# HG changeset patch # User Timo Sirainen # Date 1192910334 -10800 # Node ID c901bdf0db75e4c33efa2b59467c506b0780aa42 # Parent 79836b3474f49c91340be68a12708edb0be7f604 Fixes for listing namespaces with prefixes and real != virtual separator. diff -r 79836b3474f4 -r c901bdf0db75 src/imap/cmd-list.c --- a/src/imap/cmd-list.c Sat Oct 20 22:23:14 2007 +0300 +++ b/src/imap/cmd-list.c Sat Oct 20 22:58:54 2007 +0300 @@ -516,6 +516,7 @@ struct mail_namespace *ns = ctx->ns; struct imap_match_glob *pat_glob; enum imap_match_result match; + const char *p; size_t len; skip_namespace_prefix_pattern(ctx, &cur_ns_prefix, @@ -547,15 +548,22 @@ pat_glob = imap_match_init(pool_datastack_create(), orig_cur_pattern, inboxcase, ns->sep); match = imap_match(pat_glob, cur_ns_prefix); - if ((match & (IMAP_MATCH_YES | IMAP_MATCH_CHILDREN)) == 0) - return FALSE; + if (match == IMAP_MATCH_YES) { + if ((ns->flags & NAMESPACE_FLAG_LIST) != 0 && + (ctx->list_flags & + MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) { + /* the namespace prefix itself matches too. send it. */ + ctx->cur_ns_send_prefix = TRUE; + } + /* if the pattern contains '*' characters, we'll need to + check our children too */ + for (p = orig_cur_pattern; *p != '\0'; p++) { + if (*p == '*') + return TRUE; + } + } - if (match == IMAP_MATCH_YES && (ns->flags & NAMESPACE_FLAG_LIST) != 0 && - (ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) { - /* the namespace prefix itself matches too. send it. */ - ctx->cur_ns_send_prefix = TRUE; - } - return TRUE; + return (match & IMAP_MATCH_CHILDREN) != 0; } static void list_namespace_init(struct cmd_list_context *ctx) @@ -598,13 +606,18 @@ if (list_namespace_match_pattern(ctx, inboxcase, cur_ref, cur_ns_prefix, pattern)) { pattern = mailbox_list_join_refpattern(ns->list, - ctx->ref, mail_namespace_fix_sep(ns, pattern)); + ctx->ref, pattern); array_append(&used_patterns, &pattern, 1); } } - if (array_count(&used_patterns) == 0) + if (array_count(&used_patterns) == 0) { + /* it's possible that the namespace prefix matched, + even though its children didn't */ + if (ctx->cur_ns_send_prefix) + list_namespace_send_prefix(ctx, TRUE); return; + } (void)array_append_space(&used_patterns); /* NULL-terminate */ pat = array_idx(&used_patterns, 0); diff -r 79836b3474f4 -r c901bdf0db75 src/lib-storage/list/mailbox-list-fs-iter.c --- a/src/lib-storage/list/mailbox-list-fs-iter.c Sat Oct 20 22:23:14 2007 +0300 +++ b/src/lib-storage/list/mailbox-list-fs-iter.c Sat Oct 20 22:58:54 2007 +0300 @@ -49,19 +49,20 @@ static const struct mailbox_info * fs_list_next(struct fs_list_iterate_context *ctx); -static int pattern_get_path_pos(const char *pattern, const char *path, - unsigned int *pos_r) +static int +pattern_get_path_pos(struct mail_namespace *ns, const char *pattern, + const char *path, unsigned int *pos_r) { unsigned int i, j; - if (strncasecmp(path, "INBOX/", 6) == 0) { + if (strncasecmp(path, "INBOX", 5) == 0 && path[5] == ns->sep) { /* make sure INBOX prefix is matched case-insensitively */ char *tmp = t_strdup_noconst(pattern); - if (strncmp(path, "INBOX/", 6) != 0) - path = t_strconcat("INBOX/", path + 6, NULL); + if (strncmp(path, "INBOX", 5) != 0) + path = t_strdup_printf("INBOX%c%s", ns->sep, path + 6); - for (i = 0; tmp[i] != '/' && tmp[i] != '\0'; i++) + for (i = 0; tmp[i] != ns->sep && tmp[i] != '\0'; i++) tmp[i] = i_toupper(tmp[i]); pattern = tmp; } @@ -72,13 +73,13 @@ if (pattern[j] == '%') { /* skip until we're at the next hierarchy separator */ - if (path[i] == '/') { + if (path[i] == ns->sep) { /* assume that pattern matches. we can't be sure, but it'll be checked later. */ for (j++; pattern[j] != '\0'; j++) { if (pattern[j] == '*') return -1; - if (pattern[j] == '/') { + if (pattern[j] == ns->sep) { j++; break; } @@ -96,17 +97,19 @@ return 1; } -static bool pattern_has_wildcard_at(const char *pattern, const char *path) +static bool +pattern_has_wildcard_at(struct mail_namespace *ns, const char *pattern, + const char *path) { unsigned int pos; int ret; - if ((ret = pattern_get_path_pos(pattern, path, &pos)) < 0) + if ((ret = pattern_get_path_pos(ns, pattern, path, &pos)) < 0) return TRUE; if (ret == 0) return FALSE; - for (; pattern[pos] != '\0' && pattern[pos] != '/'; pos++) { + for (; pattern[pos] != '\0' && pattern[pos] != ns->sep; pos++) { if (pattern[pos] == '%' || pattern[pos] == '*') return TRUE; } @@ -125,7 +128,8 @@ t_push(); patterns = array_idx(&ctx->valid_patterns, 0); for (i = 0; patterns[i] != NULL; i++) { - if (pattern_has_wildcard_at(patterns[i], list_path)) + if (pattern_has_wildcard_at(ctx->ctx.list->ns, + patterns[i], list_path)) break; } t_pop(); @@ -190,13 +194,14 @@ return &ctx->ctx; } patterns = (const void *)array_idx(&ctx->valid_patterns, 0); - ctx->glob = imap_match_init_multiple(default_pool, patterns, TRUE, '/'); + ctx->glob = imap_match_init_multiple(default_pool, patterns, TRUE, + _list->ns->sep); if ((flags & (MAILBOX_LIST_ITER_SELECT_SUBSCRIBED | MAILBOX_LIST_ITER_RETURN_SUBSCRIBED)) != 0) { /* we want to return MAILBOX_SUBSCRIBED flags, possibly for all mailboxes. Build a mailbox tree of all the subscriptions. */ - ctx->subs_tree = mailbox_tree_init('/'); + ctx->subs_tree = mailbox_tree_init(_list->ns->sep); if (mailbox_list_subscriptions_fill(&ctx->ctx, ctx->subs_tree, ctx->glob, FALSE) < 0) { @@ -334,6 +339,7 @@ static int list_file(struct fs_list_iterate_context *ctx, const struct dirent *d) { + struct mail_namespace *ns = ctx->ctx.list->ns; const char *fname = d->d_name; struct list_dir_context *dir; const char *list_path, *real_path, *vpath, *inbox_path; @@ -366,7 +372,7 @@ /* make sure we give only one correct INBOX */ real_path = t_strconcat(ctx->dir->real_path, "/", fname, NULL); - if ((ctx->ctx.list->ns->flags & NAMESPACE_FLAG_INBOX) != 0 && + if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0 && strcasecmp(list_path, "INBOX") == 0) { if (ctx->inbox_listed) { /* already listed the INBOX */ @@ -405,7 +411,7 @@ if ((ctx->info.flags & MAILBOX_NOINFERIORS) == 0) { /* subdirectory. scan inside it. */ - vpath = t_strconcat(list_path, "/", NULL); + vpath = t_strdup_printf("%s%c", list_path, ns->sep); match2 = imap_match(ctx->glob, vpath); if (match == IMAP_MATCH_YES) @@ -421,7 +427,8 @@ dir = i_new(struct list_dir_context, 1); dir->dirp = dirp; dir->real_path = i_strdup(real_path); - dir->virtual_path = i_strconcat(list_path, "/", NULL); + dir->virtual_path = + i_strdup_printf("%s%c", list_path, ns->sep); dir->prev = ctx->dir; ctx->dir = dir; @@ -473,6 +480,7 @@ static struct dirent *fs_list_dir_next(struct fs_list_iterate_context *ctx) { struct list_dir_context *dir = ctx->dir; + struct mail_namespace *ns = ctx->ctx.list->ns; char *const *patterns; const char *fname, *path, *p; unsigned int pos; @@ -493,13 +501,14 @@ patterns += dir->pattern_pos; dir->pattern_pos++; - ret = pattern_get_path_pos(*patterns, dir->virtual_path, &pos); + ret = pattern_get_path_pos(ns, *patterns, dir->virtual_path, + &pos); if (ret == 0) continue; i_assert(ret > 0); /* get the filename from the pattern */ - p = strchr(*patterns + pos, '/'); + p = strchr(*patterns + pos, ns->sep); fname = p == NULL ? *patterns + pos : t_strdup_until(*patterns + pos, p); diff -r 79836b3474f4 -r c901bdf0db75 src/lib-storage/list/mailbox-list-maildir-iter.c --- a/src/lib-storage/list/mailbox-list-maildir-iter.c Sat Oct 20 22:23:14 2007 +0300 +++ b/src/lib-storage/list/mailbox-list-maildir-iter.c Sat Oct 20 22:58:54 2007 +0300 @@ -45,31 +45,39 @@ const char *p; char hierarchy_sep; bool created; + const char *ns_prefix = ctx->ctx.list->ns->prefix; + unsigned int ns_prefix_len = strlen(ns_prefix); - hierarchy_sep = ctx->ctx.list->hierarchy_sep; + hierarchy_sep = ctx->ctx.list->ns->sep; t_push(); while ((p = strrchr(mailbox_c, hierarchy_sep)) != NULL) { str_truncate(mailbox, (size_t) (p-mailbox_c)); mailbox_c = str_c(mailbox); - if (imap_match(glob, mailbox_c) == IMAP_MATCH_YES) { - created = FALSE; - node = update_only ? - mailbox_tree_lookup(ctx->tree_ctx, mailbox_c) : - mailbox_tree_get(ctx->tree_ctx, - mailbox_c, &created); - if (node != NULL) { - if (created) { - /* we haven't yet seen this mailbox, - but we might see it later */ - node->flags = MAILBOX_NONEXISTENT; - } - if (!update_only) - node->flags |= MAILBOX_MATCHED; - node->flags |= MAILBOX_CHILDREN | flags; - node->flags &= ~MAILBOX_NOCHILDREN; - node_fix_parents(node); + if (imap_match(glob, mailbox_c) != IMAP_MATCH_YES) + continue; + + if (*ns_prefix != '\0' && + strncmp(mailbox_c, ns_prefix, ns_prefix_len - 1) == 0) { + /* don't return matches to namespace prefix itself */ + continue; + } + + created = FALSE; + node = update_only ? + mailbox_tree_lookup(ctx->tree_ctx, mailbox_c) : + mailbox_tree_get(ctx->tree_ctx, mailbox_c, &created); + if (node != NULL) { + if (created) { + /* we haven't yet seen this mailbox, + but we might see it later */ + node->flags = MAILBOX_NONEXISTENT; } + if (!update_only) + node->flags |= MAILBOX_MATCHED; + node->flags |= MAILBOX_CHILDREN | flags; + node->flags &= ~MAILBOX_NOCHILDREN; + node_fix_parents(node); } } t_pop(); @@ -79,15 +87,18 @@ maildir_fill_readdir(struct maildir_list_iterate_context *ctx, struct imap_match_glob *glob, bool update_only) { + struct mail_namespace *ns = ctx->ctx.list->ns; DIR *dirp; struct dirent *d; - const char *mailbox_name, *mailbox_c; + const char *mailbox_name; + char *mailbox_c; string_t *mailbox; enum mailbox_info_flags flags; enum imap_match_result match; struct mailbox_node *node; bool created; char prefix_char; + unsigned int pos; int ret; dirp = opendir(ctx->dir); @@ -124,11 +135,18 @@ /* make sure the pattern matches */ str_truncate(mailbox, 0); - if ((ctx->ctx.list->ns->flags & NAMESPACE_FLAG_INBOX) == 0 || + if ((ns->flags & NAMESPACE_FLAG_INBOX) == 0 || strcasecmp(mailbox_name, "INBOX") != 0) - str_append(mailbox, ctx->ctx.list->ns->prefix); + str_append(mailbox, ns->prefix); + + pos = str_len(mailbox); str_append(mailbox, mailbox_name); - mailbox_c = str_c(mailbox); + mailbox_c = str_c_modifiable(mailbox); + while (mailbox_c[pos] != '\0') { + if (mailbox_c[pos] == ns->real_sep) + mailbox_c[pos] = ns->sep; + pos++; + } match = imap_match(glob, mailbox_c); if ((match & (IMAP_MATCH_YES | IMAP_MATCH_PARENT)) == 0) @@ -181,7 +199,7 @@ return -1; } - if ((ctx->ctx.list->ns->flags & NAMESPACE_FLAG_INBOX) != 0) { + if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0) { /* make sure INBOX is there */ created = FALSE; node = update_only ? @@ -198,15 +216,14 @@ node->flags |= MAILBOX_MATCHED; } } else if (mailbox_tree_lookup(ctx->tree_ctx, "INBOX") == NULL && - imap_match(glob, "INBOX")) { + imap_match(glob, "INBOX") == IMAP_MATCH_YES) { /* see if INBOX exists. */ ret = ctx->ctx.list->v. iter_is_mailbox(&ctx->ctx, ctx->dir, "", MAILBOX_LIST_FILE_TYPE_UNKNOWN, &flags); if (ret > 0) { - mailbox_c = t_strconcat(ctx->ctx.list->ns->prefix, - "INBOX", NULL); - node = mailbox_tree_get(ctx->tree_ctx, mailbox_c, NULL); + node = mailbox_tree_get(ctx->tree_ctx, + t_strconcat(ns->prefix, "INBOX", NULL), NULL); node->flags = MAILBOX_NOCHILDREN | MAILBOX_MATCHED; } } @@ -226,10 +243,9 @@ ctx->ctx.list = _list; ctx->ctx.flags = flags; ctx->pool = pool; - ctx->tree_ctx = mailbox_tree_init(_list->hierarchy_sep); + ctx->tree_ctx = mailbox_tree_init(_list->ns->sep); - glob = imap_match_init_multiple(pool, patterns, TRUE, - _list->hierarchy_sep); + glob = imap_match_init_multiple(pool, patterns, TRUE, _list->ns->sep); ctx->dir = _list->set.root_dir;