Skip to content

Instantly share code, notes, and snippets.

@ykon
Last active February 3, 2019 12:18
Show Gist options
  • Select an option

  • Save ykon/0a5955a572d81bbaa52fe829f3af80f7 to your computer and use it in GitHub Desktop.

Select an option

Save ykon/0a5955a572d81bbaa52fe829f3af80f7 to your computer and use it in GitHub Desktop.
use std::collections::HashMap;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use regex::Regex;
use itertools::Itertools;
type MailHeader = HashMap<String, Vec<String>>;
fn read_file(path: &str) -> io::Result<String> {
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
fn unfold_header(header: String) -> String {
let re = Regex::new(r"\r\n[ \t]+").unwrap();
re.replace_all(&header, " ").to_string()
}
fn split_field(line: &str) -> Option<(String, String)> {
let re = Regex::new(r"(\S+): *(.+)?").unwrap();
re.captures(line).map(|caps| {
let fname = caps.get(1).unwrap().as_str().to_string();
let fvalue = caps.get(2).map(|m| m.as_str());
(fname, fvalue.unwrap_or("").to_string())
})
}
fn parse_header(header: String) -> Vec<(String, String)> {
header.lines().filter_map(split_field).collect()
}
fn split_header_body(text: String) -> Option<(String, String)> {
match text.splitn(2, "\r\n\r\n").collect::<Vec<&str>>().as_slice() {
[header, body] => Some((header.to_string(), body.to_string())),
_ => None,
}
}
fn tuple_to_hash(header: Vec<(String, String)>) -> MailHeader {
let mut mheader = header.clone();
mheader.sort_by(|a, b| a.0.cmp(&b.0));
mheader.iter()
.group_by(|(fst, _)| fst)
.into_iter()
.map(|(fname, group)| (fname.to_lowercase(), group.map(|(_, snd)| snd.to_string()).collect()))
.collect()
}
fn main() {
let text = read_file("data.txt").expect("IO error");
let (header, _) = split_header_body(text).expect("Invalid mail-header");
let unfolded_header = unfold_header(header);
let tupled_header = parse_header(unfolded_header);
let mail_header = tuple_to_hash(tupled_header);
//println!("{:?}", mail_header);
//mail_header.iter().for_each(|(fname, fvalue)| println!("{}: {:?}", fname, fvalue));
println!("{}", mail_header.iter().map(|(fname, fvalue)| format!("{}: {:?}", fname, fvalue)).join("\n"));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment