/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * This Original Code has been modified by IBM Corporation. Modifications made * by IBM described herein are Copyright (c) International Business Machines * Corporation, 2000. Modifications to Mozilla code or documentation identified * per MPL Section 3.3 * * Date Modified by Description of modification * 04/20/2000 IBM Corp. OS/2 VisualAge build. */ #include "nsCOMPtr.h" #include "modmimee.h" #include "mimeobj.h" #include "modlmime.h" #include "mimei.h" #include "mimebuf.h" #include "mimemoz2.h" #include "mimemsg.h" #include "nsMimeTypes.h" #include #include "prmem.h" #include "plstr.h" #include "prprf.h" #include "prio.h" #include "nsIPrefService.h" #include "nsIPrefBranch.h" #include "msgCore.h" #include "nsIMsgSend.h" #include "nsMimeStringResources.h" #include "nsNetUtil.h" #include "comi18n.h" #include "nsIMsgAttachment.h" #include "nsIMsgCompFields.h" #include "nsIMsgComposeService.h" #include "nsMsgAttachmentData.h" #include "nsMsgI18N.h" #include "nsNativeCharsetUtils.h" #include "nsDirectoryServiceDefs.h" #include "nsIMsgMessageService.h" #include "nsMsgUtils.h" #include "nsCExternalHandlerService.h" #include "nsIMIMEService.h" #include "nsIMsgAccountManager.h" #include "modmimee.h" // for MimeConverterOutputCallback #include "mozilla/dom/Promise.h" #include "mozilla/mailnews/MimeHeaderParser.h" using namespace mozilla::mailnews; // // Header strings... // #define HEADER_NNTP_POSTING_HOST "NNTP-Posting-Host" #define MIME_HEADER_TABLE \ "" #define HEADER_START_JUNK "" // // Forward declarations... // extern "C" char* MIME_StripContinuations(char* original); int mime_decompose_file_init_fn(void* stream_closure, MimeHeaders* headers); int mime_decompose_file_output_fn(const char* buf, int32_t size, void* stream_closure); int mime_decompose_file_close_fn(void* stream_closure); extern int MimeHeaders_build_heads_list(MimeHeaders* hdrs); #define NS_MSGCOMPOSESERVICE_CID \ { /* 588595FE-1ADA-11d3-A715-0060B0EB39B5 */ \ 0x588595fe, 0x1ada, 0x11d3, { \ 0xa7, 0x15, 0x0, 0x60, 0xb0, 0xeb, 0x39, 0xb5 \ } \ } static NS_DEFINE_CID(kCMsgComposeServiceCID, NS_MSGCOMPOSESERVICE_CID); mime_draft_data::mime_draft_data() : url_name(nullptr), format_out(0), stream(nullptr), obj(nullptr), options(nullptr), headers(nullptr), messageBody(nullptr), curAttachment(nullptr), decoder_data(nullptr), mailcharset(nullptr), forwardInline(false), forwardInlineFilter(false), overrideComposeFormat(false), autodetectCharset(false) {} //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// // THIS SHOULD ALL MOVE TO ANOTHER FILE AFTER LANDING! //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// // safe filename for all OSes #define SAFE_TMP_FILENAME "nsmime.tmp" // // Create a file for the a unique temp file // on the local machine. Caller must free memory // nsresult nsMsgCreateTempFile(const char* tFileName, nsIFile** tFile) { if (!tFileName || !*tFileName) tFileName = SAFE_TMP_FILENAME; nsresult rv = GetSpecialDirectoryWithFileName(NS_OS_TEMP_DIR, tFileName, tFile); NS_ENSURE_SUCCESS(rv, rv); rv = (*tFile)->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 00600); if (NS_FAILED(rv)) NS_RELEASE(*tFile); return rv; } //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// // END OF - THIS SHOULD ALL MOVE TO ANOTHER FILE AFTER LANDING! //////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////// typedef enum { nsMsg_RETURN_RECEIPT_BOOL_HEADER_MASK = 0, nsMsg_ENCRYPTED_BOOL_HEADER_MASK, nsMsg_SIGNED_BOOL_HEADER_MASK, nsMsg_UUENCODE_BINARY_BOOL_HEADER_MASK, nsMsg_ATTACH_VCARD_BOOL_HEADER_MASK, nsMsg_LAST_BOOL_HEADER_MASK // last boolean header mask; must be the last one // DON'T remove. } nsMsgBoolHeaderSet; #ifdef NS_DEBUG extern "C" void mime_dump_attachments(nsMsgAttachmentData* attachData) { int32_t i = 0; class nsMsgAttachmentData* tmp = attachData; while (tmp && tmp->m_url) { printf("Real Name : %s\n", tmp->m_realName.get()); if (tmp->m_url) { ; printf("URL : %s\n", tmp->m_url->GetSpecOrDefault().get()); } printf("Desired Type : %s\n", tmp->m_desiredType.get()); printf("Real Type : %s\n", tmp->m_realType.get()); printf("Real Encoding : %s\n", tmp->m_realEncoding.get()); printf("Description : %s\n", tmp->m_description.get()); printf("Mac Type : %s\n", tmp->m_xMacType.get()); printf("Mac Creator : %s\n", tmp->m_xMacCreator.get()); printf("Size in bytes : %d\n", tmp->m_size); i++; tmp++; } } #endif nsresult CreateComposeParams(nsCOMPtr& pMsgComposeParams, nsIMsgCompFields* compFields, nsMsgAttachmentData* attachmentList, MSG_ComposeType composeType, MSG_ComposeFormat composeFormat, nsIMsgIdentity* identity, const nsACString& originalMsgURI, nsIMsgDBHdr* origMsgHdr) { #ifdef NS_DEBUG mime_dump_attachments(attachmentList); #endif nsresult rv; nsMsgAttachmentData* curAttachment = attachmentList; if (curAttachment) { nsAutoCString spec; while (curAttachment && curAttachment->m_url) { rv = curAttachment->m_url->GetSpec(spec); if (NS_SUCCEEDED(rv)) { nsCOMPtr attachment = do_CreateInstance( "@mozilla.org/messengercompose/attachment;1", &rv); if (NS_SUCCEEDED(rv) && attachment) { nsAutoString nameStr; rv = nsMsgI18NConvertToUnicode("UTF-8"_ns, curAttachment->m_realName, nameStr); if (NS_FAILED(rv)) CopyASCIItoUTF16(curAttachment->m_realName, nameStr); attachment->SetName(nameStr); attachment->SetUrl(spec); attachment->SetTemporary(true); attachment->SetContentType(curAttachment->m_realType.get()); attachment->SetMacType(curAttachment->m_xMacType.get()); attachment->SetMacCreator(curAttachment->m_xMacCreator.get()); attachment->SetSize(curAttachment->m_size); if (!curAttachment->m_cloudPartInfo.IsEmpty()) { nsCString provider; nsCString cloudUrl; nsCString cloudPartHeaderData; provider.Adopt( MimeHeaders_get_parameter(curAttachment->m_cloudPartInfo.get(), "provider", nullptr, nullptr)); cloudUrl.Adopt(MimeHeaders_get_parameter( curAttachment->m_cloudPartInfo.get(), "url", nullptr, nullptr)); cloudPartHeaderData.Adopt( MimeHeaders_get_parameter(curAttachment->m_cloudPartInfo.get(), "data", nullptr, nullptr)); attachment->SetSendViaCloud(true); attachment->SetCloudFileAccountKey(provider); attachment->SetContentLocation(cloudUrl); attachment->SetCloudPartHeaderData(cloudPartHeaderData); } compFields->AddAttachment(attachment); } } curAttachment++; } } MSG_ComposeFormat format = composeFormat; // Format to actually use. if (identity && composeType == nsIMsgCompType::ForwardInline) { bool composeHtml = false; identity->GetComposeHtml(&composeHtml); if (composeHtml) format = (composeFormat == nsIMsgCompFormat::OppositeOfDefault) ? nsIMsgCompFormat::PlainText : nsIMsgCompFormat::HTML; else format = (composeFormat == nsIMsgCompFormat::OppositeOfDefault) ? nsIMsgCompFormat::HTML : nsIMsgCompFormat::PlainText; } pMsgComposeParams = do_CreateInstance("@mozilla.org/messengercompose/composeparams;1", &rv); NS_ENSURE_SUCCESS(rv, rv); pMsgComposeParams->SetType(composeType); pMsgComposeParams->SetFormat(format); pMsgComposeParams->SetIdentity(identity); pMsgComposeParams->SetComposeFields(compFields); if (!originalMsgURI.IsEmpty()) pMsgComposeParams->SetOriginalMsgURI(originalMsgURI); if (origMsgHdr) pMsgComposeParams->SetOrigMsgHdr(origMsgHdr); return NS_OK; } nsresult CreateTheComposeWindow(nsIMsgCompFields* compFields, nsMsgAttachmentData* attachmentList, MSG_ComposeType composeType, MSG_ComposeFormat composeFormat, nsIMsgIdentity* identity, const nsACString& originalMsgURI, nsIMsgDBHdr* origMsgHdr) { nsCOMPtr pMsgComposeParams; nsresult rv = CreateComposeParams(pMsgComposeParams, compFields, attachmentList, composeType, composeFormat, identity, originalMsgURI, origMsgHdr); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr msgComposeService = do_GetService(kCMsgComposeServiceCID, &rv); NS_ENSURE_SUCCESS(rv, rv); return msgComposeService->OpenComposeWindowWithParams( nullptr /* default chrome */, pMsgComposeParams); } nsresult ForwardMsgInline(nsIMsgCompFields* compFields, nsMsgAttachmentData* attachmentList, MSG_ComposeFormat composeFormat, nsIMsgIdentity* identity, const nsACString& originalMsgURI, nsIMsgDBHdr* origMsgHdr) { nsCOMPtr pMsgComposeParams; nsresult rv = CreateComposeParams(pMsgComposeParams, compFields, attachmentList, nsIMsgCompType::ForwardInline, composeFormat, identity, originalMsgURI, origMsgHdr); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr msgComposeService = do_GetService(kCMsgComposeServiceCID, &rv); NS_ENSURE_SUCCESS(rv, rv); // create the nsIMsgCompose object to send the object nsCOMPtr pMsgCompose( do_CreateInstance("@mozilla.org/messengercompose/compose;1", &rv)); NS_ENSURE_SUCCESS(rv, rv); /** initialize nsIMsgCompose, Send the message, wait for send completion * response **/ rv = pMsgCompose->Initialize(pMsgComposeParams, nullptr, nullptr); NS_ENSURE_SUCCESS(rv, rv); RefPtr promise; rv = pMsgCompose->SendMsg(nsIMsgSend::nsMsgDeliverNow, identity, nullptr, nullptr, nullptr, getter_AddRefs(promise)); if (NS_SUCCEEDED(rv)) { nsCOMPtr origFolder; origMsgHdr->GetFolder(getter_AddRefs(origFolder)); if (origFolder) origFolder->AddMessageDispositionState( origMsgHdr, nsIMsgFolder::nsMsgDispositionState_Forwarded); } return rv; } nsresult CreateCompositionFields( const char* from, const char* reply_to, const char* to, const char* cc, const char* bcc, const char* fcc, const char* newsgroups, const char* followup_to, const char* organization, const char* subject, const char* references, const char* priority, const char* newspost_url, const nsTArray& otherHeaders, char* charset, nsIMsgCompFields** _retval) { NS_ENSURE_ARG_POINTER(_retval); nsresult rv; *_retval = nullptr; nsCOMPtr cFields = do_CreateInstance("@mozilla.org/messengercompose/composefields;1", &rv); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(cFields, NS_ERROR_OUT_OF_MEMORY); nsAutoCString val; nsAutoString outString; if (from) { nsMsgI18NConvertRawBytesToUTF16( nsDependentCString(from), charset ? nsDependentCString(charset) : EmptyCString(), outString); cFields->SetFrom(outString); } if (subject) { MIME_DecodeMimeHeader(subject, charset, false, true, val); cFields->SetSubject( NS_ConvertUTF8toUTF16(!val.IsEmpty() ? val.get() : subject)); } if (reply_to) { nsMsgI18NConvertRawBytesToUTF16( nsDependentCString(reply_to), charset ? nsDependentCString(charset) : EmptyCString(), outString); cFields->SetReplyTo(outString); } if (to) { nsMsgI18NConvertRawBytesToUTF16( nsDependentCString(to), charset ? nsDependentCString(charset) : EmptyCString(), outString); cFields->SetTo(outString); } if (cc) { nsMsgI18NConvertRawBytesToUTF16( nsDependentCString(cc), charset ? nsDependentCString(charset) : EmptyCString(), outString); cFields->SetCc(outString); } if (bcc) { nsMsgI18NConvertRawBytesToUTF16( nsDependentCString(bcc), charset ? nsDependentCString(charset) : EmptyCString(), outString); cFields->SetBcc(outString); } if (fcc) { MIME_DecodeMimeHeader(fcc, charset, false, true, val); cFields->SetFcc(NS_ConvertUTF8toUTF16(!val.IsEmpty() ? val.get() : fcc)); } if (newsgroups) { // fixme: the newsgroups header had better be decoded using the server-side // character encoding,but this |charset| might be different from it. MIME_DecodeMimeHeader(newsgroups, charset, false, true, val); cFields->SetNewsgroups( NS_ConvertUTF8toUTF16(!val.IsEmpty() ? val.get() : newsgroups)); } if (followup_to) { MIME_DecodeMimeHeader(followup_to, charset, false, true, val); cFields->SetFollowupTo( NS_ConvertUTF8toUTF16(!val.IsEmpty() ? val.get() : followup_to)); } if (organization) { MIME_DecodeMimeHeader(organization, charset, false, true, val); cFields->SetOrganization( NS_ConvertUTF8toUTF16(!val.IsEmpty() ? val.get() : organization)); } if (references) { MIME_DecodeMimeHeader(references, charset, false, true, val); cFields->SetReferences(!val.IsEmpty() ? val.get() : references); } if (priority) { MIME_DecodeMimeHeader(priority, charset, false, true, val); nsMsgPriorityValue priorityValue; NS_MsgGetPriorityFromString(!val.IsEmpty() ? val.get() : priority, priorityValue); nsAutoCString priorityName; NS_MsgGetUntranslatedPriorityName(priorityValue, priorityName); cFields->SetPriority(priorityName.get()); } if (newspost_url) { MIME_DecodeMimeHeader(newspost_url, charset, false, true, val); cFields->SetNewspostUrl(!val.IsEmpty() ? val.get() : newspost_url); } nsTArray cFieldsOtherHeaders; cFields->GetOtherHeaders(cFieldsOtherHeaders); for (auto otherHeader : otherHeaders) { if (!otherHeader.IsEmpty()) { MIME_DecodeMimeHeader(NS_ConvertUTF16toUTF8(otherHeader).get(), charset, false, true, val); cFieldsOtherHeaders.AppendElement(NS_ConvertUTF8toUTF16(val)); } else { cFieldsOtherHeaders.AppendElement(u""_ns); } } cFields->SetOtherHeaders(cFieldsOtherHeaders); cFields.forget(_retval); return rv; } static int dummy_file_write(char* buf, int32_t size, void* fileHandle) { if (!fileHandle) return -1; nsIOutputStream* tStream = (nsIOutputStream*)fileHandle; uint32_t bytesWritten; tStream->Write(buf, size, &bytesWritten); return (int)bytesWritten; } static int mime_parse_stream_write(nsMIMESession* stream, const char* buf, int32_t size) { mime_draft_data* mdd = (mime_draft_data*)stream->data_object; NS_ASSERTION(mdd, "null mime draft data!"); if (!mdd || !mdd->obj) return -1; return mdd->obj->clazz->parse_buffer((char*)buf, size, mdd->obj); } static void mime_free_attachments(nsTArray& attachments) { if (attachments.Length() <= 0) return; for (uint32_t i = 0; i < attachments.Length(); i++) { if (attachments[i]->m_tmpFile) { attachments[i]->m_tmpFile->Remove(false); attachments[i]->m_tmpFile = nullptr; } delete attachments[i]; } } static nsMsgAttachmentData* mime_draft_process_attachments( mime_draft_data* mdd) { if (!mdd) return nullptr; nsMsgAttachmentData *attachData = NULL, *tmp = NULL; nsMsgAttachedFile* tmpFile = NULL; // It's possible we must treat the message body as attachment! bool bodyAsAttachment = false; if (mdd->messageBody && !mdd->messageBody->m_type.IsEmpty() && mdd->messageBody->m_type.LowerCaseFindASCII("text/html") == kNotFound && mdd->messageBody->m_type.LowerCaseFindASCII("text/plain") == kNotFound && !mdd->messageBody->m_type.LowerCaseEqualsLiteral("text")) { bodyAsAttachment = true; } if (!mdd->attachments.Length() && !bodyAsAttachment) return nullptr; int32_t totalCount = mdd->attachments.Length(); if (bodyAsAttachment) totalCount++; attachData = new nsMsgAttachmentData[totalCount + 1]; if (!attachData) return nullptr; tmp = attachData; for (int i = 0, attachmentsIndex = 0; i < totalCount; i++, tmp++) { if (bodyAsAttachment && i == 0) tmpFile = mdd->messageBody; else tmpFile = mdd->attachments[attachmentsIndex++]; if (tmpFile->m_type.LowerCaseEqualsLiteral("text/vcard") || tmpFile->m_type.LowerCaseEqualsLiteral("text/x-vcard")) tmp->m_realName = tmpFile->m_description; if (tmpFile->m_origUrl) { nsAutoCString tmpSpec; if (NS_FAILED(tmpFile->m_origUrl->GetSpec(tmpSpec))) goto FAIL; if (NS_FAILED( nsMimeNewURI(getter_AddRefs(tmp->m_url), tmpSpec.get(), nullptr))) goto FAIL; if (tmp->m_realName.IsEmpty()) { if (!tmpFile->m_realName.IsEmpty()) tmp->m_realName = tmpFile->m_realName; else { if (tmpFile->m_type.LowerCaseFindASCII(MESSAGE_RFC822) != kNotFound) // we have the odd case of processing an e-mail that had an unnamed // eml message attached tmp->m_realName = "ForwardedMessage.eml"; else tmp->m_realName = tmpSpec.get(); } } } tmp->m_desiredType = tmpFile->m_type; tmp->m_realType = tmpFile->m_type; tmp->m_realEncoding = tmpFile->m_encoding; tmp->m_description = tmpFile->m_description; tmp->m_cloudPartInfo = tmpFile->m_cloudPartInfo; tmp->m_xMacType = tmpFile->m_xMacType; tmp->m_xMacCreator = tmpFile->m_xMacCreator; tmp->m_size = tmpFile->m_size; } return attachData; FAIL: delete[] attachData; return nullptr; } static void mime_intl_insert_message_header_1( char** body, const char* hdr_value, const char* hdr_str, const char* html_hdr_str, const char* mailcharset, bool htmlEdit) { if (!body || !hdr_value || !hdr_str) return; if (htmlEdit) { NS_MsgSACat(body, HEADER_START_JUNK); } else { NS_MsgSACat(body, MSG_LINEBREAK); } if (!html_hdr_str) html_hdr_str = hdr_str; NS_MsgSACat(body, html_hdr_str); if (htmlEdit) { NS_MsgSACat(body, HEADER_MIDDLE_JUNK); } else NS_MsgSACat(body, ": "); // MIME decode header nsAutoCString utf8Value; MIME_DecodeMimeHeader(hdr_value, mailcharset, false, true, utf8Value); if (!utf8Value.IsEmpty()) { if (htmlEdit) { nsCString escaped; nsAppendEscapedHTML(utf8Value, escaped); NS_MsgSACat(body, escaped.get()); } else { NS_MsgSACat(body, utf8Value.get()); } } else { NS_MsgSACat(body, hdr_value); // raw MIME encoded string } if (htmlEdit) NS_MsgSACat(body, HEADER_END_JUNK); } char* MimeGetNamedString(int32_t id) { static char retString[256]; retString[0] = '\0'; char* tString = MimeGetStringByID(id); if (tString) { PL_strncpy(retString, tString, sizeof(retString)); PR_Free(tString); } return retString; } void MimeGetForwardHeaderDelimiter(nsACString& retString) { nsCString defaultValue; defaultValue.Adopt(MimeGetStringByID(MIME_FORWARDED_MESSAGE_HTML_USER_WROTE)); nsString tmpRetString; NS_GetLocalizedUnicharPreferenceWithDefault( nullptr, "mailnews.forward_header_originalmessage", NS_ConvertUTF8toUTF16(defaultValue), tmpRetString); CopyUTF16toUTF8(tmpRetString, retString); } /* given an address string passed though parameter "address", this one will be converted and returned through the same parameter. The original string will be destroyed */ static void UnquoteMimeAddress(nsACString& mimeHeader, const char* charset) { if (!mimeHeader.IsEmpty()) { nsTArray addresses; ExtractDisplayAddresses(EncodedHeader(mimeHeader, charset), UTF16ArrayAdapter<>(addresses)); mimeHeader.Truncate(); uint32_t count = addresses.Length(); for (uint32_t i = 0; i < count; i++) { if (i != 0) mimeHeader.AppendASCII(", "); mimeHeader += addresses[i]; } } } static void mime_insert_all_headers(char** body, MimeHeaders* headers, MSG_ComposeFormat composeFormat, char* mailcharset) { bool htmlEdit = (composeFormat == nsIMsgCompFormat::HTML); char* newBody = NULL; char* html_tag = nullptr; if (*body && PL_strncasecmp(*body, "') + 1; int i; if (!headers->done_p) { MimeHeaders_build_heads_list(headers); headers->done_p = true; } nsCString replyHeader; MimeGetForwardHeaderDelimiter(replyHeader); if (htmlEdit) { NS_MsgSACopy(&(newBody), MIME_FORWARD_HTML_PREFIX); NS_MsgSACat(&newBody, replyHeader.get()); NS_MsgSACat(&newBody, MIME_HEADER_TABLE); } else { NS_MsgSACopy(&(newBody), MSG_LINEBREAK MSG_LINEBREAK); NS_MsgSACat(&newBody, replyHeader.get()); } for (i = 0; i < headers->heads_size; i++) { char* head = headers->heads[i]; char* end = (i == headers->heads_size - 1 ? headers->all_headers + headers->all_headers_fp : headers->heads[i + 1]); char *colon, *ocolon; char* contents; char* name = 0; // Hack for BSD Mailbox delimiter. if (i == 0 && head[0] == 'F' && !strncmp(head, "From ", 5)) { colon = head + 4; contents = colon + 1; } else { /* Find the colon. */ for (colon = head; colon < end; colon++) if (*colon == ':') break; if (colon >= end) continue; /* junk */ /* Back up over whitespace before the colon. */ ocolon = colon; for (; colon > head && IS_SPACE(colon[-1]); colon--) ; contents = ocolon + 1; } /* Skip over whitespace after colon. */ while (contents <= end && IS_SPACE(*contents)) contents++; /* Take off trailing whitespace... */ while (end > contents && IS_SPACE(end[-1])) end--; name = (char*)PR_MALLOC(colon - head + 1); if (!name) return /* MIME_OUT_OF_MEMORY */; memcpy(name, head, colon - head); name[colon - head] = 0; nsAutoCString headerValue; headerValue.Assign(contents, end - contents); /* Do not reveal bcc recipients when forwarding a message! See http://bugzilla.mozilla.org/show_bug.cgi?id=41150 */ if (PL_strcasecmp(name, "bcc") != 0) { if (!PL_strcasecmp(name, "resent-from") || !PL_strcasecmp(name, "from") || !PL_strcasecmp(name, "resent-to") || !PL_strcasecmp(name, "to") || !PL_strcasecmp(name, "resent-cc") || !PL_strcasecmp(name, "cc") || !PL_strcasecmp(name, "reply-to")) UnquoteMimeAddress(headerValue, mailcharset); mime_intl_insert_message_header_1(&newBody, headerValue.get(), name, name, mailcharset, htmlEdit); } PR_Free(name); } if (htmlEdit) { NS_MsgSACat(&newBody, "
" #define HEADER_MIDDLE_JUNK ": " #define HEADER_END_JUNK "
"); NS_MsgSACat(&newBody, MSG_LINEBREAK "

