summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/extensions/mdn
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /comm/mailnews/extensions/mdn
parentInitial commit. (diff)
downloadthunderbird-upstream.tar.xz
thunderbird-upstream.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--comm/mailnews/extensions/mdn/MDNService.jsm24
-rw-r--r--comm/mailnews/extensions/mdn/am-mdn.js161
-rw-r--r--comm/mailnews/extensions/mdn/am-mdn.xhtml231
-rw-r--r--comm/mailnews/extensions/mdn/components.conf23
-rw-r--r--comm/mailnews/extensions/mdn/jar.mn7
-rw-r--r--comm/mailnews/extensions/mdn/mdn.js25
-rw-r--r--comm/mailnews/extensions/mdn/moz.build26
-rw-r--r--comm/mailnews/extensions/mdn/nsMsgMdnGenerator.cpp1040
-rw-r--r--comm/mailnews/extensions/mdn/nsMsgMdnGenerator.h86
-rw-r--r--comm/mailnews/extensions/mdn/test/unit/head_mdn.js18
-rw-r--r--comm/mailnews/extensions/mdn/test/unit/test_askuser.js67
-rw-r--r--comm/mailnews/extensions/mdn/test/unit/test_mdnFlags.js60
-rw-r--r--comm/mailnews/extensions/mdn/test/unit/xpcshell.ini6
13 files changed, 1774 insertions, 0 deletions
diff --git a/comm/mailnews/extensions/mdn/MDNService.jsm b/comm/mailnews/extensions/mdn/MDNService.jsm
new file mode 100644
index 0000000000..47f5257b6a
--- /dev/null
+++ b/comm/mailnews/extensions/mdn/MDNService.jsm
@@ -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/. */
+
+var EXPORTED_SYMBOLS = ["MDNService"];
+
+function MDNService() {}
+
+MDNService.prototype = {
+ name: "mdn",
+ chromePackageName: "messenger",
+ showPanel(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: ChromeUtils.generateQI(["nsIMsgAccountManagerExtension"]),
+};
diff --git a/comm/mailnews/extensions/mdn/am-mdn.js b/comm/mailnews/extensions/mdn/am-mdn.js
new file mode 100644
index 0000000000..7725339fbd
--- /dev/null
+++ b/comm/mailnews/extensions/mdn/am-mdn.js
@@ -0,0 +1,161 @@
+/* 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/. */
+
+/* import-globals-from ../../base/prefs/content/amUtils.js */
+
+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 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" },
+ ];
+
+ var finalPrefString = initPrefString + "." + keyString + ".";
+ gMdnPrefBranch = Services.prefs.getBranch(finalPrefString);
+
+ disableIfLocked(allPrefElements);
+}
+
+function disableIfLocked(prefstrArray) {
+ for (let 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() {
+ parent.gSubDialog.open(
+ "chrome://messenger/content/preferences/receipts.xhtml",
+ { features: "resizable=no" }
+ );
+}
diff --git a/comm/mailnews/extensions/mdn/am-mdn.xhtml b/comm/mailnews/extensions/mdn/am-mdn.xhtml
new file mode 100644
index 0000000000..3cdf85d9e5
--- /dev/null
+++ b/comm/mailnews/extensions/mdn/am-mdn.xhtml
@@ -0,0 +1,231 @@
+<?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 html SYSTEM "chrome://messenger/locale/am-mdn.dtd">
+
+<html
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+>
+ <head>
+ <title>&pane.title;</title>
+ <script
+ defer="defer"
+ src="chrome://messenger/content/AccountManager.js"
+ ></script>
+ <script defer="defer" src="chrome://messenger/content/amUtils.js"></script>
+ <script defer="defer" src="chrome://messenger/content/am-mdn.js"></script>
+ <script>
+ // FIXME: move to script file.
+ window.addEventListener("load", event => {
+ parent.onPanelLoaded("am-mdn.xhtml");
+ });
+ </script>
+ </head>
+ <html:body
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ >
+ <vbox id="containerBox" flex="1">
+ <stringbundle
+ id="bundle_smime"
+ src="chrome://messenger/locale/am-mdn.properties"
+ />
+
+ <hbox class="dialogheader">
+ <label class="dialogheader-title" value="&pane.title;" />
+ </hbox>
+
+ <separator class="thin" />
+
+ <html:div>
+ <html:fieldset>
+ <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">
+ <vbox>
+ <hbox flex="1" align="center">
+ <label
+ id="notInToCcLabel"
+ value="&notInToCc.label;"
+ accesskey="&notInToCc.accesskey;"
+ control="server.mdn_not_in_to_cc"
+ />
+ </hbox>
+ <hbox flex="1" align="center">
+ <label
+ id="outsideDomainLabel"
+ value="&outsideDomain.label;"
+ accesskey="&outsideDomain.accesskey;"
+ control="server.mdn_outside_domain"
+ />
+ </hbox>
+ <hbox flex="1" align="center">
+ <label
+ id="otherCasesLabel"
+ value="&otherCases.label;"
+ accesskey="&otherCases.accesskey;"
+ control="server.mdn_other"
+ />
+ </hbox>
+ </vbox>
+ <vbox>
+ <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>
+ <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>
+ <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>
+ </vbox>
+ </hbox>
+ </radiogroup>
+ </vbox>
+ </vbox>
+ </html:fieldset>
+ </html:div>
+ </vbox>
+ </html:body>
+</html>
diff --git a/comm/mailnews/extensions/mdn/components.conf b/comm/mailnews/extensions/mdn/components.conf
new file mode 100644
index 0000000000..84f53febbf
--- /dev/null
+++ b/comm/mailnews/extensions/mdn/components.conf
@@ -0,0 +1,23 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# 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/.
+
+Classes = [
+ {
+ "cid": "{e007d92e-1dd1-11b2-a61e-dc962c9b8571}",
+ "contract_ids": ["@mozilla.org/accountmanager/extension;1?name=mdn"],
+ "jsm": "resource:///modules/MDNService.jsm",
+ "constructor": "MDNService",
+ "categories": {
+ "mailnews-accountmanager-extensions": "mdn-account-manager-extension"
+ },
+ },
+ {
+ "cid": "{ec917b13-8f73-4d4d-9146-d7f7aafe9076}",
+ "contract_ids": ["@mozilla.org/messenger-mdn/generator;1"],
+ "type": "nsMsgMdnGenerator",
+ "headers": ["/comm/mailnews/extensions/mdn/nsMsgMdnGenerator.h"],
+ },
+]
diff --git a/comm/mailnews/extensions/mdn/jar.mn b/comm/mailnews/extensions/mdn/jar.mn
new file mode 100644
index 0000000000..cb487cd969
--- /dev/null
+++ b/comm/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.xhtml (am-mdn.xhtml)
+ content/messenger/am-mdn.js (am-mdn.js)
diff --git a/comm/mailnews/extensions/mdn/mdn.js b/comm/mailnews/extensions/mdn/mdn.js
new file mode 100644
index 0000000000..ae82382f39
--- /dev/null
+++ b/comm/mailnews/extensions/mdn/mdn.js
@@ -0,0 +1,25 @@
+#filter dumbComments emptyLines substitution
+
+// 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
+//
+
+// false: Use global true: Use custom
+pref("mail.identity.default.use_custom_prefs", false);
+pref("mail.identity.default.request_return_receipt_on", false);
+// 0: Inbox/filter 1: Sent folder
+pref("mail.server.default.incorporate_return_receipt", 0);
+// false: Never return receipts true: Return some receipts
+pref("mail.server.default.mdn_report_enabled", true);
+// 0: Never 1: Always 2: Ask me 3: Denial
+pref("mail.server.default.mdn_not_in_to_cc", 2);
+pref("mail.server.default.mdn_outside_domain", 2);
+pref("mail.server.default.mdn_other", 2);
+// return receipt header type - 0: MDN-DNT 1: RRT 2: Both
+pref("mail.identity.default.request_receipt_header_type", 0);
+
+pref("mail.server.default.mdn_report_enabled", true);
diff --git a/comm/mailnews/extensions/mdn/moz.build b/comm/mailnews/extensions/mdn/moz.build
new file mode 100644
index 0000000000..2d7b8bce5d
--- /dev/null
+++ b/comm/mailnews/extensions/mdn/moz.build
@@ -0,0 +1,26 @@
+# 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/.
+
+JAR_MANIFESTS += ["jar.mn"]
+
+JS_PREFERENCE_PP_FILES += [
+ "mdn.js",
+]
+
+XPCSHELL_TESTS_MANIFESTS += ["test/unit/xpcshell.ini"]
+
+SOURCES += [
+ "nsMsgMdnGenerator.cpp",
+]
+
+EXTRA_JS_MODULES += [
+ "MDNService.jsm",
+]
+
+XPCOM_MANIFESTS += [
+ "components.conf",
+]
+
+FINAL_LIBRARY = "mail"
diff --git a/comm/mailnews/extensions/mdn/nsMsgMdnGenerator.cpp b/comm/mailnews/extensions/mdn/nsMsgMdnGenerator.cpp
new file mode 100644
index 0000000000..76fc6d5214
--- /dev/null
+++ b/comm/mailnews/extensions/mdn/nsMsgMdnGenerator.cpp
@@ -0,0 +1,1040 @@
+/* -*- 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 "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 "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/Components.h"
+#include "mozilla/mailnews/MimeHeaderParser.h"
+#include "mozilla/Unused.h"
+#include "nsIPromptService.h"
+#include "nsEmbedCID.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_key(nsMsgKey_None),
+ m_notInToCcOp(eNeverSendOp),
+ m_outsideDomainOp(eNeverSendOp),
+ m_otherOp(eNeverSendOp),
+ m_reallySendMdn(false),
+ m_autoSend(false),
+ m_autoAction(false),
+ m_mdnEnabled(false) {}
+
+nsMsgMdnGenerator::~nsMsgMdnGenerator() {}
+
+nsresult nsMsgMdnGenerator::FormatStringFromName(const char* aName,
+ const nsString& aString,
+ nsAString& aResultString) {
+ DEBUG_MDN("nsMsgMdnGenerator::FormatStringFromName");
+
+ nsCOMPtr<nsIStringBundleService> bundleService =
+ mozilla::components::StringBundle::Service();
+ 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);
+
+ AutoTArray<nsString, 1> formatStrings = {aString};
+ rv = bundle->FormatStringFromName(aName, formatStrings, aResultString);
+ NS_ENSURE_SUCCESS(rv, rv);
+ return rv;
+}
+
+nsresult nsMsgMdnGenerator::GetStringFromName(const char* aName,
+ nsAString& aResultString) {
+ DEBUG_MDN("nsMsgMdnGenerator::GetStringFromName");
+
+ nsCOMPtr<nsIStringBundleService> bundleService =
+ mozilla::components::StringBundle::Service();
+ 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},
+ 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
+ // the 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("@mozilla.org/messengercompose/computils;1", &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 (superseding 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, "UTF-8", 0,
+ conformToStandard);
+
+ parm = PR_smprintf("From: %s" CRLF, convbuf ? convbuf : m_email.get());
+
+ rv = FormatStringFromName("MsgMdnMsgSentTo", NS_ConvertASCIItoUTF16(m_email),
+ firstPart1);
+ if (NS_FAILED(rv)) return rv;
+
+ PUSH_N_FREE_STRING(parm);
+
+ PR_Free(convbuf);
+
+ if (compUtils) {
+ nsCString msgId;
+ rv = compUtils->MsgGenerateMessageId(m_identity, ""_ns, msgId);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ 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("MdnDisplayedReceipt", receipt_string);
+ break;
+ case nsIMsgMdnGenerator::eDispatched:
+ rv = GetStringFromName("MdnDispatchedReceipt", receipt_string);
+ break;
+ case nsIMsgMdnGenerator::eProcessed:
+ rv = GetStringFromName("MdnProcessedReceipt", receipt_string);
+ break;
+ case nsIMsgMdnGenerator::eDeleted:
+ rv = GetStringFromName("MdnDeletedReceipt", receipt_string);
+ break;
+ case nsIMsgMdnGenerator::eDenied:
+ rv = GetStringFromName("MdnDeniedReceipt", receipt_string);
+ break;
+ case nsIMsgMdnGenerator::eFailed:
+ rv = GetStringFromName("MdnFailedReceipt", 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, "UTF-8", 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, "UTF-8", 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("MsgMdnDisplayed", firstPart2);
+ break;
+ case nsIMsgMdnGenerator::eDispatched:
+ rv = GetStringFromName("MsgMdnDispatched", firstPart2);
+ break;
+ case nsIMsgMdnGenerator::eProcessed:
+ rv = GetStringFromName("MsgMdnProcessed", firstPart2);
+ break;
+ case nsIMsgMdnGenerator::eDeleted:
+ rv = GetStringFromName("MsgMdnDeleted", firstPart2);
+ break;
+ case nsIMsgMdnGenerator::eDenied:
+ rv = GetStringFromName("MsgMdnDenied", firstPart2);
+ break;
+ case nsIMsgMdnGenerator::eFailed:
+ rv = GetStringFromName("MsgMdnFailed", 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) {
+ bool sendUserAgent = false;
+ nsCOMPtr<nsIPrefBranch> prefBranch(
+ do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (NS_SUCCEEDED(rv) && prefBranch) {
+ prefBranch->GetBoolPref("mailnews.headers.sendUserAgent", &sendUserAgent);
+ }
+
+ if (sendUserAgent) {
+ bool useMinimalUserAgent = false;
+ if (prefBranch) {
+ prefBranch->GetBoolPref("mailnews.headers.useMinimalUserAgent",
+ &useMinimalUserAgent);
+ }
+ if (useMinimalUserAgent) {
+ nsCOMPtr<nsIStringBundleService> bundleService =
+ mozilla::components::StringBundle::Service();
+ if (bundleService) {
+ nsCOMPtr<nsIStringBundle> brandBundle;
+ rv = bundleService->CreateBundle(
+ "chrome://branding/locale/brand.properties",
+ getter_AddRefs(brandBundle));
+ if (NS_SUCCEEDED(rv)) {
+ nsString brandName;
+ brandBundle->GetStringFromName("brandFullName", brandName);
+ if (!brandName.IsEmpty()) {
+ NS_ConvertUTF16toUTF8 ua8(brandName);
+ tmpBuffer = PR_smprintf("Reporting-UA: %s" CRLF, ua8.get());
+ PUSH_N_FREE_STRING(tmpBuffer);
+ }
+ }
+ }
+ } else {
+ nsAutoCString userAgentString;
+ // Ignore error since we're testing the return value.
+ mozilla::Unused << 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.InsertLiteral("; ", 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("@mozilla.org/messengercompose/computils;1", &rv);
+ if (compUtils) compUtils->GetMsgMimeConformToStandard(&conformToStandard);
+
+ convbuf = nsMsgI18NEncodeMimePartIIStr(m_email.get(), true, "UTF-8", 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);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = WriteString(CRLF);
+ NS_ENSURE_SUCCESS(rv, rv);
+ 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("@mozilla.org/messengercompose/smtp;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIURI> aUri;
+ nsCOMPtr<nsIRequest> aRequest;
+ nsCString identEmail;
+ m_identity->GetEmail(identEmail);
+ smtpService->SendMailMessage(m_file, m_dntRrt.get(), m_identity,
+ identEmail.get(), EmptyString(), this, nullptr,
+ nullptr, false, ""_ns, getter_AddRefs(aUri),
+ 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("@mozilla.org/messenger/account-manager;1", &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);
+ nsTArray<RefPtr<nsIMsgIdentity>> servIdentities;
+ accountManager->GetIdentitiesForServer(m_server, servIdentities);
+
+ // First check in the "To:" header
+ for (auto ident : servIdentities) {
+ nsCString identEmail;
+ ident->GetEmail(identEmail);
+ if (!mailTo.IsEmpty() && !identEmail.IsEmpty() &&
+ FindInReadable(identEmail, mailTo,
+ nsCaseInsensitiveCStringComparator)) {
+ m_identity = ident;
+ break;
+ }
+ }
+ // If no match, check the "Cc:" header
+ if (!m_identity) {
+ for (auto ident : servIdentities) {
+ nsCString identEmail;
+ ident->GetEmail(identEmail);
+ if (!mailCC.IsEmpty() && !identEmail.IsEmpty() &&
+ FindInReadable(identEmail, mailCC,
+ nsCaseInsensitiveCStringComparator)) {
+ m_identity = ident;
+ break;
+ }
+ }
+ }
+
+ // If still no match, 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);
+ }
+ }
+ }
+ }
+
+ 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 char* exitString;
+
+ switch (aExitCode) {
+ case NS_ERROR_UNKNOWN_HOST:
+ case NS_ERROR_UNKNOWN_PROXY_HOST:
+ exitString = "smtpSendFailedUnknownServer";
+ break;
+ case NS_ERROR_CONNECTION_REFUSED:
+ case NS_ERROR_PROXY_CONNECTION_REFUSED:
+ exitString = "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 = "smtpSendInterrupted";
+ break;
+ case NS_ERROR_NET_TIMEOUT:
+ case NS_ERROR_NET_RESET:
+ exitString = "smtpSendTimeout";
+ break;
+ default:
+ exitString = errorStringNameForErrorCode(aExitCode);
+ break;
+ }
+
+ nsCOMPtr<nsISmtpService> smtpService(
+ do_GetService("@mozilla.org/messengercompose/smtp;1", &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);
+
+ AutoTArray<nsString, 1> params;
+ CopyASCIItoUTF16(smtpHostName, *params.AppendElement());
+
+ nsCOMPtr<nsIStringBundle> bundle;
+ nsCOMPtr<nsIStringBundleService> bundleService =
+ mozilla::components::StringBundle::Service();
+ 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, failed_msg);
+ bundle->GetStringFromName("sendMessageErrorTitle", dialogTitle);
+
+ nsCOMPtr<mozIDOMWindowProxy> domWindow;
+ m_window->GetDomWindow(getter_AddRefs(domWindow));
+
+ nsCOMPtr<nsIPromptService> dlgService(
+ do_GetService(NS_PROMPTSERVICE_CONTRACTID, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ dlgService->Alert(domWindow, dialogTitle.get(), failed_msg.get());
+
+ return NS_OK;
+}
diff --git a/comm/mailnews/extensions/mdn/nsMsgMdnGenerator.h b/comm/mailnews/extensions/mdn/nsMsgMdnGenerator.h
new file mode 100644
index 0000000000..74eea8bcad
--- /dev/null
+++ b/comm/mailnews/extensions/mdn/nsMsgMdnGenerator.h
@@ -0,0 +1,86 @@
+/* -*- 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 "nsString.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 char* aName, nsAString& aResultString);
+ nsresult FormatStringFromName(const char* aName, const nsString& aString,
+ nsAString& 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_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_
diff --git a/comm/mailnews/extensions/mdn/test/unit/head_mdn.js b/comm/mailnews/extensions/mdn/test/unit/head_mdn.js
new file mode 100644
index 0000000000..0735341e30
--- /dev/null
+++ b/comm/mailnews/extensions/mdn/test/unit/head_mdn.js
@@ -0,0 +1,18 @@
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+var { mailTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/MailTestUtils.jsm"
+);
+var { localAccountUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/LocalAccountUtils.jsm"
+);
+
+var CC = Components.Constructor;
+
+// Ensure the profile directory is set up
+do_get_profile();
+
+registerCleanupFunction(function () {
+ load("../../../../../mailnews/resources/mailShutdown.js");
+});
diff --git a/comm/mailnews/extensions/mdn/test/unit/test_askuser.js b/comm/mailnews/extensions/mdn/test/unit/test_askuser.js
new file mode 100644
index 0000000000..b30ab49b0f
--- /dev/null
+++ b/comm/mailnews/extensions/mdn/test/unit/test_askuser.js
@@ -0,0 +1,67 @@
+localAccountUtils.loadLocalMailAccount();
+
+var localAccount = MailServices.accounts.FindAccountForServer(
+ localAccountUtils.incomingServer
+);
+var identity = MailServices.accounts.createIdentity();
+identity.email = "bob@t2.example.net";
+localAccount.addIdentity(identity);
+localAccount.defaultIdentity = identity;
+
+function run_test() {
+ var headers =
+ "from: alice@t1.example.com\r\n" +
+ "to: bob@t2.example.net\r\n" +
+ "return-path: alice@t1.example.com\r\n" +
+ "Disposition-Notification-To: alice@t1.example.com\r\n";
+
+ let mimeHdr = Cc["@mozilla.org/messenger/mimeheaders;1"].createInstance(
+ Ci.nsIMimeHeaders
+ );
+ mimeHdr.initialize(headers);
+ let receivedHeader = mimeHdr.extractHeader("To", false);
+ dump(receivedHeader + "\n");
+
+ localAccountUtils.inboxFolder.QueryInterface(Ci.nsIMsgLocalMailFolder);
+ localAccountUtils.inboxFolder.addMessage(
+ "From \r\n" + headers + "\r\nhello\r\n"
+ );
+ // Need to setup some prefs
+ Services.prefs.setBoolPref("mail.mdn.report.enabled", true);
+ Services.prefs.setIntPref("mail.mdn.report.not_in_to_cc", 2);
+ Services.prefs.setIntPref("mail.mdn.report.other", 2);
+ Services.prefs.setIntPref("mail.mdn.report.outside_domain", 2);
+
+ var msgFolder = localAccountUtils.inboxFolder;
+
+ var msgWindow = {};
+
+ var msgHdr = mailTestUtils.firstMsgHdr(localAccountUtils.inboxFolder);
+
+ // Everything looks good so far, let's generate the MDN response.
+ var mdnGenerator = Cc[
+ "@mozilla.org/messenger-mdn/generator;1"
+ ].createInstance(Ci.nsIMsgMdnGenerator);
+
+ Services.prefs.setIntPref("mail.mdn.report.outside_domain", 1);
+ var askUser = mdnGenerator.process(
+ Ci.nsIMsgMdnGenerator.eDisplayed,
+ msgWindow,
+ msgFolder,
+ msgHdr.messageKey,
+ mimeHdr,
+ false
+ );
+ Assert.ok(!askUser);
+
+ Services.prefs.setIntPref("mail.mdn.report.outside_domain", 2);
+ askUser = mdnGenerator.process(
+ Ci.nsIMsgMdnGenerator.eDisplayed,
+ msgWindow,
+ msgFolder,
+ msgHdr.messageKey,
+ mimeHdr,
+ false
+ );
+ Assert.ok(askUser);
+}
diff --git a/comm/mailnews/extensions/mdn/test/unit/test_mdnFlags.js b/comm/mailnews/extensions/mdn/test/unit/test_mdnFlags.js
new file mode 100644
index 0000000000..4d6094e89d
--- /dev/null
+++ b/comm/mailnews/extensions/mdn/test/unit/test_mdnFlags.js
@@ -0,0 +1,60 @@
+/**
+ * This tests that setting mdn flags works correctly, so that we don't
+ * reprompt when the user re-selects a message.
+ */
+
+localAccountUtils.loadLocalMailAccount();
+
+var localAccount = MailServices.accounts.FindAccountForServer(
+ localAccountUtils.incomingServer
+);
+var identity = MailServices.accounts.createIdentity();
+identity.email = "bob@t2.example.net";
+localAccount.addIdentity(identity);
+localAccount.defaultIdentity = identity;
+
+function run_test() {
+ var headers =
+ "from: alice@t1.example.com\r\n" +
+ "to: bob@t2.example.net\r\n" +
+ "return-path: alice@t1.example.com\r\n" +
+ "Disposition-Notification-To: alice@t1.example.com\r\n";
+
+ let mimeHdr = Cc["@mozilla.org/messenger/mimeheaders;1"].createInstance(
+ Ci.nsIMimeHeaders
+ );
+ mimeHdr.initialize(headers);
+ mimeHdr.extractHeader("To", false);
+
+ localAccountUtils.inboxFolder.QueryInterface(Ci.nsIMsgLocalMailFolder);
+ localAccountUtils.inboxFolder.addMessage(
+ "From \r\n" + headers + "\r\nhello\r\n"
+ );
+ // Need to setup some prefs
+ Services.prefs.setBoolPref("mail.mdn.report.enabled", true);
+ Services.prefs.setIntPref("mail.mdn.report.not_in_to_cc", 2);
+ Services.prefs.setIntPref("mail.mdn.report.other", 2);
+ Services.prefs.setIntPref("mail.mdn.report.outside_domain", 2);
+
+ var msgFolder = localAccountUtils.inboxFolder;
+
+ var msgWindow = {};
+
+ var msgHdr = mailTestUtils.firstMsgHdr(localAccountUtils.inboxFolder);
+
+ // Everything looks good so far, let's generate the MDN response.
+ var mdnGenerator = Cc[
+ "@mozilla.org/messenger-mdn/generator;1"
+ ].createInstance(Ci.nsIMsgMdnGenerator);
+ mdnGenerator.process(
+ Ci.nsIMsgMdnGenerator.eDisplayed,
+ msgWindow,
+ msgFolder,
+ msgHdr.messageKey,
+ mimeHdr,
+ false
+ );
+ mdnGenerator.userDeclined();
+ Assert.notEqual(msgHdr.flags & Ci.nsMsgMessageFlags.MDNReportSent, 0);
+ Assert.equal(msgHdr.flags & Ci.nsMsgMessageFlags.MDNReportNeeded, 0);
+}
diff --git a/comm/mailnews/extensions/mdn/test/unit/xpcshell.ini b/comm/mailnews/extensions/mdn/test/unit/xpcshell.ini
new file mode 100644
index 0000000000..243145b676
--- /dev/null
+++ b/comm/mailnews/extensions/mdn/test/unit/xpcshell.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+head = head_mdn.js
+tail =
+
+[test_askuser.js]
+[test_mdnFlags.js]