diff -ru mutt-1.1.12/OPS mutt-1.1.12-dgc/OPS --- mutt-1.1.12/OPS Tue Feb 15 10:28:45 2000 +++ mutt-1.1.12-dgc/OPS Tue May 2 00:39:05 2000 @@ -83,6 +83,7 @@ OP_HALF_UP "scroll up 1/2 page" OP_HELP "this screen" OP_JUMP "jump to an index number" +OP_LABEL "add or change a message's label" OP_LAST_ENTRY "move to the last entry" OP_LIST_REPLY "reply to specified mailing list" OP_MACRO "execute a macro" diff -ru mutt-1.1.12/copy.c mutt-1.1.12-dgc/copy.c --- mutt-1.1.12/copy.c Fri Mar 3 04:10:07 2000 +++ mutt-1.1.12-dgc/copy.c Tue May 2 00:42:59 2000 @@ -95,6 +95,10 @@ ignore = 0; } + if (flags & CH_UPDATE_LABEL && + mutt_strncasecmp ("X-Label:", buf, 8) == 0) + continue; + if (!ignore && fputs (buf, out) == EOF) return (-1); } @@ -343,6 +347,7 @@ if (fputc ('\n', out) == EOF) return (-1); } + } } @@ -354,6 +359,14 @@ fprintf (out, "Lines: %d\n", h->lines); } + if (flags & CH_UPDATE_LABEL && h->xlabel_changed) + { + if (h->env->x_label != NULL) + if (fprintf(out, "X-Label: %s\n", h->env->x_label) != + 10 + strlen(h->env->x_label)) + return -1; + } + if ((flags & CH_NONEWLINE) == 0) { if (flags & CH_PREFIX) @@ -424,6 +437,9 @@ if (flags & M_CM_PREFIX) _mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix), Context, hdr, 0); + + if (hdr->xlabel_changed) + chflags |= CH_UPDATE_LABEL; if ((flags & M_CM_NOHEADER) == 0) { diff -ru mutt-1.1.12/curs_main.c mutt-1.1.12-dgc/curs_main.c --- mutt-1.1.12/curs_main.c Sat Apr 22 03:21:10 2000 +++ mutt-1.1.12-dgc/curs_main.c Tue May 2 00:39:05 2000 @@ -1634,6 +1634,21 @@ menu->redraw = REDRAW_FULL; break; + case OP_LABEL: + + CHECK_MSGCOUNT; + CHECK_READONLY; + rc = mutt_label_message(tag ? NULL : CURHDR); + if (rc > 0) { + Context->changed = 1; + menu->redraw = REDRAW_FULL; + mutt_message ("%d label%s changed.", rc, rc == 1 ? "" : "s"); + } + else { + mutt_message _("No labels changed."); + } + break; + case OP_LIST_REPLY: CHECK_ATTACH; diff -ru mutt-1.1.12/doc/manual.sgml mutt-1.1.12-dgc/doc/manual.sgml --- mutt-1.1.12/doc/manual.sgml Sat Apr 22 13:33:47 2000 +++ mutt-1.1.12-dgc/doc/manual.sgml Tue May 2 00:39:05 2000 @@ -1610,6 +1610,7 @@ ~U unread messages ~v message is part of a collapsed thread. ~x EXPR messages which contain EXPR in the `References' field +~y EXPR messages which contain EXPR in the `X-Label' field ~z [MIN]-[MAX] messages with a size in the range MIN to MAX *) @@ -1944,6 +1945,16 @@ ``From'' field. When unset, the ``Reply-To'' field will be used when present. +The ``X-Label:'' header field can be used to further identify mailing +lists or list subject matter (or just to annotate messages +individually). The variable's ``%y'' and +``%Y'' escapes can be used to expand ``X-Label:'' fields in the +index, and Mutt's pattern-matcher can match regular expressions to +``X-Label:'' fields with the ``~y'' selector. ``X-Label:'' is not a +standard message header field, but it can easily be inserted by procmail +and other mail filtering agents. + Lastly, Mutt has the ability to the mailbox into . A thread is a group of messages which all relate to the same subject. This is usually organized into a tree-like structure where a @@ -3667,6 +3678,12 @@ %u user (login) name of the author %v first name of the author, or the recipient if the message is from you +%y `x-label:' field, if present +%Y `x-label:' field, if present, and + (1) not a part of a thread tree; + (2) at the top of a thread; or + (3) `x-label' is different from + preceding message's `x-label' %Z message status flags %{fmt} the date and time of the message is converted to sender's time zone, and diff -ru mutt-1.1.12/functions.h mutt-1.1.12-dgc/functions.h --- mutt-1.1.12/functions.h Fri Mar 3 04:10:08 2000 +++ mutt-1.1.12-dgc/functions.h Tue May 2 00:39:05 2000 @@ -89,6 +89,7 @@ { "next-undeleted", OP_MAIN_NEXT_UNDELETED, "j" }, { "previous-undeleted", OP_MAIN_PREV_UNDELETED, "k" }, { "limit", OP_MAIN_LIMIT, "l" }, + { "label", OP_LABEL, "y" }, { "list-reply", OP_LIST_REPLY, "L" }, { "mail", OP_MAIL, "m" }, { "toggle-new", OP_TOGGLE_NEW, "N" }, @@ -165,6 +166,7 @@ { "next-entry", OP_NEXT_ENTRY, "J" }, { "previous-undeleted",OP_MAIN_PREV_UNDELETED, "k" }, { "previous-entry", OP_PREV_ENTRY, "K" }, + { "label", OP_LABEL, "y" }, { "list-reply", OP_LIST_REPLY, "L" }, { "redraw-screen", OP_REDRAW, "\014" }, { "mail", OP_MAIL, "m" }, diff -ru mutt-1.1.12/hdrline.c mutt-1.1.12-dgc/hdrline.c --- mutt-1.1.12/hdrline.c Fri Mar 3 04:10:08 2000 +++ mutt-1.1.12-dgc/hdrline.c Tue May 2 00:39:05 2000 @@ -216,6 +216,8 @@ * %T = $to_chars * %u = user (login) name of author * %v = first name of author, unless from self + * %y = `x-label:' field (if present) + * %Y = `x-label:' field (if present, tree unfolded, and != parent's x-label) * %Z = status flags */ struct hdr_format_info @@ -236,7 +238,7 @@ format_flag flags) { struct hdr_format_info *hfi = (struct hdr_format_info *) data; - HEADER *hdr; + HEADER *hdr, *htmp; CONTEXT *ctx; char fmt[SHORT_STRING], buf2[SHORT_STRING], ch, *p; int do_locales, i; @@ -607,6 +609,48 @@ if ((p = strpbrk (buf2, " %@"))) *p = 0; snprintf (dest, destlen, fmt, buf2); + break; + + case 'y': + if (optional) + { + optional = hdr->env->x_label ? 1 : 0; + } + snprintf (fmt, sizeof (fmt), "%%%ss", prefix); + snprintf (dest, destlen, fmt, NONULL (hdr->env->x_label)); + break; + + case 'Y': + if (hdr->env->x_label) + { + i = 1; /* reduce reuse recycle */ + htmp = NULL; + if (flags & M_FORMAT_TREE + && (hdr->prev && hdr->prev->env->x_label)) + htmp = hdr->prev; + else if (flags & M_FORMAT_TREE + && (hdr->parent && hdr->parent->env->x_label)) + htmp = hdr->parent; + if (htmp && mutt_strcasecmp (hdr->env->x_label, + htmp->env->x_label) == 0) + i = 0; + } + else + i = 0; + if (optional) + { + optional = i; + } + if (i) + { + snprintf (fmt, sizeof (fmt), "%%%ss", prefix); + snprintf (dest, destlen, fmt, NONULL (hdr->env->x_label)); + } + else + { + snprintf (fmt, sizeof (fmt), "%%%ss", prefix); + snprintf (dest, destlen, fmt, ""); + } break; case 'Z': diff -ru mutt-1.1.12/headers.c mutt-1.1.12-dgc/headers.c --- mutt-1.1.12/headers.c Wed Apr 12 11:31:25 2000 +++ mutt-1.1.12-dgc/headers.c Tue May 2 00:39:05 2000 @@ -206,3 +206,122 @@ if (!in_reply_to) mutt_free_list (&msg->env->references); } + +/* + * dgc: I mistakenly thought this would be used with OP_LABEL. (I wasn't + * thinking on the right track at all.) It's here if you want it, but + * not tested. + * + * Add/modify a user hdr to/in an envelope. If hdr already exists, + * optionally overwrite it. If hdr value is null, optionally remove it. + * + * env: message envelope + * hdr: header field name (e.g., "X-Archive") + * value: header field value (e.g., "no") + * overwrite: if true, overwrite extant values + * empty: if true and value == NULL, remove hdr field from envelope + */ +int mutt_mod_user_hdr (ENVELOPE *env, + char *hdr, + char *value, + int overwrite, + int empty) +{ + LIST *list, *last; + int len; + char *s; + + len = strlen(hdr); + if ((s = safe_malloc(len + 2 + strlen(value) + 1)) == NULL) + return 0; + + last = NULL; /* Shut the compiler up. */ + list = env->userhdrs; + while (list != NULL) { + if (tolower(*list->data) == *hdr) { + if (strncasecmp(list->data, hdr, len) == 0 && + strncmp(&list->data[len], ": ", 2)) { + if (overwrite || empty) + break; + else + return 0; + } + } + last = list; + list = list->next; + } + if (list == NULL) { + list = mutt_new_list(); + if (last != NULL) + last->next = list; + } else if (empty && value == NULL) { + if (last != NULL) + last->next = list->next; + FREE(list->data); + FREE(list); + FREE(&s); + return 1; + } + + list->data = s; + sprintf(list->data, "%s: %s", hdr, value); + + return 1; +} + +/* + * dgc: Add an X-Label: field. There's probably a better module for this, + * but I don't want to presume. + */ +int _mutt_label_message(HEADER *hdr, char *new) +{ + if (hdr == NULL) + return 0; + if (hdr->env->x_label == NULL && new == NULL) + return 0; + if (hdr->env->x_label != NULL && new != NULL && + strcmp(hdr->env->x_label, new) == 0) + return 0; + if (hdr->env->x_label != NULL) + FREE(&hdr->env->x_label); + if (new == NULL) + hdr->env->x_label = NULL; + else + hdr->env->x_label = safe_strdup(new); + return hdr->changed = hdr->xlabel_changed = 1; +} + +int mutt_label_message(HEADER *hdr) +{ + char buf[LONG_STRING], *new; + int i; + int changed; + + *buf = '\0'; + if (hdr != NULL && hdr->env->x_label != NULL) { + strncpy(buf, hdr->env->x_label, LONG_STRING); + } + + mutt_get_field("Label: ", buf, sizeof(buf), M_CLEAR); + new = buf; + SKIPWS(new); + if (*new == '\0') + new = NULL; + + changed = 0; + if (hdr != NULL) { + changed += _mutt_label_message(hdr, new); + } else { +#define HDR_OF(index) Context->hdrs[Context->v2r[(index)]] + for (i = 0; i < Context->vcount; ++i) { + if (HDR_OF(i)->tagged) + if (_mutt_label_message(HDR_OF(i), new)) { + ++changed; + mutt_set_flag(Context, HDR_OF(i), + M_TAG, 0); + } + } + } + + return changed; +} diff -ru mutt-1.1.12/mutt.h mutt-1.1.12-dgc/mutt.h --- mutt-1.1.12/mutt.h Wed Mar 22 02:18:55 2000 +++ mutt-1.1.12-dgc/mutt.h Tue May 2 00:39:05 2000 @@ -67,6 +67,7 @@ #define CH_NOLEN (1<<12) /* don't write Content-Length: and Lines: */ #define CH_WEED_DELIVERED (1<<13) /* weed eventual Delivered-To headers */ #define CH_FORCE_FROM (1<<14) /* give CH_FROM precedence over CH_WEED? */ +#define CH_UPDATE_LABEL (1<<15) /* update X-Label: from hdr->env->x_label? */ /* flags for mutt_enter_string() */ #define M_ALIAS 1 /* do alias "completion" by calling up the alias-menu */ @@ -199,6 +200,7 @@ M_PGP_ENCRYPT, M_PGP_KEY, #endif + M_XLABEL, /* Options for Mailcap lookup */ M_EDIT, @@ -459,6 +461,7 @@ char *message_id; char *supersedes; char *date; + char *x_label; LIST *references; /* message references (in reverse order) */ LIST *userhdrs; /* user defined headers */ } ENVELOPE; @@ -560,6 +563,7 @@ unsigned int threaded : 1; /* message has been threaded */ unsigned int recip_valid : 1; /* is_recipient is valid */ unsigned int active : 1; /* message is not to be removed */ + unsigned int xlabel_changed : 1; /* editable - used for syncing */ /* timezone of the sender of this message */ unsigned int zhours : 5; diff -ru mutt-1.1.12/parse.c mutt-1.1.12-dgc/parse.c --- mutt-1.1.12/parse.c Sat Apr 22 03:48:56 2000 +++ mutt-1.1.12-dgc/parse.c Tue May 2 00:39:05 2000 @@ -1181,6 +1181,11 @@ } matched = 1; } + else if (mutt_strcasecmp (line+1, "-label") == 0) + { + e->x_label = safe_strdup(p); + matched = 1; + } default: break; diff -ru mutt-1.1.12/pattern.c mutt-1.1.12-dgc/pattern.c --- mutt-1.1.12/pattern.c Sun Apr 9 07:35:03 2000 +++ mutt-1.1.12-dgc/pattern.c Tue May 2 00:39:05 2000 @@ -88,6 +88,7 @@ { 'U', M_UNREAD, 0, NULL }, { 'v', M_COLLAPSED, 0, NULL }, { 'x', M_REFERENCE, 0, eat_regexp }, + { 'y', M_XLABEL, 0, eat_regexp }, { 'z', M_SIZE, 0, eat_range }, { 0 } }; @@ -890,6 +891,8 @@ case M_PGP_KEY: return (pat->not ^ (h->pgp & PGPKEY)); #endif + case M_XLABEL: + return (pat->not ^ (h->env->x_label && regexec (pat->rx, h->env->x_label, 0, NULL, 0) == 0)); } mutt_error (_("error: unknown op %d (report this error)."), pat->op); return (-1); diff -ru mutt-1.1.12/protos.h mutt-1.1.12-dgc/protos.h --- mutt-1.1.12/protos.h Tue Mar 7 05:13:38 2000 +++ mutt-1.1.12-dgc/protos.h Tue May 2 00:39:05 2000 @@ -142,6 +142,7 @@ void mutt_edit_content_type (HEADER *, BODY *); void mutt_edit_file (const char *, const char *); void mutt_edit_headers (const char *, const char *, HEADER *, char *, size_t); +int mutt_label_message (HEADER *); void mutt_curses_error (const char *, ...); void mutt_enter_command (void); void mutt_expand_aliases_env (ENVELOPE *);