Monotone-Parent: 4962ab3aba4ec12e6e80cec90be3bb7824bb7b56

Monotone-Revision: 53a7cdc42e8710e661ce709242c9857ae53542ff

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2007-01-31T17:11:29
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Wolfgang Sourdeau 2007-01-31 17:11:29 +00:00
parent 829f96f301
commit b234f02a47
122 changed files with 18015 additions and 0 deletions

View File

@ -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.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@ -0,0 +1,4 @@
Copyright (C) 2000-2005 SKYRIX Software AG
Contact: info@skyrix.com

View File

@ -0,0 +1,109 @@
/* CardElement.h - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef CARDELEMENT_H
#define CARDELEMENT_H
#import <Foundation/NSObject.h>
@class NSArray;
@class NSDictionary;
@class NSMutableArray;
@class NSMutableDictionary;
@class NSString;
@class CardGroup;
@interface CardElement : NSObject <NSCopying>
{
NSString *tag;
NSMutableArray *values;
NSMutableDictionary *attributes;
NSString *group;
CardGroup *parent;
}
+ (id) elementWithTag: (NSString *) aTag;
+ (id) simpleElementWithTag: (NSString *) aTag
value: (NSString *) aValue;
+ (id) simpleElementWithTag: (NSString *) aTag
singleType: (NSString *) aType
value: (NSString *) aValue;
+ (id) elementWithTag: (NSString *) aTag
attributes: (NSDictionary *) someAttributes
values: (NSArray *) someValues;
- (void) setParent: (CardGroup *) aParent;
- (CardGroup *) parent;
- (void) setTag: (NSString *) aTag;
- (void) setGroup: (NSString *) aGroup;
- (NSString *) group;
- (void) addValue: (NSString *) aValue;
- (void) addValues: (NSArray *) someValues;
- (void) setValue: (unsigned int) anInt
to: (NSString *) aValue;
- (NSString *) value: (unsigned int) anInt;
- (void) setNamedValue: (NSString *) aValueName
to: (NSString *) aValue;
- (NSString *) namedValue: (NSString *) aValueName;
- (void) setValue: (unsigned int) anInt
ofAttribute: (NSString *) anAttribute
to: (NSString *) aValue;
- (NSString *) value: (unsigned int) anInt
ofAttribute: (NSString *) anAttribute;
- (void) addAttribute: (NSString *) anAttribute
value: (NSString *) aValue;
- (void) addAttributes: (NSDictionary *) someAttributes;
- (void) removeValue: (NSString *) aValue
fromAttribute: (NSString *) anAttribute;
- (void) addType: (NSString *) aType;
- (NSString *) tag;
- (NSArray *) values;
- (NSDictionary *) attributes;
- (BOOL) hasAttribute: (NSString *) aType
havingValue: (NSString *) aValue;
- (BOOL) isVoid;
- (NSString *) versitString;
- (CardGroup *) searchParentOfClass: (Class) parentClass;
- (CardElement *) elementWithClass: (Class) elementClass;
- (void) setValuesAsCopy: (NSMutableArray *) someValues;
- (void) setAttributesAsCopy: (NSMutableDictionary *) someAttributes;
@end
#endif /* CARDELEMENT_H */

View File

@ -0,0 +1,500 @@
/* CardElement.m - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import "NSArray+NGCards.h"
#import "NSDictionary+NGCards.h"
#import "CardVersitRenderer.h"
#import "CardElement.h"
#import "CardGroup.h"
@implementation CardElement
+ (id) elementWithTag: (NSString *) aTag
{
id newElement;
newElement = [self new];
[newElement autorelease];
[newElement setTag: aTag];
return newElement;
}
+ (id) simpleElementWithTag: (NSString *) aTag
value: (NSString *) aValue
{
id newElement;
newElement = [self elementWithTag: aTag];
[newElement addValue: aValue];
return newElement;
}
+ (id) simpleElementWithTag: (NSString *) aTag
singleType: (NSString *) aType
value: (NSString *) aValue
{
id newElement;
newElement = [self simpleElementWithTag: aTag
value: aValue];
[newElement addType: aType];
return newElement;
}
+ (id) elementWithTag: (NSString *) aTag
attributes: (NSDictionary *) someAttributes
values: (NSArray *) someValues
{
id newElement;
newElement = [self new];
[newElement autorelease];
[newElement setTag: aTag];
[newElement addAttributes: someAttributes];
[newElement addValues: someValues];
return newElement;
}
- (id) init
{
if ((self = [super init]))
{
parent = nil;
tag = nil;
group = nil;
values = [NSMutableArray new];
attributes = [NSMutableDictionary new];
}
return self;
}
- (void) dealloc
{
if (tag)
[tag release];
[values release];
[attributes release];
[super dealloc];
}
- (void) setParent: (CardGroup *) aParent
{
parent = aParent;
}
- (CardGroup *) parent
{
return parent;
}
- (void) setTag: (NSString *) aTag
{
if (tag)
[tag release];
tag = aTag;
if (tag)
[tag retain];
}
- (void) setGroup: (NSString *) aGroup
{
if (group)
[group release];
group = aGroup;
if (group)
[group retain];
}
- (NSString *) group
{
return group;
}
- (void) addValue: (NSString *) aValue
{
[values addObject: aValue];
}
- (void) addValues: (NSArray *) someValues
{
[values addObjectsFromArray: someValues];
}
- (void) addAttribute: (NSString *) anAttribute
value: (NSString *) aType
{
NSMutableArray *attrValues;
attrValues = [attributes objectForCaseInsensitiveKey: anAttribute];
if (!attrValues)
{
attrValues = [NSMutableArray new];
[attrValues autorelease];
[attributes setObject: attrValues forKey: anAttribute];
}
[attrValues addObject: aType];
}
- (void) removeValue: (NSString *) aValue
fromAttribute: (NSString *) anAttribute
{
NSMutableArray *attrValues;
NSString *currentValue;
attrValues = [attributes objectForCaseInsensitiveKey: anAttribute];
if (attrValues)
{
currentValue = [attrValues valueForCaseInsensitiveString: aValue];
while (currentValue)
{
[attrValues removeObject: currentValue];
currentValue = [attrValues valueForCaseInsensitiveString: aValue];
}
}
}
- (void) addAttributes: (NSDictionary *) someAttributes
{
NSEnumerator *keys;
NSString *currentKey;
NSMutableArray *oldValues;
NSArray *newValues;
keys = [[someAttributes allKeys] objectEnumerator];
currentKey = [keys nextObject];
while (currentKey)
{
oldValues = [attributes objectForCaseInsensitiveKey: currentKey];
newValues = [someAttributes objectForKey: currentKey];
if (oldValues)
[oldValues addObjectsFromArray: newValues];
else
[attributes setObject: newValues forKey: currentKey];
currentKey = [keys nextObject];
}
}
- (void) addType: (NSString *) aType
{
[self addAttribute: @"type" value: aType];
}
- (NSString *) tag
{
return tag;
}
- (NSArray *) values
{
return values;
}
- (NSDictionary *) attributes
{
return attributes;
}
- (BOOL) hasAttribute: (NSString *) anAttribute
havingValue: (NSString *) aValue
{
NSArray *attribute;
attribute = [attributes objectForCaseInsensitiveKey: anAttribute];
return (attribute && [attribute hasCaseInsensitiveString: aValue]);
}
- (void) setValue: (unsigned int) anInt
to: (NSString *) aValue
{
while ([values count] <= anInt)
[self addValue: @""];
[values replaceObjectAtIndex: anInt withObject: aValue];
}
- (NSString *) value: (unsigned int) anInt
{
NSString *value;
if ([values count] <= anInt)
value = @"";
else
value = [values objectAtIndex: anInt];
return value;
}
- (unsigned int) _namedValue: (NSString *) aValueName
{
NSString *prefix, *value;
unsigned int count, max, result;
result = NSNotFound;
prefix = [NSString stringWithFormat: @"%@=", [aValueName uppercaseString]];
max = [values count];
count = 0;
while (result == NSNotFound && count < max)
{
value = [[values objectAtIndex: count] uppercaseString];
if ([value hasPrefix: prefix])
result = count;
else
count++;
}
return result;
}
- (void) setNamedValue: (NSString *) aValueName
to: (NSString *) aValue
{
NSString *newValue;
unsigned int index;
newValue = [NSString stringWithFormat: @"%@=%@",
[aValueName uppercaseString],
aValue];
index = [self _namedValue: aValueName];
if (index == NSNotFound)
[self addValue: newValue];
else
{
if (aValue)
[self setValue: index to: newValue];
else
[values removeObjectAtIndex: index];
}
}
- (NSString *) namedValue: (NSString *) aValueName
{
unsigned int index, equalSign;
NSString *value;
index = [self _namedValue: aValueName];
if (index == NSNotFound)
value = @"";
else
{
value = [values objectAtIndex: index];
equalSign = [value indexOfString: @"="];
if (equalSign != NSNotFound)
value = [value substringFromIndex: equalSign + 1];
}
return value;
}
- (void) setValue: (unsigned int) anInt
ofAttribute: (NSString *) anAttribute
to: (NSString *) aValue
{
NSMutableArray *attrValues;
attrValues = [attributes objectForCaseInsensitiveKey: anAttribute];
if (!attrValues)
{
attrValues = [NSMutableArray new];
[attrValues autorelease];
[attributes setObject: attrValues forKey: anAttribute];
}
while ([attrValues count] <= anInt)
[attrValues addObject: @""];
[attrValues replaceObjectAtIndex: anInt
withObject: aValue];
}
- (NSString *) value: (unsigned int) anInt
ofAttribute: (NSString *) anAttribute
{
NSArray *attrValues;
NSString *value;
attrValues = [attributes objectForCaseInsensitiveKey: anAttribute];
if (attrValues && [attrValues count] > anInt)
value = [attrValues objectAtIndex: anInt];
else
value = @"";
return value;
}
- (NSString *) description
{
NSArray *attrs;
NSMutableString *str;
unsigned int count, max;
NSString *attr;
str = [NSMutableString stringWithCapacity:64];
[str appendFormat:@"<%p[%@]:", self, NSStringFromClass([self class])];
if (group)
[str appendFormat: @"%@ (group: %@)\n", tag, group];
else
[str appendFormat: @"%@\n", tag, group];
attrs = [attributes allKeys];
max = [attrs count];
if (max > 0)
{
[str appendFormat: @"\n %d attributes: {\n", [attrs count]];
for (count = 0; count < max; count++)
{
attr = [attrs objectAtIndex: count];
[str appendFormat: @" %@: %@\n",
attr, [attributes objectForKey: attr]];
}
[str appendFormat: @"}"];
}
max = [values count];
if (max > 0)
{
[str appendFormat: @"\n %d values: {\n", [values count]];
for (count = 0; count < max; count++)
[str appendFormat: @" %@\n", [values objectAtIndex: count]];
[str appendFormat: @"}"];
}
[str appendString:@">"];
return str;
}
- (BOOL) isVoid
{
BOOL result;
NSString *value;
NSEnumerator *enu;
result = YES;
enu = [values objectEnumerator];
value = [enu nextObject];
while (value && result)
{
result = ([value length] == 0);
value = [enu nextObject];
}
return result;
}
- (NSString *) versitString
{
CardVersitRenderer *renderer;
NSString *string;
renderer = [CardVersitRenderer new];
string = [renderer render: self];
[renderer release];
return string;
}
- (CardElement *) elementWithClass: (Class) elementClass
{
CardElement *newElement;
if ([self isKindOfClass: elementClass])
newElement = self;
else
{
newElement = [elementClass new];
[newElement autorelease];
[newElement setTag: tag];
[newElement setValuesAsCopy: values];
[newElement setAttributesAsCopy: attributes];
if (group)
[newElement setGroup: group];
if (parent)
{
[newElement setParent: parent];
[parent replaceThisElement: self
withThisOne: newElement];
}
}
return newElement;
}
- (void) setValuesAsCopy: (NSMutableArray *) someValues
{
[values release];
values = someValues;
[values retain];
}
- (void) setAttributesAsCopy: (NSMutableDictionary *) someAttributes
{
[attributes release];
attributes = someAttributes;
[attributes retain];
}
- (CardGroup *) searchParentOfClass: (Class) parentClass
{
CardGroup *current;
CardGroup *found;
found = nil;
current = parent;
while (current && !found)
if ([current isKindOfClass: parentClass])
found = current;
else
current = [current parent];
return found;
}
/* NSCopying */
- (id) copyWithZone: (NSZone *) aZone
{
CardElement *new;
new = [[self class] new];
[new setTag: [tag copyWithZone: aZone]];
[new setGroup: [group copyWithZone: aZone]];
[new setParent: parent];
[new setValuesAsCopy: [values copyWithZone: aZone]];
[new setAttributesAsCopy: [attributes copyWithZone: aZone]];
return new;
}
@end

View File

@ -0,0 +1,39 @@
/* CardGroup+iCal.h - this file is part of $PROJECT_NAME_HERE$
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef CARDGROUP_ICAL_H
#define CARDGROUP_ICAL_H
@class NSString;
@class NSCalendarDate;
#import "CardGroup.h"
@interface CardGroup (iCalExtensions)
- (void) setDate: (NSCalendarDate *) _value
forDateTimeValue: (NSString *) valueName;
- (NSCalendarDate *) dateForDateTimeValue: (NSString *) valueName;
@end
#endif /* CARDGROUP_ICAL_H */

View File

@ -0,0 +1,48 @@
/* CardGroup+iCal.m - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import "iCalDateTime.h"
#import "CardGroup+iCal.h"
@implementation CardGroup (iCalExtensions)
- (void) setDate: (NSCalendarDate *) _value
forDateTimeValue: (NSString *) valueName
{
iCalDateTime *dateValue;
dateValue = (iCalDateTime *) [self uniqueChildWithTag: valueName];
[dateValue setDateTime: _value];
}
- (NSCalendarDate *) dateForDateTimeValue: (NSString *) valueName
{
iCalDateTime *dateValue;
dateValue = (iCalDateTime *) [self uniqueChildWithTag: valueName];
return [dateValue dateTime];
}
@end

View File

@ -0,0 +1,76 @@
/* CardGroup.h - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef CARDGROUP_H
#define CARDGROUP_H
#import "CardElement.h"
@class NSArray;
@class NSMutableArray;
@class NSString;
@interface CardGroup : CardElement <NSCopying>
{
NSMutableArray *children;
}
+ (id) parseSingleFromSource: (id) source;
+ (NSArray *) parseFromSource: (id) source;
+ (id) groupWithTag: (NSString *) aTag;
+ (id) groupWithTag: (NSString *) aTag
children: (NSArray *) someChildren;
- (Class) classForTag: (NSString *) tagClass;
- (CardElement *) uniqueChildWithTag: (NSString *) aTag;
- (void) setUniqueChild: (CardElement *) aChild;
- (void) addChild: (CardElement *) aChild;
- (void) addChildren: (NSArray *) someChildren;
- (NSArray *) children;
- (NSArray *) childrenWithTag: (NSString *) aTag;
- (NSArray *) childrenWithAttribute: (NSString *) anAttribute
havingValue: (NSString *) aValue;
- (NSArray *) childrenWithTag: (NSString *) aTag
andAttribute: (NSString *) anAttribute
havingValue: (NSString *) aValue;
- (NSArray *) childrenGroupWithTag: (NSString *) aTag
withChild: (NSString *) aChild
havingSimpleValue: (NSString *) aValue;
- (void) addChildWithTag: (NSString *) aTag
types: (NSArray *) someTypes
singleValue: (NSString *) aValue;
- (CardGroup *) groupWithClass: (Class) groupClass;
- (void) setChildrenAsCopy: (NSMutableArray *) someChildren;
- (void) replaceThisElement: (CardElement *) oldElement
withThisOne: (CardElement *) newElement;
@end
#endif /* CARDGROUP_H */

View File

@ -0,0 +1,386 @@
/* CardGroup.m - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <SaxObjC/SaxXMLReader.h>
#import <SaxObjC/SaxXMLReaderFactory.h>
#import "NGCardsSaxHandler.h"
#import "NSArray+NGCards.h"
#import "CardGroup.h"
static id<NSObject,SaxXMLReader> parser = nil;
static NGCardsSaxHandler *sax = nil;
@implementation CardGroup
+ (id<NSObject,SaxXMLReader>) cardParser
{
if (!sax)
sax = [NGCardsSaxHandler new];
if (!parser)
{
parser =
[[[SaxXMLReaderFactory standardXMLReaderFactory]
createXMLReaderForMimeType:@"text/x-vcard"]
retain];
if (parser)
{
[parser setContentHandler:sax];
[parser setErrorHandler:sax];
}
else
NSLog(@"ERROR(%s): did not find a parser for text/x-vcard!",
__PRETTY_FUNCTION__);
}
return parser;
}
+ (NSArray *) parseFromSource: (id) source
{
static id <NSObject,SaxXMLReader> cardParser;
NSMutableArray *cardGroups;
NSEnumerator *cards;
CardGroup *currentCard;
cardParser = [self cardParser];
[sax setTopElementClass: [self class]];
if (parser)
{
cardGroups = [NSMutableArray new];
[cardGroups autorelease];
[parser parseFromSource: source];
cards = [[sax cards] objectEnumerator];
currentCard = [cards nextObject];
while (currentCard)
{
[cardGroups addObject: currentCard];
currentCard = [cards nextObject];
}
}
else
cardGroups = nil;
return cardGroups;
}
+ (id) parseSingleFromSource: (id) source
{
NSArray *cards;
CardGroup *card;
cards = [self parseFromSource: source];
if (cards && [cards count])
card = [cards objectAtIndex: 0];
else
card = nil;
return card;
}
+ (id) groupWithTag: (NSString *) aTag
{
id newGroup;
newGroup = [self new];
[newGroup autorelease];
[newGroup setTag: aTag];
return newGroup;
}
+ (id) groupWithTag: (NSString *) aTag
children: (NSArray *) someChildren
{
id newGroup;
newGroup = [self new];
[newGroup autorelease];
[newGroup setTag: aTag];
[newGroup addChildren: someChildren];
return newGroup;
}
- (id) init
{
if ((self = [super init]))
{
children = [NSMutableArray new];
}
return self;
}
- (void) dealloc
{
[children release];
[super dealloc];
}
- (Class) classForTag: (NSString *) tagClass
{
NSLog (@"class '%@': '%@'", NSStringFromClass([self class]),
tagClass);
return nil;
}
- (void) addChild: (CardElement *) aChild
{
Class mappedClass;
NSString *childTag;
CardElement *newChild;
childTag = [aChild tag];
newChild = nil;
mappedClass = [self classForTag: [childTag uppercaseString]];
if (mappedClass)
{
if (![aChild isKindOfClass: mappedClass])
{
NSLog (@"warning: new child to entity '%@': '%@' converted to '%@'",
tag, childTag, NSStringFromClass(mappedClass));
if ([aChild isKindOfClass: [CardGroup class]])
newChild = [(CardGroup *) aChild groupWithClass: mappedClass];
else
newChild = [aChild elementWithClass: mappedClass];
}
}
else
NSLog (@"warning: no mapped class for tag '%@'",
childTag);
if (!newChild)
newChild = aChild;
[children addObject: newChild];
[newChild setParent: self];
}
- (CardElement *) uniqueChildWithTag: (NSString *) aTag
{
NSArray *existing;
Class elementClass;
CardElement *uniqueChild;
existing = [self childrenWithTag: aTag];
if ([existing count] > 0)
uniqueChild = [existing objectAtIndex: 0];
else
{
elementClass = [self classForTag: [aTag uppercaseString]];
if (!elementClass)
elementClass = [CardElement class];
uniqueChild = [elementClass new];
[uniqueChild autorelease];
[uniqueChild setTag: aTag];
[self addChild: uniqueChild];
}
return uniqueChild;
}
- (void) setUniqueChild: (CardElement *) aChild
{
CardElement *currentChild;
NSString *childTag;
NSEnumerator *existing;
childTag = [aChild tag];
existing = [[self childrenWithTag: childTag] objectEnumerator];
currentChild = [existing nextObject];
while (currentChild)
{
[children removeObject: currentChild];
currentChild = [existing nextObject];
}
[self addChild: aChild];
}
- (void) addChildren: (NSArray *) someChildren
{
CardElement *currentChild;
NSEnumerator *newChildren;
newChildren = [someChildren objectEnumerator];
currentChild = [newChildren nextObject];
while (currentChild)
{
[self addChild: currentChild];
currentChild = [newChildren nextObject];
}
}
- (NSArray *) children
{
return children;
}
- (NSArray *) childrenWithTag: (NSString *) aTag
{
return [children cardElementsWithTag: aTag];
}
- (NSArray *) childrenWithAttribute: (NSString *) anAttribute
havingValue: (NSString *) aValue
{
return [children cardElementsWithAttribute: anAttribute
havingValue: aValue];
}
- (NSArray *) childrenWithTag: (NSString *) aTag
andAttribute: (NSString *) anAttribute
havingValue: (NSString *) aValue
{
NSArray *elements;
elements = [self childrenWithTag: aTag];
return [elements cardElementsWithAttribute: anAttribute
havingValue: aValue];
}
- (NSArray *) childrenGroupWithTag: (NSString *) aTag
withChild: (NSString *) aChild
havingSimpleValue: (NSString *) aValue
{
NSEnumerator *allElements;
NSMutableArray *elements;
CardGroup *element;
NSString *value;
elements = [NSMutableArray new];
[elements autorelease];
allElements = [[self childrenWithTag: aTag] objectEnumerator];
element = [allElements nextObject];
while (element)
{
if ([element isKindOfClass: [CardGroup class]])
{
value = [[element uniqueChildWithTag: aChild] value: 0];
if ([value isEqualToString: aValue])
[elements addObject: element];
}
element = [allElements nextObject];
}
return elements;
}
#warning should be renamed to elementWithClass...
- (CardGroup *) groupWithClass: (Class) groupClass
{
CardGroup *newGroup;
if ([self isKindOfClass: groupClass])
newGroup = self;
else
{
newGroup = (CardGroup *) [self elementWithClass: groupClass];
[newGroup setChildrenAsCopy: children];
}
return newGroup;
}
- (void) setChildrenAsCopy: (NSMutableArray *) someChildren
{
[children release];
children = someChildren;
[children retain];
}
- (void) addChildWithTag: (NSString *) aTag
types: (NSArray *) someTypes
singleValue: (NSString *) aValue
{
CardElement *newChild;
NSEnumerator *types;
NSString *type;
newChild = [CardElement simpleElementWithTag: aTag value: aValue];
types = [someTypes objectEnumerator];
type = [types nextObject];
while (type)
{
[newChild addType: type];
type = [types nextObject];
}
[self addChild: newChild];
}
- (NSString *) description
{
NSMutableString *str;
unsigned int count, max;
str = [NSMutableString stringWithCapacity:64];
[str appendFormat:@"<%p[%@]:%@",
self, NSStringFromClass([self class]), [self tag]];
max = [children count];
if (max > 0)
{
[str appendFormat: @"\n %d children: {\n", [children count]];
for (count = 0; count < max; count++)
[str appendFormat: @" %@\n",
[[children objectAtIndex: count] description]];
[str appendFormat: @"}"];
}
[str appendString:@">"];
return str;
}
- (void) replaceThisElement: (CardElement *) oldElement
withThisOne: (CardElement *) newElement
{
unsigned int index;
index = [children indexOfObject: oldElement];
if (index != NSNotFound)
[children replaceObjectAtIndex: index withObject: newElement];
}
- (id) copyWithZone: (NSZone *) aZone
{
CardGroup *new;
new = [super copyWithZone: aZone];
[new setChildrenAsCopy: [children copyWithZone: aZone]];
return new;
}
@end

View File

@ -0,0 +1,37 @@
/* CardVersitRenderer.h - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef CARDCARDRENDERER_H
#define CARDCARDRENDERER_H
#import <Foundation/NSObject.h>
@class CardGroup;
@class NSString;
@interface CardVersitRenderer : NSObject
- (NSString *) render: (id) anElement;
@end
#endif /* CARDCARDRENDERER_H */

View File

