#include "str-parse.h"
struct var_expand_table;
-struct var_expand_func_table;
+struct var_expand_provider;
#define SETTINGS_SEPARATOR '/'
#define SETTINGS_SEPARATOR_S "/"
.pop3c_host = "",
.pop3c_port = 110,
- .pop3c_user = "%u",
+ .pop3c_user = "%{user}",
.pop3c_master_user = "",
.pop3c_password = "",
#include "str.h"
#include "ioloop.h"
#include "settings.h"
+#include "var-expand-new.h"
#include "index-storage.h"
#include "mail-storage-service.h"
#include "mailbox-list-private.h"
};
static int
-shared_mail_user_var_home(const char *data ATTR_UNUSED, void *context,
- const char **value_r,
+shared_mail_user_var_home(const char *key ATTR_UNUSED,
+ const char **value_r, void *context,
const char **error_r)
{
struct shared_mail_user_var_expand_ctx *var_expand_ctx = context;
if (var_expand_ctx->nonexistent) {
/* No need to even bother looking up the home */
- *value_r = NULL;
- return 1;
+ *value_r = "";
+ return 0;
}
int ret = mail_user_get_home(var_expand_ctx->owner, value_r);
if (ret < 0) {
var_expand_ctx->owner->username);
return -1;
}
- if (ret == 0)
+ if (ret == 0) {
+ *value_r = "";
var_expand_ctx->nonexistent = TRUE;
- return 1;
+ }
+ return 0;
}
static int
const char *userdomain = domain == NULL ? username :
t_strdup_printf("%s@%s", username, domain);
- struct var_expand_table stack_tab[] = {
- { '\0', p_strdup(user->pool, userdomain), "owner_user" },
- { '\0', p_strdup(user->pool, username), "owner_username" },
- { '\0', p_strdup(user->pool, domain), "owner_domain" },
- { '\0', NULL, NULL },
+ const struct var_expand_table stack_tab[] = {
+ { .key = "owner_user", .value = p_strdup(user->pool, userdomain) },
+ {
+ .key = "owner_home",
+ .func = shared_mail_user_var_home,
+ },
+ VAR_EXPAND_TABLE_END
};
- struct var_expand_table *tab =
+ const struct var_expand_table *tab =
p_memdup(user->pool, stack_tab, sizeof(stack_tab));
- static struct var_expand_func_table func_tab[] = {
- { "owner_home", shared_mail_user_var_home },
- { NULL, NULL }
- };
struct var_expand_params *params =
p_new(user->pool, struct var_expand_params, 1);
params->table = tab;
- params->func_table = func_tab;
- params->func_context = var_expand_ctx;
+ params->context = var_expand_ctx;
+ params->event = user->event;
struct event *set_event = event_create(user->event);
event_add_str(set_event, SETTINGS_EVENT_NAMESPACE_NAME, ns->set->name);
#include "str.h"
#include "time-util.h"
#include "sleep.h"
-#include "var-expand.h"
#include "dict.h"
#include "settings.h"
+#include "var-expand-new.h"
#include "auth-master.h"
#include "master-service-private.h"
#include "mail-user.h"
#include "mail-namespace.h"
#include "mail-storage.h"
-#include "mail-storage-private.h"
#include "mail-storage-service.h"
#include <sys/stat.h>
remote_port = dec2str(input->remote_port);
const struct var_expand_table stack_tab[] = {
- { 'u', input->username, "user" },
- { 'n', username, "username" },
- { 'd', domain, "domain" },
- { 's', service_name, "service" },
- { 'l', net_ip2addr(&input->local_ip), "local_ip" },
- { 'r', net_ip2addr(&input->remote_ip), "remote_ip" },
- { '\0', local_port, "local_port" },
- { '\0', remote_port," remote_port" },
- { '\0', input->session_id, "session" },
- { '\0', auth_user, "auth_user" },
- { '\0', auth_username, "auth_username" },
- { '\0', auth_domain, "auth_domain" },
- { '\0', hostname, "hostname" },
- { '\0', local_name, "local_name" },
- { '\0', protocol, "protocol" },
- { '\0', master_user, "master_user" },
- { '\0', NULL, NULL }
+ { .key = "user", .value = input->username },
+ { .key = "username", .value = username },
+ { .key = "domain", .value = domain },
+ { .key = "service", .value = service_name },
+ { .key = "local_ip", .value = net_ip2addr(&input->local_ip) },
+ { .key = "remote_ip", .value = net_ip2addr(&input->remote_ip) },
+ { .key = "session", .value = input->session_id },
+ { .key = "auth_user", .value = auth_user },
+ { .key = "auth_username", .value = auth_username },
+ { .key = "auth_domain", .value = auth_domain },
+ { .key = "hostname", .value = hostname },
+ { .key = "local_name", .value = local_name },
+ { .key = "protocol", .value = protocol },
+ { .key = "master_user", .value = master_user },
+ { .key = "local_port", .value = local_port },
+ { .key = "remote_port", .value = remote_port },
+ VAR_EXPAND_TABLE_END
};
struct var_expand_table *tab;
return tab;
}
-const struct var_expand_table *
-mail_storage_service_get_var_expand_table(struct mail_storage_service_ctx *ctx,
- struct mail_storage_service_input *input)
+
+static int
+mail_storage_service_var_userdb(const char *key, const char **value_r,
+ void *context, const char **error_r ATTR_UNUSED)
+{
+ const struct mail_storage_service_input *input = context;
+
+ *value_r = mail_storage_service_fields_var_expand(key, input->userdb_fields);
+ return 0;
+}
+
+const struct var_expand_provider mail_storage_service_providers[] = {
+ { .key = "userdb", .func = mail_storage_service_var_userdb },
+ VAR_EXPAND_TABLE_END
+};
+
+const struct var_expand_params *
+mail_storage_service_get_var_expand_params(struct mail_storage_service_ctx *ctx,
+ struct mail_storage_service_input *input)
{
- return get_var_expand_table(ctx->service, NULL, input);
+ struct var_expand_params *params = t_new(struct var_expand_params, 1);
+
+ params->table = get_var_expand_table(ctx->service, NULL, input);
+ params->providers = mail_storage_service_providers;
+ params->context = input;
+ return params;
}
static int
i_set_failure_prefix("%s", user->service_ctx->default_log_prefix);
}
-static const char *field_get_default(const char *data)
-{
- const char *p;
-
- p = strchr(data, ':');
- if (p == NULL)
- return "";
- else {
- /* default value given */
- return p+1;
- }
-}
-
const char *mail_storage_service_fields_var_expand(const char *data,
const char *const *fields)
{
size_t field_name_len;
if (fields == NULL)
- return field_get_default(data);
+ return "";
field_name_len = strlen(field_name);
for (i = 0; fields[i] != NULL; i++) {
fields[i][field_name_len] == '=')
return fields[i] + field_name_len+1;
}
- return field_get_default(data);
-}
-static int
-mail_storage_service_input_var_userdb(const char *data, void *context,
- const char **value_r,
- const char **error_r ATTR_UNUSED)
-{
- struct mail_storage_service_init_var_expand_ctx *var_expand_ctx = context;
-
- *value_r = mail_storage_service_fields_var_expand(data,
- var_expand_ctx->input->userdb_fields);
- return 1;
+ return "";
}
-static const struct var_expand_func_table
-mail_storage_service_var_expand_func_table[] = {
- { "userdb", mail_storage_service_input_var_userdb },
- { NULL, NULL }
-};
-
static void
mail_storage_service_var_expand_callback(void *context,
struct var_expand_params *params_r)
params_r->table = get_var_expand_table(var_expand_ctx->ctx->service,
var_expand_ctx->user,
var_expand_ctx->input);
- params_r->func_table = mail_storage_service_var_expand_func_table;
- params_r->func_context = var_expand_ctx;
+ params_r->providers = mail_storage_service_providers;
+ params_r->context = (void*)var_expand_ctx->input;
}
const char *
enum mail_storage_service_flags
mail_storage_service_get_flags(struct mail_storage_service_ctx *ctx);
-const struct var_expand_table *
-mail_storage_service_get_var_expand_table(struct mail_storage_service_ctx *ctx,
- struct mail_storage_service_input *input);
+const struct var_expand_params *
+mail_storage_service_get_var_expand_params(struct mail_storage_service_ctx *ctx,
+ struct mail_storage_service_input *input);
const char *mail_storage_service_fields_var_expand(const char *data,
const char *const *fields);
void mail_storage_service_restore_privileges(uid_t old_uid, const char *old_cwd,
#include "lib.h"
#include "array.h"
#include "hash-format.h"
-#include "var-expand.h"
#include "unichar.h"
#include "hostpid.h"
#include "settings.h"
+#include "var-expand-new.h"
#include "message-address.h"
#include "message-header-parser.h"
#include "smtp-address.h"
.maildir_stat_dirs = FALSE,
.mail_shared_explicit_inbox = FALSE,
.lock_method = "fcntl:flock:dotlock",
- .pop3_uidl_format = "%08Xu%08Xv",
+ .pop3_uidl_format = "%{uid|number|hex(8)}%{uidvalidity|number|hex(8)}",
.recipient_delimiter = "+",
.mail_plugins = ARRAY_INIT,
.mail_plugin_dir = MODULEDIR,
- .mail_log_prefix = "%s(%u)<%{process:pid}><%{session}>: ",
+ .mail_log_prefix = "%{service}(%{user})<%{process:pid}><%{session}>: ",
.hostname = "",
- .postmaster_address = "postmaster@%{if;%d;ne;;%d;%{hostname}}",
+ .postmaster_address = "postmaster@%{domain|default(hostname)}",
};
const struct setting_parser_info mail_user_setting_parser_info = {
{
struct mail_storage_settings *set = _set;
struct hash_format *format;
- const char *p, *value, *fname, *error;
+ const char *value, *fname, *error;
bool uidl_format_ok;
- char c;
if (set->mailbox_idle_check_interval == 0) {
*error_r = "mailbox_idle_check_interval must not be 0";
}
uidl_format_ok = FALSE;
- for (p = set->pop3_uidl_format; *p != '\0'; p++) {
- if (p[0] != '%' || p[1] == '\0')
- continue;
-
- c = var_get_key(++p);
- switch (c) {
- case 'v':
- case 'u':
- case 'm':
- case 'f':
- case 'g':
- uidl_format_ok = TRUE;
- break;
- case '%':
- break;
- default:
+ struct var_expand_program *prog;
+ if (var_expand_program_create(set->pop3_uidl_format, &prog, &error) < 0) {
+ *error_r = t_strdup_printf("Invalid pop3_uidl_format: %s", error);
+ return FALSE;
+ }
+
+ const char *const *pop3_uidl_vars = var_expand_program_variables(prog);
+ const char *const pop3_uidl_allowed_vars[] = {
+ "uidvalidity",
+ "uid",
+ "md5",
+ "filename",
+ "guid",
+ NULL
+ };
+ for (; *pop3_uidl_vars != NULL; pop3_uidl_vars++) {
+ if (!str_array_find(pop3_uidl_allowed_vars, *pop3_uidl_vars)) {
*error_r = t_strdup_printf(
- "Unknown pop3_uidl_format variable: %%%c", c);
- return FALSE;
+ "Unknown pop3_uidl_format variable: %%{%s}",
+ *pop3_uidl_vars);
+ break;
}
+ uidl_format_ok = TRUE;
}
+ var_expand_program_free(&prog);
+
if (!uidl_format_ok) {
- *error_r = "pop3_uidl_format setting doesn't contain any "
- "%% variables.";
+ if (pop3_uidl_vars == NULL)
+ *error_r = "pop3_uidl_format setting doesn't contain any "
+ "%% variables.";
return FALSE;
}
#include "eacces-error.h"
#include "mkdir-parents.h"
#include "time-util.h"
-#include "var-expand.h"
#include "settings.h"
+#include "var-expand-new.h"
#include "dsasl-client.h"
#include "imap-date.h"
#include "mail-index-private.h"
return ret;
}
+static bool ATTR_PURE pop3_uidl_format_has_md5(const char *fmt)
+{
+ struct var_expand_program *prog;
+ const char *error;
+ if (var_expand_program_create(fmt, &prog, &error) < 0)
+ i_fatal("Invalid pop3_uidl_format: %s", error);
+ const char *const *vars = var_expand_program_variables(prog);
+ bool has_md5 = str_array_find(vars, "md5");
+ var_expand_program_free(&prog);
+ return has_md5;
+}
+
static int
mail_storage_create_real(struct mail_namespace *ns, struct event *set_event,
enum mail_storage_flags flags,
{
struct mail_storage *storage_class, *storage = NULL;
const struct mail_storage_settings *mail_set;
- const char *p, *driver = NULL;
+ const char *driver = NULL;
const char *inbox_path_override = NULL;
const char *root_path_override = NULL;
/* if pop3_uidl_format contains %m, we want to keep the
header MD5 sums stored even if we're not running POP3
right now. */
- p = ns->list->mail_set->pop3_uidl_format;
- while ((p = strchr(p, '%')) != NULL) {
- if (p[1] == '%')
- p += 2;
- else if (var_get_key(++p) == 'm') {
- flags |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
- break;
- }
- }
+ if (pop3_uidl_format_has_md5(ns->list->mail_set->pop3_uidl_format))
+ flags |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
}
storage = storage_class->v.alloc();
#include "str.h"
#include "istream.h"
#include "array.h"
-#include "var-expand.h"
+#include "var-expand-new.h"
#include "dlua-script.h"
#include "dlua-script-private.h"
#include "mail-storage.h"
struct mail_user *user = lua_check_storage_mail_user(L, 1);
const char *error;
const char *format = luaL_checkstring(L, 2);
- const struct var_expand_table *table = mail_user_var_expand_table(user);
+ const struct var_expand_params *params = mail_user_var_expand_params(user);
string_t *str = t_str_new(128);
- if (var_expand_with_funcs(str, format, table, mail_user_var_expand_func_table,
- user, &error) <= 0) {
+ if (var_expand_new(str, format, params, &error) < 0) {
return luaL_error(L, "var_expand(%s) failed: %s",
format, error);
}
#include "str.h"
#include "strescape.h"
#include "strfuncs.h"
-#include "var-expand.h"
#include "settings.h"
+#include "var-expand-new.h"
#include "fs-api.h"
#include "auth-master.h"
#include "master-service.h"
mail_user_var_expand_callback(void *context, struct var_expand_params *params_r)
{
struct mail_user *user = context;
-
- params_r->table = mail_user_var_expand_table(user);
- params_r->func_table = mail_user_var_expand_func_table;
- params_r->func_context = user;
+ const struct var_expand_params *params = mail_user_var_expand_params(user);
+ *params_r = *params;
}
struct mail_user *
str = t_str_new(256);
envs = array_get_modifiable(&set->plugin_envs, &count);
i_assert((count % 2) == 0);
+
+ const struct var_expand_params *params = mail_user_var_expand_params(user);
+
for (i = 0; i < count; i += 2) {
str_truncate(str, 0);
- if (var_expand_with_funcs(str, envs[i+1],
- mail_user_var_expand_table(user),
- mail_user_var_expand_func_table, user,
- &error) <= 0) {
+ if (var_expand_new(str, envs[i+1], params, &error) < 0) {
user->error = p_strdup_printf(user->pool,
"Failed to expand plugin setting %s = '%s': %s",
envs[i], envs[i+1], error);
mail_user_connection_init_from(&user->conn, user->pool, conn);
}
-const struct var_expand_table *
-mail_user_var_expand_table(struct mail_user *user)
+static int
+mail_user_var_expand_func_home(const char *data ATTR_UNUSED, const char **value_r,
+ void *context, const char **error_r)
+{
+ struct mail_user *user = context;
+
+ if (mail_user_get_home(user, value_r) <= 0) {
+ *error_r = "Setting used home directory (%h) but there is no "
+ "mail_home and userdb didn't return it";
+ return -1;
+ }
+ return 0;
+}
+
+const struct var_expand_params *
+mail_user_var_expand_params(struct mail_user *user)
{
/* use a cached table if possible */
- if (user->var_expand_table != NULL)
- return user->var_expand_table;
+ if (user->var_expand_params != NULL)
+ return user->var_expand_params;
- const char *username =
- p_strdup(user->pool, t_strcut(user->username, '@'));
- const char *domain = i_strchr_to_next(user->username, '@');
const char *local_ip = user->conn.local_ip == NULL ? NULL :
p_strdup(user->pool, net_ip2addr(user->conn.local_ip));
const char *remote_ip = user->conn.remote_ip == NULL ? NULL :
p_strdup(user->pool, net_ip2addr(user->conn.remote_ip));
-
- const char *auth_user, *auth_username, *auth_domain;
- if (user->auth_user == NULL) {
- auth_user = user->username;
- auth_username = username;
- auth_domain = domain;
- } else {
- auth_user = user->auth_user;
- auth_username =
- p_strdup(user->pool, t_strcut(user->auth_user, '@'));
- auth_domain = i_strchr_to_next(user->auth_user, '@');
- }
-
const char *local_port = "";
const char *remote_port = "";
}
const struct var_expand_table stack_tab[] = {
- { 'u', user->username, "user" },
- { 'n', username, "username" },
- { 'd', domain, "domain" },
- { 's', user->service, "service" },
- { 'l', local_ip, "local_ip" },
- { 'r', remote_ip, "remote_ip" },
- { '\0', local_port, "local_port" },
- { '\0', remote_port, "remote_port" },
- { '\0', user->session_id, "session" },
- { '\0', auth_user, "auth_user" },
- { '\0', auth_username, "auth_username" },
- { '\0', auth_domain, "auth_domain" },
- { '\0', user->set->hostname, "hostname" },
- { '\0', user->conn.local_name, "local_name" },
- { '\0', user->protocol, "protocol" },
+ { .key = "user", .value = user->username },
+ { .key = "service", .value = user->service },
+ { .key = "local_ip", .value = local_ip },
+ { .key = "remote_ip", .value = remote_ip },
+ { .key = "local_port", .value = local_port },
+ { .key = "remote_port", .value = remote_port },
+ { .key = "session", .value = user->session_id },
+ {
+ .key = "auth_user",
+ .value = user->auth_user != NULL ? user->auth_user :
+ user->username
+ },
+ { .key = "hostname", .value = user->set->hostname },
+ { .key = "local_name", .value = user->conn.local_name },
+ { .key = "protocol", .value = user->protocol },
/* default to owner being the same as user - these are
overridden by shared storage */
- { '\0', user->username, "owner_user" },
- { '\0', username, "owner_username" },
- { '\0', domain, "owner_domain" },
- { '\0', user->master_user, "master_user" },
+ { .key = "owner_user", .value = user->username },
+ { .key = "master_user", .value = user->master_user },
+ { .key = "home", .func = mail_user_var_expand_func_home },
+ { .key = "owner_home", .func = mail_user_var_expand_func_home },
/* NOTE: keep this synced with imap-hibernate's
imap_client_var_expand_table() */
- { '\0', NULL, NULL }
+ VAR_EXPAND_TABLE_END
};
- struct var_expand_table *tab;
- tab = p_malloc(user->pool, sizeof(stack_tab));
- memcpy(tab, stack_tab, sizeof(stack_tab));
-
- user->var_expand_table = tab;
- return user->var_expand_table;
-}
-
-static int
-mail_user_var_expand_func_home(const char *data ATTR_UNUSED, void *context,
- const char **value_r, const char **error_r)
-{
- struct mail_user *user = context;
+ struct var_expand_params *params =
+ p_new(user->pool, struct var_expand_params, 1);
+ params->table = p_memdup(user->pool, stack_tab, sizeof(stack_tab));
+ params->providers = mail_user_var_expand_func_table;
+ params->context = user;
+ params->event = user->event;
- if (mail_user_get_home(user, value_r) <= 0) {
- *error_r = "Setting used home directory (%h) but there is no "
- "mail_home and userdb didn't return it";
- return -1;
- }
- return 1;
+ user->var_expand_params = params;
+ return user->var_expand_params;
}
static int
-mail_user_var_expand_func_userdb(const char *data, void *context,
- const char **value_r,
- const char **error_r ATTR_UNUSED)
+mail_user_var_expand_func_userdb(const char *data, const char **value_r,
+ void *context, const char **error_r ATTR_UNUSED)
{
struct mail_user *user = context;
*value_r = mail_storage_service_fields_var_expand(data, user->userdb_fields);
- return 1;
+ return 0;
}
void mail_user_set_home(struct mail_user *user, const char *home)
return user->dict_op_set;
}
-static const struct var_expand_func_table mail_user_var_expand_func_table_arr[] = {
- { "h", mail_user_var_expand_func_home },
- { "home", mail_user_var_expand_func_home },
+static const struct var_expand_provider mail_user_var_expand_func_table_arr[] = {
/* default to owner_home being the same as user's home - this is
overridden by shared storage */
- { "owner_home", mail_user_var_expand_func_home },
{ "userdb", mail_user_var_expand_func_userdb },
{ NULL, NULL }
};
-const struct var_expand_func_table *mail_user_var_expand_func_table =
+const struct var_expand_provider *mail_user_var_expand_func_table =
mail_user_var_expand_func_table_arr;
this stays the same after IMAP client is hibernated and restored. */
time_t session_create_time;
- const struct var_expand_table *var_expand_table;
+ const struct var_expand_params_new *var_expand_params;
/* If non-NULL, fail the user initialization with this error.
This could be set by plugins that need to fail the initialization. */
const char *error;
};
extern struct mail_user_module_register mail_user_module_register;
extern struct auth_master_connection *mail_user_auth_master_conn;
-extern const struct var_expand_func_table *mail_user_var_expand_func_table;
+extern const struct var_expand_provider *mail_user_var_expand_func_table;
struct mail_user *
mail_user_alloc(struct mail_storage_service_user *service_user);
void mail_user_set_vars(struct mail_user *user, const char *service,
const struct mail_user_connection_data *conn);
/* Return %variable expansion table for the user. */
-const struct var_expand_table *
-mail_user_var_expand_table(struct mail_user *user);
+const struct var_expand_params_new *
+mail_user_var_expand_params(struct mail_user *user);
/* Specify the user's home directory. This should be called also with home=NULL
when it's known that the user doesn't have a home directory to avoid the
#include "str.h"
#include "istream.h"
#include "array.h"
-#include "var-expand.h"
#include "dlua-script.h"
#include "dlua-script-private.h"
#include "mail-storage.h"
#include "str.h"
#include "istream.h"
#include "array.h"
-#include "var-expand.h"
#include "mail-storage.h"
#include "mailbox-attribute.h"
#include "mail-storage-lua.h"
client->raw_mail_user =
raw_storage_create_from_set(storage_service, client->set_instance);
- struct var_expand_params params = {
- .table = mail_storage_service_get_var_expand_table(storage_service, &input),
- };
+ const struct var_expand_params *params =
+ mail_storage_service_get_var_expand_params(storage_service, &input);
struct event *event = event_create(client->event);
- event_set_ptr(event, SETTINGS_EVENT_VAR_EXPAND_PARAMS, ¶ms);
+ event_set_ptr(event, SETTINGS_EVENT_VAR_EXPAND_PARAMS, (void *)params);
if (settings_get(event, &lda_setting_parser_info, 0,
&client->lda_set, &error) < 0 ||
settings_get(event, &lmtp_setting_parser_info, 0,