From 26e4d50b402213c07c7d492ace8d6cd2e88a816d Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Mon, 23 Sep 2019 09:30:23 +0300 Subject: [PATCH] Try to save sent messages elsewhere if Sent folder fails If Sent folder wasn't correctly configured, the sent message would be lost. With this change it tries these folders in this order: 1. Sent 2. Inbox 3. Any other normal folder The check is done by looking at the special usage metadata on each folder. If everything fails, the message is saved in a file in the tmpfs. --- ui/src/components/mail/compose.rs | 89 +++++++++++++++---------- ui/src/components/mail/view.rs | 1 + ui/src/components/mail/view/envelope.rs | 1 + ui/src/components/mail/view/html.rs | 2 +- ui/src/conf/accounts.rs | 13 ++++ ui/src/types/helpers.rs | 21 ++++-- 6 files changed, 85 insertions(+), 42 deletions(-) diff --git a/ui/src/components/mail/compose.rs b/ui/src/components/mail/compose.rs index 699b0b90..41522690 100644 --- a/ui/src/components/mail/compose.rs +++ b/ui/src/components/mail/compose.rs @@ -616,6 +616,7 @@ impl Component for Composer { self.draft.to_string().unwrap().as_str().as_bytes(), None, None, + true, ); // TODO: check exit status @@ -773,47 +774,63 @@ pub fn send_draft(context: &mut Context, account_cursor: usize, draft: Draft) -> stdin .write_all(draft.as_bytes()) .expect("Failed to write to stdin"); - if let Err(e) = context.accounts[account_cursor].save( - draft.as_bytes(), - &context.accounts[account_cursor].sent_folder(), - Some(Flag::SEEN), - ) { - debug!("{:?} could not save sent msg", e); + for folder in &[ + &context.accounts[account_cursor].special_use_folder(SpecialUseMailbox::Sent), + &context.accounts[account_cursor].special_use_folder(SpecialUseMailbox::Inbox), + &context.accounts[account_cursor].special_use_folder(SpecialUseMailbox::Normal), + ] { + if let Err(e) = + context.accounts[account_cursor].save(draft.as_bytes(), folder, Some(Flag::SEEN)) + { + debug!("{:?} could not save sent msg", e); + context.replies.push_back(UIEvent::Notification( + Some(format!("Could not save in '{}' folder.", folder)), + e.into(), + Some(NotificationType::ERROR), + )); + } else { + failure = false; + break; + } + } + + if failure { + let file = create_temp_file(draft.as_bytes(), None, None, false); + debug!("message saved in {}", file.path.display()); context.replies.push_back(UIEvent::Notification( - Some("Could not save in 'Sent' folder.".into()), - e.into(), - Some(NotificationType::ERROR), + Some("Could not save in any folder".into()), + format!( + "Message was stored in {} so that you can restore it manually.", + file.path.display() + ), + Some(NotificationType::INFO), )); - } else { - failure = false; } } - if !failure { - let output = msmtp.wait().expect("Failed to wait on mailer"); - if output.success() { - context.replies.push_back(UIEvent::Notification( - Some("Sent.".into()), - String::new(), - None, - )); + let output = msmtp.wait().expect("Failed to wait on mailer"); + if output.success() { + context.replies.push_back(UIEvent::Notification( + Some("Sent.".into()), + String::new(), + None, + )); + } else { + if let Some(exit_code) = output.code() { + log( + format!( + "Could not send e-mail using `{}`: Process exited with {}", + cmd, exit_code + ), + ERROR, + ); } else { - if let Some(exit_code) = output.code() { - log( - format!( - "Could not send e-mail using `{}`: Process exited with {}", - cmd, exit_code - ), - ERROR, - ); - } else { - log( - format!( - "Could not send e-mail using `{}`: Process was killed by signal", - cmd - ), - ERROR, - ); - } + log( + format!( + "Could not send e-mail using `{}`: Process was killed by signal", + cmd + ), + ERROR, + ); } } !failure diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs index 2767acd6..3bf69b2e 100644 --- a/ui/src/components/mail/view.rs +++ b/ui/src/components/mail/view.rs @@ -785,6 +785,7 @@ impl Component for MailView { &decode(u, None), name.as_ref().map(|n| n.clone()), None, + true, ); Command::new(&binary) .arg(p.path()) diff --git a/ui/src/components/mail/view/envelope.rs b/ui/src/components/mail/view/envelope.rs index a614a21c..a9cfd626 100644 --- a/ui/src/components/mail/view/envelope.rs +++ b/ui/src/components/mail/view/envelope.rs @@ -448,6 +448,7 @@ impl Component for EnvelopeView { &decode(u, None), name.as_ref().map(|n| n.clone()), None, + true, ); Command::new(&binary) .arg(p.path()) diff --git a/ui/src/components/mail/view/html.rs b/ui/src/components/mail/view/html.rs index 97ee5aba..26666e78 100644 --- a/ui/src/components/mail/view/html.rs +++ b/ui/src/components/mail/view/html.rs @@ -134,7 +134,7 @@ impl Component for HtmlView { // scripts) let binary = query_default_app("text/html"); if let Ok(binary) = binary { - let p = create_temp_file(&self.bytes, None, None); + let p = create_temp_file(&self.bytes, None, None, true); Command::new(&binary) .arg(p.path()) .stdin(Stdio::piped()) diff --git a/ui/src/conf/accounts.rs b/ui/src/conf/accounts.rs index 1308a800..1a479565 100644 --- a/ui/src/conf/accounts.rs +++ b/ui/src/conf/accounts.rs @@ -771,6 +771,19 @@ impl Account { "" } } + + pub fn special_use_folder(&self, special_use: SpecialUseMailbox) -> &str { + let ret = self + .settings + .folder_confs + .iter() + .find(|(_, f)| f.usage == Some(special_use)); + if let Some(ret) = ret.as_ref() { + ret.0 + } else { + "" + } + } } impl Index for Account { diff --git a/ui/src/types/helpers.rs b/ui/src/types/helpers.rs index fa82c10c..86aea577 100644 --- a/ui/src/types/helpers.rs +++ b/ui/src/types/helpers.rs @@ -29,12 +29,15 @@ use uuid::Uuid; #[derive(Debug)] pub struct File { - path: PathBuf, + pub path: PathBuf, + delete_on_drop: bool, } impl Drop for File { fn drop(&mut self) { - std::fs::remove_file(self.path()).unwrap_or_else(|_| {}); + if self.delete_on_drop { + std::fs::remove_file(self.path()).unwrap_or_else(|_| {}); + } } } @@ -61,9 +64,14 @@ impl File { } } -/// Returned `File` will be deleted when dropped, so make sure to add it on `context.temp_files` +/// Returned `File` will be deleted when dropped if delete_on_drop is set, so make sure to add it on `context.temp_files` /// to reap it later. -pub fn create_temp_file(bytes: &[u8], filename: Option, path: Option<&PathBuf>) -> File { +pub fn create_temp_file( + bytes: &[u8], + filename: Option, + path: Option<&PathBuf>, + delete_on_drop: bool, +) -> File { let mut dir = std::env::temp_dir(); let path = if let Some(p) = path { @@ -87,5 +95,8 @@ pub fn create_temp_file(bytes: &[u8], filename: Option, path: Option<&Pa f.write_all(bytes).unwrap(); f.flush().unwrap(); - File { path: path.clone() } + File { + path: path.clone(), + delete_on_drop, + } }