mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-13 12:15:12 +00:00
[WIP/ADD] Try to separate discovery, make links nicer
This commit is contained in:
parent
2e566c73fc
commit
5ddc5d3e5c
15 changed files with 409 additions and 118 deletions
71
configure.c
71
configure.c
|
|
@ -90,22 +90,6 @@ string_cat(char *in1, char *in2)
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
static char *
|
|
||||||
trim_nl(char *in)
|
|
||||||
{
|
|
||||||
char *tc;
|
|
||||||
if (!in)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((tc = strrchr(in, '\n')))
|
|
||||||
{
|
|
||||||
*tc = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct str_array {
|
typedef struct str_array {
|
||||||
char **values;
|
char **values;
|
||||||
|
|
@ -115,6 +99,10 @@ static str_array_t *
|
||||||
str_array_create(void)
|
str_array_create(void)
|
||||||
{
|
{
|
||||||
str_array_t *ret = malloc(sizeof(*ret));
|
str_array_t *ret = malloc(sizeof(*ret));
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
ret->values = NULL;
|
ret->values = NULL;
|
||||||
ret->quantity = 0;
|
ret->quantity = 0;
|
||||||
|
|
@ -216,36 +204,6 @@ failure:
|
||||||
free(line);
|
free(line);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
static int
|
|
||||||
exec_code(char *program, char *argv[])
|
|
||||||
{
|
|
||||||
pid_t forkRet;
|
|
||||||
if (!program || !argv)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
forkRet = fork();
|
|
||||||
if (forkRet == 0)
|
|
||||||
{
|
|
||||||
/* Child */
|
|
||||||
execvp(program, argv);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Parent */
|
|
||||||
int status;
|
|
||||||
if (waitpid(forkRet, &status, 0) == -1)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We're not meant to ever be there, but TCC is stupid. */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
strchrn(char *s, char c)
|
strchrn(char *s, char c)
|
||||||
|
|
@ -253,17 +211,6 @@ strchrn(char *s, char c)
|
||||||
s = strchr(s, c);
|
s = strchr(s, c);
|
||||||
return s ? s+1 : NULL;
|
return s ? s+1 : NULL;
|
||||||
}
|
}
|
||||||
static char *
|
|
||||||
strchrl(char *s, char c)
|
|
||||||
{
|
|
||||||
char *s1 = NULL;
|
|
||||||
while ((s = strchr(s, c)))
|
|
||||||
{
|
|
||||||
s1 = s;
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
return s1;
|
|
||||||
}
|
|
||||||
static str_array_t *
|
static str_array_t *
|
||||||
split(char *dir)
|
split(char *dir)
|
||||||
{
|
{
|
||||||
|
|
@ -512,8 +459,7 @@ main_build(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
FILE *makefile;
|
FILE *makefile;
|
||||||
char *repo = cmd_stdout("git remote get-url origin");
|
char *repo = cmd_stdout("git remote get-url origin");
|
||||||
size_t size, i;
|
size_t i;
|
||||||
ssize_t nread;
|
|
||||||
bool with_static = false, with_lmdb = false;
|
bool with_static = false, with_lmdb = false;
|
||||||
int opt;
|
int opt;
|
||||||
str_array_t *sources, *images, *utils, *aya;
|
str_array_t *sources, *images, *utils, *aya;
|
||||||
|
|
@ -546,6 +492,13 @@ main_build(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
makefile = fopen("Makefile", "w");
|
makefile = fopen("Makefile", "w");
|
||||||
|
if (!makefile)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Couldn't create Makefile.\n");
|
||||||
|
fprintf(stderr, "This isn't good, actually.\n");
|
||||||
|
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
fprintf(makefile, "# Autogenerated POSIX Makefile from Parsee\n");
|
fprintf(makefile, "# Autogenerated POSIX Makefile from Parsee\n");
|
||||||
fprintf(makefile, "# Ideally do not touch, unless you have a very ");
|
fprintf(makefile, "# Ideally do not touch, unless you have a very ");
|
||||||
fprintf(makefile, "good reason to do it. \n\n");
|
fprintf(makefile, "good reason to do it. \n\n");
|
||||||
|
|
|
||||||
|
|
@ -72,12 +72,13 @@ ParseeCheckMatrix(void *datp)
|
||||||
Log(LOG_ERR, "Please check if your homeserver is active.");
|
Log(LOG_ERR, "Please check if your homeserver is active.");
|
||||||
Log(LOG_ERR, "%s shall now exit...", NAME);
|
Log(LOG_ERR, "%s shall now exit...", NAME);
|
||||||
|
|
||||||
|
/* TODO: SEGV! */
|
||||||
pthread_mutex_lock(&data->halt_lock);
|
pthread_mutex_lock(&data->halt_lock);
|
||||||
data->halted = true;
|
data->halted = true;
|
||||||
pthread_mutex_unlock(&data->halt_lock);
|
pthread_mutex_unlock(&data->halt_lock);
|
||||||
|
|
||||||
XMPPFinishCompStream(data->jabber);
|
XMPPFinishCompStream(data->jabber);
|
||||||
pthread_join(xmpp_thr, NULL);
|
//pthread_join(xmpp_thr, NULL);
|
||||||
Log(LOG_INFO, "Stopping server...");
|
Log(LOG_INFO, "Stopping server...");
|
||||||
HttpServerStop(data->server);
|
HttpServerStop(data->server);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
#include <Matrix.h>
|
#include <Matrix.h>
|
||||||
|
|
||||||
#include <Cytoplasm/Memory.h>
|
#include <Cytoplasm/Memory.h>
|
||||||
|
#include <Cytoplasm/Http.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
#include <Cytoplasm/Log.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
@ -32,3 +35,34 @@ MatrixParseID(char *user)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
UserID *
|
||||||
|
MatrixParseIDFromMTO(Uri *uri)
|
||||||
|
{
|
||||||
|
UserID *id = NULL;
|
||||||
|
char *path, *params, *decoded;
|
||||||
|
if (!uri)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!StrEquals(uri->proto, "https") || !StrEquals(uri->host, "matrix.to"))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (strncmp(uri->path, "/#/", 3))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
path = StrDuplicate(uri->path + 3);
|
||||||
|
params = path ? strchr(path, '?') : NULL;
|
||||||
|
if (params)
|
||||||
|
{
|
||||||
|
*params = '\0';
|
||||||
|
}
|
||||||
|
decoded = HttpUrlDecode(path);
|
||||||
|
id = MatrixParseID(decoded);
|
||||||
|
Free(decoded);
|
||||||
|
Free(path);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ ParseeInitData(XMPPComponent *comp)
|
||||||
data->config = ParseeConfigGet();
|
data->config = ParseeConfigGet();
|
||||||
data->router = HttpRouterCreate();
|
data->router = HttpRouterCreate();
|
||||||
data->jabber = comp;
|
data->jabber = comp;
|
||||||
|
data->muc = CreateMUCServer(data);
|
||||||
data->handler = CommandCreateRouter();
|
data->handler = CommandCreateRouter();
|
||||||
|
|
||||||
data->oid_servers = HashMapCreate();
|
data->oid_servers = HashMapCreate();
|
||||||
|
|
@ -116,6 +117,7 @@ ParseeFreeData(ParseeData *data)
|
||||||
pthread_mutex_destroy(&data->halt_lock);
|
pthread_mutex_destroy(&data->halt_lock);
|
||||||
Free(data->id);
|
Free(data->id);
|
||||||
XMPPEndCompStream(data->jabber);
|
XMPPEndCompStream(data->jabber);
|
||||||
|
FreeMUCServer(data->muc);
|
||||||
DbClose(data->db);
|
DbClose(data->db);
|
||||||
HttpRouterFree(data->router);
|
HttpRouterFree(data->router);
|
||||||
CommandFreeRouter(data->handler);
|
CommandFreeRouter(data->handler);
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@
|
||||||
#include <Cytoplasm/Http.h>
|
#include <Cytoplasm/Http.h>
|
||||||
#include <Cytoplasm/Json.h>
|
#include <Cytoplasm/Json.h>
|
||||||
#include <Cytoplasm/Str.h>
|
#include <Cytoplasm/Str.h>
|
||||||
|
#include <Cytoplasm/Uri.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <StringStream.h>
|
#include <StringStream.h>
|
||||||
|
#include <Matrix.h>
|
||||||
#include <XML.h>
|
#include <XML.h>
|
||||||
#include <AS.h>
|
#include <AS.h>
|
||||||
|
|
||||||
|
|
@ -151,20 +153,42 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags)
|
||||||
else if (StrEquals(elem->name, "a"))
|
else if (StrEquals(elem->name, "a"))
|
||||||
{
|
{
|
||||||
char *href = HashMapGet(elem->attrs, "href");
|
char *href = HashMapGet(elem->attrs, "href");
|
||||||
/* TODO: Check if the element here is a Matrix.TO
|
Uri *pref = UriParse(href);
|
||||||
* pointing to a Parsee user. */
|
if (StrEquals(pref->host, "matrix.to"))
|
||||||
Concat("(");
|
|
||||||
for (i = 0; i < ArraySize(elem->children); i++)
|
|
||||||
{
|
{
|
||||||
child = ArrayGet(elem->children, i);
|
/* TODO: Check if the element here is a Matrix.TO
|
||||||
subxep = XMPPifyElement(event, child, flags);
|
* pointing to a Parsee user. */
|
||||||
|
UserID *id = MatrixParseIDFromMTO(pref);
|
||||||
|
if (id)
|
||||||
|
{
|
||||||
|
/* TODO: Detect if it already is a Parsee user */
|
||||||
|
Concat("@");
|
||||||
|
Concat(id->localpart);
|
||||||
|
Concat(":");
|
||||||
|
Concat(id->server);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Concat(href);
|
||||||
|
}
|
||||||
|
|
||||||
Concat(subxep);
|
Free(id);
|
||||||
Free(subxep);
|
|
||||||
}
|
}
|
||||||
Concat(" points to ");
|
else
|
||||||
Concat(href);
|
{
|
||||||
Concat(" )");
|
for (i = 0; i < ArraySize(elem->children); i++)
|
||||||
|
{
|
||||||
|
child = ArrayGet(elem->children, i);
|
||||||
|
subxep = XMPPifyElement(event, child, flags);
|
||||||
|
|
||||||
|
Concat(subxep);
|
||||||
|
Free(subxep);
|
||||||
|
}
|
||||||
|
Concat(" < ");
|
||||||
|
Concat(href);
|
||||||
|
Concat(" >");
|
||||||
|
}
|
||||||
|
UriFree(pref);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,37 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
static HttpClientContext *
|
||||||
|
TryDownload(ParseeData *data, char *server, char *identi)
|
||||||
|
{
|
||||||
|
HttpClientContext *cctx;
|
||||||
|
char *path;
|
||||||
|
server = HttpUrlEncode(server);
|
||||||
|
identi = HttpUrlEncode(identi);
|
||||||
|
|
||||||
|
path = StrConcat(4, "/_matrix/media/v3/download/", server, "/", identi);
|
||||||
|
cctx = ParseeCreateRequest(data->config, HTTP_GET, path);
|
||||||
|
ASAuthenticateRequest(data->config, cctx);
|
||||||
|
Free(path);
|
||||||
|
|
||||||
|
HttpRequestSendHeaders(cctx);
|
||||||
|
if (HttpRequestSend(cctx) != HTTP_OK)
|
||||||
|
{
|
||||||
|
Log(LOG_WARNING, "Failing back.");
|
||||||
|
HttpClientContextFree(cctx);
|
||||||
|
path = StrConcat(4, "/_matrix/client/v1/media/download/", server, "/", identi);
|
||||||
|
cctx = ParseeCreateRequest(data->config, HTTP_GET, path);
|
||||||
|
ASAuthenticateRequest(data->config, cctx);
|
||||||
|
Free(path);
|
||||||
|
HttpRequestSendHeaders(cctx);
|
||||||
|
HttpRequestSend(cctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
Free(server);
|
||||||
|
Free(identi);
|
||||||
|
return cctx;
|
||||||
|
}
|
||||||
|
|
||||||
RouteHead(RouteMedia, arr, argp)
|
RouteHead(RouteMedia, arr, argp)
|
||||||
{
|
{
|
||||||
ParseeHttpArg *args = argp;
|
ParseeHttpArg *args = argp;
|
||||||
|
|
@ -44,15 +75,7 @@ RouteHead(RouteMedia, arr, argp)
|
||||||
|
|
||||||
/* Proxy the media through an authenticated endpoint if the HMAC
|
/* Proxy the media through an authenticated endpoint if the HMAC
|
||||||
* is valid. */
|
* is valid. */
|
||||||
server = HttpUrlEncode(server);
|
cctx = TryDownload(args->data, server, identi);
|
||||||
identi = HttpUrlEncode(identi);
|
|
||||||
path = StrConcat(4, "/_matrix/media/v3/download/", server, "/", identi);
|
|
||||||
cctx = ParseeCreateRequest(args->data->config, HTTP_GET, path);
|
|
||||||
ASAuthenticateRequest(args->data->config, cctx);
|
|
||||||
Free(path);
|
|
||||||
|
|
||||||
HttpRequestSendHeaders(cctx);
|
|
||||||
HttpRequestSend(cctx);
|
|
||||||
reqh = HttpResponseHeaders(cctx);
|
reqh = HttpResponseHeaders(cctx);
|
||||||
while (HashMapIterate(reqh, &key, (void **) &val))
|
while (HashMapIterate(reqh, &key, (void **) &val))
|
||||||
{
|
{
|
||||||
|
|
@ -65,8 +88,6 @@ RouteHead(RouteMedia, arr, argp)
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpClientContextFree(cctx);
|
HttpClientContextFree(cctx);
|
||||||
Free(server);
|
|
||||||
Free(identi);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ XMPPJoinMUC(XMPPComponent *comp, char *fr, char *muc, char *hash, int time, bool
|
||||||
XMLAddChild(x, history);
|
XMLAddChild(x, history);
|
||||||
|
|
||||||
XMLAddChild(presence, x);
|
XMLAddChild(presence, x);
|
||||||
features = CreateIQFeatures();
|
features = LookupJIDFeatures(from);
|
||||||
#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name);
|
#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name);
|
||||||
IQ_IDENTITY
|
IQ_IDENTITY
|
||||||
#undef IdentitySimple
|
#undef IdentitySimple
|
||||||
|
|
@ -258,7 +258,7 @@ XMPPLeaveMUC(XMPPComponent *comp, char *fr, char *muc, char *reason)
|
||||||
XMLAddChild(presence, status);
|
XMLAddChild(presence, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
features = CreateIQFeatures();
|
features = LookupJIDFeatures(from);
|
||||||
#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name);
|
#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name);
|
||||||
IQ_IDENTITY
|
IQ_IDENTITY
|
||||||
#undef IdentitySimple
|
#undef IdentitySimple
|
||||||
|
|
|
||||||
153
src/XMPP/MUCServ.c
Normal file
153
src/XMPP/MUCServ.c
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
#include <MUCServ.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm/Memory.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
#include <Cytoplasm/Log.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MUCNS "http://jabber.org/protocol/muc"
|
||||||
|
|
||||||
|
struct MUCServer {
|
||||||
|
pthread_mutex_t mut;
|
||||||
|
|
||||||
|
ParseeData *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *
|
||||||
|
GetMUCName(char *jid)
|
||||||
|
{
|
||||||
|
char *name, *at;
|
||||||
|
size_t len;
|
||||||
|
if (!jid || *jid != '#')
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jid++;
|
||||||
|
|
||||||
|
at = strchr(jid, '@');
|
||||||
|
if (!at)
|
||||||
|
{
|
||||||
|
return StrDuplicate(jid);
|
||||||
|
}
|
||||||
|
len = at - jid;
|
||||||
|
name = Malloc(len + 1);
|
||||||
|
memset(name, '\0', len + 1);
|
||||||
|
memcpy(name, jid, len);
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUCServer *
|
||||||
|
CreateMUCServer(ParseeData *data)
|
||||||
|
{
|
||||||
|
MUCServer *server;
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
server = Malloc(sizeof(*server));
|
||||||
|
pthread_mutex_init(&server->mut, NULL);
|
||||||
|
server->data = data;
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
MUCManagePresence(MUCServer *serv, XMLElement *stanza, char *from, char *to)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
XMLElement *x = XMLookForTKV(stanza, "x", "xmlns", MUCNS);
|
||||||
|
char *type = HashMapGet(stanza->attrs, "type");
|
||||||
|
if (x && !type)
|
||||||
|
{
|
||||||
|
/* The user is trying to join the MUC */
|
||||||
|
name = GetMUCName(to);
|
||||||
|
Log(LOG_WARNING, "%s is trying to join MUC '%s'", from, name);
|
||||||
|
|
||||||
|
/* TODO: Check if the user should be joining. If so, make them.
|
||||||
|
* Implementing MUCs is gonna be fun. */
|
||||||
|
|
||||||
|
/* TODO: Presence broadcast hell. */
|
||||||
|
Free(name);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
MUCManageMessage(MUCServer *serv, XMLElement *stanza, char *from, char *to)
|
||||||
|
{
|
||||||
|
Log(LOG_WARNING, "MUCSERV: got a message %s->%s", from, to);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ManageMUCStanza(MUCServer *serv, XMLElement *stanza)
|
||||||
|
{
|
||||||
|
char *stype, *from, *to;
|
||||||
|
bool ret;
|
||||||
|
if (!serv || !stanza)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
from = HashMapGet(stanza->attrs, "from");
|
||||||
|
to = HashMapGet(stanza->attrs, "to");
|
||||||
|
stype = stanza->name;
|
||||||
|
|
||||||
|
if (to && *to != '#')
|
||||||
|
{
|
||||||
|
/* We aren't interacting with a MUC at all. Don't do anything. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (StrEquals(stype, "iq"))
|
||||||
|
{
|
||||||
|
/* TODO: Worry about IQ later */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = false;
|
||||||
|
pthread_mutex_lock(&serv->mut);
|
||||||
|
if (StrEquals(stype, "presence"))
|
||||||
|
{
|
||||||
|
ret = MUCManagePresence(serv, stanza, from, to);
|
||||||
|
}
|
||||||
|
else if (StrEquals(stype, "message"))
|
||||||
|
{
|
||||||
|
ret = MUCManageMessage(serv, stanza, from, to);
|
||||||
|
}
|
||||||
|
/* TODO: Do stuff while locked */
|
||||||
|
pthread_mutex_unlock(&serv->mut);
|
||||||
|
|
||||||
|
/* TODO: Verify the destination, and make sure we aren't doing
|
||||||
|
* anything stupid(especially with discovery) */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MUCServerExists(MUCServer *serv, char *muc)
|
||||||
|
{
|
||||||
|
if (!serv || !muc)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FreeMUCServer(MUCServer *serv)
|
||||||
|
{
|
||||||
|
if (!serv)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&serv->mut);
|
||||||
|
/* TODO */
|
||||||
|
pthread_mutex_unlock(&serv->mut);
|
||||||
|
pthread_mutex_destroy(&serv->mut);
|
||||||
|
Free(serv);
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include <Cytoplasm/Util.h>
|
#include <Cytoplasm/Util.h>
|
||||||
#include <Cytoplasm/Str.h>
|
#include <Cytoplasm/Str.h>
|
||||||
#include <Cytoplasm/Sha.h>
|
#include <Cytoplasm/Sha.h>
|
||||||
|
#include <Cytoplasm/Log.h>
|
||||||
|
|
||||||
#include <StringStream.h>
|
#include <StringStream.h>
|
||||||
#include <XMPPCommand.h>
|
#include <XMPPCommand.h>
|
||||||
|
|
@ -142,3 +143,39 @@ XMPPAnnotatePresence(XMLElement *presence, IQFeatures *features)
|
||||||
XMLAddChild(presence, c);
|
XMLAddChild(presence, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IQFeatures *
|
||||||
|
LookupJIDFeatures(char *jid)
|
||||||
|
{
|
||||||
|
IQFeatures *features;
|
||||||
|
if (!jid)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
features = CreateIQFeatures();
|
||||||
|
|
||||||
|
if (*jid == '#')
|
||||||
|
{
|
||||||
|
/* This is a MUC. As such, we need to advertise MUCs */
|
||||||
|
#define ID(...) AddIQIdentity(features, __VA_ARGS__)
|
||||||
|
#define AD(var) AdvertiseIQFeature(features, var)
|
||||||
|
ID("gateway", NULL, "matrix", "Parsee MUC gateway");
|
||||||
|
ID("conference", NULL, "text", "Parsee MUC gateway");
|
||||||
|
ID("component", NULL, "generic", "Parsee component");
|
||||||
|
|
||||||
|
AD("http://jabber.org/protocol/muc");
|
||||||
|
#undef AD
|
||||||
|
#undef ID
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name);
|
||||||
|
IQ_IDENTITY
|
||||||
|
#undef IdentitySimple
|
||||||
|
#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature);
|
||||||
|
IQ_ADVERT
|
||||||
|
#undef AdvertiseSimple
|
||||||
|
}
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,12 @@ XMPPDispatcher(void *argp)
|
||||||
Log(LOG_DEBUG, "Received stanza='%s'.", stanza->name);
|
Log(LOG_DEBUG, "Received stanza='%s'.", stanza->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ManageMUCStanza(args->muc, stanza))
|
||||||
|
{
|
||||||
|
XMLFreeElement(stanza);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (StrEquals(stanza->name, "presence"))
|
if (StrEquals(stanza->name, "presence"))
|
||||||
{
|
{
|
||||||
PresenceStanza(args, stanza, thread);
|
PresenceStanza(args, stanza, thread);
|
||||||
|
|
|
||||||
|
|
@ -115,33 +115,37 @@ end:
|
||||||
|
|
||||||
#define DISCO "http://jabber.org/protocol/disco#info"
|
#define DISCO "http://jabber.org/protocol/disco#info"
|
||||||
static XMLElement *
|
static XMLElement *
|
||||||
IQGenerateQuery(void)
|
IQGenerateQuery(IQFeatures *features)
|
||||||
{
|
{
|
||||||
XMLElement *query = XMLCreateTag("query");
|
XMLElement *query;
|
||||||
|
if (!features)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
query = XMLCreateTag("query");
|
||||||
XMLAddAttr(query, "xmlns", DISCO);
|
XMLAddAttr(query, "xmlns", DISCO);
|
||||||
{
|
{
|
||||||
XMLElement *feature;
|
XMLElement *feature;
|
||||||
#define IdentitySimple(c,t,n) do \
|
size_t i;
|
||||||
{ \
|
for (i = 0; i < ArraySize(features->identity); i++)
|
||||||
feature = XMLCreateTag("identity"); \
|
{
|
||||||
XMLAddAttr(feature, "category", c); \
|
XMPPIdentity *identity = ArrayGet(features->identity, i);
|
||||||
XMLAddAttr(feature, "type", t); \
|
|
||||||
XMLAddAttr(feature, "name", n); \
|
|
||||||
XMLAddChild(query, feature); \
|
|
||||||
} \
|
|
||||||
while (0);
|
|
||||||
IQ_IDENTITY
|
|
||||||
#undef IdentitySimple
|
|
||||||
#define AdvertiseSimple(f) do \
|
|
||||||
{ \
|
|
||||||
feature = XMLCreateTag("feature"); \
|
|
||||||
XMLAddAttr(feature, "var", f); \
|
|
||||||
XMLAddChild(query, feature); \
|
|
||||||
} \
|
|
||||||
while (0);
|
|
||||||
|
|
||||||
IQ_ADVERT
|
feature = XMLCreateTag("identity");
|
||||||
#undef AdvertiseSimple
|
XMLAddAttr(feature, "category", identity->category);
|
||||||
|
XMLAddAttr(feature, "type", identity->type);
|
||||||
|
XMLAddAttr(feature, "name", identity->name);
|
||||||
|
|
||||||
|
XMLAddChild(query, feature);
|
||||||
|
}
|
||||||
|
for (i = 0; i < ArraySize(features->adverts); i++)
|
||||||
|
{
|
||||||
|
char *var = ArrayGet(features->adverts, i);
|
||||||
|
|
||||||
|
feature = XMLCreateTag("feature");
|
||||||
|
XMLAddAttr(feature, "var", var);
|
||||||
|
XMLAddChild(query, feature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
|
|
@ -151,7 +155,7 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza)
|
||||||
{
|
{
|
||||||
char *from, *to, *id;
|
char *from, *to, *id;
|
||||||
XMLElement *iq_reply, *query;
|
XMLElement *iq_reply, *query;
|
||||||
IQFeatures *features = CreateIQFeatures();
|
IQFeatures *features;
|
||||||
|
|
||||||
from = HashMapGet(stanza->attrs, "from");
|
from = HashMapGet(stanza->attrs, "from");
|
||||||
to = HashMapGet(stanza->attrs, "to");
|
to = HashMapGet(stanza->attrs, "to");
|
||||||
|
|
@ -164,13 +168,8 @@ IQDiscoGet(ParseeData *args, XMPPComponent *jabber, XMLElement *stanza)
|
||||||
XMLAddAttr(iq_reply, "type", "result");
|
XMLAddAttr(iq_reply, "type", "result");
|
||||||
XMLAddAttr(iq_reply, "id", id);
|
XMLAddAttr(iq_reply, "id", id);
|
||||||
|
|
||||||
query = IQGenerateQuery();
|
features = LookupJIDFeatures(to);
|
||||||
#define IdentitySimple(cat, Type, Name) AddIQIdentity(features, cat, NULL, Type, Name);
|
query = IQGenerateQuery(features);
|
||||||
IQ_IDENTITY
|
|
||||||
#undef IdentitySimple
|
|
||||||
#define AdvertiseSimple(feature) AdvertiseIQFeature(features, feature);
|
|
||||||
IQ_ADVERT
|
|
||||||
#undef AdvertiseSimple
|
|
||||||
{
|
{
|
||||||
char *ver = XMPPGenerateVer(features);
|
char *ver = XMPPGenerateVer(features);
|
||||||
char *node = StrConcat(3, REPOSITORY, "#", ver);
|
char *node = StrConcat(3, REPOSITORY, "#", ver);
|
||||||
|
|
@ -599,10 +598,14 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
char *buf = NULL;
|
||||||
|
Stream *s = StrStreamWriter(&buf);
|
||||||
Log(LOG_WARNING, "Unknown I/Q received:");
|
Log(LOG_WARNING, "Unknown I/Q received:");
|
||||||
XMLEncode(StreamStdout(), stanza);
|
XMLEncode(s, stanza);
|
||||||
StreamPrintf(StreamStdout(),"\n");
|
StreamFlush(s);
|
||||||
StreamFlush(StreamStdout());
|
StreamClose(s);
|
||||||
|
Log(LOG_WARNING, "%s", buf);
|
||||||
|
Free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,14 @@ void AddIQIdentity(IQFeatures *, char *category, char *lang, char *type, char *n
|
||||||
void AdvertiseIQFeature(IQFeatures *, char *feature);
|
void AdvertiseIQFeature(IQFeatures *, char *feature);
|
||||||
void FreeIQFeatures(IQFeatures *);
|
void FreeIQFeatures(IQFeatures *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks up the features supported by a JID
|
||||||
|
* ----------------------
|
||||||
|
* Returns: an IQ featureset[LA:HEAP] | NULL
|
||||||
|
* Thrasher: FreeIQFeatures
|
||||||
|
* Modifies: NOTHING */
|
||||||
|
IQFeatures * LookupJIDFeatures(char *jid);
|
||||||
|
|
||||||
/** Generate the B64-encoded SHA-256 hash for the 'ver' field in caps.
|
/** Generate the B64-encoded SHA-256 hash for the 'ver' field in caps.
|
||||||
* --------
|
* --------
|
||||||
* Returns: A base64 encoded ver hash[LA:HEAP]
|
* Returns: A base64 encoded ver hash[LA:HEAP]
|
||||||
|
|
|
||||||
39
src/include/MUCServ.h
Normal file
39
src/include/MUCServ.h
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef PARSEE_MUCSERV_H
|
||||||
|
#define PARSEE_MUCSERV_H
|
||||||
|
|
||||||
|
/*-* An easy interface for handling MUCs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct MUCServer MUCServer;
|
||||||
|
|
||||||
|
#include <Parsee.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/** Creates a MUC server handle given a ParseeData handle.
|
||||||
|
* This handle shall be used for all MUC-related operations.
|
||||||
|
* ----------------------------------------------------------
|
||||||
|
* Returns: a MUC server handle[HEAP] | NULL
|
||||||
|
* Thrasher: FreeMUCServer
|
||||||
|
* See-Also: https://xmpp.org/extensions/xep-0045.html */
|
||||||
|
extern MUCServer * CreateMUCServer(ParseeData *data);
|
||||||
|
|
||||||
|
/** Manages a stanza from a MUC, and returns true if the stanza
|
||||||
|
* was actually processed by the MUC server.
|
||||||
|
* -------------------------------------------------------------
|
||||||
|
* See-Also: CreateMUCServer */
|
||||||
|
extern bool ManageMUCStanza(MUCServer *serv, XMLElement *stanza);
|
||||||
|
|
||||||
|
/** Checks if a MUC(from its localpart, so
|
||||||
|
* <code>'#foobar@bridge.blow.hole' -> 'foobar'</code>) exists.
|
||||||
|
* --------------
|
||||||
|
* Returns: whenever the MUC exists */
|
||||||
|
extern bool MUCServerExists(MUCServer *serv, char *muc);
|
||||||
|
|
||||||
|
/** Destroys all memory and references from a MUC server handle.
|
||||||
|
* --------------
|
||||||
|
* Thrashes: CreateMUCServer
|
||||||
|
* See-Also: https://xmpp.org/extensions/xep-0045.html */
|
||||||
|
extern void FreeMUCServer(MUCServer *serv);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#define PARSEE_MATRIX_H
|
#define PARSEE_MATRIX_H
|
||||||
|
|
||||||
#include <Cytoplasm/Json.h>
|
#include <Cytoplasm/Json.h>
|
||||||
|
#include <Cytoplasm/Uri.h>
|
||||||
|
|
||||||
#include "FileInfo.h"
|
#include "FileInfo.h"
|
||||||
|
|
||||||
|
|
@ -20,6 +21,12 @@ typedef struct UserID {
|
||||||
* Thrasher: Free */
|
* Thrasher: Free */
|
||||||
extern UserID * MatrixParseID(char *user);
|
extern UserID * MatrixParseID(char *user);
|
||||||
|
|
||||||
|
/** Attempts to parse a Matrix ID from a matrix.to URL.
|
||||||
|
* -------------------------------------------------
|
||||||
|
* Returns: a valid user ID[HEAP] | NULL
|
||||||
|
* Thrasher: Free */
|
||||||
|
extern UserID * MatrixParseIDFromMTO(Uri *uri);
|
||||||
|
|
||||||
/* Creates an error message JSON, with the specified code and message. */
|
/* Creates an error message JSON, with the specified code and message. */
|
||||||
extern HashMap * MatrixCreateError(char *err, char *msg);
|
extern HashMap * MatrixCreateError(char *err, char *msg);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ typedef struct ParseeData ParseeData;
|
||||||
#include <Command.h>
|
#include <Command.h>
|
||||||
#include <XMPP.h>
|
#include <XMPP.h>
|
||||||
|
|
||||||
|
#include <MUCServ.h>
|
||||||
|
|
||||||
#define PARSEE_VERBOSE_NONE 0
|
#define PARSEE_VERBOSE_NONE 0
|
||||||
#define PARSEE_VERBOSE_LOG 1
|
#define PARSEE_VERBOSE_LOG 1
|
||||||
#define PARSEE_VERBOSE_TIMINGS 2
|
#define PARSEE_VERBOSE_TIMINGS 2
|
||||||
|
|
@ -62,6 +64,7 @@ typedef struct ParseeData {
|
||||||
|
|
||||||
HttpServer *server;
|
HttpServer *server;
|
||||||
XMPPComponent *jabber;
|
XMPPComponent *jabber;
|
||||||
|
MUCServer *muc;
|
||||||
|
|
||||||
Db *db;
|
Db *db;
|
||||||
char *id;
|
char *id;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue