From 1476b93a45221667a0ae5d00cd71f77e745f894d Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 20 Jul 2012 15:44:25 +0000 Subject: [PATCH] Monotone-Parent: 5b4e61e92b3d68b92ea25f1513eb120e502250a1 Monotone-Revision: 1e529d97ad640de07982d342ce216985cba625f7 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-07-20T15:44:25 Monotone-Branch: ca.inverse.sogo --- OpenChange/MAPIStoreCalendarMessage.m | 68 ++++++++++++++++ OpenChange/MAPIStoreDBFolder.m | 48 ++++++++++- OpenChange/MAPIStoreMessage.m | 111 +++++++++++++++----------- OpenChange/MAPIStoreObjectProxy.m | 1 + OpenChange/MAPIStoreRecurrenceUtils.m | 71 +++++++++++++--- 5 files changed, 238 insertions(+), 61 deletions(-) diff --git a/OpenChange/MAPIStoreCalendarMessage.m b/OpenChange/MAPIStoreCalendarMessage.m index 2ad110bbb..f4dd3fbd6 100644 --- a/OpenChange/MAPIStoreCalendarMessage.m +++ b/OpenChange/MAPIStoreCalendarMessage.m @@ -115,6 +115,30 @@ return self; } +- (void) _setupAttachmentParts +{ + NSUInteger count, max; + NSArray *events; + NSString *newKey; + MAPIStoreCalendarAttachment *attachment; + NSUInteger aid; + + events = [calendar events]; + max = [events count]; + for (count = 1; count < max; count++) + { + attachment = [MAPIStoreCalendarAttachment + mapiStoreObjectInContainer: self]; + /* we now that there are no attachments yet, so we can assume that the + right AID is 0 from the start */ + aid = count - 1; + [attachment setAID: aid]; + [attachment setEvent: [events objectAtIndex: count]]; + newKey = [NSString stringWithFormat: @"%ul", aid]; + [attachmentParts setObject: attachment forKey: newKey]; + } +} + - (id) initWithSOGoObject: (id) newSOGoObject inContainer: (MAPIStoreObject *) newFolder { @@ -140,6 +164,7 @@ origCalendar = [sogoObject calendar: YES secure: YES]; calendar = [origCalendar mutableCopy]; masterEvent = [[calendar events] objectAtIndex: 0]; + [self _setupAttachmentParts]; } context = [self context]; userContext = [self userContext]; @@ -397,9 +422,51 @@ return rc; } +- (void) _updateAttachedEvent: (MAPIStoreCalendarAttachment *) attachment + withUID: (NSString *) uid { iCalEvent *newEvent; + SOGoUser *activeUser; + + newEvent = [iCalEvent groupWithTag: @"vevent"]; + [calendar addToEvents: newEvent]; + activeUser = [[self context] activeUser]; + [newEvent setUid: uid]; + [newEvent updateFromMAPIProperties: [attachment properties] + inUserContext: [self userContext] + withActiveUser: activeUser]; +} + +- (void) _updateAttachedEvents +{ + NSMutableArray *otherEvents; + NSArray *allAttachments; + NSUInteger count, max; + NSString *uid; + + /* cleanup all recurring events */ + otherEvents = [[calendar events] mutableCopy]; + [otherEvents removeObject: masterEvent]; + [calendar removeChildren: otherEvents]; + [otherEvents release]; + + uid = [masterEvent uid]; + + allAttachments = [attachmentParts allValues]; + max = [allAttachments count]; + for (count = 0; count < max; count++) + [self _updateAttachedEvent: [allAttachments objectAtIndex: count] + withUID: uid]; +} + +- (void) save +{ + // iCalCalendar *vCalendar; + // NSCalendarDate *now; + NSString *uid; + // iCalEvent *newEvent; // iCalPerson *userPerson; + SOGoUser *activeUser; if (isNew) { @@ -429,6 +496,7 @@ [masterEvent updateFromMAPIProperties: properties inUserContext: [self userContext] withActiveUser: activeUser]; + [self _updateAttachedEvents]; [sogoObject updateContentWithCalendar: calendar fromRequest: nil]; diff --git a/OpenChange/MAPIStoreDBFolder.m b/OpenChange/MAPIStoreDBFolder.m index 641b9dc59..06dead460 100644 --- a/OpenChange/MAPIStoreDBFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -24,6 +24,7 @@ #import #import +#import #import #import #import @@ -45,7 +46,7 @@ #include #include -static Class EOKeyValueQualifierK; +static Class EOKeyValueQualifierK, SOGoMAPIDBFolderK; static NSString *MAPIStoreRightReadItems = @"RightsReadItems"; static NSString *MAPIStoreRightCreateItems = @"RightsCreateItems"; @@ -62,6 +63,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; + (void) initialize { EOKeyValueQualifierK = [EOKeyValueQualifier class]; + SOGoMAPIDBFolderK = [SOGoMAPIDBFolder class]; } - (void) setupAuxiliaryObjects @@ -84,9 +86,40 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; withFID: (uint64_t) newFID andKey: (NSString **) newKeyP { - *newKeyP = [NSString stringWithFormat: @"0x%.16"PRIx64, (unsigned long long) newFID]; + enum mapistore_error rc; + NSString *folderName, *nameInContainer; + SOGoMAPIDBFolder *newFolder; + struct SPropValue *value; - return MAPISTORE_SUCCESS; + value = get_SPropValue_SRow (aRow, PidTagDisplayName); + if (value) + folderName = [NSString stringWithUTF8String: value->value.lpszW]; + else + { + value = get_SPropValue_SRow (aRow, PidTagDisplayName_string8); + if (value) + folderName = [NSString stringWithUTF8String: value->value.lpszA]; + else + folderName = nil; + } + + if (folderName) + { + nameInContainer = [NSString stringWithFormat: @"0x%.16"PRIx64, + (unsigned long long) newFID]; + newFolder = [SOGoMAPIDBFolderK objectWithName: nameInContainer + inContainer: sogoObject]; + [newFolder setIsNew: YES]; + [[newFolder properties] setObject: folderName + forKey: MAPIPropertyKey (PidTagDisplayName)]; + [newFolder save]; + *newKeyP = nameInContainer; + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_INVALID_PARAMETER; + + return rc; } - (MAPIStoreMessage *) createMessage @@ -134,6 +167,15 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; andSortOrderings: sortOrderings]; } +/* TODO: now that we are DB-based, this method can easily be implemented + +- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum + andCN: (NSNumber **) cnNbrs + inTableType: (enum mapistore_table_type) tableType +{ +} +*/ + - (NSDate *) lastMessageModificationTime { NSUInteger count, max; diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index 957cf8789..1217d295e 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -56,6 +56,7 @@ #include static NSString *resourcesDir = nil; +static Class MAPIStoreFolderK = nil; /* rtf conversion via unrtf */ static int @@ -130,6 +131,7 @@ rtf2html (NSData *compressedRTF) resourcesDir = [[NSBundle bundleForClass: self] resourcePath]; [resourcesDir retain]; } + MAPIStoreFolderK = [MAPIStoreFolder class]; } - (id) init @@ -442,61 +444,68 @@ rtf2html (NSData *compressedRTF) || (!isNew && [self subscriberCanModifyMessage]))) { /* notifications */ - folderId = [(MAPIStoreFolder *) container objectId]; - mstoreCtx = [[self context] connectionInfo]->mstore_ctx; - - /* folder modified */ - notif_parameters - = talloc_zero(NULL, struct mapistore_object_notification_parameters); - notif_parameters->object_id = folderId; - if (isNew) + if ([container isKindOfClass: MAPIStoreFolderK]) { - notif_parameters->tag_count = 3; - notif_parameters->tags = talloc_array (notif_parameters, - enum MAPITAGS, 3); - notif_parameters->tags[0] = PR_CONTENT_COUNT; - notif_parameters->tags[1] = PR_MESSAGE_SIZE; - notif_parameters->tags[2] = PR_NORMAL_MESSAGE_SIZE; - notif_parameters->new_message_count = true; - notif_parameters->message_count - = [[(MAPIStoreFolder *) container messageKeys] count] + 1; - } - mapistore_push_notification (mstoreCtx, - MAPISTORE_FOLDER, MAPISTORE_OBJECT_MODIFIED, - notif_parameters); - talloc_free (notif_parameters); + folderId = [(MAPIStoreFolder *) container objectId]; + mstoreCtx = [[self context] connectionInfo]->mstore_ctx; - /* message created */ - if (isNew) - { + /* folder modified */ notif_parameters - = talloc_zero(NULL, - struct mapistore_object_notification_parameters); - notif_parameters->object_id = [self objectId]; - notif_parameters->folder_id = folderId; - - notif_parameters->tag_count = 0xffff; + = talloc_zero(NULL, struct mapistore_object_notification_parameters); + notif_parameters->object_id = folderId; + if (isNew) + { + notif_parameters->tag_count = 3; + notif_parameters->tags = talloc_array (notif_parameters, + enum MAPITAGS, 3); + notif_parameters->tags[0] = PR_CONTENT_COUNT; + notif_parameters->tags[1] = PR_MESSAGE_SIZE; + notif_parameters->tags[2] = PR_NORMAL_MESSAGE_SIZE; + notif_parameters->new_message_count = true; + notif_parameters->message_count + = [[(MAPIStoreFolder *) container messageKeys] count] + 1; + } mapistore_push_notification (mstoreCtx, - MAPISTORE_MESSAGE, MAPISTORE_OBJECT_CREATED, + MAPISTORE_FOLDER, + MAPISTORE_OBJECT_MODIFIED, notif_parameters); talloc_free (notif_parameters); - } - /* we ensure the table caches are loaded so that old and new state - can be compared */ - containerTables = [self activeContainerMessageTables]; - max = [containerTables count]; - for (count = 0; count < max; count++) - [[containerTables objectAtIndex: count] restrictedChildKeys]; + /* message created */ + if (isNew) + { + notif_parameters + = talloc_zero(NULL, + struct mapistore_object_notification_parameters); + notif_parameters->object_id = [self objectId]; + notif_parameters->folder_id = folderId; + + notif_parameters->tag_count = 0xffff; + mapistore_push_notification (mstoreCtx, + MAPISTORE_MESSAGE, MAPISTORE_OBJECT_CREATED, + notif_parameters); + talloc_free (notif_parameters); + } + + /* we ensure the table caches are loaded so that old and new state + can be compared */ + containerTables = [self activeContainerMessageTables]; + max = [containerTables count]; + for (count = 0; count < max; count++) + [[containerTables objectAtIndex: count] restrictedChildKeys]; + } [self save]; - /* table modified */ - for (count = 0; count < max; count++) - [[containerTables objectAtIndex: count] - notifyChangesForChild: self]; + if ([container isKindOfClass: MAPIStoreFolderK]) + { + /* table modified */ + for (count = 0; count < max; count++) + [[containerTables objectAtIndex: count] + notifyChangesForChild: self]; + [container cleanupCaches]; + } [self setIsNew: NO]; - [container cleanupCaches]; rc = MAPISTORE_SUCCESS; } else @@ -645,9 +654,19 @@ rtf2html (NSData *compressedRTF) - (int) getPidTagMid: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - *data = MAPILongLongValue (memCtx, [self objectId]); + int rc; + uint64_t obId; - return MAPISTORE_SUCCESS; + obId = [self objectId]; + if (obId == ULLONG_MAX) + rc = MAPISTORE_ERR_NOT_FOUND; + else + { + *data = MAPILongLongValue (memCtx, obId); + rc = MAPISTORE_SUCCESS; + } + + return rc; } - (int) getPidTagMessageLocaleId: (void **) data diff --git a/OpenChange/MAPIStoreObjectProxy.m b/OpenChange/MAPIStoreObjectProxy.m index 415d26df6..945d16167 100644 --- a/OpenChange/MAPIStoreObjectProxy.m +++ b/OpenChange/MAPIStoreObjectProxy.m @@ -21,6 +21,7 @@ */ #import "MAPIStorePropertySelectors.h" +#import "NSString+MAPIStore.h" #import "MAPIStoreObjectProxy.h" diff --git a/OpenChange/MAPIStoreRecurrenceUtils.m b/OpenChange/MAPIStoreRecurrenceUtils.m index 00ddf437a..d07d640f6 100644 --- a/OpenChange/MAPIStoreRecurrenceUtils.m +++ b/OpenChange/MAPIStoreRecurrenceUtils.m @@ -22,6 +22,7 @@ #import #import +#import #import #import @@ -50,11 +51,13 @@ { NSCalendarDate *startDate, *olEndDate, *untilDate, *exDate; NSString *monthDay, *month; + NSMutableSet *exceptionDates; + NSArray *realExDates; iCalRecurrenceRule *rule; iCalByDayMask *byDayMask; iCalWeekOccurrence weekOccurrence; iCalWeekOccurrences dayMaskDays; - NSUInteger count; + NSUInteger count, max; NSInteger bySetPos; unsigned char maskValue; @@ -209,7 +212,12 @@ rp->EndType]; } - /* exception dates */ + /* exception dates: + - take all deleted instances + - remove all modified instances from the above set + - add remaining instances, in chronological order + */ + exceptionDates = [NSMutableSet set]; for (count = 0; count < rp->DeletedInstanceCount; count++) { exDate @@ -217,8 +225,23 @@ exDate = [exDate hour: [startDate hourOfDay] minute: [startDate minuteOfHour] second: [startDate secondOfMinute]]; - [entity addToExceptionDates: exDate]; + [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]]; } @end @@ -233,11 +256,14 @@ iCalRecurrenceFrequency freq; iCalByDayMask *byDayMask; NSString *byMonthDay, *bySetPos; - NSCalendarDate *startDate, *endDate, *untilDate, *beginOfWeek, *minimumDate, *moduloDate, *midnight; + NSCalendarDate *startDate, *endDate, *untilDate, *beginOfWeek, *minimumDate, + *moduloDate, *midnight; iCalWeekOccurrences *days; - NSInteger dayOfWeek, repeatInterval, repeatCount, count, firstOccurrence, max; + NSInteger dayOfWeek, repeatInterval, repeatCount, count, firstOccurrence, + max; uint32_t nbrMonths, mask; - NSArray *exDates; + NSArray *events; + NSMutableArray *deletedDates, *modifiedDates; startDate = [event firstRecurrenceStartDate]; [startDate setTimeZone: timeZone]; @@ -394,16 +420,37 @@ } } - - exDates = [[event exceptionDatesWithTimeZone: utcTZ] - sortedArrayUsingFunction: NSDateCompare - context: NULL]; - max = [exDates count]; + events = [[event parent] events]; + max = [events count]; + modifiedDates = [NSMutableArray arrayWithCapacity: max]; + for (count = 1; count < max; count++) + { + startDate = [[events objectAtIndex: count] recurrenceId]; + [modifiedDates addObject: startDate]; + } + max = [modifiedDates count]; + rp->ModifiedInstanceCount = max; + rp->ModifiedInstanceDates = talloc_array (memCtx, uint32_t, max); + for (count = 0; count < max; count++) + { + startDate = [[modifiedDates objectAtIndex: count] + hour: 0 minute: 0 second: 0]; + *(rp->ModifiedInstanceDates + count) = [startDate asMinutesSince1601]; + } + + deletedDates = [modifiedDates mutableCopy]; + [deletedDates autorelease]; + [deletedDates + addObjectsFromArray: [event exceptionDatesWithTimeZone: utcTZ]]; + [deletedDates sortUsingFunction: NSDateCompare context: NULL]; + + max = [deletedDates count]; rp->DeletedInstanceCount = max; rp->DeletedInstanceDates = talloc_array (memCtx, uint32_t, max); for (count = 0; count < max; count++) { - startDate = [[exDates objectAtIndex: count] hour: 0 minute: 0 second: 0]; + startDate = [[deletedDates objectAtIndex: count] + hour: 0 minute: 0 second: 0]; *(rp->DeletedInstanceDates + count) = [startDate asMinutesSince1601]; } }