aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2010-04-06 19:55:11 +0400
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2010-04-06 19:55:11 +0400
commit4405a019f681fcb51ce0e53b477ed64d50740138 (patch)
tree1717f2091849f9231447c5c6492f9b77361488bf
parent42baae32bc212e9287e11afa685e2de77cdf48e4 (diff)
downloadrspamd-4405a019f681fcb51ce0e53b477ed64d50740138.tar.gz
rspamd-4405a019f681fcb51ce0e53b477ed64d50740138.zip
* Add lua functions parsing for module options
* Add missing sections to XML parser (classifier, statfile, view, settings) * Add missing params to XML parser * Implement new commandline options parser (using glib) * Set version to 0.3.0 as new rspamd would use new config system
-rw-r--r--CMakeLists.txt4
-rw-r--r--src/cfg_file.h18
-rw-r--r--src/cfg_xml.c461
-rw-r--r--src/cfg_xml.h31
-rw-r--r--src/lua/lua_cfg_file.c104
-rw-r--r--src/lua/lua_common.c4
-rw-r--r--src/lua/lua_common.h4
-rw-r--r--src/main.c103
8 files changed, 619 insertions, 110 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 480fe88ce..3b93b49c7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,8 +6,8 @@
PROJECT(rspamd C)
SET(RSPAMD_VERSION_MAJOR 0)
-SET(RSPAMD_VERSION_MINOR 2)
-SET(RSPAMD_VERSION_PATCH 9)
+SET(RSPAMD_VERSION_MINOR 3)
+SET(RSPAMD_VERSION_PATCH 0)
SET(RSPAMD_VERSION "${RSPAMD_VERSION_MAJOR}.${RSPAMD_VERSION_MINOR}.${RSPAMD_VERSION_PATCH}")
SET(RSPAMD_MASTER_SITE_URL "http://cebka.pp.ru/hg/rspamd")
diff --git a/src/cfg_file.h b/src/cfg_file.h
index 225a940ac..17f81b3a6 100644
--- a/src/cfg_file.h
+++ b/src/cfg_file.h
@@ -103,6 +103,16 @@ struct script_module {
};
/**
+ * Type of lua variable
+ */
+enum lua_var_type {
+ LUA_VAR_NUM,
+ LUA_VAR_BOOLEAN,
+ LUA_VAR_STRING,
+ LUA_VAR_FUNCTION,
+ LUA_VAR_UNKNOWN
+};
+/**
* Module option
*/
struct module_opt {
@@ -110,13 +120,7 @@ struct module_opt {
gchar *value; /**< paramater value */
gpointer actual_data; /**< parsed data */
gboolean is_lua; /**< actually this is lua variable */
- enum {
- LUA_VAR_NUM,
- LUA_VAR_BOOLEAN,
- LUA_VAR_STRING,
- LUA_VAR_FUNCTION,
- LUA_VAR_UNKNOWN
- } lua_type; /**< type of lua variable */
+ enum lua_var_type lua_type; /**< type of lua variable */
};
/**
diff --git a/src/cfg_xml.c b/src/cfg_xml.c
index 872bd7a00..46ccd1e2e 100644
--- a/src/cfg_xml.c
+++ b/src/cfg_xml.c
@@ -34,6 +34,9 @@
#include "classifiers/classifiers.h"
#include "tokenizers/tokenizers.h"
#include "lua/lua_common.h"
+#include "view.h"
+#include "expressions.h"
+#include "settings.h"
/* Maximum attributes for param */
#define MAX_PARAM 64
@@ -52,11 +55,11 @@ enum xml_config_section {
XML_SECTION_WORKER,
XML_SECTION_METRIC,
XML_SECTION_CLASSIFIER,
+ XML_SECTION_STATFILE,
XML_SECTION_FACTORS,
XML_SECTION_MODULE,
XML_SECTION_MODULES,
- XML_SECTION_VIEW,
- XML_SECTION_SETTINGS
+ XML_SECTION_VIEW
};
struct xml_config_param {
@@ -117,6 +120,30 @@ static struct xml_parser_rule grammar[] = {
G_STRUCT_OFFSET (struct config_file, filters_str),
NULL
},
+ {
+ "variable",
+ handle_variable,
+ 0,
+ NULL
+ },
+ {
+ "composite",
+ handle_composite,
+ 0,
+ NULL
+ },
+ {
+ "user_settings",
+ handle_user_settings,
+ 0,
+ NULL
+ },
+ {
+ "domain_settings",
+ handle_domain_settings,
+ 0,
+ NULL
+ },
NULL_ATTR
},
NULL_ATTR
@@ -226,6 +253,71 @@ static struct xml_parser_rule grammar[] = {
NULL_ATTR
},
{ XML_SECTION_CLASSIFIER, {
+ {
+ "metric",
+ xml_handle_string,
+ G_STRUCT_OFFSET (struct classifier_config, metric),
+ NULL
+ },
+ {
+ "tokenizer",
+ handle_classifier_tokenizer,
+ 0,
+ NULL
+ },
+ {
+ "option",
+ handle_classifier_opt,
+ 0,
+ NULL
+ },
+ NULL_ATTR
+ },
+ NULL_ATTR
+ },
+ { XML_SECTION_STATFILE, {
+ {
+ "symbol",
+ xml_handle_string,
+ G_STRUCT_OFFSET (struct statfile, symbol),
+ NULL
+ },
+ {
+ "path",
+ xml_handle_string,
+ G_STRUCT_OFFSET (struct statfile, path),
+ NULL
+ },
+ {
+ "size",
+ xml_handle_size,
+ G_STRUCT_OFFSET (struct statfile, size),
+ NULL
+ },
+ {
+ "normalizer",
+ handle_statfile_normalizer,
+ 0,
+ NULL
+ },
+ {
+ "binlog",
+ handle_statfile_binlog,
+ 0,
+ NULL
+ },
+ {
+ "binlog_rotate",
+ handle_statfile_binlog_rotate,
+ 0,
+ NULL
+ },
+ {
+ "binlog_master",
+ handle_statfile_binlog_master,
+ 0,
+ NULL
+ },
NULL_ATTR
},
NULL_ATTR
@@ -257,20 +349,51 @@ static struct xml_parser_rule grammar[] = {
}
},
{ XML_SECTION_MODULES, {
+ {
+ "path",
+ handle_module_path,
+ 0,
+ NULL
+ },
NULL_ATTR
},
NULL_ATTR
},
{ XML_SECTION_VIEW, {
+ {
+ "skip_check",
+ xml_handle_boolean,
+ G_STRUCT_OFFSET (struct rspamd_view, skip_check),
+ NULL
+ },
+ {
+ "ip",
+ handle_view_ip,
+ 0,
+ NULL
+ },
+ {
+ "client_ip",
+ handle_view_client_ip,
+ 0,
+ NULL
+ },
+ {
+ "from",
+ handle_view_from,
+ 0,
+ NULL
+ },
+ {
+ "symbols",
+ handle_view_symbols,
+ 0,
+ NULL
+ },
NULL_ATTR
},
NULL_ATTR
},
- { XML_SECTION_SETTINGS, {
- NULL_ATTR
- },
- NULL_ATTR
- }
};
GQuark
@@ -373,6 +496,7 @@ call_param_handler (struct rspamd_xml_userdata *ctx, const gchar *name, gchar *v
/* Handlers */
/* Specific handlers */
+/* Logging section */
gboolean
handle_log_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
{
@@ -471,10 +595,11 @@ handle_log_level (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHas
return TRUE;
}
+/* Worker section */
gboolean
worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
{
- struct worker_conf *wrk = ctx->other_data;
+ struct worker_conf *wrk = ctx->section_pointer;
char *name;
if ((name = g_hash_table_lookup (attrs, "name")) == NULL) {
@@ -489,7 +614,7 @@ worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, G
gboolean
worker_handle_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
{
- struct worker_conf *wrk = ctx->other_data;
+ struct worker_conf *wrk = ctx->section_pointer;
if (g_ascii_strcasecmp (data, "normal") == 0) {
@@ -519,7 +644,7 @@ worker_handle_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GH
gboolean
worker_handle_bind (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
{
- struct worker_conf *wrk = ctx->other_data;
+ struct worker_conf *wrk = ctx->section_pointer;
if (!parse_bind_line (cfg, wrk, data)) {
msg_err ("cannot parse bind_socket: %s", data);
@@ -529,6 +654,7 @@ worker_handle_bind (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GH
return TRUE;
}
+/* Factors section */
gboolean
handle_factor (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
{
@@ -554,6 +680,7 @@ handle_factor (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTa
return TRUE;
}
+/* Modules section */
gboolean
handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
{
@@ -641,6 +768,243 @@ handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable
return TRUE;
}
+/* Modules section */
+gboolean
+handle_module_path (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ struct stat st;
+ struct script_module *cur;
+ glob_t globbuf;
+ char *pattern;
+ size_t len;
+ int i;
+
+ if (stat (data, &st) == -1) {
+ msg_err ("cannot stat path %s, %s", data, strerror (errno));
+ return FALSE;
+ }
+
+ globbuf.gl_offs = 0;
+ len = strlen (data) + sizeof ("*.lua");
+ pattern = g_malloc (len);
+ snprintf (pattern, len, "%s%s", data, "*.lua");
+
+ if (glob (pattern, GLOB_DOOFFS, NULL, &globbuf) == 0) {
+ for (i = 0; i < globbuf.gl_pathc; i ++) {
+ cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct script_module));
+ cur->path = memory_pool_strdup (cfg->cfg_pool, globbuf.gl_pathv[i]);
+ cfg->script_modules = g_list_prepend (cfg->script_modules, cur);
+ }
+ globfree (&globbuf);
+ }
+ else {
+ msg_err ("glob failed: %s", strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Variables and composites */
+gboolean
+handle_variable (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ gchar *val;
+
+ if ((val = g_hash_table_lookup (attrs, "name")) == NULL) {
+ msg_err ("'name' attribute is required for tag 'variable'");
+ return FALSE;
+ }
+
+ g_hash_table_insert (cfg->variables, val, memory_pool_strdup (cfg->cfg_pool, data));
+ return TRUE;
+}
+
+gboolean
+handle_composite (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ gchar *val;
+ struct expression *expr;
+
+ if ((val = g_hash_table_lookup (attrs, "name")) == NULL) {
+ msg_err ("'name' attribute is required for tag 'composite'");
+ return FALSE;
+ }
+
+ if ((expr = parse_expression (cfg->cfg_pool, data)) == NULL) {
+ msg_err ("cannot parse composite expression: %s", data);
+ return FALSE;
+ }
+ g_hash_table_insert (cfg->composite_symbols, val, expr);
+
+ return TRUE;
+}
+
+/* View section */
+gboolean
+handle_view_ip (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ struct rspamd_view *view = ctx->section_pointer;
+
+ if (!add_view_ip (view, data)) {
+ msg_err ("invalid ip line in view definition: ip = '%s'", data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+gboolean
+handle_view_client_ip (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ struct rspamd_view *view = ctx->section_pointer;
+
+ if (!add_view_client_ip (view, data)) {
+ msg_err ("invalid ip line in view definition: ip = '%s'", data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+gboolean
+handle_view_from (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ struct rspamd_view *view = ctx->section_pointer;
+
+ if (!add_view_from (view, data)) {
+ msg_err ("invalid from line in view definition: ip = '%s'", data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+gboolean
+handle_view_symbols (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ struct rspamd_view *view = ctx->section_pointer;
+
+ if (!add_view_symbols (view, data)) {
+ msg_err ("invalid symbols line in view definition: ip = '%s'", data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Settings */
+gboolean
+handle_user_settings (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ if (!read_settings (data, cfg, cfg->user_settings)) {
+ msg_err ("cannot read settings %s", data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+gboolean
+handle_domain_settings (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ if (!read_settings (data, cfg, cfg->domain_settings)) {
+ msg_err ("cannot read settings %s", data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Classifier */
+gboolean
+handle_classifier_tokenizer (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ struct classifier_config *ccf = ctx->section_pointer;
+
+ if ((ccf->tokenizer = get_tokenizer (data)) == NULL) {
+ msg_err ("unknown tokenizer %s", data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+handle_classifier_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ struct classifier_config *ccf = ctx->section_pointer;
+ gchar *val;
+
+ if ((val = g_hash_table_lookup (attrs, "name")) == NULL) {
+ msg_err ("'name' attribute is required for tag 'option'");
+ return FALSE;
+ }
+
+ g_hash_table_insert (ccf->opts, val, memory_pool_strdup (cfg->cfg_pool, data));
+ return TRUE;
+}
+
+/* Statfile */
+gboolean
+handle_statfile_normalizer (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ struct statfile *st = ctx->section_pointer;
+
+ if (!parse_normalizer (cfg, st, data)) {
+ msg_err ("cannot parse normalizer string: %s", data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+handle_statfile_binlog (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ struct statfile *st = ctx->section_pointer;
+
+ if (st->binlog == NULL) {
+ st->binlog = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct statfile_binlog_params));
+ }
+ if (g_ascii_strcasecmp (data, "master") == 0) {
+ st->binlog->affinity = AFFINITY_MASTER;
+ }
+ else if (g_ascii_strcasecmp (data, "slave") == 0) {
+ st->binlog->affinity = AFFINITY_SLAVE;
+ }
+ else {
+ st->binlog->affinity = AFFINITY_NONE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+handle_statfile_binlog_rotate (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ struct statfile *st = ctx->section_pointer;
+
+ if (st->binlog == NULL) {
+ st->binlog = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct statfile_binlog_params));
+ }
+ st->binlog->rotate_time = parse_seconds (data);
+
+ return TRUE;
+}
+
+gboolean
+handle_statfile_binlog_master (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
+{
+ struct statfile *st = ctx->section_pointer;
+ if (st->binlog == NULL) {
+ st->binlog = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct statfile_binlog_params));
+ }
+
+ if (!parse_host_port (data, &st->binlog->master_addr, &st->binlog->master_port)) {
+ msg_err ("cannot parse master address: %s", data);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/* Common handlers */
gboolean
xml_handle_string (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset)
@@ -807,7 +1171,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam
g_strlcpy (ud->section_name, res, sizeof (ud->section_name));
ud->state = XML_READ_METRIC;
/* Create object */
- ud->other_data = memory_pool_alloc0 (ud->cfg->cfg_pool, sizeof (struct metric));
+ ud->section_pointer = memory_pool_alloc0 (ud->cfg->cfg_pool, sizeof (struct metric));
}
else {
*error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'name' is required for tag 'metric'");
@@ -819,7 +1183,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam
g_strlcpy (ud->section_name, res, sizeof (ud->section_name));
ud->state = XML_READ_CLASSIFIER;
/* Create object */
- ud->other_data = check_classifier_cfg (ud->cfg, NULL);
+ ud->section_pointer = check_classifier_cfg (ud->cfg, NULL);
}
else {
*error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'type' is required for tag 'classifier'");
@@ -829,28 +1193,30 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam
else if (g_ascii_strcasecmp (element_name, "worker") == 0) {
ud->state = XML_READ_WORKER;
/* Create object */
- ud->other_data = check_worker_conf (ud->cfg, NULL);
+ ud->section_pointer = check_worker_conf (ud->cfg, NULL);
+ }
+ else if (g_ascii_strcasecmp (element_name, "view") == 0) {
+ ud->state = XML_READ_VIEW;
+ /* Create object */
+ ud->section_pointer = init_view (ud->cfg->cfg_pool);
}
- else if (g_ascii_strcasecmp (element_name, "variable") == 0) {
- if (extract_attr ("name", attribute_names, attribute_values, &res)) {
- g_strlcpy (ud->section_name, res, sizeof (ud->section_name));
- ud->state = XML_READ_VARIABLE;
- }
- else {
- *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'name' is required for tag 'variable'");
- ud->state = XML_ERROR;
- }
-
- }
else {
/* Extract other tags */
g_strlcpy (ud->section_name, element_name, sizeof (ud->section_name));
ud->state = XML_READ_VALUE;
}
break;
+ case XML_READ_CLASSIFIER:
+ if (g_ascii_strcasecmp (element_name, "statfile") == 0) {
+ ud->state = XML_READ_STATFILE;
+
+ /* Now section pointer is statfile and parent pointer is classifier */
+ ud->parent_pointer = ud->section_pointer;
+ ud->section_pointer = memory_pool_alloc0 (ud->cfg->cfg_pool, sizeof (struct statfile));
+ }
+ break;
case XML_READ_MODULE:
case XML_READ_FACTORS:
- case XML_READ_CLASSIFIER:
case XML_READ_STATFILE:
case XML_READ_WORKER:
case XML_READ_LOGGING:
@@ -882,6 +1248,9 @@ void
rspamd_xml_end_element (GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error)
{
struct rspamd_xml_userdata *ud = user_data;
+ struct metric *m;
+ struct classifier_config *ccf;
+ struct statfile *st;
gboolean res;
switch (ud->state) {
@@ -893,6 +1262,21 @@ rspamd_xml_end_element (GMarkupParseContext *context, const gchar *element_name,
break;
case XML_READ_STATFILE:
CHECK_TAG ("statfile", FALSE);
+ if (res) {
+ ccf = ud->parent_pointer;
+ st = ud->section_pointer;
+ /* Check statfile and insert it into classifier */
+ if (st->path == NULL || st->size == 0 || st->symbol == NULL) {
+ *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "not enough arguments in statfile definition");
+ ud->state = XML_ERROR;
+ }
+ ccf->statfiles = g_list_prepend (ccf->statfiles, st);
+ ud->cfg->statfiles = g_list_prepend (ud->cfg->statfiles, st);
+ g_hash_table_insert (ud->cfg->classifiers_symbols, st->symbol, ccf);
+ ud->section_pointer = ccf;
+ ud->parent_pointer = NULL;
+ ud->state = XML_READ_CLASSIFIER;
+ }
break;
case XML_READ_FACTORS:
CHECK_TAG ("factors", FALSE);
@@ -900,7 +1284,7 @@ rspamd_xml_end_element (GMarkupParseContext *context, const gchar *element_name,
case XML_READ_METRIC:
CHECK_TAG ("metric", FALSE);
if (res) {
- struct metric *m = ud->other_data;
+ m = ud->section_pointer;
if (m->name == NULL) {
*error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "metric attribute \"name\" is required but missing");
ud->state = XML_ERROR;
@@ -917,11 +1301,15 @@ rspamd_xml_end_element (GMarkupParseContext *context, const gchar *element_name,
CHECK_TAG ("worker", FALSE);
if (res) {
/* Insert object to list */
- ud->cfg->workers = g_list_prepend (ud->cfg->workers, ud->other_data);
+ ud->cfg->workers = g_list_prepend (ud->cfg->workers, ud->section_pointer);
}
break;
- case XML_READ_VARIABLE:
- CHECK_TAG ("variable", TRUE);
+ case XML_READ_VIEW:
+ CHECK_TAG ("view", FALSE);
+ if (res) {
+ /* Insert object to list */
+ ud->cfg->views = g_list_prepend (ud->cfg->views, ud->section_pointer);
+ }
break;
case XML_READ_VALUE:
/* Check tags parity */
@@ -959,13 +1347,13 @@ rspamd_xml_text (GMarkupParseContext *context, const gchar *text, gsize text_len
switch (ud->state) {
case XML_READ_MODULE:
- if (!call_param_handler (ud, ud->section_name, val, ud->other_data, XML_SECTION_MODULE)) {
+ if (!call_param_handler (ud, ud->section_name, val, ud->section_pointer, XML_SECTION_MODULE)) {
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val);
ud->state = XML_ERROR;
}
break;
case XML_READ_CLASSIFIER:
- if (!call_param_handler (ud, ud->section_name, val, ud->other_data, XML_SECTION_CLASSIFIER)) {
+ if (!call_param_handler (ud, ud->section_name, val, ud->section_pointer, XML_SECTION_CLASSIFIER)) {
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val);
ud->state = XML_ERROR;
}
@@ -979,18 +1367,23 @@ rspamd_xml_text (GMarkupParseContext *context, const gchar *text, gsize text_len
}
break;
case XML_READ_METRIC:
- if (!call_param_handler (ud, ud->section_name, val, ud->other_data, XML_SECTION_METRIC)) {
+ if (!call_param_handler (ud, ud->section_name, val, ud->section_pointer, XML_SECTION_METRIC)) {
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val);
ud->state = XML_ERROR;
}
break;
case XML_READ_WORKER:
- if (!call_param_handler (ud, ud->section_name, val, ud->other_data, XML_SECTION_WORKER)) {
+ if (!call_param_handler (ud, ud->section_name, val, ud->section_pointer, XML_SECTION_WORKER)) {
+ *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val);
+ ud->state = XML_ERROR;
+ }
+ break;
+ case XML_READ_VIEW:
+ if (!call_param_handler (ud, ud->section_name, val, ud->section_pointer, XML_SECTION_VIEW)) {
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val);
ud->state = XML_ERROR;
}
break;
- case XML_READ_VARIABLE:
case XML_READ_VALUE:
if (!call_param_handler (ud, ud->section_name, val, cfg, XML_SECTION_MAIN)) {
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val);
diff --git a/src/cfg_xml.h b/src/cfg_xml.h
index ec0547ffe..d27f147ca 100644
--- a/src/cfg_xml.h
+++ b/src/cfg_xml.h
@@ -20,10 +20,10 @@ enum xml_read_state {
XML_READ_FACTORS,
XML_READ_METRIC,
XML_READ_WORKER,
- XML_READ_VARIABLE,
+ XML_READ_VIEW,
XML_READ_LOGGING,
- XML_ERROR,
XML_READ_VALUE,
+ XML_ERROR,
XML_END
};
@@ -31,7 +31,8 @@ struct rspamd_xml_userdata {
enum xml_read_state state;
struct config_file *cfg;
gchar section_name[MAX_NAME];
- gpointer other_data;
+ gpointer section_pointer;
+ gpointer parent_pointer;
GHashTable *cur_attrs;
};
@@ -88,12 +89,36 @@ gboolean xml_handle_boolean (struct config_file *cfg, struct rspamd_xml_userdata
gboolean worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
gboolean worker_handle_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
gboolean worker_handle_bind (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+
gboolean handle_factor (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+
gboolean handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+
gboolean handle_log_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
gboolean handle_log_level (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+
gboolean handle_lua (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+gboolean handle_module_path (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+
+gboolean handle_variable (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+gboolean handle_composite (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+
+gboolean handle_view_ip (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+gboolean handle_view_client_ip (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+gboolean handle_view_from (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+gboolean handle_view_symbols (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+
+gboolean handle_user_settings (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+gboolean handle_domain_settings (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+
+gboolean handle_classifier_tokenizer (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+gboolean handle_classifier_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+
+gboolean handle_statfile_normalizer (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+gboolean handle_statfile_binlog (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+gboolean handle_statfile_binlog_rotate (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
+gboolean handle_statfile_binlog_master (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, int offset);
/* Dumper functions */
gboolean xml_dump_config (struct config_file *cfg, const char *filename);
diff --git a/src/lua/lua_cfg_file.c b/src/lua/lua_cfg_file.c
index 1ac334299..8be11b02b 100644
--- a/src/lua/lua_cfg_file.c
+++ b/src/lua/lua_cfg_file.c
@@ -121,7 +121,7 @@ lua_process_element (struct config_file *cfg, const char *name, struct module_op
opt->lua_type = LUA_VAR_STRING;
break;
case LUA_TFUNCTION:
- opt->actual_data = (gpointer)lua_topointer (L, idx);
+ opt->actual_data = memory_pool_strdup (cfg->cfg_pool, lua_tostring (L, idx));
opt->lua_type = LUA_VAR_FUNCTION;
break;
case LUA_TNIL:
@@ -152,7 +152,7 @@ lua_module_callback (gpointer key, gpointer value, gpointer ud)
lua_getglobal (L, "config");
if (lua_istable (L, -1)) {
lua_pushstring (L, opt->param);
- lua_gettable (L, -2);
+ lua_gettable (L, -2);
if (lua_isnil (L, -1)) {
/* Try to get global variable */
lua_getglobal (L, opt->param);
@@ -194,3 +194,103 @@ lua_post_load_config (struct config_file *cfg)
/* Now parse all lua params */
g_hash_table_foreach (cfg->modules_opts, lua_module_callback, cfg);
}
+
+/* Handle lua dynamic config param */
+gboolean
+lua_handle_param (struct worker_task *task, gchar *mname, gchar *optname, enum lua_var_type expected_type, gpointer *res)
+{
+ lua_State *L = task->cfg->lua_state;
+ GList *cur;
+ struct module_opt *opt;
+ struct worker_task **ptask;
+ double num_res;
+ gboolean bool_res;
+ gchar *str_res;
+
+ if ((cur = g_hash_table_lookup (task->cfg->modules_opts, mname)) == NULL) {
+ *res = NULL;
+ return FALSE;
+ }
+
+ /* Search for specified option */
+ while (cur) {
+ opt = cur->data;
+ if (opt->is_lua && g_ascii_strcasecmp (opt->param, optname) == 0) {
+ if (opt->lua_type == expected_type) {
+ /* Just push pointer to res */
+ *res = opt->actual_data;
+ return TRUE;
+ }
+ else if (opt->lua_type == LUA_VAR_FUNCTION) {
+ /* Call specified function and expect result of given expected_type */
+ /* First check function in config table */
+ lua_getglobal (L, "config");
+ if (lua_istable (L, -1)) {
+ lua_pushstring (L, opt->actual_data);
+ lua_gettable (L, -2);
+ if (lua_isnil (L, -1)) {
+ /* Try to get global variable */
+ lua_getglobal (L, opt->actual_data);
+ }
+ }
+ else {
+ /* Try to get global variable */
+ lua_getglobal (L, opt->actual_data);
+ }
+ if (lua_isnil (L, -1)) {
+ msg_err ("function with name %s is not defined", (gchar *)opt->actual_data);
+ return FALSE;
+ }
+ /* Now we got function in top of stack */
+ ptask = lua_newuserdata (L, sizeof (struct worker_task *));
+ lua_setclass (L, "rspamd{task}", -1);
+ *ptask = task;
+ /* Call function */
+ if (lua_pcall (L, 1, 1, 0) != 0) {
+ msg_info ("call to %s failed: %s", (gchar *)opt->actual_data, lua_tostring (L, -1));
+ *res = NULL;
+ return FALSE;
+ }
+ /* Get result of specified type */
+ switch (expected_type) {
+ case LUA_VAR_NUM:
+ if (!lua_isnumber (L, -1)) {
+ *res = NULL;
+ return FALSE;
+ }
+ num_res = lua_tonumber (L, -1);
+ *res = memory_pool_alloc (task->task_pool, sizeof (double));
+ **(double **)res = num_res;
+ return TRUE;
+ case LUA_VAR_BOOLEAN:
+ if (!lua_isboolean (L, -1)) {
+ *res = NULL;
+ return FALSE;
+ }
+ bool_res = lua_toboolean (L, -1);
+ *res = memory_pool_alloc (task->task_pool, sizeof (gboolean));
+ **(gboolean **)res = bool_res;
+ return TRUE;
+ case LUA_VAR_STRING:
+ if (!lua_isstring (L, -1)) {
+ *res = NULL;
+ return FALSE;
+ }
+ str_res = memory_pool_strdup (task->task_pool, lua_tostring (L, -1));
+ *res = str_res;
+ return TRUE;
+ case LUA_VAR_FUNCTION:
+ case LUA_VAR_UNKNOWN:
+ msg_err ("cannot expect function or unknown types");
+ *res = NULL;
+ return FALSE;
+ }
+ }
+ }
+ cur = g_list_next (cur);
+ }
+
+ /* Option not found */
+ *res = NULL;
+ return FALSE;
+}
diff --git a/src/lua/lua_common.c b/src/lua/lua_common.c
index 3d4e29b28..c73b663bb 100644
--- a/src/lua/lua_common.c
+++ b/src/lua/lua_common.c
@@ -181,7 +181,7 @@ luaopen_logger (lua_State * L)
}
void
-init_lua ()
+init_lua (struct config_file *cfg)
{
if (L == NULL) {
L = lua_open ();
@@ -198,6 +198,7 @@ init_lua ()
(void)luaopen_message (L);
(void)luaopen_classifier (L);
(void)luaopen_statfile (L);
+ cfg->lua_state = L;
}
}
@@ -361,7 +362,6 @@ 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) {
diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h
index 5de7bdc71..4c8ff2585 100644
--- a/src/lua/lua_common.h
+++ b/src/lua/lua_common.h
@@ -30,7 +30,7 @@ int luaopen_hash_table (lua_State *L);
int luaopen_textpart (lua_State *L);
int luaopen_classifier (lua_State *L);
int luaopen_statfile (lua_State * L);
-void init_lua ();
+void init_lua (struct config_file *cfg);
void init_lua_filters (struct config_file *cfg);
/* Filters functions */
@@ -48,6 +48,8 @@ double lua_normalizer_func (double score, void *params);
/* Config file functions */
void lua_post_load_config (struct config_file *cfg);
void lua_process_element (struct config_file *cfg, const char *name, struct module_opt *opt, int idx);
+gboolean lua_handle_param (struct worker_task *task, gchar *mname, gchar *optname,
+ enum lua_var_type expected_type, gpointer *res);
#endif /* WITH_LUA */
diff --git a/src/main.c b/src/main.c
index 926d0e5c6..022773038 100644
--- a/src/main.c
+++ b/src/main.c
@@ -28,6 +28,7 @@
#include "util.h"
#include "lmtp.h"
#include "fuzzy_storage.h"
+#include "cfg_xml.h"
#ifndef WITHOUT_PERL
@@ -65,8 +66,14 @@ GQueue *signals_info;
extern int yynerrs;
extern FILE *yyin;
-static int dump_vars = 0;
-static int dump_cache = 0;
+static gboolean config_test;
+static gboolean no_fork;
+static gchar *cfg_name;
+static gchar *rspamd_user;
+static gchar *rspamd_group;
+static gchar *rspamd_pidfile;
+static gboolean dump_vars;
+static gboolean dump_cache;
#ifndef WITHOUT_PERL
extern void xs_init (pTHX);
@@ -76,6 +83,21 @@ extern PerlInterpreter *perl_interpreter;
/* List of workers that are pending to start */
static GList *workers_pending = NULL;
+/* Commandline options */
+static GOptionEntry entries[] =
+{
+ { "config-test", 't', 0, G_OPTION_ARG_NONE, &config_test, "Do config test and exit", NULL },
+ { "no-fork", 'f', 0, G_OPTION_ARG_NONE, &no_fork, "Do not daemonize main process", NULL },
+ { "config", 'c', 0, G_OPTION_ARG_STRING, &cfg_name, "Specify config file", NULL },
+ { "user", 'u', 0, G_OPTION_ARG_STRING, &rspamd_user, "User to run rspamd as", NULL },
+ { "group", 'g', 0, G_OPTION_ARG_STRING, &rspamd_group, "Group to run rspamd as", NULL },
+ { "pid", 'p', 0, G_OPTION_ARG_STRING, &rspamd_pidfile, "Path to pidfile", NULL },
+ { "dump-vars", 'V', 0, G_OPTION_ARG_NONE, &dump_vars, "Print all rspamd variables and exit", NULL },
+ { "dump-cache", 'C', 0, G_OPTION_ARG_NONE, &dump_cache, "Dump symbols cache stats and exit", NULL },
+ { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
+};
+
+
#ifndef HAVE_SA_SIGINFO
static void
sig_handler (int signo)
@@ -156,61 +178,22 @@ print_signals_info ()
static void
read_cmd_line (int argc, char **argv, struct config_file *cfg)
{
- int ch;
- while ((ch = getopt (argc, argv, "tVChfc:u:g:p:")) != -1) {
- switch (ch) {
- case 'f':
- cfg->no_fork = 1;
- break;
- case 'c':
- if (optarg && cfg->cfg_name) {
- cfg->cfg_name = memory_pool_strdup (cfg->cfg_pool, optarg);
- }
- break;
- case 't':
- cfg->config_test = 1;
- break;
- case 'V':
- dump_vars = 1;
- break;
- case 'C':
- dump_cache = 1;
- break;
- case 'u':
- if (optarg) {
- cfg->rspamd_user = memory_pool_strdup (cfg->cfg_pool, optarg);
- }
- break;
- case 'g':
- if (optarg) {
- cfg->rspamd_group = memory_pool_strdup (cfg->cfg_pool, optarg);
- }
- break;
- case 'p':
- if (optarg) {
- cfg->pid_file = memory_pool_strdup (cfg->cfg_pool, optarg);
- }
- break;
- case 'h':
- case '?':
- default:
- /* Show help message and exit */
- printf ("Rspamd version " RVERSION "\n"
- "Usage: rspamd [-t] [-h] [-n] [-f] [-c config_file]\n"
- "-h: This help message\n"
- "-t: Do config test and exit\n"
- "-C: Dump symbols cache stats and exit\n"
- "-V Print all rspamd variables and exit\n"
- "-f: Do not daemonize main process\n"
- "-c: Specify config file (./rspamd.conf is used by default)\n"
- "-u: User to run rspamd as\n"
- "-g: Group to run rspamd as\n"
- "-p: Path to pidfile\n"
- );
- exit (0);
- break;
- }
- }
+ GError *error = NULL;
+ GOptionContext *context;
+
+ context = g_option_context_new ("- run rspamd daemon");
+ g_option_context_set_summary (context, "Summary:\n Rspamd daemon version " RVERSION);
+ g_option_context_add_main_entries (context, entries, NULL);
+ if (!g_option_context_parse (context, &argc, &argv, &error)) {
+ fprintf (stderr, "option parsing failed: %s\n", error->message);
+ exit (1);
+ }
+ cfg->no_fork = no_fork;
+ cfg->config_test = config_test;
+ cfg->rspamd_user = rspamd_user;
+ cfg->rspamd_group = rspamd_group;
+ cfg->cfg_name = cfg_name;
+ cfg->pid_file = rspamd_pidfile;
}
static void
@@ -598,8 +581,10 @@ main (int argc, char **argv, char **env)
bzero (&signals, sizeof (struct sigaction));
- rspamd->cfg->cfg_name = memory_pool_strdup (rspamd->cfg->cfg_pool, FIXED_CONFIG_FILE);
read_cmd_line (argc, argv, rspamd->cfg);
+ if (rspamd->cfg->cfg_name == NULL) {
+ rspamd->cfg->cfg_name = FIXED_CONFIG_FILE;
+ }
if (cfg->config_test) {
cfg->log_level = G_LOG_LEVEL_DEBUG;
@@ -624,7 +609,7 @@ main (int argc, char **argv, char **env)
#ifndef HAVE_SETPROCTITLE
init_title (argc, argv, environ);
#endif
- init_lua ();
+ init_lua (cfg);
f = fopen (rspamd->cfg->cfg_name, "r");
if (f == NULL) {