mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-13 21:05:10 +00:00
[MOD/FIX] Separate XMPP thread, fix EINVAL issue
threading is good actually. please hmu if you ever trigger the achievement.
This commit is contained in:
parent
299f473a81
commit
143bdf0a5a
21 changed files with 2314 additions and 1764 deletions
375
src/XMPPThread/Stanzas/Message.c
Normal file
375
src/XMPPThread/Stanzas/Message.c
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
#include "XMPPThread/internal.h"
|
||||
|
||||
#include <Cytoplasm/Memory.h>
|
||||
#include <Cytoplasm/Str.h>
|
||||
|
||||
#include <Matrix.h>
|
||||
#include <AS.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
bool
|
||||
MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
||||
{
|
||||
XMPPComponent *jabber = args->jabber;
|
||||
|
||||
XMLElement *reactions = NULL;
|
||||
XMLElement *body = NULL;
|
||||
XMLElement *data = NULL;
|
||||
XMLElement *event = NULL;
|
||||
|
||||
char *to, *room, *from, *from_matrix, *decode_from;
|
||||
char *mroom_id = NULL;
|
||||
char *replaced = XMPPGetReplacedID(stanza);
|
||||
char *retracted = XMPPGetRetractedID(stanza);
|
||||
char *reply_to = XMPPGetReply(stanza);
|
||||
char *moderated = XMPPGetModeration(stanza);
|
||||
size_t i;
|
||||
|
||||
to = NULL;
|
||||
from = NULL;
|
||||
decode_from = NULL;
|
||||
from_matrix = NULL;
|
||||
|
||||
from = HashMapGet(stanza->attrs, "from");
|
||||
if (ParseeManageBan(args, from, NULL))
|
||||
{
|
||||
XMLFreeElement(stanza);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (moderated)
|
||||
{
|
||||
/* TODO: Parsee MUST check if it is a valid MUC */
|
||||
char *resource = ParseeGetResource(from);
|
||||
char *chat_id = ParseeGetFromMUCID(args, from);
|
||||
char *event_id = NULL;
|
||||
char *encoded = ParseeMXID(args);
|
||||
mroom_id = ParseeGetBridgedRoom(args, stanza);
|
||||
if (!resource && chat_id)
|
||||
{
|
||||
event_id = ParseeGetEventFromID(args, stanza, moderated);
|
||||
ASRedact(args->config, mroom_id, NULL, event_id);
|
||||
ParseePushAllStanza(args, stanza, event_id);
|
||||
pthread_mutex_unlock(&thr->info->chk_lock);
|
||||
|
||||
Free(event_id);
|
||||
}
|
||||
Free(mroom_id);
|
||||
Free(resource);
|
||||
Free(encoded);
|
||||
Free(chat_id);
|
||||
}
|
||||
body = XMLookForUnique(stanza, "body");
|
||||
|
||||
event = XMLookForTKV(stanza, "event",
|
||||
"xmlns", "http://jabber.org/protocol/pubsub#event"
|
||||
);
|
||||
if (event)
|
||||
{
|
||||
size_t i;
|
||||
XMLElement *items =
|
||||
XMLookForTKV(event, "items", "node", "urn:xmpp:avatar:metadata");
|
||||
if (items)
|
||||
{
|
||||
for (i = 0; i < ArraySize(items->children); i++)
|
||||
{
|
||||
ManageProfileItem(
|
||||
args, ArrayGet(items->children, i),
|
||||
stanza, thr
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define CHAT_STATES "http://jabber.org/protocol/chatstates"
|
||||
if (XMLookForTKV(stanza, "composing", "xmlns", CHAT_STATES))
|
||||
{
|
||||
decode_from = ParseeLookupJID(from);
|
||||
from_matrix = ParseeEncodeJID(args->config, decode_from, true);
|
||||
mroom_id = ParseeGetBridgedRoom(args, stanza);
|
||||
|
||||
ASType(args->config, from_matrix, mroom_id, true);
|
||||
|
||||
Free(decode_from);
|
||||
Free(from_matrix);
|
||||
Free(mroom_id);
|
||||
mroom_id = NULL;
|
||||
decode_from = NULL;
|
||||
from_matrix = NULL;
|
||||
}
|
||||
if (XMLookForTKV(stanza, "active", "xmlns", CHAT_STATES))
|
||||
{
|
||||
char *latest = NULL;
|
||||
decode_from = ParseeLookupJID(from);
|
||||
from_matrix = ParseeEncodeJID(args->config, decode_from, true);
|
||||
mroom_id = ParseeGetBridgedRoom(args, stanza);
|
||||
|
||||
latest = ParseeLookupHead(mroom_id);
|
||||
|
||||
ASType(args->config, from_matrix, mroom_id, false);
|
||||
ASPresence(args->config, from_matrix, mroom_id, latest);
|
||||
|
||||
Free(decode_from);
|
||||
Free(from_matrix);
|
||||
Free(latest);
|
||||
Free(mroom_id);
|
||||
mroom_id = NULL;
|
||||
decode_from = NULL;
|
||||
from_matrix = NULL;
|
||||
}
|
||||
if (XMLookForTKV(stanza, "paused", "xmlns", CHAT_STATES) ||
|
||||
XMLookForTKV(stanza, "received", "xmlns", "urn:xmpp:receipts") ||
|
||||
XMLookForTKV(stanza, "displayed", "xmlns", "urn:xmpp:chat-markers:0"))
|
||||
{
|
||||
/* TODO: Use stanza ID if possible */
|
||||
char *latest = NULL;
|
||||
decode_from = ParseeLookupJID(from);
|
||||
from_matrix = ParseeEncodeJID(args->config, decode_from, true);
|
||||
mroom_id = ParseeGetBridgedRoom(args, stanza);
|
||||
|
||||
latest = ParseeLookupHead(mroom_id);
|
||||
|
||||
ASPresence(args->config, from_matrix, mroom_id, latest);
|
||||
|
||||
Free(decode_from);
|
||||
Free(from_matrix);
|
||||
Free(latest);
|
||||
Free(mroom_id);
|
||||
mroom_id = NULL;
|
||||
decode_from = NULL;
|
||||
from_matrix = NULL;
|
||||
|
||||
}
|
||||
#undef CHAT_STATES
|
||||
if (!body)
|
||||
{
|
||||
XMLFreeElement(stanza);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO: On semi-anonymous MUCs, it might be preferable to use a
|
||||
* form of the occupant ID as the base, as it is more unique, and
|
||||
* less prone to trigger the character limit on Matrix.
|
||||
*
|
||||
* See: https://xmpp.org/extensions/xep-0421.html */
|
||||
to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to"));
|
||||
decode_from = ParseeLookupJID(from);
|
||||
from_matrix = ParseeEncodeJID(args->config, decode_from, true);
|
||||
room = ParseeFindDMRoom(args, to, from);
|
||||
data = ArrayGet(body->children, 0);
|
||||
|
||||
/* TODO: CLEAN THAT UP */
|
||||
mroom_id = ParseeGetBridgedRoom(args, stanza);
|
||||
if (!mroom_id && !room && !XMPPIsParseeStanza(stanza) &&
|
||||
to && *to == '@')
|
||||
{
|
||||
DbRef *room_ref;
|
||||
HashMap *room_json;
|
||||
char *from = HashMapGet(stanza->attrs, "from");
|
||||
|
||||
ASRegisterUser(args->config, from_matrix);
|
||||
room = ASCreateDM(args->config, from_matrix, to);
|
||||
mroom_id = StrDuplicate(room);
|
||||
if (room)
|
||||
{
|
||||
room_ref = DbCreate(args->db, 3, "rooms", room, "data");
|
||||
room_json = DbJson(room_ref);
|
||||
HashMapSet(room_json, "is_direct", JsonValueBoolean(true));
|
||||
HashMapSet(room_json, "xmpp_user", JsonValueString(from));
|
||||
DbUnlock(args->db, room_ref);
|
||||
ParseePushDMRoom(args, to, from, room);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: THIS IS A HACK. THIS CODE IGNORES ALL MUC MESSAGES EVER
|
||||
* SENT TO NON-PARSEE PUPPETS, AS A "FIX" TO THE MULTITHREADED
|
||||
* ISSUE.
|
||||
*
|
||||
* I HATE THIS. I NEED TO FIND A BETTER WAY. */
|
||||
if (!room)
|
||||
{
|
||||
if (strncmp(HashMapGet(stanza->attrs, "to"), "parsee@", 7))
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (mroom_id && !XMPPIsParseeStanza(stanza))
|
||||
{
|
||||
char *res = ParseeGetResource(from);
|
||||
char *encoded = ParseeEncodeJID(args->config, decode_from, false);
|
||||
char *event_id = NULL;
|
||||
bool chat = false;
|
||||
|
||||
if (StrEquals(HashMapGet(stanza->attrs, "type"), "chat"))
|
||||
{
|
||||
Free(encoded);
|
||||
encoded = StrDuplicate(from_matrix);
|
||||
chat = true;
|
||||
}
|
||||
|
||||
{
|
||||
char *parsee = ParseeJID(args);
|
||||
|
||||
/* Subscribe to the sender's metadata node. */
|
||||
XMLElement *ps = CreatePubsubRequest(
|
||||
parsee, decode_from, "urn:xmpp:avatar:metadata"
|
||||
);
|
||||
pthread_mutex_lock(&jabber->write_lock);
|
||||
XMLEncode(jabber->stream, ps);
|
||||
StreamFlush(jabber->stream);
|
||||
pthread_mutex_unlock(&jabber->write_lock);
|
||||
|
||||
XMLFreeElement(ps);
|
||||
Free(parsee);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&thr->info->chk_lock);
|
||||
if (ParseeVerifyAllStanza(args, stanza) && !replaced)
|
||||
{
|
||||
XMLElement *oob, *oob_data;
|
||||
|
||||
pthread_mutex_unlock(&thr->info->chk_lock);
|
||||
ASRegisterUser(args->config, encoded);
|
||||
if (!chat)
|
||||
{
|
||||
ASSetName(args->config, encoded, res);
|
||||
}
|
||||
ASInvite(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");
|
||||
reactions = XMLookForTKV(stanza,
|
||||
"reactions", "xmlns", "urn:xmpp:reactions:0"
|
||||
);
|
||||
if (oob)
|
||||
{
|
||||
char *mxc, *mime = NULL;
|
||||
HashMap *content = NULL;
|
||||
oob_data = XMLookForUnique(oob, "url");
|
||||
oob_data =
|
||||
oob_data ? ArrayGet(oob_data->children, 0) : NULL;
|
||||
|
||||
if (oob_data)
|
||||
{
|
||||
mxc = ASReupload(args->config, oob_data->data, &mime);
|
||||
content = MatrixCreateMedia(mxc, data->data, mime);
|
||||
|
||||
/* Yeah, no, I'm not modifying the media creation code. */
|
||||
HashMapSet(content,
|
||||
"at.kappach.at.parsee.external",
|
||||
JsonValueString(oob_data->data)
|
||||
);
|
||||
ShoveStanza(content, stanza);
|
||||
|
||||
event_id = ASSend(
|
||||
args->config, mroom_id, encoded,
|
||||
"m.room.message", content
|
||||
);
|
||||
Free(mime);
|
||||
Free(mxc);
|
||||
}
|
||||
}
|
||||
else if (reactions)
|
||||
{
|
||||
Array *react_child = reactions->children;
|
||||
size_t reacts = ArraySize(react_child);
|
||||
event_id = ParseeGetReactedEvent(args, stanza);
|
||||
for (i = 0; i < reacts; i++)
|
||||
{
|
||||
XMLElement *reaction, *react_data;
|
||||
reaction = ArrayGet(react_child, i);
|
||||
react_data = ArrayGet(reaction->children, 0);
|
||||
|
||||
/* TODO: We should manage removed reactions. */
|
||||
Free(ASSend(
|
||||
args->config, mroom_id, encoded,
|
||||
"m.reaction",
|
||||
ShoveStanza(
|
||||
MatrixCreateReact(event_id, react_data->data),
|
||||
stanza
|
||||
)
|
||||
));
|
||||
}
|
||||
Free(event_id);
|
||||
event_id = NULL;
|
||||
}
|
||||
else if (retracted)
|
||||
{
|
||||
event_id = ParseeGetEventFromID(args, stanza, retracted);
|
||||
ASRedact(args->config, mroom_id, encoded, event_id);
|
||||
ParseePushAllStanza(args, stanza, event_id);
|
||||
pthread_mutex_unlock(&thr->info->chk_lock);
|
||||
|
||||
Free(event_id);
|
||||
event_id = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO: Use HTML-formatted bodies, and respect the fallback
|
||||
* trims the stanza provides us if possible. Element does not
|
||||
* like raw bodies on replies too. Go figure. */
|
||||
size_t off =
|
||||
reply_to ? ParseeFindDatastart(data->data) : 0;
|
||||
HashMap *ev = MatrixCreateMessage(data->data + off);
|
||||
if (reply_to)
|
||||
{
|
||||
char *reply_id = ParseeGetEventFromID(args, stanza, reply_to);
|
||||
MatrixSetReply(ev, reply_id);
|
||||
Free(reply_id);
|
||||
}
|
||||
ShoveStanza(ev, stanza);
|
||||
event_id = ASSend(
|
||||
args->config, mroom_id, encoded,
|
||||
"m.room.message", ev
|
||||
);
|
||||
}
|
||||
pthread_mutex_lock(&thr->info->chk_lock);
|
||||
ParseePushAllStanza(args, stanza, event_id);
|
||||
Free(event_id);
|
||||
pthread_mutex_unlock(&thr->info->chk_lock);
|
||||
}
|
||||
else if (replaced)
|
||||
{
|
||||
event_id = ParseeGetEventFromID(args, stanza, replaced);
|
||||
Free(ASSend(
|
||||
args->config, mroom_id, encoded,
|
||||
"m.room.message",
|
||||
ShoveStanza(MatrixCreateReplace(event_id, data->data), stanza)
|
||||
));
|
||||
ParseePushAllStanza(args, stanza, event_id);
|
||||
pthread_mutex_unlock(&thr->info->chk_lock);
|
||||
|
||||
Free(event_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_unlock(&thr->info->chk_lock);
|
||||
}
|
||||
Free(res);
|
||||
Free(encoded);
|
||||
}
|
||||
else
|
||||
{
|
||||
XMLElement *parsee = XMLookForUnique(stanza, "x-parsee");
|
||||
XMLElement *event = XMLookForUnique(parsee, "event-id");
|
||||
XMLElement *e_d = ArrayGet(event ? event->children : NULL, 0);
|
||||
|
||||
if (e_d)
|
||||
{
|
||||
ParseePushAllStanza(args, stanza, e_d->data);
|
||||
}
|
||||
}
|
||||
end:
|
||||
Free(mroom_id);
|
||||
mroom_id = NULL;
|
||||
Free(from_matrix);
|
||||
Free(decode_from);
|
||||
Free(room);
|
||||
Free(to);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue