struct rspamd_result *result;
GString *in_buf;
struct rspamd_metric *cur_metric;
+ gint version;
};
static struct rspamd_client *client = NULL;
{
gchar *b = conn->in_buf->str + sizeof("RSPAMD/") - 1, *p, *c;
guint remain = len - sizeof("RSPAMD/") + 1, state = 0, next_state;
+ gdouble dver;
p = b;
+ c = p;
while (p - b < remain) {
switch (state) {
case 0:
if (g_ascii_isspace (*p)) {
state = 99;
next_state = 1;
+ dver = strtod (c, NULL);
+ conn->version = floor (dver * 10 + 0.5);
}
else if (!g_ascii_isdigit (*p) && *p != '.') {
goto err;
/* Read required score */
if (g_ascii_isspace (*p) || p - b == remain - 1) {
new->required_score = strtod (c, &err_str);
- if (*err_str != *p) {
+ if (*err_str != *p && *err_str != *(p + 1)) {
/* Invalid score */
goto err;
}
struct rspamd_symbol *new;
p = b;
- c = b;
+ while (g_ascii_isspace (*p)) {
+ p ++;
+ }
+ c = p;
while (p - b < remain) {
switch (state) {
case 0:
/* Read symbol's name */
- if (g_ascii_isspace (*p)) {
- state = 99;
- next_state = 0;
- }
- else if (*p == ';' || *p == '(') {
+ if (p - b == remain - 1 || *p == ';' || *p == '(') {
if (p - c <= 1) {
/* Empty symbol name */
goto err;
}
else {
+ if (p - b == remain - 1) {
+ l = p - c + 1;
+ }
+ else {
+ if (*p == '(') {
+ next_state = 1;
+ }
+ else if (*p == ';' ) {
+ next_state = 2;
+ }
+ l = p - c;
+ }
/* Create new symbol */
- sym = g_malloc (p - c + 1);
- sym[p - c] = '\0';
- memcpy (sym, c, p - c);
+ sym = g_malloc (l + 1);
+ sym[l] = '\0';
+ memcpy (sym, c, l);
if (g_hash_table_lookup (conn->cur_metric->symbols, sym) != NULL) {
/* Duplicate symbol */
new->name = sym;
g_hash_table_insert (conn->cur_metric->symbols, sym, new);
state = 99;
- if (*p == '(') {
- next_state = 1;
- new->weight = 0;
- }
- else {
- next_state = 2;
- }
}
}
p ++;
p ++;
}
state = 99;
- next_state = 2;
+ if (conn->version >= 13) {
+ next_state = 2;
+ }
+ else {
+ next_state = 3;
+ }
}
p ++;
break;
case 2:
+ /* Read description */
+ if (*p == ';' || p - b == remain - 1) {
+ if (*p == ';') {
+ l = p - c;
+ }
+ else {
+ l = p - c + 1;
+ }
+
+ if (l > 0) {
+ sym = g_malloc (l + 1);
+ sym[l] = '\0';
+ memcpy (sym, c, l);
+ new->description = sym;
+ }
+ state = 99;
+ next_state = 3;
+ }
+ p ++;
+ break;
+ case 3:
/* Read option */
if (*p == ',' || p - b == remain - 1) {
/* Insert option into linked list */
err:
if (*err == NULL) {
- *err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid symbol line: %*s at pos: %d",
- remain, b, (int)(p - b));
+ *err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid symbol line: %*s at pos: %d, at state: %d",
+ remain, b, (int)(p - b), state);
}
upstream_fail (&conn->server->up, conn->connection_time);
return FALSE;
gint r;
/* Write command */
- r = rspamd_snprintf (outbuf, sizeof (outbuf), "%s RSPAMC/1.2\r\n", command);
+ r = rspamd_snprintf (outbuf, sizeof (outbuf), "%s RSPAMC/1.3\r\n", command);
r += rspamd_snprintf (outbuf + r, sizeof (outbuf) - r, "Content-Length: %uz\r\n", clen);
/* Iterate through headers */
if (headers != NULL) {
*/
struct rspamd_symbol {
gchar *name; /**< name */
+ gchar *description; /**< description */
double weight; /**< weight */
GList *options; /**< List of options (as const gchar *) */
};
c->action = METRIC_ACTION_REJECT;
c->grow_factor = 1.0;
c->symbols = g_hash_table_new (g_str_hash, g_str_equal);
+ c->descriptions = g_hash_table_new (g_str_hash, g_str_equal);
memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func) g_hash_table_destroy, c->symbols);
+ memory_pool_add_destructor (cfg->cfg_pool, (pool_destruct_func) g_hash_table_destroy, c->descriptions);
}
return c;
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;
+ gchar *strval, *err, *desc;
double *value;
GList *metric_list;
struct metric *metric = ctx->section_pointer;
}
}
+ if (attrs != NULL) {
+ desc = g_hash_table_lookup (attrs, "description");
+ if (desc) {
+ g_hash_table_insert (metric->descriptions, data, memory_pool_strdup (cfg->cfg_pool, desc));
+ }
+ }
+
g_hash_table_insert (metric->symbols, data, value);
if ((metric_list = g_hash_table_lookup (cfg->metrics_symbols, data)) == NULL) {
first = FALSE;
}
PRINT_FUNC ("%s(%.2f)", s->name, s->weight);
+
if (s->options) {
PRINT_FUNC ("(");
cur = g_list_first (s->options);
cur = g_list_next (cur);
}
}
-
+ if (s->description) {
+ PRINT_FUNC (" - \"%s\"", s->description);
+ }
}
}
PRINT_FUNC ("\n");
* Common definition of metric
*/
struct metric {
- gchar *name; /**< name of metric */
+ gchar *name; /**< name of metric */
gchar *func_name; /**< name of consolidation function */
metric_cons_func func; /**< c consolidation function */
double grow_factor; /**< grow factor for metric */
double required_score; /**< required score for this metric */
double reject_score; /**< reject score for this metric */
GHashTable *symbols; /**< weights of symbols in metric */
+ GHashTable *descriptions; /**< descriptions of symbols in metric */
enum rspamd_metric_action action; /**< action to do by this metric by default */
GList *actions; /**< actions that can be performed by this metric */
};
if (lua_istable (L, -1)) {
/* We got a table, so extract individual attributes */
lua_pushstring (L, "weight");
- lua_gettable (L, -1);
+ lua_gettable (L, -2);
if (lua_isnumber (L, -1)) {
score = memory_pool_alloc (cfg->cfg_pool, sizeof (double));
*score = lua_tonumber (L, -1);
msg_warn ("cannot get weight of symbol: %s", symbol);
continue;
}
+ lua_pop (L, 1);
+ lua_pushstring (L, "description");
+ lua_gettable (L, -2);
+ if (lua_isstring (L, -1)) {
+ g_hash_table_insert (metric->descriptions,
+ symbol, memory_pool_strdup (cfg->cfg_pool, lua_tostring (L, -1)));
+ }
+ lua_pop (L, 1);
}
else if (lua_isnumber (L, -1)) {
/* Just got weight */
else if (strncmp (token, RSPAMC_PROTO_1_2, sizeof (RSPAMC_PROTO_1_2) - 1) == 0) {
task->proto_ver = 12;
}
+ else if (strncmp (token, RSPAMC_PROTO_1_3, sizeof (RSPAMC_PROTO_1_3) - 1) == 0) {
+ task->proto_ver = 13;
+ }
}
}
else if (g_ascii_strncasecmp (line->begin, SPAMC_GREETING, sizeof (SPAMC_GREETING) - 1) == 0) {
gint symbols_size;
gint symbols_offset;
gboolean alive;
+ struct metric *cur_metric;
};
static void
struct metric_callback_data *cd = (struct metric_callback_data *)user_data;
struct worker_task *task = cd->task;
gint r = 0;
- gchar outbuf[OUTBUFSIZ];
+ gchar outbuf[OUTBUFSIZ], *description;
struct symbol *s = (struct symbol *)value;
GList *cur;
cd->symbols_offset = rspamd_snprintf (cd->symbols_buf + cd->symbols_offset,
cd->symbols_size - cd->symbols_offset, "%s," CRLF, (gchar *)key);
}
+ description = g_hash_table_lookup (cd->cur_metric->descriptions, key);
if (s->options) {
- if (task->proto_ver >= 12) {
+ if (task->proto_ver >= 13) {
+ if (description != NULL) {
+ r = rspamd_snprintf (outbuf, OUTBUFSIZ, "Symbol: %s(%.2f); %s;", (gchar *)key, s->score, description);
+ }
+ else {
+ r = rspamd_snprintf (outbuf, OUTBUFSIZ, "Symbol: %s(%.2f);;", (gchar *)key, s->score);
+ }
+ }
+ else if (task->proto_ver >= 12) {
r = rspamd_snprintf (outbuf, OUTBUFSIZ, "Symbol: %s(%.2f); ", (gchar *)key, s->score);
}
else {
}
}
else {
- if (task->proto_ver >= 12) {
+ if (task->proto_ver >= 13) {
+ if (description != NULL) {
+ r = rspamd_snprintf (outbuf, OUTBUFSIZ, "Symbol: %s(%.2f); %s" CRLF, (gchar *)key, s->score, description);
+ }
+ else {
+ r = rspamd_snprintf (outbuf, OUTBUFSIZ, "Symbol: %s(%.2f);" CRLF, (gchar *)key, s->score);
+ }
+ }
+ else if (task->proto_ver >= 12) {
r = rspamd_snprintf (outbuf, OUTBUFSIZ, "Symbol: %s(%.2f)" CRLF, (gchar *)key, s->score);
}
else {
static gboolean
show_metric_symbols (struct metric_result *metric_res, struct metric_callback_data *cd)
{
+ cd->cur_metric = metric_res->metric;
g_hash_table_foreach (metric_res->symbols, metric_symbols_callback, cd);
/* Remove last , from log buf */
if (cd->log_buf[cd->log_offset - 1] == ',') {
#define RSPAMC_PROTO_1_0 "1.0"
#define RSPAMC_PROTO_1_1 "1.1"
#define RSPAMC_PROTO_1_2 "1.2"
+#define RSPAMC_PROTO_1_3 "1.3"
/*
* Reply messages