From a549773554642002d9a6ba55da20737943bc905f Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Sat, 6 Oct 2012 13:02:39 -0400 Subject: [PATCH] Implemented a mechanism to preload body parts for email messages --- OpenChange/MAPIStoreMailFolder.h | 1 + OpenChange/MAPIStoreMailFolder.m | 86 +++++++++++++++++++++++++++++++ OpenChange/MAPIStoreMailMessage.h | 4 ++ OpenChange/MAPIStoreMailMessage.m | 27 +++++++++- 4 files changed, 117 insertions(+), 1 deletion(-) diff --git a/OpenChange/MAPIStoreMailFolder.h b/OpenChange/MAPIStoreMailFolder.h index ad1c2dfdb..462382e1f 100644 --- a/OpenChange/MAPIStoreMailFolder.h +++ b/OpenChange/MAPIStoreMailFolder.h @@ -37,6 +37,7 @@ @interface MAPIStoreMailFolder : MAPIStoreFolder { SOGoMAPIDBMessage *versionsMessage; + NSMutableDictionary *bodyData; } - (BOOL) ensureFolderExists; diff --git a/OpenChange/MAPIStoreMailFolder.m b/OpenChange/MAPIStoreMailFolder.m index 6f252ef20..99c9e8174 100644 --- a/OpenChange/MAPIStoreMailFolder.m +++ b/OpenChange/MAPIStoreMailFolder.m @@ -25,6 +25,7 @@ #import #import #import +#import #import #import #import @@ -50,6 +51,7 @@ #import "MAPIStoreContext.h" #import "MAPIStoreFAIMessage.h" #import "MAPIStoreMailContext.h" +#import "MAPIStoreMailMessage.h" #import "MAPIStoreMailMessageTable.h" #import "MAPIStoreMapping.h" #import "MAPIStoreTypes.h" @@ -86,6 +88,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; if ((self = [super init])) { versionsMessage = nil; + bodyData = [NSMutableDictionary new]; } return self; @@ -94,6 +97,7 @@ static Class SOGoMailFolderK, MAPIStoreMailFolderK, MAPIStoreOutboxFolderK; - (void) dealloc { [versionsMessage release]; + [bodyData release]; [super dealloc]; } @@ -1161,6 +1165,24 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) inContainer: self]; } +- (id) lookupMessage: (NSString *) messageKey +{ + MAPIStoreMailMessage *message; + NSData *rawBodyData; + NSNumber *messageUID; + + message = [super lookupMessage: messageKey]; + if (message) + { + messageUID = [self messageUIDFromMessageKey: messageKey]; + rawBodyData = [bodyData objectForKey: messageUID]; + if (rawBodyData) + [message setBodyContentFromRawData: rawBodyData]; + } + + return message; +} + - (NSArray *) rolesForExchangeRights: (uint32_t) rights { NSMutableArray *roles; @@ -1219,6 +1241,70 @@ _parseCOPYUID (NSString *line, NSArray **destUIDsP) return rights; } +- (enum mapistore_error) preloadMessageBodiesWithKeys: (NSArray *) keys +{ + MAPIStoreMailMessage *message; + NSMutableSet *bodyPartKeys; + NSMutableDictionary *keyAssoc; + NSDictionary *response; + NSUInteger count, max; + NSString *messageKey, *bodyPartKey; + NSNumber *messageUID; + NGImap4Client *client; + NSArray *fetch; + NSData *bodyContent; + + [bodyData removeAllObjects]; + max = [keys count]; + + if (max > 0) + { + bodyPartKeys = [NSMutableSet setWithCapacity: max]; + + keyAssoc = [NSMutableDictionary dictionaryWithCapacity: max]; + for (count = 0; count < max; count++) + { + messageKey = [keys objectAtIndex: count]; + messageUID = [self messageUIDFromMessageKey: messageKey]; + if (messageUID) + { + message = [self lookupMessage: messageKey]; + if (message) + { + bodyPartKey = [message bodyContentPartKey]; + [bodyPartKeys addObject: bodyPartKey]; + [keyAssoc setObject: bodyPartKey forKey: messageUID]; + } + } + } + + client = [[(SOGoMailFolder *) sogoObject imap4Connection] client]; + [client select: [sogoObject absoluteImap4Name]]; + response = [client fetchUids: [keyAssoc allKeys] + parts: [bodyPartKeys allObjects]]; + fetch = [response objectForKey: @"fetch"]; + max = [fetch count]; + for (count = 0; count < max; count++) + { + response = [fetch objectAtIndex: count]; + messageUID = [response objectForKey: @"uid"]; + if (messageUID) + { + bodyPartKey = [keyAssoc objectForKey: messageUID]; + if (bodyPartKey) + { + bodyContent = [[response objectForKey: bodyPartKey] + objectForKey: @"data"]; + if (bodyContent) + [bodyData setObject: bodyContent forKey: messageUID]; + } + } + } + } + + return MAPISTORE_SUCCESS; +} + @end @implementation MAPIStoreOutboxFolder diff --git a/OpenChange/MAPIStoreMailMessage.h b/OpenChange/MAPIStoreMailMessage.h index 76b7a3258..22d9e3320 100644 --- a/OpenChange/MAPIStoreMailMessage.h +++ b/OpenChange/MAPIStoreMailMessage.h @@ -70,6 +70,10 @@ - (int) getPidTagDisplayBcc: (void **) data inMemCtx: (TALLOC_CTX *) memCtx; +/* batch-mode helpers */ +- (NSString *) bodyContentPartKey; +- (void) setBodyContentFromRawData: (NSData *) rawContent; + @end #endif /* MAPISTOREMAILMESSAGE_H */ diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 2e6c8df0b..b1bf6bd1c 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -240,7 +240,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) if (!headerSetup) [self _fetchHeaderData]; - if (mimeKey) + if (!bodyContent && mimeKey) { result = [sogoObject fetchParts: [NSArray arrayWithObject: mimeKey]]; result = [[result valueForKey: @"RawResponse"] objectForKey: @"fetch"]; @@ -1550,6 +1550,31 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data) return MAPISTORE_SUCCESS; } +- (NSString *) bodyContentPartKey +{ + NSString *bodyPartKey; + + if (!headerSetup) + [self _fetchHeaderData]; + + if ([mimeKey hasPrefix: @"body.peek"]) + bodyPartKey = [NSString stringWithFormat: @"body[%@]", + [mimeKey _strippedBodyKey]]; + else + bodyPartKey = mimeKey; + + return bodyPartKey; +} + +- (void) setBodyContentFromRawData: (NSData *) rawContent +{ + if (!headerSetup) + [self _fetchHeaderData]; + + ASSIGN (bodyContent, [rawContent bodyDataFromEncoding: headerEncoding]); + bodySetup = YES; +} + - (void) save { NSNumber *value;