virtual-storage.c revision f95b3d29bc56f139c18c880aa574a0ca72b0cffb
a1e4113a5388e34c08459c5b69679c82ac2bddc9Pavel Březina/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina MODULE_CONTEXT(obj, virtual_mailbox_list_module)
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březinastatic MODULE_CONTEXT_DEFINE_INIT(virtual_mailbox_list_module,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinavirtual_list_delete_mailbox(struct mailbox_list *list, const char *name);
a1e4113a5388e34c08459c5b69679c82ac2bddc9Pavel Březinavirtual_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
a1e4113a5388e34c08459c5b69679c82ac2bddc9Pavel Březinavirtual_get_list_settings(struct mailbox_list_settings *list_set,
a1e4113a5388e34c08459c5b69679c82ac2bddc9Pavel Březina const char *data, enum mail_storage_flags flags,
a1e4113a5388e34c08459c5b69679c82ac2bddc9Pavel Březina bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina list_set->subscription_fname = VIRTUAL_SUBSCRIPTION_FILE_NAME;
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (data == NULL || *data == '\0' || *data == ':') {
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* we won't do any guessing for this format. */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina i_info("virtual: mailbox location not given");
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina return mailbox_list_settings_parse(data, list_set, layout_r, NULL,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinastatic struct mail_storage *virtual_alloc(void)
afdc0179af0ad8ddbedd67422193ef02dcd2bf84Lukas Slebodnik pool = pool_alloconly_create("virtual storage", 512+256);
afdc0179af0ad8ddbedd67422193ef02dcd2bf84Lukas Slebodnik storage = p_new(pool, struct virtual_storage, 1);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinastatic int virtual_create(struct mail_storage *_storage, const char *data,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina const char **error_r)
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina struct virtual_storage *storage = (struct virtual_storage *)_storage;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek if (virtual_get_list_settings(&list_set, data, _storage->flags,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek list_set.mail_storage_flags = &_storage->flags;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek "Root mail directory doesn't exist: %s",
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek *error_r = t_strdup_printf("stat(%s) failed: %m",
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina if (mailbox_list_alloc(layout, &_storage->list, error_r) < 0)
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina storage->list_module_ctx.super = _storage->list->v;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina _storage->list->v.iter_is_mailbox = virtual_list_iter_is_mailbox;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina _storage->list->v.delete_mailbox = virtual_list_delete_mailbox;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina MODULE_CONTEXT_SET_FULL(_storage->list, virtual_mailbox_list_module,
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina /* finish list init after we've overridden vfuncs */
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina mailbox_list_init(_storage->list, _storage->ns, &list_set,
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina mail_storage_get_list_flags(_storage->flags));
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březinavirtual_backend_box_lookup_name(struct virtual_mailbox *mbox, const char *name)
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina unsigned int i, count;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina bboxes = array_get(&mbox->backend_boxes, &count);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina for (i = 0; i < count; i++) {
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březinavirtual_backend_box_lookup(struct virtual_mailbox *mbox, uint32_t mailbox_id)
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina unsigned int i, count;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina bboxes = array_get(&mbox->backend_boxes, &count);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina for (i = 0; i < count; i++) {
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březinastatic int virtual_mailboxes_open(struct virtual_mailbox *mbox,
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina unsigned int i, count;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina bboxes = array_get(&mbox->backend_boxes, &count);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina for (i = 0; i < count; i++) {
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina ns = mail_namespace_find(virtual_all_namespaces, &mailbox);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina bboxes[i]->box = mailbox_open(ns->storage, mailbox,
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina str = mail_storage_get_last_error(ns->storage, &error);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina mail_storage_set_error(mbox->ibox.box.storage,
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina i_array_init(&bboxes[i]->sync_pending_removes, 64);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina for (; i > 0; i--) {
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březinastatic struct mailbox *
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březinavirtual_open(struct virtual_storage *storage, const char *name,
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina struct mail_storage *_storage = &storage->storage;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina path = mailbox_list_get_path(_storage->list, name,
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina index = index_storage_alloc(_storage, name, flags,
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina mail_index_set_fsync_types(index, MAIL_INDEX_SYNC_TYPE_APPEND |
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina pool = pool_alloconly_create("virtual mailbox", 1024+512);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina mbox = p_new(pool, struct virtual_mailbox, 1);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina mbox->ibox.mail_vfuncs = &virtual_mail_vfuncs;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina index_storage_mailbox_init(&mbox->ibox, name, flags, FALSE);
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březinastatic struct mailbox *
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březinavirtual_mailbox_open(struct mail_storage *_storage, const char *name,
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina struct istream *input, enum mailbox_open_flags flags)
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina struct virtual_storage *storage = (struct virtual_storage *)_storage;
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina "virtual doesn't support streamed mailboxes");
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina path = mailbox_list_get_path(_storage->list, name,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek mail_storage_set_error(_storage, MAIL_ERROR_NOTFOUND,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek mail_storage_set_critical(_storage, "stat(%s) failed: %m",
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozekstatic int virtual_storage_mailbox_close(struct mailbox *box)
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek unsigned int i, count;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek bboxes = array_get_modifiable(&mbox->backend_boxes, &count);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek for (i = 0; i < count; i++) {
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek mailbox_search_result_free(&bboxes[i]->search_result);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek return index_storage_mailbox_close(box) < 0 ? -1 : ret;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozekstatic int virtual_mailbox_create(struct mail_storage *_storage,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek mail_storage_set_error(_storage, MAIL_ERROR_NOTPOSSIBLE,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek "Can't create virtual mailboxes");
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozekvirtual_delete_nonrecursive(struct mailbox_list *list, const char *path,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek const char *name)
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek unsigned int dir_len;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek if (!mailbox_list_set_error_from_errno(list)) {
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek /* skip . and .. */
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek if (d->d_name[1] == '.' && d->d_name[2] == '\0')
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek /* trying to unlink() a directory gives either EPERM or EISDIR
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek (non-POSIX). it doesn't really work anywhere in practise,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek so don't bother stat()ing the file first */
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina else if (errno != ENOENT && errno != EISDIR && errno != EPERM) {
132e477d69e07e02fe6e4d668c0bb6226206474aPavel Březina "unlink(%s) failed: %m",
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek mailbox_list_set_critical(list, "closedir(%s) failed: %m",
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek else if (errno != ENOENT && errno != ENOTEMPTY) {
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek mailbox_list_set_critical(list, "rmdir(%s) failed: %m", path);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinavirtual_list_delete_mailbox(struct mailbox_list *list, const char *name)
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek struct virtual_storage *storage = VIRTUAL_LIST_CONTEXT(list);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek const char *src;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek /* Make sure the indexes are closed before trying to delete the
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek directory that contains them. It can still fail with some NFS
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek implementations if indexes are opened by another session, but
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek that can't really be helped. */
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek /* delete the index and control directories */
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek if (storage->list_module_ctx.super.delete_mailbox(list, name) < 0)
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek /* check if the mailbox actually exists */
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek src = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_MAILBOX);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek return virtual_delete_nonrecursive(list, src, name);
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozekstatic void virtual_notify_changes(struct mailbox *box)
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozek struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
bdf32fbb3c947dd1b2c54d1c21d8028a1ddc80e6Jakub Hrozekvirtual_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* try to avoid stat() with these checks */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* it's a file */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* need to stat() then */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* non-directory */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina *flags |= MAILBOX_NOSELECT | MAILBOX_NOINFERIORS;
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* no subdirectories */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina } else if (*ctx->list->set.maildir_name != '\0') {
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* non-default configuration: we have one directory
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina containing the mailboxes. if there are 3 links,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina either this is a selectable mailbox without children
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina or non-selectable mailbox with children */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* default configuration: all subdirectories are
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina child mailboxes. */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* non-selectable. probably either access denied, or symlink
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina destination not found. don't bother logging errors. */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina /* make sure it's a selectable mailbox */
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina maildir_path = t_strconcat(path, "/"VIRTUAL_CONFIG_FNAME, NULL);
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina if (stat(maildir_path, &st) < 0 || !S_ISDIR(st.st_mode))
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinavirtual_save_init(struct mailbox_transaction_context *_t,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina mail_storage_set_error(_t->box->storage, MAIL_ERROR_NOTPOSSIBLE,
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březina "Can't save to virtual mailboxes");
8fe171bf5a7a570591418e6548105f1d5a0097b3Pavel Březinastatic void virtual_class_init(void)