use anyhow::{anyhow, Context, Error, Result};
use serde::Serialize;
use std::{borrow::Cow, convert::TryFrom};
use crate::{
domain::msg::{Flag, Flags},
ui::{Cell, Row, Table},
};
pub type RawEnvelope = imap::types::Fetch;
#[derive(Debug, Default, Serialize)]
pub struct Envelope<'a> {
pub id: u32,
pub flags: Flags,
pub subject: Cow<'a, str>,
pub sender: String,
pub date: Option<String>,
}
impl<'a> TryFrom<&'a RawEnvelope> for Envelope<'a> {
type Error = Error;
fn try_from(fetch: &'a RawEnvelope) -> Result<Envelope> {
let envelope = fetch
.envelope()
.ok_or_else(|| anyhow!("cannot get envelope of message {}", fetch.message))?;
let id = fetch.message;
let flags = Flags::try_from(fetch.flags())?;
let subject: Cow<str> = envelope
.subject
.as_ref()
.map(|subj| {
rfc2047_decoder::decode(subj).context(format!(
"cannot decode subject of message {}",
fetch.message
))
})
.unwrap_or_else(|| Ok(String::default()))?
.into();
let sender = envelope
.sender
.as_ref()
.and_then(|addrs| addrs.get(0))
.or_else(|| envelope.from.as_ref().and_then(|addrs| addrs.get(0)))
.ok_or_else(|| anyhow!("cannot get sender of message {}", fetch.message))?;
let sender = if let Some(ref name) = sender.name {
rfc2047_decoder::decode(&name.to_vec()).context(format!(
"cannot decode sender's name of message {}",
fetch.message,
))?
} else {
let mbox = sender
.mailbox
.as_ref()
.ok_or_else(|| anyhow!("cannot get sender's mailbox of message {}", fetch.message))
.and_then(|mbox| {
rfc2047_decoder::decode(&mbox.to_vec()).context(format!(
"cannot decode sender's mailbox of message {}",
fetch.message,
))
})?;
let host = sender
.host
.as_ref()
.ok_or_else(|| anyhow!("cannot get sender's host of message {}", fetch.message))
.and_then(|host| {
rfc2047_decoder::decode(&host.to_vec()).context(format!(
"cannot decode sender's host of message {}",
fetch.message,
))
})?;
format!("{}@{}", mbox, host)
};
let date = fetch
.internal_date()
.map(|date| date.naive_local().to_string());
Ok(Self {
id,
flags,
subject,
sender,
date,
})
}
}
impl<'a> Table for Envelope<'a> {
fn head() -> Row {
Row::new()
.cell(Cell::new("ID").bold().underline().white())
.cell(Cell::new("FLAGS").bold().underline().white())
.cell(Cell::new("SUBJECT").shrinkable().bold().underline().white())
.cell(Cell::new("SENDER").bold().underline().white())
.cell(Cell::new("DATE").bold().underline().white())
}
fn row(&self) -> Row {
let id = self.id.to_string();
let flags = self.flags.to_symbols_string();
let unseen = !self.flags.contains(&Flag::Seen);
let subject = &self.subject;
let sender = &self.sender;
let date = self.date.as_deref().unwrap_or_default();
Row::new()
.cell(Cell::new(id).bold_if(unseen).red())
.cell(Cell::new(flags).bold_if(unseen).white())
.cell(Cell::new(subject).shrinkable().bold_if(unseen).green())
.cell(Cell::new(sender).bold_if(unseen).blue())
.cell(Cell::new(date).bold_if(unseen).yellow())
}
}