From 56e3ea1548dd1531c411ef0db53eb767c82ac654 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Wed, 15 Jan 2020 12:33:05 +0200 Subject: [PATCH] melib/imap: refactor early error exit --- melib/src/backends/imap.rs | 211 +++++++++++++++++-------------------- 1 file changed, 99 insertions(+), 112 deletions(-) diff --git a/melib/src/backends/imap.rs b/melib/src/backends/imap.rs index 439fa3e8..746cf10b 100644 --- a/melib/src/backends/imap.rs +++ b/melib/src/backends/imap.rs @@ -152,16 +152,6 @@ impl MailBackend for ImapType { } fn get(&mut self, folder: &Folder) -> Async>> { - macro_rules! exit_on_error { - ($tx:expr,$($result:expr)+) => { - $(if let Err(e) = $result { - $tx.send(AsyncStatus::Payload(Err(e.into()))).unwrap(); - $tx.send(AsyncStatus::Finished).unwrap(); - return; - })+ - }; - }; - let mut w = AsyncBuilder::new(); let handle = { let tx = w.tx(); @@ -186,113 +176,110 @@ impl MailBackend for ImapType { tx.send(AsyncStatus::Finished).unwrap(); return; } - let mut response = String::with_capacity(8 * 1024); - let conn = connection.lock(); - exit_on_error!(&tx, conn); - let mut conn = conn.unwrap(); - debug!("locked for get {}", folder_path); + let _tx = tx.clone(); + if let Err(err) = (move || { + let tx = _tx; + let mut response = String::with_capacity(8 * 1024); + let mut conn = connection.lock()?; + debug!("locked for get {}", folder_path); - /* first SELECT the mailbox to get READ/WRITE permissions (because EXAMINE only - * returns READ-ONLY for both cases) */ - exit_on_error!(&tx, - conn.send_command(format!("SELECT \"{}\"", folder_path).as_bytes()) - conn.read_response(&mut response) - ); - let examine_response = protocol_parser::select_response(&response); - exit_on_error!(&tx, examine_response); - let examine_response = examine_response.unwrap(); - *can_create_flags.lock().unwrap() = examine_response.can_create_flags; - debug!( - "folder: {} examine_response: {:?}", - folder_path, examine_response - ); - let mut exists: usize = examine_response.uidnext - 1; - { - let mut uidvalidities = uid_store.uidvalidity.lock().unwrap(); - - let v = uidvalidities - .entry(folder_hash) - .or_insert(examine_response.uidvalidity); - *v = examine_response.uidvalidity; - - let mut permissions = permissions.lock().unwrap(); - permissions.create_messages = !examine_response.read_only; - permissions.remove_messages = !examine_response.read_only; - permissions.set_flags = !examine_response.read_only; - permissions.rename_messages = !examine_response.read_only; - permissions.delete_messages = !examine_response.read_only; - permissions.delete_messages = !examine_response.read_only; - let mut folder_exists = folder_exists.lock().unwrap(); - *folder_exists = exists; - } - /* reselecting the same mailbox with EXAMINE prevents expunging it */ - exit_on_error!(&tx, - conn.send_command(format!("EXAMINE \"{}\"", folder_path).as_bytes()) - conn.read_response(&mut response) - ); - - let mut tag_lck = tag_index.write().unwrap(); - let mut our_unseen = 0; - while exists > 1 { - let mut envelopes = vec![]; - exit_on_error!(&tx, - conn.send_command(format!("UID FETCH {}:{} (UID FLAGS ENVELOPE BODYSTRUCTURE)", std::cmp::max(exists.saturating_sub(500), 1), exists).as_bytes()) - conn.read_response(&mut response) - ); + /* first SELECT the mailbox to get READ/WRITE permissions (because EXAMINE only + * returns READ-ONLY for both cases) */ + conn.send_command(format!("SELECT \"{}\"", folder_path).as_bytes())?; + conn.read_response(&mut response)?; + let examine_response = protocol_parser::select_response(&response)?; + *can_create_flags.lock().unwrap() = examine_response.can_create_flags; debug!( - "fetch response is {} bytes and {} lines", - response.len(), - response.lines().collect::>().len() + "folder: {} examine_response: {:?}", + folder_path, examine_response ); - match protocol_parser::uid_fetch_responses(&response) { - Ok((_, v, _)) => { - debug!("responses len is {}", v.len()); - for UidFetchResponse { - uid, - flags, - envelope, - .. - } in v - { - let mut env = envelope.unwrap(); - let mut h = DefaultHasher::new(); - h.write_usize(uid); - h.write(folder_path.as_bytes()); - env.set_hash(h.finish()); - if let Some((flags, keywords)) = flags { - if !flags.contains(Flag::SEEN) { - our_unseen += 1; - } - env.set_flags(flags); - for f in keywords { - let hash = tag_hash!(f); - if !tag_lck.contains_key(&hash) { - tag_lck.insert(hash, f); - } - env.labels_mut().push(hash); - } - } - uid_store - .hash_index - .lock() - .unwrap() - .insert(env.hash(), (uid, folder_hash)); - uid_store.uid_index.lock().unwrap().insert(uid, env.hash()); - envelopes.push(env); - } - } - Err(e) => { - debug!(&e); - tx.send(AsyncStatus::Payload(Err(e))).unwrap(); - } - } - exists = std::cmp::max(exists.saturating_sub(500), 1); - debug!("sending payload"); + let mut exists: usize = examine_response.uidnext - 1; + { + let mut uidvalidities = uid_store.uidvalidity.lock().unwrap(); - *unseen.lock().unwrap() = our_unseen; - tx.send(AsyncStatus::Payload(Ok(envelopes))).unwrap(); + let v = uidvalidities + .entry(folder_hash) + .or_insert(examine_response.uidvalidity); + *v = examine_response.uidvalidity; + + let mut permissions = permissions.lock().unwrap(); + permissions.create_messages = !examine_response.read_only; + permissions.remove_messages = !examine_response.read_only; + permissions.set_flags = !examine_response.read_only; + permissions.rename_messages = !examine_response.read_only; + permissions.delete_messages = !examine_response.read_only; + permissions.delete_messages = !examine_response.read_only; + let mut folder_exists = folder_exists.lock().unwrap(); + *folder_exists = exists; + } + /* reselecting the same mailbox with EXAMINE prevents expunging it */ + conn.send_command(format!("EXAMINE \"{}\"", folder_path).as_bytes())?; + conn.read_response(&mut response)?; + + let mut tag_lck = tag_index.write().unwrap(); + let mut our_unseen = 0; + while exists > 1 { + let mut envelopes = vec![]; + conn.send_command( + format!( + "UID FETCH {}:{} (UID FLAGS ENVELOPE BODYSTRUCTURE)", + std::cmp::max(exists.saturating_sub(500), 1), + exists + ) + .as_bytes(), + )?; + conn.read_response(&mut response)?; + debug!( + "fetch response is {} bytes and {} lines", + response.len(), + response.lines().collect::>().len() + ); + let (_, v, _) = protocol_parser::uid_fetch_responses(&response)?; + debug!("responses len is {}", v.len()); + for UidFetchResponse { + uid, + flags, + envelope, + .. + } in v + { + let mut env = envelope.unwrap(); + let mut h = DefaultHasher::new(); + h.write_usize(uid); + h.write(folder_path.as_bytes()); + env.set_hash(h.finish()); + if let Some((flags, keywords)) = flags { + if !flags.contains(Flag::SEEN) { + our_unseen += 1; + } + env.set_flags(flags); + for f in keywords { + let hash = tag_hash!(f); + if !tag_lck.contains_key(&hash) { + tag_lck.insert(hash, f); + } + env.labels_mut().push(hash); + } + } + uid_store + .hash_index + .lock() + .unwrap() + .insert(env.hash(), (uid, folder_hash)); + uid_store.uid_index.lock().unwrap().insert(uid, env.hash()); + envelopes.push(env); + } + exists = std::cmp::max(exists.saturating_sub(500), 1); + debug!("sending payload"); + + *unseen.lock().unwrap() = our_unseen; + tx.send(AsyncStatus::Payload(Ok(envelopes))).unwrap(); + } + drop(conn); + Ok(()) + })() { + tx.send(AsyncStatus::Payload(Err(err))).unwrap(); } - drop(conn); tx.send(AsyncStatus::Finished).unwrap(); }; Box::new(closure)