From: Vsevolod Stakhov Date: Wed, 23 Oct 2013 16:30:48 +0000 (+0100) Subject: Start to eliminate xml configuration. X-Git-Tag: 0.6.0~113 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=abb2091e00e5d07a9a2393e4ef1b281efee3f47a;p=rspamd.git Start to eliminate xml configuration. --- diff --git a/src/cfg_utils.c b/src/cfg_utils.c index 8a49237ac..49fb609ab 100644 --- a/src/cfg_utils.c +++ b/src/cfg_utils.c @@ -986,18 +986,11 @@ read_xml_config (struct config_file *cfg, const gchar *filename) /* Prepare xml parser */ ud.cfg = cfg; - ud.state = XML_READ_START; - ud.if_stack = g_queue_new (); - + ud.state = 0; ctx = g_markup_parse_context_new (&xml_parser, G_MARKUP_TREAT_CDATA_AS_TEXT, &ud, NULL); init_kvstorage_config (); res = g_markup_parse_context_parse (ctx, data, st.st_size, &err); - if (g_queue_get_length (ud.if_stack) != 0) { - msg_err ("unexpected nesting for if arguments"); - res = FALSE; - } - munmap (data, st.st_size); return res; diff --git a/src/cfg_xml.c b/src/cfg_xml.c index 6524d050a..2757fded2 100644 --- a/src/cfg_xml.c +++ b/src/cfg_xml.c @@ -41,11 +41,32 @@ #include "lua/lua_common.h" +enum xml_read_state { + XML_READ_START, + XML_READ_PARAM, + XML_READ_MODULE, + XML_READ_MODULE_META, + XML_READ_MODULES, + XML_READ_CLASSIFIER, + XML_READ_STATFILE, + XML_READ_METRIC, + XML_READ_WORKER, + XML_READ_VIEW, + XML_READ_LOGGING, + XML_READ_OPTIONS, + XML_READ_VALUE, + XML_SKIP_ELEMENTS, + XML_ERROR, + XML_SUBPARSER, + XML_END +}; + /* Maximum attributes for param */ #define MAX_PARAM 64 #define EOL "\n" +#if 0 #define NULL_ATTR \ { \ NULL, \ @@ -640,6 +661,7 @@ GHashTable *module_options = NULL, *worker_options = NULL, *classifier_options = NULL, *subparsers = NULL; +#endif GQuark xml_error_quark (void) @@ -710,482 +732,26 @@ extract_attr (const gchar *attr, const gchar **attribute_names, const gchar **at return FALSE; } -static inline gchar* -xml_asciiz_string (memory_pool_t *pool, const gchar *text, gsize len) -{ - gchar *val; - - val = memory_pool_alloc (pool, len + 1); - rspamd_strlcpy (val, text, len + 1); - - return val; -} /* Find among attributes required ones and form new array of pairs attribute-value */ -static GHashTable * -process_attrs (struct config_file *cfg, const gchar **attribute_names, const gchar **attribute_values) +static void +process_attrs (const gchar **attribute_names, const gchar **attribute_values, ucl_object_t *top) { const gchar **attr, **value; GHashTable *res; - if (*attribute_names == NULL) { - /* No attributes required */ - return NULL; - } - - res = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal); - attr = attribute_names; value = attribute_values; while (*attr) { /* Copy attributes to pool */ - g_hash_table_insert (res, memory_pool_strdup (cfg->cfg_pool, *attr), memory_pool_strdup (cfg->cfg_pool, *value)); + ucl_object_insert_key (top, ucl_object_fromstring_common (*value, 0, UCL_STRING_PARSE), *attr, 0, TRUE); attr ++; value ++; } - - memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func)g_hash_table_destroy, res); - - return res; } -static gboolean -call_param_handler (struct rspamd_xml_userdata *ctx, const gchar *name, gchar *value, gpointer dest_struct, enum xml_config_section section) -{ - struct xml_parser_rule *rule; - struct xml_config_param *param; - guint i; - - /* First find required section */ - for (i = 0; i < G_N_ELEMENTS (grammar); i ++) { - rule = &grammar[i]; - if (rule->section == section) { - /* Now find attribute in section or call default handler */ - param = &rule->params[0]; - while (param && param->handler) { - if (param->name && g_ascii_strcasecmp (param->name, name) == 0) { - /* Call specified handler */ - return param->handler (ctx->cfg, ctx, ctx->cur_attrs, value, param->user_data, dest_struct, param->offset); - } - param ++; - } - if (rule->default_param.handler != NULL) { - /* Call default handler */ - return rule->default_param.handler (ctx->cfg, ctx, name, ctx->cur_attrs, value, param->user_data, dest_struct, param->offset); - } - } - } - - msg_err ("could not find handler for tag %s at section %d", name, section); - return FALSE; -} /* 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, gint offset) -{ - gchar *val; - if (g_ascii_strcasecmp (data, "file") == 0) { - /* Find filename attribute */ - if (attrs == NULL || (val = g_hash_table_lookup (attrs, "filename")) == NULL) { - msg_err ("cannot log to file that is not specified"); - return FALSE; - } - cfg->log_type = RSPAMD_LOG_FILE; - cfg->log_file = val; - } - else if (g_ascii_strcasecmp (data, "console") == 0) { - cfg->log_type = RSPAMD_LOG_CONSOLE; - } - else if (g_ascii_strcasecmp (data, "syslog") == 0) { - if (attrs == NULL || (val = g_hash_table_lookup (attrs, "facility")) == NULL) { - msg_err ("cannot log to syslog when facility is not specified"); - return FALSE; - } - cfg->log_type = RSPAMD_LOG_SYSLOG; - /* Rather ugly check */ - if (g_ascii_strncasecmp (val, "LOG_AUTH", sizeof ("LOG_AUTH") - 1) == 0 || g_ascii_strncasecmp (val, "auth", sizeof ("auth") - 1) == 0 ) { - cfg->log_facility = LOG_AUTH; - } - else if (g_ascii_strncasecmp (val, "LOG_CRON", sizeof ("LOG_CRON") - 1) == 0 || g_ascii_strncasecmp (val, "cron", sizeof ("cron") - 1) == 0 ) { - cfg->log_facility = LOG_CRON; - } - else if (g_ascii_strncasecmp (val, "LOG_DAEMON", sizeof ("LOG_DAEMON") - 1) == 0 || g_ascii_strncasecmp (val, "daemon", sizeof ("daemon") - 1) == 0 ) { - cfg->log_facility = LOG_DAEMON; - } - else if (g_ascii_strncasecmp (val, "LOG_MAIL", sizeof ("LOG_MAIL") - 1) == 0 || g_ascii_strncasecmp (val, "mail", sizeof ("mail") - 1) == 0) { - cfg->log_facility = LOG_MAIL; - } - else if (g_ascii_strncasecmp (val, "LOG_USER", sizeof ("LOG_USER") - 1) == 0 || g_ascii_strncasecmp (val, "user", sizeof ("user") - 1) == 0 ) { - cfg->log_facility = LOG_USER; - } - else if (g_ascii_strncasecmp (val, "LOG_LOCAL0", sizeof ("LOG_LOCAL0") - 1) == 0 || g_ascii_strncasecmp (val, "local0", sizeof ("local0") - 1) == 0) { - cfg->log_facility = LOG_LOCAL0; - } - else if (g_ascii_strncasecmp (val, "LOG_LOCAL1", sizeof ("LOG_LOCAL1") - 1) == 0 || g_ascii_strncasecmp (val, "local1", sizeof ("local1") - 1) == 0) { - cfg->log_facility = LOG_LOCAL1; - } - else if (g_ascii_strncasecmp (val, "LOG_LOCAL2", sizeof ("LOG_LOCAL2") - 1) == 0 || g_ascii_strncasecmp (val, "local2", sizeof ("local2") - 1) == 0) { - cfg->log_facility = LOG_LOCAL2; - } - else if (g_ascii_strncasecmp (val, "LOG_LOCAL3", sizeof ("LOG_LOCAL3") - 1) == 0 || g_ascii_strncasecmp (val, "local3", sizeof ("local3") - 1) == 0) { - cfg->log_facility = LOG_LOCAL3; - } - else if (g_ascii_strncasecmp (val, "LOG_LOCAL4", sizeof ("LOG_LOCAL4") - 1) == 0 || g_ascii_strncasecmp (val, "local4", sizeof ("local4") - 1) == 0) { - cfg->log_facility = LOG_LOCAL4; - } - else if (g_ascii_strncasecmp (val, "LOG_LOCAL5", sizeof ("LOG_LOCAL5") - 1) == 0 || g_ascii_strncasecmp (val, "local5", sizeof ("local5") - 1) == 0) { - cfg->log_facility = LOG_LOCAL5; - } - else if (g_ascii_strncasecmp (val, "LOG_LOCAL6", sizeof ("LOG_LOCAL6") - 1) == 0 || g_ascii_strncasecmp (val, "local6", sizeof ("local6") - 1) == 0) { - cfg->log_facility = LOG_LOCAL6; - } - else if (g_ascii_strncasecmp (val, "LOG_LOCAL7", sizeof ("LOG_LOCAL7") - 1) == 0 || g_ascii_strncasecmp (val, "local7", sizeof ("local7") - 1) == 0) { - cfg->log_facility = LOG_LOCAL7; - } - else { - msg_err ("invalid logging facility: %s", val); - return FALSE; - } - } - else { - msg_err ("invalid logging type: %s", data); - return FALSE; - } - - return TRUE; -} - -gboolean -handle_log_level (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - if (g_ascii_strcasecmp (data, "error") == 0) { - cfg->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL; - } - else if (g_ascii_strcasecmp (data, "warning") == 0) { - cfg->log_level = G_LOG_LEVEL_WARNING; - } - else if (g_ascii_strcasecmp (data, "info") == 0) { - cfg->log_level = G_LOG_LEVEL_INFO | G_LOG_LEVEL_MESSAGE; - } - else if (g_ascii_strcasecmp (data, "debug") == 0) { - cfg->log_level = G_LOG_LEVEL_DEBUG; - } - else { - msg_err ("unknown log level: %s", data); - return FALSE; - } - - return TRUE; -} - -gboolean -options_handle_nameserver (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - cfg->nameservers = g_list_prepend (cfg->nameservers, memory_pool_strdup (cfg->cfg_pool, data)); - return TRUE; -} - -/* Worker section */ - -struct wrk_cbdata { - struct worker_conf *wrk; - struct config_file *cfg; - struct rspamd_xml_userdata *ctx; -}; - -struct wrk_param { - gboolean is_list; - union { - gchar *param; - GList *list; - } d; - GHashTable *attrs; -}; - -static void -worker_foreach_callback (gpointer k, gpointer v, gpointer ud) -{ - struct wrk_cbdata *cd = ud; - struct wrk_param *param = v; - struct xml_config_param *cparam; - GList *cur; - GHashTable *worker_config; - - if (!worker_options || (worker_config = g_hash_table_lookup (worker_options, &cd->wrk->type)) == NULL) { - return; - } - if ((cparam = g_hash_table_lookup (worker_config, k)) == NULL) { - /* Try to use universal handler if there is no specific handler */ - if ((cparam = g_hash_table_lookup (worker_config, "*")) != NULL) { - if (cd->wrk->ctx != NULL) { - if (param->is_list) { - cur = param->d.list; - while (cur) { - cparam->handler (cd->cfg, cd->ctx, param->attrs, cur->data, k, cd->wrk->ctx, cparam->offset); - cur = g_list_next (cur); - } - } - else { - cparam->handler (cd->cfg, cd->ctx, param->attrs, param->d.param, k, cd->wrk->ctx, cparam->offset); - } - } - else { - msg_err ("Bad error detected: worker %s has not initialized its context", g_quark_to_string (cd->wrk->type)); - } - } - else { - msg_warn ("unregistered worker attribute '%s' for worker %s", k, g_quark_to_string (cd->wrk->type)); - } - } - else { - - if (cd->wrk->ctx != NULL) { - if (param->is_list) { - cur = param->d.list; - while (cur) { - cparam->handler (cd->cfg, cd->ctx, param->attrs, cur->data, NULL, cd->wrk->ctx, cparam->offset); - cur = g_list_next (cur); - } - } - else { - cparam->handler (cd->cfg, cd->ctx, param->attrs, param->d.param, NULL, cd->wrk->ctx, cparam->offset); - } - } - else { - msg_err ("Bad error detected: worker %s has not initialized its context", g_quark_to_string (cd->wrk->type)); - } - } -} - -gboolean -worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, const gchar *tag, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - struct worker_conf *wrk = ctx->section_pointer; - const gchar *name, *tmp; - struct wrk_param *param; - - if (g_ascii_strcasecmp (tag, "option") == 0 || g_ascii_strcasecmp (tag, "param") == 0) { - if (attrs == NULL || (name = g_hash_table_lookup (attrs, "name")) == NULL) { - msg_err ("worker param tag must have \"name\" attribute"); - return FALSE; - } - } - else { - name = memory_pool_strdup (cfg->cfg_pool, tag); - } - - if ((param = g_hash_table_lookup (wrk->params, name)) == NULL) { - param = memory_pool_alloc (cfg->cfg_pool, sizeof (struct wrk_param)); - param->is_list = FALSE; - param->d.param = memory_pool_strdup (cfg->cfg_pool, data); - g_hash_table_insert (wrk->params, (char *)name, param); - /* Copy attributes */ - param->attrs = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal); - memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func)g_hash_table_destroy, param->attrs); - rspamd_hash_table_copy (attrs, param->attrs, rspamd_str_pool_copy, rspamd_str_pool_copy, cfg->cfg_pool); - } - else { - if (param->is_list) { - param->d.list = g_list_append (param->d.list, memory_pool_strdup (cfg->cfg_pool, data)); - } - else { - /* Convert to list */ - param->is_list = TRUE; - tmp = param->d.param; - param->d.list = g_list_prepend (NULL, (gpointer)tmp); - param->d.list = g_list_append (param->d.list, memory_pool_strdup (cfg->cfg_pool, data)); - memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func)g_list_free, param->d.list); - } - rspamd_hash_table_copy (attrs, param->attrs, rspamd_str_pool_copy, rspamd_str_pool_copy, cfg->cfg_pool); - } - - return TRUE; -} - -gboolean -worker_handle_type (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - struct worker_conf *wrk = ctx->section_pointer; - GQuark type; - - type = g_quark_try_string (data); - - if (type != 0) { - wrk->worker = get_worker_by_type (type); - if (wrk->worker == NULL) { - msg_err ("unknown worker type: %s", data); - return FALSE; - } - wrk->type = type; - if (wrk->worker->worker_init_func) { - wrk->ctx = wrk->worker->worker_init_func (cfg); - } - } - else { - msg_err ("unknown worker type: %s", data); - return FALSE; - } - - return TRUE; -} - -gboolean -worker_handle_bind (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - struct worker_conf *wrk = ctx->section_pointer; - - if (!parse_bind_line (cfg, wrk, data)) { - msg_err ("cannot parse bind_socket: %s", data); - return FALSE; - } - - return TRUE; -} - -gboolean -handle_metric_action (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - struct metric *metric = ctx->section_pointer; - gchar *p, *errstr; - gint res; - struct metric_action *action; - - /* First of all check whether we have data with weight (reject:50 for example) */ - if ((p = strchr (data, ':')) == NULL) { - if (check_action_str (data, &res)) { - /* XXX: no longer needed */ - return TRUE; - } - return FALSE; - } - else { - if (!check_action_str (data, &res)) { - return FALSE; - } - else { - action = &metric->actions[res]; - action->action = res; - errno = 0; - action->score = strtod (p + 1, &errstr); - if (errno != 0 || (errstr != NULL && *errstr != '\0')) { - msg_err ("invalid double value: %s", data); - return FALSE; - } - } - } - - return TRUE; -} - -static gint -symbols_group_find_func (gconstpointer a, gconstpointer b) -{ - const struct symbols_group *gr = a; - const gchar *uv = b; - - return g_ascii_strcasecmp (gr->name, uv); -} - -gboolean -handle_metric_symbol (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - gchar *strval, *err, *desc, *group; - double *value; - GList *metric_list, *group_list; - struct metric *metric = ctx->section_pointer; - struct symbols_group *sym_group; - struct symbol_def *sym_def; - - sym_def = memory_pool_alloc (cfg->cfg_pool, sizeof (struct symbol_def)); - value = memory_pool_alloc (cfg->cfg_pool, sizeof (double)); - - if (attrs == NULL || (strval = g_hash_table_lookup (attrs, "weight")) == NULL) { - msg_info ("symbol tag should have \"weight\" attribute, assume weight 1.0"); - *value = 1.0; - } - else { - errno = 0; - *value = strtod (strval, &err); - if (errno != 0 || (err != NULL && *err != 0)) { - msg_err ("invalid number: %s, %s", strval, strerror (errno)); - return FALSE; - } - } - - sym_def->weight_ptr = value; - sym_def->name = memory_pool_strdup (cfg->cfg_pool, data); - - if (attrs != NULL) { - desc = g_hash_table_lookup (attrs, "description"); - if (desc) { - sym_def->description = memory_pool_strdup (cfg->cfg_pool, desc); - g_hash_table_insert (metric->descriptions, data, sym_def->description); - } - else { - sym_def->description = NULL; - } - group = g_hash_table_lookup (attrs, "group"); - if (group == NULL) { - group = "ungrouped"; - } - } - else { - group = "ungrouped"; - sym_def->description = NULL; - } - - g_hash_table_insert (metric->symbols, sym_def->name, value); - - if ((metric_list = g_hash_table_lookup (cfg->metrics_symbols, sym_def->name)) == NULL) { - metric_list = g_list_prepend (NULL, metric); - memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func)g_list_free, metric_list); - g_hash_table_insert (cfg->metrics_symbols, sym_def->name, metric_list); - } - else { - /* Slow but keep start element of list in safe */ - if (!g_list_find (metric_list, metric)) { - metric_list = g_list_append (metric_list, metric); - } - } - - /* Search for symbol group */ - group_list = g_list_find_custom (cfg->symbols_groups, group, symbols_group_find_func); - if (group_list == NULL) { - /* Create new group */ - sym_group = memory_pool_alloc (cfg->cfg_pool, sizeof (struct symbols_group)); - sym_group->name = memory_pool_strdup (cfg->cfg_pool, group); - sym_group->symbols = NULL; - cfg->symbols_groups = g_list_prepend (cfg->symbols_groups, sym_group); - } - else { - sym_group = group_list->data; - } - /* Insert symbol */ - sym_group->symbols = g_list_prepend (sym_group->symbols, sym_def); - - return TRUE; -} - -/* Modules section */ -gboolean -handle_module_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, const gchar *tag, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - /* XXX: convert to RCL */ - - return TRUE; -} - -gboolean -handle_module_meta (struct config_file *cfg, struct rspamd_xml_userdata *ctx, const gchar *tag, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - /* XXX: Remove, unneeded and never used */ - - return TRUE; -} static void set_lua_globals (struct config_file *cfg, lua_State *L) @@ -1515,15 +1081,9 @@ handle_classifier_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, name = memory_pool_strdup (cfg->cfg_pool, tag); } - if (!classifier_options || - (classifier_config = g_hash_table_lookup (classifier_options, ccf->classifier->name)) == NULL || - (cparam = g_hash_table_lookup (classifier_config, name)) == NULL) { - msg_warn ("unregistered classifier attribute '%s' for classifier %s", name, ccf->classifier->name); - return FALSE; - } - else { - g_hash_table_insert (ccf->opts, (char *)name, memory_pool_strdup (cfg->cfg_pool, data)); - } + + g_hash_table_insert (ccf->opts, (char *)name, memory_pool_strdup (cfg->cfg_pool, data)); + return TRUE; } @@ -1607,221 +1167,18 @@ handle_statfile_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, c 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, gint offset) -{ - /* Simply assign pointer to pointer */ - gchar **dest; - - dest = (gchar **)G_STRUCT_MEMBER_P (dest_struct, offset); - *dest = memory_pool_strdup (cfg->cfg_pool, data); - - return TRUE; -} - -gboolean -xml_handle_string_list (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - GList **dest; - gchar **tokens, **cur; - - dest = (GList **)G_STRUCT_MEMBER_P (dest_struct, offset); - *dest = NULL; - - tokens = g_strsplit_set (data, ";,", 0); - if (!tokens || !tokens[0]) { - return FALSE; - } - memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func)g_strfreev, tokens); - cur = tokens; - while (*cur) { - *dest = g_list_prepend (*dest, *cur); - cur ++; - } - - return TRUE; -} - -gboolean -xml_handle_list (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) +/* XML callbacks */ +void +rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, + const gchar **attribute_values, gpointer user_data, GError **error) { - /* Simply assign pointer to pointer */ - GList **dest; - - dest = (GList **)G_STRUCT_MEMBER_P (dest_struct, offset); - *dest = g_list_prepend (*dest, memory_pool_strdup (cfg->cfg_pool, data)); - - return TRUE; -} - + struct rspamd_xml_userdata *ud = user_data; + struct xml_subparser *subparser; + struct classifier_config *ccf; + gchar *res, *condition; + ucl_object_t *obj; -gboolean -xml_handle_size (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - gsize *dest; - dest = (gsize *)G_STRUCT_MEMBER_P (dest_struct, offset); - *dest = (gsize)parse_limit (data, -1); - - return TRUE; -} - -/* Guint64 variant */ -gboolean -xml_handle_size_64 (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - guint64 *dest; - - dest = (guint64 *)G_STRUCT_MEMBER_P (dest_struct, offset); - *dest = parse_limit (data, -1); - - return TRUE; -} - -gboolean -xml_handle_seconds (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - guint32 *dest; - - dest = (guint32 *)G_STRUCT_MEMBER_P (dest_struct, offset); - *dest = rint (cfg_parse_time (data, TIME_SECONDS)); - - return TRUE; -} - -gboolean -xml_handle_seconds_double (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - gdouble *dest; - - dest = (gdouble *)G_STRUCT_MEMBER_P (dest_struct, offset); - *dest = cfg_parse_time (data, TIME_SECONDS); - - return TRUE; -} - -gboolean -xml_handle_boolean (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - gboolean *dest; - - dest = (gboolean *)G_STRUCT_MEMBER_P (dest_struct, offset); - *dest = parse_flag (data); - /* gchar -> gboolean */ - if (*dest == -1) { - msg_err ("bad boolean: %s", data); - return FALSE; - } - else if (*dest == 1) { - *dest = TRUE; - } - - return TRUE; -} - -gboolean -xml_handle_deprecated (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - - msg_err ("parameter is depreciated: %s", ctx->section_name); - return TRUE; -} - -gboolean -xml_handle_double (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - double *dest; - gchar *err = NULL; - - dest = (double *)G_STRUCT_MEMBER_P (dest_struct, offset); - errno = 0; - *dest = strtod (data, &err); - if (errno != 0 || (err != NULL && *err != 0)) { - msg_err ("invalid number: %s, %s", data, strerror (errno)); - return FALSE; - } - - return TRUE; -} - -gboolean -xml_handle_int (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - gint *dest; - gchar *err = NULL; - - dest = (gint *)G_STRUCT_MEMBER_P (dest_struct, offset); - errno = 0; - *dest = strtol (data, &err, 10); - if (errno != 0 || (err != NULL && *err != 0)) { - msg_err ("invalid number: %s, %s", data, strerror (errno)); - return FALSE; - } - - return TRUE; -} - -gboolean -xml_handle_uint32 (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - guint32 *dest; - gchar *err = NULL; - - dest = (guint32 *)G_STRUCT_MEMBER_P (dest_struct, offset); - errno = 0; - *dest = strtoul (data, &err, 10); - if (errno != 0 || (err != NULL && *err != 0)) { - msg_err ("invalid number: %s, %s", data, strerror (errno)); - return FALSE; - } - - return TRUE; -} - -gboolean -xml_handle_uint16 (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) -{ - guint16 *dest; - gchar *err = NULL; - - dest = (guint16 *)G_STRUCT_MEMBER_P (dest_struct, offset); - errno = 0; - *dest = strtoul (data, &err, 10); - if (errno != 0 || (err != NULL && *err != 0)) { - msg_err ("invalid number: %s, %s", data, strerror (errno)); - return FALSE; - } - - return TRUE; -} - -/* XML callbacks */ -void -rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, - const gchar **attribute_values, gpointer user_data, GError **error) -{ - struct rspamd_xml_userdata *ud = user_data; - struct xml_subparser *subparser; - struct classifier_config *ccf; - gchar *res, *condition; - - - if (g_ascii_strcasecmp (element_name, "if") == 0) { - /* Push current state to queue */ - g_queue_push_head (ud->if_stack, GSIZE_TO_POINTER ((gsize)ud->state)); - /* Now get attributes */ - ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values); - if (ud->cur_attrs == NULL || (condition = g_hash_table_lookup (ud->cur_attrs, "condition")) == NULL) { - msg_err ("unknown condition attribute for if tag"); - *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'condition' is required for tag 'if'"); - ud->state = XML_ERROR; - } - else if (! lua_check_condition (ud->cfg, condition)) { - ud->state = XML_SKIP_ELEMENTS; - } - return; - } switch (ud->state) { case XML_READ_START: if (g_ascii_strcasecmp (element_name, "rspamd") != 0) { @@ -1835,84 +1192,37 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam break; case XML_READ_PARAM: /* Read parameter name and try to find among list of known parameters */ - if (g_ascii_strcasecmp (element_name, "module") == 0) { - /* Read module data */ - if (extract_attr ("name", attribute_names, attribute_values, &res)) { - ud->parent_pointer[0] = memory_pool_strdup (ud->cfg->cfg_pool, res); - /* Empty list */ - ud->section_pointer = NULL; - ud->state = XML_READ_MODULE; - } - else { - *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'name' is required for tag 'module'"); - ud->state = XML_ERROR; - } - } - else if (g_ascii_strcasecmp (element_name, "modules") == 0) { - ud->state = XML_READ_MODULES; - } - else if (g_ascii_strcasecmp (element_name, "options") == 0) { - ud->state = XML_READ_OPTIONS; - } - else if (g_ascii_strcasecmp (element_name, "logging") == 0) { - ud->state = XML_READ_LOGGING; - } - else if (g_ascii_strcasecmp (element_name, "metric") == 0) { - ud->state = XML_READ_METRIC; - /* Create object */ - ud->section_pointer = check_metric_conf (ud->cfg, NULL); - } - else if (g_ascii_strcasecmp (element_name, "classifier") == 0) { + if (g_ascii_strcasecmp (element_name, "classifier") == 0) { if (extract_attr ("type", attribute_names, attribute_values, &res)) { ud->state = XML_READ_CLASSIFIER; - /* Create object */ - ccf = check_classifier_conf (ud->cfg, NULL); - if ((ccf->classifier = get_classifier (res)) == NULL) { - *error = g_error_new (xml_error_quark (), XML_INVALID_ATTR, "invalid classifier type: %s", res); - ud->state = XML_ERROR; - } - else { - ud->section_pointer = ccf; - } } else { *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'type' is required for tag 'classifier'"); ud->state = XML_ERROR; } } - else if (g_ascii_strcasecmp (element_name, "worker") == 0) { - ud->state = XML_READ_WORKER; - /* Create object */ - ud->section_pointer = check_worker_conf (ud->cfg, NULL); - } - else if (g_ascii_strcasecmp (element_name, "lua") == 0) { - rspamd_strlcpy (ud->section_name, element_name, sizeof (ud->section_name)); - ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values); - if (! handle_lua (ud->cfg, ud, ud->cur_attrs, NULL, NULL, ud->cfg, 0)) { - *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag '%s'", ud->section_name); - ud->state = XML_ERROR; + else { + /* Legacy XML support */ + if (g_ascii_strcasecmp (element_name, "param") == 0) { + if (extract_attr ("value", attribute_names, attribute_values, &res)) { + element_name = res; + } + else { + *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'value' is required for tag 'param'"); + ud->state = XML_ERROR; + } } - else { - ud->state = XML_READ_VALUE; + + if (ud->nested == 0) { + /* Top object */ + obj = ucl_object_new (); + obj->type = UCL_OBJECT; + ud->parent_pointer[0] = obj; + ucl_object_insert_key (ud->cfg->rcl_obj, obj, element_name, 0, true); + process_attrs (attribute_names, attribute_values, obj); } - } - else if (g_ascii_strcasecmp (element_name, "view") == 0) { - ud->state = XML_READ_VIEW; - /* Create object */ - ud->section_pointer = init_view (ud->cfg, ud->cfg->cfg_pool); - } -#if GLIB_MINOR_VERSION >= 18 - else if (subparsers != NULL && (subparser = g_hash_table_lookup (subparsers, element_name)) != NULL) { - ud->state = XML_SUBPARSER; - g_markup_parse_context_push (context, subparser->parser, subparser->user_data); - rspamd_strlcpy (ud->section_name, element_name, sizeof (ud->section_name)); - } -#endif - else { - /* Extract other tags */ - rspamd_strlcpy (ud->section_name, element_name, sizeof (ud->section_name)); - ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values); - ud->state = XML_READ_VALUE; + rspamd_strlcpy (ud->section_name[ud->nested], element_name, MAX_NAME); + ud->nested ++; } break; case XML_READ_CLASSIFIER: @@ -1924,43 +1234,10 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam ud->section_pointer = check_statfile_conf (ud->cfg, NULL); } else { - rspamd_strlcpy (ud->section_name, element_name, sizeof (ud->section_name)); - /* Save attributes */ - ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values); - } - break; - case XML_SKIP_ELEMENTS: - /* Do nothing */ - return; - case XML_READ_MODULE: - if (g_ascii_strcasecmp (element_name, "meta") == 0) { - ud->parent_pointer[1] = ud->section_pointer; - ud->state = XML_READ_MODULE_META; - ud->section_pointer = memory_pool_alloc0 (ud->cfg->cfg_pool, sizeof (struct module_meta_opt)); - } - else { - rspamd_strlcpy (ud->section_name, element_name, sizeof (ud->section_name)); + rspamd_strlcpy (ud->section_name[ud->nested], element_name, MAX_NAME); /* Save attributes */ - ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values); } break; - case XML_READ_MODULE_META: - case XML_READ_METRIC: - case XML_READ_MODULES: - case XML_READ_STATFILE: - case XML_READ_WORKER: - case XML_READ_LOGGING: - case XML_READ_VIEW: - case XML_READ_OPTIONS: - rspamd_strlcpy (ud->section_name, element_name, sizeof (ud->section_name)); - /* Save attributes */ - ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values); - break; - case XML_SUBPARSER: - /* Recursive call of this function but with other state */ - ud->state = XML_READ_PARAM; - rspamd_xml_start_element (context, element_name, attribute_names, attribute_values, user_data, error); - break; default: if (*error == NULL) { *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "element %s is unexpected in this state %s", @@ -1970,185 +1247,20 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam } } -#define CHECK_TAG(x, required) \ -do { \ -if (g_ascii_strcasecmp (element_name, (x)) == 0) { \ - ud->state = XML_READ_PARAM; \ - res = TRUE; \ -} \ -else { \ - res = FALSE; \ - if ((required) == TRUE) { \ - if (*error == NULL) *error = g_error_new (xml_error_quark (), XML_UNMATCHED_TAG, "element %s is unexpected in this state, expected %s", element_name, (x)); \ - ud->state = XML_ERROR; \ - } \ -} \ -} while (0) 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; - gpointer tptr; - struct wrk_cbdata wcd; - struct xml_subparser *subparser; - GList *labels; - - if (g_ascii_strcasecmp (element_name, "if") == 0) { - tptr = g_queue_pop_head (ud->if_stack); - if (tptr == NULL) { - *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "element %s is umatched", element_name); - ud->state = XML_ERROR; - } - /* Restore state */ - if (ud->state == XML_SKIP_ELEMENTS) { - ud->state = GPOINTER_TO_SIZE (tptr); - } - /* Skip processing */ + struct rspamd_xml_userdata *ud = user_data; - return; + if (g_ascii_strcasecmp (ud->section_name[ud->nested], element_name) == 0) { + ud->nested --; } - - switch (ud->state) { - case XML_READ_MODULE_META: - CHECK_TAG ("meta", FALSE); - if (res) { - ud->section_pointer = ud->parent_pointer[1]; - ud->parent_pointer[1] = NULL; - ud->state = XML_READ_MODULE; - } - break; - case XML_READ_MODULE: - CHECK_TAG ("module", FALSE); - if (res) { - if (ud->section_pointer != NULL) { - /* Reverse options list */ - ud->parent_pointer[0] = NULL; - ud->section_pointer = NULL; - } - } - break; - case XML_READ_CLASSIFIER: - CHECK_TAG ("classifier", FALSE); - if (res) { - ccf = ud->section_pointer; - if (ccf->statfiles == NULL || !check_classifier_statfiles (ccf)) { - *error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "classifier cannot contains no statfiles or statfiles of the same class"); - ud->state = XML_ERROR; - return; - } - ud->cfg->classifiers = g_list_prepend (ud->cfg->classifiers, ccf); - } - break; - case XML_READ_STATFILE: - CHECK_TAG ("statfile", FALSE); - if (res) { - ccf = ud->parent_pointer[0]; - 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; - return; - } - 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); - if (st->label) { - if ((labels = g_hash_table_lookup (ccf->labels, st->label))) { - labels = g_list_append (labels, st); - } - else { - g_hash_table_insert (ccf->labels, st->label, g_list_prepend (NULL, st)); - } - } - ud->section_pointer = ccf; - ud->parent_pointer[0] = NULL; - ud->state = XML_READ_CLASSIFIER; - } - break; - case XML_READ_MODULES: - CHECK_TAG ("modules", FALSE); - break; - case XML_READ_OPTIONS: - CHECK_TAG ("options", FALSE); - break; - case XML_READ_METRIC: - CHECK_TAG ("metric", FALSE); - if (res) { - 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; - return; - } - g_hash_table_insert (ud->cfg->metrics, m->name, m); - ud->cfg->metrics_list = g_list_prepend (ud->cfg->metrics_list, m); - } - break; - case XML_READ_WORKER: - CHECK_TAG ("worker", FALSE); - if (res) { - /* Parse params */ - wcd.wrk = ud->section_pointer; - wcd.cfg = ud->cfg; - wcd.ctx = ud; - g_hash_table_foreach (wcd.wrk->params, - worker_foreach_callback, &wcd); - /* Insert object to list */ - ud->cfg->workers = g_list_prepend (ud->cfg->workers, ud->section_pointer); - } - break; - 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 */ - CHECK_TAG (ud->section_name, TRUE); - break; - case XML_READ_LOGGING: - CHECK_TAG ("logging", FALSE); - break; - case XML_READ_PARAM: - if (g_ascii_strcasecmp (element_name, "rspamd") == 0) { - /* End of document */ - ud->state = XML_END; - } - else { - *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "element %s is umatched", element_name); - ud->state = XML_ERROR; - } - break; - case XML_SKIP_ELEMENTS: - return; -#if GLIB_MINOR_VERSION >= 18 - case XML_SUBPARSER: - CHECK_TAG (ud->section_name, TRUE); - if (subparsers != NULL && (subparser = g_hash_table_lookup (subparsers, element_name)) != NULL) { - if (subparser->fin_func) { - subparser->fin_func (g_markup_parse_context_pop (context)); - } - else { - g_markup_parse_context_pop (context); - } - } - ud->state = XML_READ_PARAM; - break; -#endif - default: - ud->state = XML_ERROR; - break; + else { + *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "element %s is umatched", element_name); + ud->state = XML_ERROR; } - } #undef CHECK_TAG @@ -2156,95 +1268,11 @@ void rspamd_xml_text (GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error) { struct rspamd_xml_userdata *ud = user_data; - gchar *val; - struct config_file *cfg = ud->cfg; + ucl_object_t *top; - /* Strip space symbols */ - while (*text && g_ascii_isspace (*text)) { - text ++; - } - if (*text == '\0') { - /* Skip empty text */ - return; - } - - val = xml_asciiz_string (cfg->cfg_pool, text, text_len); - - switch (ud->state) { - case XML_READ_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' data: %s", ud->section_name, val); - ud->state = XML_ERROR; - } - break; - case XML_READ_MODULE_META: - if (!call_param_handler (ud, ud->section_name, val, ud->section_pointer, XML_SECTION_MODULE_META)) { - *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag '%s' data: %s", ud->section_name, val); - ud->state = XML_ERROR; - } - break; - case XML_READ_MODULES: - if (!call_param_handler (ud, ud->section_name, val, cfg, XML_SECTION_MODULES)) { - *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag '%s' data: %s", ud->section_name, val); - ud->state = XML_ERROR; - } - break; - case XML_READ_OPTIONS: - if (!call_param_handler (ud, ud->section_name, val, cfg, XML_SECTION_OPTIONS)) { - *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag '%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->section_pointer, XML_SECTION_CLASSIFIER)) { - *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag '%s' data: %s", ud->section_name, val); - ud->state = XML_ERROR; - } - break; - case XML_READ_STATFILE: - if (!call_param_handler (ud, ud->section_name, val, ud->section_pointer, XML_SECTION_STATFILE)) { - *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag '%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->section_pointer, XML_SECTION_METRIC)) { - *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag '%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->section_pointer, XML_SECTION_WORKER)) { - *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag '%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' data: %s", ud->section_name, val); - ud->state = XML_ERROR; - } - break; - 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' data: %s", ud->section_name, val); - ud->state = XML_ERROR; - } - break; - case XML_READ_LOGGING: - if (!call_param_handler (ud, ud->section_name, val, cfg, XML_SECTION_LOGGING)) { - *error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag '%s' data: %s", ud->section_name, val); - ud->state = XML_ERROR; - } - break; - case XML_SKIP_ELEMENTS: - /* Do nothing */ - return; - default: - ud->state = XML_ERROR; - break; - } - + top = ud->parent_pointer[ud->nested - 1]; + ucl_object_insert_key (top, ucl_object_fromstring_common (text, text_len, UCL_STRING_PARSE), + ud->section_name[ud->nested], 0, true); } void @@ -2255,179 +1283,11 @@ rspamd_xml_error (GMarkupParseContext *context, GError *error, gpointer user_dat msg_err ("xml parser error: %s, at state \"%s\"", error->message, xml_state_to_string (ud)); } -/* Register handlers for specific parts of config */ - -/* Checker for module options */ -struct option_callback_data { - const gchar *optname; - gboolean res; - struct xml_config_param *param; -}; - -static void -module_option_callback (gpointer key, gpointer value, gpointer ud) -{ - const gchar *optname = key; - static gchar rebuf[512]; - struct option_callback_data *cd = ud; - GRegex *re; - GError *err = NULL; - gsize relen; - - if (*optname == '/') { - relen = strcspn (optname + 1, "/"); - if (relen > sizeof (rebuf)) { - relen = sizeof (rebuf); - } - rspamd_strlcpy (rebuf, optname + 1, relen); - /* This is a regexp so compile and check it */ - re = g_regex_new (rebuf, G_REGEX_CASELESS, 0, &err); - if (err != NULL) { - msg_err ("failed to compile regexp for option '%s', error was: %s, regexp was: %s", cd->optname, err->message, rebuf); - return; - } - if (g_regex_match (re, cd->optname, 0, NULL)) { - cd->res = TRUE; - cd->param = value; - } - } - - return; -} - -gboolean -check_module_option (const gchar *mname, const gchar *optname, const gchar *data) -{ - struct xml_config_param *param; - enum module_opt_type type; - GHashTable *module; - gchar *err_str; - struct option_callback_data cd; - union { - gint i; - gdouble d; - guint ui; - } t; - - if (module_options == NULL) { - msg_warn ("no module options registered while checking option %s for module %s", mname, optname); - return FALSE; - } - if ((module = g_hash_table_lookup (module_options, mname)) == NULL) { - msg_warn ("module %s has not registered any options while checking for option %s", mname, optname); - return FALSE; - } - - if ((param = g_hash_table_lookup (module, optname)) == NULL) { - /* Try to handle regexp options */ - cd.optname = optname; - cd.res = FALSE; - g_hash_table_foreach (module, module_option_callback, &cd); - if (!cd.res) { - msg_warn ("module %s has not registered option %s", mname, optname); - return FALSE; - } - param = cd.param; - } - - type = param->offset; - - /* Now handle option of each type */ - switch (type) { - case MODULE_OPT_TYPE_STRING: - case MODULE_OPT_TYPE_ANY: - /* Allways OK */ - return TRUE; - case MODULE_OPT_TYPE_INT: - t.i = strtol (data, &err_str, 10); - if (*err_str != '\0') { - msg_warn ("non-numeric data for option: '%s' for module: '%s' at position: '%s'", optname, mname, err_str); - return FALSE; - } - (void)t.i; - break; - case MODULE_OPT_TYPE_UINT: - t.ui = strtoul (data, &err_str, 10); - if (*err_str != '\0') { - msg_warn ("non-numeric data for option: '%s' for module: '%s' at position: '%s'", optname, mname, err_str); - return FALSE; - } - (void)t.ui; - break; - case MODULE_OPT_TYPE_DOUBLE: - t.d = strtod (data, &err_str); - if (*err_str != '\0') { - msg_warn ("non-numeric data for option: '%s' for module: '%s' at position: '%s'", optname, mname, err_str); - return FALSE; - } - (void)t.d; - break; - case MODULE_OPT_TYPE_TIME: - t.ui = cfg_parse_time (data, TIME_SECONDS); - if (errno != 0) { - msg_warn ("non-numeric data for option: '%s' for module: '%s': %s", optname, mname, strerror (errno)); - return FALSE; - } - (void)t.ui; - break; - case MODULE_OPT_TYPE_SIZE: - t.ui = parse_limit (data, -1); - if (errno != 0) { - msg_warn ("non-numeric data for option: '%s' for module: '%s': %s", optname, mname, strerror (errno)); - return FALSE; - } - (void)t.ui; - break; - case MODULE_OPT_TYPE_MAP: - if (!check_map_proto (data, NULL, NULL)) { - return FALSE; - } - break; - case MODULE_OPT_TYPE_FLAG: - if (parse_flag (data) == -1) { - return FALSE; - } - break; - case MODULE_OPT_TYPE_META: - msg_warn ("option %s should be meta option for module %s not an ordinary one", optname, mname); - return FALSE; - } - - return TRUE; -} - /* Register new module option */ void register_module_opt (const gchar *mname, const gchar *optname, enum module_opt_type type) { - struct xml_config_param *param; - GHashTable *module; - - if (module_options == NULL) { - module_options = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); - } - if ((module = g_hash_table_lookup (module_options, mname)) == NULL) { - module = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); - g_hash_table_insert (module_options, (char *)mname, module); - } - if ((param = g_hash_table_lookup (module, optname)) == NULL) { - /* Register new param */ - param = g_malloc (sizeof (struct xml_config_param)); - param->handler = NULL; - param->offset = type; - param->name = optname; - g_hash_table_insert (module, (char *)optname, param); - } - else { - /* Param already exists replace it */ - msg_warn ("replace old handler for param '%s'", optname); - g_free (param); - param = g_malloc (sizeof (struct xml_config_param)); - param->handler = NULL; - param->offset = type; - param->name = optname; - g_hash_table_insert (module, (char *)optname, param); - } + msg_err ("this function is depreciated and must not be used"); } /* Register new worker's options */ @@ -2441,447 +1301,11 @@ register_worker_opt (gint wtype, const gchar *optname, element_handler_func func void register_classifier_opt (const gchar *ctype, const gchar *optname) { - struct xml_config_param *param; - GHashTable *classifier; - - if (classifier_options == NULL) { - classifier_options = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); - } - if ((classifier = g_hash_table_lookup (classifier_options, ctype)) == NULL) { - classifier = g_hash_table_new (rspamd_str_hash, rspamd_str_equal); - g_hash_table_insert (classifier_options, (char *)ctype, classifier); - } - if ((param = g_hash_table_lookup (classifier, optname)) == NULL) { - /* Register new param */ - param = g_malloc (sizeof (struct xml_config_param)); - param->handler = NULL; - param->user_data = NULL; - param->offset = 0; - param->name = optname; - g_hash_table_insert (classifier, (char *)optname, param); - } - else { - /* Param already exists replace it */ - msg_warn ("replace old handler for param '%s'", optname); - g_free (param); - param = g_malloc (sizeof (struct xml_config_param)); - param->handler = NULL; - param->user_data = NULL; - param->offset = 0; - param->name = optname; - g_hash_table_insert (classifier, (char *)optname, param); - } + msg_err ("this function is depreciated and must not be used"); } void -register_subparser (const gchar *tag, enum xml_read_state state, const GMarkupParser *parser, void (*fin_func)(gpointer ud), gpointer user_data) -{ - struct xml_subparser *subparser; - - if (subparsers == NULL) { - subparsers = g_hash_table_new_full (rspamd_str_hash, rspamd_str_equal, g_free, g_free); - } - subparser = g_malloc (sizeof (struct xml_subparser)); - - subparser->parser = parser; - subparser->state = state; - subparser->user_data = user_data; - subparser->fin_func = fin_func; - - g_hash_table_replace (subparsers, g_strdup (tag), subparser); -} - - -/* Dumper part */ - -/* Dump specific sections */ - -/* Dump main section variables */ -static gboolean -xml_dump_main (struct config_file *cfg, FILE *f) +register_subparser (const gchar *tag, int state, const GMarkupParser *parser, void (*fin_func)(gpointer ud), gpointer user_data) { - gchar *escaped_str; - - /* Print header comment */ - rspamd_fprintf (f, "" EOL); - - escaped_str = g_markup_escape_text (cfg->temp_dir, -1); - rspamd_fprintf (f, "%s" EOL, escaped_str); - g_free (escaped_str); - - escaped_str = g_markup_escape_text (cfg->pid_file, -1); - rspamd_fprintf (f, "%s" EOL, escaped_str); - g_free (escaped_str); - - escaped_str = g_markup_escape_text (cfg->filters_str, -1); - rspamd_fprintf (f, "%s" EOL, escaped_str); - g_free (escaped_str); - - if (cfg->user_settings_str) { - escaped_str = g_markup_escape_text (cfg->user_settings_str, -1); - rspamd_fprintf (f, "%s" EOL, escaped_str); - g_free (escaped_str); - } - if (cfg->domain_settings_str) { - escaped_str = g_markup_escape_text (cfg->domain_settings_str, -1); - rspamd_fprintf (f, "%s" EOL, escaped_str); - g_free (escaped_str); - } - rspamd_fprintf (f, "%z" EOL, cfg->max_statfile_size); - - if (cfg->checksum) { - escaped_str = g_markup_escape_text (cfg->checksum, -1); - rspamd_fprintf (f, "%s" EOL, escaped_str); - g_free (escaped_str); - } - - rspamd_fprintf (f, "%s" EOL, cfg->raw_mode ? "yes" : "no"); - - /* Print footer comment */ - rspamd_fprintf (f, "" EOL EOL); - - return TRUE; -} - -/* Dump variables section */ -static void -xml_variable_callback (gpointer key, gpointer value, gpointer user_data) -{ - FILE *f = user_data; - gchar *escaped_key, *escaped_value; - - escaped_key = g_markup_escape_text (key, -1); - escaped_value = g_markup_escape_text (value, -1); - rspamd_fprintf (f, "%s" EOL, escaped_key, escaped_value); - g_free (escaped_key); - g_free (escaped_value); -} - -static gboolean -xml_dump_variables (struct config_file *cfg, FILE *f) -{ - /* Print header comment */ - rspamd_fprintf (f, "" EOL); - - /* Iterate through variables */ - g_hash_table_foreach (cfg->variables, xml_variable_callback, (gpointer)f); - - /* Print footer comment */ - rspamd_fprintf (f, "" EOL EOL); - - return TRUE; -} - -/* Composites section */ -static void -xml_composite_callback (gpointer key, gpointer value, gpointer user_data) -{ - FILE *f = user_data; - struct expression *expr; - gchar *escaped_key, *escaped_value; - - expr = value; - - escaped_key = g_markup_escape_text (key, -1); - escaped_value = g_markup_escape_text (expr->orig, -1); - rspamd_fprintf (f, "%s" EOL, escaped_key, escaped_value); - g_free (escaped_key); - g_free (escaped_value); -} - -static gboolean -xml_dump_composites (struct config_file *cfg, FILE *f) -{ - /* Print header comment */ - rspamd_fprintf (f, "" EOL); - - /* Iterate through variables */ - g_hash_table_foreach (cfg->composite_symbols, xml_composite_callback, (gpointer)f); - - /* Print footer comment */ - rspamd_fprintf (f, "" EOL EOL); - - return TRUE; -} - -/* Workers */ -static void -xml_worker_param_callback (gpointer key, gpointer value, gpointer user_data) -{ - FILE *f = user_data; - gchar *escaped_key, *escaped_value; - - escaped_key = g_markup_escape_text (key, -1); - escaped_value = g_markup_escape_text (value, -1); - rspamd_fprintf (f, " %s" EOL, escaped_key, escaped_value); - g_free (escaped_key); - g_free (escaped_value); -} - -static gboolean -xml_dump_workers (struct config_file *cfg, FILE *f) -{ - GList *cur; - struct worker_conf *wrk; - gchar *escaped_str; - - /* Print header comment */ - rspamd_fprintf (f, "" EOL); - - /* Iterate through list */ - cur = g_list_first (cfg->workers); - while (cur) { - wrk = cur->data; - - rspamd_fprintf (f, "" EOL); - - rspamd_fprintf (f, " %s" EOL, g_quark_to_string (wrk->type)); - - rspamd_fprintf (f, " %ud" EOL, wrk->count); - rspamd_fprintf (f, " %ud" EOL, wrk->rlimit_nofile); - rspamd_fprintf (f, " %ud" EOL, wrk->rlimit_maxcore); - - /* Now dump other attrs */ - rspamd_fprintf (f, "" EOL); - g_hash_table_foreach (wrk->params, xml_worker_param_callback, f); - - rspamd_fprintf (f, "" EOL); - - cur = g_list_next (cur); - } - - /* Print footer comment */ - rspamd_fprintf (f, "" EOL EOL); - - return TRUE; -} - - -/* Classifiers dump */ -static void -xml_classifier_callback (gpointer key, gpointer value, gpointer user_data) -{ - FILE *f = user_data; - gchar *escaped_key, *escaped_value; - - escaped_key = g_markup_escape_text (key, -1); - escaped_value = g_markup_escape_text (value, -1); - rspamd_fprintf (f, " " EOL, escaped_key, escaped_value); - g_free (escaped_key); - g_free (escaped_value); -} - -static gboolean -xml_dump_classifiers (struct config_file *cfg, FILE *f) -{ - GList *cur, *cur_st; - struct classifier_config *ccf; - struct statfile *st; - - /* Print header comment */ - rspamd_fprintf (f, "" EOL); - - /* Iterate through classifiers */ - cur = g_list_first (cfg->classifiers); - while (cur) { - ccf = cur->data; - rspamd_fprintf (f, "" EOL, ccf->classifier->name); - rspamd_fprintf (f, " %s" EOL, ccf->tokenizer->name); - rspamd_fprintf (f, " %s" EOL, ccf->metric); - g_hash_table_foreach (ccf->opts, xml_classifier_callback, f); - /* Statfiles */ - cur_st = g_list_first (ccf->statfiles); - while (cur_st) { - st = cur_st->data; - rspamd_fprintf (f, " " EOL); - rspamd_fprintf (f, " %s" EOL " %z" EOL " %s" EOL, - st->symbol, st->size, st->path); - rspamd_fprintf (f, " %s" EOL, st->normalizer_str); - /* Binlog */ - if (st->binlog) { - if (st->binlog->affinity == AFFINITY_MASTER) { - rspamd_fprintf (f, " master" EOL); - } - else if (st->binlog->affinity == AFFINITY_SLAVE) { - rspamd_fprintf (f, " slave" EOL); - rspamd_fprintf (f, " %s:%d" EOL, - st->binlog->master_addr, (gint)ntohs (st->binlog->master_port)); - } - rspamd_fprintf (f, " %T" EOL, st->binlog->rotate_time); - } - rspamd_fprintf (f, " " EOL); - cur_st = g_list_next (cur_st); - } - - rspamd_fprintf (f, "" EOL); - cur = g_list_next (cur); - } - - /* Print footer comment */ - rspamd_fprintf (f, "" EOL EOL); - - return TRUE; - -} - -/* Logging section */ -static gboolean -xml_dump_logging (struct config_file *cfg, FILE *f) -{ - gchar *escaped_value; - - /* Print header comment */ - rspamd_fprintf (f, "" EOL); - rspamd_fprintf (f, "" EOL); - - /* Level */ - if (cfg->log_level < G_LOG_LEVEL_WARNING) { - rspamd_fprintf (f, " error" EOL); - } - else if (cfg->log_level < G_LOG_LEVEL_MESSAGE) { - rspamd_fprintf (f, " warning" EOL); - } - else if (cfg->log_level < G_LOG_LEVEL_DEBUG) { - rspamd_fprintf (f, " info" EOL); - } - else { - rspamd_fprintf (f, " debug" EOL); - } - - /* Other options */ - rspamd_fprintf (f, " %s" EOL, cfg->log_urls ? "yes" : "no"); - if (cfg->log_buf_size != 0) { - rspamd_fprintf (f, " %ud" EOL, (guint)cfg->log_buf_size); - } - if (cfg->debug_ip_map != NULL) { - escaped_value = g_markup_escape_text (cfg->debug_ip_map, -1); - rspamd_fprintf (f, " %s" EOL, escaped_value); - g_free (escaped_value); - } - - /* Handle type */ - if (cfg->log_type == RSPAMD_LOG_FILE) { - escaped_value = g_markup_escape_text (cfg->log_file, -1); - rspamd_fprintf (f, " file" EOL, escaped_value); - g_free (escaped_value); - } - else if (cfg->log_type == RSPAMD_LOG_CONSOLE) { - rspamd_fprintf (f, " console" EOL); - } - else if (cfg->log_type == RSPAMD_LOG_SYSLOG) { - escaped_value = NULL; - switch (cfg->log_facility) { - case LOG_AUTH: - escaped_value = "LOG_AUTH"; - break; - case LOG_CRON: - escaped_value = "LOG_CRON"; - break; - case LOG_DAEMON: - escaped_value = "LOG_DAEMON"; - break; - case LOG_MAIL: - escaped_value = "LOG_MAIL"; - break; - case LOG_USER: - escaped_value = "LOG_USER"; - break; - case LOG_LOCAL0: - escaped_value = "LOG_LOCAL0"; - break; - case LOG_LOCAL1: - escaped_value = "LOG_LOCAL1"; - break; - case LOG_LOCAL2: - escaped_value = "LOG_LOCAL2"; - break; - case LOG_LOCAL3: - escaped_value = "LOG_LOCAL3"; - break; - case LOG_LOCAL4: - escaped_value = "LOG_LOCAL4"; - break; - case LOG_LOCAL5: - escaped_value = "LOG_LOCAL5"; - break; - case LOG_LOCAL6: - escaped_value = "LOG_LOCAL6"; - break; - case LOG_LOCAL7: - escaped_value = "LOG_LOCAL7"; - break; - } - rspamd_fprintf (f, " syslog" EOL, escaped_value); - } - rspamd_fprintf (f, "" EOL); - /* Print footer comment */ - rspamd_fprintf (f, "" EOL EOL); - - return TRUE; -} - -/* Modules */ -static gboolean -xml_dump_modules_paths (struct config_file *cfg, FILE *f) -{ - GList *cur; - gchar *escaped_value; - struct script_module *module; - - /* Print header comment */ - rspamd_fprintf (f, "" EOL); - rspamd_fprintf (f, "" EOL); - - cur = cfg->script_modules; - while (cur) { - module = cur->data; - escaped_value = g_markup_escape_text (module->path, -1); - rspamd_fprintf (f, " %s" EOL, escaped_value); - g_free (escaped_value); - cur = g_list_next (cur); - } - - rspamd_fprintf (f, "" EOL); - /* Print footer comment */ - rspamd_fprintf (f, "" EOL EOL); - - return TRUE; -} - - -#define CHECK_RES do { if (!res) { fclose (f); return FALSE; } } while (0) -gboolean -xml_dump_config (struct config_file *cfg, const gchar *filename) -{ - FILE *f; - gboolean res = FALSE; - - f = fopen (filename, "w"); - if (f == NULL) { - msg_err ("cannot open file '%s': %s", filename, strerror (errno)); - return FALSE; - } - - /* Header */ - rspamd_fprintf (f, "" EOL "" EOL); - /* Now dump all parts of config */ - res = xml_dump_main (cfg, f); - CHECK_RES; - res = xml_dump_logging (cfg, f); - CHECK_RES; - res = xml_dump_variables (cfg, f); - CHECK_RES; - res = xml_dump_composites (cfg, f); - CHECK_RES; - res = xml_dump_workers (cfg, f); - CHECK_RES; - res = xml_dump_classifiers (cfg, f); - CHECK_RES; - res = xml_dump_modules_paths (cfg, f); - CHECK_RES; - /* Footer */ - rspamd_fprintf (f, "" EOL); - fclose (f); - - return TRUE; + msg_err ("this function is depreciated and must not be used"); } diff --git a/src/cfg_xml.h b/src/cfg_xml.h index c2930c365..9799b4926 100644 --- a/src/cfg_xml.h +++ b/src/cfg_xml.h @@ -4,7 +4,7 @@ #include "config.h" #include "cfg_file.h" -#define MAX_NAME 8192 +#define MAX_NAME 128 #define XML_START_MISSING 1 #define XML_PARAM_MISSING 2 @@ -14,26 +14,6 @@ #define MAX_INHERIT 5 -enum xml_read_state { - XML_READ_START, - XML_READ_PARAM, - XML_READ_MODULE, - XML_READ_MODULE_META, - XML_READ_MODULES, - XML_READ_CLASSIFIER, - XML_READ_STATFILE, - XML_READ_METRIC, - XML_READ_WORKER, - XML_READ_VIEW, - XML_READ_LOGGING, - XML_READ_OPTIONS, - XML_READ_VALUE, - XML_SKIP_ELEMENTS, - XML_ERROR, - XML_SUBPARSER, - XML_END -}; - enum module_opt_type { MODULE_OPT_TYPE_STRING = 0, MODULE_OPT_TYPE_INT, @@ -51,13 +31,13 @@ enum module_opt_type { * Structure that is used for semantic resolution of configuration */ struct rspamd_xml_userdata { - enum xml_read_state state; /*< state of parser */ + int state; /*< state of parser */ struct config_file *cfg; /*< configuration object */ - gchar section_name[MAX_NAME]; /*< current section */ + gchar section_name[MAX_INHERIT][MAX_NAME]; /*< current section */ gpointer section_pointer; /*< pointer to object related with section */ gpointer parent_pointer[MAX_INHERIT]; /*< parent's section object */ GHashTable *cur_attrs; /*< attributes of current tag */ - GQueue *if_stack; /*< stack of if elements */ + gint nested; }; /* Text is NULL terminated here */ @@ -181,7 +161,7 @@ void register_worker_opt (gint wtype, const gchar *optname, element_handler_func void register_classifier_opt (const gchar *ctype, const gchar *optname); /* Register new xml subparser */ -void register_subparser (const gchar *tag, enum xml_read_state state, +void register_subparser (const gchar *tag, int state, const GMarkupParser *parser, void (*fin_func)(gpointer ud), gpointer user_data); /* Check validity of module option */ diff --git a/src/kvstorage_config.c b/src/kvstorage_config.c index 406cf7c73..dbe58cb11 100644 --- a/src/kvstorage_config.c +++ b/src/kvstorage_config.c @@ -516,7 +516,7 @@ init_kvstorage_config (void) kv_parser->state = KVSTORAGE_STATE_PARAM; kv_parser->pool = memory_pool_new (memory_pool_get_size ()); - register_subparser ("keystorage", XML_READ_START, parser, kvstorage_cleanup, kv_parser); + register_subparser ("keystorage", 0, parser, kvstorage_cleanup, kv_parser); } /* Get configuration for kvstorage with specified ID */