diff --git a/Makefile b/Makefile index 92fa82c..781f01d 100644 --- a/Makefile +++ b/Makefile @@ -19,8 +19,8 @@ SOURCE=src OBJECT=build INCLUDES=src/include CC=cc -CFLAGS=-I$(INCLUDES) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -O3 -g -ggdb -Wall -Werror -flto -LDFLAGS=-L $(CYTO_LIB) -lCytoplasm -Wl,--export-dynamic -O3 -g -ggdb -flto +CFLAGS=-I$(INCLUDES) -I$(CYTO_INC) -DNAME="\"$(NAME)\"" -DVERSION="\"$(VERSION)\"" -DREPOSITORY=\"$(REPOSITORY)\" -O3 -g -ggdb -Wall -Werror +LDFLAGS=-L $(CYTO_LIB) -lCytoplasm -Wl,--export-dynamic -O3 -g -ggdb BINARY=parsee # ============================ Compilation ================================= SRC_FILES:=$(shell find $(SOURCE) -name '*.c') diff --git a/src/XMPPCommand/Commands.c b/src/XMPPCommand/Commands.c index d72b20a..4fb77d0 100644 --- a/src/XMPPCommand/Commands.c +++ b/src/XMPPCommand/Commands.c @@ -108,13 +108,13 @@ XMPPCommandRequiresForm(XMPPCommand *cmd) return cmd ? !!cmd->options : false; } void -XMPPExecuteCommand(XMPPCommandManager *m, XMPPCommand *cmd, XMLElement *to, HashMap *arg_table) +XMPPExecuteCommand(XMPPCommandManager *m, XMPPCommand *cmd, char *from, XMLElement *to, HashMap *arg_table) { - if (!m || !cmd || !to) + if (!m || !cmd || !from || !to) { return; } - cmd->callback(m, arg_table, to); + cmd->callback(m, from, arg_table, to); /* TODO Free arg_table's strings */ HashMapFree(arg_table); diff --git a/src/XMPPCommand/Manager.c b/src/XMPPCommand/Manager.c index c50b585..bd03a7d 100644 --- a/src/XMPPCommand/Manager.c +++ b/src/XMPPCommand/Manager.c @@ -32,6 +32,8 @@ struct XMPPCommandManager { HashMap *commands; HashMap *sessions; + + void *cookie; }; static void XMPPDestroySession(XMPPSession *session) @@ -99,13 +101,14 @@ XMPPRegisterSession(XMPPCommandManager *m, char *p_jid, char *s_jid, char *node) XMPPCommandManager * -XMPPCreateManager(void) +XMPPCreateManager(void *cookie) { XMPPCommandManager *ret = Malloc(sizeof(*ret)); pthread_mutex_init(&ret->lock, NULL); ret->commands = HashMapCreate(); ret->sessions = HashMapCreate(); + ret->cookie = cookie; return ret; } @@ -237,7 +240,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data) XMLAddAttr(command_xml, "node", node); XMLAddAttr(command_xml, "status", "completed"); XMLAddAttr(command_xml, "sessionid", session_id); - XMPPExecuteCommand(m, cmd, command_xml, NULL); + XMPPExecuteCommand(m, cmd, from, command_xml, NULL); XMLAddChild(iq, command_xml); pthread_mutex_lock(&jabber->write_lock); @@ -258,3 +261,8 @@ end: pthread_mutex_unlock(&m->lock); return good; } +void * +XMPPGetManagerCookie(XMPPCommandManager *manager) +{ + return manager ? manager->cookie : NULL; +} diff --git a/src/XMPPCommands/Admins.c b/src/XMPPCommands/Admins.c new file mode 100644 index 0000000..a56d870 --- /dev/null +++ b/src/XMPPCommands/Admins.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +void +AdminsCallback(XMPPCommandManager *m, char *from, HashMap *form, XMLElement *out) +{ + ParseeData *data = XMPPGetManagerCookie(m); + char *trimmed = ParseeTrimJID(from); + size_t i; + XMLElement *x; + XMLElement *title; + XMLElement *reported, *item, *field, *value, *txt; + + if (!ParseeIsAdmin(data, trimmed)) + { + XMLElement *note = XMLCreateTag("note"); + XMLAddAttr(note, "type", "error"); + + txt = XMLCreateText("User is not authorised to execute command."); + XMLAddChild(note, txt); + XMLAddChild(out, note); + + Free(trimmed); + return; + } + Free(trimmed); + x = XMLCreateTag("x"); + title = XMLCreateTag("title"); + + { + XMLElement *title_text = XMLCreateText("Parsee administrators"); + XMLAddChild(title, title_text); + } + XMLAddChild(x, title); + + XMLAddAttr(x, "xmlns", "jabber:x:data"); + XMLAddAttr(x, "type", "result"); + { + DbRef *ref = DbLock(data->db, 1, "admins"); + Array *admins = GrabArray(DbJson(ref), 1, "admins"); + + reported = XMLCreateTag("reported"); + XMLAddChild(x, reported); + + /* Report */ + Report("admins", "Administrator globs"); + + /* Set */ + for (i = 0; i < ArraySize(admins); i++) + { + char *glob = JsonValueAsString(ArrayGet(admins, i)); + BeginItem(); + SetField("admins", glob); + EndItem(); + } + DbUnlock(data->db, ref); + } + XMLAddChild(out, x); +} diff --git a/src/XMPPCommands/Nofly.c b/src/XMPPCommands/Nofly.c new file mode 100644 index 0000000..358044d --- /dev/null +++ b/src/XMPPCommands/Nofly.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define TITLE "Parsee global bans" + +void +NoflyCallback(XMPPCommandManager *m, char *from, HashMap *form, XMLElement *out) +{ + ParseeData *data = XMPPGetManagerCookie(m); + char *trimmed = ParseeTrimJID(from); + XMLElement *x; + XMLElement *title; + XMLElement *reported, *item, *field, *value, *txt; + + if (!ParseeIsAdmin(data, trimmed)) + { + XMLElement *note = XMLCreateTag("note"); + XMLAddAttr(note, "type", "error"); + + txt = XMLCreateText("User is not authorised to execute command."); + XMLAddChild(note, txt); + XMLAddChild(out, note); + + Free(trimmed); + return; + } + + x = XMLCreateTag("x"); + XMLAddAttr(x, "xmlns", "jabber:x:data"); + title = XMLCreateTag("title"); + XMLAddChild(x, title); + XMLAddChild(out, x); + + Free(trimmed); + { + XMLElement *title_text = XMLCreateText(TITLE); + XMLAddChild(title, title_text); + } + + XMLAddAttr(x, "type", "result"); + { + DbRef *ref = DbLock(data->db, 1, "global_bans"); + HashMap *bans = DbJson(ref); + char *banned, *reason; + JsonValue *ban_val; + reported = XMLCreateTag("reported"); + XMLAddChild(x, reported); + + /* Report */ + Report("ban", "Banned glob"); + Report("reason", "Reason for the nofly"); + Report("ts", "UNIX timestamp for creation"); + + /* Set */ + while (HashMapIterate(bans, &banned, (void **) &ban_val)) + { + HashMap *ban_obj = JsonValueAsObject(ban_val); + reason = GrabString(ban_obj, 1, "reason"); + char *ts = StrDuplicate("N/A"); + if (!reason) + { + reason = "N/A"; + } + if (HashMapGet(ban_obj, "date")) + { + Free(ts); + ts = StrInt(GrabInteger(ban_obj, 1, "date") / (1 SECONDS)); + } + + BeginItem(); + SetField("ban", banned); + SetField("reason", reason); + SetField("ts", ts); + EndItem(); + + Free(ts); + } + DbUnlock(data->db, ref); + } +} diff --git a/src/XMPPCommands/Status.c b/src/XMPPCommands/Status.c new file mode 100644 index 0000000..6af7162 --- /dev/null +++ b/src/XMPPCommands/Status.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +void +StatusCallback(XMPPCommandManager *m, char *from, HashMap *form, XMLElement *out) +{ + ParseeData *data = XMPPGetManagerCookie(m); + char *trimmed = ParseeTrimJID(from); + size_t alloc = MemoryAllocated(); + size_t kb = alloc >> 10; + size_t mb = kb >> 10; + size_t gb = mb >> 10; + size_t min = gb ? gb : (mb ? mb : (kb ? kb : alloc)); + char *unit = gb ? "GB" : (mb ? "MB" : (kb ? "KB" : "B")); + XMLElement *x; + XMLElement *title, *txt; + + if (!ParseeIsAdmin(data, trimmed)) + { + XMLElement *note = XMLCreateTag("note"); + XMLAddAttr(note, "type", "error"); + + txt = XMLCreateText("User is not authorised to execute command."); + XMLAddChild(note, txt); + XMLAddChild(out, note); + + Free(trimmed); + return; + } + Free(trimmed); + x = XMLCreateTag("x"); + title = XMLCreateTag("title"); + + { + XMLElement *title_text = XMLCreateText("Parsee statistics"); + XMLAddChild(title, title_text); + } + XMLAddChild(x, title); + + XMLAddAttr(x, "xmlns", "jabber:x:data"); + XMLAddAttr(x, "type", "result"); + { + XMLElement *reported, *item, *field, *value; + reported = XMLCreateTag("reported"); + XMLAddChild(x, reported); + + /* Report */ + Report("mem-alloc", "Heap allocated with Cytoplasm"); + Report("xml-congest", "Unprocessed stanzas(congestion)"); + + /* Set */ + BeginItem(); + { + char *min_str = StrInt(min); + char *congest = StrInt(ParseeCongestion()); + char *alloc = StrConcat(3, min_str, " ", unit); + + SetField("mem-alloc", alloc); + SetField("xml-congest", congest); + + Free(congest); + Free(min_str); + Free(alloc); + } + EndItem(); + } + XMLAddChild(out, x); +} diff --git a/src/XMPPThread.c b/src/XMPPThread.c index 753ada2..db5b2da 100644 --- a/src/XMPPThread.c +++ b/src/XMPPThread.c @@ -1565,78 +1565,6 @@ ParseeCongestion(void) return congestion; } -static void -StatusCallback(XMPPCommandManager *m, HashMap *data, XMLElement *out) -{ - size_t alloc = MemoryAllocated(); - size_t kb = alloc >> 10; - size_t mb = kb >> 10; - size_t gb = mb >> 10; - size_t min = gb ? gb : (mb ? mb : (kb ? kb : alloc)); - char *unit = gb ? "GB" : (mb ? "MB" : (kb ? "KB" : "B")); - XMLElement *x = XMLCreateTag("x"); - XMLElement *title = XMLCreateTag("title"); - - { - XMLElement *title_text = XMLCreateText("Parsee statistics"); - XMLAddChild(title, title_text); - } - XMLAddChild(x, title); - - XMLAddAttr(x, "xmlns", "jabber:x:data"); - XMLAddAttr(x, "type", "result"); - { - XMLElement *reported, *item, *field, *value, *txt; - reported = XMLCreateTag("reported"); - XMLAddChild(x, reported); -#define Report(id, label) do \ - { \ - field = XMLCreateTag("field"); \ - XMLAddAttr(field, "var", id); \ - XMLAddAttr(field, "label", label); \ - XMLAddChild(reported, field); \ - } \ - while(0) -#define BeginItem() item = XMLCreateTag("item") -#define EndItem() XMLAddChild(x, item) -#define SetField(id, val) do \ - { \ - field = XMLCreateTag("field"); \ - value = XMLCreateTag("value"); \ - txt = XMLCreateText(val); \ - XMLAddAttr(field, "var", id); \ - XMLAddChild(value, txt); \ - XMLAddChild(field, value); \ - XMLAddChild(item, field); \ - } \ - while(0) - - /* Report */ - Report("mem-alloc", "Heap allocated with Cytoplasm"); - Report("xml-congest", "Unprocessed stanzas(congestion)"); - - /* Set */ - BeginItem(); - { - char *min_str = StrInt(min); - char *congest = StrInt(ParseeCongestion()); - char *alloc = StrConcat(3, min_str, " ", unit); - - SetField("mem-alloc", alloc); - SetField("xml-congest", congest); - - Free(congest); - Free(min_str); - Free(alloc); - } - EndItem(); -#undef SetField -#undef EndItem -#undef BeginItem -#undef Report - } - XMLAddChild(out, x); -} void * ParseeXMPPThread(void *argp) { @@ -1649,15 +1577,17 @@ ParseeXMPPThread(void *argp) await_table = HashMapCreate(); /* Initialise the command manager, and add all ad-hoc commands */ - info.m = XMPPCreateManager(); + info.m = XMPPCreateManager(args); { XMPPCommand *cmd; - - cmd = XMPPBasicCmd( - "status", "Get status about Parsee", - StatusCallback - ); +#define XMPP_COMMAND(f,n,t,s) \ + cmd = XMPPBasicCmd( \ + n, t, f \ + ); \ + s \ XMPPRegisterCommand(info.m, cmd); + XMPPCOMMANDS +#undef XMPP_COMMAND } /* Initialise the FIFO */ diff --git a/src/include/XMPPCommand.h b/src/include/XMPPCommand.h index 27e7225..095634f 100644 --- a/src/include/XMPPCommand.h +++ b/src/include/XMPPCommand.h @@ -10,15 +10,16 @@ typedef struct XMPPCommandManager XMPPCommandManager; typedef struct XMPPCommand XMPPCommand; typedef struct XMPPOption XMPPOption; -typedef void (*XMPPCmdCallback)(XMPPCommandManager *, HashMap *, XMLElement *); +typedef void (*XMPPCmdCallback)(XMPPCommandManager *, char *, HashMap *, XMLElement *); /** Creates a simple XMPP command manager, which routes commands - * with a single-stage form system. + * with a single-stage form system, with a {cookie} * ------------------------------------------- * Returns: An opaque command manager[LA:HEAP] * Modifies: NOTHING * See-Also: XMPPFreeManager */ -extern XMPPCommandManager * XMPPCreateManager(void); +extern XMPPCommandManager * XMPPCreateManager(void *cookie); +extern void * XMPPGetManagerCookie(XMPPCommandManager *manager); /** Create a basic command with a node and name description * ----------------------------------------------------- @@ -31,7 +32,7 @@ extern XMLElement * XMPPFormifyCommand(XMPPCommand *cmd); extern char * XMPPGetCommandNode(XMPPCommand *cmd); extern char * XMPPGetCommandDesc(XMPPCommand *cmd); extern bool XMPPCommandRequiresForm(XMPPCommand *cmd); -extern void XMPPExecuteCommand(XMPPCommandManager *m, XMPPCommand *cmd, XMLElement *to, HashMap *arg_table); +extern void XMPPExecuteCommand(XMPPCommandManager *m, XMPPCommand *cmd, char *from, XMLElement *to, HashMap *arg_table); /** Create a basic option. * ----------------------------------------------------- @@ -80,4 +81,15 @@ extern void XMPPFreeManager(XMPPCommandManager *manager); * Modifies: {manager} * See-Also: XMPPCreateManager */ extern bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data); + + +/* --------------------------------- COMMANDS --------------------------------- */ +#define XMPPCOMMANDS \ + XMPP_COMMAND(StatusCallback, "stats", "Get Parsee statistics", {}) \ + XMPP_COMMAND(AdminsCallback, "admin", "Get Parsee admin list", {}) \ + XMPP_COMMAND(NoflyCallback, "nofly", "Get Parsee nofly list", {}) + +#define XMPP_COMMAND(f,n,t,s) extern void f(XMPPCommandManager *, char *, HashMap *, XMLElement *); + XMPPCOMMANDS +#undef XMPP_COMMAND #endif diff --git a/src/include/XMPPFormTool.h b/src/include/XMPPFormTool.h new file mode 100644 index 0000000..2e44f94 --- /dev/null +++ b/src/include/XMPPFormTool.h @@ -0,0 +1,38 @@ +#ifndef PARSEE_FORM_H +#define PARSEE_FORM_H + +#define Report(id, label) do \ + { \ + field = XMLCreateTag("field"); \ + XMLAddAttr(field, "var", id); \ + XMLAddAttr(field, "label", label); \ + XMLAddChild(reported, field); \ + } \ + while(0) +#define BeginItem() item = XMLCreateTag("item") +#define EndItem() XMLAddChild(x, item) +#define SetField(id, val) do \ + { \ + field = XMLCreateTag("field"); \ + value = XMLCreateTag("value"); \ + txt = XMLCreateText(val); \ + XMLAddAttr(field, "var", id); \ + XMLAddChild(value, txt); \ + XMLAddChild(field, value); \ + XMLAddChild(item, field); \ + } \ + while(0) +#define SetFixed(id, val) do \ + { \ + field = XMLCreateTag("field"); \ + value = XMLCreateTag("value"); \ + txt = XMLCreateText(val); \ + XMLAddAttr(field, "var", id); \ + XMLAddAttr(field, "type", "fixed"); \ + XMLAddChild(value, txt); \ + XMLAddChild(field, value); \ + XMLAddChild(item, field); \ + } \ + while(0) + +#endif