+2007-01-30 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * UI/MailerUI/UIxMailListView.m ([UIxMailListView
+ -defaultAction]): invoke "flushMailCaches" on [self clientObject]
+ so that the mailbox cache is refreshed everytime the user presses
+ on "get mail". I doubt a mailbox cache really is useful in general
+ anyway.
+
+2007-01-26 Wolfgang Sourdeau <wsourdeau@inverse.ca>
+
+ * SoObjects/SOGo/SOGoAuthenticator.m ([SOGoAuthenticator
+ -userInContext:]): if the lookup is on "freebusy.ifb" and the
+ username is "anonymous" the user is automatically set to
+ "freebusy".
+
2007-01-12 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* SoObjects/SOGo/SOGoAuthenticator.m ([SOGoAuthenticator
include $(GNUSTEP_MAKEFILES)/common.make
SUBPROJECTS = \
+ SOPE/NGCards \
OGoContentStore \
SoObjects \
Main \
Protocols \
include $(GNUSTEP_MAKEFILES)/aggregate.make
-
ADDITIONAL_LIB_DIRS += \
-L../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR)/ \
- -L../OGoContentStore/$(GNUSTEP_OBJ_DIR)/
+ -L../OGoContentStore/$(GNUSTEP_OBJ_DIR)/ \
+ -L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/
SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
LIBRARY_NAME = libOGoContentStore
TOOL_NAME = test_quick_extract
-TYPEMODELS_DIR = $(GNUSTEP_USER_ROOT)/Library/OCSTypeModels/
+TYPEMODELS_DIR = $(GNUSTEP_SYSTEM_ROOT)/Library/OCSTypeModels/
libOGoContentStore_HEADER_FILES_DIR = .
libOGoContentStore_HEADER_FILES_INSTALL_DIR = /OGoContentStore
-lEOControl \
-lSaxObjC
-ADDITIONAL_INCLUDE_DIRS += -I. -I..
+ADDITIONAL_INCLUDE_DIRS += -I. -I.. -I../SOPE
-ADDITIONAL_LIB_DIRS += -L./$(GNUSTEP_OBJ_DIR)
+ADDITIONAL_LIB_DIRS += -L./$(GNUSTEP_OBJ_DIR) -L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/
SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
-- TODO:
-- add a unique constraints on path
+DROP SEQUENCE SOGo_folder_info_seq;
+
CREATE SEQUENCE SOGo_folder_info_seq;
DROP TABLE SOGo_folder_info;
c_acl_location VARCHAR(2048) NULL, -- URL to quicktable of folder
c_folder_type VARCHAR(255) NOT NULL -- the folder type ...
);
-
-INSERT INTO SOGo_folder_info
- ( c_path, c_path1, c_path2, c_path3, c_path4, c_foldername,
- c_location, c_quick_location, c_folder_type )
-VALUES
- ( '/Users',
- 'Users',
- NULL,
- NULL,
- NULL,
- 'Users',
- 'http://OGo:OGo@localhost:5432/OGo/SOGo_user_folder',
- 'http://OGo:OGo@localhost:5432/OGo/SOGo_user_folder_quick',
- 'http://OGo:OGo@localhost:5432/OGo/SOGo_user_folder_acl',
- 'Container' );
DB_USER="sogo"
DB_PASS="sogo"
-DB_HOST="192.168.0.4"
+DB_HOST="127.0.0.1"
DB_PORT="5432"
DB_NAME="sogo"
TIMEZONE="Canada/Eastern"
-I.. \
-I../.. \
-I../../.. \
- -I../../SoObjects
+ -I../../SoObjects \
+ -I../../SOPE
+RELBUILD_DIR_libNGCards = \
+ $(GNUSTEP_BUILD_DIR)/../../SOPE/NGCards/$(GNUSTEP_OBJ_DIR_NAME)
RELBUILD_DIR_libSOGo = \
$(GNUSTEP_BUILD_DIR)/../../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR_NAME)
RELBUILD_DIR_libOGoContentStore = \
$(GNUSTEP_BUILD_DIR)/../../OGoContentStore/$(GNUSTEP_OBJ_DIR_NAME)
ADDITIONAL_LIB_DIRS += \
+ -L$(RELBUILD_DIR_libNGCards) \
-L$(RELBUILD_DIR_libSOGo) \
-L$(RELBUILD_DIR_libOGoContentStore)
--- /dev/null
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+\f
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+Copyright (C) 2000-2005 SKYRIX Software AG
+
+
+Contact: info@skyrix.com
--- /dev/null
+/* CardElement.h - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CARDELEMENT_H
+#define CARDELEMENT_H
+
+#import <Foundation/NSObject.h>
+
+@class NSArray;
+@class NSDictionary;
+@class NSMutableArray;
+@class NSMutableDictionary;
+@class NSString;
+
+@class CardGroup;
+
+@interface CardElement : NSObject <NSCopying>
+{
+ NSString *tag;
+ NSMutableArray *values;
+ NSMutableDictionary *attributes;
+ NSString *group;
+ CardGroup *parent;
+}
+
++ (id) elementWithTag: (NSString *) aTag;
+
++ (id) simpleElementWithTag: (NSString *) aTag
+ value: (NSString *) aValue;
+
++ (id) simpleElementWithTag: (NSString *) aTag
+ singleType: (NSString *) aType
+ value: (NSString *) aValue;
+
++ (id) elementWithTag: (NSString *) aTag
+ attributes: (NSDictionary *) someAttributes
+ values: (NSArray *) someValues;
+
+- (void) setParent: (CardGroup *) aParent;
+- (CardGroup *) parent;
+
+- (void) setTag: (NSString *) aTag;
+
+- (void) setGroup: (NSString *) aGroup;
+- (NSString *) group;
+
+- (void) addValue: (NSString *) aValue;
+- (void) addValues: (NSArray *) someValues;
+
+- (void) setValue: (unsigned int) anInt
+ to: (NSString *) aValue;
+- (NSString *) value: (unsigned int) anInt;
+
+- (void) setNamedValue: (NSString *) aValueName
+ to: (NSString *) aValue;
+- (NSString *) namedValue: (NSString *) aValueName;
+
+- (void) setValue: (unsigned int) anInt
+ ofAttribute: (NSString *) anAttribute
+ to: (NSString *) aValue;
+- (NSString *) value: (unsigned int) anInt
+ ofAttribute: (NSString *) anAttribute;
+
+- (void) addAttribute: (NSString *) anAttribute
+ value: (NSString *) aValue;
+- (void) addAttributes: (NSDictionary *) someAttributes;
+- (void) removeValue: (NSString *) aValue
+ fromAttribute: (NSString *) anAttribute;
+
+- (void) addType: (NSString *) aType;
+
+- (NSString *) tag;
+- (NSArray *) values;
+- (NSDictionary *) attributes;
+- (BOOL) hasAttribute: (NSString *) aType
+ havingValue: (NSString *) aValue;
+
+- (BOOL) isVoid;
+
+- (NSString *) versitString;
+
+- (CardGroup *) searchParentOfClass: (Class) parentClass;
+
+- (CardElement *) elementWithClass: (Class) elementClass;
+- (void) setValuesAsCopy: (NSMutableArray *) someValues;
+- (void) setAttributesAsCopy: (NSMutableDictionary *) someAttributes;
+
+@end
+
+#endif /* CARDELEMENT_H */
--- /dev/null
+/* CardElement.m - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSDictionary.h>
+#import <Foundation/NSString.h>
+
+#import "NSArray+NGCards.h"
+#import "NSDictionary+NGCards.h"
+#import "CardVersitRenderer.h"
+
+#import "CardElement.h"
+#import "CardGroup.h"
+
+@implementation CardElement
+
++ (id) elementWithTag: (NSString *) aTag
+{
+ id newElement;
+
+ newElement = [self new];
+ [newElement autorelease];
+ [newElement setTag: aTag];
+
+ return newElement;
+}
+
++ (id) simpleElementWithTag: (NSString *) aTag
+ value: (NSString *) aValue
+{
+ id newElement;
+
+ newElement = [self elementWithTag: aTag];
+ [newElement addValue: aValue];
+
+ return newElement;
+}
+
++ (id) simpleElementWithTag: (NSString *) aTag
+ singleType: (NSString *) aType
+ value: (NSString *) aValue
+{
+ id newElement;
+
+ newElement = [self simpleElementWithTag: aTag
+ value: aValue];
+ [newElement addType: aType];
+
+ return newElement;
+}
+
++ (id) elementWithTag: (NSString *) aTag
+ attributes: (NSDictionary *) someAttributes
+ values: (NSArray *) someValues
+{
+ id newElement;
+
+ newElement = [self new];
+ [newElement autorelease];
+ [newElement setTag: aTag];
+ [newElement addAttributes: someAttributes];
+ [newElement addValues: someValues];
+
+ return newElement;
+}
+
+- (id) init
+{
+ if ((self = [super init]))
+ {
+ parent = nil;
+ tag = nil;
+ group = nil;
+ values = [NSMutableArray new];
+ attributes = [NSMutableDictionary new];
+ }
+
+ return self;
+}
+
+- (void) dealloc
+{
+ if (tag)
+ [tag release];
+ [values release];
+ [attributes release];
+ [super dealloc];
+}
+
+- (void) setParent: (CardGroup *) aParent
+{
+ parent = aParent;
+}
+
+- (CardGroup *) parent
+{
+ return parent;
+}
+
+- (void) setTag: (NSString *) aTag
+{
+ if (tag)
+ [tag release];
+ tag = aTag;
+ if (tag)
+ [tag retain];
+}
+
+- (void) setGroup: (NSString *) aGroup
+{
+ if (group)
+ [group release];
+ group = aGroup;
+ if (group)
+ [group retain];
+}
+
+- (NSString *) group
+{
+ return group;
+}
+
+- (void) addValue: (NSString *) aValue
+{
+ [values addObject: aValue];
+}
+
+- (void) addValues: (NSArray *) someValues
+{
+ [values addObjectsFromArray: someValues];
+}
+
+- (void) addAttribute: (NSString *) anAttribute
+ value: (NSString *) aType
+{
+ NSMutableArray *attrValues;
+
+ attrValues = [attributes objectForCaseInsensitiveKey: anAttribute];
+ if (!attrValues)
+ {
+ attrValues = [NSMutableArray new];
+ [attrValues autorelease];
+ [attributes setObject: attrValues forKey: anAttribute];
+ }
+
+ [attrValues addObject: aType];
+}
+
+- (void) removeValue: (NSString *) aValue
+ fromAttribute: (NSString *) anAttribute
+{
+ NSMutableArray *attrValues;
+ NSString *currentValue;
+
+ attrValues = [attributes objectForCaseInsensitiveKey: anAttribute];
+ if (attrValues)
+ {
+ currentValue = [attrValues valueForCaseInsensitiveString: aValue];
+ while (currentValue)
+ {
+ [attrValues removeObject: currentValue];
+ currentValue = [attrValues valueForCaseInsensitiveString: aValue];
+ }
+ }
+}
+
+- (void) addAttributes: (NSDictionary *) someAttributes
+{
+ NSEnumerator *keys;
+ NSString *currentKey;
+ NSMutableArray *oldValues;
+ NSArray *newValues;
+
+ keys = [[someAttributes allKeys] objectEnumerator];
+ currentKey = [keys nextObject];
+ while (currentKey)
+ {
+ oldValues = [attributes objectForCaseInsensitiveKey: currentKey];
+ newValues = [someAttributes objectForKey: currentKey];
+ if (oldValues)
+ [oldValues addObjectsFromArray: newValues];
+ else
+ [attributes setObject: newValues forKey: currentKey];
+ currentKey = [keys nextObject];
+ }
+}
+
+- (void) addType: (NSString *) aType
+{
+ [self addAttribute: @"type" value: aType];
+}
+
+- (NSString *) tag
+{
+ return tag;
+}
+
+- (NSArray *) values
+{
+ return values;
+}
+
+- (NSDictionary *) attributes
+{
+ return attributes;
+}
+
+- (BOOL) hasAttribute: (NSString *) anAttribute
+ havingValue: (NSString *) aValue
+{
+ NSArray *attribute;
+
+ attribute = [attributes objectForCaseInsensitiveKey: anAttribute];
+
+ return (attribute && [attribute hasCaseInsensitiveString: aValue]);
+}
+
+- (void) setValue: (unsigned int) anInt
+ to: (NSString *) aValue
+{
+ while ([values count] <= anInt)
+ [self addValue: @""];
+ [values replaceObjectAtIndex: anInt withObject: aValue];
+}
+
+- (NSString *) value: (unsigned int) anInt
+{
+ NSString *value;
+
+ if ([values count] <= anInt)
+ value = @"";
+ else
+ value = [values objectAtIndex: anInt];
+
+ return value;
+}
+
+- (unsigned int) _namedValue: (NSString *) aValueName
+{
+ NSString *prefix, *value;
+ unsigned int count, max, result;
+
+ result = NSNotFound;
+
+ prefix = [NSString stringWithFormat: @"%@=", [aValueName uppercaseString]];
+ max = [values count];
+ count = 0;
+
+ while (result == NSNotFound && count < max)
+ {
+ value = [[values objectAtIndex: count] uppercaseString];
+ if ([value hasPrefix: prefix])
+ result = count;
+ else
+ count++;
+ }
+
+ return result;
+}
+
+- (void) setNamedValue: (NSString *) aValueName
+ to: (NSString *) aValue
+{
+ NSString *newValue;
+ unsigned int index;
+
+ newValue = [NSString stringWithFormat: @"%@=%@",
+ [aValueName uppercaseString],
+ aValue];
+ index = [self _namedValue: aValueName];
+ if (index == NSNotFound)
+ [self addValue: newValue];
+ else
+ {
+ if (aValue)
+ [self setValue: index to: newValue];
+ else
+ [values removeObjectAtIndex: index];
+ }
+}
+
+- (NSString *) namedValue: (NSString *) aValueName
+{
+ unsigned int index, equalSign;
+ NSString *value;
+
+ index = [self _namedValue: aValueName];
+ if (index == NSNotFound)
+ value = @"";
+ else
+ {
+ value = [values objectAtIndex: index];
+ equalSign = [value indexOfString: @"="];
+ if (equalSign != NSNotFound)
+ value = [value substringFromIndex: equalSign + 1];
+ }
+
+ return value;
+}
+
+- (void) setValue: (unsigned int) anInt
+ ofAttribute: (NSString *) anAttribute
+ to: (NSString *) aValue
+{
+ NSMutableArray *attrValues;
+
+ attrValues = [attributes objectForCaseInsensitiveKey: anAttribute];
+ if (!attrValues)
+ {
+ attrValues = [NSMutableArray new];
+ [attrValues autorelease];
+ [attributes setObject: attrValues forKey: anAttribute];
+ }
+
+ while ([attrValues count] <= anInt)
+ [attrValues addObject: @""];
+ [attrValues replaceObjectAtIndex: anInt
+ withObject: aValue];
+}
+
+- (NSString *) value: (unsigned int) anInt
+ ofAttribute: (NSString *) anAttribute
+{
+ NSArray *attrValues;
+ NSString *value;
+
+ attrValues = [attributes objectForCaseInsensitiveKey: anAttribute];
+ if (attrValues && [attrValues count] > anInt)
+ value = [attrValues objectAtIndex: anInt];
+ else
+ value = @"";
+
+ return value;
+}
+
+- (NSString *) description
+{
+ NSArray *attrs;
+ NSMutableString *str;
+ unsigned int count, max;
+ NSString *attr;
+
+ str = [NSMutableString stringWithCapacity:64];
+ [str appendFormat:@"<%p[%@]:", self, NSStringFromClass([self class])];
+ if (group)
+ [str appendFormat: @"%@ (group: %@)\n", tag, group];
+ else
+ [str appendFormat: @"%@\n", tag, group];
+
+ attrs = [attributes allKeys];
+ max = [attrs count];
+ if (max > 0)
+ {
+ [str appendFormat: @"\n %d attributes: {\n", [attrs count]];
+ for (count = 0; count < max; count++)
+ {
+ attr = [attrs objectAtIndex: count];
+ [str appendFormat: @" %@: %@\n",
+ attr, [attributes objectForKey: attr]];
+ }
+ [str appendFormat: @"}"];
+ }
+
+ max = [values count];
+ if (max > 0)
+ {
+ [str appendFormat: @"\n %d values: {\n", [values count]];
+ for (count = 0; count < max; count++)
+ [str appendFormat: @" %@\n", [values objectAtIndex: count]];
+ [str appendFormat: @"}"];
+ }
+
+ [str appendString:@">"];
+
+ return str;
+}
+
+- (BOOL) isVoid
+{
+ BOOL result;
+ NSString *value;
+ NSEnumerator *enu;
+
+ result = YES;
+
+ enu = [values objectEnumerator];
+ value = [enu nextObject];
+ while (value && result)
+ {
+ result = ([value length] == 0);
+ value = [enu nextObject];
+ }
+
+ return result;
+}
+
+- (NSString *) versitString
+{
+ CardVersitRenderer *renderer;
+ NSString *string;
+
+ renderer = [CardVersitRenderer new];
+ string = [renderer render: self];
+ [renderer release];
+
+ return string;
+}
+
+- (CardElement *) elementWithClass: (Class) elementClass
+{
+ CardElement *newElement;
+
+ if ([self isKindOfClass: elementClass])
+ newElement = self;
+ else
+ {
+ newElement = [elementClass new];
+ [newElement autorelease];
+ [newElement setTag: tag];
+ [newElement setValuesAsCopy: values];
+ [newElement setAttributesAsCopy: attributes];
+ if (group)
+ [newElement setGroup: group];
+ if (parent)
+ {
+ [newElement setParent: parent];
+ [parent replaceThisElement: self
+ withThisOne: newElement];
+ }
+ }
+
+ return newElement;
+}
+
+- (void) setValuesAsCopy: (NSMutableArray *) someValues
+{
+ [values release];
+ values = someValues;
+ [values retain];
+}
+
+- (void) setAttributesAsCopy: (NSMutableDictionary *) someAttributes
+{
+ [attributes release];
+ attributes = someAttributes;
+ [attributes retain];
+}
+
+- (CardGroup *) searchParentOfClass: (Class) parentClass
+{
+ CardGroup *current;
+ CardGroup *found;
+
+ found = nil;
+ current = parent;
+ while (current && !found)
+ if ([current isKindOfClass: parentClass])
+ found = current;
+ else
+ current = [current parent];
+
+ return found;
+}
+
+/* NSCopying */
+
+- (id) copyWithZone: (NSZone *) aZone
+{
+ CardElement *new;
+
+ new = [[self class] new];
+ [new setTag: [tag copyWithZone: aZone]];
+ [new setGroup: [group copyWithZone: aZone]];
+ [new setParent: parent];
+ [new setValuesAsCopy: [values copyWithZone: aZone]];
+ [new setAttributesAsCopy: [attributes copyWithZone: aZone]];
+
+ return new;
+}
+
+@end
--- /dev/null
+/* CardGroup+iCal.h - this file is part of $PROJECT_NAME_HERE$
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CARDGROUP_ICAL_H
+#define CARDGROUP_ICAL_H
+
+@class NSString;
+@class NSCalendarDate;
+
+#import "CardGroup.h"
+
+@interface CardGroup (iCalExtensions)
+
+- (void) setDate: (NSCalendarDate *) _value
+ forDateTimeValue: (NSString *) valueName;
+- (NSCalendarDate *) dateForDateTimeValue: (NSString *) valueName;
+
+@end
+
+#endif /* CARDGROUP_ICAL_H */
--- /dev/null
+/* CardGroup+iCal.m - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import "iCalDateTime.h"
+
+#import "CardGroup+iCal.h"
+
+@implementation CardGroup (iCalExtensions)
+
+- (void) setDate: (NSCalendarDate *) _value
+ forDateTimeValue: (NSString *) valueName
+{
+ iCalDateTime *dateValue;
+
+ dateValue = (iCalDateTime *) [self uniqueChildWithTag: valueName];
+
+ [dateValue setDateTime: _value];
+}
+
+- (NSCalendarDate *) dateForDateTimeValue: (NSString *) valueName
+{
+ iCalDateTime *dateValue;
+
+ dateValue = (iCalDateTime *) [self uniqueChildWithTag: valueName];
+
+ return [dateValue dateTime];
+}
+
+@end
--- /dev/null
+/* CardGroup.h - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CARDGROUP_H
+#define CARDGROUP_H
+
+#import "CardElement.h"
+
+@class NSArray;
+@class NSMutableArray;
+@class NSString;
+
+@interface CardGroup : CardElement <NSCopying>
+{
+ NSMutableArray *children;
+}
+
++ (id) parseSingleFromSource: (id) source;
++ (NSArray *) parseFromSource: (id) source;
+
++ (id) groupWithTag: (NSString *) aTag;
++ (id) groupWithTag: (NSString *) aTag
+ children: (NSArray *) someChildren;
+
+- (Class) classForTag: (NSString *) tagClass;
+
+- (CardElement *) uniqueChildWithTag: (NSString *) aTag;
+- (void) setUniqueChild: (CardElement *) aChild;
+
+- (void) addChild: (CardElement *) aChild;
+- (void) addChildren: (NSArray *) someChildren;
+
+- (NSArray *) children;
+- (NSArray *) childrenWithTag: (NSString *) aTag;
+- (NSArray *) childrenWithAttribute: (NSString *) anAttribute
+ havingValue: (NSString *) aValue;
+- (NSArray *) childrenWithTag: (NSString *) aTag
+ andAttribute: (NSString *) anAttribute
+ havingValue: (NSString *) aValue;
+- (NSArray *) childrenGroupWithTag: (NSString *) aTag
+ withChild: (NSString *) aChild
+ havingSimpleValue: (NSString *) aValue;
+
+- (void) addChildWithTag: (NSString *) aTag
+ types: (NSArray *) someTypes
+ singleValue: (NSString *) aValue;
+
+
+- (CardGroup *) groupWithClass: (Class) groupClass;
+- (void) setChildrenAsCopy: (NSMutableArray *) someChildren;
+
+- (void) replaceThisElement: (CardElement *) oldElement
+ withThisOne: (CardElement *) newElement;
+
+@end
+
+#endif /* CARDGROUP_H */
--- /dev/null
+/* CardGroup.m - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSDictionary.h>
+#import <Foundation/NSString.h>
+#import <SaxObjC/SaxXMLReader.h>
+#import <SaxObjC/SaxXMLReaderFactory.h>
+
+#import "NGCardsSaxHandler.h"
+#import "NSArray+NGCards.h"
+
+#import "CardGroup.h"
+
+static id<NSObject,SaxXMLReader> parser = nil;
+static NGCardsSaxHandler *sax = nil;
+
+@implementation CardGroup
+
++ (id<NSObject,SaxXMLReader>) cardParser
+{
+ if (!sax)
+ sax = [NGCardsSaxHandler new];
+
+ if (!parser)
+ {
+ parser =
+ [[[SaxXMLReaderFactory standardXMLReaderFactory]
+ createXMLReaderForMimeType:@"text/x-vcard"]
+ retain];
+ if (parser)
+ {
+ [parser setContentHandler:sax];
+ [parser setErrorHandler:sax];
+ }
+ else
+ NSLog(@"ERROR(%s): did not find a parser for text/x-vcard!",
+ __PRETTY_FUNCTION__);
+ }
+
+ return parser;
+}
+
++ (NSArray *) parseFromSource: (id) source
+{
+ static id <NSObject,SaxXMLReader> cardParser;
+ NSMutableArray *cardGroups;
+ NSEnumerator *cards;
+ CardGroup *currentCard;
+
+ cardParser = [self cardParser];
+ [sax setTopElementClass: [self class]];
+
+ if (parser)
+ {
+ cardGroups = [NSMutableArray new];
+ [cardGroups autorelease];
+
+ [parser parseFromSource: source];
+ cards = [[sax cards] objectEnumerator];
+
+ currentCard = [cards nextObject];
+ while (currentCard)
+ {
+ [cardGroups addObject: currentCard];
+ currentCard = [cards nextObject];
+ }
+ }
+ else
+ cardGroups = nil;
+
+ return cardGroups;
+}
+
++ (id) parseSingleFromSource: (id) source
+{
+ NSArray *cards;
+ CardGroup *card;
+
+ cards = [self parseFromSource: source];
+ if (cards && [cards count])
+ card = [cards objectAtIndex: 0];
+ else
+ card = nil;
+
+ return card;
+}
+
++ (id) groupWithTag: (NSString *) aTag
+{
+ id newGroup;
+
+ newGroup = [self new];
+ [newGroup autorelease];
+ [newGroup setTag: aTag];
+
+ return newGroup;
+}
+
++ (id) groupWithTag: (NSString *) aTag
+ children: (NSArray *) someChildren
+{
+ id newGroup;
+
+ newGroup = [self new];
+ [newGroup autorelease];
+ [newGroup setTag: aTag];
+ [newGroup addChildren: someChildren];
+
+ return newGroup;
+}
+
+- (id) init
+{
+ if ((self = [super init]))
+ {
+ children = [NSMutableArray new];
+ }
+
+ return self;
+}
+
+- (void) dealloc
+{
+ [children release];
+ [super dealloc];
+}
+
+- (Class) classForTag: (NSString *) tagClass
+{
+ NSLog (@"class '%@': '%@'", NSStringFromClass([self class]),
+ tagClass);
+
+ return nil;
+}
+
+- (void) addChild: (CardElement *) aChild
+{
+ Class mappedClass;
+ NSString *childTag;
+ CardElement *newChild;
+
+ childTag = [aChild tag];
+ newChild = nil;
+ mappedClass = [self classForTag: [childTag uppercaseString]];
+ if (mappedClass)
+ {
+ if (![aChild isKindOfClass: mappedClass])
+ {
+ NSLog (@"warning: new child to entity '%@': '%@' converted to '%@'",
+ tag, childTag, NSStringFromClass(mappedClass));
+ if ([aChild isKindOfClass: [CardGroup class]])
+ newChild = [(CardGroup *) aChild groupWithClass: mappedClass];
+ else
+ newChild = [aChild elementWithClass: mappedClass];
+ }
+ }
+ else
+ NSLog (@"warning: no mapped class for tag '%@'",
+ childTag);
+
+ if (!newChild)
+ newChild = aChild;
+ [children addObject: newChild];
+ [newChild setParent: self];
+}
+
+- (CardElement *) uniqueChildWithTag: (NSString *) aTag
+{
+ NSArray *existing;
+ Class elementClass;
+ CardElement *uniqueChild;
+
+ existing = [self childrenWithTag: aTag];
+ if ([existing count] > 0)
+ uniqueChild = [existing objectAtIndex: 0];
+ else
+ {
+ elementClass = [self classForTag: [aTag uppercaseString]];
+ if (!elementClass)
+ elementClass = [CardElement class];
+
+ uniqueChild = [elementClass new];
+ [uniqueChild autorelease];
+ [uniqueChild setTag: aTag];
+ [self addChild: uniqueChild];
+ }
+
+ return uniqueChild;
+}
+
+- (void) setUniqueChild: (CardElement *) aChild
+{
+ CardElement *currentChild;
+ NSString *childTag;
+ NSEnumerator *existing;
+
+ childTag = [aChild tag];
+ existing = [[self childrenWithTag: childTag] objectEnumerator];
+
+ currentChild = [existing nextObject];
+ while (currentChild)
+ {
+ [children removeObject: currentChild];
+ currentChild = [existing nextObject];
+ }
+
+ [self addChild: aChild];
+}
+
+- (void) addChildren: (NSArray *) someChildren
+{
+ CardElement *currentChild;
+ NSEnumerator *newChildren;
+
+ newChildren = [someChildren objectEnumerator];
+ currentChild = [newChildren nextObject];
+ while (currentChild)
+ {
+ [self addChild: currentChild];
+ currentChild = [newChildren nextObject];
+ }
+}
+
+- (NSArray *) children
+{
+ return children;
+}
+
+- (NSArray *) childrenWithTag: (NSString *) aTag
+{
+ return [children cardElementsWithTag: aTag];
+}
+
+- (NSArray *) childrenWithAttribute: (NSString *) anAttribute
+ havingValue: (NSString *) aValue
+{
+ return [children cardElementsWithAttribute: anAttribute
+ havingValue: aValue];
+}
+
+- (NSArray *) childrenWithTag: (NSString *) aTag
+ andAttribute: (NSString *) anAttribute
+ havingValue: (NSString *) aValue
+{
+ NSArray *elements;
+
+ elements = [self childrenWithTag: aTag];
+
+ return [elements cardElementsWithAttribute: anAttribute
+ havingValue: aValue];
+}
+
+- (NSArray *) childrenGroupWithTag: (NSString *) aTag
+ withChild: (NSString *) aChild
+ havingSimpleValue: (NSString *) aValue
+{
+ NSEnumerator *allElements;
+ NSMutableArray *elements;
+ CardGroup *element;
+ NSString *value;
+
+ elements = [NSMutableArray new];
+ [elements autorelease];
+
+ allElements = [[self childrenWithTag: aTag] objectEnumerator];
+ element = [allElements nextObject];
+ while (element)
+ {
+ if ([element isKindOfClass: [CardGroup class]])
+ {
+ value = [[element uniqueChildWithTag: aChild] value: 0];
+ if ([value isEqualToString: aValue])
+ [elements addObject: element];
+ }
+ element = [allElements nextObject];
+ }
+
+ return elements;
+}
+
+#warning should be renamed to elementWithClass...
+- (CardGroup *) groupWithClass: (Class) groupClass
+{
+ CardGroup *newGroup;
+
+ if ([self isKindOfClass: groupClass])
+ newGroup = self;
+ else
+ {
+ newGroup = (CardGroup *) [self elementWithClass: groupClass];
+ [newGroup setChildrenAsCopy: children];
+ }
+
+ return newGroup;
+}
+
+- (void) setChildrenAsCopy: (NSMutableArray *) someChildren
+{
+ [children release];
+ children = someChildren;
+ [children retain];
+}
+
+- (void) addChildWithTag: (NSString *) aTag
+ types: (NSArray *) someTypes
+ singleValue: (NSString *) aValue
+{
+ CardElement *newChild;
+ NSEnumerator *types;
+ NSString *type;
+
+ newChild = [CardElement simpleElementWithTag: aTag value: aValue];
+ types = [someTypes objectEnumerator];
+ type = [types nextObject];
+ while (type)
+ {
+ [newChild addType: type];
+ type = [types nextObject];
+ }
+
+ [self addChild: newChild];
+}
+
+- (NSString *) description
+{
+ NSMutableString *str;
+ unsigned int count, max;
+
+ str = [NSMutableString stringWithCapacity:64];
+ [str appendFormat:@"<%p[%@]:%@",
+ self, NSStringFromClass([self class]), [self tag]];
+ max = [children count];
+ if (max > 0)
+ {
+ [str appendFormat: @"\n %d children: {\n", [children count]];
+ for (count = 0; count < max; count++)
+ [str appendFormat: @" %@\n",
+ [[children objectAtIndex: count] description]];
+ [str appendFormat: @"}"];
+ }
+ [str appendString:@">"];
+
+ return str;
+}
+
+- (void) replaceThisElement: (CardElement *) oldElement
+ withThisOne: (CardElement *) newElement
+{
+ unsigned int index;
+
+ index = [children indexOfObject: oldElement];
+ if (index != NSNotFound)
+ [children replaceObjectAtIndex: index withObject: newElement];
+}
+
+- (id) copyWithZone: (NSZone *) aZone
+{
+ CardGroup *new;
+
+ new = [super copyWithZone: aZone];
+ [new setChildrenAsCopy: [children copyWithZone: aZone]];
+
+ return new;
+}
+
+@end
--- /dev/null
+/* CardVersitRenderer.h - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CARDCARDRENDERER_H
+#define CARDCARDRENDERER_H
+
+#import <Foundation/NSObject.h>
+
+@class CardGroup;
+@class NSString;
+
+@interface CardVersitRenderer : NSObject
+
+- (NSString *) render: (id) anElement;
+
+@end
+
+#endif /* CARDCARDRENDERER_H */
--- /dev/null
+/* CardVersitRenderer.m - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSDictionary.h>
+#import <Foundation/NSString.h>
+
+#import <NGExtensions/NSObject+Logs.h>
+
+#import "CardElement.h"
+#import "CardGroup.h"
+
+#import "NSString+NGCards.h"
+#import "NSArray+NGCards.h"
+
+#import "CardVersitRenderer.h"
+
+@interface CardVersitRenderer (PrivateAPI)
+
+- (NSString *) renderElement: (CardElement *) anElement;
+- (NSString *) renderGroup: (CardGroup *) aGroup;
+
+@end
+
+@implementation CardVersitRenderer
+
+- (NSString *) render: (id) anElement
+{
+ return (([anElement isKindOfClass: [CardGroup class]])
+ ? [self renderGroup: anElement]
+ : [self renderElement: anElement]);
+}
+
+- (NSString *) renderElement: (CardElement *) anElement
+{
+ NSMutableString *rendering;
+ NSDictionary *attributes;
+ NSEnumerator *keys;
+ NSArray *values, *renderedAttrs;
+ NSString *key, *finalRendering, *tag;
+
+ if (![anElement isVoid])
+ {
+ rendering = [NSMutableString new];
+ [rendering autorelease];
+ if ([anElement group])
+ [rendering appendFormat: @"%@.", [anElement group]];
+ tag = [anElement tag];
+ if (!(tag && [tag length]))
+ {
+ tag = @"<no-tag>";
+ [self warnWithFormat: @"card element of class '%@' has an empty tag",
+ NSStringFromClass([anElement class])];
+ }
+
+ [rendering appendString: [tag uppercaseString]];
+ attributes = [anElement attributes];
+ keys = [[attributes allKeys] objectEnumerator];
+ key = [keys nextObject];
+ while (key)
+ {
+ renderedAttrs = [[attributes objectForKey: key] renderedForCards];
+ [rendering appendFormat: @";%@=%@",
+ [key uppercaseString],
+ [renderedAttrs componentsJoinedByString: @","]];
+ key = [keys nextObject];
+ }
+
+ values = [anElement values];
+ if ([values count] > 0)
+ [rendering appendFormat: @":%@",
+ [[values renderedForCards] componentsJoinedByString: @";"]];
+
+ if ([rendering length] > 0)
+ [rendering appendString: @"\r\n"];
+
+ finalRendering = [rendering foldedForVersitCards];
+ }
+ else
+ finalRendering = @"";
+
+ return finalRendering;
+}
+
+- (NSString *) renderGroup: (CardGroup *) aGroup
+{
+ NSEnumerator *children;
+ CardElement *currentChild;
+ NSMutableString *rendering;
+ NSString *groupTag;
+
+ rendering = [NSMutableString new];
+ [rendering autorelease];
+
+ groupTag = [aGroup tag];
+ if (!(groupTag && [groupTag length]))
+ {
+ groupTag = @"<no-tag>";
+ [self warnWithFormat: @"card group of class '%@' has an empty tag",
+ NSStringFromClass([aGroup class])];
+ }
+
+ groupTag = [groupTag uppercaseString];
+ [rendering appendFormat: @"BEGIN:%@\r\n", groupTag];
+ children = [[aGroup children] objectEnumerator];
+ currentChild = [children nextObject];
+ while (currentChild)
+ {
+ [rendering appendString: [self render: currentChild]];
+ currentChild = [children nextObject];
+ }
+ [rendering appendFormat: @"END:%@\r\n", groupTag];
+
+ return rendering;
+}
+
+@end
--- /dev/null
+2006-08-03 Helge Hess <helge.hess@opengroupware.org>
+
+ * NGVCardSaxHandler.m: fixed a bug with returning parsing results.
+ Properly make a copy of the vCard array so that -clear doesn't
+ destroy references. Thanks go to Wolfgang Sourdeau for documenting
+ the issue! (v4.5.76)
+
+2006-07-04 Helge Hess <helge.hess@opengroupware.org>
+
+ * use %p for pointer formats, fixed gcc 4.1 warnings (v4.5.75)
+
+2006-05-16 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * iCalDataSource.h, common.h: changed EOControl related includes into
+ imports to enable compilation against MulleEOF (v4.5.74)
+
+2006-04-07 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * iCalEntityObject.h: added missing forward declaration for
+ gstep-base compile (v4.5.73)
+
+2006-04-06 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.5.72
+
+ * iCalEntityObject.[hm]: added "url" property - unfortunately
+ this was missing before. Increased class version to "1".
+
+ * iCalRepeatableEntityObject.m, iCalEvent.m, iCalToDo.m: adjusted
+ super class version check.
+
+2006-01-16 Helge Hess <helge.hess@opengroupware.org>
+
+ * iCalRecurrenceRule.m: properly include NSString+Ext.h to avoid a
+ warning during Cocoa compilation (v4.5.71)
+
+2005-11-17 Helge Hess <helge.hess@opengroupware.org>
+
+ * include string.h where required (v4.5.70)
+
+2005-10-05 Helge Hess <helge.hess@opengroupware.org>
+
+ * iCalMonthlyRecurrenceCalculator.m: implemented calculation of
+ negative byday occurrences (eg -1TH) (v4.5.69)
+
+2005-09-22 Helge Hess <helge.hess@skyrix.com>
+
+ * iCalRecurrenceRule.m: added direct parser support for 'interval',
+ allow 'until' values w/o Z marker for date-only values (v4.5.68)
+
+2005-09-22 Helge Hess <helge.hess@opengroupware.org>
+
+ * v4.5.67
+
+ * iCalMonthlyRecurrenceCalculator.m: finished 'byday' calculation
+
+ * iCalRecurrenceRule.m: added support for 'bymonthday', fixed handling
+ of occurrence1
+
+2005-09-21 Helge Hess <helge.hess@skyrix.com>
+
+ * v4.5.66
+
+ * iCalRecurrenceRule.m: temporarily expose byDayOccurence1 until the
+ API is fixed
+
+ * iCalMonthlyRecurrenceCalculator.m: prepared for byday/bymonthday
+ rule specs
+
+ * v4.5.65
+
+ * iCalMonthlyRecurrenceCalculator.m: fixed calculation of 'count' field
+
+ * iCalRecurrenceCalculator.m: minor code cleanups
+
+ * iCalRecurrenceRule.m: improved rrule parser
+
+2005-09-20 Helge Hess <helge.hess@opengroupware.org>
+
+ * iCalMonthlyRecurrenceCalculator.m: stop calculation if a byday part
+ was detected in the rule (v4.5.64)
+
+ * iCalRecurrenceCalculator.m: moved cluster subclasses to own source
+ files (v4.5.63)
+
+ * iCalRecurrenceRule.m: added some parsing/gen support for BYDAY
+ (v4.5.62)
+
+2005-09-19 Helge Hess <helge.hess@opengroupware.org>
+
+ * iCalRecurrenceRule.m: minor code improvements, more tolerant on
+ invalid iCal rrule input (v4.5.61)
+
+2005-08-16 Helge Hess <helge.hess@opengroupware.org>
+
+ * GNUmakefile, GNUmakefile.preamble: added OSX framework compilation
+ (v4.5.60)
+
+2005-08-06 Helge Hess <helge.hess@opengroupware.org>
+
+ * iCalCalendar.m, NGVCardName.m: fixed gcc 4.0 warnings (v4.5.59)
+
+2005-08-05 Helge Hess <helge.hess@opengroupware.org>
+
+ * NGVCardSaxHandler.h: fixed a gcc 4.0 warning (v4.5.58)
+
+2005-07-18 Helge Hess <helge.hess@opengroupware.org>
+
+ * iCalPerson.m: added -partStatWithDefault method to retrieve the
+ partstat and return NEEDS-ACTION in case none is set (v4.5.57)
+
+2005-07-15 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * iCalObject.[hm], iCalEntityObject.m, iCalToDo.m, iCalAlarm.m,
+ iCalPerson.m, iCalCalendar.m, iCalEvent.m, iCalTrigger.m,
+ iCalObject.m, iCalFreeBusy.m, iCalRepeatableEntityObject.m:
+ fixed NSCopying (v4.5.56)
+
+2005-07-15 Helge Hess <helge.hess@opengroupware.org>
+
+ * added fragile base class version checks (v4.5.55)
+
+2005-07-15 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * iCalObject.[hm], iCalEntityObject.m, iCalToDo.m, iCalAlarm.m,
+ iCalPerson.m, iCalCalendar.m, iCalEvent.m, iCalTrigger.m,
+ iCalObject.m, iCalFreeBusy.m, iCalRepeatableEntityObject.m:
+ added NSCopying (v4.5.54)
+
+2005-07-15 Helge Hess <helge.hess@opengroupware.org>
+
+ * v4.5.53
+
+ * iCalCalendar.m: added +parseCalendarFromSource: convenience method
+
+ * NGVCard.m: properly reset sax driver after parsing
+
+2005-07-15 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * iCalEntityObject.[hm]: added -increaseSequence (v4.5.52)
+
+ * iCalPerson.m: fixed -hasSameEmailAddress: to lowercase email
+ addresses before attempting comparison (v4.5.51)
+
+2005-07-15 Helge Hess <helge.hess@opengroupware.org>
+
+ * v4.5.50
+
+ * NGiCal.xmap: fixed mapping of 'method' property (is an attribute of
+ the calendar)
+
+ * iCalCalendar.m: use ASSIGNCOPY in accessors, added 'method' to
+ -description
+
+2005-07-14 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.5.49
+
+ * iCalCalendar.[hm]: added 'method'
+
+ * iCalEntityObject.[hm]: added 'userComment', changed all email
+ related comparisons to lowercase all strings before comparison
+
+ * iCalEvent.h: pretty printed iVars
+
+ * NGiCal.xmap: added mapping for 'comment' -> 'userComment' and
+ 'method' -> 'method'
+
+2005-07-13 Helge Hess <helge.hess@opengroupware.org>
+
+ * v4.5.48
+
+ * NGVCard.m: added some convenience methods to access the preferred
+ email, tel and adr
+
+ * NGVCardOrg.m: added a convenience method to access the first orgunit
+
+2005-07-05 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * NSCalendarDate+ICal.m: fixed 'gmtcalfmt' which removed seconds from
+ format for no obvious reason (v4.5.47)
+
+2005-05-31 Helge Hess <helge.hess@skyrix.com>
+
+ * NGVCardSaxHandler.m: ensure that types are always uppercase, improved
+ check for DUPs (v4.5.46)
+
+2005-05-16 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * NGiCal.xcode: reorganized ordering of headers/classes
+
+2005-05-15 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * NGiCal.xcode: added vCard related stuff
+
+2005-05-10 Helge Hess <helge.hess@opengroupware.org>
+
+ * NGVCard.m: added support for profile, source, name (v4.5.45)
+
+2005-05-09 Helge Hess <helge.hess@opengroupware.org>
+
+ * first version of working vCard SAX handler (v4.5.54)
+
+2005-05-08 Helge Hess <helge.hess@opengroupware.org>
+
+ * more work on vCard parsing (v4.5.53)
+
+ * work on vCard objects (incomplete) (v4.5.52)
+
+2005-04-25 Helge Hess <helge.hess@opengroupware.org>
+
+ * iCalDateHolder.m, iCalDataSource.m: fixed gcc 4.0 warnings (v4.5.51)
+
+2005-03-23 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.5.50
+
+ * iCalRenderer.h: added missing paranthesis for iVar declarations
+
+ * iCalTrigger.m, iCalEntityObject.m, iCalToDo.m,
+ iCalRecurrenceCalculator.m, iCalDateHolder.m, iCalDataSource.m,
+ iCalPerson.m, iCalCalendar.m: numerous dealloc bugs/leaks fixed
+
+2005-03-02 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * iCalRecurrenceCalculator.m: bugfix for monthly and yearly recurrences
+ (v4.5.49)
+
+ * iCalRecurrenceCalculator.m: optimized exception date handling in
+ complex calculation method quite a bit. Fixed bugs in all calculation
+ methods by introducing checks on the desired range. (v4.5.48)
+
+2005-02-28 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.5.47
+
+ * iCalRepeatableEntityObject.m: shifted code to
+ iCalRecurrenceCalculator
+
+ * iCalRecurrenceCalculator.[hm]: new class method to calculate
+ complex recurrences. In SOGo this information is stored in quick
+ fields to reduce the complexity of lookups, hence we need to offer
+ a proper API to calculate date ranges from this information.
+ Fixed all calculations to explicitly set timeZone for all newly
+ created startDates - it seems the timeZone information is not
+ properly retained by the hour:minute:second: method from NGExtensions
+ which lead to improper DST related shifts.
+
+ * iCalDateHolder.h: exposed the API
+
+ * NSCalendarDate+ICal.[hm]: new convenience constructor for calendar
+ dates from iCal representations (uses iCalDateHolder internally)
+
+ * iCalRecurrenceRule.m: changed setUntil: to utilize new public
+ NSCalendarDate+ICal category
+
+ * NGiCal.h: added NSCalendarDate+ICal.h to the public headers
+
+ * GNUmakefile: NSCalendarDate+ICal.h is public now
+
+2005-02-20 Helge Hess <helge.hess@opengroupware.org>
+
+ * NGiCal.xmap: fixed a missing semicolon (did not load on MacOSX)
+ (v.4.5.46)
+
+2005-02-17 Helge Hess <helge.hess@skyrix.com>
+
+ * GNUmakefile.preamble: fixed linking locations for dependencies
+ (v4.5.45)
+
+2005-02-17 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.5.44
+
+ * iCalEntityObject.[hm]: added convenience API
+
+ * iCalRepeatableEntityObject.[hm]: added convenience API
+
+ * iCalRecurrenceRule.m: bugfixes in -byDayList and
+ -iCalRepresentationForWeekDay:
+
+ * iCalRecurrenceCalculator.m: implemented 'BYDAY' calculations for
+ weekly frequency. Note that 'COUNT' is still broken for this case.
+
+ * iCalRenderer.m: updated rendering, now can render recurrence rules
+ and accompanied stuff properly.
+
+2005-02-15 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.5.43
+
+ * iCalRecurrenceRule.[hm]: exposed some more of the API
+
+ * iCalRecurrenceCalculator.m: some bugfixes. Split the code and gave
+ iCalWeeklyRecurrenceCalculator its own calculation - there are a
+ number of foreseeable differences to daily calculation that make
+ this necessary in the near future anyways.
+
+ * v4.5.42
+
+ * iCalRepeatableEntityObject.[hm]: added ability to properly calculate
+ the recurrence ranges within a specific calendar date range, taking
+ all possible exceptions into account.
+
+ * iCalEvent.[hm]: convenience wrapper for the new method found in
+ iCalRepeatableEntityObject.
+
+2005-02-14 Helge Hess <helge.hess@opengroupware.org>
+
+ * v4.5.41
+
+ * GNUmakefile.preamble: added missing dependency on libNGExtensions
+ (which also adds the dependency on libDOM)
+
+ * iCalRecurrenceCalculator.h: fixed missing forward declaration in
+ header
+
+2005-02-12 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.5.40
+
+ * iCalRecurrenceCalculator.[hm]: implemented all required (and simple)
+ calculations. Added some convenience API to query some of the more
+ obvious ranges suitable as limits for fetching/comparison.
+
+ * iCalRepeatableEntityObject.[hm]: new method for calculating the
+ last possible recurrence start date. This can be used for fetches
+ as well.
+
+ * iCalEvent.[hm]: more convenient wrapper for the new method found in
+ iCalRepeatableEntityObject.
+
+ * NSCalendarDate+ICal.[hm]: convenience methods for calculating
+ "distances" between dates.
+
+ * tests/*: updated
+
+2005-02-11 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.5.39
+
+ * README: updated
+
+ * iCalRepeatableEntityObject.[hm]: new base class for all other
+ repeatable entity objects. Offers a convenience API for generating
+ recurrence ranges and tests, taking all exceptions into account.
+
+ * iCalRecurrenceRule.[hm]: an iCal recurrence rule, modeled as closely
+ as possible to RFC2445. Please note that this is work in progress
+ and far from being complete, yet.
+
+ * iCalRecurrenceCalculator.[hm]: a controller implementing RFC2445
+ to properly generate recurrence ranges and accompanied functionality.
+
+ * iCalEvent.[hm], iCalToDo.[hm]: now subclasses from
+ iCalRepeatableEntityObject, thus removed code dealing with
+ recurrences
+
+ * NGiCal.h: added new headers
+
+ * NGiCal.xmap: changed recurrenceRule mappings due to model change
+
+ * tests/*: contains unit tests for stuff dealing with recurrences. See
+ accompanied README for details
+
+2004-12-17 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * iCalPerson.[hm]: formalized participationStatus according to RFC2445.
+ Provided convenience API to set status without concrete knowledge
+ of string values involved. (v4.5.38)
+
+2004-12-16 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.5.37
+
+ * iCalEvent.[hm]: Added transparency 'TRANSP'. Also multiple
+ convenience methods provided.
+
+ * NGiCal.xmap: added proper mapping for 'transp'.
+
+2004-12-14 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * NGiCal.xcode: minor changes and updated
+
+2004-12-13 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * iCalPerson.[hm]: added -cnWithoutQuotes and -rfc822Email convenience
+ methods to simplify client code dealing with these properties
+ (v4.5.36)
+
+2004-11-07 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * NGiCal.xcode: provide SOPE_{MAJOR,MINOR}_VERSION to the build
+
+2004-11-06 Helge Hess <helge.hess@opengroupware.org>
+
+ * iCalRenderer.m: use SOPE version defines for iCalendar product id
+ (v4.5.35)
+
+2004-11-04 Helge Hess <helge.hess@skyrix.com>
+
+ * use Version file for install directory location of sax mapping
+
+2004-10-31 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * iCalAlarm.[hm], iCalEvent.[hm], iCalToDo.[hm],
+ NGiCal.xmap: added recurrenceRule (v4.3.34)
+
+2004-10-20 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * NGiCal.xcode: added iCalRenderer.[hm], bumped framework version
+
+2004-10-20 Helge Hess <helge.hess@opengroupware.org>
+
+ * iCalRenderer.m: fixed some issue with Cocoa Foundation (v4.3.33)
+
+ * v4.3.32
+
+ * iCalEvent.m: added -vEvent method to produce an iCalendar
+ representation of an event
+
+ * added iCalRenderer class based on the SOGo render by ZNeK
+
+2004-10-14 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * NGiCal.xmap: added "categories" mapping (v4.3.31)
+
+2004-10-05 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * iCalEntityObject.[hm]: added categories property (v4.3.30)
+
+2004-09-22 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * NGiCal.xcode: fixed several build parameters
+
+2004-09-01 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.3.29
+
+ * iCalEventChanges.[hm]: new class for tracking changes between
+ two given events
+
+ * iCalEvent.[hm]: new API to generate iCalEventChanges objects.
+
+ * common.h: inline function and macro for "safe" comparison of
+ object values
+
+2004-09-01 Helge Hess <helge.hess@opengroupware.org>
+
+ * GNUmakefile.postamble: copy sax-model to FHS_INSTALL_ROOT +
+ /share/sope-4.3/saxmappings/ when compiling for FHS (v4.3.28)
+
+2004-08-29 Helge Hess <helge.hess@opengroupware.org>
+
+ * added hack to install the project in FHS locations - the library,
+ its headers, the tools and the resources will be installed in
+ FHS_INSTALL_ROOT if specified (eg make FHS_INSTALL_ROOT=/usr/local)
+ (v4.3.27)
+
+2004-08-26 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * NGiCal.xcode: new Xcode project
+
+2004-08-20 Helge Hess <helge.hess@opengroupware.org>
+
+ * fixed for SOPE 3.3 directory layout (v4.3.26)
+
+ * moved to sope-ical
+
+ * moved to SOPE 4.3 (v4.3.25)
+
+2004-08-14 Helge Hess <helge.hess@opengroupware.org>
+
+ * iCalEntityObject.m: changed "sequence" attribute from NSString to
+ NSNumber (this might break some code, though some care was taken to
+ accept NSString parameters) (v4.2.24)
+
+2004-07-14 Helge Hess <helge.hess@opengroupware.org>
+
+ * iCalEvent.h: moved 'status' field to iCalEntityObject, because it is
+ also available in todo objects (v4.2.23)
+
+2004-06-30 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * iCalEntityObject.m: added -removeAllAttendees and -removeAllAlarms.
+ These are necessary in case you want to remake the contents of these
+ collections, but keep all other attributes otherwise. (v4.2.22)
+
+2004-06-09 Helge Hess <helge.hess@opengroupware.org>
+
+ * v4.2.21
+
+ * GNUmakefile.preamble: added prebinding
+
+ * GNUmakefile: create GNUmakefile.preamble, GNUmakefile.postamble
+
+2004-05-05 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * GNUmakefile: added support for building with
+ GNUSTEP_BUILD_DIR environment variable set for recent
+ gnustep-make package. (v4.2.20)
+
+2004-01-23 Helge Hess <helge.hess@opengroupware.org>
+
+ * iCalDataSource.m: added some sanity checks, improved to work better
+ with Mozilla generated iCal files (v4.2.19)
+
+2003-12-22 Helge Hess <helge.hess@skyrix.com>
+
+ * iCalDateHolder.m: small fix not to print a warning for "YYYYMMDD"
+ style dates (which are supported) (v4.2.18)
+
+2003-12-21 Helge Hess <helge.hess@opengroupware.org>
+
+ * v4.2.17
+
+ * iCalEvent.m: added parsing of duration values and calculation of
+ end-dates based on that (eg required for Panther iCal.app)
+
+ * iCalEvent.m: added support for 'status' and 'duration' fields
+
+Thu Nov 20 16:31:15 2003 Martin Hoerning <martin@opengroupware.org>
+
+ * iCalDateHolder.m: added timeless date format: YYYYMMDD
+ (solves ogo bug 424) (v4.2.16)
+
+Wed Oct 29 22:04:32 2003 Martin Hoerning <martin@opengroupware.org>
+
+ * iCalDateHolder.m, iCalObject.[m|h]: added iCalDefaultTimeZone to
+ create date from iCalDates without timeZone. (solves OGoo bug 257)
+ (v4.2.15)
+
+2003-10-12 Helge Hess <helge@opengroupware.org>
+
+ * GNUmakefile (libNGiCal_LIBRARIES_DEPEND_UPON): link against
+ libSaxObjC on MacOSX (v4.2.14)
+
+Fri Jul 18 17:04:55 2003 Martin Hoerning <mh@skyrix.com>
+
+ * iCalToDo.h, iCalPerson.h, iCalEvent.h, iCalEntityObject.h: added
+ accessor-methods to interface (v4.2.13)
+
+2003-07-18 Helge Hess <helge.hess@skyrix.com>
+
+ * iCalDateHolder.m: replaces and indexOfString with rangeOfString,
+ thanks to Filip Van Raemdonck for pointing that out (v4.2.12)
+
+2003-03-21 Helge Hess <helge.hess@skyrix.com>
+
+ * added some method prototypes
+
+2003-03-13 Helge Hess <helge.hess@skyrix.com>
+
+ * moved iCalEntityObject to a separate file (v4.2.11)
+
+Mon Mar 10 18:41:10 2003 Bjoern Stierand <bjoern@skyrix.com>
+
+ * NGiCal.xmap: added missing attendee attributes (as dictated by
+ mh on the phone)
+
+2003-03-10 Helge Hess <helge.hess@skyrix.com>
+
+ * iCalPerson.h: added some method prototypes
+
+2003-02-24 Helge Hess <helge.hess@skyrix.com>
+
+ * iCalObject.h: added some accessors (v4.2.10)
+
+2003-02-12 Helge Hess <helge.hess@skyrix.com>
+
+ * moved to skyrix-core (v4.2.9)
+
+2003-01-13 Helge Hess <helge.hess@skyrix.com>
+
+ * added some support for timezones to be able to parse Evolution
+ apt creation requests (v4.2.7)
+
+2002-10-14 Helge Hess <helge.hess@skyrix.com>
+
+ * added iCalDateHolder for decoding xCal date values with timezone
+ attributes to a NSCalendarDate
+
+ * iCalObject.m: ignore X- keys
+
+ * removed all the old stuff (v4.2.4)
+
+ * ICalVEvent.m: renamed -class to -eventClass since -class conflicts
+ with the NSObject method
+
+ * started XML based iCal (v4.2.3)
+
+2002-10-10 Helge Hess <helge.hess@skyrix.com>
+
+ * ICalParser.m: small cleanups (v4.2.2)
+
+2002-10-04 Helge Hess <helge.hess@skyrix.com>
+
+ * created ChangeLog, created NGiCal library into SkyCore
+
+
--- /dev/null
+# GNUstep makefile
+
+-include ../../config.make
+include $(GNUSTEP_MAKEFILES)/common.make
+include ./Version
+
+SUBPROJECTS += versitCardsSaxDriver
+
+ifneq ($(frameworks),yes)
+LIBRARY_NAME = libNGCards
+else
+FRAMEWORK_NAME = NGCards
+endif
+
+FHS_HEADER_DIRS = NGCards
+
+libNGCards_PCH_FILE = common.h
+libNGCards_HEADER_FILES_DIR = .
+libNGCards_HEADER_FILES_INSTALL_DIR = /NGCards
+libNGCards_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+libNGCards_VERSION=$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION)
+
+libNGCards_HEADER_FILES = \
+ NSArray+NGCards.h \
+ NSCalendarDate+NGCards.h \
+ NSDictionary+NGCards.h \
+ NSString+NGCards.h \
+ NSCalendarDate+ICal.h \
+ \
+ CardElement.h \
+ CardGroup.h \
+ CardGroup+iCal.h \
+ CardVersitRenderer.h \
+ \
+ NGCards.h \
+ iCalAlarm.h \
+ iCalAttachment.h \
+ iCalCalendar.h \
+ iCalDataSource.h \
+ iCalDateTime.m \
+ iCalEntityObject.h \
+ iCalEvent.h \
+ iCalEventChanges.h \
+ iCalFreeBusy.h \
+ iCalJournal.h \
+ iCalObject.h \
+ iCalPerson.h \
+ iCalRecurrenceRule.h \
+ iCalRecurrenceCalculator.h \
+ iCalRepeatableEntityObject.h \
+ iCalTimeZone.h \
+ iCalTimeZonePeriod.h \
+ iCalToDo.h \
+ iCalTrigger.h \
+ \
+ NSCalendarDate+ICal.h \
+ \
+ NGVCard.h \
+# NGVCardAddress.h \
+# NGVCardStrArrayValue.h \
+# NGVCardName.h \
+# NGVCardOrg.h \
+# NGVCardPhone.h \
+ NGCardsSaxHandler.h \
+# NGVCardSimpleValue.h \
+# NGVCardValue.h \
+
+# IcalResponse.h \
+
+libNGCards_OBJC_FILES = \
+ NSArray+NGCards.m \
+ NSCalendarDate+NGCards.m \
+ NSDictionary+NGCards.m \
+ NSString+NGCards.m \
+ NSCalendarDate+ICal.m \
+ iCalDateHolder.m \
+ \
+ CardElement.m \
+ CardGroup.m \
+ CardGroup+iCal.m \
+ CardVersitRenderer.m \
+ \
+ iCalAlarm.m \
+ iCalAttachment.m \
+ iCalCalendar.m \
+ iCalDailyRecurrenceCalculator.m \
+ iCalDateTime.m \
+ iCalDataSource.m \
+ iCalEntityObject.m \
+ iCalEvent.m \
+ iCalEventChanges.m \
+ iCalFreeBusy.m \
+ iCalJournal.m \
+ iCalMonthlyRecurrenceCalculator.m \
+ iCalObject.m \
+ iCalPerson.m \
+ iCalRecurrenceRule.m \
+ iCalRecurrenceCalculator.m \
+ iCalRepeatableEntityObject.m \
+ iCalTimeZone.m \
+ iCalTimeZonePeriod.m \
+ iCalToDo.m \
+ iCalTrigger.m \
+ iCalWeeklyRecurrenceCalculator.m\
+ iCalYearlyRecurrenceCalculator.m\
+ \
+ NGVCard.m \
+ NGCardsSaxHandler.m \
+# IcalElements.m
+# IcalResponse.m
+
+
+# framework support
+
+NGCards_PCH_FILE = $(libNGCards_PCH_FILE)
+NGCards_HEADER_FILES = $(libNGCards_HEADER_FILES)
+NGCards_OBJC_FILES = $(libNGCards_OBJC_FILES)
+NGCards_SUBPROJECTS = $(libNGCards_SUBPROJECTS)
+
+# building
+
+-include GNUmakefile.preamble
+ifneq ($(frameworks),yes)
+include $(GNUSTEP_MAKEFILES)/library.make
+else
+include $(GNUSTEP_MAKEFILES)/framework.make
+endif
+include $(GNUSTEP_MAKEFILES)/aggregate.make
+-include GNUmakefile.postamble
+-include ../../fhslib.make
--- /dev/null
+# compilation settings
+
+ifeq ($(FHS_INSTALL_ROOT),)
+MAPDIR="$(GNUSTEP_INSTALLATION_DIR)/Library/SaxMappings/"
+else
+MAPDIR="$(FHS_INSTALL_ROOT)/share/sope-$(MAJOR_VERSION).$(MINOR_VERSION)/saxmappings/"
+endif
+
+mappings-dir ::
+ $(MKDIRS) $(MAPDIR)
+
+after-install :: mappings-dir
+ cp NGCards.xmap $(MAPDIR)
--- /dev/null
+# compilation settings
+
+SOPE_ROOT=../..
+
+ADDITIONAL_CPPFLAGS += \
+ -Wall -DCOMPILE_FOR_GSTEP_MAKE=1 \
+ -DSOPE_MAJOR_VERSION=$(MAJOR_VERSION) \
+ -DSOPE_MINOR_VERSION=$(MINOR_VERSION) \
+ -DSOPE_SUBMINOR_VERSION=$(SUBMINOR_VERSION)
+
+ADDITIONAL_INCLUDE_DIRS += \
+ -I. -I.. \
+ -I$(SOPE_ROOT)/sope-core/NGExtensions/ \
+ -I$(SOPE_ROOT)/sope-core \
+ -I$(SOPE_ROOT)/sope-xml
+
+
+# dependencies
+
+libNGCards_LIBRARIES_DEPEND_UPON += \
+ -lNGExtensions \
+ -lEOControl \
+ -lDOM \
+ -lSaxObjC
+
+NGCards_LIBRARIES_DEPEND_UPON += \
+ -framework NGExtensions -framework EOControl \
+ -framework DOM -framework SaxObjC
+
+
+# library/framework search pathes
+
+DEP_DIRS = \
+ $(SOPE_ROOT)/sope-core/NGExtensions \
+ $(SOPE_ROOT)/sope-core/EOControl \
+ $(SOPE_ROOT)/sope-xml/DOM \
+ $(SOPE_ROOT)/sope-xml/SaxObjC
+
+ifneq ($(frameworks),yes)
+ADDITIONAL_LIB_DIRS += \
+ $(foreach dir,$(DEP_DIRS),\
+ -L$(GNUSTEP_BUILD_DIR)/$(dir)/$(GNUSTEP_OBJ_DIR_NAME))
+else
+ADDITIONAL_LIB_DIRS += \
+ $(foreach dir,$(DEP_DIRS),-F$(GNUSTEP_BUILD_DIR)/$(dir))
+endif
+
+ifeq ($(findstring _64, $(GNUSTEP_TARGET_CPU)), _64)
+SYSTEM_LIB_DIR += -L/usr/local/lib64 -L/usr/lib64
+else
+SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
+endif
+
+
+# Apple
+
+ifeq ($(FOUNDATION_LIB),apple)
+libNGCards_PREBIND_ADDR="0xC1E00000"
+libNGCards_LDFLAGS += -seg1addr $(libNGCards_PREBIND_ADDR)
+NGCards_LDFLAGS += -seg1addr $(libNGCards_PREBIND_ADDR)
+endif
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include <NGObjWeb/WODynamicElement.h>
+
+@interface IcalComponent : WODynamicElement
+{
+ WOAssociation *cname;
+ WOElement *template;
+}
+@end
+
+@interface IcalProperty : WODynamicElement
+{
+ WOAssociation *pname;
+ WOElement *template;
+ NSDictionary *parameters;
+ WOAssociation *value;
+ WOAssociation *valueType;
+}
+@end
+
+#include "common.h"
+
+static inline NSDictionary *ExtractParameters(NSDictionary *_set) {
+ /* extracts ? parameters */
+ NSMutableDictionary *paras = nil;
+ NSMutableArray *paraKeys = nil;
+ NSEnumerator *keys;
+ NSString *key;
+
+ // locate query parameters
+ keys = [_set keyEnumerator];
+ while ((key = [keys nextObject])) {
+ if ([key hasPrefix:@"?"]) {
+ WOAssociation *value;
+
+ if ([key isEqualToString:@"?wosid"])
+ continue;
+
+ value = [_set objectForKey:key];
+
+ if (paraKeys == nil)
+ paraKeys = [NSMutableArray arrayWithCapacity:8];
+ if (paras == nil)
+ paras = [NSMutableDictionary dictionaryWithCapacity:8];
+
+ [paraKeys addObject:key];
+ [paras setObject:value forKey:[key substringFromIndex:1]];
+ }
+ }
+
+ // remove query parameters
+ if (paraKeys) {
+ unsigned cnt, count;
+ for (cnt = 0, count = [paraKeys count]; cnt < count; cnt++) {
+ [(NSMutableDictionary *)_set removeObjectForKey:
+ [paraKeys objectAtIndex:cnt]];
+ }
+ }
+
+ // assign parameters
+ return [paras copy];
+}
+
+static inline id GetProperty(NSDictionary *_set, NSString *_name) {
+ id propValue = [_set objectForKey:_name];
+
+ if (propValue) {
+ propValue = RETAIN(propValue);
+ [(id)_set removeObjectForKey:_name];
+ }
+ return propValue;
+}
+
+@implementation IcalComponent
+
+- (id)initWithName:(NSString *)_name
+ associations:(NSDictionary *)_config
+ template:(WOElement *)_t
+{
+ if ((self = [super initWithName:_name associations:_config template:_t])) {
+ self->cname = GetProperty(_config, @"name");
+ self->template = RETAIN(_t);
+ }
+ return self;
+}
+
+- (void)dealloc {
+ RELEASE(self->template);
+ RELEASE(self->cname);
+ [super dealloc];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+ NSString *n;
+
+ n = [self->cname stringValueInComponent:[_ctx component]];
+
+ [_response appendContentString:@"BEGIN:"];
+ [_response appendContentString:n];
+ [self->template appendToResponse:_response inContext:_ctx];
+ [_response appendContentString:@"END:"];
+ [_response appendContentString:n];
+}
+
+@end /* IcalComponent */
+
+@implementation IcalProperty
+
+- (id)initWithName:(NSString *)_name
+ associations:(NSDictionary *)_config
+ template:(WOElement *)_t
+{
+ if ((self = [super initWithName:_name associations:_config template:_t])) {
+ self->pname = GetProperty(_config, @"name");
+ self->value = GetProperty(_config, @"value");
+ self->valueType = GetProperty(_config, @"valueType");
+ self->template = RETAIN(_t);
+ self->parameters = ExtractParameters(_config);
+ }
+ return self;
+}
+
+- (void)dealloc {
+ RELEASE(self->value);
+ RELEASE(self->valueType);
+ RELEASE(self->parameters);
+ RELEASE(self->template);
+ RELEASE(self->pname);
+ [super dealloc];
+}
+
+- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
+ WOComponent *sComponent;
+ NSString *n;
+ NSEnumerator *keys;
+ NSString *key;
+ id val;
+ NSString *valType;
+
+ sComponent = [_ctx component];
+ n = [self->pname stringValueInComponent:sComponent];
+ val = [self->value valueInComponent:sComponent];
+ valType = [self->valueType stringValueInComponent:sComponent];
+
+ /* add name */
+ [_response appendContentString:n];
+
+ /* add parameters */
+ keys = [self->parameters keyEnumerator];
+ while ((key = [keys nextObject])) {
+ WOAssociation *val;
+ NSString *s;
+
+ val = [self->parameters objectForKey:key];
+ s = [val stringValueInComponent:sComponent];
+
+ if ([s length] > 0) {
+ [_response appendContentString:@";"];
+ [_response appendContentString:key];
+ [_response appendContentString:@"="];
+ [_response appendContentString:s];
+ }
+ }
+
+ /* add value */
+ [_response appendContentString:@":"];
+
+ if ([valType length] == 0) {
+ val = [val stringValue];
+ }
+ else if ([valType isEqualToString:@"datetime"]) {
+ static NSString *calfmt = @"%Y%m%dT%H%M00Z";
+
+ if ([val respondsToSelector:@selector(descriptionWithCalendarFormat:)]) {
+ static NSTimeZone *gmt = nil;
+ if (gmt == nil) gmt = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
+ [val setTimeZone:gmt];
+ val = [val descriptionWithCalendarFormat:calfmt];
+ }
+ else
+ val = [val stringValue];
+ }
+ else
+ val = [val stringValue];
+
+ [_response appendContentString:val];
+ [self->template appendToResponse:_response inContext:_ctx];
+}
+
+@end /* IcalProperty */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __SkyDaemon_skyaptd_IcalResponse_H__
+#define __SkyDaemon_skyaptd_IcalResponse_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSMutableString, NSData;
+
+@interface IcalResponse : NSObject
+{
+ NSMutableString *content;
+ BOOL isFinished;
+}
+
+- (id)initWithCapacity:(unsigned)_capacity;
+
+- (void)finish;
+- (NSString *)asString;
+- (BOOL)appendLine:(NSString *)_line;
+
+// _attr:_line
+- (BOOL)appendLine:(NSString *)_line forAttribute:(NSString *)_attr;
+
+@end /* IcalResponse */
+
+#endif /* __SkyDaemon_skyaptd_IcalResponse_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "IcalResponse.h"
+#import <Foundation/Foundation.h>
+
+@implementation IcalResponse
+
+- (void)_initContent {
+ [self appendLine:@"BEGIN:VCALENDAR"];
+ [self appendLine:@"VERSION:2.0"];
+ [self appendLine:@"PRODID:-//skyrix42/scheduler/skyaptd v.1.0//"];
+}
+
+- (id)init {
+ if ((self = [super init])) {
+ self->content = [[NSMutableString alloc] initWithCapacity:0xFFFF];
+ self->isFinished = NO;
+ [self _initContent];
+ }
+ return self;
+}
+- (id)initWithCapacity:(unsigned)_capacity {
+ if ((self = [super init])) {
+ self->content = [[NSMutableString alloc] initWithCapacity:_capacity];
+ self->isFinished = NO;
+ [self _initContent];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self->content release];
+ [super dealloc];
+}
+
+
+- (BOOL)appendLine:(NSString *)_line {
+ if (self->isFinished) {
+ NSLog(@"WARNING[%s]: already finished!", __PRETTY_FUNCTION__);
+ return NO;
+ }
+ // limit length to 75 chars
+ while ([_line length] > 75) {
+ [self appendLine:[_line substringToIndex:75]];
+ _line = [@" " stringByAppendingString:[_line substringFromIndex:75]];
+ }
+
+ [self->content appendString:_line];
+ [self->content appendString:@"\r\n"];
+
+ return YES;
+}
+
+- (BOOL)appendLine:(NSString *)_line forAttribute:(NSString *)_attr {
+ _line = [NSString stringWithFormat:@"%@:%@", _attr, _line];
+ return [self appendLine:_line];
+}
+
+
+- (void)finish {
+ if (self->isFinished) return;
+ [self appendLine:@"END:VCALENDAR"];
+ self->isFinished = YES;
+}
+
+- (NSString *)asString {
+ [self finish];
+ return [[self->content copy] autorelease];
+}
+
+@end /* IcalResponse */
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>NGiCal</string>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>org.OpenGroupware.SOPE.ical.NGiCal</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string></string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>4.5</string>
+</dict>
+</plist>
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGCards_H__
+#define __NGCards_H__
+
+#import <NGCards/iCalAttachment.h>
+#import <NGCards/iCalObject.h>
+#import <NGCards/iCalEntityObject.h>
+#import <NGCards/iCalRepeatableEntityObject.h>
+#import <NGCards/iCalCalendar.h>
+#import <NGCards/iCalToDo.h>
+#import <NGCards/iCalJournal.h>
+#import <NGCards/iCalEvent.h>
+#import <NGCards/iCalFreeBusy.h>
+#import <NGCards/iCalPerson.h>
+#import <NGCards/iCalAlarm.h>
+#import <NGCards/iCalTrigger.h>
+
+#import <NGCards/iCalEventChanges.h>
+
+#import <NGCards/iCalRecurrenceRule.h>
+#import <NGCards/iCalRecurrenceCalculator.h>
+
+#import <NGCards/NSCalendarDate+ICal.h>
+
+#import <NGCards/NSArray+NGCards.h>
+#import <NGCards/NSCalendarDate+ICal.h>
+#import <NGCards/NSCalendarDate+NGCards.h>
+#import <NGCards/NSDictionary+NGCards.h>
+#import <NGCards/NSString+NGCards.h>
+
+#endif /* __NGCards_H__ */
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ AD2EC1C408E2E630006B7836 /* iCalDailyRecurrenceCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2EC1C008E2E630006B7836 /* iCalDailyRecurrenceCalculator.m */; };
+ AD2EC1C508E2E630006B7836 /* iCalMonthlyRecurrenceCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2EC1C108E2E630006B7836 /* iCalMonthlyRecurrenceCalculator.m */; };
+ AD2EC1C608E2E630006B7836 /* iCalWeeklyRecurrenceCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2EC1C208E2E630006B7836 /* iCalWeeklyRecurrenceCalculator.m */; };
+ AD2EC1C708E2E630006B7836 /* iCalYearlyRecurrenceCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = AD2EC1C308E2E630006B7836 /* iCalYearlyRecurrenceCalculator.m */; };
+ AD596D9E083769C500C4D81D /* NGICalSaxHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = AD596D8A083769C500C4D81D /* NGICalSaxHandler.h */; };
+ AD596D9F083769C500C4D81D /* NGICalSaxHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = AD596D8B083769C500C4D81D /* NGICalSaxHandler.m */; };
+ AD596DA0083769C500C4D81D /* NGVCard.h in Headers */ = {isa = PBXBuildFile; fileRef = AD596D8C083769C500C4D81D /* NGVCard.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ AD596DA1083769C500C4D81D /* NGVCard.m in Sources */ = {isa = PBXBuildFile; fileRef = AD596D8D083769C500C4D81D /* NGVCard.m */; };
+ AD596DA2083769C500C4D81D /* NGVCardAddress.h in Headers */ = {isa = PBXBuildFile; fileRef = AD596D8E083769C500C4D81D /* NGVCardAddress.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ AD596DA3083769C500C4D81D /* NGVCardAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = AD596D8F083769C500C4D81D /* NGVCardAddress.m */; };
+ AD596DA4083769C500C4D81D /* NGVCardName.h in Headers */ = {isa = PBXBuildFile; fileRef = AD596D90083769C500C4D81D /* NGVCardName.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ AD596DA5083769C500C4D81D /* NGVCardName.m in Sources */ = {isa = PBXBuildFile; fileRef = AD596D91083769C500C4D81D /* NGVCardName.m */; };
+ AD596DA6083769C500C4D81D /* NGVCardOrg.h in Headers */ = {isa = PBXBuildFile; fileRef = AD596D92083769C500C4D81D /* NGVCardOrg.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ AD596DA7083769C500C4D81D /* NGVCardOrg.m in Sources */ = {isa = PBXBuildFile; fileRef = AD596D93083769C500C4D81D /* NGVCardOrg.m */; };
+ AD596DA8083769C500C4D81D /* NGVCardPhone.h in Headers */ = {isa = PBXBuildFile; fileRef = AD596D94083769C500C4D81D /* NGVCardPhone.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ AD596DA9083769C500C4D81D /* NGVCardPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = AD596D95083769C500C4D81D /* NGVCardPhone.m */; };
+ AD596DAA083769C500C4D81D /* NGVCardSaxHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = AD596D96083769C500C4D81D /* NGVCardSaxHandler.h */; };
+ AD596DAB083769C500C4D81D /* NGVCardSaxHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = AD596D97083769C500C4D81D /* NGVCardSaxHandler.m */; };
+ AD596DAC083769C500C4D81D /* NGVCardSimpleValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AD596D98083769C500C4D81D /* NGVCardSimpleValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ AD596DAD083769C500C4D81D /* NGVCardSimpleValue.m in Sources */ = {isa = PBXBuildFile; fileRef = AD596D99083769C500C4D81D /* NGVCardSimpleValue.m */; };
+ AD596DAE083769C500C4D81D /* NGVCardStrArrayValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AD596D9A083769C500C4D81D /* NGVCardStrArrayValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ AD596DAF083769C500C4D81D /* NGVCardStrArrayValue.m in Sources */ = {isa = PBXBuildFile; fileRef = AD596D9B083769C500C4D81D /* NGVCardStrArrayValue.m */; };
+ AD596DB0083769C500C4D81D /* NGVCardValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AD596D9C083769C500C4D81D /* NGVCardValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ AD596DB1083769C500C4D81D /* NGVCardValue.m in Sources */ = {isa = PBXBuildFile; fileRef = AD596D9D083769C500C4D81D /* NGVCardValue.m */; };
+ AD770E6907AE627500F5C7A1 /* iCalRecurrenceRule.h in Headers */ = {isa = PBXBuildFile; fileRef = AD770E6707AE627500F5C7A1 /* iCalRecurrenceRule.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ AD770E6A07AE627500F5C7A1 /* iCalRecurrenceRule.m in Sources */ = {isa = PBXBuildFile; fileRef = AD770E6807AE627500F5C7A1 /* iCalRecurrenceRule.m */; };
+ AD77103E07AE8F8500F5C7A1 /* iCalRepeatableEntityObject.h in Headers */ = {isa = PBXBuildFile; fileRef = AD77103C07AE8F8500F5C7A1 /* iCalRepeatableEntityObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ AD77103F07AE8F8500F5C7A1 /* iCalRepeatableEntityObject.m in Sources */ = {isa = PBXBuildFile; fileRef = AD77103D07AE8F8500F5C7A1 /* iCalRepeatableEntityObject.m */; };
+ AD8BF0F80701902800EC239A /* XmlRpc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD8BF0F70701902800EC239A /* XmlRpc.framework */; };
+ ADAACE6807B3973900FC48D6 /* iCalRecurrenceCalculator.h in Headers */ = {isa = PBXBuildFile; fileRef = ADAACE6607B3973900FC48D6 /* iCalRecurrenceCalculator.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADAACE6907B3973900FC48D6 /* iCalRecurrenceCalculator.m in Sources */ = {isa = PBXBuildFile; fileRef = ADAACE6707B3973900FC48D6 /* iCalRecurrenceCalculator.m */; };
+ ADAAD00707B6AF7700FC48D6 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADAAD00607B6AF7700FC48D6 /* SenTestingKit.framework */; };
+ ADAAD02307B6AFD700FC48D6 /* iCalRecurrenceCalculatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = ADAAD02107B6AFD700FC48D6 /* iCalRecurrenceCalculatorTests.m */; };
+ ADAAD04207B6B05000FC48D6 /* common.h in Headers */ = {isa = PBXBuildFile; fileRef = ADAAD04107B6B05000FC48D6 /* common.h */; };
+ ADAAD0A307B6B74F00FC48D6 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADDF503B06DE528200C4E7F8 /* Foundation.framework */; };
+ ADAAD11107B6B75300FC48D6 /* NGExtensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADDF503F06DE52F600C4E7F8 /* NGExtensions.framework */; };
+ ADAAD11207B6B7A100FC48D6 /* NGCards.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADDF4E6006DE4FF200C4E7F8 /* NGCards.framework */; };
+ ADBE3DF8072713AF000FEA6A /* iCalRenderer.h in Headers */ = {isa = PBXBuildFile; fileRef = ADBE3DF7072713AF000FEA6A /* iCalRenderer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADBE3DFA072713C2000FEA6A /* iCalRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = ADBE3DF9072713C2000FEA6A /* iCalRenderer.m */; };
+ ADD1FC9B06E4D6D400E387F0 /* iCalEventChanges.h in Headers */ = {isa = PBXBuildFile; fileRef = ADD1FC9906E4D6D400E387F0 /* iCalEventChanges.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADD1FC9C06E4D6D400E387F0 /* iCalEventChanges.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD1FC9A06E4D6D400E387F0 /* iCalEventChanges.m */; };
+ ADDF4F4106DE513D00C4E7F8 /* common.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F1306DE513D00C4E7F8 /* common.h */; };
+ ADDF4F4206DE513D00C4E7F8 /* COPYING in Resources */ = {isa = PBXBuildFile; fileRef = ADDF4F1406DE513D00C4E7F8 /* COPYING */; };
+ ADDF4F4306DE513D00C4E7F8 /* COPYRIGHT in Resources */ = {isa = PBXBuildFile; fileRef = ADDF4F1506DE513D00C4E7F8 /* COPYRIGHT */; };
+ ADDF4F4706DE513D00C4E7F8 /* iCalAlarm.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F1906DE513D00C4E7F8 /* iCalAlarm.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F4806DE513D00C4E7F8 /* iCalAlarm.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F1A06DE513D00C4E7F8 /* iCalAlarm.m */; };
+ ADDF4F4906DE513D00C4E7F8 /* iCalAttachment.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F1B06DE513D00C4E7F8 /* iCalAttachment.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F4A06DE513D00C4E7F8 /* iCalAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F1C06DE513D00C4E7F8 /* iCalAttachment.m */; };
+ ADDF4F4B06DE513D00C4E7F8 /* iCalCalendar.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F1D06DE513D00C4E7F8 /* iCalCalendar.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F4C06DE513D00C4E7F8 /* iCalCalendar.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F1E06DE513D00C4E7F8 /* iCalCalendar.m */; };
+ ADDF4F4D06DE513D00C4E7F8 /* iCalDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F1F06DE513D00C4E7F8 /* iCalDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F4E06DE513D00C4E7F8 /* iCalDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F2006DE513D00C4E7F8 /* iCalDataSource.m */; };
+ ADDF4F4F06DE513D00C4E7F8 /* iCalDateHolder.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F2106DE513D00C4E7F8 /* iCalDateHolder.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F5006DE513D00C4E7F8 /* iCalDateHolder.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F2206DE513D00C4E7F8 /* iCalDateHolder.m */; };
+ ADDF4F5106DE513D00C4E7F8 /* iCalDuration.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F2306DE513D00C4E7F8 /* iCalDuration.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F5206DE513D00C4E7F8 /* iCalDuration.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F2406DE513D00C4E7F8 /* iCalDuration.m */; };
+ ADDF4F5406DE513D00C4E7F8 /* iCalEntityObject.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F2606DE513D00C4E7F8 /* iCalEntityObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F5506DE513D00C4E7F8 /* iCalEntityObject.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F2706DE513D00C4E7F8 /* iCalEntityObject.m */; };
+ ADDF4F5606DE513D00C4E7F8 /* iCalEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F2806DE513D00C4E7F8 /* iCalEvent.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F5706DE513D00C4E7F8 /* iCalEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F2906DE513D00C4E7F8 /* iCalEvent.m */; };
+ ADDF4F5806DE513D00C4E7F8 /* iCalFreeBusy.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F2A06DE513D00C4E7F8 /* iCalFreeBusy.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F5906DE513D00C4E7F8 /* iCalFreeBusy.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F2B06DE513D00C4E7F8 /* iCalFreeBusy.m */; };
+ ADDF4F5A06DE513D00C4E7F8 /* iCalJournal.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F2C06DE513D00C4E7F8 /* iCalJournal.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F5B06DE513D00C4E7F8 /* iCalJournal.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F2D06DE513D00C4E7F8 /* iCalJournal.m */; };
+ ADDF4F5C06DE513D00C4E7F8 /* iCalObject.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F2E06DE513D00C4E7F8 /* iCalObject.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F5D06DE513D00C4E7F8 /* iCalObject.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F2F06DE513D00C4E7F8 /* iCalObject.m */; };
+ ADDF4F5E06DE513D00C4E7F8 /* iCalPerson.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F3006DE513D00C4E7F8 /* iCalPerson.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F5F06DE513D00C4E7F8 /* iCalPerson.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F3106DE513D00C4E7F8 /* iCalPerson.m */; };
+ ADDF4F6206DE513D00C4E7F8 /* iCalToDo.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F3406DE513D00C4E7F8 /* iCalToDo.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F6306DE513D00C4E7F8 /* iCalToDo.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F3506DE513D00C4E7F8 /* iCalToDo.m */; };
+ ADDF4F6406DE513D00C4E7F8 /* iCalTrigger.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F3606DE513D00C4E7F8 /* iCalTrigger.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F6506DE513D00C4E7F8 /* iCalTrigger.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F3706DE513D00C4E7F8 /* iCalTrigger.m */; };
+ ADDF4F6606DE513D00C4E7F8 /* NGCards.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F3806DE513D00C4E7F8 /* NGCards.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F6806DE513D00C4E7F8 /* NSCalendarDate+ICal.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDF4F3A06DE513D00C4E7F8 /* NSCalendarDate+ICal.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ ADDF4F6906DE513D00C4E7F8 /* NSCalendarDate+ICal.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF4F3B06DE513D00C4E7F8 /* NSCalendarDate+ICal.m */; };
+ ADDF4F6C06DE513D00C4E7F8 /* README in Resources */ = {isa = PBXBuildFile; fileRef = ADDF4F3E06DE513D00C4E7F8 /* README */; };
+ ADDF503C06DE528200C4E7F8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADDF503B06DE528200C4E7F8 /* Foundation.framework */; };
+ ADDF504106DE52F600C4E7F8 /* DOM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADDF503D06DE52F600C4E7F8 /* DOM.framework */; };
+ ADDF504206DE52F600C4E7F8 /* EOControl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADDF503E06DE52F600C4E7F8 /* EOControl.framework */; };
+ ADDF504306DE52F600C4E7F8 /* NGExtensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADDF503F06DE52F600C4E7F8 /* NGExtensions.framework */; };
+ ADDF504406DE52F600C4E7F8 /* SaxObjC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADDF504006DE52F600C4E7F8 /* SaxObjC.framework */; };
+ ADDF51AC06DE56E100C4E7F8 /* NGCards.xmap in CopyFiles */ = {isa = PBXBuildFile; fileRef = ADDF4F3906DE513D00C4E7F8 /* NGCards.xmap */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXBuildStyle section */
+ ADDF4E5306DE4FC600C4E7F8 /* Development */ = {
+ isa = PBXBuildStyle;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "APPLE_RUNTIME=1",
+ "NeXT_Foundation_LIBRARY=1",
+ "COCOA_Foundation_LIBRARY=1",
+ "NeXT_RUNTIME=1",
+ "COMPILE_AS_FRAMEWORK=1",
+ "DEBUG=1",
+ );
+ };
+ name = Development;
+ };
+ ADDF4E5406DE4FC800C4E7F8 /* Wrapper */ = {
+ isa = PBXBuildStyle;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEPLOYMENT_LOCATION = NO;
+ DEPLOYMENT_POSTPROCESSING = YES;
+ DSTROOT = /;
+ DYLIB_INSTALL_NAME_BASE = "@executable_path/../Frameworks/";
+ FRAMEWORK_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_OPTIMIZATION_LEVEL = 3;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "APPLE_RUNTIME=1",
+ "NeXT_Foundation_LIBRARY=1",
+ "COCOA_Foundation_LIBRARY=1",
+ "NeXT_RUNTIME=1",
+ "COMPILE_AS_FRAMEWORK=1",
+ );
+ SKIP_INSTALL = YES;
+ SYMROOT = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+ TEMP_DIR = "$(SYMROOT)/$(PROJECT_NAME).build";
+ UNSTRIPPED_PRODUCT = NO;
+ ZERO_LINK = NO;
+ };
+ name = Wrapper;
+ };
+/* End PBXBuildStyle section */
+
+/* Begin PBXContainerItemProxy section */
+ ADAACFED07B6AEBF00FC48D6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = ADDF4E5506DE4FC800C4E7F8 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = ADDF4E5F06DE4FF200C4E7F8;
+ remoteInfo = NGCards;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ ADDF51AB06DE56C500C4E7F8 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /Library/SaxMappings;
+ dstSubfolderSpec = 0;
+ files = (
+ ADDF51AC06DE56E100C4E7F8 /* NGCards.xmap in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ AD2EC1C008E2E630006B7836 /* iCalDailyRecurrenceCalculator.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = iCalDailyRecurrenceCalculator.m; sourceTree = "<group>"; };
+ AD2EC1C108E2E630006B7836 /* iCalMonthlyRecurrenceCalculator.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = iCalMonthlyRecurrenceCalculator.m; sourceTree = "<group>"; };
+ AD2EC1C208E2E630006B7836 /* iCalWeeklyRecurrenceCalculator.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = iCalWeeklyRecurrenceCalculator.m; sourceTree = "<group>"; };
+ AD2EC1C308E2E630006B7836 /* iCalYearlyRecurrenceCalculator.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = iCalYearlyRecurrenceCalculator.m; sourceTree = "<group>"; };
+ AD596D8A083769C500C4D81D /* NGICalSaxHandler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGICalSaxHandler.h; sourceTree = "<group>"; };
+ AD596D8B083769C500C4D81D /* NGICalSaxHandler.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGICalSaxHandler.m; sourceTree = "<group>"; };
+ AD596D8C083769C500C4D81D /* NGVCard.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCard.h; sourceTree = "<group>"; };
+ AD596D8D083769C500C4D81D /* NGVCard.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCard.m; sourceTree = "<group>"; };
+ AD596D8E083769C500C4D81D /* NGVCardAddress.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardAddress.h; sourceTree = "<group>"; };
+ AD596D8F083769C500C4D81D /* NGVCardAddress.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardAddress.m; sourceTree = "<group>"; };
+ AD596D90083769C500C4D81D /* NGVCardName.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardName.h; sourceTree = "<group>"; };
+ AD596D91083769C500C4D81D /* NGVCardName.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardName.m; sourceTree = "<group>"; };
+ AD596D92083769C500C4D81D /* NGVCardOrg.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardOrg.h; sourceTree = "<group>"; };
+ AD596D93083769C500C4D81D /* NGVCardOrg.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardOrg.m; sourceTree = "<group>"; };
+ AD596D94083769C500C4D81D /* NGVCardPhone.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardPhone.h; sourceTree = "<group>"; };
+ AD596D95083769C500C4D81D /* NGVCardPhone.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardPhone.m; sourceTree = "<group>"; };
+ AD596D96083769C500C4D81D /* NGVCardSaxHandler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardSaxHandler.h; sourceTree = "<group>"; };
+ AD596D97083769C500C4D81D /* NGVCardSaxHandler.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardSaxHandler.m; sourceTree = "<group>"; };
+ AD596D98083769C500C4D81D /* NGVCardSimpleValue.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardSimpleValue.h; sourceTree = "<group>"; };
+ AD596D99083769C500C4D81D /* NGVCardSimpleValue.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardSimpleValue.m; sourceTree = "<group>"; };
+ AD596D9A083769C500C4D81D /* NGVCardStrArrayValue.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardStrArrayValue.h; sourceTree = "<group>"; };
+ AD596D9B083769C500C4D81D /* NGVCardStrArrayValue.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardStrArrayValue.m; sourceTree = "<group>"; };
+ AD596D9C083769C500C4D81D /* NGVCardValue.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardValue.h; sourceTree = "<group>"; };
+ AD596D9D083769C500C4D81D /* NGVCardValue.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardValue.m; sourceTree = "<group>"; };
+ AD770E6707AE627500F5C7A1 /* iCalRecurrenceRule.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalRecurrenceRule.h; sourceTree = "<group>"; };
+ AD770E6807AE627500F5C7A1 /* iCalRecurrenceRule.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalRecurrenceRule.m; sourceTree = "<group>"; };
+ AD77103C07AE8F8500F5C7A1 /* iCalRepeatableEntityObject.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalRepeatableEntityObject.h; sourceTree = "<group>"; };
+ AD77103D07AE8F8500F5C7A1 /* iCalRepeatableEntityObject.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalRepeatableEntityObject.m; sourceTree = "<group>"; };
+ AD8BF0F70701902800EC239A /* XmlRpc.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XmlRpc.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/XmlRpc.framework"; sourceTree = "<absolute>"; };
+ ADAACE6607B3973900FC48D6 /* iCalRecurrenceCalculator.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalRecurrenceCalculator.h; sourceTree = "<group>"; };
+ ADAACE6707B3973900FC48D6 /* iCalRecurrenceCalculator.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalRecurrenceCalculator.m; sourceTree = "<group>"; };
+ ADAACFEB07B6AEB500FC48D6 /* NGCardsTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NGCardsTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ ADAACFEC07B6AEB500FC48D6 /* NGCardsTests-Info.plist */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = text.xml; path = "NGCardsTests-Info.plist"; sourceTree = "<group>"; };
+ ADAAD00607B6AF7700FC48D6 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = /Library/Frameworks/SenTestingKit.framework; sourceTree = "<absolute>"; };
+ ADAAD02107B6AFD700FC48D6 /* iCalRecurrenceCalculatorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iCalRecurrenceCalculatorTests.m; sourceTree = "<group>"; };
+ ADAAD04007B6B02400FC48D6 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ ADAAD04107B6B05000FC48D6 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
+ ADBE3DF7072713AF000FEA6A /* iCalRenderer.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalRenderer.h; sourceTree = "<group>"; };
+ ADBE3DF9072713C2000FEA6A /* iCalRenderer.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalRenderer.m; sourceTree = "<group>"; };
+ ADBE3DFE072713DB000FEA6A /* fhs.make */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 5; indentWidth = 8; path = fhs.make; sourceTree = "<group>"; tabWidth = 8; };
+ ADD1FC9906E4D6D400E387F0 /* iCalEventChanges.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalEventChanges.h; sourceTree = "<group>"; };
+ ADD1FC9A06E4D6D400E387F0 /* iCalEventChanges.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalEventChanges.m; sourceTree = "<group>"; };
+ ADDF4E6006DE4FF200C4E7F8 /* NGCards.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NGCards.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ ADDF4E6206DE4FF200C4E7F8 /* NGCards-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "NGCards-Info.plist"; sourceTree = "<group>"; };
+ ADDF4F1206DE513D00C4E7F8 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 8; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
+ ADDF4F1306DE513D00C4E7F8 /* common.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
+ ADDF4F1406DE513D00C4E7F8 /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYING; sourceTree = "<group>"; };
+ ADDF4F1506DE513D00C4E7F8 /* COPYRIGHT */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYRIGHT; sourceTree = "<group>"; };
+ ADDF4F1606DE513D00C4E7F8 /* GNUmakefile */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; indentWidth = 8; path = GNUmakefile; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
+ ADDF4F1706DE513D00C4E7F8 /* GNUmakefile.postamble */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; indentWidth = 8; path = GNUmakefile.postamble; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
+ ADDF4F1806DE513D00C4E7F8 /* GNUmakefile.preamble */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; indentWidth = 8; path = GNUmakefile.preamble; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
+ ADDF4F1906DE513D00C4E7F8 /* iCalAlarm.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalAlarm.h; sourceTree = "<group>"; };
+ ADDF4F1A06DE513D00C4E7F8 /* iCalAlarm.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalAlarm.m; sourceTree = "<group>"; };
+ ADDF4F1B06DE513D00C4E7F8 /* iCalAttachment.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalAttachment.h; sourceTree = "<group>"; };
+ ADDF4F1C06DE513D00C4E7F8 /* iCalAttachment.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalAttachment.m; sourceTree = "<group>"; };
+ ADDF4F1D06DE513D00C4E7F8 /* iCalCalendar.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalCalendar.h; sourceTree = "<group>"; };
+ ADDF4F1E06DE513D00C4E7F8 /* iCalCalendar.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalCalendar.m; sourceTree = "<group>"; };
+ ADDF4F1F06DE513D00C4E7F8 /* iCalDataSource.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalDataSource.h; sourceTree = "<group>"; };
+ ADDF4F2006DE513D00C4E7F8 /* iCalDataSource.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalDataSource.m; sourceTree = "<group>"; };
+ ADDF4F2106DE513D00C4E7F8 /* iCalDateHolder.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalDateHolder.h; sourceTree = "<group>"; };
+ ADDF4F2206DE513D00C4E7F8 /* iCalDateHolder.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalDateHolder.m; sourceTree = "<group>"; };
+ ADDF4F2306DE513D00C4E7F8 /* iCalDuration.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalDuration.h; sourceTree = "<group>"; };
+ ADDF4F2406DE513D00C4E7F8 /* iCalDuration.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalDuration.m; sourceTree = "<group>"; };
+ ADDF4F2506DE513D00C4E7F8 /* IcalElements.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = IcalElements.m; sourceTree = "<group>"; };
+ ADDF4F2606DE513D00C4E7F8 /* iCalEntityObject.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalEntityObject.h; sourceTree = "<group>"; };
+ ADDF4F2706DE513D00C4E7F8 /* iCalEntityObject.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalEntityObject.m; sourceTree = "<group>"; };
+ ADDF4F2806DE513D00C4E7F8 /* iCalEvent.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalEvent.h; sourceTree = "<group>"; };
+ ADDF4F2906DE513D00C4E7F8 /* iCalEvent.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalEvent.m; sourceTree = "<group>"; };
+ ADDF4F2A06DE513D00C4E7F8 /* iCalFreeBusy.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalFreeBusy.h; sourceTree = "<group>"; };
+ ADDF4F2B06DE513D00C4E7F8 /* iCalFreeBusy.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalFreeBusy.m; sourceTree = "<group>"; };
+ ADDF4F2C06DE513D00C4E7F8 /* iCalJournal.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalJournal.h; sourceTree = "<group>"; };
+ ADDF4F2D06DE513D00C4E7F8 /* iCalJournal.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalJournal.m; sourceTree = "<group>"; };
+ ADDF4F2E06DE513D00C4E7F8 /* iCalObject.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalObject.h; sourceTree = "<group>"; };
+ ADDF4F2F06DE513D00C4E7F8 /* iCalObject.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalObject.m; sourceTree = "<group>"; };
+ ADDF4F3006DE513D00C4E7F8 /* iCalPerson.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalPerson.h; sourceTree = "<group>"; };
+ ADDF4F3106DE513D00C4E7F8 /* iCalPerson.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalPerson.m; sourceTree = "<group>"; };
+ ADDF4F3206DE513D00C4E7F8 /* IcalResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = IcalResponse.h; sourceTree = "<group>"; };
+ ADDF4F3306DE513D00C4E7F8 /* IcalResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = IcalResponse.m; sourceTree = "<group>"; };
+ ADDF4F3406DE513D00C4E7F8 /* iCalToDo.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalToDo.h; sourceTree = "<group>"; };
+ ADDF4F3506DE513D00C4E7F8 /* iCalToDo.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalToDo.m; sourceTree = "<group>"; };
+ ADDF4F3606DE513D00C4E7F8 /* iCalTrigger.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalTrigger.h; sourceTree = "<group>"; };
+ ADDF4F3706DE513D00C4E7F8 /* iCalTrigger.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalTrigger.m; sourceTree = "<group>"; };
+ ADDF4F3806DE513D00C4E7F8 /* NGCards.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = NGCards.h; sourceTree = "<group>"; };
+ ADDF4F3906DE513D00C4E7F8 /* NGCards.xmap */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text.xml; path = NGCards.xmap; sourceTree = "<group>"; };
+ ADDF4F3A06DE513D00C4E7F8 /* NSCalendarDate+ICal.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = "NSCalendarDate+ICal.h"; sourceTree = "<group>"; };
+ ADDF4F3B06DE513D00C4E7F8 /* NSCalendarDate+ICal.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "NSCalendarDate+ICal.m"; sourceTree = "<group>"; };
+ ADDF4F3C06DE513D00C4E7F8 /* NSString+ICal.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = "NSString+ICal.h"; sourceTree = "<group>"; };
+ ADDF4F3D06DE513D00C4E7F8 /* NSString+ICal.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "NSString+ICal.m"; sourceTree = "<group>"; };
+ ADDF4F3E06DE513D00C4E7F8 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ ADDF4F3F06DE513D00C4E7F8 /* Version */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; indentWidth = 8; path = Version; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
+ ADDF503B06DE528200C4E7F8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ ADDF503D06DE52F600C4E7F8 /* DOM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DOM.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/DOM.framework"; sourceTree = "<absolute>"; };
+ ADDF503E06DE52F600C4E7F8 /* EOControl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = EOControl.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/EOControl.framework"; sourceTree = "<absolute>"; };
+ ADDF503F06DE52F600C4E7F8 /* NGExtensions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NGExtensions.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/NGExtensions.framework"; sourceTree = "<absolute>"; };
+ ADDF504006DE52F600C4E7F8 /* SaxObjC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SaxObjC.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/SaxObjC.framework"; sourceTree = "<absolute>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ ADAACFE807B6AEB500FC48D6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ADAAD0A307B6B74F00FC48D6 /* Foundation.framework in Frameworks */,
+ ADAAD11107B6B75300FC48D6 /* NGExtensions.framework in Frameworks */,
+ ADAAD00707B6AF7700FC48D6 /* SenTestingKit.framework in Frameworks */,
+ ADAAD11207B6B7A100FC48D6 /* NGCards.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ ADDF4E5E06DE4FF200C4E7F8 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ADDF503C06DE528200C4E7F8 /* Foundation.framework in Frameworks */,
+ ADDF504206DE52F600C4E7F8 /* EOControl.framework in Frameworks */,
+ ADDF504306DE52F600C4E7F8 /* NGExtensions.framework in Frameworks */,
+ ADDF504406DE52F600C4E7F8 /* SaxObjC.framework in Frameworks */,
+ ADDF504106DE52F600C4E7F8 /* DOM.framework in Frameworks */,
+ AD8BF0F80701902800EC239A /* XmlRpc.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ AD596D730837697900C4D81D /* iCal */ = {
+ isa = PBXGroup;
+ children = (
+ ADDF4F7306DE516A00C4E7F8 /* Headers */,
+ ADDF4FD406DE517900C4E7F8 /* Classes */,
+ );
+ name = iCal;
+ sourceTree = "<group>";
+ };
+ AD596D830837698200C4D81D /* vCard */ = {
+ isa = PBXGroup;
+ children = (
+ AD596D860837699600C4D81D /* Headers */,
+ AD596D890837699A00C4D81D /* Classes */,
+ );
+ name = vCard;
+ sourceTree = "<group>";
+ };
+ AD596D860837699600C4D81D /* Headers */ = {
+ isa = PBXGroup;
+ children = (
+ AD596D96083769C500C4D81D /* NGVCardSaxHandler.h */,
+ AD596D8C083769C500C4D81D /* NGVCard.h */,
+ AD596D9C083769C500C4D81D /* NGVCardValue.h */,
+ AD596D98083769C500C4D81D /* NGVCardSimpleValue.h */,
+ AD596D9A083769C500C4D81D /* NGVCardStrArrayValue.h */,
+ AD596D8E083769C500C4D81D /* NGVCardAddress.h */,
+ AD596D90083769C500C4D81D /* NGVCardName.h */,
+ AD596D92083769C500C4D81D /* NGVCardOrg.h */,
+ AD596D94083769C500C4D81D /* NGVCardPhone.h */,
+ );
+ name = Headers;
+ sourceTree = "<group>";
+ };
+ AD596D890837699A00C4D81D /* Classes */ = {
+ isa = PBXGroup;
+ children = (
+ AD596D97083769C500C4D81D /* NGVCardSaxHandler.m */,
+ AD596D8D083769C500C4D81D /* NGVCard.m */,
+ AD596D9D083769C500C4D81D /* NGVCardValue.m */,
+ AD596D99083769C500C4D81D /* NGVCardSimpleValue.m */,
+ AD596D9B083769C500C4D81D /* NGVCardStrArrayValue.m */,
+ AD596D8F083769C500C4D81D /* NGVCardAddress.m */,
+ AD596D91083769C500C4D81D /* NGVCardName.m */,
+ AD596D93083769C500C4D81D /* NGVCardOrg.m */,
+ AD596D95083769C500C4D81D /* NGVCardPhone.m */,
+ );
+ name = Classes;
+ sourceTree = "<group>";
+ };
+ ADAACFFF07B6AF0E00FC48D6 /* Unit Tests */ = {
+ isa = PBXGroup;
+ children = (
+ ADAAD04007B6B02400FC48D6 /* README */,
+ ADAAD01F07B6AFA600FC48D6 /* Classes */,
+ ADAAD05C07B6B0CB00FC48D6 /* Resources */,
+ );
+ fileEncoding = 5;
+ indentWidth = 2;
+ name = "Unit Tests";
+ path = tests;
+ sourceTree = "<group>";
+ };
+ ADAAD01F07B6AFA600FC48D6 /* Classes */ = {
+ isa = PBXGroup;
+ children = (
+ ADAAD04107B6B05000FC48D6 /* common.h */,
+ ADAAD02107B6AFD700FC48D6 /* iCalRecurrenceCalculatorTests.m */,
+ );
+ name = Classes;
+ sourceTree = "<group>";
+ };
+ ADAAD05C07B6B0CB00FC48D6 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ ADAACFEC07B6AEB500FC48D6 /* NGCardsTests-Info.plist */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ ADDF4E5106DE4FC600C4E7F8 = {
+ isa = PBXGroup;
+ children = (
+ ADDF4F3E06DE513D00C4E7F8 /* README */,
+ ADDF4F1406DE513D00C4E7F8 /* COPYING */,
+ ADDF4F1506DE513D00C4E7F8 /* COPYRIGHT */,
+ ADDF4F1206DE513D00C4E7F8 /* ChangeLog */,
+ ADDF4F3F06DE513D00C4E7F8 /* Version */,
+ ADDF4F7006DE514B00C4E7F8 /* Makefiles */,
+ AD596D730837697900C4D81D /* iCal */,
+ AD596D830837698200C4D81D /* vCard */,
+ ADDF503706DE520000C4E7F8 /* Unused */,
+ ADAACFFF07B6AF0E00FC48D6 /* Unit Tests */,
+ ADDF4E6506DE500200C4E7F8 /* Resources */,
+ ADDF4E6106DE4FF200C4E7F8 /* Products */,
+ ADDF503A06DE524200C4E7F8 /* Linked Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ ADDF4E6106DE4FF200C4E7F8 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ ADDF4E6006DE4FF200C4E7F8 /* NGCards.framework */,
+ ADAACFEB07B6AEB500FC48D6 /* NGCardsTests.framework */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ ADDF4E6506DE500200C4E7F8 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ ADDF4E6206DE4FF200C4E7F8 /* NGCards-Info.plist */,
+ ADDF4F3906DE513D00C4E7F8 /* NGCards.xmap */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ ADDF4F7006DE514B00C4E7F8 /* Makefiles */ = {
+ isa = PBXGroup;
+ children = (
+ ADDF4F1606DE513D00C4E7F8 /* GNUmakefile */,
+ ADDF4F1806DE513D00C4E7F8 /* GNUmakefile.preamble */,
+ ADDF4F1706DE513D00C4E7F8 /* GNUmakefile.postamble */,
+ ADBE3DFE072713DB000FEA6A /* fhs.make */,
+ );
+ name = Makefiles;
+ sourceTree = "<group>";
+ };
+ ADDF4F7306DE516A00C4E7F8 /* Headers */ = {
+ isa = PBXGroup;
+ children = (
+ ADDF4F3806DE513D00C4E7F8 /* NGCards.h */,
+ AD596D8A083769C500C4D81D /* NGICalSaxHandler.h */,
+ ADDF4F1906DE513D00C4E7F8 /* iCalAlarm.h */,
+ ADDF4F1B06DE513D00C4E7F8 /* iCalAttachment.h */,
+ ADDF4F1D06DE513D00C4E7F8 /* iCalCalendar.h */,
+ ADDF4F1F06DE513D00C4E7F8 /* iCalDataSource.h */,
+ ADDF4F2106DE513D00C4E7F8 /* iCalDateHolder.h */,
+ ADDF4F2306DE513D00C4E7F8 /* iCalDuration.h */,
+ ADDF4F2606DE513D00C4E7F8 /* iCalEntityObject.h */,
+ AD77103C07AE8F8500F5C7A1 /* iCalRepeatableEntityObject.h */,
+ ADDF4F2806DE513D00C4E7F8 /* iCalEvent.h */,
+ ADDF4F2A06DE513D00C4E7F8 /* iCalFreeBusy.h */,
+ ADDF4F2C06DE513D00C4E7F8 /* iCalJournal.h */,
+ ADDF4F2E06DE513D00C4E7F8 /* iCalObject.h */,
+ ADDF4F3006DE513D00C4E7F8 /* iCalPerson.h */,
+ ADDF4F3406DE513D00C4E7F8 /* iCalToDo.h */,
+ ADDF4F3606DE513D00C4E7F8 /* iCalTrigger.h */,
+ ADD1FC9906E4D6D400E387F0 /* iCalEventChanges.h */,
+ ADBE3DF7072713AF000FEA6A /* iCalRenderer.h */,
+ AD770E6707AE627500F5C7A1 /* iCalRecurrenceRule.h */,
+ ADAACE6607B3973900FC48D6 /* iCalRecurrenceCalculator.h */,
+ ADDF4F3A06DE513D00C4E7F8 /* NSCalendarDate+ICal.h */,
+ );
+ fileEncoding = 5;
+ indentWidth = 2;
+ name = Headers;
+ sourceTree = "<group>";
+ };
+ ADDF4FD406DE517900C4E7F8 /* Classes */ = {
+ isa = PBXGroup;
+ children = (
+ ADDF4F1306DE513D00C4E7F8 /* common.h */,
+ AD596D8B083769C500C4D81D /* NGICalSaxHandler.m */,
+ ADDF4F1A06DE513D00C4E7F8 /* iCalAlarm.m */,
+ ADDF4F1C06DE513D00C4E7F8 /* iCalAttachment.m */,
+ ADDF4F1E06DE513D00C4E7F8 /* iCalCalendar.m */,
+ ADDF4F2006DE513D00C4E7F8 /* iCalDataSource.m */,
+ ADDF4F2206DE513D00C4E7F8 /* iCalDateHolder.m */,
+ ADDF4F2406DE513D00C4E7F8 /* iCalDuration.m */,
+ ADDF4F2706DE513D00C4E7F8 /* iCalEntityObject.m */,
+ AD77103D07AE8F8500F5C7A1 /* iCalRepeatableEntityObject.m */,
+ ADDF4F2906DE513D00C4E7F8 /* iCalEvent.m */,
+ ADDF4F2B06DE513D00C4E7F8 /* iCalFreeBusy.m */,
+ ADDF4F2D06DE513D00C4E7F8 /* iCalJournal.m */,
+ ADDF4F2F06DE513D00C4E7F8 /* iCalObject.m */,
+ ADDF4F3106DE513D00C4E7F8 /* iCalPerson.m */,
+ ADDF4F3506DE513D00C4E7F8 /* iCalToDo.m */,
+ ADDF4F3706DE513D00C4E7F8 /* iCalTrigger.m */,
+ ADD1FC9A06E4D6D400E387F0 /* iCalEventChanges.m */,
+ ADBE3DF9072713C2000FEA6A /* iCalRenderer.m */,
+ AD770E6807AE627500F5C7A1 /* iCalRecurrenceRule.m */,
+ ADAACE6707B3973900FC48D6 /* iCalRecurrenceCalculator.m */,
+ AD2EC1C008E2E630006B7836 /* iCalDailyRecurrenceCalculator.m */,
+ AD2EC1C208E2E630006B7836 /* iCalWeeklyRecurrenceCalculator.m */,
+ AD2EC1C108E2E630006B7836 /* iCalMonthlyRecurrenceCalculator.m */,
+ AD2EC1C308E2E630006B7836 /* iCalYearlyRecurrenceCalculator.m */,
+ ADDF4F3B06DE513D00C4E7F8 /* NSCalendarDate+ICal.m */,
+ );
+ fileEncoding = 5;
+ indentWidth = 2;
+ name = Classes;
+ sourceTree = "<group>";
+ };
+ ADDF503706DE520000C4E7F8 /* Unused */ = {
+ isa = PBXGroup;
+ children = (
+ ADDF4F3206DE513D00C4E7F8 /* IcalResponse.h */,
+ ADDF4F3306DE513D00C4E7F8 /* IcalResponse.m */,
+ ADDF4F2506DE513D00C4E7F8 /* IcalElements.m */,
+ ADDF4F3C06DE513D00C4E7F8 /* NSString+ICal.h */,
+ ADDF4F3D06DE513D00C4E7F8 /* NSString+ICal.m */,
+ );
+ name = Unused;
+ sourceTree = "<group>";
+ };
+ ADDF503A06DE524200C4E7F8 /* Linked Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ ADDF503B06DE528200C4E7F8 /* Foundation.framework */,
+ ADDF503E06DE52F600C4E7F8 /* EOControl.framework */,
+ ADDF503F06DE52F600C4E7F8 /* NGExtensions.framework */,
+ ADAAD00607B6AF7700FC48D6 /* SenTestingKit.framework */,
+ ADDF510206DE54BE00C4E7F8 /* sope-xml */,
+ );
+ name = "Linked Frameworks";
+ sourceTree = "<group>";
+ };
+ ADDF510206DE54BE00C4E7F8 /* sope-xml */ = {
+ isa = PBXGroup;
+ children = (
+ ADDF504006DE52F600C4E7F8 /* SaxObjC.framework */,
+ ADDF503D06DE52F600C4E7F8 /* DOM.framework */,
+ AD8BF0F70701902800EC239A /* XmlRpc.framework */,
+ );
+ name = "sope-xml";
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ ADAACFE507B6AEB500FC48D6 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ADAAD04207B6B05000FC48D6 /* common.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ ADDF4E5B06DE4FF200C4E7F8 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ADDF4F4106DE513D00C4E7F8 /* common.h in Headers */,
+ ADDF4F4706DE513D00C4E7F8 /* iCalAlarm.h in Headers */,
+ ADDF4F4906DE513D00C4E7F8 /* iCalAttachment.h in Headers */,
+ ADDF4F4B06DE513D00C4E7F8 /* iCalCalendar.h in Headers */,
+ ADDF4F4D06DE513D00C4E7F8 /* iCalDataSource.h in Headers */,
+ ADDF4F4F06DE513D00C4E7F8 /* iCalDateHolder.h in Headers */,
+ ADDF4F5106DE513D00C4E7F8 /* iCalDuration.h in Headers */,
+ ADDF4F5406DE513D00C4E7F8 /* iCalEntityObject.h in Headers */,
+ ADDF4F5606DE513D00C4E7F8 /* iCalEvent.h in Headers */,
+ ADDF4F5806DE513D00C4E7F8 /* iCalFreeBusy.h in Headers */,
+ ADDF4F5A06DE513D00C4E7F8 /* iCalJournal.h in Headers */,
+ ADDF4F5C06DE513D00C4E7F8 /* iCalObject.h in Headers */,
+ ADDF4F5E06DE513D00C4E7F8 /* iCalPerson.h in Headers */,
+ ADDF4F6206DE513D00C4E7F8 /* iCalToDo.h in Headers */,
+ ADDF4F6406DE513D00C4E7F8 /* iCalTrigger.h in Headers */,
+ ADDF4F6606DE513D00C4E7F8 /* NGCards.h in Headers */,
+ ADDF4F6806DE513D00C4E7F8 /* NSCalendarDate+ICal.h in Headers */,
+ ADD1FC9B06E4D6D400E387F0 /* iCalEventChanges.h in Headers */,
+ ADBE3DF8072713AF000FEA6A /* iCalRenderer.h in Headers */,
+ AD770E6907AE627500F5C7A1 /* iCalRecurrenceRule.h in Headers */,
+ AD77103E07AE8F8500F5C7A1 /* iCalRepeatableEntityObject.h in Headers */,
+ ADAACE6807B3973900FC48D6 /* iCalRecurrenceCalculator.h in Headers */,
+ AD596D9E083769C500C4D81D /* NGICalSaxHandler.h in Headers */,
+ AD596DA0083769C500C4D81D /* NGVCard.h in Headers */,
+ AD596DA2083769C500C4D81D /* NGVCardAddress.h in Headers */,
+ AD596DA4083769C500C4D81D /* NGVCardName.h in Headers */,
+ AD596DA6083769C500C4D81D /* NGVCardOrg.h in Headers */,
+ AD596DA8083769C500C4D81D /* NGVCardPhone.h in Headers */,
+ AD596DAA083769C500C4D81D /* NGVCardSaxHandler.h in Headers */,
+ AD596DAC083769C500C4D81D /* NGVCardSimpleValue.h in Headers */,
+ AD596DAE083769C500C4D81D /* NGVCardStrArrayValue.h in Headers */,
+ AD596DB0083769C500C4D81D /* NGVCardValue.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ ADAACFEA07B6AEB500FC48D6 /* NGCardsTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = ADA07A4D0857394900993825 /* Build configuration list for PBXNativeTarget "NGCardsTests" */;
+ buildPhases = (
+ ADAACFE507B6AEB500FC48D6 /* Headers */,
+ ADAACFE607B6AEB500FC48D6 /* Resources */,
+ ADAACFE707B6AEB500FC48D6 /* Sources */,
+ ADAACFE807B6AEB500FC48D6 /* Frameworks */,
+ ADAACFE907B6AEB500FC48D6 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 4.5.74;
+ FRAMEWORK_SEARCH_PATHS = "\"$(USER_LIBRARY_DIR)/EmbeddedFrameworks\"";
+ FRAMEWORK_VERSION = A;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ INFOPLIST_FILE = "tests/NGCardsTests-Info.plist";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ OTHER_CFLAGS = "-fobjc-exceptions";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = NGCardsTests;
+ SECTORDER_FLAGS = "";
+ TEST_AFTER_BUILD = YES;
+ WARNING_CFLAGS = "-Wmost";
+ };
+ dependencies = (
+ ADAACFEE07B6AEBF00FC48D6 /* PBXTargetDependency */,
+ );
+ name = NGCardsTests;
+ productName = NGCardsTests;
+ productReference = ADAACFEB07B6AEB500FC48D6 /* NGCardsTests.framework */;
+ productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>NGCardsTests</string>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.MySoftwareCompany.NGCardsTests</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string></string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+ productType = "com.apple.product-type.framework";
+ };
+ ADDF4E5F06DE4FF200C4E7F8 /* NGCards */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = ADA07A490857394900993825 /* Build configuration list for PBXNativeTarget "NGCards" */;
+ buildPhases = (
+ ADDF4E5B06DE4FF200C4E7F8 /* Headers */,
+ ADDF4E5C06DE4FF200C4E7F8 /* Resources */,
+ ADDF4E5D06DE4FF200C4E7F8 /* Sources */,
+ ADDF4E5E06DE4FF200C4E7F8 /* Frameworks */,
+ ADDF51AB06DE56C500C4E7F8 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 4.5.74;
+ FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ FRAMEWORK_VERSION = A;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = common.h;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ INFOPLIST_FILE = "NGCards-Info.plist";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ OTHER_CFLAGS = (
+ "-DSOPE_MAJOR_VERSION=4",
+ "-DSOPE_MINOR_VERSION=5",
+ );
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0xC1E00000,
+ "-headerpad_max_install_names",
+ );
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = NGCards;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ };
+ dependencies = (
+ );
+ name = NGCards;
+ productName = NGCards;
+ productReference = ADDF4E6006DE4FF200C4E7F8 /* NGCards.framework */;
+ productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>NGCards</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.NGCards</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
+";
+ productType = "com.apple.product-type.framework";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ ADDF4E5506DE4FC800C4E7F8 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = ADA07A510857394900993825 /* Build configuration list for PBXProject "NGCards" */;
+ buildSettings = {
+ };
+ buildStyles = (
+ ADDF4E5306DE4FC600C4E7F8 /* Development */,
+ ADDF4E5406DE4FC800C4E7F8 /* Wrapper */,
+ );
+ hasScannedForEncodings = 0;
+ mainGroup = ADDF4E5106DE4FC600C4E7F8;
+ productRefGroup = ADDF4E6106DE4FF200C4E7F8 /* Products */;
+ projectDirPath = "";
+ targets = (
+ ADDF4E5F06DE4FF200C4E7F8 /* NGCards */,
+ ADAACFEA07B6AEB500FC48D6 /* NGCardsTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ ADAACFE607B6AEB500FC48D6 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ ADDF4E5C06DE4FF200C4E7F8 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ADDF4F4206DE513D00C4E7F8 /* COPYING in Resources */,
+ ADDF4F4306DE513D00C4E7F8 /* COPYRIGHT in Resources */,
+ ADDF4F6C06DE513D00C4E7F8 /* README in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ ADAACFE907B6AEB500FC48D6 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = /Developer/Tools/RunTargetUnitTests;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ ADAACFE707B6AEB500FC48D6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ADAAD02307B6AFD700FC48D6 /* iCalRecurrenceCalculatorTests.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ ADDF4E5D06DE4FF200C4E7F8 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ADDF4F4806DE513D00C4E7F8 /* iCalAlarm.m in Sources */,
+ ADDF4F4A06DE513D00C4E7F8 /* iCalAttachment.m in Sources */,
+ ADDF4F4C06DE513D00C4E7F8 /* iCalCalendar.m in Sources */,
+ ADDF4F4E06DE513D00C4E7F8 /* iCalDataSource.m in Sources */,
+ ADDF4F5006DE513D00C4E7F8 /* iCalDateHolder.m in Sources */,
+ ADDF4F5206DE513D00C4E7F8 /* iCalDuration.m in Sources */,
+ ADDF4F5506DE513D00C4E7F8 /* iCalEntityObject.m in Sources */,
+ ADDF4F5706DE513D00C4E7F8 /* iCalEvent.m in Sources */,
+ ADDF4F5906DE513D00C4E7F8 /* iCalFreeBusy.m in Sources */,
+ ADDF4F5B06DE513D00C4E7F8 /* iCalJournal.m in Sources */,
+ ADDF4F5D06DE513D00C4E7F8 /* iCalObject.m in Sources */,
+ ADDF4F5F06DE513D00C4E7F8 /* iCalPerson.m in Sources */,
+ ADDF4F6306DE513D00C4E7F8 /* iCalToDo.m in Sources */,
+ ADDF4F6506DE513D00C4E7F8 /* iCalTrigger.m in Sources */,
+ ADDF4F6906DE513D00C4E7F8 /* NSCalendarDate+ICal.m in Sources */,
+ ADD1FC9C06E4D6D400E387F0 /* iCalEventChanges.m in Sources */,
+ ADBE3DFA072713C2000FEA6A /* iCalRenderer.m in Sources */,
+ AD770E6A07AE627500F5C7A1 /* iCalRecurrenceRule.m in Sources */,
+ AD77103F07AE8F8500F5C7A1 /* iCalRepeatableEntityObject.m in Sources */,
+ ADAACE6907B3973900FC48D6 /* iCalRecurrenceCalculator.m in Sources */,
+ AD596D9F083769C500C4D81D /* NGICalSaxHandler.m in Sources */,
+ AD596DA1083769C500C4D81D /* NGVCard.m in Sources */,
+ AD596DA3083769C500C4D81D /* NGVCardAddress.m in Sources */,
+ AD596DA5083769C500C4D81D /* NGVCardName.m in Sources */,
+ AD596DA7083769C500C4D81D /* NGVCardOrg.m in Sources */,
+ AD596DA9083769C500C4D81D /* NGVCardPhone.m in Sources */,
+ AD596DAB083769C500C4D81D /* NGVCardSaxHandler.m in Sources */,
+ AD596DAD083769C500C4D81D /* NGVCardSimpleValue.m in Sources */,
+ AD596DAF083769C500C4D81D /* NGVCardStrArrayValue.m in Sources */,
+ AD596DB1083769C500C4D81D /* NGVCardValue.m in Sources */,
+ AD2EC1C408E2E630006B7836 /* iCalDailyRecurrenceCalculator.m in Sources */,
+ AD2EC1C508E2E630006B7836 /* iCalMonthlyRecurrenceCalculator.m in Sources */,
+ AD2EC1C608E2E630006B7836 /* iCalWeeklyRecurrenceCalculator.m in Sources */,
+ AD2EC1C708E2E630006B7836 /* iCalYearlyRecurrenceCalculator.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ ADAACFEE07B6AEBF00FC48D6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = ADDF4E5F06DE4FF200C4E7F8 /* NGCards */;
+ targetProxy = ADAACFED07B6AEBF00FC48D6 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ ADA07A4A0857394900993825 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 4.5.74;
+ FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ FRAMEWORK_VERSION = A;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = common.h;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "APPLE_RUNTIME=1",
+ "NeXT_Foundation_LIBRARY=1",
+ "COCOA_Foundation_LIBRARY=1",
+ "NeXT_RUNTIME=1",
+ "COMPILE_AS_FRAMEWORK=1",
+ "DEBUG=1",
+ );
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ INFOPLIST_FILE = "NGCards-Info.plist";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ OTHER_CFLAGS = (
+ "-DSOPE_MAJOR_VERSION=4",
+ "-DSOPE_MINOR_VERSION=5",
+ );
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0xC1E00000,
+ "-headerpad_max_install_names",
+ );
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = NGCards;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ };
+ name = Development;
+ };
+ ADA07A4B0857394900993825 /* Wrapper */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEPLOYMENT_LOCATION = NO;
+ DEPLOYMENT_POSTPROCESSING = YES;
+ DSTROOT = /;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 4.5.74;
+ DYLIB_INSTALL_NAME_BASE = "@executable_path/../Frameworks/";
+ FRAMEWORK_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+ FRAMEWORK_VERSION = A;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_OPTIMIZATION_LEVEL = 3;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = common.h;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "APPLE_RUNTIME=1",
+ "NeXT_Foundation_LIBRARY=1",
+ "COCOA_Foundation_LIBRARY=1",
+ "NeXT_RUNTIME=1",
+ "COMPILE_AS_FRAMEWORK=1",
+ );
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ INFOPLIST_FILE = "NGCards-Info.plist";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ OTHER_CFLAGS = (
+ "-DSOPE_MAJOR_VERSION=4",
+ "-DSOPE_MINOR_VERSION=5",
+ );
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0xC1E00000,
+ "-headerpad_max_install_names",
+ );
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = NGCards;
+ SECTORDER_FLAGS = "";
+ SKIP_INSTALL = YES;
+ SYMROOT = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+ TEMP_DIR = "$(SYMROOT)/$(PROJECT_NAME).build";
+ UNSTRIPPED_PRODUCT = NO;
+ WARNING_CFLAGS = "-Wmost";
+ ZERO_LINK = NO;
+ };
+ name = Wrapper;
+ };
+ ADA07A4C0857394900993825 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 4.5.74;
+ FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ FRAMEWORK_VERSION = A;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = common.h;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ INFOPLIST_FILE = "NGCards-Info.plist";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ OTHER_CFLAGS = (
+ "-DSOPE_MAJOR_VERSION=4",
+ "-DSOPE_MINOR_VERSION=5",
+ );
+ OTHER_LDFLAGS = (
+ "-seg1addr",
+ 0xC1E00000,
+ "-headerpad_max_install_names",
+ );
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = NGCards;
+ SECTORDER_FLAGS = "";
+ WARNING_CFLAGS = "-Wmost";
+ };
+ name = Default;
+ };
+ ADA07A4E0857394900993825 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 4.5.74;
+ FRAMEWORK_SEARCH_PATHS = "\"$(USER_LIBRARY_DIR)/EmbeddedFrameworks\"";
+ FRAMEWORK_VERSION = A;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "APPLE_RUNTIME=1",
+ "NeXT_Foundation_LIBRARY=1",
+ "COCOA_Foundation_LIBRARY=1",
+ "NeXT_RUNTIME=1",
+ "COMPILE_AS_FRAMEWORK=1",
+ "DEBUG=1",
+ );
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ INFOPLIST_FILE = "tests/NGCardsTests-Info.plist";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ OTHER_CFLAGS = "-fobjc-exceptions";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = NGCardsTests;
+ SECTORDER_FLAGS = "";
+ TEST_AFTER_BUILD = YES;
+ WARNING_CFLAGS = "-Wmost";
+ };
+ name = Development;
+ };
+ ADA07A4F0857394900993825 /* Wrapper */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEPLOYMENT_LOCATION = NO;
+ DEPLOYMENT_POSTPROCESSING = YES;
+ DSTROOT = /;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 4.5.74;
+ DYLIB_INSTALL_NAME_BASE = "@executable_path/../Frameworks/";
+ FRAMEWORK_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+ FRAMEWORK_VERSION = A;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_OPTIMIZATION_LEVEL = 3;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "APPLE_RUNTIME=1",
+ "NeXT_Foundation_LIBRARY=1",
+ "COCOA_Foundation_LIBRARY=1",
+ "NeXT_RUNTIME=1",
+ "COMPILE_AS_FRAMEWORK=1",
+ );
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ INFOPLIST_FILE = "tests/NGCardsTests-Info.plist";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ OTHER_CFLAGS = "-fobjc-exceptions";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = NGCardsTests;
+ SECTORDER_FLAGS = "";
+ SKIP_INSTALL = YES;
+ SYMROOT = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+ TEMP_DIR = "$(SYMROOT)/$(PROJECT_NAME).build";
+ TEST_AFTER_BUILD = YES;
+ UNSTRIPPED_PRODUCT = NO;
+ WARNING_CFLAGS = "-Wmost";
+ ZERO_LINK = NO;
+ };
+ name = Wrapper;
+ };
+ ADA07A500857394900993825 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 4.5.74;
+ FRAMEWORK_SEARCH_PATHS = "\"$(USER_LIBRARY_DIR)/EmbeddedFrameworks\"";
+ FRAMEWORK_VERSION = A;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
+ GCC_WARN_UNKNOWN_PRAGMAS = NO;
+ INFOPLIST_FILE = "tests/NGCardsTests-Info.plist";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ OTHER_CFLAGS = "-fobjc-exceptions";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = NGCardsTests;
+ SECTORDER_FLAGS = "";
+ TEST_AFTER_BUILD = YES;
+ WARNING_CFLAGS = "-Wmost";
+ };
+ name = Default;
+ };
+ ADA07A520857394900993825 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Development;
+ };
+ ADA07A530857394900993825 /* Wrapper */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = (
+ ppc,
+ i386,
+ );
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Wrapper;
+ };
+ ADA07A540857394900993825 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Default;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ ADA07A490857394900993825 /* Build configuration list for PBXNativeTarget "NGCards" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ ADA07A4A0857394900993825 /* Development */,
+ ADA07A4B0857394900993825 /* Wrapper */,
+ ADA07A4C0857394900993825 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ ADA07A4D0857394900993825 /* Build configuration list for PBXNativeTarget "NGCardsTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ ADA07A4E0857394900993825 /* Development */,
+ ADA07A4F0857394900993825 /* Wrapper */,
+ ADA07A500857394900993825 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ ADA07A510857394900993825 /* Build configuration list for PBXProject "NGCards" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ ADA07A520857394900993825 /* Development */,
+ ADA07A530857394900993825 /* Wrapper */,
+ ADA07A540857394900993825 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = ADDF4E5506DE4FC800C4E7F8 /* Project object */;
+}
--- /dev/null
+{
+ "http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt" = {
+
+ // components
+
+ iCalendar = {
+ class = NSMutableDictionary; // "ICalXRoot";
+ tagKey = "tag";
+
+ ToManyRelationships = {
+ "subcomponents" = ( vcalendar );
+ };
+ };
+
+ vcalendar = {
+ class = iCalCalendar; // ICalVCalendar;
+
+ attributes = {
+ prodid = prodId;
+ version = version;
+ calscale = calscale;
+ method = method;
+ };
+
+ ToManyRelationships = {
+ events = ( vevent );
+ todos = ( vtodo );
+ journals = ( journals );
+ freeBusys = ( vfreebusy );
+ timezones = ( vtimezone );
+ };
+ };
+
+ vevent = {
+ class = iCalEvent;
+
+ attributes = {
+ };
+
+ ToManyRelationships = {
+ "alarms" = ( valarm );
+ "attendees" = ( attendee );
+ "recurrenceRules" = ( rrule );
+ "exceptionRules" = ( exrule );
+ "exceptionDates" = ( exdate );
+ };
+ };
+
+ vtodo = {
+ class = "iCalToDo";
+
+ attributes = {
+ };
+
+ ToManyRelationships = {
+ "alarms" = ( valarm );
+ "attendees" = ( attendee );
+ };
+ };
+
+ valarm = {
+ class = "iCalAlarm";
+
+ attributes = {
+ rrule = recurrenceRule;
+ };
+ };
+
+ vfreebusy = {
+ class = "iCalFreeBusy";
+
+ ToManyRelationships = {
+ "entries" = ( freebusy );
+ };
+ };
+
+ vtimezone = {
+ class = NSMutableDictionary;
+
+ attributes = {
+ tzid = timeZoneID;
+ "X-LIC-LOCATION" = location;
+ daylight = daylightInfo;
+ standard = standardInfo;
+ };
+ };
+ daylight = {
+ class = NSMutableDictionary;
+
+ attributes = {
+ tzoffsetfrom = tzOffsetFrom;
+ tzoffsetto = tzOffsetTo;
+ tzname = tzName;
+ dtstart = startDate;
+ rrule = recurrenceRule;
+ };
+ };
+ standard = {
+ class = NSMutableDictionary;
+
+ attributes = {
+ tzoffsetfrom = tzOffsetFrom;
+ tzoffsetto = tzOffsetTo;
+ tzname = tzName;
+ dtstart = startDate;
+ rrule = recurrenceRule;
+ };
+ };
+
+ // attributes
+
+ dtstamp = {
+ class = iCalDateHolder;
+ key = "timeStampAsDate";
+ tagKey = "tag";
+ contentKey = "string";
+ };
+ created = {
+ class = iCalDateHolder;
+ key = "created";
+ tagKey = "tag";
+ contentKey = "string";
+ };
+ "last-modified" = {
+ class = iCalDateHolder;
+ key = "lastModified";
+ tagKey = "tag";
+ contentKey = "string";
+ };
+
+ dtstart = {
+ class = iCalDateHolder;
+ key = "startDate";
+ attributes = {
+ tzid = tzid;
+ };
+ tagKey = "tag";
+ contentKey = "string";
+ };
+ dtend = {
+ class = iCalDateHolder;
+ key = "endDate";
+ attributes = {
+ tzid = tzid;
+ };
+ tagKey = "tag";
+ contentKey = "string";
+ };
+ exdate = {
+ class = iCalDateHolder;
+ key = "recurrenceRuleExceptionDate";
+ attributes = {
+ tzid = tzid;
+ };
+ tagKey = "tag";
+ contentKey = "string";
+ };
+ due = {
+ class = iCalDateHolder;
+ attributes = {
+ tzid = tzid;
+ };
+ tagKey = "tag";
+ contentKey = "string";
+ };
+ completed = {
+ class = iCalDateHolder;
+ attributes = {
+ tzid = tzid;
+ };
+ tagKey = "tag";
+ contentKey = "string";
+ };
+
+ duration = {
+ class = NSString;
+ };
+
+ summary = { class = NSString; };
+ description = { class = NSString; key = comment; };
+ comment = { class = NSString; key = userComment; };
+ uid = { class = NSString; };
+ action = { class = NSString; };
+ priority = { class = NSString; };
+ status = { class = NSString; };
+ transp = { class = NSString; key = transparency; };
+ sequence = { class = NSString; };
+ categories = { class = NSString; };
+ class = { class = NSString; key = accessClass; };
+ percent-complete = { class = NSString; key = "percentComplete"; };
+
+ attendee = {
+ class = iCalPerson;
+ attributes = {
+ cn = cn;
+ rsvp = rsvp;
+ role = role;
+ partstat = partStat;
+ };
+ contentKey = "email";
+ };
+ organizer = {
+ class = iCalPerson;
+ attributes = {
+ cn = cn;
+ };
+ contentKey = "email";
+ };
+
+ freebusy = {
+ class = NSString;
+ };
+ url = {
+ class = NSString;
+ };
+
+ trigger = {
+ class = iCalTrigger;
+ attributes = {
+ value = valueType;
+ };
+ contentKey = "value";
+ };
+ attach = {
+ class = iCalAttachment;
+ attributes = {
+ value = valueType;
+ };
+ contentKey = "value";
+ };
+
+ tzid = {
+ class = NSString;
+ };
+ tzname = {
+ class = NSString;
+ };
+ tzoffsetfrom = {
+ class = NSString;
+ };
+ tzoffsetto = {
+ class = NSString;
+ };
+ rrule = {
+ class = iCalRecurrenceRule;
+ /*
+ attributes = {
+ freq = rrFreq;
+ until = rrUntil;
+ count = rrCount;
+ interval = rrInterval;
+ bysecond = rrBySecondList;
+ byminute = rrByMinuteList;
+ byhour = rrByHourList;
+ byday = rrByDayList;
+ bymonthday = rrByMonthDayList;
+ byyearday = rrByYearDayList;
+ byweekno = rrByWeekNumberList;
+ bymonth = rrByMonthList;
+ bysetpos = rrBySetPosList;
+ wkst = rrWeekStart;
+ };
+ */
+ contentKey = "rrule";
+ key = "recurrenceRule";
+ };
+ location = {
+ class = NSString;
+ };
+
+ // extra tags
+
+ "X-LIC-LOCATION" = {
+ class = NSString;
+ };
+
+ "X-WR-TIMEZONE" = {
+ rejectWithContent = YES;
+ };
+ "X-WR-CALNAME" = {
+ rejectWithContent = YES;
+ };
+ "X-WR-RELCALID" = {
+ rejectWithContent = YES;
+ };
+
+ "X-MICROSOFT-CDO-TZID" = {
+ rejectWithContent = YES;
+ };
+ "X-MICROSOFT-CDO-BUSYSTATUS" = {
+ rejectWithContent = YES;
+ };
+ "X-MICROSOFT-CDO-INSTTYPE" = {
+ rejectWithContent = YES;
+ };
+ "X-MICROSOFT-CDO-INTENDEDSTATUS" = {
+ rejectWithContent = YES;
+ };
+ "X-MICROSOFT-CDO-ALLDAYEVENT" = {
+ rejectWithContent = YES;
+ };
+ "X-MICROSOFT-CDO-IMPORTANCE" = {
+ rejectWithContent = YES;
+ };
+
+ "X-PILOTID" = {
+ rejectWithContent = YES;
+ };
+ "X-PILOTSTAT" = {
+ rejectWithContent = YES;
+ };
+ };
+}
--- /dev/null
+/*
+ Copyright (C) 2005 Helge Hess
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGiCal_NGCardsSaxHandler_H__
+#define __NGiCal_NGCardsSaxHandler_H__
+
+#include <SaxObjC/SaxDefaultHandler.h>
+
+/*
+ NGCardsSaxHandler
+
+ This SAX handler is supposed to create the NGiCal object model from SAX
+ events.
+*/
+
+@class NSString, NSMutableString, NSMutableArray;
+@class NSDictionary, NSMutableDictionary;
+
+@class CardElement;
+@class CardGroup;
+
+@interface NGCardsSaxHandler : SaxDefaultHandler
+{
+ NSMutableArray *cards;
+ CardElement *currentElement;
+ CardGroup *currentCardGroup;
+
+ NSString *currentGroup;
+ unichar *content;
+ unsigned contentLength;
+
+ NSMutableDictionary *xtags;
+ NSMutableDictionary *subvalues;
+ NSMutableArray *types;
+ NSMutableDictionary *args;
+ NSMutableArray *tel;
+ NSMutableArray *adr;
+ NSMutableArray *email;
+ NSMutableArray *label;
+ NSMutableArray *url;
+ NSMutableArray *fburl;
+ NSMutableArray *caluri;
+
+ struct {
+ int isInVCardSet:1;
+ int isInVCard:1;
+ int isInN:1;
+ int isInAdr:1;
+ int isInOrg:1;
+ int isInGroup:1;
+ int isInGeo:1;
+ int collectContent:1;
+ int reserved:24;
+ } vcs;
+
+ Class topGroupClass;
+}
+
+/* results */
+
+- (NSArray *) cards;
+- (void)reset;
+
+/* content */
+
+- (void) startCollectingContent;
+- (NSArray *) finishCollectingContent;
+
+- (void) startGroupElement: (NSString *) _localName;
+- (void) endGroupElement;
+
+- (void) setTopElementClass: (Class) aGroupClass;
+
+@end
+
+#endif /* __NGiCal_NGCardsSaxHandler_H__ */
--- /dev/null
+/*
+ Copyright (C) 2005 Helge Hess
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import "NGCardsSaxHandler.h"
+#import "common.h"
+#import <string.h>
+
+#import "CardGroup.h"
+
+#ifndef XMLNS_VCARD_XML_03
+# define XMLNS_VCARD_XML_03 \
+ @"http://www.ietf.org/internet-drafts/draft-dawson-vcard-xml-dtd-03.txt"
+#endif
+
+@implementation NGCardsSaxHandler
+
+- (id) init
+{
+ if ((self = [super init]))
+ topGroupClass = nil;
+
+ return self;
+}
+
+- (void) dealloc
+{
+ if (content)
+ free(content);
+ [cards release];
+ if (currentGroup)
+ [currentGroup release];
+ [super dealloc];
+}
+
+/* results */
+
+- (NSArray *) cards
+{
+ return [[cards copy] autorelease];;
+}
+
+/* state */
+
+- (void)resetExceptResult
+{
+ if (content)
+ {
+ free(content);
+ content = NULL;
+ }
+
+ vcs.isInVCardSet = 0;
+ vcs.collectContent = 0;
+}
+
+- (void) reset
+{
+ [self resetExceptResult];
+ [cards removeAllObjects];
+}
+
+/* document events */
+
+- (void) startDocument
+{
+ if (!cards)
+ cards = [[NSMutableArray alloc] initWithCapacity:16];
+ [self reset];
+}
+
+- (void) endDocument
+{
+ [self resetExceptResult];
+}
+
+/* common tags */
+
+- (void) startValueTag: (NSString *) _tag
+ attributes: (id<SaxAttributes>) _attrs
+{
+ /* a tag with types and attributes */
+ unsigned i, count;
+
+ [types removeAllObjects];
+ [args removeAllObjects];
+
+ for (i = 0, count = [_attrs count]; i < count; i++) {
+ NSString *n, *v;
+
+ n = [_attrs nameAtIndex:i];
+ v = [_attrs valueAtIndex:i];
+
+ if ([n hasSuffix:@".type"] || [n isEqualToString:@"TYPE"]) {
+ /*
+ Note: types cannot be separated by comma! Its indeed always a space,eg
+ "work pref voice"
+ If you find commas, usually the vCard is broken.
+ */
+ NSEnumerator *e;
+ NSString *k;
+
+ e = [[v componentsSeparatedByString:@" "] objectEnumerator];
+ while ((k = [e nextObject]) != nil) {
+ k = [k uppercaseString];
+ if ([types containsObject:k]) continue;
+ [types addObject:k];
+ }
+ }
+ else
+ [args setObject:v forKey:n];
+ }
+}
+
+- (void)endValueTag
+{
+ [types removeAllObjects];
+ [args removeAllObjects];
+}
+
+/* handle elements */
+
+- (void) startGroup: (NSString *)_name
+{
+ vcs.isInGroup = 1;
+ ASSIGNCOPY(currentGroup, _name);
+}
+
+- (void) endGroup
+{
+ vcs.isInGroup = 0;
+ [currentGroup release];
+ currentGroup = nil;
+}
+
+- (void)startVCardSet
+{
+ currentCardGroup = nil;
+ currentGroup = nil;
+ vcs.isInVCardSet = 1;
+}
+
+- (void)endVCardSet
+{
+ vcs.isInVCardSet = 0;
+}
+
+/* element events */
+
+- (void) startElement:(NSString *)_localName
+ namespace:(NSString *)_ns
+ rawName:(NSString *)_rawName
+ attributes:(id<SaxAttributes>)_attrs
+{
+ unsigned int count, max;
+ Class elementClass;
+
+// NSLog (@"startElement localName: '%@'", _localName);
+
+ if ([_localName isEqualToString: @"vCardSet"])
+ [self startVCardSet];
+ else if ([_localName isEqualToString: @"group"])
+ [self startGroup: [_attrs valueAtIndex: 0]];
+ else if ([_localName isEqualToString: @"container"])
+ [self startGroupElement: [_attrs valueAtIndex: 0]];
+ else
+ {
+ if (currentCardGroup)
+ elementClass
+ = [currentCardGroup classForTag: [_localName uppercaseString]];
+ else
+ elementClass = topGroupClass;
+
+ if (!elementClass)
+ elementClass = [CardElement class];
+
+ currentElement = [elementClass elementWithTag: _localName];
+ [currentElement setTag: _localName];
+ if (currentGroup)
+ [currentElement setGroup: currentGroup];
+
+ max = [_attrs count];
+ for (count = 0; count < max; count++)
+ [currentElement addAttribute: [_attrs nameAtIndex: count]
+ value: [_attrs valueAtIndex: count]];
+
+ [currentCardGroup addChild: currentElement];
+ [self startCollectingContent];
+ }
+}
+
+- (void) endElement: (NSString *)_localName
+ namespace: (NSString *)_ns
+ rawName: (NSString *)_rawName
+{
+// NSLog (@"endElement localName: '%@'", _localName);
+ if ([_localName isEqualToString: @"vCardSet"])
+ [self endVCardSet];
+ else if ([_localName isEqualToString: @"group"])
+ [self endGroup];
+ else if ([_localName isEqualToString: @"container"])
+ [self endGroupElement];
+ else
+ [currentElement addValues: [self finishCollectingContent]];
+}
+
+/* content */
+
+- (void) startCollectingContent
+{
+ if (content) {
+ free(content);
+ content = NULL;
+ }
+ vcs.collectContent = 1;
+}
+
+- (NSArray *) finishCollectingContent
+{
+ NSArray *contentValues;
+ NSString *s;
+
+ vcs.collectContent = 0;
+
+ if (content && contentLength)
+ {
+ s = [NSString stringWithCharacters: content
+ length: contentLength];
+ free (content);
+ content = NULL;
+// NSLog (@"content: '%@'", s);
+ contentValues = [s componentsSeparatedByString: @";"];
+ }
+ else
+ contentValues = nil;
+
+ return contentValues;
+}
+
+- (void) characters:(unichar *)_chars
+ length:(int)_len
+{
+ if (_len && _chars)
+ {
+ if (!content)
+ {
+ /* first content */
+ contentLength = _len;
+ content = calloc (_len + 1, sizeof(unichar));
+ memcpy (content, _chars, (_len * sizeof(unichar)));
+ }
+ else
+ {
+ /* increase content */
+ content =
+ realloc (content, (contentLength + _len+2) * sizeof(unichar));
+ memcpy (&(content[contentLength]), _chars,
+ (_len * sizeof(unichar)));
+ contentLength += _len;
+ }
+ content[contentLength] = 0;
+ }
+}
+
+- (void) startGroupElement: (NSString *) _localName
+{
+ CardGroup *newGroup;
+ Class groupClass;
+
+// NSLog (@"startGroupElement localName: '%@'", _localName);
+
+ if (currentCardGroup)
+ {
+ groupClass
+ = [currentCardGroup classForTag: [_localName uppercaseString]];
+ if (!groupClass)
+ groupClass = [CardGroup class];
+
+ newGroup = [groupClass groupWithTag: _localName];
+ [currentCardGroup addChild: newGroup];
+ }
+ else
+ {
+ if (topGroupClass)
+ groupClass = topGroupClass;
+ else
+ groupClass = [CardGroup class];
+
+ newGroup = [groupClass groupWithTag: _localName];
+ [cards addObject: newGroup];
+ }
+
+ currentCardGroup = newGroup;
+}
+
+- (void) endGroupElement
+{
+// NSLog (@"endGroupElement localName: '%@'", _localName);
+
+ if (currentCardGroup)
+ currentCardGroup = [currentCardGroup parent];
+}
+
+- (void) setTopElementClass: (Class) aGroupClass
+{
+ topGroupClass = aGroupClass;
+}
+
+@end /* NGCardsSaxHandler */
--- /dev/null
+/*
+ Copyright (C) 2005 Helge Hess
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGiCal_NGVCard_H__
+#define __NGiCal_NGVCard_H__
+
+#import "CardGroup.h"
+
+/*
+ NGVCard
+
+ Represents a vCard object.
+
+ XML DTD in Dawson-03 Draft:
+ <!ELEMENT vCard (%prop.man;, (%prop.opt;)*)>
+
+ <!ATTLIST vCard
+ %attr.lang;
+ xmlns CDATA #FIXED
+ 'http://www.ietf.org/internet-drafts/draft-dawson-vcard-xml-dtd-02.txt'
+ xmlns:vcf CDATA #FIXED
+ 'http://www.ietf.org/internet-drafts/draft-dawson-vcard-xml-dtd-02.txt'
+ version CDATA #REQUIRED
+ rev CDATA #IMPLIED
+ uid CDATA #IMPLIED
+ prodid CDATA #IMPLIED
+ class (PUBLIC | PRIVATE | CONFIDENTIAL) "PUBLIC"
+ value NOTATION (VCARD) #IMPLIED>
+ <!-- version - Must be "3.0" if document conforms to this spec -->
+ <!-- rev - ISO 8601 formatted date or date/time string -->
+ <!-- uid - UID associated with the object described by the vCard -->
+ <!-- prodid - ISO 9070 FPI for product that generated vCard -->
+ <!-- class - Security classification for vCard information -->
+
+ Mandatory elements:
+ n
+ fn
+*/
+
+@class NSArray;
+@class NSDictionary;
+@class NSString;
+
+@interface NGVCard : CardGroup
+
++ (id) cardWithUid: (NSString *) _uid;
+- (id) initWithUid: (NSString *) _uid;
+
+/* accessors */
+
+- (void) setVersion: (NSString *) _version;
+- (NSString *) version;
+
+- (void) setUid: (NSString *) _uid;
+- (NSString *) uid;
+
+- (void) setPreferred: (CardElement *) aChild;
+
+- (void) setVClass: (NSString *) _s;
+- (NSString *) vClass;
+- (void) setVName: (NSString *) _s;
+- (NSString *) vName;
+- (void) setProdID: (NSString *) _s;
+- (NSString *) prodID;
+- (void) setProfile: (NSString *) _s;
+- (NSString *) profile;
+- (void) setSource: (NSString *) _s;
+- (NSString *) source;
+
+- (void) setFn: (NSString *) _fn;
+- (NSString *) fn;
+- (void) setNickname: (NSString *) aValue;
+- (NSString *) nickname;
+
+- (void) setRole: (NSString *) _s;
+- (NSString *) role;
+- (void) setTitle: (NSString *) _title;
+- (NSString *) title;
+- (void) setBday: (NSString *) _bday;
+- (NSString *) bday;
+- (void) setNote: (NSString *) _note;
+- (NSString *) note;
+- (void) setTz: (NSString *) _tz;
+- (NSString *) tz;
+
+- (void) addTel: (NSString *) phoneNumber
+ types: (NSArray *) types;
+- (void) addEmail: (NSString *) emailAddress
+ types: (NSArray *) types;
+
+- (void) setNWithFamily: (NSString *) family
+ given: (NSString *) given
+ additional: (NSString *) additional
+ prefixes: (NSString *) prefixes
+ suffixes: (NSString *) suffixes;
+- (NSArray *) n;
+
+- (void) setOrg: (NSString *) anOrg
+ units: (NSArray *) someUnits;
+- (NSArray *) org;
+
+// - (void) setN: (NGVCardName *) _v;
+// - (NGVCardName *) n;
+// - (void) setOrg: (NGVCardOrg *) _v;
+// - (NGVCardOrg *) org;
+
+// - (void) setCategories: (id) _v;
+// - (NGVCardStrArrayValue *) categories;
+
+// - (void) setTel: (NSArray *) _tel;
+// - (NSArray *) tel;
+// - (void) setAdr: (NSArray *) _adr;
+// - (NSArray *) adr;
+// - (void) setEmail: (NSArray *) _array;
+// - (NSArray *) email;
+// - (void) setLabel: (NSArray *) _array;
+// - (NSArray *) label;
+// - (void) setUrl: (NSArray *) _url;
+// - (NSArray *) url;
+
+// - (void) setFreeBusyURL: (NSArray *) _v;
+// - (NSArray *) freeBusyURL;
+// - (void) setCalURI: (NSArray *) _calURI;
+// - (NSArray *) calURI;
+
+// - (void) setX: (NSDictionary *) _dict;
+// - (NSDictionary *) x;
+
+/* convenience */
+
+- (NSString *) preferredEMail;
+- (NSString *) preferredTel;
+- (CardElement *) preferredAdr;
+
+@end
+
+#endif /* __NGiCal_NGVCard_H__ */
--- /dev/null
+/*
+ Copyright (C) 2005 Helge Hess
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSEnumerator.h>
+#import <Foundation/NSString.h>
+
+#import "NSArray+NGCards.h"
+
+#import "NGVCard.h"
+
+@implementation NGVCard
+
++ (id) parseSingleFromSource: (id) source
+{
+ NGVCard *newCard;
+
+ newCard = [super parseSingleFromSource: source];
+ [newCard setVersion: @"3.0"];
+
+ return newCard;
+}
+
++ (id) cardWithUid: (NSString *) _uid
+{
+ NGVCard *newCard;
+
+ newCard = [[self alloc] initWithUid: _uid];
+ [newCard autorelease];
+
+ return newCard;
+}
+
+- (id) initWithUid: (NSString *) _uid
+{
+ if ((self = [self init]))
+ {
+ [self setTag: @"vcard"];
+ [self setUid: _uid];
+ [self setVersion: @"3.0"];
+ }
+
+ return self;
+}
+
+/* class mapping */
+- (Class) classForTag: (NSString *) classTag
+{
+ Class tagClass;
+
+ tagClass = Nil;
+ if ([classTag isEqualToString: @"PRODID"]
+ || [classTag isEqualToString: @"PRODID"]
+ || [classTag isEqualToString: @"PROFILE"]
+ || [classTag isEqualToString: @"UID"]
+ || [classTag isEqualToString: @"CLASS"]
+ || [classTag isEqualToString: @"N"]
+ || [classTag isEqualToString: @"FN"]
+ || [classTag isEqualToString: @"ORG"]
+ || [classTag isEqualToString: @"ADR"]
+ || [classTag isEqualToString: @"TEL"]
+ || [classTag isEqualToString: @"TZ"]
+ || [classTag isEqualToString: @"URL"]
+ || [classTag isEqualToString: @"LABEL"]
+ || [classTag isEqualToString: @"EMAIL"]
+ || [classTag isEqualToString: @"NICKNAME"]
+ || [classTag isEqualToString: @"NOTE"]
+ || [classTag isEqualToString: @"BDAY"]
+ || [classTag isEqualToString: @"TITLE"]
+ || [classTag isEqualToString: @"VERSION"])
+ tagClass = [CardElement class];
+ else
+ tagClass = [super classForTag: classTag];
+
+ return tagClass;
+}
+
+- (void) setPreferred: (CardElement *) aChild
+{
+ NSEnumerator *elements;
+ CardElement *element;
+
+ if (![aChild hasAttribute: @"type" havingValue: @"pref"])
+ {
+ elements = [[children cardElementsWithTag: tag] objectEnumerator];
+ element = [elements nextObject];
+ while (element)
+ {
+ [element removeValue: @"pref" fromAttribute: @"type"];
+ element = [elements nextObject];
+ }
+ [aChild addAttribute: @"type" value: @"pref"];
+ }
+}
+
+/* helpers */
+- (NSArray *) childrenWithType: (NSString *) aType
+{
+ return [self childrenWithAttribute: @"type" havingValue: aType];
+}
+
+/* accessors */
+
+- (void) setVersion: (NSString *) _version
+{
+ [[self uniqueChildWithTag: @"version"] setValue: 0 to: _version];
+}
+
+- (NSString *) version
+{
+ return [[self uniqueChildWithTag: @"version"] value: 0];
+}
+
+- (void) setUid: (NSString *) _uid
+{
+ [[self uniqueChildWithTag: @"uid"] setValue: 0 to: _uid];
+}
+
+- (NSString *) uid
+{
+ return [[self uniqueChildWithTag: @"uid"] value: 0];
+}
+
+- (void) setVClass: (NSString *) _class
+{
+ [[self uniqueChildWithTag: @"class"] setValue: 0 to: _class];
+}
+
+- (NSString *) vClass
+{
+ return [[self uniqueChildWithTag: @"class"] value: 0];
+}
+
+- (void) setVName: (NSString *) _vname
+{
+ [[self uniqueChildWithTag: @"vname"] setValue: 0 to: _vname];
+}
+
+- (NSString *) vName
+{
+ return [[self uniqueChildWithTag: @"vname"] value: 0];
+}
+
+- (void) setProdID: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"prodid"] setValue: 0 to: _value];
+}
+
+- (NSString *) prodID
+{
+ return [[self uniqueChildWithTag: @"prodid"] value: 0];
+}
+
+- (void) setProfile: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"profile"] setValue: 0 to: _value];
+}
+
+- (NSString *) profile
+{
+ return [[self uniqueChildWithTag: @"profile"] value: 0];
+}
+
+- (void) setSource: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"source"] setValue: 0 to: _value];
+}
+
+- (NSString *) source
+{
+ return [[self uniqueChildWithTag: @"source"] value: 0];
+}
+
+- (void) setFn: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"fn"] setValue: 0 to: _value];
+}
+
+- (NSString *) fn
+{
+ return [[self uniqueChildWithTag: @"fn"] value: 0];
+}
+
+- (void) setRole: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"role"] setValue: 0 to: _value];
+}
+
+- (NSString *) role
+{
+ return [[self uniqueChildWithTag: @"role"] value: 0];
+}
+
+- (void) setTitle: (NSString *) _title
+{
+ [[self uniqueChildWithTag: @"title"] setValue: 0 to: _title];
+}
+
+- (NSString *) title
+{
+ return [[self uniqueChildWithTag: @"title"] value: 0];
+}
+
+- (void) setBday: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"bday"] setValue: 0 to: _value];
+}
+
+- (NSString *) bday
+{
+ return [[self uniqueChildWithTag: @"bday"] value: 0];
+}
+
+- (void) setNote: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"note"] setValue: 0 to: _value];
+}
+
+- (NSString *) note
+{
+ return [[self uniqueChildWithTag: @"note"] value: 0];
+}
+
+- (void) setTz: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"tz"] setValue: 0 to: _value];
+}
+
+- (NSString *) tz
+{
+ return [[self uniqueChildWithTag: @"tz"] value: 0];
+}
+
+- (void) setNickname: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"nickname"] setValue: 0 to: _value];
+}
+
+- (NSString *) nickname
+{
+ return [[self uniqueChildWithTag: @"nickname"] value: 0];
+}
+
+- (void) addTel: (NSString *) phoneNumber
+ types: (NSArray *) types
+{
+ [self addChildWithTag: @"tel" types: types singleValue: phoneNumber];
+}
+
+- (void) addEmail: (NSString *) emailAddress
+ types: (NSArray *) types
+{
+ [self addChildWithTag: @"email"
+ types: types
+ singleValue: emailAddress];
+}
+
+- (void) setNWithFamily: (NSString *) family
+ given: (NSString *) given
+ additional: (NSString *) additional
+ prefixes: (NSString *) prefixes
+ suffixes: (NSString *) suffixes
+{
+ CardElement *n;
+
+ n = [self uniqueChildWithTag: @"n"];
+ if (family)
+ [n setValue: 0 to: family];
+ if (given)
+ [n setValue: 1 to: given];
+ if (additional)
+ [n setValue: 2 to: additional];
+ if (prefixes)
+ [n setValue: 3 to: prefixes];
+ if (suffixes)
+ [n setValue: 4 to: suffixes];
+}
+
+- (NSArray *) n
+{
+ NSArray *elements, *n;
+
+ elements = [self childrenWithTag: @"n"];
+ if ([elements count] > 0)
+ n = [[elements objectAtIndex: 0] values];
+ else
+ n = nil;
+
+ return n;
+}
+
+- (void) setOrg: (NSString *) anOrg
+ units: (NSArray *) someUnits
+{
+ CardElement *org;
+ unsigned int count, max;
+
+ org = [self uniqueChildWithTag: @"org"];
+ if (anOrg)
+ [org setValue: 0 to: anOrg];
+ if (someUnits)
+ {
+ max = [someUnits count];
+ for (count = 0; count < max; count++)
+ [org setValue: count + 1 to: [someUnits objectAtIndex: count]];
+ }
+}
+
+- (NSArray *) org
+{
+ NSArray *elements, *org;
+
+ elements = [self childrenWithTag: @"org"];
+ if ([elements count] > 0)
+ org = [[elements objectAtIndex: 0] values];
+ else
+ org = nil;
+
+ return org;
+}
+
+// - (void) setOrg: (NGVCardOrg *) _v
+// {
+// ASSIGNCOPY(self->org, _v);
+// }
+
+// - (NGVCardOrg *)org {
+// return self->org;
+// }
+
+// - (void)setNickname: (id) _v
+// {
+// if (![_v isKindOfClass:[NGVCardStrArrayValue class]] && [_v isNotNull])
+// _v = [[[NGVCardStrArrayValue alloc] initWithPropertyList:_v] autorelease];
+
+// ASSIGNCOPY(self->nickname, _v);
+// }
+
+// - (NGVCardStrArrayValue *) nickname
+// {
+// return self->nickname;
+// }
+
+// - (void) setCategories: (id) _v
+// {
+// if (![_v isKindOfClass:[NGVCardStrArrayValue class]] && [_v isNotNull])
+// _v = [[[NGVCardStrArrayValue alloc] initWithPropertyList:_v] autorelease];
+
+// ASSIGNCOPY(self->categories, _v);
+// }
+
+// - (NGVCardStrArrayValue *) categories
+// {
+// return self->categories;
+// }
+
+// - (void) setTel: (NSArray *) _tel
+// {
+// ASSIGNCOPY(self->tel, _tel);
+// }
+
+// - (NSArray *) tel
+// {
+// return [self childrenWithTag: @"tel"];
+// }
+
+// - (void) setAdr: (NSArray *) _adr
+// {
+// ASSIGNCOPY(self->adr, _adr);
+// }
+
+// - (NSArray *) adr
+// {
+// return self->adr;
+// }
+
+// - (void) setEmail: (NSArray *) _email
+// {
+// ASSIGNCOPY(self->email, _email);
+// }
+
+// - (NSArray *) email
+// {
+// return [self childrenWithTag: @"email"];
+// }
+
+// - (void) setLabel: (NSArray *) _label
+// {
+// ASSIGNCOPY(self->label, _label);
+// }
+
+// - (NSArray *) label
+// {
+// return [self childrenWithTag: @"email"];
+// }
+
+// - (void) setUrl: (NSArray *) _url
+// {
+// ASSIGNCOPY(self->url, _url);
+// }
+
+// - (NSArray *) url
+// {
+// return self->url;
+// }
+
+// - (void) setFreeBusyURL: (NSArray *) _v
+// {
+// ASSIGNCOPY(self->fburl, _v);
+// }
+
+// - (NSArray *) freeBusyURL
+// {
+// return self->fburl;
+// }
+
+// - (void) setCalURI: (NSArray *) _v
+// {
+// ASSIGNCOPY(self->caluri, _v);
+// }
+
+// - (NSArray *) calURI
+// {
+// return self->caluri;
+// }
+
+// - (void) setX: (NSDictionary *) _dict
+// {
+// ASSIGNCOPY(self->x, _dict);
+// }
+
+// - (NSDictionary *) x
+// {
+// return self->x;
+// }
+
+/* convenience */
+
+- (CardElement *) _preferredElementWithTag: (NSString *) aTag
+{
+ NSArray *elements, *prefElements;
+ CardElement *element;
+
+ elements = [self childrenWithTag: aTag];
+ if (elements && [elements count] > 0)
+ {
+ prefElements = [elements cardElementsWithAttribute: @"type"
+ havingValue: @"pref"];
+ if (prefElements && [prefElements count] > 0)
+ element = [prefElements objectAtIndex: 0];
+ else
+ element = [elements objectAtIndex: 0];
+ }
+ else
+ element = nil;
+
+ return element;
+}
+
+- (NSString *) preferredEMail
+{
+ return [[self _preferredElementWithTag: @"email"] value: 0];
+}
+
+- (NSString *) preferredTel
+{
+ return [[self _preferredElementWithTag: @"tel"] value: 0];
+}
+
+- (CardElement *) preferredAdr
+{
+ return [self _preferredElementWithTag: @"adr"];
+}
+
+/* description */
+
+- (void) appendAttributesToDescription: (NSMutableString *) _ms
+{
+ if ([self uid]) [_ms appendFormat:@" uid='%@'", [self uid]];
+
+// if ([[self tel] count] > 0) [_ms appendFormat:@" tel=%@", [self tel];
+// if ([[self adr] count])
+// [_ms appendFormat:@" adr=%@", [self adr]];
+// if ([[self email] count])
+// [_ms appendFormat:@" email=%@", [self email]];
+// if ([[self label] count])
+// [_ms appendFormat:@" label=%@", [self label]];
+// if ([[self x] count])
+// [_ms appendFormat:@" x=%@", [self x]];
+}
+
+- (NSString *) description
+{
+ NSMutableString *str = nil;
+
+ str = [NSMutableString stringWithCapacity:64];
+ [str appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
+ [self appendAttributesToDescription:str];
+ [str appendString:@">"];
+ return str;
+}
+
+@end /* NGVCard */
--- /dev/null
+/* NSArray+NGCards.h - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef NSARRAY_NGCARDS_H
+#define NSARRAY_NGCARDS_H
+
+#import <Foundation/NSArray.h>
+
+@interface NSArray (NGCardsExtensions)
+
+- (NSString *) valueForCaseInsensitiveString: (NSString *) aString;
+
+- (BOOL) hasCaseInsensitiveString: (NSString *) aString;
+
+- (NSArray *) cardElementsWithTag: (NSString *) aTag;
+- (NSArray *) cardElementsWithAttribute: (NSString *) anAttribute
+ havingValue: (NSString *) aValue;
+
+- (NSArray *) renderedForCards;
+
+@end
+
+#endif /* NSARRAY_NGCARDS_H */
--- /dev/null
+/* NSArray+NGCards.m - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/NSString.h>
+
+#import "CardElement.h"
+#import "NSString+NGCards.h"
+
+#import "NSArray+NGCards.h"
+
+@implementation NSArray (NGCardsExtensions)
+
+- (NSString *) valueForCaseInsensitiveString: (NSString *) aString
+{
+ NSString *currentString, *resultString, *cmpString;
+ unsigned int count, max;
+ BOOL found;
+
+ found = NO;
+
+ cmpString = [aString uppercaseString];
+ max = [self count];
+ count = 0;
+
+ currentString = nil;
+ while (!found && count < max)
+ {
+ currentString = [self objectAtIndex: count];
+ if ([[currentString uppercaseString] isEqualToString: cmpString])
+ found = YES;
+ else
+ count++;
+ }
+
+ if (found)
+ resultString = currentString;
+ else
+ resultString = nil;
+
+ return resultString;
+}
+
+- (BOOL) hasCaseInsensitiveString: (NSString *) aString
+{
+ return ([self valueForCaseInsensitiveString: aString] != nil);
+}
+
+- (NSArray *) cardElementsWithTag: (NSString *) aTag
+{
+ NSMutableArray *matchingElements;
+ NSEnumerator *allElements;
+ CardElement *currentElement;
+ NSString *cmpTag, *currentTag;
+
+ cmpTag = [aTag uppercaseString];
+
+ matchingElements = [NSMutableArray new];
+ [matchingElements autorelease];
+
+ allElements = [self objectEnumerator];
+ currentElement = [allElements nextObject];
+ while (currentElement)
+ {
+ currentTag = [[currentElement tag] uppercaseString];
+ if ([currentTag isEqualToString: cmpTag])
+ [matchingElements addObject: currentElement];
+ currentElement = [allElements nextObject];
+ }
+
+ return matchingElements;
+}
+
+- (NSArray *) cardElementsWithAttribute: (NSString *) anAttribute
+ havingValue: (NSString *) aValue
+{
+ NSMutableArray *matchingElements;
+ NSEnumerator *allElements;
+ CardElement *currentElement;
+
+ allElements = [self objectEnumerator];
+
+ matchingElements = [NSMutableArray new];
+ [matchingElements autorelease];
+ currentElement = [allElements nextObject];
+ while (currentElement)
+ {
+ if ([currentElement hasAttribute: anAttribute
+ havingValue: aValue])
+ [matchingElements addObject: currentElement];
+ currentElement = [allElements nextObject];
+ }
+
+ return matchingElements;
+}
+
+- (NSArray *) renderedForCards
+{
+ NSMutableArray *purified;
+ NSString *string;
+ NSEnumerator *strings;
+
+ purified = [NSMutableArray arrayWithCapacity: [self count]];
+ strings = [self objectEnumerator];
+ string = [strings nextObject];
+ while (string)
+ {
+ [purified addObject: [string escapedForCards]];
+ string = [strings nextObject];
+ }
+
+ return purified;
+}
+
+@end
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGiCal_NSCalendarDate_ICal_H__
+#define __NGiCal_NSCalendarDate_ICal_H__
+
+#import <Foundation/NSCalendarDate.h>
+
+@class NSTimeZone;
+
+@interface NSCalendarDate(iCalRepresentation)
+
++ (id)calendarDateWithICalRepresentation:(NSString *)_iCalRep;
+
+/* represention */
+
+- (NSString *)icalStringWithTimeZone:(NSTimeZone *)_tz;
+- (NSString *)icalString;
+
+@end
+
+@interface NSCalendarDate (iCalRecurrenceCalculatorExtensions)
+- (unsigned)yearsBetweenDate:(NSCalendarDate *)_date;
+- (unsigned)monthsBetweenDate:(NSCalendarDate *)_date;
+- (unsigned)daysBetweenDate:(NSCalendarDate *)_date;
+@end
+
+#endif /* __NGiCal_NSCalendarDate_ICal_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "NSCalendarDate+ICal.h"
+#include "iCalDateHolder.h"
+#include "common.h"
+
+static NSTimeZone *gmt = nil;
+static inline void _setupGMT(void) {
+ if (gmt == nil)
+ gmt = [[NSTimeZone timeZoneWithAbbreviation:@"GMT"] retain];
+}
+
+@interface iCalDateHolder (PrivateAPI)
+- (id)awakeAfterUsingSaxDecoder:(id)_decoder;
+@end
+
+@implementation NSCalendarDate(iCalRepresentation)
+
+/* represention */
+
+static NSString *gmtcalfmt = @"%Y%m%dT%H%M%SZ";
+
++ (id)calendarDateWithICalRepresentation:(NSString *)_iCalRep {
+ iCalDateHolder *dh;
+ NSCalendarDate *date;
+
+ dh = [[iCalDateHolder alloc] init];
+ [dh setString:_iCalRep];
+ date = [dh awakeAfterUsingSaxDecoder:nil];
+ [dh release];
+ return date;
+}
+
+- (NSString *)icalStringInGMT {
+ NSTimeZone *oldtz;
+ NSString *s;
+ _setupGMT();
+
+ /* set GMT as timezone */
+ oldtz = [[self timeZone] retain];
+ if (oldtz == gmt) {
+ [oldtz release];
+ oldtz = nil;
+ }
+ else {
+ [self setTimeZone:gmt];
+ }
+
+ /* calc string */
+ s = [self descriptionWithCalendarFormat:gmtcalfmt];
+
+ /* restore old timezone */
+ if (oldtz) {
+ [self setTimeZone:oldtz];
+ [oldtz release];
+ }
+
+ return s;
+}
+
+- (NSString *)icalStringWithTimeZone:(NSTimeZone *)_tz {
+ _setupGMT();
+
+ if (_tz == gmt || _tz == nil)
+ return [self icalStringInGMT];
+ else if ([_tz isEqual:gmt])
+ return [self icalStringInGMT];
+ else {
+ /* not in GMT */
+ NSLog(@"WARNING(%s): arbitary timezones not supported yet: %@",
+ __PRETTY_FUNCTION__, _tz);
+ return [self icalStringInGMT];
+ }
+}
+
+- (NSString *)icalString {
+ _setupGMT();
+ return [self icalStringWithTimeZone:gmt];
+}
+
+@end /* NSDate(ICalValue) */
+
+
+#ifndef ABS
+#define ABS(a) ((a) < 0 ? -(a) : (a))
+#endif
+
+@implementation NSCalendarDate (iCalRecurrenceCalculatorExtensions)
+
+- (unsigned)yearsBetweenDate:(NSCalendarDate *)_date {
+ return ABS([self yearOfCommonEra] - [_date yearOfCommonEra]);
+}
+
+- (unsigned)monthsBetweenDate:(NSCalendarDate *)_date {
+ NSCalendarDate *start, *end;
+ NSComparisonResult order;
+ int yDiff;
+
+ order = [self compare:_date];
+ if (order == NSOrderedSame)
+ return 0;
+ else if (order == NSOrderedAscending) {
+ start = self;
+ end = _date;
+ }
+ else {
+ start = _date;
+ end = self;
+ }
+ yDiff = [end yearOfCommonEra] - [start yearOfCommonEra];
+ if (yDiff > 0) {
+ unsigned monthsRemaining, monthsToGo;
+
+ monthsRemaining = 12 - [start monthOfYear];
+ monthsToGo = [end monthOfYear];
+ yDiff -= 1;
+ return monthsRemaining + monthsToGo + (12 * yDiff);
+ }
+ /* start and end in same year, calculate plain diff */
+ return [end monthOfYear] - [start monthOfYear];
+}
+
+- (unsigned)daysBetweenDate:(NSCalendarDate *)_date {
+ return ABS([self julianNumber] - [_date julianNumber]);
+}
+@end /* NSCalendarDate (iCalRecurrenceCalculatorExtensions) */
--- /dev/null
+/* NSDate+NGCards.h - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef NSDATE_NGCARDS_H
+#define NSDATE_NGCARDS_H
+
+#import <Foundation/NSDate.h>
+#import <Foundation/NSCalendarDate.h>
+
+#import "CardElement.h"
+
+@interface NSDate (NGCardsExtensions)
+
+- (NSString *) iCalFormattedDateTimeString;
+- (NSString *) iCalFormattedDateString;
+
+@end
+
+#endif /* NSDATE_NGCARDS_H */
--- /dev/null
+/* NSDate+NGCards.m - this file is part of SOGo
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/NSString.h>
+
+#import "CardElement.h"
+
+#import "NSCalendarDate+NGCards.h"
+#import "NSString+NGCards.h"
+
+@implementation NSCalendarDate (NGCardsExtensions)
+
+- (NSString *) iCalFormattedDateTimeString
+{
+ return [NSString stringWithFormat: @"%.4d%.2d%.2dT%.2d%.2d%.2d",
+ [self yearOfCommonEra], [self monthOfYear],
+ [self dayOfMonth], [self hourOfDay],
+ [self minuteOfHour], [self secondOfMinute]];
+}
+
+- (NSString *) iCalFormattedDateString
+{
+ return [NSString stringWithFormat: @"%.4d%.2d%.2d",
+ [self yearOfCommonEra], [self monthOfYear],
+ [self dayOfMonth]];
+}
+
+@end
--- /dev/null
+/* NSDictionary+NGCards.h - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef NSDICTIONARY_NGCARDS_H
+#define NSDICTIONARY_NGCARDS_H
+
+#import <Foundation/NSDictionary.h>
+
+@interface NSDictionary (NGCardsExtensions)
+
+- (id) objectForCaseInsensitiveKey: (NSString *) aKey;
+
+@end
+
+#endif /* NSDICTIONARY_NGCARDS_H */
--- /dev/null
+/* NSDictionary+NGCards.m - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import "NSArray+NGCards.h"
+
+#import "NSDictionary+NGCards.h"
+
+@implementation NSDictionary (NGCardsExtension)
+
+- (id) objectForCaseInsensitiveKey: (NSString *) aKey
+{
+ NSString *realKey;
+ NSArray *keys;
+
+ keys = [self allKeys];
+ realKey = [keys valueForCaseInsensitiveString: aKey];
+
+ return ((realKey) ? [self objectForKey: realKey] : nil);
+}
+
+@end
--- /dev/null
+/* NSString+NGCards.h - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef NSSTRING_NGCARDS_H
+#define NSSTRING_NGCARDS_H
+
+#import <Foundation/NSString.h>
+
+@class NSCalendarDate;
+@class NSTimeZone;
+
+@interface NSString (NGCardsExtensions)
+
+- (NSString *) foldedForVersitCards;
+- (NSArray *) asCardAttributeValues;
+- (NSString *) escapedForCards;
+- (NSString *) unescapedFromCard;
+
+- (NSTimeInterval) durationAsTimeInterval;
+- (NSCalendarDate *) asCalendarDate;
+
+- (NSArray *) commaSeparatedValues;
+
+@end
+
+#endif /* NSSTRING_NGCARDS_H */
--- /dev/null
+/* NSString+NGCards.m - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSRange.h>
+#import <Foundation/NSTimeZone.h>
+#import <NGExtensions/NSObject+Logs.h>
+
+#import <ctype.h>
+
+#import "NSString+NGCards.h"
+
+static NSString *commaSeparator = nil;
+
+@implementation NSString (NGCardsExtensions)
+
+- (void) _initCommaSeparator
+{
+ commaSeparator = [NSMutableString stringWithFormat: @"%c", 255];
+ [commaSeparator retain];
+}
+
+- (NSString *) foldedForVersitCards
+{
+ NSString *newString;
+ NSMutableString *foldedString;
+ unsigned int length;
+ NSRange subStringRange;
+
+ length = [self length];
+ if (length < 76)
+ newString = self;
+ else
+ {
+ foldedString = [NSMutableString new];
+ [foldedString autorelease];
+
+ subStringRange = NSMakeRange (0, 75);
+ [foldedString appendFormat: @"%@\r\n",
+ [self substringWithRange: subStringRange]];
+ subStringRange = NSMakeRange (75, 74);
+ while ((length - subStringRange.location) > 74)
+ {
+ [foldedString appendFormat: @" %@\r\n",
+ [self substringWithRange: subStringRange]];
+ subStringRange.location += 74;
+ }
+ subStringRange.length = length - subStringRange.location;
+ [foldedString appendFormat: @" %@",
+ [self substringWithRange: subStringRange]];
+
+ newString = foldedString;
+ }
+
+ return newString;
+}
+
+- (NSArray *) asCardAttributeValues
+{
+ NSMutableArray *values;
+ NSEnumerator *rawValues;
+ NSString *tmpString, *rawValue, *newString;
+
+ values = [NSMutableArray new];
+ [values autorelease];
+
+ if (!commaSeparator)
+ [self _initCommaSeparator];
+
+ tmpString = [self stringByReplacingString: @"\\,"
+ withString: commaSeparator];
+ rawValues = [[tmpString componentsSeparatedByString: @","]
+ objectEnumerator];
+ rawValue = [rawValues nextObject];
+ while (rawValue)
+ {
+ newString = [rawValue stringByReplacingString: commaSeparator
+ withString: @","];
+ [values addObject: [newString stringByTrimmingSpaces]];
+ rawValue = [rawValues nextObject];
+ }
+
+ return values;
+}
+
+- (NSString *) escapedForCards
+{
+ NSString *string;
+
+ string = [self stringByReplacingString: @"\\"
+ withString: @"\\\\"];
+ string = [string stringByReplacingString: @","
+ withString: @"\\,"];
+// string = [string stringByReplacingString: @":"
+// withString: @"\\:"];
+ string = [string stringByReplacingString: @";"
+ withString: @"\\;"];
+ string = [string stringByReplacingString: @"\n"
+ withString: @"\\n"];
+ string = [string stringByReplacingString: @"\r"
+ withString: @"\\r"];
+
+ return string;
+}
+
+- (NSString *) unescapedFromCard
+{
+ NSString *string;
+
+ string = [self stringByReplacingString: @"\\,"
+ withString: @","];
+ string = [string stringByReplacingString: @"\\:"
+ withString: @":"];
+ string = [string stringByReplacingString: @"\\;"
+ withString: @";"];
+ string = [string stringByReplacingString: @"\\n"
+ withString: @"\n"];
+ string = [string stringByReplacingString: @"\\r"
+ withString: @"\r"];
+ string = [string stringByReplacingString: @"\\\\"
+ withString: @"\\"];
+
+ return string;
+}
+
+- (NSTimeInterval) durationAsTimeInterval
+{
+ /*
+ eg: DURATION:PT1H
+ P - "period"
+ P2H30M - "2 hours 30 minutes"
+
+ dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
+
+ dur-date = dur-day [dur-time]
+ dur-time = "T" (dur-hour / dur-minute / dur-second)
+ dur-week = 1*DIGIT "W"
+ dur-hour = 1*DIGIT "H" [dur-minute]
+ dur-minute = 1*DIGIT "M" [dur-second]
+ dur-second = 1*DIGIT "S"
+ dur-day = 1*DIGIT "D"
+ */
+ unsigned i, len;
+ NSTimeInterval ti;
+ BOOL isTime;
+ int val;
+
+ if (![self hasPrefix:@"P"]) {
+ NSLog(@"Cannot parse iCal duration value: '%@'", self);
+ return 0.0;
+ }
+
+ ti = 0.0;
+ val = 0;
+ for (i = 1, len = [self length], isTime = NO; i < len; i++) {
+ unichar c;
+
+ c = [self characterAtIndex:i];
+ if (c == 't' || c == 'T') {
+ isTime = YES;
+ val = 0;
+ continue;
+ }
+
+ if (isdigit(c)) {
+ val = (val * 10) + (c - 48);
+ continue;
+ }
+
+ switch (c) {
+ case 'W': /* week */
+ ti += (val * 7 * 24 * 60 * 60);
+ break;
+ case 'D': /* day */
+ ti += (val * 24 * 60 * 60);
+ break;
+ case 'H': /* hour */
+ ti += (val * 60 * 60);
+ break;
+ case 'M': /* min */
+ ti += (val * 60);
+ break;
+ case 'S': /* sec */
+ ti += val;
+ break;
+ default:
+ [self logWithFormat: @"cannot process duration unit: '%c'", c];
+ break;
+ }
+ val = 0;
+ }
+ return ti;
+}
+
+- (NSCalendarDate *) asCalendarDate
+{
+ NSRange cursor;
+ NSCalendarDate *date;
+ NSTimeZone *utc;
+ int year, month, day, hour, minute, second;
+
+ if ([self length] > 14)
+ {
+ cursor = NSMakeRange(0, 4);
+ year = [[self substringWithRange: cursor] intValue];
+ cursor.location += cursor.length;
+ cursor.length = 2;
+ month = [[self substringWithRange: cursor] intValue];
+ cursor.location += cursor.length;
+ day = [[self substringWithRange: cursor] intValue];
+
+ cursor.location += cursor.length + 1;
+ hour = [[self substringWithRange: cursor] intValue];
+ cursor.location += cursor.length;
+ minute = [[self substringWithRange: cursor] intValue];
+ cursor.location += cursor.length;
+ second = [[self substringWithRange: cursor] intValue];
+
+ utc = [NSTimeZone timeZoneWithAbbreviation: @"GMT"];
+ date = [NSCalendarDate dateWithYear: year month: month
+ day: day hour: hour minute: minute
+ second: second
+ timeZone: utc];
+ }
+ else
+ date = nil;
+
+ return date;
+}
+
+- (NSArray *) commaSeparatedValues
+{
+ NSEnumerator *rawValues;
+ NSMutableArray *values;
+ NSString *currentValue, *newValue;
+
+ values = [NSMutableArray new];
+ [values autorelease];
+
+ rawValues = [[self componentsSeparatedByString: @","] objectEnumerator];
+ currentValue = [rawValues nextObject];
+ while (currentValue)
+ {
+ newValue = [currentValue stringByTrimmingSpaces];
+ if ([newValue length])
+ [values addObject: newValue];
+ currentValue = [rawValues nextObject];
+ }
+
+ return values;
+}
+
+@end
--- /dev/null
+TODO: improve text
+
+Objective-C classes for representing iCalendar entities as objects. To
+actually parse iCalendar entities the sope-xml versitSaxDriver is used.
+Note that this library doesn't make any use of the now deprecated libical but
+rather relies on the SAX interface (SaxObjectDecoder is used).
+
+Recurrences
+===========
+
+Recurrences are modeled via iCalRecurrenceRules and an iCalRecurrenceCalculator
+which contains all the necessary logic according to RFC2445 to interpret
+iCalRecurrenceRules. The calculator needs a referrence date for the first
+instance of a recurrence which is usually provided by any of the repeatable
+entity objects (i.e. iCalEvent).
+
+Please note that recurrences are work in progress and far from being
+complete/compliant with RFC2445. So far only the most simple cases are done
+properly.
--- /dev/null
+# version file
+
+MAJOR_VERSION=4
+MINOR_VERSION=5
+SUBMINOR_VERSION:=76
+
+# v4.5.40 requires NGExtensions v4.5.145
+# v4.5.37 requires NGExtensions v4.5.140
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __ICal_common_H__
+#define __ICal_common_H__
+
+#import <Foundation/Foundation.h>
+#import <EOControl/EOControl.h>
+#include <NGExtensions/NGExtensions.h>
+
+#define IS_EQUAL(a, b, sel) \
+ _iCalSafeCompareObjects(a, b, @selector(sel))
+
+static __inline__ BOOL _iCalSafeCompareObjects(id a, id b, SEL comparator) {
+ id va = a;
+ id vb = b;
+ BOOL (*compm)(id, SEL, id);
+
+ if((va == nil && vb != nil) || (va != nil && vb == nil))
+ return NO;
+ else if(va == vb)
+ return YES;
+ compm = (BOOL (*)( id, SEL, id))[va methodForSelector:comparator];
+ return compm(va, comparator, vb);
+}
+
+#endif /* __ICal_common_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGCards_iCalAlarm_H__
+#define __NGCards_iCalAlarm_H__
+
+#import "CardGroup.h"
+
+@class NSString;
+@class iCalTrigger;
+@class iCalAttachment;
+
+@interface iCalAlarm : CardGroup
+
+/* accessors */
+
+- (iCalTrigger *) trigger;
+- (iCalAttachment *) attach;
+- (NSString *) comment;
+- (NSString *) action;
+- (void) setRecurrenceRule: (NSString *) _recurrenceRule;
+- (NSString *) recurrenceRule;
+
+@end
+
+#endif /* __NGCards_iCalAlarm_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import "iCalAttachment.h"
+#import "iCalRecurrenceRule.h"
+#import "iCalTrigger.h"
+
+#import "iCalAlarm.h"
+#import "common.h"
+
+@implementation iCalAlarm
+
+- (Class) classForTag: (NSString *) classTag
+{
+ Class tagClass;
+
+ if ([classTag isEqualToString: @"TRIGGER"])
+ tagClass = [iCalTrigger class];
+ else if ([classTag isEqualToString: @"ATTACH"])
+ tagClass = [iCalAttachment class];
+ else if ([classTag isEqualToString: @"RRULE"])
+ tagClass = [iCalRecurrenceRule class];
+ else if ([classTag isEqualToString: @"ACTION"]
+ || [classTag isEqualToString: @"COMMENT"])
+ tagClass = [CardElement class];
+ else
+ tagClass = [super classForTag: classTag];
+
+ return tagClass;
+}
+
+/* accessors */
+
+- (void) setTrigger: (iCalTrigger *) _value
+{
+ [self setUniqueChild: _value];
+}
+
+- (iCalTrigger *) trigger
+{
+ return (iCalTrigger *) [self uniqueChildWithTag: @"trigger"];
+}
+
+- (void) setAttach: (iCalAttachment *) _value
+{
+ [self setUniqueChild: _value];
+}
+
+- (iCalAttachment *) attach
+{
+ return (iCalAttachment *) [self uniqueChildWithTag: @"attach"];
+}
+
+- (void) setComment: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"comment"] setValue: 0
+ to: _value];
+}
+
+- (NSString *) comment
+{
+ return [[self uniqueChildWithTag: @"comment"] value: 0];
+}
+
+- (void) setAction: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"action"] setValue: 0
+ to: _value];
+}
+
+- (NSString *) action
+{
+ return [[self uniqueChildWithTag: @"action"] value: 0];
+}
+
+- (void) setRecurrenceRule: (NSString *) _recurrenceRule
+{
+ [[self uniqueChildWithTag: @"rrule"] setValue: 0
+ to: _recurrenceRule];
+}
+
+- (NSString *) recurrenceRule
+{
+ return [[self uniqueChildWithTag: @"rrule"] value: 0];
+}
+
+@end /* iCalAlarm */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGiCal_iCalAttachment_H__
+#define __NGiCal_iCalAttachment_H__
+
+#import "CardElement.h"
+
+@class NSString;
+
+@interface iCalAttachment : CardElement
+
+- (void) setValue: (NSString *) aValue;
+- (NSString *) value;
+
+- (void) setValueType: (NSString *) aType;
+- (NSString *) valueType;
+
+@end
+
+#endif /* __NGiCal_iCalAttachment_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import "iCalAttachment.h"
+#import "common.h"
+
+@implementation iCalAttachment
+
+/* accessors */
+
+- (void) setValue: (NSString *) _value
+{
+ [self setValue: 0 to: _value];
+}
+
+- (NSString *) value
+{
+ return [self value: 0];
+}
+
+- (void) setValueType: (NSString *) _value
+{
+ [self setValue: 0 ofAttribute: @"type" to: _value];
+}
+
+- (NSString *) valueType
+{
+ return [self value: 0 ofAttribute: @"type"];
+}
+
+@end /* iCalAttachment */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGCards_iCalCalendar_H__
+#define __NGCards_iCalCalendar_H__
+
+#import "CardGroup.h"
+
+@class NSString;
+@class NSMutableArray;
+@class NSArray;
+@class NSEnumerator;
+@class NSMutableDictionary;
+
+@class iCalEvent;
+@class iCalToDo;
+@class iCalJournal;
+@class iCalFreeBusy;
+@class iCalEntityObject;
+@class iCalTimeZone;
+
+@interface iCalCalendar : CardGroup
+// {
+// NSString *version;
+// NSString *calscale;
+// NSString *prodId;
+// NSString *method;
+
+// NSMutableArray *todos;
+// NSMutableArray *events;
+// NSMutableArray *journals;
+// NSMutableArray *freeBusys;
+// NSMutableDictionary *timezones;
+// }
+
+/* accessors */
+
+- (void) setMethod: (NSString *)_method;
+- (NSString *) method;
+
+- (void) setCalscale: (NSString *) _calscale;
+- (NSString *) calscale;
+
+- (void) setVersion: (NSString *) _version;
+- (NSString *) version;
+
+- (void) setProdID: (NSString *) _prodid;
+- (NSString *) prodId;
+
+- (void) setMethod: (NSString *) _method;
+- (NSString *) method;
+
+- (NSArray *) events;
+- (NSArray *) todos;
+- (NSArray *) journals;
+- (NSArray *) freeBusys;
+
+- (void) addTimeZone: (iCalTimeZone *) iTZ;
+- (iCalTimeZone *) timeZoneWithId: (NSString *) tzId;
+
+/* collection */
+
+- (NSArray *) allObjects;
+
+@end
+
+#endif /* __NGCards_iCalCalendar_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSString.h>
+
+#import "iCalEvent.h"
+#import "iCalToDo.h"
+#import "iCalJournal.h"
+#import "iCalFreeBusy.h"
+#import "iCalEntityObject.h"
+#import "iCalTimeZone.h"
+
+#import "iCalCalendar.h"
+
+@interface iCalCalendar (Privates)
+- (void) addToEvents: (iCalEvent *) _event;
+- (void) addToTimezones: (iCalTimeZone *) _tz;
+- (void) addToTodos: (iCalToDo *) _todo;
+- (void) addToJournals: (iCalJournal *) _obj;
+- (void) addToFreeBusys: (iCalFreeBusy *) _obj;
+@end
+
+@implementation iCalCalendar
+
+/* class mapping */
+- (Class) classForTag: (NSString *) classTag
+{
+ Class tagClass;
+
+ tagClass = Nil;
+ if ([classTag isEqualToString: @"VEVENT"])
+ tagClass = [iCalEvent class];
+ else if ([classTag isEqualToString: @"VTODO"])
+ tagClass = [iCalToDo class];
+ else if ([classTag isEqualToString: @"VJOURNAL"])
+ tagClass = [iCalJournal class];
+ else if ([classTag isEqualToString: @"VFREEBUSY"])
+ tagClass = [iCalFreeBusy class];
+ else if ([classTag isEqualToString: @"VTIMEZONE"])
+ tagClass = [iCalTimeZone class];
+ else if ([classTag isEqualToString: @"METHOD"]
+ || [classTag isEqualToString: @"PRODID"]
+ || [classTag isEqualToString: @"VERSION"])
+ tagClass = [CardElement class];
+ else
+ tagClass = [super classForTag: classTag];
+
+ return tagClass;
+}
+
+/* accessors */
+
+- (void) setCalscale: (NSString *) _calscale
+{
+ [[self uniqueChildWithTag: @"calscale"] setValue: 0 to: _calscale];
+}
+
+- (NSString *) calscale
+{
+ return [[self uniqueChildWithTag: @"calscale"] value: 0];
+}
+
+- (void) setVersion: (NSString *) _version
+{
+ [[self uniqueChildWithTag: @"version"] setValue: 0 to: _version];
+}
+
+- (NSString *) version
+{
+ return [[self uniqueChildWithTag: @"version"] value: 0];
+}
+
+- (void) setProdID: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"prodid"] setValue: 0 to: _value];
+}
+
+- (NSString *) prodId
+{
+ return [[self uniqueChildWithTag: @"prodid"] value: 0];
+}
+
+- (void) setMethod: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"method"] setValue: 0 to: _value];
+}
+
+- (NSString *) method
+{
+ return [[self uniqueChildWithTag: @"method"] value: 0];
+}
+
+- (void) addToEvents: (iCalEvent *) _event
+{
+ [self addChild: _event];
+}
+
+- (NSArray *) events
+{
+ return [self childrenWithTag: @"vevent"];
+}
+
+- (void) addToTimezones: (iCalTimeZone *) _tz
+{
+ [self addChild: _tz];
+}
+
+- (NSArray *) timezones
+{
+ return [self childrenWithTag: @"vtimezone"];
+}
+
+- (void) addToTodos: (iCalToDo *) _todo
+{
+ [self addChild: _todo];
+}
+
+- (NSArray *) todos
+{
+ return [self childrenWithTag: @"vtodo"];
+}
+
+- (void) addToJournals: (iCalJournal *) _todo
+{
+ [self addChild: _todo];
+}
+
+- (NSArray *) journals
+{
+ return [self childrenWithTag: @"vjournal"];
+}
+
+- (void) addToFreeBusys: (iCalFreeBusy *) _fb
+{
+ [self addChild: _fb];
+}
+
+- (NSArray *) freeBusys
+{
+ return [self childrenWithTag: @"vfreebusy"];
+}
+
+- (void) addTimeZone: (iCalTimeZone *) iTZ
+{
+ iCalTimeZone *possibleTz;
+
+ possibleTz = [self timeZoneWithId: [iTZ tzId]];
+ if (!possibleTz)
+ [self addChild: iTZ];
+}
+
+- (iCalTimeZone *) timeZoneWithId: (NSString *) tzId
+{
+ NSArray *matchingTimeZones;
+ iCalTimeZone *timeZone;
+
+ matchingTimeZones = [self childrenGroupWithTag: @"vtimezone"
+ withChild: @"tzid"
+ havingSimpleValue: tzId];
+ if ([matchingTimeZones count])
+ timeZone = [matchingTimeZones objectAtIndex: 0];
+ else
+ timeZone = nil;
+
+ return timeZone;
+}
+
+/* collection */
+
+- (NSArray *) allObjects
+{
+ NSMutableArray *ma;
+
+ ma = [NSMutableArray new];
+ [ma addObjectsFromArray: [self events]];
+ [ma addObjectsFromArray: [self todos]];
+ [ma addObjectsFromArray: [self journals]];
+ [ma addObjectsFromArray: [self freeBusys]];
+
+ return ma;
+}
+
+/* ical typing */
+
+- (NSString *) entityName
+{
+ return @"vcalendar";
+}
+
+@end /* iCalCalendar */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalRecurrenceCalculator.h"
+
+@interface iCalDailyRecurrenceCalculator : iCalRecurrenceCalculator
+@end
+
+#include <NGExtensions/NGCalendarDateRange.h>
+#include "iCalRecurrenceRule.h"
+#include "NSCalendarDate+ICal.h"
+#include "common.h"
+
+@interface iCalRecurrenceCalculator(PrivateAPI)
+- (NSCalendarDate *)lastInstanceStartDate;
+@end
+
+@implementation iCalDailyRecurrenceCalculator
+
+- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{
+ NSMutableArray *ranges;
+ NSCalendarDate *firStart;
+ long i, jnFirst, jnStart, jnEnd, startEndCount;
+ unsigned interval;
+
+ firStart = [self->firstRange startDate];
+ jnFirst = [firStart julianNumber];
+ jnEnd = [[_r endDate] julianNumber];
+
+ if (jnFirst > jnEnd)
+ return nil;
+
+ jnStart = [[_r startDate] julianNumber];
+ interval = [self->rrule repeatInterval];
+
+ /* if rule is bound, check the bounds */
+ if (![self->rrule isInfinite]) {
+ NSCalendarDate *until;
+ long jnRuleLast;
+
+ until = [self->rrule untilDate];
+ if (until) {
+ if ([until compare:[_r startDate]] == NSOrderedAscending)
+ return nil;
+ jnRuleLast = [until julianNumber];
+ }
+ else {
+ jnRuleLast = (interval * [self->rrule repeatCount])
+ + jnFirst;
+ if (jnRuleLast < jnStart)
+ return nil;
+ }
+ /* jnStart < jnRuleLast < jnEnd ? */
+ if (jnEnd > jnRuleLast)
+ jnEnd = jnRuleLast;
+ }
+
+ startEndCount = (jnEnd - jnStart) + 1;
+ ranges = [NSMutableArray arrayWithCapacity:startEndCount];
+ for (i = 0 ; i < startEndCount; i++) {
+ long jnCurrent;
+
+ jnCurrent = jnStart + i;
+ if (jnCurrent >= jnFirst) {
+ long jnTest;
+
+ jnTest = jnCurrent - jnFirst;
+ if ((jnTest % interval) == 0) {
+ NSCalendarDate *start, *end;
+ NGCalendarDateRange *r;
+
+ start = [NSCalendarDate dateForJulianNumber:jnCurrent];
+ [start setTimeZone:[firStart timeZone]];
+ start = [start hour: [firStart hourOfDay]
+ minute:[firStart minuteOfHour]
+ second:[firStart secondOfMinute]];
+ end = [start addTimeInterval:[self->firstRange duration]];
+ r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
+ endDate:end];
+ if ([_r containsDateRange:r])
+ [ranges addObject:r];
+ }
+ }
+ }
+ return ranges;
+}
+
+- (NSCalendarDate *)lastInstanceStartDate {
+ if ([self->rrule repeatCount] > 0) {
+ long jnFirst, jnRuleLast;
+ NSCalendarDate *firStart, *until;
+
+ firStart = [self->firstRange startDate];
+ jnFirst = [firStart julianNumber];
+ jnRuleLast = ([self->rrule repeatInterval] *
+ [self->rrule repeatCount]) +
+ jnFirst;
+ until = [NSCalendarDate dateForJulianNumber:jnRuleLast];
+ until = [until hour: [firStart hourOfDay]
+ minute:[firStart minuteOfHour]
+ second:[firStart secondOfMinute]];
+ return until;
+ }
+ return [super lastInstanceStartDate];
+}
+
+@end /* iCalDailyRecurrenceCalculator */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGiCal_iCalDataSource_H__
+#define __NGiCal_iCalDataSource_H__
+
+#import <EOControl/EODataSource.h>
+
+@class NSString, NSURL;
+@class EOFetchSpecification;
+
+@interface iCalDataSource : EODataSource
+{
+ EOFetchSpecification *fetchSpecification;
+ NSURL *url;
+ NSString *entityName;
+}
+
+- (id)initWithURL:(NSURL *)_url entityName:(NSString *)_ename;
+- (id)initWithPath:(NSString *)_file entityName:(NSString *)_ename;
+- (id)initWithURL:(NSURL *)_url;
+- (id)initWithPath:(NSString *)_file;
+
+/* accessors */
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec;
+- (EOFetchSpecification *)fetchSpecification;
+
+/* fetching */
+
+- (NSArray *)fetchObjects;
+
+@end
+
+#endif /* __NGiCal_iCalDataSource_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalDataSource.h"
+#include "iCalObject.h"
+#include "iCalCalendar.h"
+#include <SaxObjC/SaxObjC.h>
+#include "common.h"
+
+@interface NSObject(suppressCapitalizedKeyWarning)
++ (void)suppressCapitalizedKeyWarning;
+@end
+
+@implementation iCalDataSource
+
+// THREAD
+static id<NSObject,SaxXMLReader> parser = nil;
+static SaxObjectDecoder *sax = nil;
+
+- (void)_setupGlobals {
+ if (parser == nil ) {
+ SaxXMLReaderFactory *factory =
+ [SaxXMLReaderFactory standardXMLReaderFactory];
+ parser = [[factory createXMLReaderForMimeType:@"text/calendar"] retain];
+ if (parser == nil)
+ [self logWithFormat:@"ERROR: found no SAX driver for 'text/calendar'!"];
+ }
+ if (sax == nil && parser != nil) {
+ NSBundle *bundle;
+ NSString *p;
+
+#if COCOA_Foundation_LIBRARY
+ /* otherwise we get warning on "X-WR-TIMEZONE" etc */
+ [NSClassFromString(@"NSKeyBinding") suppressCapitalizedKeyWarning];
+#endif
+
+ bundle = [NSBundle bundleForClass:[self class]];
+ if ((p = [bundle pathForResource:@"NGiCal" ofType:@"xmap"]))
+ sax = [[SaxObjectDecoder alloc] initWithMappingAtPath:p];
+ else
+ sax = [[SaxObjectDecoder alloc] initWithMappingNamed:@"NGiCal"];
+
+ [parser setContentHandler:sax];
+ [parser setErrorHandler:sax];
+ }
+}
+
+
+- (id)initWithURL:(NSURL *)_url entityName:(NSString *)_ename {
+ [self _setupGlobals];
+ if ((self = [super init])) {
+ self->url = [_url copy];
+ self->entityName = [_ename copy];
+ }
+ return self;
+}
+- (id)initWithPath:(NSString *)_path entityName:(NSString *)_ename {
+ NSURL *lurl;
+
+ lurl = [[[NSURL alloc] initFileURLWithPath:_path] autorelease];
+ return [self initWithURL:lurl entityName:_ename];
+}
+
+- (id)initWithURL:(NSURL *)_url {
+ return [self initWithURL:_url entityName:nil];
+}
+- (id)initWithPath:(NSString *)_path {
+ return [self initWithPath:_path entityName:nil];
+}
+- (id)init {
+ return [self initWithURL:nil];
+}
+
+- (void)dealloc {
+ [self->fetchSpecification release];
+ [self->url release];
+ [self->entityName release];
+ [super dealloc];
+}
+
+/* accessors */
+
+- (void)setFetchSpecification:(EOFetchSpecification *)_fspec {
+ if ([self->fetchSpecification isEqual:_fspec])
+ return;
+
+ ASSIGNCOPY(self->fetchSpecification, _fspec);
+
+ [self postDataSourceChangedNotification];
+}
+- (EOFetchSpecification *)fetchSpecification {
+ return self->fetchSpecification;
+}
+
+/* fetching */
+
+- (id)_parseCalendar {
+ id cal;
+
+ if (parser == nil) {
+ [self logWithFormat:@"ERROR: missing iCalendar parser!"];
+ return nil;
+ }
+ if (sax == nil) {
+ [self logWithFormat:@"ERROR: missing SAX handler!"];
+ return nil;
+ }
+
+ [parser parseFromSource:self->url];
+ cal = [sax rootObject];
+
+ return cal;
+}
+
+- (NSArray *)objectsForEntityNamed:(NSString *)ename inCalendar:(id)_cal {
+ if ([ename isEqualToString:@"vevent"])
+ return [_cal events];
+ if ([ename isEqualToString:@"vtodo"])
+ return [_cal todos];
+ if ([ename isEqualToString:@"vjournal"])
+ return [_cal journals];
+ if ([ename isEqualToString:@"vfreebusy"])
+ return [_cal freeBusys];
+
+ [self logWithFormat:@"unknown calendar entity '%@'", ename];
+ return nil;
+}
+
+- (NSArray *)objectsFromCalendar:(id)_cal {
+ NSString *ename;
+
+ ename = [self->fetchSpecification entityName];
+ if ([ename length] == 0)
+ ename = self->entityName;
+
+ if ([ename length] == 0)
+ return [_cal allObjects];
+
+ if ([_cal isKindOfClass:[NSDictionary class]]) {
+ /*
+ This happens with Mozilla Calendar which posts one vcalendar
+ entry (with method 'PUBLISH') per event.
+ */
+ NSMutableArray *ma;
+ NSArray *calendars;
+ unsigned i, count;
+
+ if (![[(NSDictionary *)_cal objectForKey:@"tag"]
+ isEqualToString:@"iCalendar"]) {
+ [self logWithFormat:
+ @"ERROR: calendar (entity=%@) passed in as a dictionary: %@",
+ _cal];
+ }
+
+ if ((calendars=[(NSDictionary *)_cal objectForKey:@"subcomponents"])==nil)
+ return nil;
+
+ count = [calendars count];
+ ma = [NSMutableArray arrayWithCapacity:(count + 1)];
+
+ for (i = 0; i < count; i++) {
+ NSArray *objects;
+
+ objects = [self objectsForEntityNamed:ename
+ inCalendar:[calendars objectAtIndex:i]];
+ if ([objects count] == 0)
+ continue;
+
+ [ma addObjectsFromArray:objects];
+ }
+ return ma;
+ }
+
+ return [self objectsForEntityNamed:ename inCalendar:_cal];
+}
+
+- (NSArray *)fetchObjects {
+ NSAutoreleasePool *pool;
+ NSArray *result;
+ id calendar;
+
+ pool = [[NSAutoreleasePool alloc] init];
+
+ if ((calendar = [self _parseCalendar]) == nil)
+ return nil;
+
+ if (self->fetchSpecification == nil) {
+ result = [[self objectsFromCalendar:calendar] shallowCopy];
+ }
+ else {
+ NSMutableArray *ma;
+ NSEnumerator *e;
+ EOQualifier *q;
+ NSArray *sort;
+ NSArray *objects;
+ iCalObject *object;
+
+ /* get objects */
+
+ objects = [self objectsFromCalendar:calendar];
+
+ /* first filter using qualifier */
+
+ ma = [NSMutableArray arrayWithCapacity:[objects count]];
+ q = [self->fetchSpecification qualifier];
+ e = [objects objectEnumerator];
+ while ((object = [e nextObject])) {
+ if (q) {
+ if (![(id<EOQualifierEvaluation>)q evaluateWithObject:object])
+ continue;
+ }
+
+ [ma addObject:object];
+ }
+
+ /* now sort */
+
+ if ((sort = [self->fetchSpecification sortOrderings]))
+ [ma sortUsingKeyOrderArray:sort];
+
+ result = [ma shallowCopy];
+ }
+
+ [pool release];
+
+ return [result autorelease];
+}
+
+@end /* iCalDataSource */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGiCal_iCalDateHolder_H__
+#define __NGiCal_iCalDateHolder_H__
+
+#import <Foundation/NSObject.h>
+
+@class NSString, NSTimeZone;
+
+@interface iCalDateHolder : NSObject
+{
+ NSString *tzid;
+ NSString *string;
+ NSString *tag;
+}
+
+- (void)setString:(NSString *)_value;
+- (NSString *)string;
+
+- (void)setTag:(NSString *)_value;
+- (NSString *)tag;
+
+- (void)setTzid:(NSString *)_value;
+- (NSString *)tzid;
+
+- (NSTimeZone *)timeZone;
+
+@end
+
+#endif /* __NGiCal_iCalDateHolder_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalDateHolder.h"
+#include "iCalObject.h"
+#include "common.h"
+
+@interface NSTimeZone(iCalTimeZone)
+
++ (NSTimeZone *)timeZoneWithICalId:(NSString *)_tz;
+
+@end
+
+@implementation iCalDateHolder
+
+static NSTimeZone *gmt = nil;
+
++ (void)initialize {
+ if (gmt == nil)
+ gmt = [[NSTimeZone timeZoneWithName:@"GMT"] retain];
+}
+
+- (void)dealloc {
+ [self->tzid release];
+ [self->string release];
+ [self->tag release];
+ [super dealloc];
+}
+
+/* accessors */
+
+- (void)setString:(NSString *)_value {
+ ASSIGNCOPY(self->string, _value);
+}
+- (NSString *)string {
+ return self->string;
+}
+
+- (void)setTag:(NSString *)_value {
+ ASSIGNCOPY(self->tag, _value);
+}
+- (NSString *)tag {
+ return self->tag;
+}
+
+- (void)setTzid:(NSString *)_value {
+ ASSIGNCOPY(self->tzid, _value);
+}
+- (NSString *)tzid {
+ return self->tzid;
+}
+
+/* mapping to Foundation */
+
+- (NSTimeZone *)timeZone {
+ // TODO: lookup tzid in iCalCalendar !
+ NSString *s;
+
+ s = [self tzid];
+
+ /* a hack */
+ if ([s hasPrefix:@"/softwarestudio.org"]) {
+ NSRange r;
+
+ r = [s rangeOfString:@"Europe/"];
+ if (r.length > 0)
+ s = [s substringFromIndex:r.location];
+ }
+ return [NSTimeZone timeZoneWithICalId:s];
+}
+
+/* decoding */
+
+- (id)awakeAfterUsingSaxDecoder:(id)_decoder {
+ NSCalendarDate *date = nil;
+ NSString *s;
+ NSTimeZone *tz;
+
+ s = self->string;
+ if ([s length] < 5) {
+ [self logWithFormat:@"tag %@: got an weird date string '%@' ?!",
+ self->tag, s];
+ return s;
+ }
+
+ /* calculate timezone */
+
+ if ([self->string hasSuffix:@"Z"]) {
+ /* zulu time, eg 20021009T094500Z */
+ tz = gmt;
+ s = [s substringToIndex:([s length] - 1)];
+ }
+ else
+ tz = [self timeZone];
+
+ /*
+ 012345678901234
+ 20021009T094500 - 15 chars
+ 20021009T0945 - 13 chars
+ 991009T0945 - 11 chars
+
+ 20031111 - 8 chars
+ */
+ if ([s rangeOfString:@"T"].length == 0 && [s length] == 8) {
+ /* hm, maybe a date without a time? like an allday event! */
+ int year, month, day;
+ char buf[16];
+ [s getCString:&(buf[0])];
+
+ buf[9] = '\0';
+ day = atoi(&(buf[6])); buf[6] = '\0';
+ month = atoi(&(buf[4])); buf[4] = '\0';
+ year = atoi(&(buf[0]));
+
+ date = [NSCalendarDate dateWithYear:year month:month day:day
+ hour:0 minute:0 second:0
+ timeZone:tz];
+ }
+ else if ([s length] == 15) {
+ int year, month, day, hour, minute, second;
+ char buf[24];
+ [s getCString:&(buf[0])];
+
+ second = atoi(&(buf[13])); buf[13] = '\0';
+ minute = atoi(&(buf[11])); buf[11] = '\0';
+ hour = atoi(&(buf[9])); buf[9] = '\0';
+ day = atoi(&(buf[6])); buf[6] = '\0';
+ month = atoi(&(buf[4])); buf[4] = '\0';
+ year = atoi(&(buf[0]));
+
+ date = [NSCalendarDate dateWithYear:year month:month day:day
+ hour:hour minute:minute second:second
+ timeZone:tz];
+ }
+ else
+ NSLog(@"%s: unknown date format (%@) ???", __PRETTY_FUNCTION__, s);
+
+ if (date == nil)
+ NSLog(@"couldn't convert string '%@' to date (format '%@') ..", s);
+
+ return date;
+}
+
+/* description */
+
+- (void)appendAttributesToDescription:(NSMutableString *)ms {
+ if (self->tag) [ms appendFormat:@" %@", self->tag];
+ if (self->string) [ms appendFormat:@" '%@'", self->string];
+ if (self->tzid) [ms appendFormat:@" tz=%@", self->tzid];
+}
+
+- (NSString *)description {
+ NSMutableString *ms;
+
+ ms = [NSMutableString stringWithCapacity:128];
+ [ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
+ [self appendAttributesToDescription:ms];
+ [ms appendString:@">"];
+ return ms;
+}
+
+@end /* iCalDateHolder */
+
+@implementation NSTimeZone(iCalTimeZone)
+
+static NSMutableDictionary *idToTz = nil; // THREAD
+
++ (NSTimeZone *)timeZoneWithICalId:(NSString *)_tzid {
+ static NSString *iCalDefaultTZ = nil;
+ NSTimeZone *tz;
+
+ if (idToTz == nil)
+ idToTz = [[NSMutableDictionary alloc] initWithCapacity:16];
+
+ if ([_tzid length] == 0) {
+
+ tz = [iCalObject iCalDefaultTimeZone];
+ if (tz != nil) return tz;
+
+ if (iCalDefaultTZ == nil) {
+ NSString *defTz;
+ NSUserDefaults *ud;
+ // TODO: take a default timeZone
+ ud = [NSUserDefaults standardUserDefaults];
+ defTz = [ud stringForKey:@"iCalTimeZoneName"];
+ if ([defTz length] == 0)
+ defTz = [ud stringForKey:@"TimeZoneName"];
+ if ([defTz length] == 0)
+ defTz = [ud stringForKey:@"TimeZone"];
+ if ([defTz length] == 0)
+ defTz = @"GMT";
+ iCalDefaultTZ = [defTz retain];
+ }
+
+ _tzid = iCalDefaultTZ;
+
+ }
+
+ if ([_tzid length] == 0)
+ _tzid = @"GMT";
+
+ tz = [idToTz objectForKey:_tzid];
+ if (tz == nil) tz = [NSTimeZone timeZoneWithName:_tzid];
+ if (tz == nil) tz = [NSTimeZone timeZoneWithAbbreviation:_tzid];
+
+ if (tz == nil) {
+ NSLog(@"couldn't map timezone id %@", _tzid);
+ }
+
+ if (tz) [idToTz setObject:tz forKey:_tzid];
+ return tz;
+}
+
+@end /* NSTimeZone(iCalTimeZone) */
--- /dev/null
+/* iCalDateTime.h - this file is part of SOGo
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ICALDATETIMEELEMENT_H
+#define ICALDATETIMEELEMENT_H
+
+@class NSCalendarDate;
+@class iCalTimeZone;
+
+#import "CardElement.h"
+
+@interface iCalDateTime : CardElement
+
+- (void) setTimeZone: (iCalTimeZone *) iTZ;
+- (iCalTimeZone *) timeZone;
+
+- (void) setDateTime: (NSCalendarDate *) dateTime;
+- (NSCalendarDate *) dateTime;
+
+@end
+
+#endif /* ICALDATETIMEELEMENT_H */
--- /dev/null
+/* iCalDateTime.m - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/NSString.h>
+#import <Foundation/NSTimeZone.h>
+
+#import "NSCalendarDate+NGCards.h"
+#import "NSString+NGCards.h"
+
+#import "iCalCalendar.h"
+#import "iCalTimeZone.h"
+
+#import "iCalDateTime.h"
+
+// static NSTimeZone *localTimeZone = nil;
+
+@implementation iCalDateTime
+
+// + (void) initialize
+// {
+// if (!localTimeZone)
+// {
+// localTimeZone = [NSTimeZone defaultTimeZone];
+// [localTimeZone retain];
+// }
+// }
+
+// + (void) setLocalTimeZone: (NSTimeZone *) aTimeZone
+// {
+// [localTimeZone release];
+// localTimeZone = aTimeZone;
+// [localTimeZone retain];
+// }
+
+- (void) setTimeZone: (iCalTimeZone *) iTZ
+{
+ iCalCalendar *calendar;
+ NSCalendarDate *dateTime;
+ NSString *newTZId;
+
+ dateTime = [self dateTime];
+ if (iTZ)
+ {
+ calendar
+ = (iCalCalendar *) [self searchParentOfClass: [iCalCalendar class]];
+ if (calendar)
+ [calendar addTimeZone: iTZ];
+ newTZId = [iTZ tzId];
+ }
+ [self setValue: 0 ofAttribute: @"tzid" to: newTZId];
+ [self setDateTime: dateTime];
+}
+
+- (iCalTimeZone *) timeZone
+{
+ iCalCalendar *calendar;
+ NSString *tzId;
+ iCalTimeZone *timeZone;
+
+ tzId = [self value: 0 ofAttribute: @"tzid"];
+ calendar
+ = (iCalCalendar *) [self searchParentOfClass: [iCalCalendar class]];
+ if ([tzId length] && calendar)
+ timeZone = [calendar timeZoneWithId: tzId];
+ else
+ timeZone = nil;
+
+ return timeZone;
+}
+
+/* TODO: should implement the case where the TZ would be implicitly local
+ (no TZID and no UTC) */
+- (void) setDateTime: (NSCalendarDate *) dateTime
+{
+ NSCalendarDate *tmpTime;
+ NSTimeZone *utcTZ;
+ NSString *timeString;
+ iCalTimeZone *tz;
+
+ if (dateTime)
+ {
+ tz = [self timeZone];
+ if (tz)
+ timeString = [tz dateTimeStringForDate: dateTime];
+ else
+ {
+ utcTZ = [NSTimeZone timeZoneWithName: @"GMT"];
+
+ tmpTime = [dateTime copy];
+ [tmpTime setTimeZone: utcTZ];
+ timeString = [NSString stringWithFormat: @"%@Z",
+ [tmpTime iCalFormattedDateTimeString]];
+ [tmpTime release];
+ }
+ }
+ else
+ timeString = @"";
+
+ [self setValue: 0 to: timeString];
+}
+
+- (NSCalendarDate *) dateTime
+{
+ iCalTimeZone *iTZ;
+ NSString *date;
+ NSCalendarDate *initialDate, *dateTime;
+ NSTimeZone *tz;
+
+ date = [self value: 0];
+ iTZ = [self timeZone];
+ if (iTZ)
+ dateTime = [iTZ dateForDateTimeString: date];
+ else
+ {
+ initialDate = [date asCalendarDate];
+ if (initialDate)
+ {
+ if ([date hasSuffix: @"Z"] || [date hasSuffix: @"z"])
+ dateTime = initialDate;
+ else
+ {
+ /* same TODO as above */
+ tz = [NSTimeZone defaultTimeZone];
+ dateTime = [initialDate addYear: 0 month: 0 day: 0
+ hour: 0 minute: 0
+ second: -[tz secondsFromGMT]];
+ }
+ }
+ else
+ dateTime = nil;
+ }
+
+ return dateTime;
+}
+
+@end
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGCards_iCalEntityObject_H__
+#define __NGCards_iCalEntityObject_H__
+
+#import "CardGroup.h"
+
+/*
+ iCalEntityObject
+
+ This is a common base class for tasks and appointments which share a lot of
+ attributes.
+*/
+
+@class NSCalendarDate, NSMutableArray, NSString, NSArray, NSNumber;
+@class iCalPerson;
+@class NSURL;
+
+@interface iCalEntityObject : CardGroup
+
+/* accessors */
+
+- (void) setUid: (NSString *) _value;
+- (NSString *) uid;
+
+- (void) setSummary: (NSString *) _value;
+- (NSString *) summary;
+
+- (void) setLocation: (NSString *) _value;
+- (NSString *) location;
+
+- (void) setComment: (NSString *) _value;
+- (NSString *) comment;
+
+- (void) setAccessClass:(NSString *) _value;
+- (NSString *) accessClass;
+- (BOOL) isPublic;
+
+- (void) setPriority: (NSString *) _value;
+- (NSString *) priority;
+
+- (void) setCategories: (NSString *) _value;
+- (NSString *)categories;
+
+- (void) setUserComment: (NSString *) _userComment;
+- (NSString *) userComment;
+
+- (void) setTimeStampAsDate: (NSCalendarDate *)_date;
+- (NSCalendarDate *) timeStampAsDate;
+
+- (void)setStartDate:(NSCalendarDate *)_date;
+- (NSCalendarDate *)startDate;
+- (BOOL) hasStartDate;
+
+- (void)setLastModified:(NSCalendarDate *)_value;
+- (NSCalendarDate *)lastModified;
+
+- (void)setCreated:(NSCalendarDate *)_value;
+- (NSCalendarDate *)created;
+
+- (void)setSequence:(NSNumber *)_value; /* this is an int */
+- (NSNumber *)sequence;
+- (void)increaseSequence;
+
+/* url can either be set as NSString or NSURL */
+- (void)setUrl:(id)_value;
+- (NSURL *)url;
+
+- (void)setOrganizer:(iCalPerson *)_organizer;
+- (iCalPerson *)organizer;
+- (BOOL)isOrganizer:(id)_email;
+
+- (void)setStatus:(NSString *)_value;
+- (NSString *)status;
+
+- (void)removeAllAttendees;
+- (void)addToAttendees:(iCalPerson *)_person;
+- (NSArray *)attendees;
+- (void) setAttendees: (NSArray *) attendees;
+
+/* categorize attendees into participants and resources */
+- (NSArray *)participants;
+- (NSArray *)resources;
+- (BOOL)isParticipant:(id)_email;
+- (iCalPerson *)findParticipantWithEmail:(id)_email;
+
+- (void)removeAllAlarms;
+- (void)addToAlarms:(id)_alarm;
+- (NSArray *)alarms;
+- (BOOL)hasAlarms;
+
+@end
+
+#endif /* __NGCards_iCalEntityObject_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import "NSCalendarDate+NGCards.h"
+#import "CardGroup+iCal.h"
+
+#import "iCalAlarm.h"
+#import "iCalDateTime.h"
+#import "iCalEntityObject.h"
+#import "iCalPerson.h"
+#import "common.h"
+
+@interface iCalEntityObject (PrivateAPI)
+- (NSArray *)_filteredAttendeesThinkingOfPersons:(BOOL)_persons;
+@end
+
+@implementation iCalEntityObject
+
+- (Class) classForTag: (NSString *) classTag
+{
+ Class tagClass;
+
+ if ([classTag isEqualToString: @"ATTENDEE"]
+ || [classTag isEqualToString: @"ORGANIZER"])
+ tagClass = [iCalPerson class];
+ else if ([classTag isEqualToString: @"VALARM"])
+ tagClass = [iCalAlarm class];
+ else if ([classTag isEqualToString: @"SUMMARY"]
+ || [classTag isEqualToString: @"UID"]
+ || [classTag isEqualToString: @"COMMENT"]
+ || [classTag isEqualToString: @"DESCRIPTION"]
+ || [classTag isEqualToString: @"CLASS"]
+ || [classTag isEqualToString: @"STATUS"]
+ || [classTag isEqualToString: @"SEQUENCE"]
+ || [classTag isEqualToString: @"URL"]
+ || [classTag isEqualToString: @"PRIORITY"]
+ || [classTag isEqualToString: @"CATEGORIES"]
+ || [classTag isEqualToString: @"LOCATION"])
+ tagClass = [CardElement class];
+ else if ([classTag isEqualToString: @"DTSTAMP"]
+ || [classTag isEqualToString: @"DTSTART"]
+ || [classTag isEqualToString: @"CREATED"]
+ || [classTag isEqualToString: @"LAST-MODIFIED"])
+ tagClass = [iCalDateTime class];
+ else
+ tagClass = [super classForTag: classTag];
+
+ return tagClass;
+}
+
+/* accessors */
+
+- (void) setUid: (NSString *) _uid
+{
+ [[self uniqueChildWithTag: @"uid"] setValue: 0 to: _uid];
+}
+
+- (NSString *) uid
+{
+ return [[self uniqueChildWithTag: @"uid"] value: 0];
+}
+
+- (void) setSummary: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"summary"] setValue: 0 to: _value];
+}
+
+- (NSString *) summary
+{
+ return [[self uniqueChildWithTag: @"summary"] value: 0];
+}
+
+- (void) setLocation: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"location"] setValue: 0 to: _value];
+}
+
+- (NSString *) location
+{
+ return [[self uniqueChildWithTag: @"location"] value: 0];
+}
+
+- (void) setComment: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"description"] setValue: 0 to: _value];
+}
+
+- (NSString *) comment
+{
+ return [[self uniqueChildWithTag: @"description"] value: 0];
+}
+
+- (void) setAccessClass: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"class"] setValue: 0 to: _value];
+}
+
+- (NSString *) accessClass
+{
+ return [[self uniqueChildWithTag: @"class"] value: 0];
+}
+
+- (BOOL) isPublic
+{
+ return [[[self accessClass] uppercaseString] isEqualToString: @"PUBLIC"];
+}
+
+- (void) setPriority: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"priority"] setValue: 0 to: _value];
+}
+
+- (NSString *) priority
+{
+ return [[self uniqueChildWithTag: @"priority"] value: 0];
+}
+
+- (void) setCategories: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"categories"] setValue: 0 to: _value];
+}
+
+- (NSString *) categories
+{
+ return [[self uniqueChildWithTag: @"categories"] value: 0];
+}
+
+- (void) setUserComment: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"usercomment"] setValue: 0 to: _value];
+}
+
+- (NSString *) userComment
+{
+ return [[self uniqueChildWithTag: @"usercomment"] value: 0];
+}
+
+- (void) setStatus: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"status"] setValue: 0 to: _value];
+}
+
+- (NSString *) status
+{
+ return [[self uniqueChildWithTag: @"status"] value: 0];
+}
+
+- (void) setSequence: (NSNumber *)_value
+{
+ NSString *sequence;
+
+ sequence = [NSString stringWithFormat: @"%@", _value];
+ [[self uniqueChildWithTag: @"sequence"] setValue: 0
+ to: sequence];;
+}
+
+- (NSNumber *) sequence
+{
+ NSString *sequence;
+
+ sequence = [[self uniqueChildWithTag: @"sequence"] value: 0];
+
+ return [NSNumber numberWithInt: [sequence intValue]];
+}
+
+- (void) increaseSequence
+{
+ int seq;
+
+ seq = [[self sequence] intValue];
+ seq += 1;
+ [self setSequence: [NSNumber numberWithInt: seq]];
+}
+
+- (void) setCreated: (NSCalendarDate *) _value
+{
+ [self setDate: _value forDateTimeValue: @"created"];
+}
+
+- (NSCalendarDate *) created
+{
+ return [self dateForDateTimeValue: @"created"];
+}
+
+- (void) setLastModified: (NSCalendarDate *) _value
+{
+ [self setDate: _value forDateTimeValue: @"last-modified"];
+}
+
+- (NSCalendarDate *) lastModified
+{
+ return [self dateForDateTimeValue: @"last-modified"];
+}
+
+- (void) setTimeStampAsDate: (NSCalendarDate *) _value
+{
+ [self setDate: _value forDateTimeValue: @"dtstamp"];
+}
+
+- (NSCalendarDate *) timeStampAsDate
+{
+ return [self dateForDateTimeValue: @"dtstamp"];
+}
+
+- (void) setStartDate: (NSCalendarDate *) _value
+{
+ [self setDate: _value forDateTimeValue: @"dtstart"];
+}
+
+- (NSCalendarDate *) startDate
+{
+ return [self dateForDateTimeValue: @"dtstart"];
+}
+
+- (BOOL) hasStartDate
+{
+ return ([[self childrenWithTag: @"dtstart"] count] > 0);
+}
+
+- (void) setOrganizer: (iCalPerson *) _organizer
+{
+ [_organizer setTag: @"organizer"];
+ [self setUniqueChild: _organizer];
+}
+
+- (iCalPerson *) organizer
+{
+ return (iCalPerson *) [self uniqueChildWithTag: @"organizer"];
+}
+
+- (void) removeAllAttendees
+{
+ [children removeObjectsInArray: [self attendees]];
+}
+
+- (void) addToAttendees: (iCalPerson *) _person
+{
+ [_person setTag: @"attendee"];
+ [self addChild: _person];
+}
+
+- (void) setAttendees: (NSArray *) attendees
+{
+ [self removeAllAttendees];
+ [self addChildren: attendees];
+}
+
+- (NSArray *) attendees
+{
+ return [self childrenWithTag: @"attendee"];
+}
+
+- (void) removeAllAlarms
+{
+ [children removeObjectsInArray: [self alarms]];
+}
+
+- (void) addToAlarms: (id) _alarm
+{
+ if (_alarm)
+ {
+ [_alarm setTag: @"valarm"];
+ [self addChild: _alarm];
+ }
+}
+
+- (BOOL) hasAlarms
+{
+ return ([[self childrenWithTag: @"valarm"] count] > 0);
+}
+
+- (NSArray *) alarms
+{
+ return [self childrenWithTag: @"valarm"];
+}
+
+- (void) setUrl: (id) _value
+{
+ NSString *asString;
+
+ if ([_value isKindOfClass: [NSString class]])
+ asString = _value;
+ else if ([_value isKindOfClass: [NSURL class]])
+ asString = [_value absoluteString];
+ else
+ asString = @"";
+
+ [[self uniqueChildWithTag: @"url"] setValue: 0 to: asString];
+}
+
+- (NSURL *) url
+{
+ NSString *stringUrl;
+
+ stringUrl = [[self uniqueChildWithTag: @"url"] value: 0];
+
+ return [NSURL URLWithString: stringUrl];
+}
+
+/* stuff */
+
+- (NSArray *) participants
+{
+ return [self _filteredAttendeesThinkingOfPersons: YES];
+}
+
+- (NSArray *) resources
+{
+ return [self _filteredAttendeesThinkingOfPersons: NO];
+}
+
+- (NSArray *) _filteredAttendeesThinkingOfPersons: (BOOL) _persons
+{
+ NSArray *list;
+ NSMutableArray *filtered;
+ unsigned count, max;
+ iCalPerson *person;
+ NSString *role;
+
+ if (_persons)
+ {
+ list = [self attendees];
+ max = [list count];
+ filtered = [NSMutableArray arrayWithCapacity: max];
+ for (count = 0; count < max; count++)
+ {
+ person = (iCalPerson *) [list objectAtIndex: count];
+ role = [[person role] uppercaseString];
+ if (![role hasPrefix: @"NON-PART"])
+ [filtered addObject: person];
+ }
+
+ list = filtered;
+ }
+ else
+ list = [self childrenWithTag: @"attendee"
+ andAttribute: @"role"
+ havingValue: @"non-part"];
+
+ return list;
+}
+
+- (BOOL) isOrganizer: (id)_email
+{
+ _email = [_email lowercaseString];
+
+ return [[[[self organizer] rfc822Email] lowercaseString]
+ isEqualToString:_email];
+}
+
+- (BOOL) isParticipant: (id) _email
+{
+ NSArray *partEmails;
+
+ _email = [_email lowercaseString];
+ partEmails = [[self participants] valueForKey:@"rfc822Email"];
+ partEmails = [partEmails valueForKey: @"lowercaseString"];
+ return [partEmails containsObject:_email];
+}
+
+- (iCalPerson *) findParticipantWithEmail: (id) _email
+{
+ NSArray *ps;
+ unsigned i, count;
+
+ _email = [_email lowercaseString];
+ ps = [self participants];
+ count = [ps count];
+
+ for (i = 0; i < count; i++) {
+ iCalPerson *p;
+
+ p = [ps objectAtIndex:i];
+ if ([[[p rfc822Email] lowercaseString] isEqualToString:_email])
+ return p;
+ }
+
+ return nil; /* not found */
+}
+
+@end /* iCalEntityObject */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGCards_iCalEvent_H__
+#define __NGCards_iCalEvent_H__
+
+#import "iCalRepeatableEntityObject.h"
+
+/*
+ iCalEvent
+
+ This class keeps the attributes of an iCalendar event record, that is,
+ an appointment.
+*/
+
+@class NSCalendarDate;
+@class NSDate;
+@class NSString;
+@class NSMutableArray;
+
+@class NGCalendarDateRange;
+@class iCalEventChanges;
+
+@interface iCalEvent : iCalRepeatableEntityObject
+
+/* accessors */
+
+- (void) setEndDate: (NSCalendarDate *) _date;
+- (NSCalendarDate *) endDate;
+- (BOOL) hasEndDate;
+
+- (void) setDuration: (NSString *) _value;
+- (NSString *) duration;
+- (BOOL) hasDuration;
+- (NSTimeInterval) durationAsTimeInterval;
+
+- (void) setTransparency: (NSString *) _transparency;
+- (NSString *) transparency;
+
+/* convenience */
+
+- (BOOL) isOpaque;
+- (BOOL) isAllDay;
+
+- (BOOL) isWithinCalendarDateRange: (NGCalendarDateRange *) _range;
+- (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *)_r;
+
+- (NSCalendarDate *) lastPossibleRecurrenceStartDate;
+
+/* calculating changes */
+
+- (iCalEventChanges *) getChangesRelativeToEvent: (iCalEvent *) _event;
+
+@end
+
+#endif /* __NGCards_iCalEvent_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import <NGExtensions/NGCalendarDateRange.h>
+
+#import "NSCalendarDate+NGCards.h"
+#import "CardGroup+iCal.h"
+#import "NSString+NGCards.h"
+
+#import "iCalEventChanges.h"
+#import "iCalDateTime.h"
+
+#import "iCalEvent.h"
+
+@implementation iCalEvent
+
+- (Class) classForTag: (NSString *) classTag
+{
+ Class tagClass;
+
+ if ([classTag isEqualToString: @"DURATION"]
+ || [classTag isEqualToString: @"TRANSP"])
+ tagClass = [CardElement class];
+ else if ([classTag isEqualToString: @"DTEND"])
+ tagClass = [iCalDateTime class];
+ else
+ tagClass = [super classForTag: classTag];
+
+ return tagClass;
+}
+
+/* accessors */
+
+- (void) setEndDate: (NSCalendarDate *)_date
+{
+ [self setDate: _date forDateTimeValue: @"dtend"];
+}
+
+- (NSCalendarDate *) endDate
+{
+ return [self dateForDateTimeValue: @"dtend"];
+}
+
+- (BOOL) hasEndDate
+{
+ return ([[self childrenWithTag: @"dtend"] count] > 0);
+}
+
+- (void) setDuration: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"duration"] setValue: 0
+ to: _value];
+}
+
+- (NSString *) duration
+{
+ return [[self uniqueChildWithTag: @"duration"] value: 0];
+}
+
+- (BOOL) hasDuration
+{
+ return ([[self childrenWithTag: @"duration"] count] > 0);
+}
+
+- (NSTimeInterval) durationAsTimeInterval
+{
+ /*
+ eg: DURATION:PT1H
+ P - "period"
+ P2H30M - "2 hours 30 minutes"
+
+ dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
+
+ dur-date = dur-day [dur-time]
+ dur-time = "T" (dur-hour / dur-minute / dur-second)
+ dur-week = 1*DIGIT "W"
+ dur-hour = 1*DIGIT "H" [dur-minute]
+ dur-minute = 1*DIGIT "M" [dur-second]
+ dur-second = 1*DIGIT "S"
+ dur-day = 1*DIGIT "D"
+ */
+ NSTimeInterval interval;
+
+ if ([self hasDuration])
+ interval = [[self duration] durationAsTimeInterval];
+ else if ([self hasEndDate] && [self hasStartDate])
+ /* calculate duration using enddate */
+ interval = [[self endDate] timeIntervalSinceDate: [self startDate]];
+ else
+ interval = 0.0;
+
+ return interval;
+}
+
+- (void) setTransparency: (NSString *) _transparency
+{
+ [[self uniqueChildWithTag: @"transp"] setValue: 0
+ to: _transparency];
+}
+
+- (NSString *) transparency
+{
+ return [[self uniqueChildWithTag: @"transp"] value: 0];
+}
+
+/* convenience */
+
+- (BOOL) isOpaque
+{
+ NSString *s;
+
+ s = [[self transparency] uppercaseString];
+
+ return (![s isEqualToString: @"TRANSPARENT"]);
+}
+
+/* TODO: FIX THIS!
+ The problem is, that startDate/endDate are inappropriately modelled here.
+ We'd need to have a special iCalDate in order to fix all the mess.
+ For the time being, we chose allday to mean 00:00 - 23:59 in startDate's
+ timezone.
+*/
+- (BOOL) isAllDay
+{
+ NSCalendarDate *ed, *startDate;
+ BOOL allDay;
+
+ if ([self hasEndDate])
+ {
+ ed = [self endDate];
+ startDate = [self startDate];
+ [ed setTimeZone: [startDate timeZone]];
+ allDay = (([startDate hourOfDay] == 0)
+ && ([startDate minuteOfHour] == 0)
+ && ([ed hourOfDay] == 23)
+ && ([ed minuteOfHour] == 59));
+ }
+ else
+ allDay = NO;
+
+ return allDay;
+}
+
+- (BOOL) isWithinCalendarDateRange: (NGCalendarDateRange *) _range
+{
+ NGCalendarDateRange *r;
+ NSCalendarDate *startDate, *endDate;
+ NGCalendarDateRange *fir;
+
+ startDate = [self startDate];
+ endDate = [self endDate];
+
+ if (![self isRecurrent])
+ {
+ if ([self hasStartDate] && [self hasEndDate])
+ {
+ r = [NGCalendarDateRange calendarDateRangeWithStartDate: startDate
+ endDate: endDate];
+ return [_range containsDateRange: r];
+ }
+ else
+ return [_range containsDate: startDate];
+ }
+ else
+ {
+ fir = [NGCalendarDateRange calendarDateRangeWithStartDate:startDate
+ endDate: endDate];
+
+ return [self isWithinCalendarDateRange: _range
+ firstInstanceCalendarDateRange: fir];
+ }
+
+ return NO;
+}
+
+- (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *)_r
+{
+ NGCalendarDateRange *fir;
+
+ if (![self isRecurrent])
+ return nil;
+
+ fir = [NGCalendarDateRange calendarDateRangeWithStartDate: [self startDate]
+ endDate: [self endDate]];
+ return [self recurrenceRangesWithinCalendarDateRange:_r
+ firstInstanceCalendarDateRange:fir];
+}
+
+- (NSCalendarDate *) lastPossibleRecurrenceStartDate
+{
+ NGCalendarDateRange *fir;
+
+ if (![self isRecurrent])
+ return nil;
+
+ fir = [NGCalendarDateRange calendarDateRangeWithStartDate: [self startDate]
+ endDate: [self endDate]];
+
+ return [self lastPossibleRecurrenceStartDateUsingFirstInstanceCalendarDateRange: fir];
+}
+
+/* ical typing */
+
+- (NSString *) entityName
+{
+ return @"vevent";
+}
+
+/* descriptions */
+
+// - (NSString *) description {
+// NSMutableString *ms;
+
+// ms = [NSMutableString stringWithCapacity:128];
+// [ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
+
+// if (uid) [ms appendFormat:@" uid=%@", uid];
+// if (startDate) [ms appendFormat:@" from=%@", startDate];
+// if (endDate) [ms appendFormat:@" to=%@", endDate];
+// if (summary) [ms appendFormat:@" summary=%@", summary];
+
+// if (organizer)
+// [ms appendFormat:@" organizer=%@", organizer];
+// if (attendees)
+// [ms appendFormat:@" attendees=%@", attendees];
+
+// if ([self hasAlarms])
+// [ms appendFormat:@" alarms=%@", alarms];
+
+// [ms appendString:@">"];
+// return ms;
+// }
+
+/* changes */
+
+- (iCalEventChanges *) getChangesRelativeToEvent: (iCalEvent *) _event
+{
+ return [iCalEventChanges changesFromEvent: _event
+ toEvent: self];
+}
+
+@end /* iCalEvent */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+ */
+// Created by znek on 31.08.04.
+
+#ifndef __NGiCal_iCalEventChanges_H_
+#define __NGiCal_iCalEventChanges_H_
+
+#include <Foundation/NSObject.h>
+
+@class iCalEvent, NSArray, NSMutableArray;
+
+@interface iCalEventChanges : NSObject
+{
+ NSMutableArray *insertedAttendees;
+ NSMutableArray *deletedAttendees;
+ NSMutableArray *updatedAttendees;
+ NSMutableArray *insertedAlarms;
+ NSMutableArray *deletedAlarms;
+ NSMutableArray *updatedAlarms;
+ NSMutableArray *updatedProperties;
+}
+
++ (id)changesFromEvent:(iCalEvent *)_old toEvent:(iCalEvent *)_to;
+- (id)initWithFromEvent:(iCalEvent *)_from toEvent:(iCalEvent *)_to;
+
+- (BOOL)hasChanges;
+
+- (BOOL)hasAttendeeChanges;
+- (NSArray *)insertedAttendees;
+- (NSArray *)deletedAttendees;
+- (NSArray *)updatedAttendees;
+
+- (BOOL)hasAlarmChanges;
+- (NSArray *)insertedAlarms;
+- (NSArray *)deletedAlarms;
+- (NSArray *)updatedAlarms;
+
+- (BOOL)hasPropertyChanges;
+- (NSArray *)updatedProperties;
+
+@end
+
+#endif /* __NGiCal_iCalEventChanges_H_ */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+ */
+
+
+#include "iCalEventChanges.h"
+#include "iCalEvent.h"
+#include "iCalPerson.h"
+#include "common.h"
+
+@interface iCalEventChanges (PrivateAPI)
+- (void)_trackAttendeeChanges:(iCalEvent *)_from :(iCalEvent *)_to;
+- (void)_trackAlarmChanges:(iCalEvent *)_from :(iCalEvent *)_to;
+- (void)_trackPropertyChanges:(iCalEvent *)_from :(iCalEvent *)_to;
+@end
+
+@implementation iCalEventChanges
+
++ (id)changesFromEvent:(iCalEvent *)_from toEvent:(iCalEvent *)_to {
+ return [[[self alloc] initWithFromEvent:_from toEvent:_to] autorelease];
+}
+
+- (id)initWithFromEvent:(iCalEvent *)_from toEvent:(iCalEvent *)_to {
+ self = [super init];
+ if(self) {
+ self->insertedAttendees = [[NSMutableArray alloc] init];
+ self->deletedAttendees = [[NSMutableArray alloc] init];
+ self->updatedAttendees = [[NSMutableArray alloc] init];
+ self->insertedAlarms = [[NSMutableArray alloc] init];
+ self->deletedAlarms = [[NSMutableArray alloc] init];
+ self->updatedAlarms = [[NSMutableArray alloc] init];
+ self->updatedProperties = [[NSMutableArray alloc] init];
+ [self _trackAttendeeChanges:_from :_to];
+ [self _trackPropertyChanges:_from :_to];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self->insertedAttendees release];
+ [self->deletedAttendees release];
+ [self->updatedAttendees release];
+ [self->insertedAlarms release];
+ [self->deletedAlarms release];
+ [self->updatedAlarms release];
+ [self->updatedProperties release];
+ [super dealloc];
+}
+
+- (void)_trackAttendeeChanges:(iCalEvent *)_from :(iCalEvent *)_to {
+ unsigned f, t, fcount, tcount;
+ NSArray *fromAttendees, *toAttendees;
+
+ fromAttendees = [_from attendees];
+ fcount = [fromAttendees count];
+ toAttendees = [_to attendees];
+ tcount = [toAttendees count];
+ for(f = 0; f < fcount; f++) {
+ iCalPerson *fp;
+ BOOL found = NO;
+
+ fp = [fromAttendees objectAtIndex:f];
+
+ for(t = 0; t < tcount; t++) {
+ iCalPerson *tp;
+
+ tp = [toAttendees objectAtIndex:t];
+ if([fp hasSameEmailAddress:tp]) {
+ found = YES;
+ if(![fp isEqualToPerson:tp]) {
+ [self->updatedAttendees addObject:tp];
+ }
+ break;
+ }
+ }
+ if(!found) {
+ [self->deletedAttendees addObject:fp];
+ }
+ }
+ for(t = 0; t < tcount; t++) {
+ iCalPerson *tp;
+ BOOL found = NO;
+
+ tp = [toAttendees objectAtIndex:t];
+ for(f = 0; f < fcount; f++) {
+ iCalPerson *fp;
+
+ fp = [fromAttendees objectAtIndex:f];
+ if([tp hasSameEmailAddress:fp]) {
+ found = YES;
+ break;
+ }
+ }
+ if(!found)
+ [self->insertedAttendees addObject:tp];
+ }
+}
+
+- (void)_trackAlarmChanges:(iCalEvent *)_from :(iCalEvent *)_to {
+}
+
+- (void)_trackPropertyChanges:(iCalEvent *)_from :(iCalEvent *)_to {
+ if(!IS_EQUAL([_from startDate], [_to startDate], isEqualToDate:))
+ [self->updatedProperties addObject:@"startDate"];
+ if(!IS_EQUAL([_from endDate], [_to endDate], isEqualToDate:))
+ [self->updatedProperties addObject:@"endDate"];
+ if(!IS_EQUAL([_from created], [_to created], isEqualToDate:))
+ [self->updatedProperties addObject:@"created"];
+ if(!IS_EQUAL([_from lastModified], [_to lastModified], isEqualToDate:))
+ [self->updatedProperties addObject:@"lastModified"];
+ if(![_from durationAsTimeInterval] == [_to durationAsTimeInterval])
+ [self->updatedProperties addObject:@"duration"];
+ if(!IS_EQUAL([_from summary], [_to summary], isEqualToString:))
+ [self->updatedProperties addObject:@"summary"];
+ if(!IS_EQUAL([_from location], [_to location], isEqualToString:))
+ [self->updatedProperties addObject:@"location"];
+ if(!IS_EQUAL([_from comment], [_to comment], isEqualToString:))
+ [self->updatedProperties addObject:@"comment"];
+ if(!IS_EQUAL([_from priority], [_to priority], isEqualToString:))
+ [self->updatedProperties addObject:@"priority"];
+ if(!IS_EQUAL([_from status], [_to status], isEqualToString:))
+ [self->updatedProperties addObject:@"status"];
+ if(!IS_EQUAL([_from accessClass], [_to accessClass], isEqualToString:))
+ [self->updatedProperties addObject:@"accessClass"];
+ if(!IS_EQUAL([_from sequence], [_to sequence], isEqualToNumber:))
+ [self->updatedProperties addObject:@"sequence"];
+ if(!IS_EQUAL([_from organizer], [_to organizer], isEqual:))
+ [self->updatedProperties addObject:@"organizer"];
+}
+
+- (BOOL)hasChanges {
+ return [self hasAttendeeChanges] ||
+ [self hasAlarmChanges] ||
+ [self hasPropertyChanges];
+}
+
+- (BOOL)hasAttendeeChanges {
+ return [[self insertedAttendees] count] > 0 ||
+ [[self deletedAttendees] count] > 0 ||
+ [[self updatedAttendees] count] > 0;
+}
+
+- (BOOL)hasAlarmChanges {
+ return [[self insertedAlarms] count] > 0 ||
+ [[self deletedAlarms] count] > 0 ||
+ [[self updatedAlarms] count] > 0;
+}
+
+- (BOOL)hasPropertyChanges {
+ return [[self updatedProperties] count] > 0;
+}
+
+- (NSArray *)insertedAttendees {
+ return self->insertedAttendees;
+}
+- (NSArray *)deletedAttendees {
+ return self->deletedAttendees;
+}
+- (NSArray *)updatedAttendees {
+ return self->updatedAttendees;
+}
+
+- (NSArray *)insertedAlarms {
+ return self->insertedAlarms;
+}
+- (NSArray *)deletedAlarms {
+ return self->deletedAlarms;
+}
+- (NSArray *)updatedAlarms {
+ return self->updatedAlarms;
+}
+
+- (NSArray *)updatedProperties {
+ return self->updatedProperties;
+}
+
+/* descriptions */
+
+- (NSString *)description {
+ NSMutableString *ms;
+
+ ms = [NSMutableString stringWithCapacity:128];
+ [ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
+
+ [ms appendFormat:@" updatedProperties=%@", self->updatedProperties];
+ [ms appendFormat:@" insertedAttendees=%@", self->insertedAttendees];
+ [ms appendFormat:@" deletedAttendees=%@", self->deletedAttendees];
+ [ms appendFormat:@" updatedAttendees=%@", self->updatedAttendees];
+
+ [ms appendString:@">"];
+ return ms;
+}
+
+@end
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGCards_iCalFreeBusy_H__
+#define __NGCards_iCalFreeBusy_H__
+
+#import "iCalEntityObject.h"
+
+@class NSString;
+@class NSCalendarDate;
+@class NSURL;
+@class iCalPerson;
+
+typedef enum iCalFreeBusyType
+{
+ iCalFBBusy,
+ iCalFBFree,
+ iCalFBBusyUnavailable,
+ iCalFBBusyTentative
+} iCalFreeBusyType;
+
+@interface iCalFreeBusy : iCalEntityObject
+
+- (void) setEndDate: (NSCalendarDate *) _date;
+- (NSCalendarDate *) endDate;
+- (BOOL) hasEndDate;
+
+- (void) addFreeBusyFrom: (NSCalendarDate *) start
+ to: (NSCalendarDate *) end
+ type: (iCalFreeBusyType) type;
+
+@end
+
+#endif /* __NGCards_iCalFreeBusy_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSString.h>
+#import <Foundation/NSTimeZone.h>
+
+#import "CardGroup+iCal.h"
+#import "iCalDateTime.h"
+#import "NSCalendarDate+NGCards.h"
+
+#import "iCalFreeBusy.h"
+
+@implementation iCalFreeBusy
+
+- (Class) classForTag: (NSString *) classTag
+{
+ Class tagClass;
+
+ if ([classTag isEqualToString: @"DTEND"])
+ tagClass = [iCalDateTime class];
+ else if ([classTag isEqualToString: @"FREEBUSY"])
+ tagClass = [CardElement class];
+ else
+ tagClass = [super classForTag: classTag];
+
+ return tagClass;
+}
+
+/* accessors */
+- (void) setEndDate: (NSCalendarDate *)_date
+{
+ [self setDate: _date forDateTimeValue: @"dtend"];
+}
+
+- (NSCalendarDate *) endDate
+{
+ return [self dateForDateTimeValue: @"dtend"];
+}
+
+- (BOOL) hasEndDate
+{
+ return ([[self childrenWithTag: @"dtend"] count] > 0);
+}
+
+- (NSString *) _freeBusyTypeString: (iCalFreeBusyType) type
+{
+ NSString *typeString;
+
+ switch (type)
+ {
+ case iCalFBBusy:
+ typeString = @"BUSY";
+ break;
+ case iCalFBFree:
+ typeString = @"FREE";
+ break;
+ case iCalFBBusyUnavailable:
+ typeString = @"BUSY-UNAVAILABLE";
+ break;
+ default:
+ typeString = @"BUSY-TENTATIVE";
+ }
+
+ return typeString;
+}
+
+- (void) addFreeBusyFrom: (NSCalendarDate *) start
+ to: (NSCalendarDate *) end
+ type: (iCalFreeBusyType) type
+{
+ CardElement *freeBusyElement;
+ NSString *value;
+ NSCalendarDate *utcStart, *utcEnd;
+ NSTimeZone *uTZ;
+
+ uTZ = [NSTimeZone timeZoneWithAbbreviation: @"GMT"];
+ utcStart = [start copy];
+ utcEnd = [end copy];
+ [utcStart setTimeZone: uTZ];
+ [utcEnd setTimeZone: uTZ];
+
+ value = [NSString stringWithFormat: @"%@Z/%@Z",
+ [utcStart iCalFormattedDateTimeString],
+ [utcEnd iCalFormattedDateTimeString]];
+ freeBusyElement = [CardElement simpleElementWithTag: @"freebusy"
+ value: value];
+ [freeBusyElement addAttribute: @"fbtype"
+ value: [self _freeBusyTypeString: type]];
+ [self addChild: freeBusyElement];
+
+ [utcStart release];
+ [utcEnd release];
+}
+
+/* ical typing */
+
+- (NSString *) entityName
+{
+ return @"vfreebusy";
+}
+
+@end /* iCalFreeBusy */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGCards_iCalJournal_H__
+#define __NGCards_iCalJournal_H__
+
+#import "CardGroup.h"
+
+@interface iCalJournal : CardGroup
+{
+}
+
+@end
+
+#endif /* __NGCards_iCalJournal_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalJournal.h"
+#include "common.h"
+
+@implementation iCalJournal
+
+/* ical typing */
+
+- (NSString *) entityName
+{
+ return @"vjournal";
+}
+
+/* descriptions */
+
+@end /* iCalJournal */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalRecurrenceCalculator.h"
+
+@interface iCalMonthlyRecurrenceCalculator : iCalRecurrenceCalculator
+@end
+
+#include <NGExtensions/NGCalendarDateRange.h>
+#include "iCalRecurrenceRule.h"
+#include "NSCalendarDate+ICal.h"
+#include "common.h"
+#include <string.h>
+
+@interface iCalRecurrenceCalculator(PrivateAPI)
+- (NSCalendarDate *)lastInstanceStartDate;
+@end
+
+// #define HEAVY_DEBUG 1
+
+@implementation iCalMonthlyRecurrenceCalculator
+
+typedef BOOL NGMonthSet[12];
+typedef BOOL NGMonthDaySet[32]; // 0 is unused
+
+static void NGMonthDaySet_clear(NGMonthDaySet *daySet) {
+ register unsigned i;
+
+ for (i = 1; i <= 31; i++)
+ (*daySet)[i] = NO;
+}
+
+static void NGMonthDaySet_copyOrUnion(NGMonthDaySet *base, NGMonthDaySet *new,
+ BOOL doCopy)
+{
+ register unsigned i;
+
+ if (doCopy)
+ memcpy(base, new, sizeof(NGMonthDaySet));
+ else {
+ for (i = 1; i <= 31; i++) {
+ if (!(*new)[i])
+ (*base)[i] = NO;
+ }
+ }
+}
+
+static BOOL NGMonthDaySet_fillWithByMonthDay(NGMonthDaySet *daySet,
+ NSArray *byMonthDay)
+{
+ /* list of days in the month */
+ unsigned i, count;
+ BOOL ok;
+
+ NGMonthDaySet_clear(daySet);
+
+ for (i = 0, count = [byMonthDay count], ok = YES; i < count; i++) {
+ int dayInMonth; /* -31..-1 and 1..31 */
+
+ if ((dayInMonth = [[byMonthDay objectAtIndex:i] intValue]) == 0) {
+ ok = NO;
+ continue; /* invalid value */
+ }
+ if (dayInMonth > 31) {
+ ok = NO;
+ continue; /* error, value to large */
+ }
+ if (dayInMonth < -31) {
+ ok = NO;
+ continue; /* error, value to large */
+ }
+
+ /* adjust negative days */
+
+ if (dayInMonth < 0) {
+ /* eg: -1 == last day in month, 30 days => 30 */
+ dayInMonth = 32 - dayInMonth /* because we count from 1 */;
+ }
+
+ (*daySet)[dayInMonth] = YES;
+ }
+ return ok;
+}
+
+static inline unsigned iCalDoWForNSDoW(int dow) {
+ switch (dow) {
+ case 0: return iCalWeekDaySunday;
+ case 1: return iCalWeekDayMonday;
+ case 2: return iCalWeekDayTuesday;
+ case 3: return iCalWeekDayWednesday;
+ case 4: return iCalWeekDayThursday;
+ case 5: return iCalWeekDayFriday;
+ case 6: return iCalWeekDaySaturday;
+ case 7: return iCalWeekDaySunday;
+ default: return 0;
+ }
+}
+
+#if HEAVY_DEBUG
+static NSString *dowEN[8] = {
+ @"SU", @"MO", @"TU", @"WE", @"TH", @"FR", @"SA", @"SU-"
+};
+#endif
+
+static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
+ unsigned dayMask,
+ unsigned firstDoWInMonth,
+ unsigned numberOfDaysInMonth,
+ int occurrence1)
+{
+ // TODO: this is called 'X' because the API doesn't allow for full iCalendar
+ // functionality. The daymask must be a list of occurence+dow
+ register unsigned dayInMonth;
+ register int dow; /* current day of the week */
+ int occurrences[7] = { 0, 0, 0, 0, 0, 0, 0 } ;
+
+ NGMonthDaySet_clear(daySet);
+
+ if (occurrence1 >= 0) {
+ for (dayInMonth = 1, dow = firstDoWInMonth; dayInMonth<=31; dayInMonth++) {
+ // TODO: complete me
+
+ if (dayMask & iCalDoWForNSDoW(dow)) {
+ if (occurrence1 == 0)
+ (*daySet)[dayInMonth] = YES;
+ else { /* occurrence1 > 0 */
+ occurrences[dow] = occurrences[dow] + 1;
+
+ if (occurrences[dow] == occurrence1)
+ (*daySet)[dayInMonth] = YES;
+ }
+ }
+
+ dow = (dow == 6 /* Sat */) ? 0 /* Sun */ : (dow + 1);
+ }
+ }
+ else {
+ int lastDoWInMonthSet;
+
+ /* get the last dow in the set (not necessarily the month!) */
+ for (dayInMonth = 1, dow = firstDoWInMonth;
+ dayInMonth < numberOfDaysInMonth;dayInMonth++)
+ dow = (dow == 6 /* Sat */) ? 0 /* Sun */ : (dow + 1);
+ lastDoWInMonthSet = dow;
+
+#if HEAVY_DEBUG
+ NSLog(@"LAST DOW IN SET: %i / %@",
+ lastDoWInMonthSet, dowEN[lastDoWInMonthSet]);
+#endif
+ /* start at the end of the set */
+ for (dayInMonth = numberOfDaysInMonth, dow = lastDoWInMonthSet;
+ dayInMonth >= 1; dayInMonth--) {
+ // TODO: complete me
+
+#if HEAVY_DEBUG
+ NSLog(@" CHECK day-of-month %02i, "
+ @" dow=%i/%@ (first=%i/%@, last=%i/%@)",
+ dayInMonth,
+ dow, dowEN[dow],
+ firstDoWInMonth, dowEN[firstDoWInMonth],
+ lastDoWInMonthSet, dowEN[lastDoWInMonthSet]
+ );
+#endif
+
+ if (dayMask & iCalDoWForNSDoW(dow)) {
+ occurrences[dow] = occurrences[dow] + 1;
+#if HEAVY_DEBUG
+ NSLog(@" MATCH %i/%@ count: %i occurences=%i",
+ dow, dowEN[dow], occurrences[dow], occurrence1);
+#endif
+
+ if (occurrences[dow] == -occurrence1) {
+#if HEAVY_DEBUG
+ NSLog(@" COUNT MATCH");
+#endif
+ (*daySet)[dayInMonth] = YES;
+ }
+ }
+
+ dow = (dow == 0 /* Sun */) ? 6 /* Sat */ : (dow - 1);
+ }
+ }
+}
+
+- (BOOL)_addInstanceWithStartDate:(NSCalendarDate *)_startDate
+ limitDate:(NSCalendarDate *)_until
+ limitRange:(NGCalendarDateRange *)_r
+ toArray:(NSMutableArray *)_ranges
+{
+ NGCalendarDateRange *r;
+ NSCalendarDate *end;
+
+ /* check whether we are still in the limits */
+
+ // TODO: I think we should check in here whether we succeeded the
+ // repeatCount. Currently we precalculate that info in the
+ // -lastInstanceStartDate method.
+ if (_until != nil) {
+ /* Note: the 'until' in the rrule is inclusive as per spec */
+ if ([_until compare:_startDate] == NSOrderedAscending)
+ /* start after until */
+ return NO; /* Note: we assume that the algorithm is sequential */
+ }
+
+ /* create end date */
+
+ end = [_startDate addTimeInterval:[self->firstRange duration]];
+ [end setTimeZone:[_startDate timeZone]];
+
+ /* create range and check whether its in the requested range */
+
+ r = [[NGCalendarDateRange alloc] initWithStartDate:_startDate endDate:end];
+ if ([_r containsDateRange:r])
+ [_ranges addObject:r];
+ [r release]; r = nil;
+
+ return YES;
+}
+
+- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{
+ /* main entry */
+ // TODO: check whether this is OK for multiday-events!
+ NSMutableArray *ranges;
+ NSTimeZone *timeZone;
+ NSCalendarDate *eventStartDate, *rStart, *rEnd, *until;
+ int eventDayOfMonth;
+ unsigned monthIdxInRange, numberOfMonthsInRange, interval;
+ int diff;
+ NGMonthSet byMonthList = { // TODO: fill from rrule, this is the default
+ YES, YES, YES, YES, YES, YES,
+ YES, YES, YES, YES, YES, YES
+ };
+ NSArray *byMonthDay = nil; // array of ints (-31..-1 and 1..31)
+ NGMonthDaySet byMonthDaySet;
+
+ eventStartDate = [self->firstRange startDate];
+ eventDayOfMonth = [eventStartDate dayOfMonth];
+ timeZone = [eventStartDate timeZone];
+ rStart = [_r startDate];
+ rEnd = [_r endDate];
+ interval = [self->rrule repeatInterval];
+ until = [self lastInstanceStartDate]; // TODO: maybe replace
+ byMonthDay = [self->rrule byMonthDay];
+
+
+ /* check whether the range to be processed is beyond the 'until' date */
+
+ if (until != nil) {
+ if ([until compare:rStart] == NSOrderedAscending) /* until before start */
+ return nil;
+ if ([until compare:rEnd] == NSOrderedDescending) /* end before until */
+ rEnd = until; // TODO: why is that? end is _before_ until?
+ }
+
+
+ /* precalculate month days (same for all instances) */
+
+ if (byMonthDay != nil)
+ NGMonthDaySet_fillWithByMonthDay(&byMonthDaySet, byMonthDay);
+
+
+ // TODO: I think the 'diff' is to skip recurrence which are before the
+ // requested range. Not sure whether this is actually possible, eg
+ // the repeatCount must be processed from the start.
+ diff = [eventStartDate monthsBetweenDate:rStart];
+ if ((diff != 0) && [rStart compare:eventStartDate] == NSOrderedAscending)
+ diff = -diff;
+
+ numberOfMonthsInRange = [rStart monthsBetweenDate:rEnd] + 1;
+ ranges = [NSMutableArray arrayWithCapacity:numberOfMonthsInRange];
+
+ /*
+ Note: we do not add 'eventStartDate', this is intentional, the event date
+ itself is _not_ necessarily part of the sequence, eg with monthly
+ byday recurrences.
+ */
+
+ for (monthIdxInRange = 0; monthIdxInRange < numberOfMonthsInRange;
+ monthIdxInRange++) {
+ NSCalendarDate *cursor;
+ unsigned numDaysInMonth;
+ int monthIdxInRecurrence, dom;
+ NGMonthDaySet monthDays;
+ BOOL didByFill, doCont;
+
+ monthIdxInRecurrence = diff + monthIdxInRange;
+
+ if (monthIdxInRecurrence < 0)
+ continue;
+
+ /* first check whether we are in the interval */
+
+ if ((monthIdxInRecurrence % interval) != 0)
+ continue;
+
+ /*
+ Then the sequence is:
+ - check whether the month is in the BYMONTH list
+ */
+
+ cursor = [eventStartDate dateByAddingYears:0
+ months:(diff + monthIdxInRange)
+ days:0];
+ [cursor setTimeZone:timeZone];
+ numDaysInMonth = [cursor numberOfDaysInMonth];
+
+
+ /* check whether we match the bymonth specification */
+
+ if (!byMonthList[[cursor monthOfYear] - 1])
+ continue;
+
+
+ /* check 'day level' byXYZ rules */
+
+ didByFill = NO;
+
+ if (byMonthDay != nil) { /* list of days in the month */
+ NGMonthDaySet_copyOrUnion(&monthDays, &byMonthDaySet, !didByFill);
+ didByFill = YES;
+ }
+
+ if ([self->rrule byDayMask] != 0) { // TODO: replace the mask with an array
+ NGMonthDaySet ruleset;
+ unsigned firstDoWInMonth;
+
+ firstDoWInMonth = [[cursor firstDayOfMonth] dayOfWeek];
+
+ NGMonthDaySet_fillWithByDayX(&ruleset,
+ [self->rrule byDayMask],
+ firstDoWInMonth,
+ [cursor numberOfDaysInMonth],
+ [self->rrule byDayOccurence1]);
+ NGMonthDaySet_copyOrUnion(&monthDays, &ruleset, !didByFill);
+ didByFill = YES;
+ }
+
+ if (!didByFill) {
+ /* no rules applied, take the dayOfMonth of the startDate */
+ NGMonthDaySet_clear(&monthDays);
+ monthDays[eventDayOfMonth] = YES;
+ }
+
+ // TODO: add processing of byhour/byminute/bysecond etc
+
+ for (dom = 1, doCont = YES; dom <= numDaysInMonth && doCont; dom++) {
+ NSCalendarDate *start;
+
+ if (!monthDays[dom])
+ continue;
+
+ if (eventDayOfMonth == dom)
+ start = cursor;
+ else {
+ start = [cursor dateByAddingYears:0 months:0
+ days:(dom - eventDayOfMonth)];
+ }
+
+ doCont = [self _addInstanceWithStartDate:start
+ limitDate:until
+ limitRange:_r
+ toArray:ranges];
+ }
+ if (!doCont) break; /* reached some limit */
+ }
+ return ranges;
+}
+
+- (NSCalendarDate *)lastInstanceStartDate {
+ if ([self->rrule repeatCount] > 0) {
+ NSCalendarDate *until;
+ unsigned months, interval;
+
+ interval = [self->rrule repeatInterval];
+ months = [self->rrule repeatCount] - 1 /* the first counts as one! */;
+
+ if (interval > 0)
+ months *= interval;
+
+ until = [[self->firstRange startDate] dateByAddingYears:0
+ months:months
+ days:0];
+ return until;
+ }
+ return [super lastInstanceStartDate];
+}
+
+@end /* iCalMonthlyRecurrenceCalculator */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+/* WAS: class being obsoleted !! */
+
+#ifndef __NGiCal_iCalObject_H__
+#define __NGiCal_iCalObject_H__
+
+#import <Foundation/NSObject.h>
+#import <Foundation/NSDate.h>
+
+/*
+ iCalObject
+
+ A common base class for all iCal objects. Does some patches on key-value
+ coding.
+*/
+
+@class NSTimeZone;
+
+@interface iCalObject : NSObject <NSCopying>
+{
+}
+
+// what shall we take, if no timeZone is specified in dateValues
++ (void)setICalDefaultTimeZone:(NSTimeZone *)_timeZone;
++ (NSTimeZone *)iCalDefaultTimeZone;
+
+@end
+
+
+
+#endif /* __NGiCal_iCalObject_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalObject.h"
+#include "common.h"
+
+@implementation iCalObject
+
++ (int)version {
+ return 0;
+}
+
+// what shall we take, if no timeZone is specified in dateValues
+static NSTimeZone *defTZ = nil;
++ (void)setICalDefaultTimeZone:(NSTimeZone *)_timeZone {
+ ASSIGNCOPY(defTZ,_timeZone);
+}
++ (NSTimeZone *)iCalDefaultTimeZone {
+ return defTZ;
+}
+
+- (void)dealloc {
+ [super dealloc];
+}
+
+/* NSCopying */
+
+- (id)copyWithZone:(NSZone *)_zone {
+ iCalObject *new;
+
+ new = [[[self class] allocWithZone:_zone] init];
+ return new;
+}
+
+/* KVC */
+
+- (void)takeValue:(id)_value forXKey:(id)_key {
+ /* extended keys are ignored by default */
+}
+
+- (void)handleTakeValue:(id)_value forUnboundKey:(NSString *)_key {
+ if ([_key hasPrefix:@"X-"]) {
+ [self takeValue:_value forXKey:_key];
+ }
+ else {
+ NSLog(@"0x%08x[%@]: ignoring attempt to set unbound key '%@'",
+ self, NSStringFromClass([self class]), _key);
+ }
+}
+
+@end /* iCalObject */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGCards_iCalPerson_H__
+#define __NGCards_iCalPerson_H__
+
+#import "CardElement.h"
+
+typedef enum {
+ iCalPersonPartStatNeedsAction = 0, /* NEEDS-ACTION (DEFAULT) */
+ iCalPersonPartStatAccepted = 1, /* ACCEPTED */
+ iCalPersonPartStatDeclined = 2, /* DECLINED */
+ /* up to here defined for VJOURNAL */
+ iCalPersonPartStatTentative = 3, /* TENTATIVE */
+ iCalPersonPartStatDelegated = 4, /* DELEGATED */
+ /* up to here defined for VEVENT */
+ iCalPersonPartStatCompleted = 5, /* COMPLETED */
+ iCalPersonPartStatInProcess = 6, /* IN-PROCESS */
+ /* up to there defined for VTODO */
+
+ /* these are also defined for VJOURNAL, VEVENT and VTODO */
+ iCalPersonPartStatExperimental = 7, /* x-name */
+ iCalPersonPartStatOther = 8 /* iana-token */
+} iCalPersonPartStat;
+
+@interface iCalPerson : CardElement
+
+/* accessors */
+
+- (void)setCn:(NSString *)_s;
+- (NSString *)cn;
+- (NSString *)cnWithoutQuotes;
+
+- (void)setEmail:(NSString *)_s;
+- (NSString *)email;
+- (NSString *)rfc822Email; /* email without 'mailto:' prefix */
+
+- (void)setRsvp:(NSString *)_s;
+- (NSString *)rsvp;
+
+// - (void)setXuid:(NSString *)_s;
+// - (NSString *)xuid;
+
+- (void)setRole:(NSString *)_s;
+- (NSString *)role;
+
+- (void)setPartStat:(NSString *)_s;
+- (NSString *)partStat;
+- (NSString *)partStatWithDefault;
+
+- (void)setParticipationStatus:(iCalPersonPartStat)_status;
+- (iCalPersonPartStat)participationStatus;
+
+- (BOOL)isEqualToPerson:(iCalPerson *)_other;
+- (BOOL)hasSameEmailAddress:(iCalPerson *)_other;
+
+@end
+
+#endif /* __NGCards_iCalPerson_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalPerson.h"
+#include "common.h"
+
+@implementation iCalPerson
+
+/* accessors */
+
+- (void) setCn: (NSString *) _s
+{
+ [self setValue: 0 ofAttribute: @"cn" to: _s];
+}
+
+- (NSString *) cn
+{
+ return [self value: 0 ofAttribute: @"cn"];
+}
+
+- (NSString *) cnWithoutQuotes
+{
+ /* remove quotes around a CN */
+ NSString *_cn;
+
+ _cn = [self cn];
+ if ([_cn length] <= 2)
+ return _cn;
+ if ([_cn characterAtIndex:0] != '"')
+ return _cn;
+ if (![_cn hasSuffix:@"\""])
+ return _cn;
+
+ return [_cn substringWithRange:NSMakeRange(1, [_cn length] - 2)];
+}
+
+- (void) setEmail: (NSString *)_s
+{
+ [self setValue: 0
+ to: [NSString stringWithFormat: @"MAILTO:%@", _s]];
+}
+
+- (NSString *) email
+{
+ return [self value: 0];
+}
+
+- (NSString *) rfc822Email
+{
+ NSString *_email;
+ unsigned idx;
+
+ _email = [self email];
+ idx = NSMaxRange([_email rangeOfString:@":"]);
+
+ if ((idx > 0) && ([_email length] > idx))
+ return [_email substringFromIndex:idx];
+
+ return _email;
+}
+
+- (void) setRsvp: (NSString *) _s
+{
+ [self setValue: 0 ofAttribute: @"rsvp" to: _s];
+}
+
+- (NSString *) rsvp
+{
+ return [self value: 0 ofAttribute: @"rsvp"];
+}
+
+// - (void)setXuid:(NSString *)_s {
+// ASSIGNCOPY(self->xuid, _s);
+// }
+// - (NSString *)xuid {
+// return self->xuid;
+// }
+
+- (void)setRole:(NSString *)_s
+{
+ [self setValue: 0 ofAttribute: @"role" to: _s];
+}
+
+- (NSString *) role
+{
+ return [self value: 0 ofAttribute: @"role"];
+}
+
+- (void)setPartStat:(NSString *)_s
+{
+ [self setValue: 0 ofAttribute: @"partstat" to: _s];
+}
+
+- (NSString *) partStat
+{
+ return [self value: 0 ofAttribute: @"partstat"];
+}
+
+- (NSString *) partStatWithDefault
+{
+ NSString *s;
+
+ s = [self partStat];
+ if ([s length] > 0)
+ return s;
+
+ return @"NEEDS-ACTION";
+}
+
+- (void) setParticipationStatus: (iCalPersonPartStat) _status
+{
+ NSString *stat;
+
+ switch (_status) {
+ case iCalPersonPartStatAccepted:
+ stat = @"ACCEPTED";
+ break;
+ case iCalPersonPartStatDeclined:
+ stat = @"DECLINED";
+ break;
+ case iCalPersonPartStatTentative:
+ stat = @"TENTATIVE";
+ break;
+ case iCalPersonPartStatDelegated:
+ stat = @"DELEGATED";
+ break;
+ case iCalPersonPartStatCompleted:
+ stat = @"COMPLETED";
+ break;
+ case iCalPersonPartStatInProcess:
+ stat = @"IN-PROCESS";
+ break;
+ case iCalPersonPartStatExperimental:
+ case iCalPersonPartStatOther:
+// [NSException raise:NSInternalInconsistencyException
+// format:@"Attempt to set meaningless "
+// @"participationStatus (%d)!", _status];
+ stat = nil; /* keep compiler happy */
+ break;
+ default:
+ stat = @"NEEDS-ACTION";
+ break;
+ }
+ if (stat)
+ [self setPartStat:stat];
+}
+
+- (iCalPersonPartStat)participationStatus {
+ NSString *stat;
+
+ stat = [[self partStat] uppercaseString];
+ if (![stat length] || [stat isEqualToString:@"NEEDS-ACTION"])
+ return iCalPersonPartStatNeedsAction;
+ else if ([stat isEqualToString:@"ACCEPTED"])
+ return iCalPersonPartStatAccepted;
+ else if ([stat isEqualToString:@"DECLINED"])
+ return iCalPersonPartStatDeclined;
+ else if ([stat isEqualToString:@"TENTATIVE"])
+ return iCalPersonPartStatTentative;
+ else if ([stat isEqualToString:@"DELEGATED"])
+ return iCalPersonPartStatDelegated;
+ else if ([stat isEqualToString:@"COMPLETED"])
+ return iCalPersonPartStatCompleted;
+ else if ([stat isEqualToString:@"IN-PROCESS"])
+ return iCalPersonPartStatInProcess;
+ else if ([stat hasPrefix:@"X-"])
+ return iCalPersonPartStatExperimental;
+ return iCalPersonPartStatOther;
+}
+
+
+/* comparison */
+
+- (unsigned)hash {
+ if([self email])
+ return [[self email] hash];
+ return [super hash];
+}
+
+- (BOOL)isEqual:(id)_other {
+ if(_other == nil)
+ return NO;
+ if([_other class] != self->isa)
+ return NO;
+ if([_other hash] != [self hash])
+ return NO;
+ return [self isEqualToPerson:_other];
+}
+
+- (BOOL)isEqualToPerson:(iCalPerson *)_other {
+ if(![self hasSameEmailAddress:_other])
+ return NO;
+ if(!IS_EQUAL([self cn], [_other cn], isEqualToString:))
+ return NO;
+ if(!IS_EQUAL([self rsvp], [_other rsvp], isEqualToString:))
+ return NO;
+ if(!IS_EQUAL([self partStat], [_other partStat], isEqualToString:))
+ return NO;
+ if(!IS_EQUAL([self role], [_other role], isEqualToString:))
+ return NO;
+// if(!IS_EQUAL([self xuid], [_other xuid], isEqualToString:))
+// return NO;
+ return YES;
+}
+
+- (BOOL)hasSameEmailAddress:(iCalPerson *)_other {
+ return IS_EQUAL([[self email] lowercaseString],
+ [[_other email] lowercaseString],
+ isEqualToString:);
+}
+
+@end /* iCalPerson */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGiCal_iCalRecurrenceCalculator_H_
+#define __NGiCal_iCalRecurrenceCalculator_H_
+
+#import <Foundation/NSObject.h>
+
+/*
+ iCalRecurrenceCalculator
+
+ Provides an API for performing common calculations performed in conjunction
+ with iCalRecurrenceRule objects.
+
+ TODO: rather move this functionality to iCalRecurrenceRule?
+*/
+
+@class NSArray;
+@class iCalRecurrenceRule, NGCalendarDateRange;
+
+@interface iCalRecurrenceCalculator : NSObject
+{
+ NGCalendarDateRange *firstRange;
+ iCalRecurrenceRule *rrule;
+}
+
++ (NSArray *)
+ recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
+ firstInstanceCalendarDateRange: (NGCalendarDateRange *) _fir
+ recurrenceRules: (NSArray *) _rRules
+ exceptionRules: (NSArray *) _exRules
+ exceptionDates: (NSArray *) _exDates;
+
++ (id) recurrenceCalculatorForRecurrenceRule: (iCalRecurrenceRule *) _rrule
+ withFirstInstanceCalendarDateRange: (NGCalendarDateRange *) _range;
+
+- (id) initWithRecurrenceRule: (iCalRecurrenceRule *) _rrule
+ firstInstanceCalendarDateRange: (NGCalendarDateRange *) _range;
+
+- (NSArray *)
+ recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *)_r;
+- (BOOL) doesRecurrWithinCalendarDateRange: (NGCalendarDateRange *) _range;
+
+- (NGCalendarDateRange *) firstInstanceCalendarDateRange;
+- (NGCalendarDateRange *) lastInstanceCalendarDateRange; /* might be nil */
+
+@end
+
+#endif /* __NGiCal_iCalRecurrenceCalculator_H_ */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalRecurrenceCalculator.h"
+#include <NGExtensions/NGCalendarDateRange.h>
+#include "iCalRecurrenceRule.h"
+#include "NSCalendarDate+ICal.h"
+#include "common.h"
+
+/* class cluster */
+
+
+/* Private */
+
+@interface iCalRecurrenceCalculator (PrivateAPI)
+- (NSCalendarDate *)lastInstanceStartDate;
+
+- (unsigned)offsetFromSundayForJulianNumber:(long)_jn;
+- (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay;
+- (unsigned)offsetFromSundayForCurrentWeekStart;
+
+- (iCalWeekDay)weekDayForJulianNumber:(long)_jn;
+@end
+
+@implementation iCalRecurrenceCalculator
+
+static Class NSCalendarDateClass = Nil;
+static Class iCalRecurrenceRuleClass = Nil;
+static Class dailyCalcClass = Nil;
+static Class weeklyCalcClass = Nil;
+static Class monthlyCalcClass = Nil;
+static Class yearlyCalcClass = Nil;
+
++ (void)initialize {
+ static BOOL didInit = NO;
+
+ if (didInit) return;
+ didInit = YES;
+
+ NSCalendarDateClass = [NSCalendarDate class];
+ iCalRecurrenceRuleClass = [iCalRecurrenceRule class];
+
+ dailyCalcClass = NSClassFromString(@"iCalDailyRecurrenceCalculator");
+ weeklyCalcClass = NSClassFromString(@"iCalWeeklyRecurrenceCalculator");
+ monthlyCalcClass = NSClassFromString(@"iCalMonthlyRecurrenceCalculator");
+ yearlyCalcClass = NSClassFromString(@"iCalYearlyRecurrenceCalculator");
+}
+
+/* factory */
+
++ (id)recurrenceCalculatorForRecurrenceRule:(iCalRecurrenceRule *)_rrule
+ withFirstInstanceCalendarDateRange:(NGCalendarDateRange *)_range
+{
+ return [[[self alloc] initWithRecurrenceRule:_rrule
+ firstInstanceCalendarDateRange:_range] autorelease];
+}
+
+/* complex calculation convenience */
+
++ (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r
+ firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir
+ recurrenceRules:(NSArray *)_rRules
+ exceptionRules:(NSArray *)_exRules
+ exceptionDates:(NSArray *)_exDates
+{
+ id rule;
+ iCalRecurrenceCalculator *calc;
+ NSMutableArray *ranges;
+ NSMutableArray *exDates;
+ unsigned i, count, rCount;
+
+ ranges = [NSMutableArray arrayWithCapacity:64];
+
+ for (i = 0, count = [_rRules count]; i < count; i++) {
+ NSArray *rs;
+
+ rule = [_rRules objectAtIndex:i];
+ if (![rule isKindOfClass:iCalRecurrenceRuleClass])
+ rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:rule];
+
+ calc = [self recurrenceCalculatorForRecurrenceRule:rule
+ withFirstInstanceCalendarDateRange:_fir];
+ rs = [calc recurrenceRangesWithinCalendarDateRange:_r];
+ [ranges addObjectsFromArray:rs];
+ }
+
+ if ([ranges count] == 0)
+ return nil;
+
+ /* test if any exceptions do match */
+
+ for (i = 0, count = [_exRules count]; i < count; i++) {
+ NSArray *rs;
+
+ rule = [_exRules objectAtIndex:i];
+ if (![rule isKindOfClass:iCalRecurrenceRuleClass])
+ rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:rule];
+
+ calc = [self recurrenceCalculatorForRecurrenceRule:rule
+ withFirstInstanceCalendarDateRange:_fir];
+ rs = [calc recurrenceRangesWithinCalendarDateRange:_r];
+ [ranges removeObjectsInArray:rs];
+ }
+
+ if (![ranges isNotEmpty])
+ return nil;
+
+ /* exception dates */
+
+ if ((count = [_exDates count]) == 0)
+ return ranges;
+
+ /* sort out exDates not within range */
+
+ exDates = [NSMutableArray arrayWithCapacity:count];
+ for (i = 0; i < count; i++) {
+ id exDate;
+
+ exDate = [_exDates objectAtIndex:i];
+ if (![exDate isKindOfClass:NSCalendarDateClass])
+ exDate = [NSCalendarDate calendarDateWithICalRepresentation:exDate];
+
+ if ([_r containsDate:exDate])
+ [exDates addObject:exDate];
+ }
+
+ /* remove matching exDates from ranges */
+
+ if ((count = [exDates count]) == 0)
+ return ranges;
+
+ for (i = 0, rCount = [ranges count]; i < count; i++) {
+ NSCalendarDate *exDate;
+ NGCalendarDateRange *r;
+ unsigned k;
+
+ exDate = [exDates objectAtIndex:i];
+ for (k = 0; k < rCount; k++) {
+ unsigned rIdx;
+
+ rIdx = (rCount - k) - 1;
+ r = [ranges objectAtIndex:rIdx];
+ if ([r containsDate:exDate]) {
+ [ranges removeObjectAtIndex:rIdx];
+ rCount--;
+ break; /* this is safe because we know that ranges don't overlap */
+ }
+ }
+ }
+ return ranges;
+}
+
+
+/* init */
+
+- (id)initWithRecurrenceRule:(iCalRecurrenceRule *)_rrule
+ firstInstanceCalendarDateRange:(NGCalendarDateRange *)_range
+{
+ iCalRecurrenceFrequency freq;
+ Class calcClass = Nil;
+
+ freq = [_rrule frequency];
+ if (freq == iCalRecurrenceFrequenceDaily)
+ calcClass = dailyCalcClass;
+ else if (freq == iCalRecurrenceFrequenceWeekly)
+ calcClass = weeklyCalcClass;
+ else if (freq == iCalRecurrenceFrequenceMonthly)
+ calcClass = monthlyCalcClass;
+ else if (freq == iCalRecurrenceFrequenceYearly)
+ calcClass = yearlyCalcClass;
+ else {
+ [self errorWithFormat:@"unsupported rrule frequency: %@", _rrule];
+ calcClass = Nil;
+ [self release];
+ return nil;
+ }
+
+ [self autorelease]; // TODO: why autorelease?
+ if (calcClass == Nil)
+ return nil;
+
+ if ((self = [[calcClass alloc] init]) != nil) {
+ self->rrule = [_rrule retain];
+ self->firstRange = [_range retain];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self->firstRange release];
+ [self->rrule release];
+ [super dealloc];
+}
+
+/* helpers */
+
+- (unsigned)offsetFromSundayForJulianNumber:(long)_jn {
+ return (unsigned)((int)(_jn + 1.5)) % 7;
+}
+
+- (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay {
+ unsigned offset;
+
+ switch (_weekDay) {
+ case iCalWeekDaySunday: offset = 0; break;
+ case iCalWeekDayMonday: offset = 1; break;
+ case iCalWeekDayTuesday: offset = 2; break;
+ case iCalWeekDayWednesday: offset = 3; break;
+ case iCalWeekDayThursday: offset = 4; break;
+ case iCalWeekDayFriday: offset = 5; break;
+ case iCalWeekDaySaturday: offset = 6; break;
+ default: offset = 0; break;
+ }
+ return offset;
+}
+
+- (unsigned)offsetFromSundayForCurrentWeekStart {
+ return [self offsetFromSundayForWeekDay:[self->rrule weekStart]];
+}
+
+- (iCalWeekDay)weekDayForJulianNumber:(long)_jn {
+ unsigned day;
+ iCalWeekDay weekDay;
+
+ day = [self offsetFromSundayForJulianNumber:_jn];
+ switch (day) {
+ case 0: weekDay = iCalWeekDaySunday; break;
+ case 1: weekDay = iCalWeekDayMonday; break;
+ case 2: weekDay = iCalWeekDayTuesday; break;
+ case 3: weekDay = iCalWeekDayWednesday; break;
+ case 4: weekDay = iCalWeekDayThursday; break;
+ case 5: weekDay = iCalWeekDayFriday; break;
+ case 6: weekDay = iCalWeekDaySaturday; break;
+ default:
+ [self errorWithFormat:@"got unexpected weekday: %d", day];
+ weekDay = iCalWeekDaySunday;
+ break; /* keep compiler happy */
+ }
+ return weekDay;
+}
+
+/* calculation */
+
+- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{
+ return nil; /* subclass responsibility */
+}
+- (BOOL)doesRecurrWithinCalendarDateRange:(NGCalendarDateRange *)_range {
+ NSArray *ranges;
+
+ ranges = [self recurrenceRangesWithinCalendarDateRange:_range];
+ return (ranges == nil || [ranges count] == 0) ? NO : YES;
+}
+
+- (NGCalendarDateRange *)firstInstanceCalendarDateRange {
+ return self->firstRange;
+}
+
+- (NGCalendarDateRange *)lastInstanceCalendarDateRange {
+ NSCalendarDate *start, *end;
+
+ if ((start = [self lastInstanceStartDate]) == nil)
+ return nil;
+
+ end = [start addTimeInterval:[self->firstRange duration]];
+ return [NGCalendarDateRange calendarDateRangeWithStartDate:start
+ endDate:end];
+}
+
+- (NSCalendarDate *)lastInstanceStartDate {
+ NSCalendarDate *until;
+
+ /*
+ NOTE: this is horribly inaccurate and doesn't even consider the use
+ of repeatCount. It MUST be implemented by subclasses properly!
+ However, it does the trick for SOGo 1.0 - that's why it's left here.
+ */
+ if ((until = [self->rrule untilDate]) != nil)
+ return until;
+
+ return nil;
+}
+
+@end /* iCalRecurrenceCalculator */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGiCal_iCalRecurrenceRule_H_
+#define __NGiCal_iCalRecurrenceRule_H_
+
+#import "CardElement.h"
+
+/*
+ iCalRecurrenceRule
+
+ Encapsulates a (probably complex) recurrence rule by offering
+ a high level API.
+
+ NOTE: as of now, only a very limited subset of RFC2445 is implemented.
+ Please see the unit tests for what is covered.
+*/
+
+// TODO: we could use string constants?
+typedef enum {
+ iCalRecurrenceFrequenceSecondly = 1,
+ iCalRecurrenceFrequenceMinutely = 2,
+ iCalRecurrenceFrequenceHourly = 3,
+ iCalRecurrenceFrequenceDaily = 4,
+ iCalRecurrenceFrequenceWeekly = 5,
+ iCalRecurrenceFrequenceMonthly = 6,
+ iCalRecurrenceFrequenceYearly = 7,
+} iCalRecurrenceFrequency;
+
+typedef enum {
+ iCalWeekDayMonday = 1,
+ iCalWeekDayTuesday = 2,
+ iCalWeekDayWednesday = 4,
+ iCalWeekDayThursday = 8,
+ iCalWeekDayFriday = 16,
+ iCalWeekDaySaturday = 32,
+ iCalWeekDaySunday = 64,
+} iCalWeekDay;
+
+@class NSString, NSCalendarDate, NGCalendarDateRange, NSArray;
+
+@interface iCalRecurrenceRule : CardElement
+// {
+// iCalRecurrenceFrequency frequency;
+// int interval;
+// unsigned repeatCount;
+// NSCalendarDate *untilDate;
+// struct {
+// unsigned weekStart: 7;
+// unsigned mask: 7;
+// unsigned useOccurence:1;
+// unsigned reserved:1;
+// } byDay;
+// int byDayOccurence1;
+// NSArray *byMonthDay;
+
+// NSString *rrule;
+// }
+
++ (id) recurrenceRuleWithICalRepresentation: (NSString *) _iCalRep;
+- (id) initWithString: (NSString *) _str;
+
+/* accessors */
+
+- (void) setFrequency: (iCalRecurrenceFrequency) _frequency;
+- (iCalRecurrenceFrequency) frequency;
+
+- (void) setRepeatInterval: (int) _repeatInterval;
+- (int) repeatInterval;
+
+- (void) setWeekStart: (iCalWeekDay) _weekStart;
+- (iCalWeekDay) weekStart;
+
+- (void) setByDayMask: (unsigned int) _mask;
+- (unsigned int) byDayMask;
+- (int) byDayOccurence1;
+
+- (NSArray *) byMonthDay;
+
+/* count and untilDate are mutually exclusive */
+
+- (void) setRepeatCount: (int) _repeatCount;
+- (int) repeatCount;
+
+- (void) setUntilDate: (NSCalendarDate *) _untilDate;
+- (NSCalendarDate *) untilDate;
+
+- (BOOL) isInfinite;
+
+/* parse complete iCal RRULE */
+
+- (void) setRrule: (NSString *) _rrule; // TODO: weird name? (better: RRule?)
+
+// - (NSString *)iCalRepresentation;
+
+@end
+
+#endif /* __NGiCal_iCalRecurrenceRule_H_ */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import <Foundation/NSException.h>
+#import <NGExtensions/NSString+Ext.h>
+#import <NGExtensions/NSObject+Logs.h>
+
+#import <ctype.h>
+
+#import "NSCalendarDate+NGCards.h"
+#import "NSString+NGCards.h"
+
+#import "NSCalendarDate+ICal.h"
+
+#import "iCalRecurrenceRule.h"
+
+/*
+ freq = rrFreq;
+ until = rrUntil;
+ count = rrCount;
+ interval = rrInterval;
+ bysecond = rrBySecondList;
+ byminute = rrByMinuteList;
+ byhour = rrByHourList;
+ byday = rrByDayList;
+ bymonthday = rrByMonthDayList;
+ byyearday = rrByYearDayList;
+ byweekno = rrByWeekNumberList;
+ bymonth = rrByMonthList;
+ bysetpos = rrBySetPosList;
+ wkst = rrWeekStart;
+*/
+
+// TODO: private API in the header file?!
+@interface iCalRecurrenceRule (PrivateAPI)
+
+- (iCalWeekDay) weekDayFromICalRepresentation: (NSString *) _day;
+- (NSString *) iCalRepresentationForWeekDay: (iCalWeekDay) _waeekDay;
+- (NSString *) freq;
+- (NSString *) wkst;
+- (NSString *) byDayList;
+
+// - (void)_parseRuleString:(NSString *)_rrule;
+
+/* currently used by parser, should be removed (replace with an -init..) */
+- (void)setByday:(NSString *)_byDayList;
+
+@end
+
+@implementation iCalRecurrenceRule
+
++ (id) recurrenceRuleWithICalRepresentation: (NSString *) _iCalRep
+{
+ return [self simpleElementWithTag: @"rrule" value: _iCalRep];
+}
+
+- (id) init
+{
+ if ((self = [super init]) != nil)
+ {
+ [self setTag: @"rrule"];
+ }
+
+ return self;
+}
+
+- (id) initWithString: (NSString *) _str
+{
+ if ((self = [self init]))
+ {
+ [self setRrule: _str];
+ }
+
+ return self;
+}
+
+- (void) setRrule: (NSString *) _rrule
+{
+ NSEnumerator *newValues;
+ NSString *newValue;
+
+ newValues = [[_rrule componentsSeparatedByString: @";"] objectEnumerator];
+ newValue = [newValues nextObject];
+ while (newValue)
+ {
+ [self addValue: newValue];
+ newValue = [newValues nextObject];
+ }
+}
+
+- (iCalRecurrenceFrequency) valueForFrequency: (NSString *) value
+{
+ NSString *frequency;
+ iCalRecurrenceFrequency freq;
+
+ frequency = [value uppercaseString];
+ if ([frequency isEqualToString:@"WEEKLY"])
+ freq = iCalRecurrenceFrequenceWeekly;
+ else if ([frequency isEqualToString:@"MONTHLY"])
+ freq = iCalRecurrenceFrequenceMonthly;
+ else if ([frequency isEqualToString:@"DAILY"])
+ freq = iCalRecurrenceFrequenceDaily;
+ else if ([frequency isEqualToString:@"YEARLY"])
+ freq = iCalRecurrenceFrequenceYearly;
+ else if ([frequency isEqualToString:@"HOURLY"])
+ freq = iCalRecurrenceFrequenceHourly;
+ else if ([frequency isEqualToString:@"MINUTELY"])
+ freq = iCalRecurrenceFrequenceMinutely;
+ else if ([frequency isEqualToString:@"SECONDLY"])
+ freq = iCalRecurrenceFrequenceSecondly;
+ else
+ freq = NSNotFound;
+
+ return freq;
+}
+
+- (NSString *) frequencyForValue: (iCalRecurrenceFrequency) freq
+{
+ NSString *frequency;
+
+ switch (freq)
+ {
+ case iCalRecurrenceFrequenceWeekly:
+ frequency = @"WEEKLY";
+ break;
+ case iCalRecurrenceFrequenceMonthly:
+ frequency = @"MONTHLY";
+ break;
+ case iCalRecurrenceFrequenceDaily:
+ frequency = @"DAILY";
+ break;
+ case iCalRecurrenceFrequenceYearly:
+ frequency = @"YEARLY";
+ break;
+ case iCalRecurrenceFrequenceHourly:
+ frequency = @"HOURLY";
+ break;
+ case iCalRecurrenceFrequenceMinutely:
+ frequency = @"MINUTELY";
+ break;
+ case iCalRecurrenceFrequenceSecondly:
+ frequency = @"SECONDLY";
+ break;
+ default:
+ frequency = nil;
+ }
+
+ return frequency;
+}
+
+/* accessors */
+
+- (void) setFrequency: (iCalRecurrenceFrequency) _frequency
+{
+ [self setNamedValue: @"freq" to: [self frequencyForValue: _frequency]];
+}
+
+- (iCalRecurrenceFrequency) frequency
+{
+ return [self valueForFrequency: [self namedValue: @"freq"]];
+}
+
+- (void) setRepeatCount: (int) _repeatCount
+{
+ [self setNamedValue: @"count"
+ to: [NSString stringWithFormat: @"%d", _repeatCount]];
+}
+
+- (int) repeatCount
+{
+ return [[self namedValue: @"count"] intValue];
+}
+
+- (void) setUntilDate: (NSCalendarDate *) _untilDate
+{
+ [self setNamedValue: @"until"
+ to: [_untilDate iCalFormattedDateTimeString]];
+}
+
+- (NSCalendarDate *) untilDate
+{
+#warning handling of default timezone needs to be implemented
+ return [[self namedValue: @"until"] asCalendarDate];
+}
+
+- (void) setInterval: (NSString *) _interval
+{
+ [self setNamedValue: @"interval" to: _interval];
+}
+
+- (void) setCount: (NSString *) _count
+{
+ [self setNamedValue: @"count" to: _count];
+}
+
+- (void) setUntil: (NSString *) _until
+{
+ [self setNamedValue: @"until" to: _until];
+}
+
+- (void) setRepeatInterval: (int) _repeatInterval
+{
+ [self setNamedValue: @"interval"
+ to: [NSString stringWithFormat: @"%d", _repeatInterval]];
+}
+
+- (int) repeatInterval
+{
+ return [[self namedValue: @"interval"] intValue];
+}
+
+- (void) setWkst: (NSString *) _weekStart
+{
+ [self setNamedValue: @"wkst" to: _weekStart];
+}
+
+- (NSString *) wkst
+{
+ return [self namedValue: @"wkst"];
+}
+
+- (void) setWeekStart: (iCalWeekDay) _weekStart
+{
+ [self setWkst: [self iCalRepresentationForWeekDay: _weekStart]];
+}
+
+- (iCalWeekDay) weekStart
+{
+ return [self weekDayFromICalRepresentation: [self wkst]];
+}
+
+- (void) setByDayMask: (unsigned) _mask
+{
+ NSMutableArray *days;
+ unsigned int count;
+ unsigned char maskDays[] = { iCalWeekDayMonday, iCalWeekDayTuesday,
+ iCalWeekDayWednesday, iCalWeekDayThursday,
+ iCalWeekDayFriday, iCalWeekDaySaturday,
+ iCalWeekDaySunday };
+ days = [NSMutableArray arrayWithCapacity: 7];
+ if (_mask)
+ {
+ for (count = 0; count < 7; count++)
+ if (_mask & maskDays[count])
+ [days addObject:
+ [self iCalRepresentationForWeekDay: maskDays[count]]];
+ }
+
+ [self setNamedValue: @"byday" to: [days componentsJoinedByString: @","]];
+}
+
+- (unsigned int) byDayMask
+{
+ NSArray *days;
+ unsigned int mask, count, max;
+ NSString *day;
+
+ mask = 0;
+
+ days = [[self namedValue: @"byday"] componentsSeparatedByString: @","];
+ max = [days count];
+ for (count = 0; count < max; count++)
+ {
+ day = [days objectAtIndex: count];
+ day = [day substringFromIndex: [day length] - 2];
+ mask |= [self weekDayFromICalRepresentation: day];
+ }
+
+ return mask;
+}
+
+#warning this is fucked up
+- (int) byDayOccurence1
+{
+ return 0;
+// return byDayOccurence1;
+}
+
+- (NSArray *) byMonthDay
+{
+ return [[self namedValue: @"bymonthday"] componentsSeparatedByString: @","];
+}
+
+- (BOOL) isInfinite
+{
+ return !([self repeatCount] || [self untilDate]);
+}
+
+/* private */
+
+- (iCalWeekDay) weekDayFromICalRepresentation: (NSString *) _day
+{
+ if ([_day length] > 1) {
+ /* be tolerant */
+ unichar c0, c1;
+
+ c0 = [_day characterAtIndex:0];
+ if (c0 == 'm' || c0 == 'M') return iCalWeekDayMonday;
+ if (c0 == 'w' || c0 == 'W') return iCalWeekDayWednesday;
+ if (c0 == 'f' || c0 == 'F') return iCalWeekDayFriday;
+
+ c1 = [_day characterAtIndex:1];
+ if (c0 == 't' || c0 == 'T') {
+ if (c1 == 'u' || c1 == 'U') return iCalWeekDayTuesday;
+ if (c1 == 'h' || c1 == 'H') return iCalWeekDayThursday;
+ }
+ if (c0 == 's' || c0 == 'S') {
+ if (c1 == 'a' || c1 == 'A') return iCalWeekDaySaturday;
+ if (c1 == 'u' || c1 == 'U') return iCalWeekDaySunday;
+ }
+ }
+
+ // TODO: do not raise but rather return an error value?
+ [NSException raise:NSGenericException
+ format:@"Incorrect weekDay '%@' specified!", _day];
+ return iCalWeekDayMonday; /* keep compiler happy */
+}
+
+- (NSString *) iCalRepresentationForWeekDay: (iCalWeekDay) _weekDay
+{
+ switch (_weekDay)
+ {
+ case iCalWeekDayMonday: return @"MO";
+ case iCalWeekDayTuesday: return @"TU";
+ case iCalWeekDayWednesday: return @"WE";
+ case iCalWeekDayThursday: return @"TH";
+ case iCalWeekDayFriday: return @"FR";
+ case iCalWeekDaySaturday: return @"SA";
+ case iCalWeekDaySunday: return @"SU";
+ default: return @"MO"; // TODO: return error?
+ }
+}
+
+// - (iCalWeekDay) weekDayForiCalRepre: (NSString *) _weekDay
+// {
+// iCalWeekDay day;
+// NSString *weekDay;
+
+// weekDay = [_weekDay uppercaseString];
+// if ([weekDay isEqualToString: @"TU"])
+// day = iCalWeekDayTuesday;
+// else if ([weekDay isEqualToString: @"WE"])
+// day = iCalWeekDayWednesday;
+// else if ([weekDay isEqualToString: @"TH"])
+// day = iCalWeekDayThursday;
+// else if ([weekDay isEqualToString: @"FR"])
+// day = iCalWeekDayFriday;
+// else if ([weekDay isEqualToString: @"SA"])
+// day = iCalWeekDaySaturday;
+// else if ([weekDay isEqualToString: @"SU"])
+// day = iCalWeekDaySunday;
+// else
+// day = iCalWeekDayMonday;
+
+// return day;
+// }
+
+// - (NSString *) wkst
+// {
+// return [self iCalRepresentationForWeekDay:byDay.weekStart];
+// }
+
+/*
+ TODO:
+ Each BYDAY value can also be preceded by a positive (+n) or negative
+ (-n) integer. If present, this indicates the nth occurrence of the
+ specific day within the MONTHLY or YEARLY RRULE. For example, within
+ a MONTHLY rule, +1MO (or simply 1MO) represents the first Monday
+ within the month, whereas -1MO represents the last Monday of the
+ month. If an integer modifier is not present, it means all days of
+ this type within the specified frequency. For example, within a
+ MONTHLY rule, MO represents all Mondays within the month.
+*/
+// - (NSString *) byDayList
+// {
+// NSMutableString *s;
+// unsigned dow, mask, day;
+// BOOL needsComma;
+
+// s = [NSMutableString stringWithCapacity:20];
+// needsComma = NO;
+// mask = byDay.mask;
+// day = iCalWeekDayMonday;
+
+// for (dow = 0 /* Sun */; dow < 7; dow++) {
+// if (mask & day) {
+// if (needsComma)
+// [s appendString:@","];
+
+// if (byDay.useOccurence)
+// // Note: we only support one occurrence for all currently
+// [s appendFormat:@"%i", byDayOccurence1];
+
+// [s appendString:[self iCalRepresentationForWeekDay:day]];
+// needsComma = YES;
+// }
+// day = (day << 1);
+// }
+
+// return s;
+// }
+
+/* parsing rrule */
+
+// - (void) _parseRuleString: (NSString *) _rrule
+// {
+// // TODO: to be exact we would need a timezone to properly process the 'until'
+// // date
+// unsigned i, count;
+// NSString *pFrequency = nil;
+// NSString *pUntil = nil;
+// NSString *pCount = nil;
+// NSString *pByday = nil;
+// NSString *pBymday = nil;
+// NSString *pBysetpos = nil;
+// NSString *pInterval = nil;
+
+// for (i = 0, count = [values count]; i < count; i++) {
+// NSString *prop, *key, *value;
+// NSRange r;
+// NSString **vHolder = NULL;
+
+// prop = [values objectAtIndex:i];
+// r = [prop rangeOfString:@"="];
+// if (r.length > 0) {
+// key = [prop substringToIndex:r.location];
+// value = [prop substringFromIndex:NSMaxRange(r)];
+// }
+// else {
+// key = prop;
+// value = nil;
+// }
+
+// key = [[key stringByTrimmingSpaces] lowercaseString];
+// if (![key isNotEmpty]) {
+// [self errorWithFormat:@"empty component in rrule: %@", _rrule];
+// continue;
+// }
+
+// vHolder = NULL;
+// switch ([key characterAtIndex:0]) {
+// case 'b':
+// if ([key isEqualToString:@"byday"]) { vHolder = &pByday; break; }
+// if ([key isEqualToString:@"bymonthday"]) { vHolder = &pBymday; break; }
+// if ([key isEqualToString:@"bysetpos"]) { vHolder = &pBysetpos; break; }
+// break;
+// case 'c':
+// if ([key isEqualToString:@"count"]) { vHolder = &pCount; break; }
+// break;
+// case 'f':
+// if ([key isEqualToString:@"freq"]) { vHolder = &pFrequency; break; }
+// break;
+// case 'i':
+// if ([key isEqualToString:@"interval"]) { vHolder = &pInterval; break; }
+// break;
+// case 'u':
+// if ([key isEqualToString:@"until"]) { vHolder = &pUntil; break; }
+// break;
+// default:
+// break;
+// }
+
+// if (vHolder != NULL) {
+// if ([*vHolder isNotEmpty])
+// [self errorWithFormat:@"more than one '%@' in: %@", key, _rrule];
+// else
+// *vHolder = [value copy];
+// }
+// else {
+// // TODO: we should just parse known keys and put remainders into a
+// // separate dictionary
+// [self logWithFormat:@"TODO: add explicit support for key: %@", key];
+// [self takeValue:value forKey:key];
+// }
+// }
+
+// /* parse and fill individual values */
+// // TODO: this method should be a class method and create a new rrule object
+
+// if ([pFrequency isNotEmpty])
+// [self setNamedValue: @"FREQ" to: pFrequency];
+// else
+// [self errorWithFormat:@"rrule contains no frequency: '%@'", _rrule];
+// [pFrequency release]; pFrequency = nil;
+
+// if (pInterval != nil)
+// interval = [pInterval intValue];
+// [pInterval release]; pInterval = nil;
+
+// // TODO: we should parse byday in here
+// if (pByday != nil) [self setByday:pByday];
+// [pByday release]; pByday = nil;
+
+// if (pBymday != nil) {
+// NSArray *t;
+
+// t = [pBymday componentsSeparatedByString:@","];
+// ASSIGNCOPY(byMonthDay, t);
+// }
+// [pBymday release]; pBymday = nil;
+
+// if (pBysetpos != nil)
+// // TODO: implement
+// [self errorWithFormat:@"rrule contains bysetpos, unsupported: %@", _rrule];
+// [pBysetpos release]; pBysetpos = nil;
+
+// if (pUntil != nil) {
+// NSCalendarDate *pUntilDate;
+
+// if (pCount != nil) {
+// [self errorWithFormat:@"rrule contains 'count' AND 'until': %@", _rrule];
+// [pCount release];
+// pCount = nil;
+// }
+
+// /*
+// The spec says:
+// "If specified as a date-time value, then it MUST be specified in an
+// UTC time format."
+// TODO: we still need some object representing a 'timeless' date.
+// */
+// if (![pUntil hasSuffix:@"Z"] && [pUntil length] > 8) {
+// [self warnWithFormat:@"'until' date has no explicit UTC marker: '%@'",
+// _rrule];
+// }
+
+// pUntilDate = [NSCalendarDate calendarDateWithICalRepresentation:pUntil];
+// if (pUntilDate != nil)
+// [self setUntilDate:pUntilDate];
+// else {
+// [self errorWithFormat:@"could not parse 'until' in rrule: %@",
+// _rrule];
+// }
+// }
+// [pUntil release]; pUntil = nil;
+
+// if (pCount != nil)
+// [self setRepeatCount:[pCount intValue]];
+// [pCount release]; pCount = nil;
+// }
+
+/* properties */
+
+// - (void) setByday: (NSString *) _byDayList
+// {
+// // TODO: each day can have an associated occurence, eg:
+// // +1MO,+2TU,-9WE
+// // TODO: this should be moved to the parser
+// NSArray *days;
+// unsigned i, count;
+// NSString *iCalDay;
+// iCalWeekDay day;
+// unsigned len;
+// unichar c0;
+// int occurence;
+// int offset;
+
+// /* reset mask */
+// byDay.mask = 0;
+// byDay.useOccurence = 0;
+// byDayOccurence1 = 0;
+
+// days = [_byDayList componentsSeparatedByString:@","];
+// for (i = 0, count = [days count]; i < count; i++)
+// {
+// iCalDay = [days objectAtIndex:i]; // eg: MO or TU
+// if ((len = [iCalDay length]) == 0)
+// {
+// [self errorWithFormat:@"found an empty day in byday list: '%@'",
+// _byDayList];
+// continue;
+// }
+
+// c0 = [iCalDay characterAtIndex:0];
+// if (((c0 == '+' || c0 == '-') && len > 2) || (isdigit(c0) && len > 1)) {
+// occurence = [iCalDay intValue];
+
+// offset = 1; /* skip occurence */
+// while (offset < len && isdigit([iCalDay characterAtIndex:offset]))
+// offset++;
+
+// iCalDay = [iCalDay substringFromIndex:offset];
+
+// if (byDay.useOccurence && (occurence != byDayOccurence1))
+// {
+// [self errorWithFormat:
+// @"we only supported one occurence (occ=%i,day=%@): '%@'",
+// occurence, iCalDay, _byDayList];
+// continue;
+// }
+
+// byDay.useOccurence = 1;
+// byDayOccurence1 = occurence;
+// }
+// else if (byDay.useOccurence)
+// [self errorWithFormat:
+// @"a byday occurence was specified on one day, but not on others"
+// @" (unsupported): '%@'", _byDayList];
+
+// day = [self weekDayFromICalRepresentation:iCalDay];
+// byDay.mask |= day;
+// }
+// }
+
+/* key/value coding */
+
+- (void) handleTakeValue: (id) _value
+ forUnboundKey: (NSString *)_key
+{
+ [self warnWithFormat:@"Cannot handle unbound key: '%@'", _key];
+}
+
+@end /* iCalRecurrenceRule */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGCards_iCalRepeatableEntityObject_H_
+#define __NGCards_iCalRepeatableEntityObject_H_
+
+#import "iCalEntityObject.h"
+
+/*
+ iCalRepeatableEntityObject
+
+ Specifies an iCal entity object which can bear a (possibly complex) set
+ of recurrence rules and exceptions thereof. According to RFC 2445 these
+ are VEVENT, VTODO and VJOURNAL.
+*/
+
+@class NSMutableArray, NGCalendarDateRange;
+
+@interface iCalRepeatableEntityObject : iCalEntityObject
+// {
+// NSMutableArray *rRules;
+// NSMutableArray *exRules;
+// NSMutableArray *exDates;
+// }
+
+- (void)removeAllRecurrenceRules;
+- (void)addToRecurrenceRules:(id)_rrule;
+- (BOOL)hasRecurrenceRules;
+- (NSArray *)recurrenceRules;
+
+- (void)removeAllExceptionRules;
+- (void)addToExceptionRules:(id)_rrule;
+- (BOOL)hasExceptionRules;
+- (NSArray *)exceptionRules;
+
+- (void)removeAllExceptionDates;
+- (void)addToExceptionDates:(id)_date;
+- (BOOL)hasExceptionDates;
+- (NSArray *)exceptionDates;
+
+- (BOOL)isRecurrent;
+- (BOOL)isWithinCalendarDateRange:(NGCalendarDateRange *)_range
+ firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir;
+- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r
+ firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir;
+
+/* this is the outmost bound possible, not necessarily the real last date */
+- (NSCalendarDate *)lastPossibleRecurrenceStartDateUsingFirstInstanceCalendarDateRange:(NGCalendarDateRange *)_r;
+
+@end
+
+#endif /* __NGCards_iCalRepeatableEntityObject_H_ */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalRepeatableEntityObject.h"
+#include <NGExtensions/NGCalendarDateRange.h>
+#include "iCalRecurrenceRule.h"
+#include "iCalRecurrenceCalculator.h"
+#include "common.h"
+
+@implementation iCalRepeatableEntityObject
+
+- (Class) classForTag: (NSString *) classTag
+{
+ Class tagClass;
+
+ if ([classTag isEqualToString: @"RRULE"])
+ tagClass = [iCalRecurrenceRule class];
+ else
+ tagClass = [super classForTag: classTag];
+
+ return tagClass;
+}
+
+/* Accessors */
+
+- (void) removeAllRecurrenceRules
+{
+ [children removeObjectsInArray: [self childrenWithTag: @"rrule"]];
+}
+
+- (void) addToRecurrenceRules: (id) _rrule
+{
+ [self addChild: _rrule];
+}
+
+- (void) setRecurrenceRules: (NSArray *) _rrules
+{
+ [children removeObjectsInArray: [self childrenWithTag: @"rrule"]];
+ [self addChildren: _rrules];
+}
+
+- (BOOL) hasRecurrenceRules
+{
+ return ([[self childrenWithTag: @"rrule"] count] > 0);
+}
+
+- (NSArray *) recurrenceRules
+{
+ return [self childrenWithTag: @"rrule"];
+}
+
+- (void) removeAllExceptionRules
+{
+ [children removeObjectsInArray: [self childrenWithTag: @"exrule"]];
+}
+
+- (void) addToExceptionRules: (id) _rrule
+{
+ [self addChild: _rrule];
+}
+
+- (void) setExceptionRules: (NSArray *) _rrules
+{
+ [children removeObjectsInArray: [self childrenWithTag: @"exrule"]];
+ [self addChildren: _rrules];
+}
+
+- (BOOL) hasExceptionRules
+{
+ return ([[self childrenWithTag: @"exrule"] count] > 0);
+}
+
+- (NSArray *) exceptionRules
+{
+ return [self childrenWithTag: @"exrule"];
+}
+
+- (void) removeAllExceptionDates
+{
+ [children removeObjectsInArray: [self childrenWithTag: @"exdate"]];
+}
+
+- (void) addToExceptionDates: (id) _rdate
+{
+ [self addChild: _rdate];
+}
+
+- (void) setExceptionDates: (NSArray *) _rdates
+{
+ [children removeObjectsInArray: [self childrenWithTag: @"exdate"]];
+ [self addChildren: _rdates];
+}
+
+- (BOOL) hasExceptionDates
+{
+ return ([[self childrenWithTag: @"exdate"] count] > 0);
+}
+
+- (NSArray *) exceptionDates
+{
+ return [self childrenWithTag: @"exdate"];
+}
+
+/* Convenience */
+
+- (BOOL) isRecurrent
+{
+ return [self hasRecurrenceRules];
+}
+
+/* Matching */
+
+- (BOOL) isWithinCalendarDateRange: (NGCalendarDateRange *) _range
+ firstInstanceCalendarDateRange: (NGCalendarDateRange *) _fir
+{
+ NSArray *ranges;
+
+ ranges = [self recurrenceRangesWithinCalendarDateRange:_range
+ firstInstanceCalendarDateRange:_fir];
+ return [ranges count] > 0;
+}
+
+- (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *)_r
+ firstInstanceCalendarDateRange: (NGCalendarDateRange *)_fir
+{
+ return [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: _r
+ firstInstanceCalendarDateRange: _fir
+ recurrenceRules: [self recurrenceRules]
+ exceptionRules: [self exceptionRules]
+ exceptionDates: [self exceptionDates]];
+}
+
+
+/* this is the outmost bound possible, not necessarily the real last date */
+- (NSCalendarDate *)
+lastPossibleRecurrenceStartDateUsingFirstInstanceCalendarDateRange: (NGCalendarDateRange *)_r
+{
+ NSCalendarDate *date;
+ NSEnumerator *rRules;
+ iCalRecurrenceRule *rule;
+ iCalRecurrenceCalculator *calc;
+ NSCalendarDate *rdate;
+
+ date = nil;
+
+ rRules = [[self recurrenceRules] objectEnumerator];
+ rule = [rRules nextObject];
+ while (rule && ![rule isInfinite] & !date)
+ {
+ calc = [iCalRecurrenceCalculator
+ recurrenceCalculatorForRecurrenceRule: rule
+ withFirstInstanceCalendarDateRange: _r];
+ rdate = [[calc lastInstanceCalendarDateRange] startDate];
+ if (!date
+ || ([date compare: rdate] == NSOrderedAscending))
+ date = rdate;
+ else
+ rule = [rRules nextObject];
+ }
+
+ return date;
+}
+
+@end
--- /dev/null
+/* iCalTimeZone.h - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ICALTIMEZONE_H
+#define ICALTIMEZONE_H
+
+@class NSString;
+@class NSCalendarDate;
+
+#import "CardGroup.h"
+
+@interface iCalTimeZone : CardGroup
+
+- (NSString *) tzId;
+- (NSString *) dateTimeStringForDate: (NSCalendarDate *) date;
+- (NSCalendarDate *) dateForDateTimeString: (NSString *) string;
+
+@end
+
+#endif /* ICALTIMEZONE_H */
--- /dev/null
+/* iCalTimeZone.m - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSString.h>
+#import <Foundation/NSCalendarDate.h>
+
+#import "NSCalendarDate+NGCards.h"
+#import "NSString+NGCards.h"
+#import "iCalTimeZonePeriod.h"
+
+#import "iCalTimeZone.h"
+
+@implementation iCalTimeZone
+
+- (Class) classForTag: (NSString *) classTag
+{
+ Class tagClass;
+
+ if ([classTag isEqualToString: @"STANDARD"]
+ || [classTag isEqualToString: @"DAYLIGHT"])
+ tagClass = [iCalTimeZonePeriod class];
+ else if ([classTag isEqualToString: @"TZID"])
+ tagClass = [CardElement class];
+ else
+ tagClass = [super classForTag: classTag];
+
+ return tagClass;
+}
+
+- (void) setTzId: (NSString *) tzId
+{
+ [[self uniqueChildWithTag: @"tzid"] setValue: 0 to: tzId];
+}
+
+- (NSString *) tzId
+{
+ return [[self uniqueChildWithTag: @"tzid"] value: 0];
+}
+
+- (NSCalendarDate *) _occurenceForPeriodNamed: (NSString *) pName
+ forDate: (NSCalendarDate *) aDate
+{
+ NSArray *periods;
+ iCalTimeZonePeriod *period;
+ NSCalendarDate *occurence;
+
+ periods = [self childrenWithTag: pName];
+ if ([periods count])
+ {
+ period = (iCalTimeZonePeriod *) [periods objectAtIndex: 0];
+ occurence = [period occurenceForDate: aDate];
+ }
+ else
+ occurence = nil;
+
+ return occurence;
+}
+
+- (iCalTimeZonePeriod *) periodForDate: (NSCalendarDate *) date
+{
+ NSCalendarDate *daylightOccurence, *standardOccurence;
+ iCalTimeZonePeriod *period;
+
+ /* FIXME, this could cause crashes when timezones are not properly
+ specified, but let's say it won't happen often... */
+
+ daylightOccurence = [self _occurenceForPeriodNamed: @"daylight"
+ forDate: date];
+ standardOccurence = [self _occurenceForPeriodNamed: @"standard"
+ forDate: date];
+ if ([date earlierDate: daylightOccurence] == date
+ || [date earlierDate: standardOccurence] == standardOccurence)
+ period = (iCalTimeZonePeriod *) [self uniqueChildWithTag: @"standard"];
+ else
+ period = (iCalTimeZonePeriod *) [self uniqueChildWithTag: @"daylight"];
+
+ NSLog (@"chosen period: '%@'", [period tag]);
+
+ return period;
+}
+
+- (NSString *) dateTimeStringForDate: (NSCalendarDate *) date
+{
+ NSCalendarDate *tmpDate;
+ NSTimeZone *utc;
+
+ utc = [NSTimeZone timeZoneWithName: @"GMT"];
+ tmpDate = [date copy];
+ [tmpDate autorelease];
+ [tmpDate setTimeZone: utc];
+ tmpDate
+ = [tmpDate addYear: 0 month: 0 day: 0
+ hour: 0 minute: 0
+ second: [[self periodForDate: date] secondsOffsetFromGMT]];
+
+ return [tmpDate iCalFormattedDateTimeString];
+}
+
+- (NSCalendarDate *) dateForDateTimeString: (NSString *) string
+{
+ NSCalendarDate *tmpDate;
+ iCalTimeZonePeriod *period;
+
+ tmpDate = [string asCalendarDate];
+ period = [self periodForDate: tmpDate];
+
+ return [tmpDate addYear: 0 month: 0 day: 0
+ hour: 0 minute: 0
+ second: -[period secondsOffsetFromGMT]];
+}
+
+@end
--- /dev/null
+/* iCalTimeZonePeriod.h - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ICALTIMEZONEPERIOD_H
+#define ICALTIMEZONEPERIOD_H
+
+#import "CardGroup.h"
+
+@interface iCalTimeZonePeriod : CardGroup
+
+- (NSCalendarDate *) occurenceForDate: (NSCalendarDate *) refDate;
+- (int) secondsOffsetFromGMT;
+
+@end
+
+#endif /* ICALTIMEZONEPERIOD_H */
--- /dev/null
+/* iCalTimeZonePeriod.m - this file is part of SOPE
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/NSCalendarDate.h>
+#import <Foundation/NSString.h>
+
+#import "iCalDateTime.h"
+#import "iCalRecurrenceRule.h"
+#import "CardGroup+iCal.h"
+
+#import "iCalTimeZonePeriod.h"
+
+@implementation iCalTimeZonePeriod
+
+- (Class) classForTag: (NSString *) classTag
+{
+ Class tagClass;
+
+ if ([classTag isEqualToString: @"RRULE"])
+ tagClass = [iCalRecurrenceRule class];
+ else if ([classTag isEqualToString: @"DTSTART"])
+ tagClass = [iCalDateTime class];
+ else if ([classTag isEqualToString: @"TZNAME"]
+ || [classTag isEqualToString: @"TZOFFSETFROM"]
+ || [classTag isEqualToString: @"TZOFFSETTO"])
+ tagClass = [CardElement class];
+ else
+ tagClass = [super classForTag: classTag];
+
+ return tagClass;
+}
+
+- (int) _secondsOfOffset: (NSString *) offsetName
+{
+ NSString *offsetTo;
+ BOOL negative;
+ NSRange cursor;
+ unsigned int length;
+ unsigned int seconds;
+
+ seconds = 0;
+
+ offsetTo = [[self uniqueChildWithTag: offsetName]
+ value: 0];
+ length = [offsetTo length];
+ negative = [offsetTo hasPrefix: @"-"];
+ if (negative)
+ {
+ length--;
+ cursor = NSMakeRange(1, 2);
+ }
+ else if ([offsetTo hasPrefix: @"+"])
+ {
+ length--;
+ cursor = NSMakeRange(1, 2);
+ }
+ else
+ cursor = NSMakeRange(0, 2);
+
+ seconds = 3600 * [[offsetTo substringWithRange: cursor] intValue];
+ cursor.location += 2;
+ seconds += 60 * [[offsetTo substringWithRange: cursor] intValue];
+ if (length == 6)
+ {
+ cursor.location += 2;
+ seconds += [[offsetTo substringWithRange: cursor] intValue];
+ }
+
+ return ((negative) ? -seconds : seconds);
+}
+
+- (unsigned int) dayOfWeekFromRruleDay: (iCalWeekDay) day
+{
+ unsigned int dayOfWeek;
+
+ dayOfWeek = 1;
+ while (day >> dayOfWeek)
+ dayOfWeek++;
+
+ return dayOfWeek;
+}
+
+- (NSCalendarDate *) occurenceForDate: (NSCalendarDate *) refDate;
+{
+ NSCalendarDate *tmpDate;
+ iCalRecurrenceRule *rrule;
+ NSString *byDay;
+ int dayOfWeek, dateDayOfWeek, offset, pos;
+
+ rrule = (iCalRecurrenceRule *) [self uniqueChildWithTag: @"rrule"];
+ byDay = [rrule namedValue: @"byday"];
+ dayOfWeek = [self dayOfWeekFromRruleDay: [rrule byDayMask]];
+ pos = [[byDay substringToIndex: 2] intValue];
+ if (!pos)
+ pos = 1;
+
+ tmpDate = [NSCalendarDate
+ dateWithYear: [refDate yearOfCommonEra]
+ month: [[rrule namedValue: @"bymonth"] intValue]
+ day: 1 hour: 0 minute: 0 second: 0
+ timeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
+ tmpDate = [tmpDate addYear: 0 month: ((pos > 0) ? 0 : 1)
+ day: 0 hour: 0 minute: 0
+ second: -[self _secondsOfOffset: @"tzoffsetfrom"]];
+ dateDayOfWeek = [tmpDate dayOfWeek];
+ offset = (dayOfWeek - dateDayOfWeek);
+ if (pos > 0 && offset < 0)
+ offset += 7;
+ offset += (pos * 7);
+ tmpDate = [tmpDate addYear: 0 month: 0 day: offset
+ hour: 0 minute: 0 second: 0];
+
+ return tmpDate;
+}
+
+- (int) secondsOffsetFromGMT
+{
+ return [self _secondsOfOffset: @"tzoffsetto"];
+}
+
+@end
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGCards_iCalToDo_H__
+#define __NGCards_iCalToDo_H__
+
+#import "iCalRepeatableEntityObject.h"
+
+/*
+ iCalToDo
+
+ This class keeps the attributes of an iCalendar todo record (a task).
+*/
+
+@class NSCalendarDate;
+@class NSString;
+
+@interface iCalToDo : iCalRepeatableEntityObject
+
+- (void) setPercentComplete: (NSString *) _value;
+- (NSString *) percentComplete;
+
+- (void) setDue: (NSCalendarDate *) _date;
+- (NSCalendarDate *) due;
+
+- (void) setCompleted: (NSCalendarDate *) _date;
+- (NSCalendarDate *) completed;
+
+@end
+
+#endif /* __NGCards_iCalToDo_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import <Foundation/NSString.h>
+
+#import "NSCalendarDate+NGCards.h"
+#import "CardGroup+iCal.h"
+
+#import "iCalDateTime.h"
+#import "iCalToDo.h"
+
+@implementation iCalToDo
+
+- (Class) classForTag: (NSString *) classTag
+{
+ Class tagClass;
+
+ if ([classTag isEqualToString: @"DUE"]
+ || [classTag isEqualToString: @"COMPLETED"])
+ tagClass = [iCalDateTime class];
+ else if ([classTag isEqualToString: @"PERCENT-COMPLETE"])
+ tagClass = [CardElement class];
+ else
+ tagClass = [super classForTag: classTag];
+
+ return tagClass;
+}
+
+/* accessors */
+
+- (void) setPercentComplete: (NSString *) _value
+{
+ [[self uniqueChildWithTag: @"percent-complete"] setValue: 0
+ to: _value];
+}
+
+- (NSString *) percentComplete
+{
+ return [[self uniqueChildWithTag: @"percent-complete"] value: 0];
+}
+
+- (void) setDue: (NSCalendarDate *) _date
+{
+ [self setDate: _date
+ forDateTimeValue: @"due"];
+}
+
+- (NSCalendarDate *) due
+{
+ return [self dateForDateTimeValue: @"due"];
+// return [[self uniqueChildWithTag: @"percent-complete"] asCalendarDate];
+}
+
+- (void) setCompleted: (NSCalendarDate *) _date
+{
+ [self setStatus: @"COMPLETED"];
+ [self setDate: _date forDateTimeValue: @"completed"];
+}
+
+- (NSCalendarDate *) completed
+{
+ return [self dateForDateTimeValue: @"completed"];
+}
+
+/* ical typing */
+
+- (NSString *) entityName
+{
+ return @"vtodo";
+}
+
+// /* descriptions */
+
+// - (NSString *)description {
+// NSMutableString *ms;
+
+// ms = [NSMutableString stringWithCapacity:128];
+// [ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
+
+// if (uid) [ms appendFormat:@" uid=%@", uid];
+// if (startDate) [ms appendFormat:@" start=%@", startDate];
+// if (due) [ms appendFormat:@" due=%@", due];
+// if (priority) [ms appendFormat:@" pri=%@", priority];
+
+// if (completed)
+// [ms appendFormat:@" completed=%@", completed];
+// if (percentComplete)
+// [ms appendFormat:@" complete=%@", percentComplete];
+// if (accessClass)
+// [ms appendFormat:@" class=%@", accessClass];
+
+// if (summary)
+// [ms appendFormat:@" summary=%@", summary];
+
+// [ms appendString:@">"];
+// return ms;
+// }
+
+@end /* iCalToDo */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGCards_iCalTrigger_H__
+#define __NGCards_iCalTrigger_H__
+
+#import "CardElement.h"
+
+@interface iCalTrigger : CardElement
+
+- (void) setValue: (NSString *) aValue;
+- (NSString *) value;
+
+- (void) setValueType: (NSString *) aType;
+- (NSString *) valueType;
+
+@end
+
+#endif /* __NGCards_iCalTrigger_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalTrigger.h"
+#include "common.h"
+
+@implementation iCalTrigger
+
+/* accessors */
+
+- (void) setValue: (NSString *) _value
+{
+ [self setValue: 0 to: _value];
+}
+
+- (NSString *) value
+{
+ return [self value: 0];
+}
+
+- (void) setValueType: (NSString *) _value
+{
+ [self setValue: 0 ofAttribute: @"type" to: _value];
+}
+
+- (NSString *) valueType
+{
+ return [self value: 0 ofAttribute: @"type"];
+}
+
+@end /* iCalTrigger */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalRecurrenceCalculator.h"
+
+@interface iCalWeeklyRecurrenceCalculator : iCalRecurrenceCalculator
+@end
+
+#include <NGExtensions/NGCalendarDateRange.h>
+#include "iCalRecurrenceRule.h"
+#include "NSCalendarDate+ICal.h"
+#include "common.h"
+
+@interface iCalRecurrenceCalculator (PrivateAPI)
+
+- (NSCalendarDate *)lastInstanceStartDate;
+
+- (unsigned)offsetFromSundayForJulianNumber:(long)_jn;
+- (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay;
+- (unsigned)offsetFromSundayForCurrentWeekStart;
+
+- (iCalWeekDay)weekDayForJulianNumber:(long)_jn;
+
+@end
+
+/*
+ TODO: If BYDAY is specified, lastInstanceStartDate and recurrences will
+ differ significantly!
+*/
+@implementation iCalWeeklyRecurrenceCalculator
+
+- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r {
+ NSMutableArray *ranges;
+ NSCalendarDate *firStart;
+ long i, jnFirst, jnStart, jnEnd, startEndCount;
+ unsigned interval, byDayMask;
+
+ firStart = [self->firstRange startDate];
+ jnFirst = [firStart julianNumber];
+ jnEnd = [[_r endDate] julianNumber];
+
+ if (jnFirst > jnEnd)
+ return nil;
+
+ jnStart = [[_r startDate] julianNumber];
+ interval = [self->rrule repeatInterval];
+
+ /* if rule is bound, check the bounds */
+ if (![self->rrule isInfinite]) {
+ NSCalendarDate *until;
+ long jnRuleLast;
+
+ until = [self->rrule untilDate];
+ if (until) {
+ if ([until compare:[_r startDate]] == NSOrderedAscending)
+ return nil;
+ jnRuleLast = [until julianNumber];
+ }
+ else {
+ jnRuleLast = (interval * [self->rrule repeatCount] * 7)
+ + jnFirst;
+ if (jnRuleLast < jnStart)
+ return nil;
+ }
+ /* jnStart < jnRuleLast < jnEnd ? */
+ if (jnEnd > jnRuleLast)
+ jnEnd = jnRuleLast;
+ }
+
+ startEndCount = (jnEnd - jnStart) + 1;
+ ranges = [NSMutableArray arrayWithCapacity:startEndCount];
+ byDayMask = [self->rrule byDayMask];
+ if (!byDayMask) {
+ for (i = 0 ; i < startEndCount; i++) {
+ long jnCurrent;
+
+ jnCurrent = jnStart + i;
+ if (jnCurrent >= jnFirst) {
+ long jnDiff;
+
+ jnDiff = jnCurrent - jnFirst; /* difference in days */
+ if ((jnDiff % (interval * 7)) == 0) {
+ NSCalendarDate *start, *end;
+ NGCalendarDateRange *r;
+
+ start = [NSCalendarDate dateForJulianNumber:jnCurrent];
+ [start setTimeZone:[firStart timeZone]];
+ start = [start hour: [firStart hourOfDay]
+ minute:[firStart minuteOfHour]
+ second:[firStart secondOfMinute]];
+ end = [start addTimeInterval:[self->firstRange duration]];
+ r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
+ endDate:end];
+ if ([_r containsDateRange:r])
+ [ranges addObject:r];
+ }
+ }
+ }
+ }
+ else {
+ long jnFirstWeekStart, weekStartOffset;
+
+ /* calculate jnFirst's week start - this depends on our setting of week
+ start */
+ weekStartOffset = [self offsetFromSundayForJulianNumber:jnFirst] -
+ [self offsetFromSundayForCurrentWeekStart];
+
+ jnFirstWeekStart = jnFirst - weekStartOffset;
+
+ for (i = 0 ; i < startEndCount; i++) {
+ long jnCurrent;
+
+ jnCurrent = jnStart + i;
+ if (jnCurrent >= jnFirst) {
+ long jnDiff;
+
+ /* we need to calculate a difference in weeks */
+ jnDiff = (jnCurrent - jnFirstWeekStart) % 7;
+ if ((jnDiff % interval) == 0) {
+ BOOL isRecurrence = NO;
+
+ if (jnCurrent == jnFirst) {
+ isRecurrence = YES;
+ }
+ else {
+ iCalWeekDay weekDay;
+
+ weekDay = [self weekDayForJulianNumber:jnCurrent];
+ isRecurrence = (weekDay & [self->rrule byDayMask]) ? YES : NO;
+ }
+ if (isRecurrence) {
+ NSCalendarDate *start, *end;
+ NGCalendarDateRange *r;
+
+ start = [NSCalendarDate dateForJulianNumber:jnCurrent];
+ [start setTimeZone:[firStart timeZone]];
+ start = [start hour: [firStart hourOfDay]
+ minute:[firStart minuteOfHour]
+ second:[firStart secondOfMinute]];
+ end = [start addTimeInterval:[self->firstRange duration]];
+ r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
+ endDate:end];
+ if ([_r containsDateRange:r])
+ [ranges addObject:r];
+ }
+ }
+ }
+ }
+ }
+ return ranges;
+}
+
+- (NSCalendarDate *)lastInstanceStartDate {
+ if ([self->rrule repeatCount] > 0) {
+ long jnFirst, jnRuleLast;
+ NSCalendarDate *firStart, *until;
+
+ firStart = [self->firstRange startDate];
+ jnFirst = [firStart julianNumber];
+ jnRuleLast = ([self->rrule repeatInterval] *
+ [self->rrule repeatCount] * 7) +
+ jnFirst;
+ until = [NSCalendarDate dateForJulianNumber:jnRuleLast];
+ until = [until hour: [firStart hourOfDay]
+ minute:[firStart minuteOfHour]
+ second:[firStart secondOfMinute]];
+ return until;
+ }
+ return [super lastInstanceStartDate];
+}
+
+@end /* iCalWeeklyRecurrenceCalculator */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "iCalRecurrenceCalculator.h"
+
+@interface iCalYearlyRecurrenceCalculator : iCalRecurrenceCalculator
+@end
+
+#include <NGExtensions/NGCalendarDateRange.h>
+#include "iCalRecurrenceRule.h"
+#include "NSCalendarDate+ICal.h"
+#include "common.h"
+
+@interface iCalRecurrenceCalculator(PrivateAPI)
+- (NSCalendarDate *)lastInstanceStartDate;
+@end
+
+@implementation iCalYearlyRecurrenceCalculator
+
+- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{
+ NSMutableArray *ranges;
+ NSCalendarDate *firStart, *rStart, *rEnd, *until;
+ unsigned i, count, interval;
+ int diff;
+
+ firStart = [self->firstRange startDate];
+ rStart = [_r startDate];
+ rEnd = [_r endDate];
+ interval = [self->rrule repeatInterval];
+ until = [self lastInstanceStartDate];
+
+ if (until) {
+ if ([until compare:rStart] == NSOrderedAscending)
+ return nil;
+ if ([until compare:rEnd] == NSOrderedDescending)
+ rEnd = until;
+ }
+
+ diff = [firStart yearsBetweenDate:rStart];
+ if ((diff != 0) && [rStart compare:firStart] == NSOrderedAscending)
+ diff = -diff;
+
+ count = [rStart yearsBetweenDate:rEnd] + 1;
+ ranges = [NSMutableArray arrayWithCapacity:count];
+ for (i = 0 ; i < count; i++) {
+ int test;
+
+ test = diff + i;
+ if ((test >= 0) && (test % interval) == 0) {
+ NSCalendarDate *start, *end;
+ NGCalendarDateRange *r;
+
+ start = [firStart dateByAddingYears:diff + i
+ months:0
+ days:0];
+ [start setTimeZone:[firStart timeZone]];
+ end = [start addTimeInterval:[self->firstRange duration]];
+ r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
+ endDate:end];
+ if ([_r containsDateRange:r])
+ [ranges addObject:r];
+ }
+ }
+ return ranges;
+}
+
+- (NSCalendarDate *)lastInstanceStartDate {
+ if ([self->rrule repeatCount] > 0) {
+ NSCalendarDate *until;
+ unsigned years, interval;
+
+ interval = [self->rrule repeatInterval];
+ years = [self->rrule repeatCount] * interval;
+ until = [[self->firstRange startDate] dateByAddingYears:years
+ months:0
+ days:0];
+ return until;
+ }
+ return [super lastInstanceStartDate];
+}
+
+@end /* iCalYearlyRecurrenceCalculator */
--- /dev/null
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+\f
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+2005-09-19 Helge Hess <helge.hess@opengroupware.org>
+
+ * ievalrrule.m: started tool to evaluate iCal rrules on the shell
+
+2005-08-16 Helge Hess <helge.hess@opengroupware.org>
+
+ * link tools against OSX frameworks if configured so
+
+2005-05-06 Helge Hess <helge.hess@opengroupware.org>
+
+ * renamed ical3.m to icalds.m, ical2.m to icalparsetest
+
+2005-04-25 Helge Hess <helge.hess@opengroupware.org>
+
+ * properly include config.make
+
+ * fixed some gcc 4.0 warnings
+
+2004-09-26 Helge Hess <helge.hess@opengroupware.org>
+
+ * GNUmakefile.preamble: fixed makefiles for SOPE inline compilation
+
+2004-08-29 Helge Hess <helge.hess@opengroupware.org>
+
+ * added hack to install the tools in FHS locations - the executables
+ will be installed in FHS_INSTALL_ROOT if specified (eg make
+ FHS_INSTALL_ROOT=/usr/local)
+
+2004-08-17 Helge Hess <helge.hess@opengroupware.org>
+
+ * subclassing.m: fixed a compiler warning
+
+2004-07-09 Helge Hess <helge.hess@skyrix.com>
+
+ * bmlookup.m: major code cleanups, improved output
+
+2004-06-27 Helge Hess <helge.hess@opengroupware.org>
+
+ * ldap2dsml.m: fixed a compile warning
+
+2004-06-21 Helge Hess <helge.hess@opengroupware.org>
+
+ * common.h: fixed compatibility with gstep-base
+
+2004-06-17 Helge Hess <helge.hess@opengroupware.org>
+
+ * added 'testurl' to test NSURL for the Cocoa Foundation bug wrt the
+ trailing suffix in -path
+
+2004-05-09 Helge Hess <helge.hess@opengroupware.org>
+
+ * subclassing.m: added support for Apple runtime
+
+2004-04-12 Helge Hess <helge.hess@opengroupware.org>
+
+ * ImapListTool, ImapTool.m, imapls.m: minor code cleanups
+
+2004-01-19 Helge Hess <helge.hess@opengroupware.org>
+
+ * ldapls.m: minor fixes (moved NSAutoreleasePool to correct place)
+
+2004-01-11 Helge Hess <helge.hess@opengroupware.org>
+
+ * minor cleanups to log messages
+
+2003-10-12 Helge Hess <helge@opengroupware.org>
+
+ * EOQualTool.m: fix: returned value in a void method
+
+ * GNUmakefile (TOOL_NAME): do not compile subclassing.m on
+ MacOSX
+
+ * EncodingTool.m: fixed compilation on MacOSX
+
+2003-05-15 Helge Hess <helge.hess@skyrix.com>
+
+ * added parserule for testing parsing of NGRule objects
+
+2003-05-14 Helge Hess <helge.hess@skyrix.com>
+
+ * some gcc 3.3 warnings fixed
+
+2003-04-03 Helge Hess <helge.hess@skyrix.com>
+
+ * GNUmakefile: added ldapchkpwd tool
+
+ * ldap2dsml.m: added autorelease-pool to main()
+
+2003-04-01 GNUstep User <helge.hess@skyrix.com>
+
+ * ImapListTool.m: do not use NSFileIdentifier constant
+
+ * EncodingTool.m: removed some undeclared encodings when compiling for
+ GNUstep Base
+
+2003-02-12 Helge Hess <helge.hess@skyrix.com>
+
+ * added ical2.m, ical3.m - examples for NGiCal
+
+2003-01-30 Helge Hess <helge.hess@skyrix.com>
+
+ * added httpu_notify, a small tool to send out HTTP-over-UDP
+ NOTIFY notifications
+
+2003-01-08 Helge Hess <helge.hess@skyrix.com>
+
+ * testsock.m: improved test code
+
+2003-01-07 Helge Hess <helge.hess@skyrix.com>
+
+ * subclassing.m, ImapQuotaTool.m, imapquota.m: fixed compilation
+ warnings
+
+ * moved in testsock.m from NGStreams
+
+ * changes for improved compilation on MacOSX, replaced RETAIN macros
+ with methods
+
+Fri Dec 27 10:54:40 2002 Helge Hess <helge.hess@skyrix.com>
+
+ * Mime2XmlTool.m: fixed a protocol warning
+
+Mon Dec 23 15:36:01 2002 Helge Hess <helge.hess@skyrix.com>
+
+ * ImapListTool.m: pass correct filemanager as a parameter
+
+2002-12-08 Helge Hess <helge.hess@skyrix.com>
+
+ * testdirenum.m: cleanups
+
+Tue Dec 17 15:07:40 2002 <jan@skyrix.com>
+
+ * imapquota.m: add quota test
+
+2002-11-21 Jan Reichmann <jr@skyrix.com>
+
+ * added Imap-Super class, improve imapls
+
+2002-11-21 Helge Hess <helge.hess@skyrix.com>
+
+ * added ldapls, ldap2dsml as examples for NGLdap
+
+2002-11-15 Helge Hess <helge.hess@skyrix.com>
+
+ * EOQualTool.m: added test for complex cast
+
+2002-10-29 Helge Hess <helge.hess@skyrix.com>
+
+ * EOQualTool.m: added support for parsing SQL using the new EOSQLParser
+
+2002-10-25 Helge Hess <helge.hess@skyrix.com>
+
+ * added eoqual tool for parsing EOQualifier's (useful for syntax
+ checks)
+
+ * created ChangeLog
+
--- /dev/null
+# GNUstep makefile
+
+-include ../../config.make
+include $(GNUSTEP_MAKEFILES)/common.make
+
+TOOL_NAME = vcardtest versittest icalparsetest icalds vcf2xml vcfparsetest ievalrrule
+
+ADDITIONAL_INCLUDE_DIRS += -I../NGCards
+
+vcardtest_OBJC_FILES = unittest.m vcardtest.m CardElement.m CardGroup.m CardVersitRenderer.m NSArray+NGCards.m NSDictionary+NGCards.m
+versittest_OBJC_FILES = unittest.m versittest.m CardElement.m CardGroup.m CardVersitRenderer.m NSArray+NGCards.m NSDictionary+NGCards.m NSString+NGCards.m
+icalparsetest_OBJC_FILES = icalparsetest.m
+icalds_OBJC_FILES = icalds.m
+vcf2xml_OBJC_FILES = vcf2xml.m
+vcfparsetest_OBJC_FILES = vcfparsetest.m CardElement.m CardGroup.m CardVersitRenderer.m NSArray+NGCards.m NSDictionary+NGCards.m NSString+NGCards.m
+ievalrrule_OBJC_FILES = ievalrrule.m
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/tool.make
+-include GNUmakefile.postamble
+-include fhs.make
+
+CardElement.m: ../NGCards/CardElement.m
+ ln -sf ../NGCards/CardElement.m ./
+
+CardGroup.m: ../NGCards/CardGroup.m
+ ln -sf ../NGCards/CardGroup.m ./
+
+CardVersitRenderer.m: ../NGCards/CardVersitRenderer.m
+ ln -sf ../NGCards/CardVersitRenderer.m ./
+
+NSArray+NGCards.m: ../NGCards/NSArray+NGCards.m
+ ln -sf ../NGCards/NSArray+NGCards.m ./
+
+NSDictionary+NGCards.m: ../NGCards/NSDictionary+NGCards.m
+ ln -sf ../NGCards/NSDictionary+NGCards.m ./
+
+NSString+NGCards.m: ../NGCards/NSString+NGCards.m
+ ln -sf ../NGCards/NSString+NGCards.m ./
+
+
+distclean clean::
+ -rm -f CardElement.m CardGroup.m CardVersitRenderer.m NSArray+NGCards.m NSDictionary+NGCards.m NSString+NGCards.m
--- /dev/null
+# compilation flags
+
+SOPE_ROOT=../..
+SOPE_CORE="../../sope-core"
+SOPE_XML="../../sope-xml"
+
+ADDITIONAL_INCLUDE_DIRS += \
+ -I.. \
+ -I$(SOPE_CORE)/NGStreams \
+ -I$(SOPE_CORE)/NGExtensions \
+
+
+# PCH
+
+icalparsetest_PCH_FILE = common.h
+icalds_PCH_FILE = common.h
+vcf2xml_PCH_FILE = common.h
+vcfparsetest_PCH_FILE = common.h
+ievalrrule_PCH_FILE = common.h
+
+
+# dependencies
+
+ifneq ($(frameworks),yes)
+icalparsetest_TOOL_LIBS += -lNGCards
+icalds_TOOL_LIBS += -lNGCards
+vcfparsetest_TOOL_LIBS += -lNGCards
+ievalrrule_TOOL_LIBS += -lNGCards
+
+ADDITIONAL_TOOL_LIBS += \
+ -lNGStreams -lNGExtensions -lEOControl \
+ -lDOM -lSaxObjC
+else
+icalparsetest_TOOL_LIBS += -framework NGCards
+icalds_TOOL_LIBS += -framework NGCards
+vcfparsetest_TOOL_LIBS += -framework NGCards
+ievalrrule_TOOL_LIBS += -framework NGCards
+
+ADDITIONAL_TOOL_LIBS += \
+ -framework NGStreams -framework NGExtensions -framework EOControl \
+ -framework DOM -framework SaxObjC
+endif
+
+
+# library/framework search pathes
+
+DEP_DIRS = \
+ ../NGCards/ \
+ $(SOPE_ROOT)/sope-core/NGExtensions \
+ $(SOPE_ROOT)/sope-core/NGStreams \
+ $(SOPE_ROOT)/sope-core/EOControl \
+ $(SOPE_ROOT)/sope-xml/DOM \
+ $(SOPE_ROOT)/sope-xml/SaxObjC
+
+ifneq ($(frameworks),yes)
+ADDITIONAL_LIB_DIRS += \
+ $(foreach dir,$(DEP_DIRS),\
+ -L$(GNUSTEP_BUILD_DIR)/$(dir)/$(GNUSTEP_OBJ_DIR_NAME))
+else
+ADDITIONAL_LIB_DIRS += \
+ $(foreach dir,$(DEP_DIRS),-F$(GNUSTEP_BUILD_DIR)/$(dir))
+endif
+
+SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
--- /dev/null
+sope-ical/samples
+
+This directory contains sample programs for the sope-ical libraries.
+
+Tools
+=====
+
+ical2 - uses SaxObjectDecoder with NGiCal.xmap
+ical3 - uses iCalDataSource to run queries on iCal files
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import <Foundation/Foundation.h>
+
+#if LIB_FOUNDATION_LIBRARY
+# include <Foundation/exceptions/GeneralExceptions.h>
+#else
+# include <NGExtensions/NGObjectMacros.h>
+# include <NGExtensions/NSString+Ext.h>
+#endif
+
+#include <NGExtensions/NGExtensions.h>
--- /dev/null
+# postprocessing
+
+# FHS support (this is a hack and is going to be done by gstep-make!)
+
+ifneq ($(FHS_INSTALL_ROOT),)
+
+FHS_INCLUDE_DIR=$(FHS_INSTALL_ROOT)/include/
+FHS_LIB_DIR=$(FHS_INSTALL_ROOT)/lib/
+FHS_BIN_DIR=$(FHS_INSTALL_ROOT)/bin/
+
+fhs-bin-dirs ::
+ $(MKDIRS) $(FHS_BIN_DIR)
+
+NONFHS_BINDIR="$(GNUSTEP_TOOLS)/$(GNUSTEP_TARGET_LDIR)"
+
+move-tools-to-fhs :: fhs-bin-dirs
+ @echo "moving tools from $(NONFHS_BINDIR) to $(FHS_BIN_DIR) .."
+ for i in $(TOOL_NAME); do \
+ mv "$(NONFHS_BINDIR)/$${i}" $(FHS_BIN_DIR); \
+ done
+
+move-to-fhs :: move-tools-to-fhs
+
+after-install :: move-to-fhs
+
+endif
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import <Foundation/Foundation.h>
+
+@class EOQualifier, NSString, EOSortOrdering;
+
+@interface iCal3Tool : NSObject
+{
+ EOQualifier *qualifier;
+ NSString *entityName;
+ NSArray *sortOrderings;
+}
+
+- (int)runWithArguments:(NSArray *)_args;
+
+@end
+
+#include <NGCards/iCalDataSource.h>
+#include <NGCards/iCalObject.h>
+#include <EOControl/EOQualifier.h>
+#include <EOControl/EOSortOrdering.h>
+#include "common.h"
+
+@implementation iCal3Tool
+
+- (id)init {
+ if ((self = [super init])) {
+ NSUserDefaults *ud;
+ id tmp;
+
+ /* collect options */
+ ud = [NSUserDefaults standardUserDefaults];
+
+ self->entityName = [[ud stringForKey:@"entity"] copy];
+
+ if ((tmp = [ud objectForKey:@"qualifier"]) != nil) {
+ self->qualifier = [[EOQualifier alloc] initWithPropertyList:tmp
+ owner:nil];
+ }
+
+ if ((tmp = [ud objectForKey:@"sort"]) != nil) {
+ tmp = [[EOSortOrdering alloc] initWithPropertyList:tmp owner:nil];
+ if (tmp != nil) {
+ self->sortOrderings = [[NSArray alloc] initWithObjects:&tmp count:1];
+ [tmp release]; tmp = nil;
+ }
+ }
+ }
+ return self;
+}
+- (void)dealloc {
+ [self->sortOrderings release];
+ [self->qualifier release];
+ [self->entityName release];
+ [super dealloc];
+}
+
+/* run */
+
+- (void)printObject:(id)_object {
+ printf("object: %s\n", [[_object description] cString]);
+}
+
+- (int)runWithArguments:(NSArray *)_args {
+ NSEnumerator *args;
+ NSString *arg;
+
+ /* begin processing */
+
+ args = [_args objectEnumerator];
+ [args nextObject]; // process name ...
+
+ while ((arg = [args nextObject])) {
+ NSAutoreleasePool *pool2;
+
+ if ([arg hasPrefix:@"-"]) { /* consume defaults */
+ [args nextObject];
+ continue;
+ }
+
+ pool2 = [[NSAutoreleasePool alloc] init];
+ {
+ iCalDataSource *ds;
+ EOFetchSpecification *fspec;
+ NSArray *objs;
+ iCalObject *obj;
+
+ /* setup fetch specification */
+
+ fspec = [[[EOFetchSpecification alloc] init] autorelease];
+ [fspec setEntityName:self->entityName];
+ [fspec setQualifier:self->qualifier];
+
+ /* setup datasource */
+
+ ds = [iCalDataSource alloc]; // keep gcc happy
+ ds = [[ds initWithPath:arg] autorelease];
+ [ds setFetchSpecification:fspec];
+
+ /* perform fetch */
+
+ if ((objs = [ds fetchObjects]) == nil) {
+ /* fetch failed */
+
+ NSLog(@"fetch on ical file failed: %@", arg);
+ }
+ else {
+ /* process results */
+ NSEnumerator *e;
+
+ e = [objs objectEnumerator];
+ while ((obj = [e nextObject])) {
+ [self printObject:obj];
+ }
+ }
+ }
+ [pool2 release];
+ }
+ return 0;
+}
+
+@end /* iCal3Tool */
+
+int main(int argc, char **argv, char **env) {
+ NSAutoreleasePool *pool;
+ iCal3Tool *tool;
+ int rc;
+
+ pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+ [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+ if ((tool = [[iCal3Tool alloc] init])) {
+ NS_DURING
+ rc = [tool runWithArguments:[[NSProcessInfo processInfo] arguments]];
+ NS_HANDLER
+ abort();
+ NS_ENDHANDLER;
+
+ [tool release];
+ }
+ else
+ rc = 1;
+
+ [pool release];
+ return rc;
+}
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import <Foundation/Foundation.h>
+#include <SaxObjC/SaxObjC.h>
+
+@interface iCal2Tool : NSObject
+{
+ id<NSObject,SaxXMLReader> parser;
+ SaxObjectDecoder *sax;
+}
+
+- (int)runWithArguments:(NSArray *)_args;
+
+@end
+
+@implementation iCal2Tool
+
+- (id)init {
+ if ((self = [super init])) {
+ self->parser =
+ [[[SaxXMLReaderFactory standardXMLReaderFactory]
+ createXMLReaderForMimeType:@"text/calendar"]
+ retain];
+ if (self->parser == nil) {
+ NSLog(@"%s: did not find a parser for text/calendar !",
+ __PRETTY_FUNCTION__);
+ [self release];
+ return nil;
+ }
+
+ /* ensure that NGCards.xmap can be found ! (Library/SaxMappings) */
+ self->sax = [[SaxObjectDecoder alloc] initWithMappingNamed:@"NGCards"];
+ if (self->sax == nil) {
+ NSLog(@"could not create the iCal SAX handler !");
+ [self release];
+ return nil;
+ }
+
+ [self->parser setContentHandler:self->sax];
+ [self->parser setErrorHandler:self->sax];
+ }
+ return self;
+}
+- (void)dealloc {
+ [self->sax release];
+ [self->parser release];
+ [super dealloc];
+}
+
+/* parsing */
+
+- (id)parseFile:(NSString *)_path {
+ if ([_path length] == 0) return nil;
+
+ _path = [@"file://" stringByAppendingString:_path];
+
+ [self->parser parseFromSystemId:_path];
+
+ return [self->sax rootObject];
+}
+
+- (void)printParsedObject:(id)_object {
+ NSLog(@"component: %@", _object);
+#if 0
+ NSLog(@" subcomponents: %@", [_object subComponents]);
+
+ printf("%s", [[_object icalString] cString]);
+#endif
+}
+
+/* run */
+
+- (int)runWithArguments:(NSArray *)_args {
+ NSEnumerator *args;
+ NSString *arg;
+
+ args = [_args objectEnumerator];
+ [args nextObject]; // process name ...
+
+ while ((arg = [args nextObject])) {
+ NSAutoreleasePool *pool2;
+
+ if ([arg hasPrefix:@"-"]) { /* consume defaults */
+ [args nextObject];
+ continue;
+ }
+
+ pool2 = [[NSAutoreleasePool alloc] init];
+ {
+ id component;
+
+ NS_DURING
+ component = [self parseFile:arg];
+ NS_HANDLER
+ abort();
+ NS_ENDHANDLER;
+
+ if (component == nil)
+ NSLog(@"could not parse file: '%@'", arg);
+ else
+ [self printParsedObject:component];
+ }
+ [pool2 release];
+ }
+ return 0;
+}
+
+@end /* iCal2Tool */
+
+int main(int argc, char **argv, char **env) {
+ NSAutoreleasePool *pool;
+ iCal2Tool *tool;
+ int rc;
+
+#if LIB_FOUNDATION_LIBRARY
+ [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+ pool = [[NSAutoreleasePool alloc] init];
+
+ if ((tool = [[iCal2Tool alloc] init])) {
+ NS_DURING
+ rc = [tool runWithArguments:[[NSProcessInfo processInfo] arguments]];
+ NS_HANDLER
+ abort();
+ NS_ENDHANDLER;
+
+ [tool release];
+ }
+ else
+ rc = 1;
+
+ [pool release];
+ return rc;
+}
--- /dev/null
+/*
+ Copyright (C) 2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include <NGCards/iCalRecurrenceRule.h>
+#include <NGCards/iCalRecurrenceCalculator.h>
+#include <NGExtensions/NGCalendarDateRange.h>
+#include "common.h"
+
+static NSCalendarDate *dateForString(NSString *_s) {
+ // copied from ogo-chkaptconflicts, maybe move to NGExtensions?
+ static NSCalendarDate *now = nil;
+ static NSCalendarDate *mon = nil;
+
+ if (now == nil) now = [[NSCalendarDate date] retain];
+ if (mon == nil) mon = [[now mondayOfWeek] retain];
+ _s = [_s lowercaseString];
+
+ if ([_s isEqualToString:@"now"]) return now;
+ if ([_s isEqualToString:@"tomorrow"]) return [now tomorrow];
+ if ([_s isEqualToString:@"yesterday"]) return [now yesterday];
+
+ if ([_s hasPrefix:@"mon"]) return mon;
+ if ([_s hasPrefix:@"tue"]) return [mon dateByAddingYears:0 months:0 days:1];
+ if ([_s hasPrefix:@"wed"]) return [mon dateByAddingYears:0 months:0 days:2];
+ if ([_s hasPrefix:@"thu"]) return [mon dateByAddingYears:0 months:0 days:3];
+ if ([_s hasPrefix:@"fri"]) return [mon dateByAddingYears:0 months:0 days:4];
+ if ([_s hasPrefix:@"sat"]) return [mon dateByAddingYears:0 months:0 days:5];
+ if ([_s hasPrefix:@"sun"]) return [mon dateByAddingYears:0 months:0 days:6];
+
+ switch ([_s length]) {
+ case 6:
+ return [NSCalendarDate dateWithString:_s calendarFormat:@"%Y%m"];
+ case 8:
+ return [NSCalendarDate dateWithString:_s calendarFormat:@"%Y%m%d"];
+ case 10:
+ return [NSCalendarDate dateWithString:_s calendarFormat:@"%Y%-m-%d"];
+ case 13:
+ return [NSCalendarDate dateWithString:_s calendarFormat:@"%Y%m%d %H%M"];
+ case 14:
+ return [NSCalendarDate dateWithString:_s calendarFormat:@"%Y%m%d %H:%M"];
+ case 16:
+ return [NSCalendarDate dateWithString:_s calendarFormat:@"%Y-%m-%d %H:%M"];
+ default:
+ return nil;
+ }
+}
+
+static int usage(NSArray *args) {
+ fprintf(stderr,
+ "usage: %s <rrule> <startdate> <enddate> <cycleend>\n"
+ "\n"
+ "sample:\n"
+ " %s 'FREQ=MONTHLY;BYDAY=2TU' '20050901 14:00' '20050901 15:00' "
+ "20060921\n",
+ [[args objectAtIndex:0] cString],
+ [[args objectAtIndex:0] cString]);
+ return 1;
+}
+
+static void printInstances(NSArray *instances) {
+ unsigned i, count;
+
+ if ((count = [instances count]) == 0) {
+ printf("no reccurrences in given range\n");
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ NGCalendarDateRange *instance;
+ NSString *s;
+
+ instance = [instances objectAtIndex:i];
+
+ s = [[instance startDate] descriptionWithCalendarFormat:
+ @"%a, %Y-%m-%d at %H:%M"];
+ printf("%s - ", [s cString]);
+
+ s = [[instance endDate] descriptionWithCalendarFormat:
+ [[instance startDate] isDateOnSameDay:
+ [instance endDate]]
+ ? @"%H:%M"
+ : @"%a, %Y-%m-%d at %H:%M"];
+ printf("%s\n", [s cString]);
+ }
+}
+
+static int runIt(NSArray *args) {
+ iCalRecurrenceCalculator *cpu;
+ iCalRecurrenceRule *rrule;
+ NGCalendarDateRange *startRange, *calcRange;
+ NSCalendarDate *from, *to, *cycleTo;
+ NSString *pattern;
+ NSArray *instances;
+
+ if ([args count] < 5)
+ return usage(args);
+
+ pattern = [args objectAtIndex:1];
+ from = dateForString([args objectAtIndex:2]);
+ to = dateForString([args objectAtIndex:3]);
+ cycleTo = dateForString([args objectAtIndex:4]);
+
+ if (from == nil || to == nil || cycleTo == nil || ![pattern isNotEmpty])
+ return usage(args);
+
+ startRange =
+ [NGCalendarDateRange calendarDateRangeWithStartDate:from endDate:to];
+
+ calcRange =
+ [NGCalendarDateRange calendarDateRangeWithStartDate:from endDate:cycleTo];
+
+ /* parse rrule */
+
+ if ((rrule = [[iCalRecurrenceRule alloc] initWithString:pattern]) == nil) {
+ usage(args);
+ fprintf(stderr, "error: could not parse reccurence rule: '%s'\n",
+ [pattern cString]);
+ return 2;
+ }
+
+ NSLog(@"from: %@ to: %@, cycle %@", from, to, cycleTo);
+ NSLog(@"rrule: %@", rrule);
+
+ /* calculate */
+
+ cpu = [iCalRecurrenceCalculator
+ recurrenceCalculatorForRecurrenceRule:rrule
+ withFirstInstanceCalendarDateRange:startRange];
+
+ instances = [cpu recurrenceRangesWithinCalendarDateRange:calcRange];
+ printInstances(instances);
+
+ return 0;
+}
+
+int main(int argc, char **argv, char **env) {
+ NSAutoreleasePool *pool;
+ int rc;
+
+ pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+ [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+ rc = runIt([[NSProcessInfo processInfo] argumentsWithoutDefaults]);
+ [pool release];
+ return rc;
+}
--- /dev/null
+/* unittest.h - this file is part of $PROJECT_NAME_HERE$
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef UNITTEST_H
+#define UNITTEST_H
+
+#import <Foundation/NSObject.h>
+
+@interface unittest : NSObject
+
+- (void) run;
+
+@end
+
+#define testEqual(x,y) \
+ if ((x) != (y)) { \
+ NSLog (@"%s: values not equal at line %d", \
+ __PRETTY_FUNCTION__, __LINE__); \
+ return NO; \
+ }
+
+#define testObjectsEqual(x,y) \
+ if (![(x) isEqual: (y)]) { \
+ NSLog (@"%s: objects not equal at line %d", \
+ __PRETTY_FUNCTION__, __LINE__); \
+ return NO; \
+ }
+
+#define testStringsEqual(x,y) \
+ if (!([(x) isKindOfClass: [NSString class]] \
+ && [(y) isKindOfClass: [NSString class]] ) \
+ || ![(x) isEqualToString: (y)]) { \
+ NSLog (@"%s: strings \"%@\" and \"%@\" not equal at" \
+ @" line %d", __PRETTY_FUNCTION__, (x), (y), \
+ __LINE__); \
+ return NO; \
+ }
+
+#define testNotEqual(x,y) \
+ if ((x) == (y)) { \
+ NSLog (@"%s: values equal at line %d", \
+ __PRETTY_FUNCTION__, __LINE__); \
+ return NO; \
+ }
+
+#define testObjectsNotEqual(x,y) \
+ if ([(x) isEqual: (y)]) { \
+ NSLog (@"%s: objects not equal at line %d", \
+ __PRETTY_FUNCTION__, __LINE__); \
+ return NO; \
+ }
+
+#define testStringsNotEqual(x,y) \
+ if (!([(x) isKindOfClass: [NSString class]] \
+ && [(y) isKindOfClass: [NSString class]]) \
+ || [(x) isEqualToString: (y)]) { \
+ NSLog (@"%s: strings not equal at line %d", \
+ __PRETTY_FUNCTION__, __LINE__); \
+ return NO; \
+ }
+
+@interface unittest (OptionalMethods)
+
+- (void) setUp;
+- (void) tearDown;
+
+@end
+
+#endif /* UNITTEST_H */
--- /dev/null
+/* unittest.m - this file is part of $PROJECT_NAME_HERE$
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSString.h>
+
+#import "unittest.h"
+
+@implementation unittest
+
+- (NSArray *) _testMethods
+{
+ Class testClass;
+ MethodList *methodList;
+ NSMutableArray *methods;
+ NSString *methodName;
+ unsigned int count, max;
+
+ testClass = [self class];
+
+ methods = [NSMutableArray new];
+ [methods autorelease];
+
+ while (testClass)
+ {
+ methodList = testClass->methods;
+ max = methodList->method_count;
+
+ for (count = 0; count < max; count++)
+ {
+ methodName
+ = NSStringFromSelector (methodList->method_list[count].method_name);
+ if ([methodName hasPrefix: @"test"])
+ [methods addObject: methodName];
+ }
+
+ testClass = testClass->super_class;
+ }
+
+ return methods;
+}
+
+- (void) run
+{
+ NSEnumerator *methods;
+ NSString *methodName;
+ unsigned int count, successes, failures;
+ BOOL success;
+
+ methods = [[self _testMethods] objectEnumerator];
+ methodName = [methods nextObject];
+
+ count = 0;
+ successes = 0;
+ failures = 0;
+ NSLog (@"-- start: %@", NSStringFromClass([self class]));
+ while (methodName)
+ {
+ count++;
+ if ([self respondsToSelector: @selector (setUp)])
+ [self setUp];
+ success
+ = (BOOL) [self performSelector: NSSelectorFromString (methodName)];
+ NSLog (@"%@ '%@'",
+ ((success) ? @"PASSED" : @"FAILED"), methodName);
+ if ([self respondsToSelector: @selector (tearDown)])
+ [self tearDown];
+ if (success)
+ successes++;
+ else
+ failures++;
+ methodName = [methods nextObject];
+ }
+
+ NSLog (@"-- end: %d methods, %d successes, %d failures",
+ count, successes, failures);
+}
+
+@end
--- /dev/null
+/* vcardtest.m - this file is part of $PROJECT_NAME_HERE$
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "CardElement.h"
+#import "CardGroup.h"
+
+#import "unittest.h"
+
+@interface subtest: unittest
+{
+ CardElement *element;
+}
+@end
+
+@implementation subtest: unittest
+
+- (void) setUp
+{
+ element = [CardElement new];
+}
+
+- (void) tearDown
+{
+ [element release];
+}
+
+- (BOOL) testSimpleElementWithTag_value
+{
+ CardElement *testElement;
+ NSArray *values;
+
+ testElement = [CardElement simpleElementWithTag: @"pouet"
+ value: @"tutu"];
+ testStringsEqual([testElement tag], @"pouet");
+
+ values = [testElement values];
+ testNotEqual(values, nil);
+ testEqual([values count], 1);
+ testStringsEqual([values objectAtIndex: 0], @"tutu");
+
+ return YES;
+}
+
+- (BOOL) testSimpleElementWithTag_singleType_value
+{
+ CardElement *testElement;
+ NSArray *values, *keys;
+ NSDictionary *attrs;
+
+ testElement = [CardElement simpleElementWithTag: @"pouet"
+ singleType: @"coucou"
+ value: @"tutu"];
+ testStringsEqual([testElement tag], @"pouet");
+
+ values = [testElement values];
+ testNotEqual(values, nil);
+ testEqual([values count], 1);
+ testStringsEqual([values objectAtIndex: 0], @"tutu");
+
+ attrs = [testElement attributes];
+ keys = [attrs allKeys];
+ testEqual([keys count], 1);
+ testStringsEqual([[keys objectAtIndex: 0] uppercaseString], @"TYPE");
+
+ return YES;
+}
+
+- (BOOL) testElementWithTag_attributes_values
+{
+ NSMutableDictionary *addedAttrs;
+ NSMutableArray *addedValues;
+ NSArray *rValues, *keys;
+ NSDictionary *rAttrs;
+ CardElement *testElement;
+
+ addedAttrs = [NSMutableDictionary new];
+ [addedAttrs setObject: [NSMutableArray arrayWithObjects:
+ @"value1", @"blabla", nil]
+ forKey: @"key1"];
+ [addedAttrs setObject: [NSMutableArray arrayWithObject: @"test2"]
+ forKey: @"key2"];
+ addedValues = [NSMutableArray new];
+ [addedValues addObject: @"value1"];
+ [addedValues addObject: @"pouetpouet2"];
+
+ testElement = [CardElement elementWithTag: @"pouet"
+ attributes: addedAttrs
+ values: addedValues];
+
+
+ testStringsEqual([testElement tag], @"pouet");
+ rValues = [testElement values];
+ rAttrs = [testElement attributes];
+ keys = [rAttrs allKeys];
+
+ testNotEqual(rValues, nil);
+ testNotEqual(rAttrs, nil);
+ testEqual([rValues count], 2);
+ testEqual([keys count], 2);
+ testNotEqual(addedValues, rValues);
+ testNotEqual(addedAttrs, rAttrs);
+
+ testStringsEqual([rValues objectAtIndex: 0], @"value1");
+ testStringsEqual([rValues objectAtIndex: 1], @"pouetpouet2");
+ testNotEqual([rAttrs objectForKey: @"key1"], nil);
+ testNotEqual([rAttrs objectForKey: @"key2"], nil);
+ testEqual([[rAttrs objectForKey: @"key1"] count], 2);
+ testEqual([[rAttrs objectForKey: @"key2"] count], 1);
+
+ testStringsEqual([[rAttrs objectForKey: @"key1"] objectAtIndex: 0],
+ @"value1");
+ testStringsEqual([[rAttrs objectForKey: @"key1"] objectAtIndex: 1],
+ @"blabla");
+ testStringsEqual([[rAttrs objectForKey: @"key2"] objectAtIndex: 0],
+ @"test2");
+
+ return YES;
+}
+
+- (BOOL) testAddValue
+{
+ NSArray *values;
+
+ values = [element values];
+ testEqual([values count], 0);
+ [element addValue: @"test"];
+ testEqual([values count], 1);
+ testStringsEqual([values objectAtIndex: 0], @"test");
+ [element addValue: @"coucou"];
+ testEqual([values count], 2);
+ testStringsEqual([values objectAtIndex: 0], @"test");
+ testStringsEqual([values objectAtIndex: 1], @"coucou");
+
+ return YES;
+}
+
+- (BOOL) testAddValues
+{
+ NSArray *values;
+
+ values = [element values];
+ [element addValue: @"cuicui"];
+ testEqual([values count], 1);
+
+ [element addValues: [NSArray arrayWithObject: @"coucou"]];
+ testEqual([values count], 2);
+
+ [element addValue: @"cuicui2"];
+ testEqual([values count], 3);
+ testStringsEqual([values objectAtIndex: 1], @"coucou");
+ testStringsEqual([values objectAtIndex: 2], @"cuicui2");
+
+ return YES;
+}
+
+- (BOOL) testAddType
+{
+ NSMutableDictionary *attrs;
+ NSArray *types;
+
+ attrs = (NSMutableDictionary *) [element attributes];
+ testEqual([attrs objectForKey: @"TYPE"], nil);
+ [element addType: @"INTERNET"];
+ types = [attrs objectForKey: @"type"];
+ testNotEqual(types, nil);
+ testEqual([types count], 1);
+ testStringsEqual([types objectAtIndex: 0],
+ @"INTERNET");
+
+ [element addType: @"pref"];
+ testEqual([types count], 2);
+ testStringsEqual([types objectAtIndex: 0],
+ @"INTERNET");
+ testStringsEqual([types objectAtIndex: 1],
+ @"pref");
+
+ return YES;
+}
+
+- (BOOL) testAddAttribute_value
+{
+ NSMutableDictionary *attrs;
+
+ attrs = (NSMutableDictionary *) [element attributes];
+ testEqual([attrs objectForKey: @"attr1"], nil);
+ [element addAttribute: @"attr1" value: @"value1"];
+ testNotEqual([attrs objectForKey: @"attr1"], nil);
+ testEqual([[attrs objectForKey: @"attr1"] count], 1);
+ testStringsEqual([[attrs objectForKey: @"attr1"] objectAtIndex: 0],
+ @"value1");
+
+ [element addAttribute: @"attr1" value: @"value2"];
+ testEqual([[attrs objectForKey: @"attr1"] count], 2);
+ testStringsEqual([[attrs objectForKey: @"attr1"] objectAtIndex: 0],
+ @"value1");
+ testStringsEqual([[attrs objectForKey: @"attr1"] objectAtIndex: 1],
+ @"value2");
+
+ return YES;
+}
+
+- (BOOL) testAddAttributes
+{
+ NSMutableDictionary *attrs, *addedAttrs;
+ NSArray *keys;
+
+ attrs = (NSMutableDictionary *) [element attributes];
+ keys = [attrs allKeys];
+ testEqual([keys count], 0);
+
+ [attrs setObject: [NSMutableArray arrayWithObject: @"test1"]
+ forKey: @"key1"];
+ keys = [attrs allKeys];
+ testEqual([keys count], 1);
+
+ addedAttrs = [NSMutableDictionary new];
+ [addedAttrs setObject: [NSMutableArray arrayWithObject: @"test2"]
+ forKey: @"key2"];
+ [element addAttributes: addedAttrs];
+ [addedAttrs release];
+ keys = [attrs allKeys];
+ testEqual([keys count], 2);
+ testNotEqual([attrs objectForKey: @"key2"], nil);
+ testStringsEqual([[attrs objectForKey: @"key2"] objectAtIndex: 0],
+ @"test2");
+
+ testNotEqual([attrs objectForKey: @"key1"], nil);
+ testStringsEqual([[attrs objectForKey: @"key1"] objectAtIndex: 0],
+ @"test1");
+ testEqual([[attrs objectForKey: @"key1"] count], 1);
+ addedAttrs = [NSMutableDictionary new];
+ [addedAttrs setObject: [NSMutableArray arrayWithObject: @"test3"]
+ forKey: @"key1"];
+ [element addAttributes: addedAttrs];
+ [addedAttrs release];
+ testStringsEqual([[attrs objectForKey: @"key1"] objectAtIndex: 1],
+ @"test3");
+
+ return YES;
+}
+
+- (BOOL) testSetValue_To
+{
+ NSArray *values;
+
+ values = [element values];
+ testEqual([values count], 0);
+
+ [element setValue: 2 to: @"coucou"];
+ testStringsEqual([values objectAtIndex: 0], @"");
+ testStringsEqual([values objectAtIndex: 1], @"");
+ testStringsEqual([values objectAtIndex: 2], @"coucou");
+
+ [element setValue: 0 to: @"cuicui"];
+ testStringsEqual([values objectAtIndex: 0], @"cuicui");
+ testStringsEqual([values objectAtIndex: 1], @"");
+ testStringsEqual([values objectAtIndex: 2], @"coucou");
+
+ return YES;
+}
+
+// BEGIN:VCALENDAR
+// CALSCALE:GREGORIAN
+// X-WR-TIMEZONE;VALUE=TEXT:Europe/Berlin
+// PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
+// X-WR-CALNAME;VALUE=TEXT:shire-cal1
+// X-WR-RELCALID;VALUE=TEXT:C3CBA0E4-DBCC-11D6-A381-00039340AF4A
+// VERSION:2.0
+// BEGIN:VEVENT
+// DTSTAMP:20021008T155243Z
+// SUMMARY:work
+// UID:C3CB87C0-DBCC-11D6-A381-00039340AF4A
+// DTSTART;TZID=Europe/Berlin:20021009T120000
+// DURATION:PT3H45M
+// END:VEVENT
+// BEGIN:VEVENT
+// ATTENDEE;CN=Anja Berlin:mailto:anja.berlin@regiocom.net
+// ATTENDEE;CN=Marcus Müller:mailto:mm@codeon.de
+// DTSTAMP:20021009T211904Z
+// SUMMARY:trink
+// UID:C3CB8E9A-DBCC-11D6-A381-00039340AF4A
+// ORGANIZER;CN=Helge Heß:mailto:helge.hess@skyrix.com
+// DTSTART;TZID=Europe/Berlin:20021010T190000
+// DURATION:PT45M
+// BEGIN:VALARM
+// TRIGGER;VALUE=DURATION:-PT15M
+// ACTION:DISPLAY
+// DESCRIPTION:Event reminder
+// END:VALARM
+// BEGIN:VALARM
+// ATTACH;VALUE=URI:Ping
+// TRIGGER;VALUE=DURATION:-PT15M
+// ACTION:AUDIO
+// END:VALARM
+// END:VEVENT
+// BEGIN:VEVENT
+// DTSTAMP:20021008T155256Z
+// SUMMARY:Zahnarzt
+// DTEND;TZID=Europe/Berlin:20021009T110000
+// UID:C3CB92B0-DBCC-11D6-A381-00039340AF4A
+// DTSTART;TZID=Europe/Berlin:20021009T094500
+// END:VEVENT
+// BEGIN:VTODO
+// DTSTAMP:20021009T154221Z
+// SUMMARY:testjob
+// UID:C3CB96C7-DBCC-11D6-A381-00039340AF4A
+// DUE;TZID=Europe/Berlin:20021011T175228
+// PRIORITY:5
+// DTSTART;TZID=Europe/Berlin:20021008T175228
+// END:VTODO
+// BEGIN:VTODO
+// UID:C3CB9A9F-DBCC-11D6-A381-00039340AF4A
+// DTSTART;TZID=Europe/Berlin:20021010T000000
+// DTSTAMP:20021009T154205Z
+// SUMMARY:testjob2
+// END:VTODO
+// END:VCALENDAR
+
+@end
+
+int main (int argc, char **argv, char **env)
+{
+ NSAutoreleasePool *pool;
+ subtest *test;
+ int rc;
+
+ pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+ [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+ test = [subtest new];
+ if (test) {
+ NS_DURING
+ [test run];
+ NS_HANDLER
+ abort();
+ NS_ENDHANDLER;
+
+ [test release];
+ }
+ else
+ rc = 1;
+
+ [pool release];
+
+ return rc;
+}
--- /dev/null
+/*
+ Copyright (C) 2005 Helge Hess
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+// Note: this does not yet produce valid XML output
+
+#import <Foundation/NSObject.h>
+#include <SaxObjC/SaxObjC.h>
+
+@interface vcf2xml : NSObject
+{
+ id<NSObject,SaxXMLReader> parser;
+ id sax;
+}
+
+- (int)runWithArguments:(NSArray *)_args;
+
+@end
+
+#include "common.h"
+
+@interface MySAXHandler : SaxDefaultHandler
+{
+ id locator;
+ int indent;
+
+ NSString *lastNS;
+}
+
+- (void)indent;
+
+@end
+
+@implementation vcf2xml
+
+- (id)init {
+ if ((self = [super init]) != nil) {
+ self->parser = [[[SaxXMLReaderFactory standardXMLReaderFactory]
+ createXMLReaderForMimeType:@"text/x-vcard"] retain];
+ if (parser == nil) {
+ fprintf(stderr, "Error: could not load a vCard SAX driver bundle!\n");
+ exit(2);
+ }
+ //NSLog(@"Using parser: %@", self->parser);
+
+ self->sax = [[MySAXHandler alloc] init];
+ [parser setContentHandler:self->sax];
+ [parser setErrorHandler:self->sax];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [self->sax release];
+ [self->parser release];
+ [super dealloc];
+}
+
+/* process files */
+
+- (void)processFile:(NSString *)_path {
+ [self->parser parseFromSystemId:_path];
+}
+
+/* error handling */
+
+- (NSException *)handleException:(NSException *)_exc onPath:(NSString *)_p {
+ fprintf(stderr, "Error: catched exception on path '%s': %s\n",
+ [_p cString], [[_exc description] cString]);
+ return nil;
+}
+
+/* main entry */
+
+- (int)runWithArguments:(NSArray *)_args {
+ NSEnumerator *args;
+ NSString *arg;
+
+ /* begin processing */
+
+ args = [_args objectEnumerator];
+ [args nextObject]; // skip tool name ...
+
+ while ((arg = [args nextObject]) != nil) {
+ NSAutoreleasePool *pool2;
+
+ if ([arg hasPrefix:@"-"]) { /* consume defaults */
+ [args nextObject];
+ continue;
+ }
+
+ pool2 = [[NSAutoreleasePool alloc] init];
+
+
+ if (![arg isAbsolutePath]) {
+ arg = [[[NSFileManager defaultManager] currentDirectoryPath]
+ stringByAppendingPathComponent:arg];
+ }
+
+ NS_DURING
+ [self->parser parseFromSystemId:arg];
+ NS_HANDLER
+ [[self handleException:localException onPath:arg] raise];
+ NS_ENDHANDLER;
+
+ [pool2 release];
+ }
+ return 0;
+}
+
+@end /* vcf2xml */
+
+
+@implementation MySAXHandler
+
+- (void)dealloc {
+ [self->lastNS release];
+ [self->locator release];
+ [super dealloc];
+}
+
+/* output */
+
+- (void)indent {
+ int i;
+
+ for (i = 0; i < (self->indent * 4); i++)
+ fputc(' ', stdout);
+}
+
+/* documents */
+
+- (void)setDocumentLocator:(id<NSObject,SaxLocator>)_loc {
+ [self->locator autorelease];
+ self->locator = [_loc retain];
+}
+
+- (void)startDocument {
+ //puts("start document ..");
+ //self->indent++;
+}
+- (void)endDocument {
+ //self->indent--;
+ //puts("end document.");
+}
+
+- (void)startPrefixMapping:(NSString *)_prefix uri:(NSString *)_uri {
+ [self indent];
+ //printf("ns-map: %s=%s\n", [_prefix cString], [_uri cString]);
+}
+- (void)endPrefixMapping:(NSString *)_prefix {
+ [self indent];
+ //printf("ns-unmap: %s\n", [_prefix cString]);
+}
+
+- (void)startElement:(NSString *)_localName
+ namespace:(NSString *)_ns
+ rawName:(NSString *)_rawName
+ attributes:(id<SaxAttributes>)_attrs
+{
+ int i, c;
+ [self indent];
+ printf("<%s", [_localName cString]);
+
+ if ([_ns length] > 0) {
+ if ([_ns isEqualToString:self->lastNS])
+ ;
+ else {
+ printf(" xmlns='%s'", [_ns cString]);
+ ASSIGNCOPY(self->lastNS, _ns);
+ }
+ }
+
+ for (i = 0, c = [_attrs count]; i < c; i++) {
+ NSString *type;
+ NSString *ans;
+
+ ans = [_attrs uriAtIndex:i];
+
+ printf(" %s=\"%s\"",
+ [[_attrs nameAtIndex:i] cString],
+ [[_attrs valueAtIndex:i] cString]);
+
+ if (![_ns isEqualToString:ans])
+ printf("(ns=%s)", [ans cString]);
+
+ type = [_attrs typeAtIndex:i];
+ if (![type isEqualToString:@"CDATA"] && (type != nil))
+ printf("[%s]", [type cString]);
+ }
+ puts(">");
+ self->indent++;
+}
+- (void)endElement:(NSString *)_localName
+ namespace:(NSString *)_ns
+ rawName:(NSString *)_rawName
+{
+ self->indent--;
+ [self indent];
+ printf("</%s>\n", [_localName cString]);
+}
+
+- (void)characters:(unichar *)_chars length:(int)_len {
+ NSString *str;
+ id tmp;
+ unsigned i, len;
+
+ if (_len == 0) {
+ [self indent];
+ printf("\"\"\n");
+ return;
+ }
+
+ for (i = 0; i < (unsigned)_len; i++) {
+ if (_chars[i] > 255) {
+ NSLog(@"detected large char: o%04o d%03i h%04X",
+ _chars[i], _chars[i], _chars[i]);
+ }
+ }
+
+ str = [NSString stringWithCharacters:_chars length:_len];
+ len = [str length];
+
+ tmp = [str componentsSeparatedByString:@"\n"];
+ str = [tmp componentsJoinedByString:@"\\n"];
+ tmp = [str componentsSeparatedByString:@"\r"];
+ str = [tmp componentsJoinedByString:@"\\r"];
+
+ [self indent];
+ printf("\"%s\"\n", [str cString]);
+}
+- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
+ NSString *data;
+ id tmp;
+
+ data = [NSString stringWithCharacters:_chars length:_len];
+ tmp = [data componentsSeparatedByString:@"\n"];
+ data = [tmp componentsJoinedByString:@"\\n"];
+ tmp = [data componentsSeparatedByString:@"\r"];
+ data = [tmp componentsJoinedByString:@"\\r"];
+
+ [self indent];
+ printf("whitespace: \"%s\"\n", [data cString]);
+}
+
+- (void)processingInstruction:(NSString *)_pi data:(NSString *)_data {
+ [self indent];
+ printf("PI: '%s' '%s'\n", [_pi cString], [_data cString]);
+}
+
+#if 0
+- (xmlEntityPtr)getEntity:(NSString *)_name {
+ NSLog(@"get entity %@", _name);
+ return NULL;
+}
+- (xmlEntityPtr)getParameterEntity:(NSString *)_name {
+ NSLog(@"get para entity %@", _name);
+ return NULL;
+}
+#endif
+
+/* entities */
+
+- (id)resolveEntityWithPublicId:(NSString *)_pubId
+ systemId:(NSString *)_sysId
+{
+ [self indent];
+ printf("shall resolve entity with '%s' '%s'",
+ [_pubId cString], [_sysId cString]);
+ return nil;
+}
+
+/* errors */
+
+- (void)warning:(SaxParseException *)_exception {
+ NSLog(@"warning(%@:%i): %@",
+ [[_exception userInfo] objectForKey:@"publicId"],
+ [[[_exception userInfo] objectForKey:@"line"] intValue],
+ [_exception reason]);
+}
+
+- (void)error:(SaxParseException *)_exception {
+ NSLog(@"error(%@:%i): %@",
+ [[_exception userInfo] objectForKey:@"publicId"],
+ [[[_exception userInfo] objectForKey:@"line"] intValue],
+ [_exception reason]);
+}
+
+- (void)fatalError:(SaxParseException *)_exception {
+ NSLog(@"fatal error(%@:%i): %@",
+ [[_exception userInfo] objectForKey:@"publicId"],
+ [[[_exception userInfo] objectForKey:@"line"] intValue],
+ [_exception reason]);
+ [_exception raise];
+}
+
+@end /* MySAXHandler */
+
+
+
+int main(int argc, char **argv, char **env) {
+ NSAutoreleasePool *pool;
+ vcf2xml *tool;
+ int rc;
+
+ pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+ [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+ if ((tool = [[vcf2xml alloc] init])) {
+ NS_DURING
+ rc = [tool runWithArguments:[[NSProcessInfo processInfo] arguments]];
+ NS_HANDLER
+ abort();
+ NS_ENDHANDLER;
+
+ [tool release];
+ }
+ else
+ rc = 1;
+
+ [pool release];
+ return rc;
+}
--- /dev/null
+/*
+ Copyright (C) 2005 Helge Hess
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import <Foundation/Foundation.h>
+#import <NGCards/NGVCard.h>
+
+@interface vcsparsetest : NSObject
+{
+}
+
+- (int)runWithArguments:(NSArray *)_args;
+
+@end
+
+@implementation vcsparsetest
+
+- (id)init {
+ if ((self = [super init])) {
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [super dealloc];
+}
+
+/* parsing */
+
+- (id)parseFile:(NSString *)_path {
+ if ([_path length] == 0) return nil;
+ return [NGVCard parseVCardsFromSource:[NSURL fileURLWithPath:_path]];
+}
+
+- (void)printParsedObject: (NSArray *)_cards
+{
+ NSEnumerator *cardObjects;
+ NGVCard *card;
+
+ cardObjects = [_cards objectEnumerator];
+ card = [cardObjects nextObject];
+ while (card)
+ {
+ NSLog (@"-------s\n%@\ne-------", [card versitString]);
+ card = [cardObjects nextObject];
+ }
+
+#if 0
+ NSLog(@" subcomponents: %@", [_object subComponents]);
+
+ printf("%s", [[_object icalString] cString]);
+#endif
+}
+
+/* run */
+
+- (int)runWithArguments:(NSArray *)_args {
+ NSEnumerator *args;
+ NSString *arg;
+
+ args = [_args objectEnumerator];
+ [args nextObject]; // process name ...
+
+ while ((arg = [args nextObject])) {
+ NSAutoreleasePool *pool2;
+
+ if ([arg hasPrefix:@"-"]) { /* consume defaults */
+ [args nextObject];
+ continue;
+ }
+
+ pool2 = [[NSAutoreleasePool alloc] init];
+ {
+ NSArray *cards;
+
+ NS_DURING
+ cards = [self parseFile:arg];
+ NS_HANDLER
+ abort();
+ NS_ENDHANDLER;
+
+ if (!cards)
+ NSLog(@"could not parse file: '%@'", arg);
+ else
+ [self printParsedObject:cards];
+ }
+ [pool2 release];
+ }
+ return 0;
+}
+
+@end /* vcsparsetest */
+
+int main(int argc, char **argv, char **env) {
+ NSAutoreleasePool *pool;
+ vcsparsetest *tool;
+ int rc;
+
+ pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+ [NSProcessInfo initializeWithArguments:argv count:argc environment:env];
+#endif
+
+ if ((tool = [[vcsparsetest alloc] init]) != nil) {
+ NS_DURING
+ rc = [tool runWithArguments:[[NSProcessInfo processInfo] arguments]];
+ NS_HANDLER
+ abort();
+ NS_ENDHANDLER;
+
+ [tool release];
+ }
+ else
+ rc = 1;
+
+ [pool release];
+ return rc;
+}
--- /dev/null
+/* versittest.m - this file is part of $PROJECT_NAME_HERE$
+ *
+ * Copyright (C) 2006 Inverse groupe conseil
+ *
+ * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "CardElement.h"
+#import "CardGroup.h"
+#import "CardVersitRenderer.h"
+#import "NSString+NGCards.h"
+
+#import "unittest.h"
+
+@interface versittest : unittest
+
+@end
+
+@implementation versittest
+
+- (BOOL) testRendering
+{
+ NSLog (@"rendering>");
+ CardVersitRenderer *renderer;
+ CardGroup *g, *g2;
+ CardElement *e;
+
+ g = [CardGroup groupWithTag: @"VCALENDAR"];
+ e = [CardElement simpleElementWithTag: @"CALSCALE"
+ value: @"GREGORIAN"];
+ [g addChild: e];
+ e = [CardElement simpleElementWithTag: @"X-WR-TIMEZONE"
+ value: @"Europe/Berlin"];
+ [e addAttribute: @"VALUE" value: @"TEXT"];
+ [g addChild: e];
+ e = [CardElement simpleElementWithTag: @"PRODID"
+ value: @"-//Apple Computer, Inc//iCal 1.0//EN"];
+ [g addChild: e];
+ e = [CardElement simpleElementWithTag: @"X-WR-CALNAME"
+ value: @"shire-cal1"];
+ [e addAttribute: @"VALUE" value: @"TEXT"];
+ [e setGroup: @"item1"];
+ [g addChild: e];
+ e = [CardElement simpleElementWithTag: @"X-WR-RELCALID"
+ value: @"C3CBA0E4-DBCC-11D6-A381-00039340AF4A"];
+ [e addAttribute: @"VALUE" value: @"TEXT"];
+ [g addChild: e];
+ e = [CardElement simpleElementWithTag: @"VERSION"
+ value: @"2.0"];
+ [g addChild: e];
+
+ g2 = [CardGroup groupWithTag: @"VEVENT"];
+ e = [CardElement simpleElementWithTag: @"DTSTAMP"
+ value: @"20021008T155243Z"];
+ [g2 addChild: e];
+ e = [CardElement simpleElementWithTag: @"SUMMARY"
+ value: @"work"];
+ [g2 addChild: e];
+ e = [CardElement simpleElementWithTag: @"UID"
+ value: @"C3CB87C0-DBCC-11D6-A381-00039340AF4A"];
+ [g2 addChild: e];
+ e = [CardElement simpleElementWithTag: @"DTSTART"
+ value: @"20021009T120000"];
+ [e addAttribute: @"TZID" value: @"Europe/Berlin"];
+ [g2 addChild: e];
+ e = [CardElement simpleElementWithTag: @"DURATION"
+ value: @"PT3H45M"];
+ [g2 addChild: e];
+ [g addChild: g2];
+
+ g2 = [CardGroup groupWithTag: @"VEVENT"];
+ e = [CardElement simpleElementWithTag: @"ATTENDEE"
+ value: @"mailto:anja.berlin@regiocom.net"];
+ [e addAttribute: @"CN" value: @"Anja Berlin"];
+ [g2 addChild: e];
+ e = [CardElement simpleElementWithTag: @"ATTENDEE"
+ value: @"mailto:mm@codeon.de"];
+ [e addAttribute: @"CN" value: @"Marcus Müller"];
+ [g2 addChild: e];
+ e = [CardElement simpleElementWithTag: @"DTSTAMP"
+ value: @"20021009T211904Z"];
+ [g2 addChild: e];
+ e = [CardElement simpleElementWithTag: @"SUMMARY"
+ value: @"trink"];
+ [g2 addChild: e];
+ e = [CardElement simpleElementWithTag: @"UID"
+ value: @"C3CB8E9A-DBCC-11D6-A381-00039340AF4A"];
+ [g2 addChild: e];
+ e = [CardElement simpleElementWithTag: @"ORGANIZER"
+ value: @"mailto:helge.hess@skyrix.com"];
+ [e addAttribute: @"CN" value: @"Helge Heß"];
+ [g2 addChild: e];
+ e = [CardElement simpleElementWithTag: @"DTSTART"
+ value: @"20021010T190000"];
+ [e addAttribute: @"TZID" value: @"Europe/Berlin"];
+ [g2 addChild: e];
+ e = [CardElement simpleElementWithTag: @"DURATION"
+ value: @"PT45M"];
+ [g2 addChild: e];
+ [g addChild: g2];
+
+ renderer = [CardVersitRenderer new];
+ NSLog (@"\n\n%@\n", [renderer render: g]);
+ [renderer release];
+
+ NSLog (@"<done");
+
+ return YES;
+}
+
+- (BOOL) testNSStringFoldedForVersitCards
+{
+ NSString *shortString, *longString, *foldedString;
+
+ shortString = @"PATATE";
+ testStringsEqual(shortString, [shortString foldedForVersitCards]);
+
+ longString = @"blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabl"
+ @"a PATATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabla PA"
+ @"TATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE"
+ @"blabla PATATE blabla PATATE blabla PATATE";
+
+ foldedString = @"blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabl\r\n"
+ @" a PATATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabla PA\r\n"
+ @" TATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE\r\n"
+ @" blabla PATATE blabla PATATE blabla PATATE";
+
+ testStringsEqual(foldedString, [longString foldedForVersitCards]);
+
+ return YES;
+}
+
+- (BOOL) testNSStringAsCardValues
+{
+ NSString *values[5];
+ NSArray *array[5];
+ NSArray *testarray[5];
+ unsigned int i, count, max;
+
+// patate,pouetpouet
+ values[0] = @"patate,pouetpouet";
+// patate\,pouetpouet
+ values[1] = @"patate\\,pouetpouet";
+// patate\\,pouetpouet
+ values[2] = @"patate\\\\,pouetpouet";
+// patate\\\,pouetpouet
+ values[3] = @"patate\\\\\\,pouetpouet";
+// patate,pouetpouet
+ values[4] = @"patate, pouetpouet";
+
+ testarray[0] = [NSArray arrayWithObjects: @"patate", @"pouetpouet", nil];
+ testarray[1] = [NSArray arrayWithObjects: @"patate,pouetpouet", nil];
+// should give [ @"patate\\", @"pouetpouet" ] instead...:
+ testarray[2] = [NSArray arrayWithObjects: @"patate\\,pouetpouet", nil];
+ testarray[3] = [NSArray arrayWithObjects: @"patate\\\\,pouetpouet", nil];
+ testarray[4] = [NSArray arrayWithObjects: @"patate", @"pouetpouet", nil];
+
+ for (i = 0; i < (sizeof(values) / sizeof(NSString *)); i++)
+ {
+ array[i] = [values[i] asCardAttributeValues];
+ max = [testarray[i] count];
+ for (count = 0; count < max; count++)
+ testStringsEqual([testarray[i] objectAtIndex: count],
+ [array[i] objectAtIndex: count]);
+ }
+
+ return YES;
+}
+
+@end
+
+int main (int argc, char **argv, char **env)
+{
+ NSAutoreleasePool *pool;
+ versittest *test;
+ int rc;
+
+ pool = [[NSAutoreleasePool alloc] init];
+#if LIB_FOUNDATION_LIBRARY
+ [NSProcessInfo initializeWithArguments: argv
+ count: argc
+ environment: env];
+#endif
+
+ test = [versittest new];
+ if (test) {
+ NS_DURING
+ [test run];
+ NS_HANDLER
+ abort();
+ NS_ENDHANDLER;
+
+ [test release];
+ }
+ else
+ rc = 1;
+
+ [pool release];
+
+ return rc;
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>NGiCalTests</string>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>org.OpenGroupware.SOPE.ical.NGiCalTests</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string></string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>4.5</string>
+</dict>
+</plist>
--- /dev/null
+This folder contains unit tests for the NGiCal project.
+
+It uses SEN:TE's OCUnit project which can be found at
+http://www.sente.ch/software/ocunit/
+
+I used OCUnitRoot v38, later versions might work as well.
+
+NOTE: This is currently provided in Xcode only.
\ No newline at end of file
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#ifndef __NGiCalTests_common_H__
+#define __NGiCalTests_common_H__
+
+#import <Foundation/Foundation.h>
+#import <SenTestingKit/SenTestingKit.h>
+#include <NGExtensions/NGExtensions.h>
+#include <NGExtensions/NGCalendarDateRange.h>
+
+#endif /* __NGiCalTests_common_H__ */
--- /dev/null
+/*
+ Copyright (C) 2000-2005 SKYRIX Software AG
+
+ This file is part of SOPE.
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "common.h"
+
+@class NGCalendarDateRange;
+@class iCalRecurrenceRule;
+
+@interface iCalRecurrenceCalculatorTests : SenTestCase
+{
+ NSTimeZone *gmt;
+ NGCalendarDateRange *fir;
+ NGCalendarDateRange *tr1;
+ NGCalendarDateRange *dr1;
+}
+
+- (iCalRecurrenceRule *)ruleWithICalString:(NSString *)_rule;
+
+@end
+
+#include "iCalRecurrenceRule.h"
+#include "iCalRecurrenceCalculator.h"
+
+@implementation iCalRecurrenceCalculatorTests
+
+/* Setup / Teardown */
+
+- (void)setUp {
+ NSCalendarDate *sd, *ed;
+
+ gmt = [[NSTimeZone timeZoneForSecondsFromGMT:0] retain];
+
+ sd = [NSCalendarDate dateWithYear:2005
+ month:2
+ day:6
+ hour:12
+ minute:0
+ second:0
+ timeZone:self->gmt];
+ ed = [NSCalendarDate dateWithYear:2005
+ month:2
+ day:6
+ hour:15
+ minute:30
+ second:0
+ timeZone:self->gmt];
+
+ self->fir = [[NGCalendarDateRange calendarDateRangeWithStartDate:sd
+ endDate:ed] retain];
+
+ sd = [NSCalendarDate dateWithYear:2005
+ month:2
+ day:11
+ hour:0
+ minute:0
+ second:0
+ timeZone:self->gmt];
+ ed = [NSCalendarDate dateWithYear:2005
+ month:2
+ day:13
+ hour:23
+ minute:59
+ second:59
+ timeZone:self->gmt];
+
+ self->tr1 = [[NGCalendarDateRange calendarDateRangeWithStartDate:sd
+ endDate:ed] retain];
+
+
+ sd = [NSCalendarDate dateWithYear:2005
+ month:2
+ day:6
+ hour:0
+ minute:0
+ second:0
+ timeZone:self->gmt];
+ ed = [NSCalendarDate dateWithYear:2005
+ month:2
+ day:13
+ hour:23
+ minute:59
+ second:59
+ timeZone:self->gmt];
+
+ self->dr1 = [[NGCalendarDateRange calendarDateRangeWithStartDate:sd
+ endDate:ed] retain];
+}
+
+- (void)tearDown {
+ [self->gmt release];
+ [self->fir release];
+ [self->tr1 release];
+ [self->dr1 release];
+}
+
+/* Private Helper */
+
+- (iCalRecurrenceRule *)ruleWithICalString:(NSString *)_rule {
+ iCalRecurrenceRule *rule;
+
+ rule = [[[iCalRecurrenceRule alloc] init] autorelease];
+ [rule setRrule:_rule];
+ return rule;
+}
+
+- (void)testUnboundDailyRecurrence {
+ iCalRecurrenceRule *rule;
+ iCalRecurrenceCalculator *calc;
+ BOOL result;
+
+ /* recurrence occurs within range, 02/14/2005 */
+ rule = [self ruleWithICalString:@"FREQ=DAILY;INTERVAL=2"];
+ calc = [iCalRecurrenceCalculator recurrenceCalculatorForRecurrenceRule:rule
+ withFirstInstanceCalendarDateRange:fir];
+ result = [calc doesRecurrWithinCalendarDateRange:self->tr1];
+ STAssertTrue(result, @"missed recurrence!");
+
+ /* recurrence outside of range */
+ rule = [self ruleWithICalString:@"FREQ=DAILY;INTERVAL=4"];
+ calc = [iCalRecurrenceCalculator recurrenceCalculatorForRecurrenceRule:rule
+ withFirstInstanceCalendarDateRange:fir];
+ result = [calc doesRecurrWithinCalendarDateRange:self->tr1];
+
+ STAssertFalse(result, @"recurrence unexpected!");
+}
+
+- (void)testBoundDailyRecurrence {
+ iCalRecurrenceRule *rule;
+ iCalRecurrenceCalculator *calc;
+ BOOL result;
+ NSArray *ranges;
+
+ /* recurrence outside of range */
+ rule = [self ruleWithICalString:@"FREQ=DAILY;INTERVAL=2;COUNT=2"];
+ calc = [iCalRecurrenceCalculator recurrenceCalculatorForRecurrenceRule:rule
+ withFirstInstanceCalendarDateRange:fir];
+ result = [calc doesRecurrWithinCalendarDateRange:self->tr1];
+ STAssertFalse(result, @"recurrence!");
+
+ /* recurrence within range */
+ rule = [self ruleWithICalString:@"FREQ=DAILY;INTERVAL=2;UNTIL=20050212T120000Z"];
+ calc = [iCalRecurrenceCalculator recurrenceCalculatorForRecurrenceRule:rule
+ withFirstInstanceCalendarDateRange:fir];
+ result = [calc doesRecurrWithinCalendarDateRange:self->tr1];
+ STAssertTrue(result, @"didn't spot expected recurrence!");
+ ranges = [calc recurrenceRangesWithinCalendarDateRange:self->tr1];
+ STAssertTrue([ranges count] == 1, @"didn't spot expected recurrence!");
+ ranges = [calc recurrenceRangesWithinCalendarDateRange:self->dr1];
+ STAssertTrue([ranges count] == 4, @"didn't spot expected recurrence!");
+}
+
+
+- (void)testBoundWeeklyRecurrence {
+ iCalRecurrenceRule *rule;
+ iCalRecurrenceCalculator *calc;
+ BOOL result;
+
+ /* recurrence outside of range */
+ rule = [self ruleWithICalString:@"FREQ=WEEKLY;INTERVAL=1;UNTIL=20050210T225959Z;BYDAY=WE;WKST=MO"];
+ calc = [iCalRecurrenceCalculator recurrenceCalculatorForRecurrenceRule:rule
+ withFirstInstanceCalendarDateRange:fir];
+ result = [calc doesRecurrWithinCalendarDateRange:self->tr1];
+ STAssertFalse(result, @"recurrence!");
+
+ /* recurrence outside of range */
+ rule = [self ruleWithICalString:@"FREQ=WEEKLY;INTERVAL=1;COUNT=3;BYDAY=WE"];
+ calc = [iCalRecurrenceCalculator recurrenceCalculatorForRecurrenceRule:rule
+ withFirstInstanceCalendarDateRange:fir];
+ result = [calc doesRecurrWithinCalendarDateRange:self->tr1];
+ STAssertFalse(result, @"recurrence!");
+}
+
+@end
--- /dev/null
+Max Berger <max@berger.name>
+Marcus Mueller <znek@mulle-kybernetik.com>
--- /dev/null
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+\f
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
--- /dev/null
+Copyright (C) 2003-2004 Max Berger <max@berger.name>
+Copyright (C) 2004 OpenGroupware.org
+
+Contact: info@opengroupware.org
--- /dev/null
+2006-07-04 Helge Hess <helge.hess@opengroupware.org>
+
+ * use %p for pointer formats, fixed gcc 4.1 warnings (v4.5.24)
+
+2006-04-21 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * GNUmakefile: properly declare principal class (v4.5.23)
+
+2006-04-08 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * VSSaxDriver.m: improved error reporting in case no data could be
+ retrieved from a URL (v4.5.22)
+
+2005-12-05 Helge Hess <helge.hess@skyrix.com>
+
+ * v4.5.21
+
+ * VSSaxDriver.m: added some debug logs, throw an error if a tagline
+ starts with a colon/semicolon (tagname missing)
+
+ * VSvCardSaxDriver.m: minor code cleanups
+
+2005-11-17 Helge Hess <helge.hess@opengroupware.org>
+
+ * VSSaxDriver.m: renamed internal -error: method to -reportError: to
+ avoid a conflict with gstep-base (v4.5.20)
+
+2005-09-28 Helge Hess <helge.hess@opengroupware.org>
+
+ * GNUmakefile.preamble: install bundle in proper SaxObjC framework
+ location (v4.5.19)
+
+2005-08-16 Helge Hess <helge.hess@opengroupware.org>
+
+ * install into /Library/SaxDrivers-4.5 when compiling for frameworks
+ (v4.5.18)
+
+ * GNUmakefile.preamble: added support for OSX frameworks (v4.5.17)
+
+2005-06-02 Helge Hess <helge.hess@skyrix.com>
+
+ * VSSaxDriver.m: transparently decode property values if
+ ENCODING=QUOTED-PRINTABLE is set as an attribute (used by Outlook
+ vCards, needs testing against umlauts/charsets) (v4.5.16)
+
+2005-05-06 Helge Hess <helge.hess@opengroupware.org>
+
+ * VSSaxDriver.m: more reorganisations, added support for groupings
+ (v4.5.15)
+
+2005-05-05 Helge Hess <helge.hess@opengroupware.org>
+
+ * VSSaxDriver.m: code cleanups / reorgs, properly embed reported
+ contents in <vCardSet> tag, added support for vCards in Unicode
+ 16-bit encoding (v4.5.14)
+
+ * VSSaxDriver.m: improved parsing entry methods, added support for SAX
+ error handlers (v4.5.13)
+
+2005-04-25 Helge Hess <helge.hess@opengroupware.org>
+
+ * VSSaxDriver.m: fixed a gcc 4.0 warning (v4.5.12)
+
+2004-12-14 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * versitSaxDriver.xcode: minor changes and updated
+
+2004-10-20 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * VSSaxDriver.m: fixed edge case problem introduced in v4.3.10
+ (v4.3.11)
+
+ * VSSaxDriver.m: remove surrounding double quotes from attribute values
+ if any. During parsing, check if end tags match expectations and
+ issue warnings if they don't. Added some logic to get parsing
+ straight nevertheless in such events. (v4.3.10)
+
+2004-10-19 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.3.9
+
+ * VSSaxDriver.m: improved robustness in respect to illegal content
+ lines - the parser shouldn't crash anymore. Also, changed the
+ "OGoDebugVersitSaxDriver" default to "VSSaxDriverDebugEnabled".
+
+ * README: documented the default
+
+2004-10-18 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v4.3.8
+
+ * VSSaxDriver.m: added support in _parseString: for Unix style
+ terminated content lines. Such content lines clearly violate the
+ RFC but such ical files happen to appear in the wildlife.
+
+ * README: updated
+
+ * v4.3.7
+
+ * Version: removed major and minor. This effectively bumps the version
+ to v4.3.7 which is in sync with the rest of sope-ical.
+
+2004-10-17 Helge Hess <helge.hess@opengroupware.org>
+
+ * added fhs.make, some other minor fixes to makefiles (v1.0.6)
+
+2004-10-16 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v1.0.5
+
+ * VSSaxDriver.m: rewrote _parseLine: to properly parse content lines
+ according to RFC2445.
+
+ * README: updated
+
+ * v1.0.4
+
+ * VSStringFormatter.m: properly unescape '\N'
+
+ * README: updated, need to fix _parseLine:
+
+ * v1.0.3
+
+ * VSStringFormatter.[hm]: new singleton to perform unescaping on
+ iCal content/attributes.
+
+ * VSSaxDriver.m: uses the new VSStringFormatter in some funky places.
+ Unescaping is pretty memory efficient, hence its slight overuse is
+ justifyable I guess.
+
+2004-10-15 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * GNUmakefile.preamble: NGExtensions was missing for proper inline
+ compilation to work (v1.0.2)
+
+ * v1.0.1
+
+ * README: corrected the examples
+
+ * GNUmakefile.preamble: properly add paths
+
+2004-10-14 Marcus Mueller <znek@mulle-kybernetik.com>
+
+ * v1.0.0
+
+ * README, COPYRIGHT, COPYING, AUTHORS: new files
+
+ * VersitSaxDriver.[hm]: renamed to VSSaxDriver.[hm]
+
+ * ICalendarSaxDriver.[hm]: renamed to VSiCalSaxDriver.[hm]
+
+ * VCardSaxDriver.[hm]: renamed to VSvCardSaxDriver.[hm]
+
+ * ICalendarSaxDriver.[hm]: renamed to VSiCalSaxDriver.[hm]
+
+ * VSSaxDriver.m: Major cleanups, cache all character sets as class
+ variables, rewrote _parseString: to properly do unfolding. Bugfixes.
+
+ * VSiCalSaxDriver.m, VSvCardSaxDriver.m: cache character sets, cleanup,
+ minor fixes.
+
+ * bundle-info.plist: adjusted names
+
+2004-04-09 Max Berger <max@berger.name>
+
+ * fixed another bug related to libFoundation that applied to
+ NSMutableCharacterSet (v0.1.18)
+
+2004-02-24 Max Berger <max@berger.name>
+
+ * fixed bug to crash on libFoundation in scanner line (v0.1.17)
+
+2004-02-25 Helge Hess <helge.hess@skyrix.com>
+
+ * v0.1.16
+
+ * GNUmakefile.preamble: properly link with OGo gstep-make
+
+ * added a common.h file (and use that in the source files)
+
+ * VersitSaxDriver.m: fixed type, fixed a "==" vs "=" bug in -init,
+ minor code cleanups
+
+2004-02-24 Max Berger <max@berger.name>
+
+ * v0.1.15
+
+ * added new initialize function to check for debug property
+
+ * added debug messages to parseFromSource
+
+ * updated Copyright in VersitSaxDriver.m
+
+2003-12-13 Max Berger <max@berger.name>
+
+ * replaces commas by spaces in attrs (as in spec) (v0.1.15)
+
+2003-12-13 Max Berger <max@berger.name>
+
+ * v0.1.14
+
+ * added support for apple item1.adr elements
+
+ * added support for multiple attributes of same type
+
+
+2003-12-12 Max Berger <max@berger.name>
+
+ * added support for subitems, added subitems for ical and vcard (v0.1.13)
+
+2003-12-12 Max Berger <max@berger.name>
+
+ * added mappings into vcard driver (v0.1.12)
+
+2003-12-11 Max Berger <max@berger.name>
+
+ * collapsed drivers for vcard 21 and 30 (v0.1.11)
+
+2003-12-11 Max Berger <max@berger.name>
+
+ * fixed range check (v0.1.10)
+
+2003-12-11 Max Berger <max@berger.name>
+
+ * fixed another missing () in malloc (v0.1.9)
+
+2003-12-11 Max Berger <max@berger.name>
+
+ * fixed a missing () in malloc (v0.1.8)
+
+2003-12-11 Helge Hess <helge.hess@opengroupware.org>
+
+ * v0.1.7
+
+ * minor tweaks to sourcecode style ;-)
+
+ * created GNUmakefile's
+
+2003-11-23 Max Berger <max@berger.name>
+
+ * v0.1.6
+
+ * added GNUmakefile for unix
+
+ * fixed bundle-info.plist
+
+ * fixed a bug that caused libFondation to crash
+
+2003-11-23 Max Berger <max@berger.name>
+
+ * v0.1.5
+
+ * Implemented attribute mapping
+
+ * Added list of attributes for xcal
+
+2003-11-23 Max Berger <max@berger.name>
+
+ * v0.1.4
+
+ * implemented handling via list and stack
+
+ * added support for name mapping and mapping to attributes
+
+ * added complete iCalendar Name mapping
+
+2003-11-23 Max Berger <max@berger.name>
+
+ * v0.1.3
+
+ * VersitSaxDriver.m: Split up in lines works correctly
+
+ * VersitSaxDriver: added support for contentHandler
+
+ * VersitSaxDriver: added support for namespace
+
+ * VersitSaxDriver: now has begin/end document
+
+ * ICalendarSaxDriver: now set correct namespace
+
+ * VersitSaxDriver: now parses Tags, attibutes and values
+
+2003-11-23 Max Berger <max@berger.name>
+
+ * v0.1.2
+
+ * fixed Copyright notice
+
+ * added Data Retrieval
+
+ * added unfold method (doesnt do anything yet)
+
+2003-11-23 Max Berger <max@berger.name>
+
+ * Initial Version (v0.1.1)
--- /dev/null
+# GNUstep makefile
+
+-include ../../../config.make
+include $(GNUSTEP_MAKEFILES)/common.make
+-include ./Version
+
+BUNDLE_NAME = versitCardsSaxDriver
+BUNDLE_EXTENSION = .sax
+BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/SaxDrivers-$(MAJOR_VERSION).$(MINOR_VERSION)/
+
+versitCardsSaxDriver_PRINCIPAL_CLASS = VSSaxDriver
+
+versitCardsSaxDriver_PCH_FILE = common.h
+
+versitCardsSaxDriver_OBJC_FILES = \
+ VSSaxDriver.m \
+ VSCardSaxDriver.m \
+ VSStringFormatter.m \
+
+versitCardsSaxDriver_RESOURCE_FILES = bundle-info.plist
+
+-include GNUmakefile.preamble
+include $(GNUSTEP_MAKEFILES)/bundle.make
+-include GNUmakefile.postamble
+include fhs.make
--- /dev/null
+# $Id: GNUmakefile.postamble 257 2004-10-14 21:01:23Z znek $
+
+after-all ::
+ @(cp bundle-info.plist \
+ $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
--- /dev/null
+# compilation settings
+
+SOPE_ROOT=../..
+SOPE_OBJ_ROOT=$(GNUSTEP_BUILD_DIR)/$(SOPE_ROOT)
+
+ifeq ($(frameworks),yes)
+# hm, we might prefer /Library/SaxDrivers-$(MAJOR_VERSION).$(MINOR_VERSION)/
+# but this is harder with the FRAMEWORK_INSTALL_DIR
+BUNDLE_INSTALL_DIR := $(FRAMEWORK_INSTALL_DIR)/SaxObjC.framework/Versions/A/Resources/SaxDrivers/
+endif
+
+
+ADDITIONAL_INCLUDE_DIRS += \
+ -I../.. \
+ -I$(SOPE_ROOT)/sope-xml \
+ -I$(SOPE_ROOT)/sope-core/NGExtensions
+
+
+# dependencies
+
+ifneq ($(frameworks),yes)
+BUNDLE_LIBS += -lSaxObjC
+else
+BUNDLE_LIBS += -framework SaxObjC
+endif
+ADDITIONAL_BUNDLE_LIBS += $(BUNDLE_LIBS)
+
+
+# library/framework search pathes
+
+DEP_DIRS = \
+ $(SOPE_ROOT)/sope-core/NGExtensions \
+ $(SOPE_ROOT)/sope-xml/SaxObjC
+
+ifneq ($(frameworks),yes)
+ADDITIONAL_LIB_DIRS += \
+ $(foreach dir,$(DEP_DIRS),\
+ -L$(GNUSTEP_BUILD_DIR)/$(dir)/$(GNUSTEP_OBJ_DIR_NAME))
+else
+ADDITIONAL_LIB_DIRS += \
+ $(foreach dir,$(DEP_DIRS),-F$(GNUSTEP_BUILD_DIR)/$(dir))
+endif
+
+ifeq ($(findstring _64, $(GNUSTEP_TARGET_CPU)), _64)
+SYSTEM_LIB_DIR += -L/usr/local/lib64 -L/usr/lib64
+else
+SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
+endif
--- /dev/null
+Overview
+========
+
+Two SaxObjC drivers for iCalendar and vCard files, initially written by
+Max Berger <max@berger.name>.
+
+VSiCalSaxDriver basically maps iCal 2.0 components, properties and parameters
+to the XML events according to the xCal 02 draft (iCal 3.0).
+
+Having a SAX driver for iCal might seem strange and a bit inefficient at
+first look, but the time saved for the application-level developer is
+significant, since he only needs to learn (or usually already knows) the
+SAX or DOM APIs and any XML API based on them (like XPATH, XQUERY).
+
+The VSiCalSaxDriver is aimed to be a replacement for the older (but better
+tested as of now) iCalSaxDriver. However, the iCalSaxDriver depends on the
+abandoned and hardly maintainable libical, which itself is an additional
+dependency to the OGo project and thus a welcome candidate for replacement.
+
+The VSSaxDriver attempts to follow RFC2445 closely, however the parser is
+written to be robust when it comes to parsing real life content. Currently,
+unescaping is done for more characters then it MUST according to RFC2445, but
+this is probably not a bad idea - wrongly escaped characters will still be
+parsed according to the original intent. Also, the VSSaxDriver supports Unix
+style terminated lines/folding.
+
+ToDo
+====
+
+- improve error handling (SaxExceptions !)
+- make the driver fully xCal compliant
+
+
+Defaults
+========
+
+Name Type Description
+------------------------------------------------------------------------------
+VSSaxDriverDebugEnabled BOOL YES -> log some debug information
+ via NSLog
+
+
+Examples
+========
+
+To "convert" an iCalendar to xCal (the test programs print out some XML):
+
+ saxxml -XMLReader VSiCalSaxDriver test1.ics
+ domxml -XMLReader VSiCalSaxDriver -xml test1.ics
+
+To "convert" an iCalendar to PYX:
+
+ domxml -XMLReader VSiCalSaxDriver -pyx test1.ics
--- /dev/null
+/*
+ Copyright (C) 2003-2004 Max Berger
+ Copyright (C) 2004-2005 OpenGroupware.org
+
+ This file is part of versitCardsSaxDriver, written for the OpenGroupware.org
+ project (OGo).
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+ */
+
+#ifndef __versitCardsSaxDriver_VSCardSaxDriver_H__
+#define __versitCardsSaxDriver_VSCardSaxDriver_H__
+
+#include "VSSaxDriver.h"
+
+// TODO: photo is reported incorrectly
+
+@interface VSCardSaxDriver : VSSaxDriver
+{
+}
+
+@end
+
+#endif /* __versitCardsSaxDriver_VSCardSaxDriver_H__ */
--- /dev/null
+/*
+ Copyright (C) 2003-2004 Max Berger
+ Copyright (C) 2004-2005 OpenGroupware.org
+
+ This file is part of versitCardsSaxDriver, written for the OpenGroupware.org
+ project (OGo).
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "VSCardSaxDriver.h"
+#include "common.h"
+
+#define XMLNS_VSvCard \
+ @"http://www.ietf.org/internet-drafts/draft-dawson-vcard-xml-dtd-03.txt"
+
+@implementation VSCardSaxDriver
+
+static NSSet *defElementNames = nil;
+
++ (void)initialize {
+ static BOOL didInit = NO;
+
+ if(didInit)
+ return;
+ didInit = YES;
+
+ defElementNames = [[NSSet alloc] initWithObjects:
+ @"class", @"prodid", @"rev", @"uid", @"version", nil];
+}
+
+- (id)init {
+ if ((self = [super init]) != nil) {
+ [self setPrefixURI:XMLNS_VSvCard];
+// [self setElementMapping:[[self class] xcardMapping]];
+// [self setAttributeElements:defElementNames];
+ }
+ return self;
+}
+
+/* top level parsing method */
+
+- (void)reportDocStart {
+ [super reportDocStart];
+
+ [self->contentHandler startElement:@"vCardSet" namespace:self->prefixURI
+ rawName:@"vCardSet" attributes:nil];
+}
+- (void)reportDocEnd {
+ [self->contentHandler endElement:@"vCardSet" namespace:self->prefixURI
+ rawName:@"vCardSet"];
+
+ [super reportDocEnd];
+}
+
+@end /* VCardSaxDriver */
--- /dev/null
+/*
+ Copyright (C) 2003-2004 Max Berger
+ Copyright (C) 2004-2005 OpenGroupware.org
+
+ This file is part of versitCardsSaxDriver, written for the OpenGroupware.org
+ project (OGo).
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+ */
+
+#ifndef __versitCardsSaxDriver_VSSaxDriver_H__
+#define __versitCardsSaxDriver_VSSaxDriver_H__
+
+#import <Foundation/NSObject.h>
+#include <SaxObjC/SaxXMLReader.h>
+
+@class NSString, NSSet, NSDictionary, NSMutableArray, NSMutableDictionary;
+
+@interface VSSaxDriver : NSObject < SaxXMLReader >
+{
+ id<NSObject,SaxContentHandler> contentHandler;
+ id<NSObject,SaxErrorHandler> errorHandler;
+ NSString *prefixURI;
+ NSMutableArray *cardStack;
+ NSMutableArray *elementList; /* a list of tags to be rep. */
+
+ NSSet *attributeElements;
+}
+
+- (void)setPrefixURI:(NSString*)_uri;
+- (NSString *)prefixURI;
+
+/* events */
+
+- (void)reportDocStart;
+- (void)reportDocEnd;
+
+@end
+
+#endif /* __versitCardsSaxDriver_VersitCardsSaxDriver_H__ */
--- /dev/null
+/*
+ Copyright (C) 2003-2004 Max Berger
+ Copyright (C) 2004-2005 OpenGroupware.org
+
+ This file is part of versitCardsSaxDriver, written for the OpenGroupware.org
+ project (OGo).
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+/* FIXME: this class is badly designed. It is expected to feed
+ NGVCardSaxHandler with correct values but it won't handle escaped
+ commas. Also, it should handle CardGroups and CardElements
+ correctly: treat the former as open/close tags and the latter as
+ simple tags. Wrt that, the methods startGroupElement/endGroupElement
+ are not expected in a sax handler... this is all wrong. */
+
+#import "VSSaxDriver.h"
+#import "VSStringFormatter.h"
+#import <SaxObjC/SaxException.h>
+#import <NGExtensions/NGQuotedPrintableCoding.h>
+#import <NGCards/NSString+NGCards.h>
+#import "common.h"
+
+@interface VSSaxTag : NSObject
+{
+@private;
+ char type;
+ NSString *tagName;
+ NSString *group;
+@public;
+ SaxAttributes *attrs;
+ unichar *data;
+ unsigned int datalen;
+ BOOL groupElement;
+}
+
++ (id) beginTag: (NSString *) _tag
+ group: (NSString *) _group
+ attributes: (SaxAttributes *) _attrs;
+- (id) initEndTag: (NSString *) _tag;
+
+- (id) initWithContentString: (NSString *) _data;
+- (void) setGroupElement: (BOOL) aBool;
+
+- (NSString *) tagName;
+- (NSString *) group;
+- (BOOL) isStartTag;
+- (BOOL) isEndTag;
+- (BOOL) isTag;
+
+@end
+
+@implementation VSSaxTag
+
++ (id) beginTag: (NSString *) _tag
+ group: (NSString *) _group
+ attributes: (SaxAttributes *) _attrs
+{
+ VSSaxTag *tag;
+
+ tag = [[self new] autorelease];
+ tag->type = 'B';
+ tag->tagName = [_tag copy];
+ tag->group = [_group copy];
+ tag->attrs = [_attrs retain];
+
+ return tag;
+}
+
+- (id) init
+{
+ if ((self = [super init]))
+ {
+ groupElement = NO;
+ }
+
+ return self;
+}
+
+- (id) initEndTag: (NSString *) _tag
+{
+ type = 'E';
+ tagName = [_tag copy];
+
+ return self;
+}
+
+- (id) initWithContentString: (NSString *) _data
+{
+ if (!_data)
+ {
+ [self release];
+ return nil;
+ }
+
+ datalen = [_data length];
+ data = calloc(datalen + 1, sizeof(unichar));
+ [_data getCharacters: data range: NSMakeRange(0, datalen)];
+ return self;
+}
+
+- (void) setGroupElement: (BOOL) aBool
+{
+ groupElement = aBool;
+}
+
+- (void) dealloc {
+ if (data) free(data);
+ [group release];
+ [tagName release];
+ [attrs release];
+ [super dealloc];
+}
+
+- (char) tagType
+{
+ return type;
+}
+
+/* accessors */
+
+- (NSString *) tagName {
+ return tagName;
+}
+- (NSString *) group {
+ return group;
+}
+
+- (BOOL) isStartTag {
+ return type == 'B' ? YES : NO;
+}
+- (BOOL) isEndTag {
+ return type == 'E' ? YES : NO;
+}
+- (BOOL) isTag {
+ return (type == 'B' || type == 'E') ? YES : NO;
+}
+
+@end /* VSSaxTag */
+
+@implementation VSSaxDriver
+
+static BOOL debugOn = NO;
+
+static NSCharacterSet *dotCharSet = nil;
+static NSCharacterSet *equalSignCharSet = nil;
+static NSCharacterSet *commaCharSet = nil;
+static NSCharacterSet *colonAndSemicolonCharSet = nil;
+static NSCharacterSet *colonSemicolonAndDquoteCharSet = nil;
+static NSCharacterSet *whitespaceCharSet = nil;
+
+static VSStringFormatter *stringFormatter = nil;
+
++ (void) initialize
+{
+ static BOOL didInit = NO;
+ NSUserDefaults *ud;
+
+ if (didInit)
+ return;
+ didInit = YES;
+
+ ud = [NSUserDefaults standardUserDefaults];
+ debugOn = [ud boolForKey: @"VSSaxDriverDebugEnabled"];
+
+ dotCharSet =
+ [[NSCharacterSet characterSetWithCharactersInString: @"."] retain];
+ equalSignCharSet =
+ [[NSCharacterSet characterSetWithCharactersInString: @"="] retain];
+ commaCharSet =
+ [[NSCharacterSet characterSetWithCharactersInString: @","] retain];
+ colonAndSemicolonCharSet =
+ [[NSCharacterSet characterSetWithCharactersInString: @": ;"] retain];
+ colonSemicolonAndDquoteCharSet =
+ [[NSCharacterSet characterSetWithCharactersInString: @": ;\""] retain];
+ whitespaceCharSet =
+ [[NSCharacterSet whitespaceCharacterSet] retain];
+
+ stringFormatter = [VSStringFormatter sharedFormatter];
+}
+
+- (id) init {
+ if ((self = [super init]))
+ {
+ prefixURI = @"";
+ cardStack = [[NSMutableArray alloc] initWithCapacity: 4];
+ elementList = [[NSMutableArray alloc] initWithCapacity: 8];
+ }
+
+ return self;
+}
+
+- (void) dealloc
+{
+ [contentHandler release];
+ [errorHandler release];
+ [prefixURI release];
+ [cardStack release];
+ [elementList release];
+ [super dealloc];
+}
+
+/* accessors */
+
+- (void) setFeature: (NSString *) _name to: (BOOL) _value
+{
+}
+
+- (BOOL) feature: (NSString *) _name
+{
+ return NO;
+}
+
+- (void) setProperty: (NSString *) _name to: (id) _value
+{
+}
+
+- (id) property: (NSString *) _name
+{
+ return nil;
+}
+
+/* handlers */
+
+- (void) setContentHandler: (id<NSObject,SaxContentHandler>) _handler
+{
+ ASSIGN(contentHandler, _handler);
+}
+
+- (void) setDTDHandler: (id<NSObject,SaxDTDHandler>) _handler
+{
+ // FIXME
+}
+
+- (void) setErrorHandler: (id<NSObject,SaxErrorHandler>) _handler
+{
+ ASSIGN(errorHandler, _handler);
+}
+
+- (void) setEntityResolver: (id<NSObject,SaxEntityResolver>) _handler
+{
+ // FIXME
+}
+
+- (id<NSObject,SaxContentHandler>) contentHandler
+{
+ return contentHandler;
+}
+
+- (id<NSObject,SaxDTDHandler>) dtdHandler
+{
+ // FIXME
+ return nil;
+}
+
+- (id<NSObject,SaxErrorHandler>) errorHandler
+{
+ return errorHandler;
+}
+
+- (id<NSObject,SaxEntityResolver>) entityResolver
+{
+ // FIXME
+ return nil;
+}
+
+- (void) setPrefixURI: (NSString *) _uri
+{
+ ASSIGNCOPY(prefixURI, _uri);
+}
+
+- (NSString *) prefixURI
+{
+ return prefixURI;
+}
+
+/* parsing */
+
+- (NSString *) _groupFromTagName: (NSString *) _tagName
+{
+ NSRange r;
+
+ r = [_tagName rangeOfCharacterFromSet: dotCharSet];
+ if (!r.length)
+ return nil;
+
+ return [_tagName substringToIndex: r.location];
+}
+
+- (NSString *) _mapTagName: (NSString *) _tagName
+{
+ NSString *ret;
+ NSRange r;
+
+ //NSLog(@"Unknown Key: %@ in %@",_tagName,elementMapping);
+ ret = _tagName;
+
+ /*
+ This is to allow parsing of vCards produced by Apple
+ Addressbook.
+ The dot-notation is described as 'grouping' in RFC 2425, section 5.8.2.
+ */
+ r = [_tagName rangeOfCharacterFromSet: dotCharSet];
+ if (r.length > 0)
+ ret = [self _mapTagName: [_tagName substringFromIndex: (r.location + 1)]];
+
+ return ret;
+}
+
+- (void) _parseAttr: (NSString *) _attr
+ forTag: (NSString *) _tagName
+ intoAttr: (NSString **) attr_
+ intoValue: (NSString **) value_
+{
+ NSRange r;
+ NSString *attrName, *attrValue;
+
+ r = [_attr rangeOfCharacterFromSet: equalSignCharSet];
+ if (r.length > 0)
+ {
+ unsigned left, right;
+
+ attrName = [[_attr substringToIndex: r.location] uppercaseString];
+ left = NSMaxRange(r);
+ right = [_attr length] - 1;
+ if (left < right)
+ {
+ if (([_attr characterAtIndex: left] == '"') &&
+ ([_attr characterAtIndex: right] == '"'))
+ {
+ left += 1;
+ r = NSMakeRange(left, right - left);
+ attrValue = [_attr substringWithRange: r];
+ }
+ else
+ {
+ attrValue = [_attr substringFromIndex: left];
+ }
+ }
+ else if (left == right)
+ {
+ attrValue = [_attr substringFromIndex: left];
+ }
+ else
+ {
+ attrValue = @"";
+ }
+ }
+ else
+ {
+ if ([[_attr uppercaseString] isEqualToString: @"QUOTED-PRINTABLE"])
+ attrName = @"ENCODING";
+ else
+ attrName = @"TYPE";
+ attrValue = _attr;
+ }
+
+#if 0
+ // ZNeK: what's this for?
+ r = [attrValue rangeOfCharacterFromSet: commaCharSet];
+ while (r.length > 0)
+ {
+ [attrValue replaceCharactersInRange: r withString: @" "];
+ r = [attrValue rangeOfCharacterFromSet: commaCharSet];
+ }
+#endif
+
+ *attr_ = attrName;
+ *value_ = [attrValue unescapedFromCard];
+// *value_ = [stringFormatter stringByUnescapingRFC2445Text: attrValue];
+}
+
+- (SaxAttributes *) _mapAttrs: (NSArray *) _attrs
+ forTag: (NSString *) _tagName
+{
+ SaxAttributes *retAttrs;
+ NSEnumerator *attrEnum, *values;
+ NSString *curAttr, *mappedAttr, *mappedValue, *curValue;
+
+ /*
+ TODO: values are not always mapped to CDATA! Eg in the dawson draft:
+ | TYPE for TEL | tel.type | NMTOKENS | 'VOICE' |
+ | TYPE for EMAIL | email.type | NMTOKENS | 'INTERNET' |
+ | TYPE for PHOTO,| img.type | CDATA | REQUIRED |
+ | and LOGO | | | |
+ | TYPE for SOUND | aud.type | CDATA | REQUIRED |
+ | VALUE | value | NOTATION | See elements |
+ */
+
+ if (_attrs && [_attrs count] > 0)
+ {
+ retAttrs = [[SaxAttributes alloc] init];
+ [retAttrs autorelease];
+
+ attrEnum = [_attrs objectEnumerator];
+ curAttr = [attrEnum nextObject];
+ while (curAttr)
+ {
+ [self _parseAttr: curAttr
+ forTag: _tagName
+ intoAttr: &mappedAttr
+ intoValue: &mappedValue];
+ values = [[mappedValue asCardAttributeValues] objectEnumerator];
+ curValue = [values nextObject];
+ while (curValue)
+ {
+ [retAttrs addAttribute: mappedAttr
+ uri: prefixURI
+ rawName: mappedAttr
+ type: @"CDATA"
+ value: curValue];
+ curValue = [values nextObject];
+ }
+ curAttr = [attrEnum nextObject];
+ }
+ }
+ else
+ retAttrs = nil;
+
+ return retAttrs;
+}
+
+- (VSSaxTag *) _beginTag: (NSString *) _tagName
+ group: (NSString *) _group
+ withAttrs: (SaxAttributes *) _attrs
+{
+ VSSaxTag *tag;
+
+ tag = [VSSaxTag beginTag: [_tagName uppercaseString]
+ group: _group attributes: _attrs];
+ [elementList addObject: tag];
+
+ return tag;
+}
+
+- (void) _endTag: (NSString *) _tagName
+{
+ VSSaxTag *tag;
+
+ tag = [[VSSaxTag alloc] initEndTag: _tagName];
+ [elementList addObject: tag];
+ [tag release]; tag = nil;
+}
+
+- (void) _endGroupElementTag: (NSString *) _tagName
+{
+ VSSaxTag *tag;
+
+ tag = [[VSSaxTag alloc] initEndTag: _tagName];
+ [elementList addObject: tag];
+ [tag setGroupElement: YES];
+ [tag release]; tag = nil;
+}
+
+- (void) _reportContentAsTag: (NSString *) _tagName
+ group: (NSString *) _group
+ withAttrs: (SaxAttributes *) _attrs
+ andContent: (NSString *) _content
+{
+ /*
+ This is called for all non-BEGIN|END types.
+ */
+
+// _content = [stringFormatter stringByUnescapingRFC2445Text: _content];
+
+ /* check whether type should be reported as an attribute in XML */
+
+ [self _beginTag: _tagName group: _group withAttrs: _attrs];
+
+ if ([_content length] > 0)
+ {
+ VSSaxTag *a;
+
+ a = [(VSSaxTag *)[VSSaxTag alloc]
+ initWithContentString: [_content unescapedFromCard]];
+ if (a)
+ {
+ [elementList addObject: a];
+ [a release];
+ }
+ }
+
+ [self _endTag: _tagName];
+}
+
+/* report events for collected elements */
+
+- (void) reportStartGroup: (NSString *) _group
+{
+ SaxAttributes *attrs;
+
+ attrs = [[SaxAttributes alloc] init];
+ [attrs addAttribute: @"name" uri: prefixURI rawName: @"name"
+ type: @"CDATA" value: _group];
+
+ [contentHandler startElement: @"group"
+ namespace: prefixURI
+ rawName: @"group"
+ attributes: attrs];
+ [attrs release];
+}
+
+- (void) reportEndGroup
+{
+ [contentHandler endElement: @"group"
+ namespace: prefixURI
+ rawName: @"group"];
+}
+
+- (void) reportStartContainer: (NSString *) _container
+{
+ SaxAttributes *attrs;
+
+ attrs = [[SaxAttributes alloc] init];
+ [attrs addAttribute: @"name"
+ uri: prefixURI
+ rawName: @"name"
+ type: @"CDATA"
+ value: _container];
+ [contentHandler startElement: @"container"
+ namespace: prefixURI
+ rawName: @"container"
+ attributes: attrs];
+ [attrs release];
+}
+
+- (void) reportEndContainer
+{
+ [contentHandler endElement: @"container"
+ namespace: prefixURI
+ rawName: @"container"];
+}
+
+- (void) reportQueuedTags
+{
+ /*
+ Why does the parser need the list instead of reporting the events
+ straight away?
+
+ Because some vCard tags like the 'version' are reported as attributes
+ on the container tag. So we have a sequence like:
+ BEGIN: VCARD
+ ...
+ VERSION: 3.0
+ which will get reported as:
+ <vcard version="3.0">
+ */
+ NSEnumerator *enu;
+ VSSaxTag *tagToReport;
+ NSString *lastGroup, *tg, *tagName;
+
+ lastGroup = nil;
+
+ enu = [elementList objectEnumerator];
+ tagToReport = [enu nextObject];
+ while (tagToReport)
+ {
+ tagName = [tagToReport tagName];
+
+ if ([tagToReport isStartTag])
+ {
+ tg = [tagToReport group];
+ if (![lastGroup isEqualToString: tg]
+ && lastGroup != tg)
+ {
+ if (lastGroup) [self reportEndGroup];
+ ASSIGNCOPY(lastGroup, tg);
+ if (lastGroup) [self reportStartGroup: lastGroup];
+ }
+ }
+
+ if ([tagToReport isStartTag])
+ {
+ if (tagToReport->groupElement)
+ [self reportStartContainer: tagName];
+ else
+ [contentHandler startElement: tagName
+ namespace: prefixURI
+ rawName: tagName
+ attributes: tagToReport->attrs];
+ }
+ else if ([tagToReport isEndTag])
+ {
+ if (tagToReport->groupElement)
+ [self reportEndContainer];
+ else
+ [contentHandler endElement: tagName
+ namespace: prefixURI
+ rawName: tagName];
+ }
+ else
+ [contentHandler characters: tagToReport->data
+ length: tagToReport->datalen];
+
+ tagToReport = [enu nextObject];
+ }
+
+ /* flush event group */
+ [elementList removeAllObjects];
+
+ /* close open groups */
+ if (lastGroup)
+ {
+ [self reportEndGroup];
+ [lastGroup release];
+ lastGroup = nil;
+ }
+}
+
+/* errors */
+
+- (void) reportError: (NSString *) _text
+{
+ SaxParseException *e;
+
+ e = (id)[SaxParseException exceptionWithName: @"SaxParseException"
+ reason: _text
+ userInfo: nil];
+ [errorHandler error: e];
+}
+
+- (void) warn: (NSString *) _warn
+{
+ SaxParseException *e;
+
+ e = (id)[SaxParseException exceptionWithName: @"SaxParseException"
+ reason: _warn
+ userInfo: nil];
+ [errorHandler warning: e];
+}
+
+/* parsing raw string */
+
+- (void) _beginComponentWithValue: (NSString *) tagValue
+{
+ VSSaxTag *tag;
+
+ tag = [self _beginTag: [self _mapTagName: tagValue]
+ group: nil
+ withAttrs: [[[SaxAttributes alloc] init] autorelease]];
+ [tag setGroupElement: YES];
+ [cardStack addObject: tag];
+}
+
+- (void) _endComponent: (NSString *) tagName
+ value: (NSString *) tagValue
+{
+ NSString *mtName;
+
+ mtName = [[self _mapTagName: tagValue] uppercaseString];
+ if ([cardStack count] > 0)
+ {
+ NSString *expectedName;
+
+ expectedName = [(VSSaxTag *)[cardStack lastObject] tagName];
+ if (![expectedName isEqualToString: mtName])
+ {
+ NSString *s;
+
+ // TODO: rather report an error?
+ // TODO: setup userinfo dict with details
+ s = [NSString stringWithFormat:
+ @"Found end tag '%@' which does not match expected "
+ @"name '%@'!"
+ @" Tag '%@' has not been closed properly. Given "
+ @"document contains errors!",
+ mtName, expectedName, expectedName];
+ [self reportError: s];
+
+ /* probably futile attempt to parse anyways */
+ if (debugOn)
+ {
+ NSLog(@"%s trying to fix previous error by inserting bogus end "
+ @"tag.",
+ __PRETTY_FUNCTION__);
+ }
+ [self _endGroupElementTag: expectedName];
+ [cardStack removeLastObject];
+ }
+ }
+ else
+ {
+ // TOOD: generate error?
+ [self reportError: [@"found end tag without any open tags left: "
+ stringByAppendingString: mtName]];
+ }
+ [self _endGroupElementTag: mtName];
+ [cardStack removeLastObject];
+
+ /* report parsed elements */
+
+ if ([cardStack count] == 0)
+ [self reportQueuedTags];
+}
+
+- (void) _parseLine: (NSString *) _line
+{
+ NSString *tagName, *tagValue;
+ NSMutableArray *tagAttributes;
+ NSRange r, todoRange;
+ unsigned length;
+
+#if 0
+ if (debugOn)
+ NSLog(@"%s: parse line: '%@'", __PRETTY_FUNCTION__, _line);
+#endif
+
+ length = [_line length];
+ todoRange = NSMakeRange(0, length);
+ r = [_line rangeOfCharacterFromSet: colonAndSemicolonCharSet
+ options: 0
+ range: todoRange];
+ /* is line well-formed? */
+ if (!r.length || !r.location)
+ {
+#if 0
+ NSLog(@"todo-range: %i-%i, range: %i-%i, length %i, str-class %@",
+ todoRange.location, todoRange.length,
+ r.location, r.length,
+ length, NSStringFromClass([_line class]));
+#endif
+
+ [self reportError:
+ [@"got an improper content line! (did not find colon) ->\n"
+ stringByAppendingString: _line]];
+ return;
+ }
+
+ /* tagname is everything up to a ': ' or ';' (value or parameter) */
+ tagName = [[_line substringToIndex: r.location] uppercaseString];
+ tagAttributes = [[NSMutableArray alloc] initWithCapacity: 16];
+
+ if (debugOn && ([tagName length] == 0))
+ {
+ [self reportError: [@"got an improper content line! ->\n"
+ stringByAppendingString: _line]];
+ return;
+ }
+
+ /*
+ possible shortcut: if we spotted a ': ', we don't have to do "expensive"
+ argument scanning/processing.
+ */
+ if ([_line characterAtIndex: r.location] != ':')
+ {
+ BOOL isAtEnd = NO;
+ BOOL isInDquote = NO;
+ unsigned start;
+
+ start = NSMaxRange(r);
+ todoRange = NSMakeRange(start, length - start);
+ while(!isAtEnd)
+ {
+ BOOL skip = YES;
+
+ /* scan for parameters */
+ r = [_line rangeOfCharacterFromSet: colonSemicolonAndDquoteCharSet
+ options: 0
+ range: todoRange];
+
+ /* is line well-formed? */
+ if (!r.length || !r.location)
+ {
+ [self reportError: [@"got an improper content line! ->\n"
+ stringByAppendingString: _line]];
+ [tagAttributes release]; tagAttributes = nil;
+ return;
+ }
+
+ /* first check if delimiter candidate is escaped */
+ if ([_line characterAtIndex: (r.location - 1)] != '\\')
+ {
+ unichar delimiter;
+ NSRange copyRange;
+
+ delimiter = [_line characterAtIndex: r.location];
+ if (delimiter == '\"')
+ {
+ /* not a real delimiter - toggle isInDquote for proper escaping */
+ isInDquote = !isInDquote;
+ }
+ else
+ {
+ if (!isInDquote)
+ {
+ /* is a delimiter, which one? */
+ skip = NO;
+ if (delimiter == ':')
+ {
+ isAtEnd = YES;
+ }
+ copyRange = NSMakeRange(start, r.location - start);
+ [tagAttributes addObject: [_line substringWithRange: copyRange]];
+ if (!isAtEnd)
+ {
+ /* adjust start, todoRange */
+ start = NSMaxRange(r);
+ todoRange = NSMakeRange(start, length - start);
+ }
+ }
+ }
+ }
+ if (skip)
+ {
+ /* adjust todoRange */
+ unsigned offset = NSMaxRange(r);
+ todoRange = NSMakeRange(offset, length - offset);
+ }
+ }
+ }
+ tagValue = [_line substringFromIndex: NSMaxRange(r)];
+
+ if (debugOn && ([tagName length] == 0))
+ {
+ NSLog(@"%s: missing tagname in line: '%@'",
+ __PRETTY_FUNCTION__, _line);
+ }
+
+ /*
+ At this point we have:
+ name: 'BEGIN', 'TEL', 'EMAIL', 'ITEM1.ADR' etc
+ value: ';;;Magdeburg;;;Germany'
+ attributes: ("type=INTERNET", "type=HOME", "type=pref")
+ */
+
+#if 0
+# warning DEBUG LOG ENABLED
+ NSLog(@"TAG: %@, value %@ attrs %@",
+ tagName, tagValue, tagAttributes);
+#endif
+
+ /* process tag */
+
+ if ([tagName isEqualToString: @"BEGIN"])
+ {
+ if ([tagAttributes count] > 0)
+ [self warn: @"Losing unexpected parameters of BEGIN line."];
+ [self _beginComponentWithValue: tagValue];
+ }
+ else if ([tagName isEqualToString: @"END"])
+ {
+ if ([tagAttributes count] > 0)
+ [self warn: @"Losing unexpected parameters of END line."];
+ [self _endComponent: tagName value: tagValue];
+ }
+ else
+ {
+ /* a regular content tag */
+
+ /*
+ check whether the tga value is encoded in quoted printable,
+ this one is used with Outlook vCards (see data/ for examples)
+ */
+ // TODO: make the encoding check more generic
+ if ([tagAttributes containsObject: @"ENCODING=QUOTED-PRINTABLE"])
+ {
+ // TODO: QP is charset specific! The one below decodes in Unicode!
+ tagValue = [tagValue stringByDecodingQuotedPrintable];
+ [tagAttributes removeObject: @"ENCODING=QUOTED-PRINTABLE"];
+ }
+
+ [self _reportContentAsTag: [self _mapTagName: tagName]
+ group: [self _groupFromTagName: tagName]
+ withAttrs: [self _mapAttrs: tagAttributes forTag: tagName]
+ andContent: tagValue];
+ }
+
+ [tagAttributes release];
+}
+
+
+/* top level parsing method */
+
+- (void) reportDocStart
+{
+ [contentHandler startDocument];
+ [contentHandler startPrefixMapping: @"" uri: prefixURI];
+}
+
+- (void) reportDocEnd
+{
+ [contentHandler endPrefixMapping: @""];
+ [contentHandler endDocument];
+}
+
+- (void) _parseString: (NSString *) _rawString
+{
+ /*
+ This method split the string into content lines for actual vCard
+ parsing.
+
+ RFC2445:
+ contentline = name *(";" param ) ": " value CRLF
+ ; When parsing a content line, folded lines MUST first
+ ; be unfolded
+ */
+ NSMutableString *line;
+ unsigned pos, length;
+ NSRange r;
+
+ [self reportDocStart];
+
+ /* start parsing */
+
+ length = [_rawString length];
+ r = NSMakeRange(0, 0);
+ line = [[NSMutableString alloc] initWithCapacity: 75 + 2];
+
+ for (pos = 0; pos < length; pos++)
+ {
+ unichar c;
+
+ c = [_rawString characterAtIndex: pos];
+
+ if (c == '\r')
+ {
+ if (((length - 1) - pos) >= 1)
+ {
+ if ([_rawString characterAtIndex: pos + 1] == '\n')
+ {
+ BOOL isAtEndOfLine = YES;
+
+ /* test for folding first */
+ if (((length - 1) - pos) >= 2)
+ {
+ unichar ws;
+
+ ws = [_rawString characterAtIndex: pos + 2];
+ isAtEndOfLine = [whitespaceCharSet characterIsMember: ws] ? NO : YES;
+ if (!isAtEndOfLine)
+ {
+ /* assemble part of line up to pos */
+ if (r.length > 0)
+ {
+ [line appendString: [_rawString substringWithRange: r]];
+ }
+ /* unfold */
+ pos += 2;
+ r = NSMakeRange(pos + 1, 0); /* begin new range */
+ }
+ }
+ if (isAtEndOfLine)
+ {
+ /* assemble part of line up to pos */
+ if (r.length > 0)
+ {
+ [line appendString: [_rawString substringWithRange: r]];
+ }
+ [self _parseLine: line];
+ /* reset line */
+ [line deleteCharactersInRange: NSMakeRange(0, [line length])];
+ pos += 1;
+ r = NSMakeRange(pos + 1, 0); /* begin new range */
+ }
+ }
+ }
+ else
+ {
+ /* garbled last line! */
+ [self warn: @"last line is truncated, trying to parse anyways!"];
+ }
+ }
+ else if (c == '\n')
+ { /* broken, non-standard */
+ BOOL isAtEndOfLine = YES;
+
+ /* test for folding first */
+ if (((length - 1) - pos) >= 1)
+ {
+ unichar ws;
+
+ ws = [_rawString characterAtIndex: (pos + 1)];
+
+ isAtEndOfLine = [whitespaceCharSet characterIsMember: ws] ? NO : YES;
+ if (!isAtEndOfLine)
+ {
+ /* assemble part of line up to pos */
+ if (r.length > 0)
+ {
+ [line appendString: [_rawString substringWithRange: r]];
+ }
+ /* unfold */
+ pos += 1;
+ r = NSMakeRange(pos + 1, 0); /* begin new range */
+ }
+ }
+ if (isAtEndOfLine)
+ {
+ /* assemble part of line up to pos */
+ if (r.length > 0)
+ {
+ [line appendString: [_rawString substringWithRange: r]];
+ }
+ [self _parseLine: line];
+ /* reset line */
+ [line deleteCharactersInRange: NSMakeRange(0, [line length])];
+ r = NSMakeRange(pos + 1, 0); /* begin new range */
+ }
+ }
+ else
+ {
+ r.length += 1;
+ }
+ }
+ if (r.length > 0)
+ {
+ [self warn: @"Last line of parse string is not properly terminated!"];
+ [line appendString: [_rawString substringWithRange: r]];
+ [self _parseLine: line];
+ }
+
+ if ([cardStack count] != 0)
+ {
+ [self warn: @"found elements on cardStack. This indicates an improper "
+ @"nesting structure! Not all required events will have been "
+ @"generated, leading to unpredictable results!"];
+ [cardStack removeAllObjects]; // clean up
+ }
+
+ [line release]; line = nil;
+
+ [self reportDocEnd];
+}
+
+/* main entry functions */
+
+- (id) sourceForData: (NSData *) _data
+ systemId: (NSString *) _sysId
+{
+ SaxParseException *e = nil;
+ NSStringEncoding encoding;
+ unsigned len;
+ const unsigned char *bytes;
+ id source;
+
+ if (debugOn)
+ {
+ NSLog(@"%s: trying to decode data (0x%p,len=%d) ...",
+ __PRETTY_FUNCTION__, _data, [_data length]);
+ }
+
+ if ((len = [_data length]) == 0)
+ {
+ e = (id)[SaxParseException exceptionWithName: @"SaxIOException"
+ reason: @"Got no parsing data!"
+ userInfo: nil];
+ [errorHandler fatalError: e];
+ return nil;
+ }
+ if (len < 10)
+ {
+ e = (id)[SaxParseException exceptionWithName: @"SaxIOException"
+ reason: @"Input data to short for vCard!"
+ userInfo: nil];
+ [errorHandler fatalError: e];
+ return nil;
+ }
+
+ bytes = [_data bytes];
+ if ((bytes[0] == 0xFF && bytes[1] == 0xFE) ||
+ (bytes[0] == 0xFE && bytes[1] == 0xFF))
+ encoding = NSUnicodeStringEncoding;
+ else
+ encoding = NSUTF8StringEncoding;
+
+ // FIXME: Data is not always utf-8.....
+ source = [[[NSString alloc] initWithData: _data encoding: encoding]
+ autorelease];
+ if (!source)
+ {
+ e = (id)[SaxParseException exceptionWithName: @"SaxIOException"
+ reason: @"Could not convert input to string!"
+ userInfo: nil];
+ [errorHandler fatalError: e];
+ }
+ return source;
+}
+
+- (void) parseFromSource: (id) _source
+ systemId: (NSString *) _sysId
+{
+ if (debugOn)
+ NSLog(@"%s: parse: %@ (sysid=%@)", __PRETTY_FUNCTION__, _source, _sysId);
+
+ if ([_source isKindOfClass: [NSURL class]])
+ {
+ NSURL *url;
+
+ url = _source;
+ if (!_sysId) _sysId = [url absoluteString];
+
+ if (debugOn)
+ {
+ NSLog(@"%s: trying to load URL: %@ (sysid=%@)",__PRETTY_FUNCTION__,
+ url, _sysId);
+ }
+
+ // TODO: remember encoding of source
+ _source = [url resourceDataUsingCache: NO];
+ if (!_source || ![_source length])
+ {
+ SaxParseException *e;
+ NSString *s;
+
+ if (debugOn)
+ NSLog(@"%s: got no data from url: %@", __PRETTY_FUNCTION__, url);
+
+ s = [NSString stringWithFormat: @"got no data from url: %@", url];
+ e = (id)[SaxParseException exceptionWithName: @"SaxIOException"
+ reason: s
+ userInfo: nil];
+ [errorHandler fatalError: e];
+ return;
+ }
+ }
+
+ if ([_source isKindOfClass: [NSData class]])
+ {
+ if (!_sysId) _sysId = @"<data>";
+ if ((_source = [self sourceForData: _source systemId: _sysId]) == nil)
+ return;
+ }
+
+ if (![_source isKindOfClass: [NSString class]])
+ {
+ SaxParseException *e;
+ NSString *s;
+
+ if (debugOn)
+ NSLog(@"%s: unrecognizable source: %@", __PRETTY_FUNCTION__,_source);
+
+ s = [@"cannot handle data-source: " stringByAppendingString:
+ [_source description]];
+ e = (id)[SaxParseException exceptionWithName: @"SaxIOException"
+ reason: s
+ userInfo: nil];
+
+ [errorHandler fatalError: e];
+ return;
+ }
+
+ /* ensure consistent state */
+
+ [cardStack removeAllObjects];
+ [elementList removeAllObjects];
+
+ /* start parsing */
+
+ if (debugOn)
+ {
+ NSLog(@"%s: trying to parse string (0x%p,len=%d) ...",
+ __PRETTY_FUNCTION__, _source, [_source length]);
+ }
+ if (!_sysId) _sysId = @"<string>";
+ [self _parseString: _source];
+
+ /* tear down */
+
+ [cardStack removeAllObjects];
+ [elementList removeAllObjects];
+}
+
+- (void) parseFromSource: (id) _source
+{
+ [self parseFromSource: _source systemId: nil];
+}
+
+- (void) parseFromSystemId: (NSString *) _sysId
+{
+ NSURL *url;
+
+ if (![_sysId rangeOfString: @"://"].length)
+ {
+ /* seems to be a path, path to be a proper URL */
+ url = [NSURL fileURLWithPath: _sysId];
+ }
+ else
+ {
+ /* Note: Cocoa NSURL doesn't complain on "/abc/def" like input! */
+ url = [NSURL URLWithString: _sysId];
+ }
+
+ if (!url)
+ {
+ SaxParseException *e;
+
+ e = (id)[SaxParseException exceptionWithName: @"SaxIOException"
+ reason: @"cannot handle system-id"
+ userInfo: nil];
+ [errorHandler fatalError: e];
+ return;
+ }
+
+ [self parseFromSource: url systemId: _sysId];
+}
+
+/* debugging */
+
+- (BOOL) isDebuggingEnabled
+{
+ return debugOn;
+}
+
+@end /* VersitCardsSaxDriver */
+
--- /dev/null
+/*
+ Copyright (C) 2004-2005 OpenGroupware.org
+
+ This file is part of versitCardsSaxDriver, written for the OpenGroupware.org
+ project (OGo).
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+ */
+
+
+#ifndef __VSStringFormatter_H_
+#define __VSStringFormatter_H_
+
+#import <Foundation/Foundation.h>
+
+@interface VSStringFormatter : NSObject
+{
+}
+
++ (id)sharedFormatter;
+- (NSString *)stringByUnescapingRFC2445Text:(NSString *)_s;
+
+@end
+
+#endif /* __VSStringFormatter_H_ */
--- /dev/null
+/*
+ Copyright (C) 2004-2005 OpenGroupware.org
+
+ This file is part of versitCardsSaxDriver, written for the OpenGroupware.org
+ project (OGo).
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#include "VSStringFormatter.h"
+#include "common.h"
+
+@implementation VSStringFormatter
+
+static NSCharacterSet *escSet = nil;
+
++ (void)initialize {
+ static BOOL didInit = NO;
+
+ if(didInit)
+ return;
+
+ didInit = YES;
+ escSet = [[NSCharacterSet characterSetWithCharactersInString:@"\\"] retain];
+}
+
++ (id)sharedFormatter {
+ static id sharedInstance = nil;
+ if(!sharedInstance) {
+ sharedInstance = [[self alloc] init];
+ }
+ return sharedInstance;
+}
+
+- (NSString *)stringByUnescapingRFC2445Text:(NSString *)_s {
+ NSMutableString *safeString;
+ unsigned length;
+ NSRange prevRange, escRange;
+ NSRange todoRange;
+ BOOL needsEscaping;
+
+ length = [_s length];
+ prevRange = NSMakeRange(0, length);
+ escRange = [_s rangeOfCharacterFromSet:escSet options:0 range:prevRange];
+
+ needsEscaping = escRange.length > 0 ? YES : NO;
+ if (!needsEscaping)
+ return _s; /* cheap */
+
+ safeString = [NSMutableString stringWithCapacity:length];
+
+ do {
+ prevRange.length = escRange.location - prevRange.location;
+ if (prevRange.length > 0)
+ [safeString appendString:[_s substringWithRange:prevRange]];
+
+ /* test edge case */
+ if(NSMaxRange(escRange) < length) {
+ unichar c = [_s characterAtIndex:escRange.location + 1];
+ if(c == 'n' || c == 'N') {
+ [safeString appendString:@"\n"];
+ escRange.length += 1; /* skip the 'n' */
+ }
+ }
+
+ prevRange.location = NSMaxRange(escRange);
+ todoRange.location = prevRange.location;
+ todoRange.length = length - prevRange.location;
+ escRange = [_s rangeOfCharacterFromSet:escSet
+ options:0
+ range:todoRange];
+ }
+ while(escRange.length > 0);
+
+ if (todoRange.length > 0)
+ [safeString appendString:[_s substringWithRange:todoRange]];
+
+ return safeString;
+}
+
+@end /* VSStringFormatter */
--- /dev/null
+# Version file
+
+# SOPE version:
+MAJOR_VERSION=4
+MINOR_VERSION=5
+
+SUBMINOR_VERSION:=24
--- /dev/null
+{
+ requires = {
+ bundleManagerVersion = 1;
+ classes = ( { name = NSObject; } );
+ };
+
+ provides = {
+ SAXDrivers = (
+ {
+ name = "VSCardSaxDriver";
+ sourceTypes = ( "text/x-vcard", "text/vcard",
+ "text/x-calendar", "text/calendar" );
+ }
+ );
+ classes = (
+ { name = "VSCardSaxDriver"; }
+ );
+ };
+}
--- /dev/null
+/*
+ Copyright (C) 2004 OpenGroupware.org
+
+ This file is part of versitCardsSaxDriver, written for the OpenGroupware.org
+ project (OGo).
+
+ SOPE is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with SOPE; see the file COPYING. If not, write to the
+ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+#import <Foundation/Foundation.h>
+
+#include <NGExtensions/NGObjectMacros.h>
--- /dev/null
+# postprocessing
+
+# FHS support (this is a hack and is going to be done by gstep-make!)
+
+ifneq ($(FHS_INSTALL_ROOT),)
+
+ifeq ($(findstring _64, $(GNUSTEP_TARGET_CPU)), _64)
+FHS_LIB_DIR=$(FHS_INSTALL_ROOT)/lib64/
+else
+FHS_LIB_DIR=$(FHS_INSTALL_ROOT)/lib/
+endif
+FHS_SAX_DIR=$(FHS_LIB_DIR)sope-$(MAJOR_VERSION).$(MINOR_VERSION)/saxdrivers/
+
+fhs-sax-dirs ::
+ $(MKDIRS) $(FHS_SAX_DIR)
+
+move-bundles-to-fhs :: fhs-sax-dirs
+ @echo "moving bundles $(BUNDLE_INSTALL_DIR) to $(FHS_SAX_DIR) .."
+ for i in $(BUNDLE_NAME); do \
+ j="$(FHS_SAX_DIR)/$${i}$(BUNDLE_EXTENSION)"; \
+ if test -d $$j; then rm -r $$j; fi; \
+ mv "$(BUNDLE_INSTALL_DIR)/$${i}$(BUNDLE_EXTENSION)" $$j; \
+ done
+
+move-to-fhs :: move-bundles-to-fhs
+
+after-install :: move-to-fhs
+
+endif
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>versitCardsSaxDriver</string>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>org.OpenGroupware.SOPE.sope-cards.versitCardsSaxDriver</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string></string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1656CD26058806680012D2BC /* VSSaxDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 1656CD24058806680012D2BC /* VSSaxDriver.h */; };
+ 1656CD27058806680012D2BC /* VSSaxDriver.m in Sources */ = {isa = PBXBuildFile; fileRef = 1656CD25058806680012D2BC /* VSSaxDriver.m */; };
+ 1656CD38058806CE0012D2BC /* bundle-info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1656CD37058806CE0012D2BC /* bundle-info.plist */; };
+ 1656CD7E058809660012D2BC /* VSCardSaxDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 1656CD7C058809660012D2BC /* VSCardSaxDriver.h */; };
+ 1656CD7F058809660012D2BC /* VSCardSaxDriver.m in Sources */ = {isa = PBXBuildFile; fileRef = 1656CD7D058809660012D2BC /* VSCardSaxDriver.m */; };
+ AD0CFACC071FFF0000E72147 /* VSStringFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = AD0CFACA071FFF0000E72147 /* VSStringFormatter.h */; };
+ AD0CFACD071FFF0000E72147 /* VSStringFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0CFACB071FFF0000E72147 /* VSStringFormatter.m */; };
+ AD5010A6071F18AE0020300E /* README in Resources */ = {isa = PBXBuildFile; fileRef = AD5010A5071F18AE0020300E /* README */; };
+ AD5010A8071F18B80020300E /* AUTHORS in Resources */ = {isa = PBXBuildFile; fileRef = AD5010A7071F18B80020300E /* AUTHORS */; };
+ AD5010BF071F18F00020300E /* COPYING in Resources */ = {isa = PBXBuildFile; fileRef = AD5010BE071F18F00020300E /* COPYING */; };
+ AD5010C1071F18FA0020300E /* COPYRIGHT in Resources */ = {isa = PBXBuildFile; fileRef = AD5010C0071F18FA0020300E /* COPYRIGHT */; };
+ AD665AB0071EB30200EC5911 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD665AAF071EB30200EC5911 /* Foundation.framework */; };
+ AD665AB4071EB36D00EC5911 /* SaxObjC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD665AB3071EB36D00EC5911 /* SaxObjC.framework */; };
+ AD665AB6071EB38C00EC5911 /* common.h in Headers */ = {isa = PBXBuildFile; fileRef = AD665AB5071EB38C00EC5911 /* common.h */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXBuildStyle section */
+ 1656CC9F058802980012D2BC /* Development */ = {
+ isa = PBXBuildStyle;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ ZERO_LINK = YES;
+ };
+ name = Development;
+ };
+ 1656CCA0058802990012D2BC /* Deployment */ = {
+ isa = PBXBuildStyle;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ ZERO_LINK = NO;
+ };
+ name = Deployment;
+ };
+/* End PBXBuildStyle section */
+
+/* Begin PBXFileReference section */
+ 1656CCB80588036A0012D2BC /* versitCardsSaxDriver-Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist; path = "versitCardsSaxDriver-Info.plist"; sourceTree = "<group>"; };
+ 1656CD24058806680012D2BC /* VSSaxDriver.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = VSSaxDriver.h; sourceTree = "<group>"; };
+ 1656CD25058806680012D2BC /* VSSaxDriver.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = VSSaxDriver.m; sourceTree = "<group>"; };
+ 1656CD37058806CE0012D2BC /* bundle-info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = "bundle-info.plist"; sourceTree = "<group>"; };
+ 1656CD7C058809660012D2BC /* VSCardSaxDriver.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = VSCardSaxDriver.h; sourceTree = "<group>"; };
+ 1656CD7D058809660012D2BC /* VSCardSaxDriver.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = VSCardSaxDriver.m; sourceTree = "<group>"; };
+ 16800E2F05880E8E007700A5 /* versitCardsSaxDriver.sax */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = versitCardsSaxDriver.sax; sourceTree = BUILT_PRODUCTS_DIR; };
+ 16800E4205880EC4007700A5 /* ChangeLog */ = {isa = PBXFileReference; explicitFileType = text; fileEncoding = 30; indentWidth = 8; path = ChangeLog; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
+ 16800E4305880EC4007700A5 /* Version */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 30; indentWidth = 8; path = Version; sourceTree = "<group>"; tabWidth = 8; };
+ AD0CFACA071FFF0000E72147 /* VSStringFormatter.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = VSStringFormatter.h; sourceTree = "<group>"; };
+ AD0CFACB071FFF0000E72147 /* VSStringFormatter.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = VSStringFormatter.m; sourceTree = "<group>"; };
+ AD5010A5071F18AE0020300E /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ AD5010A7071F18B80020300E /* AUTHORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AUTHORS; sourceTree = "<group>"; };
+ AD5010BE071F18F00020300E /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYING; sourceTree = "<group>"; };
+ AD5010C0071F18FA0020300E /* COPYRIGHT */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYRIGHT; sourceTree = "<group>"; };
+ AD665AAF071EB30200EC5911 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ AD665AB3071EB36D00EC5911 /* SaxObjC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SaxObjC.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/SaxObjC.framework"; sourceTree = "<absolute>"; };
+ AD665AB5071EB38C00EC5911 /* common.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
+ AD665AB7071EB39600EC5911 /* GNUmakefile */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 5; indentWidth = 8; path = GNUmakefile; sourceTree = "<group>"; tabWidth = 8; };
+ AD665AB8071EB39600EC5911 /* GNUmakefile.postamble */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 5; indentWidth = 8; path = GNUmakefile.postamble; sourceTree = "<group>"; tabWidth = 8; };
+ AD665AB9071EB39600EC5911 /* GNUmakefile.preamble */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 5; indentWidth = 8; path = GNUmakefile.preamble; sourceTree = "<group>"; tabWidth = 8; };
+ ADB07DC207666226003C5ACF /* fhs.make */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 5; indentWidth = 8; path = fhs.make; sourceTree = "<group>"; tabWidth = 8; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 1656CCAD058802B80012D2BC /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AD665AB0071EB30200EC5911 /* Foundation.framework in Frameworks */,
+ AD665AB4071EB36D00EC5911 /* SaxObjC.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 1656CC9D058802980012D2BC = {
+ isa = PBXGroup;
+ children = (
+ AD5010A5071F18AE0020300E /* README */,
+ AD5010C0071F18FA0020300E /* COPYRIGHT */,
+ AD5010BE071F18F00020300E /* COPYING */,
+ AD5010A7071F18B80020300E /* AUTHORS */,
+ 16800E4205880EC4007700A5 /* ChangeLog */,
+ 16800E4305880EC4007700A5 /* Version */,
+ AD665AAE071EB2C200EC5911 /* Makefiles */,
+ AD665ABF071EB3D500EC5911 /* Headers */,
+ 1656CD1F0588063D0012D2BC /* Classes */,
+ 1656CD8F058809E30012D2BC /* Resources */,
+ 1656CD92058809FD0012D2BC /* Frameworks */,
+ 16800E3905880EA1007700A5 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ 1656CD1F0588063D0012D2BC /* Classes */ = {
+ isa = PBXGroup;
+ children = (
+ AD665AB5071EB38C00EC5911 /* common.h */,
+ 1656CD25058806680012D2BC /* VSSaxDriver.m */,
+ 1656CD7D058809660012D2BC /* VSCardSaxDriver.m */,
+ AD0CFACB071FFF0000E72147 /* VSStringFormatter.m */,
+ );
+ name = Classes;
+ sourceTree = "<group>";
+ };
+ 1656CD8F058809E30012D2BC /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 1656CCB80588036A0012D2BC /* versitCardsSaxDriver-Info.plist */,
+ 1656CD37058806CE0012D2BC /* bundle-info.plist */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 1656CD92058809FD0012D2BC /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ AD665AB3071EB36D00EC5911 /* SaxObjC.framework */,
+ AD665AAF071EB30200EC5911 /* Foundation.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 16800E3905880EA1007700A5 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 16800E2F05880E8E007700A5 /* versitCardsSaxDriver.sax */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ AD665AAE071EB2C200EC5911 /* Makefiles */ = {
+ isa = PBXGroup;
+ children = (
+ AD665AB7071EB39600EC5911 /* GNUmakefile */,
+ AD665AB9071EB39600EC5911 /* GNUmakefile.preamble */,
+ AD665AB8071EB39600EC5911 /* GNUmakefile.postamble */,
+ ADB07DC207666226003C5ACF /* fhs.make */,
+ );
+ name = Makefiles;
+ sourceTree = "<group>";
+ };
+ AD665ABF071EB3D500EC5911 /* Headers */ = {
+ isa = PBXGroup;
+ children = (
+ 1656CD24058806680012D2BC /* VSSaxDriver.h */,
+ 1656CD7C058809660012D2BC /* VSCardSaxDriver.h */,
+ AD0CFACA071FFF0000E72147 /* VSStringFormatter.h */,
+ );
+ name = Headers;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 1656CCAA058802B80012D2BC /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1656CD26058806680012D2BC /* VSSaxDriver.h in Headers */,
+ 1656CD7E058809660012D2BC /* VSCardSaxDriver.h in Headers */,
+ AD665AB6071EB38C00EC5911 /* common.h in Headers */,
+ AD0CFACC071FFF0000E72147 /* VSStringFormatter.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 1656CCAE058802B80012D2BC /* versitCardsSaxDriver */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = ADA07A610857395900993825 /* Build configuration list for PBXNativeTarget "versitCardsSaxDriver" */;
+ buildPhases = (
+ 1656CCAA058802B80012D2BC /* Headers */,
+ 1656CCAB058802B80012D2BC /* Resources */,
+ 1656CCAC058802B80012D2BC /* Sources */,
+ 1656CCAD058802B80012D2BC /* Frameworks */,
+ );
+ buildRules = (
+ );
+ buildSettings = {
+ FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = common.h;
+ INFOPLIST_FILE = "versitCardsSaxDriver-Info.plist";
+ INSTALL_PATH = "$(USER_LIBRARY_DIR)/SaxDrivers-4.5";
+ PRODUCT_NAME = versitCardsSaxDriver;
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = sax;
+ };
+ dependencies = (
+ );
+ name = versitCardsSaxDriver;
+ productName = versitCardsSaxDriver;
+ productReference = 16800E2F05880E8E007700A5 /* versitCardsSaxDriver.sax */;
+ productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>versitCardsSaxDriver</string>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.MySoftwareCompany.versitCardsSaxDriver</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string></string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0.0d1</string>
+</dict>
+</plist>
+";
+ productType = "com.apple.product-type.bundle";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 1656CCA1058802990012D2BC /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = ADA07A650857395900993825 /* Build configuration list for PBXProject "versitCardsSaxDriver" */;
+ buildSettings = {
+ };
+ buildStyles = (
+ 1656CC9F058802980012D2BC /* Development */,
+ 1656CCA0058802990012D2BC /* Deployment */,
+ );
+ hasScannedForEncodings = 1;
+ mainGroup = 1656CC9D058802980012D2BC;
+ productRefGroup = 1656CC9D058802980012D2BC;
+ projectDirPath = "";
+ targets = (
+ 1656CCAE058802B80012D2BC /* versitCardsSaxDriver */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 1656CCAB058802B80012D2BC /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1656CD38058806CE0012D2BC /* bundle-info.plist in Resources */,
+ AD5010A6071F18AE0020300E /* README in Resources */,
+ AD5010A8071F18B80020300E /* AUTHORS in Resources */,
+ AD5010BF071F18F00020300E /* COPYING in Resources */,
+ AD5010C1071F18FA0020300E /* COPYRIGHT in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 1656CCAC058802B80012D2BC /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1656CD27058806680012D2BC /* VSSaxDriver.m in Sources */,
+ 1656CD7F058809660012D2BC /* VSCardSaxDriver.m in Sources */,
+ AD0CFACD071FFF0000E72147 /* VSStringFormatter.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ ADA07A620857395900993825 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = common.h;
+ INFOPLIST_FILE = "versitCardsSaxDriver-Info.plist";
+ INSTALL_PATH = "$(USER_LIBRARY_DIR)/SaxDrivers-4.5";
+ PRODUCT_NAME = versitCardsSaxDriver;
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = sax;
+ ZERO_LINK = YES;
+ };
+ name = Development;
+ };
+ ADA07A630857395900993825 /* Wrapper */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ FRAMEWORK_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = common.h;
+ INFOPLIST_FILE = "versitCardsSaxDriver-Info.plist";
+ INSTALL_PATH = "$(USER_LIBRARY_DIR)/SaxDrivers-4.5";
+ PRODUCT_NAME = versitCardsSaxDriver;
+ SYMROOT = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
+ TEMP_DIR = "$(SYMROOT)/$(PROJECT_NAME).build";
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = sax;
+ ZERO_LINK = NO;
+ };
+ name = Wrapper;
+ };
+ ADA07A640857395900993825 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = common.h;
+ INFOPLIST_FILE = "versitCardsSaxDriver-Info.plist";
+ INSTALL_PATH = "$(USER_LIBRARY_DIR)/SaxDrivers-4.5";
+ PRODUCT_NAME = versitCardsSaxDriver;
+ WARNING_CFLAGS = "-Wmost";
+ WRAPPER_EXTENSION = sax;
+ };
+ name = Default;
+ };
+ ADA07A660857395900993825 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Development;
+ };
+ ADA07A670857395900993825 /* Wrapper */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = (
+ ppc,
+ i386,
+ );
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Wrapper;
+ };
+ ADA07A680857395900993825 /* Default */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Default;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ ADA07A610857395900993825 /* Build configuration list for PBXNativeTarget "versitCardsSaxDriver" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ ADA07A620857395900993825 /* Development */,
+ ADA07A630857395900993825 /* Wrapper */,
+ ADA07A640857395900993825 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+ ADA07A650857395900993825 /* Build configuration list for PBXProject "versitCardsSaxDriver" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ ADA07A660857395900993825 /* Development */,
+ ADA07A670857395900993825 /* Wrapper */,
+ ADA07A680857395900993825 /* Default */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Default;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 1656CCA1058802990012D2BC /* Project object */;
+}
- (id)lookupHomeFolderForUID:(NSString *)_uid inContext:(id)_ctx;
- (NSArray *)lookupCalendarFoldersForUIDs:(NSArray *)_uids inContext:(id)_ctx;
-/* raw saving */
-
-- (NSException *)primarySaveContentString:(NSString *)_iCalString;
-- (NSException *)primaryDelete;
-
/* "iCal multifolder saves" */
- (NSException *)saveContentString:(NSString *)_iCal baseSequence:(int)_v;
- (NSException *)deleteWithBaseSequence:(int)_v;
- (NSException *)saveContentString:(NSString *)_iCalString;
-- (NSException *)delete;
- (NSException *)changeParticipationStatus:(NSString *)_status
inContext:(id)_ctx;
@interface SOGoAppointmentObject (PrivateAPI)
- (NSString *) homePageURLForPerson: (iCalPerson *) _person;
-- (void)sendEMailUsingTemplateNamed:(NSString *)_pageName
- forOldAppointment:(iCalEvent *)_newApt
- andNewAppointment:(iCalEvent *)_oldApt
- toAttendees:(NSArray *)_attendees;
-
-- (void)sendInvitationEMailForAppointment:(iCalEvent *)_apt
- toAttendees:(NSArray *)_attendees;
-- (void)sendAppointmentUpdateEMailForOldAppointment:(iCalEvent *)_oldApt
- newAppointment:(iCalEvent *)_newApt
- toAttendees:(NSArray *)_attendees;
-- (void)sendAttendeeRemovalEMailForAppointment:(iCalEvent *)_apt
- toAttendees:(NSArray *)_attendees;
-- (void)sendAppointmentDeletionEMailForAppointment:(iCalEvent *)_apt
- toAttendees:(NSArray *)_attendees;
+- (void) sendEMailUsingTemplateNamed: (NSString *) _pageName
+ forOldAppointment: (iCalEvent *) _newApt
+ andNewAppointment: (iCalEvent *) _oldApt
+ toAttendees: (NSArray *) _attendees;
+
+- (void) sendInvitationEMailForAppointment: (iCalEvent *) _apt
+ toAttendees: (NSArray *) _attendees;
+- (void) sendAppointmentUpdateEMailForOldAppointment: (iCalEvent *) _oldApt
+ newAppointment: (iCalEvent *) _newApt
+ toAttendees: (NSArray *) _attendees;
+- (void) sendAttendeeRemovalEMailForAppointment: (iCalEvent *) _apt
+ toAttendees: (NSArray *) _attendees;
+- (void) sendAppointmentDeletionEMailForAppointment: (iCalEvent *) _apt
+ toAttendees: (NSArray *) _attendees;
@end
@implementation SOGoAppointmentObject
-static NSString *mailTemplateDefaultLanguage = nil;
+static NSString *mailTemplateDefaultLanguage = nil;
+static BOOL sendEMailNotifications = NO;
-+ (void)initialize {
++ (void) initialize
+{
NSUserDefaults *ud;
static BOOL didInit = NO;
- if (didInit) return;
- didInit = YES;
+ if (!didInit)
+ {
+ didInit = YES;
- ud = [NSUserDefaults standardUserDefaults];
- mailTemplateDefaultLanguage = [[ud stringForKey:@"SOGoDefaultLanguage"]
- retain];
- if (!mailTemplateDefaultLanguage)
- mailTemplateDefaultLanguage = @"French";
+ ud = [NSUserDefaults standardUserDefaults];
+ mailTemplateDefaultLanguage = [[ud stringForKey:@"SOGoDefaultLanguage"]
+ retain];
+ if (!mailTemplateDefaultLanguage)
+ mailTemplateDefaultLanguage = @"French";
+
+ sendEMailNotifications
+ = [ud boolForKey: @"SOGoAppointmentSendEMailNotifications"];
+ }
}
/* accessors */
}
/* iCal handling */
-
-- (NSArray *)attendeeUIDsFromAppointment:(iCalEvent *)_apt {
+- (NSArray *) attendeeUIDsFromAppointment: (iCalEvent *) _apt
+{
AgenorUserManager *um;
- NSMutableArray *uids;
- NSArray *attendees;
+ NSMutableArray *uids;
+ NSArray *attendees;
unsigned i, count;
NSString *email, *uid;
- (NSException *)saveContentString:(NSString *)_iCal inUIDs:(NSArray *)_uids {
NSEnumerator *e;
- id folder;
- NSException *allErrors = nil;
+ id folder;
+ NSException *allErrors = nil;
id ctx;
ctx = [[WOApplication application] context];
allErrors = error;
}
}
+
return allErrors;
}
+
- (NSException *)deleteInUIDs:(NSArray *)_uids {
NSEnumerator *e;
- id folder;
- NSException *allErrors = nil;
- id ctx;
+ id folder;
+ NSException *allErrors = nil;
+ id ctx;
ctx = [[WOApplication application] context];
AgenorUserManager *um;
iCalCalendar *newCalendar;
iCalEvent *oldApt, *newApt;
- iCalEventChanges *changes;
- iCalPerson *organizer;
- NSString *oldContent, *uid;
- NSArray *uids, *props;
- NSMutableArray *attendees, *storeUIDs, *removedUIDs;
- NSException *storeError, *delError;
- BOOL updateForcesReconsider;
+ iCalEventChanges *changes;
+ iCalPerson *organizer;
+ NSString *oldContent, *uid;
+ NSArray *uids, *props;
+ NSMutableArray *attendees, *storeUIDs, *removedUIDs;
+ NSException *storeError, *delError;
+ BOOL updateForcesReconsider;
updateForcesReconsider = NO;
changes = [iCalEventChanges changesFromEvent: oldApt
toEvent: newApt];
- uids = [um getUIDsForICalPersons:[changes deletedAttendees]
+ uids = [um getUIDsForICalPersons:[changes deletedAttendees]
applyStrictMapping:NO];
removedUIDs = [NSMutableArray arrayWithArray:uids];
- uids = [um getUIDsForICalPersons:[newApt attendees]
+ uids = [um getUIDsForICalPersons:[newApt attendees]
applyStrictMapping:NO];
- storeUIDs = [NSMutableArray arrayWithArray:uids];
- props = [changes updatedProperties];
+ storeUIDs = [NSMutableArray arrayWithArray:uids];
+ props = [changes updatedProperties];
/* detect whether sequence has to be increased */
if ([changes hasChanges])
/* preserve organizer */
organizer = [newApt organizer];
- uid = [um getUIDForICalPerson:organizer];
+ uid = [um getUIDForICalPerson:organizer];
if (uid) {
if (![storeUIDs containsObject:uid])
[storeUIDs addObject:uid];
/* perform storing */
storeError = [self saveContentString:_iCal inUIDs:storeUIDs];
- delError = [self deleteInUIDs:removedUIDs];
+ delError = [self deleteInUIDs:removedUIDs];
// TODO: make compound
if (storeError != nil) return storeError;
if (delError != nil) return delError;
/* email notifications */
+ if (sendEMailNotifications)
+ {
+ attendees = [NSMutableArray arrayWithArray:[changes insertedAttendees]];
+ [attendees removePerson:organizer];
+ [self sendInvitationEMailForAppointment:newApt
+ toAttendees:attendees];
+
+ if (updateForcesReconsider) {
+ attendees = [NSMutableArray arrayWithArray:[newApt attendees]];
+ [attendees removeObjectsInArray:[changes insertedAttendees]];
+ [attendees removePerson:organizer];
+ [self sendAppointmentUpdateEMailForOldAppointment:oldApt
+ newAppointment:newApt
+ toAttendees:attendees];
+ }
- attendees = [NSMutableArray arrayWithArray:[changes insertedAttendees]];
- [attendees removePerson:organizer];
- [self sendInvitationEMailForAppointment:newApt
- toAttendees:attendees];
-
- if (updateForcesReconsider) {
- attendees = [NSMutableArray arrayWithArray:[newApt attendees]];
- [attendees removeObjectsInArray:[changes insertedAttendees]];
- [attendees removePerson:organizer];
- [self sendAppointmentUpdateEMailForOldAppointment:oldApt
- newAppointment:newApt
- toAttendees:attendees];
- }
-
- attendees = [NSMutableArray arrayWithArray:[changes deletedAttendees]];
- [attendees removePerson: organizer];
- if ([attendees count]) {
- iCalEvent *canceledApt;
+ attendees = [NSMutableArray arrayWithArray:[changes deletedAttendees]];
+ [attendees removePerson: organizer];
+ if ([attendees count])
+ {
+ iCalEvent *canceledApt;
- canceledApt = [newApt copy];
- [(iCalCalendar *) [canceledApt parent] setMethod: @"cancel"];
- [self sendAttendeeRemovalEMailForAppointment:canceledApt
- toAttendees: attendees];
- [canceledApt release];
- }
+ canceledApt = [newApt copy];
+ [(iCalCalendar *) [canceledApt parent] setMethod: @"cancel"];
+ [self sendAttendeeRemovalEMailForAppointment:canceledApt
+ toAttendees: attendees];
+ [canceledApt release];
+ }
+ }
+
return nil;
}
- send iMIP mail for all folders not found
*/
iCalEvent *apt;
- NSArray *removedUIDs;
- NSMutableArray *attendees;
+ NSArray *removedUIDs;
+ NSMutableArray *attendees;
/* load existing content */
/* compare sequence if requested */
- if (_v != 0) {
- // TODO
- }
+// if (_v != 0) {
+// // TODO
+// }
removedUIDs = [self attendeeUIDsFromAppointment:apt];
- /* send notification email to attendees excluding organizer */
- attendees = [NSMutableArray arrayWithArray:[apt attendees]];
- [attendees removePerson:[apt organizer]];
+ if (sendEMailNotifications)
+ {
+ /* send notification email to attendees excluding organizer */
+ attendees = [NSMutableArray arrayWithArray:[apt attendees]];
+ [attendees removePerson:[apt organizer]];
- /* flag appointment as being canceled */
- [(iCalCalendar *) [apt parent] setMethod: @"cancel"];
- [apt increaseSequence];
+ /* flag appointment as being canceled */
+ [(iCalCalendar *) [apt parent] setMethod: @"cancel"];
+ [apt increaseSequence];
- /* remove all attendees to signal complete removal */
- [apt removeAllAttendees];
+ /* remove all attendees to signal complete removal */
+ [apt removeAllAttendees];
- /* send notification email */
- [self sendAppointmentDeletionEMailForAppointment:apt
- toAttendees:attendees];
+ /* send notification email */
+ [self sendAppointmentDeletionEMailForAppointment:apt
+ toAttendees:attendees];
+ }
/* perform */
-
+
return [self deleteInUIDs:removedUIDs];
}
-- (NSException *)saveContentString:(NSString *)_iCalString {
- return [self saveContentString:_iCalString baseSequence:0];
+- (NSException *) saveContentString: (NSString *) _iCalString
+{
+ return [self saveContentString: _iCalString baseSequence: 0];
}
-- (NSException *)changeParticipationStatus:(NSString *)_status
- inContext:(id)_ctx
+- (NSException *) changeParticipationStatus: (NSString *) _status
+ inContext: (id) _ctx
{
iCalEvent *apt;
- iCalPerson *p;
- NSString *newContent;
- NSException *ex;
- NSString *myEMail;
+ iCalPerson *p;
+ NSString *newContent;
+ NSException *ex;
+ NSString *myEMail;
+ ex = nil;
+
// TODO: do we need to use SOGoAppointment? (prefer iCalEvent?)
apt = [self event];
- if (apt == nil) {
- return [NSException exceptionWithHTTPStatus:500 /* Server Error */
- reason:@"unable to parse appointment record"];
- }
-
- myEMail = [[_ctx activeUser] email];
- if ((p = [apt findParticipantWithEmail:myEMail]) == nil) {
- return [NSException exceptionWithHTTPStatus:404 /* Not Found */
- reason:@"user does not participate in this "
- @"appointment"];
- }
-
- [p setPartStat:_status];
- newContent = [[apt parent] versitString];
-
+ if (apt)
+ {
+ myEMail = [[_ctx activeUser] email];
+ p = [apt findParticipantWithEmail: myEMail];
+ if (p)
+ {
// TODO: send iMIP reply mails?
-// [apt release]; apt = nil;
-
- if (newContent == nil) {
- return [NSException exceptionWithHTTPStatus:500 /* Server Error */
- reason:@"Could not generate iCalendar data ..."];
- }
-
- if ((ex = [self saveContentString:newContent]) != nil) {
- // TODO: why is the exception wrapped?
- return [NSException exceptionWithHTTPStatus:500 /* Server Error */
- reason:[ex reason]];
- }
-
- return nil /* means: no error */;
+ [p setPartStat:_status];
+ newContent = [[apt parent] versitString];
+ if (newContent)
+ {
+ ex = [self saveContentString:newContent];
+ if (ex)
+ // TODO: why is the exception wrapped?
+ /* Server Error */
+ ex = [NSException exceptionWithHTTPStatus: 500
+ reason: [ex reason]];
+ }
+ else
+ ex
+ = [NSException exceptionWithHTTPStatus: 500 /* Server Error */
+ reason: @"Could not generate iCalendar data ..."];
+ }
+ else
+ ex = [NSException exceptionWithHTTPStatus: 404 /* Not Found */
+ reason: @"user does not participate in this "
+ @"appointment"];
+ }
+ else
+ ex = [NSException exceptionWithHTTPStatus:500 /* Server Error */
+ reason:@"unable to parse appointment record"];
+
+ return ex;
}
/* message type */
-- (NSString *)outlookMessageClass {
+- (NSString *) outlookMessageClass
+{
return @"IPM.Appointment";
}
/* EMail Notifications */
-- (NSString *)homePageURLForPerson:(iCalPerson *)_person {
- static AgenorUserManager *um = nil;
- static NSString *baseURL = nil;
+- (NSString *) homePageURLForPerson: (iCalPerson *) _person
+{
+ NSString *baseURL;
NSString *uid;
+ WOContext *ctx;
+ NSArray *traversalObjects;
- if (!um) {
- WOContext *ctx;
- NSArray *traversalObjects;
-
- um = [[AgenorUserManager sharedUserManager] retain];
-
- /* generate URL from traversal stack */
- ctx = [[WOApplication application] context];
- traversalObjects = [ctx objectTraversalStack];
- if ([traversalObjects count] >= 1) {
- baseURL = [[[traversalObjects objectAtIndex:0] baseURLInContext:ctx]
- retain];
- }
- else {
- [self warnWithFormat:@"Unable to create baseURL from context!"];
+ /* generate URL from traversal stack */
+ ctx = [[WOApplication application] context];
+ traversalObjects = [ctx objectTraversalStack];
+ if ([traversalObjects count] > 0)
+ baseURL = [[traversalObjects objectAtIndex:0] baseURLInContext:ctx];
+ else
+ {
baseURL = @"http://localhost/";
+ [self warnWithFormat:@"Unable to create baseURL from context!"];
}
- }
- uid = [um getUIDForEmail:[_person rfc822Email]];
- if (!uid) return nil;
- return [NSString stringWithFormat:@"%@%@", baseURL, uid];
+ uid = [[AgenorUserManager sharedUserManager]
+ getUIDForEmail: [_person rfc822Email]];
+
+ return ((uid)
+ ? [NSString stringWithFormat:@"%@%@", baseURL, uid]
+ : nil);
}
- (NSException *) saveContentString: (NSString *) contentString
baseVersion: baseVersion];
}
-- (void)sendEMailUsingTemplateNamed: (NSString *)_pageName
- forOldAppointment: (iCalEvent *)_oldApt
- andNewAppointment: (iCalEvent *)_newApt
- toAttendees: (NSArray *)_attendees
+- (void) sendEMailUsingTemplateNamed: (NSString *) _pageName
+ forOldAppointment: (iCalEvent *) _oldApt
+ andNewAppointment: (iCalEvent *) _newApt
+ toAttendees: (NSArray *) _attendees
{
- NSString *pageName;
- iCalPerson *organizer;
- NSString *cn, *sender, *iCalString;
- NGSendMail *sendmail;
- WOApplication *app;
- unsigned i, count;
-
- if (![_attendees count]) return; // another job neatly done :-)
-
- /* sender */
-
- organizer = [_newApt organizer];
- cn = [organizer cnWithoutQuotes];
- if (cn) {
- sender = [NSString stringWithFormat:@"%@ <%@>",
- cn,
- [organizer rfc822Email]];
- }
- else {
- sender = [organizer rfc822Email];
- }
+ NSString *pageName;
+ iCalPerson *organizer;
+ NSString *cn, *sender, *iCalString;
+ NGSendMail *sendmail;
+ WOApplication *app;
+ unsigned i, count;
+ iCalPerson *attendee;
+ NSString *recipient;
+ SOGoAptMailNotification *p;
+ NSString *subject, *text, *header;
+ NGMutableHashMap *headerMap;
+ NGMimeMessage *msg;
+ NGMimeBodyPart *bodyPart;
+ NGMimeMultipartBody *body;
+
+ if ([_attendees count])
+ {
+ /* sender */
+
+ organizer = [_newApt organizer];
+ cn = [organizer cnWithoutQuotes];
+ if (cn)
+ sender = [NSString stringWithFormat:@"%@ <%@>",
+ cn,
+ [organizer rfc822Email]];
+ else
+ sender = [organizer rfc822Email];
- /* generate iCalString once */
- iCalString = [[_newApt parent] versitString];
+ /* generate iCalString once */
+ iCalString = [[_newApt parent] versitString];
- /* get sendmail object */
- sendmail = [NGSendMail sharedSendMail];
+ /* get sendmail object */
+ sendmail = [NGSendMail sharedSendMail];
- /* get WOApplication instance */
- app = [WOApplication application];
+ /* get WOApplication instance */
+ app = [WOApplication application];
- /* generate dynamic message content */
-
- count = [_attendees count];
- for (i = 0; i < count; i++) {
- iCalPerson *attendee;
- NSString *recipient;
- SOGoAptMailNotification *p;
- NSString *subject, *text, *header;
- NGMutableHashMap *headerMap;
- NGMimeMessage *msg;
- NGMimeBodyPart *bodyPart;
- NGMimeMultipartBody *body;
-
- attendee = [_attendees objectAtIndex:i];
-
- /* construct recipient */
- cn = [attendee cn];
- if (cn) {
- recipient = [NSString stringWithFormat:@"%@ <%@>",
- cn,
- [attendee rfc822Email]];
- }
- else {
- recipient = [attendee rfc822Email];
- }
+ /* generate dynamic message content */
- /* create page name */
- // TODO: select user's default language?
- pageName = [NSString stringWithFormat:@"SOGoAptMail%@%@",
- mailTemplateDefaultLanguage,
- _pageName];
- /* construct message content */
- p = [app pageWithName:pageName inContext:[WOContext context]];
- [p setNewApt:_newApt];
- [p setOldApt:_oldApt];
- [p setHomePageURL:[self homePageURLForPerson:attendee]];
- [p setViewTZ: [self userTimeZone: cn]];
- subject = [p getSubject];
- text = [p getBody];
-
- /* construct message */
- headerMap = [NGMutableHashMap hashMapWithCapacity:5];
-
- /* NOTE: multipart/alternative seems like the correct choice but
- * unfortunately Thunderbird doesn't offer the rich content alternative
- * at all. Mail.app shows the rich content alternative _only_
- * so we'll stick with multipart/mixed for the time being.
- */
- [headerMap setObject:@"multipart/mixed" forKey:@"content-type"];
- [headerMap setObject:sender forKey:@"From"];
- [headerMap setObject:recipient forKey:@"To"];
- [headerMap setObject:[NSCalendarDate date] forKey:@"date"];
- [headerMap setObject:subject forKey:@"Subject"];
- msg = [NGMimeMessage messageWithHeader:headerMap];
-
- /* multipart body */
- body = [[NGMimeMultipartBody alloc] initWithPart:msg];
+ count = [_attendees count];
+ for (i = 0; i < count; i++)
+ {
+ attendee = [_attendees objectAtIndex:i];
+
+ /* construct recipient */
+ cn = [attendee cn];
+ if (cn)
+ recipient = [NSString stringWithFormat: @"%@ <%@>",
+ cn,
+ [attendee rfc822Email]];
+ else
+ recipient = [attendee rfc822Email];
+
+ /* create page name */
+ // TODO: select user's default language?
+ pageName = [NSString stringWithFormat: @"SOGoAptMail%@%@",
+ mailTemplateDefaultLanguage,
+ _pageName];
+ /* construct message content */
+ p = [app pageWithName: pageName inContext: [WOContext context]];
+ [p setNewApt: _newApt];
+ [p setOldApt: _oldApt];
+ [p setHomePageURL: [self homePageURLForPerson: attendee]];
+ [p setViewTZ: [self userTimeZone: cn]];
+ subject = [p getSubject];
+ text = [p getBody];
+
+ /* construct message */
+ headerMap = [NGMutableHashMap hashMapWithCapacity: 5];
- /* text part */
- headerMap = [NGMutableHashMap hashMapWithCapacity:1];
- [headerMap setObject:@"text/plain; charset=utf-8" forKey:@"content-type"];
- bodyPart = [NGMimeBodyPart bodyPartWithHeader:headerMap];
- [bodyPart setBody:[text dataUsingEncoding:NSUTF8StringEncoding]];
-
- /* attach text part to multipart body */
- [body addBodyPart:bodyPart];
+ /* NOTE: multipart/alternative seems like the correct choice but
+ * unfortunately Thunderbird doesn't offer the rich content alternative
+ * at all. Mail.app shows the rich content alternative _only_
+ * so we'll stick with multipart/mixed for the time being.
+ */
+ [headerMap setObject: @"multipart/mixed" forKey: @"content-type"];
+ [headerMap setObject: sender forKey: @"From"];
+ [headerMap setObject: recipient forKey: @"To"];
+ [headerMap setObject: [NSCalendarDate date] forKey: @"date"];
+ [headerMap setObject: subject forKey: @"Subject"];
+ msg = [NGMimeMessage messageWithHeader: headerMap];
+
+ /* multipart body */
+ body = [[NGMimeMultipartBody alloc] initWithPart: msg];
- /* calendar part */
- header = [NSString stringWithFormat:@"text/calendar; method=%@;"
- @" charset=utf-8",
- [(iCalCalendar *) [_newApt parent] method]];
- headerMap = [NGMutableHashMap hashMapWithCapacity:1];
- [headerMap setObject:header forKey:@"content-type"];
- bodyPart = [NGMimeBodyPart bodyPartWithHeader:headerMap];
- [bodyPart setBody:[iCalString dataUsingEncoding:NSUTF8StringEncoding]];
+ /* text part */
+ headerMap = [NGMutableHashMap hashMapWithCapacity: 1];
+ [headerMap setObject: @"text/plain; charset=utf-8"
+ forKey: @"content-type"];
+ bodyPart = [NGMimeBodyPart bodyPartWithHeader: headerMap];
+ [bodyPart setBody: [text dataUsingEncoding: NSUTF8StringEncoding]];
+
+ /* attach text part to multipart body */
+ [body addBodyPart: bodyPart];
- /* attach calendar part to multipart body */
- [body addBodyPart:bodyPart];
+ /* calendar part */
+ header = [NSString stringWithFormat: @"text/calendar; method=%@;"
+ @" charset=utf-8",
+ [(iCalCalendar *) [_newApt parent] method]];
+ headerMap = [NGMutableHashMap hashMapWithCapacity: 1];
+ [headerMap setObject:header forKey: @"content-type"];
+ bodyPart = [NGMimeBodyPart bodyPartWithHeader: headerMap];
+ [bodyPart setBody: [iCalString dataUsingEncoding: NSUTF8StringEncoding]];
+
+ /* attach calendar part to multipart body */
+ [body addBodyPart: bodyPart];
- /* attach multipart body to message */
- [msg setBody:body];
- [body release];
-
- /* send the damn thing */
- [sendmail sendMimePart:msg
- toRecipients:[NSArray arrayWithObject:[attendee rfc822Email]]
- sender:[organizer rfc822Email]];
- }
+ /* attach multipart body to message */
+ [msg setBody: body];
+ [body release];
+
+ /* send the damn thing */
+ [sendmail sendMimePart: msg
+ toRecipients: [NSArray arrayWithObject: [attendee rfc822Email]]
+ sender: [organizer rfc822Email]];
+ }
+ }
}
-- (void)sendInvitationEMailForAppointment:(iCalEvent *)_apt
- toAttendees:(NSArray *)_attendees
+- (void) sendInvitationEMailForAppointment: (iCalEvent *) _apt
+ toAttendees: (NSArray *) _attendees
{
- if (![_attendees count]) return; // another job neatly done :-)
-
- [self sendEMailUsingTemplateNamed:@"Invitation"
- forOldAppointment:nil
- andNewAppointment:_apt
- toAttendees:_attendees];
+ if ([_attendees count])
+ [self sendEMailUsingTemplateNamed: @"Invitation"
+ forOldAppointment: nil
+ andNewAppointment: _apt
+ toAttendees: _attendees];
}
-- (void)sendAppointmentUpdateEMailForOldAppointment:(iCalEvent *)_oldApt
- newAppointment:(iCalEvent *)_newApt
- toAttendees:(NSArray *)_attendees
+- (void) sendAppointmentUpdateEMailForOldAppointment: (iCalEvent *) _oldApt
+ newAppointment: (iCalEvent *) _newApt
+ toAttendees: (NSArray *) _attendees
{
- if (![_attendees count]) return;
-
- [self sendEMailUsingTemplateNamed:@"Update"
- forOldAppointment:_oldApt
- andNewAppointment:_newApt
- toAttendees:_attendees];
+ if ([_attendees count])
+ [self sendEMailUsingTemplateNamed: @"Update"
+ forOldAppointment: _oldApt
+ andNewAppointment: _newApt
+ toAttendees: _attendees];
}
-- (void)sendAttendeeRemovalEMailForAppointment:(iCalEvent *)_apt
- toAttendees:(NSArray *)_attendees
+- (void) sendAttendeeRemovalEMailForAppointment: (iCalEvent *) _apt
+ toAttendees: (NSArray *) _attendees
{
- if (![_attendees count]) return;
-
- [self sendEMailUsingTemplateNamed:@"Removal"
- forOldAppointment:nil
- andNewAppointment:_apt
- toAttendees:_attendees];
+ if ([_attendees count])
+ [self sendEMailUsingTemplateNamed: @"Removal"
+ forOldAppointment: nil
+ andNewAppointment: _apt
+ toAttendees: _attendees];
}
-- (void)sendAppointmentDeletionEMailForAppointment:(iCalEvent *)_apt
- toAttendees:(NSArray *)_attendees
+- (void) sendAppointmentDeletionEMailForAppointment: (iCalEvent *) _apt
+ toAttendees: (NSArray *) _attendees
{
- if (![_attendees count]) return;
-
- [self sendEMailUsingTemplateNamed:@"Deletion"
- forOldAppointment:nil
- andNewAppointment:_apt
- toAttendees:_attendees];
+ if ([_attendees count])
+ [self sendEMailUsingTemplateNamed: @"Deletion"
+ forOldAppointment: nil
+ andNewAppointment: _apt
+ toAttendees: _attendees];
}
- (NSString *) davContentType
- (NSString *) iCalString;
- (iCalCalendar *) calendar;
+- (NSException *) primarySaveContentString: (NSString *) _iCalString;
+- (NSException *) primaryDelete;
+
- (NSException *) delete;
@end
/* raw saving */
-- (NSException *)primarySaveContentString:(NSString *)_iCalString {
+- (NSException *) primarySaveContentString: (NSString *) _iCalString
+{
return [super saveContentString:_iCalString];
}
-- (NSException *)primaryDelete {
+- (NSException *) primaryDelete
+{
return [super delete];
}
-- (NSException *)deleteWithBaseSequence: (int) a
+- (NSException *) deleteWithBaseSequence: (int) a
{
[self subclassResponsibility: _cmd];
- (id)lookupHomeFolderForUID:(NSString *)_uid inContext:(id)_ctx;
- (NSArray *)lookupCalendarFoldersForUIDs:(NSArray *)_uids inContext:(id)_ctx;
-/* raw saving */
-
-- (NSException *)primarySaveContentString:(NSString *)_iCalString;
-- (NSException *)primaryDelete;
-
/* "iCal multifolder saves" */
- (NSException *)saveContentString:(NSString *)_iCal baseSequence:(int)_v;
- (NSException *)deleteWithBaseSequence:(int)_v;
- (NSException *)saveContentString:(NSString *)_iCalString;
-- (NSException *)delete;
- (NSException *)changeParticipationStatus:(NSString *)_status
inContext:(id)_ctx;
Appointments \
Contacts \
Mailer \
- Sieve \
+# Sieve \
include $(GNUSTEP_MAKEFILES)/aggregate.make
-/* NSString+URL.h - this file is part of SOGo
+/* NSString+Utilities.h - this file is part of SOGo
*
* Copyright (C) 2006 Inverse groupe conseil
*
-/* NSString+URL.m - this file is part of SOGo
+/* NSString+Utilities.m - this file is part of SOGo
*
* Copyright (C) 2006 Inverse group conseil
*
- (SoUser *) userInContext:(WOContext *)_ctx
{
static SoUser *anonymous = nil, *freebusy;
- NSString *login;
-
+ SoUser *user;
+ NSArray *traversalPath;
+ NSString *login;
+
if (!anonymous)
anonymous
= [[SOGoUser alloc] initWithLogin:@"anonymous"
roles: [NSArray arrayWithObject: SoRole_Anonymous]];
-
if (!freebusy)
freebusy
= [[SOGoUser alloc] initWithLogin: @"freebusy"
roles: [NSArray arrayWithObject: SOGoRole_FreeBusy]];
- if ((login = [self checkCredentialsInContext:_ctx]) == nil)
- /* some error (otherwise result would have been anonymous */
- return nil;
-
- if ([login isEqualToString: @"anonymous"])
- return anonymous;
- else if ([login isEqualToString: @"freebusy"])
- return freebusy;
-
-// uroles = [NSMutableArray arrayWithArray: ];
+ login = [self checkCredentialsInContext:_ctx];
+ if (login)
+ {
+ if ([login isEqualToString: @"anonymous"])
+ {
+ traversalPath = [_ctx objectForKey: @"SoRequestTraversalPath"];
+ if ([[traversalPath lastObject] isEqualToString: @"freebusy.ifb"])
+ user = freebusy;
+ else
+ user = anonymous;
+ }
+ else
+ user = [[[SOGoUser alloc] initWithLogin: login
+ roles: [self rolesForLogin: login]]
+ autorelease];
+ }
+ else
+ user = nil;
- return [[[SOGoUser alloc] initWithLogin: login
- roles: [self rolesForLogin: login]]
- autorelease];
+ return user;
}
// - (BOOL) renderException: (NSException *) exception
WOBUNDLE_EXTENSION = $(BUNDLE_EXTENSION)
WOBUNDLE_INSTALL_DIR = $(BUNDLE_INSTALL_DIR)
-SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
+# SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
ADDITIONAL_INCLUDE_DIRS += \
-I.. \
-I../..
ADDITIONAL_LIB_DIRS += \
- -L../SOGo/$(GNUSTEP_OBJ_DIR)/ \
+ -L../SOGo/$(GNUSTEP_OBJ_DIR)/ \
+ -L../../SOGo/$(GNUSTEP_OBJ_DIR)/ \
-L../../OGoContentStore/$(GNUSTEP_OBJ_DIR)/
BUNDLE_LIBS += \
#import <SoObjects/Mailer/SOGoMailObject.h>
#import "common.h"
-#import <SOGo/NSString+URL.h>
+#import <SOGo/NSString+Utilities.h>
@implementation UIxMailEditorAction
NSString *specificMessage;
request = [[self context] request];
+
+ [[self clientObject] flushMailCaches];
+
specificMessage = [request formValueForKey: @"pageforuid"];
self->firstMessageNumber
= ((specificMessage)
#import <NGObjWeb/SoHTTPAuthenticator.h>
#import <NGObjWeb/WOResourceManager.h>
-#import <SOGo/NSString+URL.h>
+#import <SOGo/NSString+Utilities.h>
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoObject.h>
(255 / colorTable[0]) - 1];
}
- NSLog(@"color = '%@'", color);
-
return color;
}
xmlns:label="OGo:label"
className="UIxPageFrame"
title="panelTitle"
- const:popup="YES"
- >
- <div id="headerArea">
- <div id="attachmentsArea">
- <var:string label:value="Attachments:" />
- <div id="compose_attachments_list"
- onclick="clickedEditorAttach(this);"
- ><var:foreach list="attachmentNames" item="attachmentName">
+ const:popup="YES">
+ <form name="pageform">
+ <div id="headerArea">
+ <div id="attachmentsArea">
+ <var:string label:value="Attachments:" />
+ <div id="compose_attachments_list"
+ onclick="clickedEditorAttach(this);"
+ ><var:foreach list="attachmentNames" item="attachmentName">
<var:string value="attachmentName" /><br />
- </var:foreach>
+ </var:foreach>
+ </div>
</div>
+ <span class="headerField"><var:string label:value="From" />:</span>
+ <var:popup const:name="from"
+ list="fromEMails"
+ item="item"
+ selection="from"
+ /><br />
+ <div>
+ <var:component className="UIxMailToSelection"
+ to="to" cc="cc" bcc="bcc" />
+ </div>
+ <div class="addressListElement" id="subjectRow"
+ ><span class="headerField"><var:string label:value="Subject"
+ />:</span
+ ><span class="headerInput"
+ ><input name="subject"
+ type="text"
+ class="textField"
+ var:value="subject"
+ /></span></div>
</div>
- <span class="headerField"><var:string label:value="From" />:</span>
- <var:popup const:name="from"
- list="fromEMails"
- item="item"
- selection="from"
- /><br />
- <div>
- <var:component className="UIxMailToSelection"
- to="to" cc="cc" bcc="bcc" />
- </div>
- <div class="addressListElement" id="subjectRow"
- ><span class="headerField"><var:string label:value="Subject"
- />:</span
- ><span class="headerInput"
- ><input name="subject"
- type="text"
- class="textField"
- var:value="subject"
- /></span></div>
- </div>
<!-- separator line -->
- <textarea name="content" var:value="text" />
+ <textarea name="content" var:value="text" />
<!-- img rsrc:src="tbird_073_compose.png" alt="screenshot" / -->
+ </form>
</var:component>
}
function onMailboxTreeItemClick(event) {
- var topNode = $('d');
+ var topNode = $("d");
var mailbox = this.parentNode.getAttribute("dataname");
- if (topNode.selectedEntry)
+ if (topNode.selectedEntry) {
+ log ("deselecting");
topNode.selectedEntry.deselect();
+ }
this.select();
topNode.selectedEntry = this;
var onhide, menuName;
var menutype = this.parentNode.getAttribute("datatype");
- log("parentNode: " + this.parentNode.tagName);
- log("menutype: " + menutype);
+// log("parentNode: " + this.parentNode.tagName);
+// log("menutype: " + menutype);
if (menutype) {
if (menutype == "inbox") {
menuName = "inboxIconMenu";
function initMailboxSelection(mailboxName)
{
currentMailbox = mailboxName;
-
+ log("initMailboxSelection: " + mailboxName);
var tree = $("d");
var treeNodes = document.getElementsByClassName("dTreeNode", tree);
var i = 0;
&& treeNodes[i].getAttribute("dataname") != currentMailbox)
i++;
if (i < treeNodes.length) {
+ log ("found mailbox");
var links = document.getElementsByClassName("node", treeNodes[i]);
if (tree.selectedEntry)
tree.selectedEntry.deselect();
}
var messageListData = function(type) {
- var rows = this.getSelectedRowsId();
+ var rows = this.parentNode.parentNode.getSelectedRowsId();
var msgIds = new Array();
for (var i = 0; i < rows.length; i++)
msgIds.push(rows[i].substr(4));
/* dnd */
function initDnd() {
- log ("MailerUI initDnd");
+// log ("MailerUI initDnd");
var tree = $("d");
if (tree) {
function openInbox(node) {
var done = false;
openMailbox(node.parentNode.getAttribute("dataname"));
+ var tree = $("d");
+ tree.selectedEntry = node;
node.select();
var currentNode = node.parentNode.parentNode;
while (!done) {
}
},
dragGestureMouseUpHandler: function (event) {
- log("mouseup");
+// log("mouseup");
document._currentMouseGestureObject._removeGestureHandlers();
},
dragGestureMouseMoveHandler: function (event) {
document.DNDManager.destinationExit, false);
if (operation.destination == event.target) {
// log("drag / drop: " + operation.source + " to " + operation.destination);
- if (operation.destination.dndExit)
- event.target.dndExit();
+ if (operation.destination.dndExit) {
+// log ("destination.dndExit...");
+ operation.destination.dndExit();
+ }
if (operation.destination.dndDrop) {
+// log ("destination.dndDrop...");
var data = null;
+// log ("optype: " + operation.type);
if (operation.source.dndDataForType)
data = operation.source.dndDataForType(operation.type);
- var result = event.target.dndDrop(data);
+// log ("data: " + data);
+ var result = operation.destination.dndDrop(data);
+// log ("result: " + result);
if (operation.ghost) {
if (result)
operation.bustGhost();
width: auto;
position: static; }
-
DIV.daysView > DIV.hours
{ position: absolute;
border: 0px;
right: 0px;
padding: 0px; }
+DIV[class~="appointment"]._selected > DIV.appointmentInside
+{ background-color: #ffa !important; }
+
DIV.appointment > DIV
{ position: absolute;
overflow: hidden;
var listFilter = 'view_today';
var listOfSelection = null;
+var selectedCalendarCell;
var hideCompletedTasks = 0;
for (var i = 0; i < nodes.length; i++)
_editEventId(nodes[i].getAttribute("id"),
nodes[i].getAttribute("owner"));
+ } else if (selectedCalendarCell) {
+ _editEventId(selectedCalendarCell.getAttribute("aptCName"),
+ selectedCalendarCell.getAttribute("owner"));
}
return false; /* stop following the link */
}
}
}
+ else if (selectedCalendarCell) {
+ var label = labels["appointmentDeleteConfirmation"].decodeEntities();
+ if (confirm(label)) {
+ if (document.deleteEventAjaxRequest) {
+ document.deleteEventAjaxRequest.aborted = true;
+ document.deleteEventAjaxRequest.abort();
+ }
+ eventsToDelete.push([selectedCalendarCell.getAttribute("aptCName")]);
+ ownersOfEventsToDelete.push(selectedCalendarCell.getAttribute("owner"));
+ _batchDeleteEvents();
+ }
+ }
else
window.alert("no selection");
log("closing window...?");
if (queryParameters["mail-invitation"] == "yes")
closeInvitationWindow();
- else
- window.close();
+ else {
+ window.opener.setTimeout("refreshAppointmentsAndDisplay();", 100);
+ window.setTimeout("window.close();", 100);
+ }
}
else {
log("showing alert...");
{
if (http.readyState == 4
&& http.status == 200) {
- var nodes = $(http.callbackData);
+ var nodes = http.callbackData;
for (var i = 0; i < nodes.length; i++) {
var node = $(nodes[i]);
- node.parentNode.removeChild(node);
+ if (node)
+ node.parentNode.removeChild(node);
}
if (eventsToDelete.length)
_batchDeleteEvents();
{
var url = ApplicationBaseURL + ((newView) ? newView : currentView);
+ selectedCalendarCell = null;
+
var day = null;
var hour = null;
if (time) {
function scrollDayView(hour)
{
- log("stest1");
var rowNumber;
if (hour) {
if (hour.length == 3)
var hours = daysView.childNodesWithTag("div")[0].childNodesWithTag("div");
if (hours.length > 0)
daysView.parentNode.scrollTop = hours[rowNumber + 1].offsetTop;
-
- log("stest2");
}
function onClickableCellsDblClick(event) {
list.deselectAll();
var aptCName = this.getAttribute("aptCName");
+ if (selectedCalendarCell)
+ selectedCalendarCell.deselect();
+ this.select();
+ selectedCalendarCell = this;
var row = $(aptCName);
if (row) {
var div = row.parentNode.parentNode.parentNode;
changeMonthCalendarDisplayOfSelectedDay(this);
changeDateSelectorDisplay(day);
+ if (listOfSelection) {
+ listOfSelection.addClassName("_unfocused");
+ listOfSelection = null;
+ }
+
if (needRefresh)
refreshAppointments();
}
TEXTAREA
{ vertical-align: top; }
-DIV, TEXTAREA, INPUT
+DIV, TEXTAREA, INPUT, SELECT
{ font-family: inherit;
font-size: inherit; }
function d2h(d) {
var hD = "0123456789abcdef";
- var h = hD.substr(d&15,1);
- while (d>15) {
- d>>=4;
- h=hD.substr(d&15,1)+h;
+ var h = hD.substr(d & 15, 1);
+
+ while (d > 15) {
+ d >>= 4;
+ h = hD.substr(d & 15, 1) + h;
}
+
return h;
}
-I.. \
-I../.. \
-I../../.. \
- -I../../SoObjects
+ -I../../SoObjects \
+ -I../../SOPE
ifeq ($(GNUSTEP_BUILD_DIR),)
ADDITIONAL_LIB_DIRS += \
+ -L../../SOPE/NGCards/$(GNUSTEP_OBJ_DIR) \
-L../SOGoUI/$(GNUSTEP_OBJ_DIR) \
-L../../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR)
else
+RELBUILD_DIR_libNGCards = \
+ $(GNUSTEP_BUILD_DIR)/../../SOPE/NGCards/$(GNUSTEP_OBJ_DIR_NAME)
RELBUILD_DIR_libSOGo = \
$(GNUSTEP_BUILD_DIR)/../../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR_NAME)
RELBUILD_DIR_libSOGoUI = \
$(GNUSTEP_BUILD_DIR)/../../OGoContentStore/$(GNUSTEP_OBJ_DIR_NAME)
ADDITIONAL_LIB_DIRS += \
+ -L$(RELBUILD_DIR_libNGCards) \
-L$(RELBUILD_DIR_libSOGo) \
-L$(RELBUILD_DIR_libSOGoUI) \
-L$(RELBUILD_DIR_libOGoContentStore)