printf("don't set the prefs, they are already set since this ab was migrated\n");
PRINTF("don't set the prefs, they are already set since this ab was migrated\n");
static PRBool dir_IsServerDeleted(DIR_Server * server);static DIR_DefaultAttribute *DIR_GetDefaultAttribute (DIR_AttributeId id);static char *DIR_GetStringPref(const char *prefRoot, const char *prefLeaf, char *scratch, const char *defaultValue);static char *DIR_GetLocalizedStringPref(const char *prefRoot, const char *prefLeaf, char *scratch, const char *defaultValue);static PRInt32 DIR_GetIntPref(const char *prefRoot, const char *prefLeaf, char *scratch, PRInt32 defaultValue);static PRBool DIR_GetBoolPref(const char *prefRoot, const char *prefLeaf, char *scratch, PRBool defaultValue);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);// This can now use nsTextFormater. // e.g.// #include "nsTextFormater.h"// nsString aString(""); // nsAutoString fmt("%s"); // PRUnichar *uniBuffer = nsTextFormater::smprintf(fmt.GetUnicode(), aBuffer); // this converts UTF-8 to UCS-2 // Do not use void* that was inherited from old libmime when it could not include C++, use PRUnichar* instead.PRInt32 INTL_ConvertToUnicode(const char* aBuffer, const PRInt32 aLength,                                      void** uniBuffer){	if (nsnull == aBuffer) 	{		return -1;	}  NS_ConvertUTF8toUCS2 temp(aBuffer, aLength);  *uniBuffer = nsCRT::strdup(temp.GetUnicode());  return (*uniBuffer) ? 0 : -1;}// This can now use ToNewUTF8String (or this function itself can be substitued by that).// e.g.// nsAutoString aStr(uniBuffer);// *aBuffer = aStr.ToNewUTF8String();// Do not use void* that was inherited from old libmime when it could not include C++, use PRUnichar* instead.PRInt32 INTL_ConvertFromUnicode(const PRUnichar* uniBuffer, const PRInt32 uniLength, char** aBuffer){	if (nsnull == uniBuffer) 	{		return -1;	}  NS_ConvertUCS2toUTF8 temp(uniBuffer, uniLength);  *aBuffer = nsCRT::strdup(temp.GetBuffer());  return (*aBuffer) ? 0 : -1;}/***************************************************************************** * 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)	{        NS_WITH_SERVICE(nsIPref, pPref, kPrefCID, &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)			{				nsString name; name.AssignWithConversion(server->fileName);				PRInt32 pos = name.Find(ABFileName_kPreviousSuffix);				if (pos > 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 = PL_strdup(kMainPersonalAddressBook);					DIR_SavePrefsForOneServer(server);				}			}#ifdef CONVERT_TO_MORK_DONE			if (server && server->fileName)			{				nsString name(server->fileName);				PRInt32 pos = name.Find(ABFileName_kPreviousSuffix);				if (pos)				{					name.Cut(pos, PL_strlen(ABFileName_kPreviousSuffix));					name.Append(ABFileName_kCurrentSuffix);					PR_FREEIF (server->fileName);					server->fileName = name.ToNewCString();				}				DIR_SavePrefsForOneServer(server);			}#endif /* CONVERT_TO_MORK_DONE */		}	}	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;	NS_WITH_SERVICE(nsIPref, pPref, kPrefCID, &rv); 	if (NS_FAILED(rv) || !pPref) 		return NS_ERROR_FAILURE;	pPref->SavePrefFile();	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;	}	return NS_OK;}static NS_DEFINE_CID(kAddressBookDBCID, NS_ADDRDATABASE_CID);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, DIR_Server** pServer){	DIR_Server * server = (DIR_Server *) PR_Malloc(sizeof(DIR_Server));	DIR_InitServerWithType (server, PABDirectory);	if (!dir_ServerList)		DIR_GetDirServers();	if (dir_ServerList)	{		PRInt32 count = dir_ServerList->Count();		nsString descString(dirName);		PRInt32 unicharLength = descString.Length();		INTL_ConvertFromUnicode(dirName, unicharLength, &server->description);		server->position = count + 1;		if (fileName)			server->fileName = PL_strdup(fileName);		else			DIR_SetFileName(&server->fileName, kMainPersonalAddressBook);		dir_ServerList->AppendElement(server);		if (!migrating) {			DIR_SavePrefsForOneServer(server); 		}#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;		NS_WITH_SERVICE(nsIPref, pPref, kPrefCID, &rv); 		if (NS_FAILED(rv) || !pPref) 			return NS_ERROR_FAILURE;		pPref->SavePrefFile();		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);	if (dirType == LDAPDirectory)	{		server->columnAttributes = PL_strdup(kDefaultLDAPColumnHeaders);		server->dirType = LDAPDirectory;		server->isOffline = PR_TRUE;		server->csid = CS_UTF8;		server->locale = nsnull;	}	else if (dirType == PABDirectory)	{		server->columnAttributes = PL_strdup(kDefaultPABColumnHeaders);		server->dirType = PABDirectory;		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)	{		XP_BZERO(server, 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;	}	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 && !PL_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 = PL_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] = PL_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 = PL_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] = PL_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 = PL_strdup (inInfo->description);		if (inInfo->fileName)			outInfo->fileName = PL_strdup (inInfo->fileName);		if (inInfo->dataVersion)			outInfo->dataVersion = PL_strdup (inInfo->dataVersion);		if (inInfo->syncURL)			outInfo->syncURL = PL_strdup (inInfo->syncURL);		if (inInfo->filter)			outInfo->filter = PL_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)		{			XP_BZERO (*out, sizeof(DIR_Server));			if (in->prefName)			{				(*out)->prefName = PL_strdup(in->prefName);				if (!(*out)->prefName)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->description)			{				(*out)->description = PL_strdup(in->description);				if (!(*out)->description)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->serverName)			{				(*out)->serverName = PL_strdup(in->serverName);				if (!(*out)->serverName)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->searchBase)			{				(*out)->searchBase = PL_strdup(in->searchBase);				if (!(*out)->searchBase)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->fileName)			{				(*out)->fileName = PL_strdup(in->fileName);				if (!(*out)->fileName)					err = NS_ERROR_OUT_OF_MEMORY; 			}			if (in->columnAttributes)			{				(*out)->columnAttributes = PL_strdup(in->columnAttributes);				if (!(*out)->columnAttributes)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->locale)			{				(*out)->locale = PL_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 = PL_strdup (in->authDn);				if (!(*out)->authDn)					err = NS_ERROR_OUT_OF_MEMORY;			}			if (in->password)			{				(*out)->password = PL_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 = PL_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)				{					XP_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 = PL_strdup (in->customDisplayUrl);			if (in->searchPairList)				(*out)->searchPairList = PL_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;}/***************************************************************************** * Functions for manipulating DIR_Servers' positions *//* Worker function to sort the servers in the given list by position value. * Uses a simple bubble sort to perform the operation (the server list * shouldn't be too long, right?) */static void dir_SortServersByPosition(DIR_Server **serverList, PRInt32 count){	PRInt32 i, j;	DIR_Server *server;	for (i = 0; i < count - 1; i++)	{		for (j = i + 1; j < count; j++)		{			if (serverList[j]->position < serverList[i]->position)			{				server        = serverList[i];				serverList[i] = serverList[j];				serverList[j] = server;			}		}	}}/* Sorts the servers in the given list by position value and lock state * (in eight easy steps...). * * Here's how we do it: *  1) Create a list of the servers in array form from the list *  2) Separate the array into two parts, locked and unlocked servers *  3) Sort the locked portion of the array *  4) Sort the unlocked portion of the array *  5) Move unlocked servers to fill holes in the locked portion of the array *  6) Adjust any remaining unlocked servers positions to match the new order *  7) Delete the old server list *  8) Create a new server list based on the sorted order * * Returns PR_TRUE if the list was re-sorted. */PRBool DIR_SortServersByPosition(nsVoidArray *wholeList){	PRInt32		i, count, pos;	PRInt32		in_order;	nsVoidArray  *walkList;	DIR_Server  *server;	DIR_Server **serverList;	/* Allocate space for the array of servers.	 */	count = wholeList->Count();	serverList = (DIR_Server **)PR_Malloc(sizeof(DIR_Server *) * count);	if (!serverList)		return PR_FALSE;	/* Copy the servers in the list into the array in the same order.	 * While doing so check to see if the servers are aready in order.	 */	pos = 1;	in_order = 2;	walkList = wholeList;	count = walkList->Count();	for (i = 0; i < count;)	{		if ((server = (DIR_Server *)walkList->ElementAt(i)) != nsnull)		{			if (in_order > 0)			{				/* If the position values are out of order, then the list is				 * out of order.				 */				if (i > 0 && serverList[i - 1]->position > server->position)					in_order = 0;				else				{					/* The list is considered to be in order if the position					 * values are non-contiguous and all of the servers have					 * locked positions.					 */					if (in_order == 2 && server->position != pos)						in_order = 1;					if (in_order == 1 && !DIR_TestFlag(server, DIR_POSITION_LOCKED))						in_order = 0;				}			}			serverList[i++] = server;			pos++;		}	}	/* Don't do anything if the servers are already in order.	 */	if (in_order == 0)	{		PRInt32 first_unlocked, j;		/* Separate the array into two sections:  locked and unlocked.		 */		for (i = 0, j = count - 1; i < j; )		{			if (!DIR_TestFlag(serverList[i], DIR_POSITION_LOCKED))			{				while (i < j && !DIR_TestFlag(serverList[j], DIR_POSITION_LOCKED))					j--;				if (i < j)				{					server        = serverList[j];					serverList[j] = serverList[i];					serverList[i] = server;					i++, j--;				}			}			else				i++;		}			/* If there are no servers with locked positions, then the first		 * unlocked server is the first server.		 */		if (i == 0 && !DIR_TestFlag(serverList[0], DIR_POSITION_LOCKED))			first_unlocked = 0;		/* Otherwise, the first unlocked server is at the index of the		 * last locked server plus one.  Sort the subset of locked		 * servers.		 */		else		{			first_unlocked = i;			dir_SortServersByPosition(serverList, first_unlocked);		}		/* Sort the subset of servers with unlocked positions.		 */		dir_SortServersByPosition(&serverList[first_unlocked], count - first_unlocked);			/* Merge the two sub-lists by moving servers with unlocked positions		 * into the holes in the servers with locked positions.		 */		for (pos = 1, i = 0; i < first_unlocked; pos++, i++)		{			if (serverList[i]->position != pos && first_unlocked < count)			{				server                     = serverList[i];				serverList[i]              = serverList[first_unlocked];				serverList[first_unlocked] = server;				serverList[i]->position = pos;				first_unlocked++;			}		}		/* Adjust the position values of the remaining unlocked servers (those		 * not moved to fill holes in the locked servers).		 */		for (i = first_unlocked; i < count; i++)			serverList[i]->position = pos++;		/* Delete the old list.  We can't just call delete because		 * we must use the same list as passed in.		 */		for (i = count - 1; i >= 0; i--)			wholeList->RemoveElementAt(i);		/* Create a new list based on the array		 */		for (i = 0; i < count; i++)			wholeList->InsertElementAt(serverList[i], i);		/* Any time the unified server list is scrambled we need to notify		 * whoever is interested.		 */		if (wholeList == dir_ServerList)			DIR_SendNotification(nsnull, DIR_NOTIFY_SCRAMBLE, idNone);	}	PR_Free(serverList);	return in_order == 0;}/* 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;    NS_WITH_SERVICE(nsIPref, pPref, kPrefCID, &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)		{			char *name = PR_smprintf("%s.position", server->prefName);			if (name != nsnull)			{				/* We can't just delete default servers, we can only mark them				 * as "deleted" by setting their position to 0.  Since there				 * doesn't seem to be a way to figure out if a server is a				 * default server we must set the position of all deleted				 * servers to 0.				 */       			DIR_ClearPrefBranch(server->prefName);				pPref->SetIntPref(name, 0);				PR_smprintf_free(name);			}		}		/* 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;	}	/* If necessary, re-sort the server list.  This function tries to keep from	 * calling the sort function when it can, but complicated cases may be	 * more appropriate to leave up to the sort function to see if the list	 * needs to be re-sorted.	 */	if (resort)		resort = DIR_SortServersByPosition(wholeList);	/* 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;    NS_WITH_SERVICE(nsIPref, pPref, kPrefCID, &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 'v': /* vlvDisabled */		rc = idVLVDisabled;		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 (PL_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				         && PL_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 (PL_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 && PL_strcasecmp(server->serverName, serverName) == 0		    && server->searchBase && PL_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;}