This implements new group consistency algorithm described in
<https://github.com/deltachat/deltachat-core-rust/issues/6401>
New `Chat-Group-Member-Timestamps` header is added
to send timestamps of member additions and removals.
Member is part of the chat if its addition timestamp
is greater or equal to the removal timestamp.
shows the last reaction in chatlist's summaries if there is no
newer message.
the reason to show reactions in the summary, is to make them a _little_
more visible when one is not in the chat. esp. in not-so-chatty or in
one-to-ones chats this becomes handy: imaging a question and someone
"answers" with "thumbs up" ...
otoh, reactions are still tuned down on purpose: no notifications, chats
are opend as usual, the chatlist is not sorted by reactions and also the
date in the summary refer to the last message - i thought quite a bit
about that, this seems to be good compromise and will raise the fewest
questions. it is somehow clear to the users that reactions are not the
same as a real message. also, it is comparable easy to implement - no
UI changes required :)
all that is very close to what whatsapp is doing (figured that out by
quite some testing ... to cite @adbenitez: if in doubt, we can blame
whatsapp :)
technically, i first wanted to go for the "big solution" and add two
more columns, chat_id and timestamp, however, it seemed a bit bloated if
we really only need the last one. therefore, i just added the last
reaction information to the chat's param, which seems more performant
but also easier to code :)
I.e. exclude from the list the following chats as well:
- Read-only mailing lists.
- Chats we're not a member of.
But as for ProtectionBroken chats, we return them, as that may happen to a verified chat at any
time. It may be confusing if a chat that is normally in the list disappears suddenly. The UI need to
deal with that case anyway.
(cherry picked from commit 83ef25e7de)
I.e. exclude from the list the following chats as well:
- Read-only mailing lists.
- Chats we're not a member of.
But as for ProtectionBroken chats, we return them, as that may happen to a verified chat at any
time. It may be confusing if a chat that is normally in the list disappears suddenly. The UI need to
deal with that case anyway.
Message.set_text() and Message.get_text() are modified accordingly
to accept String and return String.
Messages which previously contained None text
are now represented as messages with empty text.
Use Message.set_text("".to_string())
instead of Message.set_text(None).
Why? because desktop currently fetches the chatlist multiple times, even though it just needs the
chatlistitem for one chat.
Note: @r10s was worried before that exposing the method to get a single updated chatlistitem could
lead to race conditions where the chatlist item is newer than the chatlist order. But I don't think
this will change anything for desktop besides making it a little faster (because currently desktop
fetches the whole chatlist instead of just the entry it needs when an entry updates).
Moved custom ToSql trait including Send + Sync from lib.rs to sql.rs.
Replaced most params! and paramsv! macro usage with tuples.
Replaced paramsv! and params_iterv! with params_slice!,
because there is no need to construct a vector.
* move 'archived link' betweeen pinned and normal cahts or above normal chats
* add icon for 'archived chats' link
* let get_fresh_msg_cnt() work for DC_CHAT_ID_ARCHIVED_LINK
* move 'archived link' topmost
* use less noticeable archived-icon
* slightly smaller archived icon
* update CHANGELOG
* Do ephemeral deletion in background loop
1. in start_io start ephemeral async task, in stop_io cancel ephemeral async task
2. start ephemeral async task which loops like this:
- wait until next time a message deletion is needed or an interrupt occurs (see 3.)
- perform delete_expired_messages including sending MSGS_CHANGED events
3. on new messages (incoming or outgoing) with ephemeral timer:
- interrupt ephemeral async task
* Changelog
* Fix and improve test
* no return value needed
* address @link2xt review comments
* slight normalization: have only one place where we wait for interrupt_receiver
* simplify sql statement -- and don't exit the ephemeral_task if there is an sql problem but rather wait
* Remove now-unused `ephemeral_task` JoinHandle
The JoinHandle is now inside the Scheduler.
* fix clippy
* Revert accidental move of the line
* Add log
Co-authored-by: holger krekel <holger@merlinux.eu>
Co-authored-by: link2xt <link2xt@testrun.org>
This makes the contact ID its own newtype instead of being a plain
u32. The change purposefully does not yet try and reap any benefits
from this yet, instead aiming for a boring change that's easy to
review. Only exception is the ToSql/FromSql as not doing that yet
would also have created churn in the database code and it is easier to
go straight for the right solution here.
- Replace .ok_or_else() and .map_err() with anyhow::Context where possible.
- Use .context() to check Option for None when it's an error
- Resultify Chatlist.get_chat_id()
- Add useful .context() to some errors
- IMAP error handling cleanup
`imap` table maps Message-IDs to UIDs on the server. `dc_receive_imf`
no longer gets the UID of the message as an argument and does not
insert the folder and UID of the message into the `msgs`
table. `server_folder` and `server_uid` columns in `msgs` table are
deprecated.
MoveMsg and DeleteMsgOnImap jobs are removed. Now messages are moved
and deleted only in the `fetch_move_delete` procedure that consults
the `target` column of the `imap` table to determine where the message
should go.
Where the message should go is determined after prefetching by the
`imap::target_folder()` procedure. Messages are only downloaded once
they reach their target folder to avoid race conditions in multidevice
setting, such as:
1. One device trying to FETCH the message while the other tries to
MOVE it.
2. One device marking the message as \Seen in the Inbox while the
other has already copied unseen message to the Movebox and is going to
delete the \Seen message in the Inbox.
3. Device downloads the message from the Inbox while there are newer
messages in the Movebox placed there by the other device, thus
processing the messages out of order.
* refactor: cleanup send_handshake_msg()
- rename to send_alice_handshake_msg() as used by Alice only
- remove dead code from Bob
(Bob's code is at BobState::send_handshake_message() since some time)
- take a contact_id and not a chat_id;
this makes things less confusing when
info-messages are put to the final group chat
* always directly return chat-id from dc_join_securejoin()
* take care not to create a group twice
* adapt documentation
* add info-msg on group invites; add inviter directly after creation
* document existing 'joinqr' command in repl tool
* do not create empty one-to-one chats for group-joins
* refactor: cleanup fingerprint_equals_sender()
- the function takes a contact_id directly now.
before it consumes the first contact of a one-to-one chat -
which may be easily confused with the group-chat in creation.
moreover, the conversion contact_id -> chat_id -> contact_id
is unneeded overhead.
* show info-messages in destination chat for alice
* fingerprint_equals_sender() returns Err on database failure
* tweak documentation
* clarify what an 'unfinished tasks' task is.
* add regression test for create_for_contact_with_blocked()
* rename Blocked::Manually to better fitting Blocked::Yes
* tweak test_secure_join() and make sure, Alice and Bob have only on chat after a group-join
* add Chattype::Broadcast and create_broadcast_list()
* do not disclose recipients for broadcasts
* allow sending/add-/remove-member for broadcast
* set broadcast subject same as for one-to-one chats
* broadcast-recipient-list does not include SELF
* use special icon for broadcast groups
* generate initial broadcast names
* make clippy happy
* send BCC message unencrypted to avoid unexpected disclosing; encryption is opportunistic anyway. if we have 'protected chats' at some point, we can think that over.
* reword 'To:'-group
* simplify can-send-check
* add broadcast tests
* tweak comments
* Update deltachat-ffi/deltachat.h
Co-authored-by: Hocuri <hocuri@gmx.de>
* change name of can_edit() to is_self_in_chat()
Co-authored-by: Hocuri <hocuri@gmx.de>
summary::Summary replaces Lot in the Rust API for methods returning
chatlist summaries. Lot is a legacy type for C API compatibility, so
Summary can be converted into Lot.
* add a test for archived requests
* fix archived requests
* move requests but the last one to "Archived Chats"
this way, the app looks familiar after the contact request upgrade.
the subselect was copied from the old get_last_deaddrop_fresh_msg()
(which was removed by the contact request upgrade #2514)
* just move all old requests to "Archived Chats"
ux-wise, the advantage of keeping the last one is questionable,
one may think, always the last one is shown in chatlist.
showing _all_ fresh request is not doable
as past cores did not really take care of that
and the db-state is not consistent in that regard.
that would make the already complicated code even more complicated,
so we decided to go the easy way.
Contact request chats are not merged into a single virtual "deaddrop"
chat anymore. Instead, they are shown in the chatlist the same way as
other chats, but sending of messages to them is not allowed and MDNs
are not sent automatically until the chat is "accepted" by the user.
New API:
- dc_chat_is_contact_request(): returns true if chat is a contact
request. In this case option to accept and block the chat via
dc_accept_chat() and dc_block_chat() should be shown in the UI.
- dc_accept_chat(): accept contact request and unblock the chat
- dc_block_chat(): decline contact request and block the chat
Removed API:
- dc_create_chat_by_msg_id(): deprecated 2021-02-07 in favor of
dc_decide_on_contact_request()
- dc_marknoticed_contact(): deprecated 2021-02-07 in favor of
dc_decide_on_contact_request()
- dc_decide_on_contact_request(): this call requires a message ID from
deaddrop chat as input. As deaddrop chat is removed, this call can't
be used anymore.
- dc_msg_get_real_chat_id(): use dc_msg_get_chat_id() instead, the
only difference between these calls was in handling of deaddrop chat
- removed DC_CHAT_ID_DEADDROP and DC_STR_DEADDROP constants
This moves the module-level lookup and creation functions to the
types, which make the naming more consistent. Now the lookup_* get_*
and create_* functions all behave similarly.
Peraps even more important the API of the lookup now allows
distinguishing failure from not found. This in turn is important to
be able to remove reliance on a ChatId with a 0 or "unset" value. The
locations where this ChatId(0) is still used is in database queries
which should be solved in an independed commit.