1 Return-Path: <bremner@tesseract.cs.unb.ca>
\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 arlo.cworth.org (Postfix) with ESMTP id 24C696DE0360
\r
6 for <notmuch@notmuchmail.org>; Tue, 2 Aug 2016 21:40:47 -0700 (PDT)
\r
7 X-Virus-Scanned: Debian amavisd-new at cworth.org
\r
11 X-Spam-Status: No, score=-0.005 tagged_above=-999 required=5
\r
12 tests=[AWL=-0.006, HEADER_FROM_DIFFERENT_DOMAINS=0.001]
\r
14 Received: from arlo.cworth.org ([127.0.0.1])
\r
15 by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024)
\r
16 with ESMTP id BuBpj7cbVM9R for <notmuch@notmuchmail.org>;
\r
17 Tue, 2 Aug 2016 21:40:39 -0700 (PDT)
\r
18 Received: from fethera.tethera.net (fethera.tethera.net [198.245.60.197])
\r
19 by arlo.cworth.org (Postfix) with ESMTPS id 5EE576DE092E
\r
20 for <notmuch@notmuchmail.org>; Tue, 2 Aug 2016 21:39:21 -0700 (PDT)
\r
21 Received: from remotemail by fethera.tethera.net with local (Exim 4.84_2)
\r
22 (envelope-from <bremner@tesseract.cs.unb.ca>)
\r
23 id 1bUnxx-0000I7-JU; Wed, 03 Aug 2016 00:39:37 -0400
\r
24 Received: (nullmailer pid 12793 invoked by uid 1000);
\r
25 Wed, 03 Aug 2016 00:30:32 -0000
\r
26 From: David Bremner <david@tethera.net>
\r
27 To: notmuch@notmuchmail.org
\r
28 Subject: [PATCH 8/8] cli: optionally restore message properties from dump file
\r
29 Date: Wed, 3 Aug 2016 09:30:28 +0900
\r
30 Message-Id: <1470184228-12517-9-git-send-email-david@tethera.net>
\r
31 X-Mailer: git-send-email 2.8.1
\r
32 In-Reply-To: <1470184228-12517-1-git-send-email-david@tethera.net>
\r
33 References: <1470184228-12517-1-git-send-email-david@tethera.net>
\r
34 X-BeenThere: notmuch@notmuchmail.org
\r
35 X-Mailman-Version: 2.1.20
\r
37 List-Id: "Use and development of the notmuch mail system."
\r
38 <notmuch.notmuchmail.org>
\r
39 List-Unsubscribe: <https://notmuchmail.org/mailman/options/notmuch>,
\r
40 <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>
\r
41 List-Archive: <http://notmuchmail.org/pipermail/notmuch/>
\r
42 List-Post: <mailto:notmuch@notmuchmail.org>
\r
43 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>
\r
44 List-Subscribe: <https://notmuchmail.org/mailman/listinfo/notmuch>,
\r
45 <mailto:notmuch-request@notmuchmail.org?subject=subscribe>
\r
46 X-List-Received-Date: Wed, 03 Aug 2016 04:40:47 -0000
\r
48 This somewhat mimics the config line parsing, except there can be
\r
49 arbitrarily many key value pairs, so one more level of looping is
\r
52 doc/man1/notmuch-restore.rst | 13 +++++--
\r
53 notmuch-restore.c | 85 +++++++++++++++++++++++++++++++++++++++++--
\r
54 test/T610-message-property.sh | 28 ++++++++++++++
\r
55 3 files changed, 120 insertions(+), 6 deletions(-)
\r
57 diff --git a/doc/man1/notmuch-restore.rst b/doc/man1/notmuch-restore.rst
\r
58 index 87fa22e..a0c1b3c 100644
\r
59 --- a/doc/man1/notmuch-restore.rst
\r
60 +++ b/doc/man1/notmuch-restore.rst
\r
61 @@ -50,7 +50,7 @@ Supported options for **restore** include
\r
62 format, this heuristic, based the fact that batch-tag format
\r
63 contains no parentheses, should be accurate.
\r
65 - ``--include=(config|tags)``
\r
66 + ``--include=(config|properties|tags)``
\r
68 Control what kind of metadata is restored.
\r
70 @@ -60,13 +60,20 @@ Supported options for **restore** include
\r
71 with "#@ ", followed by a space seperated key-value pair.
\r
72 Both key and value are hex encoded if needed.
\r
76 + Output per-message (key,value) metadata. Each line starts
\r
77 + with "#= ", followed by a message id, and a space seperated
\r
78 + list of key=value pairs. pair. Ids, keys and values are
\r
79 + hex encoded if needed.
\r
83 Output per-message metadata, namely tags. See *format* above
\r
86 - The default is to restore both tags and configuration
\r
88 + The default is to restore all available types of data. The
\r
89 + option can be specified multiple times to select some subset.
\r
91 ``--input=``\ <filename>
\r
92 Read input from given file instead of stdin.
\r
93 diff --git a/notmuch-restore.c b/notmuch-restore.c
\r
94 index 371237c..3cd8a40 100644
\r
95 --- a/notmuch-restore.c
\r
96 +++ b/notmuch-restore.c
\r
97 @@ -57,6 +57,72 @@ process_config_line (notmuch_database_t *notmuch, const char* line)
\r
102 +process_properties_line (notmuch_database_t *notmuch, const char* line)
\r
105 + const char *id_p, *tok;
\r
106 + size_t id_len = 0, tok_len = 0;
\r
109 + notmuch_message_t *message = NULL;
\r
110 + const char *delim = " \t\n";
\r
111 + int ret = EXIT_FAILURE;
\r
113 + void *local = talloc_new (NULL);
\r
115 + id_p = strtok_len_c (line, delim, &id_len);
\r
116 + id = talloc_strndup (local, id_p, id_len);
\r
117 + if (hex_decode_inplace (id) != HEX_SUCCESS) {
\r
118 + fprintf (stderr, "hex decoding failure on line %s\n", line);
\r
122 + if (print_status_database ("notmuch restore", notmuch,
\r
123 + notmuch_database_find_message (notmuch, id, &message)))
\r
126 + if (print_status_database ("notmuch restore", notmuch,
\r
127 + notmuch_message_remove_all_properties (message)))
\r
130 + tok = id_p + id_len;
\r
132 + while ((tok = strtok_len_c (tok + tok_len, delim, &tok_len)) != NULL) {
\r
133 + char *key, *value;
\r
134 + size_t off = strcspn (tok, "=");
\r
135 + if (off > tok_len) {
\r
136 + fprintf (stderr, "unparsable token %s\n", tok);
\r
140 + key = talloc_strndup (local, tok, off);
\r
141 + value = talloc_strndup (local, tok + off + 1, tok_len - off - 1);
\r
143 + if (hex_decode_inplace (key) != HEX_SUCCESS) {
\r
144 + fprintf (stderr, "hex decoding failure on key %s\n", key);
\r
148 + if (hex_decode_inplace (value) != HEX_SUCCESS) {
\r
149 + fprintf (stderr, "hex decoding failure on value %s\n", value);
\r
153 + if (print_status_database ("notmuch restore", notmuch,
\r
154 + notmuch_message_add_property (message, key, value)))
\r
159 + ret = EXIT_SUCCESS;
\r
162 + talloc_free (local);
\r
167 static regex_t regex;
\r
169 /* Non-zero return indicates an error in retrieving the message,
\r
170 @@ -188,6 +254,7 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
\r
172 { NOTMUCH_OPT_KEYWORD_FLAGS, &include, "include", 'I',
\r
173 (notmuch_keyword_t []){ { "config", DUMP_INCLUDE_CONFIG },
\r
174 + { "properties", DUMP_INCLUDE_PROPERTIES },
\r
175 { "tags", DUMP_INCLUDE_TAGS} } },
\r
177 { NOTMUCH_OPT_STRING, &input_file_name, "input", 'i', 0 },
\r
178 @@ -206,7 +273,7 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
\r
179 notmuch_exit_if_unmatched_db_uuid (notmuch);
\r
181 if (include == 0) {
\r
182 - include = DUMP_INCLUDE_CONFIG | DUMP_INCLUDE_TAGS;
\r
183 + include = DUMP_INCLUDE_CONFIG | DUMP_INCLUDE_PROPERTIES | DUMP_INCLUDE_TAGS;
\r
186 name_for_error = input_file_name ? input_file_name : "stdin";
\r
187 @@ -273,13 +340,18 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
\r
191 + if ((include & DUMP_INCLUDE_PROPERTIES) && line_len >= 2 && line[0] == '#' && line[1] == '=') {
\r
192 + ret = process_properties_line (notmuch, line + 2);
\r
197 } while ((line_len == 0) ||
\r
198 (line[0] == '#') ||
\r
199 /* the cast is safe because we checked about for line_len < 0 */
\r
200 (strspn (line, " \t\n") == (unsigned)line_len));
\r
202 - if (! (include & DUMP_INCLUDE_TAGS)) {
\r
203 + if (! ((include & DUMP_INCLUDE_TAGS) || (include & DUMP_INCLUDE_PROPERTIES))) {
\r
204 ret = EXIT_SUCCESS;
\r
207 @@ -306,6 +378,13 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
\r
208 talloc_free (line_ctx);
\r
210 line_ctx = talloc_new (config);
\r
212 + if ((include & DUMP_INCLUDE_PROPERTIES) && line_len >= 2 && line[0] == '#' && line[1] == '=') {
\r
213 + ret = process_properties_line (notmuch, line + 2);
\r
218 if (input_format == DUMP_FORMAT_SUP) {
\r
219 ret = parse_sup_line (line_ctx, line, &query_string, tag_ops);
\r
221 @@ -344,7 +423,7 @@ notmuch_restore_command (notmuch_config_t *config, int argc, char *argv[])
\r
224 } while (! (ret = gz_getline (line_ctx, &line, &line_len, input)));
\r
228 /* EOF is normal loop termination condition, UTIL_SUCCESS is
\r
229 * impossible here */
\r
230 diff --git a/test/T610-message-property.sh b/test/T610-message-property.sh
\r
231 index e594979..8952eb7 100755
\r
232 --- a/test/T610-message-property.sh
\r
233 +++ b/test/T610-message-property.sh
\r
234 @@ -209,4 +209,32 @@ EOF
\r
235 notmuch dump | grep '^#=' > OUTPUT
\r
236 test_expect_equal_file PROPERTIES OUTPUT
\r
239 +test_begin_subtest "restore missing message property (single line)"
\r
240 +notmuch dump | grep '^#=' > BEFORE1
\r
241 +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
\r
242 +EXPECT0(notmuch_message_remove_property (message, "testkey1", "bob"));
\r
244 +notmuch restore < BEFORE1
\r
245 +notmuch dump | grep '^#=' > OUTPUT
\r
246 +test_expect_equal_file PROPERTIES OUTPUT
\r
249 +test_begin_subtest "restore missing message property (full dump)"
\r
250 +notmuch dump > BEFORE2
\r
251 +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
\r
252 +EXPECT0(notmuch_message_remove_property (message, "testkey1", "bob"));
\r
254 +notmuch restore < BEFORE2
\r
255 +notmuch dump | grep '^#=' > OUTPUT
\r
256 +test_expect_equal_file PROPERTIES OUTPUT
\r
258 +test_begin_subtest "restore clear extra message property"
\r
259 +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
\r
260 +EXPECT0(notmuch_message_add_property (message, "testkey1", "charles"));
\r
262 +notmuch restore < BEFORE2
\r
263 +notmuch dump | grep '^#=' > OUTPUT
\r
264 +test_expect_equal_file PROPERTIES OUTPUT
\r