summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-03-26 19:12:03 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-03-26 19:12:03 (GMT)
commit5b69ce81ec29afeea0e67bd8b0f0b193a7b0c022 (patch) (side-by-side diff)
tree8e4579dde855742117781426ea92ab08bf0b6432
parent7a1b9263d79005cd66ed7ebdd8b8e2842e7cd6b3 (diff)
downloadmailutils-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.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/mailutils/list.h2
-rw-r--r--include/mailutils/registrar.h9
-rw-r--r--libmailutils/base/registrar.c63
-rw-r--r--libmailutils/mailbox/fsfolder.c182
-rw-r--r--libmailutils/tests/Makefile.am2
-rw-r--r--libmailutils/tests/fsfolder.c38
-rw-r--r--libmailutils/tests/fsfolder03.at44
-rw-r--r--libmailutils/tests/fsfolder04.at42
-rw-r--r--libmailutils/tests/testsuite.at2
9 files changed, 305 insertions, 79 deletions
diff --git a/include/mailutils/list.h b/include/mailutils/list.h
index e019132..2614a88 100644
--- a/include/mailutils/list.h
+++ b/include/mailutils/list.h
@@ -317,7 +317,7 @@ typedef int (*mu_list_folder_t) (void *_item, void *_data,
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
diff --git a/include/mailutils/registrar.h b/include/mailutils/registrar.h
index a2cd76b..a9e6212 100644
--- a/include/mailutils/registrar.h
+++ b/include/mailutils/registrar.h
@@ -74,8 +74,17 @@ 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. */
diff --git a/libmailutils/base/registrar.c b/libmailutils/base/registrar.c
index e25e6d8..debac37 100644
--- a/libmailutils/base/registrar.c
+++ b/libmailutils/base/registrar.c
@@ -446,3 +446,66 @@ mu_registrar_apply_filter (int (*flt) (mu_record_t, void *), void *data)
mu_monitor_unlock (&registrar_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 (&registrar_monitor);
+ rc = mu_list_map (registrar_list, select_match, &mc, 1, &lst);
+ mu_monitor_unlock (&registrar_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 30a706c..553c9fd 100644
--- a/libmailutils/mailbox/fsfolder.c
+++ b/libmailutils/mailbox/fsfolder.c
@@ -199,7 +199,97 @@ inode_list_lookup (struct inode_list *list, struct stat *st)
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,
@@ -260,6 +350,7 @@ list_helper (struct mu_folder_scanner *scn,
int type = 0;
struct mu_list_response *resp;
mu_record_t rec = NULL;
+ int rc;
resp = malloc (sizeof (*resp));
if (resp == NULL)
@@ -270,65 +361,56 @@ list_helper (struct mu_folder_scanner *scn,
free (fname);
continue;
}
-
- mu_registrar_lookup (refname, MU_FOLDER_ATTRIBUTE_ALL,
- &rec, &type);
+
if (scn->records)
+ rc = best_match (scn->records, refname, &rec, &type);
+ else
+ rc = mu_registrar_lookup (refname, MU_FOLDER_ATTRIBUTE_ALL,
+ &rec, &type);
+
+ if (rc || type == 0)
{
- 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;
+ if (f == MU_FOLDER_ATTRIBUTE_DIRECTORY)
+ type = f;
}
-
- resp->name = fname;
- resp->level = level;
- resp->separator = '/';
- resp->type = type;
- resp->format = rec;
-
- if (scn->enumfun)
+ else
{
- if (scn->enumfun (data->folder, resp, scn->enumdata))
+ resp->name = fname;
+ resp->level = level;
+ resp->separator = '/';
+ resp->type = type;
+ resp->format = rec;
+
+ if (scn->enumfun)
{
- free (resp->name);
- free (resp);
- stop = 1;
- break;
+ if (scn->enumfun (data->folder, resp, scn->enumdata))
+ {
+ free (resp->name);
+ free (resp);
+ stop = 1;
+ break;
+ }
}
- }
- 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;
+ 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;
+ }
+ else
+ free (resp);
}
- else
- free (resp);
if ((type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
&& !inode_list_lookup (ilist, &st))
diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am
index ef95577..b589c42 100644
--- a/libmailutils/tests/Makefile.am
+++ b/libmailutils/tests/Makefile.am
@@ -119,6 +119,8 @@ TESTSUITE_AT = \
fsfolder00.at\
fsfolder01.at\
fsfolder02.at\
+ fsfolder03.at\
+ fsfolder04.at\
hdrcpy.at\
hdrflt.at\
htmlent.at\
diff --git a/libmailutils/tests/fsfolder.c b/libmailutils/tests/fsfolder.c
index 8c25798..5a4d9df 100644
--- a/libmailutils/tests/fsfolder.c
+++ b/libmailutils/tests/fsfolder.c
@@ -152,28 +152,6 @@ com_unsubscribe (int argc, char **argv, mu_assoc_t options, void *env)
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)
{
@@ -205,9 +183,9 @@ com_scan (int argc, char **argv, mu_assoc_t options, void *env)
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));
@@ -215,7 +193,11 @@ com_scan (int argc, char **argv, mu_assoc_t options, void *env)
}
else
{
- mu_error ("%s: no such record found", s);
+ 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;
}
@@ -284,7 +266,7 @@ _always_is_scheme (mu_record_t record, mu_url_t url, int flags)
return res & flags;
}
-static struct _mu_record test_record =
+static struct _mu_record any_record =
{
10,
"any",
@@ -339,7 +321,7 @@ main (int argc, char **argv)
int glob_option = 0;
mu_tesh_init (argv[0]);
- mu_registrar_record (&test_record);
+ mu_registrar_record (&any_record);
mu_registrar_record (&reg_record);
if (argc == 1)
diff --git a/libmailutils/tests/fsfolder03.at b/libmailutils/tests/fsfolder03.at
new file mode 100644
index 0000000..8bf44b0
--- a/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 0000000..35b6842
--- a/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 5e302ee..05b77b1 100644
--- a/libmailutils/tests/testsuite.at
+++ b/libmailutils/tests/testsuite.at
@@ -198,6 +198,8 @@ 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])

Return to:

Send suggestions and report system problems to the System administrator.