#include "imap4d.h" #include int copycheck(Box*, Msg *m, int, void *) { int fd; if(m->expunged) return 0; fd = msgfile(m, "rawunix"); if(fd < 0){ msgdead(m); return 0; } close(fd); return 1; } static int opendeliver(int *pip, char *folder, char *from, long t) { char *av[7], buf[32]; int i, pid, fd[2]; if(pipe(fd) != 0) sysfatal("pipe: %r"); pid = fork(); switch(pid){ case -1: return -1; case 0: av[0] = "mbappend"; av[1] = folder; i = 2; if(from){ av[i++] = "-f"; av[i++] = from; } if(t != 0){ snprint(buf, sizeof buf, "%ld", t); av[i++] = "-t"; av[i++] = buf; } av[i] = 0; close(0); dup(fd[1], 0); if(fd[1] != 0) close(fd[1]); close(fd[0]); exec("/bin/upas/mbappend", av); ilog("exec: %r"); _exits("b0rked"); return -1; default: *pip = fd[0]; close(fd[1]); return pid; } } static int closedeliver(int pid, int fd) { int nz, wpid; Waitmsg *w; close(fd); while(w = wait()){ nz = !w->msg || !w->msg[0]; wpid = w->pid; free(w); if(wpid == pid) return nz? 0: -1; } return -1; } /* * we're going to all this trouble of fiddling the .imp file for * the target mailbox because we wish to save the flags. we * should be using upas/fs's flags instead. * * note. appendmb for mbox fmt wants to lock the directory. * since the locking is intentionally broken, we could get by * with aquiring the lock before we fire up appendmb and * trust that he doesn't worry if he does acquire the lock. * instead, we'll just do locking around the .imp file. */ static int savemsg(char *dst, int flags, char *head, int nhead, Biobuf *b, long n, Uidplus *u) { char *digest, buf[Bufsize + 1], digbuf[Ndigest + 1], folder[Pathlen]; uchar shadig[SHA1dlen]; int i, fd, pid, nr, ok; DigestState *dstate; Mblock *ml; snprint(folder, sizeof folder, "%s/%s", mboxdir, dst); pid = opendeliver(&fd, folder, 0, 0); if(pid == -1) return 0; ok = 1; dstate = sha1(nil, 0, nil, nil); if(nhead){ sha1((uchar*)head, nhead, nil, dstate); if(write(fd, head, nhead) != nhead){ ok = 0; goto loose; } } while(n > 0){ nr = n; if(nr > Bufsize) nr = Bufsize; nr = Bread(b, buf, nr); if(nr <= 0){ ok = 0; break; } n -= nr; sha1((uchar*)buf, nr, nil, dstate); if(write(fd, buf, nr) != nr){ ok = 0; break; } } loose: closedeliver(pid, fd); sha1(nil, 0, shadig, dstate); if(ok){ digest = digbuf; for(i = 0; i < SHA1dlen; i++) sprint(digest + 2*i, "%2.2ux", shadig[i]); ml = mblock(); if(ml == nil) return 0; ok = appendimp(dst, digest, flags, u) == 0; mbunlock(ml); } return ok; } static int copysave(Box*, Msg *m, int, void *vs, Uidplus *u) { int ok, fd; vlong length; Biobuf b; Dir *d; if(m->expunged) return 0; if((fd = msgfile(m, "rawunix")) == -1){ msgdead(m); return 0; } if((d = dirfstat(fd)) == nil){ close(fd); return 0; } length = d->length; free(d); Binit(&b, fd, OREAD); ok = savemsg(vs, m->flags, 0, 0, &b, length, u); Bterm(&b); close(fd); return ok; } int copysaveu(Box *box, Msg *m, int i, void *vs) { int ok; Uidplus *u; u = binalloc(&parsebin, sizeof *u, 1); ok = copysave(box, m, i, vs, u); *uidtl = u; uidtl = &u->next; return ok; } /* * first spool the input into a temorary file, * and massage the input in the process. * then save to real box. */ /* * copy from bin to bout, * map "\r\n" to "\n" and * return the number of bytes in the mapped file. * * exactly n bytes must be read from the input, * unless an input error occurs. */ static long spool(Biobuf *bout, Biobuf *bin, long n) { int c; while(n > 0){ c = Bgetc(bin); n--; if(c == '\r' && n-- > 0){ c = Bgetc(bin); if(c != '\n') Bputc(bout, '\r'); } if(c < 0) return -1; if(Bputc(bout, c) < 0) return -1; } if(Bflush(bout) < 0) return -1; return Boffset(bout); } int appendsave(char *mbox, int flags, char *head, Biobuf *b, long n, Uidplus *u) { int fd, ok; Biobuf btmp; fd = imaptmp(); if(fd < 0) return 0; Bprint(&bout, "+ Ready for literal data\r\n"); if(Bflush(&bout) < 0) writeerr(); Binit(&btmp, fd, OWRITE); n = spool(&btmp, b, n); Bterm(&btmp); if(n < 0){ close(fd); return 0; } seek(fd, 0, 0); Binit(&btmp, fd, OREAD); ok = savemsg(mbox, flags, head, strlen(head), &btmp, n, u); Bterm(&btmp); close(fd); return ok; }