[PATCH v6 0/7] notmuch search --output=sender/recipients
Michal Sojka
sojkam1 at fel.cvut.cz
Fri Oct 31 14:53:54 PDT 2014
Hi all,
this is v6 of the search --output=address series. It obsoletes v5
(id:1414713573-21461-1-git-send-email-sojkam1 at fel.cvut.cz).
Changes from v5 (full diff below):
- Added quoting of name parts if that is necessary (pointed out by
Mark Walters). Structured formats contain both full address
(possibly with quoted name) and unquoted individual fields.
- Fixed bug in --output=count --filter-by=*fold (reported by Jesse
Rosenthal). New test was added for this case. Fixing the bug also
resulted in simpler code :)
- Added missing unreferencing of InternetAddressList.
Changes from v4:
- patch changed to commit in commit messages
- opt->format changed to format
- Added comments to process_* functions
- duplicite changed to duplicate
- check_duplicate changed to is_duplicate
- Deduplication was split into two commits: basic deduplication
without a command line option and configurable deduplication with
--fiter-by.
Changes from v3:
- `o' renamed to `opt'.
- Conversion of --output from keyword to keyword-flags is now a
separate patch.
- Structured output formats print name and address separately.
- Added test for --format=json.
- Changed --filter-by default to nameaddr. In v2, the default was
addrfold, in v3 the default was no filtering at all. I believe that
Mark's suggestion to make nameaddr the default is good trade off.
- Added new --output=count
- Minor style fixes
- Few typos fixed
- There is no way to output unfiltered (duplicite) addresses.
Hopefully, the introduction of --output=count is sufficient
replacement for this "feature".
Cheers,
-Michal
Jani Nikula (1):
cli: Add support for parsing keyword-flag arguments
Michal Sojka (6):
cli: search: Refactor passing of command line options
cli: search: Convert --output to keyword-flag argument
cli: search: Add --output={sender,recipients}
cli: search: Do not output duplicate addresses
cli: search: Add --output=count
cli: search: Add --filter-by option to configure address filtering
command-line-arguments.c | 6 +-
command-line-arguments.h | 1 +
completion/notmuch-completion.bash | 8 +-
completion/notmuch-completion.zsh | 4 +-
doc/man1/notmuch-search.rst | 66 ++++++-
notmuch-search.c | 390 +++++++++++++++++++++++++++++--------
test/T090-search-output.sh | 87 +++++++++
test/T095-search-filter-by.sh | 73 +++++++
test/T410-argument-parsing.sh | 3 +-
test/arg-test.c | 9 +
10 files changed, 565 insertions(+), 82 deletions(-)
create mode 100755 test/T095-search-filter-by.sh
--
2.1.1
diff --git a/notmuch-search.c b/notmuch-search.c
index 8bc80d3..a350f06 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -246,33 +246,35 @@ is_duplicate (const search_options_t *opt, GHashTable *addrs, const char *name,
{
notmuch_bool_t duplicate;
char *key;
+ gchar *addrfold = NULL;
mailbox_t *mailbox;
if (opt->filter_by == FILTER_BY_ADDRFOLD ||
- opt->filter_by == FILTER_BY_NAMEADDRFOLD) {
- gchar *folded = g_utf8_casefold (addr, -1);
- addr = talloc_strdup (opt->format, folded);
- g_free (folded);
- }
+ opt->filter_by == FILTER_BY_NAMEADDRFOLD)
+ addrfold = g_utf8_casefold (addr, -1);
+
switch (opt->filter_by) {
case FILTER_BY_NAMEADDR:
- case FILTER_BY_NAMEADDRFOLD:
key = talloc_asprintf (opt->format, "%s <%s>", name, addr);
break;
+ case FILTER_BY_NAMEADDRFOLD:
+ key = talloc_asprintf (opt->format, "%s <%s>", name, addrfold);
+ break;
case FILTER_BY_NAME:
key = talloc_strdup (opt->format, name); /* !name results in !key */
break;
case FILTER_BY_ADDR:
- case FILTER_BY_ADDRFOLD:
key = talloc_strdup (opt->format, addr);
break;
+ case FILTER_BY_ADDRFOLD:
+ key = talloc_strdup (opt->format, addrfold);
+ break;
default:
INTERNAL_ERROR("invalid --filter-by flags");
}
- if (opt->filter_by == FILTER_BY_ADDRFOLD ||
- opt->filter_by == FILTER_BY_NAMEADDRFOLD)
- talloc_free ((char*)addr);
+ if (addrfold)
+ g_free (addrfold);
if (! key)
return FALSE;
@@ -300,33 +302,28 @@ print_mailbox (const search_options_t *opt, const mailbox_t *mailbox)
const char *addr = mailbox->addr;
int count = mailbox->count;
sprinter_t *format = opt->format;
+ InternetAddress *ia = internet_address_mailbox_new (name, addr);
+ char *name_addr;
- if (format->is_text_printer) {
- char *mailbox_str;
+ /* name_addr has the name part quoted if necessary. Compare
+ * 'John Doe <john at doe.com>' vs. '"Doe, John" <john at doe.com>' */
+ name_addr = internet_address_to_string (ia, FALSE);
- if (name && *name)
- mailbox_str = talloc_asprintf (format, "%s <%s>", name, addr);
- else
- mailbox_str = talloc_strdup (format, addr);
-
- if (! mailbox_str) {
- fprintf (stderr, "Error: out of memory\n");
- return;
- }
+ if (format->is_text_printer) {
if (count > 0) {
format->integer (format, count);
format->string (format, "\t");
}
- format->string (format, mailbox_str);
+ format->string (format, name_addr);
format->separator (format);
-
- talloc_free (mailbox_str);
} else {
format->begin_map (format);
format->map_key (format, "name");
format->string (format, name);
format->map_key (format, "address");
format->string (format, addr);
+ format->map_key (format, "name-addr");
+ format->string (format, name_addr);
if (count > 0) {
format->map_key (format, "count");
format->integer (format, count);
@@ -334,6 +331,9 @@ print_mailbox (const search_options_t *opt, const mailbox_t *mailbox)
format->end (format);
format->separator (format);
}
+
+ g_object_unref (ia);
+ g_free (name_addr);
}
/* Print or prepare for printing addresses from InternetAddressList. */
@@ -389,6 +389,8 @@ process_address_header (const search_options_t *opt, GHashTable *addrs, const ch
return;
process_address_list (opt, addrs, list);
+
+ g_object_unref (list);
}
static void
diff --git a/test/T090-search-output.sh b/test/T090-search-output.sh
index 5a9bbc9..82380ac 100755
--- a/test/T090-search-output.sh
+++ b/test/T090-search-output.sh
@@ -413,73 +413,23 @@ test_expect_equal_file OUTPUT EXPECTED
test_begin_subtest "--output=sender --format=json"
notmuch search --output=sender --format=json '*' >OUTPUT
cat <<EOF >EXPECTED
-[{"name": "François Boulogne", "address": "boulogne.f at gmail.com"},
-{"name": "Olivier Berger", "address": "olivier.berger at it-sudparis.eu"},
-{"name": "Chris Wilson", "address": "chris at chris-wilson.co.uk"},
-{"name": "Carl Worth", "address": "cworth at cworth.org"},
-{"name": "Alexander Botero-Lowry", "address": "alex.boterolowry at gmail.com"},
-{"name": "Keith Packard", "address": "keithp at keithp.com"},
-{"name": "Jjgod Jiang", "address": "gzjjgod at gmail.com"},
-{"name": "Rolland Santimano", "address": "rollandsantimano at yahoo.com"},
-{"name": "Jan Janak", "address": "jan at ryngle.com"},
-{"name": "Stewart Smith", "address": "stewart at flamingspork.com"},
-{"name": "Lars Kellogg-Stedman", "address": "lars at seas.harvard.edu"},
-{"name": "Alex Botero-Lowry", "address": "alex.boterolowry at gmail.com"},
-{"name": "Ingmar Vanhassel", "address": "ingmar at exherbo.org"},
-{"name": "Aron Griffis", "address": "agriffis at n01se.net"},
-{"name": "Adrian Perez de Castro", "address": "aperez at igalia.com"},
-{"name": "Israel Herraiz", "address": "isra at herraiz.org"},
-{"name": "Mikhail Gusarov", "address": "dottedmag at dottedmag.net"}]
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--output=sender --output=count"
-notmuch search --output=sender --output=count '*' | sort -n >OUTPUT
-cat <<EOF >EXPECTED
-1 Adrian Perez de Castro <aperez at igalia.com>
-1 Aron Griffis <agriffis at n01se.net>
-1 Chris Wilson <chris at chris-wilson.co.uk>
-1 François Boulogne <boulogne.f at gmail.com>
-1 Ingmar Vanhassel <ingmar at exherbo.org>
-1 Israel Herraiz <isra at herraiz.org>
-1 Olivier Berger <olivier.berger at it-sudparis.eu>
-1 Rolland Santimano <rollandsantimano at yahoo.com>
-2 Alex Botero-Lowry <alex.boterolowry at gmail.com>
-2 Jjgod Jiang <gzjjgod at gmail.com>
-3 Stewart Smith <stewart at flamingspork.com>
-4 Alexander Botero-Lowry <alex.boterolowry at gmail.com>
-4 Jan Janak <jan at ryngle.com>
-5 Lars Kellogg-Stedman <lars at seas.harvard.edu>
-5 Mikhail Gusarov <dottedmag at dottedmag.net>
-7 Keith Packard <keithp at keithp.com>
-12 Carl Worth <cworth at cworth.org>
-EOF
-test_expect_equal_file OUTPUT EXPECTED
-
-test_begin_subtest "--output=sender --output=count --format=json"
-# Since the iteration order of GHashTable is not specified, we
-# preprocess and sort the results to keep the order stable here.
-notmuch search --output=sender --output=count --format=json '*' | \
- sed -e 's/^\[//' -e 's/]$//' -e 's/,$//' | \
- sort --field-separator=":" --key=4n --key=2 >OUTPUT
-cat <<EOF >EXPECTED
-{"name": "Adrian Perez de Castro", "address": "aperez at igalia.com", "count": 1}
-{"name": "Aron Griffis", "address": "agriffis at n01se.net", "count": 1}
-{"name": "Chris Wilson", "address": "chris at chris-wilson.co.uk", "count": 1}
-{"name": "François Boulogne", "address": "boulogne.f at gmail.com", "count": 1}
-{"name": "Ingmar Vanhassel", "address": "ingmar at exherbo.org", "count": 1}
-{"name": "Israel Herraiz", "address": "isra at herraiz.org", "count": 1}
-{"name": "Olivier Berger", "address": "olivier.berger at it-sudparis.eu", "count": 1}
-{"name": "Rolland Santimano", "address": "rollandsantimano at yahoo.com", "count": 1}
-{"name": "Alex Botero-Lowry", "address": "alex.boterolowry at gmail.com", "count": 2}
-{"name": "Jjgod Jiang", "address": "gzjjgod at gmail.com", "count": 2}
-{"name": "Stewart Smith", "address": "stewart at flamingspork.com", "count": 3}
-{"name": "Alexander Botero-Lowry", "address": "alex.boterolowry at gmail.com", "count": 4}
-{"name": "Jan Janak", "address": "jan at ryngle.com", "count": 4}
-{"name": "Lars Kellogg-Stedman", "address": "lars at seas.harvard.edu", "count": 5}
-{"name": "Mikhail Gusarov", "address": "dottedmag at dottedmag.net", "count": 5}
-{"name": "Keith Packard", "address": "keithp at keithp.com", "count": 7}
-{"name": "Carl Worth", "address": "cworth at cworth.org", "count": 12}
+[{"name": "François Boulogne", "address": "boulogne.f at gmail.com", "name-addr": "François Boulogne <boulogne.f at gmail.com>"},
+{"name": "Olivier Berger", "address": "olivier.berger at it-sudparis.eu", "name-addr": "Olivier Berger <olivier.berger at it-sudparis.eu>"},
+{"name": "Chris Wilson", "address": "chris at chris-wilson.co.uk", "name-addr": "Chris Wilson <chris at chris-wilson.co.uk>"},
+{"name": "Carl Worth", "address": "cworth at cworth.org", "name-addr": "Carl Worth <cworth at cworth.org>"},
+{"name": "Alexander Botero-Lowry", "address": "alex.boterolowry at gmail.com", "name-addr": "Alexander Botero-Lowry <alex.boterolowry at gmail.com>"},
+{"name": "Keith Packard", "address": "keithp at keithp.com", "name-addr": "Keith Packard <keithp at keithp.com>"},
+{"name": "Jjgod Jiang", "address": "gzjjgod at gmail.com", "name-addr": "Jjgod Jiang <gzjjgod at gmail.com>"},
+{"name": "Rolland Santimano", "address": "rollandsantimano at yahoo.com", "name-addr": "Rolland Santimano <rollandsantimano at yahoo.com>"},
+{"name": "Jan Janak", "address": "jan at ryngle.com", "name-addr": "Jan Janak <jan at ryngle.com>"},
+{"name": "Stewart Smith", "address": "stewart at flamingspork.com", "name-addr": "Stewart Smith <stewart at flamingspork.com>"},
+{"name": "Lars Kellogg-Stedman", "address": "lars at seas.harvard.edu", "name-addr": "Lars Kellogg-Stedman <lars at seas.harvard.edu>"},
+{"name": "Alex Botero-Lowry", "address": "alex.boterolowry at gmail.com", "name-addr": "Alex Botero-Lowry <alex.boterolowry at gmail.com>"},
+{"name": "Ingmar Vanhassel", "address": "ingmar at exherbo.org", "name-addr": "Ingmar Vanhassel <ingmar at exherbo.org>"},
+{"name": "Aron Griffis", "address": "agriffis at n01se.net", "name-addr": "Aron Griffis <agriffis at n01se.net>"},
+{"name": "Adrian Perez de Castro", "address": "aperez at igalia.com", "name-addr": "Adrian Perez de Castro <aperez at igalia.com>"},
+{"name": "Israel Herraiz", "address": "isra at herraiz.org", "name-addr": "Israel Herraiz <isra at herraiz.org>"},
+{"name": "Mikhail Gusarov", "address": "dottedmag at dottedmag.net", "name-addr": "Mikhail Gusarov <dottedmag at dottedmag.net>"}]
EOF
test_expect_equal_file OUTPUT EXPECTED
@@ -487,7 +437,7 @@ test_begin_subtest "--output=recipients"
notmuch search --output=recipients '*' >OUTPUT
cat <<EOF >EXPECTED
Allan McRae <allan at archlinux.org>
-Discussion about the Arch User Repository (AUR) <aur-general at archlinux.org>
+"Discussion about the Arch User Repository (AUR)" <aur-general at archlinux.org>
olivier.berger at it-sudparis.eu
notmuch at notmuchmail.org
notmuch <notmuch at notmuchmail.org>
@@ -501,7 +451,7 @@ notmuch search --output=sender --output=recipients '*' >OUTPUT
cat <<EOF >EXPECTED
François Boulogne <boulogne.f at gmail.com>
Allan McRae <allan at archlinux.org>
-Discussion about the Arch User Repository (AUR) <aur-general at archlinux.org>
+"Discussion about the Arch User Repository (AUR)" <aur-general at archlinux.org>
Olivier Berger <olivier.berger at it-sudparis.eu>
olivier.berger at it-sudparis.eu
Chris Wilson <chris at chris-wilson.co.uk>
diff --git a/test/T095-search-filter-by.sh b/test/T095-search-filter-by.sh
index 97d9a9b..15c9f77 100755
--- a/test/T095-search-filter-by.sh
+++ b/test/T095-search-filter-by.sh
@@ -2,17 +2,17 @@
test_description='duplicite address filtering in "notmuch search --output=recipients"'
. ./test-lib.sh
-add_message '[to]="Real Name <foo at example.com>, Real Name <bar at example.com>"'
-add_message '[to]="Nickname <foo at example.com>"' '[cc]="Real Name <Bar at Example.COM>"'
-add_message '[to]="Nickname <foo at example.com>"' '[bcc]="Real Name <Bar at Example.COM>"'
+add_message '[to]="John Doe <foo at example.com>, John Doe <bar at example.com>"'
+add_message '[to]="\"Doe, John\" <foo at example.com>"' '[cc]="John Doe <Bar at Example.COM>"'
+add_message '[to]="\"Doe, John\" <foo at example.com>"' '[bcc]="John Doe <Bar at Example.COM>"'
test_begin_subtest "--output=recipients"
notmuch search --output=recipients "*" >OUTPUT
cat <<EOF >EXPECTED
-Real Name <foo at example.com>
-Real Name <bar at example.com>
-Nickname <foo at example.com>
-Real Name <Bar at Example.COM>
+John Doe <foo at example.com>
+John Doe <bar at example.com>
+"Doe, John" <foo at example.com>
+John Doe <Bar at Example.COM>
EOF
test_expect_equal_file OUTPUT EXPECTED
@@ -20,44 +20,53 @@ test_begin_subtest "--output=recipients --filter-by=nameaddr"
notmuch search --output=recipients --filter-by=nameaddr "*" >OUTPUT
# The same as above
cat <<EOF >EXPECTED
-Real Name <foo at example.com>
-Real Name <bar at example.com>
-Nickname <foo at example.com>
-Real Name <Bar at Example.COM>
+John Doe <foo at example.com>
+John Doe <bar at example.com>
+"Doe, John" <foo at example.com>
+John Doe <Bar at Example.COM>
EOF
test_expect_equal_file OUTPUT EXPECTED
test_begin_subtest "--output=recipients --filter-by=name"
notmuch search --output=recipients --filter-by=name "*" >OUTPUT
cat <<EOF >EXPECTED
-Real Name <foo at example.com>
-Nickname <foo at example.com>
+John Doe <foo at example.com>
+"Doe, John" <foo at example.com>
EOF
test_expect_equal_file OUTPUT EXPECTED
test_begin_subtest "--output=recipients --filter-by=addr"
notmuch search --output=recipients --filter-by=addr "*" >OUTPUT
cat <<EOF >EXPECTED
-Real Name <foo at example.com>
-Real Name <bar at example.com>
-Real Name <Bar at Example.COM>
+John Doe <foo at example.com>
+John Doe <bar at example.com>
+John Doe <Bar at Example.COM>
EOF
test_expect_equal_file OUTPUT EXPECTED
test_begin_subtest "--output=recipients --filter-by=addrfold"
notmuch search --output=recipients --filter-by=addrfold "*" >OUTPUT
cat <<EOF >EXPECTED
-Real Name <foo at example.com>
-Real Name <bar at example.com>
+John Doe <foo at example.com>
+John Doe <bar at example.com>
EOF
test_expect_equal_file OUTPUT EXPECTED
test_begin_subtest "--output=recipients --filter-by=nameaddrfold"
notmuch search --output=recipients --filter-by=nameaddrfold "*" >OUTPUT
cat <<EOF >EXPECTED
-Real Name <foo at example.com>
-Real Name <bar at example.com>
-Nickname <foo at example.com>
+John Doe <foo at example.com>
+John Doe <bar at example.com>
+"Doe, John" <foo at example.com>
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=recipients --filter-by=nameaddrfold --output=count"
+notmuch search --output=recipients --filter-by=nameaddrfold --output=count "*" | sort -n >OUTPUT
+cat <<EOF >EXPECTED
+1 John Doe <foo at example.com>
+2 "Doe, John" <foo at example.com>
+3 John Doe <bar at example.com>
EOF
test_expect_equal_file OUTPUT EXPECTED
More information about the notmuch
mailing list