summaryrefslogtreecommitdiffstats
path: root/mailnews/extensions/mdn
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/extensions/mdn')
-rw-r--r--mailnews/extensions/mdn/content/am-mdn.js155
-rw-r--r--mailnews/extensions/mdn/content/am-mdn.xul136
-rw-r--r--mailnews/extensions/mdn/content/mdn.js23
-rw-r--r--mailnews/extensions/mdn/jar.mn7
-rw-r--r--mailnews/extensions/mdn/moz.build12
-rw-r--r--mailnews/extensions/mdn/src/mdn-service.js24
-rw-r--r--mailnews/extensions/mdn/src/mdn-service.manifest3
-rw-r--r--mailnews/extensions/mdn/src/moz.build16
-rw-r--r--mailnews/extensions/mdn/src/nsMsgMdnCID.h22
-rw-r--r--mailnews/extensions/mdn/src/nsMsgMdnGenerator.cpp1139
-rw-r--r--mailnews/extensions/mdn/src/nsMsgMdnGenerator.h90
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="&notInToCc.label;"
+ accesskey="&notInToCc.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..69f557274
--- /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, or local accounts
+ return (server.type != "nntp" && server.type != "rss" &&
+ 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_
+