Populate attribute list
This commit is contained in:
parent
f5385bba44
commit
aca37b64c8
1 changed files with 101 additions and 120 deletions
|
@ -1,4 +1,5 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
use std::num::NonZeroU32;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -278,64 +279,12 @@ impl MailboxView {
|
|||
FetchAttribute::Envelope => {
|
||||
attributes.push(MessageAttribute::Envelope(message_envelope(&parsed)))
|
||||
}
|
||||
FetchAttribute::Body => {
|
||||
/*
|
||||
* CAPTURE:
|
||||
b fetch 29878:29879 (BODY)
|
||||
* 29878 FETCH (BODY (("text" "plain" ("charset" "utf-8") NIL NIL "quoted-printable" 3264 82)("text" "html" ("charset" "utf-8") NIL NIL "quoted-printable" 31834 643) "alternative"))
|
||||
* 29879 FETCH (BODY ("text" "html" ("charset" "us-ascii") NIL NIL "7bit" 4107 131))
|
||||
^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^ ^^^^^^ ^^^^ ^^^
|
||||
| | | | | | number of lines
|
||||
| | | | | size
|
||||
| | | | content transfer encoding
|
||||
| | | description
|
||||
| | id
|
||||
| parameter list
|
||||
b OK Fetch completed (0.001 + 0.000 secs).
|
||||
*
|
||||
*/
|
||||
|
||||
/*match parsed.structure {
|
||||
Part(part_id) => {
|
||||
match parsed.parts.get(part_id)? {
|
||||
Text(
|
||||
let fb = FetchBody {
|
||||
parameter_list: vec![],
|
||||
id: NString(None),
|
||||
descritpion: NString(None),
|
||||
// Default value is 7bit"
|
||||
// https://datatracker.ietf.org/doc/html/rfc2045#section-6.1
|
||||
content_transfer_encoding: IString::try_from("7bit").unwrap(),
|
||||
};
|
||||
}
|
||||
}
|
||||
List(part_list) => todo!(),
|
||||
MultiPart((first, rest)) => todo!(),
|
||||
}*/
|
||||
|
||||
// @TODO This is a stub
|
||||
let is = IString::try_from("test").unwrap();
|
||||
let b = BodyStructure::Single {
|
||||
body: FetchBody {
|
||||
basic: BasicFields {
|
||||
parameter_list: vec![],
|
||||
id: NString(Some(is.clone())),
|
||||
description: NString(Some(is.clone())),
|
||||
content_transfer_encoding: is.clone(),
|
||||
size: 1,
|
||||
},
|
||||
specific: SpecificFields::Text {
|
||||
// @FIXME I do not understand yet how this part works
|
||||
subtype: is,
|
||||
number_of_lines: 1,
|
||||
},
|
||||
},
|
||||
// Always None for Body, can be populated for BodyStructure
|
||||
extension: None,
|
||||
};
|
||||
|
||||
attributes.push(MessageAttribute::Body(b));
|
||||
}
|
||||
FetchAttribute::Body => attributes.push(MessageAttribute::Body(
|
||||
build_imap_email_struct(&parsed, &parsed.structure)?,
|
||||
)),
|
||||
FetchAttribute::BodyStructure => attributes.push(MessageAttribute::Body(
|
||||
build_imap_email_struct(&parsed, &parsed.structure)?,
|
||||
)),
|
||||
FetchAttribute::BodyExt {
|
||||
section,
|
||||
partial,
|
||||
|
@ -350,30 +299,6 @@ impl MailboxView {
|
|||
data: NString(Some(is)),
|
||||
})
|
||||
}
|
||||
FetchAttribute::BodyStructure => {
|
||||
// @TODO This is a stub
|
||||
let is = IString::try_from("test").unwrap();
|
||||
let b = BodyStructure::Single {
|
||||
body: FetchBody {
|
||||
basic: BasicFields {
|
||||
parameter_list: vec![],
|
||||
id: NString(Some(is.clone())),
|
||||
description: NString(Some(is.clone())),
|
||||
content_transfer_encoding: is.clone(),
|
||||
size: 1,
|
||||
},
|
||||
specific: SpecificFields::Text {
|
||||
// @FIXME I do not understand yet how this part works
|
||||
subtype: is,
|
||||
number_of_lines: 1,
|
||||
},
|
||||
},
|
||||
// Always None for Body, can be populated for BodyStructure
|
||||
extension: None,
|
||||
};
|
||||
|
||||
attributes.push(MessageAttribute::BodyStructure(b));
|
||||
}
|
||||
FetchAttribute::InternalDate => {
|
||||
attributes.push(MessageAttribute::InternalDate(MyDateTime(
|
||||
Utc.fix()
|
||||
|
@ -564,6 +489,20 @@ fn convert_address(a: &mail_parser::Addr<'_>) -> Address {
|
|||
)
|
||||
}
|
||||
|
||||
/*
|
||||
--CAPTURE--
|
||||
b fetch 29878:29879 (BODY)
|
||||
* 29878 FETCH (BODY (("text" "plain" ("charset" "utf-8") NIL NIL "quoted-printable" 3264 82)("text" "html" ("charset" "utf-8") NIL NIL "quoted-printable" 31834 643) "alternative"))
|
||||
* 29879 FETCH (BODY ("text" "html" ("charset" "us-ascii") NIL NIL "7bit" 4107 131))
|
||||
^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^ ^^^^^^ ^^^^ ^^^
|
||||
| | | | | | number of lines
|
||||
| | | | | size
|
||||
| | | | content transfer encoding
|
||||
| | | description
|
||||
| | id
|
||||
| parameter list
|
||||
b OK Fetch completed (0.001 + 0.000 secs).
|
||||
*/
|
||||
fn build_imap_email_struct<'a>(
|
||||
msg: &Message<'a>,
|
||||
node: &MessageStructure,
|
||||
|
@ -574,47 +513,89 @@ fn build_imap_email_struct<'a>(
|
|||
"Email part referenced in email structure is missing"
|
||||
))?;
|
||||
match part {
|
||||
MessagePart::Text(bp) => Ok(BodyStructure::Single {
|
||||
body: FetchBody {
|
||||
basic: BasicFields {
|
||||
parameter_list: vec![], //@TODO
|
||||
id: match bp.headers_rfc.get(&RfcHeader::ContentId) {
|
||||
Some(HeaderValue::Text(v)) => {
|
||||
NString(IString::try_from(v.clone().into_owned()).ok())
|
||||
}
|
||||
_ => NString(None),
|
||||
},
|
||||
description: NString(None), //@TODO
|
||||
content_transfer_encoding: match bp
|
||||
.headers_rfc
|
||||
.get(&RfcHeader::ContentTransferEncoding)
|
||||
{
|
||||
Some(HeaderValue::Text(v)) => {
|
||||
IString::try_from(v.clone().into_owned())
|
||||
.unwrap_or(unchecked_istring("7bit"))
|
||||
}
|
||||
_ => unchecked_istring("7bit"),
|
||||
},
|
||||
size: u32::try_from(bp.len())?,
|
||||
},
|
||||
specific: SpecificFields::Text {
|
||||
subtype: match bp.headers_rfc.get(&RfcHeader::ContentType) {
|
||||
Some(HeaderValue::ContentType(ContentType {
|
||||
c_subtype: Some(st),
|
||||
..
|
||||
})) => IString::try_from(st.clone().into_owned())
|
||||
.unwrap_or(unchecked_istring("plain")),
|
||||
_ => unchecked_istring("plain"),
|
||||
},
|
||||
number_of_lines: u32::try_from(bp.get_text_contents().lines().count())?,
|
||||
},
|
||||
},
|
||||
extension: None,
|
||||
}),
|
||||
MessagePart::Multipart(_) => {
|
||||
unreachable!("A multipart entry can not be found here.")
|
||||
}
|
||||
_ => todo!(),
|
||||
MessagePart::Text(bp) => {
|
||||
// Extract subtype+attributes from Content-Type header
|
||||
let (st, ct_attrs) = match bp.headers_rfc.get(&RfcHeader::ContentType) {
|
||||
Some(HeaderValue::ContentType(c)) => {
|
||||
(c.c_subtype.as_ref(), c.attributes.as_ref())
|
||||
}
|
||||
_ => (None, None),
|
||||
};
|
||||
|
||||
// Transform the Content-Type attributes into IMAP's parameter list
|
||||
// Also check if there is a charset defined.
|
||||
let (charset_found, mut parameter_list) = ct_attrs
|
||||
.map(|attr| {
|
||||
attr.iter().fold(
|
||||
(false, vec![]),
|
||||
|(charset_found, mut param_list), (k, v)| {
|
||||
let nk = k.to_lowercase();
|
||||
match (
|
||||
IString::try_from(k.as_ref()),
|
||||
IString::try_from(v.as_ref()),
|
||||
) {
|
||||
(Ok(ik), Ok(iv)) => param_list.push((ik, iv)),
|
||||
_ => (),
|
||||
};
|
||||
|
||||
(charset_found || nk == "charset", param_list)
|
||||
},
|
||||
)
|
||||
})
|
||||
.unwrap_or((false, vec![]));
|
||||
|
||||
// If the charset is not defined, set it to "us-ascii"
|
||||
if !charset_found {
|
||||
parameter_list
|
||||
.push((unchecked_istring("charset"), unchecked_istring("us-ascii")));
|
||||
}
|
||||
|
||||
// If the subtype is not defined, set it to "plain"
|
||||
let subtype = st
|
||||
.map(|st| IString::try_from(st.clone().into_owned()).ok())
|
||||
.flatten()
|
||||
.unwrap_or(unchecked_istring("plain"));
|
||||
|
||||
Ok(BodyStructure::Single {
|
||||
body: FetchBody {
|
||||
basic: BasicFields {
|
||||
parameter_list,
|
||||
id: match bp.headers_rfc.get(&RfcHeader::ContentId) {
|
||||
Some(HeaderValue::Text(v)) => {
|
||||
NString(IString::try_from(v.clone().into_owned()).ok())
|
||||
}
|
||||
_ => NString(None),
|
||||
},
|
||||
description: NString(None), //@TODO
|
||||
content_transfer_encoding: match bp
|
||||
.headers_rfc
|
||||
.get(&RfcHeader::ContentTransferEncoding)
|
||||
{
|
||||
Some(HeaderValue::Text(v)) => {
|
||||
IString::try_from(v.clone().into_owned())
|
||||
.unwrap_or(unchecked_istring("7bit"))
|
||||
}
|
||||
_ => unchecked_istring("7bit"),
|
||||
},
|
||||
size: u32::try_from(bp.len())?,
|
||||
},
|
||||
specific: SpecificFields::Text {
|
||||
subtype,
|
||||
number_of_lines: u32::try_from(
|
||||
bp.get_text_contents().lines().count(),
|
||||
)?,
|
||||
},
|
||||
},
|
||||
extension: None,
|
||||
})
|
||||
},
|
||||
MessagePart::Html(_) => todo!(),
|
||||
MessagePart::Binary(_) => todo!(),
|
||||
MessagePart::InlineBinary(_) => todo!(),
|
||||
MessagePart::Message(_) => todo!(),
|
||||
}
|
||||
}
|
||||
MessageStructure::List(l) => todo!(),
|
||||
|
|
Loading…
Reference in a new issue