mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-13 18:35:11 +00:00
[ADD/WIP] Start making a simple SAX parser, ASwerk
This commit is contained in:
parent
0fa95c2d14
commit
79217d3608
14 changed files with 1066 additions and 26 deletions
130
src/AS.c
130
src/AS.c
|
|
@ -54,3 +54,133 @@ ASAuthenticateRequest(ParseeConfig *data, HttpClientContext *ctx)
|
||||||
HttpRequestHeader(ctx, "Authorization", bearer);
|
HttpRequestHeader(ctx, "Authorization", bearer);
|
||||||
Free(bearer);
|
Free(bearer);
|
||||||
}
|
}
|
||||||
|
bool
|
||||||
|
ASRegisterUser(ParseeConfig *conf, char *user)
|
||||||
|
{
|
||||||
|
HttpClientContext *ctx = NULL;
|
||||||
|
HashMap *json = NULL;
|
||||||
|
HttpStatus status;
|
||||||
|
if (!conf || !user)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create user. We don't actually care about the value as we can
|
||||||
|
* masquerade, as long as it exists. */
|
||||||
|
ctx = ParseeCreateRequest(
|
||||||
|
conf,
|
||||||
|
HTTP_POST, "/_matrix/client/v3/register"
|
||||||
|
);
|
||||||
|
json = HashMapCreate();
|
||||||
|
|
||||||
|
HashMapSet(json,"type",JsonValueString("m.login.application_service"));
|
||||||
|
HashMapSet(json,"username",JsonValueString(user));
|
||||||
|
|
||||||
|
ASAuthenticateRequest(conf, ctx);
|
||||||
|
status = ParseeSetRequestJSON(ctx, json);
|
||||||
|
HttpClientContextFree(ctx);
|
||||||
|
JsonFree(json);
|
||||||
|
|
||||||
|
return status == HTTP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ASPing(ParseeConfig *conf)
|
||||||
|
{
|
||||||
|
HttpClientContext *ctx = NULL;
|
||||||
|
HashMap *json = NULL;
|
||||||
|
char *path;
|
||||||
|
if (!conf)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(LOG_NOTICE, "Pinging...");
|
||||||
|
path = StrConcat(3,
|
||||||
|
"/_matrix/client/v1/appservice/",
|
||||||
|
"Parsee%20XMPP",
|
||||||
|
"/ping"
|
||||||
|
);
|
||||||
|
ctx = ParseeCreateRequest(
|
||||||
|
conf,
|
||||||
|
HTTP_POST, path
|
||||||
|
);
|
||||||
|
Free(path);
|
||||||
|
json = HashMapCreate();
|
||||||
|
ASAuthenticateRequest(conf, ctx);
|
||||||
|
ParseeSetRequestJSON(ctx, json);
|
||||||
|
HttpClientContextFree(ctx);
|
||||||
|
JsonFree(json);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
ASJoin(ParseeConfig *conf, char *id, char *masquerade)
|
||||||
|
{
|
||||||
|
HttpClientContext *ctx = NULL;
|
||||||
|
HashMap *json = NULL, *params_obj;
|
||||||
|
char *path, *params;
|
||||||
|
if (!conf || !id)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
params_obj = HashMapCreate();
|
||||||
|
if (masquerade)
|
||||||
|
{
|
||||||
|
HashMapSet(params_obj, "user_id", masquerade);
|
||||||
|
}
|
||||||
|
params = HttpParamEncode(params_obj);
|
||||||
|
HashMapFree(params_obj);
|
||||||
|
path = StrConcat(4,
|
||||||
|
"/_matrix/client/v3/rooms/", id, "/join?",
|
||||||
|
params
|
||||||
|
);
|
||||||
|
Free(params);
|
||||||
|
|
||||||
|
ctx = ParseeCreateRequest(
|
||||||
|
conf,
|
||||||
|
HTTP_POST, path
|
||||||
|
);
|
||||||
|
Free(path);
|
||||||
|
json = HashMapCreate();
|
||||||
|
ASAuthenticateRequest(conf, ctx);
|
||||||
|
ParseeSetRequestJSON(ctx, json);
|
||||||
|
HttpClientContextFree(ctx);
|
||||||
|
JsonFree(json);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
ASSend(ParseeConfig *conf, char *id, char *user, char *type, HashMap *c)
|
||||||
|
{
|
||||||
|
HttpClientContext *ctx = NULL;
|
||||||
|
HashMap *json = NULL, *params_obj;
|
||||||
|
char *path, *params;
|
||||||
|
char *txn;
|
||||||
|
if (!conf || !id || !type || !c)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
txn = StrRandom(16);
|
||||||
|
params_obj = HashMapCreate();
|
||||||
|
if (user)
|
||||||
|
{
|
||||||
|
HashMapSet(params_obj, "user_id", user);
|
||||||
|
}
|
||||||
|
params = HttpParamEncode(params_obj);
|
||||||
|
HashMapFree(params_obj);
|
||||||
|
path = StrConcat(8,
|
||||||
|
"/_matrix/client/v3/rooms/",
|
||||||
|
id, "/send/", type, "/", txn, "?",
|
||||||
|
params
|
||||||
|
);
|
||||||
|
Log(LOG_INFO, "Sending %s", path);
|
||||||
|
Free(params);
|
||||||
|
Free(txn);
|
||||||
|
|
||||||
|
ctx = ParseeCreateRequest(conf, HTTP_PUT, path);
|
||||||
|
Free(path);
|
||||||
|
json = HashMapCreate();
|
||||||
|
ASAuthenticateRequest(conf, ctx);
|
||||||
|
Log(LOG_INFO, "%d", ParseeSetRequestJSON(ctx, c));
|
||||||
|
HttpClientContextFree(ctx);
|
||||||
|
JsonFree(c);
|
||||||
|
}
|
||||||
|
|
|
||||||
17
src/Events.c
Normal file
17
src/Events.c
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include <Matrix.h>
|
||||||
|
|
||||||
|
HashMap *
|
||||||
|
MatrixCreateNotice(char *body)
|
||||||
|
{
|
||||||
|
HashMap *map;
|
||||||
|
if (!body)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = HashMapCreate();
|
||||||
|
HashMapSet(map, "msgtype", JsonValueString("m.notice"));
|
||||||
|
HashMapSet(map, "body", JsonValueString(body));
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
30
src/Main.c
30
src/Main.c
|
|
@ -4,6 +4,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <Parsee.h>
|
#include <Parsee.h>
|
||||||
|
#include <XML.h>
|
||||||
#include <AS.h>
|
#include <AS.h>
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -12,7 +13,7 @@ Main(void)
|
||||||
HttpServer *server = NULL;
|
HttpServer *server = NULL;
|
||||||
HttpServerConfig conf;
|
HttpServerConfig conf;
|
||||||
ParseeData *data;
|
ParseeData *data;
|
||||||
const ParseeConfig *parseeConf;
|
const ParseeConfig *parsee_conf;
|
||||||
Stream *yaml;
|
Stream *yaml;
|
||||||
|
|
||||||
Log(LOG_INFO, "%s - v%s", NAME, VERSION);
|
Log(LOG_INFO, "%s - v%s", NAME, VERSION);
|
||||||
|
|
@ -23,29 +24,14 @@ Main(void)
|
||||||
ParseeExportConfigYAML(yaml);
|
ParseeExportConfigYAML(yaml);
|
||||||
StreamClose(yaml);
|
StreamClose(yaml);
|
||||||
|
|
||||||
parseeConf = ParseeConfigGet();
|
parsee_conf = ParseeConfigGet();
|
||||||
Log(LOG_INFO, "HS token: %s", parseeConf->hs_token);
|
Log(LOG_INFO, "HS token: %s", parsee_conf->hs_token);
|
||||||
|
|
||||||
|
ASRegisterUser(parsee_conf, parsee_conf->sender_localpart);
|
||||||
|
|
||||||
{
|
|
||||||
/* Create user. We don't actually care about the value as we can
|
|
||||||
* masquerade, as long as it exists. */
|
|
||||||
HttpClientContext *ctx = ParseeCreateRequest(
|
|
||||||
parseeConf,
|
|
||||||
HTTP_POST, "/_matrix/client/v3/register"
|
|
||||||
);
|
|
||||||
HashMap *json = HashMapCreate();
|
|
||||||
|
|
||||||
HashMapSet(json,"type",JsonValueString("m.login.application_service"));
|
|
||||||
HashMapSet(json,"username",JsonValueString(parseeConf->sender_localpart));
|
|
||||||
|
|
||||||
ASAuthenticateRequest(parseeConf, ctx);
|
|
||||||
Log(LOG_INFO, "Got %d", ParseeSetRequestJSON(ctx, json));
|
|
||||||
HttpClientContextFree(ctx);
|
|
||||||
JsonFree(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&conf, 0, sizeof(conf));
|
memset(&conf, 0, sizeof(conf));
|
||||||
conf.port = parseeConf->port;
|
conf.port = parsee_conf->port;
|
||||||
conf.threads = 4;
|
conf.threads = 4;
|
||||||
conf.maxConnections = 32;
|
conf.maxConnections = 32;
|
||||||
conf.handlerArgs = ParseeInitData();
|
conf.handlerArgs = ParseeInitData();
|
||||||
|
|
@ -54,6 +40,8 @@ Main(void)
|
||||||
/* TODO: The rest of Parsee. */
|
/* TODO: The rest of Parsee. */
|
||||||
server = HttpServerCreate(&conf);
|
server = HttpServerCreate(&conf);
|
||||||
HttpServerStart(server);
|
HttpServerStart(server);
|
||||||
|
|
||||||
|
/* TODO: Manage signals(^C) with finesse */
|
||||||
HttpServerJoin(server);
|
HttpServerJoin(server);
|
||||||
|
|
||||||
HttpServerFree(server);
|
HttpServerFree(server);
|
||||||
|
|
|
||||||
69
src/MatrixEventHandler.c
Normal file
69
src/MatrixEventHandler.c
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
#include <Parsee.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm/Json.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
#include <Cytoplasm/Log.h>
|
||||||
|
|
||||||
|
#include <Matrix.h>
|
||||||
|
#include <AS.h>
|
||||||
|
|
||||||
|
#define GrabString(obj, ...) JsonValueAsString(JsonGet(obj, __VA_ARGS__))
|
||||||
|
static void
|
||||||
|
ParseeMemberHandler(const ParseeConfig *conf, HashMap *event)
|
||||||
|
{
|
||||||
|
char *state_key = GrabString(event, 1, "state_key");
|
||||||
|
char *membership = GrabString(event, 2, "content", "membership");
|
||||||
|
char *room_id = GrabString(event, 1, "room_id");
|
||||||
|
Log(LOG_INFO, "Membership '%s'->'%s'", state_key, membership);
|
||||||
|
|
||||||
|
if (StrEquals(membership, "invite") && ParseeIsPuppet(conf, state_key))
|
||||||
|
{
|
||||||
|
Log(LOG_INFO, "Looks like %s was invited to %s",
|
||||||
|
state_key,
|
||||||
|
GrabString(event, 1, "room_id")
|
||||||
|
);
|
||||||
|
ASJoin(conf, room_id, state_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
ParseeMessageHandler(const ParseeConfig *conf, HashMap *event)
|
||||||
|
{
|
||||||
|
char *msgtype = GrabString(event, 2, "content", "msgtype");
|
||||||
|
char *body = GrabString(event, 2, "content", "body");
|
||||||
|
char *id = GrabString(event, 1, "room_id");
|
||||||
|
if (StrEquals(body, "!help"))
|
||||||
|
{
|
||||||
|
Log(LOG_ERR, "Not implemented!");
|
||||||
|
ASSend(conf, id, NULL, "m.room.message",
|
||||||
|
MatrixCreateNotice("No help, pal.")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ParseeEventHandler(const ParseeConfig *conf, HashMap *event)
|
||||||
|
{
|
||||||
|
char *event_type;
|
||||||
|
if (!conf || !event)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(LOG_INFO, "Event by '%s', with type '%s'",
|
||||||
|
JsonValueAsString(HashMapGet(event, "sender")),
|
||||||
|
JsonValueAsString(HashMapGet(event, "type"))
|
||||||
|
);
|
||||||
|
|
||||||
|
event_type = GrabString(event, 1, "type");
|
||||||
|
if (StrEquals(event_type, "m.room.member"))
|
||||||
|
{
|
||||||
|
ParseeMemberHandler(conf, event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StrEquals(event_type, "m.room.message"))
|
||||||
|
{
|
||||||
|
ParseeMessageHandler(conf, event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
32
src/ParseeUser.c
Normal file
32
src/ParseeUser.c
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#include <Parsee.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
bool
|
||||||
|
ParseeIsPuppet(const ParseeConfig *conf, char *user)
|
||||||
|
{
|
||||||
|
char *localpart;
|
||||||
|
bool flag = true;
|
||||||
|
size_t len;
|
||||||
|
if (!user || !conf || *user != '@')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
localpart = user + 1;
|
||||||
|
len = strlen(conf->namespace_base);
|
||||||
|
if (strncmp(localpart, conf->namespace_base, len))
|
||||||
|
{
|
||||||
|
flag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(conf->sender_localpart);
|
||||||
|
if (!strncmp(localpart, conf->sender_localpart, len))
|
||||||
|
{
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Check serverpart. 2 Parsee instances may be running in the same
|
||||||
|
* room. */
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
37
src/Routes/Ping.c
Normal file
37
src/Routes/Ping.c
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#include <Routes.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm/Log.h>
|
||||||
|
|
||||||
|
#include <Matrix.h>
|
||||||
|
#include <AS.h>
|
||||||
|
|
||||||
|
RouteHead(RoutePing, arr, argp)
|
||||||
|
{
|
||||||
|
ParseeHttpArg *args = argp;
|
||||||
|
HashMap *request = NULL;
|
||||||
|
HashMap *response = NULL;
|
||||||
|
|
||||||
|
response = ASVerifyRequest(args);
|
||||||
|
if (response)
|
||||||
|
{
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (HttpRequestMethodGet(args->ctx) != HTTP_POST)
|
||||||
|
{
|
||||||
|
HttpResponseStatus(args->ctx, HTTP_METHOD_NOT_ALLOWED);
|
||||||
|
response = MatrixCreateError(
|
||||||
|
"M_UNRECOGNIZED",
|
||||||
|
"Path /ping only accepts POST as a valid method."
|
||||||
|
);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
Log(LOG_INFO, "Pong!");
|
||||||
|
|
||||||
|
RequestJSON();
|
||||||
|
|
||||||
|
/* TODO: Load ping info */
|
||||||
|
response = HashMapCreate();
|
||||||
|
end:
|
||||||
|
JsonFree(request);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
#include <Routes.h>
|
#include <Routes.h>
|
||||||
|
|
||||||
|
#include <AS.h>
|
||||||
|
|
||||||
RouteHead(RouteRoot, arr, argp)
|
RouteHead(RouteRoot, arr, argp)
|
||||||
{
|
{
|
||||||
ParseeHttpArg *args = argp;
|
ParseeHttpArg *args = argp;
|
||||||
|
|
||||||
|
ASPing(args->data->config);
|
||||||
|
|
||||||
HttpResponseHeader(args->ctx, "Content-Type", "text/html");
|
HttpResponseHeader(args->ctx, "Content-Type", "text/html");
|
||||||
HttpSendHeaders(args->ctx);
|
HttpSendHeaders(args->ctx);
|
||||||
StreamPrintf(args->stream, "<html lang=\"en\">");
|
StreamPrintf(args->stream, "<html lang=\"en\">");
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,11 @@ RouteHead(RouteTxns, arr, argp)
|
||||||
for (i = 0; i < ArraySize(events); i++)
|
for (i = 0; i < ArraySize(events); i++)
|
||||||
{
|
{
|
||||||
HashMap *event = JsonValueAsObject(ArrayGet(events, i));
|
HashMap *event = JsonValueAsObject(ArrayGet(events, i));
|
||||||
Log(LOG_INFO, "Event by '%s', with type '%s'",
|
ParseeEventHandler(args->data->config, event);
|
||||||
JsonValueAsString(HashMapGet(event, "sender")),
|
|
||||||
JsonValueAsString(HashMapGet(event, "type"))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: Store TXN ID somewhere so that we can commit
|
||||||
|
* "Epic Matrix Idempotency" */
|
||||||
|
|
||||||
Log(LOG_INFO, "OK!");
|
Log(LOG_INFO, "OK!");
|
||||||
response = HashMapCreate();
|
response = HashMapCreate();
|
||||||
|
|
|
||||||
702
src/XML/SAX.c
Normal file
702
src/XML/SAX.c
Normal file
|
|
@ -0,0 +1,702 @@
|
||||||
|
#include <XML.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm/HashMap.h>
|
||||||
|
#include <Cytoplasm/Memory.h>
|
||||||
|
#include <Cytoplasm/Array.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
#include <Cytoplasm/Log.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
struct XMLexer {
|
||||||
|
Stream *stream;
|
||||||
|
bool autofree;
|
||||||
|
|
||||||
|
/* A temporary buffer */
|
||||||
|
int *buffer;
|
||||||
|
ssize_t length;
|
||||||
|
ssize_t top;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
XML_STATE_NONE = 0,
|
||||||
|
XML_STATE_COMMENT,
|
||||||
|
|
||||||
|
XML_STATE_ATTR,
|
||||||
|
XML_STATE_ATTRHEAD_PROP,
|
||||||
|
XML_STATE_ATTRTAIL
|
||||||
|
} state;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
Array *elements;
|
||||||
|
char *str;
|
||||||
|
} data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* "Looks ahead" in the XML stream for a NUL-terminated string.
|
||||||
|
* If it was found and skip is set, then also skips over it. */
|
||||||
|
static bool XMLookahead(XMLexer *lexer, const char *str, bool skip);
|
||||||
|
|
||||||
|
/* Parses an XML "name" */
|
||||||
|
static bool XMLIsStart(XMLexer *lexer);
|
||||||
|
static char * XMLParseName(XMLexer *lexer);
|
||||||
|
static bool XMLSkipSpace(XMLexer *lexer);
|
||||||
|
static char * XMLParseAttValue(XMLexer *lexer);
|
||||||
|
|
||||||
|
static ssize_t XMLInitialiseBuffer(XMLexer *lexer);
|
||||||
|
static int XMLGetc(XMLexer *lexer);
|
||||||
|
static void XMLUngetc(XMLexer *lexer, int ch);
|
||||||
|
static void XMLEndBuffer(XMLexer *lexer);
|
||||||
|
static void XMLRollback(XMLexer *lexer);
|
||||||
|
static void XMLReset(XMLexer *lexer, ssize_t loc);
|
||||||
|
static char * XMLStringify(XMLexer *lexer, ssize_t point);
|
||||||
|
static HashMap * XMLReadProps(XMLexer *l);
|
||||||
|
static void XMLPushElement(XMLexer *lexer, char *e);
|
||||||
|
static char * XMLPopElement(XMLexer *lexer);
|
||||||
|
|
||||||
|
static XMLEvent * XMLCreateEmptyElem(XMLexer *lexer, HashMap *attrs);
|
||||||
|
static XMLEvent * XMLCreateStart(XMLexer *lexer, HashMap *attrs);
|
||||||
|
static XMLEvent * XMLCreateRelax(XMLexer *lexer);
|
||||||
|
static XMLEvent * XMLCreateEnd(XMLexer *lexer, char *end);
|
||||||
|
static XMLEvent * XMLCreateData(XMLexer *lexer);
|
||||||
|
|
||||||
|
XMLexer *
|
||||||
|
XMLCreateLexer(Stream *stream, bool autofree)
|
||||||
|
{
|
||||||
|
XMLexer *lexer;
|
||||||
|
if (!stream)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer = Malloc(sizeof(*lexer));
|
||||||
|
lexer->stream = stream;
|
||||||
|
lexer->autofree = autofree;
|
||||||
|
lexer->state = XML_STATE_NONE;
|
||||||
|
|
||||||
|
lexer->buffer = NULL;
|
||||||
|
lexer->length = -1;
|
||||||
|
lexer->top = -1;
|
||||||
|
|
||||||
|
lexer->data.elements = ArrayCreate();
|
||||||
|
lexer->data.str = NULL;
|
||||||
|
|
||||||
|
return lexer;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
XMLFreeLexer(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
if (!lexer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lexer->autofree)
|
||||||
|
{
|
||||||
|
StreamClose(lexer->stream);
|
||||||
|
}
|
||||||
|
if (lexer->buffer)
|
||||||
|
{
|
||||||
|
Free(lexer->buffer);
|
||||||
|
}
|
||||||
|
if (lexer->data.str)
|
||||||
|
{
|
||||||
|
Free(lexer->data.str);
|
||||||
|
}
|
||||||
|
if (lexer->data.elements)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Array *elems = lexer->data.elements;
|
||||||
|
for (i = 0; i < ArraySize(elems); i++)
|
||||||
|
{
|
||||||
|
Free(ArrayGet(elems, i));
|
||||||
|
}
|
||||||
|
ArrayFree(lexer->data.elements);
|
||||||
|
}
|
||||||
|
Free(lexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XMLEvent *
|
||||||
|
XMLCrank(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
XMLEvent *event = NULL;
|
||||||
|
char c;
|
||||||
|
char *attrname;
|
||||||
|
HashMap *props;
|
||||||
|
char *key, *val;
|
||||||
|
char cbuf[2] = { 0 };
|
||||||
|
char *tmp;
|
||||||
|
if (!lexer)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (StreamEof(lexer->stream))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
event = XMLCreateRelax(lexer);
|
||||||
|
switch (lexer->state)
|
||||||
|
{
|
||||||
|
case XML_STATE_NONE:
|
||||||
|
if (XMLookahead(lexer, "<!--", true))
|
||||||
|
{
|
||||||
|
if (lexer->data.str)
|
||||||
|
{
|
||||||
|
XMLFreeEvent(event);
|
||||||
|
event = XMLCreateData(lexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer->state = XML_STATE_COMMENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (XMLookahead(lexer, "</", true))
|
||||||
|
{
|
||||||
|
if (lexer->data.str)
|
||||||
|
{
|
||||||
|
XMLFreeEvent(event);
|
||||||
|
event = XMLCreateData(lexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer->state = XML_STATE_ATTRTAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (XMLookahead(lexer, "<", true))
|
||||||
|
{
|
||||||
|
if (lexer->data.str)
|
||||||
|
{
|
||||||
|
XMLFreeEvent(event);
|
||||||
|
event = XMLCreateData(lexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer->state = XML_STATE_ATTR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* TODO: Try storing character into str buffer. */
|
||||||
|
cbuf[0] = XMLGetc(lexer);
|
||||||
|
tmp = lexer->data.str;
|
||||||
|
lexer->data.str = StrConcat(2, tmp, cbuf);
|
||||||
|
Free(tmp);
|
||||||
|
break;
|
||||||
|
case XML_STATE_COMMENT:
|
||||||
|
if (XMLookahead(lexer, "-->", true))
|
||||||
|
{
|
||||||
|
lexer->state = XML_STATE_NONE;
|
||||||
|
}
|
||||||
|
else if (XMLookahead(lexer, "--", false))
|
||||||
|
{
|
||||||
|
/* Throw error */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XML_STATE_ATTR:
|
||||||
|
attrname = XMLParseName(lexer);
|
||||||
|
if (!attrname)
|
||||||
|
{
|
||||||
|
/* TODO: Throw error */
|
||||||
|
}
|
||||||
|
XMLPushElement(lexer, attrname);
|
||||||
|
|
||||||
|
props = XMLReadProps(lexer);
|
||||||
|
|
||||||
|
XMLSkipSpace(lexer);
|
||||||
|
if (XMLookahead(lexer, "/>", true))
|
||||||
|
{
|
||||||
|
lexer->state = XML_STATE_NONE;
|
||||||
|
XMLFreeEvent(event);
|
||||||
|
event = XMLCreateEmptyElem(lexer, props);
|
||||||
|
|
||||||
|
Free(XMLPopElement(lexer));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (XMLookahead(lexer, ">", true))
|
||||||
|
{
|
||||||
|
lexer->state = XML_STATE_NONE;
|
||||||
|
XMLFreeEvent(event);
|
||||||
|
event = XMLCreateStart(lexer, props);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XML_STATE_ATTRTAIL:
|
||||||
|
attrname = XMLParseName(lexer);
|
||||||
|
Free(XMLPopElement(lexer));
|
||||||
|
if (!XMLookahead(lexer, ">", true))
|
||||||
|
{
|
||||||
|
/* TODO: Throw error. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lexer->state = XML_STATE_NONE;
|
||||||
|
XMLFreeEvent(event);
|
||||||
|
event = XMLCreateEnd(lexer, attrname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* TODO: Crank our XML parser. */
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
XMLFreeEvent(XMLEvent *event)
|
||||||
|
{
|
||||||
|
if (!event)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event->element)
|
||||||
|
{
|
||||||
|
Free(event->element);
|
||||||
|
}
|
||||||
|
if (event->attrs)
|
||||||
|
{
|
||||||
|
char *key;
|
||||||
|
void *val;
|
||||||
|
while (HashMapIterate(event->attrs, &key, &val))
|
||||||
|
{
|
||||||
|
Log(LOG_INFO, "Trying to free %s", val);
|
||||||
|
Free(val);
|
||||||
|
}
|
||||||
|
HashMapFree(event->attrs);
|
||||||
|
}
|
||||||
|
if (event->data)
|
||||||
|
{
|
||||||
|
Free(event->data);
|
||||||
|
}
|
||||||
|
Free(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
XMLookahead(XMLexer *lexer, const char *str, bool skip)
|
||||||
|
{
|
||||||
|
int *stack;
|
||||||
|
size_t top, i;
|
||||||
|
ssize_t ntop;
|
||||||
|
bool ret = false;
|
||||||
|
if (!lexer || !str)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
top = 0;
|
||||||
|
stack = Malloc(strlen(str) * sizeof(*stack));
|
||||||
|
|
||||||
|
for (i = 0; i < strlen(str); i++)
|
||||||
|
{
|
||||||
|
char c = str[i];
|
||||||
|
int getc = XMLGetc(lexer);
|
||||||
|
|
||||||
|
stack[top++] = getc;
|
||||||
|
if (getc != c || getc == EOF)
|
||||||
|
{
|
||||||
|
goto seekback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have been able to seek the string properly */
|
||||||
|
ret = true;
|
||||||
|
if (!skip)
|
||||||
|
{
|
||||||
|
goto seekback;
|
||||||
|
}
|
||||||
|
Free(stack);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
seekback:
|
||||||
|
for (ntop = top - 1; ntop >= 0; ntop--)
|
||||||
|
{
|
||||||
|
XMLUngetc(lexer, stack[ntop]);
|
||||||
|
}
|
||||||
|
Free(stack);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IsNamestart(c) ((c == ':') || isalpha(c) || (c == '_'))
|
||||||
|
#define IsNamepart(c) (IsNamestart(c) || (c == '-') || isdigit(c))
|
||||||
|
static char *
|
||||||
|
XMLParseName(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
ssize_t point;
|
||||||
|
|
||||||
|
point = XMLInitialiseBuffer(lexer);
|
||||||
|
c = XMLGetc(lexer);
|
||||||
|
if (!IsNamestart(c))
|
||||||
|
{
|
||||||
|
XMLRollback(lexer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((c = XMLGetc(lexer)))
|
||||||
|
{
|
||||||
|
if (!IsNamepart(c))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XMLUngetc(lexer, c);
|
||||||
|
|
||||||
|
return XMLStringify(lexer, point);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
XMLInitialiseBuffer(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
if (!lexer)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (lexer->length != -1)
|
||||||
|
{
|
||||||
|
return lexer->top;
|
||||||
|
}
|
||||||
|
|
||||||
|
lexer->length = 0;
|
||||||
|
lexer->top = 0;
|
||||||
|
lexer->buffer = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static int
|
||||||
|
XMLGetc(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
int ch;
|
||||||
|
if (lexer->length == -1)
|
||||||
|
{
|
||||||
|
return StreamGetc(lexer->stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = StreamGetc(lexer->stream);
|
||||||
|
if (lexer->top >= lexer->length)
|
||||||
|
{
|
||||||
|
lexer->length += 8;
|
||||||
|
lexer->buffer = Realloc(
|
||||||
|
lexer->buffer,
|
||||||
|
lexer->length * sizeof(*lexer->buffer)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
lexer->buffer[lexer->top++] = ch;
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
XMLUngetc(XMLexer *lexer, int ch)
|
||||||
|
{
|
||||||
|
if (!lexer || lexer->length == -1)
|
||||||
|
{
|
||||||
|
StreamUngetc(lexer->stream, ch);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (lexer->top == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamUngetc(lexer->stream, ch);
|
||||||
|
lexer->top--;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
XMLEndBuffer(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
if (!lexer || lexer->length == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lexer->top = -1;
|
||||||
|
lexer->length = -1;
|
||||||
|
|
||||||
|
Free(lexer->buffer);
|
||||||
|
lexer->buffer = NULL;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
XMLRollback(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
ssize_t i;
|
||||||
|
if (!lexer || lexer->length == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (i = lexer->top - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
StreamUngetc(lexer->stream, lexer->buffer[i]);
|
||||||
|
}
|
||||||
|
XMLEndBuffer(lexer);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
XMLReset(XMLexer *lexer, ssize_t loc)
|
||||||
|
{
|
||||||
|
ssize_t i;
|
||||||
|
if (!lexer || lexer->length == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (i = lexer->top - 1; i >= loc; i--)
|
||||||
|
{
|
||||||
|
StreamUngetc(lexer->stream, lexer->buffer[i]);
|
||||||
|
}
|
||||||
|
lexer->top = loc;
|
||||||
|
}
|
||||||
|
char *
|
||||||
|
XMLStringify(XMLexer *lexer, ssize_t point)
|
||||||
|
{
|
||||||
|
ssize_t i;
|
||||||
|
char *str;
|
||||||
|
if (!lexer || lexer->length == -1)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
str = Malloc(lexer->top + 1);
|
||||||
|
memset(str, '\0', lexer->top + 1);
|
||||||
|
for (i = point; i < lexer->top; i++)
|
||||||
|
{
|
||||||
|
str[i - point] = (char) lexer->buffer[i];
|
||||||
|
}
|
||||||
|
XMLEndBuffer(lexer);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IsSpace(c) ((c == ' ') || (c == 0x09) || (c == 0x0D) || (c == 0x0A))
|
||||||
|
bool
|
||||||
|
XMLSkipSpace(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
bool r = false;
|
||||||
|
while ((c = XMLGetc(lexer)) != EOF)
|
||||||
|
{
|
||||||
|
if (!IsSpace(c))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r = true;
|
||||||
|
}
|
||||||
|
XMLUngetc(lexer, c);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
HashMap *
|
||||||
|
XMLReadProps(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
ssize_t point = XMLInitialiseBuffer(lexer);
|
||||||
|
HashMap *map = HashMapCreate();
|
||||||
|
bool error = false;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
char *value = NULL;
|
||||||
|
|
||||||
|
if (!XMLSkipSpace(lexer))
|
||||||
|
{
|
||||||
|
/* A lack of space is totally excepted */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = XMLParseName(lexer);
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
/* A lack of name is totally excepted */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = StrDuplicate("");
|
||||||
|
if (XMLookahead(lexer, "=", true))
|
||||||
|
{
|
||||||
|
/* TODO: Values aren't names. */
|
||||||
|
Free(value);
|
||||||
|
value = XMLParseAttValue(lexer);
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
error = true;
|
||||||
|
Free(name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HashMapSet(map, name, value);
|
||||||
|
Free(name);
|
||||||
|
}
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
XMLReset(lexer, point);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
static XMLEvent *
|
||||||
|
XMLCreateStart(XMLexer *lexer, HashMap *attrs)
|
||||||
|
{
|
||||||
|
XMLEvent *event = Malloc(sizeof(*event));
|
||||||
|
size_t elements = ArraySize(lexer->data.elements) - 1;
|
||||||
|
char *h_element = StrDuplicate(ArrayGet(lexer->data.elements, elements));
|
||||||
|
|
||||||
|
event->type = XML_LEXER_STARTELEM;
|
||||||
|
event->element = h_element;
|
||||||
|
event->attrs = attrs;
|
||||||
|
event->data = NULL;
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
event->line = 0;
|
||||||
|
event->col = 0;
|
||||||
|
event->offset = 0;
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
XMLEvent *
|
||||||
|
XMLCreateEnd(XMLexer *lexer, char *end)
|
||||||
|
{
|
||||||
|
XMLEvent *event = Malloc(sizeof(*event));
|
||||||
|
|
||||||
|
event->type = XML_LEXER_ENDELEM;
|
||||||
|
event->element = end;
|
||||||
|
event->attrs = NULL;
|
||||||
|
event->data = NULL;
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
event->line = 0;
|
||||||
|
event->col = 0;
|
||||||
|
event->offset = 0;
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
static XMLEvent *
|
||||||
|
XMLCreateEmptyElem(XMLexer *lexer, HashMap *attrs)
|
||||||
|
{
|
||||||
|
XMLEvent *event = Malloc(sizeof(*event));
|
||||||
|
size_t elements = ArraySize(lexer->data.elements) - 1;
|
||||||
|
char *h_element = StrDuplicate(ArrayGet(lexer->data.elements, elements));
|
||||||
|
|
||||||
|
event->type = XML_LEXER_ELEM;
|
||||||
|
event->element = h_element;
|
||||||
|
event->attrs = attrs;
|
||||||
|
event->data = NULL;
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
event->line = 0;
|
||||||
|
event->col = 0;
|
||||||
|
event->offset = 0;
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
XMLEvent *
|
||||||
|
XMLCreateData(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
XMLEvent *event = Malloc(sizeof(*event));
|
||||||
|
size_t elements = ArraySize(lexer->data.elements);
|
||||||
|
|
||||||
|
event->type = XML_LEXER_DATA;
|
||||||
|
event->element = elements ?
|
||||||
|
StrDuplicate(ArrayGet(lexer->data.elements, elements - 1)) :
|
||||||
|
NULL;
|
||||||
|
event->attrs = NULL;
|
||||||
|
event->data = lexer->data.str;
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
event->line = 0;
|
||||||
|
event->col = 0;
|
||||||
|
event->offset = 0;
|
||||||
|
|
||||||
|
lexer->data.str = NULL;
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
static XMLEvent *
|
||||||
|
XMLCreateRelax(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
XMLEvent *event = Malloc(sizeof(*event));
|
||||||
|
size_t elements = ArraySize(lexer->data.elements);
|
||||||
|
|
||||||
|
event->type = XML_RELAX;
|
||||||
|
event->element = elements ?
|
||||||
|
StrDuplicate(ArrayGet(lexer->data.elements, elements - 1)) :
|
||||||
|
NULL;
|
||||||
|
event->attrs = NULL;
|
||||||
|
event->data = NULL;
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
event->line = 0;
|
||||||
|
event->col = 0;
|
||||||
|
event->offset = 0;
|
||||||
|
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
XMLPushElement(XMLexer *lexer, char *e)
|
||||||
|
{
|
||||||
|
ArrayAdd(lexer->data.elements, e);
|
||||||
|
}
|
||||||
|
static char *
|
||||||
|
XMLPopElement(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
size_t n = ArraySize(lexer->data.elements);
|
||||||
|
if (n == 0)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ArrayDelete(lexer->data.elements, n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IsNormalQ(c) ((c != '<') && (c != '&') && (c != '\''))
|
||||||
|
#define IsNormalD(c) ((c != '<') && (c != '&') && (c != '"'))
|
||||||
|
static char *
|
||||||
|
XMLParseAttQuote(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
ssize_t point;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
point = XMLInitialiseBuffer(lexer);
|
||||||
|
|
||||||
|
while ((c = XMLGetc(lexer)))
|
||||||
|
{
|
||||||
|
if (!IsNormalQ(c))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c != '\'')
|
||||||
|
{
|
||||||
|
XMLUngetc(lexer, c);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Decode the string */
|
||||||
|
str = XMLStringify(lexer, point);
|
||||||
|
str[strlen(str) - 1] = '\0'; /* Trim the quote. */
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
static char *
|
||||||
|
XMLParseAttDouble(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
ssize_t point;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
point = XMLInitialiseBuffer(lexer);
|
||||||
|
|
||||||
|
while ((c = XMLGetc(lexer)))
|
||||||
|
{
|
||||||
|
if (!IsNormalD(c))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c != '"')
|
||||||
|
{
|
||||||
|
XMLUngetc(lexer, c);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Decode the string */
|
||||||
|
str = XMLStringify(lexer, point);
|
||||||
|
str[strlen(str) - 1] = '\0'; /* Trim the quote. */
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
static char *
|
||||||
|
XMLParseAttValue(XMLexer *lexer)
|
||||||
|
{
|
||||||
|
ssize_t point = XMLInitialiseBuffer(lexer);
|
||||||
|
|
||||||
|
if (XMLookahead(lexer, "'", true))
|
||||||
|
{
|
||||||
|
return XMLParseAttQuote(lexer);
|
||||||
|
}
|
||||||
|
else if (XMLookahead(lexer, "\"", true))
|
||||||
|
{
|
||||||
|
return XMLParseAttDouble(lexer);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
@ -15,4 +15,19 @@ extern HashMap * ASVerifyRequest(ParseeHttpArg *);
|
||||||
* It does not send the request, however. */
|
* It does not send the request, however. */
|
||||||
extern void ASAuthenticateRequest(ParseeConfig *, HttpClientContext *);
|
extern void ASAuthenticateRequest(ParseeConfig *, HttpClientContext *);
|
||||||
|
|
||||||
|
/* Registers an user through the Application Service API. Returns
|
||||||
|
* true if the user was created. */
|
||||||
|
extern bool ASRegisterUser(ParseeConfig *, char *);
|
||||||
|
|
||||||
|
/* Pings the homeserver to get attention. */
|
||||||
|
extern void ASPing(ParseeConfig *);
|
||||||
|
|
||||||
|
/* Joins a room from an ID and a given user we want to masquerade
|
||||||
|
* as. */
|
||||||
|
extern void ASJoin(ParseeConfig *, char *, char *);
|
||||||
|
|
||||||
|
/* Sends a message event with a specific type and body.
|
||||||
|
* Said body is freed during the function's execution. */
|
||||||
|
extern void ASSend(ParseeConfig *, char *, char *, char *, HashMap *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,7 @@
|
||||||
|
|
||||||
/* 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);
|
||||||
|
|
||||||
|
/* Creates the content for a notice message. */
|
||||||
|
extern HashMap * MatrixCreateNotice(char *body);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -52,4 +52,10 @@ extern HttpClientContext * ParseeCreateRequest(ParseeConfig *, HttpRequestMethod
|
||||||
|
|
||||||
/* Sends headers, and writes the JSON object. */
|
/* Sends headers, and writes the JSON object. */
|
||||||
extern HttpStatus ParseeSetRequestJSON(HttpClientContext *, HashMap *);
|
extern HttpStatus ParseeSetRequestJSON(HttpClientContext *, HashMap *);
|
||||||
|
|
||||||
|
/* This function is called on every event received, and routes/manages it. */
|
||||||
|
extern void ParseeEventHandler(const ParseeConfig *, HashMap *);
|
||||||
|
|
||||||
|
/* Verifies if a user is a Parsee puppet user. */
|
||||||
|
extern bool ParseeIsPuppet(const ParseeConfig *, char *);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ typedef struct ParseeHttpArg {
|
||||||
|
|
||||||
/* A list of all routes. */
|
/* A list of all routes. */
|
||||||
#define ROUTES X_ROUTE("/", RouteRoot) \
|
#define ROUTES X_ROUTE("/", RouteRoot) \
|
||||||
X_ROUTE("/_matrix/app/v1/transactions/(.*)", RouteTxns)
|
X_ROUTE("/_matrix/app/v1/transactions/(.*)", RouteTxns) \
|
||||||
|
X_ROUTE("/_matrix/app/v1/ping", RoutePing)
|
||||||
|
|
||||||
#define X_ROUTE(path, name) extern void * name(Array *, void *);
|
#define X_ROUTE(path, name) extern void * name(Array *, void *);
|
||||||
ROUTES
|
ROUTES
|
||||||
|
|
|
||||||
36
src/include/XML.h
Normal file
36
src/include/XML.h
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef PARSEE_XML_H
|
||||||
|
#define PARSEE_XML_H
|
||||||
|
|
||||||
|
#include <Cytoplasm/HashMap.h>
|
||||||
|
#include <Cytoplasm/Stream.h>
|
||||||
|
|
||||||
|
typedef struct XMLexer XMLexer;
|
||||||
|
typedef struct XMLEvent {
|
||||||
|
enum {
|
||||||
|
XML_LEXER_UNKNOWN = 0,
|
||||||
|
XML_LEXER_STARTELEM,
|
||||||
|
XML_LEXER_ELEM, /* Empty attr */
|
||||||
|
XML_LEXER_DATA,
|
||||||
|
XML_LEXER_ENDELEM,
|
||||||
|
|
||||||
|
XML_RELAX
|
||||||
|
} type;
|
||||||
|
|
||||||
|
int line, col;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
/* The element name */
|
||||||
|
char *element;
|
||||||
|
|
||||||
|
/* Attributes hashmap */
|
||||||
|
HashMap *attrs;
|
||||||
|
|
||||||
|
/* The decoded data */
|
||||||
|
char *data;
|
||||||
|
} XMLEvent;
|
||||||
|
|
||||||
|
extern XMLexer * XMLCreateLexer(Stream *, bool);
|
||||||
|
extern XMLEvent * XMLCrank(XMLexer *);
|
||||||
|
extern void XMLFreeEvent(XMLEvent *);
|
||||||
|
extern void XMLFreeLexer(XMLexer *);
|
||||||
|
#endif
|
||||||
Loading…
Add table
Add a link
Reference in a new issue