NotificationType: add melib::ErrorKind

memfd
Manos Pitsidianakis 2020-09-13 15:23:14 +03:00
parent 352f7505fc
commit fadf20d7b1
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
14 changed files with 418 additions and 323 deletions

View File

@ -37,12 +37,30 @@ pub type Result<T> = result::Result<T, MeliError>;
#[derive(Debug, Copy, PartialEq, Clone)] #[derive(Debug, Copy, PartialEq, Clone)]
pub enum ErrorKind { pub enum ErrorKind {
None, None,
External,
Authentication, Authentication,
Bug, Bug,
Network, Network,
Timeout, Timeout,
} }
impl fmt::Display for ErrorKind {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(
fmt,
"{}",
match self {
ErrorKind::None => "None",
ErrorKind::External => "External",
ErrorKind::Authentication => "Authentication",
ErrorKind::Bug => "Bug, please report this!",
ErrorKind::Network => "Network",
ErrorKind::Timeout => "Timeout",
}
)
}
}
impl ErrorKind { impl ErrorKind {
pub fn is_network(&self) -> bool { pub fn is_network(&self) -> bool {
match self { match self {
@ -172,17 +190,7 @@ impl fmt::Display for MeliError {
write!(f, "\nCaused by: {}", source)?; write!(f, "\nCaused by: {}", source)?;
} }
if self.kind != ErrorKind::None { if self.kind != ErrorKind::None {
write!( write!(f, "\nKind: {}", self.kind)?;
f,
"\nKind: {}",
match self.kind {
ErrorKind::None => "None",
ErrorKind::Authentication => "Authentication",
ErrorKind::Bug => "Bug, please report this!",
ErrorKind::Network => "Network",
ErrorKind::Timeout => "Timeout",
}
)?;
} }
Ok(()) Ok(())
} }

View File

@ -750,7 +750,7 @@ impl Component for Composer {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Sent.".into()), Some("Sent.".into()),
String::new(), String::new(),
Some(NotificationType::INFO), Some(NotificationType::Info),
)); ));
context context
.replies .replies
@ -760,7 +760,7 @@ impl Component for Composer {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
None, None,
err.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(err.kind)),
)); ));
save_draft( save_draft(
self.draft.clone().finalise().unwrap().as_bytes(), self.draft.clone().finalise().unwrap().as_bytes(),
@ -869,7 +869,7 @@ impl Component for Composer {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
None, None,
err.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(err.kind)),
)); ));
self.set_dirty(true); self.set_dirty(true);
} else { } else {
@ -980,7 +980,9 @@ impl Component for Composer {
"Subprocess has exited with exit code {}", "Subprocess has exited with exit code {}",
exit_code exit_code
), ),
Some(NotificationType::ERROR), Some(NotificationType::Error(
melib::error::ErrorKind::External,
)),
)); ));
} else if let EmbedStatus::Running(_, f) = embed { } else if let EmbedStatus::Running(_, f) = embed {
let result = f.read_to_string(); let result = f.read_to_string();
@ -995,11 +997,11 @@ impl Component for Composer {
} }
self.draft = new_draft; self.draft = new_draft;
} }
Err(_) => { Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
None, Some("Could not parse draft headers correctly.".to_string()),
"Could not parse draft headers correctly. The invalid text has been set as the body of your draft".to_string(), format!("{}\nThe invalid text has been set as the body of your draft", &err),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::error::ErrorKind::None)),
)); ));
self.draft.set_body(result); self.draft.set_body(result);
self.has_changes = true; self.has_changes = true;
@ -1013,6 +1015,24 @@ impl Component for Composer {
.replies .replies
.push_back(UIEvent::ChangeMode(UIMode::Normal)); .push_back(UIEvent::ChangeMode(UIMode::Normal));
} }
#[cfg(any(target_os = "linux", target_os = "android"))]
Ok(WaitStatus::PtraceEvent(_, _, _))
| Ok(WaitStatus::PtraceSyscall(_)) => {
drop(embed_guard);
match self.embed.take() {
Some(EmbedStatus::Running(e, f))
| Some(EmbedStatus::Stopped(e, f)) => {
self.embed = Some(EmbedStatus::Stopped(e, f));
}
_ => {}
}
self.mode = ViewMode::Edit;
context
.replies
.push_back(UIEvent::ChangeMode(UIMode::Normal));
self.dirty = true;
return true;
}
Ok(WaitStatus::Stopped(_, _)) => { Ok(WaitStatus::Stopped(_, _)) => {
drop(embed_guard); drop(embed_guard);
match self.embed.take() { match self.embed.take() {
@ -1035,11 +1055,28 @@ impl Component for Composer {
.push_back(UIEvent::EmbedInput((k.clone(), b.to_vec()))); .push_back(UIEvent::EmbedInput((k.clone(), b.to_vec())));
return true; return true;
} }
e => { Ok(WaitStatus::Signaled(_, signal, _)) => {
drop(embed_guard);
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
None, None,
format!("Subprocess has exited with reason {:?}", e), format!("Subprocess was killed by {} signal", signal),
Some(NotificationType::ERROR), Some(NotificationType::Error(
melib::error::ErrorKind::External,
)),
));
self.embed = None;
self.mode = ViewMode::Edit;
context
.replies
.push_back(UIEvent::ChangeMode(UIMode::Normal));
}
Err(err) => {
context.replies.push_back(UIEvent::Notification(
Some("Embed editor crashed.".to_string()),
format!("Subprocess has exited with reason {}", &err),
Some(NotificationType::Error(
melib::error::ErrorKind::External,
)),
)); ));
drop(embed_guard); drop(embed_guard);
self.embed = None; self.embed = None;
@ -1083,11 +1120,11 @@ impl Component for Composer {
editor_command.to_string() editor_command.to_string()
} else { } else {
match std::env::var("EDITOR") { match std::env::var("EDITOR") {
Err(e) => { Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some(e.to_string()), Some(err.to_string()),
"$EDITOR is not set. You can change an envvar's value with setenv or set composing.editor_command setting in your configuration.".to_string(), "$EDITOR is not set. You can change an envvar's value with setenv or set composing.editor_command setting in your configuration.".to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::error::ErrorKind::None)),
)); ));
return true; return true;
} }
@ -1150,7 +1187,7 @@ impl Component for Composer {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some(format!("Failed to execute {}: {}", editor, err)), Some(format!("Failed to execute {}: {}", editor, err)),
err.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::error::ErrorKind::External)),
)); ));
context.replies.push_back(UIEvent::Fork(ForkType::Finished)); context.replies.push_back(UIEvent::Fork(ForkType::Finished));
context.restore_input(); context.restore_input();
@ -1167,11 +1204,14 @@ impl Component for Composer {
} }
self.draft = new_draft; self.draft = new_draft;
} }
Err(_) => { Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
None, Some("Could not parse draft headers correctly.".to_string()),
"Could not parse draft headers correctly. The invalid text has been set as the body of your draft".to_string(), format!(
Some(NotificationType::ERROR), "{}\nThe invalid text has been set as the body of your draft",
&err
),
Some(NotificationType::Error(melib::error::ErrorKind::None)),
)); ));
self.draft.set_body(result); self.draft.set_body(result);
self.has_changes = true; self.has_changes = true;
@ -1181,14 +1221,13 @@ impl Component for Composer {
self.dirty = true; self.dirty = true;
return true; return true;
} }
UIEvent::Action(ref a) => { UIEvent::Action(ref a) => match a {
match a {
Action::Compose(ComposeAction::AddAttachmentPipe(ref command)) => { Action::Compose(ComposeAction::AddAttachmentPipe(ref command)) => {
if command.is_empty() { if command.is_empty() {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
None, None,
format!("pipe command value is invalid: {}", command), format!("pipe command value is invalid: {}", command),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::error::ErrorKind::None)),
)); ));
return false; return false;
} }
@ -1205,13 +1244,15 @@ impl Component for Composer {
.expect("failed to launch command") .expect("failed to launch command")
.stdout; .stdout;
let mut attachment = let mut attachment =
match melib::email::attachment_from_file(f.path()) { match melib::email::compose::attachment_from_file(f.path()) {
Ok(a) => a, Ok(a) => a,
Err(e) => { Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("could not add attachment".to_string()), Some("could not add attachment".to_string()),
e.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(
melib::error::ErrorKind::None,
)),
)); ));
self.dirty = true; self.dirty = true;
return true; return true;
@ -1232,21 +1273,21 @@ impl Component for Composer {
Err(err) => { Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
None, None,
format!("could not execute pipe command {}: {}", command, err), format!("could not execute pipe command {}: {}", command, &err),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::error::ErrorKind::External)),
)); ));
return true; return true;
} }
} }
} }
Action::Compose(ComposeAction::AddAttachment(ref path)) => { Action::Compose(ComposeAction::AddAttachment(ref path)) => {
let mut attachment = match melib::email::attachment_from_file(path) { let mut attachment = match melib::email::compose::attachment_from_file(path) {
Ok(a) => a, Ok(a) => a,
Err(e) => { Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("could not add attachment".to_string()), Some("could not add attachment".to_string()),
e.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::error::ErrorKind::None)),
)); ));
self.dirty = true; self.dirty = true;
return true; return true;
@ -1275,9 +1316,11 @@ impl Component for Composer {
return true; return true;
} }
self.draft.attachments_mut().remove(*idx); self.draft.attachments_mut().remove(*idx);
context.replies.push_back(UIEvent::StatusEvent( context
StatusEvent::DisplayMessage("attachment removed".to_string()), .replies
)); .push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage(
"attachment removed".to_string(),
)));
self.dirty = true; self.dirty = true;
return true; return true;
} }
@ -1298,8 +1341,7 @@ impl Component for Composer {
return true; return true;
} }
_ => {} _ => {}
} },
}
_ => {} _ => {}
} }
false false
@ -1469,7 +1511,7 @@ pub fn send_draft(
context.accounts[&account_hash].name() context.accounts[&account_hash].name()
)), )),
err.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(err.kind)),
)); ));
return Err(err); return Err(err);
} }
@ -1513,12 +1555,15 @@ pub fn save_draft(
) { ) {
match context.accounts[&account_hash].save_special(bytes, mailbox_type, flags) { match context.accounts[&account_hash].save_special(bytes, mailbox_type, flags) {
Err(MeliError { Err(MeliError {
summary, details, .. summary,
details,
kind,
..
}) => { }) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
summary.map(|s| s.into()), summary.map(|s| s.into()),
details.into(), details.into(),
Some(NotificationType::ERROR), Some(NotificationType::Error(kind)),
)); ));
} }
Ok(mailbox_hash) => { Ok(mailbox_hash) => {
@ -1528,7 +1573,7 @@ pub fn save_draft(
"Message saved in `{}`", "Message saved in `{}`",
&context.accounts[&account_hash].mailbox_entries[&mailbox_hash].name &context.accounts[&account_hash].mailbox_entries[&mailbox_hash].name
), ),
Some(NotificationType::INFO), Some(NotificationType::Info),
)); ));
} }
} }

