[ADD] Respect MIME, start bridging leaves/kicks

Wow, this one _wasn't_ pushed at 3AM, Outstanding.
This commit is contained in:
LDA 2024-07-07 17:30:48 +02:00
commit 43b3f8aaf5
8 changed files with 146 additions and 24 deletions

View file

@ -10,7 +10,7 @@ Somewhat implemented XEPs:
IM platforms I won't mention), so this doesn't sound too bad to do IM platforms I won't mention), so this doesn't sound too bad to do
HALF-IMPLEMENTED: Removing reacts won't work. HALF-IMPLEMENTED: Removing reacts won't work.
~ https://xmpp.org/extensions/xep-0184.html ~ https://xmpp.org/extensions/xep-0184.html
no one wants to send me receipts :((((((((((((( Only Matrix->XMPP as of now
For future XEPs: For future XEPs:
- https://xmpp.org/extensions/xep-0421.html - https://xmpp.org/extensions/xep-0421.html
@ -31,6 +31,10 @@ For future XEPs:
Stickers are great. Matrix and XMPP somewhat has support for them, so 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. might be a nice-to-have, and also to push over XMPP support.
- https://xmpp.org/extensions/xep-0050.html
Ad-hoc commands that bridge maintainers can deal with XMPP-style are
also a nice to have.
ON STANDBY BECAUSE THESE HAVE BEEN TERRIBLE TO DEAL WITH AND WHO KEEPS WRITING ON STANDBY BECAUSE THESE HAVE BEEN TERRIBLE TO DEAL WITH AND WHO KEEPS WRITING
THESE I WANT TO SEND THEM A NICE, BRIGHT GIFT: THESE I WANT TO SEND THEM A NICE, BRIGHT GIFT:
(x) https://xmpp.org/extensions/xep-0084.html (x) https://xmpp.org/extensions/xep-0084.html

View file

@ -632,7 +632,7 @@ ASSetPL(const ParseeConfig *conf, char *id, HashMap *m)
} }
char * char *
ASUpload(const ParseeConfig *c, Stream *from, unsigned int size) ASUpload(const ParseeConfig *c, Stream *from, unsigned int size, char *mime)
{ {
char *size_str, *path, *ret, *user; char *size_str, *path, *ret, *user;
int i; int i;
@ -640,7 +640,6 @@ ASUpload(const ParseeConfig *c, Stream *from, unsigned int size)
HashMap *reply; HashMap *reply;
if (!c || !from) if (!c || !from)
{ {
Log(LOG_INFO, "Obvious upload fail");
return NULL; return NULL;
} }
@ -655,6 +654,10 @@ ASUpload(const ParseeConfig *c, Stream *from, unsigned int size)
{ {
HttpRequestHeader(ctx, "Content-Length", size_str); HttpRequestHeader(ctx, "Content-Length", size_str);
} }
if (mime)
{
HttpRequestHeader(ctx, "Content-Type", mime);
}
HttpRequestSendHeaders(ctx); HttpRequestSendHeaders(ctx);
for (i = 0; i < size; i++) for (i = 0; i < size; i++)
@ -739,7 +742,7 @@ ASReupload(const ParseeConfig *c, char *from, char **mime)
{ {
size = strtol(content_len, NULL, 10); size = strtol(content_len, NULL, 10);
} }
ret = ASUpload(c, HttpClientStream(ctx), size); ret = ASUpload(c, HttpClientStream(ctx), size, mime ? *mime : NULL);
HttpClientContextFree(ctx); HttpClientContextFree(ctx);
UriFree(uri); UriFree(uri);

View file

@ -63,6 +63,35 @@ ParseeMemberHandler(ParseeData *data, HashMap *event)
Free(jid); Free(jid);
Free(chat_id); Free(chat_id);
} }
else if (StrEquals(membership, "leave") && !ParseeIsPuppet(conf, state_key))
{
/* TODO: Manage bans */
XMPPComponent *jabber = data->jabber;
char *jid = ParseeEncodeMXID(state_key);
char *name = NULL, *rev = NULL, *muc_id = NULL;
char *reason = GrabString(event, 2, "content", "reason");
/* Try to find the chat ID */
chat_id = ParseeGetFromRoomID(data, room_id);
muc_id = ParseeGetMUCID(data, chat_id);
if (!chat_id)
{
goto end;
}
/* TODO: Check the name's validity */
name = ASGetName(data->config, room_id, state_key);
rev = StrConcat(4, muc_id, "/", name, "[p]");
XMPPLeaveMUC(jabber, jid, rev, reason);
end:
Free(chat_id);
Free(muc_id);
Free(name);
Free(rev);
Free(jid);
}
} }
static void static void
ParseeBotHandler(ParseeData *data, HashMap *event) ParseeBotHandler(ParseeData *data, HashMap *event)
@ -95,7 +124,6 @@ ParseeBotHandler(ParseeData *data, HashMap *event)
return; return;
} }
/* TODO: Make an improvment. This is the bare minimum */
if (!ParseeIsAdmin(data, sender)) if (!ParseeIsAdmin(data, sender))
{ {
Free(ASSend( Free(ASSend(
@ -172,8 +200,6 @@ ParseeMessageHandler(ParseeData *data, HashMap *event)
return; return;
} }
/* TODO: Reunite DM/MUC code to bring feature parity. */
type = direct ? "chat" : "groupchat"; type = direct ? "chat" : "groupchat";
user = GrabString(json, 1, "xmpp_user"); user = GrabString(json, 1, "xmpp_user");
unauth = ParseeToUnauth(data, url); unauth = ParseeToUnauth(data, url);
@ -237,7 +263,7 @@ ParseeMessageHandler(ParseeData *data, HashMap *event)
stanza, sender, ev_id, unauth, origin_id, stanza, sender, ev_id, unauth, origin_id,
xmpp_ident xmpp_ident
); );
/* Culprit */
if (direct) if (direct)
{ {
ParseePushDMStanza( ParseePushDMStanza(

View file

@ -48,6 +48,9 @@ RouteHead(RouteRoomAck, arr, argp)
char *creator = NULL, *muc_name = NULL, *chatid = NULL; char *creator = NULL, *muc_name = NULL, *chatid = NULL;
/* TODO: If an ACK request maps to a MUC that has a chat ID,
* DO NOT create a new one, and instead make a new mapping to
* the previous one. */
response = ASVerifyRequest(args); response = ASVerifyRequest(args);
if (response) if (response)
{ {
@ -67,7 +70,6 @@ RouteHead(RouteRoomAck, arr, argp)
if (ParseeManageBan(args->data, muc, NULL)) if (ParseeManageBan(args->data, muc, NULL))
{ {
HttpResponseStatus(args->ctx, HTTP_METHOD_NOT_ALLOWED); HttpResponseStatus(args->ctx, HTTP_METHOD_NOT_ALLOWED);
Log(LOG_INFO, "Nofly...");
response = MatrixCreateError( response = MatrixCreateError(
"M_NOT_FOUND", "M_NOT_FOUND",
"XMPP MUC is banned from being accessed on this instance" "XMPP MUC is banned from being accessed on this instance"
@ -94,7 +96,6 @@ RouteHead(RouteRoomAck, arr, argp)
); );
if (!id) if (!id)
{ {
Log(LOG_INFO, "No ID");
HttpResponseStatus(args->ctx, HTTP_INTERNAL_SERVER_ERROR); HttpResponseStatus(args->ctx, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixCreateError( response = MatrixCreateError(
"M_UNKNOWN", "M_UNKNOWN",

View file

@ -176,6 +176,44 @@ XMPPSendMUC(XMPPComponent *comp, char *fr, char *as, char *to, char *msg, char *
pthread_mutex_unlock(&comp->write_lock); pthread_mutex_unlock(&comp->write_lock);
} }
void void
XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason)
{
XMLElement *presence;
char *from, *id;
if (!comp || !fr || !muc)
{
return;
}
pthread_mutex_lock(&comp->write_lock);
presence = XMLCreateTag("presence");
XMLAddAttr(presence, "from", (from = StrConcat(3, fr, "@", comp->host)));
XMLAddAttr(presence, "to", muc);
XMLAddAttr(presence, "id", (id = StrRandom(8)));
XMLAddAttr(presence, "type", "unavailable");
if (reason)
{
XMLElement *status = XMLCreateTag("status");
XMLElement *string = XMLCreateText(reason);
XMLAddChild(status, string);
XMLAddChild(presence, status);
}
XMPPAnnotatePresence(presence);
XMLEncode(comp->stream, presence);
StreamFlush(comp->stream);
XMLFreeElement(presence);
Free(from);
Free(id);
pthread_mutex_unlock(&comp->write_lock);
}
void
XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc) XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc)
{ {
XMLElement *presence, *x; XMLElement *presence, *x;

View file

@ -822,7 +822,7 @@ IQResult(ParseeData *args, XMLElement *stanza)
/* TODO: Bound checks for a size limit. */ /* TODO: Bound checks for a size limit. */
bdata = (char *) Base64Decode(base64, b64len); bdata = (char *) Base64Decode(base64, b64len);
datastream = StrStreamReaderN(bdata, length); datastream = StrStreamReaderN(bdata, length);
mxc = ASUpload(args->config, datastream, length); mxc = ASUpload(args->config, datastream, length, "image/png");
jid = ParseeLookupJID(from); jid = ParseeLookupJID(from);
from_matrix = ParseeEncodeJID(args->config, jid, false); from_matrix = ParseeEncodeJID(args->config, jid, false);
@ -859,34 +859,65 @@ IQResult(ParseeData *args, XMLElement *stanza)
if (photo) if (photo)
{ {
XMLElement *binval = XMLookForUnique(photo, "BINVAL"); XMLElement *binval = XMLookForUnique(photo, "BINVAL");
XMLElement *data = ArrayGet(binval->children, 0); XMLElement *type = XMLookForUnique(photo, "TYPE");
XMLElement *data =
binval ? ArrayGet(binval->children, 0) : NULL;
XMLElement *tdata = type ? ArrayGet(type->children, 0) : NULL;
char *base64; char *base64;
char *bdata; char *bdata;
size_t length, b64len; size_t length, b64len;
Stream *datastream; Stream *datastream;
char *mxc, *from_matrix, *jid; char *mxc = NULL, *from_matrix = NULL, *jid = NULL;
char *room = NULL;
if (!data || !data->data) if (!data || !data->data)
{ {
Log(LOG_ERR, "%s NOT FOUND", HashMapGet(stanza->attrs, "from"));
return; return;
} }
/* Get the base64, decode it, and shove it in a nicely put
* MXC address */
base64 = data->data; base64 = data->data;
b64len = base64 ? strlen(base64) : 0; b64len = base64 ? strlen(base64) : 0;
length = Base64DecodedSize(base64, b64len); length = Base64DecodedSize(base64, b64len);
bdata = Base64Decode(base64, b64len); bdata = Base64Decode(base64, b64len);
datastream = StrStreamReaderN(bdata, length); datastream = StrStreamReaderN(bdata, length);
mxc = ASUpload(args->config, datastream, length); mxc = ASUpload(
args->config,
jid = ParseeLookupJID(HashMapGet(stanza->attrs, "from")); datastream,
from_matrix = ParseeEncodeJID(args->config, jid, false); length,
ASSetAvatar(args->config, from_matrix, mxc); tdata ? tdata->data : NULL
);
/* TODO: Check if already set. */
Free(bdata); Free(bdata);
StreamClose(datastream); StreamClose(datastream);
room = ParseeGetBridgedRoom(args, stanza);
jid = ParseeLookupJID(HashMapGet(stanza->attrs, "from"));
if (jid && !StrEquals(jid, HashMapGet(stanza->attrs, "from")))
{
from_matrix = ParseeEncodeJID(args->config, jid, false);
ASSetAvatar(args->config, from_matrix, mxc);
}
else if (room)
{
char *mask = StrConcat(4,
"@", args->config->sender_localpart,
":", args->config->homeserver_host
);
HashMap *obj = HashMapCreate();
HashMapSet(obj, "url", JsonValueString(mxc));
ASSetState(
args->config,
room, "m.room.avatar", "",
mask, obj
);
Free(mask);
}
Free(from_matrix); Free(from_matrix);
Free(room);
Free(jid); Free(jid);
Free(mxc); Free(mxc);
} }
@ -1117,7 +1148,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza)
json = DbJson(avatars); json = DbJson(avatars);
avatar_id = GrabString(json, 1, oid); avatar_id = GrabString(json, 1, oid);
if (StrEquals(avatar_id, p_dat->data)) if (avatar_id && StrEquals(avatar_id, p_dat->data))
{ {
DbUnlock(args->db, avatars); DbUnlock(args->db, avatars);
return; return;
@ -1142,6 +1173,24 @@ PresenceStanza(ParseeData *args, XMLElement *stanza)
XMLFreeElement(vcard_request); XMLFreeElement(vcard_request);
Free(from); Free(from);
} }
/* TODO: Sending VCard on presence is slow and stalls the thread */
if (0)
{
XMPPComponent *jabber = args->jabber;
char *from = StrConcat(2, "parsee@", args->config->component_host);
XMLElement *vcard_request = CreateVCardRequest(
from, HashMapGet(stanza->attrs, "from")
);
pthread_mutex_lock(&jabber->write_lock);
XMLEncode(jabber->stream, vcard_request);
StreamFlush(jabber->stream);
pthread_mutex_unlock(&jabber->write_lock);
XMLFreeElement(vcard_request);
Free(from);
}
#undef MUC_USER_NS #undef MUC_USER_NS
} }

View file

@ -63,7 +63,7 @@ extern void ASSetAvatar(const ParseeConfig *c, char *user, char *mxc);
extern char * ASGetName(const ParseeConfig *c, char *room, char *user); extern char * ASGetName(const ParseeConfig *c, char *room, char *user);
/* Uploads data to Matrix to be used later */ /* Uploads data to Matrix to be used later */
extern char * ASUpload(const ParseeConfig *c, Stream *from, unsigned int size); extern char * ASUpload(const ParseeConfig *c, Stream *from, unsigned int size, char *mime);
/* Reuploads a HTTP URL to Matrix, with an optional MIME type returned. */ /* Reuploads a HTTP URL to Matrix, with an optional MIME type returned. */
extern char * ASReupload(const ParseeConfig *c, char *from, char **mime); extern char * ASReupload(const ParseeConfig *c, char *from, char **mime);

View file

@ -24,8 +24,9 @@ extern XMPPComponent * XMPPInitialiseCompStream(char *host, int port);
* after XMPPInitialiseCompStream. */ * after XMPPInitialiseCompStream. */
extern bool XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared); extern bool XMPPAuthenticateCompStream(XMPPComponent *comp, char *shared);
/* Makes a user join a MUC */ /* Makes a user join/leave a MUC */
extern void XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc); extern void XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc);
extern void XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *r);
/* TODO: XMPP stuff, I don't fucking know, I'm not a Jabbernerd. */ /* TODO: XMPP stuff, I don't fucking know, I'm not a Jabbernerd. */
extern void XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, char *rst, char *rse, char *event_id, char *oob, char *id); extern void XMPPSendPlain(XMPPComponent *comp, char *fr, char *to, char *msg, char *type, char *rst, char *rse, char *event_id, char *oob, char *id);