diff -r 5fc8c7cee1dd OPS
--- a/OPS Tue Mar 06 18:13:14 2007 -0800
+++ b/OPS Mon Mar 05 16:10:15 2007 -0600
@@ -56,6 +56,7 @@ OP_DISPLAY_ADDRESS "display full address
OP_DISPLAY_ADDRESS "display full address of sender"
OP_DISPLAY_HEADERS "display message and toggle header weeding"
OP_DISPLAY_MESSAGE "display a message"
+OP_EDIT_LABEL "add, change, or delete a message's label"
OP_EDIT_MESSAGE "edit the raw message"
OP_EDITOR_BACKSPACE "delete the char in front of the cursor"
OP_EDITOR_BACKWARD_CHAR "move the cursor one character to the left"
diff -r 5fc8c7cee1dd PATCHES
--- a/PATCHES Tue Mar 06 18:13:14 2007 -0800
+++ b/PATCHES Wed Mar 07 15:14:36 2007 -0600
@@ -0,0 +1,1 @@
+patch-1.5.13.dgc.xlabel_ext.9
diff -r 5fc8c7cee1dd commands.c
--- a/commands.c Tue Mar 06 18:13:14 2007 -0800
+++ b/commands.c Mon Mar 05 16:10:15 2007 -0600
@@ -506,9 +506,9 @@ int mutt_select_sort (int reverse)
int method = Sort; /* save the current method in case of abort */
switch (mutt_multi_choice (reverse ?
- _("Rev-Sort (d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/(u)nsort/si(z)e/s(c)ore/s(p)am?: ") :
- _("Sort (d)ate/(f)rm/(r)ecv/(s)ubj/t(o)/(t)hread/(u)nsort/si(z)e/s(c)ore/s(p)am?: "),
- _("dfrsotuzcp")))
+ _("Rev-Sort Date/Frm/Recv/Subj/tO/Thread/Unsort/siZe/sCore/sPam/Label?: ") :
+ _("Sort Date/Frm/Recv/Subj/tO/Thread/Unsort/siZe/sCore/sPam/Label?: "),
+ _("dfrsotuzcpl")))
{
case -1: /* abort - don't resort */
return -1;
@@ -551,6 +551,10 @@ int mutt_select_sort (int reverse)
case 10: /* s(p)am */
Sort = SORT_SPAM;
+ break;
+
+ case 11: /* (l)abel */
+ Sort = SORT_LABEL;
break;
}
if (reverse)
diff -r 5fc8c7cee1dd copy.c
--- a/copy.c Tue Mar 06 18:13:14 2007 -0800
+++ b/copy.c Mon Mar 05 16:10:15 2007 -0600
@@ -109,6 +109,10 @@ mutt_copy_hdr (FILE *in, FILE *out, LOFF
continue;
ignore = 0;
}
+
+ if (flags & CH_UPDATE_LABEL &&
+ mutt_strncasecmp ("X-Label:", buf, 8) == 0)
+ continue;
if (!ignore && fputs (buf, out) == EOF)
return (-1);
@@ -458,6 +462,15 @@ mutt_copy_header (FILE *in, HEADER *h, F
fprintf (out, "Lines: %d\n", h->lines);
}
+ if (flags & CH_UPDATE_LABEL && h->xlabel_changed)
+ {
+ h->xlabel_changed = 0;
+ 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)
@@ -538,6 +551,9 @@ _mutt_copy_message (FILE *fpout, FILE *f
else
_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 -r 5fc8c7cee1dd curs_main.c
--- a/curs_main.c Tue Mar 06 18:13:14 2007 -0800
+++ b/curs_main.c Mon Mar 05 16:10:15 2007 -0600
@@ -1901,6 +1901,21 @@ int mutt_index_menu (void)
menu->redraw = REDRAW_FULL;
break;
+ case OP_EDIT_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 -r 5fc8c7cee1dd doc/manual.xml.head
--- a/doc/manual.xml.head Tue Mar 06 18:13:14 2007 -0800
+++ b/doc/manual.xml.head Wed Mar 07 15:14:37 2007 -0600
@@ -4360,6 +4360,12 @@ and other mail filtering agents.
+You can change or delete the ``X-Label:'' field within Mutt using the
+``edit-label'' command, bound to the ``y'' key by default. This works
+for tagged messages, too.
+
+
+
Lastly, Mutt has the ability to sort the mailbox into
threads. 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
diff -r 5fc8c7cee1dd functions.h
--- a/functions.h Tue Mar 06 18:13:14 2007 -0800
+++ b/functions.h Mon Mar 05 16:10:15 2007 -0600
@@ -82,6 +82,7 @@ struct binding_t OpMain[] = {
{ "delete-thread", OP_DELETE_THREAD, "\004" },
{ "delete-subthread", OP_DELETE_SUBTHREAD, "\033d" },
{ "edit", OP_EDIT_MESSAGE, "e" },
+ { "edit-label", OP_EDIT_LABEL, "y" },
{ "edit-type", OP_EDIT_TYPE, "\005" },
{ "forward-message", OP_FORWARD_MESSAGE, "f" },
{ "flag-message", OP_FLAG_MESSAGE, "F" },
@@ -166,6 +167,7 @@ struct binding_t OpPager[] = {
{ "delete-thread", OP_DELETE_THREAD, "\004" },
{ "delete-subthread", OP_DELETE_SUBTHREAD, "\033d" },
{ "edit", OP_EDIT_MESSAGE, "e" },
+ { "edit-label", OP_EDIT_LABEL, "y" },
{ "edit-type", OP_EDIT_TYPE, "\005" },
{ "forward-message", OP_FORWARD_MESSAGE, "f" },
{ "flag-message", OP_FLAG_MESSAGE, "F" },
diff -r 5fc8c7cee1dd headers.c
--- a/headers.c Tue Mar 06 18:13:14 2007 -0800
+++ b/headers.c Mon Mar 05 16:10:15 2007 -0600
@@ -205,3 +205,59 @@ void mutt_edit_headers (const char *edit
}
}
}
+
+/*
+ * dgc: Add an X-Label: field.
+ */
+static int 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), 0 /* | M_CLEAR */);
+ new = buf;
+ SKIPWS(new);
+ if (*new == '\0')
+ new = NULL;
+
+ changed = 0;
+ if (hdr != NULL) {
+ changed += 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 (label_message(HDR_OF(i), new)) {
+ ++changed;
+ mutt_set_flag(Context, HDR_OF(i),
+ M_TAG, 0);
+ }
+ }
+ }
+
+ return changed;
+}
diff -r 5fc8c7cee1dd imap/imap.c
--- a/imap/imap.c Tue Mar 06 18:13:14 2007 -0800
+++ b/imap/imap.c Mon Mar 05 16:10:30 2007 -0600
@@ -1167,7 +1167,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int
* we delete the message and reupload it.
* This works better if we're expunging, of course. */
if ((h->env && (h->env->refs_changed || h->env->irt_changed)) ||
- h->attach_del)
+ h->attach_del || h->xlabel_changed)
{
mutt_message (_("Saving changed messages... [%d/%d]"), n+1,
ctx->msgcount);
@@ -1179,6 +1179,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int
}
else
_mutt_save_message (h, appendctx, 1, 0, 0);
+ h->xlabel_changed = 0;
}
}
}
diff -r 5fc8c7cee1dd imap/message.c
--- a/imap/message.c Tue Mar 06 18:13:14 2007 -0800
+++ b/imap/message.c Mon Mar 05 16:10:36 2007 -0600
@@ -368,6 +368,7 @@ int imap_fetch_message (MESSAGE *msg, CO
IMAP_CACHE *cache;
int read;
int rc;
+ char *x_label = NULL;
/* Sam's weird courier server returns an OK response even when FETCH
* fails. Thanks Sam. */
short fetched = 0;
diff -r 5fc8c7cee1dd init.h
--- a/init.h Tue Mar 06 18:13:14 2007 -0800
+++ b/init.h Wed Mar 07 15:14:37 2007 -0600
@@ -3059,6 +3059,7 @@ const struct mapping_t SortMethods[] = {
{ "to", SORT_TO },
{ "score", SORT_SCORE },
{ "spam", SORT_SPAM },
+ { "label", SORT_LABEL },
{ NULL, 0 }
};
@@ -3078,6 +3079,7 @@ const struct mapping_t SortAuxMethods[]
{ "to", SORT_TO },
{ "score", SORT_SCORE },
{ "spam", SORT_SPAM },
+ { "label", SORT_LABEL },
{ NULL, 0 }
};
diff -r 5fc8c7cee1dd mh.c
--- a/mh.c Tue Mar 06 18:13:14 2007 -0800
+++ b/mh.c Wed Mar 07 15:14:38 2007 -0600
@@ -1429,7 +1429,7 @@ static int mh_sync_message (CONTEXT * ct
{
HEADER *h = ctx->hdrs[msgno];
- if (h->attach_del ||
+ if (h->attach_del || h->xlabel_changed ||
(h->env && (h->env->refs_changed || h->env->irt_changed)))
if (mh_rewrite_message (ctx, msgno) != 0)
return -1;
@@ -1441,7 +1441,7 @@ static int maildir_sync_message (CONTEXT
{
HEADER *h = ctx->hdrs[msgno];
- if (h->attach_del ||
+ if (h->attach_del || h->xlabel_changed ||
(h->env && (h->env->refs_changed || h->env->irt_changed)))
{
/* when doing attachment deletion/rethreading, fall back to the MH case. */
@@ -1560,6 +1560,7 @@ int mh_sync_mailbox (CONTEXT * ctx, int
}
}
else if (ctx->hdrs[i]->changed || ctx->hdrs[i]->attach_del ||
+ ctx->hdrs[i]->xlabel_changed ||
(ctx->magic == M_MAILDIR
&& (option (OPTMAILDIRTRASH) || ctx->hdrs[i]->trash)
&& (ctx->hdrs[i]->deleted != ctx->hdrs[i]->trash)))
diff -r 5fc8c7cee1dd mutt.h
--- a/mutt.h Tue Mar 06 18:13:14 2007 -0800
+++ b/mutt.h Mon Mar 05 16:10:15 2007 -0600
@@ -94,6 +94,7 @@
#define CH_NOQFROM (1<<15) /* give CH_FROM precedence over CH_WEED? */
#define CH_UPDATE_IRT (1<<16) /* update In-Reply-To: */
#define CH_UPDATE_REFS (1<<17) /* update References: */
+#define CH_UPDATE_LABEL (1<<18) /* 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 */
@@ -723,6 +724,7 @@ typedef struct header
* This flag is used by the maildir_trash
* option.
*/
+ unsigned int xlabel_changed : 1; /* editable - used for syncing */
/* timezone of the sender of this message */
unsigned int zhours : 5;
diff -r 5fc8c7cee1dd pager.c
--- a/pager.c Tue Mar 06 18:13:14 2007 -0800
+++ b/pager.c Mon Mar 05 16:10:16 2007 -0600
@@ -2624,6 +2624,18 @@ search_next:
redraw = REDRAW_FULL;
break;
+ case OP_EDIT_LABEL:
+ CHECK_MODE(IsHeader (extra));
+ rc = mutt_label_message(extra->hdr);
+ if (rc > 0) {
+ Context->changed = 1;
+ redraw = REDRAW_FULL;
+ mutt_message ("%d label%s changed.", rc, rc == 1 ? "" : "s");
+ }
+ else {
+ mutt_message _("No labels changed.");
+ }
+ break;
case OP_MAIL_KEY:
if (!(WithCrypto & APPLICATION_PGP))
diff -r 5fc8c7cee1dd protos.h
--- a/protos.h Tue Mar 06 18:13:14 2007 -0800
+++ b/protos.h Wed Mar 07 15:14:39 2007 -0600
@@ -176,6 +176,7 @@ void mutt_edit_file (const char *, const
void mutt_edit_file (const char *, const char *);
void mutt_edit_headers (const char *, const char *, HEADER *, char *, size_t);
int mutt_filter_unprintable (char **);
+int mutt_label_message (HEADER *);
void mutt_curses_error (const char *, ...);
void mutt_curses_message (const char *, ...);
void mutt_enter_command (void);
diff -r 5fc8c7cee1dd sort.c
--- a/sort.c Tue Mar 06 18:13:14 2007 -0800
+++ b/sort.c Mon Mar 05 16:10:16 2007 -0600
@@ -205,6 +205,36 @@ int compare_spam (const void *a, const v
AUXSORT(result, a, b);
}
+ return (SORTCODE(result));
+}
+
+int compare_label (const void *a, const void *b)
+{
+ HEADER **ppa = (HEADER **) a;
+ HEADER **ppb = (HEADER **) b;
+ int ahas, bhas, result;
+
+ /* As with compare_spam, not all messages will have the x-label
+ * property. Blank X-Labels are treated as null in the index
+ * display, so we'll consider them as null for sort, too. */
+ ahas = (*ppa)->env && (*ppa)->env->x_label && *((*ppa)->env->x_label);
+ bhas = (*ppb)->env && (*ppb)->env->x_label && *((*ppb)->env->x_label);
+
+ /* First we bias toward a message with a label, if the other does not. */
+ if (ahas && !bhas)
+ return (SORTCODE(-1));
+ if (!ahas && bhas)
+ return (SORTCODE(1));
+
+ /* If neither has a label, use aux sort. */
+ if (!ahas && !bhas)
+ {
+ AUXSORT(result, a, b);
+ return (SORTCODE(result));
+ }
+
+ /* If both have a label, we just do a lexical compare. */
+ result = mutt_strcasecmp((*ppa)->env->x_label, (*ppb)->env->x_label);
return (SORTCODE(result));
}
@@ -230,6 +260,8 @@ sort_t *mutt_get_sort_func (int method)
return (compare_score);
case SORT_SPAM:
return (compare_spam);
+ case SORT_LABEL:
+ return (compare_label);
default:
return (NULL);
}
diff -r 5fc8c7cee1dd sort.h
--- a/sort.h Tue Mar 06 18:13:14 2007 -0800
+++ b/sort.h Mon Mar 05 16:10:16 2007 -0600
@@ -31,6 +31,7 @@
#define SORT_KEYID 12
#define SORT_TRUST 13
#define SORT_SPAM 14
+#define SORT_LABEL 15
/* dgc: Sort & SortAux are shorts, so I'm bumping these bitflags up from
* bits 4 & 5 to bits 8 & 9 to make room for more sort keys in the future. */
#define SORT_MASK 0xff