Skip to content

Commit ae0d404

Browse files
committed
fix: Order of messages if Sentbox is synced before Inbox
This fixes a Gmail-like scenario when outgoing messages are saved to Sentbox as well and it is fetched before Inbox by chance, by adding a new `OutRcvd` message state for received outgoing messages so that they can mingle with fresh incoming ones. As for `OutPending`, `OutDelivered` etc. messages, they are sent locally by the user and there's no need to make them more noticeable even if they are newer. All APIs still return `OutDelivered` instead of `OutRcvd` for compatibility.
1 parent 7e4d4cf commit ae0d404

File tree

14 files changed

+45
-26
lines changed

14 files changed

+45
-26
lines changed

deltachat-ffi/src/lib.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use deltachat::context::{Context, ContextBuilder};
2929
use deltachat::ephemeral::Timer as EphemeralTimer;
3030
use deltachat::imex::BackupProvider;
3131
use deltachat::key::preconfigure_keypair;
32-
use deltachat::message::MsgId;
32+
use deltachat::message::{MessageState, MsgId};
3333
use deltachat::qr_code_generator::{create_qr_svg, generate_backup_qr, get_securejoin_qr_svg};
3434
use deltachat::stock_str::StockMessage;
3535
use deltachat::webxdc::StatusUpdateSerial;
@@ -3344,7 +3344,11 @@ pub unsafe extern "C" fn dc_msg_get_state(msg: *mut dc_msg_t) -> libc::c_int {
33443344
return 0;
33453345
}
33463346
let ffi_msg = &*msg;
3347-
ffi_msg.message.get_state() as libc::c_int
3347+
let state = match ffi_msg.message.get_state() {
3348+
MessageState::OutRcvd => MessageState::OutDelivered,
3349+
s => s,
3350+
};
3351+
state as libc::c_int
33483352
}
33493353

33503354
#[no_mangle]

deltachat-ffi/src/lot.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ impl From<MessageState> for LotState {
240240
OutDraft => LotState::MsgOutDraft,
241241
OutPending => LotState::MsgOutPending,
242242
OutFailed => LotState::MsgOutFailed,
243-
OutDelivered => LotState::MsgOutDelivered,
243+
OutDelivered | OutRcvd => LotState::MsgOutDelivered,
244244
OutMdnRcvd => LotState::MsgOutMdnRcvd,
245245
}
246246
}

