Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions src/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2851,11 +2851,6 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) -
let attach_selfavatar = mimefactory.attach_selfavatar;
let mut recipients = mimefactory.recipients();

let from = context.get_primary_self_addr().await?;
let lowercase_from = from.to_lowercase();

recipients.retain(|x| x.to_lowercase() != lowercase_from);

Comment on lines -2854 to -2858

@Hocuri Hocuri Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like the self recipient may be added twice now under some circumstances? I just noticed that we don't have any tests at all for recipients, will write one

Edit: Nevermind, we do have some tests for it

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What we did not have is a test for not adding the self address twice in a group, or for not adding it at all when bcc_self is off. I wrote a test, and directly pushed it since @hpk42 said he won't engage much with DC development this week

@Hocuri Hocuri Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The self recipient may now be added twice if one of the group members' transports uses the same address as the self (primary) self address. This is such a rare case (and an already-broken setup) that it seems fine. For all other cases, the if id != ContactId::SELF checks in mimefactory.rs are most likely enough (confirmed by the test I just added).

// Default Webxdc integrations are hidden messages and must not be sent out:
if (msg.param.get_int(Param::WebxdcIntegration).is_some() && msg.hidden)
// This may happen eg. for groups with only SELF and bcc_self disabled:
Expand Down
2 changes: 1 addition & 1 deletion src/chat/chat_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3957,7 +3957,7 @@ async fn test_leave_broadcast_multidevice() -> Result<()> {

let leave_msg = bob0.pop_sent_msg().await;
let parsed = MimeMessage::from_bytes(bob1, leave_msg.payload().as_bytes()).await?;
assert_eq!(parsed.parts[0].msg, "bob@example.net left the group.");
assert_eq!(parsed.parts[0].msg, "Member bob@example.net was removed.");

let rcvd = bob1.recv_msg(&leave_msg).await;

Expand Down
6 changes: 1 addition & 5 deletions src/contact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1230,17 +1230,13 @@ ORDER BY c.origin>=? DESC, c.last_seen DESC, c.id DESC
.await?;

if let Some(query) = query {
let self_addr = context
.get_config(Config::ConfiguredAddr)
.await?
.unwrap_or_default();
let self_name = context
.get_config(Config::Displayname)
.await?
.unwrap_or_default();
let self_name2 = stock_str::self_msg(context);

if self_addr.contains(query)
if self_addrs.iter().any(|a| a.contains(query))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change and the test in contacts_tests looks good.

|| self_name.contains(query)
|| self_name2.contains(query)
{
Expand Down
14 changes: 14 additions & 0 deletions src/contact/contact_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,20 @@ async fn test_get_contacts() -> Result<()> {
assert_eq!(contacts.len(), 1);
let contacts = Contact::get_all(&context, 0, Some("δ")).await?;
assert_eq!(contacts.len(), 1);

// Searching for a secondary self address finds "Me",
// even if the transport is unpublished.
crate::transport::add_pseudo_transport(&context, "bob@second.example").await?;
context
.set_transport_unpublished("bob@second.example", true)
.await?;
let contacts = Contact::get_all(
&context,
constants::DC_GCL_ADD_SELF,
Some("bob@second.example"),
)
.await?;
assert_eq!(contacts, vec![ContactId::SELF]);
Ok(())
}

Expand Down
13 changes: 3 additions & 10 deletions src/mimefactory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1421,16 +1421,9 @@ impl MimeFactory {
let email_to_remove = msg.param.get(Param::Arg).unwrap_or_default();
let fingerprint_to_remove = msg.param.get(Param::Arg4).unwrap_or_default();

if email_to_remove
Comment thread
hpk42 marked this conversation as resolved.
== context
.get_config(Config::ConfiguredAddr)
.await?
.unwrap_or_default()
{
placeholdertext = Some(format!("{email_to_remove} left the group."));
} else {
placeholdertext = Some(format!("Member {email_to_remove} was removed."));
};
// Only visible in classic email clients,
// Delta Chat renders removals from the headers.
placeholdertext = Some(format!("Member {email_to_remove} was removed."));

if !email_to_remove.is_empty() {
headers.push((
Expand Down
24 changes: 24 additions & 0 deletions src/mimefactory/mimefactory_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,30 @@ async fn test_new_member_is_first_recipient() -> Result<()> {
Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_bcc_self() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;

for bcc_self in [false, true] {
alice.set_config_bool(Config::BccSelf, bcc_self).await?;

let group = alice.create_group_with_members("Group", &[bob]).await;
let single_chat = alice.create_chat_id(bob).await;

for chat_id in [group, single_chat] {
let sent = alice.send_text(chat_id, "Heyho!").await;
if bcc_self {
assert_eq!(sent.recipients, "bob@example.net alice@example.org");
} else {
assert_eq!(sent.recipients, "bob@example.net");
}
}
}
Ok(())
}

/// Regression test: mimefactory should never create an empty to header,
/// also not if the Selftalk parameter is missing
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
Expand Down
16 changes: 7 additions & 9 deletions src/receive_imf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3177,15 +3177,13 @@ async fn apply_group_changes(
.await?;
} else {
let mut new_members: BTreeSet<ContactId>;
// True if a Delta Chat client has explicitly and really added our primary address to an
Comment on lines 3178 to -3180

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code block is untested, and writing a test seems involved (i tried).
I wonder if the original reason for this block has to do with pre-v2 versions?
You can also reach the block today i guess with someone sending from a stale member list (60 days no messages), so without member-timestamps, but it requires more conditions to cause this block to execute. And if we want to accept an explicit addition, we should still prefer later arriving member-timestamps and i am nto sure that's happening. It's all not too important i think, but if you have an easy answer, let me know. I just didn't bother with the test because the self-addr fix is small enough and straightfoward.

// already existing group.
let self_added =
if let Some(added_addr) = mime_parser.get_header(HeaderDef::ChatGroupMemberAdded) {
addr_cmp(&context.get_primary_self_addr().await?, added_addr)
&& !chat_contacts.contains(&ContactId::SELF)
} else {
false
};
let self_added = if let Some(added_addr) =
mime_parser.get_header(HeaderDef::ChatGroupMemberAdded)
{
context.is_self_addr(added_addr).await? && !chat_contacts.contains(&ContactId::SELF)
} else {
false
};
if self_added {
new_members = BTreeSet::from_iter(to_ids_flat.iter().copied());
new_members.insert(ContactId::SELF);
Expand Down