fputs(buf, out);
fputc('\n', out);
}
- const char *tags = driver_tags_get(h->tags);
+ char *tags = driver_tags_get(&h->tags);
if (tags && !(option(OPT_WEED) && mutt_matches_ignore("tags")))
{
fputs("Tags: ", out);
fputs(tags, out);
fputc('\n', out);
}
+ FREE(&tags);
}
#endif
CHECK_MSGCOUNT;
CHECK_VISIBLE;
CHECK_READONLY;
-
- rc = mx_tags_editor(Context, tag ? NULL : driver_tags_get_with_hidden(CURHDR->tags), buf, sizeof(buf));
+ char *tags = NULL;
+ if (!tag)
+ tags = driver_tags_get_with_hidden(&CURHDR->tags);
+ rc = mx_tags_editor(Context, tags, buf, sizeof(buf));
+ FREE(&tags);
if (rc < 0)
break;
else if (rc == 0)
#include "list.h"
#include "mbyte.h"
#include "mutt_regex.h"
+#include "mutt_tags.h"
#include "parameter.h"
#include "protos.h"
#include "rfc822.h"
nh.path = NULL;
nh.tree = NULL;
nh.thread = NULL;
- nh.tags = NULL;
+ STAILQ_INIT(&nh.tags);
#ifdef MIXMASTER
STAILQ_INIT(&nh.chain);
#endif
struct HdrFormatInfo *hfi = (struct HdrFormatInfo *) data;
struct Header *hdr = NULL, *htmp = NULL;
struct Context *ctx = NULL;
- char fmt[SHORT_STRING], buf2[LONG_STRING], *p = NULL;
+ char fmt[SHORT_STRING], buf2[LONG_STRING], *p, *tags = NULL;
char *wch = NULL;
int do_locales, i;
int optional = (flags & MUTT_FORMAT_OPTIONAL);
optional = 0;
break;
- case 'g':
+ case 'g':;
+ tags = driver_tags_get_transformed(&hdr->tags);
if (!optional)
{
colorlen = add_index_color(dest, destlen, flags, MT_COLOR_INDEX_TAGS);
- mutt_format_s(dest + colorlen, destlen - colorlen, prefix,
- driver_tags_get_transformed(hdr->tags));
+ mutt_format_s(dest + colorlen, destlen - colorlen, prefix, NONULL(tags));
add_index_color(dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
}
- else if (!driver_tags_get_transformed(hdr->tags))
+ else if (!tags)
optional = 0;
+ FREE(&tags);
break;
case 'G':;
- const char *tag_transformed = NULL;
char format[3];
char *tag = NULL;
tag = hash_find(TagFormats, format);
if (tag)
{
- tag_transformed = driver_tags_get_transformed_for(tag, hdr->tags);
+ tags = driver_tags_get_transformed_for(tag, &hdr->tags);
colorlen = add_index_color(dest, destlen, flags, MT_COLOR_INDEX_TAG);
- mutt_format_s(dest + colorlen, destlen - colorlen, prefix,
- (tag_transformed) ? tag_transformed : "");
+ mutt_format_s(dest + colorlen, destlen - colorlen, prefix, NONULL(tags));
add_index_color(dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+ FREE(&tags);
}
src++;
}
format[2] = 0;
tag = hash_find(TagFormats, format);
- if (tag)
- if (driver_tags_get_transformed_for(tag, hdr->tags) == NULL)
+ if (tag) {
+ tags = driver_tags_get_transformed_for(tag, &hdr->tags);
+ if (!tags)
optional = 0;
+ FREE(&tags);
+ }
}
break;
break;
case 'J':;
- const char *tags = driver_tags_get_transformed(hdr->tags);
+ tags = driver_tags_get_transformed(&hdr->tags);
if (tags)
{
i = 1; /* reduce reuse recycle */
- htmp = NULL;
-
- if (flags & MUTT_FORMAT_TREE &&
- (hdr->thread->prev && hdr->thread->prev->message &&
- driver_tags_get_transformed(hdr->thread->prev->message->tags)))
- htmp = hdr->thread->prev->message;
- else if (flags & MUTT_FORMAT_TREE &&
- (hdr->thread->parent && hdr->thread->parent->message &&
- driver_tags_get_transformed(hdr->thread->parent->message->tags)))
- htmp = hdr->thread->parent->message;
- if (htmp && mutt_strcasecmp(tags, driver_tags_get_transformed(htmp->tags)) == 0)
- i = 0;
+ if (flags & MUTT_FORMAT_TREE){
+ char *parent_tags = NULL;
+ if (hdr->thread->prev && hdr->thread->prev->message)
+ parent_tags = driver_tags_get_transformed(&hdr->thread->prev->message->tags);
+ if (!parent_tags && hdr->thread->parent && hdr->thread->parent->message)
+ parent_tags = driver_tags_get_transformed(&hdr->thread->parent->message->tags);
+ if (parent_tags && mutt_strcasecmp(tags, parent_tags) == 0)
+ i = 0;
+ FREE(&parent_tags);
+ }
}
else
i = 0;
else
mutt_format_s(dest + colorlen, destlen - colorlen, prefix, "");
add_index_color(dest + colorlen, destlen - colorlen, flags, MT_COLOR_INDEX);
+ FREE(&tags);
break;
case 'l':
int refno; /**< message number on server */
#endif
- struct TagHead *tags; /**< for drivers that support server tagging */
+ struct TagHead tags; /**< for drivers 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 */
#ifdef MIXMASTER
STAILQ_INIT(&h->chain);
#endif
+ STAILQ_INIT(&h->tags);
return h;
}
struct Buffer *cmd, int *err_continue)
{
char flags[LONG_STRING];
+ char *tags;
char uid[11];
if (!compare_flags_for_copy(hdr))
if (HEADER_DATA(hdr)->flags_system)
safe_strcat(flags, sizeof(flags), HEADER_DATA(hdr)->flags_system);
/* set custom flags */
- if (driver_tags_get_with_hidden(hdr->tags))
- safe_strcat(flags, sizeof(flags), driver_tags_get_with_hidden(hdr->tags));
+ tags = driver_tags_get_with_hidden(&hdr->tags);
+ if (tags) {
+ safe_strcat(flags, sizeof(flags), tags);
+ FREE(&tags);
+ }
}
mutt_remove_trailing_ws(flags);
/* server have now the updated flags */
FREE(&HEADER_DATA(hdr)->flags_remote);
- HEADER_DATA(hdr)->flags_remote = safe_strdup(driver_tags_get_with_hidden(hdr->tags));
+ HEADER_DATA(hdr)->flags_remote = driver_tags_get_with_hidden(&hdr->tags);
hdr->active = true;
if (hdr->deleted == HEADER_DATA(hdr)->deleted)
/* We are good sync them */
mutt_debug(1, "NEW TAGS: %d\n", tags);
- driver_tags_replace(h->tags, tags);
+ driver_tags_replace(&h->tags, tags);
FREE(&HEADER_DATA(h)->flags_remote);
- HEADER_DATA(h)->flags_remote = safe_strdup(driver_tags_get_with_hidden(h->tags));
+ HEADER_DATA(h)->flags_remote = driver_tags_get_with_hidden(&h->tags);
return 0;
}
ctx->hdrs[idx]->changed = h.data->changed;
/* ctx->hdrs[msgno]->received is restored from mutt_hcache_restore */
ctx->hdrs[idx]->data = (void *) (h.data);
- driver_tags_init(ctx->hdrs[idx]->tags);
- driver_tags_replace(ctx->hdrs[idx]->tags, safe_strdup(h.data->flags_remote));
+ STAILQ_INIT(&ctx->hdrs[idx]->tags);
+ driver_tags_replace(&ctx->hdrs[idx]->tags, safe_strdup(h.data->flags_remote));
ctx->msgcount++;
ctx->size += ctx->hdrs[idx]->content->length;
ctx->hdrs[idx]->changed = h.data->changed;
ctx->hdrs[idx]->received = h.received;
ctx->hdrs[idx]->data = (void *) (h.data);
- driver_tags_init(ctx->hdrs[idx]->tags);
- driver_tags_replace(ctx->hdrs[idx]->tags, safe_strdup(h.data->flags_remote));
+ STAILQ_INIT(&ctx->hdrs[idx]->tags);
+ driver_tags_replace(&ctx->hdrs[idx]->tags, safe_strdup(h.data->flags_remote));
if (maxuid < h.data->uid)
maxuid = h.data->uid;
return NULL;
/* Update tags system */
- driver_tags_replace(h->tags, safe_strdup(hd->flags_remote));
+ driver_tags_replace(&h->tags, safe_strdup(hd->flags_remote));
/* YAUH (yet another ugly hack): temporarily set context to
* read-write even if it's read-only, so *server* updates of
struct RegexList;
struct State;
struct ListHead;
+struct TagHead;
struct Mapping;
/* On OS X 10.5.x, wide char functions are inlined by default breaking
#endif
notmuch_tags_t *tags = NULL;
char *new_tags = NULL;
+ char *old_tags = NULL;
mutt_debug(2, "nm: tags update requested (%s)\n", data->virtual_id);
mutt_str_append_item(&new_tags, t, ' ');
}
- if (driver_tags_get(h->tags) && new_tags && (strcmp(driver_tags_get(h->tags), new_tags) == 0))
+
+ old_tags = driver_tags_get(&h->tags);
+
+ if (new_tags && old_tags && (strcmp(old_tags, new_tags) == 0))
{
+ FREE(&old_tags);
FREE(&new_tags);
mutt_debug(2, "nm: tags unchanged\n");
return 1;
}
/* new version */
- driver_tags_replace(h->tags, new_tags);
- mutt_debug(2, "nm: new tags: '%s'\n", driver_tags_get(h->tags));
- mutt_debug(2, "nm: new tag transforms: '%s'\n", driver_tags_get_transformed(h->tags));
+ driver_tags_replace(&h->tags, new_tags);
+ FREE(&new_tags);
+
+ new_tags = driver_tags_get_transformed(&h->tags);
+ mutt_debug(2, "nm: new tags: '%s'\n", new_tags);
+ FREE(&new_tags);
+
+ new_tags = driver_tags_get(&h->tags);
+ mutt_debug(2, "nm: new tag transforms: '%s'\n", new_tags);
+ FREE(&new_tags);
return 0;
}
h->data = safe_calloc(1, sizeof(struct NmHdrData));
h->free_cb = deinit_header;
- driver_tags_init(h->tags);
/*
* Notmuch ensures that message Id exists (if not notmuch Notmuch will
{
notmuch_message_maildir_flags_to_tags(msg);
update_header_tags(h, msg);
- update_tags(msg, driver_tags_get(h->tags));
+
+ char *tags = driver_tags_get(&h->tags);
+ update_tags(msg, tags);
+ FREE(&tags);
}
rc = 0;
if (st == NOTMUCH_STATUS_SUCCESS && msg)
{
notmuch_message_maildir_flags_to_tags(msg);
- if (h)
- update_tags(msg, driver_tags_get(h->tags));
+ if (h) {
+ char *tags = driver_tags_get(&h->tags);
+ update_tags(msg, tags);
+ FREE(&tags);
+ }
if (NmRecordTags)
update_tags(msg, NmRecordTags);
}
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <stddef.h>
+
#include "config.h"
#include "mutt_tags.h"
#include "globals.h"
#include "lib/hash.h"
#include "lib/string2.h"
-#include "mx.h"
+#include "queue.h"
+
/**
- * driver_tags_free_tag_list - free tag
- * @param[in] h: pointer to a Header struct
+ * driver_tags_free - Free tags from a header
+ * @param[in] head: pointer to the tags head
*
- * Free tag
+ * Free the whole tags structure
*/
-static void driver_tags_free_tag_list(struct TagNode **kw_list)
+void driver_tags_free(struct TagHead *head)
{
- struct TagNode *tmp = NULL;
+ if (!head)
+ return;
- while ((tmp = *kw_list) != NULL)
+ struct TagNode *np = STAILQ_FIRST(head), *next = NULL;
+ while (np)
{
- *kw_list = tmp->next;
- FREE(&tmp->name);
- FREE(&tmp->transformed);
- FREE(&tmp);
+ next = STAILQ_NEXT(np, entries);
+ FREE(&np->name);
+ FREE(&np->transformed);
+ FREE(&np);
+ np = next;
}
-
- *kw_list = 0;
+ STAILQ_INIT(head);
}
/**
- * driver_tags_free - Free tags from a header
- * @param[in] h: pointer to a header struct
+ * driver_tags_get_transformed - Get transformed tags
+ * @param[in] head: pointer to the tags head
*
- * Free the whole tags structure
+ * Return a new allocated string containing tags separated by space
*/
-void driver_tags_free(struct TagHead *head)
+static char *driver_tags_getter(struct TagHead *head, bool show_hidden, bool show_tranformed, char *filter)
{
if (!head)
- return;
- FREE(&head->tags);
- FREE(&head->tags_transformed);
- FREE(&head->tags_with_hidden);
- driver_tags_free_tag_list(&head->tag_list);
- FREE(head);
+ return NULL;
+
+ char *tags = NULL;
+ struct TagNode *np;
+ STAILQ_FOREACH(np, head, entries)
+ {
+ if(filter && mutt_strcmp(np->name, filter) != 0)
+ continue;
+ if (show_hidden || !np->hidden)
+ {
+ if (show_tranformed && np->transformed)
+ mutt_str_append_item(&tags, np->transformed, ' ');
+ else
+ mutt_str_append_item(&tags, np->name, ' ');
+ }
+ }
+ return tags;
}
+
/**
- * driver_tags_get_transformed - Get transformed tags from a header
- * @param[in] h: pointer to a header struct
- *
- * @return string transformed tags
+ * driver_tags_get_transformed - Get transformed tags
+ * @param[in] head: pointer to the tags head
*
- * Return a string containing all transformed tags separated by space
- * without hidden tags
+ * Return a new allocated string containing all tags separated by space with
+ * transformation
*/
-const char *driver_tags_get_transformed(struct TagHead *head)
+char *driver_tags_get_transformed(struct TagHead *head)
{
- if (!head)
- return NULL;
- if(!head->tags_transformed)
- return head->tags;
- return head->tags_transformed;
+ return driver_tags_getter(head, false, true, NULL);
}
/**
- * driver_tags_get - Get tags from a header
- * @param[in] h: pointer to a header struct
- *
- * @return string tags
+ * driver_tags_get - Get tags
+ * @param[in] head: pointer to the tags head
*
- * Return a string containing all tags separated by space with
- * hidden tags
+ * Return a new allocated string containing all tags separated by space
*/
-const char *driver_tags_get(struct TagHead *head)
+char *driver_tags_get(struct TagHead *head)
{
- if (!head || !head->tags)
- return NULL;
- return head->tags;
+ return driver_tags_getter(head, false, false, NULL);
}
/**
- * driver_tags_get_with_hidden - Get tags with hiddens from a header
- * @param[in] h: pointer to a header struct
- *
- * @return string tags
+ * driver_tags_get_with_hidden - Get tags with hiddens
+ * @param[in] head: pointer to the tags head
*
- * Return a string containing all tags separated by space
- * even the hiddens.
+ * Return a new allocated string containing all tags separated by space even
+ * the hiddens.
*/
-const char *driver_tags_get_with_hidden(struct TagHead *head)
+char *driver_tags_get_with_hidden(struct TagHead *head)
{
- if (!head || !head->tags_with_hidden)
- return NULL;
- return head->tags_with_hidden;
+ return driver_tags_getter(head, true, false, NULL);
}
/**
* driver_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
+ * @param[in] head: pointer to the tags head
*
* @return string tag
*
- * Return a string containing transformed tag that match the tag
- * even if this is a hidden tags
+ * Return a new allocated string containing all tags separated by space even
+ * the hiddens.
*/
-const char *driver_tags_get_transformed_for(char *name, struct TagHead *head)
-{
- if (!head || !head->tag_list)
- return NULL;
-
- struct TagNode *tag = head->tag_list;
- while (tag)
- {
- if (strcmp(tag->name, name) == 0) {
- if (!tag->transformed)
- return tag->name;
- else
- return tag->transformed;
- }
- tag = tag->next;
- }
- return NULL;
-}
-
-void driver_tags_init(struct TagHead *head)
+char *driver_tags_get_transformed_for(char *name, struct TagHead *head)
{
- head = safe_calloc(1, sizeof(struct TagHead));
- head->tags = NULL;
- head->tags_transformed = NULL;
- head->tags_with_hidden = NULL;
- head->tag_list = NULL;
+ return driver_tags_getter(head, true, true, name);
}
/**
* driver_tags_add - Add a tag to header
- * @param[in] h: pointer to a header struct
+ * @param[in] head: pointer to the tags head
* @param[in] new_tag: string representing the new tag
*
* Add a tag to the header tags
*/
static void driver_tags_add(struct TagHead *head, char *new_tag)
{
- struct TagNode *ttmp = NULL;
- char *new_tag_transformed = NULL;
+ char *new_tag_transformed = hash_find(TagTransforms, new_tag);
- new_tag_transformed = hash_find(TagTransforms, new_tag);
-
- ttmp = safe_calloc(1, sizeof(*ttmp));
- ttmp->name = safe_strdup(new_tag);
+ struct TagNode *np = safe_calloc(1, sizeof(struct TagNode));
+ np->name = safe_strdup(new_tag);;
+ np->hidden = false;
if (new_tag_transformed)
- ttmp->transformed = safe_strdup(new_tag_transformed);
- ttmp->next = head->tag_list;
- head->tag_list = ttmp;
-
- /* expand the all un-transformed tag string */
- mutt_str_append_item(&head->tags_with_hidden, new_tag, ' ');
+ np->transformed = safe_strdup(new_tag_transformed);
/* filter out hidden tags */
if (HiddenTags)
if (p && ((p == HiddenTags) || (*(p - 1) == ',') || (*(p - 1) == ' ')) &&
((*(p + xsz) == '\0') || (*(p + xsz) == ',') || (*(p + xsz) == ' ')))
- return;
+ np->hidden = true;
}
- /* expand the visible un-transformed tag string */
- mutt_str_append_item(&head->tags, new_tag, ' ');
-
- /* expand the transformed tag string */
- if (new_tag_transformed)
- mutt_str_append_item(&head->tags_transformed, new_tag_transformed, ' ');
- else
- mutt_str_append_item(&head->tags_transformed, new_tag, ' ');
+ STAILQ_INSERT_TAIL(head, np, entries);
}
/**
* driver_tags_replace - Replace all tags
- * @param[in] h: pointer to a header struct
+ * @param[in] head: pointer to the tags head
* @param[in] tags: string of all tags separated by space
*
* @retval 0 If no change are made
*/
int driver_tags_replace(struct TagHead *head, char *tags)
{
- if (tags && head && head->tags &&
- mutt_strcmp(head->tags, tags) == 0)
+ if (!head)
return 0;
driver_tags_free(head);
- driver_tags_init(head);
if (tags)
{
#ifndef _MUTT_TAG_H
#define _MUTT_TAG_H
+#include <stdbool.h>
+#include <stddef.h>
+#include "queue.h"
+
/**
- * struct TagNode - Tag element
+ * struct TagNode - LinkedList Tag Element
*
* Keep a linked list of header tags and their transformed values.
* Textual tags can be transformed to symbols to save space.
*
- * @sa TagNodes
+ * @sa TagNode
*/
-struct TagNode
-{
- char *name;
- char *transformed;
- struct TagNode *next;
-};
-/**
- * struct TagHead - tags data attached to an email
- *
- * This stores all tags data associated with an email.
- */
-struct TagHead
+STAILQ_HEAD(TagHead, TagNode);
+struct TagNode
{
- /* Without hidden tags */
- char *tags;
- char *tags_transformed;
-
- /* With hidden tags */
- char *tags_with_hidden;
- struct TagNode *tag_list;
+ char *name;
+ char *transformed;
+ bool hidden;
+ STAILQ_ENTRY(TagNode) entries;
};
void driver_tags_free(struct TagHead *head);
-const char *driver_tags_get(struct TagHead *head);
-const char *driver_tags_get_with_hidden(struct TagHead *head);
-const char *driver_tags_get_transformed(struct TagHead *head);
-const char *driver_tags_get_transformed_for(char *name, struct TagHead *head);
-void driver_tags_init(struct TagHead *head);
+char *driver_tags_get(struct TagHead *head);
+char *driver_tags_get_with_hidden(struct TagHead *head);
+char *driver_tags_get_transformed(struct TagHead *head);
+char *driver_tags_get_transformed_for(char *name, struct TagHead *head);
int driver_tags_replace(struct TagHead *head, char *tags);
#endif /* _MUTT_TAG_H */
#ifdef MIXMASTER
mutt_list_free(&(*h)->chain);
#endif
- driver_tags_free((*h)->tags);
+ driver_tags_free(&(*h)->tags);
#if defined(USE_POP) || defined(USE_IMAP) || defined(USE_NNTP) || defined(USE_NOTMUCH)
if ((*h)->free_cb)
(*h)->free_cb(*h);
return (pat->not ^ (h->env->x_label && patmatch(pat, h->env->x_label) == 0));
case MUTT_DRIVER_LABEL:
{
- const char *tags = driver_tags_get(h->tags);
- return (pat->not ^ (tags && patmatch(pat, tags) == 0));
+ char *tags = driver_tags_get(&h->tags);
+ bool ret = (pat->not ^ (tags && patmatch(pat, tags) == 0));
+ FREE(&tags);
+ return ret;
}
case MUTT_HORMEL:
return (pat->not ^ (h->env->spam && h->env->spam->data &&