From 6d5b5983e71f9d75cf0cb00bca8c4953875e0610 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 18 Jul 2016 00:23:31 +0200 Subject: [PATCH] Prepare thread for message fetching. --- src/main.cpp | 11 +++- src/mrimap.cpp | 134 +++++++++++++++++++++++++++++++++++-------- src/mrimap.h | 26 +++++++-- src/mrloginparam.cpp | 22 +------ src/mrloginparam.h | 8 +-- src/mrmailbox.cpp | 49 ++++++++++------ src/mrmailbox.h | 4 +- 7 files changed, 178 insertions(+), 76 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4e840c1f..5dd2c6a3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -87,6 +87,7 @@ int main(int argc, char ** argv) printf("get show configuration value\n"); printf("connect connect to mailbox server\n"); printf("disconnect disconnect from mailbox server\n"); + printf("fetch fetch messages\n"); printf("info show database information\n"); printf("exit exit program\n"); } @@ -117,12 +118,20 @@ int main(int argc, char ** argv) } else if( strcmp(cmd, "connect")==0 ) { - mailbox->Connect(); + if( !mailbox->Connect() ) { + print_error(); + } } else if( strcmp(cmd, "disconnect")==0 ) { mailbox->Disconnect(); } + else if( strcmp(cmd, "fetch")==0 ) + { + if( !mailbox->Fetch() ) { + print_error(); + } + } else if( strncmp(cmd, "set", 3)==0 ) { char* arg1 = (char*)strstr(cmd, " "); diff --git a/src/mrimap.cpp b/src/mrimap.cpp index 61a3becd..b1254a6e 100644 --- a/src/mrimap.cpp +++ b/src/mrimap.cpp @@ -23,6 +23,11 @@ * Authors: Björn Petersen * Purpose: Reading from IMAP servers, see header for details. * + ******************************************************************************* + * + * TODO: On Android, I think, the thread must be marked using + * AttachCurrentThread(), see MailCore2 code + * ******************************************************************************/ @@ -47,6 +52,7 @@ static bool is_error(int r, const char* msg) return true; } + static char * get_msg_att_msg_content(struct mailimap_msg_att * msg_att, size_t * p_msg_size) { clistiter * cur; @@ -182,6 +188,11 @@ static void fetch_messages(struct mailimap * imap) clistiter * cur; int r; + r = mailimap_select(imap, "INBOX"); + if( is_error(r, "could not select INBOX") ) { + return; + } + /* as improvement UIDVALIDITY should be read and the message cache should be cleaned if the UIDVALIDITY is not the same */ @@ -211,52 +222,127 @@ static void fetch_messages(struct mailimap * imap) mailimap_fetch_list_free(fetch_result); } +/******************************************************************************* + * The working thread + ******************************************************************************/ + + +void MrImap::WorkingThread() +{ + // connect to server + struct mailimap* imap; + + int r; + imap = mailimap_new(0, NULL); + r = mailimap_ssl_connect(imap, m_loginParam->m_mail_server, m_loginParam->m_mail_port); + if( is_error(r, "could not connect to server") ) { + goto WorkingThread_Exit; + } + + r = mailimap_login(imap, m_loginParam->m_mail_user, m_loginParam->m_mail_pw); + if( is_error(r, "could not login") ) { + goto WorkingThread_Exit; + } + + // endless look + while( 1 ) + { + // wait for condition + pthread_mutex_lock(&m_condmutex); + pthread_cond_wait(&m_cond, &m_condmutex); // wait unlocks the mutex and waits for signal, if it returns, the mutex is locked again + int dowhat = m_dowhat; + pthread_mutex_unlock(&m_condmutex); + + switch( dowhat ) + { + case DO_FETCH: + fetch_messages(imap); + break; + + case DO_EXIT: + goto WorkingThread_Exit; + } + + } + +WorkingThread_Exit: + if( imap ) { + mailimap_logout(imap); + mailimap_free(imap); + imap = NULL; + } + m_threadRunning = false; +} + + +/******************************************************************************* + * Connect/disconnect by start/stop the working thread + ******************************************************************************/ + MrImap::MrImap(MrMailbox* mailbox) { - m_mailbox = mailbox; + m_mailbox = mailbox; + m_threadRunning = false; + m_loginParam = NULL; + + pthread_mutex_init(&m_condmutex, NULL); + pthread_cond_init(&m_cond, NULL); } MrImap::~MrImap() { + Disconnect(); + + pthread_cond_destroy(&m_cond); + pthread_mutex_destroy(&m_condmutex); } bool MrImap::Connect(const MrLoginParam* param) { - struct mailimap * imap; - int r; - - if( param->m_mail_server == NULL || param->m_mail_user == NULL || param->m_mail_pw == NULL ) { - return false; + if( param==NULL || param->m_mail_server==NULL || param->m_mail_user==NULL || param->m_mail_pw==NULL ) { + return false; // error, bad parameters } - imap = mailimap_new(0, NULL); - r = mailimap_ssl_connect(imap, param->m_mail_server, param->m_mail_port); - if( is_error(r, "could not connect to server") ) { - return false; + if( m_threadRunning ) { + return true; // already trying to connect } - r = mailimap_login(imap, param->m_mail_user, param->m_mail_pw); - if( is_error(r, "could not login") ) { - return false; - } - - r = mailimap_select(imap, "INBOX"); - if( is_error(r, "could not select INBOX") ) { - return false; - } - - fetch_messages(imap); - - mailimap_logout(imap); - mailimap_free(imap); + m_loginParam = param; + m_threadRunning = true; + pthread_create(&m_thread, NULL, (void * (*)(void *)) MrImap::StartupHelper, this); + // success, so far, the real connection takes place in the working thread return true; } void MrImap::Disconnect() { + if( !m_threadRunning ) { + return; // already disconnected + } + + pthread_mutex_lock(&m_condmutex); + m_dowhat = DO_EXIT; + pthread_mutex_unlock(&m_condmutex); + pthread_cond_signal(&m_cond); +} + + +bool MrImap::Fetch() +{ + if( !m_threadRunning ) { + return false; // not connected + } + + pthread_mutex_lock(&m_condmutex); + m_dowhat = DO_FETCH; + pthread_mutex_unlock(&m_condmutex); + pthread_cond_signal(&m_cond); + + // success, so far + return true; } diff --git a/src/mrimap.h b/src/mrimap.h index bf241309..6dfc6d2b 100644 --- a/src/mrimap.h +++ b/src/mrimap.h @@ -37,13 +37,29 @@ class MrMailbox; class MrImap { public: - MrImap (MrMailbox* mailbox); - ~MrImap (); - bool Connect (const MrLoginParam*); - void Disconnect (); + MrImap (MrMailbox* mailbox); + ~MrImap (); + + bool IsConnected () { return m_threadRunning; } + bool Connect (const MrLoginParam*); + void Disconnect (); + bool Fetch (); private: - MrMailbox* m_mailbox; + MrMailbox* m_mailbox; + const MrLoginParam* m_loginParam; + + pthread_t m_thread; + bool m_threadRunning; + pthread_cond_t m_cond; + pthread_mutex_t m_condmutex; + + #define DO_FETCH 1 + #define DO_EXIT 2 + int m_dowhat; + + static void StartupHelper (MrImap* imap) { imap->WorkingThread(); } + void WorkingThread (); }; diff --git a/src/mrloginparam.cpp b/src/mrloginparam.cpp index 1399adec..e0ac9519 100644 --- a/src/mrloginparam.cpp +++ b/src/mrloginparam.cpp @@ -32,10 +32,8 @@ #include "mrloginparam.h" -MrLoginParam::MrLoginParam(MrMailbox* mailbox) +MrLoginParam::MrLoginParam() { - m_mailbox = mailbox; - // init pointers (this cannot be done by Clear() as this function checks against NULL pointers) m_email = NULL; @@ -75,24 +73,6 @@ void MrLoginParam::Clear() } -void MrLoginParam::ReadFromSql() -{ - Clear(); - - m_email = m_mailbox->GetConfig ("email", NULL); - - m_mail_server = m_mailbox->GetConfig ("mail_server", NULL); - m_mail_port = m_mailbox->GetConfigInt("mail_port", 0); - m_mail_user = m_mailbox->GetConfig ("mail_user", NULL); - m_mail_pw = m_mailbox->GetConfig ("mail_pw", NULL); - - m_send_server = m_mailbox->GetConfig ("send_server", NULL); - m_send_port = m_mailbox->GetConfigInt("send_port", 0); - m_send_user = m_mailbox->GetConfig ("send_user", NULL); - m_send_pw = m_mailbox->GetConfig ("send_pw", NULL); -} - - void MrLoginParam::Complete() { if( m_email == NULL ) { diff --git a/src/mrloginparam.h b/src/mrloginparam.h index f077ad46..ce7c635e 100644 --- a/src/mrloginparam.h +++ b/src/mrloginparam.h @@ -36,15 +36,12 @@ class MrMailbox; class MrLoginParam { public: - MrLoginParam (MrMailbox* mailbox); + MrLoginParam (); ~MrLoginParam (); // clears all data and frees its memory. All pointers are NULL after this function is called. void Clear (); - // read all data from database, unset values are still NULL after calling ReadFromSql() - void ReadFromSql (); - // tries to set missing parameters from at least m_email and m_mail_pw void Complete (); @@ -60,9 +57,6 @@ public: char* m_send_user; char* m_send_pw; uint16_t m_send_port; - -private: - MrMailbox* m_mailbox; }; diff --git a/src/mrmailbox.cpp b/src/mrmailbox.cpp index cf35fe3f..383aed83 100644 --- a/src/mrmailbox.cpp +++ b/src/mrmailbox.cpp @@ -63,18 +63,6 @@ bool MrMailbox::Open(const char* dbfile) } } - // test LibEtPan - #if 0 - struct mailimf_mailbox * mb; - char * display_name; - char * address; - - display_name = strdup("DINH =?iso-8859-1?Q?Vi=EAt_Ho=E0?="); - address = strdup("dinh.viet.hoa@free.fr"); - mb = mailimf_mailbox_new(display_name, address); // mailimf_mailbox_new() takes ownership of the given strings! - mailimf_mailbox_free(mb); - #endif - // success return true; @@ -98,15 +86,36 @@ void MrMailbox::Close() ******************************************************************************/ -void MrMailbox::Connect() +bool MrMailbox::Connect() { - MrLoginParam param(this); + if( m_imap.IsConnected() ) { + return true; + } - param.ReadFromSql(); + // read parameter, unset parameters are still NULL afterwards + { + MrSqlite3Locker locker(m_sql); - param.Complete(); + m_loginParam.Clear(); - m_imap.Connect(¶m); + m_loginParam.m_email = m_sql.GetConfig ("email", NULL); + + m_loginParam.m_mail_server = m_sql.GetConfig ("mail_server", NULL); + m_loginParam.m_mail_port = m_sql.GetConfigInt("mail_port", 0); + m_loginParam.m_mail_user = m_sql.GetConfig ("mail_user", NULL); + m_loginParam.m_mail_pw = m_sql.GetConfig ("mail_pw", NULL); + + m_loginParam.m_send_server = m_sql.GetConfig ("send_server", NULL); + m_loginParam.m_send_port = m_sql.GetConfigInt("send_port", 0); + m_loginParam.m_send_user = m_sql.GetConfig ("send_user", NULL); + m_loginParam.m_send_pw = m_sql.GetConfig ("send_pw", NULL); + } + + // try to suggest unset parameters + m_loginParam.Complete(); + + // connect + return m_imap.Connect(&m_loginParam); } @@ -116,6 +125,12 @@ void MrMailbox::Disconnect() } +bool MrMailbox::Fetch() +{ + return m_imap.Fetch(); +} + + /******************************************************************************* * Handle contacts ******************************************************************************/ diff --git a/src/mrmailbox.h b/src/mrmailbox.h index fecacb04..ccd58648 100644 --- a/src/mrmailbox.h +++ b/src/mrmailbox.h @@ -59,8 +59,9 @@ public: void Close (); // connect to the mailbox: error are be received asynchronously. - void Connect (); + bool Connect (); void Disconnect (); + bool Fetch (); // iterate contacts size_t GetContactCnt () { MrSqlite3Locker l(m_sql); return m_sql.GetContactCnt(); } @@ -82,6 +83,7 @@ public: private: // private stuff MrSqlite3 m_sql; + MrLoginParam m_loginParam; MrImap m_imap; friend class MrImap; };