]> granicus.if.org Git - neomutt/commitdiff
Make the notmuch tags generic
authorMehdi Abaakouk <sileht@sileht.net>
Tue, 14 Feb 2017 09:45:45 +0000 (10:45 +0100)
committerRichard Russon <rich@flatcap.org>
Tue, 3 Oct 2017 12:47:30 +0000 (13:47 +0100)
This change make the notmuch tags generic.

This is in preparation of reusing it for imap keywords feature.

21 files changed:
Makefile.am
color.c
copy.c
functions.h
globals.h
hcache/hcache.c
hdrline.c
header.h
init.c
init.h
lib/string.c
lib/string2.h
menu.c
mutt.h
mutt_curses.h
mutt_notmuch.c
mutt_tags.c [new file with mode: 0644]
mutt_tags.h [new file with mode: 0644]
muttlib.c
opcodes.h
pattern.c

index b00d1f8ac1927c236b7f05f4daf48396a83c4285..d3e125b41416a9b89b15df29f75757e7b122a08c 100644 (file)
@@ -55,7 +55,7 @@ neomutt_SOURCES = account.c addrbook.c address.h alias.c alias.h attach.c \
        query.c recvattach.c recvcmd.c rfc1524.c rfc2047.c rfc2231.c rfc3676.c \
        rfc822.c safe_asprintf.c score.c send.c sendlib.c sidebar.c signal.c \
        smtp.c sort.c state.c state.h status.c system.c thread.c thread.h url.c \
-       version.c where.h
+       version.c where.h mutt_tags.c
 
 nodist_neomutt_SOURCES = $(BUILT_SOURCES)
 
@@ -90,7 +90,7 @@ EXTRA_DIST = account.h attach.h bcache.h browser.h buffy.h \
        mutt_socket.h mutt_ssl.h mutt_tunnel.h mx.h myvar.h nntp.h opcodes.h pager.h \
        pgpewrap.c pop.h protos.h queue.h README.md README.SSL remailer.c remailer.h \
        rfc1524.h rfc2047.h rfc2231.h rfc3676.h rfc822.h sidebar.h \
-       sort.h txt2c.c txt2c.sh version.h
+       sort.h txt2c.c txt2c.sh version.h mutt_tags.h
 
 EXTRA_SCRIPTS =
 
diff --git a/color.c b/color.c
index 44986cb387fc12911fd07682664338b31b6dd6a2..b1bccfec1e295dfe223a231721393e6b7f24bb1f 100644 (file)
--- a/color.c
+++ b/color.c
@@ -51,9 +51,7 @@ struct ColorLine *ColorIndexList = NULL;
 struct ColorLine *ColorIndexAuthorList = NULL;
 struct ColorLine *ColorIndexFlagsList = NULL;
 struct ColorLine *ColorIndexSubjectList = NULL;
-#ifdef USE_NOTMUCH
 struct ColorLine *ColorIndexTagList = NULL;
-#endif
 
 /* local to this file */
 static int ColorQuoteSize;
@@ -123,10 +121,8 @@ static const struct Mapping Fields[] = {
   { "index_number", MT_COLOR_INDEX_NUMBER },
   { "index_size", MT_COLOR_INDEX_SIZE },
   { "index_subject", MT_COLOR_INDEX_SUBJECT },
-#ifdef USE_NOTMUCH
   { "index_tag", MT_COLOR_INDEX_TAG },
   { "index_tags", MT_COLOR_INDEX_TAGS },
-#endif
   { "prompt", MT_COLOR_PROMPT },
 #ifdef USE_SIDEBAR
   { "sidebar_divider", MT_COLOR_DIVIDER },
@@ -572,10 +568,8 @@ static int _mutt_parse_uncolor(struct Buffer *buf, struct Buffer *s, unsigned lo
     do_uncolor(buf, s, &ColorIndexFlagsList, &do_cache, parse_uncolor);
   else if (object == MT_COLOR_INDEX_SUBJECT)
     do_uncolor(buf, s, &ColorIndexSubjectList, &do_cache, parse_uncolor);
-#ifdef USE_NOTMUCH
   else if (object == MT_COLOR_INDEX_TAG)
     do_uncolor(buf, s, &ColorIndexTagList, &do_cache, parse_uncolor);
-#endif
 
   if (do_cache && !option(OPT_NO_CURSES))
   {
@@ -847,10 +841,7 @@ static int _mutt_parse_color(struct Buffer *buf, struct Buffer *s, struct Buffer
   if ((object == MT_COLOR_BODY) || (object == MT_COLOR_HEADER) ||
       (object == MT_COLOR_ATTACH_HEADERS) || (object == MT_COLOR_INDEX) ||
       (object == MT_COLOR_INDEX_AUTHOR) || (object == MT_COLOR_INDEX_FLAGS) ||
-#ifdef USE_NOTMUCH
-      (object == MT_COLOR_INDEX_TAG) ||
-#endif
-      (object == MT_COLOR_INDEX_SUBJECT))
+      (object == MT_COLOR_INDEX_TAG) || (object == MT_COLOR_INDEX_SUBJECT))
   {
     if (!MoreArgs(s))
     {
@@ -945,13 +936,11 @@ static int _mutt_parse_color(struct Buffer *buf, struct Buffer *s, struct Buffer
     r = add_pattern(&ColorIndexSubjectList, buf->data, 1, fg, bg, attr, err, 1, match);
     mutt_set_menu_redraw_full(MENU_MAIN);
   }
-#ifdef USE_NOTMUCH
   else if (object == MT_COLOR_INDEX_TAG)
   {
     r = add_pattern(&ColorIndexTagList, buf->data, 1, fg, bg, attr, err, 1, match);
     mutt_set_menu_redraw_full(MENU_MAIN);
   }
-#endif
   else if (object == MT_COLOR_QUOTED)
   {
     if (q_level >= ColorQuoteSize)
diff --git a/copy.c b/copy.c
index e84a124157b528be7217a4d1c1c2194dec09d05e..0934b48a6b3787c53730b532c8a78af3dce9e128 100644 (file)
--- a/copy.c
+++ b/copy.c
@@ -39,6 +39,7 @@
 #include "mime.h"
 #include "mutt_curses.h"
 #include "mutt_idna.h"
+#include "mutt_tags.h"
 #include "mx.h"
 #include "ncrypt/ncrypt.h"
 #include "options.h"
@@ -464,7 +465,7 @@ int mutt_copy_header(FILE *in, struct Header *h, FILE *out, int flags, const cha
       fputs(buf, out);
       fputc('\n', out);
     }
-    char *tags = nm_header_get_tags(h);
+    const char *tags = hdr_tags_get(h);
     if (tags && !(option(OPT_WEED) && mutt_matches_ignore("tags")))
     {
       fputs("Tags: ", out);
index ad81ce28637f0635fd513fd4cc838cb9b4348084..36b0faebccc2c56f53b244383ba31bb9b7e212f1 100644 (file)
@@ -213,13 +213,14 @@ const struct Binding OpMain[] = { /* map: index */
   { "sidebar-toggle-virtual",    OP_SIDEBAR_TOGGLE_VIRTUAL,         NULL },
   { "sidebar-toggle-visible",    OP_SIDEBAR_TOGGLE_VISIBLE,         NULL },
 #endif
+  { "modify-labels",             OP_MAIN_MODIFY_LABELS,             NULL },
+  { "modify-labels-then-hide",   OP_MAIN_MODIFY_LABELS_THEN_HIDE,   NULL },
+
 #ifdef USE_NOTMUCH
   { "change-vfolder",            OP_MAIN_CHANGE_VFOLDER,            NULL },
   { "vfolder-from-query",        OP_MAIN_VFOLDER_FROM_QUERY,        NULL },
   { "vfolder-window-backward",   OP_MAIN_WINDOWED_VFOLDER_BACKWARD, NULL },
   { "vfolder-window-forward",    OP_MAIN_WINDOWED_VFOLDER_FORWARD,  NULL },
-  { "modify-labels",             OP_MAIN_MODIFY_LABELS,             NULL },
-  { "modify-labels-then-hide",   OP_MAIN_MODIFY_LABELS_THEN_HIDE,   NULL },
   { "entire-thread",             OP_MAIN_ENTIRE_THREAD,             NULL },
 #endif
   { NULL,                        0,                                 NULL },
@@ -349,11 +350,12 @@ const struct Binding OpPager[] = { /* map: pager */
   { "sidebar-toggle-virtual",    OP_SIDEBAR_TOGGLE_VIRTUAL,       NULL },
   { "sidebar-toggle-visible",    OP_SIDEBAR_TOGGLE_VISIBLE,       NULL },
 #endif
+  { "modify-labels",             OP_MAIN_MODIFY_LABELS,           NULL },
+  { "modify-labels-then-hide",   OP_MAIN_MODIFY_LABELS_THEN_HIDE, NULL },
+
 #ifdef USE_NOTMUCH
   { "change-vfolder",            OP_MAIN_CHANGE_VFOLDER,          NULL },
   { "vfolder-from-query",        OP_MAIN_VFOLDER_FROM_QUERY,      NULL },
-  { "modify-labels",             OP_MAIN_MODIFY_LABELS,           NULL },
-  { "modify-labels-then-hide",   OP_MAIN_MODIFY_LABELS_THEN_HIDE, NULL },
   { "entire-thread",             OP_MAIN_ENTIRE_THREAD,           NULL },
 #endif
   { NULL,                        0,                               NULL },
index 5aa899aae7fed10096138d2a749fe09a9ece3885..79a966dd811586a13e02951ec4df90b901aeaaff 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -198,10 +198,9 @@ WHERE const char *GitVer;
 
 WHERE struct Hash *Groups;
 WHERE struct Hash *ReverseAliases;
-#ifdef USE_NOTMUCH
+WHERE char *HiddenTags;
 WHERE struct Hash *TagTransforms;
 WHERE struct Hash *TagFormats;
-#endif
 
 WHERE struct ListHead AutoViewList INITVAL(STAILQ_HEAD_INITIALIZER(AutoViewList));
 WHERE struct ListHead AlternativeOrderList INITVAL(STAILQ_HEAD_INITIALIZER(AlternativeOrderList));
@@ -332,7 +331,6 @@ WHERE int NmOpenTimeout;
 WHERE char *NmDefaultUri;
 WHERE char *NmExcludeTags;
 WHERE char *NmUnreadTag;
-WHERE char *NmHiddenTags;
 WHERE char *VfolderFormat;
 WHERE int NmDbLimit;
 WHERE char *NmQueryType;
index e6b3bd830a902a259021ea21cac28acab1b59e46..2e6c0c96c467f1453c684c544dc82814267bb783 100644 (file)
@@ -685,6 +685,7 @@ static void *hcache_dump(header_cache_t *h, struct Header *header, int *off,
   nh.path = NULL;
   nh.tree = NULL;
   nh.thread = NULL;
+  nh.tags = NULL;
 #ifdef MIXMASTER
   STAILQ_INIT(&nh.chain);
 #endif
index 8f8ffc2a5edfacfcce3867c35f706c2d41efadb7..a9aa2327d0a810d4534093d17b3111631af18b7d 100644 (file)
--- a/hdrline.c
+++ b/hdrline.c
@@ -42,6 +42,7 @@
 #include "mbtable.h"
 #include "mutt_curses.h"
 #include "mutt_idna.h"
+#include "mutt_tags.h"
 #include "ncrypt/ncrypt.h"
 #include "options.h"
 #include "protos.h"
@@ -469,7 +470,8 @@ static char *apply_subject_mods(struct Envelope *env)
  * | \%E     | number of messages in current thread
  * | \%f     | entire from line
  * | \%F     | like %n, unless from self
- * | \%g     | message labels (e.g. notmuch tags)
+ * | \%g     | message tags (e.g. notmuch tags)
+ * | \%Gx    | individual message tag (e.g. notmuch tags)
  * | \%i     | message-id
  * | \%I     | initials of author
  * | \%K     | the list to which the letter was sent (if any; otherwise: empty)
@@ -837,22 +839,20 @@ static const char *hdr_format_str(char *dest, size_t destlen, size_t col, int co
         optional = 0;
       break;
 
-#ifdef USE_NOTMUCH
     case 'g':
       if (!optional)
       {
         colorlen = add_index_color(dest, destlen, flags, MT_COLOR_INDEX_TAGS);
         mutt_format_s(dest + colorlen, destlen - colorlen, prefix,
-                      nm_header_get_tags_transformed(hdr));
+                      hdr_tags_get_transformed(hdr));
         add_index_color(dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
       }
-      else if (!nm_header_get_tags_transformed(hdr))
+      else if (!hdr_tags_get_transformed(hdr))
         optional = 0;
       break;
 
-    case 'G':
-    {
-      char *tag_transformed = NULL;
+    case 'G':;
+      const char *tag_transformed = NULL;
       char format[3];
       char *tag = NULL;
 
@@ -865,14 +865,12 @@ static const char *hdr_format_str(char *dest, size_t destlen, size_t col, int co
         tag = hash_find(TagFormats, format);
         if (tag)
         {
-          tag_transformed = nm_header_get_tag_transformed(tag, hdr);
-
+          tag_transformed = hdr_tags_get_transformed_for(tag, hdr);
           colorlen = add_index_color(dest, destlen, flags, MT_COLOR_INDEX_TAG);
           mutt_format_s(dest + colorlen, destlen - colorlen, prefix,
                         (tag_transformed) ? tag_transformed : "");
           add_index_color(dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
         }
-
         src++;
       }
       else
@@ -883,12 +881,10 @@ static const char *hdr_format_str(char *dest, size_t destlen, size_t col, int co
 
         tag = hash_find(TagFormats, format);
         if (tag)
-          if (nm_header_get_tag_transformed(tag, hdr) == NULL)
+          if (hdr_tags_get_transformed_for(tag, hdr) == NULL)
             optional = 0;
       }
       break;
-    }
-#endif
 
     case 'H':
       /* (Hormel) spam score */
index 12a11017670c8da215a18cab52532f238d5228c9..27add4da18e9d91c77c8e93509cf3591ead5980b 100644 (file)
--- a/header.h
+++ b/header.h
@@ -108,6 +108,7 @@ struct Header
   int refno; /**< message number on server */
 #endif
 
+  void *tags; /* for driver that support server tagging */
 #if defined(USE_POP) || defined(USE_IMAP) || defined(USE_NNTP) || defined(USE_NOTMUCH)
   void *data;                       /**< driver-specific data */
   void (*free_cb)(struct Header *); /**< driver-specific data free function */
diff --git a/init.c b/init.c
index a357184ea8b65a957dcc11d7c558d1c5e51aba64..28297d6433bd5388087959e7482c1ac1fb6b1708 100644 (file)
--- a/init.c
+++ b/init.c
@@ -4091,10 +4091,8 @@ void mutt_init(int skip_sys_rc, struct ListHead *commands)
   /* reverse alias keys need to be strdup'ed because of idna conversions */
   ReverseAliases =
       hash_create(1031, MUTT_HASH_STRCASECMP | MUTT_HASH_STRDUP_KEYS | MUTT_HASH_ALLOW_DUPS);
-#ifdef USE_NOTMUCH
   TagTransforms = hash_create(64, 1);
   TagFormats = hash_create(64, 0);
-#endif
 
   mutt_menu_init();
 
@@ -4490,7 +4488,6 @@ bail:
   return -1;
 }
 
-#ifdef USE_NOTMUCH
 static int parse_tag_transforms(struct Buffer *b, struct Buffer *s,
                                 unsigned long data, struct Buffer *err)
 {
@@ -4562,7 +4559,6 @@ static int parse_tag_formats(struct Buffer *b, struct Buffer *s,
   }
   return 0;
 }
-#endif
 
 #ifdef USE_IMAP
 /**
diff --git a/init.h b/init.h
index 64a6d482c2d74d8087fc596c46511add5891a4f8..5e2d71f65ff3b1e3d62dcc5edc543acc2cb58045 100644 (file)
--- a/init.h
+++ b/init.h
@@ -2110,12 +2110,6 @@ struct Option MuttVars[] = {
    ** This variable specifies the default Notmuch database in format
    ** notmuch://<absolute path>.
    */
-  { "nm_hidden_tags", DT_STRING, R_NONE, UL &NmHiddenTags, UL "unread,draft,flagged,passed,replied,attachment,signed,encrypted" },
-  /*
-   ** .pp
-   ** This variable specifies private notmuch tags which should not be printed
-   ** on screen.
-   */
   { "nm_exclude_tags", DT_STRING,  R_NONE, UL &NmExcludeTags, 0 },
   /*
    ** .pp
@@ -2187,6 +2181,12 @@ struct Option MuttVars[] = {
   ** directly from the pager, and screen resizes cause lines longer than
   ** the screen width to be badly formatted in the help menu.
   */
+  { "hidden_tags", DT_STRING, R_NONE, UL &HiddenTags, UL "unread,draft,flagged,passed,replied,attachment,signed,encrypted" },
+  /*
+   ** .pp
+   ** This variable specifies private notmuch tags which should not be printed
+   ** on screen.
+   */
   { "pager_context",    DT_NUMBER,  R_NONE, UL &PagerContext, 0 },
   /*
   ** .pp
@@ -4530,6 +4530,8 @@ static int parse_spam_list       (struct Buffer *buf, struct Buffer *s, unsigned
 static int parse_stailq          (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
 static int parse_subjectrx_list  (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
 static int parse_subscribe       (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
+static int parse_tag_formats     (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
+static int parse_tag_transforms  (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
 static int parse_unalias         (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
 static int parse_unalternates    (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
 static int parse_unattachments   (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
@@ -4544,10 +4546,6 @@ static int parse_unsubscribe     (struct Buffer *buf, struct Buffer *s, unsigned
 static int parse_subscribe_to    (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
 static int parse_unsubscribe_from(struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
 #endif
-#ifdef USE_NOTMUCH
-static int parse_tag_formats     (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
-static int parse_tag_transforms  (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
-#endif
 #ifdef USE_SIDEBAR
 static int parse_path_list       (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
 static int parse_path_unlist     (struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err);
@@ -4627,10 +4625,8 @@ const struct Command Commands[] = {
 #ifdef USE_IMAP
   { "subscribe-to",        parse_subscribe_to,     0 },
 #endif
-#ifdef USE_NOTMUCH
   { "tag-formats",         parse_tag_formats,      0 },
   { "tag-transforms",      parse_tag_transforms,   0 },
-#endif
   { "timeout-hook",        mutt_parse_hook,        MUTT_TIMEOUTHOOK | MUTT_GLOBALHOOK },
   { "toggle",              parse_set,              MUTT_SET_INV },
   { "unalias",             parse_unalias,          0 },
index 81547c5bae63ebcab3eb1f91db9657fa4fb328db..070369062f4fbdcb84ddb11296d0e11c9de550dc 100644 (file)
@@ -45,6 +45,7 @@
  * | mutt_strncmp()            | Compare two strings (to a maximum), safely
  * | mutt_str_adjust()         | Shrink-to-fit a string
  * | mutt_str_replace()        | Replace one string with another
+ * | mutt_str_append_item()    | Add a string to another
  * | mutt_substrcpy()          | Copy a sub-string into a buffer
  * | mutt_substrdup()          | Duplicate a sub-string
  * | rfc822_dequote_comment()  | Un-escape characters in an email address comment
@@ -248,6 +249,30 @@ void mutt_str_replace(char **p, const char *s)
   *p = safe_strdup(s);
 }
 
+/**
+ * mutt_str_append_item - Add string to another seprated by sep
+ * @param str String appened
+ * @param item String to append
+ * @param sep separator between string item
+ *
+ * This function appends a string to another separate them by sep
+ * if needed
+ *
+ * This function alters the pointer of the caller.
+ */
+void mutt_str_append_item(char **str, const char *item, int sep)
+{
+  char *p = NULL;
+  size_t sz = strlen(item);
+  size_t ssz = *str ? strlen(*str) : 0;
+
+  safe_realloc(str, ssz + ((ssz && sep) ? 1 : 0) + sz + 1);
+  p = *str + ssz;
+  if (sep && ssz)
+    *p++ = sep;
+  memcpy(p, item, sz + 1);
+}
+
 /**
  * mutt_str_adjust - Shrink-to-fit a string
  * @param p String to alter
index ffcf18af4e0f1b8ba011b276c71271f659ae5556..9fb4e7e72868dc371be04b09269805f1dd62c423 100644 (file)
@@ -64,6 +64,7 @@ int         mutt_atos(const char *str, short *dst);
 void        mutt_remove_trailing_ws(char *s);
 char *      mutt_skip_whitespace(char *p);
 void        mutt_str_adjust(char **p);
+void        mutt_str_append_item(char **p, const char *item, int sep);
 int         mutt_strcasecmp(const char *a, const char *b);
 const char *mutt_strchrnul(const char *s, char c);
 int         mutt_strcmp(const char *a, const char *b);
diff --git a/menu.c b/menu.c
index 0ab01d367ba8df72d87bfe78dbda9c9f80e7e72e..5f30cb1ede9db3d0e825519e23ad12bcfde97c55 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -71,7 +71,6 @@ static int get_color(int index, unsigned char *s)
     case MT_COLOR_INDEX_SUBJECT:
       color = ColorIndexSubjectList;
       break;
-#ifdef USE_NOTMUCH
     case MT_COLOR_INDEX_TAG:
       for (color = ColorIndexTagList; color; color = color->next)
       {
@@ -83,7 +82,6 @@ static int get_color(int index, unsigned char *s)
           return color->pair;
       }
       return 0;
-#endif
     default:
       return ColorDefs[type];
   }
diff --git a/mutt.h b/mutt.h
index 01845ec722c358ebc282030f202fc98e7734412d..c97a1cb049449623a232541206fbc15d53533f43 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -196,9 +196,7 @@ enum MuttMisc
   MUTT_PGP_KEY,
   MUTT_XLABEL,
   MUTT_SERVERSEARCH,
-#ifdef USE_NOTMUCH
-  MUTT_NOTMUCH_LABEL,
-#endif
+  MUTT_DRIVER_LABEL,
   MUTT_MIMEATTACH,
 #ifdef USE_NNTP
   MUTT_NEWSGROUPS,
index c0b5a8f8f47ea0387bdd8b9bf9c13bf7367381f6..c6820c75f407993c4d34e0327d1ec32bf7861f17 100644 (file)
@@ -166,9 +166,7 @@ enum ColorId
   MT_COLOR_INDEX,
   MT_COLOR_INDEX_AUTHOR,
   MT_COLOR_INDEX_FLAGS,
-#ifdef USE_NOTMUCH
   MT_COLOR_INDEX_TAG,
-#endif
   MT_COLOR_INDEX_SUBJECT,
   /* below here - only index coloring stuff that doesn't have a pattern */
   MT_COLOR_INDEX_COLLAPSED,
@@ -176,9 +174,7 @@ enum ColorId
   MT_COLOR_INDEX_LABEL,
   MT_COLOR_INDEX_NUMBER,
   MT_COLOR_INDEX_SIZE,
-#ifdef USE_NOTMUCH
   MT_COLOR_INDEX_TAGS,
-#endif
   MT_COLOR_COMPOSE_HEADER,
   MT_COLOR_COMPOSE_SECURITY_ENCRYPT,
   MT_COLOR_COMPOSE_SECURITY_SIGN,
@@ -280,10 +276,7 @@ extern struct ColorLine *ColorIndexList;
 extern struct ColorLine *ColorIndexAuthorList;
 extern struct ColorLine *ColorIndexFlagsList;
 extern struct ColorLine *ColorIndexSubjectList;
-
-#ifdef USE_NOTMUCH
 extern struct ColorLine *ColorIndexTagList;
-#endif
 
 void ci_start_color(void);
 
index 01814aa35023516e5b9d14e570f211dbcee81941..22929fcefcc246d2bf7204908fb0daa65d4cd6b2 100644 (file)
@@ -57,6 +57,7 @@
 #include "header.h"
 #include "mailbox.h"
 #include "mutt_curses.h"
+#include "mutt_tags.h"
 #include "mx.h"
 #include "protos.h"
 #include "thread.h"
@@ -98,22 +99,7 @@ struct UriTag
   struct UriTag *next;
 };
 
-/**
- * struct NmHdrTag - NotMuch Mail Header Tags
- *
- * Keep a linked list of header tags and their transformed values.
- * Textual tags can be transformed to symbols to save space.
- *
- * @sa NmHdrData#tag_list
- */
-struct NmHdrTag
-{
-  char *tag;
-  char *transformed;
-  struct NmHdrTag *next;
-};
-
-/**
+/*
  * struct NmHdrData - NotMuch data attached to an email
  *
  * This stores all the NotMuch data associated with an email.
@@ -123,9 +109,6 @@ struct NmHdrTag
 struct NmHdrData
 {
   char *folder; /**< Location of the email */
-  char *tags;
-  char *tags_transformed;
-  struct NmHdrTag *tag_list;
   char *oldpath;
   char *virtual_id; /**< Unique NotMuch Id */
   int magic;        /**< Type of mailbox the email is in */
@@ -302,36 +285,6 @@ err:
   return false;
 }
 
-/**
- * free_tag_list - Free a list of tags
- * @param tag_list List of tags
- *
- * Take a nm_hdrtag struct (a singly-linked list) and free the attached strings
- * and the list itself.
- */
-static void free_tag_list(struct NmHdrTag **tag_list)
-{
-  struct NmHdrTag *tmp = NULL;
-
-  while ((tmp = *tag_list) != NULL)
-  {
-    *tag_list = tmp->next;
-    FREE(&tmp->tag);
-    FREE(&tmp->transformed);
-    FREE(&tmp);
-  }
-
-  *tag_list = 0;
-}
-
-/**
- * free_hdrdata - Free header data attached to an email
- * @param data Header data
- *
- * Each email can have an attached nm_hdrdata struct, which contains things
- * like the tags (labels).  This function frees all the resources and the
- * nm_hdrdata struct itself.
- */
 static void free_hdrdata(struct NmHdrData *data)
 {
   if (!data)
@@ -339,9 +292,6 @@ static void free_hdrdata(struct NmHdrData *data)
 
   mutt_debug(2, "nm: freeing header %p\n", (void *) data);
   FREE(&data->folder);
-  FREE(&data->tags);
-  FREE(&data->tags_transformed);
-  free_tag_list(&data->tag_list);
   FREE(&data->oldpath);
   FREE(&data->virtual_id);
   FREE(&data);
@@ -885,25 +835,11 @@ err:
   return NULL;
 }
 
-static void append_str_item(char **str, const char *item, int sep)
-{
-  char *p = NULL;
-  size_t sz = strlen(item);
-  size_t ssz = *str ? strlen(*str) : 0;
-
-  safe_realloc(str, ssz + ((ssz && sep) ? 1 : 0) + sz + 1);
-  p = *str + ssz;
-  if (sep && ssz)
-    *p++ = sep;
-  memcpy(p, item, sz + 1);
-}
-
 static int update_header_tags(struct Header *h, notmuch_message_t *msg)
 {
   struct NmHdrData *data = h->data;
   notmuch_tags_t *tags = NULL;
-  char *tstr = NULL, *ttstr = NULL;
-  struct NmHdrTag *tag_list = NULL, *tmp = NULL;
+  char *new_tags = NULL;
 
   mutt_debug(2, "nm: tags update requested (%s)\n", data->virtual_id);
 
@@ -911,61 +847,24 @@ static int update_header_tags(struct Header *h, notmuch_message_t *msg)
        notmuch_tags_move_to_next(tags))
   {
     const char *t = notmuch_tags_get(tags);
-    const char *tt = NULL;
 
     if (!t || !*t)
       continue;
 
-    tt = hash_find(TagTransforms, t);
-    if (!tt)
-      tt = t;
-
-    /* tags list contains all tags */
-    tmp = safe_calloc(1, sizeof(*tmp));
-    tmp->tag = safe_strdup(t);
-    tmp->transformed = safe_strdup(tt);
-    tmp->next = tag_list;
-    tag_list = tmp;
-
-    /* filter out hidden tags */
-    if (NmHiddenTags)
-    {
-      char *p = strstr(NmHiddenTags, t);
-      size_t xsz = p ? strlen(t) : 0;
-
-      if (p && ((p == NmHiddenTags) || (*(p - 1) == ',') || (*(p - 1) == ' ')) &&
-          ((*(p + xsz) == '\0') || (*(p + xsz) == ',') || (*(p + xsz) == ' ')))
-        continue;
-    }
-
-    /* expand the transformed tag string */
-    append_str_item(&ttstr, tt, ' ');
-
-    /* expand the un-transformed tag string */
-    append_str_item(&tstr, t, ' ');
+    mutt_str_append_item(&new_tags, t, ' ');
   }
 
-  free_tag_list(&data->tag_list);
-  data->tag_list = tag_list;
-
-  if (data->tags && tstr && (strcmp(data->tags, tstr) == 0))
+  if (hdr_tags_get(h) && new_tags && (strcmp(hdr_tags_get(h), new_tags) == 0))
   {
-    FREE(&tstr);
-    FREE(&ttstr);
+    FREE(&new_tags);
     mutt_debug(2, "nm: tags unchanged\n");
     return 1;
   }
 
-  /* free old version */
-  FREE(&data->tags);
-  FREE(&data->tags_transformed);
-
   /* new version */
-  data->tags = tstr;
-  mutt_debug(2, "nm: new tags: '%s'\n", tstr);
-
-  data->tags_transformed = ttstr;
-  mutt_debug(2, "nm: new tag transforms: '%s'\n", ttstr);
+  hdr_tags_replace(h, new_tags);
+  mutt_debug(2, "nm: new tags: '%s'\n", hdr_tags_get(h));
+  mutt_debug(2, "nm: new tag transforms: '%s'\n", hdr_tags_get_transformed(h));
 
   return 0;
 }
@@ -1061,6 +960,7 @@ static int init_header(struct Header *h, const char *path, notmuch_message_t *ms
 
   h->data = safe_calloc(1, sizeof(struct NmHdrData));
   h->free_cb = deinit_header;
+  hdr_tags_init(h);
 
   /*
    * Notmuch ensures that message Id exists (if not notmuch Notmuch will
@@ -1695,7 +1595,7 @@ static int rename_filename(struct NmCtxData *data, const char *old,
   {
     notmuch_message_maildir_flags_to_tags(msg);
     update_header_tags(h, msg);
-    update_tags(msg, nm_header_get_tags(h));
+    update_tags(msg, hdr_tags_get(h));
   }
 
   rc = 0;
@@ -1735,32 +1635,6 @@ char *nm_header_get_folder(struct Header *h)
   return (h && h->data) ? ((struct NmHdrData *) h->data)->folder : NULL;
 }
 
-char *nm_header_get_tags(struct Header *h)
-{
-  return (h && h->data) ? ((struct NmHdrData *) h->data)->tags : NULL;
-}
-
-char *nm_header_get_tags_transformed(struct Header *h)
-{
-  return (h && h->data) ? ((struct NmHdrData *) h->data)->tags_transformed : NULL;
-}
-
-char *nm_header_get_tag_transformed(char *tag, struct Header *h)
-{
-  struct NmHdrTag *tmp = NULL;
-
-  if (!h || !h->data)
-    return NULL;
-
-  for (tmp = ((struct NmHdrData *) h->data)->tag_list; tmp != NULL; tmp = tmp->next)
-  {
-    if (strcmp(tag, tmp->tag) == 0)
-      return tmp->transformed;
-  }
-
-  return NULL;
-}
-
 void nm_longrun_init(struct Context *ctx, bool writable)
 {
   struct NmCtxData *data = get_ctxdata(ctx);
@@ -1814,8 +1688,8 @@ int nm_read_entire_thread(struct Context *ctx, struct Header *h)
   id = notmuch_message_get_thread_id(msg);
   if (!id)
     goto done;
-  append_str_item(&qstr, "thread:", 0);
-  append_str_item(&qstr, id, 0);
+  mutt_str_append_item(&qstr, "thread:", 0);
+  mutt_str_append_item(&qstr, id, 0);
 
   q = notmuch_query_create(db, qstr);
   FREE(&qstr);
@@ -2235,7 +2109,7 @@ int nm_record_message(struct Context *ctx, char *path, struct Header *h)
   {
     notmuch_message_maildir_flags_to_tags(msg);
     if (h)
-      update_tags(msg, nm_header_get_tags(h));
+      update_tags(msg, hdr_tags_get(h));
     if (NmRecordTags)
       update_tags(msg, NmRecordTags);
   }
diff --git a/mutt_tags.c b/mutt_tags.c
new file mode 100644 (file)
index 0000000..02fe154
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2017 Mehdi Abaakouk <sileht@sileht.net>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "mutt_tags.h"
+#include "globals.h"
+#include "lib/hash.h"
+#include "lib/string2.h"
+#include "header.h"
+
+#define HEADER_TAGS(ph) ((struct HeaderTags *) ((ph)->tags))
+
+/**
+ * hdr_tags_free_tag_list - free tag
+ * @param[in] h: pointer to a header struct
+ *
+ * Free tag
+ */
+void hdr_tags_free_tag_list(struct HeaderTag **kw_list)
+{
+  struct HeaderTag *tmp = NULL;
+
+  while ((tmp = *kw_list) != NULL)
+  {
+    *kw_list = tmp->next;
+    FREE(&tmp->name);
+    FREE(&tmp->transformed);
+    FREE(&tmp);
+  }
+
+  *kw_list = 0;
+}
+
+/**
+ * hdr_tags_free - Free tags from a header
+ * @param[in] h: pointer to a header struct
+ *
+ * Free the whole tags structure
+ */
+void hdr_tags_free(struct Header *h)
+{
+  if (!HEADER_TAGS(h))
+    return;
+  FREE(&HEADER_TAGS(h)->tags);
+  FREE(&HEADER_TAGS(h)->tags_transformed);
+  FREE(&HEADER_TAGS(h)->tags_with_hidden);
+  hdr_tags_free_tag_list(&HEADER_TAGS(h)->tag_list);
+}
+
+/**
+ * hdr_tags_get_transformed - Get transformed tags from a header
+ * @param[in] h: pointer to a header struct
+ *
+ * @return string transformed tags
+ *
+ * Return a string containing all transformed tags separated by space
+ * without hidden tags
+ */
+const char *hdr_tags_get_transformed(struct Header *h)
+{
+  if (!h || !HEADER_TAGS(h) || !HEADER_TAGS(h)->tags_transformed)
+    return NULL;
+  return HEADER_TAGS(h)->tags_transformed;
+}
+
+/*
+ * hdr_tags_get - Get tags from a header
+ * @param[in] h: pointer to a header struct
+ *
+ * @return string tags
+ *
+ * Return a string containing all tags separated by space with
+ * hidden tags
+ */
+const char *hdr_tags_get(struct Header *h)
+{
+  if (!h || !HEADER_TAGS(h) || !HEADER_TAGS(h)->tags)
+    return NULL;
+  return HEADER_TAGS(h)->tags;
+}
+
+/*
+ * hdr_tags_get - Get tags with hiddens from a header
+ * @param[in] h: pointer to a header struct
+ *
+ * @return string tags
+ *
+ * Return a string containing all tags separated by space
+ * even the hiddens.
+ */
+const char *hdr_tags_get_with_hidden(struct Header *h)
+{
+  if (!h || !HEADER_TAGS(h) || !HEADER_TAGS(h)->tags_with_hidden)
+    return NULL;
+  return HEADER_TAGS(h)->tags_with_hidden;
+}
+
+/**
+ * hdr_tags_get_transformed_for - Get tranformed tag for a tag name from a header
+ * @param[in] tag: char* to the tag to get the transformed version
+ * @param[in] h: pointer to a header struct
+ *
+ * @return string tag
+ *
+ * Return a string containing transformed tag that match the tag
+ * even if this is a hidden tags
+ */
+const char *hdr_tags_get_transformed_for(char *name, struct Header *h)
+{
+  if (!h || !HEADER_TAGS(h) || !HEADER_TAGS(h)->tag_list)
+    return NULL;
+
+  struct HeaderTag *tag = HEADER_TAGS(h)->tag_list;
+  while (tag)
+  {
+    if (strcmp(tag->name, name) == 0)
+      return tag->transformed;
+    tag = tag->next;
+  }
+  return NULL;
+}
+
+void hdr_tags_init(struct Header *h)
+{
+  h->tags = safe_calloc(1, sizeof(struct HeaderTags));
+  HEADER_TAGS(h)->tags = NULL;
+  HEADER_TAGS(h)->tags_transformed = NULL;
+  HEADER_TAGS(h)->tags_with_hidden = NULL;
+  HEADER_TAGS(h)->tag_list = NULL;
+}
+/**
+ * hdr_tags_replace - Add a tag to header
+ * @param[in] h: pointer to a header struct
+ * @param[in] new_tag: string representing the new tag
+ *
+ * Add a tag to the header tags
+ */
+void hdr_tags_add(struct Header *h, char *new_tag)
+{
+  struct HeaderTag *ttmp = NULL;
+  char *new_tag_transformed = NULL;
+
+  new_tag_transformed = hash_find(TagTransforms, new_tag);
+  if (!new_tag_transformed)
+    new_tag_transformed = new_tag;
+
+  ttmp = safe_calloc(1, sizeof(*ttmp));
+  ttmp->name = safe_strdup(new_tag);
+  ttmp->transformed = safe_strdup(new_tag_transformed);
+  ttmp->next = HEADER_TAGS(h)->tag_list;
+  HEADER_TAGS(h)->tag_list = ttmp;
+
+  /* expand the all un-transformed tag string */
+  mutt_str_append_item(&HEADER_TAGS(h)->tags_with_hidden, new_tag, ' ');
+
+  /* filter out hidden tags */
+  if (HiddenTags)
+  {
+    char *p = strstr(HiddenTags, new_tag);
+    size_t xsz = p ? strlen(new_tag) : 0;
+
+    if (p && ((p == HiddenTags) || (*(p - 1) == ',') || (*(p - 1) == ' ')) &&
+        ((*(p + xsz) == '\0') || (*(p + xsz) == ',') || (*(p + xsz) == ' ')))
+      return;
+  }
+
+  /* expand the visible un-transformed tag string */
+  mutt_str_append_item(&HEADER_TAGS(h)->tags, new_tag, ' ');
+
+  /* expand the transformed tag string */
+  mutt_str_append_item(&HEADER_TAGS(h)->tags_transformed, new_tag_transformed, ' ');
+}
+
+/**
+ * hdr_tags_replace - Replace all tags
+ * @param[in] h: pointer to a header struct
+ * @param[in] tags: string of all tags separated by space
+ *
+ * @retval  0 If no change are made
+ * @retval  1 If tags are updated
+ *
+ *
+ * Free current tags structures and replace it by
+ * new tags
+ */
+int hdr_tags_replace(struct Header *h, char *tags)
+{
+  if (!h)
+    return 0;
+  if (tags && HEADER_TAGS(h) && HEADER_TAGS(h)->tags &&
+      mutt_strcmp(HEADER_TAGS(h)->tags, tags) == 0)
+    return 0;
+
+  hdr_tags_free(h);
+
+  if (tags)
+  {
+    char *tag;
+    while ((tag = strsep(&tags, " ")))
+      hdr_tags_add(h, tag);
+    FREE(&tags);
+  }
+  return 1;
+}
diff --git a/mutt_tags.h b/mutt_tags.h
new file mode 100644 (file)
index 0000000..af58696
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 Mehdi Abaakouk <sileht@sileht.net>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef _MUTT_TAG_H
+#define _MUTT_TAG_H
+
+#include "header.h"
+#include "context.h"
+
+/**
+ * hdr_tag -  Mail Header Tags
+ *
+ * Keep a linked list of header tags and their transformed values.
+ * Textual tags can be transformed to symbols to save space.
+ *
+ * @sa hdr_tags#tag_list
+ */
+struct HeaderTag
+{
+  char *name;
+  char *transformed;
+  struct HeaderTag *next;
+};
+
+/**
+ * struct HeaderTags - tags data attached to an email
+ *
+ * This stores all tags data associated with an email.
+ *
+ */
+struct HeaderTags
+{
+  /* Without hidden tags */
+  char *tags;
+  char *tags_transformed;
+
+  /* With hidden tags */
+  char *tags_with_hidden;
+  struct HeaderTag *tag_list;
+};
+
+void hdr_tags_free_tag_list(struct HeaderTag **kw_list);
+void hdr_tags_free(struct Header *h);
+const char *hdr_tags_get(struct Header *h);
+const char *hdr_tags_get_with_hidden(struct Header *h);
+const char *hdr_tags_get_transformed(struct Header *h);
+const char *hdr_tags_get_transformed_for(char *name, struct Header *h);
+void hdr_tags_init(struct Header *h);
+void hdr_tags_add(struct Header *h, char *new_tag);
+int hdr_tags_replace(struct Header *h, char *tags);
+
+#endif /* _MUTT_TAG_H */
index c62e143d6da6466521ef6ef06a53c3f848c22987..75597dcc62330a699494dcd1ece8dff5017ecbd2 100644 (file)
--- a/muttlib.c
+++ b/muttlib.c
 #include "mime.h"
 #include "mutt_curses.h"
 #include "mutt_regex.h"
+#if defined USE_IMAP || defined USE_NOTMUCH
+#include "mutt_tags.h"
+#endif
+
 #include "mx.h"
 #include "ncrypt/ncrypt.h"
 #include "options.h"
@@ -165,6 +169,8 @@ void mutt_free_header(struct Header **h)
 #ifdef MIXMASTER
   mutt_list_free(&(*h)->chain);
 #endif
+  hdr_tags_free(*h);
+  FREE(&(*h)->tags);
 #if defined(USE_POP) || defined(USE_IMAP) || defined(USE_NNTP) || defined(USE_NOTMUCH)
   if ((*h)->free_cb)
     (*h)->free_cb(*h);
index f083f3b788805615e2e7625e99ad9b258221fbaf..b266a9345306870e6c4a66f9d90465935c058650 100644 (file)
--- a/opcodes.h
+++ b/opcodes.h
   _fmt(OP_MAIN_SHOW_LIMIT,                N_("show currently active limit pattern")) \
   _fmt(OP_MAIN_COLLAPSE_THREAD,           N_("collapse/uncollapse current thread")) \
   _fmt(OP_MAIN_COLLAPSE_ALL,              N_("collapse/uncollapse all threads")) \
+  _fmt(OP_MAIN_MODIFY_LABELS,             N_("modify (notmuch) tags")) \
+  _fmt(OP_MAIN_MODIFY_LABELS_THEN_HIDE,   N_("modify labels and then hide message")) \
 
 #define OPS_CRYPT(_fmt) \
   _fmt(OP_DECRYPT_SAVE,                   N_("make decrypted copy and delete")) \
   _fmt(OP_MAIN_VFOLDER_FROM_QUERY,        N_("generate virtual folder from query")) \
   _fmt(OP_MAIN_WINDOWED_VFOLDER_FORWARD,  N_("shifts virtual folder time window forwards")) \
   _fmt(OP_MAIN_WINDOWED_VFOLDER_BACKWARD, N_("shifts virtual folder time window backwards")) \
-  _fmt(OP_MAIN_MODIFY_LABELS,             N_("modify (notmuch) tags")) \
-  _fmt(OP_MAIN_MODIFY_LABELS_THEN_HIDE,   N_("modify labels and then hide message")) \
   _fmt(OP_MAIN_ENTIRE_THREAD,             N_("read entire thread of the current message"))
 #else
 #define OPS_NOTMUCH(_)
index 3aaf1a03c796e75c23487c8b99316c14ecd54e5c..d22d5edc9a76902fa1c7e0df490299149e5b4a91 100644 (file)
--- a/pattern.c
+++ b/pattern.c
@@ -62,8 +62,9 @@
 #include "thread.h"
 #ifdef USE_IMAP
 #include "imap/imap.h"
-#include "mx.h"
 #endif
+#include "mutt_tags.h"
+#include "mx.h"
 #ifdef USE_NOTMUCH
 #include "mutt_notmuch.h"
 #endif
@@ -871,9 +872,7 @@ static const struct PatternFlags
   { 'x', MUTT_REFERENCE, 0, eat_regex },
   { 'X', MUTT_MIMEATTACH, 0, eat_range },
   { 'y', MUTT_XLABEL, 0, eat_regex },
-#ifdef USE_NOTMUCH
-  { 'Y', MUTT_NOTMUCH_LABEL, 0, eat_regex },
-#endif
+  { 'Y', MUTT_DRIVER_LABEL, 0, eat_regex },
   { 'z', MUTT_SIZE, 0, eat_range },
   { '=', MUTT_DUPLICATED, 0, NULL },
   { '$', MUTT_UNREFERENCED, 0, NULL },
@@ -1713,18 +1712,11 @@ int mutt_pattern_exec(struct Pattern *pat, enum PatternExecFlag flags,
       return (pat->not ^ ((h->security & APPLICATION_PGP) && (h->security & PGPKEY)));
     case MUTT_XLABEL:
       return (pat->not ^ (h->env->x_label && patmatch(pat, h->env->x_label) == 0));
-#ifdef USE_NOTMUCH
-    case MUTT_NOTMUCH_LABEL:
-      if (ctx && (ctx->magic == MUTT_NOTMUCH))
-      {
-        char *tags = nm_header_get_tags(h);
-        return (pat->not ^ (tags && patmatch(pat, tags) == 0));
-      }
-      else
-      {
-        return 0;
-      }
-#endif
+    case MUTT_DRIVER_LABEL:
+    {
+      const char *tags = hdr_tags_get(h);
+      return (pat->not ^ (tags && patmatch(pat, tags) == 0));
+    }
     case MUTT_HORMEL:
       return (pat->not ^ (h->env->spam && h->env->spam->data &&
                           patmatch(pat, h->env->spam->data) == 0));