* Rework of config structure types (use glib types) * TODO: - implement the whole syntax of rspamd in XML - implement custom handlers that modules can install - write missing handlerstags/0.3.0
@@ -77,10 +77,10 @@ enum rspamd_log_type { | |||
*/ | |||
struct rspamd_regexp { | |||
enum rspamd_regexp_type type; /**< regexp type */ | |||
char *regexp_text; /**< regexp text representation */ | |||
gchar *regexp_text; /**< regexp text representation */ | |||
GRegex *regexp; /**< glib regexp structure */ | |||
GRegex *raw_regexp; /**< glib regexp structure for raw matching */ | |||
char *header; /**< header name for header regexps */ | |||
gchar *header; /**< header name for header regexps */ | |||
}; | |||
/** | |||
@@ -98,16 +98,16 @@ struct memcached_server { | |||
* script module list item | |||
*/ | |||
struct script_module { | |||
char *name; /**< name of module */ | |||
char *path; /**< path to module */ | |||
gchar *name; /**< name of module */ | |||
gchar *path; /**< path to module */ | |||
}; | |||
/** | |||
* Module option | |||
*/ | |||
struct module_opt { | |||
char *param; /**< parameter name */ | |||
char *value; /**< paramater value */ | |||
gchar *param; /**< parameter name */ | |||
gchar *value; /**< paramater value */ | |||
}; | |||
/** | |||
@@ -123,7 +123,7 @@ struct statfile_section { | |||
* Statfile autolearn parameters | |||
*/ | |||
struct statfile_autolearn_params { | |||
const char *metric; /**< metric name for autolearn triggering */ | |||
const gchar *metric; /**< metric name for autolearn triggering */ | |||
double threshold_min; /**< threshold mark */ | |||
double threshold_max; /**< threshold mark */ | |||
GList *symbols; /**< list of symbols */ | |||
@@ -154,9 +154,9 @@ typedef double (*statfile_normalize_func)(double score, void *params); | |||
* Statfile config definition | |||
*/ | |||
struct statfile { | |||
char *symbol; /**< symbol of statfile */ | |||
char *path; /**< filesystem pattern (with %r or %f) */ | |||
size_t size; /**< size of statfile */ | |||
gchar *symbol; /**< symbol of statfile */ | |||
gchar *path; /**< filesystem pattern (with %r or %f) */ | |||
gsize size; /**< size of statfile */ | |||
GList *sections; /**< list of sections in statfile */ | |||
struct statfile_autolearn_params *autolearn; /**< autolearn params */ | |||
struct statfile_binlog_params *binlog; /**< binlog params */ | |||
@@ -169,7 +169,7 @@ struct statfile { | |||
*/ | |||
struct classifier_config { | |||
GList *statfiles; /**< statfiles list */ | |||
char *metric; /**< metric of this classifier */ | |||
gchar *metric; /**< metric of this classifier */ | |||
struct classifier *classifier; /**< classifier interface */ | |||
struct tokenizer *tokenizer; /**< tokenizer used for classifier */ | |||
GHashTable *opts; /**< other options */ | |||
@@ -196,7 +196,7 @@ struct config_scalar { | |||
*/ | |||
struct worker_conf { | |||
int type; /**< worker type */ | |||
char *bind_host; /**< bind line */ | |||
gchar *bind_host; /**< bind line */ | |||
struct in_addr bind_addr; /**< bind address in case of TCP socket */ | |||
uint16_t bind_port; /**< bind port in case of TCP socket */ | |||
uint16_t bind_family; /**< bind type (AF_UNIX or AF_INET) */ | |||
@@ -213,14 +213,14 @@ struct worker_conf { | |||
* Structure that stores all config data | |||
*/ | |||
struct config_file { | |||
char *rspamd_user; /**< user to run as */ | |||
char *rspamd_group; /**< group to run as */ | |||
gchar *rspamd_user; /**< user to run as */ | |||
gchar *rspamd_group; /**< group to run as */ | |||
memory_pool_t *cfg_pool; /**< memory pool for config */ | |||
char *cfg_name; /**< name of config file */ | |||
char *pid_file; /**< name of pid file */ | |||
char *temp_dir; /**< dir for temp files */ | |||
gchar *cfg_name; /**< name of config file */ | |||
gchar *pid_file; /**< name of pid file */ | |||
gchar *temp_dir; /**< dir for temp files */ | |||
#ifdef WITH_GPERF_TOOLS | |||
char *profile_path; | |||
gchar *profile_path; | |||
#endif | |||
gboolean no_fork; /**< if 1 do not call daemon() */ | |||
@@ -230,16 +230,16 @@ struct config_file { | |||
enum rspamd_log_type log_type; /**< log type */ | |||
int log_facility; /**< log facility in case of syslog */ | |||
int log_level; /**< log level trigger */ | |||
char *log_file; /**< path to logfile in case of file logging */ | |||
gchar *log_file; /**< path to logfile in case of file logging */ | |||
gboolean log_buffered; /**< whether logging is buffered */ | |||
uint32_t log_buf_size; /**< length of log buffer */ | |||
char *debug_ip_map; /**< turn on debugging for specified ip addresses */ | |||
gchar *debug_ip_map; /**< turn on debugging for specified ip addresses */ | |||
gboolean log_urls; /**< whether we should log URLs */ | |||
size_t max_statfile_size; /**< maximum size for statfile */ | |||
gsize max_statfile_size; /**< maximum size for statfile */ | |||
struct memcached_server memcached_servers[MAX_MEMCACHED_SERVERS]; /**< memcached servers */ | |||
size_t memcached_servers_num; /**< number of memcached servers */ | |||
gsize memcached_servers_num; /**< number of memcached servers */ | |||
memc_proto_t memcached_protocol; /**< memcached protocol */ | |||
unsigned int memcached_error_time; /**< memcached error time (see upstream documentation) */ | |||
unsigned int memcached_dead_time; /**< memcached dead time */ | |||
@@ -247,18 +247,18 @@ struct config_file { | |||
unsigned int memcached_connect_timeout; /**< connection timeout */ | |||
gboolean delivery_enable; /**< is delivery agent is enabled */ | |||
char *deliver_host; /**< host for mail deliviring */ | |||
gchar *deliver_host; /**< host for mail deliviring */ | |||
struct in_addr deliver_addr; /**< its address */ | |||
uint16_t deliver_port; /**< port for deliviring */ | |||
uint16_t deliver_family; /**< socket family for delivirnig */ | |||
char *deliver_agent_path; /**< deliver to pipe instead of socket */ | |||
gchar *deliver_agent_path; /**< deliver to pipe instead of socket */ | |||
gboolean deliver_lmtp; /**< use LMTP instead of SMTP */ | |||
GList *script_modules; /**< linked list of script modules to load */ | |||
GList *filters; /**< linked list of all filters */ | |||
GList *workers; /**< linked list of all workers params */ | |||
char *filters_str; /**< string of filters */ | |||
gchar *filters_str; /**< string of filters */ | |||
GHashTable* modules_opts; /**< hash for module options indexed by module name */ | |||
GHashTable* variables; /**< hash of $variables defined in config, indexed by variable name */ | |||
GHashTable* metrics; /**< hash of metrics indexed by metric name */ | |||
@@ -284,7 +284,7 @@ struct config_file { | |||
* @param str line that describes server's credits | |||
* @return 1 if line was successfully parsed and 0 in case of error | |||
*/ | |||
int add_memcached_server (struct config_file *cf, char *str); | |||
int add_memcached_server (struct config_file *cf, gchar *str); | |||
/** | |||
* Parse host:port line | |||
@@ -292,7 +292,7 @@ int add_memcached_server (struct config_file *cf, char *str); | |||
* @param port port | |||
* @return TRUE if string was parsed | |||
*/ | |||
gboolean parse_host_port (const char *str, struct in_addr *ina, uint16_t *port); | |||
gboolean parse_host_port (const gchar *str, struct in_addr *ina, uint16_t *port); | |||
/** | |||
* Parse bind credits | |||
@@ -301,7 +301,7 @@ gboolean parse_host_port (const char *str, struct in_addr *ina, uint16_t *port); | |||
* @param type type of credits | |||
* @return 1 if line was successfully parsed and 0 in case of error | |||
*/ | |||
int parse_bind_line (struct config_file *cfg, struct worker_conf *cf, char *str); | |||
int parse_bind_line (struct config_file *cfg, struct worker_conf *cf, gchar *str); | |||
/** | |||
* Init default values | |||
@@ -322,28 +322,28 @@ void free_config (struct config_file *cfg); | |||
* @param opt_name name of option to get | |||
* @return module value or NULL if option does not defined | |||
*/ | |||
char* get_module_opt (struct config_file *cfg, char *module_name, char *opt_name); | |||
gchar* get_module_opt (struct config_file *cfg, gchar *module_name, gchar *opt_name); | |||
/** | |||
* Parse limit | |||
* @param limit string representation of limit (eg. 1M) | |||
* @return numeric value of limit | |||
*/ | |||
size_t parse_limit (const char *limit); | |||
gsize parse_limit (const gchar *limit); | |||
/** | |||
* Parse seconds | |||
* @param t string representation of seconds (eg. 1D) | |||
* @return numeric value of string | |||
*/ | |||
unsigned int parse_seconds (const char *t); | |||
unsigned int parse_seconds (const gchar *t); | |||
/** | |||
* Parse flag | |||
* @param str string representation of flag (eg. 'on') | |||
* @return numeric value of flag (0 or 1) | |||
*/ | |||
char parse_flag (const char *str); | |||
gchar parse_flag (const gchar *str); | |||
/** | |||
* Substitutes variable in specified string, may be recursive (eg. ${var1${var2}}) | |||
@@ -353,7 +353,7 @@ char parse_flag (const char *str); | |||
* @param recursive whether do recursive scanning | |||
* @return new string with substituted variables (uses cfg memory pool for allocating) | |||
*/ | |||
char* substitute_variable (struct config_file *cfg, char *name, char *str, u_char recursive); | |||
gchar* substitute_variable (struct config_file *cfg, gchar *name, gchar *str, guchar recursive); | |||
/** | |||
* Do post load actions for config | |||
@@ -366,19 +366,19 @@ void post_load_config (struct config_file *cfg); | |||
* Replace all \" with a single " in given string | |||
* @param line input string | |||
*/ | |||
void unescape_quotes (char *line); | |||
void unescape_quotes (gchar *line); | |||
GList* parse_comma_list (memory_pool_t *pool, char *line); | |||
GList* parse_comma_list (memory_pool_t *pool, gchar *line); | |||
struct classifier_config* check_classifier_cfg (struct config_file *cfg, struct classifier_config *c); | |||
struct worker_conf* check_worker_conf (struct config_file *cfg, struct worker_conf *c); | |||
gboolean parse_normalizer (struct config_file *cfg, struct statfile *st, const char *line); | |||
gboolean read_xml_config (struct config_file *cfg, const char *filename); | |||
gboolean parse_normalizer (struct config_file *cfg, struct statfile *st, const gchar *line); | |||
gboolean read_xml_config (struct config_file *cfg, const gchar *filename); | |||
int yylex (void); | |||
int yyparse (void); | |||
void yyrestart (FILE *); | |||
void parse_err (const char *fmt, ...); | |||
void parse_warn (const char *fmt, ...); | |||
void parse_err (const gchar *fmt, ...); | |||
void parse_warn (const gchar *fmt, ...); | |||
#endif /* ifdef CFG_FILE_H */ | |||
/* |
@@ -41,10 +41,10 @@ | |||
#define DEFAULT_RLIMIT_MAXCORE 0 | |||
extern int yylineno; | |||
extern char *yytext; | |||
extern gchar *yytext; | |||
int | |||
add_memcached_server (struct config_file *cf, char *str) | |||
add_memcached_server (struct config_file *cf, gchar *str) | |||
{ | |||
struct memcached_server *mc; | |||
uint16_t port; | |||
@@ -71,9 +71,9 @@ add_memcached_server (struct config_file *cf, char *str) | |||
} | |||
gboolean | |||
parse_host_port (const char *str, struct in_addr *ina, uint16_t *port) | |||
parse_host_port (const gchar *str, struct in_addr *ina, uint16_t *port) | |||
{ | |||
char **tokens, *err_str; | |||
gchar **tokens, *err_str; | |||
struct hostent *hent; | |||
unsigned int port_parsed, saved_errno = errno; | |||
@@ -128,9 +128,9 @@ err: | |||
} | |||
int | |||
parse_bind_line (struct config_file *cfg, struct worker_conf *cf, char *str) | |||
parse_bind_line (struct config_file *cfg, struct worker_conf *cf, gchar *str) | |||
{ | |||
char **host; | |||
gchar **host; | |||
int16_t *family, *port; | |||
struct in_addr *addr; | |||
@@ -148,7 +148,7 @@ parse_bind_line (struct config_file *cfg, struct worker_conf *cf, char *str) | |||
/* Try to check path of bind credit */ | |||
struct stat st; | |||
int fd; | |||
char *copy = memory_pool_strdup (cfg->cfg_pool, str); | |||
gchar *copy = memory_pool_strdup (cfg->cfg_pool, str); | |||
if (stat (copy, &st) == -1) { | |||
if (errno == ENOENT) { | |||
if ((fd = open (str, O_RDWR | O_TRUNC | O_CREAT, S_IWUSR | S_IRUSR)) == -1) { | |||
@@ -235,8 +235,8 @@ free_config (struct config_file *cfg) | |||
memory_pool_delete (cfg->cfg_pool); | |||
} | |||
char * | |||
get_module_opt (struct config_file *cfg, char *module_name, char *opt_name) | |||
gchar * | |||
get_module_opt (struct config_file *cfg, gchar *module_name, gchar *opt_name) | |||
{ | |||
GList *cur_opt; | |||
struct module_opt *cur; | |||
@@ -257,11 +257,11 @@ get_module_opt (struct config_file *cfg, char *module_name, char *opt_name) | |||
return NULL; | |||
} | |||
size_t | |||
parse_limit (const char *limit) | |||
gsize | |||
parse_limit (const gchar *limit) | |||
{ | |||
size_t result = 0; | |||
char *err_str; | |||
gsize result = 0; | |||
gchar *err_str; | |||
if (!limit || *limit == '\0') | |||
return 0; | |||
@@ -287,10 +287,10 @@ parse_limit (const char *limit) | |||
} | |||
unsigned int | |||
parse_seconds (const char *t) | |||
parse_seconds (const gchar *t) | |||
{ | |||
unsigned int result = 0; | |||
char *err_str; | |||
gchar *err_str; | |||
if (!t || *t == '\0') | |||
return 0; | |||
@@ -322,8 +322,8 @@ parse_seconds (const char *t) | |||
return result; | |||
} | |||
char | |||
parse_flag (const char *str) | |||
gchar | |||
parse_flag (const gchar *str) | |||
{ | |||
if (!str || !*str) | |||
return -1; | |||
@@ -351,11 +351,11 @@ parse_flag (const char *str) | |||
* Try to substitute all variables in given string | |||
* Return: newly allocated string with substituted variables (original string may be freed if variables are found) | |||
*/ | |||
char * | |||
substitute_variable (struct config_file *cfg, char *name, char *str, u_char recursive) | |||
gchar * | |||
substitute_variable (struct config_file *cfg, gchar *name, gchar *str, guchar recursive) | |||
{ | |||
char *var, *new, *v_begin, *v_end, *p, t; | |||
size_t len; | |||
gchar *var, *new, *v_begin, *v_end, *p, t; | |||
gsize len; | |||
gboolean changed = FALSE; | |||
if (str == NULL) { | |||
@@ -423,11 +423,11 @@ substitute_all_variables (gpointer key, gpointer value, gpointer data) | |||
struct config_file *cfg = (struct config_file *)data; | |||
/* Do recursive substitution */ | |||
(void)substitute_variable (cfg, (char *)key, (char *)value, 1); | |||
(void)substitute_variable (cfg, (gchar *)key, (gchar *)value, 1); | |||
} | |||
static void | |||
parse_filters_str (struct config_file *cfg, const char *str) | |||
parse_filters_str (struct config_file *cfg, const gchar *str) | |||
{ | |||
gchar **strvec, **p; | |||
struct filter *cur; | |||
@@ -544,10 +544,10 @@ post_load_config (struct config_file *cfg) | |||
void | |||
parse_err (const char *fmt, ...) | |||
parse_err (const gchar *fmt, ...) | |||
{ | |||
va_list aq; | |||
char logbuf[BUFSIZ], readbuf[32]; | |||
gchar logbuf[BUFSIZ], readbuf[32]; | |||
int r; | |||
va_start (aq, fmt); | |||
@@ -561,10 +561,10 @@ parse_err (const char *fmt, ...) | |||
} | |||
void | |||
parse_warn (const char *fmt, ...) | |||
parse_warn (const gchar *fmt, ...) | |||
{ | |||
va_list aq; | |||
char logbuf[BUFSIZ], readbuf[32]; | |||
gchar logbuf[BUFSIZ], readbuf[32]; | |||
int r; | |||
va_start (aq, fmt); | |||
@@ -578,9 +578,9 @@ parse_warn (const char *fmt, ...) | |||
} | |||
void | |||
unescape_quotes (char *line) | |||
unescape_quotes (gchar *line) | |||
{ | |||
char *c = line, *t; | |||
gchar *c = line, *t; | |||
while (*c) { | |||
if (*c == '\\' && *(c + 1) == '"') { | |||
@@ -595,10 +595,10 @@ unescape_quotes (char *line) | |||
} | |||
GList * | |||
parse_comma_list (memory_pool_t * pool, char *line) | |||
parse_comma_list (memory_pool_t * pool, gchar *line) | |||
{ | |||
GList *res = NULL; | |||
char *c, *p, *str; | |||
gchar *c, *p, *str; | |||
c = line; | |||
p = c; | |||
@@ -682,10 +682,10 @@ internal_normalizer_func (double score, void *data) | |||
} | |||
static gboolean | |||
parse_internal_normalizer (struct config_file *cfg, struct statfile *st, const char *line) | |||
parse_internal_normalizer (struct config_file *cfg, struct statfile *st, const gchar *line) | |||
{ | |||
double *max; | |||
char *err; | |||
gchar *err; | |||
/* Line contains maximum value for internal normalizer */ | |||
max = memory_pool_alloc (cfg->cfg_pool, sizeof (double)); | |||
@@ -705,9 +705,9 @@ parse_internal_normalizer (struct config_file *cfg, struct statfile *st, const c | |||
#ifdef WITH_LUA | |||
static gboolean | |||
parse_lua_normalizer (struct config_file *cfg, struct statfile *st, const char *line) | |||
parse_lua_normalizer (struct config_file *cfg, struct statfile *st, const gchar *line) | |||
{ | |||
char *code_begin; | |||
gchar *code_begin; | |||
GList *params = NULL; | |||
int len; | |||
@@ -736,9 +736,9 @@ parse_lua_normalizer (struct config_file *cfg, struct statfile *st, const char * | |||
gboolean | |||
parse_normalizer (struct config_file *cfg, struct statfile *st, const char *line) | |||
parse_normalizer (struct config_file *cfg, struct statfile *st, const gchar *line) | |||
{ | |||
char *params_begin; | |||
gchar *params_begin; | |||
params_begin = strchr (line, ':'); | |||
if (params_begin == NULL) { | |||
@@ -769,7 +769,7 @@ static GMarkupParser xml_parser = { | |||
}; | |||
gboolean | |||
read_xml_config (struct config_file *cfg, const char *filename) | |||
read_xml_config (struct config_file *cfg, const gchar *filename) | |||
{ | |||
struct stat st; | |||
int fd; |
@@ -29,6 +29,151 @@ | |||
#include "config.h" | |||
#include "cfg_xml.h" | |||
#include "logger.h" | |||
#include "util.h" | |||
/* Maximum attributes for param */ | |||
#define MAX_PARAM 64 | |||
#define NULL_ATTR \ | |||
{ \ | |||
NULL, \ | |||
NULL, \ | |||
0, \ | |||
NULL \ | |||
} \ | |||
/* Basic xml parsing functions */ | |||
gboolean xml_handle_string (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset); | |||
/* Numeric params */ | |||
gboolean xml_handle_size (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset); | |||
gboolean xml_handle_double (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset); | |||
gboolean xml_handle_seconds (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset); | |||
gboolean xml_handle_int (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset); | |||
gboolean xml_handle_uint32 (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset); | |||
gboolean xml_handle_uint16 (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset); | |||
/* Flags */ | |||
gboolean xml_handle_boolean (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset); | |||
/* Specific params */ | |||
gboolean worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset); | |||
gboolean handle_factor (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset); | |||
enum xml_config_section { | |||
XML_SECTION_MAIN, | |||
XML_SECTION_LOGGING, | |||
XML_SECTION_WORKER, | |||
XML_SECTION_METRIC, | |||
XML_SECTION_CLASSIFIER, | |||
XML_SECTION_FACTORS, | |||
XML_SECTION_MODULE, | |||
XML_SECTION_MODULES, | |||
XML_SECTION_VIEW, | |||
XML_SECTION_SETTINGS | |||
}; | |||
struct xml_config_param { | |||
const char *name; | |||
element_handler_func handler; | |||
int 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; | |||
}; | |||
/* Here we describes our basic grammar */ | |||
static struct xml_parser_rule grammar[] = { | |||
{ XML_SECTION_MAIN, { | |||
{ | |||
"pidfile", | |||
xml_handle_string, | |||
G_STRUCT_OFFSET (struct config_file, pid_file), | |||
NULL | |||
}, | |||
{ | |||
"statfile_pool_size", | |||
xml_handle_size, | |||
G_STRUCT_OFFSET (struct config_file, max_statfile_size), | |||
NULL | |||
}, | |||
{ | |||
"filters", | |||
xml_handle_string, | |||
G_STRUCT_OFFSET (struct config_file, filters_str), | |||
NULL | |||
}, | |||
NULL_ATTR | |||
}, | |||
NULL_ATTR | |||
}, | |||
{ XML_SECTION_LOGGING, { | |||
NULL_ATTR | |||
}, | |||
NULL_ATTR | |||
}, | |||
{ XML_SECTION_WORKER, { | |||
NULL_ATTR | |||
}, | |||
{ | |||
NULL, | |||
worker_handle_param, | |||
0, | |||
NULL | |||
}, | |||
}, | |||
{ XML_SECTION_METRIC, { | |||
NULL_ATTR | |||
}, | |||
NULL_ATTR | |||
}, | |||
{ XML_SECTION_CLASSIFIER, { | |||
NULL_ATTR | |||
}, | |||
NULL_ATTR | |||
}, | |||
{ XML_SECTION_FACTORS, { | |||
{ | |||
"grow_factor", | |||
xml_handle_double, | |||
G_STRUCT_OFFSET (struct config_file, grow_factor), | |||
NULL | |||
}, | |||
NULL_ATTR | |||
}, | |||
{ | |||
NULL, | |||
handle_factor, | |||
0, | |||
NULL | |||
} | |||
}, | |||
{ XML_SECTION_MODULE, { | |||
NULL_ATTR | |||
}, | |||
NULL_ATTR | |||
}, | |||
{ XML_SECTION_MODULES, { | |||
NULL_ATTR | |||
}, | |||
NULL_ATTR | |||
}, | |||
{ XML_SECTION_VIEW, { | |||
NULL_ATTR | |||
}, | |||
NULL_ATTR | |||
}, | |||
{ XML_SECTION_SETTINGS, { | |||
NULL_ATTR | |||
}, | |||
NULL_ATTR | |||
} | |||
}; | |||
GQuark | |||
xml_error_quark (void) | |||
@@ -68,6 +213,77 @@ xml_asciiz_string (memory_pool_t *pool, const gchar *text, gsize len) | |||
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) | |||
{ | |||
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)); | |||
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, const gchar *value, gpointer dest_struct, enum xml_config_section section) | |||
{ | |||
struct xml_parser_rule *rule; | |||
struct xml_config_param *param; | |||
int 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) { | |||
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 FALSE; | |||
} | |||
gboolean | |||
worker_handle_param (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset) | |||
{ | |||
} | |||
gboolean | |||
handle_factor (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset) | |||
{ | |||
} | |||
static void | |||
xml_parse_module_opt (struct rspamd_xml_userdata *ud, const gchar *text, gsize len) | |||
{ | |||
@@ -105,6 +321,129 @@ xml_parse_module_opt (struct rspamd_xml_userdata *ud, const gchar *text, gsize l | |||
} | |||
/* Common handlers */ | |||
gboolean | |||
xml_handle_string (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset) | |||
{ | |||
/* Simply assign pointer to pointer */ | |||
gchar **dest; | |||
dest = (char **)G_STRUCT_MEMBER_P (dest_struct, offset); | |||
*dest = memory_pool_strdup (cfg->cfg_pool, data); | |||
return TRUE; | |||
} | |||
gboolean | |||
xml_handle_size (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset) | |||
{ | |||
gsize *dest; | |||
dest = (gsize *)G_STRUCT_MEMBER_P (dest_struct, offset); | |||
*dest = parse_limit (data); | |||
return TRUE; | |||
} | |||
gboolean | |||
xml_handle_seconds (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset) | |||
{ | |||
time_t *dest; | |||
dest = (time_t *)G_STRUCT_MEMBER_P (dest_struct, offset); | |||
*dest = parse_seconds (data); | |||
return TRUE; | |||
} | |||
gboolean | |||
xml_handle_boolean (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int 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_double (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset) | |||
{ | |||
double *dest; | |||
char *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, const gchar *data, gpointer user_data, gpointer dest_struct, int offset) | |||
{ | |||
int *dest; | |||
char *err = NULL; | |||
dest = (int *)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, const gchar *data, gpointer user_data, gpointer dest_struct, int offset) | |||
{ | |||
uint32_t *dest; | |||
char *err = NULL; | |||
dest = (uint32_t *)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, const gchar *data, gpointer user_data, gpointer dest_struct, int offset) | |||
{ | |||
uint16_t *dest; | |||
char *err = NULL; | |||
dest = (uint16_t *)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; | |||
} | |||
void | |||
rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, | |||
const gchar **attribute_values, gpointer user_data, GError **error) | |||
@@ -128,7 +467,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam | |||
if (g_ascii_strcasecmp (element_name, "module") == 0) { | |||
/* Read module data */ | |||
if (extract_attr ("name", attribute_names, attribute_values, &res)) { | |||
ud->section_name = g_strdup (res); | |||
g_strlcpy (ud->section_name, res, sizeof (res)); | |||
ud->state = XML_READ_MODULE; | |||
} | |||
else { | |||
@@ -144,7 +483,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam | |||
} | |||
else if (g_ascii_strcasecmp (element_name, "metric") == 0) { | |||
if (extract_attr ("name", attribute_names, attribute_values, &res)) { | |||
ud->section_name = g_strdup (res); | |||
g_strlcpy (ud->section_name, res, sizeof (res)); | |||
ud->state = XML_READ_METRIC; | |||
} | |||
else { | |||
@@ -154,7 +493,7 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam | |||
} | |||
else if (g_ascii_strcasecmp (element_name, "classifier") == 0) { | |||
if (extract_attr ("type", attribute_names, attribute_values, &res)) { | |||
ud->section_name = g_strdup (res); | |||
g_strlcpy (ud->section_name, res, sizeof (res)); | |||
ud->state = XML_READ_CLASSIFIER; | |||
} | |||
else { | |||
@@ -163,20 +502,13 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam | |||
} | |||
} | |||
else if (g_ascii_strcasecmp (element_name, "worker") == 0) { | |||
if (extract_attr ("type", attribute_names, attribute_values, &res)) { | |||
ud->section_name = g_strdup (res); | |||
ud->state = XML_READ_WORKER; | |||
} | |||
else { | |||
*error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'type' is required for tag 'worker'"); | |||
ud->state = XML_ERROR; | |||
} | |||
ud->state = XML_READ_WORKER; | |||
} | |||
else { | |||
/* Other params */ | |||
if (g_ascii_strcasecmp (element_name, "variable") == 0) { | |||
if (extract_attr ("name", attribute_names, attribute_values, &res)) { | |||
ud->section_name = g_strdup (res); | |||
g_strlcpy (ud->section_name, res, sizeof (res)); | |||
ud->state = XML_READ_VARIABLE; | |||
} | |||
else { | |||
@@ -194,34 +526,13 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam | |||
} | |||
break; | |||
case XML_READ_MODULE: | |||
if (g_ascii_strcasecmp (element_name, "param") == 0) { | |||
if (extract_attr ("name", attribute_names, attribute_values, &res)) { | |||
ud->other_data = g_strdup (res); | |||
} | |||
else { | |||
*error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'name' is required for tag 'param'"); | |||
ud->state = XML_ERROR; | |||
} | |||
} | |||
break; | |||
case XML_READ_FACTORS: | |||
case XML_READ_CLASSIFIER: | |||
break; | |||
case XML_READ_STATFILE: | |||
break; | |||
case XML_READ_FACTORS: | |||
if (g_ascii_strcasecmp (element_name, "factor") == 0) { | |||
if (extract_attr ("name", attribute_names, attribute_values, &res)) { | |||
ud->other_data = g_strdup (res); | |||
} | |||
else { | |||
*error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'name' is required for tag 'factor'"); | |||
ud->state = XML_ERROR; | |||
} | |||
} | |||
break; | |||
case XML_READ_WORKER: | |||
break; | |||
case XML_READ_LOGGING: | |||
/* Save attributes */ | |||
ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values); | |||
break; | |||
default: | |||
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "element %s is unexpected in this state", element_name); | |||
@@ -234,9 +545,6 @@ do { \ | |||
if (g_ascii_strcasecmp (element_name, (x)) == 0) { \ | |||
ud->state = XML_READ_PARAM; \ | |||
res = TRUE; \ | |||
if (!required) { \ | |||
g_free (ud->section_name); \ | |||
} \ | |||
} \ | |||
else { \ | |||
res = FALSE; \ | |||
@@ -310,55 +618,57 @@ rspamd_xml_text (GMarkupParseContext *context, const gchar *text, gsize text_len | |||
{ | |||
struct rspamd_xml_userdata *ud = user_data; | |||
char *val; | |||
double *tmp; | |||
struct config_file *cfg = ud->cfg; | |||
val = xml_asciiz_string (cfg->cfg_pool, text, text_len); | |||
switch (ud->state) { | |||
case XML_READ_MODULE: | |||
if (ud->other_data) { | |||
/* Insert or replace module's option */ | |||
xml_parse_module_opt (ud, text, text_len); | |||
g_free (ud->other_data); | |||
if (!call_param_handler (ud, ud->section_name, val, ud->other_data, XML_SECTION_MODULE)) { | |||
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); | |||
ud->state = XML_ERROR; | |||
} | |||
break; | |||
case XML_READ_CLASSIFIER: | |||
if (!call_param_handler (ud, ud->section_name, val, ud->other_data, XML_SECTION_CLASSIFIER)) { | |||
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); | |||
ud->state = XML_ERROR; | |||
} | |||
break; | |||
case XML_READ_STATFILE: | |||
break; | |||
case XML_READ_FACTORS: | |||
if (ud->other_data) { | |||
/* Assume that we have factor name in other_data */ | |||
val = xml_asciiz_string (ud->cfg->cfg_pool, text, text_len); | |||
tmp = memory_pool_alloc (ud->cfg->cfg_pool, sizeof (double)); | |||
*tmp = strtod (val, NULL); | |||
g_hash_table_insert (ud->cfg->factors, ud->other_data, tmp); | |||
g_free (ud->other_data); | |||
if (!call_param_handler (ud, ud->section_name, val, cfg, XML_SECTION_CLASSIFIER)) { | |||
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); | |||
ud->state = XML_ERROR; | |||
} | |||
break; | |||
case XML_READ_METRIC: | |||
if (!call_param_handler (ud, ud->section_name, val, ud->other_data, XML_SECTION_METRIC)) { | |||
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); | |||
ud->state = XML_ERROR; | |||
} | |||
break; | |||
case XML_READ_WORKER: | |||
break; | |||
case XML_READ_VARIABLE: | |||
if (ud->other_data) { | |||
/* Assume that we have factor name in other_data */ | |||
val = xml_asciiz_string (ud->cfg->cfg_pool, text, text_len); | |||
g_hash_table_insert (ud->cfg->variables, ud->other_data, val); | |||
g_free (ud->other_data); | |||
if (!call_param_handler (ud, ud->section_name, val, ud->other_data, XML_SECTION_WORKER)) { | |||
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); | |||
ud->state = XML_ERROR; | |||
} | |||
break; | |||
case XML_READ_VARIABLE: | |||
case XML_READ_PIDFILE: | |||
val = xml_asciiz_string (ud->cfg->cfg_pool, text, text_len); | |||
ud->cfg->pid_file = val; | |||
break; | |||
case XML_READ_STATFILE_POOL: | |||
val = xml_asciiz_string (ud->cfg->cfg_pool, text, text_len); | |||
ud->cfg->max_statfile_size = strtoull (val, NULL, 10); | |||
break; | |||
case XML_READ_FILTERS: | |||
val = xml_asciiz_string (ud->cfg->cfg_pool, text, text_len); | |||
ud->cfg->filters_str = val; | |||
if (!call_param_handler (ud, ud->section_name, val, cfg, XML_SECTION_MAIN)) { | |||
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "cannot parse tag's '%s' data: %s", ud->section_name, val); | |||
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 '%s' data: %s", ud->section_name, val); | |||
ud->state = XML_ERROR; | |||
} | |||
break; | |||
case XML_READ_PARAM: | |||
break; |
@@ -4,6 +4,8 @@ | |||
#include "config.h" | |||
#include "cfg_file.h" | |||
#define MAX_NAME 8192 | |||
#define XML_START_MISSING 1 | |||
#define XML_PARAM_MISSING 2 | |||
#define XML_EXTRA_ELEMENT 3 | |||
@@ -30,10 +32,14 @@ enum xml_read_state { | |||
struct rspamd_xml_userdata { | |||
enum xml_read_state state; | |||
struct config_file *cfg; | |||
gchar *section_name; | |||
gchar section_name[MAX_NAME]; | |||
gpointer other_data; | |||
GHashTable *cur_attrs; | |||
}; | |||
/* Text is NULL terminated here */ | |||
typedef gboolean (*element_handler_func) (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, const gchar *data, gpointer user_data, gpointer dest_struct, int offset); | |||
/* Called for open tags <foo bar="baz"> */ | |||
void rspamd_xml_start_element (GMarkupParseContext *context, | |||
const gchar *element_name, |