From 33ad6cd48b53c04e543503be54806188de917335 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 29 Jul 2011 02:11:52 +0000 Subject: [PATCH 1/3] Monotone-Parent: 6b4e2f16b2a1ac3bbbb8f854763b7deb70bd8a46 Monotone-Revision: b82c98742f6f58a7217e5b601c74d10f86e4ab18 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2011-07-29T02:11:52 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 7 +++++++ SoObjects/Mailer/SOGoMailFolder.h | 3 +++ SoObjects/Mailer/SOGoMailFolder.m | 29 +++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/ChangeLog b/ChangeLog index 3898f89e0..2e259b6d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2011-07-28 Wolfgang Sourdeau + + * SoObjects/Mailer/SOGoMailFolder.m (-statusForFlags:): new method + that returns the values of flags passed as parameters. + (-fetchUIDsOfVanishedItems:): new method that returns the list of + UID that are reported to have vanished since the specified modseq. + 2011-07-27 Wolfgang Sourdeau * OpenChange/MAPIStoreGCSMessageTable.m diff --git a/SoObjects/Mailer/SOGoMailFolder.h b/SoObjects/Mailer/SOGoMailFolder.h index dd5603b37..4fb2cac76 100644 --- a/SoObjects/Mailer/SOGoMailFolder.h +++ b/SoObjects/Mailer/SOGoMailFolder.h @@ -52,6 +52,8 @@ - (NSArray *) toOneRelationshipKeys; - (NSArray *) toManyRelationshipKeys; +- (NSDictionary *) statusForFlags: (NSArray *) flags; + - (NSException *) deleteUIDs: (NSArray *) uids useTrashFolder: (BOOL *) withTrash inContext: (id) context; @@ -63,6 +65,7 @@ - (NSArray *) fetchUIDsMatchingQualifier: (id) _q sortOrdering: (id) _so; - (NSArray *) fetchUIDsMatchingQualifier: (id) _q sortOrdering: (id) _so threaded: (BOOL) _threaded; - (NSArray *) fetchUIDs: (NSArray *) _uids parts: (NSArray *) _parts; +- (NSArray *) fetchUIDsOfVanishedItems: (uint64_t) modseq; - (WOResponse *) copyUIDs: (NSArray *) uids toFolder: (NSString *) destinationFolder diff --git a/SoObjects/Mailer/SOGoMailFolder.m b/SoObjects/Mailer/SOGoMailFolder.m index 5dbcc9bf3..5dd8568f3 100644 --- a/SoObjects/Mailer/SOGoMailFolder.m +++ b/SoObjects/Mailer/SOGoMailFolder.m @@ -555,6 +555,24 @@ static NSString *defaultUserID = @"anyone"; return result; } +- (NSDictionary *) statusForFlags: (NSArray *) flags +{ + NGImap4Client *client; + NSString *folderName; + NSDictionary *result, *status; + + client = [[self imap4Connection] client]; + folderName = [[self imap4Connection] imap4FolderNameForURL: [self imap4URL]]; + result = [client status: folderName flags: flags]; + if ([[result objectForKey: @"result"] boolValue]) + status = [[[result objectForKey: @"RawResponse"] objectForKey: @"status"] + objectForKey: @"flags"]; + else + status = nil; + + return status; +} + - (NSArray *) fetchUIDsMatchingQualifier: (id) _q sortOrdering: (id) _so { @@ -588,6 +606,17 @@ static NSString *defaultUserID = @"anyone"; parts: _parts]; } +- (NSArray *) fetchUIDsOfVanishedItems: (uint64_t) modseq +{ + NGImap4Client *client; + NSDictionary *result; + + client = [[self imap4Connection] client]; + result = [client fetchVanished: modseq]; + + return [result objectForKey: @"vanished"]; +} + - (NSException *) postData: (NSData *) _data flags: (id) _flags { From aaa7559ff09cb00e7ab419e3b81e2fa5efcfa9eb Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 29 Jul 2011 02:12:59 +0000 Subject: [PATCH 2/3] Monotone-Parent: b82c98742f6f58a7217e5b601c74d10f86e4ab18 Monotone-Revision: 48c9c37f78835c3255c4103136b86bdfcaaca051 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2011-07-29T02:12:59 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 +++ OpenChange/MAPIStoreTable.m | 8 -------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2e259b6d1..07cedbb98 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2011-07-28 Wolfgang Sourdeau + * OpenChange/MAPIStoreTable.m (-loggingPrefix): removed method as + it was causing crashes when the parent object was deallocated. + * SoObjects/Mailer/SOGoMailFolder.m (-statusForFlags:): new method that returns the values of flags passed as parameters. (-fetchUIDsOfVanishedItems:): new method that returns the list of diff --git a/OpenChange/MAPIStoreTable.m b/OpenChange/MAPIStoreTable.m index d08901eb2..870113103 100644 --- a/OpenChange/MAPIStoreTable.m +++ b/OpenChange/MAPIStoreTable.m @@ -916,12 +916,4 @@ static Class NSDataK, NSStringK; [self subclassResponsibility: _cmd]; } -/* logging */ -- (NSString *) loggingPrefix -{ - return [NSString stringWithFormat:@"<%@:%p:%@>", - NSStringFromClass (isa), self, - [container nameInContainer]]; -} - @end From 7a5f67babe3d1e1f9bff22c2699689f0d1dc7012 Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Fri, 29 Jul 2011 02:13:39 +0000 Subject: [PATCH 3/3] Monotone-Parent: 48c9c37f78835c3255c4103136b86bdfcaaca051 Monotone-Revision: d9c62c6e142174bc3d2adb12ee04492347c95ede Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2011-07-29T02:13:39 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 3 ++ OpenChange/MAPIStoreFolder.h | 9 ++++ OpenChange/MAPIStoreFolder.m | 65 ++++++++++++++++++++++++ OpenChange/MAPIStoreGCSFolder.m | 86 ++++++++++++++++++++++++++++++++ OpenChange/MAPIStoreMailFolder.m | 59 ++++++++++++++++++++++ OpenChange/MAPIStoreMapping.m | 3 ++ OpenChange/MAPIStoreSOGo.m | 34 +++++++++++++ 7 files changed, 259 insertions(+) diff --git a/ChangeLog b/ChangeLog index 07cedbb98..ccb02d2ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2011-07-28 Wolfgang Sourdeau + * OpenChange/MAPIStoreSOGo.m (sogo_folder_get_deleted_fmids): + implemented new backend method. + * OpenChange/MAPIStoreTable.m (-loggingPrefix): removed method as it was causing crashes when the parent object was deallocated. diff --git a/OpenChange/MAPIStoreFolder.h b/OpenChange/MAPIStoreFolder.h index 705c7261d..1daddb573 100644 --- a/OpenChange/MAPIStoreFolder.h +++ b/OpenChange/MAPIStoreFolder.h @@ -29,6 +29,7 @@ @class NSArray; @class NSMutableArray; +@class NSNumber; @class NSURL; @class EOQualifier; @@ -109,6 +110,11 @@ inMemCtx: (TALLOC_CTX *) memCtx; - (int) deleteMessageWithMID: (uint64_t) mid andFlags: (uint8_t) flags; +- (int) getDeletedFMIDs: (struct I8Array_r **) fmidsPtr + andCN: (uint64_t *) cnPtr + fromChangeNumber: (uint64_t) changeNum + inTableType: (uint8_t) tableType + inMemCtx: (TALLOC_CTX *) mem_ctx; - (int) getTable: (MAPIStoreTable **) tablePtr andRowCount: (uint32_t *) count @@ -124,6 +130,9 @@ - (MAPIStoreMessageTable *) messageTable; - (NSArray *) messageKeysMatchingQualifier: (EOQualifier *) qualifier andSortOrderings: (NSArray *) sortOrderings; +- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum + andCN: (NSNumber **) cnNbr + inTableType: (uint8_t) tableType; - (NSString *) createFolder: (struct SRow *) aRow withFID: (uint64_t) newFID; diff --git a/OpenChange/MAPIStoreFolder.m b/OpenChange/MAPIStoreFolder.m index cc2b2368e..e65ea16a6 100644 --- a/OpenChange/MAPIStoreFolder.m +++ b/OpenChange/MAPIStoreFolder.m @@ -519,6 +519,64 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return rc; } +- (int) getDeletedFMIDs: (struct I8Array_r **) fmidsPtr + andCN: (uint64_t *) cnPtr + fromChangeNumber: (uint64_t) changeNum + inTableType: (uint8_t) tableType + inMemCtx: (TALLOC_CTX *) memCtx +{ + int rc; + NSString *baseURL, *format, *url; + NSArray *keys; + NSNumber *cnNbr; + NSUInteger count, max; + MAPIStoreMapping *mapping; + struct I8Array_r *fmids; + uint64_t fmid; + + keys = [self getDeletedKeysFromChangeNumber: changeNum andCN: &cnNbr + inTableType: tableType]; + if (keys) + { + mapping = [[self context] mapping]; + + max = [keys count]; + + fmids = talloc_zero (memCtx, struct I8Array_r); + fmids->cValues = 0; + fmids->lpi8 = talloc_array (fmids, int64_t, max); + *fmidsPtr = fmids; + if (max > 0) + *cnPtr = [cnNbr unsignedLongLongValue]; + + baseURL = [self url]; + if ([baseURL hasSuffix: @"/"]) + format = @"%@%@"; + else + format = @"%@/%@"; + + for (count = 0; count < max; count++) + { + url = [NSString stringWithFormat: format, + baseURL, [keys objectAtIndex: count]]; + fmid = [mapping idFromURL: url]; + if (fmid != NSNotFound) /* if no fmid is returned, then the object + "never existed" in the OpenChange + databases */ + { + fmids->lpi8[fmids->cValues] = fmid; + fmids->cValues++; + } + } + + rc = MAPISTORE_SUCCESS; + } + else + rc = MAPISTORE_ERR_NOT_FOUND; + + return rc; +} + - (int) getTable: (MAPIStoreTable **) tablePtr andRowCount: (uint32_t *) countPtr tableType: (uint8_t) tableType @@ -928,6 +986,13 @@ Class NSExceptionK, MAPIStoreFAIMessageK, MAPIStoreMessageTableK, MAPIStoreFAIMe return nil; } +- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum + andCN: (NSNumber **) cnNbrs + inTableType: (uint8_t) tableType +{ + return nil; +} + - (Class) messageClass { [self subclassResponsibility: _cmd]; diff --git a/OpenChange/MAPIStoreGCSFolder.m b/OpenChange/MAPIStoreGCSFolder.m index 7ad627ebb..8f601dbcd 100644 --- a/OpenChange/MAPIStoreGCSFolder.m +++ b/OpenChange/MAPIStoreGCSFolder.m @@ -299,6 +299,92 @@ return changeNumber; } +- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum + andCN: (NSNumber **) cnNbr + inTableType: (uint8_t) tableType +{ + NSArray *deletedKeys, *deletedCNames, *records; + NSNumber *changeNumNbr, *lastModified; + NSString *cName; + NSDictionary *versionProperties; + NSMutableDictionary *messages, *mapping; + uint64_t newChangeNum = 0; + EOAndQualifier *fetchQualifier; + EOKeyValueQualifier *cDeletedQualifier, *cLastModifiedQualifier; + EOFetchSpecification *fs; + GCSFolder *ocsFolder; + NSUInteger count, max; + + if (tableType == MAPISTORE_MESSAGE_TABLE) + { + deletedKeys = [NSMutableArray array]; + + changeNumNbr = [NSNumber numberWithUnsignedLongLong: changeNum]; + lastModified = [self lastModifiedFromMessageChangeNumber: changeNumNbr]; + if (lastModified) + { + versionProperties = [versionsMessage properties]; + messages = [versionProperties objectForKey: @"Messages"]; + + ocsFolder = [sogoObject ocsFolder]; + cLastModifiedQualifier = [[EOKeyValueQualifier alloc] + initWithKey: @"c_lastmodified" + operatorSelector: EOQualifierOperatorGreaterThanOrEqualTo + value: lastModified]; + cDeletedQualifier = [[EOKeyValueQualifier alloc] + initWithKey: @"c_deleted" + operatorSelector: EOQualifierOperatorEqual + value: [NSNumber numberWithInt: 1]]; + fetchQualifier = [[EOAndQualifier alloc] initWithQualifiers: + cLastModifiedQualifier, + cDeletedQualifier, + nil]; + [fetchQualifier autorelease]; + [cLastModifiedQualifier release]; + [cDeletedQualifier release]; + + fs = [EOFetchSpecification + fetchSpecificationWithEntityName: [ocsFolder folderName] + qualifier: fetchQualifier + sortOrderings: nil]; + records = [ocsFolder + fetchFields: [NSArray arrayWithObject: @"c_name"] + fetchSpecification: fs + ignoreDeleted: NO]; + deletedCNames = [records objectsForKey: @"c_name" notFoundMarker: nil]; + max = [deletedCNames count]; + if (max > 0) + { + mapping = [versionProperties objectForKey: @"VersionsMapping"]; + for (count = 0; count < max; count++) + { + cName = [deletedCNames objectAtIndex: count]; + if ([messages objectForKey: cName]) + { + [messages removeObjectForKey: cName]; + [(NSMutableArray *) deletedKeys addObject: cName]; + newChangeNum = [[self context] getNewChangeNumber]; + } + } + if (newChangeNum) + { + changeNumNbr + = [NSNumber numberWithUnsignedLongLong: newChangeNum]; + [mapping setObject: lastModified forKey: changeNumNbr]; + *cnNbr = changeNumNbr; + [versionsMessage save]; + } + } + } + } + else + deletedKeys = [super getDeletedKeysFromChangeNumber: changeNum + andCN: cnNbr + inTableType: tableType]; + + return deletedKeys; +} + /* subclasses */ - (EOQualifier *) componentQualifier diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 84df178ad..eb0c36693 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -32,6 +32,7 @@ #import #import #import +#import #import #import #import @@ -97,6 +98,9 @@ static Class SOGoMailFolderK; accountFolder = [accountsFolder lookupName: @"0" inContext: woContext acquire: NO]; + [[accountFolder imap4Connection] + enableExtension: @"QRESYNC"]; + [parentContainersBag addObject: accountFolder]; [woContext setClientObject: accountFolder]; @@ -501,6 +505,61 @@ _compareFetchResultsByMODSEQ (id entry1, id entry2, void *data) return changeNumber; } +- (NSArray *) getDeletedKeysFromChangeNumber: (uint64_t) changeNum + andCN: (NSNumber **) cnNbr + inTableType: (uint8_t) tableType +{ + NSArray *deletedKeys, *deletedUIDs; + NSNumber *changeNumNbr; + uint64_t modseq; + NSDictionary *versionProperties, *status; + NSMutableDictionary *messages, *mapping; + NSNumber *newChangeNumNbr, *highestModseq; + uint64_t newChangeNum; + NSUInteger count, max; + + if (tableType == MAPISTORE_MESSAGE_TABLE) + { + changeNumNbr = [NSNumber numberWithUnsignedLongLong: changeNum]; + modseq = [[self modseqFromMessageChangeNumber: changeNumNbr] + unsignedLongLongValue]; + if (modseq > 0) + { + status + = [sogoObject + statusForFlags: [NSArray arrayWithObject: @"HIGHESTMODSEQ"]]; + highestModseq = [status objectForKey: @"highestmodseq"]; + + versionProperties = [versionsMessage properties]; + messages = [versionProperties objectForKey: @"Messages"]; + deletedUIDs = [(SOGoMailFolder *) sogoObject + fetchUIDsOfVanishedItems: modseq]; + deletedKeys = [deletedUIDs stringsWithFormat: @"%@.eml"]; + max = [deletedUIDs count]; + if (max > 0) + { + [messages removeObjectsForKeys: deletedUIDs]; + + mapping = [versionProperties objectForKey: @"VersionsMapping"]; + for (count = 0; count < max; count++) + newChangeNum = [[self context] getNewChangeNumber]; + newChangeNumNbr = [NSNumber numberWithUnsignedLongLong: newChangeNum]; + *cnNbr = newChangeNumNbr; + [mapping setObject: newChangeNumNbr forKey: @"SyncLastModseq"]; + [versionsMessage save]; + } + } + else + deletedKeys = [NSArray array]; + } + else + deletedKeys = [super getDeletedKeysFromChangeNumber: changeNum + andCN: cnNbr + inTableType: tableType]; + + return deletedKeys; +} + @end @implementation MAPIStoreInboxFolder : MAPIStoreMailFolder diff --git a/OpenChange/MAPIStoreMapping.m b/OpenChange/MAPIStoreMapping.m index fbcaf93a7..7fd5b8e29 100644 --- a/OpenChange/MAPIStoreMapping.m +++ b/OpenChange/MAPIStoreMapping.m @@ -62,6 +62,8 @@ MAPIStoreMappingTDBTraverse (TDB_CONTEXT *ctx, TDB_DATA data1, TDB_DATA data2, mapping = data; [mapping setObject: uri forKey: idNbr]; + NSLog (@"preregistered url '%@' for id '%@'", uri, idNbr); + return 0; } @@ -104,6 +106,7 @@ MAPIStoreMappingTDBTraverse (TDB_CONTEXT *ctx, TDB_DATA data1, TDB_DATA data2, { idNbr = [keys objectAtIndex: count]; uri = [mapping objectForKey: idNbr]; + [self logWithFormat: @"preregistered id '%@' for url '%@'", idNbr, uri]; [reverseMapping setObject: idNbr forKey: uri]; } } diff --git a/OpenChange/MAPIStoreSOGo.m b/OpenChange/MAPIStoreSOGo.m index 88fba7c1b..494320262 100644 --- a/OpenChange/MAPIStoreSOGo.m +++ b/OpenChange/MAPIStoreSOGo.m @@ -441,6 +441,39 @@ sogo_folder_delete_message(void *folder_object, uint64_t mid, uint8_t flags) return rc; } +static int +sogo_folder_get_deleted_fmids(void *folder_object, TALLOC_CTX *mem_ctx, + uint8_t table_type, uint64_t change_num, + struct I8Array_r **fmidsp, uint64_t *cnp) +{ + struct MAPIStoreTallocWrapper *wrapper; + NSAutoreleasePool *pool; + MAPIStoreFolder *folder; + int rc; + + DEBUG (5, ("[SOGo: %s:%d]\n", __FUNCTION__, __LINE__)); + + if (folder_object) + { + wrapper = folder_object; + folder = wrapper->MAPIStoreSOGoObject; + pool = [NSAutoreleasePool new]; + rc = [folder getDeletedFMIDs: fmidsp + andCN: cnp + fromChangeNumber: change_num + inTableType: table_type + inMemCtx: mem_ctx]; + [pool release]; + } + else + { + NSLog (@" UNEXPECTED WEIRDNESS: RECEIVED NO OBJECT"); + rc = MAPISTORE_SUCCESS; + } + + return rc; +} + static int sogo_folder_open_table(void *folder_object, TALLOC_CTX *mem_ctx, uint8_t table_type, uint32_t handle_id, @@ -989,6 +1022,7 @@ int mapistore_init_backend(void) backend.folder.open_message = sogo_folder_open_message; backend.folder.create_message = sogo_folder_create_message; backend.folder.delete_message = sogo_folder_delete_message; + backend.folder.get_deleted_fmids = sogo_folder_get_deleted_fmids; backend.folder.get_child_count = sogo_folder_get_child_count; backend.folder.open_table = sogo_folder_open_table; backend.message.create_attachment = sogo_message_create_attachment;