mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-03-28 01:22:44 +00:00
Merge pull request #256 from zentyal/jag/multipart-nested-2
oc-mail: Better management of nested multipart types
This commit is contained in:
@@ -44,11 +44,11 @@
|
||||
NSMutableDictionary *bodyPartsEncodings;
|
||||
NSMutableDictionary *bodyPartsCharsets;
|
||||
NSMutableDictionary *bodyPartsMimeTypes;
|
||||
NSMutableDictionary *bodyPartsMixed;
|
||||
|
||||
NSString *headerCharset;
|
||||
NSString *headerMimeType;
|
||||
BOOL bodySetup;
|
||||
BOOL multipartMixed;
|
||||
NSArray *bodyContent;
|
||||
BOOL fetchedAttachments;
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSObject+Values.h>
|
||||
#import <NGExtensions/NSString+Encoding.h>
|
||||
@@ -42,6 +43,7 @@
|
||||
#import <Mailer/SOGoMailBodyPart.h>
|
||||
#import <Mailer/SOGoMailObject.h>
|
||||
#import <Mailer/NSDictionary+Mail.h>
|
||||
#import <Mailer/NSString+Mail.h>
|
||||
|
||||
#import "Codepages.h"
|
||||
#import "NSData+MAPIStore.h"
|
||||
@@ -131,11 +133,11 @@ static NSArray *acceptedMimeTypes;
|
||||
bodyPartsEncodings = nil;
|
||||
bodyPartsCharsets = nil;
|
||||
bodyPartsMimeTypes = nil;
|
||||
bodyPartsMixed = nil;
|
||||
|
||||
headerSetup = NO;
|
||||
bodySetup = NO;
|
||||
bodyContent = nil;
|
||||
multipartMixed = NO;
|
||||
|
||||
mailIsEvent = NO;
|
||||
mailIsMeetingRequest = NO;
|
||||
@@ -155,6 +157,7 @@ static NSArray *acceptedMimeTypes;
|
||||
[bodyPartsEncodings release];
|
||||
[bodyPartsCharsets release];
|
||||
[bodyPartsMimeTypes release];
|
||||
[bodyPartsMixed release];
|
||||
|
||||
[bodyContent release];
|
||||
|
||||
@@ -260,7 +263,8 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
|
||||
keys = [NSMutableArray array];
|
||||
[sogoObject addRequiredKeysOfStructure: [sogoObject bodyStructure]
|
||||
path: @"" toArray: keys
|
||||
path: @""
|
||||
toArray: keys
|
||||
acceptedTypes: acceptedMimeTypes
|
||||
withPeek: YES];
|
||||
[keys sortUsingFunction: _compareBodyKeysByPriority context: acceptedMimeTypes];
|
||||
@@ -268,39 +272,29 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
if (keysCount > 0)
|
||||
{
|
||||
NSUInteger i;
|
||||
id bodyStructure;
|
||||
BOOL hasHtml = NO;
|
||||
BOOL hasText = NO;
|
||||
|
||||
bodyStructure = [sogoObject bodyStructure];
|
||||
/* multipart/mixed is the default type.
|
||||
multipart/alternative and multipart/related are the only other type of multipart supported for the
|
||||
message body
|
||||
*/
|
||||
if ([[bodyStructure objectForKey: @"type"] isEqualToString: @"multipart"])
|
||||
{
|
||||
NSString *subtype = [bodyStructure objectForKey: @"subtype"];
|
||||
multipartMixed = !([subtype isEqualToString: @"alternative"] ||
|
||||
[subtype isEqualToString: @"related"]);
|
||||
}
|
||||
else
|
||||
multipartMixed = NO;
|
||||
|
||||
bodyContentKeys = [[NSMutableArray alloc] initWithCapacity: keysCount];
|
||||
bodyPartsEncodings = [[NSMutableDictionary alloc] initWithCapacity: keysCount];
|
||||
bodyPartsCharsets = [[NSMutableDictionary alloc] initWithCapacity: keysCount];
|
||||
bodyPartsMimeTypes = [[NSMutableDictionary alloc] initWithCapacity: keysCount];
|
||||
bodyPartsMixed = [[NSMutableDictionary alloc] initWithCapacity: keysCount];
|
||||
|
||||
for (i = 0; i < keysCount; i++)
|
||||
{
|
||||
NSDictionary *bodyStructureKey;
|
||||
NSString *key;
|
||||
NSString *mimeType;
|
||||
BOOL mixedPart;
|
||||
NSString *strippedKey;
|
||||
NSString *encoding;
|
||||
NSString *charset;
|
||||
NSDictionary *partParameters;
|
||||
NSString *multipart;
|
||||
|
||||
key = [[keys objectAtIndex: i] objectForKey: @"key"];
|
||||
bodyStructureKey = [keys objectAtIndex: i];
|
||||
key = [bodyStructureKey objectForKey: @"key"];
|
||||
if (key == nil)
|
||||
continue;
|
||||
|
||||
@@ -312,7 +306,21 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
partParameters = [partHeaderData objectForKey: @"parameterList"];
|
||||
encoding = [partHeaderData objectForKey: @"encoding"];
|
||||
charset = [partParameters objectForKey: @"charset"];
|
||||
mimeType = [[keys objectAtIndex: i] objectForKey: @"mimeType"];
|
||||
mimeType = [bodyStructureKey objectForKey: @"mimeType"];
|
||||
|
||||
/* multipart/mixed is the default type.
|
||||
multipart/alternative is the only other type of multipart supported now.
|
||||
*/
|
||||
multipart = [bodyStructureKey objectForKey: @"multipart"];
|
||||
if ([multipart isEqualToString: @""])
|
||||
{
|
||||
mixedPart = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
mixedPart = !([multipart isEqualToString: @"multipart/alternative"] ||
|
||||
[multipart isEqualToString: @"multipart/related"]);
|
||||
}
|
||||
|
||||
if (encoding)
|
||||
[bodyPartsEncodings setObject: encoding forKey: key];
|
||||
@@ -326,6 +334,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
else if ([mimeType isEqualToString: @"text/html"])
|
||||
hasHtml = YES;
|
||||
}
|
||||
[bodyPartsMixed setObject: [NSNumber numberWithBool: mixedPart] forKey: key];
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
@@ -336,17 +345,28 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
if (charset)
|
||||
{
|
||||
if (headerCharset == nil)
|
||||
ASSIGN (headerCharset, charset);
|
||||
{
|
||||
ASSIGN (headerCharset, charset);
|
||||
}
|
||||
else if (![headerCharset isEqualToString: charset])
|
||||
{
|
||||
/* Because we have different charsets we will encode all in UTF-8 */
|
||||
ASSIGN (headerCharset, @"utf-8");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!hasHtml || !hasText)
|
||||
multipartMixed = NO;
|
||||
{
|
||||
NSArray *bodyPartsMixedKeys = [bodyPartsMixed allKeys];
|
||||
for (i = 0; i < [keys count]; i++)
|
||||
{
|
||||
NSString *key = [bodyPartsMixedKeys objectAtIndex: i];
|
||||
[bodyPartsMixed setObject: [NSNumber numberWithBool: NO] forKey: key];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ([headerMimeType isEqualToString: @"text/calendar"]
|
||||
|| [headerMimeType isEqualToString: @"application/ics"])
|
||||
@@ -410,9 +430,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
NSString *mimeType = [bodyPartsMimeTypes objectForKey: key];
|
||||
if (mimeType == nil)
|
||||
continue;
|
||||
NSString *encoding = [bodyPartsEncodings objectForKey: key];
|
||||
if (encoding == nil)
|
||||
encoding = @"7-bit";
|
||||
NSString *contentEncoding = [bodyPartsEncodings objectForKey: key];
|
||||
if (contentEncoding == nil)
|
||||
contentEncoding = @"7-bit";
|
||||
|
||||
/* We should provide a case for each of the types in acceptedMimeTypes */
|
||||
if (!mailIsEvent)
|
||||
@@ -421,6 +441,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
NSStringEncoding charsetEncoding;
|
||||
NSString *stringValue;
|
||||
BOOL html;
|
||||
BOOL mixed = [[bodyPartsMixed objectForKey: key] boolValue];
|
||||
if ([mimeType isEqualToString: @"text/html"])
|
||||
{
|
||||
html = YES;
|
||||
@@ -436,7 +457,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
continue;
|
||||
}
|
||||
|
||||
content = [content bodyDataFromEncoding: encoding];
|
||||
content = [content bodyDataFromEncoding: contentEncoding];
|
||||
charset = [bodyPartsCharsets objectForKey: key];
|
||||
|
||||
stringValue = nil;
|
||||
@@ -459,7 +480,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
[textContent appendData: [stringValue dataUsingEncoding: headerEncoding]];
|
||||
}
|
||||
|
||||
if (multipartMixed)
|
||||
if (mixed)
|
||||
{
|
||||
// We must add it also to the other mail representation
|
||||
if (html)
|
||||
@@ -491,9 +512,9 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
else
|
||||
{
|
||||
/* Without charset we cannot mangle the text, so we add as it stands */
|
||||
if (html || multipartMixed)
|
||||
if (html || mixed)
|
||||
[htmlContent appendData: content];
|
||||
if (!html || multipartMixed)
|
||||
if (!html || mixed)
|
||||
[textContent appendData: content];
|
||||
}
|
||||
|
||||
@@ -501,7 +522,7 @@ _compareBodyKeysByPriority (id entry1, id entry2, void *data)
|
||||
else if ([mimeType isEqualToString: @"text/calendar"] ||
|
||||
[mimeType isEqualToString: @"application/ics"])
|
||||
{
|
||||
content = [content bodyDataFromEncoding: encoding];
|
||||
content = [content bodyDataFromEncoding: contentEncoding];
|
||||
[textContent appendData: content];
|
||||
}
|
||||
else
|
||||
|
||||
@@ -129,9 +129,9 @@ NSArray *SOGoMailCoreInfoKeys;
|
||||
inContext: (id)_ctx;
|
||||
|
||||
- (void) addRequiredKeysOfStructure: (NSDictionary *) info
|
||||
path: (NSString *) p
|
||||
toArray: (NSMutableArray *) keys
|
||||
acceptedTypes: (NSArray *) types
|
||||
path: (NSString *) p
|
||||
toArray: (NSMutableArray *) keys
|
||||
acceptedTypes: (NSArray *) types
|
||||
withPeek: (BOOL) withPeek;
|
||||
|
||||
@end
|
||||
|
||||
@@ -516,12 +516,15 @@ static BOOL debugSoParts = NO;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* This is defined before the public version without parentMimeType
|
||||
argument to be able to call it recursively */
|
||||
/* bulk fetching of plain/text content */
|
||||
- (void) addRequiredKeysOfStructure: (NSDictionary *) info
|
||||
path: (NSString *) p
|
||||
toArray: (NSMutableArray *) keys
|
||||
acceptedTypes: (NSArray *) types
|
||||
path: (NSString *) p
|
||||
toArray: (NSMutableArray *) keys
|
||||
acceptedTypes: (NSArray *) types
|
||||
withPeek: (BOOL) withPeek
|
||||
parentMultipart: (NSString *) parentMPart
|
||||
{
|
||||
/*
|
||||
This is used to collect the set of IMAP4 fetch-keys required to fetch
|
||||
@@ -536,6 +539,7 @@ static BOOL debugSoParts = NO;
|
||||
id body;
|
||||
NSString *bodyToken, *sp, *mimeType;
|
||||
id childInfo;
|
||||
NSString *multipart;
|
||||
|
||||
bodyToken = (withPeek ? @"body.peek" : @"body");
|
||||
|
||||
@@ -543,6 +547,12 @@ static BOOL debugSoParts = NO;
|
||||
[info valueForKey: @"type"],
|
||||
[info valueForKey: @"subtype"]]
|
||||
lowercaseString];
|
||||
|
||||
if ([[info valueForKey: @"type"] isEqualToString: @"multipart"])
|
||||
multipart = mimeType;
|
||||
else
|
||||
multipart = parentMPart;
|
||||
|
||||
if ([types containsObject: mimeType])
|
||||
{
|
||||
if ([p length] > 0)
|
||||
@@ -557,7 +567,8 @@ static BOOL debugSoParts = NO;
|
||||
k = [NSString stringWithFormat: @"%@[text]", bodyToken];
|
||||
}
|
||||
[keys addObject: [NSDictionary dictionaryWithObjectsAndKeys: k, @"key",
|
||||
mimeType, @"mimeType", nil]];
|
||||
mimeType, @"mimeType",
|
||||
multipart, @"multipart", nil]];
|
||||
}
|
||||
|
||||
parts = [info objectForKey: @"parts"];
|
||||
@@ -571,9 +582,11 @@ static BOOL debugSoParts = NO;
|
||||
childInfo = [parts objectAtIndex: i];
|
||||
|
||||
[self addRequiredKeysOfStructure: childInfo
|
||||
path: sp toArray: keys
|
||||
acceptedTypes: types
|
||||
withPeek: withPeek];
|
||||
path: sp
|
||||
toArray: keys
|
||||
acceptedTypes: types
|
||||
withPeek: withPeek
|
||||
parentMultipart: multipart];
|
||||
}
|
||||
|
||||
/* check body */
|
||||
@@ -597,12 +610,28 @@ static BOOL debugSoParts = NO;
|
||||
else
|
||||
sp = [p length] > 0 ? (id)[p stringByAppendingString: @".1"] : (id)@"1";
|
||||
[self addRequiredKeysOfStructure: body
|
||||
path: sp toArray: keys
|
||||
acceptedTypes: types
|
||||
withPeek: withPeek];
|
||||
path: sp
|
||||
toArray: keys
|
||||
acceptedTypes: types
|
||||
withPeek: withPeek
|
||||
parentMultipart: multipart];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) addRequiredKeysOfStructure: (NSDictionary *) info
|
||||
path: (NSString *) p
|
||||
toArray: (NSMutableArray *) keys
|
||||
acceptedTypes: (NSArray *) types
|
||||
withPeek: (BOOL) withPeek
|
||||
{
|
||||
[self addRequiredKeysOfStructure: (NSDictionary *) info
|
||||
path: (NSString *) p
|
||||
toArray: (NSMutableArray *) keys
|
||||
acceptedTypes: (NSArray *) types
|
||||
withPeek: (BOOL) withPeek
|
||||
parentMultipart: @""];
|
||||
}
|
||||
|
||||
- (NSArray *) plainTextContentFetchKeys
|
||||
{
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user