diff options
-rw-r--r-- | src/cfg_xml.c | 58 | ||||
-rw-r--r-- | src/lua/lua_common.h | 2 | ||||
-rw-r--r-- | src/lua/lua_config.c | 40 | ||||
-rw-r--r-- | src/map.c | 109 | ||||
-rw-r--r-- | src/map.h | 6 |
5 files changed, 195 insertions, 20 deletions
diff --git a/src/cfg_xml.c b/src/cfg_xml.c index 00da907f4..fba925cc6 100644 --- a/src/cfg_xml.c +++ b/src/cfg_xml.c @@ -1001,14 +1001,10 @@ handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, con return TRUE; } -/* Handle lua tag */ -gboolean -handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) +static void +set_lua_globals (struct config_file *cfg, lua_State *L) { - gchar *val, *cur_dir, *lua_dir, *lua_file, *tmp1, *tmp2; - lua_State *L = cfg->lua_state; struct config_file **pcfg; - /* First check for global variable 'config' */ lua_getglobal (L, "config"); @@ -1017,23 +1013,35 @@ handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable lua_newtable (L); lua_setglobal (L, "config"); } + lua_getglobal (L, "metrics"); if (lua_isnil (L, -1)) { lua_newtable (L); lua_setglobal (L, "metrics"); } + lua_getglobal (L, "composites"); if (lua_isnil (L, -1)) { lua_newtable (L); lua_setglobal (L, "composites"); } - lua_getglobal (L, "rspamd_config"); - if (lua_isnil (L, -1)) { - pcfg = lua_newuserdata (L, sizeof (struct config_file *)); - lua_setclass (L, "rspamd{config}", -1); - *pcfg = cfg; - lua_setglobal (L, "rspamd_config"); - } + + pcfg = lua_newuserdata (L, sizeof (struct config_file *)); + lua_setclass (L, "rspamd{config}", -1); + *pcfg = cfg; + lua_setglobal (L, "rspamd_config"); + + /* Clear stack from globals */ + lua_pop (L, 3); +} + +/* Handle lua tag */ +gboolean +handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) +{ + gchar *val, *cur_dir, *lua_dir, *lua_file, *tmp1, *tmp2; + lua_State *L = cfg->lua_state; + /* Now config tables can be used for configuring rspamd */ /* First check "src" attribute */ if (attrs != NULL && (val = g_hash_table_lookup (attrs, "src")) != NULL) { @@ -1045,7 +1053,8 @@ handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable if (lua_dir && lua_file) { cur_dir = g_malloc (PATH_MAX); if (getcwd (cur_dir, PATH_MAX) != NULL && chdir (lua_dir) != -1) { - if (luaL_dofile (L, lua_file) != 0) { + /* Load file */ + if (luaL_loadfile (L, lua_file) != 0) { msg_err ("cannot load lua file %s: %s", val, lua_tostring (L, -1)); if (chdir (cur_dir) == -1) { msg_err ("cannot chdir to %s: %s", cur_dir, strerror (errno));; @@ -1055,6 +1064,18 @@ handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable g_free (tmp2); return FALSE; } + set_lua_globals (cfg, L); + /* Now do it */ + if (lua_pcall (L, 0, LUA_MULTRET, 0) != 0) { + msg_err ("init of %s failed: %s", val, lua_tostring (L, -1)); + if (chdir (cur_dir) == -1) { + msg_err ("cannot chdir to %s: %s", cur_dir, strerror (errno));; + } + g_free (cur_dir); + g_free (tmp1); + g_free (tmp2); + return FALSE; + } } else { msg_err ("cannot chdir to %s: %s", lua_dir, strerror (errno));; @@ -1080,10 +1101,17 @@ handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable } else if (data != NULL && *data != '\0') { /* Try to load a string */ - if (luaL_dostring (L, data) != 0) { + if (luaL_loadstring (L, data) != 0) { msg_err ("cannot load lua chunk: %s", lua_tostring (L, -1)); return FALSE; } + set_lua_globals (cfg, L); + /* Now do it */ + if (lua_pcall (L, 0, LUA_MULTRET, 0) != 0) { + msg_err ("init of lua chunk failed: %s", lua_tostring (L, -1)); + return FALSE; + } + } return TRUE; } diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h index da3cc254e..2879568f0 100644 --- a/src/lua/lua_common.h +++ b/src/lua/lua_common.h @@ -16,7 +16,7 @@ extern const luaL_reg null_reg[]; -#define RSPAMD_LUA_API_VERSION 5 +#define RSPAMD_LUA_API_VERSION 6 /* Common utility functions */ void lua_newclass (lua_State *L, const gchar *classname, const struct luaL_reg *func); diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c index d69036e09..4ca3b7e45 100644 --- a/src/lua/lua_config.c +++ b/src/lua/lua_config.c @@ -38,6 +38,7 @@ LUA_FUNCTION_DEF (config, get_all_opt); 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, get_classifier); LUA_FUNCTION_DEF (config, register_symbol); LUA_FUNCTION_DEF (config, register_virtual_symbol); @@ -53,6 +54,7 @@ static const struct luaL_reg configlib_m[] = { 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, get_classifier), LUA_INTERFACE_DEF (config, register_symbol), LUA_INTERFACE_DEF (config, register_virtual_symbol), @@ -495,6 +497,36 @@ lua_config_add_hash_map (lua_State *L) } +static gint +lua_config_add_kv_map (lua_State *L) +{ + struct config_file *cfg = lua_check_config (L); + const gchar *map_line; + GHashTable **r, ***ud; + + if (cfg) { + map_line = luaL_checkstring (L, 2); + r = g_malloc (sizeof (GHashTable *)); + *r = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal); + if (!add_map (map_line, read_kv_list, fin_kv_list, (void **)r)) { + msg_warn ("invalid hash map %s", map_line); + g_hash_table_destroy (*r); + g_free (r); + lua_pushnil (L); + return 1; + } + ud = lua_newuserdata (L, sizeof (GHashTable *)); + *ud = r; + lua_setclass (L, "rspamd{hash_table}", -1); + + return 1; + } + + lua_pushnil (L); + return 1; + +} + /*** Metric functions ***/ @@ -625,18 +657,18 @@ static gint lua_hash_table_get_key (lua_State * L) { GHashTable *tbl = lua_check_hash_table (L); - const gchar *key; + const gchar *key, *value; if (tbl) { key = luaL_checkstring (L, 2); - if (g_hash_table_lookup (tbl, key) != NULL) { - lua_pushboolean (L, 1); + if ((value = g_hash_table_lookup (tbl, key)) != NULL) { + lua_pushstring (L, value); return 1; } } - lua_pushboolean (L, 0); + lua_pushnil (L); return 1; } @@ -553,6 +553,98 @@ add_map (const gchar *map_line, map_cb_t read_callback, map_fin_cb_t fin_callbac * FSM for parsing lists */ u_char * +abstract_parse_kv_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data, insert_func func) +{ + u_char *c, *p, *key = NULL, *value = NULL; + + p = chunk; + c = p; + + while (p - chunk < len) { + switch (data->state) { + case 0: + /* read key */ + /* Check here comments, eol and end of buffer */ + if (*p == '#') { + if (key != NULL && p - c > 0) { + value = memory_pool_alloc (pool, p - c + 1); + memcpy (value, c, p - c); + value[p - c] = '\0'; + value = g_strstrip (value); + func (data->cur_data, key, value); + } + data->state = 99; + } + else if (*p == '\r' || *p == '\n' || p - chunk == len - 1) { + if (key != NULL && p - c > 0) { + value = memory_pool_alloc (pool, p - c + 1); + memcpy (value, c, p - c); + value[p - c] = '\0'; + + value = g_strstrip (value); + func (data->cur_data, key, value); + } + data->state = 100; + key = NULL; + } + else if (g_ascii_isspace (*p)) { + if (p - c > 0) { + key = memory_pool_alloc (pool, p - c + 1); + memcpy (key, c, p - c); + key[p - c] = '\0'; + data->state = 2; + } + else { + key = NULL; + } + } + else { + p ++; + } + break; + case 2: + /* Skip spaces before value */ + if (!g_ascii_isspace (*p)) { + c = p; + data->state = 0; + } + else { + p ++; + } + break; + case 99: + /* SKIP_COMMENT */ + /* Skip comment till end of line */ + if (*p == '\r' || *p == '\n') { + while ((*p == '\r' || *p == '\n') && p - chunk < len) { + p++; + } + c = p; + key = NULL; + data->state = 0; + } + else { + p++; + } + break; + case 100: + /* Skip \r\n and whitespaces */ + if (*p == '\r' || *p == '\n' || g_ascii_isspace (*p)) { + p ++; + } + else { + c = p; + key = NULL; + data->state = 0; + } + break; + } + } + + return c; +} + +u_char * abstract_parse_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data, insert_func func) { u_char *s, *p, *str, *start; @@ -709,6 +801,23 @@ fin_host_list (memory_pool_t * pool, struct map_cb_data *data) } u_char * +read_kv_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data) +{ + if (data->cur_data == NULL) { + data->cur_data = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal); + } + return abstract_parse_kv_list (pool, chunk, len, data, (insert_func) g_hash_table_insert); +} + +void +fin_kv_list (memory_pool_t * pool, struct map_cb_data *data) +{ + if (data->prev_data) { + g_hash_table_destroy (data->prev_data); + } +} + +u_char * read_radix_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data) { if (data->cur_data == NULL) { @@ -107,6 +107,12 @@ u_char* read_host_list (memory_pool_t *pool, u_char *chunk, size_t len, struct m void fin_host_list (memory_pool_t *pool, struct map_cb_data *data); /** + * Kv list is an ordinal list of keys and values separated by whitespace + */ +u_char* read_kv_list (memory_pool_t *pool, u_char *chunk, size_t len, struct map_cb_data *data); +void fin_kv_list (memory_pool_t *pool, struct map_cb_data *data); + +/** * FSM for lists parsing (support comments, blank lines and partial replies) */ u_char * abstract_parse_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data, insert_func func); |