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, gint offset)
+static void
+set_lua_globals (struct config_file *cfg, lua_State *L)
{
- gchar *val, *cur_dir, *lua_dir, *lua_file, *tmp1, *tmp2;
- lua_State *L = cfg->lua_state;
struct config_file **pcfg;
-
/* First check for global variable 'config' */
lua_getglobal (L, "config");
lua_newtable (L);
lua_setglobal (L, "config");
}
+
lua_getglobal (L, "metrics");
if (lua_isnil (L, -1)) {
lua_newtable (L);
lua_setglobal (L, "metrics");
}
+
lua_getglobal (L, "composites");
if (lua_isnil (L, -1)) {
lua_newtable (L);
lua_setglobal (L, "composites");
}
- lua_getglobal (L, "rspamd_config");
- if (lua_isnil (L, -1)) {
- pcfg = lua_newuserdata (L, sizeof (struct config_file *));
- lua_setclass (L, "rspamd{config}", -1);
- *pcfg = cfg;
- lua_setglobal (L, "rspamd_config");
- }
+
+ pcfg = lua_newuserdata (L, sizeof (struct config_file *));
+ lua_setclass (L, "rspamd{config}", -1);
+ *pcfg = cfg;
+ lua_setglobal (L, "rspamd_config");
+
+ /* Clear stack from globals */
+ lua_pop (L, 3);
+}
+
+/* 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, gint offset)
+{
+ gchar *val, *cur_dir, *lua_dir, *lua_file, *tmp1, *tmp2;
+ lua_State *L = cfg->lua_state;
+
/* Now config tables can be used for configuring rspamd */
/* First check "src" attribute */
if (attrs != NULL && (val = g_hash_table_lookup (attrs, "src")) != NULL) {
if (lua_dir && lua_file) {
cur_dir = g_malloc (PATH_MAX);
if (getcwd (cur_dir, PATH_MAX) != NULL && chdir (lua_dir) != -1) {
- if (luaL_dofile (L, lua_file) != 0) {
+ /* Load file */
+ if (luaL_loadfile (L, lua_file) != 0) {
msg_err ("cannot load lua file %s: %s", val, lua_tostring (L, -1));
if (chdir (cur_dir) == -1) {
msg_err ("cannot chdir to %s: %s", cur_dir, strerror (errno));;
g_free (tmp2);
return FALSE;
}
+ set_lua_globals (cfg, L);
+ /* Now do it */
+ if (lua_pcall (L, 0, LUA_MULTRET, 0) != 0) {
+ msg_err ("init of %s failed: %s", val, lua_tostring (L, -1));
+ if (chdir (cur_dir) == -1) {
+ msg_err ("cannot chdir to %s: %s", cur_dir, strerror (errno));;
+ }
+ g_free (cur_dir);
+ g_free (tmp1);
+ g_free (tmp2);
+ return FALSE;
+ }
}
else {
msg_err ("cannot chdir to %s: %s", lua_dir, strerror (errno));;
}
else if (data != NULL && *data != '\0') {
/* Try to load a string */
- if (luaL_dostring (L, data) != 0) {
+ if (luaL_loadstring (L, data) != 0) {
msg_err ("cannot load lua chunk: %s", lua_tostring (L, -1));
return FALSE;
}
+ set_lua_globals (cfg, L);
+ /* Now do it */
+ if (lua_pcall (L, 0, LUA_MULTRET, 0) != 0) {
+ msg_err ("init of lua chunk failed: %s", lua_tostring (L, -1));
+ return FALSE;
+ }
+
}
return TRUE;
}
extern const luaL_reg null_reg[];
-#define RSPAMD_LUA_API_VERSION 5
+#define RSPAMD_LUA_API_VERSION 6
/* Common utility functions */
void lua_newclass (lua_State *L, const gchar *classname, const struct luaL_reg *func);
LUA_FUNCTION_DEF (config, register_function);
LUA_FUNCTION_DEF (config, add_radix_map);
LUA_FUNCTION_DEF (config, add_hash_map);
+LUA_FUNCTION_DEF (config, add_kv_map);
LUA_FUNCTION_DEF (config, get_classifier);
LUA_FUNCTION_DEF (config, register_symbol);
LUA_FUNCTION_DEF (config, register_virtual_symbol);
LUA_INTERFACE_DEF (config, register_function),
LUA_INTERFACE_DEF (config, add_radix_map),
LUA_INTERFACE_DEF (config, add_hash_map),
+ LUA_INTERFACE_DEF (config, add_kv_map),
LUA_INTERFACE_DEF (config, get_classifier),
LUA_INTERFACE_DEF (config, register_symbol),
LUA_INTERFACE_DEF (config, register_virtual_symbol),
}
+static gint
+lua_config_add_kv_map (lua_State *L)
+{
+ struct config_file *cfg = lua_check_config (L);
+ const gchar *map_line;
+ GHashTable **r, ***ud;
+
+ if (cfg) {
+ map_line = luaL_checkstring (L, 2);
+ r = g_malloc (sizeof (GHashTable *));
+ *r = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal);
+ if (!add_map (map_line, read_kv_list, fin_kv_list, (void **)r)) {
+ msg_warn ("invalid hash map %s", map_line);
+ g_hash_table_destroy (*r);
+ g_free (r);
+ lua_pushnil (L);
+ return 1;
+ }
+ ud = lua_newuserdata (L, sizeof (GHashTable *));
+ *ud = r;
+ lua_setclass (L, "rspamd{hash_table}", -1);
+
+ return 1;
+ }
+
+ lua_pushnil (L);
+ return 1;
+
+}
+
/*** Metric functions ***/
lua_hash_table_get_key (lua_State * L)
{
GHashTable *tbl = lua_check_hash_table (L);
- const gchar *key;
+ const gchar *key, *value;
if (tbl) {
key = luaL_checkstring (L, 2);
- if (g_hash_table_lookup (tbl, key) != NULL) {
- lua_pushboolean (L, 1);
+ if ((value = g_hash_table_lookup (tbl, key)) != NULL) {
+ lua_pushstring (L, value);
return 1;
}
}
- lua_pushboolean (L, 0);
+ lua_pushnil (L);
return 1;
}
/**
* FSM for parsing lists
*/
+u_char *
+abstract_parse_kv_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data, insert_func func)
+{
+ u_char *c, *p, *key = NULL, *value = NULL;
+
+ p = chunk;
+ c = p;
+
+ while (p - chunk < len) {
+ switch (data->state) {
+ case 0:
+ /* read key */
+ /* Check here comments, eol and end of buffer */
+ if (*p == '#') {
+ if (key != NULL && p - c > 0) {
+ value = memory_pool_alloc (pool, p - c + 1);
+ memcpy (value, c, p - c);
+ value[p - c] = '\0';
+ value = g_strstrip (value);
+ func (data->cur_data, key, value);
+ }
+ data->state = 99;
+ }
+ else if (*p == '\r' || *p == '\n' || p - chunk == len - 1) {
+ if (key != NULL && p - c > 0) {
+ value = memory_pool_alloc (pool, p - c + 1);
+ memcpy (value, c, p - c);
+ value[p - c] = '\0';
+
+ value = g_strstrip (value);
+ func (data->cur_data, key, value);
+ }
+ data->state = 100;
+ key = NULL;
+ }
+ else if (g_ascii_isspace (*p)) {
+ if (p - c > 0) {
+ key = memory_pool_alloc (pool, p - c + 1);
+ memcpy (key, c, p - c);
+ key[p - c] = '\0';
+ data->state = 2;
+ }
+ else {
+ key = NULL;
+ }
+ }
+ else {
+ p ++;
+ }
+ break;
+ case 2:
+ /* Skip spaces before value */
+ if (!g_ascii_isspace (*p)) {
+ c = p;
+ data->state = 0;
+ }
+ else {
+ p ++;
+ }
+ break;
+ case 99:
+ /* SKIP_COMMENT */
+ /* Skip comment till end of line */
+ if (*p == '\r' || *p == '\n') {
+ while ((*p == '\r' || *p == '\n') && p - chunk < len) {
+ p++;
+ }
+ c = p;
+ key = NULL;
+ data->state = 0;
+ }
+ else {
+ p++;
+ }
+ break;
+ case 100:
+ /* Skip \r\n and whitespaces */
+ if (*p == '\r' || *p == '\n' || g_ascii_isspace (*p)) {
+ p ++;
+ }
+ else {
+ c = p;
+ key = NULL;
+ data->state = 0;
+ }
+ break;
+ }
+ }
+
+ return c;
+}
+
u_char *
abstract_parse_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data, insert_func func)
{
}
}
+u_char *
+read_kv_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data)
+{
+ if (data->cur_data == NULL) {
+ data->cur_data = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal);
+ }
+ return abstract_parse_kv_list (pool, chunk, len, data, (insert_func) g_hash_table_insert);
+}
+
+void
+fin_kv_list (memory_pool_t * pool, struct map_cb_data *data)
+{
+ if (data->prev_data) {
+ g_hash_table_destroy (data->prev_data);
+ }
+}
+
u_char *
read_radix_list (memory_pool_t * pool, u_char * chunk, size_t len, struct map_cb_data *data)
{
u_char* read_host_list (memory_pool_t *pool, u_char *chunk, size_t len, struct map_cb_data *data);
void fin_host_list (memory_pool_t *pool, struct map_cb_data *data);
+/**
+ * Kv list is an ordinal list of keys and values separated by whitespace
+ */
+u_char* read_kv_list (memory_pool_t *pool, u_char *chunk, size_t len, struct map_cb_data *data);
+void fin_kv_list (memory_pool_t *pool, struct map_cb_data *data);
+
/**
* FSM for lists parsing (support comments, blank lines and partial replies)
*/