dovecot-1.2: dict sql: Added configuration for mapping dict path...

dovecot at dovecot.org dovecot at dovecot.org
Wed Aug 27 12:10:26 EEST 2008


details:   http://hg.dovecot.org/dovecot-1.2/rev/2d3e942a4cde
changeset: 8113:2d3e942a4cde
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Aug 27 12:10:21 2008 +0300
description:
dict sql: Added configuration for mapping dict paths to SQL fields.

diffstat:

7 files changed, 590 insertions(+), 261 deletions(-)
doc/dovecot-dict-sql-example.conf |   39 ++
src/dict/Makefile.am              |    1 
src/lib-dict/Makefile.am          |    7 
src/lib-dict/dict-sql-settings.c  |  215 ++++++++++++++
src/lib-dict/dict-sql-settings.h  |   24 +
src/lib-dict/dict-sql.c           |  551 +++++++++++++++++++------------------
src/lib-dict/dict.c               |   14 

diffs (truncated from 1100 to 300 lines):

diff -r d630b13ccd60 -r 2d3e942a4cde doc/dovecot-dict-sql-example.conf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/dovecot-dict-sql-example.conf	Wed Aug 27 12:10:21 2008 +0300
@@ -0,0 +1,39 @@
+#connect = host=localhost dbname=mails user=testuser password=pass
+
+# CREATE TABLE quota (
+#   username varchar(100) not null,
+#   bytes bigint not null default 0,
+#   messages integer not null default 0,
+#   primary key (username)
+# );
+
+map {
+  pattern = priv/quota/storage
+  table = quota
+  username_field = username
+  value_field = bytes
+}
+map {
+  pattern = priv/quota/messages
+  table = quota
+  username_field = username
+  value_field = messages
+}
+
+# CREATE TABLE expires (
+#   username varchar(100) not null,
+#   mailbox varchar(255) not null,
+#   expire_stamp integer not null,
+#   primary key (username, mailbox)
+# );
+
+map {
+  pattern = shared/expire/$user/$mailbox
+  table = expires
+  value_field = expire_stamp
+
+  fields {
+    username = $user
+    mailbox = $mailbox
+  }
+}
diff -r d630b13ccd60 -r 2d3e942a4cde src/dict/Makefile.am
--- a/src/dict/Makefile.am	Wed Aug 27 12:08:14 2008 +0300
+++ b/src/dict/Makefile.am	Wed Aug 27 12:10:21 2008 +0300
@@ -15,6 +15,7 @@ libs = \
 	../lib-dict/libdict_backend.a \
 	../lib-dict/libdict.a \
 	../lib-sql/libsql.a \
+	../lib-settings/libsettings.a \
 	../lib/liblib.a
 
 dict_LDADD = \
diff -r d630b13ccd60 -r 2d3e942a4cde src/lib-dict/Makefile.am
--- a/src/lib-dict/Makefile.am	Wed Aug 27 12:08:14 2008 +0300
+++ b/src/lib-dict/Makefile.am	Wed Aug 27 12:10:21 2008 +0300
@@ -5,6 +5,7 @@ AM_CPPFLAGS = \
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
 	-I$(top_srcdir)/src/lib-sql \
+	-I$(top_srcdir)/src/lib-settings \
 	-DPKG_RUNDIR=\""$(rundir)"\" \
 	$(SQL_CFLAGS)
 
@@ -14,7 +15,8 @@ base_sources = \
 
 backend_sources = \
 	dict-db.c \
-	dict-sql.c
+	dict-sql.c \
+	dict-sql-settings.c
 
 libdict_a_SOURCES = \
 	$(base_sources)
@@ -27,7 +29,8 @@ headers = \
 	dict.h \
 	dict-client.h \
 	dict-private.h \
-	dict-sql.h
+	dict-sql.h \
+	dict-sql-settings.h
 
 if INSTALL_HEADERS
   pkginc_libdir=$(pkgincludedir)/src/lib-dict
diff -r d630b13ccd60 -r 2d3e942a4cde src/lib-dict/dict-sql-settings.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-dict/dict-sql-settings.c	Wed Aug 27 12:10:21 2008 +0300
@@ -0,0 +1,215 @@
+/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "settings.h"
+#include "dict-sql-settings.h"
+
+#include <ctype.h>
+
+enum section_type {
+	SECTION_ROOT = 0,
+	SECTION_MAP,
+	SECTION_FIELDS
+};
+
+struct dict_sql_map_field {
+	const char *sql_field, *variable;
+};
+
+struct setting_parser_ctx {
+	pool_t pool;
+	struct dict_sql_settings *set;
+	enum section_type type;
+
+	struct dict_sql_map cur_map;
+	ARRAY_DEFINE(cur_fields, struct dict_sql_map_field);
+};
+
+#define DEF_STR(name) DEF_STRUCT_STR(name, dict_sql_map)
+
+static struct setting_def dict_sql_map_setting_defs[] = {
+	DEF_STR(pattern),
+	DEF_STR(table),
+	DEF_STR(username_field),
+	DEF_STR(value_field),
+
+	{ 0, NULL, 0 }
+};
+
+static const char *pattern_read_name(const char **pattern)
+{
+	const char *p = *pattern, *name;
+
+	if (*p == '{') {
+		/* ${name} */
+		name = ++p;
+		p = strchr(p, '}');
+		if (p == NULL) {
+			/* error, but allow anyway */
+			*pattern += strlen(*pattern);
+			return "";
+		}
+		*pattern = p + 1;
+	} else {
+		/* $name - ends at the first non-alnum_ character */
+		name = p;
+		for (; *p != '\0'; p++) {
+			if (!i_isalnum(*p) && *p != '_')
+				break;
+		}
+		*pattern = p;
+	}
+	name = t_strdup_until(name, p);
+	return name;
+}
+
+static const char *dict_sql_fields_map(struct setting_parser_ctx *ctx)
+{
+	struct dict_sql_map_field *fields;
+	string_t *pattern;
+	const char *p, *name;
+	unsigned int i, count;
+
+	p_array_init(&ctx->cur_map.sql_fields, ctx->pool, count);
+
+	/* go through the variables in the pattern, replace them with plain
+	   '$' character and add its sql field */
+	pattern = t_str_new(strlen(ctx->cur_map.pattern) + 1);
+	fields = array_get_modifiable(&ctx->cur_fields, &count);
+	for (p = ctx->cur_map.pattern; *p != '\0';) {
+		if (*p != '$') {
+			str_append_c(pattern, *p);
+			p++;
+			continue;
+		}
+		p++;
+		str_append_c(pattern, '$');
+
+		name = pattern_read_name(&p);
+		for (i = 0; i < count; i++) {
+			if (fields[i].variable != NULL &&
+			    strcmp(fields[i].variable, name) == 0)
+				break;
+		}
+		if (i == count) {
+			return t_strconcat("Missing SQL field for variable: ",
+					   name, NULL);
+		}
+
+		/* mark this field as used */
+		fields[i].variable = NULL;
+		array_append(&ctx->cur_map.sql_fields,
+			     &fields[i].sql_field, 1);
+	}
+
+	/* make sure there aren't any unused fields */
+	for (i = 0; i < count; i++) {
+		if (fields[i].variable != NULL) {
+			return t_strconcat("Unused variable: ",
+					   fields[i].variable, NULL);
+		}
+	}
+
+	if (ctx->set->max_field_count < count)
+		ctx->set->max_field_count = count;
+	ctx->cur_map.pattern = p_strdup(ctx->pool, str_c(pattern));
+	return NULL;
+}
+
+static const char *dict_sql_map_finish(struct setting_parser_ctx *ctx)
+{
+	if (!array_is_created(&ctx->cur_map.sql_fields)) {
+		/* no fields besides value. allocate the array anyway. */
+		p_array_init(&ctx->cur_map.sql_fields, ctx->pool, 1);
+		if (strchr(ctx->cur_map.pattern, '$') != NULL)
+			return "Missing fields for pattern variables";
+	}
+	array_append(&ctx->set->maps, &ctx->cur_map, 1);
+	memset(&ctx->cur_map, 0, sizeof(ctx->cur_map));
+	return NULL;
+}
+
+static const char *
+parse_setting(const char *key, const char *value,
+	      struct setting_parser_ctx *ctx)
+{
+	struct dict_sql_map_field *field;
+
+	switch (ctx->type) {
+	case SECTION_ROOT:
+		if (strcmp(key, "connect") == 0) {
+			ctx->set->connect = p_strdup(ctx->pool, value);
+			return NULL;
+		}
+		break;
+	case SECTION_MAP:
+		return parse_setting_from_defs(ctx->pool,
+					       dict_sql_map_setting_defs,
+					       &ctx->cur_map, key, value);
+	case SECTION_FIELDS:
+		if (*value != '$') {
+			return t_strconcat("Value is missing '$' for field: ",
+					   key, NULL);
+		}
+		field = array_append_space(&ctx->cur_fields);
+		field->sql_field = p_strdup(ctx->pool, key);
+		field->variable = p_strdup(ctx->pool, value + 1);
+		return NULL;
+	}
+	return t_strconcat("Unknown setting: ", key, NULL);
+}
+
+static bool
+parse_section(const char *type, const char *name ATTR_UNUSED,
+	      struct setting_parser_ctx *ctx, const char **error_r)
+{
+	switch (ctx->type) {
+	case SECTION_ROOT:
+		if (type == NULL)
+			return FALSE;
+		if (strcmp(type, "map") == 0) {
+			array_clear(&ctx->cur_fields);
+			ctx->type = SECTION_MAP;
+			return TRUE;
+		}
+		break;
+	case SECTION_MAP:
+		if (type == NULL) {
+			ctx->type = SECTION_ROOT;
+			*error_r = dict_sql_map_finish(ctx);
+			return FALSE;
+		}
+		if (strcmp(type, "fields") == 0) {
+			ctx->type = SECTION_FIELDS;
+			return TRUE;
+		}
+		break;
+	case SECTION_FIELDS:
+		if (type == NULL) {
+			ctx->type = SECTION_MAP;
+			*error_r = dict_sql_fields_map(ctx);
+			return FALSE;
+		}
+		break;
+	}
+	*error_r = t_strconcat("Unknown section: ", type, NULL);
+	return FALSE;
+}
+
+struct dict_sql_settings *dict_sql_settings_read(pool_t pool, const char *path)
+{
+	struct setting_parser_ctx ctx;
+
+	memset(&ctx, 0, sizeof(ctx));
+	ctx.pool = pool;
+	ctx.set = p_new(pool, struct dict_sql_settings, 1);
+	t_array_init(&ctx.cur_fields, 16);
+	p_array_init(&ctx.set->maps, pool, 8);
+
+	if (!settings_read(path, NULL, parse_setting, parse_section, &ctx))


More information about the dovecot-cvs mailing list