diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib-dict/dict-lua.c | 117 |
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); +} |