@@ -348,8 +348,7 @@ struct config_file { | |||
GList *workers; /**< linked list of all workers params */ | |||
struct rspamd_worker_cfg_parser *wrk_parsers; /**< hash for worker config parsers, indexed by worker quarks */ | |||
gchar *filters_str; /**< string of filters */ | |||
GHashTable* modules_opts; /**< hash for module options indexed by module name */ | |||
GHashTable* modules_metas; /**< hash for module meta options indexed by module name*/ | |||
rspamd_cl_object_t *rcl_obj; /**< rcl object */ | |||
GHashTable* variables; /**< hash of $variables defined in config, indexed by variable name */ | |||
GHashTable* metrics; /**< hash of metrics indexed by metric name */ | |||
GList* symbols_groups; /**< groups of symbols */ | |||
@@ -449,7 +448,8 @@ void free_config (struct config_file *cfg); | |||
* @param opt_name name of option to get | |||
* @return module value or NULL if option does not defined | |||
*/ | |||
gchar* get_module_opt (struct config_file *cfg, gchar *module_name, gchar *opt_name); | |||
rspamd_cl_object_t* get_module_opt (struct config_file *cfg, const gchar *module_name, | |||
const gchar *opt_name); | |||
/** | |||
* Parse limit | |||
@@ -534,11 +534,6 @@ gboolean parse_normalizer (struct config_file *cfg, struct statfile *st, const g | |||
*/ | |||
gboolean read_xml_config (struct config_file *cfg, const gchar *filename); | |||
/* | |||
* Check modules configuration for semantic validity | |||
*/ | |||
gboolean check_modules_config (struct config_file *cfg); | |||
/* | |||
* Register symbols of classifiers inside metrics | |||
*/ |
@@ -241,8 +241,6 @@ init_defaults (struct config_file *cfg) | |||
cfg->max_diff = 20480; | |||
cfg->max_statfile_size = DEFAULT_STATFILE_SIZE; | |||
cfg->modules_opts = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); | |||
cfg->modules_metas = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); | |||
cfg->variables = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); | |||
cfg->metrics = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); | |||
cfg->c_modules = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); | |||
@@ -267,9 +265,7 @@ free_config (struct config_file *cfg) | |||
struct symbols_group *gr; | |||
remove_all_maps (cfg); | |||
g_hash_table_remove_all (cfg->modules_opts); | |||
g_hash_table_unref (cfg->modules_opts); | |||
g_hash_table_unref (cfg->modules_metas); | |||
rspamd_cl_obj_unref (cfg->rcl_obj); | |||
g_hash_table_remove_all (cfg->variables); | |||
g_hash_table_unref (cfg->variables); | |||
g_hash_table_remove_all (cfg->metrics); | |||
@@ -303,51 +299,17 @@ free_config (struct config_file *cfg) | |||
memory_pool_delete (cfg->cfg_pool); | |||
} | |||
gchar * | |||
get_module_opt (struct config_file *cfg, gchar *module_name, gchar *opt_name) | |||
rspamd_cl_object_t * | |||
get_module_opt (struct config_file *cfg, const gchar *module_name, const gchar *opt_name) | |||
{ | |||
GList *cur_opt; | |||
struct module_opt *cur; | |||
static gchar numbuf[64]; | |||
rspamd_cl_object_t *res = NULL, *sec; | |||
cur_opt = g_hash_table_lookup (cfg->modules_opts, module_name); | |||
if (cur_opt == NULL) { | |||
return NULL; | |||
sec = rspamd_cl_obj_get_key (cfg->rcl_obj, module_name); | |||
if (sec != NULL) { | |||
res = rspamd_cl_obj_get_key (cfg->rcl_obj, opt_name); | |||
} | |||
while (cur_opt) { | |||
cur = cur_opt->data; | |||
if (strcmp (cur->param, opt_name) == 0) { | |||
/* Check if it is lua variable */ | |||
if (! cur->is_lua) { | |||
/* Plain variable */ | |||
return cur->value; | |||
} | |||
else { | |||
/* Check type */ | |||
switch (cur->lua_type) { | |||
case LUA_VAR_NUM: | |||
/* numbuf is static, so it is safe to return it "as is" */ | |||
snprintf (numbuf, sizeof (numbuf), "%f", *(double *)cur->actual_data); | |||
return numbuf; | |||
case LUA_VAR_BOOLEAN: | |||
snprintf (numbuf, sizeof (numbuf), "%s", *(gboolean *)cur->actual_data ? "yes" : "no"); | |||
return numbuf; | |||
case LUA_VAR_STRING: | |||
return (gchar *)cur->actual_data; | |||
case LUA_VAR_FUNCTION: | |||
msg_info ("option %s is dynamic, so it cannot be aqquired statically", opt_name); | |||
return NULL; | |||
case LUA_VAR_UNKNOWN: | |||
msg_info ("option %s has unknown type, maybe there is error in LUA code", opt_name); | |||
return NULL; | |||
} | |||
} | |||
} | |||
cur_opt = g_list_next (cur_opt); | |||
} | |||
return NULL; | |||
return res; | |||
} | |||
guint64 | |||
@@ -696,7 +658,6 @@ post_load_config (struct config_file *cfg) | |||
struct metric *def_metric; | |||
g_hash_table_foreach (cfg->variables, substitute_all_variables, cfg); | |||
g_hash_table_foreach (cfg->modules_opts, substitute_module_variables, cfg); | |||
fill_cfg_params (cfg); | |||
#ifdef HAVE_CLOCK_GETTIME | |||
@@ -1042,44 +1003,6 @@ read_xml_config (struct config_file *cfg, const gchar *filename) | |||
return res; | |||
} | |||
static void | |||
modules_config_callback (gpointer key, gpointer value, gpointer ud) | |||
{ | |||
extern GHashTable *module_options; | |||
GHashTable *cur_module; | |||
GList *cur; | |||
struct module_opt *opt; | |||
const gchar *mname = key; | |||
gboolean *res = ud; | |||
if ((cur_module = g_hash_table_lookup (module_options, mname)) == NULL) { | |||
msg_warn ("module %s has not registered any options but is presented in configuration", mname); | |||
*res = FALSE; | |||
return; | |||
} | |||
cur = value; | |||
while (cur) { | |||
opt = cur->data; | |||
if (!opt->is_lua && !check_module_option (mname, opt->param, opt->value)) { | |||
*res = FALSE; | |||
return; | |||
} | |||
cur = g_list_next (cur); | |||
} | |||
} | |||
gboolean | |||
check_modules_config (struct config_file *cfg) | |||
{ | |||
gboolean res = TRUE; | |||
g_hash_table_foreach (cfg->modules_opts, modules_config_callback, &res); | |||
return res; | |||
} | |||
static void | |||
symbols_classifiers_callback (gpointer key, gpointer value, gpointer ud) | |||
{ |
@@ -15,7 +15,8 @@ SET(LUASRC lua_common.c | |||
lua_session.c | |||
lua_buffer.c | |||
lua_dns.c | |||
lua_rsa.c) | |||
lua_rsa.c | |||
lua_rcl.c) | |||
ADD_LIBRARY(rspamd-lua ${LINK_TYPE} ${LUASRC}) | |||
SET_TARGET_PROPERTIES(rspamd-lua PROPERTIES VERSION ${RSPAMD_VERSION}) |
@@ -6,6 +6,7 @@ | |||
#include "main.h" | |||
#include "cfg_file.h" | |||
#include "rcl/rcl.h" | |||
#include <lua.h> | |||
#include <lauxlib.h> | |||
#include <lualib.h> | |||
@@ -101,6 +102,13 @@ struct lua_locked_state* init_lua_locked (struct config_file *cfg); | |||
*/ | |||
void free_lua_locked (struct lua_locked_state *st); | |||
/** | |||
* Push an rcl object to lua | |||
* @param L lua state | |||
* @param obj object to push | |||
*/ | |||
gint lua_rcl_obj_push (lua_State *L, rspamd_cl_object_t *obj); | |||
/** | |||
* Open libraries functions | |||
*/ |
@@ -153,17 +153,17 @@ static gint | |||
lua_config_get_module_opt (lua_State * L) | |||
{ | |||
struct config_file *cfg = lua_check_config (L); | |||
const gchar *mname, *optname, *val; | |||
const gchar *mname, *optname; | |||
rspamd_cl_object_t *obj; | |||
if (cfg) { | |||
mname = luaL_checkstring (L, 2); | |||
optname = luaL_checkstring (L, 3); | |||
if (mname && optname) { | |||
val = get_module_opt (cfg, (gchar *)mname, (gchar *)optname); | |||
if (val) { | |||
lua_pushstring (L, val); | |||
return 1; | |||
obj = get_module_opt (cfg, mname, optname); | |||
if (obj) { | |||
return lua_rcl_obj_push (L, obj); | |||
} | |||
} | |||
} | |||
@@ -185,83 +185,21 @@ lua_config_get_mempool (lua_State * L) | |||
return 1; | |||
} | |||
static gint | |||
opt_compare (gconstpointer a, gconstpointer b) | |||
{ | |||
const struct module_opt *o1 = a, | |||
*o2 = b; | |||
return g_ascii_strcasecmp (o1->param, o2->param); | |||
} | |||
static gint | |||
lua_config_get_all_opt (lua_State * L) | |||
{ | |||
struct config_file *cfg = lua_check_config (L); | |||
const gchar *mname; | |||
GList *cur_opt, *next_opt; | |||
struct module_opt *opt, *tmp; | |||
gint i; | |||
rspamd_cl_object_t *obj; | |||
if (cfg) { | |||
mname = luaL_checkstring (L, 2); | |||
if (mname) { | |||
cur_opt = g_hash_table_lookup (cfg->modules_opts, mname); | |||
if (cur_opt == NULL) { | |||
lua_pushnil (L); | |||
return 1; | |||
obj = rspamd_cl_obj_get_key (cfg->rcl_obj, mname); | |||
if (obj != NULL) { | |||
return lua_rcl_obj_push (L, obj); | |||
} | |||
/* Sort options in alphabet order by param name */ | |||
cur_opt = g_list_sort (cur_opt, opt_compare); | |||
g_hash_table_insert (cfg->modules_opts, (gpointer)mname, cur_opt); | |||
lua_newtable (L); | |||
while (cur_opt) { | |||
opt = cur_opt->data; | |||
next_opt = g_list_next (cur_opt); | |||
if (next_opt) { | |||
tmp = next_opt->data; | |||
if (g_ascii_strcasecmp (tmp->param, opt->param) == 0) { | |||
/* We have some common values */ | |||
lua_pushstring (L, opt->param); | |||
lua_newtable (L); | |||
/* Now stack looks like: | |||
* table - parent associated table of options | |||
* key - string key of this option | |||
* table - array of values, beginig from 1 | |||
*/ | |||
for (i = 1; ; i++) { | |||
lua_pushinteger (L, i); | |||
lua_pushstring (L, opt->value); | |||
lua_settable (L, -3); | |||
cur_opt = g_list_next (cur_opt); | |||
if (!cur_opt) { | |||
break; | |||
} | |||
tmp = cur_opt->data; | |||
if (g_ascii_strcasecmp (tmp->param, opt->param) != 0) { | |||
break; | |||
} | |||
opt = tmp; | |||
} | |||
/* Now set index in parent table */ | |||
lua_settable (L, -3); | |||
/* Now continue in outter cycle */ | |||
continue; | |||
} | |||
else { | |||
lua_set_table_index (L, opt->param, opt->value); | |||
} | |||
} | |||
else { | |||
lua_set_table_index (L, opt->param, opt->value); | |||
} | |||
cur_opt = next_opt; | |||
} | |||
return 1; | |||
} | |||
} | |||
lua_pushnil (L); |
@@ -0,0 +1,148 @@ | |||
/* Copyright (c) 2013, 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 ''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 "rcl/rcl.h" | |||
/** | |||
* @file lua rcl bindings | |||
*/ | |||
static gint lua_rcl_obj_push_array (lua_State *L, rspamd_cl_object_t *obj); | |||
static gint lua_rcl_obj_push_simple (lua_State *L, rspamd_cl_object_t *obj); | |||
/** | |||
* Push a single element of an object to lua | |||
* @param L | |||
* @param key | |||
* @param obj | |||
*/ | |||
static void | |||
lua_rcl_obj_push_elt (lua_State *L, const char *key, rspamd_cl_object_t *obj) | |||
{ | |||
lua_pushstring (L, key); | |||
lua_push_obj_simple (L, obj); | |||
lua_settable (L, -3); | |||
} | |||
/** | |||
* Push a single object to lua | |||
* @param L | |||
* @param obj | |||
* @return | |||
*/ | |||
static gint | |||
lua_rcl_obj_push_obj (lua_State *L, rspamd_cl_object_t *obj) | |||
{ | |||
rspamd_cl_object_t *cur, *tmp; | |||
if (obj->next != NULL) { | |||
/* Actually we need to push this as an array */ | |||
return lua_rcl_obj_push_array (L, obj); | |||
} | |||
lua_newtable (L); | |||
HASH_ITER (hh, obj, cur, tmp) { | |||
lua_rcl_obj_push_elt (L, obj->key, obj); | |||
} | |||
return 1; | |||
} | |||
/** | |||
* Push an array to lua as table indexed by integers | |||
* @param L | |||
* @param obj | |||
* @return | |||
*/ | |||
static gint | |||
lua_rcl_obj_push_array (lua_State *L, rspamd_cl_object_t *obj) | |||
{ | |||
rspamd_cl_object_t *cur; | |||
gint i = 1; | |||
lua_newtable (L); | |||
LL_FOREACH (obj, cur) { | |||
lua_rcl_obj_push (L, cur); | |||
lua_rawseti (L, -2, i); | |||
i ++; | |||
} | |||
return 1; | |||
} | |||
/** | |||
* Push a simple object to lua depending on its actual type | |||
*/ | |||
static gint | |||
lua_rcl_obj_push_simple (lua_State *L, rspamd_cl_object_t *obj) | |||
{ | |||
if (obj->next != NULL) { | |||
/* Actually we need to push this as an array */ | |||
return lua_rcl_obj_push_array (L, obj); | |||
} | |||
switch (obj->type) { | |||
case RSPAMD_CL_BOOLEAN: | |||
lua_pushboolean (L, rspamd_cl_obj_toboolean (obj)); | |||
break; | |||
case RSPAMD_CL_STRING: | |||
lua_pushstring (L, rspamd_cl_obj_tostring (obj)); | |||
break; | |||
case RSPAMD_CL_INT: | |||
#if LUA_VERSION_NUM >= 501 | |||
lua_pushinteger (L, rspamd_cl_obj_toint (obj)); | |||
#else | |||
lua_pushnumber (L, rspamd_cl_obj_toint (obj)); | |||
#endif | |||
break; | |||
case RSPAMD_CL_FLOAT: | |||
case RSPAMD_CL_TIME: | |||
lua_pushnumber (L, rspamd_cl_obj_todouble (obj)); | |||
break; | |||
default: | |||
lua_pushnil (L); | |||
break; | |||
} | |||
return 1; | |||
} | |||
/** | |||
* Push an object to lua | |||
* @param L lua state | |||
* @param obj object to push | |||
*/ | |||
gint | |||
lua_rcl_obj_push (lua_State *L, rspamd_cl_object_t *obj) | |||
{ | |||
switch (obj->type) { | |||
case RSPAMD_CL_OBJECT: | |||
return lua_rcl_obj_push_obj (L, obj->value.ov); | |||
case RSPAMD_CL_ARRAY: | |||
return lua_rcl_obj_push_array (L, obj->value.ov); | |||
default: | |||
return lua_rcl_obj_push_simple (L, obj); | |||
} | |||
} |