@ -0,0 +1,136 @@
/* CardVersitRenderer.m - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <NGExtensions/NSObject+Logs.h>
#import "CardElement.h"
#import "CardGroup.h"
#import "NSString+NGCards.h"
#import "NSArray+NGCards.h"
#import "CardVersitRenderer.h"
@interface CardVersitRenderer (PrivateAPI)
- (NSString *) renderElement: (CardElement *) anElement;
- (NSString *) renderGroup: (CardGroup *) aGroup;
@end
@implementation CardVersitRenderer
- (NSString *) render: (id) anElement
{
return (([anElement isKindOfClass: [CardGroup class]])
? [self renderGroup: anElement]
: [self renderElement: anElement]);
}
- (NSString *) renderElement: (CardElement *) anElement
{
NSMutableString *rendering;
NSDictionary *attributes;
NSEnumerator *keys;
NSArray *values, *renderedAttrs;
NSString *key, *finalRendering, *tag;
if (![anElement isVoid])
{
rendering = [NSMutableString new];
[rendering autorelease];
if ([anElement group])
[rendering appendFormat: @"%@.", [anElement group]];
tag = [anElement tag];
if (!(tag && [tag length]))
{
tag = @"<no-tag>";
[self warnWithFormat: @"card element of class '%@' has an empty tag",
NSStringFromClass([anElement class])];
}
[rendering appendString: [tag uppercaseString]];
attributes = [anElement attributes];
keys = [[attributes allKeys] objectEnumerator];
key = [keys nextObject];
while (key)
{
renderedAttrs = [[attributes objectForKey: key] renderedForCards];
[rendering appendFormat: @";%@=%@",
[key uppercaseString],
[renderedAttrs componentsJoinedByString: @","]];
key = [keys nextObject];
}
values = [anElement values];
if ([values count] > 0)
[rendering appendFormat: @":%@",
[[values renderedForCards] componentsJoinedByString: @";"]];
if ([rendering length] > 0)
[rendering appendString: @"\r\n"];
finalRendering = [rendering foldedForVersitCards];
}
else
finalRendering = @"";
return finalRendering;
}
- (NSString *) renderGroup: (CardGroup *) aGroup
{
NSEnumerator *children;
CardElement *currentChild;
NSMutableString *rendering;
NSString *groupTag;
rendering = [NSMutableString new];
[rendering autorelease];
groupTag = [aGroup tag];
if (!(groupTag && [groupTag length]))
{
groupTag = @"<no-tag>";
[self warnWithFormat: @"card group of class '%@' has an empty tag",
NSStringFromClass([aGroup class])];
}
groupTag = [groupTag uppercaseString];
[rendering appendFormat: @"BEGIN:%@\r\n", groupTag];
children = [[aGroup children] objectEnumerator];
currentChild = [children nextObject];
while (currentChild)
{
[rendering appendString: [self render: currentChild]];
currentChild = [children nextObject];
}
[rendering appendFormat: @"END:%@\r\n", groupTag];
return rendering;
}
@end

View File

@ -0,0 +1,600 @@
2006-08-03 Helge Hess <helge.hess@opengroupware.org>
* NGVCardSaxHandler.m: fixed a bug with returning parsing results.
Properly make a copy of the vCard array so that -clear doesn't
destroy references. Thanks go to Wolfgang Sourdeau for documenting
the issue! (v4.5.76)
2006-07-04 Helge Hess <helge.hess@opengroupware.org>
* use %p for pointer formats, fixed gcc 4.1 warnings (v4.5.75)
2006-05-16 Marcus Mueller <znek@mulle-kybernetik.com>
* iCalDataSource.h, common.h: changed EOControl related includes into
imports to enable compilation against MulleEOF (v4.5.74)
2006-04-07 Marcus Mueller <znek@mulle-kybernetik.com>
* iCalEntityObject.h: added missing forward declaration for
gstep-base compile (v4.5.73)
2006-04-06 Marcus Mueller <znek@mulle-kybernetik.com>
* v4.5.72
* iCalEntityObject.[hm]: added "url" property - unfortunately
this was missing before. Increased class version to "1".
* iCalRepeatableEntityObject.m, iCalEvent.m, iCalToDo.m: adjusted
super class version check.
2006-01-16 Helge Hess <helge.hess@opengroupware.org>
* iCalRecurrenceRule.m: properly include NSString+Ext.h to avoid a
warning during Cocoa compilation (v4.5.71)
2005-11-17 Helge Hess <helge.hess@opengroupware.org>
* include string.h where required (v4.5.70)
2005-10-05 Helge Hess <helge.hess@opengroupware.org>
* iCalMonthlyRecurrenceCalculator.m: implemented calculation of
negative byday occurrences (eg -1TH) (v4.5.69)
2005-09-22 Helge Hess <helge.hess@skyrix.com>
* iCalRecurrenceRule.m: added direct parser support for 'interval',
allow 'until' values w/o Z marker for date-only values (v4.5.68)
2005-09-22 Helge Hess <helge.hess@opengroupware.org>
* v4.5.67
* iCalMonthlyRecurrenceCalculator.m: finished 'byday' calculation
* iCalRecurrenceRule.m: added support for 'bymonthday', fixed handling
of occurrence1
2005-09-21 Helge Hess <helge.hess@skyrix.com>
* v4.5.66
* iCalRecurrenceRule.m: temporarily expose byDayOccurence1 until the
API is fixed
* iCalMonthlyRecurrenceCalculator.m: prepared for byday/bymonthday
rule specs
* v4.5.65
* iCalMonthlyRecurrenceCalculator.m: fixed calculation of 'count' field
* iCalRecurrenceCalculator.m: minor code cleanups
* iCalRecurrenceRule.m: improved rrule parser
2005-09-20 Helge Hess <helge.hess@opengroupware.org>
* iCalMonthlyRecurrenceCalculator.m: stop calculation if a byday part
was detected in the rule (v4.5.64)
* iCalRecurrenceCalculator.m: moved cluster subclasses to own source
files (v4.5.63)
* iCalRecurrenceRule.m: added some parsing/gen support for BYDAY
(v4.5.62)
2005-09-19 Helge Hess <helge.hess@opengroupware.org>
* iCalRecurrenceRule.m: minor code improvements, more tolerant on
invalid iCal rrule input (v4.5.61)
2005-08-16 Helge Hess <helge.hess@opengroupware.org>
* GNUmakefile, GNUmakefile.preamble: added OSX framework compilation
(v4.5.60)
2005-08-06 Helge Hess <helge.hess@opengroupware.org>
* iCalCalendar.m, NGVCardName.m: fixed gcc 4.0 warnings (v4.5.59)
2005-08-05 Helge Hess <helge.hess@opengroupware.org>
* NGVCardSaxHandler.h: fixed a gcc 4.0 warning (v4.5.58)
2005-07-18 Helge Hess <helge.hess@opengroupware.org>
* iCalPerson.m: added -partStatWithDefault method to retrieve the
partstat and return NEEDS-ACTION in case none is set (v4.5.57)
2005-07-15 Marcus Mueller <znek@mulle-kybernetik.com>
* iCalObject.[hm], iCalEntityObject.m, iCalToDo.m, iCalAlarm.m,
iCalPerson.m, iCalCalendar.m, iCalEvent.m, iCalTrigger.m,
iCalObject.m, iCalFreeBusy.m, iCalRepeatableEntityObject.m:
fixed NSCopying (v4.5.56)
2005-07-15 Helge Hess <helge.hess@opengroupware.org>
* added fragile base class version checks (v4.5.55)
2005-07-15 Marcus Mueller <znek@mulle-kybernetik.com>
* iCalObject.[hm], iCalEntityObject.m, iCalToDo.m, iCalAlarm.m,
iCalPerson.m, iCalCalendar.m, iCalEvent.m, iCalTrigger.m,
iCalObject.m, iCalFreeBusy.m, iCalRepeatableEntityObject.m:
added NSCopying (v4.5.54)
2005-07-15 Helge Hess <helge.hess@opengroupware.org>
* v4.5.53
* iCalCalendar.m: added +parseCalendarFromSource: convenience method
* NGVCard.m: properly reset sax driver after parsing
2005-07-15 Marcus Mueller <znek@mulle-kybernetik.com>
* iCalEntityObject.[hm]: added -increaseSequence (v4.5.52)
* iCalPerson.m: fixed -hasSameEmailAddress: to lowercase email
addresses before attempting comparison (v4.5.51)
2005-07-15 Helge Hess <helge.hess@opengroupware.org>
* v4.5.50
* NGiCal.xmap: fixed mapping of 'method' property (is an attribute of
the calendar)
* iCalCalendar.m: use ASSIGNCOPY in accessors, added 'method' to
-description
2005-07-14 Marcus Mueller <znek@mulle-kybernetik.com>
* v4.5.49
* iCalCalendar.[hm]: added 'method'
* iCalEntityObject.[hm]: added 'userComment', changed all email
related comparisons to lowercase all strings before comparison
* iCalEvent.h: pretty printed iVars
* NGiCal.xmap: added mapping for 'comment' -> 'userComment' and
'method' -> 'method'
2005-07-13 Helge Hess <helge.hess@opengroupware.org>
* v4.5.48
* NGVCard.m: added some convenience methods to access the preferred
email, tel and adr
* NGVCardOrg.m: added a convenience method to access the first orgunit
2005-07-05 Marcus Mueller <znek@mulle-kybernetik.com>
* NSCalendarDate+ICal.m: fixed 'gmtcalfmt' which removed seconds from
format for no obvious reason (v4.5.47)
2005-05-31 Helge Hess <helge.hess@skyrix.com>
* NGVCardSaxHandler.m: ensure that types are always uppercase, improved
check for DUPs (v4.5.46)
2005-05-16 Marcus Mueller <znek@mulle-kybernetik.com>
* NGiCal.xcode: reorganized ordering of headers/classes
2005-05-15 Marcus Mueller <znek@mulle-kybernetik.com>
* NGiCal.xcode: added vCard related stuff
2005-05-10 Helge Hess <helge.hess@opengroupware.org>
* NGVCard.m: added support for profile, source, name (v4.5.45)
2005-05-09 Helge Hess <helge.hess@opengroupware.org>
* first version of working vCard SAX handler (v4.5.54)
2005-05-08 Helge Hess <helge.hess@opengroupware.org>
* more work on vCard parsing (v4.5.53)
* work on vCard objects (incomplete) (v4.5.52)
2005-04-25 Helge Hess <helge.hess@opengroupware.org>
* iCalDateHolder.m, iCalDataSource.m: fixed gcc 4.0 warnings (v4.5.51)
2005-03-23 Marcus Mueller <znek@mulle-kybernetik.com>
* v4.5.50
* iCalRenderer.h: added missing paranthesis for iVar declarations
* iCalTrigger.m, iCalEntityObject.m, iCalToDo.m,
iCalRecurrenceCalculator.m, iCalDateHolder.m, iCalDataSource.m,
iCalPerson.m, iCalCalendar.m: numerous dealloc bugs/leaks fixed
2005-03-02 Marcus Mueller <znek@mulle-kybernetik.com>
* iCalRecurrenceCalculator.m: bugfix for monthly and yearly recurrences
(v4.5.49)
* iCalRecurrenceCalculator.m: optimized exception date handling in
complex calculation method quite a bit. Fixed bugs in all calculation
methods by introducing checks on the desired range. (v4.5.48)
2005-02-28 Marcus Mueller <znek@mulle-kybernetik.com>
* v4.5.47
* iCalRepeatableEntityObject.m: shifted code to
iCalRecurrenceCalculator
* iCalRecurrenceCalculator.[hm]: new class method to calculate
complex recurrences. In SOGo this information is stored in quick
fields to reduce the complexity of lookups, hence we need to offer
a proper API to calculate date ranges from this information.
Fixed all calculations to explicitly set timeZone for all newly
created startDates - it seems the timeZone information is not
properly retained by the hour:minute:second: method from NGExtensions
which lead to improper DST related shifts.
* iCalDateHolder.h: exposed the API
* NSCalendarDate+ICal.[hm]: new convenience constructor for calendar
dates from iCal representations (uses iCalDateHolder internally)
* iCalRecurrenceRule.m: changed setUntil: to utilize new public
NSCalendarDate+ICal category
* NGiCal.h: added NSCalendarDate+ICal.h to the public headers
* GNUmakefile: NSCalendarDate+ICal.h is public now
2005-02-20 Helge Hess <helge.hess@opengroupware.org>
* NGiCal.xmap: fixed a missing semicolon (did not load on MacOSX)
(v.4.5.46)
2005-02-17 Helge Hess <helge.hess@skyrix.com>
* GNUmakefile.preamble: fixed linking locations for dependencies
(v4.5.45)
2005-02-17 Marcus Mueller <znek@mulle-kybernetik.com>
* v4.5.44
* iCalEntityObject.[hm]: added convenience API
* iCalRepeatableEntityObject.[hm]: added convenience API
* iCalRecurrenceRule.m: bugfixes in -byDayList and
-iCalRepresentationForWeekDay:
* iCalRecurrenceCalculator.m: implemented 'BYDAY' calculations for
weekly frequency. Note that 'COUNT' is still broken for this case.
* iCalRenderer.m: updated rendering, now can render recurrence rules
and accompanied stuff properly.
2005-02-15 Marcus Mueller <znek@mulle-kybernetik.com>
* v4.5.43
* iCalRecurrenceRule.[hm]: exposed some more of the API
* iCalRecurrenceCalculator.m: some bugfixes. Split the code and gave
iCalWeeklyRecurrenceCalculator its own calculation - there are a
number of foreseeable differences to daily calculation that make
this necessary in the near future anyways.
* v4.5.42
* iCalRepeatableEntityObject.[hm]: added ability to properly calculate
the recurrence ranges within a specific calendar date range, taking
all possible exceptions into account.
* iCalEvent.[hm]: convenience wrapper for the new method found in
iCalRepeatableEntityObject.
2005-02-14 Helge Hess <helge.hess@opengroupware.org>
* v4.5.41
* GNUmakefile.preamble: added missing dependency on libNGExtensions
(which also adds the dependency on libDOM)
* iCalRecurrenceCalculator.h: fixed missing forward declaration in
header
2005-02-12 Marcus Mueller <znek@mulle-kybernetik.com>
* v4.5.40
* iCalRecurrenceCalculator.[hm]: implemented all required (and simple)
calculations. Added some convenience API to query some of the more
obvious ranges suitable as limits for fetching/comparison.
* iCalRepeatableEntityObject.[hm]: new method for calculating the
last possible recurrence start date. This can be used for fetches
as well.
* iCalEvent.[hm]: more convenient wrapper for the new method found in
iCalRepeatableEntityObject.
* NSCalendarDate+ICal.[hm]: convenience methods for calculating
"distances" between dates.
* tests/*: updated
2005-02-11 Marcus Mueller <znek@mulle-kybernetik.com>
* v4.5.39
* README: updated
* iCalRepeatableEntityObject.[hm]: new base class for all other
repeatable entity objects. Offers a convenience API for generating
recurrence ranges and tests, taking all exceptions into account.
* iCalRecurrenceRule.[hm]: an iCal recurrence rule, modeled as closely
as possible to RFC2445. Please note that this is work in progress
and far from being complete, yet.
* iCalRecurrenceCalculator.[hm]: a controller implementing RFC2445
to properly generate recurrence ranges and accompanied functionality.
* iCalEvent.[hm], iCalToDo.[hm]: now subclasses from
iCalRepeatableEntityObject, thus removed code dealing with
recurrences
* NGiCal.h: added new headers
* NGiCal.xmap: changed recurrenceRule mappings due to model change
* tests/*: contains unit tests for stuff dealing with recurrences. See
accompanied README for details
2004-12-17 Marcus Mueller <znek@mulle-kybernetik.com>
* iCalPerson.[hm]: formalized participationStatus according to RFC2445.
Provided convenience API to set status without concrete knowledge
of string values involved. (v4.5.38)
2004-12-16 Marcus Mueller <znek@mulle-kybernetik.com>
* v4.5.37
* iCalEvent.[hm]: Added transparency 'TRANSP'. Also multiple
convenience methods provided.
* NGiCal.xmap: added proper mapping for 'transp'.
2004-12-14 Marcus Mueller <znek@mulle-kybernetik.com>
* NGiCal.xcode: minor changes and updated
2004-12-13 Marcus Mueller <znek@mulle-kybernetik.com>
* iCalPerson.[hm]: added -cnWithoutQuotes and -rfc822Email convenience
methods to simplify client code dealing with these properties
(v4.5.36)
2004-11-07 Marcus Mueller <znek@mulle-kybernetik.com>
* NGiCal.xcode: provide SOPE_{MAJOR,MINOR}_VERSION to the build
2004-11-06 Helge Hess <helge.hess@opengroupware.org>
* iCalRenderer.m: use SOPE version defines for iCalendar product id
(v4.5.35)
2004-11-04 Helge Hess <helge.hess@skyrix.com>
* use Version file for install directory location of sax mapping
2004-10-31 Marcus Mueller <znek@mulle-kybernetik.com>
* iCalAlarm.[hm], iCalEvent.[hm], iCalToDo.[hm],
NGiCal.xmap: added recurrenceRule (v4.3.34)
2004-10-20 Marcus Mueller <znek@mulle-kybernetik.com>
* NGiCal.xcode: added iCalRenderer.[hm], bumped framework version
2004-10-20 Helge Hess <helge.hess@opengroupware.org>
* iCalRenderer.m: fixed some issue with Cocoa Foundation (v4.3.33)
* v4.3.32
* iCalEvent.m: added -vEvent method to produce an iCalendar
representation of an event
* added iCalRenderer class based on the SOGo render by ZNeK
2004-10-14 Marcus Mueller <znek@mulle-kybernetik.com>
* NGiCal.xmap: added "categories" mapping (v4.3.31)
2004-10-05 Marcus Mueller <znek@mulle-kybernetik.com>
* iCalEntityObject.[hm]: added categories property (v4.3.30)
2004-09-22 Marcus Mueller <znek@mulle-kybernetik.com>
* NGiCal.xcode: fixed several build parameters
2004-09-01 Marcus Mueller <znek@mulle-kybernetik.com>
* v4.3.29
* iCalEventChanges.[hm]: new class for tracking changes between
two given events
* iCalEvent.[hm]: new API to generate iCalEventChanges objects.
* common.h: inline function and macro for "safe" comparison of
object values
2004-09-01 Helge Hess <helge.hess@opengroupware.org>
* GNUmakefile.postamble: copy sax-model to FHS_INSTALL_ROOT +
/share/sope-4.3/saxmappings/ when compiling for FHS (v4.3.28)
2004-08-29 Helge Hess <helge.hess@opengroupware.org>
* added hack to install the project in FHS locations - the library,
its headers, the tools and the resources will be installed in
FHS_INSTALL_ROOT if specified (eg make FHS_INSTALL_ROOT=/usr/local)
(v4.3.27)
2004-08-26 Marcus Mueller <znek@mulle-kybernetik.com>
* NGiCal.xcode: new Xcode project
2004-08-20 Helge Hess <helge.hess@opengroupware.org>
* fixed for SOPE 3.3 directory layout (v4.3.26)
* moved to sope-ical
* moved to SOPE 4.3 (v4.3.25)
2004-08-14 Helge Hess <helge.hess@opengroupware.org>
* iCalEntityObject.m: changed "sequence" attribute from NSString to
NSNumber (this might break some code, though some care was taken to
accept NSString parameters) (v4.2.24)
2004-07-14 Helge Hess <helge.hess@opengroupware.org>
* iCalEvent.h: moved 'status' field to iCalEntityObject, because it is
also available in todo objects (v4.2.23)
2004-06-30 Marcus Mueller <znek@mulle-kybernetik.com>
* iCalEntityObject.m: added -removeAllAttendees and -removeAllAlarms.
These are necessary in case you want to remake the contents of these
collections, but keep all other attributes otherwise. (v4.2.22)
2004-06-09 Helge Hess <helge.hess@opengroupware.org>
* v4.2.21
* GNUmakefile.preamble: added prebinding
* GNUmakefile: create GNUmakefile.preamble, GNUmakefile.postamble
2004-05-05 Marcus Mueller <znek@mulle-kybernetik.com>
* GNUmakefile: added support for building with
GNUSTEP_BUILD_DIR environment variable set for recent
gnustep-make package. (v4.2.20)
2004-01-23 Helge Hess <helge.hess@opengroupware.org>
* iCalDataSource.m: added some sanity checks, improved to work better
with Mozilla generated iCal files (v4.2.19)
2003-12-22 Helge Hess <helge.hess@skyrix.com>
* iCalDateHolder.m: small fix not to print a warning for "YYYYMMDD"
style dates (which are supported) (v4.2.18)
2003-12-21 Helge Hess <helge.hess@opengroupware.org>
* v4.2.17
* iCalEvent.m: added parsing of duration values and calculation of
end-dates based on that (eg required for Panther iCal.app)
* iCalEvent.m: added support for 'status' and 'duration' fields
Thu Nov 20 16:31:15 2003 Martin Hoerning <martin@opengroupware.org>
* iCalDateHolder.m: added timeless date format: YYYYMMDD
(solves ogo bug 424) (v4.2.16)
Wed Oct 29 22:04:32 2003 Martin Hoerning <martin@opengroupware.org>
* iCalDateHolder.m, iCalObject.[m|h]: added iCalDefaultTimeZone to
create date from iCalDates without timeZone. (solves OGoo bug 257)
(v4.2.15)
2003-10-12 Helge Hess <helge@opengroupware.org>
* GNUmakefile (libNGiCal_LIBRARIES_DEPEND_UPON): link against
libSaxObjC on MacOSX (v4.2.14)
Fri Jul 18 17:04:55 2003 Martin Hoerning <mh@skyrix.com>
* iCalToDo.h, iCalPerson.h, iCalEvent.h, iCalEntityObject.h: added
accessor-methods to interface (v4.2.13)
2003-07-18 Helge Hess <helge.hess@skyrix.com>
* iCalDateHolder.m: replaces and indexOfString with rangeOfString,
thanks to Filip Van Raemdonck for pointing that out (v4.2.12)
2003-03-21 Helge Hess <helge.hess@skyrix.com>
* added some method prototypes
2003-03-13 Helge Hess <helge.hess@skyrix.com>
* moved iCalEntityObject to a separate file (v4.2.11)
Mon Mar 10 18:41:10 2003 Bjoern Stierand <bjoern@skyrix.com>
* NGiCal.xmap: added missing attendee attributes (as dictated by
mh on the phone)
2003-03-10 Helge Hess <helge.hess@skyrix.com>
* iCalPerson.h: added some method prototypes
2003-02-24 Helge Hess <helge.hess@skyrix.com>
* iCalObject.h: added some accessors (v4.2.10)
2003-02-12 Helge Hess <helge.hess@skyrix.com>
* moved to skyrix-core (v4.2.9)
2003-01-13 Helge Hess <helge.hess@skyrix.com>
* added some support for timezones to be able to parse Evolution
apt creation requests (v4.2.7)
2002-10-14 Helge Hess <helge.hess@skyrix.com>
* added iCalDateHolder for decoding xCal date values with timezone
attributes to a NSCalendarDate
* iCalObject.m: ignore X- keys
* removed all the old stuff (v4.2.4)
* ICalVEvent.m: renamed -class to -eventClass since -class conflicts
with the NSObject method
* started XML based iCal (v4.2.3)
2002-10-10 Helge Hess <helge.hess@skyrix.com>
* ICalParser.m: small cleanups (v4.2.2)
2002-10-04 Helge Hess <helge.hess@skyrix.com>
* created ChangeLog, created NGiCal library into SkyCore

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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 <NGObjWeb/WODynamicElement.h>
@interface IcalComponent : WODynamicElement
{
WOAssociation *cname;
WOElement *template;
}
@end
@interface IcalProperty : WODynamicElement
{
WOAssociation *pname;
WOElement *template;
NSDictionary *parameters;
WOAssociation *value;
WOAssociation *valueType;
}
@end
#include "common.h"
static inline NSDictionary *ExtractParameters(NSDictionary *_set) {
/* extracts ? parameters */
NSMutableDictionary *paras = nil;
NSMutableArray *paraKeys = nil;
NSEnumerator *keys;
NSString *key;
// locate query parameters
keys = [_set keyEnumerator];
while ((key = [keys nextObject])) {
if ([key hasPrefix:@"?"]) {
WOAssociation *value;
if ([key isEqualToString:@"?wosid"])
continue;
value = [_set objectForKey:key];
if (paraKeys == nil)
paraKeys = [NSMutableArray arrayWithCapacity:8];
if (paras == nil)
paras = [NSMutableDictionary dictionaryWithCapacity:8];
[paraKeys addObject:key];
[paras setObject:value forKey:[key substringFromIndex:1]];
}
}
// remove query parameters
if (paraKeys) {
unsigned cnt, count;
for (cnt = 0, count = [paraKeys count]; cnt < count; cnt++) {
[(NSMutableDictionary *)_set removeObjectForKey:
[paraKeys objectAtIndex:cnt]];
}
}
// assign parameters
return [paras copy];
}
static inline id GetProperty(NSDictionary *_set, NSString *_name) {
id propValue = [_set objectForKey:_name];
if (propValue) {
propValue = RETAIN(propValue);
[(id)_set removeObjectForKey:_name];
}
return propValue;
}
@implementation IcalComponent
- (id)initWithName:(NSString *)_name
associations:(NSDictionary *)_config
template:(WOElement *)_t
{
if ((self = [super initWithName:_name associations:_config template:_t])) {
self->cname = GetProperty(_config, @"name");
self->template = RETAIN(_t);
}
return self;
}
- (void)dealloc {
RELEASE(self->template);
RELEASE(self->cname);
[super dealloc];
}
- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
NSString *n;
n = [self->cname stringValueInComponent:[_ctx component]];
[_response appendContentString:@"BEGIN:"];
[_response appendContentString:n];
[self->template appendToResponse:_response inContext:_ctx];
[_response appendContentString:@"END:"];
[_response appendContentString:n];
}
@end /* IcalComponent */
@implementation IcalProperty
- (id)initWithName:(NSString *)_name
associations:(NSDictionary *)_config
template:(WOElement *)_t
{
if ((self = [super initWithName:_name associations:_config template:_t])) {
self->pname = GetProperty(_config, @"name");
self->value = GetProperty(_config, @"value");
self->valueType = GetProperty(_config, @"valueType");
self->template = RETAIN(_t);
self->parameters = ExtractParameters(_config);
}
return self;
}
- (void)dealloc {
RELEASE(self->value);
RELEASE(self->valueType);
RELEASE(self->parameters);
RELEASE(self->template);
RELEASE(self->pname);
[super dealloc];
}
- (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
WOComponent *sComponent;
NSString *n;
NSEnumerator *keys;
NSString *key;
id val;
NSString *valType;
sComponent = [_ctx component];
n = [self->pname stringValueInComponent:sComponent];
val = [self->value valueInComponent:sComponent];
valType = [self->valueType stringValueInComponent:sComponent];
/* add name */
[_response appendContentString:n];
/* add parameters */
keys = [self->parameters keyEnumerator];
while ((key = [keys nextObject])) {
WOAssociation *val;
NSString *s;
val = [self->parameters objectForKey:key];
s = [val stringValueInComponent:sComponent];
if ([s length] > 0) {
[_response appendContentString:@";"];
[_response appendContentString:key];
[_response appendContentString:@"="];
[_response appendContentString:s];
}
}
/* add value */
[_response appendContentString:@":"];
if ([valType length] == 0) {
val = [val stringValue];
}
else if ([valType isEqualToString:@"datetime"]) {
static NSString *calfmt = @"%Y%m%dT%H%M00Z";
if ([val respondsToSelector:@selector(descriptionWithCalendarFormat:)]) {
static NSTimeZone *gmt = nil;
if (gmt == nil) gmt = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
[val setTimeZone:gmt];
val = [val descriptionWithCalendarFormat:calfmt];
}
else
val = [val stringValue];
}
else
val = [val stringValue];
[_response appendContentString:val];
[self->template appendToResponse:_response inContext:_ctx];
}
@end /* IcalProperty */

View File

@ -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 <Foundation/NSObject.h>
@class NSMutableString, NSData;
@interface IcalResponse : NSObject
{
NSMutableString *content;
BOOL isFinished;
}
- (id)initWithCapacity:(unsigned)_capacity;
- (void)finish;
- (NSString *)asString;
- (BOOL)appendLine:(NSString *)_line;
// _attr:_line
- (BOOL)appendLine:(NSString *)_line forAttribute:(NSString *)_attr;
@end /* IcalResponse */
#endif /* __SkyDaemon_skyaptd_IcalResponse_H__ */

View File

@ -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 <Foundation/Foundation.h>
@implementation IcalResponse
- (void)_initContent {
[self appendLine:@"BEGIN:VCALENDAR"];
[self appendLine:@"VERSION:2.0"];
[self appendLine:@"PRODID:-//skyrix42/scheduler/skyaptd v.1.0//"];
}
- (id)init {
if ((self = [super init])) {
self->content = [[NSMutableString alloc] initWithCapacity:0xFFFF];
self->isFinished = NO;
[self _initContent];
}
return self;
}
- (id)initWithCapacity:(unsigned)_capacity {
if ((self = [super init])) {
self->content = [[NSMutableString alloc] initWithCapacity:_capacity];
self->isFinished = NO;
[self _initContent];
}
return self;
}
- (void)dealloc {
[self->content release];
[super dealloc];
}
- (BOOL)appendLine:(NSString *)_line {
if (self->isFinished) {
NSLog(@"WARNING[%s]: already finished!", __PRETTY_FUNCTION__);
return NO;
}
// limit length to 75 chars
while ([_line length] > 75) {
[self appendLine:[_line substringToIndex:75]];
_line = [@" " stringByAppendingString:[_line substringFromIndex:75]];
}
[self->content appendString:_line];
[self->content appendString:@"\r\n"];
return YES;
}
- (BOOL)appendLine:(NSString *)_line forAttribute:(NSString *)_attr {
_line = [NSString stringWithFormat:@"%@:%@", _attr, _line];
return [self appendLine:_line];
}
- (void)finish {
if (self->isFinished) return;
[self appendLine:@"END:VCALENDAR"];
self->isFinished = YES;
}
- (NSString *)asString {
[self finish];
return [[self->content copy] autorelease];
}
@end /* IcalResponse */

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>NGiCal</string>
<key>CFBundleGetInfoString</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>org.OpenGroupware.SOPE.ical.NGiCal</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string></string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>4.5</string>
</dict>
</plist>

View File

@ -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 <NGCards/iCalAttachment.h>
#import <NGCards/iCalObject.h>
#import <NGCards/iCalEntityObject.h>
#import <NGCards/iCalRepeatableEntityObject.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalToDo.h>
#import <NGCards/iCalJournal.h>
#import <NGCards/iCalEvent.h>
#import <NGCards/iCalFreeBusy.h>
#import <NGCards/iCalPerson.h>
#import <NGCards/iCalAlarm.h>
#import <NGCards/iCalTrigger.h>
#import <NGCards/iCalEventChanges.h>
#import <NGCards/iCalRecurrenceRule.h>
#import <NGCards/iCalRecurrenceCalculator.h>
#import <NGCards/NSCalendarDate+ICal.h>
#import <NGCards/NSArray+NGCards.h>
#import <NGCards/NSCalendarDate+ICal.h>
#import <NGCards/NSCalendarDate+NGCards.h>
#import <NGCards/NSDictionary+NGCards.h>
#import <NGCards/NSString+NGCards.h>
#endif /* __NGCards_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -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;
};
};
}

View File

@ -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 <SaxObjC/SaxDefaultHandler.h>
/*
NGCardsSaxHandler
This SAX handler is supposed to create the NGiCal object model from SAX
events.
*/
@class NSString, NSMutableString, NSMutableArray;
@class NSDictionary, NSMutableDictionary;
@class CardElement;
@class CardGroup;
@interface NGCardsSaxHandler : SaxDefaultHandler
{
NSMutableArray *cards;
CardElement *currentElement;
CardGroup *currentCardGroup;
NSString *currentGroup;
unichar *content;
unsigned contentLength;
NSMutableDictionary *xtags;
NSMutableDictionary *subvalues;
NSMutableArray *types;
NSMutableDictionary *args;
NSMutableArray *tel;
NSMutableArray *adr;
NSMutableArray *email;
NSMutableArray *label;
NSMutableArray *url;
NSMutableArray *fburl;
NSMutableArray *caluri;
struct {
int isInVCardSet:1;
int isInVCard:1;
int isInN:1;
int isInAdr:1;
int isInOrg:1;
int isInGroup:1;
int isInGeo:1;
int collectContent:1;
int reserved:24;
} vcs;
Class topGroupClass;
}
/* results */
- (NSArray *) cards;
- (void)reset;
/* content */
- (void) startCollectingContent;
- (NSArray *) finishCollectingContent;
- (void) startGroupElement: (NSString *) _localName;
- (void) endGroupElement;
- (void) setTopElementClass: (Class) aGroupClass;
@end
#endif /* __NGiCal_NGCardsSaxHandler_H__ */

View File

@ -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 <string.h>
#import "CardGroup.h"
#ifndef XMLNS_VCARD_XML_03
# define XMLNS_VCARD_XML_03 \
@"http://www.ietf.org/internet-drafts/draft-dawson-vcard-xml-dtd-03.txt"
#endif
@implementation NGCardsSaxHandler
- (id) init
{
if ((self = [super init]))
topGroupClass = nil;
return self;
}
- (void) dealloc
{
if (content)
free(content);
[cards release];
if (currentGroup)
[currentGroup release];
[super dealloc];
}
/* results */
- (NSArray *) cards
{
return [[cards copy] autorelease];;
}
/* state */
- (void)resetExceptResult
{
if (content)
{
free(content);
content = NULL;
}
vcs.isInVCardSet = 0;
vcs.collectContent = 0;
}
- (void) reset
{
[self resetExceptResult];
[cards removeAllObjects];
}
/* document events */
- (void) startDocument
{
if (!cards)
cards = [[NSMutableArray alloc] initWithCapacity:16];
[self reset];
}
- (void) endDocument
{
[self resetExceptResult];
}
/* common tags */
- (void) startValueTag: (NSString *) _tag
attributes: (id<SaxAttributes>) _attrs
{
/* a tag with types and attributes */
unsigned i, count;
[types removeAllObjects];
[args removeAllObjects];
for (i = 0, count = [_attrs count]; i < count; i++) {
NSString *n, *v;
n = [_attrs nameAtIndex:i];
v = [_attrs valueAtIndex:i];
if ([n hasSuffix:@".type"] || [n isEqualToString:@"TYPE"]) {
/*
Note: types cannot be separated by comma! Its indeed always a space,eg
"work pref voice"
If you find commas, usually the vCard is broken.
*/
NSEnumerator *e;
NSString *k;
e = [[v componentsSeparatedByString:@" "] objectEnumerator];
while ((k = [e nextObject]) != nil) {
k = [k uppercaseString];
if ([types containsObject:k]) continue;
[types addObject:k];
}
}
else
[args setObject:v forKey:n];
}
}
- (void)endValueTag
{
[types removeAllObjects];
[args removeAllObjects];
}
/* handle elements */
- (void) startGroup: (NSString *)_name
{
vcs.isInGroup = 1;
ASSIGNCOPY(currentGroup, _name);
}
- (void) endGroup
{
vcs.isInGroup = 0;
[currentGroup release];
currentGroup = nil;
}
- (void)startVCardSet
{
currentCardGroup = nil;
currentGroup = nil;
vcs.isInVCardSet = 1;
}
- (void)endVCardSet
{
vcs.isInVCardSet = 0;
}
/* element events */
- (void) startElement:(NSString *)_localName
namespace:(NSString *)_ns
rawName:(NSString *)_rawName
attributes:(id<SaxAttributes>)_attrs
{
unsigned int count, max;
Class elementClass;
// NSLog (@"startElement localName: '%@'", _localName);
if ([_localName isEqualToString: @"vCardSet"])
[self startVCardSet];
else if ([_localName isEqualToString: @"group"])
[self startGroup: [_attrs valueAtIndex: 0]];
else if ([_localName isEqualToString: @"container"])
[self startGroupElement: [_attrs valueAtIndex: 0]];
else
{
if (currentCardGroup)
elementClass
= [currentCardGroup classForTag: [_localName uppercaseString]];
else
elementClass = topGroupClass;
if (!elementClass)
elementClass = [CardElement class];
currentElement = [elementClass elementWithTag: _localName];
[currentElement setTag: _localName];
if (currentGroup)
[currentElement setGroup: currentGroup];
max = [_attrs count];
for (count = 0; count < max; count++)
[currentElement addAttribute: [_attrs nameAtIndex: count]
value: [_attrs valueAtIndex: count]];
[currentCardGroup addChild: currentElement];
[self startCollectingContent];
}
}
- (void) endElement: (NSString *)_localName
namespace: (NSString *)_ns
rawName: (NSString *)_rawName
{
// NSLog (@"endElement localName: '%@'", _localName);
if ([_localName isEqualToString: @"vCardSet"])
[self endVCardSet];
else if ([_localName isEqualToString: @"group"])
[self endGroup];
else if ([_localName isEqualToString: @"container"])
[self endGroupElement];
else
[currentElement addValues: [self finishCollectingContent]];
}
/* content */
- (void) startCollectingContent
{
if (content) {
free(content);
content = NULL;
}
vcs.collectContent = 1;
}
- (NSArray *) finishCollectingContent
{
NSArray *contentValues;
NSString *s;
vcs.collectContent = 0;
if (content && contentLength)
{
s = [NSString stringWithCharacters: content
length: contentLength];
free (content);
content = NULL;
// NSLog (@"content: '%@'", s);
contentValues = [s componentsSeparatedByString: @";"];
}
else
contentValues = nil;
return contentValues;
}
- (void) characters:(unichar *)_chars
length:(int)_len
{
if (_len && _chars)
{
if (!content)
{
/* first content */
contentLength = _len;
content = calloc (_len + 1, sizeof(unichar));
memcpy (content, _chars, (_len * sizeof(unichar)));
}
else
{
/* increase content */
content =
realloc (content, (contentLength + _len+2) * sizeof(unichar));
memcpy (&(content[contentLength]), _chars,
(_len * sizeof(unichar)));
contentLength += _len;
}
content[contentLength] = 0;
}
}
- (void) startGroupElement: (NSString *) _localName
{
CardGroup *newGroup;
Class groupClass;
// NSLog (@"startGroupElement localName: '%@'", _localName);
if (currentCardGroup)
{
groupClass
= [currentCardGroup classForTag: [_localName uppercaseString]];
if (!groupClass)
groupClass = [CardGroup class];
newGroup = [groupClass groupWithTag: _localName];
[currentCardGroup addChild: newGroup];
}
else
{
if (topGroupClass)
groupClass = topGroupClass;
else
groupClass = [CardGroup class];
newGroup = [groupClass groupWithTag: _localName];
[cards addObject: newGroup];
}
currentCardGroup = newGroup;
}
- (void) endGroupElement
{
// NSLog (@"endGroupElement localName: '%@'", _localName);
if (currentCardGroup)
currentCardGroup = [currentCardGroup parent];
}
- (void) setTopElementClass: (Class) aGroupClass
{
topGroupClass = aGroupClass;
}
@end /* NGCardsSaxHandler */

View File

@ -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:
<!ELEMENT vCard (%prop.man;, (%prop.opt;)*)>
<!ATTLIST vCard
%attr.lang;
xmlns CDATA #FIXED
'http://www.ietf.org/internet-drafts/draft-dawson-vcard-xml-dtd-02.txt'
xmlns:vcf CDATA #FIXED
'http://www.ietf.org/internet-drafts/draft-dawson-vcard-xml-dtd-02.txt'
version CDATA #REQUIRED
rev CDATA #IMPLIED
uid CDATA #IMPLIED
prodid CDATA #IMPLIED
class (PUBLIC | PRIVATE | CONFIDENTIAL) "PUBLIC"
value NOTATION (VCARD) #IMPLIED>
<!-- version - Must be "3.0" if document conforms to this spec -->
<!-- rev - ISO 8601 formatted date or date/time string -->
<!-- uid - UID associated with the object described by the vCard -->
<!-- prodid - ISO 9070 FPI for product that generated vCard -->
<!-- class - Security classification for vCard information -->
Mandatory elements:
n
fn
*/
@class NSArray;
@class NSDictionary;
@class NSString;
@interface NGVCard : CardGroup
+ (id) cardWithUid: (NSString *) _uid;
- (id) initWithUid: (NSString *) _uid;
/* accessors */
- (void) setVersion: (NSString *) _version;
- (NSString *) version;
- (void) setUid: (NSString *) _uid;
- (NSString *) uid;
- (void) setPreferred: (CardElement *) aChild;
- (void) setVClass: (NSString *) _s;
- (NSString *) vClass;
- (void) setVName: (NSString *) _s;
- (NSString *) vName;
- (void) setProdID: (NSString *) _s;
- (NSString *) prodID;
- (void) setProfile: (NSString *) _s;
- (NSString *) profile;
- (void) setSource: (NSString *) _s;
- (NSString *) source;
- (void) setFn: (NSString *) _fn;
- (NSString *) fn;
- (void) setNickname: (NSString *) aValue;
- (NSString *) nickname;
- (void) setRole: (NSString *) _s;
- (NSString *) role;
- (void) setTitle: (NSString *) _title;
- (NSString *) title;
- (void) setBday: (NSString *) _bday;
- (NSString *) bday;
- (void) setNote: (NSString *) _note;
- (NSString *) note;
- (void) setTz: (NSString *) _tz;
- (NSString *) tz;
- (void) addTel: (NSString *) phoneNumber
types: (NSArray *) types;
- (void) addEmail: (NSString *) emailAddress
types: (NSArray *) types;
- (void) setNWithFamily: (NSString *) family
given: (NSString *) given
additional: (NSString *) additional
prefixes: (NSString *) prefixes
suffixes: (NSString *) suffixes;
- (NSArray *) n;
- (void) setOrg: (NSString *) anOrg
units: (NSArray *) someUnits;
- (NSArray *) org;
// - (void) setN: (NGVCardName *) _v;
// - (NGVCardName *) n;
// - (void) setOrg: (NGVCardOrg *) _v;
// - (NGVCardOrg *) org;
// - (void) setCategories: (id) _v;
// - (NGVCardStrArrayValue *) categories;
// - (void) setTel: (NSArray *) _tel;
// - (NSArray *) tel;
// - (void) setAdr: (NSArray *) _adr;
// - (NSArray *) adr;
// - (void) setEmail: (NSArray *) _array;
// - (NSArray *) email;
// - (void) setLabel: (NSArray *) _array;
// - (NSArray *) label;
// - (void) setUrl: (NSArray *) _url;
// - (NSArray *) url;
// - (void) setFreeBusyURL: (NSArray *) _v;
// - (NSArray *) freeBusyURL;
// - (void) setCalURI: (NSArray *) _calURI;
// - (NSArray *) calURI;
// - (void) setX: (NSDictionary *) _dict;
// - (NSDictionary *) x;
/* convenience */
- (NSString *) preferredEMail;
- (NSString *) preferredTel;
- (CardElement *) preferredAdr;
@end
#endif /* __NGiCal_NGVCard_H__ */

View File

@ -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 <Foundation/NSArray.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSString.h>
#import "NSArray+NGCards.h"
#import "NGVCard.h"
@implementation NGVCard
+ (id) parseSingleFromSource: (id) source
{
NGVCard *newCard;
newCard = [super parseSingleFromSource: source];
[newCard setVersion: @"3.0"];
return newCard;
}
+ (id) cardWithUid: (NSString *) _uid
{
NGVCard *newCard;
newCard = [[self alloc] initWithUid: _uid];
[newCard autorelease];
return newCard;
}
- (id) initWithUid: (NSString *) _uid
{
if ((self = [self init]))
{
[self setTag: @"vcard"];
[self setUid: _uid];
[self setVersion: @"3.0"];
}
return self;
}
/* class mapping */
- (Class) classForTag: (NSString *) classTag
{
Class tagClass;
tagClass = Nil;
if ([classTag isEqualToString: @"PRODID"]
|| [classTag isEqualToString: @"PRODID"]
|| [classTag isEqualToString: @"PROFILE"]
|| [classTag isEqualToString: @"UID"]
|| [classTag isEqualToString: @"CLASS"]
|| [classTag isEqualToString: @"N"]
|| [classTag isEqualToString: @"FN"]
|| [classTag isEqualToString: @"ORG"]
|| [classTag isEqualToString: @"ADR"]
|| [classTag isEqualToString: @"TEL"]
|| [classTag isEqualToString: @"TZ"]
|| [classTag isEqualToString: @"URL"]
|| [classTag isEqualToString: @"LABEL"]
|| [classTag isEqualToString: @"EMAIL"]
|| [classTag isEqualToString: @"NICKNAME"]
|| [classTag isEqualToString: @"NOTE"]
|| [classTag isEqualToString: @"BDAY"]
|| [classTag isEqualToString: @"TITLE"]
|| [classTag isEqualToString: @"VERSION"])
tagClass = [CardElement class];
else
tagClass = [super classForTag: classTag];
return tagClass;
}
- (void) setPreferred: (CardElement *) aChild
{
NSEnumerator *elements;
CardElement *element;
if (![aChild hasAttribute: @"type" havingValue: @"pref"])
{
elements = [[children cardElementsWithTag: tag] objectEnumerator];
element = [elements nextObject];
while (element)
{
[element removeValue: @"pref" fromAttribute: @"type"];
element = [elements nextObject];
}
[aChild addAttribute: @"type" value: @"pref"];
}
}
/* helpers */
- (NSArray *) childrenWithType: (NSString *) aType
{
return [self childrenWithAttribute: @"type" havingValue: aType];
}
/* accessors */
- (void) setVersion: (NSString *) _version
{
[[self uniqueChildWithTag: @"version"] setValue: 0 to: _version];
}
- (NSString *) version
{
return [[self uniqueChildWithTag: @"version"] value: 0];
}
- (void) setUid: (NSString *) _uid
{
[[self uniqueChildWithTag: @"uid"] setValue: 0 to: _uid];
}
- (NSString *) uid
{
return [[self uniqueChildWithTag: @"uid"] value: 0];
}
- (void) setVClass: (NSString *) _class
{
[[self uniqueChildWithTag: @"class"] setValue: 0 to: _class];
}
- (NSString *) vClass
{
return [[self uniqueChildWithTag: @"class"] value: 0];
}
- (void) setVName: (NSString *) _vname
{
[[self uniqueChildWithTag: @"vname"] setValue: 0 to: _vname];
}
- (NSString *) vName
{
return [[self uniqueChildWithTag: @"vname"] value: 0];
}
- (void) setProdID: (NSString *) _value
{
[[self uniqueChildWithTag: @"prodid"] setValue: 0 to: _value];
}
- (NSString *) prodID
{
return [[self uniqueChildWithTag: @"prodid"] value: 0];
}
- (void) setProfile: (NSString *) _value
{
[[self uniqueChildWithTag: @"profile"] setValue: 0 to: _value];
}
- (NSString *) profile
{
return [[self uniqueChildWithTag: @"profile"] value: 0];
}
- (void) setSource: (NSString *) _value
{
[[self uniqueChildWithTag: @"source"] setValue: 0 to: _value];
}
- (NSString *) source
{
return [[self uniqueChildWithTag: @"source"] value: 0];
}
- (void) setFn: (NSString *) _value
{
[[self uniqueChildWithTag: @"fn"] setValue: 0 to: _value];
}
- (NSString *) fn
{
return [[self uniqueChildWithTag: @"fn"] value: 0];
}
- (void) setRole: (NSString *) _value
{
[[self uniqueChildWithTag: @"role"] setValue: 0 to: _value];
}
- (NSString *) role
{
return [[self uniqueChildWithTag: @"role"] value: 0];
}
- (void) setTitle: (NSString *) _title
{
[[self uniqueChildWithTag: @"title"] setValue: 0 to: _title];
}
- (NSString *) title
{
return [[self uniqueChildWithTag: @"title"] value: 0];
}
- (void) setBday: (NSString *) _value
{
[[self uniqueChildWithTag: @"bday"] setValue: 0 to: _value];
}
- (NSString *) bday
{
return [[self uniqueChildWithTag: @"bday"] value: 0];
}
- (void) setNote: (NSString *) _value
{
[[self uniqueChildWithTag: @"note"] setValue: 0 to: _value];
}
- (NSString *) note
{
return [[self uniqueChildWithTag: @"note"] value: 0];
}
- (void) setTz: (NSString *) _value
{
[[self uniqueChildWithTag: @"tz"] setValue: 0 to: _value];
}
- (NSString *) tz
{
return [[self uniqueChildWithTag: @"tz"] value: 0];
}
- (void) setNickname: (NSString *) _value
{
[[self uniqueChildWithTag: @"nickname"] setValue: 0 to: _value];
}
- (NSString *) nickname
{
return [[self uniqueChildWithTag: @"nickname"] value: 0];
}
- (void) addTel: (NSString *) phoneNumber
types: (NSArray *) types
{
[self addChildWithTag: @"tel" types: types singleValue: phoneNumber];
}
- (void) addEmail: (NSString *) emailAddress
types: (NSArray *) types
{
[self addChildWithTag: @"email"
types: types
singleValue: emailAddress];
}
- (void) setNWithFamily: (NSString *) family
given: (NSString *) given
additional: (NSString *) additional
prefixes: (NSString *) prefixes
suffixes: (NSString *) suffixes
{
CardElement *n;
n = [self uniqueChildWithTag: @"n"];
if (family)
[n setValue: 0 to: family];
if (given)
[n setValue: 1 to: given];
if (additional)
[n setValue: 2 to: additional];
if (prefixes)
[n setValue: 3 to: prefixes];
if (suffixes)
[n setValue: 4 to: suffixes];
}
- (NSArray *) n
{
NSArray *elements, *n;
elements = [self childrenWithTag: @"n"];
if ([elements count] > 0)
n = [[elements objectAtIndex: 0] values];
else
n = nil;
return n;
}
- (void) setOrg: (NSString *) anOrg
units: (NSArray *) someUnits
{
CardElement *org;
unsigned int count, max;
org = [self uniqueChildWithTag: @"org"];
if (anOrg)
[org setValue: 0 to: anOrg];
if (someUnits)
{
max = [someUnits count];
for (count = 0; count < max; count++)
[org setValue: count + 1 to: [someUnits objectAtIndex: count]];
}
}
- (NSArray *) org
{
NSArray *elements, *org;
elements = [self childrenWithTag: @"org"];
if ([elements count] > 0)
org = [[elements objectAtIndex: 0] values];
else
org = nil;
return org;
}
// - (void) setOrg: (NGVCardOrg *) _v
// {
// ASSIGNCOPY(self->org, _v);
// }
// - (NGVCardOrg *)org {
// return self->org;
// }
// - (void)setNickname: (id) _v
// {
// if (![_v isKindOfClass:[NGVCardStrArrayValue class]] && [_v isNotNull])
// _v = [[[NGVCardStrArrayValue alloc] initWithPropertyList:_v] autorelease];
// ASSIGNCOPY(self->nickname, _v);
// }
// - (NGVCardStrArrayValue *) nickname
// {
// return self->nickname;
// }
// - (void) setCategories: (id) _v
// {
// if (![_v isKindOfClass:[NGVCardStrArrayValue class]] && [_v isNotNull])
// _v = [[[NGVCardStrArrayValue alloc] initWithPropertyList:_v] autorelease];
// ASSIGNCOPY(self->categories, _v);
// }
// - (NGVCardStrArrayValue *) categories
// {
// return self->categories;
// }
// - (void) setTel: (NSArray *) _tel
// {
// ASSIGNCOPY(self->tel, _tel);
// }
// - (NSArray *) tel
// {
// return [self childrenWithTag: @"tel"];
// }
// - (void) setAdr: (NSArray *) _adr
// {
// ASSIGNCOPY(self->adr, _adr);
// }
// - (NSArray *) adr
// {
// return self->adr;
// }
// - (void) setEmail: (NSArray *) _email
// {
// ASSIGNCOPY(self->email, _email);
// }
// - (NSArray *) email
// {
// return [self childrenWithTag: @"email"];
// }
// - (void) setLabel: (NSArray *) _label
// {
// ASSIGNCOPY(self->label, _label);
// }
// - (NSArray *) label
// {
// return [self childrenWithTag: @"email"];
// }
// - (void) setUrl: (NSArray *) _url
// {
// ASSIGNCOPY(self->url, _url);
// }
// - (NSArray *) url
// {
// return self->url;
// }
// - (void) setFreeBusyURL: (NSArray *) _v
// {
// ASSIGNCOPY(self->fburl, _v);
// }
// - (NSArray *) freeBusyURL
// {
// return self->fburl;
// }
// - (void) setCalURI: (NSArray *) _v
// {
// ASSIGNCOPY(self->caluri, _v);
// }
// - (NSArray *) calURI
// {
// return self->caluri;
// }
// - (void) setX: (NSDictionary *) _dict
// {
// ASSIGNCOPY(self->x, _dict);
// }
// - (NSDictionary *) x
// {
// return self->x;
// }
/* convenience */
- (CardElement *) _preferredElementWithTag: (NSString *) aTag
{
NSArray *elements, *prefElements;
CardElement *element;
elements = [self childrenWithTag: aTag];
if (elements && [elements count] > 0)
{
prefElements = [elements cardElementsWithAttribute: @"type"
havingValue: @"pref"];
if (prefElements && [prefElements count] > 0)
element = [prefElements objectAtIndex: 0];
else
element = [elements objectAtIndex: 0];
}
else
element = nil;
return element;
}
- (NSString *) preferredEMail
{
return [[self _preferredElementWithTag: @"email"] value: 0];
}
- (NSString *) preferredTel
{
return [[self _preferredElementWithTag: @"tel"] value: 0];
}
- (CardElement *) preferredAdr
{
return [self _preferredElementWithTag: @"adr"];
}
/* description */
- (void) appendAttributesToDescription: (NSMutableString *) _ms
{
if ([self uid]) [_ms appendFormat:@" uid='%@'", [self uid]];
// if ([[self tel] count] > 0) [_ms appendFormat:@" tel=%@", [self tel];
// if ([[self adr] count])
// [_ms appendFormat:@" adr=%@", [self adr]];
// if ([[self email] count])
// [_ms appendFormat:@" email=%@", [self email]];
// if ([[self label] count])
// [_ms appendFormat:@" label=%@", [self label]];
// if ([[self x] count])
// [_ms appendFormat:@" x=%@", [self x]];
}
- (NSString *) description
{
NSMutableString *str = nil;
str = [NSMutableString stringWithCapacity:64];
[str appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
[self appendAttributesToDescription:str];
[str appendString:@">"];
return str;
}
@end /* NGVCard */

View File

@ -0,0 +1,42 @@
/* NSArray+NGCards.h - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef NSARRAY_NGCARDS_H
#define NSARRAY_NGCARDS_H
#import <Foundation/NSArray.h>
@interface NSArray (NGCardsExtensions)
- (NSString *) valueForCaseInsensitiveString: (NSString *) aString;
- (BOOL) hasCaseInsensitiveString: (NSString *) aString;
- (NSArray *) cardElementsWithTag: (NSString *) aTag;
- (NSArray *) cardElementsWithAttribute: (NSString *) anAttribute
havingValue: (NSString *) aValue;
- (NSArray *) renderedForCards;
@end
#endif /* NSARRAY_NGCARDS_H */

View File

@ -0,0 +1,133 @@
/* NSArray+NGCards.m - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSString.h>
#import "CardElement.h"
#import "NSString+NGCards.h"
#import "NSArray+NGCards.h"
@implementation NSArray (NGCardsExtensions)
- (NSString *) valueForCaseInsensitiveString: (NSString *) aString
{
NSString *currentString, *resultString, *cmpString;
unsigned int count, max;
BOOL found;
found = NO;
cmpString = [aString uppercaseString];
max = [self count];
count = 0;
currentString = nil;
while (!found && count < max)
{
currentString = [self objectAtIndex: count];
if ([[currentString uppercaseString] isEqualToString: cmpString])
found = YES;
else
count++;
}
if (found)
resultString = currentString;
else
resultString = nil;
return resultString;
}
- (BOOL) hasCaseInsensitiveString: (NSString *) aString
{
return ([self valueForCaseInsensitiveString: aString] != nil);
}
- (NSArray *) cardElementsWithTag: (NSString *) aTag
{
NSMutableArray *matchingElements;
NSEnumerator *allElements;
CardElement *currentElement;
NSString *cmpTag, *currentTag;
cmpTag = [aTag uppercaseString];
matchingElements = [NSMutableArray new];
[matchingElements autorelease];
allElements = [self objectEnumerator];
currentElement = [allElements nextObject];
while (currentElement)
{
currentTag = [[currentElement tag] uppercaseString];
if ([currentTag isEqualToString: cmpTag])
[matchingElements addObject: currentElement];
currentElement = [allElements nextObject];
}
return matchingElements;
}
- (NSArray *) cardElementsWithAttribute: (NSString *) anAttribute
havingValue: (NSString *) aValue
{
NSMutableArray *matchingElements;
NSEnumerator *allElements;
CardElement *currentElement;
allElements = [self objectEnumerator];
matchingElements = [NSMutableArray new];
[matchingElements autorelease];
currentElement = [allElements nextObject];
while (currentElement)
{
if ([currentElement hasAttribute: anAttribute
havingValue: aValue])
[matchingElements addObject: currentElement];
currentElement = [allElements nextObject];
}
return matchingElements;
}
- (NSArray *) renderedForCards
{
NSMutableArray *purified;
NSString *string;
NSEnumerator *strings;
purified = [NSMutableArray arrayWithCapacity: [self count]];
strings = [self objectEnumerator];
string = [strings nextObject];
while (string)
{
[purified addObject: [string escapedForCards]];
string = [strings nextObject];
}
return purified;
}
@end

View File

@ -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 <Foundation/NSCalendarDate.h>
@class NSTimeZone;
@interface NSCalendarDate(iCalRepresentation)
+ (id)calendarDateWithICalRepresentation:(NSString *)_iCalRep;
/* represention */
- (NSString *)icalStringWithTimeZone:(NSTimeZone *)_tz;
- (NSString *)icalString;
@end
@interface NSCalendarDate (iCalRecurrenceCalculatorExtensions)
- (unsigned)yearsBetweenDate:(NSCalendarDate *)_date;
- (unsigned)monthsBetweenDate:(NSCalendarDate *)_date;
- (unsigned)daysBetweenDate:(NSCalendarDate *)_date;
@end
#endif /* __NGiCal_NSCalendarDate_ICal_H__ */

View File

@ -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) */

View File

@ -0,0 +1,38 @@
/* NSDate+NGCards.h - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef NSDATE_NGCARDS_H
#define NSDATE_NGCARDS_H
#import <Foundation/NSDate.h>
#import <Foundation/NSCalendarDate.h>
#import "CardElement.h"
@interface NSDate (NGCardsExtensions)
- (NSString *) iCalFormattedDateTimeString;
- (NSString *) iCalFormattedDateString;
@end
#endif /* NSDATE_NGCARDS_H */

View File

@ -0,0 +1,47 @@
/* NSDate+NGCards.m - this file is part of SOGo
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSString.h>
#import "CardElement.h"
#import "NSCalendarDate+NGCards.h"
#import "NSString+NGCards.h"
@implementation NSCalendarDate (NGCardsExtensions)
- (NSString *) iCalFormattedDateTimeString
{
return [NSString stringWithFormat: @"%.4d%.2d%.2dT%.2d%.2d%.2d",
[self yearOfCommonEra], [self monthOfYear],
[self dayOfMonth], [self hourOfDay],
[self minuteOfHour], [self secondOfMinute]];
}
- (NSString *) iCalFormattedDateString
{
return [NSString stringWithFormat: @"%.4d%.2d%.2d",
[self yearOfCommonEra], [self monthOfYear],
[self dayOfMonth]];
}
@end

View File

@ -0,0 +1,34 @@
/* NSDictionary+NGCards.h - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef NSDICTIONARY_NGCARDS_H
#define NSDICTIONARY_NGCARDS_H
#import <Foundation/NSDictionary.h>
@interface NSDictionary (NGCardsExtensions)
- (id) objectForCaseInsensitiveKey: (NSString *) aKey;
@end
#endif /* NSDICTIONARY_NGCARDS_H */

View File

@ -0,0 +1,40 @@
/* NSDictionary+NGCards.m - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import "NSArray+NGCards.h"
#import "NSDictionary+NGCards.h"
@implementation NSDictionary (NGCardsExtension)
- (id) objectForCaseInsensitiveKey: (NSString *) aKey
{
NSString *realKey;
NSArray *keys;
keys = [self allKeys];
realKey = [keys valueForCaseInsensitiveString: aKey];
return ((realKey) ? [self objectForKey: realKey] : nil);
}
@end

View File

@ -0,0 +1,45 @@
/* NSString+NGCards.h - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef NSSTRING_NGCARDS_H
#define NSSTRING_NGCARDS_H
#import <Foundation/NSString.h>
@class NSCalendarDate;
@class NSTimeZone;
@interface NSString (NGCardsExtensions)
- (NSString *) foldedForVersitCards;
- (NSArray *) asCardAttributeValues;
- (NSString *) escapedForCards;
- (NSString *) unescapedFromCard;
- (NSTimeInterval) durationAsTimeInterval;
- (NSCalendarDate *) asCalendarDate;
- (NSArray *) commaSeparatedValues;
@end
#endif /* NSSTRING_NGCARDS_H */

View File

