From e82423d4e2236d67a154928ebd45eefbd590ecbe Mon Sep 17 00:00:00 2001 From: Wolfgang Sourdeau Date: Tue, 19 Jul 2011 21:31:16 +0000 Subject: [PATCH] Monotone-Parent: 430f5637e275bb6a780f5be502428ee3c01c1d98 Monotone-Revision: 4b4728f355bbb34bff8025c45fdf5a359fe6387a Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2011-07-19T21:31:16 Monotone-Branch: ca.inverse.sogo --- ChangeLog | 6 + OpenChange/MAPIStoreMailMessage.h | 7 + OpenChange/MAPIStoreMailMessage.m | 205 +++++++++++++++++------------- 3 files changed, 128 insertions(+), 90 deletions(-) diff --git a/ChangeLog b/ChangeLog index 63569bde9..9f38957a4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2011-07-19 Wolfgang Sourdeau + * OpenChange/MAPIStoreMailMessage.m (-_setupBodyData): new + centralized method that performs the common operations required to + fetch the message body. + (-getPrHtml:inMemCtx,-getPrBody:inMemCtx:): make use of the above + method. + * SoObjects/SOGo/NSString+Utilities.m (-countOccurrencesOfString:): new self-explicit method. diff --git a/OpenChange/MAPIStoreMailMessage.h b/OpenChange/MAPIStoreMailMessage.h index ea9fd2266..476c213b9 100644 --- a/OpenChange/MAPIStoreMailMessage.h +++ b/OpenChange/MAPIStoreMailMessage.h @@ -25,9 +25,16 @@ #import "MAPIStoreMessage.h" +@class NSData; +@class NSString; + @interface MAPIStoreMailMessage : MAPIStoreMessage { BOOL fetchedAttachments; + BOOL bodySetup; + NSData *bodyContent; + NSString *bodyMimeType; + NSString *bodyCharset; } @end diff --git a/OpenChange/MAPIStoreMailMessage.m b/OpenChange/MAPIStoreMailMessage.m index 18ba1c333..ee29369da 100644 --- a/OpenChange/MAPIStoreMailMessage.m +++ b/OpenChange/MAPIStoreMailMessage.m @@ -25,6 +25,7 @@ #import #import #import +#import #import #import #import @@ -88,11 +89,25 @@ static Class NSExceptionK, MAPIStoreSentItemsFolderK, MAPIStoreDraftsFolderK; - (id) init { if ((self = [super init])) - fetchedAttachments = NO; + { + bodySetup = NO; + bodyContent = nil; + bodyMimeType = nil; + bodyCharset = nil; + fetchedAttachments = NO; + } return self; } +- (void) dealloc +{ + [bodyContent release]; + [bodyMimeType release]; + [bodyCharset release]; + [super dealloc]; +} + - (int) getPrIconIndex: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { @@ -494,53 +509,108 @@ static Class NSExceptionK, MAPIStoreSentItemsFolderK, MAPIStoreDraftsFolderK; return MAPISTORE_SUCCESS; } +static NSComparisonResult +_compareBodyKeysByPriority (id entry1, id entry2, void *data) +{ + NSComparisonResult result; + NSArray *keys; + NSString *data1, *data2; + NSUInteger count1, count2; + + keys = data; + + data1 = [entry1 objectForKey: @"mimeType"]; + count1 = [keys indexOfObject: data1]; + data2 = [entry2 objectForKey: @"mimeType"]; + count2 = [keys indexOfObject: data2]; + + if (count1 == count2) + { + data1 = [entry1 objectForKey: @"key"]; + count1 = [data1 countOccurrencesOfString: @"."]; + data2 = [entry2 objectForKey: @"key"]; + count2 = [data2 countOccurrencesOfString: @"."]; + if (count1 == count2) + { + data1 = [data1 _strippedBodyKey]; + count1 = [data1 intValue]; + data2 = [data2 _strippedBodyKey]; + count2 = [data2 intValue]; + if (count1 == count2) + result = NSOrderedSame; + else if (count1 < count2) + result = NSOrderedAscending; + else + result = NSOrderedDescending; + } + else if (count1 < count2) + result = NSOrderedAscending; + else + result = NSOrderedDescending; + } + else if (count1 < count2) + result = NSOrderedAscending; + else + result = NSOrderedDescending; + + return result; +} + +- (void) _setupBodyData +{ + NSMutableArray *keys; + NSArray *acceptedTypes; + NSDictionary *messageData, *partHeaderData; + NSString *messageKey, *encoding; + NSData *rawContent; + id result; + + acceptedTypes = [NSArray arrayWithObjects: // @"text/calendar", + // @"application/ics", + @"text/html", + @"text/plain", nil]; + keys = [NSMutableArray array]; + [sogoObject addRequiredKeysOfStructure: [sogoObject bodyStructure] + path: @"" toArray: keys + acceptedTypes: acceptedTypes]; + [keys sortUsingFunction: _compareBodyKeysByPriority context: acceptedTypes]; + if ([keys count] > 0) + { + messageData = [keys objectAtIndex: 0]; + ASSIGN (bodyMimeType, [messageData objectForKey: @"mimeType"]); + messageKey = [messageData objectForKey: @"key"]; + result = [sogoObject fetchParts: [NSArray arrayWithObject: messageKey]]; + result = [[result valueForKey: @"RawResponse"] objectForKey: @"fetch"]; + rawContent = [[result objectForKey: messageKey] objectForKey: @"data"]; + partHeaderData = [sogoObject + lookupInfoForBodyPart: [messageKey _strippedBodyKey]]; + encoding = [partHeaderData objectForKey: @"encoding"]; + ASSIGN (bodyContent, [rawContent bodyDataFromEncoding: encoding]); + ASSIGN (bodyCharset, [[partHeaderData objectForKey: @"parameterList"] + objectForKey: @"charset"]); + } + + bodySetup = YES; +} + - (int) getPrBody: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - NSMutableArray *keys; - id result; - NSData *content; - NSDictionary *partHeaderData; - NSString *partKey, *encoding, *charset, *stringValue; + NSString *stringValue; int rc = MAPISTORE_SUCCESS; - keys = [NSMutableArray array]; - [sogoObject addRequiredKeysOfStructure: [sogoObject bodyStructure] - path: @"" toArray: keys - acceptedTypes: [NSArray arrayWithObject: - @"text/html"]]; - if ([keys count] > 0) + if (!bodySetup) + [self _setupBodyData]; + + if ([bodyMimeType isEqualToString: @"text/plain"]) { - *data = NULL; - rc = MAPISTORE_ERR_NOT_FOUND; + stringValue = [bodyContent bodyStringFromCharset: bodyCharset]; + *data = [stringValue asUnicodeInMemCtx: memCtx]; } else { - [keys removeAllObjects]; - [sogoObject addRequiredKeysOfStructure: [sogoObject bodyStructure] - path: @"" toArray: keys - acceptedTypes: [NSArray arrayWithObject: - @"text/plain"]]; - if ([keys count] > 0) - { - result = [sogoObject fetchParts: [keys objectsForKey: @"key" - notFoundMarker: nil]]; - result = [[result valueForKey: @"RawResponse"] objectForKey: @"fetch"]; - partKey = [[keys objectAtIndex: 0] objectForKey: @"key"]; - content = [[result objectForKey: partKey] objectForKey: @"data"]; - - partHeaderData - = [sogoObject lookupInfoForBodyPart: [partKey _strippedBodyKey]]; - encoding = [partHeaderData objectForKey: @"encoding"]; - charset = [[partHeaderData objectForKey: @"parameterList"] - objectForKey: @"charset"]; - stringValue = [[content bodyDataFromEncoding: encoding] - bodyStringFromCharset: charset]; - - *data = [stringValue asUnicodeInMemCtx: memCtx]; - } - else - rc = MAPISTORE_ERR_NOT_FOUND; + *data = NULL; + rc = MAPISTORE_ERR_NOT_FOUND; } return rc; @@ -549,64 +619,19 @@ static Class NSExceptionK, MAPIStoreSentItemsFolderK, MAPIStoreDraftsFolderK; - (int) getPrHtml: (void **) data inMemCtx: (TALLOC_CTX *) memCtx { - id result; - NSData *content; - NSDictionary *partHeaderData; - NSString *key, *encoding; - char *oldBytes, *newBytes; - NSUInteger c, newC, max, newMax; - NSMutableArray *keys; - NSArray *acceptedTypes; int rc = MAPISTORE_SUCCESS; - acceptedTypes = [NSArray arrayWithObject: @"text/html"]; - keys = [NSMutableArray array]; - [sogoObject addRequiredKeysOfStructure: [sogoObject bodyStructure] - path: @"" toArray: keys - acceptedTypes: acceptedTypes]; - if ([keys count] > 0) - { - result = [sogoObject fetchParts: [keys objectsForKey: @"key" - notFoundMarker: nil]]; - result = [[result valueForKey: @"RawResponse"] objectForKey: - @"fetch"]; - key = [[keys objectAtIndex: 0] objectForKey: @"key"]; - content = [[result objectForKey: key] objectForKey: @"data"]; - - max = [content length]; - newMax = max; - oldBytes = malloc (max); - newBytes = malloc (max * 2); - [content getBytes: oldBytes]; - newC = 0; - for (c = 0; c < max; c++) - { - if (*(oldBytes + c) == '\n') - { - *(newBytes + newC) = '\r'; - newC++; - newMax++; - } - *(newBytes + newC) = *(oldBytes + c); - newC++; - } - content = [[NSData alloc] initWithBytesNoCopy: newBytes - length: newMax];; - [content autorelease]; - free(oldBytes); - - partHeaderData - = [sogoObject lookupInfoForBodyPart: [key _strippedBodyKey]]; - encoding = [partHeaderData objectForKey: @"encoding"]; - content = [content bodyDataFromEncoding: encoding]; - *data = [content asBinaryInMemCtx: memCtx]; - } + if (!bodySetup) + [self _setupBodyData]; + + if ([bodyMimeType isEqualToString: @"text/html"]) + *data = [bodyContent asBinaryInMemCtx: memCtx]; else { *data = NULL; rc = MAPISTORE_ERR_NOT_FOUND; } - + return rc; }