Commit 00c27bc2 00c27bc22c1d032e0b9716bc87abbf6b68cbbb43 by Sergey Poznyakoff

Improve handling of namespace references

* imap4d/list.c (refinfo) <pfxlen>: Remove.
(list_fun): Change the algorithm for restoring the printable reference name.
(imap4d_list): Use actual reference, not the prefix value.
* imap4d/namespace.c: Fix handling of NS_OTHER prefixes.
* imap4d/tests/list.at: Change the testcase.
1 parent 5e425f04
......@@ -24,7 +24,6 @@ struct refinfo
char *refptr; /* Original reference */
size_t reflen; /* Length of the original reference */
struct namespace_prefix const *pfx;
size_t pfxlen;
size_t dirlen; /* Length of the current directory prefix */
char *buf;
size_t bufsize;
......@@ -43,8 +42,8 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data)
name = resp->name;
size = strlen (name);
if (size == refinfo->pfxlen + 6
&& memcmp (name + refinfo->pfxlen + 1, "INBOX", 5) == 0)
if (size == refinfo->reflen + 6
&& memcmp (name + refinfo->reflen + 1, "INBOX", 5) == 0)
return 0;
io_sendf ("* %s", "LIST (");
......@@ -59,37 +58,25 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data)
io_sendf (") \"%c\" ", refinfo->pfx->delim);
name = resp->name + refinfo->dirlen + 1;
size = strlen (name) + refinfo->pfxlen + 2;
size = strlen (name) + refinfo->reflen + 2;
if (size > refinfo->bufsize)
{
if (refinfo->buf == NULL)
{
refinfo->bufsize = size;
refinfo->buf = malloc (refinfo->bufsize);
if (!refinfo->buf)
{
mu_error ("%s", mu_strerror (errno));
return 1;
}
memcpy (refinfo->buf, refinfo->refptr, refinfo->reflen);
refinfo->buf = mu_alloc (refinfo->bufsize);
}
else
{
char *p = realloc (refinfo->buf, size);
if (!p)
{
mu_error ("%s", mu_strerror (errno));
return 1;
}
refinfo->buf = p;
refinfo->buf = mu_realloc (refinfo->buf, size);
refinfo->bufsize = size;
}
}
if (refinfo->pfxlen)
if (refinfo->refptr[0])
{
p = mu_stpcpy (refinfo->buf, refinfo->pfx->prefix);
if (*name)
p = mu_stpcpy (refinfo->buf, refinfo->refptr);
if (refinfo->refptr[refinfo->reflen-1] != refinfo->pfx->delim)
*p++ = refinfo->pfx->delim;
}
else
......@@ -185,35 +172,16 @@ imap4d_list (struct imap4d_session *session,
struct refinfo refinfo;
size_t i;
struct namespace_prefix const *pfx;
if (*wcard == '~')
{
for (i = 1;
mu_c_is_class (wcard[i], MU_CTYPE_ALPHA|MU_CTYPE_DIGIT)
|| wcard[i] == '_'; i++)
;
ref = mu_alloc (i + 1);
memcpy (ref, wcard, i);
ref[i] = 0;
wcard += i;
}
else
ref = mu_strdup (ref);
cwd = namespace_translate_name (ref, 0, &pfx);
if (!cwd)
{
free (ref);
return io_completion_response (command, RESP_NO,
"The requested item could not be found.");
}
free (cwd);
if (*wcard == pfx->delim && ref[0] != '~')
{
/* Absolute Path in wcard, dump the old ref. */
ref[0] = 0;
}
ref = mu_strdup (ref);
/* Find the longest directory prefix */
i = strcspn (wcard, "%*");
......@@ -223,14 +191,9 @@ imap4d_list (struct imap4d_session *session,
if (i)
{
size_t reflen = strlen (ref);
int addslash = (reflen > 0
&& ref[reflen-1] != pfx->delim
&& *wcard != pfx->delim);
size_t len = i + reflen + addslash;
size_t len = i + reflen;
ref = mu_realloc (ref, len);
if (addslash)
ref[reflen++] = pfx->delim;
memcpy (ref + reflen, wcard, i - 1); /* omit the trailing / */
ref[len-1] = 0;
......@@ -278,8 +241,6 @@ imap4d_list (struct imap4d_session *session,
mu_url_sget_path (url, &dir);
refinfo.dirlen = strlen (dir);
refinfo.pfxlen = strlen (pfx->prefix);
/* The special name INBOX is included in the output from LIST, if
INBOX is supported by this server for this user and if the
uppercase string "INBOX" matches the interpreted reference and
......
......@@ -104,7 +104,6 @@ namespace_init (void)
}
pfx->ns = i;
trim_delim (pfx->prefix, pfx->delim);
trim_delim (pfx->dir, '/');
rc = mu_assoc_install (prefixes, pfx->prefix, pfx);
......@@ -182,9 +181,7 @@ prefix_translate_name (struct namespace_prefix const *pfx, char const *name,
{
size_t pfxlen = strlen (pfx->prefix);
if (pfxlen <= namelen
&& memcmp (pfx->prefix, name, pfxlen) == 0
&& (pfxlen == 0 || pfxlen == namelen || name[pfxlen] == pfx->delim))
if (pfxlen <= namelen && memcmp (pfx->prefix, name, pfxlen) == 0)
{
char *tmpl, *p;
......@@ -212,10 +209,17 @@ prefix_translate_name (struct namespace_prefix const *pfx, char const *name,
p = mu_stpcpy (p, pfx->dir);
if (*name)
{
*p++ = '/';
if (pfx->ns == NS_OTHER
&& pfx->prefix[strlen(pfx->prefix) - 1] != pfx->delim)
{
while (*name && *name != pfx->delim)
name++;
}
else if (*name != pfx->delim)
*p++ = '/';
translate_delim (p, name, '/', pfx->delim);
}
return tmpl;
}
return NULL;
......@@ -230,15 +234,6 @@ i_translate_name (char const *name, int url, int ns,
char *res = NULL;
size_t namelen = strlen (name);
#if 0
FIXME
if (namelen >= 5
&& strcmp (name + namelen - 5, "INBOX") == 0
&& (namelen == 5 && name[namelen - 6] == '/'))
{
}
#endif
rc = mu_assoc_get_iterator (prefixes, &itr);
if (rc)
{
......@@ -285,7 +280,10 @@ extract_username (char const *name, struct namespace_prefix const *pfx)
len = end - p;
else
len = strlen (p);
if (len == 0)
return mu_strdup (auth_data->name);
user = mu_alloc (len + 1);
memcpy (user, p, len);
user[len] = 0;
......@@ -310,17 +308,10 @@ namespace_translate_name (char const *name, int url,
struct namespace_prefix const *pfx;
char *env[] = ENV_INITIALIZER;
if (name[0] == '~')
if (mu_c_strcasecmp (name, "INBOX") == 0 && auth_data->change_uid)
{
if (name[1] == 0 || name[1] == '/')
{
if (mu_c_strcasecmp (name, "INBOX") == 0 && auth_data->change_uid)
res = mu_strdup (auth_data->mailbox);
else
res = i_translate_name (name, url, NS_PRIVATE, &pfx);
}
else
res = i_translate_name (name, url, NS_OTHER, &pfx);
res = mu_strdup (auth_data->mailbox);
pfx = mu_assoc_get (prefixes, "");
}
else
res = i_translate_name (name, url, NS_MAX, &pfx);
......@@ -336,7 +327,7 @@ namespace_translate_name (char const *name, int url,
env[ENV_HOME] = real_homedir;
break;
case NS_SHARED:
case NS_OTHER:
{
struct mu_auth_data *adata;
env[ENV_USER] = extract_username (name, pfx);
......@@ -349,7 +340,7 @@ namespace_translate_name (char const *name, int url,
}
break;
case NS_OTHER:
case NS_SHARED:
break;
}
......
......@@ -76,16 +76,17 @@ LIST_CHECK([empty ref + asterisk],[list02],
* LIST (\NoInferiors) NIL INBOX
])
# FIXME: I'm not sure whether it should include / in the reply.
LIST_CHECK([root ref + asterisk],[list03],
["/" "*"],
[dnl
* LIST (\NoInferiors) "/" bigto.mbox
* LIST (\NoInferiors) "/" mbox
* LIST (\NoInferiors) "/" mbox1
* LIST (\NoInferiors) "/" relational.mbox
* LIST (\NoInferiors) "/" search.mbox
* LIST (\NoInferiors) "/" sieve.mbox
* LIST (\NoInferiors) "/" teaparty.mbox
* LIST (\NoInferiors) "/" /bigto.mbox
* LIST (\NoInferiors) "/" /mbox
* LIST (\NoInferiors) "/" /mbox1
* LIST (\NoInferiors) "/" /relational.mbox
* LIST (\NoInferiors) "/" /search.mbox
* LIST (\NoInferiors) "/" /sieve.mbox
* LIST (\NoInferiors) "/" /teaparty.mbox
])
LIST_CHECK([absolute reference + asterisk],[list04],
......