filter: mail processing command

This commit is contained in:
FliegendeWurst 2021-03-31 11:43:59 +02:00 committed by Arne Keller
parent a349925f78
commit c9dde850b7
5 changed files with 129 additions and 4 deletions

63
Cargo.lock generated
View File

@ -278,6 +278,7 @@ dependencies = [
"itertools", "itertools",
"maildir", "maildir",
"mailparse", "mailparse",
"mailproc",
"moins", "moins",
"rusqlite", "rusqlite",
"rustls-connector", "rustls-connector",
@ -349,9 +350,11 @@ dependencies = [
[[package]] [[package]]
name = "maildir" name = "maildir"
version = "0.5.0" version = "0.5.0"
source = "git+https://github.com/FliegendeWurst/maildir.git?branch=master#f9b8ffa12161ebed0688518f303b907a1f34eac6"
dependencies = [ dependencies = [
"gethostname", "gethostname",
"mailparse", "mailparse",
"memmap",
] ]
[[package]] [[package]]
@ -365,12 +368,36 @@ dependencies = [
"quoted_printable", "quoted_printable",
] ]
[[package]]
name = "mailproc"
version = "0.3.1"
source = "git+https://github.com/FliegendeWurst/mailproc.git?branch=master#46e27f9a10f64b6f77b7fbbddb03e2187ca3465a"
dependencies = [
"log",
"mailparse",
"regex",
"serde",
"serde_derive",
"subprocess",
"toml",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.3.4" version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "memmap"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "moins" name = "moins"
version = "0.5.0" version = "0.5.0"
@ -677,6 +704,23 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "serde"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
[[package]]
name = "serde_derive"
version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.6.1" version = "1.6.1"
@ -695,6 +739,16 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "subprocess"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69b9ad6c3e1b525a55872a4d2f2d404b3c959b7bbcbfd83c364580f68ed157bd"
dependencies = [
"libc",
"winapi",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.67" version = "1.0.67"
@ -729,6 +783,15 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.7.1" version = "1.7.1"

View File

@ -10,7 +10,7 @@ license = "GPL-3.0-or-later"
[dependencies] [dependencies]
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 = { git = "https://github.com/FliegendeWurst/maildir.git", branch = "master", features = ["mmap"] }
mailparse = "0.13.2" mailparse = "0.13.2"
rustls-connector = "0.13.1" rustls-connector = "0.13.1"
ascii_table = { git = "https://gitlab.com/arnekeller/ascii-table.git", branch = "master" } ascii_table = { git = "https://gitlab.com/arnekeller/ascii-table.git", branch = "master" }
@ -20,3 +20,4 @@ rusqlite = { git = "https://github.com/rusqlite/rusqlite", branch = "master", fe
rustyline = "8.0.0" rustyline = "8.0.0"
moins = { git = "https://github.com/FliegendeWurst/moins", branch = "master" } moins = { git = "https://github.com/FliegendeWurst/moins", branch = "master" }
anyhow = "1.0.40" anyhow = "1.0.40"
mailproc = { git = "https://github.com/FliegendeWurst/mailproc.git", branch = "master" }

52
src/bin/filter.rs Normal file
View File

@ -0,0 +1,52 @@
use std::env;
use anyhow::anyhow;
use inboxid::*;
use itertools::Itertools;
use mailproc::Config;
fn main() -> Result<()> {
let args = env::args().collect_vec();
if args.len() < 3 {
Err(anyhow!("required arguments: mailbox name, filter file path"))?;
unreachable!()
} else {
do_filtering(&args[1], &args[2])
}
}
fn do_filtering(mailbox: &str, config: &str) -> Result<()> {
let config = Config::load_from_path(config)?;
let maildir = get_maildir(mailbox)?;
let mut mails = Vec::new();
for x in maildir.list_cur() {
mails.push(x?);
}
let mut mails = maildir.get_mails(&mut mails)?;
mails.sort_by_key(|x| x.id);
let mut imap_session = get_imap_session()?;
imap_session.select(mailbox)?;
for mail in mails {
if let Some(action) = mailproc::handle(&mail, &[], &config) { // TODO: provide raw bytes
println!("{:?}", action.0);
println!(" matched {}", mail.subject);
for action in action.0.action.as_ref().unwrap() {
match &*action[0] {
"mv" => {
println!(" moving to mailbox {}", action[1]);
imap_session.uid_mv(mail.id.uid.to_string(), &action[1])?;
},
x => {
println!("WARNING: unknown action {:?}", x);
}
}
}
}
}
Ok(())
}

View File

@ -35,7 +35,7 @@ fn sync(
println!("{:?}", x); println!("{:?}", x);
names.push(x.name()); names.push(x.name());
} }
names = vec!["INBOX", "nebenan"]; names = vec!["INBOX", "Github", "nebenan"];
let mut remote = HashMap::new(); let mut remote = HashMap::new();

View File

@ -9,8 +9,9 @@ use rusqlite::{Connection, params};
use rustls_connector::{RustlsConnector, rustls::{ClientSession, StreamOwned}}; use rustls_connector::{RustlsConnector, rustls::{ClientSession, StreamOwned}};
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>; pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
pub type ImapSession = Session<StreamOwned<ClientSession, TcpStream>>;
pub fn connect(host: &str, port: u16, user: &str, password: &str) -> Result<Session<StreamOwned<ClientSession, TcpStream>>> { pub fn connect(host: &str, port: u16, user: &str, password: &str) -> Result<ImapSession> {
println!("connecting.."); println!("connecting..");
let stream = TcpStream::connect((host, port))?; let stream = TcpStream::connect((host, port))?;
let tls = RustlsConnector::new_with_native_certs()?; let tls = RustlsConnector::new_with_native_certs()?;
@ -54,7 +55,7 @@ pub fn gen_id(uid_validity: u32, uid: u32) -> String {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct MaildirID { pub struct MaildirID {
uid_validity: u32, uid_validity: u32,
uid: u32, pub uid: u32,
} }
impl TryFrom<&str> for MaildirID { impl TryFrom<&str> for MaildirID {
@ -157,3 +158,11 @@ pub fn remove_cow<'a>(x: &Flag<'a>) -> Flag<'static> {
Flag::MayCreate => Flag::MayCreate, Flag::MayCreate => Flag::MayCreate,
} }
} }
pub fn get_imap_session() -> Result<ImapSession> {
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 port = 993;
connect(&host, port, &user, &password)
}