Commit Graph

5517 Commits

Author SHA1 Message Date
link2xt
4dd0ba2c72 fix: move sorting outside of SQL query in store_seen_flags_on_imap
With `ORDER BY` statement SQLite searches
the `imap` table by `transport_id` and for each found row
scans the whole `imap_markseen` table.
Number of `imap` entries for each `transport_id`
is usually large as we need to know
which UIDs to delete on IMAP server
when deleting a message.

```
sqlite> EXPLAIN QUERY PLAN
SELECT imap.id, uid, folder FROM imap, imap_markseen
WHERE imap.id = imap_markseen.id
AND imap.transport_id=?
AND target = folder
ORDER BY folder, uid;
QUERY PLAN
|--SEARCH imap USING INDEX sqlite_autoindex_imap_1 (transport_id=?)
`--SCAN imap_markseen
```

Without `ORDER BY` statement SQLite scans `imap_markseen`
table which is expected to be small,
and then searches `imap` table by `rowid` for each found result.

```
sqlite> EXPLAIN QUERY PLAN
SELECT imap.id, uid, folder FROM imap, imap_markseen
WHERE imap.id = imap_markseen.id
AND imap.transport_id=?
AND target = folder;
QUERY PLAN
|--SCAN imap_markseen
`--SEARCH imap USING INTEGER PRIMARY KEY (rowid=?)
```

Query planning was tested with SQLite 3.52.0.
It is possible to explictly make
query planner move sorting to the last step
with `ORDER +folder, +uid`, but this is not recommended
in SQLite documentation
(see <https://www.sqlite.org/optoverview.html#uplus>).

It is also possible to add indexes,
but indexes use space,
adding them requires an SQL migration,
and each index needs to be updated so it will slow down writes.
2026-03-26 16:24:11 +00:00
iequidoo
af16fc9038 fix: Make Message-ID of pre-messages stable across resends (#8007) 2026-03-25 23:32:33 -03:00
link2xt
c99b8a4482 feat: improve IMAP loop logs
Only inbox loop is changed because non-inbox loop is going to be removed
together with `mvbox_move`.

Added transport IDs to the log and logging around quota updates.
Removed some logs that add noise,
like logging that IDLE is supported each time right before using it.
2026-03-25 20:31:53 +00:00
link2xt
76e2c36d85 refactor: cleanup remaining Autocrypt Setup Message processing in mimeparser 2026-03-25 19:54:19 +00:00
link2xt
ebe8550c52 chore: fix clippy warnings 2026-03-25 19:53:10 +00:00
link2xt
2637c3bea4 refactor: replace async RwLock with sync RwLock for stock strings 2026-03-25 19:48:40 +00:00
iequidoo
d1f1633c60 refactor: Remove wal_checkpoint_mutex, lock write_mutex before getting sql connection instead
The original idea was to always lock `write_mutex` before acquiring an `InnerPool.semaphore` permit
to avoid ABBA deadlocks, but when refactoring a PR for b696a242fc,
that was forgotten.

This doesn't really change the program flow as we have `Context::housekeeping_mutex` anyway,
just simplifies the code.
2026-03-25 06:13:10 -03:00
link2xt
5ab1fdca2e feat: use SEIPDv2 if all recipients support it 2026-03-24 02:37:40 +00:00
link2xt
f616d1bd6c refactor: remove code to send messages without intended recipient fingerprint 2026-03-23 22:45:10 +00:00
link2xt
e885e052c3 test: make add_or_lookup_contact_id_no_key public 2026-03-23 22:45:10 +00:00
link2xt
6b1e62faba fix: delete available_post_msgs row if there is no corresponding IMAP entry
If we learn about this message being available on IMAP later,
we will add another available_post_msgs row.
If we don't delete the row, we will keep failing each time
until IMAP entry becomes available and it may not happen.
2026-03-23 22:01:16 +00:00
link2xt
7b9e7ae611 fix: delete available_post_msgs row if the message is already downloaded
The row does not need to stay in the database
only to be skipped each time.
2026-03-23 22:01:16 +00:00
Hocuri
e86b170969 fix: Don't fall into infinite loop if the folder is missing (#8021)
Previously, if the mvbox_move folder is missing, then core will loop
infinitely, because `new_mail` is never set to false.

The fix is to first set `new_mail` to false, then return if the folder
is missing.

This is the bug @hpk42 experienced when commenting in
https://github.com/chatmail/core/issues/7989

---------

Co-authored-by: holger krekel <holger@merlinux.eu>
2026-03-23 18:29:49 +01:00
Hocuri
5d06ca3c8e fix: Make newlines work in chat descriptions (#8012)
This fixes a bug: If there is a multi-line chat description, only the
first line was shown on recipient devices.

Credits to @lk108 for noticing!
2026-03-21 14:48:56 +01:00
link2xt
bcaf1284e2 feat(tls): do not verify TLS certificates for hostnames starting with _ 2026-03-18 17:51:03 +00:00
Hocuri
fba4e63961 api: Rename Transport to TransportListEntry (#8009)
Follow-up to https://github.com/chatmail/core/pull/7994/, in order to
prevent clashes with other things that are called `Transport`, and in
order to make the struct name more greppable
2026-03-18 16:17:53 +01:00
Hocuri
810dab12dc api: Add list_transports_ex() and set_transport_unpublished() functions
Closes https://github.com/chatmail/core/issues/7980.

Unpublished transports are not advertised to contacts, and self-sent messages are not sent there, so that we don't cause extra messages to the corresponding inbox, but can still receive messages from contacts who don't know the new relay addresses yet.

- This adds `list_transports_ex()` and `set_transport_unpublished()` JsonRPC functions
- By default, transports are published, but when updating, all existing transports except for the primary one become unpublished in order not to break existing users that followed https://delta.chat/legacy-move
- It is not possible to unpublish the primary transport, and setting a transport as primary automatically sets it to published

An alternative would be to change the existing list_transports API rather than adding a new one list_transports_ex. But to be honest, I don't mind the _ex prefix that much, and I am wary about compatibility issues. But maybe it would be fine; see b08ba4bb8 for how this would look.
2026-03-18 12:14:56 +01:00
Hocuri
c0cc2ae816 refactor: Move transport_tests to their own file 2026-03-18 12:14:56 +01:00
link2xt
296ed6d74a api!: remove functions for sending and receiving Autocrypt Setup Message 2026-03-17 20:10:59 +00:00
link2xt
8116460f14 feat: enable anonymous OpenPGP key IDs
This was disabled for interoperability in
098084b9a7,
enabling it back now.
2026-03-17 20:08:38 +00:00
link2xt
52f4293bc5 feat: decode dcaccount:// URLs and error out on empty URLs early
The problem was reported at
<https://support.delta.chat/t/could-not-find-dns-resolutions-for-imap-993-when-adding-a-relay/4907>

iOS typically transforms `:` into `://`,
we already handle this in `dclogin` URLs,
so handle it for `dcaccount` as well.
2026-03-17 20:08:24 +00:00
link2xt
cff0192e38 refactor: import tokio_rustls::rustls 2026-03-17 19:10:18 +00:00
link2xt
6f17a86903 refactor: use re-exported rustls::pki_types 2026-03-17 19:10:18 +00:00
link2xt
e06372c954 fix: count recipients by Intended Recipient Fingerprints
Fixes <https://github.com/chatmail/core/issues/7987>
2026-03-17 00:32:33 +00:00
B. Petersen
50cd2514cd test markfresh_chat()
the tests were initially generated by AI and then reworked.
2026-03-16 21:00:32 +01:00
B. Petersen
e690186236 feat: mark messages as "fresh"
this adds an api to make the newest incoming message of a chat as "fresh",
so that UI can offer a "mark chat unread" option as usual for messengers
(eg. swipe right on iOS toggels between "read" and "unread").

"mark unread" is one of the most requested missing features,
used by many ppl to organize their every day messenger usage -
tho "pinning" and "saved messages" are similar,
it seems to be missed often.

we follow a very simple approach here
and just reset the state to `MessageState::InFresh`.
this does not introduce new states or flows.

therefore, chats without any incoming message cannot be marked as fresh.
in practise, this is probably not really an issue,
as the "mark fresh" is usually used to undo a "mark noticed" operation -
and then you have incoming message.
also, most status messages as "all messages are e2ee" count as incoming.

to avoid double sending of MDN,
we remove `Param::WantsMdn` once the MDN is scheduled.
in case MDN are used for syncing, MDN is still sent as before.

many other messenger show a "badge without number",
if we want that as well,
we can always track the "manually set as fresh" state in a parameter.
but for now, it is fine without and showing a "1", which alsso makes sense as badges may be summed up.

there is an iOS pr that uses this new feature,
jsonrpc is left out until api is settled.

also out of scope is synchronisation -
main reason is that "mark noticed" is not synced as well, so we avoid an imbalance here.
both, "mark noticed" as well as "mark fresh" should be synced however,
as soon as this feature is merged.
2026-03-16 21:00:32 +01:00
link2xt
e14151d6cc fix: fsync() the rename() of accounts.toml 2026-03-16 17:09:57 +00:00
link2xt
c6cdccdb97 fix: call sync_all() instead of sync_data() when writing accounts.toml 2026-03-16 17:09:57 +00:00
link2xt
822a99ea9c fix: do not send MDNs for hidden messages
Hidden messages are marked as seen
when chat is marked as noticed.
MDNs to such messages should not be sent
as this notifies the hidden message sender
that the chat was opened.

The issue discovered by Frank Seifferth.
2026-03-15 20:54:50 +00:00
WofWca
bf02785a36 feat: add IncomingCallAccepted.from_this_device 2026-03-14 22:21:46 +04:00
iequidoo
01b2aa0f66 fix: Mark call message as seen when accepting/declining a call (#7842) 2026-03-14 13:46:25 -03:00
iequidoo
fb46c34b55 test: Shift time even more in flaky test_sync_broadcast_and_send_message
As of now, alice1 makes 3 more calls of create_smeared_timestamp() than alice2 does, so we need to
shift time by 3s to fix the test.
2026-03-14 16:20:46 +01:00
link2xt
7b17b1f8b8 test: set some address for test context in decrypt_bytes()
This is needed to create pseudo transport, otherwise
public key generation fails.
2026-03-14 02:23:25 +00:00
Hocuri
d8d7f12af0 fix: Domain separation between securejoin auth tokens and broadcast channel secrets (#7981)
Can be reviewed commit-by-commit.

This fixes another silly thing you can do with securejoinv3: show Bob a
QR code with auth token that is a broadcast channel secret of a known
channel, then never respond. Bob will decrypt messages from the channel
and drop them because they are sent by the "wrong" sender.

This can be avoided with domain separation, instead of
encrypting/decrypting securejoinv3 messages directly with auth token,
encrypt/decrypt them with `securejoin/<auth token>` as the secret or
even `securejoinv3/<alice's fingerprint>/<auth token>`. For existing
broadcast channels we cannot do this, but for securejoinv3 that is not
released yet this looks like an improvement that avoids at least this
problem.

Credits to link2xt for noticing the problem.

This also adds Alice's fingerprint to the auth tokens, which
was pretty easy to do. I find it hard to develop an intuition for
whether this is important, or whether we will be annoyed by it in the
future.

**Note:** This means that QR code scans will not work if one of the chat
partners uses a self-compiled core between c724e2981 and merging this PR
here. This is fine; we will just have to tell the other developers to
update their self-compiled cores.
2026-03-13 22:01:19 +01:00
link2xt
0150d38ddd fix: update add_timestamp when the transport is selected as primary 2026-03-13 15:02:08 +00:00
link2xt
11b6a108f5 feat: merge OpenPGP certificates and distribute relays in them
We put all relay addresses as a notation subpacket
in the direct key signature to distribute the relay addresses.
2026-03-13 15:02:08 +00:00
link2xt
54858361a9 feat: mutex to prevent fetching from multiple IMAP servers at the same time 2026-03-13 15:02:08 +00:00
link2xt
6a705a3ef6 fix: update device chats at the end of configuration 2026-03-13 15:02:08 +00:00
link2xt
a23e41ea6d fix: fix debug assert message incorrectly talking about past members in the current member branch 2026-03-13 15:02:08 +00:00
link2xt
bdca3e5c09 refactor: order self addresses by addition timestamp
This way the order does not change when
primary address is changed.
2026-03-13 15:02:08 +00:00
Hocuri
5404e683eb fix: Drop messages encrypted with the wrong symmetric secret (#7963)
The tests were originally generated with AI and then reworked.

Follow-up to https://github.com/chatmail/core/pull/7754 (c724e29)

This prevents the following attack:

/// Eve is subscribed to a channel and wants to know whether Alice is also subscribed to it.
/// To achieve this, Eve sends a message to Alice
/// encrypted with the symmetric secret of this broadcast channel.
///
/// If Alice sends an answer (or read receipt),
/// then Eve knows that Alice is in the broadcast channel.
///
/// A similar attack would be possible with auth tokens
/// that are also used to symmetrically encrypt messages.
///
/// To prevent this, a message that was unexpectedly
/// encrypted with a symmetric secret must be dropped.
2026-03-12 18:59:19 +00:00
B. Petersen
3c5af7a559 fix: use correct string for encryption info
encryption info needs a dedicated string for "Messages are end-to-end encrypted"
as the UI will add more infomation to the info messages,
smth. as "Tap for more information".

an alternative fix would have been to let the UI render the info-message
differently, but adding another string to core causes less friction.
2026-03-11 15:03:07 +01:00
Jagoda Estera Ślązak
c0a3d77301 fix: Correct channel system messages (#7959)
Previously channels used the same system messages
as groups, which can be confusing.

Fixes #7951

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-03-11 07:56:30 +00:00
iequidoo
9891c2a531 fix: Add "member added" messages to OutBroadcast when executing SetPgpContacts sync message (#7952)
If one of broadcast owner's devices didn't add a new subscriber for any reason, e.g. because of
missing SecureJoin messages, this device shall add "member added" messages when syncing the member
list from the `SetPgpContacts` message.
2026-03-10 22:03:04 -03:00
iequidoo
f85c625799 test: Work around test_sync_broadcast_and_send_message flakiness
The test sometimes fails because of wrong message ordering for bob:
     [...]
     Waiting for the device of alice@example.org to reply… [NOTICED][INFO]
    <Msg#2010🔒:  (Contact#Contact#2001): hi [FRESH]
     Msg#2008🔒:  (Contact#Contact#2001): You joined the channel. [FRESH][INFO]
    >Msg#2010🔒:  (Contact#Contact#2001): hi [FRESH]
     Msg#2011🔒:  (Contact#Contact#2001): Member Me removed by alice@example.org. [FRESH][INFO]

This adds `SystemTime::shift(Duration::from_secs(1))` as a workaround.

Co-authored-by: Hocuri <hocuri@gmx.de>
2026-03-10 10:00:54 -03:00
link2xt
53acfaa054 fix: add mutex around wal_checkpoint()
Documentation comment explains how it prevents the deadlock.
2026-03-06 09:35:12 +00:00
link2xt
874e38c146 refactor: move WAL checkpointing into sql::pool submodule
This change is mainly to avoid exposing the write lock outside the pool module.
To avoid deadlocks, outside code should work only with the pooled connections
and use no more than one connection per thread.
2026-03-06 09:35:12 +00:00
link2xt
cce8e3bc5a fix: do not run more than one housekeeping at a time
With multiple transports there are multiple inbox loops on the same profile `Context`. 
They tend to start running housekeeping at the same time, e.g. when deleting
a message with an attachment, and then `remove_unused_files()`
tries to remove the same files that are already deleted by another thread
and logs errors.
2026-03-06 09:34:20 +00:00
Hocuri
1e20055523 feat: Don't send unencrypted Auto-Submitted header (#7938)
Cherry-picked 8c09ca3

Follow-up to https://github.com/chatmail/core/pull/7935
2026-03-06 10:29:17 +01:00
Jagoda Estera Ślązak
abb93cd79d fix: Set proper placeholder texts for system messages (#7953)
Don't use first-person form in placeholder texts,
as these can be misleading when broadcasted to group.
Additionally ensures that broadcasted system messages
are not localized to not leak locally-set language 
to the group chat.

Fixes #7930

Signed-off-by: Jagoda Ślązak <jslazak@jslazak.com>
2026-03-05 14:56:23 +00:00