From 47859b76d62af1462dc9a8a9e67ed68780432798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enrique=20J=2E=20Hern=C3=A1ndez=20Blasco?= Date: Mon, 24 Aug 2015 23:42:38 +0200 Subject: [PATCH] oc-mail: Return right change key after saving a draft mail After saving a draft mail (this is done automatically by Outlook) a GetProps call is done checking the PidTagChangeKey has been updated properly. Without this patch, it returned MAPI_E_NOT_FOUND. With this patch, we addressed that problem and we have updated the Predecessor Change List metadata for the draft mail with the change key provided by the client to avoid conflicting messages whenever it is possible. --- OpenChange/MAPIStoreMailFolder.h | 2 ++ OpenChange/MAPIStoreMailFolder.m | 38 +++++++++++++++++++++++ OpenChange/MAPIStoreMailVolatileMessage.m | 36 ++++++++++++++------- OpenChange/MAPIStoreMessage.m | 3 +- 4 files changed, 67 insertions(+), 12 deletions(-) diff --git a/OpenChange/MAPIStoreMailFolder.h b/OpenChange/MAPIStoreMailFolder.h index c56e74862..717868efb 100644 --- a/OpenChange/MAPIStoreMailFolder.h +++ b/OpenChange/MAPIStoreMailFolder.h @@ -52,6 +52,8 @@ - (NSString *) changeNumberForMessageUID: (NSString *) messageUid; - (void) setChangeKey: (NSData *) changeKey forMessageWithKey: (NSString *) messageKey; +- (BOOL) updatePredecessorChangeListWith: (NSData *) changeKey + forMessageWithKey: (NSString *) messageKey; - (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey; - (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey; diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 963fb7463..06a7d039d 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -999,6 +999,44 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) [versionsMessage save]; } +- (BOOL) updatePredecessorChangeListWith: (NSData *) changeKey + forMessageWithKey: (NSString *) messageKey +{ + /* Update predecessor change list property given the change key. It + returns if the change key has been added to the list or not */ + BOOL added = NO; + NSData *globCnt, *oldGlobCnt; + NSDictionary *messageEntry; + NSMutableDictionary *changeList; + NSString *guid; + struct XID *xid; + + xid = [changeKey asXIDInMemCtx: NULL]; + guid = [NSString stringWithGUID: &xid->NameSpaceGuid]; + globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length]; + talloc_free (xid); + + messageEntry = [self _messageEntryFromMessageKey: messageKey]; + if (messageEntry) + { + changeList = [messageEntry objectForKey: @"PredecessorChangeList"]; + if (changeList) + { + oldGlobCnt = [changeList objectForKey: guid]; + if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending)) + { + [changeList setObject: globCnt forKey: guid]; + [versionsMessage save]; + added = YES; + } + } + else + [self errorWithFormat: @"Missing predecessor change list to update"]; + } + + return added; +} + - (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey { NSDictionary *messages, *changeKeyDict; diff --git a/OpenChange/MAPIStoreMailVolatileMessage.m b/OpenChange/MAPIStoreMailVolatileMessage.m index f2581a54a..8a7ba2c58 100644 --- a/OpenChange/MAPIStoreMailVolatileMessage.m +++ b/OpenChange/MAPIStoreMailVolatileMessage.m @@ -34,6 +34,7 @@ #import #import #import +#import #import #import #import @@ -285,7 +286,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" }; version = [properties objectForKey: @"version"]; return (version - ? exchange_globcnt ([version unsignedLongLongValue]) + ? [version unsignedLongLongValue] : ULLONG_MAX); } @@ -1110,7 +1111,8 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS - (void) save: (TALLOC_CTX *) memCtx { - NSString *folderName, *flag, *newIdString, *messageKey; + BOOL updatedMetadata; + NSString *folderName, *flag, *newIdString, *messageKey, *changeNumber; NSData *changeKey, *messageData; NGImap4Connection *connection; NGImap4Client *client; @@ -1146,21 +1148,33 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS [sogoObject setNameInContainer: messageKey]; [mapping registerURL: [self url] withID: mid]; - /* synchronise the cache and update the change key with the one provided - by the client. Before doing this, lets issue a unselect/select combo - because of timing issues with Dovecot in obtaining the latest modseq. - Sometimes, Dovecot doesn't return the newly appended UID if we do - a "UID SORT (DATE) UTF-8 (MODSEQ XYZ) (NOT DELETED)" command (where - XYZ is the HIGHESTMODSEQ+1) immediately after IMAP APPEND */ + /* synchronise the cache and update the predecessor change list + with the change key provided by the client. Before doing + this, lets issue a unselect/select combo because of timing + issues with Dovecot in obtaining the latest modseq. + Sometimes, Dovecot doesn't return the newly appended UID if + we do a "UID SORT (DATE) UTF-8 (MODSEQ XYZ) (NOT DELETED)" + command (where XYZ is the HIGHESTMODSEQ+1) immediately after + IMAP APPEND */ [client unselect]; [client select: folderName]; [(MAPIStoreMailFolder *) container synchroniseCache]; changeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; if (changeKey) - [(MAPIStoreMailFolder *) container - setChangeKey: changeKey - forMessageWithKey: messageKey]; + { + updatedMetadata = [(MAPIStoreMailFolder *) container updatePredecessorChangeListWith: changeKey + forMessageWithKey: messageKey]; + if (!updatedMetadata) + [self warnWithFormat: @"Predecessor change list not updated with client data"]; + } + + /* Update version property (PR_CHANGE_KEY indeed) as it is + requested once it is saved */ + changeNumber = [(MAPIStoreMailFolder *) container changeNumberForMessageUID: newIdString]; + if (changeNumber) + [properties setObject: [NSNumber numberWithUnsignedLongLong: [changeNumber unsignedLongLongValue] >> 16] + forKey: @"version"]; } } diff --git a/OpenChange/MAPIStoreMessage.m b/OpenChange/MAPIStoreMessage.m index b842b2d6c..a5febc41c 100644 --- a/OpenChange/MAPIStoreMessage.m +++ b/OpenChange/MAPIStoreMessage.m @@ -549,11 +549,12 @@ rtf2html (NSData *compressedRTF) } [self save: memCtx]; - /* We make sure that any change-related properties are removes from the + /* We make sure that any change-related properties are removed from the properties dictionary, to make sure that related methods will be invoked the next time they are requested. */ [properties removeObjectForKey: MAPIPropertyKey (PidTagChangeKey)]; [properties removeObjectForKey: MAPIPropertyKey (PidTagChangeNumber)]; + [properties removeObjectForKey: MAPIPropertyKey (PidTagPredecessorChangeList)]; if ([container isKindOfClass: MAPIStoreFolderK]) {