"); if (html_tag) NS_MsgSACat(&newBody, html_tag); else if (*body) NS_MsgSACat(&newBody, *body); } else { NS_MsgSACat(&newBody, MSG_LINEBREAK MSG_LINEBREAK); if (*body) NS_MsgSACat(&newBody, *body); } if (newBody) { PR_FREEIF(*body); *body = newBody; } } static void mime_insert_normal_headers(char** body, MimeHeaders* headers, MSG_ComposeFormat composeFormat, char* mailcharset) { char* newBody = nullptr; char* subject = MimeHeaders_get(headers, HEADER_SUBJECT, false, false); char* resent_comments = MimeHeaders_get(headers, HEADER_RESENT_COMMENTS, false, false); char* resent_date = MimeHeaders_get(headers, HEADER_RESENT_DATE, false, true); nsCString resent_from( MimeHeaders_get(headers, HEADER_RESENT_FROM, false, true)); nsCString resent_to(MimeHeaders_get(headers, HEADER_RESENT_TO, false, true)); nsCString resent_cc(MimeHeaders_get(headers, HEADER_RESENT_CC, false, true)); char* date = MimeHeaders_get(headers, HEADER_DATE, false, true); nsCString from(MimeHeaders_get(headers, HEADER_FROM, false, true)); nsCString reply_to(MimeHeaders_get(headers, HEADER_REPLY_TO, false, true)); char* organization = MimeHeaders_get(headers, HEADER_ORGANIZATION, false, false); nsCString to(MimeHeaders_get(headers, HEADER_TO, false, true)); nsCString cc(MimeHeaders_get(headers, HEADER_CC, false, true)); char* newsgroups = MimeHeaders_get(headers, HEADER_NEWSGROUPS, false, true); char* followup_to = MimeHeaders_get(headers, HEADER_FOLLOWUP_TO, false, true); char* references = MimeHeaders_get(headers, HEADER_REFERENCES, false, true); const char* html_tag = nullptr; if (*body && PL_strncasecmp(*body, "') + 1; bool htmlEdit = composeFormat == nsIMsgCompFormat::HTML; if (from.IsEmpty()) from.Adopt(MimeHeaders_get(headers, HEADER_SENDER, false, true)); if (resent_from.IsEmpty()) resent_from.Adopt( MimeHeaders_get(headers, HEADER_RESENT_SENDER, false, true)); UnquoteMimeAddress(resent_from, mailcharset); UnquoteMimeAddress(resent_to, mailcharset); UnquoteMimeAddress(resent_cc, mailcharset); UnquoteMimeAddress(reply_to, mailcharset); UnquoteMimeAddress(from, mailcharset); UnquoteMimeAddress(to, mailcharset); UnquoteMimeAddress(cc, mailcharset); nsCString replyHeader; MimeGetForwardHeaderDelimiter(replyHeader); if (htmlEdit) { NS_MsgSACopy(&(newBody), MIME_FORWARD_HTML_PREFIX); NS_MsgSACat(&newBody, replyHeader.get()); NS_MsgSACat(&newBody, MIME_HEADER_TABLE); } else { NS_MsgSACopy(&(newBody), MSG_LINEBREAK MSG_LINEBREAK); NS_MsgSACat(&newBody, replyHeader.get()); } if (subject) mime_intl_insert_message_header_1(&newBody, subject, HEADER_SUBJECT, MimeGetNamedString(MIME_MHTML_SUBJECT), mailcharset, htmlEdit); if (resent_comments) mime_intl_insert_message_header_1( &newBody, resent_comments, HEADER_RESENT_COMMENTS, MimeGetNamedString(MIME_MHTML_RESENT_COMMENTS), mailcharset, htmlEdit); if (resent_date) mime_intl_insert_message_header_1( &newBody, resent_date, HEADER_RESENT_DATE, MimeGetNamedString(MIME_MHTML_RESENT_DATE), mailcharset, htmlEdit); if (!resent_from.IsEmpty()) { mime_intl_insert_message_header_1( &newBody, resent_from.get(), HEADER_RESENT_FROM, MimeGetNamedString(MIME_MHTML_RESENT_FROM), mailcharset, htmlEdit); } if (!resent_to.IsEmpty()) { mime_intl_insert_message_header_1( &newBody, resent_to.get(), HEADER_RESENT_TO, MimeGetNamedString(MIME_MHTML_RESENT_TO), mailcharset, htmlEdit); } if (!resent_cc.IsEmpty()) { mime_intl_insert_message_header_1( &newBody, resent_cc.get(), HEADER_RESENT_CC, MimeGetNamedString(MIME_MHTML_RESENT_CC), mailcharset, htmlEdit); } if (date) mime_intl_insert_message_header_1(&newBody, date, HEADER_DATE, MimeGetNamedString(MIME_MHTML_DATE), mailcharset, htmlEdit); if (!from.IsEmpty()) { mime_intl_insert_message_header_1(&newBody, from.get(), HEADER_FROM, MimeGetNamedString(MIME_MHTML_FROM), mailcharset, htmlEdit); } if (!reply_to.IsEmpty()) { mime_intl_insert_message_header_1(&newBody, reply_to.get(), HEADER_REPLY_TO, MimeGetNamedString(MIME_MHTML_REPLY_TO), mailcharset, htmlEdit); } if (organization) mime_intl_insert_message_header_1( &newBody, organization, HEADER_ORGANIZATION, MimeGetNamedString(MIME_MHTML_ORGANIZATION), mailcharset, htmlEdit); if (!to.IsEmpty()) { mime_intl_insert_message_header_1(&newBody, to.get(), HEADER_TO, MimeGetNamedString(MIME_MHTML_TO), mailcharset, htmlEdit); } if (!cc.IsEmpty()) { mime_intl_insert_message_header_1(&newBody, cc.get(), HEADER_CC, MimeGetNamedString(MIME_MHTML_CC), mailcharset, htmlEdit); } /* Do not reveal bcc recipients when forwarding a message! See http://bugzilla.mozilla.org/show_bug.cgi?id=41150 */ if (newsgroups) mime_intl_insert_message_header_1(&newBody, newsgroups, HEADER_NEWSGROUPS, MimeGetNamedString(MIME_MHTML_NEWSGROUPS), mailcharset, htmlEdit); if (followup_to) { mime_intl_insert_message_header_1( &newBody, followup_to, HEADER_FOLLOWUP_TO, MimeGetNamedString(MIME_MHTML_FOLLOWUP_TO), mailcharset, htmlEdit); } // only show references for newsgroups if (newsgroups && references) { mime_intl_insert_message_header_1(&newBody, references, HEADER_REFERENCES, MimeGetNamedString(MIME_MHTML_REFERENCES), mailcharset, htmlEdit); } if (htmlEdit) { NS_MsgSACat(&newBody, ""); NS_MsgSACat(&newBody, MSG_LINEBREAK "

