[Patch v2 09/17] tag-util.[ch]: New files for common tagging routines

2012-11-30 Thread Austin Clements
Quoth David Bremner on Nov 29 at  8:17 pm:
> Mark Walters  writes:
> > I don't know how freeze/thaw work but does it matter that you don't thaw
> > when there is an error?
> 
> My interpretation is that by not thawing before we destroy the message,
> we are aborting the transaction, since the freeze/thaw information is
> stored in the message structure. It is documented as forbidden to call
> thaw _more_ times than freeze, but less is not explicitely mentioned.

Yes, this should work.  It smells a little hacky and I couldn't say if
it was an intended use of the API, but it should work.  Perhaps we
should document it.


Re: [Patch v2 09/17] tag-util.[ch]: New files for common tagging routines

2012-11-30 Thread Austin Clements
Quoth David Bremner on Nov 29 at  8:17 pm:
 Mark Walters markwalters1...@gmail.com writes:
  I don't know how freeze/thaw work but does it matter that you don't thaw
  when there is an error?
 
 My interpretation is that by not thawing before we destroy the message,
 we are aborting the transaction, since the freeze/thaw information is
 stored in the message structure. It is documented as forbidden to call
 thaw _more_ times than freeze, but less is not explicitely mentioned.

Yes, this should work.  It smells a little hacky and I couldn't say if
it was an intended use of the API, but it should work.  Perhaps we
should document it.
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[Patch v2 09/17] tag-util.[ch]: New files for common tagging routines

2012-11-29 Thread David Bremner
Mark Walters  writes:


> I don't know how freeze/thaw work but does it matter that you don't thaw
> when there is an error?

My interpretation is that by not thawing before we destroy the message,
we are aborting the transaction, since the freeze/thaw information is
stored in the message structure. It is documented as forbidden to call
thaw _more_ times than freeze, but less is not explicitely mentioned.

>> +
>> +/*
>> + * Add a tag operation (delete iff remote == TRUE) to a list.
>> + * The list is expanded as necessary.
>> + */
>
> Typo s/remote/remove/

fixed in local git.
>> +
>> +/*
>> + * Apply a list of tag operations, in order to a message.
>
> I found the comment awkward to parse: as "in order to "

Re-punctu-worded to 

"Apply a list of tag operations, in order, to a given message"


Re: [Patch v2 09/17] tag-util.[ch]: New files for common tagging routines

2012-11-29 Thread David Bremner
Mark Walters markwalters1...@gmail.com writes:


 I don't know how freeze/thaw work but does it matter that you don't thaw
 when there is an error?

My interpretation is that by not thawing before we destroy the message,
we are aborting the transaction, since the freeze/thaw information is
stored in the message structure. It is documented as forbidden to call
thaw _more_ times than freeze, but less is not explicitely mentioned.

 +
 +/*
 + * Add a tag operation (delete iff remote == TRUE) to a list.
 + * The list is expanded as necessary.
 + */

 Typo s/remote/remove/

