#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
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 {
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
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
}
},
{ 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
/* 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)
{
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) {
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) {
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);
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)
{
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)
{
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)
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'");
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'");
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:
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) {
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);
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;
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 */
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;
}
}
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);
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
};
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;
};
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);
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:
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);
/* 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;
+}
#include "util.h"
#include "lmtp.h"
#include "fuzzy_storage.h"
+#include "cfg_xml.h"
#ifndef WITHOUT_PERL
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);
/* 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)
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
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;
#ifndef HAVE_SETPROCTITLE
init_title (argc, argv, environ);
#endif
- init_lua ();
+ init_lua (cfg);
f = fopen (rspamd->cfg->cfg_name, "r");
if (f == NULL) {