Update of /cvsroot/mahogany/M/src/mail
In directory usw-pr-cvs1:/tmp/cvs-serv6537/src/mail
Modified Files:
MailFolderCC.cpp MailFolderCmn.cpp
Log Message:
implemented connection pool for IMAP folders
Index: MailFolderCC.cpp
===================================================================
RCS file: /cvsroot/mahogany/M/src/mail/MailFolderCC.cpp,v
retrieving revision 1.608
retrieving revision 1.609
diff -b -u -2 -r1.608 -r1.609
--- MailFolderCC.cpp 27 Apr 2002 10:20:55 -0000 1.608
+++ MailFolderCC.cpp 27 Apr 2002 20:58:11 -0000 1.609
@@ -135,4 +135,5 @@
extern const MOption MP_DEBUG_CCLIENT;
extern const MOption MP_FOLDERPROGRESS_THRESHOLD;
+extern const MOption MP_FOLDER_CLOSE_DELAY;
extern const MOption MP_FOLDER_FILE_DRIVER;
extern const MOption MP_FOLDER_LOGIN;
@@ -177,7 +178,10 @@
// ----------------------------------------------------------------------------
-// turn on to get messages about using the mail folder cache (ms_StreamList)
+// turn on to get messages about using the mail folder cache (gs_StreamList)
#define TRACE_MF_CACHE "mfcache"
+// turn on to get messages about caching MAILSTREAMs
+#define TRACE_CONN_CACHE "conncache"
+
// turn on to log [almost] all cclient callbacks
#define TRACE_MF_CALLBACK "cccback"
@@ -220,4 +224,7 @@
MAILSTATUS *status);
+// return the c-client "{...}" string for the given folder
+static wxString GetImapSpec(const MFolder *folder);
+
// ----------------------------------------------------------------------------
// globals
@@ -227,4 +234,7 @@
static class CCEventReflector *gs_CCEventReflector = NULL;
+/// mapping MAILSTREAM* to objects of this class and their names
+static class StreamConnectionList *gs_StreamList;
+
#ifdef USE_DIALUP
/// object used to close the streams if it can't be done when closing folder
@@ -258,4 +268,254 @@
// ============================================================================
+/// a list of MAILSTREAM pointers
+M_LIST_PTR(StreamList, MAILSTREAM);
+
+/// structure to hold MailFolder pointer and associated mailstream pointer
+class StreamConnection
+{
+public:
+ /// pointer to a MailFolderCC object
+ MailFolderCC *folder;
+
+ /// pointer to the associated MAILSTREAM
+ MAILSTREAM *stream;
+
+ /// name of the MailFolderCC object
+ String name;
+
+ /// for POP3/IMAP/NNTP: login or newsgroup
+ String login;
+
+ StreamConnection()
+ {
+ folder = NULL;
+ stream = NULL;
+ }
+
+#ifdef DEBUG
+ ~StreamConnection();
+#endif // DEBUG
+};
+
+M_LIST_PTR(StreamConnectionList, StreamConnection);
+
+/**
+ Whenever we need to establish a connection with a remote server, we try to
+ reuse an existing ServerInfoEntry for it (and create a new one if none was
+ found). This allows us to reuse the authentification information and the
+ network connections.
+
+ For the former, it's simple: we remember the name and the password after
+ connection to the server successfully and use them for any new connections.
+ This allows the users who don't want to store their logins/passwords in the
+ profile to only enter them once and they will be reused until the end of the
+ session (notice that they may explicitly choose to not store sensitive
+ information even in memory - then this isn't done).
+
+ For the latter, we do the following:
+
+ a) when opening a folder, check if we have an existing connection to its
+ server and use it instead of NULL when calling mail_open()
+
+ b) when closing the folder, don't close the connection with mail_close()
+ but give it back to the folders server entry, it will close it later (if
+ it's not reused)
+ */
+
+M_LIST(TimeList, time_t);
+
+class ServerInfoEntry
+{
+public:
+ /**
+ @name Server managing
+
+ Functions for iterating over the entire list of servers, finding the
+ servers in it and adding the new ones.
+ */
+ //@{
+
+ /**
+ Find the server entry for the specified folder and return it or NULL if
+ not found.
+ */
+ static ServerInfoEntry *Get(const MFolder *folder);
+
+ /**
+ Find the server entry for the specified folder creating one if we hadn't
+ had it yet and return it.
+
+ Unlike Get(), this method only returns NULL if folder doesn't refer to a
+ remote mailbox which is an error in the caller.
+ */
+ static ServerInfoEntry *GetOrCreate(const MFolder *folder);
+
+ /// return true if this server can be used with the given NETMBX
+ bool IsSameAs(const NETMBX& netmbx) const;
+
+ /// check for the timed out connections for all servers
+ static void CheckTimeoutAll();
+
+ /// delete all server entries
+ static void DeleteAll();
+
+ //@}
+
+
+ /**
+ @name Auth info
+
+ We keep the account information for this server so that normally we don't
+ ask the user more than once about it and thus SetAuthInfo() is supposed to
+ be called only once while GetAuthInfo() may be called many times after it.
+ */
+ //@{
+
+ /// set the login and password to use with this server
+ void SetAuthInfo(const String& login, const String& password)
+ {
+ CHECK_RET( !login.empty(), "empty login not allowed" );
+
+ ASSERT_MSG( !m_hasAuthInfo, "overriding auth info for the server?" );
+
+ m_hasAuthInfo = true;
+ m_login = login;
+ m_password = password;
+ }
+
+ /**
+ Retrieve the auth info for the server in the provided variables. If it
+ returns false the values of login and password are not modified.
+
+ @param login receives the user name
+ @param password receives the password
+ @return false if won't have auth info, true if ok
+ */
+ bool GetAuthInfo(String& login, String& password) const
+ {
+ if ( !m_hasAuthInfo )
+ return false;
+
+ login = m_login;
+ password = m_password;
+
+ return true;
+ }
+
+ //@}
+
+
+ /**
+ @name Connection pooling
+ */
+ //@{
+
+ /// return an existing connection to this server or NULL if none
+ MAILSTREAM *GetStream();
+
+ /// give us a stream to reuse later (or close if nobody wants it)
+ void KeepStream(MAILSTREAM *stream, const MFolder *folder);
+
+ /// close those of our connections which have timed out
+ void CheckTimeout();
+
+ //@}
+
+ // dtor must be public in order to use M_LIST_OWN() but nobody should delete
+ // us directly!
+ ~ServerInfoEntry();
+
+private:
+ // ctor is private, nobody except GetFolderServer() can create us
+ ServerInfoEntry(const MFolder *folder, const NETMBX& netmbx);
+
+ // this struct contains the server hostname, port, username &c
+ NETMBX m_netmbx;
+
+ // the pool of connections to this server which may be reused (may be empty,
+ // of course)
+ //
+ // this list is used as a FIFO queue, in fact
+ StreamList m_connections;
+
+ // the timeouts for each of the connections, i.e. the moment when we should
+ // close them
+ TimeList m_timeouts;
+
+ // login and password for this server if we need it and if we're allowed to
+ // store it
+ String m_login,
+ m_password;
+
+ // if true, we have valid m_login and m_password
+ //
+ // note that we need this flag because in principle empty passwords are
+ // allowed and login could be non empty because it is stored in the config
+ // file
+ bool m_hasAuthInfo;
+
+ // the lists of all servers
+ M_LIST_OWN(ServerInfoList, ServerInfoEntry);
+ static ServerInfoList ms_servers;
+
+ GCC_DTOR_WARN_OFF
+};
+
+/**
+ Close a stream: these functions either really close it or put it to the
+ server connection pool for those folders for which it makes sense, i.e. IMAP
+ and NNTP (POP connections cannot and shouldn't be reused).
+
+ Having two versions is only useful because it avoids calling
+ ServerInfoEntry::Get() again unnecessarily if the caller already has the
+ server.
+*/
+
+/// is this a reusable folder?
+static bool IsReusableFolder(const MFolder *folder)
+{
+ CHECK( folder, false, "NULL folder in IsReusableFolder" );
+
+ MFolderType folderType = folder->GetType();
+ return folderType == MF_IMAP || folderType == MF_NNTP;
+}
+
+/// close the stream associated with the given folder and server
+static void CloseOrKeepStream(MAILSTREAM *stream,
+ const MFolder *folder,
+ ServerInfoEntry *server)
+{
+ // don't cache the connections if we're going to shutdown (and hence close
+ // them all) soon anyhow
+ if ( server && IsReusableFolder(folder) && !mApplication->IsShuttingDown() )
+ {
+ server->KeepStream(stream, folder);
+ }
+ else
+ {
+ mail_close(stream);
+ }
+}
+
+/// close the stream associated with the given folder
+static void CloseOrKeepStream(MAILSTREAM *stream,
+ const MFolder *folder)
+{
+ if ( IsReusableFolder(folder) )
+ {
+ // do look for the server
+ CloseOrKeepStream(stream, folder, ServerInfoEntry::GetOrCreate(folder));
+ }
+ else // no need
+ {
+ mail_close(stream);
+ }
+}
+
+/**
+ The function called to close the connections which had timed out.
+ */
+extern void CheckConnectionsTimeout() { ServerInfoEntry::CheckTimeoutAll(); }
+
/**
The idea behind CCEventReflector is to allow postponing some actions in
@@ -370,6 +630,4 @@
dialup connection broke before we could close them.
We remember them and try to close them at program exit. */
-KBLIST_DEFINE(StreamList, MAILSTREAM);
-
class CCStreamCleaner
{
@@ -941,33 +1199,4 @@
// ----------------------------------------------------------------------------
-// AuthInfoList: stores the login/password pairs for the folders which don't
-// store this info in the config - this allows to ask the user
-// only once for them during the same session
-// ----------------------------------------------------------------------------
-
-struct AuthInfoEntry
-{
- AuthInfoEntry(const String& folderName,
- const String& login,
- const String& password)
- : m_folderName(folderName),
- m_login(login),
- m_password(password)
- {
- }
-
- // the full folder name in the tree
- String m_folderName;
-
- // the login and password for it, both non empty
- String m_login,
- m_password;
-};
-
-M_LIST_OWN(AuthInfoList, AuthInfoEntry);
-
-static AuthInfoList gs_authInfoList;
-
-// ----------------------------------------------------------------------------
// LastNewUIDList: stores the UID of the last seen new message permanently,
// i.e. keeps it even after the folder was closed
@@ -1737,7 +1966,8 @@
if ( HasLogin() )
{
- gs_authInfoList.push_front(new AuthInfoEntry(m_mfolder->GetFullName(),
- m_login,
- m_password));
+ ServerInfoEntry *server = ServerInfoEntry::GetOrCreate(m_mfolder);
+ CHECK_RET( server, "folder which has login must have server as well!" );
+
+ server->SetAuthInfo(m_login, m_password);
}
}
@@ -1760,22 +1990,10 @@
if ( login.empty() || password.empty() )
{
- String folderName = mfolder->GetFullName();
- if ( !folderName.empty() )
+ // do we already have login/password for this folder?
+ ServerInfoEntry *server = ServerInfoEntry::Get(mfolder);
+ if ( server && server->GetAuthInfo(login, password) )
{
- // try to find login/password in the list of the previously entered
- // ones
- for ( AuthInfoList::iterator i = gs_authInfoList.begin();
- i != gs_authInfoList.end();
- i++ )
- {
- if ( i->m_folderName == folderName )
- {
- login = i->m_login;
- password = i->m_password;
-
return true;
}
- }
- }
// we don't have password for this folder, ask the user about it
@@ -1886,6 +2104,6 @@
else // successfully opened
{
- // either keep the stream for the caller or close it if we don't need it
- // any more
+ // either keep the stream for the caller or close it if we don't need
+ // it any more
if ( pStream )
*pStream = stream;
@@ -2267,5 +2485,9 @@
if ( !m_MailStream && tryOpen )
{
- m_MailStream = mail_open(NIL, (char *)m_ImapSpec.c_str(), ccOptions);
+ // try to reuse an existing stream if possible
+ ServerInfoEntry *server = ServerInfoEntry::Get(m_mfolder);
+
+ m_MailStream = mail_open(server ? server->GetStream() : NIL,
+ (char *)m_ImapSpec.c_str(), ccOptions);
}
} // end of cclient lock block
@@ -2294,5 +2516,5 @@
MAILSTREAM *msHalfOpened = mail_open
(
- NIL,
+ m_MailStream,
(char *)m_ImapSpec.c_str(),
(mm_show_debug ? OP_DEBUG : 0) | OP_HALFOPEN
@@ -2318,5 +2540,4 @@
//else: it can't be opened at all
- mail_close(m_MailStream);
m_MailStream = NIL;
}
@@ -2455,5 +2676,6 @@
#endif // 0
- mail_close(m_MailStream);
+ // don't close the stream immediately, reuse it later
+ CloseOrKeepStream(m_MailStream, m_mfolder);
}
@@ -2553,16 +2775,15 @@
CHECK_STREAM_LIST();
- size_t count = ms_StreamList.size();
+ size_t count = gs_StreamList->size();
MailFolder **mfOpened = new MailFolder *[count + 1];
size_t n = 0;
- for ( StreamConnectionList::iterator i = ms_StreamList.begin();
- i != ms_StreamList.end();
+ for ( StreamConnectionList::iterator i = gs_StreamList->begin();
+ i != gs_StreamList->end();
i++ )
{
- StreamConnection *conn = *i;
- if ( conn->stream && !conn->stream->halfopen )
+ if ( i->stream && !i->stream->halfopen )
{
- mfOpened[n++] = conn->folder;
+ mfOpened[n++] = i->folder;
}
}
@@ -2631,6 +2852,4 @@
// ----------------------------------------------------------------------------
-StreamConnectionList MailFolderCC::ms_StreamList(FALSE);
-
bool MailFolderCC::ms_CClientInitialisedFlag = false;
@@ -2651,12 +2870,9 @@
// check that the folder is not already in the list
StreamConnectionList::iterator i;
- for ( i = ms_StreamList.begin(); i != ms_StreamList.end(); i++ )
+ for ( i = gs_StreamList->begin(); i != gs_StreamList->end(); i++ )
{
- StreamConnection *conn = *i;
- if ( conn->folder == this )
+ if ( i->folder == this )
{
FAIL_MSG("adding a folder to the stream list twice");
-
- return;
}
}
@@ -2666,8 +2882,8 @@
StreamConnection *conn = new StreamConnection;
conn->folder = (MailFolderCC *) this;
- conn->stream = stream;
+ conn->stream = (MAILSTREAM *)stream;
conn->name = m_ImapSpec;
conn->login = login;
- ms_StreamList.push_front(conn);
+ gs_StreamList->push_front(conn);
CHECK_STREAM_LIST();
@@ -2684,10 +2900,10 @@
bool canExit = true;
StreamConnectionList::iterator i;
- for(i = ms_StreamList.begin(); i != ms_StreamList.end(); i++)
+ for(i = gs_StreamList->begin(); i != gs_StreamList->end(); i++)
{
- if( (*i)->folder->InCritical() )
+ if( i->folder->InCritical() )
{
canExit = false;
- *which << (*i)->folder->GetName() << '\n';
+ *which << i->folder->GetName() << '\n';
}
}
@@ -2702,10 +2918,10 @@
CHECK_STREAM_LIST();
- StreamConnectionList::iterator i;
- for(i = ms_StreamList.begin(); i != ms_StreamList.end(); i++)
+ for ( StreamConnectionList::iterator i = gs_StreamList->begin();
+ i != gs_StreamList->end();
+ i++ )
{
- StreamConnection *conn = *i;
- if ( conn->stream == stream )
- return conn->folder;
+ if ( i->stream == stream )
+ return i->folder;
}
@@ -2724,10 +2940,10 @@
if ( name )
{
- StreamConnectionList::iterator i;
- for(i = ms_StreamList.begin(); i != ms_StreamList.end(); i++)
+ for ( StreamConnectionList::iterator i = gs_StreamList->begin();
+ i != gs_StreamList->end();
+ i++ )
{
- StreamConnection *conn = *i;
- if( conn->name == name )
- return conn->folder;
+ if ( i->name == name )
+ return i->folder;
}
}
@@ -2778,17 +2994,17 @@
CHECK_STREAM_LIST();
- StreamConnectionList::iterator i;
wxLogTrace(TRACE_MF_CACHE, "Looking for folder to re-use: '%s',login '%s'",
path.c_str(), login.c_str());
- for(i = ms_StreamList.begin(); i != ms_StreamList.end(); i++)
+ for ( StreamConnectionList::iterator i = gs_StreamList->begin();
+ i != gs_StreamList->end();
+ i++ )
{
- StreamConnection *conn = *i;
- if( conn->name == path && conn->login == login)
+ if( i->name == path && i->login == login)
{
wxLogTrace(TRACE_MF_CACHE, " Re-using entry: '%s',login '%s'",
- conn->name.c_str(), conn->login.c_str());
+ i->name.c_str(), i->login.c_str());
- MailFolderCC *mf = conn->folder;
+ MailFolderCC *mf = i->folder;
mf->IncRef();
@@ -2810,12 +3026,14 @@
CHECK_STREAM_LIST();
- StreamConnectionList::iterator i;
- for(i = ms_StreamList.begin(); i != ms_StreamList.end(); i++)
- {
- if( (*i)->folder == this )
+ for ( StreamConnectionList::iterator i = gs_StreamList->begin();
+ i != gs_StreamList->end();
+ ++i )
{
StreamConnection *conn = *i;
+
+ if ( conn->folder == this )
+ {
delete conn;
- ms_StreamList.erase(i);
+ gs_StreamList->erase(i);
break;
@@ -2825,5 +3043,5 @@
CHECK_STREAM_LIST();
- if( ms_StreamListDefaultObj == this )
+ if ( ms_StreamListDefaultObj == this )
{
// no more
@@ -4098,19 +4316,10 @@
wxLogDebug("--list of streams and objects--");
- StreamConnection *conn;
- StreamConnectionList::iterator i;
-
- for(i = ms_StreamList.begin(); i != ms_StreamList.end(); i++)
- {
- conn = *i;
-
- if ( !conn )
+ for ( StreamConnectionList::iterator i = gs_StreamList->begin();
+ i != gs_StreamList->end();
+ i++ )
{
- FAIL_MSG( "NULL stream in the list" );
- continue;
- }
-
wxLogDebug("\t%p -> %p \"%s\"",
- conn->stream, conn->folder, conn->folder->GetName().c_str());
+ i->stream, i->folder, i->folder->GetName().c_str());
}
wxLogDebug("--end of list--");
@@ -5043,4 +5252,7 @@
#endif // OS_UNIX
+ // create the map MAILSTREAM -> MailFolder
+ gs_StreamList = new StreamConnectionList;
+
ms_CClientInitialisedFlag = true;
@@ -5063,13 +5275,22 @@
delete gs_CCEventReflector;
- if(! mApplication->IsOnline())
+ bool isOnline = mApplication->IsOnline();
+
+ for ( StreamList::iterator i = m_List.begin(); i != m_List.end(); ++i )
{
- // brutally free all memory without closing stream:
- MAILSTREAM *stream;
- StreamList::iterator i;
- for(i = m_List.begin(); i != m_List.end(); i++)
+ MAILSTREAM *stream = *i;
+
+ if ( isOnline )
{
+ // we are online, so we can close it properly:
+ DBGMESSAGE(("CCStreamCleaner: closing stream"));
+
+ mail_close(stream);
+ }
+ else // !online
+ {
+ // brutally free all memory without closing stream:
DBGMESSAGE(("CCStreamCleaner: freeing stream offline"));
- stream = *i;
+
// copied from c-client mail.c:
if (stream->mailbox) fs_give ((void **) &stream->mailbox);
@@ -5082,14 +5303,4 @@
}
}
- else
- {
- // we are online, so we can close it properly:
- StreamList::iterator i;
- for(i = m_List.begin(); i != m_List.end(); i++)
- {
- DBGMESSAGE(("CCStreamCleaner: closing stream"));
- mail_close(*i);
- }
- }
}
@@ -5109,4 +5320,6 @@
extern void MailFolderCCCleanup(void)
{
+ ServerInfoEntry::DeleteAll();
+
// as c-client lib doesn't seem to think that deallocating memory is
// something good to do, do it at it's place...
@@ -5124,14 +5337,20 @@
#endif // USE_DIALUP
- ASSERT_MSG( MailFolderCC::ms_StreamList.empty(), "some folder objects leaked" );
+ if ( gs_StreamList )
+ {
+ ASSERT_MSG( gs_StreamList->empty(), "some folder objects leaked" );
// FIXME: we really need to clean up these entries, so we just
// decrement the reference count until they go away.
- while ( !MailFolderCC::ms_StreamList.empty() )
+ while ( !gs_StreamList->empty() )
{
- MailFolderCC *folder = MailFolderCC::ms_StreamList.front()->folder;
+ MailFolderCC *folder = gs_StreamList->front()->folder;
wxLogDebug("\tFolder '%s' leaked", folder->GetName().c_str());
folder->DecRef();
}
+
+ delete gs_StreamList;
+ gs_StreamList = NULL;
+ }
}
@@ -5752,4 +5971,5 @@
unsigned long nmsgs;
CCCallbackDisabler *noCCC;
+ ServerInfoEntry *server;
MailFolderCC *mf = FindFolder(mboxpath, login);
@@ -5763,4 +5983,5 @@
noCCC = NULL;
+ server = NULL;
}
else // this folder is not opened
@@ -5776,7 +5997,11 @@
noCCC = new CCCallbackDisabler;
+ // try to reuse an existing connection, if any
+ server = ServerInfoEntry::Get(mfolder);
+ stream = server ? server->GetStream() : NIL;
+
// open the folder: although we don't need to do it to get its status, we
// have to do it anyhow below, so better do it right now
- stream = mail_open(NIL, (char *)mboxpath.c_str(),
+ stream = mail_open(stream, (char *)mboxpath.c_str(),
mm_show_debug ? OP_DEBUG : NIL);
@@ -5827,4 +6052,9 @@
//else: no messages to delete
+ if ( stream )
+ {
+ CloseOrKeepStream(stream, mfolder, server);
+ }
+
if ( mf )
mf->DecRef();
@@ -5868,4 +6098,7 @@
// ----------------------------------------------------------------------------
+// currently unused
+#if 0
+
/*
Small function to check if the mailstream has \inferiors flag set or
@@ -5880,12 +6113,12 @@
long attrib)
{
- gs_HasInferiorsFlag = ((attrib & LATT_NOINFERIORS) == 0);
+ gs_HasInferiorsFlag = !(attrib & LATT_NOINFERIORS);
}
/* static */
bool
-MailFolderCC::HasInferiors(const String &imapSpec,
- const String &login,
- const String &passwd)
+MailFolderCC::HasInferiors(const String& imapSpec,
+ const String& login,
+ const String& passwd)
{
// We lock the complete c-client code as we need to immediately
@@ -5902,12 +6135,14 @@
gs_HasInferiorsFlag = -1;
- MAILSTREAM *mailStream = mail_open(NIL, (char *)imapSpec.c_str(),
- (mm_show_debug ? OP_DEBUG : NIL) |
- OP_HALFOPEN);
+ ServerInfoEntry *server = ServerInfoEntry::Get(mfolder);
+ MAILSTREAM *stream = server ? server->GetStream() : NIL;
+
+ stream = mail_open(stream, (char *)imapSpec.c_str(),
+ (mm_show_debug ? OP_DEBUG : NIL) | OP_HALFOPEN);
- if(mailStream != NIL)
+ if ( stream != NIL )
{
MMListRedirector redirect(HasInferiorsMMList);
- mail_list (mailStream, NULL, (char *) imapSpec.c_str());
+ mail_list (stream, NULL, (char *) imapSpec.c_str());
/* This does happen for for folders where the server does not know
@@ -5916,5 +6151,6 @@
ASSERT(gs_HasInferiorsFlag != -1);
*/
- mail_close(mailStream);
+
+ CloseOrKeepStream(stream, mfolder, server);
}
@@ -5922,4 +6158,6 @@
}
+#endif // 0
+
// ----------------------------------------------------------------------------
// network operations progress
@@ -6235,3 +6473,183 @@
} // extern "C"
+
+// ============================================================================
+// ServerInfoEntry implementation
+// ============================================================================
+
+ServerInfoEntry::ServerInfoList ServerInfoEntry::ms_servers;
+
+// ----------------------------------------------------------------------------
+// creation
+// ----------------------------------------------------------------------------
+
+ServerInfoEntry::ServerInfoEntry(const MFolder *folder, const NETMBX& netmbx)
+ : m_netmbx(netmbx)
+{
+ m_login = folder->GetLogin();
+ m_password = folder->GetPassword();
+
+ m_hasAuthInfo = !m_login.empty() && !m_password.empty();
+
+ wxLogTrace(TRACE_CONN_CACHE,
+ "Created server entry for %s(%s).",
+ folder->GetFullName().c_str(), m_login.c_str());
+}
+
+ServerInfoEntry::~ServerInfoEntry()
+{
+ wxLogTrace(TRACE_CONN_CACHE,
+ "Deleting server entry for %s(%s).",
+ m_netmbx.host, m_netmbx.user);
+
+ // close all connections we may still have
+ for ( StreamList::iterator i = m_connections.begin();
+ i != m_connections.end();
+ ++i )
+ {
+ mail_close(*i);
+ }
+}
+
+bool ServerInfoEntry::IsSameAs(const NETMBX& netmbx) const
+{
+ return strcmp(m_netmbx.host, netmbx.host) == 0 &&
+ strcmp(m_netmbx.service, netmbx.service) == 0 &&
+ (!m_netmbx.port || (m_netmbx.port == netmbx.port)) &&
+ (m_netmbx.anoflag == netmbx.anoflag) &&
+ (!m_netmbx.user[0] || (strcmp(m_netmbx.user, netmbx.user) == 0));
+}
+
+/* static */
+ServerInfoEntry *ServerInfoEntry::Get(const MFolder *folder)
+{
+ String spec = GetImapSpec(folder);
+
+ NETMBX mbx;
+ if ( !mail_valid_net_parse((char *)spec.c_str(), &mbx) )
+ {
+ // invalid remote spec?
+ return NULL;
+ }
+
+ // look among the existing ones
+ for ( ServerInfoList::iterator i = ms_servers.begin();
+ i != ms_servers.end();
+ ++i )
+ {
+ if ( i->IsSameAs(mbx) )
+ return *i;
+ }
+
+ // not found
+ return NULL;
+}
+
+/* static */
+ServerInfoEntry *ServerInfoEntry::GetOrCreate(const MFolder *folder)
+{
+ NETMBX mbx;
+ if ( !mail_valid_net_parse((char *)GetImapSpec(folder).c_str(), &mbx) )
+ {
+ // invalid remote spec?
+ return NULL;
+ }
+
+ // look among the existing ones first
+ ServerInfoEntry *serverInfo = Get(folder);
+
+ if ( !serverInfo )
+ {
+ // not found: create a new entry and add it to the list
+ serverInfo = new ServerInfoEntry(folder, mbx);
+ ms_servers.push_back(serverInfo);
+ }
+
+ return serverInfo;
+}
+
+/* static */
+void ServerInfoEntry::DeleteAll()
+{
+ ms_servers.clear();
+}
+
+// ----------------------------------------------------------------------------
+// ServerInfoEntry connection caching
+// ----------------------------------------------------------------------------
+
+MAILSTREAM *ServerInfoEntry::GetStream()
+{
+ if ( m_connections.empty() )
+ return NULL;
+
+ MAILSTREAM *stream = *m_connections.begin();
+ m_connections.pop_front();
+ m_timeouts.pop_front();
+
+ wxLogTrace(TRACE_CONN_CACHE,
+ "Reusing connection to %s.", stream->mailbox);
+
+ return stream;
+}
+
+void ServerInfoEntry::KeepStream(MAILSTREAM *stream, const MFolder *folder)
+{
+ m_connections.push_back(stream);
+
+ Profile_obj profile(folder->GetProfile());
+ time_t t = time(NULL);
+ time_t delay = READ_CONFIG(profile, MP_FOLDER_CLOSE_DELAY);
+
+ wxLogTrace(TRACE_CONN_CACHE,
+ "Keeping connection to %s alive for %d seconds.",
+ stream->mailbox, delay);
+
+ m_timeouts.push_back(t + delay);
+}
+
+void ServerInfoEntry::CheckTimeout()
+{
+ time_t t = time(NULL);
+
+ // iterate in parallel over both lists
+ StreamList::iterator i = m_connections.begin();
+ TimeList::iterator j = m_timeouts.begin();
+ while ( i != m_connections.end() )
+ {
+ if ( *j < t )
+ {
+ // timed out
+ MAILSTREAM *stream = *i;
+
+ wxLogTrace(TRACE_CONN_CACHE,
+ "Connection to %s timed out, closing.", stream->mailbox);
+
+ mail_close(stream);
+
+ i = m_connections.erase(i);
+ j = m_timeouts.erase(j);
+ }
+ else
+ {
+ ++i;
+ ++j;
+ }
+ }
+}
+
+/* static */
+void ServerInfoEntry::CheckTimeoutAll()
+{
+ for ( ServerInfoList::iterator i = ms_servers.begin();
+ i != ms_servers.end();
+ ++i )
+ {
+ // micro optimization
+ if ( !i->m_connections.empty() )
+ {
+ i->CheckTimeout();
+ }
+ }
+}
Index: MailFolderCmn.cpp
===================================================================
RCS file: /cvsroot/mahogany/M/src/mail/MailFolderCmn.cpp,v
retrieving revision 1.86
retrieving revision 1.87
diff -b -u -2 -r1.86 -r1.87
--- MailFolderCmn.cpp 19 Mar 2002 01:43:45 -0000 1.86
+++ MailFolderCmn.cpp 27 Apr 2002 20:58:11 -0000 1.87
@@ -386,6 +386,5 @@
void MfCloser::OnTimer(void)
{
- MfList::iterator i;
- for( i = m_MfList.begin(); i != m_MfList.end();)
+ for ( MfList::iterator i = m_MfList.begin(); i != m_MfList.end();)
{
if ( i->HasExpired() )
@@ -403,4 +402,8 @@
}
}
+
+ // FIXME: this is just a temp hack
+ extern void CheckConnectionsTimeout();
+ CheckConnectionsTimeout();
}
@@ -481,4 +484,7 @@
MailFolderCmn::DecRef()
{
+ // FIXME: revise this code taking into account connection caching we now do
+ // in MailFolderCC, it can't work without changes probably
+#if 0
// don't keep folders alive artificially if we're going to terminate soon
// anyhow - or if we didn't start up fully yet and gs_MailFolderCloser
@@ -522,4 +528,5 @@
}
}
+#endif // 0
return RealDecRef();
_______________________________________________
Mahogany-cvsupdates mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/mahogany-cvsupdates