changeset 2057:5e0167577399 HEAD

Fixed var_expand() to take a table of variables rather than a few predefined ones. Added support for modifiers.
author Timo Sirainen <tss@iki.fi>
date Tue, 25 May 2004 01:33:50 +0300
parents 7c47536833ca
children 0a1755f79392
files dovecot-example.conf src/auth/auth-master-connection.c src/auth/mech.c src/auth/mech.h src/auth/passdb-ldap.c src/auth/passdb-mysql.c src/auth/passdb-pgsql.c src/auth/userdb-ldap.c src/auth/userdb-mysql.c src/auth/userdb-passwd-file.c src/auth/userdb-passwd.c src/auth/userdb-pgsql.c src/auth/userdb-static.c src/auth/userdb-vpopmail.c src/auth/userdb.h src/lib-index/mail-index-sync-update.c src/lib/strfuncs.c src/lib/strfuncs.h src/lib/var-expand.c src/lib/var-expand.h src/master/common.h src/master/login-process.h src/master/mail-process.c
diffstat 23 files changed, 221 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/dovecot-example.conf	Tue May 25 01:13:55 2004 +0300
+++ b/dovecot-example.conf	Tue May 25 01:33:50 2004 +0300
@@ -166,6 +166,12 @@
 #   %n - user part in user@domain, same as %u if there's no domain
 #   %d - domain part in user@domain, empty if user there's no domain
 #   %h - home directory
+#   %p - protocol (IMAP or POP3)
+#
+# You can apply a modifiers for each variable (eg. %Lp = pop3):
+#   %L - lowercase
+#   %U - uppercase
+#   %E - escape '"', "'" and '\' characters by inserting '\' before them.
 #
 # You can also limit a width of string by giving the number of max. characters
 # after the '%' character. For example %1u gives the first character of
--- a/src/auth/auth-master-connection.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/auth-master-connection.c	Tue May 25 01:33:50 2004 +0300
@@ -149,7 +149,7 @@
 		master_request->tag = request->tag;
 
 		conn->refcount++;
-		userdb->lookup(auth_request->user, userdb_callback,
+		userdb->lookup(auth_request, userdb_callback,
 			       master_request);
 
 		/* the auth request is finished, we don't need it anymore */
--- a/src/auth/mech.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/mech.c	Tue May 25 01:33:50 2004 +0300
@@ -5,6 +5,7 @@
 #include "buffer.h"
 #include "hash.h"
 #include "mech.h"
+#include "var-expand.h"
 #include "auth-client-connection.h"
 
 #include <stdlib.h>
@@ -225,6 +226,48 @@
 	return FALSE;
 }
 
+static const char *escape_none(const char *str)
+{
+	return str;
+}
+
+const struct var_expand_table *
+auth_request_get_var_expand_table(const struct auth_request *auth_request,
+				  const char *(*escape_func)(const char *))
+{
+	static struct var_expand_table static_tab[] = {
+		{ 'u', NULL },
+		{ 'n', NULL },
+		{ 'd', NULL },
+		{ 'p', NULL },
+		{ '\0', NULL }
+	};
+	struct var_expand_table *tab;
+
+	if (escape_func == NULL)
+		escape_func = escape_none;
+
+	tab = t_malloc(sizeof(static_tab));
+	memcpy(tab, static_tab, sizeof(static_tab));
+
+	tab[0].value = escape_func(auth_request->user);
+	tab[1].value = escape_func(t_strcut(auth_request->user, '@'));
+	tab[2].value = strchr(auth_request->user, '@');
+	if (tab[2].value != NULL)
+		tab[2].value = escape_func(tab[2].value+1);
+
+	switch (auth_request->protocol) {
+	case AUTH_PROTOCOL_IMAP:
+		tab[3].value = "IMAP";
+		break;
+	case AUTH_PROTOCOL_POP3:
+		tab[3].value = "POP3";
+		break;
+	}
+
+	return tab;
+}
+
 extern struct mech_module mech_plain;
 extern struct mech_module mech_cram_md5;
 extern struct mech_module mech_digest_md5;
--- a/src/auth/mech.h	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/mech.h	Tue May 25 01:33:50 2004 +0300
@@ -75,6 +75,10 @@
 void auth_request_ref(struct auth_request *request);
 int auth_request_unref(struct auth_request *request);
 
