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/**
|
||||
|
||||
# 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 *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);
|
||||
free(ofl);
|
||||
|
|
@ -516,7 +516,8 @@ main_build(int argc, char *argv[])
|
|||
ssize_t nread;
|
||||
bool with_static = false, with_lmdb = false;
|
||||
int opt;
|
||||
str_array_t *sources, *images, *utils, *aya;
|
||||
str_array_t *sources, *janet = NULL, *images, *utils, *aya;
|
||||
char *janet_dir = NULL;
|
||||
|
||||
if (repo)
|
||||
{
|
||||
|
|
@ -531,7 +532,7 @@ main_build(int argc, char *argv[])
|
|||
repo = strdup("N/A");
|
||||
}
|
||||
|
||||
while ((opt = getopt(argc, argv, "sl")) != -1)
|
||||
while ((opt = getopt(argc, argv, "slJ:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
|
|
@ -542,6 +543,9 @@ main_build(int argc, char *argv[])
|
|||
with_lmdb = with_static;
|
||||
with_static = true;
|
||||
break;
|
||||
case 'J':
|
||||
janet_dir = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -560,13 +564,22 @@ main_build(int argc, char *argv[])
|
|||
|
||||
/* Create all objects */
|
||||
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");
|
||||
fprintf(makefile, "binary:");
|
||||
write_objects(makefile, sources);
|
||||
write_images(makefile, images);
|
||||
fprintf(makefile, "\n\t");
|
||||
{
|
||||
fprintf(makefile, "$(CC) -o $(BINARY)");
|
||||
fprintf(makefile, "$(CC) -lm -o $(BINARY)");
|
||||
if (with_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");
|
||||
if (with_lmdb) fprintf(makefile, " -llmdb");
|
||||
}
|
||||
fprintf(makefile, " -lCytoplasm $(LDFLAGS)\n");
|
||||
fprintf(makefile, " -lCytoplasm -lm $(LDFLAGS)\n");
|
||||
}
|
||||
|
||||
/* Write rules for every source */
|
||||
|
|
@ -587,7 +600,7 @@ main_build(int argc, char *argv[])
|
|||
{
|
||||
char *src = str_array_get(sources, i);
|
||||
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);
|
||||
analyse_dependencies(makefile, src);
|
||||
|
|
@ -605,6 +618,10 @@ main_build(int argc, char *argv[])
|
|||
str_array_free(s);
|
||||
|
||||
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, "-DNAME=\"\\\"$(NAME)\\\"\" ");
|
||||
fprintf(makefile, "-DCODE=\"\\\"$(CODE)\\\"\" ");
|
||||
|
|
@ -675,7 +692,7 @@ main_build(int argc, char *argv[])
|
|||
fprintf(makefile, " -lCytoplasm -lmbedtls -lmbedx509 -lmbedcrypto");
|
||||
if (with_lmdb) fprintf(makefile, " -llmdb");
|
||||
}
|
||||
fprintf(makefile, " -lCytoplasm $(CFLAGS)\n");
|
||||
fprintf(makefile, " -lCytoplasm -lm $(CFLAGS)\n");
|
||||
}
|
||||
|
||||
free(ofl);
|
||||
|
|
@ -763,6 +780,7 @@ main_build(int argc, char *argv[])
|
|||
str_array_free(aya);
|
||||
fflush(makefile);
|
||||
fclose(makefile);
|
||||
free(janet_dir);
|
||||
free(repo);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ CommandHead(CmdSetPL, cmd, argp)
|
|||
char *user = HashMapGet(cmd->arguments, "user");
|
||||
char *room = HashMapGet(cmd->arguments, "room");
|
||||
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;
|
||||
|
||||
|
||||
|
|
|
|||
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 */
|
||||
HttpResponseStatus(ctx, HTTP_OK);
|
||||
HttpResponseHeader(ctx, "Server", NAME "/v" VERSION);
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
HttpResponseHeader(ctx, "X-Powered-By", "some weirdows");
|
||||
#endif
|
||||
HttpResponseHeader(ctx, "Connection", "close");
|
||||
|
||||
arg.data = data;
|
||||
|
|
|
|||
16
src/Main.c
16
src/Main.c
|
|
@ -18,6 +18,11 @@
|
|||
#include <XMPP.h>
|
||||
#include <AS.h>
|
||||
|
||||
#ifdef JANET
|
||||
#include <janet.h>
|
||||
#endif
|
||||
#include <Extension.h>
|
||||
|
||||
static HttpServer *server = NULL;
|
||||
static pthread_t xmpp_thr;
|
||||
static XMPPComponent *jabber = NULL;
|
||||
|
|
@ -99,6 +104,8 @@ Main(Array *args, HashMap *env)
|
|||
int http = 8;
|
||||
int verbose = 0;
|
||||
|
||||
Extensions *ext_ctx = NULL;
|
||||
|
||||
start = UtilTsMillis();
|
||||
|
||||
memset(&conf, 0, sizeof(conf));
|
||||
|
|
@ -110,6 +117,9 @@ Main(Array *args, HashMap *env)
|
|||
Log(LOG_INFO, "=======================");
|
||||
Log(LOG_INFO, "(C)opyright 2024 LDA and other contributors");
|
||||
Log(LOG_INFO, "(This program is free software, see LICENSE.)");
|
||||
#ifdef JANET
|
||||
Log(LOG_INFO, "**Built with Janet!**");
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_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);
|
||||
((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...");
|
||||
if (ASRegisterUser(parsee_conf, parsee_conf->sender_localpart))
|
||||
{
|
||||
|
|
@ -332,6 +346,8 @@ end:
|
|||
ParseeDestroyHeadTable();
|
||||
ParseeDestroyJIDTable();
|
||||
|
||||
ExtensionDestroyContext(ext_ctx);
|
||||
|
||||
(void) env;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ ParseeConfigLoad(char *conf)
|
|||
CopyToStr(component_host, "component_host");
|
||||
CopyToStr(shared_comp_secret, "shared_secret");
|
||||
CopyToInt(max_stanza_size, "max_stanza_size");
|
||||
|
||||
CopyToStr(extensions, "extensions");
|
||||
if (!config->max_stanza_size)
|
||||
{
|
||||
/* Standard XMPP "minimum" maximum */
|
||||
|
|
@ -140,6 +142,7 @@ ParseeConfigFree(void)
|
|||
Free(config->namespace_base);
|
||||
Free(config->media_base);
|
||||
Free(config->listen_as);
|
||||
Free(config->extensions);
|
||||
Free(config);
|
||||
}
|
||||
const ParseeConfig *
|
||||
|
|
|
|||
|
|
@ -726,3 +726,13 @@ ParseeIsMediaEnabled(ParseeData *data, char *chat_id)
|
|||
|
||||
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");
|
||||
/* TODO: Check if the element here is a Matrix.TO
|
||||
* pointing to a Parsee user. */
|
||||
Concat("(");
|
||||
for (i = 0; i < ArraySize(elem->children); i++)
|
||||
{
|
||||
child = ArrayGet(elem->children, i);
|
||||
|
|
@ -162,9 +161,9 @@ XMPPifyElement(HashMap *event, XMLElement *elem, XMPPFlags flags)
|
|||
Concat(subxep);
|
||||
Free(subxep);
|
||||
}
|
||||
Concat(" points to ");
|
||||
Concat("< ");
|
||||
Concat(href);
|
||||
Concat(" )");
|
||||
Concat(" >");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ RouteHead(RouteTxns, arr, argp)
|
|||
for (i = 0; i < ArraySize(events); i++)
|
||||
{
|
||||
HashMap *event = JsonValueAsObject(ArrayGet(events, i));
|
||||
if (ExtensionPushEvent(args->data->exts, event))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ParseeEventHandler(args->data, event);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,20 +4,10 @@
|
|||
#include <Cytoplasm/Array.h>
|
||||
#include <Cytoplasm/Str.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;
|
||||
};
|
||||
#include "XMPPCommand/Internal.h"
|
||||
|
||||
XMPPCommand *
|
||||
XMPPBasicCmd(char *node, char *name, XMPPCmdCallback callback_funct)
|
||||
XMPPBasicCmd(XMPPCommandFlags flags, char *node, char *name, XMPPCmdCallback callback_funct)
|
||||
{
|
||||
XMPPCommand *cmd;
|
||||
|
||||
|
|
@ -32,6 +22,7 @@ XMPPBasicCmd(char *node, char *name, XMPPCmdCallback callback_funct)
|
|||
cmd->name = StrDuplicate(name);
|
||||
cmd->form_instruction = NULL;
|
||||
cmd->form_title = NULL;
|
||||
cmd->flags = flags;
|
||||
|
||||
/* No options -> no form required */
|
||||
cmd->options = NULL;
|
||||
|
|
@ -127,7 +118,7 @@ XMPPFormifyCommand(XMPPCommandManager *m, XMPPCommand *cmd, char *from)
|
|||
ArrayFree(cmd->options);
|
||||
cmd->options = NULL;
|
||||
|
||||
cmd->otf(m, cmd, from);
|
||||
cmd->otf(m, cmd, from, cmd->node);
|
||||
}
|
||||
if (!cmd->options)
|
||||
{
|
||||
|
|
@ -184,13 +175,13 @@ XMPPCommandRequiresForm(XMPPCommand *cmd)
|
|||
return cmd ? (cmd->otf || !!cmd->options) : false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
cmd->callback(m, from, form, to);
|
||||
cmd->callback(m, from, form, to, node);
|
||||
}
|
||||
|
||||
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 "XMPPCommand/Internal.h"
|
||||
|
||||
typedef struct XMPPSession {
|
||||
char *identifier;
|
||||
|
||||
|
|
@ -323,7 +325,7 @@ XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeData *data)
|
|||
XMLAddAttr(command_xml, "node", node);
|
||||
XMLAddAttr(command_xml, "status", "completed");
|
||||
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);
|
||||
|
||||
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, "status", "completed");
|
||||
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);
|
||||
|
||||
XMPPSendStanza(jabber, iq, data->config->max_stanza_size);
|
||||
|
|
@ -385,3 +387,15 @@ XMPPGetManagerCookie(XMPPCommandManager *manager)
|
|||
{
|
||||
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>
|
||||
|
||||
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);
|
||||
char *trimmed = ParseeTrimJID(from);
|
||||
|
|
@ -23,6 +23,8 @@ AddAdminCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement
|
|||
|
||||
GetFieldValue(glob, "glob", form);
|
||||
|
||||
(void) node;
|
||||
|
||||
if (!ParseeIsAdmin(data, trimmed))
|
||||
{
|
||||
SetNote("error", "User is not authorised to execute command.");
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <XML.h>
|
||||
|
||||
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);
|
||||
char *trimmed = ParseeTrimJID(from);
|
||||
|
|
@ -21,6 +21,8 @@ AddNoflyCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement
|
|||
GetFieldValue(entity, "entity", form);
|
||||
GetFieldValue(reason, "reason", form);
|
||||
|
||||
(void) node;
|
||||
|
||||
if (!ParseeIsAdmin(data, trimmed))
|
||||
{
|
||||
SetNote("error", "User is not authorised to execute command.");
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <XML.h>
|
||||
|
||||
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);
|
||||
size_t i;
|
||||
|
|
@ -20,6 +20,8 @@ AdminsCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *
|
|||
XMLElement *title;
|
||||
XMLElement *reported, *item, *field, *value, *txt;
|
||||
|
||||
(void) node;
|
||||
|
||||
x = XMLCreateTag("x");
|
||||
title = XMLCreateTag("title");
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <XML.h>
|
||||
|
||||
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);
|
||||
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.");
|
||||
|
||||
(void) form;
|
||||
(void) node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ DelAdmin(Array *admin_list, char *glob)
|
|||
return removed;
|
||||
}
|
||||
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);
|
||||
char *trimmed = ParseeTrimJID(from);
|
||||
|
|
@ -84,9 +84,11 @@ DelAdminCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement
|
|||
}
|
||||
SetNote("info", "Sucessfully removed admins");
|
||||
/* TODO */
|
||||
|
||||
(void) node;
|
||||
}
|
||||
void
|
||||
FormDelAdminCallback(XMPPCommandManager *m, XMPPCommand *cmd, char *from)
|
||||
FormDelAdminCallback(XMPPCommandManager *m, XMPPCommand *cmd, char *from, char *node)
|
||||
{
|
||||
ParseeData *data = XMPPGetManagerCookie(m);
|
||||
DbRef *admins;
|
||||
|
|
@ -120,4 +122,6 @@ FormDelAdminCallback(XMPPCommandManager *m, XMPPCommand *cmd, char *from)
|
|||
|
||||
DbUnlock(data->db, admins);
|
||||
XMPPAddOption(cmd, admin_opt);
|
||||
|
||||
(void) node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <XML.h>
|
||||
|
||||
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);
|
||||
char *muc = ParseeTrimJID(from);
|
||||
|
|
@ -29,9 +29,10 @@ MUCInformationID(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement
|
|||
Free(room_id);
|
||||
Free(chat_id);
|
||||
(void) form;
|
||||
(void) node;
|
||||
}
|
||||
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);
|
||||
char *muc = ParseeTrimJID(from);
|
||||
|
|
@ -46,4 +47,5 @@ MUCInformationCID(XMPPCommandManager *m, char *from, XMLElement *form, XMLElemen
|
|||
Free(msg);
|
||||
Free(chat_id);
|
||||
(void) form;
|
||||
(void) node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
#include <AS.h>
|
||||
|
||||
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);
|
||||
char *affiliation, *role;
|
||||
|
|
@ -51,9 +51,10 @@ end:
|
|||
Free(chat_id);
|
||||
Free(muc);
|
||||
(void) form;
|
||||
(void) node;
|
||||
}
|
||||
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);
|
||||
char *affiliation = NULL, *role = NULL;
|
||||
|
|
@ -114,4 +115,5 @@ end:
|
|||
Free(chat_id);
|
||||
Free(muc);
|
||||
(void) form;
|
||||
(void) node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
#include <AS.h>
|
||||
|
||||
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);
|
||||
char *affiliation, *role;
|
||||
|
|
@ -64,4 +64,5 @@ MUCUnlink(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *out)
|
|||
Free(room);
|
||||
Free(muc);
|
||||
(void) form;
|
||||
(void) node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
#define TITLE "Parsee global bans"
|
||||
|
||||
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);
|
||||
char *trimmed = ParseeTrimJID(from);
|
||||
|
|
@ -89,4 +89,5 @@ NoflyCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *o
|
|||
}
|
||||
|
||||
(void) form;
|
||||
(void) node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <XML.h>
|
||||
|
||||
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);
|
||||
size_t alloc = MemoryAllocated();
|
||||
|
|
@ -69,5 +69,6 @@ StatusCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElement *
|
|||
XMLAddChild(out, x);
|
||||
|
||||
(void) form;
|
||||
(void) node;
|
||||
(void) m;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <XML.h>
|
||||
|
||||
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);
|
||||
char *trimmed = ParseeTrimJID(from);
|
||||
|
|
@ -35,9 +35,10 @@ ClearWhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLE
|
|||
SetNote("info", "Parsee whitelist was removed.");
|
||||
|
||||
(void) form;
|
||||
(void) node;
|
||||
}
|
||||
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);
|
||||
char *trimmed = ParseeTrimJID(from);
|
||||
|
|
@ -79,9 +80,10 @@ AddWhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLEle
|
|||
DbUnlock(data->db, ref);
|
||||
|
||||
SetNote("info", "Server successfully whitelisted.");
|
||||
(void) node;
|
||||
}
|
||||
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);
|
||||
char *trimmed = ParseeTrimJID(from);
|
||||
|
|
@ -139,4 +141,5 @@ WhitelistCallback(XMPPCommandManager *m, char *from, XMLElement *form, XMLElemen
|
|||
}
|
||||
|
||||
(void) form;
|
||||
(void) node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,15 +94,13 @@ PEPVCardEvent(PEPManager *m, XMLElement *stanza, XMLElement *item)
|
|||
AddTextField(vcard, "fn", name);
|
||||
AddTextField(vcard, "nickname", mxid);
|
||||
|
||||
AddURIField(vcard, "url", REPOSITORY);
|
||||
AddURIField(vcard, "url", "https://kappach.at/parsee");
|
||||
AddURIField(vcard, "url", "https://matrix.org");
|
||||
AddURIField(vcard, "url", m_to);
|
||||
|
||||
AddTextField(
|
||||
vcard,
|
||||
"note",
|
||||
"This is a bridged Matrix user, from Parsee."
|
||||
"This is a bridged Matrix user, from " NAME "."
|
||||
);
|
||||
Free(mxid);
|
||||
Free(name);
|
||||
|
|
|
|||
|
|
@ -65,6 +65,16 @@ XMPPDispatcher(void *argp)
|
|||
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"))
|
||||
{
|
||||
PresenceStanza(args, stanza, thread);
|
||||
|
|
@ -130,6 +140,7 @@ bool
|
|||
XMPPCommandFilter(XMPPCommandManager *m, char *id, XMLElement *stanza)
|
||||
{
|
||||
ParseeData *args = XMPPGetManagerCookie(m);
|
||||
XMPPCommandFlags flags;
|
||||
char *trimmed_from;
|
||||
char *from;
|
||||
char *chat_id;
|
||||
|
|
@ -144,28 +155,24 @@ XMPPCommandFilter(XMPPCommandManager *m, char *id, XMLElement *stanza)
|
|||
is_muc = !!(chat_id = ParseeGetFromMUCID(args, trimmed_from));
|
||||
Free(trimmed_from);
|
||||
Free(chat_id);
|
||||
#define XMPP_COMMAND(f,l,n,t,s) \
|
||||
if (StrEquals(n, id)) \
|
||||
{ \
|
||||
if (l == XMPPCMD_ALL) \
|
||||
{ \
|
||||
return true; \
|
||||
} \
|
||||
else if (l == XMPPCMD_MUC) \
|
||||
{ \
|
||||
return is_muc; \
|
||||
} \
|
||||
else if (l == XMPPCMD_ADMINS) \
|
||||
{ \
|
||||
bool is_admin; \
|
||||
trimmed_from = ParseeTrimJID(from); \
|
||||
is_admin = ParseeIsAdmin(args, trimmed_from); \
|
||||
Free(trimmed_from); \
|
||||
return is_admin; \
|
||||
} \
|
||||
flags = XMPPGetCommandFlags(m, id);
|
||||
|
||||
if (flags == XMPPCMD_ALL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (flags == XMPPCMD_MUC)
|
||||
{
|
||||
return is_muc;
|
||||
}
|
||||
else if (flags == XMPPCMD_ADMINS)
|
||||
{
|
||||
bool is_admin;
|
||||
trimmed_from = ParseeTrimJID(from);
|
||||
is_admin = ParseeIsAdmin(args, trimmed_from);
|
||||
Free(trimmed_from);
|
||||
return is_admin;
|
||||
}
|
||||
XMPPCOMMANDS
|
||||
#undef XMPP_COMMAND
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -191,13 +198,14 @@ ParseeXMPPThread(void *argp)
|
|||
XMPPCommand *cmd;
|
||||
#define XMPP_COMMAND(f,l,n,t,s) \
|
||||
cmd = XMPPBasicCmd( \
|
||||
n, t, f \
|
||||
l, n, t, f \
|
||||
); \
|
||||
s \
|
||||
XMPPRegisterCommand(info.m, cmd);
|
||||
XMPPCOMMANDS
|
||||
#undef XMPP_COMMAND
|
||||
}
|
||||
ExtensionRequestCommands(args->exts);
|
||||
info.pep_manager = CreatePEPManager(args, &info);
|
||||
{
|
||||
PEPManagerAddEvent(
|
||||
|
|
|
|||
|
|
@ -421,10 +421,16 @@ IQGet(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
|||
char *parsee_muc_jid = StrConcat(3, trimmed, "/", "parsee");
|
||||
XMLAddAttr(q, "xmlns", "http://jabber.org/protocol/disco#items");
|
||||
XMLAddAttr(q, "node", "http://jabber.org/protocol/commands");
|
||||
|
||||
XMPPShoveCommandList(thr->info->m,
|
||||
IsInMUC(args, from) ? parsee_muc_jid : to,
|
||||
q, stanza
|
||||
);
|
||||
ExtensionShoveCommands(
|
||||
args->exts,
|
||||
IsInMUC(args, from) ? parsee_muc_jid : to,
|
||||
q, stanza
|
||||
);
|
||||
XMLAddChild(iq_reply, q);
|
||||
Free(parsee_muc_jid);
|
||||
}
|
||||
|
|
@ -611,6 +617,7 @@ IQSet(ParseeData *args, XMLElement *stanza, XMPPThread *thr)
|
|||
{
|
||||
XMPPCommandManager *manager = thr->info->m;
|
||||
XMPPManageCommand(manager, stanza, args);
|
||||
ExtensionManageCommands(args->exts, stanza);
|
||||
}
|
||||
#undef DISCO
|
||||
|
||||
|
|
|
|||
|
|
@ -411,7 +411,17 @@ end_error:
|
|||
|
||||
/* Check if it is a media link */
|
||||
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;
|
||||
HashMap *content = NULL;
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ int IdentitySort(void *idap, void *idbp);
|
|||
char * ParseeGetBridgedRoom(ParseeData *data, XMLElement *stanza);
|
||||
char * ParseeGetEventFromID(ParseeData *data, XMLElement *stanza, char *id);
|
||||
char * ParseeGetReactedEvent(ParseeData *data, XMLElement *stanza);
|
||||
void ParseePushAllStanza(ParseeData *args, XMLElement *stanza, char *event);
|
||||
bool ParseeVerifyAllStanza(ParseeData *args, 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);
|
||||
|
||||
char * ParseeGetBridgedUserI(ParseeData *data, XMLElement *stanza, char *force);
|
||||
#define ParseeGetBridgedUser(data, stanza) ParseeGetBridgedUserI(data, stanza, NULL)
|
||||
|
||||
PEPManager * CreatePEPManager(ParseeData *data, void *cookie);
|
||||
void * PEPManagerCookie(PEPManager *manager);
|
||||
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 <Extension.h>
|
||||
#include <Command.h>
|
||||
#include <XMPP.h>
|
||||
|
||||
|
|
@ -50,6 +51,7 @@ typedef struct ParseeConfig {
|
|||
/* ------- DB -------- */
|
||||
char *db_path;
|
||||
size_t db_size;
|
||||
char *extensions;
|
||||
|
||||
/* - COMMAND-LINE FLAGS - */
|
||||
int xmpp_threads, http_threads;
|
||||
|
|
@ -72,8 +74,10 @@ typedef struct ParseeData {
|
|||
pthread_mutex_t oidl;
|
||||
|
||||
/* If Parsee was intentionally halted */
|
||||
bool halted;
|
||||
volatile bool halted;
|
||||
pthread_mutex_t halt_lock;
|
||||
|
||||
Extensions *exts;
|
||||
} ParseeData;
|
||||
|
||||
typedef struct Argument {
|
||||
|
|
@ -93,6 +97,8 @@ typedef struct Argument {
|
|||
#define GrabObject(obj, ...) JsonValueAsObject(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
|
||||
* in timestamps */
|
||||
#define SECONDS * 1000
|
||||
|
|
@ -121,6 +127,7 @@ extern const char *parsee_ascii[PARSEE_ASCII_LINES];
|
|||
* Modifies: the logger output */
|
||||
extern void ParseePrintASCII(void);
|
||||
|
||||
|
||||
/**
|
||||
* Checks if two versions of Parsee can be considered "compatible".
|
||||
* 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 */
|
||||
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),
|
||||
* 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.
|
||||
|
|
@ -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 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 */
|
||||
extern bool ParseeVerifyStanza(ParseeData *, char *chat_id, char *stanza_id);
|
||||
|
||||
|
|
@ -488,4 +509,8 @@ extern void ParseeUnlinkRoom(ParseeData *data, char *chat_id);
|
|||
* Modifies: NOTHING */
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
typedef struct XMPPCommandManager XMPPCommandManager;
|
||||
#ifndef PARSEE_XMPPCOMMAND_H
|
||||
#define PARSEE_XMPPCOMMAND_H
|
||||
|
||||
|
|
@ -7,11 +8,16 @@
|
|||
#include <Parsee.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 XMPPOption XMPPOption;
|
||||
typedef void (*XMPPCmdCallback)(XMPPCommandManager *, char *, XMLElement *, XMLElement *);
|
||||
typedef void (*XMPPOptionWriter)(XMPPCommandManager *, XMPPCommand *, char *);
|
||||
typedef void (*XMPPCmdCallback)(XMPPCommandManager *, char *, XMLElement *, XMLElement *, char *);
|
||||
typedef void (*XMPPOptionWriter)(XMPPCommandManager *, XMPPCommand *, char *, char *);
|
||||
typedef bool (*XMPPCmdFilter)(XMPPCommandManager *, char *id, XMLElement *stanza);
|
||||
|
||||
/** Creates a simple XMPP command manager, which routes commands
|
||||
|
|
@ -39,7 +45,7 @@ XMPPManagerSetFilter(XMPPCommandManager *manager, XMPPCmdFilter filter);
|
|||
* Modifies: NOTHING
|
||||
* See-Also: XMPPRegisterCommand */
|
||||
extern XMPPCommand *
|
||||
XMPPBasicCmd(char *node, char *name, XMPPCmdCallback cb);
|
||||
XMPPBasicCmd(XMPPCommandFlags flags, char *node, char *name, XMPPCmdCallback cb);
|
||||
extern void
|
||||
XMPPCmdOptionsCreator(XMPPCommand *cmd, XMPPOptionWriter writer);
|
||||
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 XMPPSetFormTitle(XMPPCommand *cmd, char *title);
|
||||
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.
|
||||
* -----------------------------------------------------
|
||||
|
|
@ -91,6 +97,12 @@ extern void XMPPRegisterCommand(XMPPCommandManager *m, XMPPCommand *cmd);
|
|||
* See-Also: XMPPCreateManager */
|
||||
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}.
|
||||
* -----------------------------------------------------
|
||||
* Returns: NOTHING
|
||||
|
|
@ -111,11 +123,11 @@ extern bool XMPPManageCommand(XMPPCommandManager *m, XMLElement *stanza, ParseeD
|
|||
|
||||
#define XMPP_COMMAND(f,l,n,t,s) \
|
||||
extern void \
|
||||
f(XMPPCommandManager *, char *, XMLElement *, XMLElement *); \
|
||||
f(XMPPCommandManager *, char *, XMLElement *, XMLElement *, char *); \
|
||||
/* This symbol might not exist. We do, however, not care, as
|
||||
* it is not always done. */ \
|
||||
extern void \
|
||||
Form##f(XMPPCommandManager *, XMPPCommand *, char *); \
|
||||
Form##f(XMPPCommandManager *, XMPPCommand *, char *, char *); \
|
||||
|
||||
#include "XMPPCommands.x.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,4 @@
|
|||
/* C X-macro file */
|
||||
typedef enum XMPPCommandFlags {
|
||||
XMPPCMD_ALL = 0,
|
||||
XMPPCMD_MUC , /* Only for MUCs */
|
||||
XMPPCMD_ADMINS /* Only for administrators */
|
||||
} XMPPCommandFlags;
|
||||
#define XMPPCOMMANDS \
|
||||
XMPP_COMMAND(StatusCallback, XMPPCMD_ALL, "stats", "Get Parsee statistics", {}) \
|
||||
XMPP_COMMAND(CleanCallback, XMPPCMD_ADMINS, "clean", "Cleanup temporary Parsee data", {}) \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue