diff --git a/XEPS-TBD.TXT b/XEPS-TBD.TXT index f887385..9878acd 100644 --- a/XEPS-TBD.TXT +++ b/XEPS-TBD.TXT @@ -48,9 +48,9 @@ THESE I WANT TO SEND THEM A NICE, BRIGHT GIFT: Not XEPs, but ideas that _needs_ to be added: + ~ "also it [Bifrost] doesn't respect voice either" -> Send a form on moderated + MUCs (which is standard, so its not too bad!). Currently WIP, and barely tested. ~ "GIVE THE PUPPETS APPROPRIATE PLS/ROLES" - Hydro/t4d - - "also it [Bifrost] doesn't respect voice either" -> Send a form on moderated - MUCs (which is standard, so its not too bad!) - Standalone/Static Parsee, ideally as small as it can be(if not as APE). - https://www.youtube.com/watch?v=InL414iDZmY diff --git a/src/XMPP/MUC.c b/src/XMPP/MUC.c index cbdd91e..2f29a38 100644 --- a/src/XMPP/MUC.c +++ b/src/XMPP/MUC.c @@ -106,3 +106,64 @@ XMPPGetMUCName(MUCInfo info) return name; } +void +XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc) +{ + XMLElement *stanza; + char *identifier; + if (!jabber || !from || !muc) + { + return; + } + + pthread_mutex_lock(&jabber->write_lock); + stanza = XMLCreateTag("message"); + XMLAddAttr(stanza, "id", (identifier = StrRandom(32))); + XMLAddAttr(stanza, "from", from); + XMLAddAttr(stanza, "to", muc); + { + XMLElement *x = XMLCreateTag("x"); + XMLAddAttr(x, "xmlns", "jabber:x:data"); + XMLAddAttr(x, "type", "submit"); + { + XMLElement *field; + + field = XMLCreateTag("field"); + XMLAddAttr(field, "var", "FORM_TYPE"); + { + XMLElement *value = XMLCreateTag("value"); + { + XMLElement *data = XMLCreateText( + "http://jabber.org/protocol/muc#request" + ); + XMLAddChild(value, data); + } + XMLAddChild(field, value); + } + XMLAddChild(x, field); + + field = XMLCreateTag("field"); + XMLAddAttr(field, "var", "muc#role"); + XMLAddAttr(field, "type", "list-single"); + XMLAddAttr(field, "label", "Requested role"); + { + XMLElement *value = XMLCreateTag("value"); + { + XMLElement *data = XMLCreateText( + "participant" + ); + XMLAddChild(value, data); + } + XMLAddChild(field, value); + } + XMLAddChild(x, field); + } + XMLAddChild(stanza, x); + } + XMLEncode(jabber->stream, stanza); + StreamFlush(jabber->stream); + pthread_mutex_unlock(&jabber->write_lock); + + XMLFreeElement(stanza); + Free(identifier); +} diff --git a/src/XMPP/Stanza.c b/src/XMPP/Stanza.c index 564b236..bc1e1c8 100644 --- a/src/XMPP/Stanza.c +++ b/src/XMPP/Stanza.c @@ -540,3 +540,44 @@ XMPPDiscoAdvertises(XMLElement *disco, char *var) return !!XMLookForTKV(query, "feature", "var", var); } + +char * +XMPPGetErrtype(XMLElement *stanza) +{ + XMLElement *error = XMLookForUnique(stanza, "error"); + XMLElement *type = NULL; + if (!error) + { + return NULL; + } + + type = ArrayGet(error->children, 0); + if (!type) + { + return NULL; + } + + return type->name; +} + +char * +XMPPGetErrtext(XMLElement *stanza) +{ + XMLElement *error = XMLookForUnique(stanza, "error"); + XMLElement *text = NULL, *data; + if (!error) + { + return NULL; + } + + text = XMLookForUnique(error, "text"); + if (!text) + { + return NULL; + } + + data = ArrayGet(text->children, 0); + + return data ? data->data : NULL; + +} diff --git a/src/XMPPThread/Stanzas/Message.c b/src/XMPPThread/Stanzas/Message.c index ec37c3d..5d33297 100644 --- a/src/XMPPThread/Stanzas/Message.c +++ b/src/XMPPThread/Stanzas/Message.c @@ -24,7 +24,8 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) char *retracted = XMPPGetRetractedID(stanza); char *reply_to = XMPPGetReply(stanza); char *moderated = XMPPGetModeration(stanza); - bool chat = StrEquals(HashMapGet(stanza->attrs, "type"), "chat"); + char *type = HashMapGet(stanza->attrs, "type"); + bool chat = StrEquals(type, "chat"); size_t i; to = NULL; @@ -39,6 +40,45 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) return false; } + if (StrEquals(type, "error")) + { + char *type, *text, *user, *parsee; + char *message, *room; + + from = HashMapGet(stanza->attrs, "from"); + to = HashMapGet(stanza->attrs, "to"); + + /* Tiny little trick. */ + XMLAddAttr(stanza, "type", "groupchat"); + + parsee = ParseeMXID(args); + type = XMPPGetErrtype(stanza); + text = XMPPGetErrtext(stanza); + user = ParseeDecodeMXID(to); + + /* Avoid fun hypothetical cases of looping. */ + if (StrEquals(parsee, user)) + { + goto end_error; + } + + message = StrConcat(3, type, ": ", text); + room = ParseeGetBridgedRoom(args, stanza); + Free(ASSend( + args->config, room, parsee, + "m.room.message", + MatrixCreateNotice(message) + )); + +end_error: + XMLFreeElement(stanza); + Free(message); + Free(parsee); + Free(room); + Free(user); + return false; + } + if (moderated) { /* TODO: Parsee MUST check if it is a valid MUC */ diff --git a/src/XMPPThread/Stanzas/Presence.c b/src/XMPPThread/Stanzas/Presence.c index 220bbb5..5d08497 100644 --- a/src/XMPPThread/Stanzas/Presence.c +++ b/src/XMPPThread/Stanzas/Presence.c @@ -79,6 +79,7 @@ PresenceStanza(ParseeData *args, XMLElement *stanza) char *decode_from, *real_matrix; char *matrix_user_pl = ParseeEncodeJID(args->config, trim, false); char *affiliation = HashMapGet(item->attrs, "affiliation"); + char *role = HashMapGet(item->attrs, "role"); int power_level = 0; char *parsee = ParseeMXID(args); @@ -117,6 +118,24 @@ PresenceStanza(ParseeData *args, XMLElement *stanza) power_level = -1; } + if (StrEquals(role, "visitor")) + { + char *parsee = ParseeJID(args); + if (!StrEquals(HashMapGet(stanza->attrs, "to"), parsee) && + IsStatus(110)) + { + char *muc = ParseeTrimJID(HashMapGet(stanza->attrs, "from")); + char *usr = HashMapGet(stanza->attrs, "to"); + + /* Ask for voice */ + XMPPRequestVoice(args->jabber, usr, muc); + + Free(muc); + } + + Free(parsee); + } + /* Set the user's PL * TODO: Do NOT change the PL of *real* people nilly-willy. * In some scenarios, this is really bad behaviour. */ diff --git a/src/include/AS.h b/src/include/AS.h index cc824e2..f12d17a 100644 --- a/src/include/AS.h +++ b/src/include/AS.h @@ -72,10 +72,19 @@ extern HashMap *ASGetPL(const ParseeConfig *conf, char *id); * See-Also: ASGetPL */ extern void ASSetPL(const ParseeConfig *conf, char *id, HashMap *m); -/* Creates a room, with a masquerade user as its creator. This function - * returns it's ID if it exists. */ +/** Creates a room, with a masquerade user ({by}) as its creator and an + * optional {alias}. + * -------- + * Returns: a valid room ID[HEAP] | NULL + * Modifies: NOTHING + * See-Also: ASCreateDM */ extern char * ASCreateRoom(const ParseeConfig *c, char *by, char *alias); +/** Creates a new DM {with} a Matrix user, from a puppet {by} + * -------- + * Returns: a valid room ID[HEAP] | NULL + * Modifies: NOTHING + * See-Also: ASCreateRoom */ extern char * ASCreateDM(const ParseeConfig *c, char *by, char *with); /** Sets the user's global display{name} diff --git a/src/include/XMPP.h b/src/include/XMPP.h index 4852a30..3fb89c9 100644 --- a/src/include/XMPP.h +++ b/src/include/XMPP.h @@ -107,4 +107,26 @@ extern bool XMPPHasError(XMLElement *stanza, char *type); extern XMLElement * XMPPSendDisco(XMPPComponent *jabber, char *from, char *to); extern bool XMPPDiscoAdvertises(XMLElement *disco, char *var); + +/** Requests for 'voice' in a moderated MUC as a user by sending a specific + * form. + * ----------- + * Returns: NOTHING + * Modifies: the XMPP MUCs state + * See-Also: https://xmpp.org/extensions/xep-0045.html#requestvoice */ +extern void XMPPRequestVoice(XMPPComponent *jabber, char *from, char *muc); + +/** Retrieves the error type in a stanza if existent. + * ----------------- + * Returns: a valid string error type[stanza] | NULL + * Modifies: NOTHING + * See-Also: XMPPGetErrtext */ +extern char * XMPPGetErrtype(XMLElement *stanza); + +/** Retrieves the error text in a stanza if existent. + * ----------------- + * Returns: a valid string error text[stanza] | NULL + * Modifies: NOTHING + * See-Also: XMPPGetErrtype */ +extern char * XMPPGetErrtext(XMLElement *stanza); #endif