From 45974ec74b49d383cf5fbfa75f8d4d85c3774ac3 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Wed, 15 Aug 2012 01:02:08 +0000 Subject: [PATCH] Monotone-Parent: 5599b85afd7e2707325836a3b533b900d96b8b0c Monotone-Revision: 570b17715b63da450bef9fde6d9c95288911034f Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2012-08-15T01:02:08 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 5 + OpenChange/MAPIStoreAttachment.h | 3 + OpenChange/MAPIStoreAttachment.m | 24 ++++ OpenChange/MAPIStoreDBFolder.m | 12 +- OpenChange/MAPIStoreFolder.h | 6 +- OpenChange/MAPIStoreFolder.m | 183 +++++++++++++++++++++---------- OpenChange/MAPIStoreMailFolder.m | 19 ++-- OpenChange/MAPIStoreMessage.h | 3 + OpenChange/MAPIStoreMessage.m | 35 ++++++ OpenChange/MAPIStoreObject.h | 3 + OpenChange/MAPIStoreObject.m | 56 ++++++++++ OpenChange/MAPIStoreSOGo.m | 6 +- 12 files changed, 284 insertions(+), 71 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5169befd9..815c1a29e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2012-08-14 Wolfgang Sourdeau + * OpenChange/MAPIStoreFolder.m (-moveToFolder:withNewName:): + renamed to "moveCopyToFolder:withNewName:isMove:isRecursive:", + with the ability to specify whether the operation is a move or + copy operation and whether it is recursive or not (for copy). + * OpenChange/MAPIStoreSOGo.m (sogo_folder_move_folder): if "target_folder_object", we do not attempt to access the corresponding instance member. diff --git a/OpenChange/MAPIStoreAttachment.h b/OpenChange/MAPIStoreAttachment.h index 76afd8539..5ee546c0e 100644 --- a/OpenChange/MAPIStoreAttachment.h +++ b/OpenChange/MAPIStoreAttachment.h @@ -47,6 +47,9 @@ /* helpers */ - (NSData *) mimeAttachTag; +/* move & copy operations */ +- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment; + /* subclasses */ - (MAPIStoreEmbeddedMessage *) openEmbeddedMessage; - (MAPIStoreEmbeddedMessage *) createEmbeddedMessage; diff --git a/OpenChange/MAPIStoreAttachment.m b/OpenChange/MAPIStoreAttachment.m index b7a2a75d4..a3c17ec45 100644 --- a/OpenChange/MAPIStoreAttachment.m +++ b/OpenChange/MAPIStoreAttachment.m @@ -158,6 +158,30 @@ return ULLONG_MAX; } +- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment +{ + void *attachMethod; + enum mapistore_error error; + MAPIStoreEmbeddedMessage *embeddedMessage, *newEmbeddedMessage; + + [self copyPropertiesToObject: newAttachment]; + + attachMethod = NULL; + error = [self getProperty: &attachMethod + withTag: PidTagAttachMethod + inMemCtx: NULL]; + if (error == MAPISTORE_SUCCESS && attachMethod) + { + if (*(uint32_t *) attachMethod == afEmbeddedMessage) + { + embeddedMessage = [self openEmbeddedMessage]; + newEmbeddedMessage = [newAttachment createEmbeddedMessage]; + [embeddedMessage copyToMessage: newEmbeddedMessage]; + } + talloc_free (attachMethod); + } +} + /* subclasses */ - (MAPIStoreEmbeddedMessage *) openEmbeddedMessage { diff --git a/OpenChange/MAPIStoreDBFolder.m b/OpenChange/MAPIStoreDBFolder.m index 3cb90b949..8b89202f4 100644 --- a/OpenChange/MAPIStoreDBFolder.m +++ b/OpenChange/MAPIStoreDBFolder.m @@ -126,8 +126,10 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; return rc; } -- (enum mapistore_error) moveToFolder: (MAPIStoreFolder *) targetFolder - withNewName: (NSString *) newFolderName +- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName + isMove: (BOOL) isMove + isRecursive: (BOOL) isRecursive { enum mapistore_error rc; NSString *path, *pathComponent, *targetPath, *newPath; @@ -135,7 +137,7 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; MAPIStoreMapping *mapping; NSRange slashRange; - if ([targetFolder isKindOfClass: MAPIStoreDBFolderK]) + if (isMove && [targetFolder isKindOfClass: MAPIStoreDBFolderK]) { path = [sogoObject path]; slashRange = [path rangeOfString: @"/" options: NSBackwardsSearch]; @@ -158,7 +160,9 @@ static NSString *MAPIStoreRightFolderContact = @"RightsFolderContact"; rc = MAPISTORE_SUCCESS; } else - rc = MAPISTORE_ERR_DENIED; + rc = [super moveCopyToFolder: targetFolder withNewName: newFolderName + isMove: isMove + isRecursive: isRecursive]; return rc; } diff --git a/OpenChange/MAPIStoreFolder.h b/OpenChange/MAPIStoreFolder.h index bb2aefec1..b31f8ce49 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -123,8 +123,10 @@ andChangeKeys: (struct Binary_r **) targetChangeKeys wantCopy: (uint8_t) want_copy; -- (enum mapistore_error) moveToFolder: (MAPIStoreFolder *) targetFolder - withNewName: (NSString *) newFolderName; +- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName + isMove: (BOOL) isMove + isRecursive: (BOOL) isRecursive; - (enum mapistore_error) copyToFolder: (MAPIStoreFolder *) targetFolder recursive: (BOOL) resursive withNewName: (NSString *) newFolderName; diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index d39683bff..606c4a7cd 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -23,6 +23,7 @@ /* TODO: main key arrays must be initialized */ #import +#import #import #import #import @@ -653,13 +654,8 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe int rc; MAPIStoreMessage *sourceMsg, *destMsg; TALLOC_CTX *memCtx; - struct SPropTagArray *availableProps; - bool *exclusions; - NSUInteger count; - enum MAPITAGS propTag; - struct SRow *aRow; - int error; - void *data; + struct SRow aRow; + struct SPropValue property; memCtx = talloc_zero (NULL, TALLOC_CTX); rc = [sourceFolder openMessage: &sourceMsg @@ -669,56 +665,23 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe if (rc != MAPISTORE_SUCCESS) goto end; - rc = [sourceMsg getAvailableProperties: &availableProps - inMemCtx: memCtx]; - if (rc != MAPISTORE_SUCCESS) - goto end; - - exclusions = talloc_array(NULL, bool, 65536); - exclusions[PR_ROW_TYPE >> 16] = true; - exclusions[PR_INSTANCE_KEY >> 16] = true; - exclusions[PR_INSTANCE_NUM >> 16] = true; - exclusions[PR_INST_ID >> 16] = true; - exclusions[PR_FID >> 16] = true; - exclusions[PR_MID >> 16] = true; - exclusions[PR_SOURCE_KEY >> 16] = true; - exclusions[PR_PARENT_SOURCE_KEY >> 16] = true; - exclusions[PR_PARENT_FID >> 16] = true; - exclusions[PR_CHANGE_KEY >> 16] = true; - exclusions[PR_PREDECESSOR_CHANGE_LIST >> 16] = true; - - aRow = talloc_zero (memCtx, struct SRow); - aRow->lpProps = talloc_array (aRow, struct SPropValue, 65535); - - for (count = 0; count < availableProps->cValues; count++) - { - propTag = availableProps->aulPropTag[count]; - if (!exclusions[propTag >> 16]) - { - error = [sourceMsg getProperty: &data - withTag: propTag - inMemCtx: aRow]; - if (error == MAPISTORE_SUCCESS && data) - { - set_SPropValue_proptag(&aRow->lpProps[aRow->cValues], propTag, data); - aRow->cValues++; - } - } - } - - if (targetChangeKey) - { - set_SPropValue_proptag(&aRow->lpProps[aRow->cValues], PR_CHANGE_KEY, targetChangeKey); - aRow->cValues++; - } - rc = [self createMessage: &destMsg withMID: targetMid isAssociated: [sourceMsg isKindOfClass: MAPIStoreFAIMessageK]]; if (rc != MAPISTORE_SUCCESS) goto end; - rc = [destMsg addPropertiesFromRow: aRow]; - if (rc != MAPISTORE_SUCCESS) - goto end; + + [sourceMsg copyToMessage: destMsg]; + + if (targetChangeKey) + { + property.ulPropTag = PidTagChangeKey; + property.value.bin = *targetChangeKey; + aRow.cValues = 1; + aRow.lpProps = &property; + rc = [destMsg addPropertiesFromRow: &aRow]; + if (rc != MAPISTORE_SUCCESS) + goto end; + } [destMsg save]; if (!wantCopy) rc = [sourceFolder deleteMessageWithMID: srcMid andFlags: 0]; @@ -795,10 +758,118 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return rc; } -- (enum mapistore_error) moveToFolder: (MAPIStoreFolder *) targetFolder - withNewName: (NSString *) newFolderName +- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName + isMove: (BOOL) isMove + isRecursive: (BOOL) isRecursive { - return MAPISTORE_ERR_DENIED; + enum mapistore_error rc; + NSAutoreleasePool *pool; + struct SRow folderRow; + struct SPropValue nameProperty; + MAPIStoreFolder *subFolder, *newFolder; + NSArray *children; + MAPIStoreMapping *mapping; + MAPIStoreMessage *message, *targetMessage; + NSUInteger count, max; + NSString *childKey; + uint64_t fmid; + + /* TODO: one possible issue with this algorithm is that moved messages will + lack a version number and will all be assigned a new one, even though + they have not changed. This also means that they will be transferred + again to the client during a sync operation. */ + + if ([targetFolder supportsSubFolders]) + { + mapping = [self mapping]; + + if (!newFolderName) + newFolderName = [sogoObject displayName]; + nameProperty.ulPropTag = PidTagDisplayName; + nameProperty.value.lpszW = [newFolderName UTF8String]; + folderRow.lpProps = &nameProperty; + folderRow.cValues = 1; + rc = [targetFolder createFolder: &folderRow + withFID: [self objectId] + andKey: &childKey]; + if (rc == MAPISTORE_SUCCESS) + { + newFolder = [targetFolder lookupFolder: childKey]; + [self copyPropertiesToObject: newFolder]; + + pool = [NSAutoreleasePool new]; + children = [self messageKeys]; + max = [children count]; + for (count = 0; count < max; count++) + { + childKey = [children objectAtIndex: count]; + message = [self lookupMessage: childKey]; + targetMessage = [newFolder createMessage: NO]; + [message copyToMessage: targetMessage]; + if (isMove) + { + fmid = [mapping idFromURL: [message url]]; + [self deleteMessageWithMID: fmid andFlags: 0]; + [mapping registerURL: [targetMessage url] + withID: fmid]; + } + [targetMessage save]; + } + [pool release]; + + pool = [NSAutoreleasePool new]; + children = [self faiMessageKeys]; + max = [children count]; + for (count = 0; count < max; count++) + { + childKey = [children objectAtIndex: count]; + message = [self lookupFAIMessage: childKey]; + targetMessage = [newFolder createMessage: YES]; + [message copyToMessage: targetMessage]; + if (isMove) + { + fmid = [mapping idFromURL: [message url]]; + [self deleteMessageWithMID: fmid andFlags: 0]; + [mapping registerURL: [targetMessage url] + withID: fmid]; + } + [targetMessage save]; + } + [pool release]; + + if (isRecursive) + { + pool = [NSAutoreleasePool new]; + children = [self folderKeys]; + max = [children count]; + for (count = 0; count < max; count++) + { + childKey = [children objectAtIndex: count]; + subFolder = [self lookupFolder: childKey]; + [subFolder moveCopyToFolder: newFolder withNewName: nil + isMove: isMove + isRecursive: isRecursive]; + } + [pool release]; + } + + if (isMove) + { + fmid = [mapping idFromURL: [self url]]; + [mapping unregisterURLWithID: fmid]; + [self deleteFolder]; + [mapping registerURL: [newFolder url] + withID: fmid]; + } + [targetFolder cleanupCaches]; + } + [self cleanupCaches]; + } + else + rc = MAPISTORE_ERR_DENIED; + + return rc; } - (enum mapistore_error) copyToFolder: (MAPIStoreFolder *) targetFolder diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 8aea7e359..787d1db45 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -207,7 +207,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; } - (int) getPidTagContentUnreadCount: (void **) data - inMemCtx: (TALLOC_CTX *) memCtx + inMemCtx: (TALLOC_CTX *) memCtx { EOQualifier *searchQualifier; uint32_t longValue; @@ -1012,8 +1012,10 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) return MAPISTORE_SUCCESS; } -- (enum mapistore_error) moveToFolder: (MAPIStoreFolder *) targetFolder - withNewName: (NSString *) newFolderName +- (enum mapistore_error) moveCopyToFolder: (MAPIStoreFolder *) targetFolder + withNewName: (NSString *) newFolderName + isMove: (BOOL) isMove + isRecursive: (BOOL) isRecursive { enum mapistore_error rc; NSURL *folderURL, *newFolderURL; @@ -1022,12 +1024,11 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) NSException *error; MAPIStoreMapping *mapping; - if ([targetFolder isKindOfClass: MAPIStoreMailFolderK]) + if (isMove && [targetFolder isKindOfClass: MAPIStoreMailFolderK]) { folderURL = [sogoObject imap4URL]; if (!newFolderName) - newFolderName = [[sogoObject nameInContainer] - substringFromIndex: 6]; /* length of "folder" */ + newFolderName = [sogoObject displayName]; newFolderName = [newFolderName stringByEscapingURL]; targetSOGoFolder = [targetFolder sogoObject]; newFolderURL = [NSURL URLWithString: newFolderName @@ -1053,9 +1054,13 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) parentDBFolderPath, newFolderName]]; } + [targetFolder cleanupCaches]; + [self cleanupCaches]; } else - rc = MAPISTORE_ERR_DENIED; + rc = [super moveCopyToFolder: targetFolder withNewName: newFolderName + isMove: isMove + isRecursive: isRecursive]; return rc; } diff --git a/OpenChange/MAPIStoreMessage.h b/OpenChange/MAPIStoreMessage.h index 51fa56ec3..28230622e 100644 --- a/OpenChange/MAPIStoreMessage.h +++ b/OpenChange/MAPIStoreMessage.h @@ -70,6 +70,9 @@ - (NSArray *) activeUserRoles; +/* move & copy internal ops */ +- (void) copyToMessage: (MAPIStoreMessage *) newMessage; + /* subclasses */ - (void) save; diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index febdb629c..20c518baa 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -425,6 +425,41 @@ rtf2html (NSData *compressedRTF) andType: MAPISTORE_MESSAGE_TABLE]; } +- (void) copyToMessage: (MAPIStoreMessage *) newMessage + +{ + TALLOC_CTX *memCtx; + struct mapistore_message *messageData; + NSArray *keys; + NSUInteger count, max; + NSString *key; + MAPIStoreAttachment *attachment, *newAttachment; + + memCtx = talloc_zero (NULL, TALLOC_CTX); + + /* message headers and recipients */ + [self getMessageData: &messageData inMemCtx: memCtx]; + [newMessage modifyRecipientsWithRecipients: messageData->recipients + andCount: messageData->recipients_count + andColumns: messageData->columns]; + + /* properties */ + [self copyPropertiesToObject: newMessage]; + + /* attachments */ + keys = [self attachmentKeys]; + max = [keys count]; + for (count = 0; count < max; count++) + { + key = [keys objectAtIndex: count]; + attachment = [self lookupAttachment: key]; + newAttachment = [newMessage createAttachment]; + [attachment copyToAttachment: newAttachment]; + } + + talloc_free (memCtx); +} + - (enum mapistore_error) saveMessage { enum mapistore_error rc; diff --git a/OpenChange/MAPIStoreObject.h b/OpenChange/MAPIStoreObject.h index ddb28ada0..ccbc5a157 100644 --- a/OpenChange/MAPIStoreObject.h +++ b/OpenChange/MAPIStoreObject.h @@ -90,6 +90,9 @@ - (int) getPidTagLastModificationTime: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; +/* move and copy operations */ +- (void) copyPropertiesToObject: (MAPIStoreObject *) newObject; + /* subclasses */ - (NSString *) nameInContainer; - (NSDate *) creationTime; diff --git a/OpenChange/MAPIStoreObject.m b/OpenChange/MAPIStoreObject.m index eba69c966..9f1b04969 100644 --- a/OpenChange/MAPIStoreObject.m +++ b/OpenChange/MAPIStoreObject.m @@ -315,6 +315,62 @@ static Class NSExceptionK, MAPIStoreFolderK; return MAPISTORE_SUCCESS; } +/* move and copy operations */ +- (void) copyPropertiesToObject: (MAPIStoreObject *) newObject +{ + TALLOC_CTX *memCtx; + struct SPropTagArray *availableProps; + struct SRow row; + enum MAPITAGS propTag; + bool *exclusions; + NSUInteger count; + enum mapistore_error error; + void *data; + + memCtx = talloc_zero (NULL, TALLOC_CTX); + + [self getAvailableProperties: &availableProps inMemCtx: memCtx]; + + /* We exclude identity and versioning properties to facilitate copy + operations. If they need to be set (move operations), the caller will need + to take care of them. */ + exclusions = talloc_array (memCtx, bool, 65536); + exclusions[PidTagRowType >> 16] = true; + exclusions[PidTagInstanceKey >> 16] = true; + exclusions[PidTagInstanceNum >> 16] = true; + exclusions[PidTagInstID >> 16] = true; + exclusions[PidTagAttachNumber >> 16] = true; + exclusions[PidTagFolderId >> 16] = true; + exclusions[PidTagMid >> 16] = true; + exclusions[PidTagSourceKey >> 16] = true; + exclusions[PidTagParentSourceKey >> 16] = true; + exclusions[PidTagParentFolderId >> 16] = true; + exclusions[PidTagChangeKey >> 16] = true; + exclusions[PidTagChangeNumber >> 16] = true; + exclusions[PidTagPredecessorChangeList >> 16] = true; + + row.cValues = 0; + row.lpProps = talloc_array (memCtx, struct SPropValue, 65535); + + for (count = 0; count < availableProps->cValues; count++) + { + propTag = availableProps->aulPropTag[count]; + if (!exclusions[propTag >> 16]) + { + error = [self getProperty: &data withTag: propTag inMemCtx: memCtx]; + if (error == MAPISTORE_SUCCESS && data) + { + set_SPropValue_proptag (row.lpProps + row.cValues, propTag, data); + row.cValues++; + } + } + } + [newObject addPropertiesFromRow: &row]; + + talloc_free (memCtx); + +} + /* subclasses */ - (NSString *) nameInContainer { diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 38bdd765a..2d4e11dec 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -639,8 +639,10 @@ sogo_folder_move_folder(void *folder_object, void *target_folder_object, else newFolderName = nil; - rc = [moveFolder moveToFolder: targetFolder - withNewName: newFolderName]; + rc = [moveFolder moveCopyToFolder: targetFolder + withNewName: newFolderName + isMove: YES + isRecursive: YES]; [pool release]; GSUnregisterCurrentThread (); }