#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;
}
|