[PATCH 2 of 2] imported patch display-subject
# HG changeset patch
# User David Champion <dgc@xxxxxxxxxxxx>
# Date 1227038081 21600
# Branch HEAD
# Node ID b674b979da7eafe229222444a9529e8c70a8da4a
# Parent bd0ea10f5757dc9776c6c661a9fbc8d21903bdac
imported patch display-subject
diff -r bd0ea10f5757 -r b674b979da7e doc/manual.xml.head
--- a/doc/manual.xml.head Tue Nov 18 13:54:41 2008 -0600
+++ b/doc/manual.xml.head Tue Nov 18 13:54:41 2008 -0600
@@ -2912,6 +2912,58 @@
</para>
</sect1>
+
+<sect1 id="subjrepl">
+<title>Altering the Display Subject</title>
+
+<para>
+In today's world of e-mail automation, Subject: headers often turn up
+with redundant, machine-generated text that provides no information
+useful to you as a reader, but consumes screen space. To reduce
+the effect of this trend, you can use the <literal>subjectrx</literal>
+and <literal>unsubjectrx</literal> commands to apply regular expression
+transformations to your Subject: headers.
+</para>
+
+<para>
+<literallayout>
+Usage: <literal>subjectrx</literal> <emphasis>regex</emphasis>
<emphasis>replace</emphasis>
+Usage: <literal>unsubjectrx</literal> <emphasis>regex</emphasis>
+</literallayout>
+</para>
+
+<para>
+<literal>subjectrx</literal> creates a new subject transformation. Wherever
+the <emphasis>regex</emphasis> appears in a Subject: header, it will
+be replaced with <emphasis>replace</emphasis> for the index view only.
+The actual subject of the message is not changed, as you'll see when
+you view, edit, or reply to the message. The <emphasis>replace</emphasis>
+string can contain certain substitution tokens: %L for the part of
+the subject to the left of the regex, %R for the part to the right,
+and %1, %2, etc. for successive subexpressions. The
+<emphasis>replace</emphasis> text replaces the <emphasis>entire</emphasis>
+subject, not just the matching part.
+</para>
+
+<para>
+<literal>unsubjectrx</literal> removes a <emphasis>regex</emphasis> from
+the list of transformations in use.
+</para>
+
+
+<para>
+Example: At my office we use the RT ticketing system for handling
+customer and internal projects. RT inserts a prefix on each Subject:
+header which it uses to associate e-mail to a ticket. It's critical
+that this be present in the mail, but it's wasteful on my index screen.
+This <literal>subjectrx</literal> command hides it from view:
+<screen>
+subjectrx "\\[rt #[0-9]+\\] *" "%L%R"
+</screen>
+</para>
+
+</sect1>
+
<sect1 id="set">
<title>Setting and Querying Variables</title>
diff -r bd0ea10f5757 -r b674b979da7e globals.h
--- a/globals.h Tue Nov 18 13:54:41 2008 -0600
+++ b/globals.h Tue Nov 18 13:54:41 2008 -0600
@@ -172,6 +172,7 @@
WHERE RX_LIST *UnSubscribedLists INITVAL(0);
WHERE REPLACE_LIST *SpamList INITVAL(0);
WHERE RX_LIST *NoSpamList INITVAL(0);
+WHERE REPLACE_LIST *SubjectRxList INITVAL(0);
/* bit vector for boolean variables */
diff -r bd0ea10f5757 -r b674b979da7e hdrline.c
--- a/hdrline.c Tue Nov 18 13:54:41 2008 -0600
+++ b/hdrline.c Tue Nov 18 13:54:41 2008 -0600
@@ -196,6 +196,91 @@
return h->recipient;
}
+
+static char *apply_subject_mods (ENVELOPE *env)
+{
+ REPLACE_LIST *l;
+ static regmatch_t *pmatch = NULL;
+ static int nmatch = 0;
+ static char twinbuf[2][LONG_STRING];
+ int switcher = 0;
+ char *p;
+ int i, n;
+ int tlen = 0;
+ char *src, *dst;
+
+ if (env == NULL)
+ return NULL;
+
+ if (SubjectRxList == NULL)
+ return env->subject;
+
+ src = twinbuf[switcher];
+ dst = src;
+
+ strncpy(src, env->subject, LONG_STRING-1);
+ src[LONG_STRING-1] = '\0';
+
+ for (l = SubjectRxList; l; l = l->next)
+ {
+ /* If this pattern needs more matches, expand pmatch. */
+ if (l->nmatch > nmatch)
+ {
+ safe_realloc (&pmatch, l->nmatch * sizeof(regmatch_t));
+ nmatch = l->nmatch;
+ }
+
+ if (regexec (l->rx->rx, src, l->nmatch, pmatch, 0) == 0)
+ {
+ tlen = 0;
+ switcher ^= 1;
+ dst = twinbuf[switcher];
+
+ dprint (5, (debugfile, "apply_subject_mods: %s matches %s\n", src,
l->rx->pattern));
+
+ /* Copy into other twinbuf with substitutions */
+ if (l->template)
+ {
+ for (p = l->template; *p; )
+ {
+ if (*p == '%')
+ {
+ p++;
+ if (*p == 'L')
+ {
+ p++;
+ strncpy(&dst[tlen], src, pmatch[0].rm_so);
+ tlen += pmatch[0].rm_so;
+ }
+ else if (*p == 'R')
+ {
+ p++;
+ strncpy(&dst[tlen], &src[pmatch[0].rm_eo], LONG_STRING-tlen-1);
+ tlen += strlen(src) - pmatch[0].rm_eo;
+ }
+ else
+ {
+ n = atoi(++p); /* get subst number */
+ while (isdigit((unsigned char)*p)) /* skip subst token */
+ ++p;
+ for (i = pmatch[n].rm_so; (i < pmatch[n].rm_eo) && (tlen <
LONG_STRING-1); i++)
+ dst[tlen++] = src[i];
+ }
+ }
+ else
+ dst[tlen++] = *p++;
+ }
+ }
+ dst[tlen] = '\0';
+ dprint (5, (debugfile, "apply_subject_mods: subst %s\n", dst));
+ }
+ src = dst;
+ }
+
+ env->disp_subj = safe_strdup(dst);
+ return env->disp_subj;
+}
+
/* %a = address of author
* %A = reply-to address (if present; otherwise: address of author
@@ -547,20 +632,28 @@
break;
case 's':
-
- if (flags & M_FORMAT_TREE && !hdr->collapsed)
{
- if (flags & M_FORMAT_FORCESUBJ)
+ char *subj;
+ if (hdr->env->disp_subj)
+ subj = hdr->env->disp_subj;
+ else if (SubjectRxList)
+ subj = apply_subject_mods(hdr->env);
+ else
+ subj = hdr->env->subject;
+ if (flags & M_FORMAT_TREE && !hdr->collapsed)
{
- mutt_format_s (dest, destlen, "", NONULL (hdr->env->subject));
- snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree, dest);
- mutt_format_s_tree (dest, destlen, prefix, buf2);
+ if (flags & M_FORMAT_FORCESUBJ)
+ {
+ mutt_format_s (dest, destlen, "", NONULL (subj));
+ snprintf (buf2, sizeof (buf2), "%s%s", hdr->tree, dest);
+ mutt_format_s_tree (dest, destlen, prefix, buf2);
+ }
+ else
+ mutt_format_s_tree (dest, destlen, prefix, hdr->tree);
}
else
- mutt_format_s_tree (dest, destlen, prefix, hdr->tree);
+ mutt_format_s (dest, destlen, prefix, NONULL (subj));
}
- else
- mutt_format_s (dest, destlen, prefix, NONULL (hdr->env->subject));
break;
case 'S':
diff -r bd0ea10f5757 -r b674b979da7e init.c
--- a/init.c Tue Nov 18 13:54:41 2008 -0600
+++ b/init.c Tue Nov 18 13:54:41 2008 -0600
@@ -734,6 +734,88 @@
return 0;
}
+
+static int parse_replace_list (BUFFER *buf, BUFFER *s, unsigned long data,
BUFFER *err)
+{
+ REPLACE_LIST **list = (REPLACE_LIST **)data;
+ BUFFER templ;
+
+ memset(&templ, 0, sizeof(templ));
+
+ /* First token is a regexp. */
+ if (!MoreArgs(s))
+ {
+ strfcpy(err->data, _("not enough arguments"), err->dsize);
+ return -1;
+ }
+ mutt_extract_token(buf, s, 0);
+
+ /* Second token is a replacement template */
+ if (!MoreArgs(s))
+ {
+ strfcpy(err->data, _("not enough arguments"), err->dsize);
+ return -1;
+ }
+ mutt_extract_token(&templ, s, 0);
+
+ if (add_to_replace_list(list, buf->data, templ.data, err) != 0) {
+ FREE(&templ.data);
+ return -1;
+ }
+ FREE(&templ.data);
+
+ return 0;
+}
+
+static int parse_unreplace_list (BUFFER *buf, BUFFER *s, unsigned long data,
BUFFER *err)
+{
+ REPLACE_LIST **list = (REPLACE_LIST **)data;
+
+ /* First token is a regexp. */
+ if (!MoreArgs(s))
+ {
+ strfcpy(err->data, _("not enough arguments"), err->dsize);
+ return -1;
+ }
+
+ mutt_extract_token(buf, s, 0);
+ remove_from_replace_list(list, buf->data);
+ return 0;
+}
+
+
+static void clear_subject_mods (void)
+{
+ int i;
+ if (Context && Context->msgcount)
+ {
+ for (i = 0; i < Context->msgcount; i++)
+ FREE(&Context->hdrs[i]->env->disp_subj);
+ }
+}
+
+
+static int parse_subjectrx_list (BUFFER *buf, BUFFER *s, unsigned long data,
BUFFER *err)
+{
+ int rc;
+
+ rc = parse_replace_list(buf, s, data, err);
+ if (rc == 0)
+ clear_subject_mods();
+ return rc;
+}
+
+
+static int parse_unsubjectrx_list (BUFFER *buf, BUFFER *s, unsigned long data,
BUFFER *err)
+{
+ int rc;
+
+ rc = parse_unreplace_list(buf, s, data, err);
+ if (rc == 0)
+ clear_subject_mods();
+ return rc;
+}
+
static int parse_spam_list (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER
*err)
{
diff -r bd0ea10f5757 -r b674b979da7e init.h
--- a/init.h Tue Nov 18 13:54:41 2008 -0600
+++ b/init.h Tue Nov 18 13:54:41 2008 -0600
@@ -3320,6 +3320,10 @@
static int parse_unsubscribe (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_attachments (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_unattachments (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+static int parse_replace_list (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+static int parse_unreplace_list (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+static int parse_subjectrx_list (BUFFER *, BUFFER *, unsigned long, BUFFER *);
+static int parse_unsubjectrx_list (BUFFER *, BUFFER *, unsigned long, BUFFER
*);
static int parse_alternates (BUFFER *, BUFFER *, unsigned long, BUFFER *);
@@ -3389,6 +3393,8 @@
{ "spam", parse_spam_list, M_SPAM },
{ "nospam", parse_spam_list, M_NOSPAM },
{ "subscribe", parse_subscribe, 0 },
+ { "subjectrx", parse_subjectrx_list, UL &SubjectRxList },
+ { "unsubjectrx", parse_unsubjectrx_list, UL &SubjectRxList },
{ "toggle", parse_set, M_SET_INV },
{ "unalias", parse_unalias, 0 },
{ "unalternative_order",parse_unlist, UL
&AlternativeOrderList },
diff -r bd0ea10f5757 -r b674b979da7e mutt.h
--- a/mutt.h Tue Nov 18 13:54:41 2008 -0600
+++ b/mutt.h Tue Nov 18 13:54:41 2008 -0600
@@ -571,6 +571,7 @@
char *list_post; /* this stores a mailto URL, or nothing */
char *subject;
char *real_subj; /* offset of the real subject */
+ char *disp_subj; /* display subject (modified copy of subject) */
char *message_id;
char *supersedes;
char *date;
diff -r bd0ea10f5757 -r b674b979da7e muttlib.c
--- a/muttlib.c Tue Nov 18 13:54:41 2008 -0600
+++ b/muttlib.c Tue Nov 18 13:54:41 2008 -0600
@@ -670,6 +670,7 @@
FREE (&(*p)->list_post);
FREE (&(*p)->subject);
/* real_subj is just an offset to subject and shouldn't be freed */
+ FREE (&(*p)->disp_subj);
FREE (&(*p)->message_id);
FREE (&(*p)->supersedes);
FREE (&(*p)->date);
@@ -717,8 +718,10 @@
{
base->subject = (*extra)->subject;
base->real_subj = (*extra)->real_subj;
+ base->disp_subj = (*extra)->disp_subj;
(*extra)->subject = NULL;
(*extra)->real_subj = NULL;
+ (*extra)->disp_subj = NULL;
}
/* spam and user headers should never be hashed, and the new envelope may
* have better values. Use new versions regardless. */