async function reloadOpenPgpUI()

in mail/extensions/am-e2e/am-e2e.js [940:1394]


async function reloadOpenPgpUI() {
  const result = {};
  await EnigmailKeyRing.getAllSecretKeysByEmail(gIdentity.email, result, true);
  let keyCount = result.all.length;

  let externalKey = null;
  if (Services.prefs.getBoolPref("mail.openpgp.allow_external_gnupg")) {
    externalKey = gIdentity.getUnicharAttribute(
      "last_entered_external_gnupg_key_id"
    );
    if (externalKey) {
      keyCount++;
    }
  }

  // Show the radiogroup container only if the current identity has keys.
  // But still show it if a key (missing or unusable) is configured.
  document.getElementById("openPgpKeyList").hidden = keyCount == 0 && !gKeyId;

  // Update the OpenPGP intro description with the current key count.
  if (keyCount) {
    document.l10n.setAttributes(
      document.getElementById("openPgpDescription"),
      "openpgp-description-has-keys",
      {
        count: keyCount,
        identity: gIdentity.email,
      }
    );
  } else {
    document.l10n.setAttributes(
      document.getElementById("openPgpDescription"),
      "openpgp-description-no-key",
      {
        identity: gIdentity.email,
      }
    );
  }

  const radiogroup = document.getElementById("openPgpKeyListRadio");

  if (!gKeyId) {
    radiogroup.selectedIndex = 0; // None
  }

  // Remove all the previously generated radio options, except the first.
  while (radiogroup.lastChild.id != "openPgpOptionNone") {
    radiogroup.removeChild(radiogroup.lastChild);
  }

  // Currently configured key is not in available, maybe deleted by the user?
  if (gKeyId && !externalKey && !result.all.find(key => key.keyId == gKeyId)) {
    const container = document.createXULElement("vbox");
    container.id = `openPgpOption${gKeyId}`;
    container.classList.add("content-blocking-category");

    const box = document.createXULElement("hbox");
    const radio = document.createXULElement("radio");
    radio.setAttribute("flex", "1");
    radio.disabled = true;
    radio.id = `openPgp${gKeyId}`;
    radio.value = gKeyId;
    radio.label = `0x${gKeyId}`;
    box.appendChild(radio);

    const box2 = document.createXULElement("vbox");
    box2.classList.add("indent");
    const desc = document.createXULElement("description");
    box2.appendChild(desc);

    const key = EnigmailKeyRing.getKeyById(gKeyId);
    if (key && !key.secretAvailable) {
      document.l10n.setAttributes(desc, "openpgp-radio-key-not-usable");
    } else if (key && !(await PgpSqliteDb2.isAcceptedAsPersonalKey(key.fpr))) {
      document.l10n.setAttributes(desc, "openpgp-radio-key-not-accepted");
      const btnContainer = document.createXULElement("hbox");
      btnContainer.setAttribute("pack", "end");
      btnContainer.style.width = "100%";
      const info = document.createXULElement("button");
      info.classList.add("openpgp-image-btn", "openpgp-props-btn");
      document.l10n.setAttributes(info, "openpgp-key-man-key-props");
      info.addEventListener("command", event => {
        event.stopPropagation();
        enigmailKeyDetails(key.keyId);
      });
      btnContainer.appendChild(info);
      box2.appendChild(btnContainer);
    } else {
      document.l10n.setAttributes(desc, "openpgp-radio-key-not-found");
    }

    container.appendChild(box);
    container.appendChild(box2);
    radiogroup.appendChild(container);
  }

  // Sort keys by create date from newest to oldest.
  result.all.sort((a, b) => {
    return b.keyCreated - a.keyCreated;
  });

  // If the user has an external key saved, and the allow_external_gnupg
  // pref is true, we show it on top of the list.
  if (externalKey) {
    const container = document.createXULElement("vbox");
    container.id = `openPgpOption${externalKey}`;
    container.classList.add("content-blocking-category");

    const box = document.createXULElement("hbox");

    const radio = document.createXULElement("radio");
    radio.setAttribute("flex", "1");
    radio.id = `openPgp${externalKey}`;
    radio.value = externalKey;
    radio.label = `0x${externalKey}`;

    const remove = document.createXULElement("button");
    document.l10n.setAttributes(remove, "openpgp-key-remove-external");
    remove.addEventListener("command", removeExternalKey);
    remove.classList.add("button-small");

    box.appendChild(radio);
    box.appendChild(remove);

    const indent = document.createXULElement("vbox");
    indent.classList.add("indent");

    const dateContainer = document.createXULElement("hbox");
    dateContainer.classList.add("expiration-date-container");
    dateContainer.setAttribute("align", "center");

    const external = document.createXULElement("description");
    external.classList.add("external-pill");
    document.l10n.setAttributes(external, "key-external-label");

    dateContainer.appendChild(external);
    indent.appendChild(dateContainer);

    container.appendChild(box);
    container.appendChild(indent);

    radiogroup.appendChild(container);
  }

  // List all the available keys.
  for (const key of result.all) {
    const container = document.createXULElement("vbox");
    container.id = `openPgpOption${key.keyId}`;
    container.classList.add("content-blocking-category");

    const box = document.createXULElement("hbox");

    const radio = document.createXULElement("radio");
    radio.setAttribute("flex", "1");
    radio.id = `openPgp${key.keyId}`;
    radio.value = key.keyId;
    radio.label = `0x${key.keyId}`;

    const toggle = document.createXULElement("button");
    toggle.classList.add("arrowhead");
    toggle.setAttribute("aria-expanded", "false");
    document.l10n.setAttributes(toggle, "openpgp-key-expand-section");
    toggle.addEventListener("command", toggleExpansion);

    box.appendChild(radio);
    box.appendChild(toggle);

    const indent = document.createXULElement("vbox");
    indent.classList.add("indent");

    const dateContainer = document.createXULElement("hbox");
    dateContainer.classList.add("expiration-date-container");
    dateContainer.setAttribute("align", "center");

    const dateIcon = document.createElement("img");
    dateIcon.classList.add("expiration-date-icon");

    const dateButton = document.createXULElement("button");
    document.l10n.setAttributes(dateButton, "openpgp-key-man-change-expiry");
    dateButton.addEventListener("command", event => {
      event.stopPropagation();
      enigmailEditKeyDate(key);
    });
    dateButton.setAttribute("hidden", "true");
    dateButton.classList.add("button-small");

    const description = document.createXULElement("description");

    if (key.expiryTime) {
      if (Math.round(Date.now() / 1000) > key.expiryTime) {
        // Has expired.
        dateContainer.classList.add("key-expired");
        dateIcon.setAttribute(
          "src",
          "chrome://messenger/skin/icons/new/compact/warning.svg"
        );
        // Sets the title attribute.
        // The alt attribute is not set because the accessible name is already
        // set by the title.
        document.l10n.setAttributes(dateIcon, "openpgp-key-has-expired-icon");

        document.l10n.setAttributes(description, "openpgp-radio-key-expired", {
          date: key.expiry,
        });

        dateButton.removeAttribute("hidden");
        // This key is expired, so make it unselectable.
        radio.setAttribute("disabled", "true");
      } else {
        // If the key expires in less than 6 months.
        const sixMonths = new Date();
        sixMonths.setMonth(sixMonths.getMonth() + 6);
        if (Math.round(Date.parse(sixMonths) / 1000) > key.expiryTime) {
          dateContainer.classList.add("key-is-expiring");
          dateIcon.setAttribute(
            "src",
            "chrome://messenger/skin/icons/new/compact/info.svg"
          );
          // Sets the title attribute.
          // The alt attribute is not set because the accessible name is already
          // set by the title.
          document.l10n.setAttributes(
            dateIcon,
            "openpgp-key-expires-within-6-months-icon"
          );
          dateButton.removeAttribute("hidden");
        }

        document.l10n.setAttributes(description, "openpgp-radio-key-expires", {
          date: key.expiry,
        });
      }
    } else {
      document.l10n.setAttributes(description, "key-does-not-expire");
    }

    dateContainer.appendChild(dateIcon);
    dateContainer.appendChild(description);
    dateContainer.appendChild(dateButton);

    let publishContainer = null;

    // If this key is the currently selected key, suggest publishing.
    if (key.keyId == gKeyId) {
      publishContainer = document.createXULElement("hbox");
      publishContainer.setAttribute("align", "center");

      const publishButton = document.createElement("button");
      document.l10n.setAttributes(publishButton, "openpgp-key-publish");
      publishButton.addEventListener("click", () => {
        amE2eUploadKey(key);
      });
      publishButton.classList.add("button-small");

      const desc = document.createXULElement("description");
      document.l10n.setAttributes(desc, "openpgp-suggest-publishing-key");

      publishContainer.appendChild(desc);
      publishContainer.appendChild(publishButton);
    }

    const hiddenContainer = document.createXULElement("vbox");
    hiddenContainer.classList.add(
      "content-blocking-extra-information",
      "indent"
    );

    // Start key info section.
    const grid = document.createXULElement("hbox");
    grid.classList.add("extra-information-label");

    // Key fingerprint.
    const fingerprintImage = document.createElement("img");
    fingerprintImage.setAttribute(
      "src",
      "chrome://messenger/skin/icons/new/compact/fingerprint.svg"
    );
    fingerprintImage.setAttribute("alt", "");

    const fingerprintLabel = document.createXULElement("label");
    document.l10n.setAttributes(
      fingerprintLabel,
      "openpgp-key-details-fingerprint-label"
    );
    fingerprintLabel.classList.add("extra-information-label-type");

    const fgrInputContainer = document.createXULElement("hbox");
    fgrInputContainer.classList.add("input-container");
    fgrInputContainer.setAttribute("flex", "1");

    const fingerprintInput = document.createElement("input");
    fingerprintInput.setAttribute("type", "text");
    fingerprintInput.classList.add("plain");
    fingerprintInput.setAttribute("readonly", "readonly");
    fingerprintInput.value = EnigmailKey.formatFpr(key.fpr);

    fgrInputContainer.appendChild(fingerprintInput);

    grid.appendChild(fingerprintImage);
    grid.appendChild(fingerprintLabel);
    grid.appendChild(fgrInputContainer);

    // Key creation date.
    const createdImage = document.createElement("img");
    createdImage.setAttribute(
      "src",
      "chrome://messenger/skin/icons/new/compact/calendar.svg"
    );
    createdImage.setAttribute("alt", "");

    const createdLabel = document.createXULElement("label");
    document.l10n.setAttributes(
      createdLabel,
      "openpgp-key-details-created-header"
    );
    createdLabel.classList.add("extra-information-label-type");

    const createdValueContainer = document.createXULElement("hbox");
    createdValueContainer.classList.add("input-container");
    createdValueContainer.setAttribute("flex", "1");

    const createdValue = document.createElement("input");
    createdValue.setAttribute("type", "text");
    createdValue.classList.add("plain");
    createdValue.setAttribute("readonly", "readonly");
    createdValue.value = key.created;

    createdValueContainer.appendChild(createdValue);

    grid.appendChild(createdImage);
    grid.appendChild(createdLabel);
    grid.appendChild(createdValueContainer);
    // End key info section.

    hiddenContainer.appendChild(grid);

    // Action buttons.
    const btnContainer = document.createXULElement("hbox");
    btnContainer.setAttribute("pack", "end");

    const info = document.createXULElement("button");
    info.classList.add("openpgp-image-btn", "openpgp-props-btn");
    document.l10n.setAttributes(info, "openpgp-key-man-key-props");
    info.addEventListener("command", event => {
      event.stopPropagation();
      enigmailKeyDetails(key.keyId);
    });

    const more = document.createXULElement("button");
    more.setAttribute("type", "menu");
    more.classList.add("openpgp-more-btn", "last-element");
    document.l10n.setAttributes(more, "openpgp-key-man-key-more");

    const menupopup = document.createXULElement("menupopup");
    menupopup.classList.add("more-button-menupopup");

    const copyItem = document.createXULElement("menuitem");
    document.l10n.setAttributes(copyItem, "openpgp-key-copy-key");
    copyItem.addEventListener("command", event => {
      event.stopPropagation();
      openPgpCopyToClipboard(`0x${key.keyId}`);
    });

    const sendItem = document.createXULElement("menuitem");
    document.l10n.setAttributes(sendItem, "openpgp-key-send-key");
    sendItem.addEventListener("command", event => {
      event.stopPropagation();
      openPgpSendKeyEmail(`0x${key.keyId}`);
    });

    const exportItem = document.createXULElement("menuitem");
    document.l10n.setAttributes(exportItem, "openpgp-key-export-key");
    exportItem.addEventListener("command", event => {
      event.stopPropagation();
      openPgpExportPublicKey(`0x${key.keyId}`);
    });

    const backupItem = document.createXULElement("menuitem");
    document.l10n.setAttributes(backupItem, "openpgp-key-backup-key");
    backupItem.addEventListener("command", event => {
      event.stopPropagation();
      openPgpExportSecretKey(`0x${key.keyId}`, `${key.fpr}`);
    });

    const revokeItem = document.createXULElement("menuitem");
    document.l10n.setAttributes(revokeItem, "openpgp-key-man-revoke-key");
    revokeItem.addEventListener("command", event => {
      event.stopPropagation();
      openPgpRevokeKey(key);
    });

    const deleteItem = document.createXULElement("menuitem");
    document.l10n.setAttributes(deleteItem, "openpgp-delete-key");
    deleteItem.addEventListener("command", event => {
      event.stopPropagation();
      enigmailDeleteKey(key);
    });

    menupopup.appendChild(copyItem);
    menupopup.appendChild(sendItem);
    menupopup.appendChild(exportItem);
    menupopup.appendChild(document.createXULElement("menuseparator"));
    menupopup.appendChild(backupItem);
    menupopup.appendChild(document.createXULElement("menuseparator"));
    menupopup.appendChild(revokeItem);
    menupopup.appendChild(deleteItem);

    more.appendChild(menupopup);

    btnContainer.appendChild(info);
    btnContainer.appendChild(more);

    hiddenContainer.appendChild(btnContainer);

    indent.appendChild(dateContainer);
    if (publishContainer) {
      indent.appendChild(publishContainer);
    }
    indent.appendChild(hiddenContainer);

    container.appendChild(box);
    container.appendChild(indent);

    radiogroup.appendChild(container);
  }

  // Reflect the selected key in the UI.
  radiogroup.selectedItem = radiogroup.querySelector(
    `radio[value="${gKeyId}"]`
  );

  // Update all the encryption options based on the selected OpenPGP key.
  if (gKeyId) {
    enableEncryptionControls(true);
    enableSigningControls(true);
  } else {
    const stillHaveOtherEncryption =
      gEncryptionCertName && gEncryptionCertName.value;
    if (!stillHaveOtherEncryption) {
      enableEncryptionControls(false);
    }
    const stillHaveOtherSigning = gSignCertName && gSignCertName.value;
    if (!stillHaveOtherSigning) {
      enableSigningControls(false);
    }
  }

  updateTechPref();
  enableSelectButtons();
  updateUIForSelectedOpenPgpKey();

  gAttachKey.disabled = !gKeyId;
  gEncryptSubject.disabled = !gKeyId;
  gSendAutocryptHeaders.disabled = !gKeyId;
}