mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-13 16:55:10 +00:00
[MOD] Basic work to get XMPP avatars through PEP
Attaboy!
This commit is contained in:
parent
f31a9c37b6
commit
e54332e376
13 changed files with 428 additions and 25 deletions
|
|
@ -21,7 +21,7 @@ of Parsee. May occasionally deadlock.
|
||||||
Fixes some media metadata things, and replaces the build
|
Fixes some media metadata things, and replaces the build
|
||||||
system of Parsee.
|
system of Parsee.
|
||||||
#### New things
|
#### New things
|
||||||
*NONE*
|
- Start dealing with some basic PEP-based avatars.
|
||||||
#### Bugfixes
|
#### Bugfixes
|
||||||
- Adds more information to media events so that clients can behave.
|
- Adds more information to media events so that clients can behave.
|
||||||
- Fixes issues where SIGPIPE can actually just kill Parsee.
|
- Fixes issues where SIGPIPE can actually just kill Parsee.
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ Currently, the main sources of documentation are the Ayadocs(for headers) and th
|
||||||
|
|
||||||
## TODOS before 1.0 rolls around
|
## TODOS before 1.0 rolls around
|
||||||
- PROPER FUCKING AVATARS
|
- PROPER FUCKING AVATARS
|
||||||
XMPP->Matrix is decent, Matrix->XMPP is effectiveny not done
|
XMPP->Matrix is decent, Matrix->XMPP is effectively a WIP
|
||||||
- Add [libomemo](https://github.com/gkdr/libomemo) or something as an optional dependency.
|
- Add [libomemo](https://github.com/gkdr/libomemo) or something as an optional dependency.
|
||||||
- It depends on more stuff anyways, and I don't want to weigh down the
|
- It depends on more stuff anyways, and I don't want to weigh down the
|
||||||
dependency list of Parsee for that.
|
dependency list of Parsee for that.
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <Cytoplasm/Str.h>
|
#include <Cytoplasm/Str.h>
|
||||||
#include <Cytoplasm/Log.h>
|
#include <Cytoplasm/Log.h>
|
||||||
#include <Cytoplasm/Uri.h>
|
#include <Cytoplasm/Uri.h>
|
||||||
|
#include <Cytoplasm/Sha.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -127,3 +128,95 @@ ASReupload(const ParseeConfig *c, char *from, char **mime)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ASGetMIMESHA(const ParseeConfig *c, char *mxc, char **mime, char **sha)
|
||||||
|
{
|
||||||
|
HttpClientContext *cctx;
|
||||||
|
Stream *stream;
|
||||||
|
Stream *fake;
|
||||||
|
Uri *uri;
|
||||||
|
char *path, *buf = NULL;
|
||||||
|
unsigned char *sha1;
|
||||||
|
size_t len;
|
||||||
|
bool ret;
|
||||||
|
if (!c || !mxc || !mime || !sha)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*mime = NULL;
|
||||||
|
*sha = NULL;
|
||||||
|
|
||||||
|
if (!(uri = UriParse(mxc)) || !StrEquals(uri->proto, "mxc"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = StrConcat(3, "/_matrix/media/v3/download/", uri->host, uri->path);
|
||||||
|
cctx = ParseeCreateRequest(c, HTTP_GET, path);
|
||||||
|
ASAuthenticateRequest(c, cctx);
|
||||||
|
HttpRequestSendHeaders(cctx);
|
||||||
|
HttpRequestSend(cctx);
|
||||||
|
|
||||||
|
*mime = StrDuplicate(
|
||||||
|
HashMapGet(HttpResponseHeaders(cctx), "content-type")
|
||||||
|
);
|
||||||
|
stream = HttpClientStream(cctx);
|
||||||
|
fake = StreamFile(open_memstream(&buf, &len));
|
||||||
|
StreamCopy(stream, fake);
|
||||||
|
StreamClose(fake);
|
||||||
|
|
||||||
|
sha1 = Sha1Raw(buf, len);
|
||||||
|
free(buf);
|
||||||
|
*sha = ShaToHex(sha1, HASH_SHA1);
|
||||||
|
Free(sha1);
|
||||||
|
|
||||||
|
HttpClientContextFree(cctx);
|
||||||
|
UriFree(uri);
|
||||||
|
Free(path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool
|
||||||
|
ASGrab(const ParseeConfig *c, char *mxc, char **mime, char **out, size_t *len)
|
||||||
|
{
|
||||||
|
HttpClientContext *cctx;
|
||||||
|
Stream *stream;
|
||||||
|
Stream *fake;
|
||||||
|
Uri *uri;
|
||||||
|
char *path, *buf = NULL;
|
||||||
|
bool ret;
|
||||||
|
if (!c || !mxc || !mime || !out || !len)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*mime = NULL;
|
||||||
|
*out = NULL;
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
if (!(uri = UriParse(mxc)) || !StrEquals(uri->proto, "mxc"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = StrConcat(3, "/_matrix/media/v3/download/", uri->host, uri->path);
|
||||||
|
cctx = ParseeCreateRequest(c, HTTP_GET, path);
|
||||||
|
ASAuthenticateRequest(c, cctx);
|
||||||
|
HttpRequestSendHeaders(cctx);
|
||||||
|
HttpRequestSend(cctx);
|
||||||
|
|
||||||
|
*mime = StrDuplicate(
|
||||||
|
HashMapGet(HttpResponseHeaders(cctx), "content-type")
|
||||||
|
);
|
||||||
|
stream = HttpClientStream(cctx);
|
||||||
|
fake = StreamFile(open_memstream(&buf, len));
|
||||||
|
StreamCopy(stream, fake);
|
||||||
|
StreamClose(fake);
|
||||||
|
|
||||||
|
*out = Malloc(*len);
|
||||||
|
memcpy(*out, buf, *len);
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
HttpClientContextFree(cctx);
|
||||||
|
UriFree(uri);
|
||||||
|
Free(path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -136,3 +136,72 @@ ASGetName(const ParseeConfig *c, char *room, char *user)
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
char *
|
||||||
|
ASGetAvatar(const ParseeConfig *c, char *room, char *user)
|
||||||
|
{
|
||||||
|
HttpClientContext *ctx;
|
||||||
|
HashMap *reply;
|
||||||
|
char *path = NULL, *ret = NULL;
|
||||||
|
char *u2 = user;
|
||||||
|
if (!c || !user)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (room)
|
||||||
|
{
|
||||||
|
user = HttpUrlEncode(user);
|
||||||
|
room = HttpUrlEncode(room);
|
||||||
|
path = StrConcat(4,
|
||||||
|
"/_matrix/client/v3/rooms/", room,
|
||||||
|
"/state/m.room.member/", user
|
||||||
|
);
|
||||||
|
ctx = ParseeCreateRequest(c, HTTP_GET, path);
|
||||||
|
Free(user);
|
||||||
|
Free(room);
|
||||||
|
ASAuthenticateRequest(c, ctx);
|
||||||
|
HttpRequestSendHeaders(ctx);
|
||||||
|
HttpRequestSend(ctx);
|
||||||
|
|
||||||
|
reply = JsonDecode(HttpClientStream(ctx));
|
||||||
|
|
||||||
|
ret = StrDuplicate(
|
||||||
|
JsonValueAsString(HashMapGet(reply, "avatar_url"))
|
||||||
|
);
|
||||||
|
HttpClientContextFree(ctx);
|
||||||
|
JsonFree(reply);
|
||||||
|
Free(path);
|
||||||
|
|
||||||
|
user = u2;
|
||||||
|
|
||||||
|
Log(LOG_DEBUG, "ASGetAvatar: trying to grab avatar from room, got %s", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
user = HttpUrlEncode(user);
|
||||||
|
path = StrConcat(3,
|
||||||
|
"/_matrix/client/v3/profile/", user, "/avatar_url"
|
||||||
|
);
|
||||||
|
ctx = ParseeCreateRequest(c, HTTP_GET, path);
|
||||||
|
Free(user);
|
||||||
|
user = u2;
|
||||||
|
ASAuthenticateRequest(c, ctx);
|
||||||
|
HttpRequestSendHeaders(ctx);
|
||||||
|
HttpRequestSend(ctx);
|
||||||
|
|
||||||
|
reply = JsonDecode(HttpClientStream(ctx));
|
||||||
|
|
||||||
|
ret = StrDuplicate(
|
||||||
|
JsonValueAsString(HashMapGet(reply, "avatar_url"))
|
||||||
|
);
|
||||||
|
StreamFlush(StreamStderr());
|
||||||
|
HttpClientContextFree(ctx);
|
||||||
|
JsonFree(reply);
|
||||||
|
Free(path);
|
||||||
|
|
||||||
|
Log(LOG_DEBUG, "ASGetAvatar: trying to grab avatar from profile, got %s", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,8 @@ Main(Array *args, HashMap *env)
|
||||||
);
|
);
|
||||||
ParseePrintASCII();
|
ParseePrintASCII();
|
||||||
Log(LOG_INFO, "=======================");
|
Log(LOG_INFO, "=======================");
|
||||||
|
Log(LOG_INFO, "(C)opyright 2023 LDA");
|
||||||
|
Log(LOG_INFO, "(This program is free software, see LICENSE.)");
|
||||||
LogConfigIndent(LogConfigGlobal());
|
LogConfigIndent(LogConfigGlobal());
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
static const char *
|
static const char *
|
||||||
GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to);
|
GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to);
|
||||||
|
|
||||||
static void
|
static char *
|
||||||
JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name)
|
JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name)
|
||||||
{
|
{
|
||||||
char *sender = GrabString(event, 1, "sender");
|
char *sender = GrabString(event, 1, "sender");
|
||||||
|
|
@ -50,7 +50,7 @@ JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name)
|
||||||
|
|
||||||
ParseePushNickTable(muc, sender, nick);
|
ParseePushNickTable(muc, sender, nick);
|
||||||
Free(nick);
|
Free(nick);
|
||||||
Free(rev);
|
return (rev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -98,13 +98,71 @@ ParseeMemberHandler(ParseeData *data, HashMap *event)
|
||||||
{
|
{
|
||||||
char *muc = ParseeGetMUCID(data, chat_id);
|
char *muc = ParseeGetMUCID(data, chat_id);
|
||||||
char *name = ASGetName(data->config, room_id, state_key);
|
char *name = ASGetName(data->config, room_id, state_key);
|
||||||
|
char *avatar = ASGetAvatar(data->config, room_id, state_key);
|
||||||
|
char *jabber = JoinMUC(data, event, jid, muc, name);
|
||||||
|
|
||||||
JoinMUC(data, event, jid, muc, name);
|
Log(LOG_DEBUG, "MATRIX: Joining as '%s' (avatar=%s)", jabber, avatar);
|
||||||
|
|
||||||
|
Free(avatar);
|
||||||
|
Free(jabber);
|
||||||
Free(name);
|
Free(name);
|
||||||
Free(muc);
|
Free(muc);
|
||||||
|
|
||||||
/* TODO: XEP-0084 magic to advertise a new avatar if possible. */
|
/* TODO: XEP-0084 magic to advertise a new avatar if possible. */
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *avatar = ASGetAvatar(data->config, room_id, state_key);
|
||||||
|
char *sha = NULL, *mime = NULL, *url = NULL;
|
||||||
|
char *full_jid = StrConcat(3,
|
||||||
|
jid, "@", data->config->component_host
|
||||||
|
);
|
||||||
|
XMLElement *elem, *pevent, *items, *item, *meta, *info;
|
||||||
|
|
||||||
|
Log(LOG_DEBUG, "MATRIX: Got local user '%s'(mxid=%s avatar=%s)", jid, state_key, avatar);
|
||||||
|
|
||||||
|
url = ParseeToUnauth(data, avatar);
|
||||||
|
elem = XMLCreateTag("message");
|
||||||
|
ASGetMIMESHA(data->config, avatar, &mime, &sha);
|
||||||
|
{
|
||||||
|
#define PUBSUB "http://jabber.org/protocol/pubsub"
|
||||||
|
#define AVATAR "urn:xmpp:avatar:metadata"
|
||||||
|
pevent = XMLCreateTag("event");
|
||||||
|
XMLAddAttr(pevent, "xmlns", PUBSUB "#event");
|
||||||
|
{
|
||||||
|
items = XMLCreateTag("items");
|
||||||
|
item = XMLCreateTag("item");
|
||||||
|
XMLAddAttr(items, "node", AVATAR);
|
||||||
|
XMLAddAttr(item, "id", sha);
|
||||||
|
{
|
||||||
|
meta = XMLCreateTag("metadata");
|
||||||
|
info = XMLCreateTag("info");
|
||||||
|
XMLAddAttr(meta, "xmlns", AVATAR);
|
||||||
|
|
||||||
|
XMLAddAttr(info, "id", sha);
|
||||||
|
XMLAddAttr(info, "url", url);
|
||||||
|
XMLAddAttr(info, "type", mime);
|
||||||
|
|
||||||
|
XMLAddChild(meta, info);
|
||||||
|
XMLAddChild(item, meta);
|
||||||
|
}
|
||||||
|
XMLAddChild(items, item);
|
||||||
|
XMLAddChild(pevent, items);
|
||||||
|
}
|
||||||
|
XMLAddChild(elem, pevent);
|
||||||
|
#undef PUBSUB
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Broadcast PEP avatar change */
|
||||||
|
ParseeBroadcastStanza(data, full_jid, elem);
|
||||||
|
XMLFreeElement(elem);
|
||||||
|
|
||||||
|
Free(full_jid);
|
||||||
|
Free(avatar);
|
||||||
|
Free(mime);
|
||||||
|
Free(sha);
|
||||||
|
Free(url);
|
||||||
|
}
|
||||||
Free(jid);
|
Free(jid);
|
||||||
Free(chat_id);
|
Free(chat_id);
|
||||||
}
|
}
|
||||||
|
|
@ -263,7 +321,7 @@ GetXMPPInformation(ParseeData *data, HashMap *event, char **from, char **to)
|
||||||
}
|
}
|
||||||
|
|
||||||
matrix_name = ASGetName(data->config, room_id, matrix_sender);
|
matrix_name = ASGetName(data->config, room_id, matrix_sender);
|
||||||
JoinMUC(data, event, *from, muc_id, matrix_name);
|
Free(JoinMUC(data, event, *from, muc_id, matrix_name));
|
||||||
*to = muc_id;
|
*to = muc_id;
|
||||||
|
|
||||||
Free(matrix_name);
|
Free(matrix_name);
|
||||||
|
|
@ -350,12 +408,8 @@ ParseeMessageHandler(ParseeData *data, HashMap *event)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Check the name's validity.
|
|
||||||
* Is there a good way to check for that that isn't
|
|
||||||
* just "await on join and try again?" */
|
|
||||||
name = ASGetName(data->config, id, m_sender);
|
name = ASGetName(data->config, id, m_sender);
|
||||||
|
Free(JoinMUC(data, event, encoded_from, muc_id, name));
|
||||||
JoinMUC(data, event, encoded_from, muc_id, name);
|
|
||||||
|
|
||||||
to = muc_id;
|
to = muc_id;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ static bool
|
||||||
IsPubsubRequest(XMLElement *stanza)
|
IsPubsubRequest(XMLElement *stanza)
|
||||||
{
|
{
|
||||||
char *type = HashMapGet(stanza ? stanza->attrs : NULL, "type");
|
char *type = HashMapGet(stanza ? stanza->attrs : NULL, "type");
|
||||||
XMLElement *pubsub, *subscribe;
|
XMLElement *pubsub;
|
||||||
if (!stanza)
|
if (!stanza)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -58,7 +58,6 @@ IsPubsubRequest(XMLElement *stanza)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log(LOG_INFO, "WOAH");
|
|
||||||
return XMLookForUnique(pubsub, "subscribe");
|
return XMLookForUnique(pubsub, "subscribe");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,14 @@
|
||||||
#include "XMPPThread/internal.h"
|
#include "XMPPThread/internal.h"
|
||||||
|
|
||||||
|
#include <Cytoplasm/Memory.h>
|
||||||
|
#include <Cytoplasm/Base64.h>
|
||||||
|
#include <Cytoplasm/Json.h>
|
||||||
|
#include <Cytoplasm/Log.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
#include <Cytoplasm/Db.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
SubscriptionHash(ParseeData *data, char *from, char *to)
|
SubscriptionHash(ParseeData *data, char *from, char *to)
|
||||||
{
|
{
|
||||||
|
|
@ -10,14 +19,28 @@ SubscriptionHash(ParseeData *data, char *from, char *to)
|
||||||
len = strlen(from) + 1 + strlen(to);
|
len = strlen(from) + 1 + strlen(to);
|
||||||
sum = Malloc(len);
|
sum = Malloc(len);
|
||||||
memset(sum, 0x00, len);
|
memset(sum, 0x00, len);
|
||||||
memcpy(sum[0], from, strlen(from)):
|
memcpy(&sum[0], from, strlen(from));
|
||||||
memcpy(sum[strlen(from) + 1], to, strlen(to));
|
memcpy(&sum[strlen(from) + 1], to, strlen(to));
|
||||||
|
|
||||||
hash = ParseeHMAC(data->id, sum, len);
|
hash = Base64Encode(sum, len);
|
||||||
Free(sum);
|
Free(sum);
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
static void
|
||||||
|
DecodeSubscription(ParseeData *data, char *hash, char **from, char **to)
|
||||||
|
{
|
||||||
|
char *sum;
|
||||||
|
if (!data || !hash || !from || !to)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sum = Base64Decode(hash, strlen(hash));
|
||||||
|
*from = StrDuplicate(sum);
|
||||||
|
*to = StrDuplicate(sum + strlen(sum) + 1);
|
||||||
|
Free(sum);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AddPresenceSubscriber(ParseeData *data, char *from, char *to)
|
AddPresenceSubscriber(ParseeData *data, char *from, char *to)
|
||||||
|
|
@ -32,13 +55,18 @@ AddPresenceSubscriber(ParseeData *data, char *from, char *to)
|
||||||
|
|
||||||
database = data->db;
|
database = data->db;
|
||||||
hash = SubscriptionHash(data, from, to);
|
hash = SubscriptionHash(data, from, to);
|
||||||
ref = DbCreate(database, 2, "subscriptions", hash);
|
ref = DbCreate(database, 2, "subs", hash);
|
||||||
|
if (!ref)
|
||||||
|
{
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
HashMapSet(DbRef(ref), "from", JsonValueString(from));
|
HashMapSet(DbJson(ref), "from", JsonValueString(from));
|
||||||
HashMapSet(DbRef(ref), "to", JsonValueString(to));
|
HashMapSet(DbJson(ref), "to", JsonValueString(to));
|
||||||
/* I don't think we need more information right now */
|
/* I don't think we need more information right now */
|
||||||
|
|
||||||
DbClose(database, ref);
|
end:
|
||||||
|
DbUnlock(database, ref);
|
||||||
Free(hash);
|
Free(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,15 +76,73 @@ IsSubscribed(ParseeData *data, char *user, char *to)
|
||||||
Db *database;
|
Db *database;
|
||||||
char *hash;
|
char *hash;
|
||||||
bool ret;
|
bool ret;
|
||||||
if (!data || !from || !to)
|
if (!data || !user || !to)
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
database = data->db;
|
database = data->db;
|
||||||
hash = SubscriptionHash(data, from, to);
|
hash = SubscriptionHash(data, user, to);
|
||||||
ret = DbExists(database, 2, "subscriptions", hash);
|
ret = DbExists(database, 2, "subs", hash);
|
||||||
Free(hash);
|
Free(hash);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ParseeBroadcastStanza(ParseeData *data, char *from, XMLElement *stanza)
|
||||||
|
{
|
||||||
|
XMPPComponent *jabber = data ? data->jabber : NULL;
|
||||||
|
Array *entries;
|
||||||
|
size_t i;
|
||||||
|
if (!data || !from || !stanza)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy our stanza so that we can freely modify it */
|
||||||
|
stanza = XMLCopy(stanza);
|
||||||
|
|
||||||
|
/* Start doing a storm on Mt. Subs. */
|
||||||
|
entries = DbList(data->db, 1, "subs");
|
||||||
|
for (i = 0; i < ArraySize(entries); i++)
|
||||||
|
{
|
||||||
|
char *entry = ArrayGet(entries, i);
|
||||||
|
char *entry_from = NULL, *entry_to = NULL;
|
||||||
|
char *storm_id; /* ooe */
|
||||||
|
XMLElement *sub;
|
||||||
|
|
||||||
|
DecodeSubscription(data, entry, &entry_from, &entry_to);
|
||||||
|
|
||||||
|
if (!StrEquals(entry_to, from))
|
||||||
|
{
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(LOG_DEBUG,
|
||||||
|
"PRESENCE SYSTEM: "
|
||||||
|
"We should be brotkasting straight to %s (from %s)",
|
||||||
|
entry_from, from
|
||||||
|
);
|
||||||
|
sub = XMLCopy(stanza);
|
||||||
|
XMLAddAttr(sub, "from", from);
|
||||||
|
XMLAddAttr(sub, "to", entry_from);
|
||||||
|
|
||||||
|
/* TODO: Should we store IDs somewhere? */
|
||||||
|
XMLAddAttr(sub, "id", (storm_id = StrRandom(16)));
|
||||||
|
|
||||||
|
pthread_mutex_lock(&jabber->write_lock);
|
||||||
|
XMLEncode(jabber->stream, sub);
|
||||||
|
StreamFlush(jabber->stream);
|
||||||
|
pthread_mutex_unlock(&jabber->write_lock);
|
||||||
|
|
||||||
|
XMLFreeElement(sub);
|
||||||
|
Free(storm_id);
|
||||||
|
end:
|
||||||
|
Free(entry_from);
|
||||||
|
Free(entry_to);
|
||||||
|
}
|
||||||
|
DbListFree(entries);
|
||||||
|
XMLFreeElement(stanza);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -327,6 +327,7 @@ void
|
||||||
IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
||||||
{
|
{
|
||||||
XMPPComponent *jabber = args->jabber;
|
XMPPComponent *jabber = args->jabber;
|
||||||
|
XMLElement *pubsub;
|
||||||
char *from = HashMapGet(stanza->attrs, "from");
|
char *from = HashMapGet(stanza->attrs, "from");
|
||||||
char *to = HashMapGet(stanza->attrs, "to");
|
char *to = HashMapGet(stanza->attrs, "to");
|
||||||
char *id = HashMapGet(stanza->attrs, "id");
|
char *id = HashMapGet(stanza->attrs, "id");
|
||||||
|
|
@ -395,6 +396,68 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
||||||
XMLFreeElement(iqVCard);
|
XMLFreeElement(iqVCard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#define PS "http://jabber.org/protocol/pubsub"
|
||||||
|
else if ((pubsub = XMLookForTKV(stanza, "pubsub", "xmlns", PS)))
|
||||||
|
{
|
||||||
|
/* TODO: Pass this through the PEP manager */
|
||||||
|
XMLElement *a_items = XMLookForTKV(pubsub,
|
||||||
|
"items", "node", "urn:xmpp:avatar:data"
|
||||||
|
);
|
||||||
|
if (a_items)
|
||||||
|
{
|
||||||
|
/* Do, without regret, start shoving an avatar out the bus */
|
||||||
|
char *to_matrix = ParseeDecodeMXID(to);
|
||||||
|
char *avatar = ASGetAvatar(args->config, NULL, to_matrix);
|
||||||
|
char *buf, *mime;
|
||||||
|
char *b64;
|
||||||
|
size_t len;
|
||||||
|
XMLElement *reply;
|
||||||
|
|
||||||
|
ASGrab(args->config, avatar, &mime, &buf, &len);
|
||||||
|
b64 = Base64Encode(buf, len);
|
||||||
|
Free(buf);
|
||||||
|
|
||||||
|
Log(LOG_INFO, "FM=%s", to_matrix);
|
||||||
|
Log(LOG_INFO, "B=%s (%dB)", b64, (int) len);
|
||||||
|
/* Strike back with a response */
|
||||||
|
reply = XMLCreateTag("iq");
|
||||||
|
XMLAddAttr(reply, "type", "result");
|
||||||
|
XMLAddAttr(reply, "to", from);
|
||||||
|
XMLAddAttr(reply, "from", to);
|
||||||
|
XMLAddAttr(reply, "id", HashMapGet(stanza->attrs, "id"));
|
||||||
|
{
|
||||||
|
XMLElement *ps = XMLCreateTag("pubsub");
|
||||||
|
XMLElement *items = XMLCreateTag("items");
|
||||||
|
XMLAddAttr(ps, "xmlns", PS);
|
||||||
|
XMLAddAttr(items, "node", "urn:xmpp:avatar:data");
|
||||||
|
{
|
||||||
|
XMLElement *item = XMLCreateTag("item");
|
||||||
|
XMLElement *data = XMLCreateTag("data");
|
||||||
|
XMLAddAttr(item, "id", "TODO");
|
||||||
|
XMLAddAttr(data, "xmlns", "urn:xmpp:avatar:data");
|
||||||
|
|
||||||
|
XMLAddChild(data, XMLCreateText(b64));
|
||||||
|
|
||||||
|
XMLAddChild(item, data);
|
||||||
|
XMLAddChild(items, item);
|
||||||
|
}
|
||||||
|
XMLAddChild(ps, items);
|
||||||
|
XMLAddChild(reply, ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&jabber->write_lock);
|
||||||
|
XMLEncode(jabber->stream, reply);
|
||||||
|
StreamFlush(jabber->stream);
|
||||||
|
pthread_mutex_unlock(&jabber->write_lock);
|
||||||
|
XMLFreeElement(reply);
|
||||||
|
|
||||||
|
Free(to_matrix);
|
||||||
|
Free(avatar);
|
||||||
|
Free(mime);
|
||||||
|
Free(b64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#undef PS
|
||||||
else if (XMLookForTKV(stanza, "query", "xmlns", DISCO))
|
else if (XMLookForTKV(stanza, "query", "xmlns", DISCO))
|
||||||
{
|
{
|
||||||
IQDiscoGet(args, jabber, stanza);
|
IQDiscoGet(args, jabber, stanza);
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,17 @@ MessageStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
||||||
Log(LOG_DEBUG, "<message/> usage=%d (%s:%d)", MemoryAllocated(), __FILE__, __LINE__);
|
Log(LOG_DEBUG, "<message/> usage=%d (%s:%d)", MemoryAllocated(), __FILE__, __LINE__);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
/*{
|
||||||
|
XMLElement *foo = XMLCreateTag("message");
|
||||||
|
XMLElement *body = XMLCreateTag("body");
|
||||||
|
XMLAddAttr(foo, "type", "chat");
|
||||||
|
XMLAddChild(foo, body);
|
||||||
|
XMLAddChild(body, XMLCreateText("Storm on Mt. Ooe (sorry if you see this)"));
|
||||||
|
|
||||||
|
BroadcastStanza(args, HashMapGet(stanza->attrs, "to"), foo);
|
||||||
|
XMLFreeElement(foo);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
if (ServerHasXEP421(args, from))
|
if (ServerHasXEP421(args, from))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,14 @@ extern void ASSetStatus(const ParseeConfig *c, char *user, UserStatus status, ch
|
||||||
* Modifies: NOTHING */
|
* Modifies: NOTHING */
|
||||||
extern char * ASGetName(const ParseeConfig *c, char *room, char *user);
|
extern char * ASGetName(const ParseeConfig *c, char *room, char *user);
|
||||||
|
|
||||||
|
/** Returns the user's avatar in a room, or a the global user avatar, to be
|
||||||
|
* Free'd
|
||||||
|
* -------------
|
||||||
|
* Returns: The user's name in the [HEAP] | NULL
|
||||||
|
* Thrasher: Free
|
||||||
|
* Modifies: NOTHING */
|
||||||
|
extern char * ASGetAvatar(const ParseeConfig *c, char *room, char *user);
|
||||||
|
|
||||||
/** Uploads data to Matrix to be used later
|
/** Uploads data to Matrix to be used later
|
||||||
* ----------------
|
* ----------------
|
||||||
* Returns: A valid MXC URI[HEAP] | NULL
|
* Returns: A valid MXC URI[HEAP] | NULL
|
||||||
|
|
@ -170,4 +178,16 @@ extern Array * ASGetRelations(const ParseeConfig *c, size_t n, char *room, char
|
||||||
* Thrashes: {relations}
|
* Thrashes: {relations}
|
||||||
* See-Also: ASGetRelations */
|
* See-Also: ASGetRelations */
|
||||||
extern void ASFreeRelations(Array *relations);
|
extern void ASFreeRelations(Array *relations);
|
||||||
|
|
||||||
|
/** Returns the MIME and SHA-1 hash of a media entry, in one fell swoop.
|
||||||
|
* -----------------
|
||||||
|
* Returns: whenever the media exists
|
||||||
|
* Modifies: {mime}[HEAP], {sha}[HEAP] */
|
||||||
|
extern bool ASGetMIMESHA(const ParseeConfig *c, char *mxc, char **mime, char **sha);
|
||||||
|
|
||||||
|
/** Retrieves media off an MXC link.
|
||||||
|
* ------------
|
||||||
|
* Returns: whenever the media exists
|
||||||
|
* Modifies {mime}[HEAP], {out}[HEAP], {len} */
|
||||||
|
extern bool ASGrab(const ParseeConfig *c, char *mxc, char **mime, char **out, size_t *len);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -401,4 +401,10 @@ extern void ParseeSetThreads(int xmpp, int http);
|
||||||
extern char * ParseeHMAC(char *key, uint8_t *msg, size_t msglen);
|
extern char * ParseeHMAC(char *key, uint8_t *msg, size_t msglen);
|
||||||
#define ParseeHMACS(key, msg) ParseeHMAC(key, (uint8_t *) msg, strlen(msg))
|
#define ParseeHMACS(key, msg) ParseeHMAC(key, (uint8_t *) msg, strlen(msg))
|
||||||
|
|
||||||
|
/** Broadcasts a stanza from a user to any that may be interested by it
|
||||||
|
* (PEP or subscription)
|
||||||
|
* -------------------------------------
|
||||||
|
* Returns: NOTHING */
|
||||||
|
extern void ParseeBroadcastStanza(ParseeData *data, char *from, XMLElement *s);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ ParseAyadoc(char *raw)
|
||||||
if (parsing_notes)
|
if (parsing_notes)
|
||||||
{
|
{
|
||||||
char *del = strchr(line_content, ':');
|
char *del = strchr(line_content, ':');
|
||||||
char *val = del + 1;
|
char *val = del ? del + 1 : NULL;
|
||||||
if (del && strlen(del) >= 1)
|
if (del && strlen(del) >= 1)
|
||||||
{
|
{
|
||||||
while (*val && isspace(*val))
|
while (*val && isspace(*val))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue