]> source.dussan.org Git - rspamd.git/commitdiff
[Rework] Move maps code to a separate lua unit
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Sun, 6 Mar 2016 18:12:33 +0000 (18:12 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Sun, 6 Mar 2016 18:12:33 +0000 (18:12 +0000)
src/lua/CMakeLists.txt
src/lua/lua_common.h
src/lua/lua_config.c
src/lua/lua_map.c [new file with mode: 0644]
src/lua/lua_map.h [new file with mode: 0644]

index 3d3a7cebfab02b5b9618fb4b5383696393ba312a..cb97ca3ed6513f77d6f1124ebb4b60a995691795 100644 (file)
@@ -26,6 +26,7 @@ SET(LUASRC                      ${CMAKE_CURRENT_SOURCE_DIR}/lua_common.c
                                          ${CMAKE_CURRENT_SOURCE_DIR}/lua_html.c
                                          ${CMAKE_CURRENT_SOURCE_DIR}/lua_fann.c
                                          ${CMAKE_CURRENT_SOURCE_DIR}/lua_sqlite3.c
-                                         ${CMAKE_CURRENT_SOURCE_DIR}/lua_cryptobox.c)
+                                         ${CMAKE_CURRENT_SOURCE_DIR}/lua_cryptobox.c
+                                         ${CMAKE_CURRENT_SOURCE_DIR}/lua_map.c)
 
 SET(RSPAMD_LUA ${LUASRC} PARENT_SCOPE)
index 8629d6366e243310b5865604a54313f601d8b2cd..d39f42793e390f222fd6ae2d7540eaea2c77456b 100644 (file)
@@ -43,6 +43,8 @@ luaL_register (lua_State *L, const gchar *name, const struct luaL_reg *methods)
 /* Interface definitions */
 #define LUA_FUNCTION_DEF(class, name) static gint lua_ ## class ## _ ## name ( \
                lua_State * L)
+#define LUA_PUBLIC_FUNCTION_DEF(class, name) gint lua_ ## class ## _ ## name ( \
+               lua_State * L)
 #define LUA_INTERFACE_DEF(class, name) { # name, lua_ ## class ## _ ## name }
 
 extern const luaL_reg null_reg[];
@@ -80,7 +82,6 @@ struct rspamd_lua_regexp {
        gint re_flags;
 };
 
-
 /* Common utility functions */
 
 /**
index 1fbf6efdc1c7e98f0d2522e8f0292fc1d057010e..9f97902bb724ff82e733b8cbb98c3fafe26557a0 100644 (file)
  * limitations under the License.
  */
 #include "lua_common.h"
-#include "map.h"
-#include "message.h"
-#include "radix.h"
-#include "expression.h"
-#include "composites.h"
+#include "libmime/message.h"
+#include "libutil/expression.h"
+#include "libserver/composites.h"
+#include "lua/lua_map.h"
 #include "utlist.h"
 
 /***
@@ -78,7 +77,7 @@ local function foo(task)
        return false
 end
  */
-LUA_FUNCTION_DEF (config, add_radix_map);
+
 /***
  * @method rspamd_config:radix_from_config(mname, optname)
  * Creates new static map of IP/mask addresses from config.
@@ -96,7 +95,6 @@ local function foo(task)
        return false
 end
  */
-LUA_FUNCTION_DEF (config, radix_from_config);
 /***
  * @method rspamd_config:add_hash_map(mapline[, description])
  * Creates new dynamic map string objects.
@@ -114,7 +112,6 @@ local function foo(task)
        return false
 end
  */
-LUA_FUNCTION_DEF (config, add_hash_map);
 /***
  * @method rspamd_config:add_kv_map(mapline[, description])
  * Creates new dynamic map of key/values associations.
@@ -135,7 +132,6 @@ local function foo(task)
        return false
 end
  */
-LUA_FUNCTION_DEF (config, add_kv_map);
 /***
  * @method rspamd_config:add_map(mapline[, description], callback)
  * Creates new dynamic map with free-form callback
@@ -152,7 +148,6 @@ end
 
 rspamd_config:add_map('http://example.com/map', "settings map", process_map)
  */
