From: helge Date: Mon, 16 Aug 2004 01:46:00 +0000 (+0000) Subject: git-svn-id: http://svn.opengroupware.org/SOGo/trunk@244 d1b88da0-ebda-0310-925b-ed51d... X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2bb250cd8720e0f3a6aeb0260ce494b2db331bcf;p=scalable-opengroupware.org git-svn-id: http://svn.opengroupware.org/SOGo/trunk@244 d1b88da0-ebda-0310-925b-ed51d893ca5b --- diff --git a/SOGo/SoObjects/Appointments/ChangeLog b/SOGo/SoObjects/Appointments/ChangeLog index 1d9e3e0d..80689259 100644 --- a/SOGo/SoObjects/Appointments/ChangeLog +++ b/SOGo/SoObjects/Appointments/ChangeLog @@ -1,6 +1,9 @@ 2004-08-16 Helge Hess - * SOGoAppointmentObject.m: added new multi folder methods (v0.9.7) + * SOGoAppointmentObject.m: finished multi folder storage methods + (v0.9.8) + + * SOGoAppointmentObject.m: added multi folder storage methods (v0.9.7) 2004-08-14 Helge Hess diff --git a/SOGo/SoObjects/Appointments/SOGoAppointmentObject.m b/SOGo/SoObjects/Appointments/SOGoAppointmentObject.m index 345c51d2..0c30e089 100644 --- a/SOGo/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SOGo/SoObjects/Appointments/SOGoAppointmentObject.m @@ -21,6 +21,8 @@ // $Id$ #include "SOGoAppointmentObject.h" +#include +#include #include "common.h" @implementation SOGoAppointmentObject @@ -36,6 +38,63 @@ return [self contentAsString]; } +/* iCal handling */ + +- (NSArray *)attendeeUIDsFromAppointment:(SOGoAppointment *)_apt { + AgenorUserManager *um; + NSMutableArray *uids; + NSArray *attendees; + unsigned i, count; + NSString *email, *uid; + + if (![_apt isNotNull]) + return nil; + + if ((attendees = [_apt attendees]) == nil) + return nil; + count = [attendees count]; + uids = [NSMutableArray arrayWithCapacity:count + 1]; + + um = [AgenorUserManager sharedUserManager]; + + /* add organizer */ + + email = [[_apt organizer] email]; + if ([email isNotNull]) { + uid = [um getUIDForEmail:email]; + if ([uid isNotNull]) { + if ([uid hasPrefix:@"mailto:"]) + uid = [uid substringFromIndex:7]; + [uids addObject:uid]; + } + else + [self logWithFormat:@"Note: got no uid for organizer: '%@'", email]; + } + + /* add attendees */ + + for (i = 0; i < count; i++) { + iCalPerson *person; + + person = [attendees objectAtIndex:i]; + email = [person email]; + if (![email isNotNull]) continue; + + uid = [um getUIDForEmail:email]; + if (![uid isNotNull]) { + [self logWithFormat:@"Note: got no uid for email: '%@'", email]; + continue; + } + if ([uid hasPrefix:@"mailto:"]) + uid = [uid substringFromIndex:7]; + + if (![uids containsObject:uid]) + [uids addObject:uid]; + } + + return uids; +} + /* raw saving */ - (NSException *)primarySaveContentString:(NSString *)_iCalString { @@ -45,6 +104,127 @@ return [super delete]; } +/* folder management */ + +- (id)_primaryLookupFolderForUID:(NSString *)_uid inContext:(id)_ctx { + // TODO: DUP to SOGoGroupFolder + NSException *error = nil; + NSArray *path; + id ctx, result; + + if (_ctx == nil) _ctx = [[WOApplication application] context]; + + /* create subcontext, so that we don't destroy our environment */ + + if ((ctx = [_ctx createSubContext]) == nil) { + [self logWithFormat:@"ERROR: could not create SOPE subcontext!"]; + return nil; + } + + /* build path */ + + path = _uid != nil ? [NSArray arrayWithObjects:&_uid count:1] : nil; + + /* traverse path */ + + result = [[ctx application] traversePathArray:path inContext:ctx + error:&error acquire:NO]; + if (error != nil) { + [self logWithFormat:@"ERROR: folder lookup failed (uid=%@): %@", + _uid, error]; + return nil; + } + + [self debugWithFormat:@"Note: got folder for uid %@ path %@: %@", + _uid, [path componentsJoinedByString:@"=>"], result]; + return result; +} +- (NSArray *)lookupCalendarFoldersForUIDs:(NSArray *)_uids inContext:(id)_ctx { + NSMutableArray *folders; + NSEnumerator *e; + NSString *uid; + + if ([_uids count] == 0) return nil; + folders = [NSMutableArray arrayWithCapacity:16]; + e = [_uids objectEnumerator]; + while ((uid = [e nextObject])) { + id folder; + + folder = [self _primaryLookupFolderForUID:uid inContext:nil]; + folder = [folder lookupName:@"Calendar" inContext:nil acquire:NO]; + if (![folder isNotNull]) { + [self logWithFormat:@"Note: did not find folder for uid: '%@'", uid]; + continue; + } + + [folders addObject:folder]; + } + return folders; +} + +/* store in all the other folders */ + +- (NSException *)saveContentString:(NSString *)_iCal inUIDs:(NSArray *)_uids { + NSEnumerator *e; + id folder; + NSException *allErrors = nil; + id ctx; + + ctx = [[WOApplication application] context]; + + e = [[self lookupCalendarFoldersForUIDs:_uids inContext:ctx] + objectEnumerator]; + while ((folder = [e nextObject])) { + NSException *error; + SOGoAppointmentObject *apt; + + apt = [folder lookupName:[self nameInContainer] inContext:ctx + acquire:NO]; + if (![apt isNotNull]) { + [self logWithFormat:@"Note: did not find '%@' in folder: %@", + [self nameInContainer], folder]; + continue; + } + + if ((error = [apt primarySaveContentString:_iCal]) != nil) { + [self logWithFormat:@"Note: failed to save iCal in folder: %@", folder]; + // TODO: make compound + allErrors = error; + } + } + return allErrors; +} +- (NSException *)deleteInUIDs:(NSArray *)_uids { + NSEnumerator *e; + id folder; + NSException *allErrors = nil; + id ctx; + + ctx = [[WOApplication application] context]; + + e = [[self lookupCalendarFoldersForUIDs:_uids inContext:ctx] + objectEnumerator]; + while ((folder = [e nextObject])) { + NSException *error; + SOGoAppointmentObject *apt; + + apt = [folder lookupName:[self nameInContainer] inContext:ctx + acquire:NO]; + if (![apt isNotNull]) { + [self logWithFormat:@"Note: did not find '%@' in folder: %@", + [self nameInContainer], folder]; + continue; + } + + if ((error = [apt primaryDelete]) != nil) { + [self logWithFormat:@"Note: failed to delete in folder: %@", folder]; + // TODO: make compound + allErrors = error; + } + } + return allErrors; +} + /* "iCal multifolder saves" */ - (NSException *)saveContentString:(NSString *)_iCal baseSequence:(int)_v { @@ -64,8 +244,73 @@ - delete in removed folders - send iMIP mail for all folders not found */ -#warning TODO: implement proper "multi-saves" - return [self primarySaveContentString:_iCal]; + SOGoAppointment *oldApt, *newApt; + NSString *oldContent; + NSArray *oldUIDs, *newUIDs; + NSMutableArray *storeUIDs, *removedUIDs; + unsigned i, count; + NSException *storeError, *delError; + + /* handle old content */ + + oldContent = [self iCalString]; /* if nil, this is a new appointment */ + oldApt = + [[[SOGoAppointment alloc] initWithICalString:oldContent] autorelease]; + + /* compare sequence if requested */ + + if (_v != 0) { + // TODO + } + + oldUIDs = [self attendeeUIDsFromAppointment:oldApt]; + + /* handle new content */ + + newApt = [[[SOGoAppointment alloc] initWithICalString:_iCal] autorelease]; + newUIDs = [self attendeeUIDsFromAppointment:newApt]; + + /* diff */ + + count = [oldUIDs count]; + removedUIDs = [NSMutableArray arrayWithCapacity:count]; + storeUIDs = [NSMutableArray arrayWithCapacity:count]; + for (i = 0; i < count; i++) { + NSString *uid; + + uid = [oldUIDs objectAtIndex:i]; + if ([newUIDs containsObject:uid]) + [storeUIDs addObject:uid]; /* old ID is still available */ + else + [removedUIDs addObject:uid]; /* old ID is not available anymore */ + } + count = [newUIDs count]; + for (i = 0; i < count; i++) { + NSString *uid; + + uid = [newUIDs objectAtIndex:i]; + if ([storeUIDs containsObject:uid]) /* old ID is still available */ + continue; + if ([removedUIDs containsObject:uid]) /* old ID is not available anymore */ + continue; + + /* new ID which is not part of the old set => store a new */ + [storeUIDs addObject:uid]; + } + + [self debugWithFormat:@"store: %@", storeUIDs]; + [self debugWithFormat:@"remove: %@", removedUIDs]; + + /* perform */ + + storeError = [self saveContentString:_iCal inUIDs:storeUIDs]; + delError = [self deleteInUIDs:removedUIDs]; + + // TODO: make compound + if (storeError) return storeError; + if (delError) return delError; + + return nil; } - (NSException *)deleteWithBaseSequence:(int)_v { @@ -74,9 +319,35 @@ for all external accounts. Delete is basically identical to save with all attendees and the organizer being deleted. + + Steps: + - fetch stored content + - parse old content + - check if sequence matches (or if 0=ignore) + - extract old attendee list + organizer (make unique) + - delete in removed folders + - send iMIP mail for all folders not found */ -#warning TODO: implement proper "multi-saves" - return [self primaryDelete]; + SOGoAppointment *apt; + NSString *econtent; + NSArray *removedUIDs; + + /* load existing content */ + + econtent = [self iCalString]; /* if nil, this is a new appointment */ + apt = [[[SOGoAppointment alloc] initWithICalString:econtent] autorelease]; + + /* compare sequence if requested */ + + if (_v != 0) { + // TODO + } + + removedUIDs = [self attendeeUIDsFromAppointment:apt]; + + /* perform */ + + return [self deleteInUIDs:removedUIDs]; } - (NSException *)saveContentString:(NSString *)_iCalString { diff --git a/SOGo/SoObjects/Appointments/Version b/SOGo/SoObjects/Appointments/Version index a4628e90..4ae9cc8e 100644 --- a/SOGo/SoObjects/Appointments/Version +++ b/SOGo/SoObjects/Appointments/Version @@ -1,3 +1,3 @@ # $Id: Version,v 1.9 2004/05/19 14:30:45 helge Exp $ -SUBMINOR_VERSION:=7 +SUBMINOR_VERSION:=8