@@ -2859,19 +2859,26 @@ async fn prepare_send_msg(
2859
2859
) -> Result < Vec < i64 > > {
2860
2860
let mut chat = Chat :: load_from_db ( context, chat_id) . await ?;
2861
2861
2862
- // Check if the chat can be sent to.
2863
- if let Some ( reason) = chat. why_cant_send ( context) . await ? {
2864
- if matches ! (
2865
- reason,
2866
- CantSendReason :: ProtectionBroken
2867
- | CantSendReason :: ContactRequest
2868
- | CantSendReason :: SecurejoinWait
2869
- ) && msg. param . get_cmd ( ) == SystemMessage :: SecurejoinMessage
2870
- {
2871
- // Send out the message, the securejoin message is supposed to repair the verification.
2872
- // If the chat is a contact request, let the user accept it later.
2873
- } else {
2874
- bail ! ( "cannot send to {chat_id}: {reason}" ) ;
2862
+ // Check if the chat can be sent to,
2863
+ // but always allow to send "Member removed" messages
2864
+ // so we can leave the group.
2865
+ //
2866
+ // Necessary checks should be made anyway before removing contact
2867
+ // from the chat.
2868
+ if msg. param . get_cmd ( ) != SystemMessage :: MemberRemovedFromGroup {
2869
+ if let Some ( reason) = chat. why_cant_send ( context) . await ? {
2870
+ if matches ! (
2871
+ reason,
2872
+ CantSendReason :: ProtectionBroken
2873
+ | CantSendReason :: ContactRequest
2874
+ | CantSendReason :: SecurejoinWait
2875
+ ) && msg. param . get_cmd ( ) == SystemMessage :: SecurejoinMessage
2876
+ {
2877
+ // Send out the message, the securejoin message is supposed to repair the verification.
2878
+ // If the chat is a contact request, let the user accept it later.
2879
+ } else {
2880
+ bail ! ( "cannot send to {chat_id}: {reason}" ) ;
2881
+ }
2875
2882
}
2876
2883
}
2877
2884
@@ -3930,6 +3937,11 @@ pub async fn remove_contact_from_chat(
3930
3937
bail ! ( "{}" , err_msg) ;
3931
3938
} else {
3932
3939
let mut sync = Nosync ;
3940
+
3941
+ // Remove contact locally first
3942
+ // to set `chats_contacts.remove_timestamp`.
3943
+ remove_from_chat_contacts_table ( context, chat_id, contact_id) . await ?;
3944
+
3933
3945
// We do not return an error if the contact does not exist in the database.
3934
3946
// This allows to delete dangling references to deleted contacts
3935
3947
// in case of the database becoming inconsistent due to a bug.
@@ -3959,18 +3971,6 @@ pub async fn remove_contact_from_chat(
3959
3971
sync = Sync ;
3960
3972
}
3961
3973
}
3962
- // we remove the member from the chat after constructing the
3963
- // to-be-send message. If between send_msg() and here the
3964
- // process dies, the user will be able to redo the action. It's better than the other
3965
- // way round: you removed someone from DB but no peer or device gets to know about it
3966
- // and group membership is thus different on different devices. But if send_msg()
3967
- // failed, we still remove the member locally, otherwise it would be impossible to
3968
- // remove a member with missing key from a protected group.
3969
- // Note also that sending a message needs all recipients
3970
- // in order to correctly determine encryption so if we
3971
- // removed it first, it would complicate the
3972
- // check/encryption logic.
3973
- remove_from_chat_contacts_table ( context, chat_id, contact_id) . await ?;
3974
3974
context. emit_event ( EventType :: ChatModified ( chat_id) ) ;
3975
3975
if sync. into ( ) {
3976
3976
chat. sync_contacts ( context) . await . log_err ( context) . ok ( ) ;
0 commit comments