changeset 14918:8eae4e205c82

Hash table API is now (mostly) type safe.
author Timo Sirainen <tss@iki.fi>
date Sun, 19 Aug 2012 13:55:34 +0300
parents 1ce71b5bc94a
children ed0fd7c1e8ff
files src/anvil/connect-limit.c src/anvil/penalty.c src/auth/auth-cache.c src/auth/auth-request-handler.c src/auth/db-checkpassword.c src/auth/db-ldap.c src/auth/db-passwd-file.c src/auth/db-passwd-file.h src/auth/mech-otp-skey-common.c src/config/config-request.c src/director/director-test.c src/director/user-directory.c src/doveadm/doveadm-director.c src/doveadm/doveadm-kick.c src/doveadm/doveadm-log.c src/doveadm/doveadm-mail-server.c src/doveadm/doveadm-stats.c src/doveadm/doveadm-who.c src/doveadm/doveadm-who.h src/doveadm/dsync/dsync-brain-mailbox.c src/doveadm/dsync/dsync-brain-private.h src/doveadm/dsync/dsync-brain.c src/doveadm/dsync/dsync-mailbox-export.c src/doveadm/dsync/dsync-mailbox-import.c src/doveadm/dsync/dsync-mailbox-tree-fill.c src/doveadm/dsync/dsync-mailbox-tree-private.h src/doveadm/dsync/dsync-mailbox-tree-sync.c src/doveadm/dsync/dsync-mailbox-tree.c src/doveadm/dsync/dsync-transaction-log-scan.c src/doveadm/dsync/dsync-transaction-log-scan.h src/indexer/indexer-queue.c src/lib-auth/auth-server-connection.c src/lib-auth/auth-server-connection.h src/lib-dict/dict-file.c src/lib-index/mail-cache-fields.c src/lib-index/mail-cache-private.h src/lib-index/mail-cache.c src/lib-index/mail-index-private.h src/lib-index/mail-index.c src/lib-lda/duplicate.c src/lib-master/master-auth.c src/lib-master/master-login-auth.c src/lib-master/master-service-settings-cache.c src/lib-settings/settings-parser.c src/lib-sql/sql-db-cache.c src/lib-storage/index/dbox-multi/mdbox-purge.c src/lib-storage/index/dbox-multi/mdbox-storage-rebuild.c src/lib-storage/index/index-thread-finish.c src/lib-storage/index/maildir/maildir-filename.c src/lib-storage/index/maildir/maildir-filename.h src/lib-storage/index/maildir/maildir-keywords.c src/lib-storage/index/maildir/maildir-uidlist.c src/lib-storage/list/mailbox-list-index-sync.c src/lib-storage/list/mailbox-list-index.c src/lib-storage/list/mailbox-list-index.h src/lib-storage/mailbox-guid-cache.c src/lib-storage/mailbox-list-private.h src/lib-storage/mailbox-list.c src/lib/child-wait.c src/lib/guid.c src/lib/guid.h src/lib/hash.c src/lib/hash.h src/lib/lib.h src/lib/macros.h src/log/log-connection.c src/login-common/login-proxy-state.c src/login-common/ssl-proxy-openssl.c src/master/service-monitor.c src/master/service-process.c src/master/service.c src/master/service.h src/plugins/acl/acl-cache.c src/plugins/expire/doveadm-expire.c src/plugins/fts-lucene/fts-backend-lucene.c src/plugins/fts-lucene/lucene-wrapper.cc src/plugins/fts-lucene/lucene-wrapper.h src/plugins/fts-solr/fts-backend-solr-old.c src/plugins/fts-solr/fts-backend-solr.c src/plugins/fts-solr/solr-connection.c src/plugins/fts/fts-expunge-log.c src/pop3/pop3-commands.c src/replication/aggregator/replicator-connection.c src/replication/replicator/replicator-queue.c src/stats/mail-domain.c src/stats/mail-ip.c src/stats/mail-session.c src/stats/mail-user.c
diffstat 88 files changed, 730 insertions(+), 656 deletions(-) [+]
line wrap: on
line diff
--- a/src/anvil/connect-limit.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/anvil/connect-limit.c	Sun Aug 19 13:55:34 2012 +0300
@@ -16,22 +16,18 @@
 
 struct connect_limit {
 	/* ident => refcount */
-	struct hash_table *ident_hash;
+	HASH_TABLE(char *, unsigned int) ident_hash;
 	/* struct ident_pid => struct ident_pid */
-	struct hash_table *ident_pid_hash;
+	HASH_TABLE(struct ident_pid *, struct ident_pid *) ident_pid_hash;
 };
 
-static unsigned int ident_pid_hash(const void *p)
+static unsigned int ident_pid_hash(const struct ident_pid *i)
 {
-	const struct ident_pid *i = p;
-
 	return str_hash(i->ident) ^ i->pid;
 }
 
-static int ident_pid_cmp(const void *p1, const void *p2)
+static int ident_pid_cmp(const struct ident_pid *i1, const struct ident_pid *i2)
 {
-	const struct ident_pid *i1 = p1, *i2 = p2;
-
 	if (i1->pid < i2->pid)
 		return -1;
 	else if (i1->pid > i2->pid)
@@ -45,12 +41,9 @@
 	struct connect_limit *limit;
 
 	limit = i_new(struct connect_limit, 1);
-	limit->ident_hash =
-		hash_table_create(default_pool, 0,
-				  str_hash, (hash_cmp_callback_t *)strcmp);
-	limit->ident_pid_hash =
-		hash_table_create(default_pool, 0,
-				  ident_pid_hash, ident_pid_cmp);
+	hash_table_create(&limit->ident_hash, default_pool, 0, str_hash, strcmp);
+	hash_table_create(&limit->ident_pid_hash, default_pool, 0,
+			  ident_pid_hash, ident_pid_cmp);
 	return limit;
 }
 
@@ -67,27 +60,24 @@
 unsigned int connect_limit_lookup(struct connect_limit *limit,
 				  const char *ident)
 {
-	void *value;
-
-	value = hash_table_lookup(limit->ident_hash, ident);
-	if (value == NULL)
-		return 0;
-
-	return POINTER_CAST_TO(value, unsigned int);
+	return hash_table_lookup(limit->ident_hash, ident);
 }
 
 void connect_limit_connect(struct connect_limit *limit, pid_t pid,
 			   const char *ident)
 {
 	struct ident_pid *i, lookup_i;
-	void *key, *value;
+	void *orig_key, *orig_value;
+	char *key;
+	unsigned int value;
 
-	if (!hash_table_lookup_full(limit->ident_hash, ident, &key, &value)) {
+	if (!hash_table_lookup_full(limit->ident_hash, ident,
+				    &orig_key, &orig_value)) {
 		key = i_strdup(ident);
-		value = POINTER_CAST(1);
-		hash_table_insert(limit->ident_hash, key, value);
+		hash_table_insert(limit->ident_hash, key, 1U);
 	} else {
-		value = POINTER_CAST(POINTER_CAST_TO(value, unsigned int) + 1);
+		key = orig_key;
+		value = POINTER_CAST_TO(orig_value, unsigned int) + 1;
 		hash_table_update(limit->ident_hash, key, value);
 	}
 
@@ -108,16 +98,18 @@
 static void
 connect_limit_ident_hash_unref(struct connect_limit *limit, const char *ident)
 {
-	void *key, *value;
+	void *orig_key, *orig_value;
+	char *key;
 	unsigned int new_refcount;
 
-	if (!hash_table_lookup_full(limit->ident_hash, ident, &key, &value))
+	if (!hash_table_lookup_full(limit->ident_hash, ident,
+				    &orig_key, &orig_value))
 		i_panic("connect limit hash tables are inconsistent");
 
-	new_refcount = POINTER_CAST_TO(value, unsigned int) - 1;
+	key = orig_key;
+	new_refcount = POINTER_CAST_TO(orig_value, unsigned int) - 1;
 	if (new_refcount > 0) {
-		value = POINTER_CAST(new_refcount);
-		hash_table_update(limit->ident_hash, key, value);
+		hash_table_update(limit->ident_hash, key, new_refcount);
 	} else {
 		hash_table_remove(limit->ident_hash, key);
 		i_free(key);
@@ -150,14 +142,12 @@
 void connect_limit_disconnect_pid(struct connect_limit *limit, pid_t pid)
 {
 	struct hash_iterate_context *iter;
-	struct ident_pid *i;
-	void *key, *value;
+	struct ident_pid *i, *value;
 
 	/* this should happen rarely (or never), so this slow implementation
 	   should be fine. */
 	iter = hash_table_iterate_init(limit->ident_pid_hash);
-	while (hash_table_iterate(iter, &key, &value)) {
-		i = key;
+	while (hash_table_iterate_t(iter, limit->ident_pid_hash, &i, &value)) {
 		if (i->pid == pid) {
 			hash_table_remove(limit->ident_pid_hash, i);
 			for (; i->refcount > 0; i->refcount--)
@@ -171,13 +161,11 @@
 void connect_limit_dump(struct connect_limit *limit, struct ostream *output)
 {
 	struct hash_iterate_context *iter;
-	void *key, *value;
+	struct ident_pid *i, *value;
 	string_t *str = t_str_new(256);
 
 	iter = hash_table_iterate_init(limit->ident_pid_hash);
-	while (hash_table_iterate(iter, &key, &value)) {
-		struct ident_pid *i = key;
-
+	while (hash_table_iterate_t(iter, limit->ident_pid_hash, &i, &value)) {
 		str_truncate(str, 0);
 		str_tabescape_write(str, i->ident);
 		str_printfa(str, "\t%ld\t%u\n", (long)i->pid, i->refcount);
--- a/src/anvil/penalty.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/anvil/penalty.c	Sun Aug 19 13:55:34 2012 +0300
@@ -38,7 +38,7 @@
 
 struct penalty {
 	/* ident => penalty_rec */
-	struct hash_table *hash;
+	HASH_TABLE(char *, struct penalty_rec *) hash;
 	struct penalty_rec *oldest, *newest;
 
 	unsigned int expire_secs;
@@ -50,9 +50,7 @@
 	struct penalty *penalty;
 
 	penalty = i_new(struct penalty, 1);
-	penalty->hash =
-		hash_table_create(default_pool, 0,
-				  str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&penalty->hash, default_pool, 0, str_hash, strcmp);
 	penalty->expire_secs = PENALTY_DEFAULT_EXPIRE_SECS;
 	return penalty;
 }
--- a/src/auth/auth-cache.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/auth/auth-cache.c	Sun Aug 19 13:55:34 2012 +0300
@@ -12,7 +12,7 @@
 #include <time.h>
 
 struct auth_cache {
-	struct hash_table *hash;
+	HASH_TABLE(char *, struct auth_cache_node *) hash;
 	struct auth_cache_node *head, *tail;
 
 	size_t size_left;
@@ -178,10 +178,12 @@
 static void
 auth_cache_node_destroy(struct auth_cache *cache, struct auth_cache_node *node)
 {
+	char *key = node->data;
+
 	auth_cache_node_unlink(cache, node);
 
 	cache->size_left += node->alloc_size;
-	hash_table_remove(cache->hash, node->data);
+	hash_table_remove(cache->hash, key);
 	i_free(node);
 }
 
@@ -221,8 +223,7 @@
 	struct auth_cache *cache;
 
 	cache = i_new(struct auth_cache, 1);
-	cache->hash = hash_table_create(default_pool, 0, str_hash,
-					(hash_cmp_callback_t *)strcmp);
+	hash_table_create(&cache->hash, default_pool, 0, str_hash, strcmp);
 	cache->size_left = max_size;
 	cache->ttl_secs = ttl_secs;
 	cache->neg_ttl_secs = neg_ttl_secs;
@@ -386,7 +387,7 @@
 {
         struct auth_cache_node *node;
 	size_t data_size, alloc_size, key_len, value_len = strlen(value);
-	char *current_username;
+	char *hash_key, *current_username;
 
 	if (*value == '\0' && cache->neg_ttl_secs == 0) {
 		/* we're not caching negative entries */
@@ -430,7 +431,8 @@
 	auth_cache_node_link_head(cache, node);
 
 	cache->size_left -= alloc_size;
-	hash_table_insert(cache->hash, node->data, node);
+	hash_key = node->data;
+	hash_table_insert(cache->hash, hash_key, node);
 
 	if (*value != '\0') {
 		cache->pos_entries++;
--- a/src/auth/auth-request-handler.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/auth/auth-request-handler.c	Sun Aug 19 13:55:34 2012 +0300
@@ -21,7 +21,7 @@
 struct auth_request_handler {
 	int refcount;
 	pool_t pool;
-	struct hash_table *requests;
+	HASH_TABLE(unsigned int, struct auth_request *) requests;
 
         unsigned int connect_uid, client_pid;
 
@@ -52,7 +52,7 @@
 	handler = p_new(pool, struct auth_request_handler, 1);
 	handler->refcount = 1;
 	handler->pool = pool;
-	handler->requests = hash_table_create(pool, 0, NULL, NULL);
+	hash_table_create_direct(&handler->requests, pool, 0);
 	handler->callback = callback;
 	handler->context = context;
 	handler->master_callback = master_callback;
@@ -72,6 +72,7 @@
 
 	iter = hash_table_iterate_init(handler->requests);
 	while (hash_table_iterate(iter, &key, &value)) {
+		unsigned int id = POINTER_CAST_TO(key, unsigned int);
 		struct auth_request *auth_request = value;
 
 		switch (auth_request->state) {
@@ -79,7 +80,7 @@
 		case AUTH_REQUEST_STATE_MECH_CONTINUE:
 		case AUTH_REQUEST_STATE_FINISHED:
 			auth_request_unref(&auth_request);
-			hash_table_remove(handler->requests, key);
+			hash_table_remove(handler->requests, id);
 			break;
 		case AUTH_REQUEST_STATE_PASSDB:
 		case AUTH_REQUEST_STATE_USERDB:
@@ -146,7 +147,7 @@
 	   request, so make sure we don't get back here. */
 	timeout_remove(&request->to_abort);
 
-	hash_table_remove(handler->requests, POINTER_CAST(request->id));
+	hash_table_remove(handler->requests, request->id);
 	auth_request_unref(&request);
 }
 
@@ -513,7 +514,7 @@
 		auth_request_unref(&request);
 		return FALSE;
 	}
-	if (hash_table_lookup(handler->requests, POINTER_CAST(id)) != NULL) {
+	if (hash_table_lookup(handler->requests, id) != NULL) {
 		i_error("BUG: Authentication client %u "
 			"sent a duplicate ID %u", handler->client_pid, id);
 		auth_request_unref(&request);
@@ -523,7 +524,7 @@
 
 	request->to_abort = timeout_add(MASTER_AUTH_SERVER_TIMEOUT_SECS * 1000,
 					auth_request_timeout, request);
-	hash_table_insert(handler->requests, POINTER_CAST(id), request);
+	hash_table_insert(handler->requests, id, request);
 
 	if (request->set->ssl_require_client_cert &&
 	    !request->valid_client_cert) {
@@ -578,7 +579,7 @@
 	}
 	data++;
 
-	request = hash_table_lookup(handler->requests, POINTER_CAST(id));
+	request = hash_table_lookup(handler->requests, id);
 	if (request == NULL) {
 		struct auth_stream_reply *reply;
 
@@ -685,7 +686,7 @@
 
 	reply = auth_stream_reply_init(pool_datastack_create());
 
-	request = hash_table_lookup(handler->requests, POINTER_CAST(client_id));
+	request = hash_table_lookup(handler->requests, client_id);
 	if (request == NULL) {
 		i_error("Master request %u.%u not found",
 			handler->client_pid, client_id);
@@ -730,7 +731,7 @@
 {
 	struct auth_request *request;
 
-	request = hash_table_lookup(handler->requests, POINTER_CAST(client_id));
+	request = hash_table_lookup(handler->requests, client_id);
 	if (request != NULL)
 		auth_request_handler_remove(handler, request);
 }
--- a/src/auth/db-checkpassword.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/auth/db-checkpassword.c	Sun Aug 19 13:55:34 2012 +0300
@@ -45,7 +45,7 @@
 struct db_checkpassword {
 	char *checkpassword_path, *checkpassword_reply_path;
 
-	struct hash_table *clients;
+	HASH_TABLE(pid_t, struct chkpw_auth_request *) clients;
 	struct child_wait *child_wait;
 };
 
@@ -89,8 +89,7 @@
 	*_request = NULL;
 
 	if (!request->exited) {
-		hash_table_remove(request->db->clients,
-				  POINTER_CAST(request->pid));
+		hash_table_remove(request->db->clients, request->pid);
 		child_wait_remove_pid(request->db->child_wait, request->pid);
 	}
 	checkpassword_request_close(request);
@@ -416,11 +415,11 @@
 			    struct db_checkpassword *db)
 {
 	struct chkpw_auth_request *request = 
-		hash_table_lookup(db->clients, POINTER_CAST(status->pid));
+		hash_table_lookup(db->clients, status->pid);
 
 	i_assert(request != NULL);
 
-	hash_table_remove(db->clients, POINTER_CAST(status->pid));
+	hash_table_remove(db->clients, status->pid);
 	request->exited = TRUE;
 
 	if (WIFSIGNALED(status->status)) {
@@ -532,7 +531,7 @@
 		io_add(fd_out[1], IO_WRITE, checkpassword_child_output,
 		       chkpw_auth_request);
 
-	hash_table_insert(db->clients, POINTER_CAST(pid), chkpw_auth_request);
+	hash_table_insert(db->clients, pid, chkpw_auth_request);
 	child_wait_add_pid(db->child_wait, pid);
 }
 
@@ -545,8 +544,7 @@
 	db = i_new(struct db_checkpassword, 1);
 	db->checkpassword_path = i_strdup(checkpassword_path);
 	db->checkpassword_reply_path = i_strdup(checkpassword_reply_path);
-	db->clients = hash_table_create(default_pool, 0,
-					NULL, NULL);
+	hash_table_create_direct(&db->clients, default_pool, 0);
 	db->child_wait =
 		child_wait_new_with_pid((pid_t)-1, sigchld_handler, db);
 	return db;
--- a/src/auth/db-ldap.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/auth/db-ldap.c	Sun Aug 19 13:55:34 2012 +0300
@@ -61,8 +61,8 @@
 	const ARRAY_TYPE(ldap_field) *attr_map;
 	unsigned int attr_idx;
 
-	/* ldap_attr_name => struct db_ldap_value */
-	struct hash_table *ldap_attrs;
+	/* attribute name => value */
+	HASH_TABLE(char *, struct db_ldap_value *) ldap_attrs;
 	struct var_expand_table *var_table;
 
 	const char *val_1_arr[2];
@@ -1195,9 +1195,7 @@
 	ctx->pool = pool;
 	ctx->auth_request = auth_request;
 	ctx->attr_map = attr_map;
-	ctx->ldap_attrs =
-		hash_table_create(pool, 0, strcase_hash,
-				  (hash_cmp_callback_t *)strcasecmp);
+	hash_table_create(&ctx->ldap_attrs, pool, 0, strcase_hash, strcasecmp);
 	if (auth_request->set->debug)
 		ctx->debug = t_str_new(256);
 
@@ -1312,7 +1310,8 @@
 db_ldap_result_finish_debug(struct db_ldap_result_iterate_context *ctx)
 {
 	struct hash_iterate_context *iter;
-	void *key, *value;
+	char *name;
+	struct db_ldap_value *value;
 	unsigned int orig_len, unused_count = 0;
 
 	orig_len = str_len(ctx->debug);
@@ -1325,11 +1324,8 @@
 	str_append(ctx->debug, "; ");
 
 	iter = hash_table_iterate_init(ctx->ldap_attrs);
-	while (hash_table_iterate(iter, &key, &value)) {
-		const char *name = key;
-		struct db_ldap_value *ldap_value = value;
-
-		if (!ldap_value->used) {
+	while (hash_table_iterate_t(iter, ctx->ldap_attrs, &name, &value)) {
+		if (!value->used) {
 			str_printfa(ctx->debug, "%s,", name);
 			unused_count++;
 		}
--- a/src/auth/db-passwd-file.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/auth/db-passwd-file.c	Sun Aug 19 13:55:34 2012 +0300
@@ -156,7 +156,7 @@
 	pw->path = i_strdup(expanded_path);
 	pw->fd = -1;
 
-	if (db->files != NULL)
+	if (hash_table_is_created(db->files))
 		hash_table_insert(db->files, pw->path, pw);
 	return pw;
 }
@@ -194,8 +194,7 @@
 	pw->size = st.st_size;
 
 	pw->pool = pool_alloconly_create(MEMPOOL_GROWING"passwd_file", 10240);
-	pw->users = hash_table_create(pw->pool, 100,
-				      str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&pw->users, pw->pool, 0, str_hash, strcmp);
 
 	start_time = time(NULL);
 	input = i_stream_create_fd(pw->fd, 4096, FALSE);
@@ -238,7 +237,7 @@
 		pw->fd = -1;
 	}
 
-	if (pw->users != NULL)
+	if (hash_table_is_created(pw->users))
 		hash_table_destroy(&pw->users);
 	if (pw->pool != NULL)
 		pool_unref(&pw->pool);
@@ -246,7 +245,7 @@
 
 static void passwd_file_free(struct passwd_file *pw)
 {
-	if (pw->db->files != NULL)
+	if (hash_table_is_created(pw->db->files))
 		hash_table_remove(pw->db->files, pw->path);
 
 	passwd_file_close(pw);
@@ -344,8 +343,8 @@
 
 	db->path = i_strdup(path);
 	if (db->vars) {
-		db->files = hash_table_create(default_pool, 100, str_hash,
-					      (hash_cmp_callback_t *)strcmp);
+		hash_table_create(&db->files, default_pool, 0,
+				  str_hash, strcmp);
 	} else {
 		db->default_file = passwd_file_new(db, path);
 	}
@@ -368,7 +367,8 @@
         struct db_passwd_file *db = *_db;
         struct db_passwd_file **p;
 	struct hash_iterate_context *iter;
-	void *key, *value;
+	char *path;
+	struct passwd_file *file;
 
 	*_db = NULL;
 	i_assert(db->refcount >= 0);
@@ -386,11 +386,8 @@
 		passwd_file_free(db->default_file);
 	else {
 		iter = hash_table_iterate_init(db->files);
-		while (hash_table_iterate(iter, &key, &value)) {
-			struct passwd_file *file = value;
-
+		while (hash_table_iterate_t(iter, db->files, &path, &file))
 			passwd_file_free(file);
-		}
 		hash_table_iterate_deinit(&iter);
 		hash_table_destroy(&db->files);
 	}
--- a/src/auth/db-passwd-file.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/auth/db-passwd-file.h	Sun Aug 19 13:55:34 2012 +0300
@@ -1,6 +1,8 @@
 #ifndef DB_PASSWD_FILE_H
 #define DB_PASSWD_FILE_H
 
+#include "hash.h"
+
 #define PASSWD_FILE_DEFAULT_USERNAME_FORMAT "%u"
 #define PASSWD_FILE_DEFAULT_SCHEME "CRYPT"
 
@@ -23,7 +25,7 @@
 	off_t size;
 	int fd;
 
-	struct hash_table *users;
+	HASH_TABLE(char *, struct passwd_user *) users;
 };
 
 struct db_passwd_file {
@@ -32,7 +34,7 @@
 	int refcount;
 
 	char *path;
-	struct hash_table *files;
+	HASH_TABLE(char *, struct passwd_file *) files;
         struct passwd_file *default_file;
 
 	unsigned int vars:1;
--- a/src/auth/mech-otp-skey-common.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/auth/mech-otp-skey-common.c	Sun Aug 19 13:55:34 2012 +0300
@@ -13,15 +13,15 @@
 #include "otp.h"
 #include "mech-otp-skey-common.h"
 
-static struct hash_table *otp_lock_table;
+static HASH_TABLE(char *, struct auth_request *) otp_lock_table;
 
 void otp_lock_init(void)
 {
-	if (otp_lock_table != NULL)
+	if (hash_table_is_created(otp_lock_table))
 		return;
 
-	otp_lock_table = hash_table_create(default_pool, 128, strcase_hash,
-					   (hash_cmp_callback_t *)strcasecmp);
+	hash_table_create(&otp_lock_table, default_pool, 128,
+			  strcase_hash, strcasecmp);
 }
 
 int otp_try_lock(struct auth_request *auth_request)
@@ -30,7 +30,6 @@
 		return FALSE;
 
 	hash_table_insert(otp_lock_table, auth_request->user, auth_request);
-
 	return TRUE;
 }
 
--- a/src/config/config-request.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/config/config-request.c	Sun Aug 19 13:55:34 2012 +0300
@@ -15,7 +15,7 @@
 	pool_t pool;
 	string_t *value;
 	string_t *prefix;
-	struct hash_table *keys;
+	HASH_TABLE(char *, char *) keys;
 	enum config_dump_scope scope;
 
 	config_request_callback_t *callback;
@@ -361,8 +361,7 @@
 	ctx->scope = scope;
 	ctx->value = t_str_new(256);
 	ctx->prefix = t_str_new(64);
-	ctx->keys = hash_table_create(ctx->pool, 0, str_hash,
-				      (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&ctx->keys, ctx->pool, 0, str_hash, strcmp);
 	return ctx;
 }
 
--- a/src/director/director-test.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/director/director-test.c	Sun Aug 19 13:55:34 2012 +0300
@@ -89,8 +89,8 @@
 
 static struct imap_client *imap_clients;
 static struct director_connection *director_connections;
-static struct hash_table *users;
-static struct hash_table *hosts;
+static HASH_TABLE(char *, struct user *) users;
+static HASH_TABLE(struct ip_addr *, struct host *) hosts;
 static ARRAY_DEFINE(hosts_array, struct host *);
 static struct admin_connection *admin;
 static struct timeout *to_disconnect;
@@ -532,11 +532,8 @@
 
 static void main_init(const char *admin_path)
 {
-	users = hash_table_create(default_pool, 0, str_hash,
-				  (hash_cmp_callback_t *)strcmp);
-	hosts = hash_table_create(default_pool, 0,
-				  (hash_callback_t *)net_ip_hash,
-				  (hash_cmp_callback_t *)net_ip_cmp);
+	hash_table_create(&users, default_pool, 0, str_hash, strcmp);
+	hash_table_create(&hosts, default_pool, 0, net_ip_hash, net_ip_cmp);
 	i_array_init(&hosts_array, 256);
 
 	admin = admin_connect(admin_path);
--- a/src/director/user-directory.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/director/user-directory.c	Sun Aug 19 13:55:34 2012 +0300
@@ -20,8 +20,8 @@
 };
 
 struct user_directory {
-	/* const char *username => struct user* */
-	struct hash_table *hash;
+	/* username_hash => user */
+	HASH_TABLE(unsigned int, struct user *) hash;
 	/* sorted by time */
 	struct user *head, *tail;
 	struct user *prev_insert_pos;
@@ -55,7 +55,7 @@
 
 	user_move_iters(dir, user);
 
-	hash_table_remove(dir->hash, POINTER_CAST(user->username_hash));
+	hash_table_remove(dir->hash, user->username_hash);
 	DLLIST2_REMOVE(&dir->head, &dir->tail, user);
 	i_free(user);
 }
@@ -80,7 +80,7 @@
 {
 	user_directory_drop_expired(dir);
 
-	return hash_table_lookup(dir->hash, POINTER_CAST(username_hash));
+	return hash_table_lookup(dir->hash, username_hash);
 }
 
 static void
@@ -162,7 +162,7 @@
 	}
 
 	dir->prev_insert_pos = user;
-	hash_table_insert(dir->hash, POINTER_CAST(user->username_hash), user);
+	hash_table_insert(dir->hash, user->username_hash, user);
 	return user;
 }
 
@@ -225,7 +225,7 @@
 		I_MAX(dir->user_near_expiring_secs, 1);
 
 	dir->username_hash_fmt = i_strdup(username_hash_fmt);
-	dir->hash = hash_table_create(default_pool, 0, NULL, NULL);
+	hash_table_create_direct(&dir->hash, default_pool, 0);
 	i_array_init(&dir->iters, 8);
 	return dir;
 }
--- a/src/doveadm/doveadm-director.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/doveadm-director.c	Sun Aug 19 13:55:34 2012 +0300
@@ -29,6 +29,8 @@
 	const char *name;
 };
 
+HASH_TABLE_DEFINE_TYPE(user_list, unsigned int, struct user_list *);
+
 extern struct doveadm_cmd doveadm_cmd_director[];
 
 static void director_cmd_help(doveadm_command_t *cmd) ATTR_NORETURN;
@@ -190,7 +192,8 @@
 }
 
 static void
-user_list_add(const char *username, pool_t pool, struct hash_table *users)
+user_list_add(const char *username, pool_t pool,
+	      HASH_TABLE_TYPE(user_list) users)
 {
 	struct user_list *user, *old_user;
 	unsigned int user_hash;
@@ -199,15 +202,15 @@
 	user->name = p_strdup(pool, username);
 	user_hash = director_username_hash(username);
 
-	old_user = hash_table_lookup(users, POINTER_CAST(user_hash));
+	old_user = hash_table_lookup(users, user_hash);
 	if (old_user != NULL)
 		user->next = old_user;
-	hash_table_insert(users, POINTER_CAST(user_hash), user);
+	hash_table_insert(users, user_hash, user);
 }
 
 static void ATTR_NULL(1)
 userdb_get_user_list(const char *auth_socket_path, pool_t pool,
-		     struct hash_table *users)
+		     HASH_TABLE_TYPE(user_list) users)
 {
 	struct auth_master_user_list_ctx *ctx;
 	struct auth_master_connection *conn;
@@ -230,7 +233,8 @@
 }
 
 static void
-user_file_get_user_list(const char *path, pool_t pool, struct hash_table *users)
+user_file_get_user_list(const char *path, pool_t pool,
+			HASH_TABLE_TYPE(user_list) users)
 {
 	struct istream *input;
 	const char *username;
@@ -282,7 +286,7 @@
 	const char *line, *const *args;
 	struct ip_addr *ips, user_ip;
 	pool_t pool;
-	struct hash_table *users;
+	HASH_TABLE_TYPE(user_list) users;
 	struct user_list *user;
 	unsigned int ips_count, user_hash, expires;
 
@@ -295,7 +299,7 @@
 		director_get_host(argv[optind], &ips, &ips_count);
 
 	pool = pool_alloconly_create("director map users", 1024*128);
-	users = hash_table_create(pool, 0, NULL, NULL);
+	hash_table_create_direct(&users, pool, 0);
 	if (ctx->users_path == NULL)
 		userdb_get_user_list(NULL, pool, users);
 	else
@@ -325,8 +329,7 @@
 				doveadm_exit_code = EX_PROTOCOL;
 			} else if (ips_count == 0 ||
 				 ip_find(ips, ips_count, &user_ip)) {
-				user = hash_table_lookup(users,
-						POINTER_CAST(user_hash));
+				user = hash_table_lookup(users, user_hash);
 				if (user == NULL) {
 					doveadm_print("<unknown>");
 					doveadm_print(args[2]);
--- a/src/doveadm/doveadm-kick.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/doveadm-kick.c	Sun Aug 19 13:55:34 2012 +0300
@@ -27,7 +27,7 @@
 
 struct kick_context {
 	struct who_context who;
-	struct hash_table *pids;
+	HASH_TABLE(pid_t, struct kick_pid *) pids;
 	bool force_kick;
 	ARRAY_DEFINE(kicked_users, const char *);
 };
@@ -42,12 +42,12 @@
 
 	memset(&new_user, 0, sizeof(new_user));
 
-	k_pid = hash_table_lookup(ctx->pids, POINTER_CAST(line->pid));
+	k_pid = hash_table_lookup(ctx->pids, line->pid);
 	if (k_pid == NULL) {
 		k_pid = p_new(ctx->who.pool, struct kick_pid, 1);
 		k_pid->pid = line->pid;
 		p_array_init(&k_pid->users, ctx->who.pool, 5);
-		hash_table_insert(ctx->pids, POINTER_CAST(line->pid), k_pid);
+		hash_table_insert(ctx->pids, line->pid, k_pid);
 	}
 
 	array_foreach_modifiable(&k_pid->users, user) {
@@ -129,16 +129,16 @@
 static void kick_users(struct kick_context *ctx)
 {
 	bool show_enforce_warning = FALSE;
+	struct hash_iterate_context *iter;
 	void *key, *value;
-	struct kick_pid *k_pid;
-	struct hash_iterate_context *iter;
 	const struct kick_user *user;
 
 	p_array_init(&ctx->kicked_users, ctx->who.pool, 10);
 
 	iter = hash_table_iterate_init(ctx->pids);
 	while (hash_table_iterate(iter, &key, &value)) {
-		k_pid = value;
+		struct kick_pid *k_pid = value;
+
 		if (kick_pid_want_kicked(ctx, k_pid, &show_enforce_warning))
 			k_pid->kick = TRUE;
 	}
@@ -151,7 +151,8 @@
 
 	iter = hash_table_iterate_init(ctx->pids);
 	while (hash_table_iterate(iter, &key, &value)) {
-		k_pid = value;
+		struct kick_pid *k_pid = value;
+
 		if (!k_pid->kick)
 			continue;
 
@@ -179,7 +180,7 @@
 	ctx.who.anvil_path = t_strconcat(doveadm_settings->base_dir, "/anvil", NULL);
 	ctx.force_kick = FALSE;
 	ctx.who.pool = pool_alloconly_create("kick pids", 10240);
-	ctx.pids = hash_table_create(ctx.who.pool, 0, NULL, NULL);
+	hash_table_create_direct(&ctx.pids, ctx.who.pool, 0);
 
 	while ((c = getopt(argc, argv, "a:f")) > 0) {
 		switch (c) {
--- a/src/doveadm/doveadm-log.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/doveadm-log.c	Sun Aug 19 13:55:34 2012 +0300
@@ -62,7 +62,7 @@
 
 struct log_find_context {
 	pool_t pool;
-	struct hash_table *files;
+	HASH_TABLE(char *, struct log_find_file *) files;
 };
 
 static void cmd_log_find_add(struct log_find_context *ctx,
@@ -222,8 +222,7 @@
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.pool = pool_alloconly_create("log file", 1024*32);
-	ctx.files = hash_table_create(ctx.pool, 0,
-				      str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&ctx.files, ctx.pool, 0, str_hash, strcmp);
 
 	/* first get the paths that we know are used */
 	set = master_service_settings_get(master_service);
--- a/src/doveadm/doveadm-mail-server.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/doveadm-mail-server.c	Sun Aug 19 13:55:34 2012 +0300
@@ -22,7 +22,7 @@
 #define DOVEADM_MAIL_SERVER_FAILED() \
 	(internal_failure || master_service_is_killed(master_service))
 
-static struct hash_table *servers;
+static HASH_TABLE(char *, struct doveadm_server *) servers;
 static pool_t server_pool;
 static struct doveadm_mail_cmd_context *cmd_ctx;
 static bool internal_failure = FALSE;
@@ -36,10 +36,9 @@
 	struct doveadm_server *server;
 	char *dup_name;
 
-	if (servers == NULL) {
+	if (!hash_table_is_created(servers)) {
 		server_pool = pool_alloconly_create("doveadm servers", 1024*16);
-		servers = hash_table_create(server_pool, 0, str_hash,
-					    (hash_cmp_callback_t *)strcmp);
+		hash_table_create(&servers, server_pool, 0, str_hash, strcmp);
 	}
 	server = hash_table_lookup(servers, name);
 	if (server == NULL) {
@@ -277,12 +276,11 @@
 static void doveadm_servers_destroy_all_connections(void)
 {
 	struct hash_iterate_context *iter;
-	void *key, *value;
+	char *key;
+	struct doveadm_server *server;
 
 	iter = hash_table_iterate_init(servers);
-	while (hash_table_iterate(iter, &key, &value)) {
-		struct doveadm_server *server = value;
-
+	while (hash_table_iterate_t(iter, servers, &key, &server)) {
 		while (array_count(&server->connections) > 0) {
 			struct server_connection *const *connp, *conn;
 
@@ -298,7 +296,7 @@
 {
 	struct doveadm_server *server;
 
-	if (servers == NULL) {
+	if (!hash_table_is_created(servers)) {
 		cmd_ctx = NULL;
 		return;
 	}
--- a/src/doveadm/doveadm-stats.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/doveadm-stats.c	Sun Aug 19 13:55:34 2012 +0300
@@ -37,7 +37,7 @@
 
 	pool_t prev_pool, cur_pool;
 	/* id => struct top_line. */
-	struct hash_table *sessions;
+	HASH_TABLE(char *, struct top_line *) sessions;
 	ARRAY_DEFINE(lines, struct top_line *);
 	int (*lines_sort)(struct top_line *const *, struct top_line *const *);
 
@@ -203,14 +203,13 @@
 static void stats_drop_stale(struct top_context *ctx)
 {
 	struct hash_iterate_context *iter;
-	void *key, *value;
+	char *id;
+	struct top_line *line;
 
 	iter = hash_table_iterate_init(ctx->sessions);
-	while (hash_table_iterate(iter, &key, &value)) {
-		struct top_line *line = value;
-
+	while (hash_table_iterate_t(iter, ctx->sessions, &id, &line)) {
 		if (line->flip != ctx->flip)
-			hash_table_remove(ctx->sessions, key);
+			hash_table_remove(ctx->sessions, id);
 	}
 	hash_table_iterate_deinit(&iter);
 }
@@ -477,9 +476,7 @@
 	ctx.prev_pool = pool_alloconly_create("stats top", 1024*16);
 	ctx.cur_pool = pool_alloconly_create("stats top", 1024*16);
 	i_array_init(&ctx.lines, 128);
-	ctx.sessions =
-		hash_table_create(default_pool, 0,
-				  str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&ctx.sessions, default_pool, 0, str_hash, strcmp);
 	net_set_nonblock(ctx.fd, FALSE);
 
 	ctx.input = i_stream_create_fd(ctx.fd, (size_t)-1, TRUE);
--- a/src/doveadm/doveadm-who.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/doveadm-who.c	Sun Aug 19 13:55:34 2012 +0300
@@ -23,17 +23,14 @@
 	unsigned int connection_count;
 };
 
-static unsigned int who_user_hash(const void *p)
+static unsigned int who_user_hash(const struct who_user *user)
 {
-	const struct who_user *user = p;
-
 	return str_hash(user->username) + str_hash(user->service);
 }
 
-static int who_user_cmp(const void *p1, const void *p2)
+static int who_user_cmp(const struct who_user *user1,
+			const struct who_user *user2)
 {
-	const struct who_user *user1 = p1, *user2 = p2;
-
 	if (strcmp(user1->username, user2->username) != 0)
 		return 1;
 	if (strcmp(user1->service, user2->service) != 0)
@@ -274,8 +271,7 @@
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.anvil_path = t_strconcat(doveadm_settings->base_dir, "/anvil", NULL);
 	ctx.pool = pool_alloconly_create("who users", 10240);
-	ctx.users = hash_table_create(ctx.pool, 0,
-				      who_user_hash, who_user_cmp);
+	hash_table_create(&ctx.users, ctx.pool, 0, who_user_hash, who_user_cmp);
 
 	while ((c = getopt(argc, argv, "1a:")) > 0) {
 		switch (c) {
--- a/src/doveadm/doveadm-who.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/doveadm-who.h	Sun Aug 19 13:55:34 2012 +0300
@@ -21,7 +21,7 @@
 	struct who_filter filter;
 
 	pool_t pool;
-	struct hash_table *users; /* username -> who_user */
+	HASH_TABLE(struct who_user *, struct who_user *) users;
 };
 
 typedef void who_callback_t(struct who_context *ctx,
--- a/src/doveadm/dsync/dsync-brain-mailbox.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/dsync/dsync-brain-mailbox.c	Sun Aug 19 13:55:34 2012 +0300
@@ -193,13 +193,14 @@
 void dsync_brain_sync_mailbox_deinit(struct dsync_brain *brain)
 {
 	struct dsync_mailbox_state *state;
+	uint8_t *guid_p;
 
 	i_assert(brain->box != NULL);
 
 	state = p_new(brain->pool, struct dsync_mailbox_state, 1);
 	*state = brain->mailbox_state;
-	hash_table_insert(brain->remote_mailbox_states,
-			  state->mailbox_guid, state);
+	guid_p = state->mailbox_guid;
+	hash_table_insert(brain->remote_mailbox_states, guid_p, state);
 
 	if (brain->box_exporter != NULL) {
 		const char *error;
--- a/src/doveadm/dsync/dsync-brain-private.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/dsync/dsync-brain-private.h	Sun Aug 19 13:55:34 2012 +0300
@@ -1,6 +1,7 @@
 #ifndef DSYNC_BRAIN_PRIVATE_H
 #define DSYNC_BRAIN_PRIVATE_H
 
+#include "hash.h"
 #include "dsync-brain.h"
 #include "dsync-mailbox.h"
 #include "dsync-mailbox-state.h"
@@ -63,7 +64,7 @@
 	struct dsync_mailbox_state mailbox_state;
 	/* GUID -> dsync_mailbox_state for mailboxes that have already
 	   been synced */
-	struct hash_table *remote_mailbox_states;
+	HASH_TABLE(uint8_t *, struct dsync_mailbox_state *) remote_mailbox_states;
 
 	unsigned int master_brain:1;
 	unsigned int guid_requests:1;
--- a/src/doveadm/dsync/dsync-brain.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/dsync/dsync-brain.c	Sun Aug 19 13:55:34 2012 +0300
@@ -47,8 +47,8 @@
 	brain->user = user;
 	brain->slave = slave;
 	brain->sync_type = DSYNC_BRAIN_SYNC_TYPE_UNKNOWN;
-	brain->remote_mailbox_states =
-		hash_table_create(brain->pool, 0, guid_128_hash, guid_128_cmp);
+	hash_table_create(&brain->remote_mailbox_states,
+			  brain->pool, 0, guid_128_hash, guid_128_cmp);
 	p_array_init(&brain->mailbox_states, pool, 64);
 	return brain;
 }
--- a/src/doveadm/dsync/dsync-mailbox-export.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/dsync/dsync-mailbox-export.c	Sun Aug 19 13:55:34 2012 +0300
@@ -27,7 +27,7 @@
 	struct mail_search_context *search_ctx;
 
 	/* GUID => instances */
-	struct hash_table *export_guids;
+	HASH_TABLE(char *, struct dsync_mail_guid_instances *) export_guids;
 	ARRAY_TYPE(seq_range) requested_uids;
 	unsigned int requested_uid_search_idx;
 
@@ -36,7 +36,7 @@
 	unsigned int expunged_guid_idx;
 
 	/* UID => struct dsync_mail_change */
-	struct hash_table *changes;
+	HASH_TABLE(uint32_t, struct dsync_mail_change *) changes;
 	/* changes sorted by UID */
 	ARRAY_DEFINE(sorted_changes, struct dsync_mail_change *);
 	unsigned int change_idx;
@@ -156,8 +156,7 @@
 	const char *guid, *hdr_hash;
 	int ret;
 
-	change = hash_table_lookup(exporter->changes,
-				   POINTER_CAST(mail->uid));
+	change = hash_table_lookup(exporter->changes, mail->uid);
 	i_assert(change != NULL);
 	i_assert(change->type == DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE);
 
@@ -188,11 +187,11 @@
 {
 	struct dsync_mail_change *change;
 
-	change = hash_table_lookup(exporter->changes, POINTER_CAST(uid));
+	change = hash_table_lookup(exporter->changes, uid);
 	if (change == NULL) {
 		change = p_new(exporter->pool, struct dsync_mail_change, 1);
 		change->uid = uid;
-		hash_table_insert(exporter->changes, POINTER_CAST(uid), change);
+		hash_table_insert(exporter->changes, uid, change);
 	} else {
 		/* move flag changes into a save. this happens only when
 		   last_common_uid isn't known */
@@ -294,7 +293,7 @@
 
 		if (change->type == DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE &&
 		    change->uid > exporter->last_common_uid)
-			hash_table_remove(exporter->changes, key);
+			hash_table_remove(exporter->changes, change->uid);
 	}
 	hash_table_iterate_deinit(&iter);
 }
@@ -381,7 +380,7 @@
 dsync_mailbox_export_log_scan(struct dsync_mailbox_exporter *exporter,
 			      struct dsync_transaction_log_scan *log_scan)
 {
-	struct hash_table *log_changes;
+	HASH_TABLE_TYPE(dsync_uid_mail_change) log_changes;
 	struct hash_iterate_context *iter;
 	void *key, *value;
 	struct dsync_mail_change *dup_change;
@@ -391,16 +390,15 @@
 		exporter->return_all_mails = TRUE;
 
 	/* clone the hash table, since we're changing it. */
-	exporter->changes =
-		hash_table_create(exporter->pool,
-				  hash_table_count(log_changes), NULL, NULL);
+	hash_table_create_direct(&exporter->changes, exporter->pool,
+				 hash_table_count(log_changes));
 	iter = hash_table_iterate_init(log_changes);
 	while (hash_table_iterate(iter, &key, &value)) {
 		const struct dsync_mail_change *change = value;
 
 		dup_change = p_new(exporter->pool, struct dsync_mail_change, 1);
 		*dup_change = *change;
-		hash_table_insert(exporter->changes, key, dup_change);
+		hash_table_insert(exporter->changes, change->uid, dup_change);
 		if (exporter->highest_changed_uid < change->uid)
 			exporter->highest_changed_uid = change->uid;
 	}
@@ -430,9 +428,7 @@
 	exporter->mails_have_guids =
 		(flags & DSYNC_MAILBOX_EXPORTER_FLAG_MAILS_HAVE_GUIDS) != 0;
 	p_array_init(&exporter->requested_uids, pool, 16);
-	exporter->export_guids =
-		hash_table_create(pool, 0,
-				  str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&exporter->export_guids, pool, 0, str_hash, strcmp);
 	p_array_init(&exporter->expunged_seqs, pool, 16);
 	p_array_init(&exporter->expunged_guids, pool, 16);
 
--- a/src/doveadm/dsync/dsync-mailbox-import.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/dsync/dsync-mailbox-import.c	Sun Aug 19 13:55:34 2012 +0300
@@ -33,6 +33,9 @@
 	unsigned int copy_failed:1;
 };
 
+HASH_TABLE_DEFINE_TYPE(guid_new_mail, const char *, struct importer_new_mail *);
+HASH_TABLE_DEFINE_TYPE(uid_new_mail, uint32_t, struct importer_new_mail *);
+
 struct dsync_mailbox_importer {
 	pool_t pool;
 	struct mailbox *box;
@@ -50,15 +53,15 @@
 	const char *cur_guid;
 
 	/* UID => struct dsync_mail_change */
-	const struct hash_table *local_changes;
+	HASH_TABLE_TYPE(dsync_uid_mail_change) local_changes;
 
 	ARRAY_TYPE(seq_range) maybe_expunge_uids;
 	ARRAY_DEFINE(maybe_saves, struct dsync_mail_change *);
 
 	/* GUID => struct importer_new_mail */
-	struct hash_table *import_guids;
+	HASH_TABLE_TYPE(guid_new_mail) import_guids;
 	/* UID => struct importer_new_mail */
-	struct hash_table *import_uids;
+	HASH_TABLE_TYPE(uid_new_mail) import_uids;
 
 	ARRAY_DEFINE(newmails, struct importer_new_mail *);
 	ARRAY_TYPE(uint32_t) wanted_uids;
@@ -134,11 +137,8 @@
 	importer->remote_first_recent_uid = remote_first_recent_uid;
 	importer->remote_highest_modseq = remote_highest_modseq;
 
-	importer->import_guids =
-		hash_table_create(pool, 0,
-				  str_hash, (hash_cmp_callback_t *)strcmp);
-	importer->import_uids =
-		hash_table_create(pool, 0, NULL, NULL);
+	hash_table_create(&importer->import_guids, pool, 0, str_hash, strcmp);
+	hash_table_create_direct(&importer->import_uids, pool, 0);
 	i_array_init(&importer->maybe_expunge_uids, 16);
 	i_array_init(&importer->maybe_saves, 128);
 	i_array_init(&importer->newmails, 128);
@@ -269,7 +269,7 @@
 		if (first_mail == NULL) {
 			/* first mail for this GUID */
 			hash_table_insert(importer->import_guids,
-					  (void *)newmail->guid, newmail);
+					  newmail->guid, newmail);
 			importer_mail_request(importer, newmail);
 			return;
 		}
@@ -279,11 +279,11 @@
 			return;
 		}
 		first_mail = hash_table_lookup(importer->import_uids,
-					POINTER_CAST(newmail->uid));
+					       newmail->uid);
 		if (first_mail == NULL) {
 			/* first mail for this UID */
 			hash_table_insert(importer->import_uids,
-					  POINTER_CAST(newmail->uid), newmail);
+					  newmail->uid, newmail);
 			importer_mail_request(importer, newmail);
 			return;
 		}
@@ -656,8 +656,7 @@
 		mail = importer->mail;
 	}
 
-	local_change = hash_table_lookup(importer->local_changes,
-					 POINTER_CAST(change->uid));
+	local_change = hash_table_lookup(importer->local_changes, change->uid);
 	if (local_change == NULL) {
 		local_add = local_remove = 0;
 	} else {
@@ -876,8 +875,7 @@
 	   transaction log and check if the GUIDs match. The GUID in
 	   log is a 128bit GUID, so we may need to convert the remote's
 	   GUID string to 128bit GUID first. */
-	local_change = hash_table_lookup(importer->local_changes,
-					 POINTER_CAST(change->uid));
+	local_change = hash_table_lookup(importer->local_changes, change->uid);
 	if (local_change == NULL || local_change->guid == NULL)
 		return;
 	if (guid_128_from_string(local_change->guid, guid_128) < 0)
@@ -1210,7 +1208,7 @@
 
 	newmail = *mail->guid != '\0' ?
 		hash_table_lookup(importer->import_guids, mail->guid) :
-		hash_table_lookup(importer->import_uids, POINTER_CAST(mail->uid));
+		hash_table_lookup(importer->import_uids, mail->uid);
 	if (newmail == NULL) {
 		if (importer->want_mail_requests) {
 			i_error("%s: Remote sent unwanted message body for "
@@ -1222,10 +1220,8 @@
 	}
 	if (*mail->guid != '\0')
 		hash_table_remove(importer->import_guids, mail->guid);
-	else {
-		hash_table_remove(importer->import_uids,
-				  POINTER_CAST(mail->uid));
-	}
+	else
+		hash_table_remove(importer->import_uids, mail->uid);
 
 	/* save all instances of the message */
 	allmails = newmail;
@@ -1386,7 +1382,28 @@
 }
 
 static unsigned int
-dsync_mailbox_import_count_missing_imports(struct hash_table *imports)
+dsync_mailbox_import_count_missing_guid_imports(HASH_TABLE_TYPE(guid_new_mail) imports)
+{
+	struct hash_iterate_context *iter;
+	const char *key;
+	struct importer_new_mail *mail;
+	unsigned int msgs_left = 0;
+
+	iter = hash_table_iterate_init(imports);
+	while (hash_table_iterate_t(iter, imports, &key, &mail)) {
+		for (; mail != NULL; mail = mail->next) {
+			if (!mail->uid_in_local) {
+				msgs_left++;
+				break;
+			}
+		}
+	}
+	hash_table_iterate_deinit(&iter);
+	return msgs_left;
+}
+
+static unsigned int
+dsync_mailbox_import_count_missing_uid_imports(HASH_TABLE_TYPE(uid_new_mail) imports)
 {
 	struct hash_iterate_context *iter;
 	void *key, *value;
@@ -1423,8 +1440,8 @@
 		dsync_mailbox_import_assign_new_uids(importer);
 
 	msgs_left =
-		dsync_mailbox_import_count_missing_imports(importer->import_guids) +
-		dsync_mailbox_import_count_missing_imports(importer->import_uids);
+		dsync_mailbox_import_count_missing_guid_imports(importer->import_guids) +
+		dsync_mailbox_import_count_missing_uid_imports(importer->import_uids);
 	if (!importer->failed && msgs_left > 0) {
 		i_error("%s: Remote didn't send %u expected message bodies",
 			mailbox_get_vname(importer->box), msgs_left);
--- a/src/doveadm/dsync/dsync-mailbox-tree-fill.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/dsync/dsync-mailbox-tree-fill.c	Sun Aug 19 13:55:34 2012 +0300
@@ -83,7 +83,7 @@
 {
 	struct dsync_mailbox_node *node;
 
-	if (tree->name128_hash == NULL)
+	if (!hash_table_is_created(tree->name128_hash))
 		dsync_mailbox_tree_build_name128_hash(tree);
 
 	node = hash_table_lookup(tree->name128_hash, sha128);
@@ -99,6 +99,7 @@
 	struct mailbox_log *log;
 	struct mailbox_log_iter *iter;
 	const struct mailbox_log_record *rec;
+	const uint8_t *guid_p;
 	time_t timestamp;
 
 	log = mailbox_list_get_changelog(ns->list);
@@ -112,8 +113,8 @@
 
 		switch (rec->type) {
 		case MAILBOX_LOG_RECORD_DELETE_MAILBOX:
-			if (hash_table_lookup(tree->guid_hash,
-					      rec->mailbox_guid) != NULL) {
+			guid_p = rec->mailbox_guid;
+			if (hash_table_lookup(tree->guid_hash, guid_p) != NULL) {
 				/* mailbox still exists. maybe it was restored
 				   from backup or something. */
 				break;
--- a/src/doveadm/dsync/dsync-mailbox-tree-private.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/dsync/dsync-mailbox-tree-private.h	Sun Aug 19 13:55:34 2012 +0300
@@ -13,9 +13,9 @@
 	ARRAY_DEFINE(deletes, struct dsync_mailbox_delete);
 
 	/* guid_128_t => struct dsync_mailbox_node */
-	struct hash_table *name128_hash;
-	struct hash_table *name128_remotesep_hash;
-	struct hash_table *guid_hash;
+	HASH_TABLE(uint8_t *, struct dsync_mailbox_node *) name128_hash;
+	HASH_TABLE(uint8_t *, struct dsync_mailbox_node *) name128_remotesep_hash;
+	HASH_TABLE(uint8_t *, struct dsync_mailbox_node *) guid_hash;
 };
 
 void dsync_mailbox_tree_build_name128_hash(struct dsync_mailbox_tree *tree);
--- a/src/doveadm/dsync/dsync-mailbox-tree-sync.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/dsync/dsync-mailbox-tree-sync.c	Sun Aug 19 13:55:34 2012 +0300
@@ -106,11 +106,12 @@
 	struct dsync_mailbox_node *other_node;
 	struct dsync_mailbox_tree_sync_change *change;
 	const char *name;
+	const uint8_t *guid_p;
 
 	other_tree = tree == ctx->local_tree ?
 		ctx->remote_tree : ctx->local_tree;
-	other_node = hash_table_lookup(other_tree->guid_hash,
-				       node->mailbox_guid);
+	guid_p = node->mailbox_guid;
+	other_node = hash_table_lookup(other_tree->guid_hash, guid_p);
 	if (other_node == NULL) {
 		/* doesn't exist / already deleted */
 	} else if (other_tree == ctx->local_tree) {
@@ -165,10 +166,11 @@
 	       struct dsync_mailbox_node *other_node)
 {
 	struct dsync_mailbox_node *n1, *n2;
+	const uint8_t *guid_p;
 
 	if (!guid_128_is_empty(other_node->mailbox_guid)) {
-		return hash_table_lookup(tree->guid_hash,
-					 other_node->mailbox_guid);
+		guid_p = other_node->mailbox_guid;
+		return hash_table_lookup(tree->guid_hash, guid_p);
 	}
 	/* if we can find a node that has all of the same mailboxes as children,
 	   return it. */
@@ -178,7 +180,8 @@
 	}
 	if (n1 == NULL)
 		return NULL;
-	n2 = hash_table_lookup(tree->guid_hash, n1->mailbox_guid);
+	guid_p = n1->mailbox_guid;
+	n2 = hash_table_lookup(tree->guid_hash, guid_p);
 	if (n2 == NULL)
 		return NULL;
 
@@ -400,6 +403,7 @@
 	struct dsync_mailbox_tree_iter *iter;
 	struct dsync_mailbox_node *node, *other_node;
 	const char *name;
+	const uint8_t *guid_p;
 
 	other_tree = tree == ctx->local_tree ?
 		ctx->remote_tree : ctx->local_tree;
@@ -411,8 +415,8 @@
 
 		i_assert(node->existence == DSYNC_MAILBOX_NODE_EXISTS);
 
-		other_node = hash_table_lookup(other_tree->guid_hash,
-					       node->mailbox_guid);
+		guid_p = node->mailbox_guid;
+		other_node = hash_table_lookup(other_tree->guid_hash, guid_p);
 		if (other_node == NULL)
 			other_node = sorted_tree_get(other_tree, name);
 		if (!guid_128_is_empty(other_node->mailbox_guid)) {
@@ -564,8 +568,8 @@
 	struct dsync_mailbox_tree_sync_ctx *ctx;
 	pool_t pool;
 
-	i_assert(local_tree->guid_hash != NULL);
-	i_assert(remote_tree->guid_hash != NULL);
+	i_assert(hash_table_is_created(local_tree->guid_hash));
+	i_assert(hash_table_is_created(remote_tree->guid_hash));
 
 	pool = pool_alloconly_create(MEMPOOL_GROWING"dsync mailbox trees sync",
 				     1024*64);
--- a/src/doveadm/dsync/dsync-mailbox-tree.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/dsync/dsync-mailbox-tree.c	Sun Aug 19 13:55:34 2012 +0300
@@ -36,9 +36,9 @@
 	struct dsync_mailbox_tree *tree = *_tree;
 
 	*_tree = NULL;
-	if (tree->name128_hash != NULL)
+	if (hash_table_is_created(tree->name128_hash))
 		hash_table_destroy(&tree->name128_hash);
-	if (tree->guid_hash != NULL)
+	if (hash_table_is_created(tree->guid_hash))
 		hash_table_destroy(&tree->guid_hash);
 	array_free(&tree->deletes);
 	pool_unref(&tree->pool);
@@ -208,16 +208,18 @@
 	struct dsync_mailbox_node *node;
 	const char *name;
 	guid_128_t *sha128;
-
-	i_assert(tree->name128_hash == NULL);
+	uint8_t *guid_p;
 
-	tree->name128_hash = hash_table_create(tree->pool, 0,
-					       guid_128_hash, guid_128_cmp);
+	i_assert(!hash_table_is_created(tree->name128_hash));
+
+	hash_table_create(&tree->name128_hash,
+			  tree->pool, 0, guid_128_hash, guid_128_cmp);
 	iter = dsync_mailbox_tree_iter_init(tree);
 	while (dsync_mailbox_tree_iter_next(iter, &name, &node)) {
 		sha128 = p_new(tree->pool, guid_128_t, 1);
 		mailbox_name_get_sha128(name, *sha128);
-		hash_table_insert(tree->name128_hash, *sha128, node);
+		guid_p = *sha128;
+		hash_table_insert(tree->name128_hash, guid_p, node);
 	}
 	dsync_mailbox_tree_iter_deinit(&iter);
 }
@@ -246,13 +248,13 @@
 	struct dsync_mailbox_node *node;
 	const char *name;
 	guid_128_t *sha128;
+	uint8_t *guid_p;
 
 	i_assert(tree->sep != tree->remote_sep);
-	i_assert(tree->name128_remotesep_hash == NULL);
+	i_assert(!hash_table_is_created(tree->name128_remotesep_hash));
 
-	tree->name128_remotesep_hash =
-		hash_table_create(tree->pool, 0,
-				  guid_128_hash, guid_128_cmp);
+	hash_table_create(&tree->name128_remotesep_hash, tree->pool, 0,
+			  guid_128_hash, guid_128_cmp);
 	iter = dsync_mailbox_tree_iter_init(tree);
 	while (dsync_mailbox_tree_iter_next(iter, &name, &node)) {
 		sha128 = p_new(tree->pool, guid_128_t, 1);
@@ -261,7 +263,8 @@
 				convert_name_to_remote_sep(tree, name);
 			mailbox_name_get_sha128(remote_name, *sha128);
 		} T_END;
-		hash_table_insert(tree->name128_remotesep_hash, *sha128, node);
+		guid_p = *sha128;
+		hash_table_insert(tree->name128_remotesep_hash, guid_p, node);
 	}
 	dsync_mailbox_tree_iter_deinit(&iter);
 }
@@ -270,11 +273,12 @@
 				     struct dsync_mailbox_node *node)
 {
 	struct dsync_mailbox_node *old_node;
+	uint8_t *guid = node->mailbox_guid;
 
 	if (guid_128_is_empty(node->mailbox_guid))
 		return 0;
 
-	old_node = hash_table_lookup(tree->guid_hash, node->mailbox_guid);
+	old_node = hash_table_lookup(tree->guid_hash, guid);
 	if (old_node != NULL) {
 		i_error("Duplicate mailbox GUID %s "
 			"for mailboxes %s and %s",
@@ -283,7 +287,7 @@
 			dsync_mailbox_node_get_full_name(tree, node));
 		return -1;
 	}
-	hash_table_insert(tree->guid_hash, node->mailbox_guid, node);
+	hash_table_insert(tree->guid_hash, guid, node);
 	return 0;
 }
 
@@ -294,10 +298,10 @@
 	const char *name;
 	int ret = 0;
 
-	i_assert(tree->guid_hash == NULL);
+	i_assert(!hash_table_is_created(tree->guid_hash));
 
-	tree->guid_hash = hash_table_create(tree->pool, 0,
-					    guid_128_hash, guid_128_cmp);
+	hash_table_create(&tree->guid_hash, tree->pool, 0,
+			  guid_128_hash, guid_128_cmp);
 	iter = dsync_mailbox_tree_iter_init(tree);
 	while (dsync_mailbox_tree_iter_next(iter, &name, &node))
 		(void)dsync_mailbox_tree_guid_hash_add(tree, node);
@@ -316,28 +320,27 @@
 dsync_mailbox_tree_find_delete(struct dsync_mailbox_tree *tree,
 			       const struct dsync_mailbox_delete *del)
 {
-	struct hash_table *hash;
+	const uint8_t *guid_p = del->guid;
 
-	i_assert(tree->guid_hash != NULL);
+	i_assert(hash_table_is_created(tree->guid_hash));
 	i_assert(tree->remote_sep != '\0');
 
 	if (del->delete_mailbox) {
 		/* find node by GUID */
-		return hash_table_lookup(tree->guid_hash, del->guid);
+		return hash_table_lookup(tree->guid_hash, guid_p);
 	}
 
 	/* find node by name. this is a bit tricky, since the hierarchy
 	   separator may differ from ours. */
 	if (tree->sep == tree->remote_sep) {
-		if (tree->name128_hash == NULL)
+		if (!hash_table_is_created(tree->name128_hash))
 			dsync_mailbox_tree_build_name128_hash(tree);
-		hash = tree->name128_hash;
+		return hash_table_lookup(tree->name128_hash, guid_p);
 	} else {
-		if (tree->name128_remotesep_hash == NULL)
+		if (!hash_table_is_created(tree->name128_remotesep_hash))
 			dsync_mailbox_tree_build_name128_remotesep_hash(tree);
-		hash = tree->name128_remotesep_hash;
+		return hash_table_lookup(tree->name128_remotesep_hash, guid_p);
 	}
-	return hash_table_lookup(hash, del->guid);
 }
 
 void dsync_mailbox_tree_set_remote_sep(struct dsync_mailbox_tree *tree,
--- a/src/doveadm/dsync/dsync-transaction-log-scan.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/dsync/dsync-transaction-log-scan.c	Sun Aug 19 13:55:34 2012 +0300
@@ -9,7 +9,7 @@
 
 struct dsync_transaction_log_scan {
 	pool_t pool;
-	struct hash_table *changes;
+	HASH_TABLE_TYPE(dsync_uid_mail_change) changes;
 	struct mail_index_view *view;
 	uint32_t highest_wanted_uid;
 
@@ -35,13 +35,13 @@
 	if (uid > ctx->highest_wanted_uid)
 		return FALSE;
 
-	change = hash_table_lookup(ctx->changes, POINTER_CAST(uid));
+	change = hash_table_lookup(ctx->changes, uid);
 	if (change == NULL) {
 		/* first change for this UID */
 		change = p_new(ctx->pool, struct dsync_mail_change, 1);
 		change->uid = uid;
 		change->type = type;
-		hash_table_insert(ctx->changes, POINTER_CAST(uid), change);
+		hash_table_insert(ctx->changes, uid, change);
 	} else if (type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE) {
 		/* expunge overrides flag changes */
 		orig_guid = change->guid;
@@ -343,7 +343,7 @@
 				     10240);
 	ctx = p_new(pool, struct dsync_transaction_log_scan, 1);
 	ctx->pool = pool;
-	ctx->changes = hash_table_create(pool, 0, NULL, NULL);
+	hash_table_create_direct(&ctx->changes, pool, 0);
 	ctx->view = view;
 	ctx->highest_wanted_uid = highest_wanted_uid;
 
@@ -406,7 +406,7 @@
 	return 0;
 }
 
-struct hash_table *
+HASH_TABLE_TYPE(dsync_uid_mail_change)
 dsync_transaction_log_scan_get_hash(struct dsync_transaction_log_scan *scan)
 {
 	return scan->changes;
@@ -454,8 +454,7 @@
 	}
 	mail_transaction_log_view_close(&log_view);
 
-	return !found ? NULL :
-		hash_table_lookup(scan->changes, POINTER_CAST(uid));
+	return !found ? NULL : hash_table_lookup(scan->changes, uid);
 }
 
 void dsync_transaction_log_scan_deinit(struct dsync_transaction_log_scan **_scan)
--- a/src/doveadm/dsync/dsync-transaction-log-scan.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/doveadm/dsync/dsync-transaction-log-scan.h	Sun Aug 19 13:55:34 2012 +0300
@@ -1,6 +1,9 @@
 #ifndef DSYNC_TRANSACTION_LOG_SCAN_H
 #define DSYNC_TRANSACTION_LOG_SCAN_H
 
+HASH_TABLE_DEFINE_TYPE(dsync_uid_mail_change,
+		       uint32_t, struct dsync_mail_change*);
+
 struct mail_index_view;
 struct dsync_transaction_log_scan;
 
@@ -8,7 +11,7 @@
 				    uint32_t highest_wanted_uid,
 				    uint64_t modseq,
 				    struct dsync_transaction_log_scan **scan_r);
-struct hash_table *
+HASH_TABLE_TYPE(dsync_uid_mail_change)
 dsync_transaction_log_scan_get_hash(struct dsync_transaction_log_scan *scan);
 /* Returns TRUE if the entire transaction log was scanned */
 bool dsync_transaction_log_scan_has_all_changes(struct dsync_transaction_log_scan *scan);
--- a/src/indexer/indexer-queue.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/indexer/indexer-queue.c	Sun Aug 19 13:55:34 2012 +0300
@@ -10,21 +10,19 @@
 	void (*listen_callback)(struct indexer_queue *);
 
 	/* username+mailbox -> indexer_request */
-	struct hash_table *requests;
+	HASH_TABLE(struct indexer_request *, struct indexer_request *) requests;
 	struct indexer_request *head, *tail;
 };
 
-static unsigned int indexer_request_hash(const void *p)
+static unsigned int
+indexer_request_hash(const struct indexer_request *request)
 {
-	const struct indexer_request *request = p;
-
 	return str_hash(request->username) ^ str_hash(request->mailbox);
 }
 
-static int indexer_request_cmp(const void *p1, const void *p2)
+static int indexer_request_cmp(const struct indexer_request *r1,
+			       const struct indexer_request *r2)
 {
-	const struct indexer_request *r1 = p1, *r2 = p2;
-
 	return strcmp(r1->username, r2->username) == 0 &&
 		strcmp(r1->mailbox, r2->mailbox) == 0 ? 0 : 1;
 }
@@ -36,9 +34,8 @@
 	
 	queue = i_new(struct indexer_queue, 1);
 	queue->callback = callback;
-	queue->requests = hash_table_create(default_pool, 0,
-					    indexer_request_hash,
-					    indexer_request_cmp);
+	hash_table_create(&queue->requests, default_pool, 0,
+			  indexer_request_hash, indexer_request_cmp);
 	return queue;
 }
 
--- a/src/lib-auth/auth-server-connection.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-auth/auth-server-connection.c	Sun Aug 19 13:55:34 2012 +0300
@@ -144,13 +144,13 @@
 		return -1;
 	}
 
-	request = hash_table_lookup(conn->requests, POINTER_CAST(id));
+	request = hash_table_lookup(conn->requests, id);
 	if (request == NULL) {
 		i_error("BUG: Authentication server sent unknown id %u", id);
 		return -1;
 	}
 	if (remove || auth_client_request_is_aborted(request))
-		hash_table_remove(conn->requests, POINTER_CAST(id));
+		hash_table_remove(conn->requests, id);
 
 	*request_r = request;
 	return 0;
@@ -303,7 +303,7 @@
 
 	conn->client = client;
 	conn->fd = -1;
-	conn->requests = hash_table_create(pool, 100, NULL, NULL);
+	hash_table_create_direct(&conn->requests, pool, 100);
 	i_array_init(&conn->available_auth_mechs, 8);
 	return conn;
 }
@@ -477,6 +477,6 @@
 		/* wrapped - ID 0 not allowed */
 		id = ++conn->client->request_id_counter;
 	}
-	hash_table_insert(conn->requests, POINTER_CAST(id), request);
+	hash_table_insert(conn->requests, id, request);
 	return id;
 }
--- a/src/lib-auth/auth-server-connection.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-auth/auth-server-connection.h	Sun Aug 19 13:55:34 2012 +0300
@@ -19,7 +19,7 @@
 
 	ARRAY_DEFINE(available_auth_mechs, struct auth_mech_desc);
 
-        struct hash_table *requests;
+	HASH_TABLE(unsigned int, struct auth_client_request *) requests;
 
 	unsigned int version_received:1;
 	unsigned int handshake_received:1;
--- a/src/lib-dict/dict-file.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-dict/dict-file.c	Sun Aug 19 13:55:34 2012 +0300
@@ -23,7 +23,7 @@
 	enum file_lock_method lock_method;
 
 	char *path;
-	struct hash_table *hash;
+	HASH_TABLE(char *, char *) hash;
 	int fd;
 
 	bool refreshed;
@@ -77,8 +77,7 @@
 	}
 	dict->dict = *driver;
 	dict->hash_pool = pool_alloconly_create("file dict", 1024);
-	dict->hash = hash_table_create(dict->hash_pool, 0,
-				       str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&dict->hash, dict->hash_pool, 0, str_hash, strcmp);
 	dict->fd = -1;
 	return &dict->dict;
 }
@@ -233,16 +232,17 @@
 {
 	struct file_dict_iterate_context *ctx =
 		(struct file_dict_iterate_context *)_ctx;
+	struct file_dict *dict = (struct file_dict *)_ctx->dict;
 	const struct file_dict_iterate_path *path;
-	void *key, *value;
+	char *key, *value;
 
-	while (hash_table_iterate(ctx->iter, &key, &value)) {
+	while (hash_table_iterate_t(ctx->iter, dict->hash, &key, &value)) {
 		path = file_dict_iterate_find_path(ctx, key);
 		if (path == NULL)
 			continue;
 
 		if ((ctx->flags & DICT_ITERATE_FLAG_RECURSE) == 0 &&
-		    strchr((char *)key + path->len, '/') != NULL)
+		    strchr(key + path->len, '/') != NULL)
 			continue;
 
 		*key_r = key;
@@ -281,14 +281,14 @@
 	struct file_dict *dict = (struct file_dict *)ctx->ctx.dict;
 	const char *tmp;
 	char *key, *value, *old_value;
-	void *orig_key, *orig_value;
+	char *orig_key, *orig_value;
 	const struct dict_transaction_memory_change *change;
 	unsigned int new_len;
 	long long diff;
 
 	array_foreach(&ctx->changes, change) {
-		if (hash_table_lookup_full(dict->hash, change->key,
-					   &orig_key, &orig_value)) {
+		if (hash_table_lookup_full_t(dict->hash, change->key,
+					     &orig_key, &orig_value)) {
 			key = orig_key;
 			old_value = orig_value;
 		} else {
@@ -450,7 +450,7 @@
 	const char *temp_path = NULL;
 	struct hash_iterate_context *iter;
 	struct ostream *output;
-	void *key, *value;
+	char *key, *value;
 	int fd = -1;
 
 	*atomic_inc_not_found_r = FALSE;
@@ -502,7 +502,7 @@
 	output = o_stream_create_fd(fd, 0, FALSE);
 	o_stream_cork(output);
 	iter = hash_table_iterate_init(dict->hash);
-	while (hash_table_iterate(iter, &key, &value)) {
+	while (hash_table_iterate_t(iter, dict->hash, &key, &value)) {
 		o_stream_nsend_str(output, key);
 		o_stream_nsend(output, "\n", 1);
 		o_stream_nsend_str(output, value);
--- a/src/lib-index/mail-cache-fields.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-index/mail-cache-fields.c	Sun Aug 19 13:55:34 2012 +0300
@@ -151,8 +151,7 @@
 		if (!field_has_fixed_size(cache->fields[idx].field.type))
 			cache->fields[idx].field.field_size = (unsigned int)-1;
 
-		hash_table_insert(cache->field_name_hash,
-				  name, POINTER_CAST(idx));
+		hash_table_insert(cache->field_name_hash, name, idx);
 	}
 	cache->fields_count = new_idx;
 }
@@ -166,7 +165,7 @@
 				   &orig_key, &orig_value))
 		return POINTER_CAST_TO(orig_value, unsigned int);
 	else
-		return (unsigned int)-1;
+		return -1U;
 }
 
 const struct mail_cache_field *
--- a/src/lib-index/mail-cache-private.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-index/mail-cache-private.h	Sun Aug 19 13:55:34 2012 +0300
@@ -158,7 +158,7 @@
 	struct mail_cache_field_private *fields;
 	uint32_t *field_file_map;
 	unsigned int fields_count;
-	struct hash_table *field_name_hash; /* name -> idx */
+	HASH_TABLE(char *, unsigned int) field_name_hash; /* name -> idx */
 	uint32_t last_field_header_offset;
 
 	/* 0 is no need for compression, otherwise the file sequence number
--- a/src/lib-index/mail-cache.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-index/mail-cache.c	Sun Aug 19 13:55:34 2012 +0300
@@ -410,9 +410,8 @@
 	cache->filepath =
 		i_strconcat(index->filepath, MAIL_CACHE_FILE_SUFFIX, NULL);
 	cache->field_pool = pool_alloconly_create("Cache fields", 2048);
-	cache->field_name_hash =
-		hash_table_create(cache->field_pool, 0,
-				  strcase_hash, (hash_cmp_callback_t *)strcasecmp);
+	hash_table_create(&cache->field_name_hash, cache->field_pool, 0,
+			  strcase_hash, strcasecmp);
 
 	cache->dotlock_settings.use_excl_lock =
 		(index->flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
--- a/src/lib-index/mail-index-private.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-index/mail-index-private.h	Sun Aug 19 13:55:34 2012 +0300
@@ -215,7 +215,7 @@
 
 	pool_t keywords_pool;
 	ARRAY_TYPE(keywords) keywords;
-	struct hash_table *keywords_hash; /* name -> idx */
+	HASH_TABLE(char *, unsigned int) keywords_hash; /* name -> idx */
 
 	uint32_t keywords_ext_id;
 	uint32_t modseq_ext_id;
--- a/src/lib-index/mail-index.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-index/mail-index.c	Sun Aug 19 13:55:34 2012 +0300
@@ -52,9 +52,8 @@
 					128, 2, 1);
 	index->keywords_pool = pool_alloconly_create("keywords", 512);
 	i_array_init(&index->keywords, 16);
-	index->keywords_hash =
-		hash_table_create(index->keywords_pool, 0,
-				  strcase_hash, (hash_cmp_callback_t *)strcasecmp);
+	hash_table_create(&index->keywords_hash, index->keywords_pool, 0,
+			  strcase_hash, strcasecmp);
 	index->log = mail_transaction_log_alloc(index);
 	mail_index_modseq_init(index);
 	return index;
@@ -262,7 +261,7 @@
 		return TRUE;
 	}
 
-	*idx_r = (unsigned int)-1;
+	*idx_r = -1U;
 	return FALSE;
 }
 
@@ -280,8 +279,7 @@
 	keyword = keyword_dup = p_strdup(index->keywords_pool, keyword);
 	*idx_r = array_count(&index->keywords);
 
-	hash_table_insert(index->keywords_hash,
-			  keyword_dup, POINTER_CAST(*idx_r));
+	hash_table_insert(index->keywords_hash, keyword_dup, *idx_r);
 	array_append(&index->keywords, &keyword, 1);
 
 	/* keep the array NULL-terminated, but the NULL itself invisible */
--- a/src/lib-lda/duplicate.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-lda/duplicate.c	Sun Aug 19 13:55:34 2012 +0300
@@ -40,7 +40,7 @@
 
 struct duplicate_file {
 	pool_t pool;
-	struct hash_table *hash;
+	HASH_TABLE(struct duplicate *, struct duplicate *) hash;
 	const char *path;
 
 	int new_fd;
@@ -59,19 +59,16 @@
 	.stale_timeout = 10,
 };
 
-static int duplicate_cmp(const void *p1, const void *p2)
+static int duplicate_cmp(const struct duplicate *d1, const struct duplicate *d2)
 {
-	const struct duplicate *d1 = p1, *d2 = p2;
-
 	return (d1->id_size == d2->id_size &&
 		memcmp(d1->id, d2->id, d1->id_size) == 0 &&
 		strcasecmp(d1->user, d2->user) == 0) ? 0 : 1;
 }
 
-static unsigned int duplicate_hash(const void *p)
+static unsigned int duplicate_hash(const struct duplicate *d)
 {
 	/* a char* hash function from ASU -- from glib */
-	const struct duplicate *d = p;
         const unsigned char *s = d->id, *end = s + d->id_size;
 	unsigned int g, h = 0;
 
@@ -214,8 +211,7 @@
 					 &file->dotlock);
 	if (file->new_fd == -1)
 		i_error("file_dotlock_create(%s) failed: %m", file->path);
-	file->hash = hash_table_create(pool, 0,
-				       duplicate_hash, duplicate_cmp);
+	hash_table_create(&file->hash, pool, 0, duplicate_hash, duplicate_cmp);
 	(void)duplicate_read(file);
 	return file;
 }
@@ -287,7 +283,7 @@
 	struct duplicate_record_header rec;
 	struct ostream *output;
         struct hash_iterate_context *iter;
-	void *key, *value;
+	struct duplicate *d;
 
 	if (file == NULL || !file->changed || file->new_fd == -1)
 		return;
@@ -301,9 +297,7 @@
 
 	memset(&rec, 0, sizeof(rec));
 	iter = hash_table_iterate_init(file->hash);
-	while (hash_table_iterate(iter, &key, &value)) {
-		struct duplicate *d = value;
-
+	while (hash_table_iterate_t(iter, file->hash, &d, &d)) {
 		rec.stamp = d->time;
 		rec.id_size = d->id_size;
 		rec.user_size = strlen(d->user);
--- a/src/lib-master/master-auth.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-master/master-auth.c	Sun Aug 19 13:55:34 2012 +0300
@@ -37,7 +37,7 @@
 	const char *path;
 
 	unsigned int tag_counter;
-	struct hash_table *connections;
+	HASH_TABLE(unsigned int, struct master_auth_connection *) connections;
 };
 
 struct master_auth *
@@ -51,7 +51,7 @@
 	auth->pool = pool;
 	auth->service = service;
 	auth->path = p_strdup(pool, path);
-	auth->connections = hash_table_create(pool, 0, NULL, NULL);
+	hash_table_create_direct(&auth->connections, pool, 0);
 	return auth;
 }
 
@@ -62,10 +62,8 @@
 
 	*_conn = NULL;
 
-	if (conn->tag != 0) {
-		hash_table_remove(conn->auth->connections,
-				  POINTER_CAST(conn->tag));
-	}
+	if (conn->tag != 0)
+		hash_table_remove(conn->auth->connections, conn->tag);
 
 	if (conn->callback != NULL)
 		conn->callback(NULL, conn->context);
@@ -211,7 +209,7 @@
 			       master_auth_connection_timeout, conn);
 	conn->io = io_add(conn->fd, IO_READ,
 			  master_auth_connection_input, conn);
-	hash_table_insert(auth->connections, POINTER_CAST(req.tag), conn);
+	hash_table_insert(auth->connections, req.tag, conn);
 	*tag_r = req.tag;
 }
 
@@ -219,7 +217,7 @@
 {
         struct master_auth_connection *conn;
 
-	conn = hash_table_lookup(auth->connections, POINTER_CAST(tag));
+	conn = hash_table_lookup(auth->connections, tag);
 	if (conn == NULL)
 		i_panic("master_auth_request_abort(): tag %u not found", tag);
 
--- a/src/lib-master/master-login-auth.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-master/master-login-auth.c	Sun Aug 19 13:55:34 2012 +0300
@@ -47,7 +47,7 @@
 	struct timeout *to;
 
 	unsigned int id_counter;
-	struct hash_table *requests;
+	HASH_TABLE(unsigned int, struct master_login_auth_request *) requests;
 	/* linked list of requests, ordered by create_stamp */
 	struct master_login_auth_request *request_head, *request_tail;
 
@@ -71,7 +71,7 @@
 	auth->auth_socket_path = p_strdup(pool, auth_socket_path);
 	auth->refcount = 1;
 	auth->fd = -1;
-	auth->requests = hash_table_create(pool, 0, NULL, NULL);
+	hash_table_create_direct(&auth->requests, pool, 0);
 	auth->id_counter = (rand() % 32767) * 131072U;
 	return auth;
 }
@@ -158,7 +158,7 @@
 		request = auth->request_head;
 		DLLIST2_REMOVE(&auth->request_head,
 			       &auth->request_tail, request);
-		hash_table_remove(auth->requests, POINTER_CAST(request->id));
+		hash_table_remove(auth->requests, request->id);
 
 		reason = t_strdup_printf(
 			"Auth server request timed out after %u secs",
@@ -188,7 +188,7 @@
 
 	update_timeout = request->prev == NULL;
 
-	hash_table_remove(auth->requests, POINTER_CAST(request->id));
+	hash_table_remove(auth->requests, request->id);
 	DLLIST2_REMOVE(&auth->request_head, &auth->request_tail, request);
 
 	if (update_timeout) {
@@ -203,7 +203,7 @@
 {
 	struct master_login_auth_request *request;
 
-	request = hash_table_lookup(auth->requests, POINTER_CAST(id));
+	request = hash_table_lookup(auth->requests, id);
 	if (request == NULL) {
 		i_error("Auth server sent reply with unknown ID %u", id);
 		return NULL;
@@ -476,7 +476,7 @@
 	memcpy(login_req->cookie, req->cookie, sizeof(login_req->cookie));
 	login_req->callback = callback;
 	login_req->context = context;
-	hash_table_insert(auth->requests, POINTER_CAST(id), login_req);
+	hash_table_insert(auth->requests, id, login_req);
 	DLLIST2_APPEND(&auth->request_head, &auth->request_tail, login_req);
 
 	if (auth->to == NULL)
--- a/src/lib-master/master-service-settings-cache.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-master/master-service-settings-cache.c	Sun Aug 19 13:55:34 2012 +0300
@@ -38,8 +38,8 @@
 	/* separate list for entries whose parser=global_parser */
 	struct settings_entry *oldest_global, *newest_global;
 	/* local_name, local_ip => struct settings_entry */
-	struct hash_table *local_name_hash;
-	struct hash_table *local_ip_hash;
+	HASH_TABLE(char *, struct settings_entry *) local_name_hash;
+	HASH_TABLE(struct ip_addr *, struct settings_entry *) local_ip_hash;
 
 	/* Initial size for new settings entry pools */
 	size_t approx_entry_pool_size;
@@ -85,9 +85,9 @@
 		settings_parser_deinit(&entry->parser);
 		pool_unref(&entry->pool);
 	}
-	if (cache->local_name_hash != NULL)
+	if (hash_table_is_created(cache->local_name_hash))
 		hash_table_destroy(&cache->local_name_hash);
-	if (cache->local_ip_hash != NULL)
+	if (hash_table_is_created(cache->local_ip_hash))
 		hash_table_destroy(&cache->local_ip_hash);
 	if (cache->global_parser != NULL)
 		settings_parser_deinit(&cache->global_parser);
@@ -134,11 +134,11 @@
 	   don't even try to use local_ip (even though we have it), because
 	   there may be different settings specifically for local_name */
 	if (input->local_name != NULL) {
-		if (cache->local_name_hash != NULL) {
+		if (hash_table_is_created(cache->local_name_hash)) {
 			entry = hash_table_lookup(cache->local_name_hash,
 						  input->local_name);
 		}
-	} else if (cache->local_ip_hash != NULL &&
+	} else if (hash_table_is_created(cache->local_ip_hash) &&
 		   input->local_ip.family != 0) {
 		entry = hash_table_lookup(cache->local_ip_hash,
 					  &input->local_ip);
@@ -231,21 +231,17 @@
 	cache->cache_malloc_size += pool_alloconly_get_total_alloc_size(pool);
 
 	if (input->local_name != NULL) {
-		if (cache->local_name_hash == NULL) {
-			cache->local_name_hash =
-				hash_table_create(cache->pool, 0,
-						  str_hash,
-						  (hash_cmp_callback_t *)strcmp);
+		if (!hash_table_is_created(cache->local_name_hash)) {
+			hash_table_create(&cache->local_name_hash,
+					  cache->pool, 0, str_hash, strcmp);
 		}
 		hash_table_insert(cache->local_name_hash,
 				  entry_local_name, entry);
 	}
 	if (input->local_ip.family != 0) {
-		if (cache->local_ip_hash == NULL) {
-			cache->local_ip_hash =
-				hash_table_create(cache->pool, 0,
-						  (hash_callback_t *)net_ip_hash,
-						  (hash_cmp_callback_t *)net_ip_cmp);
+		if (!hash_table_is_created(cache->local_ip_hash)) {
+			hash_table_create(&cache->local_ip_hash, cache->pool, 0,
+					  net_ip_hash, net_ip_cmp);
 		}
 		hash_table_insert(cache->local_ip_hash,
 				  &entry->local_ip, entry);
--- a/src/lib-settings/settings-parser.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-settings/settings-parser.c	Sun Aug 19 13:55:34 2012 +0300
@@ -48,7 +48,7 @@
 
 	struct setting_link *roots;
 	unsigned int root_count;
-	struct hash_table *links;
+	HASH_TABLE(char *, struct setting_link *) links;
 
 	unsigned int linenum;
 	const char *error;
@@ -66,6 +66,9 @@
 	.parent_offset = (size_t)-1
 };
 
+HASH_TABLE_DEFINE_TYPE(setting_link, struct setting_link *,
+		       struct setting_link *);
+
 static int settings_parse_keyvalue(struct setting_parser_context *ctx,
 				   const char *key, const char *value);
 
@@ -206,8 +209,7 @@
 	ctx->set_pool = set_pool;
 	ctx->parser_pool = parser_pool;
 	ctx->flags = flags;
-	ctx->links = hash_table_create(ctx->parser_pool, 0,
-				       str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&ctx->links, ctx->parser_pool, 0, str_hash, strcmp);
 
 	ctx->root_count = count;
 	ctx->roots = p_new(ctx->parser_pool, struct setting_link, count);
@@ -1687,7 +1689,7 @@
 
 static struct setting_link *
 settings_link_get_new(struct setting_parser_context *new_ctx,
-		      struct hash_table *links,
+		      HASH_TABLE_TYPE(setting_link) links,
 		      struct setting_link *old_link)
 {
 	struct setting_link *new_link;
@@ -1735,9 +1737,9 @@
 {
 	struct setting_parser_context *new_ctx;
 	struct hash_iterate_context *iter;
-	struct setting_link *new_link;
-	struct hash_table *links;
-	void *key, *value;
+	HASH_TABLE_TYPE(setting_link) links;
+	struct setting_link *new_link, *value;
+	char *key;
 	unsigned int i;
 	pool_t parser_pool;
 
@@ -1753,7 +1755,7 @@
 	new_ctx->error = p_strdup(new_ctx->parser_pool, old_ctx->error);
 	new_ctx->prev_info = old_ctx->prev_info;
 
-	links = hash_table_create(new_ctx->parser_pool, 0, NULL, NULL);
+	hash_table_create_direct(&links, new_ctx->parser_pool, 0);
 
 	new_ctx->root_count = old_ctx->root_count;
 	new_ctx->roots = p_new(new_ctx->parser_pool, struct setting_link,
@@ -1775,12 +1777,11 @@
 				  &new_ctx->roots[i]);
 	}
 
-	new_ctx->links =
-		hash_table_create(new_ctx->parser_pool, 0,
-				  str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&new_ctx->links, new_ctx->parser_pool, 0,
+			  str_hash, strcmp);
 
 	iter = hash_table_iterate_init(old_ctx->links);
-	while (hash_table_iterate(iter, &key, &value)) {
+	while (hash_table_iterate_t(iter, old_ctx->links, &key, &value)) {
 		new_link = settings_link_get_new(new_ctx, links, value);
 		hash_table_insert(new_ctx->links,
 				  p_strdup(new_ctx->parser_pool, key),
--- a/src/lib-sql/sql-db-cache.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-sql/sql-db-cache.c	Sun Aug 19 13:55:34 2012 +0300
@@ -20,7 +20,7 @@
 };
 
 struct sql_db_cache {
-	struct hash_table *dbs;
+	HASH_TABLE(char *, struct sql_db *) dbs;
 	unsigned int unused_count, max_unused_connections;
 	struct sql_db *unused_tail, *unused_head;
 };
@@ -128,8 +128,7 @@
 	struct sql_db_cache *cache;
 
 	cache = i_new(struct sql_db_cache, 1);
-	cache->dbs = hash_table_create(default_pool, 0, str_hash,
-				       (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&cache->dbs, default_pool, 0, str_hash, strcmp);
 	cache->max_unused_connections = max_unused_connections;
 	return cache;
 }
--- a/src/lib-storage/index/dbox-multi/mdbox-purge.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/index/dbox-multi/mdbox-purge.c	Sun Aug 19 13:55:34 2012 +0300
@@ -43,8 +43,8 @@
 	/* list of file_ids that we need to purge */
 	ARRAY_TYPE(seq_range) purge_file_ids;
 
-	/* map_uid => mdbox_msg_action */
-	struct hash_table *altmoves;
+	/* map_uid => action */
+	HASH_TABLE(uint32_t, enum mdbox_msg_action) altmoves;
 	bool have_altmoves;
 
 	struct mdbox_map_atomic_context *atomic;
@@ -169,16 +169,11 @@
 mdbox_purge_want_altpath(struct mdbox_purge_context *ctx, uint32_t map_uid)
 {
 	enum mdbox_msg_action action;
-	void *value;
 
 	if (!ctx->have_altmoves)
 		return FALSE;
 
-	value = hash_table_lookup(ctx->altmoves, POINTER_CAST(map_uid));
-	if (value == NULL)
-		return FALSE;
-
-	action = POINTER_CAST_TO(value, enum mdbox_msg_action);
+	action = hash_table_lookup(ctx->altmoves, map_uid);
 	return action == MDBOX_MSG_ACTION_MOVE_TO_ALT;
 }
 
@@ -475,7 +470,7 @@
 	ctx->lowest_primary_file_id = (uint32_t)-1;
 	i_array_init(&ctx->primary_file_ids, 64);
 	i_array_init(&ctx->purge_file_ids, 64);
-	ctx->altmoves = hash_table_create(pool, 0, NULL, NULL);
+	hash_table_create_direct(&ctx->altmoves, pool, 0);
 	return ctx;
 }
 
@@ -569,6 +564,7 @@
 	const uint32_t *map_uids;
 	unsigned int i, count, alt_refcount = 0;
 	struct mdbox_map_mail_index_record cur_rec;
+	enum mdbox_msg_action action;
 	uint32_t cur_map_uid;
 	uint16_t cur_refcount = 0;
 	uoff_t offset;
@@ -599,9 +595,8 @@
 		if (alt_refcount == cur_refcount &&
 		    seq_range_exists(&ctx->primary_file_ids, cur_rec.file_id)) {
 			/* all instances marked as moved to alt storage */
-			hash_table_insert(ctx->altmoves,
-				POINTER_CAST(cur_map_uid),
-				POINTER_CAST(MDBOX_MSG_ACTION_MOVE_TO_ALT));
+			action = MDBOX_MSG_ACTION_MOVE_TO_ALT;
+			hash_table_insert(ctx->altmoves, cur_map_uid, action);
 			seq_range_array_add(&ctx->purge_file_ids,
 					    cur_rec.file_id);
 		}
@@ -632,8 +627,8 @@
 			continue;
 		}
 
-		hash_table_insert(ctx->altmoves, POINTER_CAST(cur_map_uid),
-				  POINTER_CAST(MDBOX_MSG_ACTION_MOVE_FROM_ALT));
+		action = MDBOX_MSG_ACTION_MOVE_FROM_ALT;
+		hash_table_insert(ctx->altmoves, cur_map_uid, action);
 		seq_range_array_add(&ctx->purge_file_ids, cur_rec.file_id);
 	}
 	ctx->have_altmoves = hash_table_count(ctx->altmoves) > 0;
--- a/src/lib-storage/index/dbox-multi/mdbox-storage-rebuild.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/index/dbox-multi/mdbox-storage-rebuild.c	Sun Aug 19 13:55:34 2012 +0300
@@ -45,7 +45,7 @@
 	pool_t pool;
 
 	struct mdbox_map_mail_index_header orig_map_hdr;
-	struct hash_table *guid_hash;
+	HASH_TABLE(uint8_t *, struct mdbox_rebuild_msg *) guid_hash;
 	ARRAY_DEFINE(msgs, struct mdbox_rebuild_msg *);
 	ARRAY_TYPE(seq_range) seen_file_ids;
 
@@ -69,8 +69,8 @@
 	ctx->storage = storage;
 	ctx->atomic = atomic;
 	ctx->pool = pool_alloconly_create("dbox map rebuild", 1024*256);
-	ctx->guid_hash = hash_table_create(ctx->pool, 0,
-					   guid_128_hash, guid_128_cmp);
+	hash_table_create(&ctx->guid_hash, ctx->pool, 0,
+			  guid_128_hash, guid_128_cmp);
 	i_array_init(&ctx->msgs, 512);
 	i_array_init(&ctx->seen_file_ids, 128);
 
@@ -127,6 +127,7 @@
 			      struct dbox_file *file, uint32_t file_id)
 {
 	const char *guid;
+	uint8_t *guid_p;
 	struct mdbox_rebuild_msg *rec, *old_rec;
 	uoff_t offset, prev_offset;
 	bool last, first, fixed = FALSE;
@@ -180,9 +181,10 @@
 		i_assert(!guid_128_is_empty(rec->guid_128));
 		array_append(&ctx->msgs, &rec, 1);
 
-		old_rec = hash_table_lookup(ctx->guid_hash, rec->guid_128);
+		guid_p = rec->guid_128;
+		old_rec = hash_table_lookup(ctx->guid_hash, guid_p);
 		if (old_rec == NULL)
-			hash_table_insert(ctx->guid_hash, rec->guid_128, rec);
+			hash_table_insert(ctx->guid_hash, guid_p, rec);
 		else if (rec->size == old_rec->size) {
 			/* duplicate. save this as a refcount=0 to map,
 			   so it will eventually be deleted. */
@@ -372,6 +374,7 @@
 	const struct mail_index_header *hdr;
 	struct mdbox_rebuild_msg *rec;
 	const void *data;
+	const uint8_t *guid_p;
 	bool expunged;
 	uint32_t old_seq, new_seq, uid, map_uid;
 
@@ -392,11 +395,12 @@
 
 		mail_index_lookup_ext(view, old_seq, mbox->guid_ext_id,
 				      &data, &expunged);
+		guid_p = data;
 
 		/* see if we can find this message based on
 		   1) GUID, 2) map_uid */
-		rec = data == NULL ? NULL :
-			hash_table_lookup(ctx->guid_hash, data);
+		rec = guid_p == NULL ? NULL :
+			hash_table_lookup(ctx->guid_hash, guid_p);
 		if (rec == NULL) {
 			/* multi-dbox message that wasn't found with GUID.
 			   either it's lost or GUID has been corrupted. we can
--- a/src/lib-storage/index/index-thread-finish.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/index/index-thread-finish.c	Sun Aug 19 13:55:34 2012 +0300
@@ -59,7 +59,7 @@
 	struct thread_finish_context *ctx;
 
 	pool_t subject_pool;
-	struct hash_table *subject_hash;
+	HASH_TABLE(char *, struct mail_thread_root_node *) subject_hash;
 };
 
 static void
@@ -68,7 +68,6 @@
 {
 	struct mail_thread_root_node *hash_node;
 	char *hash_subject;
-	void *key, *value;
 	bool is_reply_or_forward;
 
 	subject = imap_get_base_subject_cased(pool_datastack_create(), subject,
@@ -79,16 +78,14 @@
 
 	/* (iii) Look up the message associated with the thread
 	   subject in the subject table. */
-	if (!hash_table_lookup_full(ctx->subject_hash, subject, &key, &value)) {
+	if (!hash_table_lookup_full_t(ctx->subject_hash, subject, &hash_subject,
+				      &hash_node)) {
 		/* (iv) If there is no message in the subject table with the
 		   thread subject, add the current message and the thread
 		   subject to the subject table. */
 		hash_subject = p_strdup(ctx->subject_pool, subject);
 		hash_table_insert(ctx->subject_hash, hash_subject, node);
 	} else {
-		hash_subject = key;
-		hash_node = value;
-
 		/* Otherwise, if the message in the subject table is not a
 		   dummy, AND either of the following criteria are true:
 
@@ -222,10 +219,8 @@
 	gather_ctx.subject_pool =
 		pool_alloconly_create(MEMPOOL_GROWING"base subjects",
 				      nearest_power(count * 20));
-	gather_ctx.subject_hash =
-		hash_table_create(gather_ctx.subject_pool,
-				  count * 2, str_hash,
-				  (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&gather_ctx.subject_hash, gather_ctx.subject_pool,
+			  count * 2, str_hash, strcmp);
 
 	i_array_init(&sorted_children, 64);
 	for (i = 0; i < count; i++) {
--- a/src/lib-storage/index/maildir/maildir-filename.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/index/maildir/maildir-filename.c	Sun Aug 19 13:55:34 2012 +0300
@@ -59,9 +59,8 @@
 }
 
 /* a char* hash function from ASU -- from glib */
-unsigned int maildir_filename_base_hash(const void *p)
+unsigned int maildir_filename_base_hash(const char *s)
 {
-        const unsigned char *s = p;
 	unsigned int g, h = 0;
 
 	while (*s != MAILDIR_INFO_SEP && *s != '\0') {
@@ -78,10 +77,8 @@
 	return h;
 }
 
-int maildir_filename_base_cmp(const void *p1, const void *p2)
+int maildir_filename_base_cmp(const char *fname1, const char *fname2)
 {
-	const char *fname1 = p1, *fname2 = p2;
-
 	while (*fname1 == *fname2 && *fname1 != MAILDIR_INFO_SEP &&
 	       *fname1 != '\0') {
 		i_assert(*fname1 != '/');
--- a/src/lib-storage/index/maildir/maildir-filename.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/index/maildir/maildir-filename.h	Sun Aug 19 13:55:34 2012 +0300
@@ -7,8 +7,8 @@
 
 bool maildir_filename_get_size(const char *fname, char type, uoff_t *size_r);
 
-unsigned int maildir_filename_base_hash(const void *p);
-int maildir_filename_base_cmp(const void *p1, const void *p2);
+unsigned int maildir_filename_base_hash(const char *fname);
+int maildir_filename_base_cmp(const char *fname1, const char *fname2);
 int maildir_filename_sort_cmp(const char *fname1, const char *fname2);
 
 #endif
--- a/src/lib-storage/index/maildir/maildir-keywords.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/index/maildir/maildir-keywords.c	Sun Aug 19 13:55:34 2012 +0300
@@ -32,7 +32,7 @@
 
 	pool_t pool;
 	ARRAY_TYPE(keywords) list;
-	struct hash_table *hash; /* name -> idx+1 */
+	HASH_TABLE(char *, unsigned int) hash; /* name -> idx+1 */
 
         struct dotlock_settings dotlock_settings;
 
@@ -74,8 +74,7 @@
 	mk->path = i_strconcat(dir, "/" MAILDIR_KEYWORDS_NAME, NULL);
 	mk->pool = pool_alloconly_create("maildir keywords", 512);
 	i_array_init(&mk->list, MAILDIR_MAX_KEYWORDS);
-	mk->hash = hash_table_create(mk->pool, 0, strcase_hash,
-				     (hash_cmp_callback_t *)strcasecmp);
+	hash_table_create(&mk->hash, mk->pool, 0, strcase_hash, strcasecmp);
 
 	mk->dotlock_settings.use_excl_lock =
 		box->storage->set->dotlock_use_excl;
@@ -177,7 +176,7 @@
 
 		/* save it */
 		new_name = p_strdup(mk->pool, p);
-		hash_table_insert(mk->hash, new_name, POINTER_CAST(idx + 1));
+		hash_table_insert(mk->hash, new_name, idx + 1);
 
 		strp = array_idx_modifiable(&mk->list, idx);
 		*strp = new_name;
@@ -198,10 +197,10 @@
 maildir_keywords_lookup(struct maildir_keywords *mk, const char *name,
 			unsigned int *chridx_r)
 {
-	void *p;
+	unsigned int num;
 
-	p = hash_table_lookup(mk->hash, name);
-	if (p == NULL) {
+	num = hash_table_lookup(mk->hash, name);
+	if (num == 0) {
 		if (mk->synced)
 			return 0;
 
@@ -209,12 +208,12 @@
 			return -1;
 		i_assert(mk->synced);
 
-		p = hash_table_lookup(mk->hash, name);
-		if (p == NULL)
+		num = hash_table_lookup(mk->hash, name);
+		if (num == 0)
 			return 0;
 	}
 
-	*chridx_r = POINTER_CAST_TO(p, int)-1;
+	*chridx_r = num-1;
 	return 1;
 }
 
@@ -228,7 +227,7 @@
 	i_assert(chridx < MAILDIR_MAX_KEYWORDS);
 
 	new_name = p_strdup(mk->pool, name);
-	hash_table_insert(mk->hash, new_name, POINTER_CAST(chridx + 1));
+	hash_table_insert(mk->hash, new_name, chridx + 1);
 
 	strp = array_idx_modifiable(&mk->list, chridx);
 	*strp = new_name;
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Sun Aug 19 13:55:34 2012 +0300
@@ -59,6 +59,9 @@
 };
 ARRAY_DEFINE_TYPE(maildir_uidlist_rec_p, struct maildir_uidlist_rec *);
 
+HASH_TABLE_DEFINE_TYPE(path_to_maildir_uidlist_rec,
+		       char *, struct maildir_uidlist_rec *);
+
 struct maildir_uidlist {
 	struct mailbox *box;
 	char *path;
@@ -76,7 +79,7 @@
 
 	pool_t record_pool;
 	ARRAY_TYPE(maildir_uidlist_rec_p) records;
-	struct hash_table *files;
+	HASH_TABLE_TYPE(path_to_maildir_uidlist_rec) files;
 	unsigned int change_counter;
 
 	unsigned int version;
@@ -105,7 +108,7 @@
 
 	pool_t record_pool;
 	ARRAY_TYPE(maildir_uidlist_rec_p) records;
-	struct hash_table *files;
+	HASH_TABLE_TYPE(path_to_maildir_uidlist_rec) files;
 
 	unsigned int first_unwritten_pos, first_new_pos;
 	unsigned int new_files_count;
@@ -271,9 +274,9 @@
 	uidlist->fd = -1;
 	uidlist->path = i_strconcat(control_dir, "/"MAILDIR_UIDLIST_NAME, NULL);
 	i_array_init(&uidlist->records, 128);
-	uidlist->files = hash_table_create(default_pool, 4096,
-					   maildir_filename_base_hash,
-					   maildir_filename_base_cmp);
+	hash_table_create(&uidlist->files, default_pool, 4096,
+			  maildir_filename_base_hash,
+			  maildir_filename_base_cmp);
 	uidlist->next_uid = 1;
 	uidlist->hdr_extensions = str_new(default_pool, 128);
 
@@ -1650,9 +1653,9 @@
 
 	ctx->record_pool = pool_alloconly_create(MEMPOOL_GROWING
 						 "maildir_uidlist_sync", 16384);
-	ctx->files = hash_table_create(ctx->record_pool, 4096,
-				       maildir_filename_base_hash,
-				       maildir_filename_base_cmp);
+	hash_table_create(&ctx->files, ctx->record_pool, 4096,
+			  maildir_filename_base_hash,
+			  maildir_filename_base_cmp);
 
 	i_array_init(&ctx->records, array_count(&uidlist->records));
 	return 1;
@@ -1978,7 +1981,7 @@
 
 	hash_table_destroy(&uidlist->files);
 	uidlist->files = ctx->files;
-	ctx->files = NULL;
+	memset(&ctx->files, 0, sizeof(ctx->files));
 
 	if (uidlist->record_pool != NULL)
 		pool_unref(&uidlist->record_pool);
@@ -2049,7 +2052,7 @@
 	if (ctx->locked)
 		maildir_uidlist_unlock(ctx->uidlist);
 
-	if (ctx->files != NULL)
+	if (hash_table_is_created(ctx->files))
 		hash_table_destroy(&ctx->files);
 	if (ctx->record_pool != NULL)
 		pool_unref(&ctx->record_pool);
--- a/src/lib-storage/list/mailbox-list-index-sync.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/list/mailbox-list-index-sync.c	Sun Aug 19 13:55:34 2012 +0300
@@ -90,10 +90,8 @@
 		node->next = ctx->ilist->mailbox_tree;
 		ctx->ilist->mailbox_tree = node;
 	}
-	hash_table_insert(ctx->ilist->mailbox_hash,
-			  POINTER_CAST(node->uid), node);
-	hash_table_insert(ctx->ilist->mailbox_names,
-			  POINTER_CAST(node->name_id), dup_name);
+	hash_table_insert(ctx->ilist->mailbox_hash, node->uid, node);
+	hash_table_insert(ctx->ilist->mailbox_names, node->name_id, dup_name);
 
 	node_add_to_index(ctx, node, seq_r);
 	return node;
@@ -184,8 +182,7 @@
 	array_foreach(&existing_name_ids, id_p) {
 		if (*id_p != prev_id) {
 			buffer_append(hdr_buf, id_p, sizeof(*id_p));
-			name = hash_table_lookup(ilist->mailbox_names,
-						 POINTER_CAST(*id_p));
+			name = hash_table_lookup(ilist->mailbox_names, *id_p);
 			buffer_append(hdr_buf, name, strlen(name) + 1);
 			prev_id = *id_p;
 		}
--- a/src/lib-storage/list/mailbox-list-index.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/list/mailbox-list-index.c	Sun Aug 19 13:55:34 2012 +0300
@@ -111,7 +111,7 @@
 struct mailbox_list_index_node *
 mailbox_list_index_lookup_uid(struct mailbox_list_index *ilist, uint32_t uid)
 {
-	return hash_table_lookup(ilist->mailbox_hash, POINTER_CAST(uid));
+	return hash_table_lookup(ilist->mailbox_hash, uid);
 }
 
 void mailbox_list_index_node_get_path(const struct mailbox_list_index_node *node,
@@ -160,7 +160,7 @@
 		i += len + 1;
 
 		/* add id => name to hash table */
-		hash_table_insert(ilist->mailbox_names, POINTER_CAST(id), name);
+		hash_table_insert(ilist->mailbox_names, id, name);
 		ilist->highest_name_id = id;
 	}
 	i_assert(i == size);
@@ -193,7 +193,7 @@
 
 		node->name_id = irec->name_id;
 		node->name = hash_table_lookup(ilist->mailbox_names,
-					       POINTER_CAST(irec->name_id));
+					       irec->name_id);
 		if (node->name == NULL)
 			return -1;
 
@@ -208,8 +208,7 @@
 			node->next = ilist->mailbox_tree;
 			ilist->mailbox_tree = node;
 		}
-		hash_table_insert(ilist->mailbox_hash,
-				  POINTER_CAST(node->uid), node);
+		hash_table_insert(ilist->mailbox_hash, node->uid, node);
 	}
 	return 0;
 }
@@ -439,10 +438,8 @@
 				sizeof(uint32_t));
 
 	ilist->mailbox_pool = pool_alloconly_create("mailbox list index", 4096);
-	ilist->mailbox_names =
-		hash_table_create(ilist->mailbox_pool, 0, NULL, NULL);
-	ilist->mailbox_hash =
-		hash_table_create(ilist->mailbox_pool, 0, NULL, NULL);
+	hash_table_create_direct(&ilist->mailbox_names, ilist->mailbox_pool, 0);
+	hash_table_create_direct(&ilist->mailbox_hash, ilist->mailbox_pool, 0);
 
 	mailbox_list_index_status_init_list(list);
 }
--- a/src/lib-storage/list/mailbox-list-index.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/list/mailbox-list-index.h	Sun Aug 19 13:55:34 2012 +0300
@@ -93,8 +93,8 @@
 	int iter_refcount;
 
 	pool_t mailbox_pool;
-	/* uint32_t id => const char *name */
-	struct hash_table *mailbox_names;
+	/* id => name */
+	HASH_TABLE(uint32_t, char *) mailbox_names;
 	uint32_t highest_name_id;
 
 	uint32_t sync_log_file_seq;
@@ -102,8 +102,8 @@
 	uint32_t sync_stamp;
 	struct timeout *to_refresh;
 
-	/* uint32_t uid => struct mailbox_list_index_node* */
-	struct hash_table *mailbox_hash;
+	/* uid => node */
+	HASH_TABLE(uint32_t, struct mailbox_list_index_node *) mailbox_hash;
 	struct mailbox_list_index_node *mailbox_tree;
 
 	unsigned int opened:1;
--- a/src/lib-storage/mailbox-guid-cache.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/mailbox-guid-cache.c	Sun Aug 19 13:55:34 2012 +0300
@@ -15,15 +15,16 @@
 			    const guid_128_t guid, const char **vname_r)
 {
 	const struct mailbox_guid_cache_rec *rec;
+	const uint8_t *guid_p = guid;
 
-	if (list->guid_cache == NULL) {
+	if (!hash_table_is_created(list->guid_cache)) {
 		mailbox_guid_cache_refresh(list);
-		rec = hash_table_lookup(list->guid_cache, guid);
+		rec = hash_table_lookup(list->guid_cache, guid_p);
 	} else {
-		rec = hash_table_lookup(list->guid_cache, guid);
+		rec = hash_table_lookup(list->guid_cache, guid_p);
 		if (rec == NULL) {
 			mailbox_guid_cache_refresh(list);
-			rec = hash_table_lookup(list->guid_cache, guid);
+			rec = hash_table_lookup(list->guid_cache, guid_p);
 		}
 	}
 	if (rec == NULL) {
@@ -41,13 +42,13 @@
 	struct mailbox *box;
 	struct mailbox_metadata metadata;
 	struct mailbox_guid_cache_rec *rec;
+	uint8_t *guid_p;
 
-	if (list->guid_cache == NULL) {
+	if (!hash_table_is_created(list->guid_cache)) {
 		list->guid_cache_pool =
 			pool_alloconly_create("guid cache", 1024*16);
-		list->guid_cache = hash_table_create(list->guid_cache_pool, 0,
-						     guid_128_hash,
-						     guid_128_cmp);
+		hash_table_create(&list->guid_cache, list->guid_cache_pool, 0,
+				  guid_128_hash, guid_128_cmp);
 	} else {
 		hash_table_clear(list->guid_cache, TRUE);
 		p_clear(list->guid_cache_pool);
@@ -72,7 +73,8 @@
 				    struct mailbox_guid_cache_rec, 1);
 			memcpy(rec->guid, metadata.guid, sizeof(rec->guid));
 			rec->vname = p_strdup(list->guid_cache_pool, info->vname);
-			hash_table_insert(list->guid_cache, rec->guid, rec);
+			guid_p = rec->guid;
+			hash_table_insert(list->guid_cache, guid_p, rec);
 		}
 		mailbox_free(&box);
 	}
--- a/src/lib-storage/mailbox-list-private.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/mailbox-list-private.h	Sun Aug 19 13:55:34 2012 +0300
@@ -135,7 +135,7 @@
 	time_t changelog_timestamp;
 
 	pool_t guid_cache_pool;
-	struct hash_table *guid_cache;
+	HASH_TABLE(uint8_t *, struct mailbox_guid_cache_rec *) guid_cache;
 	bool guid_cache_errors;
 
 	char *error_string;
--- a/src/lib-storage/mailbox-list.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib-storage/mailbox-list.c	Sun Aug 19 13:55:34 2012 +0300
@@ -569,7 +569,7 @@
 	*_list = NULL;
 	i_free_and_null(list->error_string);
 
-	if (list->guid_cache != NULL) {
+	if (hash_table_is_created(list->guid_cache)) {
 		hash_table_destroy(&list->guid_cache);
 		pool_unref(&list->guid_cache_pool);
 	}
--- a/src/lib/child-wait.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib/child-wait.c	Sun Aug 19 13:55:34 2012 +0300
@@ -14,7 +14,7 @@
 	void *context;
 };
 
-struct hash_table *child_pids;
+HASH_TABLE(pid_t, struct child_wait *) child_pids;
 
 #undef child_wait_new_with_pid
 struct child_wait *
@@ -37,6 +37,7 @@
 	struct child_wait *wait = *_wait;
 	struct hash_iterate_context *iter;
 	void *key, *value;
+	pid_t pid;
 
 	*_wait = NULL;
 
@@ -45,7 +46,8 @@
 		iter = hash_table_iterate_init(child_pids);
 		while (hash_table_iterate(iter, &key, &value)) {
 			if (value == wait) {
-				hash_table_remove(child_pids, key);
+				pid = POINTER_CAST_TO(key, pid_t);
+				hash_table_remove(child_pids, pid);
 				if (--wait->pid_count == 0)
 					break;
 			}
@@ -59,13 +61,13 @@
 void child_wait_add_pid(struct child_wait *wait, pid_t pid)
 {
 	wait->pid_count++;
-	hash_table_insert(child_pids, POINTER_CAST(pid), wait);
+	hash_table_insert(child_pids, pid, wait);
 }
 
 void child_wait_remove_pid(struct child_wait *wait, pid_t pid)
 {
 	wait->pid_count--;
-	hash_table_remove(child_pids, POINTER_CAST(pid));
+	hash_table_remove(child_pids, pid);
 }
 
 static void
@@ -74,8 +76,7 @@
 	struct child_wait_status status;
 
 	while ((status.pid = waitpid(-1, &status.status, WNOHANG)) > 0) {
-		status.wait = hash_table_lookup(child_pids,
-						POINTER_CAST(status.pid));
+		status.wait = hash_table_lookup(child_pids, status.pid);
 		if (status.wait != NULL) {
 			child_wait_remove_pid(status.wait, status.pid);
 			status.wait->callback(&status, status.wait->context);
@@ -88,7 +89,7 @@
 
 void child_wait_init(void)
 {
-	child_pids = hash_table_create(default_pool, 0, NULL, NULL);
+	hash_table_create_direct(&child_pids, default_pool, 0);
 
 	lib_signals_set_handler(SIGCHLD, LIBSIG_FLAGS_SAFE,
 				sigchld_handler, NULL);
--- a/src/lib/guid.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib/guid.c	Sun Aug 19 13:55:34 2012 +0300
@@ -102,16 +102,12 @@
 	return binary_to_hex(guid, GUID_128_SIZE);
 }
 
-unsigned int guid_128_hash(const void *p)
+unsigned int guid_128_hash(const uint8_t *guid)
 {
-	const uint8_t *guid = p;
-
 	return mem_hash(guid, GUID_128_SIZE);
 }
 
-int guid_128_cmp(const void *p1, const void *p2)
+int guid_128_cmp(const uint8_t *guid1, const uint8_t *guid2)
 {
-	const uint8_t *g1 = p1, *g2 = p2;
-
-	return memcmp(g1, g2, GUID_128_SIZE);
+	return memcmp(guid1, guid2, GUID_128_SIZE);
 }
--- a/src/lib/guid.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib/guid.h	Sun Aug 19 13:55:34 2012 +0300
@@ -17,7 +17,7 @@
 int guid_128_from_string(const char *str, guid_128_t guid_r);
 
 /* guid_128 hash/cmp functions for hash.h */
-unsigned int guid_128_hash(const void *p);
-int guid_128_cmp(const void *p1, const void *p2);
+unsigned int guid_128_hash(const uint8_t *guid);
+int guid_128_cmp(const uint8_t *guid1, const uint8_t *guid2);
 
 #endif
--- a/src/lib/hash.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib/hash.c	Sun Aug 19 13:55:34 2012 +0300
@@ -10,6 +10,22 @@
 
 #define HASH_TABLE_MIN_SIZE 131
 
+#undef hash_table_create
+#undef hash_table_create_direct
+#undef hash_table_destroy
+#undef hash_table_clear
+#undef hash_table_lookup
+#undef hash_table_lookup_full
+#undef hash_table_insert
+#undef hash_table_update
+#undef hash_table_remove
+#undef hash_table_count
+#undef hash_table_iterate_init
+#undef hash_table_iterate
+#undef hash_table_freeze
+#undef hash_table_thaw
+#undef hash_table_copy
+
 struct hash_node {
 	struct hash_node *next;
 	void *key;
@@ -38,9 +54,24 @@
 
 static bool hash_table_resize(struct hash_table *table, bool grow);
 
-static int direct_cmp(const void *p1, const void *p2)
+void hash_table_create(struct hash_table **table_r, pool_t node_pool,
+		       unsigned int initial_size, hash_callback_t *hash_cb,
+		       hash_cmp_callback_t *key_compare_cb)
 {
-	return p1 == p2 ? 0 : 1;
+	struct hash_table *table;
+
+	pool_ref(node_pool);
+	table = i_new(struct hash_table, 1);
+	table->node_pool = node_pool;
+	table->initial_size =
+		I_MAX(primes_closest(initial_size), HASH_TABLE_MIN_SIZE);
+
+	table->hash_cb = hash_cb;
+	table->key_compare_cb = key_compare_cb;
+
+	table->size = table->initial_size;
+	table->nodes = i_new(struct hash_node, table->size);
+	*table_r = table;
 }
 
 static unsigned int direct_hash(const void *p)
@@ -49,24 +80,16 @@
 	return POINTER_CAST_TO(p, unsigned int);
 }
 
-struct hash_table *
-hash_table_create(pool_t node_pool, unsigned int initial_size,
-		  hash_callback_t *hash_cb, hash_cmp_callback_t *key_compare_cb)
+static int direct_cmp(const void *p1, const void *p2)
 {
-	struct hash_table *table;
+	return p1 == p2 ? 0 : 1;
+}
 
-	table = i_new(struct hash_table, 1);
-	table->node_pool = node_pool;
-	table->initial_size =
-		I_MAX(primes_closest(initial_size), HASH_TABLE_MIN_SIZE);
-
-	table->hash_cb = hash_cb != NULL ? hash_cb : direct_hash;
-	table->key_compare_cb = key_compare_cb == NULL ?
-		direct_cmp : key_compare_cb;
-
-	table->size = table->initial_size;
-	table->nodes = i_new(struct hash_node, table->size);
-	return table;
+void hash_table_create_direct(struct hash_table **table_r, pool_t node_pool,
+			      unsigned int initial_size)
+{
+	hash_table_create(table_r, node_pool, initial_size,
+			  direct_hash, direct_cmp);
 }
 
 static void free_node(struct hash_table *table, struct hash_node *node)
@@ -111,6 +134,7 @@
 		destroy_node_list(table, table->free_nodes);
 	}
 
+	pool_unref(&table->node_pool);
 	i_free(table->nodes);
 	i_free(table);
 }
@@ -159,9 +183,9 @@
 	return node != NULL ? node->value : NULL;
 }
 
-bool hash_table_lookup_full(const struct hash_table *table,
-			    const void *lookup_key,
-			    void **orig_key, void **value)
+bool hash_table_lookup_full_i(const struct hash_table *table,
+			      const void *lookup_key,
+			      void **orig_key, void **value)
 {
 	struct hash_node *node;
 
@@ -474,9 +498,9 @@
 }
 
 /* a char* hash function from ASU -- from glib */
-unsigned int str_hash(const void *p)
+unsigned int str_hash(const char *p)
 {
-        const unsigned char *s = p;
+        const unsigned char *s = (const unsigned char *)p;
 	unsigned int g, h = 0;
 
 	while (*s != '\0') {
@@ -492,9 +516,9 @@
 }
 
 /* a char* hash function from ASU -- from glib */
-unsigned int strcase_hash(const void *p)
+unsigned int strcase_hash(const char *p)
 {
-        const unsigned char *s = p;
+        const unsigned char *s = (const unsigned char *)p;
 	unsigned int g, h = 0;
 
 	while (*s != '\0') {
--- a/src/lib/hash.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib/hash.h	Sun Aug 19 13:55:34 2012 +0300
@@ -1,59 +1,155 @@
 #ifndef HASH_H
 #define HASH_H
 
+struct hash_table;
+
+#ifdef __GNUC__
+#  define HASH_VALUE_CAST(table) (typeof((table)._value))
+#else
+#  define HASH_VALUE_CAST(table)
+#endif
+
 /* Returns hash code. */
 typedef unsigned int hash_callback_t(const void *p);
 /* Returns 0 if the pointers are equal. */
 typedef int hash_cmp_callback_t(const void *p1, const void *p2);
 
 /* Create a new hash table. If initial_size is 0, the default value is used.
-   If hash_cb or key_compare_cb is NULL, direct hashing/comparing is used.
-
    table_pool is used to allocate/free large hash tables, node_pool is used
    for smaller allocations and can also be alloconly pool. The pools must not
    be free'd before hash_table_destroy() is called. */
-struct hash_table *
-hash_table_create(pool_t node_pool, unsigned int initial_size,
-		  hash_callback_t *hash_cb, hash_cmp_callback_t *key_compare_cb)
-	ATTR_NULL(4, 5);
+void hash_table_create(struct hash_table **table_r, pool_t node_pool,
+		       unsigned int initial_size,
+		       hash_callback_t *hash_cb,
+		       hash_cmp_callback_t *key_compare_cb);
+#if defined (__GNUC__) && !defined(__cplusplus)
+#  define hash_table_create(table, pool, size, hash_cb, key_cmp_cb) \
+	({(void)COMPILE_ERROR_IF_TRUE( \
+		sizeof((*table)._key) > sizeof(void *) || \
+		sizeof((*table)._value) > sizeof(void *)); \
+	(void)COMPILE_ERROR_IF_TRUE( \
+		!__builtin_types_compatible_p(typeof(&key_cmp_cb), \
+			int (*)(typeof((*table)._key), typeof((*table)._key))) && \
+		!__builtin_types_compatible_p(typeof(&key_cmp_cb), \
+			int (*)(typeof((*table)._const_key), typeof((*table)._const_key)))); \
+	(void)COMPILE_ERROR_IF_TRUE( \
+		!__builtin_types_compatible_p(typeof(&hash_cb), \
+			unsigned int (*)(typeof((*table)._key))) && \
+		!__builtin_types_compatible_p(typeof(&hash_cb), \
+			unsigned int (*)(typeof((*table)._const_key)))); \
+	hash_table_create(&(*table)._table, pool, size, \
+		(hash_callback_t *)hash_cb, \
+		(hash_cmp_callback_t *)key_cmp_cb);})
+#else
+#  define hash_table_create(table, pool, size, hash_cb, key_cmp_cb) \
+	hash_table_create(&(*table)._table, pool, size, \
+		(hash_callback_t *)hash_cb, \
+		(hash_cmp_callback_t *)key_cmp_cb)
+#endif
+
+/* Create hash table where comparisons are done directly with the pointers. */
+void hash_table_create_direct(struct hash_table **table_r, pool_t node_pool,
+			      unsigned int initial_size);
+#if defined (__GNUC__) && !defined(__cplusplus)
+#  define hash_table_create_direct(table, pool, size) \
+	({(void)COMPILE_ERROR_IF_TRUE( \
+		sizeof((*table)._key) > sizeof(void *) || \
+		sizeof((*table)._value) > sizeof(void *)); \
+	hash_table_create_direct(&(*table)._table, pool, size);})
+#else
+#  define hash_table_create_direct(table, pool, size) \
+	hash_table_create_direct(&(*table)._table, pool, size)
+#endif
+
+#define hash_table_is_created(table) \
+	((table)._table != NULL)
+
 void hash_table_destroy(struct hash_table **table);
+#define hash_table_destroy(table) \
+	hash_table_destroy(&(*table)._table)
 /* Remove all nodes from hash table. If free_collisions is TRUE, the
    memory allocated from node_pool is freed, or discarded with
    alloconly pools. */
 void hash_table_clear(struct hash_table *table, bool free_collisions);
+#define hash_table_clear(table, free_collisions) \
+	hash_table_clear((table)._table, free_collisions)
 
 void *hash_table_lookup(const struct hash_table *table, const void *key) ATTR_PURE;
-bool hash_table_lookup_full(const struct hash_table *table,
-			    const void *lookup_key,
-			    void **orig_key, void **value);
+#define hash_table_lookup(table, key) \
+	HASH_VALUE_CAST(table)hash_table_lookup((table)._table, \
+		(const void *)((const char *)(key) + COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE((table)._key, (table)._const_key, key)))
+
+bool hash_table_lookup_full_i(const struct hash_table *table,
+			      const void *lookup_key,
+			      void **orig_key_r, void **value_r);
+/* Type-safe lookup_full requires that key and value types are pointers. */
+#define hash_table_lookup_full_t(table, lookup_key, orig_key_r, value_r) \
+	hash_table_lookup_full_i((table)._table, \
+		(void *)((const char *)(lookup_key) + COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE((table)._const_key, (table)._key, lookup_key)), \
+		(void **)(orig_key_r) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._keyp, orig_key_r) + \
+			COMPILE_ERROR_IF_TRUE(sizeof(*orig_key_r) != sizeof(void *)), \
+		(void **)(value_r) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._valuep, value_r) + \
+			COMPILE_ERROR_IF_TRUE(sizeof(*value_r) != sizeof(void *)))
+/* Type-unsafe lookup_full works for all types. */
+#define hash_table_lookup_full(table, lookup_key, orig_key_r, value_r) \
+	hash_table_lookup_full_i((table)._table, lookup_key, orig_key_r, value_r)
 
 /* Insert/update node in hash table. The difference is that hash_table_insert()
    replaces the key in table to given one, while hash_table_update() doesnt. */
 void hash_table_insert(struct hash_table *table, void *key, void *value);
 void hash_table_update(struct hash_table *table, void *key, void *value);
+#define hash_table_insert(table, key, value) \
+	hash_table_insert((table)._table, \
+		(void *)((char*)(key) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._key, key)), \
+		(void *)((char*)(value) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._value, value)))
+#define hash_table_update(table, key, value) \
+	hash_table_update((table)._table, \
+		(void *)((char *)(key) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._key, key)), \
+		(void *)((char *)(value) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._value, value)))
 
 void hash_table_remove(struct hash_table *table, const void *key);
+#define hash_table_remove(table, key) \
+	hash_table_remove((table)._table, \
+		(const void *)((const char *)(key) + COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE((table)._const_key, (table)._key, key)))
 unsigned int hash_table_count(const struct hash_table *table) ATTR_PURE;
+#define hash_table_count(table) \
+	hash_table_count((table)._table)
 
 /* Iterates through all nodes in hash table. You may safely call hash_table_*()
    functions while iterating, but if you add any new nodes, they may or may
    not be called for in this iteration. */
 struct hash_iterate_context *hash_table_iterate_init(struct hash_table *table);
+#define hash_table_iterate_init(table) \
+	hash_table_iterate_init((table)._table)
+/* Type-unsafe iterate works for all types. */
 bool hash_table_iterate(struct hash_iterate_context *ctx,
 			void **key_r, void **value_r);
+/* Type-safe iterate requires that key and value types are pointers. */
+#define hash_table_iterate_t(ctx, table, key_r, value_r) \
+	hash_table_iterate(ctx, \
+		(void **)(key_r) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._keyp, key_r) + \
+			COMPILE_ERROR_IF_TRUE(sizeof(*key_r) != sizeof(void *)) + \
+			COMPILE_ERROR_IF_TRUE(sizeof(*value_r) != sizeof(void *)), \
+		(void **)(value_r) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._valuep, value_r))
 void hash_table_iterate_deinit(struct hash_iterate_context **ctx);
 
 /* Hash table isn't resized, and removed nodes aren't removed from
    the list while hash table is freezed. Supports nesting. */
 void hash_table_freeze(struct hash_table *table);
 void hash_table_thaw(struct hash_table *table);
+#define hash_table_freeze(table) \
+	hash_table_freeze((table)._table)
+#define hash_table_thaw(table) \
+	hash_table_thaw((table)._table)
 
 /* Copy all nodes from one hash table to another */
 void hash_table_copy(struct hash_table *dest, struct hash_table *src);
+#define hash_table_copy(table1, table2) \
+	hash_table_copy((table1)._table, (table2)._table)
 
 /* hash function for strings */
-unsigned int str_hash(const void *p) ATTR_PURE;
-unsigned int strcase_hash(const void *p) ATTR_PURE;
+unsigned int str_hash(const char *p) ATTR_PURE;
+unsigned int strcase_hash(const char *p) ATTR_PURE;
 /* a generic hash for a given memory block */
 unsigned int mem_hash(const void *p, unsigned int size) ATTR_PURE;
 
--- a/src/lib/lib.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib/lib.h	Sun Aug 19 13:55:34 2012 +0300
@@ -36,6 +36,7 @@
 struct ostream;
 
 #include "array-decl.h" /* ARRAY_DEFINE()s may exist in any header */
+#include "hash-decl.h" /* HASH_TABLE*()s may exist in any header */
 #include "strfuncs.h"
 #include "strnum.h"
 
--- a/src/lib/macros.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/lib/macros.h	Sun Aug 19 13:55:34 2012 +0300
@@ -159,16 +159,21 @@
 	name(__VA_ARGS__, (callback_type *)callback, context)
 #endif
 
-#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0)
+#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0)) && !defined(__cplusplus)
 #  define HAVE_TYPEOF
 #  define COMPILE_ERROR_IF_TRUE(condition) \
 	(sizeof(char[1 - 2 * !!(condition)]) - 1)
 #  define COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(_a, _b) \
 	COMPILE_ERROR_IF_TRUE( \
 		!__builtin_types_compatible_p(typeof(_a), typeof(_b)))
+#define COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE(_a1, _a2, _b) \
+	COMPILE_ERROR_IF_TRUE( \
+		!__builtin_types_compatible_p(typeof(_a1), typeof(_b)) && \
+		!__builtin_types_compatible_p(typeof(_a2), typeof(_b)))
 #else
 #  define COMPILE_ERROR_IF_TRUE(condition) 0
 #  define COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(_a, _b) 0
+#  define COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE(_a1, _a2, _b) 0
 #endif
 
 #if __GNUC__ > 2
--- a/src/log/log-connection.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/log/log-connection.c	Sun Aug 19 13:55:34 2012 +0300
@@ -33,8 +33,7 @@
 	struct istream *input;
 
 	char *default_prefix;
-	/* pid -> struct log_client* */
-	struct hash_table *clients;
+	HASH_TABLE(pid_t, struct log_client *) clients;
 
 	unsigned int master:1;
 	unsigned int handshaked:1;
@@ -49,10 +48,10 @@
 {
 	struct log_client *client;
 
-	client = hash_table_lookup(log->clients, POINTER_CAST(pid));
+	client = hash_table_lookup(log->clients, pid);
 	if (client == NULL) {
 		client = i_new(struct log_client, 1);
-		hash_table_insert(log->clients, POINTER_CAST(pid), client);
+		hash_table_insert(log->clients, pid, client);
 	}
 	return client;
 }
@@ -60,7 +59,7 @@
 static void log_client_free(struct log_connection *log,
 			    struct log_client *client, pid_t pid)
 {
-	hash_table_remove(log->clients, POINTER_CAST(pid));
+	hash_table_remove(log->clients, pid);
 
 	i_free(client->prefix);
 	i_free(client);
@@ -141,7 +140,7 @@
 	const char *p, *p2, *cmd;
 	unsigned int count;
 	int service_fd;
-	long pid;
+	pid_t pid;
 
 	p = strchr(line, ' ');
 	if (p == NULL || (p2 = strchr(++p, ' ')) == NULL) {
@@ -164,7 +163,7 @@
 		return;
 	}
 	log = logs[service_fd];
-	client = hash_table_lookup(log->clients, POINTER_CAST(pid));
+	client = hash_table_lookup(log->clients, pid);
 
 	if (strcmp(cmd, "BYE") == 0) {
 		if (client == NULL) {
@@ -212,8 +211,7 @@
 		log_parse_option(log, &failure);
 		return;
 	default:
-		client = hash_table_lookup(log->clients,
-					   POINTER_CAST(failure.pid));
+		client = hash_table_lookup(log->clients, failure.pid);
 		break;
 	}
 	i_assert(failure.log_type < LOG_TYPE_COUNT);
@@ -317,7 +315,7 @@
 	log->listen_fd = listen_fd;
 	log->io = io_add(fd, IO_READ, log_connection_input, log);
 	log->input = i_stream_create_fd(fd, PIPE_BUF, FALSE);
-	log->clients = hash_table_create(default_pool, 0, NULL, NULL);
+	hash_table_create_direct(&log->clients, default_pool, 0);
 	array_idx_set(&logs_by_fd, listen_fd, &log);
 
 	DLLIST_PREPEND(&log_connections, log);
--- a/src/login-common/login-proxy-state.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/login-common/login-proxy-state.c	Sun Aug 19 13:55:34 2012 +0300
@@ -14,7 +14,8 @@
 #define NOTIFY_RETRY_REOPEN_MSECS (60*1000)
 
 struct login_proxy_state {
-	struct hash_table *hash;
+	HASH_TABLE(struct login_proxy_record *,
+		   struct login_proxy_record *) hash;
 	pool_t pool;
 
 	const char *notify_path;
@@ -25,17 +26,15 @@
 
 static int login_proxy_state_notify_open(struct login_proxy_state *state);
 
-static unsigned int login_proxy_record_hash(const void *p)
+static unsigned int
+login_proxy_record_hash(const struct login_proxy_record *rec)
 {
-	const struct login_proxy_record *rec = p;
-
 	return net_ip_hash(&rec->ip) ^ rec->port;
 }
 
-static int login_proxy_record_cmp(const void *p1, const void *p2)
+static int login_proxy_record_cmp(struct login_proxy_record *rec1,
+				  struct login_proxy_record *rec2)
 {
-	const struct login_proxy_record *rec1 = p1, *rec2 = p2;
-
 	if (!net_ip_compare(&rec1->ip, &rec2->ip))
 		return 1;
 
@@ -48,9 +47,8 @@
 
 	state = i_new(struct login_proxy_state, 1);
 	state->pool = pool_alloconly_create("login proxy state", 1024);
-	state->hash = hash_table_create(state->pool, 0,
-					login_proxy_record_hash,
-					login_proxy_record_cmp);
+	hash_table_create(&state->hash, state->pool, 0,
+			  login_proxy_record_hash, login_proxy_record_cmp);
 	state->notify_path = p_strdup(state->pool, notify_path);
 	state->notify_fd = -1;
 	return state;
--- a/src/login-common/ssl-proxy-openssl.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/login-common/ssl-proxy-openssl.c	Sun Aug 19 13:55:34 2012 +0300
@@ -98,7 +98,8 @@
 };
 
 static int extdata_index;
-static struct hash_table *ssl_servers;
+static HASH_TABLE(struct ssl_server_context *,
+		  struct ssl_server_context *) ssl_servers;
 static SSL_CTX *ssl_client_ctx;
 static unsigned int ssl_proxy_count;
 static struct ssl_proxy *ssl_proxies;
@@ -118,9 +119,8 @@
 			const struct master_service_ssl_settings *ssl_set);
 static void ssl_server_context_deinit(struct ssl_server_context **_ctx);
 
-static unsigned int ssl_server_context_hash(const void *p)
+static unsigned int ssl_server_context_hash(const struct ssl_server_context *ctx)
 {
-	const struct ssl_server_context *ctx = p;
 	unsigned int i, g, h = 0;
 
 	/* checking for different certs is typically good enough,
@@ -135,10 +135,9 @@
 	return h;
 }
 
-static int ssl_server_context_cmp(const void *p1, const void *p2)
+static int ssl_server_context_cmp(const struct ssl_server_context *ctx1,
+				  const struct ssl_server_context *ctx2)
 {
-	const struct ssl_server_context *ctx1 = p1, *ctx2 = p2;
-
 	if (strcmp(ctx1->cert, ctx2->cert) != 0)
 		return 1;
 	if (strcmp(ctx1->key, ctx2->key) != 0)
@@ -1292,9 +1291,8 @@
 
 	extdata_index = SSL_get_ex_new_index(0, dovecot, NULL, NULL, NULL);
 
-	ssl_servers = hash_table_create(default_pool, 0,
-					ssl_server_context_hash,
-					ssl_server_context_cmp);
+	hash_table_create(&ssl_servers, default_pool, 0,
+			  ssl_server_context_hash, ssl_server_context_cmp);
 	(void)ssl_server_context_init(login_set, ssl_set);
 
 	ssl_proxy_init_client(login_set, ssl_set);
@@ -1321,7 +1319,7 @@
 void ssl_proxy_deinit(void)
 {
 	struct hash_iterate_context *iter;
-	void *key, *value;
+	struct ssl_server_context *ctx;
 
 	if (!ssl_initialized)
 		return;
@@ -1330,11 +1328,8 @@
 		ssl_proxy_destroy(ssl_proxies);
 
 	iter = hash_table_iterate_init(ssl_servers);
-	while (hash_table_iterate(iter, &key, &value)) {
-		struct ssl_server_context *ctx = value;
-
+	while (hash_table_iterate_t(iter, ssl_servers, &ctx, &ctx))
 		ssl_server_context_deinit(&ctx);
-	}
 	hash_table_iterate_deinit(&iter);
 	hash_table_destroy(&ssl_servers);
 
--- a/src/master/service-monitor.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/master/service-monitor.c	Sun Aug 19 13:55:34 2012 +0300
@@ -122,7 +122,7 @@
 {
         struct service_process *process;
 
-	process = hash_table_lookup(service_pids, &status->pid);
+	process = hash_table_lookup(service_pids, status->pid);
 	if (process == NULL) {
 		/* we've probably wait()ed it away already. ignore */
 		return;
@@ -574,7 +574,7 @@
 	bool service_stopped, throttle;
 
 	while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
-		process = hash_table_lookup(service_pids, &pid);
+		process = hash_table_lookup(service_pids, pid);
 		if (process == NULL) {
 			i_error("waitpid() returned unknown PID %s",
 				dec2str(pid));
--- a/src/master/service-process.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/master/service-process.c	Sun Aug 19 13:55:34 2012 +0300
@@ -322,7 +322,7 @@
 	DLLIST_PREPEND(&service->processes, process);
 
 	service_list_ref(service->list);
-	hash_table_insert(service_pids, &process->pid, process);
+	hash_table_insert(service_pids, process->pid, process);
 
 	if (service->type == SERVICE_TYPE_ANVIL && process_forked)
 		service_anvil_process_created(process);
@@ -335,7 +335,7 @@
 	struct service_list *service_list = service->list;
 
 	DLLIST_REMOVE(&service->processes, process);
-	hash_table_remove(service_pids, &process->pid);
+	hash_table_remove(service_pids, process->pid);
 
 	if (process->available_count > 0)
 		service->process_avail--;
--- a/src/master/service.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/master/service.c	Sun Aug 19 13:55:34 2012 +0300
@@ -19,7 +19,7 @@
 #define SERVICE_DIE_TIMEOUT_MSECS (1000*60)
 #define SERVICE_LOGIN_NOTIFY_MIN_INTERVAL_SECS 2
 
-struct hash_table *service_pids;
+HASH_TABLE_TYPE(pid_process) service_pids;
 
 void service_error(struct service *service, const char *format, ...)
 {
@@ -376,21 +376,6 @@
 	return service;
 }
 
-static unsigned int pid_hash(const void *p)
-{
-	const pid_t *pid = p;
-
-	return (unsigned int)*pid;
-}
-
-static int pid_hash_cmp(const void *p1, const void *p2)
-{
-	const pid_t *pid1 = p1, *pid2 = p2;
-
-	return *pid1 < *pid2 ? -1 :
-		*pid1 > *pid2 ? 1 : 0;
-}
-
 struct service *
 service_lookup(struct service_list *service_list, const char *name)
 {
@@ -726,8 +711,7 @@
 
 void service_pids_init(void)
 {
-	service_pids = hash_table_create(default_pool, 0,
-					 pid_hash, pid_hash_cmp);
+	hash_table_create_direct(&service_pids, default_pool, 0);
 }
 
 void service_pids_deinit(void)
--- a/src/master/service.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/master/service.h	Sun Aug 19 13:55:34 2012 +0300
@@ -142,7 +142,8 @@
 	unsigned int sigterm_sent_to_log:1;
 };
 
-extern struct hash_table *service_pids;
+HASH_TABLE_DEFINE_TYPE(pid_process, pid_t, struct service_process *);
+extern HASH_TABLE_TYPE(pid_process) service_pids;
 
 /* Create all services from settings */
 int services_create(const struct master_settings *set,
--- a/src/plugins/acl/acl-cache.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/plugins/acl/acl-cache.c	Sun Aug 19 13:55:34 2012 +0300
@@ -21,7 +21,8 @@
 
 struct acl_cache {
 	struct acl_backend *backend;
-	struct hash_table *objects; /* name => struct acl_object_cache* */
+	/* name => object */
+	HASH_TABLE(char *, struct acl_object_cache *) objects;
 
 	size_t validity_rec_size;
 
@@ -31,8 +32,8 @@
 	pool_t right_names_pool;
 	/* idx => right name. */
 	ARRAY_DEFINE(right_idx_name_map, const char *);
-	/* name => idx */
-	struct hash_table *right_name_idx_map;
+	/* name => idx+1 */
+	HASH_TABLE(char *, unsigned int) right_name_idx_map;
 };
 
 static struct acl_mask negative_cache_entry;
@@ -47,11 +48,9 @@
 	cache->validity_rec_size = validity_rec_size;
 	cache->right_names_pool =
 		pool_alloconly_create("ACL right names", 1024);
-	cache->objects = hash_table_create(default_pool, 0,
-					   str_hash, (hash_cmp_callback_t *)strcmp);
-	cache->right_name_idx_map =
-		hash_table_create(cache->right_names_pool, 0,
-				  str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&cache->objects, default_pool, 0, str_hash, strcmp);
+	hash_table_create(&cache->right_name_idx_map,
+			  cache->right_names_pool, 0, str_hash, strcmp);
 	i_array_init(&cache->right_idx_name_map, DEFAULT_ACL_RIGHTS_COUNT);
 	return cache;
 }
@@ -143,23 +142,21 @@
 unsigned int acl_cache_right_lookup(struct acl_cache *cache, const char *right)
 {
 	unsigned int idx;
-	void *idx_p;
 	char *name;
 	const char *const_name;
 
 	/* use +1 for right_name_idx_map values because we can't add NULL
 	   values. */
-	idx_p = hash_table_lookup(cache->right_name_idx_map, right);
-	if (idx_p == NULL) {
+	idx = hash_table_lookup(cache->right_name_idx_map, right);
+	if (idx == 0) {
 		/* new right name, add it */
 		const_name = name = p_strdup(cache->right_names_pool, right);
 
 		idx = array_count(&cache->right_idx_name_map);
 		array_append(&cache->right_idx_name_map, &const_name, 1);
-		hash_table_insert(cache->right_name_idx_map, name,
-				  POINTER_CAST(idx + 1));
+		hash_table_insert(cache->right_name_idx_map, name, idx + 1);
 	} else {
-		idx = POINTER_CAST_TO(idx_p, unsigned int)-1;
+		idx--;
 	}
 	return idx;
 }
@@ -178,14 +175,12 @@
 void acl_cache_flush_all(struct acl_cache *cache)
 {
 	struct hash_iterate_context *iter;
-	void *key, *value;
+	char *key;
+	struct acl_object_cache *obj_cache;
 
 	iter = hash_table_iterate_init(cache->objects);
-	while (hash_table_iterate(iter, &key, &value)) {
-		struct acl_object_cache *obj_cache = value;
-
+	while (hash_table_iterate_t(iter, cache->objects, &key, &obj_cache))
 		acl_cache_free_object_cache(obj_cache);
-	}
 	hash_table_iterate_deinit(&iter);
 
 	hash_table_clear(cache->objects, FALSE);
--- a/src/plugins/expire/doveadm-expire.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/plugins/expire/doveadm-expire.c	Sun Aug 19 13:55:34 2012 +0300
@@ -33,7 +33,7 @@
 	struct dict_transaction_context *trans;
 	struct dict_iterate_context *iter;
 
-	struct hash_table *users;
+	HASH_TABLE(char *, enum expire_user_state) user_states;
 	ARRAY_DEFINE(queries, struct expire_query);
 	time_t oldest_before_time;
 	bool delete_nonexistent_users;
@@ -79,6 +79,7 @@
 	const char *username, *mailbox;
 	enum expire_user_state state;
 	void *key, *value;
+	char *orig_username;
 
 	/* dict_key = DICT_EXPIRE_PREFIX<user>/<mailbox> */
 	username = dict_key + strlen(DICT_EXPIRE_PREFIX);
@@ -90,7 +91,8 @@
 	}
 	username = t_strdup_until(username, mailbox++);
 
-	if (!hash_table_lookup_full(ectx->users, username, &key, &value)) {
+	if (!hash_table_lookup_full(ectx->user_states, username,
+				    &key, &value)) {
 		/* user no longer exists, delete the record */
 		return -1;
 	}
@@ -110,9 +112,10 @@
 		/* this mailbox doesn't have any matching messages */
 		return 0;
 	}
-	hash_table_update(ectx->users, key,
-			  POINTER_CAST(EXPIRE_USER_STATE_SEEN));
-	*username_r = key;
+	state = EXPIRE_USER_STATE_SEEN;
+	orig_username = key;
+	hash_table_update(ectx->user_states, orig_username, state);
+	*username_r = orig_username;
 	return 1;
 }
 
@@ -356,7 +359,7 @@
 	if (dict_transaction_commit(&ectx->trans) < 0)
 		i_error("expire: Dictionary commit failed");
 	dict_deinit(&ectx->dict);
-	hash_table_destroy(&ectx->users);
+	hash_table_destroy(&ectx->user_states);
 
 	ectx->module_ctx.super.deinit(ctx);
 }
@@ -368,6 +371,7 @@
 	const struct expire_query *query;
 	const char *expire_dict, *username, *value;
 	char *username_dup;
+	enum expire_user_state state;
 
 	if (ctx->search_args == NULL)
 		return;
@@ -416,12 +420,11 @@
 	ctx->v.deinit = doveadm_expire_mail_cmd_deinit;
 	ctx->v.get_next_user = doveadm_expire_mail_cmd_get_next_user;
 
-	ectx->users = hash_table_create(ctx->pool, 0, str_hash,
-					(hash_cmp_callback_t *)strcmp);
+	hash_table_create(&ectx->user_states, ctx->pool, 0, str_hash, strcmp);
 	while (mail_storage_service_all_next(ctx->storage_service, &username) > 0) {
 		username_dup = p_strdup(ctx->pool, username);
-		hash_table_insert(ectx->users, username_dup,
-				  POINTER_CAST(EXPIRE_USER_STATE_EXISTS));
+		state = EXPIRE_USER_STATE_EXISTS;
+		hash_table_insert(ectx->user_states, username_dup, state);
 	}
 
 	ectx->dict = dict;
--- a/src/plugins/fts-lucene/fts-backend-lucene.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/plugins/fts-lucene/fts-backend-lucene.c	Sun Aug 19 13:55:34 2012 +0300
@@ -471,9 +471,8 @@
 }
 
 /* a char* hash function from ASU -- from glib */
-static unsigned int wstr_hash(const void *p)
+static unsigned int wstr_hash(const wchar_t *s)
 {
-        const wchar_t *s = p;
 	unsigned int g, h = 0;
 
 	while (*s != '\0') {
@@ -490,7 +489,8 @@
 
 static int
 mailboxes_get_guids(struct mailbox *const boxes[],
-		    struct hash_table *guids, struct fts_multi_result *result)
+		    HASH_TABLE_TYPE(wguid_result) guids,
+		    struct fts_multi_result *result)
 {
 	ARRAY_DEFINE(box_results, struct fts_result);
 	struct fts_result *box_result;
@@ -529,10 +529,9 @@
 	int ret;
 
 	T_BEGIN {
-		struct hash_table *guids;
+		HASH_TABLE_TYPE(wguid_result) guids;
 
-		guids = hash_table_create(default_pool, 0, wstr_hash,
-					  (hash_cmp_callback_t *)wcscmp);
+		hash_table_create(&guids, default_pool, 0, wstr_hash, wcscmp);
 		ret = mailboxes_get_guids(boxes, guids, result);
 		if (ret == 0) {
 			ret = lucene_index_lookup_multi(backend->index,
--- a/src/plugins/fts-lucene/lucene-wrapper.cc	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/plugins/fts-lucene/lucene-wrapper.cc	Sun Aug 19 13:55:34 2012 +0300
@@ -80,7 +80,7 @@
 	int box_ret;
 
 	pool_t pool;
-	struct hash_table *guids;
+	HASH_TABLE(uint8_t *, uint8_t *) seen_mailbox_guids;
 
 	ARRAY_TYPE(seq_range) uids;
 	struct seq_range_iter uids_iter;
@@ -95,7 +95,7 @@
 static int textcat_refcount = 0;
 
 static void rescan_clear_unseen_mailboxes(struct lucene_index *index,
-					  struct hash_table *guids);
+					  struct rescan_context *rescan_ctx);
 
 struct lucene_index *lucene_index_init(const char *path,
 				       struct mailbox_list *list,
@@ -647,7 +647,7 @@
 
 	guidp = p_new(ctx->pool, guid_128_t, 1);
 	memcpy(guidp, guid, sizeof(*guidp));
-	hash_table_insert(ctx->guids, guidp, guidp);
+	hash_table_insert(ctx->seen_mailbox_guids, guidp, guidp);
 
 	if (ctx->box != NULL)
 		rescan_finish(ctx);
@@ -727,7 +727,7 @@
 }
 
 static void rescan_clear_unseen_mailboxes(struct lucene_index *index,
-					  struct hash_table *guids)
+					  struct rescan_context *rescan_ctx)
 {
 	const enum mailbox_list_iter_flags iter_flags =
 		(enum mailbox_list_iter_flags)
@@ -748,8 +748,9 @@
 				    (enum mailbox_flags)0);
 		if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID,
 					 &metadata) == 0 &&
-		    (guids == NULL ||
-		     hash_table_lookup(guids, metadata.guid) == NULL)) {
+		    (rescan_ctx == NULL ||
+		     hash_table_lookup(rescan_ctx->seen_mailbox_guids,
+				       metadata.guid) == NULL)) {
 			/* this mailbox had no records in lucene index.
 			   make sure its last indexed uid is 0 */
 			(void)fts_index_set_header(box, &hdr);
@@ -779,7 +780,8 @@
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.index = index;
 	ctx.pool = pool_alloconly_create("guids", 1024);
-	ctx.guids = hash_table_create(ctx.pool, 0, guid_128_hash, guid_128_cmp);
+	hash_table_create(&ctx.seen_mailbox_guids, ctx.pool, 0,
+			  guid_128_hash, guid_128_cmp);
 	i_array_init(&ctx.uids, 128);
 
 	if (ret > 0) try {
@@ -805,8 +807,8 @@
 		rescan_finish(&ctx);
 	array_free(&ctx.uids);
 
-	rescan_clear_unseen_mailboxes(index, ctx.guids);
-	hash_table_destroy(&ctx.guids);
+	rescan_clear_unseen_mailboxes(index, &ctx);
+	hash_table_destroy(&ctx.seen_mailbox_guids);
 	pool_unref(&ctx.pool);
 	return failed ? -1 : 0;
 }
@@ -1296,7 +1298,8 @@
 }
 
 static int
-lucene_index_search_multi(struct lucene_index *index, struct hash_table *guids,
+lucene_index_search_multi(struct lucene_index *index,
+			  HASH_TABLE_TYPE(wguid_result) guids,
 			  ARRAY_TYPE(lucene_query) &queries,
 			  struct fts_multi_result *result)
 {
@@ -1308,10 +1311,11 @@
 
 	BooleanQuery mailbox_query;
 	struct hash_iterate_context *iter;
-	void *key, *value;
+	wchar_t *key;
+	struct fts_result *value;
 	iter = hash_table_iterate_init(guids);
-	while (hash_table_iterate(iter, &key, &value)) {
-		Term *term = _CLNEW Term(_T("box"), (wchar_t *)key);
+	while (hash_table_iterate_t(iter, guids, &key, &value)) {
+		Term *term = _CLNEW Term(_T("box"), key);
 		TermQuery *q = _CLNEW TermQuery(term);
 		mailbox_query.add(q, true, BooleanClause::SHOULD);
 	}
@@ -1332,8 +1336,8 @@
 				ret = -1;
 				break;
 			}
-			struct fts_result *br = (struct fts_result *)
-				hash_table_lookup(guids, (const void *)box_guid);
+			struct fts_result *br =
+				hash_table_lookup(guids, box_guid);
 			if (br == NULL) {
 				i_warning("lucene: Returned unexpected mailbox with GUID %ls", box_guid);
 				continue;
@@ -1363,7 +1367,7 @@
 }
 
 int lucene_index_lookup_multi(struct lucene_index *index,
-			      struct hash_table *guids,
+			      HASH_TABLE_TYPE(wguid_result) guids,
 			      struct mail_search_arg *args, bool and_args,
 			      struct fts_multi_result *result)
 {
--- a/src/plugins/fts-lucene/lucene-wrapper.h	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/plugins/fts-lucene/lucene-wrapper.h	Sun Aug 19 13:55:34 2012 +0300
@@ -4,7 +4,6 @@
 #include "fts-api-private.h"
 #include "guid.h"
 
-struct hash_table;
 struct mailbox_list;
 struct fts_expunge_log;
 struct fts_lucene_settings;
@@ -16,6 +15,8 @@
 	uint32_t uid;
 };
 
+HASH_TABLE_DEFINE_TYPE(wguid_result, wchar_t *, struct fts_result *);
+
 struct lucene_index *
 lucene_index_init(const char *path, struct mailbox_list *list,
 		  const struct fts_lucene_settings *set)
@@ -45,7 +46,7 @@
 			struct fts_result *result);
 
 int lucene_index_lookup_multi(struct lucene_index *index,
-			      struct hash_table *guids,
+			      HASH_TABLE_TYPE(wguid_result) guids,
 			      struct mail_search_arg *args, bool and_args,
 			      struct fts_multi_result *result);
 
--- a/src/plugins/fts-solr/fts-backend-solr-old.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/plugins/fts-solr/fts-backend-solr-old.c	Sun Aug 19 13:55:34 2012 +0300
@@ -724,7 +724,7 @@
 	ARRAY_DEFINE(fts_results, struct fts_result);
 	struct mail_namespace *ns;
 	struct mailbox_status status;
-	struct hash_table *mailboxes;
+	HASH_TABLE(char *, struct mailbox *) mailboxes;
 	struct mailbox *box;
 	const char *box_name;
 	char *box_id;
@@ -738,8 +738,7 @@
 	else
 		str_append(str, "%22%22");
 
-	mailboxes = hash_table_create(default_pool, 0,
-				      str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&mailboxes, default_pool, 0, str_hash, strcmp);
 	str_append(str, "%2B(");
 	len = str_len(str);
 	for (i = 0; boxes[i] != NULL; i++) {
--- a/src/plugins/fts-solr/fts-backend-solr.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/plugins/fts-solr/fts-backend-solr.c	Sun Aug 19 13:55:34 2012 +0300
@@ -801,7 +801,7 @@
 	struct solr_result **solr_results;
 	struct fts_result *fts_result;
 	ARRAY_DEFINE(fts_results, struct fts_result);
-	struct hash_table *mailboxes;
+	HASH_TABLE(char *, struct mailbox *) mailboxes;
 	struct mailbox *box;
 	const char *box_guid;
 	unsigned int i, len;
@@ -814,8 +814,7 @@
 	else
 		str_append(str, "%22%22");
 
-	mailboxes = hash_table_create(default_pool, 0,
-				      str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&mailboxes, default_pool, 0, str_hash, strcmp);
 	str_append(str, "%2B(");
 	len = str_len(str);
 	for (i = 0; boxes[i] != NULL; i++) {
--- a/src/plugins/fts-solr/solr-connection.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/plugins/fts-solr/solr-connection.c	Sun Aug 19 13:55:34 2012 +0300
@@ -40,7 +40,7 @@
 
 	pool_t result_pool;
 	/* box_id -> solr_result */
-	struct hash_table *mailboxes;
+	HASH_TABLE(char *, struct solr_result *) mailboxes;
 	ARRAY_DEFINE(results, struct solr_result *);
 };
 
@@ -419,9 +419,8 @@
 
 	memset(&solr_lookup_context, 0, sizeof(solr_lookup_context));
 	solr_lookup_context.result_pool = pool;
-	solr_lookup_context.mailboxes =
-		hash_table_create(default_pool, 0,
-				  str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&solr_lookup_context.mailboxes, default_pool, 0,
+			  str_hash, strcmp);
 	p_array_init(&solr_lookup_context.results, pool, 32);
 
 	i_free_and_null(conn->http_failure);
--- a/src/plugins/fts/fts-expunge-log.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/plugins/fts/fts-expunge-log.c	Sun Aug 19 13:55:34 2012 +0300
@@ -46,7 +46,7 @@
 	struct fts_expunge_log *log;
 	pool_t pool;
 
-	struct hash_table *mailboxes;
+	HASH_TABLE(uint8_t *, struct fts_expunge_log_mailbox *) mailboxes;
 	struct fts_expunge_log_mailbox *prev_mailbox;
 
 	bool failed;
@@ -177,7 +177,7 @@
 	ctx = p_new(pool, struct fts_expunge_log_append_ctx, 1);
 	ctx->log = log;
 	ctx->pool = pool;
-	ctx->mailboxes = hash_table_create(pool, 0, guid_128_hash, guid_128_cmp);
+	hash_table_create(&ctx->mailboxes, pool, 0, guid_128_hash, guid_128_cmp);
 
 	if (fts_expunge_log_reopen_if_needed(log, TRUE) < 0)
 		ctx->failed = TRUE;
@@ -188,12 +188,15 @@
 fts_expunge_log_mailbox_alloc(struct fts_expunge_log_append_ctx *ctx,
 			      const guid_128_t mailbox_guid)
 {
+	uint8_t *guid_p;
 	struct fts_expunge_log_mailbox *mailbox;
 
 	mailbox = p_new(ctx->pool, struct fts_expunge_log_mailbox, 1);
 	memcpy(mailbox->guid, mailbox_guid, sizeof(mailbox->guid));
 	p_array_init(&mailbox->uids, ctx->pool, 16);
-	hash_table_insert(ctx->mailboxes, mailbox->guid, mailbox);
+
+	guid_p = mailbox->guid;
+	hash_table_insert(ctx->mailboxes, guid_p, mailbox);
 	return mailbox;
 }
 
@@ -201,13 +204,14 @@
 				 const guid_128_t mailbox_guid,
 				 uint32_t uid)
 {
+	const uint8_t *guid_p = mailbox_guid;
 	struct fts_expunge_log_mailbox *mailbox;
 
 	if (ctx->prev_mailbox != NULL &&
 	    memcmp(mailbox_guid, ctx->prev_mailbox->guid, GUID_128_SIZE) == 0)
 		mailbox = ctx->prev_mailbox;
 	else {
-		mailbox = hash_table_lookup(ctx->mailboxes, mailbox_guid);
+		mailbox = hash_table_lookup(ctx->mailboxes, guid_p);
 		if (mailbox == NULL)
 			mailbox = fts_expunge_log_mailbox_alloc(ctx, mailbox_guid);
 		ctx->prev_mailbox = mailbox;
@@ -221,14 +225,13 @@
 		       uint32_t expunge_count, buffer_t *output)
 {
 	struct hash_iterate_context *iter;
-	void *key, *value;
+	uint8_t *guid_p;
+	struct fts_expunge_log_mailbox *mailbox;
 	struct fts_expunge_log_record *rec;
 	size_t rec_offset;
 
 	iter = hash_table_iterate_init(ctx->mailboxes);
-	while (hash_table_iterate(iter, &key, &value)) {
-		struct fts_expunge_log_mailbox *mailbox = value;
-
+	while (hash_table_iterate_t(iter, ctx->mailboxes, &guid_p, &mailbox)) {
 		rec_offset = output->used;
 		rec = buffer_append_space_unsafe(output, sizeof(*rec));
 		memcpy(rec->guid, mailbox->guid, sizeof(rec->guid));
--- a/src/pop3/pop3-commands.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/pop3/pop3-commands.c	Sun Aug 19 13:55:34 2012 +0300
@@ -711,15 +711,21 @@
         (void)list_uids_iter(client, ctx);
 }
 
-static void uidl_rename_duplicate(string_t *uidl, struct hash_table *prev_uidls)
+HASH_TABLE_DEFINE_TYPE(uidl_counter, char *, unsigned int);
+
+static void
+uidl_rename_duplicate(string_t *uidl, HASH_TABLE_TYPE(uidl_counter) prev_uidls)
 {
-	void *key, *value;
+	void *orig_key, *orig_value;
+	char *key;
 	unsigned int counter;
 
-	while (hash_table_lookup_full(prev_uidls, str_c(uidl), &key, &value)) {
+	while (hash_table_lookup_full(prev_uidls, str_c(uidl),
+				      &orig_key, &orig_value)) {
 		/* duplicate. the value contains the number of duplicates. */
-		counter = POINTER_CAST_TO(value, unsigned int) + 1;
-		hash_table_update(prev_uidls, key, POINTER_CAST(counter));
+		key = orig_key;
+		counter = POINTER_CAST_TO(orig_value, unsigned int) + 1;
+		hash_table_update(prev_uidls, key, counter);
 		str_printfa(uidl, "-%u", counter);
 		/* the second lookup really should return NULL, but just in
 		   case of some weird UIDLs do this as many times as needed */
@@ -731,7 +737,7 @@
 	struct mail_search_context *search_ctx;
 	struct mail_search_args *search_args;
 	struct mail *mail;
-	struct hash_table *prev_uidls;
+	HASH_TABLE_TYPE(uidl_counter) prev_uidls;
 	string_t *str;
 	char *uidl;
 	enum mail_fetch_field wanted_fields;
@@ -752,8 +758,7 @@
 
 	uidl_duplicates_rename =
 		strcmp(client->set->pop3_uidl_duplicates, "rename") == 0;
-	prev_uidls = hash_table_create(default_pool, 0,
-				       str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&prev_uidls, default_pool, 0, str_hash, strcmp);
 	client->uidl_pool = pool_alloconly_create("message uidls", 1024);
 	client->message_uidls = p_new(client->uidl_pool, const char *,
 				      client->messages_count+1);
@@ -772,7 +777,7 @@
 			uidl_rename_duplicate(str, prev_uidls);
 		uidl = p_strdup(client->uidl_pool, str_c(str));
 		client->message_uidls[msgnum] = uidl;
-		hash_table_insert(prev_uidls, uidl, POINTER_CAST(1));
+		hash_table_insert(prev_uidls, uidl, 1U);
 		msgnum++;
 	}
 	(void)mailbox_search_deinit(&search_ctx);
--- a/src/replication/aggregator/replicator-connection.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/replication/aggregator/replicator-connection.c	Sun Aug 19 13:55:34 2012 +0300
@@ -29,7 +29,7 @@
 
 	buffer_t *queue[REPLICATION_PRIORITY_SYNC + 1];
 
-	struct hash_table *requests;
+	HASH_TABLE(unsigned int, void *) requests;
 	unsigned int request_id_counter;
 	replicator_sync_callback_t *callback;
 };
@@ -49,12 +49,12 @@
 		return -1;
 	}
 
-	context = hash_table_lookup(conn->requests, POINTER_CAST(id));
+	context = hash_table_lookup(conn->requests, id);
 	if (context == NULL) {
 		i_error("Replicator sent invalid ID: %u", id);
 		return -1;
 	}
-	hash_table_remove(conn->requests, context);
+	hash_table_remove(conn->requests, id);
 	conn->callback(line[0] == '+', context);
 	return 0;
 }
@@ -209,7 +209,7 @@
 
 	conn = i_new(struct replicator_connection, 1);
 	conn->fd = -1;
-	conn->requests = hash_table_create(default_pool, 0, NULL, NULL);
+	hash_table_create_direct(&conn->requests, default_pool, 0);
 	for (i = REPLICATION_PRIORITY_LOW; i <= REPLICATION_PRIORITY_SYNC; i++)
 		conn->queue[i] = buffer_create_dynamic(default_pool, 1024);
 	return conn;
@@ -316,7 +316,7 @@
 
 	id = ++conn->request_id_counter;
 	if (id == 0) id++;
-	hash_table_insert(conn->requests, POINTER_CAST(id), context);
+	hash_table_insert(conn->requests, id, context);
 
 	T_BEGIN {
 		replicator_send(conn, REPLICATION_PRIORITY_SYNC, t_strdup_printf(
--- a/src/replication/replicator/replicator-queue.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/replication/replicator/replicator-queue.c	Sun Aug 19 13:55:34 2012 +0300
@@ -25,7 +25,7 @@
 struct replicator_queue {
 	struct priorityq *user_queue;
 	/* username => struct replicator_user* */
-	struct hash_table *user_hash;
+	HASH_TABLE(char *, struct replicator_user *) user_hash;
 
 	ARRAY_DEFINE(sync_lookups, struct replicator_sync_lookup);
 
@@ -67,8 +67,8 @@
 	queue = i_new(struct replicator_queue, 1);
 	queue->full_sync_interval = full_sync_interval;
 	queue->user_queue = priorityq_init(user_priority_cmp, 1024);
-	queue->user_hash = hash_table_create(default_pool, 1024, str_hash,
-					     (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&queue->user_hash, default_pool, 1024,
+			  str_hash, strcmp);
 	i_array_init(&queue->sync_lookups, 32);
 	return queue;
 }
--- a/src/stats/mail-domain.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/stats/mail-domain.c	Sun Aug 19 13:55:34 2012 +0300
@@ -9,7 +9,7 @@
 #include "mail-stats.h"
 #include "mail-domain.h"
 
-static struct hash_table *mail_domains_hash;
+static HASH_TABLE(char *, struct mail_domain *) mail_domains_hash;
 /* domains are sorted by their last_update timestamp, oldest first */
 static struct mail_domain *mail_domains_head, *mail_domains_tail;
 struct mail_domain *stable_mail_domains;
@@ -112,9 +112,7 @@
 
 void mail_domains_init(void)
 {
-	mail_domains_hash =
-		hash_table_create(default_pool, 0,
-				  str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&mail_domains_hash, default_pool, 0, str_hash, strcmp);
 }
 
 void mail_domains_deinit(void)
--- a/src/stats/mail-ip.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/stats/mail-ip.c	Sun Aug 19 13:55:34 2012 +0300
@@ -9,7 +9,7 @@
 #include "mail-stats.h"
 #include "mail-ip.h"
 
-static struct hash_table *mail_ips_hash;
+static HASH_TABLE(struct ip_addr *, struct mail_ip *) mail_ips_hash;
 /* ips are sorted by their last_update timestamp, oldest first */
 static struct mail_ip *mail_ips_head, *mail_ips_tail;
 struct mail_ip *stable_mail_ips;
@@ -108,10 +108,8 @@
 
 void mail_ips_init(void)
 {
-	mail_ips_hash =
-		hash_table_create(default_pool, 0,
-				  (hash_callback_t *)net_ip_hash,
-				  (hash_cmp_callback_t *)net_ip_cmp);
+	hash_table_create(&mail_ips_hash, default_pool, 0,
+			  net_ip_hash, net_ip_cmp);
 }
 
 void mail_ips_deinit(void)
--- a/src/stats/mail-session.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/stats/mail-session.c	Sun Aug 19 13:55:34 2012 +0300
@@ -23,7 +23,7 @@
    flooding the error log with hundreds of warnings.) */
 #define SESSION_GUID_WARN_HIDE_SECS (60*5)
 
-static struct hash_table *mail_sessions_hash;
+static HASH_TABLE(uint8_t *, struct mail_session *) mail_sessions_hash;
 /* sessions are sorted by their last_update timestamp, oldest first */
 static struct mail_session *mail_sessions_head, *mail_sessions_tail;
 static time_t session_guid_warn_hide_until;
@@ -38,7 +38,9 @@
 
 static void mail_session_disconnect(struct mail_session *session)
 {
-	hash_table_remove(mail_sessions_hash, session->guid);
+	uint8_t *guid_p = session->guid;
+
+	hash_table_remove(mail_sessions_hash, guid_p);
 	session->disconnected = TRUE;
 	timeout_remove(&session->to_idle);
 	mail_session_unref(&session);
@@ -57,6 +59,7 @@
 {
 	struct mail_session *session;
 	guid_128_t session_guid;
+	uint8_t *guid_p;
 	pid_t pid;
 	struct ip_addr ip;
 	unsigned int i;
@@ -75,7 +78,8 @@
 		return -1;
 	}
 
-	session = hash_table_lookup(mail_sessions_hash, session_guid);
+	guid_p = session_guid;
+	session = hash_table_lookup(mail_sessions_hash, guid_p);
 	if (session != NULL) {
 		*error_r = "CONNECT: Duplicate session GUID";
 		return -1;
@@ -96,7 +100,8 @@
 			session->ip = mail_ip_login(&ip);
 	}
 
-	hash_table_insert(mail_sessions_hash, session->guid, session);
+	guid_p = session->guid;
+	hash_table_insert(mail_sessions_hash, guid_p, session);
 	DLLIST_PREPEND_FULL(&stable_mail_sessions, session,
 			    stable_prev, stable_next);
 	DLLIST2_APPEND_FULL(&mail_sessions_head, &mail_sessions_tail, session,
@@ -130,6 +135,8 @@
 
 static void mail_session_free(struct mail_session *session)
 {
+	uint8_t *guid_p = session->guid;
+
 	i_assert(session->refcount == 0);
 
 	global_memory_free(mail_session_memsize(session));
@@ -137,7 +144,7 @@
 	if (session->to_idle != NULL)
 		timeout_remove(&session->to_idle);
 	if (!session->disconnected)
-		hash_table_remove(mail_sessions_hash, session->guid);
+		hash_table_remove(mail_sessions_hash, guid_p);
 	DLLIST_REMOVE_FULL(&stable_mail_sessions, session,
 			   stable_prev, stable_next);
 	DLLIST2_REMOVE_FULL(&mail_sessions_head, &mail_sessions_tail, session,
@@ -174,6 +181,7 @@
 			const char **error_r)
 {
 	guid_128_t session_guid;
+	uint8_t *guid_p;
 
 	if (guid == NULL) {
 		*error_r = "Too few parameters";
@@ -183,7 +191,8 @@
 		*error_r = "Invalid GUID";
 		return -1;
 	}
-	*session_r = hash_table_lookup(mail_sessions_hash, session_guid);
+	guid_p = session_guid;
+	*session_r = hash_table_lookup(mail_sessions_hash, guid_p);
 	if (*session_r == NULL) {
 		mail_session_guid_lost(session_guid);
 		return 0;
@@ -291,9 +300,8 @@
 {
 	session_guid_warn_hide_until =
 		ioloop_time + SESSION_GUID_WARN_HIDE_SECS;
-	mail_sessions_hash =
-		hash_table_create(default_pool, 0,
-				  guid_128_hash, guid_128_cmp);
+	hash_table_create(&mail_sessions_hash, default_pool, 0,
+			  guid_128_hash, guid_128_cmp);
 }
 
 void mail_sessions_deinit(void)
--- a/src/stats/mail-user.c	Sun Aug 19 07:20:13 2012 +0300
+++ b/src/stats/mail-user.c	Sun Aug 19 13:55:34 2012 +0300
@@ -10,7 +10,7 @@
 #include "mail-domain.h"
 #include "mail-user.h"
 
-static struct hash_table *mail_users_hash;
+static HASH_TABLE(char *, struct mail_user *) mail_users_hash;
 /* users are sorted by their last_update timestamp, oldest first */
 static struct mail_user *mail_users_head, *mail_users_tail;
 struct mail_user *stable_mail_users;
@@ -130,9 +130,7 @@
 
 void mail_users_init(void)
 {
-	mail_users_hash =
-		hash_table_create(default_pool, 0,
-				  str_hash, (hash_cmp_callback_t *)strcmp);
+	hash_table_create(&mail_users_hash, default_pool, 0, str_hash, strcmp);
 }
 
 void mail_users_deinit(void)