diff --git a/NEWS b/NEWS index 506495dc7..3069604c5 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ Enhancements - Improve sync speed from Outlook by non-reprocessing already downloaded unread mails Bug fixes + - Fix exception modifications import in recurrence series - Sent mails are not longer in Drafts folder using Outlook - Fix server side crash parsing rtf emails with images (with word97 format) diff --git a/OpenChange/MAPIStoreRecurrenceUtils.h b/OpenChange/MAPIStoreRecurrenceUtils.h index 68c84361e..df3700575 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.h +++ b/OpenChange/MAPIStoreRecurrenceUtils.h @@ -25,6 +25,8 @@ #include +#import + #import #import @@ -41,7 +43,10 @@ @interface iCalCalendar (MAPIStoreRecurrence) - (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity - fromRecurrencePattern: (struct RecurrencePattern *) rp; + fromRecurrencePattern: (struct RecurrencePattern *) rp + withExceptions: (struct ExceptionInfo *) exInfos + andExceptionCount: (uint16_t) exInfoCount + inTimeZone: (NSTimeZone *) tz; @end diff --git a/OpenChange/MAPIStoreRecurrenceUtils.m b/OpenChange/MAPIStoreRecurrenceUtils.m index ebf588000..28b1be22c 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.m +++ b/OpenChange/MAPIStoreRecurrenceUtils.m @@ -24,6 +24,7 @@ #import #import #import +#import #import #import @@ -48,6 +49,10 @@ - (void) setupRecurrenceWithMasterEntity: (iCalRepeatableEntityObject *) entity fromRecurrencePattern: (struct RecurrencePattern *) rp + withExceptions: (struct ExceptionInfo *) exInfos + andExceptionCount: (uint16_t) exInfoCount + inTimeZone: (NSTimeZone *) tz + { NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate; NSString *monthDay, *month; @@ -214,34 +219,42 @@ /* exception dates: - take all deleted instances - - remove all modified instances from the above set + - remove all modified instances available in ExceptionInfo from the above set - add remaining instances, in chronological order */ - exceptionDates = [NSMutableSet set]; - for (count = 0; count < rp->DeletedInstanceCount; count++) - { - exDate - = [NSDate dateFromMinutesSince1601: rp->DeletedInstanceDates[count]]; - exDate = [exDate hour: [startDate hourOfDay] - minute: [startDate minuteOfHour] - second: [startDate secondOfMinute]]; - [exceptionDates addObject: exDate]; - } - for (count = 0; count < rp->ModifiedInstanceCount; count++) - { - exDate - = [NSDate dateFromMinutesSince1601: rp->ModifiedInstanceDates[count]]; - exDate = [exDate hour: [startDate hourOfDay] - minute: [startDate minuteOfHour] - second: [startDate secondOfMinute]]; - [exceptionDates removeObject: exDate]; - } - realExDates = [[exceptionDates allObjects] - sortedArrayUsingSelector: @selector (compare:)]; - max = [realExDates count]; - for (count = 0; count < max; count++) - [entity addToExceptionDates: [realExDates objectAtIndex: count]]; + /* Heuristic to avoid these loops */ + if (rp->DeletedInstanceCount != rp->ModifiedInstanceCount) { + exceptionDates = [NSMutableSet set]; + for (count = 0; count < rp->DeletedInstanceCount; count++) + { + exDate + = [NSDate dateFromMinutesSince1601: rp->DeletedInstanceDates[count]]; + exDate = [exDate hour: [startDate hourOfDay] + minute: [startDate minuteOfHour] + second: [startDate secondOfMinute]]; + [exceptionDates addObject: exDate]; + } + /* Read the exceptions to remove the instances that are modified and not deleted */ + if (exInfos && exInfoCount > 0) + { + for (count = 0; count < exInfoCount; count++) + { + /* The OriginalStartDate is in local time */ + exDate = [NSDate dateFromMinutesSince1601: exInfos[count].OriginalStartDate]; + exDate = [exDate dateByAddingYears: 0 months: 0 days: 0 + hours: 0 minutes: 0 + seconds: - [tz secondsFromGMT]]; + [exceptionDates removeObject: exDate]; + } + } + + realExDates = [[exceptionDates allObjects] + sortedArrayUsingSelector: @selector (compare:)]; + max = [realExDates count]; + for (count = 0; count < max; count++) + [entity addToExceptionDates: [realExDates objectAtIndex: count]]; + } } @end diff --git a/OpenChange/iCalEvent+MAPIStore.m b/OpenChange/iCalEvent+MAPIStore.m index 3ccc31a6c..d8c016250 100644 --- a/OpenChange/iCalEvent+MAPIStore.m +++ b/OpenChange/iCalEvent+MAPIStore.m @@ -74,6 +74,7 @@ @implementation iCalEvent (MAPIStoreProperties) - (void) _setupEventRecurrence: (NSData *) mapiRecurrenceData + inTimeZone: (NSTimeZone *) tz inMemCtx: (TALLOC_CTX *) memCtx { struct Binary_r *blob; @@ -87,9 +88,12 @@ return; } - [(iCalCalendar *) parent - setupRecurrenceWithMasterEntity: self - fromRecurrencePattern: &pattern->RecurrencePattern]; + [(iCalCalendar *) parent setupRecurrenceWithMasterEntity: self + fromRecurrencePattern: &pattern->RecurrencePattern + withExceptions: pattern->ExceptionInfo + andExceptionCount: pattern->ExceptionCount + inTimeZone: tz + ]; //talloc_free (blob); } @@ -362,7 +366,7 @@ value = [properties objectForKey: MAPIPropertyKey (PidLidAppointmentRecur)]; if (value) - [self _setupEventRecurrence: value inMemCtx: memCtx]; + [self _setupEventRecurrence: value inTimeZone: userTimeZone inMemCtx: memCtx]; /* alarm */ [self _setupEventAlarmFromProperties: properties];