Back to index

lightning-sunbird  0.9+nobinonly
nsDirPrefs.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Seth Spitzer <sspitzer@netscape.com>
00024  *   Dan Mosedale <dmose@mozilla.org>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 /* directory server preferences (used to be dirprefs.c in 4.x) */
00041 
00042 #include "nsIPref.h"
00043 #include "nsVoidArray.h"
00044 #include "nsIServiceManager.h"
00045 #include "nsDirPrefs.h"
00046 #include "nsIAddrDatabase.h"
00047 #include "nsCOMPtr.h"
00048 #include "nsAbBaseCID.h"
00049 #include "nsIAddrBookSession.h"
00050 #include "nsICharsetConverterManager.h"
00051 #include "nsIAbUpgrader.h"
00052 #include "nsXPIDLString.h"
00053 #include "nsReadableUtils.h"
00054 
00055 #include "prlog.h"
00056 #include "plstr.h"
00057 #include "prmem.h"
00058 #include "prprf.h"
00059 
00060 #define LDAP_PORT 389
00061 #define LDAPS_PORT 636
00062 #define PREF_NOERROR 0
00063 
00064 #if !defined(MOZADDRSTANDALONE)
00065 
00066 typedef enum
00067 {
00068        MK_ADDR_PAB,
00069        MK_LDAP_COMMON_NAME,
00070        MK_LDAP_GIVEN_NAME,
00071        MK_LDAP_SURNAME,
00072        MK_LDAP_EMAIL_ADDRESS,
00073        MK_LDAP_PHONE_NUMBER,
00074        MK_LDAP_ORGANIZATION, 
00075        MK_LDAP_ORG_UNIT, 
00076        MK_LDAP_LOCALITY,
00077        MK_LDAP_STREET,
00078        MK_LDAP_CUSTOM1, 
00079        MK_LDAP_CUSTOM2,
00080        MK_LDAP_CUSTOM3, 
00081        MK_LDAP_CUSTOM4,
00082        MK_LDAP_CUSTOM5,
00083        MK_LDAP_DESCRIPTION,   
00084        MK_LDAP_EMPLOYEE_TYPE, 
00085        MK_LDAP_FAX_NUMBER,    
00086        MK_LDAP_MANAGER,       
00087        MK_LDAP_OBJECT_CLASS,       
00088        MK_LDAP_POSTAL_ADDRESS,
00089        MK_LDAP_POSTAL_CODE,   
00090        MK_LDAP_SECRETARY,
00091        MK_LDAP_TITLE,
00092        MK_LDAP_CAR_LICENSE,
00093        MK_LDAP_BUSINESS_CAT,
00094        MK_LDAP_DEPT_NUMBER,
00095        MK_LDAP_REPL_QUERY_RESYNC,
00096        MK_LDAP_NICK_NAME,
00097        MK_LDAP_HOMEPHONE,
00098        MK_LDAP_MOBILEPHONE,
00099        MK_LDAP_PAGER
00100 } DIR_ResourceID;
00101 
00102 #else
00103 
00104 #define NS_ERROR_OUT_OF_MEMORY -1;
00105 
00106 #endif /* #if !defined(MOZADDRSTANDALONE) */
00107 
00108 #define XP_FILE_URL_PATH char *
00109 #define XP_FILE_NATIVE_PATH char *
00110 
00111 XP_FILE_URL_PATH     XP_PlatformFileToURL (const XP_FILE_NATIVE_PATH ) {return NULL;}
00112 
00113 /*****************************************************************************
00114  * Private structs and stuff
00115  */
00116 
00117 /* DIR_Server.customAttributes is a list of DIR_Attribute structures */
00118 typedef struct DIR_Attribute
00119 {
00120        DIR_AttributeId id;
00121        char *prettyName;
00122        char **attrNames;
00123 } DIR_Attribute;
00124 
00125 /* Our internal view of a default attribute is a resourceId for the pretty
00126  * name and the real attribute name. These are catenated to create a string
00127  * of the form "Pretty Name:attrname"
00128  */
00129 typedef struct DIR_DefaultAttribute
00130 {
00131        DIR_AttributeId id;
00132        PRInt32 resourceId;
00133        const char *name;
00134 } DIR_DefaultAttribute;
00135 
00136 /* DIR_Filter.flags */
00137 #define DIR_F_SUBST_STARS_FOR_SPACES   0x00000001
00138 #define DIR_F_REPEAT_FILTER_FOR_TOKENS 0x00000002
00139 
00140 /* DIR_Server.filters is a list of DIR_Filter structures */
00141 typedef struct DIR_Filter
00142 {
00143        char *string;
00144        PRUint32 flags;
00145 } DIR_Filter;
00146 
00147 /* Callback list structure */
00148 typedef struct DIR_Callback
00149 {
00150        DIR_NOTIFICATION_FN  fn;
00151        PRUint32               flags;
00152        void                *data;
00153        struct DIR_Callback *next;
00154 } DIR_Callback;
00155 
00156 /* Codeset type */
00157 #define SINGLEBYTE   0x0000 /* 0000 0000 0000 0000 =    0 */
00158 #define MULTIBYTE    0x0100 /* 0000 0001 0000 0000 =  256 */
00159 
00160 /* Code Set IDs */
00161 /* CS_DEFAULT: used if no charset param in header */
00162 /* CS_UNKNOWN: used for unrecognized charset */
00163 
00164                     /* type                  id   */
00165 #define CS_DEFAULT    (SINGLEBYTE         |   0) /*    0 */
00166 #define CS_UTF8       (MULTIBYTE          |  34) /*  290 */
00167 #define CS_UNKNOWN    (SINGLEBYTE         | 255) /* 255 */
00168 
00169 /* Default settings for site-configurable prefs */
00170 #define kDefaultTokenSeps " ,."
00171 #define kDefaultSubstStarsForSpaces PR_TRUE
00172 #define kDefaultRepeatFilterForTokens PR_TRUE
00173 #define kDefaultEfficientWildcards PR_TRUE
00174 #define kDefaultFilter "(cn=*%s*)"
00175 #define kDefaultEfficientFilter "(|(givenname=%s)(sn=%s))"
00176 #define kDefaultStopOnHit PR_TRUE
00177 #define kDefaultMaxHits 100
00178 #define kDefaultIsOffline PR_TRUE
00179 #define kDefaultEnableAuth PR_FALSE
00180 #define kDefaultSavePassword PR_FALSE
00181 #define kDefaultLDAPCSID CS_UTF8 
00182 #define kDefaultPABCSID  CS_DEFAULT
00183 #define kDefaultVLVDisabled PR_FALSE
00184 #define kDefaultPosition 1
00185 
00186 #define kDefaultAutoCompleteEnabled PR_FALSE
00187 #define kDefaultAutoCompleteNever   PR_FALSE
00188 
00189 #define kDefaultReplicateNever PR_FALSE
00190 #define kDefaultReplicaEnabled PR_FALSE
00191 #define kDefaultReplicaFileName nsnull
00192 #define kDefaultReplicaDataVersion nsnull
00193 #define kDefaultReplicaDescription nsnull
00194 #define kDefaultReplicaChangeNumber -1
00195 #define kDefaultReplicaFilter "(objectclass=*)"
00196 #define kDefaultReplicaExcludedAttributes nsnull
00197 
00198 #define kDefaultPABColumnHeaders "cn,mail,o,nickname,telephonenumber,l"  /* default column headers for the address book window */
00199 #define kDefaultLDAPColumnHeaders "cn,mail,o,telephonenumber,l,nickname"
00200 
00201 static PRBool dir_IsServerDeleted(DIR_Server * server);
00202 static DIR_DefaultAttribute *DIR_GetDefaultAttribute (DIR_AttributeId id);
00203 static char *DIR_GetStringPref(const char *prefRoot, const char *prefLeaf, char *scratch, const char *defaultValue);
00204 static char *DIR_GetLocalizedStringPref(const char *prefRoot, const char *prefLeaf, char *scratch, const char *defaultValue);
00205 static PRInt32 DIR_GetIntPref(const char *prefRoot, const char *prefLeaf, char *scratch, PRInt32 defaultValue);
00206 static PRBool DIR_GetBoolPref(const char *prefRoot, const char *prefLeaf, char *scratch, PRBool defaultValue);
00207 static char * dir_ConvertDescriptionToPrefName(DIR_Server * server);
00208 void DIR_SetFileName(char** filename, const char* leafName);
00209 static void DIR_SetIntPref (const char *prefRoot, const char *prefLeaf, char *scratch, PRInt32 value, PRInt32 defaultValue);
00210 
00211 static PRInt32 PR_CALLBACK dir_ServerPrefCallback(const char *pref, void *inst_data);
00212 
00213 /*****************************************************************************
00214  * Functions for creating the new back end managed DIR_Server list.
00215  */
00216 
00217 static PRBool       dir_ServerPrefCallbackRegistered = PR_FALSE;
00218 static PRInt32      dir_UserId = 0;
00219 static DIR_Callback *dir_CallbackList = nsnull;
00220 
00221 nsVoidArray  *dir_ServerList = nsnull;
00222 
00223 nsVoidArray* DIR_GetDirectories()
00224 {
00225     if (!dir_ServerList)
00226         DIR_GetDirServers();
00227        return dir_ServerList;
00228 }
00229 
00230 nsresult DIR_GetDirServers()
00231 {
00232   nsresult rv = NS_OK;
00233   
00234   if (!dir_ServerList)
00235   {
00236     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
00237     if (NS_FAILED(rv) || !pPref) 
00238               return NS_ERROR_FAILURE;
00239     
00240     /* we need to build the DIR_Server list */ 
00241     rv = DIR_GetServerPreferences(&dir_ServerList);
00242     
00243     /* Register the preference call back if necessary. */
00244     if (NS_SUCCEEDED(rv) && (!dir_ServerPrefCallbackRegistered))
00245     {
00246       dir_ServerPrefCallbackRegistered = PR_TRUE;
00247       pPref->RegisterCallback(PREF_LDAP_SERVER_TREE_NAME, dir_ServerPrefCallback, nsnull);
00248     }
00249   }
00250   return rv;
00251 }
00252 
00253 static nsresult dir_ConvertToMabFileName()
00254 {
00255   if (dir_ServerList)
00256   {
00257     PRInt32 count = dir_ServerList->Count();
00258     PRInt32 i;
00259     for (i = 0; i < count; i++)
00260     {
00261       DIR_Server *server = (DIR_Server *)dir_ServerList->ElementAt(i);
00262       
00263       // convert for main personal addressbook only
00264       // do other address book when convert from 4.5 to mork is done
00265       if (server && server->position == 1 && server->fileName)
00266       {
00267         // determine if server->fileName ends with ".na2"
00268         PRUint32 fileNameLen = strlen(server->fileName);
00269         if ((fileNameLen > kABFileName_PreviousSuffixLen) && 
00270           strcmp(server->fileName + fileNameLen - kABFileName_PreviousSuffixLen, kABFileName_PreviousSuffix) == 0)
00271         {
00272           //Move old abook.na2 to end of the list and change the description
00273           DIR_Server * newServer = nsnull;
00274           DIR_CopyServer(server, &newServer);
00275           newServer->position = count + 1;
00276           char *newDescription = PR_smprintf("%s 4.x", newServer->description);
00277           PR_FREEIF(newServer->description);
00278           newServer->description = newDescription;
00279           char *newPrefName = PR_smprintf("%s4x", newServer->prefName);
00280           PR_FREEIF(newServer->prefName);
00281           newServer->prefName = newPrefName;
00282           dir_ServerList->AppendElement(newServer);
00283           DIR_SavePrefsForOneServer(newServer);
00284           
00285           PR_FREEIF (server->fileName);
00286           server->fileName = nsCRT::strdup(kPersonalAddressbook);
00287           DIR_SavePrefsForOneServer(server);
00288         }
00289       }
00290     }
00291   }
00292   return NS_OK;
00293 }
00294 
00295 nsresult DIR_ShutDown()  /* FEs should call this when the app is shutting down. It frees all DIR_Servers regardless of ref count values! */
00296 {
00297   nsresult rv = NS_OK;
00298   nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
00299   if (NS_FAILED(rv) || !pPref) 
00300     return NS_ERROR_FAILURE;
00301   pPref->SavePrefFile(nsnull);
00302   
00303   if (dir_ServerList)
00304   {
00305     PRInt32 count = dir_ServerList->Count();
00306     PRInt32 i;
00307     for (i = 0; i < count; i++)
00308     {
00309       DIR_DeleteServer((DIR_Server *)(dir_ServerList->ElementAt(i)));
00310     }
00311     delete dir_ServerList;
00312     dir_ServerList = nsnull;
00313   }
00314   
00315   /* unregister the preference call back, if necessary.
00316   * we need to do this as DIR_Shutdown() is called when switching profiles
00317   * when using turbo.  (see nsAbDirectoryDataSource::Observe())
00318   * When switching profiles, prefs get unloaded and then re-loaded
00319   * we don't want our callback to get called for all that.
00320   * We'll reset our callback the first time DIR_GetDirServers() is called
00321   * after we've switched profiles.
00322   */
00323   if (dir_ServerPrefCallbackRegistered) {
00324     pPref->UnregisterCallback(PREF_LDAP_SERVER_TREE_NAME, dir_ServerPrefCallback, nsnull);
00325     dir_ServerPrefCallbackRegistered = PR_FALSE;
00326   }
00327   
00328   return NS_OK;
00329 }
00330 
00331 nsresult DIR_ContainsServer(DIR_Server* pServer, PRBool *hasDir)
00332 {
00333   if (dir_ServerList)
00334   {
00335     PRInt32 count = dir_ServerList->Count();
00336     PRInt32 i;
00337     for (i = 0; i < count; i++)
00338     {
00339       DIR_Server* server = (DIR_Server *)(dir_ServerList->ElementAt(i));
00340       if (server == pServer)
00341       {
00342         *hasDir = PR_TRUE;
00343         return NS_OK;
00344       }
00345     }
00346   }
00347   *hasDir = PR_FALSE;
00348   return NS_OK;
00349 }
00350 
00351 nsresult DIR_AddNewAddressBook(const PRUnichar *dirName, const char *fileName, PRBool migrating, const char * uri, int maxHits, const char * authDn, DirectoryType dirType, DIR_Server** pServer)
00352 {
00353   DIR_Server * server = (DIR_Server *) PR_Malloc(sizeof(DIR_Server));
00354   DIR_InitServerWithType (server, dirType);
00355   if (!dir_ServerList)
00356     DIR_GetDirServers();
00357   if (dir_ServerList)
00358   {
00359     NS_ConvertUCS2toUTF8 utf8str(dirName);
00360     server->description = ToNewCString(utf8str);
00361     server->position = kDefaultPosition; // don't set position so alphabetic sort will happen.
00362     
00363     if (fileName)
00364       server->fileName = nsCRT::strdup(fileName);
00365     else
00366       DIR_SetFileName(&server->fileName, kPersonalAddressbook);
00367     if (dirType == LDAPDirectory) {
00368       // We don't actually allow the password to be saved in the preferences;
00369       // this preference is (effectively) ignored by the current code base.  
00370       // It's here because versions of Mozilla 1.0 and earlier (maybe 1.1alpha
00371       // too?) would blow away the .auth.dn preference if .auth.savePassword
00372       // is not set.  To avoid trashing things for users who switch between
00373       // versions, we'll set it.  Once the versions in question become 
00374       // obsolete enough, this workaround can be gotten rid of.
00375       server->savePassword = PR_TRUE;
00376       if (uri)
00377         server->uri = nsCRT::strdup(uri);
00378       if (authDn)
00379         server->authDn = nsCRT::strdup(authDn);
00380       // force new LDAP directories to be treated as v3 this includes the case when 
00381       // we are migrating directories.
00382       DIR_ForceFlag(server, DIR_LDAP_VERSION3, PR_TRUE);
00383     }
00384     if (maxHits)
00385       server->maxHits = maxHits;
00386     
00387     dir_ServerList->AppendElement(server);
00388     if (!migrating) {
00389       DIR_SavePrefsForOneServer(server); 
00390     }
00391     else if (!server->prefName)
00392     {
00393       // Need to return pref names here so the caller will be able to get the
00394       // right directory properties. For migration, pref names were already
00395       // created so no need to get unique ones via DIR_CreateServerPrefName().
00396       if (!strcmp(server->fileName, kPersonalAddressbook))
00397         server->prefName = nsCRT::strdup("ldap_2.servers.pab");
00398       else if (!strcmp(server->fileName, kCollectedAddressbook))
00399         server->prefName = nsCRT::strdup("ldap_2.servers.history");
00400       else
00401       {
00402         char * leafName = dir_ConvertDescriptionToPrefName (server);
00403         if (leafName)
00404           server->prefName = PR_smprintf(PREF_LDAP_SERVER_TREE_NAME".%s", leafName);
00405       }
00406     }
00407 #ifdef DEBUG_sspitzer
00408     else {
00409       printf("don't set the prefs, they are already set since this ab was migrated\n");
00410     }
00411 #endif
00412     *pServer = server;
00413     
00414     // save new address book into pref file 
00415     nsresult rv = NS_OK;
00416     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
00417     if (NS_FAILED(rv) || !pPref) 
00418       return NS_ERROR_FAILURE;
00419     pPref->SavePrefFile(nsnull);
00420     
00421     return NS_OK;
00422   }
00423   return NS_ERROR_FAILURE;
00424 }
00425 
00426 nsresult DIR_DecrementServerRefCount (DIR_Server *server)
00427 {
00428   NS_ASSERTION((server != nsnull), "server is null");
00429        if (server && --server->refCount <= 0)
00430           return DIR_DeleteServer(server);
00431         else
00432           return 1;
00433 }
00434 
00435 nsresult DIR_IncrementServerRefCount (DIR_Server *server)
00436 {
00437   NS_ASSERTION((server != nsnull), "server is null");
00438   if (server)
00439     server->refCount++;
00440   return NS_OK;
00441 }
00442 
00443 /*****************************************************************************
00444  * Functions for creating DIR_Servers
00445  */
00446 
00447 /* use this when you want to create a server of a particular type */
00448 nsresult DIR_InitServerWithType(DIR_Server * server, DirectoryType dirType)
00449 {
00450   DIR_InitServer(server);
00451   server->dirType = dirType;
00452   if (dirType == LDAPDirectory)
00453   {
00454     server->columnAttributes = nsCRT::strdup(kDefaultLDAPColumnHeaders);
00455     server->isOffline = PR_TRUE;
00456     server->csid = CS_UTF8;
00457     server->locale = nsnull;
00458   }
00459   else if (dirType == PABDirectory || dirType == MAPIDirectory)
00460   {
00461     server->columnAttributes = nsCRT::strdup(kDefaultPABColumnHeaders);
00462     server->isOffline = PR_FALSE;
00463     server->csid = CS_UTF8;
00464     //        server->csid = INTL_GetCharSetID(INTL_DefaultTextWidgetCsidSel);
00465     server->locale = nsnull; /* get the locale we are going to use with this AB */
00466     /*        server->locale = INTL_GetCollationKeyLocale(nsnull); */
00467   }
00468   return NS_OK;
00469 }
00470 
00471 nsresult DIR_InitServer (DIR_Server *server)
00472 {
00473   NS_ASSERTION((server != nsnull), "server is null");
00474   if (server)
00475   {
00476     memset(server, 0, sizeof(DIR_Server));
00477     server->saveResults = PR_TRUE;
00478     server->efficientWildcards = kDefaultEfficientWildcards;
00479     server->port = LDAP_PORT;
00480     server->maxHits = kDefaultMaxHits;
00481     server->isOffline = kDefaultIsOffline;
00482     server->refCount = 1;
00483     server->position = kDefaultPosition;
00484     server->csid = CS_UTF8;
00485     server->locale = nsnull;
00486     server->uri = nsnull;
00487     // initialize the palm category
00488     server->PalmCategoryId = -1;
00489   }
00490   return NS_OK;
00491 }
00492 
00493 DIR_DescriptionCode DIR_ValidateDirectoryDescription(nsVoidArray * wholeList, DIR_Server * serverToValidate)
00494 {
00495   /* right now the only invalid description is a duplicate...so check for duplicates */
00496   if (wholeList && serverToValidate && serverToValidate->description)
00497   {
00498     PRInt32 numItems = wholeList->Count();
00499     PRInt32 i;
00500     for (i = 0; i < numItems; i++)
00501     {
00502       DIR_Server *s = (DIR_Server *)(dir_ServerList->ElementAt(i));
00503       /* don't check the description if it is the same directory as the one we are comparing against */
00504       if (s != serverToValidate && s->description && !nsCRT::strcasecmp(s->description, serverToValidate->description))
00505         return DIR_DuplicateDescription;
00506     }
00507     
00508   }
00509   
00510   return DIR_ValidDescription;
00511 }
00512 
00513 
00514 /*****************************************************************************
00515  * Functions for cloning DIR_Servers
00516  */
00517 
00518 static DIR_Attribute *DIR_CopyAttribute (DIR_Attribute *inAttribute)
00519 {
00520        DIR_Attribute *outAttribute = (DIR_Attribute*) PR_Malloc(sizeof(DIR_Attribute));
00521        if (outAttribute)
00522        {
00523               PRInt32 count = 0;
00524               outAttribute->id = inAttribute->id;
00525         outAttribute->prettyName = nsCRT::strdup(inAttribute->prettyName);
00526               while (inAttribute->attrNames[count])
00527                      count++;
00528               outAttribute->attrNames = (char**) PR_Malloc((count + 1) * sizeof(char*));
00529               if (outAttribute->attrNames)
00530               {
00531                      PRInt32 i;
00532                      for (i = 0; i < count; i++)
00533                 outAttribute->attrNames[i] = nsCRT::strdup(inAttribute->attrNames[i]);
00534                      outAttribute->attrNames[i] = nsnull;
00535               }
00536        }
00537        return outAttribute;
00538 }
00539 
00540 
00541 static DIR_Filter *DIR_CopyFilter (DIR_Filter *inFilter)
00542 {
00543        DIR_Filter *outFilter = (DIR_Filter*) PR_Malloc(sizeof(DIR_Filter));
00544        if (outFilter)
00545        {
00546               outFilter->flags = inFilter->flags;
00547         outFilter->string = nsCRT::strdup(inFilter->string);
00548        }
00549        return outFilter;
00550 }
00551 
00552 
00553 static nsresult dir_CopyTokenList (char **inList, PRInt32 inCount, char ***outList, PRInt32 *outCount)
00554 {
00555        nsresult status = NS_OK;
00556        if (0 != inCount && nsnull != inList)
00557        {
00558               *outList = (char**) PR_Malloc(inCount * sizeof(char*));
00559               if (*outList)
00560               {
00561                      PRInt32 i;
00562                      for (i = 0; i < inCount; i++)
00563                 (*outList)[i] = nsCRT::strdup (inList[i]);
00564                      *outCount = inCount;
00565               }
00566               else
00567                      status = NS_ERROR_OUT_OF_MEMORY;
00568        }
00569        return status;
00570 }
00571 
00572 
00573 static DIR_ReplicationInfo *dir_CopyReplicationInfo (DIR_ReplicationInfo *inInfo)
00574 {
00575        DIR_ReplicationInfo *outInfo = (DIR_ReplicationInfo*) PR_Calloc (1, sizeof(DIR_ReplicationInfo));
00576        if (outInfo)
00577        {
00578               outInfo->lastChangeNumber = inInfo->lastChangeNumber;
00579               if (inInfo->description)
00580             outInfo->description = nsCRT::strdup (inInfo->description);
00581               if (inInfo->fileName)
00582             outInfo->fileName = nsCRT::strdup (inInfo->fileName);
00583               if (inInfo->dataVersion)
00584             outInfo->dataVersion = nsCRT::strdup (inInfo->dataVersion);
00585               if (inInfo->syncURL)
00586             outInfo->syncURL = nsCRT::strdup (inInfo->syncURL);
00587               if (inInfo->filter)
00588             outInfo->filter = nsCRT::strdup (inInfo->filter);
00589               dir_CopyTokenList (inInfo->excludedAttributes, inInfo->excludedAttributesCount,
00590                      &outInfo->excludedAttributes, &outInfo->excludedAttributesCount);
00591        }
00592        return outInfo;
00593 }
00594 
00595 nsresult DIR_CopyServer (DIR_Server *in, DIR_Server **out)
00596 {
00597        nsresult err = NS_OK;
00598        if (in) {
00599               *out = (DIR_Server*)PR_Malloc(sizeof(DIR_Server));
00600               if (*out)
00601               {
00602                      memset(*out, 0, sizeof(DIR_Server));
00603 
00604                      if (in->prefName)
00605                      {
00606                 (*out)->prefName = nsCRT::strdup(in->prefName);
00607                             if (!(*out)->prefName)
00608                                    err = NS_ERROR_OUT_OF_MEMORY;
00609                      }
00610 
00611                      if (in->description)
00612                      {
00613                 (*out)->description = nsCRT::strdup(in->description);
00614                             if (!(*out)->description)
00615                                    err = NS_ERROR_OUT_OF_MEMORY;
00616                      }
00617 
00618                      if (in->serverName)
00619                      {
00620                 (*out)->serverName = nsCRT::strdup(in->serverName);
00621                             if (!(*out)->serverName)
00622                                    err = NS_ERROR_OUT_OF_MEMORY;
00623                      }
00624 
00625                      if (in->searchBase)
00626                      {
00627                 (*out)->searchBase = nsCRT::strdup(in->searchBase);
00628                             if (!(*out)->searchBase)
00629                                    err = NS_ERROR_OUT_OF_MEMORY;
00630                      }
00631 
00632                      if (in->fileName)
00633                      {
00634                 (*out)->fileName = nsCRT::strdup(in->fileName);
00635                             if (!(*out)->fileName)
00636                                    err = NS_ERROR_OUT_OF_MEMORY;
00637                      }
00638 
00639                      if (in->columnAttributes)
00640                      {
00641                 (*out)->columnAttributes = nsCRT::strdup(in->columnAttributes);
00642                             if (!(*out)->columnAttributes)
00643                                    err = NS_ERROR_OUT_OF_MEMORY;
00644                      }
00645 
00646                      if (in->locale)
00647                      {
00648                 (*out)->locale = nsCRT::strdup(in->locale);
00649                             if (!(*out)->locale)
00650                                    err = NS_ERROR_OUT_OF_MEMORY;
00651                      }
00652 
00653                      (*out)->position = in->position;
00654                      (*out)->port = in->port;
00655                      (*out)->maxHits = in->maxHits;
00656                      (*out)->isSecure = in->isSecure;
00657                      (*out)->saveResults = in->saveResults;
00658                      (*out)->isOffline = in->isOffline;
00659                      (*out)->efficientWildcards = in->efficientWildcards;
00660                      (*out)->dirType = in->dirType;
00661                      (*out)->csid = in->csid;
00662 
00663                      (*out)->flags = in->flags;
00664                      
00665                      (*out)->enableAuth = in->enableAuth;
00666                      (*out)->savePassword = in->savePassword;
00667                      if (in->authDn)
00668                      {
00669                 (*out)->authDn = nsCRT::strdup (in->authDn);
00670                             if (!(*out)->authDn)
00671                                    err = NS_ERROR_OUT_OF_MEMORY;
00672                      }
00673                      if (in->password)
00674                      {
00675                 (*out)->password = nsCRT::strdup (in->password);
00676                             if (!(*out)->password)
00677                                    err = NS_ERROR_OUT_OF_MEMORY;
00678                      }
00679 
00680                      if (in->customAttributes)
00681                      {
00682                             (*out)->customAttributes = new nsVoidArray();
00683                             if ((*out)->customAttributes)
00684                             {
00685                                    nsVoidArray *list = in->customAttributes;
00686                                    DIR_Attribute *attribute = nsnull;
00687                                    PRInt32 count = list->Count();
00688                                    PRInt32 i;
00689                                    for (i = 0; i < count; i++)
00690                                    {
00691                                           attribute = (DIR_Attribute *)list->ElementAt(i);
00692                                           if (attribute)
00693                                           {
00694                                                  DIR_Attribute *outAttr = DIR_CopyAttribute (attribute);
00695                                                  if (outAttr)
00696                                                         ((*out)->customAttributes)->AppendElement(outAttr);
00697                                                  else
00698                                                         err = NS_ERROR_OUT_OF_MEMORY;
00699                                           }
00700                                    }
00701                             }
00702                             else
00703                                    err = NS_ERROR_OUT_OF_MEMORY;
00704                      }
00705 
00706                      if (in->customFilters)
00707                      {
00708                             (*out)->customFilters = new nsVoidArray();
00709                             if ((*out)->customFilters)
00710                             {
00711                                    nsVoidArray *list = in->customFilters;
00712                                    DIR_Filter *filter = nsnull;
00713 
00714                                    PRInt32 count = list->Count();
00715                                    PRInt32 i;
00716                                    for (i = 0; i < count; i++)
00717                                    {
00718                                           filter = (DIR_Filter *)list->ElementAt(i);
00719                                           if (filter)
00720                                           {
00721                                                  DIR_Filter *outFilter = DIR_CopyFilter (filter);
00722                                                  if (outFilter)
00723                                                         ((*out)->customFilters)->AppendElement(outFilter);
00724                                                  else
00725                                                         err = NS_ERROR_OUT_OF_MEMORY;
00726                                           }
00727                                    }
00728                             }
00729                             else
00730                                    err = NS_ERROR_OUT_OF_MEMORY;
00731                      }
00732 
00733                      if (in->autoCompleteFilter)
00734                      {
00735                 (*out)->autoCompleteFilter = nsCRT::strdup(in->autoCompleteFilter);
00736                             if (!(*out)->autoCompleteFilter)
00737                                    err = NS_ERROR_OUT_OF_MEMORY;
00738                      }
00739 
00740                      if (in->replInfo)
00741                             (*out)->replInfo = dir_CopyReplicationInfo (in->replInfo);
00742 
00743                      if (in->basicSearchAttributesCount > 0)
00744                      {
00745                             PRInt32 bsaLength = in->basicSearchAttributesCount * sizeof(DIR_AttributeId);
00746                             (*out)->basicSearchAttributes = (DIR_AttributeId*) PR_Malloc(bsaLength);
00747                             if ((*out)->basicSearchAttributes)
00748                             {
00749                                    memcpy((*out)->basicSearchAttributes, in->basicSearchAttributes, bsaLength);
00750                                    (*out)->basicSearchAttributesCount = in->basicSearchAttributesCount;
00751                             }
00752                      }
00753 
00754                      dir_CopyTokenList (in->dnAttributes, in->dnAttributesCount,
00755                             &(*out)->dnAttributes, &(*out)->dnAttributesCount);
00756                      dir_CopyTokenList (in->suppressedAttributes, in->suppressedAttributesCount,
00757                             &(*out)->suppressedAttributes, &(*out)->suppressedAttributesCount);
00758                      dir_CopyTokenList (in->uriAttributes, in->uriAttributesCount,
00759                             &(*out)->uriAttributes, &(*out)->uriAttributesCount);
00760 
00761                      if (in->customDisplayUrl)
00762                 (*out)->customDisplayUrl = nsCRT::strdup (in->customDisplayUrl);
00763                      if (in->searchPairList)
00764                 (*out)->searchPairList = nsCRT::strdup (in->searchPairList);
00765 
00766                      (*out)->refCount = 1;
00767               }
00768               else {
00769                      err = NS_ERROR_OUT_OF_MEMORY;
00770                      (*out) = nsnull;
00771               }
00772        }
00773        else {
00774               PR_ASSERT (0);
00775               err = NS_ERROR_FAILURE;
00776               (*out) = nsnull;
00777        }
00778 
00779        return err;
00780 }
00781 
00782 
00783 /* Function for setting the position of a server.  Can be used to append,
00784  * delete, or move a server in a server list.
00785  *
00786  * The third parameter specifies the new position the server is to occupy.
00787  * The resulting position may differ depending on the lock state of the
00788  * given server and other servers in the list.  The following special values
00789  * are supported:
00790  *   DIR_POS_APPEND - Appends the server to the end of the list.  If the server
00791  *                    is already in the list, does nothing.
00792  *   DIR_POS_DELETE - Deletes the given server from the list.  Note that this
00793  *                    does not cause the server structure to be freed.
00794  *
00795  * Returns PR_TRUE if the server list was re-sorted.
00796  */
00797  PRBool DIR_SetServerPosition(nsVoidArray *wholeList, DIR_Server *server, PRInt32 position)
00798  {
00799    nsresult rv = NS_OK;
00800    nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
00801    if (NS_FAILED(rv) || !pPref) 
00802      return PR_FALSE;
00803    
00804    PRInt32    i, count, num;
00805    PRBool     resort = PR_FALSE;
00806    DIR_Server *s=nsnull;
00807    
00808    switch (position) {
00809    case DIR_POS_APPEND:
00810    /* Do nothing if the request is to append a server that is already
00811                * in the list.
00812      */
00813      count = wholeList->Count();
00814      for (i= 0; i < count; i++)
00815      {
00816        if  ((s = (DIR_Server *)wholeList->ElementAt(i)) != nsnull)
00817          if (s == server)
00818            return PR_FALSE;
00819      }
00820      /* In general, if there are any servers already in the list, set the
00821      * position to the position of the last server plus one.  If there
00822      * are none, set it to position 1.
00823      */
00824      if (count > 0)
00825      {
00826      /* Exception to the rule: if the last server is a locked server,
00827      * find the position of last unlocked server.  If there are no
00828      * unlocked servers, set the position to 1; otherwise, set it to
00829      * the position of the last unlocked server plus one.  In either
00830      * case the list must be resorted (to find the correct position).
00831        */
00832        s = (DIR_Server *)wholeList->ElementAt(count - 1);
00833        if (DIR_TestFlag(s, DIR_POSITION_LOCKED))
00834        {
00835          DIR_Server *sLast = nsnull;
00836          
00837          for (i= 0; i < count; i++)
00838          {
00839            if  ((s = (DIR_Server *)wholeList->ElementAt(i)) != nsnull)
00840              if (!DIR_TestFlag(s, DIR_POSITION_LOCKED))
00841                sLast = s;
00842          }
00843          
00844          if (sLast)
00845            server->position = sLast->position + 1;
00846          else
00847            server->position = 1;
00848          
00849          resort = PR_TRUE;
00850        }
00851        else
00852          server->position = s->position + 1;
00853      }
00854      else
00855        server->position = 1;
00856      
00857      wholeList->AppendElement(server);
00858      
00859      if (wholeList == dir_ServerList)
00860        DIR_SendNotification(server, DIR_NOTIFY_ADD, idNone);
00861      break;
00862      
00863    case DIR_POS_DELETE:
00864    /* Undeletable servers cannot be deleted.
00865      */
00866      if (DIR_TestFlag(server, DIR_UNDELETABLE))
00867        return PR_FALSE;
00868      
00869        /* Remove the prefs corresponding to the given server.  If the prefName
00870        * value is nsnull, the server has never been saved and there are no
00871        * prefs to remove.
00872      */
00873      if (server->prefName)
00874      {
00875        char tempstring[256];
00876        
00877        DIR_ClearPrefBranch(server->prefName);
00878        // mark the server as deleted by setting its position to 0
00879        DIR_SetIntPref (server->prefName, "position", tempstring, 0, -1);
00880      }
00881      
00882      /* If the server is in the server list, remove it.
00883      */
00884      num = wholeList->IndexOf(server);
00885      if (num >= 0)
00886      {
00887      /* The list does not need to be re-sorted if the server is the
00888      * last one in the list.
00889        */
00890        count = wholeList->Count();
00891        if (num == count - 1)
00892        {
00893          wholeList->RemoveElementAt(num);
00894        }
00895        else
00896        {
00897          resort = PR_TRUE;
00898          wholeList->RemoveElement(server);
00899        }
00900        
00901        if (wholeList == dir_ServerList)
00902          DIR_SendNotification(server, DIR_NOTIFY_DELETE, idNone);
00903      }
00904      break;
00905      
00906    default:
00907    /* See if the server is already in the list.
00908      */
00909      count = wholeList->Count();
00910      for (i= 0; i < count; i++)
00911      {
00912        if  ((s = (DIR_Server *)wholeList->ElementAt(i)) != nsnull)
00913          if (s == server)
00914            break;
00915      }
00916      
00917      /* If the server is not in the list, add it to the beginning and re-sort.
00918      */
00919      if (s == nsnull)
00920      {
00921        server->position = position;
00922        wholeList->AppendElement(server);
00923        resort = PR_TRUE;
00924        
00925        if (wholeList == dir_ServerList)
00926          DIR_SendNotification(server, DIR_NOTIFY_ADD, idNone);
00927      }
00928      
00929      /* Servers with locked position values cannot be moved.
00930      */
00931      else if (DIR_TestFlag(server, DIR_POSITION_LOCKED))
00932        return PR_FALSE;
00933      
00934        /* Don't re-sort if the server is already in the requested position.
00935      */
00936      else if (server->position != position)
00937      {
00938        server->position = position;
00939        wholeList->RemoveElement(server);
00940        wholeList->AppendElement(server);
00941        resort = PR_TRUE;
00942      }
00943      break;
00944         }
00945         
00946         /* Make sure our position changes get saved back to prefs
00947         */
00948         DIR_SaveServerPreferences(wholeList);
00949         
00950         return resort;
00951 }
00952 
00953 
00954 /*****************************************************************************
00955  * DIR_Server Callback Notification Functions
00956  */
00957 
00958 /* dir_matchServerPrefToServer
00959  *
00960  * This function finds the DIR_Server in the unified DIR_Server list to which
00961  * the given preference string belongs.
00962  */
00963 static DIR_Server *dir_MatchServerPrefToServer(nsVoidArray *wholeList, const char *pref)
00964 {
00965        DIR_Server *server;
00966 
00967        PRInt32 count = wholeList->Count();
00968        PRInt32 i;
00969        for (i = 0; i < count; i++)
00970        {
00971               if ((server = (DIR_Server *)wholeList->ElementAt(i)) != nsnull)
00972               {
00973                      if (server->prefName && PL_strstr(pref, server->prefName) == pref)
00974                      {
00975                             char c = pref[PL_strlen(server->prefName)];
00976                             if (c == 0 || c == '.')
00977                                    return server;
00978                      }
00979               }
00980        }
00981        return nsnull;
00982 }
00983 
00984 /* dir_ValidateAndAddNewServer
00985  *
00986  * This function verifies that the position, serverName and description values
00987  * are set for the given prefName.  If they are then it adds the server to the
00988  * unified server list.
00989  */
00990 static PRBool dir_ValidateAndAddNewServer(nsVoidArray *wholeList, const char *fullprefname)
00991 {
00992        PRBool rc = PR_FALSE;
00993 
00994        const char *endname = PL_strchr(&fullprefname[PL_strlen(PREF_LDAP_SERVER_TREE_NAME) + 1], '.');
00995        if (endname)
00996        {
00997               char *prefname = (char *)PR_Malloc(endname - fullprefname + 1);
00998               if (prefname)
00999               {
01000                      PRInt32 dirType;
01001                      char *t1 = nsnull, *t2 = nsnull;
01002                      char tempstring[256];
01003 
01004                      PL_strncpyz(prefname, fullprefname, endname - fullprefname + 1);
01005 
01006                      dirType = DIR_GetIntPref(prefname, "dirType", tempstring, -1);
01007                      if (   dirType != -1
01008                          && DIR_GetIntPref(prefname, "position", tempstring, 0)    != 0
01009                          && (t1 = DIR_GetStringPref(prefname, "description", tempstring, nsnull)) != nsnull)
01010                      {
01011                             if (   dirType == PABDirectory
01012                                    || (t2 = DIR_GetStringPref(prefname, "serverName",  tempstring, nsnull)) != nsnull)
01013                             {
01014                                    DIR_Server *server = (DIR_Server *)PR_Malloc(sizeof(DIR_Server));
01015                                    if (server)
01016                                    {
01017                                           DIR_InitServerWithType(server, (DirectoryType)dirType);
01018                                           server->prefName = prefname;
01019                                           DIR_GetPrefsForOneServer(server, PR_FALSE, PR_FALSE);
01020                                           DIR_SetServerPosition(wholeList, server, server->position);
01021                                           rc = PR_TRUE;
01022                                    }
01023                                    PR_FREEIF(t2);
01024                             }
01025                             PR_Free(t1);
01026                      }
01027                      else
01028                             PR_Free(prefname);
01029               }
01030        }
01031 
01032        return rc;
01033 }
01034 
01035 static PRInt32 PR_CALLBACK dir_ServerPrefCallback(const char *prefname, void *inst_data)
01036 {
01037     nsresult rv = NS_OK;
01038     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
01039     if (NS_FAILED(rv) || !pPref) 
01040               return NS_ERROR_FAILURE;
01041 
01042        DIR_PrefId id = DIR_AtomizePrefName(prefname);
01043 
01044        /* Check to see if the server is in the unified server list.
01045         */
01046        DIR_Server *server = dir_MatchServerPrefToServer(dir_ServerList, prefname);
01047        if (server)
01048        {
01049               /* If the server is in the process of being saved, just ignore this
01050                * change.  The DIR_Server structure is not really changing.
01051                */
01052               if (DIR_TestFlag(server, DIR_SAVING_SERVER))
01053                   return NS_OK;
01054 
01055               /* Reparse the root DSE if one of the following attributes changed.
01056                */
01057               if (   id == idServerName || id == idSearchBase
01058                      || id == idEnableAuth || id == idAuthDn || id == idPassword)
01059                      DIR_ClearFlag(server, DIR_LDAP_ROOTDSE_PARSED);
01060 
01061               /* If the pref that changed is the position, read it in.  If the new
01062                * position is zero, remove the server from the list.
01063                */
01064               if (id == idPosition)
01065               {
01066                      PRInt32 position;
01067 
01068                      /* We must not do anything if the new position is the same as the
01069                       * position in the DIR_Server.  This avoids recursion in cases
01070                       * where we are deleting the server.
01071                       */
01072                      pPref->GetIntPref(prefname, &position);
01073                      if (position != server->position)
01074                      {
01075                             server->position = position;
01076                             if (dir_IsServerDeleted(server))
01077                                    DIR_SetServerPosition(dir_ServerList, server, DIR_POS_DELETE);
01078                             else
01079                                    DIR_SendNotification(server, DIR_NOTIFY_PROPERTY_CHANGE, idPosition);
01080                      }
01081               }
01082 
01083               /* Some pref other position changed, reload the server and send a property
01084                * changed notification.
01085                */
01086               else if (dir_CallbackList != nsnull)
01087               {
01088                      DIR_GetPrefsForOneServer(server, PR_TRUE, PR_FALSE);
01089                      DIR_SendNotification(server, DIR_NOTIFY_PROPERTY_CHANGE, id);
01090               }
01091        }
01092 
01093        /* If the server is not in the unified list, we may need to add it.  Servers
01094         * are only added when the position, serverName and description are valid.
01095         */
01096        else
01097        {
01098               if (id == idPosition || id == idType || id == idServerName || id == idDescription)
01099                      dir_ValidateAndAddNewServer(dir_ServerList, prefname);
01100        }
01101 
01102     return NS_OK;
01103 }
01104 
01105 PRBool DIR_RegisterNotificationCallback(DIR_NOTIFICATION_FN fn, PRUint32 flags, void *inst_data)
01106 {
01107        DIR_Callback *cb;
01108 
01109        for (cb = dir_CallbackList; cb; cb = cb->next)
01110        {
01111               if (cb->fn == fn)
01112               {
01113                      cb->flags = flags;
01114                      return PR_TRUE;
01115               }
01116        }
01117 
01118        cb = (DIR_Callback *)PR_Malloc(sizeof(DIR_Callback));
01119        if (!cb)
01120               return PR_FALSE;
01121 
01122        cb->fn    = fn;
01123        cb->flags = flags;
01124        cb->data  = inst_data;
01125        cb->next  = dir_CallbackList;
01126        dir_CallbackList = cb;
01127 
01128        return PR_TRUE;
01129 }
01130 
01131 PRBool DIR_DeregisterNotificationCallback(DIR_NOTIFICATION_FN fn, void *inst_data)
01132 {
01133        DIR_Callback *cb, *cbPrev=nsnull;
01134 
01135        for (cb = dir_CallbackList; cb && cb->fn != fn && cb->data != inst_data; cb = cb->next)
01136               cbPrev = cb;
01137 
01138        if (cb == nsnull)
01139               return PR_FALSE;
01140 
01141        if (cb == dir_CallbackList)
01142               dir_CallbackList = cb->next;
01143        else
01144               cbPrev->next = cb->next;
01145 
01146        PR_Free(cb);
01147        return PR_TRUE;
01148 }
01149 
01150 PRBool DIR_SendNotification(DIR_Server *server, PRUint32 flag, DIR_PrefId id)
01151 {
01152        PRBool sent = PR_FALSE;
01153        DIR_Callback *cb, *cbNext;
01154 
01155        for (cb = dir_CallbackList; cb; cb = cbNext)
01156        {
01157               cbNext = cb->next;
01158 
01159               if (cb->flags & flag)
01160               {
01161                      sent = PR_TRUE;
01162                      cb->fn(server, flag, id, cb->data);
01163               }
01164        }
01165 
01166        return sent;
01167 }
01168 
01169 
01170 char *DIR_CopyServerStringPref(DIR_Server *server, DIR_PrefId prefid, int16 csid)
01171 {
01172        char *pref;
01173 
01174        if (!server)
01175               return nsnull;
01176 
01177        switch (prefid) {
01178        case idAuthDn:
01179               pref = server->authDn;
01180               break;
01181        case idPassword:
01182               pref = server->password;
01183               break;
01184        case idSearchBase:
01185               pref = server->searchBase;
01186               break;
01187        default:
01188               PR_ASSERT(0);
01189               pref = nsnull;
01190               break;
01191        }
01192 
01193        if (pref)
01194               pref = DIR_ConvertFromServerCharSet(server, pref, csid);
01195 
01196        return pref;
01197 }
01198 
01199 PRBool DIR_SetServerStringPref(DIR_Server *server, DIR_PrefId prefid, char *pref, PRInt16 csid)
01200 {
01201        PRBool rc = PR_TRUE;
01202 
01203        if (!server || !pref)
01204               return PR_FALSE;
01205 
01206        pref = DIR_ConvertToServerCharSet(server, pref, csid);
01207 
01208        switch (prefid) {
01209        case idAuthDn:
01210               PR_FREEIF(server->authDn);
01211               server->authDn = pref;
01212               break;
01213        case idPassword:
01214               PR_FREEIF(server->password);
01215               server->password = pref;
01216               break;
01217        case idSearchBase:
01218               PR_FREEIF(server->searchBase);
01219               server->searchBase = pref;
01220               break;
01221        default:
01222               PR_ASSERT(0);
01223               rc = PR_FALSE;
01224               break;
01225        }
01226 
01227        return PR_FALSE;
01228 }
01229 
01230 
01231 DIR_PrefId DIR_AtomizePrefName(const char *prefname)
01232 {
01233        DIR_PrefId rc = idNone;
01234 
01235        /* Skip the "ldap_2.servers.<server-name>." portion of the string.
01236         */
01237        if (PL_strstr(prefname, PREF_LDAP_SERVER_TREE_NAME) == prefname)
01238        {
01239               prefname = PL_strchr(&prefname[PL_strlen(PREF_LDAP_SERVER_TREE_NAME) + 1], '.');
01240               if (!prefname)
01241                      return idNone;
01242               else
01243                      prefname = prefname + 1;
01244        }
01245 
01246 
01247        switch (prefname[0]) {
01248        case 'a':
01249               if (PL_strstr(prefname, "autoComplete.") == prefname)
01250               {
01251                      switch (prefname[13]) {
01252                      case 'e': /* autoComplete.enabled */
01253                             rc = idAutoCompleteEnabled;
01254                             break;
01255                      case 'f':
01256                             rc = idAutoCompleteFilter;
01257                             break;
01258                      case 'n':
01259                             rc = idAutoCompleteNever;
01260                             break;
01261                      }
01262               }
01263               else if (PL_strstr(prefname, "auth.") == prefname)
01264               {
01265                      switch (prefname[5]) {
01266                      case 'd': /* auth.dn */
01267                             rc = idAuthDn;
01268                             break;
01269                      case 'e': /* auth.enabled */
01270                             rc = idEnableAuth;
01271                             break;
01272                      case 'p': /* auth.password */
01273                             rc = idPassword;
01274                             break;
01275                      case 's': /* auth.savePassword */
01276                             rc = idSavePassword;
01277                             break;
01278                      }
01279               }
01280               else if (PL_strstr(prefname, "attributes.") == prefname)
01281               {
01282                      rc = idCustomAttributes;
01283               }
01284               break;
01285 
01286        case 'b':
01287               rc = idBasicSearchAttributes;
01288               break;
01289 
01290        case 'c':
01291               switch (prefname[1]) {
01292               case 'h': /* charset */
01293                      rc = idCSID;
01294                      break;
01295               case 's': /* the new csid pref that replaced char set */
01296                      rc = idCSID;
01297                      break;
01298               case 'o': /* columns */
01299                      rc = idColumnAttributes;
01300                      break;
01301               case 'u': /* customDisplayUrl */
01302                      rc = idCustomDisplayUrl;
01303                      break;
01304               }
01305               break;
01306 
01307        case 'd':
01308               switch (prefname[1]) {
01309               case 'e': /* description */
01310                      rc = idDescription;
01311                      break;
01312               case 'i': /* dirType */
01313                      rc = idType;
01314                      break;
01315               }
01316               break;
01317 
01318        case 'e':
01319               switch (prefname[1]) {
01320               case 'e': /* efficientWildcards */
01321                      rc = idEfficientWildcards;
01322                      break;
01323               }
01324               break;
01325 
01326        case 'f':
01327               if (PL_strstr(prefname, "filter") == prefname)
01328               {
01329                      rc = idCustomFilters;
01330               }
01331               else
01332               {
01333                      rc = idFileName;
01334               }
01335               break;
01336 
01337        case 'h':
01338               if (PL_strstr(prefname, "html.") == prefname)
01339               {
01340                      switch (prefname[5]) {
01341                      case 'd':
01342                             rc = idDnAttributes;
01343                             break;
01344                      case 's':
01345                             rc = idSuppressedAttributes;
01346                             break;
01347                      case 'u':
01348                             rc = idUriAttributes;
01349                             break;
01350                      }
01351               }
01352               break;
01353               
01354        case 'i':
01355               switch (prefname[2]) {
01356               case 'O': /* filename */
01357                      rc = idIsOffline;
01358                      break;
01359               case 'S': /* filename */
01360                      rc = idIsSecure;
01361                      break;
01362               }
01363               break;
01364        case 'l':
01365               rc = idLocale;
01366               break;
01367 
01368        case 'm':
01369               rc = idMaxHits;
01370               break;
01371 
01372        case 'p':
01373               switch (prefname[1]) {
01374               case 'o':
01375                      switch (prefname[2]) {
01376                      case 'r': /* port */
01377                             rc = idPort;
01378                             break;
01379                      case 's': /* position */
01380                             rc = idPosition;
01381                             break;
01382                      }
01383                      break;
01384                 case  'r': /* protocolVersion */
01385                     rc = idProtocolVersion;
01386               }
01387               break;
01388 
01389        case 'r':
01390               if (PL_strstr(prefname, "replication.") == prefname)
01391               {
01392                      switch (prefname[12]) {
01393                      case 'd':
01394                             switch (prefname[13]) {
01395                                    case 'a': /* replication.dataVersion */
01396                                           rc = idReplDataVersion;
01397                                           break;
01398                                    case 'e': /* replication.description */
01399                                           rc = idReplDescription;
01400                                           break;
01401                             }
01402                             break;
01403                      case 'e':
01404                             switch (prefname[13]) {
01405                             case 'n': /* replication.enabled */
01406                                    rc = idReplEnabled;
01407                                    break;
01408                             case 'x': /* replication.excludedAttributes */
01409                                    rc = idReplExcludedAttributes;
01410                                    break;
01411                             }
01412                             break;
01413                      case 'f':
01414                             switch (prefname[15]) {
01415                             case 'e': /* replication.fileName */
01416                                    rc = idReplFileName;
01417                                    break;
01418                             case 't': /* replication.filter */
01419                                    rc = idReplFilter;
01420                                    break;
01421                             }
01422                             break;
01423                      case 'l': /* replication.lastChangeNumber */
01424                             rc = idReplLastChangeNumber;
01425                             break;
01426                      case 'n': /* replication.never */
01427                             rc = idReplNever;
01428                             break;
01429                      case 's': /* replication.syncURL */
01430                             rc = idReplSyncURL;
01431                             break;
01432                      }
01433               }
01434               break;
01435 
01436        case 's':
01437               switch (prefname[1]) {
01438               case 'a': /* saveResults */
01439                      rc = idSaveResults;
01440                      break;
01441               case 'e':
01442                      switch (prefname[2]) {
01443                      case 'a':
01444                             switch (prefname[6]) {
01445                             case 'B': /* searchBase */
01446                                    rc = idSearchBase;
01447                                    break;
01448                             case 'S': /* searchString */
01449                                    rc = idLastSearchString;
01450                                    break;
01451                             }
01452                             break;
01453                      case 'r': /* serverName */
01454                             rc = idServerName;
01455                             break;
01456                      }
01457                      break;
01458               }
01459               break;
01460 
01461        case 'u': /* uri */
01462               rc = idUri;
01463               break;
01464 
01465 
01466 
01467        case 'v': /* vlvDisabled */
01468               rc = idVLVDisabled;
01469               break;
01470        case 'P':
01471               switch (prefname[4]) {
01472                      case 'C': /* PalmCategoryId */
01473                             rc = idPalmCategory;
01474                             break;
01475                      case 'S': /* PalmSyncTimeStamp */
01476                             rc = idPalmSyncTimeStamp;
01477                             break;
01478               }
01479               break;
01480        }
01481 
01482        PR_ASSERT(rc != idNone);
01483        return rc;
01484 }
01485 
01486 
01487 /*****************************************************************************
01488  * Function for comparing DIR_Servers 
01489  */
01490 
01491 static PRBool dir_AreLDAPServersSame (DIR_Server *first, DIR_Server *second, PRBool strict)
01492 {
01493        PR_ASSERT (first->serverName && second->serverName);
01494 
01495        if (first->serverName && second->serverName)
01496        {
01497         if (nsCRT::strcasecmp (first->serverName, second->serverName) == 0) 
01498               {
01499                      if (first->port == second->port) 
01500                      {
01501                             /* allow for a null search base */
01502                             if (!strict || (first->searchBase == nsnull && second->searchBase == nsnull))
01503                                    return PR_TRUE;
01504                             /* otherwise check the strings */
01505                             else if (   first->searchBase
01506                                      && second->searchBase
01507                          && nsCRT::strcasecmp (first->searchBase, second->searchBase) == 0)
01508                                    return PR_TRUE;
01509                      }
01510               }
01511        }
01512 
01513        return PR_FALSE;
01514 }
01515 
01516 static PRBool dir_AreServersSame (DIR_Server *first, DIR_Server *second, PRBool strict)
01517 {
01518        /* This function used to be written to assume that we only had one PAB so it
01519           only checked the server type for PABs. If both were PABDirectories, then 
01520           it returned PR_TRUE. Now that we support multiple address books, we need to
01521           check type & file name for address books to test if they are the same */
01522 
01523        if (first && second) 
01524        {
01525               /* assume for right now one personal address book type where offline is PR_FALSE */
01526               if ((first->dirType == PABDirectory) && (second->dirType == PABDirectory))
01527               {
01528       /* are they both really address books? */
01529       if (!first->isOffline && !second->isOffline)
01530                      {
01531                             PR_ASSERT(first->fileName && second->fileName);
01532                             if (first->fileName && second->fileName)
01533                     if (nsCRT::strcasecmp(first->fileName, second->fileName) == 0)
01534                                           return PR_TRUE;
01535 
01536                             return PR_FALSE;
01537                      }
01538                      else
01539                             return dir_AreLDAPServersSame(first, second, strict);
01540               }
01541 
01542               if (first->dirType == second->dirType)
01543                      return dir_AreLDAPServersSame(first, second, strict);
01544        }
01545        return PR_FALSE;
01546 }
01547 
01548 PRBool DIR_AreServersSame (DIR_Server *first, DIR_Server *second)
01549 {
01550        return dir_AreServersSame(first, second, PR_TRUE);
01551 }
01552 
01553 DIR_Server *DIR_LookupServer(char *serverName, PRInt32 port, char *searchBase)
01554 {
01555        PRInt32 i;
01556        DIR_Server *server;
01557 
01558        if (!serverName || !searchBase || !dir_ServerList)
01559               return nsnull;
01560 
01561        for (i = dir_ServerList->Count() - 1; i >= 0; i--)
01562        {
01563               server = (DIR_Server *)dir_ServerList->ElementAt(i);
01564               if (   server->port == port
01565             && server->serverName && nsCRT::strcasecmp(server->serverName, serverName) == 0
01566             && server->searchBase && nsCRT::strcasecmp(server->searchBase, searchBase) == 0)
01567               {
01568                      return server;
01569               }
01570        }
01571 
01572        return nsnull;
01573 }
01574 
01575 /*****************************************************************************
01576  * Functions for destroying DIR_Servers 
01577  */
01578 
01579 /* this function determines if the passed in server is no longer part of the of
01580    the global server list. */
01581 static PRBool dir_IsServerDeleted(DIR_Server * server)
01582 {
01583        if (server && server->position == 0)
01584               return PR_TRUE;
01585        else
01586               return PR_FALSE;
01587 }
01588 
01589 static void dir_DeleteTokenList (char **tokenList, PRInt32 tokenListCount)
01590 {
01591        PRInt32 tokenIdx;
01592        for (tokenIdx = 0; tokenIdx < tokenListCount; tokenIdx++)
01593               PR_Free(tokenList[tokenIdx]);
01594        PR_Free(tokenList);
01595 }
01596 
01597 
01598 static nsresult DIR_DeleteFilter (DIR_Filter *filter)
01599 {
01600        if (filter->string)
01601               PR_Free(filter->string);
01602        PR_Free(filter);
01603        return NS_OK;
01604 }
01605 
01606 
01607 static nsresult DIR_DeleteAttribute (DIR_Attribute *attribute)
01608 {
01609        PRInt32 i = 0;
01610        if (attribute->prettyName)
01611               PR_Free(attribute->prettyName);
01612        if (attribute->attrNames)
01613        {
01614               while (attribute->attrNames[i])
01615                      PR_Free((char**)attribute->attrNames[i++]);
01616               PR_Free(attribute->attrNames);
01617        }
01618        PR_Free(attribute);
01619        return NS_OK;
01620 }
01621 
01622 
01623 static void dir_DeleteReplicationInfo (DIR_Server *server)
01624 {
01625        DIR_ReplicationInfo *info = nsnull;
01626        if (server && (info = server->replInfo) != nsnull)
01627        {
01628               dir_DeleteTokenList (info->excludedAttributes, info->excludedAttributesCount);
01629               
01630               PR_FREEIF(info->description);
01631               PR_FREEIF(info->fileName);
01632               PR_FREEIF(info->dataVersion);
01633               PR_FREEIF(info->syncURL);
01634               PR_FREEIF(info->filter);
01635               PR_Free(info);
01636        }
01637 }
01638 
01639 /* when the back end manages the server list, deleting a server just decrements its ref count,
01640    in the old world, we actually delete the server */
01641 static nsresult dir_DeleteServerContents (DIR_Server *server)
01642 {
01643        if (server)
01644        {
01645               PRInt32 i;
01646 
01647               /* when destroying the server check its clear flag to see if things need cleared */
01648 #ifdef XP_FileRemove
01649               if (DIR_TestFlag(server, DIR_CLEAR_SERVER))
01650               {
01651                      if (server->fileName)
01652                             XP_FileRemove (server->fileName, xpAddrBookNew);
01653                      if (server->replInfo && server->replInfo->fileName)
01654                             XP_FileRemove (server->replInfo->fileName, xpAddrBookNew);
01655               }
01656 #endif /* XP_FileRemove */
01657 
01658               PR_FREEIF (server->prefName);
01659               PR_FREEIF (server->description);
01660               PR_FREEIF (server->serverName);
01661               PR_FREEIF (server->searchBase);
01662               PR_FREEIF (server->fileName);
01663               PR_FREEIF (server->lastSearchString);
01664               PR_FREEIF (server->tokenSeps);
01665               PR_FREEIF (server->authDn);
01666               PR_FREEIF (server->password);
01667               PR_FREEIF (server->columnAttributes);
01668               PR_FREEIF (server->locale);
01669         PR_FREEIF (server->uri);
01670 
01671               if (server->customFilters)
01672               {
01673                      PRInt32 count = server->customFilters->Count();
01674                      for (i = 0; i < count; i++)
01675                             DIR_DeleteFilter ((DIR_Filter*) server->customFilters->ElementAt(i));
01676                      delete server->customFilters;
01677               }
01678 
01679               PR_FREEIF (server->autoCompleteFilter);
01680 
01681               if (server->customAttributes)
01682               {
01683                      nsVoidArray *list = server->customAttributes;
01684                      DIR_Attribute *walkAttrStruct = nsnull;
01685                      PRInt32 count = list->Count();
01686                      for (i = 0; i < count; i++)
01687                      {
01688                             walkAttrStruct = (DIR_Attribute *)list->ElementAt(i);
01689                             if (walkAttrStruct != nsnull)
01690                                    DIR_DeleteAttribute (walkAttrStruct);
01691                      }
01692                      delete server->customAttributes;
01693               }
01694 
01695               if (server->uriAttributes)
01696                      dir_DeleteTokenList (server->uriAttributes, server->uriAttributesCount);
01697               if (server->suppressedAttributes)
01698                      dir_DeleteTokenList (server->suppressedAttributes, server->suppressedAttributesCount);
01699               if (server->dnAttributes)
01700                      dir_DeleteTokenList (server->dnAttributes, server->dnAttributesCount);
01701               PR_FREEIF (server->basicSearchAttributes);
01702               if (server->replInfo)
01703                      dir_DeleteReplicationInfo (server);
01704 
01705               PR_FREEIF (server->customDisplayUrl);
01706               PR_FREEIF (server->searchPairList);
01707        }
01708        return NS_OK;
01709 }
01710 
01711 nsresult DIR_DeleteServer(DIR_Server *server)
01712 {
01713        if (server)
01714        {
01715               dir_DeleteServerContents(server);
01716               PR_Free(server);
01717        }
01718 
01719        return NS_OK;
01720 }
01721 
01722 nsresult DIR_DeleteServerFromList(DIR_Server *server)
01723 {
01724        if (!server)
01725               return NS_ERROR_NULL_POINTER;
01726 
01727        nsresult rv = NS_OK;
01728        nsCOMPtr<nsILocalFile> dbPath;
01729 
01730        nsCOMPtr<nsIAddrBookSession> abSession = 
01731                 do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv); 
01732        if(NS_SUCCEEDED(rv))
01733          rv = abSession->GetUserProfileDirectory(getter_AddRefs(dbPath));
01734        
01735        if (NS_SUCCEEDED(rv))
01736        {
01737     // close the database, as long as it isn't the special ones 
01738     // (personal addressbook and collected addressbook)
01739     // which can never be deleted.  There was a bug where we would slap in
01740     // "abook.mab" as the file name for LDAP directories, which would cause a crash
01741     // on delete of LDAP directories.  this is just extra protection.
01742     if (strcmp(server->fileName, kPersonalAddressbook) && 
01743         strcmp(server->fileName, kCollectedAddressbook)) {
01744               nsCOMPtr<nsIAddrDatabase> database;
01745 
01746               rv = dbPath->AppendNative(nsDependentCString(server->fileName));
01747               NS_ENSURE_SUCCESS(rv, rv);
01748 
01749               // close file before delete it
01750               nsCOMPtr<nsIAddrDatabase> addrDBFactory = 
01751                        do_GetService(NS_ADDRDATABASE_CONTRACTID, &rv);
01752 
01753               if (NS_SUCCEEDED(rv) && addrDBFactory)
01754                      rv = addrDBFactory->Open(dbPath, PR_FALSE, PR_TRUE, getter_AddRefs(database));
01755               if (database)  /* database exists */
01756               {
01757                      database->ForceClosed();
01758                      rv = dbPath->Remove(PR_FALSE);
01759                      NS_ENSURE_SUCCESS(rv, rv);
01760               }
01761     }
01762 
01763               nsVoidArray *dirList = DIR_GetDirectories();
01764               DIR_SetServerPosition(dirList, server, DIR_POS_DELETE);
01765               DIR_DeleteServer(server);
01766 
01767               rv = NS_OK;
01768               nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
01769               if (NS_FAILED(rv) || !pPref) 
01770                      return NS_ERROR_FAILURE;
01771 
01772               pPref->SavePrefFile(nsnull);
01773 
01774               return NS_OK;
01775        }
01776 
01777        return NS_ERROR_NULL_POINTER;
01778 }
01779 
01780 nsresult DIR_DeleteServerList(nsVoidArray *wholeList)
01781 {
01782        DIR_Server *server = nsnull;
01783        
01784        /* TBD: Send notifications? */
01785        PRInt32 count = wholeList->Count();
01786        PRInt32 i;
01787        for (i = count - 1; i >=0; i--)
01788        {
01789               server = (DIR_Server *)wholeList->ElementAt(i);
01790               if (server != nsnull)
01791                      DIR_DeleteServer(server);
01792        }
01793        delete wholeList;
01794        return NS_OK;
01795 }
01796 
01797 
01798 nsresult DIR_CleanUpServerPreferences(nsVoidArray *deletedList)
01799 {
01800        /* OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE */
01801        PR_ASSERT(PR_FALSE);
01802        return NS_OK;
01803        /* OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE */
01804 }
01805 
01806 
01807 /*****************************************************************************
01808  * Functions for retrieving subsets of the DIR_Server list 
01809  */
01810 
01811 #define DIR_SUBSET_MATCH(_SERVER, _FLAGS)                                                 \
01812        (   (   (_FLAGS & DIR_SUBSET_PAB_ALL          ) && PABDirectory  == _SERVER->dirType) \
01813         || (   (_FLAGS & DIR_SUBSET_HTML_ALL         ) && HTMLDirectory == _SERVER->dirType) \
01814         || (   (_FLAGS & DIR_SUBSET_LDAP_ALL         ) && LDAPDirectory == _SERVER->dirType) \
01815         || (   (_FLAGS & DIR_SUBSET_LDAP_AUTOCOMPLETE) && LDAPDirectory == _SERVER->dirType  \
01816                && !DIR_TestFlag(s, DIR_AUTO_COMPLETE_NEVER))                                    \
01817         || (   (_FLAGS & DIR_SUBSET_LDAP_REPLICATE   ) && LDAPDirectory == _SERVER->dirType  \
01818                && !DIR_TestFlag(s, DIR_REPLICATE_NEVER))                                        \
01819     )
01820 
01821 nsresult DIR_GetDirServerSubset(nsVoidArray *wholeList, nsVoidArray *subList, PRUint32 flags)
01822 {
01823        if (wholeList && subList && flags)
01824        {
01825               PRInt32 i;
01826               PRInt32 numItems = wholeList->Count();
01827 
01828               for (i = 0; i < numItems; i++)
01829               {
01830                      DIR_Server *s = (DIR_Server*) wholeList->ElementAt(i);
01831                      if (DIR_SUBSET_MATCH(s, flags))
01832                      {
01833                             subList->AppendElement(s);
01834                      }
01835               }
01836               return NS_OK;
01837        }
01838        return NS_ERROR_FAILURE;
01839 }
01840 
01841 PRInt32 DIR_GetDirServerSubsetCount(nsVoidArray * wholeList, PRUint32 flags)
01842 {
01843        PRInt32 count = 0;
01844 
01845        if (wholeList && flags)
01846        {
01847               PRInt32 i;
01848               PRInt32 numItems = wholeList->Count();
01849 
01850               for (i = 0; i < numItems; i++)
01851               {
01852                      DIR_Server *s = (DIR_Server*) wholeList->ElementAt(i);
01853                      if (DIR_SUBSET_MATCH(s, flags))
01854                      {
01855                             count++;
01856                      }
01857               }
01858        }
01859 
01860        return count;
01861 }
01862 
01863 nsresult DIR_GetComposeNameCompletionAddressBook (nsVoidArray *wholeList, DIR_Server **cab)
01864 {
01865        /* OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE */
01866        PR_ASSERT(PR_FALSE);
01867     return NS_ERROR_FAILURE;
01868        /* OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE */
01869 }
01870 
01871 nsresult DIR_GetLdapServers (nsVoidArray *wholeList, nsVoidArray *subList)
01872 {
01873        /* OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE */
01874        return DIR_GetDirServerSubset(wholeList, subList, DIR_SUBSET_LDAP_ALL);
01875        /* OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE */
01876 }
01877 
01878 nsresult DIR_GetPersonalAddressBook(nsVoidArray *wholeList, DIR_Server **pab)
01879 {
01880        if (wholeList && pab)
01881        {
01882               PRInt32 count = wholeList->Count();
01883               PRInt32 i;
01884 
01885               *pab = nsnull;
01886               for (i = 0; i < count; i++)
01887               {
01888                      DIR_Server *server = (DIR_Server *)wholeList->ElementAt(i);
01889                      if ((PABDirectory == server->dirType) && (PR_FALSE == server->isOffline))
01890                      {
01891                             if (server->serverName == nsnull || server->serverName[0] == '\0')
01892                             {
01893                                    *pab = server;
01894                                    return NS_OK;
01895                             }
01896                      }
01897               }
01898        }
01899        return NS_ERROR_FAILURE;
01900 }
01901 
01902 
01903 #ifndef MOZADDRSTANDALONE
01904 
01905 /*****************************************************************************
01906  * Functions for managing JavaScript prefs for the DIR_Servers 
01907  */
01908 
01909 #include "nsQuickSort.h"
01910 
01911 PR_STATIC_CALLBACK(int)
01912 comparePrefArrayMembers(const void* aElement1, const void* aElement2, void* aData)
01913 {
01914     const char* element1 = *NS_STATIC_CAST(const char* const *, aElement1);
01915     const char* element2 = *NS_STATIC_CAST(const char* const *, aElement2);
01916     const PRUint32 offset = *((const PRUint32*)aData);
01917 
01918     // begin the comparison at |offset| chars into the string -
01919     // this avoids comparing the "ldap_2.servers." portion of every element,
01920     // which will always remain the same.
01921     return strcmp(element1 + offset, element2 + offset);
01922 }
01923 
01924 static nsresult dir_GetChildList(const nsAFlatCString &aBranch,
01925                                  PRUint32 *aCount, char ***aChildList)
01926 {
01927     PRUint32 branchLen = aBranch.Length();
01928 
01929     nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
01930     if (!prefBranch) {
01931         return NS_ERROR_FAILURE;
01932     }
01933 
01934     nsresult rv = prefBranch->GetChildList(aBranch.get(), aCount, aChildList);
01935     if (NS_FAILED(rv)) {
01936         return rv;
01937     }
01938 
01939     // traverse the list, and truncate all the descendant strings to just
01940     // one branch level below the root branch.
01941     for (PRUint32 i = *aCount; i--; ) {
01942         // The prefname we passed to GetChildList was of the form
01943         // "ldap_2.servers." and we are returned the descendants
01944         // in the form of "ldap_2.servers.servername.foo"
01945         // But we want the prefbranch of the servername, so
01946         // write a NUL character in to terminate the string early.
01947         char *endToken = strchr((*aChildList)[i] + branchLen, '.');
01948         if (endToken)
01949             *endToken = '\0';
01950     }
01951 
01952     if (*aCount > 1) {
01953         // sort the list, in preparation for duplicate entry removal
01954         NS_QuickSort(*aChildList, *aCount, sizeof(char*), comparePrefArrayMembers, &branchLen);
01955 
01956         // traverse the list and remove duplicate entries.
01957         // we use two positions in the list; the current entry and the next
01958         // entry; and perform a bunch of in-place ptr moves. so |cur| points
01959         // to the last unique entry, and |next| points to some (possibly much
01960         // later) entry to test, at any given point. we know we have >= 2
01961         // elements in the list here, so we just init the two counters sensibly
01962         // to begin with.
01963         PRUint32 cur = 0;
01964         for (PRUint32 next = 1; next < *aCount; ++next) {
01965             // check if the elements are equal or unique
01966             if (!comparePrefArrayMembers(&((*aChildList)[cur]), &((*aChildList)[next]), &branchLen)) {
01967                 // equal - just free & increment the next element ptr
01968 
01969                 nsMemory::Free((*aChildList)[next]);
01970             } else {
01971                 // cur & next are unique, so we need to shift the element.
01972                 // ++cur will point to the next free location in the
01973                 // reduced array (it's okay if that's == next)
01974                 (*aChildList)[++cur] = (*aChildList)[next];
01975             }
01976         }
01977 
01978         // update the unique element count
01979         *aCount = cur + 1;
01980     }
01981 
01982     return NS_OK;
01983 }
01984 
01985 
01986 static char *DIR_GetStringPref(const char *prefRoot, const char *prefLeaf, char *scratch, const char *defaultValue)
01987 {
01988     nsresult rv = NS_OK;
01989     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
01990     if (NS_FAILED(rv) || !pPref) 
01991               return nsnull;
01992 
01993        char *value = nsnull;
01994        PL_strcpy(scratch, prefRoot);
01995        PL_strcat(scratch, ".");
01996        PL_strcat(scratch, prefLeaf);
01997  
01998        if (PREF_NOERROR == pPref->CopyCharPref(scratch, &value))
01999        {
02000               /* unfortunately, there may be some prefs out there which look like this */
02001               if (!PL_strcmp(value, "(null)")) 
02002               {
02003                      PR_FREEIF(value); /* free old value because we are going to give it a new value.... */
02004             value = defaultValue ? nsCRT::strdup(defaultValue) : nsnull;
02005               }
02006               if (!value || !*value)
02007               {
02008                      PR_FREEIF(value);
02009                      pPref->CopyDefaultCharPref(scratch, &value);
02010               }
02011        }
02012        else
02013        {
02014               PR_FREEIF(value); /* the pref may have generated an error but we still might have something in value...... */
02015         value = defaultValue ? nsCRT::strdup(defaultValue) : nsnull;
02016        }
02017        return value;
02018 }
02019 
02020 /*
02021        Get localized unicode string pref from properties file, convert into an UTF8 string 
02022        since address book prefs store as UTF8 strings.  So far there are 2 default 
02023        prefs stored in addressbook.properties.
02024        "ldap_2.servers.pab.description"
02025        "ldap_2.servers.history.description"
02026 */
02027 static char *DIR_GetLocalizedStringPref
02028 (const char *prefRoot, const char *prefLeaf, char *scratch, const char *defaultValue)
02029 {
02030     nsresult rv = NS_OK;
02031     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
02032     if (NS_FAILED(rv) || !pPref) 
02033               return nsnull;
02034 
02035        PL_strcpy(scratch, prefRoot);
02036        PL_strcat(scratch, ".");
02037        PL_strcat(scratch, prefLeaf);
02038 
02039        nsXPIDLString wvalue;
02040        rv = pPref->GetLocalizedUnicharPref(scratch, getter_Copies(wvalue));
02041        char *value = nsnull;
02042        if ((const PRUnichar*)wvalue)
02043        {
02044     NS_ConvertUCS2toUTF8 utf8str(wvalue.get());
02045     value = ToNewCString(utf8str);
02046        }
02047        else
02048     value = defaultValue ? nsCRT::strdup(defaultValue) : nsnull;
02049 
02050        return value;
02051 }
02052 
02053 static PRInt32 DIR_GetIntPref(const char *prefRoot, const char *prefLeaf, char *scratch, PRInt32 defaultValue)
02054 {
02055     nsresult rv = NS_OK;
02056     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
02057     if (NS_FAILED(rv) || !pPref) 
02058               return defaultValue;
02059 
02060        PRInt32 value;
02061        PL_strcpy(scratch, prefRoot);
02062        PL_strcat(scratch, ".");
02063        PL_strcat(scratch, prefLeaf);
02064 
02065        if (PREF_NOERROR != pPref->GetIntPref(scratch, &value))
02066               value = defaultValue;
02067 
02068        return value;
02069 }
02070 
02071 
02072 static PRBool DIR_GetBoolPref(const char *prefRoot, const char *prefLeaf, char *scratch, PRBool defaultValue)
02073 {
02074     nsresult rv = NS_OK;
02075     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
02076     if (NS_FAILED(rv) || !pPref) 
02077               return defaultValue;
02078 
02079        PRBool value;
02080        PL_strcpy(scratch, prefRoot);
02081        PL_strcat(scratch, ".");
02082        PL_strcat(scratch, prefLeaf);
02083 
02084        if (PREF_NOERROR != pPref->GetBoolPref(scratch, &value))
02085               value = defaultValue;
02086        return value;
02087 }
02088 
02089 
02090 nsresult DIR_AttributeNameToId(DIR_Server *server, const char *attrName, DIR_AttributeId *id)
02091 {
02092        nsresult status = NS_OK;
02093 
02094        /* Look for a default attribute with a matching name.
02095         */
02096        switch (attrName[0])
02097        {
02098        case 'a':
02099         if (!nsCRT::strcasecmp(attrName, "auth"))
02100                      *id = auth;
02101               else
02102                      status = NS_ERROR_FAILURE;
02103               break;
02104        case 'b':
02105         if (!nsCRT::strcasecmp(attrName, "businesscategory"))
02106                      *id = businesscategory;
02107               else
02108                      status = NS_ERROR_FAILURE;
02109               break;
02110        case 'c' :
02111         if (!nsCRT::strcasecmp(attrName, "cn"))
02112                      *id = cn;
02113         else if (!nsCRT::strcasecmp(attrName, "carlicense"))
02114                      *id = carlicense;
02115         else if (!nsCRT::strncasecmp(attrName, "custom", 6))
02116               {
02117                      switch (attrName[6])
02118                      {
02119                      case '1': *id = custom1; break;
02120                      case '2': *id = custom2; break;
02121                      case '3': *id = custom3; break;
02122                      case '4': *id = custom4; break;
02123                      case '5': *id = custom5; break;
02124                      default: status = NS_ERROR_FAILURE; 
02125                      }
02126               }
02127               else
02128                      status = NS_ERROR_FAILURE;
02129               break;
02130        case 'd':
02131         if (!nsCRT::strcasecmp(attrName, "departmentnumber"))
02132                      *id = departmentnumber;
02133               else
02134             if (!nsCRT::strcasecmp(attrName, "description"))
02135                             *id = description;
02136               else
02137                      status = NS_ERROR_FAILURE;
02138               break;
02139        case 'e':
02140         if (!nsCRT::strcasecmp(attrName, "employeetype"))
02141                      *id = employeetype;
02142               else
02143                      status = NS_ERROR_FAILURE;
02144               break;
02145        case 'f':
02146         if (!nsCRT::strcasecmp(attrName, "facsimiletelephonenumber"))
02147                      *id = facsimiletelephonenumber;
02148               else
02149                      status = NS_ERROR_FAILURE;
02150               break;
02151        case 'g':
02152         if (!nsCRT::strcasecmp(attrName, "givenname"))
02153                      *id = givenname; 
02154               else
02155                      status = NS_ERROR_FAILURE;
02156               break;
02157        case 'h':
02158         if (!nsCRT::strcasecmp(attrName, "homephone"))
02159                      *id = homephone;
02160               else
02161                      status = NS_ERROR_FAILURE;
02162               break;
02163        case 'l':
02164         if (!nsCRT::strcasecmp(attrName, "l"))
02165                      *id = l;
02166               else
02167                      status = NS_ERROR_FAILURE;
02168               break;
02169        case 'm':
02170         if (!nsCRT::strcasecmp(attrName, "mail"))
02171                      *id = mail;
02172         else if (!nsCRT::strcasecmp(attrName, "manager"))
02173                      *id = manager;
02174         else if (!nsCRT::strcasecmp(attrName, "mobiletelephonenumber"))
02175                      *id = mobiletelephonenumber;
02176               else
02177                      status = NS_ERROR_FAILURE;
02178               break;
02179        case 'n':
02180         if (!nsCRT::strcasecmp(attrName, "nickname"))
02181                      *id = nickname;
02182               else
02183                      status = NS_ERROR_FAILURE;
02184               break;
02185        case 'o':
02186         if (!nsCRT::strcasecmp(attrName, "o"))
02187                      *id = o;
02188         else if (!nsCRT::strcasecmp(attrName, "ou"))
02189                      *id = ou;
02190         else if (!nsCRT::strcasecmp(attrName, "objectclass"))
02191                      *id = objectclass;
02192               else
02193                      status = NS_ERROR_FAILURE;
02194               break;
02195        case 'p':
02196         if (!nsCRT::strcasecmp(attrName, "pager"))
02197                      *id = pager;
02198         else if (!nsCRT::strcasecmp(attrName, "postalcode"))
02199                      *id = postalcode;
02200         else if (!nsCRT::strcasecmp(attrName, "postaladdress"))
02201                      *id = postaladdress;
02202               else
02203                      status = NS_ERROR_FAILURE;
02204               break;
02205        case 's': 
02206         if (!nsCRT::strcasecmp(attrName, "street"))
02207                      *id = street;
02208         else if (!nsCRT::strcasecmp(attrName, "sn"))
02209                      *id = sn;
02210         else if (!nsCRT::strcasecmp(attrName, "secretary"))
02211                      *id = secretary;
02212               else
02213                      status = NS_ERROR_FAILURE;
02214               break;
02215        case 't':
02216         if (!nsCRT::strcasecmp(attrName, "telephonenumber"))
02217                      *id = telephonenumber;
02218         else if (!nsCRT::strcasecmp(attrName, "title"))
02219                      *id = title;
02220               else
02221                      status = NS_ERROR_FAILURE;
02222               break;
02223        default:
02224               status = NS_ERROR_FAILURE;
02225        }
02226 
02227        return status;
02228 }
02229 
02230 static nsresult DIR_AddCustomAttribute(DIR_Server *server, const char *attrName, char *jsAttr)
02231 {
02232        nsresult status = NS_OK;
02233        char *jsCompleteAttr = nsnull;
02234        char *jsAttrForTokenizing = jsAttr;
02235 
02236        DIR_AttributeId id;
02237        status = DIR_AttributeNameToId(server, attrName, &id);
02238 
02239        /* If the string they gave us doesn't have a ':' in it, assume it's one or more
02240         * attributes without a pretty name. So find the default pretty name, and generate
02241         * a "complete" string to use for tokenizing.
02242         */
02243        if (NS_SUCCEEDED(status) && !PL_strchr(jsAttr, ':'))
02244        {
02245               const char *defaultPrettyName = DIR_GetAttributeName (server, id);
02246               if (defaultPrettyName)
02247               {
02248                      jsCompleteAttr = PR_smprintf ("%s:%s", defaultPrettyName, jsAttr);
02249                      if (jsCompleteAttr)
02250                             jsAttrForTokenizing = jsCompleteAttr;
02251                      else
02252                             status = NS_ERROR_OUT_OF_MEMORY;
02253               }
02254        }
02255 
02256        if (NS_SUCCEEDED(status))
02257        {
02258         char *scratchAttr = nsCRT::strdup(jsAttrForTokenizing);
02259               DIR_Attribute *attrStruct = (DIR_Attribute*) PR_Malloc(sizeof(DIR_Attribute));
02260               if (!server->customAttributes)
02261                      server->customAttributes = new nsVoidArray();
02262 
02263               if (attrStruct && server->customAttributes && scratchAttr)
02264               {
02265                      char *attrToken = nsnull;
02266                      PRUint32 attrCount = 0;
02267 
02268                      memset(attrStruct, 0, sizeof(DIR_Attribute));
02269 
02270                      /* Try to pull out the pretty name into the struct */
02271                      attrStruct->id = id;
02272             attrStruct->prettyName = nsCRT::strdup(strtok(scratchAttr, ":")); 
02273 
02274                      /* Count up the attribute names */
02275                      while ((attrToken = strtok(nsnull, ", ")) != nsnull)
02276                             attrCount++;
02277 
02278                      /* Pull the attribute names into the struct */
02279                      PL_strcpy(scratchAttr, jsAttrForTokenizing);
02280                      strtok(scratchAttr, ":"); 
02281                      attrStruct->attrNames = (char**) PR_Malloc((attrCount + 1) * sizeof(char*));
02282                      if (attrStruct->attrNames)
02283                      {
02284                             PRInt32 i = 0;
02285                             while ((attrToken = strtok(nsnull, ", ")) != nsnull)
02286                     attrStruct->attrNames[i++] = nsCRT::strdup(attrToken);
02287                             attrStruct->attrNames[i] = nsnull; /* null-terminate the array */
02288                      }
02289 
02290                      if (NS_SUCCEEDED(status)) /* status is always NS_OK! */
02291                             server->customAttributes->AppendElement(attrStruct);
02292                      else
02293                             DIR_DeleteAttribute (attrStruct);
02294 
02295                      PR_Free(scratchAttr);
02296               }
02297               else 
02298                      status = NS_ERROR_OUT_OF_MEMORY;
02299        }
02300 
02301        if (jsCompleteAttr)
02302               PR_smprintf_free(jsCompleteAttr);
02303 
02304        return status;
02305 }
02306 
02307 static nsresult dir_CreateTokenListFromWholePref(const char *pref, char ***outList, PRInt32 *outCount)
02308 {
02309     nsresult result = NS_OK;
02310     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &result)); 
02311     if (NS_FAILED(result)) 
02312               return result;
02313 
02314        char *commaSeparatedList = nsnull;
02315 
02316        if (PREF_NOERROR == pPref->CopyCharPref(pref, &commaSeparatedList) && commaSeparatedList)
02317        {
02318               char *tmpList = commaSeparatedList;
02319               *outCount = 1;
02320               while (*tmpList)
02321                      if (*tmpList++ == ',')
02322                             (*outCount)++;
02323 
02324               *outList = (char**) PR_Malloc(*outCount * sizeof(char*));
02325               if (*outList)
02326               {
02327                      PRInt32 i;
02328                      char *token = strtok(commaSeparatedList, ", ");
02329                      for (i = 0; i < *outCount; i++)
02330                      {
02331                 (*outList)[i] = nsCRT::strdup(token);
02332                             token = strtok(nsnull, ", ");
02333                      }
02334               }
02335               else
02336                      result = NS_ERROR_OUT_OF_MEMORY;
02337 
02338               PR_Free (commaSeparatedList);
02339        }
02340        else
02341               result = NS_ERROR_FAILURE;
02342        return result;
02343 }
02344 
02345 
02346 static nsresult dir_CreateTokenListFromPref
02347 (const char *prefBase, const char *prefLeaf, char ***outList, PRInt32 *outCount)
02348 {
02349     nsCAutoString prefName(prefBase);
02350     prefName.Append(".");
02351     prefName.Append(prefLeaf);
02352 
02353     return dir_CreateTokenListFromWholePref(prefName.get(), outList, outCount);
02354 }
02355 
02356 
02357 static nsresult dir_ConvertTokenListToIdList
02358 (DIR_Server *server, char **tokenList, PRInt32 tokenCount, DIR_AttributeId **outList)
02359 {
02360        *outList = (DIR_AttributeId*) PR_Malloc(sizeof(DIR_AttributeId) * tokenCount);
02361        if (*outList)
02362        {
02363               PRInt32 i;
02364               for (i = 0; i < tokenCount; i++)
02365                      DIR_AttributeNameToId(server, tokenList[i], &(*outList)[i]);
02366        }
02367        else
02368               return NS_ERROR_OUT_OF_MEMORY;
02369        return NS_OK;
02370 }
02371 
02372 
02373 static void dir_GetReplicationInfo(const char *prefstring, DIR_Server *server, char *scratch)
02374 {
02375        char replPrefName[128];
02376        PR_ASSERT(server->replInfo == nsnull);
02377 
02378        server->replInfo = (DIR_ReplicationInfo *)PR_Calloc(1, sizeof (DIR_ReplicationInfo));
02379        if (server->replInfo && replPrefName)
02380        {
02381               PRBool prefBool;
02382 
02383               PL_strcpy(replPrefName, prefstring);
02384               PL_strcat(replPrefName, ".replication");
02385 
02386               prefBool = DIR_GetBoolPref(replPrefName, "never", scratch, kDefaultReplicateNever);
02387               DIR_ForceFlag(server, DIR_REPLICATE_NEVER, prefBool);
02388 
02389               prefBool = DIR_GetBoolPref(replPrefName, "enabled", scratch, kDefaultReplicaEnabled);
02390               DIR_ForceFlag(server, DIR_REPLICATION_ENABLED, prefBool);
02391 
02392               server->replInfo->description = DIR_GetStringPref(replPrefName, "description", scratch, kDefaultReplicaDescription);
02393               server->replInfo->syncURL = DIR_GetStringPref(replPrefName, "syncURL", scratch, nsnull);
02394               server->replInfo->filter = DIR_GetStringPref(replPrefName, "filter", scratch, kDefaultReplicaFilter);
02395 
02396           dir_CreateTokenListFromPref(replPrefName, "excludedAttributes", &server->replInfo->excludedAttributes, 
02397                                           &server->replInfo->excludedAttributesCount);
02398 
02399               /* The file name and data version must be set or we ignore the
02400                * remaining replication prefs.
02401                */
02402               server->replInfo->fileName = DIR_GetStringPref(replPrefName, "fileName", scratch, kDefaultReplicaFileName);
02403               server->replInfo->dataVersion = DIR_GetStringPref(replPrefName, "dataVersion", scratch, kDefaultReplicaDataVersion);
02404               if (server->replInfo->fileName && server->replInfo->dataVersion)
02405               {
02406                      server->replInfo->lastChangeNumber = DIR_GetIntPref(replPrefName, "lastChangeNumber", scratch, kDefaultReplicaChangeNumber);
02407               }
02408        }
02409 }
02410 
02411 
02412 /* Called at startup-time to read whatever overrides the LDAP site administrator has
02413  * done to the attribute names
02414  */
02415 static nsresult DIR_GetCustomAttributePrefs(const char *prefstring, DIR_Server *server)
02416 {
02417     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID)); 
02418     if (!pPref)
02419               return NS_ERROR_FAILURE;
02420 
02421     char **tokenList = nsnull;
02422     char **childList = nsnull;
02423 
02424     nsCAutoString branch(prefstring);
02425     branch.Append(".attributes.");
02426 
02427     PRUint32 branchLen = branch.Length();
02428 
02429     PRUint32 prefCount;
02430     nsresult rv = dir_GetChildList(branch, &prefCount, &childList);
02431     if (NS_SUCCEEDED(rv))
02432        {
02433         for (PRUint32 i = 0; i < prefCount; ++i)
02434               {
02435             char *jsValue = nsnull;
02436 
02437             rv = pPref->CopyCharPref(childList[i], &jsValue);
02438             if (NS_SUCCEEDED(rv))
02439                      {
02440                 if (jsValue && jsValue[0])
02441                             {
02442                     char *attrName = childList[i] + branchLen;
02443                     DIR_AddCustomAttribute (server, attrName, jsValue);
02444                             }
02445                 PR_FREEIF(jsValue);
02446                      }
02447               }
02448 
02449         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, childList);
02450        }
02451 
02452     if (0 == dir_CreateTokenListFromPref (prefstring, "basicSearchAttributes",
02453               &tokenList, &server->basicSearchAttributesCount))
02454        {
02455               dir_ConvertTokenListToIdList (server, tokenList, server->basicSearchAttributesCount, 
02456                      &server->basicSearchAttributes);
02457               dir_DeleteTokenList (tokenList, server->basicSearchAttributesCount);
02458        }
02459 
02460        /* The DN, suppressed and url attributes can be attributes that
02461         * we've never heard of, so they're stored by name, so we can match 'em
02462         * as we get 'em from the server
02463         */
02464     dir_CreateTokenListFromPref (prefstring, "html.dnAttributes", 
02465               &server->dnAttributes, &server->dnAttributesCount);
02466     dir_CreateTokenListFromPref (prefstring, "html.excludedAttributes", 
02467               &server->suppressedAttributes, &server->suppressedAttributesCount);
02468     dir_CreateTokenListFromPref (prefstring, "html.uriAttributes",
02469               &server->uriAttributes, &server->uriAttributesCount);
02470 
02471        return NS_OK;
02472 }
02473 
02474 
02475 /* Called at startup-time to read whatever overrides the LDAP site administrator has
02476  * done to the filtering logic
02477  */
02478 static nsresult DIR_GetCustomFilterPrefs(const char *prefstring, DIR_Server *server, char *scratch)
02479 {
02480        char *localScratch = (char*)PR_Malloc(128);
02481        if (!localScratch)
02482               return NS_ERROR_OUT_OF_MEMORY;
02483 
02484     nsresult rv = NS_OK;
02485     PRBool keepGoing = PR_TRUE;
02486     PRInt32 filterNum = 1;
02487 
02488        server->tokenSeps = DIR_GetStringPref (prefstring, "wordSeparators", localScratch, kDefaultTokenSeps);
02489        
02490        do {
02491         char **childList = nsnull;
02492 
02493               PR_snprintf (scratch, 128, "%s.filter%d", prefstring, filterNum);
02494 
02495         nsCAutoString branch(scratch);
02496         branch.Append(".");
02497 
02498         PRUint32 prefCount;
02499         rv = dir_GetChildList(branch, &prefCount, &childList);
02500         if (NS_SUCCEEDED(rv))
02501               {
02502             if (prefCount > 0)
02503                      {
02504                             DIR_Filter *filter = (DIR_Filter*) PR_Malloc (sizeof(DIR_Filter));
02505                             if (filter)
02506                             {
02507                                    PRBool tempBool;
02508                                    memset(filter, 0, sizeof(DIR_Filter));
02509 
02510                                    /* Pull per-filter preferences out of JS values */
02511                                    filter->string = DIR_GetStringPref (scratch, "string", localScratch, 
02512                                           server->efficientWildcards ? kDefaultFilter : kDefaultEfficientFilter);
02513                                    tempBool = DIR_GetBoolPref (scratch, "repeatFilterForWords", localScratch, kDefaultRepeatFilterForTokens);
02514                                    if (tempBool)
02515                                           filter->flags |= DIR_F_REPEAT_FILTER_FOR_TOKENS;
02516                                    tempBool = DIR_GetBoolPref (scratch, "substituteStarsForSpaces", localScratch, kDefaultSubstStarsForSpaces);
02517                                    if (tempBool)
02518                                           filter->flags |= DIR_F_SUBST_STARS_FOR_SPACES;
02519 
02520                                    /* Add resulting DIR_Filter to the list */
02521                                    if (!server->customFilters)
02522                                           server->customFilters = new nsVoidArray();
02523                                    if (server->customFilters)
02524                                           server->customFilters->AppendElement(filter);
02525                                    else
02526                                           rv = NS_ERROR_OUT_OF_MEMORY;
02527                             }
02528                             else
02529                                    rv = NS_ERROR_OUT_OF_MEMORY;
02530                             filterNum++;
02531                      }
02532                      else
02533                             keepGoing = PR_FALSE;
02534             NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, childList);
02535               }
02536               else
02537                      keepGoing = PR_FALSE;
02538        } while (keepGoing && NS_SUCCEEDED(rv));
02539 
02540        PR_Free(localScratch);
02541        return rv;
02542 }
02543 
02544 /* This will convert from the old preference that was a path and filename */
02545 /* to a just a filename */
02546 static void DIR_ConvertServerFileName(DIR_Server* pServer)
02547 {
02548        char* leafName = pServer->fileName;
02549        char* newLeafName = nsnull;
02550 #if defined(XP_WIN) || defined(XP_OS2)
02551        /* jefft -- bug 73349 This is to allow users share same address book.
02552         * It only works if the user specify a full path filename.
02553         */
02554 #ifdef XP_FileIsFullPath
02555        if (! XP_FileIsFullPath(leafName))
02556               newLeafName = XP_STRRCHR (leafName, '\\');
02557 #endif /* XP_FileIsFullPath */
02558 #else
02559        newLeafName = strrchr(leafName, '/');
02560 #endif
02561     pServer->fileName = newLeafName ? nsCRT::strdup(newLeafName + 1) : nsCRT::strdup(leafName);
02562        if (leafName) PR_Free(leafName);
02563 }
02564 
02565 /* This will generate a correct filename and then remove the path.
02566  * Note: we are assuming that the default name is in the native
02567  * filesystem charset. The filename will be returned as a UTF8
02568  * string.
02569  */
02570 void DIR_SetFileName(char** fileName, const char* defaultName)
02571 {
02572        nsresult rv = NS_OK;
02573        nsCOMPtr<nsILocalFile> dbPath;
02574 
02575        *fileName = nsnull;
02576 
02577        nsCOMPtr<nsIAddrBookSession> abSession = 
02578                 do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv); 
02579        if(NS_SUCCEEDED(rv))
02580               rv = abSession->GetUserProfileDirectory(getter_AddRefs(dbPath));
02581        if (NS_SUCCEEDED(rv))
02582        {
02583               rv = dbPath->AppendNative(nsDependentCString(defaultName));
02584               if (NS_SUCCEEDED(rv))
02585               {
02586                 rv = dbPath->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0664);
02587 
02588                 nsAutoString realFileName;
02589                 rv = dbPath->GetLeafName(realFileName);
02590 
02591                 if (NS_SUCCEEDED(rv))
02592                   *fileName = ToNewUTF8String(realFileName);
02593               }
02594        }
02595 }
02596 
02597 /****************************************************************
02598 Helper function used to generate a file name from the description
02599 of a directory. Caller must free returned string. 
02600 An extension is not applied 
02601 *****************************************************************/
02602 
02603 char * dir_ConvertDescriptionToPrefName(DIR_Server * server)
02604 {
02605 #define MAX_PREF_NAME_SIZE 25
02606        char * fileName = nsnull;
02607        char fileNameBuf[MAX_PREF_NAME_SIZE];
02608        PRInt32 srcIndex = 0;
02609        PRInt32 destIndex = 0;
02610        PRInt32 numSrcBytes = 0;
02611        const char * descr = nsnull;
02612        if (server && server->description)
02613        {
02614               descr = server->description;
02615               numSrcBytes = PL_strlen(descr);
02616               while (srcIndex < numSrcBytes && destIndex < MAX_PREF_NAME_SIZE-1)
02617               {
02618                      if (nsCRT::IsAsciiDigit(descr[srcIndex]) || nsCRT::IsAsciiAlpha(descr[srcIndex]) )
02619                      {
02620                             fileNameBuf[destIndex] = descr[srcIndex];
02621                             destIndex++;
02622                      }
02623 
02624                      srcIndex++;
02625               }
02626 
02627               fileNameBuf[destIndex] = '\0'; /* zero out the last character */
02628        }
02629 
02630        if (destIndex) /* have at least one character in the file name? */
02631         fileName = nsCRT::strdup(fileNameBuf);
02632 
02633        return fileName;
02634 }
02635 
02636 
02637 void DIR_SetServerFileName(DIR_Server *server, const char* leafName)
02638 {
02639        char * tempName = nsnull; 
02640        const char * prefName = nsnull;
02641        PRUint32 numHeaderBytes = 0; 
02642 
02643        if (server && (!server->fileName || !(*server->fileName)) )
02644        {
02645           PR_FREEIF(server->fileName); // might be one byte empty string.
02646               /* make sure we have a pref name...*/
02647               if (!server->prefName || !*server->prefName)
02648                      server->prefName = DIR_CreateServerPrefName (server, nsnull);
02649 
02650               /* set default personal address book file name*/
02651               if ((server->position == 1) && (server->dirType == PABDirectory))
02652             server->fileName = nsCRT::strdup(kPersonalAddressbook);
02653               else
02654               {
02655                      /* now use the pref name as the file name since we know the pref name
02656                         will be unique */
02657                      prefName = server->prefName;
02658                      if (prefName && *prefName)
02659                      {
02660                             /* extract just the pref name part and not the ldap tree name portion from the string */
02661                             numHeaderBytes = PL_strlen(PREF_LDAP_SERVER_TREE_NAME) + 1; /* + 1 for the '.' b4 the name */
02662                             if (PL_strlen(prefName) > numHeaderBytes) 
02663                     tempName = nsCRT::strdup(prefName + numHeaderBytes);
02664 
02665                             if (tempName)
02666                             {
02667                                    server->fileName = PR_smprintf("%s%s", tempName, kABFileName_CurrentSuffix);
02668                                    PR_Free(tempName);
02669                             }
02670                      }
02671               }
02672 
02673               if (!server->fileName || !*server->fileName) /* when all else has failed, generate a default name */
02674               {
02675                      if (server->dirType == LDAPDirectory)
02676                             DIR_SetFileName(&(server->fileName), kMainLdapAddressBook); /* generates file name with an ldap prefix */
02677                      else
02678                             DIR_SetFileName(&(server->fileName), kPersonalAddressbook);
02679               }
02680        }
02681 }
02682 
02683 char *DIR_CreateServerPrefName (DIR_Server *server, char *name)
02684 {
02685   /* we are going to try to be smart in how we generate our server
02686      pref name. We'll try to convert the description into a pref name
02687      and then verify that it is unique. If it is unique then use it... */
02688   char * leafName = nsnull;
02689   char * prefName = nsnull;
02690   PRBool isUnique = PR_FALSE;
02691 
02692   if (name)
02693     leafName = nsCRT::strdup(name);
02694   else
02695     leafName = dir_ConvertDescriptionToPrefName (server);
02696 
02697   if (!leafName || !*leafName)
02698   {
02699     // we need to handle this in case the description has no alphanumeric chars
02700     // it's very common for cjk users
02701     leafName = nsCRT::strdup("_nonascii");
02702   }
02703 
02704   if (leafName)
02705   {
02706     PRInt32 uniqueIDCnt = 0;
02707         char **children = nsnull;
02708     /* we need to verify that this pref string name is unique */
02709     prefName = PR_smprintf(PREF_LDAP_SERVER_TREE_NAME".%s", leafName);
02710     isUnique = PR_FALSE;
02711     PRUint32 prefCount;
02712     nsresult rv = dir_GetChildList(NS_LITERAL_CSTRING(PREF_LDAP_SERVER_TREE_NAME "."),
02713                                    &prefCount, &children);
02714     if (NS_SUCCEEDED(rv))
02715     {
02716       while (!isUnique && prefName)
02717       {
02718         isUnique = PR_TRUE; /* now flip the logic and assume we are unique until we find a match */
02719         for (PRUint32 i = 0; i < prefCount && isUnique; ++i)
02720         {
02721           if (!nsCRT::strcasecmp(children[i], prefName)) /* are they the same branch? */
02722             isUnique = PR_FALSE;
02723         }
02724         if (!isUnique) /* then try generating a new pref name and try again */
02725         {
02726           PR_smprintf_free(prefName);
02727           prefName = PR_smprintf(PREF_LDAP_SERVER_TREE_NAME".%s_%d", leafName, ++uniqueIDCnt);
02728         }
02729       } /* if we have a list of pref Names */
02730 
02731       NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, children);
02732     } /* while we don't have a unique name */
02733 
02734     // fallback to "user_directory_N" form if we failed to verify
02735     if (!isUnique && prefName)
02736     {
02737       PR_smprintf_free(prefName);
02738       prefName = nsnull;
02739     }
02740 
02741     PR_Free(leafName);
02742 
02743   } /* if leafName */
02744 
02745   if (!prefName) /* last resort if we still don't have a pref name is to use user_directory string */
02746     return PR_smprintf(PREF_LDAP_SERVER_TREE_NAME".user_directory_%d", ++dir_UserId);
02747   else
02748     return prefName;
02749 }
02750 
02751 void DIR_GetPrefsForOneServer (DIR_Server *server, PRBool reinitialize, PRBool oldstyle /* 4.0 Branch */)
02752 {
02753   nsresult rv = NS_OK;
02754   nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
02755   if (NS_FAILED(rv) || !pPref) 
02756     return;
02757   
02758   PRBool  prefBool;
02759   char    *prefstring = server->prefName;
02760   char     tempstring[256];
02761   char    *csidString  = nsnull;
02762   PRBool forcePrefSave = PR_FALSE;  /* if when reading in the prefs we did something that forces us to save the branch...*/
02763   
02764   if (reinitialize)
02765   {
02766     /* If we're reinitializing, we need to save off the runtime volatile
02767     * data which isn't stored in persistent JS prefs and restore it
02768     */
02769     PRUint32 oldRefCount = server->refCount;
02770     server->prefName = nsnull;
02771     dir_DeleteServerContents(server);
02772     DIR_InitServer(server);
02773     server->prefName = prefstring;
02774     server->refCount = oldRefCount; 
02775   }
02776   
02777   // this call fills in tempstring with the position pref, and
02778   // we then check to see if it's locked.
02779   server->position = DIR_GetIntPref (prefstring, "position", tempstring, kDefaultPosition);
02780   PRBool bIsLocked;
02781   pPref->PrefIsLocked(tempstring, &bIsLocked);
02782   DIR_ForceFlag(server, DIR_UNDELETABLE | DIR_POSITION_LOCKED, bIsLocked);
02783   
02784   server->isSecure = DIR_GetBoolPref (prefstring, "isSecure", tempstring, PR_FALSE);
02785   server->saveResults = DIR_GetBoolPref (prefstring, "saveResults", tempstring, PR_TRUE);                       
02786   server->efficientWildcards = DIR_GetBoolPref (prefstring, "efficientWildcards", tempstring, PR_TRUE);                       
02787   server->port = DIR_GetIntPref (prefstring, "port", tempstring, server->isSecure ? LDAPS_PORT : LDAP_PORT);
02788   if (server->port == 0)
02789     server->port = server->isSecure ? LDAPS_PORT : LDAP_PORT;
02790   server->maxHits = DIR_GetIntPref (prefstring, "maxHits", tempstring, kDefaultMaxHits);
02791   
02792   if (0 == PL_strcmp(prefstring, "ldap_2.servers.pab") || 
02793     0 == PL_strcmp(prefstring, "ldap_2.servers.history")) 
02794   {
02795     // get default address book name from addressbook.properties 
02796     server->description = DIR_GetLocalizedStringPref(prefstring, "description", tempstring, "");
02797   }
02798   else
02799     server->description = DIR_GetStringPref (prefstring, "description", tempstring, "");
02800   
02801   server->serverName = DIR_GetStringPref (prefstring, "serverName", tempstring, "");
02802   server->searchBase = DIR_GetStringPref (prefstring, "searchBase", tempstring, "");
02803   server->isOffline = DIR_GetBoolPref (prefstring, "isOffline", tempstring, kDefaultIsOffline);
02804   server->dirType = (DirectoryType)DIR_GetIntPref (prefstring, "dirType", tempstring, LDAPDirectory);
02805   if (server->dirType == PABDirectory)
02806   {
02807     /* make sure there is a PR_TRUE PAB */
02808     if (!server->serverName || !*server->serverName)
02809       server->isOffline = PR_FALSE;
02810     server->saveResults = PR_TRUE; /* never let someone delete their PAB this way */
02811   }
02812   
02813   /* load in the column attributes */
02814   if (server->dirType == PABDirectory || server->dirType == MAPIDirectory)
02815     server->columnAttributes = DIR_GetStringPref(prefstring, "columns", tempstring, kDefaultPABColumnHeaders);
02816   else
02817     server->columnAttributes = DIR_GetStringPref(prefstring, "columns", tempstring, kDefaultLDAPColumnHeaders);
02818   
02819   server->fileName = DIR_GetStringPref (prefstring, "filename", tempstring, "");
02820   if ( (!server->fileName || !*(server->fileName)) && !oldstyle) /* if we don't have a file name and this is the new branch get a file name */
02821     DIR_SetServerFileName (server, server->serverName);
02822   if (server->fileName && *server->fileName)
02823     DIR_ConvertServerFileName(server);
02824   
02825   // the string "s" is the default uri ( <scheme> + "://" + <filename> )
02826   nsCString s((server->dirType == PABDirectory || server->dirType == MAPIDirectory) ? kMDBDirectoryRoot : kLDAPDirectoryRoot);
02827   s.Append (server->fileName);
02828   server->uri = DIR_GetStringPref (prefstring, "uri", tempstring, s.get ());
02829   
02830   server->lastSearchString = DIR_GetStringPref (prefstring, "searchString", tempstring, "");
02831   
02832   /* This is where site-configurable attributes and filters are read from JavaScript */
02833   DIR_GetCustomAttributePrefs (prefstring, server);
02834   DIR_GetCustomFilterPrefs (prefstring, server, tempstring);
02835   
02836   /* The replicated attributes and basic search attributes can only be
02837         * attributes which are in our predefined set (DIR_AttributeId) so
02838          * store those in an array of IDs for more convenient access
02839         */
02840   dir_GetReplicationInfo (prefstring, server, tempstring);
02841   
02842   server->PalmCategoryId = DIR_GetIntPref (prefstring, "PalmCategoryId", tempstring, -1);
02843   server->PalmSyncTimeStamp = DIR_GetIntPref (prefstring, "PalmSyncTimeStamp", tempstring, 0);
02844   
02845   /* Get authentication prefs */
02846   server->enableAuth = DIR_GetBoolPref (prefstring, "auth.enabled", tempstring, kDefaultEnableAuth);
02847   server->authDn = DIR_GetStringPref (prefstring, "auth.dn", tempstring, nsnull);
02848   server->savePassword = DIR_GetBoolPref (prefstring, "auth.savePassword", tempstring, kDefaultSavePassword);
02849   if (server->savePassword)
02850     server->password = DIR_GetStringPref (prefstring, "auth.password", tempstring, "");
02851   
02852   char *versionString = DIR_GetStringPref(prefstring, "protocolVersion", 
02853                                           tempstring, "3");
02854   DIR_ForceFlag(server, DIR_LDAP_VERSION3, !strcmp(versionString, "3"));
02855   nsCRT::free(versionString);
02856 
02857   prefBool = DIR_GetBoolPref (prefstring, "autoComplete.enabled", tempstring, kDefaultAutoCompleteEnabled);
02858   DIR_ForceFlag (server, DIR_AUTO_COMPLETE_ENABLED, prefBool);
02859   prefBool = DIR_GetBoolPref (prefstring, "autoComplete.never", tempstring, kDefaultAutoCompleteNever);
02860   DIR_ForceFlag (server, DIR_AUTO_COMPLETE_NEVER, prefBool);
02861   server->autoCompleteFilter = DIR_GetStringPref (prefstring, "autoComplete.filter", tempstring, nsnull);
02862   
02863   /* read in the I18N preferences for the directory --> locale and csid */
02864   
02865   /* okay we used to write out the csid as a integer pref called "charset" then we switched to a string pref called "csid" 
02866   for I18n folks. So we want to read in the old integer pref and if it is not kDefaultPABCSID (which is a bogus -1), 
02867   then use it as the csid and when we save the server preferences later on we'll clear the old "charset" pref so we don't
02868   have to do this again. Otherwise, we already have a string pref so use that one */
02869   
02870   csidString = DIR_GetStringPref (prefstring, "csid", tempstring, nsnull);
02871   if (csidString) /* do we have a csid string ? */
02872   {
02873     server->csid = CS_UTF8;
02874     //        server->csid = INTL_CharSetNameToID (csidString);
02875     PR_Free(csidString);
02876   }
02877   else 
02878   { 
02879     /* try to read it in from the old integer style char set preference */
02880     if (server->dirType == PABDirectory || server->dirType == MAPIDirectory)
02881       server->csid = (PRInt16) DIR_GetIntPref (prefstring, "charset", tempstring, kDefaultPABCSID);
02882     else
02883       server->csid = (PRInt16) DIR_GetIntPref (prefstring, "charset", tempstring, kDefaultLDAPCSID);     
02884     
02885     forcePrefSave = PR_TRUE; /* since we read from the old pref we want to force the new pref to be written out */
02886   }
02887   
02888   if (server->csid == CS_DEFAULT || server->csid == CS_UNKNOWN)
02889     server->csid = CS_UTF8;
02890   //          server->csid = INTL_GetCharSetID(INTL_DefaultTextWidgetCsidSel);
02891   
02892   /* now that the csid is taken care of, read in the locale preference */
02893   server->locale = DIR_GetStringPref (prefstring, "locale", tempstring, nsnull);
02894   
02895   prefBool = DIR_GetBoolPref (prefstring, "vlvDisabled", tempstring, kDefaultVLVDisabled);
02896   DIR_ForceFlag (server, DIR_LDAP_VLV_DISABLED | DIR_LDAP_ROOTDSE_PARSED, prefBool);
02897   
02898   server->customDisplayUrl = DIR_GetStringPref (prefstring, "customDisplayUrl", tempstring, "");
02899   
02900   if (!oldstyle /* we don't care about saving old directories */ && forcePrefSave && !dir_IsServerDeleted(server) )
02901     DIR_SavePrefsForOneServer(server); 
02902 }
02903 
02904 /* return total number of directories */
02905 static PRInt32 dir_GetPrefsFrom40Branch(nsVoidArray **list)
02906 {
02907   nsresult rv = NS_OK;
02908   nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
02909   if (NS_FAILED(rv) || !pPref) 
02910     return -1;
02911   
02912   PRInt32 result = -1;
02913   (*list) = new nsVoidArray();
02914   if (!(*list))
02915     return result;
02916   
02917   /* get the preference for how many directories */
02918   if (*list)
02919   {
02920     PRInt32 i = 0;
02921     PRInt32 numDirectories = 0;
02922     
02923     pPref->GetIntPref("ldap_1.number_of_directories", &numDirectories);      
02924     /* ldap_1.directory start from 1 */
02925     for (i = 1; i <= numDirectories; i++)
02926     {
02927       DIR_Server *server;
02928       
02929       server = (DIR_Server *)PR_Calloc(1, sizeof(DIR_Server));
02930       if (server)
02931       {
02932         char *prefName = PR_smprintf("ldap_1.directory%i", i);
02933         if (prefName)
02934         {
02935           DIR_InitServer(server);
02936           server->prefName = prefName;
02937           DIR_GetPrefsForOneServer(server, PR_FALSE, PR_TRUE);                      
02938           PR_smprintf_free(server->prefName);
02939           server->prefName = DIR_CreateServerPrefName (server, nsnull);
02940           /* Leave room for Netcenter */
02941           server->position = (server->dirType == PABDirectory ? i : i + 1);
02942           (*list)->AppendElement(server);
02943         }
02944       }
02945     }
02946     
02947     /* all.js should have filled this stuff in */
02948     PR_ASSERT(numDirectories != 0);
02949     
02950     result = numDirectories;
02951   }
02952   
02953   return result;
02954 }
02955 
02956 static nsresult dir_GetPrefsFrom45Branch(nsVoidArray **list, nsVoidArray **obsoleteList)
02957 {
02958     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID));
02959     if (!pPref)
02960         return NS_ERROR_FAILURE;
02961 
02962     (*list) = new nsVoidArray();
02963     if (!(*list))
02964         return NS_ERROR_OUT_OF_MEMORY;
02965 
02966     if (obsoleteList)
02967     {
02968         (*obsoleteList) = new nsVoidArray();
02969         if (!(*obsoleteList))
02970         {
02971             delete (*list);
02972             return NS_ERROR_OUT_OF_MEMORY;
02973         }
02974     }
02975 
02976     char **children;
02977     PRUint32 prefCount;
02978 
02979     nsresult rv = dir_GetChildList(NS_LITERAL_CSTRING(PREF_LDAP_SERVER_TREE_NAME "."),
02980                                    &prefCount, &children);
02981     if (NS_FAILED(rv))
02982         return rv;
02983 
02984     /* TBD: Temporary code to read broken "ldap" preferences tree.
02985      *      Remove line with if statement after M10.
02986      */
02987     if (dir_UserId == 0)
02988         pPref->GetIntPref(PREF_LDAP_GLOBAL_TREE_NAME".user_id", &dir_UserId);
02989 
02990     for (PRUint32 i = 0; i < prefCount; ++i)
02991     {
02992         DIR_Server *server;
02993 
02994         server = (DIR_Server *)PR_Calloc(1, sizeof(DIR_Server));
02995         if (server)
02996         {
02997             DIR_InitServer(server);
02998             server->prefName = nsCRT::strdup(children[i]);
02999             DIR_GetPrefsForOneServer(server, PR_FALSE, PR_FALSE);
03000             if (server->description && server->description[0] && 
03001                 ((server->dirType == PABDirectory ||
03002                   server->dirType == MAPIDirectory ||
03003                   server->dirType == FixedQueryLDAPDirectory ||  // this one might go away
03004                   server->dirType == LDAPDirectory) ||
03005                  (server->serverName && server->serverName[0])))
03006             {
03007                 if (!dir_IsServerDeleted(server))
03008                 {
03009                     (*list)->AppendElement(server);
03010                 }
03011                 else if (obsoleteList)
03012                     (*obsoleteList)->AppendElement(server);
03013                 else
03014                     DIR_DeleteServer(server);
03015             }
03016             else
03017             {
03018                 DIR_DeleteServer(server);
03019             }
03020         }
03021     }
03022 
03023     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, children);
03024 
03025     return NS_OK;
03026 }
03027 
03028 // I don't think we care about locked positions, etc.
03029 void DIR_SortServersByPosition(nsVoidArray *serverList)
03030 {
03031   int i, j;
03032   DIR_Server *server;
03033   
03034   int count = serverList->Count();
03035   for (i = 0; i < count - 1; i++)
03036   {
03037     for (j = i + 1; j < count; j++)
03038     {
03039       if (((DIR_Server *) serverList->ElementAt(j))->position < ((DIR_Server *) serverList->ElementAt(i))->position)
03040       {
03041         server        = (DIR_Server *) serverList->ElementAt(i);
03042         serverList->ReplaceElementAt(serverList->ElementAt(j), i);
03043         serverList->ReplaceElementAt(server, j);
03044       }
03045     }
03046   }
03047 }
03048 
03049 
03050 nsresult DIR_GetServerPreferences(nsVoidArray** list)
03051 {
03052   nsresult err = NS_OK;
03053   nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &err)); 
03054   if (NS_FAILED(err) || !pPref) 
03055     return NS_ERROR_FAILURE;
03056   
03057   PRInt32 position = 1;
03058   PRInt32 version = -1;
03059   char **oldChildren = nsnull;
03060   PRBool savePrefs = PR_FALSE;
03061   PRBool migrating = PR_FALSE;
03062   nsVoidArray *oldList = nsnull;
03063   nsVoidArray *obsoleteList = nsnull;
03064   nsVoidArray *newList = nsnull;
03065   PRInt32 i, j, count;
03066   
03067   
03068   /* Update the ldap list version and see if there are old prefs to migrate. */
03069   if (pPref->GetIntPref(PREF_LDAP_VERSION_NAME, &version) == PREF_NOERROR)
03070   {
03071     if (version < kPreviousListVersion)
03072     {
03073       pPref->SetIntPref(PREF_LDAP_VERSION_NAME, kCurrentListVersion);
03074       
03075       /* Look to see if there's an old-style "ldap_1" tree in prefs */
03076       PRUint32 prefCount;
03077       err = dir_GetChildList(NS_LITERAL_CSTRING("ldap_1."),
03078         &prefCount, &oldChildren);
03079       if (NS_SUCCEEDED(err))
03080       {
03081         if (prefCount > 0)
03082         {
03083           migrating = PR_TRUE;
03084           position = dir_GetPrefsFrom40Branch(&oldList);
03085         }
03086         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, oldChildren);
03087       }
03088     }
03089   }
03090   
03091   /* Find the new-style "ldap_2.servers" tree in prefs */
03092   err = dir_GetPrefsFrom45Branch(&newList, migrating ? &obsoleteList : nsnull);
03093   
03094   /* Merge the new tree onto the old tree, old on top, new at bottom */
03095   if (NS_SUCCEEDED(err) && oldList && newList)
03096   {
03097     DIR_Server *newServer;
03098     
03099     /* Walk through the new list looking for servers that are duplicates of
03100     * ones in the old list.  Mark any duplicates for non-inclusion in the
03101     * final list.
03102     */
03103     PRInt32 newCount = newList->Count();
03104     for (i = 0; i < newCount; i++)
03105     {
03106       newServer = (DIR_Server *)newList->ElementAt(i);
03107       if (nsnull != newServer)
03108       {
03109         DIR_Server *oldServer;
03110         
03111         PRInt32 oldCount = oldList->Count();
03112         for (j = 0; j < oldCount; j++)
03113         {
03114           oldServer = (DIR_Server *)oldList->ElementAt(j);
03115           if (nsnull != oldServer)
03116           {
03117           /* Don't add servers which are in the old list and don't add a
03118           * second personal address book.
03119             */
03120             if (dir_AreServersSame(newServer, oldServer, PR_FALSE) ||
03121                 (oldServer->dirType == PABDirectory && !oldServer->isOffline &&
03122                  newServer->dirType == PABDirectory && !newServer->isOffline))
03123             {
03124             /* Copy any new prefs out of the new server.
03125               */
03126               PR_FREEIF(oldServer->prefName);
03127               oldServer->prefName  = nsCRT::strdup(newServer->prefName);
03128               /* since the pref name has now been set, we can generate a proper
03129               file name in case we don't have one already */
03130               if (!oldServer->fileName || !*oldServer->fileName)
03131                 DIR_SetServerFileName(oldServer, nsnull); 
03132               
03133               oldServer->flags     = newServer->flags;
03134               
03135               /* Mark the new version of the server as one not to be moved
03136               * to the final list.
03137               */
03138               newServer->position = 0;
03139               break;
03140             }
03141           }
03142         }
03143       }
03144     }
03145     
03146     /* Walk throught the new list again.  This time delete duplicates and
03147     * move the rest to the old (final) list.
03148     */
03149     count = newList->Count();
03150     for (i = count - 1; i >= 0; i--)
03151     {
03152       newServer = (DIR_Server *)newList->ElementAt(i);
03153       if (!dir_IsServerDeleted(newServer))
03154       {
03155       /* Make sure new servers are placed after old servers, but
03156       * keep them in relative order.
03157         */
03158         if (!DIR_TestFlag(newServer, DIR_POSITION_LOCKED))
03159         {
03160         /* The server at position 2 (i.e. Netcenter) must be left
03161         * at position 2.
03162           */
03163           if (newServer->position > 2) 
03164             newServer->position += position;
03165         }
03166         oldList->AppendElement(newServer);
03167       }
03168       else
03169       {
03170         DIR_DecrementServerRefCount(newServer);
03171       }
03172     }
03173     newList->Clear();
03174     DIR_DeleteServerList(newList);
03175     
03176     *list = oldList;
03177     savePrefs = PR_TRUE;
03178   }
03179   else
03180     *list = newList;
03181   
03182     /* Remove any obsolete servers from the list.
03183     * Note that we only remove obsolete servers when we are migrating.  We
03184     * don't do it otherwise because that would keep users from manually
03185     * re-adding these servers (which they should be allowed to do).
03186     */
03187   if (NS_SUCCEEDED(err) && obsoleteList)
03188   {
03189     DIR_Server *obsoleteServer;
03190     nsVoidArray *walkObsoleteList = obsoleteList;
03191     
03192     count = walkObsoleteList->Count();
03193     for (i = 0; i < count;i++)
03194     {
03195       if (nsnull != (obsoleteServer = (DIR_Server *)walkObsoleteList->ElementAt(i)))
03196       {
03197         DIR_Server *existingServer;
03198         nsVoidArray *walkExistingList = *list;
03199         
03200         PRInt32 existCount = walkExistingList->Count();
03201         for (j = 0; j < existCount;j++)
03202         {
03203           existingServer = (DIR_Server *)walkExistingList->ElementAt(j);
03204           if (nsnull != existingServer)
03205           {
03206             if (dir_AreServersSame(existingServer, obsoleteServer, PR_FALSE))
03207             {
03208               savePrefs = PR_TRUE;
03209               DIR_DecrementServerRefCount(existingServer);
03210               (*list)->RemoveElement(existingServer);
03211               break;
03212             }
03213           }
03214         }
03215       }
03216     }
03217   }
03218   if (obsoleteList)
03219     DIR_DeleteServerList(obsoleteList);
03220   
03221   if (version < kCurrentListVersion)
03222   {
03223     pPref->SetIntPref(PREF_LDAP_VERSION_NAME, kCurrentListVersion);
03224     // see if we have the ab upgrader.  if so, skip this, since we
03225     // will be migrating.
03226     nsresult rv;
03227     nsCOMPtr <nsIAbUpgrader> abUpgrader = do_GetService(NS_AB4xUPGRADER_CONTRACTID, &rv);
03228     if (NS_FAILED(rv) || !abUpgrader) 
03229     {
03230       // if we can upgrade, don't touch the 4.x pab.
03231       // if we can't, move the 4.x pab aside
03232       dir_ConvertToMabFileName();
03233     }
03234   }
03235   /* Write the merged list so we get it next time we ask */
03236   if (savePrefs)
03237     DIR_SaveServerPreferences(*list);
03238  
03239   DIR_SortServersByPosition(*list);
03240   return err;
03241 }
03242 
03243 void DIR_ClearPrefBranch(const char *branch)
03244 {
03245   nsresult rv = NS_OK;
03246   nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
03247   if (NS_FAILED(rv) || !pPref) 
03248     return;
03249   
03250   pPref->DeleteBranch (branch);
03251 }
03252 
03253 static void DIR_ClearIntPref (const char *pref)
03254 {
03255     nsresult rv = NS_OK;
03256     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
03257     if (NS_FAILED(rv) || !pPref) 
03258               return;
03259 
03260        PRInt32 oldDefault;
03261        PRInt32 prefErr = pPref->GetDefaultIntPref (pref, &oldDefault);
03262        DIR_ClearPrefBranch (pref);
03263        if (prefErr >= 0)
03264               pPref->SetDefaultIntPref (pref, oldDefault);
03265 }
03266 
03267 
03268 static void DIR_ClearStringPref (const char *pref)
03269 {
03270     nsresult rv = NS_OK;
03271     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
03272     if (NS_FAILED(rv) || !pPref) 
03273               return;
03274 
03275        char *oldDefault = nsnull;
03276        PRInt32 prefErr = pPref->CopyDefaultCharPref (pref, &oldDefault);
03277        DIR_ClearPrefBranch (pref);
03278        if (prefErr >= 0)
03279               pPref->SetDefaultCharPref (pref, oldDefault);
03280        PR_FREEIF(oldDefault);
03281 }
03282 
03283 
03284 static void DIR_ClearBoolPref (const char *pref)
03285 {
03286     nsresult rv = NS_OK;
03287     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
03288     if (NS_FAILED(rv) || !pPref) 
03289               return;
03290 
03291        PRBool oldDefault;
03292        PRInt32 prefErr = pPref->GetDefaultBoolPref (pref, &oldDefault);
03293        DIR_ClearPrefBranch (pref);
03294        if (prefErr >= 0)
03295               pPref->SetDefaultBoolPref (pref, oldDefault);
03296 }
03297 
03298 
03299 static void DIR_SetStringPref (const char *prefRoot, const char *prefLeaf, char *scratch, const char *value, const char *defaultValue)
03300 {
03301     nsresult rv = NS_OK;
03302     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
03303     if (NS_FAILED(rv) || !pPref) 
03304               return;
03305 
03306        char *defaultPref = nsnull;
03307        PRInt32 prefErr = PREF_NOERROR;
03308 
03309        PL_strcpy(scratch, prefRoot);
03310        PL_strcat(scratch, ".");
03311        PL_strcat(scratch, prefLeaf);
03312 
03313        if (PREF_NOERROR == pPref->CopyDefaultCharPref (scratch, &defaultPref))
03314        {
03315               /* If there's a default pref, just set ours in and let libpref worry 
03316                * about potential defaults in all.js
03317                */
03318                if (value) /* added this check to make sure we have a value before we try to set it..*/
03319                      prefErr = pPref->SetCharPref (scratch, value);
03320                else
03321                       DIR_ClearStringPref(scratch);
03322 
03323               PR_Free(defaultPref);
03324        }
03325        else
03326        {
03327               /* If there's no default pref, look for a user pref, and only set our value in
03328                * if the user pref is different than one of them.
03329                */
03330               char *userPref = nsnull;
03331               if (PREF_NOERROR == pPref->CopyCharPref (scratch, &userPref))
03332               {
03333             if (value && (defaultValue ? nsCRT::strcasecmp(value, defaultValue) : value != defaultValue))
03334                             prefErr = pPref->SetCharPref (scratch, value);
03335                      else
03336                             DIR_ClearStringPref (scratch); 
03337               }
03338               else
03339               {
03340             if (value && (defaultValue ? nsCRT::strcasecmp(value, defaultValue) : value != defaultValue))
03341                             prefErr = pPref->SetCharPref (scratch, value); 
03342               }
03343 
03344               PR_FREEIF(userPref);
03345        }
03346 
03347        PR_ASSERT(prefErr >= 0);
03348 }
03349 
03350 
03351 static void DIR_SetIntPref (const char *prefRoot, const char *prefLeaf, char *scratch, PRInt32 value, PRInt32 defaultValue)
03352 {
03353     nsresult rv = NS_OK;
03354     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
03355     if (NS_FAILED(rv) || !pPref) 
03356               return;
03357 
03358        PRInt32 defaultPref;
03359        PRInt32 prefErr = PREF_NOERROR;
03360 
03361        PL_strcpy(scratch, prefRoot);
03362        PL_strcat(scratch, ".");
03363        PL_strcat(scratch, prefLeaf);
03364 
03365        if (PREF_NOERROR == pPref->GetDefaultIntPref (scratch, &defaultPref))
03366        {
03367               /* solve the problem where reordering user prefs must override default prefs */
03368               pPref->SetIntPref (scratch, value);
03369        }
03370        else
03371        {
03372               PRInt32 userPref;
03373               if (PREF_NOERROR == pPref->GetIntPref (scratch, &userPref))
03374               {
03375                      if (value != defaultValue)
03376                             prefErr = pPref->SetIntPref(scratch, value);
03377                      else
03378                             DIR_ClearIntPref (scratch);
03379               }
03380               else
03381               {
03382                      if (value != defaultValue)
03383                             prefErr = pPref->SetIntPref (scratch, value); 
03384               }
03385        }
03386 
03387        PR_ASSERT(prefErr >= 0);
03388 }
03389 
03390 
03391 static void DIR_SetBoolPref (const char *prefRoot, const char *prefLeaf, char *scratch, PRBool value, PRBool defaultValue)
03392 {
03393     nsresult rv = NS_OK;
03394     nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
03395     if (NS_FAILED(rv) || !pPref) 
03396               return;
03397 
03398        PRBool defaultPref;
03399        PRInt32 prefErr = PREF_NOERROR;
03400 
03401        PL_strcpy(scratch, prefRoot);
03402        PL_strcat(scratch, ".");
03403        PL_strcat(scratch, prefLeaf);
03404 
03405        if (PREF_NOERROR == pPref->GetDefaultBoolPref (scratch, &defaultPref))
03406        {
03407               /* solve the problem where reordering user prefs must override default prefs */
03408               prefErr = pPref->SetBoolPref (scratch, value);
03409        }
03410        else
03411        {
03412               PRBool userPref;
03413               if (PREF_NOERROR == pPref->GetBoolPref (scratch, &userPref))
03414               {
03415                      if (value != defaultValue)
03416                             prefErr = pPref->SetBoolPref(scratch, value);
03417                      else
03418                             DIR_ClearBoolPref (scratch);
03419               }
03420               else
03421               {
03422                      if (value != defaultValue)
03423                             prefErr = pPref->SetBoolPref (scratch, value);
03424               }
03425 
03426        }
03427 
03428        PR_ASSERT(prefErr >= 0);
03429 }
03430 
03431 
03432 static nsresult DIR_ConvertAttributeToPrefsString (DIR_Attribute *attrib, char **ppPrefsString)
03433 {
03434        nsresult err = NS_OK;
03435 
03436        /* Compute size in bytes req'd for prefs string */
03437        PRUint32 length = PL_strlen(attrib->prettyName);
03438        PRInt32 i = 0;
03439        while (attrib->attrNames[i])
03440        {
03441               length += PL_strlen(attrib->attrNames[i]) + 1; /* +1 for comma separator */
03442               i++;
03443        }
03444        length += 1; /* +1 for colon */
03445 
03446        /* Allocate prefs string */
03447        *ppPrefsString = (char*) PR_Malloc(length + 1); /* +1 for null term */
03448 
03449        /* Unravel attrib struct back out into prefs */
03450        if (*ppPrefsString)
03451        {
03452               PRInt32 j = 0;
03453               PL_strcpy (*ppPrefsString, attrib->prettyName);
03454               PL_strcat (*ppPrefsString, ":");
03455               while (attrib->attrNames[j])
03456               {
03457                      PL_strcat (*ppPrefsString, attrib->attrNames[j]);
03458                      if (j + 1 < i)
03459                             PL_strcat (*ppPrefsString, ",");
03460                      j++;
03461               }
03462        }
03463        else
03464               err = NS_ERROR_OUT_OF_MEMORY;
03465 
03466        return err;
03467 }
03468 
03469 
03470 static nsresult DIR_SaveOneCustomAttribute (const char *prefRoot, char *scratch, DIR_Server *server, DIR_AttributeId id)
03471 {
03472        const char *name = DIR_GetDefaultAttribute (id)->name;
03473        nsresult err = NS_OK;
03474 
03475        if (server->customAttributes)
03476        {
03477               DIR_Attribute *attrib = nsnull;
03478               nsVoidArray *walkList = server->customAttributes;
03479               PRInt32  count = walkList->Count();
03480               PRInt32  i;
03481               for (i = 0; i < count; i++)
03482               {
03483                      if ((attrib = (DIR_Attribute *)walkList->ElementAt(i)) != nsnull)
03484                      {
03485                             if (attrib->id == id)
03486                             {
03487                                    char *jsString = nsnull;
03488                                    nsresult res = DIR_ConvertAttributeToPrefsString(attrib, &jsString);
03489                                    if (NS_SUCCEEDED(res))
03490                                    {
03491                                           DIR_SetStringPref (prefRoot, name, scratch, jsString, "");
03492                                           PR_Free(jsString);
03493                                           return err;
03494                                    }
03495                             }
03496                      }
03497               }
03498        }
03499 
03500        /* This server doesn't have a custom attribute for the requested ID
03501         * so set it to the null string just in case there's an ALL.JS setting
03502         * or had a previous user value
03503         */
03504        DIR_SetStringPref (prefRoot, name, scratch, "", "");
03505 
03506        return err;
03507 }
03508 
03509 
03510 static nsresult DIR_SaveCustomAttributes (const char *prefRoot, char *scratch, DIR_Server *server)
03511 {
03512        nsresult err = NS_OK;
03513        char *localScratch = (char*) PR_Malloc(256);
03514 
03515        if (localScratch)
03516        {
03517               PL_strcpy(scratch, prefRoot);
03518               PL_strcat(scratch, ".attributes");
03519 
03520               DIR_SaveOneCustomAttribute (scratch, localScratch, server, cn);
03521               DIR_SaveOneCustomAttribute (scratch, localScratch, server, givenname);
03522               DIR_SaveOneCustomAttribute (scratch, localScratch, server, sn);
03523               DIR_SaveOneCustomAttribute (scratch, localScratch, server, mail);
03524               DIR_SaveOneCustomAttribute (scratch, localScratch, server, telephonenumber);
03525               DIR_SaveOneCustomAttribute (scratch, localScratch, server, o);
03526               DIR_SaveOneCustomAttribute (scratch, localScratch, server, ou);
03527               DIR_SaveOneCustomAttribute (scratch, localScratch, server, l);
03528               DIR_SaveOneCustomAttribute (scratch, localScratch, server, street);
03529               DIR_SaveOneCustomAttribute (scratch, localScratch, server, custom1);
03530               DIR_SaveOneCustomAttribute (scratch, localScratch, server, custom2);
03531               DIR_SaveOneCustomAttribute (scratch, localScratch, server, custom3);
03532               DIR_SaveOneCustomAttribute (scratch, localScratch, server, custom4);
03533               DIR_SaveOneCustomAttribute (scratch, localScratch, server, custom5);
03534               DIR_SaveOneCustomAttribute (scratch, localScratch, server, auth);
03535               PR_Free(localScratch);
03536        }
03537        else
03538               err = NS_ERROR_OUT_OF_MEMORY;
03539 
03540        return err;
03541 }
03542 
03543 
03544 static nsresult DIR_SaveCustomFilters (const char *prefRoot, char *scratch, DIR_Server *server)
03545 {
03546        char *localScratch = (char*) PR_Malloc(256);
03547        nsresult err = NS_OK;
03548 
03549        if (!localScratch)
03550               return NS_ERROR_OUT_OF_MEMORY;
03551 
03552        PL_strcpy (scratch, prefRoot);
03553        PL_strcat (scratch, ".filter1");
03554        if (server->customFilters)
03555        {
03556               /* Save the custom filters into the JS prefs */
03557               DIR_Filter *filter = nsnull;
03558               nsVoidArray *walkList = server->customFilters;
03559               PRInt32 count = walkList->Count();
03560               PRInt32 i;
03561               for (i = 0; i < count; i++)
03562               {
03563                      if ((filter = (DIR_Filter *)walkList->ElementAt(i)) != nsnull)
03564                      {
03565                             DIR_SetBoolPref (scratch, "repeatFilterForWords", localScratch, 
03566                                    (filter->flags & DIR_F_REPEAT_FILTER_FOR_TOKENS) != 0, kDefaultRepeatFilterForTokens);
03567                             DIR_SetStringPref (scratch, "string", localScratch, filter->string, kDefaultFilter);
03568                      }
03569               }
03570        }
03571        else
03572        {
03573               /* The DIR_Server object doesn't think it has any custom filters,
03574                * so make sure the prefs settings are empty too
03575                */
03576               DIR_SetBoolPref (scratch, "repeatFilterForWords", localScratch, 
03577                      kDefaultRepeatFilterForTokens, kDefaultRepeatFilterForTokens);
03578               DIR_SetStringPref (scratch, "string", localScratch, kDefaultFilter, kDefaultFilter);
03579        }
03580 
03581        PR_Free(localScratch);
03582        return err;
03583 }
03584 
03585 
03586 static nsresult dir_SaveReplicationInfo (const char *prefRoot, char *scratch, DIR_Server *server)
03587 {
03588        nsresult err = NS_OK;
03589        char *localScratch = (char*) PR_Malloc(256);
03590        if (!localScratch)
03591               return NS_ERROR_OUT_OF_MEMORY;
03592 
03593        PL_strcpy (scratch, prefRoot);
03594        PL_strcat (scratch, ".replication");
03595 
03596        DIR_SetBoolPref (scratch, "never", localScratch, DIR_TestFlag (server, DIR_REPLICATE_NEVER), kDefaultReplicateNever);
03597        DIR_SetBoolPref (scratch, "enabled", localScratch, DIR_TestFlag (server, DIR_REPLICATION_ENABLED), kDefaultReplicaEnabled);
03598 
03599        if (server->replInfo)
03600        {
03601               char *excludedList = nsnull;
03602               PRInt32 i;
03603               PRInt32 excludedLength = 0;
03604               for (i = 0; i < server->replInfo->excludedAttributesCount; i++)
03605                      excludedLength += PL_strlen (server->replInfo->excludedAttributes[i]) + 2; /* +2 for ", " */
03606               if (excludedLength)
03607               {
03608                      excludedList = (char*) PR_Malloc (excludedLength + 1);
03609                      if (excludedList)
03610                      {
03611                             excludedList[0] = '\0';
03612                             for (i = 0; i < server->replInfo->excludedAttributesCount; i++)
03613                             {
03614                                    PL_strcat (excludedList, server->replInfo->excludedAttributes[i]);
03615                                    PL_strcat (excludedList, ", ");
03616                             }
03617                      }
03618                      else
03619                             err = NS_ERROR_OUT_OF_MEMORY;
03620               }
03621 
03622               DIR_SetStringPref (scratch, "excludedAttributes", localScratch, excludedList, kDefaultReplicaExcludedAttributes);
03623 
03624               DIR_SetStringPref (scratch, "description", localScratch, server->replInfo->description, kDefaultReplicaDescription);
03625               DIR_SetStringPref (scratch, "fileName", localScratch, server->replInfo->fileName, kDefaultReplicaFileName);
03626               DIR_SetStringPref (scratch, "filter", localScratch, server->replInfo->filter, kDefaultReplicaFilter);
03627               DIR_SetIntPref (scratch, "lastChangeNumber", localScratch, server->replInfo->lastChangeNumber, kDefaultReplicaChangeNumber);
03628               DIR_SetStringPref (scratch, "syncURL", localScratch, server->replInfo->syncURL, nsnull);
03629               DIR_SetStringPref (scratch, "dataVersion", localScratch, server->replInfo->dataVersion, kDefaultReplicaDataVersion);
03630        }
03631        else if (DIR_TestFlag (server, DIR_REPLICATION_ENABLED))
03632               server->replInfo = (DIR_ReplicationInfo *) PR_Calloc (1, sizeof(DIR_ReplicationInfo));
03633 
03634        PR_Free(localScratch);
03635        return err;
03636 }
03637 
03638 
03639 void DIR_SavePrefsForOneServer(DIR_Server *server)
03640 {
03641        char *prefstring;
03642        char tempstring[256];
03643        char * csidAsString = nsnull;
03644 
03645        if (server->prefName == nsnull)
03646               server->prefName = DIR_CreateServerPrefName (server, nsnull);
03647        prefstring = server->prefName;
03648 
03649        DIR_SetFlag(server, DIR_SAVING_SERVER);
03650 
03651        DIR_SetIntPref (prefstring, "position", tempstring, server->position, kDefaultPosition);
03652 
03653        // Only save the non-default address book name
03654        if (0 != PL_strcmp(prefstring, "ldap_2.servers.pab") &&
03655               0 != PL_strcmp(prefstring, "ldap_2.servers.history")) 
03656               DIR_SetStringPref (prefstring, "description", tempstring, server->description, "");
03657 
03658        DIR_SetStringPref (prefstring, "serverName", tempstring, server->serverName, "");
03659        DIR_SetStringPref (prefstring, "searchBase", tempstring, server->searchBase, "");
03660        DIR_SetStringPref (prefstring, "filename", tempstring, server->fileName, "");
03661        if (server->port == 0)
03662               server->port = server->isSecure ? LDAPS_PORT : LDAP_PORT;
03663        DIR_SetIntPref (prefstring, "port", tempstring, server->port, server->isSecure ? LDAPS_PORT : LDAP_PORT);
03664        DIR_SetIntPref (prefstring, "maxHits", tempstring, server->maxHits, kDefaultMaxHits);
03665        DIR_SetBoolPref (prefstring, "isSecure", tempstring, server->isSecure, PR_FALSE);
03666        DIR_SetBoolPref (prefstring, "saveResults", tempstring, server->saveResults, PR_TRUE);
03667        DIR_SetBoolPref (prefstring, "efficientWildcards", tempstring, server->efficientWildcards, PR_TRUE);
03668        DIR_SetStringPref (prefstring, "searchString", tempstring, server->lastSearchString, "");
03669        DIR_SetIntPref (prefstring, "dirType", tempstring, server->dirType, LDAPDirectory);
03670        DIR_SetBoolPref (prefstring, "isOffline", tempstring, server->isOffline, kDefaultIsOffline);
03671 
03672   if (server->dirType == LDAPDirectory)
03673       DIR_SetStringPref(prefstring, "uri", tempstring, server->uri, "");
03674 
03675        /* save the column attributes */
03676        if (server->dirType == PABDirectory || server->dirType == MAPIDirectory)
03677               DIR_SetStringPref(prefstring, "columns", tempstring, server->columnAttributes, kDefaultPABColumnHeaders);
03678        else
03679               DIR_SetStringPref(prefstring, "columns", tempstring, server->columnAttributes, kDefaultLDAPColumnHeaders);
03680 
03681        DIR_SetBoolPref (prefstring, "autoComplete.enabled", tempstring, DIR_TestFlag(server, DIR_AUTO_COMPLETE_ENABLED), kDefaultAutoCompleteEnabled);
03682        DIR_SetStringPref (prefstring, "autoComplete.filter", tempstring, server->autoCompleteFilter, nsnull);
03683        DIR_SetBoolPref (prefstring, "autoComplete.never", tempstring, DIR_TestFlag(server, DIR_AUTO_COMPLETE_NEVER), kDefaultAutoCompleteNever);
03684 
03685        /* save the I18N information for the directory */
03686        
03687        /* I18N folks want us to save out the csid as a string.....*/
03688 /*     csidAsString = (char *) INTL_CsidToCharsetNamePt(server->csid);*/ /* this string is actually static we should not free it!!! */
03689        csidAsString = NULL; /* this string is actually static we should not free it!!! */
03690        if (csidAsString)
03691               DIR_SetStringPref(prefstring, "csid", tempstring, csidAsString, nsnull);
03692        
03693        /* since we are no longer writing out the csid as an integer, make sure that preference is removed.
03694           kDefaultPABCSID is a bogus csid value that when we read back in we can recognize as an outdated pref */
03695 
03696        /* this is dirty but it works...this is how we assemble the pref name in all of the DIR_SetString/bool/intPref functions */
03697        PL_strcpy(tempstring, prefstring);
03698        PL_strcat(tempstring, ".");
03699        PL_strcat(tempstring, "charset");
03700        DIR_ClearIntPref(tempstring);  /* now clear the pref */
03701 
03702        /* now save the locale string */
03703        DIR_SetStringPref(prefstring, "locale", tempstring, server->locale, nsnull);
03704 
03705        /* Save authentication prefs */
03706        DIR_SetBoolPref (prefstring, "auth.enabled", tempstring, server->enableAuth, kDefaultEnableAuth);
03707        DIR_SetBoolPref (prefstring, "auth.savePassword", tempstring, server->savePassword, kDefaultSavePassword);
03708     DIR_SetStringPref (prefstring, "auth.dn", tempstring, server->authDn, "");
03709        if (server->savePassword && server->authDn && server->password)
03710        {
03711               DIR_SetStringPref (prefstring, "auth.password", tempstring, server->password, "");
03712        }
03713        else
03714        {
03715               DIR_SetStringPref (prefstring, "auth.password", tempstring, "", "");
03716               PR_FREEIF (server->password);
03717        }
03718 
03719        DIR_SetBoolPref (prefstring, "vlvDisabled", tempstring, DIR_TestFlag(server, DIR_LDAP_VLV_DISABLED), kDefaultVLVDisabled);
03720 
03721         DIR_SetStringPref(prefstring, "protocolVersion", tempstring,
03722                           DIR_TestFlag(server, DIR_LDAP_VERSION3) ? "3" : "2",
03723                           "3");
03724 
03725        DIR_SaveCustomAttributes (prefstring, tempstring, server);
03726        DIR_SaveCustomFilters (prefstring, tempstring, server);
03727 
03728        dir_SaveReplicationInfo (prefstring, tempstring, server);
03729        
03730        DIR_SetIntPref (prefstring, "PalmCategoryId", tempstring, server->PalmCategoryId, -1);
03731        DIR_SetIntPref (prefstring, "PalmSyncTimeStamp", tempstring, server->PalmSyncTimeStamp, 0);
03732 
03733        DIR_SetStringPref (prefstring, "customDisplayUrl", tempstring, server->customDisplayUrl, "");
03734 
03735        DIR_ClearFlag(server, DIR_SAVING_SERVER);
03736 }
03737 
03738 nsresult DIR_SaveServerPreferences (nsVoidArray *wholeList)
03739 {
03740        if (wholeList)
03741        {
03742               nsresult rv = NS_OK;
03743               nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 
03744               if (NS_FAILED(rv) || !pPref) 
03745                      return NS_ERROR_FAILURE;
03746 
03747               PRInt32  i;
03748               PRInt32  count = wholeList->Count();
03749               DIR_Server *server;
03750 
03751               for (i = 0; i < count; i++)
03752               {
03753                      server = (DIR_Server *) wholeList->ElementAt(i);
03754                      if (server)
03755                             DIR_SavePrefsForOneServer(server);
03756               }
03757               pPref->SetIntPref(PREF_LDAP_GLOBAL_TREE_NAME".user_id", dir_UserId);
03758        }
03759 
03760        return NS_OK;
03761 }
03762 
03763 /*****************************************************************************
03764  * Functions for getting site-configurable preferences, from JavaScript if
03765  * the site admin has provided them, else out of thin air.
03766  */
03767 
03768 static DIR_DefaultAttribute *DIR_GetDefaultAttribute (DIR_AttributeId id)
03769 {
03770        PRInt32 i = 0;
03771 
03772        static DIR_DefaultAttribute defaults[32];
03773 
03774        if (defaults[0].name == nsnull)
03775        {
03776               defaults[0].id = cn;
03777               defaults[0].resourceId = MK_LDAP_COMMON_NAME;
03778               defaults[0].name = "cn";
03779        
03780               defaults[1].id = givenname;
03781               defaults[1].resourceId = MK_LDAP_GIVEN_NAME;
03782               defaults[1].name = "givenname";
03783        
03784               defaults[2].id = sn;
03785               defaults[2].resourceId = MK_LDAP_SURNAME;
03786               defaults[2].name = "sn";
03787        
03788               defaults[3].id = mail;
03789               defaults[3].resourceId = MK_LDAP_EMAIL_ADDRESS;
03790               defaults[3].name = "mail";
03791        
03792               defaults[4].id = telephonenumber;
03793               defaults[4].resourceId = MK_LDAP_PHONE_NUMBER;
03794               defaults[4].name = "telephonenumber";
03795        
03796               defaults[5].id = o;
03797               defaults[5].resourceId = MK_LDAP_ORGANIZATION;
03798               defaults[5].name = "o";
03799        
03800               defaults[6].id = ou;
03801               defaults[6].resourceId = MK_LDAP_ORG_UNIT;
03802               defaults[6].name = "ou";
03803        
03804               defaults[7].id = l;
03805               defaults[7].resourceId = MK_LDAP_LOCALITY;
03806               defaults[7].name = "l";
03807        
03808               defaults[8].id = street;
03809               defaults[8].resourceId = MK_LDAP_STREET;
03810               defaults[8].name = "street";
03811        
03812               defaults[9].id = custom1;
03813               defaults[9].resourceId = MK_LDAP_CUSTOM1;
03814               defaults[9].name = "custom1";
03815        
03816               defaults[10].id = custom2;
03817               defaults[10].resourceId = MK_LDAP_CUSTOM2;
03818               defaults[10].name = "custom2";
03819        
03820               defaults[11].id = custom3;
03821               defaults[11].resourceId = MK_LDAP_CUSTOM3;
03822               defaults[11].name = "custom3";
03823        
03824               defaults[12].id = custom4;
03825               defaults[12].resourceId = MK_LDAP_CUSTOM4;
03826               defaults[12].name = "custom4";
03827        
03828               defaults[13].id = custom5;
03829               defaults[13].resourceId = MK_LDAP_CUSTOM5;
03830               defaults[13].name = "custom5";
03831 
03832               defaults[14].id = auth;
03833               defaults[14].resourceId = MK_LDAP_EMAIL_ADDRESS;
03834               defaults[14].name = "mail";
03835 
03836               defaults[15].id = carlicense;
03837               defaults[15].resourceId = MK_LDAP_CAR_LICENSE;
03838               defaults[15].name = "carlicense";
03839 
03840               defaults[16].id = businesscategory;
03841               defaults[16].resourceId = MK_LDAP_BUSINESS_CAT;
03842               defaults[16].name = "businesscategory";
03843 
03844               defaults[17].id = departmentnumber;
03845               defaults[17].resourceId = MK_LDAP_DEPT_NUMBER;
03846               defaults[17].name = "businesscategory";
03847 
03848               defaults[18].id = description;
03849               defaults[18].resourceId = MK_LDAP_DESCRIPTION;
03850               defaults[18].name = "description";
03851 
03852               defaults[19].id = employeetype;
03853               defaults[19].resourceId = MK_LDAP_EMPLOYEE_TYPE;
03854               defaults[19].name = "employeetype";
03855 
03856               defaults[20].id = facsimiletelephonenumber;
03857               defaults[20].resourceId = MK_LDAP_FAX_NUMBER;
03858               defaults[20].name = "facsimiletelephonenumber";
03859 
03860               defaults[21].id = manager;
03861               defaults[21].resourceId = MK_LDAP_MANAGER;
03862               defaults[21].name = "manager";
03863 
03864               defaults[22].id = objectclass;
03865               defaults[22].resourceId = MK_LDAP_OBJECT_CLASS;
03866               defaults[22].name = "objectclass";
03867 
03868               defaults[23].id = postaladdress;
03869               defaults[23].resourceId = MK_LDAP_POSTAL_ADDRESS;
03870               defaults[23].name = "postaladdress";
03871 
03872               defaults[24].id = postalcode;
03873               defaults[24].resourceId = MK_LDAP_POSTAL_CODE;
03874               defaults[24].name = "postalcode";
03875 
03876               defaults[25].id = secretary;
03877               defaults[25].resourceId = MK_LDAP_SECRETARY;
03878               defaults[25].name = "secretary";
03879 
03880               defaults[26].id = title;
03881               defaults[26].resourceId = MK_LDAP_TITLE;
03882               defaults[26].name = "title";
03883 
03884               defaults[27].id = nickname;
03885               defaults[27].resourceId = MK_LDAP_NICK_NAME;
03886               defaults[27].name = "nickname";
03887 
03888               defaults[28].id = homephone;
03889               defaults[28].resourceId = MK_LDAP_HOMEPHONE;
03890               defaults[28].name = "homephone";
03891 
03892               defaults[29].id = pager;
03893               defaults[29].resourceId = MK_LDAP_PAGER;
03894               defaults[29].name = "pager";
03895 
03896               defaults[30].id = mobiletelephonenumber;
03897               defaults[30].resourceId = MK_LDAP_MOBILEPHONE;
03898               defaults[30].name = "mobiletelephonenumber";
03899 
03900               defaults[31].id = cn;
03901               defaults[31].resourceId = 0;
03902               defaults[31].name = nsnull;
03903        }
03904 
03905        while (defaults[i].name)
03906        {
03907               if (defaults[i].id == id)
03908                      return &defaults[i];
03909               i++;
03910        }
03911 
03912        return nsnull;
03913 }
03914 
03915 const char *DIR_GetAttributeName (DIR_Server *server, DIR_AttributeId id)
03916 {
03917        char *result = nsnull;
03918 
03919        /* First look in the custom attributes in case the attribute is overridden */
03920        nsVoidArray *list = server->customAttributes;
03921        DIR_Attribute *walkList = nsnull;
03922 
03923        PRInt32  count = list->Count();
03924        PRInt32  i;
03925        for (i = 0; i < count; i++)
03926        {
03927               if ((walkList = (DIR_Attribute *)list->ElementAt(i)) != nsnull)
03928               {
03929                      if (walkList->id == id)
03930                             result = walkList->prettyName;
03931               }
03932        }
03933 
03934        /* If we didn't find it, look in our own static list of attributes */
03935 //     if (!result)
03936 //     {
03937 //            DIR_DefaultAttribute *def;
03938 //            if ((def = DIR_GetDefaultAttribute(id)) != nsnull)
03939 //                   result = (char*)XP_GetString(def->resourceId);
03940 //     }
03941 
03942        return result;
03943 }
03944 
03945 
03946 const char **DIR_GetAttributeStrings (DIR_Server *server, DIR_AttributeId id)
03947 {
03948        const char **result = nsnull;
03949 
03950        if (server && server->customAttributes)
03951        {
03952               /* First look in the custom attributes in case the attribute is overridden */
03953               nsVoidArray *list = server->customAttributes;
03954               DIR_Attribute *walkList = nsnull;
03955               PRInt32  count = list->Count();
03956               PRInt32  i;
03957               for (i = 0; i < count; i++)
03958               {
03959                      while ((walkList = (DIR_Attribute *)list->ElementAt(i)) != nsnull)
03960                      {
03961                             if (walkList->id == id)
03962                                    result = (const char**)walkList->attrNames;
03963                      }
03964               }
03965        }
03966 
03967        /* If we didn't find it, look in our own static list of attributes */
03968        if (!result)
03969        {
03970               static const char *array[2];
03971               array[0] = DIR_GetDefaultAttribute(id)->name;
03972               array[1] = nsnull;
03973               result = (const char**)array;
03974        }
03975        return result;
03976 }
03977 
03978 
03979 const char *DIR_GetFirstAttributeString (DIR_Server *server, DIR_AttributeId id)
03980 {
03981        const char **array = DIR_GetAttributeStrings (server, id);
03982        return array[0];
03983 }
03984 
03985 const char *DIR_GetReplicationFilter (DIR_Server *server)
03986 {
03987        if (server && server->replInfo)
03988               return server->replInfo->filter;
03989        else
03990               return nsnull;
03991 }
03992 
03993 const char *DIR_GetFilterString (DIR_Server *server)
03994 {
03995        if (!server)
03996               return nsnull;
03997 
03998        DIR_Filter *filter = (DIR_Filter *)server->customFilters->SafeElementAt(0);
03999        if (filter)
04000               return filter->string;
04001        return nsnull;
04002 }
04003 
04004 
04005 static DIR_Filter *DIR_LookupFilter (DIR_Server *server, const char *filter)
04006 {
04007        if (!server)
04008               return nsnull;
04009 
04010        nsVoidArray *list = server->customFilters;
04011        DIR_Filter *walkFilter = nsnull;
04012 
04013        PRInt32  count = list->Count();
04014        PRInt32  i;
04015        for (i = 0; i < count; i++)
04016        {
04017               if ((walkFilter = (DIR_Filter *)list->ElementAt(i)) != nsnull)
04018             if (!nsCRT::strcasecmp(filter, walkFilter->string))
04019                             return walkFilter;
04020        }
04021        return nsnull;
04022 }
04023 
04024 
04025 PRBool DIR_RepeatFilterForTokens (DIR_Server *server, const char *filter)
04026 {
04027        if (!server)
04028               return nsnull;
04029 
04030        DIR_Filter *f;
04031        
04032        if (!filter)
04033               f = (DIR_Filter *)server->customFilters->SafeElementAt(0);
04034        else
04035               f = DIR_LookupFilter (server, filter);
04036 
04037        return f ? (f->flags & DIR_F_REPEAT_FILTER_FOR_TOKENS) != 0 : kDefaultRepeatFilterForTokens;
04038 }
04039 
04040 
04041 PRBool DIR_SubstStarsForSpaces (DIR_Server *server, const char *filter)
04042 {
04043        const DIR_Filter *filterStruct = DIR_LookupFilter (server, filter);
04044        if (filterStruct)
04045               return (filterStruct->flags & DIR_F_SUBST_STARS_FOR_SPACES) != 0;
04046 
04047        return kDefaultSubstStarsForSpaces;
04048 }
04049 
04050 
04051 const char *DIR_GetTokenSeparators (DIR_Server *server)
04052 {
04053        return server->tokenSeps ? server->tokenSeps : kDefaultTokenSeps;
04054 }
04055 
04056 PRBool DIR_UseCustomAttribute (DIR_Server *server, DIR_AttributeId id)
04057 {
04058        nsVoidArray *list = server->customAttributes;
04059        DIR_Attribute *walkList = nsnull;
04060 
04061        PRInt32  count = list->Count();
04062        PRInt32  i;
04063        for (i = 0; i < count; i++)
04064        {
04065               if ((walkList = (DIR_Attribute *)list->ElementAt(i)) != nsnull)
04066                      if (walkList->id == id)
04067                             return PR_TRUE;
04068        }
04069        return PR_FALSE;
04070 }
04071 
04072 
04073 PRBool DIR_IsDnAttribute (DIR_Server *s, const char *attrib)
04074 {
04075        if (s && s->dnAttributes)
04076        {
04077               /* Look in the server object to see if there are prefs to tell
04078                * us which attributes contain DNs
04079                */
04080               PRInt32 i;
04081               for (i = 0; i < s->dnAttributesCount; i++)
04082               {
04083             if (!nsCRT::strcasecmp(attrib, s->dnAttributes[i]))
04084                             return PR_TRUE;
04085               }
04086        }
04087        else
04088        {
04089               /* We have some default guesses about what attributes 
04090                * are likely to contain DNs 
04091                */
04092               switch (tolower(attrib[0]))
04093               {
04094               case 'm':
04095             if (!nsCRT::strcasecmp(attrib, "manager") || 
04096                 !nsCRT::strcasecmp(attrib, "member"))
04097                             return PR_TRUE;
04098                      break;
04099               case 'o':
04100             if (!nsCRT::strcasecmp(attrib, "owner"))
04101                             return PR_TRUE;
04102                      break;
04103               case 'u':
04104             if (!nsCRT::strcasecmp(attrib, "uniquemember"))
04105                             return PR_TRUE;
04106                      break;
04107               }
04108        }
04109        return PR_FALSE;
04110 }
04111 
04112 
04113 PRBool DIR_IsAttributeExcludedFromHtml (DIR_Server *s, const char *attrib)
04114 {
04115        if (s && s->suppressedAttributes)
04116        {
04117               /* Look in the server object to see if there are prefs to tell
04118                * us which attributes shouldn't be shown in HTML
04119                */
04120               PRInt32 i;
04121               for (i = 0; i < s->suppressedAttributesCount; i++)
04122               {
04123             if (!nsCRT::strcasecmp(attrib, s->suppressedAttributes[i]))
04124                             return PR_TRUE;
04125               }
04126        }
04127        /* else don't exclude it. By default we show everything */
04128 
04129        return PR_FALSE;
04130 }
04131 
04132 PRBool DIR_IsUriAttribute (DIR_Server *s, const char *attrib)
04133 {
04134        if (s && s->uriAttributes)
04135        {
04136               /* Look in the server object to see if there are prefs to tell
04137                * us which attributes are URLs
04138                */
04139               PRInt32 i;
04140               for (i = 0; i < s->uriAttributesCount; i++)
04141               {
04142             if (!nsCRT::strcasecmp(attrib, s->uriAttributes[i]))
04143                             return PR_TRUE;
04144               }
04145        }
04146        else
04147        {
04148               /* We have some default guesses about what attributes 
04149                * are likely to contain URLs
04150                */
04151               switch (tolower(attrib[0]))
04152               {
04153               case 'l':
04154             if (   !nsCRT::strcasecmp(attrib, "labeleduri")
04155                 || !nsCRT::strcasecmp(attrib, "labeledurl"))
04156                             return PR_TRUE;
04157                      break;
04158               case 'u':
04159             if (!nsCRT::strcasecmp(attrib, "url"))
04160                             return PR_TRUE;
04161                      break;
04162               }
04163        }
04164        return PR_FALSE;
04165 }
04166 
04167 void DIR_SetAuthDN (DIR_Server *s, const char *dn)
04168 {
04169        char *tmp = nsnull;
04170 
04171        PR_ASSERT(dn && s);
04172        if (!dn || !s)
04173               return;
04174        if (s->authDn && !PL_strcmp(dn, s->authDn))
04175               return; /* no change - no need to broadcast */
04176 
04177     tmp = nsCRT::strdup (dn);
04178        if (tmp)
04179        {
04180               /* Always remember the authDn in the DIR_Server, so that users only
04181                * have to authenticate to the server once during a session. Whether
04182                * or not we push the authDN into the prefs is a separate issue, and 
04183                * is covered by the prefs read/write code
04184                */
04185               PR_FREEIF(s->authDn);
04186               s->authDn = tmp;
04187        }
04188        if (s->savePassword)
04189               DIR_SavePrefsForOneServer (s);
04190 }
04191 
04192 
04193 void DIR_SetPassword (DIR_Server *s, const char *password)
04194 {
04195        char *tmp = nsnull;
04196 
04197        PR_ASSERT(password && s);
04198        if (!password || !s)
04199               return; 
04200        if (s->password && !PL_strcmp(password, s->password))
04201               return; /* no change - no need to broadcast */
04202 
04203     tmp = nsCRT::strdup (password);
04204        if (tmp)
04205        {
04206               /* Always remember the password in the DIR_Server, so that users only
04207                * have to authenticate to the server once during a session. Whether
04208                * or not we push the password into the prefs is a separate issue, and 
04209                * is covered by the prefs read/write code
04210                */
04211               PR_FREEIF(s->password);
04212               s->password = tmp;
04213        }
04214        if (s->savePassword)
04215               DIR_SavePrefsForOneServer (s);
04216 }
04217 
04218 
04219 PRBool DIR_IsEscapedAttribute (DIR_Server *s, const char *attrib)
04220 {
04221        /* We're not exposing this setting in JS prefs right now, but in case we
04222         * might want to in the future, leave the DIR_Server* in the prototype.
04223         */
04224 
04225        switch (tolower(attrib[0]))
04226        {
04227        case 'p':
04228         if (!nsCRT::strcasecmp(attrib, "postaladdress"))
04229                      return PR_TRUE;
04230               break;
04231        case 'f': 
04232         if (!nsCRT::strcasecmp(attrib, "facsimiletelephonenumber"))
04233                      return PR_TRUE;
04234               break;
04235        case 'o':
04236         if (!nsCRT::strcasecmp(attrib, "othermail"))
04237                      return PR_TRUE;
04238               break;
04239        }
04240        return PR_FALSE;
04241 }
04242 
04243 
04244 char *DIR_Unescape (const char *src, PRBool makeHtml)
04245 {
04246 /* Borrowed from libnet\mkparse.c */
04247 #define UNHEX(C) \
04248        ((C >= '0' && C <= '9') ? C - '0' : \
04249        ((C >= 'A' && C <= 'F') ? C - 'A' + 10 : \
04250        ((C >= 'a' && C <= 'f') ? C - 'a' + 10 : 0)))
04251 
04252        char *dest = nsnull;
04253        PRUint32 destLength = 0;
04254 
04255        PRUint32 dollarCount = 0;
04256        PRUint32 convertedLengthOfDollar = makeHtml ? 4 : 1;
04257 
04258        const char *tmpSrc = src;
04259 
04260        while (*tmpSrc)
04261               if (*tmpSrc++ == '$')
04262                      dollarCount++;
04263 
04264        destLength = PL_strlen(src) + (dollarCount * convertedLengthOfDollar);
04265        dest = (char*) PR_Malloc (destLength + 1);
04266        if (dest)
04267        {
04268               char *tmpDst = dest;
04269               *dest = '\0';
04270               tmpSrc = src;
04271 
04272               while (*tmpSrc)
04273               {
04274                      switch (*tmpSrc)
04275                      {
04276                      case '$':
04277                             /* A dollar sign is a linebreak. This is easy for HTML, but if we're converting
04278                              * for the Address Book or something without multiple lines, just put in a space
04279                              */
04280                             if (makeHtml)
04281                             {
04282                                    *tmpDst++ = '<';
04283                                    *tmpDst++ = 'B';
04284                                    *tmpDst++ = 'R';
04285                                    *tmpDst++ = '>';
04286                             }
04287                             else
04288                                    *tmpDst++ = ' ';
04289                             break;
04290                      case '\\': {
04291                             /* A backslash indicates that two hex digits follow, which we're supposed to
04292                              * convert. The spec sez that '$', '#' and '\'' (single quote) must be encoded
04293                              * this way. 
04294                              */
04295                             PRBool didEscape = PR_FALSE;
04296                             char c1 = *(tmpSrc + 1);
04297                             if (c1 && (nsCRT::IsAsciiDigit(c1) || nsCRT::IsAsciiAlpha(c1)))
04298                             {
04299                                    char c2 = *(tmpSrc + 2);
04300                                    if (c2 && (nsCRT::IsAsciiDigit(c2) || nsCRT::IsAsciiAlpha(c2)))
04301                                    {
04302                                           *tmpDst++ = (UNHEX(c1) << 4) | UNHEX(c2);
04303                                           tmpSrc +=2;
04304                                           didEscape = PR_TRUE;
04305                                    }
04306                             }
04307                             if (!didEscape)
04308                                    *tmpDst++ = *tmpSrc;
04309                      }
04310                      break;
04311                      default:
04312                             /* Just a plain old char -- copy it over */
04313                             *tmpDst++ = *tmpSrc;
04314                      }
04315                      tmpSrc++;
04316               }
04317               *tmpDst = '\0';
04318        }
04319 
04320        return dest;
04321 }
04322 
04323 #endif /* #if !defined(MOZADDRSTANDALONE) */
04324 
04325 PRBool DIR_TestFlag (DIR_Server *server, PRUint32 flag)
04326 {
04327        if (server)
04328               return NS_OK != (server->flags & flag);
04329        return PR_FALSE;
04330 }
04331 
04332 void DIR_SetFlag (DIR_Server *server, PRUint32 flag)
04333 {
04334        PR_ASSERT(server);
04335        if (server)
04336               server->flags |= flag;
04337 }
04338 
04339 void DIR_ClearFlag (DIR_Server *server, PRUint32 flag)
04340 {
04341        PR_ASSERT(server);
04342        if (server)
04343               server->flags &= ~flag;
04344 }
04345 
04346 
04347 void DIR_ForceFlag (DIR_Server *server, PRUint32 flag, PRBool setIt)
04348 {
04349        PR_ASSERT(server);
04350        if (server)
04351        {
04352               if (setIt)
04353                      server->flags |= flag;
04354               else
04355                      server->flags &= ~flag;
04356        }
04357 }
04358 
04359 
04360 /* Centralize this charset conversion so everyone can do the UTF8 conversion
04361  * in the same way. Also, if someone ever makes us do T.61 or some other silly
04362  * thing, we can use these bottlenecks.
04363  */
04364 
04365 char *DIR_ConvertToServerCharSet(DIR_Server *server, char *src, PRInt16 srcCSID)
04366 {
04367        return DIR_ConvertString(srcCSID, (PRInt16)(server ? server->csid : CS_DEFAULT), src);
04368 }
04369 
04370 char *DIR_ConvertFromServerCharSet(DIR_Server *server, char *src, PRInt16 dstCSID)
04371 {
04372        return DIR_ConvertString((PRInt16)(server ? server->csid : CS_DEFAULT), dstCSID, src);
04373 }
04374 
04375 char *DIR_ConvertString(PRInt16 srcCSID, PRInt16 dstCSID, const char *string)
04376 {
04377     return nsCRT::strdup(string);
04378 }