summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2011-12-16 14:36:29 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2011-12-16 18:58:59 (GMT)
commit33a5d85239028bc3e34eec59909253d12d5434f4 (patch) (side-by-side diff)
tree5bd640ccf3988c2a616d7c44575c9be35e02f16f
parenta837453677a2888155aa565666acc956cdd3f896 (diff)
downloadmailutils-33a5d85239028bc3e34eec59909253d12d5434f4.tar.gz
mailutils-33a5d85239028bc3e34eec59909253d12d5434f4.tar.bz2
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.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/mailutils/folder.h2
-rw-r--r--include/mailutils/mailbox.h2
-rw-r--r--libmailutils/mailbox/Makefile.am1
-rw-r--r--libmailutils/mailbox/folder.c64
-rw-r--r--libmailutils/mailbox/fsfolder.c528
-rw-r--r--libmailutils/mailbox/mailbox.c116
-rw-r--r--libmailutils/tests/.gitignore1
-rw-r--r--libmailutils/tests/Makefile.am4
-rw-r--r--libmailutils/tests/fsfolder.c293
-rw-r--r--libmailutils/tests/fsfolder00.at53
-rw-r--r--libmailutils/tests/fsfolder01.at74
-rw-r--r--libmailutils/tests/fsfolder02.at39
-rw-r--r--libmailutils/tests/testsuite.at5
-rw-r--r--libproto/imap/tests/imapfolder.c1
-rw-r--r--libproto/maildir/folder.c45
-rw-r--r--libproto/mbox/folder.c517
-rw-r--r--libproto/mh/folder.c37
-rw-r--r--testsuite/.gitignore1
-rw-r--r--testsuite/Makefile.am1
-rw-r--r--testsuite/fldel.c54
20 files changed, 1271 insertions, 567 deletions
diff --git a/include/mailutils/folder.h b/include/mailutils/folder.h
index e8f6cb9..90e21b9 100644
--- a/include/mailutils/folder.h
+++ b/include/mailutils/folder.h
@@ -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
}
diff --git a/include/mailutils/mailbox.h b/include/mailutils/mailbox.h
index 8969859..f21dc89 100644
--- a/include/mailutils/mailbox.h
+++ b/include/mailutils/mailbox.h
@@ -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 *);
diff --git a/libmailutils/mailbox/Makefile.am b/libmailutils/mailbox/Makefile.am
index 27e6c04..cb9e775 100644
--- a/libmailutils/mailbox/Makefile.am
+++ b/libmailutils/mailbox/Makefile.am
@@ -25,6 +25,7 @@ libmailbox_la_SOURCES = \
body.c\
envelope.c\
folder.c\
+ fsfolder.c\
hdrfirst.c\
hdritr.c\
header.c\
diff --git a/libmailutils/mailbox/folder.c b/libmailutils/mailbox/folder.c
index 3314fcd..9d1fc1a 100644
--- a/libmailutils/mailbox/folder.c
+++ b/libmailutils/mailbox/folder.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);
}
diff --git a/libmailutils/mailbox/fsfolder.c b/libmailutils/mailbox/fsfolder.c
new file mode 100644
index 0000000..fb43e33
--- a/dev/null
+++ b/libmailutils/mailbox/fsfolder.c
@@ -0,0 +1,528 @@
+/* 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;
+}
+
diff --git a/libmailutils/mailbox/mailbox.c b/libmailutils/mailbox/mailbox.c
index a31682a..990ae6a 100644
--- a/libmailutils/mailbox/mailbox.c
+++ b/libmailutils/mailbox/mailbox.c
@@ -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;
}
diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore
index d67519f..6a1188d 100644
--- a/libmailutils/tests/.gitignore
+++ b/libmailutils/tests/.gitignore
@@ -12,6 +12,7 @@ decode2047
encode2047
fltst
fsaf
+fsfolder
imapio
listop
mailcap
diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am
index 1cb2968..aca151a 100644
--- a/libmailutils/tests/Makefile.am
+++ b/libmailutils/tests/Makefile.am
@@ -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\
diff --git a/libmailutils/tests/fsfolder.c b/libmailutils/tests/fsfolder.c
new file mode 100644
index 0000000..367106c
--- a/dev/null
+++ b/libmailutils/tests/fsfolder.c
@@ -0,0 +1,293 @@
+/* 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;
+}
diff --git a/libmailutils/tests/fsfolder00.at b/libmailutils/tests/fsfolder00.at
new file mode 100644
index 0000000..cf3ce90
--- a/dev/null
+++ b/libmailutils/tests/fsfolder00.at
@@ -0,0 +1,53 @@
+# 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
diff --git a/libmailutils/tests/fsfolder01.at b/libmailutils/tests/fsfolder01.at
new file mode 100644
index 0000000..ba7c79e
--- a/dev/null
+++ b/libmailutils/tests/fsfolder01.at
@@ -0,0 +1,74 @@
+# 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
+
+
+
diff --git a/libmailutils/tests/fsfolder02.at b/libmailutils/tests/fsfolder02.at
new file mode 100644
index 0000000..b6739b7
--- a/dev/null
+++ b/libmailutils/tests/fsfolder02.at
@@ -0,0 +1,39 @@
+# 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
+
diff --git a/libmailutils/tests/testsuite.at b/libmailutils/tests/testsuite.at
index 888c25a..4c1b427 100644
--- a/libmailutils/tests/testsuite.at
+++ b/libmailutils/tests/testsuite.at
@@ -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])
diff --git a/libproto/imap/tests/imapfolder.c b/libproto/imap/tests/imapfolder.c
index cb3a08b..d19b052 100644
--- a/libproto/imap/tests/imapfolder.c
+++ b/libproto/imap/tests/imapfolder.c
@@ -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 }
diff --git a/libproto/maildir/folder.c b/libproto/maildir/folder.c
index bba6848..df25e53 100644
--- a/libproto/maildir/folder.c
+++ b/libproto/maildir/folder.c
@@ -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. */
diff --git a/libproto/mbox/folder.c b/libproto/mbox/folder.c
index 2cc23bb..9e2c3f1 100644
--- a/libproto/mbox/folder.c
+++ b/libproto/mbox/folder.c
@@ -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;
-}
diff --git a/libproto/mh/folder.c b/libproto/mh/folder.c
index 66e02cf..4d9b43f 100644
--- a/libproto/mh/folder.c
+++ b/libproto/mh/folder.c
@@ -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. */
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
index 9db984b..29a9221 100644
--- a/testsuite/.gitignore
+++ b/testsuite/.gitignore
@@ -1,5 +1,6 @@
atconfig
atlocal
+fldel
package.m4
testsuite
testsuite.dir
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 1707985..e113ec8 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -50,6 +50,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
INCLUDES = @MU_LIB_COMMON_INCLUDES@
noinst_PROGRAMS = \
+ fldel\
lstuid\
mbdel\
mimetest\
diff --git a/testsuite/fldel.c b/testsuite/fldel.c
new file mode 100644
index 0000000..206f6b6
--- a/dev/null
+++ b/testsuite/fldel.c
@@ -0,0 +1,54 @@
+/* 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;
+}

Return to:

Send suggestions and report system problems to the System administrator.