--- doc/manual.xml.head.orig	2017-05-30 19:27:52 UTC
+++ doc/manual.xml.head
@@ -4265,6 +4265,22 @@ variable <quote>all</quote>, which allow
 their system defaults.
 </para>
 
+<para>
+<emphasis role="bold">Parent and child match</emphasis>.
+You can tell mutt that the following pattern has to be matched against
+the parent message with &lt; or one of its childs with &gt;.
+This example matches all mails which have at least an unread duplicate
+message:
+</para>
+
+<para>
+
+<screen>
+>(~= ~N)
+</screen>
+
+</para>
+
 </sect2>
 
 <sect2 id="set-myvar">
--- mutt.h.orig	2017-06-03 23:16:03 UTC
+++ mutt.h
@@ -865,6 +865,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 */
   unsigned int isalias : 1;
   int min;
--- pattern.c.orig	2017-05-30 19:26:40 UTC
+++ pattern.c
@@ -46,6 +46,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, pattern_cache_t *cache);
 
 static const struct pattern_flags
 {
@@ -781,6 +782,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 */
   int isalias = 0;
@@ -810,6 +813,24 @@ pattern_t *mutt_pattern_comp (/* const *
 	ps.dptr++;
 	isalias = !isalias;
 	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)
 	{
@@ -835,6 +856,8 @@ pattern_t *mutt_pattern_comp (/* const *
 	implicit = 0;
 	not = 0;
 	alladdr = 0;
+	parentmatch = 0;
+	childsmatch = 0;
 	isalias = 0;
 	break;
       case '%':
@@ -865,9 +888,13 @@ pattern_t *mutt_pattern_comp (/* const *
 	  last = tmp;
 	  tmp->not ^= not;
 	  tmp->alladdr |= alladdr;
+	  tmp->parentmatch |= parentmatch;
+	  tmp->childsmatch |= childsmatch;
 	  tmp->isalias |= isalias;
 	  not = 0;
 	  alladdr = 0;
+	  parentmatch = 0;
+	  childsmatch = 0;
 	  isalias = 0;
 	  /* compile the sub-expression */
 	  buf = mutt_substrdup (ps.dptr + 1, p);
@@ -896,11 +923,15 @@ pattern_t *mutt_pattern_comp (/* const *
 	tmp = new_pattern ();
 	tmp->not = not;
 	tmp->alladdr = alladdr;
+	tmp->parentmatch = parentmatch;
+	tmp->childsmatch = childsmatch;
 	tmp->isalias = isalias;
         tmp->stringmatch = (*ps.dptr == '=') ? 1 : 0;
         tmp->groupmatch  = (*ps.dptr == '%') ? 1 : 0;
 	not = 0;
 	alladdr = 0;
+	parentmatch = 0;
+	childsmatch = 0;
 	isalias = 0;
 
 	if (last)
@@ -967,9 +998,13 @@ pattern_t *mutt_pattern_comp (/* const *
 	last = tmp;
 	tmp->not ^= not;
 	tmp->alladdr |= alladdr;
+	tmp->parentmatch |= parentmatch;
+	tmp->childsmatch |= childsmatch;
 	tmp->isalias |= isalias;
 	not = 0;
 	alladdr = 0;
+	parentmatch = 0;
+	childsmatch = 0;
 	isalias = 0;
 	ps.dptr = p + 1; /* restore location */
 	break;
@@ -1137,6 +1172,37 @@ int
 mutt_pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx, HEADER *h,
                    pattern_cache_t *cache)
 {
+  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, cache);
+    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, cache))
+	return !pat->not;
+    }
+    return pat->not;
+  }
+  return pattern_exec (pat, flags, ctx, h, cache);
+}
+
+static int
+pattern_exec (struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx, HEADER *h,
+			  pattern_cache_t *cache)
+{
   int result;
   int *cache_entry;
 
