Commit Graph
100 Commits
Author SHA1 Message Date
link2xt fae6a63023 fix: use correct address for Bcc-self in unencrypted mails 2026-09-19 17:44:10 +00:00
link2xt 54e16429b8 fix: use correct From address when sending MDNs 2026-09-19 17:44:10 +00:00
link2xt e1d58706ce api!: remove Contact.get_name_n_addr() and related APIs
UIs should use display name everywhere and avoid displaying email addresses.

BREAKING CHANGE: dc_contact_get_name_n_addr() CFFI is removed
BREAKING CHANGE: JSON-RPC contact objects don't have nameAndAddr field anymore
2026-09-19 08:16:30 +00:00
link2xt 0a7e697f50 refactor: add smtp::queue module
No changes except that smtp::is_queue_empty is renamed into smtp::queue::is_empty,
mimefactory::QueuedEncryption is renamed into smtp::queue::Encryption
and mimefactory::QueueSideEffects is renamed to smtp::queue::SideEffects.
mimefactory module does not know anything about smtp2 table anymore.
2026-09-18 18:23:16 +00:00
link2xt 310dda494c feat: do not use ConfiguredAddr when connecting to SMTP 2026-09-18 17:10:29 +00:00
link2xt 8f39d7510f feat: do not restart I/O when setting configured_addr 2026-09-18 17:10:29 +00:00
link2xt f7c97d8557 test: add pseudo transport explicitly rather than by setting ConfiguredAddr
ConfiguredAddr is going to be removed, but we need to be able to add fake transports,
also for existing offline Python tests.
2026-09-18 08:09:33 +00:00
link2xt 78caa6f53c fix: emit SmtpMessageSent event after deleting the message from SMTP queue
This is mostly needed to fix flaky
tests/test_something.py::test_is_sending_finished
by making sure that is_sending_finished() return false
once we got an event that message was sent.
2026-09-17 18:59:20 +00:00
link2xt 349c9650e3 fix: do not send a sync message when changing "configured_addr"
Sending transport is not synchronized since
cd42efb36d
(PR https://github.com/chatmail/core/pull/8510)
so there is no need to send a sync message
when the sending transport is changed.
2026-09-17 18:50:09 +00:00
link2xt 44c2febbe1 test(direct_imap): always pass mark_seen=False to fetch()
mark_seen=True is the default and translates to fetching BODY
of the message. mark_seen=False translates to fetching BODY.PEEK
that is described in IETF RFC 3501 as
"An alternate form of BODY[<section>] that does not implicitly set the \Seen flag."

It is unexpected unless you know this detail of IMAP protocol already,
but this is not going to be fixed in imap_tools: <https://github.com/ikvk/imap_tools/issues/179>
2026-09-17 13:58:42 +00:00
link2xt 555b8b8b51 test: do not fetch all messages when direct_imap is created
This code is likely from the time when we reused mailboxes
in python/ tests, it does not do anything anymore.
2026-09-17 13:58:42 +00:00
link2xt dc9bba0697 refactor(sql): disable double-quoted string literals
Double-quoted string literals are not standard
and may be accidentally treated as an identifier
if there is an identifier with the same name
as the string contents:
https://sqlite.org/quirks.html#double_quoted_string_literals_are_accepted
2026-09-17 13:31:41 +00:00
link2xt 3858c47ceb api!: remove default value for "addr" config
"addr" is already deprecated and its default value was using "configured_addr".
We want to get rid of "configured_addr" too, but users should at least
not access it through deprecated config.
2026-09-17 12:46:43 +00:00
link2xt 6b1d982cfc test: rename test_aeap_transition_{0,1} to test_aeap_transition_{single,group} 2026-09-17 09:31:15 +00:00
link2xt 5a71fe101e test: do not talk about "inconsistent key state" in test_securejoin_after_contact_resetup
"Inconsistent key state" referred to acpeerstates table row
with different Autocrypt and verified keys.
Since v2 and introduction of key contacts it is not possible for a contact
to have inconsistent key state, so this translates to having
two contacts with the same email address but different keys.
2026-09-17 09:30:51 +00:00
link2xt 6c3a866892 docs: mention get_app_version() API in the changelog for 2.59.0
It was added in https://github.com/chatmail/core/pull/8557,
but the changelog entry just says "Client version information".
2026-09-16 15:46:25 +00:00
link2xt 373f1840a6 feat: queue messages for SMTP before encryption
Headers like From and Autocrypt are now added late,
right before sending the message over SMTP.
This way we advertise the latest list of transports
and use the correct From address in the encrypted part
even for messages queued while being offline.

BCC-self recipients are also added late.
For unencrypted messages we only want to send a copy
to the sending address, but we don't know the sending address
when queueing the message.
Adding bcc-self recipients when dequeuing the message
also makes it possible to send copies to updated list of relays.
2026-09-16 13:06:06 +00:00
link2xt 81982273e8 refactor: separate QueuedEncryption
This is similar to mimefactory::Encryption,
but does not have email addresses for asymmetrically encrypted messages.
Queued messages don't need email addresses for public keys.
Addresses are only needed to render Autocrypt-Gossip headers.
2026-09-16 13:06:06 +00:00
link2xt 5be489790f refactor: add Encryption.is_encrypted() 2026-09-16 13:06:06 +00:00
link2xt 81ca5aa1ca test: cleanup get_smtp_rows_for_msg()
It was incorrectly converting unused row ID to MsgId type
and selecting already known msg_id.
2026-09-16 13:06:06 +00:00
link2xt 15488ed210 chore: fix some types in deltachat_rpc_client 2026-09-16 11:43:25 +00:00
link2xt f03088f247 chore: fix nightly "cargo" warnings 2026-09-16 11:43:06 +00:00
link2xt abb0a119cb chore: update rustls to 0.23.45
This fixes https://rustsec.org/advisories/RUSTSEC-2026-0285
2026-09-15 12:11:18 +00:00
link2xt 44387f5e58 api: add JSON-RPC API is_sending_finished() 2026-09-12 23:35:58 +00:00
link2xt 9e8c3a63ad docs: update sys.msgsize_max_recommended documentation
Errors are no longer shown as a toast by UIs
and it is no longer true that any warning or error is logged.
2026-09-11 22:35:33 +00:00
link2xt f725e91b2a chore: bump version to 2.61.0-dev 2026-09-11 21:14:09 +00:00
link2xt a2d8ced169 chore(release): prepare for 2.60.0 2026-09-11 19:59:10 +00:00
link2xt 75a80fbb65 feat: ignore Chat-Disposition-Notification-To value
Main change is the removal of the comparison of Chat-Disposition-Notification-To
to the From header for incoming messages.

Removed code that was settting WantsMdn for outgoing messages
is a leftover not cleaned up in ade39fe026
We do not actually use WantsMdn for outgoing messages.
2026-09-11 19:29:18 +00:00
link2xt 58b5f5d0f4 feat: increase sys.msgsize_max_recommended to match chatmail message size limit
This also affects maximum number of webxdc updates attached to the message.
2026-09-10 21:18:33 +00:00
link2xt 51b6d50a22 test: print which error/warning was expected if it does not arrive 2026-09-10 19:09:56 +00:00
link2xt 61d73433ea chore: bump chacha20 0.10.1 to 0.10.2
0.10.1 is yanked: https://github.com/RustCrypto/stream-ciphers/pull/583
2026-09-10 18:02:04 +00:00
link2xt 4232b8b20d ci: update Rust to 1.98.1 2026-09-10 17:53:15 +00:00
link2xt b0e5b08531 refactor: use &[..] instead of &Vec<..>
Most of such cases are detected by clippy::ptr_arg,
but in these cases clippy did not catch anything.
2026-09-09 08:34:39 +00:00
link2xt 49c30ecc75 refactor: split flake.nix into multiple files 2026-09-04 20:10:24 +00:00
link2xt 506a78b5d4 fix: do not load webxdc icon if it has too large dimensions
BREAKING CHANGE: get_webxdc_blob() may fail to load icon.png or icon.jpg if image dimensions are too large.

The issue is discovered by https://github.com/Sergei768
2026-09-04 10:05:25 +00:00
link2xt a516829171 feat: remove Final-Recipient from MDNs (and keyupdates)
This Final-Recipient was not set to the correct value anyway.
We could query the database and find out via `imap` table
which transport we have received the message on,
but it is not worth the effort as the field is not practically used
and cannot be relied on as old versions still send incorrect value.

This removes one call to get_primary_self_addr()
to make it easier to remove the concept of the "primary"
address eventually.
2026-09-03 16:45:03 +00:00
link2xt 5ebab3d859 fix: remove Original-Recipient field from MDNs
According to
<https://datatracker.ietf.org/doc/html/rfc8098#section-3.2.3>
Original-Recipient field values in MDNs MUST NOT be included
if the information about original recipient is not available.
Original recipient may be obtained from ORCPT parameter
of SMTP envelope or from Original-Recipient header
which MTAs are expected to convert Original-Recipient to.

The way we have been using Original-Recipient field is not correct. 
Technically we should look for Original-Recipient header
on the message when downloading it from IMAP
and then copy the value into MDN,
but simply assuming it is never there is more correct
than always assuming it is the same as our current address.

I also grepped for Original-Recipient
and removed it together with Reporting-UA from the tests.
Orignal-Recipient is now only left in NDN (bounce messages) test data,
there it is correct as this field is added by MTAs
that have direct access to ORCPT parameter.
2026-09-03 16:45:03 +00:00
link2xt 77dd9075ca chore(cargo): bump mail-builder from 0.4.4 to 0.5.0 2026-09-02 21:35:13 +00:00
link2xt 0b0398561d fix: do not emit events in set_profile_image() if contact avatar is unchanged
Previously `changed` variable was always set to `true`.
2026-09-02 20:51:51 +00:00
link2xt 3ff8011676 refactor: remove the code to set own avatar in set_profile_image()
This code remains from the time when we have synchronized the avatar
between devices by looking at outgoing messages.
2026-09-02 20:51:51 +00:00
link2xt 38d6cf2bcd feat: import Autocrypt-Gossip keys without checking the addresses
It is safe to import any keys into the keychain.
Keys can anyway be imported from vCards
and Autocrypt headers without any checks.

These checks are from the time before we had key-contacts
and maintained Autocrypt `peerstates` table.
2026-09-02 20:51:15 +00:00
link2xt 46d45faf7e refactor: remove unused functions from the tools module
Also marked functions that are not used outside as pub(crate).
Some functions like get_filesuffix_lc() are still used
by deltachat-repl, so the whole module cannot be made private.
2026-09-01 17:12:38 +00:00
link2xt 4d5ebe9ff4 feat: delete avatars referred to by parameters of special contacts
It is not clear if old versions stored SELF avatar in parameters
or if it happened due to a bug, but if it happens,
we can safely delete the avatar.

get_profile_image_ext() is refactored to make it
not try to load avatars for any special contacts.
2026-08-29 16:50:50 +00:00
link2xt 322dd11d99 docs: update the timeout value in DC_EVENT_CALL_ENDED description
RINGING_SECONDS constant was changed in 3d234e7fc7,
but the documentation was not updated.
2026-08-28 17:47:43 +00:00
link2xt 693c404266 fix: do not try to load profile image from param for self
I have an old profile which has ProfileImage param
set on the reserved SELF contact.  When I deleted
an avatar from the profile, very old profile image
showed up in the settings in Delta Chat Desktop instead,
which can be "deleted" again without any result.

This fix is to return `None` early from get_profile_image_ext
for self contact without trying to load the parameter.
Fallthrough to loading params was likely there
since keycontacts and grey avatars for address contacts
introduction in 416131b4a2
2026-08-27 21:44:45 +00:00
link2xt 9a33555604 test: test dc_send_msg_sync() 2026-08-26 20:22:57 +00:00
link2xt 3af45c306a fix: make create_send_msg_jobs actually return row IDs
.execute() was returning the number of rows, so usually 1.
.insert() is returning the row ID.

In most cases it does not matter because the result is checked with .is_empty(),
but send_msg_sync() actually uses the row IDs.
2026-08-26 20:22:57 +00:00
link2xt 709c56a889 refactor: make create_send_msg_jobs() private
It is not called from outside the "chat" module.
2026-08-26 20:22:57 +00:00
link2xt 7421e67ab6 feat: do not create device messages for IMAP authentication errors
Authentication failures may happen because of internal server errors.
Device message saying "Please check if the email address and the password are correct"
was written for classic email setups when the user knows the password.
For users of chatmail relays this message is not actionable,
but still appears when relay fails to check the password.
2026-08-26 13:53:02 +00:00
link2xt 6c47e86380 refactor: turn DC_MSG_ID_* into MsgId::* associated constants 2026-08-22 20:21:20 +00:00
link2xt fe25e93d6c refactor: turn DC_CHAT_ID_* into ChatId::* associated constants
We already have it done for ContactId.
2026-08-22 20:21:20 +00:00
link2xt 0b2ff5d0e2 fix: take timestamp_rcvd into account in estimate_deletion_cnt
This did not affect actual message deletion,
because select_expired_messages already takes timestamp_rcvd
into account and does not delete system messages
that say "Messages are end-to-end encrypted" too early.

So it is a minor bug as estimate_deletion_cnt
is meant to only roughly estimate the number of messages
to be deleted. Still, there were no tests before,
so now estimate_deletion_cnt is tested.
2026-08-22 20:21:20 +00:00
link2xt d2286254b3 ci: update Rust to 1.98.0 2026-08-22 12:52:12 +00:00
link2xt 3df1e3712a fix: send legacy securejoin key requests as multipart/mixed
chatmail relays (filtermail) expect {vc,vg}-request
messages to be multipart/mixed with a single part.
Messages had this structure
before commit e0494b0b37
so we need to keep it for compatibility.
2026-08-20 20:31:27 +00:00
link2xt f09f8fd8a4 docs: always suggest using --locked with "cargo install"
Otherwise the lockfile is completely ignored
as <https://doc.rust-lang.org/cargo/commands/cargo-install.html#dealing-with-the-lockfile>
says "By default, the Cargo.lock file that is included with the package will be ignored."

Mostly a reaction to <https://blog.rust-lang.org/2026/08/20/supply-chain-attack-on-arrayref/>
2026-08-20 16:00:15 +00:00
link2xt 357c6e74d5 build: use --locked in scripts/clippy.sh
This is mostly a reaction in response to
https://blog.rust-lang.org/2026/08/20/supply-chain-attack-on-arrayref/

I don't know when exactly
`cargo clippy` and similar commands (check, build, run etc.)
may update dependencies
and it does not look like they actively pull
the package index and update yanked crates.
We also keep the lockfile updated all the time
by checking in CI.

Still, all commands better use --locked as a precaution.
2026-08-20 14:52:32 +00:00
link2xt aa95d87568 chore: bump version to 2.60.0-dev 2026-08-14 12:02:17 +00:00
link2xt e322fdf157 chore(release): prepare for 2.59.0 2026-08-14 11:59:48 +00:00
link2xt 3dce06b02b refactor(mimefactory): add Encryption enum
This replaces independent data structures
which allowed invalid state of having both the public keys
and the shared secret, or having a shared secret
but not encrypting the message because encryption_pubkeys
was None instead of Some(Vec::new()).
2026-08-14 11:32:33 +00:00
link2xt 40faf829d3 feat: stop creating info messages for old broadcast lists
Creating QR code or sending a message will still fail
with a shorter error, but no info message will be created anymore.
Most users should have migrated the channels by recreating them by now.

This change is needed for moving loading of the shared secret
to earlier stages of message preparation,
otherwise mimefactory will have to create these info messages
when loading the message into memory.
2026-08-14 11:32:33 +00:00
link2xt e0494b0b37 feat: remove hidden headers
Unencrypted messages are no longer sent as multipart/mixed
with Message-ID header duplicated inside.
This was useful as non-standard protection
against servers that rewrite the Message-ID,
but now most messages are sent encrypted
and for them standard RFC 9788 header protection
works the same way.
2026-08-14 07:09:49 +00:00
link2xtandbiørn 31c37848ec docs: add SQL schema documentation
There is currently no place to document up to date SQL schema.
New database is initialized with src/sql/tables.sql
and then updated by migrations,
So tracking down how some column is used requires grepping the code,
looking for a migration adding it and corresponding commits.

Co-Authored-By: biørn <r10s@b44t.com>
2026-08-13 12:07:15 +00:00
link2xt ec4d195814 fix: send MDNs to self even if MDNs are disabled
MDNs to self are used for seen status synhronization between devices.
2026-08-13 11:36:50 +00:00
link2xt e2b0eb1fb9 chore: fix nightly clippy warnings 2026-08-12 20:56:33 +00:00
link2xt 292bd9f58d docs: do not talk about verified chats in securejoin QR-scanning functions
The chat is always going to be encrypted, this is enough.
We actually do mark the contact as verified,
but the meaning of this verification is unclear
and we don't even display it visibly in the chat anymore.
2026-08-12 19:28:32 +00:00
link2xt 998892395a docs: do not refer to is_chat_protected()
is_chat_protected() does not exist anymore.
2026-08-12 19:28:32 +00:00
link2xt 9f5fbcdcae api!: remove deprecated dc_chat_is_protected() 2026-08-12 19:28:32 +00:00
link2xt d89a972a2c refactor: stop setting chats.protected column explicitly
It is not used anymore and has a default value of 0.
2026-08-12 19:28:32 +00:00
link2xt ae5b27fb69 refactor: remove MessengerMessage
This value is not used for any logic
except the disappearing messages timer rollback prevention.
It is unlikely that non-chat clients
participate in chats with disappearing messages,
and the case was not tested anyway.
2026-08-12 07:44:38 +00:00
link2xt c3563f73e4 chore: bump version to 2.59.0-dev 2026-08-11 03:07:37 +00:00
link2xt 7990e17859 refactor(mimefactory): separate rendering of message payload and sendable message
This change separates rendering into two separate steps:
1. Rendering of the message payload without the From, Date and Autocrypt headers.
2. Adding the From, Date and Autocrypt headers and possibly encrypting the message.

The goal is to have serializable result of the first step
that can be persisted in the database and sent later with any email address.
This way it will be possible to send queued messages over any relay.

This will make it possible not to remove all messages from the queue
when the sending relay is changed.
Currently changing `configured_addr` deletes everything from `smtp` table.

This change is however only a refactoring and does not implement any features.
2026-08-04 11:57:57 +00:00
link2xt 2ac217ddd4 feat: send messages to 5 relays instead of the newest 3 ones
Otherwise users may add up to 5 relays, but 2 oldest relays
are actually ignored.

Having the maximum number of published relays
and the number of relays used the same between all clients
makes the order of relays in the key irrelevant.
We may even remove sorting by `add_timestamp`
from `get_all_self_addrs()` in the future.
2026-08-03 14:04:15 +00:00
link2xt 8e60ed7d89 perf: Box::pin iroh::endpoint::Builder::bind
It is has a size of 13k and increases the size of all futures calling it as a result,
while only being used for initialization.
2026-08-03 13:54:49 +00:00
link2xt fab974f31e feat: collect ICE servers from all relays 2026-08-03 13:38:40 +00:00
link2xt 99d202a973 api(ffi): store reference-counted Context in dc_chatlist_t 2026-08-02 17:22:56 +00:00
link2xt ae02b6dcfc api!: remove dc_chatlist_get_context()
This API is dangerous because returned pointer
is only valid until the chatlist is freed,
and may accidentally be passed into dc_context_unref().
2026-08-02 17:22:56 +00:00
link2xt e1f5858fa3 api(ffi): store reference-counted Context in dc_contact_t 2026-08-02 17:22:56 +00:00
link2xt abfc1b9a76 api(ffi): store reference-counted Context in dc_msg_t
The change is similar to the change done to dc_chat_t
in b5acbaa31c
2026-08-02 17:22:56 +00:00
link2xt 057d6c0c5e refactor: reduce the scope of unsafe in dc_context_unref() 2026-08-02 17:09:56 +00:00
link2xt cf5f87c81b chore(cargo): introduce syn 3 dependency
It is now used by at the latest versions of anyhow and thiserror,
so we will eventually have this duplicate dependency anyway.
2026-08-02 02:31:45 +00:00
link2xt 62d3f3877f refactor: mark enabled ephemeral timer duration as NonZero
Now the type system ensures that Timer::Enabled
never stores 0 value inside accidentally,
it is impossible to put 0 there without unsafe code.
2026-07-31 23:55:49 +00:00
link2xt fb4fdeb470 fix(python): create event emitter when EventThread is initialized
EventThread is created in Account.__init__,
but the thread start may be scheduled later.
If the thread only cals dc_get_event_emitter()
after some events have been emitted,
EventThread will never capture such events
and the tests will timeout waiting for the event.

This happened in CI on a Linux runner
with test_markseen_invalid_message_ids
timing out waiting for DC_EVENT_MSGS_CHANGED
right after sending a message.
2026-07-31 23:20:17 +00:00
link2xt 3d50f3c9a3 refactor: do not clean imap_send table on transport change
imap_send table is not unused anymore
and should eventually be deleted.
It only exists for compatibility
and no other SQL statements use it anymore.
2026-07-30 16:54:04 +00:00
link2xt e74ffb6e93 docs: add missing slash to ConnectionSecurity::Starttls doc comment 2026-07-29 23:50:59 +00:00
link2xt bbcfa5e40e chore: disable "large futures" lint again
The lint is reasonable, but without some work
to bring the future sizes way below the limit,
this lint is frequently triggered in unrelated PRs
that just add some local variables to async functions
or extend some structure that is passed on the stack.
2026-07-29 00:47:39 +00:00
link2xt 733bec326a fix: mark as_path() function unsafe 2026-07-27 23:48:11 +00:00
link2xt 2d7af15124 build: update all crates to Rust 2024 edition
Largest change is in the FFI crate.
With 2024 (but not 2021) edition unsafe code
inside unsafe functions should be marked separately
so we can mark exactly the code that is unsafe.
Some CFFI functions even have no unsafe code inside.

Most interesting change is that .strdup()
functions are not marked as unsafe anymore.
They are allocating memory and return raw pointers,
but there is nothing unsafe about it.
Only using the returned raw pointers is unsafe.
This way calls to .strdup() don't have to be marked
with unsafe{} blocks.
2026-07-27 23:48:11 +00:00
link2xt 850ac0831f refactor: use the new regex! macro
It was introduced in regex crate 1.13.0
2026-07-26 13:21:40 +00:00
link2xt 55ede9f2f6 ci: update github actions monthly instead of weekly 2026-07-25 14:21:44 +00:00
link2xt 234e491172 fix: never merge outer To headers if standard header protection is used 2026-07-24 11:59:59 +00:00
link2xt 3a913dfb07 feat: enable TLS certificate compression
Enabling brotli does not add new dependencies,
we have it already.
Documentation at <https://docs.rs/rustls/0.23.42/rustls/compress/>
recommends enabling at least brotli.

zlib feature is not enabled as it pulls in duplicate zlib-rs 0.6.6
zlib was even never supported in Chromium (while brotli is).
It might still be interesting to enable it in the future
because it seems to be the only option supported by OpenSSL
and there may be servers that support zlib but not brotli.

RFC 8879 specifies zstd as well, but there is no feature to enable it yet.

This also brings back explicit TLS 1.2 feature that was reverted.
We don't want TLS 1.2 support to be accidentally dropped
if no dependencies explicitly require it anymore.
2026-07-22 14:03:36 +00:00
link2xt bdd9d96844 feat: accept messages from key contacts with forged From address
From address is not used for key contacts
other than as the address to send replies to.
2026-07-21 19:59:32 +00:00
link2xt 8c53f86fbc chore: bump version to 2.57.0-dev 2026-07-21 19:35:26 +00:00
link2xt 1721c0316a feat: do not set backup_time in exported databases
backup_time is unused, it is only set, but nobody reads it.
2026-07-21 12:02:39 +00:00
link2xt 35d7b4e21c chore(release): prepare for 2.55.0 2026-07-20 18:47:28 +00:00
link2xt 03725c5f32 ci: update Node version to 24
https://docs.npmjs.com/trusted-publishers recommends node-version 24
and not updating npm separately, this change copies the recommended configuration.

Also update node version to 24 in non-release workflows, version 18 is EOL.
There is a version 26 already, but 24 is LTS.

Also disable cache for release pipelines.
2026-07-20 17:39:13 +00:00
link2xt a0c96f4ce1 chore: bump version to 2.55.0-dev 2026-07-20 15:20:53 +00:00
link2xt b432d08aa8 chore(release): prepare for 2.54.0 2026-07-20 14:57:57 +00:00
link2xt ebd1c20997 fix: do not log errors if full message is not available on any transport
Before this change "Err" case spams the logs with
"Failed to download message rfc724_mid=...: IMAP location for ... post-message is unknown."
logged by every transports when the message is not available on any transport.
2026-07-20 09:50:27 +00:00
link2xt aadd11a771 feat(imap): use CAPABILITY response code if LOGIN command returns it
This saves one round trip during connection establishment
if the server returns capabilities in the LOGIN command response already.
2026-07-17 21:36:45 +00:00