-LUA_FUNCTION_DEF (config, add_map);
 /***
  * @method rspamd_config:get_classifier(name)
  * Returns classifier config.
@@ -416,33 +411,6 @@ static const struct luaL_reg configlib_m[] = {
        {NULL, NULL}
 };
 
-enum rspamd_lua_map_type {
-       RSPAMD_LUA_MAP_RADIX = 0,
-       RSPAMD_LUA_MAP_SET,
-       RSPAMD_LUA_MAP_HASH,
-       RSPAMD_LUA_MAP_CALLBACK
-};
-
-struct rspamd_lua_map {
-       struct rspamd_map *map;
-       enum rspamd_lua_map_type type;
-
-       union {
-               radix_compressed_t *radix;
-               GHashTable *hash;
-               gint cbref;
-       } data;
-};
-
-/* Radix tree */
-LUA_FUNCTION_DEF (map, get_key);
-
-static const struct luaL_reg maplib_m[] = {
-       LUA_INTERFACE_DEF (map, get_key),
-       {"__tostring", rspamd_lua_class_tostring},
-       {NULL, NULL}
-};
-
 struct rspamd_config *
 lua_check_config (lua_State * L, gint pos)
 {
@@ -451,14 +419,6 @@ lua_check_config (lua_State * L, gint pos)
        return ud ? *((struct rspamd_config **)ud) : NULL;
 }
 
-static struct rspamd_lua_map  *
-lua_check_map (lua_State * L)
-{
-       void *ud = luaL_checkudata (L, 1, "rspamd{map}");
-       luaL_argcheck (L, ud != NULL, 1, "'map' expected");
-       return ud ? *((struct rspamd_lua_map **)ud) : NULL;
-}
-
 /*** Config functions ***/
 static gint
 lua_config_get_api_version (lua_State *L)
@@ -761,161 +721,6 @@ lua_config_register_pre_filter (lua_State *L)
        return 1;
 }
 
