diff --git a/OpenChange/MAPIStoreDBMessage.m b/OpenChange/MAPIStoreDBMessage.m index bb5acbb57..98d357bf7 100644 --- a/OpenChange/MAPIStoreDBMessage.m +++ b/OpenChange/MAPIStoreDBMessage.m @@ -109,18 +109,70 @@ 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 { - NSNumber *versionNbr; + /* Return the global counter from CN structure. + See [MS-OXCFXICS] Section 2.2.2.1 */ + NSNumber *versionNbr, *cn; uint64_t objectVersion; [(SOGoMAPIDBMessage *) sogoObject reloadIfNeeded]; - versionNbr = [properties objectForKey: @"version"]; + versionNbr = [properties objectForKey: @"version_number"]; if (versionNbr) - objectVersion = (([versionNbr unsignedLongLongValue] >> 16) - & 0x0000ffffffffffffLL); + objectVersion = exchange_globcnt ([versionNbr unsignedLongLongValue]); 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; } @@ -283,13 +335,19 @@ [properties setObject: attachmentParts forKey: @"attachments"]; newVersion = [[self context] getNewChangeNumber]; + newVersion = exchange_globcnt ((newVersion >> 16) & 0x0000ffffffffffffLL); + [properties setObject: [NSNumber numberWithUnsignedLongLong: newVersion] - forKey: @"version"]; + forKey: @"version_number"]; + + /* Remove old version */ + [properties removeObjectForKey: @"version"]; /* Update PredecessorChangeList accordingly */ [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]; } diff --git a/OpenChange/MAPIStoreDBMessageTable.m b/OpenChange/MAPIStoreDBMessageTable.m index de22e238e..a8c68abd1 100644 --- a/OpenChange/MAPIStoreDBMessageTable.m +++ b/OpenChange/MAPIStoreDBMessageTable.m @@ -61,14 +61,15 @@ static Class MAPIStoreDBMessageK = Nil; if ((uint32_t) res->ulPropTag == PidTagChangeNumber) { + SEL operator; + value = NSObjectFromMAPISPropValue (&res->lpProp); cVersion = exchange_globcnt (([value unsignedLongLongValue] >> 16) & 0x0000ffffffffffffLL); version = [NSNumber numberWithUnsignedLongLong: cVersion]; - //[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]]; - [self logWithFormat: @" version: %.16lx", cVersion]; - *qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"version" - operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo + operator = [self operatorFromRestrictionOperator: res->relop]; + *qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"version_number" + operatorSelector: operator value: version]; [*qualifier autorelease]; rc = MAPIRestrictionStateNeedsEval; diff --git a/OpenChange/MAPIStoreGCSFolder.m b/OpenChange/MAPIStoreGCSFolder.m index 2dacdb4cf..336474675 100644 --- a/OpenChange/MAPIStoreGCSFolder.m +++ b/OpenChange/MAPIStoreGCSFolder.m @@ -681,12 +681,12 @@ static Class NSNumberK; - (NSNumber *) lastModifiedFromMessageChangeNumber: (NSString *) changeNumber { NSDictionary *mapping; - NSNumber *modseq; + NSNumber *lastModified; mapping = [[versionsMessage properties] objectForKey: @"VersionMapping"]; - modseq = [mapping objectForKey: changeNumber]; + lastModified = [mapping objectForKey: changeNumber]; - return modseq; + return lastModified; } - (NSString *) changeNumberForMessageWithKey: (NSString *) messageKey diff --git a/OpenChange/MAPIStoreGCSMessageTable.m b/OpenChange/MAPIStoreGCSMessageTable.m index e6da41039..0dac1fff9 100644 --- a/OpenChange/MAPIStoreGCSMessageTable.m +++ b/OpenChange/MAPIStoreGCSMessageTable.m @@ -27,6 +27,7 @@ #import #import +#import #import #import @@ -38,7 +39,6 @@ #import "MAPIStoreTypes.h" #import "MAPIStoreGCSFolder.h" - #import "MAPIStoreGCSMessageTable.h" #undef DEBUG @@ -89,21 +89,31 @@ if (res->ulPropTag == PidTagChangeNumber) { + NSString *changeNumber; + value = NSObjectFromMAPISPropValue (&res->lpProp); + changeNumber = [NSString stringWithUnsignedLongLong: [(NSNumber *)value unsignedLongLongValue]]; lastModified = [(MAPIStoreGCSFolder *) - container lastModifiedFromMessageChangeNumber: value]; + container lastModifiedFromMessageChangeNumber: changeNumber]; //[self logWithFormat: @"change number from oxcfxics: %.16lx", [value unsignedLongLongValue]]; //[self logWithFormat: @" c_lastmodified: %@", lastModified]; if (lastModified) { + SEL operator; + + operator = [self operatorFromRestrictionOperator: res->relop]; *qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_lastmodified" - operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo + operatorSelector: operator value: lastModified]; [*qualifier autorelease]; rc = MAPIRestrictionStateNeedsEval; } else - rc = MAPIRestrictionStateAlwaysTrue; + { + [self logWithFormat: @"No last modified found for: 0x%.16"PRIx64". Then no restriction applied", + [value unsignedLongLongValue]]; + rc = MAPIRestrictionStateAlwaysTrue; + } } else { diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 6934e7a60..02e25acbd 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -74,6 +74,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; #include #include #include +#include #include #include @@ -257,6 +258,67 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; 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 { static EOQualifier *nonDeletedQualifier = nil; @@ -281,7 +343,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; andSortOrderings: (NSArray *) sortOrderings { NSArray *uidKeys; - EOQualifier *fetchQualifier; + EOQualifier *fetchQualifier, *simplifiedQualifier; if ([self ensureFolderExists]) { @@ -290,9 +352,10 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; if (qualifier) { + simplifiedQualifier = [self simplifyQualifier: qualifier]; fetchQualifier = [[EOAndQualifier alloc] initWithQualifiers: - [self nonDeletedQualifier], qualifier, + [self nonDeletedQualifier], simplifiedQualifier, nil]; [fetchQualifier autorelease]; } diff --git a/OpenChange/MAPIStoreMailMessageTable.m b/OpenChange/MAPIStoreMailMessageTable.m index c71097d63..d315f6527 100644 --- a/OpenChange/MAPIStoreMailMessageTable.m +++ b/OpenChange/MAPIStoreMailMessageTable.m @@ -181,8 +181,8 @@ static Class MAPIStoreMailMessageK, NSDataK, NSStringK; else { /* Ignore other operations as IMAP only support MODSEQ >= X */ - [self warnWithFormat: @"Ignoring %@ as only supported operators are > and >=", - [self operatorFromRestrictionOperator: res->relop]]; + [self warnWithFormat: @"Ignoring '%@' as only supported operators are > and >=", + NSStringFromSelector ([self operatorFromRestrictionOperator: res->relop])]; rc = MAPIRestrictionStateAlwaysTrue; } } diff --git a/OpenChange/MAPIStoreSOGoObject.m b/OpenChange/MAPIStoreSOGoObject.m index 2d7b6ad99..7f1cc4b6a 100644 --- a/OpenChange/MAPIStoreSOGoObject.m +++ b/OpenChange/MAPIStoreSOGoObject.m @@ -197,6 +197,7 @@ static Class MAPIStoreFolderK; inMemCtx: (TALLOC_CTX *) memCtx { int rc; + struct mapistore_connection_info *connInfo; uint64_t obVersion; obVersion = [self objectVersion]; @@ -204,8 +205,9 @@ static Class MAPIStoreFolderK; rc = MAPISTORE_ERR_NOT_FOUND; else { + connInfo = [[self context] connectionInfo]; *data = MAPILongLongValue (memCtx, ((obVersion << 16) - | 0x0001)); + | connInfo->repl_id)); rc = MAPISTORE_SUCCESS; }