[Patch v2 13/17] notmuch-restore: add support for input format 'batch-tag'

2012-12-02 Thread Jani Nikula
On Sat, 24 Nov 2012, david at tethera.net wrote:
> From: David Bremner 
>
> This is the same as the batch input for notmuch tag, except by default
> it removes all tags before modifying a given message id and only "id:"
> is supported.
> ---
>  notmuch-restore.c |  199 
> +
>  1 file changed, 125 insertions(+), 74 deletions(-)
>
> diff --git a/notmuch-restore.c b/notmuch-restore.c
> index f03dcac..22fcd2d 100644
> --- a/notmuch-restore.c
> +++ b/notmuch-restore.c
> @@ -19,18 +19,22 @@
>   */
>  
>  #include "notmuch-client.h"
> +#include "dump-restore-private.h"
> +#include "tag-util.h"
> +#include "string-util.h"
> +
> +static volatile sig_atomic_t interrupted;
> +static regex_t regex;
>  
>  static int
> -tag_message (notmuch_database_t *notmuch, const char *message_id,
> -  char *file_tags, notmuch_bool_t remove_all,
> -  notmuch_bool_t synchronize_flags)
> +tag_message (unused (void *ctx),
> +  notmuch_database_t *notmuch,
> +  const char *message_id,
> +  tag_op_list_t *tag_ops,
> +  tag_op_flag_t flags)
>  {
>  notmuch_status_t status;
> -notmuch_tags_t *db_tags;
> -char *db_tags_str;
>  notmuch_message_t *message = NULL;
> -const char *tag;
> -char *next;
>  int ret = 0;
>  
>  status = notmuch_database_find_message (notmuch, message_id, );
> @@ -44,55 +48,63 @@ tag_message (notmuch_database_t *notmuch, const char 
> *message_id,
>  
>  /* In order to detect missing messages, this check/optimization is
>   * intentionally done *after* first finding the message. */
> -if (! remove_all && (file_tags == NULL || *file_tags == '\0'))
> - goto DONE;
> -
> -db_tags_str = NULL;
> -for (db_tags = notmuch_message_get_tags (message);
> -  notmuch_tags_valid (db_tags);
> -  notmuch_tags_move_to_next (db_tags)) {
> - tag = notmuch_tags_get (db_tags);
> -
> - if (db_tags_str)
> - db_tags_str = talloc_asprintf_append (db_tags_str, " %s", tag);
> - else
> - db_tags_str = talloc_strdup (message, tag);
> -}
> +if ( (flags & TAG_FLAG_REMOVE_ALL) || (tag_op_list_size (tag_ops)))

Extra space between ('s, and no need to wrap tag_op_list_size call in
braces.

> + tag_op_list_apply (message, tag_ops, flags);
>  
> -if (((file_tags == NULL || *file_tags == '\0') &&
> -  (db_tags_str == NULL || *db_tags_str == '\0')) ||
> - (file_tags && db_tags_str && strcmp (file_tags, db_tags_str) == 0))

This is a necessary optimization you're throwing away, but I'll get back
to this after checking the last patch in the series.

> - goto DONE;
> +if (message)
> + notmuch_message_destroy (message);

message != NULL always, you can remove the if.

>  
> -notmuch_message_freeze (message);
> +return ret;
> +}
>  
> -if (remove_all)
> - notmuch_message_remove_all_tags (message);
> +static int
> +parse_sup_line (void *ctx, char *line,
> + char **query_str, tag_op_list_t *tag_ops)
> +{
>  
> -next = file_tags;
> -while (next) {
> - tag = strsep (, " ");
> - if (*tag == '\0')
> - continue;
> - status = notmuch_message_add_tag (message, tag);
> - if (status) {
> - fprintf (stderr, "Error applying tag %s to message %s:\n",
> -  tag, message_id);
> - fprintf (stderr, "%s\n", notmuch_status_to_string (status));
> - ret = 1;
> - }
> +regmatch_t match[3];
> +char *file_tags;
> +int rerr;
> +
> +tag_op_list_reset (tag_ops);
> +
> +chomp_newline (line);
> +
> +/* Silently ignore blank lines */
> +if (line[0] == '\0') {
> + return 1;
> +}
> +
> +rerr = xregexec (, line, 3, match, 0);
> +if (rerr == REG_NOMATCH) {
> + fprintf (stderr, "Warning: Ignoring invalid input line: %s\n",
> +  line);
> + return 1;
>  }
>  
> -notmuch_message_thaw (message);
> +*query_str = talloc_strndup (ctx, line + match[1].rm_so,
> +  match[1].rm_eo - match[1].rm_so);
> +file_tags = talloc_strndup (ctx, line + match[2].rm_so,
> + match[2].rm_eo - match[2].rm_so);
>  
> -if (synchronize_flags)
> - notmuch_message_tags_to_maildir_flags (message);
> +char *tok = file_tags;
> +size_t tok_len = 0;
>  
> -  DONE:
> -if (message)
> - notmuch_message_destroy (message);
> +tag_op_list_reset (tag_ops);
> +
> +while ((tok = strtok_len (tok + tok_len, " ", _len)) != NULL) {
> +
> + if (*(tok + tok_len) != '\0') {
> + *(tok + tok_len) = '\0';
> + tok_len++;
> + }
> +
> + if (tag_op_list_append (ctx, tag_ops, tok, FALSE))
> + return -1;
> +}
> +
> +return 0;
>  
> -return ret;
>  }
>  
>  int
> @@ -100,16 +112,19 @@ notmuch_restore_command (unused (void *ctx), int argc, 
> char *argv[])
>  {
>  notmuch_config_t *config;
>  notmuch_database_t 

Re: [Patch v2 13/17] notmuch-restore: add support for input format 'batch-tag'

2012-12-02 Thread Jani Nikula
On Sat, 24 Nov 2012, da...@tethera.net wrote:
 From: David Bremner brem...@debian.org

 This is the same as the batch input for notmuch tag, except by default
 it removes all tags before modifying a given message id and only id:
 is supported.
 ---
  notmuch-restore.c |  199 
 +
  1 file changed, 125 insertions(+), 74 deletions(-)

 diff --git a/notmuch-restore.c b/notmuch-restore.c
 index f03dcac..22fcd2d 100644
 --- a/notmuch-restore.c
 +++ b/notmuch-restore.c
 @@ -19,18 +19,22 @@
   */
  
  #include notmuch-client.h
 +#include dump-restore-private.h
 +#include tag-util.h
 +#include string-util.h
 +
 +static volatile sig_atomic_t interrupted;
 +static regex_t regex;
  
  static int
 -tag_message (notmuch_database_t *notmuch, const char *message_id,
 -  char *file_tags, notmuch_bool_t remove_all,
 -  notmuch_bool_t synchronize_flags)
 +tag_message (unused (void *ctx),
 +  notmuch_database_t *notmuch,
 +  const char *message_id,
 +  tag_op_list_t *tag_ops,
 +  tag_op_flag_t flags)
  {
  notmuch_status_t status;
 -notmuch_tags_t *db_tags;
 -char *db_tags_str;
  notmuch_message_t *message = NULL;
 -const char *tag;
 -char *next;
  int ret = 0;
  
  status = notmuch_database_find_message (notmuch, message_id, message);
 @@ -44,55 +48,63 @@ tag_message (notmuch_database_t *notmuch, const char 
 *message_id,
  
  /* In order to detect missing messages, this check/optimization is
   * intentionally done *after* first finding the message. */
 -if (! remove_all  (file_tags == NULL || *file_tags == '\0'))
 - goto DONE;
 -
 -db_tags_str = NULL;
 -for (db_tags = notmuch_message_get_tags (message);
 -  notmuch_tags_valid (db_tags);
 -  notmuch_tags_move_to_next (db_tags)) {
 - tag = notmuch_tags_get (db_tags);
 -
 - if (db_tags_str)
 - db_tags_str = talloc_asprintf_append (db_tags_str,  %s, tag);
 - else
 - db_tags_str = talloc_strdup (message, tag);
 -}
 +if ( (flags  TAG_FLAG_REMOVE_ALL) || (tag_op_list_size (tag_ops)))

Extra space between ('s, and no need to wrap tag_op_list_size call in
braces.

 + tag_op_list_apply (message, tag_ops, flags);
  
 -if (((file_tags == NULL || *file_tags == '\0') 
 -  (db_tags_str == NULL || *db_tags_str == '\0')) ||
 - (file_tags  db_tags_str  strcmp (file_tags, db_tags_str) == 0))

This is a necessary optimization you're throwing away, but I'll get back
to this after checking the last patch in the series.

 - goto DONE;
 +if (message)
 + notmuch_message_destroy (message);

message != NULL always, you can remove the if.

  
 -notmuch_message_freeze (message);
 +return ret;
 +}
  
 -if (remove_all)
 - notmuch_message_remove_all_tags (message);
 +static int
 +parse_sup_line (void *ctx, char *line,
 + char **query_str, tag_op_list_t *tag_ops)
 +{
  
 -next = file_tags;
 -while (next) {
 - tag = strsep (next,  );
 - if (*tag == '\0')
 - continue;
 - status = notmuch_message_add_tag (message, tag);
 - if (status) {
 - fprintf (stderr, Error applying tag %s to message %s:\n,
 -  tag, message_id);
 - fprintf (stderr, %s\n, notmuch_status_to_string (status));
 - ret = 1;
 - }
 +regmatch_t match[3];
 +char *file_tags;
 +int rerr;
 +
 +tag_op_list_reset (tag_ops);
 +
 +chomp_newline (line);
 +
 +/* Silently ignore blank lines */
 +if (line[0] == '\0') {
 + return 1;
 +}
 +
 +rerr = xregexec (regex, line, 3, match, 0);
 +if (rerr == REG_NOMATCH) {
 + fprintf (stderr, Warning: Ignoring invalid input line: %s\n,
 +  line);
 + return 1;
  }
  
 -notmuch_message_thaw (message);
 +*query_str = talloc_strndup (ctx, line + match[1].rm_so,
 +  match[1].rm_eo - match[1].rm_so);
 +file_tags = talloc_strndup (ctx, line + match[2].rm_so,
 + match[2].rm_eo - match[2].rm_so);
  
 -if (synchronize_flags)
 - notmuch_message_tags_to_maildir_flags (message);
 +char *tok = file_tags;
 +size_t tok_len = 0;
  
 -  DONE:
 -if (message)
 - notmuch_message_destroy (message);
 +tag_op_list_reset (tag_ops);
 +
 +while ((tok = strtok_len (tok + tok_len,  , tok_len)) != NULL) {
 +
 + if (*(tok + tok_len) != '\0') {
 + *(tok + tok_len) = '\0';
 + tok_len++;
 + }
 +
 + if (tag_op_list_append (ctx, tag_ops, tok, FALSE))
 + return -1;
 +}
 +
 +return 0;
  
 -return ret;
  }
  
  int
 @@ -100,16 +112,19 @@ notmuch_restore_command (unused (void *ctx), int argc, 
 char *argv[])
  {
  notmuch_config_t *config;
  notmuch_database_t *notmuch;
 -notmuch_bool_t synchronize_flags;
  notmuch_bool_t accumulate = FALSE;
 +tag_op_flag_t flags = 0;
 +tag_op_list_t *tag_ops;
 

[Patch v2 13/17] notmuch-restore: add support for input format 'batch-tag'

2012-11-24 Thread da...@tethera.net
From: David Bremner 

This is the same as the batch input for notmuch tag, except by default
it removes all tags before modifying a given message id and only "id:"
is supported.
---
 notmuch-restore.c |  199 +
 1 file changed, 125 insertions(+), 74 deletions(-)

diff --git a/notmuch-restore.c b/notmuch-restore.c
index f03dcac..22fcd2d 100644
--- a/notmuch-restore.c
+++ b/notmuch-restore.c
@@ -19,18 +19,22 @@
  */

 #include "notmuch-client.h"
+#include "dump-restore-private.h"
+#include "tag-util.h"
+#include "string-util.h"
+
+static volatile sig_atomic_t interrupted;
+static regex_t regex;

 static int
-tag_message (notmuch_database_t *notmuch, const char *message_id,
-char *file_tags, notmuch_bool_t remove_all,
-notmuch_bool_t synchronize_flags)
+tag_message (unused (void *ctx),
+notmuch_database_t *notmuch,
+const char *message_id,
+tag_op_list_t *tag_ops,
+tag_op_flag_t flags)
 {
 notmuch_status_t status;
-notmuch_tags_t *db_tags;
-char *db_tags_str;
 notmuch_message_t *message = NULL;
-const char *tag;
-char *next;
 int ret = 0;

 status = notmuch_database_find_message (notmuch, message_id, );
@@ -44,55 +48,63 @@ tag_message (notmuch_database_t *notmuch, const char 
*message_id,

 /* In order to detect missing messages, this check/optimization is
  * intentionally done *after* first finding the message. */
-if (! remove_all && (file_tags == NULL || *file_tags == '\0'))
-   goto DONE;
-
-db_tags_str = NULL;
-for (db_tags = notmuch_message_get_tags (message);
-notmuch_tags_valid (db_tags);
-notmuch_tags_move_to_next (db_tags)) {
-   tag = notmuch_tags_get (db_tags);
-
-   if (db_tags_str)
-   db_tags_str = talloc_asprintf_append (db_tags_str, " %s", tag);
-   else
-   db_tags_str = talloc_strdup (message, tag);
-}
+if ( (flags & TAG_FLAG_REMOVE_ALL) || (tag_op_list_size (tag_ops)))
+   tag_op_list_apply (message, tag_ops, flags);

-if (((file_tags == NULL || *file_tags == '\0') &&
-(db_tags_str == NULL || *db_tags_str == '\0')) ||
-   (file_tags && db_tags_str && strcmp (file_tags, db_tags_str) == 0))
-   goto DONE;
+if (message)
+   notmuch_message_destroy (message);

-notmuch_message_freeze (message);
+return ret;
+}

-if (remove_all)
-   notmuch_message_remove_all_tags (message);
+static int
+parse_sup_line (void *ctx, char *line,
+   char **query_str, tag_op_list_t *tag_ops)
+{

-next = file_tags;
-while (next) {
-   tag = strsep (, " ");
-   if (*tag == '\0')
-   continue;
-   status = notmuch_message_add_tag (message, tag);
-   if (status) {
-   fprintf (stderr, "Error applying tag %s to message %s:\n",
-tag, message_id);
-   fprintf (stderr, "%s\n", notmuch_status_to_string (status));
-   ret = 1;
-   }
+regmatch_t match[3];
+char *file_tags;
+int rerr;
+
+tag_op_list_reset (tag_ops);
+
+chomp_newline (line);
+
+/* Silently ignore blank lines */
+if (line[0] == '\0') {
+   return 1;
+}
+
+rerr = xregexec (, line, 3, match, 0);
+if (rerr == REG_NOMATCH) {
+   fprintf (stderr, "Warning: Ignoring invalid input line: %s\n",
+line);
+   return 1;
 }

-notmuch_message_thaw (message);
+*query_str = talloc_strndup (ctx, line + match[1].rm_so,
+match[1].rm_eo - match[1].rm_so);
+file_tags = talloc_strndup (ctx, line + match[2].rm_so,
+   match[2].rm_eo - match[2].rm_so);

-if (synchronize_flags)
-   notmuch_message_tags_to_maildir_flags (message);
+char *tok = file_tags;
+size_t tok_len = 0;

-  DONE:
-if (message)
-   notmuch_message_destroy (message);
+tag_op_list_reset (tag_ops);
+
+while ((tok = strtok_len (tok + tok_len, " ", _len)) != NULL) {
+
+   if (*(tok + tok_len) != '\0') {
+   *(tok + tok_len) = '\0';
+   tok_len++;
+   }
+
+   if (tag_op_list_append (ctx, tag_ops, tok, FALSE))
+   return -1;
+}
+
+return 0;

-return ret;
 }

 int
@@ -100,16 +112,19 @@ notmuch_restore_command (unused (void *ctx), int argc, 
char *argv[])
 {
 notmuch_config_t *config;
 notmuch_database_t *notmuch;
-notmuch_bool_t synchronize_flags;
 notmuch_bool_t accumulate = FALSE;
+tag_op_flag_t flags = 0;
+tag_op_list_t *tag_ops;
+
 char *input_file_name = NULL;
 FILE *input = stdin;
 char *line = NULL;
 size_t line_size;
 ssize_t line_len;
-regex_t regex;
-int rerr;
+
+int ret = 0;
 int opt_index;
+int input_format = DUMP_FORMAT_AUTO;

 config = notmuch_config_open (ctx, NULL, NULL);
 if (config == NULL)
@@ -119,9 +134,15 @@