<<< Date Index >>>     <<< Thread Index >>>

[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: &percnt;L for the part of
+the subject to the left of the regex, &percnt;R for the part to the right,
+and &percnt;1, &percnt;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. */