View File

@ -929,7 +929,7 @@ impl Component for Listing {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Could not refresh.".to_string()), Some("Could not refresh.".to_string()),
err.to_string(), err.to_string(),
Some(NotificationType::INFO), Some(NotificationType::Error(err.kind)),
)); ));
} }
} }

View File

@ -1358,13 +1358,13 @@ impl CompactListing {
self.new_cursor_pos.2 = 0; self.new_cursor_pos.2 = 0;
let message = format!( let message = format!(
"Encountered an error while searching for `{}`: {}.", "Encountered an error while searching for `{}`: {}.",
search_term, err search_term, &err
); );
log(message.clone(), ERROR); log(message.clone(), ERROR);
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Could not perform search".to_string()), Some("Could not perform search".to_string()),
message, message,
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
)); ));
} }
} }
@ -1710,7 +1710,7 @@ impl Component for CompactListing {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Could not perform search".to_string()), Some("Could not perform search".to_string()),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
)); ));
} }
}; };
@ -1739,7 +1739,7 @@ impl Component for CompactListing {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Could not perform search".to_string()), Some("Could not perform search".to_string()),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
)); ));
} }
}; };

View File

@ -1567,7 +1567,7 @@ impl Component for ConversationsListing {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Could not perform search".to_string()), Some("Could not perform search".to_string()),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
)); ));
} }
}; };

View File

@ -1348,7 +1348,7 @@ impl Component for PlainListing {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Could not perform search".to_string()), Some("Could not perform search".to_string()),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
)); ));
} }
}; };

View File

@ -28,7 +28,7 @@ pub fn verify_signature(a: &Attachment, context: &mut Context) -> Vec<u8> {
Ok((bytes, sig)) => { Ok((bytes, sig)) => {
let bytes_file = create_temp_file(&bytes, None, None, true); let bytes_file = create_temp_file(&bytes, None, None, true);
let signature_file = create_temp_file(sig, None, None, true); let signature_file = create_temp_file(sig, None, None, true);
if let Ok(gpg) = Command::new( match Command::new(
context context
.settings .settings
.pgp .pgp
@ -48,8 +48,10 @@ pub fn verify_signature(a: &Attachment, context: &mut Context) -> Vec<u8> {
.stderr(Stdio::piped()) .stderr(Stdio::piped())
.spawn() .spawn()
{ {
Ok(gpg) => {
return gpg.wait_with_output().unwrap().stderr; return gpg.wait_with_output().unwrap().stderr;
} else { }
Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some(format!( Some(format!(
"Failed to launch {} to verify PGP signature", "Failed to launch {} to verify PGP signature",
@ -61,16 +63,20 @@ pub fn verify_signature(a: &Attachment, context: &mut Context) -> Vec<u8> {
.map(String::as_str) .map(String::as_str)
.unwrap_or("gpg2"), .unwrap_or("gpg2"),
)), )),
"see meli.conf(5) for configuration setting pgp.gpg_binary".to_string(), format!(
Some(NotificationType::ERROR), "{}\nsee meli.conf(5) for configuration setting pgp.gpg_binary",
&err
),
Some(NotificationType::Error(melib::error::ErrorKind::External)),
)); ));
} }
} }
Err(e) => { }
Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some(e.to_string()), Some("Could not verify signature.".to_string()),
String::new(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(err.kind)),
)); ));
} }
} }

