diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2019-03-26 21:12:03 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2019-03-26 21:12:03 +0200 |
commit | 5b69ce81ec29afeea0e67bd8b0f0b193a7b0c022 (patch) | |
tree | 8e4579dde855742117781426ea92ab08bf0b6432 | |
parent | 7a1b9263d79005cd66ed7ebdd8b8e2842e7cd6b3 (diff) | |
download | mailutils-5b69ce81ec29afeea0e67bd8b0f0b193a7b0c022.tar.gz mailutils-5b69ce81ec29afeea0e67bd8b0f0b193a7b0c022.tar.bz2 |
Implement selection of requested mailbox formats in scanning the local file system folders.
* include/mailutils/registrar.h (mu_record_match): New struct.
(mu_registrar_match_records): New proto.
* libmailutils/base/registrar.c (mu_registrar_match_records): New
function.
* libmailutils/mailbox/fsfolder.c (list_helper): Actually select
the matching record from scn->records (if supplied).
* libmailutils/tests/Makefile.am: Add new tests.
* libmailutils/tests/fsfolder.c: Minor changes.
* libmailutils/tests/testsuite.at: Add new tests.
* libmailutils/tests/fsfolder03.at: New file.
* libmailutils/tests/fsfolder04.at: New file.
-rw-r--r-- | include/mailutils/list.h | 2 | ||||
-rw-r--r-- | include/mailutils/registrar.h | 9 | ||||
-rw-r--r-- | libmailutils/base/registrar.c | 63 | ||||
-rw-r--r-- | libmailutils/mailbox/fsfolder.c | 120 | ||||
-rw-r--r-- | libmailutils/tests/Makefile.am | 2 | ||||
-rw-r--r-- | libmailutils/tests/fsfolder.c | 36 | ||||
-rw-r--r-- | libmailutils/tests/fsfolder03.at | 44 | ||||
-rw-r--r-- | libmailutils/tests/fsfolder04.at | 42 | ||||
-rw-r--r-- | libmailutils/tests/testsuite.at | 2 |
9 files changed, 273 insertions, 47 deletions
diff --git a/include/mailutils/list.h b/include/mailutils/list.h index e01913283..2614a882a 100644 --- a/include/mailutils/list.h +++ b/include/mailutils/list.h @@ -314,13 +314,13 @@ typedef int (*mu_list_folder_t) (void *_item, void *_data, well. Possible return codes: 0 - success, EINVAL - _list or _fold is NULL, - MU_ERR_OUT_PTR_NULL - _return_code is NULL + MU_ERR_OUT_PTR_NULL - _return_value is NULL other value - non-zero value returned by _fold. The _fold function is not allowed to alter the list it is being applied to. The mu_list_rfold acts similarly, except that it iterates over list diff --git a/include/mailutils/registrar.h b/include/mailutils/registrar.h index a2cd76b0b..a9e621235 100644 --- a/include/mailutils/registrar.h +++ b/include/mailutils/registrar.h @@ -71,14 +71,23 @@ int mu_registrar_lookup_scheme (const char *scheme, int mu_registrar_lookup (const char *name, int flags, mu_record_t *precord, int *pflags); int mu_registrar_lookup_url (mu_url_t url, int flags, mu_record_t *precord, int *pflags); int mu_registrar_record (mu_record_t); int mu_unregistrar_record (mu_record_t); + int mu_registrar_apply_filter (int (*flt) (mu_record_t, void *), void *data); +struct mu_record_match +{ + mu_record_t record; + int flags; +}; + +int mu_registrar_match_records (char const *name, int flags, mu_list_t *ret); + int mu_record_is_local (mu_record_t); /* Scheme. */ int mu_record_is_scheme (mu_record_t, mu_url_t, int flags); /* Url. */ diff --git a/libmailutils/base/registrar.c b/libmailutils/base/registrar.c index e25e6d810..debac377d 100644 --- a/libmailutils/base/registrar.c +++ b/libmailutils/base/registrar.c @@ -443,6 +443,69 @@ mu_registrar_apply_filter (int (*flt) (mu_record_t, void *), void *data) mu_list_remove (registrar_list, record); } mu_iterator_destroy (&iterator); mu_monitor_unlock (®istrar_monitor); return 0; } + +struct match_closure +{ + mu_url_t url; + int flags; + int err; +}; + +static int +select_match (void **itmv, size_t itmc, void *call_data) +{ + struct match_closure *mc = call_data; + int rc = mu_record_is_scheme (itmv[0], mc->url, mc->flags); + if (rc) + { + struct mu_record_match *match = malloc (sizeof (*match)); + if (!match) + { + mc->err = errno; + return MU_LIST_MAP_STOP; + } + match->record = itmv[0]; + match->flags = rc; + itmv[0] = match; + return MU_LIST_MAP_OK; + } + return MU_LIST_MAP_SKIP; +} + +/* Select records matching pathname NAME with given FLAGS + (MU_FOLDER_ATTRIBUTE_* bitmask). On success, store each + match as a pointer to struct mu_record_match in *RET. +*/ +int +mu_registrar_match_records (char const *name, int flags, mu_list_t *ret) +{ + int rc; + struct match_closure mc; + mu_list_t lst; + + rc = mu_url_create (&mc.url, name); + if (rc) + return rc; + mc.flags = flags; + mc.err = 0; + + mu_monitor_wrlock (®istrar_monitor); + rc = mu_list_map (registrar_list, select_match, &mc, 1, &lst); + mu_monitor_unlock (®istrar_monitor); + mu_url_destroy (&mc.url); + if (rc == 0) + { + mu_list_set_destroy_item (lst, mu_list_free_item); + if (mc.err) + { + mu_list_destroy (&lst); + rc = mc.err; + } + } + if (rc == 0) + *ret = lst; + return rc; +} diff --git a/libmailutils/mailbox/fsfolder.c b/libmailutils/mailbox/fsfolder.c index 30a706c3b..553c9fddf 100644 --- a/libmailutils/mailbox/fsfolder.c +++ b/libmailutils/mailbox/fsfolder.c @@ -198,12 +198,102 @@ inode_list_lookup (struct inode_list *list, struct stat *st) if (list->inode == st->st_ino && list->dev == st->st_dev) return 1; return 0; } static int +fold_record_match (void *item, void *data, void *prev, void **ret) +{ + struct mu_record_match *cur_match = item; + struct mu_record_match *prev_match = prev; + if (prev == NULL || cur_match->flags >= prev_match->flags) + *ret = cur_match; + else + *ret = prev_match; + return 0; +} + +/* List item comparator for computing an intersection between a list + of mu_record_t objects and a list of struct mi_record_match pointers. +*/ +static int +mcomp (const void *a, const void *b) +{ + struct _mu_record const * r = a; + struct mu_record_match const *m = b; + return !(m->record == r); +} + +/* Find a record from RECORDS that is the best match for mailbox REFNAME. + Return the record found in PREC and mailbox attribute flags (the + MU_FOLDER_ATTRIBUTE_* bitmask) in PFLAGS. + + Return 0 on success, MU_ERR_NOENT if no match was found and mailutils + error code on error. + */ +static int +best_match (mu_list_t records, char const *refname, + mu_record_t *prec, int *pflags) +{ + int rc; + mu_list_t mlist, isect; + mu_list_comparator_t prev; + struct mu_record_match *m; + + rc = mu_registrar_match_records (refname, + MU_FOLDER_ATTRIBUTE_ALL, + &mlist); + if (rc) + { + mu_debug (MU_DEBCAT_FOLDER, MU_DEBUG_ERROR, + ("%s():%s: %s", + __func__, + "mu_registrar_match_records", + mu_strerror (rc))); + return rc; + } + + prev = mu_list_set_comparator (records, mcomp); + rc = mu_list_intersect (&isect, mlist, records); + mu_list_set_comparator (records, prev); + if (rc) + { + mu_debug (MU_DEBCAT_FOLDER, MU_DEBUG_ERROR, + ("%s():%s: %s", + __func__, + "mu_list_intersect", + mu_strerror (rc))); + mu_list_destroy (&mlist); + return rc; + } + + rc = mu_list_fold (isect, fold_record_match, NULL, NULL, &m); + if (rc == 0) + { + if (m == NULL) + rc = MU_ERR_NOENT; + else + { + *prec = m->record; + *pflags = m->flags; + } + } + else + { + mu_debug (MU_DEBCAT_FOLDER, MU_DEBUG_ERROR, + ("%s():%s: %s", + __func__, + "mu_list_fold", + mu_strerror (rc))); + } + mu_list_destroy (&mlist); + mu_list_destroy (&isect); + return rc; +} + +static int list_helper (struct mu_folder_scanner *scn, struct folder_scan_data *data, struct inode_list *ilist, const char *dirname, size_t level) { DIR *dirp; @@ -257,47 +347,38 @@ list_helper (struct mu_folder_scanner *scn, scn->match_flags) == 0) { char *refname = fname; int type = 0; struct mu_list_response *resp; mu_record_t rec = NULL; + int rc; resp = malloc (sizeof (*resp)); if (resp == NULL) { mu_debug (MU_DEBCAT_FOLDER, MU_DEBUG_ERROR, ("%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; - } - } + rc = best_match (scn->records, refname, &rec, &type); + else + rc = mu_registrar_lookup (refname, MU_FOLDER_ATTRIBUTE_ALL, + &rec, &type); - if (type == 0) + if (rc || type == 0) { - free (fname); free (resp); - continue; + if (f == MU_FOLDER_ATTRIBUTE_DIRECTORY) + type = f; } - + else + { resp->name = fname; resp->level = level; resp->separator = '/'; resp->type = type; resp->format = rec; @@ -326,12 +407,13 @@ list_helper (struct mu_folder_scanner *scn, loop */ fname = NULL; } else free (resp); + } if ((type & MU_FOLDER_ATTRIBUTE_DIRECTORY) && !inode_list_lookup (ilist, &st)) { struct inode_list idata; diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am index ef95577f9..b589c42cc 100644 --- a/libmailutils/tests/Makefile.am +++ b/libmailutils/tests/Makefile.am @@ -116,12 +116,14 @@ TESTSUITE_AT = \ fromflt.at\ fsaf.at\ fsaftomod.at\ fsfolder00.at\ fsfolder01.at\ fsfolder02.at\ + fsfolder03.at\ + fsfolder04.at\ hdrcpy.at\ hdrflt.at\ htmlent.at\ globtest.at\ imapio.at\ inline-comment.at\ diff --git a/libmailutils/tests/fsfolder.c b/libmailutils/tests/fsfolder.c index 8c2579838..5a4d9df7d 100644 --- a/libmailutils/tests/fsfolder.c +++ b/libmailutils/tests/fsfolder.c @@ -149,34 +149,12 @@ com_unsubscribe (int argc, char **argv, mu_assoc_t options, void *env) mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_unsubscribe", argv[1], rc); else mu_printf ("unsubscribe successful\n"); return 0; } -static mu_record_t -find_record (char const *scheme) -{ - mu_iterator_t itr; - mu_record_t result = NULL; - - MU_ASSERT (mu_registrar_get_iterator (&itr)); - for (mu_iterator_first (itr); !mu_iterator_is_done (itr); - mu_iterator_next (itr)) - { - mu_record_t rec; - mu_iterator_current (itr, (void **)&rec); - if (strcmp (rec->scheme, scheme) == 0) - { - result = rec; - break; - } - } - mu_iterator_destroy (&itr); - return result; -} - static int com_scan (int argc, char **argv, mu_assoc_t options, void *env) { mu_folder_t folder = env; struct mu_folder_scanner scn = MU_FOLDER_SCANNER_INITIALIZER; char *s; @@ -202,23 +180,27 @@ com_scan (int argc, char **argv, mu_assoc_t options, void *env) return 0; } } if (mu_assoc_lookup (options, "type", &s) == 0) { - mu_record_t rec = find_record (s); - - if (rec) + mu_record_t rec; + rc = mu_registrar_lookup_scheme (s, &rec); + if (rc == 0) { if (!scn.records) MU_ASSERT (mu_list_create (&scn.records)); MU_ASSERT (mu_list_append (scn.records, rec)); } else { + if (rc == MU_ERR_NOENT) mu_error ("%s: no such record found", s); + else + mu_diag_funcall (MU_DIAG_ERROR, "mu_registrar_lookup_scheme", + NULL, rc); mu_list_destroy (&scn.records); return 0; } } rc = mu_folder_scan (folder, &scn); @@ -281,13 +263,13 @@ _always_is_scheme (mu_record_t record, mu_url_t url, int flags) if (S_ISLNK (st.st_mode)) res |= MU_FOLDER_ATTRIBUTE_LINK; return res & flags; } -static struct _mu_record test_record = +static struct _mu_record any_record = { 10, "any", MU_RECORD_LOCAL, MU_URL_SCHEME | MU_URL_PATH, MU_URL_PATH, @@ -336,13 +318,13 @@ main (int argc, char **argv) int rc; mu_folder_t folder; char *fname = NULL; int glob_option = 0; mu_tesh_init (argv[0]); - mu_registrar_record (&test_record); + mu_registrar_record (&any_record); mu_registrar_record (®_record); if (argc == 1) { usage (); exit (0); diff --git a/libmailutils/tests/fsfolder03.at b/libmailutils/tests/fsfolder03.at new file mode 100644 index 000000000..8bf44b01d --- /dev/null +++ b/libmailutils/tests/fsfolder03.at @@ -0,0 +1,44 @@ +# This file is part of GNU Mailutils. -*- Autotest -*- +# Copyright (C) 2011-2019 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([Maxdepth]) +AT_KEYWORDS([fsfolder maxdepth]) + +AT_CHECK([mkdir dir +mkdir dir/a +mkdir dir/a/b +mkdir dir/a/b/c +mkdir dir/a/b/c/d +mkdir dir/b +mkdir dir/b/b +mkdir dir/b/c +echo maxdepth=1 +fsfolder -name=dir -sort scan -maxdepth=1 +echo maxdepth=2 +fsfolder -name=dir -sort scan -maxdepth=2 +], +[0], +[maxdepth=1 +d- / 0 dir/a +d- / 0 dir/b +maxdepth=2 +d- / 0 dir/a +d- / 0 dir/b +d- / 1 dir/a/b +d- / 1 dir/b/b +d- / 1 dir/b/c +]) +AT_CLEANUP diff --git a/libmailutils/tests/fsfolder04.at b/libmailutils/tests/fsfolder04.at new file mode 100644 index 000000000..35b6842e5 --- /dev/null +++ b/libmailutils/tests/fsfolder04.at @@ -0,0 +1,42 @@ +# This file is part of GNU Mailutils. -*- Autotest -*- +# Copyright (C) 2011-2019 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([Type selection]) +AT_KEYWORDS([fsfolder types]) + +AT_CHECK([mkdir dir +mkdir dir/a +> dir/1 +> dir/a/2 +mkdir dir/b +echo type=any +fsfolder -name=dir -sort scan -type=any +echo type=reg +fsfolder -name=dir -sort scan -type=reg +], +[0], +[type=any +-f / 0 dir/1 +d- / 0 dir/a +d- / 0 dir/b +-f / 1 dir/a/2 +type=reg +-f / 0 dir/1 +-f / 1 dir/a/2 +]) + +AT_CLEANUP + diff --git a/libmailutils/tests/testsuite.at b/libmailutils/tests/testsuite.at index 5e302ee6a..05b77b116 100644 --- a/libmailutils/tests/testsuite.at +++ b/libmailutils/tests/testsuite.at @@ -195,12 +195,14 @@ 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]) +m4_include([fsfolder03.at]) +m4_include([fsfolder04.at]) AT_BANNER(Base64) m4_include([base64e.at]) m4_include([base64d.at]) AT_BANNER(RFC 2047) |