]> err.no Git - sope/blob - sope-ical/NGiCal/iCalCalendar.m
d0664c772eacd88b6e2bb8c9b03a10dd38781b9b
[sope] / sope-ical / NGiCal / iCalCalendar.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "iCalCalendar.h"
23 #include <SaxObjC/SaxObjC.h>
24 #include "iCalEntityObject.h"
25 #include "common.h"
26
27 @interface iCalCalendar(Privates)
28 - (void)addToEvents:(iCalEvent *)_event;
29 - (void)addToTimezones:(id)_tz;
30 - (void)addToTodos:(iCalToDo *)_todo;
31 - (void)addToJournals:(iCalJournal *)_obj;
32 - (void)addToFreeBusys:(iCalFreeBusy *)_obj;
33 @end
34
35 @implementation iCalCalendar
36
37 static id<NSObject,SaxXMLReader> parser  = nil; // THREAD
38 static SaxObjectDecoder          *sax    = nil; // THREAD
39
40 + (id<NSObject,SaxXMLReader>)iCalParser {
41   if (sax == nil) {
42     sax = [[SaxObjectDecoder alloc] initWithMappingNamed:@"NGiCal"];;
43     if (sax == nil) {
44       NSLog(@"ERROR(%s): could not create iCal SAX handler!",
45             __PRETTY_FUNCTION__);
46     }
47   }
48   if (sax != nil && parser == nil) {
49     parser =
50       [[[SaxXMLReaderFactory standardXMLReaderFactory] 
51                              createXMLReaderForMimeType:@"text/calendar"]
52                              retain];
53     if (parser == nil) {
54       NSLog(@"ERROR(%s): did not find a parser for text/calendar!",
55             __PRETTY_FUNCTION__);
56       return nil;
57     }
58     
59     [parser setContentHandler:sax];
60     [parser setErrorHandler:sax];
61   }
62   return parser;
63 }
64
65 + (iCalCalendar *)parseCalendarFromSource:(id)_src {
66   static id<NSObject,SaxXMLReader> parser;
67   id root, cal;
68   
69   if ((parser = [self iCalParser]) == nil)
70     return nil;
71   
72   [parser parseFromSource:_src];
73   root = [[sax rootObject] retain];
74   [sax reset];
75   
76   if (root == nil)
77     return nil;
78   if ([root isKindOfClass:self])
79     return [root autorelease];
80   
81   if (![root isKindOfClass:[iCalEntityObject class]]) {
82     NSLog(@"ERROR(%s): parsed object is of an unexpected class %@: %@",
83           __PRETTY_FUNCTION__, NSStringFromClass([root class]), root);
84     [root release];
85     return nil;
86   }
87   
88   /* so we just got an iCalEntityObject, wrap that manually into a cal */
89   cal = [[[self alloc] initWithEntityObject:root] autorelease];
90   [root release]; root = nil;
91   return cal;
92 }
93
94 - (id)initWithEntityObject:(iCalEntityObject *)_entityObject {
95   if ((self = [self init])) {
96     if ([_entityObject isKindOfClass:[iCalEvent class]])
97       [self addToEvents:(iCalEvent *)_entityObject];
98     else if ([_entityObject isKindOfClass:[iCalToDo class]])
99       [self addToTodos:(iCalToDo *)_entityObject];
100     else if ([_entityObject isKindOfClass:[iCalJournal class]])
101       [self addToJournals:(iCalJournal *)_entityObject];
102     else if ([_entityObject isKindOfClass:[iCalFreeBusy class]])
103       [self addToFreeBusys:(iCalFreeBusy *)_entityObject];
104     else if ([_entityObject isNotNull]) {
105       [self errorWithFormat:@"Unexpected entity object: %@", _entityObject];
106       [self release];
107       return nil;
108     }
109   }
110   return self;
111 }
112
113 - (void)dealloc {
114   [self->version   release];
115   [self->calscale  release];
116   [self->prodId    release];
117   [self->method    release];
118
119   [self->todos     release];
120   [self->events    release];
121   [self->journals  release];
122   [self->freeBusys release];
123   [self->timezones release];
124   [super dealloc];
125 }
126
127 /* NSCopying */
128
129 - (id)copyWithZone:(NSZone *)_zone {
130   iCalCalendar *new;
131   
132   new = [super copyWithZone:_zone];
133
134   ASSIGNCOPY(new->version,  self->version);
135   ASSIGNCOPY(new->calscale, self->calscale);
136   ASSIGNCOPY(new->prodId,   self->prodId);
137   ASSIGNCOPY(new->method,   self->method);
138
139   ASSIGNCOPY(new->todos,     self->todos);
140   ASSIGNCOPY(new->events,    self->events);
141   ASSIGNCOPY(new->journals,  self->journals);
142   ASSIGNCOPY(new->freeBusys, self->freeBusys);
143   ASSIGNCOPY(new->timezones, self->timezones);
144
145   return new;
146 }
147
148 /* accessors */
149
150 - (void)setCalscale:(NSString *)_value {
151   ASSIGNCOPY(self->calscale, _value);
152 }
153 - (NSString *)calscale {
154   return self->calscale;
155 }
156 - (void)setVersion:(NSString *)_value {
157   ASSIGNCOPY(self->version, _value);
158 }
159 - (NSString *)version {
160   return self->version;
161 }
162 - (void)setProdId:(NSString *)_value {
163   ASSIGNCOPY(self->prodId, _value);
164 }
165 - (NSString *)prodId {
166   return self->prodId;
167 }
168 - (void)setMethod:(NSString *)_method {
169   ASSIGNCOPY(self->method, _method);
170 }
171 - (NSString *)method {
172   return self->method;
173 }
174
175 - (void)addToEvents:(iCalEvent *)_event {
176   if (_event == nil) return;
177   if (self->events == nil)
178     self->events = [[NSMutableArray alloc] initWithCapacity:4];
179   [self->events addObject:_event];
180 }
181 - (NSArray *)events {
182   return self->events;
183 }
184
185 - (void)addToTimezones:(id)_tz {
186   NSString *tzid;
187   
188   if (_tz == nil) return;
189   if (self->timezones == nil)
190     self->timezones = [[NSMutableDictionary alloc] initWithCapacity:4];
191   
192   if ((tzid = [_tz valueForKey:@"tzid"]) == nil) {
193     [self logWithFormat:@"ERROR: missing timezone-id in timezone: %@", _tz];
194     return;
195   }
196   [self->timezones setObject:_tz forKey:tzid];
197 }
198 - (NSArray *)timezones {
199   return [self->timezones allValues];
200 }
201
202 - (void)addToTodos:(iCalToDo *)_todo {
203   if (_todo == nil) return;
204   if (self->todos == nil)
205     self->todos = [[NSMutableArray alloc] initWithCapacity:4];
206   [self->todos addObject:_todo];
207 }
208 - (NSArray *)todos {
209   return self->todos;
210 }
211
212 - (void)addToJournals:(iCalJournal *)_obj {
213   if (_obj == nil) return;
214   if (self->journals == nil)
215     self->journals = [[NSMutableArray alloc] initWithCapacity:4];
216   [self->journals addObject:_obj];
217 }
218 - (NSArray *)journals {
219   return self->journals;
220 }
221
222 - (void)addToFreeBusys:(iCalFreeBusy *)_obj {
223   if (_obj == nil) return;
224   if (self->freeBusys == nil)
225     self->freeBusys = [[NSMutableArray alloc] initWithCapacity:4];
226   [self->freeBusys addObject:_obj];
227 }
228 - (NSArray *)freeBusys {
229   return self->freeBusys;
230 }
231
232 /* collection */
233
234 - (NSArray *)allObjects {
235   NSMutableArray *ma;
236   
237   ma = [NSMutableArray arrayWithCapacity:32];
238   if (self->events)    [ma addObjectsFromArray:self->events];
239   if (self->todos)     [ma addObjectsFromArray:self->todos];
240   if (self->freeBusys) [ma addObjectsFromArray:self->freeBusys];
241   if (self->journals)  [ma addObjectsFromArray:self->journals];
242   return ma;
243 }
244 - (NSEnumerator *)objectEnumerator {
245   return [[self allObjects] objectEnumerator];
246 }
247
248 /* ical typing */
249
250 - (NSString *)entityName {
251   return @"vcalendar";
252 }
253
254 /* descriptions */
255
256 - (NSString *)description {
257   NSMutableString *ms;
258
259   ms = [NSMutableString stringWithCapacity:128];
260   [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
261
262   if (self->version)  [ms appendFormat:@" v%@",         self->version];
263   if (self->method)   [ms appendFormat:@" method=%@",   self->method];
264   if (self->prodId)   [ms appendFormat:@" product=%@",  self->prodId];
265   if (self->calscale) [ms appendFormat:@" calscale=%@", self->calscale];
266
267   if ([self->events count] > 0)
268     [ms appendFormat:@" events=%@", self->events];
269   if ([self->todos count] > 0)
270     [ms appendFormat:@" todos=%@", self->todos];
271   if ([self->freeBusys count] > 0)
272     [ms appendFormat:@" fb=%@", self->freeBusys];
273   if ([self->journals count] > 0)
274     [ms appendFormat:@" journals=%@", self->journals];
275
276   if ([self->timezones count] > 0)
277     [ms appendFormat:@" tzs=%@", [self->timezones allKeys]];
278   
279   [ms appendString:@">"];
280   return ms;
281 }
282
283 @end /* iCalCalendar */