Nico Golde:
[apps/madmutt.git] / pattern.c
index f9c0e11..e07a52c 100644 (file)
--- a/pattern.c
+++ b/pattern.c
  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  */ 
 
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
 #include "mutt.h"
 #include "mapping.h"
 #include "keymap.h"
@@ -58,6 +62,7 @@ Flags[] =
   { 'g', M_CRYPT_SIGN,                 0,              NULL },
   { 'G', M_CRYPT_ENCRYPT,      0,              NULL },
   { 'h', M_HEADER,             M_FULL_MSG,     eat_regexp },
+  { 'H', M_HORMEL,             0,              eat_regexp },
   { 'i', M_ID,                 0,              eat_regexp },
   { 'k', M_PGP_KEY,            0,              NULL },
   { 'L', M_ADDRESS,            0,              eat_regexp },
@@ -85,6 +90,8 @@ Flags[] =
   { 'y', M_XLABEL,             0,              eat_regexp },
   { 'z', M_SIZE,               0,              eat_range },
   { '=', M_DUPLICATED,         0,              NULL },
+  { '$', M_UNREFERENCED,       0,              NULL },
+  { '*', M_REALNAME,           0,              NULL },
   { 0 }
 };
 
@@ -946,6 +953,25 @@ static int match_user (int alladdr, ADDRESS *a1, ADDRESS *a2)
   return alladdr;
 }
 
+/* test if name is considered a real name, i.e. consists of at least 2
+ * space-separated words of which none may end in a dot
+ */
+static int valid_realname (const char* name)
+{
+  const char* p = name;
+  int ret = 0;
+  while (*p)
+  {
+    if (isspace (*p))
+      ret++;
+    else if (*p == '.')
+      /* skip abbr. parts of names (e.g. 'J. User') */
+      ret--;
+    p++;
+  }
+  return (ret >= 1);
+}
+
 /* flags
        M_MATCH_FULL_ADDRESS    match both personal and machine address */
 int
@@ -1005,9 +1031,9 @@ mutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx,
       return (pat->not ^ match_adrlist (pat->rx, flags & M_MATCH_FULL_ADDRESS,
                                        pat->alladdr, 1, h->env->cc));
     case M_SUBJECT:
-      return (pat->not ^ (h->env->subject && regexec (pat->rx, h->env->subject, 0, NULL, 0) == 0));
+      return (pat->not ^ (h->env && h->env->subject && regexec (pat->rx, h->env->subject, 0, NULL, 0) == 0));
     case M_ID:
-      return (pat->not ^ (h->env->message_id && regexec (pat->rx, h->env->message_id, 0, NULL, 0) == 0));
+      return (pat->not ^ (h->env && h->env->message_id && regexec (pat->rx, h->env->message_id, 0, NULL, 0) == 0));
     case M_SCORE:
       return (pat->not ^ (h->score >= pat->min && (pat->max == M_MAXRANGE ||
                                                   h->score <= pat->max)));
@@ -1016,18 +1042,18 @@ mutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx,
     case M_REFERENCE:
       return (pat->not ^ match_reference (pat->rx, h->env->references));
     case M_ADDRESS:
-      return (pat->not ^ match_adrlist (pat->rx, flags & M_MATCH_FULL_ADDRESS,
+      return (pat->not ^ (h->env && match_adrlist (pat->rx, flags & M_MATCH_FULL_ADDRESS,
                                        pat->alladdr, 4, h->env->from,
-                                       h->env->sender, h->env->to, h->env->cc));
+                                       h->env->sender, h->env->to, h->env->cc)));
     case M_RECIPIENT:
-           return (pat->not ^ match_adrlist (pat->rx, flags & M_MATCH_FULL_ADDRESS,
-                                       pat->alladdr, 2, h->env->to, h->env->cc));
+           return (pat->not ^ (h->env && match_adrlist (pat->rx, flags & M_MATCH_FULL_ADDRESS,
+                                       pat->alladdr, 2, h->env->to, h->env->cc)));
     case M_LIST:
-      return (pat->not ^ mutt_is_list_recipient (pat->alladdr, h->env->to, h->env->cc));
+      return (pat->not ^ (h->env && mutt_is_list_recipient (pat->alladdr, h->env->to, h->env->cc)));
     case M_PERSONAL_RECIP:
-      return (pat->not ^ match_user (pat->alladdr, h->env->to, h->env->cc));
+      return (pat->not ^ (h->env && match_user (pat->alladdr, h->env->to, h->env->cc)));
     case M_PERSONAL_FROM:
-      return (pat->not ^ match_user (pat->alladdr, h->env->from, NULL));
+      return (pat->not ^ (h->env && match_user (pat->alladdr, h->env->from, NULL)));
     case M_COLLAPSED:
       return (pat->not ^ (h->collapsed && h->num_hidden > 1));
    case M_CRYPT_SIGN:
@@ -1048,8 +1074,24 @@ mutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx,
      return (pat->not ^ ((h->security & APPLICATION_PGP) && (h->security & PGPKEY)));
     case M_XLABEL:
       return (pat->not ^ (h->env->x_label && regexec (pat->rx, h->env->x_label, 0, NULL, 0) == 0));
+    case M_HORMEL:
+      return (pat->not ^ (h->env->spam && h->env->spam->data && regexec (pat->rx, h->env->spam->data, 0, NULL, 0) == 0));
     case M_DUPLICATED:
       return (pat->not ^ (h->thread && h->thread->duplicate_thread));
+    case M_UNREFERENCED:
+      return (pat->not ^ (h->thread && !h->thread->child));
+    case M_REALNAME:
+      /* realname filter:
+       * we have a match if
+       * - From: matches $alternates
+       * - or we have an alias for current address
+       * - or From: contains valid email address _and_ name has >= 2 fields
+       */
+      return (pat->not ^ (h->env && h->env->from && (
+                            mutt_addr_is_user (h->env->from) ||
+                            (alias_reverse_lookup (h->env->from) != NULL) ||
+                            (h->env->from->personal && valid_realname (h->env->from->personal) && h->env->from->mailbox)
+                            )));
 #ifdef USE_NNTP
     case M_NEWSGROUPS:
       return (pat->not ^ (h->env->newsgroups && regexec (pat->rx, h->env->newsgroups, 0, NULL, 0) == 0));