summaryrefslogtreecommitdiffstats
path: root/mailnews/extensions/smime/content
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/extensions/smime/content')
-rw-r--r--mailnews/extensions/smime/content/am-smime.js478
-rw-r--r--mailnews/extensions/smime/content/am-smime.xul26
-rw-r--r--mailnews/extensions/smime/content/am-smimeIdentityEditOverlay.xul39
-rw-r--r--mailnews/extensions/smime/content/am-smimeOverlay.xul102
-rw-r--r--mailnews/extensions/smime/content/certFetchingStatus.js265
-rw-r--r--mailnews/extensions/smime/content/certFetchingStatus.xul24
-rw-r--r--mailnews/extensions/smime/content/certpicker.js73
-rw-r--r--mailnews/extensions/smime/content/certpicker.xul38
-rw-r--r--mailnews/extensions/smime/content/msgCompSMIMEOverlay.js357
-rw-r--r--mailnews/extensions/smime/content/msgCompSMIMEOverlay.xul85
-rw-r--r--mailnews/extensions/smime/content/msgCompSecurityInfo.js244
-rw-r--r--mailnews/extensions/smime/content/msgCompSecurityInfo.xul68
-rw-r--r--mailnews/extensions/smime/content/msgHdrViewSMIMEOverlay.js264
-rw-r--r--mailnews/extensions/smime/content/msgHdrViewSMIMEOverlay.xul29
-rw-r--r--mailnews/extensions/smime/content/msgReadSMIMEOverlay.js102
-rw-r--r--mailnews/extensions/smime/content/msgReadSMIMEOverlay.xul34
-rw-r--r--mailnews/extensions/smime/content/msgReadSecurityInfo.js232
-rw-r--r--mailnews/extensions/smime/content/msgReadSecurityInfo.xul68
-rw-r--r--mailnews/extensions/smime/content/smime.js14
19 files changed, 2542 insertions, 0 deletions
diff --git a/mailnews/extensions/smime/content/am-smime.js b/mailnews/extensions/smime/content/am-smime.js
new file mode 100644
index 000000000..4a90d0cd7
--- /dev/null
+++ b/mailnews/extensions/smime/content/am-smime.js
@@ -0,0 +1,478 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+var nsIX509CertDB = Components.interfaces.nsIX509CertDB;
+var nsX509CertDBContractID = "@mozilla.org/security/x509certdb;1";
+var nsIX509Cert = Components.interfaces.nsIX509Cert;
+
+var email_recipient_cert_usage = 5;
+var email_signing_cert_usage = 4;
+
+var gIdentity;
+var gPref = null;
+var gEncryptionCertName = null;
+var gHiddenEncryptionPolicy = null;
+var gEncryptionChoices = null;
+var gSignCertName = null;
+var gSignMessages = null;
+var gEncryptAlways = null;
+var gNeverEncrypt = null;
+var gBundle = null;
+var gBrandBundle;
+var gSmimePrefbranch;
+var gEncryptionChoicesLocked;
+var gSigningChoicesLocked;
+var kEncryptionCertPref = "identity.encryption_cert_name";
+var kSigningCertPref = "identity.signing_cert_name";
+
+function onInit()
+{
+ smimeInitializeFields();
+}
+
+function smimeInitializeFields()
+{
+ // initialize all of our elements based on the current identity values....
+ gEncryptionCertName = document.getElementById(kEncryptionCertPref);
+ gHiddenEncryptionPolicy = document.getElementById("identity.encryptionpolicy");
+ gEncryptionChoices = document.getElementById("encryptionChoices");
+ gSignCertName = document.getElementById(kSigningCertPref);
+ gSignMessages = document.getElementById("identity.sign_mail");
+ gEncryptAlways = document.getElementById("encrypt_mail_always");
+ gNeverEncrypt = document.getElementById("encrypt_mail_never");
+ gBundle = document.getElementById("bundle_smime");
+ gBrandBundle = document.getElementById("bundle_brand");
+
+ gEncryptionChoicesLocked = false;
+ gSigningChoicesLocked = false;
+
+ if (!gIdentity) {
+ // The user is going to create a new identity.
+ // Set everything to default values.
+ // Do not take over the values from gAccount.defaultIdentity
+ // as the new identity is going to have a different mail address.
+
+ gEncryptionCertName.value = "";
+ gEncryptionCertName.nickname = "";
+ gEncryptionCertName.dbKey = "";
+ gSignCertName.value = "";
+ gSignCertName.nickname = "";
+ gSignCertName.dbKey = "";
+
+ gEncryptAlways.setAttribute("disabled", true);
+ gNeverEncrypt.setAttribute("disabled", true);
+ gSignMessages.setAttribute("disabled", true);
+
+ gSignMessages.checked = false;
+ gEncryptionChoices.value = 0;
+ }
+ else {
+ var certdb = Components.classes[nsX509CertDBContractID].getService(nsIX509CertDB);
+ var x509cert = null;
+
+ gEncryptionCertName.value = gIdentity.getUnicharAttribute("encryption_cert_name");
+ gEncryptionCertName.dbKey = gIdentity.getCharAttribute("encryption_cert_dbkey");
+ // If we succeed in looking up the certificate by the dbkey pref, then
+ // append the serial number " [...]" to the display value, and remember the
+ // nickname in a separate property.
+ try {
+ if (certdb && gEncryptionCertName.dbKey &&
+ (x509cert = certdb.findCertByDBKey(gEncryptionCertName.dbKey))) {
+ gEncryptionCertName.value = x509cert.nickname + " [" + x509cert.serialNumber + "]";
+ gEncryptionCertName.nickname = x509cert.nickname;
+ }
+ } catch(e) {}
+
+ gEncryptionChoices.value = gIdentity.getIntAttribute("encryptionpolicy");
+
+ if (!gEncryptionCertName.value) {
+ gEncryptAlways.setAttribute("disabled", true);
+ gNeverEncrypt.setAttribute("disabled", true);
+ }
+ else {
+ enableEncryptionControls(true);
+ }
+
+ gSignCertName.value = gIdentity.getUnicharAttribute("signing_cert_name");
+ gSignCertName.dbKey = gIdentity.getCharAttribute("signing_cert_dbkey");
+ x509cert = null;
+ // same procedure as with gEncryptionCertName (see above)
+ try {
+ if (certdb && gSignCertName.dbKey &&
+ (x509cert = certdb.findCertByDBKey(gSignCertName.dbKey))) {
+ gSignCertName.value = x509cert.nickname + " [" + x509cert.serialNumber + "]";
+ gSignCertName.nickname = x509cert.nickname;
+ }
+ } catch(e) {}
+
+ gSignMessages.checked = gIdentity.getBoolAttribute("sign_mail");
+ if (!gSignCertName.value)
+ {
+ gSignMessages.setAttribute("disabled", true);
+ }
+ else {
+ enableSigningControls(true);
+ }
+ }
+
+ // Always start with enabling signing and encryption cert select buttons.
+ // This will keep the visibility of buttons in a sane state as user
+ // jumps from security panel of one account to another.
+ enableCertSelectButtons();
+
+ // Disable all locked elements on the panel
+ if (gIdentity)
+ onLockPreference();
+}
+
+function onPreInit(account, accountValues)
+{
+ gIdentity = account.defaultIdentity;
+}
+
+function onSave()
+{
+ smimeSave();
+}
+
+function smimeSave()
+{
+ // find out which radio for the encryption radio group is selected and set that on our hidden encryptionChoice pref....
+ var newValue = gEncryptionChoices.value;
+ gHiddenEncryptionPolicy.setAttribute('value', newValue);
+ gIdentity.setIntAttribute("encryptionpolicy", newValue);
+ gIdentity.setUnicharAttribute("encryption_cert_name",
+ gEncryptionCertName.nickname || gEncryptionCertName.value);
+ gIdentity.setCharAttribute("encryption_cert_dbkey", gEncryptionCertName.dbKey);
+
+ gIdentity.setBoolAttribute("sign_mail", gSignMessages.checked);
+ gIdentity.setUnicharAttribute("signing_cert_name",
+ gSignCertName.nickname || gSignCertName.value);
+ gIdentity.setCharAttribute("signing_cert_dbkey", gSignCertName.dbKey);
+}
+
+function smimeOnAcceptEditor()
+{
+ try {
+ if (!onOk())
+ return false;
+ }
+ catch (ex) {}
+
+ smimeSave();
+
+ return true;
+}
+
+function onLockPreference()
+{
+ var initPrefString = "mail.identity";
+ var finalPrefString;
+
+ var allPrefElements = [
+ { prefstring:"signingCertSelectButton", id:"signingCertSelectButton"},
+ { prefstring:"encryptionCertSelectButton", id:"encryptionCertSelectButton"},
+ { prefstring:"sign_mail", id:"identity.sign_mail"},
+ { prefstring:"encryptionpolicy", id:"encryptionChoices"}
+ ];
+
+ finalPrefString = initPrefString + "." + gIdentity.key + ".";
+ gSmimePrefbranch = Services.prefs.getBranch(finalPrefString);
+
+ disableIfLocked( allPrefElements );
+}
+
+
+// Does the work of disabling an element given the array which contains xul id/prefstring pairs.
+// Also saves the id/locked state in an array so that other areas of the code can avoid
+// stomping on the disabled state indiscriminately.
+function disableIfLocked( prefstrArray )
+{
+ var i;
+ for (i=0; i<prefstrArray.length; i++) {
+ var id = prefstrArray[i].id;
+ var element = document.getElementById(id);
+ if (gSmimePrefbranch.prefIsLocked(prefstrArray[i].prefstring)) {
+ // If encryption choices radio group is locked, make sure the individual
+ // choices in the group are locked. Set a global (gEncryptionChoicesLocked)
+ // indicating the status so that locking can be maintained further.
+ if (id == "encryptionChoices") {
+ document.getElementById("encrypt_mail_never").setAttribute("disabled", "true");
+ document.getElementById("encrypt_mail_always").setAttribute("disabled", "true");
+ gEncryptionChoicesLocked = true;
+ }
+ // If option to sign mail is locked (with true/false set in config file), disable
+ // the corresponding checkbox and set a global (gSigningChoicesLocked) in order to
+ // honor the locking as user changes other elements on the panel.
+ if (id == "identity.sign_mail") {
+ document.getElementById("identity.sign_mail").setAttribute("disabled", "true");
+ gSigningChoicesLocked = true;
+ }
+ else {
+ element.setAttribute("disabled", "true");
+ if (id == "signingCertSelectButton") {
+ document.getElementById("signingCertClearButton").setAttribute("disabled", "true");
+ }
+ else if (id == "encryptionCertSelectButton") {
+ document.getElementById("encryptionCertClearButton").setAttribute("disabled", "true");
+ }
+ }
+ }
+ }
+}
+
+function alertUser(message)
+{
+ Services.prompt.alert(window,
+ gBrandBundle.getString("brandShortName"),
+ message);
+}
+
+function askUser(message)
+{
+ let button = Services.prompt.confirmEx(
+ window,
+ gBrandBundle.getString("brandShortName"),
+ message,
+ Services.prompt.STD_YES_NO_BUTTONS,
+ null,
+ null,
+ null,
+ null,
+ {});
+ // confirmEx returns button index:
+ return (button == 0);
+}
+
+function checkOtherCert(cert, pref, usage, msgNeedCertWantSame, msgWantSame, msgNeedCertWantToSelect, enabler)
+{
+ var otherCertInfo = document.getElementById(pref);
+ if (!otherCertInfo)
+ return;
+
+ if (otherCertInfo.dbKey == cert.dbKey)
+ // all is fine, same cert is now selected for both purposes
+ return;
+
+ var certdb = Components.classes[nsX509CertDBContractID].getService(nsIX509CertDB);
+ if (!certdb)
+ return;
+
+ if (email_recipient_cert_usage == usage) {
+ matchingOtherCert = certdb.findEmailEncryptionCert(cert.nickname);
+ }
+ else if (email_signing_cert_usage == usage) {
+ matchingOtherCert = certdb.findEmailSigningCert(cert.nickname);
+ }
+ else
+ return;
+
+ var userWantsSameCert = false;
+
+ if (!otherCertInfo.value.length) {
+ if (matchingOtherCert && (matchingOtherCert.dbKey == cert.dbKey)) {
+ userWantsSameCert = askUser(gBundle.getString(msgNeedCertWantSame));
+ }
+ else {
+ if (askUser(gBundle.getString(msgNeedCertWantToSelect))) {
+ smimeSelectCert(pref);
+ }
+ }
+ }
+ else {
+ if (matchingOtherCert && (matchingOtherCert.dbKey == cert.dbKey)) {
+ userWantsSameCert = askUser(gBundle.getString(msgWantSame));
+ }
+ }
+
+ if (userWantsSameCert) {
+ otherCertInfo.value = cert.nickname + " [" + cert.serialNumber + "]";
+ otherCertInfo.nickname = cert.nickname;
+ otherCertInfo.dbKey = cert.dbKey;
+ enabler(true);
+ }
+}
+
+function smimeSelectCert(smime_cert)
+{
+ var certInfo = document.getElementById(smime_cert);
+ if (!certInfo)
+ return;
+
+ var picker = Components.classes["@mozilla.org/user_cert_picker;1"]
+ .createInstance(Components.interfaces.nsIUserCertPicker);
+ var canceled = new Object;
+ var x509cert = 0;
+ var certUsage;
+ var selectEncryptionCert;
+
+ if (smime_cert == kEncryptionCertPref) {
+ selectEncryptionCert = true;
+ certUsage = email_recipient_cert_usage;
+ } else if (smime_cert == kSigningCertPref) {
+ selectEncryptionCert = false;
+ certUsage = email_signing_cert_usage;
+ }
+
+ try {
+ x509cert = picker.pickByUsage(window,
+ certInfo.value,
+ certUsage, // this is from enum SECCertUsage
+ false, true,
+ gIdentity.email,
+ canceled);
+ } catch(e) {
+ canceled.value = false;
+ x509cert = null;
+ }
+
+ if (!canceled.value) {
+ if (!x509cert) {
+ if (gIdentity.email) {
+ alertUser(gBundle.getFormattedString(selectEncryptionCert ?
+ "NoEncryptionCertForThisAddress" :
+ "NoSigningCertForThisAddress",
+ [ gIdentity.email ]));
+ } else {
+ alertUser(gBundle.getString(selectEncryptionCert ?
+ "NoEncryptionCert" : "NoSigningCert"));
+ }
+ }
+ else {
+ certInfo.removeAttribute("disabled");
+ certInfo.value = x509cert.nickname + " [" + x509cert.serialNumber + "]";
+ certInfo.nickname = x509cert.nickname;
+ certInfo.dbKey = x509cert.dbKey;
+
+ if (selectEncryptionCert) {
+ enableEncryptionControls(true);
+
+ checkOtherCert(x509cert,
+ kSigningCertPref, email_signing_cert_usage,
+ "signing_needCertWantSame",
+ "signing_wantSame",
+ "signing_needCertWantToSelect",
+ enableSigningControls);
+ } else {
+ enableSigningControls(true);
+
+ checkOtherCert(x509cert,
+ kEncryptionCertPref, email_recipient_cert_usage,
+ "encryption_needCertWantSame",
+ "encryption_wantSame",
+ "encryption_needCertWantToSelect",
+ enableEncryptionControls);
+ }
+ }
+ }
+
+ enableCertSelectButtons();
+}
+
+function enableEncryptionControls(do_enable)
+{
+ if (gEncryptionChoicesLocked)
+ return;
+
+ if (do_enable) {
+ gEncryptAlways.removeAttribute("disabled");
+ gNeverEncrypt.removeAttribute("disabled");
+ gEncryptionCertName.removeAttribute("disabled");
+ }
+ else {
+ gEncryptAlways.setAttribute("disabled", "true");
+ gNeverEncrypt.setAttribute("disabled", "true");
+ gEncryptionCertName.setAttribute("disabled", "true");
+ gEncryptionChoices.value = 0;
+ }
+}
+
+function enableSigningControls(do_enable)
+{
+ if (gSigningChoicesLocked)
+ return;
+
+ if (do_enable) {
+ gSignMessages.removeAttribute("disabled");
+ gSignCertName.removeAttribute("disabled");
+ }
+ else {
+ gSignMessages.setAttribute("disabled", "true");
+ gSignCertName.setAttribute("disabled", "true");
+ gSignMessages.checked = false;
+ }
+}
+
+function enableCertSelectButtons()
+{
+ document.getElementById("signingCertSelectButton").removeAttribute("disabled");
+
+ if (document.getElementById('identity.signing_cert_name').value.length)
+ document.getElementById("signingCertClearButton").removeAttribute("disabled");
+ else
+ document.getElementById("signingCertClearButton").setAttribute("disabled", "true");
+
+ document.getElementById("encryptionCertSelectButton").removeAttribute("disabled");
+
+ if (document.getElementById('identity.encryption_cert_name').value.length)
+ document.getElementById("encryptionCertClearButton").removeAttribute("disabled");
+ else
+ document.getElementById("encryptionCertClearButton").setAttribute("disabled", "true");
+}
+
+function smimeClearCert(smime_cert)
+{
+ var certInfo = document.getElementById(smime_cert);
+ if (!certInfo)
+ return;
+
+ certInfo.setAttribute("disabled", "true");
+ certInfo.value = "";
+ certInfo.nickname = "";
+ certInfo.dbKey = "";
+
+ if (smime_cert == kEncryptionCertPref) {
+ enableEncryptionControls(false);
+ } else if (smime_cert == kSigningCertPref) {
+ enableSigningControls(false);
+ }
+
+ enableCertSelectButtons();
+}
+
+function openCertManager()
+{
+ // Check for an existing certManager window and focus it; it's not
+ // application modal.
+ let lastCertManager = Services.wm.getMostRecentWindow("mozilla:certmanager");
+ if (lastCertManager)
+ lastCertManager.focus();
+ else
+ window.openDialog("chrome://pippki/content/certManager.xul", "",
+ "centerscreen,resizable=yes,dialog=no");
+}
+
+function openDeviceManager()
+{
+ // Check for an existing deviceManager window and focus it; it's not
+ // application modal.
+ let lastCertManager = Services.wm.getMostRecentWindow("mozilla:devicemanager");
+ if (lastCertManager)
+ lastCertManager.focus();
+ else
+ window.openDialog("chrome://pippki/content/device_manager.xul", "",
+ "centerscreen,resizable=yes,dialog=no");
+}
+
+function smimeOnLoadEditor()
+{
+ smimeInitializeFields();
+
+ document.documentElement.setAttribute("ondialogaccept",
+ "return smimeOnAcceptEditor();");
+}
+
diff --git a/mailnews/extensions/smime/content/am-smime.xul b/mailnews/extensions/smime/content/am-smime.xul
new file mode 100644
index 000000000..bb46bb49d
--- /dev/null
+++ b/mailnews/extensions/smime/content/am-smime.xul
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://messenger/skin/accountManage.css" type="text/css"?>
+
+<?xul-overlay href="chrome://messenger/content/am-smimeOverlay.xul"?>
+
+<!DOCTYPE page SYSTEM "chrome://messenger/locale/am-smime.dtd">
+
+<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ class="color-dialog"
+ onload="parent.onPanelLoaded('am-smime.xul');"
+ ondialogaccept="smimeOnAcceptEditor();">
+
+ <vbox flex="1" style="overflow: auto;">
+ <script type="application/javascript" src="chrome://messenger/content/AccountManager.js"/>
+ <script type="application/javascript" src="chrome://messenger/content/am-smime.js"/>
+
+ <dialogheader title="&securityTitle.label;"/>
+
+ <vbox flex="1" id="smimeEditing"/>
+ </vbox>
+
+</page>
diff --git a/mailnews/extensions/smime/content/am-smimeIdentityEditOverlay.xul b/mailnews/extensions/smime/content/am-smimeIdentityEditOverlay.xul
new file mode 100644
index 000000000..2ff5c2b7d
--- /dev/null
+++ b/mailnews/extensions/smime/content/am-smimeIdentityEditOverlay.xul
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://messenger/skin/accountManage.css"
+ type="text/css"?>
+
+<?xul-overlay href="chrome://messenger/content/am-smimeOverlay.xul"?>
+
+<!DOCTYPE overlay SYSTEM "chrome://messenger/locale/am-smime.dtd">
+
+<!--
+ This is the overlay that adds the SMIME configurator
+ to the identity editor of the account manager
+-->
+<overlay id="smimeAmIdEditOverlay"
+ xmlns:html="http://www.w3.org/1999/xhtml"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript"
+ src="chrome://messenger/content/AccountManager.js"/>
+ <script type="application/javascript"
+ src="chrome://messenger/content/am-smime.js"/>
+
+ <tabs id="identitySettings">
+ <tab label="&securityTab.label;"/>
+ </tabs>
+
+ <tabpanels id="identityTabsPanels">
+ <vbox flex="1" name="smimeEditingContent" id="smimeEditing"/>
+ </tabpanels>
+
+ <script type="application/javascript">
+ <![CDATA[
+ window.addEventListener("load", smimeOnLoadEditor, false);
+ ]]>
+ </script>
+</overlay>
diff --git a/mailnews/extensions/smime/content/am-smimeOverlay.xul b/mailnews/extensions/smime/content/am-smimeOverlay.xul
new file mode 100644
index 000000000..eb76b4b2c
--- /dev/null
+++ b/mailnews/extensions/smime/content/am-smimeOverlay.xul
@@ -0,0 +1,102 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://messenger/skin/accountManage.css"
+ type="text/css"?>
+
+<!DOCTYPE overlay SYSTEM "chrome://messenger/locale/am-smime.dtd">
+
+<overlay xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <vbox id="smimeEditing">
+
+ <stringbundleset>
+ <stringbundle id="bundle_smime" src="chrome://messenger/locale/am-smime.properties"/>
+ <stringbundle id="bundle_brand" src="chrome://branding/locale/brand.properties"/>
+ </stringbundleset>
+
+ <label hidden="true" wsm_persist="true" id="identity.encryptionpolicy"/>
+
+ <description>&securityHeading.label;</description>
+
+ <groupbox id="signing.titlebox">
+ <caption label="&signingGroupTitle.label;"/>
+
+ <label value="&signingCert.message;" control="identity.signing_cert_name"
+ prefstring="mail.identity.%identitykey%.encryptionpolicy"/>
+
+ <hbox align="center">
+ <textbox id="identity.signing_cert_name" wsm_persist="true" flex="1"
+ prefstring="mail.identity.%identitykey%.signing_cert_name"
+ readonly="true" disabled="true"/>
+
+ <button id="signingCertSelectButton"
+ label="&digitalSign.certificate.button;"
+ accesskey="&digitalSign.certificate.accesskey;"
+ oncommand="smimeSelectCert('identity.signing_cert_name')"/>
+
+ <button id="signingCertClearButton"
+ label="&digitalSign.certificate_clear.button;"
+ accesskey="&digitalSign.certificate_clear.accesskey;"
+ oncommand="smimeClearCert('identity.signing_cert_name')"/>
+ </hbox>
+
+ <separator class="thin"/>
+
+ <checkbox id="identity.sign_mail" wsm_persist="true"
+ prefstring="mail.identity.%identitykey%.sign_mail"
+ label="&signMessage.label;" accesskey="&signMessage.accesskey;"/>
+ </groupbox>
+
+ <groupbox id="encryption.titlebox">
+ <caption label="&encryptionGroupTitle.label;"/>
+
+ <label value="&encryptionCert.message;"
+ control="identity.encryption_cert_name"/>
+
+ <hbox align="center">
+ <textbox id="identity.encryption_cert_name" wsm_persist="true" flex="1"
+ prefstring="mail.identity.%identitykey%.encryption_cert_name"
+ readonly="true" disabled="true"/>
+
+ <button id="encryptionCertSelectButton"
+ label="&encryption.certificate.button;"
+ accesskey="&encryption.certificate.accesskey;"
+ oncommand="smimeSelectCert('identity.encryption_cert_name')"/>
+
+ <button id="encryptionCertClearButton"
+ label="&encryption.certificate_clear.button;"
+ accesskey="&encryption.certificate_clear.accesskey;"
+ oncommand="smimeClearCert('identity.encryption_cert_name')"/>
+ </hbox>
+
+ <separator class="thin"/>
+
+ <label value="&encryptionChoiceLabel.label;" control="encryptionChoices"/>
+
+ <radiogroup id="encryptionChoices">
+ <radio id="encrypt_mail_never" wsm_persist="true" value="0"
+ label="&neverEncrypt.label;"
+ accesskey="&neverEncrypt.accesskey;"/>
+
+ <radio id="encrypt_mail_always" wsm_persist="true" value="2"
+ label="&alwaysEncryptMessage.label;"
+ accesskey="&alwaysEncryptMessage.accesskey;"/>
+ </radiogroup>
+ </groupbox>
+
+ <!-- Certificate manager -->
+ <groupbox id="smimeCertificateManager" orient="horizontal">
+ <caption label="&certificates.label;"/>
+ <button id="openCertManagerButton" oncommand="openCertManager();"
+ label="&manageCerts2.label;" accesskey="&manageCerts2.accesskey;"
+ prefstring="security.disable_button.openCertManager"/>
+ <button id="openDeviceManagerButton" oncommand="openDeviceManager();"
+ label="&manageDevices.label;" accesskey="&manageDevices.accesskey;"
+ prefstring="security.disable_button.openDeviceManager"/>
+ </groupbox>
+ </vbox>
+</overlay>
diff --git a/mailnews/extensions/smime/content/certFetchingStatus.js b/mailnews/extensions/smime/content/certFetchingStatus.js
new file mode 100644
index 000000000..8848ff9b6
--- /dev/null
+++ b/mailnews/extensions/smime/content/certFetchingStatus.js
@@ -0,0 +1,265 @@
+/* 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/. */
+
+/* We expect the following arguments:
+ - pref name of LDAP directory to fetch from
+ - array with email addresses
+
+ Display modal dialog with message and stop button.
+ In onload, kick off binding to LDAP.
+ When bound, kick off the searches.
+ On finding certificates, import into permanent cert database.
+ When all searches are finished, close the dialog.
+*/
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+var nsIX509CertDB = Components.interfaces.nsIX509CertDB;
+var nsX509CertDB = "@mozilla.org/security/x509certdb;1";
+var CertAttribute = "usercertificate;binary";
+
+var gEmailAddresses;
+var gDirectoryPref;
+var gLdapServerURL;
+var gLdapConnection;
+var gCertDB;
+var gLdapOperation;
+var gLogin;
+
+function onLoad()
+{
+ gDirectoryPref = window.arguments[0];
+ gEmailAddresses = window.arguments[1];
+
+ if (!gEmailAddresses.length)
+ {
+ window.close();
+ return;
+ }
+
+ setTimeout(search, 1);
+}
+
+function search()
+{
+ // get the login to authenticate as, if there is one
+ try {
+ gLogin = Services.prefs.getComplexValue(gDirectoryPref + ".auth.dn", Components.interfaces.nsISupportsString).data;
+ } catch (ex) {
+ // if we don't have this pref, no big deal
+ }
+
+ try {
+ let url = Services.prefs.getCharPref(gDirectoryPref + ".uri");
+
+ gLdapServerURL = Services.io
+ .newURI(url, null, null).QueryInterface(Components.interfaces.nsILDAPURL);
+
+ gLdapConnection = Components.classes["@mozilla.org/network/ldap-connection;1"]
+ .createInstance().QueryInterface(Components.interfaces.nsILDAPConnection);
+
+ gLdapConnection.init(gLdapServerURL, gLogin, new boundListener(),
+ null, Components.interfaces.nsILDAPConnection.VERSION3);
+
+ } catch (ex) {
+ dump(ex);
+ dump(" exception creating ldap connection\n");
+ window.close();
+ }
+}
+
+function stopFetching()
+{
+ if (gLdapOperation) {
+ try {
+ gLdapOperation.abandon();
+ }
+ catch (e) {
+ }
+ }
+ return true;
+}
+
+function importCert(ber_value)
+{
+ if (!gCertDB) {
+ gCertDB = Components.classes[nsX509CertDB].getService(nsIX509CertDB);
+ }
+
+ var cert_length = new Object();
+ var cert_bytes = ber_value.get(cert_length);
+
+ if (cert_bytes) {
+ gCertDB.importEmailCertificate(cert_bytes, cert_length.value, null);
+ }
+}
+
+function getLDAPOperation()
+{
+ gLdapOperation = Components.classes["@mozilla.org/network/ldap-operation;1"]
+ .createInstance().QueryInterface(Components.interfaces.nsILDAPOperation);
+
+ gLdapOperation.init(gLdapConnection,
+ new ldapMessageListener(),
+ null);
+}
+
+function getPassword()
+{
+ // we only need a password if we are using credentials
+ if (gLogin)
+ {
+ let authPrompter = Services.ww.getNewAuthPrompter(window.QueryInterface(Components.interfaces.nsIDOMWindow));
+ let strBundle = document.getElementById('bundle_ldap');
+ let password = { value: "" };
+
+ // nsLDAPAutocompleteSession uses asciiHost instead of host for the prompt text, I think we should be
+ // consistent.
+ if (authPrompter.promptPassword(strBundle.getString("authPromptTitle"),
+ strBundle.getFormattedString("authPromptText", [gLdapServerURL.asciiHost]),
+ gLdapServerURL.spec,
+ authPrompter.SAVE_PASSWORD_PERMANENTLY,
+ password))
+ return password.value;
+ }
+
+ return null;
+}
+
+function kickOffBind()
+{
+ try {
+ getLDAPOperation();
+ gLdapOperation.simpleBind(getPassword());
+ }
+ catch (e) {
+ window.close();
+ }
+}
+
+function kickOffSearch()
+{
+ try {
+ var prefix1 = "";
+ var suffix1 = "";
+
+ var urlFilter = gLdapServerURL.filter;
+
+ if (urlFilter != null && urlFilter.length > 0 && urlFilter != "(objectclass=*)") {
+ if (urlFilter.startsWith('(')) {
+ prefix1 = "(&" + urlFilter;
+ }
+ else {
+ prefix1 = "(&(" + urlFilter + ")";
+ }
+ suffix1 = ")";
+ }
+
+ var prefix2 = "";
+ var suffix2 = "";
+
+ if (gEmailAddresses.length > 1) {
+ prefix2 = "(|";
+ suffix2 = ")";
+ }
+
+ var mailFilter = "";
+
+ for (var i = 0; i < gEmailAddresses.length; ++i) {
+ mailFilter += "(mail=" + gEmailAddresses[i] + ")";
+ }
+
+ var filter = prefix1 + prefix2 + mailFilter + suffix2 + suffix1;
+
+ var wanted_attributes = CertAttribute;
+
+ // Max search results =>
+ // Double number of email addresses, because each person might have
+ // multiple certificates listed. We expect at most two certificates,
+ // one for signing, one for encrypting.
+ // Maybe that number should be larger, to allow for deployments,
+ // where even more certs can be stored per user???
+
+ var maxEntriesWanted = gEmailAddresses.length * 2;
+
+ getLDAPOperation();
+ gLdapOperation.searchExt(gLdapServerURL.dn, gLdapServerURL.scope,
+ filter, wanted_attributes, 0, maxEntriesWanted);
+ }
+ catch (e) {
+ window.close();
+ }
+}
+
+
+function boundListener() {
+}
+
+boundListener.prototype.QueryInterface =
+ function(iid) {
+ if (iid.equals(Components.interfaces.nsISupports) ||
+ iid.equals(Components.interfaces.nsILDAPMessageListener))
+ return this;
+
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ }
+
+boundListener.prototype.onLDAPMessage =
+ function(aMessage) {
+ }
+
+boundListener.prototype.onLDAPInit =
+ function(aConn, aStatus) {
+ kickOffBind();
+ }
+
+
+function ldapMessageListener() {
+}
+
+ldapMessageListener.prototype.QueryInterface =
+ function(iid) {
+ if (iid.equals(Components.interfaces.nsISupports) ||
+ iid.equals(Components.interfaces.nsILDAPMessageListener))
+ return this;
+
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ }
+
+ldapMessageListener.prototype.onLDAPMessage =
+ function(aMessage) {
+ if (Components.interfaces.nsILDAPMessage.RES_SEARCH_RESULT == aMessage.type) {
+ window.close();
+ return;
+ }
+
+ if (Components.interfaces.nsILDAPMessage.RES_BIND == aMessage.type) {
+ if (Components.interfaces.nsILDAPErrors.SUCCESS != aMessage.errorCode) {
+ window.close();
+ }
+ else {
+ kickOffSearch();
+ }
+ return;
+ }
+
+ if (Components.interfaces.nsILDAPMessage.RES_SEARCH_ENTRY == aMessage.type) {
+ var outSize = new Object();
+ try {
+ var outBinValues = aMessage.getBinaryValues(CertAttribute, outSize);
+
+ var i;
+ for (i=0; i < outSize.value; ++i) {
+ importCert(outBinValues[i]);
+ }
+ }
+ catch (e) {
+ }
+ return;
+ }
+ }
+
+ldapMessageListener.prototype.onLDAPInit =
+ function(aConn, aStatus) {
+ }
diff --git a/mailnews/extensions/smime/content/certFetchingStatus.xul b/mailnews/extensions/smime/content/certFetchingStatus.xul
new file mode 100644
index 000000000..29b824fc9
--- /dev/null
+++ b/mailnews/extensions/smime/content/certFetchingStatus.xul
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://messenger/skin/smime/certFetchingStatus.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://messenger-smime/locale/certFetchingStatus.dtd">
+
+<dialog id="certFetchingStatus" title="&title.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ style="width: 50em;"
+ buttons="cancel"
+ buttonlabelcancel="&stop.label;"
+ ondialogcancel="return stopFetching();"
+ onload="onLoad();">
+
+ <stringbundle id="bundle_ldap" src="chrome://mozldap/locale/ldap.properties"/>
+<script type="application/javascript" src="chrome://messenger-smime/content/certFetchingStatus.js"/>
+
+ <description>&info.message;</description>
+
+</dialog>
diff --git a/mailnews/extensions/smime/content/certpicker.js b/mailnews/extensions/smime/content/certpicker.js
new file mode 100644
index 000000000..19554066f
--- /dev/null
+++ b/mailnews/extensions/smime/content/certpicker.js
@@ -0,0 +1,73 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock;
+
+var dialogParams;
+var itemCount = 0;
+
+function onLoad()
+{
+ dialogParams = window.arguments[0].QueryInterface(nsIDialogParamBlock);
+
+ var selectElement = document.getElementById("nicknames");
+ itemCount = dialogParams.GetInt(0);
+
+ var selIndex = dialogParams.GetInt(1);
+ if (selIndex < 0) {
+ selIndex = 0;
+ }
+
+ for (let i = 0; i < itemCount; i++) {
+ let menuItemNode = document.createElement("menuitem");
+ let nick = dialogParams.GetString(i);
+ menuItemNode.setAttribute("value", i);
+ menuItemNode.setAttribute("label", nick); // This is displayed.
+ selectElement.firstChild.appendChild(menuItemNode);
+
+ if (selIndex == i) {
+ selectElement.selectedItem = menuItemNode;
+ }
+ }
+
+ dialogParams.SetInt(0, 0); // Set cancel return value.
+ setDetails();
+}
+
+function setDetails()
+{
+ let selItem = document.getElementById("nicknames").value;
+ if (selItem.length == 0) {
+ return;
+ }
+
+ let index = parseInt(selItem);
+ let details = dialogParams.GetString(index + itemCount);
+ document.getElementById("details").value = details;
+}
+
+function onCertSelected()
+{
+ setDetails();
+}
+
+function doOK()
+{
+ // Signal that the user accepted.
+ dialogParams.SetInt(0, 1);
+
+ // Signal the index of the selected cert in the list of cert nicknames
+ // provided.
+ let index = parseInt(document.getElementById("nicknames").value);
+ dialogParams.SetInt(1, index);
+ return true;
+}
+
+function doCancel()
+{
+ dialogParams.SetInt(0, 0); // Signal that the user cancelled.
+ return true;
+}
diff --git a/mailnews/extensions/smime/content/certpicker.xul b/mailnews/extensions/smime/content/certpicker.xul
new file mode 100644
index 000000000..2c4cd3b22
--- /dev/null
+++ b/mailnews/extensions/smime/content/certpicker.xul
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % amSMIMEDTD SYSTEM "chrome://messenger/locale/am-smime.dtd" >
+%amSMIMEDTD;
+]>
+
+<dialog id="certPicker" title="&certPicker.title;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ style="width: 50em;"
+ buttons="accept,cancel"
+ ondialogaccept="return doOK();"
+ ondialogcancel="return doCancel();"
+ onload="onLoad();">
+
+<script type="application/javascript"
+ src="chrome://messenger/content/certpicker.js"/>
+
+ <hbox align="center">
+ <broadcaster id="certSelected" oncommand="onCertSelected();"/>
+ <label id="pickerInfo" value="&certPicker.info;"/>
+ <!-- The items in this menulist must never be sorted,
+ but remain in the order filled by the application
+ -->
+ <menulist id="nicknames" observes="certSelected">
+ <menupopup/>
+ </menulist>
+ </hbox>
+ <separator class="thin"/>
+ <label value="&certPicker.detailsLabel;"/>
+ <textbox readonly="true" id="details" multiline="true"
+ style="height: 12em;" flex="1"/>
+</dialog>
diff --git a/mailnews/extensions/smime/content/msgCompSMIMEOverlay.js b/mailnews/extensions/smime/content/msgCompSMIMEOverlay.js
new file mode 100644
index 000000000..582a073ea
--- /dev/null
+++ b/mailnews/extensions/smime/content/msgCompSMIMEOverlay.js
@@ -0,0 +1,357 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+// Account encryption policy values:
+// const kEncryptionPolicy_Never = 0;
+// 'IfPossible' was used by ns4.
+// const kEncryptionPolicy_IfPossible = 1;
+var kEncryptionPolicy_Always = 2;
+
+var gEncryptedURIService =
+ Components.classes["@mozilla.org/messenger-smime/smime-encrypted-uris-service;1"]
+ .getService(Components.interfaces.nsIEncryptedSMIMEURIsService);
+
+var gNextSecurityButtonCommand = "";
+var gSMFields = null;
+var gEncryptOptionChanged;
+var gSignOptionChanged;
+
+function onComposerLoad()
+{
+ // Are we already set up ? Or are the required fields missing ?
+ if (gSMFields || !gMsgCompose || !gMsgCompose.compFields)
+ return;
+
+ gMsgCompose.compFields.securityInfo = null;
+
+ gSMFields = Components.classes["@mozilla.org/messenger-smime/composefields;1"]
+ .createInstance(Components.interfaces.nsIMsgSMIMECompFields);
+ if (!gSMFields)
+ return;
+
+ gMsgCompose.compFields.securityInfo = gSMFields;
+
+ // Set up the intial security state.
+ gSMFields.requireEncryptMessage =
+ gCurrentIdentity.getIntAttribute("encryptionpolicy") == kEncryptionPolicy_Always;
+ if (!gSMFields.requireEncryptMessage &&
+ gEncryptedURIService &&
+ gEncryptedURIService.isEncrypted(gMsgCompose.originalMsgURI))
+ {
+ // Override encryption setting if original is known as encrypted.
+ gSMFields.requireEncryptMessage = true;
+ }
+ if (gSMFields.requireEncryptMessage)
+ setEncryptionUI();
+ else
+ setNoEncryptionUI();
+
+ gSMFields.signMessage = gCurrentIdentity.getBoolAttribute("sign_mail");
+ if (gSMFields.signMessage)
+ setSignatureUI();
+ else
+ setNoSignatureUI();
+}
+
+addEventListener("load", smimeComposeOnLoad, {capture: false, once: true});
+
+// this function gets called multiple times
+function smimeComposeOnLoad()
+{
+ onComposerLoad();
+
+ top.controllers.appendController(SecurityController);
+
+ addEventListener("compose-from-changed", onComposerFromChanged, true);
+ addEventListener("compose-send-message", onComposerSendMessage, true);
+
+ addEventListener("unload", smimeComposeOnUnload, {capture: false, once: true});
+}
+
+function smimeComposeOnUnload()
+{
+ removeEventListener("compose-from-changed", onComposerFromChanged, true);
+ removeEventListener("compose-send-message", onComposerSendMessage, true);
+
+ top.controllers.removeController(SecurityController);
+}
+
+function showNeedSetupInfo()
+{
+ let compSmimeBundle = document.getElementById("bundle_comp_smime");
+ let brandBundle = document.getElementById("bundle_brand");
+ if (!compSmimeBundle || !brandBundle)
+ return;
+
+ let buttonPressed = Services.prompt.confirmEx(window,
+ brandBundle.getString("brandShortName"),
+ compSmimeBundle.getString("NeedSetup"),
+ Services.prompt.STD_YES_NO_BUTTONS, 0, 0, 0, null, {});
+ if (buttonPressed == 0)
+ openHelp("sign-encrypt", "chrome://communicator/locale/help/suitehelp.rdf");
+}
+
+function toggleEncryptMessage()
+{
+ if (!gSMFields)
+ return;
+
+ gSMFields.requireEncryptMessage = !gSMFields.requireEncryptMessage;
+
+ if (gSMFields.requireEncryptMessage)
+ {
+ // Make sure we have a cert.
+ if (!gCurrentIdentity.getUnicharAttribute("encryption_cert_name"))
+ {
+ gSMFields.requireEncryptMessage = false;
+ showNeedSetupInfo();
+ return;
+ }
+
+ setEncryptionUI();
+ }
+ else
+ {
+ setNoEncryptionUI();
+ }
+
+ gEncryptOptionChanged = true;
+}
+
+function toggleSignMessage()
+{
+ if (!gSMFields)
+ return;
+
+ gSMFields.signMessage = !gSMFields.signMessage;
+
+ if (gSMFields.signMessage) // make sure we have a cert name...
+ {
+ if (!gCurrentIdentity.getUnicharAttribute("signing_cert_name"))
+ {
+ gSMFields.signMessage = false;
+ showNeedSetupInfo();
+ return;
+ }
+
+ setSignatureUI();
+ }
+ else
+ {
+ setNoSignatureUI();
+ }
+
+ gSignOptionChanged = true;
+}
+
+function setSecuritySettings(menu_id)
+{
+ if (!gSMFields)
+ return;
+
+ document.getElementById("menu_securityEncryptRequire" + menu_id)
+ .setAttribute("checked", gSMFields.requireEncryptMessage);
+ document.getElementById("menu_securitySign" + menu_id)
+ .setAttribute("checked", gSMFields.signMessage);
+}
+
+function setNextCommand(what)
+{
+ gNextSecurityButtonCommand = what;
+}
+
+function doSecurityButton()
+{
+ var what = gNextSecurityButtonCommand;
+ gNextSecurityButtonCommand = "";
+
+ switch (what)
+ {
+ case "encryptMessage":
+ toggleEncryptMessage();
+ break;
+
+ case "signMessage":
+ toggleSignMessage();
+ break;
+
+ case "show":
+ default:
+ showMessageComposeSecurityStatus();
+ }
+}
+
+function setNoSignatureUI()
+{
+ top.document.getElementById("securityStatus").removeAttribute("signing");
+ top.document.getElementById("signing-status").collapsed = true;
+}
+
+function setSignatureUI()
+{
+ top.document.getElementById("securityStatus").setAttribute("signing", "ok");
+ top.document.getElementById("signing-status").collapsed = false;
+}
+
+function setNoEncryptionUI()
+{
+ top.document.getElementById("securityStatus").removeAttribute("crypto");
+ top.document.getElementById("encryption-status").collapsed = true;
+}
+
+function setEncryptionUI()
+{
+ top.document.getElementById("securityStatus").setAttribute("crypto", "ok");
+ top.document.getElementById("encryption-status").collapsed = false;
+}
+
+function showMessageComposeSecurityStatus()
+{
+ Recipients2CompFields(gMsgCompose.compFields);
+
+ window.openDialog(
+ "chrome://messenger-smime/content/msgCompSecurityInfo.xul",
+ "",
+ "chrome,modal,resizable,centerscreen",
+ {
+ compFields : gMsgCompose.compFields,
+ subject : GetMsgSubjectElement().value,
+ smFields : gSMFields,
+ isSigningCertAvailable :
+ gCurrentIdentity.getUnicharAttribute("signing_cert_name") != "",
+ isEncryptionCertAvailable :
+ gCurrentIdentity.getUnicharAttribute("encryption_cert_name") != "",
+ currentIdentity : gCurrentIdentity
+ }
+ );
+}
+
+var SecurityController =
+{
+ supportsCommand: function(command)
+ {
+ switch (command)
+ {
+ case "cmd_viewSecurityStatus":
+ return true;
+
+ default:
+ return false;
+ }
+ },
+
+ isCommandEnabled: function(command)
+ {
+ switch (command)
+ {
+ case "cmd_viewSecurityStatus":
+ return true;
+
+ default:
+ return false;
+ }
+ }
+};
+
+function onComposerSendMessage()
+{
+ let missingCount = new Object();
+ let emailAddresses = new Object();
+
+ try
+ {
+ if (!gMsgCompose.compFields.securityInfo.requireEncryptMessage)
+ return;
+
+ Components.classes["@mozilla.org/messenger-smime/smimejshelper;1"]
+ .createInstance(Components.interfaces.nsISMimeJSHelper)
+ .getNoCertAddresses(gMsgCompose.compFields,
+ missingCount,
+ emailAddresses);
+ }
+ catch (e)
+ {
+ return;
+ }
+
+ if (missingCount.value > 0)
+ {
+ // The rules here: If the current identity has a directoryServer set, then
+ // use that, otherwise, try the global preference instead.
+
+ let autocompleteDirectory;
+
+ // Does the current identity override the global preference?
+ if (gCurrentIdentity.overrideGlobalPref)
+ {
+ autocompleteDirectory = gCurrentIdentity.directoryServer;
+ }
+ else
+ {
+ // Try the global one
+ if (Services.prefs.getBoolPref("ldap_2.autoComplete.useDirectory"))
+ autocompleteDirectory =
+ Services.prefs.getCharPref("ldap_2.autoComplete.directoryServer");
+ }
+
+ if (autocompleteDirectory)
+ window.openDialog("chrome://messenger-smime/content/certFetchingStatus.xul",
+ "",
+ "chrome,modal,resizable,centerscreen",
+ autocompleteDirectory,
+ emailAddresses.value);
+ }
+}
+
+function onComposerFromChanged()
+{
+ if (!gSMFields)
+ return;
+
+ var encryptionPolicy = gCurrentIdentity.getIntAttribute("encryptionpolicy");
+ var useEncryption = false;
+
+ if (!gEncryptOptionChanged)
+ {
+ // Encryption wasn't manually checked.
+ // Set up the encryption policy from the setting of the new identity.
+
+ // 0 == never, 1 == if possible (ns4), 2 == always encrypt.
+ useEncryption = (encryptionPolicy == kEncryptionPolicy_Always);
+ }
+ else
+ {
+ useEncryption = !!gCurrentIdentity.getUnicharAttribute("encryption_cert_name");
+ }
+
+ gSMFields.requireEncryptMessage = useEncryption;
+ if (useEncryption)
+ setEncryptionUI();
+ else
+ setNoEncryptionUI();
+
+ // - If signing is disabled, we will not turn it on automatically.
+ // - If signing is enabled, but the new account defaults to not sign, we will turn signing off.
+ var signMessage = gCurrentIdentity.getBoolAttribute("sign_mail");
+ var useSigning = false;
+
+ if (!gSignOptionChanged)
+ {
+ // Signing wasn't manually checked.
+ // Set up the signing policy from the setting of the new identity.
+ useSigning = signMessage;
+ }
+ else
+ {
+ useSigning = !!gCurrentIdentity.getUnicharAttribute("signing_cert_name");
+ }
+ gSMFields.signMessage = useSigning;
+ if (useSigning)
+ setSignatureUI();
+ else
+ setNoSignatureUI();
+}
diff --git a/mailnews/extensions/smime/content/msgCompSMIMEOverlay.xul b/mailnews/extensions/smime/content/msgCompSMIMEOverlay.xul
new file mode 100644
index 000000000..ec6495e20
--- /dev/null
+++ b/mailnews/extensions/smime/content/msgCompSMIMEOverlay.xul
@@ -0,0 +1,85 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+
+<?xml-stylesheet href="chrome://messenger/skin/smime/msgCompSMIMEOverlay.css" type="text/css"?>
+
+<!DOCTYPE overlay SYSTEM "chrome://messenger-smime/locale/msgCompSMIMEOverlay.dtd">
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://messenger-smime/content/msgCompSMIMEOverlay.js"/>
+
+ <window id="msgcomposeWindow">
+ <broadcaster id="securityStatus" crypto="" signing=""/>
+ <observes element="securityStatus" attribute="crypto" />
+ <observes element="securityStatus" attribute="signing" />
+ <stringbundle id="bundle_comp_smime" src="chrome://messenger-smime/locale/msgCompSMIMEOverlay.properties"/>
+ <stringbundle id="bundle_brand" src="chrome://branding/locale/brand.properties"/>
+ </window>
+
+ <menupopup id="optionsMenuPopup"
+ onpopupshowing="setSecuritySettings(1);">
+ <menuseparator id="smimeOptionsSeparator"/>
+
+ <menuitem id="menu_securityEncryptRequire1"
+ type="checkbox"
+ label="&menu_securityEncryptRequire.label;"
+ accesskey="&menu_securityEncryptRequire.accesskey;"
+ oncommand="toggleEncryptMessage();"/>
+ <menuitem id="menu_securitySign1"
+ type="checkbox"
+ label="&menu_securitySign.label;"
+ accesskey="&menu_securitySign.accesskey;"
+ oncommand="toggleSignMessage();"/>
+ </menupopup>
+
+ <toolbarpalette id="MsgComposeToolbarPalette">
+ <toolbarbutton id="button-security"
+ type="menu-button"
+ class="toolbarbutton-1"
+ label="&securityButton.label;"
+ tooltiptext="&securityButton.tooltip;"
+ oncommand="doSecurityButton();">
+ <menupopup onpopupshowing="setSecuritySettings(2);">
+ <menuitem id="menu_securityEncryptRequire2"
+ type="checkbox"
+ label="&menu_securityEncryptRequire.label;"
+ accesskey="&menu_securityEncryptRequire.accesskey;"
+ oncommand="setNextCommand('encryptMessage');"/>
+ <menuitem id="menu_securitySign2"
+ type="checkbox"
+ label="&menu_securitySign.label;"
+ accesskey="&menu_securitySign.accesskey;"
+ oncommand="setNextCommand('signMessage');"/>
+ <menuseparator id="smimeToolbarButtonSeparator"/>
+ <menuitem id="menu_securityStatus2"
+ label="&menu_securityStatus.label;"
+ accesskey="&menu_securityStatus.accesskey;"
+ oncommand="setNextCommand('show');"/>
+ </menupopup>
+ </toolbarbutton>
+ </toolbarpalette>
+
+ <statusbar id="status-bar">
+ <statusbarpanel insertbefore="offline-status" class="statusbarpanel-iconic" collapsed="true"
+ id="signing-status" oncommand="showMessageComposeSecurityStatus();"/>
+ <statusbarpanel insertbefore="offline-status" class="statusbarpanel-iconic" collapsed="true"
+ id="encryption-status" oncommand="showMessageComposeSecurityStatus();"/>
+ </statusbar>
+
+ <commandset id="composeCommands">
+ <command id="cmd_viewSecurityStatus" oncommand="showMessageComposeSecurityStatus();"/>
+ </commandset>
+
+ <menupopup id="menu_View_Popup">
+ <menuseparator id="viewMenuBeforeSecurityStatusSeparator"/>
+ <menuitem id="menu_viewSecurityStatus"
+ label="&menu_viewSecurityStatus.label;"
+ accesskey="&menu_viewSecurityStatus.accesskey;"
+ command="cmd_viewSecurityStatus"/>
+ </menupopup>
+
+</overlay>
diff --git a/mailnews/extensions/smime/content/msgCompSecurityInfo.js b/mailnews/extensions/smime/content/msgCompSecurityInfo.js
new file mode 100644
index 000000000..5a2a7432f
--- /dev/null
+++ b/mailnews/extensions/smime/content/msgCompSecurityInfo.js
@@ -0,0 +1,244 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+var gListBox;
+var gViewButton;
+var gBundle;
+
+var gEmailAddresses;
+var gCertStatusSummaries;
+var gCertIssuedInfos;
+var gCertExpiresInfos;
+var gCerts;
+var gCount;
+
+var gSMimeContractID = "@mozilla.org/messenger-smime/smimejshelper;1";
+var gISMimeJSHelper = Components.interfaces.nsISMimeJSHelper;
+var gIX509Cert = Components.interfaces.nsIX509Cert;
+var nsICertificateDialogs = Components.interfaces.nsICertificateDialogs;
+var nsCertificateDialogs = "@mozilla.org/nsCertificateDialogs;1"
+
+function getStatusExplanation(value)
+{
+ switch (value)
+ {
+ case gIX509Cert.VERIFIED_OK:
+ return gBundle.getString("StatusValid");
+
+ case gIX509Cert.NOT_VERIFIED_UNKNOWN:
+ case gIX509Cert.INVALID_CA:
+ case gIX509Cert.USAGE_NOT_ALLOWED:
+ return gBundle.getString("StatusInvalid");
+
+ case gIX509Cert.CERT_REVOKED:
+ return gBundle.getString("StatusRevoked");
+
+ case gIX509Cert.CERT_EXPIRED:
+ return gBundle.getString("StatusExpired");
+
+ case gIX509Cert.CERT_NOT_TRUSTED:
+ case gIX509Cert.ISSUER_NOT_TRUSTED:
+ case gIX509Cert.ISSUER_UNKNOWN:
+ return gBundle.getString("StatusUntrusted");
+ }
+
+ return "";
+}
+
+function onLoad()
+{
+ var params = window.arguments[0];
+ if (!params)
+ return;
+
+ var helper = Components.classes[gSMimeContractID].createInstance(gISMimeJSHelper);
+
+ if (!helper)
+ return;
+
+ gListBox = document.getElementById("infolist");
+ gViewButton = document.getElementById("viewCertButton");
+ gBundle = document.getElementById("bundle_smime_comp_info");
+
+ gEmailAddresses = new Object();
+ gCertStatusSummaries = new Object();
+ gCertIssuedInfos = new Object();
+ gCertExpiresInfos = new Object();
+ gCerts = new Object();
+ gCount = new Object();
+ var canEncrypt = new Object();
+
+ var allow_ldap_cert_fetching = false;
+
+ try {
+ if (params.compFields.securityInfo.requireEncryptMessage) {
+ allow_ldap_cert_fetching = true;
+ }
+ }
+ catch (e)
+ {
+ }
+
+ while (true)
+ {
+ try
+ {
+ helper.getRecipientCertsInfo(
+ params.compFields,
+ gCount,
+ gEmailAddresses,
+ gCertStatusSummaries,
+ gCertIssuedInfos,
+ gCertExpiresInfos,
+ gCerts,
+ canEncrypt);
+ }
+ catch (e)
+ {
+ dump(e);
+ return;
+ }
+
+ if (!allow_ldap_cert_fetching)
+ break;
+
+ allow_ldap_cert_fetching = false;
+
+ var missing = new Array();
+
+ for (var j = gCount.value - 1; j >= 0; --j)
+ {
+ if (!gCerts.value[j])
+ {
+ missing[missing.length] = gEmailAddresses.value[j];
+ }
+ }
+
+ if (missing.length > 0)
+ {
+ var autocompleteLdap = Services.prefs
+ .getBoolPref("ldap_2.autoComplete.useDirectory");
+
+ if (autocompleteLdap)
+ {
+ var autocompleteDirectory = null;
+ if (params.currentIdentity.overrideGlobalPref) {
+ autocompleteDirectory = params.currentIdentity.directoryServer;
+ } else {
+ autocompleteDirectory = Services.prefs
+ .getCharPref("ldap_2.autoComplete.directoryServer");
+ }
+
+ if (autocompleteDirectory)
+ {
+ window.openDialog('chrome://messenger-smime/content/certFetchingStatus.xul',
+ '',
+ 'chrome,resizable=1,modal=1,dialog=1',
+ autocompleteDirectory,
+ missing
+ );
+ }
+ }
+ }
+ }
+
+ if (gBundle)
+ {
+ var yes_string = gBundle.getString("StatusYes");
+ var no_string = gBundle.getString("StatusNo");
+ var not_possible_string = gBundle.getString("StatusNotPossible");
+
+ var signed_element = document.getElementById("signed");
+ var encrypted_element = document.getElementById("encrypted");
+
+ if (params.smFields.requireEncryptMessage)
+ {
+ if (params.isEncryptionCertAvailable && canEncrypt.value)
+ {
+ encrypted_element.value = yes_string;
+ }
+ else
+ {
+ encrypted_element.value = not_possible_string;
+ }
+ }
+ else
+ {
+ encrypted_element.value = no_string;
+ }
+
+ if (params.smFields.signMessage)
+ {
+ if (params.isSigningCertAvailable)
+ {
+ signed_element.value = yes_string;
+ }
+ else
+ {
+ signed_element.value = not_possible_string;
+ }
+ }
+ else
+ {
+ signed_element.value = no_string;
+ }
+ }
+
+ var imax = gCount.value;
+
+ for (var i = 0; i < imax; ++i)
+ {
+ var listitem = document.createElement("listitem");
+
+ listitem.appendChild(createCell(gEmailAddresses.value[i]));
+
+ if (!gCerts.value[i])
+ {
+ listitem.appendChild(createCell(gBundle.getString("StatusNotFound")));
+ }
+ else
+ {
+ listitem.appendChild(createCell(getStatusExplanation(gCertStatusSummaries.value[i])));
+ listitem.appendChild(createCell(gCertIssuedInfos.value[i]));
+ listitem.appendChild(createCell(gCertExpiresInfos.value[i]));
+ }
+
+ gListBox.appendChild(listitem);
+ }
+}
+
+function onSelectionChange(event)
+{
+ gViewButton.disabled = !(gListBox.selectedItems.length == 1 &&
+ certForRow(gListBox.selectedIndex));
+}
+
+function viewCertHelper(parent, cert) {
+ var cd = Components.classes[nsCertificateDialogs].getService(nsICertificateDialogs);
+ cd.viewCert(parent, cert);
+}
+
+function certForRow(aRowIndex) {
+ return gCerts.value[aRowIndex];
+}
+
+function viewSelectedCert()
+{
+ if (!gViewButton.disabled)
+ viewCertHelper(window, certForRow(gListBox.selectedIndex));
+}
+
+function doHelpButton()
+{
+ openHelp('compose_security', 'chrome://communicator/locale/help/suitehelp.rdf');
+}
+
+function createCell(label)
+{
+ var cell = document.createElement("listcell");
+ cell.setAttribute("label", label)
+ return cell;
+}
diff --git a/mailnews/extensions/smime/content/msgCompSecurityInfo.xul b/mailnews/extensions/smime/content/msgCompSecurityInfo.xul
new file mode 100644
index 000000000..c8769d621
--- /dev/null
+++ b/mailnews/extensions/smime/content/msgCompSecurityInfo.xul
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://messenger/skin/smime/msgCompSecurityInfo.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://messenger-smime/locale/msgCompSecurityInfo.dtd">
+
+<dialog id="msgCompSecurityInfo" title="&title.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ style="width: 50em;"
+ persist="width height"
+ buttons="accept"
+ onload="onLoad();">
+
+ <script type="application/javascript" src="chrome://messenger-smime/content/msgCompSecurityInfo.js"/>
+
+ <stringbundle id="bundle_smime_comp_info" src="chrome://messenger-smime/locale/msgCompSecurityInfo.properties"/>
+
+ <description>&subject.plaintextWarning;</description>
+ <separator class="thin"/>
+ <description>&status.heading;</description>
+ <grid>
+ <columns>
+ <column/>
+ <column/>
+ </columns>
+ <rows>
+ <row>
+ <label value="&status.signed;"/>
+ <label id="signed"/>
+ </row>
+ <row>
+ <label value="&status.encrypted;"/>
+ <label id="encrypted"/>
+ </row>
+ </rows>
+ </grid>
+
+ <separator class="thin"/>
+ <label value="&status.certificates;" control="infolist"/>
+
+ <listbox id="infolist" flex="1"
+ onselect="onSelectionChange(event);">
+ <listcols>
+ <listcol flex="3" width="0"/>
+ <splitter class="tree-splitter"/>
+ <listcol flex="1" width="0"/>
+ <splitter class="tree-splitter"/>
+ <listcol flex="2" width="0"/>
+ <splitter class="tree-splitter"/>
+ <listcol flex="2" width="0"/>
+ </listcols>
+ <listhead>
+ <listheader label="&tree.recipient;"/>
+ <listheader label="&tree.status;"/>
+ <listheader label="&tree.issuedDate;"/>
+ <listheader label="&tree.expiresDate;"/>
+ </listhead>
+ </listbox>
+ <hbox pack="start">
+ <button id="viewCertButton" disabled="true"
+ label="&view.label;" accesskey="&view.accesskey;"
+ oncommand="viewSelectedCert();"/>
+ </hbox>
+</dialog>
diff --git a/mailnews/extensions/smime/content/msgHdrViewSMIMEOverlay.js b/mailnews/extensions/smime/content/msgHdrViewSMIMEOverlay.js
new file mode 100644
index 000000000..2d9469d6c
--- /dev/null
+++ b/mailnews/extensions/smime/content/msgHdrViewSMIMEOverlay.js
@@ -0,0 +1,264 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var gSignedUINode = null;
+var gEncryptedUINode = null;
+var gSMIMEContainer = null;
+var gStatusBar = null;
+var gSignedStatusPanel = null;
+var gEncryptedStatusPanel = null;
+
+var gEncryptedURIService = null;
+var gMyLastEncryptedURI = null;
+
+var gSMIMEBundle = null;
+// var gBrandBundle; -- defined in mailWindow.js
+
+// manipulates some globals from msgReadSMIMEOverlay.js
+
+var nsICMSMessageErrors = Components.interfaces.nsICMSMessageErrors;
+
+/// Get the necko URL for the message URI.
+function neckoURLForMessageURI(aMessageURI)
+{
+ let msgSvc = Components.classes["@mozilla.org/messenger;1"]
+ .createInstance(Components.interfaces.nsIMessenger)
+ .messageServiceFromURI(aMessageURI);
+ let neckoURI = {};
+ msgSvc.GetUrlForUri(aMessageURI, neckoURI, null);
+ return neckoURI.value.spec;
+}
+
+var smimeHeaderSink =
+{
+ maxWantedNesting: function()
+ {
+ return 1;
+ },
+
+ signedStatus: function(aNestingLevel, aSignatureStatus, aSignerCert)
+ {
+ if (aNestingLevel > 1) {
+ // we are not interested
+ return;
+ }
+
+ gSignatureStatus = aSignatureStatus;
+ gSignerCert = aSignerCert;
+
+ gSMIMEContainer.collapsed = false;
+ gSignedUINode.collapsed = false;
+ gSignedStatusPanel.collapsed = false;
+
+ switch (aSignatureStatus) {
+ case nsICMSMessageErrors.SUCCESS:
+ gSignedUINode.setAttribute("signed", "ok");
+ gStatusBar.setAttribute("signed", "ok");
+ break;
+
+ case nsICMSMessageErrors.VERIFY_NOT_YET_ATTEMPTED:
+ gSignedUINode.setAttribute("signed", "unknown");
+ gStatusBar.setAttribute("signed", "unknown");
+ break;
+
+ case nsICMSMessageErrors.VERIFY_CERT_WITHOUT_ADDRESS:
+ case nsICMSMessageErrors.VERIFY_HEADER_MISMATCH:
+ gSignedUINode.setAttribute("signed", "mismatch");
+ gStatusBar.setAttribute("signed", "mismatch");
+ break;
+
+ default:
+ gSignedUINode.setAttribute("signed", "notok");
+ gStatusBar.setAttribute("signed", "notok");
+ break;
+ }
+ },
+
+ encryptionStatus: function(aNestingLevel, aEncryptionStatus, aRecipientCert)
+ {
+ if (aNestingLevel > 1) {
+ // we are not interested
+ return;
+ }
+
+ gEncryptionStatus = aEncryptionStatus;
+ gEncryptionCert = aRecipientCert;
+
+ gSMIMEContainer.collapsed = false;
+ gEncryptedUINode.collapsed = false;
+ gEncryptedStatusPanel.collapsed = false;
+
+ if (nsICMSMessageErrors.SUCCESS == aEncryptionStatus)
+ {
+ gEncryptedUINode.setAttribute("encrypted", "ok");
+ gStatusBar.setAttribute("encrypted", "ok");
+ }
+ else
+ {
+ gEncryptedUINode.setAttribute("encrypted", "notok");
+ gStatusBar.setAttribute("encrypted", "notok");
+ }
+
+ if (gEncryptedURIService)
+ {
+ // Remember the message URI and the corresponding necko URI.
+ gMyLastEncryptedURI = GetLoadedMessage();
+ gEncryptedURIService.rememberEncrypted(gMyLastEncryptedURI);
+ gEncryptedURIService.rememberEncrypted(
+ neckoURLForMessageURI(gMyLastEncryptedURI));
+ }
+
+ switch (aEncryptionStatus)
+ {
+ case nsICMSMessageErrors.SUCCESS:
+ case nsICMSMessageErrors.ENCRYPT_INCOMPLETE:
+ break;
+ default:
+ var brand = gBrandBundle.getString("brandShortName");
+ var title = gSMIMEBundle.getString("CantDecryptTitle").replace(/%brand%/g, brand);
+ var body = gSMIMEBundle.getString("CantDecryptBody").replace(/%brand%/g, brand);
+
+ // insert our message
+ msgWindow.displayHTMLInMessagePane(title,
+ "<html>\n" +
+ "<body bgcolor=\"#fafaee\">\n" +
+ "<center><br><br><br>\n" +
+ "<table>\n" +
+ "<tr><td>\n" +
+ "<center><strong><font size=\"+3\">\n" +
+ title+"</font></center><br>\n" +
+ body+"\n" +
+ "</td></tr></table></center></body></html>", false);
+ }
+ },
+
+ QueryInterface : function(iid)
+ {
+ if (iid.equals(Components.interfaces.nsIMsgSMIMEHeaderSink) || iid.equals(Components.interfaces.nsISupports))
+ return this;
+ throw Components.results.NS_NOINTERFACE;
+ }
+};
+
+function forgetEncryptedURI()
+{
+ if (gMyLastEncryptedURI && gEncryptedURIService)
+ {
+ gEncryptedURIService.forgetEncrypted(gMyLastEncryptedURI);
+ gEncryptedURIService.forgetEncrypted(
+ neckoURLForMessageURI(gMyLastEncryptedURI));
+ gMyLastEncryptedURI = null;
+ }
+}
+
+function onSMIMEStartHeaders()
+{
+ gEncryptionStatus = -1;
+ gSignatureStatus = -1;
+
+ gSignerCert = null;
+ gEncryptionCert = null;
+
+ gSMIMEContainer.collapsed = true;
+
+ gSignedUINode.collapsed = true;
+ gSignedUINode.removeAttribute("signed");
+ gSignedStatusPanel.collapsed = true;
+ gStatusBar.removeAttribute("signed");
+
+ gEncryptedUINode.collapsed = true;
+ gEncryptedUINode.removeAttribute("encrypted");
+ gEncryptedStatusPanel.collapsed = true;
+ gStatusBar.removeAttribute("encrypted");
+
+ forgetEncryptedURI();
+}
+
+function onSMIMEEndHeaders()
+{}
+
+function onSmartCardChange()
+{
+ // only reload encrypted windows
+ if (gMyLastEncryptedURI && gEncryptionStatus != -1)
+ ReloadMessage();
+}
+
+function msgHdrViewSMIMEOnLoad(event)
+{
+ window.crypto.enableSmartCardEvents = true;
+ document.addEventListener("smartcard-insert", onSmartCardChange, false);
+ document.addEventListener("smartcard-remove", onSmartCardChange, false);
+ if (!gSMIMEBundle)
+ gSMIMEBundle = document.getElementById("bundle_read_smime");
+
+ // we want to register our security header sink as an opaque nsISupports
+ // on the msgHdrSink used by mail.....
+ msgWindow.msgHeaderSink.securityInfo = smimeHeaderSink;
+
+ gSignedUINode = document.getElementById('signedHdrIcon');
+ gEncryptedUINode = document.getElementById('encryptedHdrIcon');
+ gSMIMEContainer = document.getElementById('smimeBox');
+ gStatusBar = document.getElementById('status-bar');
+ gSignedStatusPanel = document.getElementById('signed-status');
+ gEncryptedStatusPanel = document.getElementById('encrypted-status');
+
+ // add ourself to the list of message display listeners so we get notified when we are about to display a
+ // message.
+ var listener = {};
+ listener.onStartHeaders = onSMIMEStartHeaders;
+ listener.onEndHeaders = onSMIMEEndHeaders;
+ gMessageListeners.push(listener);
+
+ gEncryptedURIService =
+ Components.classes["@mozilla.org/messenger-smime/smime-encrypted-uris-service;1"]
+ .getService(Components.interfaces.nsIEncryptedSMIMEURIsService);
+}
+
+function msgHdrViewSMIMEOnUnload(event)
+{
+ window.crypto.enableSmartCardEvents = false;
+ document.removeEventListener("smartcard-insert", onSmartCardChange, false);
+ document.removeEventListener("smartcard-remove", onSmartCardChange, false);
+ forgetEncryptedURI();
+ removeEventListener("messagepane-loaded", msgHdrViewSMIMEOnLoad, true);
+ removeEventListener("messagepane-unloaded", msgHdrViewSMIMEOnUnload, true);
+ removeEventListener("messagepane-hide", msgHdrViewSMIMEOnMessagePaneHide, true);
+ removeEventListener("messagepane-unhide", msgHdrViewSMIMEOnMessagePaneUnhide, true);
+}
+
+function msgHdrViewSMIMEOnMessagePaneHide()
+{
+ gSMIMEContainer.collapsed = true;
+ gSignedUINode.collapsed = true;
+ gSignedStatusPanel.collapsed = true;
+ gEncryptedUINode.collapsed = true;
+ gEncryptedStatusPanel.collapsed = true;
+}
+
+function msgHdrViewSMIMEOnMessagePaneUnhide()
+{
+ if (gEncryptionStatus != -1 || gSignatureStatus != -1)
+ {
+ gSMIMEContainer.collapsed = false;
+
+ if (gSignatureStatus != -1)
+ {
+ gSignedUINode.collapsed = false;
+ gSignedStatusPanel.collapsed = false;
+ }
+
+ if (gEncryptionStatus != -1)
+ {
+ gEncryptedUINode.collapsed = false;
+ gEncryptedStatusPanel.collapsed = false;
+ }
+ }
+}
+
+addEventListener('messagepane-loaded', msgHdrViewSMIMEOnLoad, true);
+addEventListener('messagepane-unloaded', msgHdrViewSMIMEOnUnload, true);
+addEventListener('messagepane-hide', msgHdrViewSMIMEOnMessagePaneHide, true);
+addEventListener('messagepane-unhide', msgHdrViewSMIMEOnMessagePaneUnhide, true);
diff --git a/mailnews/extensions/smime/content/msgHdrViewSMIMEOverlay.xul b/mailnews/extensions/smime/content/msgHdrViewSMIMEOverlay.xul
new file mode 100644
index 000000000..957d2a15b
--- /dev/null
+++ b/mailnews/extensions/smime/content/msgHdrViewSMIMEOverlay.xul
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://messenger/skin/smime/msgHdrViewSMIMEOverlay.css" type="text/css"?>
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://messenger-smime/content/msgHdrViewSMIMEOverlay.js"/>
+<!-- These stringbundles are already defined in msgReadSMIMEOverlay.xul!
+ <stringbundleset id="stringbundleset">
+ <stringbundle id="bundle_read_smime" src="chrome://messenger-smime/locale/msgReadSMIMEOverlay.properties"/>
+ <stringbundle id="bundle_brand" src="chrome://branding/locale/brand.properties"/>
+ </stringbundleset>
+-->
+
+ <hbox id="expandedHeaderView">
+ <vbox id="smimeBox" insertafter="expandedHeaders" collapsed="true">
+ <spacer flex="1"/>
+ <image id="signedHdrIcon"
+ onclick="showMessageReadSecurityInfo();" collapsed="true"/>
+ <image id="encryptedHdrIcon"
+ onclick="showMessageReadSecurityInfo();" collapsed="true"/>
+ <spacer flex="1"/>
+ </vbox>
+ </hbox>
+</overlay>
+
diff --git a/mailnews/extensions/smime/content/msgReadSMIMEOverlay.js b/mailnews/extensions/smime/content/msgReadSMIMEOverlay.js
new file mode 100644
index 000000000..ab362d418
--- /dev/null
+++ b/mailnews/extensions/smime/content/msgReadSMIMEOverlay.js
@@ -0,0 +1,102 @@
+/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+var gEncryptionStatus = -1;
+var gSignatureStatus = -1;
+var gSignerCert = null;
+var gEncryptionCert = null;
+
+addEventListener("load", smimeReadOnLoad, {capture: false, once: true});
+
+function smimeReadOnLoad()
+{
+ top.controllers.appendController(SecurityController);
+
+ addEventListener("unload", smimeReadOnUnload, {capture: false, once: true});
+}
+
+function smimeReadOnUnload()
+{
+ top.controllers.removeController(SecurityController);
+}
+
+function showImapSignatureUnknown()
+{
+ let readSmimeBundle = document.getElementById("bundle_read_smime");
+ let brandBundle = document.getElementById("bundle_brand");
+ if (!readSmimeBundle || !brandBundle)
+ return;
+
+ if (Services.prompt.confirm(window, brandBundle.getString("brandShortName"),
+ readSmimeBundle.getString("ImapOnDemand")))
+ {
+ gDBView.reloadMessageWithAllParts();
+ }
+}
+
+function showMessageReadSecurityInfo()
+{
+ let gSignedUINode = document.getElementById("signedHdrIcon");
+ if (gSignedUINode && gSignedUINode.getAttribute("signed") == "unknown")
+ {
+ showImapSignatureUnknown();
+ return;
+ }
+
+ let params = Components.classes["@mozilla.org/embedcomp/dialogparam;1"]
+ .createInstance(Components.interfaces.nsIDialogParamBlock);
+ params.objects = Components.classes["@mozilla.org/array;1"]
+ .createInstance(Components.interfaces.nsIMutableArray);
+ // Append even if null... the receiver must handle that.
+ params.objects.appendElement(gSignerCert, false);
+ params.objects.appendElement(gEncryptionCert, false);
+
+ // int array starts with index 0, but that is used for window exit status
+ params.SetInt(1, gSignatureStatus);
+ params.SetInt(2, gEncryptionStatus);
+
+ window.openDialog("chrome://messenger-smime/content/msgReadSecurityInfo.xul",
+ "", "chrome,resizable,modal,dialog,centerscreen", params);
+}
+
+var SecurityController =
+{
+ supportsCommand: function(command)
+ {
+ switch (command)
+ {
+ case "cmd_viewSecurityStatus":
+ return true;
+
+ default:
+ return false;
+ }
+ },
+
+ isCommandEnabled: function(command)
+ {
+ switch (command)
+ {
+ case "cmd_viewSecurityStatus":
+ if (document.documentElement.getAttribute('windowtype') == "mail:messageWindow")
+ return GetNumSelectedMessages() > 0;
+
+ if (GetNumSelectedMessages() > 0 && gDBView)
+ {
+ let enabled = {value: false};
+ let checkStatus = {};
+ gDBView.getCommandStatus(nsMsgViewCommandType.cmdRequiringMsgBody,
+ enabled, checkStatus);
+ return enabled.value;
+ }
+ // else: fall through.
+
+ default:
+ return false;
+ }
+ }
+};
diff --git a/mailnews/extensions/smime/content/msgReadSMIMEOverlay.xul b/mailnews/extensions/smime/content/msgReadSMIMEOverlay.xul
new file mode 100644
index 000000000..a55828c0f
--- /dev/null
+++ b/mailnews/extensions/smime/content/msgReadSMIMEOverlay.xul
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://messenger/skin/smime/msgReadSMIMEOverlay.css" type="text/css"?>
+
+<!DOCTYPE overlay SYSTEM "chrome://messenger-smime/locale/msgReadSMIMEOverlay.dtd">
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script type="application/javascript" src="chrome://messenger-smime/content/msgReadSMIMEOverlay.js"/>
+
+ <commandset id="mailViewMenuItems">
+ <command id="cmd_viewSecurityStatus" oncommand="showMessageReadSecurityInfo();" disabled="true"/>
+ </commandset>
+
+ <menupopup id="menu_View_Popup">
+ <menuitem insertafter="pageSourceMenuItem" label="&menu_securityStatus.label;"
+ accesskey="&menu_securityStatus.accesskey;" command="cmd_viewSecurityStatus"/>
+ </menupopup>
+
+ <statusbar id="status-bar">
+ <statusbarpanel insertbefore="offline-status" class="statusbarpanel-iconic"
+ id="signed-status" collapsed="true" oncommand="showMessageReadSecurityInfo();"/>
+ <statusbarpanel insertbefore="offline-status" class="statusbarpanel-iconic"
+ id="encrypted-status" collapsed="true" oncommand="showMessageReadSecurityInfo();"/>
+ <stringbundle id="bundle_read_smime" src="chrome://messenger-smime/locale/msgReadSMIMEOverlay.properties"/>
+<!-- This stringbundle is already defined on top window level!
+ <stringbundle id="bundle_brand" src="chrome://branding/locale/brand.properties"/>
+-->
+ </statusbar>
+
+</overlay>
diff --git a/mailnews/extensions/smime/content/msgReadSecurityInfo.js b/mailnews/extensions/smime/content/msgReadSecurityInfo.js
new file mode 100644
index 000000000..310cfc18a
--- /dev/null
+++ b/mailnews/extensions/smime/content/msgReadSecurityInfo.js
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var nsIDialogParamBlock = Components.interfaces.nsIDialogParamBlock;
+var nsIX509Cert = Components.interfaces.nsIX509Cert;
+var nsICMSMessageErrors = Components.interfaces.nsICMSMessageErrors;
+var nsICertificateDialogs = Components.interfaces.nsICertificateDialogs;
+var nsCertificateDialogs = "@mozilla.org/nsCertificateDialogs;1"
+
+var gSignerCert = null;
+var gEncryptionCert = null;
+
+var gSignatureStatus = -1;
+var gEncryptionStatus = -1;
+
+function setText(id, value) {
+ var element = document.getElementById(id);
+ if (!element)
+ return;
+ if (element.hasChildNodes())
+ element.firstChild.remove();
+ var textNode = document.createTextNode(value);
+ element.appendChild(textNode);
+}
+
+function onLoad()
+{
+ var paramBlock = window.arguments[0].QueryInterface(nsIDialogParamBlock);
+ paramBlock.objects.QueryInterface(Components.interfaces.nsIMutableArray);
+ try {
+ gSignerCert = paramBlock.objects.queryElementAt(0, nsIX509Cert);
+ } catch(e) { } // maybe null
+ try {
+ gEncryptionCert = paramBlock.objects.queryElementAt(1, nsIX509Cert);
+ } catch(e) { } // maybe null
+
+ gSignatureStatus = paramBlock.GetInt(1);
+ gEncryptionStatus = paramBlock.GetInt(2);
+
+ var bundle = document.getElementById("bundle_smime_read_info");
+
+ if (bundle) {
+ var sigInfoLabel = null;
+ var sigInfoHeader = null;
+ var sigInfo = null;
+ var sigInfo_clueless = false;
+
+ switch (gSignatureStatus) {
+ case -1:
+ case nsICMSMessageErrors.VERIFY_NOT_SIGNED:
+ sigInfoLabel = "SINoneLabel";
+ sigInfo = "SINone";
+ break;
+
+ case nsICMSMessageErrors.SUCCESS:
+ sigInfoLabel = "SIValidLabel";
+ sigInfo = "SIValid";
+ break;
+
+
+ case nsICMSMessageErrors.VERIFY_BAD_SIGNATURE:
+ case nsICMSMessageErrors.VERIFY_DIGEST_MISMATCH:
+ sigInfoLabel = "SIInvalidLabel";
+ sigInfoHeader = "SIInvalidHeader";
+ sigInfo = "SIContentAltered";
+ break;
+
+ case nsICMSMessageErrors.VERIFY_UNKNOWN_ALGO:
+ case nsICMSMessageErrors.VERIFY_UNSUPPORTED_ALGO:
+ sigInfoLabel = "SIInvalidLabel";
+ sigInfoHeader = "SIInvalidHeader";
+ sigInfo = "SIInvalidCipher";
+ break;
+
+ case nsICMSMessageErrors.VERIFY_HEADER_MISMATCH:
+ sigInfoLabel = "SIPartiallyValidLabel";
+ sigInfoHeader = "SIPartiallyValidHeader";
+ sigInfo = "SIHeaderMismatch";
+ break;
+
+ case nsICMSMessageErrors.VERIFY_CERT_WITHOUT_ADDRESS:
+ sigInfoLabel = "SIPartiallyValidLabel";
+ sigInfoHeader = "SIPartiallyValidHeader";
+ sigInfo = "SICertWithoutAddress";
+ break;
+
+ case nsICMSMessageErrors.VERIFY_UNTRUSTED:
+ sigInfoLabel = "SIInvalidLabel";
+ sigInfoHeader = "SIInvalidHeader";
+ sigInfo = "SIUntrustedCA";
+ // XXX Need to extend to communicate better errors
+ // might also be:
+ // SIExpired SIRevoked SINotYetValid SIUnknownCA SIExpiredCA SIRevokedCA SINotYetValidCA
+ break;
+
+ case nsICMSMessageErrors.VERIFY_NOT_YET_ATTEMPTED:
+ case nsICMSMessageErrors.GENERAL_ERROR:
+ case nsICMSMessageErrors.VERIFY_NO_CONTENT_INFO:
+ case nsICMSMessageErrors.VERIFY_BAD_DIGEST:
+ case nsICMSMessageErrors.VERIFY_NOCERT:
+ case nsICMSMessageErrors.VERIFY_ERROR_UNVERIFIED:
+ case nsICMSMessageErrors.VERIFY_ERROR_PROCESSING:
+ case nsICMSMessageErrors.VERIFY_MALFORMED_SIGNATURE:
+ sigInfoLabel = "SIInvalidLabel";
+ sigInfoHeader = "SIInvalidHeader";
+ sigInfo_clueless = true;
+ break;
+ default:
+ Components.utils.reportError("Unexpected gSignatureStatus: " +
+ gSignatureStatus);
+ }
+
+ document.getElementById("signatureLabel").value =
+ bundle.getString(sigInfoLabel);
+
+ var label;
+ if (sigInfoHeader) {
+ label = document.getElementById("signatureHeader");
+ label.collapsed = false;
+ label.value = bundle.getString(sigInfoHeader);
+ }
+
+ var str;
+ if (sigInfo) {
+ str = bundle.getString(sigInfo);
+ }
+ else if (sigInfo_clueless) {
+ str = bundle.getString("SIClueless") + " (" + gSignatureStatus + ")";
+ }
+ setText("signatureExplanation", str);
+
+ var encInfoLabel = null;
+ var encInfoHeader = null;
+ var encInfo = null;
+ var encInfo_clueless = false;
+
+ switch (gEncryptionStatus) {
+ case -1:
+ encInfoLabel = "EINoneLabel2";
+ encInfo = "EINone";
+ break;
+
+ case nsICMSMessageErrors.SUCCESS:
+ encInfoLabel = "EIValidLabel";
+ encInfo = "EIValid";
+ break;
+
+ case nsICMSMessageErrors.ENCRYPT_INCOMPLETE:
+ encInfoLabel = "EIInvalidLabel";
+ encInfo = "EIContentAltered";
+ break;
+
+ case nsICMSMessageErrors.GENERAL_ERROR:
+ encInfoLabel = "EIInvalidLabel";
+ encInfoHeader = "EIInvalidHeader";
+ encInfo_clueless = 1;
+ break;
+ default:
+ Components.utils.reportError("Unexpected gEncryptionStatus: " +
+ gEncryptionStatus);
+ }
+
+ document.getElementById("encryptionLabel").value =
+ bundle.getString(encInfoLabel);
+
+ if (encInfoHeader) {
+ label = document.getElementById("encryptionHeader");
+ label.collapsed = false;
+ label.value = bundle.getString(encInfoHeader);
+ }
+
+ if (encInfo) {
+ str = bundle.getString(encInfo);
+ }
+ else if (encInfo_clueless) {
+ str = bundle.getString("EIClueless");
+ }
+ setText("encryptionExplanation", str);
+ }
+
+ if (gSignerCert) {
+ document.getElementById("signatureCert").collapsed = false;
+ if (gSignerCert.subjectName) {
+ document.getElementById("signedBy").value = gSignerCert.commonName;
+ }
+ if (gSignerCert.emailAddress) {
+ document.getElementById("signerEmail").value = gSignerCert.emailAddress;
+ }
+ if (gSignerCert.issuerName) {
+ document.getElementById("sigCertIssuedBy").value = gSignerCert.issuerCommonName;
+ }
+ }
+
+ if (gEncryptionCert) {
+ document.getElementById("encryptionCert").collapsed = false;
+ if (gEncryptionCert.subjectName) {
+ document.getElementById("encryptedFor").value = gEncryptionCert.commonName;
+ }
+ if (gEncryptionCert.emailAddress) {
+ document.getElementById("recipientEmail").value = gEncryptionCert.emailAddress;
+ }
+ if (gEncryptionCert.issuerName) {
+ document.getElementById("encCertIssuedBy").value = gEncryptionCert.issuerCommonName;
+ }
+ }
+}
+
+function viewCertHelper(parent, cert) {
+ var cd = Components.classes[nsCertificateDialogs].getService(nsICertificateDialogs);
+ cd.viewCert(parent, cert);
+}
+
+function viewSignatureCert()
+{
+ if (gSignerCert) {
+ viewCertHelper(window, gSignerCert);
+ }
+}
+
+function viewEncryptionCert()
+{
+ if (gEncryptionCert) {
+ viewCertHelper(window, gEncryptionCert);
+ }
+}
+
+function doHelpButton()
+{
+ openHelp('received_security');
+}
diff --git a/mailnews/extensions/smime/content/msgReadSecurityInfo.xul b/mailnews/extensions/smime/content/msgReadSecurityInfo.xul
new file mode 100644
index 000000000..8e0a1f5f5
--- /dev/null
+++ b/mailnews/extensions/smime/content/msgReadSecurityInfo.xul
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://messenger/skin/smime/msgReadSecurityInfo.css" type="text/css"?>
+
+<!DOCTYPE dialog SYSTEM "chrome://messenger-smime/locale/msgReadSecurityInfo.dtd">
+
+<dialog id="msgReadSecurityInfo" title="&status.label;"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ style="width: 40em;"
+ buttons="accept"
+ onload="onLoad();">
+
+ <script type="application/javascript" src="chrome://messenger-smime/content/msgReadSecurityInfo.js"/>
+
+ <stringbundle id="bundle_smime_read_info" src="chrome://messenger-smime/locale/msgSecurityInfo.properties"/>
+
+ <vbox flex="1">
+ <label id="signatureLabel"/>
+ <label id="signatureHeader" collapsed="true"/>
+ <description id="signatureExplanation"/>
+ <vbox id="signatureCert" collapsed="true">
+ <hbox>
+ <label id="signedByLabel">&signer.name;</label>
+ <description id="signedBy"/>
+ </hbox>
+ <hbox>
+ <label id="signerEmailLabel">&email.address;</label>
+ <description id="signerEmail"/>
+ </hbox>
+ <hbox>
+ <label id="sigCertIssuedByLabel">&issuer.name;</label>
+ <description id="sigCertIssuedBy"/>
+ </hbox>
+ <hbox>
+ <button id="signatureCertView" label="&signatureCert.label;"
+ oncommand="viewSignatureCert()"/>
+ </hbox>
+ </vbox>
+
+ <separator/>
+
+ <label id="encryptionLabel"/>
+ <label id="encryptionHeader" collapsed="true"/>
+ <description id="encryptionExplanation"/>
+ <vbox id="encryptionCert" collapsed="true">
+ <hbox>
+ <label id="encryptedForLabel">&recipient.name;</label>
+ <description id="encryptedFor"/>
+ </hbox>
+ <hbox>
+ <label id="recipientEmailLabel">&email.address;</label>
+ <description id="recipientEmail"/>
+ </hbox>
+ <hbox>
+ <label id="encCertIssuedByLabel">&issuer.name;</label>
+ <description id="encCertIssuedBy"/>
+ </hbox>
+ <hbox>
+ <button id="encryptionCertView" label="&encryptionCert.label;"
+ oncommand="viewEncryptionCert()"/>
+ </hbox>
+ </vbox>
+ </vbox>
+</dialog>
diff --git a/mailnews/extensions/smime/content/smime.js b/mailnews/extensions/smime/content/smime.js
new file mode 100644
index 000000000..8259ead1a
--- /dev/null
+++ b/mailnews/extensions/smime/content/smime.js
@@ -0,0 +1,14 @@
+/* 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/. */
+
+/*
+ Add any default pref values we want for smime
+*/
+
+pref("mail.identity.default.encryption_cert_name","");
+pref("mail.identity.default.encryptionpolicy", 0);
+pref("mail.identity.default.signing_cert_name", "");
+pref("mail.identity.default.sign_mail", false);
+
+