Commit 9a94d41a 9a94d41a0c8cd941db019478c7a75b1036ddf580 by Sergey Poznyakoff

Rewrite namespace support

* imap4d/imap4d.c (imap4d_homedir)
(modify_homedir, mailbox_mode): Remove.
(imap4d_srv_param): New configuration statement "namespace"
Remove statements: homedir, personal-namespace,
shared-namespace, other-mailbox-mode, shared-mailbox-mode.
* imap4d/imap4d.h (imap4d_homedir, modify_homedir)
(mailbox_mode): Remove.
(namespace, namespace_init_session, util_getfullpath)
(namespace_getfullpath, namespace_checkfullpath): Remove.
(namespace_prefix, namespace): New structs.
(namespace_lookup, namespace_translate_name)
(namespace_get_url, translate_delim): New protos.
* imap4d/list.c (refinfo): Revamp.
(list_fun): Rewrite.
* imap4d/namespace.c: Rewrite from scratch.
* imap4d/append.c: Use new namespace functions.
* imap4d/util.c (util_getfullpath): Remove.

* imap4d/copy.c: Likewise.
* imap4d/create.c: Likewise.
* imap4d/delete.c: Likewise.
* imap4d/quota.c: Likewise.
* imap4d/rename.c: Likewise.
* imap4d/select.c: Likewise.
* imap4d/status.c: Likewise.

* imap4d/tests/atlocal.in (make_config): New function.
* imap4d/tests/testsuite.at (IMAP4D_CONFIG)
(IMAP4D_RUN): New functions.
* imap4d/tests/list.at: Update tests 16, 17, 18, 19

* imap4d/tests/IDEF0955.at: Use IMAP4D_RUN.
* imap4d/tests/IDEF0956.at: Likewise.
* imap4d/tests/append00.at: Likewise.
* imap4d/tests/append01.at: Likewise.
* imap4d/tests/create01.at: Likewise.
* imap4d/tests/create02.at: Likewise.
1 parent 068c0599
......@@ -253,7 +253,7 @@ imap4d_append (struct imap4d_session *session,
msg_text = imap4d_tokbuf_getarg (tok, i);
mboxname = namespace_getfullpath (mboxname, NULL);
mboxname = namespace_get_url (mboxname, NULL);
if (!mboxname)
return io_completion_response (command, RESP_NO, "Couldn't open mailbox");
......
......@@ -211,7 +211,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
char *end;
mu_mailbox_t cmbox = NULL;
int arg = IMAP4_ARG_1 + !!isuid;
int ns;
int mode = 0;
*err_text = NULL;
if (imap4d_tokbuf_argc (tok) != arg + 2)
......@@ -240,7 +240,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
return RESP_BAD;
}
mailbox_name = namespace_getfullpath (name, &ns);
mailbox_name = namespace_get_url (name, &mode);
if (!mailbox_name)
{
......@@ -255,7 +255,7 @@ imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
if (status == 0)
{
/* It SHOULD NOT automatifcllly create the mailbox. */
status = mu_mailbox_open (cmbox, MU_STREAM_RDWR | mailbox_mode[ns]);
status = mu_mailbox_open (cmbox, MU_STREAM_RDWR | mode);
if (status == 0)
{
mu_list_t msglist;
......
......@@ -39,7 +39,7 @@ imap4d_create (struct imap4d_session *session,
{
char *name;
int isdir = 0;
int ns;
int mode = 0;
int rc = RESP_OK;
const char *msg = "Completed";
......@@ -67,7 +67,7 @@ imap4d_create (struct imap4d_session *session,
isdir = 1;
/* Allocates memory. */
name = namespace_getfullpath (name, &ns);
name = namespace_get_url (name, &mode);
if (!name)
return io_completion_response (command, RESP_NO, "Cannot create mailbox");
......@@ -96,7 +96,7 @@ imap4d_create (struct imap4d_session *session,
}
else if ((rc = mu_mailbox_open (mbox,
MU_STREAM_RDWR | MU_STREAM_CREAT
| mailbox_mode[ns])))
| mode)))
{
mu_diag_output (MU_DIAG_ERR,
_("Cannot open mailbox %s: %s"),
......
......@@ -49,7 +49,7 @@ imap4d_delete (struct imap4d_session *session,
return io_completion_response (command, RESP_NO, "Already exist");
/* Allocates memory. */
name = namespace_getfullpath (name, NULL);
name = namespace_get_url (name, NULL);
if (!name)
return io_completion_response (command, RESP_NO, "Cannot remove");
......
......@@ -27,8 +27,6 @@ int imap4d_transcript;
mu_mailbox_t mbox; /* Current mailbox */
char *real_homedir; /* Homedir as returned by user database */
char *imap4d_homedir; /* Homedir as visible for the remote party */
char *modify_homedir; /* Expression to produce imap4d_homedir */
int state = STATE_NONAUTH; /* Current IMAP4 state */
struct mu_auth_data *auth_data;
......@@ -40,8 +38,6 @@ mu_list_t user_retain_groups;
int home_dir_mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
int mailbox_mode[NS_MAX];
/* Saved command line. */
int imap4d_argc;
char **imap4d_argv;
......@@ -359,7 +355,179 @@ imap_check_group_list (mu_list_t l)
return MU_ERR_NOENT;
return rc;
}
static int
cb_prefix_delim (void *data, mu_config_value_t *val)
{
if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
return 1;
if (val->v.string[0] == 0)
mu_error (_("delimiter cannot be empty"));
else if (val->v.string[1] != 0)
mu_error (_("delimiter must be a single character"));
else
*(int*) data = val->v.string[0];
return 0;
}
static int
cb_prefix_scheme (void *data, mu_config_value_t *val)
{
struct namespace_prefix *pfx = data;
char *scheme;
mu_record_t rec;
int rc;
int (*mbx) (mu_mailbox_t);
if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
return 1;
scheme = mu_strdup (val->v.string);
rc = mu_registrar_lookup_scheme (scheme, &rec);
if (rc == MU_ERR_NOENT)
{
mu_error (_("unknown mailbox type"));
return 1;
}
else if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_registrar_lookup_scheme", scheme, rc);
return 1;
}
rc = mu_record_get_mailbox (rec, &mbx);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_record_get_mailbox", scheme, rc);
return 1;
}
if (!mbx || !mu_record_is_local (rec))
{
mu_error (_("not a local mailbox type"));
return 1;
}
pfx->scheme = scheme;
pfx->record = rec;
return 0;
}
static struct mu_cfg_param prefix_param[] = {
{ "directory", mu_c_string,
NULL, mu_offsetof (struct namespace_prefix, dir), NULL,
N_("Directory in the file system") },
{ "delimiter", mu_cfg_callback,
NULL, mu_offsetof (struct namespace_prefix, delim), cb_prefix_delim,
N_("Hierarchy delimiter character") },
{ "mailbox-type", mu_cfg_callback,
NULL, 0, cb_prefix_scheme,
N_("Type of mailboxes residing under this prefix") },
{ NULL }
};
static struct mu_cfg_param namespace_param[] = {
{ "mailbox-mode", mu_cfg_callback,
NULL, mu_offsetof (struct namespace, mode), cb_mailbox_mode,
N_("File mode for newly created mailboxes in this namespace"),
N_("mode: g(+|=)[wr]+,o(+|=)[wr]+") },
{ "prefix", mu_cfg_section },
{ NULL }
};
static int
prefix_section_parser (enum mu_cfg_section_stage stage,
const mu_cfg_node_t *node,
const char *section_label, void **section_data,
void *call_data,
mu_cfg_tree_t *tree)
{
struct namespace_prefix *pfx;
switch (stage)
{
case mu_cfg_section_start:
{
struct namespace *nspace = *section_data;
if (node->label == NULL || node->label->type != MU_CFG_STRING)
return 1;
pfx = mu_zalloc (sizeof (*pfx));
pfx->prefix = mu_strdup (node->label->v.string);
mu_list_append (nspace->prefixes, pfx);
*section_data = pfx;
}
break;
case mu_cfg_section_end:
pfx = *section_data;
if (!pfx->delim)
pfx->delim = '/';
if (!pfx->dir)
{
if (pfx->prefix)
pfx->dir = mu_strdup (pfx->prefix);
else
{
mu_error (_("bad prefix definition"));
return 1;
}
}
else if (!pfx->prefix)
{
pfx->prefix = mu_alloc (strlen (pfx->dir) + 1);
translate_delim (pfx->prefix, pfx->dir, pfx->delim, '/');
}
}
return 0;
}
static int
namespace_section_parser (enum mu_cfg_section_stage stage,
const mu_cfg_node_t *node,
const char *section_label, void **section_data,
void *call_data,
mu_cfg_tree_t *tree)
{
if (stage == mu_cfg_section_start)
{
struct namespace *ns;
if (node->label == NULL || node->label->type != MU_CFG_STRING)
return 1;
ns = namespace_lookup (node->label->v.string);
if (!ns)
{
mu_error (_("unknown namespace"));
return 0;
}
*section_data = ns;
}
return 0;
}
static void
namespace_cfg_init (void)
{
struct mu_cfg_section *section;
if (mu_create_canned_section ("prefix", &section))
abort ();
section->docstring = N_("Define a single prefix");
mu_cfg_section_add_params (section, prefix_param);
section->parser = prefix_section_parser;
if (mu_create_canned_section ("namespace", &section))
abort ();
section->docstring = N_("Define a namespace");
section->label = "private | other | shared";
section->parser = namespace_section_parser;
mu_cfg_section_add_params (section, namespace_param);
}
static struct mu_cfg_param imap4d_srv_param[] = {
#ifdef WITH_TLS
{ "tls", mu_cfg_callback,
......@@ -385,8 +553,12 @@ static struct mu_cfg_param imap4d_cfg_param[] = {
0, NULL,
N_("Deny access if the user group is in this list.") },
{ "namespace", mu_cfg_section },
#if 0
{ "homedir", mu_c_string, &modify_homedir, 0, NULL,
N_("Modify home directory.") },
{ "personal-namespace", MU_CFG_LIST_OF(mu_c_string), &namespace[NS_PRIVATE],
0, NULL,
N_("Set personal namespace.") },
......@@ -396,6 +568,7 @@ static struct mu_cfg_param imap4d_cfg_param[] = {
{ "shared-namespace", MU_CFG_LIST_OF(mu_c_string), &namespace[NS_SHARED],
0, NULL,
N_("Set shared namespace.") },
FIXME
{ "other-mailbox-mode", mu_cfg_callback, &mailbox_mode[NS_OTHER], 0,
cb_mailbox_mode,
N_("File mode for mailboxes in other namespace."),
......@@ -404,6 +577,7 @@ static struct mu_cfg_param imap4d_cfg_param[] = {
cb_mailbox_mode,
N_("File mode for mailboxes in shared namespace."),
N_("mode: g(+|=)[wr]+,o(+|=)[wr]+") },
#endif
{ "login-disabled", mu_c_bool, &login_disabled, 0, NULL,
N_("Disable LOGIN command.") },
{ "create-home-dir", mu_c_bool, &create_home_dir, 0, NULL,
......@@ -530,52 +704,6 @@ imap4d_session_setup0 ()
real_homedir = mu_normalize_path (mu_strdup (auth_data->dir));
if (imap4d_check_home_dir (real_homedir, auth_data->uid, auth_data->gid))
return 1;
if (modify_homedir)
{
char *expr = mu_tilde_expansion (modify_homedir, MU_HIERARCHY_DELIMITER,
real_homedir);
struct mu_wordsplit ws;
const char *env[5];
env[0] = "user";
env[1] = auth_data->name;
env[2] = "home";
env[3] = real_homedir;
env[4] = NULL;
ws.ws_env = env;
if (mu_wordsplit (expr, &ws,
MU_WRDSF_NOSPLIT | MU_WRDSF_NOCMD |
MU_WRDSF_ENV | MU_WRDSF_ENV_KV))
{
mu_error (_("cannot expand line `%s': %s"), expr,
mu_wordsplit_strerror (&ws));
return 1;
}
else if (ws.ws_wordc == 0)
{
mu_error (_("expanding %s yields empty string"), expr);
return 1;
}
imap4d_homedir = mu_strdup (ws.ws_wordv[0]);
if (!imap4d_homedir)
{
mu_error ("%s", mu_strerror (errno));
return 1;
}
}
else
imap4d_homedir = mu_strdup (real_homedir);
if (strcmp (imap4d_homedir, real_homedir)
&& imap4d_check_home_dir (imap4d_homedir,
auth_data->uid, auth_data->gid))
{
free (imap4d_homedir);
free (real_homedir);
return 1;
}
if (auth_data->change_uid)
{
......@@ -591,7 +719,6 @@ imap4d_session_setup0 ()
if (rc)
{
mu_error(_("cannot create list: %s"), mu_strerror (rc));
free (imap4d_homedir);
free (real_homedir);
return 1;
}
......@@ -603,7 +730,6 @@ imap4d_session_setup0 ()
{
/* FIXME: When mu_get_user_groups goes to the library, add a
diag message here */
free (imap4d_homedir);
free (real_homedir);
return 1;
}
......@@ -614,15 +740,13 @@ imap4d_session_setup0 ()
{
mu_error (_("can't switch to user %s privileges: %s"),
auth_data->name, mu_strerror (rc));
free (imap4d_homedir);
free (real_homedir);
return 1;
}
}
}
util_chdir (imap4d_homedir);
namespace_init_session (imap4d_homedir);
util_chdir (real_homedir);
mu_diag_output (MU_DIAG_INFO,
_("user `%s' logged in (source: %s)"), auth_data->name,
......@@ -936,6 +1060,7 @@ main (int argc, char **argv)
mu_tcpwrapper_cfg_init ();
manlock_cfg_init ();
mu_acl_cfg_init ();
namespace_cfg_init ();
mu_m_server_create (&server, program_version);
mu_m_server_set_config_size (server, sizeof (struct imap4d_srv_config));
......@@ -959,6 +1084,8 @@ main (int argc, char **argv)
mu_error (_("too many arguments"));
exit (EX_USAGE);
}
namespace_init ();
if (test_mode)
mu_m_server_set_mode (server, MODE_INTERACTIVE);
......@@ -966,8 +1093,6 @@ main (int argc, char **argv)
if (login_disabled)
imap4d_capability_add (IMAP_CAPA_LOGINDISABLED);
namespace_init ();
if (mu_gsasl_enabled ())
{
auth_gssapi_init ();
......
......@@ -197,17 +197,13 @@ struct imap4d_session
extern struct imap4d_command imap4d_command_table[];
extern mu_mailbox_t mbox;
extern char *imap4d_homedir;
extern char *real_homedir;
extern char *modify_homedir;
extern int state;
extern size_t children;
extern int is_virtual;
extern struct mu_auth_data *auth_data;
extern const char *program_version;
extern int mailbox_mode[NS_MAX];
extern int login_disabled;
extern enum imap4d_preauth preauth_mode;
extern char *preauth_program;
......@@ -394,15 +390,34 @@ extern int imap4d_bye0 (int reason, struct imap4d_command *command);
void imap4d_enter_critical (void);
void imap4d_leave_critical (void);
/* Namespace functions */
extern mu_list_t namespace[NS_MAX];
extern int namespace_init_session (char *path);
extern void namespace_init (void);
extern char *namespace_getfullpath (const char *name, int *pns);
extern char *namespace_checkfullpath (const char *name, const char *pattern,
int *pns);
struct namespace_prefix
{
char *prefix; /* Prefix string */
int delim; /* Delimiter character */
char *dir; /* Directory in the file system */
char *scheme; /* Mailbox URL scheme (type) */
mu_record_t record; /* The corresponding record */
int ns; /* Namespace */
};
struct namespace
{
char const *name;
int mode; /* File mode for creating new mailboxes */
mu_list_t prefixes; /* List of prefixes (struct namespace_prefix */
};
void namespace_init (void);
struct namespace *namespace_lookup (char const *name);
char *namespace_translate_name (char const *name, int url,
struct namespace_prefix const **pfx);
char *namespace_get_url (char const *name, int *mode);
void translate_delim (char *dst, char const *src, int dst_delim, int src_delim);
int imap4d_session_setup (char *username);
int imap4d_session_setup0 (void);
void imap4d_child_signal_setup (RETSIGTYPE (*handler) (int signo));
......@@ -417,7 +432,6 @@ extern void imap4d_capability_init (void);
extern int util_start (char *);
extern int util_getstate (void);
extern int util_do_command (struct imap4d_session *, imap4d_tokbuf_t);
extern char *util_getfullpath (const char *);
extern struct imap4d_command *util_getcommand (char *,
struct imap4d_command []);
......
......@@ -23,8 +23,9 @@ struct refinfo
{
char *refptr; /* Original reference */
size_t reflen; /* Length of the original reference */
size_t pfxlen; /* Length of the current prefix */
size_t homelen; /* Length of homedir */
struct namespace_prefix const *pfx;
size_t pfxlen;
size_t dirlen; /* Length of the current directory prefix */
char *buf;
size_t bufsize;
};
......@@ -35,12 +36,15 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data)
char *name;
struct refinfo *refinfo = data;
size_t size;
char *p;
if (refinfo->pfx->record && refinfo->pfx->record != resp->format)
return 0;
name = resp->name;
size = strlen (name);
if (size == refinfo->homelen + 6
&& memcmp (name, imap4d_homedir, refinfo->homelen) == 0
&& memcmp (name + refinfo->homelen + 1, "INBOX", 5) == 0)
if (size == refinfo->pfxlen + 6
&& memcmp (name + refinfo->pfxlen + 1, "INBOX", 5) == 0)
return 0;
io_sendf ("* %s", "LIST (");
......@@ -52,10 +56,10 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data)
else if (resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
io_sendf ("\\NoSelect");
io_sendf (") \"%c\" ", resp->separator);
io_sendf (") \"%c\" ", refinfo->pfx->delim);
name = resp->name + refinfo->pfxlen;
size = strlen (name) + refinfo->reflen + 1;
name = resp->name + refinfo->dirlen + 1;
size = strlen (name) + refinfo->pfxlen + 2;
if (size > refinfo->bufsize)
{
if (refinfo->buf == NULL)
......@@ -82,10 +86,17 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data)
}
}
if ((refinfo->reflen == 0 || refinfo->refptr[refinfo->reflen - 1] == '/')
&& name[0] == '/')
name++;
strcpy (refinfo->buf + refinfo->reflen, name);
if (refinfo->pfxlen)
{
p = mu_stpcpy (refinfo->buf, refinfo->pfx->prefix);
if (*name)
*p++ = refinfo->pfx->delim;
}
else
p = refinfo->buf;
if (*name)
translate_delim (p, name, refinfo->pfx->delim, resp->separator);
name = refinfo->buf;
if (strpbrk (name, "\"{}"))
......@@ -168,69 +179,84 @@ imap4d_list (struct imap4d_session *session,
{
int status;
mu_folder_t folder;
mu_url_t url;
char *cwd;
char const *dir;
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);
switch (*wcard)
if (*wcard == pfx->delim && ref[0] != '~')
{
/* Absolute Path in wcard, dump the old ref. */
case '/':
ref = mu_strdup ("/");
wcard++;
break;
/* Absolute Path, but take care of things like ~guest/Mail,
ref becomes ref = ~guest. */
case '~':
{
char *s = strchr (wcard, '/');
if (s)
{
ref = calloc (s - wcard + 1, 1);
memcpy (ref, wcard, s - wcard);
ref [s - wcard] = '\0';
wcard = s + 1;
}
else
{
ref = mu_strdup (wcard);
wcard += strlen (wcard);
}
}
break;
default:
ref = mu_strdup (ref);
ref[0] = 0;
}
/* Find the longest directory prefix */
i = strcspn (wcard, "%*");
while (i > 0 && wcard[i - 1] != '/')
while (i > 0 && wcard[i - 1] != pfx->delim)
i--;
/* Append it to the reference */
if (i)
{
size_t reflen = strlen (ref);
int addslash = (reflen > 0 && ref[reflen-1] != '/');
int addslash = (reflen > 0
&& ref[reflen-1] != pfx->delim
&& *wcard != pfx->delim);
size_t len = i + reflen + addslash;
ref = mu_realloc (ref, len);
if (addslash)
ref[reflen++] = '/';
ref[reflen++] = pfx->delim;
memcpy (ref + reflen, wcard, i - 1); /* omit the trailing / */
ref[len-1] = 0;
wcard += i;
}
/* Allocates. */
cwd = namespace_checkfullpath (ref, wcard, NULL);
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.");
"The requested item could not be found.");
}
if (pfx->ns == NS_OTHER
&& strcmp (ref, pfx->prefix) == 0
&& *mu_str_skip_cset_comp (wcard, "*%"))
{
/* [A] server MAY return NO to such a LIST command, requiring that a
user name be included with the Other Users' Namespace prefix
before listing any other user's mailboxes */
free (ref);
return io_completion_response (command, RESP_NO,
"The requested item could not be found.");
}
status = mu_folder_create (&folder, cwd);
if (status)
{
......@@ -246,8 +272,13 @@ imap4d_list (struct imap4d_session *session,
refinfo.refptr = ref;
refinfo.reflen = strlen (ref);
refinfo.pfxlen = strlen (cwd);
refinfo.homelen = strlen (imap4d_homedir);
refinfo.pfx = pfx;
mu_folder_get_url (folder, &url);
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
......
......@@ -16,93 +16,407 @@
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#include "imap4d.h"
#include <mailutils/assoc.h>
typedef int (*nsfp_t) (void *closure, int ns, char *path, int delim);
struct namespace namespace[NS_MAX] = {
[NS_PRIVATE] = { "private" },
[NS_OTHER] = { "other" },
[NS_SHARED] = { "shared" }
};
static mu_assoc_t prefixes;
mu_list_t namespace[NS_MAX];
struct namespace *
namespace_lookup (char const *name)
{
size_t i;
for (i = 0; i < NS_MAX; i++)
if (strcmp (namespace[i].name, name) == 0)
{
if (!namespace[i].prefixes)
{
int rc = mu_list_create (&namespace[i].prefixes);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_list_create", NULL, rc);
abort ();
}
}
return &namespace[i];
}
return NULL;
}
static int
cmplen (const char *aname, const void *adata,
const char *bname, const void *bdata,
void *closure)
{
return strlen (bname) - strlen (aname);
}
static const char *
printable_pathname (const char *str)
void
translate_delim (char *dst, char const *src, int dst_delim, int src_delim)
{
if (strncmp (str, imap4d_homedir, strlen (imap4d_homedir)) == 0)
do
*dst++ = *src == src_delim ? dst_delim : *src;
while (*src++);
}
static void
trim_delim (char *str, int delim)
{
size_t len = strlen (str);
while (len && str[len-1] == '/')
len--;
str[len] = 0;
}
void
namespace_init (void)
{
int i;
int rc;
struct namespace_prefix *pfx;
if (mu_assoc_create (&prefixes, 0))
imap4d_bye (ERR_NO_MEM);
for (i = 0; i < NS_MAX; i++)
{
mu_iterator_t itr;
if (mu_list_is_empty (namespace[i].prefixes))
continue;
if (mu_list_get_iterator (namespace[i].prefixes, &itr))
imap4d_bye (ERR_NO_MEM);
for (mu_iterator_first (itr);
!mu_iterator_is_done (itr); mu_iterator_next (itr))
{
rc = mu_iterator_current (itr, (void **)&pfx);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_iterator_current", NULL, rc);
continue;
}
pfx->ns = i;
trim_delim (pfx->prefix, pfx->delim);
trim_delim (pfx->dir, '/');
rc = mu_assoc_install (prefixes, pfx->prefix, pfx);
if (rc == MU_ERR_EXISTS)
{
mu_error (_("%s: namespace prefix appears twice"), pfx->prefix);
exit (EX_CONFIG);
}
else if (rc)
{
mu_error (_("%s: can't install prefix: %s"),
pfx->prefix, mu_strerror (rc));
exit (EX_CONFIG);
}
}
}
pfx = mu_assoc_get (prefixes, "");
if (pfx)
{
if (pfx->ns != NS_PRIVATE)
{
mu_error (_("empty prefix not allowed in the namespace %s"),
namespace[pfx->ns].name);
exit (EX_CONFIG);
}
}
else
{
str += strlen (imap4d_homedir);
if (str[0] == '/')
str++;
struct namespace *priv;
pfx = mu_zalloc (sizeof (*pfx));
pfx->prefix = mu_strdup ("");
pfx->dir = mu_strdup ("$home");
pfx->delim = '/';
priv = namespace_lookup ("private");
mu_list_prepend (priv->prefixes, pfx);
rc = mu_assoc_install (prefixes, pfx->prefix, pfx);
if (rc)
{
mu_error (_("%s: can't install prefix: %s"),
pfx->prefix, mu_strerror (rc));
exit (EX_CONFIG);
}
}
return str;
mu_assoc_sort_r (prefixes, cmplen, NULL);
}
static int
print_namespace_fun (void *item, void *data)
expand_vars (char **env, char const *input, char **output)
{
int *pcount = data;
const char *dir = printable_pathname (item);
char *suf = (dir[0] && dir[strlen (dir) - 1] != '/') ? "/" : "";
if ((*pcount)++)
io_sendf (" ");
io_sendf ("(\"%s%s\" \"/\")", dir, suf);
struct mu_wordsplit ws;
size_t wordc;
char **wordv;
ws.ws_env = (const char **) env;
if (mu_wordsplit (input, &ws,
MU_WRDSF_NOSPLIT | MU_WRDSF_NOCMD |
MU_WRDSF_ENV | MU_WRDSF_ENV_KV))
{
mu_error (_("cannot expand line `%s': %s"), input,
mu_wordsplit_strerror (&ws));
return 1;
}
mu_wordsplit_get_words (&ws, &wordc, &wordv);
*output = wordv[0];
mu_wordsplit_free (&ws);
return 0;
}
static void
print_namespace (int nsid)
static char *
prefix_translate_name (struct namespace_prefix const *pfx, char const *name,
size_t namelen, int url)
{
mu_list_t list = namespace[nsid];
if (!list)
io_sendf ("NIL");
else
size_t pfxlen = strlen (pfx->prefix);
if (pfxlen <= namelen
&& memcmp (pfx->prefix, name, pfxlen) == 0
&& (pfxlen == 0 || pfxlen == namelen || name[pfxlen] == pfx->delim))
{
int count;
count = 0;
io_sendf ("(");
mu_list_foreach (list, print_namespace_fun, &count);
io_sendf (")");
char *tmpl, *p;
if (!pfx->scheme)
url = 0;
name += pfxlen;
if (pfx->ns == NS_PRIVATE && strcmp (name, "INBOX") == 0)
{
tmpl = mu_strdup (auth_data->mailbox);
return tmpl;//FIXME
}
tmpl = mu_alloc (namelen - pfxlen + strlen (pfx->dir)
+ (url ? strlen (pfx->scheme) + 3 : 0)
+ 2);
if (url)
{
p = mu_stpcpy (tmpl, pfx->scheme);
p = mu_stpcpy (p, "://");
}
else
p = tmpl;
p = mu_stpcpy (p, pfx->dir);
if (*name)
{
*p++ = '/';
translate_delim (p, name, '/', pfx->delim);
}
return tmpl;
}
return NULL;
}
struct ns_closure
static char *
i_translate_name (char const *name, int url, int ns,
struct namespace_prefix const **return_pfx)
{
int id;
nsfp_t fun;
void *closure;
};
mu_iterator_t itr;
int rc;
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)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_get_iterator", NULL, rc);
return NULL;
}
for (mu_iterator_first (itr);
!mu_iterator_is_done (itr); mu_iterator_next (itr))
{
struct namespace_prefix *pfx;
rc = mu_iterator_current (itr, (void **)&pfx);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_iterator_current", NULL, rc);
continue;
}
static int
_enum_fun (void *item, void *data)
{
struct ns_closure *nsp = data;
return nsp->fun (nsp->closure, nsp->id, (char*) item, '/');
if (ns != NS_MAX && ns != pfx->ns)
continue;
res = prefix_translate_name (pfx, name, namelen, url);
if (res)
{
if (return_pfx)
*return_pfx = pfx;
break;
}
}
mu_iterator_destroy (&itr);
return res;
}
static char *
extract_username (char const *name, struct namespace_prefix const *pfx)
{
char const *p = name + strlen (pfx->prefix);
char *end = strchr (p, pfx->delim);
char *user;
size_t len;
static int
namespace_enumerate (int id, nsfp_t f, void *closure)
if (end)
len = end - p;
else
len = strlen (p);
user = mu_alloc (len + 1);
memcpy (user, p, len);
user[len] = 0;
return user;
}
enum
{
ENV_USER = 1,
ENV_HOME = 3,
ENV_NULL = 4
};
#define ENV_INITIALIZER \
{ [ENV_USER-1] = "user", [ENV_HOME-1] = "home", [ENV_NULL] = NULL }
char *
namespace_translate_name (char const *name, int url,
struct namespace_prefix const **return_pfx)
{
struct ns_closure nsc;
char *res = NULL;
struct namespace_prefix const *pfx;
char *env[] = ENV_INITIALIZER;
if (name[0] == '~')
{
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);
}
else
res = i_translate_name (name, url, NS_MAX, &pfx);
nsc.id = id;
nsc.fun = f;
nsc.closure = closure;
if (namespace[id])
if (res)
{
int rc = mu_list_foreach (namespace[id], _enum_fun, &nsc);
if (rc == MU_ERR_USER0)
return 1;
else if (rc != 0)
char *dir;
switch (pfx->ns)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_list_foreach", NULL, rc);
return 0;
case NS_PRIVATE:
env[ENV_USER] = auth_data->name;
env[ENV_HOME] = real_homedir;
break;
case NS_SHARED:
{
struct mu_auth_data *adata;
env[ENV_USER] = extract_username (name, pfx);
adata = mu_get_auth_by_name (env[ENV_USER]);
if (adata)
{
env[ENV_HOME] = mu_strdup (adata->dir);
mu_auth_data_free (adata);
}
}
break;
case NS_OTHER:
break;
}
if (expand_vars (env, res, &dir))
imap4d_bye (ERR_NO_MEM);
free (res);
res = dir;
trim_delim (res, '/');
if (pfx->ns == NS_OTHER)
{
free (env[ENV_USER]);
free (env[ENV_HOME]);
}
if (return_pfx)
*return_pfx = pfx;
}
return 0;
return res;
}
char *
namespace_get_url (char const *name, int *mode)
{
struct namespace_prefix const *pfx;
char *path = namespace_translate_name (name, 1, &pfx);
if (path && pfx->scheme)
{
char *p = mu_alloc (strlen (pfx->scheme) + 3 + strlen (path) + 1);
strcpy (p, pfx->scheme);
strcat (p, "://");
strcat (p, path);
free (path);
path = p;
}
if (mode)
*mode = namespace[pfx->ns].mode;
return path;
}
static int
namespace_enumerate_all (nsfp_t f, void *closure)
prefix_printer(void *item, void *data)
{
return namespace_enumerate (NS_PRIVATE, f, closure)
|| namespace_enumerate (NS_OTHER, f, closure)
|| namespace_enumerate (NS_SHARED, f, closure);
struct namespace_prefix *pfx = item;
int *first = data;
if (*first)
*first = 0;
else
io_sendf (" ");
io_sendf ("(\"%s\" \"%c\")", pfx->prefix, pfx->delim);
return 0;
}
static void
print_namespace (int ns)
{
if (mu_list_is_empty (namespace[ns].prefixes))
io_sendf ("NIL");
else
{
int first = 1;
io_sendf ("(");
mu_list_foreach (namespace[ns].prefixes, prefix_printer, &first);
io_sendf (")");
}
}
/*
......@@ -139,153 +453,3 @@ imap4d_namespace (struct imap4d_session *session,
return io_completion_response (command, RESP_OK, "Completed");
}
struct namespace_info
{
char *name;
int namelen;
int ns;
int exact;
};
static int
check_namespace (void *closure, int ns, char *path, int delim)
{
struct namespace_info *p = (struct namespace_info *) closure;
int len = strlen (path);
if ((len == 0 && p->namelen == len)
|| (len > 0 && strncmp (path, p->name, strlen (path)) == 0))
{
p->ns = ns;
p->exact = len == p->namelen;
return MU_ERR_USER0;
}
return 0;
}
static int
risky_pattern (const char *pattern, int delim)
{
for (; *pattern && *pattern != delim; pattern++)
{
if (*pattern == '%' || *pattern == '*')
return 1;
}
return 0;
}
char *
namespace_checkfullpath (const char *name, const char *pattern,
int *nspace)
{
struct namespace_info info;
const char *p;
char *path = NULL;
char *scheme = NULL;
p = strchr (name, ':');
if (p)
{
size_t size = p - name + 1;
scheme = malloc (size + 1);
if (!scheme)
return NULL;
memcpy (scheme, name, size);
scheme[size] = 0;
name = p + 1;
}
path = util_getfullpath (name);
if (!path)
{
free (scheme);
return path;
}
info.name = path;
info.namelen = strlen (path);
if (!namespace_enumerate_all (check_namespace, &info))
{
free (scheme);
free (path);
return NULL;
}
if (pattern &&
info.ns == NS_OTHER && info.exact && risky_pattern (pattern, '/'))
{
free (scheme);
free (path);
return NULL;
}
if (nspace)
*nspace = info.ns;
if (scheme)
{
char *pathstr = malloc (strlen (scheme) + strlen (path) + 2);
if (pathstr)
{
strcpy (pathstr, scheme);
strcat (pathstr, path);
}
free (scheme);
free (path);
path = pathstr;
}
return path;
}
char *
namespace_getfullpath (const char *name, int *nspace)
{
char *ret;
if (mu_c_strcasecmp (name, "INBOX") == 0 && auth_data->change_uid)
{
ret = mu_strdup (auth_data->mailbox);
if (nspace)
*nspace = NS_PRIVATE;
}
else
ret = namespace_checkfullpath (name, NULL, nspace);
return ret;
}
int
namespace_init_session (char *path)
{
if (!namespace[NS_PRIVATE])
mu_list_create (&namespace[NS_PRIVATE]);
mu_list_prepend (namespace[NS_PRIVATE],
mu_strdup (mu_normalize_path (path)));
return 0;
}
static int
normalize_fun (void *item, void *data)
{
char *name = item;
mu_list_t list = data;
return mu_list_append (list,
mu_strdup (mu_normalize_path (name)));
}
void
namespace_init ()
{
int i;
for (i = 0; i < NS_MAX; i++)
{
if (namespace[i])
{
mu_list_t list;
mu_list_create (&list);
mu_list_set_destroy_item (list, mu_list_free_item);
mu_list_foreach (namespace[i], normalize_fun, list);
mu_list_set_destroy_item (namespace[i], mu_list_free_item);
mu_list_destroy (&namespace[i]);
namespace[i] = list;
}
}
}
......
......@@ -120,9 +120,9 @@ directory_size (const char *dirname, mu_off_t *size)
mu_off_t used_size;
void
quota_setup ()
quota_setup (void)
{
directory_size (imap4d_homedir, &used_size);
directory_size (real_homedir, &used_size);
}
int
......@@ -138,7 +138,7 @@ quota_check (mu_off_t size)
total = used_size;
mailbox_name = namespace_getfullpath ("INBOX", NULL);
mailbox_name = namespace_get_url ("INBOX", NULL);
rc = mu_mailbox_create (&mbox, mailbox_name);
if (rc)
{
......
......@@ -109,7 +109,7 @@ imap4d_rename (struct imap4d_session *session,
int rc = RESP_OK;
const char *msg = "Completed";
struct stat newst;
int ns;
int mode = 0;
if (imap4d_tokbuf_argc (tok) != 4)
return io_completion_response (command, RESP_BAD, "Invalid arguments");
......@@ -121,7 +121,7 @@ imap4d_rename (struct imap4d_session *session,
return io_completion_response (command, RESP_NO, "Name Inbox is reservered");
/* Allocates memory. */
newname = namespace_getfullpath (newname, &ns);
newname = namespace_get_url (newname, &mode);
if (!newname)
return io_completion_response (command, RESP_NO, "Permission denied");
......@@ -160,8 +160,7 @@ imap4d_rename (struct imap4d_session *session,
}
if (mu_mailbox_create (&newmbox, newname) != 0
|| mu_mailbox_open (newmbox,
MU_STREAM_CREAT | MU_STREAM_RDWR
| mailbox_mode[ns]) != 0)
MU_STREAM_CREAT | MU_STREAM_RDWR | mode) != 0)
{
free (newname);
return io_completion_response (command, RESP_NO,
......@@ -200,7 +199,7 @@ imap4d_rename (struct imap4d_session *session,
return io_completion_response (command, RESP_OK, "Rename successful");
}
oldname = namespace_getfullpath (oldname, NULL);
oldname = namespace_get_url (oldname, NULL);
/* It must exist. */
/* FIXME: 1. What if odlname or newname is a remote mailbox?
......
......@@ -59,7 +59,7 @@ imap4d_select0 (struct imap4d_command *command, const char *mboxname,
if (strcmp (mboxname, "INBOX") == 0)
flags |= MU_STREAM_CREAT;
mailbox_name = namespace_getfullpath (mboxname, NULL);
mailbox_name = namespace_translate_name (mboxname, 1, NULL);
if (!mailbox_name)
return io_completion_response (command, RESP_NO, "Couldn't open mailbox");
......
......@@ -81,7 +81,7 @@ imap4d_status (struct imap4d_session *session,
name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
mailbox_name = namespace_getfullpath (name, NULL);
mailbox_name = namespace_get_url (name, NULL);
if (!mailbox_name)
return io_completion_response (command, RESP_NO, "Error opening mailbox");
......
......@@ -28,7 +28,11 @@ EOT
MUT_MBCOPY($abs_top_srcdir/testsuite/spool/mbox1,INBOX)
imap4d IMAP4D_OPTIONS < input | remove_uidvalidity | tr -d '\r'
IMAP4D_RUN([1 select INBOX
2 FETCH 1:$MU_ULONG_MAX_1 FLAGS
3 UID FETCH 1:$MU_ULONG_MAX_1 FLAGS
X LOGOUT
],[expand]) | remove_uidvalidity
],
[0],
[* PREAUTH IMAP4rev1 Test mode
......
......@@ -20,14 +20,14 @@ AT_CHECK([
test "$MU_ULONG_MAX_1" = 0 && AT_SKIP_TEST
cat > input <<EOT
1 select INBOX
2 FETCH 1 BODY[[TEXT]]<0.$MU_ULONG_MAX_1>
X LOGOUT
EOT
MUT_MBCOPY($abs_top_srcdir/testsuite/spool/search.mbox,INBOX)
imap4d IMAP4D_OPTIONS < input | remove_uidvalidity | tr -d '\r'
IMAP4D_RUN([1 select INBOX
2 FETCH 1 BODY[[TEXT]]<0.$MU_ULONG_MAX_1>
X LOGOUT
],[expand]) | remove_uidvalidity
],
[0],
[* PREAUTH IMAP4rev1 Test mode
......
......@@ -17,8 +17,9 @@
AT_SETUP([append with flags])
AT_KEYWORDS([append00])
AT_DATA([input],
[1 APPEND mbox (\Seen) {300+}
AT_CHECK([
> mbox
IMAP4D_RUN([1 APPEND mbox (\Seen) {300+}
Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
From: Fred Foobar <foobar@Blurdybloop.COM>
Subject: afternoon meeting
......@@ -31,10 +32,6 @@ Hello Joe, do you think we can meet at 3:30 tomorrow
X LOGOUT
])
AT_CHECK([
> mbox
imap4d IMAP4D_OPTIONS < input | tr -d '\r'
echo "=="
awk 'NR==1 {print "1:",$1,$2; next} NF==0 {print NR":"; next} {print NR":",$0}' mbox
],
......
......@@ -17,8 +17,9 @@
AT_SETUP([append with envelope date])
AT_KEYWORDS([append01])
AT_DATA([input],
[1 APPEND mbox "25-Aug-2002 18:00:00 +0200" {274+}
AT_CHECK([
> mbox
IMAP4D_RUN([1 APPEND mbox "25-Aug-2002 18:00:00 +0200" {274+}
Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
From: Fred Foobar <foobar@Blurdybloop.COM>
Subject: afternoon meeting again
......@@ -31,10 +32,6 @@ Better yet at 04:00?
X LOGOUT
])
AT_CHECK([
> mbox
imap4d IMAP4D_OPTIONS < input | tr -d '\r'
echo "=="
awk 'NF==0 {print NR":"; next} {print NR":",$0}' mbox
],
......
......@@ -5,6 +5,35 @@
PATH=@abs_builddir@:@abs_top_builddir@/imap4d:$top_srcdir:$srcdir:$PATH
MU_ULONG_MAX_1=@MU_ULONG_MAX_1@
make_config() {
CWD=`pwd`
HOMEDIR=${CWD}${1:+/}$1
cat > imap4d.conf <<EOT
logging {
syslog off;
severity notice;
}
gsasl {
enable off;
}
namespace private {
prefix "" {
directory "$HOMEDIR";
}
prefix "~" {
directory "$HOMEDIR";
}
}
mailbox {
folder "$CWD";
mailbox-pattern "$CWD/INBOX";
}
EOT
}
remove_untagged() {
sed '/^\*/d'
}
......
......@@ -18,12 +18,9 @@ AT_SETUP([create])
AT_KEYWORDS([create create00])
AT_CHECK([
AT_DATA([input],[dnl
1 create flat
IMAP4D_RUN([1 create flat
X LOGOUT
])
imap4d IMAP4D_OPTIONS < input | tr -d '\r'
find . -name flat
],
[0],
......
......@@ -18,12 +18,9 @@ AT_SETUP([create nested])
AT_KEYWORDS([create create01])
AT_CHECK([
AT_DATA([input],[dnl
1 create en/to/tre
IMAP4D_RUN([1 create en/to/tre
X LOGOUT
])
imap4d IMAP4D_OPTIONS < input | tr -d '\r'
find . -name tre
],
[0],
......
......@@ -79,55 +79,35 @@ LIST_CHECK([empty ref + asterisk],[list02],
LIST_CHECK([root ref + asterisk],[list03],
["/" "*"],
[dnl
1 NO LIST The requested item could not be found.
* 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],
["$cwd/spool" "*"],
[dnl
* LIST (\NoInferiors) "/" ////bigto.mbox
* LIST (\NoInferiors) "/" ////folder/one
* LIST (\NoInferiors) "/" ////folder/two
* LIST (\NoInferiors) "/" ////mbox
* LIST (\NoInferiors) "/" ////mbox1
* LIST (\NoInferiors) "/" ////relational.mbox
* LIST (\NoInferiors) "/" ////search.mbox
* LIST (\NoInferiors) "/" ////sieve.mbox
* LIST (\NoInferiors) "/" ////teaparty.mbox
* LIST (\NoSelect) "/" ////folder
],
["/foo/bar/baz" "*"],
[],
[mkdir IMAP4D_HOMEDIR/folder
MUT_MBCOPY($abs_top_srcdir/testsuite/folder/one,IMAP4D_HOMEDIR/folder)
MUT_MBCOPY($abs_top_srcdir/testsuite/folder/two,IMAP4D_HOMEDIR/folder)],
[sed "s|$cwd/IMAP4D_HOMEDIR|///|"],
[expand])
MUT_MBCOPY($abs_top_srcdir/testsuite/folder/two,IMAP4D_HOMEDIR/folder)])
LIST_CHECK([absolute reference + percent],[list05],
["$cwd/spool" "%"],
[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 (\NoSelect) "/" ////folder
],
["/foo/bar/baz" "%"],
[],
[mkdir IMAP4D_HOMEDIR/folder
MUT_MBCOPY($abs_top_srcdir/testsuite/folder/one,IMAP4D_HOMEDIR/folder)
MUT_MBCOPY($abs_top_srcdir/testsuite/folder/two,IMAP4D_HOMEDIR/folder)],
[sed "s|$cwd/IMAP4D_HOMEDIR|///|"],
[expand])
MUT_MBCOPY($abs_top_srcdir/testsuite/folder/two,IMAP4D_HOMEDIR/folder)])
LIST_CHECK([absolute reference + mailbox],[list06],
["$cwd/spool" "search.mbox"],
[dnl
* LIST (\NoInferiors) "/" ////search.mbox
],
["/foo/bar/baz" "mbox"],
[],
[sed "s|$cwd/IMAP4D_HOMEDIR|///|"],
[expand])
[mkdir IMAP4D_HOMEDIR/folder
MUT_MBCOPY($abs_top_srcdir/testsuite/folder/one,IMAP4D_HOMEDIR/folder)
MUT_MBCOPY($abs_top_srcdir/testsuite/folder/two,IMAP4D_HOMEDIR/folder)])
LIST_CHECK([empty reference + INBOX],[list07],
["" INBOX],
......
......@@ -19,14 +19,9 @@ m4_include([testsuite.inc])
m4_define([IMAP4D_HOMEDIR])
m4_define([IMAP4D_DEFAULT_OPTIONS],[dnl
--no-site-config dnl
--no-config dnl
--config-file=imap4d.conf dnl
--test dnl
--set logging.syslog=0 dnl
--set logging.severity=notice dnl
--set .gsasl.enable=0 dnl
--set '|homedir='`pwd`m4_if([IMAP4D_HOMEDIR],,,/[IMAP4D_HOMEDIR]) dnl
--set '|mailbox|folder='`pwd` dnl
--set '|mailbox|mailbox-pattern='`pwd`/INBOX dnl
])
m4_define([IMAP4D_PREAUTH_OPTIONS],[dnl
......@@ -36,22 +31,27 @@ IMAP4D_DEFAULT_OPTIONS dnl
m4_define([IMAP4D_OPTIONS],[IMAP4D_PREAUTH_OPTIONS])
m4_define([IMAP4D_CONFIG],[make_config IMAP4D_HOMEDIR])
m4_define([IMAP4D_RUN],[IMAP4D_CONFIG
m4_if([$2],[expand],
[cat > input <<EOT
$1
EOT
],[dnl
AT_DATA([input],[$1])dnl
])
imap4d IMAP4D_OPTIONS < input | tr -d '\r'])
dnl ------------------------------------------------------------
dnl IMAP4D_CHECK([PREP], [INPUT], [STDOUT = `'], [STDERR = `'],
dnl [FILTER = `'],[expand])
dnl
m4_pushdef([IMAP4D_CHECK],[
cwd=`pwd`
m4_if([$6],,[dnl
AT_DATA([input],[$2])dnl
],[cat > input <<EOT
[$2]
EOT
])
$1
AT_CHECK([
imap4d IMAP4D_OPTIONS < input | tr -d '\r' | dnl
m4_if([$5],,[remove_uidvalidity],[$5])
IMAP4D_RUN([$2],[$6]) | m4_if([$5],,[remove_uidvalidity],[$5])
],
[0],
[$3],
......
......@@ -17,26 +17,6 @@
#include "imap4d.h"
/* Get the absolute path. */
/* NOTE: Path is allocated and must be free()d by the caller. */
char *
util_getfullpath (const char *name)
{
char *exp = mu_tilde_expansion (name, MU_HIERARCHY_DELIMITER,
imap4d_homedir);
if (*exp != MU_HIERARCHY_DELIMITER)
{
char *p, *s =
mu_alloc (strlen (imap4d_homedir) + 1 + strlen (exp) + 1);
p = mu_stpcpy (s, imap4d_homedir);
*p++ = MU_HIERARCHY_DELIMITER;
strcpy (p, exp);
free (exp);
exp = s;
}
return mu_normalize_path (exp);
}
int
util_do_command (struct imap4d_session *session, imap4d_tokbuf_t tok)
{
......