From 7ae34daa0380cde366057cf4b5ad5f99e75174e5 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 30 Nov 2017 23:10:27 +0100 Subject: [PATCH] do not start a thread for the import-/export process. --- cmdline/cmdline.c | 14 +-- src/mrevent.h | 16 +-- src/mrmailbox.h | 4 +- src/mrmailbox_configure.c | 2 +- src/mrmailbox_imex.c | 232 +++++++++++++++++++------------------- 5 files changed, 124 insertions(+), 144 deletions(-) diff --git a/cmdline/cmdline.c b/cmdline/cmdline.c index de23f705..3fe9a7e1 100644 --- a/cmdline/cmdline.c +++ b/cmdline/cmdline.c @@ -437,23 +437,19 @@ char* mrmailbox_cmdline(mrmailbox_t* mailbox, const char* cmdline) if( arg2 ) { *arg2 = 0; arg2++; } if( strcmp(arg1, "export-keys")==0 && arg2==NULL ) { - mrmailbox_imex(mailbox, MR_IMEX_EXPORT_SELF_KEYS, mailbox->m_blobdir, NULL); - ret = COMMAND_SUCCEEDED; + ret = mrmailbox_imex(mailbox, MR_IMEX_EXPORT_SELF_KEYS, mailbox->m_blobdir, NULL)? COMMAND_SUCCEEDED : COMMAND_FAILED; } else if( strcmp(arg1, "import-keys")==0 ) { - mrmailbox_imex(mailbox, MR_IMEX_IMPORT_SELF_KEYS, mailbox->m_blobdir, NULL); - ret = COMMAND_SUCCEEDED; + ret = mrmailbox_imex(mailbox, MR_IMEX_IMPORT_SELF_KEYS, mailbox->m_blobdir, NULL)? COMMAND_SUCCEEDED : COMMAND_FAILED; } else if( strcmp(arg1, "export-backup")==0 && arg2==NULL ) { - mrmailbox_imex(mailbox, MR_IMEX_EXPORT_BACKUP, mailbox->m_blobdir, NULL); - ret = COMMAND_SUCCEEDED; + ret = mrmailbox_imex(mailbox, MR_IMEX_EXPORT_BACKUP, mailbox->m_blobdir, NULL)? COMMAND_SUCCEEDED : COMMAND_FAILED; } else if( strcmp(arg1, "import-backup")==0 && arg2!=NULL ) { - mrmailbox_imex(mailbox, MR_IMEX_IMPORT_BACKUP, arg2, NULL); - ret = COMMAND_SUCCEEDED; + ret = mrmailbox_imex(mailbox, MR_IMEX_IMPORT_BACKUP, arg2, NULL)? COMMAND_SUCCEEDED : COMMAND_FAILED; } else if( strcmp(arg1, "cancel")==0 ) { - mrmailbox_imex(mailbox, 0, NULL, NULL); + mrmailbox_imex_cancel(mailbox); ret = COMMAND_SUCCEEDED; } else { diff --git a/src/mrevent.h b/src/mrevent.h index 5d1b875b..afd29de7 100644 --- a/src/mrevent.h +++ b/src/mrevent.h @@ -172,19 +172,6 @@ extern "C" { #define MR_EVENT_CONFIGURE_PROGRESS 2041 -/** - * Import/export done. You'll get this event from a call to mrmailbox_imex(). - * As we want to get rid of the threads in the core, this event may be deleted. - * - * @param data1 0:failed, 1=success - * - * @param data2 0 - * - * @return 0 - */ -#define MR_EVENT_IMEX_ENDED 2050 - - /** * Inform about the import/export progress started by mrmailbox_imex(). * @@ -199,8 +186,7 @@ extern "C" { /** * A file has been exported. A file has been written by mrmailbox_imex(). - * This event may be send multiple times by a single call to mrmailbox_imex(); - * if the export is done, #MR_EVENT_IMEX_ENDED is sent. + * This event may be send multiple times by a single call to mrmailbox_imex(). * * A typical purpose for a handler of this event may be to make the file public to some system * services. diff --git a/src/mrmailbox.h b/src/mrmailbox.h index 5f2518cb..2cc88af7 100644 --- a/src/mrmailbox.h +++ b/src/mrmailbox.h @@ -319,7 +319,6 @@ mrcontact_t* mrmailbox_get_contact (mrmailbox_t*, uint32_t contact_id); /* Import/export and Tools */ -#define MR_IMEX_CANCEL 0 #define MR_IMEX_EXPORT_SELF_KEYS 1 /* param1 is a directory where the keys are written to */ #define MR_IMEX_IMPORT_SELF_KEYS 2 /* param1 is a directory where the keys are searched in and read from */ #define MR_IMEX_EXPORT_BACKUP 11 /* param1 is a directory where the backup is written to */ @@ -327,7 +326,8 @@ mrcontact_t* mrmailbox_get_contact (mrmailbox_t*, uint32_t contact_id); #define MR_IMEX_EXPORT_SETUP_MESSAGE 20 /* param1 is a directory where the setup file is written to */ #define MR_BAK_PREFIX "delta-chat" #define MR_BAK_SUFFIX "bak" -void mrmailbox_imex (mrmailbox_t*, int what, const char* param1, const char* setup_code); +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_create_setup_code (mrmailbox_t*); diff --git a/src/mrmailbox_configure.c b/src/mrmailbox_configure.c index 34863963..668f34a1 100644 --- a/src/mrmailbox_configure.c +++ b/src/mrmailbox_configure.c @@ -691,7 +691,7 @@ cleanup: mrloginparam_unref(param_autoconfig); free(param_addr_urlencoded); - s_configure_do_exit = 1; /* set this before sending terminating, avoids mrmailbox_configure_cancel() to stop the thread */ + s_configure_do_exit = 1; /* avoids mrmailbox_configure_cancel() to stop the thread */ s_configure_running = 0; return success; } diff --git a/src/mrmailbox_imex.c b/src/mrmailbox_imex.c index 69c1ba4c..f46aad86 100644 --- a/src/mrmailbox_imex.c +++ b/src/mrmailbox_imex.c @@ -33,7 +33,8 @@ #include "mrapeerstate.h" #include "mrpgp.h" -static int s_imex_do_exit = 1; /* the value 1 avoids MR_IMEX_CANCEL from stopping already stopped threads */ +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 */ /******************************************************************************* @@ -818,91 +819,6 @@ cleanup: ******************************************************************************/ -typedef struct mrimexthreadparam_t -{ - mrmailbox_t* m_mailbox; - int m_what; - char* m_param1; /* meaning depends on m_what */ - char* m_setup_code; -} mrimexthreadparam_t; - - -static pthread_t s_imex_thread; -static int s_imex_thread_created = 0; - - -static void* imex_thread_entry_point(void* entry_arg) -{ - int success = 0; - mrimexthreadparam_t* thread_param = (mrimexthreadparam_t*)entry_arg; - mrmailbox_t* mailbox = thread_param->m_mailbox; /*keep a local pointer as we free thread_param sooner or later */ - - mrosnative_setup_thread(mailbox); /* must be first */ - mrmailbox_log_info(mailbox, 0, "Import/export thread started."); - - if( !mrsqlite3_is_open(thread_param->m_mailbox->m_sql) ) { - mrmailbox_log_error(mailbox, 0, "Import/export: Database not opened."); - goto cleanup; - } - - if( thread_param->m_what==MR_IMEX_EXPORT_SELF_KEYS || thread_param->m_what==MR_IMEX_EXPORT_BACKUP ) { - /* before we export anything, make sure the private key exists */ - if( !mrmailbox_ensure_secret_key_exists(mailbox) ) { - mrmailbox_log_error(mailbox, 0, "Import/export: Cannot create private key or private key not available."); - goto cleanup; - } - /* also make sure, the directory for exporting exists */ - mr_create_folder(thread_param->m_param1, mailbox); - } - - switch( thread_param->m_what ) - { - case MR_IMEX_EXPORT_SELF_KEYS: - if( !export_self_keys(mailbox, thread_param->m_param1) ) { - goto cleanup; - } - break; - - case MR_IMEX_IMPORT_SELF_KEYS: - if( !import_self_keys(mailbox, thread_param->m_param1) ) { - goto cleanup; - } - break; - - case MR_IMEX_EXPORT_BACKUP: - if( !export_backup(mailbox, thread_param->m_param1) ) { - goto cleanup; - } - break; - - case MR_IMEX_IMPORT_BACKUP: - if( !import_backup(mailbox, thread_param->m_param1) ) { - goto cleanup; - } - break; - - case MR_IMEX_EXPORT_SETUP_MESSAGE: - if( !export_setup_file(mailbox, thread_param->m_param1, thread_param->m_setup_code) ) { - goto cleanup; - } - break; - } - - success = 1; - -cleanup: - mrmailbox_log_info(mailbox, 0, "Import/export thread ended."); - s_imex_do_exit = 1; /* set this before sending MR_EVENT_EXPORT_ENDED, avoids MR_IMEX_CANCEL to stop the thread */ - mailbox->m_cb(mailbox, MR_EVENT_IMEX_ENDED, success, 0); - s_imex_thread_created = 0; - free(thread_param->m_param1); - free(thread_param->m_setup_code); - free(thread_param); - mrosnative_unsetup_thread(mailbox); /* must be very last (here we really new the local copy of the pointer) */ - return NULL; -} - - /** * Import/export things. * @@ -926,64 +842,146 @@ cleanup: * - **MR_IMEX_IMPORT_SELF_KEYS** (2) - Import private keys found in the directory given as `param1`. * The last imported key is made the default keys unless its name contains the string `legacy`. Public keys are not imported. * - * - **MR_IMEX_CANCEL** (0) - Cancel any pending import or export. - * * The function may take a long time until it finishes, so it might be a good idea to start it in a * separate thread. During its execution, the function sends out some events: * - * - The function sends out a number of #MR_EVENT_IMEX_PROGRESS events that may be used to create + * - A number of #MR_EVENT_IMEX_PROGRESS events are sent and may be used to create * a progress bar or stuff like that. * * - 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(). + * * @memberof mrmailbox_t * * @param mailbox Mailbox object as created by mrmailbox_new(). * @param what One of the MR_IMEX_* constants. * @param param1 Meaning depends on the MR_IMEX_* constants. If this parameter is a directory, it should not end with - * a slash (otherwise you'll get double slashes when receiving #MR_EVENT_IMEX_FILE_WRITTEN). - * @param setup_code Optional setup-code to encrypt/decrypt data. + * a slash (otherwise you'll get double slashes when receiving #MR_EVENT_IMEX_FILE_WRITTEN). Set to NULL if not used. + * @param param2 Meaning depends on the MR_IMEX_* constants. Set to NULL if not used. * - * @return None. + * @return 1=success, 0=error or progress canceled. */ -void mrmailbox_imex(mrmailbox_t* mailbox, int what, const char* param1, const char* setup_code) +int mrmailbox_imex(mrmailbox_t* mailbox, int what, const char* param1, const char* param2) { - mrimexthreadparam_t* thread_param; + int success = 0; if( mailbox==NULL || mailbox->m_sql==NULL ) { - return; - } - - if( what == MR_IMEX_CANCEL ) { - /* cancel an running export */ - if( s_imex_thread_created && s_imex_do_exit==0 ) { - mrmailbox_log_info(mailbox, 0, "Stopping import/export thread..."); - s_imex_do_exit = 1; - pthread_join(s_imex_thread, NULL); - mrmailbox_log_info(mailbox, 0, "Import/export thread stopped."); - } - return; + return 0; } if( param1 == NULL ) { mrmailbox_log_error(mailbox, 0, "No Import/export dir/file given."); - return; + return 0; } - if( s_imex_thread_created || s_imex_do_exit==0 ) { + if( s_imex_running || s_imex_do_exit==0 ) { mrmailbox_log_warning(mailbox, 0, "Already importing/exporting."); - return; + return 0; } - s_imex_thread_created = 1; + + s_imex_running = 1; s_imex_do_exit = 0; - memset(&s_imex_thread, 0, sizeof(pthread_t)); - thread_param = calloc(1, sizeof(mrimexthreadparam_t)); - thread_param->m_mailbox = mailbox; - thread_param->m_what = what; - thread_param->m_param1 = safe_strdup(param1); - thread_param->m_setup_code = safe_strdup(setup_code); - pthread_create(&s_imex_thread, NULL, imex_thread_entry_point, thread_param); + mrmailbox_log_info(mailbox, 0, "Import/export process started."); + + if( !mrsqlite3_is_open(mailbox->m_sql) ) { + mrmailbox_log_error(mailbox, 0, "Import/export: Database not opened."); + goto cleanup; + } + + if( what==MR_IMEX_EXPORT_SELF_KEYS || what==MR_IMEX_EXPORT_BACKUP ) { + /* before we export anything, make sure the private key exists */ + if( !mrmailbox_ensure_secret_key_exists(mailbox) ) { + mrmailbox_log_error(mailbox, 0, "Import/export: Cannot create private key or private key not available."); + goto cleanup; + } + /* also make sure, the directory for exporting exists */ + mr_create_folder(param1, mailbox); + } + + switch( what ) + { + case MR_IMEX_EXPORT_SELF_KEYS: + if( !export_self_keys(mailbox, param1) ) { + goto cleanup; + } + break; + + case MR_IMEX_IMPORT_SELF_KEYS: + if( !import_self_keys(mailbox, param1) ) { + goto cleanup; + } + break; + + case MR_IMEX_EXPORT_BACKUP: + if( !export_backup(mailbox, param1) ) { + goto cleanup; + } + break; + + case MR_IMEX_IMPORT_BACKUP: + if( !import_backup(mailbox, param1) ) { + goto cleanup; + } + break; + + case MR_IMEX_EXPORT_SETUP_MESSAGE: + if( !export_setup_file(mailbox, param1, param2) ) { + goto cleanup; + } + break; + + default: + goto cleanup; + } + + success = 1; + +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; + 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."); + } }