diff --git a/examples/simple.rs b/examples/simple.rs index 0aa1e6af7..bee1a6212 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -72,8 +72,8 @@ fn main() { let ctx1 = ctx.clone(); let t2 = std::thread::spawn(move || loop { - // dc_perform_smtp_jobs(&ctx1); - // dc_perform_smtp_idle(&ctx1); + dc_perform_smtp_jobs(&ctx1); + dc_perform_smtp_idle(&ctx1); }); let dir = tempdir().unwrap(); diff --git a/src/dc_context.rs b/src/dc_context.rs index 5ba0ee5e4..35142d98b 100644 --- a/src/dc_context.rs +++ b/src/dc_context.rs @@ -134,10 +134,10 @@ pub fn dc_context_new( dbfile: Arc::new(RwLock::new(std::ptr::null_mut())), inbox: Arc::new(RwLock::new({ dc_imap_new( - Some(cb_get_config), - Some(cb_set_config), - Some(cb_precheck_imf), - Some(cb_receive_imf), + cb_get_config, + cb_set_config, + cb_precheck_imf, + cb_receive_imf, ) })), userdata, @@ -156,10 +156,10 @@ pub fn dc_context_new( b"SENTBOX\x00" as *const u8 as *const libc::c_char, b"configured_sentbox_folder\x00" as *const u8 as *const libc::c_char, dc_imap_new( - Some(cb_get_config), - Some(cb_set_config), - Some(cb_precheck_imf), - Some(cb_receive_imf), + cb_get_config, + cb_set_config, + cb_precheck_imf, + cb_receive_imf, ), ) })), @@ -168,10 +168,10 @@ pub fn dc_context_new( b"MVBOX\x00" as *const u8 as *const libc::c_char, b"configured_mvbox_folder\x00" as *const u8 as *const libc::c_char, dc_imap_new( - Some(cb_get_config), - Some(cb_set_config), - Some(cb_precheck_imf), - Some(cb_receive_imf), + cb_get_config, + cb_set_config, + cb_precheck_imf, + cb_receive_imf, ), ) })), diff --git a/src/dc_imap.rs b/src/dc_imap.rs index 7c82fb828..39a69e6ec 100644 --- a/src/dc_imap.rs +++ b/src/dc_imap.rs @@ -152,6 +152,21 @@ impl Session { Session::Insecure(i) => i.fetch(sequence_set, query), } } + + pub fn uid_fetch( + &mut self, + uid_set: S1, + query: S2, + ) -> imap::error::Result>> + where + S1: AsRef, + S2: AsRef, + { + match self { + Session::Secure(i) => i.uid_fetch(uid_set, query), + Session::Insecure(i) => i.uid_fetch(uid_set, query), + } + } } pub struct ImapConfig { @@ -238,7 +253,8 @@ impl dc_imap_t { } pub fn should_reconnect(&self) -> bool { - unimplemented!(); + // TODO: figuer out proper handling + false } pub fn connect(&self, context: &dc_context_t, lp: *const dc_loginparam_t) -> libc::c_int { @@ -455,7 +471,7 @@ impl dc_imap_t { ) -> (u32, u32) { let key = format!("imap.mailbox.{}", folder.as_ref()); let val1 = unsafe { - self.get_config.expect("non-null function pointer")( + (self.get_config)( context, CString::new(key).unwrap().as_ptr(), 0 as *const libc::c_char, @@ -542,8 +558,7 @@ impl dc_imap_t { // id we do not do this here, we'll miss the first message // as we will get in here again and fetch from lastseenuid+1 then - // TODO. - // self.set_config_last_seen_uid(context, &folder, mailbox.exists, 0); + self.set_config_last_seen_uid(context, &folder, mailbox.uid_validity.unwrap(), 0); return 0; } @@ -593,124 +608,117 @@ impl dc_imap_t { CString::new(folder.as_ref().to_owned()).unwrap().as_ptr(), ) }; + return 0; } } } } let mut read_cnt = 0; + let mut read_errors = 0; + let mut new_last_seen_uid = 0; - // match current_block { - // 17288151659885296046 => {} - // _ => { - // set = mailimap_set_new_interval( - // lastseenuid.wrapping_add(1 as libc::c_uint), - // 0 as uint32_t, - // ); - // r = mailimap_uid_fetch( - // imap.etpan, - // set, - // imap.fetch_type_prefetch, - // &mut fetch_result, - // ); - // if !set.is_null() { - // mailimap_set_free(set); - // set = 0 as *mut mailimap_set - // } - // if 0 != dc_imap_is_error(context, imap, r) || fetch_result.is_null() { - // fetch_result = 0 as *mut clist; - // if r == MAILIMAP_ERROR_PROTOCOL as libc::c_int { - // dc_log_info( - // context, - // 0, - // b"Folder \"%s\" is empty\x00" as *const u8 as *const libc::c_char, - // folder, - // ); - // } else { - // /* the folder is simply empty, this is no error */ - // dc_log_warning( - // context, - // 0, - // b"Cannot fetch message list from folder \"%s\".\x00" as *const u8 - // as *const libc::c_char, - // folder, - // ); - // } - // } else { - // cur = (*fetch_result).first; - // while !cur.is_null() { - // let mut msg_att_0: *mut mailimap_msg_att = (if !cur.is_null() { - // (*cur).data - // } else { - // 0 as *mut libc::c_void - // }) - // as *mut mailimap_msg_att; - // let mut cur_uid: uint32_t = peek_uid(msg_att_0); - // if cur_uid > lastseenuid { - // let mut rfc724_mid: *mut libc::c_char = - // unquote_rfc724_mid(peek_rfc724_mid(msg_att_0)); - // read_cnt = read_cnt.wrapping_add(1); - // if 0 == imap.precheck_imf.expect("non-null function pointer")( - // context, rfc724_mid, folder, cur_uid, - // ) { - // if fetch_single_msg(context, imap, folder, cur_uid) == 0 { - // dc_log_info(context, 0, - // b"Read error for message %s from \"%s\", trying over later.\x00" - // as *const u8 as - // *const libc::c_char, - // rfc724_mid, folder); - // read_errors = read_errors.wrapping_add(1) - // } - // } else { - // dc_log_info( - // context, - // 0, - // b"Skipping message %s from \"%s\" by precheck.\x00" - // as *const u8 - // as *const libc::c_char, - // rfc724_mid, - // folder, - // ); - // } - // if cur_uid > new_lastseenuid { - // new_lastseenuid = cur_uid - // } - // free(rfc724_mid as *mut libc::c_void); - // } - // cur = if !cur.is_null() { - // (*cur).next - // } else { - // 0 as *mut clistcell_s - // } - // } - // if 0 == read_errors && new_lastseenuid > 0 as libc::c_uint { - // set_config_lastseenuid( - // context, - // imap, - // folder, - // uidvalidity, - // new_lastseenuid, - // ); - // } - // } - // } - // } - // } + if let Some(ref mut session) = *self.session.lock().unwrap() { + // 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); + let list = match session.uid_fetch(set, query) { + Ok(list) => list, + Err(err) => { + eprintln!("fetch err: {:?}", err); + return 0; + } + }; + println!("fetched {} messages", list.len()); + // go through all mails in folder (this is typically _fast_ as we already have the whole list) - unsafe { - dc_log_info( - context, - 0i32, - b"%i mails read from \"%s\".\x00" as *const u8 as *const libc::c_char, - read_cnt as libc::c_int, - folder, - ) - }; - // } - // if !fetch_result.is_null() { - // mailimap_fetch_list_free(fetch_result); - // fetch_result = 0 as *mut clist - // } + for msg in &list { + let cur_uid = msg.uid.unwrap_or_else(|| 0); + if cur_uid > last_seen_uid { + read_cnt += 1; + + let message_id = msg + .envelope() + .expect("missing envelope") + .message_id + .expect("missing message id"); + + let message_id_c = CString::new(message_id).unwrap(); + let folder_c = CString::new(folder.as_ref().to_owned()).unwrap(); + if 0 == unsafe { + (self.precheck_imf)( + context, + message_id_c.as_ptr(), + folder_c.as_ptr(), + cur_uid, + ) + } { + // check passed, go fetch the rest + if self.fetch_single_msg(context, &folder, cur_uid) == 0 { + unsafe { + dc_log_info( + context, + 0, + b"Read error for message %s from \"%s\", trying over later.\x00" + as *const u8 + as *const libc::c_char, + message_id_c.as_ptr(), + folder_c.as_ptr(), + ) + }; + read_errors += 1; + } + } else { + // check failed + unsafe { + dc_log_info( + context, + 0, + b"Skipping message %s from \"%s\" by precheck.\x00" as *const u8 + as *const libc::c_char, + message_id_c.as_ptr(), + folder_c.as_ptr(), + ) + }; + } + if cur_uid > new_last_seen_uid { + new_last_seen_uid = cur_uid + } + } + } + } + + if 0 == read_errors && new_last_seen_uid > 0 { + // TODO: it might be better to increase the lastseenuid also on partial errors. + // however, this requires to sort the list before going through it above. + self.set_config_last_seen_uid(context, &folder, uid_validity, new_last_seen_uid); + } + + if read_errors > 0 { + unsafe { + dc_log_warning( + context, + 0i32, + b"%i mails read from \"%s\" with %i errors.\x00" as *const u8 + as *const libc::c_char, + read_cnt as libc::c_int, + CString::new(folder.as_ref().to_owned()).unwrap().as_ptr(), + read_errors as libc::c_int, + ) + }; + } else { + unsafe { + dc_log_info( + context, + 0i32, + b"%i mails read from \"%s\".\x00" as *const u8 as *const libc::c_char, + read_cnt as libc::c_int, + CString::new(folder.as_ref().to_owned()).unwrap().as_ptr(), + ) + }; + } read_cnt } @@ -722,27 +730,23 @@ impl dc_imap_t { uidvalidity: u32, lastseenuid: u32, ) { - unimplemented!() - } - // let mut key: *mut libc::c_char = dc_mprintf( - // b"imap.mailbox.%s\x00" as *const u8 as *const libc::c_char, - // folder, - // ); - // let mut val: *mut libc::c_char = dc_mprintf( - // b"%lu:%lu\x00" as *const u8 as *const libc::c_char, - // uidvalidity, - // lastseenuid, - // ); - // imap.set_config.expect("non-null function pointer")(context, key, val); - // free(val as *mut libc::c_void); - // free(key as *mut libc::c_void); - // } + let key = format!("imap.mailbox.{}", folder.as_ref()); + let val = format!("{}:{}", uidvalidity, lastseenuid); - fn fetch_single_msg( + unsafe { + (self.set_config)( + context, + CString::new(key).unwrap().as_ptr(), + CString::new(val).unwrap().as_ptr(), + ) + }; + } + + fn fetch_single_msg>( &self, context: &dc_context_t, - folder: *const libc::c_char, - server_uid: uint32_t, + folder: S, + server_uid: u32, ) -> usize { unimplemented!(); } diff --git a/src/types.rs b/src/types.rs index 2b5b139f5..2a62a0e0c 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1167,38 +1167,32 @@ pub type blkcnt_t = libc::blkcnt_t; pub type blksize_t = libc::blksize_t; pub type nlink_t = __uint16_t; -pub type dc_receive_imf_t = Option< - unsafe fn( - _: &dc_context_t, - _: *const libc::c_char, - _: size_t, - _: *const libc::c_char, - _: uint32_t, - _: uint32_t, - ) -> (), ->; +pub type dc_receive_imf_t = unsafe fn( + _: &dc_context_t, + _: *const libc::c_char, + _: size_t, + _: *const libc::c_char, + _: uint32_t, + _: uint32_t, +) -> (); /* Purpose: Reading from IMAP servers with no dependencies to the database. dc_context_t is only used for logging and to get information about the online state. */ -pub type dc_precheck_imf_t = Option< - unsafe fn( - _: &dc_context_t, - _: *const libc::c_char, - _: *const libc::c_char, - _: uint32_t, - ) -> libc::c_int, ->; +pub type dc_precheck_imf_t = unsafe fn( + _: &dc_context_t, + _: *const libc::c_char, + _: *const libc::c_char, + _: u32, +) -> libc::c_int; pub type dc_set_config_t = - Option ()>; -pub type dc_get_config_t = Option< - unsafe fn( - _: &dc_context_t, - _: *const libc::c_char, - _: *const libc::c_char, - ) -> *mut libc::c_char, ->; + unsafe fn(_: &dc_context_t, _: *const libc::c_char, _: *const libc::c_char) -> (); +pub type dc_get_config_t = unsafe fn( + _: &dc_context_t, + _: *const libc::c_char, + _: *const libc::c_char, +) -> *mut libc::c_char; #[inline] pub unsafe fn isascii(mut _c: libc::c_int) -> libc::c_int {