View File

@ -342,19 +342,19 @@ impl MailView {
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn(); .spawn();
if command_obj.is_err() { match command_obj {
Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some(format!( Some(format!(
"Failed to start html filter process: {}", "Failed to start html filter process: {}",
filter_invocation, filter_invocation,
)), )),
String::new(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::ErrorKind::External)),
)); ));
return; return;
} }
Ok(mut html_filter) => {
let mut html_filter = command_obj.unwrap();
html_filter html_filter
.stdin .stdin
.as_mut() .as_mut()
@ -367,13 +367,16 @@ impl MailView {
) )
.into_bytes(); .into_bytes();
v.extend(html_filter.wait_with_output().unwrap().stdout); v.extend(html_filter.wait_with_output().unwrap().stdout);
}
}
} else { } else {
if let Ok(mut html_filter) = Command::new("w3m") match Command::new("w3m")
.args(&["-I", "utf-8", "-T", "text/html"]) .args(&["-I", "utf-8", "-T", "text/html"])
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn() .spawn()
{ {
Ok(mut html_filter) => {
html_filter html_filter
.stdin .stdin
.as_mut() .as_mut()
@ -385,17 +388,16 @@ impl MailView {
) )
.into_bytes(); .into_bytes();
v.extend(html_filter.wait_with_output().unwrap().stdout); v.extend(html_filter.wait_with_output().unwrap().stdout);
} else { }
Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some( Some("Failed to launch w3m to use as html filter".to_string()),
"Failed to find any application to use as html filter" err.to_string(),
.to_string(), Some(NotificationType::Error(melib::ErrorKind::External)),
),
String::new(),
Some(NotificationType::ERROR),
)); ));
} }
} }
}
} else if a.is_signed() { } else if a.is_signed() {
v.clear(); v.clear();
if context.settings.pgp.auto_verify_signatures { if context.settings.pgp.auto_verify_signatures {
@ -469,7 +471,7 @@ impl MailView {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Failed to open e-mail".to_string()), Some("Failed to open e-mail".to_string()),
err.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(err.kind)),
)); ));
log( log(
format!("Failed to open envelope: {}", err.to_string()), format!("Failed to open envelope: {}", err.to_string()),
@ -563,7 +565,7 @@ impl MailView {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
None, None,
s, s,
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::ErrorKind::None)),
)); ));
} }
_ => {} _ => {}
@ -877,7 +879,7 @@ impl Component for MailView {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Failed to open e-mail".to_string()), Some("Failed to open e-mail".to_string()),
err.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(err.kind)),
)); ));
log( log(
format!("Failed to open envelope: {}", err.to_string()), format!("Failed to open envelope: {}", err.to_string()),
@ -1219,7 +1221,7 @@ impl Component for MailView {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Failed to open e-mail".to_string()), Some("Failed to open e-mail".to_string()),
err_string, err_string,
Some(NotificationType::ERROR), Some(NotificationType::Error(err.kind)),
)); ));
} }
} }
@ -1414,7 +1416,7 @@ impl Component for MailView {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Failed to launch xdg-open".to_string()), Some("Failed to launch xdg-open".to_string()),
err.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::ErrorKind::External)),
)); ));
} }
} }
@ -1451,7 +1453,7 @@ impl Component for MailView {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Failed to open e-mail".to_string()), Some("Failed to open e-mail".to_string()),
err.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(err.kind)),
)); ));
log( log(
format!("Failed to open envelope: {}", err.to_string()), format!("Failed to open envelope: {}", err.to_string()),
@ -1475,7 +1477,7 @@ impl Component for MailView {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some(format!("Failed to create file at {}", path.display())), Some(format!("Failed to create file at {}", path.display())),
err.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::ErrorKind::External)),
)); ));
log( log(
format!( format!(
@ -1501,7 +1503,7 @@ impl Component for MailView {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
None, None,
format!("Saved at {}", &path.display()), format!("Saved at {}", &path.display()),
Some(NotificationType::INFO), Some(NotificationType::Info),
)); ));
return true; return true;
@ -1515,17 +1517,17 @@ impl Component for MailView {
| ContentType::PGPSignature => { | ContentType::PGPSignature => {
debug!(path); debug!(path);
let mut f = match std::fs::File::create(path) { let mut f = match std::fs::File::create(path) {
Err(e) => { Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some(format!("Failed to create file at {}", path)), Some(format!("Failed to create file at {}", path)),
e.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::ErrorKind::External)),
)); ));
log( log(
format!( format!(
"Failed to create file at {}: {}", "Failed to create file at {}: {}",
path, path,
e.to_string() err.to_string()
), ),
ERROR, ERROR,
); );
@ -1557,17 +1559,17 @@ impl Component for MailView {
name: ref _name, .. name: ref _name, ..
} => { } => {
let mut f = match std::fs::File::create(path.trim()) { let mut f = match std::fs::File::create(path.trim()) {
Err(e) => { Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some(format!("Failed to create file at {}", path)), Some(format!("Failed to create file at {}", path)),
e.to_string(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::ErrorKind::External)),
)); ));
log( log(
format!( format!(
"Failed to create file at {}: {}", "Failed to create file at {}: {}",
path, path,
e.to_string() err.to_string()
), ),
ERROR, ERROR,
); );
@ -1583,7 +1585,7 @@ impl Component for MailView {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
None, None,
format!("Saved at {}", &path), format!("Saved at {}", &path),
Some(NotificationType::INFO), Some(NotificationType::Info),
)); ));
} else { } else {
context context

View File

@ -101,19 +101,19 @@ impl EnvelopeView {
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn(); .spawn();
if command_obj.is_err() { match command_obj {
Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some(format!( Some(format!(
"Failed to start html filter process: {}", "Failed to start html filter process: {}",
filter_invocation, filter_invocation,
)), )),
String::new(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::ErrorKind::External)),
)); ));
return; return;
} }
Ok(mut html_filter) => {
let mut html_filter = command_obj.unwrap();
html_filter html_filter
.stdin .stdin
.as_mut() .as_mut()
@ -128,6 +128,8 @@ impl EnvelopeView {
v.extend(html_filter.wait_with_output().unwrap().stdout); v.extend(html_filter.wait_with_output().unwrap().stdout);
} }
} }
}
}
})), })),
)) ))
.into_owned(); .into_owned();

