email/src/bin/mailparse.rs

90 lines
2.3 KiB
Rust

use std::env;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::process::exit;
use std::slice::Iter;
use mailparse::dateparse;
use mailparse::MailHeaderMap;
fn newline(b: &u8) -> bool {
*b == b'\n'
}
fn index_of(it: &mut Iter<u8>, needle: &[u8]) -> Option<usize> {
let mut needle_ix = 0;
it.position(move |&b| {
if b == needle[needle_ix] {
needle_ix += 1;
if needle_ix == needle.len() {
return true;
}
} else if b == needle[0] {
needle_ix = 1;
} else {
needle_ix = 0;
}
false
})
}
fn parse_mbox(mbox_bytes: &Vec<u8>) -> Result<(), Box<dyn Error>> {
let mut it = mbox_bytes.iter();
let mut ix = 0;
loop {
let mail_start = it.position(newline);
if mail_start.is_none() {
return Ok(());
}
ix += mail_start.unwrap() + 1;
let start = ix;
let delim = b"\nFrom ";
let next_mail_start = index_of(&mut it, delim);
let end = match next_mail_start {
Some(x) => {
ix += x + 1;
ix - delim.len()
}
None => mbox_bytes.len(),
};
let mail_bytes = &mbox_bytes[start..end];
let mail = mailparse::parse_mail(mail_bytes).unwrap();
println!(
"{:?} {:?} from {:?}",
match mail.headers.get_first_value("Date")? {
Some(date) => date,
None => "NO DATE".to_string(),
},
match mail.headers.get_first_value("Subject")? {
Some(subject) => subject,
None => "NO SUBJECT".to_string(),
},
match mail.headers.get_first_value("From")? {
Some(from) => from,
None => "NO FROM".to_string(),
},
);
}
}
fn main() {
if env::args().count() <= 1 {
println!("Provide mbox files as arguments");
exit(1);
}
let mut args = env::args();
args.next(); // drop executable name
args.for_each(|mbox_path| {
let mut mbox = File::open(mbox_path).unwrap();
let mut mails = Vec::new();
mbox.read_to_end(&mut mails).unwrap();
parse_mbox(&mails);
});
}