diff --git a/SOPE/NGCards/iCalRecurrenceRule.m b/SOPE/NGCards/iCalRecurrenceRule.m index 53f9939ab..622506d5c 100644 --- a/SOPE/NGCards/iCalRecurrenceRule.m +++ b/SOPE/NGCards/iCalRecurrenceRule.m @@ -686,4 +686,34 @@ [self warnWithFormat:@"Cannot handle unbound key: '%@'", _key]; } +- (BOOL) isEqual: (id) rrule +{ + BOOL isEqual = YES; + + if ([rrule isKindOfClass: [iCalRecurrenceRule class]]) + { + /* + NSLog(@"*** iCalRecurrenceRule comparison ***"); + NSLog(@"Event 1 : repeat %i, interval %i, frequency %i, until %@", + [self repeatCount], [self repeatInterval], [self frequency], [self untilDate]); + NSLog(@"Event 2 : repeat %i, interval %i, frequency %i, until %@", + [rrule repeatCount], [rrule repeatInterval], [rrule frequency], [rrule untilDate]); + */ + + if ([self untilDate] && [rrule untilDate]) + isEqual = [[self untilDate] isEqual: [rrule untilDate]]; + else if ([self untilDate] || [self untilDate]) + isEqual = NO; + + isEqual = isEqual && + [self repeatCount] == [rrule repeatCount] && + [self repeatInterval] == [rrule repeatInterval] && + [self frequency] == [rrule frequency]; + } + else + isEqual = NO; + + return isEqual; +} + @end /* iCalRecurrenceRule */ diff --git a/SoObjects/Appointments/SOGoAppointmentObject.m b/SoObjects/Appointments/SOGoAppointmentObject.m index 4d9119776..2ac9ebe84 100644 --- a/SoObjects/Appointments/SOGoAppointmentObject.m +++ b/SoObjects/Appointments/SOGoAppointmentObject.m @@ -163,7 +163,7 @@ NSString *possibleName; folder = [container lookupCalendarFolderForUID: uid]; - // should call lookupCalendarFoldersForUIDs to search among all folders +#warning Should call lookupCalendarFoldersForUIDs to search among all folders object = [folder lookupName: nameInContainer inContext: context acquire: NO]; if ([object isKindOfClass: [NSException class]]) @@ -364,6 +364,8 @@ { iCalEvent *oldEvent; NSArray *attendees; + NSCalendarDate *recurrenceId; + NSString *recurrenceTime; SOGoUser *ownerUser; [[newEvent parent] setMethod: @""]; @@ -395,8 +397,23 @@ else { // Event is modified -- sent update status to all attendees - oldEvent = [self component: NO secure: NO]; + recurrenceId = [newEvent recurrenceId]; + if (recurrenceId == nil) + oldEvent = [self component: NO secure: NO]; + else + { + // If recurrenceId is defined, find the specified occurence + // within the repeating vEvent. + recurrenceTime = [NSString stringWithFormat: @"%f", [recurrenceId timeIntervalSince1970]]; + oldEvent = (iCalEvent*)[self lookupOccurence: recurrenceTime]; + if (oldEvent == nil) + // If no occurence found, create one + oldEvent = (iCalEvent*)[self newOccurenceWithID: recurrenceTime]; + } [self _handleUpdatedEvent: newEvent fromOldEvent: oldEvent]; + + // The sequence has possibly been increased -- resave the event + [super saveComponent: newEvent]; } } } @@ -437,7 +454,7 @@ { // We must update main event and all its occurences (if any). calendar = [eventObject calendar: NO secure: NO]; - event = [calendar firstChildWithTag: [self componentTag]]; + event = (iCalEntityObject*)[calendar firstChildWithTag: [self componentTag]]; events = [calendar allObjects]; } else @@ -891,16 +908,16 @@ // If _recurrenceId is defined, find the specified occurence // within the repeating vEvent. recurrenceTime = [NSString stringWithFormat: @"%f", [_recurrenceId timeIntervalSince1970]]; - event = [self lookupOccurence: recurrenceTime]; + event = (iCalEvent*)[self lookupOccurence: recurrenceTime]; if (event == nil) // If no occurence found, create one - event = [self newOccurenceWithID: recurrenceTime]; + event = (iCalEvent*)[self newOccurenceWithID: recurrenceTime]; } else // No specific occurence specified; return the first vEvent of // the vCalendar. - event = [calendar firstChildWithTag: [self componentTag]]; + event = (iCalEvent*)[calendar firstChildWithTag: [self componentTag]]; } if (event) { diff --git a/UI/MailPartViewers/UIxMailPartICalActions.m b/UI/MailPartViewers/UIxMailPartICalActions.m index ad506bea0..29b4cbc06 100644 --- a/UI/MailPartViewers/UIxMailPartICalActions.m +++ b/UI/MailPartViewers/UIxMailPartICalActions.m @@ -75,6 +75,7 @@ eventObject = nil; +#warning Should call lookupCalendarFoldersForUIDs to search among all folders personalFolder = [user personalCalendarFolderInContext: context]; cname = [personalFolder resourceNameForEventUID: uid]; if (cname) @@ -149,12 +150,35 @@ chosenEvent = emailEvent; else { - calendarEvent = (iCalEvent *) [*eventObject component: NO - secure: NO]; - if ([calendarEvent compare: emailEvent] == NSOrderedAscending) - chosenEvent = emailEvent; + if ([emailEvent recurrenceId]) + { + // Event attached to email is not completed -- retrieve it + // from the database. + NSString *recurrenceTime; + + recurrenceTime = [NSString stringWithFormat: @"%f", + [[emailEvent recurrenceId] timeIntervalSince1970]]; + calendarEvent = [*eventObject lookupOccurence: recurrenceTime]; + } else - chosenEvent = calendarEvent; + calendarEvent = (iCalEvent *) [*eventObject component: NO + secure: NO]; + + if (calendarEvent != nil) + { + // Calendar event still exists -- verify which of the calendar + // and email events is the most recent. + if ([calendarEvent compare: emailEvent] == NSOrderedAscending) + chosenEvent = emailEvent; + else + { + chosenEvent = calendarEvent; + if (![[[chosenEvent parent] method] length]) + [[chosenEvent parent] setMethod: [[emailEvent parent] method]]; + } + } + else + chosenEvent = emailEvent; } organizer = [chosenEvent organizer]; @@ -163,7 +187,7 @@ } else chosenEvent = nil; - + return chosenEvent; } @@ -171,46 +195,75 @@ - (void) _updateAttendee: (iCalPerson *) attendee ownerUser: (SOGoUser *) theOwnerUser forEventUID: (NSString *) eventUID + withRecurrenceId: (NSCalendarDate *) recurrenceId withSequence: (NSNumber *) sequence forUID: (NSString *) uid shouldAddSentBy: (BOOL) b { SOGoAppointmentObject *eventObject; + iCalCalendar *calendar; iCalEvent *event; iCalPerson *otherAttendee; - NSString *iCalString; + NSArray *events; + NSString *iCalString, *recurrenceTime; eventObject = [self _eventObjectWithUID: eventUID forUser: [SOGoUser userWithLogin: uid roles: nil]]; if (![eventObject isNew]) { - event = [eventObject component: NO secure: NO]; + if (recurrenceId == nil) + { + // We must update main event and all its occurences (if any). + calendar = [eventObject calendar: NO secure: NO]; + event = [calendar firstChildWithTag: [eventObject componentTag]]; + events = [calendar allObjects]; + } + else + { + // If recurrenceId is defined, find the specified occurence + // within the repeating vEvent. + recurrenceTime = [NSString stringWithFormat: @"%f", [recurrenceId timeIntervalSince1970]]; + event = [eventObject lookupOccurence: recurrenceTime]; + + if (event == nil) + // If no occurence found, create one + event = [eventObject newOccurenceWithID: recurrenceTime]; + + events = [NSArray arrayWithObject: event]; + } + if ([[event sequence] compare: sequence] == NSOrderedSame) { SOGoUser *currentUser; + int i; - otherAttendee = [event findParticipant: theOwnerUser]; - [otherAttendee setPartStat: [attendee partStat]]; - - // If one has accepted / declined an invitation on behalf of - // the attendee, we add the user to the SENT-BY attribute. currentUser = [context activeUser]; - if (b && ![[currentUser login] isEqualToString: [theOwnerUser login]]) - { - NSString *currentEmail; - currentEmail = [[currentUser allEmails] objectAtIndex: 0]; - [otherAttendee addAttribute: @"SENT-BY" - value: [NSString stringWithFormat: @"\"MAILTO:%@\"", currentEmail]]; - } - else - { - // We must REMOVE any SENT-BY here. This is important since if A accepted - // the event for B and then, B changes by himself his participation status, - // we don't want to keep the previous SENT-BY attribute there. - [(NSMutableDictionary *)[otherAttendee attributes] removeObjectForKey: @"SENT-BY"]; - } + for (i = 0; i < [events count]; i++) + { + event = [events objectAtIndex: i]; + + otherAttendee = [event findParticipant: theOwnerUser]; + [otherAttendee setPartStat: [attendee partStat]]; + + // If one has accepted / declined an invitation on behalf of + // the attendee, we add the user to the SENT-BY attribute. + if (b && ![[currentUser login] isEqualToString: [theOwnerUser login]]) + { + NSString *currentEmail; + currentEmail = [[currentUser allEmails] objectAtIndex: 0]; + [otherAttendee addAttribute: @"SENT-BY" + value: [NSString stringWithFormat: @"\"MAILTO:%@\"", currentEmail]]; + } + else + { + // We must REMOVE any SENT-BY here. This is important since if A accepted + // the event for B and then, B changes by himself his participation status, + // we don't want to keep the previous SENT-BY attribute there. + [(NSMutableDictionary *)[otherAttendee attributes] removeObjectForKey: @"SENT-BY"]; + } + } iCalString = [[event parent] versitString]; [eventObject saveContentString: iCalString]; } @@ -232,6 +285,7 @@ user = [chosenEvent findParticipant: [context activeUser]]; [user setPartStat: newStatus]; calendar = [chosenEvent parent]; + emailCalendar = [[self _emailEvent] parent]; method = [[emailCalendar method] lowercaseString]; if ([method isEqualToString: @"request"]) @@ -241,16 +295,24 @@ } else rsvp = nil; + + // We generate the updated iCalendar file and we save it + // in the database. [eventObject saveContentString: [calendar versitString]]; + + // Send a notification to the organizer if necessary if ([rsvp isEqualToString: @"true"] && [chosenEvent isStillRelevant]) [eventObject sendResponseToOrganizer: chosenEvent from: [context activeUser]]; + organizerUID = [[chosenEvent organizer] uid]; if (organizerUID) + // Update the event in the organizer's calendar [self _updateAttendee: user ownerUser: [context activeUser] forEventUID: [chosenEvent uid] + withRecurrenceId: [chosenEvent recurrenceId] withSequence: [chosenEvent sequence] forUID: organizerUID shouldAddSentBy: YES]; @@ -281,6 +343,7 @@ ownerUser: [context activeUser] forEventUID: [chosenEvent uid] withSequence: [chosenEvent sequence] + withRecurrenceId: [chosenEvent recurrenceId] forUID: uid shouldAddSentBy: YES]; } diff --git a/UI/MailPartViewers/UIxMailPartICalViewer.m b/UI/MailPartViewers/UIxMailPartICalViewer.m index 677e604c5..d994aad28 100644 --- a/UI/MailPartViewers/UIxMailPartICalViewer.m +++ b/UI/MailPartViewers/UIxMailPartICalViewer.m @@ -104,7 +104,7 @@ { events = [[self inCalendar] events]; if ([events count] > 0) - inEvent = [[events objectAtIndex:0] retain]; + inEvent = [[events objectAtIndex: 0] retain]; } return inEvent; @@ -262,7 +262,25 @@ { if (!storedEvent) { - storedEvent = [[self storedEventObject] component: NO secure: NO]; + NSCalendarDate *recurrenceId; + + recurrenceId = [[self inEvent] recurrenceId]; + + if (recurrenceId == nil) + storedEvent = [[self storedEventObject] component: NO secure: NO]; + else + { + // Find the specific occurence within the repeating vEvent. + NSString *recurrenceTime; + + recurrenceTime = [NSString stringWithFormat: @"%f", [recurrenceId timeIntervalSince1970]]; + storedEvent = (iCalEvent*)[[self storedEventObject] lookupOccurence: recurrenceTime]; + + if (storedEvent == nil) + // If no occurence found, create one + storedEvent = (iCalEvent*)[storedEventObject newOccurenceWithID: recurrenceTime]; + } + [storedEvent retain]; }