2 Copyright (C) 2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo 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
11 OGo 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.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "OCSiCalFieldExtractor.h"
24 #include <NGCards/NGCards.h>
25 #include "iCalEntityObject+OCS.h"
26 #include "iCalRepeatableEntityObject+OCS.h"
28 @implementation OCSiCalFieldExtractor
30 static OCSiCalFieldExtractor *extractor = nil;
31 static NSCalendarDate *distantFuture = nil;
32 static NSNumber *distantFutureNumber = nil;
36 static BOOL didInit = NO;
41 distantFuture = [[NSCalendarDate distantFuture] retain];
42 /* INT_MAX due to Postgres constraint */
43 distantFutureNumber = [[NSNumber numberWithUnsignedInt:INT_MAX] retain];
46 + (id) sharedICalFieldExtractor
49 extractor = [self new];
56 - (NSNumber *) numberForDate: (NSCalendarDate *) _date
58 if (_date == distantFuture)
59 return distantFutureNumber;
61 return [NSNumber numberWithUnsignedInt:[_date timeIntervalSince1970]];
64 - (NSMutableDictionary *) extractQuickFieldsFromEvent: (iCalEvent *) _event
66 NSMutableDictionary *row;
67 NSCalendarDate *startDate, *endDate;
69 NSString *uid, *title, *location, *status, *accessClass;
72 id participants, partmails;
73 NSMutableString *partstates;
81 startDate = [_event startDate];
82 endDate = [_event endDate];
84 title = [_event summary];
85 location = [_event location];
86 sequence = [_event sequence];
87 accessClass = [[_event accessClass] uppercaseString];
88 status = [[_event status] uppercaseString];
90 attendees = [_event attendees];
91 partmails = [attendees valueForKey:@"rfc822Email"];
92 partmails = [partmails componentsJoinedByString:@"\n"];
93 participants = [attendees valueForKey:@"cn"];
94 participants = [participants componentsJoinedByString:@"\n"];
98 row = [NSMutableDictionary dictionaryWithCapacity:8];
100 [row setObject: @"vevent" forKey: @"component"];
103 [row setObject:uid forKey:@"uid"];
105 [self logWithFormat:@"WARNING: could not extract a uid from event!"];
107 [row setObject:[NSNumber numberWithBool: [_event isAllDay]]
108 forKey: @"isallday"];
109 [row setObject:[NSNumber numberWithBool: [_event isRecurrent]]
111 [row setObject:[NSNumber numberWithBool: [_event isOpaque]]
112 forKey: @"isopaque"];
113 [row setObject:[NSNumber numberWithInt: [_event priorityNumber]]
114 forKey: @"priority"];
116 if ([title isNotNull]) [row setObject: title forKey:@"title"];
117 if ([location isNotNull]) [row setObject: location forKey:@"location"];
118 if ([sequence isNotNull]) [row setObject: sequence forKey:@"sequence"];
120 if ([startDate isNotNull])
121 [row setObject: [self numberForDate: startDate] forKey:@"startdate"];
122 if ([endDate isNotNull])
123 [row setObject: [self numberForDate: endDate] forKey:@"enddate"];
124 if ([_event isRecurrent]) {
125 NSCalendarDate *date;
127 date = [_event lastPossibleRecurrenceStartDate];
129 /* this could also be *nil*, but in the end it makes the fetchspecs
130 more complex - thus we set it to a "reasonable" distant future */
131 date = distantFuture;
133 [row setObject:[self numberForDate:date] forKey:@"cycleenddate"];
134 [row setObject:[_event cycleInfo] forKey:@"cycleinfo"];
137 if ([participants length] > 0)
138 [row setObject: participants forKey:@"participants"];
139 if ([partmails length] > 0)
140 [row setObject: partmails forKey:@"partmails"];
142 if ([status isNotNull]) {
145 if ([status isEqualToString:@"TENTATIVE"])
147 else if ([status isEqualToString:@"CANCELLED"])
149 [row setObject:[NSNumber numberWithInt:code] forKey:@"status"];
152 /* confirmed by default */
153 [row setObject: [NSNumber numberWithInt:1] forKey: @"status"];
156 if([accessClass isNotNull] && ![accessClass isEqualToString:@"PUBLIC"]) {
157 [row setObject:[NSNumber numberWithBool:NO] forKey:@"ispublic"];
160 [row setObject:[NSNumber numberWithBool:YES] forKey:@"ispublic"];
163 organizer = [_event organizer];
167 email = [organizer valueForKey:@"rfc822Email"];
169 [row setObject:email forKey:@"orgmail"];
172 /* construct partstates */
173 count = [attendees count];
174 partstates = [[NSMutableString alloc] initWithCapacity:count * 2];
175 for ( i = 0; i < count; i++) {
177 iCalPersonPartStat stat;
179 p = [attendees objectAtIndex:i];
180 stat = [p participationStatus];
182 [partstates appendString:@"\n"];
183 [partstates appendFormat:@"%d", stat];
185 [row setObject:partstates forKey:@"partstates"];
186 [partstates release];
190 - (NSMutableDictionary *) extractQuickFieldsFromTodo: (iCalToDo *) _task
192 NSMutableDictionary *row;
193 NSCalendarDate *startDate, *dueDate;
195 NSString *uid, *title, *location, *status, *accessClass;
198 id participants, partmails;
199 NSMutableString *partstates;
200 unsigned i, count, code;
207 startDate = [_task startDate];
208 dueDate = [_task due];
210 title = [_task summary];
211 location = [_task location];
212 sequence = [_task sequence];
213 accessClass = [[_task accessClass] uppercaseString];
214 status = [[_task status] uppercaseString];
216 attendees = [_task attendees];
217 partmails = [attendees valueForKey:@"rfc822Email"];
218 partmails = [partmails componentsJoinedByString:@"\n"];
219 participants = [attendees valueForKey:@"cn"];
220 participants = [participants componentsJoinedByString:@"\n"];
224 row = [NSMutableDictionary dictionaryWithCapacity:8];
226 [row setObject: @"vtodo" forKey: @"component"];
229 [row setObject:uid forKey:@"uid"];
231 [self logWithFormat:@"WARNING: could not extract a uid from event!"];
233 [row setObject:[NSNumber numberWithBool:[_task isRecurrent]]
235 [row setObject:[NSNumber numberWithInt:[_task priorityNumber]]
238 if ([title isNotNull]) [row setObject: title forKey:@"title"];
239 if ([location isNotNull]) [row setObject: location forKey:@"location"];
240 if ([sequence isNotNull]) [row setObject: sequence forKey:@"sequence"];
242 if ([startDate isNotNull])
243 date = [self numberForDate: startDate];
245 date = [NSNull null];
246 [row setObject: date forKey: @"startdate"];
248 if ([dueDate isNotNull])
249 date = [self numberForDate: dueDate];
251 date = [NSNull null];
252 [row setObject: date forKey: @"enddate"];
254 if ([participants length] > 0)
255 [row setObject:participants forKey:@"participants"];
256 if ([partmails length] > 0)
257 [row setObject:partmails forKey:@"partmails"];
259 if ([status isNotNull]) {
260 code = 0; /* NEEDS-ACTION */
261 if ([status isEqualToString:@"COMPLETED"])
263 else if ([status isEqualToString:@"IN-PROCESS"])
265 else if ([status isEqualToString:@"CANCELLED"])
267 [row setObject: [NSNumber numberWithInt: code] forKey:@"status"];
270 /* confirmed by default */
271 [row setObject:[NSNumber numberWithInt:1] forKey:@"status"];
274 if([accessClass isNotNull] && ![accessClass isEqualToString:@"PUBLIC"]) {
275 [row setObject:[NSNumber numberWithBool:NO] forKey:@"ispublic"];
278 [row setObject:[NSNumber numberWithBool:YES] forKey:@"ispublic"];
281 organizer = [_task organizer];
285 email = [organizer valueForKey:@"rfc822Email"];
287 [row setObject:email forKey:@"orgmail"];
290 /* construct partstates */
291 count = [attendees count];
292 partstates = [[NSMutableString alloc] initWithCapacity:count * 2];
293 for ( i = 0; i < count; i++) {
295 iCalPersonPartStat stat;
297 p = [attendees objectAtIndex:i];
298 stat = [p participationStatus];
300 [partstates appendString:@"\n"];
301 [partstates appendFormat:@"%d", stat];
303 [row setObject:partstates forKey:@"partstates"];
304 [partstates release];
308 - (CardGroup *) firstElementFromCalendar: (iCalCalendar *) ical
314 elements = [ical allObjects];
315 count = [elements count];
320 @"WARNING: given calendar contains more than one event: %@",
322 element = [elements objectAtIndex: 0];
326 [self logWithFormat:@"ERROR: given calendar contains no elements: %@", ical];
333 - (NSMutableDictionary *)extractQuickFieldsFromContent:(NSString *)_content {
334 NSAutoreleasePool *pool;
335 NSDictionary *fields;
338 if ([_content length] == 0)
341 pool = [[NSAutoreleasePool alloc] init];
342 cal = [iCalCalendar parseSingleFromSource: _content];
347 if ([cal isKindOfClass:[iCalCalendar class]])
348 cal = [self firstElementFromCalendar: cal];
350 if ([cal isKindOfClass:[iCalEvent class]])
351 fields = [[self extractQuickFieldsFromEvent:cal] retain];
352 else if ([cal isKindOfClass:[iCalToDo class]])
353 fields = [[self extractQuickFieldsFromTodo:cal] retain];
354 else if ([cal isNotNull]) {
355 [self logWithFormat:@"ERROR: unexpected iCalendar parse result: %@",
360 [self logWithFormat:@"ERROR: parsing source didn't return anything"];
364 return [fields autorelease];
367 @end /* OCSiCalFieldExtractor */