cli: address: Do not output duplicate addresses

This filters out duplicate addresses from address command output.

It also also adds tests for the address command.

The code here is an extended version of a patch from Jani Nikula.
This commit is contained in:
Michal Sojka 2014-11-05 01:25:57 +01:00 committed by David Bremner
parent 5c32365d87
commit 4176e527fc
3 changed files with 141 additions and 2 deletions

View file

@ -11,7 +11,7 @@ DESCRIPTION
=========== ===========
Search for messages matching the given search terms, and display the Search for messages matching the given search terms, and display the
addresses from them. addresses from them. Duplicate addresses are filtered out.
See **notmuch-search-terms(7)** for details of the supported syntax for See **notmuch-search-terms(7)** for details of the supported syntax for
<search-terms>. <search-terms>.

View file

@ -53,6 +53,7 @@ typedef struct {
int offset; int offset;
int limit; int limit;
int dupe; int dupe;
GHashTable *addresses;
} search_context_t; } search_context_t;
typedef struct { typedef struct {
@ -240,6 +241,28 @@ do_search_threads (search_context_t *ctx)
return 0; return 0;
} }
/* Returns TRUE iff name and addr is duplicate. If not, stores the
* name/addr pair in order to detect subsequent duplicates. */
static notmuch_bool_t
is_duplicate (const search_context_t *ctx, const char *name, const char *addr)
{
notmuch_bool_t duplicate;
char *key;
key = talloc_asprintf (ctx->format, "%s <%s>", name, addr);
if (! key)
return FALSE;
duplicate = g_hash_table_lookup_extended (ctx->addresses, key, NULL, NULL);
if (! duplicate)
g_hash_table_insert (ctx->addresses, key, NULL);
else
talloc_free (key);
return duplicate;
}
static void static void
print_mailbox (const search_context_t *ctx, const mailbox_t *mailbox) print_mailbox (const search_context_t *ctx, const mailbox_t *mailbox)
{ {
@ -274,7 +297,8 @@ print_mailbox (const search_context_t *ctx, const mailbox_t *mailbox)
/* Print addresses from InternetAddressList. */ /* Print addresses from InternetAddressList. */
static void static void
process_address_list (const search_context_t *ctx, InternetAddressList *list) process_address_list (const search_context_t *ctx,
InternetAddressList *list)
{ {
InternetAddress *address; InternetAddress *address;
int i; int i;
@ -298,6 +322,9 @@ process_address_list (const search_context_t *ctx, InternetAddressList *list)
.addr = internet_address_mailbox_get_addr (mailbox), .addr = internet_address_mailbox_get_addr (mailbox),
}; };
if (is_duplicate (ctx, mbx.name, mbx.addr))
continue;
print_mailbox (ctx, &mbx); print_mailbox (ctx, &mbx);
} }
} }
@ -321,6 +348,13 @@ process_address_header (const search_context_t *ctx, const char *value)
g_object_unref (list); g_object_unref (list);
} }
/* Destructor for talloc-allocated GHashTable keys and values. */
static void
_talloc_free_for_g_hash (void *ptr)
{
talloc_free (ptr);
}
static int static int
_count_filenames (notmuch_message_t *message) _count_filenames (notmuch_message_t *message)
{ {
@ -673,8 +707,14 @@ notmuch_address_command (notmuch_config_t *config, int argc, char *argv[])
argc - opt_index, argv + opt_index)) argc - opt_index, argv + opt_index))
return EXIT_FAILURE; return EXIT_FAILURE;
ctx->addresses = g_hash_table_new_full (g_str_hash, g_str_equal,
_talloc_free_for_g_hash, NULL);
ret = do_search_messages (ctx); ret = do_search_messages (ctx);
g_hash_table_unref (ctx->addresses);
_notmuch_search_cleanup (ctx); _notmuch_search_cleanup (ctx);
return ret ? EXIT_FAILURE : EXIT_SUCCESS; return ret ? EXIT_FAILURE : EXIT_SUCCESS;

99
test/T095-address.sh Executable file
View file

@ -0,0 +1,99 @@
#!/usr/bin/env bash
test_description='"notmuch address" in several variants'
. ./test-lib.sh
add_email_corpus
test_begin_subtest "--output=sender"
notmuch address --output=sender '*' >OUTPUT
cat <<EOF >EXPECTED
François Boulogne <boulogne.f@gmail.com>
Olivier Berger <olivier.berger@it-sudparis.eu>
Chris Wilson <chris@chris-wilson.co.uk>
Carl Worth <cworth@cworth.org>
Alexander Botero-Lowry <alex.boterolowry@gmail.com>
Keith Packard <keithp@keithp.com>
Jjgod Jiang <gzjjgod@gmail.com>
Rolland Santimano <rollandsantimano@yahoo.com>
Jan Janak <jan@ryngle.com>
Stewart Smith <stewart@flamingspork.com>
Lars Kellogg-Stedman <lars@seas.harvard.edu>
Alex Botero-Lowry <alex.boterolowry@gmail.com>
Ingmar Vanhassel <ingmar@exherbo.org>
Aron Griffis <agriffis@n01se.net>
Adrian Perez de Castro <aperez@igalia.com>
Israel Herraiz <isra@herraiz.org>
Mikhail Gusarov <dottedmag@dottedmag.net>
EOF
test_expect_equal_file OUTPUT EXPECTED
test_begin_subtest "--output=sender --format=json"
notmuch address --output=sender --format=json '*' >OUTPUT
cat <<EOF >EXPECTED
[{"name": "François Boulogne", "address": "boulogne.f@gmail.com", "name-addr": "François Boulogne <boulogne.f@gmail.com>"},
{"name": "Olivier Berger", "address": "olivier.berger@it-sudparis.eu", "name-addr": "Olivier Berger <olivier.berger@it-sudparis.eu>"},
{"name": "Chris Wilson", "address": "chris@chris-wilson.co.uk", "name-addr": "Chris Wilson <chris@chris-wilson.co.uk>"},
{"name": "Carl Worth", "address": "cworth@cworth.org", "name-addr": "Carl Worth <cworth@cworth.org>"},
{"name": "Alexander Botero-Lowry", "address": "alex.boterolowry@gmail.com", "name-addr": "Alexander Botero-Lowry <alex.boterolowry@gmail.com>"},
{"name": "Keith Packard", "address": "keithp@keithp.com", "name-addr": "Keith Packard <keithp@keithp.com>"},
{"name": "Jjgod Jiang", "address": "gzjjgod@gmail.com", "name-addr": "Jjgod Jiang <gzjjgod@gmail.com>"},
{"name": "Rolland Santimano", "address": "rollandsantimano@yahoo.com", "name-addr": "Rolland Santimano <rollandsantimano@yahoo.com>"},
{"name": "Jan Janak", "address": "jan@ryngle.com", "name-addr": "Jan Janak <jan@ryngle.com>"},
{"name": "Stewart Smith", "address": "stewart@flamingspork.com", "name-addr": "Stewart Smith <stewart@flamingspork.com>"},
{"name": "Lars Kellogg-Stedman", "address": "lars@seas.harvard.edu", "name-addr": "Lars Kellogg-Stedman <lars@seas.harvard.edu>"},
{"name": "Alex Botero-Lowry", "address": "alex.boterolowry@gmail.com", "name-addr": "Alex Botero-Lowry <alex.boterolowry@gmail.com>"},
{"name": "Ingmar Vanhassel", "address": "ingmar@exherbo.org", "name-addr": "Ingmar Vanhassel <ingmar@exherbo.org>"},
{"name": "Aron Griffis", "address": "agriffis@n01se.net", "name-addr": "Aron Griffis <agriffis@n01se.net>"},
{"name": "Adrian Perez de Castro", "address": "aperez@igalia.com", "name-addr": "Adrian Perez de Castro <aperez@igalia.com>"},
{"name": "Israel Herraiz", "address": "isra@herraiz.org", "name-addr": "Israel Herraiz <isra@herraiz.org>"},
{"name": "Mikhail Gusarov", "address": "dottedmag@dottedmag.net", "name-addr": "Mikhail Gusarov <dottedmag@dottedmag.net>"}]
EOF
test_expect_equal_file OUTPUT EXPECTED
test_begin_subtest "--output=recipients"
notmuch address --output=recipients '*' >OUTPUT
cat <<EOF >EXPECTED
Allan McRae <allan@archlinux.org>
"Discussion about the Arch User Repository (AUR)" <aur-general@archlinux.org>
olivier.berger@it-sudparis.eu
notmuch@notmuchmail.org
notmuch <notmuch@notmuchmail.org>
Keith Packard <keithp@keithp.com>
Mikhail Gusarov <dottedmag@dottedmag.net>
EOF
test_expect_equal_file OUTPUT EXPECTED
test_begin_subtest "--output=sender --output=recipients"
notmuch address --output=sender --output=recipients '*' >OUTPUT
cat <<EOF >EXPECTED
François Boulogne <boulogne.f@gmail.com>
Allan McRae <allan@archlinux.org>
"Discussion about the Arch User Repository (AUR)" <aur-general@archlinux.org>
Olivier Berger <olivier.berger@it-sudparis.eu>
olivier.berger@it-sudparis.eu
Chris Wilson <chris@chris-wilson.co.uk>
notmuch@notmuchmail.org
Carl Worth <cworth@cworth.org>
Alexander Botero-Lowry <alex.boterolowry@gmail.com>
Keith Packard <keithp@keithp.com>
Jjgod Jiang <gzjjgod@gmail.com>
Rolland Santimano <rollandsantimano@yahoo.com>
Jan Janak <jan@ryngle.com>
Stewart Smith <stewart@flamingspork.com>
Lars Kellogg-Stedman <lars@seas.harvard.edu>
notmuch <notmuch@notmuchmail.org>
Alex Botero-Lowry <alex.boterolowry@gmail.com>
Ingmar Vanhassel <ingmar@exherbo.org>
Aron Griffis <agriffis@n01se.net>
Adrian Perez de Castro <aperez@igalia.com>
Israel Herraiz <isra@herraiz.org>
Mikhail Gusarov <dottedmag@dottedmag.net>
EOF
test_expect_equal_file OUTPUT EXPECTED
test_begin_subtest "without --output"
notmuch address '*' >OUTPUT
# Use EXPECTED from previous subtest
test_expect_equal_file OUTPUT EXPECTED
test_done