crabmail

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

commit 91b97744b36a93bd5d2cbe31526a8b0986266a47
parent fcaae8942531ea1f8faa339467501e1d7cea8e59
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Sat, 19 Mar 2022 18:51:21 -0700

add gmi

Diffstat:
MTODO | 5+++--
Msrc/main.rs | 1+
Msrc/models.rs | 5++++-
Msrc/templates/gmi.rs | 45++++++++++++++++++++++++++++++++++++++++++++-
Msrc/templates/html.rs | 9+++++++--
Msrc/util.rs | 9+++++----
6 files changed, 64 insertions(+), 10 deletions(-)

diff --git a/TODO b/TODO @@ -1,10 +1,11 @@ TODO ==== -truncate in-reply-to string +understand content-transfer-encoding for eml body +figure out whats up with format=flowed. update library? + use get_thread_name? get export working -> use mail-builder (fork it and/or cut deps) -Replace "Download" with "export eml" get reply link working allow mbox/single folder input atom feeds working diff --git a/src/main.rs b/src/main.rs @@ -19,6 +19,7 @@ mod models; mod templates; mod threading; mod time; +mod util; const ATOM_ENTRY_LIMIT: i32 = 100; const PAGE_SIZE: i32 = 100; diff --git a/src/models.rs b/src/models.rs @@ -130,9 +130,12 @@ impl StrMessage { message.from((from.as_str(), self.from.address.as_str())); message.to("jane@doe.com"); // cc + if let Some(irt) = &self.in_reply_to { + message.in_reply_to(irt.as_str()); + } // list-archive - // in-reply-to message.subject(&self.subject); + // Figure out body export and content-transfer... message.text_body(&self.body); let mut output = Vec::new(); message.write_to(&mut output).unwrap(); diff --git a/src/templates/gmi.rs b/src/templates/gmi.rs @@ -1,3 +1,5 @@ +// WIP +// use crate::models::*; use nanotemplate::template; @@ -21,6 +23,47 @@ impl List { impl Thread { pub fn to_gmi(&self) -> String { - String::new() + let mut out = format!( + r#"# {} + "#, + self.messages[0].subject.replace("\n", " ") + ); + for msg in &self.messages { + let msg = template( + r#" +## {subject} +From: {from} +Date: {date} +In-Reply-To: adsf +Message-Id: {msg_id} +To: ... +Cc: ... +--------------------- +{body} +"#, + &[ + ("subject", &h(&msg.subject)), + ("date", &h(&msg.date)), + ("msg_id", &h(&msg.id)), + ("from", &h(&msg.from.address)), + ("body", &escape_body(&msg.body)), + ], + ) + .unwrap(); + out.push_str(&msg); + } + out } } + +// TODO ... +fn escape_body(s: &str) -> String { + let mut out = " ".to_string(); + out.push_str(&s.replace("\n", "\n ")); + out +} + +// escape header +fn h(s: &str) -> String { + s.replace("\n", " ") +} diff --git a/src/templates/html.rs b/src/templates/html.rs @@ -2,6 +2,7 @@ use super::util::xml_escape; use super::util::xml_safe as x; use crate::models::*; use crate::time::Date; +use crate::util::*; use linkify::{LinkFinder, LinkKind}; use nanotemplate::template; use std::borrow::Cow; @@ -147,7 +148,11 @@ impl Thread { // fix from header parsing // TODO in reply to let in_reply_to = if let Some(irt) = &msg.in_reply_to { - format!("In-Reply-To: <a href='#{0}'>{0}</a><br>\n", x(irt)) + format!( + "In-Reply-To: <a href='#{0}'>{1}</a><br>\n", + x(irt), + x(&truncate_ellipsis(irt, 40)) + ) } else { String::new() }; @@ -192,7 +197,7 @@ impl Thread { {extra_headers} </details> <a class="bold" href="tbd">Reply</a> - [<a href="../messages/{msg_path}.eml">Download</a>] + [<a href="../messages/{msg_path}.eml">Export</a>] </div> <div class="email-body"> {body} diff --git a/src/util.rs b/src/util.rs @@ -1,13 +1,14 @@ // Truncate a string, adding ellpises if it's too long -fn truncate_ellipsis(s: &str, n: usize) -> String { - let out = String::with_capacity(n); +pub fn truncate_ellipsis(s: &str, n: usize) -> String { + let mut out = String::with_capacity(n); if s.len() <= n { - return s[..n].to_owned(); + return s.to_owned(); } let res = match s.char_indices().nth(n - 3) { None => s, Some((idx, _)) => &s[..idx], }; out.push_str(res); - res + out.push_str("..."); + out.to_string() }