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, needle: &[u8]) -> Option { 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) -> Result<(), Box> { 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); }); }