From fe77906cde59dd9afa174728d7477d936b870ecc Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 23 Jun 2024 23:46:46 +0200 Subject: [PATCH] [MOD] Carve the way to XMPP rich replies Bifrost could *never*! --- src/AS.c | 13 ++++++--- src/Events.c | 15 +++++++++++ src/MatrixEventHandler.c | 24 +++++++++++++++-- src/Parsee/User.c | 57 +++++++++++++++++++++++++++++++++++++--- src/XMPP/Stanza.c | 11 +++++++- src/XMPPThread.c | 12 +++++---- src/include/AS.h | 2 +- src/include/Matrix.h | 3 +++ src/include/Parsee.h | 5 +++- src/include/XMPP.h | 2 +- 10 files changed, 126 insertions(+), 18 deletions(-) diff --git a/src/AS.c b/src/AS.c index ee6f74a..367b058 100644 --- a/src/AS.c +++ b/src/AS.c @@ -169,16 +169,17 @@ ASSetState(const ParseeConfig *conf, char *id, char *type, char *key, char *mask HttpClientContextFree(ctx); JsonFree(state); } -void +char * ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c) { HttpClientContext *ctx = NULL; char *path, *params; - char *txn; + char *txn, *ret; + HashMap *reply; if (!conf || !id || !type || !user || !c) { JsonFree(c); - return; + return NULL; } txn = StrRandom(16); @@ -193,9 +194,15 @@ ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c) Free(path); ASAuthenticateRequest(conf, ctx); ParseeSetRequestJSON(ctx, c); + + reply = JsonDecode(HttpClientStream(ctx)); + ret = StrDuplicate(JsonValueAsString(HashMapGet(reply, "event_id"))); + JsonFree(reply); HttpClientContextFree(ctx); JsonFree(c); + + return ret; } char * ASCreateRoom(const ParseeConfig *conf, char *by, char *alias) diff --git a/src/Events.c b/src/Events.c index bbbbacf..c07779a 100644 --- a/src/Events.c +++ b/src/Events.c @@ -114,3 +114,18 @@ MatrixCreateMedia(char *mxc, char *body, char *mime) return map; } + +char * +MatrixGetReply(HashMap *event) +{ + if (!event) + { + return NULL; + } + + return StrDuplicate(JsonValueAsString( + JsonGet(event, 4, "content", + "m.relates_to", "m.in_reply_to", + "event_id") + )); +} diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 9a0e17f..2913082 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -69,16 +69,24 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) char *msgtype = GrabString(event, 2, "content", "msgtype"); char *body = GrabString(event, 2, "content", "body"); char *id = GrabString(event, 1, "room_id"); + char *ev_id = GrabString(event, 1, "event_id"); char *sender = GrabString(event, 1, "sender"); char *chat_id, *muc_id, *jid; + char *reply_id = MatrixGetReply(event); bool direct = false; if (ParseeIsPuppet(data->config, sender)) { + Free(reply_id); return; } + if (reply_id) + { + Log(LOG_INFO, "reply=%s", reply_id); + } + ref = DbLock(data->db, 3, "rooms", id, "data"); json = DbJson(ref); direct = JsonValueAsBoolean(HashMapGet(json, "is_direct")); @@ -89,9 +97,10 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) char *user = GrabString(json, 1, "xmpp_user"); char *local = ParseeEncodeMXID(sender); - XMPPSendPlain(jabber, local, user, body, NULL); + XMPPSendPlain(jabber, local, user, body, NULL, NULL, NULL); Free(local); + Free(reply_id); return; } @@ -100,6 +109,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) muc_id = ParseeGetMUCID(data, chat_id); if (!chat_id) { + Free(reply_id); return; } jid = ParseeEncodeMXID(sender); @@ -107,14 +117,24 @@ ParseeMessageHandler(ParseeData *data, HashMap *event) /* TODO: Check the name's validity */ char *name = ASGetName(data->config, NULL, sender); char *rev = StrConcat(3, muc_id, "/", name); + char *stanza = NULL, *sender = NULL; + if (reply_id) + { + ParseeGetStanzaInfo(data, chat_id, reply_id, &stanza, &sender); + + Log(LOG_INFO, "Replying to %s by %s", stanza, sender); + } XMPPJoinMUC(jabber, jid, rev); - XMPPSendPlain(jabber, jid, muc_id, body, "groupchat"); + XMPPSendPlain(jabber, jid, muc_id, body, "groupchat", stanza, sender); Free(rev); Free(name); + Free(stanza); + Free(sender); } Free(chat_id); Free(muc_id); Free(jid); + Free(reply_id); } void diff --git a/src/Parsee/User.c b/src/Parsee/User.c index 3b4cc30..ecfd1ff 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -541,14 +541,14 @@ ParseeGetMUCID(ParseeData *data, char *chat_id) } void -ParseePushStanza(ParseeData *data, char *chat_id, char *stanza_id) +ParseePushStanza(ParseeData *data, char *chat_id, char *stanza_id, char *ev, char *sender) { DbRef *ref; HashMap *j; - HashMap *stanzas, *obj; - bool new_stanzas = false; + HashMap *stanzas, *obj, *events; + bool new_stanzas = false, new_events = false; uint64_t age = UtilTsMillis(); - if (!data || !chat_id || !stanza_id) + if (!data || !chat_id || !stanza_id || !ev || !sender) { return; } @@ -576,6 +576,20 @@ ParseePushStanza(ParseeData *data, char *chat_id, char *stanza_id) HashMapSet(j, "stanzas", JsonValueObject(stanzas)); } + events = JsonValueAsObject(HashMapGet(j, "events")); + if (!events) + { + events = HashMapCreate(); + new_events = true; + } + obj = HashMapCreate(); + HashMapSet(obj, "stanza", JsonValueString(stanza_id)); + HashMapSet(obj, "sender", JsonValueString(sender)); + JsonValueFree(HashMapSet(events, ev, JsonValueObject(obj))); + if (new_events) + { + HashMapSet(j, "events", JsonValueObject(events)); + } DbUnlock(data->db, ref); } @@ -636,3 +650,38 @@ ParseeSendPresence(ParseeData *data) } DbUnlock(data->db, ref); } +bool +ParseeGetStanzaInfo(ParseeData *data, char *chat_id, char *ev, char **st, char **se) +{ + DbRef *ref = NULL; + HashMap *j = NULL; + HashMap *event = NULL; + bool ret = false; + if (!data || !chat_id || !ev || !st || !se) + { + Log(LOG_INFO, "%p %p %p %p %p", data, chat_id, ev, st, se); + return false; + } + + ref = DbLock(data->db, 2, "chats", chat_id); + j = DbJson(ref); + if (!ref) + { + Log(LOG_INFO, "LF"); + goto end; + } + + + event = JsonValueAsObject(JsonGet(j, 2, "events", ev)); + if (!event) + { + Log(LOG_INFO, "EF %s", ev); + goto end; + } + *st = StrDuplicate(JsonValueAsString(HashMapGet(event, "stanza"))); + *se = StrDuplicate(JsonValueAsString(HashMapGet(event, "sender"))); + ret = true; +end: + DbUnlock(data->db, ref); + return ret; +} diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index fdf6949..73be3ba 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -7,7 +7,7 @@ #include void -XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type) +XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, char *rst, char *rse) { XMLElement *message, *body, *data, *parsee; char *from; @@ -50,6 +50,15 @@ XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type) /* TODO: Add custom fields depending on the caller's wishes */ } + if (rst && rse) + { + XMLElement *reply = XMLCreateTag("reply"); + XMLAddAttr(reply, "to", rse); + XMLAddAttr(reply, "id", rst); + XMLAddAttr(reply, "xmlns", "urn:xmpp:reply:0"); + XMLAddChild(message, reply); + } + XMLAddChild(message, body); XMLAddChild(message, parsee); XMLAddChild(body, data); diff --git a/src/XMPPThread.c b/src/XMPPThread.c index b0d6ab0..ab20d0c 100644 --- a/src/XMPPThread.c +++ b/src/XMPPThread.c @@ -27,10 +27,10 @@ ParseeWakeupThread(void) static void ParseeDMHandler(char *room, char *from, XMLElement *data, const ParseeConfig *c) { - ASSend( + Free(ASSend( c, room, from, "m.room.message", MatrixCreateMessage(data->data) - ); + )); } static bool @@ -71,6 +71,7 @@ MessageStanza(ParseeData *args, XMLElement *stanza) char *res = ParseeGetResource(from); char *encoded = ParseeEncodeJID(args->config, from, false); char *s_id_str = HashMapGet(stanza_id->attrs, "id"); + char *event_id; /* TODO: Create smarter puppet names */ if (ParseeVerifyStanza(args, chat_id, s_id_str)) @@ -93,7 +94,7 @@ MessageStanza(ParseeData *args, XMLElement *stanza) mxc = ASReupload(args->config, oob_data->data, &mime); content = MatrixCreateMedia(mxc, data->data, mime); - ASSend( + event_id = ASSend( args->config, mroom_id, encoded, "m.room.message", content ); @@ -102,12 +103,13 @@ MessageStanza(ParseeData *args, XMLElement *stanza) } else { - ASSend( + event_id = ASSend( args->config, mroom_id, encoded, "m.room.message", MatrixCreateMessage(data->data) ); } - ParseePushStanza(args, chat_id, s_id_str); + ParseePushStanza(args, chat_id, s_id_str, event_id, from); + Free(event_id); } Free(res); diff --git a/src/include/AS.h b/src/include/AS.h index 2c2f7c7..e1bd679 100644 --- a/src/include/AS.h +++ b/src/include/AS.h @@ -28,7 +28,7 @@ extern void ASJoin(const ParseeConfig *, char *, char *); /* Sends a message event with a specific type and body. * Said body is freed during the function's execution. */ -extern void ASSend(const ParseeConfig *, char *, char *, char *, HashMap *); +extern char * ASSend(const ParseeConfig *, char *, char *, char *, HashMap *); /* Sets a state event with a specific type and body */ extern void ASSetState(const ParseeConfig *conf, char *id, char *type, char *key, char *mask, HashMap *event); diff --git a/src/include/Matrix.h b/src/include/Matrix.h index e361c56..974f20d 100644 --- a/src/include/Matrix.h +++ b/src/include/Matrix.h @@ -20,4 +20,7 @@ extern HashMap * MatrixCreateNameState(char *name); /* Creates a join membership with a specific nickname */ extern HashMap * MatrixCreateNickChange(char *nick); + +/* Get the event ID of the reply if existent */ +extern char * MatrixGetReply(HashMap *event); #endif diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 2fa357d..14cc605 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -145,11 +145,14 @@ extern char * ParseeGetRoomID(ParseeData *, char *chat_id); extern char * ParseeGetMUCID(ParseeData *, char *chat_id); /* Pushes a stanza ID to a chat ID */ -extern void ParseePushStanza(ParseeData *, char *chat_id, char *stanza_id); +extern void ParseePushStanza(ParseeData *, char *chat_id, char *stanza_id, char *event, char *sender); /* Checks if a stanza is not duplicated in a chat ID */ extern bool ParseeVerifyStanza(ParseeData *, char *chat_id, char *stanza_id); +/* Gets the stanza ID and sender of an event */ +extern bool ParseeGetStanzaInfo(ParseeData *, char *c_id, char *e, char **st, char **se); + /* Sends presence requests for every MUC around as a fake JID */ extern void ParseeSendPresence(ParseeData *); diff --git a/src/include/XMPP.h b/src/include/XMPP.h index 22b1111..b8cef94 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -28,7 +28,7 @@ extern bool XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared); extern void XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc); /* TODO: XMPP stuff, I don't fucking know, I'm not a Jabbernerd. */ -extern void XMPPSendPlain(XMPPComponent *c, char *f, char *t, char *m, char *type); +extern void XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, char *rst, char *rse); extern void XMPPSendMUC(XMPPComponent *comp, char *fr, char *as, char *to, char *msg, char *type); /* Closes a raw component stream. */