1*7dd7cddfSDavid du Colombier #include <u.h> 2*7dd7cddfSDavid du Colombier #include <libc.h> 3*7dd7cddfSDavid du Colombier #include <bio.h> 4*7dd7cddfSDavid du Colombier #include "imap4d.h" 5*7dd7cddfSDavid du Colombier 6*7dd7cddfSDavid du Colombier char *fetchPartNames[FPMax] = 7*7dd7cddfSDavid du Colombier { 8*7dd7cddfSDavid du Colombier "", 9*7dd7cddfSDavid du Colombier "HEADER", 10*7dd7cddfSDavid du Colombier "HEADER.FIELDS", 11*7dd7cddfSDavid du Colombier "HEADER.FIELDS.NOT", 12*7dd7cddfSDavid du Colombier "MIME", 13*7dd7cddfSDavid du Colombier "TEXT", 14*7dd7cddfSDavid du Colombier }; 15*7dd7cddfSDavid du Colombier 16*7dd7cddfSDavid du Colombier /* 17*7dd7cddfSDavid du Colombier * implicitly set the \seen flag. done in a separate pass 18*7dd7cddfSDavid du Colombier * so the .imp file doesn't need to be open while the 19*7dd7cddfSDavid du Colombier * messages are sent to the client. 20*7dd7cddfSDavid du Colombier */ 21*7dd7cddfSDavid du Colombier int 22*7dd7cddfSDavid du Colombier fetchSeen(Box *box, Msg *m, int uids, void *vf) 23*7dd7cddfSDavid du Colombier { 24*7dd7cddfSDavid du Colombier Fetch *f; 25*7dd7cddfSDavid du Colombier 26*7dd7cddfSDavid du Colombier USED(uids); 27*7dd7cddfSDavid du Colombier 28*7dd7cddfSDavid du Colombier if(m->expunged) 29*7dd7cddfSDavid du Colombier return uids; 30*7dd7cddfSDavid du Colombier for(f = vf; f != nil; f = f->next){ 31*7dd7cddfSDavid du Colombier switch(f->op){ 32*7dd7cddfSDavid du Colombier case FRfc822: 33*7dd7cddfSDavid du Colombier case FRfc822Text: 34*7dd7cddfSDavid du Colombier case FBodySect: 35*7dd7cddfSDavid du Colombier msgSeen(box, m); 36*7dd7cddfSDavid du Colombier goto breakout; 37*7dd7cddfSDavid du Colombier } 38*7dd7cddfSDavid du Colombier } 39*7dd7cddfSDavid du Colombier breakout: 40*7dd7cddfSDavid du Colombier 41*7dd7cddfSDavid du Colombier return 1; 42*7dd7cddfSDavid du Colombier } 43*7dd7cddfSDavid du Colombier 44*7dd7cddfSDavid du Colombier /* 45*7dd7cddfSDavid du Colombier * fetch messages 46*7dd7cddfSDavid du Colombier * 47*7dd7cddfSDavid du Colombier * imap4 body[] requestes get translated to upas/fs files as follows 48*7dd7cddfSDavid du Colombier * body[id.header] == id/rawheader file + extra \r\n 49*7dd7cddfSDavid du Colombier * body[id.text] == id/rawbody 50*7dd7cddfSDavid du Colombier * body[id.mime] == id/mimeheader + extra \r\n 51*7dd7cddfSDavid du Colombier * body[id] === body[id.header] + body[id.text] 52*7dd7cddfSDavid du Colombier */ 53*7dd7cddfSDavid du Colombier int 54*7dd7cddfSDavid du Colombier fetchMsg(Box *box, Msg *m, int uids, void *vf) 55*7dd7cddfSDavid du Colombier { 56*7dd7cddfSDavid du Colombier Tm tm; 57*7dd7cddfSDavid du Colombier Fetch *f; 58*7dd7cddfSDavid du Colombier char *sep; 59*7dd7cddfSDavid du Colombier int todo; 60*7dd7cddfSDavid du Colombier 61*7dd7cddfSDavid du Colombier if(m->expunged) 62*7dd7cddfSDavid du Colombier return uids; 63*7dd7cddfSDavid du Colombier 64*7dd7cddfSDavid du Colombier todo = 0; 65*7dd7cddfSDavid du Colombier for(f = vf; f != nil; f = f->next){ 66*7dd7cddfSDavid du Colombier switch(f->op){ 67*7dd7cddfSDavid du Colombier case FFlags: 68*7dd7cddfSDavid du Colombier /* 69*7dd7cddfSDavid du Colombier * flags get sent with status update 70*7dd7cddfSDavid du Colombier */ 71*7dd7cddfSDavid du Colombier box->sendFlags = 1; 72*7dd7cddfSDavid du Colombier m->sendFlags = 1; 73*7dd7cddfSDavid du Colombier break; 74*7dd7cddfSDavid du Colombier case FUid: 75*7dd7cddfSDavid du Colombier todo = 1; 76*7dd7cddfSDavid du Colombier break; 77*7dd7cddfSDavid du Colombier case FInternalDate: 78*7dd7cddfSDavid du Colombier case FEnvelope: 79*7dd7cddfSDavid du Colombier case FRfc822: 80*7dd7cddfSDavid du Colombier case FRfc822Head: 81*7dd7cddfSDavid du Colombier case FRfc822Size: 82*7dd7cddfSDavid du Colombier case FRfc822Text: 83*7dd7cddfSDavid du Colombier case FBodySect: 84*7dd7cddfSDavid du Colombier case FBodyPeek: 85*7dd7cddfSDavid du Colombier case FBody: 86*7dd7cddfSDavid du Colombier case FBodyStruct: 87*7dd7cddfSDavid du Colombier todo = 1; 88*7dd7cddfSDavid du Colombier if(!msgStruct(m, 1)){ 89*7dd7cddfSDavid du Colombier msgDead(m); 90*7dd7cddfSDavid du Colombier return uids; 91*7dd7cddfSDavid du Colombier } 92*7dd7cddfSDavid du Colombier break; 93*7dd7cddfSDavid du Colombier default: 94*7dd7cddfSDavid du Colombier bye("bad implementation of fetch"); 95*7dd7cddfSDavid du Colombier return 0; 96*7dd7cddfSDavid du Colombier } 97*7dd7cddfSDavid du Colombier } 98*7dd7cddfSDavid du Colombier 99*7dd7cddfSDavid du Colombier if(m->expunged) 100*7dd7cddfSDavid du Colombier return uids; 101*7dd7cddfSDavid du Colombier if(!todo) 102*7dd7cddfSDavid du Colombier return 1; 103*7dd7cddfSDavid du Colombier 104*7dd7cddfSDavid du Colombier /* 105*7dd7cddfSDavid du Colombier * note: it is allowed to send back the responses one at a time 106*7dd7cddfSDavid du Colombier * rather than all together. this is exploited to send flags elsewhere. 107*7dd7cddfSDavid du Colombier */ 108*7dd7cddfSDavid du Colombier Bprint(&bout, "* %lud fetch (", m->seq); 109*7dd7cddfSDavid du Colombier sep = ""; 110*7dd7cddfSDavid du Colombier if(uids){ 111*7dd7cddfSDavid du Colombier Bprint(&bout, "uid %lud", m->uid); 112*7dd7cddfSDavid du Colombier sep = " "; 113*7dd7cddfSDavid du Colombier } 114*7dd7cddfSDavid du Colombier for(f = vf; f != nil; f = f->next){ 115*7dd7cddfSDavid du Colombier switch(f->op){ 116*7dd7cddfSDavid du Colombier default: 117*7dd7cddfSDavid du Colombier bye("bad implementation of fetch"); 118*7dd7cddfSDavid du Colombier break; 119*7dd7cddfSDavid du Colombier case FFlags: 120*7dd7cddfSDavid du Colombier continue; 121*7dd7cddfSDavid du Colombier case FUid: 122*7dd7cddfSDavid du Colombier if(uids) 123*7dd7cddfSDavid du Colombier continue; 124*7dd7cddfSDavid du Colombier Bprint(&bout, "%suid %lud", sep, m->uid); 125*7dd7cddfSDavid du Colombier break; 126*7dd7cddfSDavid du Colombier case FEnvelope: 127*7dd7cddfSDavid du Colombier Bprint(&bout, "%senvelope ", sep); 128*7dd7cddfSDavid du Colombier fetchEnvelope(m); 129*7dd7cddfSDavid du Colombier break; 130*7dd7cddfSDavid du Colombier case FInternalDate: 131*7dd7cddfSDavid du Colombier Bprint(&bout, "%sinternaldate ", sep); 132*7dd7cddfSDavid du Colombier Bimapdate(&bout, date2tm(&tm, m->unixDate)); 133*7dd7cddfSDavid du Colombier break; 134*7dd7cddfSDavid du Colombier case FBody: 135*7dd7cddfSDavid du Colombier Bprint(&bout, "%sbody ", sep); 136*7dd7cddfSDavid du Colombier fetchBodyStruct(m, &m->head, 0); 137*7dd7cddfSDavid du Colombier break; 138*7dd7cddfSDavid du Colombier case FBodyStruct: 139*7dd7cddfSDavid du Colombier Bprint(&bout, "%sbodystructure ", sep); 140*7dd7cddfSDavid du Colombier fetchBodyStruct(m, &m->head, 1); 141*7dd7cddfSDavid du Colombier break; 142*7dd7cddfSDavid du Colombier case FRfc822Size: 143*7dd7cddfSDavid du Colombier Bprint(&bout, "%srfc822.size %lud", sep, msgSize(m)); 144*7dd7cddfSDavid du Colombier break; 145*7dd7cddfSDavid du Colombier case FRfc822: 146*7dd7cddfSDavid du Colombier f->part = FPAll; 147*7dd7cddfSDavid du Colombier Bprint(&bout, "%srfc822", sep); 148*7dd7cddfSDavid du Colombier fetchBody(m, f); 149*7dd7cddfSDavid du Colombier break; 150*7dd7cddfSDavid du Colombier case FRfc822Head: 151*7dd7cddfSDavid du Colombier f->part = FPHead; 152*7dd7cddfSDavid du Colombier Bprint(&bout, "%srfc822.header", sep); 153*7dd7cddfSDavid du Colombier fetchBody(m, f); 154*7dd7cddfSDavid du Colombier break; 155*7dd7cddfSDavid du Colombier case FRfc822Text: 156*7dd7cddfSDavid du Colombier f->part = FPText; 157*7dd7cddfSDavid du Colombier Bprint(&bout, "%srfc822.text", sep); 158*7dd7cddfSDavid du Colombier fetchBody(m, f); 159*7dd7cddfSDavid du Colombier break; 160*7dd7cddfSDavid du Colombier case FBodySect: 161*7dd7cddfSDavid du Colombier case FBodyPeek: 162*7dd7cddfSDavid du Colombier Bprint(&bout, "%sbody", sep); 163*7dd7cddfSDavid du Colombier fetchBody(fetchSect(m, f), f); 164*7dd7cddfSDavid du Colombier break; 165*7dd7cddfSDavid du Colombier } 166*7dd7cddfSDavid du Colombier sep = " "; 167*7dd7cddfSDavid du Colombier } 168*7dd7cddfSDavid du Colombier Bprint(&bout, ")\r\n"); 169*7dd7cddfSDavid du Colombier 170*7dd7cddfSDavid du Colombier return 1; 171*7dd7cddfSDavid du Colombier } 172*7dd7cddfSDavid du Colombier 173*7dd7cddfSDavid du Colombier /* 174*7dd7cddfSDavid du Colombier * print out section, part, headers; 175*7dd7cddfSDavid du Colombier * find and return message section 176*7dd7cddfSDavid du Colombier */ 177*7dd7cddfSDavid du Colombier Msg * 178*7dd7cddfSDavid du Colombier fetchSect(Msg *m, Fetch *f) 179*7dd7cddfSDavid du Colombier { 180*7dd7cddfSDavid du Colombier Bputc(&bout, '['); 181*7dd7cddfSDavid du Colombier BNList(&bout, f->sect, "."); 182*7dd7cddfSDavid du Colombier if(f->part != FPAll){ 183*7dd7cddfSDavid du Colombier if(f->sect != nil) 184*7dd7cddfSDavid du Colombier Bputc(&bout, '.'); 185*7dd7cddfSDavid du Colombier Bprint(&bout, "%s", fetchPartNames[f->part]); 186*7dd7cddfSDavid du Colombier if(f->hdrs != nil){ 187*7dd7cddfSDavid du Colombier Bprint(&bout, " ("); 188*7dd7cddfSDavid du Colombier BSList(&bout, f->hdrs, " "); 189*7dd7cddfSDavid du Colombier Bputc(&bout, ')'); 190*7dd7cddfSDavid du Colombier } 191*7dd7cddfSDavid du Colombier } 192*7dd7cddfSDavid du Colombier Bprint(&bout, "]"); 193*7dd7cddfSDavid du Colombier return findMsgSect(m, f->sect); 194*7dd7cddfSDavid du Colombier } 195*7dd7cddfSDavid du Colombier 196*7dd7cddfSDavid du Colombier /* 197*7dd7cddfSDavid du Colombier * actually return the body pieces 198*7dd7cddfSDavid du Colombier */ 199*7dd7cddfSDavid du Colombier void 200*7dd7cddfSDavid du Colombier fetchBody(Msg *m, Fetch *f) 201*7dd7cddfSDavid du Colombier { 202*7dd7cddfSDavid du Colombier Pair p; 203*7dd7cddfSDavid du Colombier char *s, *t, *e, buf[BufSize + 2]; 204*7dd7cddfSDavid du Colombier ulong n, start, stop, pos; 205*7dd7cddfSDavid du Colombier int fd, nn; 206*7dd7cddfSDavid du Colombier 207*7dd7cddfSDavid du Colombier if(m == nil){ 208*7dd7cddfSDavid du Colombier fetchBodyStr(f, "", 0); 209*7dd7cddfSDavid du Colombier return; 210*7dd7cddfSDavid du Colombier } 211*7dd7cddfSDavid du Colombier switch(f->part){ 212*7dd7cddfSDavid du Colombier case FPHeadFields: 213*7dd7cddfSDavid du Colombier case FPHeadFieldsNot: 214*7dd7cddfSDavid du Colombier n = m->head.size + 3; 215*7dd7cddfSDavid du Colombier s = emalloc(n); 216*7dd7cddfSDavid du Colombier n = selectFields(s, n, m->head.buf, f->hdrs, f->part == FPHeadFields); 217*7dd7cddfSDavid du Colombier fetchBodyStr(f, s, n); 218*7dd7cddfSDavid du Colombier free(s); 219*7dd7cddfSDavid du Colombier return; 220*7dd7cddfSDavid du Colombier case FPHead: 221*7dd7cddfSDavid du Colombier fetchBodyStr(f, m->head.buf, m->head.size); 222*7dd7cddfSDavid du Colombier return; 223*7dd7cddfSDavid du Colombier case FPMime: 224*7dd7cddfSDavid du Colombier fetchBodyStr(f, m->mime.buf, m->mime.size); 225*7dd7cddfSDavid du Colombier return; 226*7dd7cddfSDavid du Colombier case FPAll: 227*7dd7cddfSDavid du Colombier fd = msgFile(m, "rawbody"); 228*7dd7cddfSDavid du Colombier if(fd < 0){ 229*7dd7cddfSDavid du Colombier msgDead(m); 230*7dd7cddfSDavid du Colombier fetchBodyStr(f, "", 0); 231*7dd7cddfSDavid du Colombier return; 232*7dd7cddfSDavid du Colombier } 233*7dd7cddfSDavid du Colombier p = fetchBodyPart(f, msgSize(m)); 234*7dd7cddfSDavid du Colombier start = p.start; 235*7dd7cddfSDavid du Colombier if(start < m->head.size){ 236*7dd7cddfSDavid du Colombier stop = p.stop; 237*7dd7cddfSDavid du Colombier if(stop > m->head.size) 238*7dd7cddfSDavid du Colombier stop = m->head.size; 239*7dd7cddfSDavid du Colombier Bwrite(&bout, &m->head.buf[start], stop - start); 240*7dd7cddfSDavid du Colombier start = 0; 241*7dd7cddfSDavid du Colombier stop = p.stop; 242*7dd7cddfSDavid du Colombier if(stop <= m->head.size){ 243*7dd7cddfSDavid du Colombier close(fd); 244*7dd7cddfSDavid du Colombier return; 245*7dd7cddfSDavid du Colombier } 246*7dd7cddfSDavid du Colombier }else 247*7dd7cddfSDavid du Colombier start -= m->head.size; 248*7dd7cddfSDavid du Colombier stop = p.stop - m->head.size; 249*7dd7cddfSDavid du Colombier break; 250*7dd7cddfSDavid du Colombier case FPText: 251*7dd7cddfSDavid du Colombier fd = msgFile(m, "rawbody"); 252*7dd7cddfSDavid du Colombier if(fd < 0){ 253*7dd7cddfSDavid du Colombier msgDead(m); 254*7dd7cddfSDavid du Colombier fetchBodyStr(f, "", 0); 255*7dd7cddfSDavid du Colombier return; 256*7dd7cddfSDavid du Colombier } 257*7dd7cddfSDavid du Colombier p = fetchBodyPart(f, m->size); 258*7dd7cddfSDavid du Colombier start = p.start; 259*7dd7cddfSDavid du Colombier stop = p.stop; 260*7dd7cddfSDavid du Colombier break; 261*7dd7cddfSDavid du Colombier default: 262*7dd7cddfSDavid du Colombier fetchBodyStr(f, "", 0); 263*7dd7cddfSDavid du Colombier return; 264*7dd7cddfSDavid du Colombier } 265*7dd7cddfSDavid du Colombier 266*7dd7cddfSDavid du Colombier /* 267*7dd7cddfSDavid du Colombier * read in each block, convert \n without \r to \r\n. 268*7dd7cddfSDavid du Colombier * this means partial fetch requires fetching everything 269*7dd7cddfSDavid du Colombier * through stop, since we don't know how many \r's will be added 270*7dd7cddfSDavid du Colombier */ 271*7dd7cddfSDavid du Colombier buf[0] = ' '; 272*7dd7cddfSDavid du Colombier for(pos = 0; pos < stop; ){ 273*7dd7cddfSDavid du Colombier n = BufSize; 274*7dd7cddfSDavid du Colombier if(n > stop - pos) 275*7dd7cddfSDavid du Colombier n = stop - pos; 276*7dd7cddfSDavid du Colombier n = read(fd, &buf[1], n); 277*7dd7cddfSDavid du Colombier if(n <= 0){ 278*7dd7cddfSDavid du Colombier fetchBodyFill(stop - pos); 279*7dd7cddfSDavid du Colombier break; 280*7dd7cddfSDavid du Colombier } 281*7dd7cddfSDavid du Colombier e = &buf[n + 1]; 282*7dd7cddfSDavid du Colombier *e = '\0'; 283*7dd7cddfSDavid du Colombier for(s = &buf[1]; s < e && pos < stop; s = t + 1){ 284*7dd7cddfSDavid du Colombier t = memchr(s, '\n', e - s); 285*7dd7cddfSDavid du Colombier if(t == nil) 286*7dd7cddfSDavid du Colombier t = e; 287*7dd7cddfSDavid du Colombier n = t - s; 288*7dd7cddfSDavid du Colombier if(pos < start){ 289*7dd7cddfSDavid du Colombier if(pos + n <= start){ 290*7dd7cddfSDavid du Colombier s = t; 291*7dd7cddfSDavid du Colombier pos += n; 292*7dd7cddfSDavid du Colombier }else{ 293*7dd7cddfSDavid du Colombier s += start - pos; 294*7dd7cddfSDavid du Colombier pos = start; 295*7dd7cddfSDavid du Colombier } 296*7dd7cddfSDavid du Colombier n = t - s; 297*7dd7cddfSDavid du Colombier } 298*7dd7cddfSDavid du Colombier nn = n; 299*7dd7cddfSDavid du Colombier if(pos + nn > stop) 300*7dd7cddfSDavid du Colombier nn = stop - pos; 301*7dd7cddfSDavid du Colombier if(Bwrite(&bout, s, nn) != nn) 302*7dd7cddfSDavid du Colombier writeErr(); 303*7dd7cddfSDavid du Colombier pos += n; 304*7dd7cddfSDavid du Colombier if(*t == '\n'){ 305*7dd7cddfSDavid du Colombier if(t[-1] != '\r'){ 306*7dd7cddfSDavid du Colombier if(pos >= start && pos < stop) 307*7dd7cddfSDavid du Colombier Bputc(&bout, '\r'); 308*7dd7cddfSDavid du Colombier pos++; 309*7dd7cddfSDavid du Colombier } 310*7dd7cddfSDavid du Colombier if(pos >= start && pos < stop) 311*7dd7cddfSDavid du Colombier Bputc(&bout, '\n'); 312*7dd7cddfSDavid du Colombier pos++; 313*7dd7cddfSDavid du Colombier } 314*7dd7cddfSDavid du Colombier } 315*7dd7cddfSDavid du Colombier buf[0] = e[-1]; 316*7dd7cddfSDavid du Colombier } 317*7dd7cddfSDavid du Colombier close(fd); 318*7dd7cddfSDavid du Colombier } 319*7dd7cddfSDavid du Colombier 320*7dd7cddfSDavid du Colombier /* 321*7dd7cddfSDavid du Colombier * resolve the actual bounds of any partial fetch, 322*7dd7cddfSDavid du Colombier * and print out the bounds & size of string returned 323*7dd7cddfSDavid du Colombier */ 324*7dd7cddfSDavid du Colombier Pair 325*7dd7cddfSDavid du Colombier fetchBodyPart(Fetch *f, ulong size) 326*7dd7cddfSDavid du Colombier { 327*7dd7cddfSDavid du Colombier Pair p; 328*7dd7cddfSDavid du Colombier ulong start, stop; 329*7dd7cddfSDavid du Colombier 330*7dd7cddfSDavid du Colombier start = 0; 331*7dd7cddfSDavid du Colombier stop = size; 332*7dd7cddfSDavid du Colombier if(f->partial){ 333*7dd7cddfSDavid du Colombier start = f->start; 334*7dd7cddfSDavid du Colombier if(start > size) 335*7dd7cddfSDavid du Colombier start = size; 336*7dd7cddfSDavid du Colombier stop = start + f->size; 337*7dd7cddfSDavid du Colombier if(stop > size) 338*7dd7cddfSDavid du Colombier stop = size; 339*7dd7cddfSDavid du Colombier Bprint(&bout, "<%lud>", start); 340*7dd7cddfSDavid du Colombier } 341*7dd7cddfSDavid du Colombier Bprint(&bout, " {%lud}\r\n", stop - start); 342*7dd7cddfSDavid du Colombier p.start = start; 343*7dd7cddfSDavid du Colombier p.stop = stop; 344*7dd7cddfSDavid du Colombier return p; 345*7dd7cddfSDavid du Colombier } 346*7dd7cddfSDavid du Colombier 347*7dd7cddfSDavid du Colombier /* 348*7dd7cddfSDavid du Colombier * something went wrong fetching data 349*7dd7cddfSDavid du Colombier * produce fill bytes for what we've committed to produce 350*7dd7cddfSDavid du Colombier */ 351*7dd7cddfSDavid du Colombier void 352*7dd7cddfSDavid du Colombier fetchBodyFill(ulong n) 353*7dd7cddfSDavid du Colombier { 354*7dd7cddfSDavid du Colombier while(n-- > 0) 355*7dd7cddfSDavid du Colombier if(Bputc(&bout, ' ') < 0) 356*7dd7cddfSDavid du Colombier writeErr(); 357*7dd7cddfSDavid du Colombier } 358*7dd7cddfSDavid du Colombier 359*7dd7cddfSDavid du Colombier /* 360*7dd7cddfSDavid du Colombier * return a simple string 361*7dd7cddfSDavid du Colombier */ 362*7dd7cddfSDavid du Colombier void 363*7dd7cddfSDavid du Colombier fetchBodyStr(Fetch *f, char *buf, ulong size) 364*7dd7cddfSDavid du Colombier { 365*7dd7cddfSDavid du Colombier Pair p; 366*7dd7cddfSDavid du Colombier 367*7dd7cddfSDavid du Colombier p = fetchBodyPart(f, size); 368*7dd7cddfSDavid du Colombier Bwrite(&bout, &buf[p.start], p.stop-p.start); 369*7dd7cddfSDavid du Colombier } 370*7dd7cddfSDavid du Colombier 371*7dd7cddfSDavid du Colombier /* 372*7dd7cddfSDavid du Colombier * find the numbered sub-part of the message 373*7dd7cddfSDavid du Colombier */ 374*7dd7cddfSDavid du Colombier Msg* 375*7dd7cddfSDavid du Colombier findMsgSect(Msg *m, NList *sect) 376*7dd7cddfSDavid du Colombier { 377*7dd7cddfSDavid du Colombier ulong id; 378*7dd7cddfSDavid du Colombier 379*7dd7cddfSDavid du Colombier for(; sect != nil; sect = sect->next){ 380*7dd7cddfSDavid du Colombier id = sect->n; 381*7dd7cddfSDavid du Colombier for(m = m->kids; m != nil; m = m->next) 382*7dd7cddfSDavid du Colombier if(m->id == id) 383*7dd7cddfSDavid du Colombier break; 384*7dd7cddfSDavid du Colombier if(m == nil) 385*7dd7cddfSDavid du Colombier return nil; 386*7dd7cddfSDavid du Colombier } 387*7dd7cddfSDavid du Colombier return m; 388*7dd7cddfSDavid du Colombier } 389*7dd7cddfSDavid du Colombier 390*7dd7cddfSDavid du Colombier void 391*7dd7cddfSDavid du Colombier fetchEnvelope(Msg *m) 392*7dd7cddfSDavid du Colombier { 393*7dd7cddfSDavid du Colombier Tm tm; 394*7dd7cddfSDavid du Colombier 395*7dd7cddfSDavid du Colombier Bputc(&bout, '('); 396*7dd7cddfSDavid du Colombier Brfc822date(&bout, date2tm(&tm, m->info[IDate])); 397*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 398*7dd7cddfSDavid du Colombier Bimapstr(&bout, m->info[ISubject]); 399*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 400*7dd7cddfSDavid du Colombier Bimapaddr(&bout, m->from); 401*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 402*7dd7cddfSDavid du Colombier Bimapaddr(&bout, m->sender); 403*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 404*7dd7cddfSDavid du Colombier Bimapaddr(&bout, m->replyTo); 405*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 406*7dd7cddfSDavid du Colombier Bimapaddr(&bout, m->to); 407*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 408*7dd7cddfSDavid du Colombier Bimapaddr(&bout, m->cc); 409*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 410*7dd7cddfSDavid du Colombier Bimapaddr(&bout, m->bcc); 411*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 412*7dd7cddfSDavid du Colombier Bimapstr(&bout, m->info[IInReplyTo]); 413*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 414*7dd7cddfSDavid du Colombier Bimapstr(&bout, m->info[IMessageId]); 415*7dd7cddfSDavid du Colombier Bputc(&bout, ')'); 416*7dd7cddfSDavid du Colombier } 417*7dd7cddfSDavid du Colombier 418*7dd7cddfSDavid du Colombier void 419*7dd7cddfSDavid du Colombier fetchBodyStruct(Msg *m, Header *h, int extensions) 420*7dd7cddfSDavid du Colombier { 421*7dd7cddfSDavid du Colombier Msg *k; 422*7dd7cddfSDavid du Colombier ulong len; 423*7dd7cddfSDavid du Colombier 424*7dd7cddfSDavid du Colombier if(msgIsMulti(h)){ 425*7dd7cddfSDavid du Colombier Bputc(&bout, '('); 426*7dd7cddfSDavid du Colombier for(k = m->kids; k != nil; k = k->next) 427*7dd7cddfSDavid du Colombier fetchBodyStruct(k, &k->mime, extensions); 428*7dd7cddfSDavid du Colombier 429*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 430*7dd7cddfSDavid du Colombier Bimapstr(&bout, h->type->t); 431*7dd7cddfSDavid du Colombier 432*7dd7cddfSDavid du Colombier if(extensions){ 433*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 434*7dd7cddfSDavid du Colombier BimapMimeParams(&bout, h->type->next); 435*7dd7cddfSDavid du Colombier fetchStructExt(h); 436*7dd7cddfSDavid du Colombier } 437*7dd7cddfSDavid du Colombier 438*7dd7cddfSDavid du Colombier Bputc(&bout, ')'); 439*7dd7cddfSDavid du Colombier return; 440*7dd7cddfSDavid du Colombier } 441*7dd7cddfSDavid du Colombier 442*7dd7cddfSDavid du Colombier Bputc(&bout, '('); 443*7dd7cddfSDavid du Colombier if(h->type != nil){ 444*7dd7cddfSDavid du Colombier Bimapstr(&bout, h->type->s); 445*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 446*7dd7cddfSDavid du Colombier Bimapstr(&bout, h->type->t); 447*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 448*7dd7cddfSDavid du Colombier BimapMimeParams(&bout, h->type->next); 449*7dd7cddfSDavid du Colombier }else 450*7dd7cddfSDavid du Colombier Bprint(&bout, "\"text\" \"plain\" NIL"); 451*7dd7cddfSDavid du Colombier 452*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 453*7dd7cddfSDavid du Colombier if(h->id != nil) 454*7dd7cddfSDavid du Colombier Bimapstr(&bout, h->id->s); 455*7dd7cddfSDavid du Colombier else 456*7dd7cddfSDavid du Colombier Bprint(&bout, "NIL"); 457*7dd7cddfSDavid du Colombier 458*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 459*7dd7cddfSDavid du Colombier if(h->description != nil) 460*7dd7cddfSDavid du Colombier Bimapstr(&bout, h->description->s); 461*7dd7cddfSDavid du Colombier else 462*7dd7cddfSDavid du Colombier Bprint(&bout, "NIL"); 463*7dd7cddfSDavid du Colombier 464*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 465*7dd7cddfSDavid du Colombier if(h->encoding != nil) 466*7dd7cddfSDavid du Colombier Bimapstr(&bout, h->encoding->s); 467*7dd7cddfSDavid du Colombier else 468*7dd7cddfSDavid du Colombier Bprint(&bout, "NIL"); 469*7dd7cddfSDavid du Colombier 470*7dd7cddfSDavid du Colombier /* 471*7dd7cddfSDavid du Colombier * this is so strange: return lengths for a body[text] response, 472*7dd7cddfSDavid du Colombier * except in the case of a multipart message, when return lengths for a body[] repsonse 473*7dd7cddfSDavid du Colombier */ 474*7dd7cddfSDavid du Colombier len = m->size; 475*7dd7cddfSDavid du Colombier if(h == &m->mime) 476*7dd7cddfSDavid du Colombier len += m->head.size; 477*7dd7cddfSDavid du Colombier Bprint(&bout, " %lud", len); 478*7dd7cddfSDavid du Colombier 479*7dd7cddfSDavid du Colombier len = m->lines; 480*7dd7cddfSDavid du Colombier if(h == &m->mime) 481*7dd7cddfSDavid du Colombier len += m->head.lines; 482*7dd7cddfSDavid du Colombier 483*7dd7cddfSDavid du Colombier if(h->type == nil || cistrcmp(h->type->s, "text") == 0){ 484*7dd7cddfSDavid du Colombier Bprint(&bout, " %lud", len); 485*7dd7cddfSDavid du Colombier }else if(msgIsRfc822(h)){ 486*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 487*7dd7cddfSDavid du Colombier k = m; 488*7dd7cddfSDavid du Colombier if(h != &m->mime) 489*7dd7cddfSDavid du Colombier k = m->kids; 490*7dd7cddfSDavid du Colombier if(k == nil) 491*7dd7cddfSDavid du Colombier Bprint(&bout, "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) (\"text\" \"plain\" NIL NIL NIL NIL 0 0) 0"); 492*7dd7cddfSDavid du Colombier else{ 493*7dd7cddfSDavid du Colombier fetchEnvelope(k); 494*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 495*7dd7cddfSDavid du Colombier fetchBodyStruct(k, &k->head, extensions); 496*7dd7cddfSDavid du Colombier Bprint(&bout, " %lud", len); 497*7dd7cddfSDavid du Colombier } 498*7dd7cddfSDavid du Colombier } 499*7dd7cddfSDavid du Colombier 500*7dd7cddfSDavid du Colombier if(extensions){ 501*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 502*7dd7cddfSDavid du Colombier 503*7dd7cddfSDavid du Colombier /* 504*7dd7cddfSDavid du Colombier * don't have the md5 laying around, 505*7dd7cddfSDavid du Colombier * since the header & body have added newlines. 506*7dd7cddfSDavid du Colombier */ 507*7dd7cddfSDavid du Colombier Bprint(&bout, "NIL"); 508*7dd7cddfSDavid du Colombier 509*7dd7cddfSDavid du Colombier fetchStructExt(h); 510*7dd7cddfSDavid du Colombier } 511*7dd7cddfSDavid du Colombier Bputc(&bout, ')'); 512*7dd7cddfSDavid du Colombier } 513*7dd7cddfSDavid du Colombier 514*7dd7cddfSDavid du Colombier /* 515*7dd7cddfSDavid du Colombier * common part of bodystructure extensions 516*7dd7cddfSDavid du Colombier */ 517*7dd7cddfSDavid du Colombier void 518*7dd7cddfSDavid du Colombier fetchStructExt(Header *h) 519*7dd7cddfSDavid du Colombier { 520*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 521*7dd7cddfSDavid du Colombier if(h->disposition != nil){ 522*7dd7cddfSDavid du Colombier Bputc(&bout, '('); 523*7dd7cddfSDavid du Colombier Bimapstr(&bout, h->disposition->s); 524*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 525*7dd7cddfSDavid du Colombier BimapMimeParams(&bout, h->disposition->next); 526*7dd7cddfSDavid du Colombier Bputc(&bout, ')'); 527*7dd7cddfSDavid du Colombier }else 528*7dd7cddfSDavid du Colombier Bprint(&bout, "NIL"); 529*7dd7cddfSDavid du Colombier Bputc(&bout, ' '); 530*7dd7cddfSDavid du Colombier if(h->language != nil){ 531*7dd7cddfSDavid du Colombier if(h->language->next != nil) 532*7dd7cddfSDavid du Colombier BimapMimeParams(&bout, h->language->next); 533*7dd7cddfSDavid du Colombier else 534*7dd7cddfSDavid du Colombier Bimapstr(&bout, h->language->s); 535*7dd7cddfSDavid du Colombier }else 536*7dd7cddfSDavid du Colombier Bprint(&bout, "NIL"); 537*7dd7cddfSDavid du Colombier } 538*7dd7cddfSDavid du Colombier 539*7dd7cddfSDavid du Colombier int 540*7dd7cddfSDavid du Colombier BimapMimeParams(Biobuf *b, MimeHdr *mh) 541*7dd7cddfSDavid du Colombier { 542*7dd7cddfSDavid du Colombier char *sep; 543*7dd7cddfSDavid du Colombier int n; 544*7dd7cddfSDavid du Colombier 545*7dd7cddfSDavid du Colombier if(mh == nil) 546*7dd7cddfSDavid du Colombier return Bprint(b, "NIL"); 547*7dd7cddfSDavid du Colombier 548*7dd7cddfSDavid du Colombier n = Bputc(b, '('); 549*7dd7cddfSDavid du Colombier 550*7dd7cddfSDavid du Colombier sep = ""; 551*7dd7cddfSDavid du Colombier for(; mh != nil; mh = mh->next){ 552*7dd7cddfSDavid du Colombier n += Bprint(b, sep); 553*7dd7cddfSDavid du Colombier n += Bimapstr(b, mh->s); 554*7dd7cddfSDavid du Colombier n += Bputc(b, ' '); 555*7dd7cddfSDavid du Colombier n += Bimapstr(b, mh->t); 556*7dd7cddfSDavid du Colombier sep = " "; 557*7dd7cddfSDavid du Colombier } 558*7dd7cddfSDavid du Colombier 559*7dd7cddfSDavid du Colombier n += Bputc(b, ')'); 560*7dd7cddfSDavid du Colombier return n; 561*7dd7cddfSDavid du Colombier } 562*7dd7cddfSDavid du Colombier 563*7dd7cddfSDavid du Colombier /* 564*7dd7cddfSDavid du Colombier * print a list of addresses; 565*7dd7cddfSDavid du Colombier * each address is printed as '(' personalName AtDomainList mboxName hostName ')' 566*7dd7cddfSDavid du Colombier * the AtDomainList is always NIL 567*7dd7cddfSDavid du Colombier */ 568*7dd7cddfSDavid du Colombier int 569*7dd7cddfSDavid du Colombier Bimapaddr(Biobuf *b, MAddr *a) 570*7dd7cddfSDavid du Colombier { 571*7dd7cddfSDavid du Colombier char *host, *sep; 572*7dd7cddfSDavid du Colombier int n; 573*7dd7cddfSDavid du Colombier 574*7dd7cddfSDavid du Colombier if(a == nil) 575*7dd7cddfSDavid du Colombier return Bprint(b, "NIL"); 576*7dd7cddfSDavid du Colombier 577*7dd7cddfSDavid du Colombier n = Bputc(b, '('); 578*7dd7cddfSDavid du Colombier sep = ""; 579*7dd7cddfSDavid du Colombier for(; a != nil; a = a->next){ 580*7dd7cddfSDavid du Colombier n += Bprint(b, "%s(", sep); 581*7dd7cddfSDavid du Colombier n += Bimapstr(b, a->personal); 582*7dd7cddfSDavid du Colombier n += Bprint(b," NIL "); 583*7dd7cddfSDavid du Colombier n += Bimapstr(b, a->box); 584*7dd7cddfSDavid du Colombier n += Bputc(b, ' '); 585*7dd7cddfSDavid du Colombier 586*7dd7cddfSDavid du Colombier /* 587*7dd7cddfSDavid du Colombier * can't send NIL as hostName, since that is code for a group 588*7dd7cddfSDavid du Colombier */ 589*7dd7cddfSDavid du Colombier host = a->host; 590*7dd7cddfSDavid du Colombier if(host == nil) 591*7dd7cddfSDavid du Colombier host = ""; 592*7dd7cddfSDavid du Colombier n += Bimapstr(b, host); 593*7dd7cddfSDavid du Colombier 594*7dd7cddfSDavid du Colombier n += Bputc(b, ')'); 595*7dd7cddfSDavid du Colombier sep = " "; 596*7dd7cddfSDavid du Colombier } 597*7dd7cddfSDavid du Colombier n += Bputc(b, ')'); 598*7dd7cddfSDavid du Colombier return n; 599*7dd7cddfSDavid du Colombier } 600