diff options
Diffstat (limited to 'sys/src/cmd/upas/imap4d/copy.c')
-rw-r--r-- | sys/src/cmd/upas/imap4d/copy.c | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/sys/src/cmd/upas/imap4d/copy.c b/sys/src/cmd/upas/imap4d/copy.c new file mode 100644 index 000000000..5d6376935 --- /dev/null +++ b/sys/src/cmd/upas/imap4d/copy.c @@ -0,0 +1,248 @@ +#include "imap4d.h" +#include <libsec.h> + +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; +} |