summaryrefslogtreecommitdiffstats
path: root/src/lib-storage/mailbox-lua.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib-storage/mailbox-lua.c366
1 files changed, 366 insertions, 0 deletions
diff --git a/src/lib-storage/mailbox-lua.c b/src/lib-storage/mailbox-lua.c
new file mode 100644
index 0000000..19327ba
--- /dev/null
+++ b/src/lib-storage/mailbox-lua.c
@@ -0,0 +1,366 @@
+/* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "str.h"
+#include "istream.h"
+#include "array.h"
+#include "var-expand.h"
+#include "mail-storage.h"
+#include "mailbox-attribute.h"
+#include "mail-storage-lua.h"
+#include "mail-storage-lua-private.h"
+#include "mail-user.h"
+
+#define LUA_STORAGE_MAILBOX "struct mailbox"
+
+static int lua_storage_mailbox_gc(lua_State *L);
+
+void dlua_push_mailbox(lua_State *L, struct mailbox *box)
+{
+ luaL_checkstack(L, 4, "out of memory");
+ /* create a table for holding few things */
+ lua_createtable(L, 0, 0);
+ luaL_setmetatable(L, LUA_STORAGE_MAILBOX);
+
+ struct mailbox **ptr = lua_newuserdata(L, sizeof(struct mailbox*));
+ *ptr = box;
+ lua_createtable(L, 0, 1);
+ lua_pushcfunction(L, lua_storage_mailbox_gc);
+ lua_setfield(L, -2, "__gc");
+ lua_setmetatable(L, -2);
+ lua_setfield(L, -2, "item");
+
+ luaL_checkstack(L, 2, "out of memory");
+ lua_pushstring(L, mailbox_get_vname(box));
+ lua_setfield(L, -2, "vname");
+
+ lua_pushstring(L, mailbox_get_name(box));
+ lua_setfield(L, -2, "name");
+}
+
+static struct mailbox *
+lua_check_storage_mailbox(lua_State *L, int arg)
+{
+ if (!lua_istable(L, arg)) {
+ (void)luaL_error(L, "Bad argument #%d, expected %s got %s",
+ arg, LUA_STORAGE_MAILBOX,
+ lua_typename(L, lua_type(L, arg)));
+ }
+ lua_pushliteral(L, "item");
+ lua_rawget(L, arg);
+ struct mailbox **bp = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+ return *bp;
+}
+
+static int lua_storage_mailbox_tostring(lua_State *L)
+{
+ DLUA_REQUIRE_ARGS(L, 1);
+ struct mailbox *mbox = lua_check_storage_mailbox(L, 1);
+
+ lua_pushstring(L, mailbox_get_vname(mbox));
+ return 1;
+}
+
+/* special case, we want to ensure this is eq when mailboxes
+ are really equal */
+static int lua_storage_mailbox_eq(lua_State *L)
+{
+ DLUA_REQUIRE_ARGS(L, 2);
+ struct mailbox *mbox = lua_check_storage_mailbox(L, 1);
+ struct mailbox *mbox2 = lua_check_storage_mailbox(L, 2);
+ lua_pushboolean(L, DLUA_MAILBOX_EQUALS(mbox, mbox2));
+ return 1;
+}
+
+/* these compare based to mailbox vname */
+static int lua_storage_mailbox_lt(lua_State *L)
+{
+ DLUA_REQUIRE_ARGS(L, 2);
+ bool res = lua_storage_cmp(L) <= 0;
+ lua_pushboolean(L, res);
+ return 1;
+}
+
+static int lua_storage_mailbox_le(lua_State *L)
+{
+ DLUA_REQUIRE_ARGS(L, 2);
+ bool res = lua_storage_cmp(L) < 0;
+ lua_pushboolean(L, res);
+ return 1;
+}
+
+static int lua_storage_mailbox_unref(lua_State *L)
+{
+ DLUA_REQUIRE_ARGS(L, 1);
+ /* fetch item from table */
+ lua_pushliteral(L, "item");
+ lua_rawget(L, 1);
+ struct mailbox **mbox = lua_touserdata(L, -1);
+ if (*mbox != NULL)
+ mailbox_free(mbox);
+ *mbox = NULL;
+ lua_pop(L, 1);
+ return 0;
+}
+
+static int lua_storage_mailbox_gc(lua_State *L)
+{
+ struct mailbox **mbox = lua_touserdata(L, 1);
+
+ if (*mbox != NULL)
+ mailbox_free(mbox);
+
+ return 0;
+}
+
+static int lua_storage_mailbox_open(lua_State *L)
+{
+ DLUA_REQUIRE_ARGS(L, 1);
+ struct mailbox *mbox = lua_check_storage_mailbox(L, 1);
+
+ /* try to open the box */
+ if (mailbox_open(mbox) < 0) {
+ return luaL_error(L, "mailbox_open(%s) failed: %s",
+ mailbox_get_vname(mbox),
+ mailbox_get_last_error(mbox, NULL));
+ }
+
+ return 0;
+}
+
+static int lua_storage_mailbox_close(lua_State *L)
+{
+ DLUA_REQUIRE_ARGS(L, 1);
+ struct mailbox *mbox = lua_check_storage_mailbox(L, 1);
+
+ mailbox_close(mbox);
+
+ return 0;
+}
+
+static int lua_storage_mailbox_sync(lua_State *L)
+{
+ DLUA_REQUIRE_ARGS_IN(L, 1, 2);
+ struct mailbox *mbox = lua_check_storage_mailbox(L, 1);
+ enum mailbox_sync_flags flags = 0;
+
+ if (lua_gettop(L) >= 2)
+ flags = luaL_checkinteger(L, 2);
+
+ if (mailbox_sync(mbox, flags) < 0) {
+ const char *error = mailbox_get_last_error(mbox, NULL);
+ return luaL_error(L, "mailbox_sync(%s) failed: %s",
+ mailbox_get_vname(mbox), error);
+ }
+
+ return 0;
+}
+
+static int lua_storage_mailbox_status(lua_State *L)
+{
+ struct mailbox_status status;
+ const char *keyword;
+ struct mailbox *mbox = lua_check_storage_mailbox(L, 1);
+ /* get items as list of parameters */
+ enum mailbox_status_items items = 0;
+
+ if (lua_gettop(L) < 2)
+ return luaL_error(L, "expecting at least 1 parameter");
+ for(int i = 2; i <= lua_gettop(L); i++)
+ items |= (unsigned int)luaL_checkinteger(L, i);
+
+ i_zero(&status);
+ if (mailbox_get_status(mbox, items, &status) < 0) {
+ const char *error = mailbox_get_last_error(mbox, NULL);
+ return luaL_error(L, "mailbox_get_status(%s, %u) failed: %s",
+ mailbox_get_vname(mbox), items, error);
+ }
+ /* returns a table */
+ lua_createtable(L, 0, 20);
+
+ lua_pushstring(L, mailbox_get_vname(mbox));
+ lua_setfield(L, -2, "mailbox");
+
+#undef LUA_TABLE_SET_NUMBER
+#define LUA_TABLE_SET_NUMBER(field) \
+ lua_pushnumber(L, status.field); \
+ lua_setfield(L, -2, #field);
+#undef LUA_TABLE_SET_BOOL
+#define LUA_TABLE_SET_BOOL(field) \
+ lua_pushboolean(L, status.field); \
+ lua_setfield(L, -2, #field);
+
+ LUA_TABLE_SET_NUMBER(messages);
+ LUA_TABLE_SET_NUMBER(recent);
+ LUA_TABLE_SET_NUMBER(unseen);
+ LUA_TABLE_SET_NUMBER(uidvalidity);
+ LUA_TABLE_SET_NUMBER(uidnext);
+ LUA_TABLE_SET_NUMBER(first_unseen_seq);
+ LUA_TABLE_SET_NUMBER(first_recent_uid);
+ LUA_TABLE_SET_NUMBER(highest_modseq);
+ LUA_TABLE_SET_NUMBER(highest_pvt_modseq);
+
+ LUA_TABLE_SET_NUMBER(permanent_flags);
+ LUA_TABLE_SET_NUMBER(flags);
+
+ LUA_TABLE_SET_BOOL(permanent_keywords);
+ LUA_TABLE_SET_BOOL(allow_new_keywords);
+ LUA_TABLE_SET_BOOL(nonpermanent_modseqs);
+ LUA_TABLE_SET_BOOL(no_modseq_tracking);
+ LUA_TABLE_SET_BOOL(have_guids);
+ LUA_TABLE_SET_BOOL(have_save_guids);
+ LUA_TABLE_SET_BOOL(have_only_guid128);
+
+ if (status.keywords != NULL && array_is_created(status.keywords)) {
+ int i = 1;
+ lua_createtable(L, array_count(status.keywords), 0);
+ array_foreach_elem(status.keywords, keyword) {
+ lua_pushstring(L, keyword);
+ lua_rawseti(L, -2, i++);
+ }
+ lua_setfield(L, -2, "keywords");
+ }
+
+ return 1;
+}
+
+static int lua_storage_mailbox_metadata_get(lua_State *L)
+{
+ if (lua_gettop(L) < 2)
+ return luaL_error(L, "expecting at least 1 parameter");
+ struct mailbox *mbox = lua_check_storage_mailbox(L, 1);
+ const char *value, *error;
+ size_t value_len;
+ int ret, i, top = lua_gettop(L);
+
+ ret = 0;
+ for(i = 2; i <= top; i++) {
+ const char *key = lua_tostring(L, i);
+ if (key == NULL) {
+ ret = -1;
+ error = t_strdup_printf("expected string at #%d", i);
+ break;
+ }
+
+ if ((ret = lua_storage_mailbox_attribute_get(mbox, key, &value,
+ &value_len, &error)) < 0) {
+ break;
+ } else if (ret == 0) {
+ lua_pushnil(L);
+ } else {
+ lua_pushlstring(L, value, value_len);
+ }
+ }
+
+ if (ret < 0)
+ return luaL_error(L, "%s", error);
+
+ /* return number of pushed items */
+ i_assert(i>=2);
+ return i-2;
+}
+
+static int lua_storage_mailbox_metadata_set(lua_State *L)
+{
+ DLUA_REQUIRE_ARGS(L, 3);
+ struct mailbox *mbox = lua_check_storage_mailbox(L, 1);
+ const char *key = luaL_checkstring(L, 2);
+ const char *value, *error;
+ size_t value_len;
+
+ value = lua_tolstring(L, 3, &value_len);
+
+ if (lua_storage_mailbox_attribute_set(mbox, key, value, value_len, &error) < 0)
+ return luaL_error(L, "Cannot set attribute: %s", error);
+
+ return 0;
+}
+
+static int lua_storage_mailbox_metadata_unset(lua_State *L)
+{
+ DLUA_REQUIRE_ARGS(L, 2);
+ struct mailbox *mbox = lua_check_storage_mailbox(L, 1);
+ const char *key = luaL_checkstring(L, 2);
+ const char *error;
+
+ if (lua_storage_mailbox_attribute_set(mbox, key, NULL, 0, &error) < 0)
+ return luaL_error(L, "Cannot unset attribute: %s", error);
+
+ return 0;
+}
+
+static int lua_storage_mailbox_metadata_list(lua_State *L)
+{
+ if (lua_gettop(L) < 2)
+ return luaL_error(L, "expecting at least 1 parameter");
+ struct mailbox *mbox = lua_check_storage_mailbox(L, 1);
+ const struct lua_storage_keyvalue *item;
+ const char *error;
+ ARRAY_TYPE(lua_storage_keyvalue) items;
+ int i, ret;
+
+ T_BEGIN {
+ t_array_init(&items, 1);
+
+ ret = 0;
+ for(i = 2; i <= lua_gettop(L); i++) {
+ const char *key = lua_tostring(L, i);
+
+ if (key == NULL) {
+ ret = -1;
+ error = t_strdup_printf("expected string at #%d", i);
+ break;
+ }
+
+ if (lua_storage_mailbox_attribute_list(mbox, key, &items,
+ &error) < 0) {
+ ret = -1;
+ break;
+ }
+ }
+
+ if (ret == 0) {
+ lua_createtable(L, 0, array_count(&items));
+ array_foreach(&items, item) {
+ /* push value */
+ lua_pushlstring(L, item->value,
+ item->value_len);
+ /* set field */
+ lua_setfield(L, -2, item->key);
+ }
+ }
+ } T_END;
+
+ if (ret == -1)
+ return luaL_error(L, "%s", error);
+
+ /* stack should have table with items */
+ return 1;
+}
+
+static luaL_Reg lua_storage_mailbox_methods[] = {
+ { "__tostring", lua_storage_mailbox_tostring },
+ { "__eq", lua_storage_mailbox_eq },
+ { "__lt", lua_storage_mailbox_lt },
+ { "__le", lua_storage_mailbox_le },
+ { "free", lua_storage_mailbox_unref },
+ { "status", lua_storage_mailbox_status },
+ { "open", lua_storage_mailbox_open },
+ { "close", lua_storage_mailbox_close },
+ { "sync", lua_storage_mailbox_sync },
+ { "metadata_get", lua_storage_mailbox_metadata_get },
+ { "metadata_set", lua_storage_mailbox_metadata_set },
+ { "metadata_unset", lua_storage_mailbox_metadata_unset },
+ { "metadata_list", lua_storage_mailbox_metadata_list },
+ { NULL, NULL }
+};
+
+void lua_storage_mailbox_register(struct dlua_script *script)
+{
+ luaL_newmetatable(script->L, LUA_STORAGE_MAILBOX);
+ lua_pushvalue(script->L, -1);
+ lua_setfield(script->L, -2, "__index");
+ luaL_setfuncs(script->L, lua_storage_mailbox_methods, 0);
+ lua_pop(script->L, 1);
+}