[ADD/WIP] VCard4, slightly more PEPwerk

This commit is contained in:
LDA 2024-07-22 18:02:24 +02:00
commit ee004ca9c0
10 changed files with 313 additions and 32 deletions

View file

@ -881,3 +881,18 @@ ParseeAchievement(const char *func, const char *msg, bool die)
abort(); abort();
} }
} }
char *
ParseeGenerateMTO(char *common_id)
{
char *matrix_to;
if (!common_id)
{
return NULL;
}
common_id = HttpUrlEncode(common_id);
matrix_to = StrConcat(2, "https://matrix.to/#/", common_id);
Free(common_id);
return matrix_to;
}

126
src/XMPPThread/PEP.c Normal file
View file

@ -0,0 +1,126 @@
#include "XMPPThread/internal.h"
#include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Str.h>
#include <Cytoplasm/Log.h>
#include <pthread.h>
struct PEPManager {
pthread_mutex_t lock;
ParseeData *data;
HashMap *node_table;
void *cookie;
};
PEPManager *
CreatePEPManager(ParseeData *data, void *cookie)
{
PEPManager *ret;
if (!data)
{
return NULL;
}
ret = Malloc(sizeof(*ret));
ret->cookie = cookie;
ret->data = data;
ret->node_table = HashMapCreate();
pthread_mutex_init(&ret->lock, NULL);
return ret;
}
void *
PEPManagerCookie(PEPManager *manager)
{
return manager ? manager->cookie : NULL;
}
void
PEPManagerAddEvent(PEPManager *manager, char *node, PEPEvent event)
{
if (!manager || !node || !event)
{
return;
}
pthread_mutex_lock(&manager->lock);
HashMapSet(manager->node_table, node, event);
pthread_mutex_unlock(&manager->lock);
}
static bool
PEPManagerHandleEvent(PEPManager *manager, XMLElement *stanza)
{
PEPEvent call = NULL;
XMLElement *event, *ps, *ev;
size_t i;
if (!manager || !stanza)
{
return false;
}
#define PEP_NS "http://jabber.org/protocol/pubsub"
if (!(ps = XMLookForTKV(stanza, "pubsub", "xmlns", PEP_NS)) &&
!(ev = XMLookForTKV(stanza, "event", "xmlns", PEP_NS "#event")))
{
return false;
}
event = ps ? ps : ev;
for (i = 0; i < ArraySize(event->children); i++)
{
XMLElement *items = ArrayGet(event->children, i);
char *node = HashMapGet(items->attrs, "node");
if ((call = HashMapGet(manager->node_table, node)))
{
size_t j;
/* Use the callback over all items */
if (ev)
{
for (j = 0; j < ArraySize(items->children); j++)
{
call(manager, stanza, ArrayGet(items->children, j));
}
return true;
}
/* ... or over "items" specifically. */
call(manager, stanza, items);
return true;
}
}
return false;
}
bool
PEPManagerHandle(PEPManager *manager, XMLElement *stanza)
{
if (!manager || !stanza)
{
return false;
}
/* Check if it is a PEP stanza */
if (PEPManagerHandleEvent(manager, stanza))
{
return true;
}
return false;
}
void
DestroyPEPManager(PEPManager *manager)
{
if (!manager)
{
return;
}
pthread_mutex_destroy(&manager->lock);
HashMapFree(manager->node_table);
Free(manager);
}

View file

