(fix) appplied fix from Zentyal - PR#102

Original commit: 33a1d2c397
pull/105/head
Ludovic Marcotte 2015-09-09 08:22:33 -04:00
parent b8b45eda75
commit 18a300ca5b
22 changed files with 571 additions and 111 deletions

View File

@ -671,7 +671,7 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
return newAttachment;
}
- (int) setReadFlag: (uint8_t) flag
- (enum mapistore_error) setReadFlag: (uint8_t) flag
{
return MAPISTORE_SUCCESS;
}

View File

@ -22,6 +22,7 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSValue.h>
@ -34,6 +35,7 @@
#import "MAPIStoreDBFolder.h"
#import "MAPIStoreDBMessage.h"
#import "MAPIStoreTypes.h"
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
@ -104,6 +106,105 @@
return objectVersion;
}
- (void) _updatePredecessorChangeList
{
BOOL updated;
enum mapistore_error rc;
NSData *currentChangeList, *changeKey;
NSMutableArray *changeKeys;
NSMutableData *newChangeList;
NSUInteger count, len;
struct SizedXid *changes;
struct SPropValue property;
struct SRow aRow;
struct XID *currentChangeKey;
TALLOC_CTX *localMemCtx;
uint32_t nChanges;
localMemCtx = talloc_new (NULL);
if (!localMemCtx)
{
[self errorWithFormat: @"No more memory"];
return;
}
changeKey = [self getReplicaKeyFromGlobCnt: [self objectVersion]];
currentChangeList = [properties objectForKey: MAPIPropertyKey (PidTagPredecessorChangeList)];
if (!currentChangeList)
{
/* Create a new PredecessorChangeList */
len = [changeKey length];
newChangeList = [NSMutableData dataWithCapacity: len + 1];
[newChangeList appendUInt8: len];
[newChangeList appendData: changeKey];
}
else
{
/* Update current predecessor change list with new change key */
changes = [currentChangeList asSizedXidArrayInMemCtx: localMemCtx
with: &nChanges];
updated = NO;
currentChangeKey = [changeKey asXIDInMemCtx: localMemCtx];
for (count = 0; count < nChanges && !updated; count++)
{
if (GUID_equal(&changes[count].XID.NameSpaceGuid, &currentChangeKey->NameSpaceGuid))
{
NSData *globCnt, *oldGlobCnt;
oldGlobCnt = [NSData dataWithBytes: changes[count].XID.LocalId.data length: changes[count].XID.LocalId.length];
globCnt = [NSData dataWithBytes: currentChangeKey->LocalId.data length: currentChangeKey->LocalId.length];
if ([globCnt compare: oldGlobCnt] == NSOrderedDescending)
{
if ([globCnt length] != [oldGlobCnt length])
{
[self errorWithFormat: @"Cannot compare globcnt with different length: %@ and %@", globCnt, oldGlobCnt];
abort();
}
memcpy (changes[count].XID.LocalId.data, currentChangeKey->LocalId.data, currentChangeKey->LocalId.length);
updated = YES;
}
}
}
/* Serialise it */
changeKeys = [NSMutableArray array];
if (!updated)
[changeKeys addObject: changeKey];
for (count = 0; count < nChanges; count++)
{
changeKey = [NSData dataWithXID: &changes[count].XID];
[changeKeys addObject: changeKey];
}
[changeKeys sortUsingFunction: MAPIChangeKeyGUIDCompare context: localMemCtx];
newChangeList = [NSMutableData data];
len = [changeKeys count];
for (count = 0; count < len; count++)
{
changeKey = [changeKeys objectAtIndex: count];
[newChangeList appendUInt8: [changeKey length]];
[newChangeList appendData: changeKey];
}
}
if ([newChangeList length] > 0)
{
property.ulPropTag = PidTagPredecessorChangeList;
property.value.bin = *[newChangeList asBinaryInMemCtx: localMemCtx];
aRow.cValues = 1;
aRow.lpProps = &property;
rc = [self addPropertiesFromRow: &aRow];
if (rc != MAPISTORE_SUCCESS)
[self errorWithFormat: @"Impossible to add a new predecessor change list: %d", rc];
}
talloc_free (localMemCtx);
}
//
// FIXME: how this can happen?
//
@ -166,6 +267,9 @@
[properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion]
forKey: @"version"];
/* Update PredecessorChangeList accordingly */
[self _updatePredecessorChangeList];
[self logWithFormat: @"%d props in dict", [properties count]];
[sogoObject save];
@ -209,4 +313,36 @@
return [sogoObject lastModified];
}
- (enum mapistore_error) setReadFlag: (uint8_t) flag
{
/* Modify PidTagMessageFlags from SetMessageReadFlag and
SyncImportReadStateChanges ROPs */
NSNumber *flags;
uint32_t newFlag;
flags = [properties objectForKey: MAPIPropertyKey (PR_MESSAGE_FLAGS)];
if (flags)
{
newFlag = [flags unsignedLongValue];
if (flag & SUPPRESS_RECEIPT)
newFlag |= MSGFLAG_READ;
if (flag & CLEAR_RN_PENDING)
newFlag &= ~MSGFLAG_RN_PENDING;
if (flag & CLEAR_READ_FLAG)
newFlag &= ~MSGFLAG_READ;
if (flag & CLEAR_NRN_PENDING)
newFlag &= ~MSGFLAG_NRN_PENDING;
}
else
{
newFlag = MSGFLAG_READ;
if (flag & CLEAR_READ_FLAG)
newFlag = 0x0;
}
[properties setObject: [NSNumber numberWithUnsignedLong: newFlag]
forKey: MAPIPropertyKey (PR_MESSAGE_FLAGS)];
return MAPISTORE_SUCCESS;
}
@end

View File

@ -121,6 +121,7 @@
fromFolder: (MAPIStoreFolder *) sourceFolder
withMIDs: (uint64_t *) targetMids
andChangeKeys: (struct Binary_r **) targetChangeKeys
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
wantCopy: (uint8_t) want_copy
inMemCtx: (TALLOC_CTX *) memCtx;

View File

@ -642,6 +642,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
fromFolder: (MAPIStoreFolder *) sourceFolder
withMID: (uint64_t) targetMid
andChangeKey: (struct Binary_r *) targetChangeKey
andPredecessorChangeList: (struct Binary_r *) targetPredecessorChangeList
wantCopy: (uint8_t) wantCopy
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -669,15 +670,18 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
[sourceMsg copyToMessage: destMsg inMemCtx: memCtx];
if (targetChangeKey)
if (targetPredecessorChangeList)
{
property.ulPropTag = PidTagChangeKey;
property.value.bin = *targetChangeKey;
property.ulPropTag = PidTagPredecessorChangeList;
property.value.bin = *targetPredecessorChangeList;
aRow.cValues = 1;
aRow.lpProps = &property;
rc = [destMsg addPropertiesFromRow: &aRow];
if (rc != MAPISTORE_SUCCESS)
goto end;
{
[self errorWithFormat: @"Cannot add PredecessorChangeList on move"];
goto end;
}
}
[destMsg save: memCtx];
if (!wantCopy)
@ -696,6 +700,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
fromFolder: (MAPIStoreFolder *) sourceFolder
withMIDs: (uint64_t *) targetMids
andChangeKeys: (struct Binary_r **) targetChangeKeys
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
wantCopy: (uint8_t) wantCopy
inMemCtx: (TALLOC_CTX *) memCtx
{
@ -705,7 +710,7 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
NSString *oldMessageURL;
MAPIStoreMapping *mapping;
SOGoUser *ownerUser;
struct Binary_r *targetChangeKey;
struct Binary_r *targetChangeKey, *targetPredecessorChangeList;
//TALLOC_CTX *memCtx;
//memCtx = talloc_zero (NULL, TALLOC_CTX);
@ -726,14 +731,21 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe
if (oldMessageURL)
{
[oldMessageURLs addObject: oldMessageURL];
if (targetChangeKeys)
targetChangeKey = targetChangeKeys[count];
if (targetChangeKeys && targetPredecessorChangeList)
{
targetChangeKey = targetChangeKeys[count];
targetPredecessorChangeList = targetPredecessorChangeLists[count];
}
else
targetChangeKey = NULL;
{
targetChangeKey = NULL;
targetPredecessorChangeList = NULL;
}
rc = [self _moveCopyMessageWithMID: srcMids[count]
fromFolder: sourceFolder
withMID: targetMids[count]
andChangeKey: targetChangeKey
andPredecessorChangeList: targetPredecessorChangeList
wantCopy: wantCopy
inMemCtx: memCtx];
}

View File

@ -42,7 +42,8 @@
/* synchronisation */
- (BOOL) synchroniseCache;
- (void) updateVersionsForMessageWithKey: (NSString *) messageKey
withChangeKey: (NSData *) newChangeKey;
withChangeKey: (NSData *) oldChangeKey
andPredecessorChangeList: (NSData *) pcl;
- (NSNumber *) lastModifiedFromMessageChangeNumber: (NSString *) changeNumber;
- (NSString *) changeNumberForMessageWithKey: (NSString *) messageKey;
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey;

View File

@ -75,6 +75,7 @@ static Class NSNumberK;
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
inContainer: dbFolder]);
[versionsMessage setObjectType: MAPIInternalCacheObject];
[versionsMessage reloadIfNeeded];
}
- (void) dealloc
@ -261,7 +262,6 @@ static Class NSNumberK;
*/
- (void) _setChangeKey: (NSData *) changeKey
forMessageEntry: (NSMutableDictionary *) messageEntry
inChangeListOnly: (BOOL) inChangeListOnly
{
struct XID *xid;
NSString *guid;
@ -270,19 +270,15 @@ static Class NSNumberK;
NSMutableDictionary *changeList;
xid = [changeKey asXIDInMemCtx: NULL];
guid = [NSString stringWithGUID: &xid->GUID];
globCnt = [NSData dataWithBytes: xid->Data length: xid->Size];
guid = [NSString stringWithGUID: &xid->NameSpaceGuid];
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
talloc_free (xid);
if (!inChangeListOnly)
{
/* 1. set change key association */
changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys:
guid, @"GUID",
globCnt, @"LocalId",
nil];
[messageEntry setObject: changeKeyDict forKey: @"ChangeKey"];
}
/* 1. set change key association */
changeKeyDict = [NSDictionary dictionaryWithObjectsAndKeys: guid, @"GUID",
globCnt, @"LocalId",
nil];
[messageEntry setObject: changeKeyDict forKey: @"ChangeKey"];
/* 2. append/update predecessor change list */
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
@ -296,6 +292,77 @@ static Class NSNumberK;
[changeList setObject: globCnt forKey: guid];
}
- (void) _updatePredecessorChangeList: (NSData *) predecessorChangeList
forMessageEntry: (NSMutableDictionary *) messageEntry
withOldChangeKey: (NSData *) oldChangeKey
{
NSData *globCnt, *oldGlobCnt;
NSDictionary *changeKeyDict;
NSString *guid;
NSMutableDictionary *changeList;
struct SizedXid *sizedXIDList;
struct XID xid, *givenChangeKey;
TALLOC_CTX *localMemCtx;
uint32_t i, length;
localMemCtx = talloc_new (NULL);
if (!localMemCtx)
{
[self errorWithFormat: @"No more memory"];
return;
}
if (predecessorChangeList)
{
sizedXIDList = [predecessorChangeList asSizedXidArrayInMemCtx: localMemCtx with: &length];
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
if (!changeList)
{
changeList = [NSMutableDictionary new];
[messageEntry setObject: changeList
forKey: @"PredecessorChangeList"];
[changeList release];
}
if (sizedXIDList) {
for (i = 0; i < length; i++)
{
xid = sizedXIDList[i].XID;
guid = [NSString stringWithGUID: &xid.NameSpaceGuid];
globCnt = [NSData dataWithBytes: xid.LocalId.data length: xid.LocalId.length];
oldGlobCnt = [changeList objectForKey: guid];
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
[changeList setObject: globCnt forKey: guid];
}
}
}
if (oldChangeKey)
{
givenChangeKey = [oldChangeKey asXIDInMemCtx: localMemCtx];
if (givenChangeKey) {
guid = [NSString stringWithGUID: &givenChangeKey->NameSpaceGuid];
globCnt = [NSData dataWithBytes: givenChangeKey->LocalId.data length: givenChangeKey->LocalId.length];
changeKeyDict = [messageEntry objectForKey: @"ChangeKey"];
if (!changeKeyDict ||
([guid isEqualToString: [changeKeyDict objectForKey: @"GUID"]]
&& ([globCnt compare: [changeKeyDict objectForKey: @"LocalId"]] == NSOrderedDescending)))
{
/* The given change key is greater than current one stored in
metadata or it does not exist */
[messageEntry setObject: [NSDictionary dictionaryWithObjectsAndKeys: guid, @"GUID",
globCnt, @"LocalId",
nil]
forKey: @"ChangeKey"];
}
}
}
talloc_free (localMemCtx);
}
- (EOQualifier *) componentQualifier
{
if (!componentQualifier)
@ -465,8 +532,7 @@ static Class NSNumberK;
// A GLOBCNT structure is a 6-byte global namespace counter,
// we strip the first 2 bytes. The first two bytes is the ReplicaId
changeKey = [self getReplicaKeyFromGlobCnt: newChangeNum >> 16];
[self _setChangeKey: changeKey forMessageEntry: messageEntry
inChangeListOnly: NO];
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
}
now = [NSCalendarDate date];
@ -483,12 +549,13 @@ static Class NSNumberK;
}
- (void) updateVersionsForMessageWithKey: (NSString *) messageKey
withChangeKey: (NSData *) newChangeKey
withChangeKey: (NSData *) oldChangeKey
andPredecessorChangeList: (NSData *) pcl
{
NSMutableDictionary *messages, *messageEntry;
[self synchroniseCache];
if (newChangeKey)
if (oldChangeKey || pcl)
{
messages = [[versionsMessage properties] objectForKey: @"Messages"];
messageEntry = [messages objectForKey: messageKey];
@ -496,8 +563,8 @@ static Class NSNumberK;
[NSException raise: @"MAPIStoreIOException"
format: @"no version record found for message '%@'",
messageKey];
[self _setChangeKey: newChangeKey forMessageEntry: messageEntry
inChangeListOnly: YES];
[self _updatePredecessorChangeList: pcl forMessageEntry: messageEntry
withOldChangeKey: oldChangeKey];
[versionsMessage save];
}
}

View File

@ -209,13 +209,16 @@
- (void) updateVersions
{
NSData *newChangeKey;
/* Update ChangeKey and PredecessorChangeList on message's save */
NSData *newChangeKey, *predecessorChangeList;
newChangeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)];
predecessorChangeList = [properties objectForKey: MAPIPropertyKey (PR_PREDECESSOR_CHANGE_LIST)];
[(MAPIStoreGCSFolder *) container
updateVersionsForMessageWithKey: [self nameInContainer]
withChangeKey: newChangeKey];
updateVersionsForMessageWithKey: [self nameInContainer]
withChangeKey: newChangeKey
andPredecessorChangeList: predecessorChangeList];
}
@end

View File

@ -30,6 +30,7 @@
#import <SOGo/NSArray+Utilities.h>
#import <Mailer/SOGoMailBodyPart.h>
#import <Mailer/SOGoMailObject.h>
#import <Mailer/NSDictionary+Mail.h>
#import "MAPIStoreTypes.h"
#import "MAPIStoreMailMessage.h"
@ -108,7 +109,7 @@
static char recordBytes[] = {0xd9, 0xd8, 0x11, 0xa3, 0xe2, 0x90, 0x18, 0x41,
0x9e, 0x04, 0x58, 0x46, 0x9d, 0x6d, 0x1b,
0x68};
*data = [[NSData dataWithBytes: recordBytes length: 16]
asBinaryInMemCtx: memCtx];
@ -117,19 +118,7 @@
- (NSString *) _fileName
{
NSString *fileName;
NSDictionary *parameters;
fileName = [[bodyInfo objectForKey: @"parameterList"]
objectForKey: @"name"];
if (!fileName)
{
parameters = [[bodyInfo objectForKey: @"disposition"]
objectForKey: @"parameterList"];
fileName = [parameters objectForKey: @"filename"];
}
return fileName;
return [bodyInfo filename];
}
- (int) getPidTagAttachLongFilename: (void **) data
@ -178,7 +167,7 @@
- (int) getPidTagAttachContentId: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
{
*data = [[bodyInfo objectForKey: @"bodyId"]
asUnicodeInMemCtx: memCtx];

View File

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

View File

@ -68,6 +68,8 @@
static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
#include <gen_ndr/exchange.h>
#undef DEBUG
#include <util/attr.h>
#include <libmapi/libmapi.h>
@ -109,6 +111,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
[SOGoMAPIDBMessage objectWithName: @"versions.plist"
inContainer: dbFolder]);
[versionsMessage setObjectType: MAPIInternalCacheObject];
[versionsMessage reloadIfNeeded];
}
- (BOOL) ensureFolderExists
@ -516,6 +519,44 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
return [modseq1 compare: modseq2];
}
- (void) _updatePredecessorChangeListWith: (NSData *) predecessorChangeList
forMessageEntry: (NSMutableDictionary *) messageEntry
{
NSData *globCnt, *oldGlobCnt;
NSMutableDictionary *changeList;
NSString *guid;
struct SizedXid *sizedXIDList;
struct XID xid;
uint32_t i, length;
sizedXIDList = [predecessorChangeList asSizedXidArrayInMemCtx: NULL with: &length];
changeList = [messageEntry objectForKey: @"PredecessorChangeList"];
if (!changeList)
{
changeList = [NSMutableDictionary new];
[messageEntry setObject: changeList
forKey: @"PredecessorChangeList"];
[changeList release];
}
if (sizedXIDList) {
for (i = 0; i < length; i++)
{
xid = sizedXIDList[i].XID;
guid = [NSString stringWithGUID: &xid.NameSpaceGuid];
globCnt = [NSData dataWithBytes: xid.LocalId.data length: xid.LocalId.length];
oldGlobCnt = [changeList objectForKey: guid];
if (!oldGlobCnt || ([globCnt compare: oldGlobCnt] == NSOrderedDescending))
[changeList setObject: globCnt forKey: guid];
}
talloc_free (sizedXIDList);
}
[versionsMessage save];
}
- (void) _setChangeKey: (NSData *) changeKey
forMessageEntry: (NSMutableDictionary *) messageEntry
{
@ -526,8 +567,8 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
NSMutableDictionary *changeList;
xid = [changeKey asXIDInMemCtx: NULL];
guid = [NSString stringWithGUID: &xid->GUID];
globCnt = [NSData dataWithBytes: xid->Data length: xid->Size];
guid = [NSString stringWithGUID: &xid->NameSpaceGuid];
globCnt = [NSData dataWithBytes: xid->LocalId.data length: xid->LocalId.length];
talloc_free (xid);
/* 1. set change key association */
@ -924,8 +965,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
return changeNumber;
}
- (void) setChangeKey: (NSData *) changeKey
forMessageWithKey: (NSString *) messageKey
- (NSMutableDictionary *) _messageEntryFromMessageKey: (NSString *) messageKey
{
NSMutableDictionary *messages, *messageEntry;
NSString *messageUid;
@ -936,7 +976,7 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
messageEntry = [messages objectForKey: messageUid];
if (!messageEntry)
{
[self warnWithFormat: @"attempting to synchronise to set the change key for "
[self warnWithFormat: @"attempting to synchronise to get the message entry for "
@"this message %@", messageKey];
synced = [self synchroniseCacheForUID: messageUid];
if (synced)
@ -947,11 +987,57 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data)
abort ();
}
}
[self _setChangeKey: changeKey forMessageEntry: messageEntry];
return messageEntry;
}
- (void) setChangeKey: (NSData *) changeKey
forMessageWithKey: (NSString *) messageKey
{
[self _setChangeKey: changeKey
forMessageEntry: [self _messageEntryFromMessageKey: messageKey]];
[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;
@ -1217,6 +1303,7 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
fromFolder: (MAPIStoreFolder *) sourceFolder
withMIDs: (uint64_t *) targetMids
andChangeKeys: (struct Binary_r **) targetChangeKeys
andPredecessorChangeLists: (struct Binary_r **) targetPredecessorChangeLists
wantCopy: (uint8_t) wantCopy
inMemCtx: (TALLOC_CTX *) memCtx
@ -1231,12 +1318,13 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
NSDictionary *result;
NSUInteger count;
NSArray *a;
NSData *changeKey;
NSData *changeList;
if (![sourceFolder isKindOfClass: [MAPIStoreMailFolder class]])
return [super moveCopyMessagesWithMIDs: srcMids andCount: midCount
fromFolder: sourceFolder withMIDs: targetMids
andChangeKeys: targetChangeKeys
andPredecessorChangeLists: targetPredecessorChangeLists
wantCopy: wantCopy
inMemCtx: memCtx];
@ -1325,11 +1413,11 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP)
[self synchroniseCache];
for (count = 0; count < midCount; count++)
{
changeKey = [NSData dataWithBinary: targetChangeKeys[count]];
changeList = [NSData dataWithBinary: targetPredecessorChangeLists[count]];
messageKey = [NSString stringWithFormat: @"%@.eml",
[destUIDs objectAtIndex: count]];
[self setChangeKey: changeKey
forMessageWithKey: messageKey];
[self _updatePredecessorChangeListWith: changeList
forMessageEntry: [self _messageEntryFromMessageKey: messageKey]];
}
}

