Merge pull request #219 from zentyal/ejhernandez/mult-cn-restriction
Manage multiple Change Number restrictions
This commit is contained in:
commit
966d13c5b6
|
@ -109,18 +109,70 @@
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *) description
|
||||||
|
{
|
||||||
|
id key, value;
|
||||||
|
NSEnumerator *propEnumerator;
|
||||||
|
NSMutableString *description;
|
||||||
|
|
||||||
|
description = [NSMutableString stringWithFormat: @"%@ %@. Properties: {", NSStringFromClass ([self class]),
|
||||||
|
[self url]];
|
||||||
|
|
||||||
|
propEnumerator = [properties keyEnumerator];
|
||||||
|
while ((key = [propEnumerator nextObject]))
|
||||||
|
{
|
||||||
|
uint32_t proptag = 0;
|
||||||
|
if ([key isKindOfClass: [NSString class]] && [(NSString *)key intValue] > 0)
|
||||||
|
proptag = [(NSString *)key intValue];
|
||||||
|
else if ([key isKindOfClass: [NSNumber class]])
|
||||||
|
proptag = [key unsignedLongValue];
|
||||||
|
|
||||||
|
if (proptag > 0)
|
||||||
|
{
|
||||||
|
const char *propTagName = get_proptag_name ([key unsignedLongValue]);
|
||||||
|
NSString *propName;
|
||||||
|
|
||||||
|
if (propTagName)
|
||||||
|
propName = [NSString stringWithCString: propTagName
|
||||||
|
encoding: NSUTF8StringEncoding];
|
||||||
|
else
|
||||||
|
propName = [NSString stringWithFormat: @"0x%.4x", [key unsignedLongValue]];
|
||||||
|
|
||||||
|
[description appendFormat: @"'%@': ", propName];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
[description appendFormat: @"'%@': ", key];
|
||||||
|
|
||||||
|
value = [properties objectForKey: key];
|
||||||
|
[description appendFormat: @"%@ (%@), ", value, NSStringFromClass ([value class])];
|
||||||
|
}
|
||||||
|
|
||||||
|
[description appendString: @"}\n"];
|
||||||
|
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
- (uint64_t) objectVersion
|
- (uint64_t) objectVersion
|
||||||
{
|
{
|
||||||
NSNumber *versionNbr;
|
/* Return the global counter from CN structure.
|
||||||
|
See [MS-OXCFXICS] Section 2.2.2.1 */
|
||||||
|
NSNumber *versionNbr, *cn;
|
||||||
uint64_t objectVersion;
|
uint64_t objectVersion;
|
||||||
|
|
||||||
[(SOGoMAPIDBMessage *) sogoObject reloadIfNeeded];
|
[(SOGoMAPIDBMessage *) sogoObject reloadIfNeeded];
|
||||||
versionNbr = [properties objectForKey: @"version"];
|
versionNbr = [properties objectForKey: @"version_number"];
|
||||||
if (versionNbr)
|
if (versionNbr)
|
||||||
objectVersion = (([versionNbr unsignedLongLongValue] >> 16)
|
objectVersion = exchange_globcnt ([versionNbr unsignedLongLongValue]);
|
||||||
& 0x0000ffffffffffffLL);
|
|
||||||
else
|
else
|
||||||
objectVersion = ULLONG_MAX;
|
{
|
||||||
|
/* Old version which stored the CN structure not useful for searching */
|
||||||
|
cn = [properties objectForKey: @"version"];
|
||||||
|
if (cn)
|
||||||
|
objectVersion = (([cn unsignedLongLongValue] >> 16)
|
||||||
|
& 0x0000ffffffffffffLL);
|
||||||
|
else
|
||||||
|
objectVersion = ULLONG_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
return objectVersion;
|
return objectVersion;
|
||||||
}
|
}
|
||||||
|
@ -283,13 +335,19 @@
|
||||||
[properties setObject: attachmentParts forKey: @"attachments"];
|
[properties setObject: attachmentParts forKey: @"attachments"];
|
||||||
|
|
||||||
newVersion = [[self context] getNewChangeNumber];
|
newVersion = [[self context] getNewChangeNumber];
|
||||||
|
newVersion = exchange_globcnt ((newVersion >> 16) & 0x0000ffffffffffffLL);
|
||||||
|
|
||||||
[properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion]
|
[properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion]
|
||||||
forKey: @"version"];
|
forKey: @"version_number"];
|
||||||
|
|
||||||
|
/* Remove old version */
|
||||||
|
[properties removeObjectForKey: @"version"];
|
||||||
|
|
||||||
/* Update PredecessorChangeList accordingly */
|
/* Update PredecessorChangeList accordingly */
|
||||||
[self _updatePredecessorChangeList];
|
[self _updatePredecessorChangeList];
|
||||||
|
|
||||||
[self logWithFormat: @"%d props in dict", [properties count]];
|
// [self logWithFormat: @"Saving %@", [self description]];
|
||||||
|
// [self logWithFormat: @"%d props in dict", [properties count]];
|
||||||
|
|
||||||
[sogoObject save];
|
[sogoObject save];
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,14 +61,15 @@ static Class MAPIStoreDBMessageK = Nil;
|
||||||
|
|
||||||
if ((uint32_t) res->ulPropTag == PidTagChangeNumber)
|
if ((uint32_t) res->ulPropTag == PidTagChangeNumber)
|
||||||
{
|
{
|
||||||
|
SEL operator;
|
||||||
|
|
||||||
value = NSObjectFromMAPISPropValue (&res->lpProp);
|
value = NSObjectFromMAPISPropValue (&res->lpProp);
|
||||||
cVersion = exchange_globcnt (([value unsignedLongLongValue] >> 16)
|
cVersion = exchange_globcnt (([value unsignedLongLongValue] >> 16)
|
||||||
& 0x0000ffffffffffffLL);
|
& 0x0000ffffffffffffLL);
|
||||||
version = [NSNumber numberWithUnsignedLongLong: cVersion];
|
version = [NSNumber numberWithUnsignedLongLong: cVersion];
|
||||||
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
|
operator = [self operatorFromRestrictionOperator: res->relop];
|
||||||
[self logWithFormat: @" version: %.16lx", cVersion];
|
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"version_number"
|
||||||
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"version"
|
operatorSelector: operator
|
||||||
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
|
|
||||||
value: version];
|
value: version];
|
||||||
[*qualifier autorelease];
|
[*qualifier autorelease];
|
||||||
rc = MAPIRestrictionStateNeedsEval;
|
rc = MAPIRestrictionStateNeedsEval;
|
||||||
|
|
|
@ -681,12 +681,12 @@ static Class NSNumberK;
|
||||||
- (NSNumber *) lastModifiedFromMessageChangeNumber: (NSString *) changeNumber
|
- (NSNumber *) lastModifiedFromMessageChangeNumber: (NSString *) changeNumber
|
||||||
{
|
{
|
||||||
NSDictionary *mapping;
|
NSDictionary *mapping;
|
||||||
NSNumber *modseq;
|
NSNumber *lastModified;
|
||||||
|
|
||||||
mapping = [[versionsMessage properties] objectForKey: @"VersionMapping"];
|
mapping = [[versionsMessage properties] objectForKey: @"VersionMapping"];
|
||||||
modseq = [mapping objectForKey: changeNumber];
|
lastModified = [mapping objectForKey: changeNumber];
|
||||||
|
|
||||||
return modseq;
|
return lastModified;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) changeNumberForMessageWithKey: (NSString *) messageKey
|
- (NSString *) changeNumberForMessageWithKey: (NSString *) messageKey
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#import <Foundation/NSString.h>
|
#import <Foundation/NSString.h>
|
||||||
|
|
||||||
#import <NGExtensions/NSObject+Logs.h>
|
#import <NGExtensions/NSObject+Logs.h>
|
||||||
|
#import <NGExtensions/NSObject+Values.h>
|
||||||
|
|
||||||
#import <EOControl/EOFetchSpecification.h>
|
#import <EOControl/EOFetchSpecification.h>
|
||||||
#import <EOControl/EOQualifier.h>
|
#import <EOControl/EOQualifier.h>
|
||||||
|
@ -38,7 +39,6 @@
|
||||||
|
|
||||||
#import "MAPIStoreTypes.h"
|
#import "MAPIStoreTypes.h"
|
||||||
#import "MAPIStoreGCSFolder.h"
|
#import "MAPIStoreGCSFolder.h"
|
||||||
|
|
||||||
#import "MAPIStoreGCSMessageTable.h"
|
#import "MAPIStoreGCSMessageTable.h"
|
||||||
|
|
||||||
#undef DEBUG
|
#undef DEBUG
|
||||||
|
@ -89,21 +89,31 @@
|
||||||
|
|
||||||
if (res->ulPropTag == PidTagChangeNumber)
|
if (res->ulPropTag == PidTagChangeNumber)
|
||||||
{
|
{
|
||||||
|
NSString *changeNumber;
|
||||||
|
|
||||||
value = NSObjectFromMAPISPropValue (&res->lpProp);
|
value = NSObjectFromMAPISPropValue (&res->lpProp);
|
||||||
|
changeNumber = [NSString stringWithUnsignedLongLong: [(NSNumber *)value unsignedLongLongValue]];
|
||||||
lastModified = [(MAPIStoreGCSFolder *)
|
lastModified = [(MAPIStoreGCSFolder *)
|
||||||
container lastModifiedFromMessageChangeNumber: value];
|
container lastModifiedFromMessageChangeNumber: changeNumber];
|
||||||
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
|
//[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]];
|
||||||
//[self logWithFormat: @" c_lastmodified: %@", lastModified];
|
//[self logWithFormat: @" c_lastmodified: %@", lastModified];
|
||||||
if (lastModified)
|
if (lastModified)
|
||||||
{
|
{
|
||||||
|
SEL operator;
|
||||||
|
|
||||||
|
operator = [self operatorFromRestrictionOperator: res->relop];
|
||||||
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_lastmodified"
|
*qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_lastmodified"
|
||||||
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
|
operatorSelector: operator
|
||||||
value: lastModified];
|
value: lastModified];
|
||||||
[*qualifier autorelease];
|
[*qualifier autorelease];
|
||||||
rc = MAPIRestrictionStateNeedsEval;
|
rc = MAPIRestrictionStateNeedsEval;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rc = MAPIRestrictionStateAlwaysTrue;
|
{
|
||||||
|
[self logWithFormat: @"No last modified found for: 0x%.16"PRIx64". Then no restriction applied",
|
||||||
|
[value unsignedLongLongValue]];
|
||||||
|
rc = MAPIRestrictionStateAlwaysTrue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -74,6 +74,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||||
#include <util/attr.h>
|
#include <util/attr.h>
|
||||||
#include <libmapi/libmapi.h>
|
#include <libmapi/libmapi.h>
|
||||||
#include <libmapiproxy.h>
|
#include <libmapiproxy.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <mapistore/mapistore.h>
|
#include <mapistore/mapistore.h>
|
||||||
#include <mapistore/mapistore_errors.h>
|
#include <mapistore/mapistore_errors.h>
|
||||||
|
|
||||||
|
@ -257,6 +258,67 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||||
return MAPISTORE_SUCCESS;
|
return MAPISTORE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (EOQualifier *) simplifyQualifier: (EOQualifier *) qualifier
|
||||||
|
{
|
||||||
|
/* Hack: Reduce the number of MODSEQ constraints to a single one as
|
||||||
|
we assume the difference among MODSEQs will be small enough to
|
||||||
|
return a small number of UIDs.
|
||||||
|
|
||||||
|
This is the only case we do simplify:
|
||||||
|
MODSEQ >= x | MODSEQ >= y | MODSEQ >= z => MODSEQ >= min(x,y,z)
|
||||||
|
*/
|
||||||
|
if (qualifier && [qualifier isKindOfClass: [EOOrQualifier class]])
|
||||||
|
{
|
||||||
|
EOQualifier *simplifiedQualifier;
|
||||||
|
NSArray *quals;
|
||||||
|
NSNumber *minModseq;
|
||||||
|
NSUInteger i, count;
|
||||||
|
|
||||||
|
quals = [(EOOrQualifier *)qualifier qualifiers];
|
||||||
|
count = [quals count];
|
||||||
|
if (count < 2)
|
||||||
|
return qualifier;
|
||||||
|
|
||||||
|
minModseq = [NSNumber numberWithUnsignedLongLong: ULLONG_MAX];
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
EOQualifier *subQualifier;
|
||||||
|
|
||||||
|
subQualifier = [quals objectAtIndex: i];
|
||||||
|
if ([subQualifier isKindOfClass: [EOAndQualifier class]]
|
||||||
|
&& [[(EOAndQualifier *)subQualifier qualifiers] count] == 1)
|
||||||
|
subQualifier = [[(EOAndQualifier *)subQualifier qualifiers] objectAtIndex: 0];
|
||||||
|
|
||||||
|
if ([subQualifier isKindOfClass: [EOKeyValueQualifier class]]
|
||||||
|
&& [[(EOKeyValueQualifier *)subQualifier key] isEqualToString: @"MODSEQ"])
|
||||||
|
{
|
||||||
|
NSNumber *value;
|
||||||
|
|
||||||
|
value = (NSNumber *)[(EOKeyValueQualifier *)subQualifier value];
|
||||||
|
if ([minModseq compare: value] == NSOrderedDescending
|
||||||
|
&& [value unsignedLongLongValue] > 0)
|
||||||
|
minModseq = (NSNumber *)[(EOKeyValueQualifier *)subQualifier value];
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return qualifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([minModseq unsignedLongLongValue] > 0 && [minModseq unsignedLongLongValue] < ULLONG_MAX)
|
||||||
|
{
|
||||||
|
simplifiedQualifier = [[EOKeyValueQualifier alloc]
|
||||||
|
initWithKey: @"MODSEQ"
|
||||||
|
operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo
|
||||||
|
value: minModseq];
|
||||||
|
[simplifiedQualifier autorelease];
|
||||||
|
return simplifiedQualifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return qualifier;
|
||||||
|
}
|
||||||
|
|
||||||
- (EOQualifier *) nonDeletedQualifier
|
- (EOQualifier *) nonDeletedQualifier
|
||||||
{
|
{
|
||||||
static EOQualifier *nonDeletedQualifier = nil;
|
static EOQualifier *nonDeletedQualifier = nil;
|
||||||
|
@ -281,7 +343,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||||
andSortOrderings: (NSArray *) sortOrderings
|
andSortOrderings: (NSArray *) sortOrderings
|
||||||
{
|
{
|
||||||
NSArray *uidKeys;
|
NSArray *uidKeys;
|
||||||
EOQualifier *fetchQualifier;
|
EOQualifier *fetchQualifier, *simplifiedQualifier;
|
||||||
|
|
||||||
if ([self ensureFolderExists])
|
if ([self ensureFolderExists])
|
||||||
{
|
{
|
||||||
|
@ -290,9 +352,10 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK;
|
||||||
|
|
||||||
if (qualifier)
|
if (qualifier)
|
||||||
{
|
{
|
||||||
|
simplifiedQualifier = [self simplifyQualifier: qualifier];
|
||||||
fetchQualifier
|
fetchQualifier
|
||||||
= [[EOAndQualifier alloc] initWithQualifiers:
|
= [[EOAndQualifier alloc] initWithQualifiers:
|
||||||
[self nonDeletedQualifier], qualifier,
|
[self nonDeletedQualifier], simplifiedQualifier,
|
||||||
nil];
|
nil];
|
||||||
[fetchQualifier autorelease];
|
[fetchQualifier autorelease];
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,8 +181,8 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Ignore other operations as IMAP only support MODSEQ >= X */
|
/* Ignore other operations as IMAP only support MODSEQ >= X */
|
||||||
[self warnWithFormat: @"Ignoring %@ as only supported operators are > and >=",
|
[self warnWithFormat: @"Ignoring '%@' as only supported operators are > and >=",
|
||||||
[self operatorFromRestrictionOperator: res->relop]];
|
NSStringFromSelector ([self operatorFromRestrictionOperator: res->relop])];
|
||||||
rc = MAPIRestrictionStateAlwaysTrue;
|
rc = MAPIRestrictionStateAlwaysTrue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,6 +197,7 @@ static Class MAPIStoreFolderK;
|
||||||
inMemCtx: (TALLOC_CTX *) memCtx
|
inMemCtx: (TALLOC_CTX *) memCtx
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
struct mapistore_connection_info *connInfo;
|
||||||
uint64_t obVersion;
|
uint64_t obVersion;
|
||||||
|
|
||||||
obVersion = [self objectVersion];
|
obVersion = [self objectVersion];
|
||||||
|
@ -204,8 +205,9 @@ static Class MAPIStoreFolderK;
|
||||||
rc = MAPISTORE_ERR_NOT_FOUND;
|
rc = MAPISTORE_ERR_NOT_FOUND;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
connInfo = [[self context] connectionInfo];
|
||||||
*data = MAPILongLongValue (memCtx, ((obVersion << 16)
|
*data = MAPILongLongValue (memCtx, ((obVersion << 16)
|
||||||
| 0x0001));
|
| connInfo->repl_id));
|
||||||
rc = MAPISTORE_SUCCESS;
|
rc = MAPISTORE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue