Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
fix: always set bcc_self on backup import/export
Regardless of whether chatmail relay is used or not,
bcc_self should be enabled when second device is added.
It should also be enabled again even if the user
has turned it off manually.
  • Loading branch information
link2xt committed Nov 14, 2025
commit 36f868ef9df179347adc40a474ebbe7d79083919
35 changes: 35 additions & 0 deletions deltachat-rpc-client/tests/test_multidevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,41 @@
from deltachat_rpc_client.const import MessageState


def test_bcc_self_delete_server_after_defaults(acfactory):
"""Test default values for bcc_self and delete_server_after."""
ac = acfactory.get_online_account()

# Initially after getting online
# the setting bcc_self is set to 0 because there is only one device
# and delete_server_after is "1", meaning immediate deletion.
assert ac.get_config("bcc_self") == "0"
assert ac.get_config("delete_server_after") == "1"

# Setup a second device.
ac_clone = ac.clone()
ac_clone.bring_online()

# Second device setup
# enables bcc_self and changes default delete_server_after.
assert ac.get_config("bcc_self") == "1"
assert ac.get_config("delete_server_after") == "0"

assert ac_clone.get_config("bcc_self") == "1"
assert ac_clone.get_config("delete_server_after") == "0"

# Manually disabling bcc_self
# also restores the default for delete_server_after.
ac.set_config("bcc_self", "0")
assert ac.get_config("bcc_self") == "0"
assert ac.get_config("delete_server_after") == "1"

# Cloning the account again enables bcc_self
# even though it was manually disabled.
ac_clone = ac.clone()
assert ac.get_config("bcc_self") == "1"
assert ac.get_config("delete_server_after") == "0"


def test_one_account_send_bcc_setting(acfactory, log, direct_imap):
ac1, ac2 = acfactory.get_online_accounts(2)
ac1_clone = ac1.clone()
Expand Down
24 changes: 10 additions & 14 deletions src/imex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,15 @@ async fn import_backup_stream_inner<R: tokio::io::AsyncRead + Unpin>(
res = check_backup_version(context).await;
}
if res.is_ok() {
res = adjust_bcc_self(context).await;
// All recent backups have `bcc_self` set to "1" before export.
//
// Setting `bcc_self` to "1" on export was introduced on 2024-12-17
// in commit 21664125d798021be75f47d5b0d5006d338b4531
//
// We additionally try to set `bcc_self` to "1" after import here
// for compatibility with older backups,
// but eventually this code can be removed.
res = context.set_config(Config::BccSelf, Some("1")).await;
}
fs::remove_file(unpacked_database)
.await
Expand Down Expand Up @@ -751,7 +759,7 @@ async fn export_database(
.to_str()
.with_context(|| format!("path {} is not valid unicode", dest.display()))?;

adjust_bcc_self(context).await?;
context.set_config(Config::BccSelf, Some("1")).await?;
context
.sql
.set_raw_config_int("backup_time", timestamp)
Expand Down Expand Up @@ -785,18 +793,6 @@ async fn export_database(
.await
}

/// Sets `Config::BccSelf` (and `DeleteServerAfter` to "never" in effect) if needed so that new
/// messages are present on the server after a backup restoration or available for all devices in
/// multi-device case. NB: Calling this after a backup import isn't reliable as we can crash in
/// between, but this is a problem only for old backups, new backups already have `BccSelf` set if
/// necessary.
async fn adjust_bcc_self(context: &Context) -> Result<()> {
if context.is_chatmail().await? && !context.config_exists(Config::BccSelf).await? {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify the logic here: is_chatmail() is checked because for non-chatmail BccSelf is true by default anyway, and config_exists(Config::BccSelf) is checked because that time it was decided that it's not good to change settings which the user modified by hand (i think we should really avoid this or at least not do it silently)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote more below and added a section to #7357 so we don't forget about it.
I'd wait until deltachat/deltachat-android#4019 is merged first and also open a PR with disabling bcc_self by default for all new profiles.

context.set_config(Config::BccSelf, Some("1")).await?;
}
Ok(())
}

async fn check_backup_version(context: &Context) -> Result<()> {
let version = (context.sql.get_raw_config_int("backup_version").await?).unwrap_or(2);
ensure!(
Expand Down