diff --git a/src/drv_imap.c b/src/drv_imap.c index e12c7cc..adffc38 100644 --- a/src/drv_imap.c +++ b/src/drv_imap.c @@ -2759,23 +2759,35 @@ imap_list_store( store_t *gctx, int flags, imap_cmd_refcounted_state_t *sts = imap_refcounted_new_state( cb, aux ); // ctx->prefix may be empty, "INBOX.", or something else. - // 'flags' may be LIST_INBOX, LIST_PATH (or LIST_PATH_MAYBE), or both. - // This matrix determines what to query, and what comes out as a side effect: + // 'flags' may be LIST_INBOX, LIST_PATH (or LIST_PATH_MAYBE), or both. 'listed' + // already containing a particular value effectively removes it from 'flags'. + // This matrix determines what to query, and what comes out as a side effect. + // The lowercase letters indicate unnecessary results; the queries are done + // this way to have non-overlapping result sets, so subsequent calls create + // no duplicates: // // qry \ pfx | empty | inbox | other // ----------+-------+-------+------- - // inbox | i | i [p] | i - // both | p [i] | i [p] | i + p - // path | p [i] | p {i} | p + // inbox | p [I] | I [p] | I + // both | P [I] | I [P] | I + P + // path | P [i] | i [P] | P // - // {i} => This doesn't actually contain INBOX itself, only its subfolders. - // - if ((flags & (LIST_PATH | LIST_PATH_MAYBE)) && (!(flags & LIST_INBOX) || !is_inbox( ctx, ctx->prefix, -1 ))) + int pfx_is_empty = !*ctx->prefix; + int pfx_is_inbox = !pfx_is_empty && is_inbox( ctx, ctx->prefix, -1 ); + if (((flags & (LIST_PATH | LIST_PATH_MAYBE)) || pfx_is_empty) && !pfx_is_inbox && !(ctx->gen.listed & LIST_PATH)) { + ctx->gen.listed |= LIST_PATH; + if (pfx_is_empty) + ctx->gen.listed |= LIST_INBOX; imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box, "LIST \"\" \"%\\s*\"", ctx->prefix ); - if ((flags & LIST_INBOX) && (!(flags & (LIST_PATH | LIST_PATH_MAYBE)) || *ctx->prefix)) + } + if (((flags & LIST_INBOX) || pfx_is_inbox) && !pfx_is_empty && !(ctx->gen.listed & LIST_INBOX)) { + ctx->gen.listed |= LIST_INBOX; + if (pfx_is_inbox) + ctx->gen.listed |= LIST_PATH; imap_exec( ctx, imap_refcounted_new_cmd( sts ), imap_refcounted_done_box, "LIST \"\" INBOX*" ); + } imap_refcounted_done( sts ); } diff --git a/src/drv_maildir.c b/src/drv_maildir.c index 15b7e2e..d95d522 100644 --- a/src/drv_maildir.c +++ b/src/drv_maildir.c @@ -300,7 +300,11 @@ maildir_list_maildirpp( store_t *gctx, int flags, const char *inbox ) int warned = 0; struct stat st; - add_string_list( &gctx->boxes, "INBOX" ); + if (gctx->listed & LIST_PATH) // Implies LIST_INBOX + return 0; + + if (!(gctx->listed & LIST_INBOX)) + add_string_list( &gctx->boxes, "INBOX" ); char path[_POSIX_PATH_MAX]; int pathLen = nfsnprintf( path, _POSIX_PATH_MAX, "%s/", inbox ); @@ -317,6 +321,8 @@ maildir_list_maildirpp( store_t *gctx, int flags, const char *inbox ) char name[_POSIX_PATH_MAX]; char *effName = name; if (*ent == '.') { + if (gctx->listed & LIST_INBOX) + continue; if (!*++ent) continue; // The Maildir++ Inbox is technically not under Path (as there is none), so @@ -346,6 +352,10 @@ maildir_list_maildirpp( store_t *gctx, int flags, const char *inbox ) } } closedir (dir); + + if (flags & (LIST_PATH | LIST_PATH_MAYBE)) + gctx->listed |= LIST_PATH; + gctx->listed |= LIST_INBOX; return 0; } @@ -384,14 +394,14 @@ maildir_list_recurse( store_t *gctx, int isBox, int flags, continue; pl += pathLen; if (inbox && equals( path, pl, inbox, inboxLen )) { - /* Inbox nested into Path. List now if it won't be listed separately anyway. */ - if (!(flags & LIST_INBOX) && maildir_list_inbox( gctx, flags, 0 ) < 0) { + // Inbox nested into Path. + if (maildir_list_inbox( gctx, flags, 0 ) < 0) { closedir( dir ); return -1; } } else if (basePath && equals( path, pl, basePath, basePathLen )) { - /* Path nested into Inbox. List now if it won't be listed separately anyway. */ - if (!(flags & (LIST_PATH | LIST_PATH_MAYBE)) && maildir_list_path( gctx, flags, 0 ) < 0) { + // Path nested into Inbox. + if (maildir_list_path( gctx, flags, 0 ) < 0) { closedir( dir ); return -1; } @@ -433,6 +443,10 @@ maildir_list_inbox( store_t *gctx, int flags, const char *basePath ) { char path[_POSIX_PATH_MAX], name[_POSIX_PATH_MAX]; + if (gctx->listed & LIST_INBOX) + return 0; + gctx->listed |= LIST_INBOX; + add_string_list( &gctx->boxes, "INBOX" ); return maildir_list_recurse( gctx, 1, flags, 0, 0, basePath, basePath ? strlen( basePath ) - 1 : 0, @@ -445,6 +459,10 @@ maildir_list_path( store_t *gctx, int flags, const char *inbox ) { char path[_POSIX_PATH_MAX], name[_POSIX_PATH_MAX]; + if (gctx->listed & LIST_PATH) + return 0; + gctx->listed |= LIST_PATH; + if (maildir_ensure_path( (maildir_store_conf_t *)gctx->conf ) < 0) return -1; return maildir_list_recurse( diff --git a/src/main.c b/src/main.c index b5a39fb..a85ca22 100644 --- a/src/main.c +++ b/src/main.c @@ -945,7 +945,7 @@ store_connected( int sts, void *aux ) case DRV_CANCELED: return; case DRV_OK: - if (!mvars->skip && !mvars->chanptr->boxlist && mvars->chan->patterns && !mvars->ctx[t]->listed) { + if (!mvars->skip && !mvars->chanptr->boxlist && mvars->chan->patterns) { for (cflags = 0, cpat = mvars->chan->patterns; cpat; cpat = cpat->next) { const char *pat = cpat->string; if (*pat != '!') { @@ -1004,7 +1004,6 @@ store_listed( int sts, void *aux ) case DRV_CANCELED: return; case DRV_OK: - mvars->ctx[t]->listed = 1; if (DFlags & DEBUG_MAIN) { debug( "got mailbox list from %s:\n", str_ms[t] ); for (bx = mvars->ctx[t]->boxes; bx; bx = bx->next)