} }  PR_FREEIF(childList);
PR_FREEIF(jsValue); } }  NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, childList);
static char * dir_ConvertDescriptionToPrefName(DIR_Server * server);void DIR_SetFileName(char** filename, const char* leafName);static PRInt32 PR_CALLBACK dir_ServerPrefCallback(const char *pref, void *inst_data);/***************************************************************************** * Functions for creating the new back end managed DIR_Server list. */static PRBool       dir_ServerPrefCallbackRegistered = PR_FALSE;static PRInt32      dir_UserId = 0;static DIR_Callback *dir_CallbackList = nsnull;nsVoidArray  *dir_ServerList = nsnull;nsVoidArray* DIR_GetDirectories(){    if (!dir_ServerList)        DIR_GetDirServers();	return dir_ServerList;}nsresult DIR_GetDirServers(){    nsresult rv = NS_OK;	if (!dir_ServerList)	{        nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv));         if (NS_FAILED(rv) || !pPref)     		return NS_ERROR_FAILURE;		/* we need to build the DIR_Server list */ 		rv = DIR_GetServerPreferences(&dir_ServerList);		/* Register the preference call back if necessary. */		if (NS_SUCCEEDED(rv) && (!dir_ServerPrefCallbackRegistered))		{			dir_ServerPrefCallbackRegistered = PR_TRUE;        	pPref->RegisterCallback(PREF_LDAP_SERVER_TREE_NAME, dir_ServerPrefCallback, nsnull);		}	}	return rv;}static nsresult dir_ConvertToMabFileName(){	if (dir_ServerList)	{		PRInt32 count = dir_ServerList->Count();		PRInt32 i;		for (i = 0; i < count; i++)		{			DIR_Server *server = (DIR_Server *)dir_ServerList->ElementAt(i);			// convert for main personal addressbook only			// do other address book when convert from 4.5 to mork is done			if (server && server->position == 1 && server->fileName)			{        // determine if server->fileName ends with ".na2"        PRUint32 fileNameLen = strlen(server->fileName);        if ((fileNameLen > kABFileName_PreviousSuffixLen) &&             strcmp(server->fileName + fileNameLen - kABFileName_PreviousSuffixLen, kABFileName_PreviousSuffix) == 0)				{					//Move old abook.na2 to end of the list and change the description					DIR_Server * newServer = nsnull;					DIR_CopyServer(server, &newServer);					newServer->position = count + 1;					char *newDescription = PR_smprintf("%s 4.x", newServer->description);					PR_FREEIF(newServer->description);					newServer->description = newDescription;					char *newPrefName = PR_smprintf("%s4x", newServer->prefName);					PR_FREEIF(newServer->prefName);					newServer->prefName = newPrefName;					dir_ServerList->AppendElement(newServer);					DIR_SavePrefsForOneServer(newServer);					PR_FREEIF (server->fileName);                    server->fileName = nsCRT::strdup(kPersonalAddressbook);					DIR_SavePrefsForOneServer(server);				}			}		}	}	return NS_OK;}nsresult DIR_ShutDown()  /* FEs should call this when the app is shutting down. It frees all DIR_Servers regardless of ref count values! */{	nsresult rv = NS_OK;	nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 	if (NS_FAILED(rv) || !pPref) 		return NS_ERROR_FAILURE;	pPref->SavePrefFile(nsnull);	if (dir_ServerList)	{		PRInt32 count = dir_ServerList->Count();		PRInt32 i;		for (i = 0; i < count; i++)		{			DIR_DeleteServer((DIR_Server *)(dir_ServerList->ElementAt(i)));		}		delete dir_ServerList;		dir_ServerList = nsnull;	}  /* unregister the preference call back, if necessary.   * we need to do this as DIR_Shutdown() is called when switching profiles   * when using turbo.  (see nsAbDirectoryDataSource::Observe())   * When switching profiles, prefs get unloaded and then re-loaded   * we don't want our callback to get called for all that.   * We'll reset our callback the first time DIR_GetDirServers() is called   * after we've switched profiles.   */  if (dir_ServerPrefCallbackRegistered) {    pPref->UnregisterCallback(PREF_LDAP_SERVER_TREE_NAME, dir_ServerPrefCallback, nsnull);    dir_ServerPrefCallbackRegistered = PR_FALSE;  }	return NS_OK;}nsresult DIR_ContainsServer(DIR_Server* pServer, PRBool *hasDir){	if (dir_ServerList)	{		PRInt32 count = dir_ServerList->Count();		PRInt32 i;		for (i = 0; i < count; i++)		{			DIR_Server* server = (DIR_Server *)(dir_ServerList->ElementAt(i));			if (server == pServer)			{				*hasDir = PR_TRUE;				return NS_OK;			}		}	}	*hasDir = PR_FALSE;	return NS_OK;}nsresult DIR_AddNewAddressBook(const PRUnichar *dirName, const char *fileName, PRBool migrating, const char * uri, int maxHits, const char * authDn, DirectoryType dirType, DIR_Server** pServer){	DIR_Server * server = (DIR_Server *) PR_Malloc(sizeof(DIR_Server));	DIR_InitServerWithType (server, dirType);	if (!dir_ServerList)		DIR_GetDirServers();	if (dir_ServerList)	{		PRInt32 count = dir_ServerList->Count();    NS_ConvertUCS2toUTF8 utf8str(dirName);    server->description = ToNewCString(utf8str);		server->position = count + 1;		if (fileName)            server->fileName = nsCRT::strdup(fileName);		else			DIR_SetFileName(&server->fileName, kPersonalAddressbook);    if (dirType == LDAPDirectory) {      // We don't actually allow the password to be saved in the preferences;      // this preference is (effectively) ignored by the current code base.        // It's here because versions of Mozilla 1.0 and earlier (maybe 1.1alpha      // too?) would blow away the .auth.dn preference if .auth.savePassword      // is not set.  To avoid trashing things for users who switch between      // versions, we'll set it.  Once the versions in question become       // obsolete enough, this workaround can be gotten rid of.      server->savePassword = PR_TRUE;      if (uri)        server->uri = nsCRT::strdup(uri);      if (authDn)        server->authDn = nsCRT::strdup(authDn);    }    if (maxHits)      server->maxHits = maxHits;		dir_ServerList->AppendElement(server);		if (!migrating) {			DIR_SavePrefsForOneServer(server); 		}    else if (!server->prefName)    {      // Need to return pref names here so the caller will be able to get the      // right directory properties. For migration, pref names were already      // created so no need to get unique ones via DIR_CreateServerPrefName().      if (!strcmp(server->fileName, kPersonalAddressbook))        server->prefName = nsCRT::strdup("ldap_2.servers.pab");      else if (!strcmp(server->fileName, kCollectedAddressbook))        server->prefName = nsCRT::strdup("ldap_2.servers.history");      else      {        char * leafName = dir_ConvertDescriptionToPrefName (server);        if (leafName)          server->prefName = PR_smprintf(PREF_LDAP_SERVER_TREE_NAME".%s", leafName);      }    }#ifdef DEBUG_sspitzer		else {			printf("don't set the prefs, they are already set since this ab was migrated\n");		}#endif		*pServer = server;		// save new address book into pref file 		nsresult rv = NS_OK;		nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 		if (NS_FAILED(rv) || !pPref) 			return NS_ERROR_FAILURE;		pPref->SavePrefFile(nsnull);		return NS_OK;	}	return NS_ERROR_FAILURE;}nsresult DIR_DecrementServerRefCount (DIR_Server *server){	NS_ASSERTION((server != nsnull), "server is null"); 	if (server && --server->refCount <= 0)		return DIR_DeleteServer(server);	else		return 1;}nsresult DIR_IncrementServerRefCount (DIR_Server *server){	NS_ASSERTION((server != nsnull), "server is null");	if (server)		server->refCount++;	return NS_OK;}/***************************************************************************** * Functions for creating DIR_Servers *//* use this when you want to create a server of a particular type */nsresult DIR_InitServerWithType(DIR_Server * server, DirectoryType dirType){	DIR_InitServer(server);  server->dirType = dirType;	if (dirType == LDAPDirectory)	{        server->columnAttributes = nsCRT::strdup(kDefaultLDAPColumnHeaders);		server->isOffline = PR_TRUE;		server->csid = CS_UTF8;		server->locale = nsnull;	}	else if (dirType == PABDirectory || dirType == MAPIDirectory)	{        server->columnAttributes = nsCRT::strdup(kDefaultPABColumnHeaders);		server->isOffline = PR_FALSE;		server->csid = CS_UTF8;//		server->csid = INTL_GetCharSetID(INTL_DefaultTextWidgetCsidSel);		server->locale = nsnull; /* get the locale we are going to use with this AB *//*		server->locale = INTL_GetCollationKeyLocale(nsnull); */	}	return NS_OK;}nsresult DIR_InitServer (DIR_Server *server){	NS_ASSERTION((server != nsnull), "server is null");	if (server)	{		memset(server, 0, sizeof(DIR_Server));		server->saveResults = PR_TRUE;		server->efficientWildcards = kDefaultEfficientWildcards;		server->port = LDAP_PORT;		server->maxHits = kDefaultMaxHits;		server->isOffline = kDefaultIsOffline;		server->refCount = 1;		server->position = kDefaultPosition;		server->csid = CS_UTF8;		server->locale = nsnull;        server->uri = nsnull;        // initialize the palm category        server->PalmCategoryId = -1;	}	return NS_OK;}DIR_DescriptionCode DIR_ValidateDirectoryDescription(nsVoidArray * wholeList, DIR_Server * serverToValidate){	/* right now the only invalid description is a duplicate...so check for duplicates */	if (wholeList && serverToValidate && serverToValidate->description)	{		PRInt32 numItems = wholeList->Count();		PRInt32 i;		for (i = 0; i < numItems; i++)		{			DIR_Server *s = (DIR_Server *)(dir_ServerList->ElementAt(i));			/* don't check the description if it is the same directory as the one we are comparing against */            if (s != serverToValidate && s->description && !nsCRT::strcasecmp(s->description, serverToValidate->description))				return DIR_DuplicateDescription;		}	}	return DIR_ValidDescription;}/***************************************************************************** * Functions for cloning DIR_Servers */static DIR_Attribute *DIR_CopyAttribute (DIR_Attribute *inAttribute){	DIR_Attribute *outAttribute = (DIR_Attribute*) PR_Malloc(sizeof(DIR_Attribute));	if (outAttribute)	{		PRInt32 count = 0;		outAttribute->id = inAttribute->id;        outAttribute->prettyName = nsCRT::strdup(inAttribute->prettyName);		while (inAttribute->attrNames[count])			count++;		outAttribute->attrNames = (char**) PR_Malloc((count + 1) * sizeof(char*));		if (outAttribute->attrNames)		{			PRInt32 i;			for (i = 0; i < count; i++)                outAttribute->attrNames[i] = nsCRT::strdup(inAttribute->attrNames[i]);			outAttribute->attrNames[i] = nsnull;		}	}	return outAttribute;}static DIR_Filter *DIR_CopyFilter (DIR_Filter *inFilter){	DIR_Filter *outFilter = (DIR_Filter*) PR_Malloc(sizeof(DIR_Filter));	if (outFilter)	{		outFilter->flags = inFilter->flags;        outFilter->string = nsCRT::strdup(inFilter->string);	}	return outFilter;}static nsresult dir_CopyTokenList (char **inList, PRInt32 inCount, char ***outList, PRInt32 *outCount){	nsresult status = NS_OK;	if (0 != inCount && nsnull != inList)	{		*outList = (char**) PR_Malloc(inCount * sizeof(char*));		if (*outList)		{			PRInt32 i;			for (i = 0; i < inCount; i++)                (*outList)[i] = nsCRT::strdup (inList[i]);			*outCount = inCount;		}		else			status = NS_ERROR_OUT_OF_MEMORY;	}	return status;}static DIR_ReplicationInfo *dir_CopyReplicationInfo (DIR_ReplicationInfo *inInfo){	DIR_ReplicationInfo *outInfo = (DIR_ReplicationInfo*) PR_Calloc (1, sizeof(DIR_ReplicationInfo));	if (outInfo)	{		outInfo->lastChangeNumber = inInfo->lastChangeNumber;		if (inInfo->description)            outInfo->description = nsCRT::strdup (inInfo->description);		if (inInfo->fileName)            outInfo->fileName = nsCRT::strdup (inInfo->fileName);		if (inInfo->dataVersion)            outInfo->dataVersion = nsCRT::strdup (inInfo->dataVersion);		if (inInfo->syncURL)            outInfo->syncURL = nsCRT::strdup (inInfo->syncURL);		if (inInfo->filter)            outInfo->filter = nsCRT::strdup (inInfo->filter);		dir_CopyTokenList (inInfo->excludedAttributes, inInfo->excludedAttributesCount,			&outInfo->excludedAttributes, &outInfo->excludedAttributesCount);	}	return outInfo;}nsresult DIR_CopyServer (DIR_Server *in, DIR_Server **out){	nsresult err = NS_OK;	if (in) {		*out = (DIR_Server*)PR_Malloc(sizeof(DIR_Server));		if (*out)		{			memset(*out, 0, sizeof(DIR_Server));			if (in->prefName)			{                (*out)->prefName = nsCRT::strdup(in->prefName);				if (!(*out)->prefName)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->description)			{                (*out)->description = nsCRT::strdup(in->description);				if (!(*out)->description)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->serverName)			{                (*out)->serverName = nsCRT::strdup(in->serverName);				if (!(*out)->serverName)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->searchBase)			{                (*out)->searchBase = nsCRT::strdup(in->searchBase);				if (!(*out)->searchBase)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->fileName)			{                (*out)->fileName = nsCRT::strdup(in->fileName);				if (!(*out)->fileName)					err = NS_ERROR_OUT_OF_MEMORY; 			}			if (in->columnAttributes)			{                (*out)->columnAttributes = nsCRT::strdup(in->columnAttributes);				if (!(*out)->columnAttributes)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->locale)			{                (*out)->locale = nsCRT::strdup(in->locale);				if (!(*out)->locale)					err = NS_ERROR_OUT_OF_MEMORY;			}			(*out)->position = in->position;			(*out)->port = in->port;			(*out)->maxHits = in->maxHits;			(*out)->isSecure = in->isSecure;			(*out)->saveResults = in->saveResults;			(*out)->isOffline = in->isOffline;			(*out)->efficientWildcards = in->efficientWildcards;			(*out)->dirType = in->dirType;			(*out)->csid = in->csid;			(*out)->flags = in->flags;						(*out)->enableAuth = in->enableAuth;			(*out)->savePassword = in->savePassword;			if (in->authDn)			{                (*out)->authDn = nsCRT::strdup (in->authDn);				if (!(*out)->authDn)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->password)			{                (*out)->password = nsCRT::strdup (in->password);				if (!(*out)->password)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->customAttributes)			{				(*out)->customAttributes = new nsVoidArray();				if ((*out)->customAttributes)				{					nsVoidArray *list = in->customAttributes;					DIR_Attribute *attribute = nsnull;					PRInt32 count = list->Count();					PRInt32 i;					for (i = 0; i < count; i++)					{						attribute = (DIR_Attribute *)list->ElementAt(i);						if (attribute)						{							DIR_Attribute *outAttr = DIR_CopyAttribute (attribute);							if (outAttr)								((*out)->customAttributes)->AppendElement(outAttr);							else								err = NS_ERROR_OUT_OF_MEMORY; 						}					}				}				else					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->customFilters)			{				(*out)->customFilters = new nsVoidArray();				if ((*out)->customFilters)				{					nsVoidArray *list = in->customFilters;					DIR_Filter *filter = nsnull;					PRInt32 count = list->Count();					PRInt32 i;					for (i = 0; i < count; i++)					{						filter = (DIR_Filter *)list->ElementAt(i);						if (filter)						{							DIR_Filter *outFilter = DIR_CopyFilter (filter);							if (outFilter)								((*out)->customFilters)->AppendElement(outFilter);							else								err = NS_ERROR_OUT_OF_MEMORY;						}					}				}				else					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->autoCompleteFilter)			{                (*out)->autoCompleteFilter = nsCRT::strdup(in->autoCompleteFilter);				if (!(*out)->autoCompleteFilter)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->replInfo)				(*out)->replInfo = dir_CopyReplicationInfo (in->replInfo);			if (in->basicSearchAttributesCount > 0)			{				PRInt32 bsaLength = in->basicSearchAttributesCount * sizeof(DIR_AttributeId);				(*out)->basicSearchAttributes = (DIR_AttributeId*) PR_Malloc(bsaLength);				if ((*out)->basicSearchAttributes)				{					memcpy((*out)->basicSearchAttributes, in->basicSearchAttributes, bsaLength);					(*out)->basicSearchAttributesCount = in->basicSearchAttributesCount;				}			}			dir_CopyTokenList (in->dnAttributes, in->dnAttributesCount,				&(*out)->dnAttributes, &(*out)->dnAttributesCount);			dir_CopyTokenList (in->suppressedAttributes, in->suppressedAttributesCount,				&(*out)->suppressedAttributes, &(*out)->suppressedAttributesCount);			dir_CopyTokenList (in->uriAttributes, in->uriAttributesCount,				&(*out)->uriAttributes, &(*out)->uriAttributesCount);			if (in->customDisplayUrl)                (*out)->customDisplayUrl = nsCRT::strdup (in->customDisplayUrl);			if (in->searchPairList)                (*out)->searchPairList = nsCRT::strdup (in->searchPairList);			(*out)->refCount = 1;		}		else {			err = NS_ERROR_OUT_OF_MEMORY;			(*out) = nsnull;		}	}	else {		PR_ASSERT (0);		err = NS_ERROR_FAILURE;		(*out) = nsnull;	}	return err;}/* Function for setting the position of a server.  Can be used to append, * delete, or move a server in a server list. * * The third parameter specifies the new position the server is to occupy. * The resulting position may differ depending on the lock state of the * given server and other servers in the list.  The following special values * are supported: *   DIR_POS_APPEND - Appends the server to the end of the list.  If the server *                    is already in the list, does nothing. *   DIR_POS_DELETE - Deletes the given server from the list.  Note that this *                    does not cause the server structure to be freed. * * Returns PR_TRUE if the server list was re-sorted. */PRBool DIR_SetServerPosition(nsVoidArray *wholeList, DIR_Server *server, PRInt32 position){    nsresult rv = NS_OK;    nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv));     if (NS_FAILED(rv) || !pPref) 		return PR_FALSE;	PRInt32    i, count, num;	PRBool     resort = PR_FALSE;	DIR_Server *s=nsnull;	switch (position) {	case DIR_POS_APPEND:		/* Do nothing if the request is to append a server that is already		 * in the list.		 */		count = wholeList->Count();		for (i= 0; i < count; i++)		{			if  ((s = (DIR_Server *)wholeList->ElementAt(i)) != nsnull)				if (s == server)					return PR_FALSE;		}		/* In general, if there are any servers already in the list, set the		 * position to the position of the last server plus one.  If there		 * are none, set it to position 1.		 */		if (count > 0)		{			/* Exception to the rule: if the last server is a locked server,			 * find the position of last unlocked server.  If there are no			 * unlocked servers, set the position to 1; otherwise, set it to			 * the position of the last unlocked server plus one.  In either			 * case the list must be resorted (to find the correct position).			 */			s = (DIR_Server *)wholeList->ElementAt(count - 1);			if (DIR_TestFlag(s, DIR_POSITION_LOCKED))			{				DIR_Server *sLast = nsnull;				for (i= 0; i < count; i++)				{					if  ((s = (DIR_Server *)wholeList->ElementAt(i)) != nsnull)						if (!DIR_TestFlag(s, DIR_POSITION_LOCKED))							sLast = s;				}				if (sLast)					server->position = sLast->position + 1;				else					server->position = 1;				resort = PR_TRUE;			}			else				server->position = s->position + 1;		}		else			server->position = 1;		wholeList->AppendElement(server);		if (wholeList == dir_ServerList)			DIR_SendNotification(server, DIR_NOTIFY_ADD, idNone);		break;	case DIR_POS_DELETE:		/* Undeletable servers cannot be deleted.		 */		if (DIR_TestFlag(server, DIR_UNDELETABLE))			return PR_FALSE;		/* Remove the prefs corresponding to the given server.  If the prefName		 * value is nsnull, the server has never been saved and there are no		 * prefs to remove.		 */		if (server->prefName)		{			DIR_ClearPrefBranch(server->prefName);		}		/* If the server is in the server list, remove it.		 */		num = wholeList->IndexOf(server);		if (num >= 0)		{			/* The list does not need to be re-sorted if the server is the			 * last one in the list.			 */			count = wholeList->Count();			if (num == count - 1)			{				wholeList->RemoveElementAt(num);			}			else			{				resort = PR_TRUE;				wholeList->RemoveElement(server);			}			if (wholeList == dir_ServerList)				DIR_SendNotification(server, DIR_NOTIFY_DELETE, idNone);		}		break;	default:		/* See if the server is already in the list.		 */		count = wholeList->Count();		for (i= 0; i < count; i++)		{			if  ((s = (DIR_Server *)wholeList->ElementAt(i)) != nsnull)				if (s == server)					break;		}		/* If the server is not in the list, add it to the beginning and re-sort.		 */		if (s == nsnull)		{			server->position = position;			wholeList->AppendElement(server);			resort = PR_TRUE;			if (wholeList == dir_ServerList)				DIR_SendNotification(server, DIR_NOTIFY_ADD, idNone);		}		/* Servers with locked position values cannot be moved.		 */		else if (DIR_TestFlag(server, DIR_POSITION_LOCKED))			return PR_FALSE;				/* Don't re-sort if the server is already in the requested position.		 */		else if (server->position != position)		{			server->position = position;			wholeList->RemoveElement(server);			wholeList->AppendElement(server);			resort = PR_TRUE;		}		break;	}	/* Make sure our position changes get saved back to prefs	 */	DIR_SaveServerPreferences(wholeList);	return resort;}/***************************************************************************** * DIR_Server Callback Notification Functions *//* dir_matchServerPrefToServer * * This function finds the DIR_Server in the unified DIR_Server list to which * the given preference string belongs. */static DIR_Server *dir_MatchServerPrefToServer(nsVoidArray *wholeList, const char *pref){	DIR_Server *server;	PRInt32 count = wholeList->Count();	PRInt32 i;	for (i = 0; i < count; i++)	{		if ((server = (DIR_Server *)wholeList->ElementAt(i)) != nsnull)		{			if (server->prefName && PL_strstr(pref, server->prefName) == pref)			{				char c = pref[PL_strlen(server->prefName)];				if (c == 0 || c == '.')					return server;			}		}	}	return nsnull;}/* dir_ValidateAndAddNewServer * * This function verifies that the position, serverName and description values * are set for the given prefName.  If they are then it adds the server to the * unified server list. */static PRBool dir_ValidateAndAddNewServer(nsVoidArray *wholeList, const char *fullprefname){	PRBool rc = PR_FALSE;	const char *endname = PL_strchr(&fullprefname[PL_strlen(PREF_LDAP_SERVER_TREE_NAME) + 1], '.');	if (endname)	{		char *prefname = (char *)PR_Malloc(endname - fullprefname + 1);		if (prefname)		{			PRInt32 dirType;			char *t1 = nsnull, *t2 = nsnull;			char tempstring[256];			PL_strncpyz(prefname, fullprefname, endname - fullprefname + 1);			dirType = DIR_GetIntPref(prefname, "dirType", tempstring, -1);			if (   dirType != -1			    && DIR_GetIntPref(prefname, "position", tempstring, 0)    != 0			    && (t1 = DIR_GetStringPref(prefname, "description", tempstring, nsnull)) != nsnull)			{				if (   dirType == PABDirectory					|| (t2 = DIR_GetStringPref(prefname, "serverName",  tempstring, nsnull)) != nsnull)				{					DIR_Server *server = (DIR_Server *)PR_Malloc(sizeof(DIR_Server));					if (server)					{						DIR_InitServerWithType(server, (DirectoryType)dirType);						server->prefName = prefname;						DIR_GetPrefsForOneServer(server, PR_FALSE, PR_FALSE);						DIR_SetServerPosition(wholeList, server, server->position);						rc = PR_TRUE;					}					PR_FREEIF(t2);				}				PR_Free(t1);			}			else				PR_Free(prefname);		}	}	return rc;}static PRInt32 PR_CALLBACK dir_ServerPrefCallback(const char *prefname, void *inst_data){    nsresult rv = NS_OK;    nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv));     if (NS_FAILED(rv) || !pPref) 		return NS_ERROR_FAILURE;	DIR_PrefId id = DIR_AtomizePrefName(prefname);	/* Check to see if the server is in the unified server list.	 */	DIR_Server *server = dir_MatchServerPrefToServer(dir_ServerList, prefname);	if (server)	{		/* If the server is in the process of being saved, just ignore this		 * change.  The DIR_Server structure is not really changing.		 */		if (DIR_TestFlag(server, DIR_SAVING_SERVER))		    return NS_OK;		/* Reparse the root DSE if one of the following attributes changed.		 */		if (   id == idServerName || id == idSearchBase			|| id == idEnableAuth || id == idAuthDn || id == idPassword)			DIR_ClearFlag(server, DIR_LDAP_ROOTDSE_PARSED);		/* If the pref that changed is the position, read it in.  If the new		 * position is zero, remove the server from the list.		 */		if (id == idPosition)		{			PRInt32 position;			/* We must not do anything if the new position is the same as the			 * position in the DIR_Server.  This avoids recursion in cases			 * where we are deleting the server.			 */			pPref->GetIntPref(prefname, &position);			if (position != server->position)			{				server->position = position;				if (dir_IsServerDeleted(server))					DIR_SetServerPosition(dir_ServerList, server, DIR_POS_DELETE);				else					DIR_SendNotification(server, DIR_NOTIFY_PROPERTY_CHANGE, idPosition);			}		}		/* Some pref other position changed, reload the server and send a property		 * changed notification.		 */		else if (dir_CallbackList != nsnull)		{			DIR_GetPrefsForOneServer(server, PR_TRUE, PR_FALSE);			DIR_SendNotification(server, DIR_NOTIFY_PROPERTY_CHANGE, id);		}	}	/* If the server is not in the unified list, we may need to add it.  Servers	 * are only added when the position, serverName and description are valid.	 */	else	{		if (id == idPosition || id == idType || id == idServerName || id == idDescription)			dir_ValidateAndAddNewServer(dir_ServerList, prefname);	}    return NS_OK;}PRBool DIR_RegisterNotificationCallback(DIR_NOTIFICATION_FN fn, PRUint32 flags, void *inst_data){	DIR_Callback *cb;	for (cb = dir_CallbackList; cb; cb = cb->next)	{		if (cb->fn == fn)		{			cb->flags = flags;			return PR_TRUE;		}	}	cb = (DIR_Callback *)PR_Malloc(sizeof(DIR_Callback));	if (!cb)		return PR_FALSE;	cb->fn    = fn;	cb->flags = flags;	cb->data  = inst_data;	cb->next  = dir_CallbackList;	dir_CallbackList = cb;	return PR_TRUE;}PRBool DIR_DeregisterNotificationCallback(DIR_NOTIFICATION_FN fn, void *inst_data){	DIR_Callback *cb, *cbPrev=nsnull;	for (cb = dir_CallbackList; cb && cb->fn != fn && cb->data != inst_data; cb = cb->next)		cbPrev = cb;	if (cb == nsnull)		return PR_FALSE;	if (cb == dir_CallbackList)		dir_CallbackList = cb->next;	else		cbPrev->next = cb->next;	PR_Free(cb);	return PR_TRUE;}PRBool DIR_SendNotification(DIR_Server *server, PRUint32 flag, DIR_PrefId id){	PRBool sent = PR_FALSE;	DIR_Callback *cb, *cbNext;	for (cb = dir_CallbackList; cb; cb = cbNext)	{		cbNext = cb->next;		if (cb->flags & flag)		{			sent = PR_TRUE;			cb->fn(server, flag, id, cb->data);		}	}	return sent;}char *DIR_CopyServerStringPref(DIR_Server *server, DIR_PrefId prefid, int16 csid){	char *pref;	if (!server)		return nsnull;	switch (prefid) {	case idAuthDn:		pref = server->authDn;		break;	case idPassword:		pref = server->password;		break;	case idSearchBase:		pref = server->searchBase;		break;	default:		PR_ASSERT(0);		pref = nsnull;		break;	}	if (pref)		pref = DIR_ConvertFromServerCharSet(server, pref, csid);	return pref;}PRBool DIR_SetServerStringPref(DIR_Server *server, DIR_PrefId prefid, char *pref, PRInt16 csid){	PRBool rc = PR_TRUE;	if (!server || !pref)		return PR_FALSE;	pref = DIR_ConvertToServerCharSet(server, pref, csid);	switch (prefid) {	case idAuthDn:		PR_FREEIF(server->authDn);		server->authDn = pref;		break;	case idPassword:		PR_FREEIF(server->password);		server->password = pref;		break;	case idSearchBase:		PR_FREEIF(server->searchBase);		server->searchBase = pref;		break;	default:		PR_ASSERT(0);		rc = PR_FALSE;		break;	}	return PR_FALSE;}DIR_PrefId DIR_AtomizePrefName(const char *prefname){	DIR_PrefId rc = idNone;	/* Skip the "ldap_2.servers.<server-name>." portion of the string.	 */	if (PL_strstr(prefname, PREF_LDAP_SERVER_TREE_NAME) == prefname)	{		prefname = PL_strchr(&prefname[PL_strlen(PREF_LDAP_SERVER_TREE_NAME) + 1], '.');		if (!prefname)			return idNone;		else			prefname = prefname + 1;	}	switch (prefname[0]) {	case 'a':		if (PL_strstr(prefname, "autoComplete.") == prefname)		{			switch (prefname[13]) {			case 'e': /* autoComplete.enabled */				rc = idAutoCompleteEnabled;				break;			case 'f':				rc = idAutoCompleteFilter;				break;			case 'n':				rc = idAutoCompleteNever;				break;			}		}		else if (PL_strstr(prefname, "auth.") == prefname)		{			switch (prefname[5]) {			case 'd': /* auth.dn */				rc = idAuthDn;				break;			case 'e': /* auth.enabled */				rc = idEnableAuth;				break;			case 'p': /* auth.password */				rc = idPassword;				break;			case 's': /* auth.savePassword */				rc = idSavePassword;				break;			}		}		else if (PL_strstr(prefname, "attributes.") == prefname)		{			rc = idCustomAttributes;		}		break;	case 'b':		rc = idBasicSearchAttributes;		break;	case 'c':		switch (prefname[1]) {		case 'h': /* charset */			rc = idCSID;			break;		case 's': /* the new csid pref that replaced char set */			rc = idCSID;			break;		case 'o': /* columns */			rc = idColumnAttributes;			break;		case 'u': /* customDisplayUrl */			rc = idCustomDisplayUrl;			break;		}		break;	case 'd':		switch (prefname[1]) {		case 'e': /* description */			rc = idDescription;			break;		case 'i': /* dirType */			rc = idType;			break;		}		break;	case 'e':		switch (prefname[1]) {		case 'e': /* efficientWildcards */			rc = idEfficientWildcards;			break;		}		break;	case 'f':		if (PL_strstr(prefname, "filter") == prefname)		{			rc = idCustomFilters;		}		else		{			rc = idFileName;		}		break;	case 'h':		if (PL_strstr(prefname, "html.") == prefname)		{			switch (prefname[5]) {			case 'd':				rc = idDnAttributes;				break;			case 's':				rc = idSuppressedAttributes;				break;			case 'u':				rc = idUriAttributes;				break;			}		}		break;			case 'i':		switch (prefname[2]) {		case 'O': /* filename */			rc = idIsOffline;			break;		case 'S': /* filename */			rc = idIsSecure;			break;		}		break;	case 'l':		rc = idLocale;		break;	case 'm':		rc = idMaxHits;		break;	case 'p':		switch (prefname[1]) {		case 'o':			switch (prefname[2]) {			case 'r': /* port */				rc = idPort;				break;			case 's': /* position */				rc = idPosition;				break;			}			break;		}		break;	case 'r':		if (PL_strstr(prefname, "replication.") == prefname)		{			switch (prefname[12]) {			case 'd':				switch (prefname[13]) {					case 'a': /* replication.dataVersion */						rc = idReplDataVersion;						break;					case 'e': /* replication.description */						rc = idReplDescription;						break;				}				break;			case 'e':				switch (prefname[13]) {				case 'n': /* replication.enabled */					rc = idReplEnabled;					break;				case 'x': /* replication.excludedAttributes */					rc = idReplExcludedAttributes;					break;				}				break;			case 'f':				switch (prefname[15]) {				case 'e': /* replication.fileName */					rc = idReplFileName;					break;				case 't': /* replication.filter */					rc = idReplFilter;					break;				}				break;			case 'l': /* replication.lastChangeNumber */				rc = idReplLastChangeNumber;				break;			case 'n': /* replication.never */				rc = idReplNever;				break;			case 's': /* replication.syncURL */				rc = idReplSyncURL;				break;			}		}		break;	case 's':		switch (prefname[1]) {		case 'a': /* saveResults */			rc = idSaveResults;			break;		case 'e':			switch (prefname[2]) {			case 'a':				switch (prefname[6]) {				case 'B': /* searchBase */					rc = idSearchBase;					break;				case 'S': /* searchString */					rc = idLastSearchString;					break;				}				break;			case 'r': /* serverName */				rc = idServerName;				break;			}			break;		}		break;	case 'u': /* uri */		rc = idUri;		break;	case 'v': /* vlvDisabled */		rc = idVLVDisabled;		break;	case 'P':		switch (prefname[4]) {			case 'C': /* PalmCategoryId */				rc = idPalmCategory;				break;			case 'S': /* PalmSyncTimeStamp */				rc = idPalmSyncTimeStamp;				break;		}		break;	}	PR_ASSERT(rc != idNone);	return rc;}/***************************************************************************** * Function for comparing DIR_Servers  */static PRBool dir_AreLDAPServersSame (DIR_Server *first, DIR_Server *second, PRBool strict){	PR_ASSERT (first->serverName && second->serverName);	if (first->serverName && second->serverName)	{        if (nsCRT::strcasecmp (first->serverName, second->serverName) == 0) 		{			if (first->port == second->port) 			{				/* allow for a null search base */				if (!strict || (first->searchBase == nsnull && second->searchBase == nsnull))					return PR_TRUE;				/* otherwise check the strings */				else if (   first->searchBase				         && second->searchBase                         && nsCRT::strcasecmp (first->searchBase, second->searchBase) == 0)					return PR_TRUE;			}		}	}	return PR_FALSE;}static PRBool dir_AreServersSame (DIR_Server *first, DIR_Server *second, PRBool strict){	/* This function used to be written to assume that we only had one PAB so it	   only checked the server type for PABs. If both were PABDirectories, then 	   it returned PR_TRUE. Now that we support multiple address books, we need to	   check type & file name for address books to test if they are the same */	if (first && second) 	{		/* assume for right now one personal address book type where offline is PR_FALSE */		if ((first->dirType == PABDirectory) && (second->dirType == PABDirectory))		{			if ((first->isOffline == PR_FALSE) && (second->isOffline == PR_FALSE))  /* are they both really address books? */			{				PR_ASSERT(first->fileName && second->fileName);				if (first->fileName && second->fileName)                    if (nsCRT::strcasecmp(first->fileName, second->fileName) == 0)						return PR_TRUE;				return PR_FALSE;			}			else				return dir_AreLDAPServersSame(first, second, strict);		}		if (first->dirType == second->dirType)			return dir_AreLDAPServersSame(first, second, strict);	}	return PR_FALSE;}PRBool	DIR_AreServersSame (DIR_Server *first, DIR_Server *second){	return dir_AreServersSame(first, second, PR_TRUE);}DIR_Server *DIR_LookupServer(char *serverName, PRInt32 port, char *searchBase){	PRInt32 i;	DIR_Server *server;	if (!serverName || !searchBase || !dir_ServerList)		return nsnull;	for (i = dir_ServerList->Count() - 1; i >= 0; i--)	{		server = (DIR_Server *)dir_ServerList->ElementAt(i);		if (   server->port == port            && server->serverName && nsCRT::strcasecmp(server->serverName, serverName) == 0            && server->searchBase && nsCRT::strcasecmp(server->searchBase, searchBase) == 0)		{			return server;		}	}	return nsnull;}/***************************************************************************** * Functions for destroying DIR_Servers  *//* this function determines if the passed in server is no longer part of the of   the global server list. */static PRBool dir_IsServerDeleted(DIR_Server * server){	if (server && server->position == 0)		return PR_TRUE;	else		return PR_FALSE;}static void dir_DeleteTokenList (char **tokenList, PRInt32 tokenListCount){	PRInt32 tokenIdx;	for (tokenIdx = 0; tokenIdx < tokenListCount; tokenIdx++)		PR_Free(tokenList[tokenIdx]);	PR_Free(tokenList);}static nsresult DIR_DeleteFilter (DIR_Filter *filter){	if (filter->string)		PR_Free(filter->string);	PR_Free(filter);	return NS_OK;}static nsresult DIR_DeleteAttribute (DIR_Attribute *attribute){	PRInt32 i = 0;	if (attribute->prettyName)		PR_Free(attribute->prettyName);	if (attribute->attrNames)	{		while (attribute->attrNames[i])			PR_Free((char**)attribute->attrNames[i++]);		PR_Free(attribute->attrNames);	}	PR_Free(attribute);	return NS_OK;}static void dir_DeleteReplicationInfo (DIR_Server *server){	DIR_ReplicationInfo *info = nsnull;	if (server && (info = server->replInfo) != nsnull)	{		dir_DeleteTokenList (info->excludedAttributes, info->excludedAttributesCount);				PR_FREEIF(info->description);		PR_FREEIF(info->fileName);		PR_FREEIF(info->dataVersion);		PR_FREEIF(info->syncURL);		PR_FREEIF(info->filter);		PR_Free(info);	}}/* when the back end manages the server list, deleting a server just decrements its ref count,   in the old world, we actually delete the server */static nsresult dir_DeleteServerContents (DIR_Server *server){	if (server)	{		PRInt32 i;		/* when destroying the server check its clear flag to see if things need cleared */#ifdef XP_FileRemove		if (DIR_TestFlag(server, DIR_CLEAR_SERVER))		{			if (server->fileName)				XP_FileRemove (server->fileName, xpAddrBookNew);			if (server->replInfo && server->replInfo->fileName)				XP_FileRemove (server->replInfo->fileName, xpAddrBookNew);		}#endif /* XP_FileRemove */		PR_FREEIF (server->prefName);		PR_FREEIF (server->description);		PR_FREEIF (server->serverName);		PR_FREEIF (server->searchBase);		PR_FREEIF (server->fileName);		PR_FREEIF (server->lastSearchString);		PR_FREEIF (server->tokenSeps);		PR_FREEIF (server->authDn);		PR_FREEIF (server->password);		PR_FREEIF (server->columnAttributes);		PR_FREEIF (server->locale);        PR_FREEIF (server->uri);		if (server->customFilters)		{			PRInt32 count = server->customFilters->Count();			for (i = 0; i < count; i++)				DIR_DeleteFilter ((DIR_Filter*) server->customFilters->ElementAt(i));			delete server->customFilters;		}		PR_FREEIF (server->autoCompleteFilter);		if (server->customAttributes)		{			nsVoidArray *list = server->customAttributes;			DIR_Attribute *walkAttrStruct = nsnull;			PRInt32 count = list->Count();			for (i = 0; i < count; i++)			{				walkAttrStruct = (DIR_Attribute *)list->ElementAt(i);				if (walkAttrStruct != nsnull)					DIR_DeleteAttribute (walkAttrStruct);			}			delete server->customAttributes;		}		if (server->uriAttributes)			dir_DeleteTokenList (server->uriAttributes, server->uriAttributesCount);		if (server->suppressedAttributes)			dir_DeleteTokenList (server->suppressedAttributes, server->suppressedAttributesCount);		if (server->dnAttributes)			dir_DeleteTokenList (server->dnAttributes, server->dnAttributesCount);		PR_FREEIF (server->basicSearchAttributes);		if (server->replInfo)			dir_DeleteReplicationInfo (server);		PR_FREEIF (server->customDisplayUrl);		PR_FREEIF (server->searchPairList);	}	return NS_OK;}nsresult DIR_DeleteServer(DIR_Server *server){	if (server)	{		dir_DeleteServerContents(server);		PR_Free(server);	}	return NS_OK;}nsresult DIR_DeleteServerFromList(DIR_Server *server){	if (!server)		return NS_ERROR_NULL_POINTER;	nsresult rv = NS_OK;	nsFileSpec* dbPath = nsnull;	nsCOMPtr<nsIAddrBookSession> abSession = 	         do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv); 	if(NS_SUCCEEDED(rv))		abSession->GetUserProfileDirectory(&dbPath);		if (dbPath)	{    // close the database, as long as it isn't the special ones     // (personal addressbook and collected addressbook)    // which can never be deleted.  There was a bug where we would slap in    // "abook.mab" as the file name for LDAP directories, which would cause a crash    // on delete of LDAP directories.  this is just extra protection.    if (strcmp(server->fileName, kPersonalAddressbook) &&         strcmp(server->fileName, kCollectedAddressbook)) {		nsCOMPtr<nsIAddrDatabase> database;		(*dbPath) += server->fileName;		// close file before delete it		nsCOMPtr<nsIAddrDatabase> addrDBFactory = 		         do_GetService(NS_ADDRDATABASE_CONTRACTID, &rv);		if (NS_SUCCEEDED(rv) && addrDBFactory)			rv = addrDBFactory->Open(dbPath, PR_FALSE, getter_AddRefs(database), PR_TRUE);		if (database)  /* database exists */		{			database->ForceClosed();			dbPath->Delete(PR_FALSE);		}    delete dbPath;    }		nsVoidArray *dirList = DIR_GetDirectories();		DIR_SetServerPosition(dirList, server, DIR_POS_DELETE);		DIR_DeleteServer(server);		rv = NS_OK;		nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv)); 		if (NS_FAILED(rv) || !pPref) 			return NS_ERROR_FAILURE;		pPref->SavePrefFile(nsnull);		return NS_OK;	}	return NS_ERROR_NULL_POINTER;}nsresult DIR_DeleteServerList(nsVoidArray *wholeList){	DIR_Server *server = nsnull;		/* TBD: Send notifications? */	PRInt32 count = wholeList->Count();	PRInt32 i;	for (i = count - 1; i >=0; i--)	{		server = (DIR_Server *)wholeList->ElementAt(i);		if (server != nsnull)			DIR_DeleteServer(server);	}	delete wholeList;	return NS_OK;}nsresult DIR_CleanUpServerPreferences(nsVoidArray *deletedList){	/* OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE */	PR_ASSERT(PR_FALSE);	return NS_OK;	/* OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE */}/***************************************************************************** * Functions for retrieving subsets of the DIR_Server list  */#define DIR_SUBSET_MATCH(_SERVER, _FLAGS)                                                 \	(   (   (_FLAGS & DIR_SUBSET_PAB_ALL          ) && PABDirectory  == _SERVER->dirType) \	 || (   (_FLAGS & DIR_SUBSET_HTML_ALL         ) && HTMLDirectory == _SERVER->dirType) \	 || (   (_FLAGS & DIR_SUBSET_LDAP_ALL         ) && LDAPDirectory == _SERVER->dirType) \	 || (   (_FLAGS & DIR_SUBSET_LDAP_AUTOCOMPLETE) && LDAPDirectory == _SERVER->dirType  \		 && !DIR_TestFlag(s, DIR_AUTO_COMPLETE_NEVER))                                    \	 || (   (_FLAGS & DIR_SUBSET_LDAP_REPLICATE   ) && LDAPDirectory == _SERVER->dirType  \		 && !DIR_TestFlag(s, DIR_REPLICATE_NEVER))                                        \    )nsresult DIR_GetDirServerSubset(nsVoidArray *wholeList, nsVoidArray *subList, PRUint32 flags){	if (wholeList && subList && flags)	{		PRInt32 i;		PRInt32 numItems = wholeList->Count();		for (i = 0; i < numItems; i++)		{			DIR_Server *s = (DIR_Server*) wholeList->ElementAt(i);			if (DIR_SUBSET_MATCH(s, flags))			{				subList->AppendElement(s);			}		}		return NS_OK;	}	return NS_ERROR_FAILURE;}PRInt32 DIR_GetDirServerSubsetCount(nsVoidArray * wholeList, PRUint32 flags){	PRInt32 count = 0;	if (wholeList && flags)	{		PRInt32 i;		PRInt32 numItems = wholeList->Count();		for (i = 0; i < numItems; i++)		{			DIR_Server *s = (DIR_Server*) wholeList->ElementAt(i);			if (DIR_SUBSET_MATCH(s, flags))			{				count++;			}		}	}	return count;}nsresult DIR_GetComposeNameCompletionAddressBook (nsVoidArray *wholeList, DIR_Server **cab){	/* OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE */	PR_ASSERT(PR_FALSE);    return NS_ERROR_FAILURE;	/* OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE */}nsresult DIR_GetLdapServers (nsVoidArray *wholeList, nsVoidArray *subList){	/* OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE */	return DIR_GetDirServerSubset(wholeList, subList, DIR_SUBSET_LDAP_ALL);	/* OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE  OBSOLETE */}nsresult DIR_GetPersonalAddressBook(nsVoidArray *wholeList, DIR_Server **pab){	if (wholeList && pab)	{		PRInt32 count = wholeList->Count();		PRInt32 i;		*pab = nsnull;		for (i = 0; i < count; i++)		{			DIR_Server *server = (DIR_Server *)wholeList->ElementAt(i);			if ((PABDirectory == server->dirType) && (PR_FALSE == server->isOffline))			{				if (server->serverName == nsnull || server->serverName[0] == '\0')				{					*pab = server;					return NS_OK;				}			}		}	}	return NS_ERROR_FAILURE;}/***************************************************************************** * Functions for managing JavaScript prefs for the DIR_Servers  */#if !defined(MOZADDRSTANDALONE)static char *DIR_GetStringPref(const char *prefRoot, const char *prefLeaf, char *scratch, const char *defaultValue){    nsresult rv = NS_OK;    nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv));     if (NS_FAILED(rv) || !pPref) 		return nsnull;	char *value = nsnull;	PL_strcpy(scratch, prefRoot);	PL_strcat(scratch, ".");	PL_strcat(scratch, prefLeaf); 	if (PREF_NOERROR == pPref->CopyCharPref(scratch, &value))	{		/* unfortunately, there may be some prefs out there which look like this */		if (!PL_strcmp(value, "(null)")) 		{			PR_FREEIF(value); /* free old value because we are going to give it a new value.... */            value = defaultValue ? nsCRT::strdup(defaultValue) : nsnull;		}		if (!value || !*value)		{			PR_FREEIF(value);			pPref->CopyDefaultCharPref(scratch, &value);		}	}	else	{		PR_FREEIF(value); /* the pref may have generated an error but we still might have something in value...... */        value = defaultValue ? nsCRT::strdup(defaultValue) : nsnull;	}	return value;}/*	Get localized unicode string pref from properties file, convert into an UTF8 string 	since address book prefs store as UTF8 strings.  So far there are 2 default 	prefs stored in addressbook.properties.	"ldap_2.servers.pab.description"	"ldap_2.servers.history.description"*/static char *DIR_GetLocalizedStringPref(const char *prefRoot, const char *prefLeaf, char *scratch, const char *defaultValue){    nsresult rv = NS_OK;    nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv));     if (NS_FAILED(rv) || !pPref) 		return nsnull;	PL_strcpy(scratch, prefRoot);	PL_strcat(scratch, ".");	PL_strcat(scratch, prefLeaf);	nsXPIDLString wvalue;	rv = pPref->GetLocalizedUnicharPref(scratch, getter_Copies(wvalue));	char *value = nsnull;	if ((const PRUnichar*)wvalue)	{    NS_ConvertUCS2toUTF8 utf8str(wvalue.get());    value = ToNewCString(utf8str);	}	else    value = defaultValue ? nsCRT::strdup(defaultValue) : nsnull;	return value;}static PRInt32 DIR_GetIntPref(const char *prefRoot, const char *prefLeaf, char *scratch, PRInt32 defaultValue){    nsresult rv = NS_OK;    nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv));     if (NS_FAILED(rv) || !pPref) 		return defaultValue;	PRInt32 value;	PL_strcpy(scratch, prefRoot);	PL_strcat(scratch, ".");	PL_strcat(scratch, prefLeaf);	if (PREF_NOERROR != pPref->GetIntPref(scratch, &value))		value = defaultValue;	return value;}static PRBool DIR_GetBoolPref(const char *prefRoot, const char *prefLeaf, char *scratch, PRBool defaultValue){    nsresult rv = NS_OK;    nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv));     if (NS_FAILED(rv) || !pPref) 		return defaultValue;	PRBool value;	PL_strcpy(scratch, prefRoot);	PL_strcat(scratch, ".");	PL_strcat(scratch, prefLeaf);	if (PREF_NOERROR != pPref->GetBoolPref(scratch, &value))		value = defaultValue;	return value;}nsresult DIR_AttributeNameToId(DIR_Server *server, const char *attrName, DIR_AttributeId *id){	nsresult status = NS_OK;	/* Look for a default attribute with a matching name.	 */	switch (attrName[0])	{	case 'a':        if (!nsCRT::strcasecmp(attrName, "auth"))			*id = auth;		else			status = NS_ERROR_FAILURE;		break;	case 'b':        if (!nsCRT::strcasecmp(attrName, "businesscategory"))			*id = businesscategory;		else			status = NS_ERROR_FAILURE;		break;	case 'c' :        if (!nsCRT::strcasecmp(attrName, "cn"))			*id = cn;        else if (!nsCRT::strcasecmp(attrName, "carlicense"))			*id = carlicense;        else if (!nsCRT::strncasecmp(attrName, "custom", 6))		{			switch (attrName[6])			{			case '1': *id = custom1; break;			case '2': *id = custom2; break;			case '3': *id = custom3; break;			case '4': *id = custom4; break;			case '5': *id = custom5; break;			default: status = NS_ERROR_FAILURE; 			}		}		else			status = NS_ERROR_FAILURE;		break;	case 'd':        if (!nsCRT::strcasecmp(attrName, "departmentnumber"))			*id = departmentnumber;		else            if (!nsCRT::strcasecmp(attrName, "description"))				*id = description;		else			status = NS_ERROR_FAILURE;		break;	case 'e':        if (!nsCRT::strcasecmp(attrName, "employeetype"))			*id = employeetype;		else			status = NS_ERROR_FAILURE;		break;	case 'f':        if (!nsCRT::strcasecmp(attrName, "facsimiletelephonenumber"))			*id = facsimiletelephonenumber;		else			status = NS_ERROR_FAILURE;		break;	case 'g':        if (!nsCRT::strcasecmp(attrName, "givenname"))			*id = givenname; 		else			status = NS_ERROR_FAILURE;		break;	case 'h':        if (!nsCRT::strcasecmp(attrName, "homephone"))			*id = homephone;		else			status = NS_ERROR_FAILURE;		break;	case 'l':        if (!nsCRT::strcasecmp(attrName, "l"))			*id = l;		else			status = NS_ERROR_FAILURE;		break;	case 'm':        if (!nsCRT::strcasecmp(attrName, "mail"))			*id = mail;        else if (!nsCRT::strcasecmp(attrName, "manager"))			*id = manager;        else if (!nsCRT::strcasecmp(attrName, "mobiletelephonenumber"))			*id = mobiletelephonenumber;		else			status = NS_ERROR_FAILURE;		break;	case 'n':        if (!nsCRT::strcasecmp(attrName, "nickname"))			*id = nickname;		else			status = NS_ERROR_FAILURE;		break;	case 'o':        if (!nsCRT::strcasecmp(attrName, "o"))			*id = o;        else if (!nsCRT::strcasecmp(attrName, "ou"))			*id = ou;        else if (!nsCRT::strcasecmp(attrName, "objectclass"))			*id = objectclass;		else			status = NS_ERROR_FAILURE;		break;	case 'p':        if (!nsCRT::strcasecmp(attrName, "pager"))			*id = pager;        else if (!nsCRT::strcasecmp(attrName, "postalcode"))			*id = postalcode;        else if (!nsCRT::strcasecmp(attrName, "postaladdress"))			*id = postaladdress;		else			status = NS_ERROR_FAILURE;		break;	case 's':         if (!nsCRT::strcasecmp(attrName, "street"))			*id = street;        else if (!nsCRT::strcasecmp(attrName, "sn"))			*id = sn;        else if (!nsCRT::strcasecmp(attrName, "secretary"))			*id = secretary;		else			status = NS_ERROR_FAILURE;		break;	case 't':        if (!nsCRT::strcasecmp(attrName, "telephonenumber"))			*id = telephonenumber;        else if (!nsCRT::strcasecmp(attrName, "title"))			*id = title;		else			status = NS_ERROR_FAILURE;		break;	default:		status = NS_ERROR_FAILURE;	}	return status;}static nsresult DIR_AddCustomAttribute(DIR_Server *server, const char *attrName, char *jsAttr){	nsresult status = NS_OK;	char *jsCompleteAttr = nsnull;	char *jsAttrForTokenizing = jsAttr;	DIR_AttributeId id;	status = DIR_AttributeNameToId(server, attrName, &id);	/* If the string they gave us doesn't have a ':' in it, assume it's one or more	 * attributes without a pretty name. So find the default pretty name, and generate	 * a "complete" string to use for tokenizing.	 */	if (NS_SUCCEEDED(status) && !PL_strchr(jsAttr, ':'))	{		const char *defaultPrettyName = DIR_GetAttributeName (server, id);		if (defaultPrettyName)		{			jsCompleteAttr = PR_smprintf ("%s:%s", defaultPrettyName, jsAttr);			if (jsCompleteAttr)				jsAttrForTokenizing = jsCompleteAttr;			else				status = NS_ERROR_OUT_OF_MEMORY;		}	}	if (NS_SUCCEEDED(status))	{        char *scratchAttr = nsCRT::strdup(jsAttrForTokenizing);		DIR_Attribute *attrStruct = (DIR_Attribute*) PR_Malloc(sizeof(DIR_Attribute));		if (!server->customAttributes)			server->customAttributes = new nsVoidArray();		if (attrStruct && server->customAttributes && scratchAttr)		{			char *attrToken = nsnull;			PRUint32 attrCount = 0;			memset(attrStruct, 0, sizeof(DIR_Attribute));			/* Try to pull out the pretty name into the struct */			attrStruct->id = id;            attrStruct->prettyName = nsCRT::strdup(strtok(scratchAttr, ":")); 			/* Count up the attribute names */			while ((attrToken = strtok(nsnull, ", ")) != nsnull)				attrCount++;			/* Pull the attribute names into the struct */			PL_strcpy(scratchAttr, jsAttrForTokenizing);			strtok(scratchAttr, ":"); 			attrStruct->attrNames = (char**) PR_Malloc((attrCount + 1) * sizeof(char*));			if (attrStruct->attrNames)			{				PRInt32 i = 0;				while ((attrToken = strtok(nsnull, ", ")) != nsnull)                    attrStruct->attrNames[i++] = nsCRT::strdup(attrToken);				attrStruct->attrNames[i] = nsnull; /* null-terminate the array */			}			if (NS_SUCCEEDED(status)) /* status is always NS_OK! */				server->customAttributes->AppendElement(attrStruct);			else				DIR_DeleteAttribute (attrStruct);			PR_Free(scratchAttr);		}		else 			status = NS_ERROR_OUT_OF_MEMORY;	}	if (jsCompleteAttr)		PR_smprintf_free(jsCompleteAttr);	return status;}PRInt32 DIR_GetNumAttributeIDsForColumns(DIR_Server * server){	PRInt32 count = 0;	char * buffer = nsnull;	char * marker = nsnull;	if (server && server->columnAttributes)	{        buffer = nsCRT::strdup(server->columnAttributes);		if (buffer)		{			marker = buffer;			while (AB_pstrtok_r(0, ", ", &buffer))				count++;			PR_FREEIF(marker);		}	}	return count;}/* caller must free returned list of ids */nsresult DIR_GetAttributeIDsForColumns(DIR_Server *server, DIR_AttributeId ** ids, PRInt32 * numIds){	DIR_AttributeId * idArray = nsnull;	nsresult status = NS_OK; 	PRInt32 numAdded = 0;  /* number of ids we actually added to the array...*/	PRInt32 indx = 0;	PRInt32 numItems = 0; 	char * idName = nsnull;	char * marker = nsnull;	char * columnIDs = nsnull;	if (server && numIds && ids)	{		if (server->columnAttributes) 		{            columnIDs = nsCRT::strdup(server->columnAttributes);			numItems = DIR_GetNumAttributeIDsForColumns(server);		}		if (columnIDs && numItems)		{			marker = columnIDs;			idArray = (DIR_AttributeId *) PR_Malloc(sizeof(DIR_AttributeId) * numItems);			if (idArray)			{				for (indx = 0; indx < numItems; indx++)				{					idName = AB_pstrtok_r(0,", ",&marker);					if (idName)					{						status = DIR_AttributeNameToId(server, idName, &idArray[numAdded]);						if (NS_SUCCEEDED(status))							numAdded++;					}					else						break;				}			}			else				status = NS_ERROR_OUT_OF_MEMORY;		}		PR_FREEIF(columnIDs); 	}	if (ids)		*ids = idArray;	if (numIds)		*numIds = numAdded;	return status;}static nsresult dir_CreateTokenListFromWholePref(const char *pref, char ***outList, PRInt32 *outCount){    nsresult result = NS_OK;    nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &result));     if (NS_FAILED(result)) 		return result;	char *commaSeparatedList = nsnull;	if (PREF_NOERROR == pPref->CopyCharPref(pref, &commaSeparatedList) && commaSeparatedList)	{		char *tmpList = commaSeparatedList;		*outCount = 1;		while (*tmpList)			if (*tmpList++ == ',')				(*outCount)++;		*outList = (char**) PR_Malloc(*outCount * sizeof(char*));		if (*outList)		{			PRInt32 i;			char *token = strtok(commaSeparatedList, ", ");			for (i = 0; i < *outCount; i++)			{                (*outList)[i] = nsCRT::strdup(token);				token = strtok(nsnull, ", ");			}		}		else			result = NS_ERROR_OUT_OF_MEMORY;		PR_Free (commaSeparatedList);	}	else		result = NS_ERROR_FAILURE;	return result;}static nsresult dir_CreateTokenListFromPref(const char *prefBase, const char *prefLeaf, char *scratch, char ***outList, PRInt32 *outCount){	PL_strcpy (scratch, prefBase);	PL_strcat (scratch, ".");	PL_strcat (scratch, prefLeaf);	return dir_CreateTokenListFromWholePref(scratch, outList, outCount);}static nsresult dir_ConvertTokenListToIdList(DIR_Server *server, char **tokenList, PRInt32 tokenCount, DIR_AttributeId **outList){	*outList = (DIR_AttributeId*) PR_Malloc(sizeof(DIR_AttributeId) * tokenCount);	if (*outList)	{		PRInt32 i;		for (i = 0; i < tokenCount; i++)			DIR_AttributeNameToId(server, tokenList[i], &(*outList)[i]);	}	else		return NS_ERROR_OUT_OF_MEMORY;	return NS_OK;}static void dir_GetReplicationInfo(const char *prefstring, DIR_Server *server, char *scratch){	char replPrefName[128];	PR_ASSERT(server->replInfo == nsnull);	server->replInfo = (DIR_ReplicationInfo *)PR_Calloc(1, sizeof (DIR_ReplicationInfo));	if (server->replInfo && replPrefName)	{		PRBool prefBool;		PL_strcpy(replPrefName, prefstring);		PL_strcat(replPrefName, ".replication");		prefBool = DIR_GetBoolPref(replPrefName, "never", scratch, kDefaultReplicateNever);		DIR_ForceFlag(server, DIR_REPLICATE_NEVER, prefBool);		prefBool = DIR_GetBoolPref(replPrefName, "enabled", scratch, kDefaultReplicaEnabled);		DIR_ForceFlag(server, DIR_REPLICATION_ENABLED, prefBool);		server->replInfo->description = DIR_GetStringPref(replPrefName, "description", scratch, kDefaultReplicaDescription);		server->replInfo->syncURL = DIR_GetStringPref(replPrefName, "syncURL", scratch, nsnull);		server->replInfo->filter = DIR_GetStringPref(replPrefName, "filter", scratch, kDefaultReplicaFilter);		dir_CreateTokenListFromPref(replPrefName, "excludedAttributes", scratch, &server->replInfo->excludedAttributes, 		                            &server->replInfo->excludedAttributesCount);		/* The file name and data version must be set or we ignore the		 * remaining replication prefs.		 */		server->replInfo->fileName = DIR_GetStringPref(replPrefName, "fileName", scratch, kDefaultReplicaFileName);		server->replInfo->dataVersion = DIR_GetStringPref(replPrefName, "dataVersion", scratch, kDefaultReplicaDataVersion);		if (server->replInfo->fileName && server->replInfo->dataVersion)		{			server->replInfo->lastChangeNumber = DIR_GetIntPref(replPrefName, "lastChangeNumber", scratch, kDefaultReplicaChangeNumber);		}	}}/* Called at startup-time to read whatever overrides the LDAP site administrator has * done to the attribute names */static nsresult DIR_GetCustomAttributePrefs(const char *prefstring, DIR_Server *server, char *scratch){    nsresult rv = NS_OK;    nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &rv));     if (NS_FAILED(rv) || !pPref) 		return NS_ERROR_FAILURE;	char **tokenList = nsnull;	char *childList = nsnull;	PL_strcpy(scratch, prefstring);	PL_strcat(scratch, ".attributes");	if (PREF_NOERROR == pPref->CreateChildList(scratch, &childList))	{		if (childList && childList[0])		{			char *child = nsnull;			PRInt16 indx = 0;			while ((pPref->NextChild (childList, &indx, &child)) == NS_OK)			{				char *jsValue = nsnull;				if (PREF_NOERROR == pPref->CopyCharPref (child, &jsValue))				{					if (jsValue && jsValue[0])					{						char *attrName = child + PL_strlen(scratch) + 1;						DIR_AddCustomAttribute (server, attrName, jsValue);					}					PR_FREEIF(jsValue);				}			}		}		PR_FREEIF(childList);	}	if (0 == dir_CreateTokenListFromPref (prefstring, "basicSearchAttributes", scratch, 		&tokenList, &server->basicSearchAttributesCount))	{		dir_ConvertTokenListToIdList (server, tokenList, server->basicSearchAttributesCount, 			&server->basicSearchAttributes);		dir_DeleteTokenList (tokenList, server->basicSearchAttributesCount);	}	/* The DN, suppressed and url attributes can be attributes that	 * we've never heard of, so they're stored by name, so we can match 'em	 * as we get 'em from the server	 */	dir_CreateTokenListFromPref (prefstring, "html.dnAttributes", scratch, 		&server->dnAttributes, &server->dnAttributesCount);	dir_CreateTokenListFromPref (prefstring, "html.excludedAttributes", scratch, 		&server->suppressedAttributes, &server->suppressedAttributesCount);	dir_CreateTokenListFromPref (prefstring, "html.uriAttributes", scratch, 		&server->uriAttributes, &server->uriAttributesCount);	return NS_OK;}/* Called at startup-time to read whatever overrides the LDAP site administrator has * done to the filtering logic */static nsresult DIR_GetCustomFilterPrefs(const char *prefstring, DIR_Server *server, char *scratch){    nsresult status = NS_OK;    nsCOMPtr<nsIPref> pPref(do_GetService(NS_PREF_CONTRACTID, &status));     if (NS_FAILED(status) || !pPref) 		return NS_ERROR_FAILURE;	PRBool keepGoing = PR_TRUE;	PRInt32 filterNum = 1;	char *localScratch = (char*)PR_Malloc(128);	if (!localScratch)		return NS_ERROR_OUT_OF_MEMORY;	server->tokenSeps = DIR_GetStringPref (prefstring, "wordSeparators", localScratch, kDefaultTokenSeps);	while (keepGoing && NS_SUCCEEDED(status))	{		char *childList = nsnull;		PR_snprintf (scratch, 128, "%s.filter%d", prefstring, filterNum);		if (PREF_NOERROR == pPref->CreateChildList(scratch, &childList))		{			if ('\0' != childList[0])			{				DIR_Filter *filter = (DIR_Filter*) PR_Malloc (sizeof(DIR_Filter));				if (filter)				{					PRBool tempBool;					memset(filter, 0, sizeof(DIR_Filter));					/* Pull per-filter preferences out of JS values */					filter->string = DIR_GetStringPref (scratch, "string", localScratch, 						server->efficientWildcards ? kDefaultFilter : kDefaultEfficientFilter);					tempBool = DIR_GetBoolPref (scratch, "repeatFilterForWords", localScratch, kDefaultRepeatFilterForTokens);					if (tempBool)						filter->flags |= DIR_F_REPEAT_FILTER_FOR_TOKENS;					tempBool = DIR_GetBoolPref (scratch, "substituteStarsForSpaces", localScratch, kDefaultSubstStarsForSpaces);					if (tempBool)						filter->flags |= DIR_F_SUBST_STARS_FOR_SPACES;					/* Add resulting DIR_Filter to the list */					if (!server->customFilters)						server->customFilters = new nsVoidArray();					if (server->customFilters)						server->customFilters->AppendElement(filter);					else						status = NS_ERROR_OUT_OF_MEMORY;				}				else					status = NS_ERROR_OUT_OF_MEMORY;				filterNum++;			}			else				keepGoing = PR_FALSE;			PR_Free(childList);		}		else			keepGoing = PR_FALSE;	}	PR_Free(localScratch);	return status;}/* This will convert from the old preference that was a path and filename *//* to a just a filename */static void DIR_ConvertServerFileName(DIR_Server* pServer){	char* leafName = pServer->fileName;	char* newLeafName = nsnull;#if defined(XP_WIN) || defined(XP_OS2)	/* jefft -- bug 73349 This is to allow users share same address book.	 * It only works if the user specify a full path filename.	 */#ifdef XP_FileIsFullPath	if (! XP_FileIsFullPath(leafName))		newLeafName = XP_STRRCHR (leafName, '\\');#endif /* XP_FileIsFullPath */#else	newLeafName = strrchr(leafName, '/');#endif    pServer->fileName = newLeafName ? nsCRT::strdup(newLeafName + 1) : nsCRT::strdup(leafName);	if (leafName) PR_Free(leafName);}/* This will generate a correct filename and then remove the path */void DIR_SetFileName(char** fileName, const char* defaultName){	nsresult rv = NS_OK;	nsFileSpec* dbPath = nsnull;	nsCOMPtr<nsIAddrBookSession> abSession = 	         do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv); 	if(NS_SUCCEEDED(rv))		abSession->GetUserProfileDirectory(&dbPath);	if (dbPath)	{		(*dbPath) += defaultName;		dbPath->MakeUnique(defaultName);		char* file = nsnull;		file = dbPath->GetLeafName();        *fileName = nsCRT::strdup(file);		if (file)			nsCRT::free(file);      delete dbPath;	}}/****************************************************************Helper function used to generate a file name from the descriptionof a directory. Caller must free returned string. An extension is not applied *****************************************************************/char * dir_ConvertDescriptionToPrefName(DIR_Server * server){#define MAX_PREF_NAME_SIZE 25	char * fileName = nsnull;	char fileNameBuf[MAX_PREF_NAME_SIZE];	PRInt32 srcIndex = 0;	PRInt32 destIndex = 0;	PRInt32 numSrcBytes = 0;	const char * descr = nsnull;	if (server && server->description)	{		descr = server->description;		numSrcBytes = PL_strlen(descr);		while (srcIndex < numSrcBytes && destIndex < MAX_PREF_NAME_SIZE-1)		{			if (nsCRT::IsAsciiDigit(descr[srcIndex]) || nsCRT::IsAsciiAlpha(descr[srcIndex]) )			{				fileNameBuf[destIndex] = descr[srcIndex];				destIndex++;			}			srcIndex++;		}		fileNameBuf[destIndex] = '\0'; /* zero out the last character */	}	if (destIndex) /* have at least one character in the file name? */        fileName = nsCRT::strdup(fileNameBuf);	return fileName;}