mailbox-list-fs-iter.c revision 5fb3bff645380804c9db2510940c41db6b8fdb01
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose/* Copyright (C) 2002-2006 Timo Sirainen */
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose#include "lib.h"
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose#include "home-expand.h"
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose#include "unlink-directory.h"
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose#include "imap-match.h"
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose#include "subscription-file.h"
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose#include "mailbox-list-fs.h"
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose#include <dirent.h>
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestruct list_dir_context {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose struct list_dir_context *prev;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose DIR *dirp;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose char *real_path, *virtual_path;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose};
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestruct fs_list_iterate_context {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose struct mailbox_list_iterate_context ctx;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose struct imap_match_glob *glob;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose struct subsfile_list_context *subsfile_ctx;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose bool inbox_found;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose struct mailbox_info *(*next)(struct fs_list_iterate_context *ctx);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose pool_t info_pool;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose struct mailbox_info info;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose struct list_dir_context *dir;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose};
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestatic struct mailbox_info *fs_list_subs(struct fs_list_iterate_context *ctx);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestatic struct mailbox_info *fs_list_path(struct fs_list_iterate_context *ctx);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestatic struct mailbox_info *fs_list_next(struct fs_list_iterate_context *ctx);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestatic const char *mask_get_dir(const char *mask)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose{
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose const char *p, *last_dir;
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose last_dir = NULL;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose for (p = mask; *p != '\0' && *p != '%' && *p != '*'; p++) {
cc2d77d5218c188119fa954c856e858cbde76947Pavel Březina if (*p == '/')
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose last_dir = p;
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return last_dir == NULL ? NULL : t_strdup_until(mask, last_dir);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose}
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestatic int list_opendir(struct mailbox_list *list,
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose const char *path, bool root, DIR **dirp)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose{
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose *dirp = opendir(*path == '\0' ? "/" : path);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (*dirp != NULL)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return 1;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (ENOTFOUND(errno)) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose /* root) user gave invalid hiearchy, ignore
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose sub) probably just race condition with other client
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose deleting the mailbox. */
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return 0;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (errno == EACCES) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (!root) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose /* subfolder, ignore */
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return 0;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose }
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose mailbox_list_set_error(list, "Access denied");
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose return -1;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose }
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose mailbox_list_set_critical(list, "opendir(%s) failed: %m", path);
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose return -1;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose}
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bosestruct mailbox_list_iterate_context *
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bosefs_list_iter_init(struct mailbox_list *_list, const char *mask,
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose enum mailbox_list_iter_flags flags)
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose{
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose struct fs_mailbox_list *list =
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose (struct fs_mailbox_list *)_list;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose struct fs_list_iterate_context *ctx;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose const char *path, *virtual_path;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose DIR *dirp;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose mailbox_list_clear_error(&list->list);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ctx = i_new(struct fs_list_iterate_context, 1);
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ctx->ctx.list = _list;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ctx->ctx.flags = flags;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ctx->info_pool = pool_alloconly_create("fs list", 1024);
aa35995ef056aa8ae052a47c62c6750b7adf065eSumit Bose ctx->next = fs_list_next;
aa35995ef056aa8ae052a47c62c6750b7adf065eSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose /* check that we're not trying to do any "../../" lists */
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose if (!mailbox_list_is_valid_mask(_list, mask)) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose mailbox_list_set_error(_list, "Invalid mask");
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->ctx.failed = TRUE;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return &ctx->ctx;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if ((flags & MAILBOX_LIST_ITER_SUBSCRIBED) != 0) {
ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3Sumit Bose ctx->next = fs_list_subs;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose path = t_strconcat(_list->set.control_dir != NULL ?
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose _list->set.control_dir : _list->set.root_dir,
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose "/", _list->set.subscription_fname, NULL);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->subsfile_ctx = subsfile_list_init(_list, path);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (ctx->subsfile_ctx == NULL) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->next = fs_list_next;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->ctx.failed = TRUE;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return &ctx->ctx;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->glob = imap_match_init(default_pool, mask, TRUE, '/');
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return &ctx->ctx;
ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose /* if we're matching only subdirectories, don't bother scanning the
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose parent directories */
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose virtual_path = mask_get_dir(mask);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose path = mailbox_list_get_path(_list, virtual_path,
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose MAILBOX_LIST_PATH_TYPE_MAILBOX);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (list_opendir(_list, path, TRUE, &dirp) < 0)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return &ctx->ctx;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose /* if user gave invalid directory, we just don't show any results. */
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->ctx.flags = flags;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->glob = imap_match_init(default_pool, mask, TRUE, '/');
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3Sumit Bose if (virtual_path != NULL && dirp != NULL)
ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3Sumit Bose ctx->next = fs_list_path;
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose if (dirp != NULL) {
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose ctx->dir = i_new(struct list_dir_context, 1);
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose ctx->dir->dirp = dirp;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->dir->real_path = i_strdup(path);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->dir->virtual_path = i_strdup(virtual_path);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return &ctx->ctx;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose}
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestatic void list_dir_context_free(struct list_dir_context *dir)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose{
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose (void)closedir(dir->dirp);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose i_free(dir->real_path);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose i_free(dir->virtual_path);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose i_free(dir);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose}
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Boseint fs_list_iter_deinit(struct mailbox_list_iterate_context *_ctx)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose{
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose struct fs_list_iterate_context *ctx =
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose (struct fs_list_iterate_context *)_ctx;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose int ret = ctx->ctx.failed ? -1 : 0;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (ctx->subsfile_ctx != NULL) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (subsfile_list_deinit(ctx->subsfile_ctx) < 0)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ret = -1;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose while (ctx->dir != NULL) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose struct list_dir_context *dir = ctx->dir;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->dir = dir->prev;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose list_dir_context_free(dir);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (ctx->info_pool != NULL)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose pool_unref(ctx->info_pool);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (ctx->glob != NULL)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose imap_match_deinit(&ctx->glob);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose i_free(ctx);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return ret;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose}
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bosestruct mailbox_info *
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bosefs_list_iter_next(struct mailbox_list_iterate_context *_ctx)
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose{
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose struct fs_list_iterate_context *ctx =
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose (struct fs_list_iterate_context *)_ctx;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose if (ctx->ctx.failed)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return NULL;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose return ctx->next(ctx);
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose}
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bosestatic int
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Boselist_file(struct fs_list_iterate_context *ctx, const struct dirent *d)
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose{
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose const char *fname = d->d_name;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose struct list_dir_context *dir;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose const char *list_path, *real_path, *path, *inbox_path;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose DIR *dirp;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose enum imap_match_result match, match2;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose int ret;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose /* skip . and .. */
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (fname[0] == '.' &&
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose (fname[1] == '\0' ||
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose (fname[1] == '.' && fname[2] == '\0')))
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return 0;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3Sumit Bose /* check the mask */
ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3Sumit Bose if (ctx->dir->virtual_path == NULL)
ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3Sumit Bose list_path = fname;
ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3Sumit Bose else {
ead25e32c52c8c2f5fd9abd179e9e81de58f9ca3Sumit Bose list_path = t_strconcat(ctx->dir->virtual_path,
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose "/", fname, NULL);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if ((match = imap_match(ctx->glob, list_path)) < 0)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return 0;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose /* get the info.flags using callback */
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->info.flags = 0;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ret = ctx->ctx.list->callback(ctx->dir->real_path, fname,
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose mailbox_list_get_file_type(d),
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->ctx.flags, &ctx->info.flags,
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->ctx.list->context);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (ret <= 0)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return ret;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose /* make sure we give only one correct INBOX */
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose real_path = t_strconcat(ctx->dir->real_path, "/", fname, NULL);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (strcasecmp(list_path, "INBOX") == 0 &&
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose (ctx->ctx.list->flags & MAILBOX_LIST_FLAG_INBOX) != 0) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose inbox_path = mailbox_list_get_path(ctx->ctx.list, "INBOX",
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose MAILBOX_LIST_PATH_TYPE_MAILBOX);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (ctx->inbox_found || strcmp(real_path, inbox_path) != 0)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return 0;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->inbox_found = TRUE;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if ((ctx->info.flags & MAILBOX_NOINFERIORS) == 0) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose /* subdirectory. scan inside it. */
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose path = t_strconcat(list_path, "/", NULL);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose match2 = imap_match(ctx->glob, path);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (match > 0)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->info.name = p_strdup(ctx->info_pool, list_path);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose else if (match2 > 0)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->info.name = p_strdup(ctx->info_pool, path);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose else
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->info.name = NULL;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ret = match2 < 0 ? 0 :
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose list_opendir(ctx->ctx.list, real_path, FALSE, &dirp);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (ret > 0) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose dir = i_new(struct list_dir_context, 1);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose dir->dirp = dirp;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose dir->real_path = i_strdup(real_path);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose dir->virtual_path = i_strdup(list_path);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose dir->prev = ctx->dir;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->dir = dir;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose } else if (ret < 0)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return -1;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return match > 0 || match2 > 0;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose } else if (match > 0) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->info.name = p_strdup(ctx->info_pool, list_path);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return 1;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose return 0;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose}
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestatic void
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosepath_split(const char *path, const char **dir_r, const char **fname_r)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose{
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose const char *p;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose p = strrchr(path, '/');
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (p == NULL) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose *dir_r = "";
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose *fname_r = path;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose } else {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose *dir_r = t_strdup_until(path, p);
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose *fname_r = p + 1;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose}
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
aa35995ef056aa8ae052a47c62c6750b7adf065eSumit Bosestatic struct mailbox_info *fs_list_subs(struct fs_list_iterate_context *ctx)
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose{
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose const char *name, *path, *p, *dir, *fname;
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose enum imap_match_result match = IMAP_MATCH_NO;
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose while ((name = subsfile_list_next(ctx->subsfile_ctx)) != NULL) {
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose match = imap_match(ctx->glob, name);
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose if (match == IMAP_MATCH_YES || match == IMAP_MATCH_PARENT)
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose break;
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose }
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose if (name == NULL)
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose return NULL;
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose ctx->info.flags = 0;
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose ctx->info.name = name;
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose if (match == IMAP_MATCH_PARENT) {
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose /* placeholder */
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose ctx->info.flags = MAILBOX_NONEXISTENT | MAILBOX_CHILDREN;
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose while ((p = strrchr(name, '/')) != NULL) {
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose name = t_strdup_until(name, p);
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose if (imap_match(ctx->glob, name) > 0) {
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose p_clear(ctx->info_pool);
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose ctx->info.name = p_strdup(ctx->info_pool, name);
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose return &ctx->info;
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose }
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose }
544a20de7667f05c1a406c4dea0706b0ab507430Sumit Bose i_unreached();
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose }
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose if ((ctx->ctx.flags & MAILBOX_LIST_ITER_FAST_FLAGS) != 0)
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose return &ctx->info;
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose t_push();
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose path = mailbox_list_get_path(ctx->ctx.list, ctx->info.name,
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose MAILBOX_LIST_PATH_TYPE_MAILBOX);
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose path_split(path, &dir, &fname);
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose if (ctx->ctx.list->callback(dir, fname,
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose MAILBOX_LIST_FILE_TYPE_UNKNOWN,
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->ctx.flags, &ctx->info.flags,
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->ctx.list->context) < 0)
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->ctx.failed = TRUE;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose t_pop();
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose return &ctx->info;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose}
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bosestatic struct mailbox_info *fs_list_path(struct fs_list_iterate_context *ctx)
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose{
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ctx->next = fs_list_next;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ctx->info.flags = MAILBOX_NOSELECT | MAILBOX_CHILDREN;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ctx->info.name =
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose p_strconcat(ctx->info_pool, ctx->dir->virtual_path, "/", NULL);
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose if (imap_match(ctx->glob, ctx->info.name) > 0)
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose return &ctx->info;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose else
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose return ctx->next(ctx);
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose}
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bosestatic struct mailbox_info *fs_list_inbox(struct fs_list_iterate_context *ctx)
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose{
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose const char *inbox_path, *dir, *fname;
d0de7701d44c7a75210a9cb04634913ce3a94bfbSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ctx->info.flags = 0;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ctx->info.name = "INBOX";
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose t_push();
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose inbox_path = mailbox_list_get_path(ctx->ctx.list, "INBOX",
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose MAILBOX_LIST_PATH_TYPE_MAILBOX);
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose path_split(inbox_path, &dir, &fname);
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose if (ctx->ctx.list->callback(dir, fname,
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose MAILBOX_LIST_FILE_TYPE_UNKNOWN,
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ctx->ctx.flags, &ctx->info.flags,
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ctx->ctx.list->context) < 0)
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ctx->ctx.failed = TRUE;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose t_pop();
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose return &ctx->info;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose}
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bosestatic struct mailbox_info *fs_list_next(struct fs_list_iterate_context *ctx)
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose{
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose struct list_dir_context *dir;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose struct dirent *d;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose int ret;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose p_clear(ctx->info_pool);
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose while (ctx->dir != NULL) {
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose /* NOTE: list_file() may change ctx->dir */
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose while ((d = readdir(ctx->dir->dirp)) != NULL) {
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose t_push();
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose ret = list_file(ctx, d);
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose t_pop();
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose
d0de7701d44c7a75210a9cb04634913ce3a94bfbSumit Bose if (ret > 0)
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose return &ctx->info;
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose if (ret < 0) {
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose ctx->ctx.failed = TRUE;
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose return NULL;
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose }
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose }
39fd336e4390ece3a8465714735ef4203f329e54Sumit Bose
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose dir = ctx->dir;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose ctx->dir = dir->prev;
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose list_dir_context_free(dir);
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose }
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose if (!ctx->inbox_found &&
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose (ctx->ctx.list->flags & MAILBOX_LIST_FLAG_INBOX) != 0 &&
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose ctx->glob != NULL && imap_match(ctx->glob, "INBOX") > 0) {
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose /* show inbox */
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose ctx->inbox_found = TRUE;
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose return fs_list_inbox(ctx);
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose }
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose /* finished */
53ef8f81b60929a6c866efdd133627e7d7d61705Sumit Bose return NULL;
0a8024af282b271ad2185f68703d9f4e766d2bdcSumit Bose}
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose