]> rtime.felk.cvut.cz Git - notmuch.git/commitdiff
cli: address: Add --filter-by option to configure address filtering address-command
authorMichal Sojka <sojkam1@fel.cvut.cz>
Thu, 30 Oct 2014 23:06:26 +0000 (00:06 +0100)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Fri, 30 Jan 2015 21:01:33 +0000 (22:01 +0100)
This option allows to configure the criterion for duplicate address
filtering. Without this option, all unique combinations of name and
address parts are printed. This option allows to filter the output
more, for example to only contain unique address parts.

completion/notmuch-completion.bash
completion/notmuch-completion.zsh
doc/man1/notmuch-address.rst
notmuch-search.c
test/T097-address-filter-by.sh [new file with mode: 0755]

index 39320f8d8107681e6be8d644c1f0fe3309da16ca..5a7199e7ee26075679b40e6d779b409daa641ebd 100644 (file)
@@ -313,7 +313,7 @@ _notmuch_search()
     ! $split &&
     case "${cur}" in
        -*)
-           local options="--format= --output= --sort= --offset= --limit= --exclude= --duplicate="
+           local options="--format= --output= --sort= --offset= --limit= --exclude= --duplicate= --filter-by="
            compopt -o nospace
            COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
            ;;
@@ -346,6 +346,10 @@ _notmuch_address()
            COMPREPLY=( $( compgen -W "true false flag all" -- "${cur}" ) )
            return
            ;;
+       --filter-by)
+           COMPREPLY=( $( compgen -W "nameaddr name addr addrfold nameaddrfold" -- "${cur}" ) )
+           return
+           ;;
     esac
 
     ! $split &&
index 896856201b46ba772adf74f6027de7cc7d8bd488..c5bad216abf1b4046ad265544dd9a74523100300 100644 (file)
@@ -61,7 +61,8 @@ _notmuch_address()
 {
   _arguments -s : \
     '--sort=[sort results]:sorting:((newest-first\:"reverse chronological order" oldest-first\:"chronological order"))' \
-    '--output=[select what to output]:output:((sender recipients count))'
+    '--output=[select what to output]:output:((sender recipients count))' \
+    '--filter-by=[filter out duplicate addresses]:filter-by:((nameaddr\:"both name and address part" name\:"name part" addr\:"address part" addrfold\:"case-insensitive address part" nameaddrfold\:"name and case-insensitive address part"))'
 }
 
 _notmuch()
index 9570095b23c8437965e88831e2247fa03dcaaea1..14034249c9622b4d5e12750bf3dd997f75f80814 100644 (file)
@@ -11,7 +11,8 @@ DESCRIPTION
 ===========
 
 Search for messages matching the given search terms, and display the
-addresses from them. Duplicate addresses are filtered out.
+addresses from them. Duplicate addresses are filtered out. Filtering
+can be configured with the --filter-by option.
 
 See **notmuch-search-terms(7)** for details of the supported syntax for
 <search-terms>.
@@ -77,6 +78,39 @@ Supported options for **address** include
         **false** allows excluded messages to match search terms and
         appear in displayed results.
 
+    ``--filter-by=``\ (**nameaddr**\ \|\ **name** \|\ **addr**\ \|\ **addrfold**\ \|\ **nameaddrfold**\)
+
+       Controls how to filter out duplicate addresses. The filtering
+       algorithm receives a sequence of email addresses and outputs
+       the same sequence without the addresses that are considered a
+       duplicate of a previously output address. What is considered a
+       duplicate depends on how the two addresses are compared:
+
+       **nameaddr** means that both name and address parts are
+       compared in case-sensitive manner. Therefore, all same looking
+       addresses strings are considered duplicate. This is the
+       default.
+
+       **name** means that only the name part is compared (in
+       case-sensitive manner). For example, the addresses "John Doe
+       <me@example.com>" and "John Doe <john@doe.name>" will be
+       considered duplicate.
+
+       **addr** means that only the address part is compared (in
+       case-sensitive manner). For example, the addresses "John Doe
+       <john@example.com>" and "Dr. John Doe <john@example.com>" will
+       be considered duplicate.
+
+       **addrfold** is like **addr**, but comparison is done in
+       canse-insensitive manner. For example, the addresses "John Doe
+       <john@example.com>" and "Dr. John Doe <JOHN@EXAMPLE.COM>" will
+       be considered duplicate.
+
+       **nameaddrfold** is like **nameaddr**, but address comparison
+       is done in canse-insensitive manner. For example, the
+       addresses "John Doe <john@example.com>" and "John Doe
+       <JOHN@EXAMPLE.COM>" will be considered duplicate.
+
 EXIT STATUS
 ===========
 
index 14b9f01c5ad1d731d802e2f7a18bb5f9ef8e6597..8116cae84405a81c3ffaa2613ef6f41f2bf28e9b 100644 (file)
@@ -43,6 +43,14 @@ typedef enum {
     NOTMUCH_FORMAT_SEXP
 } format_sel_t;
 
+typedef enum {
+    FILTER_BY_NAMEADDR = 0,
+    FILTER_BY_NAME,
+    FILTER_BY_ADDR,
+    FILTER_BY_ADDRFOLD,
+    FILTER_BY_NAMEADDRFOLD,
+} filter_by_t;
+
 typedef struct {
     notmuch_database_t *notmuch;
     format_sel_t format_sel;
@@ -55,6 +63,7 @@ typedef struct {
     int limit;
     int dupe;
     GHashTable *addresses;
+    filter_by_t filter_by;
 } search_context_t;
 
 typedef struct {
@@ -243,16 +252,44 @@ do_search_threads (search_context_t *ctx)
     return 0;
 }
 
-/* Returns TRUE iff name and addr is duplicate. If not, stores the
- * name/addr pair in order to detect subsequent duplicates. */
+/* Returns TRUE iff name and/or addr is considered 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;
+    gchar *addrfold = NULL;
     mailbox_t *mailbox;
 
-    key = talloc_asprintf (ctx->format, "%s <%s>", name, addr);
+    if (ctx->filter_by == FILTER_BY_ADDRFOLD ||
+       ctx->filter_by == FILTER_BY_NAMEADDRFOLD)
+       addrfold = g_utf8_casefold (addr, -1);
+
+    switch (ctx->filter_by) {
+    case FILTER_BY_NAMEADDR:
+       key = talloc_asprintf (ctx->format, "%s <%s>", name, addr);
+       break;
+    case FILTER_BY_NAMEADDRFOLD:
+       key = talloc_asprintf (ctx->format, "%s <%s>", name, addrfold);
+       break;
+    case FILTER_BY_NAME:
+       key = talloc_strdup (ctx->format, name); /* !name results in !key */
+       break;
+    case FILTER_BY_ADDR:
+       key = talloc_strdup (ctx->format, addr);
+       break;
+    case FILTER_BY_ADDRFOLD:
+       key = talloc_strdup (ctx->format, addrfold);
+       break;
+    default:
+       INTERNAL_ERROR("invalid --filter-by flags");
+    }
+
+    if (addrfold)
+       g_free (addrfold);
+
     if (! key)
        return FALSE;
 
@@ -727,10 +764,18 @@ notmuch_address_command (notmuch_config_t *config, int argc, char *argv[])
          (notmuch_keyword_t []){ { "true", NOTMUCH_EXCLUDE_TRUE },
                                  { "false", NOTMUCH_EXCLUDE_FALSE },
                                  { 0, 0 } } },
+       { NOTMUCH_OPT_KEYWORD, &ctx->filter_by, "filter-by", 'b',
+         (notmuch_keyword_t []){ { "nameaddr", FILTER_BY_NAMEADDR },
+                                 { "name", FILTER_BY_NAME },
+                                 { "addr", FILTER_BY_ADDR },
+                                 { "addrfold", FILTER_BY_ADDRFOLD },
+                                 { "nameaddrfold", FILTER_BY_NAMEADDRFOLD },
+                                 { 0, 0 } } },
        { NOTMUCH_OPT_INHERIT, &common_options, NULL, 0, 0 },
        { 0, 0, 0, 0, 0 }
     };
 
+    ctx->filter_by = FILTER_BY_NAMEADDR,
     opt_index = parse_arguments (argc, argv, options, 1);
     if (opt_index < 0)
        return EXIT_FAILURE;
diff --git a/test/T097-address-filter-by.sh b/test/T097-address-filter-by.sh
new file mode 100755 (executable)
index 0000000..544d8e8
--- /dev/null
@@ -0,0 +1,73 @@
+#!/usr/bin/env bash
+test_description='duplicite address filtering in "notmuch address"'
+. ./test-lib.sh
+
+add_message '[to]="John Doe <foo@example.com>, John Doe <bar@example.com>"'
+add_message '[to]="\"Doe, John\" <foo@example.com>"' '[cc]="John Doe <Bar@Example.COM>"'
+add_message '[to]="\"Doe, John\" <foo@example.com>"' '[bcc]="John Doe <Bar@Example.COM>"'
+
+test_begin_subtest "--output=recipients"
+notmuch address --output=recipients "*" >OUTPUT
+cat <<EOF >EXPECTED
+John Doe <foo@example.com>
+John Doe <bar@example.com>
+"Doe, John" <foo@example.com>
+John Doe <Bar@Example.COM>
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=recipients --filter-by=nameaddr"
+notmuch address --output=recipients --filter-by=nameaddr "*" >OUTPUT
+# The same as above
+cat <<EOF >EXPECTED
+John Doe <foo@example.com>
+John Doe <bar@example.com>
+"Doe, John" <foo@example.com>
+John Doe <Bar@Example.COM>
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=recipients --filter-by=name"
+notmuch address --output=recipients --filter-by=name "*" >OUTPUT
+cat <<EOF >EXPECTED
+John Doe <foo@example.com>
+"Doe, John" <foo@example.com>
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=recipients --filter-by=addr"
+notmuch address --output=recipients --filter-by=addr "*" >OUTPUT
+cat <<EOF >EXPECTED
+John Doe <foo@example.com>
+John Doe <bar@example.com>
+John Doe <Bar@Example.COM>
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=recipients --filter-by=addrfold"
+notmuch address --output=recipients --filter-by=addrfold "*" >OUTPUT
+cat <<EOF >EXPECTED
+John Doe <foo@example.com>
+John Doe <bar@example.com>
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=recipients --filter-by=nameaddrfold"
+notmuch address --output=recipients --filter-by=nameaddrfold "*" >OUTPUT
+cat <<EOF >EXPECTED
+John Doe <foo@example.com>
+John Doe <bar@example.com>
+"Doe, John" <foo@example.com>
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_begin_subtest "--output=recipients --filter-by=nameaddrfold --output=count"
+notmuch address --output=recipients --filter-by=nameaddrfold --output=count "*" | sort -n >OUTPUT
+cat <<EOF >EXPECTED
+1      John Doe <foo@example.com>
+2      "Doe, John" <foo@example.com>
+3      John Doe <bar@example.com>
+EOF
+test_expect_equal_file OUTPUT EXPECTED
+
+test_done