NS_IMETHODIMP
nsSmtpService::CreateSmtpServer(nsISmtpServer **aResult)
{
    if (!aResult) return NS_ERROR_NULL_POINTER;

    loadSmtpServers();
    nsresult rv;
    
    PRInt32 i = 0;
    PRBool unique = PR_FALSE;

    findServerByKeyEntry entry;
    nsCAutoString key;
    
    do {
        key = "smtp";
        key.AppendInt(++i);
        
        entry.key = key.get();
        entry.server = nsnull;

        mSmtpServers.EnumerateForwards(findServerByKey, (void *)&entry);
        if (!entry.server) unique=PR_TRUE;
        
    } while (!unique);

    rv = createKeyedServer(key.get(), aResult);
    saveKeyList();
    return rv;
}
NS_IMETHODIMP
nsSmtpService::CreateServer(nsISmtpServer **aResult)
{
    if (!aResult) return NS_ERROR_NULL_POINTER;

    loadSmtpServers();
    nsresult rv;
    int32_t i = 0;
    bool unique = false;

    findServerByKeyEntry entry;
    nsAutoCString key;

    do {
        key = "smtp";
        key.AppendInt(++i);
        entry.key = key.get();
        entry.server = nullptr;

        mSmtpServers.EnumerateForwards(findServerByKey, (void *)&entry);
        if (!entry.server) unique=true;

    } while (!unique);

    rv = createKeyedServer(key.get(), aResult);
    NS_ENSURE_SUCCESS(rv, rv);
    return saveKeyList();
}
NS_IMETHODIMP
nsSmtpService::DeleteSmtpServer(nsISmtpServer *aServer)
{
    if (!aServer) return NS_OK;

    PRInt32 idx = mSmtpServers.IndexOf(aServer);
    if (idx == -1)
      return NS_OK;

    nsCString serverKey;
    aServer->GetKey(getter_Copies(serverKey));
    
    nsresult rv = mSmtpServers.RemoveObjectAt(idx);

    if (mDefaultSmtpServer.get() == aServer)
        mDefaultSmtpServer = nsnull;
    if (mSessionDefaultServer.get() == aServer)
        mSessionDefaultServer = nsnull;
    
    nsCAutoString newServerList;
    nsCString tmpStr = mServerKeyList;
    char *newStr = tmpStr.BeginWriting();
    char *token = NS_strtok(",", &newStr);
    while (token) {
      // only re-add the string if it's not the key
      if (strcmp(token, serverKey.get()) != 0) {
          if (newServerList.IsEmpty())
              newServerList = token;
          else {
            newServerList += ',';
            newServerList += token;
          }
      }
      token = NS_strtok(",", &newStr);
    }

    // make sure the server clears out it's values....
    aServer->ClearAllValues();

    mServerKeyList = newServerList;
    saveKeyList();
    return rv;
}
nsresult
nsSmtpService::loadSmtpServers()
{
    if (mSmtpServersLoaded)
      return NS_OK;
    
    nsresult rv;
    nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
    if (NS_FAILED(rv)) return rv;
    nsCOMPtr<nsIPrefBranch> prefRootBranch;
    prefService->GetBranch(nsnull, getter_AddRefs(prefRootBranch));
    if (NS_FAILED(rv)) return rv;

    nsCString tempServerList;
    nsCString serverList;
    rv = prefRootBranch->GetCharPref(PREF_MAIL_SMTPSERVERS, getter_Copies(tempServerList));

    //Get the pref in a tempServerList and then parse it to see if it has dupes.
    //if so remove the dupes and then create the serverList.
    if (!tempServerList.IsEmpty()) {

      // Tokenize the data and add each smtp server if it is not already there 
      // in the user's current smtp server list
      nsCStringArray servers;
      servers.ParseString(tempServerList.get(), SERVER_DELIMITER);
      nsCAutoString tempSmtpServer;
      for (PRInt32 i = 0; i < servers.Count(); i++)
      {
          if (servers.IndexOf(* (servers[i])) == i) {
            tempSmtpServer.Assign(* (servers[i]));
            tempSmtpServer.StripWhitespace();
            if (!serverList.IsEmpty())
              serverList += SERVER_DELIMITER;
            serverList += tempSmtpServer;
          }
      }
    }
    else {
      serverList = tempServerList;
    }

    // We need to check if we have any pre-configured smtp servers so that
    // those servers can be appended to the list. 
    nsCString appendServerList;
    rv = prefRootBranch->GetCharPref(PREF_MAIL_SMTPSERVERS_APPEND_SERVERS, getter_Copies(appendServerList));

    // Get the list of smtp servers (either from regular pref i.e, mail.smtpservers or
    // from preconfigured pref mail.smtpservers.appendsmtpservers) and create a keyed 
    // server list.
    if (!serverList.IsEmpty() || !appendServerList.IsEmpty()) {
    /** 
             * Check to see if we need to add pre-configured smtp servers.
             * Following prefs are important to note in understanding the procedure here.
             *
             * 1. pref("mailnews.append_preconfig_smtpservers.version", version number);
             * This pref registers the current version in the user prefs file. A default value 
             * is stored in mailnews.js file. If a given vendor needs to add more preconfigured 
             * smtp servers, the default version number can be increased. Comparing version 
             * number from user's prefs file and the default one from mailnews.js, we
             * can add new smtp servers and any other version level changes that need to be done.
             *
             * 2. pref("mail.smtpservers.appendsmtpservers", <comma separated servers list>);
             * This pref contains the list of pre-configured smp servers that ISP/Vendor wants to
             * to add to the existing servers list. 
             */
      nsCOMPtr<nsIPrefBranch> defaultsPrefBranch;
      rv = prefService->GetDefaultBranch(MAIL_ROOT_PREF, getter_AddRefs(defaultsPrefBranch));
      NS_ENSURE_SUCCESS(rv,rv);

      nsCOMPtr<nsIPrefBranch> prefBranch;
      rv = prefService->GetBranch(MAIL_ROOT_PREF, getter_AddRefs(prefBranch));
      NS_ENSURE_SUCCESS(rv,rv);

      PRInt32 appendSmtpServersCurrentVersion = 0;
      PRInt32 appendSmtpServersDefaultVersion = 0;
      rv = prefBranch->GetIntPref(APPEND_SERVERS_VERSION_PREF_NAME, &appendSmtpServersCurrentVersion);
      NS_ENSURE_SUCCESS(rv,rv);

      rv = defaultsPrefBranch->GetIntPref(APPEND_SERVERS_VERSION_PREF_NAME, &appendSmtpServersDefaultVersion);
      NS_ENSURE_SUCCESS(rv,rv);

      // Update the smtp server list if needed
      if ((appendSmtpServersCurrentVersion <= appendSmtpServersDefaultVersion)) {
        // If there are pre-configured servers, add them to the existing server list
        if (!appendServerList.IsEmpty()) {
          if (!serverList.IsEmpty()) {
            nsCStringArray existingSmtpServersArray;
            existingSmtpServersArray.ParseString(serverList.get(), SERVER_DELIMITER);

            // Tokenize the data and add each smtp server if it is not already there 
            // in the user's current smtp server list
            char *newSmtpServerStr = appendServerList.BeginWriting(); 
            char *token = NS_strtok(SERVER_DELIMITER, &newSmtpServerStr);

            nsCAutoString newSmtpServer;
            while (token) {
              if (token && *token) {
                newSmtpServer.Assign(token);
                newSmtpServer.StripWhitespace();
                if (existingSmtpServersArray.IndexOf(newSmtpServer) == -1) {
                  serverList += ",";
                  serverList += newSmtpServer;
                }
              }
              token = NS_strtok(SERVER_DELIMITER, &newSmtpServerStr);
            }
          }
          else {
            serverList = appendServerList;
          }
          // Increase the version number so that updates will happen as and when needed
          rv = prefBranch->SetIntPref(APPEND_SERVERS_VERSION_PREF_NAME, appendSmtpServersCurrentVersion + 1);
        }
      }

      char *newStr = serverList.BeginWriting();
      char *pref = NS_strtok(", ", &newStr);

      while (pref) {
        // fix for bug #96207
        // code above makes sure that no duplicate entries in mail.smtpservers find
        // their way to the mSmtpServers list.  But it doesn't check, if a server to be
        // added already is in mSmtpServers.  That can happen in mail has been sent before 
        // opening the settings (loading the list).
        // use GetServerByKey to check if the key (pref) is already in
        // in the list. If not it calls createKeyedServer directly.
        nsCOMPtr<nsISmtpServer> server;
        rv = GetServerByKey(pref, getter_AddRefs(server));
        NS_ASSERTION(NS_SUCCEEDED(rv), "GetServerByKey failed");
        pref = NS_strtok(", ", &newStr);
      }
    }

    saveKeyList();

    mSmtpServersLoaded = PR_TRUE;
    return NS_OK;
}
nsresult
nsSmtpService::loadSmtpServers()
{
  if (mSmtpServersLoaded)
    return NS_OK;
    
  nsresult rv;
  nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
  if (NS_FAILED(rv))
    return rv;
  nsCOMPtr<nsIPrefBranch> prefRootBranch;
  prefService->GetBranch(nullptr, getter_AddRefs(prefRootBranch));
  if (NS_FAILED(rv))
    return rv;

  nsCString serverList;
  rv = prefRootBranch->GetCharPref(PREF_MAIL_SMTPSERVERS, getter_Copies(serverList));
  serverList.StripWhitespace();

  nsTArray<nsCString> servers;
  ParseString(serverList, SERVER_DELIMITER, servers);

  /**
   * Check to see if we need to add pre-configured smtp servers.
   * Following prefs are important to note in understanding the procedure here.
   *
   * 1. pref("mailnews.append_preconfig_smtpservers.version", version number);
   * This pref registers the current version in the user prefs file. A default value
   * is stored in mailnews.js file. If a given vendor needs to add more preconfigured
   * smtp servers, the default version number can be increased. Comparing version
   * number from user's prefs file and the default one from mailnews.js, we
   * can add new smtp servers and any other version level changes that need to be done.
   *
   * 2. pref("mail.smtpservers.appendsmtpservers", <comma separated servers list>);
   * This pref contains the list of pre-configured smp servers that ISP/Vendor wants to
   * to add to the existing servers list.
   */
  nsCOMPtr<nsIPrefBranch> defaultsPrefBranch;
  rv = prefService->GetDefaultBranch(MAIL_ROOT_PREF, getter_AddRefs(defaultsPrefBranch));
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIPrefBranch> prefBranch;
  rv = prefService->GetBranch(MAIL_ROOT_PREF, getter_AddRefs(prefBranch));
  NS_ENSURE_SUCCESS(rv,rv);

  int32_t appendSmtpServersCurrentVersion = 0;
  int32_t appendSmtpServersDefaultVersion = 0;
  rv = prefBranch->GetIntPref(APPEND_SERVERS_VERSION_PREF_NAME, &appendSmtpServersCurrentVersion);
  NS_ENSURE_SUCCESS(rv,rv);

  rv = defaultsPrefBranch->GetIntPref(APPEND_SERVERS_VERSION_PREF_NAME, &appendSmtpServersDefaultVersion);
  NS_ENSURE_SUCCESS(rv,rv);

  // Update the smtp server list if needed
  if (appendSmtpServersCurrentVersion <= appendSmtpServersDefaultVersion) {
    // If there are pre-configured servers, add them to the existing server list
    nsCString appendServerList;
    rv = prefRootBranch->GetCharPref(PREF_MAIL_SMTPSERVERS_APPEND_SERVERS, getter_Copies(appendServerList));
    appendServerList.StripWhitespace();
    ParseString(appendServerList, SERVER_DELIMITER, servers);

    // Increase the version number so that updates will happen as and when needed
    prefBranch->SetIntPref(APPEND_SERVERS_VERSION_PREF_NAME, appendSmtpServersCurrentVersion + 1);
  }

  // use GetServerByKey to check if the key (pref) is already in
  // in the list. If not it calls createKeyedServer directly.

  for (uint32_t i = 0; i < servers.Length(); i++) {
    nsCOMPtr<nsISmtpServer> server;
    GetServerByKey(servers[i].get(), getter_AddRefs(server));
  }

  saveKeyList();

  mSmtpServersLoaded = true;
  return NS_OK;
}