Populate attribute list

This commit is contained in:
Quentin 2022-07-04 18:14:19 +02:00
parent f5385bba44
commit aca37b64c8
Signed by: quentin
GPG Key ID: E9602264D639FF68
1 changed files with 101 additions and 120 deletions

View File

@ -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!(),