From c4b7d1b92afd360639cb0021cd997af3c5752a8c Mon Sep 17 00:00:00 2001 From: LDA Date: Fri, 28 Jun 2024 22:34:28 +0200 Subject: [PATCH] [ADD/WIP] Create and use basic command parser Still need to write the router. --- src/Command/Parser.c | 133 +++++++++++++++++++++++++++++++++++++++ src/Command/Router.c | 49 +++++++++++++++ src/MatrixEventHandler.c | 25 ++++---- src/Parsee/Data.c | 2 + src/include/Command.h | 21 +++++++ src/include/Parsee.h | 2 + 6 files changed, 220 insertions(+), 12 deletions(-) create mode 100644 src/Command/Parser.c create mode 100644 src/Command/Router.c create mode 100644 src/include/Command.h diff --git a/src/Command/Parser.c b/src/Command/Parser.c new file mode 100644 index 0000000..c0718b6 --- /dev/null +++ b/src/Command/Parser.c @@ -0,0 +1,133 @@ +#include + +#include +#include +#include +#include + +typedef enum CommandState { + STATE_WHITE, + STATE_NAME, + STATE_VALUE +} CommandState; + +Command * +CommandParse(char *cmd) +{ + Command *ret; + char *end_data, *cur, *namestart; + char *key = NULL, *val = NULL; + size_t len; + CommandState state = STATE_WHITE; + if (!cmd) + { + return NULL; + } + + end_data = strchr(cmd, ' '); + if (!end_data) + { + ret = Malloc(sizeof(*ret)); + ret->command = StrDuplicate(cmd); + ret->arguments = HashMapCreate(); + + return ret; + } + + len = end_data - cmd; + ret = Malloc(sizeof(*ret)); + ret->arguments = HashMapCreate(); + ret->command = Malloc(len + 1); + memcpy(ret->command, cmd, len); + ret->command[len] = '\0'; + + cur = end_data + 1; + + /* Parse arguments */ + while (*cur) + { + char c = *cur; + char *tmp; + bool type; + switch (state) + { + case STATE_WHITE: + if (!isblank(c)) + { + state = STATE_NAME; + namestart = cur; + continue; + } + break; + case STATE_NAME: + if (c == '=') + { + len = cur - namestart; + key = Malloc(len + 1); + memcpy(key, namestart, len); + key[len] = '\0'; + state = STATE_VALUE; + cur++; + val = NULL; + continue; + } + break; + case STATE_VALUE: + type = c == '"'; + if (type) + { + cur++; + } + while (*cur) + { + char c = *cur; + char cb[2] = { c, '\0' }; + if ((type && c == '"') || (!type && isblank(c))) + { + break; + } + + if (c == '\\' && *(cur + 1) == '"') + { + cb[0] = '"'; + cur++; + } + tmp = val; + val = StrConcat(2, val, cb); + Free(tmp); + + cur++; + } + Free(HashMapSet(ret->arguments, key, val)); + Free(key); + key = NULL; + val = NULL; + state = STATE_WHITE; + break; + } + cur++; + } + Free(key); + Free(val); + + return ret; +} + +void +CommandFree(Command *command) +{ + char *key, *val; + if (!command) + { + return; + } + + while (HashMapIterate(command->arguments, &key, (void **) &val)) + { + Free(val); + } + HashMapFree(command->arguments); + + Free(command->command); + Free(command); +} diff --git a/src/Command/Router.c b/src/Command/Router.c new file mode 100644 index 0000000..d188640 --- /dev/null +++ b/src/Command/Router.c @@ -0,0 +1,49 @@ +#include + +#include + +struct CommandRouter { + HashMap *routes; +}; +CommandRouter * +CommandCreateRouter(void) +{ + CommandRouter *router = Malloc(sizeof(*router)); + router->routes = HashMapCreate(); + return router; +} +void +CommandAddCommand(CommandRouter *rter, char *c, CommandRoute rte) +{ + if (!rter || !c || !rte) + { + return; + } + HashMapSet(rter->routes, c, rte); +} +void +RouteCommand(CommandRouter *rter, Command *cmd, void *d) +{ + CommandRoute route; + if (!rter || !cmd) + { + return; + } + + route = HashMapGet(rter->routes, cmd->command); + if (route) + { + route(cmd, d); + } +} +void +CommandFreeRouter(CommandRouter *rter) +{ + if (!rter) + { + return; + } + + HashMapFree(rter->routes); + Free(rter); +} diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index a397eca..d42a8b5 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -73,6 +73,7 @@ ParseeBotHandler(ParseeData *data, HashMap *event) "@", data->config->sender_localpart, ":", data->config->homeserver_host ); + Command *cmd; if (StrEquals(msgtype, "m.notice")) { @@ -104,17 +105,17 @@ ParseeBotHandler(ParseeData *data, HashMap *event) return; } body++; -#define BAN_USER "ban-user " -#define BAN_LIST "ban-list " +#define BAN_USER "ban-user" +#define BAN_LIST "ban-list" #define LS_USERS "ls-flying" - if (!strncmp(body, BAN_USER, strlen(BAN_USER))) + cmd = CommandParse(body); + if (cmd && StrEquals(cmd->command, BAN_USER)) { - char user[256] = { 0 }; - char room[256] = { 0 }; + char *user = HashMapGet(cmd->arguments, "user"); + char *room = HashMapGet(cmd->arguments, "user"); char *msg; - body += strlen(BAN_USER); - if (sscanf(body, "%255s %255s", &user, &room) != 2) + if (!user || !room) { goto end; } @@ -128,7 +129,7 @@ ParseeBotHandler(ParseeData *data, HashMap *event) )); Free(msg); } - else if (!strncmp(body, LS_USERS, strlen(LS_USERS))) + else if (cmd && StrEquals(cmd->command, LS_USERS)) { DbRef *listed = DbLock(data->db, 1, "global_bans"); HashMap *json = DbJson(listed); @@ -156,13 +157,12 @@ ParseeBotHandler(ParseeData *data, HashMap *event) Free(str); DbUnlock(data->db, listed); } - else if (!strncmp(body, BAN_LIST, strlen(BAN_LIST))) + else if (cmd && StrEquals(cmd->command, BAN_LIST)) { - char user[256] = { 0 }; + char *user = HashMapGet(cmd->arguments, "user"); char *msg; - body += strlen(BAN_USER); - if (sscanf(body, "%255s", &user) != 1) + if (!user) { goto end; } @@ -178,6 +178,7 @@ ParseeBotHandler(ParseeData *data, HashMap *event) } end: Free(profile); + CommandFree(cmd); } static void ParseeMessageHandler(ParseeData *data, HashMap *event) diff --git a/src/Parsee/Data.c b/src/Parsee/Data.c index 58d9ab1..d2072ae 100644 --- a/src/Parsee/Data.c +++ b/src/Parsee/Data.c @@ -24,6 +24,7 @@ ParseeInitData(XMPPComponent *comp) data->config = ParseeConfigGet(); data->router = HttpRouterCreate(); data->jabber = comp; + data->handler = CommandCreateRouter(); data->db = DbOpen(data->config->db_path, 0); #define X_ROUTE(path, func) do {\ @@ -48,6 +49,7 @@ ParseeFreeData(ParseeData *data) XMPPEndCompStream(data->jabber); DbClose(data->db); HttpRouterFree(data->router); + CommandFreeRouter(data->handler); Free(data); } diff --git a/src/include/Command.h b/src/include/Command.h new file mode 100644 index 0000000..44734c4 --- /dev/null +++ b/src/include/Command.h @@ -0,0 +1,21 @@ +#ifndef PARSEE_COMMAND_H +#define PARSEE_COMMAND_H + +#include + +typedef struct Command { + char *command; + HashMap *arguments; +} Command; + +typedef struct CommandRouter CommandRouter; +typedef void (*CommandRoute)(Command *cmd, void *data); + +extern CommandRouter * CommandCreateRouter(void); +extern void CommandAddCommand(CommandRouter *rter, char *c, CommandRoute rte); +extern void RouteCommand(CommandRouter *rter, Command *cmd, void *data); +extern void CommandFreeRouter(CommandRouter *rter); + +extern Command * CommandParse(char *cmd); +extern void CommandFree(Command *command); +#endif diff --git a/src/include/Parsee.h b/src/include/Parsee.h index 89bee51..b34e840 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -9,6 +9,7 @@ #include +#include #include typedef struct ParseeConfig { @@ -43,6 +44,7 @@ typedef struct ParseeConfig { typedef struct ParseeData { const ParseeConfig *config; HttpRouter *router; + CommandRouter *handler; XMPPComponent *jabber;