Merge pull request #219 from zentyal/ejhernandez/mult-cn-restriction

Manage multiple Change Number restrictions
This commit is contained in:
Jesús García Sáez 2015-12-22 17:14:53 +01:00
commit 966d13c5b6
7 changed files with 157 additions and 23 deletions

View file

@ -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]);
else
{
/* Old version which stored the CN structure not useful for searching */
cn = [properties objectForKey: @"version"];
if (cn)
objectVersion = (([cn unsignedLongLongValue] >> 16)
& 0x0000ffffffffffffLL); & 0x0000ffffffffffffLL);
else else
objectVersion = ULLONG_MAX; 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];
} }

View file

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

View file

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

View file

@ -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,22 +89,32 @@
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
{
[self logWithFormat: @"No last modified found for: 0x%.16"PRIx64". Then no restriction applied",
[value unsignedLongLongValue]];
rc = MAPIRestrictionStateAlwaysTrue; rc = MAPIRestrictionStateAlwaysTrue;
} }
}
else else
{ {
property = [self backendIdentifierForProperty: res->ulPropTag]; property = [self backendIdentifierForProperty: res->ulPropTag];

View file

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

View file

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

View file

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