work on nntp connection cache,not turned on yet r=sspitzer 13506

This commit is contained in:
bienvenu%netscape.com 2000-04-13 14:41:35 +00:00
Родитель 9e5e574372
Коммит a3ebd05505
8 изменённых файлов: 334 добавлений и 53 удалений

Просмотреть файл

@ -27,6 +27,7 @@ interface nsIURI;
interface nsINntpUrl; interface nsINntpUrl;
interface nsISupportsArray; interface nsISupportsArray;
interface nsIMsgFolder; interface nsIMsgFolder;
interface nsIMsgWindow;
[scriptable, uuid(30106238-0991-11d4-a565-0060b0fc04b7)] [scriptable, uuid(30106238-0991-11d4-a565-0060b0fc04b7)]
interface nsINNTPProtocol : nsISupports { interface nsINNTPProtocol : nsISupports {
@ -37,15 +38,11 @@ interface nsINNTPProtocol : nsISupports {
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
void IsBusy(out boolean aIsConnectionBusy); void IsBusy(out boolean aIsConnectionBusy);
// Protocol instance examines the url, looking at the host name, void LoadNewsUrl(in nsIURI aUri, in nsISupports aConsumer);
// user name and folder the action would be on in order to figure out void Initialize(in nsIURI aURL, in nsIMsgWindow aMsgWindow);
// 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);
// Get last active time stamp // Get last active time stamp
void GetLastActiveTimeStamp(out PRTime aTimeStamp); void GetLastActiveTimeStamp(out PRTime aTimeStamp);
void CloseConnection();
}; };

Просмотреть файл

@ -24,6 +24,9 @@
#include "nsIFileSpec.idl" #include "nsIFileSpec.idl"
interface nsIMsgNewsFolder; interface nsIMsgNewsFolder;
interface nsINNTPProtocol;
interface nsIURI;
interface nsIMsgWindow;
[scriptable, uuid(21ea0654-f773-11d2-8aec-004005263078)] [scriptable, uuid(21ea0654-f773-11d2-8aec-004005263078)]
interface nsINntpIncomingServer : nsISupports { interface nsINntpIncomingServer : nsISupports {
@ -49,6 +52,7 @@ interface nsINntpIncomingServer : nsISupports {
attribute boolean newsrcHasChanged; attribute boolean newsrcHasChanged;
attribute long maximumConnectionsNumber;
/* used when populating the subscribe dialog */ /* used when populating the subscribe dialog */
void addNewNewsgroup(in string name, in string state, in string count); void addNewNewsgroup(in string name, in string state, in string count);
void addSubscribedNewsgroups(); void addSubscribedNewsgroups();
@ -57,4 +61,10 @@ interface nsINntpIncomingServer : nsISupports {
readonly attribute nsISupports firstGroupNeedingCounts; readonly attribute nsISupports firstGroupNeedingCounts;
void displaySubscribedGroup(in nsIMsgNewsFolder msgFolder, in long firstMessage, in long lastMessage, in long totalMessages); 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);
}; };

Просмотреть файл

@ -443,6 +443,13 @@ nsDummyBufferStream::QueryInterface(REFNSIID aIID, void** result)
return NS_ERROR_NO_INTERFACE; 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) nsNNTPProtocol::nsNNTPProtocol(nsIURI * aURL, nsIMsgWindow *aMsgWindow)
: nsMsgProtocol(aURL) : nsMsgProtocol(aURL)
{ {
@ -463,18 +470,20 @@ nsNNTPProtocol::nsNNTPProtocol(nsIURI * aURL, nsIMsgWindow *aMsgWindow)
m_commandSpecificData = nsnull; m_commandSpecificData = nsnull;
m_searchData = nsnull; m_searchData = nsnull;
if (aMsgWindow) { if (aMsgWindow)
m_msgWindow = aMsgWindow; m_msgWindow = aMsgWindow;
}
m_runningURL = null_nsCOMPtr(); m_runningURL = null_nsCOMPtr();
m_connectionBusy = PR_FALSE;
m_fromCache = PR_FALSE;
LL_I2L(m_lastActiveTimeStamp, 0);
} }
nsNNTPProtocol::~nsNNTPProtocol() nsNNTPProtocol::~nsNNTPProtocol()
{ {
if (m_nntpServer) { if (m_nntpServer) {
m_nntpServer->WriteNewsrcFile(); m_nntpServer->WriteNewsrcFile();
m_nntpServer->RemoveConnection(this);
} }
PR_FREEIF(m_currentGroup); PR_FREEIF(m_currentGroup);
if (m_lineStreamBuffer) { 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; nsresult rv = NS_OK;
net_NewsChunkSize = DEFAULT_NEWS_CHUNK_SIZE; net_NewsChunkSize = DEFAULT_NEWS_CHUNK_SIZE;
PRBool isSecure = PR_FALSE; PRBool isSecure = PR_FALSE;
if (aMsgWindow)
m_msgWindow = aMsgWindow;
nsMsgProtocol::InitFromURI(aURL);
rv = m_url->GetHost(getter_Copies(m_hostName)); rv = m_url->GetHost(getter_Copies(m_hostName));
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
rv = m_url->GetPreHost(getter_Copies(m_userName)); rv = m_url->GetPreHost(getter_Copies(m_userName));
@ -541,6 +554,7 @@ nsresult nsNNTPProtocol::Initialize(void)
// query the URL for a nsINNTPUrl // query the URL for a nsINNTPUrl
m_runningURL = do_QueryInterface(m_url); m_runningURL = do_QueryInterface(m_url);
m_connectionBusy = PR_TRUE;
if (NS_SUCCEEDED(rv) && m_runningURL) if (NS_SUCCEEDED(rv) && m_runningURL)
{ {
// okay, now fill in our event sinks...Note that each getter ref counts before // 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->GetNewsgroup(getter_AddRefs(m_newsgroup));
m_runningURL->GetOfflineNewsState(getter_AddRefs(m_offlineNewsState)); m_runningURL->GetOfflineNewsState(getter_AddRefs(m_offlineNewsState));
} }
else { else {
return rv; return rv;
} }
// call base class to set up the transport if (!m_socketIsOpen)
{
// call base class to set up the transport
if (isSecure) { if (isSecure) {
rv = OpenNetworkSocket(m_url, "ssl"); rv = OpenNetworkSocket(m_url, "ssl");
} }
else { else {
rv = OpenNetworkSocket(m_url, nsnull); rv = OpenNetworkSocket(m_url, nsnull);
} }
}
m_dataBuf = (char *) PR_Malloc(sizeof(char) * OUTPUT_BUFFER_SIZE); m_dataBuf = (char *) PR_Malloc(sizeof(char) * OUTPUT_BUFFER_SIZE);
m_dataBufSize = OUTPUT_BUFFER_SIZE; m_dataBufSize = OUTPUT_BUFFER_SIZE;
m_lineStreamBuffer = new nsMsgLineStreamBuffer(OUTPUT_BUFFER_SIZE, CRLF, PR_TRUE /* create new lines */); m_lineStreamBuffer = new nsMsgLineStreamBuffer(OUTPUT_BUFFER_SIZE, CRLF, PR_TRUE /* create new lines */);
m_nextState = SEND_FIRST_NNTP_COMMAND; m_nextState = SEND_FIRST_NNTP_COMMAND;
m_nextStateAfterResponse = NNTP_CONNECT; m_nextStateAfterResponse = NNTP_CONNECT;
m_typeWanted = 0; m_typeWanted = 0;
m_responseCode = 0; m_responseCode = 0;
m_previousResponseCode = 0; m_previousResponseCode = 0;
@ -625,6 +641,27 @@ nsNNTPProtocol::InitializeNewsFolderFromUri(const char *uri)
return NS_OK; 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) nsresult nsNNTPProtocol::LoadUrl(nsIURI * aURL, nsISupports * aConsumer)
{ {
@ -637,6 +674,14 @@ nsresult nsNNTPProtocol::LoadUrl(nsIURI * aURL, nsISupports * aConsumer)
nsCOMPtr <nsINNTPNewsgroupPost> message; nsCOMPtr <nsINNTPNewsgroupPost> message;
nsresult rv = NS_OK; 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; m_articleNumber = -1;
rv = aURL->GetHost(getter_Copies(m_hostName)); rv = aURL->GetHost(getter_Copies(m_hostName));
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
@ -645,6 +690,7 @@ nsresult nsNNTPProtocol::LoadUrl(nsIURI * aURL, nsISupports * aConsumer)
m_runningURL = do_QueryInterface(aURL, &rv); m_runningURL = do_QueryInterface(aURL, &rv);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
m_connectionBusy = PR_TRUE;
m_runningURL->GetNewsAction(&m_newsAction); m_runningURL->GetNewsAction(&m_newsAction);
// okay, now fill in our event sinks...Note that each getter ref counts before // 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... // cache so we aren't creating new connections to process each request...
// but until that time, we always want to properly shutdown the connection // 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() 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 m_nextState = NEWS_FINISHED; // so we don't spin in the free state
return NS_OK; return NS_OK;
break; #endif
case NEWS_FINISHED: case NEWS_FINISHED:
return NS_OK; return NS_OK;
break; break;
@ -4954,7 +5010,13 @@ nsresult nsNNTPProtocol::ProcessProtocolState(nsIURI * url, nsIInputStream * inp
return NS_OK; /* keep going */ 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? */ /* 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??? */ /* 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 data, there was an error or we were interrupted or
something. So, tell libmsg there was an abnormal something. So, tell libmsg there was an abnormal
exit so that it can free its data. */ 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) if (m_newsgroupList)
{ {
int status; int status;
@ -4977,10 +5047,6 @@ nsresult nsNNTPProtocol::CloseSocket()
we be releasing it here? */ we be releasing it here? */
/* NS_RELEASE(m_newsgroup->GetNewsgroupList()); */ /* 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_path);
PR_FREEIF(m_responseText); PR_FREEIF(m_responseText);
@ -4996,7 +5062,13 @@ nsresult nsNNTPProtocol::CloseSocket()
m_cancelID = nsnull; m_cancelID = nsnull;
m_runningURL = null_nsCOMPtr(); m_runningURL = null_nsCOMPtr();
m_connectionBusy = PR_FALSE;
return NS_OK;
}
nsresult nsNNTPProtocol::CloseSocket()
{
CleanupAfterRunningUrl(); // is this needed?
return nsMsgProtocol::CloseSocket(); return nsMsgProtocol::CloseSocket();
} }

Просмотреть файл

@ -14,7 +14,7 @@
* *
* The Initial Developer of the Original Code is Netscape * The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are * Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All * Copyright (C) 1998-2000 Netscape Communications Corporation. All
* Rights Reserved. * Rights Reserved.
* *
* Contributor(s): * Contributor(s):
@ -30,6 +30,7 @@
#include "nsIBufferOutputStream.h" #include "nsIBufferOutputStream.h"
#include "nsINntpUrl.h" #include "nsINntpUrl.h"
#include "nsINntpIncomingServer.h" #include "nsINntpIncomingServer.h"
#include "nsINNTPProtocol.h"
#include "nsIWebShell.h" // mscott - this dependency should only be temporary! #include "nsIWebShell.h" // mscott - this dependency should only be temporary!
@ -144,20 +145,16 @@ NEWS_FREE,
NEWS_FINISHED NEWS_FINISHED
} StatesEnum; } StatesEnum;
class nsNNTPProtocol : public nsMsgProtocol class nsNNTPProtocol : public nsINNTPProtocol, public nsMsgProtocol
{ {
public: public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSINNTPPROTOCOL
// Creating a protocol instance requires the URL // Creating a protocol instance requires the URL
// need to call Initialize after we do a new of nsNNTPProtocol // need to call Initialize after we do a new of nsNNTPProtocol
nsNNTPProtocol(nsIURI * aURL, nsIMsgWindow *aMsgWindow); nsNNTPProtocol(nsIURI * aURL, nsIMsgWindow *aMsgWindow);
virtual ~nsNNTPProtocol(); 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. // 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); 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 NS_IMETHOD Cancel(nsresult status); // handle stop button
nsresult LoadUrl(nsIURI * aURL, nsISupports * aConsumer);
private: private:
// over-rides from nsMsgProtocol // over-rides from nsMsgProtocol
virtual nsresult ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream, virtual nsresult ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream,
@ -175,7 +174,9 @@ private:
// and then calls the base class to transmit the data // and then calls the base class to transmit the data
PRInt32 SendData(nsIURI * aURL, const char * dataBuffer); PRInt32 SendData(nsIURI * aURL, const char * dataBuffer);
void ParseHeaderForCancel(char *buf); nsresult CleanupAfterRunningUrl();
void ParseHeaderForCancel(char *buf);
static PRBool CheckIfAuthor(nsISupports *aElement, void *data); static PRBool CheckIfAuthor(nsISupports *aElement, void *data);
@ -198,6 +199,9 @@ private:
// the nsINntpURL that is currently running // the nsINntpURL that is currently running
nsCOMPtr<nsINntpUrl> m_runningURL; nsCOMPtr<nsINntpUrl> m_runningURL;
PRBool m_connectionBusy;
PRBool m_fromCache; // is this connection from the cache?
PRTime m_lastActiveTimeStamp;
nsNewsAction m_newsAction; nsNewsAction m_newsAction;
// Generic state information -- What state are we in? What state do we want to go to // Generic state information -- What state are we in? What state do we want to go to

Просмотреть файл

@ -31,10 +31,11 @@
#include "nsFileStream.h" #include "nsFileStream.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsINntpService.h" #include "nsINntpService.h"
#include "nsINNTPProtocol.h"
#include "nsIRDFService.h" #include "nsIRDFService.h"
#include "nsRDFCID.h" #include "nsRDFCID.h"
#include "nsMsgNewsCID.h" #include "nsMsgNewsCID.h"
#include "nsNNTPProtocol.h"
#define NEW_NEWS_DIR_NAME "News" #define NEW_NEWS_DIR_NAME "News"
#define PREF_MAIL_NEWSRC_ROOT "mail.newsrc_root" #define PREF_MAIL_NEWSRC_ROOT "mail.newsrc_root"
@ -61,10 +62,11 @@ NS_IMPL_ISUPPORTS_INHERITED(nsNntpIncomingServer,
nsNntpIncomingServer::nsNntpIncomingServer() nsNntpIncomingServer::nsNntpIncomingServer()
{ {
NS_INIT_REFCNT(); NS_INIT_REFCNT();
mNewsrcHasChanged = PR_FALSE; mNewsrcHasChanged = PR_FALSE;
mGroupsEnumerator = nsnull; mGroupsEnumerator = nsnull;
NS_NewISupportsArray(getter_AddRefs(m_connectionCache));
} }
@ -308,9 +310,163 @@ nsNntpIncomingServer::GetNewsrcHasChanged(PRBool *aNewsrcHasChanged)
NS_IMETHODIMP NS_IMETHODIMP
nsNntpIncomingServer::CloseCachedConnections() nsNntpIncomingServer::CloseCachedConnections()
{ {
return WriteNewsrcFile(); // iterate through the connection cache for a connection that can handle this url.
PRUint32 cnt;
nsCOMPtr<nsISupports> aSupport;
nsCOMPtr<nsINNTPProtocol> 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<nsINNTPProtocol> 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<nsINNTPProtocol> connection;
nsCOMPtr<nsINNTPProtocol> 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<nsISupports> 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 NS_IMETHODIMP
nsNntpIncomingServer::AddSubscribedNewsgroups() nsNntpIncomingServer::AddSubscribedNewsgroups()
{ {

Просмотреть файл

@ -36,6 +36,9 @@
#include "nsEnumeratorUtils.h" #include "nsEnumeratorUtils.h"
class nsINntpUrl;
class nsIMsgMailNewsUrl;
/* get some implementation from nsMsgIncomingServer */ /* get some implementation from nsMsgIncomingServer */
class nsNntpIncomingServer : public nsMsgIncomingServer, class nsNntpIncomingServer : public nsMsgIncomingServer,
public nsINntpIncomingServer public nsINntpIncomingServer
@ -51,6 +54,11 @@ public:
NS_IMETHOD GetLocalStoreType(char * *type); NS_IMETHOD GetLocalStoreType(char * *type);
NS_IMETHOD CloseCachedConnections(); NS_IMETHOD CloseCachedConnections();
NS_IMETHOD PerformExpand(); NS_IMETHOD PerformExpand();
protected:
nsresult CreateProtocolInstance(nsINNTPProtocol ** aNntpConnection, nsIURI *url,
nsIMsgWindow *window);
PRBool ConnectionTimeOut(nsINNTPProtocol* aNntpConnection);
nsCOMPtr<nsISupportsArray> m_connectionCache;
NS_IMETHOD PerformBiff(); NS_IMETHOD PerformBiff();
NS_IMETHOD GetServerRequiresPasswordForBiff(PRBool *_retval); NS_IMETHOD GetServerRequiresPasswordForBiff(PRBool *_retval);

Просмотреть файл

@ -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... // almost there...now create a nntp protocol instance to run the url in...
nsNNTPProtocol *nntpProtocol = nsnull; nsNNTPProtocol *nntpProtocol = nsnull;
// ### try to access cache - but can't find server yet...
nntpProtocol = new nsNNTPProtocol(mailnewsurl, aMsgWindow); nntpProtocol = new nsNNTPProtocol(mailnewsurl, aMsgWindow);
if (!nntpProtocol) return NS_ERROR_OUT_OF_MEMORY;; if (!nntpProtocol) return NS_ERROR_OUT_OF_MEMORY;;
rv = nntpProtocol->Initialize(); rv = nntpProtocol->Initialize(mailnewsurl, aMsgWindow);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
nsCOMPtr <nsINNTPNewsgroupPost> post; nsCOMPtr <nsINNTPNewsgroupPost> post;
@ -790,7 +791,7 @@ nsresult nsNntpService::PostMessage(nsIFileSpec *fileToPost, const char *newsgro
rv = nntpUrl->SetMessageToPost(post); rv = nntpUrl->SetMessageToPost(post);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
rv = nntpProtocol->LoadUrl(mailnewsurl, /* aConsumer */ nsnull); rv = nntpProtocol->LoadNewsUrl(mailnewsurl, /* aConsumer */ nsnull);
if (_retval) if (_retval)
nntpUrl->QueryInterface(NS_GET_IID(nsIURI), (void **) _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<nsIMsgIncomingServer> server;
nsCOMPtr<nsINntpIncomingServer> 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 nsresult
nsNntpService::RunNewsUrl(nsIURI * aUri, nsIMsgWindow *aMsgWindow, nsISupports * aConsumer) nsNntpService::RunNewsUrl(nsIURI * aUri, nsIMsgWindow *aMsgWindow, nsISupports * aConsumer)
{ {
nsresult rv; nsresult rv;
// almost there...now create a nntp protocol instance to run the url in... // almost there...now create a nntp protocol instance to run the url in...
nsNNTPProtocol *nntpProtocol = nsnull; nsCOMPtr <nsINNTPProtocol> nntpProtocol;
rv = GetProtocolForUri(aUri, aMsgWindow, getter_AddRefs(nntpProtocol));
nntpProtocol = new nsNNTPProtocol(aUri, aMsgWindow); if (NS_SUCCEEDED(rv))
if (!nntpProtocol) return NS_ERROR_OUT_OF_MEMORY; rv = nntpProtocol->Initialize(aUri, aMsgWindow);
rv = nntpProtocol->Initialize();
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
rv = nntpProtocol->LoadUrl(aUri, aConsumer); rv = nntpProtocol->LoadNewsUrl(aUri, aConsumer);
return rv; return rv;
} }
@ -1061,13 +1094,13 @@ NS_IMETHODIMP nsNntpService::NewURI(const char *aSpec, nsIURI *aBaseURI, nsIURI
NS_IMETHODIMP nsNntpService::NewChannel(nsIURI *aURI, nsIChannel **_retval) NS_IMETHODIMP nsNntpService::NewChannel(nsIURI *aURI, nsIChannel **_retval)
{ {
nsresult rv = NS_OK; nsresult rv = NS_OK;
nsNNTPProtocol *nntpProtocol = new nsNNTPProtocol(aURI, nsnull); nsCOMPtr <nsINNTPProtocol> nntpProtocol;
if (!nntpProtocol) return NS_ERROR_OUT_OF_MEMORY; rv = GetProtocolForUri(aURI, nsnull, getter_AddRefs(nntpProtocol));
if (NS_SUCCEEDED(rv))
rv = nntpProtocol->Initialize(); rv = nntpProtocol->Initialize(aURI, nsnull);
if (NS_FAILED(rv)) return rv; 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 NS_IMETHODIMP

Просмотреть файл

@ -71,6 +71,7 @@ protected:
// a convience routine used to put together news urls. // a convience routine used to put together news urls.
nsresult ConstructNntpUrl(const char * urlString, const char * newsgroupName, nsMsgKey key, nsIUrlListener *aUrlListener, nsIURI ** aUrl); 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 // a convience routine to run news urls
nsresult RunNewsUrl (nsIURI * aUrl, nsIMsgWindow *aMsgWindow, nsISupports * aConsumer); nsresult RunNewsUrl (nsIURI * aUrl, nsIMsgWindow *aMsgWindow, nsISupports * aConsumer);
static PRBool findNewsServerWithGroup(nsISupports *aElement, void *data); static PRBool findNewsServerWithGroup(nsISupports *aElement, void *data);