+v2.2.UNSTABLE 2012-xx-xx Timo Sirainen <tss@iki.fi>
+
+ * "doveadm auth" command was renamed to "doveadm auth test"
+
+ + Implemented IMAP MOVE and BINARY extensions
+ + Implemented IMAP CATENATE extension (by Stephan Bosch)
+ + Implemented IMAP NOTIFY extension. Requires mailbox_list_index=yes
+ to be enabled.
+ + Improved mailbox list indexes. They should be usable now, although
+ still disabled by default.
+ + Redesigned and rewritten dsync. The new design makes the syncing
+ faster, more reliable and more featureful. The new dsync protocol
+ isn't backwards compatible with old dsync versions (but is designed
+ to be forwards compatible with future versions).
+ + All mailbox formats now support per-user message flags for shared
+ mailboxes by using a private index. It can be enabled by adding
+ :INDEXPVT=<path> to mail location. This should be used instead of
+ :INDEX also for Maildir/mbox to improve performance.
+ + LMTP proxy: Implemented XCLIENT extension for passing remote IP
+ address through proxy.
+
+ v2.1.10 2012-09-18 Timo Sirainen <tss@iki.fi>
+
+ + imap: Implemented THREAD=ORDEREDSUBJECT extension.
+ + Added "doveadm exec" command to easily execute commands from
+ libexec_dir, e.g. "doveadm exec imap -u user@domain"
+ + Added "doveadm copy" command.
+ + doveadm copy/move: Added optional user parameter to specify the
+ source username. This allows easily copying mails between different
+ users.
+ + Added namespace { disabled } setting to quickly enable/disable
+ namespaces. This is especially useful when its value is returned by
+ userdb.
+ + Added mailbox_alias plugin. It allows creating mailbox aliases using
+ symlinks.
+ + imapc storage: Added imapc_max_idle_time setting to force activity
+ on connection.
+ + fts-solr: Expunging multiple messages is now faster.
+ - director: In some conditions director may have disconnected from
+ another director (without logging about it), thinking it was sending
+ invalid data.
+ - imap: Various fixes to listing mailboxes.
+ - pop3-migration plugin: Avoid disconnection from POP3 server due
+ to idling.
+ - login processes crashed if there were a lot of local {} or remote {}
+ settings blocks.
+
v2.1.9 2012-08-01 Timo Sirainen <tss@iki.fi>
* mail-log plugin: Log mailbox names with UTF-8 everywhere
const struct var_expand_table *
auth_request_get_var_expand_table(const struct auth_request *auth_request,
- auth_request_escape_func_t *escape_func);
+ auth_request_escape_func_t *escape_func)
+ ATTR_NULL(2);
+ struct var_expand_table *
+ auth_request_get_var_expand_table_full(const struct auth_request *auth_request,
+ auth_request_escape_func_t *escape_func,
- unsigned int *count);
++ unsigned int *count) ATTR_NULL(2);
const char *auth_request_str_escape(const char *string,
const struct auth_request *request);
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];
string_t *var, *debug;
connect_str = t_strdup_printf("CONNECT\t%s\t%u\n",
net_ip2addr(&host->ip), host->port);
director_connection_send(conn, connect_str);
- (void)o_stream_flush(conn->output);
o_stream_uncork(conn->output);
+ /* wait for a while for the remote to disconnect, so it will hopefully
+ see our CONNECT command. we'll also log the warning later to avoid
+ multiple log lines about it. */
+ conn->connect_request_to = host;
+ director_host_ref(conn->connect_request_to);
+
conn->to_disconnect =
timeout_add(DIRECTOR_WAIT_DISCONNECT_SECS*1000,
director_connection_wait_timeout, conn);
ARG_PARSE_ATOM,
ARG_PARSE_STRING,
ARG_PARSE_LITERAL,
+ ARG_PARSE_LITERAL8,
ARG_PARSE_LITERAL_DATA,
- ARG_PARSE_LITERAL_DATA_FORCED
+ ARG_PARSE_LITERAL_DATA_FORCED,
+ ARG_PARSE_TEXT
};
struct imap_parser {
IMAP_PARSE_FLAG_ATOM_ALLCHARS = 0x08,
/* Allow strings to contain CRLFs */
IMAP_PARSE_FLAG_MULTILINE_STR = 0x10,
- IMAP_PARSE_FLAG_LITERAL8 = 0x40
+ /* Parse in list context; ')' parses as EOL */
+ IMAP_PARSE_FLAG_INSIDE_LIST = 0x20,
+ /* Parse literal8 and set it as flag to imap_arg. */
- IMAP_PARSE_FLAG_SERVER_TEXT = 0x20
++ IMAP_PARSE_FLAG_LITERAL8 = 0x40,
+ /* We're parsing IMAP server replies. Parse the "text" after
+ OK/NO/BAD/BYE replies as a single atom. We assume that the initial
+ "*" or tag was already skipped over. */
++ IMAP_PARSE_FLAG_SERVER_TEXT = 0x80
};
struct imap_parser;
dir = mail_user_home_expand(_storage->user,
set->mail_attachment_dir);
storage->attachment_dir = p_strdup(_storage->pool, dir);
- storage->attachment_fs = fs_init(name, args, &fs_set);
- } T_END;
+ if (fs_init(name, args, &fs_set, &storage->attachment_fs,
+ &error) < 0) {
+ *error_r = t_strdup_printf("mail_attachment_fs: %s",
+ error);
+ return -1;
+ }
+ }
- dbox_verify_alt_path(ns->list);
+ if (!ns->list->set.alt_dir_nocheck)
+ dbox_verify_alt_path(ns->list);
return 0;
}
{
struct mdbox_file *mfile = (struct mdbox_file *)file;
struct mdbox_map *map = mfile->storage->map;
- mode_t create_mode, old_mask;
- gid_t create_gid;
- const char *create_gid_origin, *p, *dir, *error;
++ struct mailbox_permissions perm;
+ mode_t old_mask;
+ const char *p, *dir;
int fd;
- old_mask = umask(0666 & ~map->perm.file_create_mode);
- mdbox_map_get_create_mode(map, &create_mode, &create_gid,
- &create_gid_origin);
- old_mask = umask(0666 & ~create_mode);
++ mailbox_list_get_root_permissions(map->root_list, &perm);
++
++ old_mask = umask(0666 & ~perm.file_create_mode);
fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
umask(old_mask);
if (fd == -1 && errno == ENOENT && parents &&
return -1;
}
/* try again */
- old_mask = umask(0666 & ~map->perm.file_create_mode);
- old_mask = umask(0666 & ~create_mode);
++ old_mask = umask(0666 & ~perm.file_create_mode);
fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
umask(old_mask);
}
if (fd == -1) {
mail_storage_set_critical(&file->storage->storage,
"open(%s, O_CREAT) failed: %m", path);
- } else if (map->perm.file_create_gid == (gid_t)-1) {
- } else if (create_gid == (gid_t)-1) {
++ } else if (perm.file_create_gid == (gid_t)-1) {
/* no group change */
- } else if (fchown(fd, (uid_t)-1, map->perm.file_create_gid) < 0) {
- } else if (fchown(fd, (uid_t)-1, create_gid) < 0) {
++ } else if (fchown(fd, (uid_t)-1, perm.file_create_gid) < 0) {
if (errno == EPERM) {
mail_storage_set_critical(&file->storage->storage, "%s",
eperm_error_get_chgrp("fchown", path,
- map->perm.file_create_gid,
- map->perm.file_create_gid_origin));
- create_gid,
- create_gid_origin));
++ perm.file_create_gid,
++ perm.file_create_gid_origin));
} else {
mail_storage_set_critical(&file->storage->storage,
"fchown(%s, -1, %ld) failed: %m",
- path, (long)map->perm.file_create_gid);
- path, (long)create_gid);
++ path, (long)perm.file_create_gid);
}
/* continue anyway */
}
uint32_t map_ext_id, ref_ext_id;
struct mailbox_list *root_list;
- struct mailbox_permissions perm;
- mode_t _create_mode;
- gid_t _create_gid;
- char *_create_gid_origin;
unsigned int verify_existing_file_ids:1;
- unsigned int create_mode_set:1;
};
struct mdbox_map_append {
static int mdbox_map_open_internal(struct mdbox_map *map, bool create_missing)
{
enum mail_index_open_flags open_flags;
- mode_t create_mode;
- gid_t create_gid;
- const char *create_gid_origin;
++ struct mailbox_permissions perm;
int ret = 0;
if (map->view != NULL) {
return 1;
}
- mdbox_map_get_create_mode(map, &create_mode, &create_gid,
- &create_gid_origin);
- mail_index_set_permissions(map->index, create_mode,
- create_gid, create_gid_origin);
++ mailbox_list_get_root_permissions(map->root_list, &perm);
++ mail_index_set_permissions(map->index, perm.file_create_mode,
++ perm.file_create_gid,
++ perm.file_create_gid_origin);
+
open_flags = MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY |
mail_storage_settings_to_index_flags(MAP_STORAGE(map)->set);
if (create_missing) {
if (ret <= 0)
return NULL;
- if (_ctx->list->ns->type == NAMESPACE_SHARED &&
++ if (_ctx->list->ns->type == MAIL_NAMESPACE_TYPE_SHARED &&
+ !_ctx->list->ns->list->mail_set->mail_shared_explicit_inbox &&
- strlen(ctx->info.name) < _ctx->list->ns->prefix_len) {
++ strlen(ctx->info.vname) < _ctx->list->ns->prefix_len) {
+ /* shared/user INBOX, IMAP code already lists it */
+ return fs_list_iter_next(_ctx);
+ }
+
if ((ctx->ctx.flags & MAILBOX_LIST_ITER_RETURN_SUBSCRIBED) != 0) {
mailbox_list_set_subscription_flags(ctx->ctx.list,
- ctx->info.name,
+ ctx->info.vname,
&ctx->info.flags);
}
- i_assert(ctx->info.name != NULL);
+ i_assert(ctx->info.vname != NULL);
return &ctx->info;
}
--- /dev/null
- /* For mailbox_list_iter_init_namespaces(): Skip namespaces that
+#ifndef MAILBOX_LIST_ITER_H
+#define MAILBOX_LIST_ITER_H
+
+#include "mail-namespace.h"
+#include "mailbox-list.h"
+
+enum mailbox_list_iter_flags {
+ /* Ignore index file and ACLs (used by ACL plugin internally) */
+ MAILBOX_LIST_ITER_RAW_LIST = 0x000001,
+ /* Don't list autocreated mailboxes (e.g. INBOX) unless they
+ physically exist */
+ MAILBOX_LIST_ITER_NO_AUTO_BOXES = 0x000004,
+
++ /* Skip all kinds of mailbox aliases. This typically includes symlinks
++ that point to the same directory. Also when iterating with
++ mailbox_list_iter_init_namespaces() skip namespaces that
+ have alias_for set. */
+ MAILBOX_LIST_ITER_SKIP_ALIASES = 0x000008,
+ /* For mailbox_list_iter_init_namespaces(): '*' in a pattern doesn't
+ match beyond namespace boundary (e.g. "foo*" or "*o" doesn't match
+ "foo." namespace's mailboxes, but "*.*" does). also '%' can't match
+ namespace prefixes, if there exists a parent namespace whose children
+ it matches. */
+ MAILBOX_LIST_ITER_STAR_WITHIN_NS = 0x000010,
+
+ /* List only subscribed mailboxes */
+ MAILBOX_LIST_ITER_SELECT_SUBSCRIBED = 0x000100,
+ /* Return MAILBOX_CHILD_* if mailbox's children match selection
+ criteria, even if the mailbox itself wouldn't match. */
+ MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH = 0x000200,
+ /* Return only mailboxes that have special use flags */
+ MAILBOX_LIST_ITER_SELECT_SPECIALUSE = 0x000400,
+
+ /* Don't return any flags unless it can be done without cost */
+ MAILBOX_LIST_ITER_RETURN_NO_FLAGS = 0x001000,
+ /* Return MAILBOX_SUBSCRIBED flag */
+ MAILBOX_LIST_ITER_RETURN_SUBSCRIBED = 0x002000,
+ /* Return children flags */
+ MAILBOX_LIST_ITER_RETURN_CHILDREN = 0x004000,
+ /* Return IMAP special use flags */
+ MAILBOX_LIST_ITER_RETURN_SPECIALUSE = 0x008000
+};
+
+struct mailbox_info {
+ const char *vname;
+ const char *special_use;
+ enum mailbox_info_flags flags;
+
+ struct mail_namespace *ns;
+};
+
+/* Returns a single pattern from given reference and pattern. */
+const char *mailbox_list_join_refpattern(struct mailbox_list *list,
+ const char *ref, const char *pattern);
+
+/* Initialize new mailbox list request. Pattern may contain '%' and '*'
+ wildcards as defined by RFC-3501. */
+struct mailbox_list_iterate_context *
+mailbox_list_iter_init(struct mailbox_list *list, const char *pattern,
+ enum mailbox_list_iter_flags flags);
+/* Like mailbox_list_iter_init(), but support multiple patterns. Patterns is
+ a NULL-terminated list of strings. It must contain at least one pattern. */
+struct mailbox_list_iterate_context *
+mailbox_list_iter_init_multiple(struct mailbox_list *list,
+ const char *const *patterns,
+ enum mailbox_list_iter_flags flags);
+/* List mailbox_list_iter_init_multiple(), but list mailboxes from all the
+ specified namespaces. */
+struct mailbox_list_iterate_context *
+mailbox_list_iter_init_namespaces(struct mail_namespace *namespaces,
+ const char *const *patterns,
+ enum mail_namespace_type type_mask,
+ enum mailbox_list_iter_flags flags);
+/* Get next mailbox. Returns the mailbox name */
+const struct mailbox_info *
+mailbox_list_iter_next(struct mailbox_list_iterate_context *ctx);
+/* Deinitialize mailbox list request. Returns -1 if some error
+ occurred while listing. */
+int mailbox_list_iter_deinit(struct mailbox_list_iterate_context **ctx);
+/* List one mailbox. Returns 1 if info returned, 0 if mailbox doesn't exist,
+ -1 if error. */
+int mailbox_list_mailbox(struct mailbox_list *list, const char *name,
+ enum mailbox_info_flags *flags_r);
+/* Returns 1 if mailbox has children, 0 if not, -1 if error. */
+int mailbox_has_children(struct mailbox_list *list, const char *name);
+
+#endif
bool mailbox_list_name_is_too_large(const char *name, char sep);
enum mailbox_list_file_type mailbox_list_get_file_type(const struct dirent *d);
+ int mailbox_list_dirent_is_alias_symlink(struct mailbox_list *list,
+ const char *dir_path,
+ const struct dirent *d);
bool mailbox_list_try_get_absolute_path(struct mailbox_list *list,
const char **name);
-int mailbox_list_create_missing_index_dir(struct mailbox_list *list,
- const char *name);
void mailbox_list_add_change(struct mailbox_list *list,
enum mailbox_log_record_type type,
char escape_char;
/* Use UTF-8 mailbox names on filesystem instead of mUTF-7 */
bool utf8;
+ /* Don't check/create the alt-dir symlink. */
+ bool alt_dir_nocheck;
};
-struct mailbox_info {
- const char *name;
- const char *special_use;
- enum mailbox_info_flags flags;
-
- struct mail_namespace *ns;
-};
-
struct mailbox_permissions {
/* The actual uid/gid of the mailbox */
uid_t file_uid;
#include <ctype.h>
- #define HASH_TABLE_MIN_SIZE 131
+ #define HASH_TABLE_MIN_SIZE 67
+#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;
static const struct setting_define lmtp_setting_defines[] = {
DEF(SET_BOOL, lmtp_proxy),
DEF(SET_BOOL, lmtp_save_to_detail_mailbox),
- DEF(SET_STR_VARS, login_greeting),
+ DEF(SET_BOOL, lmtp_rcpt_check_quota),
DEF(SET_STR, lmtp_address_translate),
+ DEF(SET_STR_VARS, login_greeting),
+ DEF(SET_STR, login_trusted_networks),
SETTING_DEFINE_LIST_END
};
static const struct lmtp_settings lmtp_default_settings = {
.lmtp_proxy = FALSE,
.lmtp_save_to_detail_mailbox = FALSE,
+ .lmtp_rcpt_check_quota = FALSE,
+ .lmtp_address_translate = "",
.login_greeting = PACKAGE_NAME" ready.",
- .lmtp_address_translate = ""
+ .login_trusted_networks = ""
};
static const struct setting_parser_info *lmtp_setting_dependencies[] = {
struct lmtp_settings {
bool lmtp_proxy;
bool lmtp_save_to_detail_mailbox;
- const char *login_greeting;
+ bool lmtp_rcpt_check_quota;
const char *lmtp_address_translate;
+ const char *login_greeting;
+ const char *login_trusted_networks;
};
extern const struct setting_parser_info lmtp_setting_parser_info;
--- /dev/null
- ARRAY_DEFINE(aliases, struct mailbox_alias);
+ /* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
+
+ #include "lib.h"
+ #include "str.h"
+ #include "mail-storage-hooks.h"
+ #include "mail-storage-private.h"
+ #include "mailbox-list-private.h"
+ #include "mailbox-alias-plugin.h"
+
+ #define MAILBOX_ALIAS_USER_CONTEXT(obj) \
+ MODULE_CONTEXT(obj, mailbox_alias_user_module)
+ #define MAILBOX_ALIAS_CONTEXT(obj) \
+ MODULE_CONTEXT(obj, mailbox_alias_storage_module)
+ #define MAILBOX_ALIAS_LIST_CONTEXT(obj) \
+ MODULE_CONTEXT(obj, mailbox_alias_mailbox_list_module)
+
+ struct mailbox_alias {
+ const char *old_vname, *new_vname;
+ };
+
+ struct mailbox_alias_user {
+ union mail_user_module_context module_ctx;
+
- ret = abox->module_ctx.super.create(box, update, directory);
++ ARRAY(struct mailbox_alias) aliases;
+ };
+
+ struct mailbox_alias_mailbox_list {
+ union mailbox_list_module_context module_ctx;
+ };
+
+ struct mailbox_alias_mailbox {
+ union mailbox_module_context module_ctx;
+ };
+
+ enum mailbox_symlink_existence {
+ MAILBOX_SYMLINK_EXISTENCE_NONEXISTENT,
+ MAILBOX_SYMLINK_EXISTENCE_SYMLINK,
+ MAILBOX_SYMLINK_EXISTENCE_NOT_SYMLINK
+ };
+
+ static MODULE_CONTEXT_DEFINE_INIT(mailbox_alias_user_module,
+ &mail_user_module_register);
+ static MODULE_CONTEXT_DEFINE_INIT(mailbox_alias_storage_module,
+ &mail_storage_module_register);
+ static MODULE_CONTEXT_DEFINE_INIT(mailbox_alias_mailbox_list_module,
+ &mailbox_list_module_register);
+
+ const char *mailbox_alias_plugin_version = DOVECOT_VERSION;
+
+ static const char *
+ mailbox_alias_find_new(struct mail_user *user, const char *new_vname)
+ {
+ struct mailbox_alias_user *auser = MAILBOX_ALIAS_USER_CONTEXT(user);
+ const struct mailbox_alias *alias;
+
+ array_foreach(&auser->aliases, alias) {
+ if (strcmp(alias->new_vname, new_vname) == 0)
+ return alias->old_vname;
+ }
+ return NULL;
+ }
+
+ static int mailbox_symlink_exists(struct mailbox_list *list, const char *vname,
+ enum mailbox_symlink_existence *existence_r)
+ {
+ struct mailbox_alias_mailbox_list *alist =
+ MAILBOX_ALIAS_LIST_CONTEXT(list);
+ struct stat st;
+ const char *symlink_name, *symlink_path;
+
+ symlink_name = alist->module_ctx.super.get_storage_name(list, vname);
+ symlink_path = mailbox_list_get_path(list, symlink_name,
+ MAILBOX_LIST_PATH_TYPE_DIR);
+ if (lstat(symlink_path, &st) < 0) {
+ if (errno == ENOENT) {
+ *existence_r = MAILBOX_SYMLINK_EXISTENCE_NONEXISTENT;
+ return 0;
+ }
+ mailbox_list_set_critical(list,
+ "lstat(%s) failed: %m", symlink_path);
+ return -1;
+ }
+ if (S_ISLNK(st.st_mode))
+ *existence_r = MAILBOX_SYMLINK_EXISTENCE_SYMLINK;
+ else
+ *existence_r = MAILBOX_SYMLINK_EXISTENCE_NOT_SYMLINK;
+ return 0;
+ }
+
+ static int mailbox_is_alias_symlink(struct mailbox *box)
+ {
+ enum mailbox_symlink_existence existence;
+
+ if (mailbox_alias_find_new(box->storage->user, box->vname) == NULL)
+ return 0;
+ if (mailbox_symlink_exists(box->list, box->vname, &existence) < 0) {
+ mail_storage_copy_list_error(box->storage, box->list);
+ return -1;
+ }
+ return existence == MAILBOX_SYMLINK_EXISTENCE_SYMLINK ? 1 : 0;
+ }
+
+ static int
+ mailbox_has_aliases(struct mailbox_list *list, const char *old_vname)
+ {
+ struct mailbox_alias_user *auser =
+ MAILBOX_ALIAS_USER_CONTEXT(list->ns->user);
+ const struct mailbox_alias *alias;
+ enum mailbox_symlink_existence existence;
+ int ret = 0;
+
+ array_foreach(&auser->aliases, alias) {
+ if (strcmp(alias->old_vname, old_vname) == 0) {
+ if (mailbox_symlink_exists(list, alias->new_vname,
+ &existence) < 0)
+ ret = -1;
+ if (existence == MAILBOX_SYMLINK_EXISTENCE_SYMLINK)
+ return 1;
+ }
+ }
+ return ret;
+ }
+
+ static int
+ mailbox_alias_create_symlink(struct mailbox *box,
+ const char *old_name, const char *new_name)
+ {
+ const char *old_path, *new_path, *fname;
+
+ old_path = mailbox_list_get_path(box->list, old_name,
+ MAILBOX_LIST_PATH_TYPE_DIR);
+ new_path = mailbox_list_get_path(box->list, new_name,
+ MAILBOX_LIST_PATH_TYPE_DIR);
+ fname = strrchr(old_path, '/');
+ i_assert(fname != NULL);
+ fname++;
+ i_assert(strncmp(new_path, old_path, fname-old_path) == 0);
+
+ if (symlink(fname, new_path) < 0) {
+ if (errno == EEXIST) {
+ mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
+ "Mailbox already exists");
+ return -1;
+ }
+ mail_storage_set_critical(box->storage,
+ "symlink(%s, %s) failed: %m", fname, new_path);
+ return -1;
+ }
+ return 0;
+ }
+
+ static const char *
+ mailbox_alias_get_storage_name(struct mailbox_list *list, const char *vname)
+ {
+ struct mailbox_alias_mailbox_list *alist =
+ MAILBOX_ALIAS_LIST_CONTEXT(list);
+ const char *old_vname;
+ enum mailbox_symlink_existence existence;
+
+ /* access the old mailbox so that e.g. full text search won't
+ index the mailbox twice. this also means that deletion must be
+ careful to delete the symlink, box->name. */
+ old_vname = mailbox_alias_find_new(list->ns->user, vname);
+ if (old_vname != NULL &&
+ mailbox_symlink_exists(list, vname, &existence) == 0 &&
+ existence != MAILBOX_SYMLINK_EXISTENCE_NOT_SYMLINK)
+ vname = old_vname;
+
+ return alist->module_ctx.super.get_storage_name(list, vname);
+ }
+
+ static int
+ mailbox_alias_create(struct mailbox *box, const struct mailbox_update *update,
+ bool directory)
+ {
+ struct mailbox_alias_mailbox *abox = MAILBOX_ALIAS_CONTEXT(box);
+ struct mailbox_alias_mailbox_list *alist =
+ MAILBOX_ALIAS_LIST_CONTEXT(box->list);
+ const char *symlink_name;
+ int ret;
+
- return abox->module_ctx.super.delete(box);
++ ret = abox->module_ctx.super.create_box(box, update, directory);
+ if (mailbox_alias_find_new(box->storage->user, box->vname) == NULL)
+ return ret;
+ if (ret < 0 && mailbox_get_last_mail_error(box) != MAIL_ERROR_EXISTS)
+ return ret;
+
+ /* all the code so far has actually only created the original
+ mailbox. now we'll create the symlink if it's missing. */
+ symlink_name = alist->module_ctx.super.
+ get_storage_name(box->list, box->vname);
+ return mailbox_alias_create_symlink(box, box->name, symlink_name);
+ }
+
+ static int mailbox_alias_delete(struct mailbox *box)
+ {
+ struct mailbox_alias_mailbox *abox = MAILBOX_ALIAS_CONTEXT(box);
+ struct mailbox_alias_mailbox_list *alist =
+ MAILBOX_ALIAS_LIST_CONTEXT(box->list);
+ const char *symlink_name;
+ int ret;
+
+ ret = mailbox_has_aliases(box->list, box->vname);
+ if (ret < 0)
+ return -1;
+ if (ret > 0) {
+ mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
+ "Can't delete mailbox while it has aliases");
+ return -1;
+ }
+
+ if (mailbox_is_alias_symlink(box)) {
+ /* we're deleting an alias mailbox. we'll need to handle this
+ explicitly since box->name points to the original mailbox */
+ symlink_name = alist->module_ctx.super.
+ get_storage_name(box->list, box->vname);
+ if (mailbox_list_delete_symlink(box->list, symlink_name) < 0) {
+ mail_storage_copy_list_error(box->storage, box->list);
+ return -1;
+ }
+ return 0;
+ }
+
-static int mailbox_alias_rename(struct mailbox *src, struct mailbox *dest,
- bool rename_children)
++ return abox->module_ctx.super.delete_box(box);
+ }
+
- return abox->module_ctx.super.rename(src, dest, rename_children);
++static int mailbox_alias_rename(struct mailbox *src, struct mailbox *dest)
+ {
+ struct mailbox_alias_mailbox *abox = MAILBOX_ALIAS_CONTEXT(src);
+ int ret;
+
+ if (mailbox_is_alias_symlink(src)) {
+ mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
+ "Can't rename alias mailboxes");
+ return -1;
+ }
+ if (mailbox_is_alias_symlink(dest)) {
+ mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
+ "Can't rename to mailbox alias");
+ return -1;
+ }
+ ret = mailbox_has_aliases(src->list, src->vname);
+ if (ret < 0)
+ return -1;
+ if (ret > 0) {
+ mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
+ "Can't rename mailbox while it has aliases");
+ return -1;
+ }
+
- v->create = mailbox_alias_create;
- v->delete = mailbox_alias_delete;
- v->rename = mailbox_alias_rename;
++ return abox->module_ctx.super.rename_box(src, dest);
+ }
+
+ static void mailbox_alias_mail_user_created(struct mail_user *user)
+ {
+ struct mail_user_vfuncs *v = user->vlast;
+ struct mailbox_alias_user *auser;
+ struct mailbox_alias *alias;
+ string_t *oldkey, *newkey;
+ const char *old_vname, *new_vname;
+ unsigned int i;
+
+ auser = p_new(user->pool, struct mailbox_alias_user, 1);
+ auser->module_ctx.super = *v;
+ user->vlast = &auser->module_ctx.super;
+
+ p_array_init(&auser->aliases, user->pool, 8);
+
+ oldkey = t_str_new(32);
+ newkey = t_str_new(32);
+ str_append(oldkey, "mailbox_alias_old");
+ str_append(newkey, "mailbox_alias_new");
+ for (i = 2;; i++) {
+ old_vname = mail_user_plugin_getenv(user, str_c(oldkey));
+ new_vname = mail_user_plugin_getenv(user, str_c(newkey));
+ if (old_vname == NULL || new_vname == NULL)
+ break;
+
+ alias = array_append_space(&auser->aliases);
+ alias->old_vname = old_vname;
+ alias->new_vname = new_vname;
+
+ str_truncate(oldkey, 0);
+ str_truncate(newkey, 0);
+ str_printfa(oldkey, "mailbox_alias_old%u", i);
+ str_printfa(newkey, "mailbox_alias_new%u", i);
+ }
+
+ MODULE_CONTEXT_SET(user, mailbox_alias_user_module, auser);
+ }
+
+ static void mailbox_alias_mailbox_list_created(struct mailbox_list *list)
+ {
+ struct mailbox_list_vfuncs *v = list->vlast;
+ struct mailbox_alias_mailbox_list *alist;
+
+ alist = p_new(list->pool, struct mailbox_alias_mailbox_list, 1);
+ alist->module_ctx.super = *v;
+ list->vlast = &alist->module_ctx.super;
+
+ v->get_storage_name = mailbox_alias_get_storage_name;
+ MODULE_CONTEXT_SET(list, mailbox_alias_mailbox_list_module, alist);
+ }
+
+ static void mailbox_alias_mailbox_allocated(struct mailbox *box)
+ {
+ struct mailbox_vfuncs *v = box->vlast;
+ struct mailbox_alias_mailbox *abox;
+
+ abox = p_new(box->pool, struct mailbox_alias_mailbox, 1);
+ abox->module_ctx.super = *v;
+ box->vlast = &abox->module_ctx.super;
+
++ v->create_box = mailbox_alias_create;
++ v->delete_box = mailbox_alias_delete;
++ v->rename_box = mailbox_alias_rename;
+ MODULE_CONTEXT_SET(box, mailbox_alias_storage_module, abox);
+ }
+
+ static struct mail_storage_hooks mailbox_alias_mail_storage_hooks = {
+ .mail_user_created = mailbox_alias_mail_user_created,
+ .mailbox_list_created = mailbox_alias_mailbox_list_created,
+ .mailbox_allocated = mailbox_alias_mailbox_allocated
+ };
+
+ void mailbox_alias_plugin_init(struct module *module)
+ {
+ mail_storage_hooks_add(module, &mailbox_alias_mail_storage_hooks);
+ }
+
+ void mailbox_alias_plugin_deinit(void)
+ {
+ mail_storage_hooks_remove(&mailbox_alias_mail_storage_hooks);
+ }