From: Vsevolod Stakhov Date: Tue, 1 Sep 2009 16:02:31 +0000 (+0400) Subject: * New functionality to lua api: X-Git-Tag: 0.2.7~29 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=68ddc2c40e474e39496718d54d907314e4c74232;p=rspamd.git * New functionality to lua api: - config class - metric class - textpart class * Add documentation for lua module --- diff --git a/src/lua/lua_common.c b/src/lua/lua_common.c index eb93dce85..66ae67d58 100644 --- a/src/lua/lua_common.c +++ b/src/lua/lua_common.c @@ -43,7 +43,7 @@ static const struct luaL_reg loggerlib_m[] = { {NULL, NULL} }; - +/* Util functions */ void lua_newclass (lua_State *L, const char *classname, const struct luaL_reg *func) { @@ -66,7 +66,8 @@ lua_newclass (lua_State *L, const char *classname, const struct luaL_reg *func) lua_pop (L, 1); } -void lua_setclass (lua_State *L, const char *classname, int objidx) +void +lua_setclass (lua_State *L, const char *classname, int objidx) { luaL_getmetatable (L, classname); if (objidx < 0) { @@ -75,6 +76,15 @@ void lua_setclass (lua_State *L, const char *classname, int objidx) lua_setmetatable (L, objidx); } +/* assume that table is at the top */ +void +lua_set_table_index (lua_State *L, const char *index, const char *value) +{ + + lua_pushstring (L, index); + lua_pushstring (L, value); + lua_settable(L, -3); +} /*** Logger interface ***/ diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h index b72171e99..6c9152417 100644 --- a/src/lua/lua_common.h +++ b/src/lua/lua_common.h @@ -14,9 +14,11 @@ 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_message (lua_State *L); int luaopen_task (lua_State *L); int luaopen_config (lua_State *L); +int luaopen_metric (lua_State *L); void init_lua_filters (struct config_file *cfg); int lua_call_filter (const char *function, struct worker_task *task); diff --git a/src/lua/lua_config.c b/src/lua/lua_config.c index e88e53daf..7eb03f871 100644 --- a/src/lua/lua_config.c +++ b/src/lua/lua_config.c @@ -37,6 +37,14 @@ static const struct luaL_reg configlib_m[] = { {NULL, NULL} }; +/* Metric methods */ +LUA_FUNCTION_DEF(metric, register_symbol); + +static const struct luaL_reg metriclib_m[] = { + LUA_INTERFACE_DEF(metric, register_symbol), + {NULL, NULL} +}; + static struct config_file * lua_check_config (lua_State *L) { @@ -45,6 +53,13 @@ lua_check_config (lua_State *L) return (struct config_file *)ud; } +static struct metric * +lua_check_metric (lua_State *L) +{ + void *ud = luaL_checkudata (L, 1, "Rspamd.metric"); + luaL_argcheck (L, ud != NULL, 1, "'metric' expected"); + return (struct metric *)ud; +} /*** Config functions ***/ static int @@ -69,6 +84,38 @@ lua_config_get_module_opt (lua_State *L) return 1; } +static int +lua_config_get_all_opt (lua_State *L) +{ + struct config_file *cfg = lua_check_config (L); + const char *mname; + GList *cur_opt; + struct module_opt *cur; + + 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; + } + + lua_newtable (L); + while (cur_opt) { + cur = cur_opt->data; + lua_set_table_index (L, cur->param, cur->value); + cur_opt = g_list_next (cur_opt); + } + return 1; + } + } + lua_pushnil (L); + return 1; +} + + static int lua_config_get_metric (lua_State *L) { @@ -83,13 +130,60 @@ lua_config_get_metric (lua_State *L) pmetric = lua_newuserdata (L, sizeof (struct metric *)); lua_setclass (L, "Rspamd.metric", -1); *pmetric = metric; + return 1; } } + lua_pushnil (L); return 1; } +/*** Metric functions ***/ + +struct lua_callback_data { + const char *name; + lua_State *L; +}; + +static void +lua_metric_symbol_callback (struct worker_task *task, gpointer ud) +{ + struct lua_callback_data *cd = ud; + struct worker_task **ptask; + + lua_getglobal (cd->L, cd->name); + ptask = lua_newuserdata (cd->L, sizeof (struct worker_task *)); + lua_setclass (cd->L, "Rspamd.task", -1); + *ptask = task; + + if (lua_pcall(cd->L, 1, 1, 0) != 0) { + msg_warn ("lua_metric_symbol_callback: error running function %s: %s", + cd->name, lua_tostring(cd->L, -1)); + } +} + +static int +lua_metric_register_symbol (lua_State *L) +{ + struct metric *metric = lua_check_metric (L); + const char *name, *callback; + double weight; + struct lua_callback_data *cd; + + if (metric) { + name = luaL_checkstring (L, 2); + weight = luaL_checknumber (L, 3); + callback = luaL_checkstring (L, 4); + if (name) { + cd = g_malloc (sizeof (struct lua_callback_data)); + cd->name = g_strdup (name); + register_symbol (&metric->cache, name, weight, lua_metric_symbol_callback, cd); + } + } + return 1; +} + int luaopen_config (lua_State *L) { @@ -99,3 +193,11 @@ luaopen_config (lua_State *L) return 1; } +int +luaopen_metric (lua_State *L) +{ + lua_newclass (L, "Rspamd.metric", configlib_m); + luaL_openlib (L, "metric", configlib_m, 0); + + return 1; +} diff --git a/src/lua/lua_message.c b/src/lua/lua_message.c index 499945ccb..b178da0d4 100644 --- a/src/lua/lua_message.c +++ b/src/lua/lua_message.c @@ -162,6 +162,7 @@ lua_message_set_header (lua_State *L) return 1; } + int luaopen_message (lua_State *L) { @@ -170,3 +171,4 @@ luaopen_message (lua_State *L) return 1; } + diff --git a/src/lua/lua_task.c b/src/lua/lua_task.c index 2e2991265..e3f1e55d6 100644 --- a/src/lua/lua_task.c +++ b/src/lua/lua_task.c @@ -24,19 +24,37 @@ #include "lua_common.h" +#include "../message.h" /* Task methods */ LUA_FUNCTION_DEF(task, get_message); LUA_FUNCTION_DEF(task, insert_result); LUA_FUNCTION_DEF(task, get_urls); +LUA_FUNCTION_DEF(task, get_text_parts); 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), + LUA_INTERFACE_DEF(task, get_text_parts), {NULL, NULL} }; +/* Textpart methods */ +LUA_FUNCTION_DEF(textpart, get_content); +LUA_FUNCTION_DEF(textpart, is_empty); +LUA_FUNCTION_DEF(textpart, is_html); +LUA_FUNCTION_DEF(textpart, get_fuzzy); + +static const struct luaL_reg textpartlib_m[] = { + LUA_INTERFACE_DEF(textpart, get_content), + LUA_INTERFACE_DEF(textpart, is_empty), + LUA_INTERFACE_DEF(textpart, is_html), + LUA_INTERFACE_DEF(textpart, get_fuzzy), + {NULL, NULL} +}; + +/* Utility functions */ static struct worker_task * lua_check_task (lua_State *L) { @@ -45,6 +63,14 @@ lua_check_task (lua_State *L) return (struct worker_task *)ud; } +static struct mime_text_part * +lua_check_textpart (lua_State *L) +{ + void *ud = luaL_checkudata (L, 1, "Rspamd.textpart"); + luaL_argcheck (L, ud != NULL, 1, "'textpart' expected"); + return (struct mime_text_part *)ud; +} + /*** Task interface ***/ static int lua_task_get_message (lua_State *L) @@ -96,7 +122,90 @@ lua_task_get_urls (lua_State *L) return 1; } +static int +lua_task_get_text_parts (lua_State *L) +{ + + struct worker_task *task = lua_check_task (L); + GList *cur; + struct mime_text_part *part, **ppart; + + if (task != NULL) { + cur = task->text_parts; + while (cur) { + part = cur->data; + ppart = lua_newuserdata (L, sizeof (struct mime_text_part *)); + lua_setclass (L, "Rspamd.textpart", -1); + *ppart = part; + cur = g_list_next (cur); + } + } + lua_pushnil (L); + return 1; +} + +/**** Textpart implementation *****/ + +static int +lua_textpart_get_content (lua_State *L) +{ + struct mime_text_part *part = lua_check_textpart (L); + + if (part == NULL || part->is_empty) { + lua_pushnil (L); + return 1; + } + + lua_pushlstring (L, part->content->data, part->content->len); + + return 1; +} + +static int +lua_textpart_is_empty (lua_State *L) +{ + struct mime_text_part *part = lua_check_textpart (L); + + if (part == NULL) { + lua_pushnil (L); + return 1; + } + + lua_pushboolean (L, part->is_empty); + + return 1; +} + +static int +lua_textpart_is_html (lua_State *L) +{ + struct mime_text_part *part = lua_check_textpart (L); + + if (part == NULL) { + lua_pushnil (L); + return 1; + } + + lua_pushboolean (L, part->is_html); + + return 1; +} + +static int +lua_textpart_get_fuzzy (lua_State *L) +{ + struct mime_text_part *part = lua_check_textpart (L); + if (part == NULL || part->is_empty) { + lua_pushnil (L); + return 1; + } + + lua_pushlstring (L, part->fuzzy->hash_pipe, sizeof (part->fuzzy->hash_pipe)); + return 1; +} + +/* Init part */ int luaopen_task (lua_State *L) { @@ -106,3 +215,12 @@ luaopen_task (lua_State *L) return 1; } +int +luaopen_textpart (lua_State *L) +{ + lua_newclass (L, "Rspamd.textpart", textpartlib_m); + luaL_openlib (L, "textpart", textpartlib_m, 0); + + return 1; +} + diff --git a/src/lua/rspamd.luadoc b/src/lua/rspamd.luadoc new file mode 100644 index 000000000..b83832a29 --- /dev/null +++ b/src/lua/rspamd.luadoc @@ -0,0 +1,100 @@ +--- Rspamd interaction package +-- contains several subclasses: +-- config - for parsing config files +-- metric - for handling metrics callbacks +-- task - for interaction with task object +-- message - gate to GMime functions +-- textpart - a single textual part of message +module Rspamd + +--- Each lua module MUST have init function that is called after config file was read: +-- it should be like +-- function module:module_init(cfg) + +------------------------------------- CONFIG ----------------------------------------- +-- +--- Get module option from config +-- @param mname module name +-- @param option option +-- @return string with value +function config:get_module_opt (mname, option) + +--- Get all module options as a table like ['param' => 'value'] +-- @param mname module name +-- @return table with options +function config:get_all_opt (mname) + +--- Get specified metric +-- @param name metric name +-- @return metric object +function config:get_metric (name) + +------------------------------------- METRIC ----------------------------------------- + +--- Register symbol in metric +-- @param symbol name of symbol +-- @param weight weight of symbol +-- @param callback fucntion that would be called as callback for symbol +function metric:register_symbol (symbol, weight, callback) + +------------------------------------- TASK ------------------------------------------- + +--- Get message object from task +-- @return message object +function task:get_message () + +--- Insert result to specified metric with specified weight (obsoleted) +-- @param metric metric name +-- @param symbol symbol name +-- @param weight weight of symbol +function task:insert_result (metric, symbol, weight) + +--- Get all urls as array +-- @return array of urls in textual form +function task:get_urls () + +--- Get all text parts +-- @return array of textpart objects +function task:get_text_parts () + +------------------------------------- TEXTPART --------------------------------------- + +--- Get part's content +-- @return string that contains part's content +function textpart:get_content () + +--- Check if part is empty +-- @return boolean value +function textpart:is_empty () + +--- Check if part is html +-- @return boolean value +function textpart:is_html () + +--- Get part's fuzzy +-- @return string that contains part's fuzzy +function textpart:get_fuzzy () + +------------------------------------- MESSAGE ---------------------------------------- + +--- Get message subject +-- @return message subject +function message:get_subject () + +--- Get message id +-- @return message id +function message:get_message_id () + +--- Get sender of message +-- @return sender's credits +function message:get_sender () + +--- Get reply-to field +-- @return value of reply-to header +function message:get_reply_to () + +--- Get header +-- @param header_name name of header +-- @return array of headers with specified name +function message:get_header (header_name) +