(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; return newAttachment;
} }
- (int) setReadFlag: (uint8_t) flag - (enum mapistore_error) setReadFlag: (uint8_t) flag
{ {
return MAPISTORE_SUCCESS; return MAPISTORE_SUCCESS;
} }

View File

@ -22,6 +22,7 @@
#import <Foundation/NSArray.h> #import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h> #import <Foundation/NSCalendarDate.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h> #import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h> #import <Foundation/NSString.h>
#import <Foundation/NSValue.h> #import <Foundation/NSValue.h>
@ -34,6 +35,7 @@
#import "MAPIStoreDBFolder.h" #import "MAPIStoreDBFolder.h"
#import "MAPIStoreDBMessage.h" #import "MAPIStoreDBMessage.h"
#import "MAPIStoreTypes.h" #import "MAPIStoreTypes.h"
#import "NSData+MAPIStore.h"
#import "NSObject+MAPIStore.h" #import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h" #import "NSString+MAPIStore.h"
@ -104,6 +106,105 @@
return objectVersion; 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? // FIXME: how this can happen?
// //
@ -166,6 +267,9 @@
[properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion] [properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion]
forKey: @"version"]; forKey: @"version"];
/* Update PredecessorChangeList accordingly */
[self _updatePredecessorChangeList];
[self logWithFormat: @"%d props in dict", [properties count]]; [self logWithFormat: @"%d props in dict", [properties count]];
[sogoObject save]; [sogoObject save];
@ -209,4 +313,36 @@
return [sogoObject lastModified]; 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 @end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -52,6 +52,8 @@
- (NSString *) changeNumberForMessageUID: (NSString *) messageUid; - (NSString *) changeNumberForMessageUID: (NSString *) messageUid;
- (void) setChangeKey: (NSData *) changeKey - (void) setChangeKey: (NSData *) changeKey
forMessageWithKey: (NSString *) messageKey; forMessageWithKey: (NSString *) messageKey;
- (BOOL) updatePredecessorChangeListWith: (NSData *) changeKey
forMessageWithKey: (NSString *) messageKey;
- (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey; - (NSData *) changeKeyForMessageWithKey: (NSString *) messageKey;
- (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey; - (NSData *) predecessorChangeListForMessageWithKey: (NSString *) messageKey;

View File

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

View File

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

View File

@ -161,15 +161,30 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK;
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]]; //[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
//[self logWithFormat: @" modseq: %.16lx", [modseq unsignedLongLongValue]]; //[self logWithFormat: @" modseq: %.16lx", [modseq unsignedLongLongValue]];
if (modseq) if (modseq)
modseq = [NSNumber numberWithUnsignedLongLong: {
[modseq unsignedLongLongValue] + 1]; if (res->relop == RELOP_GT)
modseq = [NSNumber numberWithUnsignedLongLong:
[modseq unsignedLongLongValue] + 1];
}
else else
modseq = [NSNumber numberWithUnsignedLongLong: 0]; modseq = [NSNumber numberWithUnsignedLongLong: 0];
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"MODSEQ"
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo if (res->relop == RELOP_GT || res->relop == RELOP_GE)
value: modseq]; {
[*qualifier autorelease]; *qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"MODSEQ"
rc = MAPIRestrictionStateNeedsEval; 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; break;

View File

@ -34,6 +34,7 @@
#import <NGExtensions/NGBase64Coding.h> #import <NGExtensions/NGBase64Coding.h>
#import <NGExtensions/NGHashMap.h> #import <NGExtensions/NGHashMap.h>
#import <NGExtensions/NSObject+Logs.h> #import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSObject+Values.h>
#import <NGExtensions/NSString+Encoding.h> #import <NGExtensions/NSString+Encoding.h>
#import <NGMime/NGMimeBodyPart.h> #import <NGMime/NGMimeBodyPart.h>
#import <NGMime/NGMimeMultipartBody.h> #import <NGMime/NGMimeMultipartBody.h>
@ -285,7 +286,7 @@ static NSString *recTypes[] = { @"orig", @"to", @"cc", @"bcc" };
version = [properties objectForKey: @"version"]; version = [properties objectForKey: @"version"];
return (version return (version
? exchange_globcnt ([version unsignedLongLongValue]) ? [version unsignedLongLongValue]
: ULLONG_MAX); : ULLONG_MAX);
} }
@ -1110,7 +1111,8 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
- (void) save: (TALLOC_CTX *) memCtx - (void) save: (TALLOC_CTX *) memCtx
{ {
NSString *folderName, *flag, *newIdString, *messageKey; BOOL updatedMetadata;
NSString *folderName, *flag, *newIdString, *messageKey, *changeNumber;
NSData *changeKey, *messageData; NSData *changeKey, *messageData;
NGImap4Connection *connection; NGImap4Connection *connection;
NGImap4Client *client; NGImap4Client *client;
@ -1146,21 +1148,33 @@ MakeMessageBody (NSDictionary *mailProperties, NSDictionary *attachmentParts, NS
[sogoObject setNameInContainer: messageKey]; [sogoObject setNameInContainer: messageKey];
[mapping registerURL: [self url] withID: mid]; [mapping registerURL: [self url] withID: mid];
/* synchronise the cache and update the change key with the one provided /* synchronise the cache and update the predecessor change list
by the client. Before doing this, lets issue a unselect/select combo with the change key provided by the client. Before doing
because of timing issues with Dovecot in obtaining the latest modseq. this, lets issue a unselect/select combo because of timing
Sometimes, Dovecot doesn't return the newly appended UID if we do issues with Dovecot in obtaining the latest modseq.
a "UID SORT (DATE) UTF-8 (MODSEQ XYZ) (NOT DELETED)" command (where Sometimes, Dovecot doesn't return the newly appended UID if
XYZ is the HIGHESTMODSEQ+1) immediately after IMAP APPEND */ 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 unselect];
[client select: folderName]; [client select: folderName];
[(MAPIStoreMailFolder *) container synchroniseCache]; [(MAPIStoreMailFolder *) container synchroniseCache];
changeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)]; changeKey = [properties objectForKey: MAPIPropertyKey (PR_CHANGE_KEY)];
if (changeKey) if (changeKey)
[(MAPIStoreMailFolder *) container {
setChangeKey: changeKey updatedMetadata = [(MAPIStoreMailFolder *) container updatePredecessorChangeListWith: changeKey
forMessageWithKey: messageKey]; 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; withAID: (uint32_t) aid;
- (int) getAttachmentTable: (MAPIStoreAttachmentTable **) tablePtr - (int) getAttachmentTable: (MAPIStoreAttachmentTable **) tablePtr
andRowCount: (uint32_t *) countPtr; andRowCount: (uint32_t *) countPtr;
- (int) setReadFlag: (uint8_t) flag; - (enum mapistore_error) setReadFlag: (uint8_t) flag;
- (enum mapistore_error) saveMessage: (TALLOC_CTX *) memCtx; - (enum mapistore_error) saveMessage: (TALLOC_CTX *) memCtx;
- (NSArray *) activeContainerMessageTables; - (NSArray *) activeContainerMessageTables;

View File

@ -549,11 +549,12 @@ rtf2html (NSData *compressedRTF)
} }
[self save: memCtx]; [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 properties dictionary, to make sure that related methods will be
invoked the next time they are requested. */ invoked the next time they are requested. */
[properties removeObjectForKey: MAPIPropertyKey (PidTagChangeKey)]; [properties removeObjectForKey: MAPIPropertyKey (PidTagChangeKey)];
[properties removeObjectForKey: MAPIPropertyKey (PidTagChangeNumber)]; [properties removeObjectForKey: MAPIPropertyKey (PidTagChangeNumber)];
[properties removeObjectForKey: MAPIPropertyKey (PidTagPredecessorChangeList)];
if ([container isKindOfClass: MAPIStoreFolderK]) if ([container isKindOfClass: MAPIStoreFolderK])
{ {
@ -918,7 +919,7 @@ rtf2html (NSData *compressedRTF)
return [self getNo: data inMemCtx: memCtx];; return [self getNo: data inMemCtx: memCtx];;
} }
- (int) setReadFlag: (uint8_t) flag - (enum mapistore_error) setReadFlag: (uint8_t) flag
{ {
// [self subclassResponsibility: _cmd]; // [self subclassResponsibility: _cmd];

View File

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

View File

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

View File

@ -22,6 +22,7 @@
#import <NGExtensions/NSObject+Logs.h> #import <NGExtensions/NSObject+Logs.h>
#import "MAPIStoreTypes.h"
#import "NSObject+MAPIStore.h" #import "NSObject+MAPIStore.h"
#import "NSString+MAPIStore.h" #import "NSString+MAPIStore.h"
@ -29,6 +30,7 @@
#undef DEBUG #undef DEBUG
#include <stdbool.h> #include <stdbool.h>
#include <libmapi/libmapi.h>
#include <talloc.h> #include <talloc.h>
#include <util/time.h> #include <util/time.h>
#include <gen_ndr/exchange.h> #include <gen_ndr/exchange.h>
@ -136,11 +138,11 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
NSMutableData *xidData; NSMutableData *xidData;
struct FlatUID_r flatUID; 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: flatUID.ab length: 16];
[xidData appendBytes: xid->Data length: xid->Size]; [xidData appendBytes: xid->LocalId.data length: xid->LocalId.length];
return xidData; return xidData;
} }
@ -156,12 +158,12 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
{ {
xid = talloc_zero (memCtx, struct XID); 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]; 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 else
{ {
@ -172,6 +174,38 @@ static void _fillFlatUIDWithGUID (struct FlatUID_r *flatUID, const struct GUID *
return xid; 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 + (id) dataWithChangeKeyGUID: (NSString *) guidString
andCnt: (NSData *) globCnt; andCnt: (NSData *) globCnt;
{ {

View File

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

View File

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

View File

@ -185,4 +185,79 @@ static NSString *SOGoTestAssertException = @"SOGoTestAssertException";
return YES; 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 @end

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