diff --git a/src/email.rs b/src/email.rs index c6b72c1..257253e 100644 --- a/src/email.rs +++ b/src/email.rs @@ -1,4 +1,5 @@ use imap; +use mailparse::{self, MailHeaderMap}; use rfc2047_decoder; use crate::table::{self, DisplayCell, DisplayRow, DisplayTable}; @@ -195,3 +196,31 @@ impl<'a> DisplayTable<'a, Email<'a>> for Vec> { self } } + +// Utils + +fn extract_text_bodies_into(mime: &str, part: &mailparse::ParsedMail, parts: &mut Vec) { + match part.subparts.len() { + 0 => { + if part + .get_headers() + .get_first_value("content-type") + .and_then(|v| if v.starts_with(mime) { Some(()) } else { None }) + .is_some() + { + parts.push(part.get_body().unwrap_or(String::new())) + } + } + _ => { + part.subparts + .iter() + .for_each(|part| extract_text_bodies_into(mime, part, parts)); + } + } +} + +pub fn extract_text_bodies(mime: &str, email: &mailparse::ParsedMail) -> String { + let mut parts = vec![]; + extract_text_bodies_into(mime, email, &mut parts); + parts.join("\r\n") +} diff --git a/src/imap.rs b/src/imap.rs index d2758b4..06d0aa9 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -1,10 +1,10 @@ use imap; -use mailparse::{self, MailHeaderMap}; +use mailparse; use native_tls::{self, TlsConnector, TlsStream}; use std::{fmt, net::TcpStream, result}; use crate::config; -use crate::email::Email; +use crate::email::{self, Email}; use crate::mailbox::Mailbox; // Error wrapper @@ -13,6 +13,7 @@ use crate::mailbox::Mailbox; pub enum Error { CreateTlsConnectorError(native_tls::Error), CreateImapSession(imap::Error), + ParseEmailError(mailparse::MailParseError), ReadEmailNotFoundError(String), ReadEmailEmptyPartError(String, String), } @@ -23,6 +24,7 @@ impl fmt::Display for Error { match self { Error::CreateTlsConnectorError(err) => err.fmt(f), Error::CreateImapSession(err) => err.fmt(f), + Error::ParseEmailError(err) => err.fmt(f), Error::ReadEmailNotFoundError(uid) => { write!(f, "no email found for uid {}", uid) } @@ -45,6 +47,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: mailparse::MailParseError) -> Error { + Error::ParseEmailError(err) + } +} + // Result wrapper type Result = result::Result; @@ -58,27 +66,6 @@ pub struct ImapConnector { } impl ImapConnector { - fn extract_subparts_by_mime(mime: &str, part: &mailparse::ParsedMail, parts: &mut Vec) { - match part.subparts.len() { - 0 => { - if part - .get_headers() - .get_first_value("content-type") - .and_then(|v| if v.starts_with(mime) { Some(()) } else { None }) - .is_some() - { - // TODO: push part instead of body str - parts.push(part.get_body().unwrap_or(String::new())) - } - } - _ => { - part.subparts - .iter() - .for_each(|p| Self::extract_subparts_by_mime(mime, p, parts)); - } - } - } - pub fn new(config: config::ServerInfo) -> Result { let tls = TlsConnector::new()?; let client = imap::connect(config.get_addr(), &config.host, &tls)?; @@ -123,23 +110,23 @@ impl ImapConnector { Ok(emails) } - pub fn read_email(&mut self, mbox: &str, uid: &str, mime: &str) -> Result { + pub fn read_email_body(&mut self, mbox: &str, uid: &str, mime: &str) -> Result { self.sess.select(mbox)?; match self.sess.uid_fetch(uid, "BODY[]")?.first() { None => Err(Error::ReadEmailNotFoundError(uid.to_string())), Some(fetch) => { - let email = mailparse::parse_mail(fetch.body().unwrap_or(&[])).unwrap(); - let mut parts = vec![]; - Self::extract_subparts_by_mime(mime, &email, &mut parts); + let bytes = fetch.body().unwrap_or(&[]); + let email = mailparse::parse_mail(bytes)?; + let bodies = email::extract_text_bodies(&mime, &email); - if parts.len() == 0 { + if bodies.is_empty() { Err(Error::ReadEmailEmptyPartError( uid.to_string(), mime.to_string(), )) } else { - Ok(parts.join("\r\n")) + Ok(bodies) } } } diff --git a/src/main.rs b/src/main.rs index b91f7f5..dc7c565 100644 --- a/src/main.rs +++ b/src/main.rs @@ -175,16 +175,18 @@ fn run() -> Result<()> { let mbox = matches.value_of("mailbox").unwrap(); let uid = matches.value_of("uid").unwrap(); let mime = matches.value_of("mime-type").unwrap(); - let email = ImapConnector::new(config.imap)?.read_email(&mbox, &uid, &mime)?; + let body = ImapConnector::new(config.imap)?.read_email_body(&mbox, &uid, &mime)?; - println!("{}", email); + println!("{}", body); } if let Some(_) = matches.subcommand_matches("write") { let config = Config::new_from_file()?; let draft = editor::open_with_new_template()?; + println!("Sending ..."); smtp::send(&config, draft.as_bytes()); + println!("Done!"); } Ok(()) diff --git a/src/smtp.rs b/src/smtp.rs index 7016ff2..fde2898 100644 --- a/src/smtp.rs +++ b/src/smtp.rs @@ -45,9 +45,8 @@ pub fn send(config: &config::Config, bytes: &[u8]) { .credentials(creds) .build(); - println!("Sending ..."); match mailer.send(&email) { - Ok(_) => println!("Email sent successfully!"), + Ok(_) => (), Err(e) => panic!("Could not send email: {:?}", e), } }