use std::{ collections::HashMap, error::Error, fs::OpenOptions, io::Write, net::TcpStream, path::{Path, PathBuf}, }; use imap::Session; use mail_parser::Message; use rustls_connector::RustlsConnector; use sha2::{Digest, Sha256}; extern crate imap; extern crate kuchiki; extern crate mail_parser; extern crate rustls_connector; extern crate sha2; fn main() { let dir = Path::new("data"); if !dir.exists() { std::fs::create_dir(&dir).expect("Could not create directory"); } let messsages = connect("my.kiers.eu", 993, "newsletters@kie.rs", "Jjkcloudron1!") .expect("A list of messages"); for (uid, message) in messsages { println!("Processing message {}\n", &uid); let parsed = Message::parse(&message).expect("A parsed messsage."); let html_body = parsed.get_html_body(0).expect("Could not read body"); let html_bytes = html_body.as_bytes(); //println!("{}", &html_body); let title = parsed.get_subject().expect("Expected a subject"); let hash = base16ct::lower::encode_string(&Sha256::digest(&html_bytes)); println!("{}", hash); // let dom = kuchiki::parse_html().one(String::from_utf8(html_bytes.to_vec()).expect("Could not convert HTML bytes to string")); // for img_match in dom.select("img").unwrap() { // let mut attributes = img_match.attributes.borrow_mut(); // let src = { attributes.get("src").unwrap_or_default() }.to_owned(); // attributes.remove("src"); // attributes.insert("data-src", src.to_owned()); // } // let new_html = dom.as_text() let path: PathBuf = [dir, Path::new(&format!("{}.html", &title))] .iter() .collect(); let mut file = OpenOptions::new() .write(true) .create(true) .open(path) .expect("Could not open file fir writing"); file.write_all(&html_bytes) .expect("Could not write to file."); } } fn connect( server: &str, port: u16, username: &str, password: &str, ) -> Result>, Box> { let mut session = open_session(server, port, username, password)?; session.examine("INBOX")?; let items = match session.uid_search("ALL") { Ok(i) => i, Err(e) => return Err(Box::new(e)), }; let mut msgs = HashMap::with_capacity(items.len()); //println!("# of messages: {}", &items.len()); for item in items { let msg = session.uid_fetch(&item.to_string(), "(BODY.PEEK[] UID)")?; let message = if let Some(m) = msg.iter().next() { m } else { continue; }; let body = message.body().expect("Message did not have a body."); msgs.insert(item, body.to_owned()); } session.logout().expect("Could not log out"); Ok(msgs) } fn open_session( server: &str, port: u16, username: &str, password: &str, ) -> Result< Session< rustls_connector::rustls::StreamOwned< rustls_connector::rustls::ClientConnection, TcpStream, >, >, Box, > { let stream = TcpStream::connect((server, port))?; let tls = RustlsConnector::new_with_webpki_roots_certs(); let tls_stream = tls.connect(server, stream)?; let client = imap::Client::new(tls_stream); Ok(client.login(username, password).map_err(|e| e.0)?) }