newsletter-to-web/src/main.rs

131 lines
3.4 KiB
Rust

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<HashMap<u32, Vec<u8>>, Box<dyn Error>> {
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<dyn Error + 'static>,
> {
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)?)
}