@ -0,0 +1,272 @@
/* NSString+NGCards.m - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSRange.h>
#import <Foundation/NSTimeZone.h>
#import <NGExtensions/NSObject+Logs.h>
#import <ctype.h>
#import "NSString+NGCards.h"
static NSString *commaSeparator = nil;
@implementation NSString (NGCardsExtensions)
- (void) _initCommaSeparator
{
commaSeparator = [NSMutableString stringWithFormat: @"%c", 255];
[commaSeparator retain];
}
- (NSString *) foldedForVersitCards
{
NSString *newString;
NSMutableString *foldedString;
unsigned int length;
NSRange subStringRange;
length = [self length];
if (length < 76)
newString = self;
else
{
foldedString = [NSMutableString new];
[foldedString autorelease];
subStringRange = NSMakeRange (0, 75);
[foldedString appendFormat: @"%@\r\n",
[self substringWithRange: subStringRange]];
subStringRange = NSMakeRange (75, 74);
while ((length - subStringRange.location) > 74)
{
[foldedString appendFormat: @" %@\r\n",
[self substringWithRange: subStringRange]];
subStringRange.location += 74;
}
subStringRange.length = length - subStringRange.location;
[foldedString appendFormat: @" %@",
[self substringWithRange: subStringRange]];
newString = foldedString;
}
return newString;
}
- (NSArray *) asCardAttributeValues
{
NSMutableArray *values;
NSEnumerator *rawValues;
NSString *tmpString, *rawValue, *newString;
values = [NSMutableArray new];
[values autorelease];
if (!commaSeparator)
[self _initCommaSeparator];
tmpString = [self stringByReplacingString: @"\\,"
withString: commaSeparator];
rawValues = [[tmpString componentsSeparatedByString: @","]
objectEnumerator];
rawValue = [rawValues nextObject];
while (rawValue)
{
newString = [rawValue stringByReplacingString: commaSeparator
withString: @","];
[values addObject: [newString stringByTrimmingSpaces]];
rawValue = [rawValues nextObject];
}
return values;
}
- (NSString *) escapedForCards
{
NSString *string;
string = [self stringByReplacingString: @"\\"
withString: @"\\\\"];
string = [string stringByReplacingString: @","
withString: @"\\,"];
// string = [string stringByReplacingString: @":"
// withString: @"\\:"];
string = [string stringByReplacingString: @";"
withString: @"\\;"];
string = [string stringByReplacingString: @"\n"
withString: @"\\n"];
string = [string stringByReplacingString: @"\r"
withString: @"\\r"];
return string;
}
- (NSString *) unescapedFromCard
{
NSString *string;
string = [self stringByReplacingString: @"\\,"
withString: @","];
string = [string stringByReplacingString: @"\\:"
withString: @":"];
string = [string stringByReplacingString: @"\\;"
withString: @";"];
string = [string stringByReplacingString: @"\\n"
withString: @"\n"];
string = [string stringByReplacingString: @"\\r"
withString: @"\r"];
string = [string stringByReplacingString: @"\\\\"
withString: @"\\"];
return string;
}
- (NSTimeInterval) durationAsTimeInterval
{
/*
eg: DURATION:PT1H
P - "period"
P2H30M - "2 hours 30 minutes"
dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
dur-date = dur-day [dur-time]
dur-time = "T" (dur-hour / dur-minute / dur-second)
dur-week = 1*DIGIT "W"
dur-hour = 1*DIGIT "H" [dur-minute]
dur-minute = 1*DIGIT "M" [dur-second]
dur-second = 1*DIGIT "S"
dur-day = 1*DIGIT "D"
*/
unsigned i, len;
NSTimeInterval ti;
BOOL isTime;
int val;
if (![self hasPrefix:@"P"]) {
NSLog(@"Cannot parse iCal duration value: '%@'", self);
return 0.0;
}
ti = 0.0;
val = 0;
for (i = 1, len = [self length], isTime = NO; i < len; i++) {
unichar c;
c = [self characterAtIndex:i];
if (c == 't' || c == 'T') {
isTime = YES;
val = 0;
continue;
}
if (isdigit(c)) {
val = (val * 10) + (c - 48);
continue;
}
switch (c) {
case 'W': /* week */
ti += (val * 7 * 24 * 60 * 60);
break;
case 'D': /* day */
ti += (val * 24 * 60 * 60);
break;
case 'H': /* hour */
ti += (val * 60 * 60);
break;
case 'M': /* min */
ti += (val * 60);
break;
case 'S': /* sec */
ti += val;
break;
default:
[self logWithFormat: @"cannot process duration unit: '%c'", c];
break;
}
val = 0;
}
return ti;
}
- (NSCalendarDate *) asCalendarDate
{
NSRange cursor;
NSCalendarDate *date;
NSTimeZone *utc;
int year, month, day, hour, minute, second;
if ([self length] > 14)
{
cursor = NSMakeRange(0, 4);
year = [[self substringWithRange: cursor] intValue];
cursor.location += cursor.length;
cursor.length = 2;
month = [[self substringWithRange: cursor] intValue];
cursor.location += cursor.length;
day = [[self substringWithRange: cursor] intValue];
cursor.location += cursor.length + 1;
hour = [[self substringWithRange: cursor] intValue];
cursor.location += cursor.length;
minute = [[self substringWithRange: cursor] intValue];
cursor.location += cursor.length;
second = [[self substringWithRange: cursor] intValue];
utc = [NSTimeZone timeZoneWithAbbreviation: @"GMT"];
date = [NSCalendarDate dateWithYear: year month: month
day: day hour: hour minute: minute
second: second
timeZone: utc];
}
else
date = nil;
return date;
}
- (NSArray *) commaSeparatedValues
{
NSEnumerator *rawValues;
NSMutableArray *values;
NSString *currentValue, *newValue;
values = [NSMutableArray new];
[values autorelease];
rawValues = [[self componentsSeparatedByString: @","] objectEnumerator];
currentValue = [rawValues nextObject];
while (currentValue)
{
newValue = [currentValue stringByTrimmingSpaces];
if ([newValue length])
[values addObject: newValue];
currentValue = [rawValues nextObject];
}
return values;
}
@end

View File

@ -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.

View File

@ -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

View File

@ -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 <Foundation/Foundation.h>
#import <EOControl/EOControl.h>
#include <NGExtensions/NGExtensions.h>
#define IS_EQUAL(a, b, sel) \
_iCalSafeCompareObjects(a, b, @selector(sel))
static __inline__ BOOL _iCalSafeCompareObjects(id a, id b, SEL comparator) {
id va = a;
id vb = b;
BOOL (*compm)(id, SEL, id);
if((va == nil && vb != nil) || (va != nil && vb == nil))
return NO;
else if(va == vb)
return YES;
compm = (BOOL (*)( id, SEL, id))[va methodForSelector:comparator];
return compm(va, comparator, vb);
}
#endif /* __ICal_common_H__ */

View File

@ -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__ */

View File

@ -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 */

View File

@ -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__ */

View File

@ -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 */

View File

@ -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__ */

View File

@ -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 <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import "iCalEvent.h"
#import "iCalToDo.h"
#import "iCalJournal.h"
#import "iCalFreeBusy.h"
#import "iCalEntityObject.h"
#import "iCalTimeZone.h"
#import "iCalCalendar.h"
@interface iCalCalendar (Privates)
- (void) addToEvents: (iCalEvent *) _event;
- (void) addToTimezones: (iCalTimeZone *) _tz;
- (void) addToTodos: (iCalToDo *) _todo;
- (void) addToJournals: (iCalJournal *) _obj;
- (void) addToFreeBusys: (iCalFreeBusy *) _obj;
@end
@implementation iCalCalendar
/* class mapping */
- (Class) classForTag: (NSString *) classTag
{
Class tagClass;
tagClass = Nil;
if ([classTag isEqualToString: @"VEVENT"])
tagClass = [iCalEvent class];
else if ([classTag isEqualToString: @"VTODO"])
tagClass = [iCalToDo class];
else if ([classTag isEqualToString: @"VJOURNAL"])
tagClass = [iCalJournal class];
else if ([classTag isEqualToString: @"VFREEBUSY"])
tagClass = [iCalFreeBusy class];
else if ([classTag isEqualToString: @"VTIMEZONE"])
tagClass = [iCalTimeZone class];
else if ([classTag isEqualToString: @"METHOD"]
|| [classTag isEqualToString: @"PRODID"]
|| [classTag isEqualToString: @"VERSION"])
tagClass = [CardElement class];
else
tagClass = [super classForTag: classTag];
return tagClass;
}
/* accessors */
- (void) setCalscale: (NSString *) _calscale
{
[[self uniqueChildWithTag: @"calscale"] setValue: 0 to: _calscale];
}
- (NSString *) calscale
{
return [[self uniqueChildWithTag: @"calscale"] value: 0];
}
- (void) setVersion: (NSString *) _version
{
[[self uniqueChildWithTag: @"version"] setValue: 0 to: _version];
}
- (NSString *) version
{
return [[self uniqueChildWithTag: @"version"] value: 0];
}
- (void) setProdID: (NSString *) _value
{
[[self uniqueChildWithTag: @"prodid"] setValue: 0 to: _value];
}
- (NSString *) prodId
{
return [[self uniqueChildWithTag: @"prodid"] value: 0];
}
- (void) setMethod: (NSString *) _value
{
[[self uniqueChildWithTag: @"method"] setValue: 0 to: _value];
}
- (NSString *) method
{
return [[self uniqueChildWithTag: @"method"] value: 0];
}
- (void) addToEvents: (iCalEvent *) _event
{
[self addChild: _event];
}
- (NSArray *) events
{
return [self childrenWithTag: @"vevent"];
}
- (void) addToTimezones: (iCalTimeZone *) _tz
{
[self addChild: _tz];
}
- (NSArray *) timezones
{
return [self childrenWithTag: @"vtimezone"];
}
- (void) addToTodos: (iCalToDo *) _todo
{
[self addChild: _todo];
}
- (NSArray *) todos
{
return [self childrenWithTag: @"vtodo"];
}
- (void) addToJournals: (iCalJournal *) _todo
{
[self addChild: _todo];
}
- (NSArray *) journals
{
return [self childrenWithTag: @"vjournal"];
}
- (void) addToFreeBusys: (iCalFreeBusy *) _fb
{
[self addChild: _fb];
}
- (NSArray *) freeBusys
{
return [self childrenWithTag: @"vfreebusy"];
}
- (void) addTimeZone: (iCalTimeZone *) iTZ
{
iCalTimeZone *possibleTz;
possibleTz = [self timeZoneWithId: [iTZ tzId]];
if (!possibleTz)
[self addChild: iTZ];
}
- (iCalTimeZone *) timeZoneWithId: (NSString *) tzId
{
NSArray *matchingTimeZones;
iCalTimeZone *timeZone;
matchingTimeZones = [self childrenGroupWithTag: @"vtimezone"
withChild: @"tzid"
havingSimpleValue: tzId];
if ([matchingTimeZones count])
timeZone = [matchingTimeZones objectAtIndex: 0];
else
timeZone = nil;
return timeZone;
}
/* collection */
- (NSArray *) allObjects
{
NSMutableArray *ma;
ma = [NSMutableArray new];
[ma addObjectsFromArray: [self events]];
[ma addObjectsFromArray: [self todos]];
[ma addObjectsFromArray: [self journals]];
[ma addObjectsFromArray: [self freeBusys]];
return ma;
}
/* ical typing */
- (NSString *) entityName
{
return @"vcalendar";
}
@end /* iCalCalendar */

View File

@ -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 <NGExtensions/NGCalendarDateRange.h>
#include "iCalRecurrenceRule.h"
#include "NSCalendarDate+ICal.h"
#include "common.h"
@interface iCalRecurrenceCalculator(PrivateAPI)
- (NSCalendarDate *)lastInstanceStartDate;
@end
@implementation iCalDailyRecurrenceCalculator
- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{
NSMutableArray *ranges;
NSCalendarDate *firStart;
long i, jnFirst, jnStart, jnEnd, startEndCount;
unsigned interval;
firStart = [self->firstRange startDate];
jnFirst = [firStart julianNumber];
jnEnd = [[_r endDate] julianNumber];
if (jnFirst > jnEnd)
return nil;
jnStart = [[_r startDate] julianNumber];
interval = [self->rrule repeatInterval];
/* if rule is bound, check the bounds */
if (![self->rrule isInfinite]) {
NSCalendarDate *until;
long jnRuleLast;
until = [self->rrule untilDate];
if (until) {
if ([until compare:[_r startDate]] == NSOrderedAscending)
return nil;
jnRuleLast = [until julianNumber];
}
else {
jnRuleLast = (interval * [self->rrule repeatCount])
+ jnFirst;
if (jnRuleLast < jnStart)
return nil;
}
/* jnStart < jnRuleLast < jnEnd ? */
if (jnEnd > jnRuleLast)
jnEnd = jnRuleLast;
}
startEndCount = (jnEnd - jnStart) + 1;
ranges = [NSMutableArray arrayWithCapacity:startEndCount];
for (i = 0 ; i < startEndCount; i++) {
long jnCurrent;
jnCurrent = jnStart + i;
if (jnCurrent >= jnFirst) {
long jnTest;
jnTest = jnCurrent - jnFirst;
if ((jnTest % interval) == 0) {
NSCalendarDate *start, *end;
NGCalendarDateRange *r;
start = [NSCalendarDate dateForJulianNumber:jnCurrent];
[start setTimeZone:[firStart timeZone]];
start = [start hour: [firStart hourOfDay]
minute:[firStart minuteOfHour]
second:[firStart secondOfMinute]];
end = [start addTimeInterval:[self->firstRange duration]];
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
endDate:end];
if ([_r containsDateRange:r])
[ranges addObject:r];
}
}
}
return ranges;
}
- (NSCalendarDate *)lastInstanceStartDate {
if ([self->rrule repeatCount] > 0) {
long jnFirst, jnRuleLast;
NSCalendarDate *firStart, *until;
firStart = [self->firstRange startDate];
jnFirst = [firStart julianNumber];
jnRuleLast = ([self->rrule repeatInterval] *
[self->rrule repeatCount]) +
jnFirst;
until = [NSCalendarDate dateForJulianNumber:jnRuleLast];
until = [until hour: [firStart hourOfDay]
minute:[firStart minuteOfHour]
second:[firStart secondOfMinute]];
return until;
}
return [super lastInstanceStartDate];
}
@end /* iCalDailyRecurrenceCalculator */

View File

@ -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 <EOControl/EODataSource.h>
@class NSString, NSURL;
@class EOFetchSpecification;
@interface iCalDataSource : EODataSource
{
EOFetchSpecification *fetchSpecification;
NSURL *url;
NSString *entityName;
}
- (id)initWithURL:(NSURL *)_url entityName:(NSString *)_ename;
- (id)initWithPath:(NSString *)_file entityName:(NSString *)_ename;
- (id)initWithURL:(NSURL *)_url;
- (id)initWithPath:(NSString *)_file;
/* accessors */
- (void)setFetchSpecification:(EOFetchSpecification *)_fspec;
- (EOFetchSpecification *)fetchSpecification;
/* fetching */
- (NSArray *)fetchObjects;
@end
#endif /* __NGiCal_iCalDataSource_H__ */

View File

@ -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 <SaxObjC/SaxObjC.h>
#include "common.h"
@interface NSObject(suppressCapitalizedKeyWarning)
+ (void)suppressCapitalizedKeyWarning;
@end
@implementation iCalDataSource
// THREAD
static id<NSObject,SaxXMLReader> parser = nil;
static SaxObjectDecoder *sax = nil;
- (void)_setupGlobals {
if (parser == nil ) {
SaxXMLReaderFactory *factory =
[SaxXMLReaderFactory standardXMLReaderFactory];
parser = [[factory createXMLReaderForMimeType:@"text/calendar"] retain];
if (parser == nil)
[self logWithFormat:@"ERROR: found no SAX driver for 'text/calendar'!"];
}
if (sax == nil && parser != nil) {
NSBundle *bundle;
NSString *p;
#if COCOA_Foundation_LIBRARY
/* otherwise we get warning on "X-WR-TIMEZONE" etc */
[NSClassFromString(@"NSKeyBinding") suppressCapitalizedKeyWarning];
#endif
bundle = [NSBundle bundleForClass:[self class]];
if ((p = [bundle pathForResource:@"NGiCal" ofType:@"xmap"]))
sax = [[SaxObjectDecoder alloc] initWithMappingAtPath:p];
else
sax = [[SaxObjectDecoder alloc] initWithMappingNamed:@"NGiCal"];
[parser setContentHandler:sax];
[parser setErrorHandler:sax];
}
}
- (id)initWithURL:(NSURL *)_url entityName:(NSString *)_ename {
[self _setupGlobals];
if ((self = [super init])) {
self->url = [_url copy];
self->entityName = [_ename copy];
}
return self;
}
- (id)initWithPath:(NSString *)_path entityName:(NSString *)_ename {
NSURL *lurl;
lurl = [[[NSURL alloc] initFileURLWithPath:_path] autorelease];
return [self initWithURL:lurl entityName:_ename];
}
- (id)initWithURL:(NSURL *)_url {
return [self initWithURL:_url entityName:nil];
}
- (id)initWithPath:(NSString *)_path {
return [self initWithPath:_path entityName:nil];
}
- (id)init {
return [self initWithURL:nil];
}
- (void)dealloc {
[self->fetchSpecification release];
[self->url release];
[self->entityName release];
[super dealloc];
}
/* accessors */
- (void)setFetchSpecification:(EOFetchSpecification *)_fspec {
if ([self->fetchSpecification isEqual:_fspec])
return;
ASSIGNCOPY(self->fetchSpecification, _fspec);
[self postDataSourceChangedNotification];
}
- (EOFetchSpecification *)fetchSpecification {
return self->fetchSpecification;
}
/* fetching */
- (id)_parseCalendar {
id cal;
if (parser == nil) {
[self logWithFormat:@"ERROR: missing iCalendar parser!"];
return nil;
}
if (sax == nil) {
[self logWithFormat:@"ERROR: missing SAX handler!"];
return nil;
}
[parser parseFromSource:self->url];
cal = [sax rootObject];
return cal;
}
- (NSArray *)objectsForEntityNamed:(NSString *)ename inCalendar:(id)_cal {
if ([ename isEqualToString:@"vevent"])
return [_cal events];
if ([ename isEqualToString:@"vtodo"])
return [_cal todos];
if ([ename isEqualToString:@"vjournal"])
return [_cal journals];
if ([ename isEqualToString:@"vfreebusy"])
return [_cal freeBusys];
[self logWithFormat:@"unknown calendar entity '%@'", ename];
return nil;
}
- (NSArray *)objectsFromCalendar:(id)_cal {
NSString *ename;
ename = [self->fetchSpecification entityName];
if ([ename length] == 0)
ename = self->entityName;
if ([ename length] == 0)
return [_cal allObjects];
if ([_cal isKindOfClass:[NSDictionary class]]) {
/*
This happens with Mozilla Calendar which posts one vcalendar
entry (with method 'PUBLISH') per event.
*/
NSMutableArray *ma;
NSArray *calendars;
unsigned i, count;
if (![[(NSDictionary *)_cal objectForKey:@"tag"]
isEqualToString:@"iCalendar"]) {
[self logWithFormat:
@"ERROR: calendar (entity=%@) passed in as a dictionary: %@",
_cal];
}
if ((calendars=[(NSDictionary *)_cal objectForKey:@"subcomponents"])==nil)
return nil;
count = [calendars count];
ma = [NSMutableArray arrayWithCapacity:(count + 1)];
for (i = 0; i < count; i++) {
NSArray *objects;
objects = [self objectsForEntityNamed:ename
inCalendar:[calendars objectAtIndex:i]];
if ([objects count] == 0)
continue;
[ma addObjectsFromArray:objects];
}
return ma;
}
return [self objectsForEntityNamed:ename inCalendar:_cal];
}
- (NSArray *)fetchObjects {
NSAutoreleasePool *pool;
NSArray *result;
id calendar;
pool = [[NSAutoreleasePool alloc] init];
if ((calendar = [self _parseCalendar]) == nil)
return nil;
if (self->fetchSpecification == nil) {
result = [[self objectsFromCalendar:calendar] shallowCopy];
}
else {
NSMutableArray *ma;
NSEnumerator *e;
EOQualifier *q;
NSArray *sort;
NSArray *objects;
iCalObject *object;
/* get objects */
objects = [self objectsFromCalendar:calendar];
/* first filter using qualifier */
ma = [NSMutableArray arrayWithCapacity:[objects count]];
q = [self->fetchSpecification qualifier];
e = [objects objectEnumerator];
while ((object = [e nextObject])) {
if (q) {
if (![(id<EOQualifierEvaluation>)q evaluateWithObject:object])
continue;
}
[ma addObject:object];
}
/* now sort */
if ((sort = [self->fetchSpecification sortOrderings]))
[ma sortUsingKeyOrderArray:sort];
result = [ma shallowCopy];
}
[pool release];
return [result autorelease];
}
@end /* iCalDataSource */

View File

@ -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 <Foundation/NSObject.h>
@class NSString, NSTimeZone;
@interface iCalDateHolder : NSObject
{
NSString *tzid;
NSString *string;
NSString *tag;
}
- (void)setString:(NSString *)_value;
- (NSString *)string;
- (void)setTag:(NSString *)_value;
- (NSString *)tag;
- (void)setTzid:(NSString *)_value;
- (NSString *)tzid;
- (NSTimeZone *)timeZone;
@end
#endif /* __NGiCal_iCalDateHolder_H__ */

View File

@ -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) */

View File

@ -0,0 +1,41 @@
/* iCalDateTime.h - this file is part of SOGo
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef ICALDATETIMEELEMENT_H
#define ICALDATETIMEELEMENT_H
@class NSCalendarDate;
@class iCalTimeZone;
#import "CardElement.h"
@interface iCalDateTime : CardElement
- (void) setTimeZone: (iCalTimeZone *) iTZ;
- (iCalTimeZone *) timeZone;
- (void) setDateTime: (NSCalendarDate *) dateTime;
- (NSCalendarDate *) dateTime;
@end
#endif /* ICALDATETIMEELEMENT_H */

View File

@ -0,0 +1,155 @@
/* iCalDateTime.m - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import "NSCalendarDate+NGCards.h"
#import "NSString+NGCards.h"
#import "iCalCalendar.h"
#import "iCalTimeZone.h"
#import "iCalDateTime.h"
// static NSTimeZone *localTimeZone = nil;
@implementation iCalDateTime
// + (void) initialize
// {
// if (!localTimeZone)
// {
// localTimeZone = [NSTimeZone defaultTimeZone];
// [localTimeZone retain];
// }
// }
// + (void) setLocalTimeZone: (NSTimeZone *) aTimeZone
// {
// [localTimeZone release];
// localTimeZone = aTimeZone;
// [localTimeZone retain];
// }
- (void) setTimeZone: (iCalTimeZone *) iTZ
{
iCalCalendar *calendar;
NSCalendarDate *dateTime;
NSString *newTZId;
dateTime = [self dateTime];
if (iTZ)
{
calendar
= (iCalCalendar *) [self searchParentOfClass: [iCalCalendar class]];
if (calendar)
[calendar addTimeZone: iTZ];
newTZId = [iTZ tzId];
}
[self setValue: 0 ofAttribute: @"tzid" to: newTZId];
[self setDateTime: dateTime];
}
- (iCalTimeZone *) timeZone
{
iCalCalendar *calendar;
NSString *tzId;
iCalTimeZone *timeZone;
tzId = [self value: 0 ofAttribute: @"tzid"];
calendar
= (iCalCalendar *) [self searchParentOfClass: [iCalCalendar class]];
if ([tzId length] && calendar)
timeZone = [calendar timeZoneWithId: tzId];
else
timeZone = nil;
return timeZone;
}
/* TODO: should implement the case where the TZ would be implicitly local
(no TZID and no UTC) */
- (void) setDateTime: (NSCalendarDate *) dateTime
{
NSCalendarDate *tmpTime;
NSTimeZone *utcTZ;
NSString *timeString;
iCalTimeZone *tz;
if (dateTime)
{
tz = [self timeZone];
if (tz)
timeString = [tz dateTimeStringForDate: dateTime];
else
{
utcTZ = [NSTimeZone timeZoneWithName: @"GMT"];
tmpTime = [dateTime copy];
[tmpTime setTimeZone: utcTZ];
timeString = [NSString stringWithFormat: @"%@Z",
[tmpTime iCalFormattedDateTimeString]];
[tmpTime release];
}
}
else
timeString = @"";
[self setValue: 0 to: timeString];
}
- (NSCalendarDate *) dateTime
{
iCalTimeZone *iTZ;
NSString *date;
NSCalendarDate *initialDate, *dateTime;
NSTimeZone *tz;
date = [self value: 0];
iTZ = [self timeZone];
if (iTZ)
dateTime = [iTZ dateForDateTimeString: date];
else
{
initialDate = [date asCalendarDate];
if (initialDate)
{
if ([date hasSuffix: @"Z"] || [date hasSuffix: @"z"])
dateTime = initialDate;
else
{
/* same TODO as above */
tz = [NSTimeZone defaultTimeZone];
dateTime = [initialDate addYear: 0 month: 0 day: 0
hour: 0 minute: 0
second: -[tz secondsFromGMT]];
}
}
else
dateTime = nil;
}
return dateTime;
}
@end

View File

@ -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__ */

View File

@ -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 */

View File

@ -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__ */

View File

@ -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 <NGExtensions/NGCalendarDateRange.h>
#import "NSCalendarDate+NGCards.h"
#import "CardGroup+iCal.h"
#import "NSString+NGCards.h"
#import "iCalEventChanges.h"
#import "iCalDateTime.h"
#import "iCalEvent.h"
@implementation iCalEvent
- (Class) classForTag: (NSString *) classTag
{
Class tagClass;
if ([classTag isEqualToString: @"DURATION"]
|| [classTag isEqualToString: @"TRANSP"])
tagClass = [CardElement class];
else if ([classTag isEqualToString: @"DTEND"])
tagClass = [iCalDateTime class];
else
tagClass = [super classForTag: classTag];
return tagClass;
}
/* accessors */
- (void) setEndDate: (NSCalendarDate *)_date
{
[self setDate: _date forDateTimeValue: @"dtend"];
}
- (NSCalendarDate *) endDate
{
return [self dateForDateTimeValue: @"dtend"];
}
- (BOOL) hasEndDate
{
return ([[self childrenWithTag: @"dtend"] count] > 0);
}
- (void) setDuration: (NSString *) _value
{
[[self uniqueChildWithTag: @"duration"] setValue: 0
to: _value];
}
- (NSString *) duration
{
return [[self uniqueChildWithTag: @"duration"] value: 0];
}
- (BOOL) hasDuration
{
return ([[self childrenWithTag: @"duration"] count] > 0);
}
- (NSTimeInterval) durationAsTimeInterval
{
/*
eg: DURATION:PT1H
P - "period"
P2H30M - "2 hours 30 minutes"
dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
dur-date = dur-day [dur-time]
dur-time = "T" (dur-hour / dur-minute / dur-second)
dur-week = 1*DIGIT "W"
dur-hour = 1*DIGIT "H" [dur-minute]
dur-minute = 1*DIGIT "M" [dur-second]
dur-second = 1*DIGIT "S"
dur-day = 1*DIGIT "D"
*/
NSTimeInterval interval;
if ([self hasDuration])
interval = [[self duration] durationAsTimeInterval];
else if ([self hasEndDate] && [self hasStartDate])
/* calculate duration using enddate */
interval = [[self endDate] timeIntervalSinceDate: [self startDate]];
else
interval = 0.0;
return interval;
}
- (void) setTransparency: (NSString *) _transparency
{
[[self uniqueChildWithTag: @"transp"] setValue: 0
to: _transparency];
}
- (NSString *) transparency
{
return [[self uniqueChildWithTag: @"transp"] value: 0];
}
/* convenience */
- (BOOL) isOpaque
{
NSString *s;
s = [[self transparency] uppercaseString];
return (![s isEqualToString: @"TRANSPARENT"]);
}
/* TODO: FIX THIS!
The problem is, that startDate/endDate are inappropriately modelled here.
We'd need to have a special iCalDate in order to fix all the mess.
For the time being, we chose allday to mean 00:00 - 23:59 in startDate's
timezone.
*/
- (BOOL) isAllDay
{
NSCalendarDate *ed, *startDate;
BOOL allDay;
if ([self hasEndDate])
{
ed = [self endDate];
startDate = [self startDate];
[ed setTimeZone: [startDate timeZone]];
allDay = (([startDate hourOfDay] == 0)
&& ([startDate minuteOfHour] == 0)
&& ([ed hourOfDay] == 23)
&& ([ed minuteOfHour] == 59));
}
else
allDay = NO;
return allDay;
}
- (BOOL) isWithinCalendarDateRange: (NGCalendarDateRange *) _range
{
NGCalendarDateRange *r;
NSCalendarDate *startDate, *endDate;
NGCalendarDateRange *fir;
startDate = [self startDate];
endDate = [self endDate];
if (![self isRecurrent])
{
if ([self hasStartDate] && [self hasEndDate])
{
r = [NGCalendarDateRange calendarDateRangeWithStartDate: startDate
endDate: endDate];
return [_range containsDateRange: r];
}
else
return [_range containsDate: startDate];
}
else
{
fir = [NGCalendarDateRange calendarDateRangeWithStartDate:startDate
endDate: endDate];
return [self isWithinCalendarDateRange: _range
firstInstanceCalendarDateRange: fir];
}
return NO;
}
- (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *)_r
{
NGCalendarDateRange *fir;
if (![self isRecurrent])
return nil;
fir = [NGCalendarDateRange calendarDateRangeWithStartDate: [self startDate]
endDate: [self endDate]];
return [self recurrenceRangesWithinCalendarDateRange:_r
firstInstanceCalendarDateRange:fir];
}
- (NSCalendarDate *) lastPossibleRecurrenceStartDate
{
NGCalendarDateRange *fir;
if (![self isRecurrent])
return nil;
fir = [NGCalendarDateRange calendarDateRangeWithStartDate: [self startDate]
endDate: [self endDate]];
return [self lastPossibleRecurrenceStartDateUsingFirstInstanceCalendarDateRange: fir];
}
/* ical typing */
- (NSString *) entityName
{
return @"vevent";
}
/* descriptions */
// - (NSString *) description {
// NSMutableString *ms;
// ms = [NSMutableString stringWithCapacity:128];
// [ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
// if (uid) [ms appendFormat:@" uid=%@", uid];
// if (startDate) [ms appendFormat:@" from=%@", startDate];
// if (endDate) [ms appendFormat:@" to=%@", endDate];
// if (summary) [ms appendFormat:@" summary=%@", summary];
// if (organizer)
// [ms appendFormat:@" organizer=%@", organizer];
// if (attendees)
// [ms appendFormat:@" attendees=%@", attendees];
// if ([self hasAlarms])
// [ms appendFormat:@" alarms=%@", alarms];
// [ms appendString:@">"];
// return ms;
// }
/* changes */
- (iCalEventChanges *) getChangesRelativeToEvent: (iCalEvent *) _event
{
return [iCalEventChanges changesFromEvent: _event
toEvent: self];
}
@end /* iCalEvent */

View File

@ -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 <Foundation/NSObject.h>
@class iCalEvent, NSArray, NSMutableArray;
@interface iCalEventChanges : NSObject
{
NSMutableArray *insertedAttendees;
NSMutableArray *deletedAttendees;
NSMutableArray *updatedAttendees;
NSMutableArray *insertedAlarms;
NSMutableArray *deletedAlarms;
NSMutableArray *updatedAlarms;
NSMutableArray *updatedProperties;
}
+ (id)changesFromEvent:(iCalEvent *)_old toEvent:(iCalEvent *)_to;
- (id)initWithFromEvent:(iCalEvent *)_from toEvent:(iCalEvent *)_to;
- (BOOL)hasChanges;
- (BOOL)hasAttendeeChanges;
- (NSArray *)insertedAttendees;
- (NSArray *)deletedAttendees;
- (NSArray *)updatedAttendees;
- (BOOL)hasAlarmChanges;
- (NSArray *)insertedAlarms;
- (NSArray *)deletedAlarms;
- (NSArray *)updatedAlarms;
- (BOOL)hasPropertyChanges;
- (NSArray *)updatedProperties;
@end
#endif /* __NGiCal_iCalEventChanges_H_ */

View File

@ -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

View File

@ -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__ */

View File

@ -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 <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <Foundation/NSTimeZone.h>
#import "CardGroup+iCal.h"
#import "iCalDateTime.h"
#import "NSCalendarDate+NGCards.h"
#import "iCalFreeBusy.h"
@implementation iCalFreeBusy
- (Class) classForTag: (NSString *) classTag
{
Class tagClass;
if ([classTag isEqualToString: @"DTEND"])
tagClass = [iCalDateTime class];
else if ([classTag isEqualToString: @"FREEBUSY"])
tagClass = [CardElement class];
else
tagClass = [super classForTag: classTag];
return tagClass;
}
/* accessors */
- (void) setEndDate: (NSCalendarDate *)_date
{
[self setDate: _date forDateTimeValue: @"dtend"];
}
- (NSCalendarDate *) endDate
{
return [self dateForDateTimeValue: @"dtend"];
}
- (BOOL) hasEndDate
{
return ([[self childrenWithTag: @"dtend"] count] > 0);
}
- (NSString *) _freeBusyTypeString: (iCalFreeBusyType) type
{
NSString *typeString;
switch (type)
{
case iCalFBBusy:
typeString = @"BUSY";
break;
case iCalFBFree:
typeString = @"FREE";
break;
case iCalFBBusyUnavailable:
typeString = @"BUSY-UNAVAILABLE";
break;
default:
typeString = @"BUSY-TENTATIVE";
}
return typeString;
}
- (void) addFreeBusyFrom: (NSCalendarDate *) start
to: (NSCalendarDate *) end
type: (iCalFreeBusyType) type
{
CardElement *freeBusyElement;
NSString *value;
NSCalendarDate *utcStart, *utcEnd;
NSTimeZone *uTZ;
uTZ = [NSTimeZone timeZoneWithAbbreviation: @"GMT"];
utcStart = [start copy];
utcEnd = [end copy];
[utcStart setTimeZone: uTZ];
[utcEnd setTimeZone: uTZ];
value = [NSString stringWithFormat: @"%@Z/%@Z",
[utcStart iCalFormattedDateTimeString],
[utcEnd iCalFormattedDateTimeString]];
freeBusyElement = [CardElement simpleElementWithTag: @"freebusy"
value: value];
[freeBusyElement addAttribute: @"fbtype"
value: [self _freeBusyTypeString: type]];
[self addChild: freeBusyElement];
[utcStart release];
[utcEnd release];
}
/* ical typing */
- (NSString *) entityName
{
return @"vfreebusy";
}
@end /* iCalFreeBusy */

View File

@ -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__ */

View File

@ -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 */

View File

@ -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 <NGExtensions/NGCalendarDateRange.h>
#include "iCalRecurrenceRule.h"
#include "NSCalendarDate+ICal.h"
#include "common.h"
#include <string.h>
@interface iCalRecurrenceCalculator(PrivateAPI)
- (NSCalendarDate *)lastInstanceStartDate;
@end
// #define HEAVY_DEBUG 1
@implementation iCalMonthlyRecurrenceCalculator
typedef BOOL NGMonthSet[12];
typedef BOOL NGMonthDaySet[32]; // 0 is unused
static void NGMonthDaySet_clear(NGMonthDaySet *daySet) {
register unsigned i;
for (i = 1; i <= 31; i++)
(*daySet)[i] = NO;
}
static void NGMonthDaySet_copyOrUnion(NGMonthDaySet *base, NGMonthDaySet *new,
BOOL doCopy)
{
register unsigned i;
if (doCopy)
memcpy(base, new, sizeof(NGMonthDaySet));
else {
for (i = 1; i <= 31; i++) {
if (!(*new)[i])
(*base)[i] = NO;
}
}
}
static BOOL NGMonthDaySet_fillWithByMonthDay(NGMonthDaySet *daySet,
NSArray *byMonthDay)
{
/* list of days in the month */
unsigned i, count;
BOOL ok;
NGMonthDaySet_clear(daySet);
for (i = 0, count = [byMonthDay count], ok = YES; i < count; i++) {
int dayInMonth; /* -31..-1 and 1..31 */
if ((dayInMonth = [[byMonthDay objectAtIndex:i] intValue]) == 0) {
ok = NO;
continue; /* invalid value */
}
if (dayInMonth > 31) {
ok = NO;
continue; /* error, value to large */
}
if (dayInMonth < -31) {
ok = NO;
continue; /* error, value to large */
}
/* adjust negative days */
if (dayInMonth < 0) {
/* eg: -1 == last day in month, 30 days => 30 */
dayInMonth = 32 - dayInMonth /* because we count from 1 */;
}
(*daySet)[dayInMonth] = YES;
}
return ok;
}
static inline unsigned iCalDoWForNSDoW(int dow) {
switch (dow) {
case 0: return iCalWeekDaySunday;
case 1: return iCalWeekDayMonday;
case 2: return iCalWeekDayTuesday;
case 3: return iCalWeekDayWednesday;
case 4: return iCalWeekDayThursday;
case 5: return iCalWeekDayFriday;
case 6: return iCalWeekDaySaturday;
case 7: return iCalWeekDaySunday;
default: return 0;
}
}
#if HEAVY_DEBUG
static NSString *dowEN[8] = {
@"SU", @"MO", @"TU", @"WE", @"TH", @"FR", @"SA", @"SU-"
};
#endif
static void NGMonthDaySet_fillWithByDayX(NGMonthDaySet *daySet,
unsigned dayMask,
unsigned firstDoWInMonth,
unsigned numberOfDaysInMonth,
int occurrence1)
{
// TODO: this is called 'X' because the API doesn't allow for full iCalendar
// functionality. The daymask must be a list of occurence+dow
register unsigned dayInMonth;
register int dow; /* current day of the week */
int occurrences[7] = { 0, 0, 0, 0, 0, 0, 0 } ;
NGMonthDaySet_clear(daySet);
if (occurrence1 >= 0) {
for (dayInMonth = 1, dow = firstDoWInMonth; dayInMonth<=31; dayInMonth++) {
// TODO: complete me
if (dayMask & iCalDoWForNSDoW(dow)) {
if (occurrence1 == 0)
(*daySet)[dayInMonth] = YES;
else { /* occurrence1 > 0 */
occurrences[dow] = occurrences[dow] + 1;
if (occurrences[dow] == occurrence1)
(*daySet)[dayInMonth] = YES;
}
}
dow = (dow == 6 /* Sat */) ? 0 /* Sun */ : (dow + 1);
}
}
else {
int lastDoWInMonthSet;
/* get the last dow in the set (not necessarily the month!) */
for (dayInMonth = 1, dow = firstDoWInMonth;
dayInMonth < numberOfDaysInMonth;dayInMonth++)
dow = (dow == 6 /* Sat */) ? 0 /* Sun */ : (dow + 1);
lastDoWInMonthSet = dow;
#if HEAVY_DEBUG
NSLog(@"LAST DOW IN SET: %i / %@",
lastDoWInMonthSet, dowEN[lastDoWInMonthSet]);
#endif
/* start at the end of the set */
for (dayInMonth = numberOfDaysInMonth, dow = lastDoWInMonthSet;
dayInMonth >= 1; dayInMonth--) {
// TODO: complete me
#if HEAVY_DEBUG
NSLog(@" CHECK day-of-month %02i, "
@" dow=%i/%@ (first=%i/%@, last=%i/%@)",
dayInMonth,
dow, dowEN[dow],
firstDoWInMonth, dowEN[firstDoWInMonth],
lastDoWInMonthSet, dowEN[lastDoWInMonthSet]
);
#endif
if (dayMask & iCalDoWForNSDoW(dow)) {
occurrences[dow] = occurrences[dow] + 1;
#if HEAVY_DEBUG
NSLog(@" MATCH %i/%@ count: %i occurences=%i",
dow, dowEN[dow], occurrences[dow], occurrence1);
#endif
if (occurrences[dow] == -occurrence1) {
#if HEAVY_DEBUG
NSLog(@" COUNT MATCH");
#endif
(*daySet)[dayInMonth] = YES;
}
}
dow = (dow == 0 /* Sun */) ? 6 /* Sat */ : (dow - 1);
}
}
}
- (BOOL)_addInstanceWithStartDate:(NSCalendarDate *)_startDate
limitDate:(NSCalendarDate *)_until
limitRange:(NGCalendarDateRange *)_r
toArray:(NSMutableArray *)_ranges
{
NGCalendarDateRange *r;
NSCalendarDate *end;
/* check whether we are still in the limits */
// TODO: I think we should check in here whether we succeeded the
// repeatCount. Currently we precalculate that info in the
// -lastInstanceStartDate method.
if (_until != nil) {
/* Note: the 'until' in the rrule is inclusive as per spec */
if ([_until compare:_startDate] == NSOrderedAscending)
/* start after until */
return NO; /* Note: we assume that the algorithm is sequential */
}
/* create end date */
end = [_startDate addTimeInterval:[self->firstRange duration]];
[end setTimeZone:[_startDate timeZone]];
/* create range and check whether its in the requested range */
r = [[NGCalendarDateRange alloc] initWithStartDate:_startDate endDate:end];
if ([_r containsDateRange:r])
[_ranges addObject:r];
[r release]; r = nil;
return YES;
}
- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{
/* main entry */
// TODO: check whether this is OK for multiday-events!
NSMutableArray *ranges;
NSTimeZone *timeZone;
NSCalendarDate *eventStartDate, *rStart, *rEnd, *until;
int eventDayOfMonth;
unsigned monthIdxInRange, numberOfMonthsInRange, interval;
int diff;
NGMonthSet byMonthList = { // TODO: fill from rrule, this is the default
YES, YES, YES, YES, YES, YES,
YES, YES, YES, YES, YES, YES
};
NSArray *byMonthDay = nil; // array of ints (-31..-1 and 1..31)
NGMonthDaySet byMonthDaySet;
eventStartDate = [self->firstRange startDate];
eventDayOfMonth = [eventStartDate dayOfMonth];
timeZone = [eventStartDate timeZone];
rStart = [_r startDate];
rEnd = [_r endDate];
interval = [self->rrule repeatInterval];
until = [self lastInstanceStartDate]; // TODO: maybe replace
byMonthDay = [self->rrule byMonthDay];
/* check whether the range to be processed is beyond the 'until' date */
if (until != nil) {
if ([until compare:rStart] == NSOrderedAscending) /* until before start */
return nil;
if ([until compare:rEnd] == NSOrderedDescending) /* end before until */
rEnd = until; // TODO: why is that? end is _before_ until?
}
/* precalculate month days (same for all instances) */
if (byMonthDay != nil)
NGMonthDaySet_fillWithByMonthDay(&byMonthDaySet, byMonthDay);
// TODO: I think the 'diff' is to skip recurrence which are before the
// requested range. Not sure whether this is actually possible, eg
// the repeatCount must be processed from the start.
diff = [eventStartDate monthsBetweenDate:rStart];
if ((diff != 0) && [rStart compare:eventStartDate] == NSOrderedAscending)
diff = -diff;
numberOfMonthsInRange = [rStart monthsBetweenDate:rEnd] + 1;
ranges = [NSMutableArray arrayWithCapacity:numberOfMonthsInRange];
/*
Note: we do not add 'eventStartDate', this is intentional, the event date
itself is _not_ necessarily part of the sequence, eg with monthly
byday recurrences.
*/
for (monthIdxInRange = 0; monthIdxInRange < numberOfMonthsInRange;
monthIdxInRange++) {
NSCalendarDate *cursor;
unsigned numDaysInMonth;
int monthIdxInRecurrence, dom;
NGMonthDaySet monthDays;
BOOL didByFill, doCont;
monthIdxInRecurrence = diff + monthIdxInRange;
if (monthIdxInRecurrence < 0)
continue;
/* first check whether we are in the interval */
if ((monthIdxInRecurrence % interval) != 0)
continue;
/*
Then the sequence is:
- check whether the month is in the BYMONTH list
*/
cursor = [eventStartDate dateByAddingYears:0
months:(diff + monthIdxInRange)
days:0];
[cursor setTimeZone:timeZone];
numDaysInMonth = [cursor numberOfDaysInMonth];
/* check whether we match the bymonth specification */
if (!byMonthList[[cursor monthOfYear] - 1])
continue;
/* check 'day level' byXYZ rules */
didByFill = NO;
if (byMonthDay != nil) { /* list of days in the month */
NGMonthDaySet_copyOrUnion(&monthDays, &byMonthDaySet, !didByFill);
didByFill = YES;
}
if ([self->rrule byDayMask] != 0) { // TODO: replace the mask with an array
NGMonthDaySet ruleset;
unsigned firstDoWInMonth;
firstDoWInMonth = [[cursor firstDayOfMonth] dayOfWeek];
NGMonthDaySet_fillWithByDayX(&ruleset,
[self->rrule byDayMask],
firstDoWInMonth,
[cursor numberOfDaysInMonth],
[self->rrule byDayOccurence1]);
NGMonthDaySet_copyOrUnion(&monthDays, &ruleset, !didByFill);
didByFill = YES;
}
if (!didByFill) {
/* no rules applied, take the dayOfMonth of the startDate */
NGMonthDaySet_clear(&monthDays);
monthDays[eventDayOfMonth] = YES;
}
// TODO: add processing of byhour/byminute/bysecond etc
for (dom = 1, doCont = YES; dom <= numDaysInMonth && doCont; dom++) {
NSCalendarDate *start;
if (!monthDays[dom])
continue;
if (eventDayOfMonth == dom)
start = cursor;
else {
start = [cursor dateByAddingYears:0 months:0
days:(dom - eventDayOfMonth)];
}
doCont = [self _addInstanceWithStartDate:start
limitDate:until
limitRange:_r
toArray:ranges];
}
if (!doCont) break; /* reached some limit */
}
return ranges;
}
- (NSCalendarDate *)lastInstanceStartDate {
if ([self->rrule repeatCount] > 0) {
NSCalendarDate *until;
unsigned months, interval;
interval = [self->rrule repeatInterval];
months = [self->rrule repeatCount] - 1 /* the first counts as one! */;
if (interval > 0)
months *= interval;
until = [[self->firstRange startDate] dateByAddingYears:0
months:months
days:0];
return until;
}
return [super lastInstanceStartDate];
}
@end /* iCalMonthlyRecurrenceCalculator */

View File

@ -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 <Foundation/NSObject.h>
#import <Foundation/NSDate.h>
/*
iCalObject
A common base class for all iCal objects. Does some patches on key-value
coding.
*/
@class NSTimeZone;
@interface iCalObject : NSObject <NSCopying>
{
}
// what shall we take, if no timeZone is specified in dateValues
+ (void)setICalDefaultTimeZone:(NSTimeZone *)_timeZone;
+ (NSTimeZone *)iCalDefaultTimeZone;
@end
#endif /* __NGiCal_iCalObject_H__ */

View File

@ -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 */

View File

@ -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__ */

View File

@ -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 */

View File

@ -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 <Foundation/NSObject.h>
/*
iCalRecurrenceCalculator
Provides an API for performing common calculations performed in conjunction
with iCalRecurrenceRule objects.
TODO: rather move this functionality to iCalRecurrenceRule?
*/
@class NSArray;
@class iCalRecurrenceRule, NGCalendarDateRange;
@interface iCalRecurrenceCalculator : NSObject
{
NGCalendarDateRange *firstRange;
iCalRecurrenceRule *rrule;
}
+ (NSArray *)
recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
firstInstanceCalendarDateRange: (NGCalendarDateRange *) _fir
recurrenceRules: (NSArray *) _rRules
exceptionRules: (NSArray *) _exRules
exceptionDates: (NSArray *) _exDates;
+ (id) recurrenceCalculatorForRecurrenceRule: (iCalRecurrenceRule *) _rrule
withFirstInstanceCalendarDateRange: (NGCalendarDateRange *) _range;
- (id) initWithRecurrenceRule: (iCalRecurrenceRule *) _rrule
firstInstanceCalendarDateRange: (NGCalendarDateRange *) _range;
- (NSArray *)
recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *)_r;
- (BOOL) doesRecurrWithinCalendarDateRange: (NGCalendarDateRange *) _range;
- (NGCalendarDateRange *) firstInstanceCalendarDateRange;
- (NGCalendarDateRange *) lastInstanceCalendarDateRange; /* might be nil */
@end
#endif /* __NGiCal_iCalRecurrenceCalculator_H_ */

View File

