17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include <libsec.h>
67dd7cddfSDavid du Colombier #include "imap4d.h"
77dd7cddfSDavid du Colombier
87dd7cddfSDavid du Colombier static int saveMsg(char *dst, char *digest, int flags, char *head, int nhead, Biobuf *b, long n);
97dd7cddfSDavid du Colombier static int saveb(int fd, DigestState *dstate, char *buf, int nr, int nw);
107dd7cddfSDavid du Colombier static long appSpool(Biobuf *bout, Biobuf *bin, long n);
117dd7cddfSDavid du Colombier
127dd7cddfSDavid du Colombier /*
137dd7cddfSDavid du Colombier * check if the message exists
147dd7cddfSDavid du Colombier */
157dd7cddfSDavid du Colombier int
copyCheck(Box * box,Msg * m,int uids,void * v)167dd7cddfSDavid du Colombier copyCheck(Box *box, Msg *m, int uids, void *v)
177dd7cddfSDavid du Colombier {
187dd7cddfSDavid du Colombier int fd;
197dd7cddfSDavid du Colombier
207dd7cddfSDavid du Colombier USED(box);
217dd7cddfSDavid du Colombier USED(uids);
227dd7cddfSDavid du Colombier USED(v);
237dd7cddfSDavid du Colombier
247dd7cddfSDavid du Colombier if(m->expunged)
257dd7cddfSDavid du Colombier return 0;
267dd7cddfSDavid du Colombier fd = msgFile(m, "raw");
277dd7cddfSDavid du Colombier if(fd < 0){
287dd7cddfSDavid du Colombier msgDead(m);
297dd7cddfSDavid du Colombier return 0;
307dd7cddfSDavid du Colombier }
317dd7cddfSDavid du Colombier close(fd);
327dd7cddfSDavid du Colombier return 1;
337dd7cddfSDavid du Colombier }
347dd7cddfSDavid du Colombier
357dd7cddfSDavid du Colombier int
copySave(Box * box,Msg * m,int uids,void * vs)367dd7cddfSDavid du Colombier copySave(Box *box, Msg *m, int uids, void *vs)
377dd7cddfSDavid du Colombier {
389a747e4fSDavid du Colombier Dir *d;
397dd7cddfSDavid du Colombier Biobuf b;
409a747e4fSDavid du Colombier vlong length;
417dd7cddfSDavid du Colombier char *head;
427dd7cddfSDavid du Colombier int ok, hfd, bfd, nhead;
437dd7cddfSDavid du Colombier
447dd7cddfSDavid du Colombier USED(box);
457dd7cddfSDavid du Colombier USED(uids);
467dd7cddfSDavid du Colombier
477dd7cddfSDavid du Colombier if(m->expunged)
487dd7cddfSDavid du Colombier return 0;
497dd7cddfSDavid du Colombier
507dd7cddfSDavid du Colombier hfd = msgFile(m, "unixheader");
517dd7cddfSDavid du Colombier if(hfd < 0){
527dd7cddfSDavid du Colombier msgDead(m);
537dd7cddfSDavid du Colombier return 0;
547dd7cddfSDavid du Colombier }
557dd7cddfSDavid du Colombier head = readFile(hfd);
567dd7cddfSDavid du Colombier if(head == nil){
577dd7cddfSDavid du Colombier close(hfd);
587dd7cddfSDavid du Colombier return 0;
597dd7cddfSDavid du Colombier }
607dd7cddfSDavid du Colombier
617dd7cddfSDavid du Colombier /*
627dd7cddfSDavid du Colombier * clear out the header if it doesn't end in a newline,
637dd7cddfSDavid du Colombier * since it is a runt and the "header" will show up in the raw file.
647dd7cddfSDavid du Colombier */
657dd7cddfSDavid du Colombier nhead = strlen(head);
667dd7cddfSDavid du Colombier if(nhead > 0 && head[nhead-1] != '\n')
677dd7cddfSDavid du Colombier nhead = 0;
687dd7cddfSDavid du Colombier
697dd7cddfSDavid du Colombier bfd = msgFile(m, "raw");
707dd7cddfSDavid du Colombier close(hfd);
717dd7cddfSDavid du Colombier if(bfd < 0){
727dd7cddfSDavid du Colombier msgDead(m);
737dd7cddfSDavid du Colombier return 0;
747dd7cddfSDavid du Colombier }
757dd7cddfSDavid du Colombier
769a747e4fSDavid du Colombier d = dirfstat(bfd);
779a747e4fSDavid du Colombier if(d == nil){
787dd7cddfSDavid du Colombier close(bfd);
797dd7cddfSDavid du Colombier return 0;
807dd7cddfSDavid du Colombier }
819a747e4fSDavid du Colombier length = d->length;
829a747e4fSDavid du Colombier free(d);
837dd7cddfSDavid du Colombier
847dd7cddfSDavid du Colombier Binit(&b, bfd, OREAD);
859a747e4fSDavid du Colombier ok = saveMsg(vs, m->info[IDigest], m->flags, head, nhead, &b, length);
867dd7cddfSDavid du Colombier Bterm(&b);
877dd7cddfSDavid du Colombier close(bfd);
887dd7cddfSDavid du Colombier return ok;
897dd7cddfSDavid du Colombier }
907dd7cddfSDavid du Colombier
917dd7cddfSDavid du Colombier /*
927dd7cddfSDavid du Colombier * first spool the input into a temorary file,
937dd7cddfSDavid du Colombier * and massage the input in the process.
947dd7cddfSDavid du Colombier * then save to real box.
957dd7cddfSDavid du Colombier */
967dd7cddfSDavid du Colombier int
appendSave(char * mbox,int flags,char * head,Biobuf * b,long n)977dd7cddfSDavid du Colombier appendSave(char *mbox, int flags, char *head, Biobuf *b, long n)
987dd7cddfSDavid du Colombier {
997dd7cddfSDavid du Colombier Biobuf btmp;
1007dd7cddfSDavid du Colombier int fd, ok;
1017dd7cddfSDavid du Colombier
1027dd7cddfSDavid du Colombier fd = imapTmp();
1037dd7cddfSDavid du Colombier if(fd < 0)
1047dd7cddfSDavid du Colombier return 0;
1057dd7cddfSDavid du Colombier Bprint(&bout, "+ Ready for literal data\r\n");
1067dd7cddfSDavid du Colombier if(Bflush(&bout) < 0)
1077dd7cddfSDavid du Colombier writeErr();
1087dd7cddfSDavid du Colombier Binit(&btmp, fd, OWRITE);
1097dd7cddfSDavid du Colombier n = appSpool(&btmp, b, n);
1107dd7cddfSDavid du Colombier Bterm(&btmp);
1117dd7cddfSDavid du Colombier if(n < 0){
1127dd7cddfSDavid du Colombier close(fd);
1137dd7cddfSDavid du Colombier return 0;
1147dd7cddfSDavid du Colombier }
1157dd7cddfSDavid du Colombier
1167dd7cddfSDavid du Colombier seek(fd, 0, 0);
1177dd7cddfSDavid du Colombier Binit(&btmp, fd, OREAD);
1187dd7cddfSDavid du Colombier ok = saveMsg(mbox, nil, flags, head, strlen(head), &btmp, n);
1197dd7cddfSDavid du Colombier Bterm(&btmp);
1207dd7cddfSDavid du Colombier close(fd);
1217dd7cddfSDavid du Colombier return ok;
1227dd7cddfSDavid du Colombier }
1237dd7cddfSDavid du Colombier
1247dd7cddfSDavid du Colombier /*
1257dd7cddfSDavid du Colombier * copy from bin to bout,
1267dd7cddfSDavid du Colombier * mapping "\r\n" to "\n" and "\nFrom " to "\n From "
1277dd7cddfSDavid du Colombier * return the number of bytes in the mapped file.
1287dd7cddfSDavid du Colombier *
1297dd7cddfSDavid du Colombier * exactly n bytes must be read from the input,
1307dd7cddfSDavid du Colombier * unless an input error occurs.
1317dd7cddfSDavid du Colombier */
1327dd7cddfSDavid du Colombier static long
appSpool(Biobuf * bout,Biobuf * bin,long n)1337dd7cddfSDavid du Colombier appSpool(Biobuf *bout, Biobuf *bin, long n)
1347dd7cddfSDavid du Colombier {
1357dd7cddfSDavid du Colombier int i, c;
1367dd7cddfSDavid du Colombier
1377dd7cddfSDavid du Colombier c = '\n';
1387dd7cddfSDavid du Colombier while(n > 0){
1397dd7cddfSDavid du Colombier if(c == '\n' && n >= STRLEN("From ")){
1407dd7cddfSDavid du Colombier for(i = 0; i < STRLEN("From "); i++){
1417dd7cddfSDavid du Colombier c = Bgetc(bin);
1427dd7cddfSDavid du Colombier if(c != "From "[i]){
1437dd7cddfSDavid du Colombier if(c < 0)
1447dd7cddfSDavid du Colombier return -1;
1457dd7cddfSDavid du Colombier Bungetc(bin);
1467dd7cddfSDavid du Colombier break;
1477dd7cddfSDavid du Colombier }
1487dd7cddfSDavid du Colombier n--;
1497dd7cddfSDavid du Colombier }
1507dd7cddfSDavid du Colombier if(i == STRLEN("From "))
1517dd7cddfSDavid du Colombier Bputc(bout, ' ');
1527dd7cddfSDavid du Colombier Bwrite(bout, "From ", i);
1537dd7cddfSDavid du Colombier }
1547dd7cddfSDavid du Colombier c = Bgetc(bin);
1557dd7cddfSDavid du Colombier n--;
1567dd7cddfSDavid du Colombier if(c == '\r' && n-- > 0){
1577dd7cddfSDavid du Colombier c = Bgetc(bin);
1587dd7cddfSDavid du Colombier if(c != '\n')
1597dd7cddfSDavid du Colombier Bputc(bout, '\r');
1607dd7cddfSDavid du Colombier }
1617dd7cddfSDavid du Colombier if(c < 0)
1627dd7cddfSDavid du Colombier return -1;
1637dd7cddfSDavid du Colombier if(Bputc(bout, c) < 0)
1647dd7cddfSDavid du Colombier return -1;
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier if(c != '\n')
1677dd7cddfSDavid du Colombier Bputc(bout, '\n');
1687dd7cddfSDavid du Colombier if(Bflush(bout) < 0)
1697dd7cddfSDavid du Colombier return -1;
1707dd7cddfSDavid du Colombier return Boffset(bout);
1717dd7cddfSDavid du Colombier }
1727dd7cddfSDavid du Colombier
1737dd7cddfSDavid du Colombier static int
saveMsg(char * dst,char * digest,int flags,char * head,int nhead,Biobuf * b,long n)1747dd7cddfSDavid du Colombier saveMsg(char *dst, char *digest, int flags, char *head, int nhead, Biobuf *b, long n)
1757dd7cddfSDavid du Colombier {
1767dd7cddfSDavid du Colombier DigestState *dstate;
1777dd7cddfSDavid du Colombier MbLock *ml;
1787dd7cddfSDavid du Colombier uchar shadig[SHA1dlen];
1797dd7cddfSDavid du Colombier char buf[BufSize + 1], digbuf[NDigest + 1];
1807dd7cddfSDavid du Colombier int i, fd, nr, nw, ok;
1817dd7cddfSDavid du Colombier
1827dd7cddfSDavid du Colombier ml = mbLock();
1837dd7cddfSDavid du Colombier if(ml == nil)
1847dd7cddfSDavid du Colombier return 0;
1857dd7cddfSDavid du Colombier fd = openLocked(mboxDir, dst, OWRITE);
1867dd7cddfSDavid du Colombier if(fd < 0){
1877dd7cddfSDavid du Colombier mbUnlock(ml);
1887dd7cddfSDavid du Colombier return 0;
1897dd7cddfSDavid du Colombier }
1907dd7cddfSDavid du Colombier seek(fd, 0, 2);
1917dd7cddfSDavid du Colombier
1927dd7cddfSDavid du Colombier dstate = nil;
1937dd7cddfSDavid du Colombier if(digest == nil)
1947dd7cddfSDavid du Colombier dstate = sha1(nil, 0, nil, nil);
1957dd7cddfSDavid du Colombier if(!saveb(fd, dstate, head, nhead, nhead)){
1967dd7cddfSDavid du Colombier if(dstate != nil)
1977dd7cddfSDavid du Colombier sha1(nil, 0, shadig, dstate);
1987dd7cddfSDavid du Colombier mbUnlock(ml);
199*be0c1e85SDavid du Colombier close(fd);
2007dd7cddfSDavid du Colombier return 0;
2017dd7cddfSDavid du Colombier }
2027dd7cddfSDavid du Colombier ok = 1;
2037dd7cddfSDavid du Colombier if(n == 0)
2047dd7cddfSDavid du Colombier ok = saveb(fd, dstate, "\n", 0, 1);
2057dd7cddfSDavid du Colombier while(n > 0){
2067dd7cddfSDavid du Colombier nr = n;
2077dd7cddfSDavid du Colombier if(nr > BufSize)
2087dd7cddfSDavid du Colombier nr = BufSize;
2097dd7cddfSDavid du Colombier nr = Bread(b, buf, nr);
2107dd7cddfSDavid du Colombier if(nr <= 0){
2117dd7cddfSDavid du Colombier saveb(fd, dstate, "\n\n", 0, 2);
2127dd7cddfSDavid du Colombier ok = 0;
2137dd7cddfSDavid du Colombier break;
2147dd7cddfSDavid du Colombier }
2157dd7cddfSDavid du Colombier n -= nr;
2167dd7cddfSDavid du Colombier nw = nr;
2177dd7cddfSDavid du Colombier if(n == 0){
2187dd7cddfSDavid du Colombier if(buf[nw - 1] != '\n')
2197dd7cddfSDavid du Colombier buf[nw++] = '\n';
2207dd7cddfSDavid du Colombier buf[nw++] = '\n';
2217dd7cddfSDavid du Colombier }
2227dd7cddfSDavid du Colombier if(!saveb(fd, dstate, buf, nr, nw)){
2237dd7cddfSDavid du Colombier ok = 0;
2247dd7cddfSDavid du Colombier break;
2257dd7cddfSDavid du Colombier }
2267dd7cddfSDavid du Colombier mbLockRefresh(ml);
2277dd7cddfSDavid du Colombier }
2287dd7cddfSDavid du Colombier close(fd);
2297dd7cddfSDavid du Colombier
2307dd7cddfSDavid du Colombier if(dstate != nil){
2317dd7cddfSDavid du Colombier digest = digbuf;
2327dd7cddfSDavid du Colombier sha1(nil, 0, shadig, dstate);
2337dd7cddfSDavid du Colombier for(i = 0; i < SHA1dlen; i++)
2347dd7cddfSDavid du Colombier snprint(digest+2*i, NDigest+1-2*i, "%2.2ux", shadig[i]);
2357dd7cddfSDavid du Colombier }
2367dd7cddfSDavid du Colombier if(ok){
2377dd7cddfSDavid du Colombier fd = cdOpen(mboxDir, impName(dst), OWRITE);
2387dd7cddfSDavid du Colombier if(fd < 0)
2397dd7cddfSDavid du Colombier fd = emptyImp(dst);
2407dd7cddfSDavid du Colombier if(fd >= 0){
2417dd7cddfSDavid du Colombier seek(fd, 0, 2);
2427dd7cddfSDavid du Colombier wrImpFlags(buf, flags, 1);
2437dd7cddfSDavid du Colombier fprint(fd, "%.*s %.*lud %s\n", NDigest, digest, NUid, 0UL, buf);
2447dd7cddfSDavid du Colombier close(fd);
2457dd7cddfSDavid du Colombier }
2467dd7cddfSDavid du Colombier }
2477dd7cddfSDavid du Colombier mbUnlock(ml);
2487dd7cddfSDavid du Colombier return 1;
2497dd7cddfSDavid du Colombier }
2507dd7cddfSDavid du Colombier
2517dd7cddfSDavid du Colombier static int
saveb(int fd,DigestState * dstate,char * buf,int nr,int nw)2527dd7cddfSDavid du Colombier saveb(int fd, DigestState *dstate, char *buf, int nr, int nw)
2537dd7cddfSDavid du Colombier {
2547dd7cddfSDavid du Colombier if(dstate != nil)
2557dd7cddfSDavid du Colombier sha1((uchar*)buf, nr, nil, dstate);
2567dd7cddfSDavid du Colombier if(write(fd, buf, nw) != nw)
2577dd7cddfSDavid du Colombier return 0;
2587dd7cddfSDavid du Colombier return 1;
2597dd7cddfSDavid du Colombier }
260