diff options
Diffstat (limited to 'mailnews/extensions/mdn')
-rw-r--r-- | mailnews/extensions/mdn/content/am-mdn.js | 155 | ||||
-rw-r--r-- | mailnews/extensions/mdn/content/am-mdn.xul | 136 | ||||
-rw-r--r-- | mailnews/extensions/mdn/content/mdn.js | 23 | ||||
-rw-r--r-- | mailnews/extensions/mdn/jar.mn | 7 | ||||
-rw-r--r-- | mailnews/extensions/mdn/moz.build | 12 | ||||
-rw-r--r-- | mailnews/extensions/mdn/src/mdn-service.js | 24 | ||||
-rw-r--r-- | mailnews/extensions/mdn/src/mdn-service.manifest | 3 | ||||
-rw-r--r-- | mailnews/extensions/mdn/src/moz.build | 16 | ||||
-rw-r--r-- | mailnews/extensions/mdn/src/nsMsgMdnCID.h | 22 | ||||
-rw-r--r-- | mailnews/extensions/mdn/src/nsMsgMdnGenerator.cpp | 1139 | ||||
-rw-r--r-- | mailnews/extensions/mdn/src/nsMsgMdnGenerator.h | 90 |
11 files changed, 1627 insertions, 0 deletions
diff --git a/mailnews/extensions/mdn/content/am-mdn.js b/mailnews/extensions/mdn/content/am-mdn.js new file mode 100644 index 000000000..4dd9e8d8d --- /dev/null +++ b/mailnews/extensions/mdn/content/am-mdn.js @@ -0,0 +1,155 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +var useCustomPrefs; +var requestReceipt; +var leaveInInbox; +var moveToSent; +var receiptSend; +var neverReturn; +var returnSome; +var notInToCcPref; +var notInToCcLabel; +var outsideDomainPref; +var outsideDomainLabel; +var otherCasesPref; +var otherCasesLabel; +var receiptArriveLabel; +var receiptRequestLabel; +var gIdentity; +var gIncomingServer; +var gMdnPrefBranch; + +function onInit() +{ + useCustomPrefs = document.getElementById("identity.use_custom_prefs"); + requestReceipt = document.getElementById("identity.request_return_receipt_on"); + leaveInInbox = document.getElementById("leave_in_inbox"); + moveToSent = document.getElementById("move_to_sent"); + receiptSend = document.getElementById("server.mdn_report_enabled"); + neverReturn = document.getElementById("never_return"); + returnSome = document.getElementById("return_some"); + notInToCcPref = document.getElementById("server.mdn_not_in_to_cc"); + notInToCcLabel = document.getElementById("notInToCcLabel"); + outsideDomainPref = document.getElementById("server.mdn_outside_domain"); + outsideDomainLabel = document.getElementById("outsideDomainLabel"); + otherCasesPref = document.getElementById("server.mdn_other"); + otherCasesLabel = document.getElementById("otherCasesLabel"); + receiptArriveLabel = document.getElementById("receiptArriveLabel"); + receiptRequestLabel = document.getElementById("receiptRequestLabel"); + + EnableDisableCustomSettings(); + + return true; +} + +function onSave() +{ + +} + +function EnableDisableCustomSettings() { + if (useCustomPrefs && (useCustomPrefs.getAttribute("value") == "false")) { + requestReceipt.setAttribute("disabled", "true"); + leaveInInbox.setAttribute("disabled", "true"); + moveToSent.setAttribute("disabled", "true"); + neverReturn.setAttribute("disabled", "true"); + returnSome.setAttribute("disabled", "true"); + receiptArriveLabel.setAttribute("disabled", "true"); + receiptRequestLabel.setAttribute("disabled", "true"); + } + else { + requestReceipt.removeAttribute("disabled"); + leaveInInbox.removeAttribute("disabled"); + moveToSent.removeAttribute("disabled"); + neverReturn.removeAttribute("disabled"); + returnSome.removeAttribute("disabled"); + receiptArriveLabel.removeAttribute("disabled"); + receiptRequestLabel.removeAttribute("disabled"); + } + EnableDisableAllowedReceipts(); + // Lock id based prefs + onLockPreference("mail.identity", gIdentity.key); + // Lock server based prefs + onLockPreference("mail.server", gIncomingServer.key); + return true; +} + +function EnableDisableAllowedReceipts() { + if (receiptSend) { + if (!neverReturn.getAttribute("disabled") && (receiptSend.getAttribute("value") != "false")) { + notInToCcPref.removeAttribute("disabled"); + notInToCcLabel.removeAttribute("disabled"); + outsideDomainPref.removeAttribute("disabled"); + outsideDomainLabel.removeAttribute("disabled"); + otherCasesPref.removeAttribute("disabled"); + otherCasesLabel.removeAttribute("disabled"); + } + else { + notInToCcPref.setAttribute("disabled", "true"); + notInToCcLabel.setAttribute("disabled", "true"); + outsideDomainPref.setAttribute("disabled", "true"); + outsideDomainLabel.setAttribute("disabled", "true"); + otherCasesPref.setAttribute("disabled", "true"); + otherCasesLabel.setAttribute("disabled", "true"); + } + } + return true; +} + +function onPreInit(account, accountValues) +{ + gIdentity = account.defaultIdentity; + gIncomingServer = account.incomingServer; +} + +// Disables xul elements that have associated preferences locked. +function onLockPreference(initPrefString, keyString) +{ + var finalPrefString; + + var allPrefElements = [ + { prefstring:"request_return_receipt_on", id:"identity.request_return_receipt_on"}, + { prefstring:"select_custom_prefs", id:"identity.select_custom_prefs"}, + { prefstring:"select_global_prefs", id:"identity.select_global_prefs"}, + { prefstring:"incorporate_return_receipt", id:"server.incorporate_return_receipt"}, + { prefstring:"never_return", id:"never_return"}, + { prefstring:"return_some", id:"return_some"}, + { prefstring:"mdn_not_in_to_cc", id:"server.mdn_not_in_to_cc"}, + { prefstring:"mdn_outside_domain", id:"server.mdn_outside_domain"}, + { prefstring:"mdn_other", id:"server.mdn_other"}, + ]; + + finalPrefString = initPrefString + "." + keyString + "."; + gMdnPrefBranch = Services.prefs.getBranch(finalPrefString); + + disableIfLocked( allPrefElements ); +} + +function disableIfLocked( prefstrArray ) +{ + for (var i=0; i<prefstrArray.length; i++) { + var id = prefstrArray[i].id; + var element = document.getElementById(id); + if (gMdnPrefBranch.prefIsLocked(prefstrArray[i].prefstring)) { + if (id == "server.incorporate_return_receipt") + { + document.getElementById("leave_in_inbox").setAttribute("disabled", "true"); + document.getElementById("move_to_sent").setAttribute("disabled", "true"); + } + else + element.setAttribute("disabled", "true"); + } + } +} + +/** + * Opens Preferences (Options) dialog on the pane and tab where + * the global receipts settings can be found. + */ +function showGlobalReceipts() { + openPrefsFromAccountManager("paneAdvanced", "generalTab", + {subdialog: "showReturnReceipts"}, "receipts_pane"); +} diff --git a/mailnews/extensions/mdn/content/am-mdn.xul b/mailnews/extensions/mdn/content/am-mdn.xul new file mode 100644 index 000000000..c290752ab --- /dev/null +++ b/mailnews/extensions/mdn/content/am-mdn.xul @@ -0,0 +1,136 @@ +<?xml version="1.0"?> + +<!-- + + 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/. --> + +<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?> + +<!DOCTYPE page SYSTEM "chrome://messenger/locale/am-mdn.dtd"> + +<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + title="&pane.title;" + onload="parent.onPanelLoaded('am-mdn.xul');"> + + <vbox flex="1" style="overflow: auto;"> + <stringbundle id="bundle_smime" src="chrome://messenger/locale/am-mdn.properties"/> + <script type="application/javascript" src="chrome://messenger/content/AccountManager.js"/> + <script type="application/javascript" src="chrome://messenger/content/amUtils.js"/> + <script type="application/javascript" src="chrome://messenger/content/am-mdn.js"/> + + <dialogheader title="&pane.title;"/> + + <groupbox> + + <caption label="&pane.title;"/> + + <hbox id="prefChoices" align="center" flex="1"> + <radiogroup id="identity.use_custom_prefs" wsm_persist="true" genericattr="true" + preftype="bool" prefstring="mail.identity.%identitykey%.use_custom_prefs" + oncommand="EnableDisableCustomSettings();" flex="1"> + <radio id="identity.select_global_prefs" + value="false" + label="&useGlobalPrefs.label;" + accesskey="&useGlobalPrefs.accesskey;"/> + <hbox flex="1"> + <spacer flex="1"/> + <button id="globalReceiptsLink" + label="&globalReceipts.label;" + accesskey="&globalReceipts.accesskey;" + oncommand="showGlobalReceipts();"/> + </hbox> + <radio id="identity.select_custom_prefs" + value="true" + label="&useCustomPrefs.label;" + accesskey="&useCustomPrefs.accesskey;"/> + </radiogroup> + </hbox> + + <vbox id="returnReceiptSettings" class="indent" align="start"> + <checkbox id="identity.request_return_receipt_on" label="&requestReceipt.label;" + accesskey="&requestReceipt.accesskey;" + wsm_persist="true" genericattr="true" iscontrolcontainer="true" + preftype="bool" prefstring="mail.identity.%identitykey%.request_return_receipt_on"/> + + <separator/> + + <vbox id="receiptArrive"> + <label id="receiptArriveLabel" control="server.incorporate_return_receipt">&receiptArrive.label;</label> + <radiogroup id="server.incorporate_return_receipt" wsm_persist="true" genericattr="true" + preftype="int" prefstring="mail.server.%serverkey%.incorporate_return_receipt" + class="indent"> + <radio id="leave_in_inbox" value="0" label="&leaveIt.label;" + accesskey="&leaveIt.accesskey;"/> + <radio id="move_to_sent" value="1" label="&moveToSent.label;" + accesskey="&moveToSent.accesskey;"/> + </radiogroup> + </vbox> + + <separator/> + + <vbox id="receiptRequest"> + <label id="receiptRequestLabel" control="server.mdn_report_enabled">&requestMDN.label;</label> + <radiogroup id="server.mdn_report_enabled" wsm_persist="true" genericattr="true" + preftype="bool" prefstring="mail.server.%serverkey%.mdn_report_enabled" + oncommand="EnableDisableAllowedReceipts();" + class="indent"> + <radio id="never_return" value="false" label="&never.label;" + accesskey="&never.accesskey;"/> + <radio id="return_some" value="true" label="&returnSome.label;" + accesskey="&returnSome.accesskey;"/> + + <hbox id="receiptSendIf" class="indent"> + <grid> + <columns><column/><column/></columns> + <rows> + <row align="center"> + <label id="notInToCcLabel" value="¬InToCc.label;" + accesskey="¬InToCc.accesskey;" control="server.mdn_not_in_to_cc"/> + <menulist id="server.mdn_not_in_to_cc" wsm_persist="true" genericattr="true" + preftype="int" prefstring="mail.server.%serverkey%.mdn_not_in_to_cc"> + <menupopup> + <menuitem value="0" label="&neverSend.label;"/> + <menuitem value="1" label="&alwaysSend.label;"/> + <menuitem value="2" label="&askMe.label;"/> + </menupopup> + </menulist> + </row> + <row align="center"> + <label id="outsideDomainLabel" value="&outsideDomain.label;" + accesskey="&outsideDomain.accesskey;" control="server.mdn_outside_domain"/> + <menulist id="server.mdn_outside_domain" wsm_persist="true" genericattr="true" + preftype="int" prefstring="mail.server.%serverkey%.mdn_outside_domain"> + <menupopup> + <menuitem value="0" label="&neverSend.label;"/> + <menuitem value="1" label="&alwaysSend.label;"/> + <menuitem value="2" label="&askMe.label;"/> + </menupopup> + </menulist> + </row> + <row align="center"> + <label id="otherCasesLabel" value="&otherCases.label;" + accesskey="&otherCases.accesskey;" control="server.mdn_other"/> + <menulist id="server.mdn_other" wsm_persist="true" genericattr="true" + preftype="int" prefstring="mail.server.%serverkey%.mdn_other"> + <menupopup> + <menuitem value="0" label="&neverSend.label;"/> + <menuitem value="1" label="&alwaysSend.label;"/> + <menuitem value="2" label="&askMe.label;"/> + </menupopup> + </menulist> + </row> + </rows> + </grid> + </hbox> + </radiogroup> + + </vbox> + + </vbox> + + </groupbox> + </vbox> + +</page> diff --git a/mailnews/extensions/mdn/content/mdn.js b/mailnews/extensions/mdn/content/mdn.js new file mode 100644 index 000000000..9ac481573 --- /dev/null +++ b/mailnews/extensions/mdn/content/mdn.js @@ -0,0 +1,23 @@ +/* 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/. */ + +/* + * default prefs for mdn + */ + +pref("mail.identity.default.use_custom_prefs", false); // false: Use global true: Use custom + +pref("mail.identity.default.request_return_receipt_on", false); + +pref("mail.server.default.incorporate_return_receipt", 0); // 0: Inbox/filter 1: Sent folder + +pref("mail.server.default.mdn_report_enabled", true); // false: Never return receipts true: Return some receipts + +pref("mail.server.default.mdn_not_in_to_cc", 2); // 0: Never 1: Always 2: Ask me 3: Denial +pref("mail.server.default.mdn_outside_domain", 2); +pref("mail.server.default.mdn_other", 2); + +pref("mail.identity.default.request_receipt_header_type", 0); // return receipt header type - 0: MDN-DNT 1: RRT 2: Both + +pref("mail.server.default.mdn_report_enabled", true); diff --git a/mailnews/extensions/mdn/jar.mn b/mailnews/extensions/mdn/jar.mn new file mode 100644 index 000000000..74fde6b60 --- /dev/null +++ b/mailnews/extensions/mdn/jar.mn @@ -0,0 +1,7 @@ +# 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/. + +messenger.jar: + content/messenger/am-mdn.xul (content/am-mdn.xul) + content/messenger/am-mdn.js (content/am-mdn.js) diff --git a/mailnews/extensions/mdn/moz.build b/mailnews/extensions/mdn/moz.build new file mode 100644 index 000000000..5aaa32895 --- /dev/null +++ b/mailnews/extensions/mdn/moz.build @@ -0,0 +1,12 @@ +# vim: set filetype=python: +# 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/. + +DIRS += ['src'] + +JAR_MANIFESTS += ['jar.mn'] + +JS_PREFERENCE_FILES += [ + 'content/mdn.js', +] diff --git a/mailnews/extensions/mdn/src/mdn-service.js b/mailnews/extensions/mdn/src/mdn-service.js new file mode 100644 index 000000000..32e1cbde1 --- /dev/null +++ b/mailnews/extensions/mdn/src/mdn-service.js @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * 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/. */ + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +function MDNService() {} + +MDNService.prototype = { + name: "mdn", + chromePackageName: "messenger", + showPanel: function(server) { + // don't show the panel for news, rss, im or local accounts + return (server.type != "nntp" && server.type != "rss" && + server.type != "im" && server.type != "none"); + }, + + QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIMsgAccountManagerExtension]), + classID: Components.ID("{e007d92e-1dd1-11b2-a61e-dc962c9b8571}"), +}; + +var components = [MDNService]; +var NSGetFactory = XPCOMUtils.generateNSGetFactory(components); diff --git a/mailnews/extensions/mdn/src/mdn-service.manifest b/mailnews/extensions/mdn/src/mdn-service.manifest new file mode 100644 index 000000000..493a3c69b --- /dev/null +++ b/mailnews/extensions/mdn/src/mdn-service.manifest @@ -0,0 +1,3 @@ +component {e007d92e-1dd1-11b2-a61e-dc962c9b8571} mdn-service.js +contract @mozilla.org/accountmanager/extension;1?name=mdn {e007d92e-1dd1-11b2-a61e-dc962c9b8571} +category mailnews-accountmanager-extensions mdn-account-manager-extension @mozilla.org/accountmanager/extension;1?name=mdn diff --git a/mailnews/extensions/mdn/src/moz.build b/mailnews/extensions/mdn/src/moz.build new file mode 100644 index 000000000..1aef9b208 --- /dev/null +++ b/mailnews/extensions/mdn/src/moz.build @@ -0,0 +1,16 @@ +# vim: set filetype=python: +# 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/. + +SOURCES += [ + 'nsMsgMdnGenerator.cpp', +] + +EXTRA_COMPONENTS += [ + 'mdn-service.js', + 'mdn-service.manifest', +] + +FINAL_LIBRARY = 'mail' + diff --git a/mailnews/extensions/mdn/src/nsMsgMdnCID.h b/mailnews/extensions/mdn/src/nsMsgMdnCID.h new file mode 100644 index 000000000..4dd832b7f --- /dev/null +++ b/mailnews/extensions/mdn/src/nsMsgMdnCID.h @@ -0,0 +1,22 @@ +/* -*- 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/. */ + +#ifndef nsMsgMdnCID_h__ +#define nsMsgMdnCID_h__ + +#include "nsISupports.h" +#include "nsIFactory.h" +#include "nsIComponentManager.h" + +#include "nsIMsgMdnGenerator.h" + +#define NS_MSGMDNGENERATOR_CONTRACTID \ + "@mozilla.org/messenger-mdn/generator;1" +#define NS_MSGMDNGENERATOR_CID \ +{ /* ec917b13-8f73-4d4d-9146-d7f7aafe9076 */ \ + 0xec917b13, 0x8f73, 0x4d4d, \ + { 0x91, 0x46, 0xd7, 0xf7, 0xaa, 0xfe, 0x90, 0x76 }} + +#endif /* nsMsgMdnCID_h__ */ diff --git a/mailnews/extensions/mdn/src/nsMsgMdnGenerator.cpp b/mailnews/extensions/mdn/src/nsMsgMdnGenerator.cpp new file mode 100644 index 000000000..31b55fe2f --- /dev/null +++ b/mailnews/extensions/mdn/src/nsMsgMdnGenerator.cpp @@ -0,0 +1,1139 @@ +/* -*- 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/. */ + +#include "nsMsgMdnGenerator.h" +#include "nsImapCore.h" +#include "nsIMsgImapMailFolder.h" +#include "nsIMsgAccountManager.h" +#include "nsMsgBaseCID.h" +#include "nsMimeTypes.h" +#include "prprf.h" +#include "prmem.h" +#include "prsystem.h" +#include "nsMsgI18N.h" +#include "nsMailHeaders.h" +#include "nsMsgLocalFolderHdrs.h" +#include "nsIHttpProtocolHandler.h" +#include "nsISmtpService.h" // for actually sending the message... +#include "nsMsgCompCID.h" +#include "nsComposeStrings.h" +#include "nsISmtpServer.h" +#include "nsIPrompt.h" +#include "nsIMsgCompUtils.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIStringBundle.h" +#include "nsDirectoryServiceDefs.h" +#include "nsMsgUtils.h" +#include "nsNetUtil.h" +#include "nsIMsgDatabase.h" +#include "mozilla/Services.h" +#include "nsIArray.h" +#include "nsArrayUtils.h" +#include "mozilla/mailnews/MimeHeaderParser.h" + +using namespace mozilla::mailnews; + +#define MDN_NOT_IN_TO_CC ((int) 0x0001) +#define MDN_OUTSIDE_DOMAIN ((int) 0x0002) + +#define HEADER_RETURN_PATH "Return-Path" +#define HEADER_DISPOSITION_NOTIFICATION_TO "Disposition-Notification-To" +#define HEADER_APPARENTLY_TO "Apparently-To" +#define HEADER_ORIGINAL_RECIPIENT "Original-Recipient" +#define HEADER_REPORTING_UA "Reporting-UA" +#define HEADER_MDN_GATEWAY "MDN-Gateway" +#define HEADER_FINAL_RECIPIENT "Final-Recipient" +#define HEADER_DISPOSITION "Disposition" +#define HEADER_ORIGINAL_MESSAGE_ID "Original-Message-ID" +#define HEADER_FAILURE "Failure" +#define HEADER_ERROR "Error" +#define HEADER_WARNING "Warning" +#define HEADER_RETURN_RECEIPT_TO "Return-Receipt-To" +#define HEADER_X_ACCEPT_LANGUAGE "X-Accept-Language" + +#define PUSH_N_FREE_STRING(p) \ + do { if (p) { rv = WriteString(p); PR_smprintf_free(p); p=0; \ + if (NS_FAILED(rv)) return rv; } \ + else { return NS_ERROR_OUT_OF_MEMORY; } } while (0) + +// String bundle for mdn. Class static. +#define MDN_STRINGBUNDLE_URL "chrome://messenger/locale/msgmdn.properties" + +#if defined(DEBUG_jefft) +#define DEBUG_MDN(s) printf("%s\n", s) +#else +#define DEBUG_MDN(s) +#endif + +// machine parsible string; should not be localized +char DispositionTypes[7][16] = { + "displayed", + "dispatched", + "processed", + "deleted", + "denied", + "failed", + "" +}; + +NS_IMPL_ISUPPORTS(nsMsgMdnGenerator, nsIMsgMdnGenerator, nsIUrlListener) + +nsMsgMdnGenerator::nsMsgMdnGenerator() +{ + m_disposeType = eDisplayed; + m_outputStream = nullptr; + m_reallySendMdn = false; + m_autoSend = false; + m_autoAction = false; + m_mdnEnabled = false; + m_notInToCcOp = eNeverSendOp; + m_outsideDomainOp = eNeverSendOp; + m_otherOp = eNeverSendOp; +} + +nsMsgMdnGenerator::~nsMsgMdnGenerator() +{ +} + +nsresult nsMsgMdnGenerator::FormatStringFromName(const char16_t *aName, + const char16_t *aString, + char16_t **aResultString) +{ + DEBUG_MDN("nsMsgMdnGenerator::FormatStringFromName"); + + nsCOMPtr<nsIStringBundleService> bundleService = + mozilla::services::GetStringBundleService(); + NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED); + + nsCOMPtr <nsIStringBundle> bundle; + nsresult rv = bundleService->CreateBundle(MDN_STRINGBUNDLE_URL, + getter_AddRefs(bundle)); + NS_ENSURE_SUCCESS(rv,rv); + + const char16_t *formatStrings[1] = { aString }; + rv = bundle->FormatStringFromName(aName, + formatStrings, 1, aResultString); + NS_ENSURE_SUCCESS(rv,rv); + return rv; +} + +nsresult nsMsgMdnGenerator::GetStringFromName(const char16_t *aName, + char16_t **aResultString) +{ + DEBUG_MDN("nsMsgMdnGenerator::GetStringFromName"); + + nsCOMPtr<nsIStringBundleService> bundleService = + mozilla::services::GetStringBundleService(); + NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED); + + nsCOMPtr <nsIStringBundle> bundle; + nsresult rv = bundleService->CreateBundle(MDN_STRINGBUNDLE_URL, + getter_AddRefs(bundle)); + NS_ENSURE_SUCCESS(rv,rv); + + rv = bundle->GetStringFromName(aName, aResultString); + NS_ENSURE_SUCCESS(rv,rv); + return rv; +} + +nsresult nsMsgMdnGenerator::StoreMDNSentFlag(nsIMsgFolder *folder, + nsMsgKey key) +{ + DEBUG_MDN("nsMsgMdnGenerator::StoreMDNSentFlag"); + + nsCOMPtr<nsIMsgDatabase> msgDB; + nsresult rv = folder->GetMsgDatabase(getter_AddRefs(msgDB)); + NS_ENSURE_SUCCESS(rv, rv); + rv = msgDB->MarkMDNSent(key, true, nullptr); + + nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(folder); + // Store the $MDNSent flag if the folder is an Imap Mail Folder + if (imapFolder) + return imapFolder->StoreImapFlags(kImapMsgMDNSentFlag, true, &key, 1, nullptr); + return rv; +} + +nsresult nsMsgMdnGenerator::ClearMDNNeededFlag(nsIMsgFolder *folder, + nsMsgKey key) +{ + DEBUG_MDN("nsMsgMdnGenerator::ClearMDNNeededFlag"); + + nsCOMPtr<nsIMsgDatabase> msgDB; + nsresult rv = folder->GetMsgDatabase(getter_AddRefs(msgDB)); + NS_ENSURE_SUCCESS(rv, rv); + return msgDB->MarkMDNNeeded(key, false, nullptr); +} + +bool nsMsgMdnGenerator::ProcessSendMode() +{ + DEBUG_MDN("nsMsgMdnGenerator::ProcessSendMode"); + int32_t miscState = 0; + + if (m_identity) + { + m_identity->GetEmail(m_email); + if (m_email.IsEmpty()) + return m_reallySendMdn; + + const char *accountDomain = strchr(m_email.get(), '@'); + if (!accountDomain) + return m_reallySendMdn; + + if (MailAddrMatch(m_email.get(), m_dntRrt.get())) // return address is self, don't send + return false; + + // *** fix me see Bug 132504 for more information + // *** what if the message has been filtered to different account + if (!PL_strcasestr(m_dntRrt.get(), accountDomain)) + miscState |= MDN_OUTSIDE_DOMAIN; + if (NotInToOrCc()) + miscState |= MDN_NOT_IN_TO_CC; + m_reallySendMdn = true; + // ********* + // How are we gona deal with the auto forwarding issues? Some server + // didn't bother to add addition header or modify existing header to + // thev message when forwarding. They simply copy the exact same + // message to another user's mailbox. Some change To: to + // Apparently-To: + // Unfortunately, there is nothing we can do. It's out of our control. + // ********* + // starting from lowest denominator to highest + if (!miscState) + { // under normal situation: recipent is in to and cc list, + // and the sender is from the same domain + switch (m_otherOp) + { + default: + case eNeverSendOp: + m_reallySendMdn = false; + break; + case eAutoSendOp: + m_autoSend = true; + break; + case eAskMeOp: + m_autoSend = false; + break; + case eDeniedOp: + m_autoSend = true; + m_disposeType = eDenied; + break; + } + } + else if (miscState == (MDN_OUTSIDE_DOMAIN | MDN_NOT_IN_TO_CC)) + { + if (m_outsideDomainOp != m_notInToCcOp) + { + m_autoSend = false; // ambiguous; always ask user + } + else + { + switch (m_outsideDomainOp) + { + default: + case eNeverSendOp: + m_reallySendMdn = false; + break; + case eAutoSendOp: + m_autoSend = true; + break; + case eAskMeOp: + m_autoSend = false; + break; + } + } + } + else if (miscState & MDN_OUTSIDE_DOMAIN) + { + switch (m_outsideDomainOp) + { + default: + case eNeverSendOp: + m_reallySendMdn = false; + break; + case eAutoSendOp: + m_autoSend = true; + break; + case eAskMeOp: + m_autoSend = false; + break; + } + } + else if (miscState & MDN_NOT_IN_TO_CC) + { + switch (m_notInToCcOp) + { + default: + case eNeverSendOp: + m_reallySendMdn = false; + break; + case eAutoSendOp: + m_autoSend = true; + break; + case eAskMeOp: + m_autoSend = false; + break; + } + } + } + return m_reallySendMdn; +} + +bool nsMsgMdnGenerator::MailAddrMatch(const char *addr1, const char *addr2) +{ + // Comparing two email addresses returns true if matched; local/account + // part comparison is case sensitive; domain part comparison is case + // insensitive + DEBUG_MDN("nsMsgMdnGenerator::MailAddrMatch"); + bool isMatched = true; + const char *atSign1 = nullptr, *atSign2 = nullptr; + const char *lt = nullptr, *local1 = nullptr, *local2 = nullptr; + const char *end1 = nullptr, *end2 = nullptr; + + if (!addr1 || !addr2) + return false; + + lt = strchr(addr1, '<'); + local1 = !lt ? addr1 : lt+1; + lt = strchr(addr2, '<'); + local2 = !lt ? addr2 : lt+1; + end1 = strchr(local1, '>'); + if (!end1) + end1 = addr1 + strlen(addr1); + end2 = strchr(local2, '>'); + if (!end2) + end2 = addr2 + strlen(addr2); + atSign1 = strchr(local1, '@'); + atSign2 = strchr(local2, '@'); + if (!atSign1 || !atSign2 // ill formed addr spec + || (atSign1 - local1) != (atSign2 - local2)) + isMatched = false; + else if (strncmp(local1, local2, (atSign1-local1))) // case sensitive + // compare for local part + isMatched = false; + else if ((end1 - atSign1) != (end2 - atSign2) || + PL_strncasecmp(atSign1, atSign2, (end1-atSign1))) // case + // insensitive compare for domain part + isMatched = false; + return isMatched; +} + +bool nsMsgMdnGenerator::NotInToOrCc() +{ + DEBUG_MDN("nsMsgMdnGenerator::NotInToOrCc"); + nsCString reply_to; + nsCString to; + nsCString cc; + + m_identity->GetReplyTo(reply_to); + m_headers->ExtractHeader(HEADER_TO, true, to); + m_headers->ExtractHeader(HEADER_CC, true, cc); + + // start with a simple check + if ((!to.IsEmpty() && PL_strcasestr(to.get(), m_email.get())) || + (!cc.IsEmpty() && PL_strcasestr(cc.get(), m_email.get()))) { + return false; + } + + if ((!reply_to.IsEmpty() && !to.IsEmpty() && PL_strcasestr(to.get(), reply_to.get())) || + (!reply_to.IsEmpty() && !cc.IsEmpty() && PL_strcasestr(cc.get(), reply_to.get()))) { + return false; + } + return true; +} + +bool nsMsgMdnGenerator::ValidateReturnPath() +{ + DEBUG_MDN("nsMsgMdnGenerator::ValidateReturnPath"); + // ValidateReturnPath applies to Automatic Send Mode only. If we were not + // in auto send mode we simply by passing the check + if (!m_autoSend) + return m_reallySendMdn; + + nsCString returnPath; + m_headers->ExtractHeader(HEADER_RETURN_PATH, false, returnPath); + if (returnPath.IsEmpty()) + { + m_autoSend = false; + return m_reallySendMdn; + } + m_autoSend = MailAddrMatch(returnPath.get(), m_dntRrt.get()); + return m_reallySendMdn; +} + +nsresult nsMsgMdnGenerator::CreateMdnMsg() +{ + DEBUG_MDN("nsMsgMdnGenerator::CreateMdnMsg"); + nsresult rv; + + nsCOMPtr<nsIFile> tmpFile; + rv = GetSpecialDirectoryWithFileName(NS_OS_TEMP_DIR, + "mdnmsg", + getter_AddRefs(m_file)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = m_file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 00600); + NS_ENSURE_SUCCESS(rv, rv); + rv = MsgNewBufferedFileOutputStream(getter_AddRefs(m_outputStream), + m_file, + PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE, + 0664); + NS_ASSERTION(NS_SUCCEEDED(rv),"creating mdn: failed to output stream"); + if (NS_FAILED(rv)) + return NS_OK; + + rv = CreateFirstPart(); + if (NS_SUCCEEDED(rv)) + { + rv = CreateSecondPart(); + if (NS_SUCCEEDED(rv)) + rv = CreateThirdPart(); + } + + if (m_outputStream) + { + m_outputStream->Flush(); + m_outputStream->Close(); + } + if (NS_FAILED(rv)) + m_file->Remove(false); + else + rv = SendMdnMsg(); + + return NS_OK; +} + +nsresult nsMsgMdnGenerator::CreateFirstPart() +{ + DEBUG_MDN("nsMsgMdnGenerator::CreateFirstPart"); + char *convbuf = nullptr, *tmpBuffer = nullptr; + char *parm = nullptr; + nsString firstPart1; + nsString firstPart2; + nsresult rv = NS_OK; + nsCOMPtr <nsIMsgCompUtils> compUtils; + + if (m_mimeSeparator.IsEmpty()) + { + compUtils = do_GetService(NS_MSGCOMPUTILS_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = compUtils->MimeMakeSeparator("mdn", getter_Copies(m_mimeSeparator)); + NS_ENSURE_SUCCESS(rv, rv); + } + if (m_mimeSeparator.IsEmpty()) + return NS_ERROR_OUT_OF_MEMORY; + + tmpBuffer = (char *) PR_CALLOC(256); + + if (!tmpBuffer) + return NS_ERROR_OUT_OF_MEMORY; + + PRExplodedTime now; + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &now); + + int gmtoffset = (now.tm_params.tp_gmt_offset + now.tm_params.tp_dst_offset) + / 60; + /* Use PR_FormatTimeUSEnglish() to format the date in US English format, + then figure out what our local GMT offset is, and append it (since + PR_FormatTimeUSEnglish() can't do that.) Generate four digit years as + per RFC 1123 (superceding RFC 822.) + */ + PR_FormatTimeUSEnglish(tmpBuffer, 100, + "Date: %a, %d %b %Y %H:%M:%S ", + &now); + + PR_snprintf(tmpBuffer + strlen(tmpBuffer), 100, + "%c%02d%02d" CRLF, + (gmtoffset >= 0 ? '+' : '-'), + ((gmtoffset >= 0 ? gmtoffset : -gmtoffset) / 60), + ((gmtoffset >= 0 ? gmtoffset : -gmtoffset) % 60)); + + rv = WriteString(tmpBuffer); + PR_Free(tmpBuffer); + if (NS_FAILED(rv)) + return rv; + + bool conformToStandard = false; + if (compUtils) + compUtils->GetMsgMimeConformToStandard(&conformToStandard); + + nsString fullName; + m_identity->GetFullName(fullName); + + nsCString fullAddress; + // convert fullName to UTF8 before passing it to MakeMimeAddress + MakeMimeAddress(NS_ConvertUTF16toUTF8(fullName), m_email, fullAddress); + + convbuf = nsMsgI18NEncodeMimePartIIStr(fullAddress.get(), + true, m_charset.get(), 0, conformToStandard); + + parm = PR_smprintf("From: %s" CRLF, convbuf ? convbuf : m_email.get()); + + rv = FormatStringFromName(u"MsgMdnMsgSentTo", NS_ConvertASCIItoUTF16(m_email).get(), + getter_Copies(firstPart1)); + if (NS_FAILED(rv)) + return rv; + + PUSH_N_FREE_STRING (parm); + + PR_Free(convbuf); + + if (compUtils) + { + nsCString msgId; + rv = compUtils->MsgGenerateMessageId(m_identity, getter_Copies(msgId)); + tmpBuffer = PR_smprintf("Message-ID: %s" CRLF, msgId.get()); + PUSH_N_FREE_STRING(tmpBuffer); + } + + nsString receipt_string; + switch (m_disposeType) + { + case nsIMsgMdnGenerator::eDisplayed: + rv = GetStringFromName( + u"MdnDisplayedReceipt", + getter_Copies(receipt_string)); + break; + case nsIMsgMdnGenerator::eDispatched: + rv = GetStringFromName( + u"MdnDispatchedReceipt", + getter_Copies(receipt_string)); + break; + case nsIMsgMdnGenerator::eProcessed: + rv = GetStringFromName( + u"MdnProcessedReceipt", + getter_Copies(receipt_string)); + break; + case nsIMsgMdnGenerator::eDeleted: + rv = GetStringFromName( + u"MdnDeletedReceipt", + getter_Copies(receipt_string)); + break; + case nsIMsgMdnGenerator::eDenied: + rv = GetStringFromName( + u"MdnDeniedReceipt", + getter_Copies(receipt_string)); + break; + case nsIMsgMdnGenerator::eFailed: + rv = GetStringFromName( + u"MdnFailedReceipt", + getter_Copies(receipt_string)); + break; + default: + rv = NS_ERROR_INVALID_ARG; + break; + } + + if (NS_FAILED(rv)) + return rv; + + receipt_string.AppendLiteral(" - "); + + char * encodedReceiptString = nsMsgI18NEncodeMimePartIIStr(NS_ConvertUTF16toUTF8(receipt_string).get(), false, + "UTF-8", 0, conformToStandard); + + nsCString subject; + m_headers->ExtractHeader(HEADER_SUBJECT, false, subject); + convbuf = nsMsgI18NEncodeMimePartIIStr(subject.Length() ? subject.get() : "[no subject]", + false, m_charset.get(), 0, conformToStandard); + tmpBuffer = PR_smprintf("Subject: %s%s" CRLF, + encodedReceiptString, + (convbuf ? convbuf : (subject.Length() ? subject.get() : + "[no subject]"))); + + PUSH_N_FREE_STRING(tmpBuffer); + PR_Free(convbuf); + PR_Free(encodedReceiptString); + + convbuf = nsMsgI18NEncodeMimePartIIStr(m_dntRrt.get(), true, m_charset.get(), 0, conformToStandard); + tmpBuffer = PR_smprintf("To: %s" CRLF, convbuf ? convbuf : + m_dntRrt.get()); + PUSH_N_FREE_STRING(tmpBuffer); + + PR_Free(convbuf); + + // *** This is not in the spec. I am adding this so we could do + // threading + m_headers->ExtractHeader(HEADER_MESSAGE_ID, false, m_messageId); + + if (!m_messageId.IsEmpty()) + { + if (*m_messageId.get() == '<') + tmpBuffer = PR_smprintf("References: %s" CRLF, m_messageId.get()); + else + tmpBuffer = PR_smprintf("References: <%s>" CRLF, m_messageId.get()); + PUSH_N_FREE_STRING(tmpBuffer); + } + tmpBuffer = PR_smprintf("%s" CRLF, "MIME-Version: 1.0"); + PUSH_N_FREE_STRING(tmpBuffer); + + tmpBuffer = PR_smprintf("Content-Type: multipart/report; \ +report-type=disposition-notification;\r\n\tboundary=\"%s\"" CRLF CRLF, + m_mimeSeparator.get()); + PUSH_N_FREE_STRING(tmpBuffer); + + tmpBuffer = PR_smprintf("--%s" CRLF, m_mimeSeparator.get()); + PUSH_N_FREE_STRING(tmpBuffer); + + tmpBuffer = PR_smprintf("Content-Type: text/plain; charset=UTF-8" CRLF); + PUSH_N_FREE_STRING(tmpBuffer); + + tmpBuffer = PR_smprintf("Content-Transfer-Encoding: %s" CRLF CRLF, + ENCODING_8BIT); + PUSH_N_FREE_STRING(tmpBuffer); + + if (!firstPart1.IsEmpty()) + { + tmpBuffer = PR_smprintf("%s" CRLF CRLF, NS_ConvertUTF16toUTF8(firstPart1).get()); + PUSH_N_FREE_STRING(tmpBuffer); + } + + switch (m_disposeType) + { + case nsIMsgMdnGenerator::eDisplayed: + rv = GetStringFromName( + u"MsgMdnDisplayed", + getter_Copies(firstPart2)); + break; + case nsIMsgMdnGenerator::eDispatched: + rv = GetStringFromName( + u"MsgMdnDispatched", + getter_Copies(firstPart2)); + break; + case nsIMsgMdnGenerator::eProcessed: + rv = GetStringFromName( + u"MsgMdnProcessed", + getter_Copies(firstPart2)); + break; + case nsIMsgMdnGenerator::eDeleted: + rv = GetStringFromName( + u"MsgMdnDeleted", + getter_Copies(firstPart2)); + break; + case nsIMsgMdnGenerator::eDenied: + rv = GetStringFromName( + u"MsgMdnDenied", + getter_Copies(firstPart2)); + break; + case nsIMsgMdnGenerator::eFailed: + rv = GetStringFromName( + u"MsgMdnFailed", + getter_Copies(firstPart2)); + break; + default: + rv = NS_ERROR_INVALID_ARG; + break; + } + + if (NS_FAILED(rv)) + return rv; + + if (!firstPart2.IsEmpty()) + { + tmpBuffer = + PR_smprintf("%s" CRLF CRLF, + NS_ConvertUTF16toUTF8(firstPart2).get()); + PUSH_N_FREE_STRING(tmpBuffer); + } + + return rv; +} + +nsresult nsMsgMdnGenerator::CreateSecondPart() +{ + DEBUG_MDN("nsMsgMdnGenerator::CreateSecondPart"); + char *tmpBuffer = nullptr; + char *convbuf = nullptr; + nsresult rv = NS_OK; + nsCOMPtr <nsIMsgCompUtils> compUtils; + bool conformToStandard = false; + + tmpBuffer = PR_smprintf("--%s" CRLF, m_mimeSeparator.get()); + PUSH_N_FREE_STRING(tmpBuffer); + + tmpBuffer = PR_smprintf("%s" CRLF, "Content-Type: message/disposition-notification; name=\042MDNPart2.txt\042"); + PUSH_N_FREE_STRING(tmpBuffer); + + tmpBuffer = PR_smprintf("%s" CRLF, "Content-Disposition: inline"); + PUSH_N_FREE_STRING(tmpBuffer); + + tmpBuffer = PR_smprintf("Content-Transfer-Encoding: %s" CRLF CRLF, + ENCODING_7BIT); + PUSH_N_FREE_STRING(tmpBuffer); + + nsCOMPtr<nsIHttpProtocolHandler> pHTTPHandler = + do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv); + if (NS_SUCCEEDED(rv) && pHTTPHandler) + { + nsAutoCString userAgentString; + pHTTPHandler->GetUserAgent(userAgentString); + + if (!userAgentString.IsEmpty()) + { + // Prepend the product name with the dns name according to RFC 3798. + char hostName[256]; + PR_GetSystemInfo(PR_SI_HOSTNAME_UNTRUNCATED, hostName, sizeof hostName); + if ((hostName[0] != '\0') && (strchr(hostName, '.') != NULL)) + { + userAgentString.Insert("; ", 0); + userAgentString.Insert(nsDependentCString(hostName), 0); + } + + tmpBuffer = PR_smprintf("Reporting-UA: %s" CRLF, + userAgentString.get()); + PUSH_N_FREE_STRING(tmpBuffer); + } + } + + nsCString originalRecipient; + m_headers->ExtractHeader(HEADER_ORIGINAL_RECIPIENT, false, + originalRecipient); + + if (!originalRecipient.IsEmpty()) + { + tmpBuffer = PR_smprintf("Original-Recipient: %s" CRLF, + originalRecipient.get()); + PUSH_N_FREE_STRING(tmpBuffer); + } + + compUtils = do_GetService(NS_MSGCOMPUTILS_CONTRACTID, &rv); + if (compUtils) + compUtils->GetMsgMimeConformToStandard(&conformToStandard); + + convbuf = nsMsgI18NEncodeMimePartIIStr( + m_email.get(), true, m_charset.get(), 0, + conformToStandard); + tmpBuffer = PR_smprintf("Final-Recipient: rfc822;%s" CRLF, convbuf ? + convbuf : m_email.get()); + PUSH_N_FREE_STRING(tmpBuffer); + + PR_Free (convbuf); + + if (*m_messageId.get() == '<') + tmpBuffer = PR_smprintf("Original-Message-ID: %s" CRLF, m_messageId.get()); + else + tmpBuffer = PR_smprintf("Original-Message-ID: <%s>" CRLF, m_messageId.get()); + PUSH_N_FREE_STRING(tmpBuffer); + + tmpBuffer = PR_smprintf("Disposition: %s/%s; %s" CRLF CRLF, + (m_autoAction ? "automatic-action" : + "manual-action"), + (m_autoSend ? "MDN-sent-automatically" : + "MDN-sent-manually"), + DispositionTypes[(int) m_disposeType]); + PUSH_N_FREE_STRING(tmpBuffer); + + return rv; +} + +nsresult nsMsgMdnGenerator::CreateThirdPart() +{ + DEBUG_MDN("nsMsgMdnGenerator::CreateThirdPart"); + char *tmpBuffer = nullptr; + nsresult rv = NS_OK; + + tmpBuffer = PR_smprintf("--%s" CRLF, m_mimeSeparator.get()); + PUSH_N_FREE_STRING(tmpBuffer); + + tmpBuffer = PR_smprintf("%s" CRLF, "Content-Type: text/rfc822-headers; name=\042MDNPart3.txt\042"); + PUSH_N_FREE_STRING(tmpBuffer); + + tmpBuffer = PR_smprintf("%s" CRLF, "Content-Transfer-Encoding: 7bit"); + PUSH_N_FREE_STRING(tmpBuffer); + + tmpBuffer = PR_smprintf("%s" CRLF CRLF, "Content-Disposition: inline"); + PUSH_N_FREE_STRING(tmpBuffer); + + rv = OutputAllHeaders(); + + if (NS_FAILED(rv)) + return rv; + + rv = WriteString(CRLF); + if (NS_FAILED(rv)) + return rv; + + tmpBuffer = PR_smprintf("--%s--" CRLF, m_mimeSeparator.get()); + PUSH_N_FREE_STRING(tmpBuffer); + + return rv; +} + + +nsresult nsMsgMdnGenerator::OutputAllHeaders() +{ + DEBUG_MDN("nsMsgMdnGenerator::OutputAllHeaders"); + nsCString all_headers; + int32_t all_headers_size = 0; + nsresult rv = NS_OK; + + rv = m_headers->GetAllHeaders(all_headers); + if (NS_FAILED(rv)) + return rv; + all_headers_size = all_headers.Length(); + char *buf = (char *) all_headers.get(), + *buf_end = (char *) all_headers.get()+all_headers_size; + char *start = buf, *end = buf; + + while (buf < buf_end) + { + switch (*buf) + { + case 0: + if (*(buf+1) == '\n') + { + // *buf = '\r'; + end = buf; + } + else if (*(buf+1) == 0) + { + // the case of message id + *buf = '>'; + } + break; + case '\r': + end = buf; + *buf = 0; + break; + case '\n': + if (buf > start && *(buf-1) == 0) + { + start = buf + 1; + end = start; + } + else + { + end = buf; + } + *buf = 0; + break; + default: + break; + } + buf++; + + if (end > start && *end == 0) + { + // strip out private X-Mozilla-Status header & X-Mozilla-Draft-Info && envelope header + if (!PL_strncasecmp(start, X_MOZILLA_STATUS, X_MOZILLA_STATUS_LEN) + || !PL_strncasecmp(start, X_MOZILLA_DRAFT_INFO, X_MOZILLA_DRAFT_INFO_LEN) + || !PL_strncasecmp(start, "From ", 5)) + { + while ( end < buf_end && + (*end == '\n' || *end == '\r' || *end == 0)) + end++; + start = end; + } + else + { + NS_ASSERTION (*end == 0, "content of end should be null"); + rv = WriteString(start); + if (NS_FAILED(rv)) + return rv; + rv = WriteString(CRLF); + while ( end < buf_end && + (*end == '\n' || *end == '\r' || *end == 0)) + end++; + start = end; + } + buf = start; + } + } + return NS_OK; +} + +nsresult nsMsgMdnGenerator::SendMdnMsg() +{ + DEBUG_MDN("nsMsgMdnGenerator::SendMdnMsg"); + nsresult rv; + nsCOMPtr<nsISmtpService> smtpService = do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + nsCOMPtr<nsIRequest> aRequest; + smtpService->SendMailMessage(m_file, m_dntRrt.get(), m_identity, + nullptr, this, nullptr, nullptr, false, nullptr, + getter_AddRefs(aRequest)); + + return NS_OK; +} + +nsresult nsMsgMdnGenerator::WriteString( const char *str ) +{ + NS_ENSURE_ARG (str); + uint32_t len = strlen(str); + uint32_t wLen = 0; + + return m_outputStream->Write(str, len, &wLen); +} + +nsresult nsMsgMdnGenerator::InitAndProcess(bool *needToAskUser) +{ + DEBUG_MDN("nsMsgMdnGenerator::InitAndProcess"); + nsresult rv = m_folder->GetServer(getter_AddRefs(m_server)); + nsCOMPtr<nsIMsgAccountManager> accountManager = + do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); + if (accountManager && m_server) + { + if (!m_identity) + { + // check if this is a message delivered to the global inbox, + // in which case we find the originating account's identity. + nsCString accountKey; + m_headers->ExtractHeader(HEADER_X_MOZILLA_ACCOUNT_KEY, false, + accountKey); + nsCOMPtr <nsIMsgAccount> account; + if (!accountKey.IsEmpty()) + accountManager->GetAccount(accountKey, getter_AddRefs(account)); + if (account) + account->GetIncomingServer(getter_AddRefs(m_server)); + + if (m_server) + { + // Find the correct identity based on the "To:" and "Cc:" header + nsCString mailTo; + nsCString mailCC; + m_headers->ExtractHeader(HEADER_TO, true, mailTo); + m_headers->ExtractHeader(HEADER_CC, true, mailCC); + nsCOMPtr<nsIArray> servIdentities; + accountManager->GetIdentitiesForServer(m_server, getter_AddRefs(servIdentities)); + if (servIdentities) + { + nsCOMPtr<nsIMsgIdentity> ident; + nsCString identEmail; + uint32_t count = 0; + servIdentities->GetLength(&count); + // First check in the "To:" header + for (uint32_t i = 0; i < count; i++) + { + ident = do_QueryElementAt(servIdentities, i, &rv); + if (NS_FAILED(rv)) + continue; + ident->GetEmail(identEmail); + if (!mailTo.IsEmpty() && !identEmail.IsEmpty() && + mailTo.Find(identEmail, CaseInsensitiveCompare) != kNotFound) + { + m_identity = ident; + break; + } + } + // If no match, check the "Cc:" header + if (!m_identity) + { + for (uint32_t i = 0; i < count; i++) + { + rv = servIdentities->QueryElementAt(i, NS_GET_IID(nsIMsgIdentity),getter_AddRefs(ident)); + if (NS_FAILED(rv)) + continue; + ident->GetEmail(identEmail); + if (!mailCC.IsEmpty() && !identEmail.IsEmpty() && + mailCC.Find(identEmail, CaseInsensitiveCompare) != kNotFound) + { + m_identity = ident; + break; + } + } + } + } + + // If no match again, use the first identity + if (!m_identity) + rv = accountManager->GetFirstIdentityForServer(m_server, getter_AddRefs(m_identity)); + } + } + NS_ENSURE_SUCCESS(rv,rv); + + if (m_identity) + { + bool useCustomPrefs = false; + m_identity->GetBoolAttribute("use_custom_prefs", &useCustomPrefs); + if (useCustomPrefs) + { + bool bVal = false; + m_server->GetBoolValue("mdn_report_enabled", &bVal); + m_mdnEnabled = bVal; + m_server->GetIntValue("mdn_not_in_to_cc", &m_notInToCcOp); + m_server->GetIntValue("mdn_outside_domain", + &m_outsideDomainOp); + m_server->GetIntValue("mdn_other", &m_otherOp); + } + else + { + bool bVal = false; + + nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + return rv; + + if(prefBranch) + { + prefBranch->GetBoolPref("mail.mdn.report.enabled", + &bVal); + m_mdnEnabled = bVal; + prefBranch->GetIntPref("mail.mdn.report.not_in_to_cc", + &m_notInToCcOp); + prefBranch->GetIntPref("mail.mdn.report.outside_domain", + &m_outsideDomainOp); + prefBranch->GetIntPref("mail.mdn.report.other", + &m_otherOp); + } + } + } + } + + rv = m_folder->GetCharset(m_charset); + if (m_mdnEnabled) + { + m_headers->ExtractHeader(HEADER_DISPOSITION_NOTIFICATION_TO, false, + m_dntRrt); + if (m_dntRrt.IsEmpty()) + m_headers->ExtractHeader(HEADER_RETURN_RECEIPT_TO, false, + m_dntRrt); + if (!m_dntRrt.IsEmpty() && ProcessSendMode() && ValidateReturnPath()) + { + if (!m_autoSend) + { + *needToAskUser = true; + rv = NS_OK; + } + else + { + *needToAskUser = false; + rv = UserAgreed(); + } + } + } + return rv; +} + +NS_IMETHODIMP nsMsgMdnGenerator::Process(EDisposeType type, + nsIMsgWindow *aWindow, + nsIMsgFolder *folder, + nsMsgKey key, + nsIMimeHeaders *headers, + bool autoAction, + bool *_retval) +{ + DEBUG_MDN("nsMsgMdnGenerator::Process"); + NS_ENSURE_ARG_POINTER(folder); + NS_ENSURE_ARG_POINTER(headers); + NS_ENSURE_ARG_POINTER(aWindow); + NS_ENSURE_TRUE(key != nsMsgKey_None, NS_ERROR_INVALID_ARG); + m_disposeType = type; + m_autoAction = autoAction; + m_window = aWindow; + m_folder = folder; + m_headers = headers; + m_key = key; + + mozilla::DebugOnly<nsresult> rv = InitAndProcess(_retval); + NS_ASSERTION(NS_SUCCEEDED(rv), "InitAndProcess failed"); + return NS_OK; +} + +NS_IMETHODIMP nsMsgMdnGenerator::UserAgreed() +{ + DEBUG_MDN("nsMsgMdnGenerator::UserAgreed"); + (void) NoteMDNRequestHandled(); + return CreateMdnMsg(); +} + +NS_IMETHODIMP nsMsgMdnGenerator::UserDeclined() +{ + DEBUG_MDN("nsMsgMdnGenerator::UserDeclined"); + return NoteMDNRequestHandled(); +} + +/** + * Set/clear flags appropriately so we won't ask user again about MDN + * request for this message. + */ +nsresult nsMsgMdnGenerator::NoteMDNRequestHandled() +{ + nsresult rv = StoreMDNSentFlag(m_folder, m_key); + NS_ASSERTION(NS_SUCCEEDED(rv), "StoreMDNSentFlag failed"); + rv = ClearMDNNeededFlag(m_folder, m_key); + NS_ASSERTION(NS_SUCCEEDED(rv), "ClearMDNNeededFlag failed"); + return rv; +} + +NS_IMETHODIMP nsMsgMdnGenerator::OnStartRunningUrl(nsIURI *url) +{ + DEBUG_MDN("nsMsgMdnGenerator::OnStartRunningUrl"); + return NS_OK; +} + +NS_IMETHODIMP nsMsgMdnGenerator::OnStopRunningUrl(nsIURI *url, + nsresult aExitCode) +{ + nsresult rv; + + DEBUG_MDN("nsMsgMdnGenerator::OnStopRunningUrl"); + if (m_file) + m_file->Remove(false); + + if (NS_SUCCEEDED(aExitCode)) + return NS_OK; + + const char16_t* exitString; + + switch (aExitCode) + { + case NS_ERROR_UNKNOWN_HOST: + case NS_ERROR_UNKNOWN_PROXY_HOST: + exitString = u"smtpSendFailedUnknownServer"; + break; + case NS_ERROR_CONNECTION_REFUSED: + case NS_ERROR_PROXY_CONNECTION_REFUSED: + exitString = u"smtpSendRequestRefused"; + break; + case NS_ERROR_NET_INTERRUPT: + case NS_ERROR_ABORT: // we have no proper string for error code NS_ERROR_ABORT in compose bundle + exitString = u"smtpSendInterrupted"; + break; + case NS_ERROR_NET_TIMEOUT: + case NS_ERROR_NET_RESET: + exitString = u"smtpSendTimeout"; + break; + default: + exitString = errorStringNameForErrorCode(aExitCode); + break; + } + + nsCOMPtr<nsISmtpService> smtpService(do_GetService(NS_SMTPSERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv,rv); + + // Get the smtp hostname and format the string. + nsCString smtpHostName; + nsCOMPtr<nsISmtpServer> smtpServer; + rv = smtpService->GetServerByIdentity(m_identity, getter_AddRefs(smtpServer)); + if (NS_SUCCEEDED(rv)) + smtpServer->GetHostname(smtpHostName); + + nsAutoString hostStr; + CopyASCIItoUTF16(smtpHostName, hostStr); + const char16_t *params[] = { hostStr.get() }; + + nsCOMPtr<nsIStringBundle> bundle; + nsCOMPtr<nsIStringBundleService> bundleService = + mozilla::services::GetStringBundleService(); + NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED); + + rv = bundleService->CreateBundle( + "chrome://messenger/locale/messengercompose/composeMsgs.properties", + getter_AddRefs(bundle)); + NS_ENSURE_SUCCESS(rv, rv); + + nsString failed_msg, dialogTitle; + + bundle->FormatStringFromName(exitString, params, 1, getter_Copies(failed_msg)); + bundle->GetStringFromName(u"sendMessageErrorTitle", getter_Copies(dialogTitle)); + + nsCOMPtr<nsIPrompt> dialog; + rv = m_window->GetPromptDialog(getter_AddRefs(dialog)); + if (NS_SUCCEEDED(rv)) + dialog->Alert(dialogTitle.get(),failed_msg.get()); + + return NS_OK; +} diff --git a/mailnews/extensions/mdn/src/nsMsgMdnGenerator.h b/mailnews/extensions/mdn/src/nsMsgMdnGenerator.h new file mode 100644 index 000000000..54b6efab4 --- /dev/null +++ b/mailnews/extensions/mdn/src/nsMsgMdnGenerator.h @@ -0,0 +1,90 @@ +/* -*- 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/. */ + +#ifndef _nsMsgMdnGenerator_H_ +#define _nsMsgMdnGenerator_H_ + +#include "nsIMsgMdnGenerator.h" +#include "nsCOMPtr.h" +#include "nsIUrlListener.h" +#include "nsIMsgIncomingServer.h" +#include "nsIOutputStream.h" +#include "nsIFile.h" +#include "nsIMsgIdentity.h" +#include "nsIMsgWindow.h" +#include "nsIMimeHeaders.h" +#include "nsStringGlue.h" +#include "MailNewsTypes2.h" + +#define eNeverSendOp ((int32_t) 0) +#define eAutoSendOp ((int32_t) 1) +#define eAskMeOp ((int32_t) 2) +#define eDeniedOp ((int32_t) 3) + +class nsMsgMdnGenerator : public nsIMsgMdnGenerator, public nsIUrlListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIMSGMDNGENERATOR + NS_DECL_NSIURLLISTENER + + nsMsgMdnGenerator(); + +private: + virtual ~nsMsgMdnGenerator(); + + // Sanity Check methods + bool ProcessSendMode(); // must called prior ValidateReturnPath + bool ValidateReturnPath(); + bool NotInToOrCc(); + bool MailAddrMatch(const char *addr1, const char *addr2); + + nsresult StoreMDNSentFlag(nsIMsgFolder *folder, nsMsgKey key); + nsresult ClearMDNNeededFlag(nsIMsgFolder *folder, nsMsgKey key); + nsresult NoteMDNRequestHandled(); + + nsresult CreateMdnMsg(); + nsresult CreateFirstPart(); + nsresult CreateSecondPart(); + nsresult CreateThirdPart(); + nsresult SendMdnMsg(); + + // string bundle helper methods + nsresult GetStringFromName(const char16_t *aName, char16_t **aResultString); + nsresult FormatStringFromName(const char16_t *aName, + const char16_t *aString, + char16_t **aResultString); + + // other helper methods + nsresult InitAndProcess(bool *needToAskUser); + nsresult OutputAllHeaders(); + nsresult WriteString(const char *str); + +private: + EDisposeType m_disposeType; + nsCOMPtr<nsIMsgWindow> m_window; + nsCOMPtr<nsIOutputStream> m_outputStream; + nsCOMPtr<nsIFile> m_file; + nsCOMPtr<nsIMsgIdentity> m_identity; + nsMsgKey m_key; + nsCString m_charset; + nsCString m_email; + nsCString m_mimeSeparator; + nsCString m_messageId; + nsCOMPtr<nsIMsgFolder> m_folder; + nsCOMPtr<nsIMsgIncomingServer> m_server; + nsCOMPtr<nsIMimeHeaders> m_headers; + nsCString m_dntRrt; + int32_t m_notInToCcOp; + int32_t m_outsideDomainOp; + int32_t m_otherOp; + bool m_reallySendMdn; + bool m_autoSend; + bool m_autoAction; + bool m_mdnEnabled; +}; + +#endif // _nsMsgMdnGenerator_H_ + |