Parsee/src/XMPPThread/Bridged.c
LDA dd180ee3f4 [MOD] Use server_base instead of the API host
This wasn't an issue because the server I test on has the same API host
as its name.
2024-07-26 17:13:02 +02:00

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);
}