From: wolfgang Date: Wed, 31 Jan 2007 17:26:13 +0000 (+0000) Subject: git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1013 d1b88da0-ebda-0310... X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=676baa9a4356a8dd9d99d1c88fc7589d742149b9;p=scalable-opengroupware.org git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1013 d1b88da0-ebda-0310-925b-ed51d893ca5b --- diff --git a/ChangeLog b/ChangeLog index 10d2f7a7..e236403f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2007-01-30 Wolfgang Sourdeau + + * 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 + + * 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 * SoObjects/SOGo/SOGoAuthenticator.m ([SOGoAuthenticator diff --git a/GNUmakefile b/GNUmakefile index def68eaa..75961d30 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -4,6 +4,7 @@ include $(GNUSTEP_MAKEFILES)/common.make SUBPROJECTS = \ + SOPE/NGCards \ OGoContentStore \ SoObjects \ Main \ @@ -11,4 +12,3 @@ SUBPROJECTS = \ Protocols \ include $(GNUSTEP_MAKEFILES)/aggregate.make - diff --git a/Main/GNUmakefile.preamble b/Main/GNUmakefile.preamble index 99bdcff3..9938d4af 100644 --- a/Main/GNUmakefile.preamble +++ b/Main/GNUmakefile.preamble @@ -11,7 +11,8 @@ ADDITIONAL_INCLUDE_DIRS += \ 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 diff --git a/OGoContentStore/GNUmakefile b/OGoContentStore/GNUmakefile index 1b09057c..5807b690 100644 --- a/OGoContentStore/GNUmakefile +++ b/OGoContentStore/GNUmakefile @@ -7,7 +7,7 @@ include ./Version 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 diff --git a/OGoContentStore/GNUmakefile.preamble b/OGoContentStore/GNUmakefile.preamble index faf4e378..e39140e3 100644 --- a/OGoContentStore/GNUmakefile.preamble +++ b/OGoContentStore/GNUmakefile.preamble @@ -8,9 +8,9 @@ libOGoContentStore_LIBRARIES_DEPEND_UPON += \ -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 diff --git a/OGoContentStore/sql/folderinfo-create.psql b/OGoContentStore/sql/folderinfo-create.psql index e4a499ea..30559779 100644 --- a/OGoContentStore/sql/folderinfo-create.psql +++ b/OGoContentStore/sql/folderinfo-create.psql @@ -4,6 +4,8 @@ -- TODO: -- add a unique constraints on path +DROP SEQUENCE SOGo_folder_info_seq; + CREATE SEQUENCE SOGo_folder_info_seq; DROP TABLE SOGo_folder_info; @@ -24,18 +26,3 @@ CREATE 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' ); diff --git a/OGoContentStore/sql/generate-folderinfo-sql-for-users.sh b/OGoContentStore/sql/generate-folderinfo-sql-for-users.sh index ed2e0183..2cff4355 100755 --- a/OGoContentStore/sql/generate-folderinfo-sql-for-users.sh +++ b/OGoContentStore/sql/generate-folderinfo-sql-for-users.sh @@ -5,7 +5,7 @@ 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" diff --git a/Protocols/common.make b/Protocols/common.make index 0cc98888..8d43914d 100644 --- a/Protocols/common.make +++ b/Protocols/common.make @@ -12,14 +12,18 @@ ADDITIONAL_INCLUDE_DIRS += \ -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) diff --git a/SOPE/NGCards/COPYING b/SOPE/NGCards/COPYING new file mode 100644 index 00000000..161a3d1d --- /dev/null +++ b/SOPE/NGCards/COPYING @@ -0,0 +1,482 @@ + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/SOPE/NGCards/COPYRIGHT b/SOPE/NGCards/COPYRIGHT new file mode 100644 index 00000000..70205ecc --- /dev/null +++ b/SOPE/NGCards/COPYRIGHT @@ -0,0 +1,4 @@ +Copyright (C) 2000-2005 SKYRIX Software AG + + +Contact: info@skyrix.com diff --git a/SOPE/NGCards/CardElement.h b/SOPE/NGCards/CardElement.h new file mode 100644 index 00000000..d4fd0315 --- /dev/null +++ b/SOPE/NGCards/CardElement.h @@ -0,0 +1,109 @@ +/* CardElement.h - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 + +@class NSArray; +@class NSDictionary; +@class NSMutableArray; +@class NSMutableDictionary; +@class NSString; + +@class CardGroup; + +@interface CardElement : NSObject +{ + 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 */ diff --git a/SOPE/NGCards/CardElement.m b/SOPE/NGCards/CardElement.m new file mode 100644 index 00000000..4e85a8e4 --- /dev/null +++ b/SOPE/NGCards/CardElement.m @@ -0,0 +1,500 @@ +/* CardElement.m - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 +#import +#import + +#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 diff --git a/SOPE/NGCards/CardGroup+iCal.h b/SOPE/NGCards/CardGroup+iCal.h new file mode 100644 index 00000000..ece4cf1a --- /dev/null +++ b/SOPE/NGCards/CardGroup+iCal.h @@ -0,0 +1,39 @@ +/* CardGroup+iCal.h - this file is part of $PROJECT_NAME_HERE$ + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 */ diff --git a/SOPE/NGCards/CardGroup+iCal.m b/SOPE/NGCards/CardGroup+iCal.m new file mode 100644 index 00000000..a7fb4e58 --- /dev/null +++ b/SOPE/NGCards/CardGroup+iCal.m @@ -0,0 +1,48 @@ +/* CardGroup+iCal.m - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 diff --git a/SOPE/NGCards/CardGroup.h b/SOPE/NGCards/CardGroup.h new file mode 100644 index 00000000..3108f8b9 --- /dev/null +++ b/SOPE/NGCards/CardGroup.h @@ -0,0 +1,76 @@ +/* CardGroup.h - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 +{ + 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 */ diff --git a/SOPE/NGCards/CardGroup.m b/SOPE/NGCards/CardGroup.m new file mode 100644 index 00000000..90700c8a --- /dev/null +++ b/SOPE/NGCards/CardGroup.m @@ -0,0 +1,386 @@ +/* CardGroup.m - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 +#import +#import +#import +#import + +#import "NGCardsSaxHandler.h" +#import "NSArray+NGCards.h" + +#import "CardGroup.h" + +static id parser = nil; +static NGCardsSaxHandler *sax = nil; + +@implementation CardGroup + ++ (id) 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 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 diff --git a/SOPE/NGCards/CardVersitRenderer.h b/SOPE/NGCards/CardVersitRenderer.h new file mode 100644 index 00000000..70ee8671 --- /dev/null +++ b/SOPE/NGCards/CardVersitRenderer.h @@ -0,0 +1,37 @@ +/* CardVersitRenderer.h - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 + +@class CardGroup; +@class NSString; + +@interface CardVersitRenderer : NSObject + +- (NSString *) render: (id) anElement; + +@end + +#endif /* CARDCARDRENDERER_H */ diff --git a/SOPE/NGCards/CardVersitRenderer.m b/SOPE/NGCards/CardVersitRenderer.m new file mode 100644 index 00000000..0643bbdc --- /dev/null +++ b/SOPE/NGCards/CardVersitRenderer.m @@ -0,0 +1,136 @@ +/* CardVersitRenderer.m - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 +#import +#import + +#import + +#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 = @""; + [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 = @""; + [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 diff --git a/SOPE/NGCards/ChangeLog b/SOPE/NGCards/ChangeLog new file mode 100644 index 00000000..9a889262 --- /dev/null +++ b/SOPE/NGCards/ChangeLog @@ -0,0 +1,600 @@ +2006-08-03 Helge Hess + + * 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 + + * use %p for pointer formats, fixed gcc 4.1 warnings (v4.5.75) + +2006-05-16 Marcus Mueller + + * iCalDataSource.h, common.h: changed EOControl related includes into + imports to enable compilation against MulleEOF (v4.5.74) + +2006-04-07 Marcus Mueller + + * iCalEntityObject.h: added missing forward declaration for + gstep-base compile (v4.5.73) + +2006-04-06 Marcus Mueller + + * 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 + + * iCalRecurrenceRule.m: properly include NSString+Ext.h to avoid a + warning during Cocoa compilation (v4.5.71) + +2005-11-17 Helge Hess + + * include string.h where required (v4.5.70) + +2005-10-05 Helge Hess + + * iCalMonthlyRecurrenceCalculator.m: implemented calculation of + negative byday occurrences (eg -1TH) (v4.5.69) + +2005-09-22 Helge Hess + + * 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 + + * v4.5.67 + + * iCalMonthlyRecurrenceCalculator.m: finished 'byday' calculation + + * iCalRecurrenceRule.m: added support for 'bymonthday', fixed handling + of occurrence1 + +2005-09-21 Helge Hess + + * 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 + + * 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 + + * iCalRecurrenceRule.m: minor code improvements, more tolerant on + invalid iCal rrule input (v4.5.61) + +2005-08-16 Helge Hess + + * GNUmakefile, GNUmakefile.preamble: added OSX framework compilation + (v4.5.60) + +2005-08-06 Helge Hess + + * iCalCalendar.m, NGVCardName.m: fixed gcc 4.0 warnings (v4.5.59) + +2005-08-05 Helge Hess + + * NGVCardSaxHandler.h: fixed a gcc 4.0 warning (v4.5.58) + +2005-07-18 Helge Hess + + * 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 + + * 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 + + * added fragile base class version checks (v4.5.55) + +2005-07-15 Marcus Mueller + + * 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 + + * v4.5.53 + + * iCalCalendar.m: added +parseCalendarFromSource: convenience method + + * NGVCard.m: properly reset sax driver after parsing + +2005-07-15 Marcus Mueller + + * 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 + + * 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 + + * 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 + + * 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 + + * NSCalendarDate+ICal.m: fixed 'gmtcalfmt' which removed seconds from + format for no obvious reason (v4.5.47) + +2005-05-31 Helge Hess + + * NGVCardSaxHandler.m: ensure that types are always uppercase, improved + check for DUPs (v4.5.46) + +2005-05-16 Marcus Mueller + + * NGiCal.xcode: reorganized ordering of headers/classes + +2005-05-15 Marcus Mueller + + * NGiCal.xcode: added vCard related stuff + +2005-05-10 Helge Hess + + * NGVCard.m: added support for profile, source, name (v4.5.45) + +2005-05-09 Helge Hess + + * first version of working vCard SAX handler (v4.5.54) + +2005-05-08 Helge Hess + + * more work on vCard parsing (v4.5.53) + + * work on vCard objects (incomplete) (v4.5.52) + +2005-04-25 Helge Hess + + * iCalDateHolder.m, iCalDataSource.m: fixed gcc 4.0 warnings (v4.5.51) + +2005-03-23 Marcus Mueller + + * 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 + + * 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 + + * 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 + + * NGiCal.xmap: fixed a missing semicolon (did not load on MacOSX) + (v.4.5.46) + +2005-02-17 Helge Hess + + * GNUmakefile.preamble: fixed linking locations for dependencies + (v4.5.45) + +2005-02-17 Marcus Mueller + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * NGiCal.xcode: minor changes and updated + +2004-12-13 Marcus Mueller + + * iCalPerson.[hm]: added -cnWithoutQuotes and -rfc822Email convenience + methods to simplify client code dealing with these properties + (v4.5.36) + +2004-11-07 Marcus Mueller + + * NGiCal.xcode: provide SOPE_{MAJOR,MINOR}_VERSION to the build + +2004-11-06 Helge Hess + + * iCalRenderer.m: use SOPE version defines for iCalendar product id + (v4.5.35) + +2004-11-04 Helge Hess + + * use Version file for install directory location of sax mapping + +2004-10-31 Marcus Mueller + + * iCalAlarm.[hm], iCalEvent.[hm], iCalToDo.[hm], + NGiCal.xmap: added recurrenceRule (v4.3.34) + +2004-10-20 Marcus Mueller + + * NGiCal.xcode: added iCalRenderer.[hm], bumped framework version + +2004-10-20 Helge Hess + + * 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 + + * NGiCal.xmap: added "categories" mapping (v4.3.31) + +2004-10-05 Marcus Mueller + + * iCalEntityObject.[hm]: added categories property (v4.3.30) + +2004-09-22 Marcus Mueller + + * NGiCal.xcode: fixed several build parameters + +2004-09-01 Marcus Mueller + + * 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 + + * 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 + + * 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 + + * NGiCal.xcode: new Xcode project + +2004-08-20 Helge Hess + + * 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 + + * 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 + + * iCalEvent.h: moved 'status' field to iCalEntityObject, because it is + also available in todo objects (v4.2.23) + +2004-06-30 Marcus Mueller + + * 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 + + * v4.2.21 + + * GNUmakefile.preamble: added prebinding + + * GNUmakefile: create GNUmakefile.preamble, GNUmakefile.postamble + +2004-05-05 Marcus Mueller + + * 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 + + * iCalDataSource.m: added some sanity checks, improved to work better + with Mozilla generated iCal files (v4.2.19) + +2003-12-22 Helge Hess + + * iCalDateHolder.m: small fix not to print a warning for "YYYYMMDD" + style dates (which are supported) (v4.2.18) + +2003-12-21 Helge Hess + + * 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 + + * iCalDateHolder.m: added timeless date format: YYYYMMDD + (solves ogo bug 424) (v4.2.16) + +Wed Oct 29 22:04:32 2003 Martin Hoerning + + * 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 + + * GNUmakefile (libNGiCal_LIBRARIES_DEPEND_UPON): link against + libSaxObjC on MacOSX (v4.2.14) + +Fri Jul 18 17:04:55 2003 Martin Hoerning + + * iCalToDo.h, iCalPerson.h, iCalEvent.h, iCalEntityObject.h: added + accessor-methods to interface (v4.2.13) + +2003-07-18 Helge Hess + + * iCalDateHolder.m: replaces and indexOfString with rangeOfString, + thanks to Filip Van Raemdonck for pointing that out (v4.2.12) + +2003-03-21 Helge Hess + + * added some method prototypes + +2003-03-13 Helge Hess + + * moved iCalEntityObject to a separate file (v4.2.11) + +Mon Mar 10 18:41:10 2003 Bjoern Stierand + + * NGiCal.xmap: added missing attendee attributes (as dictated by + mh on the phone) + +2003-03-10 Helge Hess + + * iCalPerson.h: added some method prototypes + +2003-02-24 Helge Hess + + * iCalObject.h: added some accessors (v4.2.10) + +2003-02-12 Helge Hess + + * moved to skyrix-core (v4.2.9) + +2003-01-13 Helge Hess + + * added some support for timezones to be able to parse Evolution + apt creation requests (v4.2.7) + +2002-10-14 Helge Hess + + * 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 + + * ICalParser.m: small cleanups (v4.2.2) + +2002-10-04 Helge Hess + + * created ChangeLog, created NGiCal library into SkyCore + + diff --git a/SOPE/NGCards/GNUmakefile b/SOPE/NGCards/GNUmakefile new file mode 100644 index 00000000..efc491c5 --- /dev/null +++ b/SOPE/NGCards/GNUmakefile @@ -0,0 +1,130 @@ +# 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 diff --git a/SOPE/NGCards/GNUmakefile.postamble b/SOPE/NGCards/GNUmakefile.postamble new file mode 100644 index 00000000..8074f126 --- /dev/null +++ b/SOPE/NGCards/GNUmakefile.postamble @@ -0,0 +1,13 @@ +# 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) diff --git a/SOPE/NGCards/GNUmakefile.preamble b/SOPE/NGCards/GNUmakefile.preamble new file mode 100644 index 00000000..0f6c0a40 --- /dev/null +++ b/SOPE/NGCards/GNUmakefile.preamble @@ -0,0 +1,61 @@ +# 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 diff --git a/SOPE/NGCards/IcalElements.m b/SOPE/NGCards/IcalElements.m new file mode 100644 index 00000000..c5002dc0 --- /dev/null +++ b/SOPE/NGCards/IcalElements.m @@ -0,0 +1,210 @@ +/* + 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 + +@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 */ diff --git a/SOPE/NGCards/IcalResponse.h b/SOPE/NGCards/IcalResponse.h new file mode 100644 index 00000000..1b2e2580 --- /dev/null +++ b/SOPE/NGCards/IcalResponse.h @@ -0,0 +1,46 @@ +/* + 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 + +@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__ */ diff --git a/SOPE/NGCards/IcalResponse.m b/SOPE/NGCards/IcalResponse.m new file mode 100644 index 00000000..1e90c2b2 --- /dev/null +++ b/SOPE/NGCards/IcalResponse.m @@ -0,0 +1,90 @@ +/* + 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 + +@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 */ diff --git a/SOPE/NGCards/NGCards-Info.plist b/SOPE/NGCards/NGCards-Info.plist new file mode 100644 index 00000000..0080a1c2 --- /dev/null +++ b/SOPE/NGCards/NGCards-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGiCal + CFBundleGetInfoString + + CFBundleIdentifier + org.OpenGroupware.SOPE.ical.NGiCal + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 4.5 + + diff --git a/SOPE/NGCards/NGCards.h b/SOPE/NGCards/NGCards.h new file mode 100644 index 00000000..f58f9a88 --- /dev/null +++ b/SOPE/NGCards/NGCards.h @@ -0,0 +1,51 @@ +/* + 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 +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#import + +#import +#import + +#import + +#import +#import +#import +#import +#import + +#endif /* __NGCards_H__ */ diff --git a/SOPE/NGCards/NGCards.xcodeproj/project.pbxproj b/SOPE/NGCards/NGCards.xcodeproj/project.pbxproj new file mode 100644 index 00000000..43e1ec52 --- /dev/null +++ b/SOPE/NGCards/NGCards.xcodeproj/project.pbxproj @@ -0,0 +1,1093 @@ +// !$*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 = ""; }; + AD2EC1C108E2E630006B7836 /* iCalMonthlyRecurrenceCalculator.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = iCalMonthlyRecurrenceCalculator.m; sourceTree = ""; }; + AD2EC1C208E2E630006B7836 /* iCalWeeklyRecurrenceCalculator.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = iCalWeeklyRecurrenceCalculator.m; sourceTree = ""; }; + AD2EC1C308E2E630006B7836 /* iCalYearlyRecurrenceCalculator.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; path = iCalYearlyRecurrenceCalculator.m; sourceTree = ""; }; + AD596D8A083769C500C4D81D /* NGICalSaxHandler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGICalSaxHandler.h; sourceTree = ""; }; + AD596D8B083769C500C4D81D /* NGICalSaxHandler.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGICalSaxHandler.m; sourceTree = ""; }; + AD596D8C083769C500C4D81D /* NGVCard.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCard.h; sourceTree = ""; }; + AD596D8D083769C500C4D81D /* NGVCard.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCard.m; sourceTree = ""; }; + AD596D8E083769C500C4D81D /* NGVCardAddress.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardAddress.h; sourceTree = ""; }; + AD596D8F083769C500C4D81D /* NGVCardAddress.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardAddress.m; sourceTree = ""; }; + AD596D90083769C500C4D81D /* NGVCardName.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardName.h; sourceTree = ""; }; + AD596D91083769C500C4D81D /* NGVCardName.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardName.m; sourceTree = ""; }; + AD596D92083769C500C4D81D /* NGVCardOrg.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardOrg.h; sourceTree = ""; }; + AD596D93083769C500C4D81D /* NGVCardOrg.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardOrg.m; sourceTree = ""; }; + AD596D94083769C500C4D81D /* NGVCardPhone.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardPhone.h; sourceTree = ""; }; + AD596D95083769C500C4D81D /* NGVCardPhone.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardPhone.m; sourceTree = ""; }; + AD596D96083769C500C4D81D /* NGVCardSaxHandler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardSaxHandler.h; sourceTree = ""; }; + AD596D97083769C500C4D81D /* NGVCardSaxHandler.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardSaxHandler.m; sourceTree = ""; }; + AD596D98083769C500C4D81D /* NGVCardSimpleValue.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardSimpleValue.h; sourceTree = ""; }; + AD596D99083769C500C4D81D /* NGVCardSimpleValue.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardSimpleValue.m; sourceTree = ""; }; + AD596D9A083769C500C4D81D /* NGVCardStrArrayValue.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardStrArrayValue.h; sourceTree = ""; }; + AD596D9B083769C500C4D81D /* NGVCardStrArrayValue.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardStrArrayValue.m; sourceTree = ""; }; + AD596D9C083769C500C4D81D /* NGVCardValue.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NGVCardValue.h; sourceTree = ""; }; + AD596D9D083769C500C4D81D /* NGVCardValue.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NGVCardValue.m; sourceTree = ""; }; + AD770E6707AE627500F5C7A1 /* iCalRecurrenceRule.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalRecurrenceRule.h; sourceTree = ""; }; + AD770E6807AE627500F5C7A1 /* iCalRecurrenceRule.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalRecurrenceRule.m; sourceTree = ""; }; + AD77103C07AE8F8500F5C7A1 /* iCalRepeatableEntityObject.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalRepeatableEntityObject.h; sourceTree = ""; }; + AD77103D07AE8F8500F5C7A1 /* iCalRepeatableEntityObject.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalRepeatableEntityObject.m; sourceTree = ""; }; + AD8BF0F70701902800EC239A /* XmlRpc.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XmlRpc.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/XmlRpc.framework"; sourceTree = ""; }; + ADAACE6607B3973900FC48D6 /* iCalRecurrenceCalculator.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalRecurrenceCalculator.h; sourceTree = ""; }; + ADAACE6707B3973900FC48D6 /* iCalRecurrenceCalculator.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalRecurrenceCalculator.m; sourceTree = ""; }; + 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 = ""; }; + ADAAD00607B6AF7700FC48D6 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = /Library/Frameworks/SenTestingKit.framework; sourceTree = ""; }; + ADAAD02107B6AFD700FC48D6 /* iCalRecurrenceCalculatorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iCalRecurrenceCalculatorTests.m; sourceTree = ""; }; + ADAAD04007B6B02400FC48D6 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; + ADAAD04107B6B05000FC48D6 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; + ADBE3DF7072713AF000FEA6A /* iCalRenderer.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalRenderer.h; sourceTree = ""; }; + ADBE3DF9072713C2000FEA6A /* iCalRenderer.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalRenderer.m; sourceTree = ""; }; + ADBE3DFE072713DB000FEA6A /* fhs.make */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 5; indentWidth = 8; path = fhs.make; sourceTree = ""; tabWidth = 8; }; + ADD1FC9906E4D6D400E387F0 /* iCalEventChanges.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalEventChanges.h; sourceTree = ""; }; + ADD1FC9A06E4D6D400E387F0 /* iCalEventChanges.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalEventChanges.m; sourceTree = ""; }; + 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 = ""; }; + ADDF4F1206DE513D00C4E7F8 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 8; lastKnownFileType = text; path = ChangeLog; sourceTree = ""; tabWidth = 8; usesTabs = 1; }; + ADDF4F1306DE513D00C4E7F8 /* common.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; + ADDF4F1406DE513D00C4E7F8 /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYING; sourceTree = ""; }; + ADDF4F1506DE513D00C4E7F8 /* COPYRIGHT */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYRIGHT; sourceTree = ""; }; + ADDF4F1606DE513D00C4E7F8 /* GNUmakefile */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; indentWidth = 8; path = GNUmakefile; sourceTree = ""; tabWidth = 8; usesTabs = 1; }; + ADDF4F1706DE513D00C4E7F8 /* GNUmakefile.postamble */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; indentWidth = 8; path = GNUmakefile.postamble; sourceTree = ""; tabWidth = 8; usesTabs = 1; }; + ADDF4F1806DE513D00C4E7F8 /* GNUmakefile.preamble */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; indentWidth = 8; path = GNUmakefile.preamble; sourceTree = ""; tabWidth = 8; usesTabs = 1; }; + ADDF4F1906DE513D00C4E7F8 /* iCalAlarm.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalAlarm.h; sourceTree = ""; }; + ADDF4F1A06DE513D00C4E7F8 /* iCalAlarm.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalAlarm.m; sourceTree = ""; }; + ADDF4F1B06DE513D00C4E7F8 /* iCalAttachment.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalAttachment.h; sourceTree = ""; }; + ADDF4F1C06DE513D00C4E7F8 /* iCalAttachment.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalAttachment.m; sourceTree = ""; }; + ADDF4F1D06DE513D00C4E7F8 /* iCalCalendar.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalCalendar.h; sourceTree = ""; }; + ADDF4F1E06DE513D00C4E7F8 /* iCalCalendar.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalCalendar.m; sourceTree = ""; }; + ADDF4F1F06DE513D00C4E7F8 /* iCalDataSource.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalDataSource.h; sourceTree = ""; }; + ADDF4F2006DE513D00C4E7F8 /* iCalDataSource.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalDataSource.m; sourceTree = ""; }; + ADDF4F2106DE513D00C4E7F8 /* iCalDateHolder.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalDateHolder.h; sourceTree = ""; }; + ADDF4F2206DE513D00C4E7F8 /* iCalDateHolder.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalDateHolder.m; sourceTree = ""; }; + ADDF4F2306DE513D00C4E7F8 /* iCalDuration.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalDuration.h; sourceTree = ""; }; + ADDF4F2406DE513D00C4E7F8 /* iCalDuration.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalDuration.m; sourceTree = ""; }; + ADDF4F2506DE513D00C4E7F8 /* IcalElements.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = IcalElements.m; sourceTree = ""; }; + ADDF4F2606DE513D00C4E7F8 /* iCalEntityObject.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalEntityObject.h; sourceTree = ""; }; + ADDF4F2706DE513D00C4E7F8 /* iCalEntityObject.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalEntityObject.m; sourceTree = ""; }; + ADDF4F2806DE513D00C4E7F8 /* iCalEvent.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalEvent.h; sourceTree = ""; }; + ADDF4F2906DE513D00C4E7F8 /* iCalEvent.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalEvent.m; sourceTree = ""; }; + ADDF4F2A06DE513D00C4E7F8 /* iCalFreeBusy.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalFreeBusy.h; sourceTree = ""; }; + ADDF4F2B06DE513D00C4E7F8 /* iCalFreeBusy.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalFreeBusy.m; sourceTree = ""; }; + ADDF4F2C06DE513D00C4E7F8 /* iCalJournal.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalJournal.h; sourceTree = ""; }; + ADDF4F2D06DE513D00C4E7F8 /* iCalJournal.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalJournal.m; sourceTree = ""; }; + ADDF4F2E06DE513D00C4E7F8 /* iCalObject.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalObject.h; sourceTree = ""; }; + ADDF4F2F06DE513D00C4E7F8 /* iCalObject.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalObject.m; sourceTree = ""; }; + ADDF4F3006DE513D00C4E7F8 /* iCalPerson.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalPerson.h; sourceTree = ""; }; + ADDF4F3106DE513D00C4E7F8 /* iCalPerson.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalPerson.m; sourceTree = ""; }; + ADDF4F3206DE513D00C4E7F8 /* IcalResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = IcalResponse.h; sourceTree = ""; }; + ADDF4F3306DE513D00C4E7F8 /* IcalResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = IcalResponse.m; sourceTree = ""; }; + ADDF4F3406DE513D00C4E7F8 /* iCalToDo.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalToDo.h; sourceTree = ""; }; + ADDF4F3506DE513D00C4E7F8 /* iCalToDo.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalToDo.m; sourceTree = ""; }; + ADDF4F3606DE513D00C4E7F8 /* iCalTrigger.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = iCalTrigger.h; sourceTree = ""; }; + ADDF4F3706DE513D00C4E7F8 /* iCalTrigger.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = iCalTrigger.m; sourceTree = ""; }; + ADDF4F3806DE513D00C4E7F8 /* NGCards.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = NGCards.h; sourceTree = ""; }; + ADDF4F3906DE513D00C4E7F8 /* NGCards.xmap */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text.xml; path = NGCards.xmap; sourceTree = ""; }; + ADDF4F3A06DE513D00C4E7F8 /* NSCalendarDate+ICal.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = "NSCalendarDate+ICal.h"; sourceTree = ""; }; + ADDF4F3B06DE513D00C4E7F8 /* NSCalendarDate+ICal.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "NSCalendarDate+ICal.m"; sourceTree = ""; }; + ADDF4F3C06DE513D00C4E7F8 /* NSString+ICal.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = "NSString+ICal.h"; sourceTree = ""; }; + ADDF4F3D06DE513D00C4E7F8 /* NSString+ICal.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "NSString+ICal.m"; sourceTree = ""; }; + ADDF4F3E06DE513D00C4E7F8 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; + ADDF4F3F06DE513D00C4E7F8 /* Version */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; indentWidth = 8; path = Version; sourceTree = ""; tabWidth = 8; usesTabs = 1; }; + ADDF503B06DE528200C4E7F8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + ADDF503D06DE52F600C4E7F8 /* DOM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DOM.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/DOM.framework"; sourceTree = ""; }; + ADDF503E06DE52F600C4E7F8 /* EOControl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = EOControl.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/EOControl.framework"; sourceTree = ""; }; + ADDF503F06DE52F600C4E7F8 /* NGExtensions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NGExtensions.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/NGExtensions.framework"; sourceTree = ""; }; + ADDF504006DE52F600C4E7F8 /* SaxObjC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SaxObjC.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/SaxObjC.framework"; sourceTree = ""; }; +/* 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 = ""; + }; + AD596D830837698200C4D81D /* vCard */ = { + isa = PBXGroup; + children = ( + AD596D860837699600C4D81D /* Headers */, + AD596D890837699A00C4D81D /* Classes */, + ); + name = vCard; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + ADAACFFF07B6AF0E00FC48D6 /* Unit Tests */ = { + isa = PBXGroup; + children = ( + ADAAD04007B6B02400FC48D6 /* README */, + ADAAD01F07B6AFA600FC48D6 /* Classes */, + ADAAD05C07B6B0CB00FC48D6 /* Resources */, + ); + fileEncoding = 5; + indentWidth = 2; + name = "Unit Tests"; + path = tests; + sourceTree = ""; + }; + ADAAD01F07B6AFA600FC48D6 /* Classes */ = { + isa = PBXGroup; + children = ( + ADAAD04107B6B05000FC48D6 /* common.h */, + ADAAD02107B6AFD700FC48D6 /* iCalRecurrenceCalculatorTests.m */, + ); + name = Classes; + sourceTree = ""; + }; + ADAAD05C07B6B0CB00FC48D6 /* Resources */ = { + isa = PBXGroup; + children = ( + ADAACFEC07B6AEB500FC48D6 /* NGCardsTests-Info.plist */, + ); + name = Resources; + sourceTree = ""; + }; + 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 = ""; + }; + ADDF4E6106DE4FF200C4E7F8 /* Products */ = { + isa = PBXGroup; + children = ( + ADDF4E6006DE4FF200C4E7F8 /* NGCards.framework */, + ADAACFEB07B6AEB500FC48D6 /* NGCardsTests.framework */, + ); + name = Products; + sourceTree = ""; + }; + ADDF4E6506DE500200C4E7F8 /* Resources */ = { + isa = PBXGroup; + children = ( + ADDF4E6206DE4FF200C4E7F8 /* NGCards-Info.plist */, + ADDF4F3906DE513D00C4E7F8 /* NGCards.xmap */, + ); + name = Resources; + sourceTree = ""; + }; + ADDF4F7006DE514B00C4E7F8 /* Makefiles */ = { + isa = PBXGroup; + children = ( + ADDF4F1606DE513D00C4E7F8 /* GNUmakefile */, + ADDF4F1806DE513D00C4E7F8 /* GNUmakefile.preamble */, + ADDF4F1706DE513D00C4E7F8 /* GNUmakefile.postamble */, + ADBE3DFE072713DB000FEA6A /* fhs.make */, + ); + name = Makefiles; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + ADDF510206DE54BE00C4E7F8 /* sope-xml */ = { + isa = PBXGroup; + children = ( + ADDF504006DE52F600C4E7F8 /* SaxObjC.framework */, + ADDF503D06DE52F600C4E7F8 /* DOM.framework */, + AD8BF0F70701902800EC239A /* XmlRpc.framework */, + ); + name = "sope-xml"; + sourceTree = ""; + }; +/* 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 = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGCardsTests + CFBundleGetInfoString + + CFBundleIdentifier + com.MySoftwareCompany.NGCardsTests + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + + +"; + 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 = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGCards + CFBundleIdentifier + com.yourcompany.NGCards + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + 1.0 + + +"; + 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 */; +} diff --git a/SOPE/NGCards/NGCards.xmap b/SOPE/NGCards/NGCards.xmap new file mode 100644 index 00000000..182db0bb --- /dev/null +++ b/SOPE/NGCards/NGCards.xmap @@ -0,0 +1,313 @@ +{ + "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; + }; + }; +} diff --git a/SOPE/NGCards/NGCardsSaxHandler.h b/SOPE/NGCards/NGCardsSaxHandler.h new file mode 100644 index 00000000..5472fe59 --- /dev/null +++ b/SOPE/NGCards/NGCardsSaxHandler.h @@ -0,0 +1,94 @@ +/* + 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 + +/* + 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__ */ diff --git a/SOPE/NGCards/NGCardsSaxHandler.m b/SOPE/NGCards/NGCardsSaxHandler.m new file mode 100644 index 00000000..8c77b557 --- /dev/null +++ b/SOPE/NGCards/NGCardsSaxHandler.m @@ -0,0 +1,326 @@ +/* + 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 + +#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) _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)_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 */ diff --git a/SOPE/NGCards/NGVCard.h b/SOPE/NGCards/NGVCard.h new file mode 100644 index 00000000..7b9f69ee --- /dev/null +++ b/SOPE/NGCards/NGVCard.h @@ -0,0 +1,155 @@ +/* + 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: + + + + + + + + + + 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__ */ diff --git a/SOPE/NGCards/NGVCard.m b/SOPE/NGCards/NGVCard.m new file mode 100644 index 00000000..21add8fb --- /dev/null +++ b/SOPE/NGCards/NGVCard.m @@ -0,0 +1,521 @@ +/* + 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 +#import +#import + +#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 */ diff --git a/SOPE/NGCards/NSArray+NGCards.h b/SOPE/NGCards/NSArray+NGCards.h new file mode 100644 index 00000000..0d2ba14f --- /dev/null +++ b/SOPE/NGCards/NSArray+NGCards.h @@ -0,0 +1,42 @@ +/* NSArray+NGCards.h - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 + +@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 */ diff --git a/SOPE/NGCards/NSArray+NGCards.m b/SOPE/NGCards/NSArray+NGCards.m new file mode 100644 index 00000000..9c87ab36 --- /dev/null +++ b/SOPE/NGCards/NSArray+NGCards.m @@ -0,0 +1,133 @@ +/* NSArray+NGCards.m - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 + +#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 diff --git a/SOPE/NGCards/NSCalendarDate+ICal.h b/SOPE/NGCards/NSCalendarDate+ICal.h new file mode 100644 index 00000000..1f10eac2 --- /dev/null +++ b/SOPE/NGCards/NSCalendarDate+ICal.h @@ -0,0 +1,46 @@ +/* + 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 + +@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__ */ diff --git a/SOPE/NGCards/NSCalendarDate+ICal.m b/SOPE/NGCards/NSCalendarDate+ICal.m new file mode 100644 index 00000000..7e420198 --- /dev/null +++ b/SOPE/NGCards/NSCalendarDate+ICal.m @@ -0,0 +1,145 @@ +/* + 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) */ diff --git a/SOPE/NGCards/NSCalendarDate+NGCards.h b/SOPE/NGCards/NSCalendarDate+NGCards.h new file mode 100644 index 00000000..bbdc9adc --- /dev/null +++ b/SOPE/NGCards/NSCalendarDate+NGCards.h @@ -0,0 +1,38 @@ +/* NSDate+NGCards.h - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 +#import + +#import "CardElement.h" + +@interface NSDate (NGCardsExtensions) + +- (NSString *) iCalFormattedDateTimeString; +- (NSString *) iCalFormattedDateString; + +@end + +#endif /* NSDATE_NGCARDS_H */ diff --git a/SOPE/NGCards/NSCalendarDate+NGCards.m b/SOPE/NGCards/NSCalendarDate+NGCards.m new file mode 100644 index 00000000..d4620e45 --- /dev/null +++ b/SOPE/NGCards/NSCalendarDate+NGCards.m @@ -0,0 +1,47 @@ +/* NSDate+NGCards.m - this file is part of SOGo + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 + +#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 diff --git a/SOPE/NGCards/NSDictionary+NGCards.h b/SOPE/NGCards/NSDictionary+NGCards.h new file mode 100644 index 00000000..97d464d4 --- /dev/null +++ b/SOPE/NGCards/NSDictionary+NGCards.h @@ -0,0 +1,34 @@ +/* NSDictionary+NGCards.h - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 + +@interface NSDictionary (NGCardsExtensions) + +- (id) objectForCaseInsensitiveKey: (NSString *) aKey; + +@end + +#endif /* NSDICTIONARY_NGCARDS_H */ diff --git a/SOPE/NGCards/NSDictionary+NGCards.m b/SOPE/NGCards/NSDictionary+NGCards.m new file mode 100644 index 00000000..2e775465 --- /dev/null +++ b/SOPE/NGCards/NSDictionary+NGCards.m @@ -0,0 +1,40 @@ +/* NSDictionary+NGCards.m - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 diff --git a/SOPE/NGCards/NSString+NGCards.h b/SOPE/NGCards/NSString+NGCards.h new file mode 100644 index 00000000..2b57059a --- /dev/null +++ b/SOPE/NGCards/NSString+NGCards.h @@ -0,0 +1,45 @@ +/* NSString+NGCards.h - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 + +@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 */ diff --git a/SOPE/NGCards/NSString+NGCards.m b/SOPE/NGCards/NSString+NGCards.m new file mode 100644 index 00000000..768009d2 --- /dev/null +++ b/SOPE/NGCards/NSString+NGCards.m @@ -0,0 +1,272 @@ +/* NSString+NGCards.m - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 +#import +#import +#import + +#import + +#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 diff --git a/SOPE/NGCards/README b/SOPE/NGCards/README new file mode 100644 index 00000000..8497a5be --- /dev/null +++ b/SOPE/NGCards/README @@ -0,0 +1,19 @@ +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. diff --git a/SOPE/NGCards/Version b/SOPE/NGCards/Version new file mode 100644 index 00000000..dbc6c2d3 --- /dev/null +++ b/SOPE/NGCards/Version @@ -0,0 +1,8 @@ +# 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 diff --git a/SOPE/NGCards/common.h b/SOPE/NGCards/common.h new file mode 100644 index 00000000..0ffdb574 --- /dev/null +++ b/SOPE/NGCards/common.h @@ -0,0 +1,45 @@ +/* + 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 +#import +#include + +#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__ */ diff --git a/SOPE/NGCards/iCalAlarm.h b/SOPE/NGCards/iCalAlarm.h new file mode 100644 index 00000000..1f975471 --- /dev/null +++ b/SOPE/NGCards/iCalAlarm.h @@ -0,0 +1,44 @@ +/* + 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__ */ diff --git a/SOPE/NGCards/iCalAlarm.m b/SOPE/NGCards/iCalAlarm.m new file mode 100644 index 00000000..2d6a95b7 --- /dev/null +++ b/SOPE/NGCards/iCalAlarm.m @@ -0,0 +1,105 @@ +/* + 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 */ diff --git a/SOPE/NGCards/iCalAttachment.h b/SOPE/NGCards/iCalAttachment.h new file mode 100644 index 00000000..0b326b7c --- /dev/null +++ b/SOPE/NGCards/iCalAttachment.h @@ -0,0 +1,39 @@ +/* + 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__ */ diff --git a/SOPE/NGCards/iCalAttachment.m b/SOPE/NGCards/iCalAttachment.m new file mode 100644 index 00000000..b115e099 --- /dev/null +++ b/SOPE/NGCards/iCalAttachment.m @@ -0,0 +1,49 @@ +/* + 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 */ diff --git a/SOPE/NGCards/iCalCalendar.h b/SOPE/NGCards/iCalCalendar.h new file mode 100644 index 00000000..074352ed --- /dev/null +++ b/SOPE/NGCards/iCalCalendar.h @@ -0,0 +1,85 @@ +/* + 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__ */ diff --git a/SOPE/NGCards/iCalCalendar.m b/SOPE/NGCards/iCalCalendar.m new file mode 100644 index 00000000..060509ee --- /dev/null +++ b/SOPE/NGCards/iCalCalendar.m @@ -0,0 +1,209 @@ +/* + 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 +#import + +#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 */ diff --git a/SOPE/NGCards/iCalDailyRecurrenceCalculator.m b/SOPE/NGCards/iCalDailyRecurrenceCalculator.m new file mode 100644 index 00000000..6ba00f16 --- /dev/null +++ b/SOPE/NGCards/iCalDailyRecurrenceCalculator.m @@ -0,0 +1,125 @@ +/* + 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 +#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 */ diff --git a/SOPE/NGCards/iCalDataSource.h b/SOPE/NGCards/iCalDataSource.h new file mode 100644 index 00000000..770987bb --- /dev/null +++ b/SOPE/NGCards/iCalDataSource.h @@ -0,0 +1,53 @@ +/* + 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 + +@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__ */ diff --git a/SOPE/NGCards/iCalDataSource.m b/SOPE/NGCards/iCalDataSource.m new file mode 100644 index 00000000..b84c3940 --- /dev/null +++ b/SOPE/NGCards/iCalDataSource.m @@ -0,0 +1,247 @@ +/* + 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 +#include "common.h" + +@interface NSObject(suppressCapitalizedKeyWarning) ++ (void)suppressCapitalizedKeyWarning; +@end + +@implementation iCalDataSource + +// THREAD +static id 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)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 */ diff --git a/SOPE/NGCards/iCalDateHolder.h b/SOPE/NGCards/iCalDateHolder.h new file mode 100644 index 00000000..fa620273 --- /dev/null +++ b/SOPE/NGCards/iCalDateHolder.h @@ -0,0 +1,49 @@ +/* + 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 + +@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__ */ diff --git a/SOPE/NGCards/iCalDateHolder.m b/SOPE/NGCards/iCalDateHolder.m new file mode 100644 index 00000000..91c4e0a8 --- /dev/null +++ b/SOPE/NGCards/iCalDateHolder.m @@ -0,0 +1,232 @@ +/* + 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) */ diff --git a/SOPE/NGCards/iCalDateTime.h b/SOPE/NGCards/iCalDateTime.h new file mode 100644 index 00000000..a3fa2c12 --- /dev/null +++ b/SOPE/NGCards/iCalDateTime.h @@ -0,0 +1,41 @@ +/* iCalDateTime.h - this file is part of SOGo + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 */ diff --git a/SOPE/NGCards/iCalDateTime.m b/SOPE/NGCards/iCalDateTime.m new file mode 100644 index 00000000..b0f1a19f --- /dev/null +++ b/SOPE/NGCards/iCalDateTime.m @@ -0,0 +1,155 @@ +/* iCalDateTime.m - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 +#import + +#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 diff --git a/SOPE/NGCards/iCalEntityObject.h b/SOPE/NGCards/iCalEntityObject.h new file mode 100644 index 00000000..0f748939 --- /dev/null +++ b/SOPE/NGCards/iCalEntityObject.h @@ -0,0 +1,113 @@ +/* + 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__ */ diff --git a/SOPE/NGCards/iCalEntityObject.m b/SOPE/NGCards/iCalEntityObject.m new file mode 100644 index 00000000..d45de9d0 --- /dev/null +++ b/SOPE/NGCards/iCalEntityObject.m @@ -0,0 +1,399 @@ +/* + 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 */ diff --git a/SOPE/NGCards/iCalEvent.h b/SOPE/NGCards/iCalEvent.h new file mode 100644 index 00000000..608b0585 --- /dev/null +++ b/SOPE/NGCards/iCalEvent.h @@ -0,0 +1,74 @@ +/* + 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__ */ diff --git a/SOPE/NGCards/iCalEvent.m b/SOPE/NGCards/iCalEvent.m new file mode 100644 index 00000000..d237619f --- /dev/null +++ b/SOPE/NGCards/iCalEvent.m @@ -0,0 +1,260 @@ +/* + 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 + +#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 */ diff --git a/SOPE/NGCards/iCalEventChanges.h b/SOPE/NGCards/iCalEventChanges.h new file mode 100644 index 00000000..b2fc90a9 --- /dev/null +++ b/SOPE/NGCards/iCalEventChanges.h @@ -0,0 +1,61 @@ +/* + 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 + +@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_ */ diff --git a/SOPE/NGCards/iCalEventChanges.m b/SOPE/NGCards/iCalEventChanges.m new file mode 100644 index 00000000..6a7401c1 --- /dev/null +++ b/SOPE/NGCards/iCalEventChanges.m @@ -0,0 +1,211 @@ +/* + 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 diff --git a/SOPE/NGCards/iCalFreeBusy.h b/SOPE/NGCards/iCalFreeBusy.h new file mode 100644 index 00000000..8e744025 --- /dev/null +++ b/SOPE/NGCards/iCalFreeBusy.h @@ -0,0 +1,52 @@ +/* + 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__ */ diff --git a/SOPE/NGCards/iCalFreeBusy.m b/SOPE/NGCards/iCalFreeBusy.m new file mode 100644 index 00000000..efae27e7 --- /dev/null +++ b/SOPE/NGCards/iCalFreeBusy.m @@ -0,0 +1,121 @@ +/* + 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 +#import +#import + +#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 */ diff --git a/SOPE/NGCards/iCalJournal.h b/SOPE/NGCards/iCalJournal.h new file mode 100644 index 00000000..62a5ec4e --- /dev/null +++ b/SOPE/NGCards/iCalJournal.h @@ -0,0 +1,33 @@ +/* + 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__ */ diff --git a/SOPE/NGCards/iCalJournal.m b/SOPE/NGCards/iCalJournal.m new file mode 100644 index 00000000..3c158772 --- /dev/null +++ b/SOPE/NGCards/iCalJournal.m @@ -0,0 +1,36 @@ +/* + 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 */ diff --git a/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m b/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m new file mode 100644 index 00000000..b2809eda --- /dev/null +++ b/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m @@ -0,0 +1,406 @@ +/* + 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 +#include "iCalRecurrenceRule.h" +#include "NSCalendarDate+ICal.h" +#include "common.h" +#include + +@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 */ diff --git a/SOPE/NGCards/iCalObject.h b/SOPE/NGCards/iCalObject.h new file mode 100644 index 00000000..5369d0e1 --- /dev/null +++ b/SOPE/NGCards/iCalObject.h @@ -0,0 +1,51 @@ +/* + 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 +#import + +/* + iCalObject + + A common base class for all iCal objects. Does some patches on key-value + coding. +*/ + +@class NSTimeZone; + +@interface iCalObject : NSObject +{ +} + +// what shall we take, if no timeZone is specified in dateValues ++ (void)setICalDefaultTimeZone:(NSTimeZone *)_timeZone; ++ (NSTimeZone *)iCalDefaultTimeZone; + +@end + + + +#endif /* __NGiCal_iCalObject_H__ */ diff --git a/SOPE/NGCards/iCalObject.m b/SOPE/NGCards/iCalObject.m new file mode 100644 index 00000000..71f4597c --- /dev/null +++ b/SOPE/NGCards/iCalObject.m @@ -0,0 +1,69 @@ +/* + 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 */ diff --git a/SOPE/NGCards/iCalPerson.h b/SOPE/NGCards/iCalPerson.h new file mode 100644 index 00000000..222de9e3 --- /dev/null +++ b/SOPE/NGCards/iCalPerson.h @@ -0,0 +1,77 @@ +/* + 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__ */ diff --git a/SOPE/NGCards/iCalPerson.m b/SOPE/NGCards/iCalPerson.m new file mode 100644 index 00000000..e22a81ab --- /dev/null +++ b/SOPE/NGCards/iCalPerson.m @@ -0,0 +1,230 @@ +/* + 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 */ diff --git a/SOPE/NGCards/iCalRecurrenceCalculator.h b/SOPE/NGCards/iCalRecurrenceCalculator.h new file mode 100644 index 00000000..6dc92a83 --- /dev/null +++ b/SOPE/NGCards/iCalRecurrenceCalculator.h @@ -0,0 +1,67 @@ +/* + 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 + +/* + 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_ */ diff --git a/SOPE/NGCards/iCalRecurrenceCalculator.m b/SOPE/NGCards/iCalRecurrenceCalculator.m new file mode 100644 index 00000000..d144efea --- /dev/null +++ b/SOPE/NGCards/iCalRecurrenceCalculator.m @@ -0,0 +1,301 @@ +/* + 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 +#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 */ diff --git a/SOPE/NGCards/iCalRecurrenceRule.h b/SOPE/NGCards/iCalRecurrenceRule.h new file mode 100644 index 00000000..53a254e7 --- /dev/null +++ b/SOPE/NGCards/iCalRecurrenceRule.h @@ -0,0 +1,116 @@ +/* + 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_ */ diff --git a/SOPE/NGCards/iCalRecurrenceRule.m b/SOPE/NGCards/iCalRecurrenceRule.m new file mode 100644 index 00000000..4292d37b --- /dev/null +++ b/SOPE/NGCards/iCalRecurrenceRule.m @@ -0,0 +1,631 @@ +/* + 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 +#import +#import + +#import + +#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 */ diff --git a/SOPE/NGCards/iCalRepeatableEntityObject.h b/SOPE/NGCards/iCalRepeatableEntityObject.h new file mode 100644 index 00000000..d3225468 --- /dev/null +++ b/SOPE/NGCards/iCalRepeatableEntityObject.h @@ -0,0 +1,70 @@ +/* + 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_ */ diff --git a/SOPE/NGCards/iCalRepeatableEntityObject.m b/SOPE/NGCards/iCalRepeatableEntityObject.m new file mode 100644 index 00000000..1a772d02 --- /dev/null +++ b/SOPE/NGCards/iCalRepeatableEntityObject.m @@ -0,0 +1,182 @@ +/* + 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 +#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 diff --git a/SOPE/NGCards/iCalTimeZone.h b/SOPE/NGCards/iCalTimeZone.h new file mode 100644 index 00000000..ba621184 --- /dev/null +++ b/SOPE/NGCards/iCalTimeZone.h @@ -0,0 +1,39 @@ +/* iCalTimeZone.h - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 */ diff --git a/SOPE/NGCards/iCalTimeZone.m b/SOPE/NGCards/iCalTimeZone.m new file mode 100644 index 00000000..51bd3729 --- /dev/null +++ b/SOPE/NGCards/iCalTimeZone.m @@ -0,0 +1,132 @@ +/* iCalTimeZone.m - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 +#import +#import + +#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 diff --git a/SOPE/NGCards/iCalTimeZonePeriod.h b/SOPE/NGCards/iCalTimeZonePeriod.h new file mode 100644 index 00000000..d7d54f88 --- /dev/null +++ b/SOPE/NGCards/iCalTimeZonePeriod.h @@ -0,0 +1,35 @@ +/* iCalTimeZonePeriod.h - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 */ diff --git a/SOPE/NGCards/iCalTimeZonePeriod.m b/SOPE/NGCards/iCalTimeZonePeriod.m new file mode 100644 index 00000000..03d6cb4b --- /dev/null +++ b/SOPE/NGCards/iCalTimeZonePeriod.m @@ -0,0 +1,140 @@ +/* iCalTimeZonePeriod.m - this file is part of SOPE + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 +#import + +#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 diff --git a/SOPE/NGCards/iCalToDo.h b/SOPE/NGCards/iCalToDo.h new file mode 100644 index 00000000..1ec31260 --- /dev/null +++ b/SOPE/NGCards/iCalToDo.h @@ -0,0 +1,49 @@ +/* + 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__ */ diff --git a/SOPE/NGCards/iCalToDo.m b/SOPE/NGCards/iCalToDo.m new file mode 100644 index 00000000..e5e2c0a1 --- /dev/null +++ b/SOPE/NGCards/iCalToDo.m @@ -0,0 +1,117 @@ +/* + 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 + +#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 */ diff --git a/SOPE/NGCards/iCalTrigger.h b/SOPE/NGCards/iCalTrigger.h new file mode 100644 index 00000000..811b6386 --- /dev/null +++ b/SOPE/NGCards/iCalTrigger.h @@ -0,0 +1,37 @@ +/* + 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__ */ diff --git a/SOPE/NGCards/iCalTrigger.m b/SOPE/NGCards/iCalTrigger.m new file mode 100644 index 00000000..ac26958f --- /dev/null +++ b/SOPE/NGCards/iCalTrigger.m @@ -0,0 +1,49 @@ +/* + 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 */ diff --git a/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m b/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m new file mode 100644 index 00000000..1db42c84 --- /dev/null +++ b/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m @@ -0,0 +1,190 @@ +/* + 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 +#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 */ diff --git a/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m b/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m new file mode 100644 index 00000000..b940b26a --- /dev/null +++ b/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m @@ -0,0 +1,100 @@ +/* + 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 +#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 */ diff --git a/SOPE/NGCards/samples/COPYING b/SOPE/NGCards/samples/COPYING new file mode 100644 index 00000000..161a3d1d --- /dev/null +++ b/SOPE/NGCards/samples/COPYING @@ -0,0 +1,482 @@ + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/SOPE/NGCards/samples/ChangeLog b/SOPE/NGCards/samples/ChangeLog new file mode 100644 index 00000000..611bc48d --- /dev/null +++ b/SOPE/NGCards/samples/ChangeLog @@ -0,0 +1,157 @@ +2005-09-19 Helge Hess + + * ievalrrule.m: started tool to evaluate iCal rrules on the shell + +2005-08-16 Helge Hess + + * link tools against OSX frameworks if configured so + +2005-05-06 Helge Hess + + * renamed ical3.m to icalds.m, ical2.m to icalparsetest + +2005-04-25 Helge Hess + + * properly include config.make + + * fixed some gcc 4.0 warnings + +2004-09-26 Helge Hess + + * GNUmakefile.preamble: fixed makefiles for SOPE inline compilation + +2004-08-29 Helge Hess + + * 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 + + * subclassing.m: fixed a compiler warning + +2004-07-09 Helge Hess + + * bmlookup.m: major code cleanups, improved output + +2004-06-27 Helge Hess + + * ldap2dsml.m: fixed a compile warning + +2004-06-21 Helge Hess + + * common.h: fixed compatibility with gstep-base + +2004-06-17 Helge Hess + + * added 'testurl' to test NSURL for the Cocoa Foundation bug wrt the + trailing suffix in -path + +2004-05-09 Helge Hess + + * subclassing.m: added support for Apple runtime + +2004-04-12 Helge Hess + + * ImapListTool, ImapTool.m, imapls.m: minor code cleanups + +2004-01-19 Helge Hess + + * ldapls.m: minor fixes (moved NSAutoreleasePool to correct place) + +2004-01-11 Helge Hess + + * minor cleanups to log messages + +2003-10-12 Helge Hess + + * 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 + + * added parserule for testing parsing of NGRule objects + +2003-05-14 Helge Hess + + * some gcc 3.3 warnings fixed + +2003-04-03 Helge Hess + + * GNUmakefile: added ldapchkpwd tool + + * ldap2dsml.m: added autorelease-pool to main() + +2003-04-01 GNUstep User + + * ImapListTool.m: do not use NSFileIdentifier constant + + * EncodingTool.m: removed some undeclared encodings when compiling for + GNUstep Base + +2003-02-12 Helge Hess + + * added ical2.m, ical3.m - examples for NGiCal + +2003-01-30 Helge Hess + + * added httpu_notify, a small tool to send out HTTP-over-UDP + NOTIFY notifications + +2003-01-08 Helge Hess + + * testsock.m: improved test code + +2003-01-07 Helge Hess + + * 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 + + * Mime2XmlTool.m: fixed a protocol warning + +Mon Dec 23 15:36:01 2002 Helge Hess + + * ImapListTool.m: pass correct filemanager as a parameter + +2002-12-08 Helge Hess + + * testdirenum.m: cleanups + +Tue Dec 17 15:07:40 2002 + + * imapquota.m: add quota test + +2002-11-21 Jan Reichmann + + * added Imap-Super class, improve imapls + +2002-11-21 Helge Hess + + * added ldapls, ldap2dsml as examples for NGLdap + +2002-11-15 Helge Hess + + * EOQualTool.m: added test for complex cast + +2002-10-29 Helge Hess + + * EOQualTool.m: added support for parsing SQL using the new EOSQLParser + +2002-10-25 Helge Hess + + * added eoqual tool for parsing EOQualifier's (useful for syntax + checks) + + * created ChangeLog + diff --git a/SOPE/NGCards/samples/GNUmakefile b/SOPE/NGCards/samples/GNUmakefile new file mode 100644 index 00000000..b7a0389c --- /dev/null +++ b/SOPE/NGCards/samples/GNUmakefile @@ -0,0 +1,43 @@ +# 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 diff --git a/SOPE/NGCards/samples/GNUmakefile.preamble b/SOPE/NGCards/samples/GNUmakefile.preamble new file mode 100644 index 00000000..db95dc45 --- /dev/null +++ b/SOPE/NGCards/samples/GNUmakefile.preamble @@ -0,0 +1,64 @@ +# 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 diff --git a/SOPE/NGCards/samples/README b/SOPE/NGCards/samples/README new file mode 100644 index 00000000..6b22a35d --- /dev/null +++ b/SOPE/NGCards/samples/README @@ -0,0 +1,9 @@ +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 diff --git a/SOPE/NGCards/samples/common.h b/SOPE/NGCards/samples/common.h new file mode 100644 index 00000000..98f27bd5 --- /dev/null +++ b/SOPE/NGCards/samples/common.h @@ -0,0 +1,31 @@ +/* + 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 + +#if LIB_FOUNDATION_LIBRARY +# include +#else +# include +# include +#endif + +#include diff --git a/SOPE/NGCards/samples/fhs.make b/SOPE/NGCards/samples/fhs.make new file mode 100644 index 00000000..27c85d13 --- /dev/null +++ b/SOPE/NGCards/samples/fhs.make @@ -0,0 +1,26 @@ +# 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 diff --git a/SOPE/NGCards/samples/icalds.m b/SOPE/NGCards/samples/icalds.m new file mode 100644 index 00000000..1ae3106b --- /dev/null +++ b/SOPE/NGCards/samples/icalds.m @@ -0,0 +1,167 @@ +/* + 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 + +@class EOQualifier, NSString, EOSortOrdering; + +@interface iCal3Tool : NSObject +{ + EOQualifier *qualifier; + NSString *entityName; + NSArray *sortOrderings; +} + +- (int)runWithArguments:(NSArray *)_args; + +@end + +#include +#include +#include +#include +#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; +} diff --git a/SOPE/NGCards/samples/icalparsetest.m b/SOPE/NGCards/samples/icalparsetest.m new file mode 100644 index 00000000..c00f6601 --- /dev/null +++ b/SOPE/NGCards/samples/icalparsetest.m @@ -0,0 +1,154 @@ +/* + 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 +#include + +@interface iCal2Tool : NSObject +{ + id 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; +} diff --git a/SOPE/NGCards/samples/ievalrrule.m b/SOPE/NGCards/samples/ievalrrule.m new file mode 100644 index 00000000..38e8c864 --- /dev/null +++ b/SOPE/NGCards/samples/ievalrrule.m @@ -0,0 +1,166 @@ +/* + 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 +#include +#include +#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 \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; +} diff --git a/SOPE/NGCards/samples/unittest.h b/SOPE/NGCards/samples/unittest.h new file mode 100644 index 00000000..305e8317 --- /dev/null +++ b/SOPE/NGCards/samples/unittest.h @@ -0,0 +1,88 @@ +/* unittest.h - this file is part of $PROJECT_NAME_HERE$ + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 + +@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 */ diff --git a/SOPE/NGCards/samples/unittest.m b/SOPE/NGCards/samples/unittest.m new file mode 100644 index 00000000..34e16442 --- /dev/null +++ b/SOPE/NGCards/samples/unittest.m @@ -0,0 +1,98 @@ +/* unittest.m - this file is part of $PROJECT_NAME_HERE$ + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 +#import + +#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 diff --git a/SOPE/NGCards/samples/vcardtest.m b/SOPE/NGCards/samples/vcardtest.m new file mode 100644 index 00000000..dfeb557c --- /dev/null +++ b/SOPE/NGCards/samples/vcardtest.m @@ -0,0 +1,369 @@ +/* vcardtest.m - this file is part of $PROJECT_NAME_HERE$ + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 + +#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; +} diff --git a/SOPE/NGCards/samples/vcf2xml.m b/SOPE/NGCards/samples/vcf2xml.m new file mode 100644 index 00000000..3f56c2c8 --- /dev/null +++ b/SOPE/NGCards/samples/vcf2xml.m @@ -0,0 +1,342 @@ +/* + 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 +#include + +@interface vcf2xml : NSObject +{ + id 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)_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)_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("\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; +} diff --git a/SOPE/NGCards/samples/vcfparsetest.m b/SOPE/NGCards/samples/vcfparsetest.m new file mode 100644 index 00000000..8b846057 --- /dev/null +++ b/SOPE/NGCards/samples/vcfparsetest.m @@ -0,0 +1,135 @@ +/* + 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 +#import + +@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; +} diff --git a/SOPE/NGCards/samples/versittest.m b/SOPE/NGCards/samples/versittest.m new file mode 100644 index 00000000..ec314f5a --- /dev/null +++ b/SOPE/NGCards/samples/versittest.m @@ -0,0 +1,218 @@ +/* versittest.m - this file is part of $PROJECT_NAME_HERE$ + * + * Copyright (C) 2006 Inverse groupe conseil + * + * Author: Wolfgang Sourdeau + * + * 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 + +#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 (@" + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NGiCalTests + CFBundleGetInfoString + + CFBundleIdentifier + org.OpenGroupware.SOPE.ical.NGiCalTests + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 4.5 + + diff --git a/SOPE/NGCards/tests/README b/SOPE/NGCards/tests/README new file mode 100644 index 00000000..5541041c --- /dev/null +++ b/SOPE/NGCards/tests/README @@ -0,0 +1,8 @@ +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 diff --git a/SOPE/NGCards/tests/common.h b/SOPE/NGCards/tests/common.h new file mode 100644 index 00000000..ae2f086c --- /dev/null +++ b/SOPE/NGCards/tests/common.h @@ -0,0 +1,30 @@ +/* + 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 +#import +#include +#include + +#endif /* __NGiCalTests_common_H__ */ diff --git a/SOPE/NGCards/tests/iCalRecurrenceCalculatorTests.m b/SOPE/NGCards/tests/iCalRecurrenceCalculatorTests.m new file mode 100644 index 00000000..eb6719b4 --- /dev/null +++ b/SOPE/NGCards/tests/iCalRecurrenceCalculatorTests.m @@ -0,0 +1,191 @@ +/* + 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 diff --git a/SOPE/NGCards/versitCardsSaxDriver/AUTHORS b/SOPE/NGCards/versitCardsSaxDriver/AUTHORS new file mode 100644 index 00000000..5a4b2257 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/AUTHORS @@ -0,0 +1,2 @@ +Max Berger +Marcus Mueller diff --git a/SOPE/NGCards/versitCardsSaxDriver/COPYING b/SOPE/NGCards/versitCardsSaxDriver/COPYING new file mode 100644 index 00000000..1adca665 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/COPYING @@ -0,0 +1,437 @@ + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 diff --git a/SOPE/NGCards/versitCardsSaxDriver/COPYRIGHT b/SOPE/NGCards/versitCardsSaxDriver/COPYRIGHT new file mode 100644 index 00000000..2a5be29f --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/COPYRIGHT @@ -0,0 +1,4 @@ +Copyright (C) 2003-2004 Max Berger +Copyright (C) 2004 OpenGroupware.org + +Contact: info@opengroupware.org diff --git a/SOPE/NGCards/versitCardsSaxDriver/ChangeLog b/SOPE/NGCards/versitCardsSaxDriver/ChangeLog new file mode 100644 index 00000000..b2644436 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/ChangeLog @@ -0,0 +1,295 @@ +2006-07-04 Helge Hess + + * use %p for pointer formats, fixed gcc 4.1 warnings (v4.5.24) + +2006-04-21 Marcus Mueller + + * GNUmakefile: properly declare principal class (v4.5.23) + +2006-04-08 Marcus Mueller + + * VSSaxDriver.m: improved error reporting in case no data could be + retrieved from a URL (v4.5.22) + +2005-12-05 Helge Hess + + * 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 + + * VSSaxDriver.m: renamed internal -error: method to -reportError: to + avoid a conflict with gstep-base (v4.5.20) + +2005-09-28 Helge Hess + + * GNUmakefile.preamble: install bundle in proper SaxObjC framework + location (v4.5.19) + +2005-08-16 Helge Hess + + * 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 + + * 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 + + * VSSaxDriver.m: more reorganisations, added support for groupings + (v4.5.15) + +2005-05-05 Helge Hess + + * VSSaxDriver.m: code cleanups / reorgs, properly embed reported + contents in 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 + + * VSSaxDriver.m: fixed a gcc 4.0 warning (v4.5.12) + +2004-12-14 Marcus Mueller + + * versitSaxDriver.xcode: minor changes and updated + +2004-10-20 Marcus Mueller + + * 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 + + * 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 + + * 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 + + * added fhs.make, some other minor fixes to makefiles (v1.0.6) + +2004-10-16 Marcus Mueller + + * 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 + + * 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 + + * 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 + + * fixed another bug related to libFoundation that applied to + NSMutableCharacterSet (v0.1.18) + +2004-02-24 Max Berger + + * fixed bug to crash on libFoundation in scanner line (v0.1.17) + +2004-02-25 Helge Hess + + * 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 + + * 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 + + * replaces commas by spaces in attrs (as in spec) (v0.1.15) + +2003-12-13 Max Berger + + * v0.1.14 + + * added support for apple item1.adr elements + + * added support for multiple attributes of same type + + +2003-12-12 Max Berger + + * added support for subitems, added subitems for ical and vcard (v0.1.13) + +2003-12-12 Max Berger + + * added mappings into vcard driver (v0.1.12) + +2003-12-11 Max Berger + + * collapsed drivers for vcard 21 and 30 (v0.1.11) + +2003-12-11 Max Berger + + * fixed range check (v0.1.10) + +2003-12-11 Max Berger + + * fixed another missing () in malloc (v0.1.9) + +2003-12-11 Max Berger + + * fixed a missing () in malloc (v0.1.8) + +2003-12-11 Helge Hess + + * v0.1.7 + + * minor tweaks to sourcecode style ;-) + + * created GNUmakefile's + +2003-11-23 Max Berger + + * v0.1.6 + + * added GNUmakefile for unix + + * fixed bundle-info.plist + + * fixed a bug that caused libFondation to crash + +2003-11-23 Max Berger + + * v0.1.5 + + * Implemented attribute mapping + + * Added list of attributes for xcal + +2003-11-23 Max Berger + + * 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 + + * 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 + + * v0.1.2 + + * fixed Copyright notice + + * added Data Retrieval + + * added unfold method (doesnt do anything yet) + +2003-11-23 Max Berger + + * Initial Version (v0.1.1) diff --git a/SOPE/NGCards/versitCardsSaxDriver/GNUmakefile b/SOPE/NGCards/versitCardsSaxDriver/GNUmakefile new file mode 100644 index 00000000..82c2d316 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/GNUmakefile @@ -0,0 +1,25 @@ +# 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 diff --git a/SOPE/NGCards/versitCardsSaxDriver/GNUmakefile.postamble b/SOPE/NGCards/versitCardsSaxDriver/GNUmakefile.postamble new file mode 100644 index 00000000..e36f8d62 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/GNUmakefile.postamble @@ -0,0 +1,5 @@ +# $Id: GNUmakefile.postamble 257 2004-10-14 21:01:23Z znek $ + +after-all :: + @(cp bundle-info.plist \ + $(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION)) diff --git a/SOPE/NGCards/versitCardsSaxDriver/GNUmakefile.preamble b/SOPE/NGCards/versitCardsSaxDriver/GNUmakefile.preamble new file mode 100644 index 00000000..eb3ae25e --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/GNUmakefile.preamble @@ -0,0 +1,48 @@ +# 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 diff --git a/SOPE/NGCards/versitCardsSaxDriver/README b/SOPE/NGCards/versitCardsSaxDriver/README new file mode 100644 index 00000000..85d148e6 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/README @@ -0,0 +1,53 @@ +Overview +======== + +Two SaxObjC drivers for iCalendar and vCard files, initially written by +Max Berger . + +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 diff --git a/SOPE/NGCards/versitCardsSaxDriver/VSCardSaxDriver.h b/SOPE/NGCards/versitCardsSaxDriver/VSCardSaxDriver.h new file mode 100644 index 00000000..a2a43fc8 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/VSCardSaxDriver.h @@ -0,0 +1,37 @@ +/* + 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__ */ diff --git a/SOPE/NGCards/versitCardsSaxDriver/VSCardSaxDriver.m b/SOPE/NGCards/versitCardsSaxDriver/VSCardSaxDriver.m new file mode 100644 index 00000000..46110fb0 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/VSCardSaxDriver.m @@ -0,0 +1,69 @@ +/* + 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 */ diff --git a/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.h b/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.h new file mode 100644 index 00000000..c6eb74f8 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.h @@ -0,0 +1,53 @@ +/* + 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 +#include + +@class NSString, NSSet, NSDictionary, NSMutableArray, NSMutableDictionary; + +@interface VSSaxDriver : NSObject < SaxXMLReader > +{ + id contentHandler; + id 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__ */ diff --git a/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.m b/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.m new file mode 100644 index 00000000..e59b7f0a --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/VSSaxDriver.m @@ -0,0 +1,1219 @@ +/* + 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 +#import +#import +#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) _handler +{ + ASSIGN(contentHandler, _handler); +} + +- (void) setDTDHandler: (id) _handler +{ + // FIXME +} + +- (void) setErrorHandler: (id) _handler +{ + ASSIGN(errorHandler, _handler); +} + +- (void) setEntityResolver: (id) _handler +{ + // FIXME +} + +- (id) contentHandler +{ + return contentHandler; +} + +- (id) dtdHandler +{ + // FIXME + return nil; +} + +- (id) errorHandler +{ + return errorHandler; +} + +- (id) 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: + + */ + 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 = @""; + 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 = @""; + [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 */ + diff --git a/SOPE/NGCards/versitCardsSaxDriver/VSStringFormatter.h b/SOPE/NGCards/versitCardsSaxDriver/VSStringFormatter.h new file mode 100644 index 00000000..13d90120 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/VSStringFormatter.h @@ -0,0 +1,38 @@ +/* + 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 + +@interface VSStringFormatter : NSObject +{ +} + ++ (id)sharedFormatter; +- (NSString *)stringByUnescapingRFC2445Text:(NSString *)_s; + +@end + +#endif /* __VSStringFormatter_H_ */ diff --git a/SOPE/NGCards/versitCardsSaxDriver/VSStringFormatter.m b/SOPE/NGCards/versitCardsSaxDriver/VSStringFormatter.m new file mode 100644 index 00000000..5535e5eb --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/VSStringFormatter.m @@ -0,0 +1,94 @@ +/* + 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 */ diff --git a/SOPE/NGCards/versitCardsSaxDriver/Version b/SOPE/NGCards/versitCardsSaxDriver/Version new file mode 100644 index 00000000..462cacfe --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/Version @@ -0,0 +1,7 @@ +# Version file + +# SOPE version: +MAJOR_VERSION=4 +MINOR_VERSION=5 + +SUBMINOR_VERSION:=24 diff --git a/SOPE/NGCards/versitCardsSaxDriver/bundle-info.plist b/SOPE/NGCards/versitCardsSaxDriver/bundle-info.plist new file mode 100644 index 00000000..41acb508 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/bundle-info.plist @@ -0,0 +1,19 @@ +{ + requires = { + bundleManagerVersion = 1; + classes = ( { name = NSObject; } ); + }; + + provides = { + SAXDrivers = ( + { + name = "VSCardSaxDriver"; + sourceTypes = ( "text/x-vcard", "text/vcard", + "text/x-calendar", "text/calendar" ); + } + ); + classes = ( + { name = "VSCardSaxDriver"; } + ); + }; +} diff --git a/SOPE/NGCards/versitCardsSaxDriver/common.h b/SOPE/NGCards/versitCardsSaxDriver/common.h new file mode 100644 index 00000000..1df59153 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/common.h @@ -0,0 +1,25 @@ +/* + 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 + +#include diff --git a/SOPE/NGCards/versitCardsSaxDriver/fhs.make b/SOPE/NGCards/versitCardsSaxDriver/fhs.make new file mode 100644 index 00000000..1c478180 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/fhs.make @@ -0,0 +1,29 @@ +# 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 diff --git a/SOPE/NGCards/versitCardsSaxDriver/versitCardsSaxDriver-Info.plist b/SOPE/NGCards/versitCardsSaxDriver/versitCardsSaxDriver-Info.plist new file mode 100644 index 00000000..bc6c308b --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/versitCardsSaxDriver-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + versitCardsSaxDriver + CFBundleGetInfoString + + CFBundleIconFile + + CFBundleIdentifier + org.OpenGroupware.SOPE.sope-cards.versitCardsSaxDriver + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 1.0 + + diff --git a/SOPE/NGCards/versitCardsSaxDriver/versitCardsSaxDriver.xcodeproj/project.pbxproj b/SOPE/NGCards/versitCardsSaxDriver/versitCardsSaxDriver.xcodeproj/project.pbxproj new file mode 100644 index 00000000..05873fc4 --- /dev/null +++ b/SOPE/NGCards/versitCardsSaxDriver/versitCardsSaxDriver.xcodeproj/project.pbxproj @@ -0,0 +1,389 @@ +// !$*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 = ""; }; + 1656CD24058806680012D2BC /* VSSaxDriver.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = VSSaxDriver.h; sourceTree = ""; }; + 1656CD25058806680012D2BC /* VSSaxDriver.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = VSSaxDriver.m; sourceTree = ""; }; + 1656CD37058806CE0012D2BC /* bundle-info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = "bundle-info.plist"; sourceTree = ""; }; + 1656CD7C058809660012D2BC /* VSCardSaxDriver.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = VSCardSaxDriver.h; sourceTree = ""; }; + 1656CD7D058809660012D2BC /* VSCardSaxDriver.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = VSCardSaxDriver.m; sourceTree = ""; }; + 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 = ""; tabWidth = 8; usesTabs = 1; }; + 16800E4305880EC4007700A5 /* Version */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 30; indentWidth = 8; path = Version; sourceTree = ""; tabWidth = 8; }; + AD0CFACA071FFF0000E72147 /* VSStringFormatter.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = VSStringFormatter.h; sourceTree = ""; }; + AD0CFACB071FFF0000E72147 /* VSStringFormatter.m */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = VSStringFormatter.m; sourceTree = ""; }; + AD5010A5071F18AE0020300E /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; + AD5010A7071F18B80020300E /* AUTHORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AUTHORS; sourceTree = ""; }; + AD5010BE071F18F00020300E /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYING; sourceTree = ""; }; + AD5010C0071F18FA0020300E /* COPYRIGHT */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYRIGHT; sourceTree = ""; }; + AD665AAF071EB30200EC5911 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + AD665AB3071EB36D00EC5911 /* SaxObjC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SaxObjC.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/SaxObjC.framework"; sourceTree = ""; }; + AD665AB5071EB38C00EC5911 /* common.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; + AD665AB7071EB39600EC5911 /* GNUmakefile */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 5; indentWidth = 8; path = GNUmakefile; sourceTree = ""; tabWidth = 8; }; + AD665AB8071EB39600EC5911 /* GNUmakefile.postamble */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 5; indentWidth = 8; path = GNUmakefile.postamble; sourceTree = ""; tabWidth = 8; }; + AD665AB9071EB39600EC5911 /* GNUmakefile.preamble */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 5; indentWidth = 8; path = GNUmakefile.preamble; sourceTree = ""; tabWidth = 8; }; + ADB07DC207666226003C5ACF /* fhs.make */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 5; indentWidth = 8; path = fhs.make; sourceTree = ""; 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 = ""; + }; + 1656CD1F0588063D0012D2BC /* Classes */ = { + isa = PBXGroup; + children = ( + AD665AB5071EB38C00EC5911 /* common.h */, + 1656CD25058806680012D2BC /* VSSaxDriver.m */, + 1656CD7D058809660012D2BC /* VSCardSaxDriver.m */, + AD0CFACB071FFF0000E72147 /* VSStringFormatter.m */, + ); + name = Classes; + sourceTree = ""; + }; + 1656CD8F058809E30012D2BC /* Resources */ = { + isa = PBXGroup; + children = ( + 1656CCB80588036A0012D2BC /* versitCardsSaxDriver-Info.plist */, + 1656CD37058806CE0012D2BC /* bundle-info.plist */, + ); + name = Resources; + sourceTree = ""; + }; + 1656CD92058809FD0012D2BC /* Frameworks */ = { + isa = PBXGroup; + children = ( + AD665AB3071EB36D00EC5911 /* SaxObjC.framework */, + AD665AAF071EB30200EC5911 /* Foundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 16800E3905880EA1007700A5 /* Products */ = { + isa = PBXGroup; + children = ( + 16800E2F05880E8E007700A5 /* versitCardsSaxDriver.sax */, + ); + name = Products; + sourceTree = ""; + }; + AD665AAE071EB2C200EC5911 /* Makefiles */ = { + isa = PBXGroup; + children = ( + AD665AB7071EB39600EC5911 /* GNUmakefile */, + AD665AB9071EB39600EC5911 /* GNUmakefile.preamble */, + AD665AB8071EB39600EC5911 /* GNUmakefile.postamble */, + ADB07DC207666226003C5ACF /* fhs.make */, + ); + name = Makefiles; + sourceTree = ""; + }; + AD665ABF071EB3D500EC5911 /* Headers */ = { + isa = PBXGroup; + children = ( + 1656CD24058806680012D2BC /* VSSaxDriver.h */, + 1656CD7C058809660012D2BC /* VSCardSaxDriver.h */, + AD0CFACA071FFF0000E72147 /* VSStringFormatter.h */, + ); + name = Headers; + sourceTree = ""; + }; +/* 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 = " + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + versitCardsSaxDriver + CFBundleGetInfoString + + CFBundleIconFile + + CFBundleIdentifier + com.MySoftwareCompany.versitCardsSaxDriver + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleShortVersionString + + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + + +"; + 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 */; +} diff --git a/SoObjects/Appointments/SOGoAppointmentObject.h b/SoObjects/Appointments/SOGoAppointmentObject.h index ccca7fb7..3c7e4d78 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.h +++ b/SoObjects/Appointments/SOGoAppointmentObject.h @@ -56,18 +56,12 @@ - (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; diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index 1531823c..42e4f01e 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -42,38 +42,45 @@ @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 */ @@ -84,11 +91,11 @@ static NSString *mailTemplateDefaultLanguage = nil; } /* 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; @@ -149,8 +156,8 @@ static NSString *mailTemplateDefaultLanguage = nil; - (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]; @@ -191,13 +198,15 @@ static NSString *mailTemplateDefaultLanguage = nil; 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]; @@ -262,13 +271,13 @@ static NSString *mailTemplateDefaultLanguage = nil; 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; @@ -312,14 +321,14 @@ static NSString *mailTemplateDefaultLanguage = nil; 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]) @@ -328,7 +337,7 @@ static NSString *mailTemplateDefaultLanguage = nil; /* preserve organizer */ organizer = [newApt organizer]; - uid = [um getUIDForICalPerson:organizer]; + uid = [um getUIDForICalPerson:organizer]; if (uid) { if (![storeUIDs containsObject:uid]) [storeUIDs addObject:uid]; @@ -379,39 +388,43 @@ static NSString *mailTemplateDefaultLanguage = nil; /* 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; } @@ -431,8 +444,8 @@ static NSString *mailTemplateDefaultLanguage = nil; - send iMIP mail for all folders not found */ iCalEvent *apt; - NSArray *removedUIDs; - NSMutableArray *attendees; + NSArray *removedUIDs; + NSMutableArray *attendees; /* load existing content */ @@ -440,116 +453,123 @@ static NSString *mailTemplateDefaultLanguage = nil; /* 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 @@ -581,175 +601,169 @@ static NSString *mailTemplateDefaultLanguage = nil; 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 diff --git a/SoObjects/Appointments/SOGoCalendarComponent.h b/SoObjects/Appointments/SOGoCalendarComponent.h index 6d93a4af..637c6f67 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.h +++ b/SoObjects/Appointments/SOGoCalendarComponent.h @@ -39,6 +39,9 @@ - (NSString *) iCalString; - (iCalCalendar *) calendar; +- (NSException *) primarySaveContentString: (NSString *) _iCalString; +- (NSException *) primaryDelete; + - (NSException *) delete; @end diff --git a/SoObjects/Appointments/SOGoCalendarComponent.m b/SoObjects/Appointments/SOGoCalendarComponent.m index 40f29e1a..adb0cc80 100644 --- a/SoObjects/Appointments/SOGoCalendarComponent.m +++ b/SoObjects/Appointments/SOGoCalendarComponent.m @@ -68,15 +68,17 @@ /* 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]; diff --git a/SoObjects/Appointments/SOGoTaskObject.h b/SoObjects/Appointments/SOGoTaskObject.h index 20ad9f72..d0603786 100644 --- a/SoObjects/Appointments/SOGoTaskObject.h +++ b/SoObjects/Appointments/SOGoTaskObject.h @@ -54,18 +54,12 @@ - (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; diff --git a/SoObjects/GNUmakefile b/SoObjects/GNUmakefile index e685b16b..4fad16f2 100644 --- a/SoObjects/GNUmakefile +++ b/SoObjects/GNUmakefile @@ -8,6 +8,6 @@ SUBPROJECTS = \ Appointments \ Contacts \ Mailer \ - Sieve \ +# Sieve \ include $(GNUSTEP_MAKEFILES)/aggregate.make diff --git a/SoObjects/SOGo/NSString+Utilities.h b/SoObjects/SOGo/NSString+Utilities.h index 45d76d7b..285c3296 100644 --- a/SoObjects/SOGo/NSString+Utilities.h +++ b/SoObjects/SOGo/NSString+Utilities.h @@ -1,4 +1,4 @@ -/* NSString+URL.h - this file is part of SOGo +/* NSString+Utilities.h - this file is part of SOGo * * Copyright (C) 2006 Inverse groupe conseil * diff --git a/SoObjects/SOGo/NSString+Utilities.m b/SoObjects/SOGo/NSString+Utilities.m index ae0b79e8..03609d0c 100644 --- a/SoObjects/SOGo/NSString+Utilities.m +++ b/SoObjects/SOGo/NSString+Utilities.m @@ -1,4 +1,4 @@ -/* NSString+URL.m - this file is part of SOGo +/* NSString+Utilities.m - this file is part of SOGo * * Copyright (C) 2006 Inverse group conseil * diff --git a/SoObjects/SOGo/SOGoAuthenticator.m b/SoObjects/SOGo/SOGoAuthenticator.m index 0aa6552e..a44d5532 100644 --- a/SoObjects/SOGo/SOGoAuthenticator.m +++ b/SoObjects/SOGo/SOGoAuthenticator.m @@ -94,32 +94,39 @@ static SOGoAuthenticator *auth = nil; - (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 diff --git a/SoObjects/common.make b/SoObjects/common.make index 8b1fb43d..3684a1e4 100644 --- a/SoObjects/common.make +++ b/SoObjects/common.make @@ -10,14 +10,15 @@ BUNDLE_INSTALL_DIR = $(GNUSTEP_USER_ROOT)/Library/SOGo-$(MAJOR_VERSION).$(MINO 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 += \ diff --git a/UI/MailerUI/UIxMailEditorAction.m b/UI/MailerUI/UIxMailEditorAction.m index 676fddfb..563bdabe 100644 --- a/UI/MailerUI/UIxMailEditorAction.m +++ b/UI/MailerUI/UIxMailEditorAction.m @@ -27,7 +27,7 @@ #import #import "common.h" -#import +#import @implementation UIxMailEditorAction diff --git a/UI/MailerUI/UIxMailListView.m b/UI/MailerUI/UIxMailListView.m index 77e8d591..8411b0e1 100644 --- a/UI/MailerUI/UIxMailListView.m +++ b/UI/MailerUI/UIxMailListView.m @@ -453,6 +453,9 @@ static int attachmentFlagSize = 8096; NSString *specificMessage; request = [[self context] request]; + + [[self clientObject] flushMailCaches]; + specificMessage = [request formValueForKey: @"pageforuid"]; self->firstMessageNumber = ((specificMessage) diff --git a/UI/SOGoUI/UIxComponent.m b/UI/SOGoUI/UIxComponent.m index 5a353f21..59ab845d 100644 --- a/UI/SOGoUI/UIxComponent.m +++ b/UI/SOGoUI/UIxComponent.m @@ -25,7 +25,7 @@ #import #import -#import +#import #import #import diff --git a/UI/Scheduler/UIxCalCalendarsListView.m b/UI/Scheduler/UIxCalCalendarsListView.m index c84369be..b25de820 100644 --- a/UI/Scheduler/UIxCalCalendarsListView.m +++ b/UI/Scheduler/UIxCalCalendarsListView.m @@ -104,8 +104,6 @@ darkenedColor (const char value) (255 / colorTable[0]) - 1]; } - NSLog(@"color = '%@'", color); - return color; } diff --git a/UI/Templates/MailerUI/UIxMailEditor.wox b/UI/Templates/MailerUI/UIxMailEditor.wox index 97c87337..213e48b0 100644 --- a/UI/Templates/MailerUI/UIxMailEditor.wox +++ b/UI/Templates/MailerUI/UIxMailEditor.wox @@ -8,39 +8,40 @@ xmlns:label="OGo:label" className="UIxPageFrame" title="panelTitle" - const:popup="YES" - > -
-
- -
+ const:popup="YES"> +
+
+
+ +

-
+ +
+ : +
+
+ +
+
:
- : -
-
- -
-
:
-
-