123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287 |
- /*
- * Copyright (c) 2009-2012, Vsevolod Stakhov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
- #include "lua_common.h"
- #include "expressions.h"
- #include "map.h"
- #include "message.h"
- #include "radix.h"
- #include "trie.h"
- #include "classifiers/classifiers.h"
-
- /* Config file methods */
- LUA_FUNCTION_DEF (config, get_module_opt);
- LUA_FUNCTION_DEF (config, get_all_opt);
- LUA_FUNCTION_DEF (config, get_mempool);
- LUA_FUNCTION_DEF (config, register_function);
- LUA_FUNCTION_DEF (config, add_radix_map);
- LUA_FUNCTION_DEF (config, add_hash_map);
- LUA_FUNCTION_DEF (config, add_kv_map);
- LUA_FUNCTION_DEF (config, add_map);
- LUA_FUNCTION_DEF (config, get_classifier);
- LUA_FUNCTION_DEF (config, register_symbol);
- LUA_FUNCTION_DEF (config, register_symbols);
- LUA_FUNCTION_DEF (config, register_virtual_symbol);
- LUA_FUNCTION_DEF (config, register_callback_symbol);
- LUA_FUNCTION_DEF (config, register_callback_symbol_priority);
- LUA_FUNCTION_DEF (config, register_pre_filter);
- LUA_FUNCTION_DEF (config, register_post_filter);
- LUA_FUNCTION_DEF (config, register_module_option);
- LUA_FUNCTION_DEF (config, get_api_version);
- LUA_FUNCTION_DEF (config, get_key);
- LUA_FUNCTION_DEF (config, newindex);
-
- static const struct luaL_reg configlib_m[] = {
- LUA_INTERFACE_DEF (config, get_module_opt),
- LUA_INTERFACE_DEF (config, get_mempool),
- LUA_INTERFACE_DEF (config, get_all_opt),
- LUA_INTERFACE_DEF (config, register_function),
- LUA_INTERFACE_DEF (config, add_radix_map),
- LUA_INTERFACE_DEF (config, add_hash_map),
- LUA_INTERFACE_DEF (config, add_kv_map),
- LUA_INTERFACE_DEF (config, add_map),
- LUA_INTERFACE_DEF (config, get_classifier),
- LUA_INTERFACE_DEF (config, register_symbol),
- LUA_INTERFACE_DEF (config, register_symbols),
- LUA_INTERFACE_DEF (config, register_virtual_symbol),
- LUA_INTERFACE_DEF (config, register_callback_symbol),
- LUA_INTERFACE_DEF (config, register_callback_symbol_priority),
- LUA_INTERFACE_DEF (config, register_module_option),
- LUA_INTERFACE_DEF (config, register_pre_filter),
- LUA_INTERFACE_DEF (config, register_post_filter),
- LUA_INTERFACE_DEF (config, get_api_version),
- LUA_INTERFACE_DEF (config, get_key),
- {"__tostring", rspamd_lua_class_tostring},
- {"__newindex", lua_config_newindex},
- {NULL, NULL}
- };
-
-
- /* Radix tree */
- LUA_FUNCTION_DEF (radix, get_key);
-
- static const struct luaL_reg radixlib_m[] = {
- LUA_INTERFACE_DEF (radix, get_key),
- {"__tostring", rspamd_lua_class_tostring},
- {NULL, NULL}
- };
-
- /* Hash table */
- LUA_FUNCTION_DEF (hash_table, get_key);
-
- static const struct luaL_reg hashlib_m[] = {
- LUA_INTERFACE_DEF (hash_table, get_key),
- {"__tostring", rspamd_lua_class_tostring},
- {NULL, NULL}
- };
-
- /* Suffix trie */
- LUA_FUNCTION_DEF (trie, create);
- LUA_FUNCTION_DEF (trie, add_pattern);
- LUA_FUNCTION_DEF (trie, search_text);
- LUA_FUNCTION_DEF (trie, search_task);
-
- static const struct luaL_reg trielib_m[] = {
- LUA_INTERFACE_DEF (trie, add_pattern),
- LUA_INTERFACE_DEF (trie, search_text),
- LUA_INTERFACE_DEF (trie, search_task),
- {"__tostring", rspamd_lua_class_tostring},
- {NULL, NULL}
- };
- static const struct luaL_reg trielib_f[] = {
- LUA_INTERFACE_DEF (trie, create),
- {NULL, NULL}
- };
-
- static struct rspamd_config *
- lua_check_config (lua_State * L)
- {
- void *ud = luaL_checkudata (L, 1, "rspamd{config}");
- luaL_argcheck (L, ud != NULL, 1, "'config' expected");
- return ud ? *((struct rspamd_config **)ud) : NULL;
- }
-
- static radix_tree_t *
- lua_check_radix (lua_State * L)
- {
- void *ud = luaL_checkudata (L, 1, "rspamd{radix}");
- luaL_argcheck (L, ud != NULL, 1, "'radix' expected");
- return ud ? **((radix_tree_t ***)ud) : NULL;
- }
-
- static GHashTable *
- lua_check_hash_table (lua_State * L)
- {
- void *ud = luaL_checkudata (L, 1, "rspamd{hash_table}");
- luaL_argcheck (L, ud != NULL, 1, "'hash_table' expected");
- return ud ? **((GHashTable ***)ud) : NULL;
- }
-
- static rspamd_trie_t *
- lua_check_trie (lua_State * L)
- {
- void *ud = luaL_checkudata (L, 1, "rspamd{trie}");
-
- luaL_argcheck (L, ud != NULL, 1, "'trie' expected");
- return ud ? *((rspamd_trie_t **)ud) : NULL;
- }
-
- /*** Config functions ***/
- static gint
- lua_config_get_api_version (lua_State *L)
- {
- lua_pushinteger (L, RSPAMD_LUA_API_VERSION);
- return 1;
- }
-
- static gint
- lua_config_get_module_opt (lua_State * L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- const gchar *mname, *optname;
- const ucl_object_t *obj;
-
- if (cfg) {
- mname = luaL_checkstring (L, 2);
- optname = luaL_checkstring (L, 3);
-
- if (mname && optname) {
- obj = rspamd_config_get_module_opt (cfg, mname, optname);
- if (obj) {
- return ucl_object_push_lua (L, obj, TRUE);
- }
- }
- }
- lua_pushnil (L);
- return 1;
- }
-
- static int
- lua_config_get_mempool (lua_State * L)
- {
- rspamd_mempool_t **ppool;
- struct rspamd_config *cfg = lua_check_config (L);
-
- if (cfg != NULL) {
- ppool = lua_newuserdata (L, sizeof (rspamd_mempool_t *));
- rspamd_lua_setclass (L, "rspamd{mempool}", -1);
- *ppool = cfg->cfg_pool;
- }
- return 1;
- }
-
- static gint
- lua_config_get_all_opt (lua_State * L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- const gchar *mname;
- const ucl_object_t *obj;
-
- if (cfg) {
- mname = luaL_checkstring (L, 2);
-
- if (mname) {
- obj = ucl_obj_get_key (cfg->rcl_obj, mname);
- if (obj != NULL) {
- return ucl_object_push_lua (L, obj, TRUE);
- }
- }
- }
- lua_pushnil (L);
- return 1;
- }
-
-
- static gint
- lua_config_get_classifier (lua_State * L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- struct rspamd_classifier_config *clc = NULL, **pclc = NULL;
- const gchar *name;
- GList *cur;
-
- if (cfg) {
- name = luaL_checkstring (L, 2);
-
- cur = g_list_first (cfg->classifiers);
- while (cur) {
- clc = cur->data;
- if (g_ascii_strcasecmp (clc->classifier->name, name) == 0) {
- pclc = &clc;
- break;
- }
- cur = g_list_next (cur);
- }
- if (pclc) {
- pclc = lua_newuserdata (L,
- sizeof (struct rspamd_classifier_config *));
- rspamd_lua_setclass (L, "rspamd{classifier}", -1);
- *pclc = clc;
- return 1;
- }
- }
-
- lua_pushnil (L);
- return 1;
-
- }
-
- struct lua_callback_data {
- union {
- gchar *name;
- gint ref;
- } callback;
- gboolean cb_is_ref;
- lua_State *L;
- gchar *symbol;
- };
-
- /*
- * Unref symbol if it is local reference
- */
- static void
- lua_destroy_cfg_symbol (gpointer ud)
- {
- struct lua_callback_data *cd = ud;
-
- /* Unref callback */
- if (cd->cb_is_ref) {
- luaL_unref (cd->L, LUA_REGISTRYINDEX, cd->callback.ref);
- }
- }
-
- static gboolean
- lua_config_function_callback (struct rspamd_task *task,
- GList *args,
- void *user_data)
- {
- struct lua_callback_data *cd = user_data;
- struct rspamd_task **ptask;
- gint i = 1;
- struct expression_argument *arg;
- GList *cur;
- gboolean res = FALSE;
-
- if (cd->cb_is_ref) {
- lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->callback.ref);
- }
- else {
- lua_getglobal (cd->L, cd->callback.name);
- }
- ptask = lua_newuserdata (cd->L, sizeof (struct rspamd_task *));
- rspamd_lua_setclass (cd->L, "rspamd{task}", -1);
- *ptask = task;
- /* Now push all arguments */
- cur = args;
- while (cur) {
- arg = get_function_arg (cur->data, task, TRUE);
- lua_pushstring (cd->L, (const gchar *)arg->data);
- cur = g_list_next (cur);
- i++;
- }
-
- if (lua_pcall (cd->L, i, 1, 0) != 0) {
- msg_info ("error processing symbol %s: call to %s failed: %s",
- cd->symbol,
- cd->cb_is_ref ? "local function" :
- cd->callback.name,
- lua_tostring (cd->L, -1));
- }
- else {
- if (lua_isboolean (cd->L, 1)) {
- res = lua_toboolean (cd->L, 1);
- }
- lua_pop (cd->L, 1);
- }
-
- return res;
- }
-
- static gint
- lua_config_register_function (lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- gchar *name;
- struct lua_callback_data *cd;
-
- if (cfg) {
- name = rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L, 2));
- cd =
- rspamd_mempool_alloc (cfg->cfg_pool,
- sizeof (struct lua_callback_data));
-
- if (lua_type (L, 3) == LUA_TSTRING) {
- cd->callback.name = rspamd_mempool_strdup (cfg->cfg_pool,
- luaL_checkstring (L, 3));
- cd->cb_is_ref = FALSE;
- }
- else {
- lua_pushvalue (L, 3);
- /* Get a reference */
- cd->callback.ref = luaL_ref (L, LUA_REGISTRYINDEX);
- cd->cb_is_ref = TRUE;
- }
- if (name) {
- cd->L = L;
- cd->symbol = name;
- register_expression_function (name, lua_config_function_callback,
- cd);
- }
- rspamd_mempool_add_destructor (cfg->cfg_pool,
- (rspamd_mempool_destruct_t)lua_destroy_cfg_symbol,
- cd);
- }
- return 1;
- }
-
- static gint
- lua_config_register_module_option (lua_State *L)
- {
- return 0;
- }
-
- void
- rspamd_lua_call_post_filters (struct rspamd_task *task)
- {
- struct lua_callback_data *cd;
- struct rspamd_task **ptask;
- GList *cur;
-
- cur = task->cfg->post_filters;
- while (cur) {
- cd = cur->data;
- if (cd->cb_is_ref) {
- lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->callback.ref);
- }
- else {
- lua_getglobal (cd->L, cd->callback.name);
- }
- ptask = lua_newuserdata (cd->L, sizeof (struct rspamd_task *));
- rspamd_lua_setclass (cd->L, "rspamd{task}", -1);
- *ptask = task;
-
- if (lua_pcall (cd->L, 1, 0, 0) != 0) {
- msg_info ("call to %s failed: %s",
- cd->cb_is_ref ? "local function" :
- cd->callback.name,
- lua_tostring (cd->L, -1));
- }
- cur = g_list_next (cur);
- }
- }
-
- static gint
- lua_config_register_post_filter (lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- struct lua_callback_data *cd;
-
- if (cfg) {
- cd =
- rspamd_mempool_alloc (cfg->cfg_pool,
- sizeof (struct lua_callback_data));
- if (lua_type (L, 2) == LUA_TSTRING) {
- cd->callback.name = rspamd_mempool_strdup (cfg->cfg_pool,
- luaL_checkstring (L, 2));
- cd->cb_is_ref = FALSE;
- }
- else {
- lua_pushvalue (L, 2);
- /* Get a reference */
- cd->callback.ref = luaL_ref (L, LUA_REGISTRYINDEX);
- cd->cb_is_ref = TRUE;
- }
- cd->L = L;
- cfg->post_filters = g_list_prepend (cfg->post_filters, cd);
- rspamd_mempool_add_destructor (cfg->cfg_pool,
- (rspamd_mempool_destruct_t)lua_destroy_cfg_symbol,
- cd);
- }
- return 1;
- }
-
- void
- rspamd_lua_call_pre_filters (struct rspamd_task *task)
- {
- struct lua_callback_data *cd;
- struct rspamd_task **ptask;
- GList *cur;
-
- cur = task->cfg->pre_filters;
- while (cur) {
- cd = cur->data;
- if (cd->cb_is_ref) {
- lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->callback.ref);
- }
- else {
- lua_getglobal (cd->L, cd->callback.name);
- }
- ptask = lua_newuserdata (cd->L, sizeof (struct rspamd_task *));
- rspamd_lua_setclass (cd->L, "rspamd{task}", -1);
- *ptask = task;
-
- if (lua_pcall (cd->L, 1, 0, 0) != 0) {
- msg_info ("call to %s failed: %s",
- cd->cb_is_ref ? "local function" :
- cd->callback.name,
- lua_tostring (cd->L, -1));
- }
- cur = g_list_next (cur);
- }
- }
-
- static gint
- lua_config_register_pre_filter (lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- struct lua_callback_data *cd;
-
- if (cfg) {
- cd =
- rspamd_mempool_alloc (cfg->cfg_pool,
- sizeof (struct lua_callback_data));
- if (lua_type (L, 2) == LUA_TSTRING) {
- cd->callback.name = rspamd_mempool_strdup (cfg->cfg_pool,
- luaL_checkstring (L, 2));
- cd->cb_is_ref = FALSE;
- }
- else {
- lua_pushvalue (L, 2);
- /* Get a reference */
- cd->callback.ref = luaL_ref (L, LUA_REGISTRYINDEX);
- cd->cb_is_ref = TRUE;
- }
- cd->L = L;
- cfg->pre_filters = g_list_prepend (cfg->pre_filters, cd);
- rspamd_mempool_add_destructor (cfg->cfg_pool,
- (rspamd_mempool_destruct_t)lua_destroy_cfg_symbol,
- cd);
- }
- return 1;
- }
-
- static gint
- lua_config_add_radix_map (lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- const gchar *map_line, *description;
- radix_tree_t **r, ***ud;
-
- if (cfg) {
- map_line = luaL_checkstring (L, 2);
- description = lua_tostring (L, 3);
- r = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (radix_tree_t *));
- *r = radix_tree_create ();
- if (!add_map (cfg, map_line, description, read_radix_list,
- fin_radix_list, (void **)r)) {
- msg_warn ("invalid radix map %s", map_line);
- radix_tree_free (*r);
- lua_pushnil (L);
- return 1;
- }
- ud = lua_newuserdata (L, sizeof (radix_tree_t *));
- *ud = r;
- rspamd_lua_setclass (L, "rspamd{radix}", -1);
-
- return 1;
- }
-
- lua_pushnil (L);
- return 1;
-
- }
-
- static gint
- lua_config_add_hash_map (lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- const gchar *map_line, *description;
- GHashTable **r, ***ud;
-
- if (cfg) {
- map_line = luaL_checkstring (L, 2);
- description = lua_tostring (L, 3);
- r = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (GHashTable *));
- *r = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal);
- if (!add_map (cfg, map_line, description, read_host_list, fin_host_list,
- (void **)r)) {
- msg_warn ("invalid hash map %s", map_line);
- g_hash_table_destroy (*r);
- lua_pushnil (L);
- return 1;
- }
- rspamd_mempool_add_destructor (cfg->cfg_pool,
- (rspamd_mempool_destruct_t)g_hash_table_destroy,
- *r);
- ud = lua_newuserdata (L, sizeof (GHashTable *));
- *ud = r;
- rspamd_lua_setclass (L, "rspamd{hash_table}", -1);
-
- return 1;
- }
-
- lua_pushnil (L);
- return 1;
-
- }
-
- static gint
- lua_config_add_kv_map (lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- const gchar *map_line, *description;
- GHashTable **r, ***ud;
-
- if (cfg) {
- map_line = luaL_checkstring (L, 2);
- description = lua_tostring (L, 3);
- r = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (GHashTable *));
- *r = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal);
- if (!add_map (cfg, map_line, description, read_kv_list, fin_kv_list,
- (void **)r)) {
- msg_warn ("invalid hash map %s", map_line);
- g_hash_table_destroy (*r);
- lua_pushnil (L);
- return 1;
- }
- rspamd_mempool_add_destructor (cfg->cfg_pool,
- (rspamd_mempool_destruct_t)g_hash_table_destroy,
- *r);
- ud = lua_newuserdata (L, sizeof (GHashTable *));
- *ud = r;
- rspamd_lua_setclass (L, "rspamd{hash_table}", -1);
-
- return 1;
- }
-
- lua_pushnil (L);
- return 1;
-
- }
-
- static gint
- lua_config_get_key (lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- const gchar *name;
- size_t namelen;
- const ucl_object_t *val;
-
- name = luaL_checklstring(L, 2, &namelen);
- if (name && cfg) {
- val = ucl_object_find_keyl(cfg->rcl_obj, name, namelen);
- if (val != NULL) {
- ucl_object_push_lua (L, val, val->type != UCL_ARRAY);
- }
- else {
- lua_pushnil (L);
- }
- }
- else {
- lua_pushnil (L);
- }
-
- return 1;
- }
-
- static void
- lua_metric_symbol_callback (struct rspamd_task *task, gpointer ud)
- {
- struct lua_callback_data *cd = ud;
- struct rspamd_task **ptask;
- gint level = lua_gettop (cd->L), nresults;
-
- if (cd->cb_is_ref) {
- lua_rawgeti (cd->L, LUA_REGISTRYINDEX, cd->callback.ref);
- }
- else {
- lua_getglobal (cd->L, cd->callback.name);
- }
- ptask = lua_newuserdata (cd->L, sizeof (struct rspamd_task *));
- rspamd_lua_setclass (cd->L, "rspamd{task}", -1);
- *ptask = task;
-
- if (lua_pcall (cd->L, 1, LUA_MULTRET, 0) != 0) {
- msg_info ("call to (%s)%s failed: %s", cd->symbol,
- cd->cb_is_ref ? "local function" : cd->callback.name,
- lua_tostring (cd->L, -1));
- }
-
- nresults = lua_gettop (cd->L) - level;
- if (nresults >= 1) {
- /* Function returned boolean, so maybe we need to insert result? */
- gboolean res;
- GList *opts = NULL;
- gint i;
- gdouble flag = 1.0;
-
- if (lua_type (cd->L, level + 1) == LUA_TBOOLEAN) {
- res = lua_toboolean (cd->L, level + 1);
- if (res) {
- gint first_opt = 2;
-
- if (lua_type (cd->L, level + 2) == LUA_TNUMBER) {
- flag = lua_tonumber (cd->L, level + 2);
- /* Shift opt index */
- first_opt = 3;
- }
-
- for (i = lua_gettop (cd->L); i >= level + first_opt; i --) {
- if (lua_type (cd->L, i) == LUA_TSTRING) {
- const char *opt = lua_tostring (cd->L, i);
-
- opts = g_list_prepend (opts,
- rspamd_mempool_strdup (task->task_pool, opt));
- }
- }
- insert_result (task, cd->symbol, flag, opts);
- }
- }
- lua_pop (cd->L, nresults);
- }
- }
-
- static void
- rspamd_register_symbol_fromlua (lua_State *L,
- struct rspamd_config *cfg,
- const gchar *name,
- gint ref,
- gdouble weight,
- gint priority,
- enum rspamd_symbol_type type)
- {
- struct lua_callback_data *cd;
-
- cd = rspamd_mempool_alloc0 (cfg->cfg_pool,
- sizeof (struct lua_callback_data));
- cd->cb_is_ref = TRUE;
- cd->callback.ref = ref;
- cd->L = L;
- if (name) {
- cd->symbol = rspamd_mempool_strdup (cfg->cfg_pool, name);
- }
-
- register_symbol_common (&cfg->cache,
- name,
- weight,
- priority,
- lua_metric_symbol_callback,
- cd,
- type);
- rspamd_mempool_add_destructor (cfg->cfg_pool,
- (rspamd_mempool_destruct_t)lua_destroy_cfg_symbol,
- cd);
- }
-
- static gint
- lua_config_register_symbol (lua_State * L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- gchar *name;
- double weight;
-
- if (cfg) {
- name = rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L, 2));
- weight = luaL_checknumber (L, 3);
-
- if (lua_type (L, 4) == LUA_TSTRING) {
- lua_getglobal (L, luaL_checkstring (L, 4));
- }
- else {
- lua_pushvalue (L, 4);
- }
- if (name) {
- rspamd_register_symbol_fromlua (L,
- cfg,
- name,
- luaL_ref (L, LUA_REGISTRYINDEX),
- weight,
- 0,
- SYMBOL_TYPE_NORMAL);
- }
- }
-
- return 0;
- }
-
- static gint
- lua_config_register_symbols (lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- gint i, top, idx;
- gchar *sym;
- gdouble weight = 1.0;
-
- if (lua_gettop (L) < 3) {
- msg_err ("not enough arguments to register a function");
- return 0;
- }
- if (cfg) {
- if (lua_type (L, 2) == LUA_TSTRING) {
- lua_getglobal (L, luaL_checkstring (L, 2));
- }
- else {
- lua_pushvalue (L, 2);
- }
- idx = luaL_ref (L, LUA_REGISTRYINDEX);
-
- if (lua_type (L, 3) == LUA_TNUMBER) {
- weight = lua_tonumber (L, 3);
- top = 4;
- }
- else {
- top = 3;
- }
- sym = rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L, top));
- rspamd_register_symbol_fromlua (L,
- cfg,
- sym,
- idx,
- weight,
- 0,
- SYMBOL_TYPE_NORMAL);
- for (i = top; i < lua_gettop (L); i++) {
- sym =
- rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L,
- i + 1));
- register_virtual_symbol (&cfg->cache, sym, weight);
- }
- }
-
- return 0;
- }
-
- static gint
- lua_config_register_virtual_symbol (lua_State * L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- gchar *name;
- double weight;
-
- if (cfg) {
- name = rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L, 2));
- weight = luaL_checknumber (L, 3);
- if (name) {
- register_virtual_symbol (&cfg->cache, name, weight);
- }
- }
- return 0;
- }
-
- static gint
- lua_config_register_callback_symbol (lua_State * L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- gchar *name;
- double weight;
-
- if (cfg) {
- name = rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L, 2));
- weight = luaL_checknumber (L, 3);
-
- if (lua_type (L, 4) == LUA_TSTRING) {
- lua_getglobal (L, luaL_checkstring (L, 4));
- }
- else {
- lua_pushvalue (L, 4);
- }
- if (name) {
- rspamd_register_symbol_fromlua (L,
- cfg,
- name,
- luaL_ref (L, LUA_REGISTRYINDEX),
- weight,
- 0,
- SYMBOL_TYPE_CALLBACK);
- }
- }
-
- return 0;
- }
-
- static gint
- lua_config_register_callback_symbol_priority (lua_State * L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- gchar *name;
- double weight;
- gint priority;
-
- if (cfg) {
- name = rspamd_mempool_strdup (cfg->cfg_pool, luaL_checkstring (L, 2));
- weight = luaL_checknumber (L, 3);
- priority = luaL_checknumber (L, 4);
-
- if (lua_type (L, 5) == LUA_TSTRING) {
- lua_getglobal (L, luaL_checkstring (L, 5));
- }
- else {
- lua_pushvalue (L, 5);
- }
- if (name) {
- rspamd_register_symbol_fromlua (L,
- cfg,
- name,
- luaL_ref (L, LUA_REGISTRYINDEX),
- weight,
- priority,
- SYMBOL_TYPE_CALLBACK);
- }
- }
-
- return 0;
- }
-
-
- static gint
- lua_config_newindex (lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- const gchar *name;
-
- name = luaL_checkstring (L, 2);
-
- if (name != NULL && lua_gettop (L) > 2) {
- if (lua_type (L, 3) == LUA_TFUNCTION) {
- /* Normal symbol from just a function */
- lua_pushvalue (L, 3);
- rspamd_register_symbol_fromlua (L,
- cfg,
- name,
- luaL_ref (L, LUA_REGISTRYINDEX),
- 1.0,
- 0,
- SYMBOL_TYPE_NORMAL);
- }
- else if (lua_type (L, 3) == LUA_TTABLE) {
- gint type = SYMBOL_TYPE_NORMAL, priority = 0, idx;
- gdouble weight = 1.0;
- const char *type_str;
-
- /*
- * Table can have the following attributes:
- * "callback" - should be a callback function
- * "weight" - optional weight
- * "priority" - optional priority
- * "type" - optional type (normal, virtual, callback)
- */
- lua_pushstring (L, "callback");
- lua_gettable (L, -2);
-
- if (lua_type (L, -1) != LUA_TFUNCTION) {
- lua_pop (L, 1);
- msg_info ("cannot find callback definition for %s", name);
- return 0;
- }
- idx = luaL_ref (L, LUA_REGISTRYINDEX);
-
- /* Optional fields */
- lua_pushstring (L, "weight");
- lua_gettable (L, -2);
-
- if (lua_type (L, -1) == LUA_TNUMBER) {
- weight = lua_tonumber (L, -1);
- }
- lua_pop (L, 1);
-
- lua_pushstring (L, "priority");
- lua_gettable (L, -2);
-
- if (lua_type (L, -1) == LUA_TNUMBER) {
- priority = lua_tonumber (L, -1);
- }
- lua_pop (L, 1);
-
- lua_pushstring (L, "type");
- lua_gettable (L, -2);
-
- if (lua_type (L, -1) == LUA_TSTRING) {
- type_str = lua_tostring (L, -1);
- if (strcmp (type_str, "normal") == 0) {
- type = SYMBOL_TYPE_NORMAL;
- }
- else if (strcmp (type_str, "virtual") == 0) {
- type = SYMBOL_TYPE_VIRTUAL;
- }
- else if (strcmp (type_str, "callback") == 0) {
- type = SYMBOL_TYPE_CALLBACK;
- }
- else {
- msg_info ("unknown type: %s", type_str);
- }
-
- }
- lua_pop (L, 1);
-
- rspamd_register_symbol_fromlua (L,
- cfg,
- name,
- idx,
- weight,
- priority,
- type);
- }
- }
-
- return 0;
- }
-
- struct lua_map_callback_data {
- lua_State *L;
- gint ref;
- GString *data;
- };
-
- static gchar *
- lua_map_read (rspamd_mempool_t *pool, gchar *chunk, gint len,
- struct map_cb_data *data)
- {
- struct lua_map_callback_data *cbdata, *old;
-
- if (data->cur_data == NULL) {
- cbdata = g_slice_alloc0 (sizeof (*cbdata));
- old = (struct lua_map_callback_data *)data->prev_data;
- cbdata->L = old->L;
- cbdata->ref = old->ref;
- data->cur_data = cbdata;
- }
- else {
- cbdata = (struct lua_map_callback_data *)data->cur_data;
- }
-
- if (cbdata->data == NULL) {
- cbdata->data = g_string_new_len (chunk, len);
- }
- else {
- g_string_append_len (cbdata->data, chunk, len);
- }
-
- return NULL;
- }
-
- void
- lua_map_fin (rspamd_mempool_t * pool, struct map_cb_data *data)
- {
- struct lua_map_callback_data *cbdata, *old;
-
- if (data->prev_data) {
- /* Cleanup old data */
- old = (struct lua_map_callback_data *)data->prev_data;
- if (old->data) {
- g_string_free (old->data, TRUE);
- }
- g_slice_free1 (sizeof (*old), old);
- data->prev_data = NULL;
- }
-
- if (data->cur_data) {
- cbdata = (struct lua_map_callback_data *)data->cur_data;
- }
- else {
- msg_err ("no data read for map");
- return;
- }
-
- if (cbdata->data != NULL && cbdata->data->len != 0) {
- lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->ref);
- lua_pushlstring (cbdata->L, cbdata->data->str, cbdata->data->len);
-
- if (lua_pcall (cbdata->L, 1, 0, 0) != 0) {
- msg_info ("call to %s failed: %s", "local function",
- lua_tostring (cbdata->L, -1));
- }
- }
- }
-
- static gint
- lua_config_add_map (lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config (L);
- const gchar *map_line, *description;
- struct lua_map_callback_data *cbdata, **pcbdata;
- int cbidx;
-
- if (cfg) {
- map_line = luaL_checkstring (L, 2);
-
- if (lua_gettop (L) == 4) {
- description = lua_tostring (L, 3);
- cbidx = 4;
- }
- else {
- description = NULL;
- cbidx = 3;
- }
-
- if (lua_type (L, cbidx) == LUA_TFUNCTION) {
- cbdata = g_slice_alloc (sizeof (*cbdata));
- cbdata->L = L;
- cbdata->data = NULL;
- lua_pushvalue (L, cbidx);
- /* Get a reference */
- cbdata->ref = luaL_ref (L, LUA_REGISTRYINDEX);
- pcbdata = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (cbdata));
- *pcbdata = cbdata;
- if (!add_map (cfg, map_line, description, lua_map_read, lua_map_fin,
- (void **)pcbdata)) {
- msg_warn ("invalid hash map %s", map_line);
- lua_pushboolean (L, false);
- }
- else {
- lua_pushboolean (L, true);
- }
- }
- else {
- msg_warn ("invalid callback argument for map %s", map_line);
- lua_pushboolean (L, false);
- }
- }
- else {
- lua_pushboolean (L, false);
- }
-
- return 1;
- }
-
- /* Radix and hash table functions */
- static gint
- lua_radix_get_key (lua_State * L)
- {
- radix_tree_t *radix = lua_check_radix (L);
- guint32 key;
-
- if (radix) {
- key = luaL_checkint (L, 2);
-
- if (radix32tree_find (radix, key) != RADIX_NO_VALUE) {
- lua_pushboolean (L, 1);
- return 1;
- }
- }
-
- lua_pushboolean (L, 0);
- return 1;
- }
-
- static gint
- lua_hash_table_get_key (lua_State * L)
- {
- GHashTable *tbl = lua_check_hash_table (L);
- const gchar *key, *value;
-
- if (tbl) {
- key = luaL_checkstring (L, 2);
-
- if ((value = g_hash_table_lookup (tbl, key)) != NULL) {
- lua_pushstring (L, value);
- return 1;
- }
- }
-
- lua_pushnil (L);
- return 1;
- }
-
- /* Trie functions */
- static gint
- lua_trie_create (lua_State *L)
- {
- rspamd_trie_t *trie, **ptrie;
- gboolean icase = FALSE;
-
- if (lua_gettop (L) == 1) {
- icase = lua_toboolean (L, 1);
- }
-
- trie = rspamd_trie_create (icase);
-
- ptrie = lua_newuserdata (L, sizeof (rspamd_trie_t *));
- rspamd_lua_setclass (L, "rspamd{trie}", -1);
- *ptrie = trie;
-
- return 1;
- }
-
- static gint
- lua_trie_add_pattern (lua_State *L)
- {
- rspamd_trie_t *trie = lua_check_trie (L);
- const gchar *pattern;
- gint id;
-
- if (trie) {
- pattern = luaL_checkstring (L, 2);
- id = luaL_checknumber (L, 3);
-
- if (pattern != NULL) {
- rspamd_trie_insert (trie, pattern, id);
- lua_pushboolean (L, 1);
- }
- }
-
- lua_pushboolean (L, 0);
-
- return 1;
- }
-
- static gint
- lua_trie_search_text (lua_State *L)
- {
- rspamd_trie_t *trie = lua_check_trie (L);
- const gchar *text, *pos;
- gint id, i = 1;
- gsize len;
- gboolean found = FALSE;
-
- if (trie) {
- text = luaL_checkstring (L, 2);
- len = strlen (text);
- if (text) {
- lua_newtable (L);
- pos = text;
- while (pos < text + len &&
- (pos = rspamd_trie_lookup (trie, pos, len, &id)) != NULL) {
- lua_pushinteger (L, i);
- lua_pushinteger (L, id);
- lua_settable (L, -3);
- i++;
- found = TRUE;
- break;
- }
-
- if (!found) {
- lua_pushnil (L);
- }
- return 1;
- }
- }
-
- lua_pushnil (L);
- return 1;
- }
-
- static gint
- lua_trie_search_task (lua_State *L)
- {
- rspamd_trie_t *trie = lua_check_trie (L);
- struct rspamd_task *task;
- struct mime_text_part *part;
- GList *cur;
- const gchar *pos, *end;
- gint id, i = 1;
- void *ud;
- gboolean found = FALSE;
-
- if (trie) {
- ud = luaL_checkudata (L, 2, "rspamd{task}");
- luaL_argcheck (L, ud != NULL, 1, "'task' expected");
- task = ud ? *((struct rspamd_task **)ud) : NULL;
- if (task) {
- lua_newtable (L);
- cur = task->text_parts;
- while (cur) {
- part = cur->data;
- if (!part->is_empty && part->content != NULL) {
- pos = (const gchar *)part->content->data;
- end = pos + part->content->len;
- while (pos < end &&
- (pos =
- rspamd_trie_lookup (trie, pos, part->content->len,
- &id)) != NULL) {
- lua_pushinteger (L, i);
- lua_pushinteger (L, id);
- lua_settable (L, -3);
- i++;
- found = TRUE;
- break;
- }
- }
- cur = g_list_next (cur);
- }
- if (!found) {
- lua_pushnil (L);
- }
- return 1;
- }
- }
-
- if (!found) {
- lua_pushnil (L);
- }
- return 1;
- }
- /* Init functions */
-
- void
- luaopen_config (lua_State * L)
- {
- rspamd_lua_new_class (L, "rspamd{config}", configlib_m);
-
- lua_pop (L, 1); /* remove metatable from stack */
- }
-
- void
- luaopen_radix (lua_State * L)
- {
- rspamd_lua_new_class (L, "rspamd{radix}", radixlib_m);
-
- lua_pop (L, 1); /* remove metatable from stack */
- }
-
- void
- luaopen_hash_table (lua_State * L)
- {
- rspamd_lua_new_class (L, "rspamd{hash_table}", hashlib_m);
- luaL_register (L, "rspamd_hash_table", null_reg);
-
- lua_pop (L, 1); /* remove metatable from stack */
- }
-
- static gint
- lua_load_trie (lua_State *L)
- {
- lua_newtable (L);
- luaL_register (L, NULL, trielib_f);
-
- return 1;
- }
-
- 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_add_preload (L, "rspamd_trie", lua_load_trie);
-
- lua_pop (L, 1); /* remove metatable from stack */
- }
|