From 2e566c73fcca4b9ba940eb37c9bddea3c6d1f519 Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 29 Nov 2024 13:58:49 +0100 Subject: [PATCH] [MOD] Start not hardcoding discovery features The eventual goal here is to have different disco replies for specific kinds of JID, effectively allowing us to have MUCs. Yeah. --- src/XMPP/MUC.c | 25 +++++++- src/XMPP/Stanza.c | 21 ------ src/XMPPThread/Caps.c | 125 +++++++++++++++++++++++++++--------- src/XMPPThread/Stanzas/IQ.c | 10 ++- src/XMPPThread/internal.h | 25 +++++++- src/include/XMPP.h | 10 --- 6 files changed, 149 insertions(+), 67 deletions(-) diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index 7064698..5813cd2 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -8,6 +8,8 @@ #include #include +#include "XMPPThread/internal.h" + bool XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out) { @@ -162,6 +164,7 @@ bool XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool ret) { XMLElement *presence, *x, *reply, *history, *photo; + IQFeatures *features; char *from, *id, *stime = "3600"; if (!comp || !fr || !muc) { @@ -189,7 +192,15 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool XMLAddChild(x, history); XMLAddChild(presence, x); - XMPPAnnotatePresence(presence); + features = CreateIQFeatures(); +#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); + IQ_IDENTITY +#undef IdentitySimple +#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature); + IQ_ADVERT +#undef AdvertiseSimple + XMPPAnnotatePresence(presence, features); + FreeIQFeatures(features); if (hash) { @@ -225,6 +236,7 @@ void XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) { XMLElement *presence; + IQFeatures *features; char *from, *id; if (!comp || !fr || !muc) { @@ -246,7 +258,16 @@ XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason) XMLAddChild(presence, status); } - XMPPAnnotatePresence(presence); + features = CreateIQFeatures(); +#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); + IQ_IDENTITY +#undef IdentitySimple +#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature); + IQ_ADVERT +#undef AdvertiseSimple + XMPPAnnotatePresence(presence, features); + FreeIQFeatures(features); + XMPPSendStanza(comp, presence, 10000); diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index 451c16f..27a658e 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -159,27 +159,6 @@ XMPPGetReply(XMLElement *elem) return HashMapGet(rep->attrs, "id"); } -void -XMPPAnnotatePresence(XMLElement *presence) -{ - XMLElement *c; - char *ver; - if (!presence) - { - return; - } - - ver = XMPPGenerateVer(); - c = XMLCreateTag("c"); - XMLAddAttr(c, "xmlns", "http://jabber.org/protocol/caps"); - XMLAddAttr(c, "hash", "sha-1"); - XMLAddAttr(c, "node", REPOSITORY); - XMLAddAttr(c, "ver", ver); - - Free(ver); - XMLAddChild(presence, c); -} - char * XMPPGetModeration(XMLElement *stanza) { diff --git a/src/XMPPThread/Caps.c b/src/XMPPThread/Caps.c index 867adbd..5e53ee1 100644 --- a/src/XMPPThread/Caps.c +++ b/src/XMPPThread/Caps.c @@ -12,33 +12,86 @@ #include "XMPPThread/internal.h" +IQFeatures * +CreateIQFeatures(void) +{ + IQFeatures *ret = Malloc(sizeof(*ret)); + + ret->identity = ArrayCreate(); + ret->adverts = ArrayCreate(); + + return ret; +} +void +FreeIQFeatures(IQFeatures *features) +{ + size_t i; + if (!features) + { + return; + } + + for (i = 0; i < ArraySize(features->adverts); i++) + { + Free(ArrayGet(features->adverts, i)); + } + ArrayFree(features->adverts); + + for (i = 0; i < ArraySize(features->identity); i++) + { + XMPPIdentity *identity = ArrayGet(features->identity, i); + + Free(identity->category); + Free(identity->type); + Free(identity->lang); + Free(identity->name); + + Free(identity); + } + ArrayFree(features->identity); + + Free(features); +} + +void +AdvertiseIQFeature(IQFeatures *f, char *feature) +{ + if (!f || !feature) + { + return; + } + + ArrayAdd(f->adverts, StrDuplicate(feature)); +} +void +AddIQIdentity(IQFeatures *f, char *cat, char *lang, char *type, char *name) +{ + XMPPIdentity *identity; + if (!f) + { + return; + } + + identity = Malloc(sizeof(*identity)); + identity->category = StrDuplicate(cat); + identity->type = StrDuplicate(type); + identity->lang = StrDuplicate(lang); + identity->name = StrDuplicate(name); + ArrayAdd(f->identity, identity); +} /* Generates a SHA-256 hash of the ver field. */ char * -XMPPGenerateVer(void) +XMPPGenerateVer(IQFeatures *features) { char *S = NULL; unsigned char *Sha = NULL; - Array *identities = ArrayCreate(); - Array *features = ArrayCreate(); size_t i; /* Initialise identity table, to be sorted */ -#define IdentitySimple(cat, Type, Name) { \ - XMPPIdentity *id = Malloc(sizeof(*id)); \ - id->category = cat; \ - id->lang = NULL; \ - id->type = Type; \ - id->name = Name; \ - ArrayAdd(identities, id); } - IQ_IDENTITY -#undef IdentitySimple -#define AdvertiseSimple(feature) ArrayAdd(features, feature); - IQ_ADVERT -#undef AdvertiseSimple - ArraySort(identities, IdentitySort); - for (i = 0; i < ArraySize(identities); i++) + ArraySort(features->identity, IdentitySort); + for (i = 0; i < ArraySize(features->identity); i++) { - XMPPIdentity *identity = ArrayGet(identities, i); + XMPPIdentity *identity = ArrayGet(features->identity, i); char *id_chunk = StrConcat(7, identity->category, "/", identity->type, "/", @@ -50,10 +103,10 @@ XMPPGenerateVer(void) Free(id_chunk); } - ArraySort(features, ((int (*) (void *, void *)) ICollate)); - for (i = 0; i < ArraySize(features); i++) + ArraySort(features->adverts, ((int (*) (void *, void *)) ICollate)); + for (i = 0; i < ArraySize(features->adverts); i++) { - char *feature = ArrayGet(features, i); + char *feature = ArrayGet(features->adverts, i); char *tmp = S; S = StrConcat(3, S, feature, "<"); Free(tmp); @@ -64,16 +117,28 @@ XMPPGenerateVer(void) S = Base64Encode((const char *) Sha, 20); Free(Sha); - ArrayFree(features); - for (i = 0; i < ArraySize(identities); i++) - { - XMPPIdentity *identity = ArrayGet(identities, i); - /* We don't have to do anything here. */ - Free(identity); - } - ArrayFree(identities); - return S; } +void +XMPPAnnotatePresence(XMLElement *presence, IQFeatures *features) +{ + XMLElement *c; + char *ver; + if (!presence || !features) + { + return; + } + + ver = XMPPGenerateVer(features); + c = XMLCreateTag("c"); + XMLAddAttr(c, "xmlns", "http://jabber.org/protocol/caps"); + XMLAddAttr(c, "hash", "sha-1"); + XMLAddAttr(c, "node", REPOSITORY); + XMLAddAttr(c, "ver", ver); + + Free(ver); + XMLAddChild(presence, c); +} + diff --git a/src/XMPPThread/Stanzas/IQ.c b/src/XMPPThread/Stanzas/IQ.c index 4ced5dc..396fec4 100644 --- a/src/XMPPThread/Stanzas/IQ.c +++ b/src/XMPPThread/Stanzas/IQ.c @@ -151,6 +151,7 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) { char *from, *to, *id; XMLElement *iq_reply, *query; + IQFeatures *features = CreateIQFeatures(); from = HashMapGet(stanza->attrs, "from"); to = HashMapGet(stanza->attrs, "to"); @@ -164,8 +165,14 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) XMLAddAttr(iq_reply, "id", id); query = IQGenerateQuery(); +#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name); + IQ_IDENTITY +#undef IdentitySimple +#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature); + IQ_ADVERT +#undef AdvertiseSimple { - char *ver = XMPPGenerateVer(); + char *ver = XMPPGenerateVer(features); char *node = StrConcat(3, REPOSITORY, "#", ver); XMLAddAttr(query, "node", node); @@ -173,6 +180,7 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza) Free(ver); } XMLAddChild(iq_reply, query); + FreeIQFeatures(features); XMPPSendStanza(jabber, iq_reply, args->config->max_stanza_size); XMLFreeElement(iq_reply); diff --git a/src/XMPPThread/internal.h b/src/XMPPThread/internal.h index 3a158b5..8602621 100644 --- a/src/XMPPThread/internal.h +++ b/src/XMPPThread/internal.h @@ -32,13 +32,17 @@ IdentitySimple("client", "pc", NAME " v" VERSION " bridge") \ IdentitySimple("component", "generic", "Parsee's component") -typedef struct PEPManager PEPManager; -typedef void (*PEPEvent)(PEPManager *m, XMLElement *stanza, XMLElement *item); - +typedef struct IQFeatures { + Array *identity; + Array *adverts; +} IQFeatures; typedef struct XMPPIdentity { char *category, *type, *lang, *name; } XMPPIdentity; +typedef struct PEPManager PEPManager; +typedef void (*PEPEvent)(PEPManager *m, XMLElement *stanza, XMLElement *item); + typedef struct XMPPThread XMPPThread; typedef struct XMPPThreadInfo { /* A FIFO of stanzas inbound, to be read by dispatcher @@ -65,6 +69,21 @@ struct XMPPThread { int ICollate(unsigned char *cata, unsigned char *catb); int IdentitySort(void *idap, void *idbp); +IQFeatures * CreateIQFeatures(void); +void AddIQIdentity(IQFeatures *, char *category, char *lang, char *type, char *name); +void AdvertiseIQFeature(IQFeatures *, char *feature); +void FreeIQFeatures(IQFeatures *); + +/** Generate the B64-encoded SHA-256 hash for the 'ver' field in caps. + * -------- + * Returns: A base64 encoded ver hash[LA:HEAP] + * Modifies: NOTHING + * See-Also: https://xmpp.org/extensions/xep-0115.html */ +char * XMPPGenerateVer(IQFeatures *features); + +/* Annotates a presence with https://xmpp.org/extensions/xep-0115.html */ +void XMPPAnnotatePresence(XMLElement *presence, IQFeatures *features); + char * ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza); char * ParseeGetEventFromID(ParseeData *data, XMLElement *stanza, char *id); char * ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza); diff --git a/src/include/XMPP.h b/src/include/XMPP.h index b2c5293..92a5d80 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -98,16 +98,6 @@ extern char * XMPPGetReply(XMLElement *elem); * See-Also: https://xmpp.org/extensions/xep-0425.html */ extern char * XMPPGetModeration(XMLElement *stanza); -/** Generate the B64-encoded SHA-256 hash for the 'ver' field in caps. - * -------- - * Returns: A base64 encoded ver hash[LA:HEAP] - * Modifies: NOTHING - * See-Also: https://xmpp.org/extensions/xep-0115.html */ -extern char * XMPPGenerateVer(void); - -/* Annotates a presence with https://xmpp.org/extensions/xep-0115.html */ -extern void XMPPAnnotatePresence(XMLElement *presence); - extern bool XMPPHasError(XMLElement *stanza, char *type); #include