1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <auth.h>
5 #include "imap4d.h"
6
7 static int dateCmp(char *date, Search *s);
8 static int addrSearch(MAddr *a, char *s);
9 static int fileSearch(Msg *m, char *file, char *pat);
10 static int headerSearch(Msg *m, char *hdr, char *pat);
11
12 /*
13 * free to exit, parseErr, since called before starting any client reply
14 *
15 * the header and envelope searches should convert mime character set escapes.
16 */
17 int
searchMsg(Msg * m,Search * s)18 searchMsg(Msg *m, Search *s)
19 {
20 MsgSet *ms;
21 int ok;
22
23 if(!msgStruct(m, 1) || m->expunged)
24 return 0;
25 for(ok = 1; ok && s != nil; s = s->next){
26 switch(s->key){
27 default:
28 ok = 0;
29 break;
30 case SKNot:
31 ok = !searchMsg(m, s->left);
32 break;
33 case SKOr:
34 ok = searchMsg(m, s->left) || searchMsg(m, s->right);
35 break;
36 case SKAll:
37 ok = 1;
38 break;
39 case SKAnswered:
40 ok = (m->flags & MAnswered) == MAnswered;
41 break;
42 case SKDeleted:
43 ok = (m->flags & MDeleted) == MDeleted;
44 break;
45 case SKDraft:
46 ok = (m->flags & MDraft) == MDraft;
47 break;
48 case SKFlagged:
49 ok = (m->flags & MFlagged) == MFlagged;
50 break;
51 case SKKeyword:
52 ok = (m->flags & s->num) == s->num;
53 break;
54 case SKNew:
55 ok = (m->flags & (MRecent|MSeen)) == MRecent;
56 break;
57 case SKOld:
58 ok = (m->flags & MRecent) != MRecent;
59 break;
60 case SKRecent:
61 ok = (m->flags & MRecent) == MRecent;
62 break;
63 case SKSeen:
64 ok = (m->flags & MSeen) == MSeen;
65 break;
66 case SKUnanswered:
67 ok = (m->flags & MAnswered) != MAnswered;
68 break;
69 case SKUndeleted:
70 ok = (m->flags & MDeleted) != MDeleted;
71 break;
72 case SKUndraft:
73 ok = (m->flags & MDraft) != MDraft;
74 break;
75 case SKUnflagged:
76 ok = (m->flags & MFlagged) != MFlagged;
77 break;
78 case SKUnkeyword:
79 ok = (m->flags & s->num) != s->num;
80 break;
81 case SKUnseen:
82 ok = (m->flags & MSeen) != MSeen;
83 break;
84
85 case SKLarger:
86 ok = msgSize(m) > s->num;
87 break;
88 case SKSmaller:
89 ok = msgSize(m) < s->num;
90 break;
91
92 case SKBcc:
93 ok = addrSearch(m->bcc, s->s);
94 break;
95 case SKCc:
96 ok = addrSearch(m->cc, s->s);
97 break;
98 case SKFrom:
99 ok = addrSearch(m->from, s->s);
100 break;
101 case SKTo:
102 ok = addrSearch(m->to, s->s);
103 break;
104 case SKSubject:
105 ok = 0;
106 if(m->info[ISubject])
107 ok = cistrstr(m->info[ISubject], s->s) != nil;
108 break;
109
110 case SKBefore:
111 ok = dateCmp(m->unixDate, s) < 0;
112 break;
113 case SKOn:
114 ok = dateCmp(m->unixDate, s) == 0;
115 break;
116 case SKSince:
117 ok = dateCmp(m->unixDate, s) > 0;
118 break;
119 case SKSentBefore:
120 ok = dateCmp(m->info[IDate], s) < 0;
121 break;
122 case SKSentOn:
123 ok = dateCmp(m->info[IDate], s) == 0;
124 break;
125 case SKSentSince:
126 ok = dateCmp(m->info[IDate], s) > 0;
127 break;
128
129 case SKUid:
130 case SKSet:
131 for(ms = s->set; ms != nil; ms = ms->next)
132 if(s->key == SKUid && m->uid >= ms->from && m->uid <= ms->to
133 || s->key == SKSet && m->seq >= ms->from && m->seq <= ms->to)
134 break;
135 ok = ms != nil;
136 break;
137
138 case SKHeader:
139 ok = headerSearch(m, s->hdr, s->s);
140 break;
141
142 case SKBody:
143 case SKText:
144 if(s->key == SKText && cistrstr(m->head.buf, s->s)){
145 ok = 1;
146 break;
147 }
148 ok = fileSearch(m, "body", s->s);
149 break;
150 }
151 }
152 return ok;
153 }
154
155 static int
fileSearch(Msg * m,char * file,char * pat)156 fileSearch(Msg *m, char *file, char *pat)
157 {
158 char buf[BufSize + 1];
159 int n, nbuf, npat, fd, ok;
160
161 npat = strlen(pat);
162 if(npat >= BufSize / 2)
163 return 0;
164
165 fd = msgFile(m, file);
166 if(fd < 0)
167 return 0;
168 ok = 0;
169 nbuf = 0;
170 for(;;){
171 n = read(fd, &buf[nbuf], BufSize - nbuf);
172 if(n <= 0)
173 break;
174 nbuf += n;
175 buf[nbuf] = '\0';
176 if(cistrstr(buf, pat) != nil){
177 ok = 1;
178 break;
179 }
180 if(nbuf > npat){
181 memmove(buf, &buf[nbuf - npat], npat);
182 nbuf = npat;
183 }
184 }
185 close(fd);
186 return ok;
187 }
188
189 static int
headerSearch(Msg * m,char * hdr,char * pat)190 headerSearch(Msg *m, char *hdr, char *pat)
191 {
192 SList hdrs;
193 char *s, *t;
194 int ok, n;
195
196 n = m->head.size + 3;
197 s = emalloc(n);
198 hdrs.next = nil;
199 hdrs.s = hdr;
200 ok = 0;
201 if(selectFields(s, n, m->head.buf, &hdrs, 1) > 0){
202 t = strchr(s, ':');
203 if(t != nil && cistrstr(t+1, pat) != nil)
204 ok = 1;
205 }
206 free(s);
207 return ok;
208 }
209
210 static int
addrSearch(MAddr * a,char * s)211 addrSearch(MAddr *a, char *s)
212 {
213 char *ok, *addr;
214
215 for(; a != nil; a = a->next){
216 addr = maddrStr(a);
217 ok = cistrstr(addr, s);
218 free(addr);
219 if(ok != nil)
220 return 1;
221 }
222 return 0;
223 }
224
225 static int
dateCmp(char * date,Search * s)226 dateCmp(char *date, Search *s)
227 {
228 Tm tm;
229
230 date2tm(&tm, date);
231 if(tm.year < s->year)
232 return -1;
233 if(tm.year > s->year)
234 return 1;
235 if(tm.mon < s->mon)
236 return -1;
237 if(tm.mon > s->mon)
238 return 1;
239 if(tm.mday < s->mday)
240 return -1;
241 if(tm.mday > s->mday)
242 return 1;
243 return 0;
244 }
245