From 24eaf01eedc2309cb8a3e027bbc33c429e0af09e Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 11 Jul 2018 15:10:18 +0200 Subject: [PATCH 01/10] bind jobs stronger to msg_id --- src/dc_job.c | 20 ++++++++++---------- src/dc_job.h | 4 ++-- src/dc_sqlite3.c | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/dc_job.c b/src/dc_job.c index efa41316..46cc3300 100644 --- a/src/dc_job.c +++ b/src/dc_job.c @@ -90,7 +90,7 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_IMAP(dc_context_t* context, dc_job_t* j } /* create message */ - if (dc_mimefactory_load_msg(&mimefactory, job->foreign_id)==0 + if (dc_mimefactory_load_msg(&mimefactory, job->msg_id)==0 || mimefactory.from_addr==NULL) { goto cleanup; /* should not happen as we've sent the message to the SMTP server before */ } @@ -119,7 +119,7 @@ static void dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(dc_context_t* context, dc_job_t* dc_msg_t* msg = dc_msg_new(); sqlite3_stmt* stmt = NULL; - if (!dc_msg_load_from_db(msg, context, job->foreign_id) + if (!dc_msg_load_from_db(msg, context, job->msg_id) || msg->rfc724_mid==NULL || msg->rfc724_mid[0]==0 /* eg. device messages have no Message-ID */) { goto cleanup; } @@ -226,7 +226,7 @@ static void dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(dc_context_t* context, dc_job_ } } - if (!dc_msg_load_from_db(msg, context, job->foreign_id)) { + if (!dc_msg_load_from_db(msg, context, job->msg_id)) { goto cleanup; } @@ -327,7 +327,7 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_SMTP(dc_context_t* context, dc_job_t* j } /* load message data */ - if (!dc_mimefactory_load_msg(&mimefactory, job->foreign_id) + if (!dc_mimefactory_load_msg(&mimefactory, job->msg_id) || mimefactory.from_addr==NULL) { dc_log_warning(context, 0, "Cannot load data to send, maybe the message is deleted in between."); goto cleanup; /* no redo, no IMAP - there won't be more recipients next time (as the data does not exist, there is no need in calling mark_as_error()) */ @@ -424,7 +424,7 @@ static void dc_job_do_DC_JOB_SEND_MDN(dc_context_t* context, dc_job_t* job) } } - if (!dc_mimefactory_load_mdn(&mimefactory, job->foreign_id) + if (!dc_mimefactory_load_mdn(&mimefactory, job->msg_id) || !dc_mimefactory_render(&mimefactory)) { goto cleanup; } @@ -472,7 +472,7 @@ static void dc_suspend_smtp_thread(dc_context_t* context, int suspend) ******************************************************************************/ -void dc_job_add(dc_context_t* context, int action, int foreign_id, const char* param, int delay_seconds) +void dc_job_add(dc_context_t* context, int action, int msg_id, const char* param, int delay_seconds) { time_t timestamp = time(NULL); sqlite3_stmt* stmt = NULL; @@ -493,7 +493,7 @@ void dc_job_add(dc_context_t* context, int action, int foreign_id, const char* p sqlite3_bind_int64(stmt, 1, timestamp); sqlite3_bind_int (stmt, 2, thread); sqlite3_bind_int (stmt, 3, action); - sqlite3_bind_int (stmt, 4, foreign_id); + sqlite3_bind_int (stmt, 4, msg_id); sqlite3_bind_text (stmt, 5, param? param : "", -1, SQLITE_STATIC); sqlite3_bind_int64(stmt, 6, delay_seconds>0? (timestamp+delay_seconds) : 0); sqlite3_step(stmt); @@ -553,9 +553,9 @@ static void dc_job_perform(dc_context_t* context, int thread) sqlite3_bind_int64(select_stmt, 2, time(NULL)); while (sqlite3_step(select_stmt)==SQLITE_ROW) { - job.job_id = sqlite3_column_int (select_stmt, 0); - job.action = sqlite3_column_int (select_stmt, 1); - job.foreign_id = sqlite3_column_int (select_stmt, 2); + job.job_id = sqlite3_column_int (select_stmt, 0); + job.action = sqlite3_column_int (select_stmt, 1); + job.msg_id = sqlite3_column_int (select_stmt, 2); dc_param_set_packed(job.param, (char*)sqlite3_column_text(select_stmt, 3)); dc_log_info(context, 0, "%s-job #%i, action %i started...", THREAD_STR, (int)job.job_id, (int)job.action); diff --git a/src/dc_job.h b/src/dc_job.h index 344becf8..dff9e02d 100644 --- a/src/dc_job.h +++ b/src/dc_job.h @@ -67,13 +67,13 @@ typedef struct dc_job_t uint32_t job_id; int action; - uint32_t foreign_id; + uint32_t msg_id; dc_param_t* param; int try_again; } dc_job_t; -void dc_job_add (dc_context_t*, int action, int foreign_id, const char* param, int delay); +void dc_job_add (dc_context_t*, int action, int msg_id, const char* param, int delay); void dc_job_kill_actions (dc_context_t*, int action1, int action2); /* delete all pending jobs with the given actions */ #define DC_DONT_TRY_AGAIN 0 diff --git a/src/dc_sqlite3.c b/src/dc_sqlite3.c index d26fa86b..0cc3e301 100644 --- a/src/dc_sqlite3.c +++ b/src/dc_sqlite3.c @@ -274,7 +274,7 @@ int dc_sqlite3_open(dc_sqlite3_t* sql, const char* dbfile, int flags) " added_timestamp INTEGER," " desired_timestamp INTEGER DEFAULT 0," " action INTEGER," - " foreign_id INTEGER," + " foreign_id INTEGER," // currently, this is always msg_id " param TEXT DEFAULT '');"); dc_sqlite3_execute(sql, "CREATE INDEX jobs_index1 ON jobs (desired_timestamp);"); From c8e484b8b166901cbde1bb32c48eecd66fdf6855 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 11 Jul 2018 15:19:25 +0200 Subject: [PATCH 02/10] allow pending errors in jobs --- src/dc_job.c | 34 +++++++++++++++++++--------------- src/dc_job.h | 4 +++- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/dc_job.c b/src/dc_job.c index 46cc3300..b5e4d46b 100644 --- a/src/dc_job.c +++ b/src/dc_job.c @@ -61,7 +61,7 @@ static int connect_to_imap(dc_context_t* context, dc_job_t* job /*may be NULL if dc_loginparam_read(param, context->sql, "configured_" /*the trailing underscore is correct*/); if (!dc_imap_connect(context->imap, param)) { - dc_job_try_again_later(job, DC_STANDARD_DELAY); + dc_job_try_again_later(job, DC_STANDARD_DELAY, NULL); goto cleanup; } @@ -84,7 +84,7 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_IMAP(dc_context_t* context, dc_job_t* j if (!dc_imap_is_connected(context->imap)) { connect_to_imap(context, NULL); if (!dc_imap_is_connected(context->imap)) { - dc_job_try_again_later(job, DC_STANDARD_DELAY); + dc_job_try_again_later(job, DC_STANDARD_DELAY, NULL); goto cleanup; } } @@ -100,7 +100,7 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_IMAP(dc_context_t* context, dc_job_t* j } if (!dc_imap_append_msg(context->imap, mimefactory.msg->timestamp, mimefactory.out->str, mimefactory.out->len, &server_folder, &server_uid)) { - dc_job_try_again_later(job, DC_AT_ONCE); + dc_job_try_again_later(job, DC_AT_ONCE, NULL); goto cleanup; } else { @@ -135,14 +135,14 @@ static void dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(dc_context_t* context, dc_job_t* if (!dc_imap_is_connected(context->imap)) { connect_to_imap(context, NULL); if (!dc_imap_is_connected(context->imap)) { - dc_job_try_again_later(job, DC_STANDARD_DELAY); + dc_job_try_again_later(job, DC_STANDARD_DELAY, NULL); goto cleanup; } } if (!dc_imap_delete_msg(context->imap, msg->rfc724_mid, msg->server_folder, msg->server_uid)) { - dc_job_try_again_later(job, DC_AT_ONCE); + dc_job_try_again_later(job, DC_AT_ONCE, NULL); goto cleanup; } } @@ -221,7 +221,7 @@ static void dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(dc_context_t* context, dc_job_ if (!dc_imap_is_connected(context->imap)) { connect_to_imap(context, NULL); if (!dc_imap_is_connected(context->imap)) { - dc_job_try_again_later(job, DC_STANDARD_DELAY); + dc_job_try_again_later(job, DC_STANDARD_DELAY, NULL); goto cleanup; } } @@ -258,7 +258,7 @@ static void dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(dc_context_t* context, dc_job_ } else { - dc_job_try_again_later(job, DC_AT_ONCE); + dc_job_try_again_later(job, DC_AT_ONCE, NULL); } cleanup: @@ -278,13 +278,13 @@ static void dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(dc_context_t* context, dc_job_ if (!dc_imap_is_connected(context->imap)) { connect_to_imap(context, NULL); if (!dc_imap_is_connected(context->imap)) { - dc_job_try_again_later(job, DC_STANDARD_DELAY); + dc_job_try_again_later(job, DC_STANDARD_DELAY, NULL); goto cleanup; } } if (dc_imap_markseen_msg(context->imap, server_folder, server_uid, DC_MS_ALSO_MOVE, &new_server_folder, &new_server_uid, &out_ms_flags)==0) { - dc_job_try_again_later(job, DC_AT_ONCE); + dc_job_try_again_later(job, DC_AT_ONCE, NULL); } cleanup: @@ -321,7 +321,7 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_SMTP(dc_context_t* context, dc_job_t* j int connected = dc_smtp_connect(context->smtp, loginparam); dc_loginparam_unref(loginparam); if (!connected) { - dc_job_try_again_later(job, DC_STANDARD_DELAY); + dc_job_try_again_later(job, DC_STANDARD_DELAY, NULL); goto cleanup; } } @@ -336,7 +336,7 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_SMTP(dc_context_t* context, dc_job_t* j /* check if the message is ready (normally, only video files may be delayed this way) */ if (mimefactory.increation) { dc_log_info(context, 0, "File is in creation, retrying later."); - dc_job_try_again_later(job, DC_INCREATION_POLL); + dc_job_try_again_later(job, DC_INCREATION_POLL, NULL); goto cleanup; } @@ -357,7 +357,7 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_SMTP(dc_context_t* context, dc_job_t* j if (!dc_smtp_send_msg(context->smtp, mimefactory.recipients_addr, mimefactory.out->str, mimefactory.out->len)) { dc_smtp_disconnect(context->smtp); - dc_job_try_again_later(job, DC_AT_ONCE); /* DC_AT_ONCE is only the _initial_ delay, if the second try failes, the delay gets larger */ + dc_job_try_again_later(job, DC_AT_ONCE, NULL); /* DC_AT_ONCE is only the _initial_ delay, if the second try failes, the delay gets larger */ goto cleanup; } } @@ -419,7 +419,7 @@ static void dc_job_do_DC_JOB_SEND_MDN(dc_context_t* context, dc_job_t* job) int connected = dc_smtp_connect(context->smtp, loginparam); dc_loginparam_unref(loginparam); if (!connected) { - dc_job_try_again_later(job, DC_STANDARD_DELAY); + dc_job_try_again_later(job, DC_STANDARD_DELAY, NULL); goto cleanup; } } @@ -433,7 +433,7 @@ static void dc_job_do_DC_JOB_SEND_MDN(dc_context_t* context, dc_job_t* job) if (!dc_smtp_send_msg(context->smtp, mimefactory.recipients_addr, mimefactory.out->str, mimefactory.out->len)) { dc_smtp_disconnect(context->smtp); - dc_job_try_again_later(job, DC_AT_ONCE); /* DC_AT_ONCE is only the _initial_ delay, if the second try failes, the delay gets larger */ + dc_job_try_again_later(job, DC_AT_ONCE, NULL); /* DC_AT_ONCE is only the _initial_ delay, if the second try failes, the delay gets larger */ goto cleanup; } @@ -508,13 +508,16 @@ void dc_job_add(dc_context_t* context, int action, int msg_id, const char* param } -void dc_job_try_again_later(dc_job_t* job, int try_again) +void dc_job_try_again_later(dc_job_t* job, int try_again, const char* pending_error) { if (job==NULL) { return; } job->try_again = try_again; + + free(job->pending_error); + job->pending_error = dc_strdup_keep_null(pending_error); } @@ -636,6 +639,7 @@ static void dc_job_perform(dc_context_t* context, int thread) cleanup: dc_param_unref(job.param); + free(job.pending_error); sqlite3_finalize(select_stmt); } diff --git a/src/dc_job.h b/src/dc_job.h index dff9e02d..4abbfd78 100644 --- a/src/dc_job.h +++ b/src/dc_job.h @@ -69,7 +69,9 @@ typedef struct dc_job_t int action; uint32_t msg_id; dc_param_t* param; + int try_again; + char* pending_error; // discarded if the retry succeeds } dc_job_t; @@ -80,7 +82,7 @@ void dc_job_kill_actions (dc_context_t*, int action1, int action2); #define DC_AT_ONCE -1 #define DC_INCREATION_POLL 2 // this value does not increase the number of tries #define DC_STANDARD_DELAY 3 -void dc_job_try_again_later (dc_job_t*, int try_again); +void dc_job_try_again_later (dc_job_t*, int try_again, const char* error); // the other dc_job_do_DC_JOB_*() functions are declared static in the c-file From 11d1083ce5e58fe06d4c3f397b45dda0138464ec Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 11 Jul 2018 15:27:09 +0200 Subject: [PATCH 03/10] allow message-errors and show them in message-info --- src/dc_msg.c | 15 +++++++++++---- src/dc_param.h | 1 + src/dc_sqlite3.c | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/dc_msg.c b/src/dc_msg.c index b3b8b4df..e5fab6d6 100644 --- a/src/dc_msg.c +++ b/src/dc_msg.c @@ -1431,6 +1431,12 @@ char* dc_get_msg_info(dc_context_t* context, uint32_t msg_id) } dc_strbuilder_cat(&ret, "\n"); + + if ((p=dc_param_get(msg->param, DC_PARAM_ERROR, NULL))!=NULL) { + dc_strbuilder_catf(&ret, "Error: %s\n", p); + free(p); + } + /* add sender (only for info messages as the avatar may not be shown for them) */ if (dc_msg_is_info(msg)) { dc_strbuilder_cat(&ret, "Sender: "); @@ -1439,9 +1445,9 @@ char* dc_get_msg_info(dc_context_t* context, uint32_t msg_id) } /* add file info */ - char* file = dc_param_get(msg->param, DC_PARAM_FILE, NULL); - if (file) { - p = dc_mprintf("\nFile: %s, %i bytes\n", file, (int)dc_get_filebytes(file)); dc_strbuilder_cat(&ret, p); free(p); + if ((p=dc_param_get(msg->param, DC_PARAM_FILE, NULL))!=NULL) { + dc_strbuilder_catf(&ret, "\nFile: %s, %i bytes\n", p, (int)dc_get_filebytes(p)); + free(p); } if (msg->type!=DC_MSG_TEXT) { @@ -1459,7 +1465,8 @@ char* dc_get_msg_info(dc_context_t* context, uint32_t msg_id) free(p); } - int w = dc_param_get_int(msg->param, DC_PARAM_WIDTH, 0), h = dc_param_get_int(msg->param, DC_PARAM_HEIGHT, 0); + int w = dc_param_get_int(msg->param, DC_PARAM_WIDTH, 0); + int h = dc_param_get_int(msg->param, DC_PARAM_HEIGHT, 0); if (w!=0 || h!=0) { p = dc_mprintf("Dimension: %i x %i\n", w, h); dc_strbuilder_cat(&ret, p); free(p); } diff --git a/src/dc_param.h b/src/dc_param.h index 040c148f..fd127252 100644 --- a/src/dc_param.h +++ b/src/dc_param.h @@ -60,6 +60,7 @@ typedef struct dc_param_t #define DC_PARAM_CMD_ARG2 'F' /* for msgs */ #define DC_PARAM_CMD_ARG3 'G' /* for msgs */ #define DC_PARAM_CMD_ARG4 'H' /* for msgs */ +#define DC_PARAM_ERROR 'L' /* for msgs */ #define DC_PARAM_SERVER_FOLDER 'Z' /* for jobs */ #define DC_PARAM_SERVER_UID 'z' /* for jobs */ diff --git a/src/dc_sqlite3.c b/src/dc_sqlite3.c index 0cc3e301..d26fa86b 100644 --- a/src/dc_sqlite3.c +++ b/src/dc_sqlite3.c @@ -274,7 +274,7 @@ int dc_sqlite3_open(dc_sqlite3_t* sql, const char* dbfile, int flags) " added_timestamp INTEGER," " desired_timestamp INTEGER DEFAULT 0," " action INTEGER," - " foreign_id INTEGER," // currently, this is always msg_id + " foreign_id INTEGER," " param TEXT DEFAULT '');"); dc_sqlite3_execute(sql, "CREATE INDEX jobs_index1 ON jobs (desired_timestamp);"); From 5770bd8b168de6c03dd7d525aaab6155ba25e430 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 11 Jul 2018 15:39:37 +0200 Subject: [PATCH 04/10] split functions --- src/dc_job.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/dc_job.c b/src/dc_job.c index b5e4d46b..015fd303 100644 --- a/src/dc_job.c +++ b/src/dc_job.c @@ -508,6 +508,27 @@ void dc_job_add(dc_context_t* context, int action, int msg_id, const char* param } +static void dc_job_update(dc_context_t* context, const dc_job_t* job) +{ + sqlite3_stmt* update_stmt = dc_sqlite3_prepare(context->sql, + "UPDATE jobs SET desired_timestamp=0, param=? WHERE id=?;"); + sqlite3_bind_text (update_stmt, 1, job->param->packed, -1, SQLITE_STATIC); + sqlite3_bind_int (update_stmt, 2, job->job_id); + sqlite3_step(update_stmt); + sqlite3_finalize(update_stmt); +} + + +static void dc_job_delete(dc_context_t* context, const dc_job_t* job) +{ + sqlite3_stmt* delete_stmt = dc_sqlite3_prepare(context->sql, + "DELETE FROM jobs WHERE id=?;"); + sqlite3_bind_int(delete_stmt, 1, job->job_id); + sqlite3_step(delete_stmt); + sqlite3_finalize(delete_stmt); +} + + void dc_job_try_again_later(dc_job_t* job, int try_again, const char* pending_error) { if (job==NULL) { @@ -608,12 +629,7 @@ static void dc_job_perform(dc_context_t* context, int thread) int tries = dc_param_get_int(job.param, DC_PARAM_TIMES, 0) + 1; dc_param_set_int(job.param, DC_PARAM_TIMES, tries); - sqlite3_stmt* update_stmt = dc_sqlite3_prepare(context->sql, - "UPDATE jobs SET desired_timestamp=0, param=? WHERE id=?;"); - sqlite3_bind_text (update_stmt, 1, job.param->packed, -1, SQLITE_STATIC); - sqlite3_bind_int (update_stmt, 2, job.job_id); - sqlite3_step(update_stmt); - sqlite3_finalize(update_stmt); + dc_job_update(context, &job); dc_log_info(context, 0, "%s-job #%i not succeeded, trying again asap.", THREAD_STR, (int)job.job_id); // if the job did not succeeded AND this is a smtp-job AND we're online, try over after a mini-delay of one second. @@ -629,11 +645,7 @@ static void dc_job_perform(dc_context_t* context, int thread) } else { - sqlite3_stmt* delete_stmt = dc_sqlite3_prepare(context->sql, - "DELETE FROM jobs WHERE id=?;"); - sqlite3_bind_int(delete_stmt, 1, job.job_id); - sqlite3_step(delete_stmt); - sqlite3_finalize(delete_stmt); + dc_job_delete(context, &job); } } From 9c59c46b571b101a6ed5684e17bbbf6091204bdc Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 11 Jul 2018 16:29:46 +0200 Subject: [PATCH 05/10] add a msg-function to set a msg into error-state, incl. error-text --- src/dc_job.c | 17 ++--------------- src/dc_msg.c | 30 ++++++++++++++++++++++++++++++ src/dc_msg.h | 1 + 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/dc_job.c b/src/dc_job.c index 015fd303..7c62455e 100644 --- a/src/dc_job.c +++ b/src/dc_job.c @@ -298,17 +298,6 @@ cleanup: ******************************************************************************/ -static void mark_as_error(dc_context_t* context, dc_msg_t* msg) -{ - if (context==NULL || msg==NULL) { - return; - } - - dc_update_msg_state(context, msg->id, DC_STATE_OUT_ERROR); - context->cb(context, DC_EVENT_MSGS_CHANGED, msg->chat_id, 0); -} - - static void dc_job_do_DC_JOB_SEND_MSG_TO_SMTP(dc_context_t* context, dc_job_t* job) { dc_mimefactory_t mimefactory; @@ -343,15 +332,13 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_SMTP(dc_context_t* context, dc_job_t* j /* send message - it's okay if there are no recipients, this is a group with only OURSELF; we only upload to IMAP in this case */ if (clist_count(mimefactory.recipients_addr) > 0) { if (!dc_mimefactory_render(&mimefactory)) { - mark_as_error(context, mimefactory.msg); - dc_log_error(context, 0, "Empty message."); /* should not happen */ + dc_update_msg_error(context, job->msg_id, "Empty message."); goto cleanup; /* no redo, no IMAP - there won't be more recipients next time. */ } /* have we guaranteed encryption but cannot fulfill it for any reason? Do not send the message then.*/ if (dc_param_get_int(mimefactory.msg->param, DC_PARAM_GUARANTEE_E2EE, 0) && !mimefactory.out_encrypted) { - mark_as_error(context, mimefactory.msg); - dc_log_error(context, 0, "End-to-end-encryption unavailable unexpectedly."); + dc_update_msg_error(context, job->msg_id, "End-to-end-encryption unavailable unexpectedly."); goto cleanup; /* unrecoverable */ } diff --git a/src/dc_msg.c b/src/dc_msg.c index e5fab6d6..8b0a197e 100644 --- a/src/dc_msg.c +++ b/src/dc_msg.c @@ -1158,6 +1158,36 @@ void dc_update_msg_state(dc_context_t* context, uint32_t msg_id, int state) } +void dc_update_msg_error(dc_context_t* context, uint32_t msg_id, const char* error) +{ + dc_msg_t* msg = dc_msg_new(); + sqlite3_stmt* stmt = NULL; + + if (!dc_msg_load_from_db(msg, context, msg_id)) { + goto cleanup; + } + + msg->state = DC_STATE_OUT_ERROR; + if (error) { + dc_param_set(msg->param, DC_PARAM_ERROR, error); + dc_log_error(context, 0, "%s", error); + } + + stmt = dc_sqlite3_prepare(context->sql, + "UPDATE msgs SET state=?, param=? WHERE id=?;"); + sqlite3_bind_int (stmt, 1, msg->state); + sqlite3_bind_text(stmt, 2, msg->param->packed, -1, SQLITE_STATIC); + sqlite3_bind_int (stmt, 3, msg_id); + sqlite3_step(stmt); + + context->cb(context, DC_EVENT_MSGS_CHANGED, msg->chat_id, 0); + +cleanup: + sqlite3_finalize(stmt); + dc_msg_unref(msg); +} + + size_t dc_get_real_msg_cnt(dc_context_t* context) { sqlite3_stmt* stmt = NULL; diff --git a/src/dc_msg.h b/src/dc_msg.h index dc1e2fb0..75144a86 100644 --- a/src/dc_msg.h +++ b/src/dc_msg.h @@ -110,6 +110,7 @@ The value is also used for CC:-summaries */ // Context functions to work with messages void dc_update_msg_chat_id (dc_context_t*, uint32_t msg_id, uint32_t chat_id); void dc_update_msg_state (dc_context_t*, uint32_t msg_id, int state); +void dc_update_msg_error (dc_context_t*, uint32_t msg_id, const char* error); int dc_mdn_from_ext (dc_context_t*, uint32_t from_id, const char* rfc724_mid, time_t, uint32_t* ret_chat_id, uint32_t* ret_msg_id); /* returns 1 if an event should be send */ size_t dc_get_real_msg_cnt (dc_context_t*); /* the number of messages assigned to real chat (!=deaddrop, !=trash) */ size_t dc_get_deaddrop_msg_cnt (dc_context_t*); From 9130e12284acb72ed96191d0938ba2cd3285373e Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 11 Jul 2018 16:30:27 +0200 Subject: [PATCH 06/10] give up executing jobs after 3 tries, typically one minute if there is network --- src/dc_job.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/dc_job.c b/src/dc_job.c index 7c62455e..fda30835 100644 --- a/src/dc_job.c +++ b/src/dc_job.c @@ -613,21 +613,30 @@ static void dc_job_perform(dc_context_t* context, int thread) } else if (job.try_again==DC_AT_ONCE || job.try_again==DC_STANDARD_DELAY) { - int tries = dc_param_get_int(job.param, DC_PARAM_TIMES, 0) + 1; - dc_param_set_int(job.param, DC_PARAM_TIMES, tries); + // Define the number of job-retries, each retry may result in 2 tries (for fast network-failure-recover). + // The first job-retries are done asap, the last retry is delayed about a minute. + // Network errors do not count as failed tries. + #define JOB_RETRIES 3 - dc_job_update(context, &job); - dc_log_info(context, 0, "%s-job #%i not succeeded, trying again asap.", THREAD_STR, (int)job.job_id); + int is_online = dc_is_online(context)? 1 : 0; + int tries_while_online = dc_param_get_int(job.param, DC_PARAM_TIMES, 0) + is_online; - // if the job did not succeeded AND this is a smtp-job AND we're online, try over after a mini-delay of one second. - // if we're not online, the ui calls interrupt idle as soon as we're online again. - // if nothing of this happens, after DC_SMTP_IDLE_SEC (60) we try again. - if (thread==DC_SMTP_THREAD - && dc_is_online(context)) - { - pthread_mutex_lock(&context->smtpidle_condmutex); - context->perform_smtp_jobs_needed = DC_JOBS_NEEDED_AVOID_DOS; - pthread_mutex_unlock(&context->smtpidle_condmutex); + if( tries_while_online < JOB_RETRIES ) { + dc_param_set_int(job.param, DC_PARAM_TIMES, tries_while_online); + dc_job_update(context, &job); + dc_log_info(context, 0, "%s-job #%i not succeeded on try #%i.", THREAD_STR, (int)job.job_id, tries_while_online); + + if (thread==DC_SMTP_THREAD && is_online && tries_while_online<(JOB_RETRIES-1)) { + pthread_mutex_lock(&context->smtpidle_condmutex); + context->perform_smtp_jobs_needed = DC_JOBS_NEEDED_AVOID_DOS; + pthread_mutex_unlock(&context->smtpidle_condmutex); + } + } + else { + if (job.msg_id) { + dc_update_msg_error(context, job.msg_id, job.pending_error); + } + dc_job_delete(context, &job); } } else From 64fc7e7e9eef2f74bac56124ce1828d5990a7113 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 11 Jul 2018 17:25:41 +0200 Subject: [PATCH 07/10] foward smtp-error to msg-object if failed some times --- src/dc_job.c | 6 +++--- src/dc_smtp.c | 22 ++++++++++++++-------- src/dc_smtp.h | 2 ++ 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/dc_job.c b/src/dc_job.c index fda30835..e31450e2 100644 --- a/src/dc_job.c +++ b/src/dc_job.c @@ -344,7 +344,7 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_SMTP(dc_context_t* context, dc_job_t* j if (!dc_smtp_send_msg(context->smtp, mimefactory.recipients_addr, mimefactory.out->str, mimefactory.out->len)) { dc_smtp_disconnect(context->smtp); - dc_job_try_again_later(job, DC_AT_ONCE, NULL); /* DC_AT_ONCE is only the _initial_ delay, if the second try failes, the delay gets larger */ + dc_job_try_again_later(job, DC_AT_ONCE, context->smtp->error); goto cleanup; } } @@ -420,7 +420,7 @@ static void dc_job_do_DC_JOB_SEND_MDN(dc_context_t* context, dc_job_t* job) if (!dc_smtp_send_msg(context->smtp, mimefactory.recipients_addr, mimefactory.out->str, mimefactory.out->len)) { dc_smtp_disconnect(context->smtp); - dc_job_try_again_later(job, DC_AT_ONCE, NULL); /* DC_AT_ONCE is only the _initial_ delay, if the second try failes, the delay gets larger */ + dc_job_try_again_later(job, DC_AT_ONCE, NULL); goto cleanup; } @@ -633,7 +633,7 @@ static void dc_job_perform(dc_context_t* context, int thread) } } else { - if (job.msg_id) { + if (job.msg_id && job.action==DC_JOB_SEND_MSG_TO_SMTP) { // in all other cases, the messages is already sent dc_update_msg_error(context, job.msg_id, job.pending_error); } dc_job_delete(context, &job); diff --git a/src/dc_smtp.c b/src/dc_smtp.c index 868b2228..0073b94b 100644 --- a/src/dc_smtp.c +++ b/src/dc_smtp.c @@ -53,13 +53,18 @@ void dc_smtp_unref(dc_smtp_t* smtp) } dc_smtp_disconnect(smtp); free(smtp->from); + free(smtp->error); free(smtp); } -/******************************************************************************* - * Connect/Disconnect - ******************************************************************************/ +static void log_error(dc_smtp_t* smtp, const char* what_failed, int r) +{ + char* error_msg = dc_mprintf("%s: %s: %s", what_failed, mailsmtp_strerror(r), smtp->etpan->response); + dc_log_error_if(&smtp->log_connect_errors, smtp->context, 0, "%s", error_msg); + free(smtp->error); + smtp->error = error_msg; +} int dc_smtp_is_connected(const dc_smtp_t* smtp) @@ -256,11 +261,12 @@ int dc_smtp_send_msg(dc_smtp_t* smtp, const clist* recipients, const char* data_ clistiter* iter = NULL; if (smtp==NULL) { - return 0; + goto cleanup; } if (recipients==NULL || clist_count(recipients)==0 || data_not_terminated==NULL || data_bytes==0) { - return 1; // "null message" send + success = 1; + goto cleanup; // "null message" send } if (smtp->etpan==NULL) { @@ -290,19 +296,19 @@ int dc_smtp_send_msg(dc_smtp_t* smtp, const clist* recipients, const char* data_ if ((r = (smtp->esmtp? mailesmtp_rcpt(smtp->etpan, rcpt, MAILSMTP_DSN_NOTIFY_FAILURE|MAILSMTP_DSN_NOTIFY_DELAY, NULL) : mailsmtp_rcpt(smtp->etpan, rcpt))) != MAILSMTP_NO_ERROR) { - dc_log_error_if(&smtp->log_connect_errors, smtp->context, 0, "Cannot add recipient %s: %s - %s", rcpt, mailsmtp_strerror(r), smtp->etpan->response); + log_error(smtp, "SMTP failed to add recipient", r); goto cleanup; } } // message if ((r = mailsmtp_data(smtp->etpan)) != MAILSMTP_NO_ERROR) { - fprintf(stderr, "mailsmtp_data: %s\n", mailsmtp_strerror(r)); + log_error(smtp, "SMTP failed to set data", r); goto cleanup; } if ((r = mailsmtp_data_message(smtp->etpan, data_not_terminated, data_bytes)) != MAILSMTP_NO_ERROR) { - fprintf(stderr, "mailsmtp_data_message: %s\n", mailsmtp_strerror(r)); + log_error(smtp, "SMTP failed to send message", r); goto cleanup; } diff --git a/src/dc_smtp.h b/src/dc_smtp.h index 2f938a6b..bc9465f6 100644 --- a/src/dc_smtp.h +++ b/src/dc_smtp.h @@ -42,6 +42,8 @@ typedef struct dc_smtp_t int log_usual_error; dc_context_t* context; /* only for logging! */ + + char* error; } dc_smtp_t; dc_smtp_t* dc_smtp_new (dc_context_t*); From 2ef6a427572cc1b846e09ca49e377494f441b49a Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 11 Jul 2018 17:28:22 +0200 Subject: [PATCH 08/10] back to foreign-id for jobs, there is only one case where the pending-error is logged and we catch this by the action-id --- src/dc_job.c | 24 ++++++++++++------------ src/dc_job.h | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/dc_job.c b/src/dc_job.c index e31450e2..8eb38af7 100644 --- a/src/dc_job.c +++ b/src/dc_job.c @@ -90,7 +90,7 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_IMAP(dc_context_t* context, dc_job_t* j } /* create message */ - if (dc_mimefactory_load_msg(&mimefactory, job->msg_id)==0 + if (dc_mimefactory_load_msg(&mimefactory, job->foreign_id)==0 || mimefactory.from_addr==NULL) { goto cleanup; /* should not happen as we've sent the message to the SMTP server before */ } @@ -119,7 +119,7 @@ static void dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(dc_context_t* context, dc_job_t* dc_msg_t* msg = dc_msg_new(); sqlite3_stmt* stmt = NULL; - if (!dc_msg_load_from_db(msg, context, job->msg_id) + if (!dc_msg_load_from_db(msg, context, job->foreign_id) || msg->rfc724_mid==NULL || msg->rfc724_mid[0]==0 /* eg. device messages have no Message-ID */) { goto cleanup; } @@ -226,7 +226,7 @@ static void dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(dc_context_t* context, dc_job_ } } - if (!dc_msg_load_from_db(msg, context, job->msg_id)) { + if (!dc_msg_load_from_db(msg, context, job->foreign_id)) { goto cleanup; } @@ -316,7 +316,7 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_SMTP(dc_context_t* context, dc_job_t* j } /* load message data */ - if (!dc_mimefactory_load_msg(&mimefactory, job->msg_id) + if (!dc_mimefactory_load_msg(&mimefactory, job->foreign_id) || mimefactory.from_addr==NULL) { dc_log_warning(context, 0, "Cannot load data to send, maybe the message is deleted in between."); goto cleanup; /* no redo, no IMAP - there won't be more recipients next time (as the data does not exist, there is no need in calling mark_as_error()) */ @@ -332,13 +332,13 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_SMTP(dc_context_t* context, dc_job_t* j /* send message - it's okay if there are no recipients, this is a group with only OURSELF; we only upload to IMAP in this case */ if (clist_count(mimefactory.recipients_addr) > 0) { if (!dc_mimefactory_render(&mimefactory)) { - dc_update_msg_error(context, job->msg_id, "Empty message."); + dc_update_msg_error(context, job->foreign_id, "Empty message."); goto cleanup; /* no redo, no IMAP - there won't be more recipients next time. */ } /* have we guaranteed encryption but cannot fulfill it for any reason? Do not send the message then.*/ if (dc_param_get_int(mimefactory.msg->param, DC_PARAM_GUARANTEE_E2EE, 0) && !mimefactory.out_encrypted) { - dc_update_msg_error(context, job->msg_id, "End-to-end-encryption unavailable unexpectedly."); + dc_update_msg_error(context, job->foreign_id, "End-to-end-encryption unavailable unexpectedly."); goto cleanup; /* unrecoverable */ } @@ -411,7 +411,7 @@ static void dc_job_do_DC_JOB_SEND_MDN(dc_context_t* context, dc_job_t* job) } } - if (!dc_mimefactory_load_mdn(&mimefactory, job->msg_id) + if (!dc_mimefactory_load_mdn(&mimefactory, job->foreign_id) || !dc_mimefactory_render(&mimefactory)) { goto cleanup; } @@ -459,7 +459,7 @@ static void dc_suspend_smtp_thread(dc_context_t* context, int suspend) ******************************************************************************/ -void dc_job_add(dc_context_t* context, int action, int msg_id, const char* param, int delay_seconds) +void dc_job_add(dc_context_t* context, int action, int foreign_id, const char* param, int delay_seconds) { time_t timestamp = time(NULL); sqlite3_stmt* stmt = NULL; @@ -480,7 +480,7 @@ void dc_job_add(dc_context_t* context, int action, int msg_id, const char* param sqlite3_bind_int64(stmt, 1, timestamp); sqlite3_bind_int (stmt, 2, thread); sqlite3_bind_int (stmt, 3, action); - sqlite3_bind_int (stmt, 4, msg_id); + sqlite3_bind_int (stmt, 4, foreign_id); sqlite3_bind_text (stmt, 5, param? param : "", -1, SQLITE_STATIC); sqlite3_bind_int64(stmt, 6, delay_seconds>0? (timestamp+delay_seconds) : 0); sqlite3_step(stmt); @@ -566,7 +566,7 @@ static void dc_job_perform(dc_context_t* context, int thread) { job.job_id = sqlite3_column_int (select_stmt, 0); job.action = sqlite3_column_int (select_stmt, 1); - job.msg_id = sqlite3_column_int (select_stmt, 2); + job.foreign_id = sqlite3_column_int (select_stmt, 2); dc_param_set_packed(job.param, (char*)sqlite3_column_text(select_stmt, 3)); dc_log_info(context, 0, "%s-job #%i, action %i started...", THREAD_STR, (int)job.job_id, (int)job.action); @@ -633,8 +633,8 @@ static void dc_job_perform(dc_context_t* context, int thread) } } else { - if (job.msg_id && job.action==DC_JOB_SEND_MSG_TO_SMTP) { // in all other cases, the messages is already sent - dc_update_msg_error(context, job.msg_id, job.pending_error); + if (job.foreign_id && job.action==DC_JOB_SEND_MSG_TO_SMTP) { // in all other cases, the messages is already sent + dc_update_msg_error(context, job.foreign_id, job.pending_error); } dc_job_delete(context, &job); } diff --git a/src/dc_job.h b/src/dc_job.h index 4abbfd78..3642f7c2 100644 --- a/src/dc_job.h +++ b/src/dc_job.h @@ -67,7 +67,7 @@ typedef struct dc_job_t uint32_t job_id; int action; - uint32_t msg_id; + uint32_t foreign_id; dc_param_t* param; int try_again; From 7d942188d9e300d75a6094ee549a101ce22a5e8b Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 11 Jul 2018 17:31:22 +0200 Subject: [PATCH 09/10] simplify condition to flush the pending error --- src/dc_job.c | 2 +- src/dc_job.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dc_job.c b/src/dc_job.c index 8eb38af7..c3ea8672 100644 --- a/src/dc_job.c +++ b/src/dc_job.c @@ -633,7 +633,7 @@ static void dc_job_perform(dc_context_t* context, int thread) } } else { - if (job.foreign_id && job.action==DC_JOB_SEND_MSG_TO_SMTP) { // in all other cases, the messages is already sent + if (job.action==DC_JOB_SEND_MSG_TO_SMTP) { // in all other cases, the messages is already sent dc_update_msg_error(context, job.foreign_id, job.pending_error); } dc_job_delete(context, &job); diff --git a/src/dc_job.h b/src/dc_job.h index 3642f7c2..6183502f 100644 --- a/src/dc_job.h +++ b/src/dc_job.h @@ -75,7 +75,7 @@ typedef struct dc_job_t } dc_job_t; -void dc_job_add (dc_context_t*, int action, int msg_id, const char* param, int delay); +void dc_job_add (dc_context_t*, int action, int foreign_id, const char* param, int delay); void dc_job_kill_actions (dc_context_t*, int action1, int action2); /* delete all pending jobs with the given actions */ #define DC_DONT_TRY_AGAIN 0 From 62c8ad3a2adad211f64396ea8b5702bc7744fec8 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 11 Jul 2018 23:58:15 +0200 Subject: [PATCH 10/10] add explicit event for failed messages --- cmdline/cmdline.c | 4 ++-- cmdline/stress.c | 2 +- src/dc_job.c | 6 +++--- src/dc_msg.c | 12 ++++++------ src/dc_msg.h | 2 +- src/dc_smtp.c | 2 +- src/deltachat.h | 18 ++++++++++++++---- src/mrmailbox.h | 2 +- 8 files changed, 29 insertions(+), 19 deletions(-) diff --git a/cmdline/cmdline.c b/cmdline/cmdline.c index 7f9c8cac..837168fa 100644 --- a/cmdline/cmdline.c +++ b/cmdline/cmdline.c @@ -287,7 +287,7 @@ static void log_msglist(dc_context_t* context, dc_array_t* msglist) case DC_STATE_OUT_PENDING: statestr = " o"; break; case DC_STATE_OUT_DELIVERED: statestr = " √"; break; case DC_STATE_OUT_MDN_RCVD: statestr = " √√"; break; - case DC_STATE_OUT_ERROR: statestr = " ERR"; break; + case DC_STATE_OUT_FAILED: statestr = " !!"; break; } char* temp2 = dc_timestamp_to_str(dc_msg_get_timestamp(msg)); @@ -701,7 +701,7 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline) case DC_STATE_OUT_PENDING: statestr = " o"; break; case DC_STATE_OUT_DELIVERED: statestr = " √"; break; case DC_STATE_OUT_MDN_RCVD: statestr = " √√"; break; - case DC_STATE_OUT_ERROR: statestr = " ERR"; break; + case DC_STATE_OUT_FAILED: statestr = " !!"; break; } char* timestr = dc_timestamp_to_str(dc_lot_get_timestamp(lot)); diff --git a/cmdline/stress.c b/cmdline/stress.c index 75140f4f..054a5b26 100644 --- a/cmdline/stress.c +++ b/cmdline/stress.c @@ -363,7 +363,7 @@ void stress_functions(dc_context_t* context) assert( strcmp("noticed=" DC_STRINGIFY(DC_STATE_IN_NOTICED), "noticed=13")==0 ); assert( strcmp("seen=" DC_STRINGIFY(DC_STATE_IN_SEEN), "seen=16")==0 ); assert( strcmp("pending=" DC_STRINGIFY(DC_STATE_OUT_PENDING), "pending=20")==0 ); - assert( strcmp("error=" DC_STRINGIFY(DC_STATE_OUT_ERROR), "error=24")==0 ); + assert( strcmp("failed=" DC_STRINGIFY(DC_STATE_OUT_FAILED), "failed=24")==0 ); assert( strcmp("delivered=" DC_STRINGIFY(DC_STATE_OUT_DELIVERED), "delivered=26")==0 ); assert( strcmp("mdn_rcvd=" DC_STRINGIFY(DC_STATE_OUT_MDN_RCVD), "mdn_rcvd=28")==0 ); diff --git a/src/dc_job.c b/src/dc_job.c index c3ea8672..079ae57d 100644 --- a/src/dc_job.c +++ b/src/dc_job.c @@ -332,13 +332,13 @@ static void dc_job_do_DC_JOB_SEND_MSG_TO_SMTP(dc_context_t* context, dc_job_t* j /* send message - it's okay if there are no recipients, this is a group with only OURSELF; we only upload to IMAP in this case */ if (clist_count(mimefactory.recipients_addr) > 0) { if (!dc_mimefactory_render(&mimefactory)) { - dc_update_msg_error(context, job->foreign_id, "Empty message."); + dc_set_msg_failed(context, job->foreign_id, "Empty message."); goto cleanup; /* no redo, no IMAP - there won't be more recipients next time. */ } /* have we guaranteed encryption but cannot fulfill it for any reason? Do not send the message then.*/ if (dc_param_get_int(mimefactory.msg->param, DC_PARAM_GUARANTEE_E2EE, 0) && !mimefactory.out_encrypted) { - dc_update_msg_error(context, job->foreign_id, "End-to-end-encryption unavailable unexpectedly."); + dc_set_msg_failed(context, job->foreign_id, "End-to-end-encryption unavailable unexpectedly."); goto cleanup; /* unrecoverable */ } @@ -634,7 +634,7 @@ static void dc_job_perform(dc_context_t* context, int thread) } else { if (job.action==DC_JOB_SEND_MSG_TO_SMTP) { // in all other cases, the messages is already sent - dc_update_msg_error(context, job.foreign_id, job.pending_error); + dc_set_msg_failed(context, job.foreign_id, job.pending_error); } dc_job_delete(context, &job); } diff --git a/src/dc_msg.c b/src/dc_msg.c index 8b0a197e..e55b3f1b 100644 --- a/src/dc_msg.c +++ b/src/dc_msg.c @@ -193,8 +193,8 @@ int dc_msg_get_type(const dc_msg_t* msg) * Outgoing message states: * - DC_STATE_OUT_PENDING (20) - The user has send the "send" button but the * message is not yet sent and is pending in some way. Maybe we're offline (no checkmark). - * - DC_STATE_OUT_ERROR (24) - _Unrecoverable_ error (_recoverable_ errors result in pending messages) - * - DC_STATE_OUT_DELIVERED (26) - Outgoing message successfully delivered to server (one checkmark). Note, that already delivered messages may get into the state DC_STATE_OUT_ERROR if we get such a hint from the server. + * - DC_STATE_OUT_FAILED (24) - _Unrecoverable_ error (_recoverable_ errors result in pending messages), you'll receive the event #DC_EVENT_MSG_FAILED. + * - DC_STATE_OUT_DELIVERED (26) - Outgoing message successfully delivered to server (one checkmark). Note, that already delivered messages may get into the state DC_STATE_OUT_FAILED if we get such a hint from the server. * If a sent message changes to this state, you'll receive the event #DC_EVENT_MSG_DELIVERED. * - DC_STATE_OUT_MDN_RCVD (28) - Outgoing message read by the recipient (two checkmarks; this requires goodwill on the receiver's side) * If a sent message changes to this state, you'll receive the event #DC_EVENT_MSG_READ. @@ -1158,7 +1158,7 @@ void dc_update_msg_state(dc_context_t* context, uint32_t msg_id, int state) } -void dc_update_msg_error(dc_context_t* context, uint32_t msg_id, const char* error) +void dc_set_msg_failed(dc_context_t* context, uint32_t msg_id, const char* error) { dc_msg_t* msg = dc_msg_new(); sqlite3_stmt* stmt = NULL; @@ -1167,7 +1167,7 @@ void dc_update_msg_error(dc_context_t* context, uint32_t msg_id, const char* err goto cleanup; } - msg->state = DC_STATE_OUT_ERROR; + msg->state = DC_STATE_OUT_FAILED; if (error) { dc_param_set(msg->param, DC_PARAM_ERROR, error); dc_log_error(context, 0, "%s", error); @@ -1180,7 +1180,7 @@ void dc_update_msg_error(dc_context_t* context, uint32_t msg_id, const char* err sqlite3_bind_int (stmt, 3, msg_id); sqlite3_step(stmt); - context->cb(context, DC_EVENT_MSGS_CHANGED, msg->chat_id, 0); + context->cb(context, DC_EVENT_MSG_FAILED, msg->chat_id, msg_id); cleanup: sqlite3_finalize(stmt); @@ -1436,7 +1436,7 @@ char* dc_get_msg_info(dc_context_t* context, uint32_t msg_id) case DC_STATE_IN_NOTICED: p = dc_strdup("Noticed"); break; case DC_STATE_IN_SEEN: p = dc_strdup("Seen"); break; case DC_STATE_OUT_DELIVERED: p = dc_strdup("Delivered"); break; - case DC_STATE_OUT_ERROR: p = dc_strdup("Error"); break; + case DC_STATE_OUT_FAILED: p = dc_strdup("Failed"); break; case DC_STATE_OUT_MDN_RCVD: p = dc_strdup("Read"); break; case DC_STATE_OUT_PENDING: p = dc_strdup("Pending"); break; default: p = dc_mprintf("%i", msg->state); break; diff --git a/src/dc_msg.h b/src/dc_msg.h index 75144a86..6789eacd 100644 --- a/src/dc_msg.h +++ b/src/dc_msg.h @@ -110,7 +110,7 @@ The value is also used for CC:-summaries */ // Context functions to work with messages void dc_update_msg_chat_id (dc_context_t*, uint32_t msg_id, uint32_t chat_id); void dc_update_msg_state (dc_context_t*, uint32_t msg_id, int state); -void dc_update_msg_error (dc_context_t*, uint32_t msg_id, const char* error); +void dc_set_msg_failed (dc_context_t*, uint32_t msg_id, const char* error); int dc_mdn_from_ext (dc_context_t*, uint32_t from_id, const char* rfc724_mid, time_t, uint32_t* ret_chat_id, uint32_t* ret_msg_id); /* returns 1 if an event should be send */ size_t dc_get_real_msg_cnt (dc_context_t*); /* the number of messages assigned to real chat (!=deaddrop, !=trash) */ size_t dc_get_deaddrop_msg_cnt (dc_context_t*); diff --git a/src/dc_smtp.c b/src/dc_smtp.c index 0073b94b..0f26e4da 100644 --- a/src/dc_smtp.c +++ b/src/dc_smtp.c @@ -61,7 +61,7 @@ void dc_smtp_unref(dc_smtp_t* smtp) static void log_error(dc_smtp_t* smtp, const char* what_failed, int r) { char* error_msg = dc_mprintf("%s: %s: %s", what_failed, mailsmtp_strerror(r), smtp->etpan->response); - dc_log_error_if(&smtp->log_connect_errors, smtp->context, 0, "%s", error_msg); + dc_log_warning(smtp->context, 0, "%s", error_msg); free(smtp->error); smtp->error = error_msg; } diff --git a/src/deltachat.h b/src/deltachat.h index 04e1e7e0..5eef5239 100644 --- a/src/deltachat.h +++ b/src/deltachat.h @@ -465,7 +465,7 @@ typedef struct _dc_msg dc_msg_t; #define DC_STATE_IN_NOTICED 13 #define DC_STATE_IN_SEEN 16 #define DC_STATE_OUT_PENDING 20 -#define DC_STATE_OUT_ERROR 24 +#define DC_STATE_OUT_FAILED 24 #define DC_STATE_OUT_DELIVERED 26 // to check if a mail was sent, use dc_msg_is_sent() #define DC_STATE_OUT_MDN_RCVD 28 @@ -621,7 +621,6 @@ time_t dc_lot_get_timestamp (const dc_lot_t*); * Messages or chats changed. One or more messages or chats changed for various * reasons in the database: * - Messages sent, received or removed - * - A message could not be sent (see dc_msg_get_state()/DC_STATE_OUT_ERROR) * - Chats created, deleted or archived * - A draft has been set * @@ -646,7 +645,7 @@ time_t dc_lot_get_timestamp (const dc_lot_t*); /** - * A single message is sent successfully; state changed from DC_STATE_OUT_PENDING to + * A single message is sent successfully. State changed from DC_STATE_OUT_PENDING to * DC_STATE_OUT_DELIVERED, see dc_msg_get_state(). * * @param data1 chat_id @@ -657,7 +656,18 @@ time_t dc_lot_get_timestamp (const dc_lot_t*); /** - * A single message is read by the receiver; state changed from DC_STATE_OUT_DELIVERED to + * A single message could not be sent. State changed from DC_STATE_OUT_PENDING or DC_STATE_OUT_DELIVERED to + * DC_STATE_OUT_FAILED, see dc_msg_get_state(). + * + * @param data1 chat_id + * @param data2 msg_id + * @return 0 + */ +#define DC_EVENT_MSG_FAILED 2012 + + +/** + * A single message is read by the receiver. State changed from DC_STATE_OUT_DELIVERED to * DC_STATE_OUT_MDN_RCVD, see dc_msg_get_state(). * * @param data1 chat_id diff --git a/src/mrmailbox.h b/src/mrmailbox.h index fcd8e477..556958f1 100644 --- a/src/mrmailbox.h +++ b/src/mrmailbox.h @@ -177,7 +177,7 @@ extern "C" { #define MR_STATE_IN_NOTICED DC_STATE_IN_NOTICED #define MR_STATE_IN_SEEN DC_STATE_IN_SEEN #define MR_STATE_OUT_PENDING DC_STATE_OUT_PENDING -#define MR_STATE_OUT_ERROR DC_STATE_OUT_ERROR +#define MR_STATE_OUT_ERROR DC_STATE_OUT_FAILED #define MR_STATE_OUT_DELIVERED DC_STATE_OUT_DELIVERED #define MR_STATE_OUT_MDN_RCVD DC_STATE_OUT_MDN_RCVD #define mrmsg_new dc_msg_new