mirror of
https://github.com/chatmail/core.git
synced 2026-10-16 18:03:01 +03:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d31be3165 |
@@ -139,12 +139,12 @@ jobs:
|
||||
- name: Tests
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
run: cargo nextest run --workspace --locked
|
||||
run: cargo nextest run --workspace
|
||||
|
||||
- name: Doc-Tests
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
run: cargo test --workspace --locked --doc
|
||||
run: cargo test --workspace --doc
|
||||
|
||||
- name: Test cargo vendor
|
||||
run: cargo vendor
|
||||
|
||||
@@ -24,7 +24,10 @@ jobs:
|
||||
show-progress: false
|
||||
persist-credentials: false
|
||||
- uses: DeterminateSystems/nix-installer-action@main
|
||||
- run: nix fmt flake.nix -- --check
|
||||
- run: nix fmt
|
||||
|
||||
# Check that formatting does not change anything.
|
||||
- run: git diff --exit-code
|
||||
|
||||
build:
|
||||
name: nix build
|
||||
|
||||
+5
-47
@@ -1,46 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## [2.17.0] - 2025-10-04
|
||||
|
||||
### API-Changes
|
||||
|
||||
- [**breaking**] Remove deprecated verified_one_on_one_chats config.
|
||||
|
||||
### CI
|
||||
|
||||
- Require that Cargo.lock is up to date.
|
||||
- Fix CI checking Nix formatting.
|
||||
|
||||
### Documentation
|
||||
|
||||
- Comment about outdated timespan.
|
||||
- Clarify CALL events ([#7188](https://github.com/chatmail/core/pull/7188)).
|
||||
- Add docs for JS `BaseDeltaChat`.
|
||||
|
||||
### Features / Changes
|
||||
|
||||
- Make `text/calendar` alternative available as an attachment.
|
||||
- Better summary for calls.
|
||||
- Add strings 'You left the channel.' and 'Scan to join Channel' ([#7266](https://github.com/chatmail/core/pull/7266)).
|
||||
- Stock strings for calls.
|
||||
- ffi: Add DC_STR_CANT_DECRYPT_OUTGOING_MSGS define.
|
||||
|
||||
### Fixes
|
||||
|
||||
- Prefer last part in `multipart/alternative`.
|
||||
- Prefetch messages in limited batches ([#6915](https://github.com/chatmail/core/pull/6915)).
|
||||
- Forward calls as text messages.
|
||||
- Consistent spelling of "canceled" with a single "l".
|
||||
- Lowercase "call" in "Missed call" and similar strings.
|
||||
|
||||
### Refactor
|
||||
|
||||
- Return the reason when failing to place calls.
|
||||
|
||||
### Tests
|
||||
|
||||
- Test reception of `multipart/alternative` with `text/calendar`.
|
||||
|
||||
## [2.16.0] - 2025-10-01
|
||||
|
||||
### API-Changes
|
||||
@@ -1805,7 +1764,7 @@ This reverts commit 6f22ce2722b51773d7fbb0d89e4764f963cafd91..
|
||||
### Fixes
|
||||
|
||||
- Reset quota on configured address change ([#5908](https://github.com/chatmail/core/pull/5908)).
|
||||
- Do not emit progress 1000 when configuration is canceled.
|
||||
- Do not emit progress 1000 when configuration is cancelled.
|
||||
- Assume file extensions are 32 chars max and don't contain whitespace ([#5338](https://github.com/chatmail/core/pull/5338)).
|
||||
- Re-add tokens.foreign_id column ([#6038](https://github.com/chatmail/core/pull/6038)).
|
||||
|
||||
@@ -4253,7 +4212,7 @@ Bugfix release attempting to fix the [iOS build error](https://github.com/chatma
|
||||
- Recreate `smtp` table with AUTOINCREMENT `id` ([#4390](https://github.com/chatmail/core/pull/4390)).
|
||||
- Do not return an error from `send_msg_to_smtp` if retry limit is exceeded.
|
||||
- Make the bots automatically accept group chat contact requests ([#4377](https://github.com/chatmail/core/pull/4377)).
|
||||
- Delete `smtp` rows when message sending is canceled ([#4391](https://github.com/chatmail/core/pull/4391)).
|
||||
- Delete `smtp` rows when message sending is cancelled ([#4391](https://github.com/chatmail/core/pull/4391)).
|
||||
|
||||
### Refactor
|
||||
|
||||
@@ -4264,7 +4223,7 @@ Bugfix release attempting to fix the [iOS build error](https://github.com/chatma
|
||||
### Fixes
|
||||
|
||||
- Fetch at most 100 existing messages even if EXISTS was not received.
|
||||
- Delete `smtp` rows when message sending is canceled.
|
||||
- Delete `smtp` rows when message sending is cancelled.
|
||||
|
||||
### Changes
|
||||
|
||||
@@ -4351,14 +4310,14 @@ Bugfix release attempting to fix the [iOS build error](https://github.com/chatma
|
||||
## [1.112.3] - 2023-03-30
|
||||
|
||||
### Fixes
|
||||
- `transfer::get_backup` now frees ongoing process when canceled. #4249
|
||||
- `transfer::get_backup` now frees ongoing process when cancelled. #4249
|
||||
|
||||
## [1.112.2] - 2023-03-30
|
||||
|
||||
### Changes
|
||||
- Update iroh, remove `default-net` from `[patch.crates-io]` section.
|
||||
- transfer backup: Connect to multiple provider addresses concurrently. This should speed up connection time significantly on the getter side. #4240
|
||||
- Make sure BackupProvider is canceled on drop (or `dc_backup_provider_unref`). The BackupProvider will now always finish with an IMEX event of 1000 or 0, previously it would sometimes finished with 1000 (success) when it really was 0 (failure). #4242
|
||||
- Make sure BackupProvider is cancelled on drop (or `dc_backup_provider_unref`). The BackupProvider will now always finish with an IMEX event of 1000 or 0, previously it would sometimes finished with 1000 (success) when it really was 0 (failure). #4242
|
||||
|
||||
### Fixes
|
||||
- Do not return media from trashed messages in the "All media" view. #4247
|
||||
@@ -6856,4 +6815,3 @@ https://github.com/chatmail/core/pulls?q=is%3Apr+is%3Aclosed
|
||||
[2.14.0]: https://github.com/chatmail/core/compare/v2.13.0..v2.14.0
|
||||
[2.15.0]: https://github.com/chatmail/core/compare/v2.14.0..v2.15.0
|
||||
[2.16.0]: https://github.com/chatmail/core/compare/v2.15.0..v2.16.0
|
||||
[2.17.0]: https://github.com/chatmail/core/compare/v2.16.0..v2.17.0
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ If you want to contribute a code, follow this guide.
|
||||
|
||||
The following prefix types are used:
|
||||
- `feat`: Features, e.g. "feat: Pause IO for BackupProvider". If you are unsure what's the category of your commit, you can often just use `feat`.
|
||||
- `fix`: Bug fixes, e.g. "fix: delete `smtp` rows when message sending is canceled"
|
||||
- `fix`: Bug fixes, e.g. "fix: delete `smtp` rows when message sending is cancelled"
|
||||
- `api`: API changes, e.g. "api(rust): add `get_msg_read_receipts(context, msg_id)`"
|
||||
- `refactor`: Refactorings, e.g. "refactor: iterate over `msg_ids` without `.iter()`"
|
||||
- `perf`: Performance improvements, e.g. "perf: improve SQLite performance with `PRAGMA synchronous=normal`"
|
||||
|
||||
Generated
+8
-8
@@ -1289,7 +1289,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat"
|
||||
version = "2.17.0"
|
||||
version = "2.16.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-broadcast",
|
||||
@@ -1399,7 +1399,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat-jsonrpc"
|
||||
version = "2.17.0"
|
||||
version = "2.16.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-channel 2.5.0",
|
||||
@@ -1421,7 +1421,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat-repl"
|
||||
version = "2.17.0"
|
||||
version = "2.16.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"deltachat",
|
||||
@@ -1437,7 +1437,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat-rpc-server"
|
||||
version = "2.17.0"
|
||||
version = "2.16.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"deltachat",
|
||||
@@ -1466,7 +1466,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat_ffi"
|
||||
version = "2.17.0"
|
||||
version = "2.16.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"deltachat",
|
||||
@@ -5289,11 +5289,11 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "sdp"
|
||||
version = "0.8.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd277015eada44a0bb810a4b84d3bf6e810573fa62fb442f457edf6a1087a69"
|
||||
checksum = "32c374dceda16965d541c8800ce9cc4e1c14acfd661ddf7952feeedc3411e5c6"
|
||||
dependencies = [
|
||||
"rand 0.8.5",
|
||||
"rand 0.9.0",
|
||||
"substring",
|
||||
"thiserror 1.0.69",
|
||||
"url",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat"
|
||||
version = "2.17.0"
|
||||
version = "2.16.0"
|
||||
edition = "2024"
|
||||
license = "MPL-2.0"
|
||||
rust-version = "1.85"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat_ffi"
|
||||
version = "2.17.0"
|
||||
version = "2.16.0"
|
||||
description = "Deltachat FFI"
|
||||
edition = "2018"
|
||||
readme = "README.md"
|
||||
|
||||
+18
-72
@@ -1222,7 +1222,7 @@ uint32_t dc_init_webxdc_integration (dc_context_t* context, uint32_t c
|
||||
* Possible actions during ringing:
|
||||
*
|
||||
* - caller cancels the call using dc_end_call():
|
||||
* callee receives #DC_EVENT_CALL_ENDED and has a "Missed call"
|
||||
* callee receives #DC_EVENT_CALL_ENDED and has a "Missed Call"
|
||||
*
|
||||
* - callee accepts using dc_accept_incoming_call():
|
||||
* caller receives #DC_EVENT_OUTGOING_CALL_ACCEPTED.
|
||||
@@ -1230,20 +1230,19 @@ uint32_t dc_init_webxdc_integration (dc_context_t* context, uint32_t c
|
||||
*
|
||||
* - callee declines using dc_end_call():
|
||||
* caller receives #DC_EVENT_CALL_ENDED and has a "Declinced Call".
|
||||
* callee's other devices receive #DC_EVENT_CALL_ENDED and have a "Canceled Call",
|
||||
* callee's other devices receive #DC_EVENT_CALL_ENDED and have a "Cancelled Call",
|
||||
*
|
||||
* - callee is already in a call:
|
||||
* what to do depends on the capabilities of UI to handle calls.
|
||||
* if UI cannot handle multiple calls, an easy approach would be to decline the new call automatically
|
||||
* and make that visble to the user in the call, e.g. by a notification
|
||||
* in this case, UI may decide to show a notification instead of ringing.
|
||||
* otherwise, this is same as timeout
|
||||
*
|
||||
* - timeout:
|
||||
* after 1 minute without action,
|
||||
* caller and callee receive #DC_EVENT_CALL_ENDED
|
||||
* to prevent endless ringing of callee
|
||||
* in case caller got offline without being able to send cancellation message.
|
||||
* for caller, this is a "Canceled call";
|
||||
* for callee, this is a "Missed call"
|
||||
* for caller, this is a "Cancelled Call";
|
||||
* for callee, this is a "Missed Call"
|
||||
*
|
||||
* Actions during the call:
|
||||
*
|
||||
@@ -1253,13 +1252,6 @@ uint32_t dc_init_webxdc_integration (dc_context_t* context, uint32_t c
|
||||
* - callee ends the call using dc_end_call():
|
||||
* caller receives #DC_EVENT_CALL_ENDED
|
||||
*
|
||||
* Contact request handling:
|
||||
*
|
||||
* - placing or accepting calls implies accepting contact requests
|
||||
*
|
||||
* - ending a call does not accept a contact request;
|
||||
* instead, the call will timeout on all affected devices.
|
||||
*
|
||||
* Note, that the events are for updating the call screen,
|
||||
* possible status messages are added and updated as usual, including the known events.
|
||||
* In the UI, the sorted chatlist is used as an overview about calls as well as messages.
|
||||
@@ -1287,7 +1279,6 @@ uint32_t dc_place_outgoing_call (dc_context_t* context, uint32_t ch
|
||||
* either #DC_EVENT_OUTGOING_CALL_ACCEPTED or #DC_EVENT_INCOMING_CALL_ACCEPTED.
|
||||
*
|
||||
* If the call is already accepted or ended, nothing happens.
|
||||
* If the chat is a contact request, it is accepted implicitly.
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object.
|
||||
@@ -1308,12 +1299,7 @@ uint32_t dc_place_outgoing_call (dc_context_t* context, uint32_t ch
|
||||
* Unaccepted calls ended by the callee are a "decline".
|
||||
* If the call was accepted, this is a "hangup".
|
||||
*
|
||||
* All participant devices get informed about the ended call via #DC_EVENT_CALL_ENDED unless they are contact requests.
|
||||
* For contact requests, the call times out on all other affected devices.
|
||||
*
|
||||
* If the message ID is wrong or does not exist for whatever reasons, nothing happens.
|
||||
* Therefore, and for resilience, UI should remove the call UI directly when calling
|
||||
* this function and not only on the event.
|
||||
* All participant devices get informed about the ended call via #DC_EVENT_CALL_ENDED.
|
||||
*
|
||||
* If the call is already ended, nothing happens.
|
||||
*
|
||||
@@ -5728,18 +5714,6 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
|
||||
/**
|
||||
* Message indicating an incoming or outgoing call.
|
||||
*
|
||||
* These messages are created by dc_place_outgoing_call()
|
||||
* and should be rendered by UI similar to text messages,
|
||||
* maybe with some "phone icon" at the side.
|
||||
*
|
||||
* The message text is updated as needed
|
||||
* and UI will be informed via #DC_EVENT_MSGS_CHANGED as usual.
|
||||
*
|
||||
* Do not start ringing when seeing this message;
|
||||
* the mesage may belong e.g. to an old missed call.
|
||||
*
|
||||
* Instead, ringing should start on the event #DC_EVENT_INCOMING_CALL
|
||||
*/
|
||||
#define DC_MSG_CALL 71
|
||||
|
||||
@@ -6747,8 +6721,7 @@ void dc_event_unref(dc_event_t* event);
|
||||
*
|
||||
* Together with this event,
|
||||
* a message of type #DC_MSG_CALL is added to the corresponding chat;
|
||||
* this message is announced and updated by the usual event as #DC_EVENT_MSGS_CHANGED,
|
||||
* there is usually no need to take care of this message from any of the CALL events.
|
||||
* this message is announced and updated by the usual even as #DC_EVENT_MSGS_CHANGED.
|
||||
*
|
||||
* If user takes action, dc_accept_incoming_call() or dc_end_call() should be called.
|
||||
*
|
||||
@@ -6765,7 +6738,8 @@ void dc_event_unref(dc_event_t* event);
|
||||
* The callee accepted an incoming call on this or another device using dc_accept_incoming_call().
|
||||
* The caller gets the event #DC_EVENT_OUTGOING_CALL_ACCEPTED at the same time.
|
||||
*
|
||||
* UI usually only takes action in case call UI was opened before, otherwise the event should be ignored.
|
||||
* The event is sent unconditionally when the corresponding message is received.
|
||||
* UI should only take action in case call UI was opened before, otherwise the event should be ignored.
|
||||
*
|
||||
* @param data1 (int) msg_id ID of the message referring to the call
|
||||
*/
|
||||
@@ -6774,7 +6748,8 @@ void dc_event_unref(dc_event_t* event);
|
||||
/**
|
||||
* A call placed using dc_place_outgoing_call() was accepted by the callee using dc_accept_incoming_call().
|
||||
*
|
||||
* UI usually only takes action in case call UI was opened before, otherwise the event should be ignored.
|
||||
* The event is sent unconditionally when the corresponding message is received.
|
||||
* UI should only take action in case call UI was opened before, otherwise the event should be ignored.
|
||||
*
|
||||
* @param data1 (int) msg_id ID of the message referring to the call
|
||||
* @param data2 (char*) accept_call_info, text passed to dc_accept_incoming_call()
|
||||
@@ -6782,10 +6757,11 @@ void dc_event_unref(dc_event_t* event);
|
||||
#define DC_EVENT_OUTGOING_CALL_ACCEPTED 2570
|
||||
|
||||
/**
|
||||
* An incoming or outgoing call was ended using dc_end_call() on this or another device, by caller or callee.
|
||||
* An incoming or outgoing call was ended using dc_end_call().
|
||||
* Moreover, the event is sent when the call was not accepted within 1 minute timeout.
|
||||
*
|
||||
* UI usually only takes action in case call UI was opened before, otherwise the event should be ignored.
|
||||
* The event is sent unconditionally when the corresponding message is received.
|
||||
* UI should only take action in case call UI was opened before, otherwise the event should be ignored.
|
||||
*
|
||||
* @param data1 (int) msg_id ID of the message referring to the call
|
||||
*/
|
||||
@@ -7585,7 +7561,7 @@ void dc_event_unref(dc_event_t* event);
|
||||
/// Used in status messages.
|
||||
#define DC_STR_REMOVE_MEMBER_BY_OTHER 131
|
||||
|
||||
/// "You left the group."
|
||||
/// "You left."
|
||||
///
|
||||
/// Used in status messages.
|
||||
#define DC_STR_GROUP_LEFT_BY_YOU 132
|
||||
@@ -7808,12 +7784,6 @@ void dc_event_unref(dc_event_t* event);
|
||||
/// `%1$s` will be replaced by the provider's domain.
|
||||
#define DC_STR_INVALID_UNENCRYPTED_MAIL 174
|
||||
|
||||
/// "⚠️ It seems you are using Delta Chat on multiple devices that cannot decrypt each other's outgoing messages. To fix this, on the older device use \"Settings / Add Second Device\" and follow the instructions."
|
||||
///
|
||||
/// Added to the device chat if could not decrypt a new outgoing message (i.e. not when fetching
|
||||
/// existing messages). But no more than once a day.
|
||||
#define DC_STR_CANT_DECRYPT_OUTGOING_MSGS 175
|
||||
|
||||
/// "You reacted %1$s to '%2$s'"
|
||||
///
|
||||
/// `%1$s` will be replaced by the reaction, usually an emoji
|
||||
@@ -7850,32 +7820,8 @@ void dc_event_unref(dc_event_t* event);
|
||||
/// "❤️ Seems you're enjoying Delta Chat!"… (donation request device message)
|
||||
#define DC_STR_DONATION_REQUEST 193
|
||||
|
||||
/// "Outgoing call"
|
||||
#define DC_STR_OUTGOING_CALL 194
|
||||
|
||||
/// "Incoming call"
|
||||
#define DC_STR_INCOMING_CALL 195
|
||||
|
||||
/// "Declined call"
|
||||
#define DC_STR_DECLINED_CALL 196
|
||||
|
||||
/// "Canceled call"
|
||||
#define DC_STR_CANCELED_CALL 197
|
||||
|
||||
/// "Missed call"
|
||||
#define DC_STR_MISSED_CALL 198
|
||||
|
||||
/// "You left the channel."
|
||||
///
|
||||
/// Used in status messages.
|
||||
#define DC_STR_CHANNEL_LEFT_BY_YOU 200
|
||||
|
||||
/// "Scan to join channel %1$s"
|
||||
///
|
||||
/// Subtitle for channel join qrcode svg image generated by the core.
|
||||
///
|
||||
/// `%1$s` will be replaced with the channel name.
|
||||
#define DC_STR_SECURE_JOIN_CHANNEL_QR_DESC 201
|
||||
/// "Contact". Deprecated, currently unused.
|
||||
#define DC_STR_CONTACT 200
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat-jsonrpc"
|
||||
version = "2.17.0"
|
||||
version = "2.16.0"
|
||||
description = "DeltaChat JSON-RPC API"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
|
||||
@@ -1809,13 +1809,13 @@ impl CommandApi {
|
||||
|
||||
/// Offers a backup for remote devices to retrieve.
|
||||
///
|
||||
/// Can be canceled by stopping the ongoing process. Success or failure can be tracked
|
||||
/// Can be cancelled by stopping the ongoing process. Success or failure can be tracked
|
||||
/// via the `ImexProgress` event which should either reach `1000` for success or `0` for
|
||||
/// failure.
|
||||
///
|
||||
/// This **stops IO** while it is running.
|
||||
///
|
||||
/// Returns once a remote device has retrieved the backup, or is canceled.
|
||||
/// Returns once a remote device has retrieved the backup, or is cancelled.
|
||||
async fn provide_backup(&self, account_id: u32) -> Result<()> {
|
||||
let ctx = self.get_context(account_id).await?;
|
||||
|
||||
@@ -1881,7 +1881,7 @@ impl CommandApi {
|
||||
/// This retrieves the backup from a remote device over the network and imports it into
|
||||
/// the current device.
|
||||
///
|
||||
/// Can be canceled by stopping the ongoing process.
|
||||
/// Can be cancelled by stopping the ongoing process.
|
||||
///
|
||||
/// Do not forget to call start_io on the account after a successful import,
|
||||
/// otherwise it will not connect to the email server.
|
||||
|
||||
@@ -20,7 +20,7 @@ pub struct JsonrpcCallInfo {
|
||||
|
||||
/// Call state.
|
||||
///
|
||||
/// For example, if the call is accepted, active, canceled, declined etc.
|
||||
/// For example, if the call is accepted, active, cancelled, declined etc.
|
||||
pub state: JsonrpcCallState,
|
||||
}
|
||||
|
||||
@@ -68,13 +68,13 @@ pub enum JsonrpcCallState {
|
||||
/// that was declined before the timeout.
|
||||
Declined,
|
||||
|
||||
/// Outgoing call that has been canceled on our side
|
||||
/// Outgoing call that has been cancelled on our side
|
||||
/// before receiving a response.
|
||||
///
|
||||
/// Incoming calls cannot be canceled,
|
||||
/// on the receiver side canceled calls
|
||||
/// Incoming calls cannot be cancelled,
|
||||
/// on the receiver side cancelled calls
|
||||
/// usually result in missed calls.
|
||||
Canceled,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
impl JsonrpcCallState {
|
||||
@@ -87,7 +87,7 @@ impl JsonrpcCallState {
|
||||
CallState::Completed { duration } => JsonrpcCallState::Completed { duration },
|
||||
CallState::Missed => JsonrpcCallState::Missed,
|
||||
CallState::Declined => JsonrpcCallState::Declined,
|
||||
CallState::Canceled => JsonrpcCallState::Canceled,
|
||||
CallState::Cancelled => JsonrpcCallState::Cancelled,
|
||||
};
|
||||
|
||||
Ok(jsonrpc_call_state)
|
||||
|
||||
@@ -54,5 +54,5 @@
|
||||
},
|
||||
"type": "module",
|
||||
"types": "dist/deltachat.d.ts",
|
||||
"version": "2.17.0"
|
||||
"version": "2.16.0"
|
||||
}
|
||||
|
||||
@@ -35,10 +35,6 @@ export class BaseDeltaChat<
|
||||
|
||||
constructor(
|
||||
public transport: Transport,
|
||||
/**
|
||||
* Whether to start calling {@linkcode RawClient.getNextEvent}
|
||||
* and emitting the respective events on this class.
|
||||
*/
|
||||
startEventLoop: boolean,
|
||||
) {
|
||||
super();
|
||||
@@ -48,9 +44,6 @@ export class BaseDeltaChat<
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see the constructor's `startEventLoop`
|
||||
*/
|
||||
async eventLoop(): Promise<void> {
|
||||
while (true) {
|
||||
const event = await this.rpc.getNextEvent();
|
||||
@@ -69,17 +62,10 @@ export class BaseDeltaChat<
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@linkcode BaseDeltaChat.rpc.getAllAccounts} instead.
|
||||
*/
|
||||
async listAccounts(): Promise<T.Account[]> {
|
||||
return await this.rpc.getAllAccounts();
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience function to listen on events binned by `account_id`
|
||||
* (see {@linkcode RawClient.getAllAccounts}).
|
||||
*/
|
||||
getContextEvents(account_id: number) {
|
||||
if (this.contextEmitters[account_id]) {
|
||||
return this.contextEmitters[account_id];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat-repl"
|
||||
version = "2.17.0"
|
||||
version = "2.16.0"
|
||||
license = "MPL-2.0"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/chatmail/core"
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "deltachat-rpc-client"
|
||||
version = "2.17.0"
|
||||
version = "2.16.0"
|
||||
description = "Python client for Delta Chat core JSON-RPC interface"
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
||||
@@ -28,7 +28,9 @@ class ACFactory:
|
||||
|
||||
def get_unconfigured_account(self) -> Account:
|
||||
"""Create a new unconfigured account."""
|
||||
return self.deltachat.add_account()
|
||||
account = self.deltachat.add_account()
|
||||
account.set_config("verified_one_on_one_chats", "1")
|
||||
return account
|
||||
|
||||
def get_unconfigured_bot(self) -> Bot:
|
||||
"""Create a new unconfigured bot."""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat-rpc-server"
|
||||
version = "2.17.0"
|
||||
version = "2.16.0"
|
||||
description = "DeltaChat JSON-RPC server"
|
||||
edition = "2021"
|
||||
readme = "README.md"
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
},
|
||||
"type": "module",
|
||||
"types": "index.d.ts",
|
||||
"version": "2.17.0"
|
||||
"version": "2.16.0"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "deltachat"
|
||||
version = "2.17.0"
|
||||
version = "2.16.0"
|
||||
description = "Python bindings for the Delta Chat Core library using CFFI against the Rust-implemented libdeltachat"
|
||||
readme = "README.rst"
|
||||
requires-python = ">=3.8"
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2025-10-04
|
||||
2025-10-01
|
||||
+24
-28
@@ -46,9 +46,9 @@ const STUN_PORT: u16 = 3478;
|
||||
///
|
||||
/// It is used to distinguish "ended" calls
|
||||
/// that are rejected by us from the calls
|
||||
/// canceled by the other side
|
||||
/// cancelled by the other side
|
||||
/// immediately after ringing started.
|
||||
const CALL_CANCELED_TIMESTAMP: Param = Param::Arg2;
|
||||
const CALL_CANCELLED_TIMESTAMP: Param = Param::Arg2;
|
||||
|
||||
/// Information about the status of a call.
|
||||
#[derive(Debug, Default)]
|
||||
@@ -123,14 +123,14 @@ impl CallInfo {
|
||||
}
|
||||
|
||||
/// Returns true if the call is missed
|
||||
/// because the caller canceled it
|
||||
/// because the caller cancelled it
|
||||
/// explicitly before ringing stopped.
|
||||
///
|
||||
/// For outgoing calls this means
|
||||
/// the receiver has rejected the call
|
||||
/// explicitly.
|
||||
pub fn is_canceled(&self) -> bool {
|
||||
self.msg.param.exists(CALL_CANCELED_TIMESTAMP)
|
||||
pub fn is_cancelled(&self) -> bool {
|
||||
self.msg.param.exists(CALL_CANCELLED_TIMESTAMP)
|
||||
}
|
||||
|
||||
async fn mark_as_ended(&mut self, context: &Context) -> Result<()> {
|
||||
@@ -139,17 +139,17 @@ impl CallInfo {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Explicitly mark the call as canceled.
|
||||
/// Explicitly mark the call as cancelled.
|
||||
///
|
||||
/// For incoming calls this should be called
|
||||
/// when "call ended" message is received
|
||||
/// from the caller before we picked up the call.
|
||||
/// In this case the call becomes "missed" early
|
||||
/// before the ringing timeout.
|
||||
async fn mark_as_canceled(&mut self, context: &Context) -> Result<()> {
|
||||
async fn mark_as_cancelled(&mut self, context: &Context) -> Result<()> {
|
||||
let now = time();
|
||||
self.msg.param.set_i64(CALL_ENDED_TIMESTAMP, now);
|
||||
self.msg.param.set_i64(CALL_CANCELED_TIMESTAMP, now);
|
||||
self.msg.param.set_i64(CALL_CANCELLED_TIMESTAMP, now);
|
||||
self.msg.update_param(context).await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -183,11 +183,7 @@ impl Context {
|
||||
place_call_info: String,
|
||||
) -> Result<MsgId> {
|
||||
let chat = Chat::load_from_db(self, chat_id).await?;
|
||||
ensure!(
|
||||
chat.typ == Chattype::Single,
|
||||
"Can only place calls in 1:1 chats"
|
||||
);
|
||||
ensure!(!chat.is_self_talk(), "Cannot call self");
|
||||
ensure!(chat.typ == Chattype::Single && !chat.is_self_talk());
|
||||
|
||||
let mut call = Message {
|
||||
viewtype: Viewtype::Call,
|
||||
@@ -259,8 +255,8 @@ impl Context {
|
||||
call.mark_as_ended(self).await?;
|
||||
call.update_text(self, "Declined call").await?;
|
||||
} else {
|
||||
call.mark_as_canceled(self).await?;
|
||||
call.update_text(self, "Canceled call").await?;
|
||||
call.mark_as_cancelled(self).await?;
|
||||
call.update_text(self, "Cancelled call").await?;
|
||||
}
|
||||
} else {
|
||||
call.mark_as_ended(self).await?;
|
||||
@@ -294,11 +290,11 @@ impl Context {
|
||||
let mut call = context.load_call_by_id(call_id).await?;
|
||||
if !call.is_accepted() && !call.is_ended() {
|
||||
if call.is_incoming() {
|
||||
call.mark_as_canceled(&context).await?;
|
||||
call.mark_as_cancelled(&context).await?;
|
||||
call.update_text(&context, "Missed call").await?;
|
||||
} else {
|
||||
call.mark_as_ended(&context).await?;
|
||||
call.update_text(&context, "Canceled call").await?;
|
||||
call.update_text(&context, "Cancelled call").await?;
|
||||
}
|
||||
context.emit_msgs_changed(call.msg.chat_id, call_id);
|
||||
context.emit_event(EventType::CallEnded {
|
||||
@@ -390,14 +386,14 @@ impl Context {
|
||||
call.mark_as_ended(self).await?;
|
||||
call.update_text(self, "Declined call").await?;
|
||||
} else {
|
||||
call.mark_as_canceled(self).await?;
|
||||
call.mark_as_cancelled(self).await?;
|
||||
call.update_text(self, "Missed call").await?;
|
||||
}
|
||||
} else {
|
||||
// outgoing
|
||||
if from_id == ContactId::SELF {
|
||||
call.mark_as_canceled(self).await?;
|
||||
call.update_text(self, "Canceled call").await?;
|
||||
call.mark_as_cancelled(self).await?;
|
||||
call.update_text(self, "Cancelled call").await?;
|
||||
} else {
|
||||
call.mark_as_ended(self).await?;
|
||||
call.update_text(self, "Declined call").await?;
|
||||
@@ -487,13 +483,13 @@ pub enum CallState {
|
||||
/// that was declined before the timeout.
|
||||
Declined,
|
||||
|
||||
/// Outgoing call that has been canceled on our side
|
||||
/// Outgoing call that has been cancelled on our side
|
||||
/// before receiving a response.
|
||||
///
|
||||
/// Incoming calls cannot be canceled,
|
||||
/// on the receiver side canceled calls
|
||||
/// Incoming calls cannot be cancelled,
|
||||
/// on the receiver side cancelled calls
|
||||
/// usually result in missed calls.
|
||||
Canceled,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
/// Returns call state given the message ID.
|
||||
@@ -508,8 +504,8 @@ pub async fn call_state(context: &Context, msg_id: MsgId) -> Result<CallState> {
|
||||
} else {
|
||||
CallState::Active
|
||||
}
|
||||
} else if call.is_canceled() {
|
||||
// Call was explicitly canceled
|
||||
} else if call.is_cancelled() {
|
||||
// Call was explicitly cancelled
|
||||
// by the caller before we picked it up.
|
||||
CallState::Missed
|
||||
} else if call.is_ended() {
|
||||
@@ -527,8 +523,8 @@ pub async fn call_state(context: &Context, msg_id: MsgId) -> Result<CallState> {
|
||||
} else {
|
||||
CallState::Active
|
||||
}
|
||||
} else if call.is_canceled() {
|
||||
CallState::Canceled
|
||||
} else if call.is_cancelled() {
|
||||
CallState::Cancelled
|
||||
} else if call.is_ended() || call.is_stale() {
|
||||
CallState::Declined
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use super::*;
|
||||
use crate::chat::forward_msgs;
|
||||
use crate::config::Config;
|
||||
use crate::test_utils::{TestContext, TestContextManager};
|
||||
|
||||
@@ -369,7 +368,7 @@ async fn test_caller_cancels_call() -> Result<()> {
|
||||
|
||||
// Alice changes their mind before Bob picks up
|
||||
alice.end_call(alice_call.id).await?;
|
||||
assert_text(&alice, alice_call.id, "Canceled call").await?;
|
||||
assert_text(&alice, alice_call.id, "Cancelled call").await?;
|
||||
alice
|
||||
.evtracker
|
||||
.get_matching(|evt| matches!(evt, EventType::CallEnded { .. }))
|
||||
@@ -377,18 +376,18 @@ async fn test_caller_cancels_call() -> Result<()> {
|
||||
let sent3 = alice.pop_sent_msg().await;
|
||||
assert_eq!(
|
||||
call_state(&alice, alice_call.id).await?,
|
||||
CallState::Canceled
|
||||
CallState::Cancelled
|
||||
);
|
||||
|
||||
alice2.recv_msg_trash(&sent3).await;
|
||||
assert_text(&alice2, alice2_call.id, "Canceled call").await?;
|
||||
assert_text(&alice2, alice2_call.id, "Cancelled call").await?;
|
||||
alice2
|
||||
.evtracker
|
||||
.get_matching(|evt| matches!(evt, EventType::CallEnded { .. }))
|
||||
.await;
|
||||
assert_eq!(
|
||||
call_state(&alice2, alice2_call.id).await?,
|
||||
CallState::Canceled
|
||||
CallState::Cancelled
|
||||
);
|
||||
|
||||
// Bob receives the ending message
|
||||
@@ -399,11 +398,6 @@ async fn test_caller_cancels_call() -> Result<()> {
|
||||
.await;
|
||||
assert_eq!(call_state(&bob, bob_call.id).await?, CallState::Missed);
|
||||
|
||||
// Test that message summary says it is a missed call.
|
||||
let bob_call_msg = Message::load_from_db(&bob, bob_call.id).await?;
|
||||
let summary = bob_call_msg.get_summary(&bob, None).await?;
|
||||
assert_eq!(summary.text, "📞 Missed call");
|
||||
|
||||
bob2.recv_msg_trash(&sent3).await;
|
||||
assert_text(&bob2, bob2_call.id, "Missed call").await?;
|
||||
bob2.evtracker
|
||||
@@ -499,33 +493,3 @@ async fn test_sdp_has_video() {
|
||||
assert_eq!(sdp_has_video(PLACE_INFO).unwrap(), false);
|
||||
assert_eq!(sdp_has_video(PLACE_INFO_VIDEO).unwrap(), true);
|
||||
}
|
||||
|
||||
/// Tests that calls are forwarded as text messages.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_forward_call() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = &tcm.alice().await;
|
||||
let bob = &tcm.bob().await;
|
||||
let charlie = &tcm.charlie().await;
|
||||
|
||||
let alice_bob_chat = alice.create_chat(bob).await;
|
||||
let alice_msg_id = alice
|
||||
.place_outgoing_call(alice_bob_chat.id, PLACE_INFO.to_string())
|
||||
.await
|
||||
.context("Failed to place a call")?;
|
||||
let alice_call = Message::load_from_db(alice, alice_msg_id).await?;
|
||||
|
||||
let _alice_sent_call = alice.pop_sent_msg().await;
|
||||
assert_eq!(alice_call.viewtype, Viewtype::Call);
|
||||
|
||||
let alice_charlie_chat = alice.create_chat(charlie).await;
|
||||
forward_msgs(alice, &[alice_call.id], alice_charlie_chat.id).await?;
|
||||
let alice_forwarded_call = alice.pop_sent_msg().await;
|
||||
let alice_forwarded_call_msg = alice_forwarded_call.load_from_db().await;
|
||||
assert_eq!(alice_forwarded_call_msg.viewtype, Viewtype::Text);
|
||||
|
||||
let charlie_forwarded_call = charlie.recv_msg(&alice_forwarded_call).await;
|
||||
assert_eq!(charlie_forwarded_call.viewtype, Viewtype::Text);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+5
-15
@@ -4207,7 +4207,7 @@ pub async fn remove_contact_from_chat(
|
||||
if chat.typ == Chattype::Group && chat.is_promoted() {
|
||||
let addr = contact.get_addr();
|
||||
|
||||
let res = send_member_removal_msg(context, &chat, contact_id, addr).await;
|
||||
let res = send_member_removal_msg(context, chat_id, contact_id, addr).await;
|
||||
|
||||
if contact_id == ContactId::SELF {
|
||||
res?;
|
||||
@@ -4231,7 +4231,7 @@ pub async fn remove_contact_from_chat(
|
||||
// For incoming broadcast channels, it's not possible to remove members,
|
||||
// but it's possible to leave:
|
||||
let self_addr = context.get_primary_self_addr().await?;
|
||||
send_member_removal_msg(context, &chat, contact_id, &self_addr).await?;
|
||||
send_member_removal_msg(context, chat_id, contact_id, &self_addr).await?;
|
||||
} else {
|
||||
bail!("Cannot remove members from non-group chats.");
|
||||
}
|
||||
@@ -4241,18 +4241,14 @@ pub async fn remove_contact_from_chat(
|
||||
|
||||
async fn send_member_removal_msg(
|
||||
context: &Context,
|
||||
chat: &Chat,
|
||||
chat_id: ChatId,
|
||||
contact_id: ContactId,
|
||||
addr: &str,
|
||||
) -> Result<MsgId> {
|
||||
let mut msg = Message::new(Viewtype::Text);
|
||||
|
||||
if contact_id == ContactId::SELF {
|
||||
if chat.typ == Chattype::InBroadcast {
|
||||
msg.text = stock_str::msg_you_left_broadcast(context).await;
|
||||
} else {
|
||||
msg.text = stock_str::msg_group_left_local(context, ContactId::SELF).await;
|
||||
}
|
||||
msg.text = stock_str::msg_group_left_local(context, ContactId::SELF).await;
|
||||
} else {
|
||||
msg.text = stock_str::msg_del_member_local(context, contact_id, ContactId::SELF).await;
|
||||
}
|
||||
@@ -4262,7 +4258,7 @@ async fn send_member_removal_msg(
|
||||
msg.param
|
||||
.set(Param::ContactAddedRemoved, contact_id.to_u32());
|
||||
|
||||
send_msg(context, chat.id, &mut msg).await
|
||||
send_msg(context, chat_id, &mut msg).await
|
||||
}
|
||||
|
||||
async fn set_group_explicitly_left(context: &Context, grpid: &str) -> Result<()> {
|
||||
@@ -4450,10 +4446,6 @@ pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId)
|
||||
.set_int(Param::Forwarded, src_msg_id.to_u32() as i32);
|
||||
}
|
||||
|
||||
if msg.get_viewtype() == Viewtype::Call {
|
||||
msg.viewtype = Viewtype::Text;
|
||||
}
|
||||
|
||||
msg.param.remove(Param::GuaranteeE2ee);
|
||||
msg.param.remove(Param::ForcePlaintext);
|
||||
msg.param.remove(Param::Cmd);
|
||||
@@ -4463,8 +4455,6 @@ pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId)
|
||||
msg.param.remove(Param::WebxdcSummary);
|
||||
msg.param.remove(Param::WebxdcSummaryTimestamp);
|
||||
msg.param.remove(Param::IsEdited);
|
||||
msg.param.remove(Param::WebrtcRoom);
|
||||
msg.param.remove(Param::WebrtcAccepted);
|
||||
msg.in_reply_to = None;
|
||||
|
||||
// do not leak data as group names; a default subject is generated by mimefactory
|
||||
|
||||
@@ -3026,7 +3026,7 @@ async fn test_leave_broadcast() -> Result<()> {
|
||||
}
|
||||
|
||||
/// Tests that if Bob leaves a broadcast channel with one device,
|
||||
/// the other device shows a correct info message "You left the channel.".
|
||||
/// the other device shows a correct info message "You left.".
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_leave_broadcast_multidevice() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
@@ -3061,7 +3061,10 @@ async fn test_leave_broadcast_multidevice() -> Result<()> {
|
||||
assert_eq!(rcvd.chat_id, bob1_hello.chat_id);
|
||||
assert!(rcvd.is_info());
|
||||
assert_eq!(rcvd.get_info_type(), SystemMessage::MemberRemovedFromGroup);
|
||||
assert_eq!(rcvd.text, stock_str::msg_you_left_broadcast(bob1).await);
|
||||
assert_eq!(
|
||||
rcvd.text,
|
||||
stock_str::msg_group_left_local(bob1, ContactId::SELF).await
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -413,6 +413,16 @@ pub enum Config {
|
||||
#[strum(props(default = "172800"))]
|
||||
GossipPeriod,
|
||||
|
||||
/// Deprecated 2025-07. Feature flag for verified 1:1 chats; the UI should set it
|
||||
/// to 1 if it supports verified 1:1 chats.
|
||||
/// Regardless of this setting, `chat.is_protected()` returns true while the key is verified,
|
||||
/// and when the key changes, an info message is posted into the chat.
|
||||
/// 0=Nothing else happens when the key changes.
|
||||
/// 1=After the key changed, `can_send()` returns false
|
||||
/// until `chat_id.accept()` is called.
|
||||
#[strum(props(default = "0"))]
|
||||
VerifiedOneOnOneChats,
|
||||
|
||||
/// Row ID of the key in the `keypairs` table
|
||||
/// used for signatures, encryption to self and included in `Autocrypt` header.
|
||||
KeyId,
|
||||
|
||||
+1
-1
@@ -137,7 +137,7 @@ impl Context {
|
||||
|
||||
let res = self
|
||||
.inner_configure(param)
|
||||
.race(cancel_channel.recv().map(|_| Err(format_err!("Canceled"))))
|
||||
.race(cancel_channel.recv().map(|_| Err(format_err!("Cancelled"))))
|
||||
.await;
|
||||
|
||||
self.free_ongoing().await;
|
||||
|
||||
@@ -98,7 +98,6 @@ pub(crate) const DC_RESEND_USER_AVATAR_DAYS: i64 = 14;
|
||||
// reference is the release date.
|
||||
// as not all system get speedy updates,
|
||||
// do not use too small value that will annoy users checking for nonexistent updates.
|
||||
// "90 days" has proven to be too short at some point (user were informed but there was no update)
|
||||
pub(crate) const DC_OUTDATED_WARNING_DAYS: i64 = 183;
|
||||
|
||||
/// messages that should be deleted get this chat_id; the messages are deleted from the working thread later then. This is also needed as rfc724_mid should be preset as long as the message is not deleted on the server (otherwise it is downloaded again)
|
||||
|
||||
@@ -1054,6 +1054,12 @@ impl Context {
|
||||
"gossip_period",
|
||||
self.get_config_int(Config::GossipPeriod).await?.to_string(),
|
||||
);
|
||||
res.insert(
|
||||
"verified_one_on_one_chats", // deprecated 2025-07
|
||||
self.get_config_bool(Config::VerifiedOneOnOneChats)
|
||||
.await?
|
||||
.to_string(),
|
||||
);
|
||||
res.insert(
|
||||
"webxdc_realtime_enabled",
|
||||
self.get_config_bool(Config::WebxdcRealtimeEnabled)
|
||||
|
||||
+6
-38
@@ -566,38 +566,10 @@ impl Imap {
|
||||
}
|
||||
session.new_mail = false;
|
||||
|
||||
let mut read_cnt = 0;
|
||||
loop {
|
||||
let (n, fetch_more) = self
|
||||
.fetch_new_msg_batch(context, session, folder, folder_meaning)
|
||||
.await?;
|
||||
read_cnt += n;
|
||||
if !fetch_more {
|
||||
return Ok(read_cnt > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns number of messages processed and whether the function should be called again.
|
||||
async fn fetch_new_msg_batch(
|
||||
&mut self,
|
||||
context: &Context,
|
||||
session: &mut Session,
|
||||
folder: &str,
|
||||
folder_meaning: FolderMeaning,
|
||||
) -> Result<(usize, bool)> {
|
||||
let uid_validity = get_uidvalidity(context, folder).await?;
|
||||
let old_uid_next = get_uid_next(context, folder).await?;
|
||||
info!(
|
||||
context,
|
||||
"fetch_new_msg_batch({folder}): UIDVALIDITY={uid_validity}, UIDNEXT={old_uid_next}."
|
||||
);
|
||||
|
||||
let uids_to_prefetch = 500;
|
||||
let msgs = session
|
||||
.prefetch(old_uid_next, uids_to_prefetch)
|
||||
.await
|
||||
.context("prefetch")?;
|
||||
let msgs = session.prefetch(old_uid_next).await.context("prefetch")?;
|
||||
let read_cnt = msgs.len();
|
||||
|
||||
let download_limit = context.download_limit().await?;
|
||||
@@ -757,8 +729,7 @@ impl Imap {
|
||||
largest_uid_fetched
|
||||
};
|
||||
|
||||
let actually_download_messages_future = async {
|
||||
let sender = sender;
|
||||
let actually_download_messages_future = async move {
|
||||
let mut uids_fetch_in_batch = Vec::with_capacity(max(uids_fetch.len(), 1));
|
||||
let mut fetch_partially = false;
|
||||
uids_fetch.push((0, !uids_fetch.last().unwrap_or(&(0, false)).1));
|
||||
@@ -793,17 +764,14 @@ impl Imap {
|
||||
// if the message has arrived after selecting mailbox
|
||||
// and determining its UIDNEXT and before prefetch.
|
||||
let mut new_uid_next = largest_uid_fetched + 1;
|
||||
let fetch_more = fetch_res.is_ok() && {
|
||||
let prefetch_uid_next = old_uid_next + uids_to_prefetch;
|
||||
if fetch_res.is_ok() {
|
||||
// If we have successfully fetched all messages we planned during prefetch,
|
||||
// then we have covered at least the range between old UIDNEXT
|
||||
// and UIDNEXT of the mailbox at the time of selecting it.
|
||||
new_uid_next = max(new_uid_next, min(prefetch_uid_next, mailbox_uid_next));
|
||||
new_uid_next = max(new_uid_next, mailbox_uid_next);
|
||||
|
||||
new_uid_next = max(new_uid_next, largest_uid_skipped.unwrap_or(0) + 1);
|
||||
|
||||
prefetch_uid_next < mailbox_uid_next
|
||||
};
|
||||
}
|
||||
if new_uid_next > old_uid_next {
|
||||
set_uid_next(context, folder, new_uid_next).await?;
|
||||
}
|
||||
@@ -820,7 +788,7 @@ impl Imap {
|
||||
// establish a new session if this one is broken.
|
||||
fetch_res?;
|
||||
|
||||
Ok((read_cnt, fetch_more))
|
||||
Ok(read_cnt > 0)
|
||||
}
|
||||
|
||||
/// Read the recipients from old emails sent by the user and add them as contacts.
|
||||
|
||||
+13
-6
@@ -110,16 +110,14 @@ impl Session {
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
/// Prefetch `n_uids` messages starting from `uid_next`. Returns a list of fetch results in the
|
||||
/// order of ascending delivery time to the server (INTERNALDATE).
|
||||
/// Prefetch all messages greater than or equal to `uid_next`. Returns a list of fetch results
|
||||
/// in the order of ascending delivery time to the server (INTERNALDATE).
|
||||
pub(crate) async fn prefetch(
|
||||
&mut self,
|
||||
uid_next: u32,
|
||||
n_uids: u32,
|
||||
) -> Result<Vec<(u32, async_imap::types::Fetch)>> {
|
||||
let uid_last = uid_next.saturating_add(n_uids - 1);
|
||||
// fetch messages with larger UID than the last one seen
|
||||
let set = format!("{uid_next}:{uid_last}");
|
||||
let set = format!("{uid_next}:*");
|
||||
let mut list = self
|
||||
.uid_fetch(set, PREFETCH_FLAGS)
|
||||
.await
|
||||
@@ -128,7 +126,16 @@ impl Session {
|
||||
let mut msgs = BTreeMap::new();
|
||||
while let Some(msg) = list.try_next().await? {
|
||||
if let Some(msg_uid) = msg.uid {
|
||||
msgs.insert((msg.internal_date(), msg_uid), msg);
|
||||
// If the mailbox is not empty, results always include
|
||||
// at least one UID, even if last_seen_uid+1 is past
|
||||
// the last UID in the mailbox. It happens because
|
||||
// uid:* is interpreted the same way as *:uid.
|
||||
// See <https://tools.ietf.org/html/rfc3501#page-61> for
|
||||
// standard reference. Therefore, sometimes we receive
|
||||
// already seen messages and have to filter them out.
|
||||
if msg_uid >= uid_next {
|
||||
msgs.insert((msg.internal_date(), msg_uid), msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+63
-44
@@ -928,56 +928,75 @@ mod tests {
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_export_and_import_backup() -> Result<()> {
|
||||
let backup_dir = tempfile::tempdir().unwrap();
|
||||
for set_verified_oneonone_chats in [true, false] {
|
||||
let backup_dir = tempfile::tempdir().unwrap();
|
||||
|
||||
let context1 = TestContext::new_alice().await;
|
||||
assert!(context1.is_configured().await?);
|
||||
let context1 = TestContext::new_alice().await;
|
||||
assert!(context1.is_configured().await?);
|
||||
if set_verified_oneonone_chats {
|
||||
context1
|
||||
.set_config_bool(Config::VerifiedOneOnOneChats, true)
|
||||
.await?;
|
||||
}
|
||||
|
||||
let context2 = TestContext::new().await;
|
||||
assert!(!context2.is_configured().await?);
|
||||
assert!(has_backup(&context2, backup_dir.path()).await.is_err());
|
||||
let context2 = TestContext::new().await;
|
||||
assert!(!context2.is_configured().await?);
|
||||
assert!(has_backup(&context2, backup_dir.path()).await.is_err());
|
||||
|
||||
// export from context1
|
||||
assert!(
|
||||
imex(&context1, ImexMode::ExportBackup, backup_dir.path(), None)
|
||||
// export from context1
|
||||
assert!(
|
||||
imex(&context1, ImexMode::ExportBackup, backup_dir.path(), None)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
let _event = context1
|
||||
.evtracker
|
||||
.get_matching(|evt| matches!(evt, EventType::ImexProgress(1000)))
|
||||
.await;
|
||||
|
||||
// import to context2
|
||||
let backup = has_backup(&context2, backup_dir.path()).await?;
|
||||
|
||||
// Import of unencrypted backup with incorrect "foobar" backup passphrase fails.
|
||||
assert!(
|
||||
imex(
|
||||
&context2,
|
||||
ImexMode::ImportBackup,
|
||||
backup.as_ref(),
|
||||
Some("foobar".to_string())
|
||||
)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
let _event = context1
|
||||
.evtracker
|
||||
.get_matching(|evt| matches!(evt, EventType::ImexProgress(1000)))
|
||||
.await;
|
||||
.is_err()
|
||||
);
|
||||
|
||||
// import to context2
|
||||
let backup = has_backup(&context2, backup_dir.path()).await?;
|
||||
assert!(
|
||||
imex(&context2, ImexMode::ImportBackup, backup.as_ref(), None)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
let _event = context2
|
||||
.evtracker
|
||||
.get_matching(|evt| matches!(evt, EventType::ImexProgress(1000)))
|
||||
.await;
|
||||
|
||||
// Import of unencrypted backup with incorrect "foobar" backup passphrase fails.
|
||||
assert!(
|
||||
imex(
|
||||
&context2,
|
||||
ImexMode::ImportBackup,
|
||||
backup.as_ref(),
|
||||
Some("foobar".to_string())
|
||||
)
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
|
||||
assert!(
|
||||
imex(&context2, ImexMode::ImportBackup, backup.as_ref(), None)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
let _event = context2
|
||||
.evtracker
|
||||
.get_matching(|evt| matches!(evt, EventType::ImexProgress(1000)))
|
||||
.await;
|
||||
|
||||
assert!(context2.is_configured().await?);
|
||||
assert_eq!(
|
||||
context2.get_config(Config::Addr).await?,
|
||||
Some("alice@example.org".to_string())
|
||||
);
|
||||
assert!(context2.is_configured().await?);
|
||||
assert_eq!(
|
||||
context2.get_config(Config::Addr).await?,
|
||||
Some("alice@example.org".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
context2
|
||||
.get_config_bool(Config::VerifiedOneOnOneChats)
|
||||
.await?,
|
||||
false
|
||||
);
|
||||
assert_eq!(
|
||||
context1
|
||||
.get_config_bool(Config::VerifiedOneOnOneChats)
|
||||
.await?,
|
||||
set_verified_oneonone_chats
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -242,7 +242,7 @@ impl BackupProvider {
|
||||
if let Err(err) = Self::handle_connection(context.clone(), conn, auth_token, dbfile).race(
|
||||
async {
|
||||
cancel_token.recv().await.ok();
|
||||
Err(format_err!("Backup transfer canceled"))
|
||||
Err(format_err!("Backup transfer cancelled"))
|
||||
}
|
||||
).race(
|
||||
async {
|
||||
@@ -262,12 +262,12 @@ impl BackupProvider {
|
||||
}
|
||||
},
|
||||
_ = cancel_token.recv() => {
|
||||
info!(context, "Backup transfer canceled by the user, stopping accept loop.");
|
||||
info!(context, "Backup transfer cancelled by the user, stopping accept loop.");
|
||||
context.emit_event(EventType::ImexProgress(0));
|
||||
break;
|
||||
}
|
||||
_ = drop_token.cancelled() => {
|
||||
info!(context, "Backup transfer canceled by dropping the provider, stopping accept loop.");
|
||||
info!(context, "Backup transfer cancelled by dropping the provider, stopping accept loop.");
|
||||
context.emit_event(EventType::ImexProgress(0));
|
||||
break;
|
||||
}
|
||||
@@ -364,7 +364,7 @@ pub async fn get_backup(context: &Context, qr: Qr) -> Result<()> {
|
||||
let res = get_backup2(context, node_addr, auth_token)
|
||||
.race(async {
|
||||
cancel_token.recv().await.ok();
|
||||
Err(format_err!("Backup reception canceled"))
|
||||
Err(format_err!("Backup reception cancelled"))
|
||||
})
|
||||
.await;
|
||||
if let Err(ref res) = res {
|
||||
|
||||
@@ -1019,7 +1019,6 @@ impl MimeFactory {
|
||||
| "in-reply-to"
|
||||
| "references"
|
||||
| "auto-submitted"
|
||||
| "chat-version"
|
||||
| "autocrypt-setup-message" => {
|
||||
unprotected_headers.push(header.clone());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! # QR code generation module.
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use anyhow::Result;
|
||||
use base64::Engine as _;
|
||||
use qrcodegen::{QrCode, QrCodeEcc};
|
||||
|
||||
@@ -108,18 +108,8 @@ async fn generate_join_group_qr_code(context: &Context, chat_id: ChatId) -> Resu
|
||||
None => None,
|
||||
};
|
||||
|
||||
let qrcode_description = match chat.typ {
|
||||
crate::constants::Chattype::Group => {
|
||||
stock_str::secure_join_group_qr_description(context, &chat).await
|
||||
}
|
||||
crate::constants::Chattype::OutBroadcast => {
|
||||
stock_str::secure_join_broadcast_qr_description(context, &chat).await
|
||||
}
|
||||
_ => bail!("Unexpected chat type {}", chat.typ),
|
||||
};
|
||||
|
||||
inner_generate_secure_join_qr_code(
|
||||
&qrcode_description,
|
||||
&stock_str::secure_join_group_qr_description(context, &chat).await,
|
||||
&securejoin::get_securejoin_qr(context, Some(chat_id)).await?,
|
||||
&color_int_to_hex_string(chat.get_color(context).await?),
|
||||
avatar,
|
||||
|
||||
+2
-1
@@ -3532,7 +3532,8 @@ async fn apply_in_broadcast_changes(
|
||||
// The only member added/removed message that is ever sent is "I left.",
|
||||
// so, this is the only case we need to handle here
|
||||
if from_id == ContactId::SELF {
|
||||
better_msg.get_or_insert(stock_str::msg_you_left_broadcast(context).await);
|
||||
better_msg
|
||||
.get_or_insert(stock_str::msg_group_left_local(context, ContactId::SELF).await);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,11 @@ async fn test_setup_contact_ex(case: SetupContactCase) {
|
||||
}
|
||||
_ => alice_auto_submitted_hdr = "Auto-Submitted: auto-replied",
|
||||
};
|
||||
for t in [&alice, &bob] {
|
||||
t.set_config_bool(Config::VerifiedOneOnOneChats, true)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
Chatlist::try_load(&alice, 0, None, None)
|
||||
@@ -697,6 +702,11 @@ async fn test_lost_contact_confirm() {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = tcm.alice().await;
|
||||
let bob = tcm.bob().await;
|
||||
for t in [&alice, &bob] {
|
||||
t.set_config_bool(Config::VerifiedOneOnOneChats, true)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let qr = get_securejoin_qr(&alice, None).await.unwrap();
|
||||
join_securejoin(&bob.ctx, &qr).await.unwrap();
|
||||
|
||||
+3
-61
@@ -279,7 +279,7 @@ pub enum StockMessage {
|
||||
#[strum(props(fallback = "Member %1$s removed by %2$s."))]
|
||||
MsgDelMemberBy = 131,
|
||||
|
||||
#[strum(props(fallback = "You left the group."))]
|
||||
#[strum(props(fallback = "You left."))]
|
||||
MsgYouLeftGroup = 132,
|
||||
|
||||
#[strum(props(fallback = "Group left by %1$s."))]
|
||||
@@ -424,27 +424,6 @@ Help keeping us to keep Delta Chat independent and make it more awesome in the f
|
||||
|
||||
https://delta.chat/donate"))]
|
||||
DonationRequest = 193,
|
||||
|
||||
#[strum(props(fallback = "Outgoing call"))]
|
||||
OutgoingCall = 194,
|
||||
|
||||
#[strum(props(fallback = "Incoming call"))]
|
||||
IncomingCall = 195,
|
||||
|
||||
#[strum(props(fallback = "Declined call"))]
|
||||
DeclinedCall = 196,
|
||||
|
||||
#[strum(props(fallback = "Canceled call"))]
|
||||
CanceledCall = 197,
|
||||
|
||||
#[strum(props(fallback = "Missed call"))]
|
||||
MissedCall = 198,
|
||||
|
||||
#[strum(props(fallback = "You left the channel."))]
|
||||
MsgYouLeftBroadcast = 200,
|
||||
|
||||
#[strum(props(fallback = "Scan to join channel %1$s"))]
|
||||
SecureJoinBrodcastQRDescription = 201,
|
||||
}
|
||||
|
||||
impl StockMessage {
|
||||
@@ -717,7 +696,7 @@ pub(crate) async fn msg_group_left_remote(context: &Context) -> String {
|
||||
translated(context, StockMessage::MsgILeftGroup).await
|
||||
}
|
||||
|
||||
/// Stock string: `You left the group.` or `Group left by %1$s.`.
|
||||
/// Stock string: `You left.` or `Group left by %1$s.`.
|
||||
pub(crate) async fn msg_group_left_local(context: &Context, by_contact: ContactId) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouLeftGroup).await
|
||||
@@ -728,11 +707,6 @@ pub(crate) async fn msg_group_left_local(context: &Context, by_contact: ContactI
|
||||
}
|
||||
}
|
||||
|
||||
/// Stock string: `You left the channel.`
|
||||
pub(crate) async fn msg_you_left_broadcast(context: &Context) -> String {
|
||||
translated(context, StockMessage::MsgYouLeftBroadcast).await
|
||||
}
|
||||
|
||||
/// Stock string: `You reacted %1$s to "%2$s"` or `%1$s reacted %2$s to "%3$s"`.
|
||||
pub(crate) async fn msg_reacted(
|
||||
context: &Context,
|
||||
@@ -827,31 +801,6 @@ pub(crate) async fn donation_request(context: &Context) -> String {
|
||||
translated(context, StockMessage::DonationRequest).await
|
||||
}
|
||||
|
||||
/// Stock string: `Outgoing call`.
|
||||
pub(crate) async fn outgoing_call(context: &Context) -> String {
|
||||
translated(context, StockMessage::OutgoingCall).await
|
||||
}
|
||||
|
||||
/// Stock string: `Incoming call`.
|
||||
pub(crate) async fn incoming_call(context: &Context) -> String {
|
||||
translated(context, StockMessage::IncomingCall).await
|
||||
}
|
||||
|
||||
/// Stock string: `Declined call`.
|
||||
pub(crate) async fn declined_call(context: &Context) -> String {
|
||||
translated(context, StockMessage::DeclinedCall).await
|
||||
}
|
||||
|
||||
/// Stock string: `Canceled call`.
|
||||
pub(crate) async fn canceled_call(context: &Context) -> String {
|
||||
translated(context, StockMessage::CanceledCall).await
|
||||
}
|
||||
|
||||
/// Stock string: `Missed call`.
|
||||
pub(crate) async fn missed_call(context: &Context) -> String {
|
||||
translated(context, StockMessage::MissedCall).await
|
||||
}
|
||||
|
||||
/// Stock string: `Scan to chat with %1$s`.
|
||||
pub(crate) async fn setup_contact_qr_description(
|
||||
context: &Context,
|
||||
@@ -868,20 +817,13 @@ pub(crate) async fn setup_contact_qr_description(
|
||||
.replace1(&name)
|
||||
}
|
||||
|
||||
/// Stock string: `Scan to join group %1$s`.
|
||||
/// Stock string: `Scan to join %1$s`.
|
||||
pub(crate) async fn secure_join_group_qr_description(context: &Context, chat: &Chat) -> String {
|
||||
translated(context, StockMessage::SecureJoinGroupQRDescription)
|
||||
.await
|
||||
.replace1(chat.get_name())
|
||||
}
|
||||
|
||||
/// Stock string: `Scan to join channel %1$s`.
|
||||
pub(crate) async fn secure_join_broadcast_qr_description(context: &Context, chat: &Chat) -> String {
|
||||
translated(context, StockMessage::SecureJoinBrodcastQRDescription)
|
||||
.await
|
||||
.replace1(chat.get_name())
|
||||
}
|
||||
|
||||
/// Stock string: `%1$s verified.`.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) async fn contact_verified(context: &Context, contact: &Contact) -> String {
|
||||
|
||||
+4
-15
@@ -4,7 +4,6 @@ use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
use crate::calls::{CallState, call_state};
|
||||
use crate::chat::Chat;
|
||||
use crate::constants::Chattype;
|
||||
use crate::contact::{Contact, ContactId};
|
||||
@@ -235,21 +234,11 @@ impl Message {
|
||||
append_text = true;
|
||||
}
|
||||
Viewtype::Call => {
|
||||
let call_state = call_state(context, self.id)
|
||||
.await
|
||||
.unwrap_or(CallState::Alerting);
|
||||
emoji = Some("📞");
|
||||
type_name = Some(match call_state {
|
||||
CallState::Alerting | CallState::Active | CallState::Completed { .. } => {
|
||||
if self.from_id == ContactId::SELF {
|
||||
stock_str::outgoing_call(context).await
|
||||
} else {
|
||||
stock_str::incoming_call(context).await
|
||||
}
|
||||
}
|
||||
CallState::Missed => stock_str::missed_call(context).await,
|
||||
CallState::Declined => stock_str::declined_call(context).await,
|
||||
CallState::Canceled => stock_str::canceled_call(context).await,
|
||||
type_name = Some(if self.from_id == ContactId::SELF {
|
||||
"Outgoing call".to_string()
|
||||
} else {
|
||||
"Incoming call".to_string()
|
||||
});
|
||||
type_file = None;
|
||||
append_text = false
|
||||
|
||||
@@ -35,6 +35,7 @@ async fn check_verified_oneonone_chat_protection_not_broken(by_classical_email:
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = tcm.alice().await;
|
||||
let bob = tcm.bob().await;
|
||||
enable_verified_oneonone_chats(&[&alice, &bob]).await;
|
||||
|
||||
tcm.execute_securejoin(&alice, &bob).await;
|
||||
|
||||
@@ -88,6 +89,7 @@ async fn test_create_verified_oneonone_chat() -> Result<()> {
|
||||
let alice = tcm.alice().await;
|
||||
let bob = tcm.bob().await;
|
||||
let fiona = tcm.fiona().await;
|
||||
enable_verified_oneonone_chats(&[&alice, &bob, &fiona]).await;
|
||||
|
||||
tcm.execute_securejoin(&alice, &bob).await;
|
||||
tcm.execute_securejoin(&bob, &fiona).await;
|
||||
@@ -149,6 +151,7 @@ async fn test_create_verified_oneonone_chat() -> Result<()> {
|
||||
drop(fiona);
|
||||
|
||||
let fiona_new = tcm.unconfigured().await;
|
||||
enable_verified_oneonone_chats(&[&fiona_new]).await;
|
||||
fiona_new.configure_addr("fiona@example.net").await;
|
||||
e2ee::ensure_secret_key_exists(&fiona_new).await?;
|
||||
|
||||
@@ -178,6 +181,7 @@ async fn test_missing_key_reexecute_securejoin() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = &tcm.alice().await;
|
||||
let bob = &tcm.bob().await;
|
||||
enable_verified_oneonone_chats(&[alice, bob]).await;
|
||||
let chat_id = tcm.execute_securejoin(bob, alice).await;
|
||||
let chat = Chat::load_from_db(bob, chat_id).await?;
|
||||
assert!(chat.is_protected());
|
||||
@@ -202,6 +206,7 @@ async fn test_create_unverified_oneonone_chat() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = tcm.alice().await;
|
||||
let bob = tcm.bob().await;
|
||||
enable_verified_oneonone_chats(&[&alice, &bob]).await;
|
||||
|
||||
// A chat with an unknown contact should be created unprotected
|
||||
let chat = alice.create_chat(&bob).await;
|
||||
@@ -241,6 +246,7 @@ async fn test_degrade_verified_oneonone_chat() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = tcm.alice().await;
|
||||
let bob = tcm.bob().await;
|
||||
enable_verified_oneonone_chats(&[&alice, &bob]).await;
|
||||
|
||||
mark_as_verified(&alice, &bob).await;
|
||||
|
||||
@@ -355,6 +361,7 @@ async fn test_mdn_doesnt_disable_verification() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = tcm.alice().await;
|
||||
let bob = tcm.bob().await;
|
||||
enable_verified_oneonone_chats(&[&alice, &bob]).await;
|
||||
bob.set_config_bool(Config::MdnsEnabled, true).await?;
|
||||
|
||||
// Alice & Bob verify each other
|
||||
@@ -379,6 +386,7 @@ async fn test_outgoing_mua_msg() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = tcm.alice().await;
|
||||
let bob = tcm.bob().await;
|
||||
enable_verified_oneonone_chats(&[&alice, &bob]).await;
|
||||
|
||||
mark_as_verified(&alice, &bob).await;
|
||||
mark_as_verified(&bob, &alice).await;
|
||||
@@ -415,6 +423,7 @@ async fn test_outgoing_encrypted_msg() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = &tcm.alice().await;
|
||||
let bob = &tcm.bob().await;
|
||||
enable_verified_oneonone_chats(&[alice]).await;
|
||||
|
||||
mark_as_verified(alice, bob).await;
|
||||
let chat_id = alice.create_chat(bob).await.id;
|
||||
@@ -440,6 +449,7 @@ async fn test_reply() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = tcm.alice().await;
|
||||
let bob = tcm.bob().await;
|
||||
enable_verified_oneonone_chats(&[&alice, &bob]).await;
|
||||
|
||||
if verified {
|
||||
mark_as_verified(&alice, &bob).await;
|
||||
@@ -482,6 +492,7 @@ async fn test_message_from_old_dc_setup() -> Result<()> {
|
||||
let alice = &tcm.alice().await;
|
||||
let bob_old = &tcm.unconfigured().await;
|
||||
|
||||
enable_verified_oneonone_chats(&[alice, bob_old]).await;
|
||||
bob_old.configure_addr("bob@example.net").await;
|
||||
mark_as_verified(bob_old, alice).await;
|
||||
let chat = bob_old.create_chat(alice).await;
|
||||
@@ -492,6 +503,7 @@ async fn test_message_from_old_dc_setup() -> Result<()> {
|
||||
|
||||
tcm.section("Bob reinstalls DC");
|
||||
let bob = &tcm.bob().await;
|
||||
enable_verified_oneonone_chats(&[bob]).await;
|
||||
|
||||
mark_as_verified(alice, bob).await;
|
||||
mark_as_verified(bob, alice).await;
|
||||
@@ -523,6 +535,7 @@ async fn test_verify_then_verify_again() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = tcm.alice().await;
|
||||
let bob = tcm.bob().await;
|
||||
enable_verified_oneonone_chats(&[&alice, &bob]).await;
|
||||
|
||||
mark_as_verified(&alice, &bob).await;
|
||||
mark_as_verified(&bob, &alice).await;
|
||||
@@ -533,6 +546,7 @@ async fn test_verify_then_verify_again() -> Result<()> {
|
||||
tcm.section("Bob reinstalls DC");
|
||||
drop(bob);
|
||||
let bob_new = tcm.unconfigured().await;
|
||||
enable_verified_oneonone_chats(&[&bob_new]).await;
|
||||
bob_new.configure_addr("bob@example.net").await;
|
||||
e2ee::ensure_secret_key_exists(&bob_new).await?;
|
||||
|
||||
@@ -585,6 +599,7 @@ async fn test_verified_member_added_reordering() -> Result<()> {
|
||||
let alice = &tcm.alice().await;
|
||||
let bob = &tcm.bob().await;
|
||||
let fiona = &tcm.fiona().await;
|
||||
enable_verified_oneonone_chats(&[alice, bob, fiona]).await;
|
||||
|
||||
let alice_fiona_contact_id = alice.add_or_lookup_contact_id(fiona).await;
|
||||
|
||||
@@ -636,6 +651,7 @@ async fn test_no_unencrypted_name_if_encrypted() -> Result<()> {
|
||||
bob.set_config(Config::Displayname, Some("Bob Smith"))
|
||||
.await?;
|
||||
if verified {
|
||||
enable_verified_oneonone_chats(&[&bob]).await;
|
||||
mark_as_verified(&bob, &alice).await;
|
||||
} else {
|
||||
tcm.send_recv_accept(&alice, &bob, "hi").await;
|
||||
@@ -866,3 +882,11 @@ async fn assert_verified(this: &TestContext, other: &TestContext, protected: Pro
|
||||
protected == ProtectionStatus::Protected
|
||||
);
|
||||
}
|
||||
|
||||
async fn enable_verified_oneonone_chats(test_contexts: &[&TestContext]) {
|
||||
for t in test_contexts {
|
||||
t.set_config_bool(Config::VerifiedOneOnOneChats, true)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,8 +437,7 @@ async fn test_maybe_warn_on_outdated() {
|
||||
let t = TestContext::new().await;
|
||||
let timestamp_now: i64 = time();
|
||||
|
||||
// in about 3 months, the app should not be outdated.
|
||||
// "90 days" has proven to be too short at some point - user were informed but there was no update
|
||||
// in about 3 months, the app should not be outdated
|
||||
maybe_warn_on_outdated(
|
||||
&t,
|
||||
timestamp_now + 90 * 24 * 60 * 60,
|
||||
|
||||
@@ -2,7 +2,7 @@ Group#Chat#10: Group chat [3 member(s)]
|
||||
--------------------------------------------------------------------------------
|
||||
Msg#10: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO]
|
||||
Msg#11🔒: (Contact#Contact#10): Hi! I created a group. [FRESH]
|
||||
Msg#12🔒: Me (Contact#Contact#Self): You left the group. [INFO] √
|
||||
Msg#12🔒: Me (Contact#Contact#Self): You left. [INFO] √
|
||||
Msg#13🔒: (Contact#Contact#10): Member charlie@example.net added by alice@example.org. [FRESH][INFO]
|
||||
Msg#14🔒: (Contact#Contact#10): What a silence! [FRESH]
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user