+const struct var_expand_table *
+auth_request_get_var_expand_table(const struct auth_request *auth_request,
+				  const char *(*escape_func)(const char *));
+
 void mech_init(void);
 void mech_deinit(void);
 
--- a/src/auth/passdb-ldap.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/passdb-ldap.c	Tue May 25 01:33:50 2004 +0300
@@ -141,16 +141,18 @@
 			     struct ldap_request *ldap_request)
 {
 	struct ldap_connection *conn = passdb_ldap_conn->conn;
-	const char *user, *filter;
+	const char *filter;
 	string_t *str;
 
-	user = ldap_escape(auth_request->user);
 	if (conn->set.pass_filter == NULL) {
 		filter = t_strdup_printf("(&(objectClass=posixAccount)(%s=%s))",
-			passdb_ldap_conn->attr_names[ATTR_VIRTUAL_USER], user);
+			passdb_ldap_conn->attr_names[ATTR_VIRTUAL_USER],
+			ldap_escape(auth_request->user));
 	} else {
 		str = t_str_new(512);
-		var_expand(str, conn->set.pass_filter, user, NULL);
+		var_expand(str, conn->set.pass_filter,
+			   auth_request_get_var_expand_table(auth_request,
+							     ldap_escape));
 		filter = str_c(str);
 	}
 
--- a/src/auth/passdb-mysql.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/passdb-mysql.c	Tue May 25 01:33:50 2004 +0300
@@ -108,7 +108,8 @@
 
 	str = t_str_new(512);
 	var_expand(str, conn->set.password_query,
-		   str_escape(auth_request->user), NULL);
+		   auth_request_get_var_expand_table(auth_request,
+						     str_escape));
 	query = str_c(str);
 
 	mysql_request->callback = mysql_handle_request;
--- a/src/auth/passdb-pgsql.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/passdb-pgsql.c	Tue May 25 01:33:50 2004 +0300
@@ -105,7 +105,8 @@
 
 	str = t_str_new(512);
 	var_expand(str, conn->set.password_query,
-		   db_pgsql_escape(auth_request->user), NULL);
+		   auth_request_get_var_expand_table(auth_request,
+						     db_pgsql_escape));
 	query = str_c(str);
 
 	pgsql_request->callback = pgsql_handle_request;
--- a/src/auth/userdb-ldap.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/userdb-ldap.c	Tue May 25 01:33:50 2004 +0300
@@ -149,21 +149,23 @@
 	t_pop();
 }
 
-static void userdb_ldap_lookup(const char *user, userdb_callback_t *callback,
-			       void *context)
+static void userdb_ldap_lookup(struct auth_request *auth_request,
+			       userdb_callback_t *callback, void *context)
 {
 	struct ldap_connection *conn = userdb_ldap_conn->conn;
 	struct userdb_ldap_request *request;
 	const char *filter;
 	string_t *str;
 
-	user = ldap_escape(user);
 	if (conn->set.user_filter == NULL) {
 		filter = t_strdup_printf("(&(objectClass=posixAccount)(%s=%s))",
-			userdb_ldap_conn->attr_names[ATTR_VIRTUAL_USER], user);
+			userdb_ldap_conn->attr_names[ATTR_VIRTUAL_USER],
+			ldap_escape(auth_request->user));
 	} else {
 		str = t_str_new(512);
-		var_expand(str, conn->set.user_filter, user, NULL);
+		var_expand(str, conn->set.user_filter,
+			   auth_request_get_var_expand_table(auth_request,
+							     ldap_escape));
 		filter = str_c(str);
 	}
 
--- a/src/auth/userdb-mysql.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/userdb-mysql.c	Tue May 25 01:33:50 2004 +0300
@@ -114,8 +114,8 @@
 	}
 }
 
