1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
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)
</verb></tscreen>
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:
<tscreen><verb>
+~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 Sun Feb 13 09:05:57 2005
+++ pattern.c Sun Feb 13 09:08:06 2005
@@ -48,6 +48,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 },
@@ -1085,6 +1086,16 @@
pat->alladdr, 2, h->env->to, h->env->cc)));
case M_LIST:
return (pat->not ^ (h->env && 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 ^ (h->env && match_threadcomplete(&tmp, flags, ctx, h->thread, 1, 1, 1, 1)));
+ }
case M_PERSONAL_RECIP:
return (pat->not ^ (h->env && match_user (pat->alladdr, h->env->to, h->env->cc)));
case M_PERSONAL_FROM:
|