return str_c(str);
}
+static void env_put_namespace(struct namespace_settings *ns,
+ const char *user, const char *home)
+{
+ const char *location;
+ unsigned int i;
+
+ for (i = 1; ns != NULL; i++, ns = ns->next) {
+ t_push();
+
+ location = expand_mail_env(ns->location, user, home);
+ env_put(t_strdup_printf("NAMESPACE_%u=%s", i, location));
+
+ if (ns->separator != NULL) {
+ env_put(t_strdup_printf("NAMESPACE_%u_SEP=%s",
+ i, ns->separator));
+ }
+ if (ns->type != NULL) {
+ env_put(t_strdup_printf("NAMESPACE_%u_TYPE=%s",
+ i, ns->type));
+ }
+ if (ns->prefix != NULL) {
+ env_put(t_strdup_printf("NAMESPACE_%u_PREFIX=%s",
+ i, ns->prefix));
+ }
+ t_pop();
+ }
+}
+
int create_mail_process(struct login_group *group, int socket,
struct ip_addr *ip,
struct auth_master_reply *reply, const char *data)
{
static const char *argv[] = { NULL, NULL, NULL };
struct settings *set = group->set;
- const char *addr, *mail, *chroot_dir, *home_dir, *full_home_dir;
+ const char *addr, *mail, *user, *chroot_dir, *home_dir, *full_home_dir;
char title[1024];
pid_t pid;
int i, err, ret;
auth process, but don't trust that too much either. Some auth
mechanism might allow leaving extra data there. */
mail = data + reply->mail_idx;
- if (*mail == '\0' && set->default_mail_env != NULL) {
- mail = expand_mail_env(set->default_mail_env,
- data + reply->virtual_user_idx,
- home_dir);
- }
+ user = data + reply->virtual_user_idx;
+ if (*mail == '\0' && set->default_mail_env != NULL)
+ mail = expand_mail_env(set->default_mail_env, user, home_dir);
+
+ if (set->server->namespaces != NULL)
+ env_put_namespace(set->server->namespaces, user, home_dir);
env_put(t_strconcat("MAIL=", mail, NULL));
env_put(t_strconcat("USER=", data + reply->virtual_user_idx, NULL));
enum settings_type {
SETTINGS_TYPE_ROOT,
SETTINGS_TYPE_SERVER,
- SETTINGS_TYPE_AUTH
+ SETTINGS_TYPE_AUTH,
+ SETTINGS_TYPE_NAMESPACE
};
struct settings_parse_ctx {
struct server_settings *root, *server;
struct auth_settings *auth;
+ struct namespace_settings *namespace;
int level;
};
{ 0, NULL, 0 }
};
+#undef DEF
+#define DEF(type, name) \
+ { type, #name, offsetof(struct namespace_settings, name) }
+
+static struct setting_def namespace_setting_defs[] = {
+ DEF(SET_STR, type),
+ DEF(SET_STR, separator),
+ DEF(SET_STR, prefix),
+ DEF(SET_STR, location),
+
+ { 0, NULL, 0 }
+};
+
struct settings default_settings = {
MEMBER(server) NULL,
MEMBER(protocol) 0,
return TRUE;
}
+static int namespace_settings_verify(struct namespace_settings *ns)
+{
+ const char *name;
+
+ name = ns->prefix != NULL ? ns->prefix : "";
+ if (ns->location == NULL) {
+ i_error("Namespace '%s': Missing location", name);
+ return FALSE;
+ }
+
+ if (ns->separator != NULL &&
+ ns->separator[0] != '\0' && ns->separator[1] != '\0') {
+ i_error("Namespace '%s': "
+ "Hierarchy separator must be only one character long",
+ name);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static const char *get_directory(const char *path)
{
char *str, *p;
return auth_settings_new(server, name);
}
+static struct namespace_settings *
+namespace_settings_new(struct server_settings *server, const char *type)
+{
+ struct namespace_settings *ns, **ns_p;
+
+ ns = p_new(settings_pool, struct namespace_settings, 1);
+
+ ns->parent = server;
+ ns->type = str_lcase(p_strdup(settings_pool, type));
+
+ ns_p = &server->namespaces;
+ while (*ns_p != NULL)
+ ns_p = &(*ns_p)->next;
+ *ns_p = ns;
+
+ return ns;
+}
+
+static struct namespace_settings *
+parse_new_namespace(struct server_settings *server, const char *name,
+ const char **errormsg)
+{
+ if (strcasecmp(name, "private") != 0 &&
+ strcasecmp(name, "shared") != 0 &&
+ strcasecmp(name, "public") != 0) {
+ *errormsg = "Unknown namespace type";
+ return NULL;
+ }
+
+ return namespace_settings_new(server, name);
+}
+
static const char *parse_setting(const char *key, const char *value,
void *context)
{
return error;
case SETTINGS_TYPE_AUTH:
return parse_setting_from_defs(settings_pool, auth_setting_defs,
- ctx->auth, key + 5, value);
+ ctx->auth, key, value);
+ case SETTINGS_TYPE_NAMESPACE:
+ return parse_setting_from_defs(settings_pool,
+ namespace_setting_defs,
+ ctx->namespace, key, value);
}
i_unreached();
*server->imap = *imap_defaults;
*server->pop3 = *pop3_defaults;
+ server->imap->server = server;
server->imap->protocol = MAIL_PROTOCOL_IMAP;
server->imap->login_executable = PKG_LIBEXECDIR"/imap-login";
server->imap->mail_executable = PKG_LIBEXECDIR"/imap";
+ server->pop3->server = server;
server->pop3->protocol = MAIL_PROTOCOL_POP3;
server->pop3->login_executable = PKG_LIBEXECDIR"/pop3-login";
server->pop3->mail_executable = PKG_LIBEXECDIR"/pop3";
ctx->parent_type = SETTINGS_TYPE_ROOT;
ctx->server = ctx->root;
ctx->auth = NULL;
+ ctx->namespace = NULL;
}
return TRUE;
}
return ctx->auth != NULL;
}
+ if (strcmp(type, "namespace") == 0) {
+ if (ctx->type != SETTINGS_TYPE_ROOT &&
+ ctx->type != SETTINGS_TYPE_SERVER) {
+ *errormsg = "Namespace section not allowed here";
+ return FALSE;
+ }
+
+ ctx->type = SETTINGS_TYPE_NAMESPACE;
+ ctx->namespace = parse_new_namespace(ctx->server, name,
+ errormsg);
+ return ctx->namespace != NULL;
+ }
+
*errormsg = "Unknown section type";
return FALSE;
}
struct settings_parse_ctx ctx;
struct server_settings *server, *prev;
struct auth_settings *auth;
+ struct namespace_settings *ns;
pool_t temp;
memset(&ctx, 0, sizeof(ctx));
if (!auth_settings_verify(auth))
return FALSE;
}
+ ns = server->namespaces;
+ for (; ns != NULL; ns = ns->next) {
+ if (!namespace_settings_verify(ns))
+ return FALSE;
+ }
prev = server;
}
}