diff --git a/ui/content/enigmailMsgComposeOverlay.js b/ui/content/enigmailMsgComposeOverlay.js index de8f9121..1b051504 100644 --- a/ui/content/enigmailMsgComposeOverlay.js +++ b/ui/content/enigmailMsgComposeOverlay.js @@ -1,5170 +1,5170 @@ /*global Components: false, EnigmailLocale: false, EnigmailApp: false, Dialog: false, EnigmailTimer: false */ /* * 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/. */ "use strict"; /*globally available Thunderbird variables/object/functions: */ /*global MimeBody: false, MimeUnknown: false, MimeMessageAttachment: false, gMsgCompose: false, getCurrentIdentity: false */ /*global msgHdrToMimeMessage: false, MimeMessage: false, MimeContainer: false, UpdateAttachmentBucket: false, gContentChanged: true */ /*global AddAttachments: false, AddAttachment: false, ChangeAttachmentBucketVisibility: false, GetResourceFromUri: false */ /*global Recipients2CompFields: false, Attachments2CompFields: false, DetermineConvertibility: false, gWindowLocked: false */ /*global CommandUpdate_MsgCompose: false, gSMFields: false, setSecuritySettings: false */ /*global Sendlater3Composing: false */ Components.utils.import("resource://enigmail/glodaMime.jsm"); Components.utils.import("resource://enigmail/core.jsm"); /*global EnigmailCore: false */ Components.utils.import("resource://enigmail/funcs.jsm"); /*global EnigmailFuncs: false */ Components.utils.import("resource://enigmail/log.jsm"); /*global EnigmailLog: false */ Components.utils.import("resource://enigmail/prefs.jsm"); /*global EnigmailPrefs: false */ Components.utils.import("resource://enigmail/os.jsm"); /*global EnigmailOS: false */ Components.utils.import("resource://enigmail/armor.jsm"); /*global EnigmailArmor: false */ Components.utils.import("resource://enigmail/locale.jsm"); /*global EnigmailLocale: false */ Components.utils.import("resource://enigmail/files.jsm"); /*global EnigmailFiles: false */ Components.utils.import("resource://enigmail/data.jsm"); /*global EnigmailData: false */ Components.utils.import("resource://enigmail/app.jsm"); /*global EnigmailApp: false */ Components.utils.import("resource://enigmail/dialog.jsm"); /*global EnigmailDialog: false */ Components.utils.import("resource://enigmail/timer.jsm"); /*global EnigmailTimer: false */ Components.utils.import("resource://enigmail/windows.jsm"); /* global EnigmailWindows: false */ Components.utils.import("resource://enigmail/events.jsm"); /*global EnigmailEvents: false */ Components.utils.import("resource://enigmail/keyRing.jsm"); /*global EnigmailKeyRing: false */ Components.utils.import("resource://enigmail/uris.jsm"); /*global EnigmailURIs: false */ Components.utils.import("resource://enigmail/constants.jsm"); /*global EnigmailConstants: false */ Components.utils.import("resource://enigmail/passwords.jsm"); /*global EnigmailPassword: false */ Components.utils.import("resource://enigmail/rules.jsm"); /*global EnigmailRules: false */ Components.utils.import("resource://enigmail/clipboard.jsm"); /*global EnigmailClipboard: false */ Components.utils.import("resource://enigmail/pEpAdapter.jsm"); /*global EnigmailPEPAdapter: false */ Components.utils.import("resource://enigmail/pEpDecrypt.jsm"); /*global EnigmailPEPDecrypt: false */ Components.utils.import("resource://gre/modules/jsmime.jsm"); /*global jsmime: false*/ try { Components.utils.import("resource:///modules/MailUtils.js"); /*global MailUtils: false */ } catch (ex) {} if (!Enigmail) 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: null, processed: null, timeoutId: null, sendPgpMime: false, 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 reasons for encryption: reasonEncrypted: "", reasonSigned: "", // encrypt/sign/pgpmime according to rules? // (1:ENIG_UNDEF(undef/maybe), 0:ENIG_NEVER(never/forceNo), 2:ENIG_ALWAYS(always/forceYes), // 22:ENIG_AUTO_ALWAYS, 99:ENIG_CONFLICT(conflict)) encryptByRules: EnigmailConstants.ENIG_UNDEF, signByRules: EnigmailConstants.ENIG_UNDEF, pgpmimeByRules: EnigmailConstants.ENIG_UNDEF, // forced to encrypt/sign/pgpmime? // (1:ENIG_UNDEF(undef/maybe), 0:ENIG_NEVER(never/forceNo), 2:ENIG_ALWAYS(always/forceYes)) encryptForced: EnigmailConstants.ENIG_UNDEF, signForced: EnigmailConstants.ENIG_UNDEF, pgpmimeForced: EnigmailConstants.ENIG_UNDEF, finalSignDependsOnEncrypt: false, // does signing finally depends on encryption mode? // resulting final encrypt/sign/pgpmime mode: // (-1:ENIG_FINAL_UNDEF, 0:ENIG_FINAL_NO, 1:ENIG_FINAL_YES, 10:ENIG_FINAL_FORCENO, 11:ENIG_FINAL_FORCEYES, 99:ENIG_FINAL_CONFLICT) statusEncrypted: EnigmailConstants.ENIG_FINAL_UNDEF, statusSigned: EnigmailConstants.ENIG_FINAL_UNDEF, statusPGPMime: EnigmailConstants.ENIG_FINAL_UNDEF, statusEncryptedInStatusBar: null, // last statusEncyrpted when processing status buttons // to find possible broken promise of encryption // is OpenPGP encryption possible without displaying the key selection dialog? autoPgpEncryption: false, // processed strings to signal final encrypt/sign/pgpmime state: statusEncryptedStr: "???", statusSignedStr: "???", statusPGPMimeStr: "???", statusSMimeStr: "???", statusInlinePGPStr: "???", statusAttachOwnKey: "???", juniorMode: false, origPepRating: null, sendProcess: false, composeBodyReady: false, identity: null, enableRules: null, modifiedAttach: null, lastFocusedWindow: null, determineSendFlagId: null, trustAllKeys: false, protectHeaders: false, attachOwnKeyObj: { appendAttachment: false, attachedObj: null, attachedKey: null }, compFieldsEnig_CID: "@mozdev.org/enigmail/composefields;1", saveDraftError: 0, composeStartup: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.composeStartup\n"); function delayedProcessFinalState() { EnigmailTimer.setTimeout(function _f() { Enigmail.msg.processFinalState(); Enigmail.msg.updateStatusBar(); }, 50); } function addSecurityListener(itemId, func) { let s = document.getElementById(itemId); if (s) { s.addEventListener("command", func); } else { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: addSecurityListener - cannot find element " + itemId + "\n"); } } // Relabel SMIME button and menu item var smimeButton = document.getElementById("button-security"); if (smimeButton) { smimeButton.setAttribute("label", "S/MIME"); } var msgId = document.getElementById("msgIdentityPopup"); if (msgId) { msgId.addEventListener("command", Enigmail.msg.setIdentityCallback); } var subj = document.getElementById("msgSubject"); subj.addEventListener('focus', Enigmail.msg.fireSendFlags); // listen to S/MIME changes to potentially display "conflict" message addSecurityListener("menu_securitySign1", delayedProcessFinalState); addSecurityListener("menu_securitySign2", delayedProcessFinalState); addSecurityListener("menu_securityEncryptRequire1", delayedProcessFinalState); addSecurityListener("menu_securityEncryptRequire2", delayedProcessFinalState); this.msgComposeReset(false); // false => not closing => call setIdentityDefaults() this.composeOpen(); this.processFinalState(); this.updateStatusBar(); }, composeUnload: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.composeUnload\n"); //if (gMsgCompose) // gMsgCompose.UnregisterStateListener(Enigmail.composeStateListener); }, handleClick: function(event, modifyType) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.handleClick\n"); switch (event.button) { case 2: // do not process the event any futher // needed on Windows to prevent displaying the context menu event.preventDefault(); this.doPgpButton(); break; case 0: this.doPgpButton(modifyType); break; } }, setIdentityCallback: function(elementId) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.setIdentityCallback: elementId=" + elementId + "\n"); EnigmailTimer.setTimeout(function _f() { Enigmail.msg.setIdentityDefaults(); }, 50); }, /* 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"); if (this.isEnigmailEnabled()) { var res = null; switch (key) { case 'sign': res = (this.identity.getIntAttribute("defaultSigningPolicy") > 0); // converts int property to bool property break; case 'encrypt': res = (this.identity.getIntAttribute("defaultEncryptionPolicy") > 0); // converts int property to bool property break; case 'pgpMimeMode': res = this.identity.getBoolAttribute(key); break; case 'signIfNotEnc': res = this.identity.getBoolAttribute("pgpSignPlain"); break; case 'signIfEnc': res = this.identity.getBoolAttribute("pgpSignEncrypted"); break; case 'attachPgpKey': res = this.identity.getBoolAttribute(key); break; } //EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.getAccDefault: "+key+"="+res+"\n"); return res; } else { // every detail is disabled if OpenPGP in general is disabled: switch (key) { case 'sign': case 'encrypt': case 'signIfNotEnc': case 'signIfEnc': case 'pgpMimeMode': case 'attachPgpKey': 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 */ getEncryptionEnabled: function() { if (this.juniorMode) return false; let id = getCurrentIdentity(); return ((id.getUnicharAttribute("encryption_cert_name") !== "") || this.isEnigmailEnabled()); }, /** * Determine if any of Enigmail (OpenPGP) or S/MIME signing is enabled for the account */ getSigningEnabled: function() { if (this.juniorMode) return false; let id = getCurrentIdentity(); return ((id.getUnicharAttribute("signing_cert_name") !== "") || this.isEnigmailEnabled()); }, getSmimeSigningEnabled: function() { if (this.juniorMode) return false; let id = getCurrentIdentity(); if (!id.getUnicharAttribute("signing_cert_name")) return false; return id.getBoolPref("sign_mail"); }, setIdentityDefaults: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.setIdentityDefaults\n"); this.identity = getCurrentIdentity(); if (this.isEnigmailEnabled()) { EnigmailFuncs.getSignMsg(this.identity); // convert old acc specific to new acc specific options } else { // reset status strings in menu to useful defaults this.statusEncryptedStr = EnigmailLocale.getString("encryptNo"); this.statusSignedStr = EnigmailLocale.getString("signNo", [""]); this.statusPGPMimeStr = EnigmailLocale.getString("pgpmimeNormal"); this.statusInlinePGPStr = EnigmailLocale.getString("inlinePGPNormal"); this.statusSMimeStr = EnigmailLocale.getString("smimeNormal"); this.statusAttachOwnKey = EnigmailLocale.getString("attachOwnKeyNo"); } if (this.juniorMode) { let pepBc = document.getElementById("enigmail-bc-pepEncrypt"); pepBc.setAttribute("encrypt", this.pepEnabled() ? "true" : "false"); } // reset default send settings, unless we have changed them already if (!this.sendModeDirty) { this.mimePreferOpenPGP = this.identity.getIntAttribute("mimePreferOpenPGP"); this.processAccountSpecificDefaultOptions(); this.determineSendFlags(); // important to use identity specific settings this.processFinalState(); this.updateStatusBar(); } }, // set the current default for sending a message // depending on the identity processAccountSpecificDefaultOptions: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.processAccountSpecificDefaultOptions\n"); const nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.SEND_ENCRYPTED; this.sendMode = 0; if (!this.isEnigmailEnabled()) { return; } if (this.getAccDefault("encrypt")) { this.sendMode |= ENCRYPT; this.reasonEncrypted = EnigmailLocale.getString("reasonEnabledByDefault"); } if (this.getAccDefault("sign")) { this.sendMode |= SIGN; this.reasonSigned = EnigmailLocale.getString("reasonEnabledByDefault"); } this.sendPgpMime = this.getAccDefault("pgpMimeMode"); this.attachOwnKeyObj.appendAttachment = this.getAccDefault("attachPgpKey"); this.setOwnKeyStatus(); this.attachOwnKeyObj.attachedObj = null; this.attachOwnKeyObj.attachedKey = null; this.finalSignDependsOnEncrypt = (this.getAccDefault("signIfEnc") || this.getAccDefault("signIfNotEnc")); }, getOriginalMsgUri: function() { let draftId = gMsgCompose.compFields.draftId; let msgUri = null; if (typeof(draftId) == "string" && draftId.length > 0) { // original message is draft msgUri = draftId.replace(/\?.*$/, ""); } else if (typeof(gMsgCompose.originalMsgURI) == "string" && gMsgCompose.originalMsgURI.length > 0) { // original message is a "true" mail msgUri = gMsgCompose.originalMsgURI; } return msgUri; }, getMsgHdr: function(msgUri) { if (!msgUri) { msgUri = this.getOriginalMsgUri(); } let messenger = Components.classes["@mozilla.org/messenger;1"].getService(Components.interfaces.nsIMessenger); return messenger.messageServiceFromURI(msgUri).messageURIToMsgHdr(msgUri); }, getMsgProperties: function(draft) { EnigmailLog.DEBUG("enigmailMessengerOverlay.js: Enigmail.msg.getMsgProperties:\n"); const nsIEnigmail = Components.interfaces.nsIEnigmail; let msgUri = this.getOriginalMsgUri(); let properties = 0; try { let msgHdr = this.getMsgHdr(msgUri); if (msgHdr) { this.setOriginalSubject(msgHdr.subject); properties = msgHdr.getUint32Property("enigmail"); if (draft) { try { msgHdrToMimeMessage(msgHdr, null, this.getMsgPropertiesCb, true, { examineEncryptedParts: true }); } catch (ex) { EnigmailLog.DEBUG("enigmailMessengerOverlay.js: Enigmail.msg.getMsgProperties: cannot use msgHdrToMimeMessage\n"); } } } } catch (ex) { EnigmailLog.DEBUG("enigmailMessengerOverlay.js: Enigmail.msg.getMsgProperties: got exception '" + ex.toString() + "'\n"); } if (EnigmailURIs.isEncryptedUri(msgUri)) { properties |= nsIEnigmail.DECRYPTION_OKAY; } return properties; }, getMsgPropertiesCb: function(msg, mimeMsg) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.getMsgPropertiesCb\n"); const nsIEnigmail = Components.interfaces.nsIEnigmail; var stat = ""; if (mimeMsg && mimeMsg.headers["x-enigmail-draft-status"]) { stat = String(mimeMsg.headers["x-enigmail-draft-status"]); } else { return; } EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.getMsgPropertiesCb: draftStatus: " + stat + "\n"); if (stat.substr(0, 1) == "N") { // new style drafts (Enigmail 1.7) var enc = "final-encryptDefault"; switch (Number(stat.substr(1, 1))) { case EnigmailConstants.ENIG_NEVER: enc = "final-encryptNo"; break; case EnigmailConstants.ENIG_ALWAYS: enc = "final-encryptYes"; } var sig = "final-signDefault"; switch (Number(stat.substr(2, 1))) { case EnigmailConstants.ENIG_NEVER: sig = "final-signNo"; break; case EnigmailConstants.ENIG_ALWAYS: sig = "final-signYes"; } var pgpMime = "final-pgpmimeDefault"; switch (Number(stat.substr(3, 1))) { case EnigmailConstants.ENIG_NEVER: pgpMime = "final-pgpmimeNo"; break; case EnigmailConstants.ENIG_ALWAYS: pgpMime = "final-pgpmimeYes"; } Enigmail.msg.setFinalSendMode(enc); Enigmail.msg.setFinalSendMode(sig); Enigmail.msg.setFinalSendMode(pgpMime); if (stat.substr(4, 1) == "1") Enigmail.msg.attachOwnKeyObj.appendAttachment = true; } else { // drafts from older versions of Enigmail var flags = Number(stat); if (flags & nsIEnigmail.SEND_SIGNED) Enigmail.msg.setFinalSendMode('final-signYes'); if (flags & nsIEnigmail.SEND_ENCRYPTED) Enigmail.msg.setFinalSendMode('final-encryptYes'); if (flags & nsIEnigmail.SEND_ATTACHMENT) Enigmail.msg.attachOwnKeyObj.appendAttachment = true; } Enigmail.msg.setOwnKeyStatus(); }, setOriginalSubject: function(subject) { const CT = Components.interfaces.nsIMsgCompType; let subjElem = document.getElementById("msgSubject"); let prefix = ""; if (!subjElem) return; switch (gMsgCompose.type) { case CT.ForwardInline: case CT.ForwardAsAttachment: prefix = this.getMailPref("mail.forward_subject_prefix") + ": "; } subject = jsmime.headerparser.decodeRFC2047Words(subject, "utf-8"); switch (gMsgCompose.type) { case CT.Draft: case CT.Template: case CT.ForwardInline: case CT.ForwardAsAttachment: gMsgCompose.compFields.subject = prefix + subject; subjElem.value = prefix + subject; break; } }, setupMenuAndToolbar: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.setupMenuAndToolbar\n"); let toolbarTxt = document.getElementById("enigmail-toolbar-text"); let encBroadcaster = document.getElementById("enigmail-bc-encrypt"); let signBroadcaster = document.getElementById("enigmail-bc-sign"); let attachBroadcaster = document.getElementById("enigmail-bc-attach"); let enigmailMenu = document.getElementById("menu_Enigmail"); let pepBroadcaster = document.getElementById("enigmail-bc-pepEncrypt"); let pepMenu = document.getElementById("menu_EnigmailPep"); let pepStatusbar = document.getElementById("enigmail-pep-statusbar"); if (this.juniorMode) { encBroadcaster.setAttribute("hidden", "true"); signBroadcaster.setAttribute("hidden", "true"); attachBroadcaster.setAttribute("hidden", "true"); if (toolbarTxt) { toolbarTxt.setAttribute("hidden", "true"); } enigmailMenu.setAttribute("hidden", "true"); pepBroadcaster.removeAttribute("hidden"); pepMenu.removeAttribute("hidden"); pepStatusbar.removeAttribute("hidden"); this.setFinalSendMode("final-encryptNo"); this.setFinalSendMode("final-signNo"); this.setFinalSendMode("final-pgpmimeNo"); this.updateStatusBar(); } else { encBroadcaster.removeAttribute("hidden"); signBroadcaster.removeAttribute("hidden"); attachBroadcaster.removeAttribute("hidden"); if (toolbarTxt) { toolbarTxt.removeAttribute("hidden"); } enigmailMenu.removeAttribute("hidden"); pepBroadcaster.setAttribute("hidden", "true"); pepMenu.setAttribute("hidden", "true"); pepStatusbar.setAttribute("hidden", "true"); } }, composeOpen: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.composeOpen\n"); const nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.SEND_ENCRYPTED; var msgFlags; var msgUri = null; var msgIsDraft = false; this.juniorMode = EnigmailPEPAdapter.getPepJuniorMode(); this.setupMenuAndToolbar(); this.determineSendFlagId = null; this.disableSmime = false; this.saveDraftError = 0; this.protectHeaders = EnigmailPrefs.getPref("protectHeaders"); this.enableUndoEncryption(false); this.displayProtectHeadersStatus(); if (this.juniorMode) { this.getOriginalPepMsgRating(); } var toobarElem = document.getElementById("composeToolbar2"); if (toobarElem && (EnigmailOS.getOS() == "Darwin")) { toobarElem.setAttribute("platform", "macos"); } // check rules for status bar icons on each change of the recipients var adrCol = document.getElementById("addressCol2#1"); // recipients field if (adrCol) { let attr = adrCol.getAttribute("oninput"); adrCol.setAttribute("oninput", attr + "; Enigmail.msg.addressOnChange(this);"); attr = adrCol.getAttribute("onchange"); adrCol.setAttribute("onchange", attr + "; Enigmail.msg.addressOnChange(this);"); adrCol.setAttribute("observes", "enigmail-bc-sendprocess"); } adrCol = document.getElementById("addressCol1#1"); // to/cc/bcc/... field if (adrCol) { let attr = adrCol.getAttribute("oncommand"); adrCol.setAttribute("oncommand", attr + "; Enigmail.msg.addressOnChange(this);"); adrCol.setAttribute("observes", "enigmail-bc-sendprocess"); } var draftId = gMsgCompose.compFields.draftId; if (EnigmailPrefs.getPref("keepSettingsForReply") && (!(this.sendMode & ENCRYPT)) || (typeof(draftId) == "string" && draftId.length > 0)) { msgUri = this.getOriginalMsgUri(); if (typeof(draftId) == "string" && draftId.length > 0) { // original message is draft msgIsDraft = true; } if (msgUri) { msgFlags = this.getMsgProperties(msgIsDraft); if (!msgIsDraft) { if (msgFlags & nsIEnigmail.DECRYPTION_OKAY) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.composeOpen: has encrypted originalMsgUri\n"); EnigmailLog.DEBUG("originalMsgURI=" + gMsgCompose.originalMsgURI + "\n"); this.setSendMode('encrypt'); this.disableSmime = true; } else if (msgFlags & (nsIEnigmail.GOOD_SIGNATURE | nsIEnigmail.BAD_SIGNATURE | nsIEnigmail.UNVERIFIED_SIGNATURE)) { this.setSendMode('sign'); } } this.removeAttachedKey(); } } // check for attached signature files and remove them var bucketList = document.getElementById("attachmentBucket"); if (bucketList.hasChildNodes()) { var node = bucketList.firstChild; let nodeNumber = 0; while (node) { if (node.attachment.contentType == "application/pgp-signature") { if (!this.findRelatedAttachment(bucketList, node)) { node = bucketList.removeItemAt(nodeNumber); // Let's release the attachment object held by the node else it won't go away until the window is destroyed node.attachment = null; } } else { ++nodeNumber; } node = node.nextSibling; } if (!bucketList.hasChildNodes()) { try { // TB only UpdateAttachmentBucket(false); } catch (ex) {} } } try { // TB only UpdateAttachmentBucket(bucketList.hasChildNodes()); } catch (ex) {} this.processFinalState(); this.updateStatusBar(); }, getOriginalPepMsgRating: function() { let msgUri = this.getOriginalMsgUri(); let msgHdr = this.getMsgHdr(msgUri); if (msgHdr) { let r = msgHdr.getUint32Property("enigmailPep"); this.origPepRating = (r - (r & 0xFF)) >> 8; } }, // check if an signature is related to another attachment findRelatedAttachment: function(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; }, msgComposeReopen: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.msgComposeReopen\n"); this.msgComposeReset(false); // false => not closing => call setIdentityDefaults() this.composeOpen(); this.fireSendFlags(); EnigmailTimer.setTimeout(function _f() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay: re-determine send flags\n"); try { this.determineSendFlags(); this.processFinalState(); this.updateStatusBar(); } catch (ex) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay: re-determine send flags - ERROR: " + ex.toString() + "\n"); } }.bind(Enigmail.msg), 1000); }, msgComposeClose: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.msgComposeClose\n"); var ioServ; try { // we should delete the original temporary files of the encrypted or signed // inline PGP attachments (the rest is done automatically) if (this.modifiedAttach) { ioServ = Components.classes[IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService); if (!ioServ) return; for (var i in this.modifiedAttach) { if (this.modifiedAttach[i].origTemp) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.msgComposeClose: deleting " + this.modifiedAttach[i].origUrl + "\n"); var fileUri = ioServ.newURI(this.modifiedAttach[i].origUrl, null, null); var fileHandle = Components.classes[LOCAL_FILE_CONTRACTID].createInstance(Components.interfaces.nsIFile); fileHandle.initWithPath(fileUri.path); if (fileHandle.exists()) fileHandle.remove(false); } } this.modifiedAttach = null; } } catch (ex) { EnigmailLog.ERROR("enigmailMsgComposeOverlay.js: ECSL.ComposeProcessDone: could not delete all files:\n" + ex.toString() + "\n"); } this.msgComposeReset(true); // true => closing => don't call setIdentityDefaults() }, msgComposeReset: function(closing) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.msgComposeReset\n"); this.dirty = 0; this.processed = null; this.timeoutId = null; this.modifiedAttach = null; this.sendMode = 0; this.sendModeDirty = false; this.reasonEncrypted = ""; this.reasonSigned = ""; this.encryptByRules = EnigmailConstants.ENIG_UNDEF; this.signByRules = EnigmailConstants.ENIG_UNDEF; this.pgpmimeByRules = EnigmailConstants.ENIG_UNDEF; this.signForced = EnigmailConstants.ENIG_UNDEF; this.encryptForced = EnigmailConstants.ENIG_UNDEF; this.pgpmimeForced = EnigmailConstants.ENIG_UNDEF; this.finalSignDependsOnEncrypt = false; this.statusSigned = EnigmailConstants.ENIG_FINAL_UNDEF; this.statusEncrypted = EnigmailConstants.ENIG_FINAL_UNDEF; this.statusPGPMime = EnigmailConstants.ENIG_FINAL_UNDEF; this.statusEncryptedStr = "???"; this.statusSignedStr = "???"; this.statusPGPMimeStr = "???"; this.statusInlinePGPStr = "???"; this.statusAttachOwnKey = "???"; this.enableRules = true; this.identity = null; this.sendProcess = false; this.trustAllKeys = false; this.mimePreferOpenPGP = 0; this.origPepRating = null; if (!closing) { this.setIdentityDefaults(); } }, initRadioMenu: function(prefName, optionIds) { EnigmailLog.DEBUG("enigmailMessengerOverlay.js: Enigmail.msg.initRadioMenu: " + prefName + "\n"); var encryptId; var prefValue = EnigmailPrefs.getPref(prefName); if (prefValue >= optionIds.length) return; var menuItem = document.getElementById("enigmail_" + optionIds[prefValue]); if (menuItem) menuItem.setAttribute("checked", "true"); }, usePpgMimeOption: function(value) { EnigmailLog.DEBUG("enigmailMessengerOverlay.js: Enigmail.msg.usePpgMimeOption: " + value + "\n"); EnigmailPrefs.setPref("usePGPMimeOption", value); return true; }, tempTrustAllKeys: function() { this.trustAllKeys = !this.trustAllKeys; }, toggleAttachOwnKey: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.toggleAttachOwnKey\n"); EnigmailCore.getService(window); // make sure Enigmail is loaded and working this.attachOwnKeyObj.appendAttachment = !this.attachOwnKeyObj.appendAttachment; this.setOwnKeyStatus(); }, toggleProtectHeaders: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.toggleProtectHeaders\n"); EnigmailCore.getService(window); // make sure Enigmail is loaded and working this.protectHeaders = !this.protectHeaders; this.displayProtectHeadersStatus(); }, displayProtectHeadersStatus: function() { let bc = document.getElementById("enigmail-bc-protectHdr"); if (this.protectHeaders) { bc.setAttribute("checked", "true"); } else { bc.removeAttribute("checked"); } }, /*** * set broadcaster to display whether the own key is attached or not */ setOwnKeyStatus: function() { let bc = document.getElementById("enigmail-bc-attach"); let attachIcon = document.getElementById("button-enigmail-attach"); if (this.allowAttachOwnKey() === 0) { this.statusAttachOwnKey = EnigmailLocale.getString("attachOwnKeyDisabled"); } else { if (this.attachOwnKeyObj.appendAttachment) { bc.setAttribute("addPubkey", "true"); bc.setAttribute("checked", "true"); this.statusAttachOwnKey = EnigmailLocale.getString("attachOwnKeyYes"); } else { bc.setAttribute("addPubkey", "false"); bc.removeAttribute("checked"); this.statusAttachOwnKey = EnigmailLocale.getString("attachOwnKeyNo"); } } if (attachIcon) attachIcon.setAttribute("tooltiptext", this.statusAttachOwnKey); }, attachOwnKey: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.attachOwnKey:\n"); var userIdValue; if (this.identity.getIntAttribute("pgpKeyMode") > 0) { userIdValue = this.identity.getCharAttribute("pgpkeyId"); if (this.attachOwnKeyObj.attachedKey && (this.attachOwnKeyObj.attachedKey != userIdValue)) { // remove attached key if user ID changed this.removeAttachedKey(); } if (!this.attachOwnKeyObj.attachedKey) { - var attachedObj = this.extractAndAttachKey([userIdValue]); + var attachedObj = this.extractAndAttachKey([userIdValue], true); if (attachedObj) { this.attachOwnKeyObj.attachedObj = attachedObj; this.attachOwnKeyObj.attachedKey = userIdValue; } } } else { EnigmailLog.ERROR("enigmailMsgComposeOverlay.js: Enigmail.msg.attachOwnKey: trying to attach unknown own key!\n"); } }, attachKey: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.attachKey: \n"); var resultObj = {}; var inputObj = {}; inputObj.dialogHeader = EnigmailLocale.getString("keysToExport"); inputObj.options = "multisel,allowexpired,nosending"; if (this.trustAllKeys) { inputObj.options += ",trustallkeys"; } var userIdValue = ""; window.openDialog("chrome://enigmail/content/enigmailKeySelection.xul", "", "dialog,modal,centerscreen,resizable", inputObj, resultObj); try { if (resultObj.cancelled) return; - this.extractAndAttachKey(resultObj.userList); + this.extractAndAttachKey(resultObj.userList, true); } catch (ex) { // cancel pressed -> do nothing return; } }, - extractAndAttachKey: function(uid) { + extractAndAttachKey: function(uid, warnOnError) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.extractAndAttachKey: \n"); var enigmailSvc = EnigmailCore.getService(window); if (!enigmailSvc) return null; var tmpDir = EnigmailFiles.getTempDir(); var tmpFile; try { tmpFile = Components.classes[LOCAL_FILE_CONTRACTID].createInstance(Components.interfaces.nsIFile); tmpFile.initWithPath(tmpDir); if (!(tmpFile.isDirectory() && tmpFile.isWritable())) { EnigmailDialog.alert(window, EnigmailLocale.getString("noTempDir")); return null; } } catch (ex) { EnigmailLog.writeException("enigmailMsgComposeOverlay.js: Enigmail.msg.extractAndAttachKey", ex); } tmpFile.append("key.asc"); tmpFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0x180); // equal 0600 // save file var exitCodeObj = {}; var errorMsgObj = {}; - EnigmailKeyRing.extractKey(false, uid.join(" "), tmpFile /*.path */ , exitCodeObj, errorMsgObj); + EnigmailKeyRing.extractKey(false, uid.join(" "), tmpFile, exitCodeObj, errorMsgObj); if (exitCodeObj.value !== 0) { - EnigmailDialog.alert(window, errorMsgObj.value); + if (warnOnError) EnigmailDialog.alert(window, errorMsgObj.value); return null; } // create attachment var ioServ = Components.classes[IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService); var tmpFileURI = ioServ.newFileURI(tmpFile); var keyAttachment = Components.classes["@mozilla.org/messengercompose/attachment;1"].createInstance(Components.interfaces.nsIMsgAttachment); keyAttachment.url = tmpFileURI.spec; if ((uid.length == 1) && (uid[0].search(/^(0x)?[a-fA-F0-9]+$/) === 0)) { keyAttachment.name = uid[0].substr(-16, 16) + ".asc"; if (keyAttachment.name.search(/^0x/) < 0) keyAttachment.name = "0x" + keyAttachment.name; } else { keyAttachment.name = "pgpkeys.asc"; } keyAttachment.temporary = true; keyAttachment.contentType = "application/pgp-keys"; // add attachment to msg this.addAttachment(keyAttachment); try { // TB only ChangeAttachmentBucketVisibility(false); } catch (ex) {} gContentChanged = true; return keyAttachment; }, addAttachment: function(attachment) { if (typeof(AddAttachment) == "undefined") { // TB >= 24 AddAttachments([attachment]); } else { // SeaMonkey AddAttachment(attachment); } }, enableUndoEncryption: function(newStatus) { let eue = document.getElementById("enigmail_undo_encryption"); if (newStatus) { eue.removeAttribute("disabled"); } else eue.setAttribute("disabled", "true"); }, /** * undo the encryption or signing; get back the original (unsigned/unencrypted) text * * useEditorUndo |Number|: > 0 use undo function of editor |n| times * 0: replace text with original text */ undoEncryption: function(useEditorUndo) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.undoEncryption:\n"); if (this.processed) { if (useEditorUndo) { EnigmailTimer.setTimeout(function _f() { Enigmail.msg.editor.undo(useEditorUndo); }, 10); } else { this.replaceEditorText(this.processed.origText); this.enableUndoEncryption(false); } this.processed = null; } else { this.decryptQuote(true); } var node; var nodeNumber; var bucketList = document.getElementById("attachmentBucket"); if (this.modifiedAttach && bucketList && bucketList.hasChildNodes()) { // undo inline encryption of attachments for (var i = 0; i < this.modifiedAttach.length; i++) { node = bucketList.firstChild; nodeNumber = -1; while (node) { ++nodeNumber; if (node.attachment.url == this.modifiedAttach[i].newUrl) { if (this.modifiedAttach[i].encrypted) { node.attachment.url = this.modifiedAttach[i].origUrl; node.attachment.name = this.modifiedAttach[i].origName; node.attachment.temporary = this.modifiedAttach[i].origTemp; node.attachment.contentType = this.modifiedAttach[i].origCType; } else { node = bucketList.removeItemAt(nodeNumber); // Let's release the attachment object held by the node else it won't go away until the window is destroyed node.attachment = null; } // delete encrypted file try { this.modifiedAttach[i].newFile.remove(false); } catch (ex) {} node = null; // next attachment please } else { node = node.nextSibling; } } } } this.removeAttachedKey(); }, removeAttachedKey: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.removeAttachedKey: \n"); var bucketList = document.getElementById("attachmentBucket"); var node = bucketList.firstChild; if (bucketList && bucketList.hasChildNodes() && this.attachOwnKeyObj.attachedObj) { // undo attaching own key var nodeNumber = -1; while (node) { ++nodeNumber; if (node.attachment.url == this.attachOwnKeyObj.attachedObj.url) { node = bucketList.removeItemAt(nodeNumber); // 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; } } if (!bucketList.hasChildNodes()) { try { // TB only ChangeAttachmentBucketVisibility(true); } catch (ex) {} } } }, resetUpdatedFields: function() { this.removeAttachedKey(); // reset subject if (gMsgCompose.compFields.securityInfo instanceof Components.interfaces.nsIEnigMsgCompFields) { let si = gMsgCompose.compFields.securityInfo.QueryInterface(Components.interfaces.nsIEnigMsgCompFields); if (si.originalSubject) { gMsgCompose.compFields.subject = si.originalSubject; } } }, replaceEditorText: function(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); }, getMsgFolderFromUri: function(uri, checkFolderAttributes) { let msgfolder = null; if (typeof MailUtils != 'undefined') { return MailUtils.getFolderForURI(uri, checkFolderAttributes); } try { // Postbox, older versions of TB let resource = GetResourceFromUri(uri); msgfolder = resource.QueryInterface(Components.interfaces.nsIMsgFolder); if (checkFolderAttributes) { if (!(msgfolder && (msgfolder.parent || msgfolder.isServer))) { msgfolder = null; } } } catch (ex) { //EnigmailLog.DEBUG("failed to get the folder resource\n"); } return msgfolder; }, goAccountManager: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.goAccountManager:\n"); EnigmailCore.getService(window); var currentId = null; var server = null; try { currentId = getCurrentIdentity(); var amService = Components.classes["@mozilla.org/messenger/account-manager;1"].getService(); var servers, folderURI; try { // Gecko >= 20 servers = amService.getServersForIdentity(currentId); folderURI = servers.queryElementAt(0, Components.interfaces.nsIMsgIncomingServer).serverURI; } catch (ex) { servers = amService.GetServersForIdentity(currentId); folderURI = servers.GetElementAt(0).QueryInterface(Components.interfaces.nsIMsgIncomingServer).serverURI; } server = this.getMsgFolderFromUri(folderURI, true).server; } catch (ex) {} window.openDialog("chrome://enigmail/content/am-enigprefs-edit.xul", "", "dialog,modal,centerscreen", { identity: currentId, account: server }); this.setIdentityDefaults(); }, /** * Determine if Enigmail is enabled for the account */ isEnigmailEnabled: function() { if (this.juniorMode) return false; return this.identity.getBoolAttribute("enablePgp"); }, doPgpButton: function(what) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.doPgpButton: what=" + what + "\n"); if (this.isEnigmailEnabled()) { EnigmailCore.getService(window); // try to access Enigmail to launch the wizard if needed } // ignore settings for this account? try { if (!this.getEncryptionEnabled() && !this.getSigningEnabled()) { if (EnigmailDialog.confirmDlg(window, EnigmailLocale.getString("configureNow"), EnigmailLocale.getString("msgCompose.button.configure"))) { // configure account settings for the first time this.goAccountManager(); if (!this.isEnigmailEnabled()) { return; } } else { return; } } } catch (ex) {} switch (what) { case 'sign': case 'encrypt': this.setSendMode(what); break; // menu entries: case 'final-signDefault': case 'final-signYes': case 'final-signNo': case 'final-encryptDefault': case 'final-encryptYes': case 'final-encryptNo': case 'final-pgpmimeDefault': case 'final-pgpmimeYes': case 'final-pgpmimeNo': case 'final-useSmime': case 'toggle-final-sign': case 'toggle-final-encrypt': case 'toggle-final-mime': this.setFinalSendMode(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 nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.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(); this.updateStatusBar(); }, // changes the FINAL sendMode // - triggered by the user interface setFinalSendMode: function(sendMode) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.setFinalSendMode: sendMode=" + sendMode + "\n"); const nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.SEND_ENCRYPTED; switch (sendMode) { // menu entries for final settings: case 'final-encryptDefault': // switch encryption to "use defaults & rules" if (this.encryptForced != EnigmailConstants.ENIG_UNDEF) { // if encrypt/noencrypt forced this.encryptForced = EnigmailConstants.ENIG_UNDEF; // back to defaults/rules } break; case 'final-encryptYes': // switch encryption to "force encryption" if (this.encryptForced != EnigmailConstants.ENIG_ALWAYS) { // if not forced to encrypt this.encryptForced = EnigmailConstants.ENIG_ALWAYS; // force to encrypt } break; case 'final-encryptNo': // switch encryption to "force no to encrypt" if (this.encryptForced != EnigmailConstants.ENIG_NEVER) { // if not forced not to encrypt this.encryptForced = EnigmailConstants.ENIG_NEVER; // force not to encrypt } break; case 'final-signDefault': // switch signing to "use defaults & rules" if (this.signForced != EnigmailConstants.ENIG_UNDEF) { // if sign/nosign forced // re-init if signing depends on encryption if this was broken before this.finalSignDependsOnEncrypt = (this.getAccDefault("signIfEnc") || this.getAccDefault("signIfNotEnc")); this.signForced = EnigmailConstants.ENIG_UNDEF; // back to defaults/rules } break; case 'final-signYes': if (this.signForced != EnigmailConstants.ENIG_ALWAYS) { // if not forced to sign this.signingNoLongerDependsOnEnc(); this.signForced = EnigmailConstants.ENIG_ALWAYS; // force to sign } break; case 'final-signNo': if (this.signForced != EnigmailConstants.ENIG_NEVER) { // if not forced not to sign this.signingNoLongerDependsOnEnc(); this.signForced = EnigmailConstants.ENIG_NEVER; // force not to sign } break; case 'final-pgpmimeDefault': if (this.pgpmimeForced != EnigmailConstants.ENIG_UNDEF) { // if any PGP mode forced this.pgpmimeForced = EnigmailConstants.ENIG_UNDEF; // back to defaults/rules } break; case 'final-pgpmimeYes': if (this.pgpmimeForced != EnigmailConstants.ENIG_ALWAYS) { // if not forced to PGP/Mime this.pgpmimeForced = EnigmailConstants.ENIG_ALWAYS; // force to PGP/Mime } break; case 'final-pgpmimeNo': if (this.pgpmimeForced != EnigmailConstants.ENIG_NEVER) { // if not forced not to PGP/Mime this.pgpmimeForced = EnigmailConstants.ENIG_NEVER; // force not to PGP/Mime } break; case 'final-useSmime': // this.pgpmimeForced = EnigmailConstants.ENIG_FORCE_SMIME; break; // status bar buttons: // - can only switch to force or not to force sign/enc case 'toggle-final-sign': this.signingNoLongerDependsOnEnc(); switch (this.statusSigned) { case EnigmailConstants.ENIG_FINAL_NO: case EnigmailConstants.ENIG_FINAL_FORCENO: this.signForced = EnigmailConstants.ENIG_ALWAYS; // force to sign break; case EnigmailConstants.ENIG_FINAL_YES: case EnigmailConstants.ENIG_FINAL_FORCEYES: this.signForced = EnigmailConstants.ENIG_NEVER; // force not to sign break; case EnigmailConstants.ENIG_FINAL_CONFLICT: this.signForced = EnigmailConstants.ENIG_NEVER; break; } break; case 'toggle-final-encrypt': if (this.juniorMode) { this.onPepEncryptButton(sendMode); return; } switch (this.statusEncrypted) { case EnigmailConstants.ENIG_FINAL_NO: case EnigmailConstants.ENIG_FINAL_FORCENO: this.encryptForced = EnigmailConstants.ENIG_ALWAYS; // force to encrypt break; case EnigmailConstants.ENIG_FINAL_YES: case EnigmailConstants.ENIG_FINAL_FORCEYES: this.encryptForced = EnigmailConstants.ENIG_NEVER; // force not to encrypt break; case EnigmailConstants.ENIG_FINAL_CONFLICT: this.encryptForced = EnigmailConstants.ENIG_NEVER; break; } break; case 'toggle-final-mime': switch (this.statusPGPMime) { case EnigmailConstants.ENIG_FINAL_NO: case EnigmailConstants.ENIG_FINAL_FORCENO: this.pgpmimeForced = EnigmailConstants.ENIG_ALWAYS; // force PGP/MIME break; case EnigmailConstants.ENIG_FINAL_YES: case EnigmailConstants.ENIG_FINAL_FORCEYES: this.pgpmimeForced = EnigmailConstants.ENIG_NEVER; // force Inline-PGP break; case EnigmailConstants.ENIG_FINAL_CONFLICT: this.pgpmimeForced = EnigmailConstants.ENIG_NEVER; break; } break; default: EnigmailDialog.alert(window, "Enigmail.msg.setFinalSendMode - unexpected value: " + sendMode); break; } // this is always a send mode change (only toggle effects) this.sendModeDirty = true; this.determineSendFlags(); //this.processFinalState(); //this.updateStatusBar(); }, /** 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.encryptByRules, this.signByRules, pgpmimeByRules - this.encryptForced, this.encryptSigned - uses as OUTPUT: - this.statusEncrypt, this.statusSign, this.statusPGPMime no return value */ processFinalState: function(sendFlags) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.processFinalState()\n"); if (this.juniorMode) return; const nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.SEND_ENCRYPTED; let encFinally = null; let encReason = ""; let signFinally = null; let signReason = ""; let pgpmimeFinally = null; // ------ 1. process OpenPGP status ------ // process resulting encrypt mode if (this.encryptForced == EnigmailConstants.ENIG_NEVER) { // force not to encrypt? encFinally = EnigmailConstants.ENIG_FINAL_FORCENO; encReason = EnigmailLocale.getString("reasonManuallyForced"); } else if (this.encryptForced == EnigmailConstants.ENIG_ALWAYS) { // force to encrypt? encFinally = EnigmailConstants.ENIG_FINAL_FORCEYES; encReason = EnigmailLocale.getString("reasonManuallyForced"); } else switch (this.encryptByRules) { case EnigmailConstants.ENIG_NEVER: encFinally = EnigmailConstants.ENIG_FINAL_NO; encReason = EnigmailLocale.getString("reasonByRecipientRules"); break; case EnigmailConstants.ENIG_UNDEF: if (this.sendMode & ENCRYPT) { encFinally = EnigmailConstants.ENIG_FINAL_YES; if (this.getAccDefault("encrypt")) { encReason = EnigmailLocale.getString("reasonEnabledByDefault"); } } else { encFinally = EnigmailConstants.ENIG_FINAL_NO; } break; case EnigmailConstants.ENIG_ALWAYS: encFinally = EnigmailConstants.ENIG_FINAL_YES; encReason = EnigmailLocale.getString("reasonByRecipientRules"); break; case EnigmailConstants.ENIG_AUTO_ALWAYS: encFinally = EnigmailConstants.ENIG_FINAL_YES; encReason = EnigmailLocale.getString("reasonByAutoEncryption"); break; case EnigmailConstants.ENIG_CONFLICT: encFinally = EnigmailConstants.ENIG_FINAL_CONFLICT; encReason = EnigmailLocale.getString("reasonByConflict"); break; } EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: encrypt=" + ((this.sendMode & ENCRYPT) !== 0) + " encryptByRules=" + this.encryptByRules + " encFinally=" + encFinally + "\n"); EnigmailLog.DEBUG(" encReason=" + encReason + "\n"); // process resulting sign mode if (this.signForced == EnigmailConstants.ENIG_NEVER) { // force not to sign? signFinally = EnigmailConstants.ENIG_FINAL_FORCENO; signReason = EnigmailLocale.getString("reasonManuallyForced"); } else if (this.signForced == EnigmailConstants.ENIG_ALWAYS) { // force to sign? signFinally = EnigmailConstants.ENIG_FINAL_FORCEYES; signReason = EnigmailLocale.getString("reasonManuallyForced"); } else switch (this.signByRules) { case EnigmailConstants.ENIG_NEVER: signFinally = EnigmailConstants.ENIG_FINAL_NO; signReason = EnigmailLocale.getString("reasonByRecipientRules"); break; case EnigmailConstants.ENIG_UNDEF: if (this.sendMode & SIGN) { signFinally = EnigmailConstants.ENIG_FINAL_YES; if (this.getAccDefault("sign")) { signReason = EnigmailLocale.getString("reasonEnabledByDefault"); } } else { signFinally = EnigmailConstants.ENIG_FINAL_NO; } break; case EnigmailConstants.ENIG_ALWAYS: signFinally = EnigmailConstants.ENIG_FINAL_YES; signReason = EnigmailLocale.getString("reasonByRecipientRules"); break; case EnigmailConstants.ENIG_CONFLICT: signFinally = EnigmailConstants.ENIG_FINAL_CONFLICT; signReason = EnigmailLocale.getString("reasonByConflict"); break; } EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: signed=" + ((this.sendMode & SIGN) !== 0) + " signByRules=" + this.signByRules + " signFinally=" + signFinally + "\n"); EnigmailLog.DEBUG(" signReason=" + signReason + "\n"); // process option to finally sign if encrypted/unencrypted // (unless rules force not to sign) //var derivedFromEncMode = false; if (this.finalSignDependsOnEncrypt) { if (this.signByRules == EnigmailConstants.ENIG_UNDEF) { // if final sign mode not clear yet //derivedFromEncMode = true; switch (encFinally) { case EnigmailConstants.ENIG_FINAL_YES: case EnigmailConstants.ENIG_FINAL_FORCEYES: if (this.getAccDefault("signIfEnc")) { signFinally = EnigmailConstants.ENIG_FINAL_YES; signReason = EnigmailLocale.getString("reasonByEncryptionMode"); } break; case EnigmailConstants.ENIG_FINAL_NO: case EnigmailConstants.ENIG_FINAL_FORCENO: if (this.getAccDefault("signIfNotEnc")) { signFinally = EnigmailConstants.ENIG_FINAL_YES; signReason = EnigmailLocale.getString("reasonByEncryptionMode"); } break; case EnigmailConstants.ENIG_FINAL_CONFLICT: if (this.getAccDefault("signIfEnc") && this.getAccDefault("signIfNotEnc")) { signFinally = EnigmailConstants.ENIG_FINAL_YES; signReason = EnigmailLocale.getString("reasonByEncryptionMode"); } else { signFinally = EnigmailConstants.ENIG_FINAL_CONFLICT; } break; } EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: derived signFinally=" + signFinally + "\n"); EnigmailLog.DEBUG(" signReason=" + signReason + "\n"); } } this.statusPGPMime = EnigmailConstants.ENIG_FINAL_UNDEF; // ------ 2. Process S/MIME status ------ if (gSMFields) { let r = this.tryEnablingSMime(encFinally, signFinally); encFinally = r.encFinally; signFinally = r.signFinally; // update the S/MIME GUI elements try { setSecuritySettings("1"); } catch (ex) {} try { setSecuritySettings("2"); } catch (ex) {} } // ------ 3. process final resulting protocol mode (inline-PGP / PGP/MIME / S/MIME) ------ if (this.statusPGPMime !== EnigmailConstants.ENIG_FINAL_SMIME && this.statusPGPMime !== EnigmailConstants.ENIG_FINAL_FORCESMIME) { // process resulting PGP/MIME mode if (this.pgpmimeForced === EnigmailConstants.ENIG_NEVER) { // force not to PGP/Mime? pgpmimeFinally = EnigmailConstants.ENIG_FINAL_FORCENO; } else if (this.pgpmimeForced === EnigmailConstants.ENIG_ALWAYS) { // force to PGP/Mime? pgpmimeFinally = EnigmailConstants.ENIG_FINAL_FORCEYES; } else switch (this.pgpmimeByRules) { case EnigmailConstants.ENIG_NEVER: pgpmimeFinally = EnigmailConstants.ENIG_FINAL_NO; break; case EnigmailConstants.ENIG_UNDEF: pgpmimeFinally = ((this.sendPgpMime || (this.sendMode & nsIEnigmail.SEND_PGP_MIME)) ? EnigmailConstants.ENIG_FINAL_YES : EnigmailConstants.ENIG_FINAL_NO); break; case EnigmailConstants.ENIG_ALWAYS: pgpmimeFinally = EnigmailConstants.ENIG_FINAL_YES; break; case EnigmailConstants.ENIG_CONFLICT: pgpmimeFinally = EnigmailConstants.ENIG_FINAL_CONFLICT; break; } this.statusPGPMime = pgpmimeFinally; } EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: pgpmimeByRules=" + this.pgpmimeByRules + " pgpmimeFinally=" + pgpmimeFinally + "\n"); this.statusEncrypted = encFinally; this.statusSigned = signFinally; this.reasonEncrypted = encReason; this.reasonSigned = signReason; }, /** * Try to enable S/MIME, repsecting the various Enigmail rules * * @param encFinally: Number - "final" encryption status before applying S/MIME * @param signFinally: Number - "final" signing status before applying S/MIME * * @return Object: * - encFinally: Number - new encryption status after trying S/MIME * - signFinally: Number - new signing status after trying S/MIME */ tryEnablingSMime: function(encFinally, signFinally) { let encryptSmime = false; gSMFields.requireEncryptMessage = false; gSMFields.signMessage = false; // do not try S/MIME encryption if one of the following applies: // - OpenPGP is preferred over S/MIME, and OpenPGP is possible // - OpenPGP is preferred over S/MIME, and OpenPGP is enabled by rules // - encryption is disabled by rules and encryption is not manually enabled // - encryption is manually disabled if (this.pgpmimeForced === EnigmailConstants.ENIG_FORCE_SMIME) { encryptSmime = true; } else if ((this.mimePreferOpenPGP === 1 && (this.autoPgpEncryption || this.encryptByRules === EnigmailConstants.ENIG_ALWAYS)) || (this.encryptByRules === EnigmailConstants.ENIG_NEVER && encFinally !== EnigmailConstants.ENIG_FINAL_FORCEYES) || (this.pgpmimeForced === EnigmailConstants.ENIG_NEVER || this.pgpmimeForced === EnigmailConstants.ENIG_ALWAYS) || encFinally === EnigmailConstants.ENIG_FINAL_FORCENO) { return { encFinally: encFinally, signFinally: signFinally }; } if (!encryptSmime) { if (EnigmailPrefs.getPref("autoSendEncrypted") == 1) { if (this.isSmimeEncryptionPossible()) { if (this.mimePreferOpenPGP === 0) { // S/MIME is preferred and encryption is possible encryptSmime = true; encFinally = EnigmailConstants.ENIG_FINAL_YES; } else if (encFinally === EnigmailConstants.ENIG_FINAL_NO || encFinally === EnigmailConstants.ENIG_FINAL_CONFLICT || !this.autoPgpEncryption) { // Enigmail is preferred but not possible; S/MIME enc. is possible encryptSmime = true; encFinally = EnigmailConstants.ENIG_FINAL_YES; } } } else if (encFinally === EnigmailConstants.ENIG_FINAL_FORCEYES) { if (this.isSmimeEncryptionPossible()) { if (this.mimePreferOpenPGP === 0 || (!this.autoPgpEncryption)) { // S/MIME is preferred and encryption is possible // or PGP/MIME is preferred but impossible encryptSmime = true; } } } } if (encryptSmime) { if (this.pgpmimeForced === EnigmailConstants.ENIG_FORCE_SMIME) { this.statusPGPMime = EnigmailConstants.ENIG_FINAL_FORCESMIME; } else this.statusPGPMime = EnigmailConstants.ENIG_FINAL_SMIME; if (encFinally === EnigmailConstants.ENIG_FINAL_YES || encFinally === EnigmailConstants.ENIG_FINAL_FORCEYES) { gSMFields.requireEncryptMessage = true; } if (signFinally === EnigmailConstants.ENIG_FINAL_YES || signFinally === EnigmailConstants.ENIG_FINAL_FORCEYES) { gSMFields.signMessage = true; } } else { gSMFields.requireEncryptMessage = false; if ((encFinally === EnigmailConstants.ENIG_FINAL_NO || encFinally === EnigmailConstants.ENIG_FINAL_FORCENO) && this.mimePreferOpenPGP === 0 && !this.autoPgpEncryption && (signFinally === EnigmailConstants.ENIG_FINAL_YES || signFinally === EnigmailConstants.ENIG_FINAL_FORCEYES)) { // S/MIME is preferred this.statusPGPMime = EnigmailConstants.ENIG_FINAL_SMIME; gSMFields.signMessage = true; } else { gSMFields.signMessage = false; } } return { encFinally: encFinally, signFinally: signFinally }; }, // process icon/strings of status bar buttons and menu entries according to final encrypt/sign/pgpmime status // - uses as INPUT: // - this.statusEncrypt, this.statusSign, this.statusPGPMime // - uses as OUTPUT: // - resulting icon symbols // - this.statusEncryptStr, this.statusSignStr, this.statusPGPMimeStr, this.statusInlinePGPStr, this.statusAttachOwnKey // - this.statusSMimeStr updateStatusBar: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.updateStatusBar()\n"); this.statusEncryptedInStatusBar = this.statusEncrypted; // to double check broken promise for encryption if (!this.identity) { this.identity = getCurrentIdentity(); } var toolbarTxt = document.getElementById("enigmail-toolbar-text"); var encBroadcaster = document.getElementById("enigmail-bc-encrypt"); var signBroadcaster = document.getElementById("enigmail-bc-sign"); var attachBroadcaster = document.getElementById("enigmail-bc-attach"); let enc = this.getEncryptionEnabled(); let sign = this.getSigningEnabled(); // enigmail disabled for this identity?: if (!enc) { // hide icons if enigmail not enabled encBroadcaster.removeAttribute("encrypted"); encBroadcaster.setAttribute("disabled", "true"); } else { encBroadcaster.removeAttribute("disabled"); } if (!sign) { signBroadcaster.removeAttribute("signed"); signBroadcaster.setAttribute("disabled", "true"); attachBroadcaster.setAttribute("disabled", "true"); } else { signBroadcaster.removeAttribute("disabled"); attachBroadcaster.removeAttribute("disabled"); } if (!(enc || sign)) { if (toolbarTxt) { toolbarTxt.value = EnigmailLocale.getString("msgCompose.toolbarTxt.disabled"); toolbarTxt.removeAttribute("class"); } return; } // process resulting icon symbol and status strings for encrypt mode var encSymbol = null; var doEncrypt = false; var encStr = null; switch (this.statusEncrypted) { case EnigmailConstants.ENIG_FINAL_FORCENO: encSymbol = "forceNo"; encStr = EnigmailLocale.getString("encryptMessageNorm"); break; case EnigmailConstants.ENIG_FINAL_FORCEYES: doEncrypt = true; encSymbol = "forceYes"; encStr = EnigmailLocale.getString("encryptMessageNorm"); break; case EnigmailConstants.ENIG_FINAL_NO: encSymbol = "inactiveNone"; encStr = EnigmailLocale.getString("encryptMessageAuto"); break; case EnigmailConstants.ENIG_FINAL_YES: doEncrypt = true; encSymbol = "activeNone"; encStr = EnigmailLocale.getString("encryptMessageAuto"); break; case EnigmailConstants.ENIG_FINAL_CONFLICT: encSymbol = "inactiveConflict"; encStr = EnigmailLocale.getString("encryptMessageAuto"); break; } var encReasonStr = null; if (doEncrypt) { if (this.reasonEncrypted && this.reasonEncrypted !== "") { encReasonStr = EnigmailLocale.getString("encryptOnWithReason", [this.reasonEncrypted]); } else { encReasonStr = EnigmailLocale.getString("encryptOn"); } } else { if (this.reasonEncrypted && this.reasonEncrypted !== "") { encReasonStr = EnigmailLocale.getString("encryptOffWithReason", [this.reasonEncrypted]); } else { encReasonStr = EnigmailLocale.getString("encryptOff"); } } EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: encSymbol=" + encSymbol + " encReasonStr=" + encReasonStr + "\n"); // update encrypt icon and tooltip/menu-text encBroadcaster.setAttribute("encrypted", encSymbol); var encIcon = document.getElementById("button-enigmail-encrypt"); if (encIcon) { encIcon.setAttribute("tooltiptext", encReasonStr); } this.statusEncryptedStr = encStr; this.setChecked("enigmail-bc-encrypt", doEncrypt); // process resulting icon symbol for sign mode var signSymbol = null; var doSign = false; var signStr = ""; switch (this.statusSigned) { case EnigmailConstants.ENIG_FINAL_FORCENO: signSymbol = "forceNo"; signStr = EnigmailLocale.getString("signMessageNorm"); signReasonStr = EnigmailLocale.getString("signOffWithReason", [this.reasonSigned]); break; case EnigmailConstants.ENIG_FINAL_FORCEYES: doSign = true; signSymbol = "forceYes"; signStr = EnigmailLocale.getString("signMessageNorm"); signReasonStr = EnigmailLocale.getString("signOnWithReason", [this.reasonSigned]); break; case EnigmailConstants.ENIG_FINAL_NO: signSymbol = "inactiveNone"; signStr = EnigmailLocale.getString("signMessageAuto"); signReasonStr = EnigmailLocale.getString("signOffWithReason", [this.reasonSigned]); break; case EnigmailConstants.ENIG_FINAL_YES: doSign = true; signSymbol = "activeNone"; signStr = EnigmailLocale.getString("signMessageAuto"); signReasonStr = EnigmailLocale.getString("signOnWithReason", [this.reasonSigned]); break; case EnigmailConstants.ENIG_FINAL_CONFLICT: signSymbol = "inactiveConflict"; signStr = EnigmailLocale.getString("signMessageAuto"); signReasonStr = EnigmailLocale.getString("signOffWithReason", [this.reasonSigned]); break; } var signReasonStr = null; if (doSign) { if (this.reasonSigned && this.reasonSigned !== "") { signReasonStr = EnigmailLocale.getString("signOnWithReason", [this.reasonSigned]); } else { signReasonStr = signStr; } } else { if (this.reasonSigned && this.reasonSigned !== "") { signReasonStr = EnigmailLocale.getString("signOffWithReason", [this.reasonSigned]); } else { signReasonStr = signStr; } } EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: signSymbol=" + signSymbol + " signReasonStr=" + signReasonStr + "\n"); // update sign icon and tooltip/menu-text signBroadcaster.setAttribute("signed", signSymbol); var signIcon = document.getElementById("button-enigmail-sign"); if (signIcon) { signIcon.setAttribute("tooltiptext", signReasonStr); } this.statusSignedStr = signStr; this.setChecked("enigmail-bc-sign", doSign); // process resulting toolbar message var toolbarMsg = ""; if (doSign && doEncrypt) { toolbarMsg = EnigmailLocale.getString("msgCompose.toolbarTxt.signAndEncrypt"); } else if (doSign) { toolbarMsg = EnigmailLocale.getString("msgCompose.toolbarTxt.signOnly"); } else if (doEncrypt) { toolbarMsg = EnigmailLocale.getString("msgCompose.toolbarTxt.encryptOnly"); } else { toolbarMsg = EnigmailLocale.getString("msgCompose.toolbarTxt.noEncryption"); } if (toolbarTxt) { toolbarTxt.value = toolbarMsg; if (gMsgCompose.compFields.securityInfo) { let si = gMsgCompose.compFields.securityInfo.QueryInterface(Components.interfaces.nsIMsgSMIMECompFields); if (!doSign && !doEncrypt && !(gMsgCompose.compFields.securityInfo instanceof Components.interfaces.nsIMsgSMIMECompFields && (si.signMessage || si.requireEncryptMessage))) { toolbarTxt.setAttribute("class", "enigmailStrong"); } else { toolbarTxt.removeAttribute("class"); } } else { toolbarTxt.removeAttribute("class"); } } // update pgp mime/inline PGP menu-text if (this.statusPGPMime == EnigmailConstants.ENIG_FINAL_YES) { this.statusPGPMimeStr = EnigmailLocale.getString("pgpmimeAuto"); } else { this.statusPGPMimeStr = EnigmailLocale.getString("pgpmimeNormal"); } if (this.statusPGPMime == EnigmailConstants.ENIG_FINAL_NO) { this.statusInlinePGPStr = EnigmailLocale.getString("inlinePGPAuto"); } else { this.statusInlinePGPStr = EnigmailLocale.getString("inlinePGPNormal"); } if (this.statusPGPMime == EnigmailConstants.ENIG_FINAL_SMIME) { this.statusSMimeStr = EnigmailLocale.getString("smimeAuto"); } else { this.statusSMimeStr = EnigmailLocale.getString("smimeNormal"); } if (this.allowAttachOwnKey() === 1) { attachBroadcaster.removeAttribute("disabled"); } else { attachBroadcaster.setAttribute("disabled", "true"); } }, /** * determine if own key may be attached. * @result: Number: * -1: account not enabled for Enigmail * 0: account enabled but key mode set to "by Email address" * 1: account enabled; key specified */ allowAttachOwnKey: function() { let allow = -1; if (this.isEnigmailEnabled()) { allow = 0; if (this.identity.getIntAttribute("pgpKeyMode") > 0) { let keyIdValue = this.identity.getCharAttribute("pgpkeyId"); if (keyIdValue.search(/^ *(0x)?[0-9a-fA-F]* *$/) === 0) { allow = 1; } } } return allow; }, /* compute whether to sign/encrypt according to current rules and sendMode * - without any interaction, just to process resulting status bar icons */ determineSendFlags: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.focusChange: Enigmail.msg.determineSendFlags\n"); if (this.juniorMode) { this.getPepMessageRating(); return; } this.statusEncryptedInStatusBar = null; // to double check broken promise for encryption if (!this.identity) { this.identity = getCurrentIdentity(); } if (this.isEnigmailEnabled()) { var compFields = gMsgCompose.compFields; if (!Enigmail.msg.composeBodyReady) { compFields = Components.classes["@mozilla.org/messengercompose/composefields;1"].createInstance(Components.interfaces.nsIMsgCompFields); } Recipients2CompFields(compFields); gMsgCompose.expandMailingLists(); // process list of to/cc email addresses // - bcc email addresses are ignored, when processing whether to sign/encrypt var toAddrList = []; var arrLen = {}; var recList; if (compFields.to.length > 0) { recList = compFields.splitRecipients(compFields.to, true, arrLen); this.addRecipients(toAddrList, recList); } if (compFields.cc.length > 0) { recList = compFields.splitRecipients(compFields.cc, true, arrLen); this.addRecipients(toAddrList, recList); } this.encryptByRules = EnigmailConstants.ENIG_UNDEF; this.signByRules = EnigmailConstants.ENIG_UNDEF; this.pgpmimeByRules = EnigmailConstants.ENIG_UNDEF; // process rules if (toAddrList.length > 0 && EnigmailPrefs.getPref("assignKeysByRules")) { var matchedKeysObj = {}; var flagsObj = {}; if (EnigmailRules.mapAddrsToKeys(toAddrList.join(", "), false, // no interaction if not all addrs have a key window, matchedKeysObj, // resulting matching keys flagsObj)) { // resulting flags (0/1/2/3 for each type) this.encryptByRules = flagsObj.encrypt; this.signByRules = flagsObj.sign; this.pgpmimeByRules = flagsObj.pgpMime; if (matchedKeysObj.value && matchedKeysObj.value.length > 0) { // replace addresses with results from rules toAddrList = matchedKeysObj.value.split(", "); } } } let validKeyList = Enigmail.hlp.validKeysForAllRecipients(toAddrList.join(", ")); this.autoPgpEncryption = (validKeyList !== null); // if not clear whether to encrypt yet, check whether automatically-send-encrypted applies if (toAddrList.length > 0 && this.encryptByRules == EnigmailConstants.ENIG_UNDEF && EnigmailPrefs.getPref("autoSendEncrypted") == 1) { if (validKeyList) { this.encryptByRules = EnigmailConstants.ENIG_AUTO_ALWAYS; } } } else { this.encryptByRules = EnigmailConstants.ENIG_AUTO_NEVER; this.autoPgpEncryption = false; } // process and signal new resulting state this.processFinalState(); this.updateStatusBar(); this.determineSendFlagId = null; }, setChecked: function(elementId, checked) { let elem = document.getElementById(elementId); if (elem) { if (checked) { elem.setAttribute("checked", "true"); } else elem.removeAttribute("checked"); } }, setMenuSettings: function(postfix) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.setMenuSettings: postfix=" + postfix + "\n"); const nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.SEND_ENCRYPTED; var elem = document.getElementById("enigmail_compose_sign_item" + postfix); if (elem) { elem.setAttribute("label", this.statusSignedStr); switch (this.statusSigned) { case EnigmailConstants.ENIG_FINAL_YES: case EnigmailConstants.ENIG_FINAL_FORCEYES: elem.setAttribute("checked", "true"); break; default: elem.setAttribute("checked", "false"); } } elem = document.getElementById("enigmail_compose_encrypt_item" + postfix); if (elem) { elem.setAttribute("label", this.statusEncryptedStr); switch (this.statusEncrypted) { case EnigmailConstants.ENIG_FINAL_YES: case EnigmailConstants.ENIG_FINAL_FORCEYES: elem.setAttribute("checked", "true"); break; default: elem.setAttribute("checked", "false"); } } elem = document.getElementById("enigmail_compose_pgpmime_item" + postfix); if (elem) { elem.setAttribute("label", this.statusPGPMimeStr); switch (this.statusPGPMime) { case EnigmailConstants.ENIG_FINAL_YES: case EnigmailConstants.ENIG_FINAL_FORCEYES: elem.setAttribute("checked", "true"); break; default: elem.setAttribute("checked", "false"); } elem = document.getElementById("enigmail_compose_inline_item" + postfix); if (elem) { elem.setAttribute("label", this.statusInlinePGPStr); switch (this.statusPGPMime) { case EnigmailConstants.ENIG_FINAL_NO: case EnigmailConstants.ENIG_FINAL_FORCENO: case EnigmailConstants.ENIG_FINAL_CONFLICT: case EnigmailConstants.ENIG_FINAL_UNDEF: elem.setAttribute("checked", "true"); break; default: elem.setAttribute("checked", "false"); } } elem = document.getElementById("enigmail_compose_smime_item" + postfix); if (elem) { elem.setAttribute("label", this.statusSMimeStr); switch (this.statusPGPMime) { case EnigmailConstants.ENIG_FINAL_SMIME: case EnigmailConstants.ENIG_FINAL_FORCESMIME: elem.setAttribute("checked", "true"); break; default: elem.setAttribute("checked", "false"); } } let menuElement = document.getElementById("enigmail_insert_own_key"); if (menuElement) { if (this.identity.getIntAttribute("pgpKeyMode") > 0) { menuElement.setAttribute("checked", this.attachOwnKeyObj.appendAttachment.toString()); menuElement.removeAttribute("disabled"); } else { menuElement.setAttribute("disabled", "true"); } } } }, pepMenuPopup: function() { let encMenu = document.getElementById("enigmail_compose_pep_encrypt"); let hsMenu = document.getElementById("enigmail_composeMenu_pep_handshake"); let pepBc = document.getElementById("enigmail-bc-pepEncrypt"); if (this.pepEnabled()) { encMenu.setAttribute("checked", pepBc.getAttribute("encrypt")); encMenu.removeAttribute("disabled"); hsMenu.removeAttribute("disabled"); } else { encMenu.setAttribute("checked", "false"); encMenu.setAttribute("disabled", "true"); hsMenu.setAttribute("disabled", "true"); } }, /** * Determine if pEp was disabled by the user */ pepEnabled: function() { let id = getCurrentIdentity(); return id.getBoolAttribute("enablePEP"); }, pepDisabledError: function() { EnigmailDialog.alert(window, EnigmailLocale.getString("pep.alert.disabledForIdentity")); }, onPepEncryptMenu: function() { if (!this.pepEnabled()) { this.pepDisabledError(); return; } let pepBc = document.getElementById("enigmail-bc-pepEncrypt"); pepBc.setAttribute("encrypt", pepBc.getAttribute("encrypt") === "true" ? "false" : "true"); this.getPepMessageRating(); }, onPepEncryptButton: function() { this.onPepEncryptMenu(); }, onPepHandshakeButton: function(event) { if (!this.pepEnabled()) { this.pepDisabledError(); return; } event.stopPropagation(); EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.onPepHandshakeButton()\n"); let bc = document.getElementById("enigmail-bc-pepEncrypt"); if (bc.getAttribute("encrypt") === "false") { EnigmailDialog.info(window, EnigmailLocale.getString("handshakeDlg.error.noProtection")); return; } let o = this.compileFromAndTo(); let toAddr = EnigmailFuncs.stripEmail(o.toAddrList.join(",")).split(/,/); if (o.toAddrList.length === 0) { EnigmailDialog.info(window, EnigmailLocale.getString("handshakeDlg.error.noPeers")); return; } let myId = getCurrentIdentity(); let inputObj = { myself: myId.email, addresses: toAddr, direction: 1, parentWindow: window, onComplete: Enigmail.msg.getPepMessageRating.bind(Enigmail.msg) }; window.openDialog("chrome://enigmail/content/pepPrepHandshake.xul", "", "dialog,modal,centerscreen", inputObj); }, displaySecuritySettings: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.displaySecuritySettings\n"); var inputObj = { statusEncrypted: this.statusEncrypted, statusSigned: this.statusSigned, statusPGPMime: this.statusPGPMime, success: false, resetDefaults: false }; window.openDialog("chrome://enigmail/content/enigmailEncryptionDlg.xul", "", "dialog,modal,centerscreen", inputObj); if (!inputObj.success) return; // Cancel pressed if (inputObj.resetDefaults) { // reset everything to defaults this.encryptForced = EnigmailConstants.ENIG_UNDEF; this.signForced = EnigmailConstants.ENIG_UNDEF; this.pgpmimeForced = EnigmailConstants.ENIG_UNDEF; this.finalSignDependsOnEncrypt = true; } else { if (this.signForced != inputObj.sign) { this.dirty = 2; this.signForced = inputObj.sign; this.finalSignDependsOnEncrypt = false; } if (this.encryptForced != inputObj.encrypt || this.pgpmimeForced != inputObj.pgpmime) { this.dirty = 2; } this.encryptForced = inputObj.encrypt; this.pgpmimeForced = inputObj.pgpmime; } this.processFinalState(); this.updateStatusBar(); }, signingNoLongerDependsOnEnc: function() { if (this.finalSignDependsOnEncrypt && (!this.juniorMode)) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.signingNoLongerDependsOnEnc(): unbundle final signing\n"); this.finalSignDependsOnEncrypt = false; EnigmailDialog.alertPref(window, EnigmailLocale.getString("signIconClicked"), "displaySignWarn"); } }, confirmBeforeSend: function(toAddrStr, gpgKeys, sendFlags, isOffline) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.confirmBeforeSend: sendFlags=" + sendFlags + "\n"); // get confirmation before sending message const nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.SEND_ENCRYPTED; // get wording for message status (e.g. " SIGNED ENCRYPTED") var msgStatus = ""; if (sendFlags & (ENCRYPT | SIGN)) { if (this.statusPGPMime === EnigmailConstants.ENIG_FINAL_SMIME || this.statusPGPMime === EnigmailConstants.ENIG_FINAL_FORCESMIME) { msgStatus += " " + EnigmailLocale.getString("statSMIME"); } else if (sendFlags & nsIEnigmail.SEND_PGP_MIME) { msgStatus += " " + EnigmailLocale.getString("statPGPMIME"); } if (sendFlags & SIGN) { msgStatus += " " + EnigmailLocale.getString("statSigned"); } if (sendFlags & ENCRYPT) { msgStatus += " " + EnigmailLocale.getString("statEncrypted"); } } else { msgStatus += " " + EnigmailLocale.getString("statPlain"); } // create message var msgConfirm = ""; if (isOffline || sendFlags & nsIEnigmail.SEND_LATER) { msgConfirm = EnigmailLocale.getString("offlineSave", [msgStatus, EnigmailFuncs.stripEmail(toAddrStr).replace(/,/g, ", ")]); } else { msgConfirm = EnigmailLocale.getString("onlineSend", [msgStatus, EnigmailFuncs.stripEmail(toAddrStr).replace(/,/g, ", ")]); } // add list of keys if (sendFlags & ENCRYPT) { gpgKeys = gpgKeys.replace(/^, /, "").replace(/, $/, ""); // make gpg keys unique let keyList = gpgKeys.split(/[, ]+/).reduce(function _f(p, key) { if (p.indexOf(key) < 0) p.push(key); return p; }, []); if (this.statusPGPMime !== EnigmailConstants.ENIG_FINAL_SMIME && this.statusPGPMime !== EnigmailConstants.ENIG_FINAL_FORCESMIME) { msgConfirm += "\n\n" + EnigmailLocale.getString("encryptKeysNote", [keyList.join(", ")]); } } return EnigmailDialog.confirmDlg(window, msgConfirm, EnigmailLocale.getString((isOffline || sendFlags & nsIEnigmail.SEND_LATER) ? "msgCompose.button.save" : "msgCompose.button.send")); }, addRecipients: function(toAddrList, recList) { for (var i = 0; i < recList.length; i++) { toAddrList.push(EnigmailFuncs.stripEmail(recList[i].replace(/[\",]/g, ""))); } }, setDraftStatus: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.setDraftStatus - enabling draft mode\n"); // Draft Status: // N (for new style) plus String of 4 numbers: // 1: encryption // 2: signing // 3: PGP/MIME // 4: attach own key var draftStatus = "N" + this.encryptForced + this.signForced + this.pgpmimeForced + (this.attachOwnKeyObj.appendAttachment ? "1" : "0"); this.setAdditionalHeader("X-Enigmail-Draft-Status", draftStatus); }, getSenderUserId: function() { var userIdValue = null; if (this.identity.getIntAttribute("pgpKeyMode") > 0) { userIdValue = this.identity.getCharAttribute("pgpkeyId"); if (!userIdValue) { var mesg = EnigmailLocale.getString("composeSpecifyEmail"); var valueObj = { value: userIdValue }; if (EnigmailDialog.promptValue(window, mesg, valueObj)) { userIdValue = valueObj.value; } } if (userIdValue) { this.identity.setCharAttribute("pgpkeyId", userIdValue); } else { this.identity.setIntAttribute("pgpKeyMode", 0); } } if (typeof(userIdValue) != "string") { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.getSenderUserId: type of userIdValue=" + typeof(userIdValue) + "\n"); userIdValue = this.identity.email; } return userIdValue; }, /* process rules and find keys for passed email addresses * This is THE core method to prepare sending encryptes emails. * - it processes the recipient rules (if not disabled) * - it * * @sendFlags: Longint - all current combined/processed send flags (incl. optSendFlags) * @optSendFlags: Longint - may only be SEND_ALWAYS_TRUST or SEND_ENCRYPT_TO_SELF * @gotSendFlags: Longint - initial sendMode of encryptMsg() (0 or SIGN or ENCRYPT or SIGN|ENCRYPT) * @fromAddr: String - from email * @toAddrList: Array - both to and cc receivers * @bccAddrList: Array - bcc receivers * @return: Object: * - sendFlags (Longint) * - toAddrStr comma separated string of unprocessed to/cc emails * - bccAddrStr comma separated string of unprocessed to/cc emails * or null (cancel sending the email) */ keySelection: function(enigmailSvc, sendFlags, optSendFlags, gotSendFlags, fromAddr, toAddrList, bccAddrList) { EnigmailLog.DEBUG("=====> keySelection()\n"); EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.keySelection()\n"); const nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.SEND_ENCRYPTED; var toAddrStr = toAddrList.join(", "); var bccAddrStr = bccAddrList.join(", "); // NOTE: If we only have bcc addresses, we currently do NOT process rules and select keys at all // This is GOOD because sending keys for bcc addresses makes bcc addresses visible // (thus compromising the concept of bcc) // THUS, we disable encryption even though all bcc receivers might want to have it encrypted. if (toAddrStr.length === 0) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.keySelection(): skip key selection because we neither have \"to\" nor \"cc\" addresses\n"); if (this.statusPGPMime == EnigmailConstants.ENIG_FINAL_YES || this.statusPGPMime == EnigmailConstants.ENIG_FINAL_FORCEYES) { sendFlags |= nsIEnigmail.SEND_PGP_MIME; } else if (this.statusPGPMime == EnigmailConstants.ENIG_FINAL_NO || this.statusPGPMime == EnigmailConstants.ENIG_FINAL_FORCENO || this.statusPGPMime == EnigmailConstants.ENIG_FINAL_CONFLICT) { sendFlags &= ~nsIEnigmail.SEND_PGP_MIME; } return { sendFlags: sendFlags, toAddrStr: toAddrStr, bccAddrStr: bccAddrStr }; } EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.keySelection(): toAddrStr=\"" + toAddrStr + "\" bccAddrStr=\"" + bccAddrStr + "\"\n"); // force add-rule dialog for each missing key?: var forceRecipientSettings = false; // if keys are ONLY assigned by rules, force add-rule dialog for each missing key if (EnigmailPrefs.getPref("assignKeysByRules") && !EnigmailPrefs.getPref("assignKeysByEmailAddr") && !EnigmailPrefs.getPref("assignKeysManuallyIfMissing") && !EnigmailPrefs.getPref("assignKeysManuallyAlways")) { forceRecipientSettings = true; } // REPEAT 1 or 2 times: // NOTE: The only way to call this loop twice is to come to the "continue;" statement below, // which forces a second iteration (with forceRecipientSettings==true) var doRulesProcessingAgain; do { doRulesProcessingAgain = false; // process rules if not disabled // - enableRules: rules not temporarily disabled // REPLACES email addresses by keys in its result !!! var refreshKeyList = true; if (EnigmailPrefs.getPref("assignKeysByRules") && this.enableRules) { let result = this.processRules(forceRecipientSettings, sendFlags, optSendFlags, toAddrStr, bccAddrStr); if (!result) { return null; } sendFlags = result.sendFlags; optSendFlags = result.optSendFlags; toAddrStr = result.toAddr; // replace email addresses with rules by the corresponding keys bccAddrStr = result.bccAddr; // replace email addresses with rules by the corresponding keys refreshKeyList = !result.didRefreshKeyList; // if key list refreshed we don't have to do it again } // if encryption is requested for the email: // - encrypt test message for default encryption // - might trigger a second iteration through this loop // - if during its dialog for manual key selection "create per-recipient rules" is pressed // to force manual settings for missing keys // LEAVES remaining email addresses not covered by rules as they are if (sendFlags & ENCRYPT) { let result = this.encryptTestMessage(enigmailSvc, sendFlags, optSendFlags, fromAddr, toAddrStr, bccAddrStr, bccAddrList, refreshKeyList); if (!result) { return null; } sendFlags = result.sendFlags; toAddrStr = result.toAddrStr; bccAddrStr = result.bccAddrStr; if (result.doRulesProcessingAgain) { // start rule processing again ? doRulesProcessingAgain = true; if (result.createNewRule) { forceRecipientSettings = true; } } } } while (doRulesProcessingAgain); EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.keySelection(): return toAddrStr=\"" + toAddrStr + "\" bccAddrStr=\"" + bccAddrStr + "\"\n"); EnigmailLog.DEBUG(" <=== keySelection()\n"); return { sendFlags: sendFlags, toAddrStr: toAddrStr, bccAddrStr: bccAddrStr }; }, /** * 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) { const nsIEnigmail = Components.interfaces.nsIEnigmail; if (gMsgCompose.compFields.securityInfo instanceof Components.interfaces.nsIMsgSMIMECompFields && (sendFlags & (nsIEnigmail.SEND_SIGNED | nsIEnigmail.SEND_ENCRYPTED))) { let si = gMsgCompose.compFields.securityInfo.QueryInterface(Components.interfaces.nsIMsgSMIMECompFields); if (si.requireEncryptMessage || si.signMessage) { if (sendFlags & nsIEnigmail.SAVE_MESSAGE) { // use S/MIME if it's enabled for saving drafts return 0; } else { return this.mimePreferOpenPGP; } } } return 1; }, /** * check if S/MIME encryption can be enabled * * @return: Boolean - true: keys for all recipients are available */ isSmimeEncryptionPossible: function() { let ret = false; let id = getCurrentIdentity(); if (id.getUnicharAttribute("encryption_cert_name") === "") return false; // enable encryption if keys for all recipients are available let missingCount = {}; let emailAddresses = {}; try { Components.classes["@mozilla.org/messenger-smime/smimejshelper;1"] .createInstance(Components.interfaces.nsISMimeJSHelper) .getNoCertAddresses(gMsgCompose.compFields, missingCount, emailAddresses); } catch (e) { return false; } if (missingCount.value === 0) { return true; } return false; }, /** * try to apply the OpenPGP rules * * @forceRecipientSetting: Boolean - force manual selection for each missing key? * @sendFlags: Integer - all current combined/processed send flags (incl. optSendFlags) * @optSendFlags: Integer - may only be SEND_ALWAYS_TRUST or SEND_ENCRYPT_TO_SELF * @toAddrStr: String - comma separated string of keys and unprocessed to/cc emails * @bccAddrStr: String - comma separated string of keys and unprocessed bcc emails * @return: { sendFlags, toAddr, bccAddr } * or null (cancel sending the email) */ processRules: function(forceRecipientSettings, sendFlags, optSendFlags, toAddrStr, bccAddrStr) { EnigmailLog.DEBUG("=====> processRules()\n"); EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.processRules(): toAddrStr=\"" + toAddrStr + "\" bccAddrStr=\"" + bccAddrStr + "\" forceRecipientSettings=" + forceRecipientSettings + "\n"); // process defaults const nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.SEND_ENCRYPTED; var didRefreshKeyList = false; // return value to signal whether the key list was refreshed // get keys for to and cc addresses: // - matchedKeysObj will contain the keys and the remaining toAddrStr elements var matchedKeysObj = {}; // returned value for matched keys var flagsObj = {}; // returned value for flags if (!EnigmailRules.mapAddrsToKeys(toAddrStr, forceRecipientSettings, // true => start dialog for addrs without any key window, matchedKeysObj, flagsObj)) { return null; } if (matchedKeysObj.value) { toAddrStr = matchedKeysObj.value; EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.processRules(): after mapAddrsToKeys() toAddrStr=\"" + toAddrStr + "\"\n"); } this.encryptByRules = flagsObj.encrypt; this.signByRules = flagsObj.sign; this.pgpmimeByRules = flagsObj.pgpMime; // if not clear whether to encrypt yet, check whether automatically-send-encrypted applies // - check whether bcc is empty here? if (bccAddrStr.length === 0) if (toAddrStr.length > 0 && this.encryptByRules == EnigmailConstants.ENIG_UNDEF && EnigmailPrefs.getPref("autoSendEncrypted") == 1) { var validKeyList = Enigmail.hlp.validKeysForAllRecipients(toAddrStr); if (validKeyList) { this.encryptByRules = EnigmailConstants.ENIG_AUTO_ALWAYS; toAddrStr = validKeyList.join(", "); } } // process final state this.processFinalState(sendFlags); // final handling of conflicts: // - pgpMime conflicts always result into pgpMime = 0/'never' if (this.statusPGPMime == EnigmailConstants.ENIG_FINAL_CONFLICT) { this.statusPGPMime = EnigmailConstants.ENIG_FINAL_NO; } // - encrypt/sign conflicts result into result 0/'never' // with possible dialog to give a corresponding feedback var conflictFound = false; if (this.statusEncrypted == EnigmailConstants.ENIG_FINAL_CONFLICT) { this.statusEncrypted = EnigmailConstants.ENIG_FINAL_NO; conflictFound = true; } if (this.statusSigned == EnigmailConstants.ENIG_FINAL_CONFLICT) { this.statusSigned = EnigmailConstants.ENIG_FINAL_NO; conflictFound = true; } if (conflictFound) { if (!Enigmail.hlp.processConflicts(this.statusEncrypted == EnigmailConstants.ENIG_FINAL_YES || this.statusEncrypted == EnigmailConstants.ENIG_FINAL_FORCEYES, this.statusSigned == EnigmailConstants.ENIG_FINAL_YES || this.statusSigned == EnigmailConstants.ENIG_FINAL_FORCEYES)) { return null; } } // process final sendMode // ENIG_FINAL_CONFLICT no longer possible switch (this.statusEncrypted) { case EnigmailConstants.ENIG_FINAL_NO: case EnigmailConstants.ENIG_FINAL_FORCENO: sendFlags &= ~ENCRYPT; break; case EnigmailConstants.ENIG_FINAL_YES: case EnigmailConstants.ENIG_FINAL_FORCEYES: sendFlags |= ENCRYPT; break; } switch (this.statusSigned) { case EnigmailConstants.ENIG_FINAL_NO: case EnigmailConstants.ENIG_FINAL_FORCENO: sendFlags &= ~SIGN; break; case EnigmailConstants.ENIG_FINAL_YES: case EnigmailConstants.ENIG_FINAL_FORCEYES: sendFlags |= SIGN; break; } switch (this.statusPGPMime) { case EnigmailConstants.ENIG_FINAL_NO: case EnigmailConstants.ENIG_FINAL_FORCENO: sendFlags &= ~nsIEnigmail.SEND_PGP_MIME; break; case EnigmailConstants.ENIG_FINAL_YES: case EnigmailConstants.ENIG_FINAL_FORCEYES: sendFlags |= nsIEnigmail.SEND_PGP_MIME; break; } // get keys according to rules for bcc addresses: // - matchedKeysObj will contain the keys and the remaining bccAddrStr elements // - NOTE: bcc recipients are ignored when in general computing whether to sign or encrypt or pgpMime if (!EnigmailRules.mapAddrsToKeys(bccAddrStr, forceRecipientSettings, // true => start dialog for addrs without any key window, matchedKeysObj, flagsObj)) { return null; } if (matchedKeysObj.value) { bccAddrStr = matchedKeysObj.value; EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.processRules(): after mapAddrsToKeys() bccAddrStr=\"" + bccAddrStr + "\"\n"); } EnigmailLog.DEBUG(" <=== processRules()\n"); return { sendFlags: sendFlags, optSendFlags: optSendFlags, toAddr: toAddrStr, bccAddr: bccAddrStr, didRefreshKeyList: didRefreshKeyList }; }, /* encrypt a test message to see whether we have all necessary keys * * @sendFlags: all current combined/processed send flags (incl. optSendFlags) * @optSendFlags: may only be SEND_ALWAYS_TRUST or SEND_ENCRYPT_TO_SELF * @fromAddr: from email * @toAddrStr: comma separated string of keys and unprocessed to/cc emails * @bccAddrStr: comma separated string of keys and unprocessed bcc emails * @bccAddrList: bcc receivers * @return: doRulesProcessingAgain: start with rule processing once more * or null (cancel sending the email) */ encryptTestMessage: function(enigmailSvc, sendFlags, optSendFlags, fromAddr, toAddrStr, bccAddrStr, bccAddrList, refresh) { EnigmailLog.DEBUG("=====> encryptTestMessage()\n"); const nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.SEND_ENCRYPTED; var testCipher = null; var testExitCodeObj = {}; var testStatusFlagsObj = {}; var testErrorMsgObj = {}; // get keys for remaining email addresses // - NOTE: This should not be necessary; however, in GPG there is a problem: // Only the first key found for an email is used. // If this is invalid, no other keys are tested. // Thus, WE make it better here in enigmail until the bug is fixed. var details = {}; // will contain msgList[] afterwards if (EnigmailPrefs.getPref("assignKeysByEmailAddr")) { var validKeyList = Enigmail.hlp.validKeysForAllRecipients(toAddrStr, details); if (validKeyList) { toAddrStr = validKeyList.join(", "); } } // encrypt test message for test recipients var testPlain = "Test Message"; var testUiFlags = nsIEnigmail.UI_TEST; var testSendFlags = nsIEnigmail.SEND_TEST | ENCRYPT | optSendFlags; EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptTestMessage(): call encryptMessage() for fromAddr=\"" + fromAddr + "\" toAddrStr=\"" + toAddrStr + "\" bccAddrStr=\"" + bccAddrStr + "\"\n"); testCipher = enigmailSvc.encryptMessage(window, testUiFlags, testPlain, fromAddr, toAddrStr, bccAddrStr, testSendFlags, testExitCodeObj, testStatusFlagsObj, testErrorMsgObj); if (testStatusFlagsObj.value & (nsIEnigmail.INVALID_RECIPIENT | nsIEnigmail.NO_SECKEY)) { // check if own key is invalid EnigmailDialog.alert(window, testErrorMsgObj.value); return null; } // if // - "always ask/manually" (even if all keys were found) or // - unless "ask for missing keys": // - we have an invalid recipient or // - we could not resolve any/all keys // (due to disabled "assignKeysByEmailAddr"" or multiple keys with same trust for a recipient) // start the dialog for user selected keys if (EnigmailPrefs.getPref("assignKeysManuallyAlways") || (((testStatusFlagsObj.value & nsIEnigmail.INVALID_RECIPIENT) || toAddrStr.indexOf('@') >= 0) && EnigmailPrefs.getPref("assignKeysManuallyIfMissing")) || (details && details.errArray && details.errArray.length > 0) ) { // check for invalid recipient keys var resultObj = {}; var inputObj = {}; inputObj.toAddr = toAddrStr; inputObj.invalidAddr = Enigmail.hlp.getInvalidAddress(testErrorMsgObj.value); if (details && details.errArray && details.errArray.length > 0) { inputObj.errArray = details.errArray; } // prepare dialog options: inputObj.options = "multisel"; if (EnigmailPrefs.getPref("assignKeysByRules")) { inputObj.options += ",rulesOption"; // enable button to create per-recipient rule } if (EnigmailPrefs.getPref("assignKeysManuallyAlways")) { inputObj.options += ",noforcedisp"; } if (!(sendFlags & SIGN)) { inputObj.options += ",unsigned"; } if (this.trustAllKeys) { inputObj.options += ",trustallkeys"; } if (sendFlags & nsIEnigmail.SEND_LATER) { let sendLaterLabel = EnigmailLocale.getString("sendLaterCmd.label"); inputObj.options += ",sendlabel=" + sendLaterLabel; } inputObj.options += ","; inputObj.dialogHeader = EnigmailLocale.getString("recipientsSelectionHdr"); // perform key selection dialog: window.openDialog("chrome://enigmail/content/enigmailKeySelection.xul", "", "dialog,modal,centerscreen,resizable", inputObj, resultObj); // process result from key selection dialog: try { // CANCEL: if (resultObj.cancelled) { return null; } // repeat checking of rules etc. (e.g. after importing new key) if (resultObj.repeatEvaluation) { // THIS is the place that triggers a second iteration let returnObj = { doRulesProcessingAgain: true, createNewRule: false, sendFlags: sendFlags, toAddrStr: toAddrStr, bccAddrStr: bccAddrStr }; // "Create per recipient rule(s)": if (resultObj.perRecipientRules && this.enableRules) { // do an extra round because the user wants to set a PGP rule returnObj.createNewRule = true; } return returnObj; } // process OK button: if (resultObj.encrypt) { sendFlags |= ENCRYPT; // should anyway be set if (bccAddrList.length > 0) { toAddrStr = ""; bccAddrStr = resultObj.userList.join(", "); } else { toAddrStr = resultObj.userList.join(", "); bccAddrStr = ""; } } else { // encryption explicitely turned off sendFlags &= ~ENCRYPT; // counts as forced non-encryption // (no internal error if different state was processed before) this.statusEncrypted = EnigmailConstants.ENIG_FINAL_NO; this.statusEncryptedInStatusBar = EnigmailConstants.ENIG_FINAL_NO; } if (resultObj.sign) { sendFlags |= SIGN; } else { sendFlags &= ~SIGN; } testCipher = "ok"; testExitCodeObj.value = 0; } catch (ex) { // cancel pressed -> don't send mail return null; } } // If test encryption failed and never ask manually, turn off default encryption if ((!testCipher || (testExitCodeObj.value !== 0)) && !EnigmailPrefs.getPref("assignKeysManuallyIfMissing") && !EnigmailPrefs.getPref("assignKeysManuallyAlways")) { sendFlags &= ~ENCRYPT; this.statusEncrypted = EnigmailConstants.ENIG_FINAL_NO; this.statusEncryptedInStatusBar = EnigmailConstants.ENIG_FINAL_NO; EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptTestMessage: No default encryption because test failed\n"); } EnigmailLog.DEBUG(" <=== encryptTestMessage()\n"); return { doRulesProcessingAgain: false, createNewRule: false, sendFlags: sendFlags, toAddrStr: toAddrStr, bccAddrStr: bccAddrStr }; }, /* 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 */ wrapInLine: function(wrapresultObj) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: WrapInLine\n"); wrapresultObj.cancelled = false; wrapresultObj.usePpgMime = false; try { const dce = Components.interfaces.nsIDocumentEncoder; var wrapper = gMsgCompose.editor.QueryInterface(Components.interfaces.nsIEditorMailSupport); var editor = gMsgCompose.editor.QueryInterface(Components.interfaces.nsIPlaintextEditor); var encoderFlags = dce.OutputFormatted | dce.OutputLFLineBreak; var wrapWidth = this.getMailPref("mailnews.wraplength"); if (wrapWidth > 0 && wrapWidth < 68 && editor.wrapWidth > 0) { if (EnigmailDialog.confirmDlg(window, EnigmailLocale.getString("minimalLineWrapping", [wrapWidth]))) { wrapWidth = 68; EnigmailPrefs.getPrefRoot().setIntPref("mailnews.wraplength", wrapWidth); } } if (wrapWidth && editor.wrapWidth > 0) { // First use standard editor wrap mechanism: editor.wrapWidth = wrapWidth - 2; wrapper.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://enigmail/content/enigmailWrapSelection.xul", "", "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 quote = ""; 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... saveDraftMessage: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: saveDraftMessage()\n"); const nsIEnigmail = Components.interfaces.nsIEnigmail; let doEncrypt = this.isEnigmailEnabled() && this.identity.getBoolAttribute("autoEncryptDrafts"); this.setDraftStatus(); if (!doEncrypt) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: drafts disabled\n"); try { if (gMsgCompose.compFields.securityInfo instanceof Components.interfaces.nsIEnigMsgCompFields) { gMsgCompose.compFields.securityInfo.sendFlags = 0; } } catch (ex) {} return true; } let sendFlags = nsIEnigmail.SEND_PGP_MIME | nsIEnigmail.SEND_ENCRYPTED | nsIEnigmail.SAVE_MESSAGE | nsIEnigmail.SEND_ALWAYS_TRUST; let fromAddr = this.identity.email; let userIdValue = this.getSenderUserId(); if (userIdValue) { fromAddr = userIdValue; } let enigmailSvc = EnigmailCore.getService(window); if (!enigmailSvc) return true; if (this.preferPgpOverSmime(sendFlags) === 0) return true; // use S/MIME // Try to save draft var testCipher = null; var testExitCodeObj = {}; var testStatusFlagsObj = {}; var testErrorMsgObj = {}; // encrypt test message for test recipients var testPlain = "Test Message"; var testUiFlags = nsIEnigmail.UI_TEST; EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.saveDraft(): call encryptMessage() for fromAddr=\"" + fromAddr + "\"\n"); testCipher = enigmailSvc.encryptMessage(null, testUiFlags, testPlain, fromAddr, fromAddr, "", sendFlags | nsIEnigmail.SEND_TEST, testExitCodeObj, testStatusFlagsObj, testErrorMsgObj); if (testStatusFlagsObj.value & (nsIEnigmail.INVALID_RECIPIENT | nsIEnigmail.NO_SECKEY)) { // check if own key is invalid if (testErrorMsgObj.value && testErrorMsgObj.value.length > 0) { ++this.saveDraftError; if (this.saveDraftError === 1) { this.notifyUser(3, EnigmailLocale.getString("msgCompose.cannotSaveDraft"), "saveDraftFailed", testErrorMsgObj.value); } return false; } } let newSecurityInfo; try { if (gMsgCompose.compFields.securityInfo instanceof Components.interfaces.nsIEnigMsgCompFields) { newSecurityInfo = gMsgCompose.compFields.securityInfo; } else { throw "dummy"; } } catch (ex) { try { newSecurityInfo = Components.classes[this.compFieldsEnig_CID].createInstance(Components.interfaces.nsIEnigMsgCompFields); if (newSecurityInfo) { let oldSecurityInfo = gMsgCompose.compFields.securityInfo; newSecurityInfo.init(oldSecurityInfo); gMsgCompose.compFields.securityInfo = newSecurityInfo; } } catch (ex2) { EnigmailLog.writeException("enigmailMsgComposeOverlay.js: Enigmail.msg.saveDraftMessage", ex); return false; } } newSecurityInfo.sendFlags = sendFlags; newSecurityInfo.UIFlags = 0; newSecurityInfo.senderEmailAddr = fromAddr; newSecurityInfo.recipients = fromAddr; newSecurityInfo.bccRecipients = ""; this.dirty = true; return true; }, createEnigmailSecurityFields: function(oldSecurityInfo) { let newSecurityInfo = Components.classes[this.compFieldsEnig_CID].createInstance(Components.interfaces.nsIEnigMsgCompFields); if (!newSecurityInfo) throw Components.results.NS_ERROR_FAILURE; newSecurityInfo.init(oldSecurityInfo); gMsgCompose.compFields.securityInfo = newSecurityInfo; }, isSendConfirmationRequired: function(sendFlags) { // process whether final confirmation is necessary const SIGN = Components.interfaces.nsIEnigmail.SEND_SIGNED; const ENCRYPT = Components.interfaces.nsIEnigmail.SEND_ENCRYPTED; let confirm = false; let confPref = EnigmailPrefs.getPref("confirmBeforeSending"); switch (confPref) { case 0: // never confirm = false; break; case 1: // always confirm = true; break; case 2: // if send encrypted confirm = ((sendFlags & ENCRYPT) == ENCRYPT); break; case 3: // if send unencrypted confirm = ((sendFlags & ENCRYPT) === 0); break; case 4: // if encryption changed due to rules confirm = ((sendFlags & ENCRYPT) != (this.sendMode & ENCRYPT)); break; } // double check that no internal error did result in broken promise of encryption // - if NOT send encrypted // - although encryption was // - the recent processed resulting encryption status or // - was signaled in the status bar but is not the outcome now if ((sendFlags & ENCRYPT) === 0 && this.statusPGPMime !== EnigmailConstants.ENIG_FINAL_SMIME && this.statusPGPMime !== EnigmailConstants.ENIG_FINAL_FORCESMIME && (this.statusEncrypted == EnigmailConstants.ENIG_FINAL_YES || this.statusEncrypted == EnigmailConstants.ENIG_FINAL_FORCEYES || this.statusEncryptedInStatusBar == EnigmailConstants.ENIG_FINAL_YES || this.statusEncryptedInStatusBar == EnigmailConstants.ENIG_FINAL_FORCEYES)) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.isSendConfirmationRequired: promised encryption did not succeed\n"); if (!EnigmailDialog.confirmDlg(window, EnigmailLocale.getString("msgCompose.internalEncryptionError"), EnigmailLocale.getString("msgCompose.button.sendAnyway"))) { return null; // cancel sending } // without canceling sending, force firnal confirmation confirm = true; } return confirm; }, setPepPrivacyLabel: function(rating) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.setPepPrivacyLabel: " + rating + "\n"); let l = document.getElementById("enigmail-pep-privacy-status"); let bc = document.getElementById("enigmail-bc-pepEncrypt"); let color = EnigmailPEPAdapter.calculateColorFromRating(rating); if (bc.getAttribute("encrypt") === "false") { color = "grey"; } else if (rating === 0) { color = "?"; } switch (color) { case "?": l.setAttribute("value", EnigmailLocale.getString("msgCompose.pepSendUnknown")); l.setAttribute("class", "enigmail-statusbar-pep-unsecure"); break; case "green": l.setAttribute("value", EnigmailLocale.getString("msgCompose.pepSendTrusted")); l.setAttribute("class", "enigmail-statusbar-pep-trusted"); break; case "yellow": l.setAttribute("value", EnigmailLocale.getString("msgCompose.pepSendSecure")); l.setAttribute("class", "enigmail-statusbar-pep-secure"); break; default: l.setAttribute("value", EnigmailLocale.getString("msgCompose.pepSendUnsecure")); l.setAttribute("class", "enigmail-statusbar-pep-unsecure"); } }, getPepMessageRating: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.getPepMessageRating\n"); if (this.pepEnabled()) { let rating = 0; let o = this.compileFromAndTo(); if (o) { rating = EnigmailPEPAdapter.getOutgoingMessageRating(o.from, o.toAddrList); } this.setPepPrivacyLabel(rating); this.determineSendFlagId = null; } else { this.setPepPrivacyLabel(0); } }, compileFromAndTo: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.compileFromAndTo\n"); let compFields = gMsgCompose.compFields; let toAddrList = []; let recList; let arrLen = {}; if (!Enigmail.msg.composeBodyReady) { compFields = Components.classes["@mozilla.org/messengercompose/composefields;1"].createInstance(Components.interfaces.nsIMsgCompFields); } Recipients2CompFields(compFields); gMsgCompose.expandMailingLists(); EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: to='" + compFields.to + "'\n"); if (compFields.to.length > 0) { toAddrList = EnigmailFuncs.parseEmails(compFields.to, false); } if (compFields.cc.length > 0) { toAddrList = toAddrList.concat(EnigmailFuncs.parseEmails(compFields.cc, false)); } if (compFields.bcc.length > 0) { toAddrList = toAddrList.concat(EnigmailFuncs.parseEmails(compFields.bcc, false)); } for (let addr of toAddrList) { // determine incomplete addresses --> do not attempt pEp encryption if (addr.email.search(/.@./) < 0) return null; } this.identity = getCurrentIdentity(); let from = { email: this.identity.email, name: this.identity.fullName }; return { from: from, toAddrList: toAddrList }; }, attachPepKey: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.attachPepKey()\n"); if (this.identity.getBoolAttribute("attachPgpKey")) { let id = EnigmailPEPAdapter.getOwnIdentityForEmail(this.identity.email); if (id) { let userIdValue = "0x" + id.fpr; if (this.attachOwnKeyObj.attachedKey && (this.attachOwnKeyObj.attachedKey != userIdValue)) { // remove attached key if user ID changed this.removeAttachedKey(); } if (!this.attachOwnKeyObj.attachedKey) { - let attachedObj = this.extractAndAttachKey([userIdValue]); + let attachedObj = this.extractAndAttachKey([userIdValue], false); if (attachedObj) { attachedObj.name = "pEpkey.asc"; this.attachOwnKeyObj.attachedObj = attachedObj; this.attachOwnKeyObj.attachedKey = userIdValue; gMsgCompose.compFields.addAttachment(attachedObj); } } } } }, encryptPepMessage: function(msgSendType) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptPepMessage()\n"); const CiMsgCompDeliverMode = Components.interfaces.nsIMsgCompDeliverMode; const nsIEnigmail = Components.interfaces.nsIEnigmail; let isDraft = false; let compFields = gMsgCompose.compFields; switch (msgSendType) { case CiMsgCompDeliverMode.SaveAsDraft: case CiMsgCompDeliverMode.SaveAsTemplate: case CiMsgCompDeliverMode.AutoSaveAsDraft: EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptPepMessage: detected save draft\n"); return true; } try { // autoEncryptDrafts equals "trusted server" in pEp mode if (this.identity.getBoolAttribute("autoEncryptDrafts")) { EnigmailPEPAdapter.filter.deleteDecryptedCopyFilter(this.identity); } else { EnigmailPEPAdapter.filter.ensureDecryptedCopyFilter(this.identity); } } catch (ex) {} let rating = 0; if (this.pepEnabled()) { let o = this.compileFromAndTo(); if (o) { rating = EnigmailPEPAdapter.getOutgoingMessageRating(o.from, o.toAddrList); if (this.origPepRating !== null && rating < this.origPepRating && this.identity.getBoolAttribute("warnWeakReply")) { let msgInput = { msgtext: EnigmailLocale.getString("pep.alert.weakReply"), button1: EnigmailLocale.getString("dlg.button.continue"), cancelButton: EnigmailLocale.getString("dlg.button.cancel"), iconType: EnigmailConstants.ICONTYPE_ALERT, dialogTitle: EnigmailLocale.getString("warning") }; if (EnigmailDialog.msgBox(window, msgInput) !== 0) return false; } } } EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptPepMessage: rating=" + rating + "\n"); if (rating >= 6) { if (!(compFields.securityInfo instanceof Components.interfaces.nsIEnigMsgCompFields)) { this.createEnigmailSecurityFields(compFields.securityInfo); } let si = compFields.securityInfo.QueryInterface(Components.interfaces.nsIEnigMsgCompFields); if (this.identity.getBoolAttribute("protectSubject")) { si.originalSubject = compFields.subject; compFields.subject = ""; } else { si.originalSubject = null; } let encrypt = document.getElementById("enigmail-bc-pepEncrypt").getAttribute("encrypt"); si.sendFlags = (encrypt === "true" ? nsIEnigmail.SEND_ENCRYPTED : 0); } else { // attach own key this.attachPepKey(); } return true; }, encryptMsg: function(msgSendType) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg: msgSendType=" + msgSendType + ", Enigmail.msg.sendMode=" + this.sendMode + ", Enigmail.msg.statusEncrypted=" + this.statusEncrypted + "\n"); if (this.juniorMode) return this.encryptPepMessage(msgSendType); const nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.SEND_ENCRYPTED; const CiMsgCompDeliverMode = Components.interfaces.nsIMsgCompDeliverMode; var promptSvc = EnigmailDialog.getPromptSvc(); var newSecurityInfo; let arrLen = {}; let toAddrList = []; let recList; let bccAddrList = []; let splitRecipients; var gotSendFlags = this.sendMode; // here we process the final state: if (this.statusEncrypted == EnigmailConstants.ENIG_FINAL_YES || this.statusEncrypted == EnigmailConstants.ENIG_FINAL_FORCEYES) { gotSendFlags |= ENCRYPT; } else if (this.statusEncrypted == EnigmailConstants.ENIG_FINAL_FORCENO) { gotSendFlags &= ~ENCRYPT; } if (this.statusSigned == EnigmailConstants.ENIG_FINAL_YES || this.statusSigned == EnigmailConstants.ENIG_FINAL_FORCEYES) { gotSendFlags |= SIGN; } else if (this.statusSigned == EnigmailConstants.ENIG_FINAL_FORCENO) { gotSendFlags &= ~SIGN; } var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService); // EnigSend: Handle both plain and encrypted messages below var isOffline = (ioService && ioService.offline); var sendFlags = 0; if (gotSendFlags & SIGN) sendFlags |= SIGN; if (gotSendFlags & ENCRYPT) sendFlags |= ENCRYPT; if (msgSendType === CiMsgCompDeliverMode.Later) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg: adding SEND_LATER\n"); sendFlags |= nsIEnigmail.SEND_LATER; } if (this.statusPGPMime == EnigmailConstants.ENIG_FINAL_SMIME || this.statusPGPMime == EnigmailConstants.ENIG_FINAL_FORCESMIME) { // use S/MIME and return let si = gMsgCompose.compFields.securityInfo.QueryInterface(Components.interfaces.nsIMsgSMIMECompFields); if (sendFlags & SIGN) si.signMessage = true; if (sendFlags & ENCRYPT) si.requireEncryptMessage = true; let conf = this.isSendConfirmationRequired(sendFlags); if (conf === null) return false; if (conf) { msgCompFields = gMsgCompose.compFields; 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); } if (!this.confirmBeforeSend(toAddrList.join(", "), "", sendFlags, isOffline)) { return false; } } return true; } switch (msgSendType) { case CiMsgCompDeliverMode.SaveAsDraft: case CiMsgCompDeliverMode.SaveAsTemplate: case CiMsgCompDeliverMode.AutoSaveAsDraft: EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg: 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(); } this.unsetAdditionalHeader("x-enigmail-draft-status"); var msgCompFields = gMsgCompose.compFields; var 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; } this.identity = getCurrentIdentity(); if (gWindowLocked) { EnigmailDialog.alert(window, EnigmailLocale.getString("windowLocked")); return false; } 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!) try { if (gMsgCompose.compFields.securityInfo instanceof Components.interfaces.nsIEnigMsgCompFields) { gMsgCompose.compFields.securityInfo.sendFlags = 0; gMsgCompose.compFields.securityInfo.originalSubject = gMsgCompose.compFields.subject; } else if (!gMsgCompose.compFields.securityInfo) { throw "dummy"; } } catch (ex) { try { newSecurityInfo = Components.classes[this.compFieldsEnig_CID].createInstance(Components.interfaces.nsIEnigMsgCompFields); if (newSecurityInfo) { newSecurityInfo.sendFlags = 0; newSecurityInfo.originalSubject = gMsgCompose.compFields.subject; gMsgCompose.compFields.securityInfo = newSecurityInfo; } } catch (ex2) { EnigmailLog.writeException("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg", ex2); } } } this.dirty = 1; var enigmailSvc = EnigmailCore.getService(window); if (!enigmailSvc) { var msg = EnigmailLocale.getString("sendUnencrypted"); if (EnigmailCore.getEnigmailService() && EnigmailCore.getEnigmailService().initializationError) { msg = EnigmailCore.getEnigmailService().initializationError + "\n\n" + msg; } return EnigmailDialog.confirmDlg(window, msg, EnigmailLocale.getString("msgCompose.button.send")); } try { this.modifiedAttach = null; EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg: currentId=" + this.identity + ", " + this.identity.email + "\n"); var fromAddr = this.identity.email; if (!this.isEnigmailEnabled()) return true; var optSendFlags = 0; var inlineEncAttach = false; // request or preference to always accept (even non-authenticated) keys? if (this.trustAllKeys) { optSendFlags |= nsIEnigmail.SEND_ALWAYS_TRUST; } else { var acceptedKeys = EnigmailPrefs.getPref("acceptedKeys"); switch (acceptedKeys) { case 0: // accept valid/authenticated keys only break; case 1: // accept all but revoked/disabled/expired keys optSendFlags |= nsIEnigmail.SEND_ALWAYS_TRUST; break; default: EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg: INVALID VALUE for acceptedKeys: \"" + acceptedKeys + "\"\n"); break; } } if (EnigmailPrefs.getPref("encryptToSelf")) { optSendFlags |= nsIEnigmail.SEND_ENCRYPT_TO_SELF; } sendFlags |= optSendFlags; var userIdValue = this.getSenderUserId(); if (userIdValue) { fromAddr = userIdValue; } EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg: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); } // special handling of bcc: // - note: bcc and encryption is a problem // - but bcc to the sender is fine if (msgCompFields.bcc.length > 0) { recList = splitRecipients(msgCompFields.bcc, true, arrLen); var bccLC = EnigmailFuncs.stripEmail(msgCompFields.bcc).toLowerCase(); EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg: BCC: " + bccLC + "\n"); var selfBCC = this.identity.email && (this.identity.email.toLowerCase() == bccLC); if (selfBCC) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg: Self BCC\n"); this.addRecipients(toAddrList, recList); } else if (sendFlags & ENCRYPT) { // BCC and encryption var dummy = { value: null }; var hideBccUsers = promptSvc.confirmEx(window, EnigmailLocale.getString("enigConfirm"), EnigmailLocale.getString("sendingHiddenRcpt"), (promptSvc.BUTTON_TITLE_IS_STRING * promptSvc.BUTTON_POS_0) + (promptSvc.BUTTON_TITLE_CANCEL * promptSvc.BUTTON_POS_1) + (promptSvc.BUTTON_TITLE_IS_STRING * promptSvc.BUTTON_POS_2), EnigmailLocale.getString("sendWithShownBcc"), null, EnigmailLocale.getString("sendWithHiddenBcc"), null, dummy); switch (hideBccUsers) { case 2: this.addRecipients(bccAddrList, recList); this.addRecipients(toAddrList, recList); break; case 0: this.addRecipients(toAddrList, recList); break; case 1: return false; } } } if (newsgroups) { toAddrList.push(newsgroups); if (sendFlags & ENCRYPT) { if (!EnigmailPrefs.getPref("encryptToNews")) { EnigmailDialog.alert(window, EnigmailLocale.getString("sendingNews")); return false; } else if (!EnigmailDialog.confirmPref(window, EnigmailLocale.getString("sendToNewsWarning"), "warnOnSendingNewsgroups", EnigmailLocale.getString("msgCompose.button.send"))) { return false; } } } var usePGPMimeOption = EnigmailPrefs.getPref("usePGPMimeOption"); if (this.sendPgpMime) { // Use PGP/MIME sendFlags |= nsIEnigmail.SEND_PGP_MIME; } var result = this.keySelection(enigmailSvc, sendFlags, // all current combined/processed send flags (incl. optSendFlags) optSendFlags, // may only be SEND_ALWAYS_TRUST or SEND_ENCRYPT_TO_SELF gotSendFlags, // initial sendMode (0 or SIGN or ENCRYPT or SIGN|ENCRYPT) fromAddr, toAddrList, bccAddrList); if (!result) { return false; } var toAddrStr; var bccAddrStr; sendFlags = result.sendFlags; toAddrStr = result.toAddrStr; bccAddrStr = result.bccAddrStr; if (this.preferPgpOverSmime(sendFlags) === 0) { // use S/MIME sendFlags = 0; return true; } if (this.attachOwnKeyObj.appendAttachment) this.attachOwnKey(); var bucketList = document.getElementById("attachmentBucket"); var hasAttachments = ((bucketList && bucketList.hasChildNodes()) || gMsgCompose.compFields.attachVCard); EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: hasAttachments = " + hasAttachments + "\n"); if (hasAttachments && (sendFlags & (ENCRYPT | SIGN)) && !(sendFlags & nsIEnigmail.SEND_PGP_MIME)) { let inputObj = { pgpMimePossible: true, inlinePossible: true, restrictedScenario: false, reasonForCheck: "" }; // init reason for dialog to be able to use the right labels if (sendFlags & ENCRYPT) { if (sendFlags & SIGN) { inputObj.reasonForCheck = "encryptAndSign"; } else { inputObj.reasonForCheck = "encrypt"; } } else { if (sendFlags & SIGN) { inputObj.reasonForCheck = "sign"; } } // determine if attachments are all local files (currently the only // supported kind of attachments) var node = bucketList.firstChild; while (node) { if (node.attachment.url.substring(0, 7) != "file://") { inputObj.inlinePossible = false; } node = node.nextSibling; } if (inputObj.pgpMimePossible || inputObj.inlinePossible) { let resultObj = { selected: EnigmailPrefs.getPref("encryptAttachments") }; //skip or not var skipCheck = EnigmailPrefs.getPref("encryptAttachmentsSkipDlg"); if (skipCheck == 1) { if ((resultObj.selected == 2 && inputObj.pgpMimePossible === false) || (resultObj.selected == 1 && inputObj.inlinePossible === false)) { //add var to disable remember box since we're dealing with restricted scenarios... inputObj.restrictedScenario = true; resultObj.selected = -1; window.openDialog("chrome://enigmail/content/enigmailAttachmentsDialog.xul", "", "dialog,modal,centerscreen", inputObj, resultObj); } } else { resultObj.selected = -1; window.openDialog("chrome://enigmail/content/enigmailAttachmentsDialog.xul", "", "dialog,modal,centerscreen", inputObj, resultObj); } if (resultObj.selected < 0) { // dialog cancelled return false; } else if (resultObj.selected == 1) { // encrypt attachments inlineEncAttach = true; } else if (resultObj.selected == 2) { // send as PGP/MIME sendFlags |= nsIEnigmail.SEND_PGP_MIME; } else if (resultObj.selected == 3) { // cancel the encryption/signing for the whole message sendFlags &= ~ENCRYPT; sendFlags &= ~SIGN; } } else { if (sendFlags & ENCRYPT) { if (!EnigmailDialog.confirmDlg(window, EnigmailLocale.getString("attachWarning"), EnigmailLocale.getString("msgCompose.button.send"))) return false; } } } var usingPGPMime = (sendFlags & nsIEnigmail.SEND_PGP_MIME) && (sendFlags & (ENCRYPT | SIGN)); // ----------------------- Rewrapping code, taken from function "encryptInline" // Check wrapping, if sign only and inline and plaintext if ((sendFlags & SIGN) && !(sendFlags & ENCRYPT) && !(usingPGPMime) && !(gMsgCompose.composeHTML)) { var wrapresultObj = {}; this.wrapInLine(wrapresultObj); if (wrapresultObj.usePpgMime) { sendFlags |= nsIEnigmail.SEND_PGP_MIME; usingPGPMime = nsIEnigmail.SEND_PGP_MIME; } if (wrapresultObj.cancelled) { return false; } } var uiFlags = nsIEnigmail.UI_INTERACTIVE; if (usingPGPMime) uiFlags |= nsIEnigmail.UI_PGP_MIME; if ((sendFlags & (ENCRYPT | SIGN)) && usingPGPMime) { // Use PGP/MIME EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg: Using PGP/MIME, flags=" + sendFlags + "\n"); var oldSecurityInfo = gMsgCompose.compFields.securityInfo; EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg: oldSecurityInfo = " + oldSecurityInfo + "\n"); if (!oldSecurityInfo) { try { newSecurityInfo = oldSecurityInfo.QueryInterface(Components.interfaces.nsIEnigMsgCompFields); } catch (ex) {} } if (!newSecurityInfo) { this.createEnigmailSecurityFields(oldSecurityInfo); newSecurityInfo = gMsgCompose.compFields.securityInfo.QueryInterface(Components.interfaces.nsIEnigMsgCompFields); } newSecurityInfo.originalSubject = gMsgCompose.compFields.subject; newSecurityInfo.originalReferences = gMsgCompose.compFields.references; if (this.protectHeaders) { sendFlags |= nsIEnigmail.ENCRYPT_HEADERS; if (sendFlags & ENCRYPT) { gMsgCompose.compFields.subject = ""; if (EnigmailPrefs.getPref("protectReferencesHdr")) { gMsgCompose.compFields.references = ""; } } } newSecurityInfo.sendFlags = sendFlags; newSecurityInfo.UIFlags = uiFlags; newSecurityInfo.senderEmailAddr = fromAddr; newSecurityInfo.recipients = toAddrStr; newSecurityInfo.bccRecipients = bccAddrStr; EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg: securityInfo = " + newSecurityInfo + "\n"); } else if (!this.processed && (sendFlags & (ENCRYPT | SIGN))) { // use inline PGP var sendInfo = { sendFlags: sendFlags, inlineEncAttach: inlineEncAttach, fromAddr: fromAddr, toAddr: toAddrStr, bccAddr: bccAddrStr, uiFlags: uiFlags, bucketList: bucketList }; if (!this.encryptInline(sendInfo)) { return false; } } // update the list of attachments Attachments2CompFields(msgCompFields); let confirm = this.isSendConfirmationRequired(sendFlags); if (confirm === null) return false; // perform confirmation dialog if necessary/requested if (confirm) { if (!this.confirmBeforeSend(toAddrList.join(", "), toAddrStr + ", " + bccAddrStr, sendFlags, isOffline)) { if (this.processed) { this.undoEncryption(0); } else { this.removeAttachedKey(); } return false; } } else if ((sendFlags & nsIEnigmail.SEND_WITH_CHECK) && !this.messageSendCheck()) { // Abort send if (this.processed) { this.undoEncryption(0); } else { this.removeAttachedKey(); } 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.encryptMsg: enabled forceMsgEncoding\n"); } } catch (ex) {} } } } catch (ex) { EnigmailLog.writeException("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg", ex); let msg = EnigmailLocale.getString("signFailed"); if (EnigmailCore.getEnigmailService() && EnigmailCore.getEnigmailService().initializationError) { msg += "\n" + EnigmailCore.getEnigmailService().initializationError; } return EnigmailDialog.confirmDlg(window, msg, EnigmailLocale.getString("msgCompose.button.sendUnencrypted")); } // The encryption process for PGP/MIME messages follows "here". It's // called automatically from nsMsgCompose->sendMsg(). // registration for this is dome in chrome.manifest return true; }, encryptInline: function(sendInfo) { // sign/encrpyt message using inline-PGP const dce = Components.interfaces.nsIDocumentEncoder; const nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.SEND_ENCRYPTED; var enigmailSvc = EnigmailCore.getService(window); if (!enigmailSvc) return false; if (gMsgCompose.composeHTML) { var errMsg = EnigmailLocale.getString("hasHTML"); EnigmailDialog.alertCount(window, "composeHtmlAlertCount", errMsg); } try { var convert = DetermineConvertibility(); if (convert == Components.interfaces.nsIMsgCompConvertible.No) { if (!EnigmailDialog.confirmDlg(window, EnigmailLocale.getString("strippingHTML"), EnigmailLocale.getString("msgCompose.button.sendAnyway"))) { return false; } } } catch (ex) { EnigmailLog.writeException("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptInline", ex); } try { if (this.getMailPref("mail.strictly_mime")) { if (EnigmailDialog.confirmPref(window, EnigmailLocale.getString("quotedPrintableWarn"), "quotedPrintableWarn")) { EnigmailPrefs.getPrefRoot().setBoolPref("mail.strictly_mime", false); } } } catch (ex) {} var sendFlowed; try { sendFlowed = this.getMailPref("mailnews.send_plaintext_flowed"); } catch (ex) { sendFlowed = true; } var encoderFlags = dce.OutputFormatted | dce.OutputLFLineBreak; var wrapper = gMsgCompose.editor.QueryInterface(Components.interfaces.nsIEditorMailSupport); var editor = gMsgCompose.editor.QueryInterface(Components.interfaces.nsIPlaintextEditor); var wrapWidth = 72; if (!(sendInfo.sendFlags & ENCRYPT)) { // signed messages only if (gMsgCompose.composeHTML) { // enforce line wrapping here // otherwise the message isn't signed correctly try { wrapWidth = this.getMailPref("editor.htmlWrapColumn"); if (wrapWidth > 0 && wrapWidth < 68 && gMsgCompose.wrapLength > 0) { if (EnigmailDialog.confirmDlg(window, EnigmailLocale.getString("minimalLineWrapping", [wrapWidth]))) { EnigmailPrefs.getPrefRoot().setIntPref("editor.htmlWrapColumn", 68); } } if (EnigmailPrefs.getPref("wrapHtmlBeforeSend")) { if (wrapWidth) { editor.wrapWidth = wrapWidth - 2; // prepare for the worst case: a 72 char's long line starting with '-' wrapper.rewrap(false); } } } catch (ex) {} } else { // plaintext: Wrapping code has been moved to superordinate function encryptMsg 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 && !(sendInfo.sendFlags & ENCRYPT)) { // 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"); // Encrypt plaintext var charset = this.editorGetCharset(); EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptMsg: charset=" + charset + "\n"); // Encode plaintext to charset from unicode var plainText = (sendInfo.sendFlags & ENCRYPT) ? EnigmailData.convertFromUnicode(origText, charset) : EnigmailData.convertFromUnicode(escText, charset); var cipherText = enigmailSvc.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 if (gMsgCompose.composeHTML) { // workaround for Thunderbird bug (TB adds an extra space in front of the text) cipherText = "\n" + cipherText; } else cipherText = cipherText.replace(/\r\n/g, "\n"); if ((sendInfo.sendFlags & ENCRYPT) && charset && (charset.search(/^us-ascii$/i) !== 0)) { // Add Charset armor header for encrypted blocks cipherText = cipherText.replace(/(-----BEGIN PGP MESSAGE----- *)(\r?\n)/, "$1$2Charset: " + charset + "$2"); } // Decode ciphertext from charset to unicode and overwrite this.replaceEditorText(EnigmailData.convertToUnicode(cipherText, charset)); this.enableUndoEncryption(true); // Save original text (for undo) this.processed = { "origText": origText, "charset": charset }; } else { // Restore original text this.replaceEditorText(origText); this.enableUndoEncryption(false); if (sendInfo.sendFlags & (ENCRYPT | SIGN)) { // Encryption/signing failed /*if (statusFlagsObj.statusMsg) { // check if own key is invalid let s = new RegExp("^(\\[GNUPG:\\] )?INV_(RECP|SGNR) [0-9]+ \\?", "m"); if (statusFlagsObj.statusMsg.search(s) >= 0) { errorMsgObj.value += "\n\n" + EnigmailLocale.getString("keyError.resolutionAction"); } }*/ this.sendAborted(window, errorMsgObj); return false; } } } if (sendInfo.inlineEncAttach) { // encrypt attachments this.modifiedAttach = []; exitCode = this.encryptAttachments(sendInfo.bucketList, this.modifiedAttach, window, sendInfo.uiFlags, sendInfo.fromAddr, sendInfo.toAddr, sendInfo.bccAddr, sendInfo.sendFlags, errorMsgObj); if (exitCode !== 0) { this.modifiedAttach = null; this.sendAborted(window, errorMsgObj); if (this.processed) { this.undoEncryption(0); } else { this.removeAttachedKey(); } return false; } } return true; }, sendAborted: function(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 += EnigmailLocale.getString("keyNotTrusted", [key]) + "\n"; } else if (reason == "1") { errorMsg += EnigmailLocale.getString("keyNotFound", [key]) + "\n"; } else if (reason == "4") { errorMsg += EnigmailLocale.getString("keyRevoked", [key]) + "\n"; } else if (reason == "5") { errorMsg += EnigmailLocale.getString("keyExpired", [key]) + "\n"; } } } if (errorMsg !== "") { txt = errorMsg + "\n" + txt; } EnigmailDialog.info(window, EnigmailLocale.getString("sendAborted") + txt); } else { EnigmailDialog.info(window, EnigmailLocale.getString("sendAborted") + "\n" + EnigmailLocale.getString("msgCompose.internalError")); } }, getMailPref: function(prefName) { let prefRoot = EnigmailPrefs.getPrefRoot(); var prefValue = null; try { var prefType = prefRoot.getPrefType(prefName); // Get pref value switch (prefType) { case prefRoot.PREF_BOOL: prefValue = prefRoot.getBoolPref(prefName); break; case prefRoot.PREF_INT: prefValue = prefRoot.getIntPref(prefName); break; case prefRoot.PREF_STRING: prefValue = prefRoot.getCharPref(prefName); break; default: prefValue = undefined; break; } } catch (ex) { // Failed to get pref value EnigmailLog.ERROR("enigmailMsgComposeOverlay.js: Enigmail.msg.getMailPref: unknown prefName:" + prefName + " \n"); } return prefValue; }, messageSendCheck: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.messageSendCheck\n"); try { var warn = this.getMailPref("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) { EnigmailPrefs.getPrefRoot().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: function(hdr, val) { if ("otherRandomHeaders" in gMsgCompose.compFields) { // TB <= 36 gMsgCompose.compFields.otherRandomHeaders += hdr + ": " + val + "\r\n"; } else { gMsgCompose.compFields.setHeader(hdr, val); } }, unsetAdditionalHeader: function(hdr) { if ("otherRandomHeaders" in gMsgCompose.compFields) { // TB <= 36 let h = gMsgCompose.compFields.otherRandomHeaders; let r = new RegExp("^(" + hdr + ":)(.*)$", "im"); let m = h.replace(r, "").replace(/(\r\n)+/, "\r\n"); gMsgCompose.compFields.otherRandomHeaders = m; } else { gMsgCompose.compFields.deleteHeader(hdr); } }, modifyCompFields: function() { const HEADERMODE_KEYID = 0x01; const HEADERMODE_URL = 0x10; try { if (!this.identity) { this.identity = getCurrentIdentity(); } if (this.isEnigmailEnabled()) { if (EnigmailPrefs.getPref("addHeaders")) { this.setAdditionalHeader("X-Enigmail-Version", EnigmailApp.getVersion()); } var pgpHeader = ""; var openPgpHeaderMode = this.identity.getIntAttribute("openPgpHeaderMode"); if (openPgpHeaderMode & HEADERMODE_KEYID) { let key = EnigmailKeyRing.getKeyById(this.identity.getCharAttribute("pgpkeyId")); if (key && key.fpr && key.fpr.length > 0) { pgpHeader += "id=" + key.fpr; } } if (openPgpHeaderMode & HEADERMODE_URL) { if (pgpHeader.indexOf("=") > 0) pgpHeader += ";\r\n\t"; pgpHeader += "url=" + this.identity.getCharAttribute("openPgpUrlName"); } if (openPgpHeaderMode === 0) { pgpHeader = "preference=signencrypt"; } if (pgpHeader.length > 0) { this.setAdditionalHeader("OpenPGP", pgpHeader); } this.setAutocryptHeader(); } } catch (ex) { EnigmailLog.writeException("enigmailMsgComposeOverlay.js: Enigmail.msg.modifyCompFields", ex); } }, setAutocryptHeader: function() { if (EnigmailPEPAdapter.usingPep() || EnigmailPrefs.getPref("autocryptMode") === 0) { return; } if (!this.identity) { this.identity = getCurrentIdentity(); } let key; if (this.identity.getIntAttribute("pgpKeyMode") > 0) { key = EnigmailKeyRing.getKeyById(this.identity.getCharAttribute("pgpkeyId")); } else { key = EnigmailKeyRing.getSecretKeyByUserId(this.identity.email); } if (key) { let k = key.getMinimalPubKey(); if (k.exitCode === 0) { let keyData = k.keyData.replace(/(.{72})/g, " $1\r\n"); this.setAdditionalHeader('Autocrypt', 'to=' + this.identity.email + '; key=\r\n' + keyData); } } }, /** * Handle the 'compose-send-message' event from TB */ sendMessageListener: function(event) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.sendMessageListener\n"); // Do nothing if a compatible version of the "SendLater" addon is installed. // SendLater will call handleSendMessageEvent when needed. try { if (typeof(Sendlater3Composing.callEnigmail) === "function") { return; } } catch (ex) {} Enigmail.msg.handleSendMessageEvent(event); }, /** * Perform handling of the compose-send-message' event from TB (or SendLater) */ handleSendMessageEvent: function(event) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.handleSendMessageEvent\n"); let msgcomposeWindow = document.getElementById("msgcomposeWindow"); let sendMsgType = Number(msgcomposeWindow.getAttribute("msgtype")); if (!(this.sendProcess && sendMsgType == Components.interfaces.nsIMsgCompDeliverMode.AutoSaveAsDraft)) { this.sendProcess = true; let bc = document.getElementById("enigmail-bc-sendprocess"); try { this.modifyCompFields(); bc.setAttribute("disabled", "true"); if (!this.encryptMsg(sendMsgType)) { this.resetUpdatedFields(); event.preventDefault(); event.stopPropagation(); } } catch (ex) {} bc.removeAttribute("disabled"); } else { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.sendMessageListener: sending in progress - autosave aborted\n"); event.preventDefault(); event.stopPropagation(); } this.sendProcess = false; }, // encrypt attachments when sending inline PGP mails // It's quite a hack: the attachments are stored locally // and the attachments list is modified to pick up the // encrypted file(s) instead of the original ones. encryptAttachments: function(bucketList, newAttachments, window, uiFlags, fromAddr, toAddr, bccAddr, sendFlags, errorMsgObj) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptAttachments\n"); const nsIEnigmail = Components.interfaces.nsIEnigmail; const SIGN = nsIEnigmail.SEND_SIGNED; const ENCRYPT = nsIEnigmail.SEND_ENCRYPTED; var ioServ; var fileTemplate; errorMsgObj.value = ""; try { ioServ = Components.classes[IOSERVICE_CONTRACTID].getService(Components.interfaces.nsIIOService); if (!ioServ) return -1; } catch (ex) { return -1; } var tmpDir = EnigmailFiles.getTempDir(); var extAppLauncher = Components.classes["@mozilla.org/mime;1"]. getService(Components.interfaces.nsPIExternalAppLauncher); try { fileTemplate = Components.classes[LOCAL_FILE_CONTRACTID].createInstance(Components.interfaces.nsIFile); fileTemplate.initWithPath(tmpDir); if (!(fileTemplate.isDirectory() && fileTemplate.isWritable())) { errorMsgObj.value = EnigmailLocale.getString("noTempDir"); return -1; } fileTemplate.append("encfile"); } catch (ex) { errorMsgObj.value = EnigmailLocale.getString("noTempDir"); return -1; } EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.encryptAttachments tmpDir=" + tmpDir + "\n"); var enigmailSvc = EnigmailCore.getService(window); if (!enigmailSvc) return null; var exitCodeObj = {}; var statusFlagsObj = {}; var node = bucketList.firstChild; while (node) { var origUrl = node.attachment.url; if (origUrl.substring(0, 7) != "file://") { // this should actually never happen since it is pre-checked! errorMsgObj.value = "The attachment '" + node.attachment.name + "' is not a local file"; return -1; } // transform attachment URL to platform-specific file name var origUri = ioServ.newURI(origUrl, null, null); var origFile = origUri.QueryInterface(Components.interfaces.nsIFileURL); if (node.attachment.temporary) { try { var origLocalFile = Components.classes[LOCAL_FILE_CONTRACTID].createInstance(Components.interfaces.nsIFile); origLocalFile.initWithPath(origFile.file.path); extAppLauncher.deleteTemporaryFileOnExit(origLocalFile); } catch (ex) {} } var newFile = fileTemplate.clone(); var txtMessage; try { newFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0x180); txtMessage = enigmailSvc.encryptAttachment(window, fromAddr, toAddr, bccAddr, sendFlags, origFile.file, newFile, exitCodeObj, statusFlagsObj, errorMsgObj); } catch (ex) {} if (exitCodeObj.value !== 0) { return exitCodeObj.value; } var fileInfo = { origFile: origFile, origUrl: node.attachment.url, origName: node.attachment.name, origTemp: node.attachment.temporary, origCType: node.attachment.contentType }; // transform platform specific new file name to file:// URL var newUri = ioServ.newFileURI(newFile); fileInfo.newUrl = newUri.asciiSpec; fileInfo.newFile = newFile; fileInfo.encrypted = (sendFlags & ENCRYPT); newAttachments.push(fileInfo); node = node.nextSibling; } var i = 0; if (sendFlags & ENCRYPT) { // if we got here, all attachments were encrpted successfully, // so we replace their names & urls node = bucketList.firstChild; while (node) { node.attachment.url = newAttachments[i].newUrl; node.attachment.name += EnigmailPrefs.getPref("inlineAttachExt"); node.attachment.contentType = "application/octet-stream"; node.attachment.temporary = true; ++i; node = node.nextSibling; } } else { // for inline signing we need to add new attachments for every // signed file for (i = 0; i < newAttachments.length; i++) { // create new attachment var fileAttachment = Components.classes["@mozilla.org/messengercompose/attachment;1"].createInstance(Components.interfaces.nsIMsgAttachment); fileAttachment.temporary = true; fileAttachment.url = newAttachments[i].newUrl; fileAttachment.name = newAttachments[i].origName + EnigmailPrefs.getPref("inlineSigAttachExt"); // add attachment to msg this.addAttachment(fileAttachment); } } return 0; }, toggleAttribute: function(attrName) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.toggleAttribute('" + attrName + "')\n"); var menuElement = document.getElementById("enigmail_" + attrName); var oldValue = EnigmailPrefs.getPref(attrName); EnigmailPrefs.setPref(attrName, !oldValue); }, toggleAccountAttr: function(attrName) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.toggleAccountAttr('" + attrName + "')\n"); var oldValue = this.identity.getBoolAttribute(attrName); this.identity.setBoolAttribute(attrName, !oldValue); }, decryptQuote: function(interactive) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.decryptQuote: " + interactive + "\n"); const nsIEnigmail = Components.interfaces.nsIEnigmail; if (gWindowLocked || this.processed) return; var enigmailSvc = EnigmailCore.getService(window); if (!enigmailSvc) return; const dce = Components.interfaces.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, "> >"); } // Delete indentation indentRegexp = new RegExp("^" + indentStr, "gm"); pgpBlock = pgpBlock.replace(indentRegexp, ""); //tail = tail.replace(indentRegexp, ""); if (indentStr.match(/[ \t]*$/)) { indentStr = indentStr.replace(/[ \t]*$/gm, ""); indentRegexp = new RegExp("^" + indentStr + "$", "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); if ((!this.getMailPref("mailnews.reply_in_default_charset")) && (blockType == "MESSAGE")) { // set charset according to PGP block, if available (encrypted messages only) cipherText = cipherText.replace(/\r\n/g, "\n"); cipherText = cipherText.replace(/\r/g, "\n"); let cPos = cipherText.search(/\nCharset: .+\n/i); if (cPos < cipherText.search(/\n\n/)) { var charMatch = cipherText.match(/\n(Charset: )(.+)\n/i); if (charMatch && charMatch.length > 2) { charset = charMatch[2]; gMsgCompose.SetDocumentCharset(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 = nsIEnigmail.UI_UNVERIFIED_ENC_OK; var plainText = ""; if (EnigmailPEPAdapter.usingPep()) { let msgHdr = this.getMsgHdr(); let addresses = { from: null, to: EnigmailFuncs.parseEmails(msgHdr.recipients), cc: EnigmailFuncs.parseEmails(msgHdr.ccList) }; let fromAddr = EnigmailFuncs.parseEmails(msgHdr.author); if (fromAddr.length > 0) addresses.from = fromAddr[0]; let pEpResult = EnigmailPEPDecrypt.decryptMessageData(false, cipherText, addresses); if (pEpResult && pEpResult.longmsg.length > 0) { plainText = pEpResult.longmsg; exitCodeObj.value = 0; errorMsgObj.value = ""; } } else { plainText = enigmailSvc.decryptMessage(window, uiFlags, cipherText, 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 (EnigmailPrefs.getPref("keepSettingsForReply")) { if (statusFlagsObj.value & nsIEnigmail.DECRYPTION_OKAY) this.setSendMode('encrypt'); } var exitCode = exitCodeObj.value; if (exitCode !== 0) { // Error processing var errorMsg = errorMsgObj.value; var statusLines = 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, nsIEnigmail.SIGNATURE_TEXT); } const nsIMsgCompType = Components.interfaces.nsIMsgCompType; var doubleDashSeparator = EnigmailPrefs.getPref("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); } } var clipBoard = Components.classes["@mozilla.org/widget/clipboard;1"]. getService(Components.interfaces.nsIClipboard); var data; if (clipBoard.supportsSelectionClipboard()) { // get the clipboard contents for selected text (X11) data = EnigmailClipboard.getClipboardContent(window, Components.interfaces.nsIClipboard.kSelectionClipboard); } // Replace encrypted quote with decrypted quote (destroys selection clipboard on X11) 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 (clipBoard.supportsSelectionClipboard()) { // restore the clipboard contents for selected text (X11) EnigmailClipboard.setClipboardContent(data, clipBoard.kSelectionClipboard); } if (interactive) return; // Position cursor var replyOnTop = 1; try { replyOnTop = this.identity.replyOnTop; } catch (ex) {} if (!indentStr || !quoteElement) replyOnTop = 1; EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.decryptQuote: replyOnTop=" + replyOnTop + ", quoteElement=" + quoteElement + "\n"); var nsISelectionController = Components.interfaces.nsISelectionController; 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(nsISelectionController.SELECTION_NORMAL, nsISelectionController.SELECTION_ANCHOR_REGION, true); } this.processFinalState(); this.updateStatusBar(); }, editorInsertText: function(plainText) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.editorInsertText\n"); if (this.editor) { var mailEditor; try { mailEditor = this.editor.QueryInterface(Components.interfaces.nsIEditorMailSupport); mailEditor.insertTextWithQuotations(plainText); } catch (ex) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.editorInsertText: no mail editor\n"); this.editor.insertText(plainText); } } }, editorInsertAsQuotation: function(plainText) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.editorInsertAsQuotation\n"); if (this.editor) { var mailEditor; try { mailEditor = this.editor.QueryInterface(Components.interfaces.nsIEditorMailSupport); } catch (ex) {} if (!mailEditor) return 0; EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.editorInsertAsQuotation: mailEditor=" + mailEditor + "\n"); mailEditor.insertAsQuotation(plainText); return 1; } return 0; }, /** * 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. */ notifyUser: function(priority, msgText, messageId, detailsText) { let notif = document.getElementById("attachmentNotificationBox"); let prio; switch (priority) { case 1: prio = notif.PRIORITY_CRITICAL_MEDIUM; break; case 3: prio = notif.PRIORITY_INFO_MEDIUM; break; default: prio = notif.PRIORITY_WARNING_MEDIUM; } let buttonArr = []; if (detailsText && detailsText.length > 0) { buttonArr.push({ accessKey: EnigmailLocale.getString("msgCompose.detailsButton.accessKey"), label: EnigmailLocale.getString("msgCompose.detailsButton.label"), callback: function(aNotificationBar, aButton) { EnigmailDialog.info(window, detailsText); } }); } notif.appendNotification(msgText, messageId, null, prio, buttonArr); }, editorSelectAll: function() { if (this.editor) { this.editor.selectAll(); } }, editorGetCharset: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.editorGetCharset\n"); return this.editor.documentCharacterSet; }, editorGetContentAs: function(mimeType, flags) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.editorGetContentAs\n"); if (this.editor) { return this.editor.outputToString(mimeType, flags); } return null; }, addrOnChangeTimer: null, addressOnChange: function(element) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.addressOnChange\n"); if (!this.addrOnChangeTimer) { var self = this; this.addrOnChangeTimer = EnigmailTimer.setTimeout(function _f() { self.fireSendFlags(); self.addrOnChangeTimer = null; }, 250); } }, focusChange: function() { // 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; Enigmail.msg.fireSendFlags(); }, fireSendFlags: function() { try { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: Enigmail.msg.fireSendFlags\n"); if (!this.determineSendFlagId) { this.determineSendFlagId = EnigmailEvents.dispatchEvent( function _sendFlagWrapper() { Enigmail.msg.determineSendFlags(); }, 0); } } catch (ex) {} }, /** * Merge multiple Re: Re: into one Re: in message subject */ fixMessageSubject: function() { let subjElem = document.getElementById("msgSubject"); if (subjElem) { let r = subjElem.value.replace(/^(Re: )+(.*)/, "Re: $2"); if (r !== subjElem.value) { subjElem.value = r; if (typeof subjElem.oninput === "function") subjElem.oninput(); } } } }; Enigmail.composeStateListener = { NotifyComposeFieldsReady: function() { // 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(Components.interfaces.nsIEditor); } catch (ex) {} if (!Enigmail.msg.editor) return; Enigmail.msg.fixMessageSubject(); function enigDocStateListener() {} enigDocStateListener.prototype = { QueryInterface: function(iid) { if (!iid.equals(Components.interfaces.nsIDocumentStateListener) && !iid.equals(Components.interfaces.nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; }, NotifyDocumentCreated: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: EDSL.NotifyDocumentCreated\n"); }, NotifyDocumentWillBeDestroyed: function() { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: EDSL.enigDocStateListener.NotifyDocumentWillBeDestroyed\n"); }, NotifyDocumentStateChanged: function(nowDirty) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: EDSL.enigDocStateListener.NotifyDocumentStateChanged\n"); } }; var docStateListener = new enigDocStateListener(); Enigmail.msg.editor.addDocumentStateListener(docStateListener); }, ComposeProcessDone: function(aResult) { // Note: called after a mail was sent (or saved) EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: ECSL.ComposeProcessDone: " + aResult + "\n"); if (aResult != Components.results.NS_OK) { if (Enigmail.msg.processed) { Enigmail.msg.undoEncryption(4); } Enigmail.msg.removeAttachedKey(); } // ensure that securityInfo is set back to S/MIME flags (especially required if draft was saved) if (gSMFields) gMsgCompose.compFields.securityInfo = gSMFields; }, NotifyComposeBodyReady: function() { 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: EDSL.ComposeBodyReady: isEmpty=" + isEmpty + ", isEditable=" + isEditable + "\n"); //FIXME EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: EDSL.ComposeBodyReady: disableSmime=" + Enigmail.msg.disableSmime + "\n"); if (Enigmail.msg.disableSmime) { if (gMsgCompose && gMsgCompose.compFields && gMsgCompose.compFields.securityInfo) { let si = gMsgCompose.compFields.securityInfo.QueryInterface(Components.interfaces.nsIMsgSMIMECompFields); si.signMessage = false; si.requireEncryptMessage = false; } else { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: EDSL.ComposeBodyReady: could not disable S/MIME\n"); } } if (!isEditable || isEmpty) return; // Required for TB < 48 (with window recycling) Enigmail.msg.fixMessageSubject(); if (!Enigmail.msg.timeoutId && !Enigmail.msg.dirty) { Enigmail.msg.timeoutId = EnigmailTimer.setTimeout(function() { Enigmail.msg.decryptQuote(false); }, 0); } }, SaveInFolderDone: function(folderURI) { //EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: ECSL.SaveInFolderDone\n"); } }; window.addEventListener("load", function _enigmail_composeStartup(event) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: got load event\n"); Enigmail.msg.composeStartup(event); }, false); window.addEventListener("unload", function _enigmail_composeUnload(event) { Enigmail.msg.composeUnload(event); }, false); // Handle recycled windows // TB < 47 window.addEventListener('compose-window-close', function _enigmail_msgComposeClose(event) { Enigmail.msg.msgComposeClose(event); }, true); // TB >= 48 window.addEventListener('compose-window-unload', function _enigmail_msgComposeDestory(event) { Enigmail.msg.msgComposeClose(event); }, true); // TB < 47 only window.addEventListener('compose-window-reopen', function _enigmail_msgComposeReopen(event) { Enigmail.msg.msgComposeReopen(event); }, true); // Listen to message sending event window.addEventListener('compose-send-message', function _enigmail_sendMessageListener(event) { Enigmail.msg.sendMessageListener(event); }, true); window.addEventListener('compose-window-init', function _enigmail_composeWindowInit(event) { EnigmailLog.DEBUG("enigmailMsgComposeOverlay.js: _enigmail_composeWindowInit\n"); gMsgCompose.RegisterStateListener(Enigmail.composeStateListener); Enigmail.msg.composeBodyReady = false; }, true);