Re: [PATCH] emacs: wash: make word-wrap bound message width
[notmuch-archives.git] / 25 / e9c36580012bd6335fe148057cf509f15e74cd
1 Return-Path: <m.walters@qmul.ac.uk>\r
2 X-Original-To: notmuch@notmuchmail.org\r
3 Delivered-To: notmuch@notmuchmail.org\r
4 Received: from localhost (localhost [127.0.0.1])\r
5         by olra.theworths.org (Postfix) with ESMTP id 20B9D431FC7\r
6         for <notmuch@notmuchmail.org>; Thu, 30 Oct 2014 01:16:53 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -1.098\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-1.098 tagged_above=-999 required=5\r
12         tests=[DKIM_ADSP_CUSTOM_MED=0.001, FREEMAIL_FROM=0.001,\r
13         NML_ADSP_CUSTOM_MED=1.2, RCVD_IN_DNSWL_MED=-2.3] autolearn=disabled\r
14 Received: from olra.theworths.org ([127.0.0.1])\r
15         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
16         with ESMTP id xL21Vn0hML0p for <notmuch@notmuchmail.org>;\r
17         Thu, 30 Oct 2014 01:16:44 -0700 (PDT)\r
18 Received: from mail2.qmul.ac.uk (mail2.qmul.ac.uk [138.37.6.6])\r
19         (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))\r
20         (No client certificate requested)\r
21         by olra.theworths.org (Postfix) with ESMTPS id 8435B431FB6\r
22         for <notmuch@notmuchmail.org>; Thu, 30 Oct 2014 01:16:43 -0700 (PDT)\r
23 Received: from smtp.qmul.ac.uk ([138.37.6.40])\r
24         by mail2.qmul.ac.uk with esmtp (Exim 4.71)\r
25         (envelope-from <m.walters@qmul.ac.uk>)\r
26         id 1Xjku5-0006EO-SM; Thu, 30 Oct 2014 08:16:42 +0000\r
27 Received: from 5751dfa2.skybroadband.com ([87.81.223.162] helo=localhost)\r
28         by smtp.qmul.ac.uk with esmtpsa (TLSv1:AES128-SHA:128) (Exim 4.71)\r
29         (envelope-from <m.walters@qmul.ac.uk>)\r
30         id 1Xjku3-0001UO-45; Thu, 30 Oct 2014 08:16:21 +0000\r
31 From: Mark Walters <markwalters1009@gmail.com>\r
32 To: Michal Sojka <sojkam1@fel.cvut.cz>, notmuch@notmuchmail.org\r
33 Subject: Re: [PATCH v4 5/6] cli: search: Add configurable way to filter\r
34         out     duplicate addresses\r
35 In-Reply-To: <1414421455-3037-6-git-send-email-sojkam1@fel.cvut.cz>\r
36 References: <1414421455-3037-1-git-send-email-sojkam1@fel.cvut.cz>\r
37         <1414421455-3037-6-git-send-email-sojkam1@fel.cvut.cz>\r
38 User-Agent: Notmuch/0.18.1+86~gef5e66a (http://notmuchmail.org) Emacs/23.4.1\r
39         (x86_64-pc-linux-gnu)\r
40 Date: Thu, 30 Oct 2014 08:16:18 +0000\r
41 Message-ID: <87egtqug4t.fsf@qmul.ac.uk>\r
42 MIME-Version: 1.0\r
43 Content-Type: text/plain; charset=utf-8\r
44 Content-Transfer-Encoding: quoted-printable\r
45 X-Sender-Host-Address: 87.81.223.162\r
46 X-QM-Geographic: According to ripencc,\r
47         this message was delivered by a machine in Britain (UK) (GB).\r
48 X-QM-SPAM-Info: Sender has good ham record.  :)\r
49 X-QM-Body-MD5: 9280583bd0e220ac2a1f2bae08d1669d (of first 20000 bytes)\r
50 X-SpamAssassin-Score: -0.1\r
51 X-SpamAssassin-SpamBar: /\r
52 X-SpamAssassin-Report: The QM spam filters have analysed this message to\r
53         determine if it is\r
54         spam. We require at least 5.0 points to mark a message as spam.\r
55         This message scored -0.1 points.\r
56         Summary of the scoring: \r
57         * 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail\r
58         provider *      (markwalters1009[at]gmail.com)\r
59         * -0.1 AWL AWL: From: address is in the auto white-list\r
60 X-QM-Scan-Virus: ClamAV says the message is clean\r
61 X-BeenThere: notmuch@notmuchmail.org\r
62 X-Mailman-Version: 2.1.13\r
63 Precedence: list\r
64 List-Id: "Use and development of the notmuch mail system."\r
65         <notmuch.notmuchmail.org>\r
66 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
67         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
68 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
69 List-Post: <mailto:notmuch@notmuchmail.org>\r
70 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
71 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
72         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
73 X-List-Received-Date: Thu, 30 Oct 2014 08:16:53 -0000\r
74 \r
75 \r
76 On Mon, 27 Oct 2014, Michal Sojka <sojkam1@fel.cvut.cz> wrote:\r
77 > This adds an algorithm to filter out duplicate addresses from address\r
78 > outputs (sender, receivers). The algorithm can be configured with\r
79 > --filter-by command line option.\r
80 >\r
81 > The code here is an extended version of a patch from Jani Nikula.\r
82 \r
83 Hi\r
84 \r
85 As this is getting into the more controversial bike shedding region I\r
86 wonder if it would be worth splitting this into 2 patches: the first\r
87 could do the default dedupe based on name/address and the second could\r
88 do add the filter-by options.=20\r
89 \r
90 I think the default deduping is obviously worth doing but I am not sure\r
91 about the rest. In any case I think the default deduping could go in\r
92 pre-freeze but I would recommend the rest is left until after.\r
93 \r
94 > ---\r
95 >  completion/notmuch-completion.bash |  6 ++-\r
96 >  completion/notmuch-completion.zsh  |  3 +-\r
97 >  doc/man1/notmuch-search.rst        | 38 +++++++++++++++\r
98 >  notmuch-search.c                   | 98 ++++++++++++++++++++++++++++++++=\r
99 +++---\r
100 >  test/T090-search-output.sh         | 87 +++++++++++++++++++++++++++++++++\r
101 >  test/T095-search-filter-by.sh      | 64 +++++++++++++++++++++++++\r
102 >  6 files changed, 288 insertions(+), 8 deletions(-)\r
103 >  create mode 100755 test/T095-search-filter-by.sh\r
104 >\r
105 > diff --git a/completion/notmuch-completion.bash b/completion/notmuch-comp=\r
106 letion.bash\r
107 > index cfbd389..6b6d43a 100644\r
108 > --- a/completion/notmuch-completion.bash\r
109 > +++ b/completion/notmuch-completion.bash\r
110 > @@ -305,12 +305,16 @@ _notmuch_search()\r
111 >           COMPREPLY=3D( $( compgen -W "true false flag all" -- "${cur}" ) )\r
112 >           return\r
113 >           ;;\r
114 > +     --filter-by)\r
115 > +         COMPREPLY=3D( $( compgen -W "nameaddr name addr addrfold nameaddrfo=\r
116 ld" -- "${cur}" ) )\r
117 > +         return\r
118 > +         ;;\r
119 >      esac\r
120 >=20=20\r
121 >      ! $split &&\r
122 >      case "${cur}" in\r
123 >       -*)\r
124 > -         local options=3D"--format=3D --output=3D --sort=3D --offset=3D --li=\r
125 mit=3D --exclude=3D --duplicate=3D"\r
126 > +         local options=3D"--format=3D --output=3D --sort=3D --offset=3D --li=\r
127 mit=3D --exclude=3D --duplicate=3D --filter-by=3D"\r
128 >           compopt -o nospace\r
129 >           COMPREPLY=3D( $(compgen -W "$options" -- ${cur}) )\r
130 >           ;;\r
131 > diff --git a/completion/notmuch-completion.zsh b/completion/notmuch-compl=\r
132 etion.zsh\r
133 > index 3e52a00..3e535df 100644\r
134 > --- a/completion/notmuch-completion.zsh\r
135 > +++ b/completion/notmuch-completion.zsh\r
136 > @@ -53,7 +53,8 @@ _notmuch_search()\r
137 >      '--max-threads=3D[display only the first x threads from the search r=\r
138 esults]:number of threads to show: ' \\r
139 >      '--first=3D[omit the first x threads from the search results]:number=\r
140  of threads to omit: ' \\r
141 >      '--sort=3D[sort results]:sorting:((newest-first\:"reverse chronologi=\r
142 cal order" oldest-first\:"chronological order"))' \\r
143 > -    '--output=3D[select what to output]:output:((summary threads message=\r
144 s files tags sender recipients))'\r
145 > +    '--output=3D[select what to output]:output:((summary threads message=\r
146 s files tags sender recipients))' \\r
147 > +    '--filter-by=3D[filter out duplicate addresses]:filter-by:((nameaddr=\r
148 \:"both name and address part" name\:"name part" addr\:"address part" addrf=\r
149 old\:"case-insensitive address part" nameaddrfold\:"name and case-insensiti=\r
150 ve address part"))'\r
151 >  }\r
152 >=20=20\r
153 >  _notmuch()\r
154 > diff --git a/doc/man1/notmuch-search.rst b/doc/man1/notmuch-search.rst\r
155 > index b6607c9..84af2da 100644\r
156 > --- a/doc/man1/notmuch-search.rst\r
157 > +++ b/doc/man1/notmuch-search.rst\r
158 > @@ -85,6 +85,9 @@ Supported options for **search** include\r
159 >              (--format=3Dtext0), as a JSON array (--format=3Djson), or as\r
160 >              an S-Expression list (--format=3Dsexp).\r
161 >=20=20\r
162 > +            Duplicate addresses are filtered out. Filtering can be\r
163 > +            configured with the --filter-by option.\r
164 > +\r
165 >           Note: Searching for **sender** should be much faster than\r
166 >           searching for **recipients**, because sender addresses are\r
167 >           cached directly in the database whereas other addresses\r
168 > @@ -151,6 +154,41 @@ Supported options for **search** include\r
169 >          prefix. The prefix matches messages based on filenames. This\r
170 >          option filters filenames of the matching messages.\r
171 >=20=20\r
172 > +    ``--filter-by=3D``\ (**nameaddr**\ \|\ **name** \|\ **addr**\ \|\ **=\r
173 addrfold**\ \|\ **nameaddrfold**\)\r
174 > +\r
175 > +     Can be used with ``--output=3Dsender`` or\r
176 > +     ``--output=3Drecipients`` to filter out duplicate addresses. The\r
177 > +     filtering algorithm receives a sequence of email addresses and\r
178 > +     outputs the same sequence without the addresses that are\r
179 > +     considered a duplicate of a previously output address. What is\r
180 > +     considered a duplicate depends on how the two addresses are\r
181 > +     compared and this can be controlled with the follwing flags:\r
182 > +\r
183 > +     **nameaddr** means that both name and address parts are\r
184 > +     compared in case-sensitive manner. Therefore, all same looking\r
185 > +     addresses strings are considered duplicate. This is the\r
186 > +     default.\r
187 > +\r
188 > +     **name** means that only the name part is compared (in\r
189 > +     case-sensitive manner). For example, the addresses "John Doe\r
190 > +     <me@example.com>" and "John Doe <john@doe.name>" will be\r
191 > +     considered duplicate.\r
192 > +\r
193 > +     **addr** means that only the address part is compared (in\r
194 > +     case-sensitive manner). For example, the addresses "John Doe\r
195 > +     <john@example.com>" and "Dr. John Doe <john@example.com>" will\r
196 > +     be considered duplicate.\r
197 > +\r
198 > +     **addrfold** is like **addr**, but comparison is done in\r
199 > +     canse-insensitive manner. For example, the addresses "John Doe\r
200 > +     <john@example.com>" and "Dr. John Doe <JOHN@EXAMPLE.COM>" will\r
201 > +     be considered duplicate.\r
202 > +\r
203 > +     **nameaddrfold** is like **nameaddr**, but address comparison\r
204 > +     is done in canse-insensitive manner. For example, the\r
205 > +     addresses "John Doe <john@example.com>" and "John Doe\r
206 > +     <JOHN@EXAMPLE.COM>" will be considered duplicate.\r
207 > +\r
208 >  EXIT STATUS\r
209 >  =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\r
210 >=20=20\r
211 > diff --git a/notmuch-search.c b/notmuch-search.c\r
212 > index ce3bfb2..47aa979 100644\r
213 > --- a/notmuch-search.c\r
214 > +++ b/notmuch-search.c\r
215 > @@ -34,6 +34,14 @@ typedef enum {\r
216 >=20=20\r
217 >  #define OUTPUT_ADDRESS_FLAGS (OUTPUT_SENDER | OUTPUT_RECIPIENTS)\r
218 >=20=20\r
219 > +typedef enum {\r
220 > +    FILTER_BY_NAMEADDR =3D 0,\r
221 > +    FILTER_BY_NAME,\r
222 > +    FILTER_BY_ADDR,\r
223 > +    FILTER_BY_ADDRFOLD,\r
224 > +    FILTER_BY_NAMEADDRFOLD,\r
225 > +} filter_by_t;\r
226 > +\r
227 >  typedef struct {\r
228 >      sprinter_t *format;\r
229 >      notmuch_query_t *query;\r
230 > @@ -42,6 +50,7 @@ typedef struct {\r
231 >      int offset;\r
232 >      int limit;\r
233 >      int dupe;\r
234 > +    filter_by_t filter_by;\r
235 >  } search_options_t;\r
236 >=20=20\r
237 >  typedef struct {\r
238 > @@ -229,6 +238,52 @@ do_search_threads (search_options_t *opt)\r
239 >      return 0;\r
240 >  }\r
241 >=20=20\r
242 > +/* Returns TRUE iff name and/or addr is considered duplicite. */\r
243 \r
244 A triviality; duplicite should be duplicate\r
245 \r
246 > +static notmuch_bool_t\r
247 > +check_duplicite (const search_options_t *opt, GHashTable *addrs, const c=\r
248 har *name, const char *addr)\r
249 \r
250 I am not sure on style but maybe is_duplicate would be clearer?\r
251 \r
252 Best wishes\r
253 \r
254 Mark\r
255 \r
256 > +{\r
257 > +    notmuch_bool_t duplicite;\r
258 > +    char *key;\r
259 > +\r
260 > +    if (opt->filter_by =3D=3D FILTER_BY_ADDRFOLD ||\r
261 > +     opt->filter_by =3D=3D FILTER_BY_NAMEADDRFOLD) {\r
262 > +     gchar *folded =3D g_utf8_casefold (addr, -1);\r
263 > +     addr =3D talloc_strdup (opt->format, folded);\r
264 > +     g_free (folded);\r
265 > +    }\r
266 > +    switch (opt->filter_by) {\r
267 > +    case FILTER_BY_NAMEADDR:\r
268 > +    case FILTER_BY_NAMEADDRFOLD:\r
269 > +     key =3D talloc_asprintf (opt->format, "%s <%s>", name, addr);\r
270 > +     break;\r
271 > +    case FILTER_BY_NAME:\r
272 > +     key =3D talloc_strdup (opt->format, name); /* !name results in !key */\r
273 > +     break;\r
274 > +    case FILTER_BY_ADDR:\r
275 > +    case FILTER_BY_ADDRFOLD:\r
276 > +     key =3D talloc_strdup (opt->format, addr);\r
277 > +     break;\r
278 > +    default:\r
279 > +     INTERNAL_ERROR("invalid --filter-by flags");\r
280 > +    }\r
281 > +\r
282 > +    if (opt->filter_by =3D=3D FILTER_BY_ADDRFOLD ||\r
283 > +     opt->filter_by =3D=3D FILTER_BY_NAMEADDRFOLD)\r
284 > +     talloc_free ((char*)addr);\r
285 > +\r
286 > +    if (! key)\r
287 > +     return FALSE;\r
288 > +\r
289 > +    duplicite =3D g_hash_table_lookup_extended (addrs, key, NULL, NULL);\r
290 > +\r
291 > +    if (! duplicite)\r
292 > +     g_hash_table_insert (addrs, key, NULL);\r
293 > +    else\r
294 > +     talloc_free (key);\r
295 > +\r
296 > +    return duplicite;\r
297 > +}\r
298 > +\r
299 >  static void\r
300 >  print_mailbox (const search_options_t *opt, const mailbox_t *mailbox)\r
301 >  {\r
302 > @@ -263,7 +318,8 @@ print_mailbox (const search_options_t *opt, const mai=\r
303 lbox_t *mailbox)\r
304 >  }\r
305 >=20=20\r
306 >  static void\r
307 > -process_address_list (const search_options_t *opt, InternetAddressList *=\r
308 list)\r
309 > +process_address_list (const search_options_t *opt, GHashTable *addrs,\r
310 > +                   InternetAddressList *list)\r
311 >  {\r
312 >      InternetAddress *address;\r
313 >      int i;\r
314 > @@ -279,7 +335,7 @@ process_address_list (const search_options_t *opt, In=\r
315 ternetAddressList *list)\r
316 >           if (group_list =3D=3D NULL)\r
317 >               continue;\r
318 >=20=20\r
319 > -         process_address_list (opt, group_list);\r
320 > +         process_address_list (opt, addrs, group_list);\r
321 >       } else {\r
322 >           InternetAddressMailbox *mailbox =3D INTERNET_ADDRESS_MAILBOX (addre=\r
323 ss);\r
324 >           mailbox_t mbx =3D {\r
325 > @@ -287,13 +343,16 @@ process_address_list (const search_options_t *opt, =\r
326 InternetAddressList *list)\r
327 >               .addr =3D internet_address_mailbox_get_addr (mailbox),\r
328 >           };\r
329 >=20=20\r
330 > +         if (check_duplicite (opt, addrs, mbx.name, mbx.addr))\r
331 > +             continue;\r
332 > +\r
333 >           print_mailbox (opt, &mbx);\r
334 >       }\r
335 >      }\r
336 >  }\r
337 >=20=20\r
338 >  static void\r
339 > -process_address_header (const search_options_t *opt, const char *value)\r
340 > +process_address_header (const search_options_t *opt, GHashTable *addrs, =\r
341 const char *value)\r
342 >  {\r
343 >      InternetAddressList *list;\r
344 >=20=20\r
345 > @@ -304,7 +363,13 @@ process_address_header (const search_options_t *opt,=\r
346  const char *value)\r
347 >      if (list =3D=3D NULL)\r
348 >       return;\r
349 >=20=20\r
350 > -    process_address_list (opt, list);\r
351 > +    process_address_list (opt, addrs, list);\r
352 > +}\r
353 > +\r
354 > +static void\r
355 > +_my_talloc_free_for_g_hash (void *ptr)\r
356 > +{\r
357 > +    talloc_free (ptr);\r
358 >  }\r
359 >=20=20\r
360 >  static int\r
361 > @@ -314,8 +379,13 @@ do_search_messages (search_options_t *opt)\r
362 >      notmuch_messages_t *messages;\r
363 >      notmuch_filenames_t *filenames;\r
364 >      sprinter_t *format =3D opt->format;\r
365 > +    GHashTable *addresses =3D NULL;\r
366 >      int i;\r
367 >=20=20\r
368 > +    if (opt->output & OUTPUT_ADDRESS_FLAGS)\r
369 > +     addresses =3D g_hash_table_new_full (g_str_hash, g_str_equal,\r
370 > +                                        _my_talloc_free_for_g_hash, NULL);\r
371 > +\r
372 >      if (opt->offset < 0) {\r
373 >       opt->offset +=3D notmuch_query_count_messages (opt->query);\r
374 >       if (opt->offset < 0)\r
375 > @@ -363,7 +433,7 @@ do_search_messages (search_options_t *opt)\r
376 >               const char *addrs;\r
377 >=20=20\r
378 >               addrs =3D notmuch_message_get_header (message, "from");\r
379 > -             process_address_header (opt, addrs);\r
380 > +             process_address_header (opt, addresses, addrs);\r
381 >           }\r
382 >=20=20\r
383 >           if (opt->output & OUTPUT_RECIPIENTS) {\r
384 > @@ -373,7 +443,7 @@ do_search_messages (search_options_t *opt)\r
385 >=20=20\r
386 >               for (j =3D 0; j < ARRAY_SIZE (hdrs); j++) {\r
387 >                   addrs =3D notmuch_message_get_header (message, hdrs[j]);\r
388 > -                 process_address_header (opt, addrs);\r
389 > +                 process_address_header (opt, addresses, addrs);\r
390 >               }\r
391 >           }\r
392 >       }\r
393 > @@ -381,6 +451,9 @@ do_search_messages (search_options_t *opt)\r
394 >       notmuch_message_destroy (message);\r
395 >      }\r
396 >=20=20\r
397 > +    if (addresses)\r
398 > +     g_hash_table_unref (addresses);\r
399 > +\r
400 >      notmuch_messages_destroy (messages);\r
401 >=20=20\r
402 >      format->end (format);\r
403 > @@ -447,6 +520,7 @@ notmuch_search_command (notmuch_config_t *config, int=\r
404  argc, char *argv[])\r
405 >       .offset =3D 0,\r
406 >       .limit =3D -1, /* unlimited */\r
407 >       .dupe =3D -1,\r
408 > +     .filter_by =3D FILTER_BY_NAMEADDR,\r
409 >      };\r
410 >      char *query_str;\r
411 >      int opt_index, ret;\r
412 > @@ -490,6 +564,13 @@ notmuch_search_command (notmuch_config_t *config, in=\r
413 t argc, char *argv[])\r
414 >       { NOTMUCH_OPT_INT, &opt.offset, "offset", 'O', 0 },\r
415 >       { NOTMUCH_OPT_INT, &opt.limit, "limit", 'L', 0  },\r
416 >       { NOTMUCH_OPT_INT, &opt.dupe, "duplicate", 'D', 0  },\r
417 > +     { NOTMUCH_OPT_KEYWORD, &opt.filter_by, "filter-by", 'b',\r
418 > +       (notmuch_keyword_t []){ { "nameaddr", FILTER_BY_NAMEADDR },\r
419 > +                               { "name", FILTER_BY_NAME },\r
420 > +                               { "addr", FILTER_BY_ADDR },\r
421 > +                               { "addrfold", FILTER_BY_ADDRFOLD },\r
422 > +                               { "nameaddrfold", FILTER_BY_NAMEADDRFOLD },\r
423 > +                               { 0, 0 } } },\r
424 >       { 0, 0, 0, 0, 0 }\r
425 >      };\r
426 >=20=20\r
427 > @@ -500,6 +581,11 @@ notmuch_search_command (notmuch_config_t *config, in=\r
428 t argc, char *argv[])\r
429 >      if (! opt.output)\r
430 >       opt.output =3D OUTPUT_SUMMARY;\r
431 >=20=20\r
432 > +    if (opt.filter_by && !(opt.output & OUTPUT_ADDRESS_FLAGS)) {\r
433 > +     fprintf (stderr, "Error: --filter-by can only be used with address outp=\r
434 ut.\n");\r
435 > +     return EXIT_FAILURE;\r
436 > +    }\r
437 > +\r
438 >      switch (format_sel) {\r
439 >      case NOTMUCH_FORMAT_TEXT:\r
440 >       opt.format =3D sprinter_text_create (config, stdout);\r
441 > diff --git a/test/T090-search-output.sh b/test/T090-search-output.sh\r
442 > index 947d572..841a721 100755\r
443 > --- a/test/T090-search-output.sh\r
444 > +++ b/test/T090-search-output.sh\r
445 > @@ -387,6 +387,93 @@ cat <<EOF >EXPECTED\r
446 >  EOF\r
447 >  test_expect_equal_file OUTPUT EXPECTED\r
448 >=20=20\r
449 > +test_begin_subtest "--output=3Dsender"\r
450 > +notmuch search --output=3Dsender '*' >OUTPUT\r
451 > +cat <<EOF >EXPECTED\r
452 > +Fran=C3=A7ois Boulogne <boulogne.f@gmail.com>\r
453 > +Olivier Berger <olivier.berger@it-sudparis.eu>\r
454 > +Chris Wilson <chris@chris-wilson.co.uk>\r
455 > +Carl Worth <cworth@cworth.org>\r
456 > +Alexander Botero-Lowry <alex.boterolowry@gmail.com>\r
457 > +Keith Packard <keithp@keithp.com>\r
458 > +Jjgod Jiang <gzjjgod@gmail.com>\r
459 > +Rolland Santimano <rollandsantimano@yahoo.com>\r
460 > +Jan Janak <jan@ryngle.com>\r
461 > +Stewart Smith <stewart@flamingspork.com>\r
462 > +Lars Kellogg-Stedman <lars@seas.harvard.edu>\r
463 > +Alex Botero-Lowry <alex.boterolowry@gmail.com>\r
464 > +Ingmar Vanhassel <ingmar@exherbo.org>\r
465 > +Aron Griffis <agriffis@n01se.net>\r
466 > +Adrian Perez de Castro <aperez@igalia.com>\r
467 > +Israel Herraiz <isra@herraiz.org>\r
468 > +Mikhail Gusarov <dottedmag@dottedmag.net>\r
469 > +EOF\r
470 > +test_expect_equal_file OUTPUT EXPECTED\r
471 > +\r
472 > +test_begin_subtest "--output=3Dsender --format=3Djson"\r
473 > +notmuch search --output=3Dsender --format=3Djson '*' >OUTPUT\r
474 > +cat <<EOF >EXPECTED\r
475 > +[{"name": "Fran=C3=A7ois Boulogne", "address": "boulogne.f@gmail.com"},\r
476 > +{"name": "Olivier Berger", "address": "olivier.berger@it-sudparis.eu"},\r
477 > +{"name": "Chris Wilson", "address": "chris@chris-wilson.co.uk"},\r
478 > +{"name": "Carl Worth", "address": "cworth@cworth.org"},\r
479 > +{"name": "Alexander Botero-Lowry", "address": "alex.boterolowry@gmail.co=\r
480 m"},\r
481 > +{"name": "Keith Packard", "address": "keithp@keithp.com"},\r
482 > +{"name": "Jjgod Jiang", "address": "gzjjgod@gmail.com"},\r
483 > +{"name": "Rolland Santimano", "address": "rollandsantimano@yahoo.com"},\r
484 > +{"name": "Jan Janak", "address": "jan@ryngle.com"},\r
485 > +{"name": "Stewart Smith", "address": "stewart@flamingspork.com"},\r
486 > +{"name": "Lars Kellogg-Stedman", "address": "lars@seas.harvard.edu"},\r
487 > +{"name": "Alex Botero-Lowry", "address": "alex.boterolowry@gmail.com"},\r
488 > +{"name": "Ingmar Vanhassel", "address": "ingmar@exherbo.org"},\r
489 > +{"name": "Aron Griffis", "address": "agriffis@n01se.net"},\r
490 > +{"name": "Adrian Perez de Castro", "address": "aperez@igalia.com"},\r
491 > +{"name": "Israel Herraiz", "address": "isra@herraiz.org"},\r
492 > +{"name": "Mikhail Gusarov", "address": "dottedmag@dottedmag.net"}]\r
493 > +EOF\r
494 > +test_expect_equal_file OUTPUT EXPECTED\r
495 > +\r
496 > +test_begin_subtest "--output=3Drecipients"\r
497 > +notmuch search --output=3Drecipients '*' >OUTPUT\r
498 > +cat <<EOF >EXPECTED\r
499 > +Allan McRae <allan@archlinux.org>\r
500 > +Discussion about the Arch User Repository (AUR) <aur-general@archlinux.o=\r
501 rg>\r
502 > +olivier.berger@it-sudparis.eu\r
503 > +notmuch@notmuchmail.org\r
504 > +notmuch <notmuch@notmuchmail.org>\r
505 > +Keith Packard <keithp@keithp.com>\r
506 > +Mikhail Gusarov <dottedmag@dottedmag.net>\r
507 > +EOF\r
508 > +test_expect_equal_file OUTPUT EXPECTED\r
509 > +\r
510 > +test_begin_subtest "--output=3Dsender --output=3Drecipients"\r
511 > +notmuch search --output=3Dsender --output=3Drecipients '*' >OUTPUT\r
512 > +cat <<EOF >EXPECTED\r
513 > +Fran=C3=A7ois Boulogne <boulogne.f@gmail.com>\r
514 > +Allan McRae <allan@archlinux.org>\r
515 > +Discussion about the Arch User Repository (AUR) <aur-general@archlinux.o=\r
516 rg>\r
517 > +Olivier Berger <olivier.berger@it-sudparis.eu>\r
518 > +olivier.berger@it-sudparis.eu\r
519 > +Chris Wilson <chris@chris-wilson.co.uk>\r
520 > +notmuch@notmuchmail.org\r
521 > +Carl Worth <cworth@cworth.org>\r
522 > +Alexander Botero-Lowry <alex.boterolowry@gmail.com>\r
523 > +Keith Packard <keithp@keithp.com>\r
524 > +Jjgod Jiang <gzjjgod@gmail.com>\r
525 > +Rolland Santimano <rollandsantimano@yahoo.com>\r
526 > +Jan Janak <jan@ryngle.com>\r
527 > +Stewart Smith <stewart@flamingspork.com>\r
528 > +Lars Kellogg-Stedman <lars@seas.harvard.edu>\r
529 > +notmuch <notmuch@notmuchmail.org>\r
530 > +Alex Botero-Lowry <alex.boterolowry@gmail.com>\r
531 > +Ingmar Vanhassel <ingmar@exherbo.org>\r
532 > +Aron Griffis <agriffis@n01se.net>\r
533 > +Adrian Perez de Castro <aperez@igalia.com>\r
534 > +Israel Herraiz <isra@herraiz.org>\r
535 > +Mikhail Gusarov <dottedmag@dottedmag.net>\r
536 > +EOF\r
537 > +test_expect_equal_file OUTPUT EXPECTED\r
538 > +\r
539 >  test_begin_subtest "sanitize output for quoted-printable line-breaks in =\r
540 author and subject"\r
541 >  add_message "[subject]=3D'two =3D?ISO-8859-1?Q?line=3D0A_subject?=3D\r
542 >       headers'"\r
543 > diff --git a/test/T095-search-filter-by.sh b/test/T095-search-filter-by.sh\r
544 > new file mode 100755\r
545 > index 0000000..97d9a9b\r
546 > --- /dev/null\r
547 > +++ b/test/T095-search-filter-by.sh\r
548 > @@ -0,0 +1,64 @@\r
549 > +#!/usr/bin/env bash\r
550 > +test_description=3D'duplicite address filtering in "notmuch search --out=\r
551 put=3Drecipients"'\r
552 > +. ./test-lib.sh\r
553 > +\r
554 > +add_message '[to]=3D"Real Name <foo@example.com>, Real Name <bar@example=\r
555 .com>"'\r
556 > +add_message '[to]=3D"Nickname <foo@example.com>"' '[cc]=3D"Real Name <Ba=\r
557 r@Example.COM>"'\r
558 > +add_message '[to]=3D"Nickname <foo@example.com>"' '[bcc]=3D"Real Name <B=\r
559 ar@Example.COM>"'\r
560 > +\r
561 > +test_begin_subtest "--output=3Drecipients"\r
562 > +notmuch search --output=3Drecipients "*" >OUTPUT\r
563 > +cat <<EOF >EXPECTED\r
564 > +Real Name <foo@example.com>\r
565 > +Real Name <bar@example.com>\r
566 > +Nickname <foo@example.com>\r
567 > +Real Name <Bar@Example.COM>\r
568 > +EOF\r
569 > +test_expect_equal_file OUTPUT EXPECTED\r
570 > +\r
571 > +test_begin_subtest "--output=3Drecipients --filter-by=3Dnameaddr"\r
572 > +notmuch search --output=3Drecipients --filter-by=3Dnameaddr "*" >OUTPUT\r
573 > +# The same as above\r
574 > +cat <<EOF >EXPECTED\r
575 > +Real Name <foo@example.com>\r
576 > +Real Name <bar@example.com>\r
577 > +Nickname <foo@example.com>\r
578 > +Real Name <Bar@Example.COM>\r
579 > +EOF\r
580 > +test_expect_equal_file OUTPUT EXPECTED\r
581 > +\r
582 > +test_begin_subtest "--output=3Drecipients --filter-by=3Dname"\r
583 > +notmuch search --output=3Drecipients --filter-by=3Dname "*" >OUTPUT\r
584 > +cat <<EOF >EXPECTED\r
585 > +Real Name <foo@example.com>\r
586 > +Nickname <foo@example.com>\r
587 > +EOF\r
588 > +test_expect_equal_file OUTPUT EXPECTED\r
589 > +\r
590 > +test_begin_subtest "--output=3Drecipients --filter-by=3Daddr"\r
591 > +notmuch search --output=3Drecipients --filter-by=3Daddr "*" >OUTPUT\r
592 > +cat <<EOF >EXPECTED\r
593 > +Real Name <foo@example.com>\r
594 > +Real Name <bar@example.com>\r
595 > +Real Name <Bar@Example.COM>\r
596 > +EOF\r
597 > +test_expect_equal_file OUTPUT EXPECTED\r
598 > +\r
599 > +test_begin_subtest "--output=3Drecipients --filter-by=3Daddrfold"\r
600 > +notmuch search --output=3Drecipients --filter-by=3Daddrfold "*" >OUTPUT\r
601 > +cat <<EOF >EXPECTED\r
602 > +Real Name <foo@example.com>\r
603 > +Real Name <bar@example.com>\r
604 > +EOF\r
605 > +test_expect_equal_file OUTPUT EXPECTED\r
606 > +\r
607 > +test_begin_subtest "--output=3Drecipients --filter-by=3Dnameaddrfold"\r
608 > +notmuch search --output=3Drecipients --filter-by=3Dnameaddrfold "*" >OUT=\r
609 PUT\r
610 > +cat <<EOF >EXPECTED\r
611 > +Real Name <foo@example.com>\r
612 > +Real Name <bar@example.com>\r
613 > +Nickname <foo@example.com>\r
614 > +EOF\r
615 > +test_expect_equal_file OUTPUT EXPECTED\r
616 > +\r
617 > +test_done\r
618 > --=20\r
619 > 2.1.1\r
620 >\r
621 > _______________________________________________\r
622 > notmuch mailing list\r
623 > notmuch@notmuchmail.org\r
624 > http://notmuchmail.org/mailman/listinfo/notmuch\r