@ -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 <NGExtensions/NGCalendarDateRange.h>
#include "iCalRecurrenceRule.h"
#include "NSCalendarDate+ICal.h"
#include "common.h"
/* class cluster */
/* Private */
@interface iCalRecurrenceCalculator (PrivateAPI)
- (NSCalendarDate *)lastInstanceStartDate;
- (unsigned)offsetFromSundayForJulianNumber:(long)_jn;
- (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay;
- (unsigned)offsetFromSundayForCurrentWeekStart;
- (iCalWeekDay)weekDayForJulianNumber:(long)_jn;
@end
@implementation iCalRecurrenceCalculator
static Class NSCalendarDateClass = Nil;
static Class iCalRecurrenceRuleClass = Nil;
static Class dailyCalcClass = Nil;
static Class weeklyCalcClass = Nil;
static Class monthlyCalcClass = Nil;
static Class yearlyCalcClass = Nil;
+ (void)initialize {
static BOOL didInit = NO;
if (didInit) return;
didInit = YES;
NSCalendarDateClass = [NSCalendarDate class];
iCalRecurrenceRuleClass = [iCalRecurrenceRule class];
dailyCalcClass = NSClassFromString(@"iCalDailyRecurrenceCalculator");
weeklyCalcClass = NSClassFromString(@"iCalWeeklyRecurrenceCalculator");
monthlyCalcClass = NSClassFromString(@"iCalMonthlyRecurrenceCalculator");
yearlyCalcClass = NSClassFromString(@"iCalYearlyRecurrenceCalculator");
}
/* factory */
+ (id)recurrenceCalculatorForRecurrenceRule:(iCalRecurrenceRule *)_rrule
withFirstInstanceCalendarDateRange:(NGCalendarDateRange *)_range
{
return [[[self alloc] initWithRecurrenceRule:_rrule
firstInstanceCalendarDateRange:_range] autorelease];
}
/* complex calculation convenience */
+ (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r
firstInstanceCalendarDateRange:(NGCalendarDateRange *)_fir
recurrenceRules:(NSArray *)_rRules
exceptionRules:(NSArray *)_exRules
exceptionDates:(NSArray *)_exDates
{
id rule;
iCalRecurrenceCalculator *calc;
NSMutableArray *ranges;
NSMutableArray *exDates;
unsigned i, count, rCount;
ranges = [NSMutableArray arrayWithCapacity:64];
for (i = 0, count = [_rRules count]; i < count; i++) {
NSArray *rs;
rule = [_rRules objectAtIndex:i];
if (![rule isKindOfClass:iCalRecurrenceRuleClass])
rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:rule];
calc = [self recurrenceCalculatorForRecurrenceRule:rule
withFirstInstanceCalendarDateRange:_fir];
rs = [calc recurrenceRangesWithinCalendarDateRange:_r];
[ranges addObjectsFromArray:rs];
}
if ([ranges count] == 0)
return nil;
/* test if any exceptions do match */
for (i = 0, count = [_exRules count]; i < count; i++) {
NSArray *rs;
rule = [_exRules objectAtIndex:i];
if (![rule isKindOfClass:iCalRecurrenceRuleClass])
rule = [iCalRecurrenceRule recurrenceRuleWithICalRepresentation:rule];
calc = [self recurrenceCalculatorForRecurrenceRule:rule
withFirstInstanceCalendarDateRange:_fir];
rs = [calc recurrenceRangesWithinCalendarDateRange:_r];
[ranges removeObjectsInArray:rs];
}
if (![ranges isNotEmpty])
return nil;
/* exception dates */
if ((count = [_exDates count]) == 0)
return ranges;
/* sort out exDates not within range */
exDates = [NSMutableArray arrayWithCapacity:count];
for (i = 0; i < count; i++) {
id exDate;
exDate = [_exDates objectAtIndex:i];
if (![exDate isKindOfClass:NSCalendarDateClass])
exDate = [NSCalendarDate calendarDateWithICalRepresentation:exDate];
if ([_r containsDate:exDate])
[exDates addObject:exDate];
}
/* remove matching exDates from ranges */
if ((count = [exDates count]) == 0)
return ranges;
for (i = 0, rCount = [ranges count]; i < count; i++) {
NSCalendarDate *exDate;
NGCalendarDateRange *r;
unsigned k;
exDate = [exDates objectAtIndex:i];
for (k = 0; k < rCount; k++) {
unsigned rIdx;
rIdx = (rCount - k) - 1;
r = [ranges objectAtIndex:rIdx];
if ([r containsDate:exDate]) {
[ranges removeObjectAtIndex:rIdx];
rCount--;
break; /* this is safe because we know that ranges don't overlap */
}
}
}
return ranges;
}
/* init */
- (id)initWithRecurrenceRule:(iCalRecurrenceRule *)_rrule
firstInstanceCalendarDateRange:(NGCalendarDateRange *)_range
{
iCalRecurrenceFrequency freq;
Class calcClass = Nil;
freq = [_rrule frequency];
if (freq == iCalRecurrenceFrequenceDaily)
calcClass = dailyCalcClass;
else if (freq == iCalRecurrenceFrequenceWeekly)
calcClass = weeklyCalcClass;
else if (freq == iCalRecurrenceFrequenceMonthly)
calcClass = monthlyCalcClass;
else if (freq == iCalRecurrenceFrequenceYearly)
calcClass = yearlyCalcClass;
else {
[self errorWithFormat:@"unsupported rrule frequency: %@", _rrule];
calcClass = Nil;
[self release];
return nil;
}
[self autorelease]; // TODO: why autorelease?
if (calcClass == Nil)
return nil;
if ((self = [[calcClass alloc] init]) != nil) {
self->rrule = [_rrule retain];
self->firstRange = [_range retain];
}
return self;
}
- (void)dealloc {
[self->firstRange release];
[self->rrule release];
[super dealloc];
}
/* helpers */
- (unsigned)offsetFromSundayForJulianNumber:(long)_jn {
return (unsigned)((int)(_jn + 1.5)) % 7;
}
- (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay {
unsigned offset;
switch (_weekDay) {
case iCalWeekDaySunday: offset = 0; break;
case iCalWeekDayMonday: offset = 1; break;
case iCalWeekDayTuesday: offset = 2; break;
case iCalWeekDayWednesday: offset = 3; break;
case iCalWeekDayThursday: offset = 4; break;
case iCalWeekDayFriday: offset = 5; break;
case iCalWeekDaySaturday: offset = 6; break;
default: offset = 0; break;
}
return offset;
}
- (unsigned)offsetFromSundayForCurrentWeekStart {
return [self offsetFromSundayForWeekDay:[self->rrule weekStart]];
}
- (iCalWeekDay)weekDayForJulianNumber:(long)_jn {
unsigned day;
iCalWeekDay weekDay;
day = [self offsetFromSundayForJulianNumber:_jn];
switch (day) {
case 0: weekDay = iCalWeekDaySunday; break;
case 1: weekDay = iCalWeekDayMonday; break;
case 2: weekDay = iCalWeekDayTuesday; break;
case 3: weekDay = iCalWeekDayWednesday; break;
case 4: weekDay = iCalWeekDayThursday; break;
case 5: weekDay = iCalWeekDayFriday; break;
case 6: weekDay = iCalWeekDaySaturday; break;
default:
[self errorWithFormat:@"got unexpected weekday: %d", day];
weekDay = iCalWeekDaySunday;
break; /* keep compiler happy */
}
return weekDay;
}
/* calculation */
- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{
return nil; /* subclass responsibility */
}
- (BOOL)doesRecurrWithinCalendarDateRange:(NGCalendarDateRange *)_range {
NSArray *ranges;
ranges = [self recurrenceRangesWithinCalendarDateRange:_range];
return (ranges == nil || [ranges count] == 0) ? NO : YES;
}
- (NGCalendarDateRange *)firstInstanceCalendarDateRange {
return self->firstRange;
}
- (NGCalendarDateRange *)lastInstanceCalendarDateRange {
NSCalendarDate *start, *end;
if ((start = [self lastInstanceStartDate]) == nil)
return nil;
end = [start addTimeInterval:[self->firstRange duration]];
return [NGCalendarDateRange calendarDateRangeWithStartDate:start
endDate:end];
}
- (NSCalendarDate *)lastInstanceStartDate {
NSCalendarDate *until;
/*
NOTE: this is horribly inaccurate and doesn't even consider the use
of repeatCount. It MUST be implemented by subclasses properly!
However, it does the trick for SOGo 1.0 - that's why it's left here.
*/
if ((until = [self->rrule untilDate]) != nil)
return until;
return nil;
}
@end /* iCalRecurrenceCalculator */

View File

@ -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_ */

View File

@ -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 <Foundation/NSException.h>
#import <NGExtensions/NSString+Ext.h>
#import <NGExtensions/NSObject+Logs.h>
#import <ctype.h>
#import "NSCalendarDate+NGCards.h"
#import "NSString+NGCards.h"
#import "NSCalendarDate+ICal.h"
#import "iCalRecurrenceRule.h"
/*
freq = rrFreq;
until = rrUntil;
count = rrCount;
interval = rrInterval;
bysecond = rrBySecondList;
byminute = rrByMinuteList;
byhour = rrByHourList;
byday = rrByDayList;
bymonthday = rrByMonthDayList;
byyearday = rrByYearDayList;
byweekno = rrByWeekNumberList;
bymonth = rrByMonthList;
bysetpos = rrBySetPosList;
wkst = rrWeekStart;
*/
// TODO: private API in the header file?!
@interface iCalRecurrenceRule (PrivateAPI)
- (iCalWeekDay) weekDayFromICalRepresentation: (NSString *) _day;
- (NSString *) iCalRepresentationForWeekDay: (iCalWeekDay) _waeekDay;
- (NSString *) freq;
- (NSString *) wkst;
- (NSString *) byDayList;
// - (void)_parseRuleString:(NSString *)_rrule;
/* currently used by parser, should be removed (replace with an -init..) */
- (void)setByday:(NSString *)_byDayList;
@end
@implementation iCalRecurrenceRule
+ (id) recurrenceRuleWithICalRepresentation: (NSString *) _iCalRep
{
return [self simpleElementWithTag: @"rrule" value: _iCalRep];
}
- (id) init
{
if ((self = [super init]) != nil)
{
[self setTag: @"rrule"];
}
return self;
}
- (id) initWithString: (NSString *) _str
{
if ((self = [self init]))
{
[self setRrule: _str];
}
return self;
}
- (void) setRrule: (NSString *) _rrule
{
NSEnumerator *newValues;
NSString *newValue;
newValues = [[_rrule componentsSeparatedByString: @";"] objectEnumerator];
newValue = [newValues nextObject];
while (newValue)
{
[self addValue: newValue];
newValue = [newValues nextObject];
}
}
- (iCalRecurrenceFrequency) valueForFrequency: (NSString *) value
{
NSString *frequency;
iCalRecurrenceFrequency freq;
frequency = [value uppercaseString];
if ([frequency isEqualToString:@"WEEKLY"])
freq = iCalRecurrenceFrequenceWeekly;
else if ([frequency isEqualToString:@"MONTHLY"])
freq = iCalRecurrenceFrequenceMonthly;
else if ([frequency isEqualToString:@"DAILY"])
freq = iCalRecurrenceFrequenceDaily;
else if ([frequency isEqualToString:@"YEARLY"])
freq = iCalRecurrenceFrequenceYearly;
else if ([frequency isEqualToString:@"HOURLY"])
freq = iCalRecurrenceFrequenceHourly;
else if ([frequency isEqualToString:@"MINUTELY"])
freq = iCalRecurrenceFrequenceMinutely;
else if ([frequency isEqualToString:@"SECONDLY"])
freq = iCalRecurrenceFrequenceSecondly;
else
freq = NSNotFound;
return freq;
}
- (NSString *) frequencyForValue: (iCalRecurrenceFrequency) freq
{
NSString *frequency;
switch (freq)
{
case iCalRecurrenceFrequenceWeekly:
frequency = @"WEEKLY";
break;
case iCalRecurrenceFrequenceMonthly:
frequency = @"MONTHLY";
break;
case iCalRecurrenceFrequenceDaily:
frequency = @"DAILY";
break;
case iCalRecurrenceFrequenceYearly:
frequency = @"YEARLY";
break;
case iCalRecurrenceFrequenceHourly:
frequency = @"HOURLY";
break;
case iCalRecurrenceFrequenceMinutely:
frequency = @"MINUTELY";
break;
case iCalRecurrenceFrequenceSecondly:
frequency = @"SECONDLY";
break;
default:
frequency = nil;
}
return frequency;
}
/* accessors */
- (void) setFrequency: (iCalRecurrenceFrequency) _frequency
{
[self setNamedValue: @"freq" to: [self frequencyForValue: _frequency]];
}
- (iCalRecurrenceFrequency) frequency
{
return [self valueForFrequency: [self namedValue: @"freq"]];
}
- (void) setRepeatCount: (int) _repeatCount
{
[self setNamedValue: @"count"
to: [NSString stringWithFormat: @"%d", _repeatCount]];
}
- (int) repeatCount
{
return [[self namedValue: @"count"] intValue];
}
- (void) setUntilDate: (NSCalendarDate *) _untilDate
{
[self setNamedValue: @"until"
to: [_untilDate iCalFormattedDateTimeString]];
}
- (NSCalendarDate *) untilDate
{
#warning handling of default timezone needs to be implemented
return [[self namedValue: @"until"] asCalendarDate];
}
- (void) setInterval: (NSString *) _interval
{
[self setNamedValue: @"interval" to: _interval];
}
- (void) setCount: (NSString *) _count
{
[self setNamedValue: @"count" to: _count];
}
- (void) setUntil: (NSString *) _until
{
[self setNamedValue: @"until" to: _until];
}
- (void) setRepeatInterval: (int) _repeatInterval
{
[self setNamedValue: @"interval"
to: [NSString stringWithFormat: @"%d", _repeatInterval]];
}
- (int) repeatInterval
{
return [[self namedValue: @"interval"] intValue];
}
- (void) setWkst: (NSString *) _weekStart
{
[self setNamedValue: @"wkst" to: _weekStart];
}
- (NSString *) wkst
{
return [self namedValue: @"wkst"];
}
- (void) setWeekStart: (iCalWeekDay) _weekStart
{
[self setWkst: [self iCalRepresentationForWeekDay: _weekStart]];
}
- (iCalWeekDay) weekStart
{
return [self weekDayFromICalRepresentation: [self wkst]];
}
- (void) setByDayMask: (unsigned) _mask
{
NSMutableArray *days;
unsigned int count;
unsigned char maskDays[] = { iCalWeekDayMonday, iCalWeekDayTuesday,
iCalWeekDayWednesday, iCalWeekDayThursday,
iCalWeekDayFriday, iCalWeekDaySaturday,
iCalWeekDaySunday };
days = [NSMutableArray arrayWithCapacity: 7];
if (_mask)
{
for (count = 0; count < 7; count++)
if (_mask & maskDays[count])
[days addObject:
[self iCalRepresentationForWeekDay: maskDays[count]]];
}
[self setNamedValue: @"byday" to: [days componentsJoinedByString: @","]];
}
- (unsigned int) byDayMask
{
NSArray *days;
unsigned int mask, count, max;
NSString *day;
mask = 0;
days = [[self namedValue: @"byday"] componentsSeparatedByString: @","];
max = [days count];
for (count = 0; count < max; count++)
{
day = [days objectAtIndex: count];
day = [day substringFromIndex: [day length] - 2];
mask |= [self weekDayFromICalRepresentation: day];
}
return mask;
}
#warning this is fucked up
- (int) byDayOccurence1
{
return 0;
// return byDayOccurence1;
}
- (NSArray *) byMonthDay
{
return [[self namedValue: @"bymonthday"] componentsSeparatedByString: @","];
}
- (BOOL) isInfinite
{
return !([self repeatCount] || [self untilDate]);
}
/* private */
- (iCalWeekDay) weekDayFromICalRepresentation: (NSString *) _day
{
if ([_day length] > 1) {
/* be tolerant */
unichar c0, c1;
c0 = [_day characterAtIndex:0];
if (c0 == 'm' || c0 == 'M') return iCalWeekDayMonday;
if (c0 == 'w' || c0 == 'W') return iCalWeekDayWednesday;
if (c0 == 'f' || c0 == 'F') return iCalWeekDayFriday;
c1 = [_day characterAtIndex:1];
if (c0 == 't' || c0 == 'T') {
if (c1 == 'u' || c1 == 'U') return iCalWeekDayTuesday;
if (c1 == 'h' || c1 == 'H') return iCalWeekDayThursday;
}
if (c0 == 's' || c0 == 'S') {
if (c1 == 'a' || c1 == 'A') return iCalWeekDaySaturday;
if (c1 == 'u' || c1 == 'U') return iCalWeekDaySunday;
}
}
// TODO: do not raise but rather return an error value?
[NSException raise:NSGenericException
format:@"Incorrect weekDay '%@' specified!", _day];
return iCalWeekDayMonday; /* keep compiler happy */
}
- (NSString *) iCalRepresentationForWeekDay: (iCalWeekDay) _weekDay
{
switch (_weekDay)
{
case iCalWeekDayMonday: return @"MO";
case iCalWeekDayTuesday: return @"TU";
case iCalWeekDayWednesday: return @"WE";
case iCalWeekDayThursday: return @"TH";
case iCalWeekDayFriday: return @"FR";
case iCalWeekDaySaturday: return @"SA";
case iCalWeekDaySunday: return @"SU";
default: return @"MO"; // TODO: return error?
}
}
// - (iCalWeekDay) weekDayForiCalRepre: (NSString *) _weekDay
// {
// iCalWeekDay day;
// NSString *weekDay;
// weekDay = [_weekDay uppercaseString];
// if ([weekDay isEqualToString: @"TU"])
// day = iCalWeekDayTuesday;
// else if ([weekDay isEqualToString: @"WE"])
// day = iCalWeekDayWednesday;
// else if ([weekDay isEqualToString: @"TH"])
// day = iCalWeekDayThursday;
// else if ([weekDay isEqualToString: @"FR"])
// day = iCalWeekDayFriday;
// else if ([weekDay isEqualToString: @"SA"])
// day = iCalWeekDaySaturday;
// else if ([weekDay isEqualToString: @"SU"])
// day = iCalWeekDaySunday;
// else
// day = iCalWeekDayMonday;
// return day;
// }
// - (NSString *) wkst
// {
// return [self iCalRepresentationForWeekDay:byDay.weekStart];
// }
/*
TODO:
Each BYDAY value can also be preceded by a positive (+n) or negative
(-n) integer. If present, this indicates the nth occurrence of the
specific day within the MONTHLY or YEARLY RRULE. For example, within
a MONTHLY rule, +1MO (or simply 1MO) represents the first Monday
within the month, whereas -1MO represents the last Monday of the
month. If an integer modifier is not present, it means all days of
this type within the specified frequency. For example, within a
MONTHLY rule, MO represents all Mondays within the month.
*/
// - (NSString *) byDayList
// {
// NSMutableString *s;
// unsigned dow, mask, day;
// BOOL needsComma;
// s = [NSMutableString stringWithCapacity:20];
// needsComma = NO;
// mask = byDay.mask;
// day = iCalWeekDayMonday;
// for (dow = 0 /* Sun */; dow < 7; dow++) {
// if (mask & day) {
// if (needsComma)
// [s appendString:@","];
// if (byDay.useOccurence)
// // Note: we only support one occurrence for all currently
// [s appendFormat:@"%i", byDayOccurence1];
// [s appendString:[self iCalRepresentationForWeekDay:day]];
// needsComma = YES;
// }
// day = (day << 1);
// }
// return s;
// }
/* parsing rrule */
// - (void) _parseRuleString: (NSString *) _rrule
// {
// // TODO: to be exact we would need a timezone to properly process the 'until'
// // date
// unsigned i, count;
// NSString *pFrequency = nil;
// NSString *pUntil = nil;
// NSString *pCount = nil;
// NSString *pByday = nil;
// NSString *pBymday = nil;
// NSString *pBysetpos = nil;
// NSString *pInterval = nil;
// for (i = 0, count = [values count]; i < count; i++) {
// NSString *prop, *key, *value;
// NSRange r;
// NSString **vHolder = NULL;
// prop = [values objectAtIndex:i];
// r = [prop rangeOfString:@"="];
// if (r.length > 0) {
// key = [prop substringToIndex:r.location];
// value = [prop substringFromIndex:NSMaxRange(r)];
// }
// else {
// key = prop;
// value = nil;
// }
// key = [[key stringByTrimmingSpaces] lowercaseString];
// if (![key isNotEmpty]) {
// [self errorWithFormat:@"empty component in rrule: %@", _rrule];
// continue;
// }
// vHolder = NULL;
// switch ([key characterAtIndex:0]) {
// case 'b':
// if ([key isEqualToString:@"byday"]) { vHolder = &pByday; break; }
// if ([key isEqualToString:@"bymonthday"]) { vHolder = &pBymday; break; }
// if ([key isEqualToString:@"bysetpos"]) { vHolder = &pBysetpos; break; }
// break;
// case 'c':
// if ([key isEqualToString:@"count"]) { vHolder = &pCount; break; }
// break;
// case 'f':
// if ([key isEqualToString:@"freq"]) { vHolder = &pFrequency; break; }
// break;
// case 'i':
// if ([key isEqualToString:@"interval"]) { vHolder = &pInterval; break; }
// break;
// case 'u':
// if ([key isEqualToString:@"until"]) { vHolder = &pUntil; break; }
// break;
// default:
// break;
// }
// if (vHolder != NULL) {
// if ([*vHolder isNotEmpty])
// [self errorWithFormat:@"more than one '%@' in: %@", key, _rrule];
// else
// *vHolder = [value copy];
// }
// else {
// // TODO: we should just parse known keys and put remainders into a
// // separate dictionary
// [self logWithFormat:@"TODO: add explicit support for key: %@", key];
// [self takeValue:value forKey:key];
// }
// }
// /* parse and fill individual values */
// // TODO: this method should be a class method and create a new rrule object
// if ([pFrequency isNotEmpty])
// [self setNamedValue: @"FREQ" to: pFrequency];
// else
// [self errorWithFormat:@"rrule contains no frequency: '%@'", _rrule];
// [pFrequency release]; pFrequency = nil;
// if (pInterval != nil)
// interval = [pInterval intValue];
// [pInterval release]; pInterval = nil;
// // TODO: we should parse byday in here
// if (pByday != nil) [self setByday:pByday];
// [pByday release]; pByday = nil;
// if (pBymday != nil) {
// NSArray *t;
// t = [pBymday componentsSeparatedByString:@","];
// ASSIGNCOPY(byMonthDay, t);
// }
// [pBymday release]; pBymday = nil;
// if (pBysetpos != nil)
// // TODO: implement
// [self errorWithFormat:@"rrule contains bysetpos, unsupported: %@", _rrule];
// [pBysetpos release]; pBysetpos = nil;
// if (pUntil != nil) {
// NSCalendarDate *pUntilDate;
// if (pCount != nil) {
// [self errorWithFormat:@"rrule contains 'count' AND 'until': %@", _rrule];
// [pCount release];
// pCount = nil;
// }
// /*
// The spec says:
// "If specified as a date-time value, then it MUST be specified in an
// UTC time format."
// TODO: we still need some object representing a 'timeless' date.
// */
// if (![pUntil hasSuffix:@"Z"] && [pUntil length] > 8) {
// [self warnWithFormat:@"'until' date has no explicit UTC marker: '%@'",
// _rrule];
// }
// pUntilDate = [NSCalendarDate calendarDateWithICalRepresentation:pUntil];
// if (pUntilDate != nil)
// [self setUntilDate:pUntilDate];
// else {
// [self errorWithFormat:@"could not parse 'until' in rrule: %@",
// _rrule];
// }
// }
// [pUntil release]; pUntil = nil;
// if (pCount != nil)
// [self setRepeatCount:[pCount intValue]];
// [pCount release]; pCount = nil;
// }
/* properties */
// - (void) setByday: (NSString *) _byDayList
// {
// // TODO: each day can have an associated occurence, eg:
// // +1MO,+2TU,-9WE
// // TODO: this should be moved to the parser
// NSArray *days;
// unsigned i, count;
// NSString *iCalDay;
// iCalWeekDay day;
// unsigned len;
// unichar c0;
// int occurence;
// int offset;
// /* reset mask */
// byDay.mask = 0;
// byDay.useOccurence = 0;
// byDayOccurence1 = 0;
// days = [_byDayList componentsSeparatedByString:@","];
// for (i = 0, count = [days count]; i < count; i++)
// {
// iCalDay = [days objectAtIndex:i]; // eg: MO or TU
// if ((len = [iCalDay length]) == 0)
// {
// [self errorWithFormat:@"found an empty day in byday list: '%@'",
// _byDayList];
// continue;
// }
// c0 = [iCalDay characterAtIndex:0];
// if (((c0 == '+' || c0 == '-') && len > 2) || (isdigit(c0) && len > 1)) {
// occurence = [iCalDay intValue];
// offset = 1; /* skip occurence */
// while (offset < len && isdigit([iCalDay characterAtIndex:offset]))
// offset++;
// iCalDay = [iCalDay substringFromIndex:offset];
// if (byDay.useOccurence && (occurence != byDayOccurence1))
// {
// [self errorWithFormat:
// @"we only supported one occurence (occ=%i,day=%@): '%@'",
// occurence, iCalDay, _byDayList];
// continue;
// }
// byDay.useOccurence = 1;
// byDayOccurence1 = occurence;
// }
// else if (byDay.useOccurence)
// [self errorWithFormat:
// @"a byday occurence was specified on one day, but not on others"
// @" (unsupported): '%@'", _byDayList];
// day = [self weekDayFromICalRepresentation:iCalDay];
// byDay.mask |= day;
// }
// }
/* key/value coding */
- (void) handleTakeValue: (id) _value
forUnboundKey: (NSString *)_key
{
[self warnWithFormat:@"Cannot handle unbound key: '%@'", _key];
}
@end /* iCalRecurrenceRule */

View File

@ -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_ */

View File

@ -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 <NGExtensions/NGCalendarDateRange.h>
#include "iCalRecurrenceRule.h"
#include "iCalRecurrenceCalculator.h"
#include "common.h"
@implementation iCalRepeatableEntityObject
- (Class) classForTag: (NSString *) classTag
{
Class tagClass;
if ([classTag isEqualToString: @"RRULE"])
tagClass = [iCalRecurrenceRule class];
else
tagClass = [super classForTag: classTag];
return tagClass;
}
/* Accessors */
- (void) removeAllRecurrenceRules
{
[children removeObjectsInArray: [self childrenWithTag: @"rrule"]];
}
- (void) addToRecurrenceRules: (id) _rrule
{
[self addChild: _rrule];
}
- (void) setRecurrenceRules: (NSArray *) _rrules
{
[children removeObjectsInArray: [self childrenWithTag: @"rrule"]];
[self addChildren: _rrules];
}
- (BOOL) hasRecurrenceRules
{
return ([[self childrenWithTag: @"rrule"] count] > 0);
}
- (NSArray *) recurrenceRules
{
return [self childrenWithTag: @"rrule"];
}
- (void) removeAllExceptionRules
{
[children removeObjectsInArray: [self childrenWithTag: @"exrule"]];
}
- (void) addToExceptionRules: (id) _rrule
{
[self addChild: _rrule];
}
- (void) setExceptionRules: (NSArray *) _rrules
{
[children removeObjectsInArray: [self childrenWithTag: @"exrule"]];
[self addChildren: _rrules];
}
- (BOOL) hasExceptionRules
{
return ([[self childrenWithTag: @"exrule"] count] > 0);
}
- (NSArray *) exceptionRules
{
return [self childrenWithTag: @"exrule"];
}
- (void) removeAllExceptionDates
{
[children removeObjectsInArray: [self childrenWithTag: @"exdate"]];
}
- (void) addToExceptionDates: (id) _rdate
{
[self addChild: _rdate];
}
- (void) setExceptionDates: (NSArray *) _rdates
{
[children removeObjectsInArray: [self childrenWithTag: @"exdate"]];
[self addChildren: _rdates];
}
- (BOOL) hasExceptionDates
{
return ([[self childrenWithTag: @"exdate"] count] > 0);
}
- (NSArray *) exceptionDates
{
return [self childrenWithTag: @"exdate"];
}
/* Convenience */
- (BOOL) isRecurrent
{
return [self hasRecurrenceRules];
}
/* Matching */
- (BOOL) isWithinCalendarDateRange: (NGCalendarDateRange *) _range
firstInstanceCalendarDateRange: (NGCalendarDateRange *) _fir
{
NSArray *ranges;
ranges = [self recurrenceRangesWithinCalendarDateRange:_range
firstInstanceCalendarDateRange:_fir];
return [ranges count] > 0;
}
- (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *)_r
firstInstanceCalendarDateRange: (NGCalendarDateRange *)_fir
{
return [iCalRecurrenceCalculator recurrenceRangesWithinCalendarDateRange: _r
firstInstanceCalendarDateRange: _fir
recurrenceRules: [self recurrenceRules]
exceptionRules: [self exceptionRules]
exceptionDates: [self exceptionDates]];
}
/* this is the outmost bound possible, not necessarily the real last date */
- (NSCalendarDate *)
lastPossibleRecurrenceStartDateUsingFirstInstanceCalendarDateRange: (NGCalendarDateRange *)_r
{
NSCalendarDate *date;
NSEnumerator *rRules;
iCalRecurrenceRule *rule;
iCalRecurrenceCalculator *calc;
NSCalendarDate *rdate;
date = nil;
rRules = [[self recurrenceRules] objectEnumerator];
rule = [rRules nextObject];
while (rule && ![rule isInfinite] & !date)
{
calc = [iCalRecurrenceCalculator
recurrenceCalculatorForRecurrenceRule: rule
withFirstInstanceCalendarDateRange: _r];
rdate = [[calc lastInstanceCalendarDateRange] startDate];
if (!date
|| ([date compare: rdate] == NSOrderedAscending))
date = rdate;
else
rule = [rRules nextObject];
}
return date;
}
@end

View File

@ -0,0 +1,39 @@
/* iCalTimeZone.h - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef ICALTIMEZONE_H
#define ICALTIMEZONE_H
@class NSString;
@class NSCalendarDate;
#import "CardGroup.h"
@interface iCalTimeZone : CardGroup
- (NSString *) tzId;
- (NSString *) dateTimeStringForDate: (NSCalendarDate *) date;
- (NSCalendarDate *) dateForDateTimeString: (NSString *) string;
@end
#endif /* ICALTIMEZONE_H */

View File

@ -0,0 +1,132 @@
/* iCalTimeZone.m - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import <Foundation/NSCalendarDate.h>
#import "NSCalendarDate+NGCards.h"
#import "NSString+NGCards.h"
#import "iCalTimeZonePeriod.h"
#import "iCalTimeZone.h"
@implementation iCalTimeZone
- (Class) classForTag: (NSString *) classTag
{
Class tagClass;
if ([classTag isEqualToString: @"STANDARD"]
|| [classTag isEqualToString: @"DAYLIGHT"])
tagClass = [iCalTimeZonePeriod class];
else if ([classTag isEqualToString: @"TZID"])
tagClass = [CardElement class];
else
tagClass = [super classForTag: classTag];
return tagClass;
}
- (void) setTzId: (NSString *) tzId
{
[[self uniqueChildWithTag: @"tzid"] setValue: 0 to: tzId];
}
- (NSString *) tzId
{
return [[self uniqueChildWithTag: @"tzid"] value: 0];
}
- (NSCalendarDate *) _occurenceForPeriodNamed: (NSString *) pName
forDate: (NSCalendarDate *) aDate
{
NSArray *periods;
iCalTimeZonePeriod *period;
NSCalendarDate *occurence;
periods = [self childrenWithTag: pName];
if ([periods count])
{
period = (iCalTimeZonePeriod *) [periods objectAtIndex: 0];
occurence = [period occurenceForDate: aDate];
}
else
occurence = nil;
return occurence;
}
- (iCalTimeZonePeriod *) periodForDate: (NSCalendarDate *) date
{
NSCalendarDate *daylightOccurence, *standardOccurence;
iCalTimeZonePeriod *period;
/* FIXME, this could cause crashes when timezones are not properly
specified, but let's say it won't happen often... */
daylightOccurence = [self _occurenceForPeriodNamed: @"daylight"
forDate: date];
standardOccurence = [self _occurenceForPeriodNamed: @"standard"
forDate: date];
if ([date earlierDate: daylightOccurence] == date
|| [date earlierDate: standardOccurence] == standardOccurence)
period = (iCalTimeZonePeriod *) [self uniqueChildWithTag: @"standard"];
else
period = (iCalTimeZonePeriod *) [self uniqueChildWithTag: @"daylight"];
NSLog (@"chosen period: '%@'", [period tag]);
return period;
}
- (NSString *) dateTimeStringForDate: (NSCalendarDate *) date
{
NSCalendarDate *tmpDate;
NSTimeZone *utc;
utc = [NSTimeZone timeZoneWithName: @"GMT"];
tmpDate = [date copy];
[tmpDate autorelease];
[tmpDate setTimeZone: utc];
tmpDate
= [tmpDate addYear: 0 month: 0 day: 0
hour: 0 minute: 0
second: [[self periodForDate: date] secondsOffsetFromGMT]];
return [tmpDate iCalFormattedDateTimeString];
}
- (NSCalendarDate *) dateForDateTimeString: (NSString *) string
{
NSCalendarDate *tmpDate;
iCalTimeZonePeriod *period;
tmpDate = [string asCalendarDate];
period = [self periodForDate: tmpDate];
return [tmpDate addYear: 0 month: 0 day: 0
hour: 0 minute: 0
second: -[period secondsOffsetFromGMT]];
}
@end

View File

@ -0,0 +1,35 @@
/* iCalTimeZonePeriod.h - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef ICALTIMEZONEPERIOD_H
#define ICALTIMEZONEPERIOD_H
#import "CardGroup.h"
@interface iCalTimeZonePeriod : CardGroup
- (NSCalendarDate *) occurenceForDate: (NSCalendarDate *) refDate;
- (int) secondsOffsetFromGMT;
@end
#endif /* ICALTIMEZONEPERIOD_H */

View File

@ -0,0 +1,140 @@
/* iCalTimeZonePeriod.m - this file is part of SOPE
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSString.h>
#import "iCalDateTime.h"
#import "iCalRecurrenceRule.h"
#import "CardGroup+iCal.h"
#import "iCalTimeZonePeriod.h"
@implementation iCalTimeZonePeriod
- (Class) classForTag: (NSString *) classTag
{
Class tagClass;
if ([classTag isEqualToString: @"RRULE"])
tagClass = [iCalRecurrenceRule class];
else if ([classTag isEqualToString: @"DTSTART"])
tagClass = [iCalDateTime class];
else if ([classTag isEqualToString: @"TZNAME"]
|| [classTag isEqualToString: @"TZOFFSETFROM"]
|| [classTag isEqualToString: @"TZOFFSETTO"])
tagClass = [CardElement class];
else
tagClass = [super classForTag: classTag];
return tagClass;
}
- (int) _secondsOfOffset: (NSString *) offsetName
{
NSString *offsetTo;
BOOL negative;
NSRange cursor;
unsigned int length;
unsigned int seconds;
seconds = 0;
offsetTo = [[self uniqueChildWithTag: offsetName]
value: 0];
length = [offsetTo length];
negative = [offsetTo hasPrefix: @"-"];
if (negative)
{
length--;
cursor = NSMakeRange(1, 2);
}
else if ([offsetTo hasPrefix: @"+"])
{
length--;
cursor = NSMakeRange(1, 2);
}
else
cursor = NSMakeRange(0, 2);
seconds = 3600 * [[offsetTo substringWithRange: cursor] intValue];
cursor.location += 2;
seconds += 60 * [[offsetTo substringWithRange: cursor] intValue];
if (length == 6)
{
cursor.location += 2;
seconds += [[offsetTo substringWithRange: cursor] intValue];
}
return ((negative) ? -seconds : seconds);
}
- (unsigned int) dayOfWeekFromRruleDay: (iCalWeekDay) day
{
unsigned int dayOfWeek;
dayOfWeek = 1;
while (day >> dayOfWeek)
dayOfWeek++;
return dayOfWeek;
}
- (NSCalendarDate *) occurenceForDate: (NSCalendarDate *) refDate;
{
NSCalendarDate *tmpDate;
iCalRecurrenceRule *rrule;
NSString *byDay;
int dayOfWeek, dateDayOfWeek, offset, pos;
rrule = (iCalRecurrenceRule *) [self uniqueChildWithTag: @"rrule"];
byDay = [rrule namedValue: @"byday"];
dayOfWeek = [self dayOfWeekFromRruleDay: [rrule byDayMask]];
pos = [[byDay substringToIndex: 2] intValue];
if (!pos)
pos = 1;
tmpDate = [NSCalendarDate
dateWithYear: [refDate yearOfCommonEra]
month: [[rrule namedValue: @"bymonth"] intValue]
day: 1 hour: 0 minute: 0 second: 0
timeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
tmpDate = [tmpDate addYear: 0 month: ((pos > 0) ? 0 : 1)
day: 0 hour: 0 minute: 0
second: -[self _secondsOfOffset: @"tzoffsetfrom"]];
dateDayOfWeek = [tmpDate dayOfWeek];
offset = (dayOfWeek - dateDayOfWeek);
if (pos > 0 && offset < 0)
offset += 7;
offset += (pos * 7);
tmpDate = [tmpDate addYear: 0 month: 0 day: offset
hour: 0 minute: 0 second: 0];
return tmpDate;
}
- (int) secondsOffsetFromGMT
{
return [self _secondsOfOffset: @"tzoffsetto"];
}
@end

View File

@ -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__ */

View File

@ -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 <Foundation/NSString.h>
#import "NSCalendarDate+NGCards.h"
#import "CardGroup+iCal.h"
#import "iCalDateTime.h"
#import "iCalToDo.h"
@implementation iCalToDo
- (Class) classForTag: (NSString *) classTag
{
Class tagClass;
if ([classTag isEqualToString: @"DUE"]
|| [classTag isEqualToString: @"COMPLETED"])
tagClass = [iCalDateTime class];
else if ([classTag isEqualToString: @"PERCENT-COMPLETE"])
tagClass = [CardElement class];
else
tagClass = [super classForTag: classTag];
return tagClass;
}
/* accessors */
- (void) setPercentComplete: (NSString *) _value
{
[[self uniqueChildWithTag: @"percent-complete"] setValue: 0
to: _value];
}
- (NSString *) percentComplete
{
return [[self uniqueChildWithTag: @"percent-complete"] value: 0];
}
- (void) setDue: (NSCalendarDate *) _date
{
[self setDate: _date
forDateTimeValue: @"due"];
}
- (NSCalendarDate *) due
{
return [self dateForDateTimeValue: @"due"];
// return [[self uniqueChildWithTag: @"percent-complete"] asCalendarDate];
}
- (void) setCompleted: (NSCalendarDate *) _date
{
[self setStatus: @"COMPLETED"];
[self setDate: _date forDateTimeValue: @"completed"];
}
- (NSCalendarDate *) completed
{
return [self dateForDateTimeValue: @"completed"];
}
/* ical typing */
- (NSString *) entityName
{
return @"vtodo";
}
// /* descriptions */
// - (NSString *)description {
// NSMutableString *ms;
// ms = [NSMutableString stringWithCapacity:128];
// [ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
// if (uid) [ms appendFormat:@" uid=%@", uid];
// if (startDate) [ms appendFormat:@" start=%@", startDate];
// if (due) [ms appendFormat:@" due=%@", due];
// if (priority) [ms appendFormat:@" pri=%@", priority];
// if (completed)
// [ms appendFormat:@" completed=%@", completed];
// if (percentComplete)
// [ms appendFormat:@" complete=%@", percentComplete];
// if (accessClass)
// [ms appendFormat:@" class=%@", accessClass];
// if (summary)
// [ms appendFormat:@" summary=%@", summary];
// [ms appendString:@">"];
// return ms;
// }
@end /* iCalToDo */

View File

@ -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__ */

View File

@ -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 */

View File

@ -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 <NGExtensions/NGCalendarDateRange.h>
#include "iCalRecurrenceRule.h"
#include "NSCalendarDate+ICal.h"
#include "common.h"
@interface iCalRecurrenceCalculator (PrivateAPI)
- (NSCalendarDate *)lastInstanceStartDate;
- (unsigned)offsetFromSundayForJulianNumber:(long)_jn;
- (unsigned)offsetFromSundayForWeekDay:(iCalWeekDay)_weekDay;
- (unsigned)offsetFromSundayForCurrentWeekStart;
- (iCalWeekDay)weekDayForJulianNumber:(long)_jn;
@end
/*
TODO: If BYDAY is specified, lastInstanceStartDate and recurrences will
differ significantly!
*/
@implementation iCalWeeklyRecurrenceCalculator
- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r {
NSMutableArray *ranges;
NSCalendarDate *firStart;
long i, jnFirst, jnStart, jnEnd, startEndCount;
unsigned interval, byDayMask;
firStart = [self->firstRange startDate];
jnFirst = [firStart julianNumber];
jnEnd = [[_r endDate] julianNumber];
if (jnFirst > jnEnd)
return nil;
jnStart = [[_r startDate] julianNumber];
interval = [self->rrule repeatInterval];
/* if rule is bound, check the bounds */
if (![self->rrule isInfinite]) {
NSCalendarDate *until;
long jnRuleLast;
until = [self->rrule untilDate];
if (until) {
if ([until compare:[_r startDate]] == NSOrderedAscending)
return nil;
jnRuleLast = [until julianNumber];
}
else {
jnRuleLast = (interval * [self->rrule repeatCount] * 7)
+ jnFirst;
if (jnRuleLast < jnStart)
return nil;
}
/* jnStart < jnRuleLast < jnEnd ? */
if (jnEnd > jnRuleLast)
jnEnd = jnRuleLast;
}
startEndCount = (jnEnd - jnStart) + 1;
ranges = [NSMutableArray arrayWithCapacity:startEndCount];
byDayMask = [self->rrule byDayMask];
if (!byDayMask) {
for (i = 0 ; i < startEndCount; i++) {
long jnCurrent;
jnCurrent = jnStart + i;
if (jnCurrent >= jnFirst) {
long jnDiff;
jnDiff = jnCurrent - jnFirst; /* difference in days */
if ((jnDiff % (interval * 7)) == 0) {
NSCalendarDate *start, *end;
NGCalendarDateRange *r;
start = [NSCalendarDate dateForJulianNumber:jnCurrent];
[start setTimeZone:[firStart timeZone]];
start = [start hour: [firStart hourOfDay]
minute:[firStart minuteOfHour]
second:[firStart secondOfMinute]];
end = [start addTimeInterval:[self->firstRange duration]];
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
endDate:end];
if ([_r containsDateRange:r])
[ranges addObject:r];
}
}
}
}
else {
long jnFirstWeekStart, weekStartOffset;
/* calculate jnFirst's week start - this depends on our setting of week
start */
weekStartOffset = [self offsetFromSundayForJulianNumber:jnFirst] -
[self offsetFromSundayForCurrentWeekStart];
jnFirstWeekStart = jnFirst - weekStartOffset;
for (i = 0 ; i < startEndCount; i++) {
long jnCurrent;
jnCurrent = jnStart + i;
if (jnCurrent >= jnFirst) {
long jnDiff;
/* we need to calculate a difference in weeks */
jnDiff = (jnCurrent - jnFirstWeekStart) % 7;
if ((jnDiff % interval) == 0) {
BOOL isRecurrence = NO;
if (jnCurrent == jnFirst) {
isRecurrence = YES;
}
else {
iCalWeekDay weekDay;
weekDay = [self weekDayForJulianNumber:jnCurrent];
isRecurrence = (weekDay & [self->rrule byDayMask]) ? YES : NO;
}
if (isRecurrence) {
NSCalendarDate *start, *end;
NGCalendarDateRange *r;
start = [NSCalendarDate dateForJulianNumber:jnCurrent];
[start setTimeZone:[firStart timeZone]];
start = [start hour: [firStart hourOfDay]
minute:[firStart minuteOfHour]
second:[firStart secondOfMinute]];
end = [start addTimeInterval:[self->firstRange duration]];
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
endDate:end];
if ([_r containsDateRange:r])
[ranges addObject:r];
}
}
}
}
}
return ranges;
}
- (NSCalendarDate *)lastInstanceStartDate {
if ([self->rrule repeatCount] > 0) {
long jnFirst, jnRuleLast;
NSCalendarDate *firStart, *until;
firStart = [self->firstRange startDate];
jnFirst = [firStart julianNumber];
jnRuleLast = ([self->rrule repeatInterval] *
[self->rrule repeatCount] * 7) +
jnFirst;
until = [NSCalendarDate dateForJulianNumber:jnRuleLast];
until = [until hour: [firStart hourOfDay]
minute:[firStart minuteOfHour]
second:[firStart secondOfMinute]];
return until;
}
return [super lastInstanceStartDate];
}
@end /* iCalWeeklyRecurrenceCalculator */

