mirror of
https://github.com/deltachat/deltachat-core.git
synced 2025-10-06 03:50:08 +02:00
Merge pull request #209 from deltachat/rework-failed-jobs
Rework failed jobs
This commit is contained in:
commit
a75dca7f8e
11 changed files with 151 additions and 80 deletions
|
@ -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));
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
124
src/dc_job.c
124
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:
|
||||
|
@ -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;
|
||||
|
@ -321,7 +310,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,28 +325,26 @@ 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;
|
||||
}
|
||||
|
||||
/* 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_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) {
|
||||
mark_as_error(context, mimefactory.msg);
|
||||
dc_log_error(context, 0, "End-to-end-encryption unavailable unexpectedly.");
|
||||
dc_set_msg_failed(context, job->foreign_id, "End-to-end-encryption unavailable unexpectedly.");
|
||||
goto cleanup; /* unrecoverable */
|
||||
}
|
||||
|
||||
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, context->smtp->error);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
@ -419,7 +406,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 +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); /* 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;
|
||||
}
|
||||
|
||||
|
@ -508,13 +495,37 @@ void dc_job_add(dc_context_t* context, int action, int foreign_id, const char* p
|
|||
}
|
||||
|
||||
|
||||
void dc_job_try_again_later(dc_job_t* job, int try_again)
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
job->try_again = try_again;
|
||||
|
||||
free(job->pending_error);
|
||||
job->pending_error = dc_strdup_keep_null(pending_error);
|
||||
}
|
||||
|
||||
|
||||
|
@ -553,9 +564,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.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);
|
||||
|
@ -602,40 +613,41 @@ 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
|
||||
|
||||
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_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.action==DC_JOB_SEND_MSG_TO_SMTP) { // in all other cases, the messages is already sent
|
||||
dc_set_msg_failed(context, job.foreign_id, job.pending_error);
|
||||
}
|
||||
dc_job_delete(context, &job);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
dc_param_unref(job.param);
|
||||
free(job.pending_error);
|
||||
sqlite3_finalize(select_stmt);
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,9 @@ typedef struct dc_job_t
|
|||
int action;
|
||||
uint32_t foreign_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
|
||||
|
|
51
src/dc_msg.c
51
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,6 +1158,36 @@ void dc_update_msg_state(dc_context_t* context, uint32_t msg_id, int state)
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
if (!dc_msg_load_from_db(msg, context, msg_id)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
msg->state = DC_STATE_OUT_FAILED;
|
||||
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_MSG_FAILED, msg->chat_id, msg_id);
|
||||
|
||||
cleanup:
|
||||
sqlite3_finalize(stmt);
|
||||
dc_msg_unref(msg);
|
||||
}
|
||||
|
||||
|
||||
size_t dc_get_real_msg_cnt(dc_context_t* context)
|
||||
{
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
|
@ -1406,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;
|
||||
|
@ -1431,6 +1461,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 +1475,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 +1495,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);
|
||||
}
|
||||
|
|
|
@ -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_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*);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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_warning(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue