From 63c1bc819ea2a5e14866c3db5c10fb0a17d21ee6 Mon Sep 17 00:00:00 2001 From: LDA Date: Thu, 18 Jul 2024 15:50:19 +0200 Subject: [PATCH] [ADD/FIX/WIP] "Fix" concurrency, prepare XEP-0421 I'll need to break down my commits more... --- Makefile | 4 +- src/MatrixEventHandler.c | 4 + src/Parsee/Data.c | 20 +++++ src/XML/Elements.c | 8 +- src/XMPP/Stanza.c | 59 ++++++++++++- src/XMPPThread/Bridged.c | 71 +++++++++++++++ src/XMPPThread/Caps.c | 79 +++++++++++++++++ src/XMPPThread/ReListener.c | 145 ++++++++++--------------------- src/XMPPThread/Stanzas/Message.c | 21 ++--- src/XMPPThread/internal.h | 30 ++++--- src/include/Parsee.h | 10 +++ src/include/XMPP.h | 4 + src/include/XMPPCommand.h | 31 +------ src/include/XMPPCommands.x | 32 +++++++ 14 files changed, 356 insertions(+), 162 deletions(-) create mode 100644 src/XMPPThread/Caps.c create mode 100644 src/include/XMPPCommands.x diff --git a/Makefile b/Makefile index bb69ac4..c62dfdb 100644 --- a/Makefile +++ b/Makefile @@ -19,8 +19,8 @@ SOURCE=src OBJECT=build INCLUDES=src/include CC=cc -CFLAGS=-I$(SOURCE) -I$(INCLUDES) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -O2 -g -ggdb -Wall -Werror -LDFLAGS=-L $(CYTO_LIB) -lCytoplasm -Wl,--export-dynamic -O2 -g -ggdb +CFLAGS=-I$(SOURCE) -I$(INCLUDES) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -g -ggdb -Wall -Werror +LDFLAGS=-L $(CYTO_LIB) -lCytoplasm -g -ggdb BINARY=parsee # ============================ Compilation ================================= SRC_FILES:=$(shell find $(SOURCE) -name '*.c') diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index 389d650..0363a12 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -209,6 +209,10 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to) matrix_name = ASGetName(data->config, room_id, matrix_sender); muc_join_as = StrConcat(4, muc_id, "/", matrix_name, "[p]"); + /* TODO: Manage name conflicts. That would have been an easy + * task(try the original one, and use a counter if it fails), + * but that'd involve modifying the rest of the code, which + * I'm not doing at 01:39 ... */ XMPPJoinMUC(jabber, *from, muc_join_as); *to = muc_id; diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 985d588..10cd0de 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -861,3 +862,22 @@ ParseeStringifyDate(uint64_t millis) return out; } + +void +ParseeAchievement(const char *func, const char *msg, bool die) +{ + Log(LOG_ERR, "=========== Achievement GET! ==========="); + Log(LOG_ERR, "%s: %s.", func, msg); + Log(LOG_ERR, "THIS IS, LET'S SAY, NOT GOOD, AND A SIGN OF "); + Log(LOG_ERR, "A PROGRAMMER ERROR. PLEASE KILLALL -9 PARSEE."); + Log(LOG_ERR, ""); + Log(LOG_ERR, "YOU, HOWEVER, GET TO WIN AN AWARD FOR THIS."); + Log(LOG_ERR, "I AM SIMPLY JEALOUS OF YOU GETTING SUCH A "); + Log(LOG_ERR, "GOOD ERROR MESSAGE."); + Log(LOG_ERR, "=========== Achievement GET! ==========="); + + if (die) + { + abort(); + } +} diff --git a/src/XML/Elements.c b/src/XML/Elements.c index 714ef5e..e3cdcbe 100644 --- a/src/XML/Elements.c +++ b/src/XML/Elements.c @@ -4,6 +4,8 @@ #include #include +#include + XMLElement * XMLCreateTag(char *name) { @@ -43,8 +45,10 @@ XMLCreateText(char *data) elem->data = StrDuplicate(data); return elem; + } + void XMLAddAttr(XMLElement *element, char *key, char *val) { @@ -52,12 +56,12 @@ XMLAddAttr(XMLElement *element, char *key, char *val) { return; } - if (element->type != XML_ELEMENT_TAG) + if (element->type != XML_ELEMENT_TAG || !element->attrs) { return; } - HashMapSet(element->attrs, key, StrDuplicate(val)); + Free(HashMapSet(element->attrs, key, StrDuplicate(val))); } void XMLAddChild(XMLElement *element, XMLElement *child) diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index 463c367..d728b64 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -312,7 +312,7 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc) pthread_mutex_unlock(&comp->write_lock); - if ((reply = ParseeAwaitStanza(id, 500))) + /*if ((reply = ParseeAwaitStanza(id, 500))) { bool exit_code = true; @@ -325,7 +325,8 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc) XMLFreeElement(reply); Free(id); return exit_code; - } + }*/ + (void) reply; Free(id); return true; } @@ -485,3 +486,57 @@ XMPPHasError(XMLElement *stanza, char *type) } return XMLookForUnique(err, type); } + +XMLElement * +XMPPSendDisco(XMPPComponent *jabber, char *from, char *to) +{ + XMLElement *ret, *iq; + char *identifier; + + if (!jabber || !from || !to) + { + return NULL; + } + + iq = XMLCreateTag("iq"); + XMLAddAttr(iq, "type", "get"); + XMLAddAttr(iq, "from", from); + XMLAddAttr(iq, "to", to); + XMLAddAttr(iq, "id", (identifier = StrRandom(69))); + { + XMLElement *query = XMLCreateTag("query"); + XMLAddAttr(query, "xmlns", "http://jabber.org/protocol/disco#info"); + XMLAddChild(iq, query); + } + + pthread_mutex_lock(&jabber->write_lock); + XMLEncode(jabber->stream, iq); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); + XMLFreeElement(iq); + + ret = ParseeAwaitStanza(identifier, 250); + Free(identifier); + return ret; +} +bool +XMPPDiscoAdvertises(XMLElement *disco, char *var) +{ + XMLElement *query; + if (!disco || !var) + { + return false; + } + + query = XMLookForTKV( + disco, + "query", "xmlns", + "http://jabber.org/protocol/disco#info" + ); + if (!query) + { + return false; + } + + return !!XMLookForTKV(query, "feature", "var", var); +} diff --git a/src/XMPPThread/Bridged.c b/src/XMPPThread/Bridged.c index fe1d94e..32afd23 100644 --- a/src/XMPPThread/Bridged.c +++ b/src/XMPPThread/Bridged.c @@ -1,6 +1,10 @@ #include "XMPPThread/internal.h" #include +#include +#include + +#include char * ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza) @@ -111,3 +115,70 @@ ParseeVerifyAllStanza(ParseeData *args, XMLElement *stanza) return ret; } + +bool +ServerHasXEP421(ParseeData *data, char *from) +{ + char *server = NULL, *parsee; + XMLElement *disco; + bool ret; + if (!data || !from) + { + return false; + } + + server = strchr(from, '@'); + if (!server) + { + server = from; + } + else + { + server++; + } + server = StrDuplicate(server); + + if (strchr(server, '/')) + { + *(strchr(server, '/')) = '\0'; + } + + parsee = ParseeJID(data); + disco = XMPPSendDisco(data->jabber, parsee, server); + + ret = XMPPDiscoAdvertises(disco, "urn:xmpp:occupant-id:0"); + + XMLFreeElement(disco); + Free(parsee); + Free(server); + return ret; +} +char * +ParseeGetBridgedUser(ParseeData *data, XMLElement *stanza) +{ + char *user, *xmpp_from, *type; + char *decode_from; + + if (!data || !stanza) + { + return NULL; + } + + xmpp_from = HashMapGet(stanza->attrs, "from"); + type = HashMapGet(stanza->attrs, "type"); + decode_from = ParseeLookupJID(xmpp_from); + + /* TODO: On semi-anonymous MUCs, it might be preferable to use a + * form of the occupant ID as the base, as it is more unique, and + * less prone to trigger the character limit on Matrix. + * I'll need to detect these first.... + * + * See: https://xmpp.org/extensions/xep-0421.html */ + user = ParseeEncodeJID( + data->config, + decode_from, + StrEquals(type, "chat") + ); + Free(decode_from); + return user; +} diff --git a/src/XMPPThread/Caps.c b/src/XMPPThread/Caps.c new file mode 100644 index 0000000..867adbd --- /dev/null +++ b/src/XMPPThread/Caps.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "XMPPThread/internal.h" + +/* Generates a SHA-256 hash of the ver field. */ +char * +XMPPGenerateVer(void) +{ + 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++) + { + XMPPIdentity *identity = ArrayGet(identities, i); + char *id_chunk = StrConcat(7, + identity->category, "/", + identity->type, "/", + identity->lang, "/", + identity->name); + char *tmp = S; + S = StrConcat(3, S, id_chunk, "<"); + Free(tmp); + Free(id_chunk); + } + + ArraySort(features, ((int (*) (void *, void *)) ICollate)); + for (i = 0; i < ArraySize(features); i++) + { + char *feature = ArrayGet(features, i); + char *tmp = S; + S = StrConcat(3, S, feature, "<"); + Free(tmp); + } + + Sha = Sha1(S); + Free(S); + 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; +} + + diff --git a/src/XMPPThread/ReListener.c b/src/XMPPThread/ReListener.c index 21390fc..e6df0f3 100644 --- a/src/XMPPThread/ReListener.c +++ b/src/XMPPThread/ReListener.c @@ -3,7 +3,10 @@ #include #include +#include #include +#include +#include #include #include @@ -21,70 +24,6 @@ #include "XMPPThread/internal.h" -/* Generates a SHA-256 hash of the ver field. */ -char * -XMPPGenerateVer(void) -{ - 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++) - { - XMPPIdentity *identity = ArrayGet(identities, i); - char *id_chunk = StrConcat(7, - identity->category, "/", - identity->type, "/", - identity->lang, "/", - identity->name); - char *tmp = S; - S = StrConcat(3, S, id_chunk, "<"); - Free(tmp); - Free(id_chunk); - } - - ArraySort(features, ((int (*) (void *, void *)) ICollate)); - for (i = 0; i < ArraySize(features); i++) - { - char *feature = ArrayGet(features, i); - char *tmp = S; - S = StrConcat(3, S, feature, "<"); - Free(tmp); - } - - Sha = Sha1(S); - Free(S); - 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; -} - XMLElement * RetrieveStanza(XMPPThread *thread) { @@ -152,11 +91,11 @@ XMPPDispatcher(void *argp) } typedef struct XMPPAwait { - pthread_mutex_t cond_lock; - pthread_cond_t condition; + XMLElement *stanza; bool usable; - XMLElement *stanza; + pthread_mutex_t cond_lock; + pthread_cond_t condition; } XMPPAwait; static pthread_mutex_t await_lock = PTHREAD_MUTEX_INITIALIZER; @@ -243,7 +182,7 @@ ParseeXMPPThread(void *argp) { pthread_mutex_lock(&await->cond_lock); await->stanza = stanza; - pthread_cond_broadcast(&await->condition); + pthread_cond_signal(&await->condition); pthread_mutex_unlock(&await->cond_lock); HashMapDelete(await_table, id); @@ -286,25 +225,37 @@ ParseeXMPPThread(void *argp) return NULL; } -#include -#include -/* TODO: This function does NIT behave well. */ XMLElement * ParseeAwaitStanza(char *identifier, int64_t timeout) { - /* TODO: Pthreads HATE me using Malloc here, so I'm abusing stackspace. - * Not *too much* of a problem, just a weird oddity. If anyone has a clue - * on why that happens (at least on ARM64 with a Pi4 running Debian), let - * me know! */ - XMPPAwait awa; + XMPPAwait *awa; XMLElement *stanza; struct timespec ts; + if (!identifier) { return NULL; } + /* XXX: You may be wondering _why_ I am using stdlib's malloc, instead of + * Cytoplasm's Malloc wrapper(which are essentially the same thing, plus + * some memchecking as of now), or the stack, as done previously. + * The reasons are that: + * - Cytoplasm's heap causes a fun bus error on ARM64. I have _no clue_ why, + * since, as I said, it is as of now just malloc with extra metadata prepended + * to it. A _guess_ may be that the metadata makes everything unaligned, which, + * just sounds silly. pthreads should be able to cope fine with that, I think. + * - The stack seems to be a prime candidate to cause a stack corruption, which + * puzzled me for a comically long while("why is the value being swapped for + * the key?" "why does duplicating twice cause the former problem to disappear, + * but still obviously creating another one?", ...). + * + * I am open to issues talking about such fun behaviour and ideas to fix this. + * This is a bodge, and potentially a problem, or vulnerability with Cytoplasm/ + * Parsee. As long as it isn't "use Rust". Please don't say that. */ + awa = malloc(sizeof(XMPPAwait)); + /* Convert into an absolute timeout. * ================================= * XXX: For anyone using timespecs: MAKE ABSOLUTELY FUCKING SURE YOUR NANOS @@ -327,30 +278,33 @@ ParseeAwaitStanza(char *identifier, int64_t timeout) ts.tv_nsec = nsc_delta; ts.tv_sec += sec_delta; } - - (void) msecond; } pthread_mutex_lock(&await_lock); - pthread_cond_init(&awa.condition, NULL); - pthread_mutex_init(&awa.cond_lock, NULL); - awa.stanza = NULL; + pthread_cond_init(&awa->condition, NULL); + pthread_mutex_init(&awa->cond_lock, NULL); + awa->stanza = NULL; - HashMapSet(await_table, identifier, &awa); + if (HashMapGet(await_table, identifier)) + { + HashMapDelete(await_table, identifier); + } + + HashMapSet(await_table, identifier, awa); pthread_mutex_unlock(&await_lock); - pthread_mutex_lock(&awa.cond_lock); - while (!awa.stanza) + pthread_mutex_lock(&awa->cond_lock); + while (!awa->stanza) { int code; if (timeout <= 0) { - pthread_cond_wait(&awa.condition, &awa.cond_lock); + pthread_cond_wait(&awa->condition, &awa->cond_lock); continue; } - code = pthread_cond_timedwait(&awa.condition, &awa.cond_lock, &ts); + code = pthread_cond_timedwait(&awa->condition, &awa->cond_lock, &ts); if (code == ETIMEDOUT) { /* Timeout detected, give up regardless of the status of our @@ -361,22 +315,15 @@ ParseeAwaitStanza(char *identifier, int64_t timeout) } if (code == EINVAL) { - Log(LOG_ERR, "=========== Achievement GET! ==========="); - Log(LOG_ERR, "%s: TIMEDWAIT RETURNED EINVAL.", __func__); - Log(LOG_ERR, "THIS IS, LET'S SAY, NOT GOOD, AND A SIGN OF "); - Log(LOG_ERR, "A PROGRAMMER ERROR. PLEASE KILLALL -9 PARSEE."); - Log(LOG_ERR, ""); - Log(LOG_ERR, "YOU, HOWEVER, GET TO WIN AN AWARD FOR THIS."); - Log(LOG_ERR, "I AM SIMPLY JEALOUS OF YOU GETTING SUCH A "); - Log(LOG_ERR, "GOOD ERROR MESSAGE."); - Log(LOG_ERR, "=========== Achievement GET! ==========="); + Achievement("TIMEDWAIT RETURNED WEIRD EINVAL", true); } } - stanza = awa.stanza; - pthread_mutex_unlock(&awa.cond_lock); + stanza = awa->stanza; + pthread_mutex_unlock(&awa->cond_lock); - pthread_cond_destroy(&awa.condition); - pthread_mutex_destroy(&awa.cond_lock); + pthread_cond_destroy(&awa->condition); + pthread_mutex_destroy(&awa->cond_lock); + free(awa); return stanza; } diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index 4ec3450..81f50e3 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -148,11 +148,11 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) return false; } - /* TODO: On semi-anonymous MUCs, it might be preferable to use a - * form of the occupant ID as the base, as it is more unique, and - * less prone to trigger the character limit on Matrix. - * - * See: https://xmpp.org/extensions/xep-0421.html */ + if (ServerHasXEP421(args, HashMapGet(stanza->attrs, "from"))) + { + + } + to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to")); decode_from = ParseeLookupJID(from); from_matrix = ParseeEncodeJID(args->config, decode_from, true); @@ -198,16 +198,9 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) if (mroom_id && !XMPPIsParseeStanza(stanza)) { char *res = ParseeGetResource(from); - char *encoded = ParseeEncodeJID(args->config, decode_from, false); + char *encoded = ParseeGetBridgedUser(args, stanza); char *event_id = NULL; - bool chat = false; - - if (StrEquals(HashMapGet(stanza->attrs, "type"), "chat")) - { - Free(encoded); - encoded = StrDuplicate(from_matrix); - chat = true; - } + bool chat = StrEquals(HashMapGet(stanza->attrs, "type"), "chat"); { char *parsee = ParseeJID(args); diff --git a/src/XMPPThread/internal.h b/src/XMPPThread/internal.h index f2bb668..e603991 100644 --- a/src/XMPPThread/internal.h +++ b/src/XMPPThread/internal.h @@ -58,20 +58,24 @@ struct XMPPThread { XMPPThreadInfo *info; }; -extern int ICollate(unsigned char *cata, unsigned char *catb); -extern int IdentitySort(void *idap, void *idbp); +int ICollate(unsigned char *cata, unsigned char *catb); +int IdentitySort(void *idap, void *idbp); -extern char * ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza); -extern char * ParseeGetEventFromID(ParseeData *data, XMLElement *stanza, char *id); -extern char * ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza); -extern void ParseePushAllStanza(ParseeData *args, XMLElement *stanza, char *event); -extern bool ParseeVerifyAllStanza(ParseeData *args, XMLElement *stanza); +char * ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza); +char * ParseeGetEventFromID(ParseeData *data, XMLElement *stanza, char *id); +char * ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza); +void ParseePushAllStanza(ParseeData *args, XMLElement *stanza, char *event); +bool ParseeVerifyAllStanza(ParseeData *args, XMLElement *stanza); -extern HashMap * ShoveStanza(HashMap *content, XMLElement *stanza); -extern void ManageProfileItem(ParseeData *args, XMLElement *item, XMLElement *stanza, XMPPThread *thr); -extern XMLElement * CreatePubsubRequest(char *from, char *to, char *node); +HashMap * ShoveStanza(HashMap *content, XMLElement *stanza); +void ManageProfileItem(ParseeData *args, XMLElement *item, XMLElement *stanza, XMPPThread *thr); +XMLElement * CreatePubsubRequest(char *from, char *to, char *node); -extern bool MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr); -extern void IQStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr); -extern void PresenceStanza(ParseeData *args, XMLElement *stanza); +bool MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr); +void IQStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr); +void PresenceStanza(ParseeData *args, XMLElement *stanza); + +bool ServerHasXEP421(ParseeData *data, char *from); + +char * ParseeGetBridgedUser(ParseeData *data, XMLElement *stanza); diff --git a/src/include/Parsee.h b/src/include/Parsee.h index c7a857c..5eec8e3 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -240,4 +240,14 @@ extern char * ParseeStringifyDate(uint64_t millis); /* Generates the JID of the Parsee bridge user. */ extern char * ParseeJID(ParseeData *data); extern char * ParseeMXID(ParseeData *data); + +/** Prints an _fatal_ and _strange_, error message, then congratulates + * the user for it(an "achievement"). + * Use this for errors that have _no business_ happening, at all. + * NOTE to users: If you see this, _*OPEN AN ISSUE*_. + * --------------------------------------------------- + * Returns: NOTHING | NORETURN */ +extern void ParseeAchievement(const char *func, const char *msg, bool die); +#define Achievement(msg, die) ParseeAchievement(__func__, msg, die) + #endif diff --git a/src/include/XMPP.h b/src/include/XMPP.h index c5eef91..7d6cf1e 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -98,4 +98,8 @@ extern char * XMPPGenerateVer(void); extern void XMPPAnnotatePresence(XMLElement *presence); extern bool XMPPHasError(XMLElement *stanza, char *type); + +extern XMLElement * XMPPSendDisco(XMPPComponent *jabber, char *from, char *to); + +extern bool XMPPDiscoAdvertises(XMLElement *disco, char *var); #endif diff --git a/src/include/XMPPCommand.h b/src/include/XMPPCommand.h index e61fdcb..1f42b08 100644 --- a/src/include/XMPPCommand.h +++ b/src/include/XMPPCommand.h @@ -94,35 +94,6 @@ extern bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeD /* --------------------------------- COMMANDS --------------------------------- */ /* Please edit stc/XMPPThread.c (you can just force-save) for these to apply! */ -#define XMPPCOMMANDS \ - XMPP_COMMAND(StatusCallback, "stats", "Get Parsee statistics", {}) \ - XMPP_COMMAND(CleanCallback, "clean", "Cleanup temporary Parsee data", {}) \ - XMPP_COMMAND(AdminsCallback, "admin", "Get Parsee admin list", {}) \ - XMPP_COMMAND(NoflyCallback, "nofly", "Get Parsee nofly list", {}) \ - XMPP_COMMAND(AddAdminCallback, "add-admin", "Adds glob as admin", { \ - XMPPOption *glob = XMPPCreateText(true, "glob", ""); \ - XMPPSetDescription(glob, "Glob pattern to set as admin"); \ - XMPPAddOption(cmd, glob); \ - \ - XMPPSetFormTitle(cmd, "Admin addition form"); \ - XMPPSetFormInstruction(cmd, "Select a glob pattern to add as an admin"); \ - }) \ - XMPP_COMMAND(DelAdminCallback, "del-admin", "Removes a glob from admin rights", { \ - XMPPCmdOptionsCreator(cmd, FormDelAdminCallback); \ - XMPPSetFormTitle(cmd, "Admin removal form"); \ - XMPPSetFormInstruction(cmd, "Select a glob pattern to remove as an admin"); \ - }) \ - XMPP_COMMAND(AddNoflyCallback, "add-nofly", "Adds user to nofly", { \ - XMPPOption *entity = XMPPCreateText(true, "entity", ""); \ - XMPPOption *reason = XMPPCreateText(false, "reason", "Not behaving"); \ - XMPPSetDescription(entity, "Entity(glob) to no-fly"); \ - XMPPAddOption(cmd, entity); \ - XMPPSetDescription(reason, "Reason for the no-fly"); \ - XMPPAddOption(cmd, reason); \ - \ - XMPPSetFormTitle(cmd, "No-fly addition form"); \ - XMPPSetFormInstruction(cmd, "Select a glob pattern to add to the nofly"); \ - }) \ #define XMPP_COMMAND(f,n,t,s) \ extern void \ @@ -132,7 +103,7 @@ extern bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeD extern void \ Form##f(XMPPCommandManager *, XMPPCommand *, char *); \ - XMPPCOMMANDS +#include "XMPPCommands.x" #undef XMPP_COMMAND #endif diff --git a/src/include/XMPPCommands.x b/src/include/XMPPCommands.x new file mode 100644 index 0000000..688b0ca --- /dev/null +++ b/src/include/XMPPCommands.x @@ -0,0 +1,32 @@ +/* C X-macro file */ +#define XMPPCOMMANDS \ + XMPP_COMMAND(StatusCallback, "stats", "Get Parsee statistics", {}) \ + XMPP_COMMAND(CleanCallback, "clean", "Cleanup temporary Parsee data", {}) \ + XMPP_COMMAND(AdminsCallback, "admin", "Get Parsee admin list", {}) \ + XMPP_COMMAND(NoflyCallback, "nofly", "Get Parsee nofly list", {}) \ + XMPP_COMMAND(AddAdminCallback, "add-admin", "Adds glob as admin", { \ + XMPPOption *glob = XMPPCreateText(true, "glob", ""); \ + XMPPSetDescription(glob, "Glob pattern to set as admin"); \ + XMPPAddOption(cmd, glob); \ + \ + XMPPSetFormTitle(cmd, "Admin addition form"); \ + XMPPSetFormInstruction(cmd, "Select a glob pattern to add as an admin"); \ + }) \ + XMPP_COMMAND(DelAdminCallback, "del-admin", "Removes a glob from admin rights", { \ + XMPPCmdOptionsCreator(cmd, FormDelAdminCallback); \ + XMPPSetFormTitle(cmd, "Admin removal form"); \ + XMPPSetFormInstruction(cmd, "Select a glob pattern to remove as an admin"); \ + }) \ + XMPP_COMMAND(AddNoflyCallback, "add-nofly", "Adds user to nofly", { \ + XMPPOption *entity = XMPPCreateText(true, "entity", ""); \ + XMPPOption *reason = XMPPCreateText(false, "reason", "Not behaving"); \ + XMPPSetDescription(entity, "Entity(glob) to no-fly"); \ + XMPPAddOption(cmd, entity); \ + XMPPSetDescription(reason, "Reason for the no-fly"); \ + XMPPAddOption(cmd, reason); \ + \ + XMPPSetFormTitle(cmd, "No-fly addition form"); \ + XMPPSetFormInstruction(cmd, "Select a glob pattern to add to the nofly"); \ + }) \ + +XMPPCOMMANDS