View File

@ -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 <NGExtensions/NGCalendarDateRange.h>
#include "iCalRecurrenceRule.h"
#include "NSCalendarDate+ICal.h"
#include "common.h"
@interface iCalRecurrenceCalculator(PrivateAPI)
- (NSCalendarDate *)lastInstanceStartDate;
@end
@implementation iCalYearlyRecurrenceCalculator
- (NSArray *)recurrenceRangesWithinCalendarDateRange:(NGCalendarDateRange *)_r{
NSMutableArray *ranges;
NSCalendarDate *firStart, *rStart, *rEnd, *until;
unsigned i, count, interval;
int diff;
firStart = [self->firstRange startDate];
rStart = [_r startDate];
rEnd = [_r endDate];
interval = [self->rrule repeatInterval];
until = [self lastInstanceStartDate];
if (until) {
if ([until compare:rStart] == NSOrderedAscending)
return nil;
if ([until compare:rEnd] == NSOrderedDescending)
rEnd = until;
}
diff = [firStart yearsBetweenDate:rStart];
if ((diff != 0) && [rStart compare:firStart] == NSOrderedAscending)
diff = -diff;
count = [rStart yearsBetweenDate:rEnd] + 1;
ranges = [NSMutableArray arrayWithCapacity:count];
for (i = 0 ; i < count; i++) {
int test;
test = diff + i;
if ((test >= 0) && (test % interval) == 0) {
NSCalendarDate *start, *end;
NGCalendarDateRange *r;
start = [firStart dateByAddingYears:diff + i
months:0
days:0];
[start setTimeZone:[firStart timeZone]];
end = [start addTimeInterval:[self->firstRange duration]];
r = [NGCalendarDateRange calendarDateRangeWithStartDate:start
endDate:end];
if ([_r containsDateRange:r])
[ranges addObject:r];
}
}
return ranges;
}
- (NSCalendarDate *)lastInstanceStartDate {
if ([self->rrule repeatCount] > 0) {
NSCalendarDate *until;
unsigned years, interval;
interval = [self->rrule repeatInterval];
years = [self->rrule repeatCount] * interval;
until = [[self->firstRange startDate] dateByAddingYears:years
months:0
days:0];
return until;
}
return [super lastInstanceStartDate];
}
@end /* iCalYearlyRecurrenceCalculator */

View File

@ -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.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@ -0,0 +1,157 @@
2005-09-19 Helge Hess <helge.hess@opengroupware.org>
* ievalrrule.m: started tool to evaluate iCal rrules on the shell
2005-08-16 Helge Hess <helge.hess@opengroupware.org>
* link tools against OSX frameworks if configured so
2005-05-06 Helge Hess <helge.hess@opengroupware.org>
* renamed ical3.m to icalds.m, ical2.m to icalparsetest
2005-04-25 Helge Hess <helge.hess@opengroupware.org>
* properly include config.make
* fixed some gcc 4.0 warnings
2004-09-26 Helge Hess <helge.hess@opengroupware.org>
* GNUmakefile.preamble: fixed makefiles for SOPE inline compilation
2004-08-29 Helge Hess <helge.hess@opengroupware.org>
* added hack to install the tools in FHS locations - the executables
will be installed in FHS_INSTALL_ROOT if specified (eg make
FHS_INSTALL_ROOT=/usr/local)
2004-08-17 Helge Hess <helge.hess@opengroupware.org>
* subclassing.m: fixed a compiler warning
2004-07-09 Helge Hess <helge.hess@skyrix.com>
* bmlookup.m: major code cleanups, improved output
2004-06-27 Helge Hess <helge.hess@opengroupware.org>
* ldap2dsml.m: fixed a compile warning
2004-06-21 Helge Hess <helge.hess@opengroupware.org>
* common.h: fixed compatibility with gstep-base
2004-06-17 Helge Hess <helge.hess@opengroupware.org>
* added 'testurl' to test NSURL for the Cocoa Foundation bug wrt the
trailing suffix in -path
2004-05-09 Helge Hess <helge.hess@opengroupware.org>
* subclassing.m: added support for Apple runtime
2004-04-12 Helge Hess <helge.hess@opengroupware.org>
* ImapListTool, ImapTool.m, imapls.m: minor code cleanups
2004-01-19 Helge Hess <helge.hess@opengroupware.org>
* ldapls.m: minor fixes (moved NSAutoreleasePool to correct place)
2004-01-11 Helge Hess <helge.hess@opengroupware.org>
* minor cleanups to log messages
2003-10-12 Helge Hess <helge@opengroupware.org>
* EOQualTool.m: fix: returned value in a void method
* GNUmakefile (TOOL_NAME): do not compile subclassing.m on
MacOSX
* EncodingTool.m: fixed compilation on MacOSX
2003-05-15 Helge Hess <helge.hess@skyrix.com>
* added parserule for testing parsing of NGRule objects
2003-05-14 Helge Hess <helge.hess@skyrix.com>
* some gcc 3.3 warnings fixed
2003-04-03 Helge Hess <helge.hess@skyrix.com>
* GNUmakefile: added ldapchkpwd tool
* ldap2dsml.m: added autorelease-pool to main()
2003-04-01 GNUstep User <helge.hess@skyrix.com>
* ImapListTool.m: do not use NSFileIdentifier constant
* EncodingTool.m: removed some undeclared encodings when compiling for
GNUstep Base
2003-02-12 Helge Hess <helge.hess@skyrix.com>
* added ical2.m, ical3.m - examples for NGiCal
2003-01-30 Helge Hess <helge.hess@skyrix.com>
* added httpu_notify, a small tool to send out HTTP-over-UDP
NOTIFY notifications
2003-01-08 Helge Hess <helge.hess@skyrix.com>
* testsock.m: improved test code
2003-01-07 Helge Hess <helge.hess@skyrix.com>
* subclassing.m, ImapQuotaTool.m, imapquota.m: fixed compilation
warnings
* moved in testsock.m from NGStreams
* changes for improved compilation on MacOSX, replaced RETAIN macros
with methods
Fri Dec 27 10:54:40 2002 Helge Hess <helge.hess@skyrix.com>
* Mime2XmlTool.m: fixed a protocol warning
Mon Dec 23 15:36:01 2002 Helge Hess <helge.hess@skyrix.com>
* ImapListTool.m: pass correct filemanager as a parameter
2002-12-08 Helge Hess <helge.hess@skyrix.com>
* testdirenum.m: cleanups
Tue Dec 17 15:07:40 2002 <jan@skyrix.com>
* imapquota.m: add quota test
2002-11-21 Jan Reichmann <jr@skyrix.com>
* added Imap-Super class, improve imapls
2002-11-21 Helge Hess <helge.hess@skyrix.com>
* added ldapls, ldap2dsml as examples for NGLdap
2002-11-15 Helge Hess <helge.hess@skyrix.com>
* EOQualTool.m: added test for complex cast
2002-10-29 Helge Hess <helge.hess@skyrix.com>
* EOQualTool.m: added support for parsing SQL using the new EOSQLParser
2002-10-25 Helge Hess <helge.hess@skyrix.com>
* added eoqual tool for parsing EOQualifier's (useful for syntax
checks)
* created ChangeLog

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 <Foundation/Foundation.h>
#if LIB_FOUNDATION_LIBRARY
# include <Foundation/exceptions/GeneralExceptions.h>
#else
# include <NGExtensions/NGObjectMacros.h>
# include <NGExtensions/NSString+Ext.h>
#endif
#include <NGExtensions/NGExtensions.h>

View File

@ -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

View File

@ -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 <Foundation/Foundation.h>
@class EOQualifier, NSString, EOSortOrdering;
@interface iCal3Tool : NSObject
{
EOQualifier *qualifier;
NSString *entityName;
NSArray *sortOrderings;
}
- (int)runWithArguments:(NSArray *)_args;
@end
#include <NGCards/iCalDataSource.h>
#include <NGCards/iCalObject.h>
#include <EOControl/EOQualifier.h>
#include <EOControl/EOSortOrdering.h>
#include "common.h"
@implementation iCal3Tool
- (id)init {
if ((self = [super init])) {
NSUserDefaults *ud;
id tmp;
/* collect options */
ud = [NSUserDefaults standardUserDefaults];
self->entityName = [[ud stringForKey:@"entity"] copy];
if ((tmp = [ud objectForKey:@"qualifier"]) != nil) {
self->qualifier = [[EOQualifier alloc] initWithPropertyList:tmp
owner:nil];
}
if ((tmp = [ud objectForKey:@"sort"]) != nil) {
tmp = [[EOSortOrdering alloc] initWithPropertyList:tmp owner:nil];
if (tmp != nil) {
self->sortOrderings = [[NSArray alloc] initWithObjects:&tmp count:1];
[tmp release]; tmp = nil;
}
}
}
return self;
}
- (void)dealloc {
[self->sortOrderings release];
[self->qualifier release];
[self->entityName release];
[super dealloc];
}
/* run */
- (void)printObject:(id)_object {
printf("object: %s\n", [[_object description] cString]);
}
- (int)runWithArguments:(NSArray *)_args {
NSEnumerator *args;
NSString *arg;
/* begin processing */
args = [_args objectEnumerator];
[args nextObject]; // process name ...
while ((arg = [args nextObject])) {
NSAutoreleasePool *pool2;
if ([arg hasPrefix:@"-"]) { /* consume defaults */
[args nextObject];
continue;
}
pool2 = [[NSAutoreleasePool alloc] init];
{
iCalDataSource *ds;
EOFetchSpecification *fspec;
NSArray *objs;
iCalObject *obj;
/* setup fetch specification */
fspec = [[[EOFetchSpecification alloc] init] autorelease];
[fspec setEntityName:self->entityName];
[fspec setQualifier:self->qualifier];
/* setup datasource */
ds = [iCalDataSource alloc]; // keep gcc happy
ds = [[ds initWithPath:arg] autorelease];
[ds setFetchSpecification:fspec];
/* perform fetch */
if ((objs = [ds fetchObjects]) == nil) {
/* fetch failed */
NSLog(@"fetch on ical file failed: %@", arg);
}
else {
/* process results */
NSEnumerator *e;
e = [objs objectEnumerator];
while ((obj = [e nextObject])) {
[self printObject:obj];
}
}
}
[pool2 release];
}
return 0;
}
@end /* iCal3Tool */
int main(int argc, char **argv, char **env) {
NSAutoreleasePool *pool;
iCal3Tool *tool;
int rc;
pool = [[NSAutoreleasePool alloc] init];
#if LIB_FOUNDATION_LIBRARY
[NSProcessInfo initializeWithArguments:argv count:argc environment:env];
#endif
if ((tool = [[iCal3Tool alloc] init])) {
NS_DURING
rc = [tool runWithArguments:[[NSProcessInfo processInfo] arguments]];
NS_HANDLER
abort();
NS_ENDHANDLER;
[tool release];
}
else
rc = 1;
[pool release];
return rc;
}

View File

@ -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 <Foundation/Foundation.h>
#include <SaxObjC/SaxObjC.h>
@interface iCal2Tool : NSObject
{
id<NSObject,SaxXMLReader> parser;
SaxObjectDecoder *sax;
}
- (int)runWithArguments:(NSArray *)_args;
@end
@implementation iCal2Tool
- (id)init {
if ((self = [super init])) {
self->parser =
[[[SaxXMLReaderFactory standardXMLReaderFactory]
createXMLReaderForMimeType:@"text/calendar"]
retain];
if (self->parser == nil) {
NSLog(@"%s: did not find a parser for text/calendar !",
__PRETTY_FUNCTION__);
[self release];
return nil;
}
/* ensure that NGCards.xmap can be found ! (Library/SaxMappings) */
self->sax = [[SaxObjectDecoder alloc] initWithMappingNamed:@"NGCards"];
if (self->sax == nil) {
NSLog(@"could not create the iCal SAX handler !");
[self release];
return nil;
}
[self->parser setContentHandler:self->sax];
[self->parser setErrorHandler:self->sax];
}
return self;
}
- (void)dealloc {
[self->sax release];
[self->parser release];
[super dealloc];
}
/* parsing */
- (id)parseFile:(NSString *)_path {
if ([_path length] == 0) return nil;
_path = [@"file://" stringByAppendingString:_path];
[self->parser parseFromSystemId:_path];
return [self->sax rootObject];
}
- (void)printParsedObject:(id)_object {
NSLog(@"component: %@", _object);
#if 0
NSLog(@" subcomponents: %@", [_object subComponents]);
printf("%s", [[_object icalString] cString]);
#endif
}
/* run */
- (int)runWithArguments:(NSArray *)_args {
NSEnumerator *args;
NSString *arg;
args = [_args objectEnumerator];
[args nextObject]; // process name ...
while ((arg = [args nextObject])) {
NSAutoreleasePool *pool2;
if ([arg hasPrefix:@"-"]) { /* consume defaults */
[args nextObject];
continue;
}
pool2 = [[NSAutoreleasePool alloc] init];
{
id component;
NS_DURING
component = [self parseFile:arg];
NS_HANDLER
abort();
NS_ENDHANDLER;
if (component == nil)
NSLog(@"could not parse file: '%@'", arg);
else
[self printParsedObject:component];
}
[pool2 release];
}
return 0;
}
@end /* iCal2Tool */
int main(int argc, char **argv, char **env) {
NSAutoreleasePool *pool;
iCal2Tool *tool;
int rc;
#if LIB_FOUNDATION_LIBRARY
[NSProcessInfo initializeWithArguments:argv count:argc environment:env];
#endif
pool = [[NSAutoreleasePool alloc] init];
if ((tool = [[iCal2Tool alloc] init])) {
NS_DURING
rc = [tool runWithArguments:[[NSProcessInfo processInfo] arguments]];
NS_HANDLER
abort();
NS_ENDHANDLER;
[tool release];
}
else
rc = 1;
[pool release];
return rc;
}

View File

@ -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 <NGCards/iCalRecurrenceRule.h>
#include <NGCards/iCalRecurrenceCalculator.h>
#include <NGExtensions/NGCalendarDateRange.h>
#include "common.h"
static NSCalendarDate *dateForString(NSString *_s) {
// copied from ogo-chkaptconflicts, maybe move to NGExtensions?
static NSCalendarDate *now = nil;
static NSCalendarDate *mon = nil;
if (now == nil) now = [[NSCalendarDate date] retain];
if (mon == nil) mon = [[now mondayOfWeek] retain];
_s = [_s lowercaseString];
if ([_s isEqualToString:@"now"]) return now;
if ([_s isEqualToString:@"tomorrow"]) return [now tomorrow];
if ([_s isEqualToString:@"yesterday"]) return [now yesterday];
if ([_s hasPrefix:@"mon"]) return mon;
if ([_s hasPrefix:@"tue"]) return [mon dateByAddingYears:0 months:0 days:1];
if ([_s hasPrefix:@"wed"]) return [mon dateByAddingYears:0 months:0 days:2];
if ([_s hasPrefix:@"thu"]) return [mon dateByAddingYears:0 months:0 days:3];
if ([_s hasPrefix:@"fri"]) return [mon dateByAddingYears:0 months:0 days:4];
if ([_s hasPrefix:@"sat"]) return [mon dateByAddingYears:0 months:0 days:5];
if ([_s hasPrefix:@"sun"]) return [mon dateByAddingYears:0 months:0 days:6];
switch ([_s length]) {
case 6:
return [NSCalendarDate dateWithString:_s calendarFormat:@"%Y%m"];
case 8:
return [NSCalendarDate dateWithString:_s calendarFormat:@"%Y%m%d"];
case 10:
return [NSCalendarDate dateWithString:_s calendarFormat:@"%Y%-m-%d"];
case 13:
return [NSCalendarDate dateWithString:_s calendarFormat:@"%Y%m%d %H%M"];
case 14:
return [NSCalendarDate dateWithString:_s calendarFormat:@"%Y%m%d %H:%M"];
case 16:
return [NSCalendarDate dateWithString:_s calendarFormat:@"%Y-%m-%d %H:%M"];
default:
return nil;
}
}
static int usage(NSArray *args) {
fprintf(stderr,
"usage: %s <rrule> <startdate> <enddate> <cycleend>\n"
"\n"
"sample:\n"
" %s 'FREQ=MONTHLY;BYDAY=2TU' '20050901 14:00' '20050901 15:00' "
"20060921\n",
[[args objectAtIndex:0] cString],
[[args objectAtIndex:0] cString]);
return 1;
}
static void printInstances(NSArray *instances) {
unsigned i, count;
if ((count = [instances count]) == 0) {
printf("no reccurrences in given range\n");
return;
}
for (i = 0; i < count; i++) {
NGCalendarDateRange *instance;
NSString *s;
instance = [instances objectAtIndex:i];
s = [[instance startDate] descriptionWithCalendarFormat:
@"%a, %Y-%m-%d at %H:%M"];
printf("%s - ", [s cString]);
s = [[instance endDate] descriptionWithCalendarFormat:
[[instance startDate] isDateOnSameDay:
[instance endDate]]
? @"%H:%M"
: @"%a, %Y-%m-%d at %H:%M"];
printf("%s\n", [s cString]);
}
}
static int runIt(NSArray *args) {
iCalRecurrenceCalculator *cpu;
iCalRecurrenceRule *rrule;
NGCalendarDateRange *startRange, *calcRange;
NSCalendarDate *from, *to, *cycleTo;
NSString *pattern;
NSArray *instances;
if ([args count] < 5)
return usage(args);
pattern = [args objectAtIndex:1];
from = dateForString([args objectAtIndex:2]);
to = dateForString([args objectAtIndex:3]);
cycleTo = dateForString([args objectAtIndex:4]);
if (from == nil || to == nil || cycleTo == nil || ![pattern isNotEmpty])
return usage(args);
startRange =
[NGCalendarDateRange calendarDateRangeWithStartDate:from endDate:to];
calcRange =
[NGCalendarDateRange calendarDateRangeWithStartDate:from endDate:cycleTo];
/* parse rrule */
if ((rrule = [[iCalRecurrenceRule alloc] initWithString:pattern]) == nil) {
usage(args);
fprintf(stderr, "error: could not parse reccurence rule: '%s'\n",
[pattern cString]);
return 2;
}
NSLog(@"from: %@ to: %@, cycle %@", from, to, cycleTo);
NSLog(@"rrule: %@", rrule);
/* calculate */
cpu = [iCalRecurrenceCalculator
recurrenceCalculatorForRecurrenceRule:rrule
withFirstInstanceCalendarDateRange:startRange];
instances = [cpu recurrenceRangesWithinCalendarDateRange:calcRange];
printInstances(instances);
return 0;
}
int main(int argc, char **argv, char **env) {
NSAutoreleasePool *pool;
int rc;
pool = [[NSAutoreleasePool alloc] init];
#if LIB_FOUNDATION_LIBRARY
[NSProcessInfo initializeWithArguments:argv count:argc environment:env];
#endif
rc = runIt([[NSProcessInfo processInfo] argumentsWithoutDefaults]);
[pool release];
return rc;
}

View File

@ -0,0 +1,88 @@
/* unittest.h - this file is part of $PROJECT_NAME_HERE$
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef UNITTEST_H
#define UNITTEST_H
#import <Foundation/NSObject.h>
@interface unittest : NSObject
- (void) run;
@end
#define testEqual(x,y) \
if ((x) != (y)) { \
NSLog (@"%s: values not equal at line %d", \
__PRETTY_FUNCTION__, __LINE__); \
return NO; \
}
#define testObjectsEqual(x,y) \
if (![(x) isEqual: (y)]) { \
NSLog (@"%s: objects not equal at line %d", \
__PRETTY_FUNCTION__, __LINE__); \
return NO; \
}
#define testStringsEqual(x,y) \
if (!([(x) isKindOfClass: [NSString class]] \
&& [(y) isKindOfClass: [NSString class]] ) \
|| ![(x) isEqualToString: (y)]) { \
NSLog (@"%s: strings \"%@\" and \"%@\" not equal at" \
@" line %d", __PRETTY_FUNCTION__, (x), (y), \
__LINE__); \
return NO; \
}
#define testNotEqual(x,y) \
if ((x) == (y)) { \
NSLog (@"%s: values equal at line %d", \
__PRETTY_FUNCTION__, __LINE__); \
return NO; \
}
#define testObjectsNotEqual(x,y) \
if ([(x) isEqual: (y)]) { \
NSLog (@"%s: objects not equal at line %d", \
__PRETTY_FUNCTION__, __LINE__); \
return NO; \
}
#define testStringsNotEqual(x,y) \
if (!([(x) isKindOfClass: [NSString class]] \
&& [(y) isKindOfClass: [NSString class]]) \
|| [(x) isEqualToString: (y)]) { \
NSLog (@"%s: strings not equal at line %d", \
__PRETTY_FUNCTION__, __LINE__); \
return NO; \
}
@interface unittest (OptionalMethods)
- (void) setUp;
- (void) tearDown;
@end
#endif /* UNITTEST_H */

View File

@ -0,0 +1,98 @@
/* unittest.m - this file is part of $PROJECT_NAME_HERE$
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
#import "unittest.h"
@implementation unittest
- (NSArray *) _testMethods
{
Class testClass;
MethodList *methodList;
NSMutableArray *methods;
NSString *methodName;
unsigned int count, max;
testClass = [self class];
methods = [NSMutableArray new];
[methods autorelease];
while (testClass)
{
methodList = testClass->methods;
max = methodList->method_count;
for (count = 0; count < max; count++)
{
methodName
= NSStringFromSelector (methodList->method_list[count].method_name);
if ([methodName hasPrefix: @"test"])
[methods addObject: methodName];
}
testClass = testClass->super_class;
}
return methods;
}
- (void) run
{
NSEnumerator *methods;
NSString *methodName;
unsigned int count, successes, failures;
BOOL success;
methods = [[self _testMethods] objectEnumerator];
methodName = [methods nextObject];
count = 0;
successes = 0;
failures = 0;
NSLog (@"-- start: %@", NSStringFromClass([self class]));
while (methodName)
{
count++;
if ([self respondsToSelector: @selector (setUp)])
[self setUp];
success
= (BOOL) [self performSelector: NSSelectorFromString (methodName)];
NSLog (@"%@ '%@'",
((success) ? @"PASSED" : @"FAILED"), methodName);
if ([self respondsToSelector: @selector (tearDown)])
[self tearDown];
if (success)
successes++;
else
failures++;
methodName = [methods nextObject];
}
NSLog (@"-- end: %d methods, %d successes, %d failures",
count, successes, failures);
}
@end

View File

@ -0,0 +1,369 @@
/* vcardtest.m - this file is part of $PROJECT_NAME_HERE$
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/Foundation.h>
#import "CardElement.h"
#import "CardGroup.h"
#import "unittest.h"
@interface subtest: unittest
{
CardElement *element;
}
@end
@implementation subtest: unittest
- (void) setUp
{
element = [CardElement new];
}
- (void) tearDown
{
[element release];
}
- (BOOL) testSimpleElementWithTag_value
{
CardElement *testElement;
NSArray *values;
testElement = [CardElement simpleElementWithTag: @"pouet"
value: @"tutu"];
testStringsEqual([testElement tag], @"pouet");
values = [testElement values];
testNotEqual(values, nil);
testEqual([values count], 1);
testStringsEqual([values objectAtIndex: 0], @"tutu");
return YES;
}
- (BOOL) testSimpleElementWithTag_singleType_value
{
CardElement *testElement;
NSArray *values, *keys;
NSDictionary *attrs;
testElement = [CardElement simpleElementWithTag: @"pouet"
singleType: @"coucou"
value: @"tutu"];
testStringsEqual([testElement tag], @"pouet");
values = [testElement values];
testNotEqual(values, nil);
testEqual([values count], 1);
testStringsEqual([values objectAtIndex: 0], @"tutu");
attrs = [testElement attributes];
keys = [attrs allKeys];
testEqual([keys count], 1);
testStringsEqual([[keys objectAtIndex: 0] uppercaseString], @"TYPE");
return YES;
}
- (BOOL) testElementWithTag_attributes_values
{
NSMutableDictionary *addedAttrs;
NSMutableArray *addedValues;
NSArray *rValues, *keys;
NSDictionary *rAttrs;
CardElement *testElement;
addedAttrs = [NSMutableDictionary new];
[addedAttrs setObject: [NSMutableArray arrayWithObjects:
@"value1", @"blabla", nil]
forKey: @"key1"];
[addedAttrs setObject: [NSMutableArray arrayWithObject: @"test2"]
forKey: @"key2"];
addedValues = [NSMutableArray new];
[addedValues addObject: @"value1"];
[addedValues addObject: @"pouetpouet2"];
testElement = [CardElement elementWithTag: @"pouet"
attributes: addedAttrs
values: addedValues];
testStringsEqual([testElement tag], @"pouet");
rValues = [testElement values];
rAttrs = [testElement attributes];
keys = [rAttrs allKeys];
testNotEqual(rValues, nil);
testNotEqual(rAttrs, nil);
testEqual([rValues count], 2);
testEqual([keys count], 2);
testNotEqual(addedValues, rValues);
testNotEqual(addedAttrs, rAttrs);
testStringsEqual([rValues objectAtIndex: 0], @"value1");
testStringsEqual([rValues objectAtIndex: 1], @"pouetpouet2");
testNotEqual([rAttrs objectForKey: @"key1"], nil);
testNotEqual([rAttrs objectForKey: @"key2"], nil);
testEqual([[rAttrs objectForKey: @"key1"] count], 2);
testEqual([[rAttrs objectForKey: @"key2"] count], 1);
testStringsEqual([[rAttrs objectForKey: @"key1"] objectAtIndex: 0],
@"value1");
testStringsEqual([[rAttrs objectForKey: @"key1"] objectAtIndex: 1],
@"blabla");
testStringsEqual([[rAttrs objectForKey: @"key2"] objectAtIndex: 0],
@"test2");
return YES;
}
- (BOOL) testAddValue
{
NSArray *values;
values = [element values];
testEqual([values count], 0);
[element addValue: @"test"];
testEqual([values count], 1);
testStringsEqual([values objectAtIndex: 0], @"test");
[element addValue: @"coucou"];
testEqual([values count], 2);
testStringsEqual([values objectAtIndex: 0], @"test");
testStringsEqual([values objectAtIndex: 1], @"coucou");
return YES;
}
- (BOOL) testAddValues
{
NSArray *values;
values = [element values];
[element addValue: @"cuicui"];
testEqual([values count], 1);
[element addValues: [NSArray arrayWithObject: @"coucou"]];
testEqual([values count], 2);
[element addValue: @"cuicui2"];
testEqual([values count], 3);
testStringsEqual([values objectAtIndex: 1], @"coucou");
testStringsEqual([values objectAtIndex: 2], @"cuicui2");
return YES;
}
- (BOOL) testAddType
{
NSMutableDictionary *attrs;
NSArray *types;
attrs = (NSMutableDictionary *) [element attributes];
testEqual([attrs objectForKey: @"TYPE"], nil);
[element addType: @"INTERNET"];
types = [attrs objectForKey: @"type"];
testNotEqual(types, nil);
testEqual([types count], 1);
testStringsEqual([types objectAtIndex: 0],
@"INTERNET");
[element addType: @"pref"];
testEqual([types count], 2);
testStringsEqual([types objectAtIndex: 0],
@"INTERNET");
testStringsEqual([types objectAtIndex: 1],
@"pref");
return YES;
}
- (BOOL) testAddAttribute_value
{
NSMutableDictionary *attrs;
attrs = (NSMutableDictionary *) [element attributes];
testEqual([attrs objectForKey: @"attr1"], nil);
[element addAttribute: @"attr1" value: @"value1"];
testNotEqual([attrs objectForKey: @"attr1"], nil);
testEqual([[attrs objectForKey: @"attr1"] count], 1);
testStringsEqual([[attrs objectForKey: @"attr1"] objectAtIndex: 0],
@"value1");
[element addAttribute: @"attr1" value: @"value2"];
testEqual([[attrs objectForKey: @"attr1"] count], 2);
testStringsEqual([[attrs objectForKey: @"attr1"] objectAtIndex: 0],
@"value1");
testStringsEqual([[attrs objectForKey: @"attr1"] objectAtIndex: 1],
@"value2");
return YES;
}
- (BOOL) testAddAttributes
{
NSMutableDictionary *attrs, *addedAttrs;
NSArray *keys;
attrs = (NSMutableDictionary *) [element attributes];
keys = [attrs allKeys];
testEqual([keys count], 0);
[attrs setObject: [NSMutableArray arrayWithObject: @"test1"]
forKey: @"key1"];
keys = [attrs allKeys];
testEqual([keys count], 1);
addedAttrs = [NSMutableDictionary new];
[addedAttrs setObject: [NSMutableArray arrayWithObject: @"test2"]
forKey: @"key2"];
[element addAttributes: addedAttrs];
[addedAttrs release];
keys = [attrs allKeys];
testEqual([keys count], 2);
testNotEqual([attrs objectForKey: @"key2"], nil);
testStringsEqual([[attrs objectForKey: @"key2"] objectAtIndex: 0],
@"test2");
testNotEqual([attrs objectForKey: @"key1"], nil);
testStringsEqual([[attrs objectForKey: @"key1"] objectAtIndex: 0],
@"test1");
testEqual([[attrs objectForKey: @"key1"] count], 1);
addedAttrs = [NSMutableDictionary new];
[addedAttrs setObject: [NSMutableArray arrayWithObject: @"test3"]
forKey: @"key1"];
[element addAttributes: addedAttrs];
[addedAttrs release];
testStringsEqual([[attrs objectForKey: @"key1"] objectAtIndex: 1],
@"test3");
return YES;
}
- (BOOL) testSetValue_To
{
NSArray *values;
values = [element values];
testEqual([values count], 0);
[element setValue: 2 to: @"coucou"];
testStringsEqual([values objectAtIndex: 0], @"");
testStringsEqual([values objectAtIndex: 1], @"");
testStringsEqual([values objectAtIndex: 2], @"coucou");
[element setValue: 0 to: @"cuicui"];
testStringsEqual([values objectAtIndex: 0], @"cuicui");
testStringsEqual([values objectAtIndex: 1], @"");
testStringsEqual([values objectAtIndex: 2], @"coucou");
return YES;
}
// BEGIN:VCALENDAR
// CALSCALE:GREGORIAN
// X-WR-TIMEZONE;VALUE=TEXT:Europe/Berlin
// PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
// X-WR-CALNAME;VALUE=TEXT:shire-cal1
// X-WR-RELCALID;VALUE=TEXT:C3CBA0E4-DBCC-11D6-A381-00039340AF4A
// VERSION:2.0
// BEGIN:VEVENT
// DTSTAMP:20021008T155243Z
// SUMMARY:work
// UID:C3CB87C0-DBCC-11D6-A381-00039340AF4A
// DTSTART;TZID=Europe/Berlin:20021009T120000
// DURATION:PT3H45M
// END:VEVENT
// BEGIN:VEVENT
// ATTENDEE;CN=Anja Berlin:mailto:anja.berlin@regiocom.net
// ATTENDEE;CN=Marcus Müller:mailto:mm@codeon.de
// DTSTAMP:20021009T211904Z
// SUMMARY:trink
// UID:C3CB8E9A-DBCC-11D6-A381-00039340AF4A
// ORGANIZER;CN=Helge Heß:mailto:helge.hess@skyrix.com
// DTSTART;TZID=Europe/Berlin:20021010T190000
// DURATION:PT45M
// BEGIN:VALARM
// TRIGGER;VALUE=DURATION:-PT15M
// ACTION:DISPLAY
// DESCRIPTION:Event reminder
// END:VALARM
// BEGIN:VALARM
// ATTACH;VALUE=URI:Ping
// TRIGGER;VALUE=DURATION:-PT15M
// ACTION:AUDIO
// END:VALARM
// END:VEVENT
// BEGIN:VEVENT
// DTSTAMP:20021008T155256Z
// SUMMARY:Zahnarzt
// DTEND;TZID=Europe/Berlin:20021009T110000
// UID:C3CB92B0-DBCC-11D6-A381-00039340AF4A
// DTSTART;TZID=Europe/Berlin:20021009T094500
// END:VEVENT
// BEGIN:VTODO
// DTSTAMP:20021009T154221Z
// SUMMARY:testjob
// UID:C3CB96C7-DBCC-11D6-A381-00039340AF4A
// DUE;TZID=Europe/Berlin:20021011T175228
// PRIORITY:5
// DTSTART;TZID=Europe/Berlin:20021008T175228
// END:VTODO
// BEGIN:VTODO
// UID:C3CB9A9F-DBCC-11D6-A381-00039340AF4A
// DTSTART;TZID=Europe/Berlin:20021010T000000
// DTSTAMP:20021009T154205Z
// SUMMARY:testjob2
// END:VTODO
// END:VCALENDAR
@end
int main (int argc, char **argv, char **env)
{
NSAutoreleasePool *pool;
subtest *test;
int rc;
pool = [[NSAutoreleasePool alloc] init];
#if LIB_FOUNDATION_LIBRARY
[NSProcessInfo initializeWithArguments:argv count:argc environment:env];
#endif
test = [subtest new];
if (test) {
NS_DURING
[test run];
NS_HANDLER
abort();
NS_ENDHANDLER;
[test release];
}
else
rc = 1;
[pool release];
return rc;
}

View File

@ -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 <Foundation/NSObject.h>
#include <SaxObjC/SaxObjC.h>
@interface vcf2xml : NSObject
{
id<NSObject,SaxXMLReader> parser;
id sax;
}
- (int)runWithArguments:(NSArray *)_args;
@end
#include "common.h"
@interface MySAXHandler : SaxDefaultHandler
{
id locator;
int indent;
NSString *lastNS;
}
- (void)indent;
@end
@implementation vcf2xml
- (id)init {
if ((self = [super init]) != nil) {
self->parser = [[[SaxXMLReaderFactory standardXMLReaderFactory]
createXMLReaderForMimeType:@"text/x-vcard"] retain];
if (parser == nil) {
fprintf(stderr, "Error: could not load a vCard SAX driver bundle!\n");
exit(2);
}
//NSLog(@"Using parser: %@", self->parser);
self->sax = [[MySAXHandler alloc] init];
[parser setContentHandler:self->sax];
[parser setErrorHandler:self->sax];
}
return self;
}
- (void)dealloc {
[self->sax release];
[self->parser release];
[super dealloc];
}
/* process files */
- (void)processFile:(NSString *)_path {
[self->parser parseFromSystemId:_path];
}
/* error handling */
- (NSException *)handleException:(NSException *)_exc onPath:(NSString *)_p {
fprintf(stderr, "Error: catched exception on path '%s': %s\n",
[_p cString], [[_exc description] cString]);
return nil;
}
/* main entry */
- (int)runWithArguments:(NSArray *)_args {
NSEnumerator *args;
NSString *arg;
/* begin processing */
args = [_args objectEnumerator];
[args nextObject]; // skip tool name ...
while ((arg = [args nextObject]) != nil) {
NSAutoreleasePool *pool2;
if ([arg hasPrefix:@"-"]) { /* consume defaults */
[args nextObject];
continue;
}
pool2 = [[NSAutoreleasePool alloc] init];
if (![arg isAbsolutePath]) {
arg = [[[NSFileManager defaultManager] currentDirectoryPath]
stringByAppendingPathComponent:arg];
}
NS_DURING
[self->parser parseFromSystemId:arg];
NS_HANDLER
[[self handleException:localException onPath:arg] raise];
NS_ENDHANDLER;
[pool2 release];
}
return 0;
}
@end /* vcf2xml */
@implementation MySAXHandler
- (void)dealloc {
[self->lastNS release];
[self->locator release];
[super dealloc];
}
/* output */
- (void)indent {
int i;
for (i = 0; i < (self->indent * 4); i++)
fputc(' ', stdout);
}
/* documents */
- (void)setDocumentLocator:(id<NSObject,SaxLocator>)_loc {
[self->locator autorelease];
self->locator = [_loc retain];
}
- (void)startDocument {
//puts("start document ..");
//self->indent++;
}
- (void)endDocument {
//self->indent--;
//puts("end document.");
}
- (void)startPrefixMapping:(NSString *)_prefix uri:(NSString *)_uri {
[self indent];
//printf("ns-map: %s=%s\n", [_prefix cString], [_uri cString]);
}
- (void)endPrefixMapping:(NSString *)_prefix {
[self indent];
//printf("ns-unmap: %s\n", [_prefix cString]);
}
- (void)startElement:(NSString *)_localName
namespace:(NSString *)_ns
rawName:(NSString *)_rawName
attributes:(id<SaxAttributes>)_attrs
{
int i, c;
[self indent];
printf("<%s", [_localName cString]);
if ([_ns length] > 0) {
if ([_ns isEqualToString:self->lastNS])
;
else {
printf(" xmlns='%s'", [_ns cString]);
ASSIGNCOPY(self->lastNS, _ns);
}
}
for (i = 0, c = [_attrs count]; i < c; i++) {
NSString *type;
NSString *ans;
ans = [_attrs uriAtIndex:i];
printf(" %s=\"%s\"",
[[_attrs nameAtIndex:i] cString],
[[_attrs valueAtIndex:i] cString]);
if (![_ns isEqualToString:ans])
printf("(ns=%s)", [ans cString]);
type = [_attrs typeAtIndex:i];
if (![type isEqualToString:@"CDATA"] && (type != nil))
printf("[%s]", [type cString]);
}
puts(">");
self->indent++;
}
- (void)endElement:(NSString *)_localName
namespace:(NSString *)_ns
rawName:(NSString *)_rawName
{
self->indent--;
[self indent];
printf("</%s>\n", [_localName cString]);
}
- (void)characters:(unichar *)_chars length:(int)_len {
NSString *str;
id tmp;
unsigned i, len;
if (_len == 0) {
[self indent];
printf("\"\"\n");
return;
}
for (i = 0; i < (unsigned)_len; i++) {
if (_chars[i] > 255) {
NSLog(@"detected large char: o%04o d%03i h%04X",
_chars[i], _chars[i], _chars[i]);
}
}
str = [NSString stringWithCharacters:_chars length:_len];
len = [str length];
tmp = [str componentsSeparatedByString:@"\n"];
str = [tmp componentsJoinedByString:@"\\n"];
tmp = [str componentsSeparatedByString:@"\r"];
str = [tmp componentsJoinedByString:@"\\r"];
[self indent];
printf("\"%s\"\n", [str cString]);
}
- (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
NSString *data;
id tmp;
data = [NSString stringWithCharacters:_chars length:_len];
tmp = [data componentsSeparatedByString:@"\n"];
data = [tmp componentsJoinedByString:@"\\n"];
tmp = [data componentsSeparatedByString:@"\r"];
data = [tmp componentsJoinedByString:@"\\r"];
[self indent];
printf("whitespace: \"%s\"\n", [data cString]);
}
- (void)processingInstruction:(NSString *)_pi data:(NSString *)_data {
[self indent];
printf("PI: '%s' '%s'\n", [_pi cString], [_data cString]);
}
#if 0
- (xmlEntityPtr)getEntity:(NSString *)_name {
NSLog(@"get entity %@", _name);
return NULL;
}
- (xmlEntityPtr)getParameterEntity:(NSString *)_name {
NSLog(@"get para entity %@", _name);
return NULL;
}
#endif
/* entities */
- (id)resolveEntityWithPublicId:(NSString *)_pubId
systemId:(NSString *)_sysId
{
[self indent];
printf("shall resolve entity with '%s' '%s'",
[_pubId cString], [_sysId cString]);
return nil;
}
/* errors */
- (void)warning:(SaxParseException *)_exception {
NSLog(@"warning(%@:%i): %@",
[[_exception userInfo] objectForKey:@"publicId"],
[[[_exception userInfo] objectForKey:@"line"] intValue],
[_exception reason]);
}
- (void)error:(SaxParseException *)_exception {
NSLog(@"error(%@:%i): %@",
[[_exception userInfo] objectForKey:@"publicId"],
[[[_exception userInfo] objectForKey:@"line"] intValue],
[_exception reason]);
}
- (void)fatalError:(SaxParseException *)_exception {
NSLog(@"fatal error(%@:%i): %@",
[[_exception userInfo] objectForKey:@"publicId"],
[[[_exception userInfo] objectForKey:@"line"] intValue],
[_exception reason]);
[_exception raise];
}
@end /* MySAXHandler */
int main(int argc, char **argv, char **env) {
NSAutoreleasePool *pool;
vcf2xml *tool;
int rc;
pool = [[NSAutoreleasePool alloc] init];
#if LIB_FOUNDATION_LIBRARY
[NSProcessInfo initializeWithArguments:argv count:argc environment:env];
#endif
if ((tool = [[vcf2xml alloc] init])) {
NS_DURING
rc = [tool runWithArguments:[[NSProcessInfo processInfo] arguments]];
NS_HANDLER
abort();
NS_ENDHANDLER;
[tool release];
}
else
rc = 1;
[pool release];
return rc;
}

View File

@ -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 <Foundation/Foundation.h>
#import <NGCards/NGVCard.h>
@interface vcsparsetest : NSObject
{
}
- (int)runWithArguments:(NSArray *)_args;
@end
@implementation vcsparsetest
- (id)init {
if ((self = [super init])) {
}
return self;
}
- (void)dealloc {
[super dealloc];
}
/* parsing */
- (id)parseFile:(NSString *)_path {
if ([_path length] == 0) return nil;
return [NGVCard parseVCardsFromSource:[NSURL fileURLWithPath:_path]];
}
- (void)printParsedObject: (NSArray *)_cards
{
NSEnumerator *cardObjects;
NGVCard *card;
cardObjects = [_cards objectEnumerator];
card = [cardObjects nextObject];
while (card)
{
NSLog (@"-------s\n%@\ne-------", [card versitString]);
card = [cardObjects nextObject];
}
#if 0
NSLog(@" subcomponents: %@", [_object subComponents]);
printf("%s", [[_object icalString] cString]);
#endif
}
/* run */
- (int)runWithArguments:(NSArray *)_args {
NSEnumerator *args;
NSString *arg;
args = [_args objectEnumerator];
[args nextObject]; // process name ...
while ((arg = [args nextObject])) {
NSAutoreleasePool *pool2;
if ([arg hasPrefix:@"-"]) { /* consume defaults */
[args nextObject];
continue;
}
pool2 = [[NSAutoreleasePool alloc] init];
{
NSArray *cards;
NS_DURING
cards = [self parseFile:arg];
NS_HANDLER
abort();
NS_ENDHANDLER;
if (!cards)
NSLog(@"could not parse file: '%@'", arg);
else
[self printParsedObject:cards];
}
[pool2 release];
}
return 0;
}
@end /* vcsparsetest */
int main(int argc, char **argv, char **env) {
NSAutoreleasePool *pool;
vcsparsetest *tool;
int rc;
pool = [[NSAutoreleasePool alloc] init];
#if LIB_FOUNDATION_LIBRARY
[NSProcessInfo initializeWithArguments:argv count:argc environment:env];
#endif
if ((tool = [[vcsparsetest alloc] init]) != nil) {
NS_DURING
rc = [tool runWithArguments:[[NSProcessInfo processInfo] arguments]];
NS_HANDLER
abort();
NS_ENDHANDLER;
[tool release];
}
else
rc = 1;
[pool release];
return rc;
}

View File

@ -0,0 +1,218 @@
/* versittest.m - this file is part of $PROJECT_NAME_HERE$
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/Foundation.h>
#import "CardElement.h"
#import "CardGroup.h"
#import "CardVersitRenderer.h"
#import "NSString+NGCards.h"
#import "unittest.h"
@interface versittest : unittest
@end
@implementation versittest
- (BOOL) testRendering
{
NSLog (@"rendering>");
CardVersitRenderer *renderer;
CardGroup *g, *g2;
CardElement *e;
g = [CardGroup groupWithTag: @"VCALENDAR"];
e = [CardElement simpleElementWithTag: @"CALSCALE"
value: @"GREGORIAN"];
[g addChild: e];
e = [CardElement simpleElementWithTag: @"X-WR-TIMEZONE"
value: @"Europe/Berlin"];
[e addAttribute: @"VALUE" value: @"TEXT"];
[g addChild: e];
e = [CardElement simpleElementWithTag: @"PRODID"
value: @"-//Apple Computer, Inc//iCal 1.0//EN"];
[g addChild: e];
e = [CardElement simpleElementWithTag: @"X-WR-CALNAME"
value: @"shire-cal1"];
[e addAttribute: @"VALUE" value: @"TEXT"];
[e setGroup: @"item1"];
[g addChild: e];
e = [CardElement simpleElementWithTag: @"X-WR-RELCALID"
value: @"C3CBA0E4-DBCC-11D6-A381-00039340AF4A"];
[e addAttribute: @"VALUE" value: @"TEXT"];
[g addChild: e];
e = [CardElement simpleElementWithTag: @"VERSION"
value: @"2.0"];
[g addChild: e];
g2 = [CardGroup groupWithTag: @"VEVENT"];
e = [CardElement simpleElementWithTag: @"DTSTAMP"
value: @"20021008T155243Z"];
[g2 addChild: e];
e = [CardElement simpleElementWithTag: @"SUMMARY"
value: @"work"];
[g2 addChild: e];
e = [CardElement simpleElementWithTag: @"UID"
value: @"C3CB87C0-DBCC-11D6-A381-00039340AF4A"];
[g2 addChild: e];
e = [CardElement simpleElementWithTag: @"DTSTART"
value: @"20021009T120000"];
[e addAttribute: @"TZID" value: @"Europe/Berlin"];
[g2 addChild: e];
e = [CardElement simpleElementWithTag: @"DURATION"
value: @"PT3H45M"];
[g2 addChild: e];
[g addChild: g2];
g2 = [CardGroup groupWithTag: @"VEVENT"];
e = [CardElement simpleElementWithTag: @"ATTENDEE"
value: @"mailto:anja.berlin@regiocom.net"];
[e addAttribute: @"CN" value: @"Anja Berlin"];
[g2 addChild: e];
e = [CardElement simpleElementWithTag: @"ATTENDEE"
value: @"mailto:mm@codeon.de"];
[e addAttribute: @"CN" value: @"Marcus Müller"];
[g2 addChild: e];
e = [CardElement simpleElementWithTag: @"DTSTAMP"
value: @"20021009T211904Z"];
[g2 addChild: e];
e = [CardElement simpleElementWithTag: @"SUMMARY"
value: @"trink"];
[g2 addChild: e];
e = [CardElement simpleElementWithTag: @"UID"
value: @"C3CB8E9A-DBCC-11D6-A381-00039340AF4A"];
[g2 addChild: e];
e = [CardElement simpleElementWithTag: @"ORGANIZER"
value: @"mailto:helge.hess@skyrix.com"];
[e addAttribute: @"CN" value: @"Helge Heß"];
[g2 addChild: e];
e = [CardElement simpleElementWithTag: @"DTSTART"
value: @"20021010T190000"];
[e addAttribute: @"TZID" value: @"Europe/Berlin"];
[g2 addChild: e];
e = [CardElement simpleElementWithTag: @"DURATION"
value: @"PT45M"];
[g2 addChild: e];
[g addChild: g2];
renderer = [CardVersitRenderer new];
NSLog (@"\n\n%@\n", [renderer render: g]);
[renderer release];
NSLog (@"<done");
return YES;
}
- (BOOL) testNSStringFoldedForVersitCards
{
NSString *shortString, *longString, *foldedString;
shortString = @"PATATE";
testStringsEqual(shortString, [shortString foldedForVersitCards]);
longString = @"blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabl"
@"a PATATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabla PA"
@"TATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE"
@"blabla PATATE blabla PATATE blabla PATATE";
foldedString = @"blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabl\r\n"
@" a PATATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabla PA\r\n"
@" TATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE blabla PATATE\r\n"
@" blabla PATATE blabla PATATE blabla PATATE";
testStringsEqual(foldedString, [longString foldedForVersitCards]);
return YES;
}
- (BOOL) testNSStringAsCardValues
{
NSString *values[5];
NSArray *array[5];
NSArray *testarray[5];
unsigned int i, count, max;
// patate,pouetpouet
values[0] = @"patate,pouetpouet";
// patate\,pouetpouet
values[1] = @"patate\\,pouetpouet";
// patate\\,pouetpouet
values[2] = @"patate\\\\,pouetpouet";
// patate\\\,pouetpouet
values[3] = @"patate\\\\\\,pouetpouet";
// patate,pouetpouet
values[4] = @"patate, pouetpouet";
testarray[0] = [NSArray arrayWithObjects: @"patate", @"pouetpouet", nil];
testarray[1] = [NSArray arrayWithObjects: @"patate,pouetpouet", nil];
// should give [ @"patate\\", @"pouetpouet" ] instead...:
testarray[2] = [NSArray arrayWithObjects: @"patate\\,pouetpouet", nil];
testarray[3] = [NSArray arrayWithObjects: @"patate\\\\,pouetpouet", nil];
testarray[4] = [NSArray arrayWithObjects: @"patate", @"pouetpouet", nil];
for (i = 0; i < (sizeof(values) / sizeof(NSString *)); i++)
{
array[i] = [values[i] asCardAttributeValues];
max = [testarray[i] count];
for (count = 0; count < max; count++)
testStringsEqual([testarray[i] objectAtIndex: count],
[array[i] objectAtIndex: count]);
}
return YES;
}
@end
int main (int argc, char **argv, char **env)
{
NSAutoreleasePool *pool;
versittest *test;
int rc;
pool = [[NSAutoreleasePool alloc] init];
#if LIB_FOUNDATION_LIBRARY
[NSProcessInfo initializeWithArguments: argv
count: argc
environment: env];
#endif
test = [versittest new];
if (test) {
NS_DURING
[test run];
NS_HANDLER
abort();
NS_ENDHANDLER;
[test release];
}
else
rc = 1;
[pool release];
return rc;
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>NGiCalTests</string>
<key>CFBundleGetInfoString</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>org.OpenGroupware.SOPE.ical.NGiCalTests</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string></string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>4.5</string>
</dict>
</plist>

View File

@ -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.

Some files were not shown because too many files have changed in this diff Show More