enum { VAL_UNDEF=0, VAL_TRUE, VAL_FALSE };
+/**
+ * Type of time configuration parameter
+ */
+enum time_type {
+ TIME_SECONDS = 0,
+ TIME_MILLISECONDS,
+ TIME_MINUTES,
+ TIME_HOURS
+};
/**
* Types of rspamd bind lines
*/
gsize parse_limit (const gchar *limit);
/**
- * Parse seconds
+ * Parse time
* @param t string representation of seconds (eg. 1D)
- * @return numeric value of string
+ * @param default_type dimension of time if no suffix is specified
+ * @return value of time in milliseconds
*/
-guint parse_seconds (const gchar *t);
+guint parse_time (const gchar *t, enum time_type default_type);
/**
* Parse flag
if (!limit || *limit == '\0')
return 0;
+ errno = 0;
result = strtoul (limit, &err_str, 10);
if (*err_str != '\0') {
else if (*err_str == 'g' || *err_str == 'G') {
result *= 1073741824L;
}
+ else {
+ msg_warn ("invalid limit value '%s' at position '%s'", limit, err_str);
+ result = 0;
+ }
}
return result;
}
guint
-parse_seconds (const gchar *t)
+parse_time (const gchar *t, enum time_type default_type)
{
- guint result = 0;
+ union {
+ guint i;
+ double d;
+ } result;
+ gboolean use_double = FALSE;
gchar *err_str;
if (!t || *t == '\0')
return 0;
- result = strtoul (t, &err_str, 10);
+ errno = 0;
+ result.i = strtoul (t, &err_str, 10);
if (*err_str != '\0') {
+ if (*err_str == '.') {
+ /* Try to handle decimal point */
+ errno = 0;
+ result.d = strtod (t, &err_str);
+ use_double = TRUE;
+ }
/* Seconds */
if (*err_str == 's' || *err_str == 'S') {
- result *= 1000;
+ if (use_double) {
+ result.d *= 1000.;
+ }
+ else {
+ result.i *= 1000;
+ }
}
/* Minutes */
else if (*err_str == 'm' || *err_str == 'M') {
/* Handle ms correctly */
- if (*(err_str + 1) == 's' || *(err_str + 1) == 'S') {
- result *= 60 * 1000;
+ if (*(err_str + 1) != 's' && *(err_str + 1) != 'S') {
+ if (use_double) {
+ result.d *= 60. * 1000.;
+ }
+ else {
+ result.i *= 60 * 1000;
+ }
}
}
/* Hours */
else if (*err_str == 'h' || *err_str == 'H') {
- result *= 60 * 60 * 1000;
+ if (use_double) {
+ result.d *= 60. * 60. * 1000.;
+ }
+ else {
+ result.i *= 60 * 60 * 1000;
+ }
}
/* Days */
else if (*err_str == 'd' || *err_str == 'D') {
- result *= 24 * 60 * 60 * 1000;
+ if (use_double) {
+ result.d *= 24. * 60. * 60. * 1000.;
+ }
+ else {
+ result.i *= 24 * 60 * 60 * 1000;
+ }
+ }
+ else {
+ msg_warn ("invalid time value '%s' at position '%s'", t, err_str);
+ if (use_double) {
+ result.d = 0.;
+ }
+ else {
+ result.i = 0;
+ }
}
}
-
- return result;
+ else {
+ /* Switch to default time multiplier */
+ switch (default_type) {
+ case TIME_HOURS:
+ if (use_double) {
+ result.d *= 60. * 60. * 1000.;
+ }
+ else {
+ result.i *= 60 * 60 * 1000;
+ }
+ break;
+ case TIME_MINUTES:
+ if (use_double) {
+ result.d *= 60. * 1000.;
+ }
+ else {
+ result.i *= 60 * 1000;
+ }
+ break;
+ case TIME_SECONDS:
+ if (use_double) {
+ result.d *= 1000.;
+ }
+ else {
+ result.i *= 1000;
+ }
+ break;
+ case TIME_MILLISECONDS:
+ break;
+ }
+ }
+ if (use_double) {
+ return rint (result.d);
+ }
+ else {
+ return result.i;
+ }
}
gchar
#include "tokenizers/tokenizers.h"
#include "lua/lua_common.h"
#include "view.h"
+#include "map.h"
#include "expressions.h"
#include "settings.h"
is_lua = TRUE;
}
}
- /* XXX: in fact we cannot check for lua modules and need to do it in post-config procedure
+ /*
+ * XXX: in fact we cannot check for lua modules and need to do it in post-config procedure
* so just insert any options provided and try to handle them in further process
*/
if (st->binlog == NULL) {
st->binlog = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct statfile_binlog_params));
}
- st->binlog->rotate_time = parse_seconds (data);
+ st->binlog->rotate_time = parse_time (data, TIME_SECONDS);
return TRUE;
}
guint32 *dest;
dest = (guint32 *)G_STRUCT_MEMBER_P (dest_struct, offset);
- *dest = parse_seconds (data);
+ *dest = parse_time (data, TIME_SECONDS);
return TRUE;
}
}
/* Register handlers for specific parts of config */
+
+/* Checker for module options */
+static gboolean
+check_module_option (struct config_file *cfg, const gchar *mname, const gchar *optname, const gchar *data)
+{
+ struct xml_config_param *param;
+ enum module_opt_type type;
+ GHashTable *module;
+ gchar *err_str;
+
+ 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) {
+ msg_warn ("module %s has not registered option %s", mname, optname);
+ return FALSE;
+ }
+
+ 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:
+ (void)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;
+ }
+ break;
+ case MODULE_OPT_TYPE_UINT:
+ (void)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;
+ }
+ break;
+ case MODULE_OPT_TYPE_TIME:
+ (void)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;
+ }
+ break;
+ case MODULE_OPT_TYPE_SIZE:
+ (void)parse_limit (data);
+ if (errno != 0) {
+ msg_warn ("non-numeric data for option: '%s' for module: '%s': %s", optname, mname, strerror (errno));
+ return FALSE;
+ }
+ break;
+ case MODULE_OPT_TYPE_MAP:
+ if (!check_map_proto (data, NULL, NULL)) {
+ return FALSE;
+ }
+ break;
+ }
+
+ return TRUE;
+}
+
/* Register new module option */
void
-register_module_opt (const gchar *mname, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset)
+register_module_opt (const gchar *mname, const gchar *optname, enum module_opt_type type)
{
struct xml_config_param *param;
GHashTable *module;
if ((param = g_hash_table_lookup (module, optname)) == NULL) {
/* Register new param */
param = g_malloc (sizeof (struct xml_config_param));
- param->handler = func;
- param->user_data = dest_struct;
- param->offset = offset;
+ param->handler = NULL;
+ param->offset = type;
param->name = optname;
g_hash_table_insert (module, (char *)optname, param);
}
msg_warn ("replace old handler for param '%s'", optname);
g_free (param);
param = g_malloc (sizeof (struct xml_config_param));
- param->handler = func;
- param->user_data = dest_struct;
- param->offset = offset;
+ param->handler = NULL;
+ param->offset = type;
param->name = optname;
g_hash_table_insert (module, (char *)optname, param);
}
XML_END
};
+enum module_opt_type {
+ MODULE_OPT_TYPE_STRING = 0,
+ MODULE_OPT_TYPE_INT,
+ MODULE_OPT_TYPE_UINT,
+ MODULE_OPT_TYPE_TIME,
+ MODULE_OPT_TYPE_MAP,
+ MODULE_OPT_TYPE_SIZE,
+ MODULE_OPT_TYPE_ANY
+};
+
struct rspamd_xml_userdata {
enum xml_read_state state;
struct config_file *cfg;
gboolean handle_statfile_binlog_master (struct config_file *cfg, struct rspamd_xml_userdata *ctx, GHashTable *attrs, gchar *data, gpointer user_data, gpointer dest_struct, gint offset);
/* Register new module option */
-void register_module_opt (const gchar *mname, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset);
+void register_module_opt (const gchar *mname, const gchar *optname, enum module_opt_type type);
/* Register new worker's options */
void register_worker_opt (gint wtype, const gchar *optname, element_handler_func func, gpointer dest_struct, gint offset);
ctx->expire_time = DEFAULT_EXPIRE_TIME;
if ((value = g_hash_table_lookup (worker->cf->params, "greylist_time")) != NULL) {
- ctx->greylist_time = parse_seconds (value) / 1000;
+ ctx->greylist_time = parse_time (value, TIME_SECONDS) / 1000;
}
if ((value = g_hash_table_lookup (worker->cf->params, "expire_time")) != NULL) {
- ctx->expire_time = parse_seconds (value) / 1000;
+ ctx->expire_time = parse_time (value, TIME_SECONDS) / 1000;
}
worker->ctx = ctx;
*map->user_data = cbdata.cur_data;
}
+gboolean
+check_map_proto (const gchar *map_line, gint *res, const gchar **pos)
+{
+ if (g_ascii_strncasecmp (map_line, "http://", sizeof ("http://") - 1) == 0) {
+ if (res && pos) {
+ *res = PROTO_HTTP;
+ *pos = map_line + sizeof ("http://") - 1;
+ }
+ }
+ else if (g_ascii_strncasecmp (map_line, "file://", sizeof ("file://") - 1) == 0) {
+ if (res && pos) {
+ *res = PROTO_FILE;
+ *pos = map_line + sizeof ("file://") - 1;
+ }
+ }
+ else {
+ msg_warn ("invalid map fetching protocol: %s", map_line);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
gboolean
add_map (const gchar *map_line, map_cb_t read_callback, map_fin_cb_t fin_callback, void **user_data)
{
struct hostent *hent;
/* First of all detect protocol line */
- if (strncmp (map_line, "http://", sizeof ("http://") - 1) == 0) {
- proto = PROTO_HTTP;
- def = map_line + sizeof ("http://") - 1;
- }
- else if (strncmp (map_line, "file://", sizeof ("file://") - 1) == 0) {
- proto = PROTO_FILE;
- def = map_line + sizeof ("file://") - 1;
- }
- else {
- msg_warn ("invalid map fetching protocol: %s", map_line);
+ if (!check_map_proto (map_line, (int *)&proto, &def)) {
return FALSE;
}
/* Constant pool */
void *map_data;
};
+/**
+ * Check map protocol
+ */
+gboolean check_map_proto (const gchar *map_line, gint *res, const gchar **pos);
/**
* Add map from line
*/
*ctx = (struct module_ctx *)surbl_module_ctx;
register_protocol_command ("urls", urls_command_handler);
+ /* Register module options */
return 0;
}
surbl_module_ctx->url_expire = DEFAULT_SURBL_URL_EXPIRE;
}
if ((value = get_module_opt (cfg, "surbl", "redirector_connect_timeout")) != NULL) {
- surbl_module_ctx->connect_timeout = parse_seconds (value);
+ surbl_module_ctx->connect_timeout = parse_time (value, TIME_SECONDS);
}
else {
surbl_module_ctx->connect_timeout = DEFAULT_REDIRECTOR_CONNECT_TIMEOUT;
}
if ((value = get_module_opt (cfg, "surbl", "redirector_read_timeout")) != NULL) {
- surbl_module_ctx->read_timeout = parse_seconds (value);
+ surbl_module_ctx->read_timeout = parse_time (value, TIME_SECONDS);
}
else {
surbl_module_ctx->read_timeout = DEFAULT_REDIRECTOR_READ_TIMEOUT;
return FALSE;
}
/* Create smtp banner */
- if ((ctx->smtp_banner_str) != NULL) {
+ if ((value = ctx->smtp_banner_str) != NULL) {
parse_smtp_banner (ctx, value);
}