changeset 3967:6fabe878c46d HEAD

Dictionary takes now a username parameter, which is used for private queries. Made dict-sql use "insert .. on duplicate key update" syntax, which unfortunately doesn't work with PostgreSQL yet.
author Timo Sirainen <tss@iki.fi>
date Tue, 31 Jan 2006 08:05:21 +0200
parents 19dcfd289610
children 93449dc37434
files src/dict/Makefile.am src/dict/dict-cache.c src/dict/dict-cache.h src/dict/dict-server.c src/dict/main.c src/lib-dict/dict-client.c src/lib-dict/dict-private.h src/lib-dict/dict-sql.c src/lib-dict/dict.c src/lib-dict/dict.h src/plugins/quota/quota-dict.c src/plugins/quota/quota.c
diffstat 12 files changed, 155 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/src/dict/Makefile.am	Tue Jan 31 08:02:35 2006 +0200
+++ b/src/dict/Makefile.am	Tue Jan 31 08:05:21 2006 +0200
@@ -5,6 +5,7 @@
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
 	-I$(top_srcdir)/src/lib-dict \
+	-I$(top_srcdir)/src/lib-sql \
 	-DPKG_RUNDIR=\""$(rundir)"\"
 
 libs = \
--- a/src/dict/dict-cache.c	Tue Jan 31 08:02:35 2006 +0200
+++ b/src/dict/dict-cache.c	Tue Jan 31 08:05:21 2006 +0200
@@ -31,14 +31,15 @@
 	i_free(cache);
 }
 
-struct dict *dict_cache_get(struct dict_cache *cache, const char *uri)
+struct dict *dict_cache_get(struct dict_cache *cache, const char *uri,
+			    const char *username)
 {
 	struct dict_entry *entry;
 
 	entry = hash_lookup(cache->dicts, uri);
 	if (entry == NULL) {
 		entry = i_new(struct dict_entry, 1);
-		entry->dict = dict_init(uri);
+		entry->dict = dict_init(uri, username);
 		entry->uri = i_strdup(uri);
 		hash_insert(cache->dicts, entry->uri, entry);
 	}
--- a/src/dict/dict-cache.h	Tue Jan 31 08:02:35 2006 +0200
+++ b/src/dict/dict-cache.h	Tue Jan 31 08:05:21 2006 +0200
@@ -4,7 +4,8 @@
 struct dict_cache *dict_cache_init(void);
 void dict_cache_deinit(struct dict_cache *cache);
 
-struct dict *dict_cache_get(struct dict_cache *cache, const char *uri);
+struct dict *dict_cache_get(struct dict_cache *cache, const char *uri,
+			    const char *username);
 void dict_cache_unref(struct dict_cache *cache, const char *uri);
 
 #endif
--- a/src/dict/dict-server.c	Tue Jan 31 08:02:35 2006 +0200
+++ b/src/dict/dict-server.c	Tue Jan 31 08:05:21 2006 +0200
@@ -294,11 +294,12 @@
 	if (*line++ != '\t')
 		return -1;
 
-	conn->username = i_strdup(username);
+	conn->username = i_strdup_until(username, line - 1);
 
 	/* the rest is dict URI */
 	conn->uri = i_strdup(line);
-	conn->dict = dict_cache_get(conn->server->cache, conn->uri);
+	conn->dict = dict_cache_get(conn->server->cache, conn->uri,
+				    conn->username);
 	if (conn->dict == NULL)
 		return -1;
 
--- a/src/dict/main.c	Tue Jan 31 08:02:35 2006 +0200
+++ b/src/dict/main.c	Tue Jan 31 08:05:21 2006 +0200
@@ -6,6 +6,7 @@
 #include "fd-close-on-exec.h"
 #include "restrict-access.h"
 #include "randgen.h"
+#include "sql-api.h"
 #include "dict-sql.h"
 #include "dict-client.h"
 #include "dict-server.h"
@@ -39,6 +40,10 @@
 	   chrooting. */
 	random_init();
 
+	/* Load built-in SQL drivers (if any) */
+	sql_drivers_init();
+	sql_drivers_register_all();
+
 	restrict_access_by_env(FALSE);
 }
 
@@ -76,6 +81,7 @@
 	dict_sql_unregister();
 	dict_client_unregister();
 
+	sql_drivers_deinit();
 	random_deinit();
 	lib_signals_deinit();
 	closelog();
