summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-03-23 11:02:38 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-03-23 11:10:18 (GMT)
commit15b4ea89880ea674717e9fa64e146dd744e8e35c (patch) (side-by-side diff)
treefe9e3285fa904cf5b64f6936541990d1a9143393
parent963add27d0c6b4361d78c30a1b5a362e2c7355e6 (diff)
downloadmailutils-15b4ea89880ea674717e9fa64e146dd744e8e35c.tar.gz
mailutils-15b4ea89880ea674717e9fa64e146dd744e8e35c.tar.bz2
Rewrite folder listing interface.
New function mu_folder_scan provides an improved scanning interface. In particular, it allows the user to abridge the scan to mailboxes of certain type (or types). Existing listing API functions are rewritten as alternative entry points to mu_folder_scan. * include/mailutils/folder.h (mu_folder_scanner): New struct. (mu_folder_scan): New function. * include/mailutils/registrar.h (mu_registrar_list_p): New function. * include/mailutils/sys/folder.h (_mu_folder._list): Change signature. * libmailutils/base/registrar.c (mu_registrar_list_p): New function. * libmailutils/mailbox/folder.c (mu_folder_scan): New function. (mu_folder_enumerate): Rewrite as entry point to mu_folder_scan. * libmailutils/mailbox/fsfolder.c: Use new API, * libmailutils/tests/fsfolder.c: Rewrite scheme matcher. * libmailutils/tests/fsfolder00.at: Fix test output. * libmailutils/tests/fsfolder02.at: Likewise. * libproto/imap/folder.c: Use new API.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/mailutils/folder.h36
-rw-r--r--include/mailutils/registrar.h1
-rw-r--r--include/mailutils/sys/folder.h3
-rw-r--r--libmailutils/base/registrar.c23
-rw-r--r--libmailutils/mailbox/folder.c44
-rw-r--r--libmailutils/mailbox/fsfolder.c118
-rw-r--r--libmailutils/tests/fsfolder.c26
-rw-r--r--libmailutils/tests/fsfolder00.at20
-rw-r--r--libmailutils/tests/fsfolder02.at2
-rw-r--r--libproto/imap/folder.c25
10 files changed, 194 insertions, 104 deletions
diff --git a/include/mailutils/folder.h b/include/mailutils/folder.h
index 1232798..4ca4b92 100644
--- a/include/mailutils/folder.h
+++ b/include/mailutils/folder.h
@@ -51,18 +51,42 @@ extern int mu_folder_delete (mu_folder_t, const char *);
extern int mu_folder_rename (mu_folder_t, const char *, const char *);
extern int mu_folder_subscribe (mu_folder_t, const char *);
extern int mu_folder_unsubscribe (mu_folder_t, const char *);
-extern int mu_folder_list (mu_folder_t, const char *, void *,
- size_t, mu_list_t *);
-extern int mu_folder_enumerate (mu_folder_t, const char *,
- void *, int,
- size_t, mu_list_t *,
- mu_folder_enumerate_fp, void *);
extern int mu_folder_lsub (mu_folder_t, const char *, const char *,
mu_list_t *);
extern int mu_folder_attach_ticket (mu_folder_t folder);
extern int mu_folder_is_local (mu_folder_t folder);
+ /* Scan API */
+/* The mu_folder_scanner structure controls the scanning. All of
+ members are optional. Unused ones must be initialized to 0.
+*/
+struct mu_folder_scanner
+{
+ char const *refname; /* Reference name */
+ void *pattern; /* Matching pattern */
+ int match_flags; /* Matching flags */
+ size_t max_level; /* Max. nesting level to descend */
+ mu_folder_enumerate_fp enumfun; /* Enumeration function */
+ void *enumdata; /* Data for enumfun */
+ mu_list_t records; /* List of allowed records */
+ mu_list_t result; /* Result list */
+};
+
+#define MU_FOLDER_SCANNER_INITIALIZER \
+ { NULL, NULL, 0, 0, NULL, NULL, NULL, NULL }
+
+int mu_folder_scan (mu_folder_t folder, struct mu_folder_scanner *scn);
+
+/* The following two functions are implemented as alternative entry
+ points to mu_folder_scan: */
+extern int mu_folder_list (mu_folder_t, const char *, void *,
+ size_t, mu_list_t *);
+extern int mu_folder_enumerate (mu_folder_t, const char *,
+ void *, int,
+ size_t, mu_list_t *,
+ mu_folder_enumerate_fp, void *);
+
/* Match function */
extern int mu_folder_set_match (mu_folder_t folder, mu_folder_match_fp pmatch);
extern int mu_folder_get_match (mu_folder_t folder,
diff --git a/include/mailutils/registrar.h b/include/mailutils/registrar.h
index 976e821..a2cd76b 100644
--- a/include/mailutils/registrar.h
+++ b/include/mailutils/registrar.h
@@ -93,6 +93,7 @@ int mu_record_get_mailer (mu_record_t, int (*(*)) (mu_mailer_t));
int mu_record_get_folder (mu_record_t, int (*(*)) (mu_folder_t));
int mu_record_list_p (mu_record_t record, const char *name, int);
+int mu_registrar_list_p (mu_list_t rlist, char const *name, int flags);
/* Records provided by the library. */
diff --git a/include/mailutils/sys/folder.h b/include/mailutils/sys/folder.h
index 050a18f..6dd2d45 100644
--- a/include/mailutils/sys/folder.h
+++ b/include/mailutils/sys/folder.h
@@ -49,8 +49,7 @@ struct _mu_folder
int (*_open) (mu_folder_t, int flag);
int (*_close) (mu_folder_t);
- int (*_list) (mu_folder_t, const char *, void *, int, size_t,
- mu_list_t, mu_folder_enumerate_fp, void *);
+ int (*_list) (mu_folder_t, struct mu_folder_scanner *);
int (*_lsub) (mu_folder_t, const char *, const char *,
mu_list_t);
mu_folder_match_fp _match;
diff --git a/libmailutils/base/registrar.c b/libmailutils/base/registrar.c
index da736a0..e25e6d8 100644
--- a/libmailutils/base/registrar.c
+++ b/libmailutils/base/registrar.c
@@ -400,6 +400,29 @@ mu_registrar_test_local_url (mu_url_t url, int *pres)
return 0;
}
+struct listable_closure
+{
+ char const *name;
+ int flags;
+};
+
+static int
+record_listable (void *item, void *data)
+{
+ mu_record_t record = item;
+ struct listable_closure *cls = data;
+ return !mu_record_list_p (record, cls->name, cls->flags);
+}
+
+int
+mu_registrar_list_p (mu_list_t rlist, char const *name, int flags)
+{
+ struct listable_closure cls = { name, flags };
+ if (!rlist)
+ rlist = registrar_list;
+ return !mu_list_foreach (rlist, record_listable, &cls);
+}
+
/* Apply flt to each record in the registry and remove those, for which it
returns non-zero. */
int
diff --git a/libmailutils/mailbox/folder.c b/libmailutils/mailbox/folder.c
index 9df89ed..8a474c8 100644
--- a/libmailutils/mailbox/folder.c
+++ b/libmailutils/mailbox/folder.c
@@ -343,6 +343,18 @@ mu_list_response_free (void *data)
}
int
+mu_folder_scan (mu_folder_t folder, struct mu_folder_scanner *scn)
+{
+ if (!folder || !scn)
+ return EINVAL;
+ if (folder->_list == NULL)
+ return ENOSYS;
+ if (scn->result)
+ mu_list_set_destroy_item (scn->result, mu_list_response_free);
+ return folder->_list (folder, scn);
+}
+
+int
mu_folder_list (mu_folder_t folder, const char *dirname, void *pattern,
size_t max_level,
mu_list_t *pflist)
@@ -360,29 +372,35 @@ mu_folder_enumerate (mu_folder_t folder, const char *name,
mu_folder_enumerate_fp enumfun, void *enumdata)
{
int status;
- if (folder == NULL)
+ if (folder == NULL || (!pflist && !enumfun))
return EINVAL;
else if (folder->_list == NULL)
return ENOSYS;
else
{
- mu_list_t list = NULL;
-
+ struct mu_folder_scanner scn;
+
+ scn.refname = name;
+ scn.pattern = pattern;
+ scn.match_flags = flags;
+ scn.max_level = max_level;
+ scn.enumfun = enumfun;
+ scn.enumdata = enumdata;
+ scn.records = NULL;
if (pflist)
{
- status = mu_list_create (&list);
+ status = mu_list_create (&scn.result);
if (status)
return status;
- *pflist = list;
- mu_list_set_destroy_item (list, mu_list_response_free);
}
- else if (!enumfun)
- return EINVAL;
-
- status = folder->_list (folder, name, pattern, flags, max_level,
- list, enumfun, enumdata);
- if (status)
- mu_list_destroy (pflist);
+ status = mu_folder_scan (folder, &scn);
+ if (status == 0)
+ {
+ if (pflist)
+ *pflist = scn.result;
+ }
+ else
+ mu_list_destroy (&scn.result);
}
return status;
}
diff --git a/libmailutils/mailbox/fsfolder.c b/libmailutils/mailbox/fsfolder.c
index 2b8aa2e..042ae67 100644
--- a/libmailutils/mailbox/fsfolder.c
+++ b/libmailutils/mailbox/fsfolder.c
@@ -183,18 +183,12 @@ struct inode_list /* Inode/dev number list used to cut off
dev_t dev;
};
-struct search_data
+struct folder_scan_data
{
- mu_list_t result;
- mu_folder_enumerate_fp enumfun;
- void *enumdata;
+ mu_folder_t folder;
char *dirname;
size_t dirlen;
- void *pattern;
- int flags;
- size_t max_level;
size_t errcnt;
- mu_folder_t folder;
};
static int
@@ -207,34 +201,28 @@ inode_list_lookup (struct inode_list *list, struct stat *st)
}
static int
-list_helper (struct search_data *data, mu_record_t record,
- const char *dirname, size_t level,
- struct inode_list *ilist)
+list_helper (struct mu_folder_scanner *scn,
+ struct folder_scan_data *data,
+ struct inode_list *ilist,
+ const char *dirname, size_t level)
{
DIR *dirp;
struct dirent *dp;
int stop = 0;
- if (data->max_level && level > data->max_level)
+ if (scn->max_level && level > scn->max_level)
return 0;
dirp = opendir (dirname);
if (dirp == NULL)
{
mu_debug (MU_DEBCAT_FOLDER, MU_DEBUG_ERROR,
- ("list_helper cannot open directory %s: %s",
- dirname, mu_strerror (errno)));
+ ("%s: %s(%s): %s",
+ __func__, "opendir", 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;
@@ -257,15 +245,16 @@ list_helper (struct search_data *data, mu_record_t record,
f = MU_FOLDER_ATTRIBUTE_LINK;
else
f = 0;
- if (mu_record_list_p (record, ename, f))
+ if (mu_registrar_list_p (scn->records, ename, f))
{
- if (data->folder->_match == NULL
+ if (scn->pattern == NULL
+ || 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)
+ scn->pattern,
+ scn->match_flags) == 0)
{
char *refname = fname;
int type = 0;
@@ -276,7 +265,7 @@ list_helper (struct search_data *data, mu_record_t record,
if (resp == NULL)
{
mu_debug (MU_DEBCAT_FOLDER, MU_DEBUG_ERROR,
- ("list_helper: %s", mu_strerror (ENOMEM)));
+ ("%s: %s", __func__, mu_strerror (ENOMEM)));
data->errcnt++;
free (fname);
continue;
@@ -284,6 +273,27 @@ list_helper (struct search_data *data, mu_record_t record,
mu_registrar_lookup (refname, MU_FOLDER_ATTRIBUTE_ALL,
&rec, &type);
+ if (scn->records)
+ {
+ int rc;
+ rc = mu_list_locate (scn->records, &rec, NULL);
+ if (rc)
+ {
+ if (rc != MU_ERR_NOENT)
+ mu_debug (MU_DEBCAT_FOLDER, MU_DEBUG_ERROR,
+ ("%s(%s):%s: %s",
+ __func__, dirname, "mu_list_locate",
+ mu_strerror (rc)));
+ continue;
+ }
+ }
+
+ if (type == 0)
+ {
+ free (fname);
+ free (resp);
+ continue;
+ }
resp->name = fname;
resp->level = level;
@@ -291,16 +301,9 @@ list_helper (struct search_data *data, mu_record_t record,
resp->type = type;
resp->format = rec;
- if (resp->type == 0)
+ if (scn->enumfun)
{
- free (resp->name);
- free (resp);
- continue;
- }
-
- if (data->enumfun)
- {
- if (data->enumfun (data->folder, resp, data->enumdata))
+ if (scn->enumfun (data->folder, resp, scn->enumdata))
{
free (resp->name);
free (resp);
@@ -309,10 +312,20 @@ list_helper (struct search_data *data, mu_record_t record,
}
}
- if (data->result)
+ if (scn->result)
{
+ int rc;
+ rc = mu_list_append (scn->result, resp);
+ if (rc)
+ mu_debug (MU_DEBCAT_FOLDER, MU_DEBUG_ERROR,
+ ("%s(%s):%s: %s",
+ __func__, dirname, "mu_list_append",
+ mu_strerror (rc)));
+
+ /* Prevent fname from being freed at the end of the
+ loop
+ */
fname = NULL;
- mu_list_append (data->result, resp);
}
else
free (resp);
@@ -325,8 +338,8 @@ list_helper (struct search_data *data, mu_record_t record,
idata.inode = st.st_ino;
idata.dev = st.st_dev;
idata.next = ilist;
- stop = list_helper (data, rec, refname, level + 1,
- &idata);
+ stop = list_helper (scn, data, &idata, refname,
+ level + 1);
}
}
else if (S_ISDIR (st.st_mode))
@@ -336,15 +349,15 @@ list_helper (struct search_data *data, mu_record_t record,
idata.inode = st.st_ino;
idata.dev = st.st_dev;
idata.next = ilist;
- stop = list_helper (data, NULL, fname, level + 1, &idata);
+ stop = list_helper (scn, data, &idata, fname, level + 1);
}
}
}
else
{
mu_debug (MU_DEBCAT_FOLDER, MU_DEBUG_ERROR,
- ("list_helper cannot stat %s: %s",
- fname, mu_strerror (errno)));
+ ("%s: lstat(%s): %s",
+ __func__, fname, mu_strerror (errno)));
}
free (fname);
}
@@ -353,29 +366,18 @@ list_helper (struct search_data *data, mu_record_t record,
}
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)
+_fsfolder_list (mu_folder_t folder, struct mu_folder_scanner *scn)
{
struct _mu_fsfolder *fsfolder = folder->data;
struct inode_list iroot;
- struct search_data sdata;
+ struct folder_scan_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.dirname = get_pathname (fsfolder->dirname, scn->refname);
+ sdata.dirlen = strlen (sdata.dirname);
sdata.errcnt = 0;
- list_helper (&sdata, NULL, sdata.dirname, 0, &iroot);
+ list_helper (scn, &sdata, &iroot, sdata.dirname, 0);
free (sdata.dirname);
/* FIXME: error code */
return 0;
diff --git a/libmailutils/tests/fsfolder.c b/libmailutils/tests/fsfolder.c
index 638f606..f6f62d7 100644
--- a/libmailutils/tests/fsfolder.c
+++ b/libmailutils/tests/fsfolder.c
@@ -19,6 +19,7 @@
#endif
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/folder.h>
@@ -182,7 +183,30 @@ usage ()
static int
_always_is_scheme (mu_record_t record, mu_url_t url, int flags)
{
- return 1;
+ int res = 0;
+ char const *p;
+ struct stat st;
+ int rc = mu_url_sget_path (url, &p);
+ if (rc)
+ {
+ mu_diag_funcall (MU_DIAG_ERROR, "mu_url_sget_path", NULL, rc);
+ return 0;
+ }
+
+ if (lstat (p, &st))
+ {
+ mu_diag_funcall (MU_DIAG_ERROR, "lstat", p, rc);
+ return 0;
+ }
+
+ if (S_ISDIR (st.st_mode))
+ res |= MU_FOLDER_ATTRIBUTE_DIRECTORY;
+ if (S_ISREG (st.st_mode))
+ res |= MU_FOLDER_ATTRIBUTE_FILE;
+ if (S_ISLNK (st.st_mode))
+ res |= MU_FOLDER_ATTRIBUTE_LINK;
+
+ return res & flags;
}
static struct _mu_record test_record =
diff --git a/libmailutils/tests/fsfolder00.at b/libmailutils/tests/fsfolder00.at
index eea9bf3..ed5f1f3 100644
--- a/libmailutils/tests/fsfolder00.at
+++ b/libmailutils/tests/fsfolder00.at
@@ -34,20 +34,20 @@ fsfolder -name=dir -sort dnl
],
[0],
[listing '' '*'
-d- / 0 dir/bar
-d- / 0 dir/foo
-d- / 0 dir/foo.mbox
+-f / 0 dir/bar
+-f / 0 dir/foo
+-f / 0 dir/foo.mbox
d- / 0 dir/subdir
-d- / 1 dir/subdir/baz.mbox
-d- / 1 dir/subdir/file
+-f / 1 dir/subdir/baz.mbox
+-f / 1 dir/subdir/file
listing 'subdir' '*'
-d- / 0 dir/subdir/baz.mbox
-d- / 0 dir/subdir/file
+-f / 0 dir/subdir/baz.mbox
+-f / 0 dir/subdir/file
listing '' '*.mbox'
-d- / 0 dir/foo.mbox
-d- / 1 dir/subdir/baz.mbox
+-f / 0 dir/foo.mbox
+-f / 1 dir/subdir/baz.mbox
listing 'subdir' '*.mbox'
-d- / 0 dir/subdir/baz.mbox
+-f / 0 dir/subdir/baz.mbox
])
AT_CLEANUP
diff --git a/libmailutils/tests/fsfolder02.at b/libmailutils/tests/fsfolder02.at
index dd8fb4f..a4a3013 100644
--- a/libmailutils/tests/fsfolder02.at
+++ b/libmailutils/tests/fsfolder02.at
@@ -29,7 +29,7 @@ fsfolder -name=dir rename bar baz
[renaming foo to bar
rename successful
listing '' '*'
-d- / 0 dir/bar
+-f / 0 dir/bar
renaming bar to baz
],
[fsfolder: mu_folder_rename(bar) failed: File exists
diff --git a/libproto/imap/folder.c b/libproto/imap/folder.c
index e8b94da..5e43312 100644
--- a/libproto/imap/folder.c
+++ b/libproto/imap/folder.c
@@ -261,21 +261,19 @@ _enumerate_helper (void *item, void *data)
return clos->fun (clos->folder, rp, clos->data);
}
+/* NOTE: scn->records is ignored */
static int
-_mu_imap_folder_list (mu_folder_t folder, const char *ref, void *name,
- int flags, size_t max_level,
- mu_list_t flist,
- mu_folder_enumerate_fp efp, void *edp)
+_mu_imap_folder_list (mu_folder_t folder, struct mu_folder_scanner *scn)
{
mu_imap_t imap = folder->data;
mu_list_t list;
- int rc = mu_imap_list_new (imap, ref, name, &list);
+ int rc = mu_imap_list_new (imap, scn->refname, scn->pattern, &list);
if (rc)
return rc;
- if (max_level ||
- (flags & MU_FOLDER_ATTRIBUTE_ALL) != MU_FOLDER_ATTRIBUTE_ALL)
+ if (scn->max_level
+ || (scn->match_flags & MU_FOLDER_ATTRIBUTE_ALL) != MU_FOLDER_ATTRIBUTE_ALL)
{
/* Filter out the list, eliminating non-matching entries */
mu_iterator_t itr;
@@ -293,25 +291,26 @@ _mu_imap_folder_list (mu_folder_t folder, const char *ref, void *name,
struct mu_list_response *rp;
mu_iterator_current (itr, (void**) &rp);
- if (!(rp->type & flags) || (max_level && rp->level > max_level))
+ if (!(rp->type & scn->match_flags)
+ || (scn->max_level && rp->level > scn->max_level))
mu_iterator_ctl (itr, mu_itrctl_delete, NULL);
}
mu_iterator_destroy (&itr);
}
- if (efp)
+ if (scn->enumfun)
{
struct enumerate_closure clos;
clos.folder = folder;
- clos.fun = efp;
- clos.data = edp;
+ clos.fun = scn->enumfun;
+ clos.data = scn->enumdata;
rc = mu_list_foreach (list, _enumerate_helper, &clos);
}
- if (flist)
- mu_list_append_list (flist, list);
+ if (scn->result)
+ mu_list_append_list (scn->result, list);
mu_list_destroy (&list);

Return to:

Send suggestions and report system problems to the System administrator.