Commit 8583edba authored by David Champion's avatar David Champion

Adds capability to edit x-labels inside mutt, and to sort by label.

parent 7989acf6
......@@ -57,6 +57,7 @@ OP_DELETE_THREAD "delete all messages in thread"
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"
......
......@@ -533,9 +533,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;
......@@ -579,6 +579,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)
Sort |= SORT_REVERSE;
......
......@@ -111,6 +111,10 @@ mutt_copy_hdr (FILE *in, FILE *out, LOFF_T off_start, LOFF_T off_end, int flags,
ignore = 0;
}
if (flags & CH_UPDATE_LABEL &&
mutt_strncasecmp ("X-Label:", buf, 8) == 0)
continue;
if (!ignore && fputs (buf, out) == EOF)
return (-1);
}
......@@ -414,6 +418,15 @@ mutt_copy_header (FILE *in, HEADER *h, FILE *out, int flags, const char *prefix)
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)
......@@ -494,6 +507,9 @@ _mutt_copy_message (FILE *fpout, FILE *fpin, HEADER *hdr, BODY *body,
_mutt_make_string (prefix, sizeof (prefix), NONULL (Prefix), Context, hdr, 0);
}
if (hdr->xlabel_changed)
chflags |= CH_UPDATE_LABEL;
if ((flags & MUTT_CM_NOHEADER) == 0)
{
if (flags & MUTT_CM_PREFIX)
......
......@@ -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 *);
......
......@@ -2093,6 +2093,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;
......
......@@ -6063,6 +6063,12 @@ not a standard message header field, but it can easily be inserted by
procmail and other mail filtering agents.
</para>
<para>
You can change or delete the <quote>X-Label:</quote> field within
Mutt using the <quote>edit-label</quote> command, bound to the
<quote>y</quote> 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
......
......@@ -99,6 +99,7 @@ const struct binding_t OpMain[] = { /* map: index */
{ "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" },
......@@ -200,6 +201,7 @@ const struct binding_t OpPager[] = { /* map: pager */
{ "set-flag", OP_MAIN_SET_FLAG, "w" },
{ "clear-flag", OP_MAIN_CLEAR_FLAG, "W" },
{ "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" },
......
......@@ -211,3 +211,61 @@ void mutt_edit_headers (const char *editor,
}
}
}
/*
* 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);
}
if (mutt_get_field("Label: ", buf, sizeof(buf), 0 /* | MUTT_CLEAR */) != 0)
return 0;
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),
MUTT_TAG, 0);
}
}
}
return changed;
}
......@@ -1242,7 +1242,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
* 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);
......@@ -1252,6 +1252,7 @@ int imap_sync_mailbox (CONTEXT* ctx, int expunge, int* index_hint)
dprint (1, (debugfile, "imap_sync_mailbox: Error opening mailbox in append mode\n"));
else
_mutt_save_message (h, appendctx, 1, 0, 0);
h->xlabel_changed = 0;
}
}
}
......
......@@ -3813,6 +3813,7 @@ const struct mapping_t SortMethods[] = {
{ "to", SORT_TO },
{ "score", SORT_SCORE },
{ "spam", SORT_SPAM },
{ "label", SORT_LABEL },
{ NULL, 0 }
};
......@@ -3832,6 +3833,7 @@ const struct mapping_t SortAuxMethods[] = {
{ "to", SORT_TO },
{ "score", SORT_SCORE },
{ "spam", SORT_SPAM },
{ "label", SORT_LABEL },
{ NULL, 0 }
};
......
......@@ -1793,7 +1793,7 @@ static int mh_sync_message (CONTEXT * ctx, int msgno)
{
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;
......@@ -1805,7 +1805,7 @@ static int maildir_sync_message (CONTEXT * ctx, int msgno)
{
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. */
......@@ -1927,6 +1927,7 @@ int mh_sync_mailbox (CONTEXT * ctx, int *index_hint)
}
}
else if (ctx->hdrs[i]->changed || ctx->hdrs[i]->attach_del ||
ctx->hdrs[i]->xlabel_changed ||
(ctx->magic == MUTT_MAILDIR
&& (option (OPTMAILDIRTRASH) || ctx->hdrs[i]->trash)
&& (ctx->hdrs[i]->deleted != ctx->hdrs[i]->trash)))
......
......@@ -760,6 +760,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;
......
......@@ -2814,6 +2814,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))
......
......@@ -186,6 +186,7 @@ void mutt_edit_content_type (HEADER *, BODY *, FILE *);
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_encode_descriptions (BODY *, short);
......
......@@ -210,6 +210,36 @@ static int compare_spam (const void *a, const void *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 = 0;
/* 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 @@ 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);
}
......
......@@ -35,6 +35,7 @@
#define SORT_UNREAD 16
#define SORT_FLAGGED 17
#define SORT_PATH 18
#define SORT_LABEL 19
/* Sort and sort_aux are shorts, and are a composite of a
* constant sort operation number and a set of compounded
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment