mirror of
https://github.com/FliegendeWurst/inboxid.git
synced 2024-11-21 16:34:59 +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"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "ascii_table"
|
||||
version = "3.0.2"
|
||||
source = "git+https://gitlab.com/arnekeller/ascii-table.git?rev=7fffb5d93b8c63283fc1359ee3c6dbfcf12ed90b#7fffb5d93b8c63283fc1359ee3c6dbfcf12ed90b"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
@ -172,9 +177,11 @@ dependencies = [
|
||||
name = "inboxid"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ascii_table",
|
||||
"imap",
|
||||
"itertools",
|
||||
"maildir",
|
||||
"mailparse",
|
||||
"rustls-connector",
|
||||
]
|
||||
|
||||
|
@ -11,4 +11,6 @@ license = "GPL-3.0-or-later"
|
||||
imap = { version = "2.4.1", default-features = false }
|
||||
itertools = "0.10.0"
|
||||
maildir = { path = "../maildir" }
|
||||
mailparse = "0.13.2"
|
||||
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 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 user = env::var("MAILUSER").expect("missing envvar MAILUSER");
|
||||
let password = env::var("MAILPASSWORD").expect("missing envvar MAILPASSWORD");
|
||||
let maildir = env::var("MAILDIR").expect("missing envvar MAILDIR");
|
||||
let maildir = Maildir::from(maildir);
|
||||
maildir.create_dirs()?;
|
||||
let maildir = get_maildir("INBOX")?;
|
||||
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(
|
||||
host: &str,
|
||||
user: String,
|
||||
password: String,
|
||||
user: &str,
|
||||
password: &str,
|
||||
port: u16,
|
||||
mailbox: &str,
|
||||
maildir: Maildir,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
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..");
|
||||
let mut imap_session = client.login(&user, &password).map_err(|e| e.0)?;
|
||||
) -> Result<()> {
|
||||
let mut imap_session = connect(host, port, user, password)?;
|
||||
println!("getting capabilities..");
|
||||
let caps = imap_session.capabilities()?;
|
||||
println!("capabilities: {}", caps.iter().map(|x| format!("{:?}", x)).join(" "));
|
||||
@ -95,16 +83,16 @@ fn fetch_inbox_top(
|
||||
}
|
||||
|
||||
trait MaildirExtension {
|
||||
fn get_file(&self, name: &str) -> Result<String, io::Error>;
|
||||
fn save_file(&self, name: &str, content: &str) -> Result<(), io::Error>;
|
||||
fn get_file(&self, name: &str) -> std::result::Result<String, io::Error>;
|
||||
fn save_file(&self, name: &str, content: &str) -> std::result::Result<(), io::Error>;
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
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