Commit d569c130 d569c130f2cee770ab0aba6ee2a65382967b324e by Sergey Poznyakoff

Allow for "INBOX." namespace.

* imap4d/imap4d.h (io_send_astring): New proto.
* imap4d/io.c (io_send_astring): New function.
* imap4d/list.c (list_fun): Use io_send_astring.
(list_ref): Special handling for empty wcard
(imap4d_list): Remove special handling for empty wcard and
INBOX.  Leave that to list_ref.  This makes it possible to
declare namespaces like "INBOX." ("." being the delimiter).
* imap4d/lsub.c (imap4d_lsub): Use io_send_astring.
* imap4d/namespace.c (namespace_translate_name): Check for
declared namespace first.
1 parent 80d8b59a
......@@ -229,6 +229,7 @@ extern int io_untagged_response (int, const char *, ...) MU_PRINTFLIKE(2,3);
extern int io_sendf (const char *, ...) MU_PRINTFLIKE(1,2);
extern int io_send_bytes (const char *buf, size_t size);
extern int io_send_qstring (const char *);
extern int io_send_astring (const char *);
extern int io_send_literal (const char *);
extern int io_copy_out (mu_stream_t str, size_t size);
extern int io_completion_response (struct imap4d_command *, int,
......
......@@ -256,6 +256,27 @@ io_send_qstring (const char *buffer)
}
int
io_send_astring (const char *buffer)
{
if (buffer == NULL)
return io_sendf ("NIL");
else if (*buffer == 0)
return io_sendf ("\"\"");
if (strpbrk (buffer, "\"\r\n\\"))
{
char *s;
int ret;
char *b = mu_strdup (buffer);
while ((s = strchr (b, '\n')) || (s = strchr (b, '\r')))
*s = ' ';
ret = io_send_literal (b);
free (b);
return ret;
}
return io_sendf ("\"%s\"", buffer);
}
int
io_send_literal (const char *buffer)
{
return io_sendf ("{%lu}\n%s", (unsigned long) strlen (buffer), buffer);
......
......@@ -97,7 +97,7 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data)
io_sendf ("%s\n", name);
else
{
io_send_qstring (name);
io_send_astring (name);
io_sendf ("\n");
}
return 0;
......@@ -128,6 +128,26 @@ list_ref (char const *ref, char const *wcard, char const *cwd,
char const *dir;
mu_url_t url;
if (!wcard[0])
{
/* An empty ("" string) mailbox name argument is a special request to
return the hierarchy delimiter and the root name of the name given
in the reference.
*/
io_sendf ("* LIST (\\NoSelect) ");
if (mu_c_strcasecmp (ref, "INBOX") == 0)
{
io_sendf ("NIL \"\"");
}
else
{
io_sendf ("\"%c\" ", pfx->delim);
io_send_astring (pfx->prefix);
}
io_sendf ("\n");
return RESP_OK;
}
if (pfx->ns == NS_OTHER && match_pfx (pfx, ref) && strpbrk (wcard, "*%"))
{
/* [A] server MAY return NO to such a LIST command, requiring that a
......@@ -226,6 +246,8 @@ imap4d_list (struct imap4d_session *session,
[RESP_NO] = "The requested item could not be found",
[RESP_BAD] = "System error"
};
char *cwd = NULL;
struct namespace_prefix const *pfx = NULL;
if (imap4d_tokbuf_argc (tok) != 4)
return io_completion_response (command, RESP_BAD, "Invalid arguments");
......@@ -233,40 +255,21 @@ imap4d_list (struct imap4d_session *session,
ref = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
wcard = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
/* If wildcard is empty, it is a special case: we have to
return the hierarchy. */
if (*wcard == '\0')
{
if (*ref)
io_untagged_response (RESP_NONE,
"LIST (\\NoSelect) \"%c\" \"%c\"",
MU_HIERARCHY_DELIMITER,
MU_HIERARCHY_DELIMITER);
else
io_untagged_response (RESP_NONE,
"LIST (\\NoSelect) \"%c\" \"\"",
MU_HIERARCHY_DELIMITER);
}
/* There is only one mailbox in the "INBOX" hierarchy ... INBOX. */
else if (mu_c_strcasecmp (ref, "INBOX") == 0
|| (ref[0] == 0 && mu_c_strcasecmp (wcard, "INBOX") == 0))
{
io_untagged_response (RESP_NONE, "LIST (\\NoInferiors) NIL INBOX");
}
else
{
char *cwd = NULL;
struct namespace_prefix const *pfx = NULL;
if (ref[0] == 0)
{
cwd = namespace_translate_name (wcard, &pfx);
if (cwd)
{
char *p = wcard + strlen (pfx->prefix);
size_t p_len = strlen (pfx->prefix);
size_t w_len = strlen (wcard);
if (p_len <= w_len)
{
memmove (wcard, wcard + p_len, w_len - p_len + 1);
ref = mu_strdup (pfx->prefix);
memmove (wcard, p, strlen (p) + 1);
}
else
ref = mu_strdup (ref);
free (cwd);
}
else
......@@ -313,7 +316,6 @@ imap4d_list (struct imap4d_session *session,
free (cwd);
free (ref);
}
return io_completion_response (command, status, resp_text[status]);
}
......
......@@ -68,7 +68,7 @@ imap4d_lsub (struct imap4d_session *session,
{
mu_stream_printf (iostream, "* LSUB () \"%c\" ",
MU_HIERARCHY_DELIMITER);
io_send_qstring (name);
io_send_astring (name);
io_sendf ("\n");
}
}
......
......@@ -279,12 +279,6 @@ namespace_translate_name (char const *name,
char *res = NULL;
struct namespace_prefix const *pfx;
if (mu_c_strcasecmp (name, "INBOX") == 0 && auth_data->change_uid)
{
res = mu_strdup (auth_data->mailbox);
pfx = mu_assoc_get (prefixes, "");
}
else
res = translate_name (name, &pfx);
if (res)
......@@ -347,10 +341,16 @@ namespace_translate_name (char const *name,
res = dir;
trim_delim (res, '/');
}
else if (mu_c_strcasecmp (name, "INBOX") == 0 && auth_data->change_uid)
{
res = mu_strdup (auth_data->mailbox);
pfx = mu_assoc_get (prefixes, "");
}
if (return_pfx)
if (res && return_pfx)
*return_pfx = pfx;
}
return res;
}
......
......@@ -446,10 +446,10 @@ mu_folder_delete (mu_folder_t folder, const char *name)
undesired results. For example, a MH mailbox can hold another
mailboxes, i.e. be a folder itself. Removing it blindly would
result in removing these mailboxes as well, which is clearly not
indended.
intended.
To solve this folder and mailbox delete methods are tightly paired,
but without looking into each-others internal mechanisms. */
To solve this, both folder and mailbox delete methods are tightly
paired, but without looking into each-others internal mechanisms. */
mu_mailbox_t mbox;
rc = mu_mailbox_create_at (&mbox, folder, name);
if (rc == 0)
......