OPTION(DEBUG_MODE "Enable debug output [default: ON]" ON)
OPTION(ENABLE_OPTIMIZATION "Enable optimization [default: OFF]" OFF)
OPTION(ENABLE_PERL "Enable perl support [default: OFF]" OFF)
-OPTION(ENABLE_LUA "Enable lua support [default: ON]" ON)
OPTION(SKIP_RELINK_RPATH "Skip relinking and full RPATH for the install tree" OFF)
OPTION(ENABLE_REDIRECTOR "Enable redirector install [default: OFF]" OFF)
OPTION(ENABLE_PROFILING "Enable profiling [default: OFF]" OFF)
SET(WITHOUT_PERL 1)
ENDIF(ENABLE_PERL MATCHES "ON")
-IF(ENABLE_LUA MATCHES "ON")
- IF (ENABLE_PERL MATCHES "ON")
- MESSAGE(FATAL_ERROR "Error: Perl and Lua support cannot be turned on together")
- ENDIF (ENABLE_PERL MATCHES "ON")
-
- INCLUDE(FindLua51)
- IF(NOT LUA_FOUND)
- # Automatic check failed, check passed variable
- IF(LUA_INCLUDE_DIR)
- INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}")
- SET(WITH_LUA 1)
- ELSE(LUA_INCLUDE_DIR)
- SET(ENABLE_LUA "OFF")
- MESSAGE(STATUS "Lua not found, lua support disabled")
- ENDIF(LUA_INCLUDE_DIR)
- ELSE(NOT LUA_FOUND)
- SET(WITH_LUA 1)
- INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}")
- ENDIF(NOT LUA_FOUND)
-ENDIF(ENABLE_LUA MATCHES "ON")
+
+INCLUDE(FindLua51)
+IF(NOT LUA_FOUND)
+ # Automatic check failed, check passed variable
+ IF(LUA_INCLUDE_DIR)
+ INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}")
+ SET(WITH_LUA 1)
+ ELSE(LUA_INCLUDE_DIR)
+ MESSAGE(FATAL_ERROR "Lua not found, lua support is required for working")
+ ENDIF(LUA_INCLUDE_DIR)
+ELSE(NOT LUA_FOUND)
+ SET(WITH_LUA 1)
+ INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}")
+ENDIF(NOT LUA_FOUND)
# Lex and yacc
FIND_PROGRAM(LEX_EXECUTABLE lex)
IF(ENABLE_PERL MATCHES "ON")
LIST(APPEND RSPAMDSRC src/perl.c)
ENDIF(ENABLE_PERL MATCHES "ON")
-IF(ENABLE_LUA MATCHES "ON")
- ADD_SUBDIRECTORY(src/lua)
-ENDIF(ENABLE_LUA MATCHES "ON")
+ADD_SUBDIRECTORY(src/lua)
ADD_SUBDIRECTORY(src/json)
ADD_SUBDIRECTORY(src/evdns)
ADD_DEPENDENCIES(rspamd perlmodule)
ENDIF(PERL_EXECUTABLE)
-IF(ENABLE_LUA MATCHES "ON")
- TARGET_LINK_LIBRARIES(rspamd rspamd_lua)
- TARGET_LINK_LIBRARIES(rspamd "${LUA_LIBRARY}")
-ENDIF(ENABLE_LUA MATCHES "ON")
+TARGET_LINK_LIBRARIES(rspamd rspamd_lua)
+TARGET_LINK_LIBRARIES(rspamd "${LUA_LIBRARY}")
TARGET_LINK_LIBRARIES(rspamd m)
IF(LIBUTIL_LIBRARY)
INSTALL(FILES conf/rspamd.conf.sample DESTINATION ${ETC_PREFIX}/)
# Lua plugins
-IF(ENABLE_LUA MATCHES "ON")
- INSTALL(CODE "EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E make_directory ${ETC_PREFIX}/rspamd/plugins)")
- INSTALL(DIRECTORY src/plugins/lua DESTINATION ${ETC_PREFIX}/rspamd/plugins PATTERN "*.lua")
-ENDIF(ENABLE_LUA MATCHES "ON")
+INSTALL(CODE "EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E make_directory ${ETC_PREFIX}/rspamd/plugins)")
+INSTALL(DIRECTORY src/plugins/lua DESTINATION ${ETC_PREFIX}/rspamd/plugins PATTERN "*.lua")
# Perl lib
IF(PERL_EXECUTABLE)
* script module list item
*/
struct script_module {
- gchar *name; /**< name of module */
- gchar *path; /**< path to module */
+ gchar *name; /**< name of module */
+ gchar *path; /**< path to module */
};
/**
struct module_opt {
gchar *param; /**< parameter name */
gchar *value; /**< paramater value */
+ gpointer actual_data; /**< parsed data */
+ gboolean is_lua; /**< actually this is lua variable */
+ enum {
+ LUA_VAR_NUM,
+ LUA_VAR_BOOLEAN,
+ LUA_VAR_STRING,
+ LUA_VAR_FUNCTION,
+ LUA_VAR_UNKNOWN
+ } lua_type; /**< type of lua variable */
};
/**
gchar* checksum; /**< real checksum of config file */
gchar* dump_checksum; /**< dump checksum of config file */
+ gpointer lua_state; /**< pointer to lua state */
};
/**
{
GList *cur_opt;
struct module_opt *cur;
+ static char numbuf[64];
cur_opt = g_hash_table_lookup (cfg->modules_opts, module_name);
if (cur_opt == NULL) {
while (cur_opt) {
cur = cur_opt->data;
if (strcmp (cur->param, opt_name) == 0) {
- return cur->value;
+ /* 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 (char *)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);
}
cfg->metrics_list = g_list_prepend (cfg->metrics_list, def_metric);
g_hash_table_insert (cfg->metrics, DEFAULT_METRIC, def_metric);
}
-
+
+ /* Lua options */
+ (void)lua_post_load_config (cfg);
}
#include "util.h"
#include "classifiers/classifiers.h"
#include "tokenizers/tokenizers.h"
+#include "lua/lua_common.h"
/* Maximum attributes for param */
#define MAX_PARAM 64
G_STRUCT_OFFSET (struct config_file, pid_file),
NULL
},
+ {
+ "lua",
+ handle_lua,
+ 0,
+ NULL
+ },
{
"raw_mode",
xml_handle_boolean,
gboolean
handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
{
- char *name;
+ char *name, *val;
GList *cur_opt;
struct module_opt *cur;
+ gboolean is_lua = FALSE;
if ((name = g_hash_table_lookup (attrs, "name")) == NULL) {
msg_err ("param tag must have \"name\" attribute");
return FALSE;
}
-
+
+ /* Check for lua */
+ if ((val = g_hash_table_lookup (attrs, "lua")) != NULL) {
+ if (g_ascii_strcasecmp (val, "yes") == 0) {
+ is_lua = TRUE;
+ }
+ }
cur_opt = g_hash_table_lookup (cfg->modules_opts, ctx->section_name);
if (cur_opt == NULL) {
/* Insert new option structure */
- cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct module_opt));
+ cur = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct module_opt));
cur->param = name;
cur->value = data;
+ cur->is_lua = is_lua;
cur_opt = g_list_prepend (NULL, cur);
g_hash_table_insert (cfg->modules_opts, memory_pool_strdup (cfg->cfg_pool, ctx->section_name), cur_opt);
}
if (strcmp (cur->param, name) == 0) {
/* cur->value is in pool */
cur->value = data;
+ cur->is_lua = is_lua;
return TRUE;
}
cur_opt = g_list_next (cur_opt);
}
/* Not found, insert */
- cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct module_opt));
+ cur = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct module_opt));
cur->param = name;
cur->value = data;
- cur_opt = g_list_prepend (cur_opt, cur);
+ cur->is_lua = is_lua;
+ /* Slow way, but we cannot prepend here as we need to modify pointer inside module_options hash */
+ cur_opt = g_list_append (cur_opt, cur);
+ }
+
+ 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, int offset)
+{
+ gchar *val;
+ lua_State *L = cfg->lua_state;
+
+ /* First check for global variable 'config' */
+ lua_getglobal (L, "config");
+
+ if (lua_isnil (L, 1)) {
+ /* Assign global table to set up attributes */
+ lua_newtable (L);
+ lua_setglobal (L, "config");
+ /* Now config table can be used for configuring rspamd */
+ }
+ /* First check "src" attribute */
+ if ((val = g_hash_table_lookup (attrs, "src")) != NULL) {
+ if (luaL_dofile (L, val) != 0) {
+ msg_err ("cannot load lua file %s: %s", val, lua_tostring (L, -1));
+ return FALSE;
+ }
+ }
+ else if (data != NULL && *data != '\0') {
+ /* Try to load a string */
+ if (luaL_dostring (L, data) != 0) {
+ msg_err ("cannot load lua chunk: %s", lua_tostring (L, -1));
+ return FALSE;
+ }
}
return TRUE;
gboolean handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
gboolean handle_log_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
gboolean handle_log_level (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+gboolean handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
/* Dumper functions */
lua_task.c
lua_message.c
lua_config.c
- lua_classifier.c)
+ lua_classifier.c
+ lua_cfg_file.c)
ADD_LIBRARY(rspamd_lua STATIC ${LUASRC})
TARGET_LINK_LIBRARIES(rspamd_lua ${LUALIB})
--- /dev/null
+/*
+ * Copyright (c) 2009, Rambler media
+ * 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 Rambler media ''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 Rambler 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"
+
+/*
+ * This is implementation of lua routines to handle config file params
+ */
+
+
+/* Check element with specified name in list, and append it to list if no element with such name was found */
+static void
+lua_check_element (memory_pool_t *pool, const gchar *name, GList *options, struct module_opt **opt)
+{
+ struct module_opt *cur;
+ GList *cur_opt;
+ gboolean found = FALSE;
+
+ cur_opt = options;
+
+ while (cur_opt) {
+ cur = cur_opt->data;
+
+ if (g_ascii_strcasecmp (cur->param, name) == 0) {
+ found = TRUE;
+ break;
+ }
+ cur_opt = g_list_next (cur_opt);
+ }
+
+ if (found) {
+ *opt = cur;
+ cur->is_lua = TRUE;
+ }
+ else {
+ /* New option */
+ *opt = memory_pool_alloc0 (pool, sizeof (struct module_opt));
+ (*opt)->is_lua = TRUE;
+ (void)g_list_append (options, *opt);
+ }
+}
+
+/* Process a single item in 'config' table */
+static void
+lua_process_module (lua_State *L, const gchar *param, struct config_file *cfg)
+{
+ GList *cur_opt;
+ struct module_opt *cur;
+ const char *name;
+ gboolean new_module = FALSE;
+
+ /* Get module opt structure */
+ if ((cur_opt = g_hash_table_lookup (cfg->modules_opts, param)) == NULL) {
+ new_module = TRUE;
+ }
+
+ /* Now iterate throught module table */
+ lua_gettable (L, -1);
+ for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
+ /* key - -2, value - -1 */
+ name = luaL_checkstring (L, -2);
+ if (name != NULL) {
+ lua_check_element (cfg->cfg_pool, name, cur_opt, &cur);
+ lua_process_element (cfg, name, cur, -1);
+ }
+ }
+
+ if (new_module && cur_opt != NULL) {
+ /* Insert new list into a hash */
+ g_hash_table_insert (cfg->modules_opts, memory_pool_strdup (cfg->cfg_pool, param), cur_opt);
+ }
+}
+
+/* Process single element */
+void
+lua_process_element (struct config_file *cfg, const char *name, struct module_opt *opt, int idx)
+{
+ lua_State *L = cfg->lua_state;
+ int t;
+ double *num;
+ gboolean *flag;
+
+ t = lua_type (L, idx);
+ /* Handle type */
+ switch (t) {
+ case LUA_TNUMBER:
+ opt->actual_data = memory_pool_alloc (cfg->cfg_pool, sizeof (double));
+ num = (double *)opt->actual_data;
+ *num = lua_tonumber (L, idx);
+ opt->lua_type = LUA_VAR_NUM;
+ break;
+ case LUA_TBOOLEAN:
+ opt->actual_data = memory_pool_alloc (cfg->cfg_pool, sizeof (gboolean));
+ flag = (gboolean *)opt->actual_data;
+ *flag = lua_toboolean (L, idx);
+ opt->lua_type = LUA_VAR_BOOLEAN;
+ break;
+ case LUA_TSTRING:
+ opt->actual_data = memory_pool_strdup (cfg->cfg_pool, lua_tostring (L, idx));
+ opt->lua_type = LUA_VAR_STRING;
+ break;
+ case LUA_TFUNCTION:
+ opt->actual_data = (gpointer)lua_topointer (L, idx);
+ opt->lua_type = LUA_VAR_FUNCTION;
+ break;
+ case LUA_TNIL:
+ case LUA_TTABLE:
+ case LUA_TUSERDATA:
+ case LUA_TTHREAD:
+ case LUA_TLIGHTUSERDATA:
+ msg_warn ("cannot handle variables of type %s as there is nothing to do with them", lua_typename (L, t));
+ opt->lua_type = LUA_VAR_UNKNOWN;
+ break;
+ }
+}
+
+
+static void
+lua_module_callback (gpointer key, gpointer value, gpointer ud)
+{
+ struct config_file *cfg = ud;
+ lua_State *L = cfg->lua_state;
+ GList *cur;
+ struct module_opt *opt;
+
+ cur = value;
+ while (cur) {
+ opt = cur->data;
+ if (opt->is_lua && opt->actual_data == NULL) {
+ /* Try to extract variable name from config table first */
+ lua_getglobal (L, "config");
+ if (lua_istable (L, -1)) {
+ lua_pushstring (L, opt->param);
+ lua_gettable (L, -2);
+ if (lua_isnil (L, -1)) {
+ /* Try to get global variable */
+ lua_getglobal (L, opt->param);
+ }
+ }
+ else {
+ /* Try to get global variable */
+ lua_getglobal (L, opt->param);
+ }
+ lua_process_element (cfg, opt->param, opt, -1);
+ }
+ cur = g_list_next (cur);
+ }
+
+}
+
+/* Do post load initialization based on lua */
+void
+lua_post_load_config (struct config_file *cfg)
+{
+ lua_State *L = cfg->lua_state;
+ const gchar *name;
+
+ /* First check all module options that may be overriden 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_checkstring (L, -2);
+ if (name != NULL && lua_istable (L, -1)) {
+ lua_process_module (L, name, cfg);
+ }
+ }
+ }
+
+ /* Now parse all lua params */
+ g_hash_table_foreach (cfg->modules_opts, lua_module_callback, cfg);
+}
return 1;
}
-static void
+void
init_lua ()
{
if (L == NULL) {
struct script_module *module;
struct statfile *st;
- init_lua ();
cur = g_list_first (cfg->script_modules);
while (cur) {
module = cur->data;
}
cur = g_list_next (cur);
}
+ /* Assign state */
+ cfg->lua_state = L;
}
/* Callback functions */
extern const luaL_reg null_reg[];
+/* Common utility functions */
void lua_newclass (lua_State *L, const char *classname, const struct luaL_reg *func);
void lua_setclass (lua_State *L, const char *classname, int objidx);
void lua_set_table_index (lua_State *L, const char *index, const char *value);
int luaopen_textpart (lua_State *L);
int luaopen_classifier (lua_State *L);
int luaopen_statfile (lua_State * L);
+void init_lua ();
void init_lua_filters (struct config_file *cfg);
+/* Filters functions */
int lua_call_filter (const char *function, struct worker_task *task);
int lua_call_chain_filter (const char *function, struct worker_task *task, int *marks, unsigned int number);
double lua_consolidation_func (struct worker_task *task, const char *metric_name, const char *function_name);
void add_luabuf (const char *line);
+/* Classify functions */
GList *call_classifier_pre_callbacks (struct classifier_config *ccf, struct worker_task *task);
double call_classifier_post_callbacks (struct classifier_config *ccf, struct worker_task *task, double in);
double lua_normalizer_func (double score, void *params);
+/* Config file functions */
+void lua_post_load_config (struct config_file *cfg);
+void lua_process_element (struct config_file *cfg, const char *name, struct module_opt *opt, int idx);
+
+
#endif /* WITH_LUA */
#endif /* RSPAMD_LUA_H */
#ifndef HAVE_SETPROCTITLE
init_title (argc, argv, environ);
#endif
+ init_lua ();
f = fopen (rspamd->cfg->cfg_name, "r");
if (f == NULL) {
}
l = g_list_next (l);
}
-#if defined(WITH_LUA)
init_lua_filters (cfg);
-#endif
if (dump_vars) {
dump_cfg_vars ();
}
perl_construct (perl_interpreter);
perl_parse (perl_interpreter, xs_init, 3, args, NULL);
init_perl_filters (cfg);
-#elif defined(WITH_LUA)
- init_lua_filters (cfg);
#endif
+ init_lua_filters (cfg);
+
/* Init symbols cache for each metric */
l = g_list_first (cfg->metrics_list);
while (l) {