diff --git a/mailnews/news/public/nsINNTPProtocol.idl b/mailnews/news/public/nsINNTPProtocol.idl index d17146c8418..fc8d788431e 100644 --- a/mailnews/news/public/nsINNTPProtocol.idl +++ b/mailnews/news/public/nsINNTPProtocol.idl @@ -27,6 +27,7 @@ interface nsIURI; interface nsINntpUrl; interface nsISupportsArray; interface nsIMsgFolder; +interface nsIMsgWindow; [scriptable, uuid(30106238-0991-11d4-a565-0060b0fc04b7)] interface nsINNTPProtocol : nsISupports { @@ -37,15 +38,11 @@ interface nsINNTPProtocol : nsISupports { ///////////////////////////////////////////////////////////////////////// void IsBusy(out boolean aIsConnectionBusy); - // Protocol instance examines the url, looking at the host name, - // user name and folder the action would be on in order to figure out - // if it can process this url. I decided to push the semantics about - // whether a connection can handle a url down into the connection level - // instead of in the connection cache. - void CanHandleUrl(in nsINntpUrl aNntpUrl, out boolean aCanRunUrl, - out boolean hasToWait); + void LoadNewsUrl(in nsIURI aUri, in nsISupports aConsumer); + void Initialize(in nsIURI aURL, in nsIMsgWindow aMsgWindow); + // Get last active time stamp void GetLastActiveTimeStamp(out PRTime aTimeStamp); - + void CloseConnection(); }; diff --git a/mailnews/news/public/nsINntpIncomingServer.idl b/mailnews/news/public/nsINntpIncomingServer.idl index 4be9a1d2ec9..21385794a7f 100644 --- a/mailnews/news/public/nsINntpIncomingServer.idl +++ b/mailnews/news/public/nsINntpIncomingServer.idl @@ -24,6 +24,9 @@ #include "nsIFileSpec.idl" interface nsIMsgNewsFolder; +interface nsINNTPProtocol; +interface nsIURI; +interface nsIMsgWindow; [scriptable, uuid(21ea0654-f773-11d2-8aec-004005263078)] interface nsINntpIncomingServer : nsISupports { @@ -49,6 +52,7 @@ interface nsINntpIncomingServer : nsISupports { attribute boolean newsrcHasChanged; + attribute long maximumConnectionsNumber; /* used when populating the subscribe dialog */ void addNewNewsgroup(in string name, in string state, in string count); void addSubscribedNewsgroups(); @@ -57,4 +61,10 @@ interface nsINntpIncomingServer : nsISupports { readonly attribute nsISupports firstGroupNeedingCounts; void displaySubscribedGroup(in nsIMsgNewsFolder msgFolder, in long firstMessage, in long lastMessage, in long totalMessages); + + + void GetNntpConnection(in nsIURI url, in nsIMsgWindow window, + out nsINNTPProtocol aNntpConnection); + void RemoveConnection(in nsINNTPProtocol aNntpConnection); + }; diff --git a/mailnews/news/src/nsNNTPProtocol.cpp b/mailnews/news/src/nsNNTPProtocol.cpp index b648502bc40..37c7ad01b58 100644 --- a/mailnews/news/src/nsNNTPProtocol.cpp +++ b/mailnews/news/src/nsNNTPProtocol.cpp @@ -443,6 +443,13 @@ nsDummyBufferStream::QueryInterface(REFNSIID aIID, void** result) return NS_ERROR_NO_INTERFACE; } +NS_IMPL_ADDREF_INHERITED(nsNNTPProtocol, nsMsgProtocol) +NS_IMPL_RELEASE_INHERITED(nsNNTPProtocol, nsMsgProtocol) + +NS_INTERFACE_MAP_BEGIN(nsNNTPProtocol) + NS_INTERFACE_MAP_ENTRY(nsINNTPProtocol) +NS_INTERFACE_MAP_END_INHERITING(nsMsgProtocol) + nsNNTPProtocol::nsNNTPProtocol(nsIURI * aURL, nsIMsgWindow *aMsgWindow) : nsMsgProtocol(aURL) { @@ -463,18 +470,20 @@ nsNNTPProtocol::nsNNTPProtocol(nsIURI * aURL, nsIMsgWindow *aMsgWindow) m_commandSpecificData = nsnull; m_searchData = nsnull; - if (aMsgWindow) { + if (aMsgWindow) m_msgWindow = aMsgWindow; - } m_runningURL = null_nsCOMPtr(); - + m_connectionBusy = PR_FALSE; + m_fromCache = PR_FALSE; + LL_I2L(m_lastActiveTimeStamp, 0); } nsNNTPProtocol::~nsNNTPProtocol() { if (m_nntpServer) { m_nntpServer->WriteNewsrcFile(); + m_nntpServer->RemoveConnection(this); } PR_FREEIF(m_currentGroup); if (m_lineStreamBuffer) { @@ -482,12 +491,16 @@ nsNNTPProtocol::~nsNNTPProtocol() } } -nsresult nsNNTPProtocol::Initialize(void) +NS_IMETHODIMP nsNNTPProtocol::Initialize(nsIURI * aURL, nsIMsgWindow *aMsgWindow) { nsresult rv = NS_OK; net_NewsChunkSize = DEFAULT_NEWS_CHUNK_SIZE; PRBool isSecure = PR_FALSE; + if (aMsgWindow) + m_msgWindow = aMsgWindow; + nsMsgProtocol::InitFromURI(aURL); + rv = m_url->GetHost(getter_Copies(m_hostName)); if (NS_FAILED(rv)) return rv; rv = m_url->GetPreHost(getter_Copies(m_userName)); @@ -541,6 +554,7 @@ nsresult nsNNTPProtocol::Initialize(void) // query the URL for a nsINNTPUrl m_runningURL = do_QueryInterface(m_url); + m_connectionBusy = PR_TRUE; if (NS_SUCCEEDED(rv) && m_runningURL) { // okay, now fill in our event sinks...Note that each getter ref counts before @@ -551,25 +565,27 @@ nsresult nsNNTPProtocol::Initialize(void) m_runningURL->GetNewsgroup(getter_AddRefs(m_newsgroup)); m_runningURL->GetOfflineNewsState(getter_AddRefs(m_offlineNewsState)); } - else { - return rv; - } + else { + return rv; + } - // call base class to set up the transport + if (!m_socketIsOpen) + { + // call base class to set up the transport if (isSecure) { rv = OpenNetworkSocket(m_url, "ssl"); } else { rv = OpenNetworkSocket(m_url, nsnull); } - + } m_dataBuf = (char *) PR_Malloc(sizeof(char) * OUTPUT_BUFFER_SIZE); m_dataBufSize = OUTPUT_BUFFER_SIZE; m_lineStreamBuffer = new nsMsgLineStreamBuffer(OUTPUT_BUFFER_SIZE, CRLF, PR_TRUE /* create new lines */); m_nextState = SEND_FIRST_NNTP_COMMAND; - m_nextStateAfterResponse = NNTP_CONNECT; + m_nextStateAfterResponse = NNTP_CONNECT; m_typeWanted = 0; m_responseCode = 0; m_previousResponseCode = 0; @@ -625,6 +641,27 @@ nsNNTPProtocol::InitializeNewsFolderFromUri(const char *uri) return NS_OK; } +/* void IsBusy (out boolean aIsConnectionBusy); */ +NS_IMETHODIMP nsNNTPProtocol::IsBusy(PRBool *aIsConnectionBusy) +{ + NS_ENSURE_ARG_POINTER(aIsConnectionBusy); + *aIsConnectionBusy = m_connectionBusy; + return NS_OK; +} + +/* void GetLastActiveTimeStamp (out PRTime aTimeStamp); */ +NS_IMETHODIMP nsNNTPProtocol::GetLastActiveTimeStamp(PRTime *aTimeStamp) +{ + NS_ENSURE_ARG_POINTER(aTimeStamp); + *aTimeStamp = m_lastActiveTimeStamp; + return NS_OK; +} + +NS_IMETHODIMP nsNNTPProtocol::LoadNewsUrl(nsIURI * aURL, nsISupports * aConsumer) +{ + return LoadUrl(aURL, aConsumer); +} + nsresult nsNNTPProtocol::LoadUrl(nsIURI * aURL, nsISupports * aConsumer) { @@ -637,6 +674,14 @@ nsresult nsNNTPProtocol::LoadUrl(nsIURI * aURL, nsISupports * aConsumer) nsCOMPtr message; nsresult rv = NS_OK; + // if this connection comes from the cache, we need to initialize the + // load group here, by generating the start request notification. + if (m_fromCache) + { + if (m_channelListener) + rv = m_channelListener->OnStartRequest(this, m_channelContext); + } + m_articleNumber = -1; rv = aURL->GetHost(getter_Copies(m_hostName)); if (NS_FAILED(rv)) return rv; @@ -645,6 +690,7 @@ nsresult nsNNTPProtocol::LoadUrl(nsIURI * aURL, nsISupports * aConsumer) m_runningURL = do_QueryInterface(aURL, &rv); if (NS_FAILED(rv)) return rv; + m_connectionBusy = PR_TRUE; m_runningURL->GetNewsAction(&m_newsAction); // okay, now fill in our event sinks...Note that each getter ref counts before @@ -4929,10 +4975,20 @@ nsresult nsNNTPProtocol::ProcessProtocolState(nsIURI * url, nsIInputStream * inp // cache so we aren't creating new connections to process each request... // but until that time, we always want to properly shutdown the connection + + m_connectionBusy = PR_FALSE; +#ifdef DEBUG_bienvenu +#define USE_CONN_CACHE +#endif +#ifdef USE_CONN_CACHE + mailnewsurl->SetUrlState(PR_FALSE, NS_OK); + m_lastActiveTimeStamp = PR_Now(); // remmeber when we last used this connection. + return CleanupAfterRunningUrl(); +#else SendData(mailnewsurl, NNTP_CMD_QUIT); // this will cause OnStopRequest get called, which will call CloseSocket() m_nextState = NEWS_FINISHED; // so we don't spin in the free state - return NS_OK; - break; + return NS_OK; +#endif case NEWS_FINISHED: return NS_OK; break; @@ -4954,7 +5010,13 @@ nsresult nsNNTPProtocol::ProcessProtocolState(nsIURI * url, nsIInputStream * inp return NS_OK; /* keep going */ } -nsresult nsNNTPProtocol::CloseSocket() +NS_IMETHODIMP nsNNTPProtocol::CloseConnection() +{ + SendData(nsnull, NNTP_CMD_QUIT); // this will cause OnStopRequest get called, which will call CloseSocket() + return NS_OK; +} + +nsresult nsNNTPProtocol::CleanupAfterRunningUrl() { /* do we need to know if we're parsing xover to call finish xover? */ /* yes, I think we do! Why did I think we should??? */ @@ -4962,7 +5024,15 @@ nsresult nsNNTPProtocol::CloseSocket() data, there was an error or we were interrupted or something. So, tell libmsg there was an abnormal exit so that it can free its data. */ - + + nsresult rv = NS_OK; + + if (m_channelListener) + rv = m_channelListener->OnStopRequest(this, m_channelContext, NS_OK, nsnull); + + if (m_loadGroup) + m_loadGroup->RemoveChannel(NS_STATIC_CAST(nsIChannel *, this), nsnull, NS_OK, nsnull); + if (m_newsgroupList) { int status; @@ -4977,10 +5047,6 @@ nsresult nsNNTPProtocol::CloseSocket() we be releasing it here? */ /* NS_RELEASE(m_newsgroup->GetNewsgroupList()); */ } -#ifdef UNREADY_CODE - if (cd->control_con) - cd->control_con->last_used_time = PR_Now(); -#endif PR_FREEIF(m_path); PR_FREEIF(m_responseText); @@ -4996,7 +5062,13 @@ nsresult nsNNTPProtocol::CloseSocket() m_cancelID = nsnull; m_runningURL = null_nsCOMPtr(); + m_connectionBusy = PR_FALSE; + return NS_OK; +} +nsresult nsNNTPProtocol::CloseSocket() +{ + CleanupAfterRunningUrl(); // is this needed? return nsMsgProtocol::CloseSocket(); } diff --git a/mailnews/news/src/nsNNTPProtocol.h b/mailnews/news/src/nsNNTPProtocol.h index 4db3c75149c..60d53cf6ecf 100644 --- a/mailnews/news/src/nsNNTPProtocol.h +++ b/mailnews/news/src/nsNNTPProtocol.h @@ -14,7 +14,7 @@ * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All + * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): @@ -30,6 +30,7 @@ #include "nsIBufferOutputStream.h" #include "nsINntpUrl.h" #include "nsINntpIncomingServer.h" +#include "nsINNTPProtocol.h" #include "nsIWebShell.h" // mscott - this dependency should only be temporary! @@ -144,20 +145,16 @@ NEWS_FREE, NEWS_FINISHED } StatesEnum; -class nsNNTPProtocol : public nsMsgProtocol +class nsNNTPProtocol : public nsINNTPProtocol, public nsMsgProtocol { public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSINNTPPROTOCOL // Creating a protocol instance requires the URL // need to call Initialize after we do a new of nsNNTPProtocol nsNNTPProtocol(nsIURI * aURL, nsIMsgWindow *aMsgWindow); virtual ~nsNNTPProtocol(); - // initialization function given a news url - NS_IMETHOD Initialize(void); - - // aConsumer is typically a display stream you may want the results to be displayed into... - virtual nsresult LoadUrl(nsIURI * aURL, nsISupports * aConsumer = nsnull); - // stop binding is a "notification" informing us that the stream associated with aURL is going away. NS_IMETHOD OnStopRequest(nsIChannel * aChannel, nsISupports * aCtxt, nsresult aStatus, const PRUnichar* aMsg); @@ -165,6 +162,8 @@ public: NS_IMETHOD Cancel(nsresult status); // handle stop button + nsresult LoadUrl(nsIURI * aURL, nsISupports * aConsumer); + private: // over-rides from nsMsgProtocol virtual nsresult ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream, @@ -175,7 +174,9 @@ private: // and then calls the base class to transmit the data PRInt32 SendData(nsIURI * aURL, const char * dataBuffer); - void ParseHeaderForCancel(char *buf); + nsresult CleanupAfterRunningUrl(); + + void ParseHeaderForCancel(char *buf); static PRBool CheckIfAuthor(nsISupports *aElement, void *data); @@ -198,6 +199,9 @@ private: // the nsINntpURL that is currently running nsCOMPtr m_runningURL; + PRBool m_connectionBusy; + PRBool m_fromCache; // is this connection from the cache? + PRTime m_lastActiveTimeStamp; nsNewsAction m_newsAction; // Generic state information -- What state are we in? What state do we want to go to diff --git a/mailnews/news/src/nsNntpIncomingServer.cpp b/mailnews/news/src/nsNntpIncomingServer.cpp index 89dbabab90a..8dc0c610dfa 100644 --- a/mailnews/news/src/nsNntpIncomingServer.cpp +++ b/mailnews/news/src/nsNntpIncomingServer.cpp @@ -31,10 +31,11 @@ #include "nsFileStream.h" #include "nsCOMPtr.h" #include "nsINntpService.h" - +#include "nsINNTPProtocol.h" #include "nsIRDFService.h" #include "nsRDFCID.h" #include "nsMsgNewsCID.h" +#include "nsNNTPProtocol.h" #define NEW_NEWS_DIR_NAME "News" #define PREF_MAIL_NEWSRC_ROOT "mail.newsrc_root" @@ -61,10 +62,11 @@ NS_IMPL_ISUPPORTS_INHERITED(nsNntpIncomingServer, nsNntpIncomingServer::nsNntpIncomingServer() { - NS_INIT_REFCNT(); + NS_INIT_REFCNT(); - mNewsrcHasChanged = PR_FALSE; + mNewsrcHasChanged = PR_FALSE; mGroupsEnumerator = nsnull; + NS_NewISupportsArray(getter_AddRefs(m_connectionCache)); } @@ -308,9 +310,163 @@ nsNntpIncomingServer::GetNewsrcHasChanged(PRBool *aNewsrcHasChanged) NS_IMETHODIMP nsNntpIncomingServer::CloseCachedConnections() { - return WriteNewsrcFile(); + // iterate through the connection cache for a connection that can handle this url. + PRUint32 cnt; + nsCOMPtr aSupport; + nsCOMPtr connection; + + if (m_connectionCache) + { + nsresult rv = m_connectionCache->Count(&cnt); + if (NS_FAILED(rv)) return rv; + for (PRUint32 i = 0; i < cnt; i++) + { + aSupport = getter_AddRefs(m_connectionCache->ElementAt(i)); + connection = do_QueryInterface(aSupport); + if (connection) + rv = connection->CloseConnection(); + } + } + return WriteNewsrcFile(); } +NS_IMPL_SERVERPREF_INT(nsNntpIncomingServer, MaximumConnectionsNumber, + "max_cached_connections"); + +PRBool +nsNntpIncomingServer::ConnectionTimeOut(nsINNTPProtocol* aConnection) +{ + PRBool retVal = PR_FALSE; + if (!aConnection) return retVal; + nsresult rv; + + PR_CEnterMonitor(this); + + PRTime cacheTimeoutLimits; + + LL_I2L(cacheTimeoutLimits, 170 * 1000000); // 170 seconds in microseconds + PRTime lastActiveTimeStamp; + rv = aConnection->GetLastActiveTimeStamp(&lastActiveTimeStamp); + + PRTime elapsedTime; + LL_SUB(elapsedTime, PR_Now(), lastActiveTimeStamp); + PRTime t; + LL_SUB(t, elapsedTime, cacheTimeoutLimits); + if (LL_GE_ZERO(t)) + { + nsCOMPtr aProtocol(do_QueryInterface(aConnection, + &rv)); + if (NS_SUCCEEDED(rv) && aProtocol) + { + m_connectionCache->RemoveElement(aConnection); + retVal = PR_TRUE; + } + } + PR_CExitMonitor(this); + return retVal; +} + + +nsresult +nsNntpIncomingServer::CreateProtocolInstance(nsINNTPProtocol ** aNntpConnection, nsIURI *url, + nsIMsgWindow *aMsgWindow) +{ + // create a new connection and add it to the connection cache + // we may need to flag the protocol connection as busy so we don't get + // a race + // condition where someone else goes through this code + nsNNTPProtocol * protocolInstance = new nsNNTPProtocol(url, aMsgWindow); + if (!protocolInstance) + return NS_ERROR_OUT_OF_MEMORY; +// nsresult rv = nsComponentManager::CreateInstance(kImapProtocolCID, nsnull, +// NS_GET_IID(nsINntpProtocol), +// (void **) &protocolInstance); + nsresult rv = protocolInstance->QueryInterface(NS_GET_IID(nsINNTPProtocol), (void **) aNntpConnection); + // take the protocol instance and add it to the connectionCache + if (NS_SUCCEEDED(rv) && *aNntpConnection) + m_connectionCache->AppendElement(*aNntpConnection); + return rv; +} + + +NS_IMETHODIMP +nsNntpIncomingServer::GetNntpConnection(nsIURI * aUri, nsIMsgWindow *aMsgWindow, + nsINNTPProtocol ** aNntpConnection) +{ + nsresult rv = NS_OK; + nsCOMPtr connection; + nsCOMPtr freeConnection; + PRBool isBusy = PR_FALSE; + + PR_CEnterMonitor(this); + + PRInt32 maxConnections = 2; // default to be 2 + rv = GetMaximumConnectionsNumber(&maxConnections); + if (NS_FAILED(rv) || maxConnections == 0) + { + maxConnections = 2; + rv = SetMaximumConnectionsNumber(maxConnections); + } + else if (maxConnections < 1) + { // forced to use at least 1 + maxConnections = 1; + rv = SetMaximumConnectionsNumber(maxConnections); + } + + *aNntpConnection = nsnull; + // iterate through the connection cache for a connection that can handle this url. + PRUint32 cnt; + nsCOMPtr aSupport; + + rv = m_connectionCache->Count(&cnt); + if (NS_FAILED(rv)) return rv; + for (PRUint32 i = 0; i < cnt && !isBusy; i++) + { + aSupport = getter_AddRefs(m_connectionCache->ElementAt(i)); + connection = do_QueryInterface(aSupport); + if (connection) + rv = connection->IsBusy(&isBusy); + if (NS_FAILED(rv)) + { + connection = null_nsCOMPtr(); + continue; + } + if (!freeConnection && !isBusy && connection) + { + freeConnection = connection; + } + } + + if (ConnectionTimeOut(connection)) + connection = null_nsCOMPtr(); + if (ConnectionTimeOut(freeConnection)) + freeConnection = null_nsCOMPtr(); + + // if we got here and we have a connection, then we should return it! + if (!isBusy && connection) + { + *aNntpConnection = freeConnection; + freeConnection->Initialize(aUri, aMsgWindow); + NS_IF_ADDREF(*aNntpConnection); + } + else // have no queueing mechanism - just create the protocol instance. + { + rv = CreateProtocolInstance(aNntpConnection, aUri, aMsgWindow); + } + return rv; +} + + +/* void RemoveConnection (in nsINNTPProtocol aNntpConnection); */ +NS_IMETHODIMP nsNntpIncomingServer::RemoveConnection(nsINNTPProtocol *aNntpConnection) +{ + if (aNntpConnection) + m_connectionCache->RemoveElement(aNntpConnection); + + return NS_OK; +} + + NS_IMETHODIMP nsNntpIncomingServer::AddSubscribedNewsgroups() { diff --git a/mailnews/news/src/nsNntpIncomingServer.h b/mailnews/news/src/nsNntpIncomingServer.h index 6e3bf6ccdeb..d29dd4fa4d8 100644 --- a/mailnews/news/src/nsNntpIncomingServer.h +++ b/mailnews/news/src/nsNntpIncomingServer.h @@ -36,6 +36,9 @@ #include "nsEnumeratorUtils.h" +class nsINntpUrl; +class nsIMsgMailNewsUrl; + /* get some implementation from nsMsgIncomingServer */ class nsNntpIncomingServer : public nsMsgIncomingServer, public nsINntpIncomingServer @@ -51,6 +54,11 @@ public: NS_IMETHOD GetLocalStoreType(char * *type); NS_IMETHOD CloseCachedConnections(); NS_IMETHOD PerformExpand(); +protected: + nsresult CreateProtocolInstance(nsINNTPProtocol ** aNntpConnection, nsIURI *url, + nsIMsgWindow *window); + PRBool ConnectionTimeOut(nsINNTPProtocol* aNntpConnection); + nsCOMPtr m_connectionCache; NS_IMETHOD PerformBiff(); NS_IMETHOD GetServerRequiresPasswordForBiff(PRBool *_retval); diff --git a/mailnews/news/src/nsNntpService.cpp b/mailnews/news/src/nsNntpService.cpp index 73953e1edff..8906f753578 100644 --- a/mailnews/news/src/nsNntpService.cpp +++ b/mailnews/news/src/nsNntpService.cpp @@ -774,10 +774,11 @@ nsresult nsNntpService::PostMessage(nsIFileSpec *fileToPost, const char *newsgro // almost there...now create a nntp protocol instance to run the url in... nsNNTPProtocol *nntpProtocol = nsnull; + // ### try to access cache - but can't find server yet... nntpProtocol = new nsNNTPProtocol(mailnewsurl, aMsgWindow); if (!nntpProtocol) return NS_ERROR_OUT_OF_MEMORY;; - rv = nntpProtocol->Initialize(); + rv = nntpProtocol->Initialize(mailnewsurl, aMsgWindow); if (NS_FAILED(rv)) return rv; nsCOMPtr post; @@ -790,7 +791,7 @@ nsresult nsNntpService::PostMessage(nsIFileSpec *fileToPost, const char *newsgro rv = nntpUrl->SetMessageToPost(post); if (NS_FAILED(rv)) return rv; - rv = nntpProtocol->LoadUrl(mailnewsurl, /* aConsumer */ nsnull); + rv = nntpProtocol->LoadNewsUrl(mailnewsurl, /* aConsumer */ nsnull); if (_retval) nntpUrl->QueryInterface(NS_GET_IID(nsIURI), (void **) _retval); @@ -842,21 +843,53 @@ nsresult nsNntpService::ConstructNntpUrl(const char * urlString, const char * ne } +nsresult +nsNntpService::GetProtocolForUri(nsIURI *aUri, nsIMsgWindow *aMsgWindow, nsINNTPProtocol **aProtocol) +{ + nsXPIDLCString hostName; + nsXPIDLCString userName; + + nsresult rv = aUri->GetHost(getter_Copies(hostName)); + rv = aUri->GetPreHost(getter_Copies(userName)); + + NS_WITH_SERVICE(nsIMsgAccountManager, accountManager, NS_MSGACCOUNTMANAGER_PROGID, &rv); + if (NS_FAILED(rv)) return rv; + + // find the incoming server + nsCOMPtr server; + nsCOMPtr nntpServer; + rv = accountManager->FindServer(userName, + hostName, + "nntp", + getter_AddRefs(server)); + + if (NS_FAILED(rv) || !server) + return rv; + + nntpServer = do_QueryInterface(server, &rv); + + if (!nntpServer || NS_FAILED(rv)) + return rv; + + rv = nntpServer->GetNntpConnection(aUri, aMsgWindow, aProtocol); + if (NS_FAILED(rv) || !*aProtocol) + return NS_ERROR_OUT_OF_MEMORY; + return rv; +} nsresult nsNntpService::RunNewsUrl(nsIURI * aUri, nsIMsgWindow *aMsgWindow, nsISupports * aConsumer) { nsresult rv; // almost there...now create a nntp protocol instance to run the url in... - nsNNTPProtocol *nntpProtocol = nsnull; + nsCOMPtr nntpProtocol; + rv = GetProtocolForUri(aUri, aMsgWindow, getter_AddRefs(nntpProtocol)); - nntpProtocol = new nsNNTPProtocol(aUri, aMsgWindow); - if (!nntpProtocol) return NS_ERROR_OUT_OF_MEMORY; - - rv = nntpProtocol->Initialize(); + if (NS_SUCCEEDED(rv)) + rv = nntpProtocol->Initialize(aUri, aMsgWindow); if (NS_FAILED(rv)) return rv; - rv = nntpProtocol->LoadUrl(aUri, aConsumer); + rv = nntpProtocol->LoadNewsUrl(aUri, aConsumer); return rv; } @@ -1061,13 +1094,13 @@ NS_IMETHODIMP nsNntpService::NewURI(const char *aSpec, nsIURI *aBaseURI, nsIURI NS_IMETHODIMP nsNntpService::NewChannel(nsIURI *aURI, nsIChannel **_retval) { nsresult rv = NS_OK; - nsNNTPProtocol *nntpProtocol = new nsNNTPProtocol(aURI, nsnull); - if (!nntpProtocol) return NS_ERROR_OUT_OF_MEMORY; - - rv = nntpProtocol->Initialize(); - if (NS_FAILED(rv)) return rv; + nsCOMPtr nntpProtocol; + rv = GetProtocolForUri(aURI, nsnull, getter_AddRefs(nntpProtocol)); + if (NS_SUCCEEDED(rv)) + rv = nntpProtocol->Initialize(aURI, nsnull); + if (NS_FAILED(rv)) return rv; - return nntpProtocol->QueryInterface(NS_GET_IID(nsIChannel), (void **) _retval); + return nntpProtocol->QueryInterface(NS_GET_IID(nsIChannel), (void **) _retval); } NS_IMETHODIMP diff --git a/mailnews/news/src/nsNntpService.h b/mailnews/news/src/nsNntpService.h index 3d1f6c094bd..fb2aa215007 100644 --- a/mailnews/news/src/nsNntpService.h +++ b/mailnews/news/src/nsNntpService.h @@ -71,6 +71,7 @@ protected: // a convience routine used to put together news urls. nsresult ConstructNntpUrl(const char * urlString, const char * newsgroupName, nsMsgKey key, nsIUrlListener *aUrlListener, nsIURI ** aUrl); + nsresult GetProtocolForUri(nsIURI *aUri, nsIMsgWindow *aMsgWindow, nsINNTPProtocol **aProtocol); // a convience routine to run news urls nsresult RunNewsUrl (nsIURI * aUrl, nsIMsgWindow *aMsgWindow, nsISupports * aConsumer); static PRBool findNewsServerWithGroup(nsISupports *aElement, void *data);