Skip to content

Commit 8bbee4a

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 and appear after them in chats. 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 10aa308 commit 8bbee4a

File tree

13 files changed

+43
-25
lines changed

13 files changed

+43
-25
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;
@@ -3294,7 +3294,11 @@ pub unsafe extern "C" fn dc_msg_get_state(msg: *mut dc_msg_t) -> libc::c_int {
32943294
return 0;
32953295
}
32963296
let ffi_msg = &*msg;
3297-
ffi_msg.message.get_state() as libc::c_int
3297+
let state = match ffi_msg.message.get_state() {
3298+
MessageState::OutRcvd => MessageState::OutDelivered,
3299+
s => s,
3300+
};
3301+
state as libc::c_int
32983302
}
32993303

33003304
#[no_mangle]

deltachat-ffi/src/lot.rs

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

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use deltachat::contact::Contact;
77
use deltachat::context::Context;
88
use deltachat::download;
99
use deltachat::message::Message;
10+
use deltachat::message::MessageState;
1011
use deltachat::message::MsgId;
1112
use deltachat::message::Viewtype;
1213
use deltachat::reaction::get_msg_reactions;
@@ -132,6 +133,12 @@ impl MessageObject {
132133

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

136+
let state = match message.get_state() {
137+
MessageState::OutRcvd => MessageState::OutDelivered,
138+
s => s,
139+
}
140+
.to_u32()
141+
.context("state conversion to number failed")?;
135142
let download_state = message.download_state().into();
136143

137144
let quote = if let Some(quoted_text) = message.quoted_text() {
@@ -193,10 +200,7 @@ impl MessageObject {
193200
has_location: message.has_location(),
194201
has_html: message.has_html(),
195202
view_type: message.get_viewtype().into(),
196-
state: message
197-
.get_state()
198-
.to_u32()
199-
.context("state conversion to number failed")?,
203+
state,
200204
error: message.error(),
201205

202206
timestamp: message.get_timestamp(),

src/chat.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,9 +1443,14 @@ impl ChatId {
14431443
.query_row_optional(
14441444
"SELECT MAX(timestamp), MAX(IIF(state=?,timestamp_sent,0))
14451445
FROM msgs
1446-
WHERE chat_id=? AND hidden=0 AND state>?
1446+
WHERE chat_id=? AND hidden=0 AND state>? AND state!=?
14471447
HAVING COUNT(*) > 0",
1448-
(MessageState::InSeen, self, MessageState::InFresh),
1448+
(
1449+
MessageState::InSeen,
1450+
self,
1451+
MessageState::InFresh,
1452+
MessageState::OutRcvd,
1453+
),
14491454
|row| {
14501455
let ts: i64 = row.get(0)?;
14511456
let ts_sent_seen: i64 = row.get(1)?;
@@ -4262,6 +4267,7 @@ pub async fn resend_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> {
42624267
MessageState::OutPending
42634268
| MessageState::OutFailed
42644269
| MessageState::OutDelivered
4270+
| MessageState::OutRcvd
42654271
| MessageState::OutMdnRcvd => {
42664272
message::update_msg_state(context, msg.id, MessageState::OutPending).await?
42674273
}

src/message.rs

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

1370+
/// Received outgoing message sent by another MUA or device.
1371+
OutRcvd = 27,
1372+
13701373
/// Outgoing message read by the recipient (two checkmarks; this
13711374
/// requires goodwill on the receiver's side). Not used in the db for new messages.
13721375
OutMdnRcvd = 28,
@@ -1387,6 +1390,7 @@ impl std::fmt::Display for MessageState {
13871390
Self::OutPending => "Pending",
13881391
Self::OutFailed => "Failed",
13891392
Self::OutDelivered => "Delivered",
1393+
Self::OutRcvd => "Other MUA",
13901394
Self::OutMdnRcvd => "Read",
13911395
}
13921396
)
@@ -1399,7 +1403,9 @@ impl MessageState {
13991403
use MessageState::*;
14001404
matches!(
14011405
self,
1402-
OutPreparing | OutPending | OutDelivered | OutMdnRcvd // OutMdnRcvd can still fail because it could be a group message and only some recipients failed.
1406+
// OutMdnRcvd can still fail because it could be a group message and only some
1407+
// recipients failed.
1408+
OutPreparing | OutPending | OutDelivered | OutRcvd | OutMdnRcvd
14031409
)
14041410
}
14051411

@@ -1408,13 +1414,13 @@ impl MessageState {
14081414
use MessageState::*;
14091415
matches!(
14101416
self,
1411-
OutPreparing | OutDraft | OutPending | OutFailed | OutDelivered | OutMdnRcvd
1417+
OutPreparing | OutDraft | OutPending | OutFailed | OutDelivered | OutRcvd | OutMdnRcvd
14121418
)
14131419
}
14141420

14151421
/// Returns adjusted message state if the message has MDNs.
14161422
pub(crate) fn with_mdns(self, has_mdns: bool) -> Self {
1417-
if self == MessageState::OutDelivered && has_mdns {
1423+
if has_mdns && self >= MessageState::OutDelivered {
14181424
return MessageState::OutMdnRcvd;
14191425
}
14201426
self

src/mimeparser.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3778,7 +3778,7 @@ Message.
37783778
)
37793779
.await?;
37803780
let msg = alice.get_last_msg().await;
3781-
assert_eq!(msg.state, MessageState::OutDelivered);
3781+
assert_eq!(msg.state, MessageState::OutRcvd);
37823782

37833783
// Due to a bug in the old version running on the other device, Alice receives a read
37843784
// receipt from self.
@@ -3817,7 +3817,7 @@ Message.
38173817

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

38223822
Ok(())
38233823
}

src/reaction.rs

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

src/receive_imf.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,9 +1030,7 @@ async fn add_parts(
10301030
} else {
10311031
// Outgoing
10321032

1033-
// the mail is on the IMAP server, probably it is also delivered.
1034-
// We cannot recreate other states (read, error).
1035-
state = MessageState::OutDelivered;
1033+
state = MessageState::OutRcvd;
10361034
to_id = to_ids.first().copied().unwrap_or_default();
10371035

10381036
let self_sent = to_ids.len() == 1 && to_ids.contains(&ContactId::SELF);

src/receive_imf/tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ async fn test_read_receipt_and_unarchive() -> Result<()> {
326326
let msg = get_chat_msg(&t, group_id, 0, 1).await;
327327
assert_eq!(msg.is_dc_message, MessengerMessage::Yes);
328328
assert_eq!(msg.text, "hello");
329-
assert_eq!(msg.state, MessageState::OutDelivered);
329+
assert_eq!(msg.state, MessageState::OutRcvd);
330330
let group = Chat::load_from_db(&t, group_id).await?;
331331
assert!(group.get_visibility() == ChatVisibility::Normal);
332332

@@ -793,7 +793,7 @@ async fn test_parse_ndn(
793793
if error_msg.is_some() {
794794
MessageState::OutFailed
795795
} else {
796-
MessageState::OutDelivered
796+
MessageState::OutRcvd
797797
}
798798
);
799799

@@ -4538,7 +4538,7 @@ async fn test_outgoing_msg_forgery() -> Result<()> {
45384538

45394539
let sent_msg = malice.send_text(malice_chat_id, "hi from malice").await;
45404540
let msg = alice.recv_msg(&sent_msg).await;
4541-
assert_eq!(msg.state, MessageState::OutDelivered);
4541+
assert_eq!(msg.state, MessageState::OutRcvd);
45424542
assert!(!msg.get_showpadlock());
45434543

45444544
Ok(())

src/tests/verified_chats.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ async fn test_old_message_5() -> Result<()> {
540540
.await?
541541
.unwrap();
542542

543-
assert!(msg_sent.sort_timestamp == msg_incoming.sort_timestamp);
543+
assert!(msg_incoming.sort_timestamp < msg_sent.sort_timestamp);
544544
alice
545545
.golden_test_chat(msg_sent.chat_id, "test_old_message_5")
546546
.await;

0 commit comments

Comments
 (0)