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 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 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 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 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 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