/* SOGoMailObject+Draft.m - this file is part of SOGo * * Copyright (C) 2007-2017 Inverse inc. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #import #import #import #import #import #import #import #import #import #import #import #import #import #import "NSData+Mail.h" #import "NSData+SMIME.h" #import "NSString+Mail.h" #import "SOGoMailAccount.h" #import "SOGoMailObject+Draft.h" #import "SOGoMailReply.h" #define MAX_FILENAME_LENGTH 64 // // // @implementation SOGoMailObject (SOGoDraftObjectExtensions) - (NSString *) subjectForReply { static NSString *replyPrefixes[] = { @"Re:", // regular @"RE:", // Outlook v11 (English?) @"AW:", // German Outlook v11 @"Re[", // numbered Re, eg "Re[2]:" nil }; BOOL hasPrefix; NSUInteger i; NSString *subject, *newSubject; hasPrefix = NO; subject = [self decodedSubject]; if (![subject length]) subject = @""; i = 0; while (!hasPrefix && replyPrefixes[i]) if ([subject hasPrefix: replyPrefixes[i]]) hasPrefix = YES; else i++; if (hasPrefix) newSubject = subject; else newSubject = [NSString stringWithFormat: @"Re: %@", subject]; return newSubject; } // // // - (NSString *) _convertRawContentForEditing: (NSString *) raw rawHtml: (BOOL) html { NSString *rc; SOGoUserDefaults *ud; BOOL htmlComposition; ud = [[context activeUser] userDefaults]; htmlComposition = [[ud mailComposeMessageType] isEqualToString: @"html"]; if (html && !htmlComposition) rc = [raw htmlToText]; else if (!html && htmlComposition) rc = [[raw stringByEscapingHTMLString] stringByConvertingCRLNToHTML]; else rc = raw; return rc; } // // // - (NSString *) _contentForEditingFromKeys: (NSArray *) keys { NSString *rawPart, *content, *contentKey; SOGoUserDefaults *ud; NSDictionary *parts; NSArray *types; NSData *data; BOOL htmlComposition, htmlContent; NSUInteger index; content = @""; if ([keys count]) { ud = [[context activeUser] userDefaults]; htmlComposition = [[ud mailComposeMessageType] isEqualToString: @"html"]; htmlContent = NO; types = [keys objectsForKey: @"mimeType" notFoundMarker: @""]; if (htmlComposition) { // Prefer HTML content index = [types indexOfObject: @"text/html"]; if (index == NSNotFound) index = [types indexOfObject: @"text/plain"]; else htmlContent = YES; } else { // Prefer text content index = [types indexOfObject: @"text/plain"]; if (index == NSNotFound) { index = [types indexOfObject: @"text/html"]; htmlContent = YES; } } if (index != NSNotFound) { contentKey = [keys objectAtIndex: index]; parts = [self fetchPlainTextStrings: [NSArray arrayWithObject: contentKey]]; if ([parts count] > 0) { rawPart = [[parts allValues] objectAtIndex: 0]; content = [self _convertRawContentForEditing: rawPart rawHtml: htmlContent]; } } } // We strip charset= information from HTML content to avoid SOGo setting // the encoding of the final mail to UTF-8 while keeping charset="iso-8859-1" // in the HTML meta headers, for example. That would cause encoding display // issues with most MUAs. data = [[content dataUsingEncoding: NSUTF8StringEncoding] sanitizedContentUsingVoidTags: nil]; content = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; return [content autorelease]; } // // // - (NSString *) _preferredContentFromPart: (id) thePart favorHTML: (BOOL) favorHTML { NSString *type, *subtype; id body; if ([thePart isKindOfClass: [NGMimeBodyPart class]]) { type = [[thePart contentType] type]; subtype = [[thePart contentType] subType]; body = [thePart body]; if ([type isEqualToString: @"text"]) { if ([subtype isEqualToString: @"html"] && favorHTML) return [[body stringByEscapingHTMLString] stringByConvertingCRLNToHTML]; else if ([subtype isEqualToString: @"html"] && !favorHTML) return [body htmlToText]; else if ([subtype isEqualToString: @"plain"]) return body; } } else if ([thePart isKindOfClass: [NGMimeMultipartBody class]]) { NSArray *parts; int i; parts = [thePart parts]; for (i = 0; i < [parts count]; i++) { type = [[[parts objectAtIndex: i] contentType] type]; if ([type isEqualToString: @"text"] || [type isEqualToString: @"multipart"]) return [self _preferredContentFromPart: [parts objectAtIndex: i] favorHTML: favorHTML]; } } return nil; } // // // - (NSString *) _contentForEditingFromEncryptedMail { NSData *certificate; certificate = [[self mailAccountFolder] certificate]; if (certificate) { SOGoUserDefaults *ud; NGMimeMessage *m; m = [[self content] messageFromEncryptedDataAndCertificate: certificate]; ud = [[context activeUser] userDefaults]; return [self _preferredContentFromPart: [m body] favorHTML: [[ud mailComposeMessageType] isEqualToString: @"html"]]; } return nil; } // // // - (NSString *) _contentForEditingFromOpaqueSignedMail { SOGoUserDefaults *ud; NGMimeMessage *m; m = [[self content] messageFromOpaqueSignedData]; ud = [[context activeUser] userDefaults]; return [self _preferredContentFromPart: [m body] favorHTML: [[ud mailComposeMessageType] isEqualToString: @"html"]]; return nil; } // // // - (NSString *) contentForEditing { NSMutableArray *keys; NSString *output; output = nil; if ([self isEncrypted]) output = [self _contentForEditingFromEncryptedMail]; else if ([self isOpaqueSigned]) output = [self _contentForEditingFromOpaqueSignedMail]; // If not encrypted or if decryption failed, we fallback // to the normal content fetching code. if (!output) { keys = [NSMutableArray array]; [self addRequiredKeysOfStructure: [self bodyStructure] path: @"" toArray: keys acceptedTypes: [NSArray arrayWithObjects: @"text/plain", @"text/html", nil] withPeek: NO]; output = [self _contentForEditingFromKeys: keys]; } return output; } // // // - (NSString *) contentForReply { NSString *pageName; SOGoMailReply *page; SOGoUserDefaults *userDefaults; userDefaults = [[context activeUser] userDefaults]; pageName = [NSString stringWithFormat: @"SOGoMail%@Reply", [userDefaults language]]; page = [[WOApplication application] pageWithName: pageName inContext: context]; [page setSourceMail: self]; [page setOutlookMode: [userDefaults mailUseOutlookStyleReplies]]; [page setReplyPlacement: [userDefaults mailReplyPlacement]]; [page setSignaturePlacement: [userDefaults mailSignaturePlacement]]; return [[page generateResponse] contentAsString]; } // // // - (NSString *) filenameForForward { NSString *subject; NSMutableString *newSubject; static NSString *sescape[] = { @"/", @"..", @"~", @"\"", @"'", @" ", @".", nil }; NSUInteger count, length; subject = [self decodedSubject]; length = [subject length]; if (!length) { subject = @"forward"; length = [subject length]; } if (length > MAX_FILENAME_LENGTH) length = MAX_FILENAME_LENGTH; newSubject = [NSMutableString stringWithString: [subject substringToIndex: length]]; count = 0; while (sescape[count]) { [newSubject replaceString: sescape[count] withString: @"_"]; count++; } [newSubject appendString: @".eml"]; return newSubject; } // // // - (NSString *) subjectForForward { NSString *subject, *newSubject; subject = [self decodedSubject]; if ([subject length] > 0) newSubject = [NSString stringWithFormat: @"Fwd: %@", subject]; else newSubject = subject; return newSubject; } // // // - (NSString *) contentForInlineForward { SOGoUserDefaults *userDefaults; NSString *pageName; SOGoMailForward *page; userDefaults = [[context activeUser] userDefaults]; pageName = [NSString stringWithFormat: @"SOGoMail%@Forward", [userDefaults language]]; page = [[WOApplication application] pageWithName: pageName inContext: context]; [page setSourceMail: self]; [page setSignaturePlacement: [userDefaults mailSignaturePlacement]]; return [[page generateResponse] contentAsString]; } @end