]> err.no Git - scalable-opengroupware.org/blob - SOGo/OGoContentStore/OCSiCalFieldExtractor.m
a35e7576084777a8d251f7b2ab9340dcf116bc71
[scalable-opengroupware.org] / SOGo / OGoContentStore / OCSiCalFieldExtractor.m
1 /*
2   Copyright (C) 2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
22 #include "OCSiCalFieldExtractor.h"
23 #include "common.h"
24 #include <SaxObjC/SaxObjC.h>
25 #include <NGiCal/NGiCal.h>
26 #include "iCalEntityObject+OCS.h"
27 #include "iCalRepeatableEntityObject+OCS.h"
28
29 @implementation OCSiCalFieldExtractor
30
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;
36
37 + (void)initialize {
38   static BOOL didInit = NO;
39   
40   if (didInit) return;
41   didInit = YES;
42
43   parser = [[[SaxXMLReaderFactory standardXMLReaderFactory] 
44                 createXMLReaderForMimeType:@"text/calendar"]
45                 retain];
46   if (parser == nil)
47     NSLog(@"ERROR: did not find a parser for text/calendar!");
48   sax = [[SaxObjectDecoder alloc] initWithMappingNamed:@"NGiCal"];
49   if (sax == nil)
50       NSLog(@"ERROR: could not create the iCal SAX handler!");
51   [parser setContentHandler:sax];
52   [parser setErrorHandler:sax];
53
54   distantFuture       = [[NSCalendarDate distantFuture] retain];
55   /* INT_MAX due to Postgres constraint */
56   distantFutureNumber = [[NSNumber numberWithUnsignedInt:INT_MAX] retain];
57 }
58
59 + (id)sharedICalFieldExtractor {
60   if (extractor == nil) extractor = [[self alloc] init];
61   return extractor;
62 }
63
64 - (void)dealloc {
65   [super dealloc];
66 }
67
68 /* operations */
69
70 - (NSNumber *)numberForDate:(NSCalendarDate *)_date {
71   if (_date == distantFuture)
72     return distantFutureNumber;
73   return [NSNumber numberWithUnsignedInt:[_date timeIntervalSince1970]];
74 }
75
76 - (NSMutableDictionary *)extractQuickFieldsFromEvent:(iCalEvent *)_event {
77   NSMutableDictionary *row;
78   NSCalendarDate      *startDate, *endDate;
79   NSArray             *attendees;
80   NSString            *uid, *title, *location, *status, *accessClass;
81   NSNumber            *sequence;
82   id                  organizer;
83   id                  participants, partmails;
84   NSMutableString     *partstates;
85   unsigned            i, count;
86
87   if (_event == nil)
88     return nil;
89
90   /* extract values */
91   
92   startDate    = [_event startDate];
93   endDate      = [_event endDate];
94   uid          = [_event uid];
95   title        = [_event summary];
96   location     = [_event location];
97   sequence     = [_event sequence];
98   accessClass  = [[_event accessClass] uppercaseString];
99   status       = [[_event status] uppercaseString];
100
101   attendees    = [_event attendees];
102   partmails    = [attendees valueForKey:@"rfc822Email"];
103   partmails    = [partmails componentsJoinedByString:@"\n"];
104   participants = [attendees valueForKey:@"cn"];
105   participants = [participants componentsJoinedByString:@"\n"];
106
107   /* build row */
108
109   row = [NSMutableDictionary dictionaryWithCapacity:8];
110   
111   if ([uid isNotNull]) 
112     [row setObject:uid forKey:@"uid"];
113   else
114     [self logWithFormat:@"WARNING: could not extract a uid from event!"];
115
116   [row setObject:[NSNumber numberWithBool:[_event isAllDay]]
117        forKey:@"isallday"];
118   [row setObject:[NSNumber numberWithBool:[_event isRecurrent]]
119        forKey:@"iscycle"];
120   [row setObject:[NSNumber numberWithBool:[_event isOpaque]]
121        forKey:@"isopaque"];
122   [row setObject:[NSNumber numberWithInt:[_event priorityNumber]]
123        forKey:@"priority"];
124
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"];
128   
129   if ([startDate isNotNull]) 
130     [row setObject:[self numberForDate:startDate] forKey:@"startdate"];
131   if ([endDate isNotNull]) 
132     [row setObject:[self numberForDate:endDate] forKey:@"enddate"];
133
134   if ([_event isRecurrent]) {
135     NSCalendarDate *date;
136     
137     date = [_event lastPossibleRecurrenceStartDate];
138     if (!date) {
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;
142     }
143     [row setObject:[self numberForDate:date] forKey:@"cycleenddate"];
144     [row setObject:[_event cycleInfo] forKey:@"cycleinfo"];
145   }
146   if ([participants length] > 0)
147     [row setObject:participants forKey:@"participants"];
148   if ([partmails length] > 0)
149     [row setObject:partmails forKey:@"partmails"];
150
151   if ([status isNotNull]) {
152     int code = 1;
153     
154     if ([status isEqualToString:@"TENTATIVE"])
155       code = 0;
156     else if ([status isEqualToString:@"CANCELLED"])
157       code = 2;
158     [row setObject:[NSNumber numberWithInt:code] forKey:@"status"];
159   }
160   else {
161     /* confirmed by default */
162     [row setObject:[NSNumber numberWithInt:1] forKey:@"status"];
163   }
164
165   if([accessClass isNotNull] && ![accessClass isEqualToString:@"PUBLIC"]) {
166     [row setObject:[NSNumber numberWithBool:NO] forKey:@"ispublic"];
167   }
168   else {
169     [row setObject:[NSNumber numberWithBool:YES] forKey:@"ispublic"];
170   }
171
172   organizer = [_event organizer];
173   if (organizer) {
174     NSString *email;
175     
176     email = [organizer valueForKey:@"rfc822Email"];
177     if (email)
178       [row setObject:email forKey:@"orgmail"];
179   }
180   
181   /* construct partstates */
182   count        = [attendees count];
183   partstates   = [[NSMutableString alloc] initWithCapacity:count * 2];
184   for ( i = 0; i < count; i++) {
185     iCalPerson         *p;
186     iCalPersonPartStat stat;
187     
188     p    = [attendees objectAtIndex:i];
189     stat = [p participationStatus];
190     if(i != 0)
191       [partstates appendString:@"\n"];
192     [partstates appendFormat:@"%d", stat];
193   }
194   [row setObject:partstates forKey:@"partstates"];
195   [partstates release];
196   return row;
197 }
198
199 - (NSMutableDictionary *)extractQuickFieldsFromCalendar:(iCalCalendar *)_cal {
200   NSArray *events;
201   
202   if (_cal == nil)
203     return nil;
204   
205   events = [_cal events];
206   if ([events count] == 0) {
207     [self logWithFormat:@"ERROR: given calendar contains no events: %@", _cal];
208     return nil;
209   }
210   if ([events count] > 1) {
211     [self logWithFormat:
212             @"WARNING: given calendar contains more than one event: %@",
213             _cal];
214   }
215   
216   return [self extractQuickFieldsFromEvent:[events objectAtIndex:0]];
217 }
218
219 - (NSMutableDictionary *)extractQuickFieldsFromContent:(NSString *)_content {
220   NSAutoreleasePool *pool;
221   NSDictionary *fields;
222   id cal;
223   
224   if (parser == nil || sax == nil)
225     return nil;
226   if ([_content length] == 0)
227     return nil;
228
229   pool = [[NSAutoreleasePool alloc] init];
230   
231   [parser parseFromSource:_content];
232   cal = [sax rootObject];
233   
234   fields = nil;
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: %@",
241             cal];
242   }
243   
244   [sax reset];
245
246   [pool release];
247   
248   return [fields autorelease];
249 }
250
251 @end /* OCSiCalFieldExtractor */