summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-03-23 13:02:38 +0200
committerSergey Poznyakoff <gray@gnu.org>2019-03-23 13:10:18 +0200
commit15b4ea89880ea674717e9fa64e146dd744e8e35c (patch)
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.
-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 12327987d..4ca4b92ee 100644
--- a/include/mailutils/folder.h
+++ b/include/mailutils/folder.h
@@ -48,24 +48,48 @@ extern int mu_folder_open (mu_folder_t, int flag);
extern int mu_folder_close (mu_folder_t);
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,
mu_folder_match_fp *pmatch);
/* Two often used matchers: */
diff --git a/include/mailutils/registrar.h b/include/mailutils/registrar.h
index 976e82190..a2cd76b0b 100644
--- a/include/mailutils/registrar.h
+++ b/include/mailutils/registrar.h
@@ -90,12 +90,13 @@ int mu_record_get_mailbox (mu_record_t, int (*(*)) (mu_mailbox_t));
/* Mailer. */
int mu_record_get_mailer (mu_record_t, int (*(*)) (mu_mailer_t));
/* Folder. */
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. */
/* Remote Folder "imap://" */
extern mu_record_t mu_imap_record;
extern mu_record_t mu_imaps_record;
diff --git a/include/mailutils/sys/folder.h b/include/mailutils/sys/folder.h
index 050a18f97..6dd2d45da 100644
--- a/include/mailutils/sys/folder.h
+++ b/include/mailutils/sys/folder.h
@@ -46,14 +46,13 @@ struct _mu_folder
/* Public methods */
void (*_destroy) (mu_folder_t);
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;
int (*_delete) (mu_folder_t, const char *);
int (*_rename) (mu_folder_t, const char *, const char *);
int (*_subscribe) (mu_folder_t, const char *);
diff --git a/libmailutils/base/registrar.c b/libmailutils/base/registrar.c
index da736a07f..e25e6d810 100644
--- a/libmailutils/base/registrar.c
+++ b/libmailutils/base/registrar.c
@@ -397,12 +397,35 @@ mu_registrar_test_local_url (mu_url_t url, int *pres)
if (rc)
return rc;
*pres = mu_record_is_local (rec);
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
mu_registrar_apply_filter (int (*flt) (mu_record_t, void *), void *data)
{
mu_iterator_t iterator;
diff --git a/libmailutils/mailbox/folder.c b/libmailutils/mailbox/folder.c
index 9df89ed05..8a474c8f6 100644
--- a/libmailutils/mailbox/folder.c
+++ b/libmailutils/mailbox/folder.c
@@ -340,12 +340,24 @@ mu_list_response_free (void *data)
struct mu_list_response *f = data;
free (f->name);
free (f);
}
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)
{
return mu_folder_enumerate (folder, dirname, pattern,
MU_FOLDER_ATTRIBUTE_ALL, max_level,
@@ -357,35 +369,41 @@ mu_folder_enumerate (mu_folder_t folder, const char *name,
void *pattern, int flags,
size_t max_level,
mu_list_t *pflist,
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;
}
int
mu_folder_lsub (mu_folder_t folder, const char *dirname, const char *basename,
diff --git a/libmailutils/mailbox/fsfolder.c b/libmailutils/mailbox/fsfolder.c
index 2b8aa2e99..042ae6707 100644
--- a/libmailutils/mailbox/fsfolder.c
+++ b/libmailutils/mailbox/fsfolder.c
@@ -180,64 +180,52 @@ struct inode_list /* Inode/dev number list used to cut off
{
struct inode_list *next;
ino_t inode;
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
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)
+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;
char *fname;
struct stat st;
@@ -254,131 +242,145 @@ list_helper (struct search_data *data, mu_record_t record,
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 (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;
struct mu_list_response *resp;
mu_record_t rec = NULL;
resp = malloc (sizeof (*resp));
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;
}
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;
resp->separator = '/';
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);
stop = 1;
break;
}
}
- 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);
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);
+ stop = list_helper (scn, data, &idata, refname,
+ level + 1);
}
}
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);
+ 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);
}
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)
+_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;
}
static int
diff --git a/libmailutils/tests/fsfolder.c b/libmailutils/tests/fsfolder.c
index 638f606ea..f6f62d7b4 100644
--- a/libmailutils/tests/fsfolder.c
+++ b/libmailutils/tests/fsfolder.c
@@ -16,12 +16,13 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.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>
@@ -179,13 +180,36 @@ usage ()
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;
+ 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 =
{
0,
"file",
diff --git a/libmailutils/tests/fsfolder00.at b/libmailutils/tests/fsfolder00.at
index eea9bf32f..ed5f1f368 100644
--- a/libmailutils/tests/fsfolder00.at
+++ b/libmailutils/tests/fsfolder00.at
@@ -31,23 +31,23 @@ fsfolder -name=dir -sort 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
+-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 dd8fb4f8d..a4a301307 100644
--- a/libmailutils/tests/fsfolder02.at
+++ b/libmailutils/tests/fsfolder02.at
@@ -26,13 +26,13 @@ fsfolder -name=dir list "" "*"
fsfolder -name=dir rename bar baz
],
[0],
[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
])
AT_CLEANUP
diff --git a/libproto/imap/folder.c b/libproto/imap/folder.c
index e8b94da27..5e4331292 100644
--- a/libproto/imap/folder.c
+++ b/libproto/imap/folder.c
@@ -258,27 +258,25 @@ _enumerate_helper (void *item, void *data)
struct mu_list_response *rp = item;
struct enumerate_closure *clos = 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;
rc = mu_list_get_iterator (list, &itr);
if (rc)
@@ -290,31 +288,32 @@ _mu_imap_folder_list (mu_folder_t folder, const char *ref, void *name,
for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
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 rc;
}

Return to:

Send suggestions and report system problems to the System administrator.