diff options
Diffstat (limited to '')
4 files changed, 909 insertions, 0 deletions
diff --git a/comm/mailnews/addrbook/prefs/content/pref-directory-add.js b/comm/mailnews/addrbook/prefs/content/pref-directory-add.js new file mode 100644 index 0000000000..23bee12a0e --- /dev/null +++ b/comm/mailnews/addrbook/prefs/content/pref-directory-add.js @@ -0,0 +1,454 @@ +/* -*- Mode: JavaScript; 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 { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); +var { isLegalHostNameOrIP, cleanUpHostName } = ChromeUtils.import( + "resource:///modules/hostnameUtils.jsm" +); + +var gCurrentDirectory = null; +var gReplicationBundle = null; +var gReplicationService = Cc[ + "@mozilla.org/addressbook/ldap-replication-service;1" +].getService(Ci.nsIAbLDAPReplicationService); +var gReplicationCancelled = false; +var gProgressText; +var gProgressMeter; +var gDownloadInProgress = false; + +var kDefaultLDAPPort = 389; +var kDefaultSecureLDAPPort = 636; + +window.addEventListener("DOMContentLoaded", Startup); +window.addEventListener("unload", onUnload); +document.addEventListener("dialogaccept", onAccept); +document.addEventListener("dialogcancel", onCancel); + +var ldapOfflineObserver = { + observe(subject, topic, state) { + // sanity checks + if (topic != "network:offline-status-changed") { + return; + } + setDownloadOfflineOnlineState(state == "offline"); + }, +}; + +function Startup() { + gReplicationBundle = document.getElementById("bundle_replication"); + + document.getElementById("download").label = + gReplicationBundle.getString("downloadButton"); + document.getElementById("download").accessKey = gReplicationBundle.getString( + "downloadButton.accesskey" + ); + + if ( + "arguments" in window && + window.arguments[0] && + window.arguments[0].selectedDirectory + ) { + gCurrentDirectory = window.arguments[0].selectedDirectory; + try { + fillSettings(); + } catch (ex) { + dump( + "pref-directory-add.js:Startup(): fillSettings() exception: " + + ex + + "\n" + ); + } + + let oldListName = gCurrentDirectory.dirName; + document.title = gReplicationBundle.getFormattedString( + "directoryTitleEdit", + [oldListName] + ); + + // Only set up the download button for online/offline status toggling + // if the pref isn't locked to disable the button. + if ( + !Services.prefs.prefIsLocked( + gCurrentDirectory.dirPrefId + ".disable_button_download" + ) + ) { + // Now connect to the offline/online observer + Services.obs.addObserver( + ldapOfflineObserver, + "network:offline-status-changed" + ); + + // Now set the initial offline/online state and update the state + setDownloadOfflineOnlineState(Services.io.offline); + } + } else { + document.title = gReplicationBundle.getString("directoryTitleNew"); + fillDefaultSettings(); + // Don't add observer here as it doesn't make any sense. + } +} + +function onUnload() { + if ( + "arguments" in window && + window.arguments[0] && + window.arguments[0].selectedDirectory && + !Services.prefs.prefIsLocked( + gCurrentDirectory.dirPrefId + ".disable_button_download" + ) + ) { + // Remove the observer that we put in on dialog startup + Services.obs.removeObserver( + ldapOfflineObserver, + "network:offline-status-changed" + ); + } +} + +var progressListener = { + onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) { + if (aStateFlags & Ci.nsIWebProgressListener.STATE_START) { + // start the spinning + gProgressMeter.removeAttribute("value"); + gProgressText.value = gReplicationBundle.getString( + aStatus ? "replicationStarted" : "changesStarted" + ); + gDownloadInProgress = true; + document.getElementById("download").label = gReplicationBundle.getString( + "cancelDownloadButton" + ); + document.getElementById("download").accessKey = + gReplicationBundle.getString("cancelDownloadButton.accesskey"); + } + + if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) { + EndDownload(aStatus); + } + }, + onProgressChange( + aWebProgress, + aRequest, + aCurSelfProgress, + aMaxSelfProgress, + aCurTotalProgress, + aMaxTotalProgress + ) { + gProgressText.value = gReplicationBundle.getFormattedString( + "currentCount", + [aCurSelfProgress] + ); + }, + onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {}, + onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {}, + onSecurityChange(aWebProgress, aRequest, state) {}, + onContentBlockingEvent(aWebProgress, aRequest, aEvent) {}, + QueryInterface: ChromeUtils.generateQI([ + "nsIWebProgressListener", + "nsISupportsWeakReference", + ]), +}; + +function DownloadNow() { + if (!gDownloadInProgress) { + gProgressText = document.getElementById("replicationProgressText"); + gProgressMeter = document.getElementById("replicationProgressMeter"); + + gProgressText.hidden = false; + gProgressMeter.hidden = false; + gReplicationCancelled = false; + + try { + if (gCurrentDirectory instanceof Ci.nsIAbLDAPDirectory) { + gReplicationService.startReplication( + gCurrentDirectory, + progressListener + ); + } else { + EndDownload(Cr.NS_ERROR_FAILURE); + } + } catch (ex) { + EndDownload(Cr.NS_ERROR_FAILURE); + } + } else { + gReplicationCancelled = true; + try { + gReplicationService.cancelReplication(gCurrentDirectory); + } catch (ex) { + // XXX todo + // perhaps replication hasn't started yet? This can happen if you hit cancel after attempting to replication when offline + dump("unexpected failure while cancelling. ex=" + ex + "\n"); + } + } +} + +function EndDownload(aStatus) { + document.getElementById("download").label = + gReplicationBundle.getString("downloadButton"); + document.getElementById("download").accessKey = gReplicationBundle.getString( + "downloadButton.accesskey" + ); + + // stop the spinning + gProgressMeter.value = 100; + gProgressMeter.hidden = true; + + gDownloadInProgress = false; + if (Components.isSuccessCode(aStatus)) { + gProgressText.value = gReplicationBundle.getString("replicationSucceeded"); + } else if (gReplicationCancelled) { + gProgressText.value = gReplicationBundle.getString("replicationCancelled"); + } else { + gProgressText.value = gReplicationBundle.getString("replicationFailed"); + } +} + +// fill the settings panel with the data from the preferences. +// +function fillSettings() { + document.getElementById("description").value = gCurrentDirectory.dirName; + + if (gCurrentDirectory instanceof Ci.nsIAbLDAPDirectory) { + var ldapUrl = gCurrentDirectory.lDAPURL; + + document.getElementById("results").value = gCurrentDirectory.maxHits; + document.getElementById("login").value = gCurrentDirectory.authDn; + document.getElementById("hostname").value = ldapUrl.host; + document.getElementById("basedn").value = ldapUrl.dn; + document.getElementById("search").value = ldapUrl.filter; + + var sub = document.getElementById("sub"); + switch (ldapUrl.scope) { + case Ci.nsILDAPURL.SCOPE_ONELEVEL: + sub.radioGroup.selectedItem = document.getElementById("one"); + break; + default: + sub.radioGroup.selectedItem = sub; + break; + } + + var sasl = document.getElementById("saslMechanism"); + switch (gCurrentDirectory.saslMechanism) { + case "GSSAPI": + sasl.selectedItem = document.getElementById("GSSAPI"); + break; + default: + sasl.selectedItem = document.getElementById("Simple"); + break; + } + + var secure = ldapUrl.options & ldapUrl.OPT_SECURE; + if (secure) { + document.getElementById("secure").setAttribute("checked", "true"); + } + + if (ldapUrl.port == -1) { + document.getElementById("port").value = secure + ? kDefaultSecureLDAPPort + : kDefaultLDAPPort; + } else { + document.getElementById("port").value = ldapUrl.port; + } + } + + // check if any of the preferences for this server are locked. + // If they are locked disable them + DisableUriFields(gCurrentDirectory.dirPrefId + ".uri"); + DisableElementIfPrefIsLocked( + gCurrentDirectory.dirPrefId + ".description", + "description" + ); + DisableElementIfPrefIsLocked( + gCurrentDirectory.dirPrefId + ".disable_button_download", + "download" + ); + DisableElementIfPrefIsLocked( + gCurrentDirectory.dirPrefId + ".maxHits", + "results" + ); + DisableElementIfPrefIsLocked( + gCurrentDirectory.dirPrefId + ".auth.dn", + "login" + ); +} + +function DisableElementIfPrefIsLocked(aPrefName, aElementId) { + if (Services.prefs.prefIsLocked(aPrefName)) { + document.getElementById(aElementId).setAttribute("disabled", true); + } +} + +// disables all the text fields corresponding to the .uri pref. +function DisableUriFields(aPrefName) { + if (Services.prefs.prefIsLocked(aPrefName)) { + let lockedElements = document.querySelectorAll('[disableiflocked="true"]'); + for (let i = 0; i < lockedElements.length; i++) { + lockedElements[i].setAttribute("disabled", "true"); + } + } +} + +function onSecure() { + document.getElementById("port").value = document.getElementById("secure") + .checked + ? kDefaultSecureLDAPPort + : kDefaultLDAPPort; +} + +function fillDefaultSettings() { + document.getElementById("port").value = kDefaultLDAPPort; + var sub = document.getElementById("sub"); + sub.radioGroup.selectedItem = sub; + + // Disable the download button and add some text indicating why. + document.getElementById("download").disabled = true; + document.getElementById("downloadWarningMsg").hidden = false; + document.getElementById("downloadWarningMsg").textContent = document + .getElementById("bundle_addressBook") + .getString("abReplicationSaveSettings"); +} + +function hasCharacters(number) { + var re = /[0-9]/g; + var num = number.match(re); + if (num && num.length == number.length) { + return false; + } + return true; +} + +function onAccept(event) { + try { + let description = document.getElementById("description").value.trim(); + let hostname = cleanUpHostName(document.getElementById("hostname").value); + let port = document.getElementById("port").value; + let secure = document.getElementById("secure"); + let results = document.getElementById("results").value; + let errorValue = null; + let errorArg = null; + let saslMechanism = ""; + + let findDupeName = function (newName) { + // Do not allow an already existing name. + for (let ab of MailServices.ab.directories) { + if ( + ab.dirName.toLowerCase() == newName.toLowerCase() && + (!gCurrentDirectory || ab.URI != gCurrentDirectory.URI) + ) { + return ab.dirName; + } + } + return null; + }; + + if (!description) { + errorValue = "invalidName"; + } else if ((errorArg = findDupeName(description))) { + errorValue = "duplicateNameText"; + } else if (!isLegalHostNameOrIP(hostname)) { + errorValue = "invalidHostname"; + } else if (port && hasCharacters(port)) { + // XXX write isValidDn and call it on the dn string here? + errorValue = "invalidPortNumber"; + } else if (results && hasCharacters(results)) { + errorValue = "invalidResults"; + } + + if (!errorValue) { + if (!port) { + port = secure.checked ? kDefaultSecureLDAPPort : kDefaultLDAPPort; + } + if (hostname.includes(":")) { + // Wrap IPv6 address in []. + hostname = `[${hostname}]`; + } + let ldapUrl = Services.io + .newURI(`${secure.checked ? "ldaps" : "ldap"}://${hostname}:${port}`) + .QueryInterface(Ci.nsILDAPURL); + + ldapUrl.dn = document.getElementById("basedn").value; + ldapUrl.scope = document.getElementById("one").selected + ? Ci.nsILDAPURL.SCOPE_ONELEVEL + : Ci.nsILDAPURL.SCOPE_SUBTREE; + + ldapUrl.filter = document.getElementById("search").value; + if (document.getElementById("GSSAPI").selected) { + saslMechanism = "GSSAPI"; + } + + // check if we are modifying an existing directory or adding a new directory + if (gCurrentDirectory) { + gCurrentDirectory.dirName = description; + gCurrentDirectory.lDAPURL = ldapUrl; + window.opener.gNewServerString = gCurrentDirectory.dirPrefId; + } else { + // adding a new directory + window.opener.gNewServerString = MailServices.ab.newAddressBook( + description, + ldapUrl.spec, + Ci.nsIAbManager.LDAP_DIRECTORY_TYPE + ); + } + + // XXX This is really annoying - both new/modify Address Book don't + // give us back the new directory we just created - so go find it from + // rdf so we can set a few final things up on it. + var targetURI = "moz-abldapdirectory://" + window.opener.gNewServerString; + var theDirectory = MailServices.ab + .getDirectory(targetURI) + .QueryInterface(Ci.nsIAbLDAPDirectory); + + theDirectory.maxHits = results; + theDirectory.authDn = document.getElementById("login").value; + theDirectory.saslMechanism = saslMechanism; + + window.opener.gNewServer = description; + // set window.opener.gUpdate to true so that LDAP Directory Servers + // dialog gets updated + window.opener.gUpdate = true; + window.arguments[0].newDirectoryUID = theDirectory.UID; + if ("onNewDirectory" in window.arguments[0]) { + window.arguments[0].onNewDirectory(theDirectory); + } + } else { + let addressBookBundle = document.getElementById("bundle_addressBook"); + + let errorText; + if (errorArg) { + errorText = addressBookBundle.getFormattedString(errorValue, [ + errorArg, + ]); + } else { + errorText = addressBookBundle.getString(errorValue); + } + + Services.prompt.alert(window, document.title, errorText); + event.preventDefault(); + return; + } + } catch (outer) { + console.error( + "Internal error in pref-directory-add.js:onAccept() " + outer + ); + } +} + +function onCancel() { + window.opener.gUpdate = false; +} + +// Sets the download button state for offline or online. +// This function should only be called for ldap edit dialogs. +function setDownloadOfflineOnlineState(isOffline) { + if (isOffline) { + // Disable the download button and add some text indicating why. + document.getElementById("downloadWarningMsg").textContent = document + .getElementById("bundle_addressBook") + .getString("abReplicationOfflineWarning"); + } + document.getElementById("downloadWarningMsg").hidden = !isOffline; + document.getElementById("download").disabled = isOffline; +} diff --git a/comm/mailnews/addrbook/prefs/content/pref-directory-add.xhtml b/comm/mailnews/addrbook/prefs/content/pref-directory-add.xhtml new file mode 100644 index 0000000000..ff2e40df1e --- /dev/null +++ b/comm/mailnews/addrbook/prefs/content/pref-directory-add.xhtml @@ -0,0 +1,190 @@ +<?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/messenger.css" type="text/css"?> +<?xml-stylesheet href="chrome://messenger/skin/shared/grid-layout.css" type="text/css"?> +<?xml-stylesheet href="chrome://messenger/skin/input-fields.css" type="text/css"?> +<?xml-stylesheet href="chrome://messenger/skin/themeableDialog.css" type="text/css"?> + +<!DOCTYPE html SYSTEM "chrome://messenger/locale/addressbook/pref-directory-add.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:html="http://www.w3.org/1999/xhtml" + lightweightthemes="true" + scrolling="false"> +<head> + <title><!-- directoryTitleEdit --></title> + <style> + #directoryTabPanels radiogroup { + margin-inline-start: 4px; + } + #directoryTabPanels textarea { + width: calc(100% - 22px); + } + #directoryTabPanels menulist { + width: calc(100% - 4px); + margin-inline-start: 4px; + } + </style> + <script defer="defer" src="chrome://messenger/content/globalOverlay.js"></script> + <script defer="defer" src="chrome://global/content/editMenuOverlay.js"></script> + <script defer="defer" src="chrome://messenger/content/dialogShadowDom.js"></script> + <script defer="defer" src="chrome://messenger/content/addressbook/pref-directory-add.js"></script> +</head> +<html:body xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> +<dialog id="addDirectory" buttons="accept,cancel" style="width:100vw; min-width:&newDirectoryWidth;"> + <stringbundle id="bundle_addressBook" src="chrome://messenger/locale/addressbook/addressBook.properties"/> + <stringbundle id="bundle_replication" src="chrome://messenger/locale/addressbook/replicationProgress.properties"/> + + <vbox id="editDirectory"> + + <tabbox style="margin:5px"> + <tabs id="directoryTabBox"> + <tab label="&General.tab;"/> + <tab label="&Offline.tab;"/> + <tab label="&Advanced.tab;"/> + </tabs> + + <tabpanels id="directoryTabPanels" flex="1"> + <vbox> + <div xmlns="http://www.w3.org/1999/xhtml" class="grid-three-column"> + <div class="flex-items-center"> + <xul:label id="descriptionLabel" value="&directoryName.label;" + accesskey="&directoryName.accesskey;" + control="description"/> + </div> + <div> + <input id="description" type="text" class="input-inline" + aria-labelledby="descriptionLabel"/> + </div> + <div></div> + <div class="flex-items-center"> + <xul:label id="hostnameLabel" + value="&directoryHostname.label;" + accesskey="&directoryHostname.accesskey;" + control="hostname"/> + </div> + <div> + <input id="hostname" type="text" + class="uri-element input-inline" + aria-labelledby="descriptionLabel" + disableiflocked="true"/> + </div> + <div></div> + <div class="flex-items-center"> + <xul:label id="basednLabel" + value="&directoryBaseDN.label;" + accesskey="&directoryBaseDN.accesskey;" + control="basedn"/> + </div> + <div> + <input id="basedn" type="text" + class="uri-element input-inline" + aria-labelledby="basednLabel" + disableiflocked="true"/> + </div> + <div class="flex-items-center flex-content-center"> + <xul:button label="&findButton.label;" + accesskey="&findButton.accesskey;" disabled="true"/> + </div> + <div class="flex-items-center"> + <xul:label id="portLabel" value="&portNumber.label;" + accesskey="&portNumber.accesskey;" + control="port"/> + </div> + <div> + <input id="port" type="number" + class="size5 input-inline" + min="1" max="65535" + aria-labelledby="portLabel" + disableiflocked="true"/> + </div> + <div></div> + <div class="flex-items-center"> + <xul:label id="loginLabel" value="&directoryLogin.label;" + accesskey="&directoryLogin.accesskey;" + control="login"/> + </div> + <div> + <input id="login" type="text" class="uri-element input-inline" + aria-labelledby="loginLabel"/> + </div> + <div></div> + </div> + <separator/> + <checkbox id="secure" label="&directorySecure.label;" + accesskey="&directorySecure.accesskey;" + oncommand="onSecure();" disableiflocked="true"/> + </vbox> + <vbox> + <description>&offlineText.label;</description> + <separator/> + <hbox> + <button id="download" oncommand="DownloadNow();"/> + <spacer flex="1"/> + </hbox> + <description id="downloadWarningMsg" hidden="true" class="error"/> + <description id="replicationProgressText" hidden="true"/> + + <html:progress id="replicationProgressMeter" value="0" max="100" hidden="hidden"/> + </vbox> + <vbox> + <div xmlns="http://www.w3.org/1999/xhtml" class="grid-two-column"> + <div class="flex-items-center"> + <xul:label id="returnMaxLabel" value="&return.label;" + accesskey="&return.accesskey;" + control="results"/> + </div> + <div class="flex-items-center"> + <input id="results" type="number" + class="size5 input-inline" + min="1" max="2147483647" value="100" + aria-labelledby="returnMaxLabel"/> + <xul:label value="&results.label;"/> + </div> + <div class="flex-items-center"> + <xul:label value="&scope.label;" control="scope" + accesskey="&scope.accesskey;"/> + </div> + <div> + <xul:radiogroup id="scope" + orient="horizontal"> + <xul:radio id="one" value="1" label="&scopeOneLevel.label;" + disableiflocked="true" accesskey="&scopeOneLevel.accesskey;"/> + <xul:radio id="sub" value="2" label="&scopeSubtree.label;" + disableiflocked="true" accesskey="&scopeSubtree.accesskey;"/> + </xul:radiogroup> + </div> + <div class="flex-items-center"> + <xul:label value="&searchFilter.label;" + accesskey="&searchFilter.accesskey;" + control="search"/> + </div> + <div> + <textarea id="search" disableiflocked="true"></textarea> + </div> + <div class="flex-items-center"> + <xul:label value="&saslMechanism.label;" control="saslMechanism" + accesskey="&saslMechanism.accesskey;"/> + </div> + <div> + <xul:menulist id="saslMechanism"> + <xul:menupopup> + <xul:menuitem id="Simple" value="" label="&saslOff.label;" + accesskey="&saslOff.accesskey;"/> + <xul:menuitem id="GSSAPI" value="GSSAPI" label="&saslGSSAPI.label;" + accesskey="&saslGSSAPI.accesskey;"/> + </xul:menupopup> + </xul:menulist> + </div> + </div> + </vbox> + </tabpanels> + </tabbox> + </vbox> +</dialog> +</html:body> +</html> diff --git a/comm/mailnews/addrbook/prefs/content/pref-editdirectories.js b/comm/mailnews/addrbook/prefs/content/pref-editdirectories.js new file mode 100644 index 0000000000..2ba3421c5a --- /dev/null +++ b/comm/mailnews/addrbook/prefs/content/pref-editdirectories.js @@ -0,0 +1,188 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* import-globals-from ../../../../mail/components/addrbook/content/abCommon.js */ + +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); + +window.addEventListener("DOMContentLoaded", onInitEditDirectories); + +// Listener to refresh the list items if something changes. In all these +// cases we just rebuild the list as it is easier than searching/adding in the +// correct places an would be an infrequent operation. +var gAddressBookAbListener = { + QueryInterface: ChromeUtils.generateQI([ + "nsIObserver", + "nsISupportsWeakReference", + ]), + + init() { + for (let topic of [ + "addrbook-directory-created", + "addrbook-directory-updated", + "addrbook-directory-deleted", + ]) { + Services.obs.addObserver(this, topic, true); + } + }, + + observe(subject, topic, data) { + subject.QueryInterface(Ci.nsIAbDirectory); + fillDirectoryList(subject); + }, +}; + +function onInitEditDirectories() { + // If the pref is locked disable the "Add" button + if (Services.prefs.prefIsLocked("ldap_2.disable_button_add")) { + document.getElementById("addButton").setAttribute("disabled", true); + } + + // Fill out the directory list + fillDirectoryList(); + + // Add a listener so we can update correctly if the list should change + gAddressBookAbListener.init(); +} + +function fillDirectoryList(aItem = null) { + var abList = document.getElementById("directoriesList"); + + // Empty out anything in the list + while (abList.hasChildNodes()) { + abList.lastChild.remove(); + } + + // Init the address book list + let holdingArray = []; + for (let ab of MailServices.ab.directories) { + if (ab.isRemote) { + holdingArray.push(ab); + } + } + + holdingArray.sort(function (a, b) { + return a.dirName.localeCompare(b.dirName); + }); + + holdingArray.forEach(function (ab) { + let item = document.createXULElement("richlistitem"); + let label = document.createXULElement("label"); + label.setAttribute("value", ab.dirName); + item.appendChild(label); + item.setAttribute("value", ab.URI); + + abList.appendChild(item); + }); + + // Forces the focus back on the list and on the first item. + // We also select an edited or recently added item. + abList.focus(); + if (aItem) { + abList.selectedIndex = holdingArray.findIndex(d => { + return d && d.URI == aItem.URI; + }); + } +} + +function selectDirectory() { + var abList = document.getElementById("directoriesList"); + var editButton = document.getElementById("editButton"); + var removeButton = document.getElementById("removeButton"); + + if (abList && abList.selectedItem) { + editButton.removeAttribute("disabled"); + + // If the disable delete button pref for the selected directory is set, + // disable the delete button for that directory. + let ab = MailServices.ab.getDirectory(abList.value); + let disable = Services.prefs.getBoolPref( + ab.dirPrefId + ".disable_delete", + false + ); + if (disable) { + removeButton.setAttribute("disabled", true); + } else { + removeButton.removeAttribute("disabled"); + } + } else { + editButton.setAttribute("disabled", true); + removeButton.setAttribute("disabled", true); + } +} + +function dblClickDirectory(event) { + // We only care about left click events. + if (event.button != 0) { + return; + } + + editDirectory(); +} + +function addDirectory() { + parent.gSubDialog.open( + "chrome://messenger/content/addressbook/pref-directory-add.xhtml", + { features: "resizable=no" } + ); +} + +function editDirectory() { + var abList = document.getElementById("directoriesList"); + + if (abList && abList.selectedItem) { + let abURI = abList.value; + let ab = MailServices.ab.getDirectory(abURI); + + parent.gSubDialog.open( + "chrome://messenger/content/addressbook/pref-directory-add.xhtml", + { features: "resizable=no" }, + { selectedDirectory: ab } + ); + } +} + +async function removeDirectory() { + let abList = document.getElementById("directoriesList"); + + if (!abList.selectedItem) { + return; + } + + let directory = GetDirectoryFromURI(abList.value); + if ( + !directory || + ["ldap_2.servers.history", "ldap_2.servers.pab"].includes( + directory.dirPrefId + ) + ) { + return; + } + + let action = "delete-book"; + if (directory.isMailList) { + action = "delete-lists"; + } else if ( + [ + Ci.nsIAbManager.CARDDAV_DIRECTORY_TYPE, + Ci.nsIAbManager.LDAP_DIRECTORY_TYPE, + ].includes(directory.dirType) + ) { + action = "remove-remote-book"; + } + + let [title, message] = await document.l10n.formatValues([ + { id: `about-addressbook-confirm-${action}-title`, args: { count: 1 } }, + { + id: `about-addressbook-confirm-${action}`, + args: { name: directory.dirName, count: 1 }, + }, + ]); + + if (Services.prompt.confirm(window, title, message)) { + MailServices.ab.deleteAddressBook(directory.URI); + } +} diff --git a/comm/mailnews/addrbook/prefs/content/pref-editdirectories.xhtml b/comm/mailnews/addrbook/prefs/content/pref-editdirectories.xhtml new file mode 100644 index 0000000000..381aee3050 --- /dev/null +++ b/comm/mailnews/addrbook/prefs/content/pref-editdirectories.xhtml @@ -0,0 +1,77 @@ +<?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/messenger.css" type="text/css"?> + +<!DOCTYPE html SYSTEM "chrome://messenger/locale/addressbook/pref-directory.dtd"> + +<html + xmlns="http://www.w3.org/1999/xhtml" + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + xmlns:html="http://www.w3.org/1999/xhtml" + scrolling="false" +> + <head> + <title>&pref.ldap.window.title;</title> + <link + rel="localization" + href="messenger/addressbook/aboutAddressBook.ftl" + /> + <script + defer="defer" + src="chrome://messenger/content/addressbook/abCommon.js" + ></script> + <script + defer="defer" + src="chrome://messenger/content/addressbook/pref-editdirectories.js" + ></script> + </head> + <html:body + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + > + <dialog id="editDirectories" buttons="accept"> + <stringbundle + id="bundle_addressBook" + src="chrome://messenger/locale/addressbook/addressBook.properties" + /> + + <label + value="&directoriesText.label;" + accesskey="&directoriesText.accesskey;" + control="directoriesList" + /> + <hbox flex="1"> + <richlistbox + id="directoriesList" + flex="1" + onselect="selectDirectory();" + ondblclick="dblClickDirectory(event);" + /> + <vbox> + <button + id="addButton" + label="&addDirectory.label;" + accesskey="&addDirectory.accesskey;" + oncommand="addDirectory();" + /> + <button + id="editButton" + label="&editDirectory.label;" + accesskey="&editDirectory.accesskey;" + disabled="true" + oncommand="editDirectory();" + /> + <button + id="removeButton" + label="&deleteDirectory.label;" + accesskey="&deleteDirectory.accesskey;" + disabled="true" + oncommand="removeDirectory();" + /> + </vbox> + </hbox> + </dialog> + </html:body> +</html> |