summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManos Pitsidianakis <el13635@mail.ntua.gr>2019-09-27 13:18:59 +0300
committerManos Pitsidianakis <el13635@mail.ntua.gr>2019-09-27 13:40:02 +0300
commit68c40a292091c9d0378ffcf31e53afd9535ac6a6 (patch)
tree855b8baa8292bae451f4a58691c02f49b9c7ac4a
parentd44a68ec6950c533cf67ee2a34f9888a4ae569cc (diff)
melib: return Result with error when an IO operation fails
Don't unwrap anything because this might be temporary, for example a short IMAP disconnection.
-rw-r--r--melib/src/email.rs44
-rw-r--r--melib/src/email/compose.rs7
-rw-r--r--ui/src/components/mail/compose.rs6
-rw-r--r--ui/src/components/mail/listing/compact.rs42
-rw-r--r--ui/src/components/mail/listing/conversations.rs8
-rw-r--r--ui/src/components/mail/view.rs62
-rw-r--r--ui/src/components/utilities.rs23
7 files changed, 144 insertions, 48 deletions
diff --git a/melib/src/email.rs b/melib/src/email.rs
index ca69f928..39a4439e 100644
--- a/melib/src/email.rs
+++ b/melib/src/email.rs
@@ -376,16 +376,18 @@ impl Envelope {
let _strings: Vec<String> = self.to.iter().map(|a| format!("{}", a)).collect();
_strings.join(", ")
}
- pub fn bytes(&self, mut operation: Box<dyn BackendOp>) -> Vec<u8> {
- operation
- .as_bytes()
- .map(|v| v.into())
- .unwrap_or_else(|_| Vec::new())
+
+ /// Requests bytes from backend and thus can fail
+ pub fn bytes(&self, mut operation: Box<dyn BackendOp>) -> Result<Vec<u8>> {
+ operation.as_bytes().map(|v| v.to_vec())
}
+
pub fn body_bytes(&self, bytes: &[u8]) -> Attachment {
let builder = AttachmentBuilder::new(bytes);
builder.build()
}
+
+ /// Requests bytes from backend and thus can fail
pub fn headers<'a>(&self, bytes: &'a [u8]) -> Result<Vec<(&'a str, &'a str)>> {
let ret = parser::headers(bytes).to_full_result()?;
let len = ret.len();
@@ -397,34 +399,14 @@ impl Envelope {
})
})
}
- pub fn body(&self, mut operation: Box<dyn BackendOp>) -> Attachment {
+
+ /// Requests bytes from backend and thus can fail
+ pub fn body(&self, mut operation: Box<dyn BackendOp>) -> Result<Attachment> {
debug!("searching body for {:?}", self.message_id_display());
- let file = operation.as_bytes();
- self.body_bytes(file.unwrap())
- /*
- let (headers, body) = match parser::mail(file.unwrap()).to_full_result() {
- Ok(v) => v,
- Err(_) => {
- debug!("2error in parsing mail\n");
- let error_msg = b"Mail cannot be shown because of errors.";
- let mut builder = AttachmentBuilder::new(error_msg);
- return builder.build();
- }
- };
- let mut builder = AttachmentBuilder::new(body);
- for (name, value) in headers {
- if value.len() == 1 && value.is_empty() {
- continue;
- }
- if name.eq_ignore_ascii_case(b"content-transfer-encoding") {
- builder.content_transfer_encoding(value);
- } else if name.eq_ignore_ascii_case(b"content-type") {
- builder.content_type(value);
- }
- }
- builder.build()
- */
+ let file = operation.as_bytes()?;
+ Ok(self.body_bytes(file))
}
+
pub fn subject(&self) -> Cow<str> {
match self.subject {
Some(ref s) => String::from_utf8_lossy(s),
diff --git a/melib/src/email/compose.rs b/melib/src/email/compose.rs
index 29a62e45..17b6c16a 100644
--- a/melib/src/email/compose.rs
+++ b/melib/src/email/compose.rs
@@ -113,7 +113,7 @@ impl str::FromStr for Draft {
}
impl Draft {
- pub fn edit(envelope: &Envelope, mut op: Box<dyn BackendOp>) -> Self {
+ pub fn edit(envelope: &Envelope, mut op: Box<dyn BackendOp>) -> Result<Self> {
let mut ret = Draft::default();
//TODO: Inform user if error
{
@@ -128,10 +128,11 @@ impl Draft {
}
}
- ret.body = envelope.body(op).text();
+ ret.body = envelope.body(op)?.text();
- ret
+ Ok(ret)
}
+
pub fn set_header(&mut self, header: &str, value: String) {
if self.headers.insert(header.to_string(), value).is_none() {
self.header_order.push(header.to_string());
diff --git a/ui/src/components/mail/compose.rs b/ui/src/components/mail/compose.rs
index 3f6da8eb..6c268772 100644
--- a/ui/src/components/mail/compose.rs
+++ b/ui/src/components/mail/compose.rs
@@ -128,15 +128,15 @@ impl Composer {
* msg: index of message we reply to in thread_nodes
* context: current context
*/
- pub fn edit(account_pos: usize, h: EnvelopeHash, context: &Context) -> Self {
+ pub fn edit(account_pos: usize, h: EnvelopeHash, context: &Context) -> Result<Self> {
let mut ret = Composer::default();
let op = context.accounts[account_pos].operation(h);
let envelope: &Envelope = context.accounts[account_pos].get_env(&h);
- ret.draft = Draft::edit(envelope, op);
+ ret.draft = Draft::edit(envelope, op)?;
ret.account_cursor = account_pos;
- ret
+ Ok(ret)
}
pub fn with_context(
coordinates: (usize, usize, usize),
diff --git a/ui/src/components/mail/listing/compact.rs b/ui/src/components/mail/listing/compact.rs
index ecbec4ad..3aef9145 100644
--- a/ui/src/components/mail/listing/compact.rs
+++ b/ui/src/components/mail/listing/compact.rs
@@ -352,6 +352,7 @@ impl ListingTrait for CompactListing {
}
self.filter_term.clear();
+ let mut error: Option<(EnvelopeHash, MeliError)> = None;
for (i, h) in self.order.keys().enumerate() {
let account = &context.accounts[self.cursor_pos.0];
let envelope = &account.collection[h];
@@ -367,8 +368,14 @@ impl ListingTrait for CompactListing {
self.selection.insert(*h, false);
continue;
}
- let op = account.operation(*h);
- let body = envelope.body(op);
+ let op = account.operation(env_hash);
+ let body = match envelope.body(op) {
+ Ok(b) => b,
+ Err(e) => {
+ error = Some((env_hash, e));
+ break;
+ }
+ };
let decoded = decode_rec(&body, None);
let body_text = String::from_utf8_lossy(&decoded);
if body_text.contains(&filter_term) {
@@ -377,22 +384,45 @@ impl ListingTrait for CompactListing {
self.selection.insert(*h, false);
}
}
- if !self.filtered_selection.is_empty() {
+
+ if let Some((env_hash, error)) = error {
+ self.length = 0;
+ let message = format!("Error: {}", error.to_string());
+ log(
+ format!(
+ "Failed to open envelope {}: {}",
+ context.accounts[self.new_cursor_pos.0]
+ .get_env(&env_hash)
+ .message_id_display(),
+ error.to_string()
+ ),
+ ERROR,
+ );
+ self.data_columns.columns[0] = CellBuffer::new(message.len(), 1, Cell::with_char(' '));
+ write_string_to_grid(
+ &message,
+ &mut self.data_columns.columns[0],
+ Color::Default,
+ Color::Default,
+ Attr::Default,
+ ((0, 0), (message.len() - 1, 0)),
+ false,
+ );
+ } else if !self.filtered_selection.is_empty() {
self.filter_term = filter_term.to_string();
self.cursor_pos.2 = std::cmp::min(self.filtered_selection.len() - 1, self.cursor_pos.2);
self.length = self.filtered_selection.len();
} else {
self.length = 0;
let message = format!("No results for `{}`.", filter_term);
- self.data_columns.columns[0] =
- CellBuffer::new(message.len(), self.length + 1, Cell::with_char(' '));
+ self.data_columns.columns[0] = CellBuffer::new(message.len(), 1, Cell::with_char(' '));
write_string_to_grid(
&message,
&mut self.data_columns.columns[0],
Color::Default,
Color::Default,
Attr::Default,
- ((0, 0), (MAX_COLS - 1, 0)),
+ ((0, 0), (message.len() - 1, 0)),
false,
);
}
diff --git a/ui/src/components/mail/listing/conversations.rs b/ui/src/components/mail/listing/conversations.rs
index 716f0882..f40c3583 100644
--- a/ui/src/components/mail/listing/conversations.rs
+++ b/ui/src/components/mail/listing/conversations.rs
@@ -417,7 +417,13 @@ impl ListingTrait for ConversationsListing {
continue;
}
let op = account.operation(env_hash);
- let body = envelope.body(op);
+ let body = match envelope.body(op) {
+ Ok(b) => b,
+ Err(e) => {
+ error = Some(e);
+ break;
+ }
+ };
let decoded = decode_rec(&body, None);
let body_text = String::from_utf8_lossy(&decoded);
if body_text.contains(&filter_term) {
diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs
index cd256f6c..529d8799 100644
--- a/ui/src/components/mail/view.rs
+++ b/ui/src/components/mail/view.rs
@@ -597,7 +597,25 @@ impl Component for MailView {
let account = &mut context.accounts[self.coordinates.0];
let envelope: &Envelope = &account.get_env(&self.coordinates.2);
let op = account.operation(envelope.hash());
- envelope.body(op)
+ match envelope.body(op) {
+ Ok(body) => body,
+ Err(e) => {
+ context.replies.push_back(UIEvent::Notification(
+ Some("Failed to open e-mail".to_string()),
+ e.to_string(),
+ Some(NotificationType::ERROR),
+ ));
+ log(
+ format!(
+ "Failed to open envelope {}: {}",
+ envelope.message_id_display(),
+ e.to_string()
+ ),
+ ERROR,
+ );
+ return;
+ }
+ }
};
match self.mode {
ViewMode::Attachment(aidx) if body.attachments()[aidx].is_html() => {
@@ -799,7 +817,27 @@ impl Component for MailView {
let account = &mut context.accounts[self.coordinates.0];
let envelope: &Envelope = &account.get_env(&self.coordinates.2);
let op = account.operation(envelope.hash());
- if let Some(u) = envelope.body(op).attachments().get(lidx) {
+
+ let attachments = match envelope.body(op) {
+ Ok(body) => body.attachments(),
+ Err(e) => {
+ context.replies.push_back(UIEvent::Notification(
+ Some("Failed to open e-mail".to_string()),
+ e.to_string(),
+ Some(NotificationType::ERROR),
+ ));
+ log(
+ format!(
+ "Failed to open envelope {}: {}",
+ envelope.message_id_display(),
+ e.to_string()
+ ),
+ ERROR,
+ );
+ return true;
+ }
+ };
+ if let Some(u) = attachments.get(lidx) {
match u.content_type() {
ContentType::MessageRfc822 => {
match EnvelopeWrapper::new(u.body().to_vec()) {
@@ -910,7 +948,25 @@ impl Component for MailView {
let envelope: &Envelope = &account.get_env(&self.coordinates.2);
let finder = LinkFinder::new();
let op = account.operation(envelope.hash());
- let t = envelope.body(op).text().to_string();
+ let t = match envelope.body(op) {
+ Ok(body) => body.text().to_string(),
+ Err(e) => {
+ context.replies.push_back(UIEvent::Notification(
+ Some("Failed to open e-mail".to_string()),
+ e.to_string(),
+ Some(NotificationType::ERROR),
+ ));
+ log(
+ format!(
+ "Failed to open envelope {}: {}",
+ envelope.message_id_display(),
+ e.to_string()
+ ),
+ ERROR,
+ );
+ return true;
+ }
+ };
let links: Vec<Link> = finder.links(&t).collect();
if let Some(u) = links.get(lidx) {
u.as_str().to_string()
diff --git a/ui/src/components/utilities.rs b/ui/src/components/utilities.rs
index 8fa94552..02711fbe 100644
--- a/ui/src/components/utilities.rs
+++ b/ui/src/components/utilities.rs
@@ -1455,7 +1455,28 @@ impl Component for Tabbed {
return true;
}
UIEvent::Action(Tab(Edit(account_pos, msg))) => {
- self.add_component(Box::new(Composer::edit(account_pos, msg, context)));
+ let composer = match Composer::edit(account_pos, msg, context) {
+ Ok(c) => c,
+ Err(e) => {
+ context.replies.push_back(UIEvent::Notification(
+ Some("Failed to open e-mail".to_string()),
+ e.to_string(),
+ Some(NotificationType::ERROR),
+ ));
+ log(
+ format!(
+ "Failed to open envelope {}: {}",
+ context.accounts[account_pos]
+ .get_env(&msg)
+ .message_id_display(),
+ e.to_string()
+ ),
+ ERROR,
+ );
+ return true;
+ }
+ };
+ self.add_component(Box::new(composer));
self.cursor_pos = self.children.len() - 1;
self.children[self.cursor_pos].set_dirty();
return true;