mirror of
https://github.com/chatmail/core.git
synced 2026-04-26 01:46:34 +03:00
Parse standard ndns (e.g. Gmail)
This commit is contained in:
@@ -2324,4 +2324,52 @@ mod tests {
|
||||
"Carl"
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_parse_ndn() {
|
||||
let t = dummy_context().await;
|
||||
t.ctx
|
||||
.set_config(Config::Addr, Some("alice@example.org"))
|
||||
.await
|
||||
.unwrap();
|
||||
t.ctx
|
||||
.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
|
||||
.await
|
||||
.unwrap();
|
||||
t.ctx
|
||||
.set_config(Config::Configured, Some("1"))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
dc_receive_imf(
|
||||
&t.ctx,
|
||||
b"From: alice@example.org\n\
|
||||
To: assidhfaaspocwaeofi@gmail.com\n\
|
||||
Subject: foo\n\
|
||||
Message-ID: <CABXKi8zruXJc_6e4Dr087H5wE7sLp+u250o0N2q5DdjF_r-8wg@mail.gmail.com>\n\
|
||||
Chat-Version: 1.0\n\
|
||||
Chat-Disposition-Notification-To: alice@example.org\n\
|
||||
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
|
||||
\n\
|
||||
hello\n",
|
||||
"INBOX",
|
||||
1,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let chats = Chatlist::try_load(&t.ctx, 0, None, None).await.unwrap();
|
||||
let msg_id = chats.get_msg_id(0).unwrap();
|
||||
|
||||
let raw = include_bytes!("../test-data/message/gmail_ndn.eml");
|
||||
dc_receive_imf(&t.ctx, raw, "INBOX", 1, false)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
Message::load_from_db(&t.ctx, msg_id).await.unwrap().state,
|
||||
MessageState::OutFailed
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1384,6 +1384,28 @@ pub async fn mdn_from_ext(
|
||||
None
|
||||
}
|
||||
|
||||
pub async fn ndn_from_ext(
|
||||
context: &Context,
|
||||
from_id: u32,
|
||||
rfc724_mid: &str,
|
||||
error: impl AsRef<str>,
|
||||
) {
|
||||
if from_id <= DC_MSG_ID_LAST_SPECIAL || rfc724_mid.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
match rfc724_mid_exists(context, rfc724_mid).await {
|
||||
Ok(Some((_, _, msg_id))) => {
|
||||
set_msg_failed(context, msg_id, Some(error)).await;
|
||||
}
|
||||
Ok(None) => info!(
|
||||
context,
|
||||
"Failed to select NDN, could not find failed msg {}", rfc724_mid
|
||||
),
|
||||
Err(e) => info!(context, "Failed to select NDN {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
/// The number of messages assigned to real chat (!=deaddrop, !=trash)
|
||||
pub async fn get_real_msg_cnt(context: &Context) -> i32 {
|
||||
match context
|
||||
|
||||
@@ -54,6 +54,7 @@ pub struct MimeMessage {
|
||||
pub(crate) user_avatar: Option<AvatarAction>,
|
||||
pub(crate) group_avatar: Option<AvatarAction>,
|
||||
pub(crate) reports: Vec<Report>,
|
||||
pub(crate) failed_msg: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -182,6 +183,7 @@ impl MimeMessage {
|
||||
message_kml: None,
|
||||
user_avatar: None,
|
||||
group_avatar: None,
|
||||
failed_msg: None,
|
||||
};
|
||||
parser.parse_mime_recursive(context, &mail).await?;
|
||||
parser.parse_headers(context)?;
|
||||
@@ -550,8 +552,8 @@ impl MimeMessage {
|
||||
(mime::MULTIPART, "report") => {
|
||||
/* RFC 6522: the first part is for humans, the second for machines */
|
||||
if mail.subparts.len() >= 2 {
|
||||
if let Some(report_type) = mail.ctype.params.get("report-type") {
|
||||
if report_type == "disposition-notification" {
|
||||
match mail.ctype.params.get("report-type").map(|s| s as &str) {
|
||||
Some("disposition-notification") => {
|
||||
if let Some(report) = self.process_report(context, mail)? {
|
||||
self.reports.push(report);
|
||||
}
|
||||
@@ -565,13 +567,24 @@ impl MimeMessage {
|
||||
self.parts.push(part);
|
||||
|
||||
any_part_added = true;
|
||||
} else {
|
||||
/* eg. `report-type=delivery-status`;
|
||||
maybe we should show them as a little error icon */
|
||||
}
|
||||
Some("delivery-status") => {
|
||||
if let Some(report) = self.process_delivery_status(context, mail)? {
|
||||
self.failed_msg = Some(report);
|
||||
}
|
||||
|
||||
let mut part = Part::default();
|
||||
part.typ = Viewtype::Unknown;
|
||||
self.parts.push(part);
|
||||
|
||||
any_part_added = true;
|
||||
}
|
||||
Some(_) => {
|
||||
if let Some(first) = mail.subparts.iter().next() {
|
||||
any_part_added = self.parse_mime_recursive(context, first).await?;
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -842,10 +855,6 @@ impl MimeMessage {
|
||||
|
||||
/// Handle reports (only MDNs for now)
|
||||
pub async fn handle_reports(&self, context: &Context, from_id: u32, sent_timestamp: i64) {
|
||||
if self.reports.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
for report in &self.reports {
|
||||
for original_message_id in
|
||||
std::iter::once(&report.original_message_id).chain(&report.additional_message_ids)
|
||||
@@ -858,6 +867,41 @@ impl MimeMessage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(original_message_id) = &self.failed_msg {
|
||||
message::ndn_from_ext(context, from_id, original_message_id, "TODO error message").await
|
||||
}
|
||||
}
|
||||
|
||||
fn process_delivery_status(
|
||||
&self,
|
||||
context: &Context,
|
||||
report: &mailparse::ParsedMail<'_>,
|
||||
) -> Result<Option<String>> {
|
||||
// parse as mailheaders
|
||||
if let Some(original_msg) = report
|
||||
.subparts
|
||||
.iter()
|
||||
.find(|p| p.ctype.mimetype == "message/rfc822")
|
||||
{
|
||||
let report_body = original_msg.get_body_raw()?;
|
||||
let (report_fields, _) = mailparse::parse_headers(&report_body)?;
|
||||
|
||||
if let Some(original_message_id) = report_fields
|
||||
.get_header_value(HeaderDef::MessageId)
|
||||
.and_then(|v| parse_message_id(&v).ok())
|
||||
{
|
||||
return Ok(Some(original_message_id));
|
||||
}
|
||||
|
||||
warn!(
|
||||
context,
|
||||
"ignoring unknown ndn-notification, Message-Id: {:?}",
|
||||
report_fields.get_header_value(HeaderDef::MessageId)
|
||||
);
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user