165 lines
2.5 KiB
C
165 lines
2.5 KiB
C
#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;
|
|
}
|
|
|
|
/* should only be called at start of file or when b->rp[-1] == '\n' */
|
|
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;
|
|
}
|
|
|
|
enum { Fromlen = sizeof "From " - 1, };
|
|
|
|
/* code to escape ' '*From' ' at the beginning of a line */
|
|
int
|
|
appendfiletombox(int in, int out)
|
|
{
|
|
int addspace, n, sol;
|
|
char *p;
|
|
Inbuf *b;
|
|
|
|
seek(out, 0, 2);
|
|
|
|
b = allocinbuf(in, out);
|
|
addspace = 0;
|
|
sol = 1;
|
|
|
|
for(;;){
|
|
if(b->wp - b->rp < Fromlen){
|
|
/*
|
|
* not enough unread bytes in buffer to match "From ",
|
|
* so get some more. We must only inject a space at
|
|
* the start of a line (one that begins with "From ").
|
|
*/
|
|
if (b->rp == b->buf || b->rp[-1] == '\n') {
|
|
n = fill(b, addspace);
|
|
addspace = 0;
|
|
} else
|
|
n = fill(b, 0);
|
|
if(n < 0)
|
|
goto error;
|
|
if(n == 0)
|
|
break;
|
|
if(n < Fromlen){ /* still can't match? */
|
|
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 ", Fromlen) != 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;
|
|
}
|