#include "imap4d.h" static int filesearch(Msg *m, char *file, char *pat) { char buf[Bufsize + 1]; int n, nbuf, npat, fd, ok; npat = strlen(pat); if(npat >= Bufsize/2) return 0; fd = msgfile(m, file); if(fd < 0) return 0; ok = 0; nbuf = 0; for(;;){ n = read(fd, &buf[nbuf], Bufsize - nbuf); if(n <= 0) break; nbuf += n; buf[nbuf] = '\0'; if(cistrstr(buf, pat) != nil){ ok = 1; break; } if(nbuf > npat){ memmove(buf, &buf[nbuf - npat], npat); nbuf = npat; } } close(fd); return ok; } static int headersearch(Msg *m, char *hdr, char *pat) { char *s, *t; int ok, n; Slist hdrs; n = m->head.size + 3; s = emalloc(n); hdrs.next = nil; hdrs.s = hdr; ok = 0; if(selectfields(s, n, m->head.buf, &hdrs, 1) > 0){ t = strchr(s, ':'); if(t != nil && cistrstr(t + 1, pat) != nil) ok = 1; } free(s); return ok; } static int addrsearch(Maddr *a, char *s) { char *ok, *addr; for(; a != nil; a = a->next){ addr = maddrstr(a); ok = cistrstr(addr, s); free(addr); if(ok != nil) return 1; } return 0; } static int datecmp(char *date, Search *s) { Tm tm; date2tm(&tm, date); if(tm.year < s->year) return -1; if(tm.year > s->year) return 1; if(tm.mon < s->mon) return -1; if(tm.mon > s->mon) return 1; if(tm.mday < s->mday) return -1; if(tm.mday > s->mday) return 1; return 0; } enum{ Simp = 0, Sinfo = 1<<0, Sbody = 1<<2, }; int searchld(Search *s) { int r; for(r = 0; (r & Sbody) == 0 && s; s = s->next) switch(s->key){ case SKall: case SKanswered: case SKdeleted: case SKdraft: case SKflagged: case SKkeyword: case SKnew: case SKold: case SKrecent: case SKseen: case SKunanswered: case SKundeleted: case SKundraft: case SKunflagged: case SKunkeyword: case SKunseen: case SKuid: case SKset: break; case SKlarger: case SKsmaller: case SKbcc: case SKcc: case SKfrom: case SKto: case SKsubject: case SKbefore: case SKon: case SKsince: case SKsentbefore: case SKsenton: case SKsentsince: r = Sinfo; break; case SKheader: if(cistrcmp(s->hdr, "message-id") == 0) r = Sinfo; else r = Sbody; break; case SKbody: break; /* msgstruct doesn't do us any good */ case SKtext: default: r = Sbody; break; case SKnot: r = searchld(s->left); break; case SKor: r = searchld(s->left) | searchld(s->right); break; } return 0; } /* important speed hack for apple mail */ int msgidsearch(char *s, char *hdr) { char c; int l, r; l = strlen(s); c = 0; if(s[0] == '<' && s[l-1] == '>'){ l -= 2; s += 1; c = s[l-1]; } r = hdr && strstr(s, hdr) != nil; if(c) s[l-1] = c; return r; } /* * free to exit, parseerr, since called before starting any client reply * * the header and envelope searches should convert mime character set escapes. */ int searchmsg(Msg *m, Search *s, int ld) { uint ok, id; Msgset *ms; if(m->expunged) return 0; if(ld & Sbody){ if(!msgstruct(m, 1)) return 0; }else if (ld & Sinfo){ if(!msginfo(m)) return 0; } for(ok = 1; ok && s != nil; s = s->next){ switch(s->key){ default: ok = 0; break; case SKnot: ok = !searchmsg(m, s->left, ld); break; case SKor: ok = searchmsg(m, s->left, ld) || searchmsg(m, s->right, ld); break; case SKall: ok = 1; break; case SKanswered: ok = (m->flags & Fanswered) == Fanswered; break; case SKdeleted: ok = (m->flags & Fdeleted) == Fdeleted; break; case SKdraft: ok = (m->flags & Fdraft) == Fdraft; break; case SKflagged: ok = (m->flags & Fflagged) == Fflagged; break; case SKkeyword: ok = (m->flags & s->num) == s->num; break; case SKnew: ok = (m->flags & (Frecent|Fseen)) == Frecent; break; case SKold: ok = (m->flags & Frecent) != Frecent; break; case SKrecent: ok = (m->flags & Frecent) == Frecent; break; case SKseen: ok = (m->flags & Fseen) == Fseen; break; case SKunanswered: ok = (m->flags & Fanswered) != Fanswered; break; case SKundeleted: ok = (m->flags & Fdeleted) != Fdeleted; break; case SKundraft: ok = (m->flags & Fdraft) != Fdraft; break; case SKunflagged: ok = (m->flags & Fflagged) != Fflagged; break; case SKunkeyword: ok = (m->flags & s->num) != s->num; break; case SKunseen: ok = (m->flags & Fseen) != Fseen; break; case SKlarger: ok = msgsize(m) > s->num; break; case SKsmaller: ok = msgsize(m) < s->num; break; case SKbcc: ok = addrsearch(m->bcc, s->s); break; case SKcc: ok = addrsearch(m->cc, s->s); break; case SKfrom: ok = addrsearch(m->from, s->s); break; case SKto: ok = addrsearch(m->to, s->s); break; case SKsubject: ok = cistrstr(m->info[Isubject], s->s) != nil; break; case SKbefore: ok = datecmp(m->info[Iunixdate], s) < 0; break; case SKon: ok = datecmp(m->info[Iunixdate], s) == 0; break; case SKsince: ok = datecmp(m->info[Iunixdate], s) > 0; break; case SKsentbefore: ok = datecmp(m->info[Idate], s) < 0; break; case SKsenton: ok = datecmp(m->info[Idate], s) == 0; break; case SKsentsince: ok = datecmp(m->info[Idate], s) > 0; break; case SKuid: id = m->uid; goto set; case SKset: id = m->seq; set: for(ms = s->set; ms != nil; ms = ms->next) if(id >= ms->from && id <= ms->to) break; ok = ms != nil; break; case SKheader: if(cistrcmp(s->hdr, "message-id") == 0) ok = msgidsearch(s->s, m->info[Imessageid]); else ok = headersearch(m, s->hdr, s->s); break; case SKbody: case SKtext: if(s->key == SKtext && cistrstr(m->head.buf, s->s)){ ok = 1; break; } ok = filesearch(m, "body", s->s); break; } } return ok; }