/*
* implicitly set the \seen flag. done in a separate pass
* so the .imp file doesn't need to be open while the
* messages are sent to the client.
*/
int
fetchseen(Box *box, Msg *m, int uids, void *vf)
{
Fetch *f;
if(m->expunged)
return uids;
for(f = vf; f != nil; f = f->next){
switch(f->op){
case Frfc822:
case Frfc822text:
case Fbodysect:
msgseen(box, m);
return 1;
}
}
return 1;
}
/*
* fetch messages
*
* imap4 body[] requests get translated to upas/fs files as follows
* body[id.header] == id/rawheader file + extra \r\n
* body[id.text] == id/rawbody
* body[id.mime] == id/mimeheader + extra \r\n
* body[id] === body[id.header] + body[id.text]
*/
int
fetchmsg(Box *, Msg *m, int uids, void *vf)
{
char *sep;
Fetch *f;
Tm tm;
if(m->expunged)
return uids;
for(f = vf; f != nil; f = f->next)
switch(f->op){
case Fflags:
break;
case Fuid:
break;
case Finternaldate:
case Fenvelope:
case Frfc822:
case Frfc822head:
case Frfc822text:
case Frfc822size:
case Fbodysect:
case Fbodypeek:
case Fbody:
case Fbodystruct:
if(!msgstruct(m, 1)){
msgdead(m);
return uids;
}
break;
default:
bye("bad implementation of fetch");
return 0;
}
if(m->expunged)
return uids;
if(vf == 0)
return 1;
/*
* note: it is allowed to send back the responses one at a time
* rather than all together. this is exploited to send flags elsewhere.
*/
Bprint(&bout, "* %ud FETCH (", m->seq);
sep = "";
if(uids){
Bprint(&bout, "UID %ud", m->uid);
sep = " ";
}
for(f = vf; f != nil; f = f->next){
switch(f->op){
default:
bye("bad implementation of fetch");
break;
case Fflags:
Bprint(&bout, "%sFLAGS (", sep);
writeflags(&bout, m, 1);
Bprint(&bout, ")");
break;
case Fuid:
if(uids)
continue;
Bprint(&bout, "%sUID %ud", sep, m->uid);
break;
case Fenvelope:
Bprint(&bout, "%sENVELOPE ", sep);
fetchenvelope(m);
break;
case Finternaldate:
Bprint(&bout, "%sINTERNALDATE %#D", sep, date2tm(&tm, m->unixdate));
break;
case Fbody:
Bprint(&bout, "%sBODY ", sep);
fetchbodystruct(m, &m->head, 0);
break;
case Fbodystruct:
Bprint(&bout, "%sBODYSTRUCTURE ", sep);
fetchbodystruct(m, &m->head, 1);
break;
case Frfc822size:
Bprint(&bout, "%sRFC822.SIZE %ud", sep, msgsize(m));
break;
case Frfc822:
f->part = FPall;
Bprint(&bout, "%sRFC822", sep);
fetchbody(m, f);
break;
case Frfc822head:
f->part = FPhead;
Bprint(&bout, "%sRFC822.HEADER", sep);
fetchbody(m, f);
break;
case Frfc822text:
f->part = FPtext;
Bprint(&bout, "%sRFC822.TEXT", sep);
fetchbody(m, f);
break;
case Fbodysect:
case Fbodypeek:
Bprint(&bout, "%sBODY", sep);
fetchbody(fetchsect(m, f), f);
break;
}
sep = " ";
}
Bprint(&bout, ")\r\n");
/*
* read in each block, convert \n without \r to \r\n.
* this means partial fetch requires fetching everything
* through stop, since we don't know how many \r's will be added
*/
buf[0] = ' ';
for(pos = 0; pos < stop; ){
n = Bufsize;
if(n > stop - pos)
n = stop - pos;
n = read(fd, &buf[1], n);
//ilog("read %ld at %d stop %ld\n", n, pos, stop);
if(n <= 0){
ilog("must fill %ld bytes\n", stop - pos);
fprint(2, "must fill %d bytes\n", stop - pos);
fetchbodyfill(stop - pos);
break;
}
e = &buf[n + 1];
*e = 0;
for(s = &buf[1]; s < e && pos < stop; s = t + 1){
t = memchr(s, '\n', e - s);
if(t == nil)
t = e;
n = t - s;
if(pos < start){
if(pos + n <= start){
s = t;
pos += n;
}else{
s += start - pos;
pos = start;
}
n = t - s;
}
nn = n;
if(pos + nn > stop)
nn = stop - pos;
if(Bwrite(&bout, s, nn) != nn)
writeerr();
//ilog("w %ld at %ld->%ld stop %ld\n", nn, pos, pos + nn, stop);
pos += n;
if(*t == '\n'){
if(t[-1] != '\r'){
if(pos >= start && pos < stop)
Bputc(&bout, '\r');
pos++;
}
if(pos >= start && pos < stop)
Bputc(&bout, '\n');
pos++;
}
}
buf[0] = e[-1];
}
close(fd);
}
/*
* resolve the actual bounds of any partial fetch,
* and print out the bounds & size of string returned
*/
Pair
fetchbodypart(Fetch *f, uint size)
{
uint start, stop;
Pair p;
/*
* something went wrong fetching data
* produce fill bytes for what we've committed to produce
*/
void
fetchbodyfill(uint n)
{
while(n-- > 0)
if(Bputc(&bout, ' ') < 0)
writeerr();
}
/*
* this is so strange: return lengths for a body[text] response,
* except in the case of a multipart message, when return lengths for a body[] response
*/
len = m->size;
if(h == &m->mime)
len += m->head.size;
Bprint(&bout, " %ud", len);
len = m->lines;
if(h == &m->mime)
len += m->head.lines;
/*
* print a list of addresses;
* each address is printed as '(' personalname atdomainlist mboxname hostname ')'
* the atdomainlist is always NIL
*/
int
Bimapaddr(Biobuf *b, Maddr *a)
{
char *host, *sep;
if(a == nil)
return Bprint(b, "NIL");
Bputc(b, '(');
sep = "";
for(; a != nil; a = a->next){
/*
* can't send NIL as hostname, since that is code for a group
*/
host = a->host? a->host: "";
Bprint(b, "%s(%Z NIL %Z %Z)", sep, a->personal, a->box, host);
sep = " ";
}
return Bputc(b, ')');
}