]> err.no Git - sope/blob - sope-ical/NGiCal/iCalDataSource.m
removed iCalSaxDriver project reference
[sope] / sope-ical / NGiCal / iCalDataSource.m
1 /*
2   Copyright (C) 2000-2003 SKYRIX Software AG
3
4   This file is part of OGo
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 // $Id$
22
23 #include "iCalDataSource.h"
24 #include "iCalObject.h"
25 #include "iCalCalendar.h"
26 #include <SaxObjC/SaxObjC.h>
27 #include "common.h"
28
29 @interface NSObject(suppressCapitalizedKeyWarning)
30 + (void)suppressCapitalizedKeyWarning;
31 @end
32
33 @implementation iCalDataSource
34
35 // THREAD
36 static id<NSObject,SaxXMLReader> parser = nil;
37 static SaxObjectDecoder *sax = nil;
38
39 - (void)_setupGlobals {
40   if (parser == nil ) {
41     SaxXMLReaderFactory *factory = 
42       [SaxXMLReaderFactory standardXMLReaderFactory];
43     parser = [[factory createXMLReaderForMimeType:@"text/calendar"] retain];
44     if (parser == nil)
45       [self logWithFormat:@"ERROR: found no SAX driver for 'text/calendar'!"];
46   }
47   if (sax == nil && parser != nil) {
48     NSBundle *bundle;
49     NSString *p;
50     
51 #if COCOA_Foundation_LIBRARY
52     /* otherwise we get warning on "X-WR-TIMEZONE" etc */
53     [NSClassFromString(@"NSKeyBinding") suppressCapitalizedKeyWarning];
54 #endif
55     
56     bundle = [NSBundle bundleForClass:[self class]];
57     if ((p = [bundle pathForResource:@"NGiCal" ofType:@"xmap"]))
58       sax = [[SaxObjectDecoder alloc] initWithMappingAtPath:p];
59     else
60       sax = [[SaxObjectDecoder alloc] initWithMappingNamed:@"NGiCal"];
61     
62     [parser setContentHandler:sax];
63     [parser setErrorHandler:sax];
64   }
65 }
66
67
68 - (id)initWithURL:(NSURL *)_url entityName:(NSString *)_ename {
69   [self _setupGlobals];
70   if ((self = [super init])) {
71     self->url        = [_url copy];
72     self->entityName = [_ename copy];
73   }
74   return self;
75 }
76 - (id)initWithPath:(NSString *)_path entityName:(NSString *)_ename {
77   NSURL *lurl;
78   
79   lurl = [[[NSURL alloc] initFileURLWithPath:_path] autorelease];
80   return [self initWithURL:lurl entityName:_ename];
81 }
82
83 - (id)initWithURL:(NSURL *)_url {
84   return [self initWithURL:_url entityName:nil];
85 }
86 - (id)initWithPath:(NSString *)_path {
87   return [self initWithPath:_path entityName:nil];
88 }
89 - (id)init {
90   return [self initWithURL:nil];
91 }
92
93 - (void)dealloc {
94   [self->fetchSpecification release];
95   [self->entityName release];
96   [self->url release];
97   [super dealloc];
98 }
99
100 /* accessors */
101
102 - (void)setFetchSpecification:(EOFetchSpecification *)_fspec {
103   if ([self->fetchSpecification isEqual:_fspec])
104     return;
105   
106   ASSIGNCOPY(self->fetchSpecification, _fspec);
107
108   [self postDataSourceChangedNotification];
109 }
110 - (EOFetchSpecification *)fetchSpecification {
111   return self->fetchSpecification;
112 }
113
114 /* fetching */
115
116 - (id)_parseCalendar {
117   id cal;
118   
119   if (parser == nil) {
120     [self logWithFormat:@"ERROR: missing iCalendar parser!"];
121     return nil;
122   }
123   if (sax == nil) {
124     [self logWithFormat:@"ERROR: missing SAX handler!"];
125     return nil;
126   }
127   
128   [parser parseFromSource:self->url];
129   cal = [sax rootObject];
130   
131   return cal;
132 }
133
134 - (NSArray *)objectsForEntityNamed:(NSString *)ename inCalendar:(id)_cal {
135   if ([ename isEqualToString:@"vevent"])
136     return [_cal events];
137   if ([ename isEqualToString:@"vtodo"])
138     return [_cal todos];
139   if ([ename isEqualToString:@"vjournal"])
140     return [_cal journals];
141   if ([ename isEqualToString:@"vfreebusy"])
142     return [_cal freeBusys];
143   
144   [self logWithFormat:@"unknown calendar entity '%@'", ename];
145   return nil;
146 }
147
148 - (NSArray *)objectsFromCalendar:(id)_cal {
149   NSString *ename;
150   
151   ename = [self->fetchSpecification entityName];
152   if ([ename length] == 0)
153     ename = self->entityName;
154
155   if ([ename length] == 0)
156     return [_cal allObjects];
157   
158   if ([_cal isKindOfClass:[NSDictionary class]]) {
159     /*
160       This happens with Mozilla Calendar which posts one vcalendar
161       entry (with method 'PUBLISH') per event.
162     */
163     NSMutableArray *ma;
164     NSArray  *calendars;
165     unsigned i, count;
166     
167     if (![[_cal objectForKey:@"tag"] isEqualToString:@"iCalendar"]) {
168       [self logWithFormat:
169               @"ERROR: calendar (entity=%@) passed in as a dictionary: %@", 
170               _cal];
171     }
172     
173     if ((calendars = [_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 */