Commit 33a5d852 33a5d85239028bc3e34eec59909253d12d5434f4 by Sergey Poznyakoff

Share folder implementation between mbox, mh and maildir. Fix mu_folder_delete.

* include/mailutils/folder.h (_mu_fsfolder_init): New proto.
* include/mailutils/mailbox.h (mu_mailbox_create_at): New proto.
* libmailutils/mailbox/mailbox.c (mu_mailbox_create_at): New function.
* libmailutils/mailbox/Makefile.am (libmailbox_la_SOURCES): Add fsfolder.c
* libmailutils/mailbox/folder.c (mu_folder_delete): If folder does
not provide its own method for deletion, use mu_mailbox_remove.
(mu_folder_open, mu_folder_close, mu_folder_enumerate)
(mu_folder_lsub, mu_folder_subscribe, mu_folder_unsubscribe)
(mu_folder_rename): Return EINVAL if folder is NULL.
(mu_folder_match): Bugfix: don't pass folder flags to fnmatch.
* libmailutils/mailbox/fsfolder.c: New file. Implementation of
file-system based folders.
* libmailutils/mailbox/mailbox (_create_mailbox0): Propagate error
return from mu_registrar_lookup_url.
* libmailutils/tests/fsfolder00.at: New test case.
* libmailutils/tests/fsfolder01.at: New test case.
* libmailutils/tests/fsfolder02.at: New test case.
* libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add fsfolder.
(TESTSUITE_AT): Add fsfolder tests.
* libmailutils/tests/testsuite.at: Include fsfolder tests.

* libproto/mbox/folder.c: Use fsfolder.
(_mh_is_scheme): Check file even if scheme matches.
* libproto/maildir/folder.c: Likewise.
(_maildir_is_scheme): Check file even if scheme matches.
* libproto/mh/folder.c: Likewise.

