mirror of
https://github.com/FliegendeWurst/inboxid.git
synced 2024-11-22 00:45:01 +00:00
Basic inbox viewer
This commit is contained in:
parent
ffda7e2179
commit
1a6dbf29e7
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -17,6 +17,11 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ascii_table"
|
||||||
|
version = "3.0.2"
|
||||||
|
source = "git+https://gitlab.com/arnekeller/ascii-table.git?rev=7fffb5d93b8c63283fc1359ee3c6dbfcf12ed90b#7fffb5d93b8c63283fc1359ee3c6dbfcf12ed90b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -172,9 +177,11 @@ dependencies = [
|
|||||||
name = "inboxid"
|
name = "inboxid"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ascii_table",
|
||||||
"imap",
|
"imap",
|
||||||
"itertools",
|
"itertools",
|
||||||
"maildir",
|
"maildir",
|
||||||
|
"mailparse",
|
||||||
"rustls-connector",
|
"rustls-connector",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -11,4 +11,6 @@ license = "GPL-3.0-or-later"
|
|||||||
imap = { version = "2.4.1", default-features = false }
|
imap = { version = "2.4.1", default-features = false }
|
||||||
itertools = "0.10.0"
|
itertools = "0.10.0"
|
||||||
maildir = { path = "../maildir" }
|
maildir = { path = "../maildir" }
|
||||||
|
mailparse = "0.13.2"
|
||||||
rustls-connector = "0.13.1"
|
rustls-connector = "0.13.1"
|
||||||
|
ascii_table = { git = "https://gitlab.com/arnekeller/ascii-table.git", rev = "7fffb5d93b8c63283fc1359ee3c6dbfcf12ed90b" }
|
||||||
|
@ -1,41 +1,29 @@
|
|||||||
use std::{cmp, env, error::Error, fs, io, net::TcpStream, time::Duration};
|
use std::{cmp, env, fs, io, time::Duration};
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use maildir::Maildir;
|
use maildir::Maildir;
|
||||||
use rustls_connector::RustlsConnector;
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
use inboxid::*;
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
let host = env::var("MAILHOST").expect("missing envvar MAILHOST");
|
let host = env::var("MAILHOST").expect("missing envvar MAILHOST");
|
||||||
let user = env::var("MAILUSER").expect("missing envvar MAILUSER");
|
let user = env::var("MAILUSER").expect("missing envvar MAILUSER");
|
||||||
let password = env::var("MAILPASSWORD").expect("missing envvar MAILPASSWORD");
|
let password = env::var("MAILPASSWORD").expect("missing envvar MAILPASSWORD");
|
||||||
let maildir = env::var("MAILDIR").expect("missing envvar MAILDIR");
|
let maildir = get_maildir("INBOX")?;
|
||||||
let maildir = Maildir::from(maildir);
|
|
||||||
maildir.create_dirs()?;
|
|
||||||
let port = 993;
|
let port = 993;
|
||||||
|
|
||||||
fetch_inbox_top(&host, user, password, port, "INBOX", maildir)
|
fetch_inbox_top(&host, &user, &password, port, "INBOX", maildir)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_inbox_top(
|
fn fetch_inbox_top(
|
||||||
host: &str,
|
host: &str,
|
||||||
user: String,
|
user: &str,
|
||||||
password: String,
|
password: &str,
|
||||||
port: u16,
|
port: u16,
|
||||||
mailbox: &str,
|
mailbox: &str,
|
||||||
maildir: Maildir,
|
maildir: Maildir,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<()> {
|
||||||
println!("connecting..");
|
let mut imap_session = connect(host, port, user, password)?;
|
||||||
let stream = TcpStream::connect((host, port))?;
|
|
||||||
let tls = RustlsConnector::new_with_native_certs()?;
|
|
||||||
println!("initializing TLS..");
|
|
||||||
let tlsstream = tls.connect(host, stream)?;
|
|
||||||
println!("initializing client..");
|
|
||||||
let client = imap::Client::new(tlsstream);
|
|
||||||
|
|
||||||
// the client we have here is unauthenticated.
|
|
||||||
// to do anything useful with the e-mails, we need to log in
|
|
||||||
println!("logging in..");
|
|
||||||
let mut imap_session = client.login(&user, &password).map_err(|e| e.0)?;
|
|
||||||
println!("getting capabilities..");
|
println!("getting capabilities..");
|
||||||
let caps = imap_session.capabilities()?;
|
let caps = imap_session.capabilities()?;
|
||||||
println!("capabilities: {}", caps.iter().map(|x| format!("{:?}", x)).join(" "));
|
println!("capabilities: {}", caps.iter().map(|x| format!("{:?}", x)).join(" "));
|
||||||
@ -95,16 +83,16 @@ fn fetch_inbox_top(
|
|||||||
}
|
}
|
||||||
|
|
||||||
trait MaildirExtension {
|
trait MaildirExtension {
|
||||||
fn get_file(&self, name: &str) -> Result<String, io::Error>;
|
fn get_file(&self, name: &str) -> std::result::Result<String, io::Error>;
|
||||||
fn save_file(&self, name: &str, content: &str) -> Result<(), io::Error>;
|
fn save_file(&self, name: &str, content: &str) -> std::result::Result<(), io::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaildirExtension for Maildir {
|
impl MaildirExtension for Maildir {
|
||||||
fn get_file(&self, name: &str) -> Result<String, io::Error> {
|
fn get_file(&self, name: &str) -> std::result::Result<String, io::Error> {
|
||||||
fs::read_to_string(self.path().join(name))
|
fs::read_to_string(self.path().join(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_file(&self, name: &str, content: &str) -> Result<(), io::Error> {
|
fn save_file(&self, name: &str, content: &str) -> std::result::Result<(), io::Error> {
|
||||||
fs::write(self.path().join(name), content)
|
fs::write(self.path().join(name), content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
src/bin/view.rs
Normal file
48
src/bin/view.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
use ascii_table::{Align, AsciiTable, Column};
|
||||||
|
use mailparse::MailHeaderMap;
|
||||||
|
|
||||||
|
use inboxid::*;
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
show_listing("INBOX")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_listing(mailbox: &str) -> Result<()> {
|
||||||
|
let maildir = get_maildir(mailbox)?;
|
||||||
|
|
||||||
|
let mut rows = Vec::new();
|
||||||
|
for mail in maildir.list_new_sorted(Box::new(|name| {
|
||||||
|
// sort by UID
|
||||||
|
name.splitn(2, '_').nth(1).map(|x| x.parse().unwrap_or(0)).unwrap_or(0)
|
||||||
|
})) {
|
||||||
|
match mail {
|
||||||
|
Ok(mut mail) => {
|
||||||
|
let mail = mail.parsed()?;
|
||||||
|
let headers = mail.get_headers();
|
||||||
|
let from = headers.get_all_values("From").join(" ");
|
||||||
|
let subj = headers.get_all_values("Subject").join(" ");
|
||||||
|
rows.push(vec![from, subj]);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("error: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ascii_table = AsciiTable::default();
|
||||||
|
ascii_table.draw_lines = false;
|
||||||
|
ascii_table.max_width = usize::MAX;
|
||||||
|
for (i, &(header, align)) in [
|
||||||
|
("From", Align::Left),
|
||||||
|
("Subject", Align::Left),
|
||||||
|
].iter().enumerate() {
|
||||||
|
let mut column = Column::default();
|
||||||
|
column.header = header.to_owned();
|
||||||
|
column.align = align;
|
||||||
|
column.max_width = usize::MAX;
|
||||||
|
ascii_table.columns.insert(i, column);
|
||||||
|
}
|
||||||
|
ascii_table.print(rows);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
30
src/lib.rs
Normal file
30
src/lib.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use std::{env, net::TcpStream};
|
||||||
|
|
||||||
|
use imap::Session;
|
||||||
|
use maildir::Maildir;
|
||||||
|
use rustls_connector::{RustlsConnector, rustls::{ClientSession, StreamOwned}};
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
|
pub fn connect(host: &str, port: u16, user: &str, password: &str) -> Result<Session<StreamOwned<ClientSession, TcpStream>>> {
|
||||||
|
println!("connecting..");
|
||||||
|
let stream = TcpStream::connect((host, port))?;
|
||||||
|
let tls = RustlsConnector::new_with_native_certs()?;
|
||||||
|
println!("initializing TLS..");
|
||||||
|
let tlsstream = tls.connect(host, stream)?;
|
||||||
|
println!("initializing client..");
|
||||||
|
let client = imap::Client::new(tlsstream);
|
||||||
|
|
||||||
|
// the client we have here is unauthenticated.
|
||||||
|
// to do anything useful with the e-mails, we need to log in
|
||||||
|
println!("logging in..");
|
||||||
|
Ok(client.login(user, password).map_err(|e| e.0)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_maildir(mailbox: &str) -> Result<Maildir> {
|
||||||
|
let maildir = env::var("MAILDIR").expect("missing envvar MAILDIR");
|
||||||
|
let maildir = format!("{}/{}", maildir, mailbox);
|
||||||
|
let maildir = Maildir::from(maildir);
|
||||||
|
maildir.create_dirs()?;
|
||||||
|
Ok(maildir)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user