summaryrefslogtreecommitdiffstats
path: root/src/lib-dict/dict-lua.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib-dict/dict-lua.c')
-rw-r--r--src/lib-dict/dict-lua.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/lib-dict/dict-lua.c b/src/lib-dict/dict-lua.c
new file mode 100644
index 0000000..d5de534
--- /dev/null
+++ b/src/lib-dict/dict-lua.c
@@ -0,0 +1,117 @@
+/* Copyright (c) 2021 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "dict.h"
+#include "dlua-script-private.h"
+#include "dict-lua-private.h"
+#include "dlua-wrapper.h"
+
+static int lua_dict_lookup(lua_State *);
+
+static luaL_Reg lua_dict_methods[] = {
+ { "lookup", lua_dict_lookup },
+ { "iterate", lua_dict_iterate },
+ { "transaction_begin", lua_dict_transaction_begin },
+ { NULL, NULL },
+};
+
+/* no actual ref counting */
+static void lua_dict_unref(struct dict *dict ATTR_UNUSED)
+{
+}
+
+DLUA_WRAP_C_DATA(dict, struct dict, lua_dict_unref, lua_dict_methods);
+
+static int lua_dict_async_continue(lua_State *L,
+ int status ATTR_UNUSED,
+ lua_KContext ctx ATTR_UNUSED)
+{
+ /*
+ * lua_dict_*_callback() already pushed the result table/nil or error
+ * string. We simply need to return/error out.
+ */
+
+ if (lua_istable(L, -1) || lua_isnil(L, -1))
+ return 1;
+ else
+ return lua_error(L);
+}
+
+static void lua_dict_lookup_callback(const struct dict_lookup_result *result,
+ lua_State *L)
+{
+ if (result->ret < 0) {
+ lua_pushstring(L, result->error);
+ } else if (result->ret == 0) {
+ lua_pushnil(L);
+ } else {
+ unsigned int i;
+
+ lua_newtable(L);
+
+ for (i = 0; i < str_array_length(result->values); i++) {
+ lua_pushstring(L, result->values[i]);
+ lua_seti(L, -2, i + 1);
+ }
+ }
+
+ dlua_pcall_yieldable_resume(L, 1);
+}
+
+void lua_dict_check_key_prefix(lua_State *L, const char *key,
+ const char *username)
+{
+ if (str_begins(key, DICT_PATH_SHARED))
+ ;
+ else if (str_begins(key, DICT_PATH_PRIVATE)) {
+ if (username == NULL || username[0] == '\0')
+ luaL_error(L, DICT_PATH_PRIVATE" dict key prefix requires username");
+ } else {
+ luaL_error(L, "Invalid dict key prefix");
+ }
+}
+
+/*
+ * Lookup a key in dict [-(2|3),+1,e]
+ *
+ * Args:
+ * 1) userdata: struct dict *dict
+ * 2) string: key
+ * 3*) string: username
+ *
+ * Returns:
+ * If key is found, returns a table with values. If key is not found,
+ * returns nil.
+ * Username will be NULL if not provided in args.
+ */
+static int lua_dict_lookup(lua_State *L)
+{
+ struct dict *dict;
+ const char *key, *username = NULL;
+
+ DLUA_REQUIRE_ARGS_IN(L, 2, 3);
+
+ dict = xlua_dict_getptr(L, 1, NULL);
+ key = luaL_checkstring(L, 2);
+ if (lua_gettop(L) >= 3)
+ username = luaL_checkstring(L, 3);
+ lua_dict_check_key_prefix(L, key, username);
+
+ struct dict_op_settings set = {
+ .username = username,
+ };
+ dict_lookup_async(dict, &set, key, lua_dict_lookup_callback, L);
+
+ return lua_dict_async_continue(L,
+ lua_yieldk(L, 0, 0, lua_dict_async_continue), 0);
+}
+
+void dlua_push_dict(lua_State *L, struct dict *dict)
+{
+ xlua_pushdict(L, dict, FALSE);
+}
+
+struct dict *dlua_check_dict(lua_State *L, int idx)
+{
+ return xlua_dict_getptr(L, idx, NULL);
+}