Compare commits

...

3 Commits

Author SHA1 Message Date
iequidoo
551555180e feat: Don't send SystemMessage::Member* in unencrypted groups
Unencrypted groups are usually ones with other MUAs which don't understand Delta Chat system
messages and show them as weird emails.

Self-removal returns an error now, otherwise remaining members won't know about it. It should be
disabled in UIs and the user should resolve it on their own (e.g. by asking other members).
2025-06-23 20:09:10 -03:00
iequidoo
3627027236 feat: Don't send SystemMessage::GroupNameChanged in unencrypted groups
Unencrypted groups are usually ones with other MUAs which don't understand Delta Chat system
messages and show them as weird emails.
2025-06-23 20:09:06 -03:00
iequidoo
919b44fb3e refactor: set_chat_profile_image(): Remove !chat.is_mailing_list() check 2025-06-23 19:43:12 -03:00
2 changed files with 76 additions and 15 deletions

View File

@@ -3945,7 +3945,7 @@ pub(crate) async fn add_contact_to_chat_ex(
}
add_to_chat_contacts_table(context, time(), chat_id, &[contact_id]).await?;
}
if chat.typ == Chattype::Group && chat.is_promoted() {
if chat.typ == Chattype::Group && !chat.grpid.is_empty() && chat.is_promoted() {
msg.viewtype = Viewtype::Text;
let contact_addr = contact.get_addr().to_lowercase();
@@ -4118,6 +4118,11 @@ pub async fn remove_contact_from_chat(
);
context.emit_event(EventType::ErrorSelfNotInGroup(err_msg.clone()));
bail!("{}", err_msg);
} else if chat.typ == Chattype::Group
&& chat.grpid.is_empty()
&& contact_id == ContactId::SELF
{
bail!("Please ask other members to remove you from the thread");
} else {
let mut sync = Nosync;
@@ -4138,7 +4143,7 @@ pub async fn remove_contact_from_chat(
// This allows to delete dangling references to deleted contacts
// in case of the database becoming inconsistent due to a bug.
if let Some(contact) = Contact::get_by_id_optional(context, contact_id).await? {
if chat.typ == Chattype::Group && chat.is_promoted() {
if chat.typ == Chattype::Group && !chat.grpid.is_empty() && chat.is_promoted() {
msg.viewtype = Viewtype::Text;
if contact_id == ContactId::SELF {
msg.text = stock_str::msg_group_left_local(context, ContactId::SELF).await;
@@ -4235,11 +4240,16 @@ async fn rename_ex(
(new_name.to_string(), chat_id),
)
.await?;
if chat.is_promoted()
&& !chat.is_mailing_list()
&& chat.typ != Chattype::Broadcast
&& sanitize_single_line(&chat.name) != new_name
if !chat.is_promoted()
|| chat.is_mailing_list()
|| chat.typ == Chattype::Broadcast
|| sanitize_single_line(&chat.name) == new_name
{
} else if chat.grpid.is_empty() {
chat_id
.update_timestamp(context, Param::GroupNameTimestamp, smeared_time(context))
.await?;
} else {
msg.viewtype = Viewtype::Text;
msg.text =
stock_str::msg_grp_name(context, &chat.name, &new_name, ContactId::SELF).await;
@@ -4312,7 +4322,7 @@ pub async fn set_chat_profile_image(
msg.text = stock_str::msg_grp_img_changed(context, ContactId::SELF).await;
}
chat.update_param(context).await?;
if chat.is_promoted() && !chat.is_mailing_list() {
if chat.is_promoted() {
msg.id = send_msg(context, chat_id, &mut msg).await?;
context.emit_msgs_changed(chat_id, msg.id);
}

View File

@@ -2808,11 +2808,15 @@ Second thread."#;
let alice_fiona_contact_id = alice_fiona_contact.id;
chat::add_contact_to_chat(&alice, alice_first_msg.chat_id, alice_fiona_contact_id).await?;
let alice_first_invite = alice.pop_sent_msg().await;
let alice_first_invite = alice
.send_text(alice_first_msg.chat_id, "I added Fiona")
.await;
let fiona_first_invite = fiona.recv_msg(&alice_first_invite).await;
chat::add_contact_to_chat(&alice, alice_second_msg.chat_id, alice_fiona_contact_id).await?;
let alice_second_invite = alice.pop_sent_msg().await;
let alice_second_invite = alice
.send_text(alice_second_msg.chat_id, "I added Fiona")
.await;
let fiona_second_invite = fiona.recv_msg(&alice_second_invite).await;
// Fiona was added to two separate chats and should see two separate chats, even though they
@@ -4431,12 +4435,22 @@ async fn test_mua_can_readd() -> Result<()> {
assert_eq!(alice_chat.typ, Chattype::Group);
assert!(is_contact_in_chat(&alice, alice_chat.id, ContactId::SELF).await?);
// And leaves it.
remove_contact_from_chat(&alice, alice_chat.id, ContactId::SELF).await?;
alice.pop_sent_msg().await;
assert!(!is_contact_in_chat(&alice, alice_chat.id, ContactId::SELF).await?);
// Self-removal from unencrypted groups should fail.
assert!(
remove_contact_from_chat(&alice, alice_chat.id, ContactId::SELF)
.await
.is_err()
);
// Bob uses a classical MUA to answer, adding Alice back.
// And removes Claire.
let claire_id = Contact::lookup_id_by_addr(&alice, "claire@example.org", Origin::OutgoingTo)
.await?
.unwrap();
remove_contact_from_chat(&alice, alice_chat.id, claire_id).await?;
assert!(!alice.sql.exists("SELECT COUNT(*) FROM smtp", ()).await?);
assert!(!is_contact_in_chat(&alice, alice_chat.id, claire_id).await?);
// Bob uses a classical MUA to answer, adding Claire back.
receive_imf(
&alice,
b"Subject: Re: Message from alice\r\n\
@@ -4451,7 +4465,44 @@ async fn test_mua_can_readd() -> Result<()> {
)
.await?
.unwrap();
assert!(is_contact_in_chat(&alice, alice_chat.id, ContactId::SELF).await?);
assert!(is_contact_in_chat(&alice, alice_chat.id, claire_id).await?);
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_rename_unencrypted_group() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
for ctx in [alice, bob] {
receive_imf(
ctx,
b"Subject: Some thread\r\n\
From: alice@example.org\r\n\
To: <bob@example.net>, <claire@example.org> \r\n\
Date: Mon, 12 Dec 2022 14:30:39 +0000\r\n\
Message-ID: <Mr.alices_original_mail@example.org>\r\n\
Chat-Version: 1.0\r\n\
\r\n\
Hi!\r\n",
false,
)
.await?
.unwrap();
}
let msg = alice.get_last_msg().await;
let alice_chat = Chat::load_from_db(alice, msg.chat_id).await?;
assert_eq!(alice_chat.typ, Chattype::Group);
SystemTime::shift(Duration::from_secs(60));
chat::set_chat_name(alice, alice_chat.id, "Renamed thread").await?;
assert!(!alice.sql.exists("SELECT COUNT(*) FROM smtp", ()).await?);
let sent_msg = alice.send_text(alice_chat.id, "I renamed the thread").await;
let msg = bob.recv_msg(&sent_msg).await;
let bob_chat = Chat::load_from_db(bob, msg.chat_id).await?;
assert_eq!(bob_chat.get_name(), "Renamed thread");
Ok(())
}