Compare commits
No commits in common. "07c0150d3effa56b05dd79923328dd150280bd18" and "2671a3b787aabf5e87e3a149abb9f0ccb4b6d521" have entirely different histories.
07c0150d3e
...
2671a3b787
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -2469,7 +2469,7 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "letterbox"
|
||||
version = "0.0.53"
|
||||
version = "0.0.52"
|
||||
dependencies = [
|
||||
"build-info",
|
||||
"build-info-build",
|
||||
@ -2988,7 +2988,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "notmuch"
|
||||
version = "0.0.53"
|
||||
version = "0.0.52"
|
||||
dependencies = [
|
||||
"itertools 0.10.5",
|
||||
"log",
|
||||
@ -3625,7 +3625,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "procmail2notmuch"
|
||||
version = "0.0.53"
|
||||
version = "0.0.52"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
]
|
||||
@ -4547,7 +4547,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "server"
|
||||
version = "0.0.53"
|
||||
version = "0.0.52"
|
||||
dependencies = [
|
||||
"ammonia",
|
||||
"anyhow",
|
||||
@ -4646,7 +4646,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "shared"
|
||||
version = "0.0.53"
|
||||
version = "0.0.52"
|
||||
dependencies = [
|
||||
"build-info",
|
||||
"notmuch",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "notmuch"
|
||||
version = "0.0.53"
|
||||
version = "0.0.52"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "procmail2notmuch"
|
||||
version = "0.0.53"
|
||||
version = "0.0.52"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "server"
|
||||
version = "0.0.53"
|
||||
version = "0.0.52"
|
||||
edition = "2021"
|
||||
default-run = "server"
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::{fmt, str::FromStr};
|
||||
use std::str::FromStr;
|
||||
|
||||
use async_graphql::{
|
||||
connection::{self, Connection, Edge, OpaqueCursor},
|
||||
@ -235,18 +235,6 @@ pub struct Email {
|
||||
pub addr: Option<String>,
|
||||
}
|
||||
|
||||
impl fmt::Display for Email {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
match (&self.name, &self.addr) {
|
||||
(Some(name), Some(addr)) => write!(f, "{name} <{addr}>")?,
|
||||
(Some(name), None) => write!(f, "{name}")?,
|
||||
(None, Some(addr)) => write!(f, "{addr}")?,
|
||||
(None, None) => write!(f, "<UNKNOWN>")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(SimpleObject)]
|
||||
pub struct Tag {
|
||||
pub name: String,
|
||||
|
||||
@ -20,15 +20,14 @@ use crate::{
|
||||
linkify_html, InlineStyle, Query, SanitizeHtml, Transformer,
|
||||
};
|
||||
|
||||
const TEXT_PLAIN: &'static str = "text/plain";
|
||||
const TEXT_HTML: &'static str = "text/html";
|
||||
const IMAGE_JPEG: &'static str = "image/jpeg";
|
||||
const IMAGE_PJPEG: &'static str = "image/pjpeg";
|
||||
const IMAGE_PNG: &'static str = "image/png";
|
||||
const MESSAGE_RFC822: &'static str = "message/rfc822";
|
||||
const MULTIPART_ALTERNATIVE: &'static str = "multipart/alternative";
|
||||
const MULTIPART_MIXED: &'static str = "multipart/mixed";
|
||||
const MULTIPART_RELATED: &'static str = "multipart/related";
|
||||
const TEXT_HTML: &'static str = "text/html";
|
||||
const TEXT_PLAIN: &'static str = "text/plain";
|
||||
|
||||
const MAX_RAW_MESSAGE_SIZE: usize = 100_000;
|
||||
|
||||
@ -175,9 +174,7 @@ pub async fn thread(
|
||||
.and_then(|d| mailparse::dateparse(&d).ok());
|
||||
let cid_prefix = shared::urls::cid_prefix(None, &id);
|
||||
let base_url = None;
|
||||
let mut part_addr = Vec::new();
|
||||
part_addr.push(id.to_string());
|
||||
let body = match extract_body(&m, &mut part_addr)? {
|
||||
let body = match extract_body(&m, &id)? {
|
||||
Body::PlainText(PlainText { text, content_tree }) => {
|
||||
let text = if text.len() > MAX_RAW_MESSAGE_SIZE {
|
||||
format!(
|
||||
@ -404,14 +401,16 @@ pub fn attachment_bytes(nm: &Notmuch, id: &str, idx: &[usize]) -> Result<Attachm
|
||||
Err(ServerError::PartNotFound)
|
||||
}
|
||||
|
||||
fn extract_body(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Body, ServerError> {
|
||||
fn extract_body(m: &ParsedMail, id: &str) -> Result<Body, ServerError> {
|
||||
let mut part_addr = Vec::new();
|
||||
part_addr.push(id.to_string());
|
||||
let body = m.get_body()?;
|
||||
let ret = match m.ctype.mimetype.as_str() {
|
||||
TEXT_PLAIN => return Ok(Body::text(body)),
|
||||
TEXT_HTML => return Ok(Body::html(body)),
|
||||
MULTIPART_MIXED => extract_mixed(m, part_addr),
|
||||
MULTIPART_ALTERNATIVE => extract_alternative(m, part_addr),
|
||||
MULTIPART_RELATED => extract_related(m, part_addr),
|
||||
MULTIPART_MIXED => extract_mixed(m, &mut part_addr),
|
||||
MULTIPART_ALTERNATIVE => extract_alternative(m, &mut part_addr),
|
||||
MULTIPART_RELATED => extract_related(m, &mut part_addr),
|
||||
_ => extract_unhandled(m),
|
||||
};
|
||||
if let Err(err) = ret {
|
||||
@ -481,14 +480,13 @@ fn extract_alternative(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Bo
|
||||
// 'serially'.
|
||||
fn extract_mixed(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Body, ServerError> {
|
||||
let handled_types = vec![
|
||||
IMAGE_JPEG,
|
||||
IMAGE_PJPEG,
|
||||
IMAGE_PNG,
|
||||
MESSAGE_RFC822,
|
||||
MULTIPART_ALTERNATIVE,
|
||||
MULTIPART_RELATED,
|
||||
TEXT_HTML,
|
||||
TEXT_PLAIN,
|
||||
IMAGE_JPEG,
|
||||
IMAGE_PJPEG,
|
||||
IMAGE_PNG,
|
||||
];
|
||||
let mut unhandled_types: Vec<_> = m
|
||||
.subparts
|
||||
@ -504,7 +502,6 @@ fn extract_mixed(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Body, Se
|
||||
for (idx, sp) in m.subparts.iter().enumerate() {
|
||||
part_addr.push(idx.to_string());
|
||||
match sp.ctype.mimetype.as_str() {
|
||||
MESSAGE_RFC822 => parts.push(extract_rfc822(&sp, part_addr)?),
|
||||
MULTIPART_RELATED => parts.push(extract_related(sp, part_addr)?),
|
||||
MULTIPART_ALTERNATIVE => parts.push(extract_alternative(sp, part_addr)?),
|
||||
TEXT_PLAIN => parts.push(Body::text(sp.get_body()?)),
|
||||
@ -549,7 +546,7 @@ fn flatten_body_parts(parts: &[Body]) -> Body {
|
||||
// Trim newlines to prevent excessive white space at the beginning/end of
|
||||
// presenation. Leave tabs and spaces incase plain text attempts to center a
|
||||
// header on the first line.
|
||||
linkify_html(&html_escape::encode_text(text).trim_matches('\n'))
|
||||
linkify_html(&text.trim_matches('\n'))
|
||||
)
|
||||
}
|
||||
Body::Html(Html { html, .. }) => html.clone(),
|
||||
@ -560,14 +557,14 @@ fn flatten_body_parts(parts: &[Body]) -> Body {
|
||||
// Trim newlines to prevent excessive white space at the beginning/end of
|
||||
// presenation. Leave tabs and spaces incase plain text attempts to center a
|
||||
// header on the first line.
|
||||
linkify_html(&html_escape::encode_text(text).trim_matches('\n'))
|
||||
linkify_html(&text.trim_matches('\n'))
|
||||
)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
info!("flatten_body_parts {}", parts.len());
|
||||
info!("flatten_body_parts {} {html}", parts.len());
|
||||
Body::html(html)
|
||||
}
|
||||
|
||||
@ -707,44 +704,6 @@ fn extract_attachment(m: &ParsedMail, id: &str, idx: &[usize]) -> Option<Attachm
|
||||
bytes,
|
||||
});
|
||||
}
|
||||
fn email_address_strings(emails: &[Email]) -> Vec<String> {
|
||||
emails
|
||||
.iter()
|
||||
.map(|e| e.to_string())
|
||||
.inspect(|e| info!("e {e}"))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn extract_rfc822(m: &ParsedMail, part_addr: &mut Vec<String>) -> Result<Body, ServerError> {
|
||||
fn extract_headers(m: &ParsedMail) -> Result<Body, ServerError> {
|
||||
let path = "<in-memory>";
|
||||
let from = email_address_strings(&email_addresses(path, &m, "from")?).join(", ");
|
||||
let to = email_address_strings(&email_addresses(path, &m, "to")?).join(", ");
|
||||
let cc = email_address_strings(&email_addresses(path, &m, "cc")?).join(", ");
|
||||
let date = m.headers.get_first_value("date").unwrap_or(String::new());
|
||||
let subject = m
|
||||
.headers
|
||||
.get_first_value("subject")
|
||||
.unwrap_or(String::new());
|
||||
let text = format!(
|
||||
r#"
|
||||
---------- Forwarded message ----------
|
||||
From: {from}
|
||||
To: {to}
|
||||
CC: {cc}
|
||||
Date: {date}
|
||||
Subject: {subject}
|
||||
"#
|
||||
);
|
||||
Ok(Body::text(text))
|
||||
}
|
||||
let inner_body = m.get_body()?;
|
||||
let inner_m = parse_mail(inner_body.as_bytes())?;
|
||||
let headers = extract_headers(&inner_m)?;
|
||||
let body = extract_body(&inner_m, part_addr)?;
|
||||
|
||||
Ok(flatten_body_parts(&[headers, body]))
|
||||
}
|
||||
|
||||
pub fn get_attachment_filename(header_value: &str) -> &str {
|
||||
info!("get_attachment_filename {header_value}");
|
||||
|
||||
@ -230,6 +230,7 @@ impl TantivyConnection {
|
||||
}
|
||||
info!("tantivy::count {query:?}");
|
||||
use tantivy::collector::Count;
|
||||
let term = query.remainder.join(" ");
|
||||
let (searcher, query) = self.searcher_and_query(&query)?;
|
||||
Ok(searcher.search(&query, &Count)?)
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "shared"
|
||||
version = "0.0.53"
|
||||
version = "0.0.52"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
version = "0.0.53"
|
||||
version = "0.0.52"
|
||||
name = "letterbox"
|
||||
repository = "https://github.com/seed-rs/seed-quickstart"
|
||||
authors = ["Bill Thiede <git@xinu.tv>"]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user