-static void userdb_mysql_lookup(const char *user, userdb_callback_t *callback,
-				void *context)
+static void userdb_mysql_lookup(struct auth_request *auth_request,
+				userdb_callback_t *callback, void *context)
 {
 	struct mysql_connection *conn = userdb_mysql_conn->conn;
 	struct userdb_mysql_request *request;
@@ -123,14 +123,17 @@
 	string_t *str;
 
 	str = t_str_new(512);
-	var_expand(str, conn->set.user_query, str_escape(user), NULL);
+	var_expand(str, conn->set.user_query,
+		   auth_request_get_var_expand_table(auth_request,
+						     str_escape));
 	query = str_c(str);
 
-	request = i_malloc(sizeof(struct userdb_mysql_request) + strlen(user));
+	request = i_malloc(sizeof(struct userdb_mysql_request) +
+			   strlen(auth_request->user));
 	request->request.callback = mysql_handle_request;
 	request->request.context = context;
 	request->userdb_callback = callback;
-	strcpy(request->username, user);
+	strcpy(request->username, auth_request->user);
 
 	db_mysql_query(conn, query, &request->request);
 }
--- a/src/auth/userdb-passwd-file.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/userdb-passwd-file.c	Tue May 25 01:33:50 2004 +0300
@@ -11,13 +11,13 @@
 
 struct passwd_file *userdb_pwf = NULL;
 
-static void passwd_file_lookup(const char *user, userdb_callback_t *callback,
-			       void *context)
+static void passwd_file_lookup(struct auth_request *auth_request,
+			       userdb_callback_t *callback, void *context)
 {
 	struct user_data data;
 	struct passwd_user *pu;
 
-	pu = db_passwd_file_lookup(userdb_pwf, user);
+	pu = db_passwd_file_lookup(userdb_pwf, auth_request->user);
 	if (pu == NULL) {
 		callback(NULL, context);
 		return;
@@ -27,7 +27,7 @@
 	data.uid = pu->uid;
 	data.gid = pu->gid;
 
-	data.virtual_user = user;
+	data.virtual_user = auth_request->user;
 	data.home = pu->home;
 	data.mail = pu->mail;
 
--- a/src/auth/userdb-passwd.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/userdb-passwd.c	Tue May 25 01:33:50 2004 +0300
@@ -10,16 +10,16 @@
 
 #include <pwd.h>
 
-static void passwd_lookup(const char *user, userdb_callback_t *callback,
-			  void *context)
+static void passwd_lookup(struct auth_request *auth_request,
+			  userdb_callback_t *callback, void *context)
 {
 	struct user_data data;
 	struct passwd *pw;
 
-	pw = getpwnam(user);
+	pw = getpwnam(auth_request->user);
 	if (pw == NULL) {
 		if (verbose)
-			i_info("passwd(%s): unknown user", user);
+			i_info("passwd(%s): unknown user", auth_request->user);
 		callback(NULL, context);
 		return;
 	}
--- a/src/auth/userdb-pgsql.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/userdb-pgsql.c	Tue May 25 01:33:50 2004 +0300
@@ -84,8 +84,8 @@
 	}
 }
 
-static void userdb_pgsql_lookup(const char *user, userdb_callback_t *callback,
-				void *context)
+static void userdb_pgsql_lookup(struct auth_request *auth_request,
+				userdb_callback_t *callback, void *context)
 {
 	struct pgsql_connection *conn = userdb_pgsql_conn->conn;
 	struct userdb_pgsql_request *request;
@@ -93,14 +93,17 @@
 	string_t *str;
 
 	str = t_str_new(512);
-	var_expand(str, conn->set.user_query, db_pgsql_escape(user), NULL);
+	var_expand(str, conn->set.user_query,
+		   auth_request_get_var_expand_table(auth_request,
+						     db_pgsql_escape));
 	query = str_c(str);
 
-	request = i_malloc(sizeof(struct userdb_pgsql_request) + strlen(user));
+	request = i_malloc(sizeof(struct userdb_pgsql_request) +
+			   strlen(auth_request->user));
 	request->request.callback = pgsql_handle_request;
 	request->request.context = context;
 	request->userdb_callback = callback;
-	strcpy(request->username, user);
+	strcpy(request->username, auth_request->user);
 
 	db_pgsql_query(conn, query, &request->request);
 }
--- a/src/auth/userdb-static.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/userdb-static.c	Tue May 25 01:33:50 2004 +0300
@@ -16,8 +16,8 @@
 static gid_t static_gid;
 static char *static_home_template;
 
-static void static_lookup(const char *user, userdb_callback_t *callback,
-			  void *context)
+static void static_lookup(struct auth_request *auth_request,
+			  userdb_callback_t *callback, void *context)
 {
 	struct user_data data;
 	string_t *str;
@@ -26,10 +26,11 @@
 	data.uid = static_uid;
 	data.gid = static_gid;
 
-	data.virtual_user = data.system_user = user;
+	data.virtual_user = data.system_user = auth_request->user;
 
 	str = t_str_new(256);
-	var_expand(str, static_home_template, user, NULL);
+	var_expand(str, static_home_template,
+		   auth_request_get_var_expand_table(auth_request, NULL));
 	data.home = str_c(str);
 
 	callback(&data, context);
--- a/src/auth/userdb-vpopmail.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/userdb-vpopmail.c	Tue May 25 01:33:50 2004 +0300
@@ -46,8 +46,8 @@
 
 #ifdef USERDB_VPOPMAIL
 
-static void vpopmail_lookup(const char *user, userdb_callback_t *callback,
-			    void *context)
+static void vpopmail_lookup(struct auth_request *auth_request,
+			    userdb_callback_t *callback, void *context)
 {
 	char vpop_user[VPOPMAIL_LIMIT], vpop_domain[VPOPMAIL_LIMIT];
 	struct vqpasswd *vpw;
@@ -56,7 +56,7 @@
 	gid_t gid;
 	pool_t pool;
 
-	vpw = vpopmail_lookup_vqp(user, vpop_user, vpop_domain);
+	vpw = vpopmail_lookup_vqp(auth_request->user, vpop_user, vpop_domain);
 	if (vpw == NULL) {
 		callback(NULL, context);
 		return;
@@ -67,7 +67,7 @@
 	if (vget_assign(vpop_domain, NULL, 0, &uid, &gid) == NULL) {
 		if (verbose) {
 			i_info("vpopmail(%s): vget_assign(%s) failed",
-			       user, vpop_domain);
+			       auth_request->user, vpop_domain);
 		}
 		callback(NULL, context);
 		return;
@@ -77,12 +77,12 @@
 		/* user's homedir doesn't exist yet, create it */
 		if (verbose) {
 			i_info("vpopmail(%s): pw_dir isn't set, creating",
-			       user);
+			       auth_request->user);
 		}
 
 		if (make_user_dir(vpop_user, vpop_domain, uid, gid) == NULL) {
 			i_error("vpopmail(%s): make_user_dir(%s, %s) failed",
-				user, vpop_user, vpop_domain);
+				auth_request->user, vpop_user, vpop_domain);
 			callback(NULL, context);
 			return;
 		}
--- a/src/auth/userdb.h	Tue May 25 01:13:55 2004 +0300
+++ b/src/auth/userdb.h	Tue May 25 01:33:50 2004 +0300
@@ -1,6 +1,8 @@
 #ifndef __USERDB_H
 #define __USERDB_H
 
+#include "mech.h"
+
 struct user_data {
 	const char *virtual_user;
 	const char *home;
@@ -17,8 +19,8 @@
 	void (*init)(const char *args);
 	void (*deinit)(void);
 
-	void (*lookup)(const char *user, userdb_callback_t *callback,
-		       void *context);
+	void (*lookup)(struct auth_request *auth_request,
+		       userdb_callback_t *callback, void *context);
 };
 
 extern struct userdb_module *userdb;
--- a/src/lib-index/mail-index-sync-update.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/lib-index/mail-index-sync-update.c	Tue May 25 01:33:50 2004 +0300
@@ -81,6 +81,7 @@
 
 	map->records_count -= count;
 	hdr->messages_count -= count;
+	view->messages_count -= count;
 
 	if (map->buffer != NULL) {
 		buffer_set_used_size(map->buffer, map->records_count);
@@ -123,6 +124,7 @@
 	map->records[map->records_count++] = *rec;
 	map->hdr_copy.messages_count++;
 	map->hdr_copy.next_uid = rec->uid+1;
+	view->messages_count++;
 
 	mail_index_header_update_counts(&map->hdr_copy, 0, rec->flags);
 	mail_index_header_update_lowwaters(&map->hdr_copy, rec);
--- a/src/lib/strfuncs.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/lib/strfuncs.c	Tue May 25 01:33:50 2004 +0300
@@ -433,6 +433,16 @@
         return str;
 }
 
+const char *t_str_lcase(const char *str)
+{
+	return str_lcase(t_strdup_noconst(str));
+}
+
+const char *t_str_ucase(const char *str)
+{
+	return str_ucase(t_strdup_noconst(str));
+}
+
 int null_strcmp(const char *s1, const char *s2)
 {
 	if (s1 == NULL)
--- a/src/lib/strfuncs.h	Tue May 25 01:13:55 2004 +0300
+++ b/src/lib/strfuncs.h	Tue May 25 01:33:50 2004 +0300
@@ -50,6 +50,8 @@
 
 char *str_ucase(char *str);
 char *str_lcase(char *str);
+const char *t_str_lcase(const char *str);
+const char *t_str_ucase(const char *str);
 
 int null_strcmp(const char *s1, const char *s2);
 int memcasecmp(const void *p1, const void *p2, size_t size);
--- a/src/lib/var-expand.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/lib/var-expand.c	Tue May 25 01:33:50 2004 +0300
@@ -2,53 +2,70 @@
 
 #include "lib.h"
 #include "str.h"
+#include "strescape.h"
 #include "var-expand.h"
 
+struct var_expand_modifier {
+	char key;
+	const char *(*func)(const char *);
+};
+
+static const struct var_expand_modifier modifiers[] = {
+	{ 'L', t_str_lcase },
+	{ 'U', t_str_ucase },
+	{ 'E', str_escape },
+	{ '\0', NULL }
+};
+
 void var_expand(string_t *dest, const char *str,
-		const char *user, const char *home)
+		const struct var_expand_table *table)
 {
+        const struct var_expand_modifier *m;
+        const struct var_expand_table *t;
 	const char *var;
 	unsigned int width;
+	const char *(*modifier)(const char *);
 
 	for (; *str != '\0'; str++) {
 		if (*str != '%')
 			str_append_c(dest, *str);
 		else {
+			str++;
 			width = 0;
-			while (str[1] >= '0' && str[1] <= '9') {
-				width = width*10 + (str[1] - '0');
+			while (*str >= '0' && *str <= '9') {
+				width = width*10 + (*str - '0');
 				str++;
 			}
 
-			switch (str[1]) {
-			case '%':
-				var = "%";
-				break;
-			case 'u':
-				var = user;
-				break;
-			case 'h':
-				var = home;
-				break;
-			case 'n':
-				var = t_strcut(user, '@');
-				break;
-			case 'd':
-				var = strchr(user, '@');
-				if (var != NULL) var++;
-				break;
-			default:
-				str_append_c(dest, '%');
-				if (str[1] != '\0')
-					str_append_c(dest, str[1]);
-				var = NULL;
-				break;
+			modifier = NULL;
+			for (m = modifiers; m->key != '\0'; m++) {
+				if (m->key == *str) {
+					modifier = m->func;
+					str++;
+					break;
+				}
 			}
 
-			if (str[1] != '\0')
-				str++;
+			if (*str == '\0')
+				break;
+
+			var = NULL;
+			for (t = table; t->key != '\0'; t++) {
+				if (t->key == *str) {
+					var = t->value != NULL ? t->value : "";
+					break;
+				}
+			}
+
+			if (var == NULL) {
+				/* not found */
+				if (*str == '%')
+					var = "%";
+			}
 
 			if (var != NULL) {
+				if (modifier != NULL)
+					var = modifier(var);
 				if (width == 0)
 					str_append(dest, var);
 				else
--- a/src/lib/var-expand.h	Tue May 25 01:13:55 2004 +0300
+++ b/src/lib/var-expand.h	Tue May 25 01:33:50 2004 +0300
@@ -1,13 +1,14 @@
 #ifndef __VAR_EXPAND_H
 #define __VAR_EXPAND_H
 
-/* Expand % variables in str:
+struct var_expand_table {
+	char key;
+	const char *value;
+};
 
-    %u user or user@domain
-    %h home
-    %n user
-    %d domain */
+/* Expand % variables in src and append the string in dest.
+   table must end with key = 0. */
 void var_expand(string_t *dest, const char *str,
-		const char *user, const char *home);
+		const struct var_expand_table *table);
 
 #endif
--- a/src/master/common.h	Tue May 25 01:13:55 2004 +0300
+++ b/src/master/common.h	Tue May 25 01:33:50 2004 +0300
@@ -9,7 +9,7 @@
 
 #include "../auth/auth-master-interface.h"
 
-enum {
+enum process_type {
 	PROCESS_TYPE_UNKNOWN,
 	PROCESS_TYPE_AUTH,
 	PROCESS_TYPE_LOGIN,
--- a/src/master/login-process.h	Tue May 25 01:13:55 2004 +0300
+++ b/src/master/login-process.h	Tue May 25 01:33:50 2004 +0300
@@ -4,7 +4,7 @@
 struct login_group {
 	struct login_group *next;
 
-	int process_type;
+	enum process_type process_type;
 	struct settings *set;
 
 	unsigned int processes;
--- a/src/master/mail-process.c	Tue May 25 01:13:55 2004 +0300
+++ b/src/master/mail-process.c	Tue May 25 01:33:50 2004 +0300
@@ -74,8 +74,35 @@
 	return FALSE;
 }
 
-static const char *expand_mail_env(const char *env, const char *user,
-				   const char *home)
+static const struct var_expand_table *
+get_var_expand_table(const char *user, const char *home,
+		     enum process_type process_type)
+{
+	static struct var_expand_table static_tab[] = {
+		{ 'u', NULL },
+		{ 'n', NULL },
+		{ 'd', NULL },
+		{ 'p', NULL },
+		{ 'h', NULL },
+		{ '\0', NULL }
+	};
+	struct var_expand_table *tab;
+
+	tab = t_malloc(sizeof(static_tab));
+	memcpy(tab, static_tab, sizeof(static_tab));
+
+	tab[0].value = user;
+	tab[1].value = t_strcut(user, '@');
+	tab[2].value = strchr(user, '@');
+	if (tab[2].value != NULL) tab[2].value++;
+	tab[3].value = str_ucase(t_strdup_noconst(process_names[process_type]));
+	tab[4].value = home;
+
+	return tab;
+}
+
+static const char *
+expand_mail_env(const char *env, const struct var_expand_table *table)
 {
 	string_t *str;
 	const char *p;
@@ -95,18 +122,17 @@
 
 	if (env[0] == '~' && env[1] == '/') {
 		/* expand home */
-		str_append(str, home);
-		env++;
+		env = t_strconcat("%h", env+1, NULL);
 	}
 
 	/* expand %vars */
-        var_expand(str, env, user, home);
+	var_expand(str, env, table);
 	return str_c(str);
 }
 
-static void env_put_namespace(struct namespace_settings *ns,
-			      const char *default_location,
-			      const char *user, const char *home)
+static void
+env_put_namespace(struct namespace_settings *ns, const char *default_location,
+		  const struct var_expand_table *table)
 {
 	const char *location;
 	unsigned int i;
@@ -120,7 +146,7 @@
 
 		location = ns->location != NULL ? ns->location :
 			default_location;
-		location = expand_mail_env(location, user, home);
+		location = expand_mail_env(location, table);
 		env_put(t_strdup_printf("NAMESPACE_%u=%s", i, location));
 
 		if (ns->separator != NULL) {
@@ -135,7 +161,7 @@
 			/* expand variables, eg. ~%u/ can be useful */
 			str = t_str_new(256);
 			str_printfa(str, "NAMESPACE_%u_PREFIX=", i);
-			var_expand(str, ns->prefix, user, home);
+			var_expand(str, ns->prefix, table);
 			env_put(str_c(str));
 		}
 		if (ns->inbox)
@@ -151,6 +177,7 @@
 			struct auth_master_reply *reply, const char *data)
 {
 	struct settings *set = group->set;
+	const struct var_expand_table *var_expand_table;
 	const char *argv[4];
 	const char *addr, *mail, *user, *chroot_dir, *home_dir, *full_home_dir;
 	const char *executable, *p, *prefix;
@@ -317,12 +344,16 @@
 	   mechanism might allow leaving extra data there. */
 	mail = data + reply->mail_idx;
 	user = data + reply->virtual_user_idx;
+
+	var_expand_table =
+		get_var_expand_table(user, home_dir, group->process_type);
+
 	if (*mail == '\0' && set->default_mail_env != NULL)
-		mail = expand_mail_env(set->default_mail_env, user, home_dir);
+		mail = expand_mail_env(set->default_mail_env, var_expand_table);
 
 	if (set->server->namespaces != NULL) {
 		env_put_namespace(set->server->namespaces,
-				  mail, user, home_dir);
+				  mail, var_expand_table);
 	}
 
 	env_put(t_strconcat("MAIL=", mail, NULL));