]> err.no Git - sope/blob - sope-appserver/samples/iCalPortal/iCalPortalUser.m
generate RSS from display group
[sope] / sope-appserver / samples / iCalPortal / iCalPortalUser.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 "iCalPortalUser.h"
23 #include "iCalPortalDatabase.h"
24 #include "iCalPortalCalendar.h"
25 #include "common.h"
26
27 @implementation iCalPortalUser
28
29 - (id)initWithDatabase:(iCalPortalDatabase *)_db {
30   if (_db == nil) {
31     [self release];
32     return nil;
33   }
34   if ((self = [super init])) {
35     self->database = [_db retain];
36
37     if ((self->fileManager = [[_db fileManager] retain]) == nil) {
38       [self release];
39       return nil;
40     }
41   }
42   return self;
43 }
44
45 - (id)initWithPath:(NSString *)_path
46   login:(NSString *)_login
47   database:(iCalPortalDatabase *)_db;
48 {
49   if ((self = [self initWithDatabase:_db])) {
50     self->path  = [_path copy];
51     self->login = [_login copy];
52
53     if (self->path) {
54       if (![self read]) {
55         [self release];
56         return nil;
57       }
58     }
59   }
60   return self;
61 }
62
63 - (id)init {
64   return [self initWithDatabase:nil];
65 }
66
67 - (void)dealloc {
68   [self->firstName    release];
69   [self->lastName     release];
70   [self->street       release];
71   [self->city         release];
72   [self->email        release];
73   [self->address      release];
74   [self->country      release];
75   [self->phone        release];
76   [self->state        release];
77   [self->zip          release];
78   [self->wantIcalNews   release];
79   [self->wantSkyrixNews release];
80   
81   [self->login       release];
82   [self->fileManager release];
83   [self->database    release];
84   [self->path        release];
85   [super dealloc];
86 }
87
88 /* accessors */
89
90 - (iCalPortalDatabase *)database {
91   return self->database;
92 }
93
94 - (void)setFirstName:(NSString *)_value {
95   ASSIGN(self->firstName, _value);
96 }
97 - (NSString *)firstName {
98   return self->firstName;
99 }
100
101 - (void)setLastName:(NSString *)_value {
102   ASSIGN(self->lastName, _value);
103 }
104 - (NSString *)lastName {
105   return self->lastName;
106 }
107
108 - (void)setStreet:(NSString *)_value {
109   ASSIGN(self->street, _value);
110 }
111 - (NSString *)street {
112   return self->street;
113 }
114
115 - (void)setCity:(NSString *)_value {
116   ASSIGN(self->city, _value);
117 }
118 - (NSString *)city {
119   return self->city;
120 }
121
122 - (void)setEmail:(NSString *)_value {
123   ASSIGN(self->email, _value);
124 }
125 - (NSString *)email {
126   return self->email;
127 }
128
129 - (void)setLogin:(NSString *)_login {
130   /* do not allow login change via KVC ! ... */
131 }
132 - (NSString *)login {
133   return self->login;
134 }
135
136 - (void)setAddress:(NSString *)_value {
137   ASSIGN(self->address, _value);
138 }
139 - (NSString *)address {
140   return self->address;
141 }
142 - (void)setCountry:(NSString *)_value {
143   ASSIGN(self->country, _value);
144 }
145 - (NSString *)country {
146   return self->country;
147 }
148 - (void)setPhone:(NSString *)_value {
149   ASSIGN(self->phone, _value);
150 }
151 - (NSString *)phone {
152   return self->phone;
153 }
154 - (void)setState:(NSString *)_value {
155   ASSIGN(self->state, _value);
156 }
157 - (NSString *)state {
158   return self->state;
159 }
160 - (void)setZip:(NSString *)_value {
161   ASSIGN(self->zip, _value);
162 }
163 - (NSString *)zip {
164   return self->zip;
165 }
166
167 - (void)setWantIcalNews:(NSString *)_value {
168   ASSIGN(self->wantIcalNews, _value);
169 }
170 - (NSString *)wantIcalNews {
171   return self->wantIcalNews;
172 }
173 - (void)setWantSkyrixNews:(NSString *)_value {
174   ASSIGN(self->wantSkyrixNews, _value);
175 }
176 - (NSString *)wantSkyrixNews {
177   return self->wantSkyrixNews;
178 }
179
180 /* do not store password in process ! ... */
181
182 - (void)setPassword:(NSString *)_value {
183 }
184 - (NSString *)password {
185   return nil;
186 }
187 - (void)setCryptedPassword:(NSString *)_value {
188 }
189 - (NSString *)cryptedPassword {
190   return nil;
191 }
192
193 /* load/store */
194
195 - (NSDictionary *)accountDictionary {
196   NSDictionary *d;
197   NSString     *p;
198   
199   if ([self->path length] < 4) {
200     [self logWithFormat:@"tried to read an account which has no path ..."];
201     return nil;
202   }
203   
204   p = [self->path stringByAppendingPathComponent:@".account.plist"];
205   
206   if ((d = [NSDictionary dictionaryWithContentsOfFile:p]) == nil) {
207     [self logWithFormat:@"couldn't load dictionary of account (%@) ...", p];
208     return nil;
209   }
210   
211   return d;
212 }
213
214 - (BOOL)read {
215   NSDictionary *d;
216   
217   if ((d = [self accountDictionary]) == nil)
218     return NO;
219   
220   [self takeValuesFromDictionary:d];
221   return YES;
222 }
223
224 - (BOOL)write {
225   return NO;
226 }
227
228 /* password checking */
229
230 - (BOOL)authenticate:(NSString *)_pwd {
231   NSDictionary *d;
232   NSString *tmp;
233   
234   if ([_pwd length] < 4) 
235     return NO;
236   
237   if ((d = [self accountDictionary]) == nil)
238     return NO;
239   
240   if ((tmp = [d objectForKey:@"cryptedPassword"]))
241     return [_pwd compareWithCryptedString:tmp];
242   
243   if ((tmp = [d objectForKey:@"password"])) {
244     if ([tmp isEqualToString:_pwd]) {
245       [self logWithFormat:@"authenticated account."];
246       return YES;
247     }
248     [self logWithFormat:@"got invalid password for account"];
249     return NO;
250   }
251   
252   return NO;
253 }
254
255 /* calendars */
256
257 - (BOOL)containsUnsafeChars:(NSString *)_path {
258   /* check for dangerous stuff ... */
259   NSRange r;
260
261   if ([_path hasPrefix:@"."]) return YES;
262   
263   r = [_path rangeOfString:@".."];
264   if (r.length > 0) return YES;
265   r = [_path rangeOfString:@"/"];
266   if (r.length > 0) return YES;
267   r = [_path rangeOfString:@"~"];
268   if (r.length > 0) return YES;
269   r = [_path rangeOfString:@"\\"];
270   if (r.length > 0) return YES;
271
272   return NO;
273 }
274
275 - (NSString *)cleanupCalendarPath:(NSString *)_path {
276   static NSArray *validExts = nil;
277   NSString *calName;
278   NSString *ext;
279   
280   if (validExts == nil) {
281     validExts = [[NSArray alloc] initWithObjects:
282                                    @"ics", @"vfb", @"ifb",
283                                    @"ical", @"cal", nil];
284   }
285   
286   if ((calName = [_path lastPathComponent]) == nil)
287     return nil;
288   
289   ext = [calName pathExtension]; 
290   
291   if ([ext length] == 0) {
292     calName = [calName stringByAppendingPathComponent:@"ics"];
293   }
294   else if (![validExts containsObject:ext]) {
295     [self logWithFormat:@"invalid calendar extension '%@': %@", ext, _path];
296     return nil;
297   }
298   
299   if ([self containsUnsafeChars:calName])
300     return nil;
301   
302   return [self->path stringByAppendingPathComponent:calName];
303 }
304
305 - (NSException *)invalidPathException:(NSString *)_path {
306   return [NSException exceptionWithName:@"InvalidCalendarPath"
307                       reason:@"got an invalid calendar path ..."
308                       userInfo:nil];
309 }
310
311 - (iCalPortalCalendar *)calendarAtPath:(NSString *)_path {
312   NSString *calpath;
313   BOOL     isDir;
314   iCalPortalCalendar *cal;
315   
316   if ((calpath = [self cleanupCalendarPath:_path]) == nil)
317     return nil;
318   
319   if (![self->fileManager fileExistsAtPath:calpath isDirectory:&isDir]) {
320     [self debugWithFormat:@"  cal '%@' does not exist ...", _path];
321     return nil;
322   }
323   if (isDir) {
324     [self logWithFormat:@"  calpath is a directory: %@ !", calpath];
325     return nil;
326   }
327   
328   cal = [[iCalPortalCalendar alloc] initWithUser:self path:calpath];
329   if (cal == nil) return nil;
330   
331   return [cal autorelease];
332 }
333 - (EODataSource *)dataSourceAtPath:(NSString *)_path {
334   iCalPortalCalendar *cal;
335   
336   if ((cal = [self calendarAtPath:_path]) == nil)
337     return nil;
338   return [cal dataSource];
339 }
340
341 - (NSException *)deleteCalendarWithPath:(NSString *)_path {
342   NSString *calpath;
343   BOOL isDir;
344   
345   if ((calpath = [self cleanupCalendarPath:_path]) == nil)
346     return [self invalidPathException:_path];
347   
348   [self debugWithFormat:@"delete calendar: %@", calpath];
349   
350   if (![self->fileManager fileExistsAtPath:calpath isDirectory:&isDir]) {
351     [self debugWithFormat:@"  cal does not exist ..."];
352     return nil;
353   }
354   if (isDir) {
355     [self logWithFormat:@"  calpath to be deleted is a directory: %@ !",
356             calpath];
357     return nil;
358   }
359   
360   /* go on, delete ... */
361   if (![self->fileManager removeFileAtPath:calpath handler:nil]) {
362     [self logWithFormat:@"  failed to delete calendar %@", path];
363     return [NSException exceptionWithName:@"DeleteError"
364                         reason:@"reason unknown"
365                         userInfo:nil];
366   }
367   
368   return nil;
369 }
370
371 - (NSException *)writeICalendarData:(NSData *)_data toCalendar:(NSString *)_path{
372   NSString *calpath;
373   
374   if ((calpath = [self cleanupCalendarPath:_path]) == nil)
375     return [self invalidPathException:_path];
376   
377   [self debugWithFormat:@"upload calendar data: %@, size %i", 
378           calpath, [_data length]];
379
380   if (![_data writeToFile:calpath atomically:YES]) {
381     [self logWithFormat:@"  failed to write calendar of size %i to path %@",
382             [_data length], calpath];
383     return [NSException exceptionWithName:@"WriteError"
384                         reason:@"reason unknown"
385                         userInfo:nil];
386   }
387   
388   return nil;
389 }
390
391 - (NSArray *)calendarNames {
392   NSAutoreleasePool *pool;
393   NSEnumerator      *e;
394   NSString          *filename;
395   NSMutableArray    *md = nil;
396   
397   e = [[self->fileManager directoryContentsAtPath:self->path]
398         objectEnumerator];
399
400   pool = [[NSAutoreleasePool alloc] init];
401   
402   while ((filename = [e nextObject])) {
403     iCalPortalCalendar *cal;
404     
405     if ([self containsUnsafeChars:filename]) continue;
406     
407     if ((cal = [self calendarAtPath:filename]) == nil)
408       continue;
409     
410     if (md == nil)
411       md = [[NSMutableArray alloc] initWithCapacity:16];
412     
413     [md addObject:filename];
414   }
415   
416   [md sortUsingSelector:@selector(compare:)];
417   [pool release];
418   
419   return [md autorelease];
420 }
421 - (NSDictionary *)calendars {
422   NSEnumerator        *e;
423   NSString            *filename;
424   NSMutableDictionary *md = nil;
425   
426   e = [[self->fileManager directoryContentsAtPath:self->path]
427         objectEnumerator];
428   
429   while ((filename = [e nextObject])) {
430     iCalPortalCalendar *cal;
431     
432     if ([self containsUnsafeChars:filename]) continue;
433     
434     if ((cal = [self calendarAtPath:filename]) == nil)
435       continue;
436     
437     if (md == nil)
438       md = [[NSMutableDictionary alloc] init];
439
440     [md setObject:cal forKey:filename];
441   }
442   return md;
443 }
444
445 /* logging */
446
447 - (BOOL)isDebuggingEnabled {
448   return YES;
449 }
450 - (NSString *)loggingPrefix {
451   return [NSString stringWithFormat:@"[user:%@]", 
452                      self->login ? self->login : @"<new>"];
453 }
454
455 - (NSString *)description {
456   NSMutableString *s;
457   
458   s = [NSMutableString stringWithCapacity:128];
459   [s appendFormat:@"<0x%08X[%@]: ", self, NSStringFromClass([self class])];
460   [s appendFormat:@" login=%@", self->login];
461   [s appendFormat:@" path=%@",  self->path];
462   [s appendString:@">"];
463   
464   return s;
465 }
466
467 @end /* iCalPortalUser */