diff --git a/src/dc_configure.rs b/src/dc_configure.rs index 0f838686f..1723883e8 100644 --- a/src/dc_configure.rs +++ b/src/dc_configure.rs @@ -1311,29 +1311,6 @@ pub unsafe fn dc_free_ongoing(context: &dc_context_t) { s.shall_stop_ongoing = true; } -unsafe fn free_folders(mut folders: *mut clist) { - if !folders.is_null() { - let mut iter1: *mut clistiter; - iter1 = (*folders).first; - while !iter1.is_null() { - let mut ret_folder: *mut dc_imapfolder_t = (if !iter1.is_null() { - (*iter1).data - } else { - 0 as *mut libc::c_void - }) as *mut dc_imapfolder_t; - free((*ret_folder).name_to_select as *mut libc::c_void); - free((*ret_folder).name_utf8 as *mut libc::c_void); - free(ret_folder as *mut libc::c_void); - iter1 = if !iter1.is_null() { - (*iter1).next - } else { - 0 as *mut clistcell_s - } - } - clist_free(folders); - }; -} - unsafe fn moz_autoconfigure( mut context: &dc_context_t, mut url: *const libc::c_char, diff --git a/src/dc_imap.rs b/src/dc_imap.rs index 0c1bc5292..7ae3d6482 100644 --- a/src/dc_imap.rs +++ b/src/dc_imap.rs @@ -13,6 +13,15 @@ use crate::types::*; pub const DC_IMAP_SEEN: usize = 0x0001; +pub const DC_SUCCESS: usize = 3; +pub const DC_ALREADY_DONE: usize = 2; +pub const DC_RETRY_LATER: usize = 1; +pub const DC_FAILED: usize = 0; + +const PREFETCH_FLAGS: &'static str = "(UID ENVELOPE)"; +const BODY_FLAGS: &'static str = "(FLAGS BODY.PEEK[])"; +const FETCH_FLAGS: &'static str = "(FLAGS)"; + #[repr(C)] pub struct dc_imap_t { config: Arc>, @@ -226,6 +235,21 @@ impl Session { Session::Insecure(i) => i.idle().map(Into::into), } } + + pub fn uid_store( + &mut self, + uid_set: S1, + query: S2, + ) -> imap::error::Result>> + where + S1: AsRef, + S2: AsRef, + { + match self { + Session::Secure(i) => i.uid_store(uid_set, query), + Session::Insecure(i) => i.uid_store(uid_set, query), + } + } } pub struct ImapConfig { @@ -264,10 +288,6 @@ impl Default for ImapConfig { watch_folder: None, }; - // prefetch: UID, ENVELOPE, - // new: FLAGS BODY.PEEK[] - // flags: FLAGS - cfg } } @@ -652,9 +672,7 @@ impl dc_imap_t { let list = if let Some(ref mut session) = *self.session.lock().unwrap() { // `FETCH (UID)` let set = format!("{}", mailbox.exists); - let query = "(UID ENVELOPE)"; - println!("fetching: {} {}", set, query); - match session.fetch(set, query) { + match session.fetch(set, PREFETCH_FLAGS) { Ok(list) => list, Err(err) => { eprintln!("fetch error: {:?}", err); @@ -705,9 +723,7 @@ impl dc_imap_t { // fetch messages with larger UID than the last one seen // (`UID FETCH lastseenuid+1:*)`, see RFC 4549 let set = format!("{}:*", last_seen_uid + 1); - let query = "(UID ENVELOPE)"; - println!("fetching: {} {}", set, query); - match session.uid_fetch(set, query) { + match session.uid_fetch(set, PREFETCH_FLAGS) { Ok(list) => list, Err(err) => { eprintln!("fetch err: {:?}", err); @@ -840,8 +856,7 @@ impl dc_imap_t { let msgs = if let Some(ref mut session) = *self.session.lock().unwrap() { let set = format!("{}", server_uid); - let query = "(FLAGS BODY.PEEK[])"; - match session.uid_fetch(set, query) { + match session.uid_fetch(set, BODY_FLAGS) { Ok(msgs) => msgs, Err(err) => { eprintln!("error fetch single: {:?}", err); @@ -999,6 +1014,7 @@ impl dc_imap_t { println!("imap idle waiting"); // TODO: proper logging of different states + // TODO: reconnect if we timed out match idle.wait_keepalive() { Ok(_) => { println!("imap done"); @@ -1087,10 +1103,10 @@ impl dc_imap_t { uid: uint32_t, dest_folder: *const libc::c_char, dest_uid: *mut uint32_t, - ) -> dc_imap_res { + ) -> usize { unimplemented!() // let mut current_block: u64; - // let mut res: dc_imap_res = DC_RETRY_LATER; + // let mut res: usize = DC_RETRY_LATER; // let mut r: libc::c_int = 0; // let mut set: *mut mailimap_set = mailimap_set_new_single(uid); // let mut res_uid: uint32_t = 0 as uint32_t; @@ -1228,32 +1244,26 @@ impl dc_imap_t { // }) as libc::c_uint // } else { // res as libc::c_uint - // }) as dc_imap_res; + // }) as usize; } - fn add_flag(&self, server_uid: uint32_t, flag: *mut mailimap_flag) -> usize { - unimplemented!() - // let mut flag_list: *mut mailimap_flag_list = 0 as *mut mailimap_flag_list; - // let mut store_att_flags: *mut mailimap_store_att_flags = 0 as *mut mailimap_store_att_flags; - // let mut set: *mut mailimap_set = mailimap_set_new_single(server_uid); - // if !(imap.etpan.is_null()) { - // flag_list = mailimap_flag_list_new_empty(); - // mailimap_flag_list_add(flag_list, flag); - // store_att_flags = mailimap_store_att_flags_new_add_flags(flag_list); - // mailimap_uid_store(imap.etpan, set, store_att_flags); - // } - // if !store_att_flags.is_null() { - // mailimap_store_att_flags_free(store_att_flags); - // } - // if !set.is_null() { - // mailimap_set_free(set); - // set = 0 as *mut mailimap_set - // } - // if 0 != imap.should_reconnect { - // 0 - // } else { - // 1 - // } + fn add_flag>(&self, server_uid: u32, flag: S) -> usize { + if let Some(ref mut session) = *self.session.lock().unwrap() { + let set = format!("{}", server_uid); + let query = format!("+ FLAGS ({})", flag.as_ref()); + match session.uid_store(set, query) { + Ok(_) => {} + Err(err) => { + eprintln!("imap store error {:?}", err); + } + } + } + + if self.should_reconnect() { + 0 + } else { + 1 + } } pub fn set_seen( @@ -1261,9 +1271,9 @@ impl dc_imap_t { context: &dc_context_t, folder: *const libc::c_char, uid: uint32_t, - ) -> dc_imap_res { + ) -> usize { unimplemented!() - // let mut res: dc_imap_res = DC_RETRY_LATER; + // let mut res: usize = DC_RETRY_LATER; // if folder.is_null() || uid == 0 as libc::c_uint { // res = DC_FAILED // } else if !imap.etpan.is_null() { @@ -1300,172 +1310,137 @@ impl dc_imap_t { // }) as libc::c_uint // } else { // res as libc::c_uint - // }) as dc_imap_res; + // }) as usize; } - pub fn set_mdnsent( - &self, - context: &dc_context_t, - folder: *const libc::c_char, - uid: uint32_t, - ) -> dc_imap_res { - unimplemented!(); - // let mut can_create_flag: libc::c_int = 0; - // let mut current_block: u64; - // // returns 0=job should be retried later, 1=job done, 2=job done and flag just set - // let mut res: dc_imap_res = DC_RETRY_LATER; - // let mut set: *mut mailimap_set = mailimap_set_new_single(uid); - // let mut fetch_result: *mut clist = 0 as *mut clist; - // if folder.is_null() || uid == 0 as libc::c_uint || set.is_null() { - // res = DC_FAILED - // } else if !imap.etpan.is_null() { - // dc_log_info( - // context, - // 0, - // b"Marking message %s/%i as $MDNSent...\x00" as *const u8 as *const libc::c_char, - // folder, - // uid as libc::c_int, - // ); - // if select_folder(context, imap, folder) == 0 { - // dc_log_warning( - // context, - // 0, - // b"Cannot select folder %s for setting $MDNSent flag.\x00" as *const u8 - // as *const libc::c_char, - // folder, - // ); - // } else { - // /* Check if the folder can handle the `$MDNSent` flag (see RFC 3503). If so, and not set: set the flags and return this information. - // If the folder cannot handle the `$MDNSent` flag, we risk duplicated MDNs; it's up to the receiving MUA to handle this then (eg. Delta Chat has no problem with this). */ - // can_create_flag = 0; - // if !(*imap.etpan).imap_selection_info.is_null() - // && !(*(*imap.etpan).imap_selection_info) - // .sel_perm_flags - // .is_null() - // { - // let mut iter: *mut clistiter = 0 as *mut clistiter; - // iter = (*(*(*imap.etpan).imap_selection_info).sel_perm_flags).first; - // while !iter.is_null() { - // let mut fp: *mut mailimap_flag_perm = (if !iter.is_null() { - // (*iter).data - // } else { - // 0 as *mut libc::c_void - // }) - // as *mut mailimap_flag_perm; - // if !fp.is_null() { - // if (*fp).fl_type == MAILIMAP_FLAG_PERM_ALL as libc::c_int { - // can_create_flag = 1; - // break; - // } else if (*fp).fl_type == MAILIMAP_FLAG_PERM_FLAG as libc::c_int - // && !(*fp).fl_flag.is_null() - // { - // let mut fl: *mut mailimap_flag = - // (*fp).fl_flag as *mut mailimap_flag; - // if (*fl).fl_type == MAILIMAP_FLAG_KEYWORD as libc::c_int - // && !(*fl).fl_data.fl_keyword.is_null() - // && strcmp( - // (*fl).fl_data.fl_keyword, - // b"$MDNSent\x00" as *const u8 as *const libc::c_char, - // ) == 0 - // { - // can_create_flag = 1; - // break; - // } - // } - // } - // iter = if !iter.is_null() { - // (*iter).next - // } else { - // 0 as *mut clistcell_s - // } - // } - // } - // if 0 != can_create_flag { - // let mut r: libc::c_int = mailimap_uid_fetch( - // imap.etpan, - // set, - // imap.fetch_type_flags, - // &mut fetch_result, - // ); - // if 0 != dc_imap_is_error(context, imap, r) || fetch_result.is_null() { - // fetch_result = 0 as *mut clist - // } else { - // let mut cur: *mut clistiter = (*fetch_result).first; - // if !cur.is_null() { - // if 0 != peek_flag_keyword( - // (if !cur.is_null() { - // (*cur).data - // } else { - // 0 as *mut libc::c_void - // }) as *mut mailimap_msg_att, - // b"$MDNSent\x00" as *const u8 as *const libc::c_char, - // ) { - // res = DC_ALREADY_DONE; - // current_block = 14832935472441733737; - // } else if add_flag( - // imap, - // uid, - // mailimap_flag_new_flag_keyword(dc_strdup( - // b"$MDNSent\x00" as *const u8 as *const libc::c_char, - // )), - // ) == 0 - // { - // current_block = 17044610252497760460; - // } else { - // res = DC_SUCCESS; - // current_block = 14832935472441733737; - // } - // match current_block { - // 17044610252497760460 => {} - // _ => { - // dc_log_info( - // context, - // 0, - // if res as libc::c_uint - // == DC_SUCCESS as libc::c_int as libc::c_uint - // { - // b"$MDNSent just set and MDN will be sent.\x00" - // as *const u8 - // as *const libc::c_char - // } else { - // b"$MDNSent already set and MDN already sent.\x00" - // as *const u8 - // as *const libc::c_char - // }, - // ); - // } - // } - // } - // } - // } else { - // res = DC_SUCCESS; - // dc_log_info( - // context, - // 0, - // b"Cannot store $MDNSent flags, risk sending duplicate MDN.\x00" as *const u8 - // as *const libc::c_char, - // ); - // } - // } - // } - // if !set.is_null() { - // mailimap_set_free(set); - // set = 0 as *mut mailimap_set - // } - // if !fetch_result.is_null() { - // mailimap_fetch_list_free(fetch_result); - // fetch_result = 0 as *mut clist - // } + pub fn set_mdnsent>(&self, context: &dc_context_t, folder: S, uid: u32) -> usize { + // returns 0=job should be retried later, 1=job done, 2=job done and flag just set + let mut res = DC_RETRY_LATER; + let mut set = format!("{}", uid); - // (if res as libc::c_uint == DC_RETRY_LATER as libc::c_int as libc::c_uint { - // (if 0 != imap.should_reconnect { - // DC_RETRY_LATER as libc::c_int - // } else { - // DC_FAILED as libc::c_int - // }) as libc::c_uint - // } else { - // res as libc::c_uint - // }) as dc_imap_res + if uid == 0 { + res = DC_FAILED; + } else if self.is_connected() { + let folder_c = CString::new(folder.as_ref().to_owned()).unwrap(); + unsafe { + dc_log_info( + context, + 0, + b"Marking message %s/%i as $MDNSent...\x00" as *const u8 as *const libc::c_char, + folder_c.as_ptr(), + uid as libc::c_int, + ) + }; + + if self.select_folder(context, Some(folder)) == 0 { + unsafe { + dc_log_warning( + context, + 0, + b"Cannot select folder %s for setting $MDNSent flag.\x00" as *const u8 + as *const libc::c_char, + folder_c.as_ptr(), + ) + }; + } else { + // Check if the folder can handle the `$MDNSent` flag (see RFC 3503). If so, and not + // set: set the flags and return this information. + // If the folder cannot handle the `$MDNSent` flag, we risk duplicated MDNs; it's up + // to the receiving MUA to handle this then (eg. Delta Chat has no problem with this). + + let can_create_flag = self + .config + .read() + .unwrap() + .selected_mailbox + .as_ref() + .map(|mbox| { + // empty means, everything can be stored + mbox.permanent_flags.is_empty() + || mbox + .permanent_flags + .iter() + .find(|flag| match flag { + imap::types::Flag::Custom(s) => s == "$MDNSent", + _ => false, + }) + .is_some() + }) + .expect("just selected folder"); + + if can_create_flag { + let fetched_msgs = if let Some(ref mut session) = *self.session.lock().unwrap() + { + match session.uid_fetch(set, FETCH_FLAGS) { + Ok(res) => Some(res), + Err(err) => { + eprintln!("fetch error: {:?}", err); + None + } + } + } else { + unreachable!(); + }; + + if let Some(msgs) = fetched_msgs { + let flag_set = msgs + .first() + .map(|msg| { + msg.flags() + .iter() + .find(|flag| match flag { + imap::types::Flag::Custom(s) => s == "$MDNSent", + _ => false, + }) + .is_some() + }) + .unwrap_or_else(|| false); + + res = if flag_set { + DC_ALREADY_DONE + } else if self.add_flag(uid, "$MDNSent") != 0 { + DC_SUCCESS + } else { + res + }; + + unsafe { + dc_log_info( + context, + 0, + if res == DC_SUCCESS { + b"$MDNSent just set and MDN will be sent.\x00" as *const u8 + as *const libc::c_char + } else { + b"$MDNSent already set and MDN already sent.\x00" as *const u8 + as *const libc::c_char + }, + ) + }; + } + } else { + res = DC_SUCCESS; + unsafe { + dc_log_info( + context, + 0, + b"Cannot store $MDNSent flags, risk sending duplicate MDN.\x00" + as *const u8 as *const libc::c_char, + ) + }; + } + } + } + + if res == DC_RETRY_LATER { + if self.should_reconnect() { + DC_RETRY_LATER + } else { + DC_FAILED + } + } else { + res + } } // only returns 0 on connection problems; we should try later again in this case * diff --git a/src/dc_job.rs b/src/dc_job.rs index 5a00151c0..b8607135f 100644 --- a/src/dc_job.rs +++ b/src/dc_job.rs @@ -1,6 +1,8 @@ +use std::ffi::CStr; +use std::time::{Duration, SystemTime}; + use libc; use rand::{thread_rng, Rng}; -use std::time::{Duration, SystemTime}; use crate::constants::Event; use crate::dc_chat::*; @@ -660,11 +662,10 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP( 1i32, ) { - match inbox.set_mdnsent( - context, - (*msg).server_folder, - (*msg).server_uid, - ) as libc::c_uint + let folder = + CStr::from_ptr((*msg).server_folder).to_str().unwrap(); + match inbox.set_mdnsent(context, folder, (*msg).server_uid) + as libc::c_uint { 1 => { current_block = 4016212065805849280; @@ -717,11 +718,11 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP( 1i32, ) { - match inbox.set_mdnsent( - context, - (*msg).server_folder, - (*msg).server_uid, - ) as libc::c_uint + let folder = + CStr::from_ptr((*msg).server_folder).to_str().unwrap(); + + match inbox.set_mdnsent(context, folder, (*msg).server_uid) + as libc::c_uint { 1 => { current_block = 4016212065805849280; diff --git a/src/dc_jobthread.rs b/src/dc_jobthread.rs index 45f205558..d70cfcc2d 100644 --- a/src/dc_jobthread.rs +++ b/src/dc_jobthread.rs @@ -5,7 +5,6 @@ use libc; use crate::dc_configure::*; use crate::dc_context::dc_context_t; use crate::dc_imap::dc_imap_t; -use crate::dc_imap::*; use crate::dc_log::*; use crate::dc_sqlite3::*; use crate::dc_tools::*; diff --git a/src/types.rs b/src/types.rs index 2a62a0e0c..e5e470703 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1283,12 +1283,6 @@ pub const MAILSMTP_AUTH_CRAM_MD5: libc::c_uint = 2; pub const MAILSMTP_AUTH_CHECKED: libc::c_uint = 1; pub const MAILSMTP_AUTH_NOT_CHECKED: libc::c_uint = 0; -pub type dc_imap_res = libc::c_uint; -pub const DC_SUCCESS: dc_imap_res = 3; -pub const DC_ALREADY_DONE: dc_imap_res = 2; -pub const DC_RETRY_LATER: dc_imap_res = 1; -pub const DC_FAILED: dc_imap_res = 0; - pub type dc_move_state_t = libc::c_uint; #[derive(Copy, Clone)]