thread_pattern v1 ----------------- Christoph Berg This this first version of the thread_pattern patch for mutt. It is meant to extend Nicolas Rachinsky's threadcomplete patch [1], and so far, I've recycled his match_threadcomplete function. This patch allows to match (tag, limit, search...) mesages that are in threads containing messages matching a certain pattern. The syntax for this is <...>. Examples: * all threads containing messages from you: <~P> * "interesting" threads: The patch homepage is at [2]. Bugs so far: * doesn't work with pseudo threads yet (the threadcomplete patch does, I'll have to invistigate this) * <~d <10> is an invalid pattern Todo: * I don't consider the syntax stable yet, especially with the second bug above. Maybe a prefix for parentheses is more appropriate, e.g. ~(~P). * support for matching sub-threads, parent matching (like the parent_match patch [3]), ancestor matching References: [1] http://www.rachinsky.de/nicolas/mutt.html [3] http://www.df7cb.de/projects/mutt/ [2] http://www.schrab.com/aaron/mutt/ diff -ur ../MUTT/mutt/PATCHES mutt/PATCHES --- ../MUTT/mutt/PATCHES 2002-12-09 18:44:54.000000000 +0100 +++ mutt/PATCHES 2004-02-14 05:11:45.000000000 +0100 @@ -0,0 +1 @@ +patch-1.5.6.cb.thread_pattern.1 diff -ur ../MUTT/mutt/mutt.h mutt/mutt.h --- ../MUTT/mutt/mutt.h 2004-02-13 16:08:32.000000000 +0100 +++ mutt/mutt.h 2004-02-14 05:00:41.000000000 +0100 @@ -209,6 +209,7 @@ /* actions for mutt_pattern_comp/mutt_pattern_exec */ M_AND, M_OR, + M_THREAD, M_TO, M_CC, M_COLLAPSED, diff -ur ../MUTT/mutt/pattern.c mutt/pattern.c --- ../MUTT/mutt/pattern.c 2003-07-24 20:40:50.000000000 +0200 +++ mutt/pattern.c 2004-02-14 05:06:08.000000000 +0100 @@ -659,13 +659,15 @@ static /* const */ char *find_matching_paren (/* const */ char *s) { - int level = 1; + int level = 0; + char left = *s; + char right = left == '(' ? ')' : '>'; for (; *s; s++) { - if (*s == '(') + if (*s == left) level++; - else if (*s == ')') + else if (*s == right) { level--; if (!level) @@ -698,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; @@ -811,10 +813,10 @@ implicit = 1; break; case '(': - p = find_matching_paren (ps.dptr + 1); + p = find_matching_paren (ps.dptr); if (*p != ')') { - snprintf (err->data, err->dsize, _("mismatched parenthesis: %s"), ps.dptr); + snprintf (err->data, err->dsize, _("mismatched parentheses: %s"), ps.dptr); mutt_pattern_free (&curlist); return NULL; } @@ -838,6 +840,37 @@ alladdr = 0; ps.dptr = p + 1; /* restore location */ break; + case '<': + p = find_matching_paren (ps.dptr); + 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; default: snprintf (err->data, err->dsize, _("error in pattern at: %s"), ps.dptr); mutt_pattern_free (&curlist); @@ -943,6 +976,30 @@ 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) + return 0; + 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 @@ -956,6 +1013,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: