feat: Get rid of MessageState::{OutPreparing, OutMdnRcvd} in the db

`OutPreparing` is deprecated since 2024-12-07, replace it with `OutDraft` to let the user review
such messages if any. `OutMdnRcvd` is not used in the db for new messages since
a30c6ae1f7, `OutDelivered` is stored instead.
This commit is contained in:
iequidoo
2026-04-14 08:36:04 -03:00
parent 82924952fb
commit b8b8e30002
9 changed files with 21 additions and 64 deletions

View File

@@ -4020,8 +4020,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. * Marked as read on IMAP and MDN may be sent. Use dc_markseen_msgs() to mark messages as being seen.
* *
* Outgoing message states: * 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_DRAFT - Message saved as draft using dc_set_draft()
* - @ref DC_STATE_OUT_PENDING - The user has pressed the "send" button but the * - @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). * message is not yet sent and is pending in some way. Maybe we're offline (no checkmark).
@@ -5604,13 +5602,6 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
*/ */
#define DC_STATE_IN_SEEN 16 #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. * Outgoing message drafted. See dc_msg_get_state() for details.
*/ */

View File

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

View File

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

View File

@@ -271,15 +271,6 @@ class Chat:
sent out. This is the same object as was passed in, which sent out. This is the same object as was passed in, which
has been modified with the new state of the core. 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) sent_id = lib.dc_send_msg(self.account._dc_context, self.id, msg._dc_msg)
if sent_id == 0: if sent_id == 0:
raise ValueError("message could not be sent") raise ValueError("message could not be sent")
@@ -333,26 +324,6 @@ class Chat:
raise ValueError("message could not be sent") raise ValueError("message could not be sent")
return Message.from_db(self.account, sent_id) 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): def set_draft(self, message):
"""set message as draft. """set message as draft.

View File

@@ -351,17 +351,12 @@ class Message:
def is_outgoing(self): def is_outgoing(self):
"""Return True if Message is outgoing.""" """Return True if Message is outgoing."""
return lib.dc_msg_get_state(self._dc_msg) in ( return lib.dc_msg_get_state(self._dc_msg) in (
const.DC_STATE_OUT_PREPARING,
const.DC_STATE_OUT_PENDING, const.DC_STATE_OUT_PENDING,
const.DC_STATE_OUT_FAILED, const.DC_STATE_OUT_FAILED,
const.DC_STATE_OUT_MDN_RCVD, const.DC_STATE_OUT_MDN_RCVD,
const.DC_STATE_OUT_DELIVERED, 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): def is_out_pending(self):
"""Return True if Message is outgoing, but is pending (no single checkmark).""" """Return True if Message is outgoing, but is pending (no single checkmark)."""
return self._msgstate == const.DC_STATE_OUT_PENDING return self._msgstate == const.DC_STATE_OUT_PENDING

View File

@@ -2623,7 +2623,7 @@ pub async fn send_msg(context: &Context, chat_id: ChatId, msg: &mut Message) ->
"chat_id cannot be a special chat: {chat_id}" "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::GuaranteeE2ee);
msg.param.remove(Param::ForcePlaintext); msg.param.remove(Param::ForcePlaintext);
// create_send_msg_jobs() will update `param` in the db. // create_send_msg_jobs() will update `param` in the db.
@@ -2731,10 +2731,7 @@ async fn prepare_send_msg(
None None
}; };
if matches!( if msg.state == MessageState::Undefined
msg.state,
MessageState::Undefined | MessageState::OutPreparing
)
// Legacy SecureJoin "v*-request" messages are unencrypted. // Legacy SecureJoin "v*-request" messages are unencrypted.
&& msg.param.get_cmd() != SystemMessage::SecurejoinMessage && msg.param.get_cmd() != SystemMessage::SecurejoinMessage
&& chat.is_encrypted(context).await? && chat.is_encrypted(context).await?
@@ -2947,8 +2944,8 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) -
UPDATE msgs SET UPDATE msgs SET
timestamp=( timestamp=(
SELECT MAX(timestamp) FROM msgs WHERE SELECT MAX(timestamp) FROM msgs WHERE
-- From `InFresh` to `OutMdnRcvd` inclusive except `OutDraft`. -- From `InFresh` to `OutDelivered` inclusive, except `OutDraft`.
state IN(10,13,16,18,20,24,26,28) AND state IN(10,13,16,18,20,24,26) AND
hidden IN(0,1) AND hidden IN(0,1) AND
chat_id=? chat_id=?
), ),

View File

@@ -1387,13 +1387,8 @@ pub enum MessageState {
/// IMAP and MDN may be sent. /// IMAP and MDN may be sent.
InSeen = 16, InSeen = 16,
/// For files which need time to be prepared before they can be // Deprecated 2024-12-07. Removed 2026-04.
/// sent, the message enters this state before // OutPreparing = 18,
/// OutPending.
///
/// Deprecated 2024-12-07.
OutPreparing = 18,
/// Message saved as draft. /// Message saved as draft.
OutDraft = 19, OutDraft = 19,
@@ -1426,7 +1421,6 @@ impl std::fmt::Display for MessageState {
Self::InFresh => "Fresh", Self::InFresh => "Fresh",
Self::InNoticed => "Noticed", Self::InNoticed => "Noticed",
Self::InSeen => "Seen", Self::InSeen => "Seen",
Self::OutPreparing => "Preparing",
Self::OutDraft => "Draft", Self::OutDraft => "Draft",
Self::OutPending => "Pending", Self::OutPending => "Pending",
Self::OutFailed => "Failed", Self::OutFailed => "Failed",
@@ -1443,7 +1437,7 @@ impl MessageState {
use MessageState::*; use MessageState::*;
matches!( matches!(
self, 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.
) )
} }
@@ -1452,7 +1446,7 @@ impl MessageState {
use MessageState::*; use MessageState::*;
matches!( matches!(
self, self,
OutPreparing | OutDraft | OutPending | OutFailed | OutDelivered | OutMdnRcvd OutDraft | OutPending | OutFailed | OutDelivered | OutMdnRcvd
) )
} }

View File

@@ -2376,6 +2376,18 @@ ALTER TABLE contacts ADD COLUMN name_normalized TEXT;
.await?; .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=18; -- Change OutPreparing to OutDraft.
",
migration_version,
)
.await?;
}
let new_version = sql let new_version = sql
.get_raw_config_int(VERSION_CFG) .get_raw_config_int(VERSION_CFG)
.await? .await?

View File

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