1
0
Fork 0
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:
Björn Petersen 2018-07-11 23:59:32 +02:00 committed by GitHub
commit a75dca7f8e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 151 additions and 80 deletions

View file

@ -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));

View file

@ -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 );

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}

View file

@ -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*);

View file

@ -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 */

View file

@ -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;
}

View file

@ -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*);

View file

@ -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

View file

@ -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