diff options
-rw-r--r-- | include/mailutils/folder.h | 36 | ||||
-rw-r--r-- | include/mailutils/registrar.h | 1 | ||||
-rw-r--r-- | include/mailutils/sys/folder.h | 3 | ||||
-rw-r--r-- | libmailutils/base/registrar.c | 23 | ||||
-rw-r--r-- | libmailutils/mailbox/folder.c | 44 | ||||
-rw-r--r-- | libmailutils/mailbox/fsfolder.c | 118 | ||||
-rw-r--r-- | libmailutils/tests/fsfolder.c | 26 | ||||
-rw-r--r-- | libmailutils/tests/fsfolder00.at | 20 | ||||
-rw-r--r-- | libmailutils/tests/fsfolder02.at | 2 | ||||
-rw-r--r-- | libproto/imap/folder.c | 25 |
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); |