mirror of
https://forge.fsky.io/lda/Parsee.git
synced 2026-03-13 12:15:12 +00:00
Compare commits
5 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de40106932 | ||
|
|
81edbec1d0 | ||
|
|
e3979e0e6e | ||
|
|
6d7d85662b | ||
|
|
ca87972b3a |
49 changed files with 3544 additions and 88 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -24,3 +24,11 @@ tags
|
||||||
!.forgejo
|
!.forgejo
|
||||||
!.forgejo/*
|
!.forgejo/*
|
||||||
!.forgejo/**
|
!.forgejo/**
|
||||||
|
|
||||||
|
# Janet
|
||||||
|
janet/*
|
||||||
|
janet/**
|
||||||
|
janet
|
||||||
|
extensions
|
||||||
|
extensions/*
|
||||||
|
extensions/**
|
||||||
|
|
|
||||||
32
configure.c
32
configure.c
|
|
@ -368,7 +368,7 @@ write_objects(FILE *makefile, str_array_t *sources)
|
||||||
{
|
{
|
||||||
char *src = str_array_get(sources, i);
|
char *src = str_array_get(sources, i);
|
||||||
char *ofl = string_rep_ext(src, ".c", ".o");
|
char *ofl = string_rep_ext(src, ".c", ".o");
|
||||||
char *obj = string_cat("build", ofl + 3);
|
char *obj = string_cat("build", strchr(ofl, '/'));
|
||||||
|
|
||||||
fprintf(makefile, " %s", obj);
|
fprintf(makefile, " %s", obj);
|
||||||
free(ofl);
|
free(ofl);
|
||||||
|
|
@ -516,7 +516,8 @@ main_build(int argc, char *argv[])
|
||||||
ssize_t nread;
|
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, *janet = NULL, *images, *utils, *aya;
|
||||||
|
char *janet_dir = NULL;
|
||||||
|
|
||||||
if (repo)
|
if (repo)
|
||||||
{
|
{
|
||||||
|
|
@ -531,7 +532,7 @@ main_build(int argc, char *argv[])
|
||||||
repo = strdup("N/A");
|
repo = strdup("N/A");
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "sl")) != -1)
|
while ((opt = getopt(argc, argv, "slJ:")) != -1)
|
||||||
{
|
{
|
||||||
switch (opt)
|
switch (opt)
|
||||||
{
|
{
|
||||||
|
|
@ -542,6 +543,9 @@ main_build(int argc, char *argv[])
|
||||||
with_lmdb = with_static;
|
with_lmdb = with_static;
|
||||||
with_static = true;
|
with_static = true;
|
||||||
break;
|
break;
|
||||||
|
case 'J':
|
||||||
|
janet_dir = strdup(optarg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -560,13 +564,22 @@ main_build(int argc, char *argv[])
|
||||||
|
|
||||||
/* Create all objects */
|
/* Create all objects */
|
||||||
sources = collect_sources("src", true, ".c");
|
sources = collect_sources("src", true, ".c");
|
||||||
|
if (janet_dir)
|
||||||
|
{
|
||||||
|
janet = collect_sources(janet_dir, true, ".c");
|
||||||
|
for (i = 0; i < str_array_len(janet); i++)
|
||||||
|
{
|
||||||
|
str_array_add(sources, str_array_get(janet, i));
|
||||||
|
}
|
||||||
|
str_array_free(janet);
|
||||||
|
}
|
||||||
images = collect_sources("etc/media", true, ".png");
|
images = collect_sources("etc/media", true, ".png");
|
||||||
fprintf(makefile, "binary:");
|
fprintf(makefile, "binary:");
|
||||||
write_objects(makefile, sources);
|
write_objects(makefile, sources);
|
||||||
write_images(makefile, images);
|
write_images(makefile, images);
|
||||||
fprintf(makefile, "\n\t");
|
fprintf(makefile, "\n\t");
|
||||||
{
|
{
|
||||||
fprintf(makefile, "$(CC) -o $(BINARY)");
|
fprintf(makefile, "$(CC) -lm -o $(BINARY)");
|
||||||
if (with_static)
|
if (with_static)
|
||||||
{
|
{
|
||||||
fprintf(makefile, " -static");
|
fprintf(makefile, " -static");
|
||||||
|
|
@ -579,7 +592,7 @@ main_build(int argc, char *argv[])
|
||||||
fprintf(makefile, " -lm -lpthread -lmbedtls -lmbedx509 -lmbedcrypto -lCytoplasm -lmbedtls -lmbedx509 -lmbedcrypto");
|
fprintf(makefile, " -lm -lpthread -lmbedtls -lmbedx509 -lmbedcrypto -lCytoplasm -lmbedtls -lmbedx509 -lmbedcrypto");
|
||||||
if (with_lmdb) fprintf(makefile, " -llmdb");
|
if (with_lmdb) fprintf(makefile, " -llmdb");
|
||||||
}
|
}
|
||||||
fprintf(makefile, " -lCytoplasm $(LDFLAGS)\n");
|
fprintf(makefile, " -lCytoplasm -lm $(LDFLAGS)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write rules for every source */
|
/* Write rules for every source */
|
||||||
|
|
@ -587,7 +600,7 @@ main_build(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char *src = str_array_get(sources, i);
|
char *src = str_array_get(sources, i);
|
||||||
char *ofl = string_rep_ext(src, ".c", ".o");
|
char *ofl = string_rep_ext(src, ".c", ".o");
|
||||||
char *obj = string_cat("build", ofl + 3);
|
char *obj = string_cat("build", strchr(ofl, '/'));
|
||||||
|
|
||||||
fprintf(makefile, "%s: %s", obj, src);
|
fprintf(makefile, "%s: %s", obj, src);
|
||||||
analyse_dependencies(makefile, src);
|
analyse_dependencies(makefile, src);
|
||||||
|
|
@ -605,6 +618,10 @@ main_build(int argc, char *argv[])
|
||||||
str_array_free(s);
|
str_array_free(s);
|
||||||
|
|
||||||
fprintf(makefile, "\t$(CC) -c -Isrc -Isrc/include -I$(CYTO_INC) ");
|
fprintf(makefile, "\t$(CC) -c -Isrc -Isrc/include -I$(CYTO_INC) ");
|
||||||
|
if (janet_dir)
|
||||||
|
{
|
||||||
|
fprintf(makefile, "-DJANET -I %s ", janet_dir);
|
||||||
|
}
|
||||||
fprintf(makefile, "-DVERSION=\"\\\"$(VERSION)\\\"\" ");
|
fprintf(makefile, "-DVERSION=\"\\\"$(VERSION)\\\"\" ");
|
||||||
fprintf(makefile, "-DNAME=\"\\\"$(NAME)\\\"\" ");
|
fprintf(makefile, "-DNAME=\"\\\"$(NAME)\\\"\" ");
|
||||||
fprintf(makefile, "-DCODE=\"\\\"$(CODE)\\\"\" ");
|
fprintf(makefile, "-DCODE=\"\\\"$(CODE)\\\"\" ");
|
||||||
|
|
@ -675,7 +692,7 @@ main_build(int argc, char *argv[])
|
||||||
fprintf(makefile, " -lCytoplasm -lmbedtls -lmbedx509 -lmbedcrypto");
|
fprintf(makefile, " -lCytoplasm -lmbedtls -lmbedx509 -lmbedcrypto");
|
||||||
if (with_lmdb) fprintf(makefile, " -llmdb");
|
if (with_lmdb) fprintf(makefile, " -llmdb");
|
||||||
}
|
}
|
||||||
fprintf(makefile, " -lCytoplasm $(CFLAGS)\n");
|
fprintf(makefile, " -lCytoplasm -lm $(CFLAGS)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ofl);
|
free(ofl);
|
||||||
|
|
@ -763,6 +780,7 @@ main_build(int argc, char *argv[])
|
||||||
str_array_free(aya);
|
str_array_free(aya);
|
||||||
fflush(makefile);
|
fflush(makefile);
|
||||||
fclose(makefile);
|
fclose(makefile);
|
||||||
|
free(janet_dir);
|
||||||
free(repo);
|
free(repo);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ CommandHead(CmdSetPL, cmd, argp)
|
||||||
char *user = HashMapGet(cmd->arguments, "user");
|
char *user = HashMapGet(cmd->arguments, "user");
|
||||||
char *room = HashMapGet(cmd->arguments, "room");
|
char *room = HashMapGet(cmd->arguments, "room");
|
||||||
char *pl_str = HashMapGet(cmd->arguments, "pl");
|
char *pl_str = HashMapGet(cmd->arguments, "pl");
|
||||||
long pl = strtol(pl_str, NULL, 10);
|
long pl = pl_str ? strtol(pl_str, NULL, 10) : 0;
|
||||||
HashMap *map;
|
HashMap *map;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
74
src/Extensions.c
Normal file
74
src/Extensions.c
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
#ifndef JANET
|
||||||
|
#include <Extension.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
bool
|
||||||
|
ExtensionEnabled(void)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Extensions *
|
||||||
|
ExtensionCreateContext(ParseeData *data)
|
||||||
|
{
|
||||||
|
(void) data;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
ExtensionDestroyContext(Extensions *ctx)
|
||||||
|
{
|
||||||
|
(void) ctx;
|
||||||
|
}
|
||||||
|
Extension *
|
||||||
|
ExtensionLoadBasic(Extensions *ctx, char *id, char *file)
|
||||||
|
{
|
||||||
|
(void) file;
|
||||||
|
(void) ctx;
|
||||||
|
(void) id;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
ExtensionLoadDir(Extensions *ctx, char *dir)
|
||||||
|
{
|
||||||
|
(void) ctx;
|
||||||
|
(void) dir;
|
||||||
|
}
|
||||||
|
bool
|
||||||
|
ExtensionPushStanza(Extensions *ctx, XMLElement *stanza, StanzaType type)
|
||||||
|
{
|
||||||
|
(void) ctx;
|
||||||
|
(void) stanza;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool
|
||||||
|
ExtensionPushEvent(Extensions *ctx, HashMap *obj)
|
||||||
|
{
|
||||||
|
(void) ctx;
|
||||||
|
(void) obj;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
ExtensionManageCommands(Extensions *ctx, XMLElement *stanza)
|
||||||
|
{
|
||||||
|
(void) ctx;
|
||||||
|
(void) stanza;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
ExtensionRequestCommands(Extensions *ctx)
|
||||||
|
{
|
||||||
|
(void) ctx;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
ExtensionShoveCommands(Extensions *ctx, char *jid, XMLElement *query, XMLElement *stanza)
|
||||||
|
{
|
||||||
|
(void) ctx;
|
||||||
|
(void) jid;
|
||||||
|
(void) query;
|
||||||
|
(void) stanza;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
ExtensionReload(Extensions *ctx, char *id)
|
||||||
|
{
|
||||||
|
(void) ctx;
|
||||||
|
(void) id;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
366
src/Extensions/DB.c
Normal file
366
src/Extensions/DB.c
Normal file
|
|
@ -0,0 +1,366 @@
|
||||||
|
#ifdef JANET
|
||||||
|
|
||||||
|
#include "Extensions/Internal.h"
|
||||||
|
|
||||||
|
static int JanetDbGet(void *data0, Janet key, Janet *out);
|
||||||
|
static void JanetMarshalDb(void *data0, JanetMarshalContext *ctx);
|
||||||
|
static void *JanetUnmarshalDb(JanetMarshalContext *ctx);
|
||||||
|
static void JanetDbToString(void *data0, JanetBuffer *buf);
|
||||||
|
static int32_t JanetHashDb(void *data0, size_t size);
|
||||||
|
static int JanetCloseDb(void *data0, size_t size);
|
||||||
|
static Janet JanetDbNext(void *data0, Janet next);
|
||||||
|
|
||||||
|
static Janet JanetRefClose(int32_t argc, Janet *argv);
|
||||||
|
static Janet JanetRefGet(int32_t argc, Janet *argv);
|
||||||
|
static Janet JanetRefSet(int32_t argc, Janet *argv);
|
||||||
|
static const JanetMethod db_methods[] = {
|
||||||
|
{ "get", JanetRefGet },
|
||||||
|
{ "set", JanetRefSet },
|
||||||
|
{ "close", JanetRefClose },
|
||||||
|
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
const JanetAbstractType janet_db_type = {
|
||||||
|
.name = "db-ref",
|
||||||
|
.gc = JanetCloseDb, .gcmark = NULL,
|
||||||
|
|
||||||
|
.get = JanetDbGet, .put = NULL,
|
||||||
|
.marshal = JanetMarshalDb, .unmarshal = JanetUnmarshalDb,
|
||||||
|
.tostring = JanetDbToString,
|
||||||
|
|
||||||
|
.compare = NULL,
|
||||||
|
.hash = JanetHashDb,
|
||||||
|
|
||||||
|
.next = JanetDbNext,
|
||||||
|
JANET_ATEND_NEXT
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct DbAndRef {
|
||||||
|
Db *database;
|
||||||
|
DbRef *ref;
|
||||||
|
|
||||||
|
bool valid;
|
||||||
|
} DbAndRef;
|
||||||
|
|
||||||
|
static Janet
|
||||||
|
CreateFromDb(Db *db, DbRef *ref)
|
||||||
|
{
|
||||||
|
JanetAbstract *abs;
|
||||||
|
|
||||||
|
abs = janet_abstract(&janet_db_type, sizeof(DbAndRef));
|
||||||
|
((DbAndRef *)(abs))->database = db;
|
||||||
|
((DbAndRef *)(abs))->ref = ref;
|
||||||
|
((DbAndRef *)(abs))->valid = true;
|
||||||
|
|
||||||
|
return janet_wrap_abstract(abs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
CloseFromJanet(Janet v)
|
||||||
|
{
|
||||||
|
DbAndRef *indirect = janet_checkabstract(v, &janet_db_type);
|
||||||
|
if (indirect)
|
||||||
|
{
|
||||||
|
indirect->valid = false;
|
||||||
|
indirect->database = NULL;
|
||||||
|
indirect->ref = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static DbRef *
|
||||||
|
RefFromJanet(Janet v)
|
||||||
|
{
|
||||||
|
DbAndRef *indirect = janet_checkabstract(v, &janet_db_type);
|
||||||
|
return (indirect && indirect->valid) ? indirect->ref : NULL;
|
||||||
|
}
|
||||||
|
static Db *
|
||||||
|
DbFromJanet(Janet v)
|
||||||
|
{
|
||||||
|
DbAndRef *indirect = janet_checkabstract(v, &janet_db_type);
|
||||||
|
return (indirect && indirect->valid) ? indirect->database : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
JanetDbGet(void *data0, Janet key, Janet *out)
|
||||||
|
{
|
||||||
|
JanetKeyword kw;
|
||||||
|
if (!janet_checktype(key, JANET_KEYWORD))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kw = janet_unwrap_keyword(key);
|
||||||
|
(void) data0;
|
||||||
|
return janet_getmethod(kw, db_methods, out);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
JanetMarshalDb(void *data0, JanetMarshalContext *ctx)
|
||||||
|
{
|
||||||
|
janet_marshal_abstract(ctx, data0);
|
||||||
|
}
|
||||||
|
static void *
|
||||||
|
JanetUnmarshalDb(JanetMarshalContext *ctx)
|
||||||
|
{
|
||||||
|
DbAndRef *data = janet_unmarshal_abstract(ctx, sizeof(DbAndRef));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
static int
|
||||||
|
JanetCloseDb(void *data0, size_t size)
|
||||||
|
{
|
||||||
|
DbAndRef *data = data0;
|
||||||
|
if (data && data->valid)
|
||||||
|
{
|
||||||
|
data->valid = false;
|
||||||
|
DbUnlock(data->database, data->ref);
|
||||||
|
data->database = NULL;
|
||||||
|
data->ref = NULL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
JanetDbToString(void *data0, JanetBuffer *buf)
|
||||||
|
{
|
||||||
|
janet_buffer_push_cstring(buf, "[" NAME " database reference]");
|
||||||
|
}
|
||||||
|
static int32_t
|
||||||
|
JanetHashDb(void *data0, size_t size)
|
||||||
|
{
|
||||||
|
uintptr_t datap = (uintptr_t) data0;
|
||||||
|
|
||||||
|
(void) size;
|
||||||
|
/* Hm. */
|
||||||
|
return (int32_t) datap;
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetDbNext(void *data0, Janet next)
|
||||||
|
{
|
||||||
|
(void) data0;
|
||||||
|
return janet_nextmethod(db_methods, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet
|
||||||
|
JanetRefClose(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
Db *db;
|
||||||
|
DbRef *ref;
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
|
||||||
|
if (!(ref = RefFromJanet(argv[0])) ||
|
||||||
|
!(db = DbFromJanet(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR,
|
||||||
|
janet_cstringv("self isnt a DbRef *")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
DbUnlock(db, ref);
|
||||||
|
CloseFromJanet(argv[0]);
|
||||||
|
return janet_wrap_true();
|
||||||
|
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetRefGet(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
DbRef *ref;
|
||||||
|
HashMap *json;
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
|
||||||
|
if (!(ref = RefFromJanet(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR,
|
||||||
|
janet_cstringv("self isnt a DbRef *")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
json = DbJson(ref);
|
||||||
|
return JsonToJanet(json);
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetRefSet(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
DbRef *ref;
|
||||||
|
JanetTable *table;
|
||||||
|
HashMap *json;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
janet_fixarity(argc, 2);
|
||||||
|
|
||||||
|
if (!(ref = RefFromJanet(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR,
|
||||||
|
janet_cstringv("self isnt a DbRef *")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype(argv[1], JANET_TABLE))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR,
|
||||||
|
janet_cstringv("object to replace isnt JSON")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
table = janet_unwrap_table(argv[1]);
|
||||||
|
if (!(json = JanetToJson(table)))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR,
|
||||||
|
janet_cstringv("object to replace isnt JSON")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = DbJsonSet(ref, json);
|
||||||
|
JsonFree(json);
|
||||||
|
|
||||||
|
return janet_wrap_boolean(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Janet
|
||||||
|
JanetDbExists(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
Array *args;
|
||||||
|
int32_t i;
|
||||||
|
bool ret;
|
||||||
|
janet_arity(argc, 2, -1);
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR,
|
||||||
|
janet_cstringv("self isnt a ParseeData *")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
args = ArrayCreate();
|
||||||
|
for (i = 1; i < argc; i++)
|
||||||
|
{
|
||||||
|
char *string = (char *) janet_to_string(argv[i]);
|
||||||
|
ArrayAdd(args, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = DbExistsArgs(data->db, args);
|
||||||
|
ArrayFree(args);
|
||||||
|
|
||||||
|
return janet_wrap_boolean(ret);
|
||||||
|
}
|
||||||
|
Janet
|
||||||
|
JanetDbList(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
Array *args, *list;
|
||||||
|
JanetArray *arr;
|
||||||
|
int32_t i;
|
||||||
|
janet_arity(argc, 1, -1);
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR,
|
||||||
|
janet_cstringv("self isnt a ParseeData *")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
args = ArrayCreate();
|
||||||
|
for (i = 1; i < argc; i++)
|
||||||
|
{
|
||||||
|
char *string = (char *) janet_to_string(argv[i]);
|
||||||
|
ArrayAdd(args, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
list = DbListArgs(data->db, args);
|
||||||
|
arr = janet_array(0);
|
||||||
|
for (i = 0; i < (int32_t) ArraySize(list); i++)
|
||||||
|
{
|
||||||
|
char *ent = ArrayGet(list, i);
|
||||||
|
janet_array_push(arr, janet_cstringv(ent));
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayFree(args);
|
||||||
|
DbListFree(list);
|
||||||
|
return janet_wrap_array(arr);
|
||||||
|
}
|
||||||
|
Janet
|
||||||
|
JanetDbLock(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
Array *args;
|
||||||
|
DbRef *ref;
|
||||||
|
int32_t i;
|
||||||
|
janet_arity(argc, 2, -1);
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR,
|
||||||
|
janet_cstringv("self isnt a ParseeData *")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
args = ArrayCreate();
|
||||||
|
for (i = 1; i < argc; i++)
|
||||||
|
{
|
||||||
|
char *string = (char *) janet_to_string(argv[i]);
|
||||||
|
ArrayAdd(args, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
ref = DbLockArgs(data->db, args);
|
||||||
|
ArrayFree(args);
|
||||||
|
|
||||||
|
if (!ref)
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR,
|
||||||
|
janet_cstringv("couldn't lock database")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateFromDb(data->db, ref);
|
||||||
|
}
|
||||||
|
Janet
|
||||||
|
JanetDbCreate(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
Array *args;
|
||||||
|
DbRef *ref;
|
||||||
|
int32_t i;
|
||||||
|
janet_arity(argc, 2, -1);
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR,
|
||||||
|
janet_cstringv("self isnt a ParseeData *")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
args = ArrayCreate();
|
||||||
|
for (i = 1; i < argc; i++)
|
||||||
|
{
|
||||||
|
char *string = (char *) janet_to_string(argv[i]);
|
||||||
|
ArrayAdd(args, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
ref = DbCreateArgs(data->db, args);
|
||||||
|
ArrayFree(args);
|
||||||
|
|
||||||
|
if (!ref)
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR,
|
||||||
|
janet_cstringv("couldn't create database")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateFromDb(data->db, ref);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
222
src/Extensions/Data.c
Normal file
222
src/Extensions/Data.c
Normal file
|
|
@ -0,0 +1,222 @@
|
||||||
|
#ifdef JANET
|
||||||
|
|
||||||
|
#include "Extensions/Internal.h"
|
||||||
|
#include "Extensions/Functions.h"
|
||||||
|
|
||||||
|
static int JanetDataGet(void *data0, Janet key, Janet *out);
|
||||||
|
static void JanetMarshalData(void *data0, JanetMarshalContext *ctx);
|
||||||
|
static void *JanetUnmarshalData(JanetMarshalContext *ctx);
|
||||||
|
static void JanetDataToString(void *data0, JanetBuffer *buf);
|
||||||
|
static int32_t JanetHashData(void *data0, size_t size);
|
||||||
|
static Janet JanetDataNext(void *data0, Janet next);
|
||||||
|
|
||||||
|
static Janet JanetShimMXC(int32_t argc, Janet *argv);
|
||||||
|
static Janet JanetMTO(int32_t argc, Janet *argv);
|
||||||
|
static Janet JanetIsAdmin(int32_t argc, Janet *argv);
|
||||||
|
static Janet JanetUptime(int32_t argc, Janet *argv);
|
||||||
|
static Janet JanetGlobalBan(int32_t argc, Janet *argv);
|
||||||
|
static const JanetMethod data_methods[] = {
|
||||||
|
/* Matrix */
|
||||||
|
{ "matrix/invite", JanetMatrixInvite },
|
||||||
|
{ "matrix/find", JanetMatrixFind },
|
||||||
|
{ "matrix/send", JanetMatrixSend },
|
||||||
|
{ "matrix/shim-mxc", JanetShimMXC },
|
||||||
|
{ "matrix/matrix-to", JanetMTO },
|
||||||
|
|
||||||
|
/* Bridge */
|
||||||
|
{ "bridge/get", JanetGetKey },
|
||||||
|
{ "bridge/set", JanetSetKey },
|
||||||
|
{ "bridge/stanza-info", JanetStanzaInfo },
|
||||||
|
|
||||||
|
/* XMPP */
|
||||||
|
{ "xmpp/write", JanetWriteStanza },
|
||||||
|
|
||||||
|
/* Database */
|
||||||
|
{ "db/lock", JanetDbLock },
|
||||||
|
{ "db/exists?", JanetDbExists },
|
||||||
|
{ "db/create", JanetDbCreate },
|
||||||
|
{ "db/list", JanetDbList },
|
||||||
|
|
||||||
|
/* General */
|
||||||
|
{ "admin?", JanetIsAdmin },
|
||||||
|
{ "uptime", JanetUptime },
|
||||||
|
{ "global-ban", JanetGlobalBan },
|
||||||
|
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const JanetAbstractType janet_data_type = {
|
||||||
|
.name = "parsee-ctx",
|
||||||
|
.gc = NULL, .gcmark = NULL,
|
||||||
|
|
||||||
|
.get = JanetDataGet, .put = NULL,
|
||||||
|
.marshal = JanetMarshalData, .unmarshal = JanetUnmarshalData,
|
||||||
|
.tostring = JanetDataToString,
|
||||||
|
|
||||||
|
.compare = NULL,
|
||||||
|
.hash = JanetHashData,
|
||||||
|
|
||||||
|
.next = JanetDataNext,
|
||||||
|
JANET_ATEND_NEXT
|
||||||
|
};
|
||||||
|
|
||||||
|
ParseeData *
|
||||||
|
GetParseeData(Janet v)
|
||||||
|
{
|
||||||
|
ParseeData **indirect = janet_checkabstract(v, &janet_data_type);
|
||||||
|
return indirect ? *indirect : NULL;
|
||||||
|
}
|
||||||
|
Janet
|
||||||
|
FromParseeData(ParseeData *data)
|
||||||
|
{
|
||||||
|
JanetAbstract abs;
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
abs = janet_abstract(&janet_data_type, sizeof(ParseeData *));
|
||||||
|
*((ParseeData **) abs) = data;
|
||||||
|
return janet_wrap_abstract(abs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
JanetDataGet(void *data0, Janet key, Janet *out)
|
||||||
|
{
|
||||||
|
JanetKeyword kw;
|
||||||
|
if (!janet_checktype(key, JANET_KEYWORD))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kw = janet_unwrap_keyword(key);
|
||||||
|
(void) data0;
|
||||||
|
return janet_getmethod(kw, data_methods, out);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
JanetMarshalData(void *data0, JanetMarshalContext *ctx)
|
||||||
|
{
|
||||||
|
janet_marshal_abstract(ctx, data0);
|
||||||
|
}
|
||||||
|
static void *
|
||||||
|
JanetUnmarshalData(JanetMarshalContext *ctx)
|
||||||
|
{
|
||||||
|
ParseeData **data = janet_unmarshal_abstract(ctx, sizeof(ParseeData *));
|
||||||
|
return data ? *data : NULL;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
JanetDataToString(void *data0, JanetBuffer *buf)
|
||||||
|
{
|
||||||
|
janet_buffer_push_cstring(buf, "[" NAME " context type]");
|
||||||
|
}
|
||||||
|
static int32_t
|
||||||
|
JanetHashData(void *data0, size_t size)
|
||||||
|
{
|
||||||
|
uintptr_t datap = (uintptr_t) data0;
|
||||||
|
|
||||||
|
(void) size;
|
||||||
|
/* We're casting down, but in a context where there is really
|
||||||
|
* just one ParseeData, is that really such a crime? */
|
||||||
|
return (int32_t) datap;
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetDataNext(void *data0, Janet next)
|
||||||
|
{
|
||||||
|
(void) data0;
|
||||||
|
return janet_nextmethod(data_methods, next);
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetIsAdmin(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
char *str;
|
||||||
|
janet_fixarity(argc, 2);
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
str = (char *) janet_to_string(argv[1]);
|
||||||
|
|
||||||
|
return janet_wrap_boolean(ParseeIsAdmin(data, str));
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetShimMXC(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
Janet v;
|
||||||
|
char *mxc, *shimmed;
|
||||||
|
janet_fixarity(argc, 2);
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
mxc = (char *) janet_to_string(argv[1]);
|
||||||
|
shimmed = ParseeToUnauth(data, mxc);
|
||||||
|
if (!shimmed)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
v = janet_cstringv(shimmed);
|
||||||
|
Free(shimmed);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetMTO(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
Janet v;
|
||||||
|
char *common, *mto;
|
||||||
|
janet_fixarity(argc, 2);
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
common = (char *) janet_to_string(argv[1]);
|
||||||
|
mto = ParseeGenerateMTO(common);
|
||||||
|
if (!mto)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
v = janet_cstringv(mto);
|
||||||
|
Free(mto);
|
||||||
|
|
||||||
|
(void) data;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetUptime(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) data;
|
||||||
|
return janet_wrap_number(ParseeUptime()/1000.);
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetGlobalBan(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
const char *user, *reason = NULL;
|
||||||
|
janet_arity(argc, 2, 3);
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!(user = janet_getcstring(argv, 1)))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (argc == 3 && janet_checktype(argv[2], JANET_STRING))
|
||||||
|
{
|
||||||
|
reason = janet_getcstring(argv, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseeGlobalBan(data, (char *) user, (char *) reason);
|
||||||
|
return janet_wrap_true();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
207
src/Extensions/Functions.c
Normal file
207
src/Extensions/Functions.c
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
#ifdef JANET
|
||||||
|
#include "Extensions/Internal.h"
|
||||||
|
|
||||||
|
#include "Extensions/Functions.h"
|
||||||
|
|
||||||
|
Janet
|
||||||
|
JanetMilliseconds(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
janet_fixarity(argc, 0);
|
||||||
|
return janet_wrap_number(UtilTsMillis()/1000.);
|
||||||
|
}
|
||||||
|
Janet
|
||||||
|
JanetCytoVersion(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
janet_fixarity(argc, 0);
|
||||||
|
return janet_cstringv(CytoplasmGetVersionStr());
|
||||||
|
}
|
||||||
|
static const JanetReg functions[] = {
|
||||||
|
/* Cytoplasm */
|
||||||
|
{
|
||||||
|
"cyto/version", JanetCytoVersion,
|
||||||
|
"(cyto/version)\n\n"
|
||||||
|
"Returns the Cytoplasm version as a string."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cyto/ts", JanetMilliseconds,
|
||||||
|
"(cyto/ts)\n\n"
|
||||||
|
"Returns the timestamp as seconds since 01-01-1970."
|
||||||
|
},
|
||||||
|
|
||||||
|
/* XML */
|
||||||
|
{
|
||||||
|
"xml/data", JanetCreateXMLData,
|
||||||
|
"(xml/data [PARENT?] [TEXT])\n\n"
|
||||||
|
"Creates a data XML element with freeform text."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"xml/tag", JanetCreateXMLTag,
|
||||||
|
"(xml/tag [PARENT?] [NAME])\n\n"
|
||||||
|
"Creates a simple XML tag with a name"
|
||||||
|
},
|
||||||
|
|
||||||
|
/* JSON */
|
||||||
|
{
|
||||||
|
"json/parse", JanetParseJSON,
|
||||||
|
"(json/parse [INPUT:buffer]) -> table|NIL\n\n"
|
||||||
|
"Parses a JSON buffer into a table."
|
||||||
|
},
|
||||||
|
|
||||||
|
/* HTTP */
|
||||||
|
{
|
||||||
|
"http/request", JanetHttpRequest,
|
||||||
|
"(http/request "
|
||||||
|
"[METHOD:string] "
|
||||||
|
"[URL:string] "
|
||||||
|
"[HEADERS:table?] "
|
||||||
|
"[DATA:buffer])\n\n"
|
||||||
|
"Creates and sends an HTTP request, and returns an HTTP response"
|
||||||
|
},
|
||||||
|
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
void
|
||||||
|
SetupBasicExtensionContext(Extension *ext, JanetTable *env)
|
||||||
|
{
|
||||||
|
char *parsee;
|
||||||
|
/* Constants */
|
||||||
|
janet_def(ext->env,
|
||||||
|
"parsee/ctx", FromParseeData(ext->source->data),
|
||||||
|
"The Parsee context used, which maps directly to a ParseeData "
|
||||||
|
"structure pointer in C99land. Used in various functions."
|
||||||
|
);
|
||||||
|
|
||||||
|
parsee = ParseeJID(ext->source->data);
|
||||||
|
janet_def(ext->env,
|
||||||
|
"parsee/jid", janet_cstringv(parsee),
|
||||||
|
"The Parsee bot's Jabber ID as a string"
|
||||||
|
);
|
||||||
|
Free(parsee);
|
||||||
|
|
||||||
|
parsee = ParseeMXID(ext->source->data);
|
||||||
|
janet_def(ext->env,
|
||||||
|
"parsee/mxid", janet_cstringv(parsee),
|
||||||
|
"The Parsee bot's MXID as a string"
|
||||||
|
);
|
||||||
|
Free(parsee);
|
||||||
|
|
||||||
|
janet_def(ext->env,
|
||||||
|
"parsee/id", janet_cstringv(ext->id),
|
||||||
|
"The extension's 'identifier'(reverse DNS) notation."
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Functions */
|
||||||
|
janet_cfuns(env, "parsee", functions);
|
||||||
|
|
||||||
|
/* "Why bother with C99?" */
|
||||||
|
#define CheckType(var, type, str) \
|
||||||
|
"(if (not= (type " #var ") :" #type ") (error `" str "`))"
|
||||||
|
janet_dostring(ext->env,
|
||||||
|
"(defn xml/get-attr[xml key] "
|
||||||
|
CheckType(xml, table, "XML is not a table")
|
||||||
|
CheckType(key, string, "KEY is not a string")
|
||||||
|
"(get (get xml :xml-attrs) key) "
|
||||||
|
")"
|
||||||
|
, "embed:" __FILE__, NULL
|
||||||
|
);
|
||||||
|
janet_dostring(ext->env,
|
||||||
|
"(defn xml/set-attr[xml key val] "
|
||||||
|
CheckType(xml, table, "XML is not a table")
|
||||||
|
CheckType(key, string, "KEY is not a string")
|
||||||
|
CheckType(val, string, "VAL is not a string")
|
||||||
|
"(put (get xml :xml-attrs) key val) "
|
||||||
|
|
||||||
|
/* Just to make sure this function returns NIL */
|
||||||
|
"nil"
|
||||||
|
")"
|
||||||
|
, "embed:" __FILE__, NULL
|
||||||
|
);
|
||||||
|
janet_dostring(ext->env,
|
||||||
|
"(defn xmppcmd/create-note [type msg] "
|
||||||
|
"(def note (xml/tag `note`)) "
|
||||||
|
"(def mesg (xml/data note msg)) "
|
||||||
|
|
||||||
|
"(xml/set-attr note `type` type) "
|
||||||
|
|
||||||
|
"note"
|
||||||
|
")"
|
||||||
|
, "embed:" __FILE__, NULL
|
||||||
|
);
|
||||||
|
janet_dostring(ext->env,
|
||||||
|
"(defn xmppcmd/create-form [] "
|
||||||
|
"(def x (xml/tag `x`)) "
|
||||||
|
"(xml/set-attr x `xmlns` `jabber:x:data`) "
|
||||||
|
|
||||||
|
"x"
|
||||||
|
")"
|
||||||
|
, "embed:" __FILE__, NULL
|
||||||
|
);
|
||||||
|
janet_dostring(ext->env,
|
||||||
|
"(defn xmppcmd/set-form-title [x title] "
|
||||||
|
"(def title-xml (xml/tag x `title`)) "
|
||||||
|
"(def title-txt (xml/data title-xml title)) "
|
||||||
|
|
||||||
|
"title-xml"
|
||||||
|
")"
|
||||||
|
, "embed:" __FILE__, NULL
|
||||||
|
);
|
||||||
|
janet_dostring(ext->env,
|
||||||
|
"(defn xmppcmd/generate-table [x fields elems] "
|
||||||
|
CheckType(x, table, "Form is not a table")
|
||||||
|
CheckType(fields, table, "Fields is not a table")
|
||||||
|
CheckType(elems, array, "Elems is not an array")
|
||||||
|
|
||||||
|
"(def reported (xml/tag x `reported`)) "
|
||||||
|
|
||||||
|
"(loop [[id name] :pairs fields] "
|
||||||
|
"(def field (xml/tag reported `field`)) "
|
||||||
|
"(xml/set-attr field `var` id) "
|
||||||
|
"(xml/set-attr field `label` name) "
|
||||||
|
") "
|
||||||
|
|
||||||
|
"(loop [entry :in elems] "
|
||||||
|
CheckType(entry, table, "Entry is not a table.")
|
||||||
|
"(def xml-entry (xml/tag x `item`)) "
|
||||||
|
|
||||||
|
"(loop [[id val] :pairs entry] "
|
||||||
|
"(def xml-field (xml/tag xml-entry `field`)) "
|
||||||
|
"(def xml-value (xml/tag xml-field `value`)) "
|
||||||
|
"(xml/data xml-value val) "
|
||||||
|
"(xml/set-attr xml-field `var` id) "
|
||||||
|
") "
|
||||||
|
") "
|
||||||
|
")"
|
||||||
|
, "embed:" __FILE__, NULL
|
||||||
|
);
|
||||||
|
janet_dostring(ext->env,
|
||||||
|
"(defn xmppcmd/find-tag [xml tag] "
|
||||||
|
"(var ret nil) "
|
||||||
|
"(loop [xml-field :in (get xml :xml-children)] "
|
||||||
|
"(if (= (get xml-field :xml-name) tag) (do"
|
||||||
|
"(set ret xml-field) "
|
||||||
|
"(break)"
|
||||||
|
")) "
|
||||||
|
") "
|
||||||
|
"ret "
|
||||||
|
")"
|
||||||
|
, "embed:" __FILE__, NULL
|
||||||
|
);
|
||||||
|
janet_dostring(ext->env,
|
||||||
|
"(defn xmppcmd/get-field [submit key] "
|
||||||
|
CheckType(submit, table, "Input is not a table")
|
||||||
|
"(var value nil) "
|
||||||
|
"(loop [xml-field :in (get submit :xml-children)] "
|
||||||
|
"(if (and (= (get xml-field :xml-name) `field`) (= (get (get xml-field :xml-attrs) `var`) key)) (do"
|
||||||
|
"(set value (xmppcmd/find-tag xml-field `value`)) "
|
||||||
|
"(set value (get (get (get value :xml-children) 0) :xml-data)) "
|
||||||
|
"(break)"
|
||||||
|
")) "
|
||||||
|
") "
|
||||||
|
"value "
|
||||||
|
") "
|
||||||
|
, "embed:" __FILE__, NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
#undef CheckType
|
||||||
|
}
|
||||||
|
#endif
|
||||||
34
src/Extensions/Functions.h
Normal file
34
src/Extensions/Functions.h
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
#ifdef JANET
|
||||||
|
|
||||||
|
#include <janet.h>
|
||||||
|
|
||||||
|
#define Bind(name) Janet Janet##name(int32_t argc, Janet *argv)
|
||||||
|
|
||||||
|
|
||||||
|
Bind(Milliseconds);
|
||||||
|
Bind(CytoVersion);
|
||||||
|
|
||||||
|
Bind(WriteStanza);
|
||||||
|
|
||||||
|
Bind(CreateXMLData);
|
||||||
|
Bind(CreateXMLTag);
|
||||||
|
Bind(SetXMLAttr);
|
||||||
|
|
||||||
|
Bind(ParseJSON);
|
||||||
|
|
||||||
|
Bind(MatrixInvite);
|
||||||
|
Bind(MatrixFind);
|
||||||
|
Bind(MatrixSend);
|
||||||
|
|
||||||
|
Bind(StanzaInfo);
|
||||||
|
Bind(GetKey);
|
||||||
|
Bind(SetKey);
|
||||||
|
|
||||||
|
Bind(DbLock);
|
||||||
|
Bind(DbCreate);
|
||||||
|
Bind(DbList);
|
||||||
|
Bind(DbExists);
|
||||||
|
|
||||||
|
Bind(HttpRequest);
|
||||||
|
|
||||||
|
#endif
|
||||||
258
src/Extensions/Http.c
Normal file
258
src/Extensions/Http.c
Normal file
|
|
@ -0,0 +1,258 @@
|
||||||
|
#ifdef JANET
|
||||||
|
|
||||||
|
#include "Extensions/Internal.h"
|
||||||
|
#include "Extensions/Functions.h"
|
||||||
|
|
||||||
|
#include <Cytoplasm/Uri.h>
|
||||||
|
#include <Cytoplasm/HttpClient.h>
|
||||||
|
|
||||||
|
static int JanetHttpGet(void *http0, Janet key, Janet *out);
|
||||||
|
static void JanetMarshalHttp(void *http0, JanetMarshalContext *ctx);
|
||||||
|
static void *JanetUnmarshalHttp(JanetMarshalContext *ctx);
|
||||||
|
static void JanetHttpToString(void *http0, JanetBuffer *buf);
|
||||||
|
static int32_t JanetHashHttp(void *http0, size_t size);
|
||||||
|
static Janet JanetHttpNext(void *http0, Janet next);
|
||||||
|
static int JanetCloseHttp(void *data0, size_t size);
|
||||||
|
|
||||||
|
static Janet JanetHttpCode(int32_t argc, Janet *argv);
|
||||||
|
static Janet JanetHttpHeaders(int32_t argc, Janet *argv);
|
||||||
|
static Janet JanetHttpResponse(int32_t argc, Janet *argv);
|
||||||
|
static const JanetMethod http_methods[] = {
|
||||||
|
{ "code", JanetHttpCode },
|
||||||
|
{ "headers", JanetHttpHeaders },
|
||||||
|
{ "response", JanetHttpResponse },
|
||||||
|
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct HttpStruct {
|
||||||
|
int code;
|
||||||
|
HashMap *headers;
|
||||||
|
|
||||||
|
uint8_t *data;
|
||||||
|
int32_t size;
|
||||||
|
} HttpStruct;
|
||||||
|
|
||||||
|
const JanetAbstractType janet_http_type = {
|
||||||
|
.name = "http-response",
|
||||||
|
.gc = JanetCloseHttp, .gcmark = NULL,
|
||||||
|
|
||||||
|
.get = JanetHttpGet, .put = NULL,
|
||||||
|
.marshal = JanetMarshalHttp, .unmarshal = JanetUnmarshalHttp,
|
||||||
|
.tostring = JanetHttpToString,
|
||||||
|
|
||||||
|
.compare = NULL,
|
||||||
|
.hash = JanetHashHttp,
|
||||||
|
|
||||||
|
.next = JanetHttpNext,
|
||||||
|
JANET_ATEND_NEXT
|
||||||
|
};
|
||||||
|
Janet
|
||||||
|
JanetHttpRequest(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
const char *method_str = NULL;
|
||||||
|
const char *path_str = NULL;
|
||||||
|
JanetTable *headers = NULL;
|
||||||
|
JanetAbstract *abs = NULL;
|
||||||
|
JanetBuffer *data = NULL;
|
||||||
|
HttpClientContext *ctx;
|
||||||
|
HashMap *raw_headers;
|
||||||
|
char *header, *value;
|
||||||
|
HttpStruct *http;
|
||||||
|
int code, ch;
|
||||||
|
int32_t i;
|
||||||
|
Uri *url;
|
||||||
|
|
||||||
|
janet_arity(argc, 2, 4);
|
||||||
|
if (!(method_str = janet_getcstring(argv, 0)) ||
|
||||||
|
!(path_str = janet_getcstring(argv, 1)))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (argc >= 3)
|
||||||
|
{
|
||||||
|
headers = janet_gettable(argv, 2);
|
||||||
|
}
|
||||||
|
if (argc >= 4)
|
||||||
|
{
|
||||||
|
data = janet_getbuffer(argv, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
url = UriParse(path_str);
|
||||||
|
if (!url ||
|
||||||
|
(!StrEquals(url->proto, "http") && !StrEquals(url->proto, "https")))
|
||||||
|
{
|
||||||
|
UriFree(url);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!url->port || StrEquals(url->proto, "http"))
|
||||||
|
{
|
||||||
|
url->port = 80;
|
||||||
|
}
|
||||||
|
if (!url->port || StrEquals(url->proto, "https"))
|
||||||
|
{
|
||||||
|
url->port = 443;
|
||||||
|
}
|
||||||
|
ctx = HttpRequest(
|
||||||
|
HttpRequestMethodFromString(method_str),
|
||||||
|
StrEquals(url->proto, "https") ? HTTP_FLAG_TLS : HTTP_FLAG_NONE,
|
||||||
|
url->port, url->host, url->path
|
||||||
|
);
|
||||||
|
UriFree(url);
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; headers && i < headers->capacity; i++)
|
||||||
|
{
|
||||||
|
JanetKV kv = headers->data[i];
|
||||||
|
char *key, *value;
|
||||||
|
if (!janet_checktype(kv.key, JANET_STRING))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = (char *) janet_unwrap_string(kv.key);
|
||||||
|
value = (char *) janet_to_string(kv.value);
|
||||||
|
HttpRequestHeader(ctx, key, value);
|
||||||
|
}
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
char *len_str = StrInt((int) data->count);
|
||||||
|
HttpRequestHeader(ctx, "Content-Length", len_str);
|
||||||
|
Free(len_str);
|
||||||
|
}
|
||||||
|
HttpRequestSendHeaders(ctx);
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
for (i = 0; i < data->count; i++)
|
||||||
|
{
|
||||||
|
uint8_t byte = data->data[i];
|
||||||
|
StreamPutc(HttpClientStream(ctx), byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
code = HttpRequestSend(ctx);
|
||||||
|
raw_headers = HttpResponseHeaders(ctx);
|
||||||
|
|
||||||
|
abs = janet_abstract(&janet_http_type, sizeof(HttpStruct));
|
||||||
|
http = (HttpStruct *) abs;
|
||||||
|
http->code = code;
|
||||||
|
http->headers = HashMapCreate();
|
||||||
|
http->size = 0;
|
||||||
|
http->data = NULL;
|
||||||
|
while (HashMapIterate(raw_headers, &header, (void **) &value))
|
||||||
|
{
|
||||||
|
HashMapSet(http->headers, header, StrDuplicate(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((ch = StreamGetc(HttpClientStream(ctx))) != EOF)
|
||||||
|
{
|
||||||
|
http->data = Realloc(http->data, ++(http->size));
|
||||||
|
http->data[http->size-1] = ch;
|
||||||
|
}
|
||||||
|
HttpClientContextFree(ctx);
|
||||||
|
|
||||||
|
return janet_wrap_abstract(abs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
JanetHttpGet(void *http0, Janet key, Janet *out)
|
||||||
|
{
|
||||||
|
JanetKeyword kw;
|
||||||
|
if (!janet_checktype(key, JANET_KEYWORD))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kw = janet_unwrap_keyword(key);
|
||||||
|
(void) http0;
|
||||||
|
return janet_getmethod(kw, http_methods, out);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
JanetMarshalHttp(void *http0, JanetMarshalContext *ctx)
|
||||||
|
{
|
||||||
|
janet_marshal_abstract(ctx, http0);
|
||||||
|
}
|
||||||
|
static void *
|
||||||
|
JanetUnmarshalHttp(JanetMarshalContext *ctx)
|
||||||
|
{
|
||||||
|
HttpStruct *http = janet_unmarshal_abstract(ctx, sizeof(HttpStruct));
|
||||||
|
return http;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
JanetHttpToString(void *http0, JanetBuffer *buf)
|
||||||
|
{
|
||||||
|
janet_buffer_push_cstring(buf, "[" NAME " HTTP object]");
|
||||||
|
}
|
||||||
|
static int32_t
|
||||||
|
JanetHashHttp(void *http0, size_t size)
|
||||||
|
{
|
||||||
|
uintptr_t httpp = (uintptr_t) http0;
|
||||||
|
|
||||||
|
(void) size;
|
||||||
|
return (int32_t) httpp;
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetHttpNext(void *http0, Janet next)
|
||||||
|
{
|
||||||
|
(void) http0;
|
||||||
|
return janet_nextmethod(http_methods, next);
|
||||||
|
}
|
||||||
|
static int
|
||||||
|
JanetCloseHttp(void *data0, size_t size)
|
||||||
|
{
|
||||||
|
HttpStruct *http = data0;
|
||||||
|
char *key;
|
||||||
|
void *val;
|
||||||
|
|
||||||
|
while (HashMapIterate(http->headers, &key, &val))
|
||||||
|
{
|
||||||
|
Free(val);
|
||||||
|
}
|
||||||
|
HashMapFree(http->headers);
|
||||||
|
Free(http->data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetHttpCode(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
JanetAbstract *abs;
|
||||||
|
HttpStruct *http;
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
|
||||||
|
abs = janet_getabstract(argv, 0, &janet_http_type);
|
||||||
|
if (!abs)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
http = (HttpStruct *) abs;
|
||||||
|
|
||||||
|
return janet_wrap_integer(http->code);
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetHttpHeaders(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetHttpResponse(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
JanetBuffer *buffer;
|
||||||
|
JanetAbstract *abs;
|
||||||
|
HttpStruct *http;
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
|
||||||
|
abs = janet_getabstract(argv, 0, &janet_http_type);
|
||||||
|
if (!abs)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
http = (HttpStruct *) abs;
|
||||||
|
|
||||||
|
buffer = janet_buffer(http->size + 1);
|
||||||
|
janet_buffer_push_bytes(buffer, (const uint8_t *) http->data, http->size);
|
||||||
|
|
||||||
|
return janet_wrap_buffer(buffer);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
98
src/Extensions/Internal.h
Normal file
98
src/Extensions/Internal.h
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
#ifndef PARSEE_IEXTENSIONS_H
|
||||||
|
#define PARSEE_IEXTENSIONS_H
|
||||||
|
#ifdef JANET
|
||||||
|
|
||||||
|
#include <Extension.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm/Cytoplasm.h>
|
||||||
|
#include <Cytoplasm/HashMap.h>
|
||||||
|
#include <Cytoplasm/Memory.h>
|
||||||
|
#include <Cytoplasm/Stream.h>
|
||||||
|
#include <Cytoplasm/Util.h>
|
||||||
|
#include <Cytoplasm/Json.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
#include <Cytoplasm/Log.h>
|
||||||
|
|
||||||
|
#include <XMPPCommand.h>
|
||||||
|
#include <Parsee.h>
|
||||||
|
#include <XML.h>
|
||||||
|
|
||||||
|
#include <janet.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define JANET_STANZA_PUSH 0
|
||||||
|
#define JANET_REQUEST_XMPPCMD 1
|
||||||
|
#define JANET_REQUEST_XMPPCMD_A 2
|
||||||
|
#define JANET_REQUEST_XMPPCMD_F 3
|
||||||
|
|
||||||
|
struct Extensions {
|
||||||
|
HashMap *extensions;
|
||||||
|
size_t count;
|
||||||
|
|
||||||
|
ParseeData *data;
|
||||||
|
|
||||||
|
pthread_mutex_t mtx;
|
||||||
|
};
|
||||||
|
struct Extension {
|
||||||
|
Extensions *source;
|
||||||
|
|
||||||
|
JanetTable *env;
|
||||||
|
JanetVM *vm;
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
uint8_t *bytes;
|
||||||
|
size_t len;
|
||||||
|
char *file;
|
||||||
|
|
||||||
|
JanetFiber *stanzas;
|
||||||
|
|
||||||
|
pthread_t thr;
|
||||||
|
volatile bool halted;
|
||||||
|
|
||||||
|
XMPPCommandManager *manager;
|
||||||
|
JanetTable *functions;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Creates a Janet table from an XML element. For all sensical
|
||||||
|
* usecases, set in to NULL.
|
||||||
|
* -----------------------
|
||||||
|
* Returns: a wrapped Janet table[janet] */
|
||||||
|
Janet ExtensionsFromXML(JanetArray *in, XMLElement *e);
|
||||||
|
|
||||||
|
/** Takes a Janet table and tries to encode it as XML.
|
||||||
|
* ----------------
|
||||||
|
* Returns: an XML element[HEAP] | NULL */
|
||||||
|
XMLElement * ExtensionsToXML(JanetTable *t);
|
||||||
|
|
||||||
|
/** Creates a Janet table from a JSON object.
|
||||||
|
* ----------
|
||||||
|
* Returns: a wrapped Janet table[janet] | NULL */
|
||||||
|
Janet JsonToJanet(HashMap *obj);
|
||||||
|
|
||||||
|
/** Takes a Janet table and tries to encode it as JSON.
|
||||||
|
* ----------------
|
||||||
|
* Returns: a JSON object[HEAP] | NULL */
|
||||||
|
HashMap * JanetToJson(JanetTable *table);
|
||||||
|
|
||||||
|
/** Configures some basic context for the embedded Janet environment.
|
||||||
|
* ---------------------------
|
||||||
|
* Returns: NOTHING
|
||||||
|
* Modifies: env */
|
||||||
|
void SetupBasicExtensionContext(Extension *ext, JanetTable *env);
|
||||||
|
|
||||||
|
/** Tries to get a ParseeData from a Janet value(see 'parsee/ctx').
|
||||||
|
* ------------------
|
||||||
|
* Returns: the data object | NULL */
|
||||||
|
ParseeData * GetParseeData(Janet v);
|
||||||
|
|
||||||
|
/** Generates a Janet value from a ParseeData.
|
||||||
|
* ------------
|
||||||
|
* See-Also; GetParseeData */
|
||||||
|
Janet FromParseeData(ParseeData *data);
|
||||||
|
|
||||||
|
bool
|
||||||
|
TryCall(Extension *ext, char *func, int32_t argc, Janet *argv, Janet *out);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
170
src/Extensions/JSON.c
Normal file
170
src/Extensions/JSON.c
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
#ifdef JANET
|
||||||
|
#include <janet.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm/Memory.h>
|
||||||
|
#include <Cytoplasm/Json.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
|
||||||
|
#include <StringStream.h>
|
||||||
|
#include <XML.h>
|
||||||
|
|
||||||
|
Janet JsonToJanet(HashMap *obj);
|
||||||
|
static Janet
|
||||||
|
JsonValueToJanet(JsonValue *val)
|
||||||
|
{
|
||||||
|
Janet jVal;
|
||||||
|
switch (JsonValueType(val))
|
||||||
|
{
|
||||||
|
case JSON_STRING:
|
||||||
|
jVal = janet_cstringv(JsonValueAsString(val));
|
||||||
|
break;
|
||||||
|
case JSON_NULL:
|
||||||
|
jVal = janet_wrap_nil();
|
||||||
|
break;
|
||||||
|
case JSON_FLOAT:
|
||||||
|
jVal = janet_wrap_number(JsonValueAsFloat(val));
|
||||||
|
break;
|
||||||
|
case JSON_INTEGER:
|
||||||
|
jVal = janet_wrap_s64(JsonValueAsInteger(val));
|
||||||
|
break;
|
||||||
|
case JSON_BOOLEAN:
|
||||||
|
jVal = janet_wrap_boolean(JsonValueAsBoolean(val));
|
||||||
|
break;
|
||||||
|
case JSON_OBJECT:
|
||||||
|
jVal = JsonToJanet(JsonValueAsObject(val));
|
||||||
|
break;
|
||||||
|
case JSON_ARRAY:
|
||||||
|
{
|
||||||
|
JanetArray *arr = janet_array(0);
|
||||||
|
Array *jArr = JsonValueAsArray(val);
|
||||||
|
size_t i, len;
|
||||||
|
for (i = 0, len = ArraySize(jArr); i < len; i++)
|
||||||
|
{
|
||||||
|
janet_array_push(arr, JsonValueToJanet(ArrayGet(jArr, i)));
|
||||||
|
}
|
||||||
|
jVal = janet_wrap_array(arr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return jVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
Janet
|
||||||
|
JsonToJanet(HashMap *obj)
|
||||||
|
{
|
||||||
|
JanetTable *table;
|
||||||
|
char *key;
|
||||||
|
JsonValue *val;
|
||||||
|
if (!obj)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
table = janet_table(0);
|
||||||
|
while (HashMapIterate(obj, &key, (void **) &val))
|
||||||
|
{
|
||||||
|
Janet jVal = JsonValueToJanet(val);
|
||||||
|
janet_table_put(table, janet_cstringv(key), jVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return janet_wrap_table(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap * JanetToJson(JanetTable *table);
|
||||||
|
static JsonValue *
|
||||||
|
JanetToJsonValue(Janet janet)
|
||||||
|
{
|
||||||
|
JsonValue *ret = NULL;
|
||||||
|
if (janet_type(janet) == JANET_STRING)
|
||||||
|
{
|
||||||
|
ret = JsonValueString((char *) janet_unwrap_string(janet));
|
||||||
|
}
|
||||||
|
else if (janet_type(janet) == JANET_BOOLEAN)
|
||||||
|
{
|
||||||
|
ret = JsonValueBoolean(janet_unwrap_boolean(janet));
|
||||||
|
}
|
||||||
|
else if (janet_type(janet) == JANET_NIL)
|
||||||
|
{
|
||||||
|
ret = JsonValueNull();
|
||||||
|
}
|
||||||
|
else if (janet_type(janet) == JANET_ARRAY)
|
||||||
|
{
|
||||||
|
JanetArray *arr = janet_unwrap_array(janet);
|
||||||
|
Array *jArr = ArrayCreate();
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < arr->count; i++)
|
||||||
|
{
|
||||||
|
Janet child = arr->data[i];
|
||||||
|
ArrayAdd(jArr, JanetToJsonValue(child));
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = JsonValueArray(jArr);
|
||||||
|
}
|
||||||
|
else if (janet_type(janet) == JANET_TABLE)
|
||||||
|
{
|
||||||
|
ret = JsonValueObject(JanetToJson(janet_unwrap_table(janet)));
|
||||||
|
}
|
||||||
|
else if (janet_is_int(janet))
|
||||||
|
{
|
||||||
|
ret = JsonValueInteger(janet_unwrap_s64(janet));
|
||||||
|
}
|
||||||
|
else if (janet_type(janet) == JANET_NUMBER)
|
||||||
|
{
|
||||||
|
ret = JsonValueFloat(janet_unwrap_number(janet));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
HashMap *
|
||||||
|
JanetToJson(JanetTable *table)
|
||||||
|
{
|
||||||
|
HashMap *ret;
|
||||||
|
size_t i;
|
||||||
|
if (!table)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = HashMapCreate();
|
||||||
|
for (i = 0; i < table->capacity; i++)
|
||||||
|
{
|
||||||
|
JanetKV *kv = &table->data[i];
|
||||||
|
char *key;
|
||||||
|
if (!janet_checktype(kv->key, JANET_STRING))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = (char *) janet_unwrap_string(kv->key);
|
||||||
|
|
||||||
|
JsonValueFree(HashMapSet(ret, key, JanetToJsonValue(kv->value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Janet
|
||||||
|
JanetParseJSON(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
JanetBuffer *buf = NULL;
|
||||||
|
Stream *buffer_stream;
|
||||||
|
HashMap *json;
|
||||||
|
Janet ret;
|
||||||
|
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
if (!(buf = janet_getbuffer(argv, 0)))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_stream = StrStreamReaderN((char *) buf->data, buf->count);
|
||||||
|
json = JsonDecode(buffer_stream);
|
||||||
|
StreamClose(buffer_stream);
|
||||||
|
ret = JsonToJanet(json);
|
||||||
|
JsonFree(json);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
30
src/Extensions/Jabber.c
Normal file
30
src/Extensions/Jabber.c
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifdef JANET
|
||||||
|
#include "Extensions/Internal.h"
|
||||||
|
|
||||||
|
#include "Extensions/Functions.h"
|
||||||
|
|
||||||
|
Janet
|
||||||
|
JanetWriteStanza(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
XMLElement *xml;
|
||||||
|
ParseeData *data;
|
||||||
|
|
||||||
|
janet_fixarity(argc, 2);
|
||||||
|
if (janet_type(argv[0]) != JANET_POINTER)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (janet_type(argv[1]) != JANET_TABLE)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
data = janet_unwrap_pointer(argv[0]);
|
||||||
|
xml = ExtensionsToXML(janet_unwrap_table(argv[1]));
|
||||||
|
|
||||||
|
XMPPSendStanza(data->jabber, xml, data->config->max_stanza_size);
|
||||||
|
|
||||||
|
XMLFreeElement(xml);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
304
src/Extensions/Janet.c
Normal file
304
src/Extensions/Janet.c
Normal file
|
|
@ -0,0 +1,304 @@
|
||||||
|
#ifdef JANET
|
||||||
|
#include <Extension.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <janet.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm/Cytoplasm.h>
|
||||||
|
#include <Cytoplasm/HashMap.h>
|
||||||
|
#include <Cytoplasm/Memory.h>
|
||||||
|
#include <Cytoplasm/Stream.h>
|
||||||
|
#include <Cytoplasm/Util.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
#include <Cytoplasm/Log.h>
|
||||||
|
|
||||||
|
#include <Parsee.h>
|
||||||
|
#include <XML.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#include "Extensions/Internal.h"
|
||||||
|
|
||||||
|
bool
|
||||||
|
ExtensionEnabled(void)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Extensions *
|
||||||
|
ExtensionCreateContext(ParseeData *data)
|
||||||
|
{
|
||||||
|
Extensions *ctx = Malloc(sizeof(*ctx));
|
||||||
|
|
||||||
|
ctx->extensions = HashMapCreate();
|
||||||
|
ctx->data = data;
|
||||||
|
ctx->count = 0;
|
||||||
|
|
||||||
|
pthread_mutex_init(&ctx->mtx, NULL);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
void
|
||||||
|
ExtensionDestroyContext(Extensions *ctx)
|
||||||
|
{
|
||||||
|
char *key;
|
||||||
|
Extension *ext;
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (HashMapIterate(ctx->extensions, &key, (void **) &ext))
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
ext->halted = true;
|
||||||
|
janet_loop1_interrupt(ext->vm);
|
||||||
|
|
||||||
|
pthread_join(ext->thr, NULL);
|
||||||
|
XMPPFreeManager(ext->manager);
|
||||||
|
Free(ext->bytes);
|
||||||
|
Free(ext->file);
|
||||||
|
Free(ext->id);
|
||||||
|
Free(ext);
|
||||||
|
}
|
||||||
|
pthread_mutex_destroy(&ctx->mtx);
|
||||||
|
HashMapFree(ctx->extensions);
|
||||||
|
Free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
Janet
|
||||||
|
GetGlobal(Extension *ext, char *key)
|
||||||
|
{
|
||||||
|
Janet v;
|
||||||
|
|
||||||
|
v = janet_table_get(ext->env, janet_csymbolv(key));
|
||||||
|
if (janet_type(v) == JANET_NIL)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
return janet_table_get(janet_unwrap_table(v), janet_ckeywordv("value"));
|
||||||
|
}
|
||||||
|
bool
|
||||||
|
TryCall(Extension *ext, char *func, int32_t argc, Janet *argv, Janet *out)
|
||||||
|
{
|
||||||
|
Janet v = GetGlobal(ext, func);
|
||||||
|
JanetFiber *fib = NULL;
|
||||||
|
JanetSignal sig = JANET_SIGNAL_OK;
|
||||||
|
if (janet_type(v) == JANET_FUNCTION)
|
||||||
|
{
|
||||||
|
sig = janet_pcall(
|
||||||
|
janet_unwrap_function(v),
|
||||||
|
argc, argv,
|
||||||
|
out, &fib
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (sig != JANET_SIGNAL_OK)
|
||||||
|
{
|
||||||
|
janet_stacktrace(fib, *out);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sig == JANET_SIGNAL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
ExtensionLoop(void *p)
|
||||||
|
{
|
||||||
|
Extension *ext = p;
|
||||||
|
Janet f_table;
|
||||||
|
|
||||||
|
janet_init();
|
||||||
|
ext->env = janet_core_env(NULL);
|
||||||
|
ext->functions = janet_table(0);
|
||||||
|
ext->vm = janet_local_vm();
|
||||||
|
|
||||||
|
f_table = janet_wrap_table(ext->functions);
|
||||||
|
janet_gcroot(f_table);
|
||||||
|
|
||||||
|
/* Load the Janet environment */
|
||||||
|
SetupBasicExtensionContext(ext, ext->env);
|
||||||
|
janet_dobytes(ext->env, ext->bytes, ext->len, ext->file, NULL);
|
||||||
|
|
||||||
|
while (!ext->halted)
|
||||||
|
{
|
||||||
|
janet_loop();
|
||||||
|
UtilSleepMillis(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
janet_gcunroot(f_table);
|
||||||
|
|
||||||
|
//janet_table_deinit(ext->env);
|
||||||
|
janet_deinit();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExtensionReload(Extensions *ctx, char *id)
|
||||||
|
{
|
||||||
|
Extension *ext;
|
||||||
|
Log(LOG_INFO, "ctx=%p id=%s", ctx, id);
|
||||||
|
if (!ctx || !id)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&ctx->mtx);
|
||||||
|
Log(LOG_INFO, "Reloading %s", id);
|
||||||
|
ext = HashMapGet(ctx->extensions, id);
|
||||||
|
if (!ext)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&ctx->mtx);
|
||||||
|
Log(LOG_INFO, ":(");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ext->halted = true;
|
||||||
|
janet_loop1_interrupt(ext->vm);
|
||||||
|
|
||||||
|
pthread_join(ext->thr, NULL);
|
||||||
|
XMPPFreeManager(ext->manager);
|
||||||
|
Free(ext->bytes);
|
||||||
|
Free(ext->id);
|
||||||
|
HashMapDelete(ctx->extensions, id);
|
||||||
|
|
||||||
|
ExtensionLoadBasic(ctx, id, ext->file);
|
||||||
|
Free(ext->file);
|
||||||
|
Free(ext);
|
||||||
|
pthread_mutex_unlock(&ctx->mtx);
|
||||||
|
}
|
||||||
|
Extension *
|
||||||
|
ExtensionLoadBasic(Extensions *ctx, char *id, char *file)
|
||||||
|
{
|
||||||
|
Extension *ext;
|
||||||
|
Stream *stream;
|
||||||
|
uint8_t *bytes = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
if (!ctx || !id || !file)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(stream = StreamOpen(file, "r")))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
while ((c = StreamGetc(stream)) != EOF)
|
||||||
|
{
|
||||||
|
bytes = Realloc(bytes, len + 1);
|
||||||
|
bytes[len++] = c;
|
||||||
|
}
|
||||||
|
StreamClose(stream);
|
||||||
|
|
||||||
|
ext = Malloc(sizeof(*ext));
|
||||||
|
|
||||||
|
/* will be set by the thread */
|
||||||
|
ext->vm = NULL;
|
||||||
|
ext->stanzas = NULL;
|
||||||
|
|
||||||
|
ext->file = StrDuplicate(file);
|
||||||
|
ext->id = StrDuplicate(id);
|
||||||
|
ext->bytes = bytes;
|
||||||
|
ext->source = ctx;
|
||||||
|
ext->len = len;
|
||||||
|
ext->halted = false;
|
||||||
|
ext->manager = XMPPCreateManager(ext);
|
||||||
|
HashMapSet(ctx->extensions, id, ext);
|
||||||
|
|
||||||
|
pthread_create(
|
||||||
|
&ext->thr,
|
||||||
|
NULL,
|
||||||
|
ExtensionLoop,
|
||||||
|
ext
|
||||||
|
);
|
||||||
|
return ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
EndsWith(char *str, const char *ext)
|
||||||
|
{
|
||||||
|
size_t len_str, len_ext;
|
||||||
|
if (!str || !ext)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
len_str = strlen(str);
|
||||||
|
len_ext = strlen(ext);
|
||||||
|
if (len_ext > len_str)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return StrEquals(str + (len_str - len_ext), ext);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
ExtensionLoadDir(Extensions *ctx, char *dir)
|
||||||
|
{
|
||||||
|
struct dirent *ent;
|
||||||
|
DIR *handle;
|
||||||
|
if (!ctx || !dir)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(handle = opendir(dir)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while ((ent = readdir(handle)))
|
||||||
|
{
|
||||||
|
const char *extension = ".janet";
|
||||||
|
char *name = ent->d_name;
|
||||||
|
char *actual_path;
|
||||||
|
char *id = name;
|
||||||
|
if (!EndsWith(name, extension))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
id = StrDuplicate(id);
|
||||||
|
actual_path = StrConcat(3, dir, "/", name);
|
||||||
|
id[strlen(name) - strlen(extension)] = '\0';
|
||||||
|
|
||||||
|
ExtensionLoadBasic(ctx, id, actual_path);
|
||||||
|
|
||||||
|
Free(actual_path);
|
||||||
|
Free(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(handle);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
ExtensionShoveCommands(Extensions *ctx, char *jid, XMLElement *query, XMLElement *stanza)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
char *key;
|
||||||
|
Extension *val;
|
||||||
|
if (!ctx || !jid || !query || !stanza)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&ctx->mtx);
|
||||||
|
for (i = 0; IterateReentrant(ctx->extensions, key, val, i); )
|
||||||
|
{
|
||||||
|
XMPPShoveCommandList(val->manager, jid, query, stanza);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&ctx->mtx);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
ExtensionManageCommands(Extensions *ctx, XMLElement *stanza)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
char *key;
|
||||||
|
Extension *val;
|
||||||
|
if (!ctx || !stanza)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&ctx->mtx);
|
||||||
|
for (i = 0; IterateReentrant(ctx->extensions, key, val, i); )
|
||||||
|
{
|
||||||
|
XMPPManageCommand(val->manager, stanza, ctx->data);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&ctx->mtx);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
86
src/Extensions/KV.c
Normal file
86
src/Extensions/KV.c
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
#ifdef JANET
|
||||||
|
|
||||||
|
#include "Extensions/Internal.h"
|
||||||
|
|
||||||
|
Janet
|
||||||
|
JanetGetKey(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
char *chat_id = NULL;
|
||||||
|
char *key = NULL, *val = NULL;
|
||||||
|
Janet ret;
|
||||||
|
|
||||||
|
janet_fixarity(argc, 3);
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(JANET_SIGNAL_ERROR, janet_cstringv("CTX is not a ptr"));
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype(argv[1], JANET_STRING))
|
||||||
|
{
|
||||||
|
janet_signalv(JANET_SIGNAL_ERROR, janet_cstringv("CHAT ID is not a string"));
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype(argv[2], JANET_STRING))
|
||||||
|
{
|
||||||
|
janet_signalv(JANET_SIGNAL_ERROR, janet_cstringv("KEY is not a string"));
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(data = janet_unwrap_pointer(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(JANET_SIGNAL_ERROR, janet_cstringv("CTX is NULL.."));
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
chat_id = (char *) janet_unwrap_string(argv[1]);
|
||||||
|
key = (char *) janet_unwrap_string(argv[2]);
|
||||||
|
|
||||||
|
if ((val = ParseeGetChatSetting(data, chat_id, key)))
|
||||||
|
{
|
||||||
|
ret = janet_cstringv(val);
|
||||||
|
Free(val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = janet_wrap_nil();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
Janet
|
||||||
|
JanetSetKey(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
char *chat_id = NULL;
|
||||||
|
char *key = NULL, *val = NULL;
|
||||||
|
|
||||||
|
janet_fixarity(argc, 4);
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(JANET_SIGNAL_ERROR, janet_cstringv("CTX is not a ptr"));
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype(argv[1], JANET_STRING))
|
||||||
|
{
|
||||||
|
janet_signalv(JANET_SIGNAL_ERROR, janet_cstringv("CHAT ID is not a string"));
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype(argv[2], JANET_STRING))
|
||||||
|
{
|
||||||
|
janet_signalv(JANET_SIGNAL_ERROR, janet_cstringv("KEY is not a string"));
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype(argv[3], JANET_STRING))
|
||||||
|
{
|
||||||
|
janet_signalv(JANET_SIGNAL_ERROR, janet_cstringv("VAL is not a string"));
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
chat_id = (char *) janet_unwrap_string(argv[1]);
|
||||||
|
key = (char *) janet_unwrap_string(argv[2]);
|
||||||
|
val = (char *) janet_unwrap_string(argv[3]);
|
||||||
|
|
||||||
|
ParseeSetChatSetting(data, chat_id, key, val);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
149
src/Extensions/Matrix.c
Normal file
149
src/Extensions/Matrix.c
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
#ifdef JANET
|
||||||
|
|
||||||
|
#include "Extensions/Internal.h"
|
||||||
|
|
||||||
|
#include <AS.h>
|
||||||
|
|
||||||
|
Janet
|
||||||
|
JanetMatrixInvite(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
char *invitee, *room;
|
||||||
|
janet_fixarity(argc, 3);
|
||||||
|
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (janet_type(argv[1]) != JANET_STRING)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (janet_type(argv[2]) != JANET_STRING)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
invitee = (char *) janet_unwrap_string(argv[1]);
|
||||||
|
room = (char *) janet_unwrap_string(argv[2]);
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
ASInvite(data->config, room, invitee);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
Janet
|
||||||
|
JanetMatrixFind(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
char *id, *room;
|
||||||
|
Janet returned;
|
||||||
|
HashMap *e;
|
||||||
|
janet_fixarity(argc, 3);
|
||||||
|
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (janet_type(argv[1]) != JANET_STRING)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (janet_type(argv[2]) != JANET_STRING)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
room = (char *) janet_unwrap_string(argv[1]);
|
||||||
|
id = (char *) janet_unwrap_string(argv[2]);
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(e = ASFind(data->config, room, id)))
|
||||||
|
{
|
||||||
|
janet_signalv(JANET_SIGNAL_ERROR, janet_cstringv("couldnt find event"));
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
returned = JsonToJanet(e);
|
||||||
|
JsonFree(e);
|
||||||
|
return returned;
|
||||||
|
}
|
||||||
|
Janet
|
||||||
|
JanetMatrixSend(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
char *from, *room, *type, *id;
|
||||||
|
JanetTable *json;
|
||||||
|
Janet returned;
|
||||||
|
HashMap *e;
|
||||||
|
janet_fixarity(argc, 5);
|
||||||
|
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("CTX is not a ptr.")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (janet_type(argv[1]) != JANET_STRING)
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("FROM is not a string.")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (janet_type(argv[2]) != JANET_STRING)
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("ROOM is not a string.")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (janet_type(argv[3]) != JANET_STRING)
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("TYPE is not a string.")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (janet_type(argv[4]) != JANET_TABLE)
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("JSON is not a table.")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
from = (char *) janet_unwrap_string(argv[1]);
|
||||||
|
room = (char *) janet_unwrap_string(argv[2]);
|
||||||
|
type = (char *) janet_unwrap_string(argv[3]);
|
||||||
|
json = janet_unwrap_table(argv[4]);
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(e = JanetToJson(json)))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("JSON is not valid JSON.")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(id = ASSend(data->config, room, from, type, e, 0)))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("Could not send event")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
returned = janet_cstringv(id);
|
||||||
|
Free(id);
|
||||||
|
return returned;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
89
src/Extensions/PushEvents.c
Normal file
89
src/Extensions/PushEvents.c
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
#ifdef JANET
|
||||||
|
|
||||||
|
#include "Extensions/Internal.h"
|
||||||
|
|
||||||
|
typedef struct ExtensionEventReply {
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
pthread_cond_t cond;
|
||||||
|
|
||||||
|
HashMap *obj;
|
||||||
|
|
||||||
|
Extension *ext;
|
||||||
|
bool reply, ack;
|
||||||
|
} ExtensionEventReply;
|
||||||
|
|
||||||
|
static void
|
||||||
|
OnEventResponse(JanetEVGenericMessage msg)
|
||||||
|
{
|
||||||
|
ExtensionEventReply *reply = msg.argp;
|
||||||
|
Extension *ext = reply->ext;
|
||||||
|
Janet args[1] = {
|
||||||
|
JsonToJanet(reply->obj),
|
||||||
|
};
|
||||||
|
Janet ret;
|
||||||
|
|
||||||
|
if (TryCall(ext, "on-event", 1, args, &ret))
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&reply->lock);
|
||||||
|
reply->ack = true;
|
||||||
|
reply->reply = janet_truthy(ret);
|
||||||
|
pthread_cond_signal(&reply->cond);
|
||||||
|
pthread_mutex_unlock(&reply->lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&reply->lock);
|
||||||
|
reply->ack = true;
|
||||||
|
reply->reply = false;
|
||||||
|
pthread_cond_signal(&reply->cond);
|
||||||
|
pthread_mutex_unlock(&reply->lock);
|
||||||
|
}
|
||||||
|
bool
|
||||||
|
ExtensionPushEvent(Extensions *ctx, HashMap *obj)
|
||||||
|
{
|
||||||
|
bool veto = false;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
char *key;
|
||||||
|
Extension *val;
|
||||||
|
if (!ctx || !obj)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&ctx->mtx);
|
||||||
|
for (i = 0; IterateReentrant(ctx->extensions, key, val, i); )
|
||||||
|
{
|
||||||
|
ExtensionEventReply *reply = Malloc(sizeof(*reply));
|
||||||
|
JanetEVGenericMessage msg = {
|
||||||
|
/* We except a veto boolean. */
|
||||||
|
.tag = JANET_STANZA_PUSH,
|
||||||
|
};
|
||||||
|
|
||||||
|
pthread_mutex_init(&reply->lock, NULL);
|
||||||
|
pthread_cond_init(&reply->cond, NULL);
|
||||||
|
reply->ext = val;
|
||||||
|
reply->reply = false;
|
||||||
|
reply->ack = false;
|
||||||
|
reply->obj = obj;
|
||||||
|
msg.argp = reply;
|
||||||
|
|
||||||
|
janet_ev_post_event(val->vm, OnEventResponse, msg);
|
||||||
|
pthread_mutex_lock(&reply->lock);
|
||||||
|
while (!reply->ack)
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&reply->cond, &reply->lock);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&reply->lock);
|
||||||
|
pthread_mutex_destroy(&reply->lock);
|
||||||
|
pthread_cond_destroy(&reply->cond);
|
||||||
|
if (reply->reply)
|
||||||
|
{
|
||||||
|
veto = true;
|
||||||
|
}
|
||||||
|
Free(reply);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&ctx->mtx);
|
||||||
|
|
||||||
|
return veto;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
98
src/Extensions/PushStanza.c
Normal file
98
src/Extensions/PushStanza.c
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
#ifdef JANET
|
||||||
|
|
||||||
|
#include "Extensions/Internal.h"
|
||||||
|
|
||||||
|
typedef struct ExtensionStanzaReply {
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
pthread_cond_t cond;
|
||||||
|
|
||||||
|
XMLElement *stanza;
|
||||||
|
|
||||||
|
Extension *ext;
|
||||||
|
bool reply, ack;
|
||||||
|
char *type;
|
||||||
|
} ExtensionStanzaReply;
|
||||||
|
|
||||||
|
static void
|
||||||
|
OnStanzaResponse(JanetEVGenericMessage msg)
|
||||||
|
{
|
||||||
|
ExtensionStanzaReply *reply = msg.argp;
|
||||||
|
Extension *ext = reply->ext;
|
||||||
|
Janet args[2] = {
|
||||||
|
ExtensionsFromXML(NULL, reply->stanza),
|
||||||
|
janet_cstringv(reply->type)
|
||||||
|
};
|
||||||
|
Janet ret;
|
||||||
|
|
||||||
|
if (TryCall(ext, "on-stanza", 2, args, &ret))
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&reply->lock);
|
||||||
|
reply->ack = true;
|
||||||
|
reply->reply = janet_truthy(ret);
|
||||||
|
pthread_cond_signal(&reply->cond);
|
||||||
|
pthread_mutex_unlock(&reply->lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&reply->lock);
|
||||||
|
reply->ack = true;
|
||||||
|
reply->reply = false;
|
||||||
|
pthread_cond_signal(&reply->cond);
|
||||||
|
pthread_mutex_unlock(&reply->lock);
|
||||||
|
}
|
||||||
|
bool
|
||||||
|
ExtensionPushStanza(Extensions *ctx, XMLElement *stanza, StanzaType t)
|
||||||
|
{
|
||||||
|
bool veto = false;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
char *table[STANZA_TYPE_COUNT] = {
|
||||||
|
"raw",
|
||||||
|
"message",
|
||||||
|
"iq",
|
||||||
|
"presence"
|
||||||
|
};
|
||||||
|
char *key;
|
||||||
|
Extension *val;
|
||||||
|
if (!ctx || !stanza)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&ctx->mtx);
|
||||||
|
for (i = 0; IterateReentrant(ctx->extensions, key, val, i); )
|
||||||
|
{
|
||||||
|
ExtensionStanzaReply *reply = Malloc(sizeof(*reply));
|
||||||
|
JanetEVGenericMessage msg = {
|
||||||
|
/* We except a veto boolean. */
|
||||||
|
.tag = JANET_STANZA_PUSH,
|
||||||
|
};
|
||||||
|
|
||||||
|
pthread_mutex_init(&reply->lock, NULL);
|
||||||
|
pthread_cond_init(&reply->cond, NULL);
|
||||||
|
reply->ext = val;
|
||||||
|
reply->reply = false;
|
||||||
|
reply->ack = false;
|
||||||
|
reply->type = table[t];
|
||||||
|
reply->stanza = stanza;
|
||||||
|
msg.argp = reply;
|
||||||
|
|
||||||
|
janet_ev_post_event(val->vm, OnStanzaResponse, msg);
|
||||||
|
pthread_mutex_lock(&reply->lock);
|
||||||
|
while (!reply->ack)
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&reply->cond, &reply->lock);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&reply->lock);
|
||||||
|
pthread_mutex_destroy(&reply->lock);
|
||||||
|
pthread_cond_destroy(&reply->cond);
|
||||||
|
if (reply->reply)
|
||||||
|
{
|
||||||
|
veto = true;
|
||||||
|
}
|
||||||
|
Free(reply);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&ctx->mtx);
|
||||||
|
|
||||||
|
return veto;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
580
src/Extensions/RequestCmds.c
Normal file
580
src/Extensions/RequestCmds.c
Normal file
|
|
@ -0,0 +1,580 @@
|
||||||
|
#ifdef JANET
|
||||||
|
|
||||||
|
#include "Extensions/Internal.h"
|
||||||
|
|
||||||
|
#include <XMPPCommand.h>
|
||||||
|
#include <XMPPFormTool.h>
|
||||||
|
|
||||||
|
typedef struct ExtensionCommandReply {
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
pthread_cond_t cond;
|
||||||
|
|
||||||
|
XMLElement *form;
|
||||||
|
char *from;
|
||||||
|
char *node;
|
||||||
|
|
||||||
|
XMLElement *out;
|
||||||
|
|
||||||
|
XMPPCommand *cmd;
|
||||||
|
|
||||||
|
Extension *ext;
|
||||||
|
bool ack;
|
||||||
|
} ExtensionCommandReply;
|
||||||
|
|
||||||
|
static void OnCommandResponse(JanetEVGenericMessage msg);
|
||||||
|
|
||||||
|
static int JanetCmdGet(void *data0, Janet key, Janet *out);
|
||||||
|
static void JanetMarshalCmd(void *data0, JanetMarshalContext *ctx);
|
||||||
|
static void *JanetUnmarshalCmd(JanetMarshalContext *ctx);
|
||||||
|
static void JanetCmdToString(void *data0, JanetBuffer *buf);
|
||||||
|
static int32_t JanetHashCmd(void *data0, size_t size);
|
||||||
|
static Janet JanetCmdNext(void *data0, Janet next);
|
||||||
|
|
||||||
|
static Janet JanetCmdCreateText(int32_t argc, Janet *argv);
|
||||||
|
static Janet JanetCmdCreateBool(int32_t argc, Janet *argv);
|
||||||
|
static Janet JanetCmdCreateFixed(int32_t argc, Janet *argv);
|
||||||
|
static Janet JanetCmdSetTitle(int32_t argc, Janet *argv);
|
||||||
|
static const JanetMethod cmd_methods[] = {
|
||||||
|
{ "create-text", JanetCmdCreateText },
|
||||||
|
{ "create-bool", JanetCmdCreateBool },
|
||||||
|
{ "create-fixed", JanetCmdCreateFixed },
|
||||||
|
{ "set-title", JanetCmdSetTitle },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
const JanetAbstractType janet_cmd_type = {
|
||||||
|
.name = "parsee-xmppcmd",
|
||||||
|
.gc = NULL, .gcmark = NULL,
|
||||||
|
|
||||||
|
.get = JanetCmdGet, .put = NULL,
|
||||||
|
.marshal = JanetMarshalCmd, .unmarshal = JanetUnmarshalCmd,
|
||||||
|
.tostring = JanetCmdToString,
|
||||||
|
|
||||||
|
.compare = NULL,
|
||||||
|
.hash = JanetHashCmd,
|
||||||
|
|
||||||
|
.next = JanetCmdNext,
|
||||||
|
JANET_ATEND_NEXT
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static XMPPCommand *
|
||||||
|
JanetToCommand(Janet v)
|
||||||
|
{
|
||||||
|
XMPPCommand **indirect = janet_checkabstract(v, &janet_cmd_type);
|
||||||
|
return indirect ? *indirect : NULL;
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
CommandToJanet(XMPPCommand *cmd)
|
||||||
|
{
|
||||||
|
JanetAbstract abs;
|
||||||
|
if (!cmd)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
abs = janet_abstract(&janet_cmd_type, sizeof(XMPPCommand *));
|
||||||
|
*((XMPPCommand **) abs) = cmd;
|
||||||
|
return janet_wrap_abstract(abs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
PutFunction(JanetTable *functions, char *node, char *kind, JanetFunction *f)
|
||||||
|
{
|
||||||
|
JanetTable *kinds;
|
||||||
|
Janet kindsv;
|
||||||
|
if (!functions || !node || !kind || !f)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
kindsv = janet_table_get(functions, janet_cstringv(node));
|
||||||
|
if (janet_checktype(kindsv, JANET_NIL))
|
||||||
|
{
|
||||||
|
kinds = janet_table(0);
|
||||||
|
janet_table_put(
|
||||||
|
functions,
|
||||||
|
janet_cstringv(node), janet_wrap_table(kinds)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
kinds = janet_unwrap_table(kindsv);
|
||||||
|
}
|
||||||
|
|
||||||
|
janet_table_put(kinds, janet_cstringv(kind), janet_wrap_function(f));
|
||||||
|
|
||||||
|
}
|
||||||
|
static JanetFunction *
|
||||||
|
FetchFunction(JanetTable *functions, char *node, char *kind)
|
||||||
|
{
|
||||||
|
Janet f_tablev, fv;
|
||||||
|
JanetTable *ftable;
|
||||||
|
if (!functions || !node || !kind)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_tablev = janet_table_get(
|
||||||
|
functions,
|
||||||
|
janet_cstringv(node)
|
||||||
|
);
|
||||||
|
if (!janet_checktype(f_tablev, JANET_TABLE))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ftable = janet_unwrap_table(f_tablev);
|
||||||
|
|
||||||
|
fv = janet_table_get(
|
||||||
|
ftable,
|
||||||
|
janet_cstringv(kind)
|
||||||
|
);
|
||||||
|
if (!janet_checktype(fv, JANET_FUNCTION))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return janet_unwrap_function(fv);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void
|
||||||
|
JanetFormCb(XMPPCommandManager *manager, XMPPCommand *cmd, char *from, char *node)
|
||||||
|
{
|
||||||
|
Extension *ext = XMPPGetManagerCookie(manager);
|
||||||
|
ExtensionCommandReply *reply;
|
||||||
|
|
||||||
|
reply = Malloc(sizeof(*reply));
|
||||||
|
JanetEVGenericMessage msg = {
|
||||||
|
.tag = JANET_REQUEST_XMPPCMD_F
|
||||||
|
};
|
||||||
|
|
||||||
|
pthread_mutex_init(&reply->lock, NULL);
|
||||||
|
pthread_cond_init(&reply->cond, NULL);
|
||||||
|
reply->ext = ext;
|
||||||
|
reply->node = node;
|
||||||
|
reply->from = from;
|
||||||
|
reply->ack = false;
|
||||||
|
reply->cmd = cmd;
|
||||||
|
msg.argp = reply;
|
||||||
|
|
||||||
|
janet_ev_post_event(ext->vm, OnCommandResponse, msg);
|
||||||
|
pthread_mutex_lock(&reply->lock);
|
||||||
|
while (!reply->ack)
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&reply->cond, &reply->lock);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&reply->lock);
|
||||||
|
pthread_mutex_destroy(&reply->lock);
|
||||||
|
pthread_cond_destroy(&reply->cond);
|
||||||
|
Free(reply);
|
||||||
|
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
JanetCmdCb(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
|
{
|
||||||
|
Extension *ext = XMPPGetManagerCookie(m);
|
||||||
|
ExtensionCommandReply *reply;
|
||||||
|
|
||||||
|
reply = Malloc(sizeof(*reply));
|
||||||
|
JanetEVGenericMessage msg = {
|
||||||
|
.tag = JANET_REQUEST_XMPPCMD_A
|
||||||
|
};
|
||||||
|
|
||||||
|
pthread_mutex_init(&reply->lock, NULL);
|
||||||
|
pthread_cond_init(&reply->cond, NULL);
|
||||||
|
reply->ext = ext;
|
||||||
|
reply->node = node;
|
||||||
|
reply->form = form;
|
||||||
|
reply->from = from;
|
||||||
|
reply->ack = false;
|
||||||
|
reply->out = out;
|
||||||
|
msg.argp = reply;
|
||||||
|
|
||||||
|
janet_ev_post_event(ext->vm, OnCommandResponse, msg);
|
||||||
|
pthread_mutex_lock(&reply->lock);
|
||||||
|
while (!reply->ack)
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&reply->cond, &reply->lock);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&reply->lock);
|
||||||
|
pthread_mutex_destroy(&reply->lock);
|
||||||
|
pthread_cond_destroy(&reply->cond);
|
||||||
|
Free(reply);
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetRegisterCommand(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
JanetTable *self;
|
||||||
|
JanetFunction *func;
|
||||||
|
JanetFunction *form;
|
||||||
|
char *node, *name;
|
||||||
|
Janet v;
|
||||||
|
|
||||||
|
Extension *ext;
|
||||||
|
XMPPCommand *cmd;
|
||||||
|
|
||||||
|
janet_arity(argc, 4, 5);
|
||||||
|
|
||||||
|
if (!janet_checktype(argv[0], JANET_TABLE) ||
|
||||||
|
!janet_checktype(argv[1], JANET_STRING) ||
|
||||||
|
!janet_checktype(argv[2], JANET_STRING) ||
|
||||||
|
!janet_checktype(argv[3], JANET_FUNCTION) ||
|
||||||
|
(argc == 5 && !janet_checktype(argv[4], JANET_FUNCTION)))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
self = janet_unwrap_table(argv[0]);
|
||||||
|
node = (char *) janet_unwrap_string(argv[1]);
|
||||||
|
name = (char *) janet_unwrap_string(argv[2]);
|
||||||
|
func = janet_unwrap_function(argv[3]);
|
||||||
|
form = argc == 5 ? janet_unwrap_function(argv[4]) : NULL;
|
||||||
|
|
||||||
|
v = janet_table_get(self, janet_ckeywordv("ptr"));
|
||||||
|
if (!janet_checktype(v, JANET_POINTER))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
ext = janet_unwrap_pointer(v);
|
||||||
|
|
||||||
|
PutFunction(ext->functions, node, "act", func);
|
||||||
|
PutFunction(ext->functions, node, "form", form);
|
||||||
|
cmd = XMPPBasicCmd(XMPPCMD_ADMINS, node, name, JanetCmdCb);
|
||||||
|
if (form)
|
||||||
|
{
|
||||||
|
XMPPCmdOptionsCreator(cmd, JanetFormCb);
|
||||||
|
}
|
||||||
|
XMPPRegisterCommand(ext->manager, cmd);
|
||||||
|
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
OnCommandResponse(JanetEVGenericMessage msg)
|
||||||
|
{
|
||||||
|
ExtensionCommandReply *reply = msg.argp;
|
||||||
|
Extension *ext = reply->ext;
|
||||||
|
Janet ret, in;
|
||||||
|
|
||||||
|
if (msg.tag == JANET_REQUEST_XMPPCMD)
|
||||||
|
{
|
||||||
|
JanetTable *cmd = janet_table(0);
|
||||||
|
janet_table_put(cmd,
|
||||||
|
janet_ckeywordv("ptr"),
|
||||||
|
janet_wrap_pointer(reply->ext)
|
||||||
|
);
|
||||||
|
janet_table_put(cmd,
|
||||||
|
janet_ckeywordv("register"),
|
||||||
|
janet_wrap_cfunction(JanetRegisterCommand)
|
||||||
|
);
|
||||||
|
in = janet_wrap_table(cmd);
|
||||||
|
|
||||||
|
TryCall(ext, "on-xmppcmd", 1, &in, &ret);
|
||||||
|
}
|
||||||
|
else if (msg.tag == JANET_REQUEST_XMPPCMD_F)
|
||||||
|
{
|
||||||
|
Janet in[2] = {
|
||||||
|
janet_cstringv(reply->from),
|
||||||
|
CommandToJanet(reply->cmd)
|
||||||
|
};
|
||||||
|
JanetFiber *fib = NULL;
|
||||||
|
JanetFunction *func;
|
||||||
|
JanetSignal sig;
|
||||||
|
|
||||||
|
func = FetchFunction(reply->ext->functions, reply->node, "form");
|
||||||
|
if (func)
|
||||||
|
{
|
||||||
|
sig = janet_pcall(func, sizeof(in)/sizeof(*in), in, &ret, &fib);
|
||||||
|
if (sig != JANET_SIGNAL_OK)
|
||||||
|
{
|
||||||
|
janet_stacktrace(fib, ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (msg.tag == JANET_REQUEST_XMPPCMD_A)
|
||||||
|
{
|
||||||
|
JanetFunction *func;
|
||||||
|
|
||||||
|
func = FetchFunction(reply->ext->functions, reply->node, "act");
|
||||||
|
if (func)
|
||||||
|
{
|
||||||
|
Janet in[2] = {
|
||||||
|
janet_cstringv(reply->from),
|
||||||
|
ExtensionsFromXML(NULL, reply->form)
|
||||||
|
};
|
||||||
|
JanetFiber *fib = NULL;
|
||||||
|
JanetSignal sig;
|
||||||
|
XMLElement *out = reply->out;
|
||||||
|
sig = janet_pcall(func, sizeof(in)/sizeof(*in), in, &ret, &fib);
|
||||||
|
if (sig != JANET_SIGNAL_OK)
|
||||||
|
{
|
||||||
|
janet_stacktrace(fib, ret);
|
||||||
|
SetNote("error", "Internal error in Janet extension.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (janet_checktype(ret, JANET_ARRAY))
|
||||||
|
{
|
||||||
|
JanetArray *arr = janet_unwrap_array(ret);
|
||||||
|
size_t i, added;
|
||||||
|
for (i = 0, added = 0; i < arr->count; i++)
|
||||||
|
{
|
||||||
|
Janet v = arr->data[i];
|
||||||
|
JanetTable *source;
|
||||||
|
XMLElement *child = NULL;
|
||||||
|
|
||||||
|
if (!reply->out || !janet_checktype(v, JANET_TABLE))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
source = janet_unwrap_table(v);
|
||||||
|
child = ExtensionsToXML(source);
|
||||||
|
XMLAddChild(reply->out, child);
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
added++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (added == 0)
|
||||||
|
{
|
||||||
|
SetNote("error", "No values returned in Janet extension.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetNote("error", "Invalid output in Janet extension.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&reply->lock);
|
||||||
|
reply->ack = true;
|
||||||
|
pthread_cond_signal(&reply->cond);
|
||||||
|
pthread_mutex_unlock(&reply->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExtensionRequestCommands(Extensions *ctx)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
char *key;
|
||||||
|
Extension *val;
|
||||||
|
if (!ctx)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&ctx->mtx);
|
||||||
|
for (i = 0; IterateReentrant(ctx->extensions, key, val, i); )
|
||||||
|
{
|
||||||
|
ExtensionCommandReply *reply = Malloc(sizeof(*reply));
|
||||||
|
JanetEVGenericMessage msg = {
|
||||||
|
.tag = JANET_REQUEST_XMPPCMD
|
||||||
|
};
|
||||||
|
|
||||||
|
pthread_mutex_init(&reply->lock, NULL);
|
||||||
|
pthread_cond_init(&reply->cond, NULL);
|
||||||
|
reply->ext = val;
|
||||||
|
reply->ack = false;
|
||||||
|
msg.argp = reply;
|
||||||
|
|
||||||
|
janet_ev_post_event(val->vm, OnCommandResponse, msg);
|
||||||
|
pthread_mutex_lock(&reply->lock);
|
||||||
|
while (!reply->ack)
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&reply->cond, &reply->lock);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&reply->lock);
|
||||||
|
pthread_mutex_destroy(&reply->lock);
|
||||||
|
pthread_cond_destroy(&reply->cond);
|
||||||
|
Free(reply);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&ctx->mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
JanetCmdGet(void *data0, Janet key, Janet *out)
|
||||||
|
{
|
||||||
|
JanetKeyword kw;
|
||||||
|
if (!janet_checktype(key, JANET_KEYWORD))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kw = janet_unwrap_keyword(key);
|
||||||
|
(void) data0;
|
||||||
|
return janet_getmethod(kw, cmd_methods, out);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
JanetMarshalCmd(void *data0, JanetMarshalContext *ctx)
|
||||||
|
{
|
||||||
|
janet_marshal_abstract(ctx, data0);
|
||||||
|
}
|
||||||
|
static void *
|
||||||
|
JanetUnmarshalCmd(JanetMarshalContext *ctx)
|
||||||
|
{
|
||||||
|
XMPPCommand **data = janet_unmarshal_abstract(ctx, sizeof(XMPPCommand *));
|
||||||
|
return data ? *data : NULL;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
JanetCmdToString(void *data0, JanetBuffer *buf)
|
||||||
|
{
|
||||||
|
janet_buffer_push_cstring(buf, "[" NAME " XMPP command type]");
|
||||||
|
}
|
||||||
|
static int32_t
|
||||||
|
JanetHashCmd(void *data0, size_t size)
|
||||||
|
{
|
||||||
|
uintptr_t datap = (uintptr_t) data0;
|
||||||
|
|
||||||
|
(void) size;
|
||||||
|
/* We're casting down, but in a context where there is really
|
||||||
|
* just one ParseeData, is that really such a crime? */
|
||||||
|
return (int32_t) datap;
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetCmdNext(void *data0, Janet next)
|
||||||
|
{
|
||||||
|
(void) data0;
|
||||||
|
return janet_nextmethod(cmd_methods, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Janet
|
||||||
|
JanetCmdCreateText(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
XMPPCommand *cmd;
|
||||||
|
XMPPOption *opt;
|
||||||
|
|
||||||
|
bool req;
|
||||||
|
char *id, *def, *desc;
|
||||||
|
|
||||||
|
janet_arity(argc, 4, 5);
|
||||||
|
if (!(cmd = JanetToCommand(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("Object is not a command")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype(argv[1], JANET_BOOLEAN) ||
|
||||||
|
!janet_checktype(argv[2], JANET_STRING) ||
|
||||||
|
!janet_checktype(argv[3], JANET_STRING) ||
|
||||||
|
((argc == 5) && !janet_checktype(argv[4], JANET_STRING)))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("Invalid argument types")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
req = janet_unwrap_boolean(argv[1]);
|
||||||
|
id = (char *) janet_unwrap_string(argv[2]);
|
||||||
|
def = (char *) janet_unwrap_string(argv[3]);
|
||||||
|
desc = argc == 5 ? (char *) janet_unwrap_string(argv[4]) : NULL;
|
||||||
|
|
||||||
|
opt = XMPPCreateText(req, id, def);
|
||||||
|
XMPPSetDescription(opt, desc);
|
||||||
|
|
||||||
|
XMPPAddOption(cmd, opt);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet
|
||||||
|
JanetCmdCreateBool(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
XMPPCommand *cmd;
|
||||||
|
XMPPOption *opt;
|
||||||
|
|
||||||
|
bool req, def;
|
||||||
|
char *id, *desc;
|
||||||
|
|
||||||
|
janet_arity(argc, 4, 5);
|
||||||
|
if (!(cmd = JanetToCommand(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("Object is not a command")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype(argv[1], JANET_BOOLEAN) ||
|
||||||
|
!janet_checktype(argv[2], JANET_STRING) ||
|
||||||
|
!janet_checktype(argv[3], JANET_BOOLEAN) ||
|
||||||
|
((argc == 5) && !janet_checktype(argv[4], JANET_STRING)))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("Invalid argument types")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
req = janet_unwrap_boolean(argv[1]);
|
||||||
|
id = (char *) janet_unwrap_string(argv[2]);
|
||||||
|
def = janet_unwrap_boolean(argv[3]);
|
||||||
|
desc = argc == 5 ? (char *) janet_unwrap_string(argv[4]) : NULL;
|
||||||
|
|
||||||
|
opt = XMPPCreateBool(req, id, def);
|
||||||
|
XMPPSetDescription(opt, desc);
|
||||||
|
|
||||||
|
XMPPAddOption(cmd, opt);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetCmdCreateFixed(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
XMPPCommand *cmd;
|
||||||
|
XMPPOption *opt;
|
||||||
|
|
||||||
|
char *id, *desc;
|
||||||
|
|
||||||
|
janet_fixarity(argc, 3);
|
||||||
|
if (!(cmd = JanetToCommand(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("Object is not a command")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype(argv[1], JANET_STRING) ||
|
||||||
|
!janet_checktype(argv[2], JANET_STRING))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("Invalid argument types")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
id = (char *) janet_unwrap_string(argv[1]);
|
||||||
|
desc = (char *) janet_unwrap_string(argv[2]);
|
||||||
|
|
||||||
|
opt = XMPPCreateFixed(id, desc);
|
||||||
|
XMPPSetDescription(opt, desc);
|
||||||
|
|
||||||
|
XMPPAddOption(cmd, opt);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetCmdSetTitle(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
XMPPCommand *cmd;
|
||||||
|
|
||||||
|
char *title;
|
||||||
|
|
||||||
|
janet_fixarity(argc, 2);
|
||||||
|
if (!(cmd = JanetToCommand(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("Object is not a command")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype(argv[1], JANET_STRING))
|
||||||
|
{
|
||||||
|
janet_signalv(
|
||||||
|
JANET_SIGNAL_ERROR, janet_cstringv("Invalid argument types")
|
||||||
|
);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
title = (char *) janet_unwrap_string(argv[1]);
|
||||||
|
|
||||||
|
XMPPSetFormTitle(cmd, title);
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
98
src/Extensions/StanzaInfo.c
Normal file
98
src/Extensions/StanzaInfo.c
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
#ifdef JANET
|
||||||
|
|
||||||
|
#include "Extensions/Internal.h"
|
||||||
|
|
||||||
|
Janet
|
||||||
|
JanetStanzaInfo(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
ParseeData *data;
|
||||||
|
XMLElement *stanza;
|
||||||
|
|
||||||
|
JanetTable *ret;
|
||||||
|
|
||||||
|
char *trimmed = NULL;
|
||||||
|
char *chat_id = NULL;
|
||||||
|
char *from = NULL;
|
||||||
|
char *room = NULL;
|
||||||
|
char *mxid = NULL;
|
||||||
|
|
||||||
|
janet_fixarity(argc, 2);
|
||||||
|
if (!(data = GetParseeData(argv[0])))
|
||||||
|
{
|
||||||
|
janet_signalv(JANET_SIGNAL_ERROR, janet_cstringv("CTX is not a ptr"));
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype(argv[1], JANET_TABLE))
|
||||||
|
{
|
||||||
|
janet_signalv(JANET_SIGNAL_ERROR, janet_cstringv("STANZA is not a table"));
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(stanza = ExtensionsToXML(janet_unwrap_table(argv[1]))))
|
||||||
|
{
|
||||||
|
janet_signalv(JANET_SIGNAL_ERROR, janet_cstringv("STANZA is not XML."));
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
from = HashMapGet(stanza->attrs, "from");
|
||||||
|
trimmed = ParseeTrimJID(from);
|
||||||
|
chat_id = ParseeGetFromMUCID(data, trimmed);
|
||||||
|
|
||||||
|
ret = janet_table(0);
|
||||||
|
janet_table_put(ret,
|
||||||
|
janet_ckeywordv("in-muc"),
|
||||||
|
janet_wrap_boolean(ParseeIsMUC(data, trimmed))
|
||||||
|
);
|
||||||
|
janet_table_put(ret,
|
||||||
|
janet_ckeywordv("in-dm"),
|
||||||
|
janet_wrap_boolean(StrEquals(HashMapGet(stanza->attrs, "type"), "chat"))
|
||||||
|
);
|
||||||
|
if (chat_id && trimmed)
|
||||||
|
{
|
||||||
|
room = ParseeGetRoomID(data, chat_id);
|
||||||
|
janet_table_put(ret,
|
||||||
|
janet_ckeywordv("muc-jid"), janet_cstringv(trimmed)
|
||||||
|
);
|
||||||
|
janet_table_put(ret,
|
||||||
|
janet_ckeywordv("id"), janet_cstringv(chat_id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *to = ParseeDecodeMXID(HashMapGet(stanza->attrs, "to"));
|
||||||
|
char *dmid = ParseeGetDMID(to, from);
|
||||||
|
|
||||||
|
room = ParseeFindDMRoom(data, to, from);
|
||||||
|
if (dmid)
|
||||||
|
{
|
||||||
|
janet_table_put(ret,
|
||||||
|
janet_ckeywordv("id"), janet_cstringv(dmid)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Free(dmid);
|
||||||
|
Free(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (room)
|
||||||
|
{
|
||||||
|
janet_table_put(ret,
|
||||||
|
janet_ckeywordv("room-id"), janet_cstringv(room)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mxid = ParseeGetBridgedUser(data, stanza)))
|
||||||
|
{
|
||||||
|
janet_table_put(ret,
|
||||||
|
janet_ckeywordv("bridged-sender"), janet_cstringv(mxid)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Free(trimmed);
|
||||||
|
Free(chat_id);
|
||||||
|
Free(room);
|
||||||
|
Free(mxid);
|
||||||
|
XMLFreeElement(stanza);
|
||||||
|
return janet_wrap_table(ret);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
357
src/Extensions/XML.c
Normal file
357
src/Extensions/XML.c
Normal file
|
|
@ -0,0 +1,357 @@
|
||||||
|
#ifdef JANET
|
||||||
|
#include <janet.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm/Memory.h>
|
||||||
|
#include <Cytoplasm/Str.h>
|
||||||
|
|
||||||
|
#include <StringStream.h>
|
||||||
|
#include <XML.h>
|
||||||
|
|
||||||
|
static Janet XMLToString(int32_t argc, Janet *argv);
|
||||||
|
static Janet JanetXMLAddAttr(int32_t argc, Janet *argv);
|
||||||
|
static void InitialiseBasicXML(JanetTable *table, char *type);
|
||||||
|
|
||||||
|
XMLElement *
|
||||||
|
ExtensionsToXML(JanetTable *t)
|
||||||
|
{
|
||||||
|
XMLElement *ret = NULL;
|
||||||
|
|
||||||
|
char *type = NULL, *name, *data;
|
||||||
|
JanetArray *children;
|
||||||
|
JanetTable *attrs;
|
||||||
|
int32_t i;
|
||||||
|
Janet v;
|
||||||
|
|
||||||
|
if (!t)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#define ChkType(ent, type) (janet_type((v = janet_table_get(t, janet_ckeywordv(ent)))) == type)
|
||||||
|
if (!ChkType("xml-type", JANET_STRING))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
type = (char *) janet_unwrap_string(v);
|
||||||
|
if (StrEquals(type, "data"))
|
||||||
|
{
|
||||||
|
if (!ChkType("xml-data", JANET_STRING))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
data = (char *) janet_unwrap_string(v);
|
||||||
|
|
||||||
|
ret = XMLCreateText(data);
|
||||||
|
}
|
||||||
|
else if (StrEquals(type, "tag"))
|
||||||
|
{
|
||||||
|
if (!ChkType("xml-name", JANET_STRING))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
name = (char *) janet_unwrap_string(v);
|
||||||
|
|
||||||
|
if (!ChkType("xml-attrs", JANET_TABLE))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = XMLCreateTag(name);
|
||||||
|
attrs = janet_unwrap_table(v);
|
||||||
|
for (i = 0; i < attrs->capacity; i++)
|
||||||
|
{
|
||||||
|
JanetKV *kv = &attrs->data[i];
|
||||||
|
if (!janet_checktype(kv->key, JANET_STRING) ||
|
||||||
|
!janet_checktype(kv->value, JANET_STRING))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
XMLAddAttr(ret,
|
||||||
|
(char *) janet_unwrap_string(kv->key),
|
||||||
|
(char *) janet_unwrap_string(kv->value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ChkType("xml-children", JANET_ARRAY))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
children = janet_unwrap_array(v);
|
||||||
|
|
||||||
|
for (i = 0; i < children->capacity; i++)
|
||||||
|
{
|
||||||
|
Janet cJanet = children->data[i];
|
||||||
|
XMLElement *cXML = NULL;
|
||||||
|
if (!janet_checktype(cJanet, JANET_TABLE))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cXML = ExtensionsToXML(janet_unwrap_table(cJanet));
|
||||||
|
XMLAddChild(ret, cXML);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
Janet
|
||||||
|
ExtensionsFromXML(JanetArray *in, XMLElement *e)
|
||||||
|
{
|
||||||
|
JanetArray *children = NULL;
|
||||||
|
JanetTable *table;
|
||||||
|
size_t i, len;
|
||||||
|
char *type = NULL;
|
||||||
|
if (!e)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
table = janet_table(0);
|
||||||
|
switch (e->type)
|
||||||
|
{
|
||||||
|
case XML_ELEMENT_TAG:
|
||||||
|
type = "tag";
|
||||||
|
break;
|
||||||
|
case XML_ELEMENT_DATA:
|
||||||
|
case XML_ELEMENT_CDATA:
|
||||||
|
type = "data";
|
||||||
|
break;
|
||||||
|
case XML_ELEMENT_PI:
|
||||||
|
type = "pi";
|
||||||
|
break;
|
||||||
|
case XML_ELEMENT_UNKNOWN:
|
||||||
|
type = "unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitialiseBasicXML(table, type);
|
||||||
|
if (e->type == XML_ELEMENT_DATA || e->type == XML_ELEMENT_PI)
|
||||||
|
{
|
||||||
|
janet_table_put(table,
|
||||||
|
janet_ckeywordv("xml-data"), janet_cstringv(e->data)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (e->type == XML_ELEMENT_TAG)
|
||||||
|
{
|
||||||
|
char *attr, *val;
|
||||||
|
JanetTable *attrs;
|
||||||
|
children = janet_array(ArraySize(e->children));
|
||||||
|
janet_table_put(table,
|
||||||
|
janet_ckeywordv("xml-name"), janet_cstringv(e->name)
|
||||||
|
);
|
||||||
|
for (i = 0, len = ArraySize(e->children); i < len; i++)
|
||||||
|
{
|
||||||
|
ExtensionsFromXML(children, ArrayGet(e->children, i));
|
||||||
|
}
|
||||||
|
janet_table_put(table,
|
||||||
|
janet_ckeywordv("xml-children"), janet_wrap_array(children)
|
||||||
|
);
|
||||||
|
|
||||||
|
attrs = janet_table(0);
|
||||||
|
while (HashMapIterate(e->attrs, &attr, (void **) &val))
|
||||||
|
{
|
||||||
|
janet_table_put(attrs,
|
||||||
|
janet_cstringv(attr), janet_cstringv(val)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
janet_table_put(table,
|
||||||
|
janet_ckeywordv("xml-attrs"), janet_wrap_table(attrs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (children && in)
|
||||||
|
{
|
||||||
|
janet_array_push(in, janet_wrap_table(table));
|
||||||
|
}
|
||||||
|
return janet_wrap_table(table);
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
JanetXMLAddAttr(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
Janet self_v, key_v, val_v, attr_v;
|
||||||
|
JanetTable *self, *attrs;
|
||||||
|
char *key, *val;
|
||||||
|
|
||||||
|
janet_fixarity(argc, 3);
|
||||||
|
|
||||||
|
if (!janet_checktype((self_v = argv[0]), JANET_TABLE))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype((key_v = argv[1]), JANET_STRING))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
if (!janet_checktype((val_v = argv[2]), JANET_STRING))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
key = (char *) janet_unwrap_string(key_v);
|
||||||
|
val = (char *) janet_unwrap_string(val_v);
|
||||||
|
|
||||||
|
self = janet_unwrap_table(self_v);
|
||||||
|
attr_v = janet_table_get(self, janet_ckeywordv("xml-attrs"));
|
||||||
|
if (!janet_checktype(attr_v, JANET_TABLE))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
attrs = janet_unwrap_table(attr_v);
|
||||||
|
|
||||||
|
janet_table_put(attrs, janet_cstringv(key), janet_cstringv(val));
|
||||||
|
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
static Janet
|
||||||
|
XMLToString(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
XMLElement *xml;
|
||||||
|
Stream *fake;
|
||||||
|
Janet ret;
|
||||||
|
char *buf = NULL;
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
|
||||||
|
if (!janet_checktype(argv[0], JANET_TABLE))
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
xml = ExtensionsToXML(janet_gettable(argv, 0));
|
||||||
|
if (!xml)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
fake = StrStreamWriter(&buf);
|
||||||
|
XMLEncode(fake, xml);
|
||||||
|
StreamFlush(fake);
|
||||||
|
StreamClose(fake);
|
||||||
|
XMLFreeElement(xml);
|
||||||
|
|
||||||
|
ret = janet_cstringv(buf);
|
||||||
|
Free(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Janet
|
||||||
|
JanetCreateXMLData(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
Janet parent_v, text_v;
|
||||||
|
JanetTable *parent;
|
||||||
|
JanetTable *ret;
|
||||||
|
char *text;
|
||||||
|
|
||||||
|
janet_arity(argc, 1, 2);
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
text_v = argv[0];
|
||||||
|
parent_v = janet_wrap_nil();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent_v = argv[0];
|
||||||
|
text_v = argv[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (janet_type(text_v) != JANET_STRING)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
text = (char *) janet_unwrap_string(text_v);
|
||||||
|
ret = janet_table(0);
|
||||||
|
InitialiseBasicXML(ret, "data");
|
||||||
|
janet_table_put(ret,
|
||||||
|
janet_ckeywordv("xml-data"), janet_cstringv(text)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (janet_type(parent_v) == JANET_TABLE)
|
||||||
|
{
|
||||||
|
JanetArray *children;
|
||||||
|
Janet children_v;
|
||||||
|
|
||||||
|
parent = janet_unwrap_table(parent_v);
|
||||||
|
children_v = janet_table_get(parent, janet_ckeywordv("xml-children"));
|
||||||
|
if (janet_type(children_v) != JANET_ARRAY)
|
||||||
|
{
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
children = janet_unwrap_array(children_v);
|
||||||
|
|
||||||
|
janet_array_push(children, janet_wrap_table(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
return janet_wrap_table(ret);
|
||||||
|
}
|
||||||
|
Janet
|
||||||
|
JanetCreateXMLTag(int32_t argc, Janet *argv)
|
||||||
|
{
|
||||||
|
Janet parent_v, text_v;
|
||||||
|
JanetTable *parent;
|
||||||
|
JanetTable *ret;
|
||||||
|
char *text;
|
||||||
|
|
||||||
|
janet_arity(argc, 1, 2);
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
text_v = argv[0];
|
||||||
|
parent_v = janet_wrap_nil();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent_v = argv[0];
|
||||||
|
text_v = argv[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (janet_type(text_v) != JANET_STRING)
|
||||||
|
{
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
text = (char *) janet_unwrap_string(text_v);
|
||||||
|
ret = janet_table(0);
|
||||||
|
|
||||||
|
InitialiseBasicXML(ret, "tag");
|
||||||
|
janet_table_put(ret,
|
||||||
|
janet_ckeywordv("xml-name"), janet_cstringv(text)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (janet_type(parent_v) == JANET_TABLE)
|
||||||
|
{
|
||||||
|
JanetArray *children;
|
||||||
|
Janet children_v;
|
||||||
|
|
||||||
|
parent = janet_unwrap_table(parent_v);
|
||||||
|
children_v = janet_table_get(parent, janet_ckeywordv("xml-children"));
|
||||||
|
if (janet_type(children_v) != JANET_ARRAY)
|
||||||
|
{
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
children = janet_unwrap_array(children_v);
|
||||||
|
|
||||||
|
janet_array_push(children, janet_wrap_table(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
return janet_wrap_table(ret);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
InitialiseBasicXML(JanetTable *table, char *type)
|
||||||
|
{
|
||||||
|
janet_table_put(table,
|
||||||
|
janet_ckeywordv("stringify"), janet_wrap_cfunction(XMLToString)
|
||||||
|
);
|
||||||
|
janet_table_put(table,
|
||||||
|
janet_ckeywordv("set-attr"), janet_wrap_cfunction(JanetXMLAddAttr)
|
||||||
|
);
|
||||||
|
janet_table_put(table,
|
||||||
|
janet_ckeywordv("xml-type"), janet_cstringv(type)
|
||||||
|
);
|
||||||
|
if (StrEquals(type, "tag"))
|
||||||
|
{
|
||||||
|
janet_table_put(table,
|
||||||
|
janet_ckeywordv("xml-attrs"), janet_wrap_table(janet_table(0))
|
||||||
|
);
|
||||||
|
janet_table_put(table,
|
||||||
|
janet_ckeywordv("xml-children"), janet_wrap_array(janet_array(0))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -22,6 +22,9 @@ ParseeRequest(HttpServerContext *ctx, void *argp)
|
||||||
/* Basic headers */
|
/* Basic headers */
|
||||||
HttpResponseStatus(ctx, HTTP_OK);
|
HttpResponseStatus(ctx, HTTP_OK);
|
||||||
HttpResponseHeader(ctx, "Server", NAME "/v" VERSION);
|
HttpResponseHeader(ctx, "Server", NAME "/v" VERSION);
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
HttpResponseHeader(ctx, "X-Powered-By", "some weirdows");
|
||||||
|
#endif
|
||||||
HttpResponseHeader(ctx, "Connection", "close");
|
HttpResponseHeader(ctx, "Connection", "close");
|
||||||
|
|
||||||
arg.data = data;
|
arg.data = data;
|
||||||
|
|
|
||||||
16
src/Main.c
16
src/Main.c
|
|
@ -18,6 +18,11 @@
|
||||||
#include <XMPP.h>
|
#include <XMPP.h>
|
||||||
#include <AS.h>
|
#include <AS.h>
|
||||||
|
|
||||||
|
#ifdef JANET
|
||||||
|
#include <janet.h>
|
||||||
|
#endif
|
||||||
|
#include <Extension.h>
|
||||||
|
|
||||||
static HttpServer *server = NULL;
|
static HttpServer *server = NULL;
|
||||||
static pthread_t xmpp_thr;
|
static pthread_t xmpp_thr;
|
||||||
static XMPPComponent *jabber = NULL;
|
static XMPPComponent *jabber = NULL;
|
||||||
|
|
@ -99,6 +104,8 @@ Main(Array *args, HashMap *env)
|
||||||
int http = 8;
|
int http = 8;
|
||||||
int verbose = 0;
|
int verbose = 0;
|
||||||
|
|
||||||
|
Extensions *ext_ctx = NULL;
|
||||||
|
|
||||||
start = UtilTsMillis();
|
start = UtilTsMillis();
|
||||||
|
|
||||||
memset(&conf, 0, sizeof(conf));
|
memset(&conf, 0, sizeof(conf));
|
||||||
|
|
@ -110,6 +117,9 @@ Main(Array *args, HashMap *env)
|
||||||
Log(LOG_INFO, "=======================");
|
Log(LOG_INFO, "=======================");
|
||||||
Log(LOG_INFO, "(C)opyright 2024 LDA and other contributors");
|
Log(LOG_INFO, "(C)opyright 2024 LDA and other contributors");
|
||||||
Log(LOG_INFO, "(This program is free software, see LICENSE.)");
|
Log(LOG_INFO, "(This program is free software, see LICENSE.)");
|
||||||
|
#ifdef JANET
|
||||||
|
Log(LOG_INFO, "**Built with Janet!**");
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef PLATFORM_IPHONE
|
#ifdef PLATFORM_IPHONE
|
||||||
Log(LOG_WARNING, "Wait. Are you running this on an iPhone?");
|
Log(LOG_WARNING, "Wait. Are you running this on an iPhone?");
|
||||||
|
|
@ -269,6 +279,10 @@ Main(Array *args, HashMap *env)
|
||||||
Log(LOG_DEBUG, "Verbosity level: %d", verbose);
|
Log(LOG_DEBUG, "Verbosity level: %d", verbose);
|
||||||
((ParseeData *) conf.handlerArgs)->verbosity = verbose;
|
((ParseeData *) conf.handlerArgs)->verbosity = verbose;
|
||||||
|
|
||||||
|
ext_ctx = ExtensionCreateContext(conf.handlerArgs);
|
||||||
|
((ParseeData *) conf.handlerArgs)->exts = ext_ctx;
|
||||||
|
ExtensionLoadDir(ext_ctx, parsee_conf->extensions);
|
||||||
|
|
||||||
Log(LOG_NOTICE, "Setting up local Matrix user...");
|
Log(LOG_NOTICE, "Setting up local Matrix user...");
|
||||||
if (ASRegisterUser(parsee_conf, parsee_conf->sender_localpart))
|
if (ASRegisterUser(parsee_conf, parsee_conf->sender_localpart))
|
||||||
{
|
{
|
||||||
|
|
@ -332,6 +346,8 @@ end:
|
||||||
ParseeDestroyHeadTable();
|
ParseeDestroyHeadTable();
|
||||||
ParseeDestroyJIDTable();
|
ParseeDestroyJIDTable();
|
||||||
|
|
||||||
|
ExtensionDestroyContext(ext_ctx);
|
||||||
|
|
||||||
(void) env;
|
(void) env;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,8 @@ ParseeConfigLoad(char *conf)
|
||||||
CopyToStr(component_host, "component_host");
|
CopyToStr(component_host, "component_host");
|
||||||
CopyToStr(shared_comp_secret, "shared_secret");
|
CopyToStr(shared_comp_secret, "shared_secret");
|
||||||
CopyToInt(max_stanza_size, "max_stanza_size");
|
CopyToInt(max_stanza_size, "max_stanza_size");
|
||||||
|
|
||||||
|
CopyToStr(extensions, "extensions");
|
||||||
if (!config->max_stanza_size)
|
if (!config->max_stanza_size)
|
||||||
{
|
{
|
||||||
/* Standard XMPP "minimum" maximum */
|
/* Standard XMPP "minimum" maximum */
|
||||||
|
|
@ -140,6 +142,7 @@ ParseeConfigFree(void)
|
||||||
Free(config->namespace_base);
|
Free(config->namespace_base);
|
||||||
Free(config->media_base);
|
Free(config->media_base);
|
||||||
Free(config->listen_as);
|
Free(config->listen_as);
|
||||||
|
Free(config->extensions);
|
||||||
Free(config);
|
Free(config);
|
||||||
}
|
}
|
||||||
const ParseeConfig *
|
const ParseeConfig *
|
||||||
|
|
|
||||||
|
|
@ -726,3 +726,13 @@ ParseeIsMediaEnabled(ParseeData *data, char *chat_id)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
bool
|
||||||
|
ParseeIsMUC(ParseeData *data, char *jid)
|
||||||
|
{
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return XMPPQueryMUC(data->jabber, jid, NULL);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,6 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags)
|
||||||
char *href = HashMapGet(elem->attrs, "href");
|
char *href = HashMapGet(elem->attrs, "href");
|
||||||
/* 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("(");
|
|
||||||
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 +161,9 @@ 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(" >");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,10 @@ 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));
|
||||||
|
if (ExtensionPushEvent(args->data->exts, event))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
ParseeEventHandler(args->data, event);
|
ParseeEventHandler(args->data, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,10 @@
|
||||||
#include <Cytoplasm/Array.h>
|
#include <Cytoplasm/Array.h>
|
||||||
#include <Cytoplasm/Str.h>
|
#include <Cytoplasm/Str.h>
|
||||||
|
|
||||||
struct XMPPCommand {
|
#include "XMPPCommand/Internal.h"
|
||||||
XMPPCmdCallback callback;
|
|
||||||
char *node, *name;
|
|
||||||
|
|
||||||
char *form_instruction;
|
|
||||||
char *form_title;
|
|
||||||
|
|
||||||
/* TODO: On-the-fly generation of options */
|
|
||||||
Array *options;
|
|
||||||
XMPPOptionWriter otf;
|
|
||||||
};
|
|
||||||
|
|
||||||
XMPPCommand *
|
XMPPCommand *
|
||||||
XMPPBasicCmd(char *node, char *name, XMPPCmdCallback callback_funct)
|
XMPPBasicCmd(XMPPCommandFlags flags, char *node, char *name, XMPPCmdCallback callback_funct)
|
||||||
{
|
{
|
||||||
XMPPCommand *cmd;
|
XMPPCommand *cmd;
|
||||||
|
|
||||||
|
|
@ -32,6 +22,7 @@ XMPPBasicCmd(char *node, char *name, XMPPCmdCallback callback_funct)
|
||||||
cmd->name = StrDuplicate(name);
|
cmd->name = StrDuplicate(name);
|
||||||
cmd->form_instruction = NULL;
|
cmd->form_instruction = NULL;
|
||||||
cmd->form_title = NULL;
|
cmd->form_title = NULL;
|
||||||
|
cmd->flags = flags;
|
||||||
|
|
||||||
/* No options -> no form required */
|
/* No options -> no form required */
|
||||||
cmd->options = NULL;
|
cmd->options = NULL;
|
||||||
|
|
@ -127,7 +118,7 @@ XMPPFormifyCommand(XMPPCommandManager *m, XMPPCommand *cmd, char *from)
|
||||||
ArrayFree(cmd->options);
|
ArrayFree(cmd->options);
|
||||||
cmd->options = NULL;
|
cmd->options = NULL;
|
||||||
|
|
||||||
cmd->otf(m, cmd, from);
|
cmd->otf(m, cmd, from, cmd->node);
|
||||||
}
|
}
|
||||||
if (!cmd->options)
|
if (!cmd->options)
|
||||||
{
|
{
|
||||||
|
|
@ -184,13 +175,13 @@ XMPPCommandRequiresForm(XMPPCommand *cmd)
|
||||||
return cmd ? (cmd->otf || !!cmd->options) : false;
|
return cmd ? (cmd->otf || !!cmd->options) : false;
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
XMPPExecuteCommand(XMPPCommandManager *m, XMPPCommand *cmd, char *from, XMLElement *to, XMLElement *form)
|
XMPPExecuteCommand(XMPPCommandManager *m, XMPPCommand *cmd, char *from, XMLElement *to, XMLElement *form, char *node)
|
||||||
{
|
{
|
||||||
if (!m || !cmd || !from || !to)
|
if (!m || !cmd || !from || !to || !node)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cmd->callback(m, from, form, to);
|
cmd->callback(m, from, form, to, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
17
src/XMPPCommand/Internal.h
Normal file
17
src/XMPPCommand/Internal.h
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include <XMPPCommand.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm/Array.h>
|
||||||
|
|
||||||
|
struct XMPPCommand {
|
||||||
|
XMPPCmdCallback callback;
|
||||||
|
char *node, *name;
|
||||||
|
|
||||||
|
char *form_instruction;
|
||||||
|
char *form_title;
|
||||||
|
|
||||||
|
/* TODO: On-the-fly generation of options */
|
||||||
|
Array *options;
|
||||||
|
XMPPOptionWriter otf;
|
||||||
|
|
||||||
|
XMPPCommandFlags flags;
|
||||||
|
};
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "XMPPCommand/Internal.h"
|
||||||
|
|
||||||
typedef struct XMPPSession {
|
typedef struct XMPPSession {
|
||||||
char *identifier;
|
char *identifier;
|
||||||
|
|
||||||
|
|
@ -323,7 +325,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data)
|
||||||
XMLAddAttr(command_xml, "node", node);
|
XMLAddAttr(command_xml, "node", node);
|
||||||
XMLAddAttr(command_xml, "status", "completed");
|
XMLAddAttr(command_xml, "status", "completed");
|
||||||
XMLAddAttr(command_xml, "sessionid", session_id);
|
XMLAddAttr(command_xml, "sessionid", session_id);
|
||||||
XMPPExecuteCommand(m, cmd, from, command_xml, NULL);
|
XMPPExecuteCommand(m, cmd, from, command_xml, NULL, node);
|
||||||
XMLAddChild(iq, command_xml);
|
XMLAddChild(iq, command_xml);
|
||||||
|
|
||||||
XMPPSendStanza(jabber, iq, data->config->max_stanza_size);
|
XMPPSendStanza(jabber, iq, data->config->max_stanza_size);
|
||||||
|
|
@ -363,7 +365,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data)
|
||||||
XMLAddAttr(command_xml, "node", node);
|
XMLAddAttr(command_xml, "node", node);
|
||||||
XMLAddAttr(command_xml, "status", "completed");
|
XMLAddAttr(command_xml, "status", "completed");
|
||||||
XMLAddAttr(command_xml, "sessionid", session_given);
|
XMLAddAttr(command_xml, "sessionid", session_given);
|
||||||
XMPPExecuteCommand(m, cmd, from, command_xml, x_form);
|
XMPPExecuteCommand(m, cmd, from, command_xml, x_form, node);
|
||||||
XMLAddChild(iq, command_xml);
|
XMLAddChild(iq, command_xml);
|
||||||
|
|
||||||
XMPPSendStanza(jabber, iq, data->config->max_stanza_size);
|
XMPPSendStanza(jabber, iq, data->config->max_stanza_size);
|
||||||
|
|
@ -385,3 +387,15 @@ XMPPGetManagerCookie(XMPPCommandManager *manager)
|
||||||
{
|
{
|
||||||
return manager ? manager->cookie : NULL;
|
return manager ? manager->cookie : NULL;
|
||||||
}
|
}
|
||||||
|
XMPPCommandFlags
|
||||||
|
XMPPGetCommandFlags(XMPPCommandManager *m, char *id)
|
||||||
|
{
|
||||||
|
XMPPCommand *cmd;
|
||||||
|
if (!m || !id)
|
||||||
|
{
|
||||||
|
return XMPPCMD_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = HashMapGet(m->commands, id);
|
||||||
|
return cmd ? cmd->flags : XMPPCMD_ALL;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
#include <XML.h>
|
#include <XML.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
AddAdminCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
AddAdminCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *trimmed = ParseeTrimJID(from);
|
char *trimmed = ParseeTrimJID(from);
|
||||||
|
|
@ -23,6 +23,8 @@ AddAdminCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement
|
||||||
|
|
||||||
GetFieldValue(glob, "glob", form);
|
GetFieldValue(glob, "glob", form);
|
||||||
|
|
||||||
|
(void) node;
|
||||||
|
|
||||||
if (!ParseeIsAdmin(data, trimmed))
|
if (!ParseeIsAdmin(data, trimmed))
|
||||||
{
|
{
|
||||||
SetNote("error", "User is not authorised to execute command.");
|
SetNote("error", "User is not authorised to execute command.");
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
#include <XML.h>
|
#include <XML.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
AddNoflyCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
AddNoflyCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *trimmed = ParseeTrimJID(from);
|
char *trimmed = ParseeTrimJID(from);
|
||||||
|
|
@ -21,6 +21,8 @@ AddNoflyCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement
|
||||||
GetFieldValue(entity, "entity", form);
|
GetFieldValue(entity, "entity", form);
|
||||||
GetFieldValue(reason, "reason", form);
|
GetFieldValue(reason, "reason", form);
|
||||||
|
|
||||||
|
(void) node;
|
||||||
|
|
||||||
if (!ParseeIsAdmin(data, trimmed))
|
if (!ParseeIsAdmin(data, trimmed))
|
||||||
{
|
{
|
||||||
SetNote("error", "User is not authorised to execute command.");
|
SetNote("error", "User is not authorised to execute command.");
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
#include <XML.h>
|
#include <XML.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
AdminsCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
AdminsCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
@ -20,6 +20,8 @@ AdminsCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *
|
||||||
XMLElement *title;
|
XMLElement *title;
|
||||||
XMLElement *reported, *item, *field, *value, *txt;
|
XMLElement *reported, *item, *field, *value, *txt;
|
||||||
|
|
||||||
|
(void) node;
|
||||||
|
|
||||||
x = XMLCreateTag("x");
|
x = XMLCreateTag("x");
|
||||||
title = XMLCreateTag("title");
|
title = XMLCreateTag("title");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
#include <XML.h>
|
#include <XML.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
CleanCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
CleanCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *trimmed = ParseeTrimJID(from);
|
char *trimmed = ParseeTrimJID(from);
|
||||||
|
|
@ -31,4 +31,5 @@ CleanCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *o
|
||||||
SetNote("info", "Parsee data was sucessfully cleant up.");
|
SetNote("info", "Parsee data was sucessfully cleant up.");
|
||||||
|
|
||||||
(void) form;
|
(void) form;
|
||||||
|
(void) node;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ DelAdmin(Array *admin_list, char *glob)
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
DelAdminCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
DelAdminCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *trimmed = ParseeTrimJID(from);
|
char *trimmed = ParseeTrimJID(from);
|
||||||
|
|
@ -84,9 +84,11 @@ DelAdminCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement
|
||||||
}
|
}
|
||||||
SetNote("info", "Sucessfully removed admins");
|
SetNote("info", "Sucessfully removed admins");
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
|
||||||
|
(void) node;
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
FormDelAdminCallback(XMPPCommandManager *m, XMPPCommand *cmd, char *from)
|
FormDelAdminCallback(XMPPCommandManager *m, XMPPCommand *cmd, char *from, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
DbRef *admins;
|
DbRef *admins;
|
||||||
|
|
@ -120,4 +122,6 @@ FormDelAdminCallback(XMPPCommandManager *m, XMPPCommand *cmd, char *from)
|
||||||
|
|
||||||
DbUnlock(data->db, admins);
|
DbUnlock(data->db, admins);
|
||||||
XMPPAddOption(cmd, admin_opt);
|
XMPPAddOption(cmd, admin_opt);
|
||||||
|
|
||||||
|
(void) node;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
#include <XML.h>
|
#include <XML.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
MUCInformationID(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
MUCInformationID(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *muc = ParseeTrimJID(from);
|
char *muc = ParseeTrimJID(from);
|
||||||
|
|
@ -29,9 +29,10 @@ MUCInformationID(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement
|
||||||
Free(room_id);
|
Free(room_id);
|
||||||
Free(chat_id);
|
Free(chat_id);
|
||||||
(void) form;
|
(void) form;
|
||||||
|
(void) node;
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
MUCInformationCID(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
MUCInformationCID(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *muc = ParseeTrimJID(from);
|
char *muc = ParseeTrimJID(from);
|
||||||
|
|
@ -46,4 +47,5 @@ MUCInformationCID(XMPPCommandManager *m, char *from, XMLElement *form, XMLElemen
|
||||||
Free(msg);
|
Free(msg);
|
||||||
Free(chat_id);
|
Free(chat_id);
|
||||||
(void) form;
|
(void) form;
|
||||||
|
(void) node;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
#include <AS.h>
|
#include <AS.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
MUCSetKey(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
MUCSetKey(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *affiliation, *role;
|
char *affiliation, *role;
|
||||||
|
|
@ -51,9 +51,10 @@ end:
|
||||||
Free(chat_id);
|
Free(chat_id);
|
||||||
Free(muc);
|
Free(muc);
|
||||||
(void) form;
|
(void) form;
|
||||||
|
(void) node;
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
MUCGetKeys(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
MUCGetKeys(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *affiliation = NULL, *role = NULL;
|
char *affiliation = NULL, *role = NULL;
|
||||||
|
|
@ -114,4 +115,5 @@ end:
|
||||||
Free(chat_id);
|
Free(chat_id);
|
||||||
Free(muc);
|
Free(muc);
|
||||||
(void) form;
|
(void) form;
|
||||||
|
(void) node;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
#include <AS.h>
|
#include <AS.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
MUCUnlink(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
MUCUnlink(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *affiliation, *role;
|
char *affiliation, *role;
|
||||||
|
|
@ -64,4 +64,5 @@ MUCUnlink(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
||||||
Free(room);
|
Free(room);
|
||||||
Free(muc);
|
Free(muc);
|
||||||
(void) form;
|
(void) form;
|
||||||
|
(void) node;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
#define TITLE "Parsee global bans"
|
#define TITLE "Parsee global bans"
|
||||||
|
|
||||||
void
|
void
|
||||||
NoflyCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
NoflyCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *trimmed = ParseeTrimJID(from);
|
char *trimmed = ParseeTrimJID(from);
|
||||||
|
|
@ -89,4 +89,5 @@ NoflyCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *o
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) form;
|
(void) form;
|
||||||
|
(void) node;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
#include <XML.h>
|
#include <XML.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
char *trimmed = ParseeTrimJID(from);
|
char *trimmed = ParseeTrimJID(from);
|
||||||
size_t alloc = MemoryAllocated();
|
size_t alloc = MemoryAllocated();
|
||||||
|
|
@ -69,5 +69,6 @@ StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *
|
||||||
XMLAddChild(out, x);
|
XMLAddChild(out, x);
|
||||||
|
|
||||||
(void) form;
|
(void) form;
|
||||||
|
(void) node;
|
||||||
(void) m;
|
(void) m;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
#include <XML.h>
|
#include <XML.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
ClearWhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
ClearWhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *trimmed = ParseeTrimJID(from);
|
char *trimmed = ParseeTrimJID(from);
|
||||||
|
|
@ -35,9 +35,10 @@ ClearWhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLE
|
||||||
SetNote("info", "Parsee whitelist was removed.");
|
SetNote("info", "Parsee whitelist was removed.");
|
||||||
|
|
||||||
(void) form;
|
(void) form;
|
||||||
|
(void) node;
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
AddWhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
AddWhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *trimmed = ParseeTrimJID(from);
|
char *trimmed = ParseeTrimJID(from);
|
||||||
|
|
@ -79,9 +80,10 @@ AddWhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLEle
|
||||||
DbUnlock(data->db, ref);
|
DbUnlock(data->db, ref);
|
||||||
|
|
||||||
SetNote("info", "Server successfully whitelisted.");
|
SetNote("info", "Server successfully whitelisted.");
|
||||||
|
(void) node;
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
WhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
WhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out, char *node)
|
||||||
{
|
{
|
||||||
ParseeData *data = XMPPGetManagerCookie(m);
|
ParseeData *data = XMPPGetManagerCookie(m);
|
||||||
char *trimmed = ParseeTrimJID(from);
|
char *trimmed = ParseeTrimJID(from);
|
||||||
|
|
@ -139,4 +141,5 @@ WhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElemen
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) form;
|
(void) form;
|
||||||
|
(void) node;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,15 +94,13 @@ PEPVCardEvent(PEPManager *m, XMLElement *stanza, XMLElement *item)
|
||||||
AddTextField(vcard, "fn", name);
|
AddTextField(vcard, "fn", name);
|
||||||
AddTextField(vcard, "nickname", mxid);
|
AddTextField(vcard, "nickname", mxid);
|
||||||
|
|
||||||
AddURIField(vcard, "url", REPOSITORY);
|
|
||||||
AddURIField(vcard, "url", "https://kappach.at/parsee");
|
AddURIField(vcard, "url", "https://kappach.at/parsee");
|
||||||
AddURIField(vcard, "url", "https://matrix.org");
|
|
||||||
AddURIField(vcard, "url", m_to);
|
AddURIField(vcard, "url", m_to);
|
||||||
|
|
||||||
AddTextField(
|
AddTextField(
|
||||||
vcard,
|
vcard,
|
||||||
"note",
|
"note",
|
||||||
"This is a bridged Matrix user, from Parsee."
|
"This is a bridged Matrix user, from " NAME "."
|
||||||
);
|
);
|
||||||
Free(mxid);
|
Free(mxid);
|
||||||
Free(name);
|
Free(name);
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,16 @@ XMPPDispatcher(void *argp)
|
||||||
Log(LOG_DEBUG, "Received stanza='%s'.", stanza->name);
|
Log(LOG_DEBUG, "Received stanza='%s'.", stanza->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ExtensionPushStanza(args->exts, stanza, STANZA_RAW))
|
||||||
|
{
|
||||||
|
if (args->verbosity >= PARSEE_VERBOSE_COMICAL)
|
||||||
|
{
|
||||||
|
Log(LOG_DEBUG, "Stanza was vetoed by an extension.");
|
||||||
|
}
|
||||||
|
XMLFreeElement(stanza);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (StrEquals(stanza->name, "presence"))
|
if (StrEquals(stanza->name, "presence"))
|
||||||
{
|
{
|
||||||
PresenceStanza(args, stanza, thread);
|
PresenceStanza(args, stanza, thread);
|
||||||
|
|
@ -130,6 +140,7 @@ bool
|
||||||
XMPPCommandFilter(XMPPCommandManager *m, char *id, XMLElement *stanza)
|
XMPPCommandFilter(XMPPCommandManager *m, char *id, XMLElement *stanza)
|
||||||
{
|
{
|
||||||
ParseeData *args = XMPPGetManagerCookie(m);
|
ParseeData *args = XMPPGetManagerCookie(m);
|
||||||
|
XMPPCommandFlags flags;
|
||||||
char *trimmed_from;
|
char *trimmed_from;
|
||||||
char *from;
|
char *from;
|
||||||
char *chat_id;
|
char *chat_id;
|
||||||
|
|
@ -144,28 +155,24 @@ XMPPCommandFilter(XMPPCommandManager *m, char *id, XMLElement *stanza)
|
||||||
is_muc = !!(chat_id = ParseeGetFromMUCID(args, trimmed_from));
|
is_muc = !!(chat_id = ParseeGetFromMUCID(args, trimmed_from));
|
||||||
Free(trimmed_from);
|
Free(trimmed_from);
|
||||||
Free(chat_id);
|
Free(chat_id);
|
||||||
#define XMPP_COMMAND(f,l,n,t,s) \
|
flags = XMPPGetCommandFlags(m, id);
|
||||||
if (StrEquals(n, id)) \
|
|
||||||
{ \
|
if (flags == XMPPCMD_ALL)
|
||||||
if (l == XMPPCMD_ALL) \
|
{
|
||||||
{ \
|
return true;
|
||||||
return true; \
|
}
|
||||||
} \
|
else if (flags == XMPPCMD_MUC)
|
||||||
else if (l == XMPPCMD_MUC) \
|
{
|
||||||
{ \
|
return is_muc;
|
||||||
return is_muc; \
|
}
|
||||||
} \
|
else if (flags == XMPPCMD_ADMINS)
|
||||||
else if (l == XMPPCMD_ADMINS) \
|
{
|
||||||
{ \
|
bool is_admin;
|
||||||
bool is_admin; \
|
trimmed_from = ParseeTrimJID(from);
|
||||||
trimmed_from = ParseeTrimJID(from); \
|
is_admin = ParseeIsAdmin(args, trimmed_from);
|
||||||
is_admin = ParseeIsAdmin(args, trimmed_from); \
|
Free(trimmed_from);
|
||||||
Free(trimmed_from); \
|
return is_admin;
|
||||||
return is_admin; \
|
|
||||||
} \
|
|
||||||
}
|
}
|
||||||
XMPPCOMMANDS
|
|
||||||
#undef XMPP_COMMAND
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -191,13 +198,14 @@ ParseeXMPPThread(void *argp)
|
||||||
XMPPCommand *cmd;
|
XMPPCommand *cmd;
|
||||||
#define XMPP_COMMAND(f,l,n,t,s) \
|
#define XMPP_COMMAND(f,l,n,t,s) \
|
||||||
cmd = XMPPBasicCmd( \
|
cmd = XMPPBasicCmd( \
|
||||||
n, t, f \
|
l, n, t, f \
|
||||||
); \
|
); \
|
||||||
s \
|
s \
|
||||||
XMPPRegisterCommand(info.m, cmd);
|
XMPPRegisterCommand(info.m, cmd);
|
||||||
XMPPCOMMANDS
|
XMPPCOMMANDS
|
||||||
#undef XMPP_COMMAND
|
#undef XMPP_COMMAND
|
||||||
}
|
}
|
||||||
|
ExtensionRequestCommands(args->exts);
|
||||||
info.pep_manager = CreatePEPManager(args, &info);
|
info.pep_manager = CreatePEPManager(args, &info);
|
||||||
{
|
{
|
||||||
PEPManagerAddEvent(
|
PEPManagerAddEvent(
|
||||||
|
|
|
||||||
|
|
@ -421,10 +421,16 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
||||||
char *parsee_muc_jid = StrConcat(3, trimmed, "/", "parsee");
|
char *parsee_muc_jid = StrConcat(3, trimmed, "/", "parsee");
|
||||||
XMLAddAttr(q, "xmlns", "http://jabber.org/protocol/disco#items");
|
XMLAddAttr(q, "xmlns", "http://jabber.org/protocol/disco#items");
|
||||||
XMLAddAttr(q, "node", "http://jabber.org/protocol/commands");
|
XMLAddAttr(q, "node", "http://jabber.org/protocol/commands");
|
||||||
|
|
||||||
XMPPShoveCommandList(thr->info->m,
|
XMPPShoveCommandList(thr->info->m,
|
||||||
IsInMUC(args, from) ? parsee_muc_jid : to,
|
IsInMUC(args, from) ? parsee_muc_jid : to,
|
||||||
q, stanza
|
q, stanza
|
||||||
);
|
);
|
||||||
|
ExtensionShoveCommands(
|
||||||
|
args->exts,
|
||||||
|
IsInMUC(args, from) ? parsee_muc_jid : to,
|
||||||
|
q, stanza
|
||||||
|
);
|
||||||
XMLAddChild(iq_reply, q);
|
XMLAddChild(iq_reply, q);
|
||||||
Free(parsee_muc_jid);
|
Free(parsee_muc_jid);
|
||||||
}
|
}
|
||||||
|
|
@ -611,6 +617,7 @@ IQSet(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
||||||
{
|
{
|
||||||
XMPPCommandManager *manager = thr->info->m;
|
XMPPCommandManager *manager = thr->info->m;
|
||||||
XMPPManageCommand(manager, stanza, args);
|
XMPPManageCommand(manager, stanza, args);
|
||||||
|
ExtensionManageCommands(args->exts, stanza);
|
||||||
}
|
}
|
||||||
#undef DISCO
|
#undef DISCO
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -411,7 +411,17 @@ end_error:
|
||||||
|
|
||||||
/* Check if it is a media link */
|
/* Check if it is a media link */
|
||||||
oob = XMLookForTKV(stanza, "x", "xmlns", "jabber:x:oob");
|
oob = XMLookForTKV(stanza, "x", "xmlns", "jabber:x:oob");
|
||||||
if (oob && data && media_enabled)
|
|
||||||
|
/* TODO: This may be way too late. I think a way to listen to *all*
|
||||||
|
* stanzas may be worthwhile. */
|
||||||
|
if (ExtensionPushStanza(args->exts, stanza, STANZA_MESSAGE))
|
||||||
|
{
|
||||||
|
//if (args->verbosity >= PARSEE_VERBOSE_COMICAL)
|
||||||
|
{
|
||||||
|
Log(LOG_DEBUG, "Stanza was vetoed by an extension.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (oob && data && media_enabled)
|
||||||
{
|
{
|
||||||
char *mxc, *mime = NULL;
|
char *mxc, *mime = NULL;
|
||||||
HashMap *content = NULL;
|
HashMap *content = NULL;
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,6 @@ int IdentitySort(void *idap, void *idbp);
|
||||||
char * ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza);
|
char * ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza);
|
||||||
char * ParseeGetEventFromID(ParseeData *data, XMLElement *stanza, char *id);
|
char * ParseeGetEventFromID(ParseeData *data, XMLElement *stanza, char *id);
|
||||||
char * ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza);
|
char * ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza);
|
||||||
void ParseePushAllStanza(ParseeData *args, XMLElement *stanza, char *event);
|
|
||||||
bool ParseeVerifyAllStanza(ParseeData *args, XMLElement *stanza);
|
bool ParseeVerifyAllStanza(ParseeData *args, XMLElement *stanza);
|
||||||
|
|
||||||
HashMap * ShoveStanza(HashMap *content, XMLElement *stanza);
|
HashMap * ShoveStanza(HashMap *content, XMLElement *stanza);
|
||||||
|
|
@ -82,9 +81,6 @@ void PresenceStanza(ParseeData *args, XMLElement *stanza, XMPPThread *thr);
|
||||||
|
|
||||||
bool ServerHasXEP421(ParseeData *data, char *from);
|
bool ServerHasXEP421(ParseeData *data, char *from);
|
||||||
|
|
||||||
char * ParseeGetBridgedUserI(ParseeData *data, XMLElement *stanza, char *force);
|
|
||||||
#define ParseeGetBridgedUser(data, stanza) ParseeGetBridgedUserI(data, stanza, NULL)
|
|
||||||
|
|
||||||
PEPManager * CreatePEPManager(ParseeData *data, void *cookie);
|
PEPManager * CreatePEPManager(ParseeData *data, void *cookie);
|
||||||
void * PEPManagerCookie(PEPManager *manager);
|
void * PEPManagerCookie(PEPManager *manager);
|
||||||
void PEPManagerAddEvent(PEPManager *manager, char *node, PEPEvent event);
|
void PEPManagerAddEvent(PEPManager *manager, char *node, PEPEvent event);
|
||||||
|
|
|
||||||
81
src/include/Extension.h
Normal file
81
src/include/Extension.h
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
#ifndef PARSEE_EXTENSION_H
|
||||||
|
#define PARSEE_EXTENSION_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm/Json.h>
|
||||||
|
|
||||||
|
#include <XML.h>
|
||||||
|
|
||||||
|
typedef struct ParseeData ParseeData;
|
||||||
|
|
||||||
|
typedef struct Extensions Extensions;
|
||||||
|
typedef struct Extension Extension;
|
||||||
|
|
||||||
|
typedef enum StanzaType {
|
||||||
|
STANZA_RAW = 0,
|
||||||
|
STANZA_MESSAGE = 1,
|
||||||
|
STANZA_IQ = 2,
|
||||||
|
STANZA_PRESENCE = 3,
|
||||||
|
|
||||||
|
STANZA_TYPE_COUNT
|
||||||
|
} StanzaType;
|
||||||
|
|
||||||
|
/** Verifies if extensions are enabled with the Parsee binary.
|
||||||
|
* Functions here <strong>WILL</strong> fail if this function
|
||||||
|
* returns false!
|
||||||
|
* -------------------
|
||||||
|
* Returns: true IFF extensions are enabled */
|
||||||
|
extern bool ExtensionEnabled(void);
|
||||||
|
|
||||||
|
/* Creates an extension context. */
|
||||||
|
extern Extensions * ExtensionCreateContext(struct ParseeData *data);
|
||||||
|
|
||||||
|
/** Destroys the entire extension context, and all of its extensions.
|
||||||
|
* -------------------------------------
|
||||||
|
* Returns: NOTHING
|
||||||
|
* Thrashes: ctx */
|
||||||
|
extern void ExtensionDestroyContext(Extensions *ctx);
|
||||||
|
|
||||||
|
/** Loads a basic extension from a simple Janet file.
|
||||||
|
* ----------------------------
|
||||||
|
* Returns: An extension handle[ctx] | NULL */
|
||||||
|
extern Extension * ExtensionLoadBasic(Extensions *ctx, char *id, char *file);
|
||||||
|
|
||||||
|
/** Reloads an extension from an ID.
|
||||||
|
* ---------------------------
|
||||||
|
* Returns: NOTHING */
|
||||||
|
extern void ExtensionReload(Extensions *ctx, char *id);
|
||||||
|
|
||||||
|
/** Loads extensions from a directory. The directory's Janet files are loaded
|
||||||
|
* (with the part before the .janet extension denoting the identifier).
|
||||||
|
* -----------------------------------
|
||||||
|
* Returns: NOTHING */
|
||||||
|
extern void ExtensionLoadDir(Extensions *ctx, char *dir);
|
||||||
|
|
||||||
|
/** Broadcasts a stanza received to all extensions(by calling the
|
||||||
|
* on-stanza function).
|
||||||
|
* -----------------------------------------
|
||||||
|
* Returns: NOTHING
|
||||||
|
* Modifies: the extensions */
|
||||||
|
extern bool ExtensionPushStanza(Extensions *ctx, XMLElement *stanza, StanzaType t);
|
||||||
|
|
||||||
|
/** Broadcasts a Matrix event to all extensions, akin to ExtensionPushStanza.
|
||||||
|
* -----------
|
||||||
|
* Returns: NOTHING
|
||||||
|
* Modifies: the extensions */
|
||||||
|
extern bool ExtensionPushEvent(Extensions *ctx, HashMap *obj);
|
||||||
|
|
||||||
|
/** Calls "on-xmpp-cmd" on extensions' Janet side, with no arguments.
|
||||||
|
* ----------
|
||||||
|
* Returns: NOTHING
|
||||||
|
* Modifies: the extensions */
|
||||||
|
extern void ExtensionRequestCommands(Extensions *ctx);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
ExtensionShoveCommands(Extensions *ctx, char *jid, XMLElement *query, XMLElement *stanza);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
ExtensionManageCommands(Extensions *ctx, XMLElement *stanza);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -15,6 +15,7 @@ typedef struct ParseeData ParseeData;
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <Extension.h>
|
||||||
#include <Command.h>
|
#include <Command.h>
|
||||||
#include <XMPP.h>
|
#include <XMPP.h>
|
||||||
|
|
||||||
|
|
@ -50,6 +51,7 @@ typedef struct ParseeConfig {
|
||||||
/* ------- DB -------- */
|
/* ------- DB -------- */
|
||||||
char *db_path;
|
char *db_path;
|
||||||
size_t db_size;
|
size_t db_size;
|
||||||
|
char *extensions;
|
||||||
|
|
||||||
/* - COMMAND-LINE FLAGS - */
|
/* - COMMAND-LINE FLAGS - */
|
||||||
int xmpp_threads, http_threads;
|
int xmpp_threads, http_threads;
|
||||||
|
|
@ -72,8 +74,10 @@ typedef struct ParseeData {
|
||||||
pthread_mutex_t oidl;
|
pthread_mutex_t oidl;
|
||||||
|
|
||||||
/* If Parsee was intentionally halted */
|
/* If Parsee was intentionally halted */
|
||||||
bool halted;
|
volatile bool halted;
|
||||||
pthread_mutex_t halt_lock;
|
pthread_mutex_t halt_lock;
|
||||||
|
|
||||||
|
Extensions *exts;
|
||||||
} ParseeData;
|
} ParseeData;
|
||||||
|
|
||||||
typedef struct Argument {
|
typedef struct Argument {
|
||||||
|
|
@ -93,6 +97,8 @@ typedef struct Argument {
|
||||||
#define GrabObject(obj, ...) JsonValueAsObject(JsonGet(obj, __VA_ARGS__))
|
#define GrabObject(obj, ...) JsonValueAsObject(JsonGet(obj, __VA_ARGS__))
|
||||||
#define GrabArray(obj, ...) JsonValueAsArray(JsonGet(obj, __VA_ARGS__))
|
#define GrabArray(obj, ...) JsonValueAsArray(JsonGet(obj, __VA_ARGS__))
|
||||||
|
|
||||||
|
#define IterateReentrant(h, k, v, i) HashMapIterateReentrant(h, &k, (void **) &v, &i)
|
||||||
|
|
||||||
/* Milliseconds to UNIT macros, to be used like 30 SECONDS and 1 MINUTES
|
/* Milliseconds to UNIT macros, to be used like 30 SECONDS and 1 MINUTES
|
||||||
* in timestamps */
|
* in timestamps */
|
||||||
#define SECONDS * 1000
|
#define SECONDS * 1000
|
||||||
|
|
@ -121,6 +127,7 @@ extern const char *parsee_ascii[PARSEE_ASCII_LINES];
|
||||||
* Modifies: the logger output */
|
* Modifies: the logger output */
|
||||||
extern void ParseePrintASCII(void);
|
extern void ParseePrintASCII(void);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if two versions of Parsee can be considered "compatible".
|
* Checks if two versions of Parsee can be considered "compatible".
|
||||||
* This is mainly used for things like database operations. TODO:
|
* This is mainly used for things like database operations. TODO:
|
||||||
|
|
@ -276,6 +283,12 @@ extern char * ParseeGetRoomID(ParseeData *, char *chat_id);
|
||||||
/* Finds the MUC JID from a chat ID */
|
/* Finds the MUC JID from a chat ID */
|
||||||
extern char * ParseeGetMUCID(ParseeData *, char *chat_id);
|
extern char * ParseeGetMUCID(ParseeData *, char *chat_id);
|
||||||
|
|
||||||
|
/** Verifies if a JID maps to a chatroom through Service Discovery.
|
||||||
|
* ----------------
|
||||||
|
* Returns: whenever the JID is a real MUC
|
||||||
|
* Modifies: the XMPP stream */
|
||||||
|
extern bool ParseeIsMUC(ParseeData *data, char *jid);
|
||||||
|
|
||||||
/** Fetches a configuration value from a key in a chat(given a Chat ID),
|
/** Fetches a configuration value from a key in a chat(given a Chat ID),
|
||||||
* as a string or NULL. Keys are to be stored like Java packages(reveres DNS).
|
* as a string or NULL. Keys are to be stored like Java packages(reveres DNS).
|
||||||
* Parsee has the right over any key with the <code>'p.'</code> prefix.
|
* Parsee has the right over any key with the <code>'p.'</code> prefix.
|
||||||
|
|
@ -321,6 +334,14 @@ ParseeIsMediaEnabled(ParseeData *data, char *chat_id);
|
||||||
extern void ParseePushStanza(ParseeData *, char *chat_id, char *stanza_id, char *origin_id, char *event, char *sender);
|
extern void ParseePushStanza(ParseeData *, char *chat_id, char *stanza_id, char *origin_id, char *event, char *sender);
|
||||||
extern void ParseePushDMStanza(ParseeData *, char *room_id, char *stanza_id, char *origin_id, char *event, char *sender);
|
extern void ParseePushDMStanza(ParseeData *, char *room_id, char *stanza_id, char *origin_id, char *event, char *sender);
|
||||||
|
|
||||||
|
/** Automatically pushes the link between a stanza and a bridged Matrix event.
|
||||||
|
* It behaves like {ParseePushStanza} and {ParseePushDMStanza}, but the routing
|
||||||
|
* is done automatically.
|
||||||
|
* ----------------------------
|
||||||
|
* Returns: NOTHING
|
||||||
|
* Modifies: the database */
|
||||||
|
extern void ParseePushAllStanza(ParseeData *args, XMLElement *stanza, char *event);
|
||||||
|
|
||||||
/* Checks if a stanza is not duplicated in a chat ID */
|
/* Checks if a stanza is not duplicated in a chat ID */
|
||||||
extern bool ParseeVerifyStanza(ParseeData *, char *chat_id, char *stanza_id);
|
extern bool ParseeVerifyStanza(ParseeData *, char *chat_id, char *stanza_id);
|
||||||
|
|
||||||
|
|
@ -488,4 +509,8 @@ extern void ParseeUnlinkRoom(ParseeData *data, char *chat_id);
|
||||||
* Modifies: NOTHING */
|
* Modifies: NOTHING */
|
||||||
extern bool ParseeIsMUCWhitelisted(ParseeData *data, char *muc);
|
extern bool ParseeIsMUCWhitelisted(ParseeData *data, char *muc);
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
extern char * ParseeGetBridgedUserI(ParseeData *data, XMLElement *stanza, char *force);
|
||||||
|
#define ParseeGetBridgedUser(data, stanza) ParseeGetBridgedUserI(data, stanza, NULL)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
typedef struct XMPPCommandManager XMPPCommandManager;
|
||||||
#ifndef PARSEE_XMPPCOMMAND_H
|
#ifndef PARSEE_XMPPCOMMAND_H
|
||||||
#define PARSEE_XMPPCOMMAND_H
|
#define PARSEE_XMPPCOMMAND_H
|
||||||
|
|
||||||
|
|
@ -7,11 +8,16 @@
|
||||||
#include <Parsee.h>
|
#include <Parsee.h>
|
||||||
#include <XML.h>
|
#include <XML.h>
|
||||||
|
|
||||||
typedef struct XMPPCommandManager XMPPCommandManager;
|
typedef enum XMPPCommandFlags {
|
||||||
|
XMPPCMD_ALL = 0,
|
||||||
|
XMPPCMD_MUC , /* Only for MUCs */
|
||||||
|
XMPPCMD_ADMINS /* Only for administrators */
|
||||||
|
} XMPPCommandFlags;
|
||||||
|
|
||||||
typedef struct XMPPCommand XMPPCommand;
|
typedef struct XMPPCommand XMPPCommand;
|
||||||
typedef struct XMPPOption XMPPOption;
|
typedef struct XMPPOption XMPPOption;
|
||||||
typedef void (*XMPPCmdCallback)(XMPPCommandManager *, char *, XMLElement *, XMLElement *);
|
typedef void (*XMPPCmdCallback)(XMPPCommandManager *, char *, XMLElement *, XMLElement *, char *);
|
||||||
typedef void (*XMPPOptionWriter)(XMPPCommandManager *, XMPPCommand *, char *);
|
typedef void (*XMPPOptionWriter)(XMPPCommandManager *, XMPPCommand *, char *, char *);
|
||||||
typedef bool (*XMPPCmdFilter)(XMPPCommandManager *, char *id, XMLElement *stanza);
|
typedef bool (*XMPPCmdFilter)(XMPPCommandManager *, char *id, XMLElement *stanza);
|
||||||
|
|
||||||
/** Creates a simple XMPP command manager, which routes commands
|
/** Creates a simple XMPP command manager, which routes commands
|
||||||
|
|
@ -39,7 +45,7 @@ XMPPManagerSetFilter(XMPPCommandManager *manager, XMPPCmdFilter filter);
|
||||||
* Modifies: NOTHING
|
* Modifies: NOTHING
|
||||||
* See-Also: XMPPRegisterCommand */
|
* See-Also: XMPPRegisterCommand */
|
||||||
extern XMPPCommand *
|
extern XMPPCommand *
|
||||||
XMPPBasicCmd(char *node, char *name, XMPPCmdCallback cb);
|
XMPPBasicCmd(XMPPCommandFlags flags, char *node, char *name, XMPPCmdCallback cb);
|
||||||
extern void
|
extern void
|
||||||
XMPPCmdOptionsCreator(XMPPCommand *cmd, XMPPOptionWriter writer);
|
XMPPCmdOptionsCreator(XMPPCommand *cmd, XMPPOptionWriter writer);
|
||||||
extern void XMPPAddOption(XMPPCommand *cmd, XMPPOption *opt);
|
extern void XMPPAddOption(XMPPCommand *cmd, XMPPOption *opt);
|
||||||
|
|
@ -49,7 +55,7 @@ extern char * XMPPGetCommandDesc(XMPPCommand *cmd);
|
||||||
extern void XMPPSetFormInstruction(XMPPCommand *cmd, char *instruction);
|
extern void XMPPSetFormInstruction(XMPPCommand *cmd, char *instruction);
|
||||||
extern void XMPPSetFormTitle(XMPPCommand *cmd, char *title);
|
extern void XMPPSetFormTitle(XMPPCommand *cmd, char *title);
|
||||||
extern bool XMPPCommandRequiresForm(XMPPCommand *cmd);
|
extern bool XMPPCommandRequiresForm(XMPPCommand *cmd);
|
||||||
extern void XMPPExecuteCommand(XMPPCommandManager *m, XMPPCommand *cmd, char *from, XMLElement *to, XMLElement *form);
|
extern void XMPPExecuteCommand(XMPPCommandManager *m, XMPPCommand *cmd, char *from, XMLElement *to, XMLElement *form, char *node);
|
||||||
|
|
||||||
/** Create a basic option.
|
/** Create a basic option.
|
||||||
* -----------------------------------------------------
|
* -----------------------------------------------------
|
||||||
|
|
@ -91,6 +97,12 @@ extern void XMPPRegisterCommand(XMPPCommandManager *m, XMPPCommand *cmd);
|
||||||
* See-Also: XMPPCreateManager */
|
* See-Also: XMPPCreateManager */
|
||||||
extern void XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p, XMLElement *s);
|
extern void XMPPShoveCommandList(XMPPCommandManager *m, char *jid, XMLElement *p, XMLElement *s);
|
||||||
|
|
||||||
|
/** Returns the flags associated to a command.
|
||||||
|
* ----------------
|
||||||
|
* Returns: some flags
|
||||||
|
* Modifies: NOTHING */
|
||||||
|
extern XMPPCommandFlags XMPPGetCommandFlags(XMPPCommandManager *m, char *id);
|
||||||
|
|
||||||
/** Destroys all memory related to the command {manager}.
|
/** Destroys all memory related to the command {manager}.
|
||||||
* -----------------------------------------------------
|
* -----------------------------------------------------
|
||||||
* Returns: NOTHING
|
* Returns: NOTHING
|
||||||
|
|
@ -111,11 +123,11 @@ extern bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeD
|
||||||
|
|
||||||
#define XMPP_COMMAND(f,l,n,t,s) \
|
#define XMPP_COMMAND(f,l,n,t,s) \
|
||||||
extern void \
|
extern void \
|
||||||
f(XMPPCommandManager *, char *, XMLElement *, XMLElement *); \
|
f(XMPPCommandManager *, char *, XMLElement *, XMLElement *, char *); \
|
||||||
/* This symbol might not exist. We do, however, not care, as
|
/* This symbol might not exist. We do, however, not care, as
|
||||||
* it is not always done. */ \
|
* it is not always done. */ \
|
||||||
extern void \
|
extern void \
|
||||||
Form##f(XMPPCommandManager *, XMPPCommand *, char *); \
|
Form##f(XMPPCommandManager *, XMPPCommand *, char *, char *); \
|
||||||
|
|
||||||
#include "XMPPCommands.x.h"
|
#include "XMPPCommands.x.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,4 @@
|
||||||
/* C X-macro file */
|
/* C X-macro file */
|
||||||
typedef enum XMPPCommandFlags {
|
|
||||||
XMPPCMD_ALL = 0,
|
|
||||||
XMPPCMD_MUC , /* Only for MUCs */
|
|
||||||
XMPPCMD_ADMINS /* Only for administrators */
|
|
||||||
} XMPPCommandFlags;
|
|
||||||
#define XMPPCOMMANDS \
|
#define XMPPCOMMANDS \
|
||||||
XMPP_COMMAND(StatusCallback, XMPPCMD_ALL, "stats", "Get Parsee statistics", {}) \
|
XMPP_COMMAND(StatusCallback, XMPPCMD_ALL, "stats", "Get Parsee statistics", {}) \
|
||||||
XMPP_COMMAND(CleanCallback, XMPPCMD_ADMINS, "clean", "Cleanup temporary Parsee data", {}) \
|
XMPP_COMMAND(CleanCallback, XMPPCMD_ADMINS, "clean", "Cleanup temporary Parsee data", {}) \
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue