[ADD/MOD] Cleanup cmd, change Matrix user format

This commit is contained in:
LDA 2024-07-14 20:00:41 +02:00
commit 91d373addb
13 changed files with 217 additions and 77 deletions

View file

@ -35,13 +35,15 @@ TODO
TODO
## TODOS
- Mess with Cytoplasm to make it have support for something like Berkeley DB as
an *optional* dependency. This should increase reliability and speed for anyone.
- Mess with Cytoplasm to make it have support for something like LMDB as an
*optional* dependency. This should increase reliability and speed for anyone.
- Nesting might be an issue we'll need to deal with. libdb and Berkley DB
seem to lack support for them. If we can shove entries at specific indices,
we _might_ just manage to get some system that can at least emulate that,
and hopefully be reasonably faster than the filesystem, with some added
reliability.
- Starting a DM from XMPP to a Matrix user(and also get rid of the '?'-syntax and
use another invalid Matrix char/valid XMPP char ('$'?) for escaped)
- PROPER FUCKING AVATARS
XEP-0084 IS THE WORST PIECE OF SHIT KNOWN TO MAN. If any Jabberbros want to

View file

@ -28,6 +28,9 @@ For future XEPs:
- https://xmpp.org/extensions/xep-0449.html
Stickers are great. Matrix and XMPP somewhat has support for them, so
might be a nice-to-have, and also to push over XMPP support.
A minor issue with that is pack management. XMPP requires a pack field
which is used along PEP, it seems, and meanwhile Matrix has ''support''
for packs too, tracking them is between "annoyance" and "yeah, no.".
- https://xmpp.org/extensions/xep-0050.html
Ad-hoc commands that bridge maintainers can deal with XMPP-style are
also a nice to have.
@ -46,6 +49,7 @@ THESE I WANT TO SEND THEM A NICE, BRIGHT GIFT:
Not XEPs, but ideas that _needs_ to be added:
- "GIVE THE PUPPETS APPROPRIATE PLS/ROLES" - Hydro/t4d
"also it [Bifrost] doesn't respect voice either"
- Standalone/Static Parsee, ideally as small as it can be(if not as APE).
- https://www.youtube.com/watch?v=InL414iDZmY

View file

@ -22,6 +22,13 @@ static HttpServer *server = NULL;
static pthread_t xmpp_thr;
static XMPPComponent *jabber = NULL;
static volatile uint64_t start;
uint64_t
ParseeUptime(void)
{
return UtilTsMillis() - start;
}
int
Main(void)
{
@ -30,6 +37,8 @@ Main(void)
Stream *yaml;
Cron *cron = NULL;
start = UtilTsMillis();
memset(&conf, 0, sizeof(conf));
Log(LOG_INFO,
"%s - v%s (Cytoplasm %s)",

View file

@ -60,6 +60,8 @@ ParseeMemberHandler(ParseeData *data, HashMap *event)
XMPPJoinMUC(data->jabber, jid, rev);
Free(rev);
Free(muc);
/* TODO: XEP-0084 magic to advertise a new avatar if possible. */
}
Free(jid);
Free(chat_id);

View file

@ -824,3 +824,40 @@ ParseeManageBan(ParseeData *data, char *user, char *room)
return banned;
}
char *
ParseeStringifyDate(uint64_t millis)
{
uint64_t rest = millis;
uint64_t hours, minutes, seconds;
char *hs, *ms, *ss, *out;
hours = rest / (1 HOURS);
rest = rest % (1 HOURS);
minutes = rest / (1 MINUTES);
rest = rest % (1 MINUTES);
seconds = rest / (1 SECONDS);
hs = StrInt(hours);
ms = StrInt(minutes);
ss = StrInt(seconds);
out = StrConcat(8,
hours ? hs : "",
hours ? " hours" : "",
(hours && minutes) ? ", " : "",
minutes ? ms : "",
minutes ? " minutes" : "",
(minutes && seconds) ? ", " : "",
seconds ? ss : "",
seconds ? " seconds" : ""
);
Free(hs);
Free(ms);
Free(ss);
return out;
}

View file

@ -39,22 +39,6 @@ ParseeIsPuppet(const ParseeConfig *conf, char *user)
* room. */
return flag;
}
bool
ParseeIsJabberPuppet(const ParseeConfig *config, char *jid)
{
char *resource;
bool ret;
if (!config || !jid)
{
return false;
}
resource = ParseeGetResource(jid);
ret = *resource == '%';
Free(resource);
return ret;
}
char *
ParseeDecodeJID(char *str, char term)
{
@ -155,6 +139,7 @@ ParseeDecodeLocalMUC(const ParseeConfig *c, char *alias)
return ParseeDecodeJID(data_start, ':');
}
static const char *HEX = "0123456789abcdef";
char *
ParseeEncodeJID(const ParseeConfig *c, char *jid, bool trim)
{
@ -168,7 +153,6 @@ ParseeEncodeJID(const ParseeConfig *c, char *jid, bool trim)
ret = StrConcat(2, c->namespace_base, "_l_");
for (i = 0; i < strlen(jid); i++)
{
const char *HEX = "0123456789abcdef";
char cpy = jid[i];
char cs[4] = { 0 };
cs[0] = cpy;
@ -237,60 +221,75 @@ char *
ParseeEncodeMXID(char *mxid)
{
char *ret;
size_t i;
size_t i, j;
if (!mxid)
{
return NULL;
}
ret = Malloc(strlen(mxid) + 1);
for (i = 0; i < strlen(mxid) + 1; i++)
/* Worst case scenario of 3-bytes the char */
ret = Malloc(strlen(mxid) * 3 + 1);
for (i = 0, j = 0; i < strlen(mxid); i++)
{
char src = mxid[i];
/* TODO: More robust system */
if (src == '@')
if (src <= 0x20 ||
(src == '"' || src == '&' ||
src == '\'' || src == '/' ||
src == ':' || src == '<' ||
src == '>' || src == '@' ||
src == 0x7F))
{
src = '%';
ret[j++] = '?';
ret[j++] = HEX[(src & 0xF0) >> 4];
ret[j++] = HEX[(src & 0x0F) >> 0];
continue;
}
else if (src == ':')
{
src = '=';
}
ret[i] = src;
ret[j++] = src;
}
ret[j] = '\0';
return ret;
}
char *
ParseeDecodeMXID(char *mxid)
{
char *ret;
size_t i;
char *out = NULL;
if (!mxid)
{
return NULL;
}
ret = Malloc(strlen(mxid) + 1);
for (i = 0; i < strlen(mxid) + 1; i++)
#define Okay(c) ((c) && (c != '@'))
while (Okay(*mxid))
{
char src = mxid[i];
if (src == '%')
char c = *mxid;
char buf[3] = { 0 };
char *tmp;
if (c == '?' && Okay(*(mxid + 1)) && Okay(*(mxid + 2)))
{
src = '@';
}
else if (src == '=')
{
src = ':';
}
else if (src == '@')
{
ret[i] = '\0';
break;
}
ret[i] = src;
}
mxid++;
return ret;
memcpy(buf, mxid, 2);
buf[0] = strtol(buf, NULL, 16);
buf[1] = '\0';
tmp = StrConcat(2, out, buf);
Free(out);
out = tmp;
mxid += 2;
continue;
}
memcpy(buf, mxid, 1);
tmp = StrConcat(2, out, buf);
Free(out);
out = tmp;
mxid++;
}
#undef Okay
return out;
}
char *
ParseeGetDMID(char *mxid, char *jid)

View file

