#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, \
*worker_options = NULL,
*classifier_options = NULL,
*subparsers = NULL;
+#endif
GQuark
xml_error_quark (void)
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)
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;
}
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) {
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:
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",
}
}
-#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
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
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 */
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, "<!-- Main section -->" EOL);
-
- escaped_str = g_markup_escape_text (cfg->temp_dir, -1);
- rspamd_fprintf (f, "<tempdir>%s</tempdir>" EOL, escaped_str);
- g_free (escaped_str);
-
- escaped_str = g_markup_escape_text (cfg->pid_file, -1);
- rspamd_fprintf (f, "<pidfile>%s</pidfile>" EOL, escaped_str);
- g_free (escaped_str);
-
- escaped_str = g_markup_escape_text (cfg->filters_str, -1);
- rspamd_fprintf (f, "<filters>%s</filters>" 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, "<user_settings>%s</user_settings>" 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, "<domain_settings>%s</domain_settings>" EOL, escaped_str);
- g_free (escaped_str);
- }
- rspamd_fprintf (f, "<statfile_pool_size>%z</statfile_pool_size>" EOL, cfg->max_statfile_size);
-
- if (cfg->checksum) {
- escaped_str = g_markup_escape_text (cfg->checksum, -1);
- rspamd_fprintf (f, "<checksum>%s</checksum>" EOL, escaped_str);
- g_free (escaped_str);
- }
-
- rspamd_fprintf (f, "<raw_mode>%s</raw_mode>" EOL, cfg->raw_mode ? "yes" : "no");
-
- /* Print footer comment */
- rspamd_fprintf (f, "<!-- End of main section -->" 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, "<variable name=\"%s\">%s</variable>" 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, "<!-- Variables section -->" EOL);
-
- /* Iterate through variables */
- g_hash_table_foreach (cfg->variables, xml_variable_callback, (gpointer)f);
-
- /* Print footer comment */
- rspamd_fprintf (f, "<!-- End of variables section -->" 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, "<composite name=\"%s\">%s</composite>" 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, "<!-- Composites section -->" EOL);
-
- /* Iterate through variables */
- g_hash_table_foreach (cfg->composite_symbols, xml_composite_callback, (gpointer)f);
-
- /* Print footer comment */
- rspamd_fprintf (f, "<!-- End of composites section -->" 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, " <param name=\"%s\">%s</param>" 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, "<!-- Workers section -->" EOL);
-
- /* Iterate through list */
- cur = g_list_first (cfg->workers);
- while (cur) {
- wrk = cur->data;
-
- rspamd_fprintf (f, "<worker>" EOL);
-
- rspamd_fprintf (f, " <type>%s</type>" EOL, g_quark_to_string (wrk->type));
-
- rspamd_fprintf (f, " <count>%ud</count>" EOL, wrk->count);
- rspamd_fprintf (f, " <maxfiles>%ud</maxfiles>" EOL, wrk->rlimit_nofile);
- rspamd_fprintf (f, " <maxcore>%ud</maxcore>" EOL, wrk->rlimit_maxcore);
-
- /* Now dump other attrs */
- rspamd_fprintf (f, "<!-- Other params -->" EOL);
- g_hash_table_foreach (wrk->params, xml_worker_param_callback, f);
-
- rspamd_fprintf (f, "</worker>" EOL);
-
- cur = g_list_next (cur);
- }
-
- /* Print footer comment */
- rspamd_fprintf (f, "<!-- End of workers section -->" 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, " <option name=\"%s\">%s</option>" 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, "<!-- Classifiers section -->" EOL);
-
- /* Iterate through classifiers */
- cur = g_list_first (cfg->classifiers);
- while (cur) {
- ccf = cur->data;
- rspamd_fprintf (f, "<classifier type=\"%s\">" EOL, ccf->classifier->name);
- rspamd_fprintf (f, " <tokenizer>%s</tokenizer>" EOL, ccf->tokenizer->name);
- rspamd_fprintf (f, " <metric>%s</metric>" 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, " <statfile>" EOL);
- rspamd_fprintf (f, " <symbol>%s</symbol>" EOL " <size>%z</size>" EOL " <path>%s</path>" EOL,
- st->symbol, st->size, st->path);
- rspamd_fprintf (f, " <normalizer>%s</normalizer>" EOL, st->normalizer_str);
- /* Binlog */
- if (st->binlog) {
- if (st->binlog->affinity == AFFINITY_MASTER) {
- rspamd_fprintf (f, " <binlog>master</binlog>" EOL);
- }
- else if (st->binlog->affinity == AFFINITY_SLAVE) {
- rspamd_fprintf (f, " <binlog>slave</binlog>" EOL);
- rspamd_fprintf (f, " <binlog_master>%s:%d</binlog_master>" EOL,
- st->binlog->master_addr, (gint)ntohs (st->binlog->master_port));
- }
- rspamd_fprintf (f, " <binlog_rotate>%T</binlog_rotate>" EOL, st->binlog->rotate_time);
- }
- rspamd_fprintf (f, " </statfile>" EOL);
- cur_st = g_list_next (cur_st);
- }
-
- rspamd_fprintf (f, "</classifier>" EOL);
- cur = g_list_next (cur);
- }
-
- /* Print footer comment */
- rspamd_fprintf (f, "<!-- End of classifiers section -->" 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, "<!-- Logging section -->" EOL);
- rspamd_fprintf (f, "<logging>" EOL);
-
- /* Level */
- if (cfg->log_level < G_LOG_LEVEL_WARNING) {
- rspamd_fprintf (f, " <level>error</level>" EOL);
- }
- else if (cfg->log_level < G_LOG_LEVEL_MESSAGE) {
- rspamd_fprintf (f, " <level>warning</level>" EOL);
- }
- else if (cfg->log_level < G_LOG_LEVEL_DEBUG) {
- rspamd_fprintf (f, " <level>info</level>" EOL);
- }
- else {
- rspamd_fprintf (f, " <level>debug</level>" EOL);
- }
-
- /* Other options */
- rspamd_fprintf (f, " <log_urls>%s</log_urls>" EOL, cfg->log_urls ? "yes" : "no");
- if (cfg->log_buf_size != 0) {
- rspamd_fprintf (f, " <log_buffer>%ud</log_buffer>" 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, " <debug_ip>%s</debug_ip>" 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, " <type filename=\"%s\">file</type>" EOL, escaped_value);
- g_free (escaped_value);
- }
- else if (cfg->log_type == RSPAMD_LOG_CONSOLE) {
- rspamd_fprintf (f, " <type>console</type>" 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, " <type facility=\"%s\">syslog</type>" EOL, escaped_value);
- }
- rspamd_fprintf (f, "</logging>" EOL);
- /* Print footer comment */
- rspamd_fprintf (f, "<!-- End of logging section -->" 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, "<!-- Modules section -->" EOL);
- rspamd_fprintf (f, "<modules>" EOL);
-
- cur = cfg->script_modules;
- while (cur) {
- module = cur->data;
- escaped_value = g_markup_escape_text (module->path, -1);
- rspamd_fprintf (f, " <path>%s</path>" EOL, escaped_value);
- g_free (escaped_value);
- cur = g_list_next (cur);
- }
-
- rspamd_fprintf (f, "</modules>" EOL);
- /* Print footer comment */
- rspamd_fprintf (f, "<!-- End of modules section -->" 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, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" EOL "<rspamd>" 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, "</rspamd>" EOL);
- fclose (f);
-
- return TRUE;
+ msg_err ("this function is depreciated and must not be used");
}