diff --git a/src/chat.rs b/src/chat.rs index b168dafeb..7f32dbc81 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -3920,63 +3920,62 @@ pub async fn remove_contact_from_chat( let mut msg = Message::default(); let chat = Chat::load_from_db(context, chat_id).await?; - if chat.typ == Chattype::Group || chat.typ == Chattype::Broadcast { - if !chat.is_self_in_chat(context).await? { - let err_msg = format!( - "Cannot remove contact {contact_id} from chat {chat_id}: self not in group." - ); - context.emit_event(EventType::ErrorSelfNotInGroup(err_msg.clone())); - bail!("{}", err_msg); - } else { - let mut sync = Nosync; - // We do not return an error if the contact does not exist in the database. - // 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() { - msg.viewtype = Viewtype::Text; - if contact_id == ContactId::SELF { - msg.text = stock_str::msg_group_left_local(context, ContactId::SELF).await; - } else { - msg.text = stock_str::msg_del_member_local( - context, - contact.get_addr(), - ContactId::SELF, - ) - .await; - } - msg.param.set_cmd(SystemMessage::MemberRemovedFromGroup); - msg.param.set(Param::Arg, contact.get_addr().to_lowercase()); - let res = send_msg(context, chat_id, &mut msg).await; - if contact_id == ContactId::SELF { - res?; - set_group_explicitly_left(context, &chat.grpid).await?; - } else if let Err(e) = res { - warn!(context, "remove_contact_from_chat({chat_id}, {contact_id}): send_msg() failed: {e:#}."); - } + if chat.typ != Chattype::Group && chat.typ != Chattype::Broadcast { + bail!("Cannot remove members from non-group chats."); + } + + if !chat.is_self_in_chat(context).await? { + let err_msg = + format!("Cannot remove contact {contact_id} from chat {chat_id}: self not in group."); + context.emit_event(EventType::ErrorSelfNotInGroup(err_msg.clone())); + bail!("{}", err_msg); + } else { + let mut sync = Nosync; + // We do not return an error if the contact does not exist in the database. + // 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() { + msg.viewtype = Viewtype::Text; + if contact_id == ContactId::SELF { + msg.text = stock_str::msg_group_left_local(context, ContactId::SELF).await; } else { - sync = Sync; + msg.text = stock_str::msg_del_member_local( + context, + contact.get_addr(), + ContactId::SELF, + ) + .await; } - } - // we remove the member from the chat after constructing the - // to-be-send message. If between send_msg() and here the - // process dies, the user will be able to redo the action. It's better than the other - // way round: you removed someone from DB but no peer or device gets to know about it - // and group membership is thus different on different devices. But if send_msg() - // failed, we still remove the member locally, otherwise it would be impossible to - // remove a member with missing key from a protected group. - // Note also that sending a message needs all recipients - // in order to correctly determine encryption so if we - // removed it first, it would complicate the - // check/encryption logic. - remove_from_chat_contacts_table(context, chat_id, contact_id).await?; - context.emit_event(EventType::ChatModified(chat_id)); - if sync.into() { - chat.sync_contacts(context).await.log_err(context).ok(); + msg.param.set_cmd(SystemMessage::MemberRemovedFromGroup); + msg.param.set(Param::Arg, contact.get_addr().to_lowercase()); + let res = send_msg(context, chat_id, &mut msg).await; + if contact_id == ContactId::SELF { + res?; + set_group_explicitly_left(context, &chat.grpid).await?; + } else if let Err(e) = res { + warn!(context, "remove_contact_from_chat({chat_id}, {contact_id}): send_msg() failed: {e:#}."); + } + } else { + sync = Sync; } } - } else { - bail!("Cannot remove members from non-group chats."); + // we remove the member from the chat after constructing the + // to-be-send message. If between send_msg() and here the + // process dies, the user will be able to redo the action. It's better than the other + // way round: you removed someone from DB but no peer or device gets to know about it + // and group membership is thus different on different devices. But if send_msg() + // failed, we still remove the member locally, otherwise it would be impossible to + // remove a member with missing key from a protected group. + // Note also that sending a message needs all recipients + // in order to correctly determine encryption so if we + // removed it first, it would complicate the + // check/encryption logic. + remove_from_chat_contacts_table(context, chat_id, contact_id).await?; + context.emit_event(EventType::ChatModified(chat_id)); + if sync.into() { + chat.sync_contacts(context).await.log_err(context).ok(); + } } Ok(())