--- a/src/lib-dict/dict-client.c	Tue Jan 31 08:02:35 2006 +0200
+++ b/src/lib-dict/dict-client.c	Tue Jan 31 08:05:21 2006 +0200
@@ -220,13 +220,14 @@
 	}
 }
 
-static struct dict *client_dict_init(struct dict *dict_class, const char *uri)
+static struct dict *client_dict_init(struct dict *dict_class, const char *uri,
+				     const char *username)
 {
 	struct client_dict *dict;
-	const char *path, *dest_uri;
+	const char *dest_uri;
 	pool_t pool;
 
-	/* uri = <username> [" " <path>] ":" <uri> */
+	/* uri = [<path>] ":" <uri> */
 	dest_uri = strchr(uri, ':');
 	if (dest_uri == NULL) {
 		i_error("dict-client: Invalid URI: %s", uri);
@@ -237,17 +238,15 @@
 	dict = p_new(pool, struct client_dict, 1);
 	dict->pool = pool;
 	dict->dict = *dict_class;
+	dict->username = p_strdup(pool, username);
 
 	dict->fd = -1;
 
-	path = strchr(uri, ' ');
-	if (path != NULL && path < dest_uri) {
+	if (*uri != ':') {
 		/* path given */
-		dict->path = p_strdup_until(pool, path + 1, dest_uri);
-		dict->username = p_strdup_until(pool, uri, path);
+		dict->path = p_strdup_until(pool, uri, dest_uri);
 	} else {
 		dict->path = DEFAULT_DICT_SERVER_SOCKET_PATH;
-		dict->username = p_strdup_until(pool, uri, dest_uri);
 	}
 	dict->uri = p_strdup(pool, dest_uri + 1);
 
--- a/src/lib-dict/dict-private.h	Tue Jan 31 08:02:35 2006 +0200
+++ b/src/lib-dict/dict-private.h	Tue Jan 31 08:05:21 2006 +0200
@@ -4,7 +4,8 @@
 #include "dict.h"
 
 struct dict_vfuncs {
-	struct dict *(*init)(struct dict *dict_class, const char *uri);
+	struct dict *(*init)(struct dict *dict_class, const char *uri,
+			     const char *username);
 	void (*deinit)(struct dict *dict);
 
 	int (*lookup)(struct dict *dict, pool_t pool,
--- a/src/lib-dict/dict-sql.c	Tue Jan 31 08:02:35 2006 +0200
+++ b/src/lib-dict/dict-sql.c	Tue Jan 31 08:05:21 2006 +0200
@@ -18,8 +18,8 @@
 	pool_t pool;
 	struct sql_db *db;
 
-	const char *connect_string;
-	const char *table, *select_field, *where_field;
+	const char *connect_string, *username;
+	const char *table, *select_field, *where_field, *username_field;
 };
 
 struct sql_dict_iterate_context {
@@ -67,6 +67,8 @@
 			dict->select_field = p_strdup(dict->pool, value);
 		else if (strcmp(line, "where_field") == 0)
 			dict->where_field = p_strdup(dict->pool, value);
+		else if (strcmp(line, "username_field") == 0)
+			dict->username_field = p_strdup(dict->pool, value);
 
 		t_pop();
 	}
@@ -89,11 +91,16 @@
 		i_error("%s: 'where_field' missing", path);
 		return -1;
 	}
+	if (dict->username_field == NULL) {
+		i_error("%s: 'username_field' missing", path);
+		return -1;
+	}
 
 	return 0;
 }
 
-static struct dict *sql_dict_init(struct dict *dict_class, const char *uri)
+static struct dict *sql_dict_init(struct dict *dict_class, const char *uri,
+				  const char *username)
 {
 	struct sql_dict *dict;
 	pool_t pool;
@@ -102,6 +109,7 @@
 	dict = p_new(pool, struct sql_dict, 1);
 	dict->pool = pool;
 	dict->dict = *dict_class;
+	dict->username = p_strdup(pool, username);
 
 	if (sql_dict_read_config(dict, uri) < 0) {
 		pool_unref(pool);
@@ -122,19 +130,51 @@
 	pool_unref(dict->pool);
 }
 
+static int sql_path_fix(const char **path, bool *private_r)
+{
+	const char *p;
+	size_t len;
+
+	p = strchr(*path, '/');
+	if (p == NULL)
+		return -1;
+	len = p - *path;
+
+	if (strncmp(*path, DICT_PATH_PRIVATE, len) == 0)
+		*private_r = TRUE;
+	else if (strncmp(*path, DICT_PATH_SHARED, len) == 0)
+		*private_r = FALSE;
+	else
+		return -1;
+
+	*path += len + 1;
+	return 0;
+}
+
 static int sql_dict_lookup(struct dict *_dict, pool_t pool,
 			   const char *key, const char **value_r)
 {
 	struct sql_dict *dict = (struct sql_dict *)_dict;
 	struct sql_result *result;
-	const char *query;
+	string_t *query;
 	int ret;
+	bool priv;
+
+	if (sql_path_fix(&key, &priv) < 0) {
+		*value_r = NULL;
+		return -1;
+	}
 
 	t_push();
-	query = t_strdup_printf("SELECT %s FROM %s WHERE %s = '%s'",
-				dict->select_field, dict->table,
-				dict->where_field, str_escape(key));
-	result = sql_query_s(dict->db, query);
+	query = t_str_new(256);
+	str_printfa(query, "SELECT %s FROM %s WHERE %s = '%s'",
+		    dict->select_field, dict->table,
+		    dict->where_field, str_escape(key));
+	if (priv) {
+		str_printfa(query, " AND %s = '%s'",
+			    dict->username_field, str_escape(dict->username));
+	}
+	result = sql_query_s(dict->db, str_c(query));
 	t_pop();
 
 	ret = sql_result_next_row(result);
@@ -155,21 +195,32 @@
 	struct sql_dict *dict = (struct sql_dict *)_dict;
         struct sql_dict_iterate_context *ctx;
 	string_t *query;
+	bool priv;
 
 	ctx = i_new(struct sql_dict_iterate_context, 1);
 	ctx->ctx.dict = _dict;
 
-	t_push();
-	query = t_str_new(256);
-	str_printfa(query, "SELECT %s, %s FROM %s WHERE %s LIKE '%s/%%'",
-		    dict->where_field, dict->select_field,
-		    dict->table, dict->where_field, str_escape(path));
-	if (!recurse) {
-		str_printfa(query, " AND %s NOT LIKE '%s/%%/%%'",
-			    dict->where_field, str_escape(path));
+	if (sql_path_fix(&path, &priv) < 0)
+		ctx->result = NULL;
+	else {
+		t_push();
+		query = t_str_new(256);
+		str_printfa(query, "SELECT %s, %s FROM %s "
+			    "WHERE %s LIKE '%s/%%'",
+			    dict->where_field, dict->select_field,
+			    dict->table, dict->where_field, str_escape(path));
+		if (priv) {
+			str_printfa(query, " AND %s = '%s'",
+				    dict->username_field,
+				    str_escape(dict->username));
+		}
+		if (!recurse) {
+			str_printfa(query, " AND %s NOT LIKE '%s/%%/%%'",
+				    dict->where_field, str_escape(path));
+		}
+		ctx->result = sql_query_s(dict->db, str_c(query));
+		t_pop();
 	}
-	ctx->result = sql_query_s(dict->db, str_c(query));
-	t_pop();
 
 	return &ctx->ctx;
 }
@@ -181,6 +232,9 @@
 		(struct sql_dict_iterate_context *)_ctx;
 	int ret;
 
+	if (ctx->result == NULL)
+		return -1;
+
 	if ((ret = sql_result_next_row(ctx->result)) <= 0)
 		return ret;
 
@@ -241,11 +295,29 @@
 		(struct sql_dict_transaction_context *)_ctx;
 	struct sql_dict *dict = (struct sql_dict *)_ctx->dict;
 	const char *query;
+	bool priv;
+
+	if (sql_path_fix(&key, &priv) < 0)
+		return;
 
 	t_push();
-	query = t_strdup_printf("UPDATE %s SET %s = '%s' WHERE %s = '%s'",
-				dict->table, dict->select_field, str_escape(value),
-				dict->where_field, str_escape(key));
+	if (priv) {
+		query = t_strdup_printf(
+			"INSERT INTO %s (%s, %s, %s) VALUES (%s, %s, %s) "
+			"ON DUPLICATE KEY UPDATE %s = '%s'",
+			dict->table, dict->select_field, dict->where_field,
+			dict->username_field,
+                        str_escape(key), str_escape(value),
+			str_escape(dict->username),
+                        str_escape(key), str_escape(value));
+	} else {
+		query = t_strdup_printf(
+			"INSERT INTO %s (%s, %s) VALUES (%s, %s) "
+			"ON DUPLICATE KEY UPDATE %s = '%s'",
+			dict->table, dict->select_field, dict->where_field,
+                        str_escape(key), str_escape(value),
+                        str_escape(key), str_escape(value));
+	}
 	sql_update(ctx->sql_ctx, query);
 	t_pop();
 }
@@ -257,12 +329,28 @@
 		(struct sql_dict_transaction_context *)_ctx;
 	struct sql_dict *dict = (struct sql_dict *)_ctx->dict;
 	const char *query;
+	bool priv;
+
+	if (sql_path_fix(&key, &priv) < 0)
+		return;
 
 	t_push();
-	query = t_strdup_printf("UPDATE %s SET %s = %s + %lld WHERE %s = '%s'",
-				dict->table, dict->select_field,
-				dict->select_field, diff,
-				dict->where_field, str_escape(key));
+	if (priv) {
+		query = t_strdup_printf(
+			"INSERT INTO %s (%s, %s, %s) VALUES (%s, %lld, %s) "
+			"ON DUPLICATE KEY UPDATE %s = %s + %lld",
+			dict->table, dict->select_field, dict->where_field,
+			dict->username_field,
+                        str_escape(key), diff, str_escape(dict->username),
+                        str_escape(key), str_escape(key), diff);
+	} else {
+		query = t_strdup_printf(
+			"INSERT INTO %s (%s, %s) VALUES (%s, %lld) "
+			"ON DUPLICATE KEY UPDATE %s = %s + %lld",
+			dict->table, dict->select_field, dict->where_field,
+                        str_escape(key), diff,
+                        str_escape(key), str_escape(key), diff);
+	}
 	sql_update(ctx->sql_ctx, query);
 	t_pop();
 }
--- a/src/lib-dict/dict.c	Tue Jan 31 08:02:35 2006 +0200
+++ b/src/lib-dict/dict.c	Tue Jan 31 08:05:21 2006 +0200
@@ -51,10 +51,10 @@
 		array_free(&dict_classes);
 }
 
-struct dict *dict_init(const char *uri)
+struct dict *dict_init(const char *uri, const char *username)
 {
 	struct dict *dict;
-	const char *p;
+	const char *p, *name;
 
 	p = strchr(uri, ':');
 	if (p == NULL) {
@@ -63,12 +63,16 @@
 	}
 
 	t_push();
-	dict = dict_class_lookup(t_strdup_until(uri, p));
+	name = t_strdup_until(uri, p);
+	dict = dict_class_lookup(name);
+	if (dict == NULL) {
+		i_error("Unknown dict module: %s", name);
+		t_pop();
+		return NULL;
+	}
 	t_pop();
-	if (dict == NULL)
-		return NULL;
 
-	return dict->v.init(dict, p+1);
+	return dict->v.init(dict, p+1, username);
 }
 
 void dict_deinit(struct dict **_dict)
--- a/src/lib-dict/dict.h	Tue Jan 31 08:02:35 2006 +0200
+++ b/src/lib-dict/dict.h	Tue Jan 31 08:05:21 2006 +0200
@@ -11,7 +11,7 @@
 
 /* Open dictionary with given URI (type:data).
    If URI is invalid, returns NULL. */
-struct dict *dict_init(const char *uri);
+struct dict *dict_init(const char *uri, const char *username);
 /* Close dictionary. */
 void dict_deinit(struct dict **dict);
 
--- a/src/plugins/quota/quota-dict.c	Tue Jan 31 08:02:35 2006 +0200
+++ b/src/plugins/quota/quota-dict.c	Tue Jan 31 08:05:21 2006 +0200
@@ -37,7 +37,7 @@
 	if (getenv("DEBUG") != NULL)
 		i_info("dict quota uri = %s", data);
 
-	dict = dict_init(data);
+	dict = dict_init(data, getenv("USER"));
 	if (dict == NULL)
 		return NULL;
 
--- a/src/plugins/quota/quota.c	Tue Jan 31 08:02:35 2006 +0200
+++ b/src/plugins/quota/quota.c	Tue Jan 31 08:05:21 2006 +0200
@@ -39,14 +39,16 @@
 		if (strcmp(quota_classes[i]->name, name) == 0)
 			break;
 	}
-	t_pop();
 
-	quota = i == QUOTA_CLASS_COUNT ? NULL :
-		quota_classes[i]->init(data);
-	if (quota != NULL) {
+	if (i == QUOTA_CLASS_COUNT) {
+		i_error("Unknown quota module: %s", name);
+		quota = NULL;
+	} else {
+		quota = quota_classes[i]->init(data);
 		array_create(&quota->quota_module_contexts,
 			     default_pool, sizeof(void *), 5);
 	}
+	t_pop();
 	return quota;
 }