(feat) many improvements to EAS SmartReply/SmartForward commands

This commit is contained in:
Ludovic Marcotte
2015-05-14 15:49:53 -04:00
parent cc1e9f2fff
commit c98a000515
2 changed files with 197 additions and 46 deletions
+196 -46
View File
@@ -61,6 +61,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <NGExtensions/NGHashMap.h>
#import <NGExtensions/NSObject+Logs.h>
#import <NGExtensions/NSString+misc.h>
#import <NGExtensions/NSString+Encoding.h>
#import <NGImap4/NGImap4Client.h>
#import <NGImap4/NGImap4Connection.h>
@@ -95,6 +96,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <SOGo/GCSSpecialQueries+SOGoCacheObject.h>
#import <SOGo/NSString+Utilities.h>
#import <SOGo/WORequest+SOGo.h>
#import <SOGo/NSArray+Utilities.h>
#import <Appointments/SOGoAppointmentFolder.h>
#import <Appointments/SOGoAppointmentFolders.h>
@@ -110,6 +112,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#import <Mailer/SOGoMailBodyPart.h>
#import <Mailer/SOGoMailFolder.h>
#import <Mailer/SOGoMailObject.h>
#import <Mailer/SOGoMailObject+Draft.h>
#import <Mailer/NSString+Mail.h>
#import <Foundation/NSObject.h>
#import <Foundation/NSString.h>
@@ -2389,26 +2394,19 @@ static BOOL debugOn = NO;
}
//
// <?xml version="1.0"?>
// <!DOCTYPE ActiveSync PUBLIC "-//MICROSOFT//DTD ActiveSync//EN" "http://www.microsoft.com/">
// <SmartForward xmlns="ComposeMail:">
// <ClientId>C9FF94FE-EA40-473A-B3E2-AAEE94F753A4</ClientId>
// <SaveInSentItems/>
// <ReplaceMime/>
// <Source>
// <FolderId>mail/INBOX</FolderId>
// <ItemId>82</ItemId>
// </Source>
// <MIME>... the data ...</MIME>
// </SmartForward>
//
- (void) processSmartForward: (id <DOMElement>) theDocumentElement
inResponse: (WOResponse *) theResponse
- (void) _processSmartCommand: (id <DOMElement>) theDocumentElement
inResponse: (WOResponse *) theResponse
isSmartForward: (BOOL ) isSmartForward
{
NSString *folderId, *itemId, *realCollectionId;
SOGoMicrosoftActiveSyncFolderType folderType;
SOGoUserDefaults *ud;
BOOL htmlComposition, isHTML;
id value;
isHTML = NO;
ud = [[context activeUser] userDefaults];
folderId = [[(id)[theDocumentElement getElementsByTagName: @"FolderId"] lastObject] textValue];
@@ -2457,11 +2455,15 @@ static BOOL debugOn = NO;
NGMutableHashMap *map;
NGMimeFileData *fdata;
NSException *error;
NSArray *attachmentKeys;
NSMutableArray *attachments;
id body, bodyFromSmartForward;
NSString *fullName, *email;
id body, bodyFromSmartForward, htmlPart, textPart;
NSString *fullName, *email, *charset, *s;
NSDictionary *identity;
int a;
userFolder = [[context activeUser] homeFolderInContext: context];
accountsFolder = [userFolder lookupName: @"Mail" inContext: context acquire: NO];
currentFolder = [accountsFolder lookupName: @"0" inContext: context acquire: NO];
@@ -2472,7 +2474,6 @@ static BOOL debugOn = NO;
mailObject = [currentCollection lookupName: itemId inContext: context acquire: NO];
parser = [[NGMimeMessageParser alloc] init];
data = [[[[(id)[theDocumentElement getElementsByTagName: @"MIME"] lastObject] textValue] stringByDecodingBase64] dataUsingEncoding: NSUTF8StringEncoding];
messageFromSmartForward = [parser parsePartFromData: data];
@@ -2493,8 +2494,8 @@ static BOOL debugOn = NO;
else
[map setObject: email forKey: @"from"];
if ([[mailObject envelope] messageId])
[map setObject: [[mailObject envelope] messageId] forKey: @"in-reply-to"];
if ([mailObject messageId])
[map setObject: [mailObject messageId] forKey: @"in-reply-to"];
messageToSend = [[[NGMimeMessage alloc] initWithHeader: map] autorelease];
body = [[[NGMimeMultipartBody alloc] initWithPart: messageToSend] autorelease];
@@ -2503,12 +2504,16 @@ static BOOL debugOn = NO;
// we take the first part text/* part we see.
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
bodyFromSmartForward = nil;
textPart = nil;
htmlPart = nil;
attachments = [NSMutableArray array];
if ([[messageFromSmartForward body] isKindOfClass: [NGMimeMultipartBody class]])
{
NGMimeBodyPart *part;
NSArray *parts;
int i;
NGMimeBodyPart *part, *apart;
NSArray *parts, *aparts;
int i, j;
parts = [[messageFromSmartForward body] parts];
@@ -2516,37 +2521,159 @@ static BOOL debugOn = NO;
{
part = [parts objectAtIndex: i];
if ([[[part contentType] type] isEqualToString: @"text"])
if ([[[part contentType] type] isEqualToString: @"multipart"] && [[[part contentType] subType] isEqualToString: @"alternative"])
{
[map setObject: [[part contentType] stringValue] forKey: @"content-type"];
bodyFromSmartForward = [part body];
break;
aparts = [[part body] parts];
for (j = 0; j < [aparts count]; j++)
{
apart = [aparts objectAtIndex: j];
if ([[[apart contentType] type] isEqualToString: @"text"] && [[[apart contentType] subType] isEqualToString: @"html"])
htmlPart = apart;
if ([[[apart contentType] type] isEqualToString: @"text"] && [[[apart contentType] subType] isEqualToString: @"plain"])
textPart = apart;
}
}
else
{
if ([[[part contentType] type] isEqualToString: @"text"] && [[[part contentType] subType] isEqualToString: @"html"])
htmlPart = part;
else if ([[[part contentType] type] isEqualToString: @"text"] && [[[part contentType] subType] isEqualToString: @"plain"])
textPart = part;
else
[attachments addObject: part];
}
}
}
else
{
[map setObject: [[messageFromSmartForward contentType] stringValue] forKey: @"content-type"];
bodyFromSmartForward = [messageFromSmartForward body];
if ([[[messageFromSmartForward contentType] type] isEqualToString: @"text"] && [[[messageFromSmartForward contentType] subType] isEqualToString: @"html"])
htmlPart = messageFromSmartForward;
else
textPart = messageFromSmartForward;
}
htmlComposition = [[ud mailComposeMessageType] isEqualToString: @"html"];
if (htmlComposition && htmlPart)
{
bodyFromSmartForward = [htmlPart body];
charset = [[htmlPart contentType] valueOfParameter: @"charset"];
isHTML = YES;
}
else if (!htmlComposition && !textPart)
{
bodyFromSmartForward = [htmlPart body];
charset = [[htmlPart contentType] valueOfParameter: @"charset"];
isHTML = YES;
}
else
{
bodyFromSmartForward = [textPart body];
charset = [[textPart contentType] valueOfParameter: @"charset"];
}
// We make sure everything is encoded in UTF-8.
if ([bodyFromSmartForward isKindOfClass: [NSData class]])
{
if (![charset length])
charset = @"utf-8";
s = [NSString stringWithData: bodyFromSmartForward usingEncodingNamed: charset];
// We fallback to ISO-8859-1 string encoding. We avoid #3103.
if (!s)
s = [[[NSString alloc] initWithData: bodyFromSmartForward encoding: NSISOLatin1StringEncoding] autorelease];
bodyFromSmartForward = s;
}
if (htmlComposition && !isHTML)
{
[map setObject: @"text/html; charset=utf-8" forKey: @"content-type"];
bodyFromSmartForward = [[bodyFromSmartForward stringByEscapingHTMLString] stringByConvertingCRLNToHTML];
}
else if (!htmlComposition && isHTML)
{
[map setObject: @"text/plain; charset=utf-8" forKey: @"content-type"];
bodyFromSmartForward = [bodyFromSmartForward htmlToText];
}
else if (htmlComposition && isHTML)
{
[map setObject: @"text/html; charset=utf-8" forKey: @"content-type"];
}
else
{
[map setObject: @"text/plain; charset=utf-8" forKey: @"content-type"];
}
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader:map] autorelease];
[bodyPart setBody: bodyFromSmartForward];
if (isSmartForward && [[ud mailMessageForwarding] isEqualToString: @"attached"])
[bodyPart setBody: [bodyFromSmartForward dataUsingEncoding: NSUTF8StringEncoding]];
else
[bodyPart setBody: [[NSString stringWithFormat: @"%@%@", bodyFromSmartForward, [mailObject contentForEditing]] dataUsingEncoding: NSUTF8StringEncoding]];
[body addBodyPart: bodyPart];
// Second part
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
[map setObject: @"message/rfc822" forKey: @"content-type"];
[map setObject: @"8bit" forKey: @"content-transfer-encoding"];
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader:map] autorelease];
data = [mailObject content];
fdata = [[NGMimeFileData alloc] initWithBytes:[data bytes]
length:[data length]];
// Add attachments
for (a = 0; a < [attachments count]; a++)
{
[body addBodyPart: [attachments objectAtIndex: a]];
}
// For a forward decide whether do it inline or as an attachment.
if (isSmartForward)
{
if ([[ud mailMessageForwarding] isEqualToString: @"attached"])
{
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
[map setObject: @"message/rfc822" forKey: @"content-type"];
[map setObject: @"8bit" forKey: @"content-transfer-encoding"];
[map addObject: [NSString stringWithFormat: @"attachment; filename=\"%@\"", [mailObject filenameForForward]] forKey: @"content-disposition"];
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader: map] autorelease];
data = [mailObject content];
fdata = [[NGMimeFileData alloc] initWithBytes: [data bytes] length: [data length]];
[bodyPart setBody: fdata];
RELEASE(fdata);
[body addBodyPart: bodyPart];
}
else
{
attachmentKeys = [mailObject fetchFileAttachmentKeys];
if ([attachmentKeys count])
{
id currentAttachment;
NGHashMap *response;
NSData *bodydata;
NSArray *paths;
paths = [attachmentKeys keysWithFormat: @"BODY[%{path}]"];
response = [[mailObject fetchParts: paths] objectForKey: @"RawResponse"];
for (a = 0; a < [attachmentKeys count]; a++)
{
currentAttachment = [attachmentKeys objectAtIndex: a];
bodydata = [[[response objectForKey: @"fetch"] objectForKey: [NSString stringWithFormat: @"body[%@]", [currentAttachment objectForKey: @"path"]]] valueForKey: @"data"];
map = [[[NGMutableHashMap alloc] initWithCapacity: 1] autorelease];
[map setObject: [currentAttachment objectForKey: @"mimetype"] forKey: @"content-type"];
[map setObject: [currentAttachment objectForKey: @"encoding"] forKey: @"content-transfer-encoding"];
[map addObject: [NSString stringWithFormat: @"attachment; filename=\"%@\"", [currentAttachment objectForKey: @"filename"]] forKey: @"content-disposition"];
bodyPart = [[[NGMimeBodyPart alloc] initWithHeader: map] autorelease];
fdata = [[NGMimeFileData alloc] initWithBytes:[bodydata bytes] length:[bodydata length]];
[bodyPart setBody: fdata];
RELEASE(fdata);
[body addBodyPart: bodyPart];
}
}
}
}
[bodyPart setBody: fdata];
RELEASE(fdata);
[body addBodyPart: bodyPart];
[messageToSend setBody: body];
generator = [[[NGMimeMessageGenerator alloc] init] autorelease];
@@ -2570,6 +2697,29 @@ static BOOL debugOn = NO;
}
}
//
// <?xml version="1.0"?>
// <!DOCTYPE ActiveSync PUBLIC "-//MICROSOFT//DTD ActiveSync//EN" "http://www.microsoft.com/">
// <SmartForward xmlns="ComposeMail:">
// <ClientId>C9FF94FE-EA40-473A-B3E2-AAEE94F753A4</ClientId>
// <SaveInSentItems/>
// <ReplaceMime/>
// <Source>
// <FolderId>mail/INBOX</FolderId>
// <ItemId>82</ItemId>
// </Source>
// <MIME>... the data ...</MIME>
// </SmartForward>
//
- (void) processSmartForward: (id <DOMElement>) theDocumentElement
inResponse: (WOResponse *) theResponse
{
[self _processSmartCommand: theDocumentElement
inResponse: theResponse
isSmartForward: YES];
}
//
// <?xml version="1.0"?>
// <!DOCTYPE ActiveSync PUBLIC "-//MICROSOFT//DTD ActiveSync//EN" "http://www.microsoft.com/">
@@ -2587,11 +2737,11 @@ static BOOL debugOn = NO;
- (void) processSmartReply: (id <DOMElement>) theDocumentElement
inResponse: (WOResponse *) theResponse
{
[self processSmartForward: theDocumentElement inResponse: theResponse];
[self _processSmartCommand: theDocumentElement
inResponse: theResponse
isSmartForward: NO];
}
//
//
//
+1
View File
@@ -19,6 +19,7 @@ Enhancements
- make sure sure email invitations can always be read by EAS clients
- now able to print event/task's description (new components only) in the list view (#2881)
- now possible to log EAS commands using the SOGoEASDebugEnabled system defaults
- many improvements to EAS SmartReply/SmartForward commands
Bug fixes
- now keep the BodyPreference for future EAS use and default to MIME if none set (#3146)