From 29aa61f8bd31e2be33d01836ff093fdf696914b8 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Thu, 19 Apr 2012 14:24:37 +0000 Subject: [PATCH] See ChangeLog. Monotone-Parent: d76454ce94cf2e0cbc0503997f50e243467692ba Monotone-Revision: 3df4271ffa54be2fdec6fa5cc5170ed38c1e01df Monotone-Author: flachapelle@inverse.ca Monotone-Date: 2012-04-19T14:24:37 --- ChangeLog | 18 +++-- .../Appointments/SOGoAppointmentFolder.h | 5 +- .../Appointments/SOGoAppointmentFolder.m | 65 ++++++++++++++----- 3 files changed, 64 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 68b6b8db2..2b0fb5c60 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-04-19 Francis Lachapelle + + * SoObjects/Appointments/SOGoAppointmentFolder.m + (-importCalendar:): associate occurrences of a repeating event to + its master vcalendar to avoid duplicated events when importing a .ics. + 2012-04-19 Wolfgang Sourdeau * SoObjects/Appointments/SOGoAppointmentFolder.m @@ -6,27 +12,27 @@ instead of c_enddate. 2012-04-18 Ludovic Marcotte - + * SoObjects/Appointments/SOGoAppointmentObject.m (-_handleResourcesConflicts: ...): We now handle recurring appointments by fetching the freebusy information for one full year from the date of the event. Also improved the conflict reporting messages. - + * SoObjects/Appointments/SOGoAppointmentObject.m (-PUTAction:): update the versit string in the request when updating the event, in case a resource auto-accepted the event - + * SoObjects/SOGo/SOGoGCSFolder.m: renamed -subscribeUser:reallydo: to subscribeUserOrGroup:reallydo and we now handle group subscriptions. Refactored all callers. - + * SoObjects/SOGo/SOGoParentFolder.m (-_appendSubscribedSource:): now returns a BOOL if the permission are still valid or not - + * SoObjects/SOGo/SOGoParentFolder.m (-appendSubscribedSources): consumes the returned value from -_appendSubscribedSource: and cleans up SubscribedFolders and FolderDisplayNames accordingly in the user's settings. - + * SoObjects/SOGo/SOGoUserManager.m (-_fillContactInfosForUser: ...): we now set the isGroup attribute as we need this for quick groups resolving. diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.h b/SoObjects/Appointments/SOGoAppointmentFolder.h index bc5f10f2c..02f13630b 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.h +++ b/SoObjects/Appointments/SOGoAppointmentFolder.h @@ -49,6 +49,7 @@ @class NSTimeZone; @class GCSFolder; @class iCalCalendar; +@class iCalTimeZone; @class SOGoWebDAVValue; typedef enum { @@ -162,8 +163,8 @@ typedef enum { - (BOOL) includeInFreeBusy; - (void) setIncludeInFreeBusy: (BOOL) newInclude; -- (BOOL) importComponent: (iCalEntityObject *) event - timezone: (NSString *) timezone; +- (NSString *) importComponent: (iCalEntityObject *) event + timezone: (iCalTimeZone *) timezone; - (int) importCalendar: (iCalCalendar *) calendar; diff --git a/SoObjects/Appointments/SOGoAppointmentFolder.m b/SoObjects/Appointments/SOGoAppointmentFolder.m index 40d31088d..24bab7273 100644 --- a/SoObjects/Appointments/SOGoAppointmentFolder.m +++ b/SoObjects/Appointments/SOGoAppointmentFolder.m @@ -1775,6 +1775,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir return [name isEqualToString: @"OPTIONS"]; } +/* - (id) lookupComponentByUID: (NSString *) uid { NSString *filename; @@ -1792,6 +1793,7 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir return nil; } +*/ - (id) lookupName: (NSString *)_key inContext: (id)_ctx @@ -2710,22 +2712,24 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir return (![inactiveFolders containsObject: nameInContainer]); } -- (BOOL) importComponent: (iCalEntityObject *) event - timezone: (NSString *) timezone +- (NSString *) importComponent: (iCalEntityObject *) event + timezone: (iCalTimeZone *) timezone { SOGoAppointmentObject *object; NSString *uid; - NSString *content; + NSMutableString *content; uid = [self globallyUniqueObjectId]; [event setUid: uid]; object = [SOGoAppointmentObject objectWithName: uid inContainer: self]; [object setIsNew: YES]; - content = - [NSString stringWithFormat: @"BEGIN:VCALENDAR\n%@%@\nEND:VCALENDAR", - timezone, [event versitString]]; - return ([object saveContentString: content] == nil); + content = [NSMutableString stringWithString: @"BEGIN:VCALENDAR\n"]; + if (timezone) + [content appendFormat: @"%@\n", [timezone versitString]]; + [content appendFormat: @"%@\nEND:VCALENDAR", [event versitString]]; + + return ([object saveContentString: content] == nil) ? uid : nil; } /** @@ -2737,11 +2741,12 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir { NSArray *vtimezones; NSMutableArray *components; - NSMutableDictionary *timezones; - NSString *tz; + NSMutableDictionary *timezones, *uids; + NSString *tzId, *uid, *originalUid, *content; iCalEntityObject *element; iCalDateTime *startDate; iCalTimeZone *timezone; + iCalCalendar *masterCalendar; iCalEvent *event; int imported, count, i; @@ -2757,11 +2762,12 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir for (i = 0; i < count; i++) { timezone = (iCalTimeZone *)[vtimezones objectAtIndex: i]; - [timezones setValue: [NSString stringWithFormat: @"%@\n", [timezone versitString]] + [timezones setValue: timezone forKey: [timezone tzId]]; } // Parse events/todos/journals and import them + uids = [NSMutableDictionary dictionary]; components = [[calendar events] mutableCopy]; [components autorelease]; [components addObjectsFromArray: [calendar todos]]; @@ -2770,14 +2776,15 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir count = [components count]; for (i = 0; i < count; i++) { - tz = nil; + timezone = nil; element = [components objectAtIndex: i]; // Use the timezone of the start date. startDate = (iCalDateTime *) [element uniqueChildWithTag: @"dtstart"]; if (startDate) { - timezone = [startDate timeZone]; - tz = [timezones valueForKey: [timezone tzId]]; + tzId = [startDate value: 0 ofAttribute: @"tzid"]; + if ([tzId length]) + timezone = [timezones valueForKey: tzId]; if ([element isKindOfClass: [iCalEvent class]]) { event = (iCalEvent *)element; @@ -2791,11 +2798,37 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir [self errorWithFormat: @"Importing event with no end date; setting duration to %@", [event duration]]; } + if ([event recurrenceId]) + { + // Event is an occurrence of a repeating event + if ((uid = [uids valueForKey: [event uid]])) + { + SOGoAppointmentObject *master = [self lookupName: uid + inContext: context + acquire: NO]; + if (master) + { + // Associate the occurrence to the master event + masterCalendar = [master calendar: NO secure: NO]; + [masterCalendar addToEvents: event]; + if (timezone) + [masterCalendar addTimeZone: timezone]; + content = [masterCalendar versitString]; + [master saveContentString: content]; + continue; + } + } + } } } - if ([self importComponent: element - timezone: (tz == nil? @"" : tz)]) - imported++; + originalUid = [element uid]; + if ((uid = [self importComponent: element + timezone: timezone])) + { + imported++; + [uids setValue: uid + forKey: originalUid]; + } } }