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: 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)
IF(LUA_INCLUDE_DIR)
INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}")
ELSE(LUA_INCLUDE_DIR)
- MESSAGE(FATAL_ERROR "Error: Lua not found but its support is enabled")
+ SET(ENABLE_LUA "OFF")
+ MESSAGE(STATUS "Lua not found, lua support disabled")
ENDIF(LUA_INCLUDE_DIR)
ELSE(NOT LUA_FOUND)
INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}")
LIST(APPEND RSPAMDSRC src/perl.c)
ENDIF(ENABLE_PERL MATCHES "ON")
IF(ENABLE_LUA MATCHES "ON")
- LIST(APPEND RSPAMDSRC src/lua.c)
+ ADD_SUBDIRECTORY(src/lua)
ENDIF(ENABLE_LUA MATCHES "ON")
SET(TOKENIZERSSRC src/tokenizers/tokenizers.c
ENDIF(ENABLE_PERL MATCHES "ON")
+IF(ENABLE_LUA MATCHES "ON")
+ TARGET_LINK_LIBRARIES(rspamd "${LUA_LIBRARY}")
+ TARGET_LINK_LIBRARIES(rspamd rspamd_lua)
+ENDIF(ENABLE_LUA MATCHES "ON")
+
TARGET_LINK_LIBRARIES(rspamd m)
IF(LIBUTIL_LIBRARY)
TARGET_LINK_LIBRARIES(rspamd util)
TARGET_LINK_LIBRARIES(rspamd event)
TARGET_LINK_LIBRARIES(rspamd ${GLIB2_LIBRARIES})
TARGET_LINK_LIBRARIES(rspamd ${GMIME2_LIBRARIES})
-IF(ENABLE_LUA MATCHES "ON")
- TARGET_LINK_LIBRARIES(rspamd "${LUA_LIBRARY}")
-ENDIF(ENABLE_LUA MATCHES "ON")
IF(ENABLE_GPERF_TOOLS MATCHES "ON")
TARGET_LINK_LIBRARIES(rspamd profiler)
};
/**
- * Perl module list item
+ * script module list item
*/
-struct perl_module {
+struct script_module {
char *path; /**< path to module */
};
};
/**
- * Config option for importing to perl module
+ * Config option for importing to script module
*/
struct config_scalar {
void *pointer; /**< pointer to data */
char *deliver_agent_path; /**< deliver to pipe instead of socket */
gboolean deliver_lmtp; /**< use LMTP instead of SMTP */
- GList *perl_modules; /**< linked list of perl modules to load */
+ GList *script_modules; /**< linked list of script modules to load */
GList *filters; /**< linked list of all filters */
GList *workers; /**< linked list of all workers params */
#include "tokenizers/tokenizers.h"
#include "view.h"
#ifdef WITH_LUA
-#include "lua-rspamd.h"
+#include "lua/lua_common.h"
#else
#include "perl.h"
#endif
MODULE EQSIGN QUOTEDSTRING {
#if !defined(WITHOUT_PERL) || defined(WITH_LUA)
struct stat st;
- struct perl_module *cur;
+ struct script_module *cur;
if (stat ($3, &st) == -1) {
yyerror ("yyparse: cannot stat file %s, %s", $3, strerror (errno));
YYERROR;
}
- cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct perl_module));
+ cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct script_module));
if (cur == NULL) {
yyerror ("yyparse: g_malloc: %s", strerror(errno));
YYERROR;
}
cur->path = $3;
- cfg->perl_modules = g_list_prepend (cfg->perl_modules, cur);
+ cfg->script_modules = g_list_prepend (cfg->script_modules, cur);
#else
yyerror ("require command is not available when perl support is not compiled");
YYERROR;
#include "perl.h"
#endif
#ifdef WITH_LUA
-#include "lua-rspamd.h"
+#include "lua/lua_common.h"
#endif
void
+++ /dev/null
-#ifndef RSPAMD_LUA_H
-#define RSPAMD_LUA_H
-
-#include "config.h"
-
-struct uri;
-struct worker_task;
-struct config_file;
-
-void init_lua_filters (struct config_file *cfg);
-
-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);
-
-#endif
+++ /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 "config.h"
-#include "url.h"
-#include "main.h"
-#include "message.h"
-#include "lua-rspamd.h"
-#include "cfg_file.h"
-
-#include <lua.h>
-#include <lauxlib.h>
-#include <lualib.h>
-
-/* Lua module init function */
-#define MODULE_INIT_FUNC "module_init"
-
-/* Interface definitions */
-#define LUA_FUNCTION_DEF(class, name) static int lua_##class##_##name(lua_State *L)
-#define LUA_INTERFACE_DEF(class, name) { #name, lua_##class##_##name }
-
-#define LUA_GMIME_BRIDGE_GET(class, name, mime_class) \
-static int \
-lua_##class##_##name(lua_State *L) \
-{ \
- GMime##mime_class *obj = lua_check_##class(L); \
- if (obj != NULL) { \
- lua_pushstring (L, g_mime_##class##_##name(obj)); \
- } \
- else { \
- lua_pushnil (L); \
- } \
- return 1; \
-}
-
-#define LUA_GMIME_BRIDGE_SET(class, name, mime_class) \
-static int \
-lua_##class##_##name(lua_State *L) \
-{ \
- const char *str; \
- GMime##mime_class *obj = lua_check_##class(L); \
- if (obj != NULL) { \
- str = luaL_checkstring (L, 2); \
- g_mime_##class##_##name(obj, str); \
- } \
- else { \
- lua_pushnil (L); \
- } \
- return 1; \
-}
-
-lua_State *L = NULL;
-
-/* Task methods */
-LUA_FUNCTION_DEF(task, get_message);
-LUA_FUNCTION_DEF(task, insert_result);
-LUA_FUNCTION_DEF(task, get_urls);
-
-static const struct luaL_reg tasklib_m[] = {
- LUA_INTERFACE_DEF(task, get_message),
- LUA_INTERFACE_DEF(task, insert_result),
- LUA_INTERFACE_DEF(task, get_urls),
- {NULL, NULL},
-};
-
-/* Message methods */
-LUA_FUNCTION_DEF(message, get_subject);
-LUA_FUNCTION_DEF(message, set_subject);
-LUA_FUNCTION_DEF(message, get_message_id);
-LUA_FUNCTION_DEF(message, set_message_id);
-LUA_FUNCTION_DEF(message, get_sender);
-LUA_FUNCTION_DEF(message, set_sender);
-LUA_FUNCTION_DEF(message, get_reply_to);
-LUA_FUNCTION_DEF(message, set_reply_to);
-LUA_FUNCTION_DEF(message, get_header);
-LUA_FUNCTION_DEF(message, set_header);
-
-static const struct luaL_reg msglib_m[] = {
- LUA_INTERFACE_DEF(message, get_subject),
- LUA_INTERFACE_DEF(message, set_subject),
- LUA_INTERFACE_DEF(message, get_message_id),
- LUA_INTERFACE_DEF(message, set_message_id),
- LUA_INTERFACE_DEF(message, get_sender),
- LUA_INTERFACE_DEF(message, set_sender),
- LUA_INTERFACE_DEF(message, get_reply_to),
- LUA_INTERFACE_DEF(message, set_reply_to),
- LUA_INTERFACE_DEF(message, get_header),
- LUA_INTERFACE_DEF(message, set_header),
- {NULL, NULL}
-};
-
-void
-lua_newclass (lua_State *L, const char *classname, const struct luaL_reg *func)
-{
- luaL_newmetatable (L, classname); /* mt */
- /* create __index table to place methods */
- lua_pushstring (L, "__index"); /* mt,"__index" */
- lua_newtable (L); /* mt,"__index",it */
- /* put class name into class metatable */
- lua_pushstring (L, "class"); /* mt,"__index",it,"class" */
- lua_pushstring (L, classname); /* mt,"__index",it,"class",classname */
- lua_rawset (L, -3); /* mt,"__index",it */
- /* pass all methods that start with _ to the metatable, and all others
- * to the index table */
- for (; func->name; func++) { /* mt,"__index",it */
- lua_pushstring (L, func->name);
- lua_pushcfunction (L, func->func);
- lua_rawset (L, func->name[0] == '_' ? -5: -3);
- }
- lua_rawset (L, -3); /* mt */
- lua_pop (L, 1);
-}
-
-void lua_setclass (lua_State *L, const char *classname, int objidx)
-{
- luaL_getmetatable (L, classname);
- if (objidx < 0) {
- objidx--;
- }
- lua_setmetatable (L, objidx);
-}
-
-static struct worker_task *
-lua_check_task (lua_State *L)
-{
- void *ud = luaL_checkudata (L, 1, "Rspamd.task");
- luaL_argcheck (L, ud != NULL, 1, "'task' expected");
- return (struct worker_task *)ud;
-}
-
-static GMimeMessage *
-lua_check_message (lua_State *L)
-{
- void *ud = luaL_checkudata (L, 1, "Rspamd.message");
- luaL_argcheck (L, ud != NULL, 1, "'message' expected");
- return (GMimeMessage *)ud;
-}
-/*** Task interface ***/
-static int
-lua_task_get_message (lua_State *L)
-{
- GMimeMessage **pmsg;
- struct worker_task *task = lua_check_task (L);
-
- if (task != NULL) {
- /* XXX write handler for message object */
- pmsg = lua_newuserdata (L, sizeof (GMimeMessage *));
- lua_setclass (L, "Rspamd.message", -1);
- *pmsg = task->message;
- }
- return 1;
-}
-
-static int
-lua_task_insert_result (lua_State *L)
-{
- struct worker_task *task = lua_check_task (L);
- const char *metric_name, *symbol_name;
- double flag;
-
- if (task != NULL) {
- metric_name = luaL_checkstring (L, 2);
- symbol_name = luaL_checkstring (L, 3);
- flag = luaL_checknumber (L, 4);
- insert_result (task, metric_name, symbol_name, flag, NULL);
- }
- return 1;
-}
-
-static int
-lua_task_get_urls (lua_State *L)
-{
- struct worker_task *task = lua_check_task (L);
- struct uri *url;
-
- if (task != NULL) {
- TAILQ_FOREACH (url, &task->urls, next) {
- lua_pushstring (L, struri (url));
- }
- }
- return 1;
-}
-
-/*** Message interface ***/
-
-LUA_GMIME_BRIDGE_GET(message, get_subject, Message)
-LUA_GMIME_BRIDGE_SET(message, set_subject, Message)
-LUA_GMIME_BRIDGE_GET(message, get_message_id, Message)
-LUA_GMIME_BRIDGE_SET(message, set_message_id, Message)
-LUA_GMIME_BRIDGE_GET(message, get_sender, Message)
-LUA_GMIME_BRIDGE_SET(message, set_sender, Message)
-LUA_GMIME_BRIDGE_GET(message, get_reply_to, Message)
-LUA_GMIME_BRIDGE_SET(message, set_reply_to, Message)
-
-static int
-lua_message_get_header (lua_State *L)
-{
- const char *headern;
- GMimeMessage *obj = lua_check_message (L);
- GList *res = NULL, *cur;
-
- if (obj != NULL) {
- headern = luaL_checkstring (L, 2);
- if (headern) {
- res = message_get_header (NULL, obj, headern);
- if (res) {
- cur = res;
- while (cur) {
- lua_pushstring (L, (const char *)cur->data);
- g_free (cur->data);
- cur = g_list_next (cur);
- }
- g_free (res);
- }
- else {
- lua_pushnil (L);
- }
- }
- else {
- lua_pushnil (L);
- }
- }
- else {
- lua_pushnil (L);
- }
-
- return 1;
-}
-
-static int
-lua_message_set_header (lua_State *L)
-{
- const char *headern, *headerv;
- GMimeMessage *obj = lua_check_message (L);
-
- if (obj != NULL) {
- headern = luaL_checkstring (L, 2);
- headerv = luaL_checkstring (L, 3);
- if (headern && headerv) {
- message_set_header (obj, headern, headerv);
- }
- else {
- lua_pushnil (L);
- }
- }
- else {
- lua_pushnil (L);
- }
-
- return 1;
-}
-
-/*** Init functions ***/
-static int
-luaopen_task (lua_State *L)
-{
- lua_newclass (L, "Rspamd.task", tasklib_m);
-
- luaL_openlib (L, "task", tasklib_m, 0);
-
- return 1;
-}
-
-static int
-luaopen_message (lua_State *L)
-{
- lua_newclass (L, "Rspamd.message", msglib_m);
-
- luaL_openlib (L, "message", msglib_m, 0);
-
- return 1;
-}
-
-static void
-init_lua ()
-{
- if (L == NULL) {
- L = lua_open ();
- luaL_openlibs (L);
-
- luaopen_task (L);
- luaopen_message (L);
- }
-}
-
-void
-init_lua_filters (struct config_file *cfg)
-{
- struct perl_module *module;
- char *init_func;
- size_t funclen;
- struct config_file **pcfg;
-
- init_lua ();
- LIST_FOREACH (module, &cfg->perl_modules, next) {
- if (module->path) {
- luaL_loadfile (L, module->path);
-
- /* Call module init function */
- funclen = strlen (module->path) + sizeof (":") + sizeof (MODULE_INIT_FUNC) - 1;
- init_func = g_malloc (funclen);
- snprintf (init_func, funclen, "%s:%s", module->path, MODULE_INIT_FUNC);
- lua_getglobal (L, init_func);
- pcfg = lua_newuserdata (L, sizeof (struct config_file *));
- lua_setclass (L, "Rspamd.config", -1);
- *pcfg = cfg;
- /* do the call (1 arguments, 1 result) */
- if (lua_pcall (L, 1, 1, 0) != 0) {
- msg_info ("lua_init_filters: call to %s failed", init_func);
- }
- }
- }
-}
-
-
-int
-lua_call_filter (const char *function, struct worker_task *task)
-{
- int result;
- struct worker_task **ptask;
-
- lua_getglobal (L, function);
- ptask = lua_newuserdata (L, sizeof (struct worker_task *));
- lua_setclass (L, "Rspamd.task", -1);
- *ptask = task;
-
- if (lua_pcall (L, 1, 1, 0) != 0) {
- msg_info ("lua_init_filters: call to %s failed", function);
- }
-
- /* retrieve result */
- if (!lua_isnumber (L, -1)) {
- msg_info ("lua_call_header_filter: function %s must return a number", function);
- }
- result = lua_tonumber (L, -1);
- lua_pop (L, 1); /* pop returned value */
- return result;
-}
-
-int
-lua_call_chain_filter (const char *function, struct worker_task *task, int *marks, unsigned int number)
-{
- int result, i;
-
- lua_getglobal (L, function);
-
- for (i = 0; i < number; i ++) {
- lua_pushnumber (L, marks[i]);
- }
- if (lua_pcall (L, number, 1, 0) != 0) {
- msg_info ("lua_init_filters: call to %s failed", function);
- }
-
- /* retrieve result */
- if (!lua_isnumber (L, -1)) {
- msg_info ("lua_call_header_filter: function %s must return a number", function);
- }
- result = lua_tonumber (L, -1);
- lua_pop (L, 1); /* pop returned value */
- return result;
-}
-
-/*
- * LUA custom consolidation function
- */
-struct consolidation_callback_data {
- struct worker_task *task;
- double score;
- const char *func;
-};
-
-static void
-lua_consolidation_callback (gpointer key, gpointer value, gpointer arg)
-{
- double res;
- struct symbol *s = (struct symbol *)value;
- struct consolidation_callback_data *data = (struct consolidation_callback_data *)arg;
-
- lua_getglobal (L, data->func);
-
- lua_pushstring (L, (const char *)key);
- lua_pushnumber (L, s->score);
- if (lua_pcall (L, 2, 1, 0) != 0) {
- msg_info ("lua_consolidation_callback: call to %s failed", data->func);
- }
-
- /* retrieve result */
- if (!lua_isnumber (L, -1)) {
- msg_info ("lua_consolidation_callback: function %s must return a number", data->func);
- }
- res = lua_tonumber (L, -1);
- lua_pop (L, 1); /* pop returned value */
- data->score += res;
-}
-
-double
-lua_consolidation_func (struct worker_task *task, const char *metric_name, const char *function_name)
-{
- struct metric_result *metric_res;
- double res = 0.;
- struct consolidation_callback_data data = { task, 0, function_name };
-
- if (function_name == NULL) {
- return 0;
- }
-
- metric_res = g_hash_table_lookup (task->results, metric_name);
- if (metric_res == NULL) {
- return res;
- }
-
- g_hash_table_foreach (metric_res->symbols, lua_consolidation_callback, &data);
-
- return data.score;
-}
-
-void
-add_luabuf (const char *line)
-{
- int error;
- init_lua ();
-
- error = luaL_loadbuffer(L, line, strlen(line), "config") ||
- lua_pcall(L, 0, 0, 0);
- if (error) {
- yyerror ("lua error: %s", lua_tostring(L, -1));
- lua_pop(L, 1); /* pop error message from the stack */
- }
-}
--- /dev/null
+# Lua support makefile
+SET(LUASRC lua_common.c
+ lua_task.c
+ lua_message.c
+ lua_config.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"
+
+/* Lua module init function */
+#define MODULE_INIT_FUNC "module_init"
+
+lua_State *L = NULL;
+
+/* Logger methods */
+LUA_FUNCTION_DEF(logger, err);
+LUA_FUNCTION_DEF(logger, warn);
+LUA_FUNCTION_DEF(logger, info);
+LUA_FUNCTION_DEF(logger, debug);
+
+static const struct luaL_reg loggerlib_m[] = {
+ LUA_INTERFACE_DEF(logger, err),
+ LUA_INTERFACE_DEF(logger, warn),
+ LUA_INTERFACE_DEF(logger, info),
+ LUA_INTERFACE_DEF(logger, debug),
+ {NULL, NULL}
+};
+
+
+void
+lua_newclass (lua_State *L, const char *classname, const struct luaL_reg *func)
+{
+ luaL_newmetatable (L, classname); /* mt */
+ /* create __index table to place methods */
+ lua_pushstring (L, "__index"); /* mt,"__index" */
+ lua_newtable (L); /* mt,"__index",it */
+ /* put class name into class metatable */
+ lua_pushstring (L, "class"); /* mt,"__index",it,"class" */
+ lua_pushstring (L, classname); /* mt,"__index",it,"class",classname */
+ lua_rawset (L, -3); /* mt,"__index",it */
+ /* pass all methods that start with _ to the metatable, and all others
+ * to the index table */
+ for (; func->name; func++) { /* mt,"__index",it */
+ lua_pushstring (L, func->name);
+ lua_pushcfunction (L, func->func);
+ lua_rawset (L, func->name[0] == '_' ? -5: -3);
+ }
+ lua_rawset (L, -3); /* mt */
+ lua_pop (L, 1);
+}
+
+void lua_setclass (lua_State *L, const char *classname, int objidx)
+{
+ luaL_getmetatable (L, classname);
+ if (objidx < 0) {
+ objidx--;
+ }
+ lua_setmetatable (L, objidx);
+}
+
+
+
+/*** Logger interface ***/
+static int
+lua_logger_err (lua_State *L)
+{
+ const char *msg;
+ msg = luaL_checkstring (L, 2);
+ msg_err (msg);
+ return 1;
+}
+
+static int
+lua_logger_warn (lua_State *L)
+{
+ const char *msg;
+ msg = luaL_checkstring (L, 2);
+ msg_warn (msg);
+ return 1;
+}
+
+static int
+lua_logger_info (lua_State *L)
+{
+ const char *msg;
+ msg = luaL_checkstring (L, 2);
+ msg_info (msg);
+ return 1;
+}
+
+static int
+lua_logger_debug (lua_State *L)
+{
+ const char *msg;
+ msg = luaL_checkstring (L, 2);
+ msg_debug (msg);
+ return 1;
+}
+
+
+/*** Init functions ***/
+
+int
+luaopen_logger (lua_State *L)
+{
+ lua_newclass (L, "Rspamd.logger", loggerlib_m);
+ luaL_openlib (L, "logger", loggerlib_m, 0);
+
+ return 1;
+}
+
+static void
+init_lua ()
+{
+ if (L == NULL) {
+ L = lua_open ();
+ luaL_openlibs (L);
+
+ luaopen_task (L);
+ luaopen_message (L);
+ luaopen_logger (L);
+ }
+}
+
+void
+init_lua_filters (struct config_file *cfg)
+{
+ char *init_func;
+ size_t funclen;
+ struct config_file **pcfg;
+ GList *cur;
+ struct script_module *module;
+
+ init_lua ();
+ cur = g_list_first (cfg->script_modules);
+ while (cur) {
+ module = cur->data;
+ if (module->path) {
+ luaL_loadfile (L, module->path);
+
+ /* Call module init function */
+ funclen = strlen (module->path) + sizeof (":") + sizeof (MODULE_INIT_FUNC) - 1;
+ init_func = g_malloc (funclen);
+ snprintf (init_func, funclen, "%s:%s", module->path, MODULE_INIT_FUNC);
+ lua_getglobal (L, init_func);
+ pcfg = lua_newuserdata (L, sizeof (struct config_file *));
+ lua_setclass (L, "Rspamd.config", -1);
+ *pcfg = cfg;
+ /* do the call (1 arguments, 1 result) */
+ if (lua_pcall (L, 1, 1, 0) != 0) {
+ msg_info ("lua_init_filters: call to %s failed", init_func);
+ }
+ }
+ cur = g_list_next (cur);
+ }
+}
+
+/* Callback functions */
+
+int
+lua_call_filter (const char *function, struct worker_task *task)
+{
+ int result;
+ struct worker_task **ptask;
+
+ lua_getglobal (L, function);
+ ptask = lua_newuserdata (L, sizeof (struct worker_task *));
+ lua_setclass (L, "Rspamd.task", -1);
+ *ptask = task;
+
+ if (lua_pcall (L, 1, 1, 0) != 0) {
+ msg_info ("lua_call_filter: call to %s failed", function);
+ }
+
+ /* retrieve result */
+ if (!lua_isnumber (L, -1)) {
+ msg_info ("lua_call_filter: function %s must return a number", function);
+ }
+ result = lua_tonumber (L, -1);
+ lua_pop (L, 1); /* pop returned value */
+ return result;
+}
+
+int
+lua_call_chain_filter (const char *function, struct worker_task *task, int *marks, unsigned int number)
+{
+ int result, i;
+
+ lua_getglobal (L, function);
+
+ for (i = 0; i < number; i ++) {
+ lua_pushnumber (L, marks[i]);
+ }
+ if (lua_pcall (L, number, 1, 0) != 0) {
+ msg_info ("lua_init_filters: call to %s failed", function);
+ }
+
+ /* retrieve result */
+ if (!lua_isnumber (L, -1)) {
+ msg_info ("lua_call_header_filter: function %s must return a number", function);
+ }
+ result = lua_tonumber (L, -1);
+ lua_pop (L, 1); /* pop returned value */
+ return result;
+}
+
+/*
+ * LUA custom consolidation function
+ */
+struct consolidation_callback_data {
+ struct worker_task *task;
+ double score;
+ const char *func;
+};
+
+static void
+lua_consolidation_callback (gpointer key, gpointer value, gpointer arg)
+{
+ double res;
+ struct symbol *s = (struct symbol *)value;
+ struct consolidation_callback_data *data = (struct consolidation_callback_data *)arg;
+
+ lua_getglobal (L, data->func);
+
+ lua_pushstring (L, (const char *)key);
+ lua_pushnumber (L, s->score);
+ if (lua_pcall (L, 2, 1, 0) != 0) {
+ msg_info ("lua_consolidation_callback: call to %s failed", data->func);
+ }
+
+ /* retrieve result */
+ if (!lua_isnumber (L, -1)) {
+ msg_info ("lua_consolidation_callback: function %s must return a number", data->func);
+ }
+ res = lua_tonumber (L, -1);
+ lua_pop (L, 1); /* pop returned value */
+ data->score += res;
+}
+
+double
+lua_consolidation_func (struct worker_task *task, const char *metric_name, const char *function_name)
+{
+ struct metric_result *metric_res;
+ double res = 0.;
+ struct consolidation_callback_data data = { task, 0, function_name };
+
+ if (function_name == NULL) {
+ return 0;
+ }
+
+ metric_res = g_hash_table_lookup (task->results, metric_name);
+ if (metric_res == NULL) {
+ return res;
+ }
+
+ g_hash_table_foreach (metric_res->symbols, lua_consolidation_callback, &data);
+
+ return data.score;
+}
+
+void
+add_luabuf (const char *line)
+{
+ int error;
+ init_lua ();
+
+ error = luaL_loadbuffer(L, line, strlen(line), "config") ||
+ lua_pcall(L, 0, 0, 0);
+ if (error) {
+ yyerror ("lua error: %s", lua_tostring(L, -1));
+ lua_pop(L, 1); /* pop error message from the stack */
+ }
+}
--- /dev/null
+#ifndef RSPAMD_LUA_H
+#define RSPAMD_LUA_H
+
+#include "../config.h"
+#include "../main.h"
+#include "../cfg_file.h"
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+/* Interface definitions */
+#define LUA_FUNCTION_DEF(class, name) static int lua_##class##_##name(lua_State *L)
+#define LUA_INTERFACE_DEF(class, name) { #name, lua_##class##_##name }
+
+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);
+int luaopen_message (lua_State *L);
+int luaopen_task (lua_State *L);
+int luaopen_config (lua_State *L);
+void init_lua_filters (struct config_file *cfg);
+
+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);
+
+#endif
--- /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"
+
+/* Config file methods */
+LUA_FUNCTION_DEF(config, get_module_opt);
+LUA_FUNCTION_DEF(config, get_metric);
+LUA_FUNCTION_DEF(config, get_all_opt);
+
+static const struct luaL_reg configlib_m[] = {
+ LUA_INTERFACE_DEF(config, get_module_opt),
+ LUA_INTERFACE_DEF(config, get_metric),
+ LUA_INTERFACE_DEF(config, get_all_opt),
+ {NULL, NULL}
+};
+
+static struct config_file *
+lua_check_config (lua_State *L)
+{
+ void *ud = luaL_checkudata (L, 1, "Rspamd.config");
+ luaL_argcheck (L, ud != NULL, 1, "'config' expected");
+ return (struct config_file *)ud;
+}
+
+
+/*** Config functions ***/
+static int
+lua_config_get_module_opt (lua_State *L)
+{
+ struct config_file *cfg = lua_check_config (L);
+ const char *mname, *optname, *val;
+
+ if (cfg) {
+ mname = luaL_checkstring (L, 2);
+ optname = luaL_checkstring (L, 3);
+
+ if (mname && optname) {
+ val = get_module_opt (cfg, (char *)mname, (char *)optname);
+ if (val) {
+ lua_pushstring (L, val);
+ return 1;
+ }
+ }
+ }
+ lua_pushnil (L);
+ return 1;
+}
+
+static int
+lua_config_get_metric (lua_State *L)
+{
+ struct config_file *cfg = lua_check_config (L);
+ struct metric *metric, **pmetric;
+ const char *name;
+
+ if (cfg) {
+ name = luaL_checkstring (L, 2);
+ metric = g_hash_table_lookup (cfg->metrics, name);
+ if (metric) {
+ pmetric = lua_newuserdata (L, sizeof (struct metric *));
+ lua_setclass (L, "Rspamd.metric", -1);
+ *pmetric = metric;
+ }
+ }
+ lua_pushnil (L);
+ return 1;
+
+}
+
+int
+luaopen_config (lua_State *L)
+{
+ lua_newclass (L, "Rspamd.config", configlib_m);
+ luaL_openlib (L, "config", configlib_m, 0);
+
+ return 1;
+}
+
--- /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"
+#include "../message.h"
+
+#define LUA_GMIME_BRIDGE_GET(class, name, mime_class) \
+static int \
+lua_##class##_##name(lua_State *L) \
+{ \
+ GMime##mime_class *obj = lua_check_##class(L); \
+ if (obj != NULL) { \
+ lua_pushstring (L, g_mime_##class##_##name(obj)); \
+ } \
+ else { \
+ lua_pushnil (L); \
+ } \
+ return 1; \
+}
+
+#define LUA_GMIME_BRIDGE_SET(class, name, mime_class) \
+static int \
+lua_##class##_##name(lua_State *L) \
+{ \
+ const char *str; \
+ GMime##mime_class *obj = lua_check_##class(L); \
+ if (obj != NULL) { \
+ str = luaL_checkstring (L, 2); \
+ g_mime_##class##_##name(obj, str); \
+ } \
+ else { \
+ lua_pushnil (L); \
+ } \
+ return 1; \
+}
+
+/* Message methods */
+LUA_FUNCTION_DEF(message, get_subject);
+LUA_FUNCTION_DEF(message, set_subject);
+LUA_FUNCTION_DEF(message, get_message_id);
+LUA_FUNCTION_DEF(message, set_message_id);
+LUA_FUNCTION_DEF(message, get_sender);
+LUA_FUNCTION_DEF(message, set_sender);
+LUA_FUNCTION_DEF(message, get_reply_to);
+LUA_FUNCTION_DEF(message, set_reply_to);
+LUA_FUNCTION_DEF(message, get_header);
+LUA_FUNCTION_DEF(message, set_header);
+
+static const struct luaL_reg msglib_m[] = {
+ LUA_INTERFACE_DEF(message, get_subject),
+ LUA_INTERFACE_DEF(message, set_subject),
+ LUA_INTERFACE_DEF(message, get_message_id),
+ LUA_INTERFACE_DEF(message, set_message_id),
+ LUA_INTERFACE_DEF(message, get_sender),
+ LUA_INTERFACE_DEF(message, set_sender),
+ LUA_INTERFACE_DEF(message, get_reply_to),
+ LUA_INTERFACE_DEF(message, set_reply_to),
+ LUA_INTERFACE_DEF(message, get_header),
+ LUA_INTERFACE_DEF(message, set_header),
+ {NULL, NULL}
+};
+
+
+
+static GMimeMessage *
+lua_check_message (lua_State *L)
+{
+ void *ud = luaL_checkudata (L, 1, "Rspamd.message");
+ luaL_argcheck (L, ud != NULL, 1, "'message' expected");
+ return (GMimeMessage *)ud;
+}
+
+
+/*** Message interface ***/
+
+LUA_GMIME_BRIDGE_GET(message, get_subject, Message)
+LUA_GMIME_BRIDGE_SET(message, set_subject, Message)
+LUA_GMIME_BRIDGE_GET(message, get_message_id, Message)
+LUA_GMIME_BRIDGE_SET(message, set_message_id, Message)
+LUA_GMIME_BRIDGE_GET(message, get_sender, Message)
+LUA_GMIME_BRIDGE_SET(message, set_sender, Message)
+LUA_GMIME_BRIDGE_GET(message, get_reply_to, Message)
+LUA_GMIME_BRIDGE_SET(message, set_reply_to, Message)
+
+static int
+lua_message_get_header (lua_State *L)
+{
+ const char *headern;
+ GMimeMessage *obj = lua_check_message (L);
+ GList *res = NULL, *cur;
+
+ if (obj != NULL) {
+ headern = luaL_checkstring (L, 2);
+ if (headern) {
+ res = message_get_header (NULL, obj, headern);
+ if (res) {
+ cur = res;
+ while (cur) {
+ lua_pushstring (L, (const char *)cur->data);
+ g_free (cur->data);
+ cur = g_list_next (cur);
+ }
+ g_free (res);
+ }
+ else {
+ lua_pushnil (L);
+ }
+ }
+ else {
+ lua_pushnil (L);
+ }
+ }
+ else {
+ lua_pushnil (L);
+ }
+
+ return 1;
+}
+
+static int
+lua_message_set_header (lua_State *L)
+{
+ const char *headern, *headerv;
+ GMimeMessage *obj = lua_check_message (L);
+
+ if (obj != NULL) {
+ headern = luaL_checkstring (L, 2);
+ headerv = luaL_checkstring (L, 3);
+ if (headern && headerv) {
+ message_set_header (obj, headern, headerv);
+ }
+ else {
+ lua_pushnil (L);
+ }
+ }
+ else {
+ lua_pushnil (L);
+ }
+
+ return 1;
+}
+
+int
+luaopen_message (lua_State *L)
+{
+ lua_newclass (L, "Rspamd.message", msglib_m);
+ luaL_openlib (L, "message", msglib_m, 0);
+
+ return 1;
+}
--- /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"
+
+/* Task methods */
+LUA_FUNCTION_DEF(task, get_message);
+LUA_FUNCTION_DEF(task, insert_result);
+LUA_FUNCTION_DEF(task, get_urls);
+
+static const struct luaL_reg tasklib_m[] = {
+ LUA_INTERFACE_DEF(task, get_message),
+ LUA_INTERFACE_DEF(task, insert_result),
+ LUA_INTERFACE_DEF(task, get_urls),
+ {NULL, NULL}
+};
+
+static struct worker_task *
+lua_check_task (lua_State *L)
+{
+ void *ud = luaL_checkudata (L, 1, "Rspamd.task");
+ luaL_argcheck (L, ud != NULL, 1, "'task' expected");
+ return (struct worker_task *)ud;
+}
+
+/*** Task interface ***/
+static int
+lua_task_get_message (lua_State *L)
+{
+ GMimeMessage **pmsg;
+ struct worker_task *task = lua_check_task (L);
+
+ if (task != NULL) {
+ /* XXX write handler for message object */
+ pmsg = lua_newuserdata (L, sizeof (GMimeMessage *));
+ lua_setclass (L, "Rspamd.message", -1);
+ *pmsg = task->message;
+ }
+ return 1;
+}
+
+static int
+lua_task_insert_result (lua_State *L)
+{
+ struct worker_task *task = lua_check_task (L);
+ const char *metric_name, *symbol_name;
+ double flag;
+
+ if (task != NULL) {
+ metric_name = luaL_checkstring (L, 2);
+ symbol_name = luaL_checkstring (L, 3);
+ flag = luaL_checknumber (L, 4);
+ insert_result (task, metric_name, symbol_name, flag, NULL);
+ }
+ return 1;
+}
+
+static int
+lua_task_get_urls (lua_State *L)
+{
+ struct worker_task *task = lua_check_task (L);
+ GList *cur;
+ struct uri *url;
+
+ if (task != NULL) {
+ cur = g_list_first (task->urls);
+ while (cur) {
+ url = cur->data;
+ lua_pushstring (L, struri (url));
+ cur = g_list_next (cur);
+ }
+ }
+
+ return 1;
+}
+
+
+int
+luaopen_task (lua_State *L)
+{
+ lua_newclass (L, "Rspamd.task", tasklib_m);
+ luaL_openlib (L, "task", tasklib_m, 0);
+
+ return 1;
+}
+
#include "perl.h"
#elif defined(WITH_LUA)
-#include "lua-rspamd.h"
+#include "lua/lua_common.h"
#endif
/* 2 seconds to fork new process in place of dead one */