mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-08 18:45:13 +00:00
refactor list mailbox command
This commit is contained in:
parent
18042b02b8
commit
80837044b2
191
src/email.rs
Normal file
191
src/email.rs
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
use imap;
|
||||||
|
use rfc2047_decoder;
|
||||||
|
|
||||||
|
use crate::table::{self, DisplayCell, DisplayRow, DisplayTable};
|
||||||
|
|
||||||
|
pub struct Uid(u32);
|
||||||
|
|
||||||
|
impl Uid {
|
||||||
|
pub fn from_fetch(fetch: &imap::types::Fetch) -> Self {
|
||||||
|
Self(fetch.uid.unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayCell for Uid {
|
||||||
|
fn styles(&self) -> &[table::Style] {
|
||||||
|
&[table::RED]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(&self) -> String {
|
||||||
|
self.0.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Flags<'a>(Vec<imap::types::Flag<'a>>);
|
||||||
|
|
||||||
|
impl Flags<'_> {
|
||||||
|
pub fn from_fetch(fetch: &imap::types::Fetch) -> Self {
|
||||||
|
let flags = fetch.flags().iter().fold(vec![], |mut flags, flag| {
|
||||||
|
use imap::types::Flag::*;
|
||||||
|
|
||||||
|
match flag {
|
||||||
|
Seen => flags.push(Seen),
|
||||||
|
Answered => flags.push(Answered),
|
||||||
|
Draft => flags.push(Draft),
|
||||||
|
Flagged => flags.push(Flagged),
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
|
||||||
|
flags
|
||||||
|
});
|
||||||
|
|
||||||
|
Self(flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayCell for Flags<'_> {
|
||||||
|
fn styles(&self) -> &[table::Style] {
|
||||||
|
&[table::WHITE]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(&self) -> String {
|
||||||
|
use imap::types::Flag::*;
|
||||||
|
|
||||||
|
let Flags(flags) = self;
|
||||||
|
let mut flags_str = String::new();
|
||||||
|
|
||||||
|
flags_str.push_str(if !flags.contains(&Seen) { &"N" } else { &" " });
|
||||||
|
flags_str.push_str(if flags.contains(&Answered) {
|
||||||
|
&"R"
|
||||||
|
} else {
|
||||||
|
&" "
|
||||||
|
});
|
||||||
|
flags_str.push_str(if flags.contains(&Draft) { &"D" } else { &" " });
|
||||||
|
flags_str.push_str(if flags.contains(&Flagged) { &"F" } else { &" " });
|
||||||
|
|
||||||
|
flags_str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Sender(String);
|
||||||
|
|
||||||
|
impl Sender {
|
||||||
|
fn try_from_fetch(fetch: &imap::types::Fetch) -> Option<String> {
|
||||||
|
let addr = fetch.envelope()?.from.as_ref()?.first()?;
|
||||||
|
|
||||||
|
addr.name
|
||||||
|
.and_then(|bytes| rfc2047_decoder::decode(bytes).ok())
|
||||||
|
.or_else(|| {
|
||||||
|
let mbox = String::from_utf8(addr.mailbox?.to_vec()).ok()?;
|
||||||
|
let host = String::from_utf8(addr.host?.to_vec()).ok()?;
|
||||||
|
Some(format!("{}@{}", mbox, host))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_fetch(fetch: &imap::types::Fetch) -> Self {
|
||||||
|
Self(Self::try_from_fetch(fetch).unwrap_or(String::new()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayCell for Sender {
|
||||||
|
fn styles(&self) -> &[table::Style] {
|
||||||
|
&[table::BLUE]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(&self) -> String {
|
||||||
|
self.0.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Subject(String);
|
||||||
|
|
||||||
|
impl Subject {
|
||||||
|
fn try_from_fetch(fetch: &imap::types::Fetch) -> Option<String> {
|
||||||
|
fetch
|
||||||
|
.envelope()?
|
||||||
|
.subject
|
||||||
|
.and_then(|bytes| rfc2047_decoder::decode(bytes).ok())
|
||||||
|
.and_then(|subject| Some(subject.replace("\r", "")))
|
||||||
|
.and_then(|subject| Some(subject.replace("\n", "")))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_fetch(fetch: &imap::types::Fetch) -> Self {
|
||||||
|
Self(Self::try_from_fetch(fetch).unwrap_or(String::new()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayCell for Subject {
|
||||||
|
fn styles(&self) -> &[table::Style] {
|
||||||
|
&[table::GREEN]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(&self) -> String {
|
||||||
|
self.0.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Date(String);
|
||||||
|
|
||||||
|
impl Date {
|
||||||
|
fn try_from_fetch(fetch: &imap::types::Fetch) -> Option<String> {
|
||||||
|
fetch
|
||||||
|
.internal_date()
|
||||||
|
.and_then(|date| Some(date.to_rfc3339()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_fetch(fetch: &imap::types::Fetch) -> Self {
|
||||||
|
Self(Self::try_from_fetch(fetch).unwrap_or(String::new()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayCell for Date {
|
||||||
|
fn styles(&self) -> &[table::Style] {
|
||||||
|
&[table::YELLOW]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(&self) -> String {
|
||||||
|
self.0.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Email<'a> {
|
||||||
|
pub uid: Uid,
|
||||||
|
pub flags: Flags<'a>,
|
||||||
|
pub from: Sender,
|
||||||
|
pub subject: Subject,
|
||||||
|
pub date: Date,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Email<'_> {
|
||||||
|
pub fn from_fetch(fetch: &imap::types::Fetch) -> Self {
|
||||||
|
Self {
|
||||||
|
uid: Uid::from_fetch(fetch),
|
||||||
|
from: Sender::from_fetch(fetch),
|
||||||
|
subject: Subject::from_fetch(fetch),
|
||||||
|
date: Date::from_fetch(fetch),
|
||||||
|
flags: Flags::from_fetch(fetch),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DisplayRow for Email<'a> {
|
||||||
|
fn to_row(&self) -> Vec<table::Cell> {
|
||||||
|
vec![
|
||||||
|
self.uid.to_cell(),
|
||||||
|
self.flags.to_cell(),
|
||||||
|
self.from.to_cell(),
|
||||||
|
self.subject.to_cell(),
|
||||||
|
self.date.to_cell(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DisplayTable<'a, Email<'a>> for Vec<Email<'a>> {
|
||||||
|
fn cols() -> &'a [&'a str] {
|
||||||
|
&["uid", "flags", "from", "subject", "date"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rows(&self) -> &Vec<Email<'a>> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
261
src/imap.rs
261
src/imap.rs
|
@ -1,150 +1,11 @@
|
||||||
use imap;
|
use imap;
|
||||||
use mailparse::{self, MailHeaderMap};
|
use mailparse::{self, MailHeaderMap};
|
||||||
use native_tls::{self, TlsConnector, TlsStream};
|
use native_tls::{self, TlsConnector, TlsStream};
|
||||||
use rfc2047_decoder;
|
|
||||||
use std::{error, fmt, net::TcpStream, result};
|
use std::{error, fmt, net::TcpStream, result};
|
||||||
|
|
||||||
use crate::config;
|
use crate::config;
|
||||||
use crate::table;
|
use crate::email::Email;
|
||||||
|
use crate::mailbox::Mailbox;
|
||||||
// Email
|
|
||||||
|
|
||||||
pub struct Uid(u32);
|
|
||||||
|
|
||||||
impl table::DisplayCell for Uid {
|
|
||||||
fn styles(&self) -> &[table::Style] {
|
|
||||||
&[table::RED]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn value(&self) -> String {
|
|
||||||
self.0.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Flags<'a>(Vec<imap::types::Flag<'a>>);
|
|
||||||
|
|
||||||
impl table::DisplayCell for Flags<'_> {
|
|
||||||
fn styles(&self) -> &[table::Style] {
|
|
||||||
&[table::WHITE]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn value(&self) -> String {
|
|
||||||
use imap::types::Flag::*;
|
|
||||||
|
|
||||||
let Flags(flags) = self;
|
|
||||||
let mut flags_str = String::new();
|
|
||||||
|
|
||||||
flags_str.push_str(if !flags.contains(&Seen) { &"N" } else { &" " });
|
|
||||||
flags_str.push_str(if flags.contains(&Answered) {
|
|
||||||
&"R"
|
|
||||||
} else {
|
|
||||||
&" "
|
|
||||||
});
|
|
||||||
flags_str.push_str(if flags.contains(&Draft) { &"D" } else { &" " });
|
|
||||||
flags_str.push_str(if flags.contains(&Flagged) { &"F" } else { &" " });
|
|
||||||
|
|
||||||
flags_str
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Sender(String);
|
|
||||||
|
|
||||||
impl table::DisplayCell for Sender {
|
|
||||||
fn styles(&self) -> &[table::Style] {
|
|
||||||
&[table::BLUE]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn value(&self) -> String {
|
|
||||||
self.0.to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Subject(String);
|
|
||||||
|
|
||||||
impl table::DisplayCell for Subject {
|
|
||||||
fn styles(&self) -> &[table::Style] {
|
|
||||||
&[table::GREEN]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn value(&self) -> String {
|
|
||||||
self.0.to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Date(String);
|
|
||||||
|
|
||||||
impl table::DisplayCell for Date {
|
|
||||||
fn styles(&self) -> &[table::Style] {
|
|
||||||
&[table::YELLOW]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn value(&self) -> String {
|
|
||||||
self.0.to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Email<'a> {
|
|
||||||
uid: Uid,
|
|
||||||
flags: Flags<'a>,
|
|
||||||
from: Sender,
|
|
||||||
subject: Subject,
|
|
||||||
date: Date,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Email<'_> {
|
|
||||||
fn first_sender_from_fetch(fetch: &imap::types::Fetch) -> Option<String> {
|
|
||||||
let addr = fetch.envelope()?.from.as_ref()?.first()?;
|
|
||||||
|
|
||||||
addr.name
|
|
||||||
.and_then(|bytes| rfc2047_decoder::decode(bytes).ok())
|
|
||||||
.or_else(|| {
|
|
||||||
let mbox = String::from_utf8(addr.mailbox?.to_vec()).ok()?;
|
|
||||||
let host = String::from_utf8(addr.host?.to_vec()).ok()?;
|
|
||||||
Some(format!("{}@{}", mbox, host))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subject_from_fetch(fetch: &imap::types::Fetch) -> Option<String> {
|
|
||||||
fetch
|
|
||||||
.envelope()?
|
|
||||||
.subject
|
|
||||||
.and_then(|bytes| rfc2047_decoder::decode(bytes).ok())
|
|
||||||
.and_then(|subject| Some(subject.replace("\r", "")))
|
|
||||||
.and_then(|subject| Some(subject.replace("\n", "")))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn date_from_fetch(fetch: &imap::types::Fetch) -> Option<String> {
|
|
||||||
fetch
|
|
||||||
.internal_date()
|
|
||||||
.and_then(|date| Some(date.to_rfc3339()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> table::DisplayRow for Email<'a> {
|
|
||||||
fn to_row(&self) -> Vec<table::Cell> {
|
|
||||||
use table::DisplayCell;
|
|
||||||
|
|
||||||
vec![
|
|
||||||
self.uid.to_cell(),
|
|
||||||
self.flags.to_cell(),
|
|
||||||
self.from.to_cell(),
|
|
||||||
self.subject.to_cell(),
|
|
||||||
self.date.to_cell(),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> table::DisplayTable<'a, Email<'a>> for Vec<Email<'a>> {
|
|
||||||
fn cols() -> &'a [&'a str] {
|
|
||||||
&["uid", "flags", "from", "subject", "date"]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rows(&self) -> &Vec<Email<'a>> {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IMAP Connector
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ImapConnector {
|
pub struct ImapConnector {
|
||||||
|
@ -163,6 +24,17 @@ impl ImapConnector {
|
||||||
Ok(Self { config, sess })
|
Ok(Self { config, sess })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn list_mailboxes(&mut self) -> Result<Vec<Mailbox<'_>>> {
|
||||||
|
let mboxes = self
|
||||||
|
.sess
|
||||||
|
.list(Some(""), Some("*"))?
|
||||||
|
.iter()
|
||||||
|
.map(Mailbox::from_name)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Ok(mboxes)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_emails(&mut self, mbox: &str, query: &str) -> Result<Vec<Email<'_>>> {
|
pub fn read_emails(&mut self, mbox: &str, query: &str) -> Result<Vec<Email<'_>>> {
|
||||||
self.sess.select(mbox)?;
|
self.sess.select(mbox)?;
|
||||||
|
|
||||||
|
@ -180,29 +52,7 @@ impl ImapConnector {
|
||||||
"(UID ENVELOPE INTERNALDATE)",
|
"(UID ENVELOPE INTERNALDATE)",
|
||||||
)?
|
)?
|
||||||
.iter()
|
.iter()
|
||||||
.map(|fetch| {
|
.map(Email::from_fetch)
|
||||||
let flags = fetch.flags().iter().fold(vec![], |mut flags, flag| {
|
|
||||||
use imap::types::Flag::*;
|
|
||||||
|
|
||||||
match flag {
|
|
||||||
Seen => flags.push(Seen),
|
|
||||||
Answered => flags.push(Answered),
|
|
||||||
Draft => flags.push(Draft),
|
|
||||||
Flagged => flags.push(Flagged),
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
|
|
||||||
flags
|
|
||||||
});
|
|
||||||
|
|
||||||
Email {
|
|
||||||
uid: Uid(fetch.uid.unwrap()),
|
|
||||||
from: Sender(Email::first_sender_from_fetch(fetch).unwrap_or(String::new())),
|
|
||||||
subject: Subject(Email::subject_from_fetch(fetch).unwrap_or(String::new())),
|
|
||||||
date: Date(Email::date_from_fetch(fetch).unwrap_or(String::new())),
|
|
||||||
flags: Flags(flags),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
Ok(emails)
|
Ok(emails)
|
||||||
|
@ -251,75 +101,26 @@ impl From<imap::Error> for Error {
|
||||||
|
|
||||||
type Result<T> = result::Result<T, Error>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
// pub fn list_mailboxes(imap_sess: &mut ImapSession) -> imap::Result<()> {
|
// fn extract_subparts_by_mime(mime: &str, part: &mailparse::ParsedMail, parts: &mut Vec<String>) {
|
||||||
// let mboxes = imap_sess.list(Some(""), Some("*"))?;
|
// match part.subparts.len() {
|
||||||
|
// 0 => {
|
||||||
// let table_head = vec![
|
// if part
|
||||||
// table::Cell::new(
|
// .get_headers()
|
||||||
// vec![table::BOLD, table::UNDERLINE, table::WHITE],
|
// .get_first_value("content-type")
|
||||||
// String::from("DELIM"),
|
// .and_then(|v| if v.starts_with(mime) { Some(()) } else { None })
|
||||||
// ),
|
// .is_some()
|
||||||
// table::Cell::new(
|
// {
|
||||||
// vec![table::BOLD, table::UNDERLINE, table::WHITE],
|
// parts.push(part.get_body().unwrap_or(String::new()))
|
||||||
// String::from("NAME"),
|
// }
|
||||||
// ),
|
// }
|
||||||
// table::Cell::new(
|
// _ => {
|
||||||
// vec![table::BOLD, table::UNDERLINE, table::WHITE],
|
// part.subparts
|
||||||
// String::from("ATTRIBUTES"),
|
// .iter()
|
||||||
// ),
|
// .for_each(|p| extract_subparts_by_mime(mime, p, parts));
|
||||||
// ];
|
// }
|
||||||
|
|
||||||
// let mut table_rows = mboxes
|
|
||||||
// .iter()
|
|
||||||
// .map(|mbox| {
|
|
||||||
// vec![
|
|
||||||
// table::Cell::new(
|
|
||||||
// vec![table::BLUE],
|
|
||||||
// mbox.delimiter().unwrap_or("").to_string(),
|
|
||||||
// ),
|
|
||||||
// table::Cell::new(vec![table::GREEN], mbox.name().to_string()),
|
|
||||||
// table::Cell::new(
|
|
||||||
// vec![table::YELLOW],
|
|
||||||
// mbox.attributes()
|
|
||||||
// .iter()
|
|
||||||
// .map(|a| format!("{:?}", a))
|
|
||||||
// .collect::<Vec<_>>()
|
|
||||||
// .join(", "),
|
|
||||||
// ),
|
|
||||||
// ]
|
|
||||||
// })
|
|
||||||
// .collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// if table_rows.len() == 0 {
|
|
||||||
// println!("No email found!");
|
|
||||||
// } else {
|
|
||||||
// table_rows.insert(0, table_head);
|
|
||||||
// println!("{}", table::render(table_rows));
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// Ok(())
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
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(
|
// pub fn read_email(
|
||||||
// imap_sess: &mut ImapSession,
|
// imap_sess: &mut ImapSession,
|
||||||
// mbox: &str,
|
// mbox: &str,
|
||||||
|
|
120
src/mailbox.rs
Normal file
120
src/mailbox.rs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
use imap;
|
||||||
|
|
||||||
|
use crate::table::{self, DisplayCell, DisplayRow, DisplayTable};
|
||||||
|
|
||||||
|
pub struct Delim(String);
|
||||||
|
|
||||||
|
impl Delim {
|
||||||
|
pub fn from_name(name: &imap::types::Name) -> Self {
|
||||||
|
Self(name.delimiter().unwrap_or("/").to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayCell for Delim {
|
||||||
|
fn styles(&self) -> &[table::Style] {
|
||||||
|
&[table::BLUE]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(&self) -> String {
|
||||||
|
self.0.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Name(String);
|
||||||
|
|
||||||
|
impl Name {
|
||||||
|
pub fn from_name(name: &imap::types::Name) -> Self {
|
||||||
|
Self(name.name().to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayCell for Name {
|
||||||
|
fn styles(&self) -> &[table::Style] {
|
||||||
|
&[table::GREEN]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(&self) -> String {
|
||||||
|
self.0.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Attributes<'a>(Vec<imap::types::NameAttribute<'a>>);
|
||||||
|
|
||||||
|
impl Attributes<'_> {
|
||||||
|
pub fn from_name(name: &imap::types::Name) -> Self {
|
||||||
|
let attrs = name.attributes().iter().fold(vec![], |mut attrs, attr| {
|
||||||
|
use imap::types::NameAttribute::*;
|
||||||
|
|
||||||
|
match attr {
|
||||||
|
NoInferiors => attrs.push(NoInferiors),
|
||||||
|
NoSelect => attrs.push(NoSelect),
|
||||||
|
Marked => attrs.push(Marked),
|
||||||
|
Unmarked => attrs.push(Unmarked),
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
|
||||||
|
attrs
|
||||||
|
});
|
||||||
|
|
||||||
|
Self(attrs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayCell for Attributes<'_> {
|
||||||
|
fn styles(&self) -> &[table::Style] {
|
||||||
|
&[table::YELLOW]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(&self) -> String {
|
||||||
|
use imap::types::NameAttribute::*;
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.map(|attr| match attr {
|
||||||
|
NoInferiors => vec!["no inferiors"],
|
||||||
|
NoSelect => vec!["no select"],
|
||||||
|
Marked => vec!["marked"],
|
||||||
|
Unmarked => vec!["unmarked"],
|
||||||
|
_ => vec![],
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.concat()
|
||||||
|
.join(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Mailbox<'a> {
|
||||||
|
pub delim: Delim,
|
||||||
|
pub name: Name,
|
||||||
|
pub attributes: Attributes<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mailbox<'_> {
|
||||||
|
pub fn from_name(name: &imap::types::Name) -> Self {
|
||||||
|
Self {
|
||||||
|
delim: Delim::from_name(name),
|
||||||
|
name: Name::from_name(name),
|
||||||
|
attributes: Attributes::from_name(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DisplayRow for Mailbox<'a> {
|
||||||
|
fn to_row(&self) -> Vec<table::Cell> {
|
||||||
|
vec![
|
||||||
|
self.delim.to_cell(),
|
||||||
|
self.name.to_cell(),
|
||||||
|
self.attributes.to_cell(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DisplayTable<'a, Mailbox<'a>> for Vec<Mailbox<'a>> {
|
||||||
|
fn cols() -> &'a [&'a str] {
|
||||||
|
&["delim", "name", "attributes"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rows(&self) -> &Vec<Mailbox<'a>> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
26
src/main.rs
26
src/main.rs
|
@ -1,5 +1,7 @@
|
||||||
mod config;
|
mod config;
|
||||||
|
mod email;
|
||||||
mod imap;
|
mod imap;
|
||||||
|
mod mailbox;
|
||||||
mod smtp;
|
mod smtp;
|
||||||
mod table;
|
mod table;
|
||||||
|
|
||||||
|
@ -9,13 +11,13 @@ use crate::config::Config;
|
||||||
use crate::imap::ImapConnector;
|
use crate::imap::ImapConnector;
|
||||||
use crate::table::DisplayTable;
|
use crate::table::DisplayTable;
|
||||||
|
|
||||||
fn new_email_tpl() -> String {
|
// fn new_email_tpl() -> String {
|
||||||
["To: ", "Subject: ", ""].join("\r\n")
|
// ["To: ", "Subject: ", ""].join("\r\n")
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn forward_email_tpl() -> String {
|
// fn forward_email_tpl() -> String {
|
||||||
["To: ", "Subject: ", ""].join("\r\n")
|
// ["To: ", "Subject: ", ""].join("\r\n")
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn mailbox_arg() -> Arg<'static, 'static> {
|
fn mailbox_arg() -> Arg<'static, 'static> {
|
||||||
Arg::with_name("mailbox")
|
Arg::with_name("mailbox")
|
||||||
|
@ -93,10 +95,14 @@ fn dispatch() -> Result<(), imap::Error> {
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
// if let Some(_) = matches.subcommand_matches("list") {
|
if let Some(_) = matches.subcommand_matches("list") {
|
||||||
// let config = Config::new_from_file();
|
let config = Config::new_from_file();
|
||||||
// ImapConnector::new(&config.imap).list_mailboxes().unwrap();
|
let mboxes = ImapConnector::new(config.imap)?
|
||||||
// }
|
.list_mailboxes()?
|
||||||
|
.to_table();
|
||||||
|
|
||||||
|
println!("{}", mboxes);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("search") {
|
if let Some(matches) = matches.subcommand_matches("search") {
|
||||||
let config = Config::new_from_file();
|
let config = Config::new_from_file();
|
||||||
|
|
Loading…
Reference in a new issue