From 6f44ec42c1bdf934f8035bdd1fb3035bc74925d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Fri, 6 Mar 2015 13:23:17 +0100 Subject: [PATCH] oc-calendar: Fix import in SOGo exceptions from recurring series According to [MS-OXICAL] Section 2.1.3.1.1.20.13, the EXDATE property must be written only if there are ocurrences from the series that have been deleted and before this commit ModifiedInstanceDates were also included. We check against every ExceptionInfo from exception ocurrences of the series to know if the ocurrence was deleted or only modified. --- NEWS | 1 + OpenChange/MAPIStoreRecurrenceUtils.h | 7 ++- OpenChange/MAPIStoreRecurrenceUtils.m | 63 ++++++++++++++++----------- OpenChange/iCalEvent+MAPIStore.m | 12 +++-- 4 files changed, 53 insertions(+), 30 deletions(-) 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];