summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-03-26 21:12:03 +0200
committerSergey Poznyakoff <gray@gnu.org>2019-03-26 21:12:03 +0200
commit5b69ce81ec29afeea0e67bd8b0f0b193a7b0c022 (patch)
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.
-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.c120
-rw-r--r--libmailutils/tests/Makefile.am2
-rw-r--r--libmailutils/tests/fsfolder.c36
-rw-r--r--libmailutils/tests/fsfolder03.at44
-rw-r--r--libmailutils/tests/fsfolder04.at42
-rw-r--r--libmailutils/tests/testsuite.at2
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 (&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 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 (&reg_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)

Return to:

Send suggestions and report system problems to the System administrator.