-static gint
-lua_config_add_radix_map (lua_State *L)
-{
-       struct rspamd_config *cfg = lua_check_config (L, 1);
-       const gchar *map_line, *description;
-       struct rspamd_lua_map *map, **pmap;
-       struct rspamd_map *m;
-
-       if (cfg) {
-               map_line = luaL_checkstring (L, 2);
-               description = lua_tostring (L, 3);
-               map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
-               map->data.radix = radix_create_compressed ();
-               map->type = RSPAMD_LUA_MAP_RADIX;
-
-               if ((m = rspamd_map_add (cfg, map_line, description,
-                               rspamd_radix_read,
-                               rspamd_radix_fin,
-                               (void **)&map->data.radix)) == NULL) {
-                       msg_warn_config ("invalid radix map %s", map_line);
-                       radix_destroy_compressed (map->data.radix);
-                       lua_pushnil (L);
-                       return 1;
-               }
-
-               map->map = m;
-               pmap = lua_newuserdata (L, sizeof (void *));
-               *pmap = map;
-               rspamd_lua_setclass (L, "rspamd{map}", -1);
-       }
-       else {
-               return luaL_error (L, "invalid arguments");
-       }
-
-       return 1;
-
-}
-
-static gint
-lua_config_radix_from_config (lua_State *L)
-{
-       struct rspamd_config *cfg = lua_check_config (L, 1);
-       const gchar *mname, *optname;
-       const ucl_object_t *obj;
-       struct rspamd_lua_map *map, **pmap;
-
-       if (!cfg) {
-               return luaL_error (L, "invalid arguments");
-       }
-
-       mname = luaL_checkstring (L, 2);
-       optname = luaL_checkstring (L, 3);
-
-       if (mname && optname) {
-               obj = rspamd_config_get_module_opt (cfg, mname, optname);
-               if (obj) {
-                       map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
-                       map->data.radix = radix_create_compressed ();
-                       map->type = RSPAMD_LUA_MAP_RADIX;
-                       map->data.radix = radix_create_compressed ();
-                       radix_add_generic_iplist (ucl_obj_tostring (obj), &map->data.radix);
-                       pmap = lua_newuserdata (L, sizeof (void *));
-                       *pmap = map;
-                       rspamd_lua_setclass (L, "rspamd{map}", -1);
-               } else {
-                       msg_warn_config ("Couldnt find config option [%s][%s]", mname,
-                                       optname);
-                       lua_pushnil (L);
-               }
-
-       }
-       else {
-               return luaL_error (L, "invalid arguments");
-       }
-
-       return 1;
-}
-
-static gint
-lua_config_add_hash_map (lua_State *L)
-{
-       struct rspamd_config *cfg = lua_check_config (L, 1);
-       const gchar *map_line, *description;
-       struct rspamd_lua_map *map, **pmap;
-       struct rspamd_map *m;
-
-       if (cfg) {
-               map_line = luaL_checkstring (L, 2);
-               description = lua_tostring (L, 3);
-               map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
-               map->data.hash = g_hash_table_new (rspamd_strcase_hash,
-                               rspamd_strcase_equal);
-               map->type = RSPAMD_LUA_MAP_SET;
-
-               if ((m = rspamd_map_add (cfg, map_line, description,
-                               rspamd_hosts_read,
-                               rspamd_hosts_fin,
-                               (void **)&map->data.hash)) == NULL) {
-                       msg_warn_config ("invalid set map %s", map_line);
-                       g_hash_table_destroy (map->data.hash);
-                       lua_pushnil (L);
-                       return 1;
-               }
-
-               map->map = m;
-               pmap = lua_newuserdata (L, sizeof (void *));
-               *pmap = map;
-               rspamd_lua_setclass (L, "rspamd{map}", -1);
-       }
-       else {
-               return luaL_error (L, "invalid arguments");
-       }
-
-       return 1;
-
-}
-
-static gint
-lua_config_add_kv_map (lua_State *L)
-{
-       struct rspamd_config *cfg = lua_check_config (L, 1);
-       const gchar *map_line, *description;
-       struct rspamd_lua_map *map, **pmap;
-       struct rspamd_map *m;
-
-       if (cfg) {
-               map_line = luaL_checkstring (L, 2);
-               description = lua_tostring (L, 3);
-               map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
-               map->data.hash = g_hash_table_new (rspamd_strcase_hash,
-                               rspamd_strcase_equal);
-               map->type = RSPAMD_LUA_MAP_HASH;
-
-               if ((m = rspamd_map_add (cfg, map_line, description,
-                               rspamd_kv_list_read,
-                               rspamd_kv_list_fin,
-                               (void **)&map->data.hash)) == NULL) {
-                       msg_warn_config ("invalid hash map %s", map_line);
-                       g_hash_table_destroy (map->data.hash);
-                       lua_pushnil (L);
-                       return 1;
-               }
-
-               map->map = m;
-               pmap = lua_newuserdata (L, sizeof (void *));
-               *pmap = map;
-               rspamd_lua_setclass (L, "rspamd{map}", -1);
-       }
-       else {
-               return luaL_error (L, "invalid arguments");
-       }
-
-       return 1;
-}
-
 static gint
 lua_config_get_key (lua_State *L)
 {
@@ -1789,215 +1594,6 @@ lua_config_replace_regexp (lua_State *L)
        return 0;
 }
 
-struct lua_map_callback_data {
-       lua_State *L;
-       gint ref;
-       GString *data;
-       struct rspamd_lua_map *lua_map;
-};
-
-static gchar *
-lua_map_read (rspamd_mempool_t *pool, gchar *chunk, gint len,
-       struct map_cb_data *data)
-{
-       struct lua_map_callback_data *cbdata, *old;
-
-       if (data->cur_data == NULL) {
-               cbdata = g_slice_alloc0 (sizeof (*cbdata));
-               old = (struct lua_map_callback_data *)data->prev_data;
-               cbdata->L = old->L;
-               cbdata->ref = old->ref;
-               cbdata->lua_map = old->lua_map;
-               data->cur_data = cbdata;
-       }
-       else {
-               cbdata = (struct lua_map_callback_data *)data->cur_data;
-       }
-
-       if (cbdata->data == NULL) {
-               cbdata->data = g_string_new_len (chunk, len);
-       }
-       else {
-               g_string_append_len (cbdata->data, chunk, len);
-       }
-
-       return NULL;
-}
-
-void
-lua_map_fin (rspamd_mempool_t * pool, struct map_cb_data *data)
-{
-       struct lua_map_callback_data *cbdata, *old;
-       struct rspamd_lua_map **pmap;
-
-       if (data->prev_data) {
-               /* Cleanup old data */
-               old = (struct lua_map_callback_data *)data->prev_data;
-               if (old->data) {
-                       g_string_free (old->data, TRUE);
-               }
-               g_slice_free1 (sizeof (*old), old);
-               data->prev_data = NULL;
-       }
-
-       if (data->cur_data) {
-               cbdata = (struct lua_map_callback_data *)data->cur_data;
-       }
-       else {
-               msg_err_pool ("no data read for map");
-               return;
-       }
-
-       if (cbdata->data != NULL && cbdata->data->len != 0) {
-               lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->ref);
-               lua_pushlstring (cbdata->L, cbdata->data->str, cbdata->data->len);
-               pmap = lua_newuserdata (cbdata->L, sizeof (void *));
-               *pmap = cbdata->lua_map;
-               rspamd_lua_setclass (cbdata->L, "rspamd{map}", -1);
-
-               if (lua_pcall (cbdata->L, -1, 0, 0) != 0) {
-                       msg_info_pool ("call to %s failed: %s", "local function",
-                               lua_tostring (cbdata->L, -1));
-                       lua_pop (cbdata->L, 1);
-               }
-       }
-}
-
-static gint
-lua_config_add_map (lua_State *L)
-{
-       struct rspamd_config *cfg = lua_check_config (L, 1);
-       const gchar *map_line, *description;
-       struct lua_map_callback_data *cbdata, **pcbdata;
-       struct rspamd_lua_map *map;
-       struct rspamd_map *m;
-       int cbidx;
-
-       if (cfg) {
-               map_line = luaL_checkstring (L, 2);
-
-               if (lua_gettop (L) == 4) {
-                       description = lua_tostring (L, 3);
-                       cbidx = 4;
-               }
-               else {
-                       description = NULL;
-                       cbidx = 3;
-               }
-
-               if (lua_type (L, cbidx) == LUA_TFUNCTION) {
-                       cbdata = g_slice_alloc (sizeof (*cbdata));
-                       cbdata->L = L;
-                       cbdata->data = NULL;
-                       lua_pushvalue (L, cbidx);
-                       /* Get a reference */
-                       cbdata->ref = luaL_ref (L, LUA_REGISTRYINDEX);
-                       map = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (*map));
-                       map->type = RSPAMD_LUA_MAP_CALLBACK;
-                       map->data.cbref = cbdata->ref;
-                       cbdata->lua_map = map;
-                       pcbdata = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (cbdata));
-                       *pcbdata = cbdata;
-
-                       if ((m = rspamd_map_add (cfg, map_line, description,
-                                       lua_map_read, lua_map_fin,
-                                       (void **)pcbdata)) == NULL) {
-                               msg_warn_config ("invalid hash map %s", map_line);
-                               lua_pushboolean (L, false);
-                       }
-                       else {
-                               map->map = m;
-                               lua_pushboolean (L, true);
-                       }
-               }
-               else {
-                       msg_warn_config ("invalid callback argument for map %s", map_line);
-                       lua_pushboolean (L, false);
-               }
-       }
-       else {
-               return luaL_error (L, "invalid arguments");
-       }
-
-       return 1;
-}
-
-/* Radix and hash table functions */
-static gint
-lua_map_get_key (lua_State * L)
-{
-       struct rspamd_lua_map *map = lua_check_map (L);
-       radix_compressed_t *radix;
-       struct rspamd_lua_ip *addr = NULL;
-       const gchar *key, *value = NULL;
-       gpointer ud;
-       guint32 key_num = 0;
-       gboolean ret = FALSE;
-
-       if (map) {
-               if (map->type == RSPAMD_LUA_MAP_RADIX) {
-                       radix = map->data.radix;
-
-                       if (lua_type (L, 2) == LUA_TNUMBER) {
-                               key_num = luaL_checknumber (L, 2);
-                               key_num = htonl (key_num);
-                       }
-                       else if (lua_type (L, 2) == LUA_TUSERDATA) {
-                               ud = luaL_checkudata (L, 2, "rspamd{ip}");
-                               if (ud != NULL) {
-                                       addr = *((struct rspamd_lua_ip **)ud);
-                                       if (addr->addr == NULL) {
-                                               msg_err ("rspamd{ip} is not valid");
-                                               addr = NULL;
-                                       }
-                               }
-                               else {
-                                       msg_err ("invalid userdata type provided, rspamd{ip} expected");
-                               }
-                       }
-
-                       if (addr != NULL) {
-                               if (radix_find_compressed_addr (radix, addr->addr)
-                                               !=  RADIX_NO_VALUE) {
-                                       ret = TRUE;
-                               }
-                       }
-                       else if (key_num != 0) {
-                               if (radix_find_compressed (radix, (guint8 *)&key_num, sizeof (key_num))
-                                               != RADIX_NO_VALUE) {
-                                       ret = TRUE;
-                               }
-                       }
-               }
-               else if (map->type == RSPAMD_LUA_MAP_SET) {
-                       key = lua_tostring (L, 2);
-
-                       if (key) {
-                               ret = g_hash_table_lookup (map->data.hash, key) != NULL;
-                       }
-               }
-               else {
-                       /* key-value map */
-                       key = lua_tostring (L, 2);
-
-                       if (key) {
-                               value = g_hash_table_lookup (map->data.hash, key);
-
-                               if (value) {
-                                       lua_pushstring (L, value);
-                                       return 1;
-                               }
-                       }
-               }
-       }
-       else {
-               return luaL_error (L, "invalid arguments");
-       }
-
-       lua_pushboolean (L, ret);
-       return 1;
-}
-
 void
 luaopen_config (lua_State * L)
 {
@@ -2005,11 +1601,3 @@ luaopen_config (lua_State * L)
 
        lua_pop (L, 1);
 }
