mirror of
https://github.com/chatmail/core.git
synced 2026-04-05 15:02:11 +03:00
Compare commits
11 Commits
v1.138.5
...
add_hop_in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ae12e83e1 | ||
|
|
2d3ff61a44 | ||
|
|
04ca047370 | ||
|
|
8a60c49b24 | ||
|
|
03553cfe47 | ||
|
|
69b9e3c5ec | ||
|
|
d185318f46 | ||
|
|
3f8878fe7a | ||
|
|
d8b8a3839c | ||
|
|
48a3643927 | ||
|
|
4fa0edcfbf |
@@ -1067,7 +1067,7 @@ INSERT INTO msgs
|
||||
txt, subject, txt_raw, param,
|
||||
bytes, hidden, mime_headers, mime_in_reply_to,
|
||||
mime_references, mime_modified, error, ephemeral_timer,
|
||||
ephemeral_timestamp, download_state
|
||||
ephemeral_timestamp, download_state, hop_info
|
||||
)
|
||||
VALUES (
|
||||
?, ?, ?, ?,
|
||||
@@ -1076,7 +1076,7 @@ INSERT INTO msgs
|
||||
?, ?, ?, ?,
|
||||
?, ?, ?, ?,
|
||||
?, ?, ?, ?,
|
||||
?, ?
|
||||
?, ?, ?
|
||||
);
|
||||
"#,
|
||||
)?;
|
||||
@@ -1161,6 +1161,7 @@ INSERT INTO msgs
|
||||
} else {
|
||||
DownloadState::Done
|
||||
},
|
||||
mime_parser.hop_info
|
||||
])?;
|
||||
let row_id = conn.last_insert_rowid();
|
||||
|
||||
|
||||
108
src/dc_tools.rs
108
src/dc_tools.rs
@@ -5,6 +5,7 @@ use core::cmp::{max, min};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
use std::str::from_utf8;
|
||||
use std::str::FromStr;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
@@ -14,6 +15,10 @@ use async_std::{fs, io};
|
||||
|
||||
use anyhow::{bail, Error};
|
||||
use chrono::{Local, TimeZone};
|
||||
use itertools::Itertools;
|
||||
use mailparse::dateparse;
|
||||
use mailparse::headers::Headers;
|
||||
use mailparse::MailHeaderMap;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
use crate::chat::{add_device_msg, add_device_msg_with_importance};
|
||||
@@ -670,13 +675,114 @@ pub fn remove_subject_prefix(last_subject: &str) -> String {
|
||||
.to_string()
|
||||
}
|
||||
|
||||
// Types and methods to create hop-info for message-info
|
||||
|
||||
fn extract_address_from_receive_header<'a>(header: &'a str, start: &str) -> Option<&'a str> {
|
||||
let header_len = header.len();
|
||||
header.find(start).and_then(|mut begin| {
|
||||
begin += start.len();
|
||||
let end = header
|
||||
.get(begin..)?
|
||||
.find(|c| c == ' ' || c == '\n')
|
||||
.unwrap_or(header_len);
|
||||
header.get(begin..begin + end)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn parse_receive_header(header: &str) -> String {
|
||||
let mut hop_info = String::from("Hop:\n");
|
||||
|
||||
if let Ok(date) = dateparse(header) {
|
||||
let date_obj = Local.timestamp(date, 0);
|
||||
hop_info.push_str(&format!("Date: {}\n", date_obj.to_rfc2822()));
|
||||
};
|
||||
|
||||
if let Some(from) = extract_address_from_receive_header(header, "from ") {
|
||||
hop_info.push_str(&format!("From: {}\n", from.trim()));
|
||||
}
|
||||
|
||||
if let Some(by) = extract_address_from_receive_header(header, "by ") {
|
||||
hop_info.push_str(&format!("By: {}\n", by.trim()));
|
||||
}
|
||||
hop_info
|
||||
}
|
||||
|
||||
/// parses "receive"-headers
|
||||
pub(crate) fn parse_receive_headers(headers: &Headers) -> String {
|
||||
let headers = headers
|
||||
.get_all_headers("Received")
|
||||
.iter()
|
||||
.rev()
|
||||
.filter_map(|header_map_item| from_utf8(header_map_item.get_value_raw()).ok())
|
||||
.enumerate()
|
||||
.map(|(i, header_value)| (i + 1).to_string() + ". " + &parse_receive_header(header_value))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
headers.iter().map(|a| a.to_string()).join("\n")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#![allow(clippy::indexing_slicing)]
|
||||
|
||||
use super::*;
|
||||
|
||||
use crate::test_utils::TestContext;
|
||||
use crate::{
|
||||
config::Config, dc_receive_imf::dc_receive_imf, message::get_msg_info,
|
||||
test_utils::TestContext,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_parse_receive_headers() {
|
||||
let raw = include_bytes!("../test-data/message/mail_with_cc.txt");
|
||||
let mail = mailparse::parse_mail(&raw[..]).unwrap();
|
||||
let hop_info = parse_receive_headers(&mail.get_headers());
|
||||
let expected = concat!(
|
||||
"1. Hop:\n",
|
||||
"Date: Sat, 14 Sep 2019 19:00:22 +0200\n",
|
||||
"From: localhost\n",
|
||||
"By: hq5.merlinux.eu\n",
|
||||
"\n",
|
||||
"2. Hop:\n",
|
||||
"Date: Sat, 14 Sep 2019 19:00:25 +0200\n",
|
||||
"From: hq5.merlinux.eu\n",
|
||||
"By: hq5.merlinux.eu\n",
|
||||
);
|
||||
assert_eq!(&hop_info, expected)
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_parse_receive_headers_integration() -> anyhow::Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
t.set_config(Config::ShowEmails, Some("2")).await?;
|
||||
let raw = include_bytes!("../test-data/message/mail_with_cc.txt");
|
||||
dc_receive_imf(&t, raw, "INBOX", 1, false).await.unwrap();
|
||||
let g = t.get_last_msg().await;
|
||||
|
||||
let expected = r"State: Fresh
|
||||
|
||||
hi
|
||||
|
||||
Message-ID: 2dfdbde7@example.org
|
||||
Last seen as: INBOX/1
|
||||
1. Hop:
|
||||
Date: Sat, 14 Sep 2019 19:00:22 +0200
|
||||
From: localhost
|
||||
By: hq5.merlinux.eu
|
||||
|
||||
2. Hop:
|
||||
Date: Sat, 14 Sep 2019 19:00:25 +0200
|
||||
From: hq5.merlinux.eu
|
||||
By: hq5.merlinux.eu
|
||||
";
|
||||
let result = get_msg_info(&t, g.id).await.unwrap();
|
||||
// little hack to ignore the first row of a parsed email because it contains a
|
||||
// send time that depends and the test runtime which makes it impossible to
|
||||
// compare with a static string
|
||||
let capped_result = &result[result.find("State").unwrap()..];
|
||||
assert_eq!(expected, capped_result);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rust_ftoa() {
|
||||
|
||||
@@ -1172,9 +1172,17 @@ pub async fn get_msg_info(context: &Context, msg_id: MsgId) -> Result<String> {
|
||||
}
|
||||
if let Some(ref server_folder) = msg.server_folder {
|
||||
if !server_folder.is_empty() {
|
||||
ret += &format!("\nLast seen as: {}/{}", server_folder, msg.server_uid);
|
||||
ret += &format!("\nLast seen as: {}/{}\n", server_folder, msg.server_uid);
|
||||
}
|
||||
}
|
||||
let hop_info: Option<String> = context
|
||||
.sql
|
||||
.query_get_value("SELECT hop_info FROM msgs WHERE id=?;", paramsv![msg_id])
|
||||
.await?;
|
||||
|
||||
if hop_info.is_some() {
|
||||
ret.push_str(&hop_info.unwrap_or_else(|| "No Hop info".to_owned()));
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use crate::blob::BlobObject;
|
||||
use crate::constants::{Viewtype, DC_DESIRED_TEXT_LEN, DC_ELLIPSIS};
|
||||
use crate::contact::addr_normalize;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::{dc_get_filemeta, dc_truncate};
|
||||
use crate::dc_tools::{dc_get_filemeta, dc_truncate, parse_receive_headers};
|
||||
use crate::dehtml::dehtml;
|
||||
use crate::e2ee;
|
||||
use crate::events::EventType;
|
||||
@@ -78,6 +78,8 @@ pub struct MimeMessage {
|
||||
/// This is non-empty only if the message was actually encrypted. It is used
|
||||
/// for e.g. late-parsing HTML.
|
||||
pub decoded_data: Vec<u8>,
|
||||
|
||||
pub(crate) hop_info: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -285,6 +287,7 @@ impl MimeMessage {
|
||||
footer: None,
|
||||
is_mime_modified: false,
|
||||
decoded_data: Vec::new(),
|
||||
hop_info: parse_receive_headers(&mail.get_headers()),
|
||||
};
|
||||
|
||||
match partial {
|
||||
|
||||
@@ -477,6 +477,7 @@ paramsv![]
|
||||
sql.execute_migration("UPDATE chats SET archived=1 WHERE blocked=2;", 78)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if dbversion < 79 {
|
||||
info!(context, "[migration] v79");
|
||||
sql.execute_migration(
|
||||
@@ -487,7 +488,11 @@ paramsv![]
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if dbversion < 80 {
|
||||
info!(context, "[migration] v80");
|
||||
sql.execute_migration("ALTER TABLE msgs ADD COLUMN hop_info TEXT DEFAULT '';", 80)
|
||||
.await?;
|
||||
}
|
||||
Ok((
|
||||
recalc_fingerprints,
|
||||
update_icons,
|
||||
|
||||
Reference in New Issue
Block a user