summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
@@ -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 976e82190..a2cd76b0b 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 050a18f97..6dd2d45da 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 da736a07f..e25e6d810 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 9df89ed05..8a474c8f6 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 2b8aa2e99..042ae6707 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 638f606ea..f6f62d7b4 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 eea9bf32f..ed5f1f368 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 dd8fb4f8d..a4a301307 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 e8b94da27..5e4331292 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.