mirror of
https://github.com/soywod/himalaya.git
synced 2025-04-17 14:53:37 +00:00
refactor write email command
This commit is contained in:
parent
80837044b2
commit
c7b326a695
3 changed files with 147 additions and 123 deletions
|
@ -3,7 +3,8 @@ use rfc2047_decoder;
|
|||
|
||||
use crate::table::{self, DisplayCell, DisplayRow, DisplayTable};
|
||||
|
||||
pub struct Uid(u32);
|
||||
#[derive(Debug)]
|
||||
pub struct Uid(pub u32);
|
||||
|
||||
impl Uid {
|
||||
pub fn from_fetch(fetch: &imap::types::Fetch) -> Self {
|
||||
|
@ -21,6 +22,7 @@ impl DisplayCell for Uid {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Flags<'a>(Vec<imap::types::Flag<'a>>);
|
||||
|
||||
impl Flags<'_> {
|
||||
|
@ -67,6 +69,7 @@ impl DisplayCell for Flags<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Sender(String);
|
||||
|
||||
impl Sender {
|
||||
|
@ -97,6 +100,7 @@ impl DisplayCell for Sender {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Subject(String);
|
||||
|
||||
impl Subject {
|
||||
|
@ -124,6 +128,7 @@ impl DisplayCell for Subject {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Date(String);
|
||||
|
||||
impl Date {
|
||||
|
@ -148,6 +153,7 @@ impl DisplayCell for Date {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Email<'a> {
|
||||
pub uid: Uid,
|
||||
pub flags: Flags<'a>,
|
||||
|
|
174
src/imap.rs
174
src/imap.rs
|
@ -7,6 +7,60 @@ use crate::config;
|
|||
use crate::email::Email;
|
||||
use crate::mailbox::Mailbox;
|
||||
|
||||
// Error wrapper
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
CreateTlsConnectorError(native_tls::Error),
|
||||
CreateImapSession(imap::Error),
|
||||
ReadEmailNotFoundError(String),
|
||||
ReadEmailEmptyPartError(String, String),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::CreateTlsConnectorError(err) => err.fmt(f),
|
||||
Error::CreateImapSession(err) => err.fmt(f),
|
||||
Error::ReadEmailNotFoundError(uid) => {
|
||||
write!(f, "No email found for UID {}", uid)
|
||||
}
|
||||
Error::ReadEmailEmptyPartError(uid, mime) => {
|
||||
write!(f, "No {} content found for UID {}", mime, uid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
match *self {
|
||||
Error::CreateTlsConnectorError(ref err) => Some(err),
|
||||
Error::CreateImapSession(ref err) => Some(err),
|
||||
Error::ReadEmailNotFoundError(_) => None,
|
||||
Error::ReadEmailEmptyPartError(_, _) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<native_tls::Error> for Error {
|
||||
fn from(err: native_tls::Error) -> Error {
|
||||
Error::CreateTlsConnectorError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<imap::Error> for Error {
|
||||
fn from(err: imap::Error) -> Error {
|
||||
Error::CreateImapSession(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Result wrapper
|
||||
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
||||
// Imap connector
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ImapConnector {
|
||||
pub config: config::ServerInfo,
|
||||
|
@ -14,6 +68,26 @@ 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()
|
||||
{
|
||||
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)?;
|
||||
|
@ -57,92 +131,26 @@ impl ImapConnector {
|
|||
|
||||
Ok(emails)
|
||||
}
|
||||
}
|
||||
|
||||
// Error wrapper
|
||||
pub fn read_email(&mut self, mbox: &str, uid: &str, mime: &str) -> Result<String> {
|
||||
self.sess.select(mbox)?;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
CreateTlsConnectorError(native_tls::Error),
|
||||
CreateImapSession(imap::Error),
|
||||
}
|
||||
match self.sess.uid_fetch(uid, "BODY[]")?.first() {
|
||||
None => return Err(Error::ReadEmailNotFoundError(uid.to_string())),
|
||||
Some(email_raw) => {
|
||||
let email = mailparse::parse_mail(email_raw.body().unwrap_or(&[])).unwrap();
|
||||
let mut parts = vec![];
|
||||
Self::extract_subparts_by_mime(mime, &email, &mut parts);
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::CreateTlsConnectorError(err) => err.fmt(f),
|
||||
Error::CreateImapSession(err) => err.fmt(f),
|
||||
if parts.len() == 0 {
|
||||
Err(Error::ReadEmailEmptyPartError(
|
||||
uid.to_string(),
|
||||
mime.to_string(),
|
||||
))
|
||||
} else {
|
||||
Ok(parts.join("\r\n"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
match *self {
|
||||
Error::CreateTlsConnectorError(ref err) => Some(err),
|
||||
Error::CreateImapSession(ref err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<native_tls::Error> for Error {
|
||||
fn from(err: native_tls::Error) -> Error {
|
||||
Error::CreateTlsConnectorError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<imap::Error> for Error {
|
||||
fn from(err: imap::Error) -> Error {
|
||||
Error::CreateImapSession(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Result wrapper
|
||||
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
||||
// 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()
|
||||
// {
|
||||
// parts.push(part.get_body().unwrap_or(String::new()))
|
||||
// }
|
||||
// }
|
||||
// _ => {
|
||||
// part.subparts
|
||||
// .iter()
|
||||
// .for_each(|p| extract_subparts_by_mime(mime, p, parts));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn read_email(
|
||||
// imap_sess: &mut ImapSession,
|
||||
// mbox: &str,
|
||||
// uid: &str,
|
||||
// mime: &str,
|
||||
// ) -> imap::Result<()> {
|
||||
// imap_sess.select(mbox)?;
|
||||
|
||||
// match imap_sess.uid_fetch(uid, "BODY[]")?.first() {
|
||||
// None => println!("No email found in mailbox {} with UID {}", mbox, uid),
|
||||
// Some(email_raw) => {
|
||||
// let email = mailparse::parse_mail(email_raw.body().unwrap_or(&[])).unwrap();
|
||||
// let mut parts = vec![];
|
||||
// extract_subparts_by_mime(mime, &email, &mut parts);
|
||||
|
||||
// if parts.len() == 0 {
|
||||
// println!("No {} content found for email {}!", mime, uid);
|
||||
// } else {
|
||||
// println!("{}", parts.join("\r\n"));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
|
88
src/main.rs
88
src/main.rs
|
@ -6,14 +6,25 @@ mod smtp;
|
|||
mod table;
|
||||
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use std::env::temp_dir;
|
||||
use std::fs::{remove_file, File};
|
||||
use std::io::{Read, Write};
|
||||
use std::process::{exit, Command};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::imap::ImapConnector;
|
||||
use crate::table::DisplayTable;
|
||||
|
||||
// fn new_email_tpl() -> String {
|
||||
// ["To: ", "Subject: ", ""].join("\r\n")
|
||||
// }
|
||||
fn main() {
|
||||
if let Err(err) = dispatch() {
|
||||
eprintln!("Error: {}", err);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn new_email_tpl() -> String {
|
||||
["To: ", "Subject: ", ""].join("\r\n")
|
||||
}
|
||||
|
||||
// fn forward_email_tpl() -> String {
|
||||
// ["To: ", "Subject: ", ""].join("\r\n")
|
||||
|
@ -35,12 +46,6 @@ fn uid_arg() -> Arg<'static, 'static> {
|
|||
.required(true)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if let Err(err) = dispatch() {
|
||||
panic!(err);
|
||||
}
|
||||
}
|
||||
|
||||
fn dispatch() -> Result<(), imap::Error> {
|
||||
let matches = App::new("Himalaya")
|
||||
.version("0.1.0")
|
||||
|
@ -140,63 +145,68 @@ fn dispatch() -> Result<(), imap::Error> {
|
|||
}
|
||||
}
|
||||
|
||||
// if let Some(matches) = matches.subcommand_matches("read") {
|
||||
// let mbox = matches.value_of("mailbox").unwrap();
|
||||
// let mime = matches.value_of("mime-type").unwrap();
|
||||
// let uid = matches.value_of("uid").unwrap();
|
||||
if let Some(matches) = matches.subcommand_matches("read") {
|
||||
let config = Config::new_from_file();
|
||||
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)?;
|
||||
|
||||
// imap::read_email(&mut imap_sess, mbox, uid, mime).unwrap();
|
||||
// }
|
||||
println!("{}", email);
|
||||
}
|
||||
|
||||
// if let Some(_) = matches.subcommand_matches("write") {
|
||||
// let mut draft_path = env::temp_dir();
|
||||
// draft_path.push("himalaya-draft.mail");
|
||||
if let Some(_) = matches.subcommand_matches("write") {
|
||||
let config = Config::new_from_file();
|
||||
|
||||
// fs::File::create(&draft_path)
|
||||
// .expect("Could not create draft file")
|
||||
// .write(new_email_tpl().as_bytes())
|
||||
// .expect("Could not write into draft file");
|
||||
let mut draft_path = temp_dir();
|
||||
draft_path.push("himalaya-draft.mail");
|
||||
|
||||
// process::Command::new(env!("EDITOR"))
|
||||
// .arg(&draft_path)
|
||||
// .status()
|
||||
// .expect("Could not start $EDITOR");
|
||||
File::create(&draft_path)
|
||||
.expect("Could not create draft file")
|
||||
.write(new_email_tpl().as_bytes())
|
||||
.expect("Could not write into draft file");
|
||||
|
||||
// let mut draft = String::new();
|
||||
// fs::File::open(&draft_path)
|
||||
// .expect("Could not open draft file")
|
||||
// .read_to_string(&mut draft)
|
||||
// .expect("Could not read draft file");
|
||||
Command::new(env!("EDITOR"))
|
||||
.arg(&draft_path)
|
||||
.status()
|
||||
.expect("Could not start $EDITOR");
|
||||
|
||||
// fs::remove_file(&draft_path).expect("Could not remove draft file");
|
||||
let mut draft = String::new();
|
||||
File::open(&draft_path)
|
||||
.expect("Could not open draft file")
|
||||
.read_to_string(&mut draft)
|
||||
.expect("Could not read draft file");
|
||||
|
||||
// smtp::send(&config, &draft.as_bytes());
|
||||
// }
|
||||
remove_file(&draft_path).expect("Could not remove draft file");
|
||||
|
||||
smtp::send(&config, &draft.as_bytes());
|
||||
}
|
||||
|
||||
// if let Some(_) = matches.subcommand_matches("forward") {
|
||||
// let config = Config::new_from_file();
|
||||
// let mbox = matches.value_of("mailbox").unwrap();
|
||||
// let uid = matches.value_of("uid").unwrap();
|
||||
|
||||
// let mut draft_path = env::temp_dir();
|
||||
// let mut draft_path = temp_dir();
|
||||
// draft_path.push("himalaya-draft.mail");
|
||||
|
||||
// fs::File::create(&draft_path)
|
||||
// File::create(&draft_path)
|
||||
// .expect("Could not create draft file")
|
||||
// .write(forward_email_tpl().as_bytes())
|
||||
// .expect("Could not write into draft file");
|
||||
|
||||
// process::Command::new(env!("EDITOR"))
|
||||
// Command::new(env!("EDITOR"))
|
||||
// .arg(&draft_path)
|
||||
// .status()
|
||||
// .expect("Could not start $EDITOR");
|
||||
|
||||
// let mut draft = String::new();
|
||||
// fs::File::open(&draft_path)
|
||||
// File::open(&draft_path)
|
||||
// .expect("Could not open draft file")
|
||||
// .read_to_string(&mut draft)
|
||||
// .expect("Could not read draft file");
|
||||
|
||||
// fs::remove_file(&draft_path).expect("Could not remove draft file");
|
||||
// remove_file(&draft_path).expect("Could not remove draft file");
|
||||
|
||||
// smtp::send(&config, &draft.as_bytes());
|
||||
// }
|
||||
|
|
Loading…
Add table
Reference in a new issue