diff --git a/server/src/graphql.rs b/server/src/graphql.rs index 3549298..21cadf2 100644 --- a/server/src/graphql.rs +++ b/server/src/graphql.rs @@ -104,6 +104,7 @@ pub struct Header { #[derive(Debug)] pub struct UnhandledContentType { text: String, + content_tree: String, } #[Object] @@ -111,6 +112,9 @@ impl UnhandledContentType { async fn contents(&self) -> &str { &self.text } + async fn content_tree(&self) -> &str { + &self.content_tree + } } #[derive(Debug)] @@ -368,6 +372,23 @@ impl QueryRoot { content_tree }, }), + + Body::UnhandledContentType(UnhandledContentType { content_tree, .. }) => { + let body_start = mmap + .windows(2) + .take(20_000) + .position(|w| w == b"\n\n") + .unwrap_or(0); + let body = mmap[body_start + 2..].to_vec(); + Body::UnhandledContentType(UnhandledContentType { + text: String::from_utf8(body)?, + content_tree: if debug_content_tree { + render_content_type_tree(&m) + } else { + content_tree + }, + }) + } b => b, }; let headers = m @@ -508,7 +529,8 @@ fn extract_unhandled(m: &ParsedMail) -> Result { render_content_type_tree(m) ); Ok(Body::UnhandledContentType(UnhandledContentType { - text: msg, + text: m.get_body()?, + content_tree: render_content_type_tree(m), })) } @@ -628,8 +650,15 @@ fn flatten_body_parts(parts: &[Body]) -> Body { ) } Body::Html(Html { html, .. }) => html.clone(), - Body::UnhandledContentType(UnhandledContentType { text }) => { - format!(r#"

{text}

"#) + Body::UnhandledContentType(UnhandledContentType { text, .. }) => { + error!("text len {}", text.len()); + format!( + r#"

{}

"#, + // 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(&text.trim_matches('\n')) + ) } }) .collect::>() diff --git a/web/graphql/schema.json b/web/graphql/schema.json index 524bcac..38ef135 100644 --- a/web/graphql/schema.json +++ b/web/graphql/schema.json @@ -1505,6 +1505,22 @@ "ofType": null } } + }, + { + "args": [], + "deprecationReason": null, + "description": null, + "isDeprecated": false, + "name": "contentTree", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } } ], "inputFields": null, diff --git a/web/graphql/show_thread.graphql b/web/graphql/show_thread.graphql index e4dc9e7..2cab65b 100644 --- a/web/graphql/show_thread.graphql +++ b/web/graphql/show_thread.graphql @@ -23,6 +23,7 @@ query ShowThreadQuery($threadId: String!) { __typename ... on UnhandledContentType { contents + contentTree } ... on PlainText { contents diff --git a/web/src/view/mod.rs b/web/src/view/mod.rs index bdaeb2d..0b925d8 100644 --- a/web/src/view/mod.rs +++ b/web/src/view/mod.rs @@ -691,8 +691,13 @@ fn message_render(msg: &ShowThreadQueryThreadMessages, open: bool) -> Node C!["body"], match &msg.body { ShowThreadQueryThreadMessagesBody::UnhandledContentType( - ShowThreadQueryThreadMessagesBodyOnUnhandledContentType { contents }, - ) => pre![C!["error"], contents], + ShowThreadQueryThreadMessagesBodyOnUnhandledContentType { contents ,content_tree}, + ) => div![ + raw_text_message(&contents), + div![C!["error"], + view_content_tree(&content_tree), + ] + ], ShowThreadQueryThreadMessagesBody::PlainText( ShowThreadQueryThreadMessagesBodyOnPlainText { contents,