]> err.no Git - sope/blob - sope-ical/NGiCal/iCalDataSource.m
changed KVC of vCard values to return nil on Cocoa
[sope] / sope-ical / NGiCal / iCalDataSource.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 "iCalDataSource.h"
23 #include "iCalObject.h"
24 #include "iCalCalendar.h"
25 #include <SaxObjC/SaxObjC.h>
26 #include "common.h"
27
28 @interface NSObject(suppressCapitalizedKeyWarning)
29 + (void)suppressCapitalizedKeyWarning;
30 @end
31
32 @implementation iCalDataSource
33
34 // THREAD
35 static id<NSObject,SaxXMLReader> parser = nil;
36 static SaxObjectDecoder *sax = nil;
37
38 - (void)_setupGlobals {
39   if (parser == nil ) {
40     SaxXMLReaderFactory *factory = 
41       [SaxXMLReaderFactory standardXMLReaderFactory];
42     parser = [[factory createXMLReaderForMimeType:@"text/calendar"] retain];
43     if (parser == nil)
44       [self logWithFormat:@"ERROR: found no SAX driver for 'text/calendar'!"];
45   }
46   if (sax == nil && parser != nil) {
47     NSBundle *bundle;
48     NSString *p;
49     
50 #if COCOA_Foundation_LIBRARY
51     /* otherwise we get warning on "X-WR-TIMEZONE" etc */
52     [NSClassFromString(@"NSKeyBinding") suppressCapitalizedKeyWarning];
53 #endif
54     
55     bundle = [NSBundle bundleForClass:[self class]];
56     if ((p = [bundle pathForResource:@"NGiCal" ofType:@"xmap"]))
57       sax = [[SaxObjectDecoder alloc] initWithMappingAtPath:p];
58     else
59       sax = [[SaxObjectDecoder alloc] initWithMappingNamed:@"NGiCal"];
60     
61     [parser setContentHandler:sax];
62     [parser setErrorHandler:sax];
63   }
64 }
65
66
67 - (id)initWithURL:(NSURL *)_url entityName:(NSString *)_ename {
68   [self _setupGlobals];
69   if ((self = [super init])) {
70     self->url        = [_url copy];
71     self->entityName = [_ename copy];
72   }
73   return self;
74 }
75 - (id)initWithPath:(NSString *)_path entityName:(NSString *)_ename {
76   NSURL *lurl;
77   
78   lurl = [[[NSURL alloc] initFileURLWithPath:_path] autorelease];
79   return [self initWithURL:lurl entityName:_ename];
80 }
81
82 - (id)initWithURL:(NSURL *)_url {
83   return [self initWithURL:_url entityName:nil];
84 }
85 - (id)initWithPath:(NSString *)_path {
86   return [self initWithPath:_path entityName:nil];
87 }
88 - (id)init {
89   return [self initWithURL:nil];
90 }
91
92 - (void)dealloc {
93   [self->fetchSpecification release];
94   [self->url                release];
95   [self->entityName         release];
96   [super dealloc];
97 }
98
99 /* accessors */
100
101 - (void)setFetchSpecification:(EOFetchSpecification *)_fspec {
102   if ([self->fetchSpecification isEqual:_fspec])
103     return;
104   
105   ASSIGNCOPY(self->fetchSpecification, _fspec);
106
107   [self postDataSourceChangedNotification];
108 }
109 - (EOFetchSpecification *)fetchSpecification {
110   return self->fetchSpecification;
111 }
112
113 /* fetching */
114
115 - (id)_parseCalendar {
116   id cal;
117   
118   if (parser == nil) {
119     [self logWithFormat:@"ERROR: missing iCalendar parser!"];
120     return nil;
121   }
122   if (sax == nil) {
123     [self logWithFormat:@"ERROR: missing SAX handler!"];
124     return nil;
125   }
126   
127   [parser parseFromSource:self->url];
128   cal = [sax rootObject];
129   
130   return cal;
131 }
132
133 - (NSArray *)objectsForEntityNamed:(NSString *)ename inCalendar:(id)_cal {
134   if ([ename isEqualToString:@"vevent"])
135     return [_cal events];
136   if ([ename isEqualToString:@"vtodo"])
137     return [_cal todos];
138   if ([ename isEqualToString:@"vjournal"])
139     return [_cal journals];
140   if ([ename isEqualToString:@"vfreebusy"])
141     return [_cal freeBusys];
142   
143   [self logWithFormat:@"unknown calendar entity '%@'", ename];
144   return nil;
145 }
146
147 - (NSArray *)objectsFromCalendar:(id)_cal {
148   NSString *ename;
149   
150   ename = [self->fetchSpecification entityName];
151   if ([ename length] == 0)
152     ename = self->entityName;
153
154   if ([ename length] == 0)
155     return [_cal allObjects];
156   
157   if ([_cal isKindOfClass:[NSDictionary class]]) {
158     /*
159       This happens with Mozilla Calendar which posts one vcalendar
160       entry (with method 'PUBLISH') per event.
161     */
162     NSMutableArray *ma;
163     NSArray  *calendars;
164     unsigned i, count;
165     
166     if (![[(NSDictionary *)_cal objectForKey:@"tag"] 
167            isEqualToString:@"iCalendar"]) {
168       [self logWithFormat:
169               @"ERROR: calendar (entity=%@) passed in as a dictionary: %@", 
170               _cal];
171     }
172     
173     if ((calendars=[(NSDictionary *)_cal objectForKey:@"subcomponents"])==nil)
174       return nil;
175
176     count = [calendars count];
177     ma = [NSMutableArray arrayWithCapacity:(count + 1)];
178     
179     for (i = 0; i < count; i++) {
180       NSArray *objects;
181       
182       objects = [self objectsForEntityNamed:ename 
183                       inCalendar:[calendars objectAtIndex:i]];
184       if ([objects count] == 0)
185         continue;
186       
187       [ma addObjectsFromArray:objects];
188     }
189     return ma;
190   }
191   
192   return [self objectsForEntityNamed:ename inCalendar:_cal];
193 }
194
195 - (NSArray *)fetchObjects {
196   NSAutoreleasePool *pool;
197   NSArray *result;
198   id calendar;
199
200   pool = [[NSAutoreleasePool alloc] init];
201   
202   if ((calendar = [self _parseCalendar]) == nil)
203     return nil;
204   
205   if (self->fetchSpecification == nil) {
206     result = [[self objectsFromCalendar:calendar] shallowCopy];
207   }
208   else {
209     NSMutableArray *ma;
210     NSEnumerator   *e;
211     EOQualifier *q;
212     NSArray     *sort;
213     NSArray     *objects;
214     iCalObject  *object;
215     
216     /* get objects */
217     
218     objects = [self objectsFromCalendar:calendar];
219     
220     /* first filter using qualifier */
221     
222     ma = [NSMutableArray arrayWithCapacity:[objects count]];
223     q  = [self->fetchSpecification qualifier];
224     e  = [objects objectEnumerator];
225     while ((object = [e nextObject])) {
226       if (q) {
227         if (![(id<EOQualifierEvaluation>)q evaluateWithObject:object])
228           continue;
229       }
230       
231       [ma addObject:object];
232     }
233     
234     /* now sort */
235     
236     if ((sort = [self->fetchSpecification sortOrderings]))
237       [ma sortUsingKeyOrderArray:sort];
238
239     result = [ma shallowCopy];
240   }
241   
242   [pool release];
243   
244   return [result autorelease];
245 }
246
247 @end /* iCalDataSource */