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"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wasm-bindgen-test = "0.3.18"
|
wasm-bindgen-test = "0.3.33"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
console_error_panic_hook = "0.1.6"
|
console_error_panic_hook = "0.1.7"
|
||||||
log = "0.4.14"
|
log = "0.4.17"
|
||||||
seed = "0.8.0"
|
seed = "0.9.2"
|
||||||
console_log = {git = "http://git.z.xinu.tv/wathiede/console_log"}
|
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"}
|
notmuch = {path = "../notmuch"}
|
||||||
|
|
||||||
[package.metadata.wasm-pack.profile.release]
|
[package.metadata.wasm-pack.profile.release]
|
||||||
|
|||||||
@ -16,6 +16,9 @@
|
|||||||
.error {
|
.error {
|
||||||
background-color: red;
|
background-color: red;
|
||||||
}
|
}
|
||||||
|
.text_plain {
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||
117
web/src/lib.rs
117
web/src/lib.rs
@ -4,9 +4,8 @@
|
|||||||
#![allow(clippy::wildcard_imports)]
|
#![allow(clippy::wildcard_imports)]
|
||||||
|
|
||||||
use log::{error, info, Level};
|
use log::{error, info, Level};
|
||||||
use seed::{prelude::*, *};
|
|
||||||
|
|
||||||
use notmuch::{Content, Part, SearchSummary, ThreadNode, ThreadSet};
|
use notmuch::{Content, Part, SearchSummary, ThreadNode, ThreadSet};
|
||||||
|
use seed::{prelude::*, *};
|
||||||
|
|
||||||
// ------ ------
|
// ------ ------
|
||||||
// Init
|
// Init
|
||||||
@ -138,9 +137,11 @@ fn view_message(thread: &ThreadNode) -> Node<Msg> {
|
|||||||
div![
|
div![
|
||||||
C!["message"],
|
C!["message"],
|
||||||
/* TODO(wathiede): collect all the tags and show them here. */
|
/* 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"], "From: ", &message.headers.from],
|
||||||
div![C!["header"], "Date: ", &message.headers.date],
|
div![C!["header"], "Date: ", &message.headers.date],
|
||||||
div![C!["header"], "To: ", &message.headers.to],
|
div![C!["header"], "To: ", &message.headers.to],
|
||||||
|
hr![],
|
||||||
div![
|
div![
|
||||||
C!["body"],
|
C!["body"],
|
||||||
match &message.body {
|
match &message.body {
|
||||||
@ -156,14 +157,60 @@ fn view_body(body: &[Part]) -> Node<Msg> {
|
|||||||
div![body.iter().map(view_part)]
|
div![body.iter().map(view_part)]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_part(part: &Part) -> Node<Msg> {
|
fn view_text_plain(content: &Option<Content>) -> Node<Msg> {
|
||||||
match part.content_type.as_str() {
|
match &content {
|
||||||
"text/plain" => match &part.content {
|
Some(Content::String(content)) => p![C!["text_plain"], content],
|
||||||
Some(Content::String(content)) => pre![content],
|
|
||||||
_ => div![
|
_ => div![
|
||||||
C!["error"],
|
C!["error"],
|
||||||
format!("Unhandled content enum for text/plain"),
|
format!("Unhandled content enum for text/plain"),
|
||||||
],
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view_part(part: &Part) -> Node<Msg> {
|
||||||
|
match part.content_type.as_str() {
|
||||||
|
"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 multipart/mixed"),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
_ => div![
|
_ => div![
|
||||||
C!["error"],
|
C!["error"],
|
||||||
@ -187,35 +234,35 @@ fn first_subject(thread: &ThreadNode) -> Option<String> {
|
|||||||
/*
|
/*
|
||||||
let msg = thread.0.as_ref();
|
let msg = thread.0.as_ref();
|
||||||
if let Some(msg) = msg {
|
if let Some(msg) = msg {
|
||||||
div![
|
div![
|
||||||
a![attrs! {At::Href=>api::original(&msg.id)}, "Original"],
|
a![attrs! {At::Href=>api::original(&msg.id)}, "Original"],
|
||||||
table![
|
table![
|
||||||
tr![th!["Subject"], td![&msg.headers.subject],],
|
tr![th!["Subject"], td![&msg.headers.subject],],
|
||||||
tr![th!["From"], td![&msg.headers.from],],
|
tr![th!["From"], td![&msg.headers.from],],
|
||||||
tr![th!["To"], td![&msg.headers.to],],
|
tr![th!["To"], td![&msg.headers.to],],
|
||||||
tr![th!["CC"], td![&msg.headers.cc],],
|
tr![th!["CC"], td![&msg.headers.cc],],
|
||||||
tr![th!["BCC"], td![&msg.headers.bcc],],
|
tr![th!["BCC"], td![&msg.headers.bcc],],
|
||||||
tr![th!["Reply-To"], td![&msg.headers.reply_to],],
|
tr![th!["Reply-To"], td![&msg.headers.reply_to],],
|
||||||
tr![th!["Date"], td![&msg.headers.date],],
|
tr![th!["Date"], td![&msg.headers.date],],
|
||||||
],
|
],
|
||||||
table![
|
table![
|
||||||
tr![th!["MessageId"], td![&msg.id],],
|
tr![th!["MessageId"], td![&msg.id],],
|
||||||
tr![
|
tr![
|
||||||
th!["Match"],
|
th!["Match"],
|
||||||
td![if msg.r#match { "true" } else { "false" }],
|
td![if msg.r#match { "true" } else { "false" }],
|
||||||
],
|
],
|
||||||
tr![
|
tr![
|
||||||
th!["Excluded"],
|
th!["Excluded"],
|
||||||
td![if msg.excluded { "true" } else { "false" }],
|
td![if msg.excluded { "true" } else { "false" }],
|
||||||
],
|
],
|
||||||
tr![th!["Filename"], td![&msg.filename],],
|
tr![th!["Filename"], td![&msg.filename],],
|
||||||
tr![th!["Timestamp"], td![msg.timestamp.to_string()],],
|
tr![th!["Timestamp"], td![msg.timestamp.to_string()],],
|
||||||
tr![th!["Date"], td![&msg.date_relative],],
|
tr![th!["Date"], td![&msg.date_relative],],
|
||||||
tr![th!["Tags"], td![format!("{:?}", msg.tags)],],
|
tr![th!["Tags"], td![format!("{:?}", msg.tags)],],
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
div![h2!["No message"]]
|
div![h2!["No message"]]
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -250,7 +297,7 @@ fn view(model: &Model) -> Node<Msg> {
|
|||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
*/
|
*/
|
||||||
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 {
|
} else if let Some(search_results) = &model.search_results {
|
||||||
let rows = search_results.0.iter().map(|r| {
|
let rows = search_results.0.iter().map(|r| {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user