mirror of
https://github.com/chatmail/core.git
synced 2026-05-22 16:26:31 +03:00
rustify job send
This commit is contained in:
@@ -122,6 +122,15 @@ pub const DC_CONTACT_ID_LAST_SPECIAL: usize = 9;
|
|||||||
|
|
||||||
pub const DC_CREATE_MVBOX: usize = 1;
|
pub const DC_CREATE_MVBOX: usize = 1;
|
||||||
|
|
||||||
|
#[repr(i32)]
|
||||||
|
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, ToSql, FromSql)]
|
||||||
|
pub enum Delay {
|
||||||
|
DoNotTryAgain = 0,
|
||||||
|
AtOnce = -1,
|
||||||
|
Standard = 3,
|
||||||
|
IncreationPoll = 2,
|
||||||
|
}
|
||||||
|
|
||||||
// Flags for configuring IMAP and SMTP servers.
|
// Flags for configuring IMAP and SMTP servers.
|
||||||
// These flags are optional
|
// These flags are optional
|
||||||
// and may be set together with the username, password etc.
|
// and may be set together with the username, password etc.
|
||||||
|
|||||||
134
src/imap.rs
134
src/imap.rs
@@ -12,14 +12,19 @@ use crate::dc_loginparam::*;
|
|||||||
use crate::dc_tools::CStringExt;
|
use crate::dc_tools::CStringExt;
|
||||||
use crate::oauth2::dc_get_oauth2_access_token;
|
use crate::oauth2::dc_get_oauth2_access_token;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
use deltachat_derive::*;
|
||||||
|
|
||||||
const DC_IMAP_SEEN: usize = 0x0001;
|
const DC_IMAP_SEEN: usize = 0x0001;
|
||||||
const DC_REGENERATE: usize = 0x01;
|
const DC_REGENERATE: usize = 0x01;
|
||||||
|
|
||||||
const DC_SUCCESS: usize = 3;
|
#[repr(usize)]
|
||||||
const DC_ALREADY_DONE: usize = 2;
|
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, ToSql, FromSql)]
|
||||||
const DC_RETRY_LATER: usize = 1;
|
pub enum ImapResult {
|
||||||
const DC_FAILED: usize = 0;
|
Success = 3,
|
||||||
|
AlreadyDone = 2,
|
||||||
|
RetryLater = 1,
|
||||||
|
Failed = 0,
|
||||||
|
}
|
||||||
|
|
||||||
const PREFETCH_FLAGS: &str = "(UID ENVELOPE)";
|
const PREFETCH_FLAGS: &str = "(UID ENVELOPE)";
|
||||||
const BODY_FLAGS: &str = "(FLAGS BODY.PEEK[])";
|
const BODY_FLAGS: &str = "(FLAGS BODY.PEEK[])";
|
||||||
@@ -1164,12 +1169,12 @@ impl Imap {
|
|||||||
uid: u32,
|
uid: u32,
|
||||||
dest_folder: S2,
|
dest_folder: S2,
|
||||||
dest_uid: &mut u32,
|
dest_uid: &mut u32,
|
||||||
) -> usize {
|
) -> ImapResult {
|
||||||
let mut res = DC_RETRY_LATER;
|
let mut res = ImapResult::RetryLater;
|
||||||
let set = format!("{}", uid);
|
let set = format!("{}", uid);
|
||||||
|
|
||||||
if uid == 0 {
|
if uid == 0 {
|
||||||
res = DC_FAILED;
|
res = ImapResult::Failed;
|
||||||
} else if folder.as_ref() == dest_folder.as_ref() {
|
} else if folder.as_ref() == dest_folder.as_ref() {
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
@@ -1180,7 +1185,7 @@ impl Imap {
|
|||||||
dest_folder.as_ref()
|
dest_folder.as_ref()
|
||||||
);
|
);
|
||||||
|
|
||||||
res = DC_ALREADY_DONE;
|
res = ImapResult::AlreadyDone;
|
||||||
} else {
|
} else {
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
@@ -1202,7 +1207,7 @@ impl Imap {
|
|||||||
let moved = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
let moved = if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||||
match session.uid_mv(&set, &dest_folder) {
|
match session.uid_mv(&set, &dest_folder) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
res = DC_SUCCESS;
|
res = ImapResult::Success;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -1239,41 +1244,38 @@ impl Imap {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if copied {
|
if copied {
|
||||||
if self.add_flag(context, uid, "\\Deleted") == 0 {
|
if !self.add_flag(context, uid, "\\Deleted") {
|
||||||
warn!(context, 0, "Cannot mark message as \"Deleted\".",);
|
warn!(context, 0, "Cannot mark message as \"Deleted\".",);
|
||||||
}
|
}
|
||||||
self.config.write().unwrap().selected_folder_needs_expunge = true;
|
self.config.write().unwrap().selected_folder_needs_expunge = true;
|
||||||
res = DC_SUCCESS;
|
res = ImapResult::Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if res == DC_SUCCESS {
|
if res == ImapResult::Success {
|
||||||
// TODO: is this correct?
|
// TODO: is this correct?
|
||||||
*dest_uid = uid;
|
*dest_uid = uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if res == DC_RETRY_LATER {
|
if res == ImapResult::RetryLater && !self.should_reconnect() {
|
||||||
if self.should_reconnect() {
|
res = ImapResult::Failed;
|
||||||
DC_RETRY_LATER
|
|
||||||
} else {
|
|
||||||
DC_FAILED
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_flag<S: AsRef<str>>(&self, context: &Context, server_uid: u32, flag: S) -> usize {
|
fn add_flag<S: AsRef<str>>(&self, context: &Context, server_uid: u32, flag: S) -> bool {
|
||||||
if server_uid == 0 {
|
if server_uid == 0 {
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
if let Some(ref mut session) = &mut *self.session.lock().unwrap() {
|
||||||
let set = format!("{}", server_uid);
|
let set = format!("{}", server_uid);
|
||||||
let query = format!("+FLAGS ({})", flag.as_ref());
|
let query = format!("+FLAGS ({})", flag.as_ref());
|
||||||
match session.uid_store(&set, &query) {
|
match session.uid_store(&set, &query) {
|
||||||
Ok(_) => {}
|
Ok(_) => {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(
|
warn!(
|
||||||
context,
|
context,
|
||||||
@@ -1282,22 +1284,20 @@ impl Imap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// All non-connection states are treated as success - the mail may
|
// All non-connection states are treated as success - the mail may
|
||||||
// already be deleted or moved away on the server.
|
// already be deleted or moved away on the server.
|
||||||
if self.should_reconnect() {
|
if !self.should_reconnect() {
|
||||||
0
|
true
|
||||||
} else {
|
} else {
|
||||||
1
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_seen<S: AsRef<str>>(&self, context: &Context, folder: S, uid: u32) -> usize {
|
pub fn set_seen<S: AsRef<str>>(&self, context: &Context, folder: S, uid: u32) -> ImapResult {
|
||||||
let mut res = DC_RETRY_LATER;
|
|
||||||
|
|
||||||
if uid == 0 {
|
if uid == 0 {
|
||||||
res = DC_FAILED
|
return ImapResult::Failed;
|
||||||
} else if self.is_connected() {
|
}
|
||||||
|
if self.is_connected() {
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
0,
|
0,
|
||||||
@@ -1313,32 +1313,29 @@ impl Imap {
|
|||||||
"Cannot select folder {} for setting SEEN flag.",
|
"Cannot select folder {} for setting SEEN flag.",
|
||||||
folder.as_ref(),
|
folder.as_ref(),
|
||||||
);
|
);
|
||||||
} else if self.add_flag(context, uid, "\\Seen") == 0 {
|
} else if !self.add_flag(context, uid, "\\Seen") {
|
||||||
warn!(context, 0, "Cannot mark message as seen.",);
|
warn!(context, 0, "Cannot mark message as seen.",);
|
||||||
} else {
|
} else {
|
||||||
res = DC_SUCCESS
|
return ImapResult::Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if res == DC_RETRY_LATER {
|
if self.should_reconnect() {
|
||||||
if self.should_reconnect() {
|
ImapResult::RetryLater
|
||||||
DC_RETRY_LATER
|
|
||||||
} else {
|
|
||||||
DC_FAILED
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
res
|
ImapResult::Failed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_mdnsent<S: AsRef<str>>(&self, context: &Context, folder: S, uid: u32) -> usize {
|
pub fn set_mdnsent<S: AsRef<str>>(&self, context: &Context, folder: S, uid: u32) -> ImapResult {
|
||||||
// returns 0=job should be retried later, 1=job done, 2=job done and flag just set
|
|
||||||
let mut res = DC_RETRY_LATER;
|
|
||||||
let set = format!("{}", uid);
|
let set = format!("{}", uid);
|
||||||
|
|
||||||
if uid == 0 {
|
if uid == 0 {
|
||||||
res = DC_FAILED;
|
return ImapResult::Failed;
|
||||||
} else if self.is_connected() {
|
}
|
||||||
|
|
||||||
|
let mut res = ImapResult::RetryLater;
|
||||||
|
if self.is_connected() {
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
0,
|
0,
|
||||||
@@ -1409,21 +1406,22 @@ impl Imap {
|
|||||||
.unwrap_or_else(|| false);
|
.unwrap_or_else(|| false);
|
||||||
|
|
||||||
res = if flag_set {
|
res = if flag_set {
|
||||||
DC_ALREADY_DONE
|
ImapResult::AlreadyDone
|
||||||
} else if self.add_flag(context, uid, "$MDNSent") != 0 {
|
} else if self.add_flag(context, uid, "$MDNSent") {
|
||||||
DC_SUCCESS
|
ImapResult::Success
|
||||||
} else {
|
} else {
|
||||||
|
assert!(res == ImapResult::RetryLater);
|
||||||
res
|
res
|
||||||
};
|
};
|
||||||
|
|
||||||
if res == DC_SUCCESS {
|
if res == ImapResult::Success {
|
||||||
info!(context, 0, "$MDNSent just set and MDN will be sent.");
|
info!(context, 0, "$MDNSent just set and MDN will be sent.");
|
||||||
} else {
|
} else {
|
||||||
info!(context, 0, "$MDNSent already set and MDN already sent.");
|
info!(context, 0, "$MDNSent already set and MDN already sent.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res = DC_SUCCESS;
|
res = ImapResult::Success;
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
0, "Cannot store $MDNSent flags, risk sending duplicate MDN.",
|
0, "Cannot store $MDNSent flags, risk sending duplicate MDN.",
|
||||||
@@ -1432,15 +1430,10 @@ impl Imap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if res == DC_RETRY_LATER {
|
if res == ImapResult::RetryLater && !self.should_reconnect() {
|
||||||
if self.should_reconnect() {
|
res = ImapResult::Failed
|
||||||
DC_RETRY_LATER
|
|
||||||
} else {
|
|
||||||
DC_FAILED
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
// only returns 0 on connection problems; we should try later again in this case *
|
// only returns 0 on connection problems; we should try later again in this case *
|
||||||
@@ -1450,11 +1443,11 @@ impl Imap {
|
|||||||
message_id: S1,
|
message_id: S1,
|
||||||
folder: S2,
|
folder: S2,
|
||||||
server_uid: &mut u32,
|
server_uid: &mut u32,
|
||||||
) -> usize {
|
) -> ImapResult {
|
||||||
let mut success = false;
|
|
||||||
if *server_uid == 0 {
|
if *server_uid == 0 {
|
||||||
success = true
|
return ImapResult::Success;
|
||||||
} else {
|
}
|
||||||
|
{
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
0,
|
0,
|
||||||
@@ -1513,20 +1506,21 @@ impl Imap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mark the message for deletion
|
// mark the message for deletion
|
||||||
if self.add_flag(context, *server_uid, "\\Deleted") == 0 {
|
if !self.add_flag(context, *server_uid, "\\Deleted") {
|
||||||
warn!(context, 0, "Cannot mark message as \"Deleted\".");
|
warn!(context, 0, "Cannot mark message as \"Deleted\".");
|
||||||
} else {
|
} else {
|
||||||
self.config.write().unwrap().selected_folder_needs_expunge = true;
|
self.config.write().unwrap().selected_folder_needs_expunge = true;
|
||||||
success = true
|
return ImapResult::Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// deletion was not successful or message was deleted already
|
||||||
if success {
|
return if self.is_connected() {
|
||||||
1
|
ImapResult::Failed
|
||||||
} else {
|
} else {
|
||||||
self.is_connected() as usize
|
// we are not connected so the caller may retry
|
||||||
}
|
ImapResult::RetryLater
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure_folders(&self, context: &Context, flags: libc::c_int) {
|
pub fn configure_folders(&self, context: &Context, flags: libc::c_int) {
|
||||||
|
|||||||
397
src/job.rs
397
src/job.rs
@@ -1,5 +1,4 @@
|
|||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::ptr;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use deltachat_derive::{FromSql, ToSql};
|
use deltachat_derive::{FromSql, ToSql};
|
||||||
@@ -82,7 +81,7 @@ pub struct Job {
|
|||||||
pub added_timestamp: i64,
|
pub added_timestamp: i64,
|
||||||
pub tries: i32,
|
pub tries: i32,
|
||||||
pub param: Params,
|
pub param: Params,
|
||||||
pub try_again: i32,
|
pub try_again: Delay,
|
||||||
pub pending_error: Option<String>,
|
pub pending_error: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,121 +110,91 @@ impl Job {
|
|||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn do_DC_JOB_SEND(&mut self, context: &Context) {
|
fn do_DC_JOB_SEND(&mut self, context: &Context) {
|
||||||
let ok_to_continue;
|
|
||||||
let mut filename = ptr::null_mut();
|
|
||||||
let mut buf = ptr::null_mut();
|
|
||||||
let mut buf_bytes = 0;
|
|
||||||
|
|
||||||
/* connect to SMTP server, if not yet done */
|
/* connect to SMTP server, if not yet done */
|
||||||
if !context.smtp.lock().unwrap().is_connected() {
|
if !context.smtp.lock().unwrap().is_connected() {
|
||||||
let loginparam = dc_loginparam_read(context, &context.sql, "configured_");
|
let loginparam = dc_loginparam_read(context, &context.sql, "configured_");
|
||||||
let connected = context.smtp.lock().unwrap().connect(context, &loginparam);
|
let connected = context.smtp.lock().unwrap().connect(context, &loginparam);
|
||||||
|
|
||||||
if !connected {
|
if !connected {
|
||||||
self.try_again_later(3i32, None);
|
self.try_again_later(Delay::Standard, None);
|
||||||
ok_to_continue = false;
|
return;
|
||||||
} else {
|
|
||||||
ok_to_continue = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ok_to_continue = true;
|
|
||||||
}
|
}
|
||||||
if ok_to_continue {
|
let filename = self.param.get(Param::File).unwrap_or_default();
|
||||||
let filename_s = self.param.get(Param::File).unwrap_or_default();
|
let body = match dc_read_file_safe(context, filename) {
|
||||||
filename = unsafe { filename_s.strdup() };
|
Some(bytes) => bytes,
|
||||||
if unsafe { strlen(filename) } == 0 {
|
None => {
|
||||||
warn!(context, 0, "Missing file name for job {}", self.job_id,);
|
warn!(context, 0, "job {} error", self.job_id);
|
||||||
} else if 0 != unsafe { dc_read_file(context, filename, &mut buf, &mut buf_bytes) } {
|
return;
|
||||||
let recipients = self.param.get(Param::Recipients);
|
}
|
||||||
if recipients.is_none() {
|
};
|
||||||
warn!(context, 0, "Missing recipients for job {}", self.job_id,);
|
|
||||||
} else {
|
|
||||||
let recipients_list = recipients
|
|
||||||
.unwrap()
|
|
||||||
.split("\x1e")
|
|
||||||
.filter_map(|addr| match lettre::EmailAddress::new(addr.to_string()) {
|
|
||||||
Ok(addr) => Some(addr),
|
|
||||||
Err(err) => {
|
|
||||||
eprintln!("WARNING: invalid recipient: {} {:?}", addr, err);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
/* if there is a msg-id and it does not exist in the db, cancel sending.
|
|
||||||
this happends if dc_delete_msgs() was called
|
|
||||||
before the generated mime was sent out */
|
|
||||||
let ok_to_continue1;
|
|
||||||
if 0 != self.foreign_id {
|
|
||||||
if 0 == unsafe { dc_msg_exists(context, self.foreign_id) } {
|
|
||||||
warn!(
|
|
||||||
context,
|
|
||||||
0,
|
|
||||||
"Message {} for job {} does not exist",
|
|
||||||
self.foreign_id,
|
|
||||||
self.job_id,
|
|
||||||
);
|
|
||||||
ok_to_continue1 = false;
|
|
||||||
} else {
|
|
||||||
ok_to_continue1 = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ok_to_continue1 = true;
|
|
||||||
}
|
|
||||||
if ok_to_continue1 {
|
|
||||||
/* send message */
|
|
||||||
let body = unsafe {
|
|
||||||
std::slice::from_raw_parts(buf as *const u8, buf_bytes).to_vec()
|
|
||||||
};
|
|
||||||
|
|
||||||
// hold the smtp lock during sending of a job and
|
let recipients = self.param.get(Param::Recipients);
|
||||||
// its ok/error response processing. Note that if a message
|
if recipients.is_none() {
|
||||||
// was sent we need to mark it in the database as we
|
error!(context, 0, "Missing recipients for job {}", self.job_id,);
|
||||||
// otherwise might send it twice.
|
return;
|
||||||
let mut sock = context.smtp.lock().unwrap();
|
}
|
||||||
if 0 == sock.send(context, recipients_list, body) {
|
let recipients_list = recipients
|
||||||
sock.disconnect();
|
.unwrap()
|
||||||
self.try_again_later(-1i32, Some(as_str(sock.error)));
|
.split("\x1e")
|
||||||
} else {
|
.filter_map(|addr| match lettre::EmailAddress::new(addr.to_string()) {
|
||||||
dc_delete_file(context, filename_s);
|
Ok(addr) => Some(addr),
|
||||||
if 0 != self.foreign_id {
|
Err(err) => {
|
||||||
dc_update_msg_state(
|
eprintln!("WARNING: invalid recipient: {} {:?}", addr, err);
|
||||||
context,
|
None
|
||||||
self.foreign_id,
|
|
||||||
MessageState::OutDelivered,
|
|
||||||
);
|
|
||||||
let chat_id: i32 = context
|
|
||||||
.sql
|
|
||||||
.query_row_col(
|
|
||||||
context,
|
|
||||||
"SELECT chat_id FROM msgs WHERE id=?",
|
|
||||||
params![self.foreign_id as i32],
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
.unwrap_or_default();
|
|
||||||
context.call_cb(
|
|
||||||
Event::MSG_DELIVERED,
|
|
||||||
chat_id as uintptr_t,
|
|
||||||
self.foreign_id as uintptr_t,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
/* if there is a msg-id and it does not exist in the db, cancel sending.
|
||||||
|
this happends if dc_delete_msgs() was called
|
||||||
|
before the generated mime was sent out */
|
||||||
|
if 0 != self.foreign_id {
|
||||||
|
if 0 == unsafe { dc_msg_exists(context, self.foreign_id) } {
|
||||||
|
warn!(
|
||||||
|
context,
|
||||||
|
0, "Message {} for job {} does not exist", self.foreign_id, self.job_id,
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { free(buf) };
|
/* send message while holding the smtp lock long enough
|
||||||
unsafe { free(filename.cast()) };
|
to also mark success in the database, to reduce chances
|
||||||
|
of a message getting sent twice.
|
||||||
|
*/
|
||||||
|
let mut sock = context.smtp.lock().unwrap();
|
||||||
|
if 0 == sock.send(context, recipients_list, body) {
|
||||||
|
sock.disconnect();
|
||||||
|
self.try_again_later(Delay::AtOnce, Some(as_str(sock.error)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dc_delete_file(context, filename);
|
||||||
|
if 0 != self.foreign_id {
|
||||||
|
dc_update_msg_state(context, self.foreign_id, MessageState::OutDelivered);
|
||||||
|
let chat_id: i32 = context
|
||||||
|
.sql
|
||||||
|
.query_row_col(
|
||||||
|
context,
|
||||||
|
"SELECT chat_id FROM msgs WHERE id=?",
|
||||||
|
params![self.foreign_id as i32],
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.unwrap_or_default();
|
||||||
|
context.call_cb(
|
||||||
|
Event::MSG_DELIVERED,
|
||||||
|
chat_id as uintptr_t,
|
||||||
|
self.foreign_id as uintptr_t,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this value does not increase the number of tries
|
// this value does not increase the number of tries
|
||||||
fn try_again_later(&mut self, try_again: libc::c_int, pending_error: Option<&str>) {
|
fn try_again_later(&mut self, try_again: Delay, pending_error: Option<&str>) {
|
||||||
self.try_again = try_again;
|
self.try_again = try_again;
|
||||||
self.pending_error = pending_error.map(|s| s.to_string());
|
self.pending_error = pending_error.map(|s| s.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn do_DC_JOB_MOVE_MSG(&mut self, context: &Context) {
|
fn do_DC_JOB_MOVE_MSG(&mut self, context: &Context) {
|
||||||
let ok_to_continue;
|
|
||||||
let mut dest_uid = 0;
|
let mut dest_uid = 0;
|
||||||
|
|
||||||
let inbox = context.inbox.read().unwrap();
|
let inbox = context.inbox.read().unwrap();
|
||||||
@@ -233,45 +202,38 @@ impl Job {
|
|||||||
if !inbox.is_connected() {
|
if !inbox.is_connected() {
|
||||||
connect_to_inbox(context, &inbox);
|
connect_to_inbox(context, &inbox);
|
||||||
if !inbox.is_connected() {
|
if !inbox.is_connected() {
|
||||||
self.try_again_later(3, None);
|
self.try_again_later(Delay::Standard, None);
|
||||||
ok_to_continue = false;
|
return;
|
||||||
} else {
|
|
||||||
ok_to_continue = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ok_to_continue = true;
|
|
||||||
}
|
}
|
||||||
if ok_to_continue {
|
if let Ok(msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
||||||
if let Ok(msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
if context
|
||||||
if context
|
.sql
|
||||||
.sql
|
.get_config_int(context, "folders_configured")
|
||||||
.get_config_int(context, "folders_configured")
|
.unwrap_or_default()
|
||||||
.unwrap_or_default()
|
< 3
|
||||||
< 3
|
{
|
||||||
{
|
inbox.configure_folders(context, 0x1i32);
|
||||||
inbox.configure_folders(context, 0x1i32);
|
}
|
||||||
}
|
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
|
||||||
|
|
||||||
if let Some(dest_folder) = dest_folder {
|
if let Some(dest_folder) = dest_folder {
|
||||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||||
|
|
||||||
match inbox.mv(
|
match inbox.mv(
|
||||||
context,
|
context,
|
||||||
server_folder,
|
server_folder,
|
||||||
msg.server_uid,
|
msg.server_uid,
|
||||||
&dest_folder,
|
&dest_folder,
|
||||||
&mut dest_uid,
|
&mut dest_uid,
|
||||||
) as libc::c_uint
|
) {
|
||||||
{
|
ImapResult::RetryLater => {
|
||||||
1 => {
|
self.try_again_later(Delay::Standard, None);
|
||||||
self.try_again_later(3i32, None);
|
|
||||||
}
|
|
||||||
3 => {
|
|
||||||
dc_update_server_uid(context, msg.rfc724_mid, &dest_folder, dest_uid);
|
|
||||||
}
|
|
||||||
0 | 2 | _ => {}
|
|
||||||
}
|
}
|
||||||
|
ImapResult::Success => {
|
||||||
|
dc_update_server_uid(context, msg.rfc724_mid, &dest_folder, dest_uid);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,53 +241,37 @@ impl Job {
|
|||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn do_DC_JOB_DELETE_MSG_ON_IMAP(&mut self, context: &Context) {
|
fn do_DC_JOB_DELETE_MSG_ON_IMAP(&mut self, context: &Context) {
|
||||||
let mut delete_from_server = 1;
|
|
||||||
let inbox = context.inbox.read().unwrap();
|
let inbox = context.inbox.read().unwrap();
|
||||||
|
|
||||||
if let Ok(mut msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
if let Ok(mut msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
||||||
if !(msg.rfc724_mid.is_null()
|
if !(msg.rfc724_mid.is_null()
|
||||||
|| unsafe { *msg.rfc724_mid.offset(0isize) as libc::c_int == 0 })
|
|| unsafe { *msg.rfc724_mid.offset(0isize) as libc::c_int == 0 })
|
||||||
{
|
{
|
||||||
let ok_to_continue1;
|
|
||||||
/* eg. device messages have no Message-ID */
|
/* eg. device messages have no Message-ID */
|
||||||
if dc_rfc724_mid_cnt(context, msg.rfc724_mid) != 1 {
|
if dc_rfc724_mid_cnt(context, msg.rfc724_mid) != 1 {
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
0, "The message is deleted from the server when all parts are deleted.",
|
0, "The message is deleted from the server when all parts are deleted.",
|
||||||
);
|
);
|
||||||
delete_from_server = 0i32
|
return;
|
||||||
}
|
}
|
||||||
/* if this is the last existing part of the message, we delete the message from the server */
|
/* if this is the last existing part of the message, we delete the message from the server */
|
||||||
if 0 != delete_from_server {
|
if !inbox.is_connected() {
|
||||||
let ok_to_continue;
|
connect_to_inbox(context, &inbox);
|
||||||
if !inbox.is_connected() {
|
if !inbox.is_connected() {
|
||||||
connect_to_inbox(context, &inbox);
|
self.try_again_later(Delay::Standard, None);
|
||||||
if !inbox.is_connected() {
|
return;
|
||||||
self.try_again_later(3i32, None);
|
|
||||||
ok_to_continue = false;
|
|
||||||
} else {
|
|
||||||
ok_to_continue = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ok_to_continue = true;
|
|
||||||
}
|
}
|
||||||
if ok_to_continue {
|
|
||||||
let mid = unsafe { CStr::from_ptr(msg.rfc724_mid).to_str().unwrap() };
|
|
||||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
|
||||||
if 0 == inbox.delete_msg(context, mid, server_folder, &mut msg.server_uid) {
|
|
||||||
self.try_again_later(-1i32, None);
|
|
||||||
ok_to_continue1 = false;
|
|
||||||
} else {
|
|
||||||
ok_to_continue1 = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ok_to_continue1 = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ok_to_continue1 = true;
|
|
||||||
}
|
}
|
||||||
if ok_to_continue1 {
|
let mid = unsafe { CStr::from_ptr(msg.rfc724_mid).to_str().unwrap() };
|
||||||
dc_delete_msg_from_db(context, msg.id);
|
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||||
|
match inbox.delete_msg(context, mid, server_folder, &mut msg.server_uid) {
|
||||||
|
ImapResult::RetryLater => {
|
||||||
|
self.try_again_later(Delay::AtOnce, None);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
dc_delete_msg_from_db(context, msg.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,57 +279,51 @@ impl Job {
|
|||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn do_DC_JOB_MARKSEEN_MSG_ON_IMAP(&mut self, context: &Context) {
|
fn do_DC_JOB_MARKSEEN_MSG_ON_IMAP(&mut self, context: &Context) {
|
||||||
let ok_to_continue;
|
|
||||||
let inbox = context.inbox.read().unwrap();
|
let inbox = context.inbox.read().unwrap();
|
||||||
|
|
||||||
if !inbox.is_connected() {
|
if !inbox.is_connected() {
|
||||||
connect_to_inbox(context, &inbox);
|
connect_to_inbox(context, &inbox);
|
||||||
if !inbox.is_connected() {
|
if !inbox.is_connected() {
|
||||||
self.try_again_later(3i32, None);
|
self.try_again_later(Delay::Standard, None);
|
||||||
ok_to_continue = false;
|
return;
|
||||||
} else {
|
|
||||||
ok_to_continue = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ok_to_continue = true;
|
|
||||||
}
|
}
|
||||||
if ok_to_continue {
|
if let Ok(msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
||||||
if let Ok(msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
match inbox.set_seen(context, server_folder, msg.server_uid) {
|
||||||
match inbox.set_seen(context, server_folder, msg.server_uid) as libc::c_uint {
|
ImapResult::Failed => {
|
||||||
0 => {}
|
return;
|
||||||
1 => {
|
|
||||||
self.try_again_later(3i32, None);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
if 0 != msg.param.get_int(Param::WantsMdn).unwrap_or_default()
|
|
||||||
&& 0 != context
|
|
||||||
.sql
|
|
||||||
.get_config_int(context, "mdns_enabled")
|
|
||||||
.unwrap_or_else(|| 1)
|
|
||||||
{
|
|
||||||
let folder = msg.server_folder.as_ref().unwrap();
|
|
||||||
|
|
||||||
match inbox.set_mdnsent(context, folder, msg.server_uid) as libc::c_uint
|
|
||||||
{
|
|
||||||
1 => {
|
|
||||||
self.try_again_later(3i32, None);
|
|
||||||
}
|
|
||||||
3 => {
|
|
||||||
send_mdn(context, msg.id);
|
|
||||||
}
|
|
||||||
0 | 2 | _ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
ImapResult::RetryLater => {
|
||||||
|
self.try_again_later(Delay::Standard, None);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
if 0 != msg.param.get_int(Param::WantsMdn).unwrap_or_default()
|
||||||
|
&& 0 != context
|
||||||
|
.sql
|
||||||
|
.get_config_int(context, "mdns_enabled")
|
||||||
|
.unwrap_or_else(|| 1)
|
||||||
|
{
|
||||||
|
let folder = msg.server_folder.as_ref().unwrap();
|
||||||
|
|
||||||
|
match inbox.set_mdnsent(context, folder, msg.server_uid) {
|
||||||
|
ImapResult::RetryLater => {
|
||||||
|
self.try_again_later(Delay::Standard, None);
|
||||||
|
}
|
||||||
|
ImapResult::Success => {
|
||||||
|
send_mdn(context, msg.id);
|
||||||
|
}
|
||||||
|
ImapResult::AlreadyDone => {}
|
||||||
|
ImapResult::Failed => {}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn do_DC_JOB_MARKSEEN_MDN_ON_IMAP(&mut self, context: &Context) {
|
fn do_DC_JOB_MARKSEEN_MDN_ON_IMAP(&mut self, context: &Context) {
|
||||||
let ok_to_continue;
|
|
||||||
let folder = self
|
let folder = self
|
||||||
.param
|
.param
|
||||||
.get(Param::ServerFolder)
|
.get(Param::ServerFolder)
|
||||||
@@ -396,34 +336,37 @@ impl Job {
|
|||||||
if !inbox.is_connected() {
|
if !inbox.is_connected() {
|
||||||
connect_to_inbox(context, &inbox);
|
connect_to_inbox(context, &inbox);
|
||||||
if !inbox.is_connected() {
|
if !inbox.is_connected() {
|
||||||
self.try_again_later(3, None);
|
self.try_again_later(Delay::Standard, None);
|
||||||
ok_to_continue = false;
|
return;
|
||||||
} else {
|
|
||||||
ok_to_continue = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ok_to_continue = true;
|
|
||||||
}
|
}
|
||||||
if ok_to_continue {
|
|
||||||
if inbox.set_seen(context, &folder, uid) == 0 {
|
match inbox.set_seen(context, &folder, uid) {
|
||||||
self.try_again_later(3i32, None);
|
ImapResult::RetryLater => {
|
||||||
|
self.try_again_later(Delay::Standard, None);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if 0 != self.param.get_int(Param::AlsoMove).unwrap_or_default() {
|
ImapResult::Failed => {
|
||||||
if context
|
return;
|
||||||
.sql
|
}
|
||||||
.get_config_int(context, "folders_configured")
|
_ => {}
|
||||||
.unwrap_or_default()
|
};
|
||||||
< 3
|
if 0 != self.param.get_int(Param::AlsoMove).unwrap_or_default() {
|
||||||
{
|
if context
|
||||||
inbox.configure_folders(context, 0x1i32);
|
.sql
|
||||||
}
|
.get_config_int(context, "folders_configured")
|
||||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
.unwrap_or_default()
|
||||||
if let Some(dest_folder) = dest_folder {
|
< 3
|
||||||
if 1 == inbox.mv(context, folder, uid, dest_folder, &mut dest_uid)
|
{
|
||||||
as libc::c_uint
|
inbox.configure_folders(context, 0x1i32);
|
||||||
{
|
}
|
||||||
self.try_again_later(3, None);
|
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||||
|
if let Some(dest_folder) = dest_folder {
|
||||||
|
match inbox.mv(context, folder, uid, dest_folder, &mut dest_uid) {
|
||||||
|
ImapResult::RetryLater => {
|
||||||
|
self.try_again_later(Delay::Standard, None);
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -811,7 +754,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
|||||||
added_timestamp: row.get(4)?,
|
added_timestamp: row.get(4)?,
|
||||||
tries: row.get(6)?,
|
tries: row.get(6)?,
|
||||||
param: row.get::<_, String>(3)?.parse().unwrap_or_default(),
|
param: row.get::<_, String>(3)?.parse().unwrap_or_default(),
|
||||||
try_again: 0,
|
try_again: Delay::DoNotTryAgain,
|
||||||
pending_error: None,
|
pending_error: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -843,7 +786,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
|||||||
// some configuration jobs are "exclusive":
|
// some configuration jobs are "exclusive":
|
||||||
// - they are always executed in the imap-thread and the smtp-thread is suspended during execution
|
// - they are always executed in the imap-thread and the smtp-thread is suspended during execution
|
||||||
// - they may change the database handle change the database handle; we do not keep old pointers therefore
|
// - they may change the database handle change the database handle; we do not keep old pointers therefore
|
||||||
// - they can be re-executed one time AT_ONCE, but they are not save in the database for later execution
|
// - they can be re-executed one time AtOnce, but they are not save in the database for later execution
|
||||||
if Action::ConfigureImap == job.action || Action::ImexImap == job.action {
|
if Action::ConfigureImap == job.action || Action::ImexImap == job.action {
|
||||||
job_kill_action(context, job.action);
|
job_kill_action(context, job.action);
|
||||||
&context
|
&context
|
||||||
@@ -864,7 +807,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
|||||||
let mut tries = 0;
|
let mut tries = 0;
|
||||||
while tries <= 1 {
|
while tries <= 1 {
|
||||||
// this can be modified by a job using dc_job_try_again_later()
|
// this can be modified by a job using dc_job_try_again_later()
|
||||||
job.try_again = 0;
|
job.try_again = Delay::DoNotTryAgain;
|
||||||
|
|
||||||
match job.action {
|
match job.action {
|
||||||
Action::SendMsgToSmtp => job.do_DC_JOB_SEND(context),
|
Action::SendMsgToSmtp => job.do_DC_JOB_SEND(context),
|
||||||
@@ -885,7 +828,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
|||||||
Action::SendMdnOld => {}
|
Action::SendMdnOld => {}
|
||||||
Action::SendMsgToSmtpOld => {}
|
Action::SendMsgToSmtpOld => {}
|
||||||
}
|
}
|
||||||
if job.try_again != -1 {
|
if job.try_again != Delay::AtOnce {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tries += 1
|
tries += 1
|
||||||
@@ -905,7 +848,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
|||||||
.unsuspend(context);
|
.unsuspend(context);
|
||||||
suspend_smtp_thread(context, false);
|
suspend_smtp_thread(context, false);
|
||||||
break;
|
break;
|
||||||
} else if job.try_again == 2 {
|
} else if job.try_again == Delay::IncreationPoll {
|
||||||
// just try over next loop unconditionally, the ui typically interrupts idle when the file (video) is ready
|
// just try over next loop unconditionally, the ui typically interrupts idle when the file (video) is ready
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
@@ -918,7 +861,7 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
|
|||||||
},
|
},
|
||||||
job.job_id
|
job.job_id
|
||||||
);
|
);
|
||||||
} else if job.try_again == -1 || job.try_again == 3 {
|
} else if job.try_again == Delay::AtOnce || job.try_again == Delay::Standard {
|
||||||
let tries = job.tries + 1;
|
let tries = job.tries + 1;
|
||||||
if tries < 17 {
|
if tries < 17 {
|
||||||
job.tries = tries;
|
job.tries = tries;
|
||||||
|
|||||||
Reference in New Issue
Block a user