summaryrefslogtreecommitdiffstats
path: root/comm/mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js')
-rw-r--r--comm/mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js3034
1 files changed, 3034 insertions, 0 deletions
diff --git a/comm/mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js b/comm/mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js
new file mode 100644
index 0000000000..db973f0ee9
--- /dev/null
+++ b/comm/mail/extensions/openpgp/content/ui/enigmailMsgComposeOverlay.js
@@ -0,0 +1,3034 @@
+/*
+ * 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 https://mozilla.org/MPL/2.0/.
+ */
+
+"use strict";
+
+/* import-globals-from ../../../../components/compose/content/MsgComposeCommands.js */
+/* import-globals-from ../../../../components/compose/content/addressingWidgetOverlay.js */
+/* global MsgAccountManager */
+/* global gCurrentIdentity */
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+var EnigmailCore = ChromeUtils.import(
+ "chrome://openpgp/content/modules/core.jsm"
+).EnigmailCore;
+var EnigmailFuncs = ChromeUtils.import(
+ "chrome://openpgp/content/modules/funcs.jsm"
+).EnigmailFuncs;
+var { EnigmailLog } = ChromeUtils.import(
+ "chrome://openpgp/content/modules/log.jsm"
+);
+var EnigmailArmor = ChromeUtils.import(
+ "chrome://openpgp/content/modules/armor.jsm"
+).EnigmailArmor;
+var EnigmailData = ChromeUtils.import(
+ "chrome://openpgp/content/modules/data.jsm"
+).EnigmailData;
+var EnigmailDialog = ChromeUtils.import(
+ "chrome://openpgp/content/modules/dialog.jsm"
+).EnigmailDialog;
+var EnigmailWindows = ChromeUtils.import(
+ "chrome://openpgp/content/modules/windows.jsm"
+).EnigmailWindows;
+var EnigmailKeyRing = ChromeUtils.import(
+ "chrome://openpgp/content/modules/keyRing.jsm"
+).EnigmailKeyRing;
+var EnigmailURIs = ChromeUtils.import(
+ "chrome://openpgp/content/modules/uris.jsm"
+).EnigmailURIs;
+var EnigmailConstants = ChromeUtils.import(
+ "chrome://openpgp/content/modules/constants.jsm"
+).EnigmailConstants;
+var EnigmailDecryption = ChromeUtils.import(
+ "chrome://openpgp/content/modules/decryption.jsm"
+).EnigmailDecryption;
+var EnigmailEncryption = ChromeUtils.import(
+ "chrome://openpgp/content/modules/encryption.jsm"
+).EnigmailEncryption;
+var EnigmailWkdLookup = ChromeUtils.import(
+ "chrome://openpgp/content/modules/wkdLookup.jsm"
+).EnigmailWkdLookup;
+var EnigmailMime = ChromeUtils.import(
+ "chrome://openpgp/content/modules/mime.jsm"
+).EnigmailMime;
+var EnigmailMsgRead = ChromeUtils.import(
+ "chrome://openpgp/content/modules/msgRead.jsm"
+).EnigmailMsgRead;
+var EnigmailMimeEncrypt = ChromeUtils.import(
+ "chrome://openpgp/content/modules/mimeEncrypt.jsm"
+).EnigmailMimeEncrypt;
+const { EnigmailCryptoAPI } = ChromeUtils.import(
+ "chrome://openpgp/content/modules/cryptoAPI.jsm"
+);
+const { OpenPGPAlias } = ChromeUtils.import(
+ "chrome://openpgp/content/modules/OpenPGPAlias.jsm"
+);
+var { jsmime } = ChromeUtils.import("resource:///modules/jsmime.jsm");
+
+var l10nOpenPGP = new Localization(["messenger/openpgp/openpgp.ftl"]);
+
+// Account encryption policy values:
+// const kEncryptionPolicy_Never = 0;
+// 'IfPossible' was used by ns4.
+// const kEncryptionPolicy_IfPossible = 1;
+var kEncryptionPolicy_Always = 2;
+
+var Enigmail = {};
+
+const IOSERVICE_CONTRACTID = "@mozilla.org/network/io-service;1";
+const LOCAL_FILE_CONTRACTID = "@mozilla.org/file/local;1";
+
+Enigmail.msg = {
+ editor: null,
+ dirty: 0,
+ // dirty means: composer contents were modified by this code, right?
+ processed: null, // contains information for undo of inline signed/encrypt
+ timeoutId: null, // TODO: once set, it's never reset
+ sendPgpMime: true,
+ //sendMode: null, // the current default for sending a message (0, SIGN, ENCRYPT, or SIGN|ENCRYPT)
+ //sendModeDirty: false, // send mode or final send options changed?
+
+ // processed strings to signal final encrypt/sign/pgpmime state:
+ statusEncryptedStr: "???",
+ statusSignedStr: "???",
+ //statusPGPMimeStr: "???",
+ //statusSMimeStr: "???",
+ //statusInlinePGPStr: "???",
+ statusAttachOwnKey: "???",
+
+ sendProcess: false,
+ composeBodyReady: false,
+ modifiedAttach: null,
+ lastFocusedWindow: null,
+ draftSubjectEncrypted: false,
+ attachOwnKeyObj: {
+ attachedObj: null,
+ attachedKey: null,
+ },
+
+ keyLookupDone: [],
+
+ addrOnChangeTimeout: 250,
+ /* timeout when entering something into the address field */
+
+ async composeStartup() {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.composeStartup\n"
+ );
+
+ if (!gMsgCompose || !gMsgCompose.compFields) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: no gMsgCompose, leaving\n"
+ );
+ return;
+ }
+
+ gMsgCompose.RegisterStateListener(Enigmail.composeStateListener);
+ Enigmail.msg.composeBodyReady = false;
+
+ // Listen to message sending event
+ addEventListener(
+ "compose-send-message",
+ Enigmail.msg.sendMessageListener.bind(Enigmail.msg),
+ true
+ );
+
+ await OpenPGPAlias.load().catch(console.error);
+
+ Enigmail.msg.composeOpen();
+ //Enigmail.msg.processFinalState();
+ },
+
+ // TODO: call this from global compose when options change
+ enigmailComposeProcessFinalState() {
+ //Enigmail.msg.processFinalState();
+ },
+
+ /*
+ handleClick: function(event, modifyType) {
+ EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.handleClick\n");
+ switch (event.button) {
+ case 2:
+ // do not process the event any further
+ // needed on Windows to prevent displaying the context menu
+ event.preventDefault();
+ this.doPgpButton();
+ break;
+ case 0:
+ this.doPgpButton(modifyType);
+ break;
+ }
+ },
+ */
+
+ /* return whether the account specific setting key is enabled or disabled
+ */
+ /*
+ getAccDefault: function(key) {
+ //EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.getAccDefault: identity="+this.identity.key+"("+this.identity.email+") key="+key+"\n");
+ let res = null;
+ let mimePreferOpenPGP = this.identity.getIntAttribute("mimePreferOpenPGP");
+ let isSmimeEnabled = Enigmail.msg.isSmimeEnabled();
+ let wasEnigmailEnabledForIdentity = Enigmail.msg.wasEnigmailEnabledForIdentity();
+ let preferSmimeByDefault = false;
+
+ if (isSmimeEnabled && wasEnigmailEnabledForIdentity) {
+ }
+
+ if (wasEnigmailEnabledForIdentity) {
+ switch (key) {
+ case 'sign':
+ if (preferSmimeByDefault) {
+ res = (this.identity.signMail);
+ }
+ else {
+ res = (this.identity.getIntAttribute("defaultSigningPolicy") > 0);
+ }
+ break;
+ case 'encrypt':
+ if (preferSmimeByDefault) {
+ res = (this.identity.encryptionPolicy > 0);
+ }
+ else {
+ res = (this.identity.getIntAttribute("defaultEncryptionPolicy") > 0);
+ }
+ break;
+ case 'sign-pgp':
+ res = (this.identity.getIntAttribute("defaultSigningPolicy") > 0);
+ break;
+ case 'pgpMimeMode':
+ res = this.identity.getBoolAttribute(key);
+ break;
+ case 'attachPgpKey':
+ res = this.identity.attachPgpKey;
+ break;
+ }
+ //EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.getAccDefault: "+key+"="+res+"\n");
+ return res;
+ }
+ else if (Enigmail.msg.isSmimeEnabled()) {
+ switch (key) {
+ case 'sign':
+ res = this.identity.signMail;
+ break;
+ case 'encrypt':
+ res = (this.identity.encryptionPolicy > 0);
+ break;
+ default:
+ res = false;
+ }
+ return res;
+ }
+ else {
+ // every detail is disabled if OpenPGP in general is disabled:
+ switch (key) {
+ case 'sign':
+ case 'encrypt':
+ case 'pgpMimeMode':
+ case 'attachPgpKey':
+ case 'sign-pgp':
+ return false;
+ }
+ }
+
+ // should not be reached
+ EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.getAccDefault: internal error: invalid key '" + key + "'\n");
+ return null;
+ },
+ */
+
+ /**
+ * Determine if any of Enigmail (OpenPGP) or S/MIME encryption is enabled for the account
+ */
+ /*
+ isAnyEncryptionEnabled: function() {
+ let id = getCurrentIdentity();
+
+ return ((id.getUnicharAttribute("encryption_cert_name") !== "") ||
+ Enigmail.msg.wasEnigmailEnabledForIdentity());
+ },
+ */
+
+ isSmimeEnabled() {
+ return (
+ gCurrentIdentity.getUnicharAttribute("signing_cert_name") !== "" ||
+ gCurrentIdentity.getUnicharAttribute("encryption_cert_name") !== ""
+ );
+ },
+
+ /**
+ * Determine if any of Enigmail (OpenPGP) or S/MIME signing is enabled for the account
+ */
+ /*
+ getSigningEnabled: function() {
+ let id = getCurrentIdentity();
+
+ return ((id.getUnicharAttribute("signing_cert_name") !== "") ||
+ Enigmail.msg.wasEnigmailEnabledForIdentity());
+ },
+ */
+
+ /*
+ getSmimeSigningEnabled: function() {
+ let id = getCurrentIdentity();
+
+ if (!id.getUnicharAttribute("signing_cert_name")) return false;
+
+ return id.signMail;
+ },
+ */
+
+ /*
+ // set the current default for sending a message
+ // depending on the identity
+ processAccountSpecificDefaultOptions: function() {
+ EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.processAccountSpecificDefaultOptions\n");
+
+ const SIGN = EnigmailConstants.SEND_SIGNED;
+ const ENCRYPT = EnigmailConstants.SEND_ENCRYPTED;
+
+ this.sendMode = 0;
+
+ if (this.getSmimeSigningEnabled()) {
+ this.sendMode |= SIGN;
+ }
+
+ if (!Enigmail.msg.wasEnigmailEnabledForIdentity()) {
+ return;
+ }
+
+ if (this.getAccDefault("encrypt")) {
+ this.sendMode |= ENCRYPT;
+ }
+ if (this.getAccDefault("sign")) {
+ this.sendMode |= SIGN;
+ }
+
+ //this.sendPgpMime = this.getAccDefault("pgpMimeMode");
+ //console.debug("processAccountSpecificDefaultOptions sendPgpMime: " + this.sendPgpMime);
+ gAttachMyPublicPGPKey = this.getAccDefault("attachPgpKey");
+ this.setOwnKeyStatus();
+ this.attachOwnKeyObj.attachedObj = null;
+ this.attachOwnKeyObj.attachedKey = null;
+
+ //this.finalSignDependsOnEncrypt = (this.getAccDefault("signIfEnc") || this.getAccDefault("signIfNotEnc"));
+ },
+ */
+
+ getOriginalMsgUri() {
+ let draftId = gMsgCompose.compFields.draftId;
+ let msgUri = null;
+
+ if (draftId) {
+ // original message is draft
+ msgUri = draftId.replace(/\?.*$/, "");
+ } else if (gMsgCompose.originalMsgURI) {
+ // original message is a "true" mail
+ msgUri = gMsgCompose.originalMsgURI;
+ }
+
+ return msgUri;
+ },
+
+ getMsgHdr(msgUri) {
+ try {
+ if (!msgUri) {
+ msgUri = this.getOriginalMsgUri();
+ }
+ if (msgUri) {
+ return gMessenger.msgHdrFromURI(msgUri);
+ }
+ } catch (ex) {
+ // See also bug 1635648
+ console.debug("exception in getMsgHdr: " + ex);
+ EnigmailLog.DEBUG(
+ "enigmailMessengerOverlay.js: exception in getMsgHdr: " + ex + "\n"
+ );
+ }
+ return null;
+ },
+
+ getMsgProperties(draft, msgUri, msgHdr, mimeMsg, obtainedDraftFlagsObj) {
+ EnigmailLog.DEBUG(
+ "enigmailMessengerOverlay.js: Enigmail.msg.getMsgProperties:\n"
+ );
+ obtainedDraftFlagsObj.value = false;
+
+ let self = this;
+ let properties = 0;
+ try {
+ if (msgHdr) {
+ properties = msgHdr.getUint32Property("enigmail");
+
+ if (draft) {
+ if (self.getSavedDraftOptions(mimeMsg)) {
+ obtainedDraftFlagsObj.value = true;
+ }
+ updateEncryptionDependencies();
+ }
+ }
+ } catch (ex) {
+ EnigmailLog.DEBUG(
+ "enigmailMessengerOverlay.js: Enigmail.msg.getMsgProperties: got exception '" +
+ ex.toString() +
+ "'\n"
+ );
+ }
+
+ if (EnigmailURIs.isEncryptedUri(msgUri)) {
+ properties |= EnigmailConstants.DECRYPTION_OKAY;
+ }
+
+ return properties;
+ },
+
+ getSavedDraftOptions(mimeMsg) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.getSavedDraftOptions\n"
+ );
+ if (!mimeMsg || !mimeMsg.headers.has("x-enigmail-draft-status")) {
+ return false;
+ }
+
+ let stat = mimeMsg.headers.get("x-enigmail-draft-status").join("");
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.getSavedDraftOptions: draftStatus: " +
+ stat +
+ "\n"
+ );
+
+ if (stat.substr(0, 1) == "N") {
+ switch (Number(stat.substr(1, 1))) {
+ case 2:
+ // treat as "user decision to enable encryption, disable auto"
+ gUserTouchedSendEncrypted = true;
+ gSendEncrypted = true;
+ updateEncryptionDependencies();
+ break;
+ case 0:
+ // treat as "user decision to disable encryption, disable auto"
+ gUserTouchedSendEncrypted = true;
+ gSendEncrypted = false;
+ updateEncryptionDependencies();
+ break;
+ case 1:
+ default:
+ // treat as "no user decision, automatic mode"
+ break;
+ }
+
+ switch (Number(stat.substr(2, 1))) {
+ case 2:
+ gSendSigned = true;
+ gUserTouchedSendSigned = true;
+ break;
+ case 0:
+ gUserTouchedSendSigned = true;
+ gSendSigned = false;
+ break;
+ case 1:
+ default:
+ // treat as "no user decision, automatic mode, based on encryption or other prefs"
+ break;
+ }
+
+ switch (Number(stat.substr(3, 1))) {
+ case 1:
+ break;
+ case EnigmailConstants.ENIG_FORCE_SMIME:
+ // 3
+ gSelectedTechnologyIsPGP = false;
+ break;
+ case 2: // pgp/mime
+ case 0: // inline
+ default:
+ gSelectedTechnologyIsPGP = true;
+ break;
+ }
+
+ switch (Number(stat.substr(4, 1))) {
+ case 1:
+ gUserTouchedAttachMyPubKey = true;
+ gAttachMyPublicPGPKey = true;
+ break;
+ case 2:
+ gUserTouchedAttachMyPubKey = false;
+ break;
+ case 0:
+ default:
+ gUserTouchedAttachMyPubKey = true;
+ gAttachMyPublicPGPKey = false;
+ break;
+ }
+
+ switch (Number(stat.substr(4, 1))) {
+ case 1:
+ gUserTouchedAttachMyPubKey = true;
+ gAttachMyPublicPGPKey = true;
+ break;
+ case 2:
+ gUserTouchedAttachMyPubKey = false;
+ break;
+ case 0:
+ default:
+ gUserTouchedAttachMyPubKey = true;
+ gAttachMyPublicPGPKey = false;
+ break;
+ }
+
+ switch (Number(stat.substr(5, 1))) {
+ case 1:
+ gUserTouchedEncryptSubject = true;
+ gEncryptSubject = true;
+ break;
+ case 2:
+ gUserTouchedEncryptSubject = false;
+ break;
+ case 0:
+ default:
+ gUserTouchedEncryptSubject = true;
+ gEncryptSubject = false;
+ break;
+ }
+ }
+ //Enigmail.msg.setOwnKeyStatus();
+ return true;
+ },
+
+ composeOpen() {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.composeOpen\n"
+ );
+
+ let msgUri = null;
+ let msgHdr = null;
+
+ msgUri = this.getOriginalMsgUri();
+ if (msgUri) {
+ msgHdr = this.getMsgHdr(msgUri);
+ if (msgHdr) {
+ try {
+ let msgUrl = EnigmailMsgRead.getUrlFromUriSpec(msgUri);
+ EnigmailMime.getMimeTreeFromUrl(msgUrl.spec, false, mimeMsg => {
+ Enigmail.msg.continueComposeOpenWithMimeTree(
+ msgUri,
+ msgHdr,
+ mimeMsg
+ );
+ });
+ } catch (ex) {
+ EnigmailLog.DEBUG(
+ "enigmailMessengerOverlay.js: composeOpen: exception in getMimeTreeFromUrl: " +
+ ex +
+ "\n"
+ );
+ this.continueComposeOpenWithMimeTree(msgUri, msgHdr, null);
+ }
+ } else {
+ this.continueComposeOpenWithMimeTree(msgUri, msgHdr, null);
+ }
+ } else {
+ this.continueComposeOpenWithMimeTree(msgUri, msgHdr, null);
+ }
+ },
+
+ continueComposeOpenWithMimeTree(msgUri, msgHdr, mimeMsg) {
+ let selectedElement = document.activeElement;
+
+ let msgIsDraft =
+ gMsgCompose.type === Ci.nsIMsgCompType.Draft ||
+ gMsgCompose.type === Ci.nsIMsgCompType.Template;
+
+ if (!gSendEncrypted || msgIsDraft) {
+ let useEncryptionUnlessWeHaveDraftInfo = false;
+ let usePGPUnlessWeKnowOtherwise = false;
+ let useSMIMEUnlessWeKnowOtherwise = false;
+
+ if (msgIsDraft) {
+ let globalSaysItsEncrypted =
+ gEncryptedURIService &&
+ gMsgCompose.originalMsgURI &&
+ gEncryptedURIService.isEncrypted(gMsgCompose.originalMsgURI);
+
+ if (globalSaysItsEncrypted) {
+ useEncryptionUnlessWeHaveDraftInfo = true;
+ useSMIMEUnlessWeKnowOtherwise = true;
+ }
+ }
+
+ let obtainedDraftFlagsObj = { value: false };
+ if (msgUri) {
+ let msgFlags = this.getMsgProperties(
+ msgIsDraft,
+ msgUri,
+ msgHdr,
+ mimeMsg,
+ obtainedDraftFlagsObj
+ );
+ if (msgFlags & EnigmailConstants.DECRYPTION_OKAY) {
+ usePGPUnlessWeKnowOtherwise = true;
+ useSMIMEUnlessWeKnowOtherwise = false;
+ }
+ if (msgIsDraft && obtainedDraftFlagsObj.value) {
+ useEncryptionUnlessWeHaveDraftInfo = false;
+ usePGPUnlessWeKnowOtherwise = false;
+ useSMIMEUnlessWeKnowOtherwise = false;
+ }
+ if (!msgIsDraft) {
+ if (msgFlags & EnigmailConstants.DECRYPTION_OKAY) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.composeOpen: has encrypted originalMsgUri\n"
+ );
+ EnigmailLog.DEBUG(
+ "originalMsgURI=" + gMsgCompose.originalMsgURI + "\n"
+ );
+ gSendEncrypted = true;
+ updateEncryptionDependencies();
+ gSelectedTechnologyIsPGP = true;
+ useEncryptionUnlessWeHaveDraftInfo = false;
+ usePGPUnlessWeKnowOtherwise = false;
+ useSMIMEUnlessWeKnowOtherwise = false;
+ }
+ }
+ this.removeAttachedKey();
+ }
+
+ if (useEncryptionUnlessWeHaveDraftInfo) {
+ gSendEncrypted = true;
+ updateEncryptionDependencies();
+ }
+ if (gSendEncrypted && !obtainedDraftFlagsObj.value) {
+ gSendSigned = true;
+ }
+ if (usePGPUnlessWeKnowOtherwise) {
+ gSelectedTechnologyIsPGP = true;
+ } else if (useSMIMEUnlessWeKnowOtherwise) {
+ gSelectedTechnologyIsPGP = false;
+ }
+ }
+
+ // check for attached signature files and remove them
+ var bucketList = document.getElementById("attachmentBucket");
+ if (bucketList.hasChildNodes()) {
+ var node = bucketList.firstChild;
+ while (node) {
+ if (node.attachment.contentType == "application/pgp-signature") {
+ if (!this.findRelatedAttachment(bucketList, node)) {
+ // Let's release the attachment object held by the node else it won't go away until the window is destroyed
+ node.attachment = null;
+ node = bucketList.removeChild(node);
+ }
+ }
+ node = node.nextSibling;
+ }
+ }
+
+ // If we removed all the children and the bucket wasn't meant
+ // to stay open, close it.
+ if (!Services.prefs.getBoolPref("mail.compose.show_attachment_pane")) {
+ UpdateAttachmentBucket(bucketList.hasChildNodes());
+ }
+
+ this.warnUserIfSenderKeyExpired();
+
+ //this.processFinalState();
+ if (selectedElement) {
+ selectedElement.focus();
+ }
+ },
+
+ // check if an signature is related to another attachment
+ findRelatedAttachment(bucketList, node) {
+ // check if filename ends with .sig
+ if (node.attachment.name.search(/\.sig$/i) < 0) {
+ return null;
+ }
+
+ var relatedNode = bucketList.firstChild;
+ var findFile = node.attachment.name.toLowerCase();
+ var baseAttachment = null;
+ while (relatedNode) {
+ if (relatedNode.attachment.name.toLowerCase() + ".sig" == findFile) {
+ baseAttachment = relatedNode.attachment;
+ }
+ relatedNode = relatedNode.nextSibling;
+ }
+ return baseAttachment;
+ },
+
+ async attachOwnKey(id) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.attachOwnKey: " + id + "\n"
+ );
+
+ if (
+ this.attachOwnKeyObj.attachedKey &&
+ this.attachOwnKeyObj.attachedKey != id
+ ) {
+ // remove attached key if user ID changed
+ this.removeAttachedKey();
+ }
+ let revokedIDs = EnigmailKeyRing.findRevokedPersonalKeysByEmail(
+ gCurrentIdentity.email
+ );
+
+ if (!this.attachOwnKeyObj.attachedKey) {
+ let hex = "0x" + id;
+ var attachedObj = await this.extractAndAttachKey(
+ hex,
+ revokedIDs,
+ gCurrentIdentity.email,
+ true,
+ true // one key plus revocations
+ );
+ if (attachedObj) {
+ this.attachOwnKeyObj.attachedObj = attachedObj;
+ this.attachOwnKeyObj.attachedKey = hex;
+ }
+ }
+ },
+
+ async extractAndAttachKey(
+ primaryId,
+ revokedIds,
+ emailForFilename,
+ warnOnError
+ ) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.extractAndAttachKey: \n"
+ );
+ var enigmailSvc = EnigmailCore.getService(window);
+ if (!enigmailSvc) {
+ return null;
+ }
+
+ var tmpFile = Services.dirsvc.get("TmpD", Ci.nsIFile);
+ tmpFile.append("key.asc");
+ tmpFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
+
+ // save file
+ var exitCodeObj = {};
+ var errorMsgObj = {};
+
+ await EnigmailKeyRing.extractPublicKeys(
+ [], // full
+ [primaryId], // reduced
+ revokedIds, // minimal
+ tmpFile,
+ exitCodeObj,
+ errorMsgObj
+ );
+ if (exitCodeObj.value !== 0) {
+ if (warnOnError) {
+ EnigmailDialog.alert(window, errorMsgObj.value);
+ }
+ return null;
+ }
+
+ // create attachment
+ var tmpFileURI = Services.io.newFileURI(tmpFile);
+ var keyAttachment = Cc[
+ "@mozilla.org/messengercompose/attachment;1"
+ ].createInstance(Ci.nsIMsgAttachment);
+ keyAttachment.url = tmpFileURI.spec;
+ keyAttachment.name = primaryId.substr(-16, 16);
+ if (keyAttachment.name.search(/^0x/) < 0) {
+ keyAttachment.name = "0x" + keyAttachment.name;
+ }
+ let withRevSuffix = "";
+ if (revokedIds && revokedIds.length) {
+ withRevSuffix = "_and_old_rev";
+ }
+ keyAttachment.name =
+ "OpenPGP_" + keyAttachment.name + withRevSuffix + ".asc";
+ keyAttachment.temporary = true;
+ keyAttachment.contentType = "application/pgp-keys";
+ keyAttachment.size = tmpFile.fileSize;
+
+ if (
+ !gAttachmentBucket.itemChildren.find(
+ item => item.attachment.name == keyAttachment.name
+ )
+ ) {
+ await this.addAttachment(keyAttachment);
+ }
+
+ gContentChanged = true;
+ return keyAttachment;
+ },
+
+ addAttachment(attachment) {
+ return AddAttachments([attachment]);
+ },
+
+ removeAttachedKey() {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.removeAttachedKey: \n"
+ );
+
+ let bucketList = document.getElementById("attachmentBucket");
+ let node = bucketList.firstElementChild;
+
+ if (bucketList.itemCount && this.attachOwnKeyObj.attachedObj) {
+ // Undo attaching own key.
+ while (node) {
+ if (node.attachment.url == this.attachOwnKeyObj.attachedObj.url) {
+ node = bucketList.removeChild(node);
+ // Let's release the attachment object held by the node else it won't
+ // go away until the window is destroyed.
+ node.attachment = null;
+ this.attachOwnKeyObj.attachedObj = null;
+ this.attachOwnKeyObj.attachedKey = null;
+ node = null; // exit loop.
+ } else {
+ node = node.nextSibling;
+ }
+ }
+
+ // Update the visibility of the attachment pane.
+ UpdateAttachmentBucket(bucketList.itemCount);
+ }
+ },
+
+ getSecurityParams(compFields = null) {
+ if (!compFields) {
+ if (!gMsgCompose) {
+ return null;
+ }
+
+ compFields = gMsgCompose.compFields;
+ }
+
+ return compFields.composeSecure;
+ },
+
+ setSecurityParams(newSecurityParams) {
+ if (!gMsgCompose || !gMsgCompose.compFields) {
+ return;
+ }
+ gMsgCompose.compFields.composeSecure = newSecurityParams;
+ },
+
+ // Used on send failure, to reset the pre-send modifications
+ resetUpdatedFields() {
+ this.removeAttachedKey();
+
+ // reset subject
+ let p = Enigmail.msg.getSecurityParams();
+ if (p && EnigmailMimeEncrypt.isEnigmailCompField(p)) {
+ let si = p.wrappedJSObject;
+ if (si.originalSubject) {
+ gMsgCompose.compFields.subject = si.originalSubject;
+ }
+ }
+ },
+
+ replaceEditorText(text) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.replaceEditorText:\n"
+ );
+
+ this.editorSelectAll();
+ // Overwrite text in clipboard for security
+ // (Otherwise plaintext will be available in the clipbaord)
+
+ if (this.editor.textLength > 0) {
+ this.editorInsertText("Enigmail");
+ } else {
+ this.editorInsertText(" ");
+ }
+
+ this.editorSelectAll();
+ this.editorInsertText(text);
+ },
+
+ /**
+ * Determine if Enigmail is enabled for the account
+ */
+
+ isEnigmailEnabledForIdentity() {
+ return !!gCurrentIdentity.getUnicharAttribute("openpgp_key_id");
+ },
+
+ /**
+ * Determine if Autocrypt is enabled for the account
+ */
+ isAutocryptEnabled() {
+ return false;
+ /*
+ if (Enigmail.msg.wasEnigmailEnabledForIdentity()) {
+ let srv = this.getCurrentIncomingServer();
+ return (srv ? srv.getBoolValue("enableAutocrypt") : false);
+ }
+
+ return false;
+ */
+ },
+
+ /*
+ doPgpButton: function(what) {
+ EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.doPgpButton: what=" + what + "\n");
+
+ if (Enigmail.msg.wasEnigmailEnabledForIdentity()) {
+ EnigmailCore.getService(window); // try to access Enigmail to launch the wizard if needed
+ }
+
+ // ignore settings for this account?
+ try {
+ if (!this.isAnyEncryptionEnabled() && !this.getSigningEnabled()) {
+ return;
+ }
+ }
+ catch (ex) {}
+
+ switch (what) {
+ case 'sign':
+ case 'encrypt':
+ this.setSendMode(what);
+ break;
+
+ case 'trustKeys':
+ this.tempTrustAllKeys();
+ break;
+
+ case 'nothing':
+ break;
+
+ case 'displaySecuritySettings':
+ this.displaySecuritySettings();
+ break;
+ default:
+ this.displaySecuritySettings();
+ }
+
+ },
+ */
+
+ // changes the DEFAULT sendMode
+ // - also called internally for saved emails
+ /*
+ setSendMode: function(sendMode) {
+ EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.setSendMode: sendMode=" + sendMode + "\n");
+ const SIGN = EnigmailConstants.SEND_SIGNED;
+ const ENCRYPT = EnigmailConstants.SEND_ENCRYPTED;
+
+ var origSendMode = this.sendMode;
+ switch (sendMode) {
+ case 'sign':
+ this.sendMode |= SIGN;
+ break;
+ case 'encrypt':
+ this.sendMode |= ENCRYPT;
+ break;
+ default:
+ EnigmailDialog.alert(window, "Enigmail.msg.setSendMode - unexpected value: " + sendMode);
+ break;
+ }
+ // sendMode changed ?
+ // - sign and send are internal initializations
+ if (!this.sendModeDirty && (this.sendMode != origSendMode) && sendMode != 'sign' && sendMode != 'encrypt') {
+ this.sendModeDirty = true;
+ }
+ this.processFinalState();
+ },
+ */
+
+ /**
+ key function to process the final encrypt/sign/pgpmime state from all settings
+ *
+ @param sendFlags: contains the sendFlags if the message is really processed. Optional, can be null
+ - uses as INPUT:
+ - this.sendMode
+ - this.encryptForced, this.encryptSigned
+ - uses as OUTPUT:
+ - this.statusEncrypt, this.statusSign
+
+ no return value
+ */
+ processFinalState(sendFlags) {},
+
+ /* check if encryption is possible (have keys for everyone or not)
+ */
+ async determineSendFlags() {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.focusChange: Enigmail.msg.determineSendFlags\n"
+ );
+
+ let detailsObj = {};
+ var compFields = gMsgCompose.compFields;
+
+ if (!Enigmail.msg.composeBodyReady) {
+ compFields = Cc[
+ "@mozilla.org/messengercompose/composefields;1"
+ ].createInstance(Ci.nsIMsgCompFields);
+ }
+ Recipients2CompFields(compFields);
+
+ // disabled, see bug 1625135
+ // gMsgCompose.expandMailingLists();
+
+ if (Enigmail.msg.isEnigmailEnabledForIdentity()) {
+ var toAddrList = [];
+ var arrLen = {};
+ var recList;
+ if (compFields.to) {
+ recList = compFields.splitRecipients(compFields.to, true, arrLen);
+ this.addRecipients(toAddrList, recList);
+ }
+ if (compFields.cc) {
+ recList = compFields.splitRecipients(compFields.cc, true, arrLen);
+ this.addRecipients(toAddrList, recList);
+ }
+ if (compFields.bcc) {
+ recList = compFields.splitRecipients(compFields.bcc, true, arrLen);
+ this.addRecipients(toAddrList, recList);
+ }
+
+ let addresses = [];
+ try {
+ addresses = EnigmailFuncs.stripEmail(toAddrList.join(", ")).split(",");
+ } catch (ex) {}
+
+ // Resolve all the email addresses if possible.
+ await EnigmailKeyRing.getValidKeysForAllRecipients(addresses, detailsObj);
+ //this.autoPgpEncryption = (validKeyList !== null);
+ }
+
+ // process and signal new resulting state
+ //this.processFinalState();
+
+ return detailsObj;
+ },
+
+ /*
+ displaySecuritySettings: function() {
+ EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.displaySecuritySettings\n");
+
+ var inputObj = {
+ gSendEncrypted: gSendEncrypted,
+ gSendSigned: gSendSigned,
+ success: false,
+ resetDefaults: false
+ };
+ window.openDialog("chrome://openpgp/content/ui/enigmailEncryptionDlg.xhtml", "", "dialog,modal,centerscreen", inputObj);
+
+ if (!inputObj.success) return; // Cancel pressed
+
+ if (inputObj.resetDefaults) {
+ // reset everything to defaults
+ this.encryptForced = 1;
+ this.signForced = 1;
+ }
+ else {
+ if (this.signForced != inputObj.sign) {
+ this.dirty = 2;
+ this.signForced = inputObj.sign;
+ }
+
+ this.dirty = 2;
+
+ this.encryptForced = inputObj.encrypt;
+ }
+
+ //this.processFinalState();
+ },
+ */
+
+ addRecipients(toAddrList, recList) {
+ for (var i = 0; i < recList.length; i++) {
+ try {
+ toAddrList.push(
+ EnigmailFuncs.stripEmail(recList[i].replace(/[",]/g, ""))
+ );
+ } catch (ex) {}
+ }
+ },
+
+ setDraftStatus(doEncrypt) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.setDraftStatus - enabling draft mode\n"
+ );
+
+ // Draft Status:
+ // N (for new style) plus 5 digits:
+ // 1: encryption
+ // 2: signing
+ // 3: PGP/MIME
+ // 4: attach own key
+ // 5: subject encrypted
+
+ var draftStatus = "N";
+
+ // Encryption:
+ // 2 -> required/enabled
+ // 0 -> disabled
+
+ if (!gUserTouchedSendEncrypted && !gIsRelatedToEncryptedOriginal) {
+ // After opening draft, it's allowed to use automatic decision.
+ draftStatus += "1";
+ } else {
+ // After opening draft, use the same state that is set now.
+ draftStatus += gSendEncrypted ? "2" : "0";
+ }
+
+ if (!gUserTouchedSendSigned) {
+ // After opening draft, it's allowed to use automatic decision.
+ draftStatus += "1";
+ } else {
+ // After opening draft, use the same state that is set now.
+ // Signing:
+ // 2 -> enabled
+ // 0 -> disabled
+ draftStatus += gSendSigned ? "2" : "0";
+ }
+
+ // MIME/technology
+ // ENIG_FORCE_SMIME == 3 -> S/MIME
+ // ENIG_FORCE_ALWAYS == 2 -> PGP/MIME
+ // 0 -> PGP inline
+ if (gSelectedTechnologyIsPGP) {
+ // inline signing currently not implemented
+ draftStatus += "2";
+ } else {
+ draftStatus += "3";
+ }
+
+ if (!gUserTouchedAttachMyPubKey) {
+ draftStatus += "2";
+ } else {
+ draftStatus += gAttachMyPublicPGPKey ? "1" : "0";
+ }
+
+ if (!gUserTouchedEncryptSubject) {
+ draftStatus += "2";
+ } else {
+ draftStatus += gSendEncrypted && gEncryptSubject ? "1" : "0";
+ }
+
+ this.setAdditionalHeader("X-Enigmail-Draft-Status", draftStatus);
+ },
+
+ getSenderUserId() {
+ let keyId = gCurrentIdentity?.getUnicharAttribute("openpgp_key_id");
+ return keyId ? "0x" + keyId : null;
+ },
+
+ /**
+ * Determine if S/MIME or OpenPGP should be used
+ *
+ * @param sendFlags: Number - input send flags.
+ *
+ * @return: Boolean:
+ * 1: use OpenPGP
+ * 0: use S/MIME
+ */
+ /*
+ preferPgpOverSmime: function(sendFlags) {
+
+ let si = Enigmail.msg.getSecurityParams(null);
+ let isSmime = !EnigmailMimeEncrypt.isEnigmailCompField(si);
+
+ if (isSmime &&
+ (sendFlags & (EnigmailConstants.SEND_SIGNED | EnigmailConstants.SEND_ENCRYPTED))) {
+
+ if (si.requireEncryptMessage || si.signMessage) {
+
+ if (sendFlags & EnigmailConstants.SAVE_MESSAGE) {
+ // use S/MIME if it's enabled for saving drafts
+ return 0;
+ }
+ else {
+ return this.mimePreferOpenPGP;
+ }
+ }
+ }
+
+ return 1;
+ },
+ */
+
+ /* Manage the wrapping of inline signed mails
+ *
+ * @wrapresultObj: Result:
+ * @wrapresultObj.cancelled, true if send operation is to be cancelled, else false
+ * @wrapresultObj.usePpgMime, true if message send option was changed to PGP/MIME, else false
+ */
+
+ async wrapInLine(wrapresultObj) {
+ EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: WrapInLine\n");
+ wrapresultObj.cancelled = false;
+ wrapresultObj.usePpgMime = false;
+ try {
+ const dce = Ci.nsIDocumentEncoder;
+ var editor = gMsgCompose.editor.QueryInterface(Ci.nsIEditorMailSupport);
+ var encoderFlags = dce.OutputFormatted | dce.OutputLFLineBreak;
+
+ var wrapWidth = Services.prefs.getIntPref("mailnews.wraplength");
+ if (wrapWidth > 0 && wrapWidth < 68 && editor.wrapWidth > 0) {
+ if (
+ EnigmailDialog.confirmDlg(
+ window,
+ await l10nOpenPGP.formatValue("minimal-line-wrapping", {
+ width: wrapWidth,
+ })
+ )
+ ) {
+ wrapWidth = 68;
+ Services.prefs.setIntPref("mailnews.wraplength", wrapWidth);
+ }
+ }
+
+ if (wrapWidth && editor.wrapWidth > 0) {
+ // First use standard editor wrap mechanism:
+ editor.wrapWidth = wrapWidth - 2;
+ editor.rewrap(true);
+ editor.wrapWidth = wrapWidth;
+
+ // Now get plaintext from editor
+ var wrapText = this.editorGetContentAs("text/plain", encoderFlags);
+
+ // split the lines into an array
+ wrapText = wrapText.split(/\r\n|\r|\n/g);
+
+ var i = 0;
+ var excess = 0;
+ // inspect all lines of mail text to detect if we still have excessive lines which the "standard" editor wrapper leaves
+ for (i = 0; i < wrapText.length; i++) {
+ if (wrapText[i].length > wrapWidth) {
+ excess = 1;
+ }
+ }
+
+ if (excess) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Excess lines detected\n"
+ );
+ var resultObj = {};
+ window.openDialog(
+ "chrome://openpgp/content/ui/enigmailWrapSelection.xhtml",
+ "",
+ "dialog,modal,centerscreen",
+ resultObj
+ );
+ try {
+ if (resultObj.cancelled) {
+ // cancel pressed -> do not send, return instead.
+ wrapresultObj.cancelled = true;
+ return;
+ }
+ } catch (ex) {
+ // cancel pressed -> do not send, return instead.
+ wrapresultObj.cancelled = true;
+ return;
+ }
+
+ var limitedLine = "";
+ var restOfLine = "";
+
+ var WrapSelect = resultObj.Select;
+ switch (WrapSelect) {
+ case "0": // Selection: Force rewrap
+ for (i = 0; i < wrapText.length; i++) {
+ if (wrapText[i].length > wrapWidth) {
+ // If the current line is too long, limit it hard to wrapWidth and insert the rest as the next line into wrapText array
+ limitedLine = wrapText[i].slice(0, wrapWidth);
+ restOfLine = wrapText[i].slice(wrapWidth);
+
+ // We should add quotes at the beginning of "restOfLine", if limitedLine is a quoted line
+ // However, this would be purely academic, because limitedLine will always be "standard"-wrapped
+ // by the editor-rewrapper at the space between quote sign (>) and the quoted text.
+
+ wrapText.splice(i, 1, limitedLine, restOfLine);
+ }
+ }
+ break;
+ case "1": // Selection: Send as is
+ break;
+ case "2": // Selection: Use MIME
+ wrapresultObj.usePpgMime = true;
+ break;
+ case "3": // Selection: Edit manually -> do not send, return instead.
+ wrapresultObj.cancelled = true;
+ return;
+ } //switch
+ }
+ // Now join all lines together again and feed it back into the compose editor.
+ var newtext = wrapText.join("\n");
+ this.replaceEditorText(newtext);
+ }
+ } catch (ex) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Exception while wrapping=" + ex + "\n"
+ );
+ }
+ },
+
+ // Save draft message. We do not want most of the other processing for encrypted mails here...
+ async saveDraftMessage(senderKeyIsGnuPG) {
+ EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: saveDraftMessage()\n");
+
+ // If we have an encryption key configured, then encrypt saved
+ // drafts by default, as a precaution. This is independent from the
+ // final decision of sending the message encrypted or not.
+ // However, we allow the user to disable encrypted drafts.
+ let doEncrypt =
+ Enigmail.msg.isEnigmailEnabledForIdentity() &&
+ gCurrentIdentity.autoEncryptDrafts;
+
+ this.setDraftStatus(doEncrypt);
+
+ if (!doEncrypt) {
+ try {
+ let p = Enigmail.msg.getSecurityParams();
+ if (EnigmailMimeEncrypt.isEnigmailCompField(p)) {
+ p.wrappedJSObject.sendFlags = 0;
+ }
+ } catch (ex) {
+ console.debug(ex);
+ }
+
+ return true;
+ }
+
+ let sendFlags =
+ EnigmailConstants.SEND_PGP_MIME |
+ EnigmailConstants.SEND_ENCRYPTED |
+ EnigmailConstants.SEND_ENCRYPT_TO_SELF |
+ EnigmailConstants.SAVE_MESSAGE;
+
+ if (gEncryptSubject) {
+ sendFlags |= EnigmailConstants.ENCRYPT_SUBJECT;
+ }
+ if (senderKeyIsGnuPG) {
+ sendFlags |= EnigmailConstants.SEND_SENDER_KEY_EXTERNAL;
+ }
+
+ let fromAddr = this.getSenderUserId();
+
+ let enigmailSvc = EnigmailCore.getService(window);
+ if (!enigmailSvc) {
+ return true;
+ }
+
+ let senderKeyUsable = await EnigmailEncryption.determineOwnKeyUsability(
+ sendFlags,
+ fromAddr,
+ senderKeyIsGnuPG
+ );
+ if (senderKeyUsable.errorMsg) {
+ let fullAlert = await document.l10n.formatValue(
+ "msg-compose-cannot-save-draft"
+ );
+ fullAlert += " - " + senderKeyUsable.errorMsg;
+ EnigmailDialog.alert(window, fullAlert);
+ return false;
+ }
+
+ //if (this.preferPgpOverSmime(sendFlags) === 0) return true; // use S/MIME
+
+ let secInfo;
+
+ let param = Enigmail.msg.getSecurityParams();
+
+ if (EnigmailMimeEncrypt.isEnigmailCompField(param)) {
+ secInfo = param.wrappedJSObject;
+ } else {
+ try {
+ secInfo = EnigmailMimeEncrypt.createMimeEncrypt(param);
+ if (secInfo) {
+ Enigmail.msg.setSecurityParams(secInfo);
+ }
+ } catch (ex) {
+ EnigmailLog.writeException(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.saveDraftMessage",
+ ex
+ );
+ return false;
+ }
+ }
+
+ secInfo.sendFlags = sendFlags;
+ secInfo.UIFlags = 0;
+ secInfo.senderEmailAddr = fromAddr;
+ secInfo.recipients = "";
+ secInfo.bccRecipients = "";
+ secInfo.originalSubject = gMsgCompose.compFields.subject;
+ this.dirty = 1;
+
+ if (sendFlags & EnigmailConstants.ENCRYPT_SUBJECT) {
+ gMsgCompose.compFields.subject = "";
+ }
+
+ return true;
+ },
+
+ createEnigmailSecurityFields(oldSecurityInfo) {
+ let newSecurityInfo = EnigmailMimeEncrypt.createMimeEncrypt(
+ Enigmail.msg.getSecurityParams()
+ );
+
+ if (!newSecurityInfo) {
+ throw Components.Exception("", Cr.NS_ERROR_FAILURE);
+ }
+
+ Enigmail.msg.setSecurityParams(newSecurityInfo);
+ },
+
+ /*
+ sendSmimeEncrypted: function(msgSendType, sendFlags, isOffline) {
+ let recList;
+ let toAddrList = [];
+ let arrLen = {};
+ const DeliverMode = Ci.nsIMsgCompDeliverMode;
+
+ switch (msgSendType) {
+ case DeliverMode.SaveAsDraft:
+ case DeliverMode.SaveAsTemplate:
+ case DeliverMode.AutoSaveAsDraft:
+ break;
+ default:
+ if (gAttachMyPublicPGPKey) {
+ await this.attachOwnKey();
+ Attachments2CompFields(gMsgCompose.compFields); // update list of attachments
+ }
+ }
+
+ gSMFields.signMessage = (sendFlags & EnigmailConstants.SEND_SIGNED ? true : false);
+ gSMFields.requireEncryptMessage = (sendFlags & EnigmailConstants.SEND_ENCRYPTED ? true : false);
+
+ Enigmail.msg.setSecurityParams(gSMFields);
+
+ let conf = this.isSendConfirmationRequired(sendFlags);
+
+ if (conf === null) return false;
+ if (conf) {
+ // confirm before send requested
+ let msgCompFields = gMsgCompose.compFields;
+ let splitRecipients = msgCompFields.splitRecipients;
+
+ if (msgCompFields.to.length > 0) {
+ recList = splitRecipients(msgCompFields.to, true, arrLen);
+ this.addRecipients(toAddrList, recList);
+ }
+
+ if (msgCompFields.cc.length > 0) {
+ recList = splitRecipients(msgCompFields.cc, true, arrLen);
+ this.addRecipients(toAddrList, recList);
+ }
+
+ switch (msgSendType) {
+ case DeliverMode.SaveAsDraft:
+ case DeliverMode.SaveAsTemplate:
+ case DeliverMode.AutoSaveAsDraft:
+ break;
+ default:
+ if (!this.confirmBeforeSend(toAddrList.join(", "), "", sendFlags, isOffline)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ },
+ */
+
+ getEncryptionFlags() {
+ let f = 0;
+
+ if (gSendEncrypted) {
+ f |= EnigmailConstants.SEND_ENCRYPTED;
+ } else {
+ f &= ~EnigmailConstants.SEND_ENCRYPTED;
+ }
+
+ if (gSendSigned) {
+ f |= EnigmailConstants.SEND_SIGNED;
+ } else {
+ f &= ~EnigmailConstants.SEND_SIGNED;
+ }
+
+ if (gSendEncrypted && gSendSigned) {
+ if (Services.prefs.getBoolPref("mail.openpgp.separate_mime_layers")) {
+ f |= EnigmailConstants.SEND_TWO_MIME_LAYERS;
+ }
+ }
+
+ if (gSendEncrypted && gEncryptSubject) {
+ f |= EnigmailConstants.ENCRYPT_SUBJECT;
+ }
+
+ return f;
+ },
+
+ resetDirty() {
+ let newSecurityInfo = null;
+
+ if (this.dirty) {
+ // make sure the sendFlags are reset before the message is processed
+ // (it may have been set by a previously cancelled send operation!)
+
+ let si = Enigmail.msg.getSecurityParams();
+
+ if (EnigmailMimeEncrypt.isEnigmailCompField(si)) {
+ si.sendFlags = 0;
+ si.originalSubject = gMsgCompose.compFields.subject;
+ } else {
+ try {
+ newSecurityInfo = EnigmailMimeEncrypt.createMimeEncrypt(si);
+ if (newSecurityInfo) {
+ newSecurityInfo.sendFlags = 0;
+ newSecurityInfo.originalSubject = gMsgCompose.compFields.subject;
+
+ Enigmail.msg.setSecurityParams(newSecurityInfo);
+ }
+ } catch (ex) {
+ EnigmailLog.writeException(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.resetDirty",
+ ex
+ );
+ }
+ }
+ }
+
+ return newSecurityInfo;
+ },
+
+ async determineMsgRecipients(sendFlags) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.determineMsgRecipients: currentId=" +
+ gCurrentIdentity +
+ ", " +
+ gCurrentIdentity.email +
+ "\n"
+ );
+
+ let fromAddr = gCurrentIdentity.email;
+ let toAddrList = [];
+ let recList;
+ let bccAddrList = [];
+ let arrLen = {};
+ let splitRecipients;
+
+ if (!Enigmail.msg.isEnigmailEnabledForIdentity()) {
+ return true;
+ }
+
+ let optSendFlags = 0;
+ let msgCompFields = gMsgCompose.compFields;
+ let newsgroups = msgCompFields.newsgroups;
+
+ if (Services.prefs.getBoolPref("temp.openpgp.encryptToSelf")) {
+ optSendFlags |= EnigmailConstants.SEND_ENCRYPT_TO_SELF;
+ }
+
+ sendFlags |= optSendFlags;
+
+ var userIdValue = this.getSenderUserId();
+ if (userIdValue) {
+ fromAddr = userIdValue;
+ }
+
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.determineMsgRecipients:gMsgCompose=" +
+ gMsgCompose +
+ "\n"
+ );
+
+ splitRecipients = msgCompFields.splitRecipients;
+
+ if (msgCompFields.to.length > 0) {
+ recList = splitRecipients(msgCompFields.to, true, arrLen);
+ this.addRecipients(toAddrList, recList);
+ }
+
+ if (msgCompFields.cc.length > 0) {
+ recList = splitRecipients(msgCompFields.cc, true, arrLen);
+ this.addRecipients(toAddrList, recList);
+ }
+
+ // We allow sending to BCC recipients, we assume the user interface
+ // has warned the user that there is no privacy of BCC recipients.
+ if (msgCompFields.bcc.length > 0) {
+ recList = splitRecipients(msgCompFields.bcc, true, arrLen);
+ this.addRecipients(bccAddrList, recList);
+ }
+
+ if (newsgroups) {
+ toAddrList.push(newsgroups);
+
+ if (sendFlags & EnigmailConstants.SEND_ENCRYPTED) {
+ if (!Services.prefs.getBoolPref("temp.openpgp.encryptToNews")) {
+ document.l10n.formatValue("sending-news").then(value => {
+ EnigmailDialog.alert(window, value);
+ });
+ return false;
+ } else if (
+ !EnigmailDialog.confirmBoolPref(
+ window,
+ await l10nOpenPGP.formatValue("send-to-news-warning"),
+ "temp.openpgp.warnOnSendingNewsgroups",
+ await l10nOpenPGP.formatValue("msg-compose-button-send")
+ )
+ ) {
+ return false;
+ }
+ }
+ }
+
+ return {
+ sendFlags,
+ optSendFlags,
+ fromAddr,
+ toAddrList,
+ bccAddrList,
+ };
+ },
+
+ prepareSending(sendFlags, toAddrStr, gpgKeys, isOffline) {
+ // perform confirmation dialog if necessary/requested
+ if (
+ sendFlags & EnigmailConstants.SEND_WITH_CHECK &&
+ !this.messageSendCheck()
+ ) {
+ // Abort send
+ if (!this.processed) {
+ this.removeAttachedKey();
+ }
+
+ return false;
+ }
+
+ return true;
+ },
+
+ prepareSecurityInfo(
+ sendFlags,
+ uiFlags,
+ rcpt,
+ newSecurityInfo,
+ autocryptGossipHeaders
+ ) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.prepareSecurityInfo(): Using PGP/MIME, flags=" +
+ sendFlags +
+ "\n"
+ );
+
+ let oldSecurityInfo = Enigmail.msg.getSecurityParams();
+
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.prepareSecurityInfo: oldSecurityInfo = " +
+ oldSecurityInfo +
+ "\n"
+ );
+
+ if (!newSecurityInfo) {
+ this.createEnigmailSecurityFields(Enigmail.msg.getSecurityParams());
+ newSecurityInfo = Enigmail.msg.getSecurityParams().wrappedJSObject;
+ }
+
+ newSecurityInfo.originalSubject = gMsgCompose.compFields.subject;
+ newSecurityInfo.originalReferences = gMsgCompose.compFields.references;
+
+ if (sendFlags & EnigmailConstants.SEND_ENCRYPTED) {
+ if (sendFlags & EnigmailConstants.ENCRYPT_SUBJECT) {
+ gMsgCompose.compFields.subject = "";
+ }
+
+ if (Services.prefs.getBoolPref("temp.openpgp.protectReferencesHdr")) {
+ gMsgCompose.compFields.references = "";
+ }
+ }
+
+ newSecurityInfo.sendFlags = sendFlags;
+ newSecurityInfo.UIFlags = uiFlags;
+ newSecurityInfo.senderEmailAddr = rcpt.fromAddr;
+ newSecurityInfo.bccRecipients = rcpt.bccAddrStr;
+ newSecurityInfo.autocryptGossipHeaders = autocryptGossipHeaders;
+
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.prepareSecurityInfo: securityInfo = " +
+ newSecurityInfo +
+ "\n"
+ );
+ return newSecurityInfo;
+ },
+
+ async prepareSendMsg(msgSendType) {
+ // msgSendType: value from nsIMsgCompDeliverMode
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.prepareSendMsg: msgSendType=" +
+ msgSendType +
+ ", gSendSigned=" +
+ gSendSigned +
+ ", gSendEncrypted=" +
+ gSendEncrypted +
+ "\n"
+ );
+
+ const SIGN = EnigmailConstants.SEND_SIGNED;
+ const ENCRYPT = EnigmailConstants.SEND_ENCRYPTED;
+ const DeliverMode = Ci.nsIMsgCompDeliverMode;
+
+ var ioService = Services.io;
+ // EnigSend: Handle both plain and encrypted messages below
+ var isOffline = ioService && ioService.offline;
+
+ let senderKeyIsGnuPG =
+ Services.prefs.getBoolPref("mail.openpgp.allow_external_gnupg") &&
+ gCurrentIdentity.getBoolAttribute("is_gnupg_key_id");
+
+ let sendFlags = this.getEncryptionFlags();
+
+ switch (msgSendType) {
+ case DeliverMode.SaveAsDraft:
+ case DeliverMode.SaveAsTemplate:
+ case DeliverMode.AutoSaveAsDraft:
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.prepareSendMsg: detected save draft\n"
+ );
+
+ // saving drafts is simpler and works differently than the rest of Enigmail.
+ // All rules except account-settings are ignored.
+ return this.saveDraftMessage(senderKeyIsGnuPG);
+ }
+
+ this.unsetAdditionalHeader("x-enigmail-draft-status");
+
+ let msgCompFields = gMsgCompose.compFields;
+ let newsgroups = msgCompFields.newsgroups; // Check if sending to any newsgroups
+
+ if (
+ msgCompFields.to === "" &&
+ msgCompFields.cc === "" &&
+ msgCompFields.bcc === "" &&
+ newsgroups === ""
+ ) {
+ // don't attempt to send message if no recipient specified
+ var bundle = document.getElementById("bundle_composeMsgs");
+ EnigmailDialog.alert(window, bundle.getString("12511"));
+ return false;
+ }
+
+ let senderKeyId = gCurrentIdentity.getUnicharAttribute("openpgp_key_id");
+
+ if ((gSendEncrypted || gSendSigned) && !senderKeyId) {
+ let msgId = gSendEncrypted
+ ? "cannot-send-enc-because-no-own-key"
+ : "cannot-send-sig-because-no-own-key";
+ let fullAlert = await document.l10n.formatValue(msgId, {
+ key: gCurrentIdentity.email,
+ });
+ EnigmailDialog.alert(window, fullAlert);
+ return false;
+ }
+
+ if (senderKeyIsGnuPG) {
+ sendFlags |= EnigmailConstants.SEND_SENDER_KEY_EXTERNAL;
+ }
+
+ if ((gSendEncrypted || gSendSigned) && senderKeyId) {
+ let senderKeyUsable = await EnigmailEncryption.determineOwnKeyUsability(
+ sendFlags,
+ senderKeyId,
+ senderKeyIsGnuPG
+ );
+ if (senderKeyUsable.errorMsg) {
+ let fullAlert = await document.l10n.formatValue(
+ "cannot-use-own-key-because",
+ {
+ problem: senderKeyUsable.errorMsg,
+ }
+ );
+ EnigmailDialog.alert(window, fullAlert);
+ return false;
+ }
+ }
+
+ let cannotEncryptMissingInfo = false;
+ if (gSendEncrypted) {
+ let canEncryptDetails = await this.determineSendFlags();
+ if (canEncryptDetails.errArray.length != 0) {
+ cannotEncryptMissingInfo = true;
+ }
+ }
+
+ if (gWindowLocked) {
+ EnigmailDialog.alert(
+ window,
+ await document.l10n.formatValue("window-locked")
+ );
+ return false;
+ }
+
+ let newSecurityInfo = this.resetDirty();
+ this.dirty = 1;
+
+ try {
+ this.modifiedAttach = null;
+
+ // fill fromAddr, toAddrList, bcc etc
+ let rcpt = await this.determineMsgRecipients(sendFlags);
+ if (typeof rcpt === "boolean") {
+ return rcpt;
+ }
+ sendFlags = rcpt.sendFlags;
+
+ if (cannotEncryptMissingInfo) {
+ showMessageComposeSecurityStatus(true);
+ return false;
+ }
+
+ if (this.sendPgpMime) {
+ // Use PGP/MIME
+ sendFlags |= EnigmailConstants.SEND_PGP_MIME;
+ }
+
+ let toAddrStr = rcpt.toAddrList.join(", ");
+ let bccAddrStr = rcpt.bccAddrList.join(", ");
+
+ if (gAttachMyPublicPGPKey) {
+ await this.attachOwnKey(senderKeyId);
+ }
+
+ let autocryptGossipHeaders = await this.getAutocryptGossip();
+
+ /*
+ if (this.preferPgpOverSmime(sendFlags) === 0) {
+ // use S/MIME
+ Attachments2CompFields(gMsgCompose.compFields); // update list of attachments
+ sendFlags = 0;
+ return true;
+ }
+ */
+
+ var usingPGPMime =
+ sendFlags & EnigmailConstants.SEND_PGP_MIME &&
+ sendFlags & (ENCRYPT | SIGN);
+
+ // ----------------------- Rewrapping code, taken from function "encryptInline"
+
+ if (sendFlags & ENCRYPT && !usingPGPMime) {
+ throw new Error("Sending encrypted inline not supported!");
+ }
+ if (sendFlags & SIGN && !usingPGPMime && gMsgCompose.composeHTML) {
+ throw new Error(
+ "Sending signed inline only supported for plain text composition!"
+ );
+ }
+
+ // Check wrapping, if sign only and inline and plaintext
+ if (
+ sendFlags & SIGN &&
+ !(sendFlags & ENCRYPT) &&
+ !usingPGPMime &&
+ !gMsgCompose.composeHTML
+ ) {
+ var wrapresultObj = {};
+
+ await this.wrapInLine(wrapresultObj);
+
+ if (wrapresultObj.usePpgMime) {
+ sendFlags |= EnigmailConstants.SEND_PGP_MIME;
+ usingPGPMime = EnigmailConstants.SEND_PGP_MIME;
+ }
+ if (wrapresultObj.cancelled) {
+ return false;
+ }
+ }
+
+ var uiFlags = EnigmailConstants.UI_INTERACTIVE;
+
+ if (usingPGPMime) {
+ uiFlags |= EnigmailConstants.UI_PGP_MIME;
+ }
+
+ if (sendFlags & (ENCRYPT | SIGN) && usingPGPMime) {
+ // Use PGP/MIME
+ newSecurityInfo = this.prepareSecurityInfo(
+ sendFlags,
+ uiFlags,
+ rcpt,
+ newSecurityInfo,
+ autocryptGossipHeaders
+ );
+ newSecurityInfo.recipients = toAddrStr;
+ newSecurityInfo.bccRecipients = bccAddrStr;
+ } else if (!this.processed && sendFlags & (ENCRYPT | SIGN)) {
+ // use inline PGP
+
+ let sendInfo = {
+ sendFlags,
+ fromAddr: rcpt.fromAddr,
+ toAddr: toAddrStr,
+ bccAddr: bccAddrStr,
+ uiFlags,
+ bucketList: document.getElementById("attachmentBucket"),
+ };
+
+ if (!(await this.signInline(sendInfo))) {
+ return false;
+ }
+ }
+
+ // update the list of attachments
+ Attachments2CompFields(msgCompFields);
+
+ if (
+ !this.prepareSending(
+ sendFlags,
+ rcpt.toAddrList.join(", "),
+ toAddrStr + ", " + bccAddrStr,
+ isOffline
+ )
+ ) {
+ return false;
+ }
+
+ if (msgCompFields.characterSet != "ISO-2022-JP") {
+ if (
+ (usingPGPMime && sendFlags & (ENCRYPT | SIGN)) ||
+ (!usingPGPMime && sendFlags & ENCRYPT)
+ ) {
+ try {
+ // make sure plaintext is not changed to 7bit
+ if (typeof msgCompFields.forceMsgEncoding == "boolean") {
+ msgCompFields.forceMsgEncoding = true;
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.prepareSendMsg: enabled forceMsgEncoding\n"
+ );
+ }
+ } catch (ex) {
+ console.debug(ex);
+ }
+ }
+ }
+ } catch (ex) {
+ EnigmailLog.writeException(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.prepareSendMsg",
+ ex
+ );
+ return false;
+ }
+
+ // The encryption process for PGP/MIME messages follows "here". It's
+ // called automatically from nsMsgCompose->sendMsg().
+ // registration for this is done in core.jsm: startup()
+
+ return true;
+ },
+
+ async signInline(sendInfo) {
+ // sign message using inline-PGP
+
+ if (sendInfo.sendFlags & ENCRYPT) {
+ throw new Error("Encryption not supported in inline messages!");
+ }
+ if (gMsgCompose.composeHTML) {
+ throw new Error(
+ "Signing inline only supported for plain text composition!"
+ );
+ }
+
+ const dce = Ci.nsIDocumentEncoder;
+ const SIGN = EnigmailConstants.SEND_SIGNED;
+ const ENCRYPT = EnigmailConstants.SEND_ENCRYPTED;
+
+ var enigmailSvc = EnigmailCore.getService(window);
+ if (!enigmailSvc) {
+ return false;
+ }
+
+ if (Services.prefs.getBoolPref("mail.strictly_mime")) {
+ if (
+ EnigmailDialog.confirmIntPref(
+ window,
+ await l10nOpenPGP.formatValue("quoted-printable-warn"),
+ "temp.openpgp.quotedPrintableWarn"
+ )
+ ) {
+ Services.prefs.setBoolPref("mail.strictly_mime", false);
+ }
+ }
+
+ var sendFlowed = Services.prefs.getBoolPref(
+ "mailnews.send_plaintext_flowed"
+ );
+ var encoderFlags = dce.OutputFormatted | dce.OutputLFLineBreak;
+
+ // plaintext: Wrapping code has been moved to superordinate function prepareSendMsg to enable interactive format switch
+
+ var exitCodeObj = {};
+ var statusFlagsObj = {};
+ var errorMsgObj = {};
+ var exitCode;
+
+ // Get plain text
+ // (Do we need to set the nsIDocumentEncoder.* flags?)
+ var origText = this.editorGetContentAs("text/plain", encoderFlags);
+ if (!origText) {
+ origText = "";
+ }
+
+ if (origText.length > 0) {
+ // Sign/encrypt body text
+
+ var escText = origText; // Copy plain text for possible escaping
+
+ if (sendFlowed) {
+ // Prevent space stuffing a la RFC 2646 (format=flowed).
+
+ //EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: escText["+encoderFlags+"] = '"+escText+"'\n");
+
+ escText = escText.replace(/^From /gm, "~From ");
+ escText = escText.replace(/^>/gm, "|");
+ escText = escText.replace(/^[ \t]+$/gm, "");
+ escText = escText.replace(/^ /gm, "~ ");
+
+ //EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: escText = '"+escText+"'\n");
+ // Replace plain text and get it again
+ this.replaceEditorText(escText);
+
+ escText = this.editorGetContentAs("text/plain", encoderFlags);
+ }
+
+ // Replace plain text and get it again (to avoid linewrapping problems)
+ this.replaceEditorText(escText);
+
+ escText = this.editorGetContentAs("text/plain", encoderFlags);
+
+ //EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: escText["+encoderFlags+"] = '"+escText+"'\n");
+
+ var charset = this.editorGetCharset();
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.signInline: charset=" +
+ charset +
+ "\n"
+ );
+
+ // Encode plaintext to charset from unicode
+ var plainText = EnigmailData.convertFromUnicode(escText, charset);
+
+ // this will sign, not encrypt
+ var cipherText = EnigmailEncryption.encryptMessage(
+ window,
+ sendInfo.uiFlags,
+ plainText,
+ sendInfo.fromAddr,
+ sendInfo.toAddr,
+ sendInfo.bccAddr,
+ sendInfo.sendFlags,
+ exitCodeObj,
+ statusFlagsObj,
+ errorMsgObj
+ );
+
+ exitCode = exitCodeObj.value;
+
+ //EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: cipherText = '"+cipherText+"'\n");
+ if (cipherText && exitCode === 0) {
+ // Encryption/signing succeeded; overwrite plaintext
+
+ cipherText = cipherText.replace(/\r\n/g, "\n");
+
+ // Decode ciphertext from charset to unicode and overwrite
+ this.replaceEditorText(
+ EnigmailData.convertToUnicode(cipherText, charset)
+ );
+
+ // Save original text (for undo)
+ this.processed = {
+ origText,
+ charset,
+ };
+ } else {
+ // Restore original text
+ this.replaceEditorText(origText);
+
+ if (sendInfo.sendFlags & SIGN) {
+ // Encryption/signing failed
+
+ this.sendAborted(window, errorMsgObj);
+ return false;
+ }
+ }
+ }
+
+ return true;
+ },
+
+ async sendAborted(window, errorMsgObj) {
+ if (errorMsgObj && errorMsgObj.value) {
+ var txt = errorMsgObj.value;
+ var txtLines = txt.split(/\r?\n/);
+ var errorMsg = "";
+ for (var i = 0; i < txtLines.length; ++i) {
+ var line = txtLines[i];
+ var tokens = line.split(/ /);
+ // process most important business reasons for invalid recipient (and sender) errors:
+ if (
+ tokens.length == 3 &&
+ (tokens[0] == "INV_RECP" || tokens[0] == "INV_SGNR")
+ ) {
+ var reason = tokens[1];
+ var key = tokens[2];
+ if (reason == "10") {
+ errorMsg +=
+ (await document.l10n.formatValue("key-not-trusted", { key })) +
+ "\n";
+ } else if (reason == "1") {
+ errorMsg +=
+ (await document.l10n.formatValue("key-not-found", { key })) +
+ "\n";
+ } else if (reason == "4") {
+ errorMsg +=
+ (await document.l10n.formatValue("key-revoked", { key })) + "\n";
+ } else if (reason == "5") {
+ errorMsg +=
+ (await document.l10n.formatValue("key-expired", { key })) + "\n";
+ }
+ }
+ }
+ if (errorMsg !== "") {
+ txt = errorMsg + "\n" + txt;
+ }
+ EnigmailDialog.info(
+ window,
+ (await document.l10n.formatValue("send-aborted")) + "\n" + txt
+ );
+ } else {
+ let [title, message] = await document.l10n.formatValues([
+ { id: "send-aborted" },
+ { id: "msg-compose-internal-error" },
+ ]);
+ EnigmailDialog.info(window, title + "\n" + message);
+ }
+ },
+
+ messageSendCheck() {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.messageSendCheck\n"
+ );
+
+ try {
+ var warn = Services.prefs.getBoolPref("mail.warn_on_send_accel_key");
+
+ if (warn) {
+ var checkValue = {
+ value: false,
+ };
+ var bundle = document.getElementById("bundle_composeMsgs");
+ var buttonPressed = EnigmailDialog.getPromptSvc().confirmEx(
+ window,
+ bundle.getString("sendMessageCheckWindowTitle"),
+ bundle.getString("sendMessageCheckLabel"),
+ EnigmailDialog.getPromptSvc().BUTTON_TITLE_IS_STRING *
+ EnigmailDialog.getPromptSvc().BUTTON_POS_0 +
+ EnigmailDialog.getPromptSvc().BUTTON_TITLE_CANCEL *
+ EnigmailDialog.getPromptSvc().BUTTON_POS_1,
+ bundle.getString("sendMessageCheckSendButtonLabel"),
+ null,
+ null,
+ bundle.getString("CheckMsg"),
+ checkValue
+ );
+ if (buttonPressed !== 0) {
+ return false;
+ }
+ if (checkValue.value) {
+ Services.prefs.setBoolPref("mail.warn_on_send_accel_key", false);
+ }
+ }
+ } catch (ex) {}
+
+ return true;
+ },
+
+ /**
+ * set non-standard message Header
+ * (depending on TB version)
+ *
+ * hdr: String: header type (e.g. X-Enigmail-Version)
+ * val: String: header data (e.g. 1.2.3.4)
+ */
+ setAdditionalHeader(hdr, val) {
+ if ("otherRandomHeaders" in gMsgCompose.compFields) {
+ // TB <= 36
+ gMsgCompose.compFields.otherRandomHeaders += hdr + ": " + val + "\r\n";
+ } else {
+ gMsgCompose.compFields.setHeader(hdr, val);
+ }
+ },
+
+ unsetAdditionalHeader(hdr) {
+ gMsgCompose.compFields.deleteHeader(hdr);
+ },
+
+ // called just before sending
+ modifyCompFields() {
+ try {
+ if (
+ !Enigmail.msg.isEnigmailEnabledForIdentity() ||
+ !gCurrentIdentity.sendAutocryptHeaders
+ ) {
+ return;
+ }
+ if ((gSendSigned || gSendEncrypted) && !gSelectedTechnologyIsPGP) {
+ // If we're sending an S/MIME message, we don't want to send
+ // the OpenPGP autocrypt header.
+ return;
+ }
+ this.setAutocryptHeader();
+ } catch (ex) {
+ EnigmailLog.writeException(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.modifyCompFields",
+ ex
+ );
+ }
+ },
+
+ getCurrentIncomingServer() {
+ let currentAccountKey = getCurrentAccountKey();
+ let account = MailServices.accounts.getAccount(currentAccountKey);
+
+ return account.incomingServer; /* returns nsIMsgIncomingServer */
+ },
+
+ /**
+ * Obtain all Autocrypt-Gossip header lines that should be included in
+ * the outgoing message, excluding the sender's (from) email address.
+ * If there is just one recipient (ignoring the from address),
+ * no headers will be returned.
+ *
+ * @returns {string} - All header lines including line endings,
+ * could be the empty string.
+ */
+ async getAutocryptGossip() {
+ let fromMail = EnigmailFuncs.stripEmail(gMsgCompose.compFields.from);
+ let replyToMail = EnigmailFuncs.stripEmail(gMsgCompose.compFields.replyTo);
+
+ let optionalReplyToGossip = "";
+ if (replyToMail != fromMail) {
+ optionalReplyToGossip = ", " + gMsgCompose.compFields.replyTo;
+ }
+
+ // Assumes that extractHeaderAddressMailboxes will separate all
+ // entries with the sequence comma-space.
+ let allEmails = MailServices.headerParser
+ .extractHeaderAddressMailboxes(
+ gMsgCompose.compFields.to +
+ ", " +
+ gMsgCompose.compFields.cc +
+ optionalReplyToGossip
+ )
+ .split(/, /);
+
+ // Use a Set to ensure we have each address only once.
+ let uniqueEmails = new Set();
+ for (let e of allEmails) {
+ uniqueEmails.add(e);
+ }
+
+ // Potentially to/cc might contain the sender email address.
+ // Remove it, if it's there.
+ uniqueEmails.delete(fromMail);
+
+ // When sending to yourself, only, allEmails.length is 0.
+ // When sending to exactly one other person (with or without
+ // "from" in to/cc), then allEmails.length is 1. In that scenario,
+ // that recipient obviously already has their own key, and doesn't
+ // need the gossip. The sender's key will be included in the
+ // separate autocrypt (non-gossip) header.
+
+ if (uniqueEmails.size < 2) {
+ return "";
+ }
+
+ let gossip = "";
+ for (const email of uniqueEmails) {
+ let k = await EnigmailKeyRing.getRecipientAutocryptKeyForEmail(email);
+ if (!k) {
+ continue;
+ }
+ let keyData =
+ " " + k.replace(/(.{72})/g, "$1\r\n ").replace(/\r\n $/, "");
+ gossip +=
+ "Autocrypt-Gossip: addr=" + email + "; keydata=\r\n" + keyData + "\r\n";
+ }
+
+ return gossip;
+ },
+
+ setAutocryptHeader() {
+ let senderKeyId = gCurrentIdentity.getUnicharAttribute("openpgp_key_id");
+ if (!senderKeyId) {
+ return;
+ }
+
+ let fromMail = gCurrentIdentity.email;
+ try {
+ fromMail = EnigmailFuncs.stripEmail(gMsgCompose.compFields.from);
+ } catch (ex) {}
+
+ let keyData = EnigmailKeyRing.getAutocryptKey("0x" + senderKeyId, fromMail);
+
+ if (keyData) {
+ keyData =
+ " " + keyData.replace(/(.{72})/g, "$1\r\n ").replace(/\r\n $/, "");
+ this.setAdditionalHeader(
+ "Autocrypt",
+ "addr=" + fromMail + "; keydata=\r\n" + keyData
+ );
+ }
+ },
+
+ /**
+ * Handle the 'compose-send-message' event from TB
+ */
+ sendMessageListener(event) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.sendMessageListener\n"
+ );
+
+ let msgcomposeWindow = document.getElementById("msgcomposeWindow");
+ let sendMsgType = Number(msgcomposeWindow.getAttribute("msgtype"));
+
+ if (
+ !(
+ this.sendProcess &&
+ sendMsgType == Ci.nsIMsgCompDeliverMode.AutoSaveAsDraft
+ )
+ ) {
+ this.modifyCompFields();
+ if (!gSelectedTechnologyIsPGP) {
+ return;
+ }
+
+ this.sendProcess = true;
+ //let bc = document.getElementById("enigmail-bc-sendprocess");
+
+ try {
+ const cApi = EnigmailCryptoAPI();
+ let encryptResult = cApi.sync(this.prepareSendMsg(sendMsgType));
+ if (!encryptResult) {
+ this.resetUpdatedFields();
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ } catch (ex) {
+ console.error("GenericSendMessage FAILED: " + ex);
+ this.resetUpdatedFields();
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ } else {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.sendMessageListener: sending in progress - autosave aborted\n"
+ );
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ this.sendProcess = false;
+ },
+
+ async decryptQuote(interactive) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.decryptQuote: " +
+ interactive +
+ "\n"
+ );
+
+ if (gWindowLocked || this.processed) {
+ return;
+ }
+
+ var enigmailSvc = EnigmailCore.getService(window);
+ if (!enigmailSvc) {
+ return;
+ }
+
+ const dce = Ci.nsIDocumentEncoder;
+ var encoderFlags = dce.OutputFormatted | dce.OutputLFLineBreak;
+
+ var docText = this.editorGetContentAs("text/plain", encoderFlags);
+
+ var blockBegin = docText.indexOf("-----BEGIN PGP ");
+ if (blockBegin < 0) {
+ return;
+ }
+
+ // Determine indentation string
+ var indentBegin = docText.substr(0, blockBegin).lastIndexOf("\n");
+ var indentStr = docText.substring(indentBegin + 1, blockBegin);
+
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.decryptQuote: indentStr='" +
+ indentStr +
+ "'\n"
+ );
+
+ var beginIndexObj = {};
+ var endIndexObj = {};
+ var indentStrObj = {};
+ var blockType = EnigmailArmor.locateArmoredBlock(
+ docText,
+ 0,
+ indentStr,
+ beginIndexObj,
+ endIndexObj,
+ indentStrObj
+ );
+ if (blockType != "MESSAGE" && blockType != "SIGNED MESSAGE") {
+ return;
+ }
+
+ var beginIndex = beginIndexObj.value;
+ var endIndex = endIndexObj.value;
+
+ var head = docText.substr(0, beginIndex);
+ var tail = docText.substr(endIndex + 1);
+
+ var pgpBlock = docText.substr(beginIndex, endIndex - beginIndex + 1);
+ var indentRegexp;
+
+ if (indentStr) {
+ if (indentStr == "> ") {
+ // replace ">> " with "> > " to allow correct quoting
+ pgpBlock = pgpBlock.replace(/^>>/gm, "> >");
+ }
+
+ // Escape regex chars.
+ let escapedIndent1 = indentStr.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
+
+ // Delete indentation
+ indentRegexp = new RegExp("^" + escapedIndent1, "gm");
+
+ pgpBlock = pgpBlock.replace(indentRegexp, "");
+ //tail = tail.replace(indentRegexp, "");
+
+ if (indentStr.match(/[ \t]*$/)) {
+ indentStr = indentStr.replace(/[ \t]*$/gm, "");
+ // Escape regex chars.
+ let escapedIndent2 = indentStr.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
+ indentRegexp = new RegExp("^" + escapedIndent2 + "$", "gm");
+
+ pgpBlock = pgpBlock.replace(indentRegexp, "");
+ }
+
+ // Handle blank indented lines
+ pgpBlock = pgpBlock.replace(/^[ \t]*>[ \t]*$/gm, "");
+ //tail = tail.replace(/^[ \t]*>[ \t]*$/g, "");
+
+ // Trim leading space in tail
+ tail = tail.replace(/^\s*\n/m, "\n");
+ }
+
+ if (tail.search(/\S/) < 0) {
+ // No non-space characters in tail; delete it
+ tail = "";
+ }
+
+ //EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.decryptQuote: pgpBlock='"+pgpBlock+"'\n");
+
+ var charset = this.editorGetCharset();
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.decryptQuote: charset=" +
+ charset +
+ "\n"
+ );
+
+ // Encode ciphertext from unicode to charset
+ var cipherText = EnigmailData.convertFromUnicode(pgpBlock, charset);
+
+ // Decrypt message
+ var signatureObj = {};
+ signatureObj.value = "";
+ var exitCodeObj = {};
+ var statusFlagsObj = {};
+ var userIdObj = {};
+ var keyIdObj = {};
+ var sigDetailsObj = {};
+ var errorMsgObj = {};
+ var blockSeparationObj = {};
+ var encToDetailsObj = {};
+
+ var uiFlags = EnigmailConstants.UI_UNVERIFIED_ENC_OK;
+
+ var plainText = "";
+
+ plainText = EnigmailDecryption.decryptMessage(
+ window,
+ uiFlags,
+ cipherText,
+ null, // date
+ signatureObj,
+ exitCodeObj,
+ statusFlagsObj,
+ keyIdObj,
+ userIdObj,
+ sigDetailsObj,
+ errorMsgObj,
+ blockSeparationObj,
+ encToDetailsObj
+ );
+ // Decode plaintext from charset to unicode
+ plainText = EnigmailData.convertToUnicode(plainText, charset).replace(
+ /\r\n/g,
+ "\n"
+ );
+
+ //if (Services.prefs.getBoolPref("temp.openpgp.keepSettingsForReply")) {
+ if (statusFlagsObj.value & EnigmailConstants.DECRYPTION_OKAY) {
+ //this.setSendMode('encrypt');
+
+ // TODO : Check, when is this code reached?
+ // automatic enabling encryption currently depends on
+ // adjustSignEncryptAfterIdentityChanged to be always reached
+ gIsRelatedToEncryptedOriginal = true;
+ gSendEncrypted = true;
+ updateEncryptionDependencies();
+ }
+ //}
+
+ var exitCode = exitCodeObj.value;
+
+ if (exitCode !== 0) {
+ // Error processing
+ var errorMsg = errorMsgObj.value;
+
+ var statusLines = errorMsg ? errorMsg.split(/\r?\n/) : [];
+
+ var displayMsg;
+ if (statusLines && statusLines.length) {
+ // Display only first ten lines of error message
+ while (statusLines.length > 10) {
+ statusLines.pop();
+ }
+
+ displayMsg = statusLines.join("\n");
+
+ if (interactive) {
+ EnigmailDialog.info(window, displayMsg);
+ }
+ }
+ }
+
+ if (blockType == "MESSAGE" && exitCode === 0 && plainText.length === 0) {
+ plainText = " ";
+ }
+
+ if (!plainText) {
+ if (blockType != "SIGNED MESSAGE") {
+ return;
+ }
+
+ // Extract text portion of clearsign block
+ plainText = EnigmailArmor.extractSignaturePart(
+ pgpBlock,
+ EnigmailConstants.SIGNATURE_TEXT
+ );
+ }
+
+ const nsIMsgCompType = Ci.nsIMsgCompType;
+ var doubleDashSeparator = Services.prefs.getBoolPref(
+ "temp.openpgp.doubleDashSeparator"
+ );
+ if (
+ gMsgCompose.type != nsIMsgCompType.Template &&
+ gMsgCompose.type != nsIMsgCompType.Draft &&
+ doubleDashSeparator
+ ) {
+ var signOffset = plainText.search(/[\r\n]-- +[\r\n]/);
+
+ if (signOffset < 0 && blockType == "SIGNED MESSAGE") {
+ signOffset = plainText.search(/[\r\n]--[\r\n]/);
+ }
+
+ if (signOffset > 0) {
+ // Strip signature portion of quoted message
+ plainText = plainText.substr(0, signOffset + 1);
+ }
+ }
+
+ this.editorSelectAll();
+
+ //EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.decryptQuote: plainText='"+plainText+"'\n");
+
+ if (head) {
+ this.editorInsertText(head);
+ }
+
+ var quoteElement;
+
+ if (indentStr) {
+ quoteElement = this.editorInsertAsQuotation(plainText);
+ } else {
+ this.editorInsertText(plainText);
+ }
+
+ if (tail) {
+ this.editorInsertText(tail);
+ }
+
+ if (statusFlagsObj.value & EnigmailConstants.DECRYPTION_OKAY) {
+ this.checkInlinePgpReply(head, tail);
+ }
+
+ if (interactive) {
+ return;
+ }
+
+ // Position cursor
+ var replyOnTop = gCurrentIdentity.replyOnTop;
+
+ if (!indentStr || !quoteElement) {
+ replyOnTop = 1;
+ }
+
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.decryptQuote: replyOnTop=" +
+ replyOnTop +
+ ", quoteElement=" +
+ quoteElement +
+ "\n"
+ );
+
+ if (this.editor.selectionController) {
+ var selection = this.editor.selectionController;
+ selection.completeMove(false, false); // go to start;
+
+ switch (replyOnTop) {
+ case 0:
+ // Position after quote
+ this.editor.endOfDocument();
+ if (tail) {
+ for (let cPos = 0; cPos < tail.length; cPos++) {
+ selection.characterMove(false, false); // move backwards
+ }
+ }
+ break;
+
+ case 2:
+ // Select quote
+
+ if (head) {
+ for (let cPos = 0; cPos < head.length; cPos++) {
+ selection.characterMove(true, false);
+ }
+ }
+ selection.completeMove(true, true);
+ if (tail) {
+ for (let cPos = 0; cPos < tail.length; cPos++) {
+ selection.characterMove(false, true); // move backwards
+ }
+ }
+ break;
+
+ default:
+ // Position at beginning of document
+
+ if (this.editor) {
+ this.editor.beginningOfDocument();
+ }
+ }
+
+ this.editor.selectionController.scrollSelectionIntoView(
+ Ci.nsISelectionController.SELECTION_NORMAL,
+ Ci.nsISelectionController.SELECTION_ANCHOR_REGION,
+ true
+ );
+ }
+
+ //this.processFinalState();
+ },
+
+ checkInlinePgpReply(head, tail) {
+ const CT = Ci.nsIMsgCompType;
+ let hLines = head.search(/[^\s>]/) < 0 ? 0 : 1;
+
+ if (hLines > 0) {
+ switch (gMsgCompose.type) {
+ case CT.Reply:
+ case CT.ReplyAll:
+ case CT.ReplyToSender:
+ case CT.ReplyToGroup:
+ case CT.ReplyToSenderAndGroup:
+ case CT.ReplyToList: {
+ // if head contains at only a few line of text, we assume it's the
+ // header above the quote (e.g. XYZ wrote:) and the user's signature
+
+ let h = head.split(/\r?\n/);
+ hLines = -1;
+
+ for (let i = 0; i < h.length; i++) {
+ if (h[i].search(/[^\s>]/) >= 0) {
+ hLines++;
+ }
+ }
+ }
+ }
+ }
+
+ if (
+ hLines > 0 &&
+ (!gCurrentIdentity.sigOnReply || gCurrentIdentity.sigBottom)
+ ) {
+ // display warning if no signature on top of message
+ this.displayPartialEncryptedWarning();
+ } else if (hLines > 10) {
+ this.displayPartialEncryptedWarning();
+ } else if (
+ tail.search(/[^\s>]/) >= 0 &&
+ !(gCurrentIdentity.sigOnReply && gCurrentIdentity.sigBottom)
+ ) {
+ // display warning if no signature below message
+ this.displayPartialEncryptedWarning();
+ }
+ },
+
+ editorInsertText(plainText) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.editorInsertText\n"
+ );
+ if (this.editor) {
+ var mailEditor;
+ try {
+ mailEditor = this.editor.QueryInterface(Ci.nsIEditorMailSupport);
+ mailEditor.insertTextWithQuotations(plainText);
+ } catch (ex) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.editorInsertText: no mail editor\n"
+ );
+ this.editor.insertText(plainText);
+ }
+ }
+ },
+
+ editorInsertAsQuotation(plainText) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.editorInsertAsQuotation\n"
+ );
+ if (this.editor) {
+ var mailEditor;
+ try {
+ mailEditor = this.editor.QueryInterface(Ci.nsIEditorMailSupport);
+ } catch (ex) {}
+
+ if (!mailEditor) {
+ return 0;
+ }
+
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.editorInsertAsQuotation: mailEditor=" +
+ mailEditor +
+ "\n"
+ );
+
+ mailEditor.insertAsCitedQuotation(plainText, "", false);
+
+ return 1;
+ }
+ return 0;
+ },
+
+ isSenderKeyExpired() {
+ const senderKeyId = this.getSenderUserId();
+
+ if (senderKeyId) {
+ const key = EnigmailKeyRing.getKeyById(senderKeyId);
+ return key?.expiryTime && Math.round(Date.now() / 1000) > key.expiryTime;
+ }
+
+ return false;
+ },
+
+ removeNotificationIfPresent(name) {
+ const notif = gComposeNotification.getNotificationWithValue(name);
+ if (notif) {
+ gComposeNotification.removeNotification(notif);
+ }
+ },
+
+ warnUserThatSenderKeyExpired() {
+ const label = {
+ "l10n-id": "openpgp-selection-status-error",
+ "l10n-args": { key: this.getSenderUserId() },
+ };
+
+ const buttons = [
+ {
+ "l10n-id": "settings-context-open-account-settings-item2",
+ callback() {
+ MsgAccountManager(
+ "am-e2e.xhtml",
+ MailServices.accounts.getServersForIdentity(gCurrentIdentity)[0]
+ );
+ Services.wm.getMostRecentWindow("mail:3pane")?.focus();
+ return true;
+ },
+ },
+ ];
+
+ gComposeNotification.appendNotification(
+ "openpgpSenderKeyExpired",
+ {
+ label,
+ priority: gComposeNotification.PRIORITY_WARNING_MEDIUM,
+ },
+ buttons
+ );
+ },
+
+ warnUserIfSenderKeyExpired() {
+ if (!this.isSenderKeyExpired()) {
+ this.removeNotificationIfPresent("openpgpSenderKeyExpired");
+ return;
+ }
+
+ this.warnUserThatSenderKeyExpired();
+ },
+
+ /**
+ * Display a notification to the user at the bottom of the window
+ *
+ * @param priority: Number - Priority of the message [1 = high (error) ... 3 = low (info)]
+ * @param msgText: String - Text to be displayed in notification bar
+ * @param messageId: String - Unique message type identification
+ * @param detailsText: String - optional text to be displayed by clicking on "Details" button.
+ * if null or "", then the Detail button will no be displayed.
+ */
+ async notifyUser(priority, msgText, messageId, detailsText) {
+ let prio;
+
+ switch (priority) {
+ case 1:
+ prio = gComposeNotification.PRIORITY_CRITICAL_MEDIUM;
+ break;
+ case 3:
+ prio = gComposeNotification.PRIORITY_INFO_MEDIUM;
+ break;
+ default:
+ prio = gComposeNotification.PRIORITY_WARNING_MEDIUM;
+ }
+
+ let buttonArr = [];
+
+ if (detailsText && detailsText.length > 0) {
+ let [accessKey, label] = await document.l10n.formatValues([
+ { id: "msg-compose-details-button-access-key" },
+ { id: "msg-compose-details-button-label" },
+ ]);
+
+ buttonArr.push({
+ accessKey,
+ label,
+ callback(aNotificationBar, aButton) {
+ EnigmailDialog.info(window, detailsText);
+ },
+ });
+ }
+ gComposeNotification.appendNotification(
+ messageId,
+ {
+ label: msgText,
+ priority: prio,
+ },
+ buttonArr
+ );
+ },
+
+ /**
+ * Display a warning message if we are replying to or forwarding
+ * a partially decrypted inline-PGP email
+ */
+ async displayPartialEncryptedWarning() {
+ let [msgLong, msgShort] = await document.l10n.formatValues([
+ { id: "msg-compose-partially-encrypted-inlinePGP" },
+ { id: "msg-compose-partially-encrypted-short" },
+ ]);
+
+ this.notifyUser(1, msgShort, "notifyPartialDecrypt", msgLong);
+ },
+
+ editorSelectAll() {
+ if (this.editor) {
+ this.editor.selectAll();
+ }
+ },
+
+ editorGetCharset() {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.editorGetCharset\n"
+ );
+ return this.editor.documentCharacterSet;
+ },
+
+ editorGetContentAs(mimeType, flags) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: Enigmail.msg.editorGetContentAs\n"
+ );
+ if (this.editor) {
+ return this.editor.outputToString(mimeType, flags);
+ }
+
+ return null;
+ },
+
+ async focusChange() {
+ // call original TB function
+ CommandUpdate_MsgCompose();
+
+ var focusedWindow = top.document.commandDispatcher.focusedWindow;
+
+ // we're just setting focus to where it was before
+ if (focusedWindow == Enigmail.msg.lastFocusedWindow) {
+ // skip
+ return;
+ }
+
+ Enigmail.msg.lastFocusedWindow = focusedWindow;
+ },
+
+ /**
+ * Merge multiple Re: Re: into one Re: in message subject
+ */
+ fixMessageSubject() {
+ let subjElem = document.getElementById("msgSubject");
+ if (subjElem) {
+ let r = subjElem.value.replace(/^(Re: )+/, "Re: ");
+ if (r !== subjElem.value) {
+ subjElem.value = r;
+ if (typeof subjElem.oninput === "function") {
+ subjElem.oninput();
+ }
+ }
+ }
+ },
+};
+
+Enigmail.composeStateListener = {
+ NotifyComposeFieldsReady() {
+ // Note: NotifyComposeFieldsReady is only called when a new window is created (i.e. not in case a window object is reused).
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: ECSL.NotifyComposeFieldsReady\n"
+ );
+
+ try {
+ Enigmail.msg.editor = gMsgCompose.editor.QueryInterface(Ci.nsIEditor);
+ } catch (ex) {}
+
+ if (!Enigmail.msg.editor) {
+ return;
+ }
+
+ Enigmail.msg.fixMessageSubject();
+
+ function enigDocStateListener() {}
+
+ enigDocStateListener.prototype = {
+ QueryInterface: ChromeUtils.generateQI(["nsIDocumentStateListener"]),
+
+ NotifyDocumentWillBeDestroyed() {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: EDSL.enigDocStateListener.NotifyDocumentWillBeDestroyed\n"
+ );
+ },
+
+ NotifyDocumentStateChanged(nowDirty) {
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: EDSL.enigDocStateListener.NotifyDocumentStateChanged\n"
+ );
+ },
+ };
+
+ var docStateListener = new enigDocStateListener();
+
+ Enigmail.msg.editor.addDocumentStateListener(docStateListener);
+ },
+
+ ComposeProcessDone(aResult) {
+ // Note: called after a mail was sent (or saved)
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: ECSL.ComposeProcessDone: " + aResult + "\n"
+ );
+
+ if (aResult != Cr.NS_OK) {
+ Enigmail.msg.removeAttachedKey();
+ }
+
+ // ensure that securityInfo is set back to S/MIME flags (especially required if draft was saved)
+ if (gSMFields) {
+ Enigmail.msg.setSecurityParams(gSMFields);
+ }
+ },
+
+ NotifyComposeBodyReady() {
+ EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: ECSL.ComposeBodyReady\n");
+
+ var isEmpty, isEditable;
+
+ isEmpty = Enigmail.msg.editor.documentIsEmpty;
+ isEditable = Enigmail.msg.editor.isDocumentEditable;
+ Enigmail.msg.composeBodyReady = true;
+
+ EnigmailLog.DEBUG(
+ "enigmailMsgComposeOverlay.js: ECSL.ComposeBodyReady: isEmpty=" +
+ isEmpty +
+ ", isEditable=" +
+ isEditable +
+ "\n"
+ );
+
+ /*
+ if (Enigmail.msg.disableSmime) {
+ if (gMsgCompose && gMsgCompose.compFields && Enigmail.msg.getSecurityParams()) {
+ let si = Enigmail.msg.getSecurityParams(null);
+ si.signMessage = false;
+ si.requireEncryptMessage = false;
+ }
+ else {
+ EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: ECSL.ComposeBodyReady: could not disable S/MIME\n");
+ }
+ }
+ */
+
+ if (isEditable && !isEmpty) {
+ if (!Enigmail.msg.timeoutId && !Enigmail.msg.dirty) {
+ Enigmail.msg.timeoutId = setTimeout(function () {
+ Enigmail.msg.decryptQuote(false);
+ }, 0);
+ }
+ }
+
+ // This must be called by the last registered NotifyComposeBodyReady()
+ // stateListener. We need this in order to know when the entire init
+ // sequence of the composeWindow has finished, so the WebExtension compose
+ // API can do its final modifications.
+ window.composeEditorReady = true;
+ window.dispatchEvent(new CustomEvent("compose-editor-ready"));
+ },
+
+ SaveInFolderDone(folderURI) {
+ //EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: ECSL.SaveInFolderDone\n");
+ },
+};
+
+window.addEventListener(
+ "load",
+ Enigmail.msg.composeStartup.bind(Enigmail.msg),
+ {
+ capture: false,
+ once: true,
+ }
+);
+
+window.addEventListener("compose-window-unload", () => {
+ if (gMsgCompose) {
+ gMsgCompose.UnregisterStateListener(Enigmail.composeStateListener);
+ }
+});