Monotone-Parent: 5599b85afd7e2707325836a3b533b900d96b8b0c

Monotone-Revision: 570b17715b63da450bef9fde6d9c95288911034f

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2012-08-15T01:02:08
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Wolfgang Sourdeau 2012-08-15 01:02:08 +00:00
parent dac62b634c
commit 45974ec74b
12 changed files with 284 additions and 71 deletions

View File

@ -1,5 +1,10 @@
2012-08-14 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* 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.

View File

@ -47,6 +47,9 @@
/* helpers */
- (NSData *) mimeAttachTag;
/* move & copy operations */
- (void) copyToAttachment: (MAPIStoreAttachment *) newAttachment;
/* subclasses */
- (MAPIStoreEmbeddedMessage *) openEmbeddedMessage;
- (MAPIStoreEmbeddedMessage *) createEmbeddedMessage;

View File

@ -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
{

View File

@ -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;
}

View File

@ -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;

View File

@ -23,6 +23,7 @@
/* TODO: main key arrays must be initialized */
#import <Foundation/NSArray.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSException.h>
@ -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

View File

@ -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;
}

View File

@ -70,6 +70,9 @@
- (NSArray *) activeUserRoles;
/* move & copy internal ops */
- (void) copyToMessage: (MAPIStoreMessage *) newMessage;
/* subclasses */
- (void) save;

View File

@ -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;

View File

@ -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;

View File

@ -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
{

View File

@ -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 ();
}