1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 2003-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 
24 /*
25  * quoted printable coder
26  */
27 
28 #include <codex.h>
29 #include <ctype.h>
30 #include <ccode.h>
31 
32 #define LINE		76
33 #define BUFFER		SF_BUFSIZE
34 
35 typedef struct State_s
36 {
37 	Codex_t*	codex;
38 
39 	unsigned char*	bp;
40 	unsigned char*	be;
41 
42 	unsigned char*	pp;
43 	unsigned char	prv[5];
44 
45 	short		xxx;
46 	short		xeh[UCHAR_MAX+1];
47 
48 	int		col;
49 
50 	unsigned char	buf[LINE + BUFFER + 1];
51 } State_t;
52 
53 static const char	hex[] = "0123456789ABCDEFabcdef";
54 
55 #define GETCHAR(p)	((p)->bp < (p)->be ? (int)*(p)->bp++ : fill(p))
56 #define PUTCHAR(p,c)	((p)->bp < (p)->be ? (int)(*(p)->bp++=(c)) : flush(p,c))
57 
58 static int
fill(State_t * state)59 fill(State_t* state)
60 {
61 	ssize_t	r;
62 
63 	state->bp = state->buf + LINE;
64 	if ((r = sfrd(state->codex->sp, state->bp, BUFFER, &state->codex->sfdisc)) <= 0)
65 	{
66 		state->be = state->bp;
67 		return EOF;
68 	}
69 	state->be = state->bp + r;
70 	return *state->bp++;
71 }
72 
73 static int
flush(register State_t * state,int c)74 flush(register State_t* state, int c)
75 {
76 	size_t	n;
77 
78 	if (c < 0 && state->col)
79 	{
80 		state->col = 0;
81 		PUTCHAR(state, '=');
82 		PUTCHAR(state, '\n');
83 	}
84 	if (state->bp && (n = state->bp - state->buf) && sfwr(state->codex->sp, state->buf, n, &state->codex->sfdisc) != n)
85 		return EOF;
86 	state->be = (state->bp = state->buf) + sizeof(state->buf);
87 	if (c >= 0)
88 		*state->bp++ = c;
89 	return 0;
90 }
91 
92 static int
qp_open(Codex_t * p,char * const args[],Codexnum_t flags)93 qp_open(Codex_t* p, char* const args[], Codexnum_t flags)
94 {
95 	register State_t*	state;
96 	register int		i;
97 
98 	if (!(state = newof(0, State_t, 1, 0)))
99 	{
100 		if (p->disc->errorf)
101 			(*p->disc->errorf)(NiL, p->disc, 2, "out of space");
102 		return -1;
103 	}
104 	if (flags & CODEX_DECODE)
105 	{
106 		for (i = -1; i < elementsof(state->xeh); i++)
107 			state->xeh[i] = -1;
108 		for (i = 0; i < elementsof(hex) - 1; i++)
109 			state->xeh[hex[i]] = i >= 16 ? (i - 6) : i;
110 	}
111 	p->data = state;
112 	state->codex = p;
113 	return 0;
114 }
115 
116 static ssize_t
qp_read(Sfio_t * sp,void * buf,size_t n,Sfdisc_t * disc)117 qp_read(Sfio_t* sp, void* buf, size_t n, Sfdisc_t* disc)
118 {
119 	register State_t*	state = (State_t*)CODEX(disc)->data;
120 	register char*		s = (char*)buf;
121 	register char*		e = s + n;
122 	register char*		x;
123 	register int		c;
124 	register int		d;
125 
126 	x = 0;
127 	while (s < e)
128 	{
129 		switch (c = GETCHAR(state))
130 		{
131 		case '=':
132 			if ((c = GETCHAR(state)) == '\n')
133 				continue;
134 			if ((d = state->xeh[c]) != EOF && (c = state->xeh[GETCHAR(state)]) != EOF)
135 			{
136 				c |= (d << 4);
137 				x = 0;
138 				break;
139 			}
140 			/*FALLTHROUGH*/
141 		case EOF:
142 			return s - (char*)buf;
143 		case '\n':
144 			if (x)
145 			{
146 				s = x;
147 				x = 0;
148 			}
149 			break;
150 		case ' ':
151 		case '\t':
152 		case '\r':
153 			if (!x)
154 				x = s;
155 			break;
156 		default:
157 			x = 0;
158 			break;
159 		}
160 		*s++ = c;
161 	}
162 	if (x)
163 		while (s > x && state->bp > state->buf)
164 			*--state->bp = *--s;
165 	return s - (char*)buf;
166 }
167 
168 static ssize_t
qp_write(Sfio_t * sp,const void * buf,size_t n,Sfdisc_t * disc)169 qp_write(Sfio_t* sp, const void* buf, size_t n, Sfdisc_t* disc)
170 {
171 	register State_t*	state = (State_t*)CODEX(disc)->data;
172 	register unsigned char*	s;
173 	register unsigned char*	e;
174 	register int		c;
175 	register int		col;
176 
177  again:
178 	if (state->pp)
179 	{
180 		s = state->prv;
181 		e = state->pp;
182 		state->col = 0;
183 	}
184 	else
185 	{
186 		s = (unsigned char*)buf;
187 		e = s + n;
188 		col = state->col;
189 	}
190 	for (;;)
191 	{
192 		if (s >= e)
193 		{
194 			if (state->pp)
195 			{
196 				state->pp = 0;
197 				state->col = col;
198 				goto again;
199 			}
200 			break;
201 		}
202 		c = *s++;
203 		if (!col++)
204 		{
205 			if (c == 'F')
206 			{
207 				if ((e - s) < 4)
208 				{
209 					s--;
210 					col--;
211 					state->pp = state->prv;
212 					for (c = 0; c < (e - s); ++c)
213 						*state->pp++ = s[c];
214 					break;
215 				}
216 				else if (s[0] == 'r' && s[1] == 'o' && s[2] == 'm' && s[3] == ' ')
217 					goto quote;
218 			}
219 			else if (c == '.')
220 			{
221 				if ((e - s) < 1)
222 				{
223 					s--;
224 					col--;
225 					state->pp = state->prv;
226 					*state->pp++ = c;
227 					break;
228 				}
229 				else if (s[0] == '\r' || s[0] == '\n')
230 					goto quote;
231 			}
232 		}
233 		if (c == '\n')
234 		{
235 			col = 0;
236 			PUTCHAR(state, c);
237 			continue;
238 		}
239 		else if (col >= (LINE - 4))
240 		{
241 			col = 0;
242 			PUTCHAR(state, '=');
243 			PUTCHAR(state, '\n');
244 		}
245 		if (c == ' ' || c == '\t')
246 		{
247 			if ((e - s) < 1)
248 			{
249 				s--;
250 				col--;
251 				state->pp = state->prv;
252 				*state->pp++ = c;
253 				break;
254 			}
255 			else if (s[0] == '\r' || s[0] == '\n')
256 				goto quote;
257 			else
258 			{
259 				if (c == '\t')
260 					col |= 7;
261 				PUTCHAR(state, c);
262 				continue;
263 			}
264 		}
265 #if CC_NATIVE == CC_ASCII
266 		else if (c >= 0x21 && c <= 0x7e && c != '=')
267 #else
268 		else if (isprint(c) && !iscntrl(c) && c != '=')
269 #endif
270 		{
271 			PUTCHAR(state, c);
272 			continue;
273 		}
274 	quote:
275 		col += 2;
276 		PUTCHAR(state, '=');
277 		PUTCHAR(state, hex[(c >> 4) & 0xF]);
278 		PUTCHAR(state, hex[c & 0xF]);
279 	}
280 	state->col = col;
281 	return n;
282 }
283 
284 static int
qp_sync(Codex_t * p)285 qp_sync(Codex_t* p)
286 {
287 	return flush((State_t*)p->data, -1);
288 }
289 
290 Codexmeth_t	codex_qp =
291 {
292 	"qp",
293 	"quoted printable encoding.",
294 	"[+(version)?codex-qp (AT&T Research) 1998-11-11]"
295 	"[+(author)?Glenn Fowler <gsf@research.att.com>]",
296 	CODEX_DECODE|CODEX_ENCODE|CODEX_UU,
297 	0,
298 	0,
299 	qp_open,
300 	0,
301 	0,
302 	0,
303 	qp_read,
304 	qp_write,
305 	qp_sync,
306 	0,
307 	0,
308 	0,
309 	0,
310 	CODEXNEXT(qp)
311 };
312 
313 CODEXLIB(qp)
314