mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-08 18:45:13 +00:00
simplify msg header decoding
This commit is contained in:
parent
f9bed5f3c2
commit
1d969a0d3a
|
@ -56,7 +56,7 @@ macro_rules! make_account_config {
|
||||||
/// Represents the text/plain format as defined in the
|
/// Represents the text/plain format as defined in the
|
||||||
/// [RFC2646](https://www.ietf.org/rfc/rfc2646.txt)
|
/// [RFC2646](https://www.ietf.org/rfc/rfc2646.txt)
|
||||||
pub format: Option<Format>,
|
pub format: Option<Format>,
|
||||||
/// Overrides the default headers displayed at the top of
|
/// Represents the default headers displayed at the top of
|
||||||
/// the read message.
|
/// the read message.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub read_headers: Vec<String>,
|
pub read_headers: Vec<String>,
|
||||||
|
|
|
@ -4,7 +4,7 @@ use chrono::{DateTime, FixedOffset};
|
||||||
use convert_case::{Case, Casing};
|
use convert_case::{Case, Casing};
|
||||||
use html_escape;
|
use html_escape;
|
||||||
use lettre::message::{header::ContentType, Attachment, MultiPart, SinglePart};
|
use lettre::message::{header::ContentType, Attachment, MultiPart, SinglePart};
|
||||||
use log::{debug, info, trace, warn};
|
use log::{info, trace, warn};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
|
@ -31,6 +31,8 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DATE_TIME_FORMAT: &str = "%d-%b-%Y %H:%M:%S %z";
|
||||||
|
|
||||||
/// Representation of a message.
|
/// Representation of a message.
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct Msg {
|
pub struct Msg {
|
||||||
|
@ -73,8 +75,9 @@ impl Msg {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Folds string body from all plain text parts into a single string body. If no plain text
|
/// Folds string body from all plain text parts into a single
|
||||||
/// parts are found, HTML parts are used instead. The result is sanitized (all HTML markup is
|
/// string body. If no plain text parts are found, HTML parts are
|
||||||
|
/// used instead. The result is sanitized (all HTML markup is
|
||||||
/// removed).
|
/// removed).
|
||||||
pub fn fold_text_plain_parts(&self) -> String {
|
pub fn fold_text_plain_parts(&self) -> String {
|
||||||
let (plain, html) = self.parts.iter().fold(
|
let (plain, html) = self.parts.iter().fold(
|
||||||
|
@ -142,7 +145,8 @@ impl Msg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fold string body from all HTML parts into a single string body.
|
/// Fold string body from all HTML parts into a single string
|
||||||
|
/// body.
|
||||||
fn fold_text_html_parts(&self) -> String {
|
fn fold_text_html_parts(&self) -> String {
|
||||||
let text_parts = self
|
let text_parts = self
|
||||||
.parts
|
.parts
|
||||||
|
@ -160,8 +164,9 @@ impl Msg {
|
||||||
text_parts
|
text_parts
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fold string body from all text parts into a single string body. The mime allows users to
|
/// Fold string body from all text parts into a single string
|
||||||
/// choose between plain text parts and html text parts.
|
/// body. The mime allows users to choose between plain text parts
|
||||||
|
/// and html text parts.
|
||||||
pub fn fold_text_parts(&self, text_mime: &str) -> String {
|
pub fn fold_text_parts(&self, text_mime: &str) -> String {
|
||||||
if text_mime == "html" {
|
if text_mime == "html" {
|
||||||
self.fold_text_html_parts()
|
self.fold_text_html_parts()
|
||||||
|
@ -651,42 +656,32 @@ impl Msg {
|
||||||
parsed_mail: mailparse::ParsedMail<'_>,
|
parsed_mail: mailparse::ParsedMail<'_>,
|
||||||
config: &AccountConfig,
|
config: &AccountConfig,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
info!("begin: building message from parsed mail");
|
trace!(">> build message from parsed mail");
|
||||||
trace!("parsed mail: {:?}", parsed_mail);
|
trace!("parsed mail: {:?}", parsed_mail);
|
||||||
|
|
||||||
let mut msg = Msg::default();
|
let mut msg = Msg::default();
|
||||||
|
|
||||||
debug!("parsing headers");
|
|
||||||
for header in parsed_mail.get_headers() {
|
for header in parsed_mail.get_headers() {
|
||||||
|
trace!(">> parse header {:?}", header);
|
||||||
|
|
||||||
let key = header.get_key();
|
let key = header.get_key();
|
||||||
debug!("header key: {:?}", key);
|
trace!("header key: {:?}", key);
|
||||||
|
|
||||||
let val = header.get_value();
|
let val = header.get_value();
|
||||||
let val = String::from_utf8(header.get_value_raw().to_vec())
|
trace!("header value: {:?}", val);
|
||||||
.map(|val| val.trim().to_string())
|
|
||||||
.context(format!(
|
|
||||||
"cannot decode value {:?} from header {:?}",
|
|
||||||
key, val
|
|
||||||
))?;
|
|
||||||
debug!("header value: {:?}", val);
|
|
||||||
|
|
||||||
match key.to_lowercase().as_str() {
|
match key.to_lowercase().as_str() {
|
||||||
"message-id" => msg.message_id = Some(val),
|
"message-id" => msg.message_id = Some(val),
|
||||||
"in-reply-to" => msg.in_reply_to = Some(val),
|
"in-reply-to" => msg.in_reply_to = Some(val),
|
||||||
"subject" => {
|
"subject" => {
|
||||||
msg.subject = rfc2047_decoder::decode(val.as_bytes())?;
|
msg.subject = val;
|
||||||
}
|
}
|
||||||
"date" => {
|
"date" => {
|
||||||
// TODO: use date format instead
|
msg.date = DateTime::parse_from_str(&val, DATE_TIME_FORMAT)
|
||||||
// https://github.com/jonhoo/rust-imap/blob/afbc5118f251da4e3f6a1e560e749c0700020b54/src/types/fetch.rs#L16
|
.map_err(|err| {
|
||||||
msg.date = DateTime::parse_from_rfc2822(
|
warn!("cannot parse message date {:?}, skipping it", val);
|
||||||
val.split_at(val.find(" (").unwrap_or_else(|| val.len())).0,
|
err
|
||||||
)
|
})
|
||||||
.map_err(|err| {
|
.ok();
|
||||||
warn!("cannot parse message date {:?}, skipping it", val);
|
|
||||||
err
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
"from" => {
|
"from" => {
|
||||||
msg.from = from_slice_to_addrs(val)
|
msg.from = from_slice_to_addrs(val)
|
||||||
|
@ -709,19 +704,17 @@ impl Msg {
|
||||||
.context(format!("cannot parse header {:?}", key))?
|
.context(format!("cannot parse header {:?}", key))?
|
||||||
}
|
}
|
||||||
key => {
|
key => {
|
||||||
msg.headers.insert(
|
msg.headers.insert(key.to_lowercase(), val);
|
||||||
key.to_lowercase(),
|
|
||||||
rfc2047_decoder::decode(val.as_bytes()).unwrap_or(val),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
trace!("<< parse header");
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.parts = Parts::from_parsed_mail(config, &parsed_mail)
|
msg.parts = Parts::from_parsed_mail(config, &parsed_mail)
|
||||||
.context("cannot parsed message mime parts")?;
|
.context("cannot parsed message mime parts")?;
|
||||||
trace!("message: {:?}", msg);
|
trace!("message: {:?}", msg);
|
||||||
|
|
||||||
info!("end: building message from parsed mail");
|
info!("<< build message from parsed mail");
|
||||||
Ok(msg)
|
Ok(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue