1ba64361bSDavid du Colombier #include "common.h"
2ba64361bSDavid du Colombier
3ba64361bSDavid du Colombier enum {
4ba64361bSDavid du Colombier Buffersize = 64*1024,
5ba64361bSDavid du Colombier };
6ba64361bSDavid du Colombier
7ba64361bSDavid du Colombier typedef struct Inbuf Inbuf;
8ba64361bSDavid du Colombier struct Inbuf
9ba64361bSDavid du Colombier {
10ba64361bSDavid du Colombier char buf[Buffersize];
11ba64361bSDavid du Colombier char *wp;
12ba64361bSDavid du Colombier char *rp;
13ba64361bSDavid du Colombier int eof;
14ba64361bSDavid du Colombier int in;
15ba64361bSDavid du Colombier int out;
16ba64361bSDavid du Colombier int last;
17ba64361bSDavid du Colombier ulong bytes;
18ba64361bSDavid du Colombier };
19ba64361bSDavid du Colombier
20ba64361bSDavid du Colombier static Inbuf*
allocinbuf(int in,int out)21ba64361bSDavid du Colombier allocinbuf(int in, int out)
22ba64361bSDavid du Colombier {
23ba64361bSDavid du Colombier Inbuf *b;
24ba64361bSDavid du Colombier
25ba64361bSDavid du Colombier b = mallocz(sizeof(Inbuf), 1);
26ba64361bSDavid du Colombier if(b == nil)
27ba64361bSDavid du Colombier sysfatal("reading mailbox: %r");
28ba64361bSDavid du Colombier b->rp = b->wp = b->buf;
29ba64361bSDavid du Colombier b->in = in;
30ba64361bSDavid du Colombier b->out = out;
31ba64361bSDavid du Colombier return b;
32ba64361bSDavid du Colombier }
33ba64361bSDavid du Colombier
34*707451d0SDavid du Colombier /* should only be called at start of file or when b->rp[-1] == '\n' */
35ba64361bSDavid du Colombier static int
fill(Inbuf * b,int addspace)36ba64361bSDavid du Colombier fill(Inbuf *b, int addspace)
37ba64361bSDavid du Colombier {
38ba64361bSDavid du Colombier int i, n;
39ba64361bSDavid du Colombier
40ba64361bSDavid du Colombier if(b->eof && b->wp - b->rp == 0)
41ba64361bSDavid du Colombier return 0;
42ba64361bSDavid du Colombier
43ba64361bSDavid du Colombier n = b->rp - b->buf;
44ba64361bSDavid du Colombier if(n > 0){
45ba64361bSDavid du Colombier i = write(b->out, b->buf, n);
46ba64361bSDavid du Colombier if(i != n)
47ba64361bSDavid du Colombier return -1;
48ba64361bSDavid du Colombier b->last = b->buf[n-1];
49ba64361bSDavid du Colombier b->bytes += n;
50ba64361bSDavid du Colombier }
51ba64361bSDavid du Colombier if(addspace){
52ba64361bSDavid du Colombier if(write(b->out, " ", 1) != 1)
53ba64361bSDavid du Colombier return -1;
54ba64361bSDavid du Colombier b->last = ' ';
55ba64361bSDavid du Colombier b->bytes++;
56ba64361bSDavid du Colombier }
57ba64361bSDavid du Colombier
58ba64361bSDavid du Colombier n = b->wp - b->rp;
59ba64361bSDavid du Colombier memmove(b->buf, b->rp, n);
60ba64361bSDavid du Colombier b->rp = b->buf;
61ba64361bSDavid du Colombier b->wp = b->rp + n;
62ba64361bSDavid du Colombier
63ba64361bSDavid du Colombier i = read(b->in, b->buf+n, sizeof(b->buf)-n);
64ba64361bSDavid du Colombier if(i < 0)
65ba64361bSDavid du Colombier return -1;
66ba64361bSDavid du Colombier b->wp += i;
67ba64361bSDavid du Colombier
68ba64361bSDavid du Colombier return b->wp - b->rp;
69ba64361bSDavid du Colombier }
70ba64361bSDavid du Colombier
71*707451d0SDavid du Colombier enum { Fromlen = sizeof "From " - 1, };
72*707451d0SDavid du Colombier
73ba64361bSDavid du Colombier /* code to escape ' '*From' ' at the beginning of a line */
74ba64361bSDavid du Colombier int
appendfiletombox(int in,int out)75ba64361bSDavid du Colombier appendfiletombox(int in, int out)
76ba64361bSDavid du Colombier {
77*707451d0SDavid du Colombier int addspace, n, sol;
78ba64361bSDavid du Colombier char *p;
79ba64361bSDavid du Colombier Inbuf *b;
80ba64361bSDavid du Colombier
81ba64361bSDavid du Colombier seek(out, 0, 2);
82ba64361bSDavid du Colombier
83ba64361bSDavid du Colombier b = allocinbuf(in, out);
84ba64361bSDavid du Colombier addspace = 0;
85ba64361bSDavid du Colombier sol = 1;
86ba64361bSDavid du Colombier
87ba64361bSDavid du Colombier for(;;){
88*707451d0SDavid du Colombier if(b->wp - b->rp < Fromlen){
89*707451d0SDavid du Colombier /*
90*707451d0SDavid du Colombier * not enough unread bytes in buffer to match "From ",
91*707451d0SDavid du Colombier * so get some more. We must only inject a space at
92*707451d0SDavid du Colombier * the start of a line (one that begins with "From ").
93*707451d0SDavid du Colombier */
94*707451d0SDavid du Colombier if (b->rp == b->buf || b->rp[-1] == '\n') {
95ba64361bSDavid du Colombier n = fill(b, addspace);
96ba64361bSDavid du Colombier addspace = 0;
97*707451d0SDavid du Colombier } else
98*707451d0SDavid du Colombier n = fill(b, 0);
99ba64361bSDavid du Colombier if(n < 0)
100ba64361bSDavid du Colombier goto error;
101ba64361bSDavid du Colombier if(n == 0)
102ba64361bSDavid du Colombier break;
103*707451d0SDavid du Colombier if(n < Fromlen){ /* still can't match? */
104ba64361bSDavid du Colombier b->rp = b->wp;
105ba64361bSDavid du Colombier continue;
106ba64361bSDavid du Colombier }
107ba64361bSDavid du Colombier }
108ba64361bSDavid du Colombier
109ba64361bSDavid du Colombier /* state machine looking for ' '*From' ' */
110ba64361bSDavid du Colombier if(!sol){
111ba64361bSDavid du Colombier p = memchr(b->rp, '\n', b->wp - b->rp);
112ba64361bSDavid du Colombier if(p == nil)
113ba64361bSDavid du Colombier b->rp = b->wp;
114ba64361bSDavid du Colombier else{
115ba64361bSDavid du Colombier b->rp = p+1;
116ba64361bSDavid du Colombier sol = 1;
117ba64361bSDavid du Colombier }
118ba64361bSDavid du Colombier continue;
119ba64361bSDavid du Colombier } else {
120*707451d0SDavid du Colombier if(*b->rp == ' ' || strncmp(b->rp, "From ", Fromlen) != 0){
121ba64361bSDavid du Colombier b->rp++;
122ba64361bSDavid du Colombier continue;
123ba64361bSDavid du Colombier }
124ba64361bSDavid du Colombier addspace = 1;
125ba64361bSDavid du Colombier sol = 0;
126ba64361bSDavid du Colombier }
127ba64361bSDavid du Colombier }
128ba64361bSDavid du Colombier
129ba64361bSDavid du Colombier /* mailbox entries always terminate with two newlines */
130ba64361bSDavid du Colombier n = b->last == '\n' ? 1 : 2;
131ba64361bSDavid du Colombier if(write(out, "\n\n", n) != n)
132ba64361bSDavid du Colombier goto error;
133ba64361bSDavid du Colombier n += b->bytes;
134ba64361bSDavid du Colombier free(b);
135ba64361bSDavid du Colombier return n;
136ba64361bSDavid du Colombier error:
137ba64361bSDavid du Colombier free(b);
138ba64361bSDavid du Colombier return -1;
139ba64361bSDavid du Colombier }
140ba64361bSDavid du Colombier
141ba64361bSDavid du Colombier int
appendfiletofile(int in,int out)142ba64361bSDavid du Colombier appendfiletofile(int in, int out)
143ba64361bSDavid du Colombier {
144ba64361bSDavid du Colombier int n;
145ba64361bSDavid du Colombier Inbuf *b;
146ba64361bSDavid du Colombier
147ba64361bSDavid du Colombier seek(out, 0, 2);
148ba64361bSDavid du Colombier
149ba64361bSDavid du Colombier b = allocinbuf(in, out);
150ba64361bSDavid du Colombier for(;;){
151ba64361bSDavid du Colombier n = fill(b, 0);
152ba64361bSDavid du Colombier if(n < 0)
153ba64361bSDavid du Colombier goto error;
154ba64361bSDavid du Colombier if(n == 0)
155ba64361bSDavid du Colombier break;
156ba64361bSDavid du Colombier b->rp = b->wp;
157ba64361bSDavid du Colombier }
158ba64361bSDavid du Colombier n = b->bytes;
159ba64361bSDavid du Colombier free(b);
160ba64361bSDavid du Colombier return n;
161ba64361bSDavid du Colombier error:
162ba64361bSDavid du Colombier free(b);
163ba64361bSDavid du Colombier return -1;
164ba64361bSDavid du Colombier }
165