Back to index

lightning-sunbird  0.9+nobinonly
nsSmtpService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "msgCore.h"    // precompiled header...
00040 #include "nsXPIDLString.h"
00041 #include "nsReadableUtils.h"
00042 #include "nsIPrefService.h"
00043 #include "nsIPrefBranch.h"
00044 #include "nsIIOService.h"
00045 #include "nsIPipe.h"
00046 #include "nsNetCID.h"
00047 #include "nsEscape.h"
00048 #include "nsNetUtil.h"
00049 
00050 #include "nsSmtpService.h"
00051 #include "nsIMsgMailSession.h"
00052 #include "nsMsgBaseCID.h"
00053 #include "nsMsgCompCID.h"
00054 
00055 #include "nsSmtpUrl.h"
00056 #include "nsSmtpProtocol.h"
00057 #include "nsIFileSpec.h"
00058 #include "nsCOMPtr.h"
00059 #include "nsIMsgIdentity.h"
00060 #include "nsMsgComposeStringBundle.h"
00061 #include "nsIPrompt.h"
00062 #include "nsIWindowWatcher.h"
00063 #include "nsMsgSimulateError.h"
00064 #include "nsIUTF8ConverterService.h"
00065 #include "nsUConvCID.h"
00066 
00067 #define SERVER_DELIMITER ","
00068 #define APPEND_SERVERS_VERSION_PREF_NAME "append_preconfig_smtpservers.version"
00069 #define MAIL_ROOT_PREF "mail."
00070 #define PREF_MAIL_SMTPSERVERS "mail.smtpservers"
00071 #define PREF_MAIL_SMTPSERVERS_APPEND_SERVERS "mail.smtpservers.appendsmtpservers"
00072 #define PREF_MAIL_SMTP_DEFAULTSERVER "mail.smtp.defaultserver"
00073 
00074 typedef struct _findServerByKeyEntry {
00075     const char *key;
00076     nsISmtpServer *server;
00077 } findServerByKeyEntry;
00078 
00079 typedef struct _findServerByHostnameEntry {
00080     const char *hostname;
00081     const char *username;
00082     nsISmtpServer *server;
00083 } findServerByHostnameEntry;
00084 
00085 static NS_DEFINE_CID(kCSmtpUrlCID, NS_SMTPURL_CID);
00086 static NS_DEFINE_CID(kCMailtoUrlCID, NS_MAILTOURL_CID);
00087 
00088 // foward declarations...
00089 nsresult
00090 NS_MsgBuildSmtpUrl(nsIFileSpec * aFilePath,
00091                    const char* aSmtpHostName, 
00092                    PRInt32 aSmtpPort,
00093                    const char* aSmtpUserName, 
00094                    const char* aRecipients, 
00095                    nsIMsgIdentity * aSenderIdentity,
00096                    nsIUrlListener * aUrlListener,
00097                    nsIMsgStatusFeedback *aStatusFeedback,
00098                    nsIInterfaceRequestor* aNotificationCallbacks,
00099                    nsIURI ** aUrl);
00100 
00101 nsresult NS_MsgLoadSmtpUrl(nsIURI * aUrl, nsISupports * aConsumer, nsIRequest ** aRequest);
00102 
00103 nsSmtpService::nsSmtpService() :
00104     mSmtpServersLoaded(PR_FALSE)
00105 {
00106     NS_NewISupportsArray(getter_AddRefs(mSmtpServers));
00107 }
00108 
00109 nsSmtpService::~nsSmtpService()
00110 {
00111     // save the SMTP servers to disk
00112 
00113 }
00114 
00115 NS_IMPL_ISUPPORTS2(nsSmtpService, nsISmtpService, nsIProtocolHandler)
00116 
00117 
00118 nsresult nsSmtpService::SendMailMessage(nsIFileSpec * aFilePath,
00119                                         const char * aRecipients, 
00120                                         nsIMsgIdentity * aSenderIdentity,
00121                                         const char * aPassword,
00122                                         nsIUrlListener * aUrlListener, 
00123                                         nsIMsgStatusFeedback *aStatusFeedback,
00124                                         nsIInterfaceRequestor* aNotificationCallbacks,
00125                                         nsIURI ** aURL,
00126                                         nsIRequest ** aRequest)
00127 {
00128   nsIURI * urlToRun = nsnull;
00129   nsresult rv = NS_OK;
00130 
00131   nsCOMPtr<nsISmtpServer> smtpServer;
00132   rv = GetSmtpServerByIdentity(aSenderIdentity, getter_AddRefs(smtpServer));
00133 
00134   if (NS_SUCCEEDED(rv) && smtpServer)
00135   {
00136     if (aPassword && *aPassword)
00137       smtpServer->SetPassword(aPassword);
00138 
00139     nsXPIDLCString smtpHostName;
00140     nsXPIDLCString smtpUserName;
00141     PRInt32 smtpPort;
00142     PRInt32 trySSL;
00143 
00144     smtpServer->GetHostname(getter_Copies(smtpHostName));
00145     smtpServer->GetUsername(getter_Copies(smtpUserName));
00146     smtpServer->GetPort(&smtpPort);
00147     smtpServer->GetTrySSL(&trySSL);
00148 
00149     if (smtpPort == 0)
00150     {
00151         if (trySSL == PREF_SECURE_ALWAYS_SMTPS)
00152             smtpPort = nsISmtpUrl::DEFAULT_SMTPS_PORT;
00153         else
00154             smtpPort = nsISmtpUrl::DEFAULT_SMTP_PORT;
00155     }
00156 
00157     if (smtpHostName && smtpHostName.get()[0] && !CHECK_SIMULATED_ERROR(SIMULATED_SEND_ERROR_10)) 
00158     {
00159       rv = NS_MsgBuildSmtpUrl(aFilePath, smtpHostName, smtpPort, smtpUserName,
00160                               aRecipients, aSenderIdentity, aUrlListener, aStatusFeedback, 
00161                               aNotificationCallbacks, &urlToRun); // this ref counts urlToRun
00162       if (NS_SUCCEEDED(rv) && urlToRun)   
00163       {
00164         nsCOMPtr<nsISmtpUrl> smtpUrl = do_QueryInterface(urlToRun, &rv);
00165         if (NS_SUCCEEDED(rv))
00166             smtpUrl->SetSmtpServer(smtpServer);
00167         rv = NS_MsgLoadSmtpUrl(urlToRun, nsnull, aRequest);
00168       }
00169 
00170       if (aURL) // does the caller want a handle on the url?
00171         *aURL = urlToRun; // transfer our ref count to the caller....
00172       else
00173         NS_IF_RELEASE(urlToRun);
00174     }
00175     else
00176       rv = NS_ERROR_COULD_NOT_LOGIN_TO_SMTP_SERVER;
00177   }
00178 
00179   return rv;
00180 }
00181 
00182 
00183 // The following are two convience functions I'm using to help expedite building and running a mail to url...
00184 
00185 // short cut function for creating a mailto url...
00186 nsresult NS_MsgBuildSmtpUrl(nsIFileSpec * aFilePath,
00187                             const char* aSmtpHostName, 
00188                             PRInt32 aSmtpPort,
00189                             const char* aSmtpUserName, 
00190                             const char * aRecipients, 
00191                             nsIMsgIdentity * aSenderIdentity,
00192                             nsIUrlListener * aUrlListener, 
00193                             nsIMsgStatusFeedback *aStatusFeedback,
00194                             nsIInterfaceRequestor* aNotificationCallbacks,
00195                             nsIURI ** aUrl)
00196 {
00197     // mscott: this function is a convience hack until netlib actually dispatches smtp urls.
00198     // in addition until we have a session to get a password, host and other stuff from, we need to use default values....
00199     // ..for testing purposes....
00200 
00201     nsresult rv = NS_OK;
00202     nsCOMPtr <nsISmtpUrl> smtpUrl (do_CreateInstance(kCSmtpUrlCID, &rv));
00203 
00204     if (NS_SUCCEEDED(rv) && smtpUrl)
00205     {
00206         nsCAutoString urlSpec("smtp://");
00207         if (aSmtpUserName) 
00208         {
00209             nsXPIDLCString escapedUsername;
00210             *((char **)getter_Copies(escapedUsername)) = nsEscape(aSmtpUserName, url_XAlphas);
00211             urlSpec += escapedUsername;
00212             urlSpec += '@';
00213         }
00214 
00215         urlSpec += aSmtpHostName;
00216         if (!PL_strchr(aSmtpHostName, ':'))
00217         {
00218             urlSpec += ':';
00219             urlSpec.AppendInt(aSmtpPort);
00220         }
00221 
00222         if (urlSpec.get())
00223         {
00224             nsCOMPtr<nsIMsgMailNewsUrl> url = do_QueryInterface(smtpUrl);
00225             url->SetSpec(urlSpec);
00226             smtpUrl->SetRecipients(aRecipients);
00227             smtpUrl->SetPostMessageFile(aFilePath);
00228             smtpUrl->SetSenderIdentity(aSenderIdentity);
00229             smtpUrl->SetNotificationCallbacks(aNotificationCallbacks);
00230 
00231             nsCOMPtr<nsIPrompt> smtpPrompt(do_GetInterface(aNotificationCallbacks));
00232             nsCOMPtr<nsIAuthPrompt> smtpAuthPrompt(do_GetInterface(aNotificationCallbacks));
00233             if (!smtpPrompt || !smtpAuthPrompt)
00234             {
00235                 nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00236                 if (wwatch) {
00237                     if (!smtpPrompt)
00238                         wwatch->GetNewPrompter(0, getter_AddRefs(smtpPrompt));
00239                     if (!smtpAuthPrompt)
00240                         wwatch->GetNewAuthPrompter(0, getter_AddRefs(smtpAuthPrompt));
00241                 }
00242             }
00243             smtpUrl->SetPrompt(smtpPrompt);            
00244             smtpUrl->SetAuthPrompt(smtpAuthPrompt);
00245             url->RegisterListener(aUrlListener);
00246             if (aStatusFeedback)
00247                 url->SetStatusFeedback(aStatusFeedback);
00248         }
00249         rv = smtpUrl->QueryInterface(NS_GET_IID(nsIURI), (void **) aUrl);
00250     }
00251 
00252     return rv;
00253 }
00254 
00255 nsresult NS_MsgLoadSmtpUrl(nsIURI * aUrl, nsISupports * aConsumer, nsIRequest ** aRequest)
00256 {
00257     // for now, assume the url is an smtp url and load it....
00258     nsCOMPtr <nsISmtpUrl> smtpUrl;
00259     nsSmtpProtocol   *smtpProtocol = nsnull;
00260     nsresult rv = NS_OK;
00261 
00262     if (!aUrl)
00263         return rv;
00264 
00265     // turn the url into an smtp url...
00266     smtpUrl = do_QueryInterface(aUrl);
00267     if (smtpUrl)
00268     {
00269         // almost there...now create a smtp protocol instance to run the url in...
00270         smtpProtocol = new nsSmtpProtocol(aUrl);
00271         if (smtpProtocol == nsnull)
00272             return NS_ERROR_OUT_OF_MEMORY;
00273 
00274         NS_ADDREF(smtpProtocol);
00275         rv = smtpProtocol->LoadUrl(aUrl, aConsumer); // protocol will get destroyed when url is completed...
00276         smtpProtocol->QueryInterface(NS_GET_IID(nsIRequest), (void **) aRequest);
00277         NS_RELEASE(smtpProtocol);
00278     }
00279 
00280     return rv;
00281 }
00282 
00283 NS_IMETHODIMP nsSmtpService::GetScheme(nsACString &aScheme)
00284 {
00285     aScheme = "mailto";
00286     return NS_OK; 
00287 }
00288 
00289 NS_IMETHODIMP nsSmtpService::GetDefaultPort(PRInt32 *aDefaultPort)
00290 {
00291     nsresult rv = NS_OK;
00292     if (aDefaultPort)
00293         *aDefaultPort = nsISmtpUrl::DEFAULT_SMTP_PORT;
00294     else
00295         rv = NS_ERROR_NULL_POINTER;
00296     return rv;
00297 }
00298 
00299 NS_IMETHODIMP 
00300 nsSmtpService::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
00301 {
00302     // allow smtp to run on any port
00303     *_retval = PR_TRUE;
00304     return NS_OK;
00305 }
00306 
00307 NS_IMETHODIMP nsSmtpService::GetProtocolFlags(PRUint32 *result)
00308 {
00309     *result = URI_NORELATIVE | ALLOWS_PROXY;
00310     return NS_OK;    
00311 }
00312 
00313 // the smtp service is also the protocol handler for mailto urls....
00314 
00315 NS_IMETHODIMP nsSmtpService::NewURI(const nsACString &aSpec,
00316                                     const char *aOriginCharset,
00317                                     nsIURI *aBaseURI,
00318                                     nsIURI **_retval)
00319 {
00320   // get a new smtp url 
00321 
00322   nsresult rv;
00323   nsCOMPtr <nsIURI> mailtoUrl = do_CreateInstance(kCMailtoUrlCID, &rv);
00324   if (NS_SUCCEEDED(rv))
00325   {
00326     nsCAutoString utf8Spec;
00327     if (aOriginCharset)
00328     {
00329        nsCOMPtr<nsIUTF8ConverterService> 
00330            utf8Converter(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID, &rv));
00331        if (NS_SUCCEEDED(rv))
00332           rv = utf8Converter->ConvertURISpecToUTF8(aSpec, aOriginCharset, utf8Spec);
00333     }
00334 
00335     // utf8Spec is filled up only when aOriginCharset is specified and 
00336     // the conversion is successful. Otherwise, fall back to aSpec.
00337     if (aOriginCharset && NS_SUCCEEDED(rv))
00338       mailtoUrl->SetSpec(utf8Spec);
00339     else
00340       mailtoUrl->SetSpec(aSpec);
00341     rv = mailtoUrl->QueryInterface(NS_GET_IID(nsIURI), (void **) _retval);
00342   }
00343   return rv;
00344 }
00345 
00346 NS_IMETHODIMP nsSmtpService::NewChannel(nsIURI *aURI, nsIChannel **_retval)
00347 {
00348   NS_ENSURE_ARG_POINTER(aURI);
00349   // create an empty pipe for use with the input stream channel.
00350   nsCOMPtr<nsIInputStream> pipeIn;
00351   nsCOMPtr<nsIOutputStream> pipeOut;
00352   nsresult rv = NS_NewPipe(getter_AddRefs(pipeIn),
00353                            getter_AddRefs(pipeOut));
00354   if (NS_FAILED(rv)) return rv;
00355 
00356   pipeOut->Close();
00357 
00358   return NS_NewInputStreamChannel(_retval, aURI, pipeIn,
00359                                   NS_LITERAL_CSTRING("application/x-mailto"));
00360 }
00361 
00362 
00363 NS_IMETHODIMP
00364 nsSmtpService::GetSmtpServers(nsISupportsArray ** aResult)
00365 {
00366   NS_ENSURE_ARG_POINTER(aResult);
00367 
00368   nsresult rv;
00369   
00370   // now read in the servers from prefs if necessary
00371   PRUint32 serverCount;
00372   rv = mSmtpServers->Count(&serverCount);
00373   if (NS_FAILED(rv)) return rv;
00374 
00375   if (serverCount<=0) loadSmtpServers();
00376 
00377   *aResult = mSmtpServers;
00378   NS_ADDREF(*aResult);
00379 
00380   return NS_OK;
00381 }
00382 
00383 nsresult
00384 nsSmtpService::loadSmtpServers()
00385 {
00386     if (mSmtpServersLoaded) return NS_OK;
00387     
00388     nsresult rv;
00389     nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00390     if (NS_FAILED(rv)) return rv;
00391     nsCOMPtr<nsIPrefBranch> prefRootBranch;
00392     prefService->GetBranch(nsnull, getter_AddRefs(prefRootBranch));
00393     if (NS_FAILED(rv)) return rv;
00394 
00395     nsXPIDLCString tempServerList;
00396     nsXPIDLCString serverList;
00397     rv = prefRootBranch->GetCharPref(PREF_MAIL_SMTPSERVERS, getter_Copies(tempServerList));
00398 
00399     //Get the pref in a tempServerList and then parse it to see if it has dupes.
00400     //if so remove the dupes and then create the serverList.
00401     if (!tempServerList.IsEmpty()) {
00402 
00403       // Tokenize the data and add each smtp server if it is not already there 
00404       // in the user's current smtp server list
00405       nsCStringArray servers;
00406       servers.ParseString(tempServerList.get(), SERVER_DELIMITER);
00407       nsCAutoString tempSmtpServer;
00408       for (PRInt32 i = 0; i < servers.Count(); i++)
00409       {
00410           if (servers.IndexOf(* (servers[i])) == i) {
00411             tempSmtpServer.Assign(* (servers[i]));
00412             tempSmtpServer.StripWhitespace();
00413             if (!serverList.IsEmpty())
00414               serverList += SERVER_DELIMITER;
00415             serverList += tempSmtpServer;
00416           }
00417       }
00418     }
00419     else {
00420       serverList = tempServerList;
00421     }
00422 
00423     // We need to check if we have any pre-configured smtp servers so that
00424     // those servers can be appended to the list. 
00425     nsXPIDLCString appendServerList;
00426     rv = prefRootBranch->GetCharPref(PREF_MAIL_SMTPSERVERS_APPEND_SERVERS, getter_Copies(appendServerList));
00427 
00428     // Get the list of smtp servers (either from regular pref i.e, mail.smtpservers or
00429     // from preconfigured pref mail.smtpservers.appendsmtpservers) and create a keyed 
00430     // server list.
00431     if (!serverList.IsEmpty() || !appendServerList.IsEmpty()) {
00447       nsCOMPtr<nsIPrefBranch> defaultsPrefBranch;
00448       rv = prefService->GetDefaultBranch(MAIL_ROOT_PREF, getter_AddRefs(defaultsPrefBranch));
00449       NS_ENSURE_SUCCESS(rv,rv);
00450 
00451       nsCOMPtr<nsIPrefBranch> prefBranch;
00452       rv = prefService->GetBranch(MAIL_ROOT_PREF, getter_AddRefs(prefBranch));
00453       NS_ENSURE_SUCCESS(rv,rv);
00454 
00455       PRInt32 appendSmtpServersCurrentVersion=0;
00456       PRInt32 appendSmtpServersDefaultVersion=0;
00457       rv = prefBranch->GetIntPref(APPEND_SERVERS_VERSION_PREF_NAME, &appendSmtpServersCurrentVersion);
00458       NS_ENSURE_SUCCESS(rv,rv);
00459 
00460       rv = defaultsPrefBranch->GetIntPref(APPEND_SERVERS_VERSION_PREF_NAME, &appendSmtpServersDefaultVersion);
00461       NS_ENSURE_SUCCESS(rv,rv);
00462 
00463       // Update the smtp server list if needed
00464       if ((appendSmtpServersCurrentVersion <= appendSmtpServersDefaultVersion)) {
00465         // If there are pre-configured servers, add them to the existing server list
00466         if (!appendServerList.IsEmpty()) {
00467           if (!serverList.IsEmpty()) {
00468             nsCStringArray existingSmtpServersArray;
00469             existingSmtpServersArray.ParseString(serverList.get(), SERVER_DELIMITER);
00470 
00471             // Tokenize the data and add each smtp server if it is not already there 
00472             // in the user's current smtp server list
00473             char *newSmtpServerStr;
00474             char *preConfigSmtpServersStr = ToNewCString(appendServerList);
00475   
00476             char *token = nsCRT::strtok(preConfigSmtpServersStr, SERVER_DELIMITER, &newSmtpServerStr);
00477 
00478             nsCAutoString newSmtpServer;
00479             while (token) {
00480               if (token && *token) {
00481                 newSmtpServer.Assign(token);
00482                 newSmtpServer.StripWhitespace();
00483 
00484                 if (existingSmtpServersArray.IndexOf(newSmtpServer) == -1) {
00485                   serverList += ",";
00486                   serverList += newSmtpServer;
00487                 }
00488               }
00489               token = nsCRT::strtok(newSmtpServerStr, SERVER_DELIMITER, &newSmtpServerStr);
00490             }
00491             PR_Free(preConfigSmtpServersStr);
00492           }
00493           else {
00494             serverList = appendServerList;
00495           }
00496           // Increase the version number so that updates will happen as and when needed
00497           rv = prefBranch->SetIntPref(APPEND_SERVERS_VERSION_PREF_NAME, appendSmtpServersCurrentVersion + 1);
00498         }
00499       }
00500 
00501       char *newStr;
00502       char *pref = nsCRT::strtok(serverList.BeginWriting(), ", ", &newStr);
00503 
00504       while (pref) {
00505         // fix for bug #96207
00506         // code above makes sure that no duplicate entries in mail.smtpservers find
00507         // their way to the mSmtpServers list.  But it doesn't check, if a server to be
00508         // added already is in mSmtpServers.  That can happen in mail has been sent before 
00509         // opening the settings (loading the list).
00510         // use GetServerByKey to check if the key (pref) is already in
00511         // in the list. If not it calls createKeyedServer directly.
00512         nsCOMPtr<nsISmtpServer> server;
00513         rv = GetServerByKey(pref, getter_AddRefs(server));
00514         NS_ASSERTION(NS_SUCCEEDED(rv), "GetServerByKey failed");
00515         pref = nsCRT::strtok(newStr, ", ", &newStr);
00516       }
00517     }
00518 
00519     saveKeyList();
00520 
00521     mSmtpServersLoaded = PR_TRUE;
00522     return NS_OK;
00523 }
00524 
00525 // save the list of keys
00526 nsresult
00527 nsSmtpService::saveKeyList()
00528 {
00529     nsresult rv;
00530     nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00531     if (NS_FAILED(rv)) return rv;
00532     
00533     return prefBranch->SetCharPref(PREF_MAIL_SMTPSERVERS, mServerKeyList.get());
00534 }
00535 
00536 nsresult
00537 nsSmtpService::createKeyedServer(const char *key, nsISmtpServer** aResult)
00538 {
00539     if (!key) return NS_ERROR_NULL_POINTER;
00540     
00541     nsresult rv;
00542     nsCOMPtr<nsISmtpServer> server = do_CreateInstance(NS_SMTPSERVER_CONTRACTID, &rv);
00543     if (NS_FAILED(rv)) return rv;
00544     
00545     server->SetKey(key);
00546     mSmtpServers->AppendElement(server);
00547 
00548     if (mServerKeyList.IsEmpty())
00549         mServerKeyList = key;
00550     else {
00551         mServerKeyList.Append(',');
00552         mServerKeyList += key;
00553     }
00554 
00555     if (aResult) {
00556         *aResult = server;
00557         NS_IF_ADDREF(*aResult);
00558     }
00559     return NS_OK;
00560 }
00561 
00562 NS_IMETHODIMP
00563 nsSmtpService::GetSessionDefaultServer(nsISmtpServer **aServer)
00564 {
00565     NS_ENSURE_ARG_POINTER(aServer);
00566     
00567     if (!mSessionDefaultServer)
00568         return GetDefaultServer(aServer);
00569 
00570     *aServer = mSessionDefaultServer;
00571     NS_ADDREF(*aServer);
00572     return NS_OK;
00573 }
00574 
00575 NS_IMETHODIMP
00576 nsSmtpService::SetSessionDefaultServer(nsISmtpServer *aServer)
00577 {
00578     mSessionDefaultServer = aServer;
00579     return NS_OK;
00580 }
00581 
00582 NS_IMETHODIMP
00583 nsSmtpService::GetDefaultServer(nsISmtpServer **aServer)
00584 {
00585   NS_ENSURE_ARG_POINTER(aServer);
00586 
00587   nsresult rv;
00588 
00589   loadSmtpServers();
00590   
00591   *aServer = nsnull;
00592   // always returns NS_OK, just leaving *aServer at nsnull
00593   if (!mDefaultSmtpServer) {
00594       nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00595       if (NS_FAILED(rv)) return rv;
00596 
00597       // try to get it from the prefs
00598       nsXPIDLCString defaultServerKey;
00599       rv = prefBranch->GetCharPref(PREF_MAIL_SMTP_DEFAULTSERVER, getter_Copies(defaultServerKey));
00600       if (NS_SUCCEEDED(rv) &&
00601           !defaultServerKey.IsEmpty()) {
00602 
00603           nsCOMPtr<nsISmtpServer> server;
00604           rv = GetServerByKey(defaultServerKey,
00605                               getter_AddRefs(mDefaultSmtpServer));
00606       } else {
00607           // no pref set, so just return the first one, and set the pref
00608       
00609           PRUint32 count=0;
00610           nsCOMPtr<nsISupportsArray> smtpServers;
00611           rv = GetSmtpServers(getter_AddRefs(smtpServers));
00612           rv = smtpServers->Count(&count);
00613 
00614           // nothing in the array, we had better create a new server
00615           // (which will add it to the array & prefs anyway)
00616           if (count == 0)
00617               return nsnull;//if there are no smtp servers then dont create one for the default.
00618           else
00619               rv = mSmtpServers->QueryElementAt(0, NS_GET_IID(nsISmtpServer),
00620                                                 (void **)getter_AddRefs(mDefaultSmtpServer));
00621 
00622           if (NS_FAILED(rv)) return rv;
00623           NS_ENSURE_TRUE(mDefaultSmtpServer, NS_ERROR_UNEXPECTED);
00624           
00625           // now we have a default server, set the prefs correctly
00626           nsXPIDLCString serverKey;
00627           mDefaultSmtpServer->GetKey(getter_Copies(serverKey));
00628           if (NS_SUCCEEDED(rv))
00629               prefBranch->SetCharPref(PREF_MAIL_SMTP_DEFAULTSERVER, serverKey);
00630       }
00631   }
00632 
00633   // at this point:
00634   // * mDefaultSmtpServer has a valid server
00635   // * the key has been set in the prefs
00636     
00637   *aServer = mDefaultSmtpServer;
00638   NS_IF_ADDREF(*aServer);
00639 
00640   return NS_OK;
00641 }
00642 
00643 NS_IMETHODIMP
00644 nsSmtpService::SetDefaultServer(nsISmtpServer *aServer)
00645 {
00646     NS_ENSURE_ARG_POINTER(aServer);
00647 
00648     mDefaultSmtpServer = aServer;
00649 
00650     nsXPIDLCString serverKey;
00651     nsresult rv = aServer->GetKey(getter_Copies(serverKey));
00652     NS_ENSURE_SUCCESS(rv,rv);
00653     
00654     nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
00655     NS_ENSURE_SUCCESS(rv,rv);
00656     prefBranch->SetCharPref(PREF_MAIL_SMTP_DEFAULTSERVER, serverKey);
00657     return NS_OK;
00658 }
00659 
00660 PRBool
00661 nsSmtpService::findServerByKey (nsISupports *element, void *aData)
00662 {
00663     nsresult rv;
00664     nsCOMPtr<nsISmtpServer> server = do_QueryInterface(element, &rv);
00665     if (NS_FAILED(rv)) return PR_TRUE;
00666     
00667     findServerByKeyEntry *entry = (findServerByKeyEntry*) aData;
00668 
00669     nsXPIDLCString key;
00670     rv = server->GetKey(getter_Copies(key));
00671     if (NS_FAILED(rv)) return PR_TRUE;
00672 
00673     if (nsCRT::strcmp(key, entry->key)==0) {
00674         entry->server = server;
00675         return PR_FALSE;
00676     }
00677     
00678     return PR_TRUE;
00679 }
00680 
00681 NS_IMETHODIMP
00682 nsSmtpService::CreateSmtpServer(nsISmtpServer **aResult)
00683 {
00684     if (!aResult) return NS_ERROR_NULL_POINTER;
00685 
00686     loadSmtpServers();
00687     nsresult rv;
00688     
00689     PRInt32 i=0;
00690     PRBool unique = PR_FALSE;
00691 
00692     findServerByKeyEntry entry;
00693     nsCAutoString key;
00694     
00695     do {
00696         key = "smtp";
00697         key.AppendInt(++i);
00698         
00699         entry.key = key.get();
00700         entry.server = nsnull;
00701 
00702         mSmtpServers->EnumerateForwards(findServerByKey, (void *)&entry);
00703         if (!entry.server) unique=PR_TRUE;
00704         
00705     } while (!unique);
00706 
00707     rv = createKeyedServer(key.get(), aResult);
00708     saveKeyList();
00709     return rv;
00710 }
00711 
00712 
00713 nsresult
00714 nsSmtpService::GetServerByKey(const char* aKey, nsISmtpServer **aResult)
00715 {
00716     NS_ENSURE_ARG_POINTER(aResult);
00717 
00718     if (!aKey || !*aKey)
00719     {
00720       NS_ASSERTION(PR_FALSE, "bad key");
00721       return NS_ERROR_FAILURE;
00722     }
00723     findServerByKeyEntry entry;
00724     entry.key = aKey;
00725     entry.server = nsnull;
00726     mSmtpServers->EnumerateForwards(findServerByKey, (void *)&entry);
00727 
00728     if (entry.server) {
00729         (*aResult) = entry.server;
00730         NS_ADDREF(*aResult);
00731         return NS_OK;
00732     }
00733 
00734     // not found in array, I guess we load it
00735     return createKeyedServer(aKey, aResult);
00736 }
00737 
00738 NS_IMETHODIMP
00739 nsSmtpService::DeleteSmtpServer(nsISmtpServer *aServer)
00740 {
00741     if (!aServer) return NS_OK;
00742 
00743     nsresult rv;
00744 
00745     PRInt32 idx = 0;
00746     rv = mSmtpServers->GetIndexOf(aServer, &idx);
00747     if (NS_FAILED(rv) || idx==-1)
00748         return NS_OK;
00749 
00750     nsXPIDLCString serverKey;
00751     aServer->GetKey(getter_Copies(serverKey));
00752     
00753     rv = mSmtpServers->DeleteElementAt(idx);
00754 
00755     if (mDefaultSmtpServer.get() == aServer)
00756         mDefaultSmtpServer = nsnull;
00757     if (mSessionDefaultServer.get() == aServer)
00758         mSessionDefaultServer = nsnull;
00759     
00760     nsCAutoString newServerList;
00761     char *newStr;
00762     char *rest = ToNewCString(mServerKeyList);
00763     
00764     char *token = nsCRT::strtok(rest, ",", &newStr);
00765     while (token) {
00766         // only re-add the string if it's not the key
00767         if (nsCRT::strcmp(token, serverKey) != 0) {
00768             if (newServerList.IsEmpty())
00769                 newServerList = token;
00770             else {
00771                 newServerList += ',';
00772                 newServerList += token;
00773             }
00774         }
00775 
00776         token = nsCRT::strtok(newStr, ",", &newStr);
00777     }
00778 
00779     // make sure the server clears out it's values....
00780     aServer->ClearAllValues();
00781 
00782     mServerKeyList = newServerList;
00783     saveKeyList();
00784     return rv;
00785 }
00786 
00787 PRBool
00788 nsSmtpService::findServerByHostname(nsISupports *element, void *aData)
00789 {
00790     nsresult rv;
00791     
00792     nsCOMPtr<nsISmtpServer> server = do_QueryInterface(element, &rv);
00793     if (NS_FAILED(rv)) return PR_TRUE;
00794 
00795     findServerByHostnameEntry *entry = (findServerByHostnameEntry*)aData;
00796 
00797     nsXPIDLCString hostname;
00798     rv = server->GetHostname(getter_Copies(hostname));
00799     if (NS_FAILED(rv)) return PR_TRUE;
00800 
00801    nsXPIDLCString username;
00802     rv = server->GetUsername(getter_Copies(username));
00803     if (NS_FAILED(rv)) return PR_TRUE;
00804 
00805     PRBool checkHostname = entry->hostname && PL_strcmp(entry->hostname, "");
00806     PRBool checkUsername = entry->username && PL_strcmp(entry->username, "");
00807     
00808     if ((!checkHostname || (PL_strcasecmp(entry->hostname, hostname)==0)) &&
00809         (!checkUsername || (PL_strcmp(entry->username, username)==0))) {
00810         entry->server = server;
00811         return PR_FALSE;        // stop when found
00812     }
00813     return PR_TRUE;
00814 }
00815 
00816 NS_IMETHODIMP
00817 nsSmtpService::FindServer(const char *aUsername,
00818                           const char *aHostname, nsISmtpServer ** aResult)
00819 {
00820     NS_ENSURE_ARG_POINTER(aResult);
00821 
00822     findServerByHostnameEntry entry;
00823     entry.server=nsnull;
00824     entry.hostname = aHostname;
00825     entry.username = aUsername;
00826 
00827     mSmtpServers->EnumerateForwards(findServerByHostname, (void *)&entry);
00828 
00829     // entry.server may be null, but that's ok.
00830     // just return null if no server is found
00831     *aResult = entry.server;
00832     NS_IF_ADDREF(*aResult);
00833     
00834     return NS_OK;
00835 }
00836 
00837 NS_IMETHODIMP
00838 nsSmtpService::GetSmtpServerByIdentity(nsIMsgIdentity *aSenderIdentity, nsISmtpServer **aSmtpServer)
00839 {
00840   NS_ENSURE_ARG_POINTER(aSmtpServer);
00841   nsresult rv = NS_ERROR_FAILURE;
00842 
00843   // First try the identity's preferred server
00844   if (aSenderIdentity) {
00845       nsXPIDLCString smtpServerKey;
00846       rv = aSenderIdentity->GetSmtpServerKey(getter_Copies(smtpServerKey));
00847       if (NS_SUCCEEDED(rv) && !(smtpServerKey.IsEmpty()))
00848           rv = GetServerByKey(smtpServerKey, aSmtpServer);
00849   }
00850 
00851   // Fallback to the default
00852   if (NS_FAILED(rv) || !(*aSmtpServer))
00853       rv = GetDefaultServer(aSmtpServer);
00854   return rv;
00855 }