[ADD/WIP] Bridging Matrix redacts

I'll still need to consider making redacts from other people count as
"moderations", whatever that is to Gajim, instead of a "self-redact".

Also, _please_, support it if you _ever_ wish adoption, XMPP users!
This commit is contained in:
LDA 2024-07-08 14:36:52 +02:00
commit 3c26ee6d22
5 changed files with 174 additions and 2 deletions

View file

@ -35,6 +35,8 @@ TODO
TODO
## TODOS
- Mess with Cytoplasm to make it have support for something like Berkeley DB as
an *optional* dependency. This should increase reliability and speed for anyone.
- PROPER FUCKING AVATARS
XEP-0084 IS THE WORST PIECE OF SHIT KNOWN TO MAN. If any Jabberbros want to
look at terrible code/XML and suggest things to have *proper* avatar support,

View file

@ -149,6 +149,77 @@ ParseeBotHandler(ParseeData *data, HashMap *event)
Free(profile);
CommandFree(cmd);
}
static const char *
GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to)
{
const char *type = NULL;
char *room_id = GrabString(event, 1, "room_id");
char *matrix_sender = GrabString(event, 1, "sender");
char *chat_id = NULL, *muc_id = NULL;
char *user;
DbRef *room_data;
HashMap *data_json;
XMPPComponent *jabber = data ? data->jabber : NULL;
bool direct = false;
if (!data || !event || !from || !to)
{
return NULL;
}
*from = NULL;
*to = NULL;
chat_id = ParseeGetFromRoomID(data, room_id);
room_data = DbLock(data->db, 3, "rooms", room_id, "data");
data_json = DbJson(room_data);
direct = GrabBoolean(data_json, 1, "is_direct");
type = direct ? "chat" : "groupchat";
user = GrabString(data_json, 1, "xmpp_user");
*from = ParseeEncodeMXID(matrix_sender);
if (direct)
{
*to = StrDuplicate(user);
Free(chat_id);
}
else
{
char *matrix_name, *muc_join_as;
muc_id = ParseeGetMUCID(data, chat_id);
if (!chat_id)
{
/* muc_id is already implied to be freed by this point */
Free(*from);
*from = NULL;
DbUnlock(data->db, room_data);
return NULL;
}
matrix_name = ASGetName(data->config, room_id, matrix_sender);
muc_join_as = StrConcat(4, muc_id, "/", matrix_name, "[p]");
XMPPJoinMUC(jabber, *from, muc_join_as);
*to = muc_id;
Free(matrix_name);
Free(muc_join_as);
}
Free(chat_id);
DbUnlock(data->db, room_data);
return type;
}
static void
ParseeMessageHandler(ParseeData *data, HashMap *event)
{
@ -316,9 +387,37 @@ ParseeEventHandler(ParseeData *data, HashMap *event)
}
else if (StrEquals(event_type, "m.room.redaction"))
{
Log(LOG_WARNING, "Unsupported event redaction %s", event_id);
char *from, *to;
char *redacted = GrabString(event, 1, "redacts");
char *redacted_stanza = NULL;
char *chat_id;
XMPPComponent *jabber = data->jabber;
const char *type = GetXMPPInformation(data, event, &from, &to);
chat_id = ParseeGetFromRoomID(data, room_id);
if (!ParseeGetOrigin(data, chat_id, redacted, &redacted_stanza))
{
ParseeGetDMOrigin(data, room_id, redacted, &redacted_stanza);
}
/* Some clients don't support retractions *at all*, which smell.
* This therefore serves as a fallback, just in case that fails. */
XMPPSendPlain(
jabber, from, to,
"[EDIT REDACT FROM PARSEE]",
(char *) type,
NULL, NULL, redacted,
NULL, redacted_stanza
);
XMPPRetract(jabber, from, to, (char *) type, redacted_stanza);
Free(redacted_stanza);
Free(chat_id);
Free(from);
Free(to);
/* TODO: Implement Matrix->XMPP redactions. */
}
}

View file

@ -15,6 +15,74 @@ XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, ch
Free(ident);
}
void
XMPPRetract(XMPPComponent *comp, char *fr, char *to, char *type, char *redact)
{
XMLElement *message;
char *ident = StrRandom(32), *from;
if (!comp || !fr || !to || !type || !redact)
{
Free(ident);
return;
}
message = XMLCreateTag("message");
XMLAddAttr(message, "from", (from = StrConcat(3, fr, "@", comp->host)));
XMLAddAttr(message, "to", to);
XMLAddAttr(message, "type", type);
XMLAddAttr(message, "id", ident);
{
XMLElement *apply_to, *retract, *body, *txt, *fallback;
apply_to = XMLCreateTag("apply-to");
XMLAddAttr(apply_to, "xmlns", "urn:xmpp:fasten:0");
XMLAddAttr(apply_to, "id", redact);
{
retract = XMLCreateTag("retract");
XMLAddAttr(retract, "xmlns", "urn:xmpp:message-retract:0");
XMLAddChild(apply_to, retract);
}
XMLAddChild(message, apply_to);
retract = XMLCreateTag("retract");
XMLAddAttr(retract, "xmlns", "urn:xmpp:message-retract:1");
XMLAddAttr(retract, "id", redact);
XMLAddChild(message, retract);
fallback = XMLCreateTag("fallback");
XMLAddAttr(fallback, "xmlns", "urn:xmpp:fallback:0");
XMLAddAttr(fallback, "for", "urn:xmpp:message-retract:0");
XMLAddChild(message, fallback);
fallback = XMLCreateTag("fallback");
XMLAddAttr(fallback, "xmlns", "urn:xmpp:fallback:0");
XMLAddAttr(fallback, "for", "urn:xmpp:message-retract:1");
XMLAddChild(message, fallback);
body = XMLCreateTag("body");
txt = XMLCreateText(
"This person attempted to retract a previous message, "
"but your client does not yet support the 0.4.1 version of "
"XEP-0424.\n\n"
"(_Parsee is jealous of being able to read such messages._)"
);
XMLAddChild(body, txt);
XMLAddChild(message, body);
}
pthread_mutex_lock(&comp->write_lock);
XMLEncode(comp->stream, message);
StreamFlush(comp->stream);
XMLFreeElement(message);
pthread_mutex_unlock(&comp->write_lock);
Free(from);
Free(ident);
}
void
XMPPSendPlainID(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, char *rst, char *rse, char *event_id, char *oob, char *edit, char *ident)
{

View file

@ -48,6 +48,7 @@ typedef struct XMPPIdentity {
char *category, *type, *lang, *name;
} XMPPIdentity;
/* Generates the JID of the Parsee bridge user. */
static char *
ParseeJID(ParseeData *data)
{
@ -548,6 +549,7 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
{
char *parsee = ParseeJID(args);
/* Subscribe to the sender's metadata node. */
XMLElement *ps = CreatePubsubRequest(
parsee, decode_from, "urn:xmpp:avatar:metadata"
);

View file

@ -31,6 +31,7 @@ extern void XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *r);
/* TODO: XMPP stuff, I don't fucking know, I'm not a Jabbernerd. */
extern void XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, char *rst, char *rse, char *event_id, char *oob, char *id);
extern void XMPPSendPlainID(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, char *rst, char *rse, char *event_id, char *oob, char *id, char *sid);
extern void XMPPRetract(XMPPComponent *comp, char *fr, char *to, char *type, char *redact);
/* Finishes a component stream, and doesn't free it. */
extern void XMPPFinishCompStream(XMPPComponent *stream);