--- a/copy.h.orig	2011-03-21 18:19:35.000000000 +0100
+++ b/copy.h	2011-03-21 18:20:06.000000000 +0100
@@ -53,6 +53,7 @@
 #define CH_UPDATE_IRT     (1<<16) /* update In-Reply-To: */
 #define CH_UPDATE_REFS    (1<<17) /* update References: */
 #define CH_DISPLAY        (1<<18) /* display result to user */
+#define CH_UPDATE_LABEL   (1<<19) /*  update X-Label: 	from hdr->env->x_label? */
 
 
 int mutt_copy_hdr (FILE *, FILE *, LOFF_T, LOFF_T, int, const char *);
diff -r 25ea67e2a1f6 OPS
--- a/OPS	Wed Apr 23 18:08:56 2008 -0500
+++ b/OPS	Wed Apr 23 18:10:04 2008 -0500
@@ -56,6 +56,7 @@
 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 25ea67e2a1f6 PATCHES
--- a/PATCHES	Wed Apr 23 18:08:56 2008 -0500
+++ b/PATCHES	Wed Apr 23 18:10:04 2008 -0500
@@ -0,0 +1,1 @@
+patch-1.5.16.dgc.xlabel_ext.9
diff -r 25ea67e2a1f6 commands.c
--- a/commands.c	Wed Apr 23 18:08:56 2008 -0500
+++ b/commands.c	Wed Apr 23 18:10:04 2008 -0500
@@ -509,9 +509,9 @@
   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;
@@ -554,6 +554,10 @@
 
   case 10: /* s(p)am */
     Sort = SORT_SPAM;
+    break;
+
+  case 11: /* (l)abel */
+    Sort = SORT_LABEL;
     break;
   }
   if (reverse)
diff -r 25ea67e2a1f6 copy.c
--- a/copy.c	Wed Apr 23 18:08:56 2008 -0500
+++ b/copy.c	Wed Apr 23 18:10:04 2008 -0500
@@ -110,6 +110,10 @@
 	  continue;
 	ignore = 0;
       }
+
+      if (flags & CH_UPDATE_LABEL &&
+	  mutt_strncasecmp ("X-Label:", buf, 8) == 0)
+	continue;
 
       if (!ignore && fputs (buf, out) == EOF)
 	return (-1);
@@ -464,6 +468,15 @@
       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)
@@ -544,6 +557,9 @@
     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 25ea67e2a1f6 curs_main.c
--- a/curs_main.c	Wed Apr 23 18:08:56 2008 -0500
+++ b/curs_main.c	Wed Apr 23 18:10:04 2008 -0500
@@ -1922,6 +1922,21 @@
 	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 25ea67e2a1f6 functions.h
--- a/functions.h	Wed Apr 23 18:08:56 2008 -0500
+++ b/functions.h	Wed Apr 23 18:10:04 2008 -0500
@@ -99,6 +99,7 @@
   { "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" },
@@ -184,6 +185,7 @@
   { "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 25ea67e2a1f6 headers.c
--- a/headers.c	Wed Apr 23 18:08:56 2008 -0500
+++ b/headers.c	Wed Apr 23 18:10:04 2008 -0500
@@ -205,3 +205,59 @@
     }
   }
 }
+
+/*
+ * 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 25ea67e2a1f6 imap/imap.c
--- a/imap/imap.c	Wed Apr 23 18:08:56 2008 -0500
+++ b/imap/imap.c	Wed Apr 23 18:10:04 2008 -0500
@@ -1169,7 +1169,7 @@
        * 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);
@@ -1181,6 +1181,7 @@
 	}
 	else
 	  _mutt_save_message (h, appendctx, 1, 0, 0);
+	h->xlabel_changed = 0;
       }
     }
   }
diff -r 25ea67e2a1f6 imap/message.c
--- a/imap/message.c	Wed Apr 23 18:08:56 2008 -0500
+++ b/imap/message.c	Wed Apr 23 18:10:04 2008 -0500
@@ -365,6 +365,7 @@
   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 25ea67e2a1f6 mh.c
--- a/mh.c	Wed Apr 23 18:08:56 2008 -0500
+++ b/mh.c	Wed Apr 23 18:10:04 2008 -0500
@@ -1537,7 +1537,7 @@
 {
   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;
@@ -1549,7 +1549,7 @@
 {
   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. */
@@ -1671,6 +1671,7 @@
       }
     }
     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 25ea67e2a1f6 mutt.h
--- a/mutt.h	Wed Apr 23 18:08:56 2008 -0500
+++ b/mutt.h	Wed Apr 23 18:10:05 2008 -0500
@@ -729,6 +730,7 @@
 					 * 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 25ea67e2a1f6 pager.c
--- a/pager.c	Wed Apr 23 18:08:56 2008 -0500
+++ b/pager.c	Wed Apr 23 18:10:05 2008 -0500
@@ -2629,6 +2629,18 @@
 	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 25ea67e2a1f6 protos.h
--- a/protos.h	Wed Apr 23 18:08:56 2008 -0500
+++ b/protos.h	Wed Apr 23 18:10:05 2008 -0500
@@ -188,6 +188,7 @@
 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 25ea67e2a1f6 sort.c
--- a/sort.c	Wed Apr 23 18:08:56 2008 -0500
+++ b/sort.c	Wed Apr 23 18:10:05 2008 -0500
@@ -210,6 +210,36 @@
   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));
+}
+
 sort_t *mutt_get_sort_func (int method)
 {
   switch (method & SORT_MASK)
@@ -232,6 +262,8 @@
       return (compare_score);
     case SORT_SPAM:
       return (compare_spam);
+    case SORT_LABEL:
+      return (compare_label);
     default:
       return (NULL);
   }
diff -r 25ea67e2a1f6 sort.h
--- a/sort.h	Wed Apr 23 18:08:56 2008 -0500
+++ b/sort.h	Wed Apr 23 18:10:05 2008 -0500
@@ -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
--- a/init.h.orig	2010-09-15 17:39:31.000000000 +0200
+++ b/init.h	2011-03-21 18:23:20.000000000 +0100
@@ -3380,6 +3380,7 @@
   { "to",		SORT_TO },
   { "score",		SORT_SCORE },
   { "spam",		SORT_SPAM },
+  { "label",       SORT_LABEL },
   { NULL,               0 }
 };
 
@@ -3399,6 +3400,7 @@
   { "to",		SORT_TO },
   { "score",		SORT_SCORE },
   { "spam",		SORT_SPAM },
+  { "label",       SORT_LABEL },
   { NULL,               0 }
 };
 
--- a/doc/manual.xml.head.orig	2010-08-24 18:34:21.000000000 +0200
+++ b/doc/manual.xml.head	2011-03-21 18:28:37.000000000 +0100
@@ -5823,6 +5823,18 @@
 </para>
 
 <para>
+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.
+</para>
+
+<para>
+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.
+</para>
+ 
+<para>
 Lastly, Mutt has the ability to <link linkend="sort">sort</link> the
 mailbox into <link linkend="threads">threads</link>.  A thread is a
 group of messages which all relate to the same subject.  This is usually
