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 = cistrstr(m->info[ISubject], s->s) != nil; 106 break; 107 108 case SKBefore: 109 ok = dateCmp(m->unixDate, s) < 0; 110 break; 111 case SKOn: 112 ok = dateCmp(m->unixDate, s) == 0; 113 break; 114 case SKSince: 115 ok = dateCmp(m->unixDate, s) > 0; 116 break; 117 case SKSentBefore: 118 ok = dateCmp(m->info[IDate], s) < 0; 119 break; 120 case SKSentOn: 121 ok = dateCmp(m->info[IDate], s) == 0; 122 break; 123 case SKSentSince: 124 ok = dateCmp(m->info[IDate], s) > 0; 125 break; 126 127 case SKUid: 128 case SKSet: 129 for(ms = s->set; ms != nil; ms = ms->next) 130 if(s->key == SKUid && m->uid >= ms->from && m->uid <= ms->to 131 || s->key == SKSet && m->seq >= ms->from && m->seq <= ms->to) 132 break; 133 ok = ms != nil; 134 break; 135 136 case SKHeader: 137 ok = headerSearch(m, s->hdr, s->s); 138 break; 139 140 case SKBody: 141 case SKText: 142 if(s->key == SKText && cistrstr(m->head.buf, s->s)){ 143 ok = 1; 144 break; 145 } 146 ok = fileSearch(m, "body", s->s); 147 break; 148 } 149 } 150 return ok; 151 } 152 153 static int 154 fileSearch(Msg *m, char *file, char *pat) 155 { 156 char buf[BufSize + 1]; 157 int n, nbuf, npat, fd, ok; 158 159 npat = strlen(pat); 160 if(npat >= BufSize / 2) 161 return 0; 162 163 fd = msgFile(m, file); 164 if(fd < 0) 165 return 0; 166 ok = 0; 167 nbuf = 0; 168 for(;;){ 169 n = read(fd, &buf[nbuf], BufSize - nbuf); 170 if(n <= 0) 171 break; 172 nbuf += n; 173 buf[nbuf] = '\0'; 174 if(cistrstr(buf, pat) != nil){ 175 ok = 1; 176 break; 177 } 178 if(nbuf > npat){ 179 memmove(buf, &buf[nbuf - npat], npat); 180 nbuf = npat; 181 } 182 } 183 close(fd); 184 return ok; 185 } 186 187 static int 188 headerSearch(Msg *m, char *hdr, char *pat) 189 { 190 SList hdrs; 191 char *s, *t; 192 int ok, n; 193 194 n = m->head.size + 3; 195 s = emalloc(n); 196 hdrs.next = nil; 197 hdrs.s = hdr; 198 ok = 0; 199 if(selectFields(s, n, m->head.buf, &hdrs, 1) > 0){ 200 t = strchr(s, ':'); 201 if(t != nil && cistrstr(t+1, pat) != nil) 202 ok = 1; 203 } 204 free(s); 205 return ok; 206 } 207 208 static int 209 addrSearch(MAddr *a, char *s) 210 { 211 char *ok, *addr; 212 213 for(; a != nil; a = a->next){ 214 addr = maddrStr(a); 215 ok = cistrstr(addr, s); 216 free(addr); 217 if(ok != nil) 218 return 1; 219 } 220 return 0; 221 } 222 223 static int 224 dateCmp(char *date, Search *s) 225 { 226 Tm tm; 227 228 date2tm(&tm, date); 229 if(tm.year < s->year) 230 return -1; 231 if(tm.year > s->year) 232 return 1; 233 if(tm.mon < s->mon) 234 return -1; 235 if(tm.mon > s->mon) 236 return 1; 237 if(tm.mday < s->mday) 238 return -1; 239 if(tm.mday > s->mday) 240 return 1; 241 return 0; 242 } 243