#include "imap-match.h"
#include "commands.h"
-struct list_node {
- struct list_node *next;
- struct list_node *children;
-
- char *name; /* escaped */
- enum mailbox_flags flags;
-};
-
-struct list_context {
- pool_t pool;
- struct list_node *nodes;
- struct mail_storage *storage;
-};
-
-struct list_send_context {
- struct client *client;
- const char *response_name;
- const char *sep;
- char sep_chr;
- struct imap_match_glob *glob;
- int listext, no_placeholder;
-};
-
-static const char *mailbox_flags2str(enum mailbox_flags flags,
- int listext, int no_placeholder)
+static const char *mailbox_flags2str(enum mailbox_flags flags, int listext)
{
const char *str;
if (flags & MAILBOX_PLACEHOLDER) {
- if ((flags & ~MAILBOX_CHILDREN) == MAILBOX_PLACEHOLDER) {
- if (!listext || no_placeholder)
- flags = MAILBOX_NOSELECT;
- } else {
- /* it was at one point, but then we got better specs */
- flags &= ~MAILBOX_PLACEHOLDER;
- }
+ i_assert((flags & ~MAILBOX_CHILDREN) == MAILBOX_PLACEHOLDER);
+
+ if (!listext)
+ flags = MAILBOX_NOSELECT;
flags |= MAILBOX_CHILDREN;
}
if ((flags & MAILBOX_NONEXISTENT) != 0 && !listext)
return *str == '\0' ? "" : str+1;
}
-static void list_node_update(pool_t pool, struct list_node **node,
- const char *path, char separator,
- enum mailbox_flags flags)
-{
- const char *name, *parent;
-
- parent = NULL;
-
- for (name = path;; path++) {
- if (*path != separator && *path != '\0')
- continue;
-
- t_push();
-
- name = t_strdup_until(name, path);
-
- /* find the node */
- while (*node != NULL) {
- if (strcmp((*node)->name, name) == 0)
- break;
-
- node = &(*node)->next;
- }
-
- if (*node == NULL) {
- /* not found, create it */
- *node = p_new(pool, struct list_node, 1);
- (*node)->name = p_strdup(pool, name);
- (*node)->flags = *path == '\0' ? flags :
- MAILBOX_PLACEHOLDER;
- } else {
- if (*path == '\0') {
- if (((*node)->flags & MAILBOX_NOSELECT) != 0 &&
- (flags & MAILBOX_NOSELECT) == 0) {
- /* overrides previous flag */
- (*node)->flags &= ~MAILBOX_NOSELECT;
- }
-
- (*node)->flags |= flags;
- }
- }
-
- t_pop();
-
- if (*path == '\0')
- break;
-
- name = path+1;
- parent = (*node)->name;
- node = &(*node)->children;
- }
-}
-
-static void list_send(struct list_send_context *ctx, struct list_node *node,
- const char *path)
-{
- const char *name, *send_name, *flagstr;
- enum imap_match_result match;
- string_t *str;
-
- for (; node != NULL; node = node->next) {
- t_push();
-
- /* Send INBOX always uppercased */
- if (path != NULL) {
- name = t_strdup_printf("%s%c%s", path, ctx->sep_chr,
- node->name);
- } else if (strcasecmp(node->name, "INBOX") == 0)
- name = "INBOX";
- else
- name = node->name;
- send_name = name;
-
- if ((node->flags & MAILBOX_PLACEHOLDER) == 0 &&
- (node->flags & MAILBOX_NOSELECT) == 0)
- match = IMAP_MATCH_YES;
- else {
- /* make sure the placeholder matches. */
- const char *buf;
-
- buf = str_unescape(t_strdup_noconst(name));
- match = imap_match(ctx->glob, buf);
- /* FIXME: IMAP spec says this should be done, but
- a) this is broken, we shouldn't give \NoSelect for
- this folder if it actually works.
- b) at least mozilla's subscriptions list breaks if
- this is sent
- c) cyrus and courier doesn't do this either..
-
- if (match == IMAP_MATCH_CHILDREN) {
- send_name = t_strdup_printf("%s%c", name,
- ctx->sep);
- buf = str_unescape(t_strdup_noconst(send_name));
- match = imap_match(ctx->glob, buf);
- }*/
- }
-
- if (match == IMAP_MATCH_YES) {
- /* node->name should already be escaped */
- flagstr = mailbox_flags2str(node->flags, ctx->listext,
- ctx->no_placeholder);
- t_push();
- str = t_str_new(256);
- str_printfa(str, "* %s (%s) \"%s\" ",
- ctx->response_name, flagstr, ctx->sep);
- imap_quote_append_string(str, send_name, FALSE);
- client_send_line(ctx->client, str_c(str));
- t_pop();
- }
-
- if (node->children != NULL)
- list_send(ctx, node->children, name);
-
- t_pop();
- }
-}
-
-static void list_and_sort(struct client *client,
- struct mailbox_list_context *ctx,
- const char *response_name, const char *mask,
- const char *sep, char sep_chr,
- enum mailbox_list_flags list_flags, int listext)
-{
- struct mailbox_list *list;
- struct list_node *nodes;
- struct list_send_context send_ctx;
- pool_t pool;
-
- pool = pool_alloconly_create("list_mailboxes", 10240);
- nodes = NULL;
-
- while ((list = client->storage->list_mailbox_next(ctx)) != NULL) {
- list_node_update(pool, &nodes, list->name,
- client->storage->hierarchy_sep,
- list->flags);
- }
-
- send_ctx.client = client;
- send_ctx.response_name = response_name;
- send_ctx.sep = sep;
- send_ctx.sep_chr = sep_chr;
- send_ctx.glob = imap_match_init(data_stack_pool, mask, TRUE,
- client->storage->hierarchy_sep);
- send_ctx.listext = listext;
- send_ctx.no_placeholder = (list_flags & MAILBOX_LIST_SUBSCRIBED) == 0;
-
- list_send(&send_ctx, nodes, NULL);
- imap_match_deinit(send_ctx.glob);
- pool_unref(pool);
-}
-
-static void list_unsorted(struct client *client,
- struct mailbox_list_context *ctx,
- const char *reply, const char *sep, int listext)
+static int mailbox_list(struct client *client, const char *mask,
+ const char *sep, const char *reply,
+ enum mailbox_list_flags list_flags, int listext)
{
+ struct mailbox_list_context *ctx;
struct mailbox_list *list;
string_t *str;
+ ctx = client->storage->list_mailbox_init(client->storage, mask,
+ list_flags);
+ if (ctx == NULL)
+ return FALSE;
+
+ str = t_str_new(256);
while ((list = client->storage->list_mailbox_next(ctx)) != NULL) {
- t_push();
- str = t_str_new(256);
+ str_truncate(str, 0);
str_printfa(str, "* %s (%s) \"%s\" ", reply,
- mailbox_flags2str(list->flags, listext, FALSE),
+ mailbox_flags2str(list->flags, listext),
sep);
if (strcasecmp(list->name, "INBOX") == 0)
str_append(str, "INBOX");
else
imap_quote_append_string(str, list->name, FALSE);
client_send_line(client, str_c(str));
- t_pop();
}
+
+ return client->storage->list_mailbox_deinit(ctx);
}
static int parse_list_flags(struct client *client, struct imap_arg *args,
{
struct imap_arg *args;
enum mailbox_list_flags list_flags;
- struct mailbox_list_context *ctx;
const char *ref, *mask;
char sep_chr, sep[3];
- int failed, sorted, listext;
+ int failed, listext;
sep_chr = client->storage->hierarchy_sep;
if (IS_ESCAPED_CHAR(sep_chr)) {
}
}
- ctx = client->storage->list_mailbox_init(client->storage, mask,
- list_flags, &sorted);
- if (ctx == NULL)
- failed = TRUE;
- else {
- const char *response_name = lsub ? "LSUB" : "LIST";
-
- if (sorted) {
- list_unsorted(client, ctx, response_name, sep,
- listext);
- } else {
- list_and_sort(client, ctx, response_name, mask,
- sep, sep_chr, list_flags,
- listext);
- }
-
- failed = !client->storage->list_mailbox_deinit(ctx);
- }
+ failed = !mailbox_list(client, mask, sep,
+ lsub ? "LSUB" : "LIST",
+ list_flags, listext);
}
if (failed)
/* Copyright (C) 2002 Timo Sirainen */
#include "lib.h"
-#include "hostpid.h"
+#include "ioloop.h"
+#include "str.h"
#include "home-expand.h"
#include "unlink-directory.h"
#include "imap-match.h"
#include "subscription-file/subscription-file.h"
-#include "maildir-index.h"
#include "maildir-storage.h"
+#include "mailbox-tree.h"
#include <dirent.h>
#include <sys/stat.h>
+#define MAILBOX_FLAG_MATCHED 0x40000000
+
struct mailbox_list_context {
- pool_t pool, list_pool;
+ pool_t pool;
struct mail_storage *storage;
const char *dir, *prefix;
enum mailbox_list_flags flags;
- DIR *dirp;
- struct imap_match_glob *glob;
- struct subsfile_list_context *subsfile_ctx;
-
- struct mailbox_list *(*next)(struct mailbox_list_context *ctx);
+ struct mailbox_tree_context *tree_ctx;
+ string_t *node_path;
+ size_t parent_pos;
+ struct mailbox_node *root, *next_node;
struct mailbox_list list;
int failed;
};
-static struct mailbox_list *maildir_list_subs(struct mailbox_list_context *ctx);
-static struct mailbox_list *maildir_list_next(struct mailbox_list_context *ctx);
+static void maildir_nodes_fix(struct mailbox_node *node, int is_subs)
+{
+ while (node != NULL) {
+ if (node->children != NULL) {
+ node->flags |= MAILBOX_CHILDREN;
+ maildir_nodes_fix(node->children, is_subs);
+ } else if ((node->flags & MAILBOX_PLACEHOLDER) != 0) {
+ if (!is_subs) {
+ node->flags &= ~MAILBOX_PLACEHOLDER;
+ node->flags |= MAILBOX_NOSELECT;
+ }
+ } else {
+ if ((node->flags & MAILBOX_CHILDREN) == 0)
+ node->flags |= MAILBOX_NOCHILDREN;
+ }
+ node = node->next;
+ }
+}
-static enum mailbox_flags maildir_get_marked_flags(const char *dir)
+static int maildir_fill_readdir(struct mailbox_list_context *ctx,
+ struct imap_match_glob *glob, int update_only)
{
- struct stat st_new, st_cur;
+ DIR *dirp;
+ struct dirent *d;
+ const char *path, *p;
+ string_t *mailbox;
+ enum imap_match_result match;
+ struct mailbox_node *node;
+ int created;
+
+ dirp = opendir(ctx->dir);
+ if (dirp == NULL) {
+ if (errno != ENOENT) {
+ mail_storage_set_critical(ctx->storage,
+ "opendir(%s) failed: %m", ctx->dir);
+ return FALSE;
+ }
+ }
- /* assume marked if new/ has been modified later than cur/ */
- if (stat(t_strconcat(dir, "/new", NULL), &st_new) < 0)
- return MAILBOX_UNMARKED;
+ /* INBOX exists always */
+ if (imap_match(glob, "INBOX") > 0 && !update_only) {
+ node = mailbox_tree_get(ctx->tree_ctx, "INBOX", NULL);
+ node->flags |= MAILBOX_FLAG_MATCHED;
+ node->flags &= ~(MAILBOX_PLACEHOLDER | MAILBOX_NONEXISTENT);
+ }
- if (stat(t_strconcat(dir, "/cur", NULL), &st_cur) < 0)
- return MAILBOX_UNMARKED;
+ mailbox = t_str_new(PATH_MAX);
+ while ((d = readdir(dirp)) != NULL) {
+ const char *fname = d->d_name;
+
+ if (fname[0] != '.')
+ continue;
+
+ /* skip . and .. */
+ if (fname[1] == '\0' || (fname[1] == '.' && fname[2] == '\0'))
+ continue;
+
+ /* FIXME: kludges. these files must be renamed later */
+ if (strcmp(fname, ".customflags") == 0 ||
+ strcmp(fname, ".subscriptions") == 0)
+ continue;
+
+ fname++;
+ if (*fname == '.') {
+ /* this mailbox is in the middle of being deleted,
+ or the process trying to delete it had died.
+
+ delete it ourself if it's been there longer than
+ one hour. don't touch it if it's outside our
+ mail root dir. */
+ struct stat st;
+
+ if (*ctx->prefix == '\0')
+ continue;
+
+ t_push();
+ path = t_strdup_printf("%s/%s", ctx->dir, fname);
+ if (stat(path, &st) == 0 &&
+ st.st_mtime < ioloop_time - 3600)
+ (void)unlink_directory(path, TRUE);
+ t_pop();
+ continue;
+ }
+
+ /* make sure the mask matches */
+ str_truncate(mailbox, 0);
+ str_append(mailbox, ctx->prefix);
+ str_append(mailbox, fname);
+
+ match = imap_match(glob, str_c(mailbox));
+
+ if (match != IMAP_MATCH_YES &&
+ (match != IMAP_MATCH_PARENT || update_only))
+ continue;
+
+ if (strcasecmp(str_c(mailbox), "INBOX") == 0)
+ continue; /* ignore inboxes */
+
+ if (match == IMAP_MATCH_PARENT) {
+ t_push();
+ while ((p = strrchr(fname, '.')) != NULL) {
+ fname = t_strdup_until(fname, p);
+ p = t_strconcat(ctx->prefix, fname, NULL);
+ if (imap_match(glob, p) > 0)
+ break;
+ }
+ i_assert(p != NULL);
+
+ node = mailbox_tree_get(ctx->tree_ctx, p, &created);
+ if (created)
+ node->flags = MAILBOX_PLACEHOLDER;
+ node->flags |= MAILBOX_CHILDREN | MAILBOX_FLAG_MATCHED;
+
+ t_pop();
+ } else {
+ p = str_c(mailbox);
+ if (update_only)
+ node = mailbox_tree_update(ctx->tree_ctx, p);
+ else
+ node = mailbox_tree_get(ctx->tree_ctx, p, NULL);
+
+ if (node != NULL) {
+ node->flags &= ~(MAILBOX_PLACEHOLDER |
+ MAILBOX_NONEXISTENT);
+ node->flags |= MAILBOX_FLAG_MATCHED;
+ }
+ }
+ }
+
+ if (closedir(dirp) < 0) {
+ mail_storage_set_critical(ctx->storage,
+ "readdir(%s) failed: %m", ctx->dir);
+ return FALSE;
+ }
+
+ maildir_nodes_fix(mailbox_tree_get(ctx->tree_ctx, NULL, NULL),
+ (ctx->flags & MAILBOX_LIST_SUBSCRIBED) != 0);
+ return TRUE;
+}
+
+static int maildir_fill_subscribed(struct mailbox_list_context *ctx,
+ struct imap_match_glob *glob,
+ int nonexistent)
+{
+ struct subsfile_list_context *subsfile_ctx;
+ const char *name, *p;
+ struct mailbox_node *node;
+ int created;
+
+ subsfile_ctx = subsfile_list_init(ctx->storage);
+ if (subsfile_ctx == NULL)
+ return FALSE;
+
+ while ((name = subsfile_list_next(subsfile_ctx)) != NULL) {
+ switch (imap_match(glob, name)) {
+ case IMAP_MATCH_YES:
+ node = mailbox_tree_get(ctx->tree_ctx, name, NULL);
+ node->flags = MAILBOX_FLAG_MATCHED;
+ if (nonexistent && strcasecmp(name, "INBOX") != 0)
+ node->flags |= MAILBOX_NONEXISTENT;
+ break;
+ case IMAP_MATCH_PARENT:
+ /* placeholder */
+ while ((p = strrchr(name, '.')) != NULL) {
+ name = t_strdup_until(name, p);
+ if (imap_match(glob, name) > 0)
+ break;
+ }
+ i_assert(p != NULL);
+
+ node = mailbox_tree_get(ctx->tree_ctx, name, &created);
+ if (created) node->flags = MAILBOX_PLACEHOLDER;
+ node->flags |= MAILBOX_FLAG_MATCHED;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return subsfile_list_deinit(subsfile_ctx);
- return st_new.st_mtime <= st_cur.st_mtime ?
- MAILBOX_UNMARKED : MAILBOX_MARKED;
}
struct mailbox_list_context *
maildir_list_mailbox_init(struct mail_storage *storage,
- const char *mask, enum mailbox_list_flags flags,
- int *sorted)
+ const char *mask, enum mailbox_list_flags flags)
{
struct mailbox_list_context *ctx;
- pool_t pool;
+ struct imap_match_glob *glob;
const char *dir, *p;
+ int nonexistent;
+ pool_t pool;
- *sorted = FALSE;
mail_storage_clear_error(storage);
pool = pool_alloconly_create("maildir_list", 1024);
ctx->pool = pool;
ctx->storage = storage;
ctx->flags = flags;
+ ctx->tree_ctx = mailbox_tree_init('.');
+
+ glob = imap_match_init(pool, mask, TRUE, '.');
if ((flags & MAILBOX_LIST_SUBSCRIBED) != 0) {
- ctx->glob = imap_match_init(pool, mask, TRUE, '.');
- ctx->subsfile_ctx = subsfile_list_init(storage);
- ctx->next = maildir_list_subs;
- if (ctx->subsfile_ctx == NULL) {
+ ctx->dir = storage->dir;
+ ctx->prefix = "";
+
+ nonexistent = (flags & MAILBOX_LIST_FAST_FLAGS) == 0;
+ if (!maildir_fill_subscribed(ctx, glob, nonexistent)) {
+ mailbox_tree_deinit(ctx->tree_ctx);
pool_unref(pool);
return NULL;
}
- return ctx;
- }
-
- if (!full_filesystem_access || (p = strrchr(mask, '/')) == NULL) {
- ctx->dir = storage->dir;
- ctx->prefix = "";
} else {
- dir = t_strdup_until(mask, p);
- ctx->prefix = t_strdup_until(mask, p+1);
-
- if (*mask != '/' && *mask != '~')
- dir = t_strconcat(storage->dir, "/", dir, NULL);
- ctx->dir = p_strdup(pool, home_expand(dir));
+ if (!full_filesystem_access ||
+ (p = strrchr(mask, '/')) == NULL) {
+ ctx->dir = storage->dir;
+ ctx->prefix = "";
+ } else {
+ dir = t_strdup_until(mask, p);
+ ctx->prefix = t_strdup_until(mask, p+1);
+
+ if (*mask != '/' && *mask != '~')
+ dir = t_strconcat(storage->dir, "/", dir, NULL);
+ ctx->dir = p_strdup(pool, home_expand(dir));
+ }
}
- ctx->dirp = opendir(ctx->dir);
- if (ctx->dirp == NULL && errno != ENOENT) {
- mail_storage_set_critical(storage, "opendir(%s) failed: %m",
- ctx->dir);
- pool_unref(pool);
- return NULL;
+ if ((flags & MAILBOX_LIST_SUBSCRIBED) == 0 ||
+ (ctx->flags & MAILBOX_LIST_FAST_FLAGS) == 0) {
+ int update_only = (flags & MAILBOX_LIST_SUBSCRIBED) != 0;
+ if (!maildir_fill_readdir(ctx, glob, update_only)) {
+ mailbox_tree_deinit(ctx->tree_ctx);
+ pool_unref(pool);
+ return NULL;
+ }
}
- ctx->list_pool = pool_alloconly_create("maildir_list.list", 4096);
- ctx->glob = imap_match_init(pool, mask, TRUE, '.');
- ctx->next = maildir_list_next;
+ ctx->node_path = str_new(pool, 256);
+ ctx->root = mailbox_tree_get(ctx->tree_ctx, NULL, NULL);
return ctx;
}
int maildir_list_mailbox_deinit(struct mailbox_list_context *ctx)
{
- int failed;
-
- if (ctx->subsfile_ctx != NULL)
- failed = !subsfile_list_deinit(ctx->subsfile_ctx);
- else
- failed = ctx->failed;
-
- if (ctx->dirp != NULL)
- (void)closedir(ctx->dirp);
- if (ctx->list_pool != NULL)
- pool_unref(ctx->list_pool);
- imap_match_deinit(ctx->glob);
+ mailbox_tree_deinit(ctx->tree_ctx);
pool_unref(ctx->pool);
-
- return !failed;
+ return TRUE;
}
-static struct mailbox_list *maildir_list_subs(struct mailbox_list_context *ctx)
+static struct mailbox_node *find_next(struct mailbox_node **node,
+ string_t *path)
{
- struct stat st;
- const char *name, *path, *p;
- enum imap_match_result match = IMAP_MATCH_NO;
+ struct mailbox_node *child;
+ size_t len;
- while ((name = subsfile_list_next(ctx->subsfile_ctx)) != NULL) {
- match = imap_match(ctx->glob, name);
- if (match == IMAP_MATCH_YES || match == IMAP_MATCH_PARENT)
- break;
- }
+ while (*node != NULL) {
+ if (((*node)->flags & MAILBOX_FLAG_MATCHED) != 0)
+ return *node;
- if (name == NULL)
- return NULL;
+ if ((*node)->children != NULL) {
+ len = str_len(path);
+ if (len != 0)
+ str_append_c(path, '.');
+ str_append(path, (*node)->name);
- ctx->list.flags = 0;
- ctx->list.name = name;
+ child = find_next(&(*node)->children, path);
+ if (child != NULL)
+ return child;
- if (match == IMAP_MATCH_PARENT) {
- /* placeholder */
- ctx->list.flags = MAILBOX_PLACEHOLDER;
- while ((p = strrchr(name, '.')) != NULL) {
- name = t_strdup_until(name, p);
- if (imap_match(ctx->glob, name) > 0) {
- ctx->list.name = name;
- return &ctx->list;
- }
+ str_truncate(path, len);
}
- i_unreached();
- }
- if ((ctx->flags & MAILBOX_LIST_FAST_FLAGS) != 0)
- return &ctx->list;
-
- t_push();
- path = maildir_get_path(ctx->storage, ctx->list.name);
- if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
- ctx->list.flags = maildir_get_marked_flags(path);
- else {
- if (strcasecmp(ctx->list.name, "INBOX") == 0)
- ctx->list.flags = 0;
- else
- ctx->list.flags = MAILBOX_NONEXISTENT;
+ *node = (*node)->next;
}
- t_pop();
- return &ctx->list;
+
+ return NULL;
}
-static struct mailbox_list *maildir_list_next(struct mailbox_list_context *ctx)
+struct mailbox_list *
+maildir_list_mailbox_next(struct mailbox_list_context *ctx)
{
- struct dirent *d;
- struct stat st;
- const char *fname, *p;
- char path[PATH_MAX];
- enum imap_match_result match;
-
- if (ctx->dirp == NULL)
- return NULL;
-
- while ((d = readdir(ctx->dirp)) != NULL) {
- fname = d->d_name;
+ struct mailbox_node *node;
- if (fname[0] != '.')
- continue;
-
- /* skip . and .. */
- if (fname[1] == '\0' || (fname[1] == '.' && fname[2] == '\0'))
- continue;
-
- /* make sure the mask matches - dirs beginning with ".."
- should be deleted and we always want to check those. */
- t_push();
- match = imap_match(ctx->glob,
- t_strconcat(ctx->prefix, fname+1, NULL));
- t_pop();
- if (fname[1] != '.' && match != IMAP_MATCH_YES &&
- match != IMAP_MATCH_PARENT)
- continue;
-
- if (str_path(path, sizeof(path), ctx->dir, fname) < 0)
- continue;
+ for (node = ctx->next_node; node != NULL; node = node->next) {
+ if ((node->flags & MAILBOX_FLAG_MATCHED) != 0)
+ break;
+ }
- /* make sure it's a directory */
- if (stat(path, &st) < 0) {
- if (errno == ENOENT)
- continue; /* just deleted, ignore */
+ if (node == NULL) {
+ str_truncate(ctx->node_path, 0);
+ node = find_next(&ctx->root, ctx->node_path);
+ ctx->parent_pos = str_len(ctx->node_path);
- mail_storage_set_critical(ctx->storage,
- "stat(%s) failed: %m", path);
- ctx->failed = TRUE;
+ if (node == NULL)
return NULL;
- }
-
- if (!S_ISDIR(st.st_mode))
- continue;
-
- fname++;
- if (*fname == '.') {
- /* this mailbox is in the middle of being deleted,
- or the process trying to delete it had died.
-
- delete it ourself if it's been there longer than
- one hour. don't touch it if it's outside our
- mail root dir. */
- if (st.st_mtime < 3600 && *ctx->prefix == '\0')
- (void)unlink_directory(path, TRUE);
- continue;
- }
-
- if (strcasecmp(fname, "INBOX") == 0)
- continue; /* ignore inboxes */
-
- if (match == IMAP_MATCH_PARENT) {
- ctx->list.flags =
- MAILBOX_PLACEHOLDER | MAILBOX_CHILDREN;
- while ((p = strrchr(fname, '.')) != NULL) {
- fname = t_strdup_until(fname, p);
- p = t_strconcat(ctx->prefix, fname, NULL);
- if (imap_match(ctx->glob, p) > 0) {
- ctx->list.name = p;
- return &ctx->list;
- }
- }
- i_unreached();
- }
-
- p_clear(ctx->list_pool);
- ctx->list.flags = (ctx->flags & MAILBOX_LIST_FAST_FLAGS) == 0 ?
- maildir_get_marked_flags(path) : 0;
- ctx->list.name = p_strconcat(ctx->list_pool,
- ctx->prefix, fname, NULL);
- return &ctx->list;
}
+ ctx->next_node = node->next;
- if (closedir(ctx->dirp) < 0) {
- mail_storage_set_critical(ctx->storage,
- "closedir(%s) failed: %m", ctx->dir);
- ctx->failed = TRUE;
- }
- ctx->dirp = NULL;
+ i_assert((node->flags & MAILBOX_FLAG_MATCHED) != 0);
+ node->flags &= ~MAILBOX_FLAG_MATCHED;
- if (imap_match(ctx->glob, "INBOX") > 0) {
- const char *path = maildir_get_path(ctx->storage, "INBOX");
+ str_truncate(ctx->node_path, ctx->parent_pos);
+ if (ctx->parent_pos != 0)
+ str_append_c(ctx->node_path, '.');
+ str_append(ctx->node_path, node->name);
- ctx->list.flags = (ctx->flags & MAILBOX_LIST_FAST_FLAGS) == 0 ?
- maildir_get_marked_flags(path) : 0;
- ctx->list.name = "INBOX";
- return &ctx->list;
- }
-
- /* we're finished */
- return NULL;
-}
-
-struct mailbox_list *
-maildir_list_mailbox_next(struct mailbox_list_context *ctx)
-{
- return ctx->next(ctx);
+ ctx->list.name = str_c(ctx->node_path);
+ ctx->list.flags = node->flags;
+ return &ctx->list;
}