View File

@ -43,18 +43,19 @@ impl HtmlView {
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn(); .spawn();
if command_obj.is_err() { match command_obj {
Err(err) => {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some(format!( Some(format!(
"Failed to start html filter process: {}", "Failed to start html filter process: {}",
filter_invocation, filter_invocation,
)), )),
String::new(), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::ErrorKind::External)),
)); ));
String::from_utf8_lossy(&bytes).to_string() String::from_utf8_lossy(&bytes).to_string()
} else { }
let mut html_filter = command_obj.unwrap(); Ok(mut html_filter) => {
html_filter html_filter
.stdin .stdin
.as_mut() .as_mut()
@ -70,6 +71,7 @@ impl HtmlView {
)); ));
display_text display_text
} }
}
} else if let Ok(mut html_filter) = Command::new("w3m") } else if let Ok(mut html_filter) = Command::new("w3m")
.args(&["-I", "utf-8", "-T", "text/html"]) .args(&["-I", "utf-8", "-T", "text/html"])
.stdin(Stdio::piped()) .stdin(Stdio::piped())
@ -93,7 +95,7 @@ impl HtmlView {
context.replies.push_back(UIEvent::Notification( context.replies.push_back(UIEvent::Notification(
Some("Failed to find any application to use as html filter".to_string()), Some("Failed to find any application to use as html filter".to_string()),
String::new(), String::new(),
Some(NotificationType::ERROR), Some(NotificationType::Error(melib::error::ErrorKind::None)),
)); ));
String::from_utf8_lossy(&bytes).to_string() String::from_utf8_lossy(&bytes).to_string()
}; };

