summaryrefslogtreecommitdiff
path: root/sys/src/cmd/upas/imap4d/copy.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/src/cmd/upas/imap4d/copy.c')
-rw-r--r--sys/src/cmd/upas/imap4d/copy.c248
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;
+}