Skip to content

Commit bcea9c5

Browse files
committed
fix: Add Chat-Group-Name-Timestamp header and use it to update group names (#6412)
Add "Chat-Group-Name-Timestamp" message header and use the last-write-wins logic when updating group names (similar to group member timestamps). Note that if the "Chat-Group-Name-Changed" header is absent though, we don't add a system message (`MsgGrpNameChangedBy`) because we don't want to blame anyone.
1 parent 44f72e7 commit bcea9c5

File tree

7 files changed

+116
-11
lines changed

7 files changed

+116
-11
lines changed

src/chat.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3039,6 +3039,11 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) -
30393039
msg.state = MessageState::OutDelivered;
30403040
return Ok(Vec::new());
30413041
}
3042+
if msg.param.get_cmd() == SystemMessage::GroupNameChanged {
3043+
msg.chat_id
3044+
.update_timestamp(context, Param::GroupNameTimestamp, msg.timestamp_sort)
3045+
.await?;
3046+
}
30423047

30433048
let rendered_msg = match mimefactory.render(context).await {
30443049
Ok(res) => Ok(res),

src/headerdef.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ pub enum HeaderDef {
5757
ChatGroupId,
5858
ChatGroupName,
5959
ChatGroupNameChanged,
60+
ChatGroupNameTimestamp,
6061
ChatVerified,
6162
ChatGroupAvatar,
6263
ChatUserAvatar,

src/mimefactory.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,12 @@ impl MimeFactory {
11901190
"Chat-Group-Name",
11911191
mail_builder::headers::text::Text::new(chat.name.to_string()).into(),
11921192
));
1193+
if let Some(ts) = chat.param.get_i64(Param::GroupNameTimestamp) {
1194+
headers.push((
1195+
"Chat-Group-Name-Timestamp",
1196+
mail_builder::headers::text::Text::new(ts.to_string()).into(),
1197+
));
1198+
}
11931199

11941200
match command {
11951201
SystemMessage::MemberRemovedFromGroup => {

src/mimeparser.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ impl MimeMessage {
446446
HeaderDef::ChatGroupId,
447447
HeaderDef::ChatGroupName,
448448
HeaderDef::ChatGroupNameChanged,
449+
HeaderDef::ChatGroupNameTimestamp,
449450
HeaderDef::ChatGroupAvatar,
450451
HeaderDef::ChatGroupMemberRemoved,
451452
HeaderDef::ChatGroupMemberAdded,

src/receive_imf.rs

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2411,9 +2411,19 @@ async fn apply_group_changes(
24112411
}
24122412

24132413
better_msg = Some(stock_str::msg_add_member_local(context, added_addr, from_id).await);
2414-
} else if let Some(old_name) = mime_parser
2414+
}
2415+
2416+
let group_name_timestamp = mime_parser
2417+
.get_header(HeaderDef::ChatGroupNameTimestamp)
2418+
.and_then(|s| s.parse::<i64>().ok());
2419+
if let Some(old_name) = mime_parser
24152420
.get_header(HeaderDef::ChatGroupNameChanged)
24162421
.map(|s| s.trim())
2422+
.or(match group_name_timestamp {
2423+
Some(0) => None,
2424+
Some(_) => Some(chat.name.as_str()),
2425+
None => None,
2426+
})
24172427
{
24182428
if let Some(grpname) = mime_parser
24192429
.get_header(HeaderDef::ChatGroupName)
@@ -2422,13 +2432,15 @@ async fn apply_group_changes(
24222432
{
24232433
let grpname = &sanitize_single_line(grpname);
24242434
let old_name = &sanitize_single_line(old_name);
2425-
if chat_id
2426-
.update_timestamp(
2427-
context,
2428-
Param::GroupNameTimestamp,
2429-
mime_parser.timestamp_sent,
2430-
)
2431-
.await?
2435+
2436+
let chat_group_name_timestamp =
2437+
chat.param.get_i64(Param::GroupNameTimestamp).unwrap_or(0);
2438+
let group_name_timestamp = group_name_timestamp.unwrap_or(mime_parser.timestamp_sent);
2439+
// To provide group name consistency, compare names if timestamps are equal.
2440+
if (chat_group_name_timestamp, grpname) < (group_name_timestamp, old_name)
2441+
&& chat_id
2442+
.update_timestamp(context, Param::GroupNameTimestamp, group_name_timestamp)
2443+
.await?
24322444
{
24332445
info!(context, "Updating grpname for chat {chat_id}.");
24342446
context
@@ -2437,10 +2449,18 @@ async fn apply_group_changes(
24372449
.await?;
24382450
send_event_chat_modified = true;
24392451
}
2440-
2441-
better_msg = Some(stock_str::msg_grp_name(context, old_name, grpname, from_id).await);
2452+
if mime_parser
2453+
.get_header(HeaderDef::ChatGroupNameChanged)
2454+
.is_some()
2455+
{
2456+
better_msg.get_or_insert(
2457+
stock_str::msg_grp_name(context, old_name, grpname, from_id).await,
2458+
);
2459+
}
24422460
}
2443-
} else if let Some(value) = mime_parser.get_header(HeaderDef::ChatContent) {
2461+
}
2462+
2463+
if let (Some(value), None) = (mime_parser.get_header(HeaderDef::ChatContent), &better_msg) {
24442464
if value == "group-avatar-changed" {
24452465
if let Some(avatar_action) = &mime_parser.group_avatar {
24462466
// this is just an explicit message containing the group-avatar,

src/receive_imf/receive_imf_tests.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5428,6 +5428,40 @@ Hello!"
54285428
Ok(())
54295429
}
54305430

5431+
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
5432+
async fn test_rename_chat_on_missing_message() -> Result<()> {
5433+
let alice = TestContext::new_alice().await;
5434+
let bob = TestContext::new_bob().await;
5435+
let chat_id = create_group_chat(&alice, ProtectionStatus::Unprotected, "Group").await?;
5436+
add_to_chat_contacts_table(
5437+
&alice,
5438+
time(),
5439+
chat_id,
5440+
&[Contact::create(&alice, "bob", "[email protected]").await?],
5441+
)
5442+
.await?;
5443+
send_text_msg(&alice, chat_id, "populate".to_string()).await?;
5444+
let bob_chat_id = bob.recv_msg(&alice.pop_sent_msg().await).await.chat_id;
5445+
bob_chat_id.accept(&bob).await?;
5446+
5447+
// Bob changes the group name. NB: If Bob does this too fast, it's not guaranteed that his group
5448+
// name wins because "Group-Name-Timestamp" may not increase.
5449+
SystemTime::shift(Duration::from_secs(3600));
5450+
chat::set_chat_name(&bob, bob_chat_id, "Renamed").await?;
5451+
bob.pop_sent_msg().await;
5452+
5453+
// Bob adds a new member.
5454+
let bob_orange = Contact::create(&bob, "orange", "[email protected]").await?;
5455+
add_contact_to_chat(&bob, bob_chat_id, bob_orange).await?;
5456+
let add_msg = bob.pop_sent_msg().await;
5457+
5458+
// Alice only receives the member addition.
5459+
alice.recv_msg(&add_msg).await;
5460+
let chat = Chat::load_from_db(&alice, chat_id).await?;
5461+
assert_eq!(chat.get_name(), "Renamed");
5462+
Ok(())
5463+
}
5464+
54315465
/// Tests that creating a group
54325466
/// is preferred over assigning message to existing
54335467
/// chat based on `In-Reply-To` and `References`.

src/update_helper.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,44 @@ mod tests {
213213
// Assert that the \n was correctly removed from the group name also in the system message
214214
assert_eq!(msg.text.contains('\n'), false);
215215

216+
// This doesn't update the name because Date is the same and name is greater.
217+
receive_imf(
218+
&t,
219+
b"From: Bob Authname <[email protected]>\n\
220+
221+
Message-ID: <[email protected]>\n\
222+
Chat-Version: 1.0\n\
223+
Chat-Group-ID: abcde123456\n\
224+
Chat-Group-Name: another name update 4\n\
225+
Chat-Group-Name-Changed: another name update\n\
226+
Date: Sun, 22 Mar 2021 03:00:00 +0000\n\
227+
\n\
228+
4th message\n",
229+
false,
230+
)
231+
.await?;
232+
let chat = Chat::load_from_db(&t, chat.id).await?;
233+
assert_eq!(chat.name, "another name update");
234+
235+
// This updates the name because Date is the same and name is lower.
236+
receive_imf(
237+
&t,
238+
b"From: Bob Authname <[email protected]>\n\
239+
240+
Message-ID: <[email protected]>\n\
241+
Chat-Version: 1.0\n\
242+
Chat-Group-ID: abcde123456\n\
243+
Chat-Group-Name: another name updat\n\
244+
Chat-Group-Name-Changed: another name update\n\
245+
Date: Sun, 22 Mar 2021 03:00:00 +0000\n\
246+
\n\
247+
5th message\n",
248+
false,
249+
)
250+
.await?;
251+
let chat = Chat::load_from_db(&t, chat.id).await?;
252+
assert_eq!(chat.name, "another name updat");
253+
216254
Ok(())
217255
}
218256
}

0 commit comments

Comments
 (0)