aboutsummaryrefslogtreecommitdiff
path: root/vendor/luasocket/src/mime.c
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/luasocket/src/mime.c')
-rwxr-xr-xvendor/luasocket/src/mime.c852
1 files changed, 852 insertions, 0 deletions
diff --git a/vendor/luasocket/src/mime.c b/vendor/luasocket/src/mime.c
new file mode 100755
index 00000000..05602f56
--- /dev/null
+++ b/vendor/luasocket/src/mime.c
@@ -0,0 +1,852 @@
1/*=========================================================================*\
2* MIME support functions
3* LuaSocket toolkit
4\*=========================================================================*/
5#include "luasocket.h"
6#include "mime.h"
7#include <string.h>
8#include <ctype.h>
9
10/*=========================================================================*\
11* Don't want to trust escape character constants
12\*=========================================================================*/
13typedef unsigned char UC;
14static const char CRLF[] = "\r\n";
15static const char EQCRLF[] = "=\r\n";
16
17/*=========================================================================*\
18* Internal function prototypes.
19\*=========================================================================*/
20static int mime_global_wrp(lua_State *L);
21static int mime_global_b64(lua_State *L);
22static int mime_global_unb64(lua_State *L);
23static int mime_global_qp(lua_State *L);
24static int mime_global_unqp(lua_State *L);
25static int mime_global_qpwrp(lua_State *L);
26static int mime_global_eol(lua_State *L);
27static int mime_global_dot(lua_State *L);
28
29static size_t dot(int c, size_t state, luaL_Buffer *buffer);
30/*static void b64setup(UC *base);*/
31static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
32static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
33static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
34
35/*static void qpsetup(UC *class, UC *unbase);*/
36static void qpquote(UC c, luaL_Buffer *buffer);
37static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
38static size_t qpencode(UC c, UC *input, size_t size,
39 const char *marker, luaL_Buffer *buffer);
40static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer);
41
42/* code support functions */
43static luaL_Reg func[] = {
44 { "dot", mime_global_dot },
45 { "b64", mime_global_b64 },
46 { "eol", mime_global_eol },
47 { "qp", mime_global_qp },
48 { "qpwrp", mime_global_qpwrp },
49 { "unb64", mime_global_unb64 },
50 { "unqp", mime_global_unqp },
51 { "wrp", mime_global_wrp },
52 { NULL, NULL }
53};
54
55/*-------------------------------------------------------------------------*\
56* Quoted-printable globals
57\*-------------------------------------------------------------------------*/
58enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST};
59
60static const UC qpclass[] = {
61 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
62 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_QUOTED, QP_QUOTED,
63 QP_QUOTED, QP_CR, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
64 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
65 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
66 QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_PLAIN, QP_PLAIN, QP_PLAIN,
67 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
68 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
69 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
70 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
71 QP_PLAIN, QP_QUOTED, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
72 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
73 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
74 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
75 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
76 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
77 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
78 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
79 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
80 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
81 QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN,
82 QP_PLAIN, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
83 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
84 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
85 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
86 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
87 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
88 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
89 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
90 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
91 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
92 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
93 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
94 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
95 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
96 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
97 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
98 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
99 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
100 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
101 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
102 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED,
103 QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED
104};
105
106static const UC qpbase[] = "0123456789ABCDEF";
107
108static const UC qpunbase[] = {
109 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
110 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
111 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
112 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
113 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255,
114 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15,
115 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
116 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
117 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255, 255,
118 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
119 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
120 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
121 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
122 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
123 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
124 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
125 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
126 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
127 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
128 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
129 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
130 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
131 255, 255, 255, 255, 255, 255, 255, 255
132};
133
134/*-------------------------------------------------------------------------*\
135* Base64 globals
136\*-------------------------------------------------------------------------*/
137static const UC b64base[] =
138 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
139
140static const UC b64unbase[] = {
141 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
142 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
143 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
144 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
145 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0,
146 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
147 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255,
148 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
149 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
150 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
151 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
152 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
153 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
154 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
155 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
156 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
157 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
158 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
159 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
160 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
161 255, 255
162};
163
164/*=========================================================================*\
165* Exported functions
166\*=========================================================================*/
167/*-------------------------------------------------------------------------*\
168* Initializes module
169\*-------------------------------------------------------------------------*/
170LUASOCKET_API int luaopen_mime_core(lua_State *L)
171{
172 lua_newtable(L);
173 luaL_setfuncs(L, func, 0);
174 /* make version string available to scripts */
175 lua_pushstring(L, "_VERSION");
176 lua_pushstring(L, MIME_VERSION);
177 lua_rawset(L, -3);
178 /* initialize lookup tables */
179 /*qpsetup(qpclass, qpunbase);*/
180 /*b64setup(b64unbase);*/
181 return 1;
182}
183
184/*=========================================================================*\
185* Global Lua functions
186\*=========================================================================*/
187/*-------------------------------------------------------------------------*\
188* Incrementaly breaks a string into lines. The string can have CRLF breaks.
189* A, n = wrp(l, B, length)
190* A is a copy of B, broken into lines of at most 'length' bytes.
191* 'l' is how many bytes are left for the first line of B.
192* 'n' is the number of bytes left in the last line of A.
193\*-------------------------------------------------------------------------*/
194static int mime_global_wrp(lua_State *L)
195{
196 size_t size = 0;
197 int left = (int) luaL_checknumber(L, 1);
198 const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size);
199 const UC *last = input + size;
200 int length = (int) luaL_optnumber(L, 3, 76);
201 luaL_Buffer buffer;
202 /* end of input black-hole */
203 if (!input) {
204 /* if last line has not been terminated, add a line break */
205 if (left < length) lua_pushstring(L, CRLF);
206 /* otherwise, we are done */
207 else lua_pushnil(L);
208 lua_pushnumber(L, length);
209 return 2;
210 }
211 luaL_buffinit(L, &buffer);
212 while (input < last) {
213 switch (*input) {
214 case '\r':
215 break;
216 case '\n':
217 luaL_addstring(&buffer, CRLF);
218 left = length;
219 break;
220 default:
221 if (left <= 0) {
222 left = length;
223 luaL_addstring(&buffer, CRLF);
224 }
225 luaL_addchar(&buffer, *input);
226 left--;
227 break;
228 }
229 input++;
230 }
231 luaL_pushresult(&buffer);
232 lua_pushnumber(L, left);
233 return 2;
234}
235
236#if 0
237/*-------------------------------------------------------------------------*\
238* Fill base64 decode map.
239\*-------------------------------------------------------------------------*/
240static void b64setup(UC *unbase)
241{
242 int i;
243 for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
244 for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i;
245 unbase['='] = 0;
246
247 printf("static const UC b64unbase[] = {\n");
248 for (int i = 0; i < 256; i++) {
249 printf("%d, ", unbase[i]);
250 }
251 printf("\n}\n;");
252}
253#endif
254
255/*-------------------------------------------------------------------------*\
256* Acumulates bytes in input buffer until 3 bytes are available.
257* Translate the 3 bytes into Base64 form and append to buffer.
258* Returns new number of bytes in buffer.
259\*-------------------------------------------------------------------------*/
260static size_t b64encode(UC c, UC *input, size_t size,
261 luaL_Buffer *buffer)
262{
263 input[size++] = c;
264 if (size == 3) {
265 UC code[4];
266 unsigned long value = 0;
267 value += input[0]; value <<= 8;
268 value += input[1]; value <<= 8;
269 value += input[2];
270 code[3] = b64base[value & 0x3f]; value >>= 6;
271 code[2] = b64base[value & 0x3f]; value >>= 6;
272 code[1] = b64base[value & 0x3f]; value >>= 6;
273 code[0] = b64base[value];
274 luaL_addlstring(buffer, (char *) code, 4);
275 size = 0;
276 }
277 return size;
278}
279
280/*-------------------------------------------------------------------------*\
281* Encodes the Base64 last 1 or 2 bytes and adds padding '='
282* Result, if any, is appended to buffer.
283* Returns 0.
284\*-------------------------------------------------------------------------*/
285static size_t b64pad(const UC *input, size_t size,
286 luaL_Buffer *buffer)
287{
288 unsigned long value = 0;
289 UC code[4] = {'=', '=', '=', '='};
290 switch (size) {
291 case 1:
292 value = input[0] << 4;
293 code[1] = b64base[value & 0x3f]; value >>= 6;
294 code[0] = b64base[value];
295 luaL_addlstring(buffer, (char *) code, 4);
296 break;
297 case 2:
298 value = input[0]; value <<= 8;
299 value |= input[1]; value <<= 2;
300 code[2] = b64base[value & 0x3f]; value >>= 6;
301 code[1] = b64base[value & 0x3f]; value >>= 6;
302 code[0] = b64base[value];
303 luaL_addlstring(buffer, (char *) code, 4);
304 break;
305 default:
306 break;
307 }
308 return 0;
309}
310
311/*-------------------------------------------------------------------------*\
312* Acumulates bytes in input buffer until 4 bytes are available.
313* Translate the 4 bytes from Base64 form and append to buffer.
314* Returns new number of bytes in buffer.
315\*-------------------------------------------------------------------------*/
316static size_t b64decode(UC c, UC *input, size_t size,
317 luaL_Buffer *buffer)
318{
319 /* ignore invalid characters */
320 if (b64unbase[c] > 64) return size;
321 input[size++] = c;
322 /* decode atom */
323 if (size == 4) {
324 UC decoded[3];
325 int valid, value = 0;
326 value = b64unbase[input[0]]; value <<= 6;
327 value |= b64unbase[input[1]]; value <<= 6;
328 value |= b64unbase[input[2]]; value <<= 6;
329 value |= b64unbase[input[3]];
330 decoded[2] = (UC) (value & 0xff); value >>= 8;
331 decoded[1] = (UC) (value & 0xff); value >>= 8;
332 decoded[0] = (UC) value;
333 /* take care of paddding */
334 valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3;
335 luaL_addlstring(buffer, (char *) decoded, valid);
336 return 0;
337 /* need more data */
338 } else return size;
339}
340
341/*-------------------------------------------------------------------------*\
342* Incrementally applies the Base64 transfer content encoding to a string
343* A, B = b64(C, D)
344* A is the encoded version of the largest prefix of C .. D that is
345* divisible by 3. B has the remaining bytes of C .. D, *without* encoding.
346* The easiest thing would be to concatenate the two strings and
347* encode the result, but we can't afford that or Lua would dupplicate
348* every chunk we received.
349\*-------------------------------------------------------------------------*/
350static int mime_global_b64(lua_State *L)
351{
352 UC atom[3];
353 size_t isize = 0, asize = 0;
354 const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
355 const UC *last = input + isize;
356 luaL_Buffer buffer;
357 /* end-of-input blackhole */
358 if (!input) {
359 lua_pushnil(L);
360 lua_pushnil(L);
361 return 2;
362 }
363 /* make sure we don't confuse buffer stuff with arguments */
364 lua_settop(L, 2);
365 /* process first part of the input */
366 luaL_buffinit(L, &buffer);
367 while (input < last)
368 asize = b64encode(*input++, atom, asize, &buffer);
369 input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
370 /* if second part is nil, we are done */
371 if (!input) {
372 size_t osize = 0;
373 asize = b64pad(atom, asize, &buffer);
374 luaL_pushresult(&buffer);
375 /* if the output is empty and the input is nil, return nil */
376 lua_tolstring(L, -1, &osize);
377 if (osize == 0) lua_pushnil(L);
378 lua_pushnil(L);
379 return 2;
380 }
381 /* otherwise process the second part */
382 last = input + isize;
383 while (input < last)
384 asize = b64encode(*input++, atom, asize, &buffer);
385 luaL_pushresult(&buffer);
386 lua_pushlstring(L, (char *) atom, asize);
387 return 2;
388}
389
390/*-------------------------------------------------------------------------*\
391* Incrementally removes the Base64 transfer content encoding from a string
392* A, B = b64(C, D)
393* A is the encoded version of the largest prefix of C .. D that is
394* divisible by 4. B has the remaining bytes of C .. D, *without* encoding.
395\*-------------------------------------------------------------------------*/
396static int mime_global_unb64(lua_State *L)
397{
398 UC atom[4];
399 size_t isize = 0, asize = 0;
400 const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
401 const UC *last = input + isize;
402 luaL_Buffer buffer;
403 /* end-of-input blackhole */
404 if (!input) {
405 lua_pushnil(L);
406 lua_pushnil(L);
407 return 2;
408 }
409 /* make sure we don't confuse buffer stuff with arguments */
410 lua_settop(L, 2);
411 /* process first part of the input */
412 luaL_buffinit(L, &buffer);
413 while (input < last)
414 asize = b64decode(*input++, atom, asize, &buffer);
415 input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
416 /* if second is nil, we are done */
417 if (!input) {
418 size_t osize = 0;
419 luaL_pushresult(&buffer);
420 /* if the output is empty and the input is nil, return nil */
421 lua_tolstring(L, -1, &osize);
422 if (osize == 0) lua_pushnil(L);
423 lua_pushnil(L);
424 return 2;
425 }
426 /* otherwise, process the rest of the input */
427 last = input + isize;
428 while (input < last)
429 asize = b64decode(*input++, atom, asize, &buffer);
430 luaL_pushresult(&buffer);
431 lua_pushlstring(L, (char *) atom, asize);
432 return 2;
433}
434
435/*-------------------------------------------------------------------------*\
436* Quoted-printable encoding scheme
437* all (except CRLF in text) can be =XX
438* CLRL in not text must be =XX=XX
439* 33 through 60 inclusive can be plain
440* 62 through 126 inclusive can be plain
441* 9 and 32 can be plain, unless in the end of a line, where must be =XX
442* encoded lines must be no longer than 76 not counting CRLF
443* soft line-break are =CRLF
444* To encode one byte, we need to see the next two.
445* Worst case is when we see a space, and wonder if a CRLF is comming
446\*-------------------------------------------------------------------------*/
447#if 0
448/*-------------------------------------------------------------------------*\
449* Split quoted-printable characters into classes
450* Precompute reverse map for encoding
451\*-------------------------------------------------------------------------*/
452static void qpsetup(UC *cl, UC *unbase)
453{
454
455 int i;
456 for (i = 0; i < 256; i++) cl[i] = QP_QUOTED;
457 for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN;
458 for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN;
459 cl['\t'] = QP_IF_LAST;
460 cl[' '] = QP_IF_LAST;
461 cl['\r'] = QP_CR;
462 for (i = 0; i < 256; i++) unbase[i] = 255;
463 unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2;
464 unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5;
465 unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8;
466 unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10;
467 unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12;
468 unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13;
469 unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15;
470 unbase['f'] = 15;
471
472printf("static UC qpclass[] = {");
473 for (int i = 0; i < 256; i++) {
474 if (i % 6 == 0) {
475 printf("\n ");
476 }
477 switch(cl[i]) {
478 case QP_QUOTED:
479 printf("QP_QUOTED, ");
480 break;
481 case QP_PLAIN:
482 printf("QP_PLAIN, ");
483 break;
484 case QP_CR:
485 printf("QP_CR, ");
486 break;
487 case QP_IF_LAST:
488 printf("QP_IF_LAST, ");
489 break;
490 }
491 }
492printf("\n};\n");
493
494printf("static const UC qpunbase[] = {");
495 for (int i = 0; i < 256; i++) {
496 int c = qpunbase[i];
497 printf("%d, ", c);
498 }
499printf("\";\n");
500}
501#endif
502
503/*-------------------------------------------------------------------------*\
504* Output one character in form =XX
505\*-------------------------------------------------------------------------*/
506static void qpquote(UC c, luaL_Buffer *buffer)
507{
508 luaL_addchar(buffer, '=');
509 luaL_addchar(buffer, qpbase[c >> 4]);
510 luaL_addchar(buffer, qpbase[c & 0x0F]);
511}
512
513/*-------------------------------------------------------------------------*\
514* Accumulate characters until we are sure about how to deal with them.
515* Once we are sure, output to the buffer, in the correct form.
516\*-------------------------------------------------------------------------*/
517static size_t qpencode(UC c, UC *input, size_t size,
518 const char *marker, luaL_Buffer *buffer)
519{
520 input[size++] = c;
521 /* deal with all characters we can have */
522 while (size > 0) {
523 switch (qpclass[input[0]]) {
524 /* might be the CR of a CRLF sequence */
525 case QP_CR:
526 if (size < 2) return size;
527 if (input[1] == '\n') {
528 luaL_addstring(buffer, marker);
529 return 0;
530 } else qpquote(input[0], buffer);
531 break;
532 /* might be a space and that has to be quoted if last in line */
533 case QP_IF_LAST:
534 if (size < 3) return size;
535 /* if it is the last, quote it and we are done */
536 if (input[1] == '\r' && input[2] == '\n') {
537 qpquote(input[0], buffer);
538 luaL_addstring(buffer, marker);
539 return 0;
540 } else luaL_addchar(buffer, input[0]);
541 break;
542 /* might have to be quoted always */
543 case QP_QUOTED:
544 qpquote(input[0], buffer);
545 break;
546 /* might never have to be quoted */
547 default:
548 luaL_addchar(buffer, input[0]);
549 break;
550 }
551 input[0] = input[1]; input[1] = input[2];
552 size--;
553 }
554 return 0;
555}
556
557/*-------------------------------------------------------------------------*\
558* Deal with the final characters
559\*-------------------------------------------------------------------------*/
560static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
561{
562 size_t i;
563 for (i = 0; i < size; i++) {
564 if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]);
565 else qpquote(input[i], buffer);
566 }
567 if (size > 0) luaL_addstring(buffer, EQCRLF);
568 return 0;
569}
570
571/*-------------------------------------------------------------------------*\
572* Incrementally converts a string to quoted-printable
573* A, B = qp(C, D, marker)
574* Marker is the text to be used to replace CRLF sequences found in A.
575* A is the encoded version of the largest prefix of C .. D that
576* can be encoded without doubts.
577* B has the remaining bytes of C .. D, *without* encoding.
578\*-------------------------------------------------------------------------*/
579static int mime_global_qp(lua_State *L)
580{
581 size_t asize = 0, isize = 0;
582 UC atom[3];
583 const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
584 const UC *last = input + isize;
585 const char *marker = luaL_optstring(L, 3, CRLF);
586 luaL_Buffer buffer;
587 /* end-of-input blackhole */
588 if (!input) {
589 lua_pushnil(L);
590 lua_pushnil(L);
591 return 2;
592 }
593 /* make sure we don't confuse buffer stuff with arguments */
594 lua_settop(L, 3);
595 /* process first part of input */
596 luaL_buffinit(L, &buffer);
597 while (input < last)
598 asize = qpencode(*input++, atom, asize, marker, &buffer);
599 input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
600 /* if second part is nil, we are done */
601 if (!input) {
602 asize = qppad(atom, asize, &buffer);
603 luaL_pushresult(&buffer);
604 if (!(*lua_tostring(L, -1))) lua_pushnil(L);
605 lua_pushnil(L);
606 return 2;
607 }
608 /* otherwise process rest of input */
609 last = input + isize;
610 while (input < last)
611 asize = qpencode(*input++, atom, asize, marker, &buffer);
612 luaL_pushresult(&buffer);
613 lua_pushlstring(L, (char *) atom, asize);
614 return 2;
615}
616
617/*-------------------------------------------------------------------------*\
618* Accumulate characters until we are sure about how to deal with them.
619* Once we are sure, output the to the buffer, in the correct form.
620\*-------------------------------------------------------------------------*/
621static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
622 int d;
623 input[size++] = c;
624 /* deal with all characters we can deal */
625 switch (input[0]) {
626 /* if we have an escape character */
627 case '=':
628 if (size < 3) return size;
629 /* eliminate soft line break */
630 if (input[1] == '\r' && input[2] == '\n') return 0;
631 /* decode quoted representation */
632 c = qpunbase[input[1]]; d = qpunbase[input[2]];
633 /* if it is an invalid, do not decode */
634 if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3);
635 else luaL_addchar(buffer, (char) ((c << 4) + d));
636 return 0;
637 case '\r':
638 if (size < 2) return size;
639 if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2);
640 return 0;
641 default:
642 if (input[0] == '\t' || (input[0] > 31 && input[0] < 127))
643 luaL_addchar(buffer, input[0]);
644 return 0;
645 }
646}
647
648/*-------------------------------------------------------------------------*\
649* Incrementally decodes a string in quoted-printable
650* A, B = qp(C, D)
651* A is the decoded version of the largest prefix of C .. D that
652* can be decoded without doubts.
653* B has the remaining bytes of C .. D, *without* decoding.
654\*-------------------------------------------------------------------------*/
655static int mime_global_unqp(lua_State *L)
656{
657 size_t asize = 0, isize = 0;
658 UC atom[3];
659 const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
660 const UC *last = input + isize;
661 luaL_Buffer buffer;
662 /* end-of-input blackhole */
663 if (!input) {
664 lua_pushnil(L);
665 lua_pushnil(L);
666 return 2;
667 }
668 /* make sure we don't confuse buffer stuff with arguments */
669 lua_settop(L, 2);
670 /* process first part of input */
671 luaL_buffinit(L, &buffer);
672 while (input < last)
673 asize = qpdecode(*input++, atom, asize, &buffer);
674 input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
675 /* if second part is nil, we are done */
676 if (!input) {
677 luaL_pushresult(&buffer);
678 if (!(*lua_tostring(L, -1))) lua_pushnil(L);
679 lua_pushnil(L);
680 return 2;
681 }
682 /* otherwise process rest of input */
683 last = input + isize;
684 while (input < last)
685 asize = qpdecode(*input++, atom, asize, &buffer);
686 luaL_pushresult(&buffer);
687 lua_pushlstring(L, (char *) atom, asize);
688 return 2;
689}
690
691/*-------------------------------------------------------------------------*\
692* Incrementally breaks a quoted-printed string into lines
693* A, n = qpwrp(l, B, length)
694* A is a copy of B, broken into lines of at most 'length' bytes.
695* 'l' is how many bytes are left for the first line of B.
696* 'n' is the number of bytes left in the last line of A.
697* There are two complications: lines can't be broken in the middle
698* of an encoded =XX, and there might be line breaks already
699\*-------------------------------------------------------------------------*/
700static int mime_global_qpwrp(lua_State *L)
701{
702 size_t size = 0;
703 int left = (int) luaL_checknumber(L, 1);
704 const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size);
705 const UC *last = input + size;
706 int length = (int) luaL_optnumber(L, 3, 76);
707 luaL_Buffer buffer;
708 /* end-of-input blackhole */
709 if (!input) {
710 if (left < length) lua_pushstring(L, EQCRLF);
711 else lua_pushnil(L);
712 lua_pushnumber(L, length);
713 return 2;
714 }
715 /* process all input */
716 luaL_buffinit(L, &buffer);
717 while (input < last) {
718 switch (*input) {
719 case '\r':
720 break;
721 case '\n':
722 left = length;
723 luaL_addstring(&buffer, CRLF);
724 break;
725 case '=':
726 if (left <= 3) {
727 left = length;
728 luaL_addstring(&buffer, EQCRLF);
729 }
730 luaL_addchar(&buffer, *input);
731 left--;
732 break;
733 default:
734 if (left <= 1) {
735 left = length;
736 luaL_addstring(&buffer, EQCRLF);
737 }
738 luaL_addchar(&buffer, *input);
739 left--;
740 break;
741 }
742 input++;
743 }
744 luaL_pushresult(&buffer);
745 lua_pushnumber(L, left);
746 return 2;
747}
748
749/*-------------------------------------------------------------------------*\
750* Here is what we do: \n, and \r are considered candidates for line
751* break. We issue *one* new line marker if any of them is seen alone, or
752* followed by a different one. That is, \n\n and \r\r will issue two
753* end of line markers each, but \r\n, \n\r etc will only issue *one*
754* marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as
755* probably other more obscure conventions.
756*
757* c is the current character being processed
758* last is the previous character
759\*-------------------------------------------------------------------------*/
760#define eolcandidate(c) (c == '\r' || c == '\n')
761static int eolprocess(int c, int last, const char *marker,
762 luaL_Buffer *buffer)
763{
764 if (eolcandidate(c)) {
765 if (eolcandidate(last)) {
766 if (c == last) luaL_addstring(buffer, marker);
767 return 0;
768 } else {
769 luaL_addstring(buffer, marker);
770 return c;
771 }
772 } else {
773 luaL_addchar(buffer, (char) c);
774 return 0;
775 }
776}
777
778/*-------------------------------------------------------------------------*\
779* Converts a string to uniform EOL convention.
780* A, n = eol(o, B, marker)
781* A is the converted version of the largest prefix of B that can be
782* converted unambiguously. 'o' is the context returned by the previous
783* call. 'n' is the new context.
784\*-------------------------------------------------------------------------*/
785static int mime_global_eol(lua_State *L)
786{
787 int ctx = (int) luaL_checkinteger(L, 1);
788 size_t isize = 0;
789 const char *input = luaL_optlstring(L, 2, NULL, &isize);
790 const char *last = input + isize;
791 const char *marker = luaL_optstring(L, 3, CRLF);
792 luaL_Buffer buffer;
793 luaL_buffinit(L, &buffer);
794 /* end of input blackhole */
795 if (!input) {
796 lua_pushnil(L);
797 lua_pushnumber(L, 0);
798 return 2;
799 }
800 /* process all input */
801 while (input < last)
802 ctx = eolprocess(*input++, ctx, marker, &buffer);
803 luaL_pushresult(&buffer);
804 lua_pushnumber(L, ctx);
805 return 2;
806}
807
808/*-------------------------------------------------------------------------*\
809* Takes one byte and stuff it if needed.
810\*-------------------------------------------------------------------------*/
811static size_t dot(int c, size_t state, luaL_Buffer *buffer)
812{
813 luaL_addchar(buffer, (char) c);
814 switch (c) {
815 case '\r':
816 return 1;
817 case '\n':
818 return (state == 1)? 2: 0;
819 case '.':
820 if (state == 2)
821 luaL_addchar(buffer, '.');
822 /* Falls through. */
823 default:
824 return 0;
825 }
826}
827
828/*-------------------------------------------------------------------------*\
829* Incrementally applies smtp stuffing to a string
830* A, n = dot(l, D)
831\*-------------------------------------------------------------------------*/
832static int mime_global_dot(lua_State *L)
833{
834 size_t isize = 0, state = (size_t) luaL_checknumber(L, 1);
835 const char *input = luaL_optlstring(L, 2, NULL, &isize);
836 const char *last = input + isize;
837 luaL_Buffer buffer;
838 /* end-of-input blackhole */
839 if (!input) {
840 lua_pushnil(L);
841 lua_pushnumber(L, 2);
842 return 2;
843 }
844 /* process all input */
845 luaL_buffinit(L, &buffer);
846 while (input < last)
847 state = dot(*input++, state, &buffer);
848 luaL_pushresult(&buffer);
849 lua_pushnumber(L, (lua_Number) state);
850 return 2;
851}
852