Assorted whitespace cleanup and typo fixes.
[haiku.git] / src / kits / mail / mail_encoding.cpp
blobc542582c3af9278b63924fd0ea5e9d943b0b3736
1 /*
2 * Copyright 2011, Haiku, Inc. All rights reserved.
3 * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
4 */
7 #include <ctype.h>
8 #include <string.h>
9 #include <strings.h>
11 #include <SupportDefs.h>
13 #include <mail_encoding.h>
16 #define DEC(c) (((c) - ' ') & 077)
19 static const char kHexAlphabet[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
20 '8','9','A','B','C','D','E','F'};
23 ssize_t
24 encode(mail_encoding encoding, char *out, const char *in, off_t length,
25 int headerMode)
27 switch (encoding) {
28 case base64:
29 return encode_base64(out,in,length,headerMode);
30 case quoted_printable:
31 return encode_qp(out,in,length,headerMode);
32 case seven_bit:
33 case eight_bit:
34 case no_encoding:
35 memcpy(out,in,length);
36 return length;
37 case uuencode:
38 default:
39 return -1;
42 return -1;
46 ssize_t
47 decode(mail_encoding encoding, char *out, const char *in, off_t length,
48 int underscoreIsSpace)
50 switch (encoding) {
51 case base64:
52 return decode_base64(out, in, length);
53 case uuencode:
54 return uu_decode(out, in, length);
55 case seven_bit:
56 case eight_bit:
57 case no_encoding:
58 memcpy(out, in, length);
59 return length;
60 case quoted_printable:
61 return decode_qp(out, in, length, underscoreIsSpace);
62 default:
63 break;
66 return -1;
70 ssize_t
71 max_encoded_length(mail_encoding encoding, off_t length)
73 switch (encoding) {
74 case base64:
76 double result = length * 1.33333333333333;
77 result += (result / BASE64_LINELENGTH) * 2 + 20;
78 return (ssize_t)(result);
80 case quoted_printable:
81 return length * 3;
82 case seven_bit:
83 case eight_bit:
84 case no_encoding:
85 return length;
86 case uuencode:
87 default:
88 return -1;
91 return -1;
95 mail_encoding
96 encoding_for_cte(const char *cte)
98 if (cte == NULL)
99 return no_encoding;
101 if (strcasecmp(cte,"uuencode") == 0)
102 return uuencode;
103 if (strcasecmp(cte,"base64") == 0)
104 return base64;
105 if (strcasecmp(cte,"quoted-printable") == 0)
106 return quoted_printable;
107 if (strcasecmp(cte,"7bit") == 0)
108 return seven_bit;
109 if (strcasecmp(cte,"8bit") == 0)
110 return eight_bit;
112 return no_encoding;
116 ssize_t
117 decode_qp(char *out, const char *in, off_t length, int underscoreIsSpace)
119 // decode Quoted Printable
120 char *dataout = out;
121 const char *datain = in, *dataend = in + length;
123 while (datain < dataend) {
124 if (*datain == '=' && dataend - datain > 2) {
125 int a = toupper(datain[1]);
126 a -= a >= '0' && a <= '9' ? '0' : (a >= 'A' && a <= 'F'
127 ? 'A' - 10 : a + 1);
129 int b = toupper(datain[2]);
130 b -= b >= '0' && b <= '9' ? '0' : (b >= 'A' && b <= 'F'
131 ? 'A' - 10 : b + 1);
133 if (a >= 0 && b >= 0) {
134 *dataout++ = (a << 4) + b;
135 datain += 3;
136 continue;
137 } else if (datain[1] == '\r' && datain[2] == '\n') {
138 // strip =<CR><NL>
139 datain += 3;
140 continue;
142 } else if (*datain == '_' && underscoreIsSpace) {
143 *dataout++ = ' ';
144 ++datain;
145 continue;
148 *dataout++ = *datain++;
151 *dataout = '\0';
152 return dataout - out;
156 ssize_t
157 encode_qp(char *out, const char *in, off_t length, int headerMode)
159 int g = 0, i = 0;
161 for (; i < length; i++) {
162 if (((uint8 *)(in))[i] > 127 || in[i] == '?' || in[i] == '='
163 || in[i] == '_'
164 // Also encode the letter F in "From " at the start of the line,
165 // which Unix systems use to mark the start of messages in their
166 // mbox files.
167 || (in[i] == 'F' && i + 5 <= length && (i == 0 || in[i - 1] == '\n')
168 && in[i + 1] == 'r' && in[i + 2] == 'o' && in[i + 3] == 'm'
169 && in[i + 4] == ' ')) {
170 out[g++] = '=';
171 out[g++] = kHexAlphabet[(in[i] >> 4) & 0x0f];
172 out[g++] = kHexAlphabet[in[i] & 0x0f];
173 } else if (headerMode && (in[i] == ' ' || in[i] == '\t')) {
174 out[g++] = '_';
175 } else if (headerMode && in[i] >= 0 && in[i] < 32) {
176 // Control codes in headers need to be sanitized, otherwise certain
177 // Japanese ISPs mangle the headers badly. But they don't mangle
178 // the body.
179 out[g++] = '=';
180 out[g++] = kHexAlphabet[(in[i] >> 4) & 0x0f];
181 out[g++] = kHexAlphabet[in[i] & 0x0f];
182 } else
183 out[g++] = in[i];
186 return g;
190 ssize_t
191 uu_decode(char *out, const char *in, off_t length)
193 long n;
194 uint8 *p, *inBuffer = (uint8 *)in;
195 uint8 *outBuffer = (uint8 *)out;
197 inBuffer = (uint8 *)strstr((char *)inBuffer, "begin");
198 goto enterLoop;
200 while ((inBuffer - (uint8 *)in) <= length
201 && strncmp((char *)inBuffer, "end", 3)) {
202 p = inBuffer;
203 n = DEC(inBuffer[0]);
205 for (++inBuffer; n > 0; inBuffer += 4, n -= 3) {
206 if (n >= 3) {
207 *outBuffer++ = DEC(inBuffer[0]) << 2 | DEC (inBuffer[1]) >> 4;
208 *outBuffer++ = DEC(inBuffer[1]) << 4 | DEC (inBuffer[2]) >> 2;
209 *outBuffer++ = DEC(inBuffer[2]) << 6 | DEC (inBuffer[3]);
210 } else {
211 if (n >= 1) {
212 *outBuffer++ = DEC(inBuffer[0]) << 2
213 | DEC (inBuffer[1]) >> 4;
215 if (n >= 2) {
216 *outBuffer++ = DEC(inBuffer[1]) << 4
217 | DEC (inBuffer[2]) >> 2;
221 inBuffer = p;
223 enterLoop:
224 while (inBuffer[0] != '\n' && inBuffer[0] != '\r' && inBuffer[0] != 0)
225 inBuffer++;
226 while (inBuffer[0] == '\n' || inBuffer[0] == '\r')
227 inBuffer++;
230 return (ssize_t)(outBuffer - (uint8 *)in);