summaryrefslogtreecommitdiffstats
path: root/src/settings.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2009-09-07 20:11:48 +0400
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2009-09-07 20:11:48 +0400
commit9af09b7467a4b9b7b2c9fbf1390b481e71bb07c6 (patch)
tree79c72ede24341ad6f47b63df0521ba3ff6591d65 /src/settings.c
parentd1b63d4cff12936a5ea4380bccadcc77b7c3ed3f (diff)
downloadrspamd-9af09b7467a4b9b7b2c9fbf1390b481e71bb07c6.tar.gz
rspamd-9af09b7467a4b9b7b2c9fbf1390b481e71bb07c6.zip
* Add JSON settings parser
Diffstat (limited to 'src/settings.c')
-rw-r--r--src/settings.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/src/settings.c b/src/settings.c
new file mode 100644
index 000000000..f05f59b45
--- /dev/null
+++ b/src/settings.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2009, Rambler media
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Rambler media ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Rambler BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "cfg_file.h"
+#include "map.h"
+#include "main.h"
+#include "settings.h"
+#include "json/jansson.h"
+
+struct json_buf {
+ GHashTable *table;
+ u_char *buf;
+ u_char *pos;
+ size_t buflen;
+};
+
+static void
+settings_free (gpointer data)
+{
+ struct rspamd_settings *s = data;
+
+ if (s->statfile_alias) {
+ g_free (s->statfile_alias);
+ }
+ if (s->factors) {
+ g_hash_table_destroy (s->factors);
+ }
+ if (s->metric_scores) {
+ g_hash_table_destroy (s->metric_scores);
+ }
+ g_free (s);
+}
+
+
+u_char*
+json_read_cb (memory_pool_t *pool, u_char *chunk, size_t len, struct map_cb_data *data)
+{
+ struct json_buf *jb;
+ size_t free, off;
+
+ if (data->cur_data == NULL) {
+ jb = g_malloc (sizeof (struct json_buf));
+ jb->table = ((struct json_buf *)data->prev_data)->table;
+ jb->buf = NULL;
+ jb->pos = NULL;
+ data->cur_data = jb;
+ }
+ else {
+ jb = data->cur_data;
+ }
+
+ if (jb->buf == NULL) {
+ /* Allocate memory for buffer */
+ jb->pos = jb->buf;
+ jb->buflen = len * 2;
+ jb->buf = g_malloc (jb->buflen);
+ }
+
+ off = jb->pos - jb->buf;
+ free = jb->buflen - off;
+
+ if (free < len) {
+ jb->buflen = MAX (free * 2, len * 2);
+ jb->buf = g_realloc (jb->buf, jb->buflen);
+ jb->pos = jb->buf + off;
+ }
+
+ memcpy (chunk, jb->pos, len);
+ jb->pos += len;
+
+ /* Say not to copy any part of this buffer */
+ return NULL;
+}
+
+void
+json_fin_cb (memory_pool_t *pool, struct map_cb_data *data)
+{
+ struct json_buf *jb;
+ int nelts, i;
+ json_t *js, *cur_elt, *cur_nm, *it_val;
+ json_error_t je;
+ struct rspamd_settings *cur_settings;
+ char *cur_name;
+ void *json_it;
+ double *score;
+
+ if (data->prev_data) {
+ jb = data->prev_data;
+ /* Clean prev data */
+ if (jb->table) {
+ g_hash_table_remove_all (jb->table);
+ }
+ if (jb->buf) {
+ g_free (jb->buf);
+ }
+ g_free (jb->buf);
+ }
+
+ /* Now parse json */
+ /* NULL terminate current buf */
+ *jb->pos = '\0';
+
+ js = json_loads (jb->buf, &je);
+ if (!js) {
+ msg_err ("json_fin_cb: cannot load json data: parse error %s, on line %d", je.text, je.line);
+ return;
+ }
+
+ if (!json_is_array (js)) {
+ json_decref (js);
+ msg_err ("json_fin_cb: loaded json is not an array");
+ return;
+ }
+
+ nelts = json_array_size (js);
+ for (i = 0; i < nelts; i ++) {
+ cur_settings = g_malloc (sizeof (struct rspamd_settings));
+ cur_settings->metric_scores = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ cur_settings->factors = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ cur_settings->statfile_alias = NULL;
+ cur_settings->want_spam = FALSE;
+
+ cur_elt = json_array_get (js, i);
+ if (!cur_elt || !json_is_object (cur_elt)) {
+ json_decref (js);
+ msg_err ("json_fin_cb: loaded json is not an object");
+ return;
+ }
+ cur_nm = json_object_get (cur_elt, "name");
+ if (cur_nm == NULL || !json_is_string (cur_nm)) {
+ json_decref (js);
+ msg_err ("json_fin_cb: name is not a string or not exists");
+ return;
+ }
+ cur_name = g_strdup (json_string_value (cur_nm));
+ /* Now check other settings */
+ /* Statfile */
+ cur_nm = json_object_get (cur_elt, "statfile");
+ if (cur_nm != NULL && json_is_string (cur_nm)) {
+ cur_settings->statfile_alias = g_strdup (json_string_value (cur_nm));
+ }
+ /* Factors object */
+ cur_nm = json_object_get (cur_elt, "factors");
+ if (cur_nm != NULL && json_is_object (cur_nm)) {
+ json_it = json_object_iter (cur_nm);
+ while (json_it) {
+ it_val = json_object_iter_value (json_it);
+ if (it_val && json_is_string (it_val)) {
+ g_hash_table_insert (cur_settings->factors, g_strdup (json_object_iter_key (json_it)),
+ g_strdup (json_string_value (it_val)));
+ }
+ json_it = json_object_iter_next(cur_nm, json_it);
+ }
+ }
+ /* Metrics object */
+ cur_nm = json_object_get (cur_elt, "metrics");
+ if (cur_nm != NULL && json_is_object (cur_nm)) {
+ json_it = json_object_iter (cur_nm);
+ while (json_it) {
+ it_val = json_object_iter_value (json_it);
+ if (it_val && json_is_number (it_val)) {
+ score = g_malloc (sizeof (double));
+ *score = json_number_value (it_val);
+ g_hash_table_insert (cur_settings->factors, g_strdup (json_object_iter_key (json_it)),
+ score);
+ }
+ json_it = json_object_iter_next(cur_nm, json_it);
+ }
+ }
+ /* Want spam */
+ cur_nm = json_object_get (cur_elt, "want_spam");
+ if (cur_nm != NULL) {
+ if (json_is_true (cur_nm)) {
+ cur_settings->want_spam = TRUE;
+ }
+ }
+ g_hash_table_insert (((struct json_buf*)data->cur_data)->table, cur_name, cur_settings);
+ }
+ json_decref (js);
+}
+
+gboolean
+read_settings (const char *path, struct config_file *cfg, GHashTable *table)
+{
+ struct json_buf *jb = g_malloc (sizeof (struct json_buf));
+
+ jb->table = table;
+ jb->buf = NULL;
+
+ if (!add_map (path, json_read_cb, json_fin_cb, (void **)&jb)) {
+ msg_err ("read_settings: cannot add map %s", path);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+init_settings (struct config_file *cfg)
+{
+ cfg->domain_settings = g_hash_table_new_full (rspamd_strcase_hash, rspamd_strcase_equal, g_free, settings_free);
+ cfg->user_settings = g_hash_table_new_full (rspamd_strcase_hash, rspamd_strcase_equal, g_free, settings_free);
+}
+
+/*
+ * vi:ts=4
+ */