Also moved python version to environment variable
so status checks will be named
"JSON-RPC Python tests (ubuntu-latest, latest)" instead of
"JSON-RPC Python tests (ubuntu-latest, 3.14)" and we don't have to
update the list of required status checks each time the version changes.
We already do the same for Rust.
Reencoding animated WebPs into JPEG loses all frames except the first one.
Avatars we still reencode because we don't want animated avatars anyway.
animated.webp is produced with this script using Pillow 12.3.0:
```
#!/usr/bin/env python3
from PIL import Image, ImageOps
with Image.open("avatar900x900.png") as im:
frames = [im.rotate(x) for x in range(10, 360, 10)]
im.save(
"animated.webp",
"webp",
append_images=frames,
lossless=True,
duration=200,
save_all=True,
)
```
Resulting image is 677K, just slightly larger than the size needed to trigger reencoding.
The test fails on main with ~150MB memory remaining allocated
after sending/receiving two 20MB messages,
and stays well below when explicitely setting libc's M_MMAP_THRESHOLD.
this PR adds a new `msg_get_summary_text(add_forwarded, add_type_emoji,
approx_chars)` api, replacing the old `get_summarytext(approx_chars)`.
checking the concrete existing and new usecases, the new options are
required, eg. for:
- pinned messages: they do not show the user name (therefore, there
should not be a "forward" indicator), and may or may not not e.g.
display image left of string (this makes type emoji optional)
- notifications, quotes: they show user name (therefore, "forward"
indicator needed) and often display e.g. image a bit off (so type emoji
is potentially useful, cmp. whatsapp, but potentially also optional)
- copy to clipboard: clipboard should get forwarded and emoji, but text
should not be truncated and linends should be preserved - esp. the
latter was a silent bug in at least android. to support that better,
`approx_chars` can be set to `0` to skip truncation and unwrapping.
| Use case | `add_forwarded` | `add_type_emoji` | `approx_chars>0` |
| --- | :---: | :---: | :---: |
| Notification | ✅ | ✅ (potentially ❌) | ✅ |
| Quote | ✅ | ✅ (potentially ❌) | ✅ |
| Pinned message | ❌ | ❌ (rarely ✅) | ✅ |
| Copy to clipboard | ✅ | ✅ | ❌ |
| Chatlist (core internal) | ✅ | ✅ | ✅ |
| Reaction summary (core internal) | ❌ | ✅ | ✅ |
(the get_summary() returning a "lot" can maybe be removed at some point,
in favor of adding the usernames directly to get_summary_text() and
changing add_forwarded to add_usernames. but that is out of scope)
jsonrpc can be added easily once we settle on name etc.
references: https://github.com/chatmail/core/pull/8812 ,
https://github.com/chatmail/core/pull/8546
cc @Amzd , @adbenitez
---------
Co-authored-by: Hocuri <hocuri@gmx.de>
mail-builder changed how such filename is encoded in Content-Disposition between versions 0.5.0 and 1.0.0.
We can parse both encodings already and the test was not failing, but it is worth adding this corner case to the tests.
mail-builder 0.5.0 encoded the filename like this:
Content-Disposition: attachment;
filename="=?utf-8?Q?very_long_filename_with_emoji_=F0=9F=98=80_very_long_file_name_with_emoji_=F0=9F=AB=A0_very_long_file_name_with_emoji.tar.gz?="
mail-builder 1.0.0 encodes the filename like this:
Content-Disposition: attachment;
filename*0*=UTF-8''very%20long%20filename%20with%20emoji%20%F0%9F%98%80%20;
filename*1*=very%20long%20file%20name%20with%20emoji%20%F0%9F%AB%A0%20very;
filename*2*=%20long%20file%20name%20with%20emoji.tar.gz
async-imap 0.12.0 uses imap-proto 0.17.0 which includes bugfixes
for parsing responses with unicode characters.
Also upgraded base64 to 0.23 since new async-imap depends on it anyway.
`dc_chatlist_get_summary2()` was introduced for desktop that time,
but then replaced by jsonrpc's `get_chat_list_item_by_id()`.
outside desktop,
the cffi function seems to be never used in the past nor is today.
@adbenitez @Amzd - can you confirm it is not used?
similar for `summaryPreviewImage` - that was used on desktop, and is now
unused member of jsonrpc's ChatListItemFetchResult. question here: i
assume that it is fine to remove the member, and that desktop (maybe
after rebuilding) is fine with that.
@WofWca @nicodh - can you confirm, desktop is fine with the removal of
the member?
for general cleanup,
in an anyway complex area, it makes sense to remove these APIs.
Every `info!`, `warn!` and `error!` call expanded a complete
`tracing::event!` to mirror its message into `tracing` (#6919),
and that mirror made up most of core's macro output, now removed:
it's down from 219k to 54k lines using
RUSTC_BOOTSTRAP=1 cargo rustc -p deltachat --lib \
--profile check -- -Zmacro-stats
A warm build and `touch src/lib.rs` with rustc 1.99.0,
CARGO_INCREMENTAL=0 RUSTC_WRAPPER= /usr/bin/time -v \
cargo check -p deltachat
takes about a third less time and 0.37 GiB less peak memory,
`cargo build -p deltachat` about a tenth less time and 0.36 GiB less.
The release binary from `nix build .#deltachat-rpc-server-x86_64-linux`
gets 2.7% smaller.
If we want to use tracing events to integrate better with iroh-debugging,
for example when we move to iroh 1.X,
we could introduce some iroh-relevant tracing events in core.
Since #8350 (2026-09-09) deltachat-jsonrpc-bindings build-depends
on deltachat-jsonrpc, so clippy, nextest and the doctests,
which select the whole workspace, compiled core
and its whole dependency tree a second time for the host.
The lint job also checked every dependency twice, once per panic strategy,
and repeated clippy's checks in a separate all-features `cargo check`.
With a warm cache on 4 CPUs on my machine, the lint job drops
from 150 to 60 seconds and the tests build
from 100 to 75 seconds.
Peak memory falls for lint from
5.1 to 3.5 GiB and for tests
7.5 to 5.4 GiB.
When connecting to SMTP, transports are now tried
from the most recently successfully used transport to the least recently used.
Transports that were never used for sending
are tried in the order of increasing ID because init_transports()
tries to select the fastest transport for the first one.
This solves the problem of having to wait for timeout each time
if the first tried transport is down.
RPC server subprocess may exit for various reasons,
e.g. because of panic or because of debug_assert! during testing,
or because the process is killed manually or by OOM killer.
We still want to shutdown all threads cleanly in this case
and not fail in Rpc.close(). Otherwise Python process cannot exit
as it waits forever for all threads to terminate.
Without the fix, when added test is run in pytest,
pytest prints "ERROR at teardown of test_shutdown" and gets stuck.
When pytest is manually terminated with ^C, the following error is printed:
```
Exception ignored while joining a thread in _thread._shutdown():
Traceback (most recent call last):
File "/usr/lib/python3.14/threading.py", line 1583, in _shutdown
_thread_shutdown()
KeyboardInterrupt:
```
_thread_shutdown() is the function waiting for all non-daemon threads to finish.
Previously, when we disconnected from the current transport, we forgot
to reset the `transport_id` and `from`. I couldn't find any bug that is caused by
this today, but it was a lingering problem.
`ImageReader::with_guessed_format()` returns I/O errors, meaning the file is likely not readable.
If we wanted to check for the case when file format was not guessed,
the correct way would be to check if imgreader.format() returns `None`.
All the widely used formats (JPEG, PNG, GIF, WebP) are guessable from the first bytes,
so the code is not worth fixing as we cannot test it.
We already have context for HTTP(S) "CONNECT" command failures,
"Failed to connect to SOCKS5 proxy" and "Failed to connect to Shadowsocks proxy",
but when TCP connection to HTTP(S) fails the error is bubbled up as is.
This resulted in confusing "All connection attempts failed: Connection to host:port failed: ..." error
when configuring a relay, without any indication that "host:port" is the proxy address.
This factors out all MDN-related code that was previously inside `MimeFactory`
into a `mimefactory::mdn` function that constructs `QueuedMail` directly,
similarly to `mimefactory::keyupdate_message`.
Removing MDN-related code from MimeFactory also means that MimeFactory only handles non-MDN messages now
and we don't have to `match` on `MimeFactory.loaded` everywhere to access `msg` and `chat`.
Unlike `MimeFactory::from_mdn`, `mimefactory::mdn` does not need to fill `MimeFactory.from_addr`.
This removes one `get_primary_self_addr()` call. `mimefactory::mdn` also does not need to fill
various fields that are never used for MDNs such as `past_members`.
It looks like the function is only called for File and Image viewtypes,
so there is no way to get into the Sticker branch
that checks the corners for transparency.
A join request is sent to every relay of an inviter, but the answering
inviter device only deleted the copy it downloaded. Another device of the inviter
fetching a different relay later answered the request again, re-adding
members who had left or been removed in the meantime.
this PR makes it easier to spot unwanted "add second device" actions, if
the unlocked device is left unattended and/or a system lock is not in
place (so cannot be checked directly before doing the "add second
device" action).
already today, the sending device gets the message "ℹ️ Profile
transferred to your second device", which, however, can be deleted.
with this PR, if the message is deleted soon after the transfer, it
first looks as if this was successful. however, the message is re-added
later, at the first housekeeping at least an hour after the transfer.
deleting the message after that is final, so users can still get rid of
it.
It is clear that this does not catch all eventualities, it is
best-effort. e.g. it is known that subsequent "add second device"
attempts remove checks of previous ones.
First line of defense is device locking and asking for secret explicitly
before adding a second device.
previous discussions about that at
https://github.com/chatmail/core/issues/4303
Paths in deltachat.pc are passed via env variables to build.rs. With
this fix, the pc will be regenerated if these env variables change.
This came up when building via CMake: the paths depend on
CMAKE_INSTALL_PREFIX, if the CMAKE_INSTALL_PREFIX changes during a
reconfigure, deltachat.pc should have the corresponding paths adjusted.