@ -8,6 +8,10 @@ struct XMPPCommand {
XMPPCmdCallback callback;
char *node, *name;
char *form_instruction;
char *form_title;
/* TODO: On-the-fly generation of options */
Array *options;
};
@ -25,12 +29,34 @@ XMPPBasicCmd(char *node, char *name, XMPPCmdCallback callback_funct)
cmd->callback = callback_funct;
cmd->node = StrDuplicate(node);
cmd->name = StrDuplicate(name);
cmd->form_instruction = NULL;
cmd->form_title = NULL;
/* No options -> no form required */
cmd->options = NULL;
return cmd;
}
void
XMPPSetFormTitle(XMPPCommand *cmd, char *title)
{
if (!cmd)
{
return;
}
Free(cmd->form_title);
cmd->form_title = StrDuplicate(title);
}
void
XMPPSetFormInstruction(XMPPCommand *cmd, char *instruction)
{
if (!cmd)
{
return;
}
Free(cmd->form_instruction);
cmd->form_instruction = StrDuplicate(instruction);
}
void
XMPPFreeCommand(XMPPCommand *cmd)
{
@ -47,6 +73,8 @@ XMPPFreeCommand(XMPPCommand *cmd)
}
ArrayFree(cmd->options);
XMPPSetFormInstruction(cmd, NULL);
XMPPSetFormTitle(cmd, NULL);
Free(cmd->node);
Free(cmd->name);
Free(cmd);
@ -80,6 +108,25 @@ XMPPFormifyCommand(XMPPCommand *cmd)
x = XMLCreateTag("x");
XMLAddAttr(x, "xmlns", "jabber:x:data");
XMLAddAttr(x, "type", "form");
if (cmd->form_title)
{
XMLElement *instr_xml, *instr_txt;
instr_xml = XMLCreateTag("title");
instr_txt = XMLCreateText(cmd->form_title);
XMLAddChild(instr_xml, instr_txt);
XMLAddChild(x, instr_xml);
}
if (cmd->form_instruction)
{
XMLElement *instr_xml, *instr_txt;
instr_xml = XMLCreateTag("instructions");
instr_txt = XMLCreateText(cmd->form_instruction);
XMLAddChild(instr_xml, instr_txt);
XMLAddChild(x, instr_xml);
}
/* TODO: Other fields */
for (i = 0; i < ArraySize(cmd->options); i++)
@ -117,23 +164,6 @@ XMPPExecuteCommand(XMPPCommandManager *m, XMPPCommand *cmd, char *from, XMLEleme
cmd->callback(m, from, form, to);
}
void
XMPPShoveOptions(XMPPCommand *cmd, XMLElement *form)
{
size_t i;
if (!cmd || !form)
{
return;
}
for (i = 0; i < ArraySize(cmd->options); i++)
{
XMPPOption *opt = ArrayGet(cmd->options, i);
XMLElement *xml = XMPPOptionToXML(opt);
XMLAddChild(form, xml);
}
}
bool
XMPPVerifyForm(XMPPCommand *cmd, XMLElement *form)
{
@ -157,7 +187,7 @@ XMPPVerifyForm(XMPPCommand *cmd, XMLElement *form)
/* Required field not found; die. */
return false;
}
/* TODO */
/* TODO: Verify type, array membership, uniqueness, etc... */
}
}

View file

@ -252,7 +252,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data)
{
XMLElement *actions = XMLCreateTag("actions");
XMLElement *completed = XMLCreateTag("complete");
XMLElement *x = XMLCreateTag("x");
XMLElement *x;
XMLAddChild(actions, completed);
session_id = XMPPRegisterSession(m, to, from, node);
@ -271,9 +271,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data)
XMLAddChild(command_xml, actions);
XMLAddChild(iq, command_xml);
XMLAddAttr(x, "xmlns", "jabber:x:data");
XMLAddAttr(x, "type", "form");
XMPPShoveOptions(cmd, x);
x = XMPPFormifyCommand(cmd);
XMLAddChild(command_xml, x);
pthread_mutex_lock(&jabber->write_lock);
@ -286,6 +284,11 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data)
}
/* Doesn't need to be freed, as it lives with m. */
/* TODO: I've noticed memory leakages around here with a
* StrDuplicate'd session ID. I think StrDuplicate should
* just "rat out" the original source in cases of leaks
* like this, maybe with extra data beyond the NULL-terminator */
session_id = XMPPRegisterSession(m, to, from, node);
/* No forms, we good. */

View file

@ -175,6 +175,8 @@ XMPPOptionToXML(XMPPOption *opt)
data = XMLCreateText(opt->desc);
XMLAddChild(desc, data);
XMLAddChild(elem, desc);
XMLAddAttr(elem, "label", opt->desc);
}
if (opt->type == XMPP_OPTION_LIST)

View file

@ -0,0 +1,32 @@
#include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Util.h>
#include <Cytoplasm/Str.h>
#include <Cytoplasm/Log.h>
#include <XMPPFormTool.h>
#include <XMPPCommand.h>
#include <Parsee.h>
#include <XMPP.h>
#include <XML.h>
void
CleanCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
{
ParseeData *data = XMPPGetManagerCookie(m);
char *trimmed = ParseeTrimJID(from);
if (!ParseeIsAdmin(data, trimmed))
{
SetNote("error", "User is not authorised to execute command.");
Free(trimmed);
return;
}
Free(trimmed);
ParseeCleanup(data);
/* TODO: Cleanup old sessions? */
SetNote("info", "Parsee data was sucessfully cleant up.");
}