View File

@ -71,17 +71,46 @@ mod dbus {
let mut notification = notify_rust::Notification::new(); let mut notification = notify_rust::Notification::new();
notification notification
.appname("meli") .appname("meli")
.icon("mail-message-new")
.summary(title.as_ref().map(String::as_str).unwrap_or("meli")) .summary(title.as_ref().map(String::as_str).unwrap_or("meli"))
.body(&escape_str(body)); .body(&escape_str(body));
if *kind == Some(NotificationType::NEWMAIL) { match *kind {
Some(NotificationType::NewMail) => {
notification.hint(notify_rust::Hint::Category("email".to_owned())); notification.hint(notify_rust::Hint::Category("email".to_owned()));
notification.icon("mail-message-new");
notification.sound_name("message-new-email");
}
Some(NotificationType::SentMail) => {
notification.hint(notify_rust::Hint::Category("email".to_owned()));
notification.icon("mail-send");
notification.sound_name("message-sent-email");
}
Some(NotificationType::Saved) => {
notification.icon("document-save");
}
Some(NotificationType::Info) => {
notification.icon("dialog-information");
}
Some(NotificationType::Error(melib::ErrorKind::Authentication)) => {
notification.icon("dialog-password");
}
Some(NotificationType::Error(melib::ErrorKind::Bug)) => {
notification.icon("face-embarrassed");
}
Some(NotificationType::Error(melib::ErrorKind::None))
| Some(NotificationType::Error(melib::ErrorKind::External)) => {
notification.icon("dialog-error");
}
Some(NotificationType::Error(melib::ErrorKind::Network)) => {
notification.icon("network-error");
}
Some(NotificationType::Error(melib::ErrorKind::Timeout)) => {
notification.icon("network-offline");
}
_ => {}
} }
if settings.play_sound.is_true() { if settings.play_sound.is_true() {
if let Some(ref sound_path) = settings.sound_file { if let Some(ref sound_path) = settings.sound_file {
notification.hint(notify_rust::Hint::SoundFile(sound_path.to_owned())); notification.hint(notify_rust::Hint::SoundFile(sound_path.to_owned()));
} else {
notification.sound_name("message-new-email");
} }
} else { } else {
notification.hint(notify_rust::Hint::SuppressSound(true)); notification.hint(notify_rust::Hint::SuppressSound(true));
@ -186,7 +215,7 @@ impl Component for NotificationCommand {
} }
} }
if *kind == Some(NotificationType::NEWMAIL) { if *kind == Some(NotificationType::NewMail) {
if let Some(ref path) = context.settings.notifications.xbiff_file_path { if let Some(ref path) = context.settings.notifications.xbiff_file_path {
if let Err(err) = update_xbiff(path) { if let Err(err) = update_xbiff(path) {
debug!("Could not update xbiff file: {:?}", &err); debug!("Could not update xbiff file: {:?}", &err);

View File

@ -856,7 +856,7 @@ impl Account {
self.name, self.name,
self.mailbox_entries[&mailbox_hash].name() self.mailbox_entries[&mailbox_hash].name()
), ),
Some(crate::types::NotificationType::NEWMAIL), Some(crate::types::NotificationType::NewMail),
)); ));
} }
RefreshEventKind::Remove(env_hash) => { RefreshEventKind::Remove(env_hash) => {
@ -906,7 +906,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
Some(format!("{} watcher exited with error", &self.name)), Some(format!("{} watcher exited with error", &self.name)),
e.to_string(), e.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
*/ */
@ -914,7 +914,7 @@ impl Account {
return Some(Notification( return Some(Notification(
Some("Account watch failed".into()), Some("Account watch failed".into()),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
)); ));
} }
} }
@ -1303,7 +1303,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
None, None,
format!("'`{}` has been subscribed.", &path), format!("'`{}` has been subscribed.", &path),
Some(crate::types::NotificationType::INFO), Some(crate::types::NotificationType::Info),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
Ok(()) Ok(())
@ -1323,7 +1323,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
None, None,
format!("'`{}` has been unsubscribed.", &path), format!("'`{}` has been unsubscribed.", &path),
Some(crate::types::NotificationType::INFO), Some(crate::types::NotificationType::Info),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
Ok(()) Ok(())
@ -1468,7 +1468,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
Some(format!("{}: authentication error", &self.name)), Some(format!("{}: authentication error", &self.name)),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
self.is_online = Err(err); self.is_online = Err(err);
@ -1511,7 +1511,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
Some(format!("{}: could not fetch mailbox", &self.name)), Some(format!("{}: could not fetch mailbox", &self.name)),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
self.mailbox_entries self.mailbox_entries
@ -1636,7 +1636,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
Some(format!("{}: could not set flag", &self.name)), Some(format!("{}: could not set flag", &self.name)),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1665,7 +1665,7 @@ impl Account {
"Message was stored in {} so that you can restore it manually.", "Message was stored in {} so that you can restore it manually.",
file.path.display() file.path.display()
), ),
Some(crate::types::NotificationType::INFO), Some(crate::types::NotificationType::Info),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1678,7 +1678,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
Some("Could not send message".to_string()), Some("Could not send message".to_string()),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1694,7 +1694,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
Some(format!("{}: could not save message", &self.name)), Some(format!("{}: could not save message", &self.name)),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1706,7 +1706,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
Some(format!("{}: could not delete message", &self.name)), Some(format!("{}: could not delete message", &self.name)),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1727,7 +1727,7 @@ impl Account {
&self.name, path &self.name, path
)), )),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1807,7 +1807,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
Some(format!("{}: could not delete mailbox", &self.name)), Some(format!("{}: could not delete mailbox", &self.name)),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1862,7 +1862,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
Some(format!("{}: mailbox deleted successfully", &self.name)), Some(format!("{}: mailbox deleted successfully", &self.name)),
String::new(), String::new(),
Some(crate::types::NotificationType::INFO), Some(crate::types::NotificationType::Info),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1882,7 +1882,7 @@ impl Account {
&self.name &self.name
)), )),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1894,7 +1894,7 @@ impl Account {
&self.name &self.name
)), )),
String::new(), String::new(),
Some(crate::types::NotificationType::INFO), Some(crate::types::NotificationType::Info),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1912,7 +1912,7 @@ impl Account {
&self.name &self.name
)), )),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1924,7 +1924,7 @@ impl Account {
&self.name &self.name
)), )),
String::new(), String::new(),
Some(crate::types::NotificationType::INFO), Some(crate::types::NotificationType::Info),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1947,7 +1947,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
Some(format!("{}: watch thread failed", &self.name)), Some(format!("{}: watch thread failed", &self.name)),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1967,7 +1967,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
Some(format!("{}: {} failed", &self.name, name,)), Some(format!("{}: {} failed", &self.name, name,)),
err.to_string(), err.to_string(),
Some(crate::types::NotificationType::ERROR), Some(crate::types::NotificationType::Error(err.kind)),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }
@ -1977,7 +1977,7 @@ impl Account {
.send(ThreadEvent::UIEvent(UIEvent::Notification( .send(ThreadEvent::UIEvent(UIEvent::Notification(
Some(format!("{}: {} succeeded", &self.name, name,)), Some(format!("{}: {} succeeded", &self.name, name,)),
String::new(), String::new(),
Some(crate::types::NotificationType::INFO), Some(crate::types::NotificationType::Info),
))) )))
.expect("Could not send event on main channel"); .expect("Could not send event on main channel");
} }

