Bug 46050 - Prevent duplicate address book names. r=jorgk, ui-r=thomasd,Paenglab
authoraceman <acelists@atlas.sk>
Thu, 24 Aug 2017 06:15:34 +0200
changeset 28794 aaf42ebb0c89b2b1e4d95fe8e395fe7b3d0df188
parent 28793 5a4764a25a0e22561012b96cc0fbd58c5e35794c
child 28795 ac14ca6da23824d04c49339e1dc2f913babdbac5
push id2027
push userclokep@gmail.com
push dateFri, 22 Sep 2017 15:34:57 +0000
treeherdercomm-beta@cffa2d0e5946 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorgk, thomasd, Paenglab
bugs46050
Bug 46050 - Prevent duplicate address book names. r=jorgk, ui-r=thomasd,Paenglab
mail/locales/en-US/chrome/messenger/addressbook/addressBook.properties
mailnews/addrbook/content/abAddressBookNameDialog.js
mailnews/addrbook/prefs/content/pref-directory-add.js
mailnews/addrbook/public/nsIAbManager.idl
suite/locales/en-US/chrome/mailnews/addressbook/addressBook.properties
--- a/mail/locales/en-US/chrome/messenger/addressbook/addressBook.properties
+++ b/mail/locales/en-US/chrome/messenger/addressbook/addressBook.properties
@@ -225,20 +225,29 @@ joinMeInThisChat=Join+me+in+this+Chat.
 headingHome=Home
 headingWork=Work
 headingOther=Other
 headingChat=Chat
 headingPhone=Phone
 headingDescription=Description
 headingAddresses=Addresses
 
-# For address books
+## For address books
 addressBookTitleNew=New Address Book
-## LOCALIZATION NOTE (addressBookTitleEdit): %S will be replaced by the the Address Book's name
+# LOCALIZATION NOTE (addressBookTitleEdit):
+# %S is the current name of the address book.
+# Example: My Custom AB Properties
 addressBookTitleEdit=%S Properties
+duplicateNameTitle=Duplicate Address Book Name
+# LOCALIZATION NOTE (duplicateNameText):
+# Don't localize "\n• %S" unless your local layout comes out wrong.
+# %S is the name of the existing address book.
+# Example: An address book with this name already exists:
+#          • My Custom AB
+duplicateNameText=An address book with this name already exists:\n• %S
 
 # For corrupt .mab files
 corruptMabFileTitle=Corrupt Address Book File
 corruptMabFileAlert=One of your address book files (%1$S file) could not be read. A new %2$S file will be created and a backup of the old file, called %3$S, will be created in the same directory.
 
 # For locked .mab files
 lockedMabFileTitle=Unable to Load Address Book File
 lockedMabFileAlert=Unable to load address book file %S. It may be read-only, or locked by another application. Please try again later.