fixed in local git.
 +
 +/*
 + * Apply a list of tag operations, in order to a message.

 I found the comment awkward to parse: as in order to do something

Re-punctu-worded to 

Apply a list of tag operations, in order, to a given message
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


[Patch v2 09/17] tag-util.[ch]: New files for common tagging routines

2012-11-25 Thread Mark Walters

This looks good. A couple of typos and a small queries (and I
agree with Tomi but I think you have already included that).

On Sat, 24 Nov 2012, david at tethera.net wrote:
> From: David Bremner 
>
> These are meant to be shared between notmuch-tag and notmuch-restore.
>
> The bulk of the routines implement a "tag operation list" abstract
> data type act as a structured representation of a set of tag
> operations (typically coming from a single tag command or line of
> input).
> ---
>  Makefile.local |1 +
>  tag-util.c |  264 
> 
>  tag-util.h |  120 ++
>  3 files changed, 385 insertions(+)
>  create mode 100644 tag-util.c
>  create mode 100644 tag-util.h
>
> diff --git a/Makefile.local b/Makefile.local
> index 2b91946..854867d 100644
> --- a/Makefile.local
> +++ b/Makefile.local
> @@ -274,6 +274,7 @@ notmuch_client_srcs = \
>   query-string.c  \
>   mime-node.c \
>   crypto.c\
> + tag-util.c
>  
>  notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
>  
> diff --git a/tag-util.c b/tag-util.c
> new file mode 100644
> index 000..287cc67
> --- /dev/null
> +++ b/tag-util.c
> @@ -0,0 +1,264 @@
> +#include "string-util.h"
> +#include "tag-util.h"
> +#include "hex-escape.h"
> +
> +struct _tag_operation_t {
> +const char *tag;
> +notmuch_bool_t remove;
> +};
> +
> +struct _tag_op_list_t {
> +tag_operation_t *ops;
> +int count;
> +int size;
> +};
> +
> +int
> +parse_tag_line (void *ctx, char *line,
> + tag_op_flag_t flags,
> + char **query_string,
> + tag_op_list_t *tag_ops)
> +{
> +char *tok = line;
> +size_t tok_len = 0;
> +
> +chomp_newline (line);
> +
> +/* remove leading space */
> +while (*tok == ' ' || *tok == '\t')
> + tok++;
> +
> +/* Skip empty and comment lines. */
> +if (*tok == '\0' || *tok == '#')
> + return 1;
> +
> +tag_op_list_reset (tag_ops);
> +
> +/* Parse tags. */
> +while ((tok = strtok_len (tok + tok_len, " ", _len)) != NULL) {
> + notmuch_bool_t remove;
> + char *tag;
> +
> + /* Optional explicit end of tags marker. */
> + if (strncmp (tok, "--", tok_len) == 0) {
> + tok = strtok_len (tok + tok_len, " ", _len);
> + break;
> + }
> +
> + /* Implicit end of tags. */
> + if (*tok != '-' && *tok != '+')
> + break;
> +
> + /* If tag is terminated by NUL, there's no query string. */
> + if (*(tok + tok_len) == '\0') {
> + tok = NULL;
> + break;
> + }
> +
> + /* Terminate, and start next token after terminator. */
> + *(tok + tok_len++) = '\0';
> +
> + remove = (*tok == '-');
> + tag = tok + 1;
> +
> + /* Maybe refuse empty tags. */
> + if (!(flags & TAG_FLAG_BE_GENEROUS) && *tag == '\0') {
> + tok = NULL;
> + break;
> + }
> +
> + /* Decode tag. */
> + if (hex_decode_inplace (tag) != HEX_SUCCESS) {
> + tok = NULL;
> + break;
> + }
> +
> + if (tag_op_list_append (ctx, tag_ops, tag, remove))
> + return -1;
> +}
> +
> +if (tok == NULL || tag_ops->count == 0) {
> + /* FIXME: line has been modified! */
> + fprintf (stderr, "Warning: Ignoring invalid input line: %s\n",
> +  line);
> + return 1;
> +}
> +
> +/* tok now points to the query string */
> +if (hex_decode_inplace (tok) != HEX_SUCCESS) {
> + /* FIXME: line has been modified! */
> + fprintf (stderr, "Warning: Ignoring invalid input line: %s\n",
> +  line);
> + return 1;
> +}
> +
> +*query_string = tok;
> +
> +return 0;
> +}
> +
> +static inline void
> +message_error (notmuch_message_t *message,
> +notmuch_status_t status,
> +const char *format, ...)
> +{
> +va_list va_args;
> +
> +va_start (va_args, format);
> +
> +vfprintf (stderr, format, va_args);
> +fprintf (stderr, "Message-ID: %s\n", notmuch_message_get_message_id 
> (message));
> +fprintf (stderr, "Status: %s\n", notmuch_status_to_string (status));
> +}
> +
> +notmuch_status_t
> +tag_op_list_apply (notmuch_message_t *message,
> +tag_op_list_t *list,
> +tag_op_flag_t flags)
> +{
> +int i;
> +
> +notmuch_status_t status = 0;
> +tag_operation_t *tag_ops = list->ops;
> +
> +status = notmuch_message_freeze (message);
> +if (status) {
> + message_error (message, status, "freezing message");
> + return status;
> +}
> +
> +if (flags & TAG_FLAG_REMOVE_ALL) {
> + status = notmuch_message_remove_all_tags (message);
> + if (status) {
> + message_error (message, status, "removing all tags" );
> + return status;
> + }
> +}
> +
> +for (i = 0; i < list->count; i++) {
> + if (tag_ops[i].remove) {
> + status = notmuch_message_remove_tag 

[Patch v2 09/17] tag-util.[ch]: New files for common tagging routines

2012-11-25 Thread Tomi Ollila
On Sat, Nov 24 2012, david at tethera.net wrote:

> From: David Bremner 
>
> These are meant to be shared between notmuch-tag and notmuch-restore.
>
> The bulk of the routines implement a "tag operation list" abstract
> data type act as a structured representation of a set of tag
> operations (typically coming from a single tag command or line of
> input).
> ---

dumping all except beginning of tag-util.h...

>  tag-util.h |  120 ++
> diff --git a/tag-util.h b/tag-util.h
> new file mode 100644
> index 000..508806f
> --- /dev/null
> +++ b/tag-util.h
> @@ -0,0 +1,120 @@
> +#ifndef _TAG_UTIL_H
> +#define _TAG_UTIL_H
> +
> +#include "notmuch-client.h"
> +
> +typedef struct _tag_operation_t tag_operation_t;
> +typedef struct _tag_op_list_t tag_op_list_t;
> +
> +#define TAG_OP_LIST_INITIAL_SIZE 10
> +
> +/* Use powers of 2 */
> +typedef enum  { TAG_FLAG_NONE = 0,
> + /* Operations are synced to maildir, if possible */
> +
> + TAG_FLAG_MAILDIR_SYNC = 1,
> +
> + /* Remove all tags from message before applying
> +  * list */
> +
> + TAG_FLAG_REMOVE_ALL = 2,
> +
> + /* Don't try to avoid database operations.  Useful
> +  * when we know that message passed needs these
> +  *  operations. */
> +
> + TAG_FLAG_PRE_OPTIMIZED = 4,
> +
> + /* Accept strange tags that might be user error;
> +intended for use by notmuch-restore.
> + */
> +
> + TAG_FLAG_BE_GENEROUS = 8} tag_op_flag_t;
> +

Maybe something like the following formatted and consistency-tuned version:

typedef enum { 
   TAG_FLAG_NONE = 0,

   /* Operations are synced to maildir, if possible.
*/
   TAG_FLAG_MAILDIR_SYNC = (1 << 0),

   /* Remove all tags from message before applying list.
*/
   TAG_FLAG_REMOVE_ALL = (1 << 1),

   /* Don't try to avoid database operations. Useful when we
* know that message passed needs these operations.
*/
   TAG_FLAG_PRE_OPTIMIZED = (1 << 2),

   /* Accept strange tags that might be user error;
* intended for use by notmuch-restore.
*/
   TAG_FLAG_BE_GENEROUS = (1 << 3)

} tag_op_flag_t;

Tomi


Re: [Patch v2 09/17] tag-util.[ch]: New files for common tagging routines

2012-11-25 Thread Mark Walters

This looks good. A couple of typos and a small queries (and I
agree with Tomi but I think you have already included that).

On Sat, 24 Nov 2012, da...@tethera.net wrote:
 From: David Bremner brem...@debian.org

 These are meant to be shared between notmuch-tag and notmuch-restore.

 The bulk of the routines implement a tag operation list abstract
 data type act as a structured representation of a set of tag
 operations (typically coming from a single tag command or line of
 input).
 ---
  Makefile.local |1 +
  tag-util.c |  264 
 
  tag-util.h |  120 ++
  3 files changed, 385 insertions(+)
  create mode 100644 tag-util.c
  create mode 100644 tag-util.h

 diff --git a/Makefile.local b/Makefile.local
 index 2b91946..854867d 100644
 --- a/Makefile.local
 +++ b/Makefile.local
 @@ -274,6 +274,7 @@ notmuch_client_srcs = \
   query-string.c  \
   mime-node.c \
   crypto.c\
 + tag-util.c
  
  notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
  
 diff --git a/tag-util.c b/tag-util.c
 new file mode 100644
 index 000..287cc67
 --- /dev/null
 +++ b/tag-util.c
 @@ -0,0 +1,264 @@
 +#include string-util.h
 +#include tag-util.h
 +#include hex-escape.h
 +
 +struct _tag_operation_t {
 +const char *tag;
 +notmuch_bool_t remove;
 +};
 +
 +struct _tag_op_list_t {
 +tag_operation_t *ops;
 +int count;
 +int size;
 +};
 +
 +int
 +parse_tag_line (void *ctx, char *line,
 + tag_op_flag_t flags,
 + char **query_string,
 + tag_op_list_t *tag_ops)
 +{
 +char *tok = line;
 +size_t tok_len = 0;
 +
 +chomp_newline (line);
 +
 +/* remove leading space */
 +while (*tok == ' ' || *tok == '\t')
 + tok++;
 +
 +/* Skip empty and comment lines. */
 +if (*tok == '\0' || *tok == '#')
 + return 1;
 +
 +tag_op_list_reset (tag_ops);
 +
 +/* Parse tags. */
 +while ((tok = strtok_len (tok + tok_len,  , tok_len)) != NULL) {
 + notmuch_bool_t remove;
 + char *tag;
 +
 + /* Optional explicit end of tags marker. */
 + if (strncmp (tok, --, tok_len) == 0) {
 + tok = strtok_len (tok + tok_len,  , tok_len);
 + break;
 + }
 +
 + /* Implicit end of tags. */
 + if (*tok != '-'  *tok != '+')
 + break;
 +
 + /* If tag is terminated by NUL, there's no query string. */
 + if (*(tok + tok_len) == '\0') {
 + tok = NULL;
 + break;
 + }
 +
 + /* Terminate, and start next token after terminator. */
 + *(tok + tok_len++) = '\0';
 +
 + remove = (*tok == '-');
 + tag = tok + 1;
 +
 + /* Maybe refuse empty tags. */
 + if (!(flags  TAG_FLAG_BE_GENEROUS)  *tag == '\0') {
 + tok = NULL;
 + break;
 + }
 +
 + /* Decode tag. */
 + if (hex_decode_inplace (tag) != HEX_SUCCESS) {
 + tok = NULL;
 + break;
 + }
 +
 + if (tag_op_list_append (ctx, tag_ops, tag, remove))
 + return -1;
 +}
 +
 +if (tok == NULL || tag_ops-count == 0) {
 + /* FIXME: line has been modified! */
 + fprintf (stderr, Warning: Ignoring invalid input line: %s\n,
 +  line);
 + return 1;
 +}
 +
 +/* tok now points to the query string */
 +if (hex_decode_inplace (tok) != HEX_SUCCESS) {
 + /* FIXME: line has been modified! */
 + fprintf (stderr, Warning: Ignoring invalid input line: %s\n,
 +  line);
 + return 1;
 +}
 +
 +*query_string = tok;
 +
 +return 0;
 +}
 +
 +static inline void
 +message_error (notmuch_message_t *message,
 +notmuch_status_t status,
 +const char *format, ...)
 +{
 +va_list va_args;
 +
 +va_start (va_args, format);
 +
 +vfprintf (stderr, format, va_args);
 +fprintf (stderr, Message-ID: %s\n, notmuch_message_get_message_id 
 (message));
 +fprintf (stderr, Status: %s\n, notmuch_status_to_string (status));
 +}
 +
 +notmuch_status_t
 +tag_op_list_apply (notmuch_message_t *message,
 +tag_op_list_t *list,
 +tag_op_flag_t flags)
 +{
 +int i;
 +
 +notmuch_status_t status = 0;
 +tag_operation_t *tag_ops = list-ops;
 +
 +status = notmuch_message_freeze (message);
 +if (status) {
 + message_error (message, status, freezing message);
 + return status;
 +}
 +
 +if (flags  TAG_FLAG_REMOVE_ALL) {
 + status = notmuch_message_remove_all_tags (message);
 + if (status) {
 + message_error (message, status, removing all tags );
 + return status;
 + }
 +}
 +
 +for (i = 0; i  list-count; i++) {
 + if (tag_ops[i].remove) {
 + status = notmuch_message_remove_tag (message, tag_ops[i].tag);
 + if (status) {
 + message_error (message, status, removing tag %s, 
 tag_ops[i].tag);
 + return status;
 + }
 + } else {
 +

[Patch v2 09/17] tag-util.[ch]: New files for common tagging routines

2012-11-24 Thread David Bremner

>
> Maybe something like the following formatted and consistency-tuned version:
>
> typedef enum { 
>TAG_FLAG_NONE = 0,
>
>/* Operations are synced to maildir, if possible.
> */
>TAG_FLAG_MAILDIR_SYNC = (1 << 0),
>
>/* Remove all tags from message before applying list.
> */
>TAG_FLAG_REMOVE_ALL = (1 << 1),
>
>/* Don't try to avoid database operations. Useful when we
> * know that message passed needs these operations.
> */
>TAG_FLAG_PRE_OPTIMIZED = (1 << 2),
>
>/* Accept strange tags that might be user error;
> * intended for use by notmuch-restore.
> */
>TAG_FLAG_BE_GENEROUS = (1 << 3)
>
> } tag_op_flag_t;
>

Applied.  We may have to fight uncrustify on this, but we both know who
likes to play with uncrustify config ;).

d



[Patch v2 09/17] tag-util.[ch]: New files for common tagging routines

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

These are meant to be shared between notmuch-tag and notmuch-restore.

The bulk of the routines implement a "tag operation list" abstract
data type act as a structured representation of a set of tag
operations (typically coming from a single tag command or line of
input).
---
 Makefile.local |1 +
 tag-util.c |  264 
 tag-util.h |  120 ++
 3 files changed, 385 insertions(+)
 create mode 100644 tag-util.c
 create mode 100644 tag-util.h

diff --git a/Makefile.local b/Makefile.local
index 2b91946..854867d 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -274,6 +274,7 @@ notmuch_client_srcs =   \
query-string.c  \
mime-node.c \
crypto.c\
+   tag-util.c

 notmuch_client_modules = $(notmuch_client_srcs:.c=.o)

diff --git a/tag-util.c b/tag-util.c
new file mode 100644
index 000..287cc67
--- /dev/null
+++ b/tag-util.c
@@ -0,0 +1,264 @@
+#include "string-util.h"
+#include "tag-util.h"
+#include "hex-escape.h"
+
+struct _tag_operation_t {
+const char *tag;
+notmuch_bool_t remove;
+};
+
+struct _tag_op_list_t {
+tag_operation_t *ops;
+int count;
+int size;
+};
+
+int
+parse_tag_line (void *ctx, char *line,
+   tag_op_flag_t flags,
+   char **query_string,
+   tag_op_list_t *tag_ops)
+{
+char *tok = line;
+size_t tok_len = 0;
+
+chomp_newline (line);
+
+/* remove leading space */
+while (*tok == ' ' || *tok == '\t')
+   tok++;
+
+/* Skip empty and comment lines. */
+if (*tok == '\0' || *tok == '#')
+   return 1;
+
+tag_op_list_reset (tag_ops);
+
+/* Parse tags. */
+while ((tok = strtok_len (tok + tok_len, " ", _len)) != NULL) {
+   notmuch_bool_t remove;
+   char *tag;
+
+   /* Optional explicit end of tags marker. */
+   if (strncmp (tok, "--", tok_len) == 0) {
+   tok = strtok_len (tok + tok_len, " ", _len);
+   break;
+   }
+
+   /* Implicit end of tags. */
+   if (*tok != '-' && *tok != '+')
+   break;
+
+   /* If tag is terminated by NUL, there's no query string. */
+   if (*(tok + tok_len) == '\0') {
+   tok = NULL;
+   break;
+   }
+
+   /* Terminate, and start next token after terminator. */
+   *(tok + tok_len++) = '\0';
+
+   remove = (*tok == '-');
+   tag = tok + 1;
+
+   /* Maybe refuse empty tags. */
+   if (!(flags & TAG_FLAG_BE_GENEROUS) && *tag == '\0') {
+   tok = NULL;
+   break;
+   }
+
+   /* Decode tag. */
+   if (hex_decode_inplace (tag) != HEX_SUCCESS) {
+   tok = NULL;
+   break;
+   }
+
+   if (tag_op_list_append (ctx, tag_ops, tag, remove))
+   return -1;
+}
+
+if (tok == NULL || tag_ops->count == 0) {
+   /* FIXME: line has been modified! */
+   fprintf (stderr, "Warning: Ignoring invalid input line: %s\n",
+line);
+   return 1;
+}
+
+/* tok now points to the query string */
+if (hex_decode_inplace (tok) != HEX_SUCCESS) {
+   /* FIXME: line has been modified! */
+   fprintf (stderr, "Warning: Ignoring invalid input line: %s\n",
+line);
+   return 1;
+}
+
+*query_string = tok;
+
+return 0;
+}
+
+static inline void
+message_error (notmuch_message_t *message,
+  notmuch_status_t status,
+  const char *format, ...)
+{
+va_list va_args;
+
+va_start (va_args, format);
+
+vfprintf (stderr, format, va_args);
+fprintf (stderr, "Message-ID: %s\n", notmuch_message_get_message_id 
(message));
+fprintf (stderr, "Status: %s\n", notmuch_status_to_string (status));
+}
+
+notmuch_status_t
+tag_op_list_apply (notmuch_message_t *message,
+  tag_op_list_t *list,
+  tag_op_flag_t flags)
+{
+int i;
+
+notmuch_status_t status = 0;
+tag_operation_t *tag_ops = list->ops;
+
+status = notmuch_message_freeze (message);
+if (status) {
+   message_error (message, status, "freezing message");
+   return status;
+}
+
+if (flags & TAG_FLAG_REMOVE_ALL) {
+   status = notmuch_message_remove_all_tags (message);
+   if (status) {
+   message_error (message, status, "removing all tags" );
+   return status;
+   }
+}
+
+for (i = 0; i < list->count; i++) {
+   if (tag_ops[i].remove) {
+   status = notmuch_message_remove_tag (message, tag_ops[i].tag);
+   if (status) {
+   message_error (message, status, "removing tag %s", 
tag_ops[i].tag);
+   return status;
+   }
+   } else {
+   status = notmuch_message_add_tag (message, tag_ops[i].tag);
+   if (status) {
+   message_error (message, status, "adding tag %s", 
tag_ops[i].tag);
+ 

[Patch v2 09/17] tag-util.[ch]: New files for common tagging routines

2012-11-24 Thread david
From: David Bremner brem...@debian.org

These are meant to be shared between notmuch-tag and notmuch-restore.

The bulk of the routines implement a tag operation list abstract
data type act as a structured representation of a set of tag
operations (typically coming from a single tag command or line of
input).
---
 Makefile.local |1 +
 tag-util.c |  264 
 tag-util.h |  120 ++
 3 files changed, 385 insertions(+)
 create mode 100644 tag-util.c
 create mode 100644 tag-util.h

diff --git a/Makefile.local b/Makefile.local
index 2b91946..854867d 100644
--- a/Makefile.local
+++ b/Makefile.local
@@ -274,6 +274,7 @@ notmuch_client_srcs =   \
query-string.c  \
mime-node.c \
crypto.c\
+   tag-util.c
 
 notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
 
diff --git a/tag-util.c b/tag-util.c
new file mode 100644
index 000..287cc67
--- /dev/null
+++ b/tag-util.c
@@ -0,0 +1,264 @@
+#include string-util.h
+#include tag-util.h
+#include hex-escape.h
+
+struct _tag_operation_t {
+const char *tag;
+notmuch_bool_t remove;
+};
+
+struct _tag_op_list_t {
+tag_operation_t *ops;
+int count;
+int size;
+};
+
+int
+parse_tag_line (void *ctx, char *line,
+   tag_op_flag_t flags,
+   char **query_string,
+   tag_op_list_t *tag_ops)
+{
+char *tok = line;
+size_t tok_len = 0;
+
+chomp_newline (line);
+
+/* remove leading space */
+while (*tok == ' ' || *tok == '\t')
+   tok++;
+
+/* Skip empty and comment lines. */
+if (*tok == '\0' || *tok == '#')
+   return 1;
+
+tag_op_list_reset (tag_ops);
+
+/* Parse tags. */
+while ((tok = strtok_len (tok + tok_len,  , tok_len)) != NULL) {
+   notmuch_bool_t remove;
+   char *tag;
+
+   /* Optional explicit end of tags marker. */
+   if (strncmp (tok, --, tok_len) == 0) {
+   tok = strtok_len (tok + tok_len,  , tok_len);
+   break;
+   }
+
+   /* Implicit end of tags. */
+   if (*tok != '-'  *tok != '+')
+   break;
+
+   /* If tag is terminated by NUL, there's no query string. */
+   if (*(tok + tok_len) == '\0') {
+   tok = NULL;
+   break;
+   }
+
+   /* Terminate, and start next token after terminator. */
+   *(tok + tok_len++) = '\0';
+
+   remove = (*tok == '-');
+   tag = tok + 1;
+
+   /* Maybe refuse empty tags. */
+   if (!(flags  TAG_FLAG_BE_GENEROUS)  *tag == '\0') {
+   tok = NULL;
+   break;
+   }
+
+   /* Decode tag. */
+   if (hex_decode_inplace (tag) != HEX_SUCCESS) {
+   tok = NULL;
+   break;
+   }
+
+   if (tag_op_list_append (ctx, tag_ops, tag, remove))
+   return -1;
+}
+
+if (tok == NULL || tag_ops-count == 0) {
+   /* FIXME: line has been modified! */
+   fprintf (stderr, Warning: Ignoring invalid input line: %s\n,
+line);
+   return 1;
+}
+
+/* tok now points to the query string */
+if (hex_decode_inplace (tok) != HEX_SUCCESS) {
+   /* FIXME: line has been modified! */
+   fprintf (stderr, Warning: Ignoring invalid input line: %s\n,
+line);
+   return 1;
+}
+
+*query_string = tok;
+
+return 0;
+}
+
+static inline void
+message_error (notmuch_message_t *message,
+  notmuch_status_t status,
+  const char *format, ...)
+{
+va_list va_args;
+
+va_start (va_args, format);
+
+vfprintf (stderr, format, va_args);
+fprintf (stderr, Message-ID: %s\n, notmuch_message_get_message_id 
(message));
+fprintf (stderr, Status: %s\n, notmuch_status_to_string (status));
+}
+
+notmuch_status_t
+tag_op_list_apply (notmuch_message_t *message,
+  tag_op_list_t *list,
+  tag_op_flag_t flags)
+{
+int i;
+
+notmuch_status_t status = 0;
+tag_operation_t *tag_ops = list-ops;
+
+status = notmuch_message_freeze (message);
+if (status) {
+   message_error (message, status, freezing message);
+   return status;
+}
+
+if (flags  TAG_FLAG_REMOVE_ALL) {
+   status = notmuch_message_remove_all_tags (message);
+   if (status) {
+   message_error (message, status, removing all tags );
+   return status;
+   }
+}
+
+for (i = 0; i  list-count; i++) {
+   if (tag_ops[i].remove) {
+   status = notmuch_message_remove_tag (message, tag_ops[i].tag);
+   if (status) {
+   message_error (message, status, removing tag %s, 
tag_ops[i].tag);
+   return status;
+   }
+   } else {
+   status = notmuch_message_add_tag (message, tag_ops[i].tag);
+   if (status) {
+   message_error (message, status, adding tag %s, 
tag_ops[i].tag);
+   return status;
+   

Re: [Patch v2 09/17] tag-util.[ch]: New files for common tagging routines

2012-11-24 Thread Tomi Ollila
On Sat, Nov 24 2012, da...@tethera.net wrote:

 From: David Bremner brem...@debian.org

 These are meant to be shared between notmuch-tag and notmuch-restore.

 The bulk of the routines implement a tag operation list abstract
 data type act as a structured representation of a set of tag
 operations (typically coming from a single tag command or line of
 input).
 ---

dumping all except beginning of tag-util.h...

  tag-util.h |  120 ++
 diff --git a/tag-util.h b/tag-util.h
 new file mode 100644
 index 000..508806f
 --- /dev/null
 +++ b/tag-util.h
 @@ -0,0 +1,120 @@
 +#ifndef _TAG_UTIL_H
 +#define _TAG_UTIL_H
 +
 +#include notmuch-client.h
 +
 +typedef struct _tag_operation_t tag_operation_t;
 +typedef struct _tag_op_list_t tag_op_list_t;
 +
 +#define TAG_OP_LIST_INITIAL_SIZE 10
 +
 +/* Use powers of 2 */
 +typedef enum  { TAG_FLAG_NONE = 0,
 + /* Operations are synced to maildir, if possible */
 +
 + TAG_FLAG_MAILDIR_SYNC = 1,
 +
 + /* Remove all tags from message before applying
 +  * list */
 +
 + TAG_FLAG_REMOVE_ALL = 2,
 +
 + /* Don't try to avoid database operations.  Useful
 +  * when we know that message passed needs these
 +  *  operations. */
 +
 + TAG_FLAG_PRE_OPTIMIZED = 4,
 +
 + /* Accept strange tags that might be user error;
 +intended for use by notmuch-restore.
 + */
 +
 + TAG_FLAG_BE_GENEROUS = 8} tag_op_flag_t;
 +

Maybe something like the following formatted and consistency-tuned version:

typedef enum { 
   TAG_FLAG_NONE = 0,

   /* Operations are synced to maildir, if possible.
*/
   TAG_FLAG_MAILDIR_SYNC = (1  0),

   /* Remove all tags from message before applying list.
*/
   TAG_FLAG_REMOVE_ALL = (1  1),

   /* Don't try to avoid database operations. Useful when we
* know that message passed needs these operations.
*/
   TAG_FLAG_PRE_OPTIMIZED = (1  2),

   /* Accept strange tags that might be user error;
* intended for use by notmuch-restore.
*/
   TAG_FLAG_BE_GENEROUS = (1  3)

} tag_op_flag_t;

Tomi
___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch


Re: [Patch v2 09/17] tag-util.[ch]: New files for common tagging routines

2012-11-24 Thread David Bremner


 Maybe something like the following formatted and consistency-tuned version:

 typedef enum { 
TAG_FLAG_NONE = 0,

/* Operations are synced to maildir, if possible.
 */
TAG_FLAG_MAILDIR_SYNC = (1  0),

/* Remove all tags from message before applying list.
 */
TAG_FLAG_REMOVE_ALL = (1  1),

/* Don't try to avoid database operations. Useful when we
 * know that message passed needs these operations.
 */
TAG_FLAG_PRE_OPTIMIZED = (1  2),

/* Accept strange tags that might be user error;
 * intended for use by notmuch-restore.
 */
TAG_FLAG_BE_GENEROUS = (1  3)

 } tag_op_flag_t;


Applied.  We may have to fight uncrustify on this, but we both know who
likes to play with uncrustify config ;).

d

___
notmuch mailing list
notmuch@notmuchmail.org
http://notmuchmail.org/mailman/listinfo/notmuch