--- mutt-1.5.20/doc/manual.xml.head 2009-05-30 19:20:08.000000000 +0200
+++ mutt-1.5.20-parentchildmatch/doc/manual.xml.head 2009-07-18 01:09:23.000000000 +0200
@@ -3947,6 +3947,22 @@ With the reset comman
which allows you to reset all variables to their system defaults.
+
+Parent and child match.
+You can tell mutt that the following pattern has to be matched against
+the parent message with < or one of its childs with >.
+This example matches all mails which have at least an unread duplicate
+message:
+
+
+
+
+
+>(~= ~N)
+
+
+
+
diff -urNp mutt-1.5.20/mutt.h mutt-1.5.20-parentchildmatch/mutt.h
--- mutt-1.5.20/mutt.h 2009-06-13 00:15:42.000000000 +0200
+++ mutt-1.5.20-parentchildmatch/mutt.h 2009-07-18 01:14:21.000000000 +0200
@@ -819,6 +819,8 @@ typedef struct pattern_t
unsigned int alladdr : 1;
unsigned int stringmatch : 1;
unsigned int groupmatch : 1;
+ unsigned int parentmatch : 1;
+ unsigned int childsmatch : 1;
unsigned int ign_case : 1; /* ignore case for local stringmatch searches */
int min;
int max;
diff -urNp mutt-1.5.20/pattern.c mutt-1.5.20-parentchildmatch/pattern.c
--- mutt-1.5.20/pattern.c 2009-06-03 22:48:31.000000000 +0200
+++ mutt-1.5.20-parentchildmatch/pattern.c 2009-07-18 01:09:23.000000000 +0200
@@ -45,6 +45,7 @@ static int eat_regexp (pattern_t *pat, B
static int eat_date (pattern_t *pat, BUFFER *, BUFFER *);
static int eat_range (pattern_t *pat, BUFFER *, BUFFER *);
static int patmatch (const pattern_t *pat, const char *buf);
+static int pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx, HEADER *h);
static struct pattern_flags
{
@@ -769,6 +770,8 @@ pattern_t *mutt_pattern_comp (/* const *
pattern_t *last = NULL;
int not = 0;
int alladdr = 0;
+ int parentmatch = 0;
+ int childsmatch = 0;
int or = 0;
int implicit = 1; /* used to detect logical AND operator */
struct pattern_flags *entry;
@@ -793,6 +796,24 @@ pattern_t *mutt_pattern_comp (/* const *
ps.dptr++;
not = !not;
break;
+ case '<':
+ ps.dptr++;
+ if (childsmatch) {
+ snprintf (err->data, err->dsize, _("cannot use both < and > as a pattern modifier"));
+ mutt_pattern_free (&curlist);
+ return NULL;
+ }
+ parentmatch = 1;
+ break;
+ case '>':
+ ps.dptr++;
+ if (parentmatch) {
+ snprintf (err->data, err->dsize, _("cannot use both < and > as a pattern modifier"));
+ mutt_pattern_free (&curlist);
+ return NULL;
+ }
+ childsmatch = 1;
+ break;
case '|':
if (!or)
{
@@ -818,6 +839,8 @@ pattern_t *mutt_pattern_comp (/* const *
implicit = 0;
not = 0;
alladdr = 0;
+ parentmatch = 0;
+ childsmatch = 0;
break;
case '%':
case '=':
@@ -841,8 +864,12 @@ pattern_t *mutt_pattern_comp (/* const *
last = tmp;
tmp->not ^= not;
tmp->alladdr |= alladdr;
+ tmp->parentmatch |= parentmatch;
+ tmp->childsmatch |= childsmatch;
not = 0;
alladdr = 0;
+ parentmatch = 0;
+ childsmatch = 0;
/* compile the sub-expression */
buf = mutt_substrdup (ps.dptr + 1, p);
if ((tmp2 = mutt_pattern_comp (buf, flags, err)) == NULL)
@@ -870,10 +897,14 @@ pattern_t *mutt_pattern_comp (/* const *
tmp = new_pattern ();
tmp->not = not;
tmp->alladdr = alladdr;
+ tmp->parentmatch = parentmatch;
+ tmp->childsmatch = childsmatch;
tmp->stringmatch = (*ps.dptr == '=') ? 1 : 0;
tmp->groupmatch = (*ps.dptr == '%') ? 1 : 0;
not = 0;
alladdr = 0;
+ parentmatch = 0;
+ childsmatch = 0;
if (last)
last->next = tmp;
@@ -939,8 +970,12 @@ pattern_t *mutt_pattern_comp (/* const *
last = tmp;
tmp->not ^= not;
tmp->alladdr |= alladdr;
+ tmp->parentmatch |= parentmatch;
+ tmp->childsmatch |= childsmatch;
not = 0;
alladdr = 0;
+ parentmatch = 0;
+ childsmatch = 0;
ps.dptr = p + 1; /* restore location */
break;
default:
@@ -1081,6 +1116,36 @@ static int match_threadcomplete(struct p
int
mutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx, HEADER *h)
{
+ THREAD *t;
+
+ if (pat->parentmatch) {
+ if (h->thread && h->thread->parent && h->thread->parent->message)
+ return pattern_exec (pat, flags, ctx, h->thread->parent->message);
+ else
+ return pat->not;
+ }
+ if (pat->childsmatch) {
+ if (!h->thread)
+ return pat->not;
+ if (!h->thread->child)
+ return pat->not;
+ t = h->thread->child;
+ while (t->prev)
+ t = t->prev;
+ for (; t; t = t->next) {
+ if (!t->message)
+ continue;
+ if (pattern_exec (pat, flags, ctx, t->message))
+ return !pat->not;
+ }
+ return pat->not;
+ }
+ return pattern_exec (pat, flags, ctx, h);
+}
+
+static int
+pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx, HEADER *h)
+{
switch (pat->op)
{
case M_AND: