1 Return-Path: <bremner@tethera.net>
\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 CE3D16DE0946
\r
6 for <notmuch@notmuchmail.org>; Sun, 12 Jun 2016 18:06:47 -0700 (PDT)
\r
7 X-Virus-Scanned: Debian amavisd-new at cworth.org
\r
11 X-Spam-Status: No, score=-0.011 tagged_above=-999 required=5
\r
12 tests=[AWL=-0.000, SPF_PASS=-0.001, T_RP_MATCHES_RCVD=-0.01]
\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 LPkA8tm9Q8yb for <notmuch@notmuchmail.org>;
\r
17 Sun, 12 Jun 2016 18:06:40 -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 9E8B16DE02DB
\r
20 for <notmuch@notmuchmail.org>; Sun, 12 Jun 2016 18:06:14 -0700 (PDT)
\r
21 Received: from remotemail by fethera.tethera.net with local (Exim 4.84)
\r
22 (envelope-from <bremner@tethera.net>)
\r
23 id 1bCGKG-0003xs-H7; Sun, 12 Jun 2016 21:06:00 -0400
\r
24 Received: (nullmailer pid 5682 invoked by uid 1000);
\r
25 Mon, 13 Jun 2016 01:06:04 -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: Sun, 12 Jun 2016 22:05:55 -0300
\r
30 Message-Id: <1465779955-5539-9-git-send-email-david@tethera.net>
\r
31 X-Mailer: git-send-email 2.8.1
\r
32 In-Reply-To: <1465779955-5539-1-git-send-email-david@tethera.net>
\r
33 References: <1465779955-5539-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: Mon, 13 Jun 2016 01:06: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 | 83 +++++++++++++++++++++++++++++++++++++++++--
\r
54 test/T610-message-property.sh | 28 +++++++++++++++
\r
55 3 files changed, 119 insertions(+), 5 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..d2ada61 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 diff --git a/test/T610-message-property.sh b/test/T610-message-property.sh
\r
222 index e594979..8952eb7 100755
\r
223 --- a/test/T610-message-property.sh
\r
224 +++ b/test/T610-message-property.sh
\r
225 @@ -209,4 +209,32 @@ EOF
\r
226 notmuch dump | grep '^#=' > OUTPUT
\r
227 test_expect_equal_file PROPERTIES OUTPUT
\r
230 +test_begin_subtest "restore missing message property (single line)"
\r
231 +notmuch dump | grep '^#=' > BEFORE1
\r
232 +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
\r
233 +EXPECT0(notmuch_message_remove_property (message, "testkey1", "bob"));
\r
235 +notmuch restore < BEFORE1
\r
236 +notmuch dump | grep '^#=' > OUTPUT
\r
237 +test_expect_equal_file PROPERTIES OUTPUT
\r
240 +test_begin_subtest "restore missing message property (full dump)"
\r
241 +notmuch dump > BEFORE2
\r
242 +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
\r
243 +EXPECT0(notmuch_message_remove_property (message, "testkey1", "bob"));
\r
245 +notmuch restore < BEFORE2
\r
246 +notmuch dump | grep '^#=' > OUTPUT
\r
247 +test_expect_equal_file PROPERTIES OUTPUT
\r
249 +test_begin_subtest "restore clear extra message property"
\r
250 +cat c_head - c_tail <<'EOF' | test_C ${MAIL_DIR}
\r
251 +EXPECT0(notmuch_message_add_property (message, "testkey1", "charles"));
\r
253 +notmuch restore < BEFORE2
\r
254 +notmuch dump | grep '^#=' > OUTPUT
\r
255 +test_expect_equal_file PROPERTIES OUTPUT
\r