@ -1,14 +1,15 @@
#include "XMPPThread/internal.h" #include "XMPPThread/internal.h"
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Str.h>
#include <Parsee.h> #include <Parsee.h>
#include <XMPP.h> #include <XMPP.h>
#include <XML.h> #include <XML.h>
/* Manages an avatar metadata pubsub item */ #include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h>
#include <Cytoplasm/Str.h>
#include <Cytoplasm/Log.h>
#include <Cytoplasm/Db.h>
static XMLElement * static XMLElement *
CreateAvatarRequest(char *from, char *to, char *avatar_id) CreateAvatarRequest(char *from, char *to, char *avatar_id)
{ {
@ -38,9 +39,11 @@ CreateAvatarRequest(char *from, char *to, char *avatar_id)
void void
ManageProfileItem(ParseeData *args, XMLElement *item, XMLElement *stanza, XMPPThread *thr) PEPAvatarEvent(PEPManager *m, XMLElement *stanza, XMLElement *item)
{ {
XMPPComponent *jabber = args->jabber; XMPPThreadInfo *info = PEPManagerCookie(m);
XMPPComponent *jabber = info->jabber;
ParseeData *args = info->args;
DbRef *avatars; DbRef *avatars;
HashMap *json; HashMap *json;
@ -82,4 +85,3 @@ ManageProfileItem(ParseeData *args, XMLElement *item, XMLElement *stanza, XMPPTh
end: end:
DbUnlock(args->db, avatars); DbUnlock(args->db, avatars);
} }

116
src/XMPPThread/PEPs/VCard.c Normal file
View file

@ -0,0 +1,116 @@
#include "XMPPThread/internal.h"
#include <Parsee.h>
#include <XMPP.h>
#include <XML.h>
#include <AS.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Str.h>
#include <Cytoplasm/Log.h>
#include <string.h>
#define AddFieldBase(type) \
XMLElement *field, *text, *text_data; \
field = XMLCreateTag(name); \
text = XMLCreateTag(type); \
text_data = XMLCreateText(value); \
\
XMLAddChild(vcard, field); \
XMLAddChild(field, text); \
XMLAddChild(text, text_data)
static void
AddTextField(XMLElement *vcard, char *name, char *value)
{
AddFieldBase("text");
}
static void
AddURIField(XMLElement *vcard, char *name, char *value)
{
AddFieldBase("uri");
}
#undef AddFieldBase
void
PEPVCardEvent(PEPManager *m, XMLElement *stanza, XMLElement *item)
{
XMPPThreadInfo *info = PEPManagerCookie(m);
XMPPComponent *jabber = info->jabber;
ParseeData *data = info->args;
char *from = HashMapGet(stanza->attrs, "from");
char *to = HashMapGet(stanza->attrs, "to");
char *id = HashMapGet(stanza->attrs, "id");
XMLElement *reply;
reply = XMLCreateTag("iq");
XMLAddAttr(reply, "type", "result");
XMLAddAttr(reply, "id", id);
XMLAddAttr(reply, "from", to);
XMLAddAttr(reply, "to", from);
{
XMLElement *pubsub, *items, *item;
pubsub = XMLCreateTag("pubsub");
items = XMLCreateTag("items");
item = XMLCreateTag("item");
XMLAddChild(reply, pubsub);
XMLAddChild(pubsub, items);
XMLAddChild(items, item);
XMLAddAttr(pubsub, "xmlns", "http://jabber.org/protocol/pubsub");
XMLAddAttr(items, "node", "urn:xmpp:vcard4");
{
XMLElement *vcard = XMLCreateTag("vcard");
XMLAddAttr(vcard, "xmlns", "urn:ietf:params:xml:ns:vcard-4.0");
if (!strncmp(to, "parsee", 6))
{
AddTextField(vcard, "title", "System user");
AddTextField(vcard, "fn", "Parsee Mizuhashi");
AddTextField(vcard, "nickname", "parsee");
AddTextField(vcard, "nickname", "that annoying bridge");
AddTextField(vcard, "nickname", "green-eyed monster");
AddURIField(vcard, "url", REPOSITORY);
AddURIField(vcard, "url", "https://kappach.at/parsee");
AddTextField(vcard, "note", "This is the Parsee user account.");
}
else
{
/* TODO: Get the user's info(over the Matrix profile API if
* the server shows support for it.) */
char *mxid = ParseeDecodeMXID(to);
char *name = ASGetName(data->config, NULL, mxid);
char *m_to = ParseeGenerateMTO(mxid);
AddTextField(vcard, "title", "Matrix user");
AddTextField(vcard, "fn", name);
AddTextField(vcard, "nickname", mxid);
AddURIField(vcard, "url", REPOSITORY);
AddURIField(vcard, "url", "https://kappach.at/parsee");
AddURIField(vcard, "url", "https://matrix.org");
AddURIField(vcard, "url", m_to);
AddTextField(
vcard,
"note",
"This is a bridged Matrix user, from Parsee."
);
Free(mxid);
Free(name);
Free(m_to);
}
XMLAddChild(item, vcard);
}
}
pthread_mutex_lock(&jabber->write_lock);
XMLEncode(jabber->stream, reply);
StreamFlush(jabber->stream);
pthread_mutex_unlock(&jabber->write_lock);
XMLFreeElement(reply);
}

View file

@ -6,6 +6,7 @@
#include <XMPP.h> #include <XMPP.h>
#include <XML.h> #include <XML.h>
/* TODO: This should be in PEP.c */
XMLElement * XMLElement *
CreatePubsubRequest(char *from, char *to, char *node) CreatePubsubRequest(char *from, char *to, char *node)
{ {

View file

@ -124,7 +124,7 @@ ParseeXMPPThread(void *argp)
/* Initialise the await table */ /* Initialise the await table */
await_table = HashMapCreate(); await_table = HashMapCreate();
/* Initialise the command manager, and add all ad-hoc commands */ /* Initialise the managers, and add all handlers. */
info.m = XMPPCreateManager(args); info.m = XMPPCreateManager(args);
{ {
XMPPCommand *cmd; XMPPCommand *cmd;
@ -137,6 +137,17 @@ ParseeXMPPThread(void *argp)
XMPPCOMMANDS XMPPCOMMANDS
#undef XMPP_COMMAND #undef XMPP_COMMAND
} }
info.pep_manager = CreatePEPManager(args, &info);
{
PEPManagerAddEvent(
info.pep_manager,
"urn:xmpp:avatar:metadata", PEPAvatarEvent
);
PEPManagerAddEvent(
info.pep_manager,
"urn:xmpp:vcard4", PEPVCardEvent
);
}
/* Initialise the FIFO */ /* Initialise the FIFO */
info.stanzas = ArrayCreate(); info.stanzas = ArrayCreate();
@ -221,6 +232,7 @@ ParseeXMPPThread(void *argp)
pthread_mutex_destroy(&info.lock); pthread_mutex_destroy(&info.lock);
DestroyPEPManager(info.pep_manager);
XMPPFreeManager(info.m); XMPPFreeManager(info.m);
return NULL; return NULL;
} }

View file

@ -120,6 +120,8 @@ IQResult(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
{ {
XMLElement *vcard = XMLookForTKV(stanza, "vCard", "xmlns", "vcard-temp"); XMLElement *vcard = XMLookForTKV(stanza, "vCard", "xmlns", "vcard-temp");
/* TODO: Move this to PEP */
XMLElement *event = XMLookForTKV(stanza, "pubsub", XMLElement *event = XMLookForTKV(stanza, "pubsub",
"xmlns", "http://jabber.org/protocol/pubsub" "xmlns", "http://jabber.org/protocol/pubsub"
); );
@ -425,10 +427,15 @@ IQSet(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
} }
#undef DISCO #undef DISCO
void IQStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr) void
IQStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
{ {
char *type; char *type = HashMapGet(stanza->attrs, "type");
type = HashMapGet(stanza->attrs, "type");
if (PEPManagerHandle(thr->info->pep_manager, stanza))
{
return;
}
#define OnType(ctyp, callback) do \ #define OnType(ctyp, callback) do \
{ \ { \
if (StrEquals(type, #ctyp)) \ if (StrEquals(type, #ctyp)) \

View file

@ -17,7 +17,6 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
XMLElement *reactions = NULL; XMLElement *reactions = NULL;
XMLElement *body = NULL; XMLElement *body = NULL;
XMLElement *data = NULL; XMLElement *data = NULL;
XMLElement *event = NULL;
char *to, *room, *from, *from_matrix, *decode_from; char *to, *room, *from, *from_matrix, *decode_from;
char *mroom_id = NULL; char *mroom_id = NULL;
@ -64,25 +63,7 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
} }
body = XMLookForUnique(stanza, "body"); body = XMLookForUnique(stanza, "body");
event = XMLookForTKV(stanza, "event", PEPManagerHandle(thr->info->pep_manager, stanza);
"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" #define CHAT_STATES "http://jabber.org/protocol/chatstates"
if (XMLookForTKV(stanza, "composing", "xmlns", CHAT_STATES)) if (XMLookForTKV(stanza, "composing", "xmlns", CHAT_STATES))

View file

@ -32,6 +32,9 @@
IdentitySimple("client", "pc", NAME " v" VERSION " bridge") \ IdentitySimple("client", "pc", NAME " v" VERSION " bridge") \
IdentitySimple("component", "generic", "Parsee's component") IdentitySimple("component", "generic", "Parsee's component")
typedef struct PEPManager PEPManager;
typedef void (*PEPEvent)(PEPManager *m, XMLElement *stanza, XMLElement *item);
typedef struct XMPPIdentity { typedef struct XMPPIdentity {
char *category, *type, *lang, *name; char *category, *type, *lang, *name;
} XMPPIdentity; } XMPPIdentity;
@ -46,6 +49,7 @@ typedef struct XMPPThreadInfo {
ParseeData *args; ParseeData *args;
XMPPComponent *jabber; XMPPComponent *jabber;
XMPPCommandManager *m; XMPPCommandManager *m;
PEPManager *pep_manager;
struct XMPPThread *dispatchers; struct XMPPThread *dispatchers;
size_t available_dispatchers; size_t available_dispatchers;
@ -80,3 +84,13 @@ bool ServerHasXEP421(ParseeData *data, char *from);
char * ParseeGetBridgedUserI(ParseeData *data, XMLElement *stanza, char *force); char * ParseeGetBridgedUserI(ParseeData *data, XMLElement *stanza, char *force);
#define ParseeGetBridgedUser(data, stanza) ParseeGetBridgedUserI(data, stanza, NULL) #define ParseeGetBridgedUser(data, stanza) ParseeGetBridgedUserI(data, stanza, NULL)
PEPManager * CreatePEPManager(ParseeData *data, void *cookie);
void * PEPManagerCookie(PEPManager *manager);
void PEPManagerAddEvent(PEPManager *manager, char *node, PEPEvent event);
bool PEPManagerHandle(PEPManager *manager, XMLElement *stanza);
void DestroyPEPManager(PEPManager *manager);
/* PEP callbacks for the handler */
void PEPAvatarEvent(PEPManager *m, XMLElement *stanza, XMLElement *item);
void PEPVCardEvent(PEPManager *m, XMLElement *stanza, XMLElement *item);

View file

@ -255,4 +255,11 @@ extern char * ParseeMXID(ParseeData *data);
extern void ParseeAchievement(const char *func, const char *msg, bool die); extern void ParseeAchievement(const char *func, const char *msg, bool die);
#define Achievement(msg, die) ParseeAchievement(__func__, msg, die) #define Achievement(msg, die) ParseeAchievement(__func__, msg, die)
/** Generates a 'matrix.to' URL from a Matrix ID, to be used for
* linking to a room, user, etc...
* ----------------------
* Returns: A Matrix URL[LA:HEAP]
* Thrasher: Free */
extern char * ParseeGenerateMTO(char *common_id);
#endif #endif