[FIX/WIP] Plumbing, -Werror, death to hitmen

Suspend killers are now no more. Except the actual killers to be gone
eventually.
Plumbing is also very basic as of now, but it "works".
This commit is contained in:
LDA 2024-07-05 20:24:15 +02:00
commit bb836789b2
23 changed files with 310 additions and 165 deletions

View file

@ -222,19 +222,33 @@ ASKick(const ParseeConfig *conf, char *id, char *banned)
HttpClientContextFree(ctx);
JsonFree(json);
}
void
char *
ASJoin(const ParseeConfig *conf, char *id, char *masquerade)
{
HttpClientContext *ctx = NULL;
HashMap *json = NULL;
char *path;
if (!conf || !id || !masquerade)
char *path, *ret;
if (!conf || !id)
{
return;
return NULL;
}
if (!masquerade)
{
char *raw = StrConcat(4,
"@", conf->sender_localpart,
":", conf->homeserver_host
);
masquerade = HttpUrlEncode(raw);
Free(raw);
}
else
{
masquerade = HttpUrlEncode(masquerade);
}
id = HttpUrlEncode(id);
path = StrConcat(5,
"/_matrix/client/v3/rooms/", id, "/join?",
"/_matrix/client/v3/join/", id, "?",
"user_id=", masquerade
);
@ -246,15 +260,23 @@ ASJoin(const ParseeConfig *conf, char *id, char *masquerade)
json = HashMapCreate();
ASAuthenticateRequest(conf, ctx);
ParseeSetRequestJSON(ctx, json);
JsonFree(json);
json = JsonDecode(HttpClientStream(ctx));
ret = StrDuplicate(GrabString(json, 1, "room_id"));
JsonFree(json);
HttpClientContextFree(ctx);
JsonFree(json);
Free(masquerade);
Free(id);
return ret;
}
void
ASSetState(const ParseeConfig *conf, char *id, char *type, char *key, char *mask, HashMap *state)
{
HttpClientContext *ctx = NULL;
char *path, *params;
char *path;
if (!conf || !id || !type || !mask || !state)
{
JsonFree(state);
@ -278,7 +300,7 @@ char *
ASSend(const ParseeConfig *conf, char *id, char *user, char *type, HashMap *c)
{
HttpClientContext *ctx = NULL;
char *path, *params;
char *path;
char *txn, *ret;
HashMap *reply;
if (!conf || !id || !type || !user || !c)
@ -626,7 +648,6 @@ ASReupload(const ParseeConfig *c, char *from, char **mime)
HttpClientContext *ctx;
unsigned short port;
int size = 0, flags = HTTP_FLAG_NONE;
int i;
char *ret, *content_len;
if (!c || !from)
@ -685,7 +706,7 @@ ASType(const ParseeConfig *c, char *user, char *room, bool status)
{
HttpClientContext *ctx = NULL;
HashMap *json;
char *path, *full;
char *path;
if (!c || !user || !room)
{
return;
@ -760,7 +781,6 @@ ASSetUserConfig(const ParseeConfig *c, char *user, char *key, HashMap *map)
{
HttpClientContext *ctx = NULL;
HashMap *json;
char *path;
if (!c || !key || !map)
{

View file

@ -4,6 +4,7 @@
#include <Cytoplasm/Str.h>
#include <Matrix.h>
#include <Bot.h>
#include <AS.h>
CommandHead(CmdBanUser, cmd, argp)
@ -13,32 +14,21 @@ CommandHead(CmdBanUser, cmd, argp)
HashMap *event = args->event;
char *user = HashMapGet(cmd->arguments, "user");
char *room = HashMapGet(cmd->arguments, "room");
char *msg;
char *msgtype = GrabString(event, 2, "content", "msgtype");
char *body = GrabString(event, 2, "content", "body");
char *id = GrabString(event, 1, "room_id");
char *ev_id = GrabString(event, 1, "event_id");
char *sender = GrabString(event, 1, "sender");
char *profile = StrConcat(4,
"@", data->config->sender_localpart,
":", data->config->homeserver_host
);
BotInitialise();
if (!user || !room)
{
Free(profile);
BotDestroy();
return;
}
ASBan(data->config, room, user);
msg = StrConcat(3, "Banning '", user, "'...");
Free(ASSend(
data->config, id, profile,
"m.room.message",
MatrixCreateNotice(msg)
));
Free(msg);
Free(profile);
ReplySprintf("Banning %s from '%s'...",
user, room
);
BotDestroy();
}
CommandHead(CmdNoFlyList, cmd, argp)
{
@ -46,30 +36,19 @@ CommandHead(CmdNoFlyList, cmd, argp)
ParseeData *data = args->data;
HashMap *event = args->event;
char *user = HashMapGet(cmd->arguments, "user");
char *msg;
char *msgtype = GrabString(event, 2, "content", "msgtype");
char *body = GrabString(event, 2, "content", "body");
char *id = GrabString(event, 1, "room_id");
char *ev_id = GrabString(event, 1, "event_id");
char *sender = GrabString(event, 1, "sender");
char *profile = StrConcat(4,
"@", data->config->sender_localpart,
":", data->config->homeserver_host
);
char *reason = HashMapGet(cmd->arguments, "reason");
BotInitialise();
if (!user)
{
Free(profile);
BotDestroy();
return;
}
msg = StrConcat(3, "Banning '", user, "'...");
Free(ASSend(
data->config, id, profile,
"m.room.message",
MatrixCreateNotice(msg)
));
Free(msg);
ParseeGlobalBan(data, user);
Free(profile);
ReplySprintf("Banning %s for '%s'",
user, reason ? reason : "[no reason specified]"
);
ParseeGlobalBan(data, user, reason);
BotDestroy();
}

View file

@ -12,7 +12,7 @@ CommandHead(CmdHelp, cmd, argp)
{
ParseeCmdArg *args = argp;
ParseeData *data = args->data;
HashMap *json, *event = args->event;
HashMap *event = args->event;
BotInitialise();
ReplyBasic("Commands: ");

89
src/Commands/Plumb.c Normal file
View file

@ -0,0 +1,89 @@
#include <Routes.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Str.h>
#include <Matrix.h>
#include <Bot.h>
#include <AS.h>
#include <stdlib.h>
CommandHead(CmdPlumb, cmd, argp)
{
ParseeCmdArg *args = argp;
ParseeData *data = args->data;
HashMap *event = args->event;
char *muc = NULL, *room = NULL, *chat_id = NULL;
char *room_id = NULL;
MUCInfo info = { .exists = false };
BotInitialise();
BotRequired(muc);
BotRequired(room);
/* Check MUC viability */
Log(LOG_INFO, "BAR1");
if (ParseeManageBan(args->data, muc, NULL))
{
ReplySprintf("MUC '%s' is not allowed on this bridge.", muc);
Log(LOG_INFO, "BAR1F");
goto end;
}
Log(LOG_INFO, "BAR2");
if (!XMPPQueryMUC(args->data->jabber, muc, &info))
{
ReplySprintf("MUC '%s' does not exist.", muc);
Log(LOG_INFO, "BAR2F");
goto end;
}
Log(LOG_INFO, "BAR3");
if ((chat_id = ParseeGetFromMUCID(args->data, muc)))
{
Free(chat_id);
chat_id = NULL;
ReplySprintf("MUC '%s' is already mapped.", muc);
Log(LOG_INFO, "BAR3F");
goto end;
}
Log(LOG_INFO, "FOO");
/* Check room viability */
room_id = ASJoin(args->data->config, room, NULL);
if (!room_id)
{
ReplySprintf("Room '%s' does not exist.", room);
Log(LOG_INFO, "FOO2");
goto end;
}
Log(LOG_INFO, "FOO3");
if ((chat_id = ParseeGetFromRoomID(args->data, room_id)))
{
Free(chat_id);
chat_id = NULL;
ReplySprintf("Room '%s' is already mapped.", room);
Log(LOG_INFO, "FOO4");
goto end;
}
Log(LOG_INFO, "FOO5");
chat_id = ParseePushMUC(args->data, room_id, muc);
if (chat_id)
{
char *rev = StrConcat(2, muc, "/parsee");
XMPPJoinMUC(args->data->jabber, "parsee", rev);
Free(rev);
}
Log(LOG_INFO, "FOO6");
ReplySprintf("Plumbed '%s'", muc);
end:
Log(LOG_INFO, "End.");
BotDestroy();
Free(chat_id);
Free(room_id);
XMPPFreeMUCInfo(info);
}

View file

@ -12,8 +12,7 @@ CommandHead(CmdStats, cmd, argp)
{
ParseeCmdArg *args = argp;
ParseeData *data = args->data;
HashMap *json, *event = args->event;
char *msg;
HashMap *event = args->event;
size_t alloc = MemoryAllocated();
size_t kb = alloc >> 10;
size_t mb = kb >> 10;
@ -30,7 +29,7 @@ CommandHead(CmdStats, cmd, argp)
);
ReplySprintf("- Memory used: %d%s (reported by Cytoplasm)",
min, unit
(int) min, unit
);
ReplySprintf("- Source code and licensing information: %s",
REPOSITORY

View file

@ -16,7 +16,6 @@ CommandHead(CmdUnlinkMUC, cmd, argp)
HashMap *json, *event = args->event, *mucs;
DbRef *ref;
char *muc = NULL, *chat_id = NULL, *room = NULL;
JsonValue *val;
BotInitialise();

View file

@ -20,12 +20,10 @@ static HttpServer *server = NULL;
static pthread_t xmpp_thr;
static XMPPComponent *jabber = NULL;
extern int ParseeFindDatastart(char *data);
int
Main(void)
{
HttpServerConfig conf;
ParseeData *data = NULL;
const ParseeConfig *parsee_conf;
Stream *yaml;
Cron *cron = NULL;

View file

@ -28,7 +28,7 @@ ParseeMemberHandler(ParseeData *data, HashMap *event)
char *jid;
bool direct = GrabBoolean(event, 2, "content", "is_direct");
bool bot = !strncmp(sender + 1, local, strlen(local));
ASJoin(conf, room_id, state_key);
Free(ASJoin(conf, room_id, state_key));
jid = ParseeDecodeLocalJID(conf, state_key);
@ -70,7 +70,6 @@ ParseeBotHandler(ParseeData *data, HashMap *event)
char *msgtype = GrabString(event, 2, "content", "msgtype");
char *body = GrabString(event, 2, "content", "body");
char *id = GrabString(event, 1, "room_id");
char *ev_id = GrabString(event, 1, "event_id");
char *sender = GrabString(event, 1, "sender");
char *profile = StrConcat(4,
"@", data->config->sender_localpart,
@ -117,7 +116,7 @@ ParseeBotHandler(ParseeData *data, HashMap *event)
RouteCommand(data->handler, cmd, &arg);
}
end:
Free(profile);
CommandFree(cmd);
}
@ -128,16 +127,14 @@ ParseeMessageHandler(ParseeData *data, HashMap *event)
DbRef *ref = NULL;
HashMap *json;
char *msgtype = GrabString(event, 2, "content", "msgtype");
char *body = GrabString(event, 2, "content", "body");
char *id = GrabString(event, 1, "room_id");
char *ev_id = GrabString(event, 1, "event_id");
char *m_sender = GrabString(event, 1, "sender");
char *chat_id, *muc_id, *jid;
char *chat_id, *muc_id;
char *reply_id = MatrixGetReply(event);
char *xepd = ParseeXMPPify(event);
char *cmd_lp = data->config->sender_localpart;
char *type, *user, *xmppified_user = NULL, *to;
char *type, *user, *xmppified_user = NULL, *to = NULL;
char *unauth = NULL;
char *origin_id = NULL, *stanza = NULL;
char *sender = NULL;
@ -189,7 +186,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event)
}
else
{
char *name, *rev, *stanza;
char *name, *rev;
/* Try to find the chat ID */
muc_id = ParseeGetMUCID(data, chat_id);
if (!chat_id)

View file

@ -369,14 +369,16 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags)
}
}
break;
default:
break;
}
return xepd;
}
char *
ParseeXMPPify(HashMap *event)
{
char *cntr, *type, *format, *html;
char *xepd = NULL, *tmp;
char *type, *format, *html;
char *xepd = NULL;
XMLElement *elem;
XMPPFlags flags;
@ -756,10 +758,10 @@ end:
}
void
ParseeGlobalBan(ParseeData *data, char *user)
ParseeGlobalBan(ParseeData *data, char *user, char *reason)
{
DbRef *ref;
HashMap *j;
HashMap *j, *obj;
if (!data || !user)
{
return;
@ -773,7 +775,13 @@ ParseeGlobalBan(ParseeData *data, char *user)
j = DbJson(ref);
JsonValueFree(HashMapSet(j, user, JsonValueObject(HashMapCreate())));
obj = HashMapCreate();
if (reason)
{
HashMapSet(obj, "reason", JsonValueString(reason));
}
HashMapSet(obj, "date", JsonValueInteger(UtilTsMillis()));
JsonValueFree(HashMapSet(j, user, JsonValueObject(obj)));
DbUnlock(data->db, ref);
}

View file

@ -529,7 +529,7 @@ ParseeSendPresence(ParseeData *data)
DbRef *ref;
HashMap *j, *mucs;
JsonValue *val;
char *chatid = NULL, *muc;
char *muc;
if (!data)
{
return;

View file

@ -13,8 +13,6 @@ RouteHead(RouteUserAck, arr, argp)
ParseeHttpArg *args = argp;
HashMap *request = NULL;
HashMap *response = NULL;
Array *events;
size_t i;
char *user = ArrayGet(arr, 0);
response = ASVerifyRequest(args);
@ -44,8 +42,6 @@ RouteHead(RouteRoomAck, arr, argp)
ParseeHttpArg *args = argp;
HashMap *request = NULL;
HashMap *response = NULL;
Array *events;
size_t i;
MUCInfo info = { .exists = false };
char *room = ArrayGet(arr, 0), *muc = NULL, *id = NULL;
@ -119,6 +115,16 @@ RouteHead(RouteRoomAck, arr, argp)
/* Creates a mapping */
chatid = ParseePushMUC(args->data, id, muc);
/* Invite the Parsee listener, so that we can have some
* events right up */
{
char *rev = StrConcat(2, muc, "/parsee");
Log(LOG_NOTICE, "Sending presence to %s", rev);
XMPPJoinMUC(args->data->jabber, "parsee", rev);
Free(rev);
}
response = HashMapCreate();
end:
if (chatid)

View file

@ -14,10 +14,6 @@ static XMPPComponent *jabber = NULL;
static void
SignalHandler(int signal)
{
size_t i;
XMLElement *message, *body, *data;
char *from;
switch (signal)
{
case SIGPIPE:
@ -32,6 +28,8 @@ SignalHandler(int signal)
return;
}
/* Create a loopback stanza, forcing the thread to die */
/* TODO: Better way to break out. */
Log(LOG_INFO, "Killing thread...");
XMPPKillThread(jabber, "killer");
pthread_join(xmpp_thr, NULL);

View file

@ -39,7 +39,6 @@ struct XMLexer {
static bool XMLookahead(XMLexer *lexer, const char *str, bool skip);
/* Parses an XML "name" */
static bool XMLIsStart(XMLexer *lexer);
static char * XMLParseName(XMLexer *lexer);
static bool XMLSkipSpace(XMLexer *lexer);
static char * XMLParseAttValue(XMLexer *lexer);
@ -122,11 +121,8 @@ XMLEvent *
XMLCrank(XMLexer *lexer)
{
XMLEvent *event = NULL;
char c;
int ch;
char *attrname;
HashMap *props;
char *key, *val;
char cbuf[2] = { 0 };
char *tmp;
if (!lexer)
@ -259,6 +255,9 @@ XMLCrank(XMLexer *lexer)
XMLFreeEvent(event);
event = XMLCreateEnd(lexer, attrname);
break;
default:
/* TODO */
break;
}
/* TODO: Crank our XML parser. */
return event;
@ -608,7 +607,7 @@ static char *
XMLDecodeString(char *s)
{
char *ret = NULL, *tmp;
char c, cs[2] = { 0 };
char cs[2] = { 0 };
while (*s)
{
@ -724,10 +723,9 @@ XMLParseAttQuote(XMLexer *lexer)
while ((c = XMLGetc(lexer)))
{
//Log(LOG_INFO, "E1=%c", c);
if (c == '&')
{
char *code = NULL;
//char *code = NULL;
int c2;
int p2 = XMLInitialiseBuffer(lexer);
int j = 0;
@ -774,7 +772,6 @@ XMLParseAttDouble(XMLexer *lexer)
//Log(LOG_INFO, "E2=%c", c);
if (c == '&')
{
char *code = NULL;
int c2;
int p2 = XMLInitialiseBuffer(lexer);
int j = 0;
@ -811,7 +808,7 @@ XMLParseAttDouble(XMLexer *lexer)
static char *
XMLParseAttValue(XMLexer *lexer)
{
ssize_t point = XMLInitialiseBuffer(lexer);
XMLInitialiseBuffer(lexer);
if (XMLookahead(lexer, "'", true))
{

View file

@ -78,6 +78,8 @@ XMPPInitialiseCompStream(char *host, int port)
comp->stream = stream;
pthread_mutex_init(&comp->write_lock, NULL);
(void) error;
return comp;
}

View file

@ -15,6 +15,7 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out)
char *uuid, *from;
if (!jabber || !muc)
{
Log(LOG_WARNING, ":(");
return false;
}
@ -32,25 +33,19 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out)
XMLAddChild(iq_query, query);
Free(from);
Free(uuid);
/* Pause the XMPP thread */
XMPPKillThread(jabber, "suspend");
UtilSleepMillis(500);
{
XMLElement *identity;
/* -- WE ARE ON OUR OWN HERE WITH STANZAS -- */
XMLEncode(jabber->stream, iq_query);
StreamFlush(jabber->stream);
XMLFreeElement(iq_query);
/* Except an IQ reply */
iq_query = XMLDecode(jabber->stream, false);
/* TODO: I've spotted presence requests spawning there. */
iq_query = ParseeAwaitStanza(uuid);
Free(uuid);
if (!iq_query || !StrEquals(iq_query->name, "iq"))
{
XMLFreeElement(iq_query);
ParseeWakeupThread();
pthread_mutex_unlock(&jabber->write_lock);
return false;
}
@ -62,7 +57,6 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out)
"conference"))
{
XMLFreeElement(iq_query);
ParseeWakeupThread();
pthread_mutex_unlock(&jabber->write_lock);
return false;
}
@ -79,9 +73,7 @@ XMPPQueryMUC(XMPPComponent *jabber, char *muc, MUCInfo *out)
XMLFreeElement(iq_query);
}
}
/* Wake it up once we're done */
pthread_mutex_unlock(&jabber->write_lock);
ParseeWakeupThread();
return true;
}

View file

@ -198,7 +198,7 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc)
void
XMPPKillThread(XMPPComponent *jabber, char *killer)
{
XMLElement *message, *body, *data;
XMLElement *message, *body;
char *from;
if (!jabber || !killer)

View file

@ -49,8 +49,8 @@ typedef struct XMPPIdentity {
static int
ICollate(unsigned char *cata, unsigned char *catb)
{
size_t al = cata ? strlen(cata) : 0;
size_t bl = catb ? strlen(catb) : 0;
size_t al = cata ? strlen((char *) cata) : 0;
size_t bl = catb ? strlen((char *) catb) : 0;
if (!al && !bl)
{
@ -89,8 +89,8 @@ IdentitySort(void *idap, void *idbp)
{
XMPPIdentity *ida = idap;
XMPPIdentity *idb = idbp;
unsigned char *cata = ida->category;
unsigned char *catb = idb->category;
unsigned char *cata = (unsigned char *) ida->category;
unsigned char *catb = (unsigned char *) idb->category;
return ICollate(cata, catb);
}
@ -144,7 +144,7 @@ XMPPGenerateVer(void)
Sha = Sha1(S);
Free(S);
S = Base64Encode(Sha, 20);
S = Base64Encode((const char *) Sha, 20);
Free(Sha);
ArrayFree(features);
@ -159,17 +159,6 @@ XMPPGenerateVer(void)
return S;
}
static pthread_mutex_t cond_var_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
void
ParseeWakeupThread(void)
{
pthread_mutex_lock(&cond_var_lock);
pthread_cond_signal(&cond_var);
pthread_mutex_unlock(&cond_var_lock);
}
static char *
ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza)
{
@ -222,7 +211,6 @@ ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza)
XMLElement *reactions = XMLookForTKV(stanza,
"reactions", "xmlns", "urn:xmpp:reactions:0"
);
char *from = (HashMapGet(stanza->attrs, "from"));
char *reacted_id = reactions ? HashMapGet(reactions->attrs, "id") : NULL;
return ParseeGetEventFromID(data, stanza, reacted_id);
@ -237,7 +225,6 @@ ParseePushAllStanza(ParseeData *args, XMLElement *stanza, char *event)
char *id_str = HashMapGet(stanza->attrs, "id");
char *s_id_str = XMPPGetStanzaID(stanza);
char *o_id_str = XMPPGetOriginID(stanza);
if (!chat_id)
{
@ -389,6 +376,8 @@ ManageProfileItem(ParseeData *args, XMLElement *item, XMLElement *stanza, XMPPTh
pthread_mutex_unlock(&jabber->write_lock);
XMLFreeElement(request);
(void) url; /* TODO */
}
end:
@ -406,7 +395,7 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
XMLElement *event = NULL;
char *to, *room, *from, *from_matrix, *decode_from;
char *chat_id = NULL, *mroom_id = NULL;
char *mroom_id = NULL;
size_t i;
to = NULL;
@ -506,9 +495,6 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
{
char *res = ParseeGetResource(from);
char *encoded = ParseeEncodeJID(args->config, decode_from, false);
char *s_id_str = XMPPGetStanzaID(stanza);
char *o_id_str = XMPPGetOriginID(stanza);
char *id_str = HashMapGet(stanza->attrs, "id");
char *event_id = NULL;
char *replaced = XMPPGetReplacedID(stanza);
char *reply_to = XMPPGetReply(stanza);
@ -548,7 +534,7 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
ASSetName(args->config, encoded, res);
}
ASInvite(args->config, mroom_id, encoded);
ASJoin(args->config, mroom_id, encoded);
Free(ASJoin(args->config, mroom_id, encoded));
/* Check if it is a media link */
oob = XMLookForTKV(stanza, "x", "xmlns", "jabber:x:oob");
@ -574,7 +560,6 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
}
else if (reactions)
{
char *reacted_id = HashMapGet(reactions->attrs, "id");
Array *react_child = reactions->children;
size_t reacts = ArraySize(react_child);
event_id = ParseeGetReactedEvent(args, stanza);
@ -642,8 +627,6 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
XMLElement *parsee = XMLookForUnique(stanza, "x-parsee");
XMLElement *event = XMLookForUnique(parsee, "event-id");
XMLElement *e_d = ArrayGet(event ? event->children : NULL, 0);
char *s_id_str = XMPPGetStanzaID(stanza);
char *id_str = HashMapGet(stanza->attrs, "id");
ParseePushAllStanza(args, stanza, e_d->data);
}
@ -752,7 +735,6 @@ TrimBase64(char *b64)
static void
IQResult(ParseeData *args, XMLElement *stanza)
{
XMPPComponent *jabber = args->jabber;
XMLElement *vcard = XMLookForTKV(stanza, "vCard", "xmlns", "vcard-temp");
XMLElement *event = XMLookForTKV(stanza, "pubsub",
@ -776,7 +758,7 @@ IQResult(ParseeData *args, XMLElement *stanza)
char *id = HashMapGet(item->attrs, "id");
char *from = HashMapGet(stanza->attrs, "from");
char *base64;
unsigned char *bdata;
char *bdata;
size_t length, b64len;
Stream *datastream;
char *mxc, *from_matrix, *jid;
@ -804,8 +786,8 @@ IQResult(ParseeData *args, XMLElement *stanza)
b64len = base64 ? strlen(base64) : 0;
length = Base64DecodedSize(base64, b64len);
/* TODO: Bound checks! */
bdata = Base64Decode(base64, b64len);
/* TODO: Bound checks for a size limit. */
bdata = (char *) Base64Decode(base64, b64len);
datastream = StrStreamReaderN(bdata, length);
mxc = ASUpload(args->config, datastream, length);
@ -837,13 +819,16 @@ IQResult(ParseeData *args, XMLElement *stanza)
if (nickname)
{
XMLElement *data = ArrayGet(nickname->children, 0);
/* TODO: Use the nickname for something.
* And the rest of the vCard, somewhere. */
(void) data;
}
if (photo)
{
XMLElement *binval = XMLookForUnique(photo, "BINVAL");
XMLElement *data = ArrayGet(binval->children, 0);
char *base64;
unsigned char *bdata;
char *bdata;
size_t length, b64len;
Stream *datastream;
char *mxc, *from_matrix, *jid;
@ -885,7 +870,7 @@ IQGet(ParseeData *args, XMLElement *stanza)
else if (XMLookForTKV(stanza, "query", "xmlns", "jabber:iq:version"))
{
XMLElement *iq_reply, *query;
XMLElement *name, *version, *val;
XMLElement *name, *version;
char *from = HashMapGet(stanza->attrs, "from");
char *to = HashMapGet(stanza->attrs, "to");
char *id = HashMapGet(stanza->attrs, "id");
@ -980,24 +965,22 @@ PresenceStanza(ParseeData *args, XMLElement *stanza)
if ((user_info = XMLookForTKV(stanza, "x", "xmlns", MUC_USER_NS)))
{
XMLElement *item = XMLookForUnique(user_info, "item");
XMPPComponent *jabber = args->jabber;
char *jid = item ? HashMapGet(item->attrs, "jid") : NULL;
char *from, *best = jid ? jid : oid;
char *from;
char *type = HashMapGet(stanza->attrs, "type");
if (StrEquals(type, "unavailable"))
{
/* TODO: Treat as a ban if the role is outcast */
/* TODO: Treat as a ban if the role is outcast.
* Modify the code to be more accurate later. */
char *room = ParseeGetBridgedRoom(args, stanza);
char *decode_from = ParseeLookupJID(oid);
char *from_matrix = ParseeDecodeMXID(decode_from);
char *affiliation = HashMapGet(item->attrs, "affiliation");
if (!from_matrix || *from_matrix != '@')
{
Free(from_matrix);
from_matrix = ParseeEncodeJID(args->config, oid, true);
}
Log(LOG_INFO, "Acting on %s", from_matrix);
Log(LOG_INFO, "OID=%s DF=%s", oid, decode_from);
if (StrEquals(affiliation, "outcast"))
{
@ -1097,11 +1080,11 @@ XMPPDispatcher(void *argp)
{
XMPPThread *thread = argp;
ParseeData *args = thread->info->args;
XMPPComponent *jabber = thread->info->jabber;
while (thread->info->running)
{
XMLElement *stanza = RetrieveStanza(thread);
if (!stanza)
{
UtilSleepMillis(1);
@ -1116,7 +1099,6 @@ XMPPDispatcher(void *argp)
}
else if (StrEquals(stanza->name, "message"))
{
size_t i;
if (!MessageStanza(args, stanza, thread))
{
continue;
@ -1135,8 +1117,19 @@ XMPPDispatcher(void *argp)
}
XMLFreeElement(stanza);
}
return NULL;
}
typedef struct XMPPAwait {
pthread_mutex_t cond_lock;
pthread_cond_t condition;
XMLElement *stanza;
} XMPPAwait;
static pthread_mutex_t await_lock = PTHREAD_MUTEX_INITIALIZER;
static HashMap *await_table = NULL;
void *
ParseeXMPPThread(void *argp)
{
@ -1144,9 +1137,10 @@ ParseeXMPPThread(void *argp)
XMPPComponent *jabber = args->jabber;
XMLElement *stanza = NULL;
XMPPThreadInfo info;
pthread_mutex_t stanzas_lock = PTHREAD_MUTEX_INITIALIZER;
size_t i, j = 0;
size_t i;
/* Initialise the await table */
await_table = HashMapCreate();
/* Initialise the FIFO */
info.stanzas = ArrayCreate();
@ -1174,9 +1168,7 @@ ParseeXMPPThread(void *argp)
while (true)
{
char *to, *room, *from, *from_matrix;
char *chat_id, *mroom_id;
ssize_t cntr;
char *from, *id;
stanza = XMLDecode(jabber->stream, false);
if (!stanza)
@ -1184,25 +1176,37 @@ ParseeXMPPThread(void *argp)
continue;
}
id = HashMapGet(stanza->attrs, "id");
if (id)
{
XMPPAwait *await;
/* Lock out the table to see if we're awaiting. */
pthread_mutex_lock(&await_lock);
if ((await = HashMapGet(await_table, id)))
{
await->stanza = stanza;
pthread_mutex_lock(&await->cond_lock);
pthread_cond_signal(&await->condition);
pthread_mutex_unlock(&await->cond_lock);
HashMapDelete(await_table, id);
pthread_mutex_unlock(&await_lock);
continue;
}
pthread_mutex_unlock(&await_lock);
}
if (StrEquals(stanza->name, "message") && XMPPIsKiller(stanza))
{
const char *killer = "killer";
const char *suspend="suspend";
from = HashMapGet(stanza->attrs, "from");
if (!strncmp(from, killer, strlen(killer)))
{
XMLFreeElement(stanza);
break;
}
else if (!strncmp(from, suspend, strlen(suspend)))
{
/* TODO */
XMLFreeElement(stanza);
pthread_mutex_lock(&cond_var_lock);
pthread_cond_wait(&cond_var, &cond_var_lock);
pthread_mutex_unlock(&cond_var_lock);
continue;
}
}
PushStanza(&info, stanza);
@ -1222,6 +1226,48 @@ ParseeXMPPThread(void *argp)
}
ArrayFree(info.stanzas);
HashMapFree(await_table);
pthread_mutex_destroy(&info.lock);
return NULL;
}
XMLElement *
ParseeAwaitStanza(char *identifier)
{
XMPPAwait awa, *await;
XMLElement *stanza;
if (!identifier)
{
return NULL;
}
/* 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! */
await = &awa;
pthread_mutex_lock(&await_lock);
pthread_cond_init(&await->condition, NULL);
pthread_mutex_init(&await->cond_lock, NULL);
await->stanza = NULL;
HashMapSet(await_table, identifier, await);
pthread_mutex_unlock(&await_lock);
pthread_mutex_lock(&await->cond_lock);
while (!await->stanza)
{
pthread_cond_wait(&await->condition, &await->cond_lock);
}
stanza = await->stanza;
pthread_mutex_lock(&await_lock);
pthread_mutex_unlock(&await_lock);
pthread_mutex_unlock(&await->cond_lock);
pthread_cond_destroy(&await->condition);
pthread_mutex_destroy(&await->cond_lock);
return stanza;
}

View file

@ -24,7 +24,7 @@ extern void ASPing(const ParseeConfig *);
/* Joins a room from an ID and a given user we want to masquerade
* as. */
extern void ASJoin(const ParseeConfig *, char *, char *);
extern char * ASJoin(const ParseeConfig *, char *, char *);
/* Bans from a room a specific user */
extern void ASBan(const ParseeConfig *, char *, char *);

View file

@ -15,6 +15,12 @@
); \
char *id = GrabString(event, 1, "room_id")
#define BotRequired(prop) prop = HashMapGet(cmd->arguments, #prop); \
if (!prop) \
{ \
ReplyBasic("Field `" #prop "` REQUIRED."); \
}
#define BotDestroy() Free(profile)
#define ReplyBasic(rep) do \

View file

@ -119,8 +119,8 @@ extern void ParseeRequest(HttpServerContext *, void *);
/* A pthread callback used for listening to a component */
extern void * ParseeXMPPThread(void *data);
/* Wakes up the XMPP thread from a "suspend" killer stanza */
extern void ParseeWakeupThread(void);
/* Wait for a specific stanza with an ID */
extern XMLElement * ParseeAwaitStanza(char *identifier);
/* Finds the room a DM is associated to, from a Matrix user and a Jabber
* ID. */
@ -204,7 +204,7 @@ extern void ParseeDestroyJIDTable(void);
/* Globally bans a Matrix user from ever interacting with Parsee, and bans
* them from bridged rooms where the bot has administrator. */
extern void ParseeGlobalBan(ParseeData *, char *user);
extern void ParseeGlobalBan(ParseeData *, char *user, char *reason);
/* Verifies if a user was globally banned. If so, then apply actions to the
* room ID */

View file

@ -40,6 +40,12 @@ typedef struct ParseeCmdArg {
"Sets the power level to send a specific event " \
"in a Parsee room" \
) \
X_COMMAND( \
"plumb-muc", CmdPlumb, \
"Plumbs an existing Matrix room to a MUC." \
"You'll need to give the Parsee bot enough " \
"privileges, however. " \
) \
X_COMMAND( \
"help", CmdHelp, \
"Shows the command list" \