--- a/mailnews/addrbook/content/abAddressBookNameDialog.js
+++ b/mailnews/addrbook/content/abAddressBookNameDialog.js
@@ -1,13 +1,15 @@
 /* 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:///modules/mailServices.js");
+Components.utils.import("resource:///modules/iteratorUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
 
 var gOkButton;
 var gNameInput;
 var gDirectory = null;
 
 var kPersonalAddressbookURI = "moz-abmdbdirectory://abook.mab";
 var kCollectedAddressbookURI = "moz-abmdbdirectory://history.mab";
 var kAllDirectoryRoot = "moz-abdirectory://";
@@ -51,16 +53,30 @@ function abNameOnLoad()
     abNameDoOkEnabling();
   }
 }
 
 function abNameOKButton()
 {
   var newName = gNameInput.value.trim();
 
+  // Do not allow an already existing name.
+  for (let ab of fixIterator(MailServices.ab.directories,
+                             Components.interfaces.nsIAbDirectory)) {
+    if ((ab.dirName.toLowerCase() == newName.toLowerCase()) &&
+        (!gDirectory || (ab.URI != gDirectory.URI))) {
+      const kAlertTitle = document.getElementById("bundle_addressBook")
+                                  .getString("duplicateNameTitle");
+      const kAlertText = document.getElementById("bundle_addressBook")
+                                 .getFormattedString("duplicateNameText", [ab.dirName]);
+      Services.prompt.alert(window, kAlertTitle, kAlertText);
+      return false;
+    }
+  }
+
   // Either create a new directory or update an existing one depending on what
   // we were given when we started.
   if (gDirectory)
     gDirectory.dirName = newName;
   else
     MailServices.ab.newAddressBook(newName, "", kPABDirectory);
 
   return true;
--- a/mailnews/addrbook/prefs/content/pref-directory-add.js
+++ b/mailnews/addrbook/prefs/content/pref-directory-add.js
@@ -2,16 +2,17 @@
 /* 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");
 Components.utils.import("resource:///modules/mailServices.js");
 Components.utils.import("resource:///modules/hostnameUtils.jsm");
+Components.utils.import("resource:///modules/iteratorUtils.jsm");
 
 var gCurrentDirectory = null;
 var gReplicationBundle = null;
 var gReplicationService =
   Components.classes["@mozilla.org/addressbook/ldap-replication-service;1"].
              getService(Components.interfaces.nsIAbLDAPReplicationService);
 var gReplicationCancelled = false;
 var gProgressText;
@@ -280,35 +281,53 @@ function hasCharacters(number)
     return false;
   else
     return true;
 }
 
 function onAccept()
 {
   try {
-    var pref_string_content = "";
-    var pref_string_title = "";
+    let pref_string_content = "";
+    let pref_string_title = "";
+
+    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 = "";
 
-    var description = document.getElementById("description").value;
-    var hostname = cleanUpHostName(document.getElementById("hostname").value);
-    var port = document.getElementById("port").value;
-    var secure = document.getElementById("secure");
-    var results = document.getElementById("results").value;
-    var errorValue = null;
-    var saslMechanism = "";
-    if ((!description) || (description.trim() == ""))
+    let findDupeName = function(newName) {
+      // Do not allow an already existing name.
+      for (let ab of fixIterator(MailServices.ab.directories,
+                                 Components.interfaces.nsIAbDirectory)) {
+        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";
     // XXX write isValidDn and call it on the dn string here?
     else if (port && hasCharacters(port))
       errorValue = "invalidPortNumber";
     else if (results && hasCharacters(results))
       errorValue = "invalidResults";
+
     if (!errorValue) {
       // XXX Due to the LDAP c-sdk pass a dummy url to the IO service, then
       // update the parts (bug 473351).
       let ldapUrl = Services.io.newURI(
         (secure.checked ? "ldaps://" : "ldap://") + "localhost/dc=???")
         .QueryInterface(Components.interfaces.nsILDAPURL);
 
       ldapUrl.host = hostname;
@@ -346,33 +365,37 @@ function onAccept()
 
       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.opener.gUpdate = true;
     } else {
-      var addressBookBundle = document.getElementById("bundle_addressBook");
+      let addressBookBundle = document.getElementById("bundle_addressBook");
 
-      Services.prompt.alert(window,
-                            document.title,
-                            addressBookBundle.getString(errorValue));
+      let errorText;
+      if (errorArg)
+        errorText = addressBookBundle.getFormattedString(errorValue, [errorArg])
+      else
+        errorText = addressBookBundle.getString(errorValue);
+
+      Services.prompt.alert(window, document.title, errorText);
       return false;
     }
   } catch (outer) {
-    dump("Internal error in pref-directory-add.js:onAccept() " + outer + "\n");
+    Components.utils.reportError("Internal error in pref-directory-add.js:onAccept() " + outer);
   }
   return true;
 }
 
 function onCancel()
-{  
+{
   window.opener.gUpdate = false;
 }
 
 
 // called by Help button in platform overlay
 function doHelpButton()
 {
   openHelp("mail-ldap-properties");
--- a/mailnews/addrbook/public/nsIAbManager.idl
+++ b/mailnews/addrbook/public/nsIAbManager.idl
@@ -143,18 +143,17 @@ interface nsIAbManager : nsISupports
 
   /**
    * Returns the user profile directory. NOTE: this should not be used
    * as it may go away soon.
    */
   readonly attribute nsIFile userProfileDirectory;
 
   /**
-   * Finds out if the mailing list name exists in any *mork/MDB* based
-   * address book
+   * Finds out if the mailing list name exists in any address book.
    *
    * @param  aName      The name of the list to try and find.
    *
    * @return            True if the name exists.
    */
   boolean mailListNameExists(in wstring name);
 
   /**
--- a/suite/locales/en-US/chrome/mailnews/addressbook/addressBook.properties
+++ b/suite/locales/en-US/chrome/mailnews/addressbook/addressBook.properties
@@ -145,20 +145,29 @@ joinMeInThisChat=Join+me+in+this+Chat.
 # For printing
 headingHome=Home
 headingWork=Work
 headingOther=Other
 headingPhone=Phone
 headingDescription=Description
 headingAddresses=Addresses
 
-# For address books
+## For address books
 addressBookTitleNew=New Address Book
-## LOCALIZATION NOTE (addressBookTitleEdit): %S will be replaced by the the Address Book's name
+# LOCALIZATION NOTE (addressBookTitleEdit):
+# %S is the current name of the address book.
+# Example: My Custom AB Properties
 addressBookTitleEdit=%S Properties
+duplicateNameTitle=Duplicate Address Book Name
+# LOCALIZATION NOTE (duplicateNameText):
+# Don't localize "\n• %S" unless your local layout comes out wrong.
+# %S is the name of the existing address book.
+# Example: An address book with this name already exists:
+#          • My Custom AB
+duplicateNameText=An address book with this name already exists:\n• %S
 
 # For corrupt .mab files
 corruptMabFileTitle=Corrupt Address Book File
 corruptMabFileAlert=One of your address book files (%1$S file) could not be read. A new %2$S file will be created and a backup of the old file, called %3$S, will be created in the same directory.
 
 # For locked .mab files
 lockedMabFileTitle=Unable to Load Address Book File
 lockedMabFileAlert=Unable to load address book file %S. It may be read-only, or locked by another application. Please try again later.