commit 346bc24b2837bb70676c79711316d9b987743cb6
parent c37140f1e7a410769daee3ff47aeb6f1ce2de79b
Author: alex wennerberg <alex@alexwennerberg.com>
Date: Sat, 19 Mar 2022 20:36:44 -0700
I think get format/unformat flowed working properly
Diffstat:
3 files changed, 10 insertions(+), 291 deletions(-)
diff --git a/src/main.rs b/src/main.rs
@@ -182,109 +182,6 @@ fn main() -> Result<()> {
// TODO del this stuff
//
//
-//
-//
-//
-//
-//
-//
-//
-//
-// // TODO rename
-// pub fn hash(&self) -> String {
-// self.id.replace("/", ";")
-// }
-// }
-
-// fn local_parse_email(parsed_mail: &ParsedMail) -> Result<Email> {
-// let mut body: String = "[Message has no body]".to_owned();
-// let mut mime: String = "".to_owned();
-// let nobody = "[No body found]";
-// // nested lookup
-// let mut queue = vec![parsed_mail];
-// let mut text_body = None;
-// let mut html_body = None;
-// while queue.len() > 0 {
-// let top = queue.pop().unwrap();
-// for sub in &top.subparts {
-// queue.push(sub);
-// }
-// let content_disposition = top.get_content_disposition();
-// if content_disposition.disposition == mailparse::DispositionType::Attachment {
-// // attachment handler
-// } else {
-// if top.ctype.mimetype == "text/plain" {
-// let b = top.get_body().unwrap_or(nobody.to_owned());
-// if parsed_mail.ctype.params.get("format") == Some(&"flowed".to_owned()) {
-// text_body = Some(b);
-// // text_body = Some(utils::unformat_flowed(&b));
-// } else {
-// text_body = Some(b);
-// }
-// }
-// if top.ctype.mimetype == "text/html" {
-// html_body = Some(nanohtml2text::html2text(
-// &top.get_body().unwrap_or(nobody.to_owned()),
-// ));
-// }
-// }
-// }
-// if let Some(b) = text_body {
-// body = b;
-// mime = "text/plain".to_owned();
-// } else if let Some(b) = html_body {
-// body = b;
-// mime = "text/html".to_owned();
-// }
-// let headers = &parsed_mail.headers;
-// let id = headers
-// .get_first_value("message-id")
-// .and_then(|m| {
-// msgidparse(&m).ok().and_then(|i| match i.len() {
-// 0 => None,
-// _ => Some(i[0].clone()),
-// })
-// })
-// .context("No valid message ID")?;
-// // Assume 1 in-reply-to header. a reasonable assumption
-// let in_reply_to = headers.get_first_value("in-reply-to").and_then(|m| {
-// msgidparse(&m).ok().and_then(|i| match i.len() {
-// 0 => None,
-// _ => Some(i[0].clone()),
-// })
-// });
-// let subject = headers
-// .get_first_value("subject")
-// .unwrap_or("(no subject)".to_owned());
-// // TODO move upstream, add key/value parsing
-// // https://datatracker.ietf.org/doc/html/rfc2822.html#section-3.6.7
-// // https://github.com/staktrace/mailparse/issues/99
-// let received = headers.get_first_value("received");
-// let date_string = match received {
-// Some(r) => {
-// let s: Vec<&str> = r.split(";").collect();
-// s[s.len() - 1].to_owned()
-// }
-// None => headers.get_first_value("date").context("No date header")?,
-// };
-
-// let date = dateparse(&date_string)? as u64;
-// let from = addrparse_header(headers.get_first_header("from").context("No from header")?)?
-// .extract_single_info()
-// .context("Could not parse from header")?;
-
-// return Ok(Email {
-// id,
-// in_reply_to,
-// from,
-// subject,
-// date,
-// date_string,
-// body,
-// mime,
-// });
-// }
-
// fn write_index(lists: Vec<String>) -> Result<()> {
// let description = &Config::global().description;
// let tmp = html! {
@@ -309,188 +206,3 @@ fn main() -> Result<()> {
// layout("Mail Archives".to_string(), tmp).write_to_io(&mut br)?;
// Ok(())
// }
-
-// // fn oldmain() -> Result<()> {
-// // let args = arg::Args::from_env();
-
-// // let mut config = Config::from_file(&args.config)?;
-// // config.out_dir = args.out_dir;
-// // config.relative_times = args.flags.contains('r');
-// // config.include_raw = args.flags.contains('R');
-// // INSTANCE.set(config).unwrap();
-
-// // // let is_subfolder = std::fs::read_dir(&args.maildir)
-// // // .unwrap()
-// // // .any(|a| a.unwrap().file_name().to_str().unwrap() == "cur");
-
-// // let css = include_bytes!("style.css");
-// // let mut names = vec![];
-// // let mut message_count = 0;
-// // for maildir in std::fs::read_dir(&args.maildir).unwrap() {
-// // let maildir = maildir?;
-// // let file_name = maildir.file_name();
-// // let config = Config::global();
-// // let out_dir = config.out_dir.join(&file_name);
-// // std::fs::create_dir(&out_dir).ok();
-// // let dirreader = Maildir::from(maildir.path().to_str().unwrap());
-// // let list_name = file_name.into_string().unwrap();
-// // // filter out maildir internal junk
-// // if list_name.as_bytes()[0] == b'.' || ["cur", "new", "tmp"].contains(&list_name.as_str()) {
-// // continue;
-// // }
-
-// // let path = out_dir.join("messages");
-// // std::fs::remove_dir_all(&path).ok();
-// // names.push(list_name.clone());
-// // // new world WIP
-// // // let mut threader = threading::Arena::default();
-// // // Loads whole file into memory for threading
-// // // for item in maildir.list_cur().chain(maildir.list_new()) {
-// // // threader.add_message(item?);
-// // // }
-// // // threader.finalize();
-// // // return Ok(());
-
-// // let mut thread_index: HashMap<String, Vec<String>> = HashMap::new();
-
-// // let mut email_index: HashMap<String, Email> = HashMap::new();
-// // for entry in dirreader.list_cur().chain(dirreader.list_new()) {
-// // let mut tmp = entry.unwrap();
-// // let buffer = tmp.parsed()?;
-// // // persist raw messages
-// // let email = match local_parse_email(&buffer) {
-// // Ok(e) => e,
-// // Err(e) => {
-// // eprintln!("Error parsing {:?} -- {:?}", tmp.path(), e);
-// // continue;
-// // }
-// // };
-// // message_count += 1;
-// // // write raw emails
-// // if Config::global().include_raw {
-// // // inefficient here -- no diff
-// // std::fs::create_dir(&path).ok();
-// // let mut file = File::create(out_dir.join("messages").join(email.hash()))?;
-// // write_parsed_mail(&buffer, &mut file)?;
-// // }
-// // // TODO fix borrow checker
-// // if let Some(reply) = email.in_reply_to.clone() {
-// // match thread_index.get(&reply) {
-// // Some(_) => {
-// // let d = thread_index.get_mut(&reply).unwrap();
-// // d.push(email.id.clone());
-// // }
-// // None => {
-// // thread_index.insert(reply, vec![email.id.clone()]);
-// // }
-// // }
-// // }
-// // email_index.insert(email.id.clone(), email);
-// // }
-
-// // // Add index by subject lines
-// // // atrocious
-// // let mut todo = vec![]; // im bad at borrow checker
-// // for (_, em) in &email_index {
-// // if em.in_reply_to.is_none()
-// // && (em.subject.starts_with("Re: ") || em.subject.starts_with("RE: "))
-// // {
-// // // TODO O(n^2)
-// // for (_, em2) in &email_index {
-// // if em2.subject == em.subject[4..] {
-// // match thread_index.get(&em2.id) {
-// // Some(_) => {
-// // let d = thread_index.get_mut(&em2.id).unwrap();
-// // d.push(em.id.clone());
-// // }
-// // None => {
-// // thread_index.insert(em2.id.clone(), vec![em.id.clone()]);
-// // }
-// // }
-// // todo.push((em.id.clone(), em2.id.clone()));
-// // break;
-// // }
-// // }
-// // }
-// // }
-// // for (id, reply) in todo {
-// // let em = email_index.get_mut(&id).unwrap();
-// // em.in_reply_to = Some(reply)
-// // }
-
-// // let mut thread_roots: Vec<Email> = email_index
-// // .iter()
-// // .filter_map(|(_, v)| {
-// // if v.in_reply_to.is_none() {
-// // // or can't find root based on Re: subject
-// // return Some(v.clone());
-// // }
-// // return None;
-// // })
-// // .collect();
-// // let thread_dir = out_dir.join("threads");
-// // std::fs::create_dir_all(&thread_dir).ok();
-// // let mut threads = vec![];
-// // let mut curr_threads = get_current_threads(&thread_dir);
-
-// // for root in &mut thread_roots {
-// // let mut thread_ids = vec![];
-// // let mut current: Vec<String> = vec![root.id.clone()];
-// // while current.len() > 0 {
-// // let top = current.pop().unwrap().clone();
-// // thread_ids.push(top.clone());
-// // if let Some(ids) = thread_index.get(&top.clone()) {
-// // for item in ids {
-// // current.push(item.to_string());
-// // }
-// // }
-// // }
-
-// // let mut messages: Vec<&Email> = thread_ids
-// // .iter()
-// // .map(|id| email_index.get(id).unwrap())
-// // .collect();
-
-// // messages.sort_by_key(|a| a.date);
-
-// // let mut thread = MailThread {
-// // messages: messages,
-// // hash: root.hash(),
-// // last_reply: 0, // TODO
-// // list_name: list_name.clone(),
-// // };
-
-// // thread.last_reply = thread.last_reply();
-
-// // thread.write_to_file()?;
-// // thread.write_atom_feed()?;
-// // curr_threads.remove(&thread.hash);
-// // threads.push(thread);
-// // }
-
-// // for leftover in curr_threads {
-// // let file_to_remove = thread_dir.join(format!("{}.html", leftover));
-// // std::fs::remove_file(&file_to_remove).ok();
-// // let file_to_remove = thread_dir.join(format!("{}.xml", leftover));
-// // std::fs::remove_file(&file_to_remove).ok();
-// // }
-
-// // // Remove any threads left over
-
-// // threads.sort_by_key(|a| a.last_reply);
-// // threads.reverse();
-// // let list = ThreadList::new(threads, &list_name);
-// // list.write_to_file()?;
-// // list.write_atom_feed()?;
-// // // kinda clunky
-// // let mut css_root = File::create(out_dir.join("style.css"))?;
-// // css_root.write(css)?;
-// // let mut css_sub = File::create(out_dir.join("threads").join("style.css"))?;
-// // css_sub.write(css)?;
-// // }
-// // let mut css_root = File::create(Config::global().out_dir.join("style.css"))?;
-// // css_root.write(css)?;
-// // write_index(names)?;
-// // eprintln!("Processed {} emails", message_count);
-// // Ok(())
-// // }
diff --git a/src/models.rs b/src/models.rs
@@ -127,6 +127,7 @@ impl StrMessage {
// wonky
pub fn export_eml(&self) -> Vec<u8> {
let mut message = MessageBuilder::new();
+ println!("{}", self.flowed);
if self.flowed {
message.format_flowed();
}
@@ -223,7 +224,7 @@ impl StrMessage {
cc: cc,
date: date.to_owned(),
body: body.to_string(),
- flowed: false,
+ flowed,
in_reply_to: in_reply_to,
}
}
diff --git a/src/templates/html.rs b/src/templates/html.rs
@@ -215,7 +215,7 @@ impl Thread {
("date", &x(&msg.date)),
("in_reply_to", &in_reply_to),
("extra_headers", &extra_headers),
- ("body", &email_body(&msg.body)),
+ ("body", &email_body(&msg.body, msg.flowed)),
],
)
.unwrap(),
@@ -269,8 +269,14 @@ data:image/svg+xml,<?xml version="1.0" encoding="UTF-8"?>
// partly stolen from
// https://github.com/robinst/linkify/blob/demo/src/lib.rs#L5
// Dual licensed under MIT and Apache
-pub fn email_body(body: &str) -> String {
+pub fn email_body(body: &str, flowed: bool) -> String {
+ let mut body = body;
let mut bytes = Vec::new();
+ let mut tmp = String::new();
+ if flowed {
+ tmp = unformat_flowed(body);
+ body = &tmp
+ }
let mut in_reply: bool = false;
for line in body.lines() {
if line.starts_with(">") || (line.starts_with("On ") && line.ends_with("wrote:")) {