"); if (html_tag) NS_MsgSACat(&newBody, html_tag); else if (*body) NS_MsgSACat(&newBody, *body); } else { NS_MsgSACat(&newBody, MSG_LINEBREAK MSG_LINEBREAK); if (*body) NS_MsgSACat(&newBody, *body); } if (newBody) { PR_FREEIF(*body); *body = newBody; } PR_FREEIF(subject); PR_FREEIF(resent_comments); PR_FREEIF(resent_date); PR_FREEIF(date); PR_FREEIF(organization); PR_FREEIF(newsgroups); PR_FREEIF(followup_to); PR_FREEIF(references); } static void mime_insert_micro_headers(char** body, MimeHeaders* headers, MSG_ComposeFormat composeFormat, char* mailcharset) { char* newBody = NULL; char* subject = MimeHeaders_get(headers, HEADER_SUBJECT, false, false); nsCString from(MimeHeaders_get(headers, HEADER_FROM, false, true)); nsCString resent_from( MimeHeaders_get(headers, HEADER_RESENT_FROM, false, true)); char* date = MimeHeaders_get(headers, HEADER_DATE, false, true); nsCString to(MimeHeaders_get(headers, HEADER_TO, false, true)); nsCString cc(MimeHeaders_get(headers, HEADER_CC, false, true)); char* newsgroups = MimeHeaders_get(headers, HEADER_NEWSGROUPS, false, true); const char* html_tag = nullptr; if (*body && PL_strncasecmp(*body, "') + 1; bool htmlEdit = composeFormat == nsIMsgCompFormat::HTML; if (from.IsEmpty()) from.Adopt(MimeHeaders_get(headers, HEADER_SENDER, false, true)); if (resent_from.IsEmpty()) resent_from.Adopt( MimeHeaders_get(headers, HEADER_RESENT_SENDER, false, true)); if (!date) date = MimeHeaders_get(headers, HEADER_RESENT_DATE, false, true); UnquoteMimeAddress(resent_from, mailcharset); UnquoteMimeAddress(from, mailcharset); UnquoteMimeAddress(to, mailcharset); UnquoteMimeAddress(cc, mailcharset); nsCString replyHeader; MimeGetForwardHeaderDelimiter(replyHeader); if (htmlEdit) { NS_MsgSACopy(&(newBody), MIME_FORWARD_HTML_PREFIX); NS_MsgSACat(&newBody, replyHeader.get()); NS_MsgSACat(&newBody, MIME_HEADER_TABLE); } else { NS_MsgSACopy(&(newBody), MSG_LINEBREAK MSG_LINEBREAK); NS_MsgSACat(&newBody, replyHeader.get()); } if (!from.IsEmpty()) { mime_intl_insert_message_header_1(&newBody, from.get(), HEADER_FROM, MimeGetNamedString(MIME_MHTML_FROM), mailcharset, htmlEdit); } if (subject) mime_intl_insert_message_header_1(&newBody, subject, HEADER_SUBJECT, MimeGetNamedString(MIME_MHTML_SUBJECT), mailcharset, htmlEdit); /* if (date) mime_intl_insert_message_header_1(&newBody, date, HEADER_DATE, MimeGetNamedString(MIME_MHTML_DATE), mailcharset, htmlEdit); */ if (!resent_from.IsEmpty()) { mime_intl_insert_message_header_1( &newBody, resent_from.get(), HEADER_RESENT_FROM, MimeGetNamedString(MIME_MHTML_RESENT_FROM), mailcharset, htmlEdit); } if (!to.IsEmpty()) { mime_intl_insert_message_header_1(&newBody, to.get(), HEADER_TO, MimeGetNamedString(MIME_MHTML_TO), mailcharset, htmlEdit); } if (!cc.IsEmpty()) { mime_intl_insert_message_header_1(&newBody, cc.get(), HEADER_CC, MimeGetNamedString(MIME_MHTML_CC), mailcharset, htmlEdit); } /* Do not reveal bcc recipients when forwarding a message! See http://bugzilla.mozilla.org/show_bug.cgi?id=41150 */ if (newsgroups) mime_intl_insert_message_header_1(&newBody, newsgroups, HEADER_NEWSGROUPS, MimeGetNamedString(MIME_MHTML_NEWSGROUPS), mailcharset, htmlEdit); if (htmlEdit) { NS_MsgSACat(&newBody, ""); NS_MsgSACat(&newBody, MSG_LINEBREAK "

