X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=SoObjects%2FAppointments%2FSOGoAppointmentObject.m;h=12f97b38a0e13f33b7df263f62e9f49f95c719c8;hb=4e6eeb543b90ae4551e7dbc24a82eb608696e1a7;hp=b2b8e1f97adf2f5f33ac97e96dd0535b04d929e5;hpb=6a3e04d97b815fb60e88a4f6ba952e85ea06828b;p=scalable-opengroupware.org diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index b2b8e1f9..12f97b38 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -19,22 +19,27 @@ 02111-1307, USA. */ -#import "SOGoAppointmentObject.h" +#import +#import +#import +#import +#import #import #import #import #import -#import -#import -#import - -#import "iCalEntityObject+Agenor.h" - -#import "common.h" +#import +#import +#import +#import +#import #import "NSArray+Appointments.h" +#import "SOGoAppointmentFolder.h" + +#import "SOGoAppointmentObject.h" @implementation SOGoAppointmentObject @@ -46,7 +51,7 @@ /* iCal handling */ - (NSArray *) attendeeUIDsFromAppointment: (iCalEvent *) _apt { - AgenorUserManager *um; + LDAPUserManager *um; NSMutableArray *uids; NSArray *attendees; unsigned i, count; @@ -60,13 +65,13 @@ count = [attendees count]; uids = [NSMutableArray arrayWithCapacity:count + 1]; - um = [AgenorUserManager sharedUserManager]; + um = [LDAPUserManager sharedUserManager]; /* add organizer */ email = [[_apt organizer] rfc822Email]; if ([email isNotNull]) { - uid = [um getUIDForEmail:email]; + uid = [um getUIDForEmail: email]; if ([uid isNotNull]) { [uids addObject:uid]; } @@ -96,97 +101,74 @@ 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 inUIDs:(NSArray *)_uids { +- (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]) != nil) { - NSException *error; - SOGoAppointmentObject *apt; - - if (![folder isNotNull]) /* no folder was found for given UID */ - continue; - - apt = [folder lookupName: [self nameInContainer] inContext:ctx - 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; - id ctx; + NSException *error; + SOGoAppointmentObject *apt; - 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 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; } /* "iCal multifolder saves" */ +- (BOOL) _aptIsStillRelevant: (iCalEvent *) appointment +{ + NSCalendarDate *now; + + now = [NSCalendarDate calendarDate]; + + return ([[appointment endDate] earlierDate: now] == now); +} - (NSException *) saveContentString: (NSString *) _iCal baseSequence: (int) _v @@ -207,8 +189,7 @@ - delete in removed folders - send iMIP mail for all folders not found */ - AgenorUserManager *um; - iCalCalendar *newCalendar; + LDAPUserManager *um; iCalEvent *oldApt, *newApt; iCalEventChanges *changes; iCalPerson *organizer; @@ -218,161 +199,170 @@ NSException *storeError, *delError; BOOL updateForcesReconsider; - updateForcesReconsider = NO; - - if ([_iCal length] == 0) { - return [NSException exceptionWithHTTPStatus:400 /* Bad Request */ - reason:@"got no iCalendar content to store!"]; - } + if ([[context request] handledByDefaultHandler]) + { + updateForcesReconsider = NO; - um = [AgenorUserManager sharedUserManager]; + if ([_iCal length] == 0) + return [NSException exceptionWithHTTPStatus: 400 /* Bad Request */ + reason: @"got no iCalendar content to store!"]; - /* 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]; - - /* compare sequence if requested */ + um = [LDAPUserManager sharedUserManager]; - if (_v != 0) { - // TODO - } + /* 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]; - /* handle new content */ - - newCalendar = [iCalCalendar parseSingleFromSource: _iCal]; - newApt = (iCalEvent *) [newCalendar firstChildWithTag: [self componentTag]]; - if (newApt == nil) { - return [NSException exceptionWithHTTPStatus:400 /* Bad Request */ - reason:@"could not parse iCalendar content!"]; - } + /* compare sequence if requested */ + if (_v != 0) { + // TODO + } - /* diff */ + /* handle new content */ - changes = [iCalEventChanges changesFromEvent: oldApt - toEvent: newApt]; - - uids = [um getUIDsForICalPersons:[changes deletedAttendees] - applyStrictMapping:NO]; - removedUIDs = [NSMutableArray arrayWithArray:uids]; - - uids = [um getUIDsForICalPersons:[newApt attendees] - applyStrictMapping:NO]; - 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 = [um getUIDForICalPerson:organizer]; - if (uid) { - if (![storeUIDs containsObject:uid]) - [storeUIDs addObject:uid]; - [removedUIDs removeObject:uid]; - } - - /* organizer might have changed completely */ + newApt = (iCalEvent *) [self component: NO]; + if (!newApt) + return [NSException exceptionWithHTTPStatus: 400 /* Bad Request */ + reason: @"could not parse iCalendar content!"]; - if (oldApt && ([props containsObject: @"organizer"])) { - uid = [um 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; + /* 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) + { + [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 */ + p = [ps objectAtIndex:i]; + if (![p hasSameEmailAddress:organizer]) + [p setParticipationStatus:iCalPersonPartStatNeedsAction]; + } + _iCal = [[newApt parent] versitString]; + updateForcesReconsider = YES; + } - storeError = [self saveContentString:_iCal inUIDs:storeUIDs]; - delError = [self deleteInUIDs:removedUIDs]; + /* perform storing */ - // TODO: make compound - if (storeError != nil) return storeError; - if (delError != nil) return delError; - - /* email notifications */ - if ([self sendEMailNotifications]) - { - 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 *canceledApt; + // 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; - canceledApt = [newApt copy]; - [(iCalCalendar *) [canceledApt parent] setMethod: @"cancel"]; - [self sendEMailUsingTemplateNamed: @"Removal" - forOldObject: nil - andNewObject: canceledApt - toAttendees: attendees]; - [canceledApt 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. @@ -388,12 +378,13 @@ - send iMIP mail for all folders not found */ iCalEvent *apt; - NSArray *removedUIDs; - NSMutableArray *attendees; + NSMutableArray *attendees, *removedUIDs; + NSException *error; + if ([[context request] handledByDefaultHandler]) + { /* load existing content */ - - apt = (iCalEvent *) [self component]; + apt = (iCalEvent *) [self component: NO]; /* compare sequence if requested */ @@ -401,88 +392,44 @@ // // TODO // } - removedUIDs = [self attendeeUIDsFromAppointment:apt]; - - 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 canceled */ - [(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]; - /* perform */ + /* remove all attendees to signal complete removal */ + [apt removeAllAttendees]; - return [self deleteInUIDs:removedUIDs]; -} + /* send notification email */ + [self sendEMailUsingTemplateNamed: @"Deletion" + forOldObject: nil + andNewObject: apt + toAttendees: attendees]; + } -- (NSException *) saveContentString: (NSString *) _iCalString -{ - return [self saveContentString: _iCalString baseSequence: 0]; -} - -- (NSException *) changeParticipationStatus: (NSString *) _status - inContext: (id) _ctx -{ - iCalEvent *apt; - iCalPerson *p; - NSString *newContent; - NSException *ex; - NSString *myEMail; - - ex = nil; - - // TODO: do we need to use SOGoAppointment? (prefer iCalEvent?) - apt = (iCalEvent *) [self component]; - - if (apt) - { - myEMail = [[_ctx activeUser] email]; - p = [apt findParticipantWithEmail: myEMail]; - if (p) - { - // TODO: send iMIP reply mails? - - [p setPartStat:_status]; - newContent = [[apt parent] versitString]; - if (newContent) - { - ex = [self saveContentString:newContent]; - if (ex) - // TODO: why is the exception wrapped? - /* Server Error */ - ex = [NSException exceptionWithHTTPStatus: 500 - reason: [ex reason]]; - } - else - ex - = [NSException exceptionWithHTTPStatus: 500 /* Server Error */ - reason: @"Could not generate iCalendar data ..."]; - } - else - ex = [NSException exceptionWithHTTPStatus: 404 /* Not Found */ - reason: @"user does not participate in this " - @"appointment"]; + error = [self deleteInUIDs: removedUIDs]; } else - ex = [NSException exceptionWithHTTPStatus:500 /* Server Error */ - reason:@"unable to parse appointment record"]; + error = [self primaryDelete]; - return ex; + return error; } +- (NSException *) saveContentString: (NSString *) _iCalString +{ + return [self saveContentString: _iCalString baseSequence: 0]; +} /* message type */ @@ -491,36 +438,4 @@ return @"IPM.Appointment"; } -- (NSException *) saveContentString: (NSString *) contentString - baseVersion: (unsigned int) baseVersion -{ - NSString *newContentString, *oldContentString; - iCalCalendar *eventCalendar; - iCalEvent *event; - NSArray *organizers; - - oldContentString = [self contentAsString]; - if (oldContentString) - newContentString = contentString; - else - { - eventCalendar = [iCalCalendar parseSingleFromSource: contentString]; - event = (iCalEvent *) [eventCalendar firstChildWithTag: [self componentTag]]; - organizers = [event childrenWithTag: @"organizer"]; - if ([organizers count]) - newContentString = contentString; - else - { - [event setOrganizerWithUid: [[self container] ownerInContext: nil]]; - newContentString = [eventCalendar versitString]; - } - } - - return [super saveContentString: newContentString - baseVersion: baseVersion]; -} - @end /* SOGoAppointmentObject */ - - -