#import <Foundation/NSCalendarDate.h>
#import <NGObjWeb/NSException+HTTP.h>
+#import <NGObjWeb/WOContext.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGCards/iCalCalendar.h>
#import <NGCards/iCalPerson.h>
#import <SoObjects/SOGo/LDAPUserManager.h>
+#import <SoObjects/SOGo/NSArray+Utilities.h>
#import <SoObjects/SOGo/SOGoObject.h>
#import <SoObjects/SOGo/SOGoPermissions.h>
+#import <SoObjects/SOGo/WORequest+SOGo.h>
#import "NSArray+Appointments.h"
+#import "SOGoAppointmentFolder.h"
+
#import "SOGoAppointmentObject.h"
@implementation SOGoAppointmentObject
return uids;
}
-/* folder management */
-
-- (id)lookupHomeFolderForUID:(NSString *)_uid inContext:(id)_ctx {
- // TODO: what does this do? lookup the home of the organizer?
- return [[self container] lookupHomeFolderForUID:_uid inContext:_ctx];
-}
-- (NSArray *)lookupCalendarFoldersForUIDs:(NSArray *)_uids inContext:(id)_ctx {
- return [[self container] lookupCalendarFoldersForUIDs:_uids inContext:_ctx];
-}
-
/* store in all the other folders */
- (NSException *) saveContentString: (NSString *) _iCal
NSEnumerator *e;
id folder;
NSException *allErrors = nil;
-
- e = [[self lookupCalendarFoldersForUIDs:_uids inContext: context]
- objectEnumerator];
- while ((folder = [e nextObject]) != nil) {
- NSException *error;
- SOGoAppointmentObject *apt;
-
- if (![folder isNotNull]) /* no folder was found for given UID */
- continue;
-
- apt = [folder lookupName: [self nameInContainer] inContext: context
- acquire: NO];
- if ([apt isKindOfClass: [NSException class]])
- {
- [self logWithFormat:@"Note: an exception occured finding '%@' in folder: %@",
- [self nameInContainer], folder];
- [self logWithFormat:@"the exception reason was: %@",
- [(NSException *) apt reason]];
- continue;
- }
+ NSException *error;
+ SOGoAppointmentObject *apt;
- if (![apt isNotNull]) {
- [self logWithFormat:@"Note: did not find '%@' in folder: %@",
- [self nameInContainer], folder];
- continue;
- }
- if ([apt isKindOfClass: [NSException class]]) {
- [self logWithFormat:@"Exception: %@", [(NSException *) apt reason]];
- continue;
- }
-
- if ((error = [apt primarySaveContentString:_iCal]) != nil) {
- [self logWithFormat:@"Note: failed to save iCal in folder: %@", folder];
- // TODO: make compound
- allErrors = error;
+ e = [[container lookupCalendarFoldersForUIDs:_uids inContext: context]
+ objectEnumerator];
+ while ((folder = [e nextObject]))
+ {
+ apt = [SOGoAppointmentObject objectWithName: nameInContainer
+ inContainer: folder];
+ error = [apt primarySaveContentString:_iCal];
+ if (error)
+ {
+ [self logWithFormat:@"Note: failed to save iCal in folder: %@", folder];
+ // TODO: make compound
+ allErrors = error;
+ }
}
- }
return allErrors;
}
-- (NSException *)deleteInUIDs:(NSArray *)_uids {
+- (NSException *) deleteInUIDs: (NSArray *) _uids
+{
NSEnumerator *e;
id folder;
NSException *allErrors = nil;
+ NSException *error;
+ SOGoAppointmentObject *apt;
- e = [[self lookupCalendarFoldersForUIDs:_uids inContext: context]
- objectEnumerator];
- while ((folder = [e nextObject])) {
- NSException *error;
- SOGoAppointmentObject *apt;
-
- apt = [folder lookupName:[self nameInContainer] inContext: context
- acquire:NO];
- if ([apt isKindOfClass: [NSException class]]) {
- [self logWithFormat: @"%@", [(NSException *) apt reason]];
- continue;
- }
+ e = [[container lookupCalendarFoldersForUIDs:_uids inContext: context]
+ objectEnumerator];
+ while ((folder = [e nextObject]))
+ {
+ apt = [folder lookupName: [self nameInContainer]
+ inContext: context
+ acquire:NO];
+ if ([apt isKindOfClass: [NSException class]]) {
+ [self logWithFormat: @"%@", [(NSException *) apt reason]];
+ continue;
+ }
- if ((error = [apt primaryDelete]) != nil) {
- [self logWithFormat:@"Note: failed to delete in folder: %@", folder];
- // TODO: make compound
- allErrors = error;
+ if ((error = [apt primaryDelete]) != nil) {
+ [self logWithFormat:@"Note: failed to delete in folder: %@", folder];
+ // TODO: make compound
+ allErrors = error;
+ }
}
- }
+
return allErrors;
}
NSException *storeError, *delError;
BOOL updateForcesReconsider;
- updateForcesReconsider = NO;
+ if ([[context request] handledByDefaultHandler])
+ {
+ updateForcesReconsider = NO;
- if ([_iCal length] == 0)
- return [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
- reason: @"got no iCalendar content to store!"];
+ if ([_iCal length] == 0)
+ return [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
+ reason: @"got no iCalendar content to store!"];
- um = [LDAPUserManager sharedUserManager];
+ um = [LDAPUserManager sharedUserManager];
- /* handle old content */
+ /* handle old content */
- oldContent = [self contentAsString]; /* if nil, this is a new appointment */
- if ([oldContent length] == 0)
- {
- /* new appointment */
- [self debugWithFormat:@"saving new appointment: %@", _iCal];
- oldApt = nil;
- }
- else
- oldApt = (iCalEvent *) [self component: NO];
+ oldContent = [self contentAsString]; /* if nil, this is a new appointment */
+ if ([oldContent length] == 0)
+ {
+ /* new appointment */
+ [self debugWithFormat:@"saving new appointment: %@", _iCal];
+ oldApt = nil;
+ }
+ else
+ oldApt = (iCalEvent *) [self component: NO];
- /* compare sequence if requested */
-
- if (_v != 0) {
- // TODO
- }
+ /* compare sequence if requested */
+ if (_v != 0) {
+ // TODO
+ }
- /* handle new content */
+ /* handle new content */
- newApt = (iCalEvent *) [self component: NO];
- if (!newApt)
- return [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
- reason: @"could not parse iCalendar content!"];
+ newApt = (iCalEvent *) [self component: NO];
+ if (!newApt)
+ return [NSException exceptionWithHTTPStatus: 400 /* Bad Request */
+ reason: @"could not parse iCalendar content!"];
- /* diff */
+ /* diff */
- changes = [iCalEventChanges changesFromEvent: oldApt toEvent: newApt];
- uids = [self getUIDsForICalPersons: [changes deletedAttendees]];
- removedUIDs = [NSMutableArray arrayWithArray: uids];
-
- uids = [self getUIDsForICalPersons: [newApt attendees]];
- storeUIDs = [NSMutableArray arrayWithArray: uids];
- props = [changes updatedProperties];
-
- /* detect whether sequence has to be increased */
- if ([changes hasChanges])
- [newApt increaseSequence];
-
- /* preserve organizer */
-
- organizer = [newApt organizer];
- uid = [self getUIDForICalPerson: organizer];
- if (!uid)
- uid = [self ownerInContext: nil];
- if (uid) {
- if (![storeUIDs containsObject:uid])
- [storeUIDs addObject:uid];
- [removedUIDs removeObject:uid];
- }
-
- /* organizer might have changed completely */
-
- if (oldApt && ([props containsObject: @"organizer"])) {
- uid = [self getUIDForICalPerson:[oldApt organizer]];
- if (uid) {
- if (![storeUIDs containsObject:uid]) {
- if (![removedUIDs containsObject:uid]) {
- [removedUIDs addObject:uid];
- }
- }
- }
- }
-
- [self debugWithFormat:@"UID ops:\n store: %@\n remove: %@",
- storeUIDs, removedUIDs];
-
- /* if time did change, all participants have to re-decide ...
- * ... exception from that rule: the organizer
- */
-
- if (oldApt != nil &&
- ([props containsObject: @"startDate"] ||
- [props containsObject: @"endDate"] ||
- [props containsObject: @"duration"]))
- {
- NSArray *ps;
- unsigned i, count;
+ changes = [iCalEventChanges changesFromEvent: oldApt toEvent: newApt];
+ uids = [self getUIDsForICalPersons: [changes deletedAttendees]];
+ removedUIDs = [NSMutableArray arrayWithArray: uids];
+
+ uids = [self getUIDsForICalPersons: [newApt attendees]];
+ storeUIDs = [NSMutableArray arrayWithArray: uids];
+ props = [changes updatedProperties];
+
+ /* detect whether sequence has to be increased */
+ if ([changes hasChanges])
+ [newApt increaseSequence];
+
+ /* preserve organizer */
+
+ organizer = [newApt organizer];
+ uid = [self getUIDForICalPerson: organizer];
+ if (!uid)
+ uid = [self ownerInContext: nil];
+ if (uid)
+ {
+ [storeUIDs addObjectUniquely: uid];
+ [removedUIDs removeObject: uid];
+ }
+
+ /* organizer might have changed completely */
+
+ if (oldApt && ([props containsObject: @"organizer"]))
+ {
+ uid = [self getUIDForICalPerson: [oldApt organizer]];
+ if (uid && ![storeUIDs containsObject: uid])
+ [removedUIDs addObjectUniquely: uid];
+ }
+
+ [self debugWithFormat: @"UID ops:\n store: %@\n remove: %@",
+ storeUIDs, removedUIDs];
+
+ /* if time did change, all participants have to re-decide ...
+ * ... exception from that rule: the organizer
+ */
+
+ if (oldApt
+ && ([props containsObject: @"startDate"]
+ || [props containsObject: @"endDate"]
+ || [props containsObject: @"duration"]))
+ {
+ NSArray *ps;
+ unsigned i, count;
- ps = [newApt attendees];
- count = [ps count];
- for (i = 0; i < count; i++) {
- iCalPerson *p;
+ ps = [newApt attendees];
+ count = [ps count];
+ for (i = 0; i < count; i++) {
+ iCalPerson *p;
- p = [ps objectAtIndex:i];
- if (![p hasSameEmailAddress:organizer])
- [p setParticipationStatus:iCalPersonPartStatNeedsAction];
- }
- _iCal = [[newApt parent] versitString];
- updateForcesReconsider = YES;
- }
-
- /* perform storing */
-
- storeError = [self saveContentString: _iCal inUIDs: storeUIDs];
- delError = [self deleteInUIDs: removedUIDs];
+ p = [ps objectAtIndex:i];
+ if (![p hasSameEmailAddress:organizer])
+ [p setParticipationStatus:iCalPersonPartStatNeedsAction];
+ }
+ _iCal = [[newApt parent] versitString];
+ updateForcesReconsider = YES;
+ }
- // TODO: make compound
- if (storeError != nil) return storeError;
- if (delError != nil) return delError;
+ /* perform storing */
- /* email notifications */
- if ([self sendEMailNotifications]
- && [self _aptIsStillRelevant: newApt])
- {
- attendees
- = [NSMutableArray arrayWithArray: [changes insertedAttendees]];
- [attendees removePerson: organizer];
- [self sendEMailUsingTemplateNamed: @"Invitation"
- forOldObject: nil
- andNewObject: newApt
- toAttendees: attendees];
-
- if (updateForcesReconsider) {
- attendees = [NSMutableArray arrayWithArray:[newApt attendees]];
- [attendees removeObjectsInArray:[changes insertedAttendees]];
- [attendees removePerson:organizer];
- [self sendEMailUsingTemplateNamed: @"Update"
- forOldObject: oldApt
- andNewObject: newApt
- toAttendees: attendees];
- }
+ storeError = [self saveContentString: _iCal inUIDs: storeUIDs];
+ delError = [self deleteInUIDs: removedUIDs];
- attendees
- = [NSMutableArray arrayWithArray: [changes deletedAttendees]];
- [attendees removePerson: organizer];
- if ([attendees count])
- {
- iCalEvent *cancelledApt;
+ // TODO: make compound
+ if (storeError != nil) return storeError;
+ if (delError != nil) return delError;
+
+ /* email notifications */
+ if ([self sendEMailNotifications]
+ && [self _aptIsStillRelevant: newApt])
+ {
+ iCalEvent *requestApt;
+
+ requestApt = [newApt copy];
+ [(iCalCalendar *) [requestApt parent] setMethod: @"request"];
+ attendees
+ = [NSMutableArray arrayWithArray: [changes insertedAttendees]];
+ [attendees removePerson: organizer];
+ [self sendEMailUsingTemplateNamed: @"Invitation"
+ forOldObject: nil
+ andNewObject: requestApt
+ toAttendees: attendees];
+ [requestApt release];
+
+ if (updateForcesReconsider)
+ {
+ iCalEvent *updatedApt;
+
+ updatedApt = [newApt copy];
+ [(iCalCalendar *) [updatedApt parent] setMethod: @"request"];
+ attendees = [NSMutableArray arrayWithArray:[newApt attendees]];
+ [attendees removeObjectsInArray:[changes insertedAttendees]];
+ [attendees removePerson:organizer];
+ [self sendEMailUsingTemplateNamed: @"Update"
+ forOldObject: oldApt
+ andNewObject: updatedApt
+ toAttendees: attendees];
+ [updatedApt release];
+ }
+
+ attendees
+ = [NSMutableArray arrayWithArray: [changes deletedAttendees]];
+ [attendees removePerson: organizer];
+ if ([attendees count])
+ {
+ iCalEvent *cancelledApt;
- cancelledApt = [newApt copy];
- [(iCalCalendar *) [cancelledApt parent] setMethod: @"cancel"];
- [self sendEMailUsingTemplateNamed: @"Removal"
- forOldObject: nil
- andNewObject: cancelledApt
- toAttendees: attendees];
- [cancelledApt release];
- }
+ cancelledApt = [newApt copy];
+ [(iCalCalendar *) [cancelledApt parent] setMethod: @"cancel"];
+ [self sendEMailUsingTemplateNamed: @"Removal"
+ forOldObject: nil
+ andNewObject: cancelledApt
+ toAttendees: attendees];
+ [cancelledApt release];
+ }
+ }
}
+ else
+ [self primarySaveContentString: _iCal];
return nil;
}
-- (NSException *)deleteWithBaseSequence:(int)_v {
+- (NSException *) deleteWithBaseSequence: (int)_v
+{
/*
Note: We need to delete in all participants folders and send iMIP messages
for all external accounts.
*/
iCalEvent *apt;
NSMutableArray *attendees, *removedUIDs;
+ NSException *error;
+ if ([[context request] handledByDefaultHandler])
+ {
/* load existing content */
-
- apt = (iCalEvent *) [self component: NO];
+ apt = (iCalEvent *) [self component: NO];
/* compare sequence if requested */
// // TODO
// }
- removedUIDs = [NSMutableArray arrayWithArray:
- [self attendeeUIDsFromAppointment: apt]];
- if (![removedUIDs containsObject: owner])
- [removedUIDs addObject: owner];
-
- if ([self sendEMailNotifications])
- {
- /* send notification email to attendees excluding organizer */
- attendees = [NSMutableArray arrayWithArray:[apt attendees]];
- [attendees removePerson:[apt organizer]];
+ removedUIDs = [NSMutableArray arrayWithArray:
+ [self attendeeUIDsFromAppointment: apt]];
+ if (![removedUIDs containsObject: owner])
+ [removedUIDs addObject: owner];
+
+ if ([self sendEMailNotifications]
+ && [self _aptIsStillRelevant: apt])
+ {
+ /* send notification email to attendees excluding organizer */
+ attendees = [NSMutableArray arrayWithArray: [apt attendees]];
+ [attendees removePerson: [apt organizer]];
- /* flag appointment as being cancelled */
- [(iCalCalendar *) [apt parent] setMethod: @"cancel"];
- [apt increaseSequence];
-
- /* remove all attendees to signal complete removal */
- [apt removeAllAttendees];
-
- /* send notification email */
- [self sendEMailUsingTemplateNamed: @"Deletion"
- forOldObject: nil
- andNewObject: apt
- toAttendees: attendees];
- }
+ /* flag appointment as being cancelled */
+ [(iCalCalendar *) [apt parent] setMethod: @"cancel"];
+ [apt increaseSequence];
+
+ /* remove all attendees to signal complete removal */
+ [apt removeAllAttendees];
- /* perform */
+ /* send notification email */
+ [self sendEMailUsingTemplateNamed: @"Deletion"
+ forOldObject: nil
+ andNewObject: apt
+ toAttendees: attendees];
+ }
+
+ error = [self deleteInUIDs: removedUIDs];
+ }
+ else
+ error = [self primaryDelete];
- return [self deleteInUIDs: removedUIDs];
+ return error;
}
- (NSException *) saveContentString: (NSString *) _iCalString