diff --git a/src/mrmailbox.h b/src/mrmailbox.h index 77e2a43a..43e2bfa8 100644 --- a/src/mrmailbox.h +++ b/src/mrmailbox.h @@ -241,7 +241,7 @@ int32_t mrmailbox_get_config_int (mrmailbox_t*, const char* key, int3 char* mrmailbox_get_version_str (void); int mrmailbox_configure_and_connect(mrmailbox_t*); -void mrmailbox_configure_cancel (mrmailbox_t*); +void mrmailbox_stop_ongoing_process(mrmailbox_t*); int mrmailbox_is_configured (mrmailbox_t*); void mrmailbox_connect (mrmailbox_t*); @@ -326,7 +326,6 @@ mrcontact_t* mrmailbox_get_contact (mrmailbox_t*, uint32_t contact_id); #define MR_BAK_PREFIX "delta-chat" #define MR_BAK_SUFFIX "bak" int mrmailbox_imex (mrmailbox_t*, int what, const char* param1, const char* param2); -void mrmailbox_imex_cancel (mrmailbox_t*); char* mrmailbox_imex_has_backup (mrmailbox_t*, const char* dir); int mrmailbox_check_password (mrmailbox_t*, const char* pw); char* mrmailbox_initiate_key_transfer(mrmailbox_t*); @@ -352,6 +351,8 @@ int mrmailbox_get_thread_index (void); int mrchat_set_draft (mrchat_t*, const char* msg); /* deprecated - use mrmailbox_set_draft() instead */ #define mrpoortext_t mrlot_t #define mrpoortext_unref mrlot_unref +#define mrmailbox_imex_cancel mrmailbox_stop_ongoing_process +#define mrmailbox_configure_cancel mrmailbox_stop_ongoing_process /* library-internal */ @@ -418,6 +419,11 @@ int mrmailbox_ensure_secret_key_exists (mrmailbox_t*); /* makes sure char* mrmailbox_create_setup_code (mrmailbox_t*); int mrmailbox_render_setup_file (mrmailbox_t* mailbox, const char* passphrase, char** ret_msg); +extern int mr_shall_stop_ongoing; +int mrmailbox_alloc_ongoing (mrmailbox_t*); +void mrmailbox_free_ongoing (mrmailbox_t*); + + #ifdef __cplusplus } /* /extern "C" */ #endif diff --git a/src/mrmailbox_configure.c b/src/mrmailbox_configure.c index 668f34a1..f5abb725 100644 --- a/src/mrmailbox_configure.c +++ b/src/mrmailbox_configure.c @@ -358,10 +358,6 @@ cleanup: ******************************************************************************/ -static int s_configure_running = 0; -static int s_configure_do_exit = 1; /* the value 1 avoids mrmailbox_configure_cancel() from stopping already stopped threads */ - - /** * Configure and connect a mailbox. * @@ -369,7 +365,7 @@ static int s_configure_do_exit = 1; /* the value 1 avoids mrmailbox_config * using mrmailbox_set_config(). * * - mrmailbox_configure_and_connect() may take a while, so it might be a good idea to let it run in a non-GUI-thread; - * to cancel the configuration progress, you can then use mrmailbox_configure_cancel(). + * to stop the configuration progress, you can use mrmailbox_stop_ongoing_process(). * * - The function sends out a number of #MR_EVENT_CONFIGURE_PROGRESS events that may be used to create * a progress bar or stuff like that. @@ -399,33 +395,28 @@ int mrmailbox_configure_and_connect(mrmailbox_t* mailbox) int success = 0, locked = 0, i; int imap_connected_here = 0; - mrloginparam_t* param = mrloginparam_new(); + mrloginparam_t* param = NULL; char* param_domain = NULL; /* just a pointer inside param, must not be freed! */ char* param_addr_urlencoded = NULL; mrloginparam_t* param_autoconfig = NULL; - #define PROGRESS(p) \ - if( s_configure_do_exit ) { goto cleanup; } \ - mailbox->m_cb(mailbox, MR_EVENT_CONFIGURE_PROGRESS, (p), 0); - if( mailbox == NULL ) { - goto cleanup; + return 0; } + if( !mrmailbox_alloc_ongoing(mailbox) ) { + return 0; /* no cleanup as this would call mrmailbox_free_ongoing() */ + } + + #define PROGRESS(p) \ + if( mr_shall_stop_ongoing ) { goto cleanup; } \ + mailbox->m_cb(mailbox, MR_EVENT_CONFIGURE_PROGRESS, (p), 0); + if( !mrsqlite3_is_open(mailbox->m_sql) ) { mrmailbox_log_error(mailbox, 0, "Cannot configure, database not opened."); - s_configure_do_exit = 1; goto cleanup; } - if( s_configure_running || s_configure_do_exit == 0 ) { - mrmailbox_log_error(mailbox, 0, "Already configuring."); - goto cleanup; - } - - s_configure_running = 1; - s_configure_do_exit = 0; - /* disconnect */ mrmailbox_disconnect(mailbox); @@ -454,6 +445,8 @@ int mrmailbox_configure_and_connect(mrmailbox_t* mailbox) /* 1. Load the parameters and check email-address and password **************************************************************************/ + param = mrloginparam_new(); + mrsqlite3_lock(mailbox->m_sql); locked = 1; @@ -691,50 +684,11 @@ cleanup: mrloginparam_unref(param_autoconfig); free(param_addr_urlencoded); - s_configure_do_exit = 1; /* avoids mrmailbox_configure_cancel() to stop the thread */ - s_configure_running = 0; + mrmailbox_free_ongoing(mailbox); return success; } -/** - * Signal the configure-process to stop. - * - * After that, mrmailbox_configure_cancel() returns _without_ waiting - * for mrmailbox_configure_and_connect() to return. - * - * mrmailbox_configure_and_connect() will return ASAP then, however, it may - * still take a moment. If in doubt, the caller may also decide the kill the - * thread after a few seconds; eg. the configuration process may hang in a - * function not under the control of the core (eg. #MR_EVENT_HTTP_GET). Another - * reason for mrmailbox_configure_cancel() not to wait is that otherwise it - * would be GUI-blocking and should be started in another thread then; this - * would make things even more complicated. - * - * @memberof mrmailbox_t - * - * @param mailbox The mailbox object as created by mrmailbox_new() - * - * @return None - */ -void mrmailbox_configure_cancel(mrmailbox_t* mailbox) -{ - if( mailbox == NULL ) { - return; - } - - if( s_configure_running && s_configure_do_exit==0 ) - { - mrmailbox_log_info(mailbox, 0, "Signaling the configure-process to stop ASAP."); - s_configure_do_exit = 1; - } - else - { - mrmailbox_log_info(mailbox, 0, "No configure-process to stop."); - } -} - - /** * Check if the mailbox is already configured. * @@ -769,3 +723,78 @@ int mrmailbox_is_configured(mrmailbox_t* mailbox) return is_configured? 1 : 0; } + +/* + * Request an ongoing process to start. + * Returns 0=process started, 1=not started, there is running another process + */ +static int s_ongoing_running = 0; +int mr_shall_stop_ongoing = 1; /* the value 1 avoids mrmailbox_stop_ongoing_process() from stopping already stopped threads */ +int mrmailbox_alloc_ongoing(mrmailbox_t* mailbox) +{ + if( mailbox == NULL ) { + return 0; + } + + if( s_ongoing_running || mr_shall_stop_ongoing == 0 ) { + mrmailbox_log_warning(mailbox, 0, "There is already another ongoing process running."); + return 0; + } + + s_ongoing_running = 1; + mr_shall_stop_ongoing = 0; + return 1; +} + + +/* + * Frees the process allocated with mrmailbox_alloc_ongoing() - independingly of mr_shall_stop_ongoing. + * If mrmailbox_alloc_ongoing() fails, this function MUST NOT be called. + */ +void mrmailbox_free_ongoing(mrmailbox_t* mailbox) +{ + s_ongoing_running = 0; + mr_shall_stop_ongoing = 1; /* avoids mrmailbox_stop_ongoing_process() to stop the thread */ +} + + +/** + * Signal an ongoing process to stop. + * + * After that, mrmailbox_stop_ongoing_process() returns _without_ waiting + * for the ongoing process to return. + * + * The ongoing process will return ASAP then, however, it may + * still take a moment. If in doubt, the caller may also decide the kill the + * thread after a few seconds; eg. the process may hang in a + * function not under the control of the core (eg. #MR_EVENT_HTTP_GET). Another + * reason for mrmailbox_stop_ongoing_process() not to wait is that otherwise it + * would be GUI-blocking and should be started in another thread then; this + * would make things even more complicated. + * + * Typical ongoing processes are started by mrmailbox_configure_and_connect(), + * mrmailbox_initiate_key_transfer() or mrmailbox_imex(). As there is always at most only + * one onging process at the same time, there is no need to define _which_ process to exit. + * + * @memberof mrmailbox_t + * + * @param mailbox The mailbox object. + * + * @return None + */ +void mrmailbox_stop_ongoing_process(mrmailbox_t* mailbox) +{ + if( mailbox == NULL ) { + return; + } + + if( s_ongoing_running && mr_shall_stop_ongoing==0 ) + { + mrmailbox_log_info(mailbox, 0, "Signaling the ongoing process to stop ASAP."); + mr_shall_stop_ongoing = 1; + } + else + { + mrmailbox_log_info(mailbox, 0, "No ongoing process to stop."); + } +} diff --git a/src/mrmailbox_imex.c b/src/mrmailbox_imex.c index 6f893672..3f58c1f7 100644 --- a/src/mrmailbox_imex.c +++ b/src/mrmailbox_imex.c @@ -35,10 +35,6 @@ #include "mrmimefactory.h" -static int s_imex_running = 0; -static int s_imex_do_exit = 1; /* the value 1 avoids mrmailbox_imex_cancel() from stopping already stopped threads */ - - /******************************************************************************* * Autocrypt Key Transfer ******************************************************************************/ @@ -464,6 +460,10 @@ char* mrmailbox_create_setup_code(mrmailbox_t* mailbox) * * For more details about the Autocrypt setup process, please refer to * https://autocrypt.org/en/latest/level1.html#autocrypt-setup-message + * + * NB: If the user has never sent a message before, this function requires a key to be created. + * In this case, the function may take some seconds to finish and it might be a good idea + * to start it in a separate thread. If so, it can be interrupted using mrmailbox_stop_ongoing_process(). */ char* mrmailbox_initiate_key_transfer(mrmailbox_t* mailbox) { @@ -475,13 +475,25 @@ char* mrmailbox_initiate_key_transfer(mrmailbox_t* mailbox) char* self_addr = NULL; uint32_t contact_id = 0; uint32_t chat_id = 0; - mrmsg_t* msg = mrmsg_new(); + mrmsg_t* msg = NULL; - if( (setup_code=mrmailbox_create_setup_code(mailbox)) == NULL - || !mrmailbox_render_setup_file(mailbox, setup_code, &setup_file_content) ) { + if( !mrmailbox_alloc_ongoing(mailbox) ) { + return 0; /* no cleanup as this would call mrmailbox_free_ongoing() */ + } + #define CHECK_EXIT if( mr_shall_stop_ongoing ) { goto cleanup; } + + if( (setup_code=mrmailbox_create_setup_code(mailbox)) == NULL ) { goto cleanup; } + CHECK_EXIT + + if( !mrmailbox_render_setup_file(mailbox, setup_code, &setup_file_content) ) { + goto cleanup; + } + + CHECK_EXIT + if( (setup_file_name=mr_get_fine_pathNfilename(mailbox->m_blobdir, "autocrypt-setup-message.html")) == NULL || !mr_write_file(setup_file_name, setup_file_content, strlen(setup_file_content), mailbox) ) { goto cleanup; @@ -497,10 +509,14 @@ char* mrmailbox_initiate_key_transfer(mrmailbox_t* mailbox) goto cleanup; } + msg = mrmsg_new(); msg->m_type = MR_MSG_FILE; mrparam_set (msg->m_param, MRP_FILE, setup_file_name); mrparam_set (msg->m_param, MRP_MIMETYPE, "application/autocrypt-setup"); mrparam_set_int(msg->m_param, MRP_SYSTEM_CMD, MR_SYSTEM_AUTOCRYPT_SETUP_MESSAGE); + + CHECK_EXIT + if( mrmailbox_send_msg_object(mailbox, chat_id, msg) == 0 ) { goto cleanup; } @@ -514,6 +530,7 @@ cleanup: mrmsg_unref(msg); free(self_name); free(self_addr); + mrmailbox_free_ongoing(mailbox); return setup_code; } @@ -817,7 +834,7 @@ static int export_backup(mrmailbox_t* mailbox, const char* dir) stmt = mrsqlite3_prepare_v2_(dest_sql, "INSERT INTO backup_blobs (file_name, file_content) VALUES (?, ?);"); while( (dir_entry=readdir(dir_handle))!=NULL ) { - if( s_imex_do_exit ) { + if( mr_shall_stop_ongoing ) { delete_dest_file = 1; goto cleanup; } @@ -954,7 +971,7 @@ static int import_backup(mrmailbox_t* mailbox, const char* backup_to_import) stmt = mrsqlite3_prepare_v2_(mailbox->m_sql, "SELECT file_name, file_content FROM backup_blobs ORDER BY id;"); while( sqlite3_step(stmt) == SQLITE_ROW ) { - if( s_imex_do_exit ) { + if( mr_shall_stop_ongoing ) { goto cleanup; } @@ -1057,7 +1074,7 @@ cleanup: * - For each file written on export, the function sends #MR_EVENT_IMEX_FILE_WRITTEN * * Only one import-/export-progress can run at the same time. - * To cancel an import-/export-progress, use mrmailbox_imex_cancel(). + * To cancel an import-/export-progress, use mrmailbox_stop_ongoing_process(). * * @memberof mrmailbox_t * @@ -1077,19 +1094,15 @@ int mrmailbox_imex(mrmailbox_t* mailbox, int what, const char* param1, const cha return 0; } + if( !mrmailbox_alloc_ongoing(mailbox) ) { + return 0; /* no cleanup as this would call mrmailbox_free_ongoing() */ + } + if( param1 == NULL ) { mrmailbox_log_error(mailbox, 0, "No Import/export dir/file given."); return 0; } - if( s_imex_running || s_imex_do_exit==0 ) { - mrmailbox_log_warning(mailbox, 0, "Already importing/exporting."); - return 0; - } - - s_imex_running = 1; - s_imex_do_exit = 0; - mrmailbox_log_info(mailbox, 0, "Import/export process started."); mailbox->m_cb(mailbox, MR_EVENT_IMEX_PROGRESS, 0, 0); @@ -1143,50 +1156,11 @@ int mrmailbox_imex(mrmailbox_t* mailbox, int what, const char* param1, const cha cleanup: mrmailbox_log_info(mailbox, 0, "Import/export process ended."); - s_imex_do_exit = 1; /* avoids mrmailbox_imex_cancel() to stop the thread */ - s_imex_running = 0; + mrmailbox_free_ongoing(mailbox); return success; } -/** - * Signal the import-/export-process to stop. - * - * After that, mrmailbox_imex_cancel() returns _without_ waiting - * for mrmailbox_imex() to return. - * - * mrmailbox_imex() will return ASAP then, however, it may - * still take a moment. If in doubt, the caller may also decide the kill the - * thread after a few seconds; eg. the process may hang in a - * function not under the control of the core (eg. #MR_EVENT_HTTP_GET). Another - * reason for mrmailbox_imex_cancel() not to wait is that otherwise it - * would be GUI-blocking and should be started in another thread then; this - * would make things even more complicated. - * - * @memberof mrmailbox_t - * - * @param mailbox The mailbox object. - * - * @return None - */ -void mrmailbox_imex_cancel(mrmailbox_t* mailbox) -{ - if( mailbox == NULL ) { - return; - } - - if( s_imex_running && s_imex_do_exit==0 ) - { - mrmailbox_log_info(mailbox, 0, "Signaling the import-/export-process to stop ASAP."); - s_imex_do_exit = 1; - } - else - { - mrmailbox_log_info(mailbox, 0, "No import-/export-process to stop."); - } -} - - /** * Check if there is a backup file. *