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 <SaxObjC/SaxObjC.h>
25 #include <NGiCal/NGiCal.h>
26 #include "iCalEntityObject+OCS.h"
27 #include "iCalRepeatableEntityObject+OCS.h"
29 @implementation OCSiCalFieldExtractor
31 static id<NSObject,SaxXMLReader> parser = nil;
32 static SaxObjectDecoder *sax = nil;
33 static OCSiCalFieldExtractor *extractor = nil;
34 static NSCalendarDate *distantFuture = nil;
35 static NSNumber *distantFutureNumber = nil;
38 static BOOL didInit = NO;
43 parser = [[[SaxXMLReaderFactory standardXMLReaderFactory]
44 createXMLReaderForMimeType:@"text/calendar"]
47 NSLog(@"ERROR: did not find a parser for text/calendar!");
48 sax = [[SaxObjectDecoder alloc] initWithMappingNamed:@"NGiCal"];
50 NSLog(@"ERROR: could not create the iCal SAX handler!");
51 [parser setContentHandler:sax];
52 [parser setErrorHandler:sax];
54 distantFuture = [[NSCalendarDate distantFuture] retain];
55 /* INT_MAX due to Postgres constraint */
56 distantFutureNumber = [[NSNumber numberWithUnsignedInt:INT_MAX] retain];
59 + (id)sharedICalFieldExtractor {
60 if (extractor == nil) extractor = [[self alloc] init];
70 - (NSNumber *)numberForDate:(NSCalendarDate *)_date {
71 if (_date == distantFuture)
72 return distantFutureNumber;
73 return [NSNumber numberWithUnsignedInt:[_date timeIntervalSince1970]];
76 - (NSMutableDictionary *)extractQuickFieldsFromEvent:(iCalEvent *)_event {
77 NSMutableDictionary *row;
78 NSCalendarDate *startDate, *endDate;
80 NSString *uid, *title, *location, *status, *accessClass;
83 id participants, partmails;
84 NSMutableString *partstates;
92 startDate = [_event startDate];
93 endDate = [_event endDate];
95 title = [_event summary];
96 location = [_event location];
97 sequence = [_event sequence];
98 accessClass = [[_event accessClass] uppercaseString];
99 status = [[_event status] uppercaseString];
101 attendees = [_event attendees];
102 partmails = [attendees valueForKey:@"rfc822Email"];
103 partmails = [partmails componentsJoinedByString:@"\n"];
104 participants = [attendees valueForKey:@"cn"];
105 participants = [participants componentsJoinedByString:@"\n"];
109 row = [NSMutableDictionary dictionaryWithCapacity:8];
112 [row setObject:uid forKey:@"uid"];
114 [self logWithFormat:@"WARNING: could not extract a uid from event!"];
116 [row setObject:[NSNumber numberWithBool:[_event isAllDay]]
118 [row setObject:[NSNumber numberWithBool:[_event isRecurrent]]
120 [row setObject:[NSNumber numberWithBool:[_event isOpaque]]
122 [row setObject:[NSNumber numberWithInt:[_event priorityNumber]]
125 if ([title isNotNull]) [row setObject:title forKey:@"title"];
126 if ([location isNotNull]) [row setObject:location forKey:@"location"];
127 if ([sequence isNotNull]) [row setObject:sequence forKey:@"sequence"];
129 if ([startDate isNotNull])
130 [row setObject:[self numberForDate:startDate] forKey:@"startdate"];
131 if ([endDate isNotNull])
132 [row setObject:[self numberForDate:endDate] forKey:@"enddate"];
134 if ([_event isRecurrent]) {
135 NSCalendarDate *date;
137 date = [_event lastPossibleRecurrenceStartDate];
139 /* this could also be *nil*, but in the end it makes the fetchspecs
140 more complex - thus we set it to a "reasonable" distant future */
141 date = distantFuture;
143 [row setObject:[self numberForDate:date] forKey:@"cycleenddate"];
144 [row setObject:[_event cycleInfo] forKey:@"cycleinfo"];
146 if ([participants length] > 0)
147 [row setObject:participants forKey:@"participants"];
148 if ([partmails length] > 0)
149 [row setObject:partmails forKey:@"partmails"];
151 if ([status isNotNull]) {
154 if ([status isEqualToString:@"TENTATIVE"])
156 else if ([status isEqualToString:@"CANCELLED"])
158 [row setObject:[NSNumber numberWithInt:code] forKey:@"status"];
161 /* confirmed by default */
162 [row setObject:[NSNumber numberWithInt:1] forKey:@"status"];
165 if([accessClass isNotNull] && ![accessClass isEqualToString:@"PUBLIC"]) {
166 [row setObject:[NSNumber numberWithBool:NO] forKey:@"ispublic"];
169 [row setObject:[NSNumber numberWithBool:YES] forKey:@"ispublic"];
172 organizer = [_event organizer];
176 email = [organizer valueForKey:@"rfc822Email"];
178 [row setObject:email forKey:@"orgmail"];
181 /* construct partstates */
182 count = [attendees count];
183 partstates = [[NSMutableString alloc] initWithCapacity:count * 2];
184 for ( i = 0; i < count; i++) {
186 iCalPersonPartStat stat;
188 p = [attendees objectAtIndex:i];
189 stat = [p participationStatus];
191 [partstates appendString:@"\n"];
192 [partstates appendFormat:@"%d", stat];
194 [row setObject:partstates forKey:@"partstates"];
195 [partstates release];
199 - (NSMutableDictionary *)extractQuickFieldsFromCalendar:(iCalCalendar *)_cal {
205 events = [_cal events];
206 if ([events count] == 0) {
207 [self logWithFormat:@"ERROR: given calendar contains no events: %@", _cal];
210 if ([events count] > 1) {
212 @"WARNING: given calendar contains more than one event: %@",
216 return [self extractQuickFieldsFromEvent:[events objectAtIndex:0]];
219 - (NSMutableDictionary *)extractQuickFieldsFromContent:(NSString *)_content {
220 NSAutoreleasePool *pool;
221 NSDictionary *fields;
224 if (parser == nil || sax == nil)
226 if ([_content length] == 0)
229 pool = [[NSAutoreleasePool alloc] init];
231 [parser parseFromSource:_content];
232 cal = [sax rootObject];
235 if ([cal isKindOfClass:[iCalEvent class]])
236 fields = [[self extractQuickFieldsFromEvent:cal] retain];
237 else if ([cal isKindOfClass:[iCalCalendar class]])
238 fields = [[self extractQuickFieldsFromCalendar:cal] retain];
239 else if ([cal isNotNull]) {
240 [self logWithFormat:@"ERROR: unexpected iCalendar parse result: %@",
248 return [fields autorelease];
251 @end /* OCSiCalFieldExtractor */