mirror of
https://github.com/chatmail/core.git
synced 2026-04-05 15:02:11 +03:00
Compare commits
20 Commits
acffad37ef
...
mlm-doc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cece414af0 | ||
|
|
2beb428c95 | ||
|
|
7227975175 | ||
|
|
aa5ca4f816 | ||
|
|
24ba96f6b2 | ||
|
|
b0a92a8727 | ||
|
|
ec18dcab64 | ||
|
|
8c3e6276c4 | ||
|
|
762aa1ed2e | ||
|
|
adcaec8665 | ||
|
|
e575be2593 | ||
|
|
b1536b3893 | ||
|
|
4e174d0c2f | ||
|
|
51e1826958 | ||
|
|
7b3e6d185e | ||
|
|
c5374565ec | ||
|
|
3287e175b4 | ||
|
|
af1930dc8d | ||
|
|
b581a97edc | ||
|
|
3eda35c088 |
19
draft/mailing_list.rst
Normal file
19
draft/mailing_list.rst
Normal file
@@ -0,0 +1,19 @@
|
||||
2. Mailing lists are now only detected by the ListId header, because how should DC sort mailing lists if the ListId header is unset and only the precedence header says it's a mailing list (?). We could just hide these emails (with "junk" or "list" precedence), as we did before, if there is a reason to do so.
|
||||
|
||||
I do not actually understand why such emails were hidden in the first place, though; if there is an automatic answer stating that someone is out of office or if an email could not be delivered (these are the usual reasons why such emails are sent), I would want to know about this as a user.
|
||||
|
||||
Björn: to the ListId-header: it is already an improvement to use only that and to keep ignoring mails with Precedence-header. historically, i ignored all these mails to reduce noise that is created from them (eg. contacts should not be added to the suggestion list...) and to be able to concentrate on other things first.
|
||||
|
||||
|
||||
3. for `List-Id: foo <bla>`, bla now is the id and foo is the name. For GitHub and GitLab notifications this is bad because all notifications will go into one chat. Maybe we should instead take the "in-reply-to" header to find out what messages belong together. For normal mailing lists, of course, this will create a second chat if someone does not use the "Reply" button to write to that mailing list.
|
||||
|
||||
Björn: well, having all notifications in one chat is not that bad. i would just follow the guidelines for now, use the ID and not the Name.
|
||||
|
||||
|
||||
4. Currently a mailing list is shown as an empty group (ChatType `Group`) ("0 members").
|
||||
|
||||
Maybe we should change the ChatType to `Single` because this way, the UI would fit better. Disadvantage: We can't show the different senders of the messages.
|
||||
|
||||
Or we introduce a `ChatType` `MailingList`. Very big disadvantage: We would have to adapt all UI project and it would be nice if we could keep the changes within the core.
|
||||
|
||||
5. Contacts from mailings lists stay "unknown" now and are not shown in the contacts suggestion list..
|
||||
13
draft/mailing_list_current_state.rst
Normal file
13
draft/mailing_list_current_state.rst
Normal file
@@ -0,0 +1,13 @@
|
||||
1. Mailing lists with Precedence-header and without List-Id are shown as normal messages.
|
||||
|
||||
2. for `List-Id: foo <bla>`, bla now is the id and foo is the name. If foo is not present, bla is taken as the name as well. For GitHub and GitLab notifications all notifications will go into one chat. To distinguish, all subjects are shown in mailing lists.
|
||||
|
||||
3. Currently a mailing list is shown as a group with SELF and the List-Id. I could not find any stable way to get a mail address that could be called the "mailing list address". To get this to work, I disabled the may_be_valid_addr check. (to be discussed...)
|
||||
|
||||
4. Contacts from mailings lists stay "unknown" and are not shown in the contacts suggestion list.
|
||||
|
||||
5. In general, only the From: address is taken as the author. If the domain matches with the List-Id domain (like `deltachat.github.com` and `Hocuri <notifications@notification.github.com>`) then the display name is added to the email address -> `Hocuri - notifications@notification.github.com`. This is not really nice, but as the UIs distinguish bettween contacts only based on the address this was the only way I could find without changing the API.
|
||||
|
||||
TODO: Prevent the user from sending emails to such contacts (like Hocuri - notifications@notification.github.com)
|
||||
|
||||
6. You can't send to mailing lists.
|
||||
71
draft/mailing_list_managers.md
Normal file
71
draft/mailing_list_managers.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Mailing list integration of Delta Chat
|
||||
|
||||
A collection of information to help with the integration of mailing lists into Delta Chat.
|
||||
|
||||
## Chat name
|
||||
|
||||
How should the chat be titled?
|
||||
|
||||
It could be taken from the email header `List-Id`:
|
||||
|
||||
### Mailman
|
||||
|
||||
* Schema: `${list-description} <${list-local-part}.${list-domain}>`
|
||||
* $list-description could be many words, should be truncated. Could also be empty, though.
|
||||
|
||||
### Schleuder
|
||||
* Schema: `<${list-local-part}.${list-domain}>`
|
||||
* No name available.
|
||||
* Could be absent: <https://0xacab.org/schleuder/schleuder/-/blob/master/lib/schleuder/mail/message.rb#L357-358>.
|
||||
|
||||
|
||||
### Sympa
|
||||
* Schema: `<${list-local-part}.${list-domain}>`
|
||||
* No name available.
|
||||
* Always present <https://github.com/sympa-community/sympa/blob/sympa-6.2/src/lib/Sympa/Spindle/TransformOutgoing.pm#L110-L118>, <https://github.com/sympa-community/sympa/blob/sympa-6.2/src/lib/Sympa/List.pm#L6832-L6833>.
|
||||
|
||||
|
||||
## Sender name
|
||||
|
||||
What's the name of the person that actually sent the message?
|
||||
|
||||
Some MLM change the sender information to avoid problems with DMARC.
|
||||
|
||||
### Mailman
|
||||
|
||||
* Since v2.1.16 the `From` depends on the list's configuration and possibly on the sender-domain's DMARC-configuration — i.e. messages from the same list can arrive one of the Variants A-D!
|
||||
* Documentation of config options:
|
||||
* <https://wiki.list.org/DOC/Mailman%202.1%20List%20Administrators%20Manual#line-544>,
|
||||
* <https://wiki.list.org/DOC/Mailman%202.1%20List%20Administrators%20Manual#line-163>,
|
||||
* <https://wiki.list.org/DEV/DMARC>
|
||||
* Variant A: `From` is unchanged.
|
||||
* Variant B. `From` is mangled like this: `${sender-name} via ${list-name} <${list-addr-spec}>`. The original sender is put into `Reply-To`.
|
||||
* Variant C. `From` is mangled like this: `${sender-name} <${encoded-sender-addr-spec}@${list-domain}>`. The original sender is put into `Reply-To`.
|
||||
* Variant D: `From` is set to ${list-name-addr}, the originally sent message is included as mime-part.
|
||||
* Variant E: `From` is set to ${list-name-addr}, original sender information is removed.
|
||||
|
||||
### Schleuder
|
||||
|
||||
* Visible only in mime-body (which is possibly encrypted), or not at all.
|
||||
* The first `text/plain` mime-part may include the information, as taken from the original message: `From: ${sender-name-addr}`.
|
||||
|
||||
### Sympa
|
||||
* Depends on the list's configuration.
|
||||
* Documentation:
|
||||
* <https://sympa-community.github.io/manual/customize/dmarc-protection.html>,
|
||||
* <https://sympa-community.github.io/gpldoc/man/sympa.conf.5.html#dmarc-protection>.
|
||||
* Variant A: `From` is unchanged.
|
||||
* Variant B: `From` is mangled like Mailman Variant B, but the original sender information is put into `X-Original-From`.
|
||||
|
||||
|
||||
## Autocrypt
|
||||
|
||||
### Mailman
|
||||
* Not supported.
|
||||
|
||||
### Schleuder
|
||||
* A list's key is included in sent messages (as of version 3.5.0) (optional, by default active): <https://0xacab.org/schleuder/schleuder/-/blob/master/lib/schleuder/mail/message.rb#L349-355>.
|
||||
* Incoming keys are not yet looked at (that feature is planned: <https://0xacab.org/schleuder/schleuder/issues/435>).
|
||||
|
||||
### Sympa
|
||||
* Not supported.
|
||||
32
src/chat.rs
32
src/chat.rs
@@ -574,9 +574,13 @@ impl Chat {
|
||||
self.param.exists(Param::Devicetalk)
|
||||
}
|
||||
|
||||
pub fn is_mailing_list(&self) -> bool {
|
||||
self.param.exists(Param::MailingList)
|
||||
}
|
||||
|
||||
/// Returns true if user can send messages to this chat.
|
||||
pub fn can_send(&self) -> bool {
|
||||
!self.id.is_special() && !self.is_device_talk()
|
||||
!self.id.is_special() && !self.is_device_talk() && !self.is_mailing_list()
|
||||
}
|
||||
|
||||
pub fn update_param(&mut self, context: &Context) -> Result<(), Error> {
|
||||
@@ -625,6 +629,10 @@ impl Chat {
|
||||
.unwrap_or_else(|| "Err".into());
|
||||
}
|
||||
|
||||
if self.typ == Chattype::Group && self.is_mailing_list() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
if self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup {
|
||||
if self.id.is_deaddrop() {
|
||||
return context.stock_str(StockMessage::DeadDrop).into();
|
||||
@@ -1097,7 +1105,11 @@ pub fn create_by_msg_id(context: &Context, msg_id: MsgId) -> Result<ChatId, Erro
|
||||
msg_id: MsgId::new(0),
|
||||
});
|
||||
}
|
||||
Contact::scaleup_origin_by_id(context, msg.from_id, Origin::CreateChat);
|
||||
|
||||
// If the message is from a mailing list, the contacts are not counted as "known"
|
||||
if !chat.is_mailing_list() {
|
||||
Contact::scaleup_origin_by_id(context, msg.from_id, Origin::CreateChat);
|
||||
}
|
||||
Ok(chat.id)
|
||||
}
|
||||
|
||||
@@ -2502,6 +2514,22 @@ pub(crate) fn get_chat_id_by_grpid(
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn get_chat_id_by_mailinglistid(
|
||||
context: &Context,
|
||||
listid: impl AsRef<str>,
|
||||
) -> Result<(ChatId, Blocked), sql::Error> {
|
||||
context.sql.query_row(
|
||||
"SELECT id, blocked, type FROM chats WHERE grpid=?;",
|
||||
params![listid.as_ref()],
|
||||
|row| {
|
||||
let chat_id = row.get::<_, ChatId>(0)?;
|
||||
|
||||
let b = row.get::<_, Option<Blocked>>(1)?.unwrap_or_default();
|
||||
Ok((chat_id, b))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Adds a message to device chat.
|
||||
///
|
||||
/// Optional `label` can be provided to ensure that message is added only once.
|
||||
|
||||
@@ -343,20 +343,6 @@ impl Contact {
|
||||
return Ok((DC_CONTACT_ID_SELF, sth_modified));
|
||||
}
|
||||
|
||||
if !may_be_valid_addr(&addr) {
|
||||
warn!(
|
||||
context,
|
||||
"Bad address \"{}\" for contact \"{}\".",
|
||||
addr,
|
||||
if !name.as_ref().is_empty() {
|
||||
name.as_ref()
|
||||
} else {
|
||||
"<unset>"
|
||||
},
|
||||
);
|
||||
bail!("Bad address supplied: {:?}", addr);
|
||||
}
|
||||
|
||||
let mut update_addr = false;
|
||||
let mut update_name = false;
|
||||
let mut update_authname = false;
|
||||
|
||||
@@ -2,6 +2,8 @@ use itertools::join;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use num_traits::FromPrimitive;
|
||||
use regex::Regex;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::chat::{self, Chat, ChatId};
|
||||
use crate::config::Config;
|
||||
@@ -71,6 +73,8 @@ pub fn dc_receive_imf(
|
||||
let mut created_db_entries = Vec::new();
|
||||
let mut create_event_to_send = Some(CreateEvent::MsgsChanged);
|
||||
|
||||
let list_id_header: Option<&String> = mime_parser.get(HeaderDef::ListId);
|
||||
|
||||
// helper method to handle early exit and memory cleanup
|
||||
let cleanup = |context: &Context,
|
||||
create_event_to_send: &Option<CreateEvent>,
|
||||
@@ -98,7 +102,7 @@ pub fn dc_receive_imf(
|
||||
// https://github.com/deltachat/deltachat-core/issues/150)
|
||||
let (from_id, from_id_blocked, incoming_origin) =
|
||||
if let Some(field_from) = mime_parser.get(HeaderDef::From_) {
|
||||
from_field_to_contact_id(context, field_from)?
|
||||
from_field_to_contact_id(context, field_from, list_id_header)?
|
||||
} else {
|
||||
(0, false, Origin::Unknown)
|
||||
};
|
||||
@@ -117,6 +121,7 @@ pub fn dc_receive_imf(
|
||||
} else {
|
||||
Origin::IncomingUnknownTo
|
||||
},
|
||||
list_id_header,
|
||||
)?);
|
||||
}
|
||||
}
|
||||
@@ -230,11 +235,13 @@ pub fn dc_receive_imf(
|
||||
pub fn from_field_to_contact_id(
|
||||
context: &Context,
|
||||
field_from: &str,
|
||||
list_id_header: Option<&String>,
|
||||
) -> Result<(u32, bool, Origin)> {
|
||||
let from_ids = dc_add_or_lookup_contacts_by_address_list(
|
||||
context,
|
||||
&field_from,
|
||||
Origin::IncomingUnknownFrom,
|
||||
list_id_header,
|
||||
)?;
|
||||
|
||||
if from_ids.contains(&DC_CONTACT_ID_SELF) {
|
||||
@@ -415,9 +422,34 @@ fn add_parts(
|
||||
|
||||
if chat_id.is_unset() {
|
||||
// check if the message belongs to a mailing list
|
||||
if mime_parser.is_mailinglist_message() {
|
||||
*chat_id = ChatId::new(DC_CHAT_ID_TRASH);
|
||||
info!(context, "Message belongs to a mailing list and is ignored.",);
|
||||
if let Some(list_id_header) = mime_parser.get(HeaderDef::ListId) {
|
||||
let create_blocked = if !test_normal_chat_id.is_unset()
|
||||
&& test_normal_chat_id_blocked == Blocked::Not
|
||||
{
|
||||
Blocked::Not
|
||||
} else {
|
||||
Blocked::Deaddrop
|
||||
};
|
||||
|
||||
let (new_chat_id, new_chat_id_blocked) = create_or_lookup_mailinglist(
|
||||
context,
|
||||
if test_normal_chat_id.is_unset() {
|
||||
allow_creation
|
||||
} else {
|
||||
true
|
||||
},
|
||||
create_blocked,
|
||||
list_id_header,
|
||||
);
|
||||
*chat_id = new_chat_id;
|
||||
chat_id_blocked = new_chat_id_blocked;
|
||||
if !chat_id.is_unset()
|
||||
&& chat_id_blocked != Blocked::Not
|
||||
&& create_blocked == Blocked::Not
|
||||
{
|
||||
new_chat_id.unblock(context);
|
||||
chat_id_blocked = Blocked::Not;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1096,6 +1128,66 @@ fn create_or_lookup_group(
|
||||
Ok((chat_id, chat_id_blocked))
|
||||
}
|
||||
|
||||
fn create_or_lookup_mailinglist(
|
||||
context: &Context,
|
||||
allow_creation: bool,
|
||||
create_blocked: Blocked,
|
||||
list_id_header: &str,
|
||||
) -> (ChatId, Blocked) {
|
||||
let re = Regex::new(r"^(.*.)<(.*.)>$").unwrap();
|
||||
let (name, listid) = match re.captures(list_id_header) {
|
||||
Some(cap) => (cap[1].trim().to_string(), cap[2].trim().to_string()),
|
||||
None => (
|
||||
list_id_header.trim().to_string(),
|
||||
list_id_header.trim().to_string(),
|
||||
),
|
||||
};
|
||||
|
||||
chat::get_chat_id_by_mailinglistid(context, &listid).unwrap_or_else(|_e| {
|
||||
if allow_creation {
|
||||
// list does not exist but should be created
|
||||
match create_mailinglist_record(context, &listid, &name, create_blocked) {
|
||||
Ok(chat_id) => {
|
||||
chat::add_to_chat_contacts_table(context, chat_id, DC_CONTACT_ID_SELF);
|
||||
|
||||
// Add the mailing list as "unknown" contact
|
||||
match add_or_lookup_contact_by_addr(
|
||||
context,
|
||||
&Some(name),
|
||||
&listid,
|
||||
Origin::IncomingUnknownFrom,
|
||||
None,
|
||||
) {
|
||||
Ok(list_id_contact) => {
|
||||
chat::add_to_chat_contacts_table(context, chat_id, list_id_contact);
|
||||
}
|
||||
Err(e) => warn!(
|
||||
context,
|
||||
"Failed to lookup mailing list contact: {}",
|
||||
e.to_string()
|
||||
),
|
||||
};
|
||||
|
||||
(chat_id, create_blocked)
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
context,
|
||||
"Failed to create mailinglist '{}' for grpid={}: {}",
|
||||
&name,
|
||||
&listid,
|
||||
e.to_string()
|
||||
);
|
||||
(ChatId::new(0), create_blocked)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info!(context, "creating list forbidden by caller");
|
||||
(ChatId::new(0), Blocked::Not)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// try extract a grpid from a message-id list header value
|
||||
fn extract_grpid(mime_parser: &MimeMessage, headerdef: HeaderDef) -> Option<&str> {
|
||||
let header = mime_parser.get(headerdef)?;
|
||||
@@ -1213,6 +1305,7 @@ fn create_or_lookup_adhoc_group(
|
||||
Ok((new_chat_id, create_blocked))
|
||||
}
|
||||
|
||||
// Insert a group record into the database. Note that this function is also used by create_mailinglist_record() below.
|
||||
fn create_group_record(
|
||||
context: &Context,
|
||||
grpid: impl AsRef<str>,
|
||||
@@ -1240,7 +1333,7 @@ fn create_group_record(
|
||||
{
|
||||
warn!(
|
||||
context,
|
||||
"Failed to create group '{}' for grpid={}",
|
||||
"Failed to create group or mailinglist '{}' for grpid={}",
|
||||
grpname.as_ref(),
|
||||
grpid.as_ref()
|
||||
);
|
||||
@@ -1250,7 +1343,7 @@ fn create_group_record(
|
||||
let chat_id = ChatId::new(row_id);
|
||||
info!(
|
||||
context,
|
||||
"Created group '{}' grpid={} as {}",
|
||||
"Created group or mailinglist '{}' grpid={} as {}",
|
||||
grpname.as_ref(),
|
||||
grpid.as_ref(),
|
||||
chat_id
|
||||
@@ -1258,6 +1351,27 @@ fn create_group_record(
|
||||
chat_id
|
||||
}
|
||||
|
||||
fn create_mailinglist_record(
|
||||
context: &Context,
|
||||
listid: impl AsRef<str>,
|
||||
name: impl AsRef<str>,
|
||||
create_blocked: Blocked,
|
||||
) -> Result<ChatId> {
|
||||
let chat_id = create_group_record(
|
||||
context,
|
||||
&listid,
|
||||
&name,
|
||||
create_blocked,
|
||||
VerifiedStatus::Unverified,
|
||||
);
|
||||
let mut chat = Chat::load_from_db(context, chat_id)?;
|
||||
|
||||
chat.param.set(Param::MailingList, "true");
|
||||
chat.update_param(context)?;
|
||||
|
||||
Ok(chat_id)
|
||||
}
|
||||
|
||||
fn create_adhoc_grp_id(context: &Context, member_ids: &[u32]) -> String {
|
||||
/* algorithm:
|
||||
- sort normalized, lowercased, e-mail addresses alphabetically
|
||||
@@ -1579,6 +1693,7 @@ fn dc_add_or_lookup_contacts_by_address_list(
|
||||
context: &Context,
|
||||
addr_list_raw: &str,
|
||||
origin: Origin,
|
||||
list_id_header: Option<&String>,
|
||||
) -> Result<ContactIds> {
|
||||
let addrs = match mailparse::addrparse(addr_list_raw) {
|
||||
Ok(addrs) => addrs,
|
||||
@@ -1596,6 +1711,7 @@ fn dc_add_or_lookup_contacts_by_address_list(
|
||||
&info.display_name,
|
||||
&info.addr,
|
||||
origin,
|
||||
list_id_header,
|
||||
)?);
|
||||
}
|
||||
mailparse::MailAddr::Group(infos) => {
|
||||
@@ -1605,6 +1721,7 @@ fn dc_add_or_lookup_contacts_by_address_list(
|
||||
&info.display_name,
|
||||
&info.addr,
|
||||
origin,
|
||||
list_id_header,
|
||||
)?);
|
||||
}
|
||||
}
|
||||
@@ -1620,6 +1737,7 @@ fn add_or_lookup_contact_by_addr(
|
||||
display_name: &Option<String>,
|
||||
addr: &str,
|
||||
origin: Origin,
|
||||
list_id_header: Option<&String>,
|
||||
) -> Result<u32> {
|
||||
if context.is_self_addr(addr)? {
|
||||
return Ok(DC_CONTACT_ID_SELF);
|
||||
@@ -1629,8 +1747,26 @@ fn add_or_lookup_contact_by_addr(
|
||||
.map(normalize_name)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut addr = Cow::from(addr);
|
||||
if let Some(list_id) = list_id_header {
|
||||
let list_id = list_id.trim().trim_end_matches('>');
|
||||
let addr_email = EmailAddress::new(&addr)?;
|
||||
let mut addr_domain_parts = addr_email.domain.split('.');
|
||||
let mut list_id_parts = list_id.split('.');
|
||||
if list_id_parts.next_back() == addr_domain_parts.next_back()
|
||||
&& list_id_parts.next_back() == addr_domain_parts.next_back()
|
||||
{
|
||||
// list_id was something like "name <name.github.com" (after trimming the last '>')
|
||||
// and addr was something like "notifications@github.com".
|
||||
// addr is not the address of the actual sender but the one of the mailing list.
|
||||
// Add the display name to the addr to make it distinguishable from other people
|
||||
// who sent to the same mailing list.
|
||||
*addr.to_mut() = format!("{} – {}", display_name_normalized, addr);
|
||||
}
|
||||
}
|
||||
|
||||
let (row_id, _modified) =
|
||||
Contact::add_or_lookup(context, display_name_normalized, addr, origin)?;
|
||||
Contact::add_or_lookup(context, display_name_normalized, &addr, origin)?;
|
||||
ensure!(row_id > 0, "could not add contact: {:?}", addr);
|
||||
|
||||
Ok(row_id)
|
||||
@@ -1660,6 +1796,97 @@ mod tests {
|
||||
use crate::message::Message;
|
||||
use crate::test_utils::{dummy_context, TestContext};
|
||||
|
||||
static MAILINGLIST: &[u8] = b"From: Max Mustermann <notifications@github.com>\n\
|
||||
To: deltachat/deltachat-core-rust <deltachat-core-rust@noreply.github.com>\n\
|
||||
Subject: [deltachat/deltachat-core-rust] PR run failed\n\
|
||||
Message-ID: <3333@example.org>\n\
|
||||
List-ID: deltachat/deltachat-core-rust <deltachat-core-rust.deltachat.github.com>\n\
|
||||
Precedence: list\n\
|
||||
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
|
||||
\n\
|
||||
hello\n";
|
||||
|
||||
static MAILINGLIST2: &[u8] = b"From: Github <notifications@github.com>\n\
|
||||
To: deltachat/deltachat-core-rust <deltachat-core-rust@noreply.github.com>\n\
|
||||
Subject: [deltachat/deltachat-core-rust] PR run failed\n\
|
||||
Message-ID: <3334@example.org>\n\
|
||||
List-ID: deltachat/deltachat-core-rust <deltachat-core-rust.deltachat.github.com>\n\
|
||||
Precedence: list\n\
|
||||
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
|
||||
\n\
|
||||
hello back\n";
|
||||
|
||||
static MAILINGLIST3: &[u8] = b"From: Alice <alice@posteo.org>\n\
|
||||
To: delta-dev@codespeak.net\n\
|
||||
Subject: Re: [delta-dev] What's up?\n\
|
||||
Message-ID: <38942@posteo.org>\n\
|
||||
List-ID: \"discussions about and around https://delta.chat developments\" <delta.codespeak.net>\n\
|
||||
Precedence: list\n\
|
||||
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
|
||||
\n\
|
||||
body\n";
|
||||
|
||||
#[test]
|
||||
fn test_mailing_list() {
|
||||
let t = configured_offline_context();
|
||||
t.ctx.set_config(Config::ShowEmails, Some("2")).unwrap();
|
||||
|
||||
dc_receive_imf(&t.ctx, MAILINGLIST, "INBOX", 1, false).unwrap();
|
||||
|
||||
let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap();
|
||||
assert_eq!(chats.len(), 1);
|
||||
|
||||
let chat_id = chat::create_by_msg_id(&t.ctx, chats.get_msg_id(0).unwrap()).unwrap();
|
||||
let chat = chat::Chat::load_from_db(&t.ctx, chat_id).unwrap();
|
||||
|
||||
assert!(chat.is_mailing_list());
|
||||
assert_eq!(chat.can_send(), false);
|
||||
assert_eq!(chat.name, "deltachat/deltachat-core-rust");
|
||||
println!("{:?}", Contact::load_from_db(&t.ctx, 1));
|
||||
println!("{:?}", chat::get_chat_contacts(&t.ctx, chat_id));
|
||||
assert_eq!(chat::get_chat_contacts(&t.ctx, chat_id).len(), 2);
|
||||
|
||||
dc_receive_imf(&t.ctx, MAILINGLIST2, "INBOX", 1, false).unwrap();
|
||||
|
||||
let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap();
|
||||
assert_eq!(chats.len(), 1);
|
||||
let contacts = Contact::get_all(&t.ctx, 0, None as Option<String>).unwrap();
|
||||
assert_eq!(contacts.len(), 0); // mailing list recipients and senders do not count as "known contacts"
|
||||
let msgs = chat::get_chat_msgs(&t.ctx, chat_id, 0, None);
|
||||
let contact1 = Contact::load_from_db(
|
||||
&t.ctx,
|
||||
Message::load_from_db(&t.ctx, msgs[0]).unwrap().from_id,
|
||||
);
|
||||
assert_eq!(
|
||||
contact1.unwrap().get_addr(),
|
||||
"Max Mustermann – notifications@github.com"
|
||||
);
|
||||
let contact2 = Contact::load_from_db(
|
||||
&t.ctx,
|
||||
Message::load_from_db(&t.ctx, msgs[1]).unwrap().from_id,
|
||||
);
|
||||
assert_eq!(
|
||||
contact2.unwrap().get_addr(),
|
||||
"Github – notifications@github.com"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mailing_list2() {
|
||||
let t = configured_offline_context();
|
||||
t.ctx.set_config(Config::ShowEmails, Some("2")).unwrap();
|
||||
dc_receive_imf(&t.ctx, MAILINGLIST3, "INBOX", 1, false).unwrap();
|
||||
let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap();
|
||||
let chat_id = chat::create_by_msg_id(&t.ctx, chats.get_msg_id(0).unwrap()).unwrap();
|
||||
|
||||
let msgs = chat::get_chat_msgs(&t.ctx, chat_id, 0, None);
|
||||
let contact1 = Contact::load_from_db(
|
||||
&t.ctx,
|
||||
Message::load_from_db(&t.ctx, msgs[0]).unwrap().from_id,
|
||||
);
|
||||
assert_eq!(contact1.unwrap().get_addr(), "alice@posteo.org");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hex_hash() {
|
||||
let data = "hello world";
|
||||
|
||||
@@ -1378,7 +1378,11 @@ fn prefetch_should_download(
|
||||
.get_header_value(HeaderDef::From_)
|
||||
.unwrap_or_default();
|
||||
|
||||
let (_contact_id, blocked_contact, origin) = from_field_to_contact_id(context, &from_field)?;
|
||||
let (_contact_id, blocked_contact, origin) = from_field_to_contact_id(
|
||||
context,
|
||||
&from_field,
|
||||
headers.get_header_value(HeaderDef::ListId).as_ref(),
|
||||
)?;
|
||||
let accepted_contact = origin.is_known();
|
||||
|
||||
let show = is_autocrypt_setup_message
|
||||
|
||||
@@ -282,18 +282,16 @@ impl MimeMessage {
|
||||
prepend_subject = false
|
||||
}
|
||||
}
|
||||
// For mailing lists, always add the subject because sometimes there are different topics
|
||||
// and otherwise it might be hard to keep track:
|
||||
if self.get(HeaderDef::ListId).is_some() {
|
||||
prepend_subject = true;
|
||||
}
|
||||
if prepend_subject {
|
||||
let subj = if let Some(n) = subject.find('[') {
|
||||
&subject[0..n]
|
||||
} else {
|
||||
subject
|
||||
}
|
||||
.trim();
|
||||
|
||||
if !subj.is_empty() {
|
||||
if !subject.is_empty() {
|
||||
for part in self.parts.iter_mut() {
|
||||
if part.typ == Viewtype::Text {
|
||||
part.msg = format!("{} – {}", subj, part.msg);
|
||||
part.msg = format!("{} – {}", subject, part.msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,8 @@ pub enum Param {
|
||||
|
||||
/// For MDN-sending job
|
||||
MsgId = b'I',
|
||||
|
||||
MailingList = b't',
|
||||
}
|
||||
|
||||
/// Possible values for `Param::ForcePlaintext`.
|
||||
|
||||
Reference in New Issue
Block a user