View File

@ -851,7 +851,7 @@ impl State {
self.context.replies.push_back(UIEvent::Notification( self.context.replies.push_back(UIEvent::Notification(
None, None,
format!("Account {} was not found.", account_name), format!("Account {} was not found.", account_name),
Some(NotificationType::ERROR), Some(NotificationType::Error(ErrorKind::None)),
)); ));
return; return;
}; };
@ -867,7 +867,7 @@ impl State {
"Account {} doesn't have an sqlite3 search backend.", "Account {} doesn't have an sqlite3 search backend.",
account_name account_name
), ),
Some(NotificationType::ERROR), Some(NotificationType::Error(ErrorKind::None)),
)); ));
return; return;
} }
@ -888,14 +888,14 @@ impl State {
self.context.replies.push_back(UIEvent::Notification( self.context.replies.push_back(UIEvent::Notification(
None, None,
"Message index rebuild started.".to_string(), "Message index rebuild started.".to_string(),
Some(NotificationType::INFO), Some(NotificationType::Info),
)); ));
} }
Err(e) => { Err(err) => {
self.context.replies.push_back(UIEvent::Notification( self.context.replies.push_back(UIEvent::Notification(
None, Some("Message index rebuild failed".to_string()),
format!("Message index rebuild failed: {}.", e), err.to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(err.kind)),
)); ));
} }
} }
@ -906,7 +906,7 @@ impl State {
None, None,
"Message index rebuild failed: meli is not built with sqlite3 support." "Message index rebuild failed: meli is not built with sqlite3 support."
.to_string(), .to_string(),
Some(NotificationType::ERROR), Some(NotificationType::Error(ErrorKind::None)),
)); ));
} }
AccountAction(ref account_name, PrintAccountSetting(ref setting)) => { AccountAction(ref account_name, PrintAccountSetting(ref setting)) => {
@ -930,7 +930,7 @@ impl State {
self.context.replies.push_back(UIEvent::Notification( self.context.replies.push_back(UIEvent::Notification(
None, None,
format!("Account {} was not found.", account_name), format!("Account {} was not found.", account_name),
Some(NotificationType::ERROR), Some(NotificationType::Error(ErrorKind::None)),
)); ));
return; return;
} }

View File

@ -91,22 +91,23 @@ pub enum ForkType {
#[derive(Debug, PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
pub enum NotificationType { pub enum NotificationType {
INFO, Info,
ERROR, Error(melib::error::ErrorKind),
NEWMAIL, NewMail,
SentMail,
Saved,
} }
impl core::fmt::Display for NotificationType { impl core::fmt::Display for NotificationType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match *self { match *self {
NotificationType::INFO => "info", NotificationType::Info => write!(f, "info"),
NotificationType::ERROR => "error", NotificationType::Error(melib::error::ErrorKind::None) => write!(f, "error"),
NotificationType::NEWMAIL => "new-mail", NotificationType::Error(kind) => write!(f, "error: {}", kind),
NotificationType::NewMail => write!(f, "new mail"),
NotificationType::SentMail => write!(f, "sent mail"),
NotificationType::Saved => write!(f, "saved"),
} }
)
} }
} }