Compare commits

..

10 Commits

Author SHA1 Message Date
link2xt
83011e7072 chore: clippy::useless-borrows-in-formatting fixes 2026-05-10 16:37:59 +02:00
link2xt
6fb2f27831 Revert "fix: set dir to "auto" in body tag when converting plain-text to HTML (#8227)"
This reverts commit 58a09df49a
which was merged with failing CI.
2026-05-08 22:11:33 +02:00
adb
58a09df49a fix: set dir to "auto" in body tag when converting plain-text to HTML (#8227)
close #8223
2026-05-08 20:20:00 +02:00
iequidoo
ca70fb9b3a feat: Get rid of MessageState::{OutPreparing,OutMdnRcvd} in the db
`OutPreparing` is deprecated since 2024-12-07, replace it with `OutFailed`, such messages are
probably not interesting anymore. `OutMdnRcvd` is not used in the db for new messages since
a30c6ae1f7, `OutDelivered` is stored instead.
2026-05-07 20:37:11 -03:00
iequidoo
045b586569 feat: Never remove primary transport when applying SyncTransports message
If we missed a message changing the primary transport, we shouldn't remove it when applying
a SyncTransports message, such a state doesn't look correct even if it's temporary.
2026-05-07 20:04:22 -03:00
iequidoo
18e1ecbb94 fix: Generate new pre-message Message-ID when forwarding
Otherwise if it's forwarded to a device that already has the original
message, the pre-message isn't received and this results in a message
having no text and `Forwarded` param.

Co-authored-by: Hocuri <hocuri@gmx.de>
2026-05-07 19:35:03 -03:00
iequidoo
6fdee2b92d docs: Remove outdated comment about "quota warning" device message
The device message was removed in 7de58f5329.
2026-05-07 19:31:38 -03:00
dependabot[bot]
9ebd4769f5 chore(cargo): bump openssl from 0.10.78 to 0.10.79
Bumps [openssl](https://github.com/rust-openssl/rust-openssl) from 0.10.78 to 0.10.79.
- [Release notes](https://github.com/rust-openssl/rust-openssl/releases)
- [Commits](https://github.com/rust-openssl/rust-openssl/compare/openssl-v0.10.78...openssl-v0.10.79)

---
updated-dependencies:
- dependency-name: openssl
  dependency-version: 0.10.79
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-07 09:13:45 -03:00
dependabot[bot]
741d1beed8 chore(cargo): bump data-encoding from 2.10.0 to 2.11.0
Bumps [data-encoding](https://github.com/ia0/data-encoding) from 2.10.0 to 2.11.0.
- [Commits](https://github.com/ia0/data-encoding/compare/v2.10.0...v2.11.0)

---
updated-dependencies:
- dependency-name: data-encoding
  dependency-version: 2.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-04 14:10:58 -03:00
dependabot[bot]
ac8b2d2fca chore(cargo): bump colorutils-rs from 0.7.6 to 0.8.0
Bumps [colorutils-rs](https://github.com/awxkee/colorutils-rs) from 0.7.6 to 0.8.0.
- [Release notes](https://github.com/awxkee/colorutils-rs/releases)
- [Commits](https://github.com/awxkee/colorutils-rs/compare/0.7.6...0.8.0)
2026-05-04 13:42:52 -03:00
29 changed files with 128 additions and 152 deletions

42
Cargo.lock generated
View File

@@ -934,9 +934,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "colorutils-rs"
version = "0.7.6"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2fc25857fa523662de5cae84225b0e7bfb24a2a3f9ed8802fecf03df7252b1"
checksum = "69abc9a8ed011e2b7946769f460b9e76e8b659ece9ef4001b9d8bba3489f796d"
dependencies = [
"erydanos",
"half",
@@ -1301,9 +1301,9 @@ dependencies = [
[[package]]
name = "data-encoding"
version = "2.10.0"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
[[package]]
name = "dbl"
@@ -1400,7 +1400,7 @@ dependencies = [
"url",
"uuid",
"walkdir",
"webpki-roots 1.0.7",
"webpki-roots",
]
[[package]]
@@ -2645,7 +2645,7 @@ dependencies = [
"tokio",
"tokio-rustls",
"tower-service",
"webpki-roots 0.26.11",
"webpki-roots",
]
[[package]]
@@ -2662,7 +2662,7 @@ dependencies = [
"hyper",
"libc",
"pin-project-lite",
"socket2 0.5.9",
"socket2 0.6.3",
"tokio",
"tower-service",
"tracing",
@@ -3009,7 +3009,7 @@ dependencies = [
"tracing",
"url",
"wasm-bindgen-futures",
"webpki-roots 0.26.11",
"webpki-roots",
"x509-parser",
"z32",
]
@@ -3195,7 +3195,7 @@ dependencies = [
"tokio-websockets",
"tracing",
"url",
"webpki-roots 0.26.11",
"webpki-roots",
"ws_stream_wasm",
"z32",
]
@@ -3941,15 +3941,14 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
[[package]]
name = "openssl"
version = "0.10.78"
version = "0.10.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f38c4372413cdaaf3cc79dd92d29d7d9f5ab09b51b10dded508fb90bb70b9222"
checksum = "bf0b434746ee2832f4f0baf10137e1cabb18cbe6912c69e2e33263c45250f542"
dependencies = [
"bitflags 2.11.0",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
@@ -3982,9 +3981,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.114"
version = "0.9.115"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6"
checksum = "158fe5b292746440aa6e7a7e690e55aeb72d41505e2804c23c6973ad0e9c9781"
dependencies = [
"cc",
"libc",
@@ -5007,7 +5006,7 @@ dependencies = [
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"webpki-roots 0.26.11",
"webpki-roots",
"windows-registry",
]
@@ -6765,18 +6764,9 @@ dependencies = [
[[package]]
name = "webpki-roots"
version = "0.26.11"
version = "0.26.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
dependencies = [
"webpki-roots 1.0.7",
]
[[package]]
name = "webpki-roots"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d"
checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9"
dependencies = [
"rustls-pki-types",
]

View File

@@ -53,7 +53,7 @@ blake3 = "1.8.2"
brotli = { version = "8", default-features=false, features = ["std"] }
bytes = "1"
chrono = { workspace = true, features = ["alloc", "clock", "std"] }
colorutils-rs = { version = "0.7.5", default-features = false }
colorutils-rs = { version = "0.8.0", default-features = false }
data-encoding = "2.9.0"
escaper = "0.1"
fast-socks5 = "1"
@@ -111,7 +111,7 @@ tracing = "0.1.41"
url = "2"
uuid = { version = "1", features = ["serde", "v4"] }
walkdir = "2.5.0"
webpki-roots = "1.0"
webpki-roots = "0.26.8"
[dev-dependencies]
anyhow = { workspace = true, features = ["backtrace"] } # Enable `backtrace` feature in tests.

View File

@@ -4003,8 +4003,6 @@ int dc_msg_get_viewtype (const dc_msg_t* msg);
* Marked as read on IMAP and MDN may be sent. Use dc_markseen_msgs() to mark messages as being seen.
*
* Outgoing message states:
* - @ref DC_STATE_OUT_PREPARING - For files which need time to be prepared before they can be sent,
* the message enters this state before @ref DC_STATE_OUT_PENDING. Deprecated.
* - @ref DC_STATE_OUT_DRAFT - Message saved as draft using dc_set_draft()
* - @ref DC_STATE_OUT_PENDING - The user has pressed the "send" button but the
* message is not yet sent and is pending in some way. Maybe we're offline (no checkmark).
@@ -5589,13 +5587,6 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
*/
#define DC_STATE_IN_SEEN 16
/**
* Outgoing message being prepared. See dc_msg_get_state() for details.
*
* @deprecated 2024-12-07
*/
#define DC_STATE_OUT_PREPARING 18
/**
* Outgoing message drafted. See dc_msg_get_state() for details.
*/

View File

@@ -275,7 +275,7 @@ pub unsafe extern "C" fn dc_get_config(
.strdup()
} else {
match config::Config::from_str(&key)
.with_context(|| format!("Invalid key {:?}", &key))
.with_context(|| format!("Invalid key {key:?}"))
.log_err(ctx)
{
Ok(key) => ctx

View File

@@ -230,7 +230,6 @@ pub enum LotState {
MsgInFresh = 10,
MsgInNoticed = 13,
MsgInSeen = 16,
MsgOutPreparing = 18,
MsgOutDraft = 19,
MsgOutPending = 20,
MsgOutFailed = 24,
@@ -246,7 +245,6 @@ impl From<MessageState> for LotState {
InFresh => LotState::MsgInFresh,
InNoticed => LotState::MsgInNoticed,
InSeen => LotState::MsgInSeen,
OutPreparing => LotState::MsgOutPreparing,
OutDraft => LotState::MsgOutDraft,
OutPending => LotState::MsgOutPending,
OutFailed => LotState::MsgOutFailed,

View File

@@ -122,7 +122,7 @@ async fn poke_spec(context: &Context, spec: Option<&str>) -> bool {
let name_f = entry.file_name();
let name = name_f.to_string_lossy();
if name.ends_with(".eml") {
let path_plus_name = format!("{}/{}", &real_spec, name);
let path_plus_name = format!("{real_spec}/{name}");
println!("Import: {path_plus_name}");
if poke_eml_file(context, Path::new(&path_plus_name))
.await
@@ -133,11 +133,11 @@ async fn poke_spec(context: &Context, spec: Option<&str>) -> bool {
}
}
} else {
eprintln!("Import: Cannot open directory \"{}\".", &real_spec);
eprintln!("Import: Cannot open directory {real_spec:?}.");
return false;
}
}
println!("Import: {} items read from \"{}\".", read_cnt, &real_spec);
println!("Import: {read_cnt} items read from {real_spec:?}.");
if read_cnt > 0 {
context.emit_msgs_changed_without_ids();
}
@@ -179,7 +179,7 @@ async fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {
msg.get_id(),
if msg.get_showpadlock() { "🔒" } else { "" },
if msg.has_location() { "📍" } else { "" },
&contact_name,
contact_name,
contact_id,
msgtext,
if msg.has_html() { "[HAS-HTML]" } else { "" },
@@ -221,7 +221,7 @@ async fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {
},
statestr,
downloadstate,
&temp2,
temp2,
);
}
@@ -561,7 +561,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
.map_or_else(String::new, |prefix| format!("{prefix}: ")),
summary.text,
statestr,
&timestr,
timestr,
if chat.is_sending_locations() {
"📍"
} else {

View File

@@ -432,7 +432,7 @@ async fn handle_cmd(
{
println!("Open the following url, set mail_pw to the generated token and server_flags to 2:\n{oauth2_url}");
} else {
println!("OAuth2 not available for {}.", &addr);
println!("OAuth2 not available for {addr}.");
}
} else {
println!("oauth2: set addr first.");

View File

@@ -190,7 +190,6 @@ class MessageState(IntEnum):
IN_FRESH = 10
IN_NOTICED = 13
IN_SEEN = 16
OUT_PREPARING = 18
OUT_DRAFT = 19
OUT_PENDING = 20
OUT_FAILED = 24

View File

@@ -271,15 +271,6 @@ class Chat:
sent out. This is the same object as was passed in, which
has been modified with the new state of the core.
"""
if msg.is_out_preparing():
assert msg.id != 0
# get a fresh copy of dc_msg, the core needs it
maybe_msg = Message.from_db(self.account, msg.id)
if maybe_msg is not None:
msg = maybe_msg
else:
raise ValueError("message does not exist")
sent_id = lib.dc_send_msg(self.account._dc_context, self.id, msg._dc_msg)
if sent_id == 0:
raise ValueError("message could not be sent")
@@ -333,26 +324,6 @@ class Chat:
raise ValueError("message could not be sent")
return Message.from_db(self.account, sent_id)
def send_prepared(self, message):
"""send a previously prepared message.
:param message: a :class:`Message` instance previously returned by
:meth:`prepare_file`.
:raises ValueError: if message can not be sent.
:returns: a :class:`deltachat.message.Message` instance as sent out.
"""
assert message.id != 0 and message.is_out_preparing()
# get a fresh copy of dc_msg, the core needs it
msg = Message.from_db(self.account, message.id)
# pass 0 as chat-id because core-docs say it's ok when out-preparing
sent_id = lib.dc_send_msg(self.account._dc_context, 0, msg._dc_msg)
if sent_id == 0:
raise ValueError("message could not be sent")
assert sent_id == msg.id
# modify message in place to avoid bad state for the caller
msg._dc_msg = Message.from_db(self.account, sent_id)._dc_msg
def set_draft(self, message):
"""set message as draft.

View File

@@ -351,17 +351,12 @@ class Message:
def is_outgoing(self):
"""Return True if Message is outgoing."""
return lib.dc_msg_get_state(self._dc_msg) in (
const.DC_STATE_OUT_PREPARING,
const.DC_STATE_OUT_PENDING,
const.DC_STATE_OUT_FAILED,
const.DC_STATE_OUT_MDN_RCVD,
const.DC_STATE_OUT_DELIVERED,
)
def is_out_preparing(self):
"""Return True if Message is outgoing, but its file is being prepared."""
return self._msgstate == const.DC_STATE_OUT_PREPARING
def is_out_pending(self):
"""Return True if Message is outgoing, but is pending (no single checkmark)."""
return self._msgstate == const.DC_STATE_OUT_PENDING

View File

@@ -794,7 +794,7 @@ impl Config {
.with_push_subscriber(push_subscriber.clone())
.build()
.await
.with_context(|| format!("failed to create context from file {:?}", &dbfile))?;
.with_context(|| format!("failed to create context from file {dbfile:?}"))?;
// Try to open without a passphrase,
// but do not return an error if account is passphare-protected.
ctx.open("".to_string()).await?;

View File

@@ -2529,7 +2529,7 @@ async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> {
// running numbers, etc.
let filename: String = match viewtype_orig {
Viewtype::Voice => format!(
"voice-messsage_{}.{}",
"voice-messsage_{}.{suffix}",
chrono::Utc
.timestamp_opt(msg.timestamp_sort, 0)
.single()
@@ -2537,10 +2537,9 @@ async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> {
|| "YY-mm-dd_hh:mm:ss".to_string(),
|ts| ts.format("%Y-%m-%d_%H-%M-%S").to_string()
),
&suffix
),
Viewtype::Image | Viewtype::Gif => format!(
"image_{}.{}",
"image_{}.{suffix}",
chrono::Utc
.timestamp_opt(msg.timestamp_sort, 0)
.single()
@@ -2548,10 +2547,9 @@ async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> {
|| "YY-mm-dd_hh:mm:ss".to_string(),
|ts| ts.format("%Y-%m-%d_%H-%M-%S").to_string(),
),
&suffix,
),
Viewtype::Video => format!(
"video_{}.{}",
"video_{}.{suffix}",
chrono::Utc
.timestamp_opt(msg.timestamp_sort, 0)
.single()
@@ -2559,7 +2557,6 @@ async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> {
|| "YY-mm-dd_hh:mm:ss".to_string(),
|ts| ts.format("%Y-%m-%d_%H-%M-%S").to_string()
),
&suffix
),
_ => filename,
};
@@ -2613,7 +2610,7 @@ pub async fn send_msg(context: &Context, chat_id: ChatId, msg: &mut Message) ->
"chat_id cannot be a special chat: {chat_id}"
);
if msg.state != MessageState::Undefined && msg.state != MessageState::OutPreparing {
if msg.state != MessageState::Undefined {
msg.param.remove(Param::GuaranteeE2ee);
msg.param.remove(Param::ForcePlaintext);
// create_send_msg_jobs() will update `param` in the db.
@@ -2721,10 +2718,7 @@ async fn prepare_send_msg(
None
};
if matches!(
msg.state,
MessageState::Undefined | MessageState::OutPreparing
)
if msg.state == MessageState::Undefined
// Legacy SecureJoin "v*-request" messages are unencrypted.
&& msg.param.get_cmd() != SystemMessage::SecurejoinMessage
&& chat.is_encrypted(context).await?
@@ -2937,8 +2931,8 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) -
UPDATE msgs SET
timestamp=(
SELECT MAX(timestamp) FROM msgs INDEXED BY msgs_index7 WHERE
-- From `InFresh` to `OutMdnRcvd` inclusive except `OutDraft`.
state IN(10,13,16,18,20,24,26,28) AND
-- From `InFresh` to `OutDelivered` inclusive, except `OutDraft`.
state IN(10,13,16,18,20,24,26) AND
hidden IN(0,1) AND
chat_id=? AND
id<=?
@@ -4539,6 +4533,7 @@ pub async fn forward_msgs_2ctx(
msg.state = MessageState::OutPending;
msg.rfc724_mid = create_outgoing_rfc724_mid();
msg.pre_rfc724_mid.clear();
msg.timestamp_sort = curr_timestamp;
chat.prepare_msg_raw(ctx_dst, &mut msg, None).await?;

View File

@@ -707,8 +707,7 @@ async fn get_autoconfig(
ctx,
// the doc does not mention `emailaddress=`, however, Thunderbird adds it, see <https://releases.mozilla.org/pub/thunderbird/>, which makes some sense
&format!(
"https://{}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={}",
&param_domain, &param_addr_urlencoded
"https://{param_domain}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={param_addr_urlencoded}"
),
&param.addr,
)
@@ -721,7 +720,7 @@ async fn get_autoconfig(
// Outlook uses always SSL but different domains (this comment describes the next two steps)
if let Ok(res) = outlk_autodiscover(
ctx,
format!("https://{}/autodiscover/autodiscover.xml", &param_domain),
format!("https://{param_domain}/autodiscover/autodiscover.xml"),
)
.await
{
@@ -731,10 +730,7 @@ async fn get_autoconfig(
if let Ok(res) = outlk_autodiscover(
ctx,
format!(
"https://autodiscover.{}/autodiscover/autodiscover.xml",
&param_domain
),
format!("https://autodiscover.{param_domain}/autodiscover/autodiscover.xml",),
)
.await
{
@@ -745,7 +741,7 @@ async fn get_autoconfig(
// always SSL for Thunderbird's database
if let Ok(res) = moz_autoconfigure(
ctx,
&format!("https://autoconfig.thunderbird.net/v1.1/{}", &param_domain),
&format!("https://autoconfig.thunderbird.net/v1.1/{param_domain}"),
&param.addr,
)
.await

View File

@@ -1045,15 +1045,12 @@ impl Session {
if target.is_empty() {
self.delete_message_batch(context, &uid_set, rowid_set)
.await
.with_context(|| format!("cannot delete batch of messages {:?}", &uid_set))?;
.with_context(|| format!("cannot delete batch of messages {uid_set:?}"))?;
} else {
self.move_message_batch(context, &uid_set, rowid_set, &target)
.await
.with_context(|| {
format!(
"cannot move batch of messages {:?} to folder {:?}",
&uid_set, target
)
format!("cannot move batch of messages {uid_set:?} to folder {target:?}",)
})?;
}
}
@@ -1287,9 +1284,10 @@ impl Session {
for (request_uids, set) in build_sequence_sets(&request_uids)? {
info!(context, "Starting UID FETCH of message set \"{}\".", set);
let mut fetch_responses = self.uid_fetch(&set, BODY_FULL).await.with_context(|| {
format!("fetching messages {} from folder \"{}\"", &set, folder)
})?;
let mut fetch_responses = self
.uid_fetch(&set, BODY_FULL)
.await
.with_context(|| format!("fetching messages {set} from folder {folder:?}"))?;
// Map from UIDs to unprocessed FETCH results. We put unprocessed FETCH results here
// when we want to process other messages first.

View File

@@ -222,7 +222,7 @@ SELECT ?1, rfc724_mid, pre_rfc724_mid, timestamp, ?, ? FROM msgs WHERE id=?1
} else {
msg.timestamp_sort
});
ret += &format!("Received: {}", &s);
ret += &format!("Received: {s}");
ret += "\n";
}
@@ -301,7 +301,7 @@ SELECT ?1, rfc724_mid, pre_rfc724_mid, timestamp, ?, ? FROM msgs WHERE id=?1
ret += "Type: ";
ret += &format!("{}", msg.viewtype);
ret += "\n";
ret += &format!("Mimetype: {}\n", &msg.get_filemime().unwrap_or_default());
ret += &format!("Mimetype: {}\n", msg.get_filemime().unwrap_or_default());
}
let w = msg.param.get_int(Param::Width).unwrap_or_default();
let h = msg.param.get_int(Param::Height).unwrap_or_default();
@@ -1381,13 +1381,8 @@ pub enum MessageState {
/// IMAP and MDN may be sent.
InSeen = 16,
/// For files which need time to be prepared before they can be
/// sent, the message enters this state before
/// OutPending.
///
/// Deprecated 2024-12-07.
OutPreparing = 18,
// Deprecated 2024-12-07. Removed 2026-04.
// OutPreparing = 18,
/// Message saved as draft.
OutDraft = 19,
@@ -1420,7 +1415,6 @@ impl std::fmt::Display for MessageState {
Self::InFresh => "Fresh",
Self::InNoticed => "Noticed",
Self::InSeen => "Seen",
Self::OutPreparing => "Preparing",
Self::OutDraft => "Draft",
Self::OutPending => "Pending",
Self::OutFailed => "Failed",
@@ -1437,7 +1431,7 @@ impl MessageState {
use MessageState::*;
matches!(
self,
OutPreparing | OutPending | OutDelivered | OutMdnRcvd // OutMdnRcvd can still fail because it could be a group message and only some recipients failed.
OutPending | OutDelivered | OutMdnRcvd // OutMdnRcvd can still fail because it could be a group message and only some recipients failed.
)
}
@@ -1446,7 +1440,7 @@ impl MessageState {
use MessageState::*;
matches!(
self,
OutPreparing | OutDraft | OutPending | OutFailed | OutDelivered | OutMdnRcvd
OutDraft | OutPending | OutFailed | OutDelivered | OutMdnRcvd
)
}

View File

@@ -332,7 +332,7 @@ fn inner_generate_secure_join_qr_code(
d.attr("cx", logo_position_x + HALF_LOGO_SIZE)?;
d.attr("cy", logo_position_y + HALF_LOGO_SIZE)?;
d.attr("r", HALF_LOGO_SIZE)?;
d.attr("style", format!("fill:{}", &color))
d.attr("style", format!("fill:{color}"))
})?;
let avatar_font_size = LOGO_SIZE * 0.65;

View File

@@ -66,12 +66,6 @@ impl Context {
/// Updates `quota.recent`, sets `quota.modified` to the current time
/// and emits an event to let the UIs update connectivity view.
///
/// Moreover, once each time quota gets larger than `QUOTA_WARN_THRESHOLD_PERCENTAGE`,
/// a device message is added.
/// As the message is added only once, the user is not spammed
/// in case for some providers the quota is always at ~100%
/// and new space is allocated as needed.
pub(crate) async fn update_recent_quota(
&self,
session: &mut ImapSession,

View File

@@ -806,8 +806,6 @@ UPDATE config SET value=? WHERE keyname='configured_addr' AND value!=?1
if transport_changed {
info!(context, "Primary transport changed to {from_addr:?}.");
context.sql.uncache_raw_config("configured_addr").await;
// Regenerate User ID in V4 keys.
context.self_public_key.lock().await.take();
context.emit_event(EventType::TransportsModified);
@@ -3562,12 +3560,7 @@ async fn create_or_lookup_mailinglist_or_broadcast(
mime_parser.timestamp_sent,
)
.await
.with_context(|| {
format!(
"failed to create mailinglist '{}' for grpid={}",
&name, &listid
)
})?;
.with_context(|| format!("failed to create mailinglist '{name}' for grpid={listid}",))?;
if chattype == Chattype::InBroadcast {
chat::add_to_chat_contacts_table(

View File

@@ -218,7 +218,7 @@ pub(crate) fn maybe_network_lost(context: &Context, stores: Vec<ConnectivityStor
impl fmt::Debug for ConnectivityStore {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(guard) = self.0.try_lock() {
write!(f, "ConnectivityStore {:?}", &*guard)
write!(f, "ConnectivityStore {:?}", *guard)
} else {
write!(f, "ConnectivityStore [LOCKED]")
}

View File

@@ -73,8 +73,7 @@ fn shorten_name(name: &str, length: usize) -> String {
// We use _ rather than ... to avoid dots at the end of the URL, which would confuse linkifiers
format!(
"{}_",
&name
.chars()
name.chars()
.take(length.saturating_sub(1))
.collect::<String>()
)

View File

@@ -992,7 +992,7 @@ async fn test_wrong_auth_token() -> Result<()> {
tcm.send_recv(alice, bob, "hi").await;
let alice_qr = get_securejoin_qr(alice, None).await?;
println!("{}", &alice_qr);
println!("{alice_qr}");
let invalid_alice_qr = alice_qr.replace("&s=", "&s=INVALIDAUTHTOKEN&someotherkey=");
join_securejoin(bob, &invalid_alice_qr).await?;

View File

@@ -2373,6 +2373,18 @@ ALTER TABLE contacts ADD COLUMN name_normalized TEXT;
.await?;
}
inc_and_check(&mut migration_version, 152)?;
if dbversion < migration_version {
sql.execute_migration(
"
UPDATE msgs SET state=26 WHERE state=28; -- Change OutMdnRcvd to OutDelivered.
UPDATE msgs SET state=19 WHERE state=24; -- Change OutPreparing to OutFailed.
",
migration_version,
)
.await?;
}
let new_version = sql
.get_raw_config_int(VERSION_CFG)
.await?

View File

@@ -1685,7 +1685,7 @@ async fn write_msg(context: &Context, prefix: &str, msg: &Message, buf: &mut Str
msg.get_id(),
if msg.get_showpadlock() { "🔒" } else { "" },
if msg.has_location() { "📍" } else { "" },
&contact_name,
contact_name,
contact_id,
msgtext,
if msg.get_from_id() == ContactId::SELF {

View File

@@ -161,7 +161,7 @@ async fn check_that_transition_worked(
2,
"Group {} has members {:?}, but should have members {:?} and {:?}",
group,
&members,
members,
alice_contact_id,
ContactId::SELF
);

View File

@@ -1,4 +1,6 @@
//! Tests about forwarding and saving Pre-Messages
use std::time::Duration;
use anyhow::Result;
use pretty_assertions::assert_eq;
@@ -8,6 +10,7 @@ use crate::chatlist::get_last_message_for_chat;
use crate::download::{DownloadState, PRE_MSG_ATTACHMENT_SIZE_THRESHOLD};
use crate::message::{Message, Viewtype};
use crate::test_utils::TestContextManager;
use crate::tests::pre_messages::util::send_large_file_message;
/// Test that forwarding Pre-Message should forward additional text to not be empty
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
@@ -86,6 +89,43 @@ async fn test_forwarding_pre_message_empty_text() -> Result<()> {
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_receive_both() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let bob = &tcm.bob().await;
let alice_chat_id = alice.create_group_with_members("", &[bob]).await;
let (pre_message, post_message, alice_msg_id) =
send_large_file_message(alice, alice_chat_id, Viewtype::File, &vec![0u8; 200_000]).await?;
let msg = bob.recv_msg(&pre_message).await;
let _ = bob.recv_msg_trash(&post_message).await;
let msg = Message::load_from_db(bob, msg.id).await?;
assert_eq!(msg.download_state(), DownloadState::Done);
assert_eq!(msg.text, "test".to_owned());
forward_msgs(alice, &[alice_msg_id], alice_chat_id).await?;
let rev_order = false;
let msg = bob
.recv_msg(
&alice
.pop_sent_msg_ex(rev_order, Duration::ZERO)
.await
.unwrap(),
)
.await;
assert_eq!(msg.download_state(), DownloadState::Available);
assert_eq!(msg.is_forwarded(), true);
assert_eq!(msg.text, "test".to_owned());
let _ = bob.recv_msg_trash(&alice.pop_sent_msg().await).await;
let msg = Message::load_from_db(bob, msg.id).await?;
assert_eq!(msg.download_state(), DownloadState::Done);
assert_eq!(msg.is_forwarded(), true);
assert_eq!(msg.text, "test".to_owned());
Ok(())
}
/// Test that forwarding Pre-Message should forward additional text to not be empty
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_saving_pre_message_empty_text() -> Result<()> {

View File

@@ -62,13 +62,13 @@ pub(crate) fn truncate(buf: &str, approx_chars: usize) -> Cow<'_, str> {
if let Some(index) = buf.get(..end_pos).and_then(|s| s.rfind([' ', '\n'])) {
Cow::Owned(format!(
"{}{}",
&buf.get(..=index).unwrap_or_default(),
buf.get(..=index).unwrap_or_default(),
DC_ELLIPSIS
))
} else {
Cow::Owned(format!(
"{}{}",
&buf.get(..end_pos).unwrap_or_default(),
buf.get(..end_pos).unwrap_or_default(),
DC_ELLIPSIS
))
}

View File

@@ -247,12 +247,12 @@ proptest! {
assert!(
l <= approx_chars + el_len,
"buf: '{}' - res: '{}' - len {}, approx {}",
&buf, &res, res.len(), approx_chars
buf, res, res.len(), approx_chars
);
if buf.chars().count() > approx_chars + el_len {
let l = res.len();
assert_eq!(&res[l-5..l], "[...]", "missing ellipsis in {}", &res);
assert_eq!(&res[l-5..l], "[...]", "missing ellipsis in {res}");
}
}
}

View File

@@ -116,7 +116,7 @@ pub(crate) struct ConnectionCandidate {
impl fmt::Display for ConnectionCandidate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}:{}", &self.host, self.port, self.security)?;
write!(f, "{}:{}:{}", self.host, self.port, self.security)?;
Ok(())
}
}
@@ -131,7 +131,7 @@ pub(crate) struct ConfiguredServerLoginParam {
impl fmt::Display for ConfiguredServerLoginParam {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.connection, &self.user)?;
write!(f, "{}:{}", self.connection, self.user)?;
Ok(())
}
}
@@ -791,7 +791,18 @@ pub(crate) async fn sync_transports(
context
.sql
.transaction(|transaction| {
let configured_addr = transaction.query_row(
"SELECT value FROM config WHERE keyname='configured_addr'",
(),
|row| {
let addr: String = row.get(0)?;
Ok(addr)
},
)?;
for RemovedTransportData { addr, timestamp } in removed_transports {
if *addr == configured_addr {
continue;
}
modified |= transaction.execute(
"DELETE FROM transports
WHERE addr=? AND add_timestamp<=?",

View File

@@ -550,7 +550,7 @@ impl Context {
let send_now = !matches!(
instance.state,
MessageState::Undefined | MessageState::OutPreparing | MessageState::OutDraft
MessageState::Undefined | MessageState::OutDraft
);
status_update.uid = Some(create_id());