123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <auth.h>
- #include <libsec.h>
- #include "imap4d.h"
- static int saveMsg(char *dst, char *digest, int flags, char *head, int nhead, Biobuf *b, long n);
- static int saveb(int fd, DigestState *dstate, char *buf, int nr, int nw);
- static long appSpool(Biobuf *bout, Biobuf *bin, long n);
- /*
- * check if the message exists
- */
- int
- copyCheck(Box *box, Msg *m, int uids, void *v)
- {
- int fd;
- USED(box);
- USED(uids);
- USED(v);
- if(m->expunged)
- return 0;
- fd = msgFile(m, "raw");
- if(fd < 0){
- msgDead(m);
- return 0;
- }
- close(fd);
- return 1;
- }
- int
- copySave(Box *box, Msg *m, int uids, void *vs)
- {
- Dir *d;
- Biobuf b;
- vlong length;
- char *head;
- int ok, hfd, bfd, nhead;
- USED(box);
- USED(uids);
- if(m->expunged)
- return 0;
- hfd = msgFile(m, "unixheader");
- if(hfd < 0){
- msgDead(m);
- return 0;
- }
- head = readFile(hfd);
- if(head == nil){
- close(hfd);
- return 0;
- }
- /*
- * clear out the header if it doesn't end in a newline,
- * since it is a runt and the "header" will show up in the raw file.
- */
- nhead = strlen(head);
- if(nhead > 0 && head[nhead-1] != '\n')
- nhead = 0;
- bfd = msgFile(m, "raw");
- close(hfd);
- if(bfd < 0){
- msgDead(m);
- return 0;
- }
- d = dirfstat(bfd);
- if(d == nil){
- close(bfd);
- return 0;
- }
- length = d->length;
- free(d);
- Binit(&b, bfd, OREAD);
- ok = saveMsg(vs, m->info[IDigest], m->flags, head, nhead, &b, length);
- Bterm(&b);
- close(bfd);
- return ok;
- }
- /*
- * first spool the input into a temorary file,
- * and massage the input in the process.
- * then save to real box.
- */
- int
- appendSave(char *mbox, int flags, char *head, Biobuf *b, long n)
- {
- Biobuf btmp;
- int fd, ok;
- 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 = appSpool(&btmp, b, n);
- Bterm(&btmp);
- if(n < 0){
- close(fd);
- return 0;
- }
- seek(fd, 0, 0);
- Binit(&btmp, fd, OREAD);
- ok = saveMsg(mbox, nil, flags, head, strlen(head), &btmp, n);
- Bterm(&btmp);
- close(fd);
- return ok;
- }
- /*
- * copy from bin to bout,
- * mapping "\r\n" to "\n" and "\nFrom " to "\n From "
- * 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
- appSpool(Biobuf *bout, Biobuf *bin, long n)
- {
- int i, c;
- c = '\n';
- while(n > 0){
- if(c == '\n' && n >= STRLEN("From ")){
- for(i = 0; i < STRLEN("From "); i++){
- c = Bgetc(bin);
- if(c != "From "[i]){
- if(c < 0)
- return -1;
- Bungetc(bin);
- break;
- }
- n--;
- }
- if(i == STRLEN("From "))
- Bputc(bout, ' ');
- Bwrite(bout, "From ", i);
- }
- 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(c != '\n')
- Bputc(bout, '\n');
- if(Bflush(bout) < 0)
- return -1;
- return Boffset(bout);
- }
- static int
- saveMsg(char *dst, char *digest, int flags, char *head, int nhead, Biobuf *b, long n)
- {
- DigestState *dstate;
- MbLock *ml;
- uchar shadig[SHA1dlen];
- char buf[BufSize + 1], digbuf[NDigest + 1];
- int i, fd, nr, nw, ok;
- ml = mbLock();
- if(ml == nil)
- return 0;
- fd = openLocked(mboxDir, dst, OWRITE);
- if(fd < 0){
- mbUnlock(ml);
- return 0;
- }
- seek(fd, 0, 2);
- dstate = nil;
- if(digest == nil)
- dstate = sha1(nil, 0, nil, nil);
- if(!saveb(fd, dstate, head, nhead, nhead)){
- if(dstate != nil)
- sha1(nil, 0, shadig, dstate);
- mbUnlock(ml);
- close(fd);
- return 0;
- }
- ok = 1;
- if(n == 0)
- ok = saveb(fd, dstate, "\n", 0, 1);
- while(n > 0){
- nr = n;
- if(nr > BufSize)
- nr = BufSize;
- nr = Bread(b, buf, nr);
- if(nr <= 0){
- saveb(fd, dstate, "\n\n", 0, 2);
- ok = 0;
- break;
- }
- n -= nr;
- nw = nr;
- if(n == 0){
- if(buf[nw - 1] != '\n')
- buf[nw++] = '\n';
- buf[nw++] = '\n';
- }
- if(!saveb(fd, dstate, buf, nr, nw)){
- ok = 0;
- break;
- }
- mbLockRefresh(ml);
- }
- close(fd);
- if(dstate != nil){
- digest = digbuf;
- sha1(nil, 0, shadig, dstate);
- for(i = 0; i < SHA1dlen; i++)
- snprint(digest+2*i, NDigest+1-2*i, "%2.2ux", shadig[i]);
- }
- if(ok){
- fd = cdOpen(mboxDir, impName(dst), OWRITE);
- if(fd < 0)
- fd = emptyImp(dst);
- if(fd >= 0){
- seek(fd, 0, 2);
- wrImpFlags(buf, flags, 1);
- fprint(fd, "%.*s %.*lud %s\n", NDigest, digest, NUid, 0UL, buf);
- close(fd);
- }
- }
- mbUnlock(ml);
- return 1;
- }
- static int
- saveb(int fd, DigestState *dstate, char *buf, int nr, int nw)
- {
- if(dstate != nil)
- sha1((uchar*)buf, nr, nil, dstate);
- if(write(fd, buf, nw) != nw)
- return 0;
- return 1;
- }
|