plugin XEP-0308: fix message edit for MUC private messages:
- Keep the destination resource when resending the correction (e.g. `room/nick`). - Match the corrected message by id (fallback: last message from the sender). - Ignore corrections that can't be matched, or whose content is already applied (e.g. own corrections redelivered by MAM).
This commit is contained in:
parent
2cfe6c7a82
commit
403b9e9d31
1 changed files with 54 additions and 38 deletions
|
|
@ -163,58 +163,73 @@ class XEP_0308:
|
|||
replace_elt = next(message_elt.elements(NS_MESSAGE_CORRECT, "replace"), None)
|
||||
if not replace_elt:
|
||||
return True
|
||||
try:
|
||||
replace_id = replace_elt["id"].strip()
|
||||
if not replace_id:
|
||||
raise KeyError
|
||||
except KeyError:
|
||||
replace_id = (replace_elt.getAttribute("id") or "").strip()
|
||||
if not replace_id:
|
||||
log.warning(f"Invalid message correction: {message_elt.toXml()}")
|
||||
else:
|
||||
return False
|
||||
# look for the corrected message by id (this also handles our own messages, e.g.
|
||||
# corrections from another device)
|
||||
message_type = message_elt.getAttribute("type", C.MESS_TYPE_NORMAL)
|
||||
edited_history = await self.host.memory.storage.get_history_from_xmpp_id(
|
||||
client, replace_id, message_type
|
||||
)
|
||||
if edited_history is None:
|
||||
# Fallback: last message from the sender (history without usable id)
|
||||
edited_history = await self.get_last_history(client, message_elt)
|
||||
if edited_history is None:
|
||||
log.warning(
|
||||
f"No message found from {from_jid.full()}, can't correct "
|
||||
f"anything: {message_elt.toXml()}"
|
||||
f"No message found to correct ({replace_id}), ignoring "
|
||||
f"correction: {message_elt.toXml()}"
|
||||
)
|
||||
return True
|
||||
return False
|
||||
check_id = edited_history.origin_id or edited_history.extra.get("message_id")
|
||||
if check_id != replace_id:
|
||||
log.warning(
|
||||
"Can't apply correction: it doesn't reference the last one:\n"
|
||||
f"{message_elt.toXml()}"
|
||||
)
|
||||
return True
|
||||
# TODO: this only accept same full JID, if we do more than last message
|
||||
# correction, we may want to accept different resource for non groupchat
|
||||
# messages (in case of reconnection with resource change for instance).
|
||||
if edited_history.source_jid != from_jid:
|
||||
log.warning(
|
||||
"Can't apply correction: correction doesn't come from same author "
|
||||
f"{edited_history.source_jid.full()}:\n{message_elt.toXml()}"
|
||||
)
|
||||
return True
|
||||
|
||||
previous_message_data = edited_history.serialise()
|
||||
message_data = await client.messageProt.parse_message(message_elt)
|
||||
if not message_data["message"] and not message_data["subject"]:
|
||||
log.warning(
|
||||
"Message correction doesn't have body nor subject, we can't edit "
|
||||
"anything"
|
||||
)
|
||||
return False
|
||||
|
||||
await self.update_history(
|
||||
client,
|
||||
edited_history,
|
||||
message_data.get("received_timestamp") or message_data["timestamp"],
|
||||
message_data["message"],
|
||||
message_data["subject"],
|
||||
message_data["extra"],
|
||||
previous_message_data["message"],
|
||||
previous_message_data["subject"],
|
||||
previous_message_data.get("extra"),
|
||||
# for groupchat, the correction must come from the same occupant, for other types,
|
||||
# the resource may have changed (e.g. reconnection)
|
||||
same_author = (
|
||||
edited_history.source_jid == from_jid
|
||||
if edited_history.type == C.MESS_TYPE_GROUPCHAT
|
||||
else edited_history.source_jid.userhost() == from_jid.userhost()
|
||||
)
|
||||
if not same_author:
|
||||
log.warning(
|
||||
"Can't apply correction: correction doesn't come from same author "
|
||||
f"{edited_history.source_jid.full()}:\n{message_elt.toXml()}"
|
||||
)
|
||||
return False
|
||||
|
||||
previous_message_data = edited_history.serialise()
|
||||
message_data = await client.messageProt.parse_message(message_elt)
|
||||
if not message_data["message"] and not message_data["subject"]:
|
||||
log.warning(
|
||||
"Message correction doesn't have body nor subject, we can't edit anything"
|
||||
)
|
||||
return False
|
||||
if (
|
||||
message_data["message"] == previous_message_data["message"]
|
||||
and message_data["subject"] == previous_message_data["subject"]
|
||||
):
|
||||
# content is already up to date (e.g. our own correction redelivered by MAM
|
||||
# after reconnection)
|
||||
log.debug(f"Ignoring already applied correction: {message_elt.toXml()}")
|
||||
return False
|
||||
|
||||
await self.update_history(
|
||||
client,
|
||||
edited_history,
|
||||
message_data.get("received_timestamp") or message_data["timestamp"],
|
||||
message_data["message"],
|
||||
message_data["subject"],
|
||||
message_data["extra"],
|
||||
previous_message_data["message"],
|
||||
previous_message_data["subject"],
|
||||
previous_message_data.get("extra"),
|
||||
)
|
||||
return False
|
||||
|
||||
async def message_edit(
|
||||
|
|
@ -248,7 +263,8 @@ class XEP_0308:
|
|||
peer_jid = edited_history.source_jid
|
||||
else:
|
||||
is_group_chat = False
|
||||
peer_jid = jid.JID(edited_history.dest)
|
||||
# keep the destination resource (e.g. room/nick for a MUC private message)
|
||||
peer_jid = edited_history.dest_jid
|
||||
history_data = await self.host.memory.history_get(
|
||||
client.jid, peer_jid, limit=1, profile=client.profile
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue