[ADD/WIP] Create and use basic command parser

Still need to write the router.
This commit is contained in:
LDA 2024-06-28 22:34:28 +02:00
commit c4b7d1b92a
6 changed files with 220 additions and 12 deletions

133
src/Command/Parser.c Normal file
View file

@ -0,0 +1,133 @@
#include <Command.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Str.h>
#include <string.h>
#include <ctype.h>
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);
}

49
src/Command/Router.c Normal file
View file

@ -0,0 +1,49 @@
#include <Command.h>
#include <Cytoplasm/Memory.h>
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);
}

View file

@ -73,6 +73,7 @@ ParseeBotHandler(ParseeData *data, HashMap *event)
"@", data->config->sender_localpart, "@", data->config->sender_localpart,
":", data->config->homeserver_host ":", data->config->homeserver_host
); );
Command *cmd;
if (StrEquals(msgtype, "m.notice")) if (StrEquals(msgtype, "m.notice"))
{ {
@ -104,17 +105,17 @@ ParseeBotHandler(ParseeData *data, HashMap *event)
return; return;
} }
body++; body++;
#define BAN_USER "ban-user " #define BAN_USER "ban-user"
#define BAN_LIST "ban-list " #define BAN_LIST "ban-list"
#define LS_USERS "ls-flying" #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 *user = HashMapGet(cmd->arguments, "user");
char room[256] = { 0 }; char *room = HashMapGet(cmd->arguments, "user");
char *msg; char *msg;
body += strlen(BAN_USER); if (!user || !room)
if (sscanf(body, "%255s %255s", &user, &room) != 2)
{ {
goto end; goto end;
} }
@ -128,7 +129,7 @@ ParseeBotHandler(ParseeData *data, HashMap *event)
)); ));
Free(msg); 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"); DbRef *listed = DbLock(data->db, 1, "global_bans");
HashMap *json = DbJson(listed); HashMap *json = DbJson(listed);
@ -156,13 +157,12 @@ ParseeBotHandler(ParseeData *data, HashMap *event)
Free(str); Free(str);
DbUnlock(data->db, listed); 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; char *msg;
body += strlen(BAN_USER); if (!user)
if (sscanf(body, "%255s", &user) != 1)
{ {
goto end; goto end;
} }
@ -178,6 +178,7 @@ ParseeBotHandler(ParseeData *data, HashMap *event)
} }
end: end:
Free(profile); Free(profile);
CommandFree(cmd);
} }
static void static void
ParseeMessageHandler(ParseeData *data, HashMap *event) ParseeMessageHandler(ParseeData *data, HashMap *event)

View file

@ -24,6 +24,7 @@ ParseeInitData(XMPPComponent *comp)
data->config = ParseeConfigGet(); data->config = ParseeConfigGet();
data->router = HttpRouterCreate(); data->router = HttpRouterCreate();
data->jabber = comp; data->jabber = comp;
data->handler = CommandCreateRouter();
data->db = DbOpen(data->config->db_path, 0); data->db = DbOpen(data->config->db_path, 0);
#define X_ROUTE(path, func) do {\ #define X_ROUTE(path, func) do {\
@ -48,6 +49,7 @@ ParseeFreeData(ParseeData *data)
XMPPEndCompStream(data->jabber); XMPPEndCompStream(data->jabber);
DbClose(data->db); DbClose(data->db);
HttpRouterFree(data->router); HttpRouterFree(data->router);
CommandFreeRouter(data->handler);
Free(data); Free(data);
} }

21
src/include/Command.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef PARSEE_COMMAND_H
#define PARSEE_COMMAND_H
#include <Cytoplasm/HashMap.h>
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

View file

@ -9,6 +9,7 @@
#include <pthread.h> #include <pthread.h>
#include <Command.h>
#include <XMPP.h> #include <XMPP.h>
typedef struct ParseeConfig { typedef struct ParseeConfig {
@ -43,6 +44,7 @@ typedef struct ParseeConfig {
typedef struct ParseeData { typedef struct ParseeData {
const ParseeConfig *config; const ParseeConfig *config;
HttpRouter *router; HttpRouter *router;
CommandRouter *handler;
XMPPComponent *jabber; XMPPComponent *jabber;