#include <u.h>
#include <libc.h>
#include <bio.h>
#include <auth.h>
#include "imap4d.h"
static int dateCmp(char *date, Search *s);
static int addrSearch(MAddr *a, char *s);
static int fileSearch(Msg *m, char *file, char *pat);
static int headerSearch(Msg *m, char *hdr, char *pat);
/*
* 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)
{
MsgSet *ms;
int ok;
if(!msgStruct(m, 1) || m->expunged)
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);
break;
case SKOr:
ok = searchMsg(m, s->left) || searchMsg(m, s->right);
break;
case SKAll:
ok = 1;
break;
case SKAnswered:
ok = (m->flags & MAnswered) == MAnswered;
break;
case SKDeleted:
ok = (m->flags & MDeleted) == MDeleted;
break;
case SKDraft:
ok = (m->flags & MDraft) == MDraft;
break;
case SKFlagged:
ok = (m->flags & MFlagged) == MFlagged;
break;
case SKKeyword:
ok = (m->flags & s->num) == s->num;
break;
case SKNew:
ok = (m->flags & (MRecent|MSeen)) == MRecent;
break;
case SKOld:
ok = (m->flags & MRecent) != MRecent;
break;
case SKRecent:
ok = (m->flags & MRecent) == MRecent;
break;
case SKSeen:
ok = (m->flags & MSeen) == MSeen;
break;
case SKUnanswered:
ok = (m->flags & MAnswered) != MAnswered;
break;
case SKUndeleted:
ok = (m->flags & MDeleted) != MDeleted;
break;
case SKUndraft:
ok = (m->flags & MDraft) != MDraft;
break;
case SKUnflagged:
ok = (m->flags & MFlagged) != MFlagged;
break;
case SKUnkeyword:
ok = (m->flags & s->num) != s->num;
break;
case SKUnseen:
ok = (m->flags & MSeen) != MSeen;
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->unixDate, s) < 0;
break;
case SKOn:
ok = dateCmp(m->unixDate, s) == 0;
break;
case SKSince:
ok = dateCmp(m->unixDate, 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:
case SKSet:
for(ms = s->set; ms != nil; ms = ms->next)
if(s->key == SKUid && m->uid >= ms->from && m->uid <= ms->to
|| s->key == SKSet && m->seq >= ms->from && m->seq <= ms->to)
break;
ok = ms != nil;
break;
case SKHeader:
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;
}
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)
{
SList hdrs;
char *s, *t;
int ok, n;
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;
}
|