[WIP/ADD] Try to separate discovery, make links nicer

This commit is contained in:
LDA 2024-12-19 20:59:12 +01:00
commit 5ddc5d3e5c
15 changed files with 409 additions and 118 deletions

View file

@ -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");

View file

@ -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);
} }

View file

@ -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;
}

View file

@ -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);

View file

@ -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,9 +153,29 @@ 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");
Uri *pref = UriParse(href);
if (StrEquals(pref->host, "matrix.to"))
{
/* TODO: Check if the element here is a Matrix.TO /* TODO: Check if the element here is a Matrix.TO
* pointing to a Parsee user. */ * pointing to a Parsee user. */
Concat("("); 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);
}
Free(id);
}
else
{
for (i = 0; i < ArraySize(elem->children); i++) for (i = 0; i < ArraySize(elem->children); i++)
{ {
child = ArrayGet(elem->children, i); child = ArrayGet(elem->children, i);
@ -162,9 +184,11 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags)
Concat(subxep); Concat(subxep);
Free(subxep); Free(subxep);
} }
Concat(" points to "); Concat(" < ");
Concat(href); Concat(href);
Concat(" )"); Concat(" >");
}
UriFree(pref);
} }
else else
{ {

View file

@ -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;
} }

View file

@ -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
View 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);
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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);
} }
} }

View file

@ -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
View 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

View file

@ -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);

View file

@ -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;