From d23c747de9d33966483fbdd41f08ad7766da7c5c Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Tue, 12 Aug 2008 12:28:42 -0400 Subject: [PATCH] Added struct mail_user and fixed the code to support multiple users per process. --HG-- branch : HEAD --- src/deliver/deliver.c | 26 +- src/imap/client.c | 14 +- src/imap/client.h | 5 +- src/imap/cmd-list.c | 8 +- src/imap/cmd-namespace.c | 6 +- src/imap/cmd-subscribe.c | 4 +- src/imap/commands-util.c | 2 +- src/imap/main.c | 23 +- src/lib-storage/Makefile.am | 2 + .../index/maildir/maildir-storage.c | 16 +- src/lib-storage/index/mbox/mbox-save.c | 8 +- src/lib-storage/index/mbox/mbox-storage.c | 40 +-- src/lib-storage/mail-namespace.c | 20 +- src/lib-storage/mail-namespace.h | 9 +- src/lib-storage/mail-storage-private.h | 1 - src/lib-storage/mail-storage.c | 6 +- src/lib-storage/mail-storage.h | 3 +- src/plugins/acl/acl-mailbox-list.c | 6 +- src/plugins/convert/convert-plugin.c | 6 +- src/plugins/convert/convert-storage.c | 9 +- src/plugins/convert/convert-storage.h | 2 - src/plugins/convert/convert-tool.c | 12 +- src/plugins/expire/expire-plugin.c | 1 + src/plugins/expire/expire-tool.c | 11 +- src/plugins/imap-quota/imap-quota-plugin.c | 8 +- .../lazy-expunge/lazy-expunge-plugin.c | 58 +++- src/plugins/quota/quota-count.c | 2 +- src/plugins/quota/quota-dict.c | 9 +- src/plugins/quota/quota-maildir.c | 18 +- src/plugins/quota/quota-plugin.c | 37 ++- src/plugins/quota/quota-plugin.h | 6 +- src/plugins/quota/quota-private.h | 51 ++-- src/plugins/quota/quota-storage.c | 54 +++- src/plugins/quota/quota.c | 285 ++++++++++-------- src/plugins/quota/quota.h | 34 ++- src/plugins/trash/trash-plugin.c | 19 +- src/plugins/virtual/virtual-config.c | 10 +- src/plugins/virtual/virtual-plugin.c | 22 -- src/plugins/virtual/virtual-plugin.h | 2 - src/plugins/virtual/virtual-storage.c | 3 +- src/pop3/client.c | 9 +- src/pop3/client.h | 6 +- src/pop3/main.c | 8 +- 43 files changed, 510 insertions(+), 371 deletions(-) diff --git a/src/deliver/deliver.c b/src/deliver/deliver.c index 6448e04cfb..f8edc51053 100644 --- a/src/deliver/deliver.c +++ b/src/deliver/deliver.c @@ -777,7 +777,8 @@ int main(int argc, char *argv[]) const char *auth_socket; const char *home, *destaddr, *user, *value, *errstr, *path; ARRAY_TYPE(string) extra_fields; - struct mail_namespace *ns, *raw_ns; + struct mail_user *mail_user, *raw_mail_user; + struct mail_namespace *raw_ns; struct mail_storage *storage; struct mailbox *box; struct raw_mailbox *raw_box; @@ -1002,12 +1003,16 @@ int main(int argc, char *argv[]) module_dir_init(modules); namespace_pool = pool_alloconly_create("namespaces", 1024); - if (mail_namespaces_init(namespace_pool, user, &ns) < 0) + mail_user = mail_user_init(user, home); + if (mail_namespaces_init(namespace_pool, mail_user) < 0) i_fatal("Namespace initialization failed"); - raw_ns = mail_namespaces_init_empty(namespace_pool); + /* create a separate mail user for the internal namespace */ + raw_mail_user = mail_user_init(user, NULL); + raw_ns = mail_namespaces_init_empty(namespace_pool, raw_mail_user); raw_ns->flags |= NAMESPACE_FLAG_INTERNAL; - if (mail_storage_create(raw_ns, "raw", "/tmp", user, + + if (mail_storage_create(raw_ns, "raw", "/tmp", MAIL_STORAGE_FLAG_FULL_FS_ACCESS, FILE_LOCK_METHOD_FCNTL, &errstr) < 0) i_fatal("Couldn't create internal raw storage: %s", errstr); @@ -1044,7 +1049,8 @@ int main(int argc, char *argv[]) if (deliver_mail == NULL) ret = -1; else { - if (deliver_mail(ns, &storage, mail, destaddr, mailbox) <= 0) { + if (deliver_mail(mail_user->namespaces, &storage, mail, + destaddr, mailbox) <= 0) { /* if message was saved, don't bounce it even though the script failed later. */ ret = saved_mail ? 0 : -1; @@ -1056,12 +1062,14 @@ int main(int argc, char *argv[]) if (ret < 0 && !tried_default_save) { /* plugins didn't handle this. save into the default mailbox. */ - ret = deliver_save(ns, &storage, mailbox, mail, 0, NULL); + ret = deliver_save(mail_user->namespaces, + &storage, mailbox, mail, 0, NULL); } if (ret < 0 && strcasecmp(mailbox, "INBOX") != 0) { /* still didn't work. try once more to save it to INBOX. */ - ret = deliver_save(ns, &storage, "INBOX", mail, 0, NULL); + ret = deliver_save(mail_user->namespaces, + &storage, "INBOX", mail, 0, NULL); } if (ret < 0 ) { @@ -1108,8 +1116,8 @@ int main(int argc, char *argv[]) mailbox_transaction_rollback(&t); mailbox_close(&box); - mail_namespaces_deinit(&raw_ns); - mail_namespaces_deinit(&ns); + mail_user_deinit(&mail_user); + mail_user_deinit(&raw_mail_user); module_dir_unload(&modules); mail_storage_deinit(); diff --git a/src/imap/client.c b/src/imap/client.c index 3ac47092a1..5b8a762bb6 100644 --- a/src/imap/client.c +++ b/src/imap/client.c @@ -25,10 +25,10 @@ static void client_idle_timeout(struct client *client) client_destroy(client, "Disconnected for inactivity"); } -struct client *client_create(int fd_in, int fd_out, - struct mail_namespace *namespaces) +struct client *client_create(int fd_in, int fd_out, struct mail_user *user) { struct client *client; + struct mail_namespace *ns; /* always use nonblocking I/O */ net_set_nonblock(fd_in, TRUE); @@ -48,12 +48,11 @@ struct client *client_create(int fd_in, int fd_out, client_idle_timeout, client); client->command_pool = pool_alloconly_create("client command", 1024*12); - client->namespaces = namespaces; + client->user = user; - while (namespaces != NULL) { - mail_storage_set_callbacks(namespaces->storage, + for (ns = user->namespaces; ns != NULL; ns = ns->next) { + mail_storage_set_callbacks(ns->storage, &mail_storage_callbacks, client); - namespaces = namespaces->next; } i_assert(my_client == NULL); @@ -130,6 +129,7 @@ static const char *client_get_disconnect_reason(struct client *client) void client_destroy(struct client *client, const char *reason) { struct client_command_context *cmd; + i_assert(!client->destroyed); client->destroyed = TRUE; @@ -161,7 +161,7 @@ void client_destroy(struct client *client, const char *reason) client_search_updates_free(client); mailbox_close(&client->mailbox); } - mail_namespaces_deinit(&client->namespaces); + mail_user_deinit(&client->user); if (client->free_parser != NULL) imap_parser_destroy(&client->free_parser); diff --git a/src/imap/client.h b/src/imap/client.h index eb236de3d6..ab5b245cb7 100644 --- a/src/imap/client.h +++ b/src/imap/client.h @@ -74,7 +74,7 @@ struct client { struct ostream *output; struct timeout *to_idle, *to_idle_output; - struct mail_namespace *namespaces; + struct mail_user *user; struct mailbox *mailbox; struct mailbox_keywords keywords; unsigned int select_counter; /* increased when mailbox is changed */ @@ -124,8 +124,7 @@ struct client { /* Create new client with specified input/output handles. socket specifies if the handle is a socket. */ -struct client *client_create(int fd_in, int fd_out, - struct mail_namespace *namespaces); +struct client *client_create(int fd_in, int fd_out, struct mail_user *user); void client_destroy(struct client *client, const char *reason); /* Disconnect client connection */ diff --git a/src/imap/cmd-list.c b/src/imap/cmd-list.c index ce9928922c..4e7027c8cc 100644 --- a/src/imap/cmd-list.c +++ b/src/imap/cmd-list.c @@ -185,7 +185,7 @@ list_get_inbox_flags(struct cmd_list_context *ctx) } /* find the INBOX flags */ - ns = mail_namespace_find_inbox(ctx->cmd->client->namespaces); + ns = mail_namespace_find_inbox(ctx->cmd->client->user->namespaces); list_iter = mailbox_list_iter_init(ns->list, "INBOX", 0); info = mailbox_list_iter_next(list_iter); if (info != NULL) { @@ -704,13 +704,13 @@ static void cmd_list_ref_root(struct client *client, const char *ref) /* Special request to return the hierarchy delimiter and mailbox root name. If namespace has a prefix, it's returned as the mailbox root. Otherwise we'll emulate UW-IMAP behavior. */ - ns = mail_namespace_find_visible(client->namespaces, &ref); + ns = mail_namespace_find_visible(client->user->namespaces, &ref); if (ns != NULL) { ns_prefix = ns->prefix; ns_sep = ns->sep; } else { ns_prefix = ""; - ns_sep = mail_namespace_get_root_sep(client->namespaces); + ns_sep = mail_namespace_get_root_sep(client->user->namespaces); } str = t_str_new(64); @@ -754,7 +754,7 @@ bool cmd_list_full(struct client_command_context *cmd, bool lsub) ctx = p_new(cmd->pool, struct cmd_list_context, 1); ctx->cmd = cmd; - ctx->ns = client->namespaces; + ctx->ns = client->user->namespaces; ctx->lsub = lsub; cmd->context = ctx; diff --git a/src/imap/cmd-namespace.c b/src/imap/cmd-namespace.c index 000c56fb59..62f86ce233 100644 --- a/src/imap/cmd-namespace.c +++ b/src/imap/cmd-namespace.c @@ -42,11 +42,11 @@ bool cmd_namespace(struct client_command_context *cmd) str = t_str_new(256); str_append(str, "* NAMESPACE "); - list_namespaces(client->namespaces, NAMESPACE_PRIVATE, str); + list_namespaces(client->user->namespaces, NAMESPACE_PRIVATE, str); str_append_c(str, ' '); - list_namespaces(client->namespaces, NAMESPACE_SHARED, str); + list_namespaces(client->user->namespaces, NAMESPACE_SHARED, str); str_append_c(str, ' '); - list_namespaces(client->namespaces, NAMESPACE_PUBLIC, str); + list_namespaces(client->user->namespaces, NAMESPACE_PUBLIC, str); client_send_line(client, str_c(str)); client_send_tagline(cmd, "OK Namespace completed."); diff --git a/src/imap/cmd-subscribe.c b/src/imap/cmd-subscribe.c index 66bb13cd1f..127845dd35 100644 --- a/src/imap/cmd-subscribe.c +++ b/src/imap/cmd-subscribe.c @@ -35,7 +35,7 @@ bool cmd_subscribe_full(struct client_command_context *cmd, bool subscribe) return FALSE; verify_name = mailbox; - ns = mail_namespace_find_subscribable(cmd->client->namespaces, + ns = mail_namespace_find_subscribable(cmd->client->user->namespaces, &mailbox); if (ns == NULL) { client_send_tagline(cmd, "NO Unknown namespace."); @@ -49,7 +49,7 @@ bool cmd_subscribe_full(struct client_command_context *cmd, bool subscribe) verify_name = t_strndup(verify_name, strlen(verify_name)-1); } - if (have_listable_namespace_prefix(cmd->client->namespaces, + if (have_listable_namespace_prefix(cmd->client->user->namespaces, verify_name)) { /* subscribing to a listable namespace prefix, allow it. */ } else { diff --git a/src/imap/commands-util.c b/src/imap/commands-util.c index adc73adc50..8413dd7da2 100644 --- a/src/imap/commands-util.c +++ b/src/imap/commands-util.c @@ -23,7 +23,7 @@ client_find_namespace(struct client_command_context *cmd, const char **mailbox) { struct mail_namespace *ns; - ns = mail_namespace_find(cmd->client->namespaces, mailbox); + ns = mail_namespace_find(cmd->client->user->namespaces, mailbox); if (ns != NULL) return ns; diff --git a/src/imap/main.c b/src/imap/main.c index 12a577a692..df2ca22a2e 100644 --- a/src/imap/main.c +++ b/src/imap/main.c @@ -161,8 +161,8 @@ static void main_init(void) { struct client *client; struct ostream *output; - struct mail_namespace *ns; - const char *user, *str, *tag; + struct mail_user *user; + const char *username, *home, *str, *tag; lib_signals_init(); lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL); @@ -170,18 +170,16 @@ static void main_init(void) lib_signals_ignore(SIGPIPE, TRUE); lib_signals_ignore(SIGALRM, FALSE); - user = getenv("USER"); - if (user == NULL) { + username = getenv("USER"); + if (username == NULL) { if (IS_STANDALONE()) - user = getlogin(); - if (user == NULL) + username = getlogin(); + if (username == NULL) i_fatal("USER environment missing"); } + home = getenv("HOME"); if (getenv("DEBUG") != NULL) { - const char *home; - - home = getenv("HOME"); i_info("Effective uid=%s, gid=%s, home=%s", dec2str(geteuid()), dec2str(getegid()), home != NULL ? home : "(none)"); @@ -232,9 +230,10 @@ static void main_init(void) parse_workarounds(); namespace_pool = pool_alloconly_create("namespaces", 1024); - if (mail_namespaces_init(namespace_pool, user, &ns) < 0) + user = mail_user_init(username, home); + if (mail_namespaces_init(namespace_pool, user) < 0) i_fatal("Namespace initialization failed"); - client = client_create(0, 1, ns); + client = client_create(0, 1, user); output = client->output; o_stream_ref(output); @@ -246,7 +245,7 @@ static void main_init(void) client_send_line(client, t_strconcat( "* PREAUTH [CAPABILITY ", str_c(capability_string), "] " - "Logged in as ", user, NULL)); + "Logged in as ", user->username, NULL)); } else { client_send_line(client, t_strconcat( tag, " OK [CAPABILITY ", diff --git a/src/lib-storage/Makefile.am b/src/lib-storage/Makefile.am index 11fd9b2116..2eaf088530 100644 --- a/src/lib-storage/Makefile.am +++ b/src/lib-storage/Makefile.am @@ -16,6 +16,7 @@ libstorage_a_SOURCES = \ mail-search.c \ mail-search-build.c \ mail-storage.c \ + mail-user.c \ mailbox-list.c \ mailbox-search-result.c \ mailbox-tree.c @@ -29,6 +30,7 @@ headers = \ mail-thread.h \ mail-storage.h \ mail-storage-private.h \ + mail-user.h \ mailbox-list.h \ mailbox-list-private.h \ mailbox-search-result-private.h \ diff --git a/src/lib-storage/index/maildir/maildir-storage.c b/src/lib-storage/index/maildir/maildir-storage.c index 8ce23f7148..c2874d76b8 100644 --- a/src/lib-storage/index/maildir/maildir-storage.c +++ b/src/lib-storage/index/maildir/maildir-storage.c @@ -60,11 +60,13 @@ maildirplusplus_iter_is_mailbox(struct mailbox_list_iterate_context *ctx, static int maildir_get_list_settings(struct mailbox_list_settings *list_set, - const char *data, enum mail_storage_flags flags, + const char *data, struct mail_storage *storage, const char **layout_r, const char **error_r) { + enum mail_storage_flags flags = storage->flags; + struct mail_user *user = storage->ns->user; bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0; - const char *home, *path; + const char *path; *layout_r = MAILDIR_PLUSPLUS_DRIVER_NAME; @@ -79,9 +81,9 @@ maildir_get_list_settings(struct mailbox_list_settings *list_set, } /* we'll need to figure out the maildir location ourself. - It's $HOME/Maildir unless we are chrooted. */ - if ((home = getenv("HOME")) != NULL) { - path = t_strconcat(home, "/Maildir", NULL); + It's ~/Maildir unless we are chrooted. */ + if (user->home != NULL) { + path = t_strconcat(user->home, "/Maildir", NULL); if (access(path, R_OK|W_OK|X_OK) == 0) { if (debug) { i_info("maildir: root exists (%s)", @@ -96,7 +98,7 @@ maildir_get_list_settings(struct mailbox_list_settings *list_set, } } else { if (debug) - i_info("maildir: HOME not set"); + i_info("maildir: Home directory not set"); } if (access("/cur", R_OK|W_OK|X_OK) == 0) { @@ -191,7 +193,7 @@ maildir_create(struct mail_storage *_storage, const char *data, const char *layout; struct stat st; - if (maildir_get_list_settings(&list_set, data, flags, &layout, + if (maildir_get_list_settings(&list_set, data, _storage, &layout, error_r) < 0) return -1; list_set.mail_storage_flags = &_storage->flags; diff --git a/src/lib-storage/index/mbox/mbox-save.c b/src/lib-storage/index/mbox/mbox-save.c index 3f55bd4a91..b897651335 100644 --- a/src/lib-storage/index/mbox/mbox-save.c +++ b/src/lib-storage/index/mbox/mbox-save.c @@ -135,9 +135,11 @@ static int write_from_line(struct mbox_save_context *ctx, time_t received_date, const char *line; if (from_envelope == NULL) { - from_envelope = - t_strconcat(ctx->mbox->storage->storage.user, - "@", my_hostdomain, NULL); + struct mail_storage *storage = + &ctx->mbox->storage->storage; + + from_envelope = t_strconcat(storage->ns->user->username, + "@", my_hostdomain, NULL); } /* save in local timezone, no matter what it was given with */ diff --git a/src/lib-storage/index/mbox/mbox-storage.c b/src/lib-storage/index/mbox/mbox-storage.c index 15deb252df..35cf59d9a9 100644 --- a/src/lib-storage/index/mbox/mbox-storage.c +++ b/src/lib-storage/index/mbox/mbox-storage.c @@ -185,12 +185,12 @@ static bool mbox_autodetect(const char *data, enum mail_storage_flags flags) return FALSE; } -static const char *get_root_dir(enum mail_storage_flags flags) +static const char *get_root_dir(struct mail_storage *storage) { const char *home, *path; - bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0; + bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0; - home = getenv("HOME"); + home = storage->ns->user->home; if (home != NULL) { path = t_strconcat(home, "/mail", NULL); if (access(path, R_OK|W_OK|X_OK) == 0) { @@ -213,7 +213,7 @@ static const char *get_root_dir(enum mail_storage_flags flags) if (debug) i_info("mbox: checking if we are chrooted:"); - if (mbox_autodetect("", flags)) + if (mbox_autodetect("", storage->flags)) return "/"; if (debug) @@ -223,11 +223,12 @@ static const char *get_root_dir(enum mail_storage_flags flags) } static const char * -get_inbox_file(const char *root_dir, bool only_root, bool debug) +get_inbox_file(const char *user, const char *root_dir, + bool only_root, bool debug) { - const char *user, *path; + const char *path; - if (!only_root && (user = getenv("USER")) != NULL) { + if (!only_root) { path = t_strconcat("/var/mail/", user, NULL); if (access(path, R_OK|W_OK) == 0) { if (debug) @@ -253,11 +254,12 @@ get_inbox_file(const char *root_dir, bool only_root, bool debug) return path; } -static const char *create_root_dir(bool debug, const char **error_r) +static const char *create_root_dir(struct mail_storage *storage, + const char **error_r) { const char *home, *path; - home = getenv("HOME"); + home = storage->ns->user->home; if (home == NULL) { *error_r = "Root mail directory not set and " "home directory is missing"; @@ -270,16 +272,17 @@ static const char *create_root_dir(bool debug, const char **error_r) return NULL; } - if (debug) + if ((storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0) i_info("mbox: root directory created: %s", path); return path; } static int mbox_get_list_settings(struct mailbox_list_settings *list_set, - const char *data, enum mail_storage_flags flags, + const char *data, struct mail_storage *storage, const char **layout_r, const char **error_r) { + enum mail_storage_flags flags = storage->flags; bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0; const char *p; struct stat st; @@ -300,8 +303,8 @@ mbox_get_list_settings(struct mailbox_list_settings *list_set, /* we'll need to figure out the mail location ourself. it's root dir if we've already chroot()ed, otherwise - either $HOME/mail or $HOME/Mail */ - list_set->root_dir = get_root_dir(flags); + either ~/mail or ~/Mail */ + list_set->root_dir = get_root_dir(storage); } else { if (debug) i_info("mbox: data=%s", data); @@ -313,7 +316,7 @@ mbox_get_list_settings(struct mailbox_list_settings *list_set, if (stat(data, &st) < 0 || S_ISDIR(st.st_mode)) list_set->root_dir = data; else { - list_set->root_dir = get_root_dir(flags); + list_set->root_dir = get_root_dir(storage); list_set->inbox_path = data; } } else { @@ -330,7 +333,7 @@ mbox_get_list_settings(struct mailbox_list_settings *list_set, return -1; } - list_set->root_dir = create_root_dir(debug, error_r); + list_set->root_dir = create_root_dir(storage, error_r); if (list_set->root_dir == NULL) return -1; } else { @@ -360,7 +363,8 @@ mbox_get_list_settings(struct mailbox_list_settings *list_set, if (list_set->inbox_path == NULL) { list_set->inbox_path = - get_inbox_file(list_set->root_dir, !autodetect, debug); + get_inbox_file(storage->ns->user->username, + list_set->root_dir, !autodetect, debug); } return 0; } @@ -432,8 +436,8 @@ static int mbox_create(struct mail_storage *_storage, const char *data, struct mailbox_list_settings list_set; const char *layout; - if (mbox_get_list_settings(&list_set, data, - _storage->flags, &layout, error_r) < 0) + if (mbox_get_list_settings(&list_set, data, _storage, + &layout, error_r) < 0) return -1; list_set.mail_storage_flags = &_storage->flags; list_set.lock_method = &_storage->lock_method; diff --git a/src/lib-storage/mail-namespace.c b/src/lib-storage/mail-namespace.c index 4f71fd0a8b..6c66e5d701 100644 --- a/src/lib-storage/mail-namespace.c +++ b/src/lib-storage/mail-namespace.c @@ -29,7 +29,7 @@ void mail_namespace_init_storage(struct mail_namespace *ns) static struct mail_namespace * namespace_add_env(pool_t pool, const char *data, unsigned int num, - const char *user, enum mail_storage_flags flags, + struct mail_user *user, enum mail_storage_flags flags, enum file_lock_method lock_method) { struct mail_namespace *ns; @@ -77,8 +77,9 @@ namespace_add_env(pool_t pool, const char *data, unsigned int num, if (sep != NULL) ns->sep = *sep; ns->prefix = p_strdup(pool, prefix); + ns->user = user; - if (mail_storage_create(ns, NULL, data, user, flags, lock_method, + if (mail_storage_create(ns, NULL, data, flags, lock_method, &error) < 0) { i_error("Namespace '%s': %s", ns->prefix, error); return NULL; @@ -177,8 +178,7 @@ namespaces_sort(struct mail_namespace *src) return dest; } -int mail_namespaces_init(pool_t pool, const char *user, - struct mail_namespace **namespaces_r) +int mail_namespaces_init(pool_t pool, struct mail_user *user) { struct mail_namespace *namespaces, *ns, **ns_p; enum mail_storage_flags flags; @@ -213,7 +213,7 @@ int mail_namespaces_init(pool_t pool, const char *user, if (!namespaces_check(namespaces)) return -1; namespaces = namespaces_sort(namespaces); - *namespaces_r = namespaces; + user->namespaces = namespaces; if (hook_mail_namespaces_created != NULL) { T_BEGIN { @@ -237,8 +237,9 @@ int mail_namespaces_init(pool_t pool, const char *user, ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST | NAMESPACE_FLAG_SUBSCRIPTIONS; ns->prefix = ""; + ns->user = user; - if (mail_storage_create(ns, NULL, mail, user, flags, lock_method, + if (mail_storage_create(ns, NULL, mail, flags, lock_method, &error) < 0) { if (mail != NULL && *mail != '\0') i_error("mail_location: %s", error); @@ -248,7 +249,7 @@ int mail_namespaces_init(pool_t pool, const char *user, } return -1; } - *namespaces_r = ns; + user->namespaces = ns; if (hook_mail_namespaces_created != NULL) { T_BEGIN { @@ -258,14 +259,17 @@ int mail_namespaces_init(pool_t pool, const char *user, return 0; } -struct mail_namespace *mail_namespaces_init_empty(pool_t pool) +struct mail_namespace * +mail_namespaces_init_empty(pool_t pool, struct mail_user *user) { struct mail_namespace *ns; ns = p_new(pool, struct mail_namespace, 1); + ns->user = user; ns->prefix = ""; ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST | NAMESPACE_FLAG_SUBSCRIPTIONS; + user->namespaces = ns; return ns; } diff --git a/src/lib-storage/mail-namespace.h b/src/lib-storage/mail-namespace.h index f9c737f15b..bcdeae1c60 100644 --- a/src/lib-storage/mail-namespace.h +++ b/src/lib-storage/mail-namespace.h @@ -1,6 +1,8 @@ #ifndef MAIL_NAMESPACE_H #define MAIL_NAMESPACE_H +#include "mail-user.h" + enum namespace_type { NAMESPACE_PRIVATE, NAMESPACE_SHARED, @@ -32,6 +34,7 @@ struct mail_namespace { const char *prefix; size_t prefix_len; + struct mail_user *user; struct mailbox_list *list; /* FIXME: we should support multiple storages in one namespace */ struct mail_storage *storage; @@ -40,9 +43,9 @@ struct mail_namespace { /* Called after namespaces has been created */ extern void (*hook_mail_namespaces_created)(struct mail_namespace *namespaces); -int mail_namespaces_init(pool_t pool, const char *user, - struct mail_namespace **namespaces_r); -struct mail_namespace *mail_namespaces_init_empty(pool_t pool); +int mail_namespaces_init(pool_t pool, struct mail_user *user); +struct mail_namespace * +mail_namespaces_init_empty(pool_t pool, struct mail_user *user); void mail_namespaces_deinit(struct mail_namespace **namespaces); /* Update hierarchy separators in given name to real_sep characters. */ diff --git a/src/lib-storage/mail-storage-private.h b/src/lib-storage/mail-storage-private.h index 70f43ad26a..933922bb97 100644 --- a/src/lib-storage/mail-storage-private.h +++ b/src/lib-storage/mail-storage-private.h @@ -61,7 +61,6 @@ struct mail_storage { struct mail_namespace *ns; struct mailbox_list *list; - const char *user; /* name of user accessing the storage */ enum mail_storage_flags flags; enum file_lock_method lock_method; unsigned int keyword_max_len; diff --git a/src/lib-storage/mail-storage.c b/src/lib-storage/mail-storage.c index 936ef6395d..41cce6c42e 100644 --- a/src/lib-storage/mail-storage.c +++ b/src/lib-storage/mail-storage.c @@ -169,8 +169,7 @@ mail_storage_set_autodetection(const char **data, const char **driver, } int mail_storage_create(struct mail_namespace *ns, const char *driver, - const char *data, const char *user, - enum mail_storage_flags flags, + const char *data, enum mail_storage_flags flags, enum file_lock_method lock_method, const char **error_r) { @@ -214,7 +213,6 @@ int mail_storage_create(struct mail_namespace *ns, const char *driver, storage = classes[i]->v.alloc(); storage->flags = flags; storage->lock_method = lock_method; - storage->user = p_strdup(storage->pool, user); storage->ns = ns; storage->callbacks = @@ -239,7 +237,7 @@ int mail_storage_create(struct mail_namespace *ns, const char *driver, return -1; } - home = getenv("HOME"); + home = ns->user->home; if (home == NULL || *home == '\0') home = "(not set)"; *error_r = t_strdup_printf( diff --git a/src/lib-storage/mail-storage.h b/src/lib-storage/mail-storage.h index 80dd30ef53..4e6451cb07 100644 --- a/src/lib-storage/mail-storage.h +++ b/src/lib-storage/mail-storage.h @@ -248,8 +248,7 @@ void mail_storage_parse_env(enum mail_storage_flags *flags_r, from data. If data is NULL, it uses the first storage that exists. The storage is put into ns->storage. */ int mail_storage_create(struct mail_namespace *ns, const char *driver, - const char *data, const char *user, - enum mail_storage_flags flags, + const char *data, enum mail_storage_flags flags, enum file_lock_method lock_method, const char **error_r); void mail_storage_destroy(struct mail_storage **storage); diff --git a/src/plugins/acl/acl-mailbox-list.c b/src/plugins/acl/acl-mailbox-list.c index 53dd11c81a..09a1240ece 100644 --- a/src/plugins/acl/acl-mailbox-list.c +++ b/src/plugins/acl/acl-mailbox-list.c @@ -415,10 +415,7 @@ void acl_mailbox_list_created(struct mailbox_list *list) acl_env = getenv("ACL"); i_assert(acl_env != NULL); - owner_username = getenv("USER"); - if (owner_username == NULL) - i_fatal("ACL: USER environment not set"); - + owner_username = list->ns->user->username; current_username = getenv("MASTER_USER"); if (current_username == NULL) current_username = owner_username; @@ -432,7 +429,6 @@ void acl_mailbox_list_created(struct mailbox_list *list) if (ns->type != NAMESPACE_PRIVATE) owner = FALSE; - /* FIXME: set groups */ backend = acl_backend_init(acl_env, list, current_username, getenv("ACL_GROUPS") == NULL ? NULL : t_strsplit(getenv("ACL_GROUPS"), ","), diff --git a/src/plugins/convert/convert-plugin.c b/src/plugins/convert/convert-plugin.c index b01006a271..46d0288661 100644 --- a/src/plugins/convert/convert-plugin.c +++ b/src/plugins/convert/convert-plugin.c @@ -19,11 +19,7 @@ static void convert_mail_storage(struct mail_namespace *namespaces, struct convert_settings set; memset(&set, 0, sizeof(set)); - set.user = getenv("USER"); - if (set.user == NULL) - i_fatal("convert plugin: USER unset"); - set.home = getenv("HOME"); - if (set.home == NULL) + if (namespaces->user->home == NULL) i_fatal("convert plugin: HOME unset"); set.skip_broken_mailboxes = diff --git a/src/plugins/convert/convert-storage.c b/src/plugins/convert/convert-storage.c index d4447bae8b..e7625251ca 100644 --- a/src/plugins/convert/convert-storage.c +++ b/src/plugins/convert/convert-storage.c @@ -392,6 +392,7 @@ int convert_storage(const char *source_data, struct mail_namespace *dest_namespaces, const struct convert_settings *set) { + struct mail_user *user = dest_namespaces->user; struct mail_namespace *source_ns, *dest_inbox_ns; struct dotlock *dotlock; enum mail_storage_flags src_flags; @@ -399,19 +400,19 @@ int convert_storage(const char *source_data, const char *path, *error; int ret; - source_ns = mail_namespaces_init_empty(pool_datastack_create()); + source_ns = mail_namespaces_init_empty(pool_datastack_create(), user); dest_inbox_ns = mail_namespace_find_inbox(dest_namespaces); src_flags = dest_inbox_ns->storage->flags; lock_method = dest_inbox_ns->storage->lock_method; src_flags |= MAIL_STORAGE_FLAG_NO_AUTOCREATE; - if (mail_storage_create(source_ns, NULL, source_data, set->user, + if (mail_storage_create(source_ns, NULL, source_data, src_flags, lock_method, &error) < 0) { /* No need for conversion. */ return 0; } - path = t_strconcat(set->home, "/"CONVERT_LOCK_FILENAME, NULL); + path = t_strconcat(user->home, "/"CONVERT_LOCK_FILENAME, NULL); dotlock_settings.use_excl_lock = (source_ns->storage->flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0; @@ -430,7 +431,7 @@ int convert_storage(const char *source_data, /* just in case if another process just had converted the mailbox, reopen the source storage */ mail_storage_destroy(&source_ns->storage); - if (mail_storage_create(source_ns, NULL, source_data, set->user, + if (mail_storage_create(source_ns, NULL, source_data, src_flags, lock_method, &error) < 0) { /* No need for conversion anymore. */ file_dotlock_delete(&dotlock); diff --git a/src/plugins/convert/convert-storage.h b/src/plugins/convert/convert-storage.h index 04b4f9db69..ab121e8220 100644 --- a/src/plugins/convert/convert-storage.h +++ b/src/plugins/convert/convert-storage.h @@ -4,8 +4,6 @@ struct mail_namespace; struct convert_settings { - const char *user; - const char *home; bool skip_broken_mailboxes; bool skip_dotdirs; char alt_hierarchy_char; diff --git a/src/plugins/convert/convert-tool.c b/src/plugins/convert/convert-tool.c index df51827f2f..ac62cc1658 100644 --- a/src/plugins/convert/convert-tool.c +++ b/src/plugins/convert/convert-tool.c @@ -18,6 +18,7 @@ int main(int argc, const char *argv[]) { struct ioloop *ioloop; struct convert_settings set; + struct mail_user *user; struct mail_namespace *dest_ns; enum mail_storage_flags dest_flags; enum file_lock_method lock_method; @@ -37,9 +38,6 @@ int main(int argc, const char *argv[]) ioloop = io_loop_create(); memset(&set, 0, sizeof(set)); - set.user = argv[1]; - set.home = argv[2]; - for (i = 5; i < argc; i++) { if (strcmp(argv[i], "skip_broken_mailboxes") != 0) set.skip_broken_mailboxes = TRUE; @@ -50,8 +48,10 @@ int main(int argc, const char *argv[]) } mail_storage_parse_env(&dest_flags, &lock_method); - dest_ns = mail_namespaces_init_empty(pool_datastack_create()); - if (mail_storage_create(dest_ns, NULL, argv[4], set.user, + user = mail_user_init(argv[1], argv[2]); + dest_ns = mail_namespaces_init_empty(pool_datastack_create(), user); + + if (mail_storage_create(dest_ns, NULL, argv[4], dest_flags, lock_method, &error) < 0) { i_fatal("Failed to create destination " "mail storage with data '%s': %s", argv[4], error); @@ -64,7 +64,7 @@ int main(int argc, const char *argv[]) i_error("Source storage not found"); else i_error("Internal failure"); - mail_namespaces_deinit(&dest_ns); + mail_user_deinit(&user); io_loop_destroy(&ioloop); mail_storage_deinit(); diff --git a/src/plugins/expire/expire-plugin.c b/src/plugins/expire/expire-plugin.c index 29a0f82673..35ccf20fc3 100644 --- a/src/plugins/expire/expire-plugin.c +++ b/src/plugins/expire/expire-plugin.c @@ -294,6 +294,7 @@ void expire_plugin_init(void) if (dict_uri == NULL) i_fatal("expire plugin: expire_dict setting missing"); + // FIXME: user should be per-mail_user?... expire.username = getenv("USER"); expire.env = expire_env_init(expunge_env, altmove_env); expire.db = dict_init(dict_uri, DICT_DATA_TYPE_UINT32, expire.username); diff --git a/src/plugins/expire/expire-tool.c b/src/plugins/expire/expire-tool.c index d06116d2be..6f23d6f1c1 100644 --- a/src/plugins/expire/expire-tool.c +++ b/src/plugins/expire/expire-tool.c @@ -2,6 +2,7 @@ #include "lib.h" #include "ioloop.h" +#include "env-util.h" #include "file-lock.h" #include "randgen.h" #include "lib-signals.h" @@ -25,8 +26,8 @@ struct expire_context { struct auth_connection *auth_conn; char *user; + struct mail_user *mail_user; pool_t namespace_pool; - struct mail_namespace *ns; bool testrun; }; @@ -34,6 +35,7 @@ static int user_init(struct expire_context *ctx, const char *user) { int ret; + env_clean(); if ((ret = auth_client_put_user_env(ctx->auth_conn, user)) <= 0) { if (ret < 0) return ret; @@ -42,14 +44,15 @@ static int user_init(struct expire_context *ctx, const char *user) return 0; } - if (mail_namespaces_init(ctx->namespace_pool, user, &ctx->ns) < 0) + ctx->mail_user = mail_user_init(user, getenv("HOME")); + if (mail_namespaces_init(ctx->namespace_pool, ctx->mail_user) < 0) return -1; return 1; } static void user_deinit(struct expire_context *ctx) { - mail_namespaces_deinit(&ctx->ns); + mail_user_deinit(&ctx->mail_user); i_free_and_null(ctx->user); p_clear(ctx->namespace_pool); } @@ -86,7 +89,7 @@ mailbox_delete_old_mails(struct expire_context *ctx, const char *user, } ns_mailbox = mailbox; - ns = mail_namespace_find(ctx->ns, &ns_mailbox); + ns = mail_namespace_find(ctx->mail_user->namespaces, &ns_mailbox); if (ns == NULL) { /* entire namespace no longer exists, remove the entry */ if (ctx->testrun) diff --git a/src/plugins/imap-quota/imap-quota-plugin.c b/src/plugins/imap-quota/imap-quota-plugin.c index f289932390..edfa43a6ca 100644 --- a/src/plugins/imap-quota/imap-quota-plugin.c +++ b/src/plugins/imap-quota/imap-quota-plugin.c @@ -82,7 +82,7 @@ static bool cmd_getquotaroot(struct client_command_context *cmd) str_append(str, "* QUOTAROOT "); imap_quote_append_string(str, orig_mailbox, FALSE); - iter = quota_root_iter_init(quota_set, box); + iter = quota_root_iter_init(box); while ((root = quota_root_iter_next(iter)) != NULL) { str_append_c(str, ' '); imap_quote_append_string(str, quota_root_get_name(root), FALSE); @@ -91,7 +91,7 @@ static bool cmd_getquotaroot(struct client_command_context *cmd) client_send_line(cmd->client, str_c(str)); /* send QUOTA reply for each quotaroot */ - iter = quota_root_iter_init(quota_set, box); + iter = quota_root_iter_init(box); while ((root = quota_root_iter_next(iter)) != NULL) quota_send(cmd, root); quota_root_iter_deinit(&iter); @@ -115,7 +115,7 @@ static bool cmd_getquota(struct client_command_context *cmd) return TRUE; } - root = quota_root_lookup(quota_set, root_name); + root = quota_root_lookup(cmd->client->user, root_name); if (root == NULL) { client_send_tagline(cmd, "NO Quota root doesn't exist."); return TRUE; @@ -148,7 +148,7 @@ static bool cmd_setquota(struct client_command_context *cmd) return TRUE; } - root = quota_root_lookup(quota_set, root_name); + root = quota_root_lookup(cmd->client->user, root_name); if (root == NULL) { client_send_tagline(cmd, "NO Quota root doesn't exist."); return TRUE; diff --git a/src/plugins/lazy-expunge/lazy-expunge-plugin.c b/src/plugins/lazy-expunge/lazy-expunge-plugin.c index a8753c0b2b..422f69c6b8 100644 --- a/src/plugins/lazy-expunge/lazy-expunge-plugin.c +++ b/src/plugins/lazy-expunge/lazy-expunge-plugin.c @@ -19,6 +19,8 @@ MODULE_CONTEXT(obj, lazy_expunge_mail_storage_module) #define LAZY_EXPUNGE_LIST_CONTEXT(obj) \ MODULE_CONTEXT(obj, lazy_expunge_mailbox_list_module) +#define LAZY_EXPUNGE_USER_CONTEXT(obj) \ + MODULE_CONTEXT(obj, lazy_expunge_mail_user_module) enum lazy_namespace { LAZY_NAMESPACE_EXPUNGE, @@ -28,6 +30,12 @@ enum lazy_namespace { LAZY_NAMESPACE_COUNT }; +struct lazy_expunge_mail_user { + union mail_user_module_context module_ctx; + + struct mail_namespace *lazy_ns[LAZY_NAMESPACE_COUNT]; +}; + struct lazy_expunge_mailbox_list { union mailbox_list_module_context module_ctx; @@ -57,6 +65,7 @@ static void (*lazy_expunge_next_hook_mail_storage_created) (struct mail_storage *storage); static void (*lazy_expunge_next_hook_mailbox_list_created) (struct mailbox_list *list); +static void (*lazy_expunge_next_hook_mail_user_created)(struct mail_user *user); static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_storage_module, &mail_storage_module_register); @@ -64,8 +73,8 @@ static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_module, &mail_module_register); static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mailbox_list_module, &mailbox_list_module_register); - -static struct mail_namespace *lazy_namespaces[LAZY_NAMESPACE_COUNT]; +static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_user_module, + &mail_user_module_register); static struct mailbox * mailbox_open_or_create(struct mail_storage *storage, const char *name) @@ -95,12 +104,14 @@ mailbox_open_or_create(struct mail_storage *storage, const char *name) static void lazy_expunge_mail_expunge(struct mail *_mail) { + struct lazy_expunge_mail_user *luser = + LAZY_EXPUNGE_USER_CONTEXT(_mail->box->storage->ns->user); struct lazy_expunge_transaction *lt = LAZY_EXPUNGE_CONTEXT(_mail->transaction); struct mail_storage *deststorage; if (lt->expunge_box == NULL) { - deststorage = lazy_namespaces[LAZY_NAMESPACE_EXPUNGE]->storage; + deststorage = luser->lazy_ns[LAZY_NAMESPACE_EXPUNGE]->storage; lt->expunge_box = mailbox_open_or_create(deststorage, _mail->box->name); if (lt->expunge_box == NULL) { @@ -414,6 +425,8 @@ mailbox_move(struct mailbox_list *src_list, const char *src_name, static int lazy_expunge_mailbox_list_delete(struct mailbox_list *list, const char *name) { + struct lazy_expunge_mail_user *luser = + LAZY_EXPUNGE_USER_CONTEXT(list->ns->user); struct lazy_expunge_mailbox_list *llist = LAZY_EXPUNGE_LIST_CONTEXT(list); struct lazy_expunge_mail_storage *lstorage; @@ -455,7 +468,7 @@ lazy_expunge_mailbox_list_delete(struct mailbox_list *list, const char *name) destname = t_strconcat(name, "-", timestamp, NULL); /* first move the actual mailbox */ - dest_list = lazy_namespaces[LAZY_NAMESPACE_DELETE]->storage->list; + dest_list = luser->lazy_ns[LAZY_NAMESPACE_DELETE]->storage->list; if ((ret = mailbox_move(list, name, dest_list, &destname)) < 0) return -1; if (ret == 0) { @@ -465,9 +478,9 @@ lazy_expunge_mailbox_list_delete(struct mailbox_list *list, const char *name) } /* next move the expunged messages mailbox, if it exists */ - list = lazy_namespaces[LAZY_NAMESPACE_EXPUNGE]->storage->list; + list = luser->lazy_ns[LAZY_NAMESPACE_EXPUNGE]->storage->list; dest_list = - lazy_namespaces[LAZY_NAMESPACE_DELETE_EXPUNGE]->storage->list; + luser->lazy_ns[LAZY_NAMESPACE_DELETE_EXPUNGE]->storage->list; (void)mailbox_move(list, name, dest_list, &destname); return 0; } @@ -526,13 +539,12 @@ static void lazy_expunge_mailbox_list_created(struct mailbox_list *list) static void lazy_expunge_hook_mail_namespaces_created(struct mail_namespace *namespaces) { + struct lazy_expunge_mail_user *luser = + LAZY_EXPUNGE_USER_CONTEXT(namespaces->user); struct lazy_expunge_mail_storage *lstorage; const char *const *p; int i; - if (lazy_expunge_next_hook_mail_namespaces_created != NULL) - lazy_expunge_next_hook_mail_namespaces_created(namespaces); - p = t_strsplit_spaces(getenv("LAZY_EXPUNGE"), " "); for (i = 0; i < LAZY_NAMESPACE_COUNT; i++, p++) { const char *name = *p; @@ -540,20 +552,36 @@ lazy_expunge_hook_mail_namespaces_created(struct mail_namespace *namespaces) if (name == NULL) i_fatal("lazy_expunge: Missing namespace #%d", i + 1); - lazy_namespaces[i] = + luser->lazy_ns[i] = mail_namespace_find_prefix(namespaces, name); - if (lazy_namespaces[i] == NULL) + if (luser->lazy_ns[i] == NULL) i_fatal("lazy_expunge: Unknown namespace: '%s'", name); - if (strcmp(lazy_namespaces[i]->storage->name, "maildir") != 0) { + if (strcmp(luser->lazy_ns[i]->storage->name, "maildir") != 0) { i_fatal("lazy_expunge: Namespace must be in maildir " "format: %s", name); } /* we don't want to override these namespaces' expunge/delete operations. */ - lstorage = LAZY_EXPUNGE_CONTEXT(lazy_namespaces[i]->storage); + lstorage = LAZY_EXPUNGE_CONTEXT(luser->lazy_ns[i]->storage); lstorage->internal_namespace = TRUE; } + + if (lazy_expunge_next_hook_mail_namespaces_created != NULL) + lazy_expunge_next_hook_mail_namespaces_created(namespaces); +} + +static void lazy_expunge_mail_user_created(struct mail_user *user) +{ + struct lazy_expunge_mail_user *luser; + + luser = p_new(user->pool, struct lazy_expunge_mail_user, 1); + luser->module_ctx.super = user->v; + + MODULE_CONTEXT_SET(user, lazy_expunge_mail_user_module, luser); + + if (lazy_expunge_next_hook_mail_user_created != NULL) + lazy_expunge_next_hook_mail_user_created(user); } void lazy_expunge_plugin_init(void) @@ -571,6 +599,9 @@ void lazy_expunge_plugin_init(void) lazy_expunge_next_hook_mailbox_list_created = hook_mailbox_list_created; hook_mailbox_list_created = lazy_expunge_mailbox_list_created; + + lazy_expunge_next_hook_mail_user_created = hook_mail_user_created; + hook_mail_user_created = lazy_expunge_mail_user_created; } void lazy_expunge_plugin_deinit(void) @@ -582,4 +613,5 @@ void lazy_expunge_plugin_deinit(void) lazy_expunge_hook_mail_namespaces_created; hook_mail_storage_created = lazy_expunge_next_hook_mail_storage_created; hook_mailbox_list_created = lazy_expunge_next_hook_mailbox_list_created; + hook_mail_user_created = lazy_expunge_next_hook_mail_user_created; } diff --git a/src/plugins/quota/quota-count.c b/src/plugins/quota/quota-count.c index 397aff56af..bf2cdfc43d 100644 --- a/src/plugins/quota/quota-count.c +++ b/src/plugins/quota/quota-count.c @@ -19,7 +19,7 @@ quota_count_mailbox(struct quota_root *root, struct mail_storage *storage, uoff_t size; int ret = 0; - rule = quota_root_rule_find(root, name); + rule = quota_root_rule_find(root->set, name); if (rule != NULL && rule->ignore) { /* mailbox not included in quota */ return 0; diff --git a/src/plugins/quota/quota-dict.c b/src/plugins/quota/quota-dict.c index ce54cf736d..02c8d7944e 100644 --- a/src/plugins/quota/quota-dict.c +++ b/src/plugins/quota/quota-dict.c @@ -3,6 +3,7 @@ #include "lib.h" #include "str.h" #include "dict.h" +#include "mail-user.h" #include "quota-private.h" #include @@ -48,9 +49,9 @@ static int dict_quota_init(struct quota_root *_root, const char *args) } if (*username == '\0') - username = getenv("USER"); + username = _root->quota->user->username; - if (_root->quota->debug) { + if (_root->quota->set->debug) { i_info("dict quota: user=%s, uri=%s, enforcing=%d", username, args, _root->no_enforcing); } @@ -104,8 +105,8 @@ dict_quota_count(struct dict_quota_root *root, } static int -dict_quota_get_resource(struct quota_root *_root, const char *name, - uint64_t *value_r) +dict_quota_get_resource(struct quota_root *_root, + const char *name, uint64_t *value_r) { struct dict_quota_root *root = (struct dict_quota_root *)_root; bool want_bytes; diff --git a/src/plugins/quota/quota-maildir.c b/src/plugins/quota/quota-maildir.c index d73c7f8bc9..108bc3c289 100644 --- a/src/plugins/quota/quota-maildir.c +++ b/src/plugins/quota/quota-maildir.c @@ -149,7 +149,7 @@ maildir_list_next(struct maildir_list_context *ctx, time_t *mtime_r) if (ctx->info == NULL) return NULL; - rule = quota_root_rule_find(&ctx->root->root, + rule = quota_root_rule_find(ctx->root->root.set, ctx->info->name); if (rule != NULL && rule->ignore) { /* mailbox not included in quota */ @@ -217,7 +217,7 @@ maildirs_check_have_changed(struct maildir_quota_root *root, static int maildirsize_write(struct maildir_quota_root *root, const char *path) { - const struct quota_rule *rule = &root->root.default_rule; + const struct quota_rule *rule = &root->root.set->default_rule; struct mail_storage *const *storages; unsigned int i, count; struct dotlock *dotlock; @@ -319,7 +319,7 @@ static int maildirsize_recalculate_storage(struct maildir_quota_root *root, static void maildirsize_rebuild_later(struct maildir_quota_root *root) { - if (!root->root.force_default_rule) { + if (!root->root.set->force_default_rule) { /* FIXME: can't unlink(), because the limits would be lost. */ return; } @@ -410,7 +410,7 @@ maildir_parse_limit(const char *str, uint64_t *bytes_r, uint64_t *count_r) static int maildirsize_parse(struct maildir_quota_root *root, int fd, const char *const *lines) { - struct quota_rule *rule = &root->root.default_rule; + struct quota_rule *rule = &root->root.set->default_rule; uint64_t message_bytes_limit, message_count_limit; long long bytes_diff, total_bytes; int count_diff, total_count; @@ -432,7 +432,7 @@ static int maildirsize_parse(struct maildir_quota_root *root, if (rule->bytes_limit == (int64_t)message_bytes_limit && rule->count_limit == (int64_t)message_count_limit) { /* limits haven't changed */ - } else if (root->root.force_default_rule) { + } else if (root->root.set->force_default_rule) { /* we know the limits and they've changed. the file must be rewritten. */ return 0; @@ -440,7 +440,7 @@ static int maildirsize_parse(struct maildir_quota_root *root, /* we're using limits from the file. */ rule->bytes_limit = message_bytes_limit; rule->count_limit = message_count_limit; - quota_root_recalculate_relative_rules(&root->root); + quota_root_recalculate_relative_rules(root->root.set); } if (*lines == NULL) { @@ -603,8 +603,8 @@ static int maildirquota_refresh(struct maildir_quota_root *root) ret = maildirsize_read(root); } T_END; if (ret == 0) { - if (root->root.default_rule.bytes_limit == 0 && - root->root.default_rule.count_limit == 0) { + if (root->root.set->default_rule.bytes_limit == 0 && + root->root.set->default_rule.count_limit == 0) { /* no quota */ return 0; } @@ -661,7 +661,7 @@ static void maildir_quota_deinit(struct quota_root *_root) } static bool -maildir_quota_parse_rule(struct quota_root *root ATTR_UNUSED, +maildir_quota_parse_rule(struct quota_root_settings *root_set ATTR_UNUSED, struct quota_rule *rule, const char *str, const char **error_r) { diff --git a/src/plugins/quota/quota-plugin.c b/src/plugins/quota/quota-plugin.c index da5c0112ac..52733cdca2 100644 --- a/src/plugins/quota/quota-plugin.c +++ b/src/plugins/quota/quota-plugin.c @@ -11,14 +11,15 @@ /* defined by imap, pop3, lda */ extern void (*hook_mail_storage_created)(struct mail_storage *storage); +void (*quota_next_hook_mail_user_created)(struct mail_user *user); void (*quota_next_hook_mail_storage_created)(struct mail_storage *storage); void (*quota_next_hook_mailbox_list_created)(struct mailbox_list *list); const char *quota_plugin_version = PACKAGE_VERSION; -struct quota *quota_set; +struct quota_settings *quota_set; static void quota_root_add_rules(const char *root_name, - struct quota_root *root) + struct quota_root_settings *root_set) { const char *rule_name, *rule, *error; unsigned int i; @@ -30,7 +31,7 @@ static void quota_root_add_rules(const char *root_name, if (rule == NULL) break; - if (quota_root_add_rule(root, rule, &error) < 0) { + if (quota_root_add_rule(root_set, rule, &error) < 0) { i_fatal("Quota root %s: Invalid rule %s: %s", root_name, rule, error); } @@ -39,7 +40,7 @@ static void quota_root_add_rules(const char *root_name, } static void quota_root_add_warning_rules(const char *root_name, - struct quota_root *root) + struct quota_root_settings *root_set) { const char *rule_name, *rule, *error; unsigned int i; @@ -51,7 +52,7 @@ static void quota_root_add_warning_rules(const char *root_name, if (rule == NULL) break; - if (quota_root_add_warning_rule(root, rule, &error) < 0) { + if (quota_root_add_warning_rule(root_set, rule, &error) < 0) { i_fatal("Quota root %s: Invalid warning rule: %s", root_name, rule); } @@ -61,7 +62,7 @@ static void quota_root_add_warning_rules(const char *root_name, void quota_plugin_init(void) { - struct quota_root *root; + struct quota_root_settings *root_set; unsigned int i; const char *env; @@ -69,13 +70,13 @@ void quota_plugin_init(void) if (env == NULL) return; - quota_set = quota_init(); + quota_set = quota_settings_init(); - root = quota_root_init(quota_set, env); - if (root == NULL) + root_set = quota_root_settings_init(quota_set, env); + if (root_set == NULL) i_fatal("Couldn't create quota root: %s", env); - quota_root_add_rules("QUOTA", root); - quota_root_add_warning_rules("QUOTA", root); + quota_root_add_rules("QUOTA", root_set); + quota_root_add_warning_rules("QUOTA", root_set); for (i = 2;; i++) { const char *root_name; @@ -86,13 +87,16 @@ void quota_plugin_init(void) if (env == NULL) break; - root = quota_root_init(quota_set, env); - if (root == NULL) + root_set = quota_root_settings_init(quota_set, env); + if (root_set == NULL) i_fatal("Couldn't create quota root: %s", env); - quota_root_add_rules(root_name, root); - quota_root_add_warning_rules(root_name, root); + quota_root_add_rules(root_name, root_set); + quota_root_add_warning_rules(root_name, root_set); } + quota_next_hook_mail_user_created = hook_mail_user_created; + hook_mail_user_created = quota_mail_user_created; + quota_next_hook_mail_storage_created = hook_mail_storage_created; hook_mail_storage_created = quota_mail_storage_created; @@ -103,10 +107,11 @@ void quota_plugin_init(void) void quota_plugin_deinit(void) { if (quota_set != NULL) { + hook_mail_user_created = quota_next_hook_mail_user_created; hook_mail_storage_created = quota_next_hook_mail_storage_created; hook_mailbox_list_created = quota_next_hook_mailbox_list_created; - quota_deinit("a_set); + quota_settings_deinit("a_set); } } diff --git a/src/plugins/quota/quota-plugin.h b/src/plugins/quota/quota-plugin.h index 6567ba8f87..74d9ccd6c9 100644 --- a/src/plugins/quota/quota-plugin.h +++ b/src/plugins/quota/quota-plugin.h @@ -3,14 +3,14 @@ struct mail_storage; +extern void (*quota_next_hook_mail_user_created)(struct mail_user *user); extern void (*quota_next_hook_mail_storage_created) (struct mail_storage *storage); extern void (*quota_next_hook_mailbox_list_created)(struct mailbox_list *list); -/* "quota" symbol already exists in OSX, so we'll use this slightly uglier - name. */ -extern struct quota *quota_set; +extern struct quota_settings *quota_set; +void quota_mail_user_created(struct mail_user *user); void quota_mail_storage_created(struct mail_storage *storage); void quota_mailbox_list_created(struct mailbox_list *list); diff --git a/src/plugins/quota/quota-private.h b/src/plugins/quota/quota-private.h index 8c397539f5..f72535e3d2 100644 --- a/src/plugins/quota/quota-private.h +++ b/src/plugins/quota/quota-private.h @@ -9,9 +9,17 @@ extern unsigned int quota_module_id; struct quota { + struct mail_user *user; + struct quota_settings *set; + ARRAY_DEFINE(roots, struct quota_root *); ARRAY_DEFINE(storages, struct mail_storage *); +}; + +struct quota_settings { + pool_t pool; + ARRAY_DEFINE(root_sets, struct quota_root_settings *); int (*test_alloc)(struct quota_transaction_context *ctx, uoff_t size, bool *too_large_r); @@ -20,7 +28,7 @@ struct quota { }; struct quota_rule { - char *mailbox_name; + const char *mailbox_name; int64_t bytes_limit, count_limit; /* relative to default_rule */ @@ -33,7 +41,7 @@ struct quota_rule { struct quota_warning_rule { struct quota_rule rule; - char *command; + const char *command; }; struct quota_backend_vfuncs { @@ -41,7 +49,8 @@ struct quota_backend_vfuncs { int (*init)(struct quota_root *root, const char *args); void (*deinit)(struct quota_root *root); - bool (*parse_rule)(struct quota_root *root, struct quota_rule *rule, + bool (*parse_rule)(struct quota_root_settings *root_set, + struct quota_rule *rule, const char *str, const char **error_r); /* called once for each backend */ @@ -49,8 +58,8 @@ struct quota_backend_vfuncs { struct mail_storage *storage); const char *const *(*get_resources)(struct quota_root *root); - int (*get_resource)(struct quota_root *root, const char *name, - uint64_t *value_r); + int (*get_resource)(struct quota_root *root, + const char *name, uint64_t *value_r); int (*update)(struct quota_root *root, struct quota_transaction_context *ctx); @@ -64,27 +73,34 @@ struct quota_backend { struct quota_backend_vfuncs v; }; -struct quota_root { - pool_t pool; - +struct quota_root_settings { /* Unique quota root name. */ const char *name; - /* pointer to the quota that owns this root */ - struct quota *quota; + struct quota_settings *set; + const char *args; - struct quota_backend backend; + const struct quota_backend *backend; struct quota_rule default_rule; ARRAY_DEFINE(rules, struct quota_rule); ARRAY_DEFINE(warning_rules, struct quota_warning_rule); + /* Limits in default_rule override backend's quota limits */ + unsigned int force_default_rule:1; +}; + +struct quota_root { + pool_t pool; + + struct quota_root_settings *set; + struct quota *quota; + struct quota_backend backend; + /* Module-specific contexts. See quota_module_id. */ ARRAY_DEFINE(quota_module_contexts, void); /* don't enforce quota when saving */ unsigned int no_enforcing:1; - /* Limits in default_rule override backend's quota limits */ - unsigned int force_default_rule:1; }; struct quota_transaction_context { @@ -105,13 +121,14 @@ struct quota_transaction_context { /* Register storage to all user's quota roots. */ void quota_add_user_storage(struct quota *quota, struct mail_storage *storage); -void quota_remove_user_storage(struct quota *quota, - struct mail_storage *storage); +void quota_remove_user_storage(struct mail_storage *storage); + +struct quota *quota_get_mail_user_quota(struct mail_user *user); struct quota_rule * -quota_root_rule_find(struct quota_root *root, const char *name); +quota_root_rule_find(struct quota_root_settings *root_set, const char *name); -void quota_root_recalculate_relative_rules(struct quota_root *root); +void quota_root_recalculate_relative_rules(struct quota_root_settings *root_set); int quota_count(struct quota_root *root, uint64_t *bytes_r, uint64_t *count_r); #endif diff --git a/src/plugins/quota/quota-storage.c b/src/plugins/quota/quota-storage.c index 7ef5781bc6..aa2dd53713 100644 --- a/src/plugins/quota/quota-storage.c +++ b/src/plugins/quota/quota-storage.c @@ -17,6 +17,14 @@ MODULE_CONTEXT(obj, quota_mail_module) #define QUOTA_LIST_CONTEXT(obj) \ MODULE_CONTEXT(obj, quota_mailbox_list_module) +#define QUOTA_USER_CONTEXT(obj) \ + MODULE_CONTEXT(obj, quota_user_module) + +struct quota_user { + union mail_user_module_context module_ctx; + + struct quota *quota; +}; struct quota_mailbox_list { union mailbox_list_module_context module_ctx; @@ -41,6 +49,8 @@ static MODULE_CONTEXT_DEFINE_INIT(quota_storage_module, static MODULE_CONTEXT_DEFINE_INIT(quota_mail_module, &mail_module_register); static MODULE_CONTEXT_DEFINE_INIT(quota_mailbox_list_module, &mailbox_list_module_register); +static MODULE_CONTEXT_DEFINE_INIT(quota_user_module, + &mail_user_module_register); static void quota_mail_expunge(struct mail *_mail) { @@ -74,7 +84,7 @@ quota_mailbox_transaction_begin(struct mailbox *box, struct quota_transaction_context *qt; t = qbox->module_ctx.super.transaction_begin(box, flags); - qt = quota_transaction_begin(quota_set, box); + qt = quota_transaction_begin(box); MODULE_CONTEXT_SET(t, quota_storage_module, qt); return t; @@ -150,7 +160,7 @@ static int quota_check(struct mailbox_transaction_context *t, struct mail *mail) return 0; else if (ret == 0) { mail_storage_set_error(t->box->storage, MAIL_ERROR_NOSPACE, - qt->quota->quota_exceeded_msg); + qt->quota->set->quota_exceeded_msg); return -1; } else { mail_storage_set_critical(t->box->storage, @@ -212,7 +222,7 @@ quota_save_begin(struct mail_save_context *ctx, struct istream *input) if (ret == 0) { mail_storage_set_error(t->box->storage, MAIL_ERROR_NOSPACE, - qt->quota->quota_exceeded_msg); + qt->quota->set->quota_exceeded_msg); return -1; } else if (ret < 0) { mail_storage_set_critical(t->box->storage, @@ -294,7 +304,7 @@ static void quota_mailbox_sync_notify(struct mailbox *box, uint32_t uid, } if (qbox->expunge_qt == NULL) - qbox->expunge_qt = quota_transaction_begin(quota_set, box); + qbox->expunge_qt = quota_transaction_begin(box); if (i != count) { /* we already know the size */ @@ -436,16 +446,47 @@ static void quota_storage_destroy(struct mail_storage *storage) { union mail_storage_module_context *qstorage = QUOTA_CONTEXT(storage); - quota_remove_user_storage(quota_set, storage); + quota_remove_user_storage(storage); if (qstorage->super.destroy != NULL) qstorage->super.destroy(storage); } +struct quota *quota_get_mail_user_quota(struct mail_user *user) +{ + struct quota_user *quser = QUOTA_USER_CONTEXT(user); + + return quser->quota; +} + +static void quota_user_deinit(struct mail_user *user) +{ + struct quota_user *quser = QUOTA_USER_CONTEXT(user); + + quota_deinit(&quser->quota); + quser->module_ctx.super.deinit(user); +} + +void quota_mail_user_created(struct mail_user *user) +{ + struct quota_user *quser; + + quser = p_new(user->pool, struct quota_user, 1); + quser->module_ctx.super = user->v; + user->v.deinit = quota_user_deinit; + quser->quota = quota_init(quota_set, user); + + MODULE_CONTEXT_SET(user, quota_user_module, quser); + + if (quota_next_hook_mail_user_created != NULL) + quota_next_hook_mail_user_created(user); +} + void quota_mail_storage_created(struct mail_storage *storage) { struct quota_mailbox_list *qlist = QUOTA_LIST_CONTEXT(storage->list); union mail_storage_module_context *qstorage; + struct quota *quota; qlist->storage = storage; @@ -459,7 +500,8 @@ void quota_mail_storage_created(struct mail_storage *storage) if (storage->ns->type == NAMESPACE_PRIVATE && (storage->ns->flags & NAMESPACE_FLAG_INTERNAL) == 0) { /* register to user's quota roots */ - quota_add_user_storage(quota_set, storage); + quota = quota_get_mail_user_quota(storage->ns->user); + quota_add_user_storage(quota, storage); } if (quota_next_hook_mail_storage_created != NULL) diff --git a/src/plugins/quota/quota.c b/src/plugins/quota/quota.c index 3e74a340b5..25c35f4b05 100644 --- a/src/plugins/quota/quota.c +++ b/src/plugins/quota/quota.c @@ -42,37 +42,30 @@ static const struct quota_backend *quota_backends[] = { static int quota_default_test_alloc(struct quota_transaction_context *ctx, uoff_t size, bool *too_large_r); -struct quota *quota_init(void) +struct quota_settings *quota_settings_init(void) { - struct quota *quota; - - quota = i_new(struct quota, 1); - quota->test_alloc = quota_default_test_alloc; - quota->debug = getenv("DEBUG") != NULL; - quota->quota_exceeded_msg = getenv("QUOTA_EXCEEDED_MESSAGE"); - if (quota->quota_exceeded_msg == NULL) - quota->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG; - i_array_init("a->roots, 4); - i_array_init("a->storages, 8); + struct quota_settings *quota_set; + pool_t pool; - return quota; + pool = pool_alloconly_create("quota settings", 256); + quota_set = p_new(pool, struct quota_settings, 1); + quota_set->pool = pool; + quota_set->test_alloc = quota_default_test_alloc; + quota_set->debug = getenv("DEBUG") != NULL; + quota_set->quota_exceeded_msg = getenv("QUOTA_EXCEEDED_MESSAGE"); + if (quota_set->quota_exceeded_msg == NULL) + quota_set->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG; + p_array_init("a_set->root_sets, pool, 4); + return quota_set; } -void quota_deinit(struct quota **_quota) +void quota_settings_deinit(struct quota_settings **_quota_set) { - struct quota *quota = *_quota; - struct quota_root **root_p, *root; + struct quota_settings *quota_set = *_quota_set; - *_quota = NULL; - while (array_count("a->roots) > 0) { - root_p = array_idx_modifiable("a->roots, 0); - root = *root_p; - quota_root_deinit(&root); - } + *_quota_set = NULL; - array_free("a->roots); - array_free("a->storages); - i_free(quota); + pool_unref("a_set->pool); } static const struct quota_backend *quota_backend_find(const char *name) @@ -87,11 +80,12 @@ static const struct quota_backend *quota_backend_find(const char *name) return NULL; } -struct quota_root *quota_root_init(struct quota *quota, const char *root_def) +struct quota_root_settings * +quota_root_settings_init(struct quota_settings *quota_set, const char *root_def) { - struct quota_root *root; + struct quota_root_settings *root_set; const struct quota_backend *backend; - const char *p, *args, *backend_name, *const *tmp; + const char *p, *args, *backend_name; /* [:[:]] */ p = strchr(root_def, ':'); @@ -107,44 +101,57 @@ struct quota_root *quota_root_init(struct quota *quota, const char *root_def) if (backend == NULL) i_fatal("Unknown quota backend: %s", backend_name); - root = backend->v.alloc(); - root->quota = quota; - root->backend = *backend; - root->pool = pool_alloconly_create("quota root", 512); + root_set = p_new(quota_set->pool, struct quota_root_settings, 1); + root_set->set = quota_set; + root_set->backend = backend; if (args != NULL) { /* save root's name */ p = strchr(args, ':'); if (p == NULL) { - root->name = p_strdup(root->pool, args); + root_set->name = p_strdup(quota_set->pool, args); args = NULL; } else { - root->name = p_strdup_until(root->pool, args, p); + root_set->name = + p_strdup_until(quota_set->pool, args, p); args = p + 1; } } else { - root->name = ""; + root_set->name = ""; } + root_set->args = p_strdup(quota_set->pool, args); - if (quota->debug) { + if (quota_set->debug) { i_info("Quota root: name=%s backend=%s args=%s", - root->name, backend_name, args == NULL ? "" : args); + root_set->name, backend_name, args == NULL ? "" : args); } - i_array_init(&root->rules, 4); - i_array_init(&root->warning_rules, 4); - array_create(&root->quota_module_contexts, default_pool, - sizeof(void *), 5); + p_array_init(&root_set->rules, quota_set->pool, 4); + p_array_init(&root_set->warning_rules, quota_set->pool, 4); + array_append("a_set->root_sets, &root_set, 1); + return root_set; +} - array_append("a->roots, &root, 1); +static struct quota_root * +quota_root_init(struct quota_root_settings *root_set, struct quota *quota) +{ + struct quota_root *root; + const char *const *tmp; - if (backend->v.init != NULL) { - if (backend->v.init(root, args) < 0) { - quota_root_deinit(&root); + root = root_set->backend->v.alloc(); + root->pool = pool_alloconly_create("quota root", 512); + root->set = root_set; + root->quota = quota; + root->backend = *root_set->backend; + + array_create(&root->quota_module_contexts, root->pool, + sizeof(void *), 10); + + if (root->backend.v.init != NULL) { + if (root->backend.v.init(root, root_set->args) < 0) return NULL; - } - } else if (args != NULL) { - tmp = t_strsplit_spaces(args, " "); + } else if (root_set->args != NULL) { + tmp = t_strsplit_spaces(root_set->args, " "); for (; *tmp != NULL; tmp++) { if (strcmp(*tmp, "noenforcing") == 0) root->no_enforcing = TRUE; @@ -154,49 +161,65 @@ struct quota_root *quota_root_init(struct quota *quota, const char *root_def) if (*tmp != NULL) { i_fatal("Quota root %s backend %s: " "Unknown parameter: %s", - root->name, backend_name, *tmp); + root_set->name, root->backend.name, *tmp); } } return root; } -void quota_root_deinit(struct quota_root **_root) +static void quota_root_deinit(struct quota_root *root) { - struct quota_root *root = *_root; pool_t pool = root->pool; - struct quota_root *const *roots; - struct quota_warning_rule *warnings; + + root->backend.v.deinit(root); + pool_unref(&pool); +} + +struct quota *quota_init(struct quota_settings *quota_set, + struct mail_user *user) +{ + struct quota *quota; + struct quota_root *root; + struct quota_root_settings *const *root_sets; unsigned int i, count; - *_root = NULL; + quota = i_new(struct quota, 1); + quota->user = user; + quota->set = quota_set; + i_array_init("a->roots, 8); - roots = array_get(&root->quota->roots, &count); + root_sets = array_get("a_set->root_sets, &count); + i_array_init("a->storages, count); for (i = 0; i < count; i++) { - if (roots[i] == root) { - array_delete(&root->quota->roots, i, 1); - break; - } + root = quota_root_init(root_sets[i], quota); + array_append("a->roots, &root, 1); } + return quota; +} - warnings = array_get_modifiable(&root->warning_rules, &count); - for (i = 0; i < count; i++) - i_free(warnings[i].command); - array_free(&root->warning_rules); +void quota_deinit(struct quota **_quota) +{ + struct quota *quota = *_quota; + struct quota_root *const *roots; + unsigned int i, count; - array_free(&root->rules); - array_free(&root->quota_module_contexts); + *_quota = NULL; - root->backend.v.deinit(root); - pool_unref(&pool); + roots = array_get("a->roots, &count); + for (i = 0; i < count; i++) + quota_root_deinit(roots[i]); + array_free("a->roots); + array_free("a->storages); + i_free(quota); } struct quota_rule * -quota_root_rule_find(struct quota_root *root, const char *name) +quota_root_rule_find(struct quota_root_settings *root_set, const char *name) { struct quota_rule *rules; unsigned int i, count; - rules = array_get_modifiable(&root->rules, &count); + rules = array_get_modifiable(&root_set->rules, &count); for (i = 0; i < count; i++) { if (strcmp(rules[i].mailbox_name, name) == 0) return &rules[i]; @@ -205,18 +228,19 @@ quota_root_rule_find(struct quota_root *root, const char *name) } static int -quota_rule_parse_percentage(struct quota_root *root, struct quota_rule *rule, +quota_rule_parse_percentage(struct quota_root_settings *root_set, + struct quota_rule *rule, int64_t *limit, const char **error_r) { int64_t percentage = *limit; if (percentage <= 0 || percentage >= -1U) { - *error_r = p_strdup_printf(root->pool, + *error_r = p_strdup_printf(root_set->set->pool, "Invalid rule percentage: %lld", (long long)percentage); return -1; } - if (rule == &root->default_rule) { + if (rule == &root_set->default_rule) { *error_r = "Default rule can't be a percentage"; return -1; } @@ -244,29 +268,29 @@ quota_rule_recalculate_relative_rules(struct quota_rule *rule, } } -void quota_root_recalculate_relative_rules(struct quota_root *root) +void quota_root_recalculate_relative_rules(struct quota_root_settings *root_set) { struct quota_rule *rules; struct quota_warning_rule *warning_rules; unsigned int i, count; - rules = array_get_modifiable(&root->rules, &count); + rules = array_get_modifiable(&root_set->rules, &count); for (i = 0; i < count; i++) { quota_rule_recalculate_relative_rules(&rules[i], - &root->default_rule); + &root_set->default_rule); } - warning_rules = array_get_modifiable(&root->warning_rules, &count); + warning_rules = array_get_modifiable(&root_set->warning_rules, &count); for (i = 0; i < count; i++) { quota_rule_recalculate_relative_rules(&warning_rules[i].rule, - &root->default_rule); + &root_set->default_rule); } } static int -quota_rule_parse_limits(struct quota_root *root, struct quota_rule *rule, - const char *limits, bool allow_negative, - const char **error_r) +quota_rule_parse_limits(struct quota_root_settings *root_set, + struct quota_rule *rule, const char *limits, + bool allow_negative, const char **error_r) { const char **args; char *p; @@ -288,7 +312,7 @@ quota_rule_parse_limits(struct quota_root *root, struct quota_rule *rule, limit = &rule->count_limit; *limit = strtoll(*args + 9, &p, 10); } else { - *error_r = p_strdup_printf(root->pool, + *error_r = p_strdup_printf(root_set->set->pool, "Unknown rule limit name: %s", *args); return -1; } @@ -314,12 +338,12 @@ quota_rule_parse_limits(struct quota_root *root, struct quota_rule *rule, break; case '%': multiply = 0; - if (quota_rule_parse_percentage(root, rule, limit, + if (quota_rule_parse_percentage(root_set, rule, limit, error_r) < 0) return -1; break; default: - *error_r = p_strdup_printf(root->pool, + *error_r = p_strdup_printf(root_set->set->pool, "Invalid rule limit value: %s", *args); return -1; } @@ -338,8 +362,8 @@ quota_rule_parse_limits(struct quota_root *root, struct quota_rule *rule, return 0; } -int quota_root_add_rule(struct quota_root *root, const char *rule_def, - const char **error_r) +int quota_root_add_rule(struct quota_root_settings *root_set, + const char *rule_def, const char **error_r) { struct quota_rule *rule; const char *p, *mailbox_name; @@ -354,43 +378,45 @@ int quota_root_add_rule(struct quota_root *root, const char *rule_def, /* : */ mailbox_name = t_strdup_until(rule_def, p++); - rule = quota_root_rule_find(root, mailbox_name); + rule = quota_root_rule_find(root_set, mailbox_name); if (rule == NULL) { if (strcmp(mailbox_name, RULE_NAME_DEFAULT_NONFORCE) == 0) - rule = &root->default_rule; + rule = &root_set->default_rule; else if (strcmp(mailbox_name, RULE_NAME_DEFAULT_FORCE) == 0) { - rule = &root->default_rule; - root->force_default_rule = TRUE; + rule = &root_set->default_rule; + root_set->force_default_rule = TRUE; } else { - rule = array_append_space(&root->rules); - rule->mailbox_name = p_strdup(root->pool, mailbox_name); + rule = array_append_space(&root_set->rules); + rule->mailbox_name = + p_strdup(root_set->set->pool, mailbox_name); } } if (strcmp(p, "ignore") == 0) { rule->ignore = TRUE; - if (root->quota->debug) { + if (root_set->set->debug) { i_info("Quota rule: root=%s mailbox=%s ignored", - root->name, mailbox_name); + root_set->name, mailbox_name); } return 0; } if (strncmp(p, "backend=", 8) == 0) { - if (!root->backend.v.parse_rule(root, rule, p + 8, error_r)) + if (!root_set->backend->v.parse_rule(root_set, rule, + p + 8, error_r)) ret = -1; } else { - bool allow_negative = rule != &root->default_rule; + bool allow_negative = rule != &root_set->default_rule; - if (quota_rule_parse_limits(root, rule, p, + if (quota_rule_parse_limits(root_set, rule, p, allow_negative, error_r) < 0) ret = -1; } - quota_root_recalculate_relative_rules(root); - if (root->quota->debug) { + quota_root_recalculate_relative_rules(root_set); + if (root_set->set->debug) { i_info("Quota rule: root=%s mailbox=%s " - "bytes=%lld (%u%%) messages=%lld (%u%%)", root->name, + "bytes=%lld (%u%%) messages=%lld (%u%%)", root_set->name, mailbox_name, (long long)rule->bytes_limit, rule->bytes_percent, (long long)rule->count_limit, rule->count_percent); @@ -398,7 +424,7 @@ int quota_root_add_rule(struct quota_root *root, const char *rule_def, return ret; } -static bool quota_root_get_rule_limits(struct quota_root *root, +static bool quota_root_get_rule_limits(struct quota_root_settings *root_set, const char *mailbox_name, uint64_t *bytes_limit_r, uint64_t *count_limit_r) @@ -407,14 +433,14 @@ static bool quota_root_get_rule_limits(struct quota_root *root, int64_t bytes_limit, count_limit; bool found; - bytes_limit = root->default_rule.bytes_limit; - count_limit = root->default_rule.count_limit; + bytes_limit = root_set->default_rule.bytes_limit; + count_limit = root_set->default_rule.count_limit; /* if default rule limits are 0, this rule applies only to specific mailboxes */ found = bytes_limit != 0 || count_limit != 0; - rule = quota_root_rule_find(root, mailbox_name); + rule = quota_root_rule_find(root_set, mailbox_name); if (rule != NULL) { if (!rule->ignore) { bytes_limit += rule->bytes_limit; @@ -489,12 +515,18 @@ void quota_add_user_storage(struct quota *quota, struct mail_storage *storage) } } -void quota_remove_user_storage(struct quota *quota, - struct mail_storage *storage) +void quota_remove_user_storage(struct mail_storage *storage) { + struct quota *quota; struct mail_storage *const *storages; unsigned int i, count; - + + quota = quota_get_mail_user_quota(storage->ns->user); + if (quota == NULL) { + /* no quota for this storage */ + return; + } + storages = array_get("a->storages, &count); for (i = 0; i < count; i++) { if (storages[i] == storage) { @@ -504,8 +536,8 @@ void quota_remove_user_storage(struct quota *quota, } } -int quota_root_add_warning_rule(struct quota_root *root, const char *rule_def, - const char **error_r) +int quota_root_add_warning_rule(struct quota_root_settings *root_set, + const char *rule_def, const char **error_r) { struct quota_warning_rule *warning; struct quota_rule rule; @@ -519,17 +551,18 @@ int quota_root_add_warning_rule(struct quota_root *root, const char *rule_def, } memset(&rule, 0, sizeof(rule)); - ret = quota_rule_parse_limits(root, &rule, t_strdup_until(rule_def, p), + ret = quota_rule_parse_limits(root_set, &rule, + t_strdup_until(rule_def, p), TRUE, error_r); if (ret < 0) return -1; - warning = array_append_space(&root->warning_rules); + warning = array_append_space(&root_set->warning_rules); warning->command = i_strdup(p+1); warning->rule = rule; - quota_root_recalculate_relative_rules(root); - if (root->quota->debug) { + quota_root_recalculate_relative_rules(root_set); + if (root_set->set->debug) { i_info("Quota warning: bytes=%llu (%u%%) " "messages=%llu (%u%%) command=%s", (unsigned long long)warning->rule.bytes_limit, @@ -541,12 +574,13 @@ int quota_root_add_warning_rule(struct quota_root *root, const char *rule_def, } struct quota_root_iter * -quota_root_iter_init(struct quota *quota, struct mailbox *box) +quota_root_iter_init(struct mailbox *box) { + struct mail_user *user = box->storage->ns->user; struct quota_root_iter *iter; iter = i_new(struct quota_root_iter, 1); - iter->quota = quota; + iter->quota = quota_get_mail_user_quota(user); iter->box = box; return iter; } @@ -608,14 +642,16 @@ void quota_root_iter_deinit(struct quota_root_iter **_iter) i_free(iter); } -struct quota_root *quota_root_lookup(struct quota *quota, const char *name) +struct quota_root *quota_root_lookup(struct mail_user *user, const char *name) { + struct quota *quota; struct quota_root *const *roots; unsigned int i, count; + quota = quota_get_mail_user_quota(user); roots = array_get("a->roots, &count); for (i = 0; i < count; i++) { - if (strcmp(roots[i]->name, name) == 0) + if (strcmp(roots[i]->set->name, name) == 0) return roots[i]; } return NULL; @@ -623,7 +659,7 @@ struct quota_root *quota_root_lookup(struct quota *quota, const char *name) const char *quota_root_get_name(struct quota_root *root) { - return root->name; + return root->set->name; } const char *const *quota_root_get_resources(struct quota_root *root) @@ -649,7 +685,7 @@ int quota_get_resource(struct quota_root *root, const char *mailbox_name, if (ret <= 0) return ret; - (void)quota_root_get_rule_limits(root, mailbox_name, + (void)quota_root_get_rule_limits(root->set, mailbox_name, &bytes_limit, &count_limit); if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0) *limit_r = bytes_limit; @@ -676,13 +712,13 @@ int quota_set_resource(struct quota_root *root ATTR_UNUSED, return -1; } -struct quota_transaction_context *quota_transaction_begin(struct quota *quota, - struct mailbox *box) +struct quota_transaction_context *quota_transaction_begin(struct mailbox *box) { + struct mail_user *user = box->storage->ns->user; struct quota_transaction_context *ctx; ctx = i_new(struct quota_transaction_context, 1); - ctx->quota = quota; + ctx->quota = quota_get_mail_user_quota(user); ctx->box = box; ctx->bytes_left = (uint64_t)-1; ctx->count_left = (uint64_t)-1; @@ -756,7 +792,7 @@ static void quota_warnings_execute(struct quota_transaction_context *ctx, uint64_t bytes_current, bytes_before, bytes_limit; uint64_t count_current, count_before, count_limit; - warnings = array_get_modifiable(&root->warning_rules, &count); + warnings = array_get_modifiable(&root->set->warning_rules, &count); if (count == 0) return; @@ -801,7 +837,8 @@ int quota_transaction_commit(struct quota_transaction_context **_ctx) if (!quota_root_is_visible(roots[i], ctx->box, TRUE)) continue; - rule = quota_root_rule_find(roots[i], mailbox_name); + rule = quota_root_rule_find(roots[i]->set, + mailbox_name); if (rule != NULL && rule->ignore) { /* mailbox not included in quota */ continue; @@ -856,7 +893,7 @@ int quota_test_alloc(struct quota_transaction_context *ctx, if (quota_transaction_set_limits(ctx) < 0) return -1; } - return ctx->quota->test_alloc(ctx, size, too_large_r); + return ctx->quota->set->test_alloc(ctx, size, too_large_r); } static int quota_default_test_alloc(struct quota_transaction_context *ctx, @@ -877,7 +914,7 @@ static int quota_default_test_alloc(struct quota_transaction_context *ctx, if (!quota_root_is_visible(roots[i], ctx->box, TRUE)) continue; - if (!quota_root_get_rule_limits(roots[i], + if (!quota_root_get_rule_limits(roots[i]->set, mailbox_get_name(ctx->box), &bytes_limit, &count_limit)) continue; diff --git a/src/plugins/quota/quota.h b/src/plugins/quota/quota.h index 2f757f7142..0a716a7e00 100644 --- a/src/plugins/quota/quota.h +++ b/src/plugins/quota/quota.h @@ -3,6 +3,7 @@ struct mail; struct mailbox; +struct mail_user; /* Message storage size kilobytes. */ #define QUOTA_NAME_STORAGE_KILOBYTES "STORAGE" @@ -16,29 +17,35 @@ struct quota_root; struct quota_root_iter; struct quota_transaction_context; -struct quota *quota_init(void); -void quota_deinit(struct quota **quota); +struct quota_settings *quota_settings_init(void); +void quota_settings_deinit(struct quota_settings **quota_set); -/* Create a new quota root. */ -struct quota_root *quota_root_init(struct quota *quota, const char *root_def); -void quota_root_deinit(struct quota_root **root); +/* Set up a new quota root. */ +struct quota_root_settings * +quota_root_settings_init(struct quota_settings *quota_set, + const char *root_def); +void quota_root_settings_deinit(struct quota_root_settings **root_set); /* Add a new rule too the quota root. Returns 0 if ok, -1 if rule is invalid. */ -int quota_root_add_rule(struct quota_root *root, const char *rule_def, - const char **error_r); +int quota_root_add_rule(struct quota_root_settings *root_set, + const char *rule_def, const char **error_r); /* Add a new warning rule for the quota root. Returns 0 if ok, -1 if rule is invalid. */ -int quota_root_add_warning_rule(struct quota_root *root, const char *rule_def, - const char **error_r); +int quota_root_add_warning_rule(struct quota_root_settings *root_set, + const char *rule_def, const char **error_r); + +/* Initialize quota for the given user. */ +struct quota *quota_init(struct quota_settings *quota_set, + struct mail_user *user); +void quota_deinit(struct quota **quota); /* List all quota roots. Returned quota roots are freed by quota_deinit(). */ -struct quota_root_iter * -quota_root_iter_init(struct quota *quota, struct mailbox *box); +struct quota_root_iter *quota_root_iter_init(struct mailbox *box); struct quota_root *quota_root_iter_next(struct quota_root_iter *iter); void quota_root_iter_deinit(struct quota_root_iter **iter); /* Return quota root or NULL. */ -struct quota_root *quota_root_lookup(struct quota *quota, const char *name); +struct quota_root *quota_root_lookup(struct mail_user *user, const char *name); /* Returns name of the quota root. */ const char *quota_root_get_name(struct quota_root *root); @@ -53,8 +60,7 @@ int quota_set_resource(struct quota_root *root, const char *name, uint64_t value, const char **error_r); /* Start a new quota transaction. */ -struct quota_transaction_context *quota_transaction_begin(struct quota *quota, - struct mailbox *box); +struct quota_transaction_context *quota_transaction_begin(struct mailbox *box); /* Commit quota transaction. Returns 0 if ok, -1 if failed. */ int quota_transaction_commit(struct quota_transaction_context **ctx); /* Rollback quota transaction changes. */ diff --git a/src/plugins/trash/trash-plugin.c b/src/plugins/trash/trash-plugin.c index 579d8747f7..e3e340912b 100644 --- a/src/plugins/trash/trash-plugin.c +++ b/src/plugins/trash/trash-plugin.c @@ -21,9 +21,9 @@ struct trash_mailbox { const char *name; int priority; /* lower number = higher priority */ - struct mail_storage *storage; - /* temporarily set while cleaning: */ + const char *ns_name; + struct mail_storage *storage; struct mailbox *box; struct mailbox_transaction_context *trans; struct mail_search_context *search_ctx; @@ -45,7 +45,7 @@ static int trash_clean_mailbox_open(struct trash_mailbox *trash) { struct mail_search_args *search_args; - trash->box = mailbox_open(trash->storage, trash->name, NULL, + trash->box = mailbox_open(trash->storage, trash->ns_name, NULL, MAILBOX_OPEN_KEEP_RECENT); if (trash->box == NULL) return 0; @@ -89,14 +89,17 @@ static int trash_clean_mailbox_get_next(struct trash_mailbox *trash, return 1; } -static void trash_find_storage(struct trash_mailbox *trash) +static void trash_find_storage(struct quota *quota, + struct trash_mailbox *trash) { struct mail_storage *const *storages; unsigned int i, count; - storages = array_get("a_set->storages, &count); + storages = array_get("a->storages, &count); for (i = 0; i < count; i++) { - if (mail_namespace_update_name(storages[i]->ns, &trash->name)) { + trash->ns_name = trash->name; + if (mail_namespace_update_name(storages[i]->ns, + &trash->ns_name)) { trash->storage = storages[i]; return; } @@ -124,7 +127,7 @@ static int trash_try_clean_mails(struct quota_transaction_context *ctx, break; if (trashes[j].storage == NULL) - trash_find_storage(&trashes[j]); + trash_find_storage(ctx->quota, &trashes[j]); ret = trash_clean_mailbox_get_next(&trashes[j], &received); @@ -177,6 +180,8 @@ err: } mailbox_close(&trash->box); + trash->storage = NULL; + trash->ns_name = NULL; } if (size_expunged < size_needed) { diff --git a/src/plugins/virtual/virtual-config.c b/src/plugins/virtual/virtual-config.c index 2dd6a125e9..bf4792e1c2 100644 --- a/src/plugins/virtual/virtual-config.c +++ b/src/plugins/virtual/virtual-config.c @@ -89,6 +89,7 @@ static int virtual_config_parse_line(struct virtual_parse_context *ctx, const char *line, const char **error_r) { + struct mail_user *user = ctx->mbox->storage->storage.ns->user; struct virtual_backend_box *bbox; if (*line == ' ') { @@ -110,7 +111,7 @@ virtual_config_parse_line(struct virtual_parse_context *ctx, const char *line, strchr(bbox->name, '%') != NULL) { bbox->glob = imap_match_init(ctx->pool, bbox->name, TRUE, ctx->sep); - bbox->ns = mail_namespace_find(virtual_all_namespaces, &line); + bbox->ns = mail_namespace_find(user->namespaces, &line); ctx->have_wildcards = TRUE; } array_append(&ctx->mbox->backend_boxes, &bbox, 1); @@ -154,6 +155,7 @@ static void virtual_config_copy_expanded(struct virtual_parse_context *ctx, static int virtual_config_expand_wildcards(struct virtual_parse_context *ctx) { + struct mail_user *user = ctx->mbox->storage->storage.ns->user; ARRAY_TYPE(virtual_backend_box) wildcard_boxes; struct mailbox_list_iterate_context *iter; struct virtual_backend_box *const *wboxes; @@ -170,8 +172,7 @@ static int virtual_config_expand_wildcards(struct virtual_parse_context *ctx) patterns[i] = wboxes[i]->name; /* match listed mailboxes to wildcards */ - iter = mailbox_list_iter_init_namespaces( - virtual_all_namespaces, patterns, + iter = mailbox_list_iter_init_namespaces(user->namespaces, patterns, MAILBOX_LIST_ITER_VIRTUAL_NAMES | MAILBOX_LIST_ITER_RETURN_NO_FLAGS); while ((info = mailbox_list_iter_next(iter)) != NULL) { @@ -191,6 +192,7 @@ static int virtual_config_expand_wildcards(struct virtual_parse_context *ctx) int virtual_config_read(struct virtual_mailbox *mbox) { + struct mail_user *user = mbox->storage->storage.ns->user; struct virtual_parse_context ctx; const char *path, *line, *error; unsigned int linenum = 0; @@ -213,7 +215,7 @@ int virtual_config_read(struct virtual_mailbox *mbox) } memset(&ctx, 0, sizeof(ctx)); - ctx.sep = mail_namespace_get_root_sep(virtual_all_namespaces); + ctx.sep = mail_namespace_get_root_sep(user->namespaces); ctx.mbox = mbox; ctx.pool = mbox->ibox.box.pool; ctx.rule = t_str_new(256); diff --git a/src/plugins/virtual/virtual-plugin.c b/src/plugins/virtual/virtual-plugin.c index 97faf4ab3f..40d0283414 100644 --- a/src/plugins/virtual/virtual-plugin.c +++ b/src/plugins/virtual/virtual-plugin.c @@ -5,36 +5,14 @@ #include "virtual-storage.h" #include "virtual-plugin.h" -static void (*virtual_next_hook_mail_namespaces_created) - (struct mail_namespace *namespaces); - const char *virtual_plugin_version = PACKAGE_VERSION; -struct mail_namespace *virtual_all_namespaces; - -static void -virtual_hook_mail_namespaces_created(struct mail_namespace *namespaces) -{ - if (virtual_next_hook_mail_namespaces_created != NULL) - virtual_next_hook_mail_namespaces_created(namespaces); - - /* FIXME: some day we should support multiple clients and this - global namespaces list doesn't work */ - virtual_all_namespaces = namespaces; -} void virtual_plugin_init(void) { mail_storage_class_register(&virtual_storage); - - virtual_next_hook_mail_namespaces_created = - hook_mail_namespaces_created; - hook_mail_namespaces_created = virtual_hook_mail_namespaces_created; } void virtual_plugin_deinit(void) { mail_storage_class_unregister(&virtual_storage); - - hook_mail_namespaces_created = - virtual_next_hook_mail_namespaces_created; } diff --git a/src/plugins/virtual/virtual-plugin.h b/src/plugins/virtual/virtual-plugin.h index cb73a76f8a..59b5c7a2a6 100644 --- a/src/plugins/virtual/virtual-plugin.h +++ b/src/plugins/virtual/virtual-plugin.h @@ -1,8 +1,6 @@ #ifndef VIRTUAL_PLUGIN_H #define VIRTUAL_PLUGIN_H -extern struct mail_namespace *virtual_all_namespaces; - void virtual_plugin_init(void); void virtual_plugin_deinit(void); diff --git a/src/plugins/virtual/virtual-storage.c b/src/plugins/virtual/virtual-storage.c index d172033cc1..81da117df6 100644 --- a/src/plugins/virtual/virtual-storage.c +++ b/src/plugins/virtual/virtual-storage.c @@ -169,6 +169,7 @@ static bool virtual_mailbox_is_in_open_stack(struct virtual_storage *storage, static int virtual_mailboxes_open(struct virtual_mailbox *mbox, enum mailbox_open_flags open_flags) { + struct mail_user *user = mbox->storage->storage.ns->user; struct virtual_backend_box *const *bboxes; struct mail_namespace *ns; unsigned int i, count; @@ -180,7 +181,7 @@ static int virtual_mailboxes_open(struct virtual_mailbox *mbox, bboxes = array_get(&mbox->backend_boxes, &count); for (i = 0; i < count; i++) { mailbox = bboxes[i]->name; - ns = mail_namespace_find(virtual_all_namespaces, &mailbox); + ns = mail_namespace_find(user->namespaces, &mailbox); bboxes[i]->box = mailbox_open(ns->storage, mailbox, NULL, open_flags); diff --git a/src/pop3/client.c b/src/pop3/client.c index 40f1fbe745..4220b157cf 100644 --- a/src/pop3/client.c +++ b/src/pop3/client.c @@ -138,8 +138,7 @@ static bool init_mailbox(struct client *client, const char **error_r) return FALSE; } -struct client *client_create(int fd_in, int fd_out, - struct mail_namespace *namespaces) +struct client *client_create(int fd_in, int fd_out, struct mail_user *user) { struct mail_storage *storage; const char *inbox; @@ -164,10 +163,10 @@ struct client *client_create(int fd_in, int fd_out, client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS, client_idle_timeout, client); - client->namespaces = namespaces; + client->user = user; inbox = "INBOX"; - client->inbox_ns = mail_namespace_find(namespaces, &inbox); + client->inbox_ns = mail_namespace_find(user->namespaces, &inbox); if (client->inbox_ns == NULL) { client_send_line(client, "-ERR No INBOX namespace for user."); client_destroy(client, "No INBOX namespace for user."); @@ -273,7 +272,7 @@ void client_destroy(struct client *client, const char *reason) } if (client->mailbox != NULL) mailbox_close(&client->mailbox); - mail_namespaces_deinit(&client->namespaces); + mail_user_deinit(&client->user); i_free(client->message_sizes); i_free(client->deleted_bitmask); diff --git a/src/pop3/client.h b/src/pop3/client.h index 35cb285e77..4c21cece99 100644 --- a/src/pop3/client.h +++ b/src/pop3/client.h @@ -16,7 +16,8 @@ struct client { command_func_t *cmd; void *cmd_context; - struct mail_namespace *namespaces, *inbox_ns; + struct mail_user *user; + struct mail_namespace *inbox_ns; struct mailbox *mailbox; struct mailbox_transaction_context *trans; @@ -49,8 +50,7 @@ struct client { /* Create new client with specified input/output handles. socket specifies if the handle is a socket. */ -struct client *client_create(int fd_in, int fd_out, - struct mail_namespace *namespaces); +struct client *client_create(int fd_in, int fd_out, struct mail_user *user); void client_destroy(struct client *client, const char *reason); /* Disconnect client connection */ diff --git a/src/pop3/main.c b/src/pop3/main.c index 227d4aec06..e25e13d8d2 100644 --- a/src/pop3/main.c +++ b/src/pop3/main.c @@ -180,7 +180,7 @@ static void drop_privileges(void) static bool main_init(void) { - struct mail_namespace *ns; + struct mail_user *user; struct client *client; const char *str; bool ret = TRUE; @@ -231,9 +231,11 @@ static bool main_init(void) "%% variables."); namespace_pool = pool_alloconly_create("namespaces", 1024); - if (mail_namespaces_init(namespace_pool, getenv("USER"), &ns) < 0) + user = mail_user_init(getenv("USER"), getenv("HOME")); + if (mail_namespaces_init(namespace_pool, user) < 0) i_fatal("Namespace initialization failed"); - client = client_create(0, 1, ns); + + client = client_create(0, 1, user); if (client == NULL) return FALSE; -- 2.47.3