-
-void
-luaopen_map (lua_State * L)
-{
-       rspamd_lua_new_class (L, "rspamd{map}", maplib_m);
-
-       lua_pop (L, 1);
-}
diff --git a/src/lua/lua_map.c b/src/lua/lua_map.c
new file mode 100644 (file)
index 0000000..ee9695c
--- /dev/null
@@ -0,0 +1,438 @@
+/*-
+ * Copyright 2016 Vsevolod Stakhov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "lua_common.h"
+#include "libutil/map.h"
+#include "libutil/map_private.h"
+#include "libutil/radix.h"
+#include "lua/lua_map.h"
+
+/***
+ * This module is used to manage rspamd maps and map like objects
+ *
+ * @module rspamd_map
+ */
+
+/* Radix tree */
+LUA_FUNCTION_DEF (map, get_key);
+
+static const struct luaL_reg maplib_m[] = {
+       LUA_INTERFACE_DEF (map, get_key),
+       {"__tostring", rspamd_lua_class_tostring},
+       {NULL, NULL}
+};
+
+enum rspamd_lua_map_type {
+       RSPAMD_LUA_MAP_RADIX = 0,
+       RSPAMD_LUA_MAP_SET,
+       RSPAMD_LUA_MAP_HASH,
+       RSPAMD_LUA_MAP_CALLBACK
+};
+
+struct rspamd_map;
+struct radix_tree_compressed;
+
+struct rspamd_lua_map {
+       struct rspamd_map *map;
+       enum rspamd_lua_map_type type;
+
+       union {
+               struct radix_tree_compressed *radix;
+               GHashTable *hash;
+               gint cbref;
+       } data;
+};
+
+struct lua_map_callback_data {
+       lua_State *L;
+       gint ref;
+       GString *data;
+       struct rspamd_lua_map *lua_map;
+};
+
+static struct rspamd_lua_map  *
+lua_check_map (lua_State * L)
+{
+       void *ud = luaL_checkudata (L, 1, "rspamd{map}");
+       luaL_argcheck (L, ud != NULL, 1, "'map' expected");
+       return ud ? *((struct rspamd_lua_map **)ud) : NULL;
+}
+
+gint
+lua_config_add_radix_map (lua_State *L)
+{
+       struct rspamd_config *cfg = lua_check_config (L, 1);
+       const gchar *map_line, *description;
+       struct rspamd_lua_map *map, **pmap;
+       struct rspamd_map *m;
+
+       if (cfg) {
+               map_line = luaL_checkstring (L, 2);
+               description = lua_tostring (L, 3);
+               map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
+               map->data.radix = radix_create_compressed ();
+               map->type = RSPAMD_LUA_MAP_RADIX;
+
+               if ((m = rspamd_map_add (cfg, map_line, description,
+                               rspamd_radix_read,
+                               rspamd_radix_fin,
+                               (void **)&map->data.radix)) == NULL) {
+                       msg_warn_config ("invalid radix map %s", map_line);
+                       radix_destroy_compressed (map->data.radix);
+                       lua_pushnil (L);
+                       return 1;
+               }
+
+               map->map = m;
+               pmap = lua_newuserdata (L, sizeof (void *));
+               *pmap = map;
+               rspamd_lua_setclass (L, "rspamd{map}", -1);
+       }
+       else {
+               return luaL_error (L, "invalid arguments");
+       }
+
+       return 1;
+
+}
+
+gint
+lua_config_radix_from_config (lua_State *L)
+{
+       struct rspamd_config *cfg = lua_check_config (L, 1);
+       const gchar *mname, *optname;
+       const ucl_object_t *obj;
+       struct rspamd_lua_map *map, **pmap;
+
+       if (!cfg) {
+               return luaL_error (L, "invalid arguments");
+       }
+
+       mname = luaL_checkstring (L, 2);
+       optname = luaL_checkstring (L, 3);
+
+       if (mname && optname) {
+               obj = rspamd_config_get_module_opt (cfg, mname, optname);
+               if (obj) {
+                       map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
+                       map->data.radix = radix_create_compressed ();
+                       map->type = RSPAMD_LUA_MAP_RADIX;
+                       map->data.radix = radix_create_compressed ();
+                       radix_add_generic_iplist (ucl_obj_tostring (obj), &map->data.radix);
+                       pmap = lua_newuserdata (L, sizeof (void *));
+                       *pmap = map;
+                       rspamd_lua_setclass (L, "rspamd{map}", -1);
+               } else {
+                       msg_warn_config ("Couldnt find config option [%s][%s]", mname,
+                                       optname);
+                       lua_pushnil (L);
+               }
+
+       }
+       else {
+               return luaL_error (L, "invalid arguments");
+       }
+
+       return 1;
+}
+
+gint
+lua_config_add_hash_map (lua_State *L)
+{
+       struct rspamd_config *cfg = lua_check_config (L, 1);
+       const gchar *map_line, *description;
+       struct rspamd_lua_map *map, **pmap;
+       struct rspamd_map *m;
+
+       if (cfg) {
+               map_line = luaL_checkstring (L, 2);
+               description = lua_tostring (L, 3);
+               map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
+               map->data.hash = g_hash_table_new (rspamd_strcase_hash,
+                               rspamd_strcase_equal);
+               map->type = RSPAMD_LUA_MAP_SET;
+
+               if ((m = rspamd_map_add (cfg, map_line, description,
+                               rspamd_hosts_read,
+                               rspamd_hosts_fin,
+                               (void **)&map->data.hash)) == NULL) {
+                       msg_warn_config ("invalid set map %s", map_line);
+                       g_hash_table_destroy (map->data.hash);
+                       lua_pushnil (L);
+                       return 1;
+               }
+
+               map->map = m;
+               pmap = lua_newuserdata (L, sizeof (void *));
+               *pmap = map;
+               rspamd_lua_setclass (L, "rspamd{map}", -1);
+       }
+       else {
+               return luaL_error (L, "invalid arguments");
+       }
+
+       return 1;
+
+}
+
+gint
+lua_config_add_kv_map (lua_State *L)
+{
+       struct rspamd_config *cfg = lua_check_config (L, 1);
+       const gchar *map_line, *description;
+       struct rspamd_lua_map *map, **pmap;
+       struct rspamd_map *m;
+
+       if (cfg) {
+               map_line = luaL_checkstring (L, 2);
+               description = lua_tostring (L, 3);
+               map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*map));
+               map->data.hash = g_hash_table_new (rspamd_strcase_hash,
+                               rspamd_strcase_equal);
+               map->type = RSPAMD_LUA_MAP_HASH;
+
+               if ((m = rspamd_map_add (cfg, map_line, description,
+                               rspamd_kv_list_read,
+                               rspamd_kv_list_fin,
+                               (void **)&map->data.hash)) == NULL) {
+                       msg_warn_config ("invalid hash map %s", map_line);
+                       g_hash_table_destroy (map->data.hash);
+                       lua_pushnil (L);
+                       return 1;
+               }
+
+               map->map = m;
+               pmap = lua_newuserdata (L, sizeof (void *));
+               *pmap = map;
+               rspamd_lua_setclass (L, "rspamd{map}", -1);
+       }
+       else {
+               return luaL_error (L, "invalid arguments");
+       }
+
+       return 1;
+}
+
+
+static gchar *
+lua_map_read (rspamd_mempool_t *pool, gchar *chunk, gint len,
+       struct map_cb_data *data)
+{
+       struct lua_map_callback_data *cbdata, *old;
+
+       if (data->cur_data == NULL) {
+               cbdata = g_slice_alloc0 (sizeof (*cbdata));
+               old = (struct lua_map_callback_data *)data->prev_data;
+               cbdata->L = old->L;
+               cbdata->ref = old->ref;
+               cbdata->lua_map = old->lua_map;
+               data->cur_data = cbdata;
+       }
+       else {
+               cbdata = (struct lua_map_callback_data *)data->cur_data;
+       }
+
+       if (cbdata->data == NULL) {
+               cbdata->data = g_string_new_len (chunk, len);
+       }
+       else {
+               g_string_append_len (cbdata->data, chunk, len);
+       }
+
+       return NULL;
+}
+
+static void
+lua_map_fin (rspamd_mempool_t * pool, struct map_cb_data *data)
+{
+       struct lua_map_callback_data *cbdata, *old;
+       struct rspamd_lua_map **pmap;
+
+       if (data->prev_data) {
+               /* Cleanup old data */
+               old = (struct lua_map_callback_data *)data->prev_data;
+               if (old->data) {
+                       g_string_free (old->data, TRUE);
+               }
+               g_slice_free1 (sizeof (*old), old);
+               data->prev_data = NULL;
+       }
+
+       if (data->cur_data) {
+               cbdata = (struct lua_map_callback_data *)data->cur_data;
+       }
+       else {
+               msg_err_pool ("no data read for map");
+               return;
+       }
+
+       if (cbdata->data != NULL && cbdata->data->len != 0) {
+               lua_rawgeti (cbdata->L, LUA_REGISTRYINDEX, cbdata->ref);
+               lua_pushlstring (cbdata->L, cbdata->data->str, cbdata->data->len);
+               pmap = lua_newuserdata (cbdata->L, sizeof (void *));
+               *pmap = cbdata->lua_map;
+               rspamd_lua_setclass (cbdata->L, "rspamd{map}", -1);
+
+               if (lua_pcall (cbdata->L, -1, 0, 0) != 0) {
+                       msg_info_pool ("call to %s failed: %s", "local function",
+                               lua_tostring (cbdata->L, -1));
+                       lua_pop (cbdata->L, 1);
+               }
+       }
+}
+
+gint
+lua_config_add_map (lua_State *L)
+{
+       struct rspamd_config *cfg = lua_check_config (L, 1);
+       const gchar *map_line, *description;
+       struct lua_map_callback_data *cbdata, **pcbdata;
+       struct rspamd_lua_map *map;
+       struct rspamd_map *m;
+       int cbidx;
+
+       if (cfg) {
+               map_line = luaL_checkstring (L, 2);
+
+               if (lua_gettop (L) == 4) {
+                       description = lua_tostring (L, 3);
+                       cbidx = 4;
+               }
+               else {
+                       description = NULL;
+                       cbidx = 3;
+               }
+
+               if (lua_type (L, cbidx) == LUA_TFUNCTION) {
+                       cbdata = g_slice_alloc (sizeof (*cbdata));
+                       cbdata->L = L;
+                       cbdata->data = NULL;
+                       lua_pushvalue (L, cbidx);
+                       /* Get a reference */
+                       cbdata->ref = luaL_ref (L, LUA_REGISTRYINDEX);
+                       map = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (*map));
+                       map->type = RSPAMD_LUA_MAP_CALLBACK;
+                       map->data.cbref = cbdata->ref;
+                       cbdata->lua_map = map;
+                       pcbdata = rspamd_mempool_alloc (cfg->cfg_pool, sizeof (cbdata));
+                       *pcbdata = cbdata;
+
+                       if ((m = rspamd_map_add (cfg, map_line, description,
+                                       lua_map_read, lua_map_fin,
+                                       (void **)pcbdata)) == NULL) {
+                               msg_warn_config ("invalid hash map %s", map_line);
+                               lua_pushboolean (L, false);
+                       }
+                       else {
+                               map->map = m;
+                               lua_pushboolean (L, true);
+                       }
+               }
+               else {
+                       msg_warn_config ("invalid callback argument for map %s", map_line);
+                       lua_pushboolean (L, false);
+               }
+       }
+       else {
+               return luaL_error (L, "invalid arguments");
+       }
+
+       return 1;
+}
+
+/* Radix and hash table functions */
+static gint
+lua_map_get_key (lua_State * L)
+{
+       struct rspamd_lua_map *map = lua_check_map (L);
+       radix_compressed_t *radix;
+       struct rspamd_lua_ip *addr = NULL;
+       const gchar *key, *value = NULL;
+       gpointer ud;
+       guint32 key_num = 0;
+       gboolean ret = FALSE;
+
+       if (map) {
+               if (map->type == RSPAMD_LUA_MAP_RADIX) {
+                       radix = map->data.radix;
+
+                       if (lua_type (L, 2) == LUA_TNUMBER) {
+                               key_num = luaL_checknumber (L, 2);
+                               key_num = htonl (key_num);
+                       }
+                       else if (lua_type (L, 2) == LUA_TUSERDATA) {
+                               ud = luaL_checkudata (L, 2, "rspamd{ip}");
+                               if (ud != NULL) {
+                                       addr = *((struct rspamd_lua_ip **)ud);
+                                       if (addr->addr == NULL) {
+                                               msg_err ("rspamd{ip} is not valid");
+                                               addr = NULL;
+                                       }
+                               }
+                               else {
+                                       msg_err ("invalid userdata type provided, rspamd{ip} expected");
+                               }
+                       }
+
+                       if (addr != NULL) {
+                               if (radix_find_compressed_addr (radix, addr->addr)
+                                               !=  RADIX_NO_VALUE) {
+                                       ret = TRUE;
+                               }
+                       }
+                       else if (key_num != 0) {
+                               if (radix_find_compressed (radix, (guint8 *)&key_num, sizeof (key_num))
+                                               != RADIX_NO_VALUE) {
+                                       ret = TRUE;
+                               }
+                       }
+               }
+               else if (map->type == RSPAMD_LUA_MAP_SET) {
+                       key = lua_tostring (L, 2);
+
+                       if (key) {
+                               ret = g_hash_table_lookup (map->data.hash, key) != NULL;
+                       }
+               }
+               else {
+                       /* key-value map */
+                       key = lua_tostring (L, 2);
+
+                       if (key) {
+                               value = g_hash_table_lookup (map->data.hash, key);
+
+                               if (value) {
+                                       lua_pushstring (L, value);
+                                       return 1;
+                               }
+                       }
+               }
+       }
+       else {
+               return luaL_error (L, "invalid arguments");
+       }
+
+       lua_pushboolean (L, ret);
+       return 1;
+}
+
+void
+luaopen_map (lua_State * L)
+{
+       rspamd_lua_new_class (L, "rspamd{map}", maplib_m);
+
+       lua_pop (L, 1);
+}
diff --git a/src/lua/lua_map.h b/src/lua/lua_map.h
new file mode 100644 (file)
index 0000000..01a7a63
--- /dev/null
@@ -0,0 +1,28 @@
+/*-
+ * Copyright 2016 Vsevolod Stakhov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef SRC_LUA_LUA_MAP_H_
+#define SRC_LUA_LUA_MAP_H_
+
+#include "lua_common.h"
+
+LUA_PUBLIC_FUNCTION_DEF (config, add_radix_map);
+LUA_PUBLIC_FUNCTION_DEF (config, radix_from_config);
+LUA_PUBLIC_FUNCTION_DEF (config, add_map);
+LUA_PUBLIC_FUNCTION_DEF (config, add_hash_map);
+LUA_PUBLIC_FUNCTION_DEF (config, add_kv_map);
+LUA_PUBLIC_FUNCTION_DEF (config, add_map);
+
+#endif /* SRC_LUA_LUA_MAP_H_ */