aboutsummaryrefslogtreecommitdiffstats
path: root/src/lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/lua')
-rw-r--r--src/lua/lua_cdb.c14
-rw-r--r--src/lua/lua_cfg_file.c42
-rw-r--r--src/lua/lua_common.c126
-rw-r--r--src/lua/lua_common.h34
-rw-r--r--src/lua/lua_config.c7
-rw-r--r--src/lua/lua_cryptobox.c50
-rw-r--r--src/lua/lua_dns_resolver.c27
-rw-r--r--src/lua/lua_expression.c14
-rw-r--r--src/lua/lua_http.c3
-rw-r--r--src/lua/lua_ip.c27
-rw-r--r--src/lua/lua_logger.c53
-rw-r--r--src/lua/lua_mempool.c14
-rw-r--r--src/lua/lua_mimepart.c34
-rw-r--r--src/lua/lua_redis.c18
-rw-r--r--src/lua/lua_regexp.c69
-rw-r--r--src/lua/lua_rsa.c36
-rw-r--r--src/lua/lua_sqlite3.c22
-rw-r--r--src/lua/lua_task.c117
-rw-r--r--src/lua/lua_tcp.c6
-rw-r--r--src/lua/lua_text.c143
-rw-r--r--src/lua/lua_trie.c135
-rw-r--r--src/lua/lua_udp.c3
-rw-r--r--src/lua/lua_upstream.c28
-rw-r--r--src/lua/lua_url.c9
-rw-r--r--src/lua/lua_util.c116
-rw-r--r--src/lua/lua_worker.c208
26 files changed, 966 insertions, 389 deletions
diff --git a/src/lua/lua_cdb.c b/src/lua/lua_cdb.c
index 5d4c499a7..1f9b48260 100644
--- a/src/lua/lua_cdb.c
+++ b/src/lua/lua_cdb.c
@@ -151,17 +151,7 @@ lua_load_cdb (lua_State *L)
void
luaopen_cdb (lua_State * L)
{
- luaL_newmetatable (L, "rspamd{cdb}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{cdb}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, cdblib_m);
- lua_pop (L, 1); /* remove metatable from stack */
-
+ rspamd_lua_new_class (L, "rspamd{cdb}", cdblib_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_cdb", lua_load_cdb);
}
diff --git a/src/lua/lua_cfg_file.c b/src/lua/lua_cfg_file.c
index 26e9811bd..23001f8f1 100644
--- a/src/lua/lua_cfg_file.c
+++ b/src/lua/lua_cfg_file.c
@@ -97,28 +97,50 @@ rspamd_lua_post_load_config (struct rspamd_config *cfg)
lua_State *L = cfg->lua_state;
const gchar *name;
ucl_object_t *obj;
- gsize keylen;
+ gsize keylen, i;
/* First check all module options that may be overridden in 'config' global */
lua_getglobal (L, "config");
if (lua_istable (L, -1)) {
- /* Iterate */
- for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
- /* 'key' is at index -2 and 'value' is at index -1 */
- /* Key must be a string and value must be a table */
- name = luaL_checklstring (L, -2, &keylen);
+ /* Iterate to get all keys */
+ GPtrArray *names = g_ptr_array_new_full (rspamd_lua_table_size (L, -1),
+ g_free);
+
+ for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 2)) {
+ gchar *tmp;
+ lua_pushvalue (L, -2);
+ name = luaL_checklstring (L, -1, &keylen);
+
+ if (name && lua_istable (L, -2)) {
+ tmp = g_malloc (keylen + 1);
+ rspamd_strlcpy (tmp, name, keylen + 1);
+ g_ptr_array_add (names, tmp);
+ }
+
if (name != NULL && lua_istable (L, -1)) {
+
+ }
+ }
+
+ PTR_ARRAY_FOREACH (names, i, name) {
+ lua_getfield (L, -1, name);
+
+ if (lua_istable (L, -1)) {
obj = ucl_object_lua_import (L, lua_gettop (L));
+
if (obj != NULL) {
+ ucl_object_sort_keys (obj, UCL_SORT_KEYS_DEFAULT);
ucl_object_insert_key_merged (cfg->rcl_obj,
- obj,
- name,
- keylen,
- true);
+ obj,
+ name,
+ strlen (name),
+ true);
}
}
}
+
+ g_ptr_array_free (names, TRUE);
}
/* Check metrics settings */
diff --git a/src/lua/lua_common.c b/src/lua/lua_common.c
index 5de0fa9ce..bbcec4c1c 100644
--- a/src/lua/lua_common.c
+++ b/src/lua/lua_common.c
@@ -45,6 +45,35 @@ lua_error_quark (void)
return g_quark_from_static_string ("lua-routines");
}
+/* idea from daurnimator */
+#if defined(WITH_LUAJIT) && (defined(_LP64) || defined(_LLP64) || defined(__arch64__) || defined (__arm64__) || defined (__aarch64__) || defined(_WIN64))
+#define RSPAMD_USE_47BIT_LIGHTUSERDATA_HACK 1
+#else
+#define RSPAMD_USE_47BIT_LIGHTUSERDATA_HACK 0
+#endif
+
+#if RSPAMD_USE_47BIT_LIGHTUSERDATA_HACK
+#define RSPAMD_LIGHTUSERDATA_MASK(p) ((void *)((uintptr_t)(p) & ((1UL<<47)-1)))
+#else
+#define RSPAMD_LIGHTUSERDATA_MASK(p) ((void *)(p))
+#endif
+
+/*
+ * Used to map string to a pointer
+ */
+KHASH_INIT (lua_class_set, const gchar *, bool, 0, rspamd_str_hash, rspamd_str_equal);
+khash_t (lua_class_set) *lua_classes = NULL;
+
+RSPAMD_CONSTRUCTOR (lua_classes_ctor)
+{
+ lua_classes = kh_init (lua_class_set);
+}
+
+RSPAMD_DESTRUCTOR (lua_classes_dtor)
+{
+ kh_destroy (lua_class_set, lua_classes);
+}
+
/* Util functions */
/**
* Create new class and store metatable on top of the stack (must be popped if not needed)
@@ -57,33 +86,44 @@ rspamd_lua_new_class (lua_State * L,
const gchar *classname,
const struct luaL_reg *methods)
{
- luaL_newmetatable (L, classname); /* mt */
+ void *class_ptr;
+ khiter_t k;
+ gint r, nmethods = 0;
+
+ k = kh_put (lua_class_set, lua_classes, classname, &r);
+ class_ptr = RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k));
+
+ if (methods) {
+ for (;;) {
+ if (methods[nmethods].name != NULL) {
+ nmethods ++;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ lua_createtable (L, 0, 3 + nmethods);
lua_pushstring (L, "__index");
lua_pushvalue (L, -2); /* pushes the metatable */
lua_settable (L, -3); /* metatable.__index = metatable */
- lua_pushstring (L, "class"); /* mt,"class" */
- lua_pushstring (L, classname); /* mt,"class",classname */
- lua_rawset (L, -3); /* mt */
+ lua_pushstring (L, "class");
+ lua_pushstring (L, classname);
+ lua_rawset (L, -3);
+
+ lua_pushstring (L, "class_ptr");
+ lua_pushlightuserdata (L, class_ptr);
+ lua_rawset (L, -3);
if (methods) {
luaL_register (L, NULL, methods); /* pushes all methods as MT fields */
}
- /* MT is left on stack ! */
-}
-/**
- * Create and register new class with static methods and store metatable on top of the stack
- */
-void
-rspamd_lua_new_class_full (lua_State *L,
- const gchar *classname,
- const gchar *static_name,
- const struct luaL_reg *methods,
- const struct luaL_reg *func)
-{
- rspamd_lua_new_class (L, classname, methods);
- luaL_register (L, static_name, func);
+ lua_pushvalue (L, -1); /* Preserves metatable */
+ lua_rawsetp (L, LUA_REGISTRYINDEX, class_ptr);
+ /* MT is left on stack ! */
}
static const gchar *
@@ -97,14 +137,7 @@ rspamd_lua_class_tostring_buf (lua_State *L, gboolean print_pointer, gint pos)
goto err;
}
- lua_pushstring (L, "__index");
- lua_gettable (L, -2);
pop ++;
-
- if (!lua_istable (L, -1)) {
- goto err;
- }
-
lua_pushstring (L, "class");
lua_gettable (L, -2);
pop ++;
@@ -150,7 +183,14 @@ rspamd_lua_class_tostring (lua_State * L)
void
rspamd_lua_setclass (lua_State * L, const gchar *classname, gint objidx)
{
- luaL_getmetatable (L, classname);
+ khiter_t k;
+
+ k = kh_get (lua_class_set, lua_classes, classname);
+
+ g_assert (k != kh_end (lua_classes));
+ lua_rawgetp (L, LUA_REGISTRYINDEX,
+ RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k)));
+
if (objidx < 0) {
objidx--;
}
@@ -161,7 +201,6 @@ rspamd_lua_setclass (lua_State * L, const gchar *classname, gint objidx)
void
rspamd_lua_table_set (lua_State * L, const gchar *index, const gchar *value)
{
-
lua_pushstring (L, index);
if (value) {
lua_pushstring (L, value);
@@ -929,16 +968,10 @@ rspamd_lua_init (bool wipe_mem)
lua_settop (L, 0);
#endif
- luaL_newmetatable (L, "rspamd{ev_base}");
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{ev_base}");
- lua_rawset (L, -3);
+ rspamd_lua_new_class (L, "rspamd{ev_base}", NULL);
lua_pop (L, 1);
- luaL_newmetatable (L, "rspamd{session}");
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{session}");
- lua_rawset (L, -3);
+ rspamd_lua_new_class (L, "rspamd{session}", NULL);
lua_pop (L, 1);
rspamd_lua_add_preload (L, "lpeg", luaopen_lpeg);
@@ -1206,12 +1239,23 @@ gpointer
rspamd_lua_check_class (lua_State *L, gint index, const gchar *name)
{
gpointer p;
+ khiter_t k;
if (lua_type (L, index) == LUA_TUSERDATA) {
p = lua_touserdata (L, index);
if (p) {
if (lua_getmetatable (L, index)) {
- lua_getfield (L, LUA_REGISTRYINDEX, name); /* get correct metatable */
+ k = kh_get (lua_class_set, lua_classes, name);
+
+ if (k == kh_end (lua_classes)) {
+ lua_pop (L, 1);
+
+ return NULL;
+ }
+
+ lua_rawgetp (L, LUA_REGISTRYINDEX,
+ RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k)));
+
if (lua_rawequal (L, -1, -2)) { /* does it have the correct mt? */
lua_pop (L, 2); /* remove both metatables */
return p;
@@ -1824,6 +1868,7 @@ rspamd_lua_check_udata_common (lua_State *L, gint pos, const gchar *classname,
{
void *p = lua_touserdata (L, pos);
guint i, top = lua_gettop (L);
+ khiter_t k;
if (p == NULL) {
goto err;
@@ -1831,7 +1876,14 @@ rspamd_lua_check_udata_common (lua_State *L, gint pos, const gchar *classname,
else {
/* Match class */
if (lua_getmetatable (L, pos)) {
- luaL_getmetatable (L, classname);
+ k = kh_get (lua_class_set, lua_classes, (gchar *)classname);
+
+ if (k == kh_end (lua_classes)) {
+ goto err;
+ }
+
+ lua_rawgetp (L, LUA_REGISTRYINDEX,
+ RSPAMD_LIGHTUSERDATA_MASK (kh_key (lua_classes, k)));
if (!lua_rawequal (L, -1, -2)) {
goto err;
diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h
index 40bbea772..9878cc521 100644
--- a/src/lua/lua_common.h
+++ b/src/lua/lua_common.h
@@ -40,6 +40,28 @@ luaL_register (lua_State *L, const gchar *name, const struct luaL_reg *methods)
}
#endif
+#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501
+static inline int lua_absindex (lua_State *L, int i) {
+ if (i < 0 && i > LUA_REGISTRYINDEX)
+ i += lua_gettop(L) + 1;
+ return i;
+}
+static inline int lua_rawgetp (lua_State *L, int i, const void *p) {
+ int abs_i = lua_absindex(L, i);
+ lua_pushlightuserdata(L, (void*)p);
+ lua_rawget(L, abs_i);
+ return lua_type(L, -1);
+}
+
+static inline void lua_rawsetp (lua_State *L, int i, const void *p) {
+ int abs_i = lua_absindex(L, i);
+ luaL_checkstack(L, 1, "not enough stack slots");
+ lua_pushlightuserdata(L, (void*)p);
+ lua_insert(L, -2);
+ lua_rawset(L, abs_i);
+}
+#endif
+
/* Interface definitions */
#define LUA_FUNCTION_DEF(class, name) static int lua_ ## class ## _ ## name ( \
lua_State * L)
@@ -133,15 +155,6 @@ void rspamd_lua_new_class (lua_State *L,
const struct luaL_reg *methods);
/**
- * Create and register new class with static methods
- */
-void rspamd_lua_new_class_full (lua_State *L,
- const gchar *classname,
- const gchar *static_name,
- const struct luaL_reg *methods,
- const struct luaL_reg *func);
-
-/**
* Set class name for object at @param objidx position
*/
void rspamd_lua_setclass (lua_State *L, const gchar *classname, gint objidx);
@@ -216,6 +229,9 @@ void rspamd_lua_task_push (lua_State *L, struct rspamd_task *task);
struct rspamd_lua_ip *lua_check_ip (lua_State *L, gint pos);
struct rspamd_lua_text *lua_check_text (lua_State *L, gint pos);
+/* Creates and *pushes* new rspamd text, data is copied if RSPAMD_TEXT_FLAG_OWN is in flags*/
+struct rspamd_lua_text *lua_new_text (lua_State *L, const gchar *start,
+ gsize len, guint flags);
struct rspamd_lua_regexp *lua_check_regexp (lua_State *L, gint pos);
diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c
index 5c914af79..f047f1530 100644
--- a/src/lua/lua_config.c
+++ b/src/lua/lua_config.c
@@ -4157,7 +4157,12 @@ lua_config_init_subsystem (lua_State *L)
rspamd_init_filters (cfg, FALSE);
}
else if (strcmp (parts[i], "langdet") == 0) {
- cfg->lang_det = rspamd_language_detector_init (cfg);
+ if (!cfg->lang_det) {
+ cfg->lang_det = rspamd_language_detector_init (cfg);
+ rspamd_mempool_add_destructor (cfg->cfg_pool,
+ (rspamd_mempool_destruct_t) rspamd_language_detector_unref,
+ cfg->lang_det);
+ }
}
else if (strcmp (parts[i], "stat") == 0) {
rspamd_stat_init (cfg, NULL);
diff --git a/src/lua/lua_cryptobox.c b/src/lua/lua_cryptobox.c
index 35faa0037..645b2495f 100644
--- a/src/lua/lua_cryptobox.c
+++ b/src/lua/lua_cryptobox.c
@@ -2437,54 +2437,20 @@ lua_load_cryptobox (lua_State * L)
void
luaopen_cryptobox (lua_State * L)
{
- luaL_newmetatable (L, "rspamd{cryptobox_pubkey}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{cryptobox_pubkey}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, cryptoboxpubkeylib_m);
+ rspamd_lua_new_class (L, "rspamd{cryptobox_pubkey}", cryptoboxpubkeylib_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_cryptobox_pubkey", lua_load_pubkey);
- luaL_newmetatable (L, "rspamd{cryptobox_keypair}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{cryptobox_keypair}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, cryptoboxkeypairlib_m);
+ rspamd_lua_new_class (L, "rspamd{cryptobox_keypair}", cryptoboxkeypairlib_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_cryptobox_keypair", lua_load_keypair);
- luaL_newmetatable (L, "rspamd{cryptobox_signature}");
-
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{cryptobox_signature}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, cryptoboxsignlib_m);
+ rspamd_lua_new_class (L, "rspamd{cryptobox_signature}", cryptoboxsignlib_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_cryptobox_signature", lua_load_signature);
- luaL_newmetatable (L, "rspamd{cryptobox_hash}");
-
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{cryptobox_hash}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, cryptoboxhashlib_m);
+ rspamd_lua_new_class (L, "rspamd{cryptobox_hash}", cryptoboxhashlib_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_cryptobox_hash", lua_load_hash);
rspamd_lua_add_preload (L, "rspamd_cryptobox", lua_load_cryptobox);
diff --git a/src/lua/lua_dns_resolver.c b/src/lua/lua_dns_resolver.c
index a4e3b4b03..75f7a3b6b 100644
--- a/src/lua/lua_dns_resolver.c
+++ b/src/lua/lua_dns_resolver.c
@@ -477,7 +477,6 @@ lua_dns_resolver_resolve_common (lua_State *L,
if (ret) {
cbdata->s = session;
-
if (item) {
cbdata->item = item;
rspamd_symcache_item_async_inc (task, item, M);
@@ -486,7 +485,11 @@ lua_dns_resolver_resolve_common (lua_State *L,
lua_pushboolean (L, TRUE);
}
else {
- lua_pushnil (L);
+ if (item) {
+ rspamd_symcache_item_async_dec_check (task, item, M);
+ }
+
+ goto err;
}
if (item) {
@@ -506,6 +509,11 @@ err:
g_free (cbdata->user_str);
}
+ /* Callback is not called in this case */
+ if (cbdata->cbref != -1) {
+ luaL_unref (L, LUA_REGISTRYINDEX, cbdata->cbref);
+ }
+
lua_pushnil (L);
return 1;
@@ -693,15 +701,7 @@ void
luaopen_dns_resolver (lua_State * L)
{
- luaL_newmetatable (L, "rspamd{resolver}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{resolver}");
- lua_rawset (L, -3);
-
+ rspamd_lua_new_class (L, "rspamd{resolver}", dns_resolverlib_m);
{
LUA_ENUM (L, DNS_A, RDNS_REQUEST_A);
LUA_ENUM (L, DNS_PTR, RDNS_REQUEST_PTR);
@@ -713,8 +713,7 @@ luaopen_dns_resolver (lua_State * L)
LUA_ENUM (L, DNS_SOA, RDNS_REQUEST_SOA);
}
- luaL_register (L, NULL, dns_resolverlib_m);
- rspamd_lua_add_preload (L, "rspamd_resolver", lua_load_dns_resolver);
+ lua_pop (L, 1);
- lua_pop (L, 1); /* remove metatable from stack */
+ rspamd_lua_add_preload (L, "rspamd_resolver", lua_load_dns_resolver);
}
diff --git a/src/lua/lua_expression.c b/src/lua/lua_expression.c
index c0e75fe84..60ee8fdf7 100644
--- a/src/lua/lua_expression.c
+++ b/src/lua/lua_expression.c
@@ -511,17 +511,7 @@ lua_load_expression (lua_State * L)
void
luaopen_expression (lua_State * L)
{
- luaL_newmetatable (L, "rspamd{expr}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{expr}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, exprlib_m);
+ rspamd_lua_new_class (L, "rspamd{expr}", exprlib_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_expression", lua_load_expression);
-
- lua_pop (L, 1); /* remove metatable from stack */
}
diff --git a/src/lua/lua_http.c b/src/lua/lua_http.c
index ec42ab39e..d73bd7281 100644
--- a/src/lua/lua_http.c
+++ b/src/lua/lua_http.c
@@ -984,7 +984,8 @@ lua_http_request (lua_State *L)
cbd->session = session;
}
- if (rspamd_parse_inet_address (&cbd->addr, msg->host->str, msg->host->len)) {
+ if (rspamd_parse_inet_address (&cbd->addr,
+ msg->host->str, msg->host->len, RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) {
/* Host is numeric IP, no need to resolve */
gboolean ret;
diff --git a/src/lua/lua_ip.c b/src/lua/lua_ip.c
index 3c3ef2d51..f873c4515 100644
--- a/src/lua/lua_ip.c
+++ b/src/lua/lua_ip.c
@@ -369,13 +369,15 @@ lua_ip_from_string (lua_State *L)
LUA_TRACE_POINT;
struct rspamd_lua_ip *ip;
const gchar *ip_str;
+ gsize len;
- ip_str = luaL_checkstring (L, 1);
+ ip_str = luaL_checklstring (L, 1, &len);
if (ip_str) {
ip = lua_ip_new (L, NULL);
- if (!rspamd_parse_inet_address (&ip->addr, ip_str, 0)) {
- msg_warn ("cannot parse ip: %s", ip_str);
+ if (!rspamd_parse_inet_address (&ip->addr,
+ ip_str, len, RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) {
+ msg_warn ("cannot parse ip: %*s", (gint) len, ip_str);
ip->addr = NULL;
}
}
@@ -490,7 +492,7 @@ lua_ip_equal (lua_State *L)
gboolean res = FALSE;
if (ip1 && ip2 && ip1->addr && ip2->addr) {
- res = rspamd_inet_address_compare (ip1->addr, ip2->addr, TRUE);
+ res = rspamd_inet_address_compare (ip1->addr, ip2->addr, TRUE) == 0;
}
lua_pushboolean (L, res);
@@ -559,7 +561,8 @@ rspamd_lua_ip_push_fromstring (lua_State *L, const gchar *ip_str)
else {
ip = g_malloc0 (sizeof (struct rspamd_lua_ip));
- if (rspamd_parse_inet_address (&ip->addr, ip_str, 0)) {
+ if (rspamd_parse_inet_address (&ip->addr,
+ ip_str, strlen (ip_str), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) {
pip = lua_newuserdata (L, sizeof (struct rspamd_lua_ip *));
rspamd_lua_setclass (L, "rspamd{ip}", -1);
@@ -584,17 +587,7 @@ lua_load_ip (lua_State * L)
void
luaopen_ip (lua_State * L)
{
- luaL_newmetatable (L, "rspamd{ip}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{ip}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, iplib_m);
- rspamd_lua_add_preload (L, "rspamd_ip", lua_load_ip);
-
+ rspamd_lua_new_class (L, "rspamd{ip}", iplib_m);
lua_pop (L, 1);
+ rspamd_lua_add_preload (L, "rspamd_ip", lua_load_ip);
}
diff --git a/src/lua/lua_logger.c b/src/lua/lua_logger.c
index bca4bc6e3..f76db8877 100644
--- a/src/lua/lua_logger.c
+++ b/src/lua/lua_logger.c
@@ -575,31 +575,34 @@ lua_logger_out_type (lua_State *L, gint pos,
trace->cur_level ++;
switch (type) {
- case LUA_TNUMBER:
- r = lua_logger_out_num (L, pos, outbuf, len, trace);
- break;
- case LUA_TBOOLEAN:
- r = lua_logger_out_boolean (L, pos, outbuf, len, trace);
- break;
- case LUA_TTABLE:
- r = lua_logger_out_table (L, pos, outbuf, len, trace, esc_type);
- break;
- case LUA_TUSERDATA:
- r = lua_logger_out_userdata (L, pos, outbuf, len, trace);
- break;
- case LUA_TFUNCTION:
- r = rspamd_snprintf (outbuf, len + 1, "function");
- break;
- case LUA_TNIL:
- r = rspamd_snprintf (outbuf, len + 1, "nil");
- break;
- case LUA_TNONE:
- r = rspamd_snprintf (outbuf, len + 1, "no value");
- break;
- default:
- /* Try to push everything as string using tostring magic */
- r = lua_logger_out_str (L, pos, outbuf, len, trace, esc_type);
- break;
+ case LUA_TNUMBER:
+ r = lua_logger_out_num (L, pos, outbuf, len, trace);
+ break;
+ case LUA_TBOOLEAN:
+ r = lua_logger_out_boolean (L, pos, outbuf, len, trace);
+ break;
+ case LUA_TTABLE:
+ r = lua_logger_out_table (L, pos, outbuf, len, trace, esc_type);
+ break;
+ case LUA_TUSERDATA:
+ r = lua_logger_out_userdata (L, pos, outbuf, len, trace);
+ break;
+ case LUA_TFUNCTION:
+ r = rspamd_snprintf (outbuf, len + 1, "function");
+ break;
+ case LUA_TLIGHTUSERDATA:
+ r = rspamd_snprintf (outbuf, len + 1, "0x%p", lua_topointer (L, pos));
+ break;
+ case LUA_TNIL:
+ r = rspamd_snprintf (outbuf, len + 1, "nil");
+ break;
+ case LUA_TNONE:
+ r = rspamd_snprintf (outbuf, len + 1, "no value");
+ break;
+ default:
+ /* Try to push everything as string using tostring magic */
+ r = lua_logger_out_str (L, pos, outbuf, len, trace, esc_type);
+ break;
}
trace->cur_level --;
diff --git a/src/lua/lua_mempool.c b/src/lua/lua_mempool.c
index 62d294111..06dcd2d5c 100644
--- a/src/lua/lua_mempool.c
+++ b/src/lua/lua_mempool.c
@@ -582,17 +582,7 @@ lua_load_mempool (lua_State * L)
void
luaopen_mempool (lua_State * L)
{
- luaL_newmetatable (L, "rspamd{mempool}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{mempool}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, mempoollib_m);
+ rspamd_lua_new_class (L, "rspamd{mempool}", mempoollib_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_mempool", lua_load_mempool);
-
- lua_pop (L, 1); /* remove metatable from stack */
}
diff --git a/src/lua/lua_mimepart.c b/src/lua/lua_mimepart.c
index dfc4ee8fa..01c64ae64 100644
--- a/src/lua/lua_mimepart.c
+++ b/src/lua/lua_mimepart.c
@@ -365,19 +365,26 @@ LUA_FUNCTION_DEF (mimepart, get_type_full);
/***
* @method mime_part:get_detected_type()
- * Extract content-type string of the mime part. Use libmagic detection
+ * Extract content-type string of the mime part. Use lua_magic detection
* @return {string,string} content type in form 'type','subtype'
*/
LUA_FUNCTION_DEF (mimepart, get_detected_type);
/***
* @method mime_part:get_detected_type_full()
- * Extract content-type string of the mime part with all attributes. Use libmagic detection
+ * Extract content-type string of the mime part with all attributes. Use lua_magic detection
* @return {string,string,table} content type in form 'type','subtype', {attrs}
*/
LUA_FUNCTION_DEF (mimepart, get_detected_type_full);
/***
+ * @method mime_part:get_detected_ext()
+ * Returns a msdos extension name according to lua_magic detection
+ * @return {string} detected extension (see lua_magic.types)
+ */
+LUA_FUNCTION_DEF (mimepart, get_detected_ext);
+
+/***
* @method mime_part:get_cte()
* Extract content-transfer-encoding for a part
* @return {string} content transfer encoding (e.g. `base64` or `7bit`)
@@ -523,6 +530,7 @@ static const struct luaL_reg mimepartlib_m[] = {
LUA_INTERFACE_DEF (mimepart, get_type),
LUA_INTERFACE_DEF (mimepart, get_type_full),
LUA_INTERFACE_DEF (mimepart, get_detected_type),
+ LUA_INTERFACE_DEF (mimepart, get_detected_ext),
LUA_INTERFACE_DEF (mimepart, get_detected_type_full),
LUA_INTERFACE_DEF (mimepart, get_cte),
LUA_INTERFACE_DEF (mimepart, get_filename),
@@ -1495,6 +1503,26 @@ lua_mimepart_get_detected_type_full (lua_State * L)
}
static gint
+lua_mimepart_get_detected_ext (lua_State * L)
+{
+ LUA_TRACE_POINT;
+ struct rspamd_mime_part *part = lua_check_mimepart (L);
+
+ if (part == NULL) {
+ return luaL_error (L, "invalid arguments");
+ }
+
+ if (part->detected_ext) {
+ lua_pushstring (L, part->detected_ext);
+ }
+ else {
+ lua_pushnil (L);
+ }
+
+ return 1;
+}
+
+static gint
lua_mimepart_get_cte (lua_State * L)
{
LUA_TRACE_POINT;
@@ -1702,7 +1730,7 @@ lua_mimepart_is_attachment (lua_State * L)
return luaL_error (L, "invalid arguments");
}
- if (!(part->flags & (RSPAMD_MIME_PART_IMAGE|RSPAMD_MIME_PART_TEXT))) {
+ if (!(part->flags & (RSPAMD_MIME_PART_IMAGE))) {
if (part->cd && part->cd->type == RSPAMD_CT_ATTACHMENT) {
lua_pushboolean (L, true);
}
diff --git a/src/lua/lua_redis.c b/src/lua/lua_redis.c
index ac1a8c297..32fa55476 100644
--- a/src/lua/lua_redis.c
+++ b/src/lua/lua_redis.c
@@ -896,7 +896,8 @@ rspamd_lua_redis_prepare_connection (lua_State *L, gint *pcbref, gboolean is_asy
else if (lua_type (L, -1) == LUA_TSTRING) {
host = lua_tostring (L, -1);
- if (rspamd_parse_inet_address (&ip, host, strlen (host))) {
+ if (rspamd_parse_inet_address (&ip,
+ host, strlen (host), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) {
addr = g_alloca (sizeof (*addr));
addr->addr = ip;
@@ -1165,7 +1166,8 @@ lua_redis_make_request_sync (lua_State *L)
}
else if (lua_type (L, -1) == LUA_TSTRING) {
host = lua_tostring (L, -1);
- if (rspamd_parse_inet_address (&ip, host, strlen (host))) {
+ if (rspamd_parse_inet_address (&ip,
+ host, strlen (host), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) {
addr = g_alloca (sizeof (*addr));
addr->addr = ip;
@@ -1603,17 +1605,7 @@ lua_load_redis (lua_State * L)
void
luaopen_redis (lua_State * L)
{
- luaL_newmetatable (L, "rspamd{redis}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{redis}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, redislib_m);
+ rspamd_lua_new_class (L, "rspamd{redis}", redislib_m);
lua_pop (L, 1);
-
rspamd_lua_add_preload (L, "rspamd_redis", lua_load_redis);
}
diff --git a/src/lua/lua_regexp.c b/src/lua/lua_regexp.c
index 4033722a3..ae1f2007a 100644
--- a/src/lua/lua_regexp.c
+++ b/src/lua/lua_regexp.c
@@ -543,7 +543,7 @@ lua_regexp_search (lua_State *L)
raw = lua_toboolean (L, 3);
}
- if (data) {
+ if (data && len > 0) {
if (lua_gettop (L) >= 4) {
capture = TRUE;
captures = g_array_new (FALSE, TRUE,
@@ -588,12 +588,14 @@ lua_regexp_search (lua_State *L)
if (capture) {
g_array_free (captures, TRUE);
}
-
- return 1;
+ }
+ else {
+ lua_pushnil (L);
}
}
-
- lua_pushnil (L);
+ else {
+ return luaL_error (L, "invalid arguments");
+ }
return 1;
}
@@ -633,7 +635,7 @@ lua_regexp_match (lua_State *L)
raw = lua_toboolean (L, 3);
}
- if (data) {
+ if (data && len > 0) {
if (re->match_limit > 0) {
len = MIN (len, re->match_limit);
}
@@ -644,11 +646,14 @@ lua_regexp_match (lua_State *L)
else {
lua_pushboolean (L, FALSE);
}
- return 1;
+ }
+ else {
+ lua_pushboolean (L, FALSE);
}
}
-
- lua_pushnil (L);
+ else {
+ return luaL_error (L, "invalid arguments");
+ }
return 1;
}
@@ -689,13 +694,13 @@ lua_regexp_matchn (lua_State *L)
}
max_matches = lua_tointeger (L, 3);
+ matches = 0;
if (lua_gettop (L) == 4) {
raw = lua_toboolean (L, 4);
}
- if (data) {
- matches = 0;
+ if (data && len > 0) {
if (re->match_limit > 0) {
len = MIN (len, re->match_limit);
@@ -714,14 +719,14 @@ lua_regexp_matchn (lua_State *L)
break;
}
}
-
- lua_pushinteger (L, matches);
-
- return 1;
}
+
+ lua_pushinteger (L, matches);
+ }
+ else {
+ return luaL_error (L, "invalid arguments");
}
- lua_pushnil (L);
return 1;
}
@@ -770,10 +775,11 @@ lua_regexp_split (lua_State *L)
len = MIN (len, re->match_limit);
}
- if (data) {
+ if (data && len > 0) {
lua_newtable (L);
i = 0;
old_start = data;
+
while (rspamd_regexp_search (re->re, data, len, &start, &end, FALSE,
NULL)) {
if (start - old_start > 0) {
@@ -824,6 +830,9 @@ lua_regexp_split (lua_State *L)
return 1;
}
}
+ else {
+ return luaL_error (L, "invalid arguments");
+ }
lua_pushnil (L);
return 1;
@@ -880,22 +889,16 @@ lua_load_regexp (lua_State * L)
void
luaopen_regexp (lua_State * L)
{
- luaL_newmetatable (L, "rspamd{regexp}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{regexp}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, regexplib_m);
+ rspamd_lua_new_class (L, "rspamd{regexp}", regexplib_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_regexp", lua_load_regexp);
+}
- if (regexp_static_pool == NULL) {
- regexp_static_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (),
- "regexp_lua_pool");
- }
-
- lua_settop (L, 0);
+RSPAMD_CONSTRUCTOR (lua_re_static_pool_ctor) {
+ regexp_static_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (),
+ "regexp_lua_pool");
}
+
+RSPAMD_DESTRUCTOR (lua_re_static_pool_dtor) {
+ rspamd_mempool_delete (regexp_static_pool);
+} \ No newline at end of file
diff --git a/src/lua/lua_rsa.c b/src/lua/lua_rsa.c
index 58607f92c..4b2caa2bf 100644
--- a/src/lua/lua_rsa.c
+++ b/src/lua/lua_rsa.c
@@ -719,40 +719,16 @@ lua_load_rsa (lua_State * L)
void
luaopen_rsa (lua_State * L)
{
- luaL_newmetatable (L, "rspamd{rsa_pubkey}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{rsa_pubkey}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, rsapubkeylib_m);
+ rspamd_lua_new_class (L, "rspamd{rsa_pubkey}", rsapubkeylib_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_rsa_pubkey", lua_load_pubkey);
- luaL_newmetatable (L, "rspamd{rsa_privkey}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{rsa_privkey}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, rsaprivkeylib_m);
+ rspamd_lua_new_class (L, "rspamd{rsa_privkey}", rsaprivkeylib_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_rsa_privkey", lua_load_privkey);
- luaL_newmetatable (L, "rspamd{rsa_signature}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{rsa_signature}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, rsasignlib_m);
+ rspamd_lua_new_class (L, "rspamd{rsa_signature}", rsasignlib_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_rsa_signature", lua_load_signature);
rspamd_lua_add_preload (L, "rspamd_rsa", lua_load_rsa);
diff --git a/src/lua/lua_sqlite3.c b/src/lua/lua_sqlite3.c
index 87d798666..95104d1b0 100644
--- a/src/lua/lua_sqlite3.c
+++ b/src/lua/lua_sqlite3.c
@@ -373,28 +373,10 @@ lua_load_sqlite3 (lua_State * L)
void
luaopen_sqlite3 (lua_State * L)
{
- luaL_newmetatable (L, "rspamd{sqlite3}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{sqlite3}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, sqlitelib_m);
+ rspamd_lua_new_class (L, "rspamd{sqlite3}", sqlitelib_m);
lua_pop (L, 1);
- luaL_newmetatable (L, "rspamd{sqlite3_stmt}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{sqlite3_stmt}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, sqlitestmtlib_m);
+ rspamd_lua_new_class (L, "rspamd{sqlite3_stmt}", sqlitestmtlib_m);
lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_sqlite3", lua_load_sqlite3);
diff --git a/src/lua/lua_task.c b/src/lua/lua_task.c
index 1664e415f..2ec6dc29b 100644
--- a/src/lua/lua_task.c
+++ b/src/lua/lua_task.c
@@ -200,9 +200,10 @@ end
*/
LUA_FUNCTION_DEF (task, append_message);
/***
- * @method task:get_urls([need_emails|list_protos])
+ * @method task:get_urls([need_emails|list_protos][, need_images])
* Get all URLs found in a message. Telephone urls and emails are not included unless explicitly asked in `list_protos`
* @param {boolean} need_emails if `true` then reutrn also email urls, this can be a comma separated string of protocols desired or a table (e.g. `mailto` or `telephone`)
+ * @param {boolean} need_images return urls from images (<img src=...>) as well
* @return {table rspamd_url} list of all urls found
@example
local function phishing_cb(task)
@@ -646,6 +647,14 @@ LUA_FUNCTION_DEF (task, get_symbols_all);
LUA_FUNCTION_DEF (task, get_symbols);
/***
+ * @method task:get_groups([need_private])
+ * Returns a map [group -> group_score] for matched group. If `need_private` is
+ * unspecified, then the global option `public_groups_only` is used for default.
+ * @return {table, number} a map [group -> group_score]
+ */
+LUA_FUNCTION_DEF (task, get_groups);
+
+/***
* @method task:get_symbols_numeric()
* Returns array of all symbols matched for this task
* @return {table|number, table|number} table of numbers with symbols ids + table of theirs scores
@@ -1149,6 +1158,7 @@ static const struct luaL_reg tasklib_m[] = {
LUA_INTERFACE_DEF (task, get_symbols_all),
LUA_INTERFACE_DEF (task, get_symbols_numeric),
LUA_INTERFACE_DEF (task, get_symbols_tokens),
+ LUA_INTERFACE_DEF (task, get_groups),
LUA_INTERFACE_DEF (task, process_ann_tokens),
LUA_INTERFACE_DEF (task, has_symbol),
LUA_INTERFACE_DEF (task, enable_symbol),
@@ -1262,14 +1272,6 @@ lua_check_archive (lua_State * L)
return ud ? *((struct rspamd_archive **)ud) : NULL;
}
-struct rspamd_lua_text *
-lua_check_text (lua_State * L, gint pos)
-{
- void *ud = rspamd_lua_check_udata (L, pos, "rspamd{text}");
- luaL_argcheck (L, ud != NULL, pos, "'text' expected");
- return ud ? (struct rspamd_lua_text *)ud : NULL;
-}
-
static void
lua_task_set_cached (lua_State *L, struct rspamd_task *task, const gchar *key,
gint pos)
@@ -1668,8 +1670,9 @@ lua_task_load_from_string (lua_State * L)
}
task = rspamd_task_new (NULL, cfg, NULL, NULL, NULL);
- task->msg.begin = g_strdup (str_message);
- task->msg.len = message_len;
+ task->msg.begin = g_malloc (message_len);
+ memcpy ((gchar *)task->msg.begin, str_message, message_len);
+ task->msg.len = message_len;
rspamd_mempool_add_destructor (task->task_pool, lua_task_free_dtor,
(gpointer)task->msg.begin);
}
@@ -2099,6 +2102,7 @@ struct lua_tree_cb_data {
lua_State *L;
int i;
gint mask;
+ gint need_images;
};
static void
@@ -2109,6 +2113,10 @@ lua_tree_url_callback (gpointer key, gpointer value, gpointer ud)
struct lua_tree_cb_data *cb = ud;
if (url->protocol & cb->mask) {
+ if (!cb->need_images && (url->flags & RSPAMD_URL_FLAG_IMAGE)) {
+ return;
+ }
+
lua_url = lua_newuserdata (cb->L, sizeof (struct rspamd_lua_url));
rspamd_lua_setclass (cb->L, "rspamd{url}", -1);
lua_url->url = url;
@@ -2125,6 +2133,8 @@ lua_task_get_urls (lua_State * L)
gint protocols_mask = 0;
static const gint default_mask = PROTOCOL_HTTP|PROTOCOL_HTTPS|
PROTOCOL_FILE|PROTOCOL_FTP;
+ const gchar *cache_name = "emails+urls";
+ gboolean need_images = FALSE;
gsize sz;
if (task) {
@@ -2184,29 +2194,42 @@ lua_task_get_urls (lua_State * L)
else {
protocols_mask = default_mask;
}
+
+ if (lua_type (L, 3) == LUA_TBOOLEAN) {
+ need_images = lua_toboolean (L, 3);
+ }
}
else {
protocols_mask = default_mask;
}
+ memset (&cb, 0, sizeof (cb));
cb.i = 1;
cb.L = L;
cb.mask = protocols_mask;
+ cb.need_images = need_images;
if (protocols_mask & PROTOCOL_MAILTO) {
+ if (need_images) {
+ cache_name = "emails+urls+img";
+ }
+ else {
+ cache_name = "emails+urls";
+ }
+
sz = g_hash_table_size (MESSAGE_FIELD (task, urls)) +
g_hash_table_size (MESSAGE_FIELD (task, emails));
if (protocols_mask == (default_mask|PROTOCOL_MAILTO)) {
/* Can use cached version */
- if (!lua_task_get_cached (L, task, "emails+urls")) {
+ if (!lua_task_get_cached (L, task, cache_name)) {
lua_createtable (L, sz, 0);
g_hash_table_foreach (MESSAGE_FIELD (task, urls),
lua_tree_url_callback, &cb);
g_hash_table_foreach (MESSAGE_FIELD (task, emails),
lua_tree_url_callback, &cb);
- lua_task_set_cached (L, task, "emails+urls", -1);
+ lua_task_set_cached (L, task, cache_name, -1);
}
}
else {
@@ -2219,14 +2242,21 @@ lua_task_get_urls (lua_State * L)
}
else {
+ if (need_images) {
+ cache_name = "urls+img";
+ }
+ else {
+ cache_name = "urls";
+ }
+
sz = g_hash_table_size (MESSAGE_FIELD (task, urls));
if (protocols_mask == (default_mask)) {
- if (!lua_task_get_cached (L, task, "urls")) {
+ if (!lua_task_get_cached (L, task, cache_name)) {
lua_createtable (L, sz, 0);
g_hash_table_foreach (MESSAGE_FIELD (task, urls),
lua_tree_url_callback, &cb);
- lua_task_set_cached (L, task, "urls", -1);
+ lua_task_set_cached (L, task, cache_name, -1);
}
}
else {
@@ -2386,6 +2416,7 @@ lua_task_get_emails (lua_State * L)
if (task) {
if (task->message) {
lua_createtable (L, g_hash_table_size (MESSAGE_FIELD (task, emails)), 0);
+ memset (&cb, 0, sizeof (cb));
cb.i = 1;
cb.L = L;
cb.mask = PROTOCOL_MAILTO;
@@ -3437,6 +3468,7 @@ lua_task_set_recipients (lua_State *L)
} \
else { \
ret = addr->len > 0; \
+ nrcpt = addr->len; \
} \
} while (0)
@@ -3445,7 +3477,7 @@ lua_task_has_from (lua_State *L)
{
LUA_TRACE_POINT;
struct rspamd_task *task = lua_check_task (L, 1);
- gint what = 0;
+ gint what = 0, nrcpt = 0;
gboolean ret = FALSE;
if (task) {
@@ -3487,7 +3519,7 @@ lua_task_has_recipients (lua_State *L)
{
LUA_TRACE_POINT;
struct rspamd_task *task = lua_check_task (L, 1);
- gint what = 0;
+ gint what = 0, nrcpt = 0;
gboolean ret = FALSE;
if (task) {
@@ -3521,6 +3553,11 @@ lua_task_has_recipients (lua_State *L)
lua_pushboolean (L, ret);
+ if (ret) {
+ lua_pushinteger (L, nrcpt);
+ return 2;
+ }
+
return 1;
}
@@ -3819,7 +3856,8 @@ lua_task_set_from_ip (lua_State *L)
{
LUA_TRACE_POINT;
struct rspamd_task *task = lua_check_task (L, 1);
- const gchar *ip_str = luaL_checkstring (L, 2);
+ gsize len;
+ const gchar *ip_str = luaL_checklstring (L, 2, &len);
rspamd_inet_addr_t *addr = NULL;
if (!task || !ip_str) {
@@ -3829,7 +3867,8 @@ lua_task_set_from_ip (lua_State *L)
else {
if (!rspamd_parse_inet_address (&addr,
ip_str,
- 0)) {
+ len,
+ RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) {
msg_warn_task ("cannot get IP from received header: '%s'",
ip_str);
}
@@ -4444,6 +4483,46 @@ lua_task_get_symbols_numeric (lua_State *L)
return 2;
}
+static gint
+lua_task_get_groups (lua_State *L)
+{
+ LUA_TRACE_POINT;
+ struct rspamd_task *task = lua_check_task (L, 1);
+ gboolean need_private;
+ struct rspamd_scan_result *mres;
+ struct rspamd_symbols_group *gr;
+ gdouble gr_score;
+
+ if (task) {
+ mres = task->result;
+
+ if (lua_isboolean (L, 2)) {
+ need_private = lua_toboolean (L, 2);
+ }
+ else {
+ need_private = !(task->cfg->public_groups_only);
+ }
+
+ lua_createtable (L, 0, kh_size (mres->sym_groups));
+
+ kh_foreach (mres->sym_groups, gr, gr_score, {
+ if (!(gr->flags & RSPAMD_SYMBOL_GROUP_PUBLIC)) {
+ if (!need_private) {
+ continue;
+ }
+ }
+
+ lua_pushnumber (L, gr_score);
+ lua_setfield (L, -2, gr->name);
+ });
+ }
+ else {
+ return luaL_error (L, "invalid arguments");
+ }
+
+ return 1;
+}
+
struct tokens_foreach_cbdata {
struct rspamd_task *task;
lua_State *L;
diff --git a/src/lua/lua_tcp.c b/src/lua/lua_tcp.c
index 10c57cea4..379d3d807 100644
--- a/src/lua/lua_tcp.c
+++ b/src/lua/lua_tcp.c
@@ -1760,7 +1760,8 @@ lua_tcp_request (lua_State *L)
}
}
- if (rspamd_parse_inet_address (&cbd->addr, host, 0)) {
+ if (rspamd_parse_inet_address (&cbd->addr,
+ host, strlen (host), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) {
rspamd_inet_address_set_port (cbd->addr, port);
/* Host is numeric IP, no need to resolve */
lua_tcp_register_watcher (cbd);
@@ -1942,7 +1943,8 @@ lua_tcp_connect_sync (lua_State *L)
}
}
- if (rspamd_parse_inet_address (&cbd->addr, host, 0)) {
+ if (rspamd_parse_inet_address (&cbd->addr,
+ host, strlen (host), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) {
rspamd_inet_address_set_port (cbd->addr, (guint16)port);
/* Host is numeric IP, no need to resolve */
if (!lua_tcp_make_connection (cbd)) {
diff --git a/src/lua/lua_text.c b/src/lua/lua_text.c
index ab52bd32d..63b1b22a8 100644
--- a/src/lua/lua_text.c
+++ b/src/lua/lua_text.c
@@ -65,6 +65,28 @@ LUA_FUNCTION_DEF (text, ptr);
* @return {boolean} true if save has been completed
*/
LUA_FUNCTION_DEF (text, save_in_file);
+/***
+ * @method rspamd_text:span(start[, len])
+ * Returns a span for lua_text starting at pos [start] (1 indexed) and with
+ * length `len` (or to the end of the text)
+ * @param {integer} start start index
+ * @param {integer} len length of span
+ * @return {rspamd_text} new rspamd_text with span (must be careful when using with owned texts...)
+ */
+LUA_FUNCTION_DEF (text, span);
+/***
+ * @method rspamd_text:at(pos)
+ * Returns a byte at the position `pos`
+ * @param {integer} pos index
+ * @return {integer} byte at the position `pos` or nil if pos out of bound
+ */
+LUA_FUNCTION_DEF (text, at);
+/***
+ * @method rspamd_text:bytes()
+ * Converts text to an array of bytes
+ * @return {table|integer} bytes in the array (as unsigned char)
+ */
+LUA_FUNCTION_DEF (text, bytes);
LUA_FUNCTION_DEF (text, take_ownership);
LUA_FUNCTION_DEF (text, gc);
LUA_FUNCTION_DEF (text, eq);
@@ -81,6 +103,9 @@ static const struct luaL_reg textlib_m[] = {
LUA_INTERFACE_DEF (text, ptr),
LUA_INTERFACE_DEF (text, take_ownership),
LUA_INTERFACE_DEF (text, save_in_file),
+ LUA_INTERFACE_DEF (text, span),
+ LUA_INTERFACE_DEF (text, at),
+ LUA_INTERFACE_DEF (text, bytes),
{"write", lua_text_save_in_file},
{"__len", lua_text_len},
{"__tostring", lua_text_str},
@@ -89,23 +114,56 @@ static const struct luaL_reg textlib_m[] = {
{NULL, NULL}
};
+struct rspamd_lua_text *
+lua_check_text (lua_State * L, gint pos)
+{
+ void *ud = rspamd_lua_check_udata (L, pos, "rspamd{text}");
+ luaL_argcheck (L, ud != NULL, pos, "'text' expected");
+ return ud ? (struct rspamd_lua_text *)ud : NULL;
+}
+
+struct rspamd_lua_text *
+lua_new_text (lua_State *L, const gchar *start, gsize len, guint flags)
+{
+ struct rspamd_lua_text *t;
+
+ t = lua_newuserdata (L, sizeof (*t));
+
+ if (len > 0 && (flags & RSPAMD_TEXT_FLAG_OWN)) {
+ gchar *storage;
+
+ storage = g_malloc (len);
+ memcpy (storage, start, len);
+ t->start = storage;
+ }
+ else {
+ t->start = start;
+ }
+
+ t->len = len;
+ t->flags = flags;
+ rspamd_lua_setclass (L, "rspamd{text}", -1);
+
+ return t;
+}
+
+
static gint
lua_text_fromstring (lua_State *L)
{
LUA_TRACE_POINT;
const gchar *str;
gsize l = 0;
- struct rspamd_lua_text *t;
+ gboolean transparent = FALSE;
str = luaL_checklstring (L, 1, &l);
if (str) {
- t = lua_newuserdata (L, sizeof (*t));
- t->start = g_malloc (l + 1);
- rspamd_strlcpy ((char *)t->start, str, l + 1);
- t->len = l;
- t->flags = RSPAMD_TEXT_FLAG_OWN;
- rspamd_lua_setclass (L, "rspamd{text}", -1);
+ if (lua_isboolean (L, 2)) {
+ transparent = lua_toboolean (L, 2);
+ }
+
+ lua_new_text (L, str, l, transparent ? 0 : RSPAMD_TEXT_FLAG_OWN);
}
else {
return luaL_error (L, "invalid arguments");
@@ -271,6 +329,77 @@ lua_text_take_ownership (lua_State *L)
}
static gint
+lua_text_span (lua_State *L)
+{
+ LUA_TRACE_POINT;
+ struct rspamd_lua_text *t = lua_check_text (L, 1);
+ gint start = lua_tointeger (L, 2), len = -1;
+
+ if (t && start >= 1 && start <= t->len) {
+ if (lua_isnumber (L, 3)) {
+ len = lua_tonumber (L, 3);
+ }
+
+ if (len == -1) {
+ len = t->len - (start - 1);
+ }
+ else if (len > (t->len - (start - 1))) {
+ return luaL_error (L, "invalid length");
+ }
+
+ lua_new_text (L, t->start + (start - 1), len, 0);
+ }
+ else {
+ return luaL_error (L, "invalid arguments");
+ }
+
+ return 1;
+}
+
+static gint
+lua_text_at (lua_State *L)
+{
+ LUA_TRACE_POINT;
+ struct rspamd_lua_text *t = lua_check_text (L, 1);
+ gint pos = lua_tointeger (L, 2);
+
+ if (t) {
+ if (pos > 0 && pos <= t->len) {
+ lua_pushinteger (L, t->start[pos - 1]);
+ }
+ else {
+ lua_pushnil (L);
+ }
+ }
+ else {
+ return luaL_error (L, "invalid arguments");
+ }
+
+ return 1;
+}
+
+static gint
+lua_text_bytes (lua_State *L)
+{
+ LUA_TRACE_POINT;
+ struct rspamd_lua_text *t = lua_check_text (L, 1);
+
+ if (t) {
+ lua_createtable (L, t->len, 0);
+
+ for (gsize i = 0; i < t->len; i ++) {
+ lua_pushinteger (L, (guchar)t->start[i]);
+ lua_rawseti (L, -2, i + 1);
+ }
+ }
+ else {
+ return luaL_error (L, "invalid arguments");
+ }
+
+ return 1;
+}
+
+static gint
lua_text_save_in_file (lua_State *L)
{
LUA_TRACE_POINT;
diff --git a/src/lua/lua_trie.c b/src/lua/lua_trie.c
index bc90fef27..a1b0de118 100644
--- a/src/lua/lua_trie.c
+++ b/src/lua/lua_trie.c
@@ -81,7 +81,7 @@ lua_trie_destroy (lua_State *L)
}
/***
- * function trie.create(patterns)
+ * function trie.create(patterns, [flags])
* Creates new trie data structure
* @param {table} array of string patterns
* @return {trie} new trie object
@@ -93,9 +93,12 @@ lua_trie_create (lua_State *L)
gint npat = 0, flags = RSPAMD_MULTIPATTERN_ICASE|RSPAMD_MULTIPATTERN_GLOB;
GError *err = NULL;
+ if (lua_isnumber (L, 2)) {
+ flags = lua_tointeger (L, 2);
+ }
+
if (!lua_istable (L, 1)) {
- msg_err ("lua trie expects array of patterns for now");
- lua_pushnil (L);
+ return luaL_error (L, "lua trie expects array of patterns for now");
}
else {
lua_pushvalue (L, 1);
@@ -142,6 +145,7 @@ lua_trie_create (lua_State *L)
return 1;
}
+/* Normal callback type */
static gint
lua_trie_callback (struct rspamd_multipattern *mp,
guint strnum,
@@ -173,18 +177,54 @@ lua_trie_callback (struct rspamd_multipattern *mp,
return ret;
}
+/* Table like callback, expect result table on top of the stack */
+static gint
+lua_trie_table_callback (struct rspamd_multipattern *mp,
+ guint strnum,
+ gint match_start,
+ gint textpos,
+ const gchar *text,
+ gsize len,
+ void *context)
+{
+ lua_State *L = context;
+
+ /* Set table, indexed by pattern number */
+ lua_rawgeti (L, -1, strnum + 1);
+
+ if (lua_istable (L, -1)) {
+ /* Already have table, add offset */
+ gsize last = rspamd_lua_table_size (L, -1);
+ lua_pushinteger (L, textpos);
+ lua_rawseti (L, -2, last + 1);
+ /* Remove table from the stack */
+ lua_pop (L, 1);
+ }
+ else {
+ /* Pop none */
+ lua_pop (L, 1);
+ /* New table */
+ lua_newtable (L);
+ lua_pushinteger (L, textpos);
+ lua_rawseti (L, -2, 1);
+ lua_rawseti (L, -2, strnum + 1);
+ }
+
+ return 0;
+}
+
/*
* We assume that callback argument is at pos 3 and icase is in position 4
*/
static gint
lua_trie_search_str (lua_State *L, struct rspamd_multipattern *trie,
- const gchar *str, gsize len)
+ const gchar *str, gsize len, rspamd_multipattern_cb_t cb)
{
gint ret;
guint nfound = 0;
if ((ret = rspamd_multipattern_lookup (trie, str, len,
- lua_trie_callback, L, &nfound)) == 0) {
+ cb, L, &nfound)) == 0) {
return nfound;
}
@@ -192,12 +232,11 @@ lua_trie_search_str (lua_State *L, struct rspamd_multipattern *trie,
}
/***
- * @method trie:match(input, cb[, caseless])
+ * @method trie:match(input, [cb])
* Search for patterns in `input` invoking `cb` optionally ignoring case
* @param {table or string} input one or several (if `input` is an array) strings of input text
* @param {function} cb callback called on each pattern match in form `function (idx, pos)` where `idx` is a numeric index of pattern (starting from 1) and `pos` is a numeric offset where the pattern ends
- * @param {boolean} caseless if `true` then match ignores symbols case (ASCII only)
- * @return {boolean} `true` if any pattern has been found (`cb` might be called multiple times however)
+ * @return {boolean} `true` if any pattern has been found (`cb` might be called multiple times however). If `cb` is not defined then it returns a table of match positions indexed by pattern number
*/
static gint
lua_trie_match (lua_State *L)
@@ -207,8 +246,16 @@ lua_trie_match (lua_State *L)
const gchar *text;
gsize len;
gboolean found = FALSE;
+ struct rspamd_lua_text *t;
+ rspamd_multipattern_cb_t cb = lua_trie_callback;
if (trie) {
+ if (lua_type (L, 3) != LUA_TFUNCTION) {
+ /* Table like match */
+ lua_newtable (L);
+ cb = lua_trie_table_callback;
+ }
+
if (lua_type (L, 2) == LUA_TTABLE) {
lua_pushvalue (L, 2);
lua_pushnil (L);
@@ -217,10 +264,19 @@ lua_trie_match (lua_State *L)
if (lua_isstring (L, -1)) {
text = lua_tolstring (L, -1, &len);
- if (lua_trie_search_str (L, trie, text, len)) {
+ if (lua_trie_search_str (L, trie, text, len, cb)) {
found = TRUE;
}
}
+ else if (lua_isuserdata (L, -1)) {
+ t = lua_check_text (L, -1);
+
+ if (t) {
+ if (lua_trie_search_str (L, trie, t->start, t->len, cb)) {
+ found = TRUE;
+ }
+ }
+ }
lua_pop (L, 1);
}
@@ -229,18 +285,28 @@ lua_trie_match (lua_State *L)
else if (lua_type (L, 2) == LUA_TSTRING) {
text = lua_tolstring (L, 2, &len);
- if (lua_trie_search_str (L, trie, text, len)) {
+ if (lua_trie_search_str (L, trie, text, len, cb)) {
+ found = TRUE;
+ }
+ }
+ else if (lua_type (L, 2) == LUA_TUSERDATA) {
+ t = lua_check_text (L, 2);
+
+ if (t && lua_trie_search_str (L, trie, t->start, t->len, cb)) {
found = TRUE;
}
}
}
- lua_pushboolean (L, found);
+ if (lua_type (L, 3) == LUA_TFUNCTION) {
+ lua_pushboolean (L, found);
+ }
+
return 1;
}
/***
- * @method trie:search_mime(task, cb[, caseless])
+ * @method trie:search_mime(task, cb)
* This is a helper mehthod to search pattern within text parts of a message in rspamd task
* @param {task} task object
* @param {function} cb callback called on each pattern match @see trie:match
@@ -257,6 +323,7 @@ lua_trie_search_mime (lua_State *L)
const gchar *text;
gsize len, i;
gboolean found = FALSE;
+ rspamd_multipattern_cb_t cb = lua_trie_callback;
if (trie && task) {
PTR_ARRAY_FOREACH (MESSAGE_FIELD (task, text_parts), i, part) {
@@ -264,7 +331,7 @@ lua_trie_search_mime (lua_State *L)
text = part->utf_content->data;
len = part->utf_content->len;
- if (lua_trie_search_str (L, trie, text, len) != 0) {
+ if (lua_trie_search_str (L, trie, text, len, cb) != 0) {
found = TRUE;
}
}
@@ -297,7 +364,7 @@ lua_trie_search_rawmsg (lua_State *L)
text = task->msg.begin;
len = task->msg.len;
- if (lua_trie_search_str (L, trie, text, len) != 0) {
+ if (lua_trie_search_str (L, trie, text, len, lua_trie_callback) != 0) {
found = TRUE;
}
}
@@ -335,7 +402,7 @@ lua_trie_search_rawbody (lua_State *L)
len = task->msg.len;
}
- if (lua_trie_search_str (L, trie, text, len) != 0) {
+ if (lua_trie_search_str (L, trie, text, len, lua_trie_callback) != 0) {
found = TRUE;
}
}
@@ -348,6 +415,30 @@ static gint
lua_load_trie (lua_State *L)
{
lua_newtable (L);
+
+ /* Flags */
+ lua_pushstring (L, "flags");
+ lua_newtable (L);
+
+ lua_pushinteger (L, RSPAMD_MULTIPATTERN_GLOB);
+ lua_setfield (L, -2, "glob");
+ lua_pushinteger (L, RSPAMD_MULTIPATTERN_RE);
+ lua_setfield (L, -2, "re");
+ lua_pushinteger (L, RSPAMD_MULTIPATTERN_ICASE);
+ lua_setfield (L, -2, "icase");
+ lua_pushinteger (L, RSPAMD_MULTIPATTERN_UTF8);
+ lua_setfield (L, -2, "utf8");
+ lua_pushinteger (L, RSPAMD_MULTIPATTERN_TLD);
+ lua_setfield (L, -2, "tld");
+ lua_pushinteger (L, RSPAMD_MULTIPATTERN_DOTALL);
+ lua_setfield (L, -2, "dot_all");
+ lua_pushinteger (L, RSPAMD_MULTIPATTERN_SINGLEMATCH);
+ lua_setfield (L, -2, "single_match");
+ lua_pushinteger (L, RSPAMD_MULTIPATTERN_NO_START);
+ lua_setfield (L, -2, "no_start");
+ lua_settable (L, -3);
+
+ /* Main content */
luaL_register (L, NULL, trielib_f);
return 1;
@@ -356,17 +447,7 @@ lua_load_trie (lua_State *L)
void
luaopen_trie (lua_State * L)
{
- luaL_newmetatable (L, "rspamd{trie}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{trie}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, trielib_m);
+ rspamd_lua_new_class (L, "rspamd{trie}", trielib_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_trie", lua_load_trie);
-
- lua_pop (L, 1); /* remove metatable from stack */
}
diff --git a/src/lua/lua_udp.c b/src/lua/lua_udp.c
index 94d27bf63..b72108c34 100644
--- a/src/lua/lua_udp.c
+++ b/src/lua/lua_udp.c
@@ -373,7 +373,8 @@ lua_udp_sendto (lua_State *L) {
if (lua_type (L, -1) == LUA_TSTRING) {
host = luaL_checkstring (L, -1);
- if (rspamd_parse_inet_address (&addr, host, 0)) {
+ if (rspamd_parse_inet_address (&addr,
+ host, strlen (host), RSPAMD_INET_ADDRESS_PARSE_DEFAULT)) {
if (port != 0) {
rspamd_inet_address_set_port (addr, port);
}
diff --git a/src/lua/lua_upstream.c b/src/lua/lua_upstream.c
index 3c4f3f4c3..7ba77839f 100644
--- a/src/lua/lua_upstream.c
+++ b/src/lua/lua_upstream.c
@@ -569,30 +569,10 @@ lua_load_upstream_list (lua_State * L)
void
luaopen_upstream (lua_State * L)
{
- luaL_newmetatable (L, "rspamd{upstream_list}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{upstream_list}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, upstream_list_m);
+ rspamd_lua_new_class (L, "rspamd{upstream_list}", upstream_list_m);
+ lua_pop (L, 1);
rspamd_lua_add_preload (L, "rspamd_upstream_list", lua_load_upstream_list);
- lua_pop (L, 1); /* remove metatable from stack */
-
- luaL_newmetatable (L, "rspamd{upstream}");
- lua_pushstring (L, "__index");
- lua_pushvalue (L, -2);
- lua_settable (L, -3);
-
- lua_pushstring (L, "class");
- lua_pushstring (L, "rspamd{upstream}");
- lua_rawset (L, -3);
-
- luaL_register (L, NULL, upstream_m);
-
- lua_pop (L, 1); /* remove metatable from stack */
+ rspamd_lua_new_class (L, "rspamd{upstream}", upstream_m);
+ lua_pop (L, 1);
}
diff --git a/src/lua/lua_url.c b/src/lua/lua_url.c
index b30e560c9..d21ab727f 100644
--- a/src/lua/lua_url.c
+++ b/src/lua/lua_url.c
@@ -110,7 +110,7 @@ lua_check_url (lua_State * L, gint pos)
return ud ? ((struct rspamd_lua_url *)ud) : NULL;
}
-static void
+static gboolean
lua_url_single_inserter (struct rspamd_url *url, gsize start_offset,
gsize end_offset, gpointer ud)
{
@@ -120,6 +120,8 @@ lua_url_single_inserter (struct rspamd_url *url, gsize start_offset,
lua_url = lua_newuserdata (L, sizeof (struct rspamd_lua_url));
rspamd_lua_setclass (L, "rspamd{url}", -1);
lua_url->url = url;
+
+ return TRUE;
}
/***
@@ -770,7 +772,7 @@ lua_url_init (lua_State *L)
return 0;
}
-static void
+static gboolean
lua_url_table_inserter (struct rspamd_url *url, gsize start_offset,
gsize end_offset, gpointer ud)
{
@@ -785,6 +787,8 @@ lua_url_table_inserter (struct rspamd_url *url, gsize start_offset,
lua_pushinteger (L, n + 1);
lua_pushlstring (L, url->string, url->urllen);
lua_settable (L, -3);
+
+ return TRUE;
}
@@ -881,6 +885,7 @@ lua_url_get_flags (lua_State *L)
PUSH_FLAG (RSPAMD_URL_FLAG_UNNORMALISED, "unnormalised");
PUSH_FLAG (RSPAMD_URL_FLAG_ZW_SPACES, "zw_spaces");
PUSH_FLAG (RSPAMD_URL_FLAG_DISPLAY_URL, "url_displayed");
+ PUSH_FLAG (RSPAMD_URL_FLAG_IMAGE, "image");
}
else {
return luaL_error (L, "invalid arguments");
diff --git a/src/lua/lua_util.c b/src/lua/lua_util.c
index be795bc55..0057dc472 100644
--- a/src/lua/lua_util.c
+++ b/src/lua/lua_util.c
@@ -23,7 +23,11 @@
#include "libmime/content_type.h"
#include "libmime/mime_headers.h"
#include "libutil/hash.h"
-#include "linenoise.h"
+
+#ifdef WITH_LUA_REPL
+#include "replxx.h"
+#endif
+
#include <math.h>
#include <glob.h>
#include <zlib.h>
@@ -229,6 +233,14 @@ LUA_FUNCTION_DEF (util, parse_mail_address);
*/
LUA_FUNCTION_DEF (util, strlen_utf8);
+/***
+ * @function util.lower_utf8(str)
+ * Converts utf8 string to lower case
+ * @param {string} str utf8 encoded string
+ * @return {string} lowercased utf8 string
+ */
+LUA_FUNCTION_DEF (util, lower_utf8);
+
/***
* @function util.strcasecmp(str1, str2)
@@ -632,6 +644,7 @@ static const struct luaL_reg utillib_f[] = {
LUA_INTERFACE_DEF (util, glob),
LUA_INTERFACE_DEF (util, parse_mail_address),
LUA_INTERFACE_DEF (util, strlen_utf8),
+ LUA_INTERFACE_DEF (util, lower_utf8),
LUA_INTERFACE_DEF (util, strcasecmp_ascii),
LUA_INTERFACE_DEF (util, strequal_caseless),
LUA_INTERFACE_DEF (util, get_ticks),
@@ -809,7 +822,6 @@ lua_util_config_from_ucl (lua_State *L)
cfg->lua_state = L;
cfg->rcl_obj = obj;
- cfg->cache = rspamd_symcache_new (cfg);
top = rspamd_rcl_config_init (cfg, NULL);
if (!rspamd_rcl_parse (top, cfg, cfg, cfg->cfg_pool, cfg->rcl_obj, &err)) {
@@ -1602,11 +1614,10 @@ lua_util_glob (lua_State *L)
LUA_TRACE_POINT;
const gchar *pattern;
glob_t gl;
- gint top, i, flags;
+ gint top, i, flags = 0;
top = lua_gettop (L);
memset (&gl, 0, sizeof (gl));
- flags = GLOB_NOSORT;
for (i = 1; i <= top; i ++, flags |= GLOB_APPEND) {
pattern = luaL_checkstring (L, i);
@@ -1676,21 +1687,53 @@ static gint
lua_util_strlen_utf8 (lua_State *L)
{
LUA_TRACE_POINT;
- const gchar *str, *end;
+ const gchar *str;
gsize len;
str = lua_tolstring (L, 1, &len);
if (str) {
- if (g_utf8_validate (str, len, &end)) {
- len = g_utf8_strlen (str, len);
+ gint32 i = 0, nchars = 0;
+ UChar32 uc;
+
+ while (i < len) {
+ U8_NEXT ((guint8 *) str, i, len, uc);
+ nchars ++;
}
- else if (end != NULL && end > str) {
- len = (g_utf8_strlen (str, end - str)) /* UTF part */
- + (len - (end - str)) /* raw part */;
+
+ lua_pushinteger (L, nchars);
+ }
+ else {
+ return luaL_error (L, "invalid arguments");
+ }
+
+ return 1;
+}
+
+static gint
+lua_util_lower_utf8 (lua_State *L)
+{
+ LUA_TRACE_POINT;
+ const gchar *str;
+ gchar *dst;
+ gsize len;
+ UChar32 uc;
+ UBool err = 0;
+ gint32 i = 0, j = 0;
+
+ str = lua_tolstring (L, 1, &len);
+
+ if (str) {
+ dst = g_malloc (len);
+
+ while (i < len && err == 0) {
+ U8_NEXT ((guint8 *) str, i, len, uc);
+ uc = u_tolower (uc);
+ U8_APPEND (dst, j, len, uc, err);
}
- lua_pushinteger (L, len);
+ lua_pushlstring (L, dst, j);
+ g_free (dst);
}
else {
return luaL_error (L, "invalid arguments");
@@ -2865,17 +2908,41 @@ lua_util_readline (lua_State *L)
if (lua_type (L, 1) == LUA_TSTRING) {
prompt = lua_tostring (L, 1);
}
+#ifdef WITH_LUA_REPL
+ static Replxx *rx_instance = NULL;
+
+ if (rx_instance == NULL) {
+ rx_instance = replxx_init ();
+ }
- input = linenoise (prompt);
+ input = (gchar *)replxx_input (rx_instance, prompt);
if (input) {
lua_pushstring (L, input);
- linenoiseHistoryAdd (input);
- linenoiseFree (input);
}
else {
lua_pushnil (L);
}
+#else
+ size_t linecap = 0;
+ ssize_t linelen;
+
+ fprintf (stdout, "%s ", prompt);
+
+ linelen = getline (&input, &linecap, stdin);
+
+ if (linelen > 0) {
+ if (input[linelen - 1] == '\n') {
+ linelen --;
+ }
+
+ lua_pushlstring (L, input, linelen);
+ free (input);
+ }
+ else {
+ lua_pushnil (L);
+ }
+#endif
return 1;
}
@@ -3687,11 +3754,28 @@ lua_util_unpack (lua_State *L)
Header h;
const char *fmt = luaL_checkstring(L, 1);
size_t ld;
- const char *data = luaL_checklstring (L, 2, &ld);
- size_t pos = (size_t) posrelat (luaL_optinteger (L, 3, 1), ld) - 1;
+ const char *data;
int n = 0; /* number of results */
+
+ if (lua_type (L, 2) == LUA_TUSERDATA) {
+ struct rspamd_lua_text *t = lua_check_text (L, 2);
+
+ if (!t) {
+ return luaL_error (L, "invalid arguments");
+ }
+
+ data = t->start;
+ ld = t->len;
+ }
+ else {
+ data = luaL_checklstring (L, 2, &ld);
+ }
+
+ size_t pos = (size_t) posrelat (luaL_optinteger (L, 3, 1), ld) - 1;
luaL_argcheck(L, pos <= ld, 3, "initial position out of string");
+
initheader (L, &h);
+
while (*fmt != '\0') {
int size, ntoalign;
KOption opt = getdetails (&h, pos, &fmt, &size, &ntoalign);
diff --git a/src/lua/lua_worker.c b/src/lua/lua_worker.c
index c3c9e729e..eaf0e02d7 100644
--- a/src/lua/lua_worker.c
+++ b/src/lua/lua_worker.c
@@ -25,6 +25,7 @@
#endif
#include <sys/wait.h>
+#include <src/libserver/rspamd_control.h>
/***
* @module rspamd_worker
@@ -42,6 +43,7 @@ LUA_FUNCTION_DEF (worker, is_scanner);
LUA_FUNCTION_DEF (worker, is_primary_controller);
LUA_FUNCTION_DEF (worker, spawn_process);
LUA_FUNCTION_DEF (worker, get_mem_stats);
+LUA_FUNCTION_DEF (worker, add_control_handler);
const luaL_reg worker_reg[] = {
LUA_INTERFACE_DEF (worker, get_name),
@@ -53,6 +55,7 @@ const luaL_reg worker_reg[] = {
LUA_INTERFACE_DEF (worker, is_scanner),
LUA_INTERFACE_DEF (worker, is_primary_controller),
LUA_INTERFACE_DEF (worker, get_mem_stats),
+ LUA_INTERFACE_DEF (worker, add_control_handler),
{"__tostring", rspamd_lua_class_tostring},
{NULL, NULL}
};
@@ -240,6 +243,211 @@ lua_worker_is_primary_controller (lua_State *L)
return 1;
}
+struct rspamd_control_cbdata {
+ lua_State *L;
+ rspamd_mempool_t *pool;
+ struct rspamd_worker *w;
+ struct rspamd_config *cfg;
+ struct ev_loop *event_loop;
+ struct rspamd_async_session *session;
+ enum rspamd_control_type cmd;
+ gint cbref;
+ gint fd;
+};
+
+static gboolean
+lua_worker_control_fin_session (void *ud)
+{
+ struct rspamd_control_reply rep;
+ struct rspamd_control_cbdata *cbd = (struct rspamd_control_cbdata *)ud;
+ rspamd_mempool_t *pool;
+ lua_State *L;
+
+ L = cbd->L;
+ pool = cbd->pool;
+
+ memset (&rep, 0, sizeof (rep));
+ rep.type = cbd->cmd;
+
+ if (write (cbd->fd, &rep, sizeof (rep)) != sizeof (rep)) {
+ msg_err_pool ("cannot write reply to the control socket: %s",
+ strerror (errno));
+ }
+
+ return TRUE;
+}
+
+static void
+lua_worker_control_session_dtor (void *ud)
+{
+ struct rspamd_control_cbdata *cbd = (struct rspamd_control_cbdata *)ud;
+
+ rspamd_mempool_delete (cbd->pool);
+}
+
+static gboolean
+lua_worker_control_handler (struct rspamd_main *rspamd_main,
+ struct rspamd_worker *worker,
+ gint fd,
+ gint attached_fd,
+ struct rspamd_control_command *cmd,
+ gpointer ud)
+{
+ struct rspamd_async_session *session, **psession;
+ struct rspamd_control_cbdata *cbd = (struct rspamd_control_cbdata *)ud;
+ rspamd_mempool_t *pool;
+ lua_State *L;
+ gint err_idx, status;
+
+ L = cbd->L;
+ pool = cbd->pool;
+ session = rspamd_session_create (cbd->pool,
+ lua_worker_control_fin_session,
+ NULL,
+ lua_worker_control_session_dtor,
+ cbd);
+ cbd->session = session;
+ cbd->fd = fd;
+
+ lua_pushcfunction (L, &rspamd_lua_traceback);
+ err_idx = lua_gettop (L);
+ lua_rawgeti (L, LUA_REGISTRYINDEX, cbd->cbref);
+ psession = lua_newuserdata (L, sizeof (*psession));
+ rspamd_lua_setclass (L, "rspamd{session}", -1);
+ *psession = session;
+
+ /* Command name */
+ lua_pushstring (L, rspamd_control_command_to_string (cmd->type));
+
+ /* Command's extras */
+ lua_newtable (L);
+
+ switch (cmd->type) {
+ case RSPAMD_CONTROL_CHILD_CHANGE:
+ lua_pushinteger (L, cmd->cmd.child_change.pid);
+ lua_setfield (L, -2, "pid");
+ switch (cmd->cmd.child_change.what) {
+ case rspamd_child_offline:
+ lua_pushstring (L, "offline");
+ lua_setfield (L, -2, "what");
+ break;
+ case rspamd_child_online:
+ lua_pushstring (L, "online");
+ lua_setfield (L, -2, "what");
+ break;
+ case rspamd_child_terminated:
+ lua_pushstring (L, "terminated");
+ lua_setfield (L, -2, "what");
+ status = cmd->cmd.child_change.additional;
+
+ if (WIFEXITED (status)) {
+ lua_pushinteger (L, WEXITSTATUS (status));
+ lua_setfield (L, -2, "exit_code");
+ }
+
+ if (WIFSIGNALED (status)) {
+ lua_pushinteger (L, WTERMSIG (status));
+ lua_setfield (L, -2, "signal");
+#ifdef WCOREDUMP
+ lua_pushboolean (L, WCOREDUMP (status));
+ lua_setfield (L, -2, "core");
+#endif
+ }
+ break;
+ }
+ break;
+ case RSPAMD_CONTROL_MONITORED_CHANGE:
+ lua_pushinteger (L, cmd->cmd.monitored_change.sender);
+ lua_setfield (L, -2, "sender");
+ lua_pushboolean (L, cmd->cmd.monitored_change.alive);
+ lua_setfield (L, -2, "alive");
+ lua_pushlstring (L, cmd->cmd.monitored_change.tag,
+ sizeof (cmd->cmd.monitored_change.tag));
+ lua_setfield (L, -2, "tag");
+ break;
+ case RSPAMD_CONTROL_HYPERSCAN_LOADED:
+ lua_pushstring (L, cmd->cmd.hs_loaded.cache_dir);
+ lua_setfield (L, -2, "cache_dir");
+ lua_pushboolean (L, cmd->cmd.hs_loaded.forced);
+ lua_setfield (L, -2, "forced");
+ break;
+ case RSPAMD_CONTROL_STAT:
+ case RSPAMD_CONTROL_RELOAD:
+ case RSPAMD_CONTROL_RERESOLVE:
+ case RSPAMD_CONTROL_RECOMPILE:
+ case RSPAMD_CONTROL_LOG_PIPE:
+ case RSPAMD_CONTROL_FUZZY_STAT:
+ case RSPAMD_CONTROL_FUZZY_SYNC:
+ default:
+ break;
+ }
+
+ if (lua_pcall (L, 3, 0, err_idx) != 0) {
+ msg_err_pool ("cannot init lua parser script: %s", lua_tostring (L, -1));
+ lua_settop (L, err_idx - 1);
+
+ struct rspamd_control_reply rep;
+
+ memset (&rep, 0, sizeof (rep));
+ rep.type = cbd->cmd;
+ rep.reply.monitored_change.status = -1;
+
+ if (write (fd, &rep, sizeof (rep)) != sizeof (rep)) {
+ msg_err_pool ("cannot write reply to the control socket: %s",
+ strerror (errno));
+ }
+
+ rspamd_session_destroy (session);
+ }
+ else {
+ lua_settop (L, err_idx - 1);
+ rspamd_session_pending (session);
+ }
+
+ return TRUE;
+}
+
+static gint
+lua_worker_add_control_handler (lua_State *L)
+{
+ struct rspamd_worker *w = lua_check_worker (L, 1);
+ struct rspamd_config *cfg = lua_check_config (L, 2);
+ struct ev_loop *event_loop = lua_check_ev_base (L, 3);
+ const gchar *cmd_name = luaL_checkstring (L, 4);
+ enum rspamd_control_type cmd;
+ struct rspamd_control_cbdata *cbd;
+
+ if (w && cfg && event_loop && cmd_name && lua_isfunction (L, 5)) {
+ cmd = rspamd_control_command_from_string (cmd_name);
+
+ if (cmd == RSPAMD_CONTROL_MAX) {
+ return luaL_error (L, "invalid command type: %s", cmd_name);
+ }
+
+ rspamd_mempool_t *pool = rspamd_mempool_new (
+ rspamd_mempool_suggest_size (), "lua_control");
+ cbd = rspamd_mempool_alloc0 (pool, sizeof (*cbd));
+ cbd->pool = pool;
+ cbd->event_loop = event_loop;
+ cbd->w = w;
+ cbd->cfg = cfg;
+ cbd->cmd = cmd;
+ cbd->L = L;
+ /* Refcount callback */
+ lua_pushvalue (L, 5);
+ cbd->cbref = luaL_ref (L, LUA_REGISTRYINDEX);
+
+ rspamd_control_worker_add_cmd_handler (w, cmd, lua_worker_control_handler,
+ cbd);
+ }
+ else {
+ return luaL_error (L, "invalid arguments, need worker, cfg, "
+ "ev_loop, cmd_name and callback function");
+ }
+
+ return 0;
+}
+
#ifdef WITH_JEMALLOC
static void
lua_worker_jemalloc_stats_cb (void *ud, const char *msg)