Commit Graph

5545 Commits

Author SHA1 Message Date
iequidoo
9cb2077c94 feat: Add EventType::CallMissed and emit it for missed calls (#7840)
Before, only `CallEnded` was emitted for missed calls, or, if a call arrives already being stale,
`IncomingMsg`. Now:
- `CallMissed` is emitted in addition to `CallEnded`.
- `IncomingMsg` is replaced with `CallMissed` for stale calls.
Having only one event type for missed calls should simplify handling them in the apps.

This doesn't emit `CallMissed` for those who aren't allowed to call us. Also, don't emit `CallEnded`
if the caller isn't allowed to call us and the call wasn't accepted, as there's no previous
`IncomingCall` event in this case.
2026-04-10 10:12:48 -03:00
link2xt
d6971ee4ac fix: make start messages stick to the top of the chat
We already set sort_timestamp to 0 for "Messages are end-to-end encrypted."
since 8f1bf963b4.
Do this for "Others will only see this group after you sent a first message."
and "Messages in this chat use classic email and are not encrypted." as well
so no messages can be added on top.
2026-04-10 03:16:12 +00:00
holger krekel
60bc4011f7 fix: let search also return hidden contacts if search value is an email address 2026-04-07 22:39:13 +02:00
link2xt
f552cf93b4 fix: assign webxdc updates from post-message to webxdc instance 2026-04-07 19:14:44 +00:00
link2xt
f75a7986b5 refactor: ignore ForcePlaintext in saved messages chat
ForcePlaintext was used for Autocrypt Setup Message,
there is no need to support it in saved messages chat anymore.
2026-04-07 17:00:47 +00:00
link2xt
3b8f1934f3 api!: remove dc_msg_force_plaintext
Message.force_plaintext() is still used in legacy SecureJoin steps
internally, so cannot be removed, but there is no need for public API.
2026-04-07 17:00:47 +00:00
link2xt
d2097d3523 fix: do not URL-encode proxy hostnames 2026-04-06 13:16:28 +00:00
link2xt
1219cbe1a3 fix: do not create 1:1 chat on second device when scanning a QR code
This avoids creating 1:1 chat on a second device when joining a channel.
Now when joining a channel there may be no 1:1 chat with the inviter
when the channel is created. In this case we still create the channel
as unblocked even if 1:1 chat would be a contact request
because joining the channel is an explicit action
and it is not possible to add someone who did not scan a QR
to the channel manually.
2026-04-06 00:42:14 +00:00
Hocuri
7233b4b811 test: Test that messages are only marked as delivered after being fully sent out (#8077)
Test for https://github.com/chatmail/core/pull/8062. I checked that the
test fails without #8062.
2026-04-05 20:37:32 +00:00
iequidoo
d1e0088201 feat: Flipped Exif orientations (#8057)
Before, sending of images flipped in Exif led to images having wrong orientation.
2026-04-05 17:04:17 -03:00
iequidoo
2f76fd98dd test: Add test for tweak_sort_timestamp()
The part of logic there adjusting the sort timestamp forward if the parent message has a greater
sort timestamp wasn't tested explicitly by any test. I only saw one unrelated "golden test" failure
when commented it out.
(Related to #8027)
2026-04-05 11:16:15 -03:00
Hocuri
626ac8161a fix: Mark a message as delivered only after it has been fully sent out (#8062)
Fix https://github.com/chatmail/core/issues/8042

The problem was that after receiving the bcc_self'ed pre-message in
`receive_imf`, the logic there only looked for a pending
`smtp`-table-entry that matches the rfc724_mid, and if there was none
then it thought "Great, apparently the message is fully sent out, we can
mark it as delivered!".

But with pre-messages, the same message can have two `smtp` entries (one
for the pre-message and one for the post-message), and the message
should only be marked as delivered once both of them are sent out.

Now, I changed the logic to look for all entries with the same msg_id.
This is actually the same SQL query used in smtp.rs, so, I extracted it
into a new function; feel free to suggest a better name for it.

I tested on Android that it now works fine.

I'll add a test in a follow-up PR.

There are a lot of other problems with sending large files, though:
- The pre-message is sent before the post-message, so that for the
receiver it looks as if the message arrived, but stays in
"downloading..." forever
- There is quite a time delay between clicking on "Send" and the
outgoing message appearing in the chat
- The message shortly gets a letter icon right after it is sent
- I'm wondering if there is a way to give feedback to the user
immediately if the message is too big
- It's unclear when exactly we want to send read receipts

I'll open a follow-up issue for these.
2026-04-02 15:12:17 +02:00
holger krekel
28cce5e31d fix: determine whether a message is an own message by looking at signature. multiple devices can temporarly have different sets of self addresses, and still need to properly recognize incoming versus outgoing messages. Disclaimer: some LLM tooling was initially involved but i went over everything by hand, and also addressed review comments. 2026-04-01 14:51:48 +02:00
link2xt
eb666d4cc3 test: the message is sorted correctly in the chat even if it arrives late 2026-03-30 08:52:19 +00:00
link2xt
ef265689dd fix: do not sort received messages below the last seen one 2026-03-30 08:52:19 +00:00
link2xt
49223792f9 fix: never sort the message before chat joining timestamp
This is to avoid sorting incoming messages that
are slightly in the past above system messages
about SecureJoin. SecureJoin messages are
timed according to smeared timestamp,
so even in the local tests they are in the future
by a few seconds.
2026-03-30 08:52:19 +00:00
Hocuri
920da083d1 fix: Manipulate sort_timestamp to not be 0 2026-03-30 08:52:19 +00:00
link2xt
8f1bf963b4 fix: always sort "Messages are end-to-end encrypted" notice to the beginning
We set timestamp of this info message to 0
to make it always appear in the beginning of the chat.
To avoid new chats being sorted to the end of the chatlist,
we ignore such 0 and use chat creation timestamp
when sorting the chatlist.
2026-03-30 08:52:19 +00:00
link2xt
e33d50b4e0 test: use load_imf_email() more 2026-03-30 08:52:19 +00:00
link2xt
f1dc03a4ee test: do not rely on loading newest chat in load_imf_email()
We know which message was added from the return value
of receive_imf(). It may be that the first chat
in the chatlist is not the one where the message was received
if there is a pinned chat or if
just received message is old.
2026-03-30 08:52:19 +00:00
link2xt
5d90cc7a2a test: remove test_old_message_5
It is not clear now what this is testing.
Golden test shows messages ordered
incorrectly according to the timestamps,
they should be ordered the other way round.

Comment talks about fetching from mvbox and inbox
in paralell which is a rare case that
could have happened if one message is left in the inbox
and the other message is a chat message moved to mvbox.
We never download anything that is not moved to the target folder.

The test also resides in "verified chats" tests
which are all legacy tests we kept after
replacing the concept of verified/protected chats
with key contacts in 2.x.
2026-03-30 08:52:19 +00:00
link2xt
68e630eb82 fix: remove migration 108
This removes migration added in 625887d249
2026-03-30 08:38:28 +00:00
iequidoo
ef718bb869 fix: When receiving MDN, mark all preceding messages as noticed, even having same timestamp (#7928)
This fixes flaky JSON-RPC `test_multidevice_sync_seen`.
2026-03-29 11:50:50 -03:00
iequidoo
f1860f90d4 feat: Log received message sort timestamp
This way it's easier to debug issues like `MsgsNoticed` not emitted for a chat.
2026-03-29 11:50:50 -03:00
link2xt
a947f4296f refactor(securejoin): do not check for self address in forwarding protection
If our key is gossiped, the message is intended for us.
The check for address is redundant for incoming messages as
if we received the message then it was addressed to us.

This whole protection code can eventually be removed
as we have intended recipient fingerprints already,
it only protects against forwarding of messages
sent by old clients.
2026-03-28 16:20:39 +00:00
link2xt
8c3139f7a2 feat: add decryption error to the device message about outgoing message decryption failure 2026-03-28 13:27:15 +00:00
link2xt
b87805ab24 fix: cleanup imap and imap_sync records without transport in housekeeping
Previously transports deleted via sync messages left unused `imap` entries.
2026-03-26 16:24:11 +00:00
link2xt
c8716ad85a fix: delete imap_markseen entries not corresponding to any imap rows 2026-03-26 16:24:11 +00:00
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