1 /* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "str.h"
5 #include "istream.h"
6 #include "array.h"
7 #include "var-expand.h"
8 #include "dlua-script.h"
9 #include "dlua-script-private.h"
10 #include "mail-storage.h"
11 #include "mailbox-attribute.h"
12 #include "mail-storage-lua.h"
13 #include "mail-storage-lua-private.h"
14 #include "mail-user.h"
15 
16 #define LUA_STORAGE_MAIL "struct mail"
17 
dlua_push_mail(lua_State * L,struct mail * mail)18 void dlua_push_mail(lua_State *L, struct mail *mail)
19 {
20 	luaL_checkstack(L, 20, "out of memory");
21 	/* create a table for holding few things */
22 	lua_createtable(L, 0, 20);
23 	luaL_setmetatable(L, LUA_STORAGE_MAIL);
24 
25 	lua_pushlightuserdata(L, mail);
26 	lua_setfield(L, -2, "item");
27 
28 #undef LUA_TABLE_SET_NUMBER
29 #define LUA_TABLE_SET_NUMBER(field) \
30 	lua_pushnumber(L, mail->field); \
31 	lua_setfield(L, -2, #field);
32 #undef LUA_TABLE_SET_BOOL
33 #define LUA_TABLE_SET_BOOL(field) \
34 	lua_pushboolean(L, mail->field); \
35 	lua_setfield(L, -2, #field);
36 
37 	LUA_TABLE_SET_NUMBER(seq);
38 	LUA_TABLE_SET_NUMBER(uid);
39 	LUA_TABLE_SET_BOOL(expunged);
40 
41 	dlua_push_mailbox(L, mail->box);
42 	lua_setfield(L, -2, "mailbox");
43 
44 }
45 
46 static struct mail *
lua_check_storage_mail(lua_State * L,int arg)47 lua_check_storage_mail(lua_State *L, int arg)
48 {
49 	if (!lua_istable(L, arg)) {
50 		(void)luaL_error(L, "Bad argument #%d, expected %s got %s",
51 				 arg, LUA_STORAGE_MAIL,
52 				 lua_typename(L, lua_type(L, arg)));
53 	}
54 	lua_pushliteral(L, "item");
55 	lua_rawget(L, arg);
56 	void *bp = (void*)lua_touserdata(L, -1);
57 	lua_pop(L, 1);
58 	return (struct mail*)bp;
59 }
60 
lua_storage_mail_tostring(lua_State * L)61 static int lua_storage_mail_tostring(lua_State *L)
62 {
63 	DLUA_REQUIRE_ARGS(L, 1);
64 	struct mail *mail = lua_check_storage_mail(L, 1);
65 
66 	const char *str =
67 		t_strdup_printf("<%s:UID %u>", mailbox_get_vname(mail->box),
68 				mail->uid);
69 	lua_pushstring(L, str);
70 	return 1;
71 }
72 
lua_storage_mail_eq(lua_State * L)73 static int lua_storage_mail_eq(lua_State *L)
74 {
75 	DLUA_REQUIRE_ARGS(L, 2);
76 	struct mail *mail = lua_check_storage_mail(L, 1);
77 	struct mail *mail2 = lua_check_storage_mail(L, 2);
78 
79 	if (!DLUA_MAILBOX_EQUALS(mail->box, mail2->box))
80 		lua_pushboolean(L, FALSE);
81 	else
82 		lua_pushboolean(L, mail->uid != mail2->uid);
83 	return 1;
84 }
85 
lua_storage_mail_lt(lua_State * L)86 static int lua_storage_mail_lt(lua_State *L)
87 {
88 	DLUA_REQUIRE_ARGS(L, 2);
89 	struct mail *mail = lua_check_storage_mail(L, 1);
90 	struct mail *mail2 = lua_check_storage_mail(L, 2);
91 
92 	if (!DLUA_MAILBOX_EQUALS(mail->box, mail2->box))
93 		return luaL_error(L,
94 				  "For lt, Mail can only be compared within same mailbox");
95 	else
96 		lua_pushboolean(L, mail->uid < mail2->uid);
97 	return 1;
98 }
99 
lua_storage_mail_le(lua_State * L)100 static int lua_storage_mail_le(lua_State *L)
101 {
102 	DLUA_REQUIRE_ARGS(L, 2);
103 	struct mail *mail = lua_check_storage_mail(L, 1);
104 	struct mail *mail2 = lua_check_storage_mail(L, 2);
105 
106 	if (!DLUA_MAILBOX_EQUALS(mail->box, mail2->box))
107 		return luaL_error(L,
108 				 "For le, mails can only be within same mailbox");
109 	else
110 		lua_pushboolean(L, mail->uid <= mail2->uid);
111 
112 	return 1;
113 }
114 
lua_storage_mail_gc(lua_State * L)115 static int lua_storage_mail_gc(lua_State *L)
116 {
117 	(void)lua_check_storage_mail(L, 1);
118 
119 	/* reset value to NULL */
120 	lua_pushliteral(L, "item");
121 	lua_pushnil(L);
122 	lua_rawset(L, 1);
123 
124 	return 0;
125 }
126 
127 static luaL_Reg lua_storage_mail_methods[] = {
128 	{ "__tostring", lua_storage_mail_tostring },
129 	{ "__eq", lua_storage_mail_eq },
130 	{ "__lt", lua_storage_mail_lt },
131 	{ "__le", lua_storage_mail_le },
132 	{ "__gc", lua_storage_mail_gc },
133 	{ NULL, NULL }
134 };
135 
lua_storage_mail_register(struct dlua_script * script)136 void lua_storage_mail_register(struct dlua_script *script)
137 {
138 	luaL_newmetatable(script->L, LUA_STORAGE_MAIL);
139 	lua_pushvalue(script->L, -1);
140 	lua_setfield(script->L, -2, "__index");
141 	luaL_setfuncs(script->L, lua_storage_mail_methods, 0);
142 	lua_pop(script->L, 1);
143 }
144