* testsuite/fldel.c: New file.
* testsuite/Makefile.am (noinst_PROGRAMS): Buld fldel.
1 parent a8374536
......@@ -92,6 +92,8 @@ extern int mu_folder_get_property (mu_folder_t, mu_property_t *);
extern int mu_folder_decrement (mu_folder_t);
extern void mu_list_response_free (void *data);
int _mu_fsfolder_init (mu_folder_t folder);
#ifdef __cplusplus
}
......
......@@ -43,6 +43,8 @@ extern int mu_mailbox_create_from_record (mu_mailbox_t *pmbox,
mu_record_t record,
const char *name);
extern int mu_mailbox_create_default (mu_mailbox_t *, const char *);
extern int mu_mailbox_create_at (mu_mailbox_t *pmbox, mu_folder_t folder,
const char *name);
extern void mu_mailbox_destroy (mu_mailbox_t *);
......
......@@ -25,6 +25,7 @@ libmailbox_la_SOURCES = \
body.c\
envelope.c\
folder.c\
fsfolder.c\
hdrfirst.c\
hdritr.c\
header.c\
......
......@@ -36,6 +36,7 @@
#include <mailutils/url.h>
#include <mailutils/errno.h>
#include <mailutils/property.h>
#include <mailutils/mailbox.h>
#include <mailutils/sys/folder.h>
......@@ -49,7 +50,7 @@ static struct mu_monitor folder_lock = MU_MONITOR_INITIALIZER;
int
mu_folder_match (const char *name, void *pattern, int flags)
{
return fnmatch (pattern, name[0] == '/' ? name + 1 : name, flags);
return fnmatch (pattern, name[0] == '/' ? name + 1 : name, 0);
}
/* A folder could be remote (IMAP), or local(a spool directory) like $HOME/Mail
......@@ -249,7 +250,9 @@ mu_folder_get_property (mu_folder_t folder, mu_property_t *prop)
int
mu_folder_open (mu_folder_t folder, int flags)
{
if (folder == NULL || folder->_open == NULL)
if (folder == NULL)
return EINVAL;
if (folder->_open == NULL)
return ENOSYS;
return folder->_open (folder, flags);
}
......@@ -257,7 +260,9 @@ mu_folder_open (mu_folder_t folder, int flags)
int
mu_folder_close (mu_folder_t folder)
{
if (folder == NULL || folder->_close == NULL)
if (folder == NULL)
return EINVAL;
if (folder->_close == NULL)
return ENOSYS;
return folder->_close (folder);
}
......@@ -381,8 +386,10 @@ mu_folder_enumerate (mu_folder_t folder, const char *name,
mu_folder_enumerate_fp enumfun, void *enumdata)
{
int status;
if (folder == NULL || folder->_list == NULL)
if (folder == NULL)
return EINVAL;
else if (folder->_list == NULL)
return ENOSYS;
else
{
mu_list_t list = NULL;
......@@ -412,7 +419,9 @@ mu_folder_lsub (mu_folder_t folder, const char *dirname, const char *basename,
{
int status;
if (folder == NULL || folder->_lsub == NULL)
if (folder == NULL)
return EINVAL;
else if (folder->_lsub == NULL)
return ENOSYS;
else
{
......@@ -428,31 +437,64 @@ mu_folder_lsub (mu_folder_t folder, const char *dirname, const char *basename,
int
mu_folder_subscribe (mu_folder_t folder, const char *name)
{
if (folder == NULL || folder->_subscribe == NULL)
if (folder == NULL)
return EINVAL;
if (folder->_subscribe == NULL)
return ENOSYS;
return folder->_subscribe (folder, name);
}
int
mu_folder_unsubscribe (mu_folder_t folder, const char *name)
{
if (folder == NULL || folder->_unsubscribe == NULL)
if (folder == NULL)
return EINVAL;
if (folder->_unsubscribe == NULL)
return ENOSYS;
return folder->_unsubscribe (folder, name);
}
int
mu_folder_delete (mu_folder_t folder, const char *name)
{
if (folder == NULL || folder->_delete == NULL)
return ENOSYS;
return folder->_delete (folder, name);
int rc;
if (folder == NULL)
return EINVAL;
if (folder->_delete)
rc = folder->_delete (folder, name);
else
{
/* If there is no folder-specific _delete method, then try to create the
mailbox and call mailbox delete (remove) method. This is necessary
because certain types of mailboxes share a common folder (e.g. mbox,
maildir and mh all use filesystem folder), but have a different
internal structure. Supplying mu_folder_t with a knowledge of mailbox
internals will harm separation of concerns. On the other hand,
removing something without looking into it may well yield 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.
To solve this 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)
{
rc = mu_mailbox_remove (mbox);
mu_mailbox_destroy (&mbox);
}
}
return rc;
}
int
mu_folder_rename (mu_folder_t folder, const char *oldname, const char *newname)
{
if (folder == NULL || folder->_rename == NULL)
if (folder == NULL)
return EINVAL;
if (folder->_rename == NULL)
return ENOSYS;
return folder->_rename (folder, oldname, newname);
}
......
/* Implementation of file-system folder for GNU Mailutils
Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008,
2010, 2011 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library. If not, see
<http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <glob.h>
#include <fnmatch.h>
#include <stdio.h>
#include <stdlib.h>
#include <mailutils/sys/folder.h>
#include <mailutils/sys/registrar.h>
#include <mailutils/auth.h>
#include <mailutils/url.h>
#include <mailutils/stream.h>
#include <mailutils/util.h>
#include <mailutils/errno.h>
#include <mailutils/debug.h>
#include <mailutils/property.h>
#include <mailutils/iterator.h>
/* File-system folder is shared between UNIX mbox, maildir and MH
mailboxes. It implements all usual folder methods, excepting
for _delete, which is implemented on the mailbox level. See
comment to mu_folder_delete in folder.c */
struct _mu_fsfolder
{
char *dirname;
mu_property_t subscription;
};
static int
open_subscription (struct _mu_fsfolder *folder)
{
int rc;
mu_property_t prop;
mu_stream_t str;
char *filename = mu_make_file_name (folder->dirname, ".mu-subscr");
rc = mu_file_stream_create (&str, filename, MU_STREAM_RDWR|MU_STREAM_CREAT);
if (rc)
return rc;
rc = mu_property_create_init (&prop, mu_assoc_property_init, str);
free (filename);
if (rc == 0)
folder->subscription = prop;
return rc;
}
static char *
get_pathname (const char *dirname, const char *basename)
{
char *pathname = NULL, *p;
/* Skip eventual protocol designator. */
p = strchr (dirname, ':');
if (p && p[1] == '/' && p[2] == '/')
dirname = p + 3;
/* null basename gives dirname. */
if (basename == NULL)
pathname = (dirname) ? strdup (dirname) : strdup (".");
/* Absolute. */
else if (basename[0] == '/')
pathname = strdup (basename);
/* Relative. */
else
{
size_t baselen = strlen (basename);
size_t dirlen = strlen (dirname);
while (dirlen > 0 && dirname[dirlen-1] == '/')
dirlen--;
pathname = calloc (dirlen + baselen + 2, sizeof (char));
if (pathname)
{
memcpy (pathname, dirname, dirlen);
pathname[dirlen] = '/';
strcpy (pathname + dirlen + 1, basename);
}
}
return pathname;
}
static void
_fsfolder_destroy (mu_folder_t folder)
{
if (folder->data)
{
struct _mu_fsfolder *fsfolder = folder->data;
free (fsfolder->dirname);
mu_property_destroy (&fsfolder->subscription);
free (folder->data);
folder->data = NULL;
}
}
/* Noop. */
static int
_fsfolder_open (mu_folder_t folder, int flags MU_ARG_UNUSED)
{
struct _mu_fsfolder *fsfolder = folder->data;
if (flags & MU_STREAM_CREAT)
{
return (mkdir (fsfolder->dirname, S_IRWXU) == 0) ? 0 : errno;
}
return 0;
}
/* Noop. */
static int
_fsfolder_close (mu_folder_t folder MU_ARG_UNUSED)
{
int rc = 0;
struct _mu_fsfolder *fsfolder = folder->data;
if (fsfolder->subscription)
rc = mu_property_save (fsfolder->subscription);
return rc;
}
static int
_fsfolder_rename (mu_folder_t folder, const char *oldpath,
const char *newpath)
{
struct _mu_fsfolder *fsfolder = folder->data;
if (oldpath && newpath)
{
int status = 0;
char *pathold = get_pathname (fsfolder->dirname, oldpath);
if (pathold)
{
char *pathnew = get_pathname (fsfolder->dirname, newpath);
if (pathnew)
{
if (access (pathnew, F_OK) == 0)
status = EEXIST;
else if (rename (pathold, pathnew) != 0)
status = errno;
free (pathnew);
}
else
status = ENOMEM;
free (pathold);
}
else
status = ENOMEM;
return status;
}
return EINVAL;
}
struct inode_list /* Inode/dev number list used to cut off
recursion */
{
struct inode_list *next;
ino_t inode;
dev_t dev;
};
struct search_data
{
mu_list_t result;
mu_folder_enumerate_fp enumfun;
void *enumdata;
char *dirname;
size_t dirlen;
void *pattern;
int flags;
size_t max_level;
size_t errcnt;
mu_folder_t folder;
};
static int
inode_list_lookup (struct inode_list *list, struct stat *st)
{
for (; list; list = list->next)
if (list->inode == st->st_ino && list->dev == st->st_dev)
return 1;
return 0;
}
static int
list_helper (struct search_data *data, mu_record_t record,
const char *dirname, size_t level,
struct inode_list *ilist)
{
DIR *dirp;
struct dirent *dp;
int stop = 0;
if (data->max_level && level > data->max_level)
return 0;
dirp = opendir (dirname);
if (dirp == NULL)
{
mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
("list_helper cannot open directory %s: %s",
dirname, mu_strerror (errno)));
data->errcnt++;
return 1;
}
if (!record)
{
int type;
mu_registrar_lookup (dirname, MU_FOLDER_ATTRIBUTE_ALL,
&record, &type);
}
while ((dp = readdir (dirp)))
{
char const *ename = dp->d_name;
char *fname;
struct stat st;
if (ename[ename[0] != '.' ? 0 : ename[1] != '.' ? 1 : 2] == 0)
continue;
if (strncmp (ename, ".mu-", 4) == 0)
continue;
fname = get_pathname (dirname, ename);
if (lstat (fname, &st) == 0)
{
int f;
if (S_ISDIR (st.st_mode))
f = MU_FOLDER_ATTRIBUTE_DIRECTORY;
else if (S_ISREG (st.st_mode))
f = MU_FOLDER_ATTRIBUTE_FILE;
else if (S_ISLNK (st.st_mode))
f = MU_FOLDER_ATTRIBUTE_LINK;
else
f = 0;
if (mu_record_list_p (record, ename, f))
{
if (data->folder->_match == NULL
|| data->folder->_match (fname + data->dirlen +
((data->dirlen > 1
&& data->dirname[data->dirlen-1] != '/') ?
1 : 0),
data->pattern,
data->flags) == 0)
{
char *refname = fname;
int type = 0;
struct mu_list_response *resp;
mu_record_t rec = NULL;
resp = malloc (sizeof (*resp));
if (resp == NULL)
{
mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
("list_helper: %s", mu_strerror (ENOMEM)));
data->errcnt++;
free (fname);
continue;
}
mu_registrar_lookup (refname, MU_FOLDER_ATTRIBUTE_ALL,
&rec, &type);
resp->name = fname;
resp->level = level;
resp->separator = '/';
resp->type = type;
resp->format = rec;
if (resp->type == 0)
{
free (resp->name);
free (resp);
continue;
}
if (data->enumfun)
{
if (data->enumfun (data->folder, resp, data->enumdata))
{
free (resp->name);
free (resp);
stop = 1;
break;
}
}
if (data->result)
{
fname = NULL;
mu_list_append (data->result, resp);
}
else
free (resp);
if ((type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
&& !inode_list_lookup (ilist, &st))
{
struct inode_list idata;
idata.inode = st.st_ino;
idata.dev = st.st_dev;
idata.next = ilist;
stop = list_helper (data, rec, refname, level + 1,
&idata);
}
}
else if (S_ISDIR (st.st_mode))
{
struct inode_list idata;
idata.inode = st.st_ino;
idata.dev = st.st_dev;
idata.next = ilist;
stop = list_helper (data, NULL, fname, level + 1, &idata);
}
}
}
else
{
mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
("list_helper cannot stat %s: %s",
fname, mu_strerror (errno)));
}
free (fname);
}
closedir (dirp);
return stop;
}
static int
_fsfolder_list (mu_folder_t folder, const char *ref,
void *pattern,
int flags,
size_t max_level,
mu_list_t flist,
mu_folder_enumerate_fp enumfun, void *enumdata)
{
struct _mu_fsfolder *fsfolder = folder->data;
struct inode_list iroot;
struct search_data sdata;
memset (&iroot, 0, sizeof iroot);
sdata.dirname = get_pathname (fsfolder->dirname, ref);
sdata.dirlen = strlen (sdata.dirname);
sdata.result = flist;
sdata.enumfun = enumfun;
sdata.enumdata = enumdata;
sdata.pattern = pattern;
sdata.flags = flags;
sdata.max_level = max_level;
sdata.folder = folder;
sdata.errcnt = 0;
list_helper (&sdata, NULL, sdata.dirname, 0, &iroot);
free (sdata.dirname);
/* FIXME: error code */
return 0;
}
static int
_fsfolder_lsub (mu_folder_t folder, const char *ref, const char *name,
mu_list_t flist)
{
struct _mu_fsfolder *fsfolder = folder->data;
int rc;
char *pattern;
mu_iterator_t itr;
if (name == NULL || *name == '\0')
name = "*";
if (!fsfolder->subscription && (rc = open_subscription (fsfolder)))
return rc;
pattern = mu_make_file_name (ref, name);
rc = mu_property_get_iterator (fsfolder->subscription, &itr);
if (rc == 0)
{
for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
const char *key, *val;
mu_iterator_current_kv (itr, (const void **)&key, (void**)&val);
if (fnmatch (pattern, key, 0) == 0)
{
struct mu_list_response *resp;
resp = malloc (sizeof (*resp));
if (resp == NULL)
{
rc = ENOMEM;
break;
}
else if ((resp->name = strdup (key)) == NULL)
{
free (resp);
rc = ENOMEM;
break;
}
resp->type = MU_FOLDER_ATTRIBUTE_FILE;
resp->level = 0;
resp->separator = '/';
rc = mu_list_append (flist, resp);
if (rc)
{
free (resp);
break;
}
}
}
mu_iterator_destroy (&itr);
}
free (pattern);
return rc;
}
static int
_fsfolder_subscribe (mu_folder_t folder, const char *name)
{
struct _mu_fsfolder *fsfolder = folder->data;
int rc;
if (!fsfolder->subscription && (rc = open_subscription (fsfolder)))
return rc;
return mu_property_set_value (fsfolder->subscription, name, "", 1);
}
static int
_fsfolder_unsubscribe (mu_folder_t folder, const char *name)
{
struct _mu_fsfolder *fsfolder = folder->data;
int rc;
if (!fsfolder->subscription && (rc = open_subscription (fsfolder)))
return rc;
return mu_property_unset (fsfolder->subscription, name);
}
static int
_fsfolder_get_authority (mu_folder_t folder, mu_authority_t *pauth)
{
int status = 0;
if (folder->authority == NULL)
status = mu_authority_create_null (&folder->authority, folder);
if (!status && pauth)
*pauth = folder->authority;
return status;
}
int
_mu_fsfolder_init (mu_folder_t folder)
{
struct _mu_fsfolder *dfolder;
int status = 0;
/* We create an authority so the API is uniform across the mailbox
types. */
status = _fsfolder_get_authority (folder, NULL);
if (status != 0)
return status;
dfolder = folder->data = calloc (1, sizeof (*dfolder));
if (dfolder == NULL)
return ENOMEM;
status = mu_url_aget_path (folder->url, &dfolder->dirname);
if (status == MU_ERR_NOENT)
{
dfolder->dirname = malloc (2);
if (dfolder->dirname == NULL)
status = ENOMEM;
else
{
strcpy (dfolder->dirname, ".");
status = 0;
}
}
if (status)
{
free (dfolder);
folder->data = NULL;
return status;
}
folder->_destroy = _fsfolder_destroy;
folder->_open = _fsfolder_open;
folder->_close = _fsfolder_close;
folder->_list = _fsfolder_list;
folder->_lsub = _fsfolder_lsub;
folder->_subscribe = _fsfolder_subscribe;
folder->_unsubscribe = _fsfolder_unsubscribe;
folder->_delete = NULL;
folder->_rename = _fsfolder_rename;
return 0;
}
......@@ -41,6 +41,7 @@
#include <mailutils/util.h>
#include <mailutils/sys/mailbox.h>
#include <mailutils/sys/folder.h>
#include <mailutils/sys/url.h>
/* Mailbox-specific flags */
......@@ -76,7 +77,8 @@ mailbox_folder_create (mu_mailbox_t mbox, const char *name,
int
_mailbox_create_from_record (mu_mailbox_t *pmbox,
mu_record_t record,
mu_url_t url,
mu_url_t url,
mu_folder_t folder,
const char *name)
{
int (*m_init) (mu_mailbox_t) = NULL;
......@@ -127,10 +129,16 @@ _mailbox_create_from_record (mu_mailbox_t *pmbox,
}
mbox->url = url;
/* Create the folder before initializing the concrete mailbox.
The mailbox needs it's back pointer. */
status = mailbox_folder_create (mbox, name, record);
if (folder)
{
folder->ref++; /* FIXME: No ref/unref function for folders */
mbox->folder = folder;
}
else
/* Create the folder before initializing the concrete mailbox.
The mailbox needs it's back pointer. */
status = mailbox_folder_create (mbox, name, record);
if (status == 0)
status = m_init (mbox); /* Create the concrete mailbox type. */
......@@ -152,11 +160,12 @@ static int
_create_mailbox0 (mu_mailbox_t *pmbox, mu_url_t url, const char *name)
{
mu_record_t record = NULL;
if (mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE, &record, NULL)
== 0)
return _mailbox_create_from_record (pmbox, record, url, name);
return ENOSYS;
int rc;
rc = mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE, &record, NULL);
if (rc == 0)
rc = _mailbox_create_from_record (pmbox, record, url, NULL, name);
return rc;
}
static int
......@@ -203,7 +212,71 @@ mu_mailbox_create_from_record (mu_mailbox_t *pmbox, mu_record_t record,
rc = mu_url_create (&url, name);
if (rc)
return rc;
rc = _mailbox_create_from_record (pmbox, record, url, name);
rc = _mailbox_create_from_record (pmbox, record, url, NULL, name);
if (rc)
mu_url_destroy (&url);
return rc;
}
int
mu_mailbox_create_at (mu_mailbox_t *pmbox, mu_folder_t folder,
const char *name)
{
int rc;
mu_url_t url;
const char *oldpath;
rc = mu_url_dup (folder->url, &url);
if (rc)
return rc;
do
{
char *path;
size_t oldlen, len;
mu_record_t record;
rc = mu_url_sget_path (url, &oldpath);
if (rc)
break;
oldlen = strlen (oldpath);
if (oldlen == 0)
{
path = strdup (name);
if (!path)
{
rc = ENOMEM;
break;
}
}
else
{
if (oldpath[oldlen-1] == '/')
oldlen--;
len = oldlen + 1 + strlen (name) + 1;
path = malloc (len);
if (!path)
{
rc = ENOMEM;
break;
}
memcpy (path, oldpath, oldlen);
path[oldlen++] = '/';
strcpy (path + oldlen, name);
}
rc = mu_url_set_path (url, path);
free (path);
if (rc)
break;
rc = mu_registrar_lookup_url (url, MU_FOLDER_ATTRIBUTE_FILE,
&record, NULL);
if (rc)
break;
rc = _mailbox_create_from_record (pmbox, record, url, folder, name);
}
while (0);
if (rc)
mu_url_destroy (&url);
return rc;
......@@ -314,7 +387,24 @@ mu_mailbox_remove (mu_mailbox_t mbox)
if (mbox->flags & _MU_MAILBOX_REMOVED)
return MU_ERR_MBX_REMOVED;
if (!mbox->_remove)
return MU_ERR_EMPTY_VFN;
{
/* Try the owning folder delete method. See comment to mu_folder_delete
in folder.c. This may result in a recursive call to mu_mailbox_remove
which is blocked by setting the _MU_MAILBOX_REMOVED flag. */
int rc;
const char *path;
rc = mu_url_sget_path (mbox->url, &path);
if (rc == 0)
{
mbox->flags |= _MU_MAILBOX_REMOVED;
rc = mu_folder_delete (mbox->folder, path);
if (rc)
mbox->flags &= ~_MU_MAILBOX_REMOVED;
}
return rc;
}
return mbox->_remove (mbox);
}
......@@ -689,7 +779,7 @@ mu_mailbox_set_folder (mu_mailbox_t mbox, mu_folder_t folder)
{
if (mbox == NULL)
return EINVAL;
mbox->folder = folder;
mbox->folder = folder;
return 0;
}
......
......@@ -12,6 +12,7 @@ decode2047
encode2047
fltst
fsaf
fsfolder
imapio
listop
mailcap
......
......@@ -47,6 +47,7 @@ noinst_PROGRAMS = \
encode2047\
fltst\
fsaf\
fsfolder\
imapio\
listop\
mailcap\
......@@ -78,6 +79,9 @@ TESTSUITE_AT = \
encode2047.at\
fromflt.at\
fsaf.at\
fsfolder00.at\
fsfolder01.at\
fsfolder02.at\
hdrflt.at\
imapio.at\
inline-comment.at\
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2011 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/folder.h>
#include <mailutils/stream.h>
#include <mailutils/stdstream.h>
#include <mailutils/list.h>
#include <mailutils/url.h>
#include <mailutils/util.h>
#include <mailutils/registrar.h>
#include <mailutils/sys/folder.h>
#include <mailutils/sys/registrar.h>
int sort_option;
int prefix_len;
struct command
{
char *verb;
int nargs;
char *args;
void (*handler) (mu_folder_t folder, char **argv);
};
static int
compare_response (void const *a, void const *b)
{
struct mu_list_response const *ra = a;
struct mu_list_response const *rb = b;
if (ra->level < rb->level)
return -1;
if (ra->level > rb->level)
return 1;
return strcmp (ra->name, rb->name);
}
static int
_print_list_entry (void *item, void *data)
{
struct mu_list_response *resp = item;
int len = data ? *(int*) data : 0;
mu_printf ("%c%c %c %4d %s\n",
(resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY) ? 'd' : '-',
(resp->type & MU_FOLDER_ATTRIBUTE_FILE) ? 'f' : '-',
resp->separator ? resp->separator : ' ',
resp->level,
resp->name + len);
return 0;
}
static void
com_list (mu_folder_t folder, char **argv)
{
int rc;
mu_list_t list;
mu_printf ("listing '%s' '%s'\n", argv[0], argv[1]);
rc = mu_folder_list (folder, argv[0], argv[1], 0, &list);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_list", argv[0], rc);
else
{
if (sort_option)
mu_list_sort (list, compare_response);
mu_list_foreach (list, _print_list_entry, &prefix_len);
mu_list_destroy (&list);
}
}
static void
com_lsub (mu_folder_t folder, char **argv)
{
int rc;
mu_list_t list;
mu_printf ("listing subscriptions for '%s' '%s'\n", argv[0], argv[1]);
rc = mu_folder_lsub (folder, argv[0], argv[1], &list);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_lsub", argv[0], rc);
else
{
if (sort_option)
mu_list_sort (list, compare_response);
mu_list_foreach (list, _print_list_entry, NULL);
mu_list_destroy (&list);
}
}
static void
com_rename (mu_folder_t folder, char **argv)
{
int rc;
mu_printf ("renaming %s to %s\n", argv[0], argv[1]);
rc = mu_folder_rename (folder, argv[0], argv[1]);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_rename", argv[0], rc);
else
mu_printf ("rename successful\n");
}
static void
com_subscribe (mu_folder_t folder, char **argv)
{
int rc;
mu_printf ("subscribing %s\n", argv[0]);
rc = mu_folder_subscribe (folder, argv[0]);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_subscribe", argv[0], rc);
else
mu_printf ("subscribe successful\n");
}
static void
com_unsubscribe (mu_folder_t folder, char **argv)
{
int rc;
mu_printf ("unsubscribing %s\n", argv[0]);
rc = mu_folder_unsubscribe (folder, argv[0]);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_unsubscribe", argv[0], rc);
else
mu_printf ("unsubscribe successful\n");
}
static struct command comtab[] = {
{ "list", 2, "REF MBX", com_list },
{ "lsub", 2, "REF MBX", com_lsub },
{ "rename", 2, "OLD NEW", com_rename },
{ "subscribe", 1, "MBX", com_subscribe },
{ "unsubscribe", 1, "MBX", com_unsubscribe },
{ NULL }
};
static struct command *
find_command (const char *name)
{
struct command *cp;
for (cp = comtab; cp->verb; cp++)
if (strcmp (cp->verb, name) == 0)
return cp;
return NULL;
}
static void
usage ()
{
struct command *cp;
mu_printf (
"usage: %s [debug=SPEC] name=URL OP ARG [ARG...] [OP ARG [ARG...]...]\n",
mu_program_name);
mu_printf ("OPerations and corresponding ARGuments are:\n");
for (cp = comtab; cp->verb; cp++)
mu_printf (" %s %s\n", cp->verb, cp->args);
}
static int
_always_is_scheme (mu_record_t record, mu_url_t url, int flags)
{
return 1;
}
static struct _mu_record test_record =
{
0,
"file",
MU_RECORD_LOCAL,
MU_URL_SCHEME | MU_URL_PATH,
MU_URL_PATH,
mu_url_expand_path, /* URL init. */
NULL, /* Mailbox init. */
NULL, /* Mailer init. */
_mu_fsfolder_init, /* Folder init. */
NULL, /* No need for an back pointer. */
_always_is_scheme, /* _is_scheme method. */
NULL, /* _get_url method. */
NULL, /* _get_mailbox method. */
NULL, /* _get_mailer method. */
NULL /* _get_folder method. */
};
int
main (int argc, char **argv)
{
int i;
int rc;
mu_folder_t folder;
char *fname = NULL;
mu_set_program_name (argv[0]);
mu_registrar_record (&test_record);
if (argc == 1)
{
usage ();
exit (0);
}
for (i = 1; i < argc; i++)
{
if (strncmp (argv[i], "debug=", 6) == 0)
mu_debug_parse_spec (argv[i] + 6);
else if (strncmp (argv[i], "name=", 5) == 0)
fname = argv[i] + 5;
else if (strcmp (argv[i], "sort") == 0)
sort_option = 1;
else
break;
}
if (!fname)
{
mu_error ("name not specified");
exit (1);
}
if (fname[0] != '/')
{
char *cwd = mu_getcwd ();
prefix_len = strlen (cwd);
if (cwd[prefix_len-1] != '/')
prefix_len++;
fname = mu_make_file_name (cwd, fname);
free (cwd);
}
rc = mu_folder_create (&folder, fname);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_create", fname, rc);
return 1;
}
rc = mu_folder_open (folder, MU_STREAM_READ);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_open", fname, rc);
return 1;
}
while (i < argc)
{
char *comargs[2];
struct command *cmd;
cmd = find_command (argv[i]);
if (!cmd)
{
mu_error ("unknown command %s\n", argv[i]);
break;
}
i++;
if (i + cmd->nargs > argc)
{
mu_error ("not enough arguments for %s", cmd->verb);
break;
}
memcpy (comargs, argv + i, cmd->nargs * sizeof (comargs[0]));
i += cmd->nargs;
cmd->handler (folder, comargs);
}
mu_folder_close (folder);
mu_folder_destroy (&folder);
return 0;
}
# This file is part of GNU Mailutils. -*- Autotest -*-
# Copyright (C) 2011 Free Software Foundation, Inc.
#
# GNU Mailutils is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or (at
# your option) any later version.
#
# GNU Mailutils is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
AT_SETUP([List])
AT_KEYWORDS([fsfolder folder-list])
AT_CHECK([
mkdir dir
> dir/foo
> dir/bar
> dir/foo.mbox
mkdir dir/subdir
> dir/subdir/file
> dir/subdir/baz.mbox
fsfolder name=dir sort dnl
list "" "*" dnl
list subdir "*" dnl
list "" "*.mbox" dnl
list "subdir" "*.mbox"
],
[0],
[listing '' '*'
d- / 0 dir/bar
d- / 0 dir/foo
d- / 0 dir/foo.mbox
d- / 0 dir/subdir
d- / 1 dir/subdir/baz.mbox
d- / 1 dir/subdir/file
listing 'subdir' '*'
d- / 0 dir/subdir/baz.mbox
d- / 0 dir/subdir/file
listing '' '*.mbox'
d- / 0 dir/foo.mbox
d- / 1 dir/subdir/baz.mbox
listing 'subdir' '*.mbox'
d- / 0 dir/subdir/baz.mbox
])
AT_CLEANUP
# This file is part of GNU Mailutils. -*- Autotest -*-
# Copyright (C) 2011 Free Software Foundation, Inc.
#
# GNU Mailutils is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or (at
# your option) any later version.
#
# GNU Mailutils is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
AT_SETUP([Subscriptions])
AT_KEYWORDS([fsfolder folder-subscribe])
AT_CHECK([
mkdir dir
fsfolder name=dir sort lsub "" "*"
fsfolder name=dir subscribe foo
fsfolder name=dir sort lsub "" "*"
fsfolder name=dir subscribe baz subscribe foo/baz subscribe foo/bar
fsfolder name=dir sort lsub "" "*"
fsfolder name=dir sort lsub foo "*"
fsfolder name=dir sort lsub "" 'foo*'
fsfolder name=dir unsubscribe baz
fsfolder name=dir sort lsub "" "*"
fsfolder name=dir unsubscribe foo
fsfolder name=dir sort lsub "" "*"
],
[0],
[listing subscriptions for '' '*'
subscribing foo
subscribe successful
listing subscriptions for '' '*'
-f / 0 foo
subscribing baz
subscribe successful
subscribing foo/baz
subscribe successful
subscribing foo/bar
subscribe successful
listing subscriptions for '' '*'
-f / 0 baz
-f / 0 foo
-f / 0 foo/bar
-f / 0 foo/baz
listing subscriptions for 'foo' '*'
-f / 0 foo/bar
-f / 0 foo/baz
listing subscriptions for '' 'foo*'
-f / 0 foo
-f / 0 foo/bar
-f / 0 foo/baz
unsubscribing baz
unsubscribe successful
listing subscriptions for '' '*'
-f / 0 foo
-f / 0 foo/bar
-f / 0 foo/baz
unsubscribing foo
unsubscribe successful
listing subscriptions for '' '*'
-f / 0 foo/bar
-f / 0 foo/baz
])
AT_CLEANUP
# This file is part of GNU Mailutils. -*- Autotest -*-
# Copyright (C) 2011 Free Software Foundation, Inc.
#
# GNU Mailutils is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or (at
# your option) any later version.
#
# GNU Mailutils is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
AT_SETUP([Rename])
AT_KEYWORDS([fsfolder folder-rename])
AT_CHECK([
mkdir dir
> dir/foo
fsfolder name=dir rename foo bar
fsfolder name=dir list "" "*"
> dir/baz
fsfolder name=dir rename bar baz
],
[0],
[renaming foo to bar
rename successful
listing '' '*'
d- / 0 dir/bar
renaming bar to baz
],
[fsfolder: mu_folder_rename(bar) failed: File exists
])
AT_CLEANUP
......@@ -68,6 +68,11 @@ m4_include([mailcap.at])
m4_include([wicket.at])
m4_include([prop.at])
AT_BANNER(File-system folder)
m4_include([fsfolder00.at])
m4_include([fsfolder01.at])
m4_include([fsfolder02.at])
AT_BANNER(Base64)
m4_include([base64e.at])
m4_include([base64d.at])
......
......@@ -133,7 +133,6 @@ static struct command comtab[] = {
{ "lsub", 2, "REF MBX", com_lsub },
{ "delete", 1, "MBX", com_delete },
{ "rename", 2, "OLD NEW", com_rename },
{ "delete", 1, "MBOX", com_delete },
{ "subscribe", 1, "MBX", com_subscribe },
{ "unsubscribe", 1, "MBX", com_unsubscribe },
{ NULL }
......
......@@ -37,12 +37,6 @@
#include <mailutils/sys/amd.h>
static int
_maildir_folder_init (mu_folder_t folder MU_ARG_UNUSED)
{
return 0;
}
static int
dir_exists (const char *name, const char *suf)
{
struct stat st;
......@@ -59,31 +53,42 @@ dir_exists (const char *name, const char *suf)
static int
_maildir_is_scheme (mu_record_t record, mu_url_t url, int flags)
{
if (mu_url_is_scheme (url, record->scheme))
return MU_FOLDER_ATTRIBUTE_FILE & flags;
if (mu_scheme_autodetect_p (url))
int scheme_matched = mu_url_is_scheme (url, record->scheme);
int rc = 0;
if (scheme_matched || mu_scheme_autodetect_p (url))
{
/* Attemp auto-detection */
const char *path;
struct stat st;
if (mu_url_sget_path (url, &path))
return 0;
if (stat (path, &st) < 0)
return 0;
{
if (errno == ENOENT && scheme_matched)
return MU_FOLDER_ATTRIBUTE_ALL & flags;
return 0;
}
if (!S_ISDIR (st.st_mode))
return 0;
if ((flags & MU_FOLDER_ATTRIBUTE_FILE)
&& dir_exists (path, TMPSUF)
&& dir_exists (path, CURSUF)
&& dir_exists (path, NEWSUF))
return MU_FOLDER_ATTRIBUTE_FILE|MU_FOLDER_ATTRIBUTE_DIRECTORY;
if (scheme_matched)
rc = MU_FOLDER_ATTRIBUTE_ALL;
else
{
rc |= MU_FOLDER_ATTRIBUTE_DIRECTORY;
if ((flags & MU_FOLDER_ATTRIBUTE_FILE)
&& dir_exists (path, TMPSUF)
&& dir_exists (path, CURSUF)
&& dir_exists (path, NEWSUF))
rc |= MU_FOLDER_ATTRIBUTE_FILE;
}
}
return 0;
return rc & flags;
}
static int
......@@ -106,7 +111,7 @@ static struct _mu_record _maildir_record =
mu_url_expand_path, /* Url init. */
_mailbox_maildir_init, /* Mailbox init. */
NULL, /* Mailer init. */
_maildir_folder_init, /* Folder init. */
_mu_fsfolder_init, /* Folder init. */
NULL, /* back pointer. */
_maildir_is_scheme, /* _is_scheme method. */
NULL, /* _get_url method. */
......
......@@ -49,19 +49,23 @@ static int
_mbox_is_scheme (mu_record_t record, mu_url_t url, int flags)
{
int rc = 0;
if (mu_url_is_scheme (url, record->scheme))
return MU_FOLDER_ATTRIBUTE_FILE & flags;
if (mu_scheme_autodetect_p (url))
int scheme_matched = mu_url_is_scheme (url, record->scheme);
if (scheme_matched || mu_scheme_autodetect_p (url))
{
struct stat st;
const char *path;
mu_url_sget_path (url, &path);
if (stat (path, &st) < 0)
return 0;
{
if (errno == ENOENT)
{
if (scheme_matched)
return MU_FOLDER_ATTRIBUTE_FILE & flags;
}
return 0;
}
if (S_ISREG (st.st_mode) || S_ISCHR (st.st_mode))
{
if (st.st_size == 0)
......@@ -71,7 +75,7 @@ _mbox_is_scheme (mu_record_t record, mu_url_t url, int flags)
else if (flags & MU_FOLDER_ATTRIBUTE_FILE)
{
#if 0
/* This effectively sieves out all non-mailbox files,
/* FIXME: This effectively sieves out all non-mailbox files,
but it makes mu_folder_enumerate crawl, which is
intolerable for imap4d LIST command. */
int fd = open (path, O_RDONLY);
......@@ -106,7 +110,7 @@ static struct _mu_record _mbox_record =
mu_url_expand_path, /* URL init. */
_mailbox_mbox_init, /* Mailbox init. */
NULL, /* Mailer init. */
_folder_mbox_init, /* Folder init. */
_mu_fsfolder_init, /* Folder init. */
NULL, /* No need for an back pointer. */
_mbox_is_scheme, /* _is_scheme method. */
NULL, /* _get_url method. */
......@@ -116,499 +120,4 @@ static struct _mu_record _mbox_record =
};
mu_record_t mu_mbox_record = &_mbox_record;
/* lsub/subscribe/unsubscribe are not needed. */
static void folder_mbox_destroy (mu_folder_t);
static int folder_mbox_open (mu_folder_t, int);
static int folder_mbox_close (mu_folder_t);
static int folder_mbox_delete (mu_folder_t, const char *);
static int folder_mbox_rename (mu_folder_t , const char *, const char *);
static int folder_mbox_list (mu_folder_t, const char *, void *, int,
size_t, mu_list_t, mu_folder_enumerate_fp,
void *);
static int folder_mbox_subscribe (mu_folder_t, const char *);
static int folder_mbox_unsubscribe (mu_folder_t, const char *);
static int folder_mbox_lsub (mu_folder_t, const char *, const char *,
mu_list_t);
static char *get_pathname (const char *, const char *);
static int folder_mbox_get_authority (mu_folder_t folder, mu_authority_t * pauth);
struct _fmbox
{
char *dirname;
char **subscribe;
size_t sublen;
};
typedef struct _fmbox *fmbox_t;
int
_folder_mbox_init (mu_folder_t folder)
{
fmbox_t dfolder;
int status = 0;
/* We create an authority so the API is uniform across the mailbox
types. */
status = folder_mbox_get_authority (folder, NULL);
if (status != 0)
return status;
dfolder = folder->data = calloc (1, sizeof (*dfolder));
if (dfolder == NULL)
return ENOMEM;
status = mu_url_aget_path (folder->url, &dfolder->dirname);
if (status == MU_ERR_NOENT)
{
dfolder->dirname = malloc (2);
if (dfolder->dirname == NULL)
status = ENOMEM;
else
{
strcpy (dfolder->dirname, ".");
status = 0;
}
}
if (status)
{
free (dfolder);
folder->data = NULL;
return status;
}
folder->_destroy = folder_mbox_destroy;
folder->_open = folder_mbox_open;
folder->_close = folder_mbox_close;
folder->_list = folder_mbox_list;
folder->_lsub = folder_mbox_lsub;
folder->_subscribe = folder_mbox_subscribe;
folder->_unsubscribe = folder_mbox_unsubscribe;
folder->_delete = folder_mbox_delete;
folder->_rename = folder_mbox_rename;
return 0;
}
void
folder_mbox_destroy (mu_folder_t folder)
{
if (folder->data)
{
fmbox_t fmbox = folder->data;
if (fmbox->dirname)
free (fmbox->dirname);
if (fmbox->subscribe)
free (fmbox->subscribe);
free (folder->data);
folder->data = NULL;
}
}
/* Noop. */
static int
folder_mbox_open (mu_folder_t folder, int flags MU_ARG_UNUSED)
{
fmbox_t fmbox = folder->data;
if (flags & MU_STREAM_CREAT)
{
return (mkdir (fmbox->dirname, S_IRWXU) == 0) ? 0 : errno;
}
return 0;
}
/* Noop. */
static int
folder_mbox_close (mu_folder_t folder MU_ARG_UNUSED)
{
return 0;
}
static int
folder_mbox_delete (mu_folder_t folder, const char *filename)
{
fmbox_t fmbox = folder->data;
if (filename)
{
int status = 0;
char *pathname = get_pathname (fmbox->dirname, filename);
if (pathname)
{
if (remove (pathname) != 0)
status = errno;
free (pathname);
}
else
status = ENOMEM;
return status;
}
return EINVAL;
}
static int
folder_mbox_rename (mu_folder_t folder, const char *oldpath,
const char *newpath)
{
fmbox_t fmbox = folder->data;
if (oldpath && newpath)
{
int status = 0;
char *pathold = get_pathname (fmbox->dirname, oldpath);
if (pathold)
{
char *pathnew = get_pathname (fmbox->dirname, newpath);
if (pathnew)
{
if (rename (pathold, pathnew) != 0)
status = errno;
free (pathnew);
}
else
status = ENOMEM;
free (pathold);
}
else
status = ENOMEM;
return status;
}
return EINVAL;
}
struct inode_list /* Inode/dev number list used to cut off
recursion */
{
struct inode_list *next;
ino_t inode;
dev_t dev;
};
struct search_data
{
mu_list_t result;
mu_folder_enumerate_fp enumfun;
void *enumdata;
char *dirname;
size_t dirlen;
void *pattern;
int flags;
size_t max_level;
size_t errcnt;
mu_folder_t folder;
};
static int
inode_list_lookup (struct inode_list *list, struct stat *st)
{
for (; list; list = list->next)
if (list->inode == st->st_ino && list->dev == st->st_dev)
return 1;
return 0;
}
static int
list_helper (struct search_data *data, mu_record_t record,
const char *dirname, size_t level,
struct inode_list *ilist)
{
DIR *dirp;
struct dirent *dp;
int stop = 0;
if (data->max_level && level > data->max_level)
return 0;
dirp = opendir (dirname);
if (dirp == NULL)
{
mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
("list_helper cannot open directory %s: %s",
dirname, mu_strerror (errno)));
data->errcnt++;
return 1;
}
if (!record)
{
int type;
mu_registrar_lookup (dirname, MU_FOLDER_ATTRIBUTE_ALL,
&record, &type);
}
while ((dp = readdir (dirp)))
{
char const *ename = dp->d_name;
char *fname;
struct stat st;
if (ename[ename[0] != '.' ? 0 : ename[1] != '.' ? 1 : 2] == 0)
continue;
fname = get_pathname (dirname, ename);
if (lstat (fname, &st) == 0)
{
int f;
if (S_ISDIR (st.st_mode))
f = MU_FOLDER_ATTRIBUTE_DIRECTORY;
else if (S_ISREG (st.st_mode))
f = MU_FOLDER_ATTRIBUTE_FILE;
else if (S_ISLNK (st.st_mode))
f = MU_FOLDER_ATTRIBUTE_LINK;
else
f = 0;
if (mu_record_list_p (record, ename, f))
{
if (data->folder->_match == NULL
|| data->folder->_match (fname + data->dirlen +
((data->dirlen > 1
&& data->dirname[data->dirlen-1] != '/') ?
1 : 0),
data->pattern,
data->flags) == 0)
{
char *refname = fname;
int type = 0;
struct mu_list_response *resp;
mu_record_t rec = NULL;
resp = malloc (sizeof (*resp));
if (resp == NULL)
{
mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
("list_helper: %s", mu_strerror (ENOMEM)));
data->errcnt++;
free (fname);
continue;
}
mu_registrar_lookup (refname, MU_FOLDER_ATTRIBUTE_ALL,
&rec, &type);
resp->name = fname;
resp->level = level;
resp->separator = '/';
resp->type = type;
resp->format = rec;
if (resp->type == 0)
{
free (resp->name);
free (resp);
continue;
}
if (data->enumfun)
{
if (data->enumfun (data->folder, resp, data->enumdata))
{
free (resp->name);
free (resp);
stop = 1;
break;
}
}
if (data->result)
{
fname = NULL;
mu_list_append (data->result, resp);
}
else
free (resp);
if ((type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
&& !inode_list_lookup (ilist, &st))
{
struct inode_list idata;
idata.inode = st.st_ino;
idata.dev = st.st_dev;
idata.next = ilist;
stop = list_helper (data, rec, refname, level + 1,
&idata);
}
}
else if (S_ISDIR (st.st_mode))
{
struct inode_list idata;
idata.inode = st.st_ino;
idata.dev = st.st_dev;
idata.next = ilist;
stop = list_helper (data, NULL, fname, level + 1, &idata);
}
}
}
else
{
mu_debug (MU_DEBCAT_MAILER, MU_DEBUG_ERROR,
("list_helper cannot stat %s: %s",
fname, mu_strerror (errno)));
}
free (fname);
}
closedir (dirp);
return stop;
}
static int
folder_mbox_list (mu_folder_t folder, const char *ref,
void *pattern,
int flags,
size_t max_level,
mu_list_t flist,
mu_folder_enumerate_fp enumfun, void *enumdata)
{
fmbox_t fmbox = folder->data;
struct inode_list iroot;
struct search_data sdata;
memset (&iroot, 0, sizeof iroot);
sdata.dirname = get_pathname (fmbox->dirname, ref);
sdata.dirlen = strlen (sdata.dirname);
sdata.result = flist;
sdata.enumfun = enumfun;
sdata.enumdata = enumdata;
sdata.pattern = pattern;
sdata.flags = flags;
sdata.max_level = max_level;
sdata.folder = folder;
sdata.errcnt = 0;
list_helper (&sdata, NULL, sdata.dirname, 0, &iroot);
free (sdata.dirname);
/* FIXME: error code */
return 0;
}
static int
folder_mbox_lsub (mu_folder_t folder, const char *ref MU_ARG_UNUSED,
const char *name,
mu_list_t flist)
{
fmbox_t fmbox = folder->data;
int status;
if (name == NULL || *name == '\0')
name = "*";
if (fmbox->sublen > 0)
{
size_t i;
for (i = 0; i < fmbox->sublen; i++)
{
if (fmbox->subscribe[i]
&& fnmatch (name, fmbox->subscribe[i], 0) == 0)
{
struct mu_list_response *resp;
resp = malloc (sizeof (*resp));
if (resp == NULL)
{
status = ENOMEM;
break;
}
else if ((resp->name = strdup (fmbox->subscribe[i])) == NULL)
{
free (resp);
status = ENOMEM;
break;
}
resp->type = MU_FOLDER_ATTRIBUTE_FILE;
resp->level = 0;
resp->separator = '/';
}
}
}
return status;
}
static int
folder_mbox_subscribe (mu_folder_t folder, const char *name)
{
fmbox_t fmbox = folder->data;
char **tmp;
size_t i;
for (i = 0; i < fmbox->sublen; i++)
{
if (fmbox->subscribe[i] && strcmp (fmbox->subscribe[i], name) == 0)
return 0;
}
tmp = realloc (fmbox->subscribe, (fmbox->sublen + 1) * sizeof (*tmp));
if (tmp == NULL)
return ENOMEM;
fmbox->subscribe = tmp;
fmbox->subscribe[fmbox->sublen] = strdup (name);
if (fmbox->subscribe[fmbox->sublen] == NULL)
return ENOMEM;
fmbox->sublen++;
return 0;
}
static int
folder_mbox_unsubscribe (mu_folder_t folder, const char *name)
{
fmbox_t fmbox = folder->data;
size_t i;
for (i = 0; i < fmbox->sublen; i++)
{
if (fmbox->subscribe[i] && strcmp (fmbox->subscribe[i], name) == 0)
{
free (fmbox->subscribe[i]);
fmbox->subscribe[i] = NULL;
return 0;
}
}
return MU_ERR_NOENT;
}
static char *
get_pathname (const char *dirname, const char *basename)
{
char *pathname = NULL;
/* Skip eventual protocol designator.
FIXME: Actually, any valid URL spec should be allowed as dirname ... */
if (strncmp (dirname, MU_MBOX_SCHEME, MU_MBOX_SCHEME_LEN) == 0)
dirname += MU_MBOX_SCHEME_LEN;
else if (strncmp (dirname, MU_FILE_SCHEME, MU_FILE_SCHEME_LEN) == 0)
dirname += MU_FILE_SCHEME_LEN;
/* null basename gives dirname. */
if (basename == NULL)
pathname = (dirname) ? strdup (dirname) : strdup (".");
/* Absolute. */
else if (basename[0] == '/')
pathname = strdup (basename);
/* Relative. */
else
{
size_t baselen = strlen (basename);
size_t dirlen = strlen (dirname);
while (dirlen > 0 && dirname[dirlen-1] == '/')
dirlen--;
pathname = calloc (dirlen + baselen + 2, sizeof (char));
if (pathname)
{
memcpy (pathname, dirname, dirlen);
pathname[dirlen] = '/';
strcpy (pathname + dirlen + 1, basename);
}
}
return pathname;
}
static int
folder_mbox_get_authority (mu_folder_t folder, mu_authority_t *pauth)
{
int status = 0;
if (folder->authority == NULL)
{
status = mu_authority_create_null (&folder->authority, folder);
}
if (!status && pauth)
*pauth = folder->authority;
return status;
}
......
......@@ -37,12 +37,6 @@
#include <mailutils/util.h>
#include <mailutils/cctype.h>
static int
_mh_folder_init (mu_folder_t folder MU_ARG_UNUSED)
{
return 0;
}
/* Check if NAME is a valid MH message name */
static int
mh_message_name_p (const char *name)
......@@ -90,13 +84,11 @@ static int
_mh_is_scheme (mu_record_t record, mu_url_t url, int flags)
{
int rc = 0;
int scheme_matched = mu_url_is_scheme (url, record->scheme);
if (mu_url_is_scheme (url, record->scheme))
return MU_FOLDER_ATTRIBUTE_ALL & flags;
if (mu_scheme_autodetect_p (url))
if (scheme_matched || mu_scheme_autodetect_p (url))
{
/* Attemp auto-detection */
/* Attempt auto-detection */
const char *path;
struct stat st;
......@@ -104,18 +96,27 @@ _mh_is_scheme (mu_record_t record, mu_url_t url, int flags)
return 0;
if (stat (path, &st) < 0)
return 0; /* mu_mailbox_open will complain*/
{
if (errno == ENOENT && scheme_matched)
return MU_FOLDER_ATTRIBUTE_ALL & flags;
return 0; /* mu_mailbox_open will complain*/
}
if (!S_ISDIR (st.st_mode))
return 0;
rc |= (MU_FOLDER_ATTRIBUTE_DIRECTORY & flags);
if (scheme_matched)
rc = MU_FOLDER_ATTRIBUTE_ALL;
else
{
rc |= MU_FOLDER_ATTRIBUTE_DIRECTORY;
if ((flags & MU_FOLDER_ATTRIBUTE_FILE) && mh_dir_p (path))
return rc | MU_FOLDER_ATTRIBUTE_FILE;
if ((flags & MU_FOLDER_ATTRIBUTE_FILE) && mh_dir_p (path))
rc |= MU_FOLDER_ATTRIBUTE_FILE;
}
}
return 0;
return rc & flags;
}
static int
......@@ -142,7 +143,7 @@ static struct _mu_record _mh_record =
mu_url_expand_path, /* Url init. */
_mailbox_mh_init, /* Mailbox init. */
NULL, /* Mailer init. */
_mh_folder_init, /* Folder init. */
_mu_fsfolder_init, /* Folder init. */
NULL, /* back pointer. */
_mh_is_scheme, /* _is_scheme method. */
NULL, /* _get_url method. */
......
atconfig
atlocal
fldel
package.m4
testsuite
testsuite.dir
......
......@@ -50,6 +50,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
INCLUDES = @MU_LIB_COMMON_INCLUDES@
noinst_PROGRAMS = \
fldel\
lstuid\
mbdel\
mimetest\
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010, 2011 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <mailutils/mailutils.h>
int
main (int argc, char **argv)
{
int rc;
mu_folder_t f;
if (argc != 3)
{
fprintf (stderr, "usage: %s URL NAME\n", argv[0]);
return 1;
}
mu_register_all_mbox_formats ();
MU_ASSERT (mu_folder_create (&f, argv[1]));
rc = mu_folder_delete (f, argv[2]);
if (rc)
{
if (rc == ENOTEMPTY)
{
printf ("mailbox removed, but has subfolders\n");
rc = 0;
}
else
fprintf (stderr, "%s\n", mu_strerror (rc));
}
mu_folder_destroy (&f);
return rc != 0;
}