deltachat-jsonrpc/src/api/types/message.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use deltachat::contact::Contact;
99
use deltachat::context::Context;
1010
use deltachat::download;
1111
use deltachat::message::Message;
12+
use deltachat::message::MessageState;
1213
use deltachat::message::MsgId;
1314
use deltachat::message::Viewtype;
1415
use deltachat::reaction::get_msg_reactions;
@@ -149,6 +150,12 @@ impl MessageObject {
149150

150151
let parent_id = message.parent(context).await?.map(|m| m.get_id().to_u32());
151152

153+
let state = match message.get_state() {
154+
MessageState::OutRcvd => MessageState::OutDelivered,
155+
s => s,
156+
}
157+
.to_u32()
158+
.context("state conversion to number failed")?;
152159
let download_state = message.download_state().into();
153160

154161
let quote = if let Some(quoted_text) = message.quoted_text() {
@@ -212,10 +219,7 @@ impl MessageObject {
212219
has_location: message.has_location(),
213220
has_html: message.has_html(),
214221
view_type: message.get_viewtype().into(),
215-
state: message
216-
.get_state()
217-
.to_u32()
218-
.context("state conversion to number failed")?,
222+
state,
219223
error: message.error(),
220224

221225
timestamp: message.get_timestamp(),

src/chat.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,17 +1427,21 @@ impl ChatId {
14271427
// received message purely by timestamp. We could place it just before that seen
14281428
// message, but anyway the user may not notice it.
14291429
//
1430-
// NB: Received outgoing messages may break sorting of fresh incoming ones, but this
1431-
// shouldn't happen frequently. Seen incoming messages don't really break sorting of
1432-
// fresh ones, they rather mean that older incoming messages are actually seen as well.
1430+
// NB: Seen incoming messages don't really break sorting of fresh ones, they rather mean
1431+
// that older incoming messages are actually seen as well.
14331432
context
14341433
.sql
14351434
.query_row_optional(
14361435
"SELECT MAX(timestamp), MAX(IIF(state=?,timestamp_sent,0))
14371436
FROM msgs
1438-
WHERE chat_id=? AND hidden=0 AND state>?
1437+
WHERE chat_id=? AND hidden=0 AND state>? AND state!=?
14391438
HAVING COUNT(*) > 0",
1440-
(MessageState::InSeen, self, MessageState::InFresh),
1439+
(
1440+
MessageState::InSeen,
1441+
self,
1442+
MessageState::InFresh,
1443+
MessageState::OutRcvd,
1444+
),
14411445
|row| {
14421446
let ts: i64 = row.get(0)?;
14431447
let ts_sent_seen: i64 = row.get(1)?;
@@ -4444,6 +4448,7 @@ pub async fn resend_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> {
44444448
MessageState::OutPending
44454449
| MessageState::OutFailed
44464450
| MessageState::OutDelivered
4451+
| MessageState::OutRcvd
44474452
| MessageState::OutMdnRcvd => {
44484453
message::update_msg_state(context, msg.id, MessageState::OutPending).await?
44494454
}

src/message.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,6 +1453,9 @@ pub enum MessageState {
14531453
/// the OutFailed state if we get such a hint from the server.
14541454
OutDelivered = 26,
14551455

1456+
/// Received outgoing message sent by another MUA or device.
1457+
OutRcvd = 27,
1458+
14561459
/// Outgoing message read by the recipient (two checkmarks; this
14571460
/// requires goodwill on the receiver's side). Not used in the db for new messages.
14581461
OutMdnRcvd = 28,
@@ -1473,6 +1476,7 @@ impl std::fmt::Display for MessageState {
14731476
Self::OutPending => "Pending",
14741477
Self::OutFailed => "Failed",
14751478
Self::OutDelivered => "Delivered",
1479+
Self::OutRcvd => "Other MUA",
14761480
Self::OutMdnRcvd => "Read",
14771481
}
14781482
)
@@ -1485,7 +1489,9 @@ impl MessageState {
14851489
use MessageState::*;
14861490
matches!(
14871491
self,
1488-
OutPreparing | OutPending | OutDelivered | OutMdnRcvd // OutMdnRcvd can still fail because it could be a group message and only some recipients failed.
1492+
// OutMdnRcvd can still fail because it could be a group message and only some
1493+
// recipients failed.
1494+
OutPreparing | OutPending | OutDelivered | OutRcvd | OutMdnRcvd
14891495
)
14901496
}
14911497

@@ -1494,13 +1500,13 @@ impl MessageState {
14941500
use MessageState::*;
14951501
matches!(
14961502
self,
1497-
OutPreparing | OutDraft | OutPending | OutFailed | OutDelivered | OutMdnRcvd
1503+
OutPreparing | OutDraft | OutPending | OutFailed | OutDelivered | OutRcvd | OutMdnRcvd
14981504
)
14991505
}
15001506

15011507
/// Returns adjusted message state if the message has MDNs.
15021508
pub(crate) fn with_mdns(self, has_mdns: bool) -> Self {
1503-
if self == MessageState::OutDelivered && has_mdns {
1509+
if has_mdns && self >= MessageState::OutDelivered {
15041510
return MessageState::OutMdnRcvd;
15051511
}
15061512
self

src/mimeparser/mimeparser_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,7 +1522,7 @@ async fn test_ignore_read_receipt_to_self() -> Result<()> {
15221522
)
15231523
.await?;
15241524
let msg = alice.get_last_msg().await;
1525-
assert_eq!(msg.state, MessageState::OutDelivered);
1525+
assert_eq!(msg.state, MessageState::OutRcvd);
15261526

15271527
// Due to a bug in the old version running on the other device, Alice receives a read
15281528
// receipt from self.
@@ -1561,7 +1561,7 @@ async fn test_ignore_read_receipt_to_self() -> Result<()> {
15611561

15621562
// Check that the state has not changed to `MessageState::OutMdnRcvd`.
15631563
let msg = Message::load_from_db(&alice, msg.id).await?;
1564-
assert_eq!(msg.state, MessageState::OutDelivered);
1564+
assert_eq!(msg.state, MessageState::OutRcvd);
15651565

15661566
Ok(())
15671567
}

src/reaction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ Can we chat at 1pm pacific, today?"
476476
)
477477
.await?;
478478
let msg = alice.get_last_msg().await;
479-
assert_eq!(msg.state, MessageState::OutDelivered);
479+
assert_eq!(msg.state, MessageState::OutRcvd);
480480
let reactions = get_msg_reactions(&alice, msg.id).await?;
481481
let contacts = reactions.contacts();
482482
assert_eq!(contacts.len(), 0);

src/receive_imf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1708,7 +1708,7 @@ async fn add_parts(
17081708
};
17091709

17101710
let state = if !mime_parser.incoming {
1711-
MessageState::OutDelivered
1711+
MessageState::OutRcvd
17121712
} else if seen || is_mdn || chat_id_blocked == Blocked::Yes || group_changes.silent
17131713
// No check for `hidden` because only reactions are such and they should be `InFresh`.
17141714
{

src/receive_imf/receive_imf_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ async fn test_parse_ndn(
684684
if error_msg.is_some() {
685685
MessageState::OutFailed
686686
} else {
687-
MessageState::OutDelivered
687+
MessageState::OutRcvd
688688
}
689689
);
690690

@@ -4312,7 +4312,7 @@ async fn test_outgoing_msg_forgery() -> Result<()> {
43124312

43134313
let sent_msg = malice.send_text(malice_chat_id, "hi from malice").await;
43144314
let msg = alice.recv_msg(&sent_msg).await;
4315-
assert_eq!(msg.state, MessageState::OutDelivered);
4315+
assert_eq!(msg.state, MessageState::OutRcvd);
43164316
assert!(!msg.get_showpadlock());
43174317

43184318
Ok(())

src/tests/verified_chats.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ async fn test_old_message_5() -> Result<()> {
351351
.await?
352352
.unwrap();
353353

354-
assert!(msg_sent.sort_timestamp == msg_incoming.sort_timestamp);
354+
assert!(msg_incoming.sort_timestamp < msg_sent.sort_timestamp);
355355
alice
356356
.golden_test_chat(msg_sent.chat_id, "test_old_message_5")
357357
.await;

0 commit comments

Comments
 (0)