14bd5da82SAxel Dörfler/*
24bd5da82SAxel Dörfler * Copyright 2011, Haiku, Inc. All rights reserved.
34bd5da82SAxel Dörfler * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
44bd5da82SAxel Dörfler */
54bd5da82SAxel Dörfler
64bd5da82SAxel Dörfler
7f7215ac8SNathan Whitehorn#include <ctype.h>
8f7215ac8SNathan Whitehorn#include <string.h>
93aeed660SJérôme Duval#include <strings.h>
10f7215ac8SNathan Whitehorn
114bd5da82SAxel Dörfler#include <SupportDefs.h>
124bd5da82SAxel Dörfler
13f7215ac8SNathan Whitehorn#include <mail_encoding.h>
14f7215ac8SNathan Whitehorn
15f7215ac8SNathan Whitehorn
164bd5da82SAxel Dörfler#define	DEC(c) (((c) - ' ') & 077)
174bd5da82SAxel Dörfler
18f7215ac8SNathan Whitehorn
194bd5da82SAxel Dörflerstatic const char kHexAlphabet[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
204bd5da82SAxel Dörfler	'8','9','A','B','C','D','E','F'};
21f7215ac8SNathan Whitehorn
22f7215ac8SNathan Whitehorn
234bd5da82SAxel Dörflerssize_t
244bd5da82SAxel Dörflerencode(mail_encoding encoding, char *out, const char *in, off_t length,
254bd5da82SAxel Dörfler	int headerMode)
26f7215ac8SNathan Whitehorn{
27f7215ac8SNathan Whitehorn	switch (encoding) {
28f7215ac8SNathan Whitehorn		case base64:
29f7215ac8SNathan Whitehorn			return encode_base64(out,in,length,headerMode);
30f7215ac8SNathan Whitehorn		case quoted_printable:
31f7215ac8SNathan Whitehorn			return encode_qp(out,in,length,headerMode);
32f7215ac8SNathan Whitehorn		case seven_bit:
33f7215ac8SNathan Whitehorn		case eight_bit:
34f7215ac8SNathan Whitehorn		case no_encoding:
35f7215ac8SNathan Whitehorn			memcpy(out,in,length);
36f7215ac8SNathan Whitehorn			return length;
37f7215ac8SNathan Whitehorn		case uuencode:
38f7215ac8SNathan Whitehorn		default:
39f7215ac8SNathan Whitehorn			return -1;
40f7215ac8SNathan Whitehorn	}
414bd5da82SAxel Dörfler
42f7215ac8SNathan Whitehorn	return -1;
43f7215ac8SNathan Whitehorn}
44f7215ac8SNathan Whitehorn
454bd5da82SAxel Dörfler
464bd5da82SAxel Dörflerssize_t
474bd5da82SAxel Dörflerdecode(mail_encoding encoding, char *out, const char *in, off_t length,
484bd5da82SAxel Dörfler	int underscoreIsSpace)
49f7215ac8SNathan Whitehorn{
50f7215ac8SNathan Whitehorn	switch (encoding) {
51f7215ac8SNathan Whitehorn		case base64:
52f7215ac8SNathan Whitehorn			return decode_base64(out, in, length);
53f7215ac8SNathan Whitehorn		case uuencode:
54f7215ac8SNathan Whitehorn			return uu_decode(out, in, length);
55f7215ac8SNathan Whitehorn		case seven_bit:
56f7215ac8SNathan Whitehorn		case eight_bit:
57f7215ac8SNathan Whitehorn		case no_encoding:
58f7215ac8SNathan Whitehorn			memcpy(out, in, length);
59f7215ac8SNathan Whitehorn			return length;
60f7215ac8SNathan Whitehorn		case quoted_printable:
614bd5da82SAxel Dörfler			return decode_qp(out, in, length, underscoreIsSpace);
62f7215ac8SNathan Whitehorn		default:
63f7215ac8SNathan Whitehorn			break;
64f7215ac8SNathan Whitehorn	}
65f7215ac8SNathan Whitehorn
66f7215ac8SNathan Whitehorn	return -1;
67f7215ac8SNathan Whitehorn}
68f7215ac8SNathan Whitehorn
69f7215ac8SNathan Whitehorn
704bd5da82SAxel Dörflerssize_t
714bd5da82SAxel Dörflermax_encoded_length(mail_encoding encoding, off_t length)
72f7215ac8SNathan Whitehorn{
73f7215ac8SNathan Whitehorn	switch (encoding) {
74f7215ac8SNathan Whitehorn		case base64:
75f7215ac8SNathan Whitehorn		{
764bd5da82SAxel Dörfler			double result = length * 1.33333333333333;
774bd5da82SAxel Dörfler			result += (result / BASE64_LINELENGTH) * 2 + 20;
78f7215ac8SNathan Whitehorn			return (ssize_t)(result);
79f7215ac8SNathan Whitehorn		}
80f7215ac8SNathan Whitehorn		case quoted_printable:
814bd5da82SAxel Dörfler			return length * 3;
82f7215ac8SNathan Whitehorn		case seven_bit:
83f7215ac8SNathan Whitehorn		case eight_bit:
84f7215ac8SNathan Whitehorn		case no_encoding:
854bd5da82SAxel Dörfler			return length;
86f7215ac8SNathan Whitehorn		case uuencode:
87f7215ac8SNathan Whitehorn		default:
88f7215ac8SNathan Whitehorn			return -1;
89f7215ac8SNathan Whitehorn	}
904bd5da82SAxel Dörfler
91f7215ac8SNathan Whitehorn	return -1;
92f7215ac8SNathan Whitehorn}
93f7215ac8SNathan Whitehorn
94f7215ac8SNathan Whitehorn
954bd5da82SAxel Dörflermail_encoding
96f7215ac8SNathan Whitehornencoding_for_cte(const char *cte)
97f7215ac8SNathan Whitehorn{
98f7215ac8SNathan Whitehorn	if (cte == NULL)
99f7215ac8SNathan Whitehorn		return no_encoding;
1004bd5da82SAxel Dörfler
101f7215ac8SNathan Whitehorn	if (strcasecmp(cte,"uuencode") == 0)
102f7215ac8SNathan Whitehorn		return uuencode;
103f7215ac8SNathan Whitehorn	if (strcasecmp(cte,"base64") == 0)
104f7215ac8SNathan Whitehorn		return base64;
105f7215ac8SNathan Whitehorn	if (strcasecmp(cte,"quoted-printable") == 0)
106f7215ac8SNathan Whitehorn		return quoted_printable;
107f7215ac8SNathan Whitehorn	if (strcasecmp(cte,"7bit") == 0)
108f7215ac8SNathan Whitehorn		return seven_bit;
109f7215ac8SNathan Whitehorn	if (strcasecmp(cte,"8bit") == 0)
110f7215ac8SNathan Whitehorn		return eight_bit;
111f7215ac8SNathan Whitehorn
112f7215ac8SNathan Whitehorn	return no_encoding;
113f7215ac8SNathan Whitehorn}
114f7215ac8SNathan Whitehorn
115f7215ac8SNathan Whitehorn
1164bd5da82SAxel Dörflerssize_t
1174bd5da82SAxel Dörflerdecode_qp(char *out, const char *in, off_t length, int underscoreIsSpace)
118f7215ac8SNathan Whitehorn{
119f7215ac8SNathan Whitehorn	// decode Quoted Printable
120f7215ac8SNathan Whitehorn	char *dataout = out;
1214bd5da82SAxel Dörfler	const char *datain = in, *dataend = in + length;
1224bd5da82SAxel Dörfler
1234bd5da82SAxel Dörfler	while (datain < dataend) {
1244bd5da82SAxel Dörfler		if (*datain == '=' && dataend - datain > 2) {
1254bd5da82SAxel Dörfler			int a = toupper(datain[1]);
1264bd5da82SAxel Dörfler			a -= a >= '0' && a <= '9' ? '0' : (a >= 'A' && a <= 'F'
1274bd5da82SAxel Dörfler				? 'A' - 10 : a + 1);
1284bd5da82SAxel Dörfler
1294bd5da82SAxel Dörfler			int b = toupper(datain[2]);
1304bd5da82SAxel Dörfler			b -= b >= '0' && b <= '9' ? '0' : (b >= 'A' && b <= 'F'
1314bd5da82SAxel Dörfler				? 'A' - 10 : b + 1);
1324bd5da82SAxel Dörfler
1334bd5da82SAxel Dörfler			if (a >= 0 && b >= 0) {
1344bd5da82SAxel Dörfler				*dataout++ = (a << 4) + b;
135f7215ac8SNathan Whitehorn				datain += 3;
136f7215ac8SNathan Whitehorn				continue;
1374bd5da82SAxel Dörfler			} else if (datain[1] == '\r' && datain[2] == '\n') {
138f7215ac8SNathan Whitehorn				// strip =<CR><NL>
139f7215ac8SNathan Whitehorn				datain += 3;
140f7215ac8SNathan Whitehorn				continue;
141f7215ac8SNathan Whitehorn			}
1424bd5da82SAxel Dörfler		} else if (*datain == '_' && underscoreIsSpace) {
143f7215ac8SNathan Whitehorn			*dataout++ = ' ';
144f7215ac8SNathan Whitehorn			++datain;
145f7215ac8SNathan Whitehorn			continue;
146f7215ac8SNathan Whitehorn		}
1474bd5da82SAxel Dörfler
148f7215ac8SNathan Whitehorn		*dataout++ = *datain++;
149f7215ac8SNathan Whitehorn	}
1504bd5da82SAxel Dörfler
151f7215ac8SNathan Whitehorn	*dataout = '\0';
1524bd5da82SAxel Dörfler	return dataout - out;
153f7215ac8SNathan Whitehorn}
154f7215ac8SNathan Whitehorn
155f7215ac8SNathan Whitehorn
1564bd5da82SAxel Dörflerssize_t
157f7215ac8SNathan Whitehornencode_qp(char *out, const char *in, off_t length, int headerMode)
158f7215ac8SNathan Whitehorn{
159f7215ac8SNathan Whitehorn	int g = 0, i = 0;
1604bd5da82SAxel Dörfler
161f7215ac8SNathan Whitehorn	for (; i < length; i++) {
1624bd5da82SAxel Dörfler		if (((uint8 *)(in))[i] > 127 || in[i] == '?' || in[i] == '='
1634bd5da82SAxel Dörfler			|| in[i] == '_'
164f7215ac8SNathan Whitehorn			// Also encode the letter F in "From " at the start of the line,
165f7215ac8SNathan Whitehorn			// which Unix systems use to mark the start of messages in their
166f7215ac8SNathan Whitehorn			// mbox files.
1674bd5da82SAxel Dörfler			|| (in[i] == 'F' && i + 5 <= length && (i == 0 || in[i - 1] == '\n')
1684bd5da82SAxel Dörfler				&& in[i + 1] == 'r' && in[i + 2] == 'o' && in[i + 3] == 'm'
1694bd5da82SAxel Dörfler				&& in[i + 4] == ' ')) {
170f7215ac8SNathan Whitehorn			out[g++] = '=';
1714bd5da82SAxel Dörfler			out[g++] = kHexAlphabet[(in[i] >> 4) & 0x0f];
1724bd5da82SAxel Dörfler			out[g++] = kHexAlphabet[in[i] & 0x0f];
1734bd5da82SAxel Dörfler		} else if (headerMode && (in[i] == ' ' || in[i] == '\t')) {
174f7215ac8SNathan Whitehorn			out[g++] = '_';
1754bd5da82SAxel Dörfler		} else if (headerMode && in[i] >= 0 && in[i] < 32) {
176f7215ac8SNathan Whitehorn			// Control codes in headers need to be sanitized, otherwise certain
177f7215ac8SNathan Whitehorn			// Japanese ISPs mangle the headers badly.  But they don't mangle
178f7215ac8SNathan Whitehorn			// the body.
179f7215ac8SNathan Whitehorn			out[g++] = '=';
1804bd5da82SAxel Dörfler			out[g++] = kHexAlphabet[(in[i] >> 4) & 0x0f];
1814bd5da82SAxel Dörfler			out[g++] = kHexAlphabet[in[i] & 0x0f];
182f7215ac8SNathan Whitehorn		} else
183f7215ac8SNathan Whitehorn			out[g++] = in[i];
184f7215ac8SNathan Whitehorn	}
185f7215ac8SNathan Whitehorn
186f7215ac8SNathan Whitehorn	return g;
187f7215ac8SNathan Whitehorn}
188f7215ac8SNathan Whitehorn
189f7215ac8SNathan Whitehorn
1904bd5da82SAxel Dörflerssize_t
191f7215ac8SNathan Whitehornuu_decode(char *out, const char *in, off_t length)
192f7215ac8SNathan Whitehorn{
193f7215ac8SNathan Whitehorn	long n;
1944bd5da82SAxel Dörfler	uint8 *p, *inBuffer = (uint8 *)in;
1954bd5da82SAxel Dörfler	uint8 *outBuffer = (uint8 *)out;
1964bd5da82SAxel Dörfler
1974bd5da82SAxel Dörfler	inBuffer = (uint8 *)strstr((char *)inBuffer, "begin");
198f7215ac8SNathan Whitehorn	goto enterLoop;
199f7215ac8SNathan Whitehorn
2004bd5da82SAxel Dörfler	while ((inBuffer - (uint8 *)in) <= length
2014bd5da82SAxel Dörfler		&& strncmp((char *)inBuffer, "end", 3)) {
202f7215ac8SNathan Whitehorn		p = inBuffer;
203f7215ac8SNathan Whitehorn		n = DEC(inBuffer[0]);
204f7215ac8SNathan Whitehorn
205f7215ac8SNathan Whitehorn		for (++inBuffer; n > 0; inBuffer += 4, n -= 3) {
206f7215ac8SNathan Whitehorn			if (n >= 3) {
207f7215ac8SNathan Whitehorn				*outBuffer++ = DEC(inBuffer[0]) << 2 | DEC (inBuffer[1]) >> 4;
208f7215ac8SNathan Whitehorn				*outBuffer++ = DEC(inBuffer[1]) << 4 | DEC (inBuffer[2]) >> 2;
209f7215ac8SNathan Whitehorn				*outBuffer++ = DEC(inBuffer[2]) << 6 | DEC (inBuffer[3]);
210f7215ac8SNathan Whitehorn			} else {
2114bd5da82SAxel Dörfler				if (n >= 1) {
2124bd5da82SAxel Dörfler					*outBuffer++ = DEC(inBuffer[0]) << 2
2134bd5da82SAxel Dörfler						| DEC (inBuffer[1]) >> 4;
2144bd5da82SAxel Dörfler				}
2154bd5da82SAxel Dörfler				if (n >= 2) {
2164bd5da82SAxel Dörfler					*outBuffer++ = DEC(inBuffer[1]) << 4
2174bd5da82SAxel Dörfler						| DEC (inBuffer[2]) >> 2;
2184bd5da82SAxel Dörfler				}
219f7215ac8SNathan Whitehorn			}
220f7215ac8SNathan Whitehorn		}
221f7215ac8SNathan Whitehorn		inBuffer = p;
222f7215ac8SNathan Whitehorn
223f7215ac8SNathan Whitehorn	enterLoop:
2244bd5da82SAxel Dörfler		while (inBuffer[0] != '\n' && inBuffer[0] != '\r' && inBuffer[0] != 0)
2254bd5da82SAxel Dörfler			inBuffer++;
2264bd5da82SAxel Dörfler		while (inBuffer[0] == '\n' || inBuffer[0] == '\r')
2274bd5da82SAxel Dörfler			inBuffer++;
228f7215ac8SNathan Whitehorn	}
229f7215ac8SNathan Whitehorn
2304bd5da82SAxel Dörfler	return (ssize_t)(outBuffer - (uint8 *)in);
231f7215ac8SNathan Whitehorn}
232f7215ac8SNathan Whitehorn
233