/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "hash.h"
#include "imap-match.h"
#include "mail-storage.h"
#include "mailbox-tree.h"
#include "mailbox-list-subscriptions.h"
#include "mailbox-list-private.h"
#include "mailbox-list-iter-private.h"
enum autocreate_match_result {
/* list contains the mailbox */
/* list contains children of the mailbox */
/* list contains parents of the mailbox */
};
struct ns_list_iterate_context {
};
struct mail_namespace *ns,
const char *prefix);
struct mailbox_list_iterate_context *
enum mailbox_list_iter_flags flags)
{
}
{
/* no subscriptions in this namespace. find where they are. */
/* no subscriptions. avoid crashes by initializing
a subscriptions tree. */
}
return 0;
}
}
}
static struct mailbox_settings *
struct mailbox_settings *in_set)
{
return in_set;
/* namespace prefix itself */
} else {
}
return out_set;
}
static void
{
unsigned int i, count;
return;
if (count == 0)
return;
/* build the list of mailboxes we need to consider as existing */
for (i = 0; i < count; i++) {
continue;
/* autocreate mailbox belongs to listed namespace */
won't get created */
}
}
}
}
struct mailbox_list_iterate_context *
const char *const *patterns,
enum mailbox_list_iter_flags flags)
{
if ((flags & (MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
MAILBOX_LIST_ITER_RETURN_SUBSCRIBED)) != 0) {
if (mailbox_list_iter_subscriptions_refresh(list) < 0)
return &mailbox_list_iter_failed;
}
if ((flags & MAILBOX_LIST_ITER_NO_AUTO_BOXES) == 0)
return ctx;
}
static bool
{
return FALSE;
return FALSE;
}
return TRUE;
}
static bool
{
switch (result) {
case IMAP_MATCH_YES:
case IMAP_MATCH_CHILDREN:
return TRUE;
case IMAP_MATCH_NO:
case IMAP_MATCH_PARENT:
break;
}
return FALSE;
}
switch (result) {
case IMAP_MATCH_YES:
/* allow matching prefix only when it's done without
wildcards */
return TRUE;
break;
case IMAP_MATCH_CHILDREN: {
/* allow this only if there isn't another namespace
with longer prefix that matches this pattern
(namespaces are sorted by prefix length) */
T_BEGIN {
break;
}
} T_END;
return TRUE;
break;
}
case IMAP_MATCH_NO:
case IMAP_MATCH_PARENT:
break;
}
return FALSE;
}
{
return TRUE;
}
return FALSE;
}
{
const char *prefix_without_sep;
len--;
NAMESPACE_FLAG_LIST_CHILDREN)) == 0) {
/* non-listable namespace matches only with exact prefix */
return FALSE;
/* with prefix="", list=no we don't want to show anything,
except when the client explicitly lists a mailbox without
wildcards (e.g. LIST "" mailbox). this is mainly useful
for working around client bugs (and supporting a specific
IMAP client behavior that's not exactly buggy but not very
good IMAP behavior either). */
return FALSE;
}
if (*prefix_without_sep == '\0')
else {
}
}
static bool
{
unsigned int i;
return FALSE;
/* filter out namespaces whose prefix doesn't match. this same code
handles both with and without STAR_WITHIN_NS, so the "without" case
is slower than necessary, but this shouldn't matter much */
T_BEGIN {
break;
}
} T_END;
}
static bool
{
const char *prefix_without_sep;
NAMESPACE_FLAG_LIST_CHILDREN)) == 0) {
/* non-listable namespace matches only with exact prefix */
return FALSE;
}
return result == IMAP_MATCH_YES &&
}
static bool
struct mail_namespace *ns)
{
unsigned int i;
T_BEGIN {
ctx->patterns_ns_match[i]);
} T_END;
if (ret)
break;
}
return ret;
}
static int
struct mail_namespace *ns)
{
int ret;
return 1;
return ret;
}
return 0;
}
static int
const char *prefix)
{
int ret;
if (ret != 0)
return ret;
}
}
return 0;
}
static bool
{
}
static bool
{
return mailbox_ns_prefix_is_shared_inbox(ns) &&
}
static int
{
const char *pattern;
int ret;
return ret;
/* we don't want to see this, try the next one */
}
if (mailbox_list_iter_deinit(&list_iter) < 0) {
if (ret == 0)
ret = -1;
}
return ret;
}
static bool
{
return TRUE;
return TRUE;
return FALSE;
}
return TRUE;
}
static bool
{
int ret;
so we can create children to INBOX. */
}
return FALSE;
if (ns->special_use_mailboxes)
}
MAILBOX_LIST_ITER_SELECT_SUBSCRIBED)) != 0) {
/* Refresh subscriptions first, this won't cause a duplicate
call later on as this is only called when the namespace's
children definitely don't match */
return FALSE;
}
}
return FALSE;
/* see if the namespace has children */
if (has_children)
/* need to check this explicitly */
else if (ret == 0) {
/* no children -> not visible */
return FALSE;
}
}
}
/* see if namespace prefix is selectable */
else
mailbox_free(&box);
}
return TRUE;
}
{
const char *prefix;
int ret;
return;
MAILBOX_NOCHILDREN)) != 0)
return;
/* prefix="" namespace doesn't exist, and neither does
anything beginning with prefix=INBOX/ (we checked this
earlier). there's no way to create children for INBOX. */
return;
}
/* INBOX namespace doesn't exist and we didn't see any children listed
for INBOX. this could be because there truly aren't any children,
or that the list patterns just didn't match them. */
if (ret > 0)
else if (ret == 0)
}
{
const char *errstr;
}
}
static bool
const struct mailbox_info **info_r)
{
(struct ns_list_iterate_context *)_ctx;
bool has_children;
/* send delayed INBOX reply */
return TRUE;
}
return TRUE;
}
if (!mailbox_list_ns_match_patterns(ctx)) {
/* namespace's children don't match the patterns,
but the namespace prefix itself might */
return TRUE;
}
return FALSE;
}
/* start listing this namespace's mailboxes */
ctx->backend_ctx =
}
else {
}
if (!ctx->cur_ns_prefix_sent) {
/* delayed sending of namespace prefix */
has_children)) {
return TRUE;
}
}
/* delay sending INBOX reply. we already saved its
flags at init stage, except for \Noinferiors
and subscription states */
return FALSE;
}
/* we know now that INBOX has children */
}
/* this is an entry for namespace prefix, which we
returned as shared/$user, or when listing
subscribed namespace prefix). */
return FALSE;
}
return TRUE;
}
/* finished with this namespace */
return FALSE;
}
static const struct mailbox_info *
{
return info;
}
static int
{
(struct ns_list_iterate_context *)_ctx;
int ret;
}
return ret;
}
static const char **
unsigned int count)
{
const char **dup;
unsigned int i;
for (i = 0; i < count; i++) {
dup[i] = p;
for (; *p != '\0'; p++) {
if (*p == '*')
*p = '%';
}
}
return dup;
}
static bool
const char *const *patterns)
{
}
struct mail_namespace *namespaces)
{
int ret;
return ret;
}
struct mailbox_list_iterate_context *
const char *const *patterns,
enum mail_namespace_type type_mask,
enum mailbox_list_iter_flags flags)
{
unsigned int i, count;
for (i = 0; i < count; i++)
(flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) {
/* we're going to list the INBOX. get its own flags (i.e. not
[no]children) immediately, so if we end up seeing something
else called INBOX (e.g. namespace prefix) we can show it
immediately with the proper flags. */
pool_unref(&pool);
return &mailbox_list_iter_failed;
}
}
if ((flags & MAILBOX_LIST_ITER_STAR_WITHIN_NS) != 0) {
/* create copies of patterns with '*' wildcard changed to '%'.
this is used only when checking which namespaces to list */
} else {
}
}
static enum autocreate_match_result
bool only_subscribed, unsigned int *idx_r)
{
unsigned int i, count;
for (i = 0; i < count; i++) {
if (only_subscribed &&
continue;
continue;
*idx_r = i;
}
return result;
}
const struct mailbox_info *
const struct mailbox_info *_info)
{
return _info;
unsigned int idx;
if (!actx->listing_autoboxes) {
if ((match & AUTOCREATE_MATCH_RESULT_YES) != 0) {
/* we have an exact match in the list.
don't list it at the end. */
}
if ((match & AUTOCREATE_MATCH_RESULT_CHILDREN) != 0 &&
/* Prevent autocreate-iteration from adding this
mailbox as a duplicate. For example we're listing %
and we're here because "foo" was found. However,
telling here to the autocreate iteration code that
"foo" was already found and it doesn't need to add
it again. */
}
}
if ((match & AUTOCREATE_MATCH_RESULT_CHILDREN) != 0) {
else {
}
}
/* make sure the mailbox existence flags are correct. */
else {
}
if ((match2 & AUTOCREATE_MATCH_RESULT_YES) != 0)
if ((match2 & AUTOCREATE_MATCH_RESULT_CHILDREN) != 0) {
}
/* we're listing all mailboxes and want \Subscribed flag */
if ((match2 & AUTOCREATE_MATCH_RESULT_YES) != 0) {
/* mailbox is also marked as autosubscribe */
}
if ((match2 & AUTOCREATE_MATCH_RESULT_CHILDREN) != 0) {
/* mailbox also has a children marked as
autosubscribe */
}
}
if ((match & AUTOCREATE_MATCH_RESULT_PARENT) != 0) {
/* there are autocreate parent boxes.
set their children flag states. */
continue;
}
}
return info;
}
const struct autocreate_box *autobox)
{
/* mailbox format using files (e.g. mbox)
without DIRNAME specified */
} else {
}
}
if (match == IMAP_MATCH_YES) {
return TRUE;
}
const char *p;
char *vname;
(old_flags & (MAILBOX_CHILDREN |
if ((old_flags & MAILBOX_NONEXISTENT) == 0) {
}
if ((old_flags & MAILBOX_SUBSCRIBED) != 0)
do {
} while (match != IMAP_MATCH_YES);
return TRUE;
}
}
return FALSE;
}
static const struct mailbox_info *
{
return NULL;
}
}
}
const struct mailbox_info *
{
unsigned int count;
return NULL;
/* do not drop boxes anymore */
/* list missing mailboxes */
}
return NULL;
}
static bool
const struct mailbox_info *info)
{
/* LIST (SPECIAL-USE RECURSIVEMATCH) used. for now we support
this only for namespace prefixes */
return TRUE;
}
}
const struct mailbox_info *
{
if (ctx == &mailbox_list_iter_failed)
return NULL;
do {
T_BEGIN {
} T_END;
return info;
}
{
if (ctx == &mailbox_list_iter_failed)
return -1;
}
{
/* If we happened to create any of the parents, we need to mark them
nonexistent. */
}
}
static void
const char *name)
{
const char *p;
add_matched = TRUE;
for (;;) {
if (match == IMAP_MATCH_YES) {
if (created) {
if (create_flags != 0)
}
if ((always_flags & MAILBOX_CHILDREN) != 0)
}
/* We don't want to show the parent mailboxes unless
something else matches them, but if they are matched
we want to show them having child subscriptions */
add_matched = FALSE;
} else {
if ((match & IMAP_MATCH_PARENT) == 0)
break;
/* We've a (possibly) non-subscribed parent mailbox
which has a subscribed child mailbox. Make sure we
return the parent mailbox. */
}
if (!ctx->match_parents)
break;
/* see if parent matches */
if (p == NULL)
break;
}
}
const char *name)
{
T_BEGIN {
} T_END;
}