changeset 1218:a70ebd3a59e2 HEAD

Removed list-sort workarounds. It's pretty much needed for maildir listing. Also added some more complexity and kludging to make everything work correctly.
author Timo Sirainen <tss@iki.fi>
date Thu, 20 Feb 2003 18:41:16 +0200
parents 15c1353d74d9
children e4210f1ea3f1
files dovecot-example.conf src/imap/cmd-list.c src/lib-imap/imap-match.c src/lib-storage/index/maildir/maildir-list.c src/lib-storage/index/mbox/mbox-list.c src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h
diffstat 7 files changed, 91 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/dovecot-example.conf	Thu Feb 20 18:40:16 2003 +0200
+++ b/dovecot-example.conf	Thu Feb 20 18:41:16 2003 +0200
@@ -215,11 +215,6 @@
 #     seems to think they are FETCH replies and gives user "Message no longer
 #     in server" error. Note that OE6 still breaks even with this workaround
 #     if synchronization is set to "Headers Only".
-#   list-sort:
-#     When replying to LIST and LSUB requests, make sure that the parent
-#     mailboxes are sent before any of their children. This is mostly
-#     maildir-specific, mbox list replies are always sorted. MacOS X's Mail.app
-#     at least wants this.
 #   outlook-idle:
 #     Outlook and Outlook Express never abort IDLE command, so if no mail
 #     arrives in half a hour, Dovecot closes the connection. This is still
--- a/src/imap/cmd-list.c	Thu Feb 20 18:40:16 2003 +0200
+++ b/src/imap/cmd-list.c	Thu Feb 20 18:41:16 2003 +0200
@@ -2,6 +2,7 @@
 
 #include "common.h"
 #include "strescape.h"
+#include "imap-match.h"
 #include "commands.h"
 
 struct list_node {
@@ -22,6 +23,9 @@
 {
 	const char *str;
 
+	if (flags == MAILBOX_PLACEHOLDER)
+		flags = MAILBOX_NOSELECT;
+
 	str = t_strconcat((flags & MAILBOX_NOSELECT) ? " \\Noselect" : "",
 			  (flags & MAILBOX_NOINFERIORS) ? " \\NoInferiors" : "",
 			  (flags & MAILBOX_MARKED) ? " \\Marked" : "",
@@ -60,7 +64,7 @@
 			/* not found, create it */
 			*node = p_new(pool, struct list_node, 1);
 			(*node)->name = p_strdup(pool, name);
-			(*node)->flags = MAILBOX_NOSELECT;
+			(*node)->flags = MAILBOX_PLACEHOLDER;
 		}
 
 		t_pop();
@@ -77,9 +81,11 @@
 }
 
 static void list_send(struct client *client, struct list_node *node,
-		      const char *cmd, const char *path, const char *sep)
+		      const char *cmd, const char *path, const char *sep,
+		      struct imap_match_glob *glob)
 {
-	const char *name, *str;
+	const char *name, *send_name, *str;
+	enum imap_match_result match;
 
 	for (; node != NULL; node = node->next) {
 		t_push();
@@ -91,20 +97,63 @@
 			name = "INBOX";
 		else
 			name = node->name;
+		send_name = name;
 
-		/* node->name should already be escaped */
-		str = t_strdup_printf("* %s (%s) \"%s\" \"%s\"", cmd,
-				      mailbox_flags2str(node->flags),
-				      sep, name);
-		client_send_line(client, str);
+		if (node->flags != MAILBOX_PLACEHOLDER)
+			match = IMAP_MATCH_YES;
+		else {
+			/* make sure the placeholder matches. */
+			const char *buf;
+
+			buf = str_unescape(t_strdup_noconst(name));
+			match = imap_match(glob, buf);
+			if (match == IMAP_MATCH_CHILDREN) {
+				send_name = t_strconcat(name, sep, NULL);
+				buf = str_unescape(t_strdup_noconst(send_name));
+				match = imap_match(glob, buf);
+			}
+		}
+
+		if (match == IMAP_MATCH_YES) {
+			/* node->name should already be escaped */
+			str = t_strdup_printf("* %s (%s) \"%s\" \"%s\"", cmd,
+					      mailbox_flags2str(node->flags),
+					      sep, send_name);
+			client_send_line(client, str);
+		}
 
 		if (node->children != NULL)
-			list_send(client, node->children, cmd, name, sep);
+			list_send(client, node->children, cmd, name, sep, glob);
 
 		t_pop();
 	}
 }
 
