#include "common.h" enum { Buffersize = 64*1024, }; typedef struct Inbuf Inbuf; struct Inbuf { char buf[Buffersize]; char *wp; char *rp; int eof; int in; int out; int last; ulong bytes; }; static Inbuf* allocinbuf(int in, int out) { Inbuf *b; b = mallocz(sizeof(Inbuf), 1); if(b == nil) sysfatal("reading mailbox: %r"); b->rp = b->wp = b->buf; b->in = in; b->out = out; return b; } static int fill(Inbuf *b, int addspace) { int i, n; if(b->eof && b->wp - b->rp == 0) return 0; n = b->rp - b->buf; if(n > 0){ i = write(b->out, b->buf, n); if(i != n) return -1; b->last = b->buf[n-1]; b->bytes += n; } if(addspace){ if(write(b->out, " ", 1) != 1) return -1; b->last = ' '; b->bytes++; } n = b->wp - b->rp; memmove(b->buf, b->rp, n); b->rp = b->buf; b->wp = b->rp + n; i = read(b->in, b->buf+n, sizeof(b->buf)-n); if(i < 0) return -1; b->wp += i; return b->wp - b->rp; } /* code to escape ' '*From' ' at the beginning of a line */ int appendfiletombox(int in, int out) { int addspace; int n; char *p; int sol; Inbuf *b; seek(out, 0, 2); b = allocinbuf(in, out); addspace = 0; sol = 1; for(;;){ if(b->wp - b->rp < 5){ n = fill(b, addspace); addspace = 0; if(n < 0) goto error; if(n == 0) break; if(n < 5){ b->rp = b->wp; continue; } } /* state machine looking for ' '*From' ' */ if(!sol){ p = memchr(b->rp, '\n', b->wp - b->rp); if(p == nil) b->rp = b->wp; else{ b->rp = p+1; sol = 1; } continue; } else { if(*b->rp == ' ' || strncmp(b->rp, "From ", 5) != 0){ b->rp++; continue; } addspace = 1; sol = 0; } } /* mailbox entries always terminate with two newlines */ n = b->last == '\n' ? 1 : 2; if(write(out, "\n\n", n) != n) goto error; n += b->bytes; free(b); return n; error: free(b); return -1; } int appendfiletofile(int in, int out) { int n; Inbuf *b; seek(out, 0, 2); b = allocinbuf(in, out); for(;;){ n = fill(b, 0); if(n < 0) goto error; if(n == 0) break; b->rp = b->wp; } n = b->bytes; free(b); return n; error: free(b); return -1; }