diff -Nru a/PATCHES b/PATCHES --- PATCHES +++ PATCHES @@ -0,0 +1 @@ +patch-1.5.6+20040904.tg.mutt-thread.3 diff -Nru a/doc/manual.sgml.head b/doc/manual.sgml.head --- doc/manual.sgml.head.orig Fri Feb 4 08:15:50 2005 +++ doc/manual.sgml.head Fri Feb 4 08:19:51 2005 @@ -1903,6 +1903,8 @@ ~z [MIN]-[MAX] messages with a size in the range MIN to MAX *) ~= duplicated messages (see $duplicate_threads) ~$ unreferenced messages (requires threaded view) +~(PATTERN) messages in threads containing messages matching a certain + pattern, e.g. all threads containing messages from you: ~(~P) Where EXPR, USER, ID, and SUBJECT are diff -Nru a/mutt.h b/mutt.h --- mutt.h 2004-07-24 12:27:21 +02:00 +++ mutt.h 2004-09-04 12:36:18 +02:00 @@ -211,6 +211,7 @@ /* actions for mutt_pattern_comp/mutt_pattern_exec */ M_AND, M_OR, + M_THREAD, M_TO, M_CC, M_COLLAPSED, diff -Nru a/pattern.c b/pattern.c --- pattern.c 2004-07-24 12:27:23 +02:00 +++ pattern.c 2004-09-04 12:37:52 +02:00 @@ -700,7 +700,7 @@ pattern_t *mutt_pattern_comp (/* const */ char *s, int flags, BUFFER *err) { pattern_t *curlist = NULL; - pattern_t *tmp; + pattern_t *tmp, *tmp2; pattern_t *last = NULL; int not = 0; int alladdr = 0; @@ -755,6 +755,39 @@ alladdr = 0; break; case '~': + if (*(ps.dptr + 1) == '(') { + ps.dptr ++; /* skip ~ */ + p = find_matching_paren (ps.dptr + 1); + if (*p != ')') + { + snprintf (err->data, err->dsize, _("mismatched brackets: %s"), ps.dptr); + mutt_pattern_free (&curlist); + return NULL; + } + tmp = new_pattern (); + tmp->op = M_THREAD; + if (last) + last->next = tmp; + else + curlist = tmp; + last = tmp; + tmp->not ^= not; + tmp->alladdr |= alladdr; + not = 0; + alladdr = 0; + /* compile the sub-expression */ + buf = mutt_substrdup (ps.dptr + 1, p); + if ((tmp2 = mutt_pattern_comp (buf, flags, err)) == NULL) + { + FREE (&buf); + mutt_pattern_free (&curlist); + return NULL; + } + FREE (&buf); + tmp->child = tmp2; + ps.dptr = p + 1; /* restore location */ + break; + } if (implicit && or) { /* A | B & C == (A | B) & C */ @@ -945,6 +978,29 @@ return alladdr; } +static int match_threadcomplete(struct pattern_t *pat, pattern_exec_flag flags, CONTEXT *ctx, THREAD *t,int left,int up,int right,int down) +{ + int a; + HEADER *h; + + if(!t) + return 0; + h = t->message; + if(h) + if(mutt_pattern_exec(pat, flags, ctx, h)) + return 1; + + if(up && (a=match_threadcomplete(pat, flags, ctx, t->parent,1,1,1,0))) + return a; + if(right && t->parent && (a=match_threadcomplete(pat, flags, ctx, t->next,0,0,1,1))) + return a; + if(left && t->parent && (a=match_threadcomplete(pat, flags, ctx, t->prev,1,0,0,1))) + return a; + if(down && (a=match_threadcomplete(pat, flags, ctx, t->child,1,0,1,1))) + return a; + return 0; +} + /* flags M_MATCH_FULL_ADDRESS match both personal and machine address */ int @@ -958,6 +1014,8 @@ return (pat->not ^ (perform_and (pat->child, flags, ctx, h) > 0)); case M_OR: return (pat->not ^ (perform_or (pat->child, flags, ctx, h) > 0)); + case M_THREAD: + return (pat->not ^ match_threadcomplete(pat->child, flags, ctx, h->thread, 1, 1, 1, 1)); case M_ALL: return (!pat->not); case M_EXPIRED: --- doc/manual.sgml.head.orig2 Mon Sep 6 09:24:16 2004 +++ doc/manual.sgml.head Mon Sep 6 09:25:41 2004 @@ -1773,6 +1773,8 @@ messages: +~a messages in threads that contain at least one tagged message; + this is the same as ~(~T) [see below for ~(..)] ~A all messages ~b EXPR messages which contain EXPR in the message body ~B EXPR messages which contain EXPR in the whole message --- mutt.h.orig2 Mon Sep 6 09:24:17 2004 +++ mutt.h Mon Sep 6 09:27:04 2004 @@ -212,6 +212,7 @@ M_LIMIT, M_EXPIRED, M_SUPERSEDED, + M_THREADCOMPLETE, /* actions for mutt_pattern_comp/mutt_pattern_exec */ M_AND, --- pattern.c.orig2 Mon Sep 6 09:24:10 2004 +++ pattern.c Mon Sep 6 09:30:02 2004 @@ -44,6 +44,7 @@ } Flags[] = { + { 'a', M_THREADCOMPLETE, 0, NULL }, { 'A', M_ALL, 0, NULL }, { 'b', M_BODY, M_FULL_MSG, eat_regexp }, { 'B', M_WHOLE_MSG, M_FULL_MSG, eat_regexp }, @@ -1024,6 +1083,16 @@ 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)); + case M_THREADCOMPLETE: + { static pattern_t tmp; + static short pattern_set = 0; + if(! pattern_set) { + memset (&tmp, 0, sizeof (tmp)); + tmp.op = M_TAG; + pattern_set = 1; + } + return (pat->not ^ match_threadcomplete(&tmp, flags, ctx, h->thread, 1, 1, 1, 1)); + } case M_PERSONAL_RECIP: return (pat->not ^ match_user (pat->alladdr, h->env->to, h->env->cc)); case M_PERSONAL_FROM: