Re: [PATCH 0/4] Allow specifying alternate names for addresses in other_email
[notmuch-archives.git] / d2 / 86c5b2e4a8da72519c085f75ed10f2cb41c70e
1 Return-Path: <novalazy@gmail.com>\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 25FF0431FAF\r
6         for <notmuch@notmuchmail.org>; Thu, 24 Jan 2013 04:09:18 -0800 (PST)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -0.799\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.799 tagged_above=-999 required=5\r
12         tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1,\r
13         FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7] 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 TsCRlnDgBiCk for <notmuch@notmuchmail.org>;\r
17         Thu, 24 Jan 2013 04:09:16 -0800 (PST)\r
18 Received: from mail-pb0-f43.google.com (mail-pb0-f43.google.com\r
19         [209.85.160.43]) (using TLSv1 with cipher RC4-SHA (128/128 bits))\r
20         (No client certificate requested)\r
21         by olra.theworths.org (Postfix) with ESMTPS id 06190431FAE\r
22         for <notmuch@notmuchmail.org>; Thu, 24 Jan 2013 04:09:15 -0800 (PST)\r
23 Received: by mail-pb0-f43.google.com with SMTP id jt11so3997106pbb.2\r
24         for <notmuch@notmuchmail.org>; Thu, 24 Jan 2013 04:09:15 -0800 (PST)\r
25 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113;\r
26         h=x-received:from:to:cc:subject:date:message-id:x-mailer;\r
27         bh=pq+bVJLMrvoa1umMAPToGStcuLLinxwPlewyyNvRcZg=;\r
28         b=J9QAYybUCsclcIpETQaEK/WLjlVFqVnIkwRd8263Wsu2gNNJ/FpMpAC6os4fCiUwoo\r
29         5mzxgrqvFD06ExhIQ8+BPQFTdPhPJY5Zm/n4BGIXuvsdAQEwDHci0N46octc3iUq1qi9\r
30         FEL1LT/3htG7XNRsdIzcuzaXZ1Z8lEKGR/SNY5BWm+SM1ROkRi5jELa1zIYjrSeHZmCh\r
31         soU2/kKhGEpw8lWsGgtwhyVUGbg1X6Mseb9/dBswlF5sVcHSK56rEiQTEQ782qKnKIxC\r
32         LKuF49SqmLaXdFde7IyCHvFhYIz1sHf7NU5cdzBNxhrpI8dImr8RvzGoBfg5+eGXZPtg\r
33         MDzg==\r
34 X-Received: by 10.68.223.35 with SMTP id qr3mr4330939pbc.27.1359029354173;\r
35         Thu, 24 Jan 2013 04:09:14 -0800 (PST)\r
36 Received: from localhost (215.42.233.220.static.exetel.com.au.\r
37         [220.233.42.215])\r
38         by mx.google.com with ESMTPS id bj9sm2746834pab.22.2013.01.24.04.09.11\r
39         (version=TLSv1.2 cipher=RC4-SHA bits=128/128);\r
40         Thu, 24 Jan 2013 04:09:13 -0800 (PST)\r
41 From: Peter Wang <novalazy@gmail.com>\r
42 To: notmuch@notmuchmail.org\r
43 Subject: [PATCH v4 00/12] insert command\r
44 Date: Thu, 24 Jan 2013 23:07:56 +1100\r
45 Message-Id: <1359029288-12132-1-git-send-email-novalazy@gmail.com>\r
46 X-Mailer: git-send-email 1.7.12.1\r
47 X-BeenThere: notmuch@notmuchmail.org\r
48 X-Mailman-Version: 2.1.13\r
49 Precedence: list\r
50 List-Id: "Use and development of the notmuch mail system."\r
51         <notmuch.notmuchmail.org>\r
52 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
53         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
54 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
55 List-Post: <mailto:notmuch@notmuchmail.org>\r
56 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
57 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
58         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
59 X-List-Received-Date: Thu, 24 Jan 2013 12:09:18 -0000\r
60 \r
61 Differences from v3:\r
62 \r
63  - squashed patches; take it up with Jani\r
64  - address some review comments (interdiff follows)\r
65  - some stylistic things I left for someone who cares\r
66    (either I tried it and didn't like it, or disagree with the premise)\r
67  - split doc and test patches so series can be partially applied\r
68    without --folder or --create-folder options\r
69 \r
70 Peter Wang (12):\r
71   tag-util: move out 'tag' command-line checks\r
72   tag-util: do not reset list in parse_tag_command_line\r
73   cli: add insert command\r
74   man: document 'insert' command\r
75   man: reference notmuch-insert.1\r
76   test: add tests for insert\r
77   insert: add --folder option\r
78   man: document insert --folder option\r
79   test: test insert --folder option\r
80   insert: add --create-folder option\r
81   man: document insert --create-folder\r
82   test: test insert --create-folder option\r
83 \r
84  Makefile.local                  |   1 +\r
85  man/Makefile.local              |   1 +\r
86  man/man1/notmuch-config.1       |   4 +-\r
87  man/man1/notmuch-count.1        |   4 +-\r
88  man/man1/notmuch-dump.1         |   4 +-\r
89  man/man1/notmuch-insert.1       |  63 ++++++\r
90  man/man1/notmuch-new.1          |   4 +-\r
91  man/man1/notmuch-reply.1        |   3 +-\r
92  man/man1/notmuch-restore.1      |   3 +-\r
93  man/man1/notmuch-search.1       |   3 +-\r
94  man/man1/notmuch-show.1         |   3 +-\r
95  man/man1/notmuch-tag.1          |   3 +-\r
96  man/man1/notmuch.1              |   3 +-\r
97  man/man5/notmuch-hooks.5        |   4 +-\r
98  man/man7/notmuch-search-terms.7 |   3 +-\r
99  notmuch-client.h                |   3 +\r
100  notmuch-insert.c                | 484 ++++++++++++++++++++++++++++++++++++++++\r
101  notmuch-tag.c                   |  10 +\r
102  notmuch.c                       |   3 +\r
103  tag-util.c                      |  13 +-\r
104  tag-util.h                      |   2 +\r
105  test/insert                     | 110 +++++++++\r
106  test/notmuch-test               |   1 +\r
107  23 files changed, 705 insertions(+), 27 deletions(-)\r
108  create mode 100644 man/man1/notmuch-insert.1\r
109  create mode 100644 notmuch-insert.c\r
110  create mode 100755 test/insert\r
111 \r
112 -- \r
113 1.7.12.1\r
114 \r
115 \r
116 diff --git a/man/man1/notmuch-insert.1 b/man/man1/notmuch-insert.1\r
117 index 4a7cbeb..8ce634e 100644\r
118 --- a/man/man1/notmuch-insert.1\r
119 +++ b/man/man1/notmuch-insert.1\r
120 @@ -24,6 +24,10 @@ configuration option, then by operations specified on the command-line:\r
121  tags prefixed by '+' are added while\r
122  those prefixed by '\-' are removed.\r
123  \r
124 +If the new message is a duplicate of an existing message in the database\r
125 +(it has same Message-ID), it will be added to the maildir folder and\r
126 +notmuch database, but the tags will not be changed.\r
127 +\r
128  Option arguments must appear before any tag operation arguments.\r
129  Supported options for\r
130  .B insert\r
131 diff --git a/notmuch-insert.c b/notmuch-insert.c\r
132 index 6b3e380..69329ad 100644\r
133 --- a/notmuch-insert.c\r
134 +++ b/notmuch-insert.c\r
135 @@ -44,33 +44,22 @@ handle_sigint (unused (int sig))\r
136  }\r
137  \r
138  /* Like gethostname but guarantees that a null-terminated hostname is\r
139 - * returned, even if it has to make one up.\r
140 - * Returns true unless hostname contains a slash. */\r
141 -static notmuch_bool_t\r
142 + * returned, even if it has to make one up. Invalid characters are\r
143 + * substituted such that the hostname can be used within a filename.\r
144 + */\r
145 +static void\r
146  safe_gethostname (char *hostname, size_t len)\r
147  {\r
148 +    char *p;\r
149 +\r
150      if (gethostname (hostname, len) == -1) {\r
151         strncpy (hostname, "unknown", len);\r
152      }\r
153      hostname[len - 1] = '\0';\r
154  \r
155 -    return (strchr (hostname, '/') == NULL);\r
156 -}\r
157 -\r
158 -/* Check the specified folder name does not contain a directory\r
159 - * component ".." to prevent writes outside of the Maildir hierarchy. */\r
160 -static notmuch_bool_t\r
161 -check_folder_name (const char *folder)\r
162 -{\r
163 -    const char *p = folder;\r
164 -\r
165 -    for (;;) {\r
166 -       if ((p[0] == '.') && (p[1] == '.') && (p[2] == '\0' || p[2] == '/'))\r
167 -           return FALSE;\r
168 -       p = strchr (p, '/');\r
169 -       if (!p)\r
170 -           return TRUE;\r
171 -       p++;\r
172 +    for (p = hostname; *p != '\0'; p++) {\r
173 +       if (*p == '/' || *p == ':')\r
174 +           *p = '_';\r
175      }\r
176  }\r
177  \r
178 @@ -96,6 +85,23 @@ sync_dir (const char *dir)\r
179      return ret;\r
180  }\r
181  \r
182 +/* Check the specified folder name does not contain a directory\r
183 + * component ".." to prevent writes outside of the Maildir hierarchy. */\r
184 +static notmuch_bool_t\r
185 +check_folder_name (const char *folder)\r
186 +{\r
187 +    const char *p = folder;\r
188 +\r
189 +    for (;;) {\r
190 +       if ((p[0] == '.') && (p[1] == '.') && (p[2] == '\0' || p[2] == '/'))\r
191 +           return FALSE;\r
192 +       p = strchr (p, '/');\r
193 +       if (!p)\r
194 +           return TRUE;\r
195 +       p++;\r
196 +    }\r
197 +}\r
198 +\r
199  /* Make the given directory, succeeding if it already exists. */\r
200  static notmuch_bool_t\r
201  make_directory (char *path, int mode)\r
202 @@ -206,10 +212,7 @@ maildir_open_tmp_file (void *ctx, const char *dir,\r
203  \r
204      /* We follow the Dovecot file name generation algorithm. */\r
205      pid = getpid ();\r
206 -    if (! safe_gethostname (hostname, sizeof (hostname))) {\r
207 -       fprintf (stderr, "Error: invalid host name.\n");\r
208 -       return -1;\r
209 -    }\r
210 +    safe_gethostname (hostname, sizeof (hostname));\r
211      do {\r
212         gettimeofday (&tv, NULL);\r
213         filename = talloc_asprintf (ctx, "%ld.M%ldP%d.%s",\r
214 @@ -247,26 +250,6 @@ maildir_open_tmp_file (void *ctx, const char *dir,\r
215      return fd;\r
216  }\r
217  \r
218 -/* Atomically move the new message file from the Maildir 'tmp' directory\r
219 - * to the 'new' directory.\r
220 - *\r
221 - * We follow the Dovecot recommendation to simply use rename()\r
222 - * instead of link() and unlink().  See also:\r
223 - * http://wiki.dovecot.org/MailboxFormat/Maildir#Mail_delivery\r
224 - */\r
225 -static notmuch_bool_t\r
226 -maildir_move_tmp_to_new (const char *tmppath, const char *newpath,\r
227 -                        const char *newdir)\r
228 -{\r
229 -    if (rename (tmppath, newpath) != 0) {\r
230 -       fprintf (stderr, "Error: rename() failed: %s\n", strerror (errno));\r
231 -       return FALSE;\r
232 -    }\r
233 -\r
234 -    /* Sync the 'new' directory after rename for durability. */\r
235 -    return sync_dir (newdir);\r
236 -}\r
237 -\r
238  /* Copy the contents of standard input (fdin) into fdout. */\r
239  static notmuch_bool_t\r
240  copy_stdin (int fdin, int fdout)\r
241 @@ -291,11 +274,9 @@ copy_stdin (int fdin, int fdout)\r
242         p = buf;\r
243         do {\r
244             written = write (fdout, p, remain);\r
245 -           if (written == 0)\r
246 -               return FALSE;\r
247 -           if (written < 0) {\r
248 -               if (errno == EINTR)\r
249 -                   continue;\r
250 +           if (written < 0 && errno == EINTR)\r
251 +               continue;\r
252 +           if (written <= 0) {\r
253                 fprintf (stderr, "Error: writing to temporary file: %s",\r
254                          strerror (errno));\r
255                 return FALSE;\r
256 @@ -320,9 +301,7 @@ add_file_to_database (notmuch_database_t *notmuch, const char *path,\r
257      status = notmuch_database_add_message (notmuch, path, &message);\r
258      switch (status) {\r
259      case NOTMUCH_STATUS_SUCCESS:\r
260 -       break;\r
261      case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:\r
262 -       fprintf (stderr, "Warning: duplicate message.\n");\r
263         break;\r
264      default:\r
265      case NOTMUCH_STATUS_FILE_NOT_EMAIL:\r
266 @@ -340,11 +319,18 @@ add_file_to_database (notmuch_database_t *notmuch, const char *path,\r
267         return FALSE;\r
268      }\r
269  \r
270 -    tag_op_list_apply (message, tag_ops, TAG_FLAG_MAILDIR_SYNC);\r
271 +    if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {\r
272 +       /* Don't change tags of an existing message. */\r
273 +       status = notmuch_message_tags_to_maildir_flags (message);\r
274 +       if (status != NOTMUCH_STATUS_SUCCESS)\r
275 +           fprintf (stderr, "Error: failed to sync tags to maildir flags\n");\r
276 +    } else {\r
277 +       status = tag_op_list_apply (message, tag_ops, TAG_FLAG_MAILDIR_SYNC);\r
278 +    }\r
279  \r
280      notmuch_message_destroy (message);\r
281  \r
282 -    return TRUE;\r
283 +    return (status == NOTMUCH_STATUS_SUCCESS) ? TRUE : FALSE;\r
284  }\r
285  \r
286  static notmuch_bool_t\r
287 @@ -355,29 +341,45 @@ insert_message (void *ctx, notmuch_database_t *notmuch, int fdin,\r
288      char *newpath;\r
289      char *newdir;\r
290      int fdout;\r
291 -    notmuch_bool_t ret;\r
292  \r
293      fdout = maildir_open_tmp_file (ctx, dir, &tmppath, &newpath, &newdir);\r
294      if (fdout < 0) {\r
295         return FALSE;\r
296      }\r
297 -    ret = copy_stdin (fdin, fdout);\r
298 -    if (ret && fsync (fdout) != 0) {\r
299 +\r
300 +    if (! copy_stdin (fdin, fdout)) {\r
301 +       close (fdout);\r
302 +       unlink (tmppath);\r
303 +       return FALSE;\r
304 +    }\r
305 +\r
306 +    if (fsync (fdout) != 0) {\r
307         fprintf (stderr, "Error: fsync failed: %s\n", strerror (errno));\r
308 -       ret = FALSE;\r
309 +       close (fdout);\r
310 +       unlink (tmppath);\r
311 +       return FALSE;\r
312      }\r
313 +\r
314      close (fdout);\r
315 -    if (ret) {\r
316 -       ret = maildir_move_tmp_to_new (tmppath, newpath, newdir);\r
317 -    }\r
318 -    if (!ret) {\r
319 +\r
320 +    /* Atomically move the new message file from the Maildir 'tmp' directory\r
321 +     * to the 'new' directory.  We follow the Dovecot recommendation to\r
322 +     * simply use rename() instead of link() and unlink().\r
323 +     * See also: http://wiki.dovecot.org/MailboxFormat/Maildir#Mail_delivery\r
324 +     */\r
325 +    if (rename (tmppath, newpath) != 0) {\r
326 +       fprintf (stderr, "Error: rename() failed: %s\n", strerror (errno));\r
327         unlink (tmppath);\r
328         return FALSE;\r
329      }\r
330  \r
331 -    ret = add_file_to_database (notmuch, newpath, tag_ops);\r
332 -    if (!ret) {\r
333 -       /* XXX maybe there should be an option to keep the file in maildir? */\r
334 +    if (! add_file_to_database (notmuch, newpath, tag_ops)) {\r
335 +       /* XXX add an option to keep the file in maildir? */\r
336 +       unlink (newpath);\r
337 +       return FALSE;\r
338 +    }\r
339 +\r
340 +    if (! sync_dir (newdir)) {\r
341         unlink (newpath);\r
342         return FALSE;\r
343      }\r
344 @@ -398,7 +400,7 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])\r
345      char *query_string = NULL;\r
346      const char *folder = NULL;\r
347      notmuch_bool_t create_folder = FALSE;\r
348 -    char *maildir;\r
349 +    const char *maildir;\r
350      int opt_index;\r
351      unsigned int i;\r
352      notmuch_bool_t ret;\r
353 @@ -443,23 +445,23 @@ notmuch_insert_command (void *ctx, int argc, char *argv[])\r
354         return 1;\r
355      }\r
356  \r
357 -    if (folder != NULL) {\r
358 +    if (folder == NULL) {\r
359 +       maildir = db_path;\r
360 +    } else {\r
361         if (! check_folder_name (folder)) {\r
362             fprintf (stderr, "Error: bad folder name: %s\n", folder);\r
363             return 1;\r
364         }\r
365         maildir = talloc_asprintf (ctx, "%s/%s", db_path, folder);\r
366 -    } else {\r
367 -       maildir = talloc_asprintf (ctx, "%s", db_path);\r
368 -    }\r
369 -    if (! maildir) {\r
370 -       fprintf (stderr, "Out of memory\n");\r
371 -       return 1;\r
372 -    }\r
373 -    if (create_folder && ! maildir_create_folder (ctx, maildir)) {\r
374 -       fprintf (stderr, "Error: creating maildir %s: %s\n",\r
375 -                maildir, strerror (errno));\r
376 -       return 1;\r
377 +       if (! maildir) {\r
378 +           fprintf (stderr, "Out of memory\n");\r
379 +           return 1;\r
380 +       }\r
381 +       if (create_folder && ! maildir_create_folder (ctx, maildir)) {\r
382 +           fprintf (stderr, "Error: creating maildir %s: %s\n",\r
383 +                    maildir, strerror (errno));\r
384 +           return 1;\r
385 +       }\r
386      }\r
387  \r
388      /* Setup our handler for SIGINT. We do not set SA_RESTART so that copying\r
389 diff --git a/tag-util.c b/tag-util.c\r
390 index 41f2c09..b57ee32 100644\r
391 --- a/tag-util.c\r
392 +++ b/tag-util.c\r
393 @@ -188,6 +188,11 @@ parse_tag_command_line (void *ctx, int argc, char **argv,\r
394  \r
395      *query_str = query_string_from_args (ctx, argc - i, &argv[i]);\r
396  \r
397 +    if (*query_str == NULL) {\r
398 +       fprintf (stderr, "Out of memory.\n");\r
399 +       return TAG_PARSE_OUT_OF_MEMORY;\r
400 +    }\r
401 +\r
402      return TAG_PARSE_SUCCESS;\r
403  }\r
404  \r
405 diff --git a/test/insert b/test/insert\r
406 index a3b6283..24a61e1 100755\r
407 --- a/test/insert\r
408 +++ b/test/insert\r
409 @@ -46,10 +46,14 @@ expected='[[[{\r
410  test_expect_equal_json "$output" "$expected"\r
411  \r
412  test_begin_subtest "Insert message, duplicate message"\r
413 -notmuch insert < "$gen_msg_filename"\r
414 +notmuch insert +duptag -unread < "$gen_msg_filename"\r
415  output=$(notmuch search --output=files "subject:insert-subject" | wc -l)\r
416  test_expect_equal "$output" 2\r
417  \r
418 +test_begin_subtest "Insert message, duplicate message does not change tags"\r
419 +output=$(notmuch search --format=json --output=tags "subject:insert-subject")\r
420 +test_expect_equal_json "$output" '["inbox", "unread"]'\r
421 +\r
422  test_begin_subtest "Insert message, add tag"\r
423  gen_insert_msg\r
424  notmuch insert +custom < "$gen_msg_filename"\r