commit 698e8ccf7ae68326ee45c0cc00c3725fb28ca30b
parent bb02f1103cf193bcb8558f1b28569b935787cbca
Author: alex wennerberg <alex@alexwennerberg.com>
Date: Sun, 13 Mar 2022 13:41:31 -0700
WIP...
Diffstat:
6 files changed, 104 insertions(+), 61 deletions(-)
diff --git a/src/main.rs b/src/main.rs
@@ -25,17 +25,7 @@ const PAGE_SIZE: i32 = 100;
// TODO
-impl Lists<'_> {
- fn add(&mut self, data: threading::ThreadIdx, name: &str) {
- let newlist = List::new(name);
- for thread in data.threads {
- // let ids = thread.iter().map(|m| m.id).collect();
- // newlist.threads.push(Thread::from_id_list(ids));
- }
- // sort threads
- self.lists.push(newlist);
- }
-
+impl Lists {
fn write_lists(&self) {
std::fs::create_dir_all(&self.out_dir);
let css = include_bytes!("style.css");
@@ -46,7 +36,7 @@ impl Lists<'_> {
write_if_unchanged(&base_path.with_extension("gmi"), self.to_gmi().as_bytes());
}
for list in &self.lists {
- list.write_all_files()
+ list.persist()
}
}
}
@@ -75,23 +65,54 @@ enum Format {
GMI,
}
-impl List<'_> {
+impl List {
// TODO move to main
// fn from_maildir() -> Self { // TODO figure out init
// where to live
// List { threads: vec![] }
- fn write_all_files(&self) {
- let index = self.out_dir.join("index");
+ //
+
+ fn persist(&self) {
+ // let written = hashset
+ self.write_index();
+ self.write_threads();
+ // for file in threads, messages
+ // if not in written
+ // delete
+ }
+ fn write_index(&self) {
+ // TODO fix lazy copy paste
+ // TODO return files written
+ for (n, gmi) in self.to_gmi().iter().enumerate() {
+ let index;
+ if n == 0 {
+ index = self.out_dir.join("index");
+ } else {
+ index = self.out_dir.join(format!("{}-{}", "index", n));
+ }
+ write_if_unchanged(&index.with_extension("gmi"), gmi.as_bytes());
+ }
+ for (n, html) in self.to_html().iter().enumerate() {
+ let index;
+ if n == 0 {
+ index = self.out_dir.join("index");
+ } else {
+ index = self.out_dir.join(format!("{}-{}", "index", n));
+ }
+ write_if_unchanged(&index.with_extension("html"), html.as_bytes());
+ }
+ // write_if_unchanged(&self.out_dir.join("atom.xml"), self.to_xml().as_bytes());
+ }
+
+ fn write_threads(&self) {
+ // files written = HashSet
let thread_dir = self.out_dir.join("threads");
std::fs::create_dir_all(&thread_dir).unwrap();
- write_if_unchanged(&self.out_dir.join("atom.xml"), self.to_html().as_bytes());
-
- // TODO write index (paginated) gmi
- // write index (paginated) html
- // Delete threads that aren't in my list (xml, gmi, html)
- for thread in &self.threads {
+ self.write_index();
+ for thread_ids in &self.thread_idx.threads {
+ // Load thread
+ let thread = Thread::new(thread_ids);
let basepath = thread_dir.join(&pathescape_msg_id(&thread.messages[0].id));
- // TODO cleanup, abstract
write_if_unchanged(
&basepath.with_extension("html"),
thread.to_html().as_bytes(),
@@ -100,7 +121,6 @@ impl List<'_> {
if Config::global().include_gemini {
write_if_unchanged(&basepath.with_extension("gmi"), thread.to_gmi().as_bytes());
}
- // Delete nonexistent messages (cache?)
// for file in thread
// write raw file
}
@@ -140,12 +160,25 @@ fn main() -> Result<()> {
}
// id list into thread
list.finalize();
- lists.add(list, &dir_name);
+ // lists.lists.push(list);
}
lists.write_lists();
Ok(())
}
+
+// TODO del this stuff
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
+//
// impl<'a> MailThread<'a> {}
// pub fn write_to_file(&self) -> Result<()> {
diff --git a/src/models.rs b/src/models.rs
@@ -1,4 +1,5 @@
use crate::config::{Config, Subsection};
+use crate::threading::{Msg, ThreadIdx};
use mail_parser::{Addr, HeaderValue, Message};
use std::borrow::Cow;
use std::path::PathBuf;
@@ -11,18 +12,19 @@ use std::path::PathBuf;
// raw_email = "/{list_name}/messages/{message_id}.eml
// paginate index somehow (TBD)
-pub struct Lists<'a> {
- pub lists: Vec<List<'a>>,
+pub struct Lists {
+ pub lists: Vec<List>,
pub out_dir: PathBuf,
}
-pub struct List<'a> {
- pub threads: Vec<Thread<'a>>,
+pub struct List {
+ pub thread_idx: crate::threading::ThreadIdx,
+ // Thread topics
pub config: Subsection, // path
pub out_dir: PathBuf,
}
-impl List<'_> {
+impl List {
pub fn new(name: &str) -> Self {
let con = Config::global();
let sub: Subsection = match con.get_subsection(name) {
@@ -30,37 +32,37 @@ impl List<'_> {
None => con.default_subsection(name),
};
Self {
- threads: vec![],
+ thread_idx: crate::threading::ThreadIdx::default(),
config: sub,
out_dir: Config::global().out_dir.join(name),
}
}
}
-pub struct Thread<'a> {
- pub messages: Vec<StrMessage<'a>>,
+pub struct Thread {
+ pub messages: Vec<StrMessage>,
}
-impl Thread<'_> {
- // fn new() -> Self {
- // Thread {messagse: }
- // }
+impl Thread {
+ pub fn new(thread_idx: &Vec<Msg>) -> Self {
+ Thread { messages: vec![] }
+ }
}
-// TODO rename
// simplified, stringified-email for templating
-pub struct StrMessage<'a> {
- pub id: Cow<'a, str>,
- pub subject: Cow<'a, str>,
+// making everything owned because I'm l a z y
+pub struct StrMessage {
+ pub id: String,
+ pub subject: String,
pub from: MailAddress,
- pub date: Cow<'a, str>, // TODO better dates
- pub body: Cow<'a, str>,
- pub in_reply_to: Option<Cow<'a, str>>,
+ pub date: String, // TODO better dates
+ pub body: String,
+ pub in_reply_to: Option<String>,
// url: Cow<'a, str>,
// download_path: PathBuf, // TODO
}
-impl StrMessage<'_> {
+impl StrMessage {
pub fn from_file() {}
}
@@ -89,8 +91,8 @@ impl MailAddress {
}
// TODO rename
-impl<'a> Thread<'a> {
- fn new_message(msg: &'a Message<'a>) -> StrMessage<'a> {
+impl StrMessage {
+ pub fn new(msg: &Message) -> StrMessage {
let id = msg.get_message_id().unwrap_or("");
let subject = msg.get_subject().unwrap_or("(No Subject)");
let invalid_email = Addr::new(None, "invalid-email");
@@ -103,7 +105,7 @@ impl<'a> Thread<'a> {
let in_reply_to = msg
.get_in_reply_to()
.as_text_ref()
- .and_then(|a| Some(Cow::Borrowed(a)));
+ .and_then(|a| Some(a.to_string()));
// TODO linkify body
// TODO unformat-flowed
@@ -111,11 +113,11 @@ impl<'a> Thread<'a> {
.get_text_body(0)
.unwrap_or(Cow::Borrowed("[No message body]"));
StrMessage {
- id: Cow::Borrowed(id),
- subject: Cow::Borrowed(subject),
+ id: id.to_owned(),
+ subject: subject.to_owned(),
from: from,
- date: Cow::Owned(date),
- body: body,
+ date: date.to_owned(),
+ body: body.to_string(),
in_reply_to: in_reply_to,
}
}
diff --git a/src/templates/gmi.rs b/src/templates/gmi.rs
@@ -1,7 +1,7 @@
use crate::models::*;
use nanotemplate::template;
-impl Lists<'_> {
+impl Lists {
pub fn to_gmi(&self) -> String {
template(
r#"
@@ -13,7 +13,13 @@ impl Lists<'_> {
}
}
-impl Thread<'_> {
+impl List {
+ pub fn to_gmi(&self) -> Vec<String> {
+ vec![]
+ }
+}
+
+impl Thread {
pub fn to_gmi(&self) -> String {
String::new()
}
diff --git a/src/templates/html.rs b/src/templates/html.rs
@@ -21,7 +21,7 @@ const layout: &str = r#"<!DOCTYPE html>
</html>
"#;
-impl Lists<'_> {
+impl Lists {
pub fn to_html(&self) -> String {
template(
r#"
@@ -34,8 +34,8 @@ impl Lists<'_> {
}
}
-impl List<'_> {
- pub fn to_html(&self) -> String {
+impl List {
+ pub fn to_html(&self) -> Vec<String> {
template(
r#"
<h1 class="page-title">
@@ -47,17 +47,18 @@ impl List<'_> {
"#,
&[("title", self.config.title.as_str()), ("rss_svg", RSS_SVG)],
)
- .unwrap()
+ .unwrap();
+ vec![]
}
}
-impl Thread<'_> {
+impl Thread {
pub fn to_html(&self) -> String {
template(r#""#, &[("title", "tbd")]).unwrap()
}
}
-impl<'a> StrMessage<'a> {
+impl StrMessage {
pub fn to_html(&self) -> String {
// TODO test thoroughly
template(
diff --git a/src/templates/xml.rs b/src/templates/xml.rs
@@ -31,7 +31,7 @@ use nanotemplate::template;
// }
// }
-impl Thread<'_> {
+impl Thread {
pub fn to_xml(&self) -> String {
String::new()
}
diff --git a/src/threading.rs b/src/threading.rs
@@ -1,6 +1,7 @@
// Simple threading algorithm based on https://datatracker.ietf.org/doc/html/rfc8621
// A thread is a collection of messages sorted by date.
-// Assumes msg can be found on disk at `path` -- could be made more abstract
+// Assumes msg can be found on disk at `path` -- should be made more abstract to handle other mail
+// stores
use mail_parser::parsers::fields::thread::thread_name;
use mail_parser::{DateTime, Message};