xref: /plan9/sys/src/cmd/ip/imap4d/search.c (revision 3a32e1046e411eba43a878ebe72e5b0033495136)
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