View File

@ -40,6 +40,7 @@
#import <Mailer/NSData+Mail.h>
#import <Mailer/SOGoMailBodyPart.h>
#import <Mailer/SOGoMailObject.h>
#import <Mailer/NSDictionary+Mail.h>
#import "Codepages.h"
#import "NSData+MAPIStore.h"
@ -196,7 +197,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
count1 = [keys indexOfObject: data1];
data2 = [entry2 objectForKey: @"mimeType"];
count2 = [keys indexOfObject: data2];
if (count1 == count2)
{
data1 = [entry1 objectForKey: @"key"];
@ -529,7 +530,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
else
stringValue = @"";
*data = [stringValue asUnicodeInMemCtx: memCtx];
return MAPISTORE_SUCCESS;
}
@ -624,7 +625,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
NSDictionary *coreInfos;
NSArray *flags;
unsigned int v = 0;
coreInfos = [sogoObject fetchCoreInfos];
flags = [coreInfos objectForKey: @"flags"];
@ -636,7 +637,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if ([[self attachmentKeys]
count] > 0)
v |= MSGFLAG_HASATTACH;
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
@ -656,7 +657,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
v = 2;
else
v = 0;
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
@ -668,15 +669,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
NSDictionary *coreInfos;
NSArray *flags;
unsigned int v;
coreInfos = [sogoObject fetchCoreInfos];
flags = [coreInfos objectForKey: @"flags"];
if ([flags containsObject: @"flagged"])
v = 6;
else
v = 0;
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
@ -755,7 +756,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if ([ngAddress isKindOfClass: [NGMailAddress class]])
{
cn = [ngAddress displayName];
// If we don't have a displayName, we use the email address instead. This
// avoid bug #2119 - where Outlook won't display anything in the "From" field,
// nor in the recipient field if we reply to the email.
@ -809,7 +810,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
entryId = MAPIStoreExternalEntryId (cn, email);
*data = [entryId asBinaryInMemCtx: memCtx];
rc = MAPISTORE_SUCCESS;
}
else
@ -966,15 +967,15 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
{
uint32_t v;
NSString *s;
s = [[sogoObject mailHeaders] objectForKey: @"x-priority"];
v = 0x1;
if ([s hasPrefix: @"1"]) v = 0x2;
else if ([s hasPrefix: @"2"]) v = 0x2;
else if ([s hasPrefix: @"4"]) v = 0x0;
else if ([s hasPrefix: @"5"]) v = 0x0;
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
@ -1163,14 +1164,14 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
if (!headerSetup)
[self _fetchHeaderData];
if ([headerMimeType isEqualToString: @"text/plain"])
format = EDITOR_FORMAT_PLAINTEXT;
else if ([headerMimeType isEqualToString: @"text/html"])
format = EDITOR_FORMAT_HTML;
else
format = 0; /* EDITOR_FORMAT_DONTKNOW */
*data = MAPILongValue (memCtx, format);
return MAPISTORE_SUCCESS;
@ -1517,7 +1518,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
p = 0;
recipient->data = talloc_array (msgData, void *, msgData->columns->cValues);
memset (recipient->data, 0, msgData->columns->cValues * sizeof (void *));
// PR_OBJECT_TYPE = MAPI_MAILUSER (see MAPI_OBJTYPE)
recipient->data[p] = MAPILongValue (msgData, MAPI_MAILUSER);
p++;
@ -1525,7 +1526,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
// PR_DISPLAY_TYPE = DT_MAILUSER (see MS-NSPI)
recipient->data[p] = MAPILongValue (msgData, 0);
p++;
// PR_7BIT_DISPLAY_NAME_UNICODE
recipient->data[p] = [cn asUnicodeInMemCtx: msgData];
p++;
@ -1533,7 +1534,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
// PR_SMTP_ADDRESS_UNICODE
recipient->data[p] = [email asUnicodeInMemCtx: msgData];
p++;
// PR_SEND_INTERNET_ENCODING = 0x00060000 (plain text, see OXCMAIL)
recipient->data[p] = MAPILongValue (msgData, 0x00060000);
p++;
@ -1566,12 +1567,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
withPrefix: (NSString *) keyPrefix
{
NSArray *parts;
NSDictionary *parameters;
NSUInteger count, max;
parameters = [[bodyInfo objectForKey: @"disposition"]
objectForKey: @"parameterList"];
if ([[parameters objectForKey: @"filename"] length] > 0)
if ([[bodyInfo filename] length] > 0)
{
if ([keyPrefix length] == 0)
keyPrefix = @"0";
@ -1645,15 +1643,29 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
return attachment;
}
- (int) setReadFlag: (uint8_t) flag
- (enum mapistore_error) setReadFlag: (uint8_t) flag
{
BOOL modified = NO;
BOOL alreadyRead = NO;
NSString *imapFlag = @"\\Seen";
alreadyRead = [[[sogoObject fetchCoreInfos] objectForKey: @"flags"]
containsObject: @"seen"];
/* TODO: notifications should probably be emitted from here */
if (flag & CLEAR_READ_FLAG)
[sogoObject removeFlags: imapFlag];
{
[sogoObject removeFlags: imapFlag];
modified = alreadyRead;
}
else
[sogoObject addFlags: imapFlag];
{
[sogoObject addFlags: imapFlag];
modified = !alreadyRead;
}
if (modified)
[(MAPIStoreMailFolder *)[self container] synchroniseCache];
return MAPISTORE_SUCCESS;
}
@ -1694,7 +1706,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
return nil;
}
- (void) save: (TALLOC_CTX *) memCtx
- (void) save: (TALLOC_CTX *) memCtx
{
NSNumber *value;

View File

@ -161,15 +161,30 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK;
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
//[self logWithFormat: @" modseq: %.16lx", [modseq unsignedLongLongValue]];
if (modseq)
modseq = [NSNumber numberWithUnsignedLongLong:
[modseq unsignedLongLongValue] + 1];
{
if (res->relop == RELOP_GT)
modseq = [NSNumber numberWithUnsignedLongLong:
[modseq unsignedLongLongValue] + 1];
}
else
modseq = [NSNumber numberWithUnsignedLongLong: 0];
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"MODSEQ"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: modseq];
[*qualifier autorelease];
rc = MAPIRestrictionStateNeedsEval;
if (res->relop == RELOP_GT || res->relop == RELOP_GE)
{
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"MODSEQ"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
value: modseq];
[*qualifier autorelease];
rc = MAPIRestrictionStateNeedsEval;
}
else
{
/* Ignore other operations as IMAP only support MODSEQ >= X */
[self warnWithFormat: @"Ignoring %@ as only supported operators are > and >=",
[self operatorFromRestrictionOperator: res->relop]];
rc = MAPIRestrictionStateAlwaysTrue;
}
}
break;

View File

@ -34,6 +34,7 @@
#import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NGHashMap.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSObject+Values.h>
#import <NGExtensions/NSString+Encoding.h>
#import <NGMime/NGMimeBodyPart.h>
#import <NGMime/NGMimeMultipartBody.h>
@ -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"];
}
}

View File

@ -63,7 +63,7 @@
withAID: (uint32_t) aid;
- (int) getAttachmentTable: (MAPIStoreAttachmentTable **) tablePtr
andRowCount: (uint32_t *) countPtr;
- (int) setReadFlag: (uint8_t) flag;
- (enum mapistore_error) setReadFlag: (uint8_t) flag;
- (enum mapistore_error) saveMessage: (TALLOC_CTX *) memCtx;
- (NSArray *) activeContainerMessageTables;

View File

@ -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])
{
@ -918,7 +919,7 @@ rtf2html (NSData *compressedRTF)
return [self getNo: data inMemCtx: memCtx];;
}
- (int) setReadFlag: (uint8_t) flag
- (enum mapistore_error) setReadFlag: (uint8_t) flag
{
// [self subclassResponsibility: _cmd];

View File

@ -674,6 +674,7 @@ sogo_folder_move_copy_messages(void *folder_object,
uint32_t mid_count,
uint64_t *src_mids, uint64_t *t_mids,
struct Binary_r **target_change_keys,
struct Binary_r **target_predecessor_change_lists,
uint8_t want_copy)
{
MAPIStoreFolder *sourceFolder, *targetFolder;
@ -698,6 +699,7 @@ sogo_folder_move_copy_messages(void *folder_object,
fromFolder: sourceFolder
withMIDs: t_mids
andChangeKeys: target_change_keys
andPredecessorChangeLists: target_predecessor_change_lists
wantCopy: want_copy
inMemCtx: mem_ctx];
TRYCATCH_END(pool)
@ -1118,7 +1120,7 @@ sogo_message_set_read_flag (void *message_object, uint8_t flag)
struct MAPIStoreTallocWrapper *wrapper;
NSAutoreleasePool *pool;
MAPIStoreMessage *message;
int rc;
enum mapistore_error rc;
if (message_object)
{

View File

@ -41,6 +41,8 @@
+ (id) dataWithXID: (const struct XID *) xid;
- (struct XID *) asXIDInMemCtx: (void *) memCtx;
- (struct SizedXid *) asSizedXidArrayInMemCtx: (void *) memCtx
with: (uint32_t *) length;
+ (id) dataWithChangeKeyGUID: (NSString *) guidString
andCnt: (NSData *) globCnt;

View File

@ -22,6 +22,7 @@
#import <NGExtensions/NSObject+Logs.h>
#import "MAPIStoreTypes.h"
#import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h"
@ -29,6 +30,7 @@
#undef DEBUG
#include <stdbool.h>
#include <libmapi/libmapi.h>
#include <talloc.h>
#include <util/time.h>
#include <gen_ndr/exchange.h>
@ -136,11 +138,11 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
NSMutableData *xidData;
struct FlatUID_r flatUID;
_fillFlatUIDWithGUID (&flatUID, &xid->GUID);
_fillFlatUIDWithGUID (&flatUID, &xid->NameSpaceGuid);
xidData = [NSMutableData dataWithCapacity: 16 + xid->Size];
xidData = [NSMutableData dataWithCapacity: 16 + xid->LocalId.length];
[xidData appendBytes: flatUID.ab length: 16];
[xidData appendBytes: xid->Data length: xid->Size];
[xidData appendBytes: xid->LocalId.data length: xid->LocalId.length];
return xidData;
}
@ -156,12 +158,12 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
{
xid = talloc_zero (memCtx, struct XID);
[self _extractGUID: &xid->GUID];
[self _extractGUID: &xid->NameSpaceGuid];
xid->Size = max - 16;
xid->LocalId.length = max - 16;
bytes = (uint8_t *) [self bytes];
xid->Data = talloc_memdup (xid, (bytes+16), xid->Size);
xid->LocalId.data = talloc_memdup (xid, (bytes+16), xid->LocalId.length);
}
else
{
@ -172,6 +174,38 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
return xid;
}
- (struct SizedXid *) asSizedXidArrayInMemCtx: (void *) memCtx
with: (uint32_t *) length
{
struct Binary_r bin;
struct SizedXid *sizedXIDArray;
bin.cb = [self length];
bin.lpb = (uint8_t *)[self bytes];
sizedXIDArray = get_SizedXidArray(memCtx, &bin, length);
if (!sizedXIDArray)
{
NSLog (@"Impossible to parse SizedXID array");
return NULL;
}
return sizedXIDArray;
}
- (NSComparisonResult) compare: (NSData *) otherGlobCnt
{
uint64_t globCnt = 0, oGlobCnt = 0;
if ([self length] > 0)
globCnt = *(uint64_t *) [self bytes];
if ([otherGlobCnt length] > 0)
oGlobCnt = *(uint64_t *) [otherGlobCnt bytes];
return MAPICNCompare (globCnt, oGlobCnt, NULL);
}
+ (id) dataWithChangeKeyGUID: (NSString *) guidString
andCnt: (NSData *) globCnt;
{

View File

@ -22,6 +22,8 @@ $(TEST_TOOL)_OBJC_FILES += \
TestSBJsonParser.m \
\
TestNGMimeAddressHeaderFieldGenerator.m \
TestNGMimeMessageGenerator.m \
\
TestNSData+Crypto.m \
TestNSString+Crypto.m \
TestNSString+URLEscaping.m \

View File

@ -25,6 +25,8 @@
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSData.h>
#import <Foundation/NSValue.h>
@class NSArray;
@ -52,6 +54,8 @@
- (BOOL) run;
- (NSString*) stringFromDiffBetween: (NSString*) str1
and: (NSString*) str2;
@end
#define test(c) { \

View File

@ -185,4 +185,79 @@ static NSString *SOGoTestAssertException = @"SOGoTestAssertException";
return YES;
}
/* Helper function for diffForString:andString */
NSString *_stringForCharacterAtIndex(NSUInteger index, NSString *str, NSUInteger length)
{
NSString *chrStr;
unichar chr;
if (index < length)
{
chr = [str characterAtIndex: index];
if (isprint(chr))
{
chrStr = [NSString stringWithFormat: @"%c", chr];
}
else
{
if (chr == 10)
chrStr = @"[NL]";
else if (chr == 0)
chrStr = @"[\0]";
else
chrStr = [NSString stringWithFormat: @"[NP: %u]", chr];
}
}
else
{
chrStr = @"[none]";
}
return chrStr;
}
/*
Returns a string with a very verbose diff of the two strings.
In case the strings are equal it returns an empty string.
Example output for the strings 'flower' and 'flotera':
<begin of example>
0 |f|
1 |l|
2 |o|
3 |w|t|<--
4 |e|
5 |r|
6 |[none]|a|<--
<end of example>
*/
- (NSString*) stringFromDiffBetween: (NSString*) str1
and: (NSString*) str2
{
BOOL differencesFound = NO;
NSString *finalSTR = @"";
NSUInteger i, length1, length2;
NSString *sc1, *sc2;
length1 = [str1 length];
length2 = [str2 length];
for (i = 0; i < length1 || i < length2; i++)
{
sc1 = _stringForCharacterAtIndex(i, str1, length1);
sc2 = _stringForCharacterAtIndex(i, str2, length2);
if ([sc1 isEqualToString: sc2])
finalSTR = [finalSTR stringByAppendingFormat: @"%u |%@|\n", i, sc1];
else
{
finalSTR = [finalSTR stringByAppendingFormat: @"%u |%@|%@|<--\n", i, sc1, sc2];
differencesFound = YES;
}
}
if (!differencesFound)
return @"";
return finalSTR;
}
@end

@ -1 +1 @@
Subproject commit f60b5e5a7713af9058f9a29966f6e324cae901b9
Subproject commit 218bb93c6b35f216e5e0d13ac032ead61af051b1