mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-13 21:25:11 +00:00
251 lines
5.7 KiB
C
251 lines
5.7 KiB
C
#include "XMPPThread/internal.h"
|
|
|
|
#include <Cytoplasm/Memory.h>
|
|
#include <Cytoplasm/Str.h>
|
|
#include <Cytoplasm/Log.h>
|
|
#include <Cytoplasm/Sha.h>
|
|
|
|
#include <Parsee.h>
|
|
|
|
#include <string.h>
|
|
|
|
char *
|
|
ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza)
|
|
{
|
|
char *to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to"));
|
|
char *from = HashMapGet(stanza->attrs, "from");
|
|
char *chat_id = ParseeGetFromMUCID(data, from);
|
|
char *mroom_id = ParseeGetRoomID(data, chat_id);
|
|
char *ret;
|
|
|
|
Free(chat_id);
|
|
if (mroom_id)
|
|
{
|
|
Free(to);
|
|
return mroom_id;
|
|
}
|
|
|
|
/* Not a MUC, find the DMd room. */
|
|
ret = ParseeFindDMRoom(data, to, from);
|
|
Free(to);
|
|
return ret;
|
|
}
|
|
|
|
|
|
char *
|
|
ParseeGetEventFromID(ParseeData *data, XMLElement *stanza, char *id)
|
|
{
|
|
char *from = (HashMapGet(stanza->attrs, "from"));
|
|
char *chat_id = ParseeGetFromMUCID(data, from);
|
|
char *ret = ParseeEventFromSID(data, chat_id, id);
|
|
char *mroom_id = ParseeGetBridgedRoom(data, stanza);
|
|
|
|
if (!ret)
|
|
{
|
|
Free(ret);
|
|
ret = ParseeEventFromID(data, chat_id, id);
|
|
}
|
|
|
|
Free(chat_id);
|
|
if (ret)
|
|
{
|
|
Free(mroom_id);
|
|
return ret;
|
|
}
|
|
ret = ParseeDMEventFromID(data, mroom_id, id);
|
|
Free(mroom_id);
|
|
|
|
return ret;
|
|
}
|
|
char *
|
|
ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza)
|
|
{
|
|
XMLElement *reactions = XMLookForTKV(stanza,
|
|
"reactions", "xmlns", "urn:xmpp:reactions:0"
|
|
);
|
|
char *reacted_id = reactions ? HashMapGet(reactions->attrs, "id") : NULL;
|
|
|
|
return ParseeGetEventFromID(data, stanza, reacted_id);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
ParseePushAllStanza(ParseeData *args, XMLElement *stanza, char *event)
|
|
{
|
|
char *xmpp_from = HashMapGet(stanza->attrs, "from");
|
|
char *mroom_id = ParseeGetBridgedRoom(args, stanza);
|
|
char *chat_id = ParseeGetFromMUCID(args, xmpp_from);
|
|
|
|
char *id_str = HashMapGet(stanza->attrs, "id");
|
|
char *s_id_str = XMPPGetStanzaID(stanza);
|
|
|
|
if (!chat_id)
|
|
{
|
|
ParseePushDMStanza(
|
|
args, mroom_id, s_id_str,
|
|
id_str, event, xmpp_from
|
|
);
|
|
}
|
|
ParseePushStanza(args, chat_id, s_id_str, id_str, event, xmpp_from);
|
|
Free(mroom_id);
|
|
Free(chat_id);
|
|
}
|
|
|
|
bool
|
|
ParseeVerifyAllStanza(ParseeData *args, XMLElement *stanza)
|
|
{
|
|
char *to, *room;
|
|
char *from = HashMapGet(stanza->attrs, "from");
|
|
char *id = HashMapGet(stanza->attrs, "id");
|
|
char *chat_id = ParseeGetFromMUCID(args, from);
|
|
bool ret;
|
|
|
|
if (chat_id)
|
|
{
|
|
char *s_id_str = XMPPGetStanzaID(stanza);
|
|
ret = ParseeVerifyStanza(args, chat_id, s_id_str);
|
|
|
|
Free(chat_id);
|
|
return ret;
|
|
}
|
|
to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to"));
|
|
room = ParseeFindDMRoom(args, to, from);
|
|
ret = ParseeVerifyDMStanza(args, chat_id, id);
|
|
|
|
Free(room);
|
|
Free(to);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* TODO: Cache this information. */
|
|
bool
|
|
ServerHasXEP421(ParseeData *data, char *from)
|
|
{
|
|
char *server = NULL, *parsee;
|
|
XMLElement *disco;
|
|
bool ret;
|
|
if (!data || !from)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
server = strchr(from, '@');
|
|
if (!server)
|
|
{
|
|
server = from;
|
|
}
|
|
else
|
|
{
|
|
server++;
|
|
}
|
|
server = StrDuplicate(server);
|
|
|
|
if (strchr(server, '/'))
|
|
{
|
|
*(strchr(server, '/')) = '\0';
|
|
}
|
|
|
|
parsee = ParseeJID(data);
|
|
disco = XMPPSendDisco(data->jabber, parsee, server);
|
|
|
|
ret = XMPPDiscoAdvertises(disco, "urn:xmpp:occupant-id:0");
|
|
|
|
XMLFreeElement(disco);
|
|
Free(parsee);
|
|
Free(server);
|
|
return ret;
|
|
}
|
|
|
|
/* Scrambles an Occupant ID so that Matrix can use it for MXIDs.
|
|
* Occupant IDs are to be treated as opaque, therefore, we hash them
|
|
* into a SHA-256 value
|
|
* > "The recipient MUST consider the occupant identifier to be an opaque
|
|
* > string.". */
|
|
static char *
|
|
ScrambleOID(ParseeData *data, char *opaque_oid)
|
|
{
|
|
unsigned char *raw;
|
|
char *sha, *mxid;
|
|
const ParseeConfig *c = data->config;
|
|
if (!opaque_oid)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* Turns this into a 128-byte long, Matrix-safe value. */
|
|
raw = Sha256(opaque_oid);
|
|
sha = ShaToHex(raw);
|
|
Free(raw);
|
|
|
|
/* TODO: Either mark this specially, or drop Parsee JID flags
|
|
* altogether before any 1.0.0 */
|
|
mxid = StrConcat(
|
|
6,
|
|
"@", c->namespace_base, "_l_", sha, ":",
|
|
c->server_base
|
|
);
|
|
Free(sha);
|
|
return mxid;
|
|
}
|
|
|
|
/* TODO: Shove that function everywhere one can see fit. */
|
|
char *
|
|
ParseeGetBridgedUserI(ParseeData *data, XMLElement *stanza, char *force)
|
|
{
|
|
char *user, *xmpp_from, *type;
|
|
char *decode_from, *occ_id = NULL, *looked = NULL;
|
|
bool is_chat, has_anon = false, is_anon = false;
|
|
|
|
if (!data || !stanza)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
xmpp_from = force ? force : HashMapGet(stanza->attrs, "from");
|
|
type = HashMapGet(stanza->attrs, "type");
|
|
decode_from = ParseeLookupJID(xmpp_from);
|
|
|
|
is_chat = StrEquals(type, "chat");
|
|
if (!is_chat)
|
|
{
|
|
has_anon = ServerHasXEP421(data, xmpp_from);
|
|
is_anon = has_anon && StrEquals(xmpp_from, decode_from);
|
|
}
|
|
|
|
if (is_anon || force)
|
|
{
|
|
XMLElement *occupant;
|
|
occupant = XMLookForTKV(
|
|
stanza, "occupant-id",
|
|
"xmlns", "urn:xmpp:occupant-id:0"
|
|
);
|
|
occ_id = occupant ? HashMapGet(occupant->attrs, "id") : NULL;
|
|
if (!occ_id)
|
|
{
|
|
occ_id = ParseeLookupOID(xmpp_from);
|
|
looked = occ_id;
|
|
}
|
|
else
|
|
{
|
|
ParseePushOIDTable(xmpp_from, occ_id);
|
|
}
|
|
}
|
|
|
|
if (!occ_id)
|
|
{
|
|
user = ParseeEncodeJID(
|
|
data->config,
|
|
decode_from,
|
|
type ? is_chat : false
|
|
);
|
|
Free(decode_from);
|
|
Free(looked);
|
|
return user;
|
|
}
|
|
|
|
Free(decode_from);
|
|
Free(looked);
|
|
return ScrambleOID(data, occ_id);
|
|
}
|