View file

@ -22,6 +22,7 @@ StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *
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;
@ -52,6 +53,7 @@ StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *
/* Report */
Report("mem-alloc", "Heap allocated with Cytoplasm");
Report("xml-congest", "Unprocessed stanzas(congestion)");
Report("uptime", "Parsee uptime");
/* Set */
BeginItem();
@ -59,13 +61,16 @@ StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *
char *min_str = StrInt(min);
char *congest = StrInt(ParseeCongestion());
char *alloc = StrConcat(3, min_str, " ", unit);
char *up = ParseeStringifyDate(ParseeUptime());
SetField("mem-alloc", alloc);
SetField("xml-congest", congest);
SetField("uptime", up);
Free(congest);
Free(min_str);
Free(alloc);
Free(up);
}
EndItem();
}

View file

@ -53,7 +53,7 @@ typedef struct ParseeData {
#define GrabObject(obj, ...) JsonValueAsObject(JsonGet(obj, __VA_ARGS__))
#define GrabArray(obj, ...) JsonValueAsArray(JsonGet(obj, __VA_ARGS__))
/* Milliseconds to UNIT macros, to be used like 30 SECONDS and 1 MINUTE
/* Milliseconds to UNIT macros, to be used like 30 SECONDS and 1 MINUTES
* in timestamps */
#define SECONDS * 1000
#define MINUTES * 60 SECONDS
@ -90,9 +90,6 @@ extern void ParseeEventHandler(ParseeData *, HashMap *);
/* Verifies if a user is a Parsee puppet user. */
extern bool ParseeIsPuppet(const ParseeConfig *, char *);
/* Verifies if a user is a Parsee puppet user on XMPP. */
extern bool ParseeIsJabberPuppet(const ParseeConfig *, char *);
/* Decodes a local JID for a user into a string. */
extern char * ParseeDecodeLocalJID(const ParseeConfig *, char *);
@ -230,4 +227,10 @@ extern bool ParseeVerifyDMStanza(ParseeData *data, char *room_id, char *id);
/* Checks if any user is an admin */
extern bool ParseeIsAdmin(ParseeData *data, char *user);
/* Measures Parsee's overall uptime */
extern uint64_t ParseeUptime(void);
/* Turns a date into a nice "X minutes, Y seconds" string */
extern char * ParseeStringifyDate(uint64_t millis);
#endif

View file

@ -31,6 +31,8 @@ extern void XMPPAddOption(XMPPCommand *cmd, XMPPOption *opt);
extern XMLElement * XMPPFormifyCommand(XMPPCommand *cmd);
extern char * XMPPGetCommandNode(XMPPCommand *cmd);
extern char * XMPPGetCommandDesc(XMPPCommand *cmd);
extern void XMPPSetFormInstruction(XMPPCommand *cmd, char *instruction);
extern void XMPPSetFormTitle(XMPPCommand *cmd, char *title);
extern bool XMPPCommandRequiresForm(XMPPCommand *cmd);
extern void XMPPExecuteCommand(XMPPCommandManager *m, XMPPCommand *cmd, char *from, XMLElement *to, XMLElement *form);
@ -51,7 +53,6 @@ extern bool XMPPIsOptionRequired(XMPPOption *opt);
extern char * XMPPOptionVar(XMPPOption *opt);
extern XMLElement * XMPPOptionToXML(XMPPOption *opt);
extern void XMPPShoveOptions(XMPPCommand *cmd, XMLElement *form);
extern void XMPPFreeOption(XMPPOption *opt);
extern void XMPPFreeCommand(XMPPCommand *cmd);
@ -92,11 +93,16 @@ extern bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeD
/* --------------------------------- COMMANDS --------------------------------- */
#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(AddNoflyCallback, "add-nofly", "Adds user to nofly", { \
XMPPOption *entity = XMPPCreateText(true, "entity", ""); \
@ -105,10 +111,16 @@ extern bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeD
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"); \
}) \
XMPP_COMMAND(NoflyCallback, "nofly", "Get Parsee nofly list", {})
#define XMPP_COMMAND(f,n,t,s) extern void f(XMPPCommandManager *, char *, XMLElement *, XMLElement *);
#define XMPP_COMMAND(f,n,t,s) \
extern void \
f(XMPPCommandManager *, char *, XMLElement *, XMLElement *);
XMPPCOMMANDS
#undef XMPP_COMMAND
#endif