+static void list_and_sort(struct client *client,
+			  struct mailbox_list_context *ctx,
+			  const char *cmd, const char *sep, const char *mask)
+{
+	struct mailbox_list *list;
+	struct list_node *nodes, *node;
+	struct imap_match_glob *glob;
+	pool_t pool;
+
+	pool = pool_alloconly_create("list_mailboxes", 10240);
+	nodes = NULL;
+
+	while ((list = client->storage->list_mailbox_next(ctx)) != NULL) {
+		node = list_node_get(pool, &nodes, list->name,
+				     client->storage->hierarchy_sep);
+		node->flags |= list->flags;
+	}
+
+	glob = imap_match_init(data_stack_pool, mask, TRUE,
+			       client->storage->hierarchy_sep);
+	list_send(client, nodes, cmd, NULL, sep, glob);
+	imap_match_deinit(glob);
+	pool_unref(pool);
+}
+
 static void list_unsorted(struct client *client,
 			  struct mailbox_list_context *ctx,
 			  const char *cmd, const char *sep)
@@ -126,30 +175,6 @@
 	}
 }
 
-static void list_and_sort(struct client *client,
-			  struct mailbox_list_context *ctx,
-			  const char *cmd, const char *sep)
-{
-	struct mailbox_list *list;
-	struct list_node *nodes, *node;
-	pool_t pool;
-
-	pool = pool_alloconly_create("list_mailboxes", 10240);
-	nodes = NULL;
-
-	while ((list = client->storage->list_mailbox_next(ctx)) != NULL) {
-		node = list_node_get(pool, &nodes, list->name,
-				     client->storage->hierarchy_sep);
-
-		/* set the flags, this also overrides the
-		   NOSELECT flag set by list_node_get() */
-		node->flags = list->flags;
-	}
-
-	list_send(client, nodes, cmd, NULL, sep);
-	pool_unref(pool);
-}
-
 static int list_mailboxes(struct client *client, const char *mask,
 			  int subscribed, const char *sep)
 {
@@ -165,10 +190,10 @@
 		return FALSE;
 
         cmd = subscribed ? "LSUB" : "LIST";
-	if (sorted || (client_workarounds & WORKAROUND_LIST_SORT) == 0)
+	if (sorted)
 		list_unsorted(client, ctx, cmd, sep);
 	else
-		list_and_sort(client, ctx, cmd, sep);
+		list_and_sort(client, ctx, cmd, sep, mask);
 
 	return client->storage->list_mailbox_deinit(ctx);
 }
--- a/src/lib-imap/imap-match.c	Thu Feb 20 18:40:16 2003 +0200
+++ b/src/lib-imap/imap-match.c	Thu Feb 20 18:41:16 2003 +0200
@@ -135,8 +135,10 @@
 				if (ret > 0)
 					break;
 
-				if (ret == IMAP_MATCH_CHILDREN)
-					best_ret = IMAP_MATCH_CHILDREN;
+				if (ret == IMAP_MATCH_CHILDREN ||
+				    (ret == IMAP_MATCH_PARENT &&
+				     best_ret == IMAP_MATCH_NO))
+					best_ret = ret;
 			}
 
 			if (*data == glob->sep_char)
--- a/src/lib-storage/index/maildir/maildir-list.c	Thu Feb 20 18:40:16 2003 +0200
+++ b/src/lib-storage/index/maildir/maildir-list.c	Thu Feb 20 18:41:16 2003 +0200
@@ -152,7 +152,7 @@
 
 	if (match == IMAP_MATCH_PARENT) {
 		/* placeholder */
-		ctx->list.flags = MAILBOX_NOSELECT;
+		ctx->list.flags = MAILBOX_PLACEHOLDER;
 		while ((p = strrchr(name, '.')) != NULL) {
 			name = t_strdup_until(name, p);
 			if (imap_match(ctx->glob, name) > 0) {
@@ -181,14 +181,15 @@
 {
 	struct dirent *d;
 	struct stat st;
+	const char *fname, *p;
 	char path[PATH_MAX];
-	int ret;
+	enum imap_match_result match;
 
 	if (ctx->dirp == NULL)
 		return NULL;
 
 	while ((d = readdir(ctx->dirp)) != NULL) {
-		const char *fname = d->d_name;
+		fname = d->d_name;
 
 		if (fname[0] != '.')
 			continue;
@@ -200,10 +201,11 @@
 		/* make sure the mask matches - dirs beginning with ".."
 		   should be deleted and we always want to check those. */
 		t_push();
-		ret = imap_match(ctx->glob,
-				 t_strconcat(ctx->prefix, fname+1, NULL));
+		match = imap_match(ctx->glob,
+				   t_strconcat(ctx->prefix, fname+1, NULL));
 		t_pop();
-		if (fname[1] == '.' || ret <= 0)
+		if (fname[1] != '.' && match != IMAP_MATCH_YES &&
+		    match != IMAP_MATCH_PARENT)
 			continue;
 
 		if (str_path(path, sizeof(path), ctx->dir, fname) < 0)
@@ -223,7 +225,8 @@
 		if (!S_ISDIR(st.st_mode))
 			continue;
 
-		if (fname[1] == '.') {
+		fname++;
+		if (*fname == '.') {
 			/* this mailbox is in the middle of being deleted,
 			   or the process trying to delete it had died.
 
@@ -234,14 +237,26 @@
 			continue;
 		}
 
-		if (strcasecmp(fname+1, "INBOX") == 0)
+		if (strcasecmp(fname, "INBOX") == 0)
 			continue; /* ignore inboxes */
 
+		if (match == IMAP_MATCH_PARENT) {
+			ctx->list.flags = MAILBOX_PLACEHOLDER;
+			while ((p = strrchr(fname, '.')) != NULL) {
+				fname = t_strdup_until(fname, p);
+				if (imap_match(ctx->glob, fname) > 0) {
+					ctx->list.name = fname;
+					return &ctx->list;
+				}
+			}
+			i_unreached();
+		}
+
 		p_clear(ctx->list_pool);
 		if ((ctx->flags & MAILBOX_LIST_NO_FLAGS) == 0)
 			ctx->list.flags = maildir_get_marked_flags(path);
 		ctx->list.name = p_strconcat(ctx->list_pool,
-					     ctx->prefix, fname+1, NULL);
+					     ctx->prefix, fname, NULL);
 		return &ctx->list;
 	}
 
--- a/src/lib-storage/index/mbox/mbox-list.c	Thu Feb 20 18:40:16 2003 +0200
+++ b/src/lib-storage/index/mbox/mbox-list.c	Thu Feb 20 18:41:16 2003 +0200
@@ -291,7 +291,7 @@
 
 	if (match == IMAP_MATCH_PARENT) {
 		/* placeholder */
-		ctx->list.flags = MAILBOX_NOSELECT;
+		ctx->list.flags = MAILBOX_PLACEHOLDER;
 		while ((p = strrchr(name, '/')) != NULL) {
 			name = t_strdup_until(name, p);
 			if (imap_match(ctx->glob, name) > 0) {
--- a/src/lib-storage/mail-storage.c	Thu Feb 20 18:40:16 2003 +0200
+++ b/src/lib-storage/mail-storage.c	Thu Feb 20 18:41:16 2003 +0200
@@ -23,7 +23,6 @@
 
 struct client_workaround_list client_workaround_list[] = {
 	{ "oe6-fetch-no-newmail", WORKAROUND_OE6_FETCH_NO_NEWMAIL },
-	{ "list-sort", WORKAROUND_LIST_SORT },
 	{ "outlook-idle", WORKAROUND_OUTLOOK_IDLE },
 	{ NULL, 0 }
 };
--- a/src/lib-storage/mail-storage.h	Thu Feb 20 18:40:16 2003 +0200
+++ b/src/lib-storage/mail-storage.h	Thu Feb 20 18:41:16 2003 +0200
@@ -17,6 +17,7 @@
 	MAILBOX_NOINFERIORS	= 0x08,
 	MAILBOX_MARKED		= 0x10,
 	MAILBOX_UNMARKED	= 0x20,
+	MAILBOX_PLACEHOLDER	= 0x40,
 
 	MAILBOX_READONLY	= 0x40
 };
@@ -92,8 +93,7 @@
 
 enum client_workarounds {
 	WORKAROUND_OE6_FETCH_NO_NEWMAIL	= 0x01,
-	WORKAROUND_LIST_SORT		= 0x02,
-	WORKAROUND_OUTLOOK_IDLE		= 0x04
+	WORKAROUND_OUTLOOK_IDLE		= 0x02
 };
 
 struct mail_full_flags {