]> err.no Git - scalable-opengroupware.org/commitdiff
git-svn-id: http://svn.opengroupware.org/SOGo/trunk@244 d1b88da0-ebda-0310-925b-ed51d...
authorhelge <helge@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Mon, 16 Aug 2004 01:46:00 +0000 (01:46 +0000)
committerhelge <helge@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Mon, 16 Aug 2004 01:46:00 +0000 (01:46 +0000)
SOGo/SoObjects/Appointments/ChangeLog
SOGo/SoObjects/Appointments/SOGoAppointmentObject.m
SOGo/SoObjects/Appointments/Version

index 1d9e3e0dac5402b77e9887c8376fcbcce0c9a154..806892590f311ba82a1259a9c15718efeacd98e3 100644 (file)
@@ -1,6 +1,9 @@
 2004-08-16  Helge Hess  <helge.hess@skyrix.com>
 
-       * 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  <helge.hess@skyrix.com>
 
index 345c51d22cf3db872036a803b8782ba49db41f6f..0c30e0898fea6ef8a26c80501e1552c37d6c2fed 100644 (file)
@@ -21,6 +21,8 @@
 // $Id$
 
 #include "SOGoAppointmentObject.h"
+#include <SOGoLogic/AgenorUserManager.h>
+#include <NGiCal/NGiCal.h>
 #include "common.h"
 
 @implementation SOGoAppointmentObject
   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 {
   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 {
      - 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 {
            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 {
index a4628e907da75903d767394c66c4f44740108726..4ae9cc8ef19a020a9044f7ebfa7f4c8be6754990 100644 (file)
@@ -1,3 +1,3 @@
 # $Id: Version,v 1.9 2004/05/19 14:30:45 helge Exp $
 
-SUBMINOR_VERSION:=7
+SUBMINOR_VERSION:=8