web: version bumps and handle more message body types.
Added handling for text/html, multipart/alternative w/ text/html & text/plain subparts, and multipart/mixed.
This commit is contained in:
parent
84290d1da6
commit
431df7da3b
@ -13,14 +13,14 @@ edition = "2018"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.18"
|
||||
wasm-bindgen-test = "0.3.33"
|
||||
|
||||
[dependencies]
|
||||
console_error_panic_hook = "0.1.6"
|
||||
log = "0.4.14"
|
||||
seed = "0.8.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
log = "0.4.17"
|
||||
seed = "0.9.2"
|
||||
console_log = {git = "http://git.z.xinu.tv/wathiede/console_log"}
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
notmuch = {path = "../notmuch"}
|
||||
|
||||
[package.metadata.wasm-pack.profile.release]
|
||||
|
||||
@ -16,6 +16,9 @@
|
||||
.error {
|
||||
background-color: red;
|
||||
}
|
||||
.text_plain {
|
||||
white-space: pre-line;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
143
web/src/lib.rs
143
web/src/lib.rs
@ -4,9 +4,8 @@
|
||||
#![allow(clippy::wildcard_imports)]
|
||||
|
||||
use log::{error, info, Level};
|
||||
use seed::{prelude::*, *};
|
||||
|
||||
use notmuch::{Content, Part, SearchSummary, ThreadNode, ThreadSet};
|
||||
use seed::{prelude::*, *};
|
||||
|
||||
// ------ ------
|
||||
// Init
|
||||
@ -138,9 +137,11 @@ fn view_message(thread: &ThreadNode) -> Node<Msg> {
|
||||
div![
|
||||
C!["message"],
|
||||
/* TODO(wathiede): collect all the tags and show them here. */
|
||||
/* TODO(wathiede): collect all the attachments from all the subparts */
|
||||
div![C!["header"], "From: ", &message.headers.from],
|
||||
div![C!["header"], "Date: ", &message.headers.date],
|
||||
div![C!["header"], "To: ", &message.headers.to],
|
||||
hr![],
|
||||
div![
|
||||
C!["body"],
|
||||
match &message.body {
|
||||
@ -156,13 +157,59 @@ fn view_body(body: &[Part]) -> Node<Msg> {
|
||||
div![body.iter().map(view_part)]
|
||||
}
|
||||
|
||||
fn view_text_plain(content: &Option<Content>) -> Node<Msg> {
|
||||
match &content {
|
||||
Some(Content::String(content)) => p![C!["text_plain"], content],
|
||||
_ => div![
|
||||
C!["error"],
|
||||
format!("Unhandled content enum for text/plain"),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn view_part(part: &Part) -> Node<Msg> {
|
||||
match part.content_type.as_str() {
|
||||
"text/plain" => match &part.content {
|
||||
Some(Content::String(content)) => pre![content],
|
||||
"text/plain" => view_text_plain(&part.content),
|
||||
"text/html" => {
|
||||
if let Some(Content::String(html)) = &part.content {
|
||||
return div![Node::from_html(None, &html)];
|
||||
} else {
|
||||
div![
|
||||
C!["error"],
|
||||
format!("Unhandled content enum for multipart/mixed"),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/MIME#alternative
|
||||
// RFC1341 states: In general, user agents that compose multipart/alternative entities
|
||||
// should place the body parts in increasing order of preference, that is, with the
|
||||
// preferred format last.
|
||||
"multipart/alternative" => {
|
||||
if let Some(Content::Multipart(parts)) = &part.content {
|
||||
for part in parts.iter().rev() {
|
||||
if part.content_type == "text/html" {
|
||||
if let Some(Content::String(html)) = &part.content {
|
||||
return div![Node::from_html(None, &html)];
|
||||
}
|
||||
}
|
||||
if part.content_type == "text/plain" {
|
||||
return view_text_plain(&part.content);
|
||||
}
|
||||
}
|
||||
div!["No known multipart/alternative parts"]
|
||||
} else {
|
||||
div![
|
||||
C!["error"],
|
||||
format!("multipart/alternative with non-multipart content"),
|
||||
]
|
||||
}
|
||||
}
|
||||
"multipart/mixed" => match &part.content {
|
||||
Some(Content::Multipart(parts)) => div![parts.iter().map(view_part)],
|
||||
_ => div![
|
||||
C!["error"],
|
||||
format!("Unhandled content enum for text/plain"),
|
||||
format!("Unhandled content enum for multipart/mixed"),
|
||||
],
|
||||
},
|
||||
_ => div![
|
||||
@ -187,35 +234,35 @@ fn first_subject(thread: &ThreadNode) -> Option<String> {
|
||||
/*
|
||||
let msg = thread.0.as_ref();
|
||||
if let Some(msg) = msg {
|
||||
div![
|
||||
a![attrs! {At::Href=>api::original(&msg.id)}, "Original"],
|
||||
table![
|
||||
tr![th!["Subject"], td![&msg.headers.subject],],
|
||||
tr![th!["From"], td![&msg.headers.from],],
|
||||
tr![th!["To"], td![&msg.headers.to],],
|
||||
tr![th!["CC"], td![&msg.headers.cc],],
|
||||
tr![th!["BCC"], td![&msg.headers.bcc],],
|
||||
tr![th!["Reply-To"], td![&msg.headers.reply_to],],
|
||||
tr![th!["Date"], td![&msg.headers.date],],
|
||||
],
|
||||
table![
|
||||
tr![th!["MessageId"], td![&msg.id],],
|
||||
tr![
|
||||
th!["Match"],
|
||||
td![if msg.r#match { "true" } else { "false" }],
|
||||
],
|
||||
tr![
|
||||
th!["Excluded"],
|
||||
td![if msg.excluded { "true" } else { "false" }],
|
||||
],
|
||||
tr![th!["Filename"], td![&msg.filename],],
|
||||
tr![th!["Timestamp"], td![msg.timestamp.to_string()],],
|
||||
tr![th!["Date"], td![&msg.date_relative],],
|
||||
tr![th!["Tags"], td![format!("{:?}", msg.tags)],],
|
||||
],
|
||||
]
|
||||
div![
|
||||
a![attrs! {At::Href=>api::original(&msg.id)}, "Original"],
|
||||
table![
|
||||
tr![th!["Subject"], td![&msg.headers.subject],],
|
||||
tr![th!["From"], td![&msg.headers.from],],
|
||||
tr![th!["To"], td![&msg.headers.to],],
|
||||
tr![th!["CC"], td![&msg.headers.cc],],
|
||||
tr![th!["BCC"], td![&msg.headers.bcc],],
|
||||
tr![th!["Reply-To"], td![&msg.headers.reply_to],],
|
||||
tr![th!["Date"], td![&msg.headers.date],],
|
||||
],
|
||||
table![
|
||||
tr![th!["MessageId"], td![&msg.id],],
|
||||
tr![
|
||||
th!["Match"],
|
||||
td![if msg.r#match { "true" } else { "false" }],
|
||||
],
|
||||
tr![
|
||||
th!["Excluded"],
|
||||
td![if msg.excluded { "true" } else { "false" }],
|
||||
],
|
||||
tr![th!["Filename"], td![&msg.filename],],
|
||||
tr![th!["Timestamp"], td![msg.timestamp.to_string()],],
|
||||
tr![th!["Date"], td![&msg.date_relative],],
|
||||
tr![th!["Tags"], td![format!("{:?}", msg.tags)],],
|
||||
],
|
||||
]
|
||||
} else {
|
||||
div![h2!["No message"]]
|
||||
div![h2!["No message"]]
|
||||
}
|
||||
*/
|
||||
|
||||
@ -235,22 +282,22 @@ fn view(model: &Model) -> Node<Msg> {
|
||||
view_message(&thread_node),
|
||||
/*
|
||||
show_results
|
||||
.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(thread_idx, thread)| div![
|
||||
h2![format!("thread {}", thread_idx)],
|
||||
thread
|
||||
.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(thread_node_idx, thread_node)| div![
|
||||
h3![format!("thread node {}", thread_node_idx)],
|
||||
view_message(thread_node)
|
||||
])
|
||||
]),
|
||||
.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(thread_idx, thread)| div![
|
||||
h2![format!("thread {}", thread_idx)],
|
||||
thread
|
||||
.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(thread_node_idx, thread_node)| div![
|
||||
h3![format!("thread node {}", thread_node_idx)],
|
||||
view_message(thread_node)
|
||||
])
|
||||
]),
|
||||
*/
|
||||
pre![format!("Thread: {:#?}", show_results).replace(" ", " ")]
|
||||
pre!["Add zippy for debug dump"] /* pre![format!("Thread: {:#?}", show_results).replace(" ", " ")] */
|
||||
]
|
||||
} else if let Some(search_results) = &model.search_results {
|
||||
let rows = search_results.0.iter().map(|r| {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user