Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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