[dovecot-cvs] dovecot/src/lib-storage/index/maildir maildir-list.c,1.12,1.13 maildir-storage.c,1.27,1.28 maildir-storage.h,1.12,1.13
cras at procontrol.fi
cras at procontrol.fi
Wed Feb 19 21:55:29 EET 2003
Update of /home/cvs/dovecot/src/lib-storage/index/maildir
In directory danu:/tmp/cvs-serv21976/src/lib-storage/index/maildir
Modified Files:
maildir-list.c maildir-storage.c maildir-storage.h
Log Message:
Rewrote LIST, LSUB and subscription file handling. LIST replies aren't
sorted anymore by default, it can be enabled with client_workarounds =
list-sort.
Index: maildir-list.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/maildir/maildir-list.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- maildir-list.c 12 Feb 2003 18:16:57 -0000 1.12
+++ maildir-list.c 19 Feb 2003 19:55:27 -0000 1.13
@@ -12,11 +12,26 @@
#include <dirent.h>
#include <sys/stat.h>
-struct find_subscribed_context {
- mailbox_list_callback_t *callback;
- void *context;
+struct mailbox_list_context {
+ pool_t pool, list_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_list list;
+ int found_inbox, 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 enum mailbox_flags
maildir_get_marked_flags_from(const char *dir, time_t index_stamp)
{
@@ -72,50 +87,147 @@
return maildir_get_marked_flags_from(dir, st.st_mtime);
}
-int maildir_find_mailboxes(struct mail_storage *storage, const char *mask,
- mailbox_list_callback_t callback, void *context)
+struct mailbox_list_context *
+maildir_list_mailbox_init(struct mail_storage *storage,
+ const char *mask, enum mailbox_list_flags flags,
+ int *sorted)
{
- struct imap_match_glob *glob;
- DIR *dirp;
- struct dirent *d;
- struct stat st;
- enum mailbox_flags flags;
- const char *dir, *prefix, *p;
- char path[PATH_MAX];
- int failed, found_inbox, ret;
+ struct mailbox_list_context *ctx;
+ pool_t pool;
+ const char *dir, *p;
+ *sorted = FALSE;
mail_storage_clear_error(storage);
+ pool = pool_alloconly_create("maildir_list", 1024);
+ ctx = p_new(pool, struct mailbox_list_context, 1);
+ ctx->pool = pool;
+ ctx->storage = storage;
+ ctx->flags = flags;
+
+ 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) {
+ pool_unref(pool);
+ return NULL;
+ }
+ return ctx;
+ }
+
if (!full_filesystem_access || (p = strrchr(mask, '/')) == NULL) {
- dir = storage->dir;
- prefix = "";
+ ctx->dir = storage->dir;
+ ctx->prefix = "";
} else {
p = strchr(p, storage->hierarchy_sep);
if (p == NULL) {
/* this isn't going to work */
mail_storage_set_error(storage, "Invalid list mask");
+ pool_unref(pool);
return FALSE;
}
dir = t_strdup_until(mask, p);
- prefix = t_strdup_until(mask, p+1);
+ ctx->prefix = t_strdup_until(mask, p+1);
if (*mask != '/' && *mask != '~')
dir = t_strconcat(storage->dir, "/", dir, NULL);
- dir = home_expand(dir);
+ ctx->dir = p_strdup(pool, home_expand(dir));
}
- dirp = opendir(dir);
- if (dirp == NULL) {
+ ctx->dirp = opendir(ctx->dir);
+ if (ctx->dirp == NULL) {
mail_storage_set_critical(storage, "opendir(%s) failed: %m",
- dir);
- return FALSE;
+ ctx->dir);
+ pool_unref(pool);
+ return NULL;
}
- glob = imap_match_init(mask, TRUE, '.');
+ ctx->list_pool = pool_alloconly_create("maildir_list.list", 4096);
+ ctx->glob = imap_match_init(pool, mask, TRUE, '.');
+ ctx->next = maildir_list_next;
+ return ctx;
+}
- failed = found_inbox = FALSE;
- while ((d = readdir(dirp)) != NULL) {
+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);
+ pool_unref(ctx->pool);
+
+ return !failed;
+}
+
+static struct mailbox_list *maildir_list_subs(struct mailbox_list_context *ctx)
+{
+ struct stat st;
+ const char *name, *path, *p;
+ enum imap_match_result match = IMAP_MATCH_NO;
+
+ 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;
+ }
+
+ if (name == NULL)
+ return NULL;
+
+ ctx->list.flags = 0;
+ ctx->list.name = name;
+
+ if ((ctx->flags & MAILBOX_LIST_NO_FLAGS) != 0)
+ return &ctx->list;
+
+ if (match == IMAP_MATCH_PARENT) {
+ /* placeholder */
+ ctx->list.flags = MAILBOX_NOSELECT;
+ 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;
+ }
+ }
+ i_unreached();
+ }
+
+ 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(ctx->storage, path);
+ else {
+ if (strcasecmp(ctx->list.name, "INBOX") == 0)
+ ctx->list.flags = 0;
+ else
+ ctx->list.flags = MAILBOX_NOSELECT;
+ }
+ t_pop();
+ return &ctx->list;
+}
+
+static struct mailbox_list *maildir_list_next(struct mailbox_list_context *ctx)
+{
+ struct dirent *d;
+ struct stat st;
+ char path[PATH_MAX];
+ int ret;
+
+ if (ctx->dirp == NULL)
+ return NULL;
+
+ while ((d = readdir(ctx->dirp)) != NULL) {
const char *fname = d->d_name;
if (fname[0] != '.')
@@ -128,23 +240,24 @@
/* make sure the mask matches - dirs beginning with ".."
should be deleted and we always want to check those. */
t_push();
- ret = imap_match(glob, t_strconcat(prefix, fname+1, NULL));
+ ret = imap_match(ctx->glob,
+ t_strconcat(ctx->prefix, fname+1, NULL));
t_pop();
if (fname[1] == '.' || ret <= 0)
continue;
- if (str_path(path, sizeof(path), dir, fname) < 0)
+ if (str_path(path, sizeof(path), ctx->dir, fname) < 0)
continue;
/* make sure it's a directory */
- if (stat(path, &st) != 0) {
+ if (stat(path, &st) < 0) {
if (errno == ENOENT)
continue; /* just deleted, ignore */
- mail_storage_set_critical(storage,
+ mail_storage_set_critical(ctx->storage,
"stat(%s) failed: %m", path);
- failed = TRUE;
- break;
+ ctx->failed = TRUE;
+ return NULL;
}
if (!S_ISDIR(st.st_mode))
@@ -162,60 +275,43 @@
}
if (strcasecmp(fname+1, "INBOX") == 0) {
- if (found_inbox) {
+ if (ctx->found_inbox) {
/* another inbox, ignore it */
continue;
}
- found_inbox = TRUE;
+ ctx->found_inbox = TRUE;
}
- t_push();
- flags = maildir_get_marked_flags(storage, path);
- callback(storage, t_strconcat(prefix, fname+1, NULL),
- flags, context);
- t_pop();
+ p_clear(ctx->list_pool);
+ if ((ctx->flags & MAILBOX_LIST_NO_FLAGS) == 0) {
+ ctx->list.flags =
+ maildir_get_marked_flags(ctx->storage, path);
+ }
+ ctx->list.name = p_strconcat(ctx->list_pool,
+ ctx->prefix, fname+1, NULL);
+ return &ctx->list;
}
- if (!failed && !found_inbox && imap_match(glob, "INBOX") > 0) {
- /* .INBOX directory doesn't exist yet, but INBOX still exists */
- callback(storage, "INBOX", 0, context);
+ if (closedir(ctx->dirp) < 0) {
+ mail_storage_set_critical(ctx->storage,
+ "closedir(%s) failed: %m", ctx->dir);
+ ctx->failed = TRUE;
}
+ ctx->dirp = NULL;
- (void)closedir(dirp);
- return !failed;
-}
-
-static int maildir_subs_cb(struct mail_storage *storage, const char *name,
- void *context)
-{
- struct find_subscribed_context *ctx = context;
- enum mailbox_flags flags;
- struct stat st;
- char path[PATH_MAX];
-
- if (str_ppath(path, sizeof(path), storage->dir, ".", name) < 0)
- flags = MAILBOX_NOSELECT;
- else {
- if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
- flags = maildir_get_marked_flags(storage, path);
- else
- flags = MAILBOX_NOSELECT;
+ if (!ctx->found_inbox && imap_match(ctx->glob, "INBOX") > 0) {
+ /* .INBOX directory doesn't exist yet, but INBOX still exists */
+ ctx->list.flags = 0;
+ ctx->list.name = "INBOX";
+ return &ctx->list;
}
- ctx->callback(storage, name, flags, ctx->context);
- return TRUE;
+ /* we're finished */
+ return NULL;
}
-int maildir_find_subscribed(struct mail_storage *storage, const char *mask,
- mailbox_list_callback_t callback, void *context)
+struct mailbox_list *
+maildir_list_mailbox_next(struct mailbox_list_context *ctx)
{
- struct find_subscribed_context ctx;
-
- ctx.callback = callback;
- ctx.context = context;
-
- if (subsfile_foreach(storage, mask, maildir_subs_cb, &ctx) <= 0)
- return FALSE;
-
- return TRUE;
+ return ctx->next(ctx);
}
Index: maildir-storage.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/maildir/maildir-storage.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- maildir-storage.c 17 Feb 2003 19:09:43 -0000 1.27
+++ maildir-storage.c 19 Feb 2003 19:55:27 -0000 1.28
@@ -120,8 +120,7 @@
return t_strconcat(t_strdup_until(name, p), "/", p, NULL);
}
-static const char *maildir_get_path(struct mail_storage *storage,
- const char *name)
+const char *maildir_get_path(struct mail_storage *storage, const char *name)
{
if (full_filesystem_access && (*name == '/' || *name == '~'))
return maildir_get_absolute_path(name);
@@ -431,43 +430,63 @@
return TRUE;
}
-static void rename_subfolder(struct mail_storage *storage, const char *name,
- enum mailbox_flags flags __attr_unused__,
- void *context)
+static int rename_subfolders(struct mail_storage *storage,
+ const char *oldname, const char *newname)
{
- struct rename_context *ctx = context;
- const char *newname, *oldpath, *newpath;
+ struct mailbox_list_context *ctx;
+ struct mailbox_list *list;
+ const char *oldpath, *newpath, *new_listname;
+ size_t oldnamelen;
+ int sorted, ret;
- i_assert(ctx->oldnamelen <= strlen(name));
+ ret = 0;
+ oldnamelen = strlen(oldname);
- newname = t_strconcat(ctx->newname, ".", name + ctx->oldnamelen, NULL);
+ ctx = storage->list_mailbox_init(storage,
+ t_strconcat(oldname, ".*", NULL),
+ MAILBOX_LIST_NO_FLAGS, &sorted);
+ while ((list = maildir_list_mailbox_next(ctx)) != NULL) {
+ i_assert(oldnamelen <= strlen(list->name));
- oldpath = maildir_get_path(storage, name);
- newpath = maildir_get_path(storage, newname);
+ t_push();
+ new_listname = t_strconcat(newname, ".",
+ list->name + oldnamelen, NULL);
+ oldpath = maildir_get_path(storage, list->name);
+ newpath = maildir_get_path(storage, new_listname);
- /* FIXME: it's possible to merge two folders if either one of them
- doesn't have existing root folder. We could check this but I'm not
- sure if it's worth it. It could be even considered as a feature.
+ /* FIXME: it's possible to merge two folders if either one of
+ them doesn't have existing root folder. We could check this
+ but I'm not sure if it's worth it. It could be even
+ considered as a feature.
- Anyway, the bug with merging is that if both folders have
- identically named subfolder they conflict. Just ignore those and
- leave them under the old folder. */
- if (rename(oldpath, newpath) == 0 || errno == EEXIST)
- ctx->found = TRUE;
- else {
- mail_storage_set_critical(storage, "rename(%s, %s) failed: %m",
- oldpath, newpath);
+ Anyway, the bug with merging is that if both folders have
+ identically named subfolder they conflict. Just ignore those
+ and leave them under the old folder. */
+ if (rename(oldpath, newpath) == 0 ||
+ errno == EEXIST || errno == ENOTEMPTY)
+ ret = 1;
+ else {
+ mail_storage_set_critical(storage, "rename(%s, %s) failed: %m",
+ oldpath, newpath);
+ ret = -1;
+ t_pop();
+ break;
+ }
+
+ (void)rename_indexes(storage, list->name, new_listname);
+ t_pop();
}
- (void)rename_indexes(storage, name, newname);
+ if (!maildir_list_mailbox_deinit(ctx))
+ return -1;
+ return ret;
}
static int maildir_rename_mailbox(struct mail_storage *storage,
const char *oldname, const char *newname)
{
- struct rename_context ctx;
const char *oldpath, *newpath;
- int ret;
+ int ret, found;
mail_storage_clear_error(storage);
@@ -495,19 +514,16 @@
if (!rename_indexes(storage, oldname, newname))
return FALSE;
- ctx.found = ret == 0;
- ctx.oldnamelen = strlen(oldname)+1;
- ctx.newname = newname;
- if (!maildir_find_mailboxes(storage,
- t_strconcat(oldname, ".*", NULL),
- rename_subfolder, &ctx))
+ found = ret == 0;
+ ret = rename_subfolders(storage, oldname, newname);
+ if (ret < 0)
return FALSE;
-
- if (!ctx.found) {
+ if (!found && ret == 0) {
mail_storage_set_error(storage,
"Mailbox doesn't exist");
return FALSE;
}
+
return TRUE;
}
@@ -581,9 +597,10 @@
maildir_create_mailbox,
maildir_delete_mailbox,
maildir_rename_mailbox,
- maildir_find_mailboxes,
+ maildir_list_mailbox_init,
+ maildir_list_mailbox_deinit,
+ maildir_list_mailbox_next,
subsfile_set_subscribed,
- maildir_find_subscribed,
maildir_get_mailbox_name_status,
mail_storage_get_last_error,
Index: maildir-storage.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/maildir/maildir-storage.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- maildir-storage.h 22 Jan 2003 19:23:28 -0000 1.12
+++ maildir-storage.h 19 Feb 2003 19:55:27 -0000 1.13
@@ -14,14 +14,19 @@
time_t received_date, int timezone_offset,
struct istream *data);
-int maildir_find_mailboxes(struct mail_storage *storage, const char *mask,
- mailbox_list_callback_t callback, void *context);
-int maildir_find_subscribed(struct mail_storage *storage, const char *mask,
- mailbox_list_callback_t callback, void *context);
+struct mailbox_list_context *
+maildir_list_mailbox_init(struct mail_storage *storage,
+ const char *mask, enum mailbox_list_flags flags,
+ int *sorted);
+int maildir_list_mailbox_deinit(struct mailbox_list_context *ctx);
+struct mailbox_list *
+maildir_list_mailbox_next(struct mailbox_list_context *ctx);
int maildir_expunge_locked(struct index_mailbox *ibox, int notify);
/* Return new filename base to save into tmp/ */
const char *maildir_generate_tmp_filename(void);
+
+const char *maildir_get_path(struct mail_storage *storage, const char *name);
#endif
More information about the dovecot-cvs
mailing list