mirror of
https://github.com/soywod/himalaya.git
synced 2025-04-22 17:23:27 +00:00
improve extract subparts fn
This commit is contained in:
parent
01de392977
commit
cb8610a35f
4 changed files with 50 additions and 33 deletions
29
src/email.rs
29
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<Email<'a>> {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
// Utils
|
||||
|
||||
fn extract_text_bodies_into(mime: &str, part: &mailparse::ParsedMail, parts: &mut Vec<String>) {
|
||||
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")
|
||||
}
|
||||
|
|
45
src/imap.rs
45
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<imap::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<mailparse::MailParseError> for Error {
|
||||
fn from(err: mailparse::MailParseError) -> Error {
|
||||
Error::ParseEmailError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Result wrapper
|
||||
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
@ -58,27 +66,6 @@ pub struct ImapConnector {
|
|||
}
|
||||
|
||||
impl ImapConnector {
|
||||
fn extract_subparts_by_mime(mime: &str, part: &mailparse::ParsedMail, parts: &mut Vec<String>) {
|
||||
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<Self> {
|
||||
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<String> {
|
||||
pub fn read_email_body(&mut self, mbox: &str, uid: &str, mime: &str) -> Result<String> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue