cmd-list.c revision 1aedd65760a63d6295c2e0e5ba40d45c1c733ddc
/* Copyright (C) 2002-2004 Timo Sirainen */
#include "common.h"
#include "str.h"
#include "strescape.h"
#include "imap-quote.h"
#include "imap-match.h"
#include "commands.h"
#include "mail-namespace.h"
enum {
_MAILBOX_LIST_ITER_HIDE_CHILDREN = 0x1000000,
_MAILBOX_LIST_ITER_LISTEXT = 0x0800000
};
struct cmd_list_context {
const char *ref;
const char *mask;
enum mailbox_list_flags list_flags;
struct mail_namespace *ns;
struct mailbox_list_iterate_context *list_iter;
struct imap_match_glob *glob;
unsigned int lsub:1;
unsigned int inbox_found:1;
unsigned int match_inbox:1;
};
static void
enum mailbox_list_flags list_flags)
{
if ((flags & MAILBOX_NONEXISTENT) != 0 &&
(list_flags & _MAILBOX_LIST_ITER_LISTEXT) == 0) {
flags &= ~MAILBOX_NONEXISTENT;
}
if ((list_flags & _MAILBOX_LIST_ITER_HIDE_CHILDREN) != 0)
if ((flags & MAILBOX_NOSELECT) != 0)
if ((flags & MAILBOX_NONEXISTENT) != 0)
if ((flags & MAILBOX_CHILDREN) != 0)
if ((flags & MAILBOX_NOCHILDREN) != 0)
if ((flags & MAILBOX_NOINFERIORS) != 0)
if ((flags & MAILBOX_MARKED) != 0)
if ((flags & MAILBOX_UNMARKED) != 0)
}
static bool
enum mailbox_list_flags *list_flags)
{
const char *atom;
"List options contains non-atoms.");
return FALSE;
}
else {
return FALSE;
}
args++;
}
return TRUE;
}
static void
{
const char *str;
/* INBOX always exists */
}
}
static int
{
struct mailbox_info *info;
const char *name;
int ret = 0;
return 1;
}
t_push();
str_truncate(name_str, 0);
/* Listing INBOX from inbox=yes namespace.
Don't insert the namespace prefix. */
if (!ctx->match_inbox) {
/* The mask doesn't match INBOX (eg. prefix.%).
We still want to list prefix.INBOX if it has
children. Otherwise we don't want to list
this INBOX at all. */
continue;
}
} else {
}
char *p = str_c_modifiable(name_str);
for (; *p != '\0'; p++) {
}
}
/* With masks containing '*' we do the checks here
so prefix is included in matching */
continue;
}
continue;
name = "INBOX";
}
str_truncate(str, 0);
/* buffer is full, continue later */
t_pop();
return 0;
}
}
ret = -1;
}
if (ret == 0)
t_pop();
}
static bool list_mask_has_wildcards(const char *mask)
{
return TRUE;
}
return FALSE;
}
static void
bool inbox_check, char sep)
{
bool match;
if (mask_len < prefix_len) {
/* eg. namespace prefix = "INBOX.", mask = "INBOX" */
return;
}
if (!match && inbox_check) {
/* try INBOX check. */
}
if (match) {
*prefix += prefix_len;
*mask += prefix_len;
}
}
static void
struct cmd_list_context *ctx)
{
enum imap_match_result match;
enum imap_match_result inbox_match;
struct mailbox_list *list;
struct imap_match_glob *inbox_glob;
unsigned int count;
/* reference argument given. skip namespace prefix using it.
cur_ref = foo/
-> cur_ns_prefix=bar/, cur_ref=""
-> cur_ns_prefix="", cur_ref="baz"
*/
/* reference parameter didn't match with
namespace prefix. skip this. */
return;
}
}
if (*cur_ns_prefix != '\0') {
/* no reference parameter. skip namespace prefix from mask. */
const char *old_ns_prefix = cur_ns_prefix;
/* trying to list the namespace prefix itself. */
}
}
/* if the original reference and mask combined produces something
that matches INBOX, the INBOX casing is on. */
(inbox_match == IMAP_MATCH_YES ||
inbox_match == IMAP_MATCH_PARENT) &&
if (*cur_ns_prefix != '\0') {
/* namespace prefix still wasn't completely skipped over.
for example cur_ns_prefix=INBOX/, mask=%/% or mask=IN%.
Check that mask matches namespace prefix. */
bool skip_trailing_sep = FALSE;
/* drop the trailing separator in namespace prefix.
don't do it if we're listing only the prefix itself. */
}
/* hidden namespaces should still be seen without wildcards.
some clients rely on this. */
if (match < 0)
return;
if (match == IMAP_MATCH_YES &&
/* The prefix itself matches */
enum mailbox_info_flags flags;
FALSE);
}
}
if (*cur_ns_prefix != '\0') {
/* We didn't skip over the whole namespace prefix. For example
cur_ns_prefix=INBOX/ and mask=%/% or IN*.
We have already verified that the mask matches the namespace
prefix, so we'll just have to skip over as many hierarchies
from mask as there exists in namespace prefix.
The "INBOX" namespace match reply was already sent. We're
only listing the actual mailboxes now. */
count++;
}
/* skip over one hierarchy */
cur_mask++;
if (*cur_mask == '*') {
/* we'll just request "*" and filter it
ourself. otherwise this gets too complex. */
cur_mask = "*";
break;
}
if (*cur_mask == '\0') {
/* mask ended too early. we won't be listing
any mailboxes. */
break;
}
cur_mask++;
}
/* oh what a horrible hack. ns_prefix="INBOX/" and
we wanted to list "%". INBOX should match. */
cur_mask = "INBOX";
}
}
/* a) we don't have '*' in mask
b) we want to display everything
we don't need to do separate filtering ourself */
}
ctx->list_flags);
}
{
int ret;
}
return TRUE;
}
return TRUE;
}
if (ret == 0)
return FALSE;
}
"OK List completed." :
"OK Lsub completed.");
return TRUE;
}
{
struct mail_namespace *ns;
enum mailbox_list_flags list_flags;
struct cmd_list_context *ctx;
/* [(<options>)] <reference> <mailbox wildcards> */
return FALSE;
if (lsub) {
/* LSUB - we don't care about flags */
/* LIST - allow children flags, but don't require them */
list_flags = 0;
} else {
&list_flags))
return TRUE;
args++;
/* don't show children flags unless explicitly specified */
if ((list_flags & MAILBOX_LIST_ITER_CHILDREN) == 0)
}
return TRUE;
}
const char *ns_prefix;
/* special request to return the hierarchy delimiter and
mailbox root name. Mailbox root name is somewhat strange
concept which probably no other client uses than Pine.
Just try our best to emulate UW-IMAP behavior and hopefully
we're fine. */
else {
const char *empty = "";
ns_prefix = "";
/* we must reply something. use INBOX
namespace's separator. */
const char *inbox = "INBOX";
&inbox);
}
}
/* public namespace, use it as the root name */
} else {
/* private namespace, or empty namespace
prefix. use the mailbox name's first part
as the root. */
if (p == NULL)
else {
FALSE);
}
}
}
} else {
if (!cmd_list_continue(cmd)) {
/* unfinished */
return FALSE;
}
return TRUE;
}
return TRUE;
}
{
}