* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <contrib/libucl/ucl.h>
#include "config.h"
#include "util.h"
#include "cfg_file.h"
enum rspamd_mime_atom_type {
MIME_ATOM_REGEXP = 0,
MIME_ATOM_INTERNAL_FUNCTION,
- MIME_ATOM_LUA_FUNCTION
+ MIME_ATOM_LUA_FUNCTION,
+ MIME_ATOM_LOCAL_LUA_FUNCTION, /* New style */
};
struct rspamd_mime_atom {
struct rspamd_regexp_atom *re;
struct rspamd_function_atom *func;
const gchar *lua_function;
+ gint lua_cbref;
} d;
enum rspamd_mime_atom_type type;
};
rspamd_expression_atom_t *a = NULL;
struct rspamd_mime_atom *mime_atom = NULL;
const gchar *p, *end;
- struct rspamd_config *cfg = ud;
+ struct rspamd_mime_expr_ud *real_ud = (struct rspamd_mime_expr_ud *)ud;
+ struct rspamd_config *cfg;
rspamd_regexp_t *own_re;
gchar t;
gint type = MIME_ATOM_REGEXP, obraces = 0, ebraces = 0;
p = line;
end = p + len;
+ cfg = real_ud->cfg;
while (p < end) {
t = *p;
state = got_obrace;
}
else if (!g_ascii_isalnum (t) && t != '_' && t != '-' && t != '=') {
- /* Likely lua function, identified by just a string */
- type = MIME_ATOM_LUA_FUNCTION;
- state = end_atom;
- /* Do not increase p */
- continue;
+ if (t == ':') {
+ if (p - line == 3 && memcmp (line, "lua", 3) == 0) {
+ type = MIME_ATOM_LOCAL_LUA_FUNCTION;
+ state = end_atom;
+ p ++;
+ continue;
+ }
+ }
+ else {
+ /* Likely lua function, identified by just a string */
+ type = MIME_ATOM_LUA_FUNCTION;
+ state = end_atom;
+ /* Do not increase p */
+ continue;
+ }
}
else if (g_ascii_isspace (t)) {
state = bad_atom;
mime_atom = rspamd_mempool_alloc (pool, sizeof (*mime_atom));
mime_atom->type = type;
- mime_atom->str = rspamd_mempool_alloc (pool, p - line + 1);
- rspamd_strlcpy (mime_atom->str, line, p - line + 1);
+
+ if (type != MIME_ATOM_LOCAL_LUA_FUNCTION) {
+ mime_atom->str = rspamd_mempool_alloc (pool, p - line + 1);
+ rspamd_strlcpy (mime_atom->str, line, p - line + 1);
+ }
+ else {
+ mime_atom->str = rspamd_mempool_alloc (pool, end - p + 1);
+ rspamd_strlcpy (mime_atom->str, p, end - p + 1);
+ }
if (type == MIME_ATOM_REGEXP) {
mime_atom->d.re = rspamd_mime_expr_parse_regexp_atom (pool,
goto err;
}
+
lua_pop (cfg->lua_state, 1);
}
+ else if (type == MIME_ATOM_LOCAL_LUA_FUNCTION) {
+ /* p pointer is set to the start of Lua function name */
+
+ if (real_ud->conf_obj == NULL) {
+ g_set_error (err, rspamd_mime_expr_quark(), 300,
+ "no config object for '%s'",
+ mime_atom->str);
+ goto err;
+ }
+
+ const ucl_object_t *functions = ucl_object_lookup (real_ud->conf_obj,
+ "functions");
+
+ if (functions == NULL) {
+ g_set_error (err, rspamd_mime_expr_quark(), 310,
+ "no functions defined for '%s'",
+ mime_atom->str);
+ goto err;
+ }
+
+ if (ucl_object_type (functions) != UCL_OBJECT) {
+ g_set_error (err, rspamd_mime_expr_quark(), 320,
+ "functions is not a table for '%s'",
+ mime_atom->str);
+ goto err;
+ }
+
+ const ucl_object_t *function_obj;
+
+ function_obj = ucl_object_lookup_len (functions, p,
+ end - p);
+
+ if (function_obj == NULL) {
+ g_set_error (err, rspamd_mime_expr_quark(), 320,
+ "function %*.s is not found for '%s'",
+ (int)(end - p), p, mime_atom->str);
+ goto err;
+ }
+
+ if (ucl_object_type (function_obj) != UCL_USERDATA) {
+ g_set_error (err, rspamd_mime_expr_quark(), 320,
+ "function %*.s has invalid type for '%s'",
+ (int)(end - p), p, mime_atom->str);
+ goto err;
+ }
+
+ struct ucl_lua_funcdata *fd = function_obj->value.ud;
+
+ mime_atom->d.lua_cbref = fd->idx;
+ }
else {
mime_atom->d.func = rspamd_mime_expr_parse_function_atom (pool,
mime_atom->str);
ret = 50;
break;
case MIME_ATOM_LUA_FUNCTION:
+ case MIME_ATOM_LOCAL_LUA_FUNCTION:
ret = 50;
break;
case MIME_ATOM_REGEXP:
lua_pop (L, 1);
}
}
+ else if (mime_atom->type == MIME_ATOM_LOCAL_LUA_FUNCTION) {
+ L = task->cfg->lua_state;
+ lua_rawgeti (L, LUA_REGISTRYINDEX, mime_atom->d.lua_cbref);
+ rspamd_lua_task_push (L, task);
+
+ if (lua_pcall (L, 1, 1, 0) != 0) {
+ msg_info_task ("lua call to local function for atom '%s' failed: %s",
+ mime_atom->str,
+ lua_tostring (L, -1));
+ lua_pop (L, 1);
+ }
+ else {
+ if (lua_type (L, -1) == LUA_TBOOLEAN) {
+ ret = lua_toboolean (L, -1);
+ }
+ else if (lua_type (L, -1) == LUA_TNUMBER) {
+ ret = lua_tonumber (L, 1);
+ }
+ else {
+ msg_err_task ("%s returned wrong return type: %s",
+ mime_atom->str, lua_typename (L, lua_type (L, -1)));
+ }
+ /* Remove result */
+ lua_pop (L, 1);
+ }
+ }
else {
ret = rspamd_mime_expr_process_function (mime_atom->d.func, task,
task->cfg->lua_state);
struct regexp_module_item *chain,
const gchar *symbol,
const gchar *line,
- struct rspamd_config *cfg)
+ struct rspamd_mime_expr_ud *ud)
{
struct rspamd_expression *e = NULL;
GError *err = NULL;
- if (!rspamd_parse_expression (line, 0, &mime_expr_subr, cfg, pool, &err,
+ if (!rspamd_parse_expression (line, 0, &mime_expr_subr, ud, pool, &err,
&e)) {
msg_warn_pool ("%s = \"%s\" is invalid regexp expression: %e", symbol,
line,
msg_warn_config ("regexp module is now single threaded, max_threads is ignored");
}
else if (value->type == UCL_STRING) {
+ struct rspamd_mime_expr_ud ud;
+
cur_item = rspamd_mempool_alloc0 (cfg->cfg_pool,
sizeof (struct regexp_module_item));
cur_item->symbol = ucl_object_key (value);
cur_item->magic = rspamd_regexp_cb_magic;
+ ud.conf_obj = NULL;
+ ud.cfg = cfg;
+
if (!read_regexp_expression (cfg->cfg_pool,
- cur_item, ucl_object_key (value),
- ucl_obj_tostring (value), cfg)) {
+ cur_item, ucl_object_key (value),
+ ucl_obj_tostring (value), &ud)) {
res = FALSE;
}
else {
gdouble score = 0.0;
guint flags = 0, priority = 0;
gboolean is_lua = FALSE, valid_expression = TRUE;
+ struct rspamd_mime_expr_ud ud;
/* We have some lua table, extract its arguments */
elt = ucl_object_lookup (value, "callback");
sizeof (struct regexp_module_item));
cur_item->symbol = ucl_object_key (value);
cur_item->magic = rspamd_regexp_cb_magic;
+ ud.cfg = cfg;
+ ud.conf_obj = elt;
if (!read_regexp_expression (cfg->cfg_pool,
cur_item, ucl_object_key (value),
- ucl_obj_tostring (elt), cfg)) {
+ ucl_obj_tostring (elt), &ud)) {
res = FALSE;
}
else {