crabmail

Static HTML email archive viewer in Rust
git clone git://git.alexwennerberg.com/crabmail
Log | Files | Refs | README | LICENSE

commit 4e54e7945985f51f236ddc5e474e4410ee71b23f
parent 346bc24b2837bb70676c79711316d9b987743cb6
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Sat, 19 Mar 2022 20:47:47 -0700

cleanup and add mailto links

Diffstat:
Msrc/main.rs | 2+-
Msrc/models.rs | 60+++++++++++++++++++++++++++++++++---------------------------
Msrc/templates/html.rs | 7++++---
3 files changed, 38 insertions(+), 31 deletions(-)

diff --git a/src/main.rs b/src/main.rs @@ -115,7 +115,7 @@ impl List { std::fs::create_dir_all(&message_dir).unwrap(); for thread_ids in &self.thread_idx.threads { // Load thread - let thread = Thread::new(thread_ids); + let thread = Thread::new(thread_ids, &self.config.name); let basepath = thread_dir.join(&thread.messages[0].pathescape_msg_id()); // hacky write_if_unchanged(&append_ext("html", &basepath), thread.to_html().as_bytes()); diff --git a/src/models.rs b/src/models.rs @@ -72,11 +72,12 @@ pub struct Thread { } impl Thread { - pub fn new(thread_idx: &Vec<Msg>) -> Self { + pub fn new(thread_idx: &Vec<Msg>, list_name: &str) -> Self { let mut out = vec![]; for m in thread_idx { let data = std::fs::read(&m.path).unwrap(); - let msg = StrMessage::new(&Message::parse(&data).unwrap()); + let mut msg = StrMessage::new(&Message::parse(&data).unwrap()); + msg.mailto = msg.mailto(list_name); out.push(msg); } Thread { messages: out } @@ -89,11 +90,13 @@ impl Thread { pub struct StrMessage { pub id: String, pub subject: String, + pub thread_subject: String, pub preview: String, pub from: MailAddress, pub date: String, // TODO better dates pub body: String, pub flowed: bool, + pub mailto: String, // mailto link pub in_reply_to: Option<String>, pub to: Vec<MailAddress>, pub cc: Vec<MailAddress>, @@ -127,7 +130,6 @@ impl StrMessage { // wonky pub fn export_eml(&self) -> Vec<u8> { let mut message = MessageBuilder::new(); - println!("{}", self.flowed); if self.flowed { message.format_flowed(); } @@ -146,33 +148,35 @@ impl StrMessage { message.write_to(&mut output).unwrap(); output } - // pub fn mailto(&self, email: &str, list_name: &str, thread_subject: &str) -> String { - // let mut url = format!("mailto:{}?", email); - // let from = self.from.address; - // // make sure k is already urlencoded - // let mut pushencode = |k: &str, v| { - // url.push_str(&format!("{}={}&", k, urlencoding::encode(v))); - // }; - // let fixed_id = format!("<{}>", &self.id); - // pushencode("cc", &from); - // pushencode("in-reply-to", &fixed_id); - // let list_url = format!("{}/{}", &Config::global().base_url, list_name); - // pushencode("list-archive", &list_url); - // pushencode("subject", &format!("Re: {}", thread_subject)); - // // quoted body - // url.push_str("body="); - // for line in self.body.lines() { - // url.push_str("%3E%20"); - // url.push_str(&urlencoding::encode(&line)); - // url.push_str("%0A"); - // } - // url.into() - // } + pub fn mailto(&self, list_name: &str) -> String { + let mut url = format!("mailto:{}?", self.from.address); + + let from = self.from.address.clone(); + // make sure k is already urlencoded + let mut pushencode = |k: &str, v| { + url.push_str(&format!("{}={}&", k, urlencoding::encode(v))); + }; + let fixed_id = format!("<{}>", &self.id); + pushencode("cc", &from); + pushencode("in-reply-to", &fixed_id); + let list_url = format!("{}/{}", &Config::global().base_url, list_name); + pushencode("list-archive", &list_url); + pushencode("subject", &format!("Re: {}", self.thread_subject)); + // quoted body + url.push_str("body="); + for line in self.body.lines() { + url.push_str("%3E%20"); + url.push_str(&urlencoding::encode(&line)); + url.push_str("%0A"); + } + url.into() + } pub fn new(msg: &Message) -> StrMessage { let id = msg.get_message_id().unwrap_or(""); let subject = msg.get_subject().unwrap_or("(No Subject)"); + let thread_subject = msg.get_thread_name().unwrap_or("(No Subject)"); let invalid_email = Addr::new(None, "invalid-email"); let preview = match msg.get_body_preview(80) { Some(b) => b.to_string(), @@ -220,11 +224,13 @@ impl StrMessage { subject: subject.to_owned(), from: from, preview, - to: to, - cc: cc, + to, + cc, + thread_subject: thread_subject.to_owned(), date: date.to_owned(), body: body.to_string(), flowed, + mailto: String::new(), in_reply_to: in_reply_to, } } diff --git a/src/templates/html.rs b/src/templates/html.rs @@ -196,7 +196,7 @@ impl Thread { <summary>More</summary> {extra_headers} </details> - <a class="bold" href="tbd">Reply</a> + <a class="bold" href="{mailto}">Reply</a> [<a href="../messages/{msg_path}.eml">Export</a>] </div> <div class="email-body"> @@ -211,6 +211,7 @@ impl Thread { ("msg_id", &x(&msg.id)), ("msg_path", &x(msg.pathescape_msg_id().to_str().unwrap())), ("subject", &x(&msg.subject)), + ("mailto", &x(&msg.mailto)), ("from", &msg.from.to_html()), ("date", &x(&msg.date)), ("in_reply_to", &in_reply_to), @@ -270,12 +271,12 @@ data:image/svg+xml,<?xml version="1.0" encoding="UTF-8"?> // https://github.com/robinst/linkify/blob/demo/src/lib.rs#L5 // Dual licensed under MIT and Apache pub fn email_body(body: &str, flowed: bool) -> String { - let mut body = body; let mut bytes = Vec::new(); + let mut body = body; let mut tmp = String::new(); if flowed { tmp = unformat_flowed(body); - body = &tmp + body = &tmp; } let mut in_reply: bool = false; for line in body.lines() {