Return-Path: X-Original-To: notmuch@notmuchmail.org Delivered-To: notmuch@notmuchmail.org Received: from localhost (localhost [127.0.0.1]) by olra.theworths.org (Postfix) with ESMTP id A0849431FDD for ; Fri, 24 Oct 2014 03:57:30 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: -2.3 X-Spam-Level: X-Spam-Status: No, score=-2.3 tagged_above=-999 required=5 tests=[RCVD_IN_DNSWL_MED=-2.3] autolearn=disabled Received: from olra.theworths.org ([127.0.0.1]) by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ftc+qzG-5rJh for ; Fri, 24 Oct 2014 03:57:23 -0700 (PDT) Received: from max.feld.cvut.cz (max.feld.cvut.cz [147.32.192.36]) by olra.theworths.org (Postfix) with ESMTP id 11DC9431FBD for ; Fri, 24 Oct 2014 03:57:23 -0700 (PDT) Received: from localhost (unknown [192.168.200.7]) by max.feld.cvut.cz (Postfix) with ESMTP id B8B3B3CFEE6; Fri, 24 Oct 2014 12:57:21 +0200 (CEST) X-Virus-Scanned: IMAP STYX AMAVIS Received: from max.feld.cvut.cz ([192.168.200.1]) by localhost (styx.feld.cvut.cz [192.168.200.7]) (amavisd-new, port 10044) with ESMTP id 1IznQ5zjB6qN; Fri, 24 Oct 2014 12:57:16 +0200 (CEST) Received: from imap.feld.cvut.cz (imap.feld.cvut.cz [147.32.192.34]) by max.feld.cvut.cz (Postfix) with ESMTP id CE5325CCF00; Fri, 24 Oct 2014 12:57:16 +0200 (CEST) Received: from wsh by steelpick.2x.cz with local (Exim 4.84) (envelope-from ) id 1XhcYW-0004pj-PB; Fri, 24 Oct 2014 12:57:16 +0200 From: Michal Sojka To: Mark Walters , notmuch@notmuchmail.org Subject: Re: [PATCH v3 3/4] cli: Extend the search command for --output={sender, recipients} In-Reply-To: <87mw8obcob.fsf@qmul.ac.uk> References: <87zjd51phx.fsf@steelpick.2x.cz> <1413150093-8383-1-git-send-email-sojkam1@fel.cvut.cz> <1413150093-8383-4-git-send-email-sojkam1@fel.cvut.cz> <87mw8obcob.fsf@qmul.ac.uk> User-Agent: Notmuch/0.18.1+101~g56b0ff0 (http://notmuchmail.org) Emacs/24.3.1 (x86_64-pc-linux-gnu) Date: Fri, 24 Oct 2014 12:57:16 +0200 Message-ID: <87fvedag6r.fsf@steelpick.2x.cz> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 24 Oct 2014 10:57:30 -0000 Hi Mark, I mostly agree with your points mentioned in this and other your emails. I'll prepare v4 based on that. On Wed, Oct 22 2014, Mark Walters wrote: > On Sun, 12 Oct 2014, Michal Sojka wrote: >> The new outputs allow printing senders, recipients or both of matching >> messages. The --output option is converted from "keyword" argument to >> "flags" argument, which means that the user can use --output=3Dsender and >> --output=3Drecipients simultaneously, to print both. Other combinations >> produce an error. >> >> This code based on a patch from Jani Nikula. >> --- >> completion/notmuch-completion.bash | 2 +- >> completion/notmuch-completion.zsh | 3 +- >> doc/man1/notmuch-search.rst | 22 +++++++- >> notmuch-search.c | 110 ++++++++++++++++++++++++++++++= ++++--- >> test/T090-search-output.sh | 64 +++++++++++++++++++++ >> 5 files changed, 189 insertions(+), 12 deletions(-) >> >> diff --git a/completion/notmuch-completion.bash b/completion/notmuch-com= pletion.bash >> index 0571dc9..cfbd389 100644 >> --- a/completion/notmuch-completion.bash >> +++ b/completion/notmuch-completion.bash >> @@ -294,7 +294,7 @@ _notmuch_search() >> return >> ;; >> --output) >> - COMPREPLY=3D( $( compgen -W "summary threads messages files tags" = -- "${cur}" ) ) >> + COMPREPLY=3D( $( compgen -W "summary threads messages files tags s= ender recipients" -- "${cur}" ) ) >> return >> ;; >> --sort) >> diff --git a/completion/notmuch-completion.zsh b/completion/notmuch-comp= letion.zsh >> index 67a9aba..3e52a00 100644 >> --- a/completion/notmuch-completion.zsh >> +++ b/completion/notmuch-completion.zsh >> @@ -52,7 +52,8 @@ _notmuch_search() >> _arguments -s : \ >> '--max-threads=3D[display only the first x threads from the search = results]:number of threads to show: ' \ >> '--first=3D[omit the first x threads from the search results]:numbe= r of threads to omit: ' \ >> - '--sort=3D[sort results]:sorting:((newest-first\:"reverse chronolog= ical order" oldest-first\:"chronological order"))' >> + '--sort=3D[sort results]:sorting:((newest-first\:"reverse chronolog= ical order" oldest-first\:"chronological order"))' \ >> + '--output=3D[select what to output]:output:((summary threads messag= es files tags sender recipients))' >> } >> >> _notmuch() >> diff --git a/doc/man1/notmuch-search.rst b/doc/man1/notmuch-search.rst >> index 90160f2..c9d38b1 100644 >> --- a/doc/man1/notmuch-search.rst >> +++ b/doc/man1/notmuch-search.rst >> @@ -35,7 +35,7 @@ Supported options for **search** include >> intended for programs that invoke **notmuch(1)** internally. If >> omitted, the latest supported version will be used. >> >> - ``--output=3D(summary|threads|messages|files|tags)`` >> + ``--output=3D(summary|threads|messages|files|tags|sender|recipients= )`` >> >> **summary** >> Output a summary of each thread with any message matching >> @@ -78,6 +78,26 @@ Supported options for **search** include >> by null characters (--format=3Dtext0), as a JSON array >> (--format=3Djson), or as an S-Expression list (--format=3Ds= exp). >> >> + **sender** >> + Output all addresses from the *From* header that appear on >> + any message matching the search terms, either one per line >> + (--format=3Dtext), separated by null characters >> + (--format=3Dtext0), as a JSON array (--format=3Djson), or as >> + an S-Expression list (--format=3Dsexp). >> + >> + Note: Searching for **sender** should be much faster than >> + searching for **recipients**, because sender addresses are >> + cached directly in the database whereas other addresses >> + need to be fetched from message files. >> + >> + **recipients** >> + Like **sender** but for addresses from *To*, *Cc* and >> + *Bcc* headers. >> + >> + This option can be given multiple times to combine different >> + outputs. Curently, this is only supported for **sender** and >> + **recipients** outputs. >> + >> ``--sort=3D``\ (**newest-first**\ \|\ **oldest-first**) >> This option can be used to present results in either >> chronological order (**oldest-first**) or reverse chronological >> diff --git a/notmuch-search.c b/notmuch-search.c >> index 5ac2a26..74588f8 100644 >> --- a/notmuch-search.c >> +++ b/notmuch-search.c >> @@ -23,11 +23,14 @@ >> #include "string-util.h" >> >> typedef enum { >> - OUTPUT_SUMMARY, >> - OUTPUT_THREADS, >> - OUTPUT_MESSAGES, >> - OUTPUT_FILES, >> - OUTPUT_TAGS >> + OUTPUT_SUMMARY =3D 1 << 0, >> + OUTPUT_THREADS =3D 1 << 1, >> + OUTPUT_MESSAGES =3D 1 << 2, >> + OUTPUT_FILES =3D 1 << 3, >> + OUTPUT_TAGS =3D 1 << 4, >> + OUTPUT_SENDER =3D 1 << 5, >> + OUTPUT_RECIPIENTS =3D 1 << 6, >> + OUTPUT_ADDRESSES =3D OUTPUT_SENDER | OUTPUT_RECIPIENTS, > > I think I would drop the OUTPUT_ADDRESSES enum as the parser no longer > uses it (and replace the one use by OUTPUT_SENDER | OUTPUT_RECIPIENTS > below). As mentioned elsewhere, this is required to suppress the following warning. notmuch-search.c:634:5: warning: case value =E2=80=9896=E2=80=99 not in enu= merated type =E2=80=98output_t=E2=80=99 [-Wswitch] > >> } output_t; >> >> typedef struct { >> @@ -220,6 +223,67 @@ do_search_threads (search_options_t *o) >> return 0; >> } >> >> +static void >> +print_address_list (const search_options_t *o, InternetAddressList *lis= t) >> +{ >> + InternetAddress *address; >> + int i; >> + >> + for (i =3D 0; i < internet_address_list_length (list); i++) { >> + address =3D internet_address_list_get_address (list, i); >> + if (INTERNET_ADDRESS_IS_GROUP (address)) { >> + InternetAddressGroup *group; >> + InternetAddressList *group_list; >> + >> + group =3D INTERNET_ADDRESS_GROUP (address); >> + group_list =3D internet_address_group_get_members (group); >> + if (group_list =3D=3D NULL) >> + continue; >> + >> + print_address_list (o, group_list); >> + } else { >> + InternetAddressMailbox *mailbox; >> + const char *name; >> + const char *addr; >> + char *full_address; >> + >> + mailbox =3D INTERNET_ADDRESS_MAILBOX (address); >> + >> + name =3D internet_address_get_name (address); >> + addr =3D internet_address_mailbox_get_addr (mailbox); >> + >> + if (name && *name) >> + full_address =3D talloc_asprintf (o->format, "%s <%s>", name, addr); >> + else >> + full_address =3D talloc_strdup (o->format, addr); >> + >> + if (!full_address) { >> + fprintf (stderr, "Error: out of memory\n"); >> + break; >> + } >> + o->format->string (o->format, full_address); >> + o->format->separator (o->format); >> + >> + talloc_free (full_address); >> + } >> + } >> +} >> + >> +static void >> +print_address_string (const search_options_t *o, const char *recipients) >> +{ >> + InternetAddressList *list; >> + >> + if (recipients =3D=3D NULL) >> + return; >> + >> + list =3D internet_address_list_parse_string (recipients); >> + if (list =3D=3D NULL) >> + return; >> + >> + print_address_list (o, list); >> +} >> + >> static int >> do_search_messages (search_options_t *o) >> { >> @@ -266,11 +330,29 @@ do_search_messages (search_options_t *o) >> >> notmuch_filenames_destroy( filenames ); >> >> - } else { /* output =3D=3D OUTPUT_MESSAGES */ >> + } else if (o->output =3D=3D OUTPUT_MESSAGES) { >> format->set_prefix (format, "id"); >> format->string (format, >> notmuch_message_get_message_id (message)); >> format->separator (format); >> + } else { >> + if (o->output & OUTPUT_SENDER) { >> + const char *addrs; >> + >> + addrs =3D notmuch_message_get_header (message, "from"); >> + print_address_string (o, addrs); >> + } >> + >> + if (o->output & OUTPUT_RECIPIENTS) { >> + const char *hdrs[] =3D { "to", "cc", "bcc" }; >> + const char *addrs; >> + size_t j; >> + >> + for (j =3D 0; j < ARRAY_SIZE (hdrs); j++) { >> + addrs =3D notmuch_message_get_header (message, hdrs[j]); >> + print_address_string (o, addrs); >> + } >> + } >> } >> >> notmuch_message_destroy (message); >> @@ -337,7 +419,7 @@ notmuch_search_command (notmuch_config_t *config, in= t argc, char *argv[]) >> notmuch_database_t *notmuch; >> search_options_t o =3D { >> .sort =3D NOTMUCH_SORT_NEWEST_FIRST, >> - .output =3D OUTPUT_SUMMARY, >> + .output =3D 0, >> .offset =3D 0, >> .limit =3D -1, /* unlimited */ >> .dupe =3D -1, > > It is slightly unfortunate that all the other defaults are defined here > but the default output is after the option parsing but I can't see a > nice way round that. I only mention it in case you (or anyone else) can > see a nice way round this. Solution would to have --output as NOTMUCH_OPT_KEYWORD rather than NOTMUCH_OPT_KEYWORD_FLAGS as it was in v2. > >> @@ -366,10 +448,12 @@ notmuch_search_command (notmuch_config_t *config, = int argc, char *argv[]) >> { "text0", NOTMUCH_FORMAT_TEXT0 }, >> { 0, 0 } } }, >> { NOTMUCH_OPT_INT, ¬much_format_version, "format-version", 0, 0 }, >> - { NOTMUCH_OPT_KEYWORD, &o.output, "output", 'o', >> + { NOTMUCH_OPT_KEYWORD_FLAGS, &o.output, "output", 'o', >> (notmuch_keyword_t []){ { "summary", OUTPUT_SUMMARY }, >> { "threads", OUTPUT_THREADS }, >> { "messages", OUTPUT_MESSAGES }, >> + { "sender", OUTPUT_SENDER }, >> + { "recipients", OUTPUT_RECIPIENTS }, >> { "files", OUTPUT_FILES }, >> { "tags", OUTPUT_TAGS }, >> { 0, 0 } } }, >> @@ -389,6 +473,9 @@ notmuch_search_command (notmuch_config_t *config, in= t argc, char *argv[]) >> if (opt_index < 0) >> return EXIT_FAILURE; >> >> + if (! o.output) >> + o.output =3D OUTPUT_SUMMARY; >> + >> switch (format_sel) { >> case NOTMUCH_FORMAT_TEXT: >> o.format =3D sprinter_text_create (config, stdout); >> @@ -455,18 +542,23 @@ notmuch_search_command (notmuch_config_t *config, = int argc, char *argv[]) >> } >> >> switch (o.output) { >> - default: >> case OUTPUT_SUMMARY: >> case OUTPUT_THREADS: >> ret =3D do_search_threads (&o); >> break; >> case OUTPUT_MESSAGES: >> + case OUTPUT_SENDER: >> + case OUTPUT_RECIPIENTS: >> + case OUTPUT_ADDRESSES: > > This is the one use of OUTPUT_ADDRESSES that I would replace with > OUTPUT_SENDER | OUTPUT_RECIPIENTS See above. -Michal