mailbox-alias-plugin.c revision d4002fe1f64d25a792f76fb102ef7dc519cd4e24
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MODULE_CONTEXT(obj, mailbox_alias_user_module)
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen MODULE_CONTEXT(obj, mailbox_alias_storage_module)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MODULE_CONTEXT(obj, mailbox_alias_mailbox_list_module)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(mailbox_alias_user_module,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(mailbox_alias_storage_module,
b9c76fe9d9ca194816606342da1ddbd9be6bc8abTimo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(mailbox_alias_mailbox_list_module,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenconst char *mailbox_alias_plugin_version = DOVECOT_ABI_VERSION;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic const char *
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenmailbox_alias_find_new(struct mail_user *user, const char *new_vname)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct mailbox_alias_user *auser = MAILBOX_ALIAS_USER_CONTEXT(user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int mailbox_symlink_exists(struct mailbox_list *list, const char *vname,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen symlink_name = alist->module_ctx.super.get_storage_name(list, vname);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = mailbox_list_get_path(list, symlink_name,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen *existence_r = MAILBOX_SYMLINK_EXISTENCE_NONEXISTENT;
ca843e046e98b12f4730f4b87ee2e1a659c26e78Timo Sirainen *existence_r = MAILBOX_SYMLINK_EXISTENCE_SYMLINK;
ca843e046e98b12f4730f4b87ee2e1a659c26e78Timo Sirainen *existence_r = MAILBOX_SYMLINK_EXISTENCE_NOT_SYMLINK;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int mailbox_is_alias_symlink(struct mailbox *box)
d694a52bce62c52080c3f87a56dcf77030fd2712Timo Sirainen if (mailbox_alias_find_new(box->storage->user, box->vname) == NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mailbox_symlink_exists(box->list, box->vname, &existence) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_copy_list_error(box->storage, box->list);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return existence == MAILBOX_SYMLINK_EXISTENCE_SYMLINK ? 1 : 0;
6303191abcb37164f435ccdc56e9dbddf1288851Timo Sirainenmailbox_has_aliases(struct mailbox_list *list, const char *old_vname)
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen if (strcmp(alias->old_vname, old_vname) == 0) {
1bf5c6c20f3d51f13d3240cfb46e471074c86276Timo Sirainen if (mailbox_symlink_exists(list, alias->new_vname,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (existence == MAILBOX_SYMLINK_EXISTENCE_SYMLINK)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volkmailbox_alias_create_symlink(struct mailbox *box,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = mailbox_list_get_path(box->list, old_name,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = mailbox_list_get_path(box->list, new_name,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Mailbox aliases not supported by storage");
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen i_assert(strncmp(new_path, old_path, fname-old_path) == 0);
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_EXISTS,
b8afdaa1bffe2f27cd4b02bf3bfbd2d297c8e648Timo Sirainen "Mailbox already exists");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "symlink(%s, %s) failed: %m", fname, new_path);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic const char *
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenmailbox_alias_get_storage_name(struct mailbox_list *list, const char *vname)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* access the old mailbox so that e.g. full text search won't
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen index the mailbox twice. this also means that deletion must be
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen careful to delete the symlink, box->name. */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen old_vname = mailbox_alias_find_new(list->ns->user, vname);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen mailbox_symlink_exists(list, vname, &existence) == 0 &&
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen existence != MAILBOX_SYMLINK_EXISTENCE_NOT_SYMLINK)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return alist->module_ctx.super.get_storage_name(list, vname);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenmailbox_alias_create(struct mailbox *box, const struct mailbox_update *update,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct mailbox_alias_mailbox *abox = MAILBOX_ALIAS_CONTEXT(box);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ret = abox->module_ctx.super.create_box(box, update, directory);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mailbox_alias_find_new(box->storage->user, box->vname) == NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (ret < 0 && mailbox_get_last_mail_error(box) != MAIL_ERROR_EXISTS)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* all the code so far has actually only created the original
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen mailbox. now we'll create the symlink if it's missing. */
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen return mailbox_alias_create_symlink(box, box->name, symlink_name);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int mailbox_alias_delete(struct mailbox *box)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct mailbox_alias_mailbox *abox = MAILBOX_ALIAS_CONTEXT(box);
75e46142d8fbac811df8f2ca58d9a2f48a75d65fTimo Sirainen ret = mailbox_has_aliases(box->list, box->vname);
75e46142d8fbac811df8f2ca58d9a2f48a75d65fTimo Sirainen mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
75e46142d8fbac811df8f2ca58d9a2f48a75d65fTimo Sirainen "Can't delete mailbox while it has aliases");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((ret = mailbox_is_alias_symlink(box)) < 0)
77f1da4b5e2b800197d8db548235497d5e9d6a4fTimo Sirainen /* we're deleting an alias mailbox. we'll need to handle this
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen explicitly since box->name points to the original mailbox */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (mailbox_list_delete_symlink(box->list, symlink_name) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_copy_list_error(box->storage, box->list);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return abox->module_ctx.super.delete_box(box);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic int mailbox_alias_rename(struct mailbox *src, struct mailbox *dest)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct mailbox_alias_mailbox *abox = MAILBOX_ALIAS_CONTEXT(src);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((ret = mailbox_is_alias_symlink(src)) < 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen else if (ret > 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Can't rename alias mailboxes");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if ((ret = mailbox_is_alias_symlink(dest)) < 0)
77f1da4b5e2b800197d8db548235497d5e9d6a4fTimo Sirainen else if (ret > 0) {
75e46142d8fbac811df8f2ca58d9a2f48a75d65fTimo Sirainen mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
77f1da4b5e2b800197d8db548235497d5e9d6a4fTimo Sirainen "Can't rename to mailbox alias");
75e46142d8fbac811df8f2ca58d9a2f48a75d65fTimo Sirainen ret = mailbox_has_aliases(src->list, src->vname);
18f1bbf05980d3c53ecae81b62574212f0891522Timo Sirainen mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "Can't rename mailbox while it has aliases");
e911b23f3e05308df9b98b1a3fdaf72e4302d8fdTimo Sirainen return abox->module_ctx.super.rename_box(src, dest);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void mailbox_alias_mail_user_created(struct mail_user *user)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen unsigned int i;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen auser = p_new(user->pool, struct mailbox_alias_user, 1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen for (i = 2;; i++) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen old_vname = mail_user_plugin_getenv(user, str_c(oldkey));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen new_vname = mail_user_plugin_getenv(user, str_c(newkey));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_printfa(oldkey, "mailbox_alias_old%u", i);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen str_printfa(newkey, "mailbox_alias_new%u", i);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainen MODULE_CONTEXT_SET(user, mailbox_alias_user_module, auser);
1093de32efb2a231949566d4bd8aa55a8f43fb70Timo Sirainenstatic void mailbox_alias_mailbox_list_created(struct mailbox_list *list)
de754cb78f75e8b3b994cddafe41c9ed1467c33dTimo Sirainen alist = p_new(list->pool, struct mailbox_alias_mailbox_list, 1);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen v->get_storage_name = mailbox_alias_get_storage_name;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen MODULE_CONTEXT_SET(list, mailbox_alias_mailbox_list_module, alist);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void mailbox_alias_mailbox_allocated(struct mailbox *box)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen abox = p_new(box->pool, struct mailbox_alias_mailbox, 1);
e7dd5065d21c569e5e6ddd713bd345dadd1cf51dTimo Sirainen MODULE_CONTEXT_SET(box, mailbox_alias_storage_module, abox);
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainenstatic struct mail_storage_hooks mailbox_alias_mail_storage_hooks = {
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen .mail_user_created = mailbox_alias_mail_user_created,
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen .mailbox_list_created = mailbox_alias_mailbox_list_created,
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainen .mailbox_allocated = mailbox_alias_mailbox_allocated
c51644e9e04effbbc9c415cadcfbcb4d9465855cTimo Sirainenvoid mailbox_alias_plugin_init(struct module *module)
2598b2f36365b52d9754b9348a5be29569293e46Timo Sirainen mail_storage_hooks_add(module, &mailbox_alias_mail_storage_hooks);