"); if (html_tag) NS_MsgSACat(&newBody, html_tag); else if (*body) NS_MsgSACat(&newBody, *body); } else { NS_MsgSACat(&newBody, MSG_LINEBREAK MSG_LINEBREAK); if (*body) NS_MsgSACat(&newBody, *body); } if (newBody) { PR_FREEIF(*body); *body = newBody; } PR_FREEIF(subject); PR_FREEIF(date); PR_FREEIF(newsgroups); } // body has to be encoded in UTF-8 static void mime_insert_forwarded_message_headers( char** body, MimeHeaders* headers, MSG_ComposeFormat composeFormat, char* mailcharset) { if (!body || !headers) return; int32_t show_headers = 0; nsresult res; nsCOMPtr prefBranch( do_GetService(NS_PREFSERVICE_CONTRACTID, &res)); if (NS_SUCCEEDED(res)) prefBranch->GetIntPref("mail.show_headers", &show_headers); switch (show_headers) { case 0: mime_insert_micro_headers(body, headers, composeFormat, mailcharset); break; default: case 1: mime_insert_normal_headers(body, headers, composeFormat, mailcharset); break; case 2: mime_insert_all_headers(body, headers, composeFormat, mailcharset); break; } } static void convert_plaintext_body_to_html(char** body) { // We need to convert the plain/text to HTML in order to escape any HTML // markup. nsCString escapedBody; nsAppendEscapedHTML(nsDependentCString(*body), escapedBody); nsCString newBody; char* q = escapedBody.BeginWriting(); char* p; int prevQuoteLevel = 0; bool isFlowed = false; bool haveSig = false; // First detect whether this appears to be flowed or not. p = q; while (*p) { // At worst we read the null byte terminator. if (*p == ' ' && (*(p + 1) == '\r' || *(p + 1) == '\n')) { // This looks flowed, but don't get fooled by a signature separator: // --space if (p - 3 >= q && (*(p - 3) == '\r' || *(p - 3) == '\n') && *(p - 2) == '-' && *(p - 1) == '-') { p++; continue; } if (p - 2 == q && *(p - 2) == '-' && *(p - 1) == '-') { p++; continue; } isFlowed = true; break; } p++; } while (*q) { p = q; // Detect quotes. A quote character is a ">" which was escaped to >. // In non-flowed messages the quote character can be optionally followed by // a space. Examples: Level 0 // > Level 0 (with leading space) // > Level 1 // > > Level 1 (with leading space, note the two spaces between the quote // characters) // >> Level 2 // > > Level 2 (only when non-flowed, otherwise Level 1 with leading space) // >>> Level 3 // > > > Level 3 (with leading space, only when non-flowed, otherwise Level // 1) int quoteLevel = 0; while (strncmp(p, ">", 4) == 0) { p += 4; if (!isFlowed && *p == ' ') p++; quoteLevel++; } // Eat space following quote character, for non-flowed already eaten above. if (quoteLevel > 0 && isFlowed && *p == ' ') p++; // Close any open signatures if we find a quote. Strange, that shouldn't // happen. if (quoteLevel > 0 && haveSig) { newBody.AppendLiteral(""); haveSig = false; } if (quoteLevel > prevQuoteLevel) { while (prevQuoteLevel < quoteLevel) { if (isFlowed) newBody.AppendLiteral("
"); else newBody.AppendLiteral( "
");
        prevQuoteLevel++;
      }
    } else if (quoteLevel < prevQuoteLevel) {
      while (prevQuoteLevel > quoteLevel) {
        if (isFlowed)
          newBody.AppendLiteral("
"); else newBody.AppendLiteral("
"); prevQuoteLevel--; } } // Position after the quote. q = p; // Detect signature. bool forceBR = false; if (quoteLevel == 0) { if (strncmp(q, "-- \r", 4) == 0 || strncmp(q, "-- \n", 4) == 0) { haveSig = true; forceBR = true; newBody.AppendLiteral("
");
      }
    }

    bool seenSpace = false;
    while (*p && *p != '\r' && *p != '\n') {
      seenSpace = (*p == ' ');
      p++;
      continue;
    }
    if (!*p) {
      // We're at the end of the string.
      if (p > q) {
        // Copy last bit over.
        newBody.Append(q);
      }
      break;
    }
    if (*p == '\r' &&
        *(p + 1) == '\n') {  // At worst we read the null byte terminator.
      // Skip the CR in CRLF.
      *p = 0;  // don't copy skipped \r.
      p++;
    }
    *p = 0;
    newBody.Append(q);
    if (!isFlowed || !seenSpace || forceBR) newBody.AppendLiteral("
"); q = p + 1; } // Close all open quotes. while (prevQuoteLevel > 0) { if (isFlowed) newBody.AppendLiteral(""); else newBody.AppendLiteral("
"); prevQuoteLevel--; } // Close any open signatures. if (haveSig) { newBody.AppendLiteral(""); haveSig = false; } PR_Free(*body); *body = ToNewCString(newBody); } static void mime_parse_stream_complete(nsMIMESession* stream) { mime_draft_data* mdd = (mime_draft_data*)stream->data_object; nsCOMPtr fields; int htmlAction = 0; int lineWidth = 0; char* host = 0; char* news_host = 0; char* to_and_cc = 0; char* re_subject = 0; char* new_refs = 0; char* from = 0; char* repl = 0; char* subj = 0; char* id = 0; char* refs = 0; char* to = 0; char* cc = 0; char* bcc = 0; char* fcc = 0; char* org = 0; char* grps = 0; char* foll = 0; char* priority = 0; char* draftInfo = 0; char* contentLanguage = 0; char* identityKey = 0; nsTArray readOtherHeaders; bool forward_inline = false; bool bodyAsAttachment = false; bool charsetOverride = false; NS_ASSERTION(mdd, "null mime draft data"); if (!mdd) return; if (mdd->obj) { int status; status = mdd->obj->clazz->parse_eof(mdd->obj, false); mdd->obj->clazz->parse_end(mdd->obj, status < 0 ? true : false); // RICHIE // We need to figure out how to pass the forwarded flag along with this // operation. // forward_inline = (mdd->format_out != FO_CMDLINE_ATTACHMENTS); forward_inline = mdd->forwardInline; NS_ASSERTION(mdd->options == mdd->obj->options, "mime draft options not same as obj->options"); mime_free(mdd->obj); mdd->obj = 0; if (mdd->options) { // save the override flag before it's unavailable charsetOverride = mdd->options->override_charset; // Override the charset only if requested. If the message doesn't have // one and we're not overriding, we'll detect it later. if (charsetOverride && mdd->options->default_charset) { PR_FREEIF(mdd->mailcharset); mdd->mailcharset = strdup(mdd->options->default_charset); } // mscott: aren't we leaking a bunch of strings here like the charset // strings and such? delete mdd->options; mdd->options = 0; } if (mdd->stream) { mdd->stream->complete((nsMIMESession*)mdd->stream->data_object); PR_Free(mdd->stream); mdd->stream = 0; } } // // Now, process the attachments that we have gathered from the message // on disk // nsMsgAttachmentData* newAttachData = mime_draft_process_attachments(mdd); // // time to bring up the compose windows with all the info gathered // if (mdd->headers) { subj = MimeHeaders_get(mdd->headers, HEADER_SUBJECT, false, false); if (forward_inline) { if (subj) { nsresult rv; nsCOMPtr prefBranch( do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv)) { nsAutoCString fwdPrefix; prefBranch->GetCharPref("mail.forward_subject_prefix", fwdPrefix); char* newSubj = PR_smprintf( "%s: %s", !fwdPrefix.IsEmpty() ? fwdPrefix.get() : "Fwd", subj); if (newSubj) { PR_Free(subj); subj = newSubj; } } } } else { from = MimeHeaders_get(mdd->headers, HEADER_FROM, false, false); repl = MimeHeaders_get(mdd->headers, HEADER_REPLY_TO, false, false); to = MimeHeaders_get(mdd->headers, HEADER_TO, false, true); cc = MimeHeaders_get(mdd->headers, HEADER_CC, false, true); bcc = MimeHeaders_get(mdd->headers, HEADER_BCC, false, true); /* These headers should not be RFC-1522-decoded. */ grps = MimeHeaders_get(mdd->headers, HEADER_NEWSGROUPS, false, true); foll = MimeHeaders_get(mdd->headers, HEADER_FOLLOWUP_TO, false, true); host = MimeHeaders_get(mdd->headers, HEADER_X_MOZILLA_NEWSHOST, false, false); if (!host) host = MimeHeaders_get(mdd->headers, HEADER_NNTP_POSTING_HOST, false, false); id = MimeHeaders_get(mdd->headers, HEADER_MESSAGE_ID, false, false); refs = MimeHeaders_get(mdd->headers, HEADER_REFERENCES, false, true); priority = MimeHeaders_get(mdd->headers, HEADER_X_PRIORITY, false, false); if (host) { char* secure = NULL; secure = PL_strcasestr(host, "secure"); if (secure) { *secure = 0; news_host = PR_smprintf("snews://%s", host); } else { news_host = PR_smprintf("news://%s", host); } } // Other headers via pref. nsCString otherHeaders; nsTArray otherHeadersArray; nsresult rv; nsCOMPtr pPrefBranch( do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); pPrefBranch->GetCharPref("mail.compose.other.header", otherHeaders); if (!otherHeaders.IsEmpty()) { ToLowerCase(otherHeaders); ParseString(otherHeaders, ',', otherHeadersArray); for (auto otherHeader : otherHeadersArray) { otherHeader.Trim(" "); nsAutoCString result; result.Assign( MimeHeaders_get(mdd->headers, otherHeader.get(), false, false)); readOtherHeaders.AppendElement(NS_ConvertUTF8toUTF16(result)); } } } CreateCompositionFields(from, repl, to, cc, bcc, fcc, grps, foll, org, subj, refs, priority, news_host, readOtherHeaders, mdd->mailcharset, getter_AddRefs(fields)); contentLanguage = MimeHeaders_get(mdd->headers, HEADER_CONTENT_LANGUAGE, false, false); if (contentLanguage) { fields->SetContentLanguage(contentLanguage); } draftInfo = MimeHeaders_get(mdd->headers, HEADER_X_MOZILLA_DRAFT_INFO, false, false); // We always preserve an existing message ID, if present, apart from some // exceptions. bool keepID = fields != nullptr; // Don't keep ID when forwarding inline. if (forward_inline) keepID = false; // nsMimeOutput::nsMimeMessageEditorTemplate is used for editing a message // "as new", creating a message from a template or editing a template. // Only in the latter case we want to preserve the ID. if (mdd->format_out == nsMimeOutput::nsMimeMessageEditorTemplate && !PL_strstr(mdd->url_name, "&edittempl=true")) keepID = false; if (keepID) fields->SetMessageId(id); if (draftInfo && fields && !forward_inline) { char* parm = 0; parm = MimeHeaders_get_parameter(draftInfo, "vcard", NULL, NULL); fields->SetAttachVCard(parm && !strcmp(parm, "1")); PR_FREEIF(parm); parm = MimeHeaders_get_parameter(draftInfo, "receipt", NULL, NULL); if (!parm || !strcmp(parm, "0")) fields->SetReturnReceipt(false); else { int receiptType = 0; fields->SetReturnReceipt(true); sscanf(parm, "%d", &receiptType); // slight change compared to 4.x; we used to use receipt= to tell // whether the draft/template has request for either MDN or DNS or both // return receipt; since the DNS is out of the picture we now use the // header type - 1 to tell whether user has requested the return receipt fields->SetReceiptHeaderType(((int32_t)receiptType) - 1); } PR_FREEIF(parm); parm = MimeHeaders_get_parameter(draftInfo, "DSN", NULL, NULL); fields->SetDSN(parm && !strcmp(parm, "1")); PR_Free(parm); parm = MimeHeaders_get_parameter(draftInfo, "html", NULL, NULL); if (parm) sscanf(parm, "%d", &htmlAction); PR_FREEIF(parm); parm = MimeHeaders_get_parameter(draftInfo, "linewidth", NULL, NULL); if (parm) sscanf(parm, "%d", &lineWidth); PR_FREEIF(parm); parm = MimeHeaders_get_parameter(draftInfo, "attachmentreminder", NULL, NULL); if (parm && !strcmp(parm, "1")) fields->SetAttachmentReminder(true); else fields->SetAttachmentReminder(false); PR_FREEIF(parm); parm = MimeHeaders_get_parameter(draftInfo, "deliveryformat", NULL, NULL); if (parm) { int32_t deliveryFormat = nsIMsgCompSendFormat::Unset; sscanf(parm, "%d", &deliveryFormat); fields->SetDeliveryFormat(deliveryFormat); } PR_FREEIF(parm); } // identity to prefer when opening the message in the compose window? identityKey = MimeHeaders_get(mdd->headers, HEADER_X_MOZILLA_IDENTITY_KEY, false, false); if (identityKey && *identityKey) { nsresult rv = NS_OK; nsCOMPtr accountManager = do_GetService("@mozilla.org/messenger/account-manager;1", &rv); if (NS_SUCCEEDED(rv) && accountManager) { nsCOMPtr overrulingIdentity; rv = accountManager->GetIdentity(nsDependentCString(identityKey), getter_AddRefs(overrulingIdentity)); if (NS_SUCCEEDED(rv) && overrulingIdentity) { mdd->identity = overrulingIdentity; fields->SetCreatorIdentityKey(identityKey); } } } if (mdd->messageBody) { MSG_ComposeFormat composeFormat = nsIMsgCompFormat::Default; if (!mdd->messageBody->m_type.IsEmpty()) { if (mdd->messageBody->m_type.LowerCaseFindASCII("text/html") != kNotFound) composeFormat = nsIMsgCompFormat::HTML; else if (mdd->messageBody->m_type.LowerCaseFindASCII("text/plain") != kNotFound || mdd->messageBody->m_type.LowerCaseEqualsLiteral("text")) composeFormat = nsIMsgCompFormat::PlainText; else // We cannot use this kind of data for the message body! Therefore, // move it as attachment bodyAsAttachment = true; } else composeFormat = nsIMsgCompFormat::PlainText; char* body = nullptr; if (!bodyAsAttachment && mdd->messageBody->m_tmpFile) { int64_t fileSize; nsCOMPtr tempFileCopy; mdd->messageBody->m_tmpFile->Clone(getter_AddRefs(tempFileCopy)); mdd->messageBody->m_tmpFile = tempFileCopy; tempFileCopy = nullptr; mdd->messageBody->m_tmpFile->GetFileSize(&fileSize); uint32_t bodyLen = 0; // The stream interface can only read up to 4GB (32bit uint). // It is highly unlikely to encounter a body lager than that limit, // so we just skip it instead of reading it in chunks. if (fileSize < UINT32_MAX) { bodyLen = fileSize; body = (char*)PR_MALLOC(bodyLen + 1); } if (body) { memset(body, 0, bodyLen + 1); uint32_t bytesRead; nsCOMPtr inputStream; nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), mdd->messageBody->m_tmpFile); if (NS_FAILED(rv)) return; inputStream->Read(body, bodyLen, &bytesRead); inputStream->Close(); // Convert the body to UTF-8 char* mimeCharset = nullptr; // Get a charset from the header if no override is set. if (!charsetOverride) mimeCharset = MimeHeaders_get_parameter( mdd->messageBody->m_type.get(), "charset", nullptr, nullptr); // If no charset is specified in the header then use the default. nsAutoCString bodyCharset; if (mimeCharset) { bodyCharset.Adopt(mimeCharset); } else if (mdd->mailcharset) { bodyCharset.Assign(mdd->mailcharset); } if (bodyCharset.IsEmpty()) { nsAutoCString detectedCharset; // We need to detect it. rv = MIME_detect_charset(body, bodyLen, detectedCharset); if (NS_SUCCEEDED(rv) && !detectedCharset.IsEmpty()) { bodyCharset = detectedCharset; } } if (!bodyCharset.IsEmpty()) { nsAutoString tmpUnicodeBody; rv = nsMsgI18NConvertToUnicode( bodyCharset, nsDependentCString(body), tmpUnicodeBody); if (NS_FAILED(rv)) // Tough luck, ASCII/ISO-8859-1 then... CopyASCIItoUTF16(nsDependentCString(body), tmpUnicodeBody); char* newBody = ToNewUTF8String(tmpUnicodeBody); if (newBody) { PR_Free(body); body = newBody; } } } } bool convertToPlainText = false; if (forward_inline) { if (mdd->identity) { bool identityComposeHTML; mdd->identity->GetComposeHtml(&identityComposeHTML); if ((identityComposeHTML && !mdd->overrideComposeFormat) || (!identityComposeHTML && mdd->overrideComposeFormat)) { // In the end, we're going to compose in HTML mode... if (body && composeFormat == nsIMsgCompFormat::PlainText) { // ... but the message body is currently plain text. convert_plaintext_body_to_html(&body); } // Body is now HTML, set the format too (so headers are inserted in // correct format). composeFormat = nsIMsgCompFormat::HTML; } else if ((identityComposeHTML && mdd->overrideComposeFormat) || !identityComposeHTML) { // In the end, we're going to compose in plain text mode... if (composeFormat == nsIMsgCompFormat::HTML) { // ... but the message body is currently HTML. // We'll do the conversion later on when headers have been // inserted, body has been set and converted to unicode. convertToPlainText = true; } } } mime_insert_forwarded_message_headers(&body, mdd->headers, composeFormat, mdd->mailcharset); } MSG_ComposeType msgComposeType = 0; // Keep compilers happy. if (mdd->format_out == nsMimeOutput::nsMimeMessageEditorTemplate) { if (PL_strstr(mdd->url_name, "?redirect=true") || PL_strstr(mdd->url_name, "&redirect=true")) msgComposeType = nsIMsgCompType::Redirect; else if (PL_strstr(mdd->url_name, "?editasnew=true") || PL_strstr(mdd->url_name, "&editasnew=true")) msgComposeType = nsIMsgCompType::EditAsNew; else if (PL_strstr(mdd->url_name, "?edittempl=true") || PL_strstr(mdd->url_name, "&edittempl=true")) msgComposeType = nsIMsgCompType::EditTemplate; else msgComposeType = nsIMsgCompType::Template; } if (body && msgComposeType == nsIMsgCompType::EditAsNew) { // When editing as new, we respect the identities preferred format // which can be overridden. if (mdd->identity) { bool identityComposeHTML; mdd->identity->GetComposeHtml(&identityComposeHTML); if (composeFormat == nsIMsgCompFormat::HTML && identityComposeHTML == mdd->overrideComposeFormat) { // We we have HTML: // If they want HTML and they want to override it (true == true) // or they don't want HTML and they don't want to override it // (false == false), then convert. Conversion happens below. convertToPlainText = true; composeFormat = nsIMsgCompFormat::PlainText; } else if (composeFormat == nsIMsgCompFormat::PlainText && identityComposeHTML != mdd->overrideComposeFormat) { // We have plain text: // If they want HTML and they don't want to override it (true != // false) or they don't want HTML and they want to override it // (false != true), then convert. convert_plaintext_body_to_html(&body); composeFormat = nsIMsgCompFormat::HTML; } } } else if (body && mdd->overrideComposeFormat && (msgComposeType == nsIMsgCompType::Template || msgComposeType == nsIMsgCompType::EditTemplate || !mdd->forwardInline)) // Draft processing. { // When using a template and overriding, the user gets the // "other" format. if (composeFormat == nsIMsgCompFormat::PlainText) { convert_plaintext_body_to_html(&body); composeFormat = nsIMsgCompFormat::HTML; } else { // Conversion happens below. convertToPlainText = true; composeFormat = nsIMsgCompFormat::PlainText; } } // convert from UTF-8 to UTF-16 if (body) { fields->SetBody(NS_ConvertUTF8toUTF16(body)); PR_Free(body); } // // At this point, we need to create a message compose window or editor // window via XP-COM with the information that we have retrieved from // the message store. // if (mdd->format_out == nsMimeOutput::nsMimeMessageEditorTemplate) { // Set the draft ID when editing a template so the original is // overwritten when saving the template again. // Note that always setting the draft ID here would cause drafts to be // overwritten when edited "as new", which is undesired. if (msgComposeType == nsIMsgCompType::EditTemplate) { fields->SetDraftId(nsDependentCString(mdd->url_name)); fields->SetTemplateId(nsDependentCString( mdd->url_name)); // Remember original template ID. } if (convertToPlainText) fields->ConvertBodyToPlainText(); CreateTheComposeWindow(fields, newAttachData, msgComposeType, composeFormat, mdd->identity, mdd->originalMsgURI, mdd->origMsgHdr); } else { if (mdd->forwardInline) { if (convertToPlainText) fields->ConvertBodyToPlainText(); if (mdd->overrideComposeFormat) composeFormat = nsIMsgCompFormat::OppositeOfDefault; if (mdd->forwardInlineFilter) { fields->SetTo(mdd->forwardToAddress); ForwardMsgInline(fields, newAttachData, composeFormat, mdd->identity, mdd->originalMsgURI, mdd->origMsgHdr); } else CreateTheComposeWindow(fields, newAttachData, nsIMsgCompType::ForwardInline, composeFormat, mdd->identity, mdd->originalMsgURI, mdd->origMsgHdr); } else { if (convertToPlainText) fields->ConvertBodyToPlainText(); fields->SetDraftId(nsDependentCString(mdd->url_name)); CreateTheComposeWindow(fields, newAttachData, nsIMsgCompType::Draft, composeFormat, mdd->identity, mdd->originalMsgURI, mdd->origMsgHdr); } } } else { // // At this point, we need to create a message compose window via // XP-COM with the information that we have retrieved from the message // store. // if (mdd->format_out == nsMimeOutput::nsMimeMessageEditorTemplate) { #ifdef NS_DEBUG printf( "RICHIE: Time to create the EDITOR with this template - NO " "body!!!!\n"); #endif CreateTheComposeWindow(fields, newAttachData, nsIMsgCompType::Template, nsIMsgCompFormat::Default, mdd->identity, EmptyCString(), mdd->origMsgHdr); } else { #ifdef NS_DEBUG printf("Time to create the composition window WITHOUT a body!!!!\n"); #endif if (mdd->forwardInline) { MSG_ComposeFormat composeFormat = (mdd->overrideComposeFormat) ? nsIMsgCompFormat::OppositeOfDefault : nsIMsgCompFormat::Default; CreateTheComposeWindow(fields, newAttachData, nsIMsgCompType::ForwardInline, composeFormat, mdd->identity, mdd->originalMsgURI, mdd->origMsgHdr); } else { fields->SetDraftId(nsDependentCString(mdd->url_name)); CreateTheComposeWindow(fields, newAttachData, nsIMsgCompType::Draft, nsIMsgCompFormat::Default, mdd->identity, EmptyCString(), mdd->origMsgHdr); } } } } else { CreateCompositionFields(from, repl, to, cc, bcc, fcc, grps, foll, org, subj, refs, priority, news_host, readOtherHeaders, mdd->mailcharset, getter_AddRefs(fields)); if (fields) CreateTheComposeWindow(fields, newAttachData, nsIMsgCompType::New, nsIMsgCompFormat::Default, mdd->identity, EmptyCString(), mdd->origMsgHdr); } if (mdd->headers) MimeHeaders_free(mdd->headers); // // Free the original attachment structure... // Make sure we only cleanup the local copy of the memory and not kill // files we need on disk // if (bodyAsAttachment) mdd->messageBody->m_tmpFile = nullptr; else if (mdd->messageBody && mdd->messageBody->m_tmpFile) mdd->messageBody->m_tmpFile->Remove(false); delete mdd->messageBody; for (uint32_t i = 0; i < mdd->attachments.Length(); i++) mdd->attachments[i]->m_tmpFile = nullptr; PR_FREEIF(mdd->mailcharset); mdd->identity = nullptr; PR_Free(mdd->url_name); mdd->origMsgHdr = nullptr; PR_Free(mdd); PR_FREEIF(host); PR_FREEIF(to_and_cc); PR_FREEIF(re_subject); PR_FREEIF(new_refs); PR_FREEIF(from); PR_FREEIF(repl); PR_FREEIF(subj); PR_FREEIF(id); PR_FREEIF(refs); PR_FREEIF(to); PR_FREEIF(cc); PR_FREEIF(grps); PR_FREEIF(foll); PR_FREEIF(priority); PR_FREEIF(draftInfo); PR_Free(identityKey); delete[] newAttachData; } static void mime_parse_stream_abort(nsMIMESession* stream, int status) { mime_draft_data* mdd = (mime_draft_data*)stream->data_object; NS_ASSERTION(mdd, "null mime draft data"); if (!mdd) return; if (mdd->obj) { int status = 0; if (!mdd->obj->closed_p) status = mdd->obj->clazz->parse_eof(mdd->obj, true); if (!mdd->obj->parsed_p) mdd->obj->clazz->parse_end(mdd->obj, true); NS_ASSERTION(mdd->options == mdd->obj->options, "draft display options not same as mime obj"); mime_free(mdd->obj); mdd->obj = 0; if (mdd->options) { delete mdd->options; mdd->options = 0; } if (mdd->stream) { mdd->stream->abort((nsMIMESession*)mdd->stream->data_object, status); PR_Free(mdd->stream); mdd->stream = 0; } } if (mdd->headers) MimeHeaders_free(mdd->headers); mime_free_attachments(mdd->attachments); PR_FREEIF(mdd->mailcharset); PR_Free(mdd); } static int make_mime_headers_copy(void* closure, MimeHeaders* headers) { mime_draft_data* mdd = (mime_draft_data*)closure; NS_ASSERTION(mdd && headers, "null mime draft data and/or headers"); if (!mdd || !headers) return 0; NS_ASSERTION(mdd->headers == NULL, "non null mime draft data headers"); mdd->headers = MimeHeaders_copy(headers); mdd->options->done_parsing_outer_headers = true; return 0; } int mime_decompose_file_init_fn(void* stream_closure, MimeHeaders* headers) { mime_draft_data* mdd = (mime_draft_data*)stream_closure; nsMsgAttachedFile* newAttachment = 0; int nAttachments = 0; // char *hdr_value = NULL; char* parm_value = NULL; bool creatingMsgBody = true; NS_ASSERTION(mdd && headers, "null mime draft data and/or headers"); if (!mdd || !headers) return -1; if (mdd->options->decompose_init_count) { mdd->options->decompose_init_count++; NS_ASSERTION(mdd->curAttachment, "missing attachment in mime_decompose_file_init_fn"); if (mdd->curAttachment) mdd->curAttachment->m_type.Adopt( MimeHeaders_get(headers, HEADER_CONTENT_TYPE, false, true)); return 0; } else mdd->options->decompose_init_count++; nAttachments = mdd->attachments.Length(); if (!nAttachments && !mdd->messageBody) { // if we've been told to use an override charset then do so....otherwise use // the charset inside the message header... if (mdd->options && mdd->options->override_charset) { if (mdd->options->default_charset) mdd->mailcharset = strdup(mdd->options->default_charset); else { mdd->mailcharset = strdup(""); mdd->autodetectCharset = true; } } else { char* contentType; contentType = MimeHeaders_get(headers, HEADER_CONTENT_TYPE, false, false); if (contentType) { mdd->mailcharset = MimeHeaders_get_parameter(contentType, "charset", NULL, NULL); PR_FREEIF(contentType); } } mdd->messageBody = new nsMsgAttachedFile; if (!mdd->messageBody) return MIME_OUT_OF_MEMORY; newAttachment = mdd->messageBody; creatingMsgBody = true; } else { /* always allocate one more extra; don't ask me why */ newAttachment = new nsMsgAttachedFile; if (!newAttachment) return MIME_OUT_OF_MEMORY; mdd->attachments.AppendElement(newAttachment); } char* workURLSpec = nullptr; char* contLoc = nullptr; newAttachment->m_realName.Adopt(MimeHeaders_get_name(headers, mdd->options)); contLoc = MimeHeaders_get(headers, HEADER_CONTENT_LOCATION, false, false); if (!contLoc) contLoc = MimeHeaders_get(headers, HEADER_CONTENT_BASE, false, false); if (!contLoc && !newAttachment->m_realName.IsEmpty()) workURLSpec = ToNewCString(newAttachment->m_realName); if (contLoc && !workURLSpec) workURLSpec = strdup(contLoc); PR_FREEIF(contLoc); mdd->curAttachment = newAttachment; newAttachment->m_type.Adopt( MimeHeaders_get(headers, HEADER_CONTENT_TYPE, false, false)); // // This is to handle the degenerated Apple Double attachment. // parm_value = MimeHeaders_get(headers, HEADER_CONTENT_TYPE, false, false); if (parm_value) { char* boundary = NULL; char* tmp_value = NULL; boundary = MimeHeaders_get_parameter(parm_value, "boundary", NULL, NULL); if (boundary) tmp_value = PR_smprintf("; boundary=\"%s\"", boundary); if (tmp_value) newAttachment->m_type = tmp_value; newAttachment->m_xMacType.Adopt( MimeHeaders_get_parameter(parm_value, "x-mac-type", NULL, NULL)); newAttachment->m_xMacCreator.Adopt( MimeHeaders_get_parameter(parm_value, "x-mac-creator", NULL, NULL)); PR_FREEIF(parm_value); PR_FREEIF(boundary); PR_FREEIF(tmp_value); } newAttachment->m_size = 0; newAttachment->m_encoding.Adopt( MimeHeaders_get(headers, HEADER_CONTENT_TRANSFER_ENCODING, false, false)); newAttachment->m_description.Adopt( MimeHeaders_get(headers, HEADER_CONTENT_DESCRIPTION, false, false)); // // If we came up empty for description or the orig URL, we should do something // about it. // if (newAttachment->m_description.IsEmpty() && workURLSpec) newAttachment->m_description = workURLSpec; PR_FREEIF(workURLSpec); // resource leak otherwise newAttachment->m_cloudPartInfo.Adopt( MimeHeaders_get(headers, HEADER_X_MOZILLA_CLOUD_PART, false, false)); nsCOMPtr tmpFile = nullptr; { // Let's build a temp file with an extension based on the content-type: // nsmail. nsAutoCString newAttachName("nsmail"); nsAutoCString fileExtension; // the content type may contain a charset. i.e. text/html; ISO-2022-JP...we // want to strip off the charset before we ask the mime service for a mime // info for this content type. nsAutoCString contentType(newAttachment->m_type); int32_t pos = contentType.FindChar(';'); if (pos > 0) contentType.SetLength(pos); int32_t extLoc = newAttachment->m_realName.RFindChar('.'); int32_t specLength = newAttachment->m_realName.Length(); // @see nsExternalHelperAppService::GetTypeFromURI() if (extLoc != -1 && extLoc != specLength - 1 && // nothing over 20 chars long can be sanely considered an // extension.... Dat dere would be just data. specLength - extLoc < 20) { fileExtension = Substring(newAttachment->m_realName, extLoc + 1); } else { nsCOMPtr mimeFinder( do_GetService(NS_MIMESERVICE_CONTRACTID)); if (mimeFinder) { mimeFinder->GetPrimaryExtension(contentType, ""_ns, fileExtension); } } if (fileExtension.IsEmpty()) { newAttachName.AppendLiteral(".tmp"); } else { newAttachName.Append('.'); newAttachName.Append(fileExtension); } nsMsgCreateTempFile(newAttachName.get(), getter_AddRefs(tmpFile)); } nsresult rv; // This needs to be done so the attachment structure has a handle // on the temp file for this attachment... if (tmpFile) { nsAutoCString fileURL; rv = NS_GetURLSpecFromFile(tmpFile, fileURL); if (NS_SUCCEEDED(rv)) nsMimeNewURI(getter_AddRefs(newAttachment->m_origUrl), fileURL.get(), nullptr); } if (!tmpFile) return MIME_OUT_OF_MEMORY; mdd->tmpFile = tmpFile; newAttachment->m_tmpFile = mdd->tmpFile; rv = MsgNewBufferedFileOutputStream(getter_AddRefs(mdd->tmpFileStream), tmpFile, PR_WRONLY | PR_CREATE_FILE, 00600); if (NS_FAILED(rv)) return MIME_UNABLE_TO_OPEN_TMP_FILE; // For now, we are always going to decode all of the attachments // for the message. This way, we have native data if (creatingMsgBody) { MimeDecoderData* (*fn)(MimeConverterOutputCallback, void*) = 0; // // Initialize a decoder if necessary. // if (newAttachment->m_encoding.LowerCaseEqualsLiteral(ENCODING_BASE64)) fn = &MimeB64DecoderInit; else if (newAttachment->m_encoding.LowerCaseEqualsLiteral( ENCODING_QUOTED_PRINTABLE)) { mdd->decoder_data = MimeQPDecoderInit(/* The (MimeConverterOutputCallback) cast is to turn the `void' argument into `MimeObject'. */ ((MimeConverterOutputCallback)dummy_file_write), mdd->tmpFileStream); if (!mdd->decoder_data) return MIME_OUT_OF_MEMORY; } else if (newAttachment->m_encoding.LowerCaseEqualsLiteral( ENCODING_UUENCODE) || newAttachment->m_encoding.LowerCaseEqualsLiteral( ENCODING_UUENCODE2) || newAttachment->m_encoding.LowerCaseEqualsLiteral( ENCODING_UUENCODE3) || newAttachment->m_encoding.LowerCaseEqualsLiteral( ENCODING_UUENCODE4)) fn = &MimeUUDecoderInit; else if (newAttachment->m_encoding.LowerCaseEqualsLiteral(ENCODING_YENCODE)) fn = &MimeYDecoderInit; if (fn) { mdd->decoder_data = fn(/* The (MimeConverterOutputCallback) cast is to turn the `void' argument into `MimeObject'. */ ((MimeConverterOutputCallback)dummy_file_write), mdd->tmpFileStream); if (!mdd->decoder_data) return MIME_OUT_OF_MEMORY; } } return 0; } int mime_decompose_file_output_fn(const char* buf, int32_t size, void* stream_closure) { mime_draft_data* mdd = (mime_draft_data*)stream_closure; int ret = 0; NS_ASSERTION(mdd && buf, "missing mime draft data and/or buf"); if (!mdd || !buf) return -1; if (!size) return 0; if (!mdd->tmpFileStream) return 0; if (mdd->autodetectCharset) { nsAutoCString detectedCharset; nsresult res = NS_OK; res = MIME_detect_charset(buf, size, detectedCharset); if (NS_SUCCEEDED(res) && !detectedCharset.IsEmpty()) { mdd->mailcharset = ToNewCString(detectedCharset); mdd->autodetectCharset = false; } } if (mdd->decoder_data) { int32_t outsize; ret = MimeDecoderWrite(mdd->decoder_data, buf, size, &outsize); if (ret == -1) return -1; mdd->curAttachment->m_size += outsize; } else { uint32_t bytesWritten; mdd->tmpFileStream->Write(buf, size, &bytesWritten); if ((int32_t)bytesWritten < size) return MIME_ERROR_WRITING_FILE; mdd->curAttachment->m_size += size; } return 0; } int mime_decompose_file_close_fn(void* stream_closure) { mime_draft_data* mdd = (mime_draft_data*)stream_closure; if (!mdd) return -1; if (--mdd->options->decompose_init_count > 0) return 0; if (mdd->decoder_data) { MimeDecoderDestroy(mdd->decoder_data, false); mdd->decoder_data = 0; } if (!mdd->tmpFileStream) { // it's ok to have a null tmpFileStream if there's no tmpFile. // This happens for cloud file attachments. NS_ASSERTION(!mdd->tmpFile, "shouldn't have a tmp file bu no stream"); return 0; } mdd->tmpFileStream->Close(); mdd->tmpFileStream = nullptr; mdd->tmpFile = nullptr; return 0; } extern "C" void* mime_bridge_create_draft_stream( nsIMimeEmitter* newEmitter, nsStreamConverter* newPluginObj2, nsIURI* uri, nsMimeOutputType format_out) { int status = 0; nsMIMESession* stream = nullptr; mime_draft_data* mdd = nullptr; MimeObject* obj = nullptr; if (!uri) return nullptr; mdd = new mime_draft_data; if (!mdd) return nullptr; nsAutoCString turl; nsCOMPtr msgService; nsCOMPtr aURL; nsAutoCString urlString; nsresult rv; // first, convert the rdf msg uri into a url that represents the message... if (NS_FAILED(uri->GetSpec(turl))) goto FAIL; rv = GetMessageServiceFromURI(turl, getter_AddRefs(msgService)); if (NS_FAILED(rv)) goto FAIL; rv = msgService->GetUrlForUri(turl, nullptr, getter_AddRefs(aURL)); if (NS_FAILED(rv)) goto FAIL; if (NS_SUCCEEDED(aURL->GetSpec(urlString))) { int32_t typeIndex = urlString.Find("&type=application/x-message-display"); if (typeIndex != -1) urlString.Cut(typeIndex, sizeof("&type=application/x-message-display") - 1); mdd->url_name = ToNewCString(urlString); if (!(mdd->url_name)) goto FAIL; } newPluginObj2->GetForwardInline(&mdd->forwardInline); newPluginObj2->GetForwardInlineFilter(&mdd->forwardInlineFilter); newPluginObj2->GetForwardToAddress(mdd->forwardToAddress); newPluginObj2->GetOverrideComposeFormat(&mdd->overrideComposeFormat); newPluginObj2->GetIdentity(getter_AddRefs(mdd->identity)); newPluginObj2->GetOriginalMsgURI(mdd->originalMsgURI); newPluginObj2->GetOrigMsgHdr(getter_AddRefs(mdd->origMsgHdr)); mdd->format_out = format_out; mdd->options = new MimeDisplayOptions; if (!mdd->options) goto FAIL; mdd->options->url = strdup(mdd->url_name); mdd->options->format_out = format_out; // output format mdd->options->decompose_file_p = true; /* new field in MimeDisplayOptions */ mdd->options->stream_closure = mdd; mdd->options->html_closure = mdd; mdd->options->decompose_headers_info_fn = make_mime_headers_copy; mdd->options->decompose_file_init_fn = mime_decompose_file_init_fn; mdd->options->decompose_file_output_fn = mime_decompose_file_output_fn; mdd->options->decompose_file_close_fn = mime_decompose_file_close_fn; mdd->options->m_prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) goto FAIL; #ifdef ENABLE_SMIME /* If we're attaching a message (for forwarding) then we must eradicate all traces of xlateion from it, since forwarding someone else a message that wasn't xlated for them doesn't work. We have to dexlate it before sending it. */ mdd->options->decrypt_p = true; #endif /* ENABLE_SMIME */ obj = mime_new((MimeObjectClass*)&mimeMessageClass, (MimeHeaders*)NULL, MESSAGE_RFC822); if (!obj) goto FAIL; obj->options = mdd->options; mdd->obj = obj; stream = PR_NEWZAP(nsMIMESession); if (!stream) goto FAIL; stream->name = "MIME To Draft Converter Stream"; stream->complete = mime_parse_stream_complete; stream->abort = mime_parse_stream_abort; stream->put_block = mime_parse_stream_write; stream->data_object = mdd; status = obj->clazz->initialize(obj); if (status >= 0) status = obj->clazz->parse_begin(obj); if (status < 0) goto FAIL; return stream; FAIL: if (mdd) { PR_Free(mdd->url_name); if (mdd->options) delete mdd->options; PR_Free(mdd); } PR_Free(stream); PR_Free(obj); return nullptr; }