diff options
Diffstat (limited to 'src/cfg_xml.c')
-rw-r--r-- | src/cfg_xml.c | 252 |
1 files changed, 208 insertions, 44 deletions
diff --git a/src/cfg_xml.c b/src/cfg_xml.c index 67523c845..ddf995481 100644 --- a/src/cfg_xml.c +++ b/src/cfg_xml.c @@ -51,6 +51,13 @@ NULL \ } \ +#define NULL_DEF_ATTR \ +{ \ + NULL, \ + 0, \ + NULL \ +} \ + enum xml_config_section { XML_SECTION_MAIN, XML_SECTION_LOGGING, @@ -64,16 +71,22 @@ enum xml_config_section { }; struct xml_config_param { - const gchar *name; - element_handler_func handler; - gint offset; - gpointer user_data; + const gchar *name; + element_handler_func handler; + gint offset; + gpointer user_data; +}; + +struct xml_default_config_param { + element_default_handler_func handler; + gint offset; + gpointer user_data; }; struct xml_parser_rule { enum xml_config_section section; struct xml_config_param params[MAX_PARAM]; - struct xml_config_param default_param; + struct xml_default_config_param default_param; }; /* Here we describes our basic grammar */ @@ -165,7 +178,7 @@ static struct xml_parser_rule grammar[] = { }, NULL_ATTR }, - NULL_ATTR + NULL_DEF_ATTR }, { XML_SECTION_LOGGING, { { @@ -206,7 +219,7 @@ static struct xml_parser_rule grammar[] = { }, NULL_ATTR }, - NULL_ATTR + NULL_DEF_ATTR }, { XML_SECTION_WORKER, { { @@ -242,7 +255,6 @@ static struct xml_parser_rule grammar[] = { NULL_ATTR }, { - NULL, worker_handle_param, 0, NULL @@ -287,7 +299,7 @@ static struct xml_parser_rule grammar[] = { }, NULL_ATTR }, - NULL_ATTR + NULL_DEF_ATTR }, { XML_SECTION_CLASSIFIER, { { @@ -302,15 +314,13 @@ static struct xml_parser_rule grammar[] = { 0, NULL }, - { - "option", - handle_classifier_opt, - 0, - NULL - }, NULL_ATTR }, - NULL_ATTR + { + handle_classifier_opt, + 0, + NULL + } }, { XML_SECTION_STATFILE, { { @@ -357,13 +367,12 @@ static struct xml_parser_rule grammar[] = { }, NULL_ATTR }, - NULL_ATTR + NULL_DEF_ATTR }, { XML_SECTION_MODULE, { NULL_ATTR }, { - NULL, handle_module_opt, 0, NULL @@ -378,7 +387,7 @@ static struct xml_parser_rule grammar[] = { }, NULL_ATTR }, - NULL_ATTR + NULL_DEF_ATTR }, { XML_SECTION_VIEW, { { @@ -419,10 +428,14 @@ static struct xml_parser_rule grammar[] = { }, NULL_ATTR }, - NULL_ATTR + NULL_DEF_ATTR }, }; +static GHashTable *module_options = NULL, + *worker_options = NULL, + *classifier_options = NULL; + GQuark xml_error_quark (void) { @@ -510,9 +523,8 @@ call_param_handler (struct rspamd_xml_userdata *ctx, const gchar *name, gchar *v param ++; } if (rule->default_param.handler != NULL) { - param = &rule->default_param; /* Call default handler */ - return param->handler (ctx->cfg, ctx, ctx->cur_attrs, value, param->user_data, dest_struct, param->offset); + return rule->default_param.handler (ctx->cfg, ctx, name, ctx->cur_attrs, value, param->user_data, dest_struct, param->offset); } } } @@ -625,17 +637,32 @@ handle_log_level (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHas /* 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, gint offset) +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; - gchar *name; + const gchar *name; + struct xml_config_param *cparam; + GHashTable *worker_config; - if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { - msg_err ("worker param tag must have \"name\" attribute"); - return FALSE; + if (g_ascii_strcasecmp (tag, "option") == 0 || g_ascii_strcasecmp (tag, "param") == 0) { + if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { + msg_err ("worker param tag must have \"name\" attribute"); + return FALSE; + } + } + else { + name = tag; } - g_hash_table_insert (wrk->params, name, memory_pool_strdup (cfg->cfg_pool, data)); + if (!worker_options || + (worker_config = g_hash_table_lookup (worker_options, &wrk->type)) == NULL || + (cparam = g_hash_table_lookup (worker_config, name)) == NULL) { + msg_warn ("unregistered worker attribute '%s' for worker %s", name, process_to_str (wrk->type)); + g_hash_table_insert (wrk->params, (char *)name, memory_pool_strdup (cfg->cfg_pool, data)); + } + else { + return cparam->handler (cfg, ctx, attrs, data, NULL, cparam->user_data, cparam->offset); + } return TRUE; } @@ -765,27 +792,36 @@ handle_metric_symbol (struct config_file *cfg, struct rspamd_xml_userdata *ctx, /* 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, gint offset) +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) { - gchar *name, *val; + gchar *val; struct module_opt *cur; gboolean is_lua = FALSE; - - if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { - msg_err ("param tag must have \"name\" attribute"); - return FALSE; + const gchar *name; + + if (g_ascii_strcasecmp (tag, "option") == 0 || g_ascii_strcasecmp (tag, "param") == 0) { + if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { + msg_err ("worker param tag must have \"name\" attribute"); + return FALSE; + } } - + else { + name = tag; + } + /* Check for lua */ if ((val = g_hash_table_lookup (attrs, "lua")) != NULL) { if (g_ascii_strcasecmp (val, "yes") == 0) { is_lua = TRUE; } } + /* XXX: in fact we cannot check for lua modules and need to do it in post-config procedure + * so just insert any options provided and try to handle them in further process + */ /* Insert option */ cur = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct module_opt)); - cur->param = name; + cur->param = (char *)name; cur->value = data; cur->is_lua = is_lua; ctx->section_pointer = g_list_prepend (ctx->section_pointer, cur); @@ -1048,17 +1084,33 @@ handle_classifier_tokenizer (struct config_file *cfg, struct rspamd_xml_userdata } gboolean -handle_classifier_opt (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset) +handle_classifier_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) { - 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; + struct classifier_config *ccf = ctx->section_pointer; + const gchar *name; + struct xml_config_param *cparam; + GHashTable *classifier_config; + + if (g_ascii_strcasecmp (tag, "option") == 0 || g_ascii_strcasecmp (tag, "param") == 0) { + if ((name = g_hash_table_lookup (attrs, "name")) == NULL) { + msg_err ("worker param tag must have \"name\" attribute"); + return FALSE; + } + } + else { + name = 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); + g_hash_table_insert (ccf->opts, (char *)name, memory_pool_strdup (cfg->cfg_pool, data)); + } + else { + return cparam->handler (cfg, ctx, attrs, data, NULL, cparam->user_data, cparam->offset); } - g_hash_table_insert (ccf->opts, val, memory_pool_strdup (cfg->cfg_pool, data)); return TRUE; } @@ -1633,6 +1685,118 @@ 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 */ +/* Register new module option */ +void +register_module_opt (const gchar *mname, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset) +{ + struct xml_config_param *param; + GHashTable *module; + + if (module_options == NULL) { + module_options = g_hash_table_new (g_str_hash, g_str_equal); + } + if ((module = g_hash_table_lookup (module_options, mname)) == NULL) { + module = g_hash_table_new (g_str_hash, g_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 = func; + param->user_data = dest_struct; + param->offset = offset; + 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 = func; + param->user_data = dest_struct; + param->offset = offset; + param->name = optname; + g_hash_table_insert (module, (char *)optname, param); + } +} + +/* Register new worker's options */ +void +register_worker_opt (gint wtype, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset) +{ + struct xml_config_param *param; + GHashTable *worker; + gint *new_key; + + if (worker_options == NULL) { + worker_options = g_hash_table_new (g_int_hash, g_int_equal); + } + if ((worker = g_hash_table_lookup (worker_options, &wtype)) == NULL) { + worker = g_hash_table_new (g_str_hash, g_str_equal); + new_key = g_malloc (sizeof (gint)); + *new_key = wtype; + g_hash_table_insert (worker_options, new_key, worker); + } + if ((param = g_hash_table_lookup (worker, optname)) == NULL) { + /* Register new param */ + param = g_malloc (sizeof (struct xml_config_param)); + param->handler = func; + param->user_data = dest_struct; + param->offset = offset; + param->name = optname; + g_hash_table_insert (worker, (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 = func; + param->user_data = dest_struct; + param->offset = offset; + param->name = optname; + g_hash_table_insert (worker, (char *)optname, param); + } +} + +/* Register new classifier option */ +void +register_classifier_opt (const gchar *ctype, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset) +{ + struct xml_config_param *param; + GHashTable *classifier; + + if (classifier_options == NULL) { + classifier_options = g_hash_table_new (g_str_hash, g_str_equal); + } + if ((classifier = g_hash_table_lookup (classifier_options, ctype)) == NULL) { + classifier = g_hash_table_new (g_str_hash, g_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 = func; + param->user_data = dest_struct; + param->offset = offset; + 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 = func; + param->user_data = dest_struct; + param->offset = offset; + param->name = optname; + g_hash_table_insert (classifier, (char *)optname, param); + } +} + /* Dumper part */ |