17dd7cddfSDavid du Colombier #include <u.h> 27dd7cddfSDavid du Colombier #include <libc.h> 37dd7cddfSDavid du Colombier #include <bio.h> 4*9a747e4fSDavid du Colombier #include <auth.h> 57dd7cddfSDavid du Colombier #include "imap4d.h" 67dd7cddfSDavid du Colombier 77dd7cddfSDavid du Colombier char *fetchPartNames[FPMax] = 87dd7cddfSDavid du Colombier { 97dd7cddfSDavid du Colombier "", 107dd7cddfSDavid du Colombier "HEADER", 117dd7cddfSDavid du Colombier "HEADER.FIELDS", 127dd7cddfSDavid du Colombier "HEADER.FIELDS.NOT", 137dd7cddfSDavid du Colombier "MIME", 147dd7cddfSDavid du Colombier "TEXT", 157dd7cddfSDavid du Colombier }; 167dd7cddfSDavid du Colombier 177dd7cddfSDavid du Colombier /* 187dd7cddfSDavid du Colombier * implicitly set the \seen flag. done in a separate pass 197dd7cddfSDavid du Colombier * so the .imp file doesn't need to be open while the 207dd7cddfSDavid du Colombier * messages are sent to the client. 217dd7cddfSDavid du Colombier */ 227dd7cddfSDavid du Colombier int 237dd7cddfSDavid du Colombier fetchSeen(Box *box, Msg *m, int uids, void *vf) 247dd7cddfSDavid du Colombier { 257dd7cddfSDavid du Colombier Fetch *f; 267dd7cddfSDavid du Colombier 277dd7cddfSDavid du Colombier USED(uids); 287dd7cddfSDavid du Colombier 297dd7cddfSDavid du Colombier if(m->expunged) 307dd7cddfSDavid du Colombier return uids; 317dd7cddfSDavid du Colombier for(f = vf; f != nil; f = f->next){ 327dd7cddfSDavid du Colombier switch(f->op){ 337dd7cddfSDavid du Colombier case FRfc822: 347dd7cddfSDavid du Colombier case FRfc822Text: 357dd7cddfSDavid du Colombier case FBodySect: 367dd7cddfSDavid du Colombier msgSeen(box, m); 377dd7cddfSDavid du Colombier goto breakout; 387dd7cddfSDavid du Colombier } 397dd7cddfSDavid du Colombier } 407dd7cddfSDavid du Colombier breakout: 417dd7cddfSDavid du Colombier 427dd7cddfSDavid du Colombier return 1; 437dd7cddfSDavid du Colombier } 447dd7cddfSDavid du Colombier 457dd7cddfSDavid du Colombier /* 467dd7cddfSDavid du Colombier * fetch messages 477dd7cddfSDavid du Colombier * 487dd7cddfSDavid du Colombier * imap4 body[] requestes get translated to upas/fs files as follows 497dd7cddfSDavid du Colombier * body[id.header] == id/rawheader file + extra \r\n 507dd7cddfSDavid du Colombier * body[id.text] == id/rawbody 517dd7cddfSDavid du Colombier * body[id.mime] == id/mimeheader + extra \r\n 527dd7cddfSDavid du Colombier * body[id] === body[id.header] + body[id.text] 537dd7cddfSDavid du Colombier */ 547dd7cddfSDavid du Colombier int 557dd7cddfSDavid du Colombier fetchMsg(Box *box, Msg *m, int uids, void *vf) 567dd7cddfSDavid du Colombier { 577dd7cddfSDavid du Colombier Tm tm; 587dd7cddfSDavid du Colombier Fetch *f; 597dd7cddfSDavid du Colombier char *sep; 607dd7cddfSDavid du Colombier int todo; 617dd7cddfSDavid du Colombier 627dd7cddfSDavid du Colombier if(m->expunged) 637dd7cddfSDavid du Colombier return uids; 647dd7cddfSDavid du Colombier 657dd7cddfSDavid du Colombier todo = 0; 667dd7cddfSDavid du Colombier for(f = vf; f != nil; f = f->next){ 677dd7cddfSDavid du Colombier switch(f->op){ 687dd7cddfSDavid du Colombier case FFlags: 697dd7cddfSDavid du Colombier /* 707dd7cddfSDavid du Colombier * flags get sent with status update 717dd7cddfSDavid du Colombier */ 727dd7cddfSDavid du Colombier box->sendFlags = 1; 737dd7cddfSDavid du Colombier m->sendFlags = 1; 747dd7cddfSDavid du Colombier break; 757dd7cddfSDavid du Colombier case FUid: 767dd7cddfSDavid du Colombier todo = 1; 777dd7cddfSDavid du Colombier break; 787dd7cddfSDavid du Colombier case FInternalDate: 797dd7cddfSDavid du Colombier case FEnvelope: 807dd7cddfSDavid du Colombier case FRfc822: 817dd7cddfSDavid du Colombier case FRfc822Head: 827dd7cddfSDavid du Colombier case FRfc822Size: 837dd7cddfSDavid du Colombier case FRfc822Text: 847dd7cddfSDavid du Colombier case FBodySect: 857dd7cddfSDavid du Colombier case FBodyPeek: 867dd7cddfSDavid du Colombier case FBody: 877dd7cddfSDavid du Colombier case FBodyStruct: 887dd7cddfSDavid du Colombier todo = 1; 897dd7cddfSDavid du Colombier if(!msgStruct(m, 1)){ 907dd7cddfSDavid du Colombier msgDead(m); 917dd7cddfSDavid du Colombier return uids; 927dd7cddfSDavid du Colombier } 937dd7cddfSDavid du Colombier break; 947dd7cddfSDavid du Colombier default: 957dd7cddfSDavid du Colombier bye("bad implementation of fetch"); 967dd7cddfSDavid du Colombier return 0; 977dd7cddfSDavid du Colombier } 987dd7cddfSDavid du Colombier } 997dd7cddfSDavid du Colombier 1007dd7cddfSDavid du Colombier if(m->expunged) 1017dd7cddfSDavid du Colombier return uids; 1027dd7cddfSDavid du Colombier if(!todo) 1037dd7cddfSDavid du Colombier return 1; 1047dd7cddfSDavid du Colombier 1057dd7cddfSDavid du Colombier /* 1067dd7cddfSDavid du Colombier * note: it is allowed to send back the responses one at a time 1077dd7cddfSDavid du Colombier * rather than all together. this is exploited to send flags elsewhere. 1087dd7cddfSDavid du Colombier */ 1097dd7cddfSDavid du Colombier Bprint(&bout, "* %lud fetch (", m->seq); 1107dd7cddfSDavid du Colombier sep = ""; 1117dd7cddfSDavid du Colombier if(uids){ 1127dd7cddfSDavid du Colombier Bprint(&bout, "uid %lud", m->uid); 1137dd7cddfSDavid du Colombier sep = " "; 1147dd7cddfSDavid du Colombier } 1157dd7cddfSDavid du Colombier for(f = vf; f != nil; f = f->next){ 1167dd7cddfSDavid du Colombier switch(f->op){ 1177dd7cddfSDavid du Colombier default: 1187dd7cddfSDavid du Colombier bye("bad implementation of fetch"); 1197dd7cddfSDavid du Colombier break; 1207dd7cddfSDavid du Colombier case FFlags: 1217dd7cddfSDavid du Colombier continue; 1227dd7cddfSDavid du Colombier case FUid: 1237dd7cddfSDavid du Colombier if(uids) 1247dd7cddfSDavid du Colombier continue; 1257dd7cddfSDavid du Colombier Bprint(&bout, "%suid %lud", sep, m->uid); 1267dd7cddfSDavid du Colombier break; 1277dd7cddfSDavid du Colombier case FEnvelope: 1287dd7cddfSDavid du Colombier Bprint(&bout, "%senvelope ", sep); 1297dd7cddfSDavid du Colombier fetchEnvelope(m); 1307dd7cddfSDavid du Colombier break; 1317dd7cddfSDavid du Colombier case FInternalDate: 1327dd7cddfSDavid du Colombier Bprint(&bout, "%sinternaldate ", sep); 1337dd7cddfSDavid du Colombier Bimapdate(&bout, date2tm(&tm, m->unixDate)); 1347dd7cddfSDavid du Colombier break; 1357dd7cddfSDavid du Colombier case FBody: 1367dd7cddfSDavid du Colombier Bprint(&bout, "%sbody ", sep); 1377dd7cddfSDavid du Colombier fetchBodyStruct(m, &m->head, 0); 1387dd7cddfSDavid du Colombier break; 1397dd7cddfSDavid du Colombier case FBodyStruct: 1407dd7cddfSDavid du Colombier Bprint(&bout, "%sbodystructure ", sep); 1417dd7cddfSDavid du Colombier fetchBodyStruct(m, &m->head, 1); 1427dd7cddfSDavid du Colombier break; 1437dd7cddfSDavid du Colombier case FRfc822Size: 1447dd7cddfSDavid du Colombier Bprint(&bout, "%srfc822.size %lud", sep, msgSize(m)); 1457dd7cddfSDavid du Colombier break; 1467dd7cddfSDavid du Colombier case FRfc822: 1477dd7cddfSDavid du Colombier f->part = FPAll; 1487dd7cddfSDavid du Colombier Bprint(&bout, "%srfc822", sep); 1497dd7cddfSDavid du Colombier fetchBody(m, f); 1507dd7cddfSDavid du Colombier break; 1517dd7cddfSDavid du Colombier case FRfc822Head: 1527dd7cddfSDavid du Colombier f->part = FPHead; 1537dd7cddfSDavid du Colombier Bprint(&bout, "%srfc822.header", sep); 1547dd7cddfSDavid du Colombier fetchBody(m, f); 1557dd7cddfSDavid du Colombier break; 1567dd7cddfSDavid du Colombier case FRfc822Text: 1577dd7cddfSDavid du Colombier f->part = FPText; 1587dd7cddfSDavid du Colombier Bprint(&bout, "%srfc822.text", sep); 1597dd7cddfSDavid du Colombier fetchBody(m, f); 1607dd7cddfSDavid du Colombier break; 1617dd7cddfSDavid du Colombier case FBodySect: 1627dd7cddfSDavid du Colombier case FBodyPeek: 1637dd7cddfSDavid du Colombier Bprint(&bout, "%sbody", sep); 1647dd7cddfSDavid du Colombier fetchBody(fetchSect(m, f), f); 1657dd7cddfSDavid du Colombier break; 1667dd7cddfSDavid du Colombier } 1677dd7cddfSDavid du Colombier sep = " "; 1687dd7cddfSDavid du Colombier } 1697dd7cddfSDavid du Colombier Bprint(&bout, ")\r\n"); 1707dd7cddfSDavid du Colombier 1717dd7cddfSDavid du Colombier return 1; 1727dd7cddfSDavid du Colombier } 1737dd7cddfSDavid du Colombier 1747dd7cddfSDavid du Colombier /* 1757dd7cddfSDavid du Colombier * print out section, part, headers; 1767dd7cddfSDavid du Colombier * find and return message section 1777dd7cddfSDavid du Colombier */ 1787dd7cddfSDavid du Colombier Msg * 1797dd7cddfSDavid du Colombier fetchSect(Msg *m, Fetch *f) 1807dd7cddfSDavid du Colombier { 1817dd7cddfSDavid du Colombier Bputc(&bout, '['); 1827dd7cddfSDavid du Colombier BNList(&bout, f->sect, "."); 1837dd7cddfSDavid du Colombier if(f->part != FPAll){ 1847dd7cddfSDavid du Colombier if(f->sect != nil) 1857dd7cddfSDavid du Colombier Bputc(&bout, '.'); 1867dd7cddfSDavid du Colombier Bprint(&bout, "%s", fetchPartNames[f->part]); 1877dd7cddfSDavid du Colombier if(f->hdrs != nil){ 1887dd7cddfSDavid du Colombier Bprint(&bout, " ("); 1897dd7cddfSDavid du Colombier BSList(&bout, f->hdrs, " "); 1907dd7cddfSDavid du Colombier Bputc(&bout, ')'); 1917dd7cddfSDavid du Colombier } 1927dd7cddfSDavid du Colombier } 1937dd7cddfSDavid du Colombier Bprint(&bout, "]"); 1947dd7cddfSDavid du Colombier return findMsgSect(m, f->sect); 1957dd7cddfSDavid du Colombier } 1967dd7cddfSDavid du Colombier 1977dd7cddfSDavid du Colombier /* 1987dd7cddfSDavid du Colombier * actually return the body pieces 1997dd7cddfSDavid du Colombier */ 2007dd7cddfSDavid du Colombier void 2017dd7cddfSDavid du Colombier fetchBody(Msg *m, Fetch *f) 2027dd7cddfSDavid du Colombier { 2037dd7cddfSDavid du Colombier Pair p; 2047dd7cddfSDavid du Colombier char *s, *t, *e, buf[BufSize + 2]; 2057dd7cddfSDavid du Colombier ulong n, start, stop, pos; 2067dd7cddfSDavid du Colombier int fd, nn; 2077dd7cddfSDavid du Colombier 2087dd7cddfSDavid du Colombier if(m == nil){ 2097dd7cddfSDavid du Colombier fetchBodyStr(f, "", 0); 2107dd7cddfSDavid du Colombier return; 2117dd7cddfSDavid du Colombier } 2127dd7cddfSDavid du Colombier switch(f->part){ 2137dd7cddfSDavid du Colombier case FPHeadFields: 2147dd7cddfSDavid du Colombier case FPHeadFieldsNot: 2157dd7cddfSDavid du Colombier n = m->head.size + 3; 2167dd7cddfSDavid du Colombier s = emalloc(n); 2177dd7cddfSDavid du Colombier n = selectFields(s, n, m->head.buf, f->hdrs, f->part == FPHeadFields); 2187dd7cddfSDavid du Colombier fetchBodyStr(f, s, n); 2197dd7cddfSDavid du Colombier free(s); 2207dd7cddfSDavid du Colombier return; 2217dd7cddfSDavid du Colombier case FPHead: 2227dd7cddfSDavid du Colombier fetchBodyStr(f, m->head.buf, m->head.size); 2237dd7cddfSDavid du Colombier return; 2247dd7cddfSDavid du Colombier case FPMime: 2257dd7cddfSDavid du Colombier fetchBodyStr(f, m->mime.buf, m->mime.size); 2267dd7cddfSDavid du Colombier return; 2277dd7cddfSDavid du Colombier case FPAll: 2287dd7cddfSDavid du Colombier fd = msgFile(m, "rawbody"); 2297dd7cddfSDavid du Colombier if(fd < 0){ 2307dd7cddfSDavid du Colombier msgDead(m); 2317dd7cddfSDavid du Colombier fetchBodyStr(f, "", 0); 2327dd7cddfSDavid du Colombier return; 2337dd7cddfSDavid du Colombier } 2347dd7cddfSDavid du Colombier p = fetchBodyPart(f, msgSize(m)); 2357dd7cddfSDavid du Colombier start = p.start; 2367dd7cddfSDavid du Colombier if(start < m->head.size){ 2377dd7cddfSDavid du Colombier stop = p.stop; 2387dd7cddfSDavid du Colombier if(stop > m->head.size) 2397dd7cddfSDavid du Colombier stop = m->head.size; 2407dd7cddfSDavid du Colombier Bwrite(&bout, &m->head.buf[start], stop - start); 2417dd7cddfSDavid du Colombier start = 0; 2427dd7cddfSDavid du Colombier stop = p.stop; 2437dd7cddfSDavid du Colombier if(stop <= m->head.size){ 2447dd7cddfSDavid du Colombier close(fd); 2457dd7cddfSDavid du Colombier return; 2467dd7cddfSDavid du Colombier } 2477dd7cddfSDavid du Colombier }else 2487dd7cddfSDavid du Colombier start -= m->head.size; 2497dd7cddfSDavid du Colombier stop = p.stop - m->head.size; 2507dd7cddfSDavid du Colombier break; 2517dd7cddfSDavid du Colombier case FPText: 2527dd7cddfSDavid du Colombier fd = msgFile(m, "rawbody"); 2537dd7cddfSDavid du Colombier if(fd < 0){ 2547dd7cddfSDavid du Colombier msgDead(m); 2557dd7cddfSDavid du Colombier fetchBodyStr(f, "", 0); 2567dd7cddfSDavid du Colombier return; 2577dd7cddfSDavid du Colombier } 2587dd7cddfSDavid du Colombier p = fetchBodyPart(f, m->size); 2597dd7cddfSDavid du Colombier start = p.start; 2607dd7cddfSDavid du Colombier stop = p.stop; 2617dd7cddfSDavid du Colombier break; 2627dd7cddfSDavid du Colombier default: 2637dd7cddfSDavid du Colombier fetchBodyStr(f, "", 0); 2647dd7cddfSDavid du Colombier return; 2657dd7cddfSDavid du Colombier } 2667dd7cddfSDavid du Colombier 2677dd7cddfSDavid du Colombier /* 2687dd7cddfSDavid du Colombier * read in each block, convert \n without \r to \r\n. 2697dd7cddfSDavid du Colombier * this means partial fetch requires fetching everything 2707dd7cddfSDavid du Colombier * through stop, since we don't know how many \r's will be added 2717dd7cddfSDavid du Colombier */ 2727dd7cddfSDavid du Colombier buf[0] = ' '; 2737dd7cddfSDavid du Colombier for(pos = 0; pos < stop; ){ 2747dd7cddfSDavid du Colombier n = BufSize; 2757dd7cddfSDavid du Colombier if(n > stop - pos) 2767dd7cddfSDavid du Colombier n = stop - pos; 2777dd7cddfSDavid du Colombier n = read(fd, &buf[1], n); 2787dd7cddfSDavid du Colombier if(n <= 0){ 2797dd7cddfSDavid du Colombier fetchBodyFill(stop - pos); 2807dd7cddfSDavid du Colombier break; 2817dd7cddfSDavid du Colombier } 2827dd7cddfSDavid du Colombier e = &buf[n + 1]; 2837dd7cddfSDavid du Colombier *e = '\0'; 2847dd7cddfSDavid du Colombier for(s = &buf[1]; s < e && pos < stop; s = t + 1){ 2857dd7cddfSDavid du Colombier t = memchr(s, '\n', e - s); 2867dd7cddfSDavid du Colombier if(t == nil) 2877dd7cddfSDavid du Colombier t = e; 2887dd7cddfSDavid du Colombier n = t - s; 2897dd7cddfSDavid du Colombier if(pos < start){ 2907dd7cddfSDavid du Colombier if(pos + n <= start){ 2917dd7cddfSDavid du Colombier s = t; 2927dd7cddfSDavid du Colombier pos += n; 2937dd7cddfSDavid du Colombier }else{ 2947dd7cddfSDavid du Colombier s += start - pos; 2957dd7cddfSDavid du Colombier pos = start; 2967dd7cddfSDavid du Colombier } 2977dd7cddfSDavid du Colombier n = t - s; 2987dd7cddfSDavid du Colombier } 2997dd7cddfSDavid du Colombier nn = n; 3007dd7cddfSDavid du Colombier if(pos + nn > stop) 3017dd7cddfSDavid du Colombier nn = stop - pos; 3027dd7cddfSDavid du Colombier if(Bwrite(&bout, s, nn) != nn) 3037dd7cddfSDavid du Colombier writeErr(); 3047dd7cddfSDavid du Colombier pos += n; 3057dd7cddfSDavid du Colombier if(*t == '\n'){ 3067dd7cddfSDavid du Colombier if(t[-1] != '\r'){ 3077dd7cddfSDavid du Colombier if(pos >= start && pos < stop) 3087dd7cddfSDavid du Colombier Bputc(&bout, '\r'); 3097dd7cddfSDavid du Colombier pos++; 3107dd7cddfSDavid du Colombier } 3117dd7cddfSDavid du Colombier if(pos >= start && pos < stop) 3127dd7cddfSDavid du Colombier Bputc(&bout, '\n'); 3137dd7cddfSDavid du Colombier pos++; 3147dd7cddfSDavid du Colombier } 3157dd7cddfSDavid du Colombier } 3167dd7cddfSDavid du Colombier buf[0] = e[-1]; 3177dd7cddfSDavid du Colombier } 3187dd7cddfSDavid du Colombier close(fd); 3197dd7cddfSDavid du Colombier } 3207dd7cddfSDavid du Colombier 3217dd7cddfSDavid du Colombier /* 3227dd7cddfSDavid du Colombier * resolve the actual bounds of any partial fetch, 3237dd7cddfSDavid du Colombier * and print out the bounds & size of string returned 3247dd7cddfSDavid du Colombier */ 3257dd7cddfSDavid du Colombier Pair 3267dd7cddfSDavid du Colombier fetchBodyPart(Fetch *f, ulong size) 3277dd7cddfSDavid du Colombier { 3287dd7cddfSDavid du Colombier Pair p; 3297dd7cddfSDavid du Colombier ulong start, stop; 3307dd7cddfSDavid du Colombier 3317dd7cddfSDavid du Colombier start = 0; 3327dd7cddfSDavid du Colombier stop = size; 3337dd7cddfSDavid du Colombier if(f->partial){ 3347dd7cddfSDavid du Colombier start = f->start; 3357dd7cddfSDavid du Colombier if(start > size) 3367dd7cddfSDavid du Colombier start = size; 3377dd7cddfSDavid du Colombier stop = start + f->size; 3387dd7cddfSDavid du Colombier if(stop > size) 3397dd7cddfSDavid du Colombier stop = size; 3407dd7cddfSDavid du Colombier Bprint(&bout, "<%lud>", start); 3417dd7cddfSDavid du Colombier } 3427dd7cddfSDavid du Colombier Bprint(&bout, " {%lud}\r\n", stop - start); 3437dd7cddfSDavid du Colombier p.start = start; 3447dd7cddfSDavid du Colombier p.stop = stop; 3457dd7cddfSDavid du Colombier return p; 3467dd7cddfSDavid du Colombier } 3477dd7cddfSDavid du Colombier 3487dd7cddfSDavid du Colombier /* 3497dd7cddfSDavid du Colombier * something went wrong fetching data 3507dd7cddfSDavid du Colombier * produce fill bytes for what we've committed to produce 3517dd7cddfSDavid du Colombier */ 3527dd7cddfSDavid du Colombier void 3537dd7cddfSDavid du Colombier fetchBodyFill(ulong n) 3547dd7cddfSDavid du Colombier { 3557dd7cddfSDavid du Colombier while(n-- > 0) 3567dd7cddfSDavid du Colombier if(Bputc(&bout, ' ') < 0) 3577dd7cddfSDavid du Colombier writeErr(); 3587dd7cddfSDavid du Colombier } 3597dd7cddfSDavid du Colombier 3607dd7cddfSDavid du Colombier /* 3617dd7cddfSDavid du Colombier * return a simple string 3627dd7cddfSDavid du Colombier */ 3637dd7cddfSDavid du Colombier void 3647dd7cddfSDavid du Colombier fetchBodyStr(Fetch *f, char *buf, ulong size) 3657dd7cddfSDavid du Colombier { 3667dd7cddfSDavid du Colombier Pair p; 3677dd7cddfSDavid du Colombier 3687dd7cddfSDavid du Colombier p = fetchBodyPart(f, size); 3697dd7cddfSDavid du Colombier Bwrite(&bout, &buf[p.start], p.stop-p.start); 3707dd7cddfSDavid du Colombier } 3717dd7cddfSDavid du Colombier 372*9a747e4fSDavid du Colombier char* 373*9a747e4fSDavid du Colombier printnlist(NList *sect) 374*9a747e4fSDavid du Colombier { 375*9a747e4fSDavid du Colombier static char buf[100]; 376*9a747e4fSDavid du Colombier char *p; 377*9a747e4fSDavid du Colombier 378*9a747e4fSDavid du Colombier for(p= buf; sect; sect=sect->next){ 379*9a747e4fSDavid du Colombier p += sprint(p, "%ld", sect->n); 380*9a747e4fSDavid du Colombier if(sect->next) 381*9a747e4fSDavid du Colombier *p++ = '.'; 382*9a747e4fSDavid du Colombier } 383*9a747e4fSDavid du Colombier *p = '\0'; 384*9a747e4fSDavid du Colombier return buf; 385*9a747e4fSDavid du Colombier } 386*9a747e4fSDavid du Colombier 3877dd7cddfSDavid du Colombier /* 3887dd7cddfSDavid du Colombier * find the numbered sub-part of the message 3897dd7cddfSDavid du Colombier */ 3907dd7cddfSDavid du Colombier Msg* 3917dd7cddfSDavid du Colombier findMsgSect(Msg *m, NList *sect) 3927dd7cddfSDavid du Colombier { 3937dd7cddfSDavid du Colombier ulong id; 3947dd7cddfSDavid du Colombier 3957dd7cddfSDavid du Colombier for(; sect != nil; sect = sect->next){ 3967dd7cddfSDavid du Colombier id = sect->n; 397*9a747e4fSDavid du Colombier #ifdef HACK 398*9a747e4fSDavid du Colombier /* HACK to solve extra level of structure not visible from upas/fs */ 399*9a747e4fSDavid du Colombier if(m->kids == 0 && id == 1 && sect->next == nil){ 400*9a747e4fSDavid du Colombier if(m->mime.type->s && strcmp(m->mime.type->s, "message")==0) 401*9a747e4fSDavid du Colombier if(m->mime.type->t && strcmp(m->mime.type->t, "rfc822")==0) 402*9a747e4fSDavid du Colombier if(m->head.type->s && strcmp(m->head.type->s, "text")==0) 403*9a747e4fSDavid du Colombier if(m->head.type->t && strcmp(m->head.type->t, "plain")==0) 404*9a747e4fSDavid du Colombier break; 405*9a747e4fSDavid du Colombier } 406*9a747e4fSDavid du Colombier /* end of HACK */ 407*9a747e4fSDavid du Colombier #endif HACK 4087dd7cddfSDavid du Colombier for(m = m->kids; m != nil; m = m->next) 4097dd7cddfSDavid du Colombier if(m->id == id) 4107dd7cddfSDavid du Colombier break; 4117dd7cddfSDavid du Colombier if(m == nil) 4127dd7cddfSDavid du Colombier return nil; 4137dd7cddfSDavid du Colombier } 4147dd7cddfSDavid du Colombier return m; 4157dd7cddfSDavid du Colombier } 4167dd7cddfSDavid du Colombier 4177dd7cddfSDavid du Colombier void 4187dd7cddfSDavid du Colombier fetchEnvelope(Msg *m) 4197dd7cddfSDavid du Colombier { 4207dd7cddfSDavid du Colombier Tm tm; 4217dd7cddfSDavid du Colombier 4227dd7cddfSDavid du Colombier Bputc(&bout, '('); 4237dd7cddfSDavid du Colombier Brfc822date(&bout, date2tm(&tm, m->info[IDate])); 4247dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4257dd7cddfSDavid du Colombier Bimapstr(&bout, m->info[ISubject]); 4267dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4277dd7cddfSDavid du Colombier Bimapaddr(&bout, m->from); 4287dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4297dd7cddfSDavid du Colombier Bimapaddr(&bout, m->sender); 4307dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4317dd7cddfSDavid du Colombier Bimapaddr(&bout, m->replyTo); 4327dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4337dd7cddfSDavid du Colombier Bimapaddr(&bout, m->to); 4347dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4357dd7cddfSDavid du Colombier Bimapaddr(&bout, m->cc); 4367dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4377dd7cddfSDavid du Colombier Bimapaddr(&bout, m->bcc); 4387dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4397dd7cddfSDavid du Colombier Bimapstr(&bout, m->info[IInReplyTo]); 4407dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4417dd7cddfSDavid du Colombier Bimapstr(&bout, m->info[IMessageId]); 4427dd7cddfSDavid du Colombier Bputc(&bout, ')'); 4437dd7cddfSDavid du Colombier } 4447dd7cddfSDavid du Colombier 4457dd7cddfSDavid du Colombier void 4467dd7cddfSDavid du Colombier fetchBodyStruct(Msg *m, Header *h, int extensions) 4477dd7cddfSDavid du Colombier { 4487dd7cddfSDavid du Colombier Msg *k; 4497dd7cddfSDavid du Colombier ulong len; 4507dd7cddfSDavid du Colombier 4517dd7cddfSDavid du Colombier if(msgIsMulti(h)){ 4527dd7cddfSDavid du Colombier Bputc(&bout, '('); 4537dd7cddfSDavid du Colombier for(k = m->kids; k != nil; k = k->next) 4547dd7cddfSDavid du Colombier fetchBodyStruct(k, &k->mime, extensions); 4557dd7cddfSDavid du Colombier 4567dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4577dd7cddfSDavid du Colombier Bimapstr(&bout, h->type->t); 4587dd7cddfSDavid du Colombier 4597dd7cddfSDavid du Colombier if(extensions){ 4607dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4617dd7cddfSDavid du Colombier BimapMimeParams(&bout, h->type->next); 4627dd7cddfSDavid du Colombier fetchStructExt(h); 4637dd7cddfSDavid du Colombier } 4647dd7cddfSDavid du Colombier 4657dd7cddfSDavid du Colombier Bputc(&bout, ')'); 4667dd7cddfSDavid du Colombier return; 4677dd7cddfSDavid du Colombier } 4687dd7cddfSDavid du Colombier 4697dd7cddfSDavid du Colombier Bputc(&bout, '('); 4707dd7cddfSDavid du Colombier if(h->type != nil){ 4717dd7cddfSDavid du Colombier Bimapstr(&bout, h->type->s); 4727dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4737dd7cddfSDavid du Colombier Bimapstr(&bout, h->type->t); 4747dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4757dd7cddfSDavid du Colombier BimapMimeParams(&bout, h->type->next); 4767dd7cddfSDavid du Colombier }else 4777dd7cddfSDavid du Colombier Bprint(&bout, "\"text\" \"plain\" NIL"); 4787dd7cddfSDavid du Colombier 4797dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4807dd7cddfSDavid du Colombier if(h->id != nil) 4817dd7cddfSDavid du Colombier Bimapstr(&bout, h->id->s); 4827dd7cddfSDavid du Colombier else 4837dd7cddfSDavid du Colombier Bprint(&bout, "NIL"); 4847dd7cddfSDavid du Colombier 4857dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4867dd7cddfSDavid du Colombier if(h->description != nil) 4877dd7cddfSDavid du Colombier Bimapstr(&bout, h->description->s); 4887dd7cddfSDavid du Colombier else 4897dd7cddfSDavid du Colombier Bprint(&bout, "NIL"); 4907dd7cddfSDavid du Colombier 4917dd7cddfSDavid du Colombier Bputc(&bout, ' '); 4927dd7cddfSDavid du Colombier if(h->encoding != nil) 4937dd7cddfSDavid du Colombier Bimapstr(&bout, h->encoding->s); 4947dd7cddfSDavid du Colombier else 4957dd7cddfSDavid du Colombier Bprint(&bout, "NIL"); 4967dd7cddfSDavid du Colombier 4977dd7cddfSDavid du Colombier /* 4987dd7cddfSDavid du Colombier * this is so strange: return lengths for a body[text] response, 499*9a747e4fSDavid du Colombier * except in the case of a multipart message, when return lengths for a body[] response 5007dd7cddfSDavid du Colombier */ 5017dd7cddfSDavid du Colombier len = m->size; 5027dd7cddfSDavid du Colombier if(h == &m->mime) 5037dd7cddfSDavid du Colombier len += m->head.size; 5047dd7cddfSDavid du Colombier Bprint(&bout, " %lud", len); 5057dd7cddfSDavid du Colombier 5067dd7cddfSDavid du Colombier len = m->lines; 5077dd7cddfSDavid du Colombier if(h == &m->mime) 5087dd7cddfSDavid du Colombier len += m->head.lines; 5097dd7cddfSDavid du Colombier 5107dd7cddfSDavid du Colombier if(h->type == nil || cistrcmp(h->type->s, "text") == 0){ 5117dd7cddfSDavid du Colombier Bprint(&bout, " %lud", len); 5127dd7cddfSDavid du Colombier }else if(msgIsRfc822(h)){ 5137dd7cddfSDavid du Colombier Bputc(&bout, ' '); 5147dd7cddfSDavid du Colombier k = m; 5157dd7cddfSDavid du Colombier if(h != &m->mime) 5167dd7cddfSDavid du Colombier k = m->kids; 5177dd7cddfSDavid du Colombier if(k == nil) 5187dd7cddfSDavid du Colombier Bprint(&bout, "(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL) (\"text\" \"plain\" NIL NIL NIL NIL 0 0) 0"); 5197dd7cddfSDavid du Colombier else{ 5207dd7cddfSDavid du Colombier fetchEnvelope(k); 5217dd7cddfSDavid du Colombier Bputc(&bout, ' '); 5227dd7cddfSDavid du Colombier fetchBodyStruct(k, &k->head, extensions); 5237dd7cddfSDavid du Colombier Bprint(&bout, " %lud", len); 5247dd7cddfSDavid du Colombier } 5257dd7cddfSDavid du Colombier } 5267dd7cddfSDavid du Colombier 5277dd7cddfSDavid du Colombier if(extensions){ 5287dd7cddfSDavid du Colombier Bputc(&bout, ' '); 5297dd7cddfSDavid du Colombier 5307dd7cddfSDavid du Colombier /* 5317dd7cddfSDavid du Colombier * don't have the md5 laying around, 5327dd7cddfSDavid du Colombier * since the header & body have added newlines. 5337dd7cddfSDavid du Colombier */ 5347dd7cddfSDavid du Colombier Bprint(&bout, "NIL"); 5357dd7cddfSDavid du Colombier 5367dd7cddfSDavid du Colombier fetchStructExt(h); 5377dd7cddfSDavid du Colombier } 5387dd7cddfSDavid du Colombier Bputc(&bout, ')'); 5397dd7cddfSDavid du Colombier } 5407dd7cddfSDavid du Colombier 5417dd7cddfSDavid du Colombier /* 5427dd7cddfSDavid du Colombier * common part of bodystructure extensions 5437dd7cddfSDavid du Colombier */ 5447dd7cddfSDavid du Colombier void 5457dd7cddfSDavid du Colombier fetchStructExt(Header *h) 5467dd7cddfSDavid du Colombier { 5477dd7cddfSDavid du Colombier Bputc(&bout, ' '); 5487dd7cddfSDavid du Colombier if(h->disposition != nil){ 5497dd7cddfSDavid du Colombier Bputc(&bout, '('); 5507dd7cddfSDavid du Colombier Bimapstr(&bout, h->disposition->s); 5517dd7cddfSDavid du Colombier Bputc(&bout, ' '); 5527dd7cddfSDavid du Colombier BimapMimeParams(&bout, h->disposition->next); 5537dd7cddfSDavid du Colombier Bputc(&bout, ')'); 5547dd7cddfSDavid du Colombier }else 5557dd7cddfSDavid du Colombier Bprint(&bout, "NIL"); 5567dd7cddfSDavid du Colombier Bputc(&bout, ' '); 5577dd7cddfSDavid du Colombier if(h->language != nil){ 5587dd7cddfSDavid du Colombier if(h->language->next != nil) 5597dd7cddfSDavid du Colombier BimapMimeParams(&bout, h->language->next); 5607dd7cddfSDavid du Colombier else 5617dd7cddfSDavid du Colombier Bimapstr(&bout, h->language->s); 5627dd7cddfSDavid du Colombier }else 5637dd7cddfSDavid du Colombier Bprint(&bout, "NIL"); 5647dd7cddfSDavid du Colombier } 5657dd7cddfSDavid du Colombier 5667dd7cddfSDavid du Colombier int 5677dd7cddfSDavid du Colombier BimapMimeParams(Biobuf *b, MimeHdr *mh) 5687dd7cddfSDavid du Colombier { 5697dd7cddfSDavid du Colombier char *sep; 5707dd7cddfSDavid du Colombier int n; 5717dd7cddfSDavid du Colombier 5727dd7cddfSDavid du Colombier if(mh == nil) 5737dd7cddfSDavid du Colombier return Bprint(b, "NIL"); 5747dd7cddfSDavid du Colombier 5757dd7cddfSDavid du Colombier n = Bputc(b, '('); 5767dd7cddfSDavid du Colombier 5777dd7cddfSDavid du Colombier sep = ""; 5787dd7cddfSDavid du Colombier for(; mh != nil; mh = mh->next){ 5797dd7cddfSDavid du Colombier n += Bprint(b, sep); 5807dd7cddfSDavid du Colombier n += Bimapstr(b, mh->s); 5817dd7cddfSDavid du Colombier n += Bputc(b, ' '); 5827dd7cddfSDavid du Colombier n += Bimapstr(b, mh->t); 5837dd7cddfSDavid du Colombier sep = " "; 5847dd7cddfSDavid du Colombier } 5857dd7cddfSDavid du Colombier 5867dd7cddfSDavid du Colombier n += Bputc(b, ')'); 5877dd7cddfSDavid du Colombier return n; 5887dd7cddfSDavid du Colombier } 5897dd7cddfSDavid du Colombier 5907dd7cddfSDavid du Colombier /* 5917dd7cddfSDavid du Colombier * print a list of addresses; 5927dd7cddfSDavid du Colombier * each address is printed as '(' personalName AtDomainList mboxName hostName ')' 5937dd7cddfSDavid du Colombier * the AtDomainList is always NIL 5947dd7cddfSDavid du Colombier */ 5957dd7cddfSDavid du Colombier int 5967dd7cddfSDavid du Colombier Bimapaddr(Biobuf *b, MAddr *a) 5977dd7cddfSDavid du Colombier { 5987dd7cddfSDavid du Colombier char *host, *sep; 5997dd7cddfSDavid du Colombier int n; 6007dd7cddfSDavid du Colombier 6017dd7cddfSDavid du Colombier if(a == nil) 6027dd7cddfSDavid du Colombier return Bprint(b, "NIL"); 6037dd7cddfSDavid du Colombier 6047dd7cddfSDavid du Colombier n = Bputc(b, '('); 6057dd7cddfSDavid du Colombier sep = ""; 6067dd7cddfSDavid du Colombier for(; a != nil; a = a->next){ 6077dd7cddfSDavid du Colombier n += Bprint(b, "%s(", sep); 6087dd7cddfSDavid du Colombier n += Bimapstr(b, a->personal); 6097dd7cddfSDavid du Colombier n += Bprint(b," NIL "); 6107dd7cddfSDavid du Colombier n += Bimapstr(b, a->box); 6117dd7cddfSDavid du Colombier n += Bputc(b, ' '); 6127dd7cddfSDavid du Colombier 6137dd7cddfSDavid du Colombier /* 6147dd7cddfSDavid du Colombier * can't send NIL as hostName, since that is code for a group 6157dd7cddfSDavid du Colombier */ 6167dd7cddfSDavid du Colombier host = a->host; 6177dd7cddfSDavid du Colombier if(host == nil) 6187dd7cddfSDavid du Colombier host = ""; 6197dd7cddfSDavid du Colombier n += Bimapstr(b, host); 6207dd7cddfSDavid du Colombier 6217dd7cddfSDavid du Colombier n += Bputc(b, ')'); 6227dd7cddfSDavid du Colombier sep = " "; 6237dd7cddfSDavid du Colombier } 6247dd7cddfSDavid du Colombier n += Bputc(b, ')'); 6257dd7cddfSDavid du Colombier return n; 6267dd7cddfSDavid du Colombier } 627