mirror of
https://github.com/chatmail/core.git
synced 2026-04-06 15:42:10 +03:00
Compare commits
2 Commits
v2.43.0
...
iequidoo/s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
221526da63 | ||
|
|
1c282c01d1 |
10
src/chat.rs
10
src/chat.rs
@@ -3719,12 +3719,12 @@ pub(crate) async fn add_contact_to_chat_ex(
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Returns true if an avatar should be attached in the given chat.
|
||||
/// Returns whether profile data should be attached when sending to the given chat.
|
||||
///
|
||||
/// This function does not check if the avatar is set.
|
||||
/// This function does not check if the avatar/status is set.
|
||||
/// If avatar is not set and this function returns `true`,
|
||||
/// a `Chat-User-Avatar: 0` header should be sent to reset the avatar.
|
||||
pub(crate) async fn shall_attach_selfavatar(context: &Context, chat_id: ChatId) -> Result<bool> {
|
||||
pub(crate) async fn should_attach_profile(context: &Context, chat_id: ChatId) -> Result<bool> {
|
||||
let timestamp_some_days_ago = time() - DC_RESEND_USER_AVATAR_DAYS * 24 * 60 * 60;
|
||||
let needs_attach = context
|
||||
.sql
|
||||
@@ -3739,8 +3739,8 @@ pub(crate) async fn shall_attach_selfavatar(context: &Context, chat_id: ChatId)
|
||||
let mut needs_attach = false;
|
||||
for row in rows {
|
||||
let row = row?;
|
||||
let selfavatar_sent = row?;
|
||||
if selfavatar_sent < timestamp_some_days_ago {
|
||||
let profile_sent = row?;
|
||||
if profile_sent < timestamp_some_days_ago {
|
||||
needs_attach = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1531,23 +1531,23 @@ async fn test_create_same_chat_twice() {
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_shall_attach_selfavatar() -> Result<()> {
|
||||
async fn test_should_attach_profile() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = &tcm.alice().await;
|
||||
let bob = &tcm.bob().await;
|
||||
|
||||
let chat_id = create_group(alice, "foo").await?;
|
||||
assert!(!shall_attach_selfavatar(alice, chat_id).await?);
|
||||
assert!(!should_attach_profile(alice, chat_id).await?);
|
||||
|
||||
let contact_id = alice.add_or_lookup_contact_id(bob).await;
|
||||
add_contact_to_chat(alice, chat_id, contact_id).await?;
|
||||
assert!(shall_attach_selfavatar(alice, chat_id).await?);
|
||||
assert!(should_attach_profile(alice, chat_id).await?);
|
||||
|
||||
chat_id.set_selfavatar_timestamp(alice, time()).await?;
|
||||
assert!(!shall_attach_selfavatar(alice, chat_id).await?);
|
||||
assert!(!should_attach_profile(alice, chat_id).await?);
|
||||
|
||||
alice.set_config(Config::Selfavatar, None).await?; // setting to None also forces re-sending
|
||||
assert!(shall_attach_selfavatar(alice, chat_id).await?);
|
||||
assert!(should_attach_profile(alice, chat_id).await?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1571,7 +1571,7 @@ async fn test_profile_data_on_group_leave() -> Result<()> {
|
||||
tokio::fs::write(&file, bytes).await?;
|
||||
t.set_config(Config::Selfavatar, Some(file.to_str().unwrap()))
|
||||
.await?;
|
||||
assert!(shall_attach_selfavatar(t, chat_id).await?);
|
||||
assert!(should_attach_profile(t, chat_id).await?);
|
||||
|
||||
remove_contact_from_chat(t, chat_id, ContactId::SELF).await?;
|
||||
let sent_msg = t.pop_sent_msg().await;
|
||||
|
||||
@@ -758,6 +758,16 @@ impl Context {
|
||||
let better_value;
|
||||
|
||||
match key {
|
||||
Config::Selfstatus => {
|
||||
// Currently we send the self-status in every appropriate message, but in the future
|
||||
// (when most users upgrade to "feat: Don't reset key-contact status if
|
||||
// Chat-User-Avatar header is absent") we want to send it periodically together with
|
||||
// the self-avatar. This ensures the correct behavior after a possible Core upgrade.
|
||||
self.sql
|
||||
.execute("UPDATE contacts SET selfavatar_sent=0", ())
|
||||
.await?;
|
||||
self.sql.set_raw_config(key.as_ref(), value).await?;
|
||||
}
|
||||
Config::Selfavatar => {
|
||||
self.sql
|
||||
.execute("UPDATE contacts SET selfavatar_sent=0;", ())
|
||||
|
||||
@@ -278,7 +278,6 @@ async fn test_sync() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sync message mustn't be sent if self-{status,avatar} is changed by a self-sent message.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_no_sync_on_self_sent_msg() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
@@ -288,7 +287,7 @@ async fn test_no_sync_on_self_sent_msg() -> Result<()> {
|
||||
a.set_config_bool(Config::SyncMsgs, true).await?;
|
||||
}
|
||||
|
||||
let status = "Synced via usual message";
|
||||
let status = "Sent via usual message";
|
||||
alice0.set_config(Config::Selfstatus, Some(status)).await?;
|
||||
alice0.send_sync_msg().await?;
|
||||
alice0.pop_sent_sync_msg().await;
|
||||
@@ -297,7 +296,7 @@ async fn test_no_sync_on_self_sent_msg() -> Result<()> {
|
||||
tcm.send_recv(alice0, alice1, "hi Alice!").await;
|
||||
assert_eq!(
|
||||
alice1.get_config(Config::Selfstatus).await?,
|
||||
Some(status.to_string())
|
||||
Some(status1.to_string())
|
||||
);
|
||||
sync(alice1, alice0).await;
|
||||
assert_eq!(
|
||||
@@ -328,7 +327,7 @@ async fn test_no_sync_on_self_sent_msg() -> Result<()> {
|
||||
alice1
|
||||
.get_config(Config::Selfavatar)
|
||||
.await?
|
||||
.filter(|path| path.ends_with(".png"))
|
||||
.filter(|path| path.ends_with(".jpg"))
|
||||
.is_some()
|
||||
);
|
||||
sync(alice1, alice0).await;
|
||||
|
||||
@@ -383,11 +383,7 @@ async fn import_vcard_contact(context: &Context, contact: &VcardContact) -> Resu
|
||||
None => None,
|
||||
};
|
||||
if let Some(path) = path {
|
||||
// Currently this value doesn't matter as we don't import the contact of self.
|
||||
let was_encrypted = false;
|
||||
if let Err(e) =
|
||||
set_profile_image(context, id, &AvatarAction::Change(path), was_encrypted).await
|
||||
{
|
||||
if let Err(e) = set_profile_image(context, id, &AvatarAction::Change(path)).await {
|
||||
warn!(
|
||||
context,
|
||||
"import_vcard_contact: Could not set avatar for {}: {e:#}.", contact.addr
|
||||
@@ -395,7 +391,7 @@ async fn import_vcard_contact(context: &Context, contact: &VcardContact) -> Resu
|
||||
}
|
||||
}
|
||||
if let Some(biography) = &contact.biography {
|
||||
if let Err(e) = set_status(context, id, biography.to_owned(), false, false).await {
|
||||
if let Err(e) = set_status(context, id, biography.to_owned()).await {
|
||||
warn!(
|
||||
context,
|
||||
"import_vcard_contact: Could not set biography for {}: {e:#}.", contact.addr
|
||||
@@ -1818,25 +1814,19 @@ WHERE type=? AND id IN (
|
||||
/// The given profile image is expected to be already in the blob directory
|
||||
/// as profile images can be set only by receiving messages, this should be always the case, however.
|
||||
///
|
||||
/// For contact SELF, the image is not saved in the contact-database but as Config::Selfavatar;
|
||||
/// this typically happens if we see message with our own profile image.
|
||||
/// For contact SELF, the image is not saved in the contact-database but as Config::Selfavatar.
|
||||
pub(crate) async fn set_profile_image(
|
||||
context: &Context,
|
||||
contact_id: ContactId,
|
||||
profile_image: &AvatarAction,
|
||||
was_encrypted: bool,
|
||||
) -> Result<()> {
|
||||
let mut contact = Contact::get_by_id(context, contact_id).await?;
|
||||
let changed = match profile_image {
|
||||
AvatarAction::Change(profile_image) => {
|
||||
if contact_id == ContactId::SELF {
|
||||
if was_encrypted {
|
||||
context
|
||||
.set_config_ex(Nosync, Config::Selfavatar, Some(profile_image))
|
||||
.await?;
|
||||
} else {
|
||||
info!(context, "Do not use unencrypted selfavatar.");
|
||||
}
|
||||
context
|
||||
.set_config_ex(Nosync, Config::Selfavatar, Some(profile_image))
|
||||
.await?;
|
||||
} else {
|
||||
contact.param.set(Param::ProfileImage, profile_image);
|
||||
}
|
||||
@@ -1844,13 +1834,9 @@ pub(crate) async fn set_profile_image(
|
||||
}
|
||||
AvatarAction::Delete => {
|
||||
if contact_id == ContactId::SELF {
|
||||
if was_encrypted {
|
||||
context
|
||||
.set_config_ex(Nosync, Config::Selfavatar, None)
|
||||
.await?;
|
||||
} else {
|
||||
info!(context, "Do not use unencrypted selfavatar deletion.");
|
||||
}
|
||||
context
|
||||
.set_config_ex(Nosync, Config::Selfavatar, None)
|
||||
.await?;
|
||||
} else {
|
||||
contact.param.remove(Param::ProfileImage);
|
||||
}
|
||||
@@ -1867,22 +1853,16 @@ pub(crate) async fn set_profile_image(
|
||||
|
||||
/// Sets contact status.
|
||||
///
|
||||
/// For contact SELF, the status is not saved in the contact table, but as Config::Selfstatus. This
|
||||
/// is only done if message is sent from Delta Chat and it is encrypted, to synchronize signature
|
||||
/// between Delta Chat devices.
|
||||
/// For contact SELF, the status is not saved in the contact table, but as Config::Selfstatus.
|
||||
pub(crate) async fn set_status(
|
||||
context: &Context,
|
||||
contact_id: ContactId,
|
||||
status: String,
|
||||
encrypted: bool,
|
||||
has_chat_version: bool,
|
||||
) -> Result<()> {
|
||||
if contact_id == ContactId::SELF {
|
||||
if encrypted && has_chat_version {
|
||||
context
|
||||
.set_config_ex(Nosync, Config::Selfstatus, Some(&status))
|
||||
.await?;
|
||||
}
|
||||
context
|
||||
.set_config_ex(Nosync, Config::Selfstatus, Some(&status))
|
||||
.await?;
|
||||
} else {
|
||||
let mut contact = Contact::get_by_id(context, contact_id).await?;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::chat::{Chat, get_chat_contacts, send_text_msg};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::securejoin::get_securejoin_qr;
|
||||
use crate::test_utils::{self, TestContext, TestContextManager, TimeShiftFalsePositiveNote};
|
||||
use crate::test_utils::{self, TestContext, TestContextManager, TimeShiftFalsePositiveNote, sync};
|
||||
|
||||
#[test]
|
||||
fn test_contact_id_values() {
|
||||
@@ -846,8 +846,7 @@ CCCB 5AA9 F6E1 141C 9431
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Tests that status is synchronized when sending encrypted BCC-self messages and not
|
||||
/// synchronized when the message is not encrypted.
|
||||
/// Tests that self-status is not synchronized from outgoing messages.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_synchronize_status() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
@@ -866,21 +865,12 @@ async fn test_synchronize_status() -> Result<()> {
|
||||
.await?;
|
||||
let chat = alice1.create_email_chat(bob).await;
|
||||
|
||||
// Alice sends a message to Bob from the first device.
|
||||
// Alice sends an unencrypted message to Bob from the first device.
|
||||
send_text_msg(alice1, chat.id, "Hello".to_string()).await?;
|
||||
let sent_msg = alice1.pop_sent_msg().await;
|
||||
|
||||
// Message is not encrypted.
|
||||
let message = sent_msg.load_from_db().await;
|
||||
assert!(!message.get_showpadlock());
|
||||
|
||||
// Alice's second devices receives a copy of outgoing message.
|
||||
alice2.recv_msg(&sent_msg).await;
|
||||
|
||||
// Bob receives message.
|
||||
bob.recv_msg(&sent_msg).await;
|
||||
|
||||
// Message was not encrypted, so status is not copied.
|
||||
assert_eq!(alice2.get_config(Config::Selfstatus).await?, default_status);
|
||||
|
||||
// Alice sends encrypted message.
|
||||
@@ -888,17 +878,9 @@ async fn test_synchronize_status() -> Result<()> {
|
||||
send_text_msg(alice1, chat.id, "Hello".to_string()).await?;
|
||||
let sent_msg = alice1.pop_sent_msg().await;
|
||||
|
||||
// Second message is encrypted.
|
||||
let message = sent_msg.load_from_db().await;
|
||||
assert!(message.get_showpadlock());
|
||||
|
||||
// Alice's second devices receives a copy of second outgoing message.
|
||||
alice2.recv_msg(&sent_msg).await;
|
||||
|
||||
assert_eq!(
|
||||
alice2.get_config(Config::Selfstatus).await?,
|
||||
Some("New status".to_string())
|
||||
);
|
||||
assert_eq!(alice2.get_config(Config::Selfstatus).await?, default_status);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -911,9 +893,9 @@ async fn test_selfavatar_changed_event() -> Result<()> {
|
||||
// Alice has two devices.
|
||||
let alice1 = &tcm.alice().await;
|
||||
let alice2 = &tcm.alice().await;
|
||||
|
||||
// Bob has one device.
|
||||
let bob = &tcm.bob().await;
|
||||
for a in [alice1, alice2] {
|
||||
a.set_config_bool(Config::SyncMsgs, true).await?;
|
||||
}
|
||||
|
||||
assert_eq!(alice1.get_config(Config::Selfavatar).await?, None);
|
||||
|
||||
@@ -929,17 +911,7 @@ async fn test_selfavatar_changed_event() -> Result<()> {
|
||||
.get_matching(|e| matches!(e, EventType::SelfavatarChanged))
|
||||
.await;
|
||||
|
||||
// Alice sends a message.
|
||||
let alice1_chat_id = alice1.create_chat(bob).await.id;
|
||||
send_text_msg(alice1, alice1_chat_id, "Hello".to_string()).await?;
|
||||
let sent_msg = alice1.pop_sent_msg().await;
|
||||
|
||||
// The message is encrypted.
|
||||
let message = sent_msg.load_from_db().await;
|
||||
assert!(message.get_showpadlock());
|
||||
|
||||
// Alice's second device receives a copy of the outgoing message.
|
||||
alice2.recv_msg(&sent_msg).await;
|
||||
sync(alice1, alice2).await;
|
||||
|
||||
// Alice's second device applies the selfavatar.
|
||||
assert!(alice2.get_config(Config::Selfavatar).await?.is_some());
|
||||
|
||||
@@ -60,7 +60,12 @@ pub enum HeaderDef {
|
||||
ChatGroupNameTimestamp,
|
||||
ChatVerified,
|
||||
ChatGroupAvatar,
|
||||
|
||||
/// If present, contact's avatar and status should be applied from the message.
|
||||
/// "Chat-User-Avatar: 0" means that the contact has no avatar. Contact's status is transferred
|
||||
/// in the message footer.
|
||||
ChatUserAvatar,
|
||||
|
||||
ChatVoiceMessage,
|
||||
ChatGroupMemberRemoved,
|
||||
ChatGroupMemberAdded,
|
||||
|
||||
@@ -182,7 +182,7 @@ impl MimeFactory {
|
||||
pub async fn from_msg(context: &Context, msg: Message) -> Result<MimeFactory> {
|
||||
let now = time();
|
||||
let chat = Chat::load_from_db(context, msg.chat_id).await?;
|
||||
let attach_profile_data = Self::should_attach_profile_data(&msg);
|
||||
let can_transfer_profile = Self::can_transfer_profile(&msg);
|
||||
let undisclosed_recipients = chat.typ == Chattype::OutBroadcast;
|
||||
|
||||
let from_addr = context.get_primary_self_addr().await?;
|
||||
@@ -194,7 +194,7 @@ impl MimeFactory {
|
||||
if let Some(override_name) = msg.param.get(Param::OverrideSenderDisplayname) {
|
||||
(override_name.to_string(), Some(config_displayname))
|
||||
} else {
|
||||
let name = match attach_profile_data {
|
||||
let name = match can_transfer_profile {
|
||||
true => config_displayname,
|
||||
false => "".to_string(),
|
||||
};
|
||||
@@ -302,7 +302,7 @@ impl MimeFactory {
|
||||
} else {
|
||||
addr
|
||||
};
|
||||
let name = match attach_profile_data {
|
||||
let name = match can_transfer_profile {
|
||||
true => authname,
|
||||
false => "".to_string(),
|
||||
};
|
||||
@@ -451,14 +451,18 @@ impl MimeFactory {
|
||||
.split_ascii_whitespace()
|
||||
.map(|s| s.trim_start_matches('<').trim_end_matches('>').to_string())
|
||||
.collect();
|
||||
let selfstatus = match attach_profile_data {
|
||||
let should_attach_profile = Self::should_attach_profile(context, &msg).await;
|
||||
// TODO: (2025-08) Attach self-status in every message for compatibility with older
|
||||
// versions. Should be replaced with
|
||||
// `should_attach_profile || !is_encrypted && can_transfer_profile`.
|
||||
let selfstatus = match can_transfer_profile {
|
||||
true => context
|
||||
.get_config(Config::Selfstatus)
|
||||
.await?
|
||||
.unwrap_or_default(),
|
||||
false => "".to_string(),
|
||||
};
|
||||
let attach_selfavatar = Self::should_attach_selfavatar(context, &msg).await;
|
||||
let attach_selfavatar = should_attach_profile;
|
||||
|
||||
ensure_and_debug_assert!(
|
||||
member_timestamps.is_empty()
|
||||
@@ -551,7 +555,7 @@ impl MimeFactory {
|
||||
}
|
||||
}
|
||||
|
||||
fn should_attach_profile_data(msg: &Message) -> bool {
|
||||
fn can_transfer_profile(msg: &Message) -> bool {
|
||||
msg.param.get_cmd() != SystemMessage::SecurejoinMessage || {
|
||||
let step = msg.param.get(Param::Arg).unwrap_or_default();
|
||||
// Don't attach profile data at the earlier SecureJoin steps:
|
||||
@@ -566,14 +570,14 @@ impl MimeFactory {
|
||||
}
|
||||
}
|
||||
|
||||
async fn should_attach_selfavatar(context: &Context, msg: &Message) -> bool {
|
||||
Self::should_attach_profile_data(msg)
|
||||
&& match chat::shall_attach_selfavatar(context, msg.chat_id).await {
|
||||
async fn should_attach_profile(context: &Context, msg: &Message) -> bool {
|
||||
Self::can_transfer_profile(msg)
|
||||
&& match chat::should_attach_profile(context, msg.chat_id).await {
|
||||
Ok(should) => should,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
context,
|
||||
"should_attach_selfavatar: cannot get selfavatar state: {err:#}."
|
||||
"should_attach_profile: chat::should_attach_profile: {err:#}."
|
||||
);
|
||||
false
|
||||
}
|
||||
@@ -638,7 +642,7 @@ impl MimeFactory {
|
||||
return Ok(format!("Re: {}", remove_subject_prefix(last_subject)));
|
||||
}
|
||||
|
||||
let self_name = match Self::should_attach_profile_data(msg) {
|
||||
let self_name = match Self::can_transfer_profile(msg) {
|
||||
true => context.get_config(Config::Displayname).await?,
|
||||
false => None,
|
||||
};
|
||||
|
||||
@@ -992,42 +992,6 @@ Content-Disposition: reaction\n\
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Regression test for reaction resetting self-status.
|
||||
///
|
||||
/// Reactions do not contain the status,
|
||||
/// but should not result in self-status being reset on other devices.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_reaction_status_multidevice() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice1 = tcm.alice().await;
|
||||
let alice2 = tcm.alice().await;
|
||||
|
||||
alice1
|
||||
.set_config(Config::Selfstatus, Some("New status"))
|
||||
.await?;
|
||||
|
||||
let alice2_msg = tcm.send_recv(&alice1, &alice2, "Hi!").await;
|
||||
assert_eq!(
|
||||
alice2.get_config(Config::Selfstatus).await?.as_deref(),
|
||||
Some("New status")
|
||||
);
|
||||
|
||||
// Alice reacts to own message from second device,
|
||||
// first device receives rection.
|
||||
{
|
||||
send_reaction(&alice2, alice2_msg.id, "👍").await?;
|
||||
let msg = alice2.pop_sent_msg().await;
|
||||
alice1.recv_msg_hidden(&msg).await;
|
||||
}
|
||||
|
||||
// Check that the status is still the same.
|
||||
assert_eq!(
|
||||
alice1.get_config(Config::Selfstatus).await?.as_deref(),
|
||||
Some("New status")
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_send_reaction_multidevice() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
|
||||
@@ -886,7 +886,7 @@ pub(crate) async fn receive_imf_inner(
|
||||
}
|
||||
|
||||
if let Some(avatar_action) = &mime_parser.user_avatar {
|
||||
if from_id != ContactId::UNDEFINED
|
||||
if !matches!(from_id, ContactId::UNDEFINED | ContactId::SELF)
|
||||
&& context
|
||||
.update_contacts_timestamp(
|
||||
from_id,
|
||||
@@ -895,23 +895,19 @@ pub(crate) async fn receive_imf_inner(
|
||||
)
|
||||
.await?
|
||||
{
|
||||
if let Err(err) = contact::set_profile_image(
|
||||
context,
|
||||
from_id,
|
||||
avatar_action,
|
||||
mime_parser.was_encrypted(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
if let Err(err) = contact::set_profile_image(context, from_id, avatar_action).await {
|
||||
warn!(context, "receive_imf cannot update profile image: {err:#}.");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore footers from mailinglists as they are often created or modified by the mailinglist software.
|
||||
if let Some(footer) = &mime_parser.footer {
|
||||
if let Some(footer) = mime_parser.footer.as_ref().filter(|footer| {
|
||||
!footer.is_empty() || mime_parser.user_avatar.is_some() || !mime_parser.was_encrypted()
|
||||
}) {
|
||||
// Ignore footers from mailinglists as they are often created or modified by the mailinglist
|
||||
// software.
|
||||
if !mime_parser.is_mailinglist_message()
|
||||
&& from_id != ContactId::UNDEFINED
|
||||
&& !matches!(from_id, ContactId::UNDEFINED | ContactId::SELF)
|
||||
&& context
|
||||
.update_contacts_timestamp(
|
||||
from_id,
|
||||
@@ -920,15 +916,7 @@ pub(crate) async fn receive_imf_inner(
|
||||
)
|
||||
.await?
|
||||
{
|
||||
if let Err(err) = contact::set_status(
|
||||
context,
|
||||
from_id,
|
||||
footer.to_string(),
|
||||
mime_parser.was_encrypted(),
|
||||
mime_parser.has_chat_version(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
if let Err(err) = contact::set_status(context, from_id, footer.clone()).await {
|
||||
warn!(context, "Cannot update contact status: {err:#}.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2254,6 +2254,41 @@ sig thursday",
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_contact_status_from_encrypted_msg() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = &tcm.alice().await;
|
||||
let bob = &tcm.bob().await;
|
||||
|
||||
let alice_chat_id = alice.create_chat(bob).await.id;
|
||||
let sent = alice.send_text(alice_chat_id, "hi").await;
|
||||
bob.recv_msg(&sent).await;
|
||||
alice.set_config(Config::Selfstatus, Some("status")).await?;
|
||||
let sent = alice.send_text(alice_chat_id, "I've set self-status").await;
|
||||
bob.recv_msg(&sent).await;
|
||||
let bob_alice = bob.add_or_lookup_contact(alice).await;
|
||||
assert_eq!(bob_alice.get_status(), "status");
|
||||
|
||||
alice
|
||||
.set_config(Config::Selfstatus, Some("status1"))
|
||||
.await?;
|
||||
alice
|
||||
.send_text(alice_chat_id, "I changed self-status")
|
||||
.await;
|
||||
|
||||
// Currently we send self-status in every appropriate message.
|
||||
let sent = alice
|
||||
.send_text(alice_chat_id, "This message also contains my status")
|
||||
.await;
|
||||
let parsed_msg = bob.parse_msg(&sent).await;
|
||||
assert!(parsed_msg.was_encrypted());
|
||||
assert!(parsed_msg.get_header(HeaderDef::ChatUserAvatar).is_none());
|
||||
bob.recv_msg(&sent).await;
|
||||
let bob_alice = bob.add_or_lookup_contact(alice).await;
|
||||
assert_eq!(bob_alice.get_status(), "status1");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_chat_assignment_private_classical_reply() {
|
||||
for outgoing_is_classical in &[true, false] {
|
||||
|
||||
Reference in New Issue
Block a user