as discussed during camp and otherwise ... add dc_perform_{mvbox,sentbox}_jobs hooks which, however, for now have an empty implementation. They can already be called from UIs, though. Next step is refactoring imap-job handling to only execute jobs belonging to the respective imap folder.

This commit is contained in:
holger krekel
2019-09-19 22:40:06 +02:00
parent 70234e5b19
commit 91b98e8c6d
6 changed files with 127 additions and 20 deletions

View File

@@ -610,12 +610,8 @@ void dc_interrupt_imap_idle (dc_context_t* context);
/** /**
* Fetch new messages from the MVBOX, if any. * Execute pending mvbox-jobs.
* The MVBOX is a folder on the account where chat messages are moved to. * This function and dc_perform_mvbox_fetch() and dc_perform_mvbox_idle()
* The moving is done to not disturb shared accounts that are used by both,
* Delta Chat and a classical MUA.
*
* This function and dc_perform_mvbox_idle()
* must be called from the same thread, typically in a loop. * must be called from the same thread, typically in a loop.
* *
* Example: * Example:
@@ -623,6 +619,7 @@ void dc_interrupt_imap_idle (dc_context_t* context);
* void* mvbox_thread_func(void* context) * void* mvbox_thread_func(void* context)
* { * {
* while (true) { * while (true) {
* dc_perform_mvbox_jobs(context);
* dc_perform_mvbox_fetch(context); * dc_perform_mvbox_fetch(context);
* dc_perform_mvbox_idle(context); * dc_perform_mvbox_idle(context);
* } * }
@@ -636,13 +633,26 @@ void dc_interrupt_imap_idle (dc_context_t* context);
* *
* // network becomes available again - * // network becomes available again -
* // the interrupt causes dc_perform_mvbox_idle() in the thread above * // the interrupt causes dc_perform_mvbox_idle() in the thread above
* // to return so that and messages are fetched. * // to return so that jobs are executed and messages are fetched.
* dc_maybe_network(context); * dc_maybe_network(context);
* *
* @memberof dc_context_t * @memberof dc_context_t
* @param context The context as created by dc_context_new(). * @param context The context as created by dc_context_new().
* @return None. * @return None.
*/ */
void dc_perform_mvbox_jobs (dc_context_t* context);
/**
* Fetch new messages from the MVBOX, if any.
* The MVBOX is a folder on the account where chat messages are moved to.
* The moving is done to not disturb shared accounts that are used by both,
* Delta Chat and a classical MUA.
*
* @memberof dc_context_t
* @param context The context as created by dc_context_new().
* @return None.
*/
void dc_perform_mvbox_fetch (dc_context_t* context); void dc_perform_mvbox_fetch (dc_context_t* context);
@@ -679,6 +689,39 @@ void dc_perform_mvbox_idle (dc_context_t* context);
*/ */
void dc_interrupt_mvbox_idle (dc_context_t* context); void dc_interrupt_mvbox_idle (dc_context_t* context);
/**
* Execute pending sentbox-jobs.
* This function and dc_perform_sentbox_fetch() and dc_perform_sentbox_idle()
* must be called from the same thread, typically in a loop.
*
* Example:
*
* void* sentbox_thread_func(void* context)
* {
* while (true) {
* dc_perform_sentbox_jobs(context);
* dc_perform_sentbox_fetch(context);
* dc_perform_sentbox_idle(context);
* }
* }
*
* // start sentbox-thread that runs forever
* pthread_t sentbox_thread;
* pthread_create(&sentbox_thread, NULL, sentbox_thread_func, context);
*
* ... program runs ...
*
* // network becomes available again -
* // the interrupt causes dc_perform_sentbox_idle() in the thread above
* // to return so that jobs are executed and messages are fetched.
* dc_maybe_network(context);
*
* @memberof dc_context_t
* @param context The context as created by dc_context_new().
* @return None.
*/
void dc_perform_sentbox_jobs (dc_context_t* context);
/** /**
* Fetch new messages from the Sent folder, if any. * Fetch new messages from the Sent folder, if any.

View File

@@ -471,6 +471,18 @@ pub unsafe extern "C" fn dc_perform_mvbox_fetch(context: *mut dc_context_t) {
.unwrap_or(()) .unwrap_or(())
} }
#[no_mangle]
pub unsafe extern "C" fn dc_perform_mvbox_jobs(context: *mut dc_context_t) {
if context.is_null() {
eprintln!("ignoring careless call to dc_perform_mvbox_jobs()");
return;
}
let ffi_context = &*context;
ffi_context
.with_inner(|ctx| job::perform_mvbox_jobs(ctx))
.unwrap_or(())
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn dc_perform_mvbox_idle(context: *mut dc_context_t) { pub unsafe extern "C" fn dc_perform_mvbox_idle(context: *mut dc_context_t) {
if context.is_null() { if context.is_null() {
@@ -507,6 +519,18 @@ pub unsafe extern "C" fn dc_perform_sentbox_fetch(context: *mut dc_context_t) {
.unwrap_or(()) .unwrap_or(())
} }
#[no_mangle]
pub unsafe extern "C" fn dc_perform_sentbox_jobs(context: *mut dc_context_t) {
if context.is_null() {
eprintln!("ignoring careless call to dc_perform_sentbox_jobs()");
return;
}
let ffi_context = &*context;
ffi_context
.with_inner(|ctx| job::perform_sentbox_jobs(ctx))
.unwrap_or(())
}
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn dc_perform_sentbox_idle(context: *mut dc_context_t) { pub unsafe extern "C" fn dc_perform_sentbox_idle(context: *mut dc_context_t) {
if context.is_null() { if context.is_null() {

View File

@@ -387,7 +387,7 @@ class Account(object):
ev = self._evlogger.get_matching("DC_EVENT_INCOMING_MSG") ev = self._evlogger.get_matching("DC_EVENT_INCOMING_MSG")
return self.get_message_by_id(ev[2]) return self.get_message_by_id(ev[2])
def start_threads(self): def start_threads(self, mvbox=False, sentbox=False):
""" start IMAP/SMTP threads (and configure account if it hasn't happened). """ start IMAP/SMTP threads (and configure account if it hasn't happened).
:raises: ValueError if 'addr' or 'mail_pw' are not configured. :raises: ValueError if 'addr' or 'mail_pw' are not configured.
@@ -395,7 +395,7 @@ class Account(object):
""" """
if not self.is_configured(): if not self.is_configured():
self.configure() self.configure()
self._threads.start() self._threads.start(mvbox=mvbox, sentbox=sentbox)
def stop_threads(self, wait=True): def stop_threads(self, wait=True):
""" stop IMAP/SMTP threads. """ """ stop IMAP/SMTP threads. """
@@ -436,10 +436,14 @@ class IOThreads:
def is_started(self): def is_started(self):
return len(self._name2thread) > 0 return len(self._name2thread) > 0
def start(self, imap=True, smtp=True): def start(self, imap=True, smtp=True, mvbox=False, sentbox=False):
assert not self.is_started() assert not self.is_started()
if imap: if imap:
self._start_one_thread("imap", self.imap_thread_run) self._start_one_thread("inbox", self.imap_thread_run)
if mvbox:
self._start_one_thread("mvbox", self.mvbox_thread_run)
if sentbox:
self._start_one_thread("sentbox", self.sentbox_thread_run)
if smtp: if smtp:
self._start_one_thread("smtp", self.smtp_thread_run) self._start_one_thread("smtp", self.smtp_thread_run)
@@ -452,17 +456,35 @@ class IOThreads:
self._thread_quitflag = True self._thread_quitflag = True
lib.dc_interrupt_imap_idle(self._dc_context) lib.dc_interrupt_imap_idle(self._dc_context)
lib.dc_interrupt_smtp_idle(self._dc_context) lib.dc_interrupt_smtp_idle(self._dc_context)
lib.dc_interrupt_mvbox_idle(self._dc_context)
lib.dc_interrupt_sentbox_idle(self._dc_context)
if wait: if wait:
for name, thread in self._name2thread.items(): for name, thread in self._name2thread.items():
thread.join() thread.join()
def imap_thread_run(self): def imap_thread_run(self):
self._log_event("py-bindings-info", 0, "IMAP THREAD START") self._log_event("py-bindings-info", 0, "INBOX THREAD START")
while not self._thread_quitflag: while not self._thread_quitflag:
lib.dc_perform_imap_jobs(self._dc_context) lib.dc_perform_imap_jobs(self._dc_context)
lib.dc_perform_imap_fetch(self._dc_context) lib.dc_perform_imap_fetch(self._dc_context)
lib.dc_perform_imap_idle(self._dc_context) lib.dc_perform_imap_idle(self._dc_context)
self._log_event("py-bindings-info", 0, "IMAP THREAD FINISHED") self._log_event("py-bindings-info", 0, "INBOX THREAD FINISHED")
def mvbox_thread_run(self):
self._log_event("py-bindings-info", 0, "MVBOX THREAD START")
while not self._thread_quitflag:
lib.dc_perform_mvbox_jobs(self._dc_context)
lib.dc_perform_mvbox_fetch(self._dc_context)
lib.dc_perform_mvbox_idle(self._dc_context)
self._log_event("py-bindings-info", 0, "MVBOX THREAD FINISHED")
def sentbox_thread_run(self):
self._log_event("py-bindings-info", 0, "SENTBOX THREAD START")
while not self._thread_quitflag:
lib.dc_perform_sentbox_jobs(self._dc_context)
lib.dc_perform_sentbox_fetch(self._dc_context)
lib.dc_perform_sentbox_idle(self._dc_context)
self._log_event("py-bindings-info", 0, "SENTBOX THREAD FINISHED")
def smtp_thread_run(self): def smtp_thread_run(self):
self._log_event("py-bindings-info", 0, "SMTP THREAD START") self._log_event("py-bindings-info", 0, "SMTP THREAD START")

View File

@@ -163,10 +163,10 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
ac._evlogger.set_timeout(30) ac._evlogger.set_timeout(30)
return ac, dict(configdict) return ac, dict(configdict)
def get_online_configuring_account(self): def get_online_configuring_account(self, mvbox=False, sentbox=False):
ac, configdict = self.get_online_config() ac, configdict = self.get_online_config()
ac.configure(**configdict) ac.configure(**configdict)
ac.start_threads() ac.start_threads(mvbox=mvbox, sentbox=sentbox)
return ac return ac
def get_two_online_accounts(self): def get_two_online_accounts(self):

View File

@@ -106,7 +106,7 @@ class TestOfflineChat:
def chat1(self, ac1): def chat1(self, ac1):
contact1 = ac1.create_contact("some1@hello.com", name="some1") contact1 = ac1.create_contact("some1@hello.com", name="some1")
chat = ac1.create_chat_by_contact(contact1) chat = ac1.create_chat_by_contact(contact1)
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL, chat.id assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL, chat.id
return chat return chat
def test_display(self, chat1): def test_display(self, chat1):
@@ -337,14 +337,14 @@ class TestOnlineAccount:
def get_chat(self, ac1, ac2): def get_chat(self, ac1, ac2):
c2 = ac1.create_contact(email=ac2.get_config("addr")) c2 = ac1.create_contact(email=ac2.get_config("addr"))
chat = ac1.create_chat_by_contact(c2) chat = ac1.create_chat_by_contact(c2)
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL
return chat return chat
def test_one_account_send(self, acfactory): def test_one_account_send(self, acfactory):
ac1 = acfactory.get_online_configuring_account() ac1 = acfactory.get_online_configuring_account()
c2 = ac1.create_contact(email=ac1.get_config("addr")) c2 = ac1.create_contact(email=ac1.get_config("addr"))
chat = ac1.create_chat_by_contact(c2) chat = ac1.create_chat_by_contact(c2)
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL assert chat.id > const.DC_CHAT_ID_LAST_SPECIAL
wait_successful_IMAP_SMTP_connection(ac1) wait_successful_IMAP_SMTP_connection(ac1)
wait_configuration_progress(ac1, 1000) wait_configuration_progress(ac1, 1000)
@@ -365,6 +365,16 @@ class TestOnlineAccount:
msg_in = ac2.get_message_by_id(msg_out.id) msg_in = ac2.get_message_by_id(msg_out.id)
assert msg_in.text == "message1" assert msg_in.text == "message1"
def test_mvbox_sentbox_threads(self, acfactory):
ac1 = acfactory.get_online_configuring_account(mvbox=True, sentbox=True)
ac2 = acfactory.get_online_configuring_account()
wait_configuration_progress(ac2, 1000)
wait_configuration_progress(ac1, 1000)
chat = self.get_chat(ac1, ac2)
chat.send_text("message1")
ev = ac2._evlogger.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED")
assert ev[2] > const.DC_CHAT_ID_LAST_SPECIAL
def test_forward_messages(self, acfactory): def test_forward_messages(self, acfactory):
ac1, ac2 = acfactory.get_two_online_accounts() ac1, ac2 = acfactory.get_two_online_accounts()
chat = self.get_chat(ac1, ac2) chat = self.get_chat(ac1, ac2)
@@ -430,8 +440,8 @@ class TestOnlineAccount:
ac2.mark_seen_messages([msg_in]) ac2.mark_seen_messages([msg_in])
lp.step("1") lp.step("1")
ev = ac1._evlogger.get_matching("DC_EVENT_MSG_READ") ev = ac1._evlogger.get_matching("DC_EVENT_MSG_READ")
assert ev[1] >= const.DC_CHAT_ID_LAST_SPECIAL assert ev[1] > const.DC_CHAT_ID_LAST_SPECIAL
assert ev[2] >= const.DC_MSG_ID_LAST_SPECIAL assert ev[2] > const.DC_MSG_ID_LAST_SPECIAL
lp.step("2") lp.step("2")
assert msg_out.is_out_mdn_received() assert msg_out.is_out_mdn_received()

View File

@@ -761,6 +761,14 @@ pub fn perform_imap_jobs(context: &Context) {
info!(context, "dc_perform_imap_jobs ended.",); info!(context, "dc_perform_imap_jobs ended.",);
} }
pub fn perform_mvbox_jobs(context: &Context) {
info!(context, "dc_perform_mbox_jobs EMPTY (for now).",);
}
pub fn perform_sentbox_jobs(context: &Context) {
info!(context, "dc_perform_sentbox_jobs EMPTY (for now).",);
}
fn job_perform(context: &Context, thread: Thread, probe_network: bool) { fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
let query = if !probe_network { let query = if !probe_network {
// processing for first-try and after backoff-timeouts: // processing for first-try and after backoff-timeouts: