summaryrefslogtreecommitdiffstats
path: root/mailnews/addrbook/src/nsDirPrefs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mailnews/addrbook/src/nsDirPrefs.cpp')
-rw-r--r--mailnews/addrbook/src/nsDirPrefs.cpp1452
1 files changed, 1452 insertions, 0 deletions
diff --git a/mailnews/addrbook/src/nsDirPrefs.cpp b/mailnews/addrbook/src/nsDirPrefs.cpp
new file mode 100644
index 000000000..5e4c046b2
--- /dev/null
+++ b/mailnews/addrbook/src/nsDirPrefs.cpp
@@ -0,0 +1,1452 @@
+/* -*- 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/. */
+
+/* directory server preferences (used to be dirprefs.c in 4.x) */
+
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+#include "nsDirPrefs.h"
+#include "nsIPrefLocalizedString.h"
+#include "nsIObserver.h"
+#include "nsTArray.h"
+#include "nsServiceManagerUtils.h"
+#include "nsMemory.h"
+#include "nsIAddrDatabase.h"
+#include "nsAbBaseCID.h"
+#include "nsIAbManager.h"
+#include "nsIFile.h"
+#include "nsWeakReference.h"
+#include "nsIAbMDBDirectory.h"
+#if defined(MOZ_LDAP_XPCOM)
+#include "nsIAbLDAPDirectory.h"
+#endif
+#include "prmem.h"
+#include "prprf.h"
+#include "plstr.h"
+#include "nsQuickSort.h"
+#include "nsComponentManagerUtils.h"
+#include "msgCore.h"
+#include "nsStringGlue.h"
+
+#include <ctype.h>
+
+/*****************************************************************************
+ * Private definitions
+ */
+
+/* Default settings for site-configurable prefs */
+#define kDefaultPosition 1
+static bool dir_IsServerDeleted(DIR_Server * server);
+
+static char *DIR_GetStringPref(const char *prefRoot, const char *prefLeaf, const char *defaultValue);
+static int32_t DIR_GetIntPref(const char *prefRoot, const char *prefLeaf, int32_t defaultValue);
+static char *DIR_GetLocalizedStringPref(const char *prefRoot, const char *prefLeaf);
+
+static char * dir_ConvertDescriptionToPrefName(DIR_Server * server);
+
+void DIR_SetFileName(char** filename, const char* leafName);
+static void DIR_SetIntPref(const char *prefRoot, const char *prefLeaf, int32_t value, int32_t defaultValue);
+static DIR_Server *dir_MatchServerPrefToServer(nsTArray<DIR_Server*> *wholeList, const char *pref);
+static bool dir_ValidateAndAddNewServer(nsTArray<DIR_Server*> *wholeList, const char *fullprefname);
+static void DIR_DeleteServerList(nsTArray<DIR_Server*> *wholeList);
+
+static char *dir_CreateServerPrefName(DIR_Server *server);
+static void DIR_GetPrefsForOneServer(DIR_Server *server);
+
+static void DIR_InitServer(DIR_Server *server, DirectoryType dirType = (DirectoryType)0);
+static DIR_PrefId DIR_AtomizePrefName(const char *prefname);
+
+const int32_t DIR_POS_APPEND = -1;
+const int32_t DIR_POS_DELETE = -2;
+static bool DIR_SetServerPosition(nsTArray<DIR_Server*> *wholeList, DIR_Server *server, int32_t position);
+
+/* These two routines should be called to initialize and save
+ * directory preferences from the XP Java Script preferences
+ */
+static nsresult DIR_GetServerPreferences(nsTArray<DIR_Server*>** list);
+static void DIR_SaveServerPreferences(nsTArray<DIR_Server*> *wholeList);
+
+static int32_t dir_UserId = 0;
+nsTArray<DIR_Server*> *dir_ServerList = nullptr;
+
+/*****************************************************************************
+ * Functions for creating the new back end managed DIR_Server list.
+ */
+class DirPrefObserver final : public nsSupportsWeakReference,
+ public nsIObserver
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+
+private:
+ ~DirPrefObserver() {}
+};
+
+NS_IMPL_ISUPPORTS(DirPrefObserver, nsISupportsWeakReference, nsIObserver)
+
+NS_IMETHODIMP DirPrefObserver::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *aData)
+{
+ nsCOMPtr<nsIPrefBranch> prefBranch(do_QueryInterface(aSubject));
+ nsCString strPrefName;
+ strPrefName.Assign(NS_ConvertUTF16toUTF8(aData));
+ const char *prefname = strPrefName.get();
+
+ DIR_PrefId id = DIR_AtomizePrefName(prefname);
+
+ // Just get out if we get nothing here - we don't need to do anything
+ if (id == idNone)
+ return NS_OK;
+
+ /* Check to see if the server is in the unified server list.
+ */
+ DIR_Server *server = dir_MatchServerPrefToServer(dir_ServerList, prefname);
+ if (server)
+ {
+ /* If the server is in the process of being saved, just ignore this
+ * change. The DIR_Server structure is not really changing.
+ */
+ if (server->savingServer)
+ return NS_OK;
+
+ /* If the pref that changed is the position, read it in. If the new
+ * position is zero, remove the server from the list.
+ */
+ if (id == idPosition)
+ {
+ int32_t position;
+
+ /* We must not do anything if the new position is the same as the
+ * position in the DIR_Server. This avoids recursion in cases
+ * where we are deleting the server.
+ */
+ prefBranch->GetIntPref(prefname, &position);
+ if (position != server->position)
+ {
+ server->position = position;
+ if (dir_IsServerDeleted(server))
+ DIR_SetServerPosition(dir_ServerList, server, DIR_POS_DELETE);
+ }
+ }
+
+ if (id == idDescription) {
+ // Ensure the local copy of the description is kept up to date.
+ PR_FREEIF(server->description);
+ server->description = DIR_GetLocalizedStringPref(prefname, nullptr);
+ }
+ }
+ /* If the server is not in the unified list, we may need to add it. Servers
+ * are only added when the position, serverName and description are valid.
+ */
+ else if (id == idPosition || id == idType || id == idDescription)
+ {
+ dir_ValidateAndAddNewServer(dir_ServerList, prefname);
+ }
+
+ return NS_OK;
+}
+
+// A pointer to the pref observer
+static DirPrefObserver *prefObserver = nullptr;
+
+static nsresult DIR_GetDirServers()
+{
+ nsresult rv = NS_OK;
+
+ if (!dir_ServerList)
+ {
+ /* we need to build the DIR_Server list */
+ rv = DIR_GetServerPreferences(&dir_ServerList);
+
+ /* Register the preference call back if necessary. */
+ if (NS_SUCCEEDED(rv) && !prefObserver)
+ {
+ nsCOMPtr<nsIPrefBranch> pbi(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return rv;
+ prefObserver = new DirPrefObserver();
+
+ if (!prefObserver)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(prefObserver);
+
+ pbi->AddObserver(PREF_LDAP_SERVER_TREE_NAME, prefObserver, true);
+ }
+ }
+ return rv;
+}
+
+nsTArray<DIR_Server*>* DIR_GetDirectories()
+{
+ if (!dir_ServerList)
+ DIR_GetDirServers();
+ return dir_ServerList;
+}
+
+DIR_Server* DIR_GetServerFromList(const char* prefName)
+{
+ DIR_Server* result = nullptr;
+
+ if (!dir_ServerList)
+ DIR_GetDirServers();
+
+ if (dir_ServerList)
+ {
+ int32_t count = dir_ServerList->Length();
+ int32_t i;
+ for (i = 0; i < count; ++i)
+ {
+ DIR_Server *server = dir_ServerList->ElementAt(i);
+
+ if (server && strcmp(server->prefName, prefName) == 0)
+ {
+ result = server;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+static nsresult SavePrefsFile()
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrefService> pPref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return rv;
+ return pPref->SavePrefFile(nullptr);
+}
+
+nsresult DIR_ShutDown() /* FEs should call this when the app is shutting down. It frees all DIR_Servers regardless of ref count values! */
+{
+ nsresult rv = SavePrefsFile();
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ DIR_DeleteServerList(dir_ServerList);
+ dir_ServerList = nullptr;
+
+ /* unregister the preference call back, if necessary.
+ * we need to do this as DIR_Shutdown() is called when switching profiles
+ * when using turbo. (see nsAbDirectoryDataSource::Observe())
+ * When switching profiles, prefs get unloaded and then re-loaded
+ * we don't want our callback to get called for all that.
+ * We'll reset our callback the first time DIR_GetDirServers() is called
+ * after we've switched profiles.
+ */
+ NS_IF_RELEASE(prefObserver);
+
+ return NS_OK;
+}
+
+nsresult DIR_ContainsServer(DIR_Server* pServer, bool *hasDir)
+{
+ if (dir_ServerList)
+ {
+ int32_t count = dir_ServerList->Length();
+ int32_t i;
+ for (i = 0; i < count; i++)
+ {
+ DIR_Server* server = dir_ServerList->ElementAt(i);
+ if (server == pServer)
+ {
+ *hasDir = true;
+ return NS_OK;
+ }
+ }
+ }
+ *hasDir = false;
+ return NS_OK;
+}
+
+nsresult DIR_AddNewAddressBook(const nsAString &dirName,
+ const nsACString &fileName,
+ const nsACString &uri,
+ DirectoryType dirType,
+ const nsACString &prefName,
+ DIR_Server** pServer)
+{
+ DIR_Server * server = (DIR_Server *) PR_Malloc(sizeof(DIR_Server));
+ if (!server)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ DIR_InitServer(server, dirType);
+ if (!dir_ServerList)
+ DIR_GetDirServers();
+ if (dir_ServerList)
+ {
+ server->description = ToNewCString(NS_ConvertUTF16toUTF8(dirName));
+ server->position = kDefaultPosition; // don't set position so alphabetic sort will happen.
+
+ if (!fileName.IsEmpty())
+ server->fileName = ToNewCString(fileName);
+ else if (dirType == PABDirectory)
+ DIR_SetFileName(&server->fileName, kPersonalAddressbook);
+ else if (dirType == LDAPDirectory)
+ DIR_SetFileName(&server->fileName, kMainLdapAddressBook);
+
+ if (dirType != PABDirectory) {
+ if (!uri.IsEmpty())
+ server->uri = ToNewCString(uri);
+ }
+
+ if (!prefName.IsEmpty())
+ server->prefName = ToNewCString(prefName);
+
+ dir_ServerList->AppendElement(server);
+
+ DIR_SavePrefsForOneServer(server);
+
+ *pServer = server;
+
+ // save new address book into pref file
+ return SavePrefsFile();
+ }
+ return NS_ERROR_FAILURE;
+}
+
+/*****************************************************************************
+ * Functions for creating DIR_Servers
+ */
+static void DIR_InitServer(DIR_Server *server, DirectoryType dirType)
+{
+ if (!server) {
+ NS_WARNING("DIR_InitServer: server parameter not initialized");
+ return;
+ }
+
+ memset(server, 0, sizeof(DIR_Server));
+ server->position = kDefaultPosition;
+ server->uri = nullptr;
+ server->savingServer = false;
+ server->dirType = dirType;
+}
+
+/* Function for setting the position of a server. Can be used to append,
+ * delete, or move a server in a server list.
+ *
+ * The third parameter specifies the new position the server is to occupy.
+ * The resulting position may differ depending on the lock state of the
+ * given server and other servers in the list. The following special values
+ * are supported:
+ * DIR_POS_APPEND - Appends the server to the end of the list. If the server
+ * is already in the list, does nothing.
+ * DIR_POS_DELETE - Deletes the given server from the list. Note that this
+ * does not cause the server structure to be freed.
+ *
+ * Returns true if the server list was re-sorted.
+ */
+static bool DIR_SetServerPosition(nsTArray<DIR_Server*> *wholeList, DIR_Server *server, int32_t position)
+ {
+ NS_ENSURE_TRUE(wholeList, false);
+
+ int32_t i, count, num;
+ bool resort = false;
+ DIR_Server *s=nullptr;
+
+ switch (position) {
+ case DIR_POS_APPEND:
+ /* Do nothing if the request is to append a server that is already
+ * in the list.
+ */
+ count = wholeList->Length();
+ for (i= 0; i < count; i++)
+ {
+ if ((s = wholeList->ElementAt(i)) != nullptr)
+ if (s == server)
+ return false;
+ }
+ /* In general, if there are any servers already in the list, set the
+ * position to the position of the last server plus one. If there
+ * are none, set it to position 1.
+ */
+ if (count > 0)
+ {
+ s = wholeList->ElementAt(count - 1);
+ server->position = s->position + 1;
+ }
+ else
+ server->position = 1;
+
+ wholeList->AppendElement(server);
+ break;
+
+ case DIR_POS_DELETE:
+ /* Remove the prefs corresponding to the given server. If the prefName
+ * value is nullptr, the server has never been saved and there are no
+ * prefs to remove.
+ */
+ if (server->prefName)
+ {
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> pPref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return false;
+
+ pPref->DeleteBranch(server->prefName);
+
+ // mark the server as deleted by setting its position to 0
+ DIR_SetIntPref(server->prefName, "position", 0, -1);
+ }
+
+ /* If the server is in the server list, remove it.
+ */
+ num = wholeList->IndexOf(server);
+ if (num >= 0)
+ {
+ /* The list does not need to be re-sorted if the server is the
+ * last one in the list.
+ */
+ count = wholeList->Length();
+ if (num == count - 1)
+ {
+ wholeList->RemoveElementAt(num);
+ }
+ else
+ {
+ resort = true;
+ wholeList->RemoveElement(server);
+ }
+ }
+ break;
+
+ default:
+ /* See if the server is already in the list.
+ */
+ count = wholeList->Length();
+ for (i= 0; i < count; i++)
+ {
+ if ((s = wholeList->ElementAt(i)) != nullptr)
+ if (s == server)
+ break;
+ }
+
+ /* If the server is not in the list, add it to the beginning and re-sort.
+ */
+ if (s == nullptr)
+ {
+ server->position = position;
+ wholeList->AppendElement(server);
+ resort = true;
+ }
+
+ /* Don't re-sort if the server is already in the requested position.
+ */
+ else if (server->position != position)
+ {
+ server->position = position;
+ wholeList->RemoveElement(server);
+ wholeList->AppendElement(server);
+ resort = true;
+ }
+ break;
+ }
+
+ /* Make sure our position changes get saved back to prefs
+ */
+ DIR_SaveServerPreferences(wholeList);
+
+ return resort;
+}
+
+/*****************************************************************************
+ * DIR_Server Callback Notification Functions
+ */
+
+/* dir_matchServerPrefToServer
+ *
+ * This function finds the DIR_Server in the unified DIR_Server list to which
+ * the given preference string belongs.
+ */
+static DIR_Server *dir_MatchServerPrefToServer(nsTArray<DIR_Server*> *wholeList, const char *pref)
+{
+ DIR_Server *server;
+
+ int32_t count = wholeList->Length();
+ int32_t i;
+ for (i = 0; i < count; i++)
+ {
+ if ((server = wholeList->ElementAt(i)) != nullptr)
+ {
+ if (server->prefName && PL_strstr(pref, server->prefName) == pref)
+ {
+ char c = pref[PL_strlen(server->prefName)];
+ if (c == 0 || c == '.')
+ return server;
+ }
+ }
+ }
+ return nullptr;
+}
+
+/* dir_ValidateAndAddNewServer
+ *
+ * This function verifies that the position, serverName and description values
+ * are set for the given prefName. If they are then it adds the server to the
+ * unified server list.
+ */
+static bool dir_ValidateAndAddNewServer(nsTArray<DIR_Server*> *wholeList, const char *fullprefname)
+{
+ bool rc = false;
+
+ const char *endname = PL_strchr(&fullprefname[PL_strlen(PREF_LDAP_SERVER_TREE_NAME) + 1], '.');
+ if (endname)
+ {
+ char *prefname = (char *)PR_Malloc(endname - fullprefname + 1);
+ if (prefname)
+ {
+ int32_t dirType;
+ char *t1 = nullptr, *t2 = nullptr;
+
+ PL_strncpyz(prefname, fullprefname, endname - fullprefname + 1);
+
+ dirType = DIR_GetIntPref(prefname, "dirType", -1);
+ if (dirType != -1 &&
+ DIR_GetIntPref(prefname, "position", 0) != 0 &&
+ (t1 = DIR_GetLocalizedStringPref(prefname, "description")) != nullptr)
+ {
+ if (dirType == PABDirectory ||
+ (t2 = DIR_GetStringPref(prefname, "serverName", nullptr)) != nullptr)
+ {
+ DIR_Server *server = (DIR_Server *)PR_Malloc(sizeof(DIR_Server));
+ if (server)
+ {
+ DIR_InitServer(server, (DirectoryType)dirType);
+ server->prefName = prefname;
+ DIR_GetPrefsForOneServer(server);
+ DIR_SetServerPosition(wholeList, server, server->position);
+ rc = true;
+ }
+ PR_FREEIF(t2);
+ }
+ PR_Free(t1);
+ }
+ else
+ PR_Free(prefname);
+ }
+ }
+
+ return rc;
+}
+
+static DIR_PrefId DIR_AtomizePrefName(const char *prefname)
+{
+ if (!prefname)
+ return idNone;
+
+ DIR_PrefId rc = idNone;
+
+ /* Skip the "ldap_2.servers.<server-name>." portion of the string.
+ */
+ if (PL_strstr(prefname, PREF_LDAP_SERVER_TREE_NAME) == prefname)
+ {
+ prefname = PL_strchr(&prefname[PL_strlen(PREF_LDAP_SERVER_TREE_NAME) + 1], '.');
+ if (!prefname)
+ return idNone;
+ else
+ prefname = prefname + 1;
+ }
+
+ switch (prefname[0]) {
+ case 'd':
+ switch (prefname[1]) {
+ case 'e': /* description */
+ rc = idDescription;
+ break;
+ case 'i': /* dirType */
+ rc = idType;
+ break;
+ }
+ break;
+
+ case 'f':
+ rc = idFileName;
+ break;
+
+ case 'p':
+ switch (prefname[1]) {
+ case 'o':
+ switch (prefname[2]) {
+ case 's': /* position */
+ rc = idPosition;
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 'u': /* uri */
+ rc = idUri;
+ break;
+ }
+
+ return rc;
+}
+
+/*****************************************************************************
+ * Functions for destroying DIR_Servers
+ */
+
+/* this function determines if the passed in server is no longer part of the of
+ the global server list. */
+static bool dir_IsServerDeleted(DIR_Server * server)
+{
+ return (server && server->position == 0);
+}
+
+/* when the back end manages the server list, deleting a server just decrements its ref count,
+ in the old world, we actually delete the server */
+static void DIR_DeleteServer(DIR_Server *server)
+{
+ if (server)
+ {
+ /* when destroying the server check its clear flag to see if things need cleared */
+#ifdef XP_FileRemove
+ if (DIR_TestFlag(server, DIR_CLEAR_SERVER))
+ {
+ if (server->fileName)
+ XP_FileRemove (server->fileName, xpAddrBookNew);
+ }
+#endif /* XP_FileRemove */
+ PR_Free(server->prefName);
+ PR_Free(server->description);
+ PR_Free(server->fileName);
+ PR_Free(server->uri);
+ PR_Free(server);
+ }
+}
+
+nsresult DIR_DeleteServerFromList(DIR_Server *server)
+{
+ if (!server)
+ return NS_ERROR_NULL_POINTER;
+
+ nsresult rv = NS_OK;
+ nsCOMPtr<nsIFile> dbPath;
+
+ nsCOMPtr<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv))
+ rv = abManager->GetUserProfileDirectory(getter_AddRefs(dbPath));
+
+ if (NS_SUCCEEDED(rv))
+ {
+ // close the database, as long as it isn't the special ones
+ // (personal addressbook and collected addressbook)
+ // which can never be deleted. There was a bug where we would slap in
+ // "abook.mab" as the file name for LDAP directories, which would cause a crash
+ // on delete of LDAP directories. this is just extra protection.
+ if (server->fileName &&
+ strcmp(server->fileName, kPersonalAddressbook) &&
+ strcmp(server->fileName, kCollectedAddressbook))
+ {
+ nsCOMPtr<nsIAddrDatabase> database;
+
+ rv = dbPath->AppendNative(nsDependentCString(server->fileName));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // close file before delete it
+ nsCOMPtr<nsIAddrDatabase> addrDBFactory =
+ do_GetService(NS_ADDRDATABASE_CONTRACTID, &rv);
+
+ if (NS_SUCCEEDED(rv) && addrDBFactory)
+ rv = addrDBFactory->Open(dbPath, false, true, getter_AddRefs(database));
+ if (database) /* database exists */
+ {
+ database->ForceClosed();
+ rv = dbPath->Remove(false);
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+ }
+
+ nsTArray<DIR_Server*> *dirList = DIR_GetDirectories();
+ DIR_SetServerPosition(dirList, server, DIR_POS_DELETE);
+ DIR_DeleteServer(server);
+
+ return SavePrefsFile();
+ }
+
+ return NS_ERROR_NULL_POINTER;
+}
+
+static void DIR_DeleteServerList(nsTArray<DIR_Server*> *wholeList)
+{
+ if (wholeList)
+ {
+ DIR_Server *server = nullptr;
+
+ /* TBD: Send notifications? */
+ int32_t count = wholeList->Length();
+ int32_t i;
+ for (i = count - 1; i >=0; i--)
+ {
+ server = wholeList->ElementAt(i);
+ if (server != nullptr)
+ DIR_DeleteServer(server);
+ }
+ delete wholeList;
+ }
+}
+
+/*****************************************************************************
+ * Functions for managing JavaScript prefs for the DIR_Servers
+ */
+
+static int
+comparePrefArrayMembers(const void* aElement1, const void* aElement2, void* aData)
+{
+ const char* element1 = *static_cast<const char* const *>(aElement1);
+ const char* element2 = *static_cast<const char* const *>(aElement2);
+ const uint32_t offset = *((const uint32_t*)aData);
+
+ // begin the comparison at |offset| chars into the string -
+ // this avoids comparing the "ldap_2.servers." portion of every element,
+ // which will always remain the same.
+ return strcmp(element1 + offset, element2 + offset);
+}
+
+static nsresult dir_GetChildList(const nsCString &aBranch,
+ uint32_t *aCount, char ***aChildList)
+{
+ uint32_t branchLen = aBranch.Length();
+
+ nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
+ if (!prefBranch) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsresult rv = prefBranch->GetChildList(aBranch.get(), aCount, aChildList);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ // traverse the list, and truncate all the descendant strings to just
+ // one branch level below the root branch.
+ for (uint32_t i = *aCount; i--; ) {
+ // The prefname we passed to GetChildList was of the form
+ // "ldap_2.servers." and we are returned the descendants
+ // in the form of "ldap_2.servers.servername.foo"
+ // But we want the prefbranch of the servername, so
+ // write a NUL character in to terminate the string early.
+ char *endToken = strchr((*aChildList)[i] + branchLen, '.');
+ if (endToken)
+ *endToken = '\0';
+ }
+
+ if (*aCount > 1) {
+ // sort the list, in preparation for duplicate entry removal
+ NS_QuickSort(*aChildList, *aCount, sizeof(char*), comparePrefArrayMembers, &branchLen);
+
+ // traverse the list and remove duplicate entries.
+ // we use two positions in the list; the current entry and the next
+ // entry; and perform a bunch of in-place ptr moves. so |cur| points
+ // to the last unique entry, and |next| points to some (possibly much
+ // later) entry to test, at any given point. we know we have >= 2
+ // elements in the list here, so we just init the two counters sensibly
+ // to begin with.
+ uint32_t cur = 0;
+ for (uint32_t next = 1; next < *aCount; ++next) {
+ // check if the elements are equal or unique
+ if (!comparePrefArrayMembers(&((*aChildList)[cur]), &((*aChildList)[next]), &branchLen)) {
+ // equal - just free & increment the next element ptr
+
+ free((*aChildList)[next]);
+ } else {
+ // cur & next are unique, so we need to shift the element.
+ // ++cur will point to the next free location in the
+ // reduced array (it's okay if that's == next)
+ (*aChildList)[++cur] = (*aChildList)[next];
+ }
+ }
+
+ // update the unique element count
+ *aCount = cur + 1;
+ }
+
+ return NS_OK;
+}
+
+static char *DIR_GetStringPref(const char *prefRoot, const char *prefLeaf, const char *defaultValue)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> pPref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return nullptr;
+
+ nsCString value;
+ nsAutoCString prefLocation(prefRoot);
+
+ prefLocation.Append('.');
+ prefLocation.Append(prefLeaf);
+
+ if (NS_SUCCEEDED(pPref->GetCharPref(prefLocation.get(), getter_Copies(value))))
+ {
+ /* unfortunately, there may be some prefs out there which look like this */
+ if (value.EqualsLiteral("(null)"))
+ {
+ if (defaultValue)
+ value = defaultValue;
+ else
+ value.Truncate();
+ }
+
+ if (value.IsEmpty())
+ {
+ rv = pPref->GetCharPref(prefLocation.get(), getter_Copies(value));
+ }
+ }
+ else
+ value = defaultValue;
+
+ return ToNewCString(value);
+}
+
+/**
+ * Get localized unicode string pref from properties file, convert into an UTF8 string
+ * since address book prefs store as UTF8 strings. So far there are 2 default
+ * prefs stored in addressbook.properties.
+ * "ldap_2.servers.pab.description"
+ * "ldap_2.servers.history.description"
+ */
+static char *DIR_GetLocalizedStringPref(const char *prefRoot, const char *prefLeaf)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> pPref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+
+ if (NS_FAILED(rv))
+ return nullptr;
+
+ nsAutoCString prefLocation(prefRoot);
+ if (prefLeaf) {
+ prefLocation.Append('.');
+ prefLocation.Append(prefLeaf);
+ }
+
+ nsString wvalue;
+ nsCOMPtr<nsIPrefLocalizedString> locStr;
+
+ rv = pPref->GetComplexValue(prefLocation.get(), NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(locStr));
+ if (NS_SUCCEEDED(rv))
+ rv = locStr->ToString(getter_Copies(wvalue));
+
+ char *value = nullptr;
+ if (!wvalue.IsEmpty())
+ {
+ value = ToNewCString(NS_ConvertUTF16toUTF8(wvalue));
+ }
+ else
+ {
+ // In TB 2 only some prefs had chrome:// URIs. We had code in place that would
+ // only get the localized string pref for the particular address books that
+ // were built-in.
+ // Additionally, nsIPrefBranch::getComplexValue will only get a non-user-set,
+ // non-locked pref value if it is a chrome:// URI and will get the string
+ // value at that chrome URI. This breaks extensions/autoconfig that want to
+ // set default pref values and allow users to change directory names.
+ //
+ // Now we have to support this, and so if for whatever reason we fail to get
+ // the localized version, then we try and get the non-localized version
+ // instead. If the string value is empty, then we'll just get the empty value
+ // back here.
+ rv = pPref->GetCharPref(prefLocation.get(), &value);
+ if (NS_FAILED(rv))
+ value = nullptr;
+ }
+
+ return value;
+}
+
+static int32_t DIR_GetIntPref(const char *prefRoot, const char *prefLeaf, int32_t defaultValue)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> pPref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+
+ if (NS_FAILED(rv))
+ return defaultValue;
+
+ int32_t value;
+ nsAutoCString prefLocation(prefRoot);
+
+ prefLocation.Append('.');
+ prefLocation.Append(prefLeaf);
+
+ if (NS_FAILED(pPref->GetIntPref(prefLocation.get(), &value)))
+ value = defaultValue;
+
+ return value;
+}
+
+/* This will convert from the old preference that was a path and filename */
+/* to a just a filename */
+static void DIR_ConvertServerFileName(DIR_Server* pServer)
+{
+ char* leafName = pServer->fileName;
+ char* newLeafName = nullptr;
+#if defined(XP_WIN)
+ /* jefft -- bug 73349 This is to allow users share same address book.
+ * It only works if the user specify a full path filename.
+ */
+#ifdef XP_FileIsFullPath
+ if (! XP_FileIsFullPath(leafName))
+ newLeafName = XP_STRRCHR (leafName, '\\');
+#endif /* XP_FileIsFullPath */
+#else
+ newLeafName = strrchr(leafName, '/');
+#endif
+ pServer->fileName = newLeafName ? strdup(newLeafName + 1) : strdup(leafName);
+ if (leafName) PR_Free(leafName);
+}
+
+/* This will generate a correct filename and then remove the path.
+ * Note: we are assuming that the default name is in the native
+ * filesystem charset. The filename will be returned as a UTF8
+ * string.
+ */
+void DIR_SetFileName(char** fileName, const char* defaultName)
+{
+ if (!fileName)
+ return;
+
+ nsresult rv = NS_OK;
+ nsCOMPtr<nsIFile> dbPath;
+
+ *fileName = nullptr;
+
+ nsCOMPtr<nsIAbManager> abManager = do_GetService(NS_ABMANAGER_CONTRACTID, &rv);
+ if (NS_SUCCEEDED(rv))
+ rv = abManager->GetUserProfileDirectory(getter_AddRefs(dbPath));
+ if (NS_SUCCEEDED(rv))
+ {
+ rv = dbPath->AppendNative(nsDependentCString(defaultName));
+ if (NS_SUCCEEDED(rv))
+ {
+ rv = dbPath->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0664);
+
+ nsAutoString realFileName;
+ rv = dbPath->GetLeafName(realFileName);
+
+ if (NS_SUCCEEDED(rv))
+ *fileName = ToNewUTF8String(realFileName);
+ }
+ }
+}
+
+/****************************************************************
+Helper function used to generate a file name from the description
+of a directory. Caller must free returned string.
+An extension is not applied
+*****************************************************************/
+
+static char * dir_ConvertDescriptionToPrefName(DIR_Server * server)
+{
+#define MAX_PREF_NAME_SIZE 25
+ char * fileName = nullptr;
+ char fileNameBuf[MAX_PREF_NAME_SIZE];
+ int32_t srcIndex = 0;
+ int32_t destIndex = 0;
+ int32_t numSrcBytes = 0;
+ const char * descr = nullptr;
+ if (server && server->description)
+ {
+ descr = server->description;
+ numSrcBytes = PL_strlen(descr);
+ while (srcIndex < numSrcBytes && destIndex < MAX_PREF_NAME_SIZE-1)
+ {
+ if (IS_DIGIT(descr[srcIndex]) || IS_ALPHA(descr[srcIndex]))
+ {
+ fileNameBuf[destIndex] = descr[srcIndex];
+ destIndex++;
+ }
+
+ srcIndex++;
+ }
+
+ fileNameBuf[destIndex] = '\0'; /* zero out the last character */
+ }
+
+ if (destIndex) /* have at least one character in the file name? */
+ fileName = strdup(fileNameBuf);
+
+ return fileName;
+}
+
+
+void DIR_SetServerFileName(DIR_Server *server)
+{
+ char * tempName = nullptr;
+ const char * prefName = nullptr;
+ uint32_t numHeaderBytes = 0;
+
+ if (server && (!server->fileName || !(*server->fileName)) )
+ {
+ PR_FREEIF(server->fileName); // might be one byte empty string.
+ /* make sure we have a pref name...*/
+ if (!server->prefName || !*server->prefName)
+ server->prefName = dir_CreateServerPrefName(server);
+
+ /* set default personal address book file name*/
+ if ((server->position == 1) && (server->dirType == PABDirectory))
+ server->fileName = strdup(kPersonalAddressbook);
+ else
+ {
+ /* now use the pref name as the file name since we know the pref name
+ will be unique */
+ prefName = server->prefName;
+ if (prefName && *prefName)
+ {
+ /* extract just the pref name part and not the ldap tree name portion from the string */
+ numHeaderBytes = PL_strlen(PREF_LDAP_SERVER_TREE_NAME) + 1; /* + 1 for the '.' b4 the name */
+ if (PL_strlen(prefName) > numHeaderBytes)
+ tempName = strdup(prefName + numHeaderBytes);
+
+ if (tempName)
+ {
+ server->fileName = PR_smprintf("%s%s", tempName, kABFileName_CurrentSuffix);
+ PR_Free(tempName);
+ }
+ }
+ }
+
+ if (!server->fileName || !*server->fileName) /* when all else has failed, generate a default name */
+ {
+ if (server->dirType == LDAPDirectory)
+ DIR_SetFileName(&(server->fileName), kMainLdapAddressBook); /* generates file name with an ldap prefix */
+ else
+ DIR_SetFileName(&(server->fileName), kPersonalAddressbook);
+ }
+ }
+}
+
+static char *dir_CreateServerPrefName (DIR_Server *server)
+{
+ /* we are going to try to be smart in how we generate our server
+ pref name. We'll try to convert the description into a pref name
+ and then verify that it is unique. If it is unique then use it... */
+ char * leafName = dir_ConvertDescriptionToPrefName(server);
+ char * prefName = nullptr;
+ bool isUnique = false;
+
+ if (!leafName || !*leafName)
+ {
+ // we need to handle this in case the description has no alphanumeric chars
+ // it's very common for cjk users
+ leafName = strdup("_nonascii");
+ }
+
+ if (leafName)
+ {
+ int32_t uniqueIDCnt = 0;
+ char **children = nullptr;
+ /* we need to verify that this pref string name is unique */
+ prefName = PR_smprintf(PREF_LDAP_SERVER_TREE_NAME".%s", leafName);
+ isUnique = false;
+ uint32_t prefCount;
+ nsresult rv = dir_GetChildList(NS_LITERAL_CSTRING(PREF_LDAP_SERVER_TREE_NAME "."),
+ &prefCount, &children);
+ if (NS_SUCCEEDED(rv))
+ {
+ while (!isUnique && prefName)
+ {
+ isUnique = true; /* now flip the logic and assume we are unique until we find a match */
+ for (uint32_t i = 0; i < prefCount && isUnique; ++i)
+ {
+ if (!PL_strcasecmp(children[i], prefName)) /* are they the same branch? */
+ isUnique = false;
+ }
+ if (!isUnique) /* then try generating a new pref name and try again */
+ {
+ PR_smprintf_free(prefName);
+ prefName = PR_smprintf(PREF_LDAP_SERVER_TREE_NAME".%s_%d", leafName, ++uniqueIDCnt);
+ }
+ } /* if we have a list of pref Names */
+
+ NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, children);
+ } /* while we don't have a unique name */
+
+ // fallback to "user_directory_N" form if we failed to verify
+ if (!isUnique && prefName)
+ {
+ PR_smprintf_free(prefName);
+ prefName = nullptr;
+ }
+
+ PR_Free(leafName);
+
+ } /* if leafName */
+
+ if (!prefName) /* last resort if we still don't have a pref name is to use user_directory string */
+ return PR_smprintf(PREF_LDAP_SERVER_TREE_NAME".user_directory_%d", ++dir_UserId);
+ else
+ return prefName;
+}
+
+static void DIR_GetPrefsForOneServer(DIR_Server *server)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> pPref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return;
+
+ char *prefstring = server->prefName;
+
+ // this call fills in tempstring with the position pref, and
+ // we then check to see if it's locked.
+ server->position = DIR_GetIntPref (prefstring, "position", kDefaultPosition);
+
+ // For default address books, this will get the name from the chrome
+ // file referenced, for other address books it'll just retrieve it from prefs
+ // as normal.
+ server->description = DIR_GetLocalizedStringPref(prefstring, "description");
+
+ server->dirType = (DirectoryType)DIR_GetIntPref (prefstring, "dirType", LDAPDirectory);
+
+ server->fileName = DIR_GetStringPref (prefstring, "filename", "");
+ // if we don't have a file name try and get one
+ if (!server->fileName || !*(server->fileName))
+ DIR_SetServerFileName (server);
+ if (server->fileName && *server->fileName)
+ DIR_ConvertServerFileName(server);
+
+ // the string "s" is the default uri ( <scheme> + "://" + <filename> )
+ nsCString s((server->dirType == PABDirectory || server->dirType == MAPIDirectory) ?
+#if defined(MOZ_LDAP_XPCOM)
+ kMDBDirectoryRoot : kLDAPDirectoryRoot);
+#else
+ // Fallback to the all directory root in the non-ldap enabled case.
+ kMDBDirectoryRoot : kAllDirectoryRoot);
+#endif
+ s.Append (server->fileName);
+ server->uri = DIR_GetStringPref (prefstring, "uri", s.get ());
+}
+
+static nsresult dir_GetPrefs(nsTArray<DIR_Server*> **list)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> pPref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return rv;
+
+ (*list) = new nsTArray<DIR_Server*>();
+ if (!(*list))
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ char **children;
+ uint32_t prefCount;
+
+ rv = dir_GetChildList(NS_LITERAL_CSTRING(PREF_LDAP_SERVER_TREE_NAME "."),
+ &prefCount, &children);
+ if (NS_FAILED(rv))
+ return rv;
+
+ /* TBD: Temporary code to read broken "ldap" preferences tree.
+ * Remove line with if statement after M10.
+ */
+ if (dir_UserId == 0)
+ pPref->GetIntPref(PREF_LDAP_GLOBAL_TREE_NAME".user_id", &dir_UserId);
+
+ for (uint32_t i = 0; i < prefCount; ++i)
+ {
+ DIR_Server *server;
+
+ server = (DIR_Server *)PR_Calloc(1, sizeof(DIR_Server));
+ if (server)
+ {
+ DIR_InitServer(server);
+ server->prefName = strdup(children[i]);
+ DIR_GetPrefsForOneServer(server);
+ if (server->description && server->description[0] &&
+ ((server->dirType == PABDirectory ||
+ server->dirType == MAPIDirectory ||
+ server->dirType == FixedQueryLDAPDirectory || // this one might go away
+ server->dirType == LDAPDirectory)))
+ {
+ if (!dir_IsServerDeleted(server))
+ {
+ (*list)->AppendElement(server);
+ }
+ else
+ DIR_DeleteServer(server);
+ }
+ else
+ {
+ DIR_DeleteServer(server);
+ }
+ }
+ }
+
+ NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, children);
+
+ return NS_OK;
+}
+
+// I don't think we care about locked positions, etc.
+void DIR_SortServersByPosition(nsTArray<DIR_Server*> *serverList)
+{
+ int i, j;
+ DIR_Server *server;
+
+ int count = serverList->Length();
+ for (i = 0; i < count - 1; i++)
+ {
+ for (j = i + 1; j < count; j++)
+ {
+ if (serverList->ElementAt(j)->position < serverList->ElementAt(i)->position)
+ {
+ server = serverList->ElementAt(i);
+ serverList->ReplaceElementAt(i, serverList->ElementAt(j));
+ serverList->ReplaceElementAt(j, server);
+ }
+ }
+ }
+}
+
+static nsresult DIR_GetServerPreferences(nsTArray<DIR_Server*>** list)
+{
+ nsresult err;
+ nsCOMPtr<nsIPrefBranch> pPref(do_GetService(NS_PREFSERVICE_CONTRACTID, &err));
+ if (NS_FAILED(err))
+ return err;
+
+ int32_t version = -1;
+ nsTArray<DIR_Server*> *newList = nullptr;
+
+ /* Update the ldap list version and see if there are old prefs to migrate. */
+ err = pPref->GetIntPref(PREF_LDAP_VERSION_NAME, &version);
+ NS_ENSURE_SUCCESS(err, err);
+
+ /* Find the new-style "ldap_2.servers" tree in prefs */
+ err = dir_GetPrefs(&newList);
+
+ if (version < kCurrentListVersion)
+ {
+ pPref->SetIntPref(PREF_LDAP_VERSION_NAME, kCurrentListVersion);
+ }
+
+ DIR_SortServersByPosition(newList);
+
+ *list = newList;
+
+ return err;
+}
+
+static void DIR_SetStringPref(const char *prefRoot, const char *prefLeaf, const char *value, const char *defaultValue)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> pPref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return;
+
+ nsCString defaultPref;
+ nsAutoCString prefLocation(prefRoot);
+
+ prefLocation.Append('.');
+ prefLocation.Append(prefLeaf);
+
+ if (NS_SUCCEEDED(pPref->GetCharPref(prefLocation.get(), getter_Copies(defaultPref))))
+ {
+ /* If there's a default pref, just set ours in and let libpref worry
+ * about potential defaults in all.js
+ */
+ if (value) /* added this check to make sure we have a value before we try to set it..*/
+ rv = pPref->SetCharPref (prefLocation.get(), value);
+ else
+ rv = pPref->ClearUserPref(prefLocation.get());
+ }
+ else
+ {
+ /* If there's no default pref, look for a user pref, and only set our value in
+ * if the user pref is different than one of them.
+ */
+ nsCString userPref;
+ if (NS_SUCCEEDED(pPref->GetCharPref (prefLocation.get(), getter_Copies(userPref))))
+ {
+ if (value && (defaultValue ? PL_strcasecmp(value, defaultValue) : value != defaultValue))
+ rv = pPref->SetCharPref (prefLocation.get(), value);
+ else
+ rv = pPref->ClearUserPref(prefLocation.get());
+ }
+ else
+ {
+ if (value && (defaultValue ? PL_strcasecmp(value, defaultValue) : value != defaultValue))
+ rv = pPref->SetCharPref (prefLocation.get(), value);
+ }
+ }
+
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Could not set pref in DIR_SetStringPref");
+}
+
+static void DIR_SetLocalizedStringPref
+(const char *prefRoot, const char *prefLeaf, const char *value)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrefService> prefSvc(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+
+ if (NS_FAILED(rv))
+ return;
+
+ nsAutoCString prefLocation(prefRoot);
+ prefLocation.Append('.');
+
+ nsCOMPtr<nsIPrefBranch> prefBranch;
+ rv = prefSvc->GetBranch(prefLocation.get(), getter_AddRefs(prefBranch));
+ if (NS_FAILED(rv))
+ return;
+
+ nsString wvalue;
+ nsCOMPtr<nsIPrefLocalizedString> newStr(
+ do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ {
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Could not createInstance in DIR_SetLocalizedStringPref");
+ return;
+ }
+
+ NS_ConvertUTF8toUTF16 newValue(value);
+
+ rv = newStr->SetData(newValue.get());
+ if (NS_FAILED(rv))
+ {
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Could not set pref data in DIR_SetLocalizedStringPref");
+ return;
+ }
+ nsCOMPtr<nsIPrefLocalizedString> locStr;
+ if (NS_SUCCEEDED(prefBranch->GetComplexValue(prefLeaf,
+ NS_GET_IID(nsIPrefLocalizedString),
+ getter_AddRefs(locStr))))
+ {
+ nsString data;
+ locStr->GetData(getter_Copies(data));
+
+ // Only set the pref if the data values aren't the same (i.e. don't change
+ // unnecessarily, but also, don't change in the case that its a chrome
+ // string pointing to the value we want to set the pref to).
+ if (newValue != data)
+ rv = prefBranch->SetComplexValue(prefLeaf,
+ NS_GET_IID(nsIPrefLocalizedString),
+ newStr);
+ }
+ else {
+ // No value set, but check the default pref branch (i.e. user may have
+ // cleared the pref)
+ nsCOMPtr<nsIPrefBranch> dPB;
+ rv = prefSvc->GetDefaultBranch(prefLocation.get(),
+ getter_AddRefs(dPB));
+
+ if (NS_SUCCEEDED(dPB->GetComplexValue(prefLeaf,
+ NS_GET_IID(nsIPrefLocalizedString),
+ getter_AddRefs(locStr))))
+ {
+ // Default branch has a value
+ nsString data;
+ locStr->GetData(getter_Copies(data));
+
+ if (newValue != data)
+ // If the vales aren't the same, set the data on the main pref branch
+ rv = prefBranch->SetComplexValue(prefLeaf,
+ NS_GET_IID(nsIPrefLocalizedString),
+ newStr);
+ else
+ // Else if they are, kill the user pref
+ rv = prefBranch->ClearUserPref(prefLeaf);
+ }
+ else
+ // No values set anywhere, so just set the pref
+ rv = prefBranch->SetComplexValue(prefLeaf,
+ NS_GET_IID(nsIPrefLocalizedString),
+ newStr);
+ }
+
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Could not set pref in DIR_SetLocalizedStringPref");
+}
+
+
+static void DIR_SetIntPref(const char *prefRoot, const char *prefLeaf, int32_t value, int32_t defaultValue)
+{
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> pPref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv))
+ return;
+
+ int32_t defaultPref;
+ nsAutoCString prefLocation(prefRoot);
+
+ prefLocation.Append('.');
+ prefLocation.Append(prefLeaf);
+
+ if (NS_SUCCEEDED(pPref->GetIntPref(prefLocation.get(), &defaultPref)))
+ {
+ /* solve the problem where reordering user prefs must override default prefs */
+ rv = pPref->SetIntPref(prefLocation.get(), value);
+ }
+ else
+ {
+ int32_t userPref;
+ if (NS_SUCCEEDED(pPref->GetIntPref(prefLocation.get(), &userPref)))
+ {
+ if (value != defaultValue)
+ rv = pPref->SetIntPref(prefLocation.get(), value);
+ else
+ rv = pPref->ClearUserPref(prefLocation.get());
+ }
+ else
+ {
+ if (value != defaultValue)
+ rv = pPref->SetIntPref(prefLocation.get(), value);
+ }
+ }
+
+ NS_ASSERTION(NS_SUCCEEDED(rv), "Could not set pref in DIR_SetIntPref");
+}
+
+void DIR_SavePrefsForOneServer(DIR_Server *server)
+{
+ if (!server)
+ return;
+
+ char *prefstring;
+
+ if (server->prefName == nullptr)
+ server->prefName = dir_CreateServerPrefName(server);
+ prefstring = server->prefName;
+
+ server->savingServer = true;
+
+ DIR_SetIntPref (prefstring, "position", server->position, kDefaultPosition);
+
+ // Only save the non-default address book name
+ DIR_SetLocalizedStringPref(prefstring, "description", server->description);
+
+ DIR_SetStringPref(prefstring, "filename", server->fileName, "");
+ DIR_SetIntPref(prefstring, "dirType", server->dirType, LDAPDirectory);
+
+ if (server->dirType != PABDirectory)
+ DIR_SetStringPref(prefstring, "uri", server->uri, "");
+
+ server->savingServer = false;
+}
+
+static void DIR_SaveServerPreferences(nsTArray<DIR_Server*> *wholeList)
+{
+ if (wholeList)
+ {
+ nsresult rv;
+ nsCOMPtr<nsIPrefBranch> pPref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+ if (NS_FAILED(rv)) {
+ NS_WARNING("DIR_SaveServerPreferences: Failed to get the pref service\n");
+ return;
+ }
+
+ int32_t i;
+ int32_t count = wholeList->Length();
+ DIR_Server *server;
+
+ for (i = 0; i < count; i++)
+ {
+ server = wholeList->ElementAt(i);
+ if (server)
+ DIR_SavePrefsForOneServer(server);
+ }
+ pPref->SetIntPref(PREF_LDAP_GLOBAL_TREE_NAME".user_id", dir_UserId);
+ }
+}