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.
embed
Manos Pitsidianakis 2019-09-23 09:30:23 +03:00
parent ed248be031
commit 26e4d50b40
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
6 changed files with 85 additions and 42 deletions

View File

@ -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

View File

@ -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())

View File

@ -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())

View File

@ -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())

View File

@ -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<FolderHash> for Account {

View File

@ -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<String>, path: Option<&PathBuf>) -> File {
pub fn create_temp_file(
bytes: &[u8],
filename: Option<String>,
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<String>, path: Option<&Pa
f.write_all(bytes).unwrap();
f.flush().unwrap();
File { path: path.clone() }
File {
path: path.clone(),
delete_on_drop,
}
}