1 /*=========================================================================*\
2 * MIME support functions
4 \*=========================================================================*/
10 #if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
11 #include "compat-5.1.h"
16 /*=========================================================================*\
17 * Don't want to trust escape character constants
18 \*=========================================================================*/
19 typedef unsigned char UC
;
20 static const char CRLF
[] = "\r\n";
21 static const char EQCRLF
[] = "=\r\n";
23 /*=========================================================================*\
24 * Internal function prototypes.
25 \*=========================================================================*/
26 static int mime_global_wrp(lua_State
*L
);
27 static int mime_global_b64(lua_State
*L
);
28 static int mime_global_unb64(lua_State
*L
);
29 static int mime_global_qp(lua_State
*L
);
30 static int mime_global_unqp(lua_State
*L
);
31 static int mime_global_qpwrp(lua_State
*L
);
32 static int mime_global_eol(lua_State
*L
);
33 static int mime_global_dot(lua_State
*L
);
35 static size_t dot(int c
, size_t state
, luaL_Buffer
*buffer
);
36 static void b64setup(UC
*base
);
37 static size_t b64encode(UC c
, UC
*input
, size_t size
, luaL_Buffer
*buffer
);
38 static size_t b64pad(const UC
*input
, size_t size
, luaL_Buffer
*buffer
);
39 static size_t b64decode(UC c
, UC
*input
, size_t size
, luaL_Buffer
*buffer
);
41 static void qpsetup(UC
*class, UC
*unbase
);
42 static void qpquote(UC c
, luaL_Buffer
*buffer
);
43 static size_t qpdecode(UC c
, UC
*input
, size_t size
, luaL_Buffer
*buffer
);
44 static size_t qpencode(UC c
, UC
*input
, size_t size
,
45 const char *marker
, luaL_Buffer
*buffer
);
46 static size_t qppad(UC
*input
, size_t size
, luaL_Buffer
*buffer
);
48 /* code support functions */
49 static luaL_Reg func
[] = {
50 { "dot", mime_global_dot
},
51 { "b64", mime_global_b64
},
52 { "eol", mime_global_eol
},
53 { "qp", mime_global_qp
},
54 { "qpwrp", mime_global_qpwrp
},
55 { "unb64", mime_global_unb64
},
56 { "unqp", mime_global_unqp
},
57 { "wrp", mime_global_wrp
},
61 /*-------------------------------------------------------------------------*\
62 * Quoted-printable globals
63 \*-------------------------------------------------------------------------*/
64 static UC qpclass
[256];
65 static UC qpbase
[] = "0123456789ABCDEF";
66 static UC qpunbase
[256];
67 enum {QP_PLAIN
, QP_QUOTED
, QP_CR
, QP_IF_LAST
};
69 /*-------------------------------------------------------------------------*\
71 \*-------------------------------------------------------------------------*/
72 static const UC b64base
[] =
73 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
74 static UC b64unbase
[256];
76 /*=========================================================================*\
78 \*=========================================================================*/
79 /*-------------------------------------------------------------------------*\
81 \*-------------------------------------------------------------------------*/
82 MIME_API
int luaopen_mime_core(lua_State
*L
)
84 luaL_openlib(L
, "mime", func
, 0);
85 /* make version string available to scripts */
86 lua_pushstring(L
, "_VERSION");
87 lua_pushstring(L
, MIME_VERSION
);
89 /* initialize lookup tables */
90 qpsetup(qpclass
, qpunbase
);
95 /*=========================================================================*\
96 * Global Lua functions
97 \*=========================================================================*/
98 /*-------------------------------------------------------------------------*\
99 * Incrementaly breaks a string into lines. The string can have CRLF breaks.
100 * A, n = wrp(l, B, length)
101 * A is a copy of B, broken into lines of at most 'length' bytes.
102 * 'l' is how many bytes are left for the first line of B.
103 * 'n' is the number of bytes left in the last line of A.
104 \*-------------------------------------------------------------------------*/
105 static int mime_global_wrp(lua_State
*L
)
108 int left
= (int) luaL_checknumber(L
, 1);
109 const UC
*input
= (UC
*) luaL_optlstring(L
, 2, NULL
, &size
);
110 const UC
*last
= input
+ size
;
111 int length
= (int) luaL_optnumber(L
, 3, 76);
113 /* end of input black-hole */
115 /* if last line has not been terminated, add a line break */
116 if (left
< length
) lua_pushstring(L
, CRLF
);
117 /* otherwise, we are done */
119 lua_pushnumber(L
, length
);
122 luaL_buffinit(L
, &buffer
);
123 while (input
< last
) {
128 luaL_addstring(&buffer
, CRLF
);
134 luaL_addstring(&buffer
, CRLF
);
136 luaL_addchar(&buffer
, *input
);
142 luaL_pushresult(&buffer
);
143 lua_pushnumber(L
, left
);
147 /*-------------------------------------------------------------------------*\
148 * Fill base64 decode map.
149 \*-------------------------------------------------------------------------*/
150 static void b64setup(UC
*unbase
)
153 for (i
= 0; i
<= 255; i
++) unbase
[i
] = (UC
) 255;
154 for (i
= 0; i
< 64; i
++) unbase
[b64base
[i
]] = (UC
) i
;
158 /*-------------------------------------------------------------------------*\
159 * Acumulates bytes in input buffer until 3 bytes are available.
160 * Translate the 3 bytes into Base64 form and append to buffer.
161 * Returns new number of bytes in buffer.
162 \*-------------------------------------------------------------------------*/
163 static size_t b64encode(UC c
, UC
*input
, size_t size
,
169 unsigned long value
= 0;
170 value
+= input
[0]; value
<<= 8;
171 value
+= input
[1]; value
<<= 8;
173 code
[3] = b64base
[value
& 0x3f]; value
>>= 6;
174 code
[2] = b64base
[value
& 0x3f]; value
>>= 6;
175 code
[1] = b64base
[value
& 0x3f]; value
>>= 6;
176 code
[0] = b64base
[value
];
177 luaL_addlstring(buffer
, (char *) code
, 4);
183 /*-------------------------------------------------------------------------*\
184 * Encodes the Base64 last 1 or 2 bytes and adds padding '='
185 * Result, if any, is appended to buffer.
187 \*-------------------------------------------------------------------------*/
188 static size_t b64pad(const UC
*input
, size_t size
,
191 unsigned long value
= 0;
192 UC code
[4] = {'=', '=', '=', '='};
195 value
= input
[0] << 4;
196 code
[1] = b64base
[value
& 0x3f]; value
>>= 6;
197 code
[0] = b64base
[value
];
198 luaL_addlstring(buffer
, (char *) code
, 4);
201 value
= input
[0]; value
<<= 8;
202 value
|= input
[1]; value
<<= 2;
203 code
[2] = b64base
[value
& 0x3f]; value
>>= 6;
204 code
[1] = b64base
[value
& 0x3f]; value
>>= 6;
205 code
[0] = b64base
[value
];
206 luaL_addlstring(buffer
, (char *) code
, 4);
214 /*-------------------------------------------------------------------------*\
215 * Acumulates bytes in input buffer until 4 bytes are available.
216 * Translate the 4 bytes from Base64 form and append to buffer.
217 * Returns new number of bytes in buffer.
218 \*-------------------------------------------------------------------------*/
219 static size_t b64decode(UC c
, UC
*input
, size_t size
,
222 /* ignore invalid characters */
223 if (b64unbase
[c
] > 64) return size
;
228 int valid
, value
= 0;
229 value
= b64unbase
[input
[0]]; value
<<= 6;
230 value
|= b64unbase
[input
[1]]; value
<<= 6;
231 value
|= b64unbase
[input
[2]]; value
<<= 6;
232 value
|= b64unbase
[input
[3]];
233 decoded
[2] = (UC
) (value
& 0xff); value
>>= 8;
234 decoded
[1] = (UC
) (value
& 0xff); value
>>= 8;
235 decoded
[0] = (UC
) value
;
236 /* take care of paddding */
237 valid
= (input
[2] == '=') ? 1 : (input
[3] == '=') ? 2 : 3;
238 luaL_addlstring(buffer
, (char *) decoded
, valid
);
244 /*-------------------------------------------------------------------------*\
245 * Incrementally applies the Base64 transfer content encoding to a string
247 * A is the encoded version of the largest prefix of C .. D that is
248 * divisible by 3. B has the remaining bytes of C .. D, *without* encoding.
249 * The easiest thing would be to concatenate the two strings and
250 * encode the result, but we can't afford that or Lua would dupplicate
251 * every chunk we received.
252 \*-------------------------------------------------------------------------*/
253 static int mime_global_b64(lua_State
*L
)
256 size_t isize
= 0, asize
= 0;
257 const UC
*input
= (UC
*) luaL_optlstring(L
, 1, NULL
, &isize
);
258 const UC
*last
= input
+ isize
;
260 /* end-of-input blackhole */
266 /* make sure we don't confuse buffer stuff with arguments */
268 /* process first part of the input */
269 luaL_buffinit(L
, &buffer
);
271 asize
= b64encode(*input
++, atom
, asize
, &buffer
);
272 input
= (UC
*) luaL_optlstring(L
, 2, NULL
, &isize
);
273 /* if second part is nil, we are done */
276 asize
= b64pad(atom
, asize
, &buffer
);
277 luaL_pushresult(&buffer
);
278 /* if the output is empty and the input is nil, return nil */
279 lua_tolstring(L
, -1, &osize
);
280 if (osize
== 0) lua_pushnil(L
);
284 /* otherwise process the second part */
285 last
= input
+ isize
;
287 asize
= b64encode(*input
++, atom
, asize
, &buffer
);
288 luaL_pushresult(&buffer
);
289 lua_pushlstring(L
, (char *) atom
, asize
);
293 /*-------------------------------------------------------------------------*\
294 * Incrementally removes the Base64 transfer content encoding from a string
296 * A is the encoded version of the largest prefix of C .. D that is
297 * divisible by 4. B has the remaining bytes of C .. D, *without* encoding.
298 \*-------------------------------------------------------------------------*/
299 static int mime_global_unb64(lua_State
*L
)
302 size_t isize
= 0, asize
= 0;
303 const UC
*input
= (UC
*) luaL_optlstring(L
, 1, NULL
, &isize
);
304 const UC
*last
= input
+ isize
;
306 /* end-of-input blackhole */
312 /* make sure we don't confuse buffer stuff with arguments */
314 /* process first part of the input */
315 luaL_buffinit(L
, &buffer
);
317 asize
= b64decode(*input
++, atom
, asize
, &buffer
);
318 input
= (UC
*) luaL_optlstring(L
, 2, NULL
, &isize
);
319 /* if second is nil, we are done */
322 luaL_pushresult(&buffer
);
323 /* if the output is empty and the input is nil, return nil */
324 lua_tolstring(L
, -1, &osize
);
325 if (osize
== 0) lua_pushnil(L
);
329 /* otherwise, process the rest of the input */
330 last
= input
+ isize
;
332 asize
= b64decode(*input
++, atom
, asize
, &buffer
);
333 luaL_pushresult(&buffer
);
334 lua_pushlstring(L
, (char *) atom
, asize
);
338 /*-------------------------------------------------------------------------*\
339 * Quoted-printable encoding scheme
340 * all (except CRLF in text) can be =XX
341 * CLRL in not text must be =XX=XX
342 * 33 through 60 inclusive can be plain
343 * 62 through 126 inclusive can be plain
344 * 9 and 32 can be plain, unless in the end of a line, where must be =XX
345 * encoded lines must be no longer than 76 not counting CRLF
346 * soft line-break are =CRLF
347 * To encode one byte, we need to see the next two.
348 * Worst case is when we see a space, and wonder if a CRLF is comming
349 \*-------------------------------------------------------------------------*/
350 /*-------------------------------------------------------------------------*\
351 * Split quoted-printable characters into classes
352 * Precompute reverse map for encoding
353 \*-------------------------------------------------------------------------*/
354 static void qpsetup(UC
*cl
, UC
*unbase
)
357 for (i
= 0; i
< 256; i
++) cl
[i
] = QP_QUOTED
;
358 for (i
= 33; i
<= 60; i
++) cl
[i
] = QP_PLAIN
;
359 for (i
= 62; i
<= 126; i
++) cl
[i
] = QP_PLAIN
;
360 cl
['\t'] = QP_IF_LAST
;
361 cl
[' '] = QP_IF_LAST
;
363 for (i
= 0; i
< 256; i
++) unbase
[i
] = 255;
364 unbase
['0'] = 0; unbase
['1'] = 1; unbase
['2'] = 2;
365 unbase
['3'] = 3; unbase
['4'] = 4; unbase
['5'] = 5;
366 unbase
['6'] = 6; unbase
['7'] = 7; unbase
['8'] = 8;
367 unbase
['9'] = 9; unbase
['A'] = 10; unbase
['a'] = 10;
368 unbase
['B'] = 11; unbase
['b'] = 11; unbase
['C'] = 12;
369 unbase
['c'] = 12; unbase
['D'] = 13; unbase
['d'] = 13;
370 unbase
['E'] = 14; unbase
['e'] = 14; unbase
['F'] = 15;
374 /*-------------------------------------------------------------------------*\
375 * Output one character in form =XX
376 \*-------------------------------------------------------------------------*/
377 static void qpquote(UC c
, luaL_Buffer
*buffer
)
379 luaL_addchar(buffer
, '=');
380 luaL_addchar(buffer
, qpbase
[c
>> 4]);
381 luaL_addchar(buffer
, qpbase
[c
& 0x0F]);
384 /*-------------------------------------------------------------------------*\
385 * Accumulate characters until we are sure about how to deal with them.
386 * Once we are sure, output to the buffer, in the correct form.
387 \*-------------------------------------------------------------------------*/
388 static size_t qpencode(UC c
, UC
*input
, size_t size
,
389 const char *marker
, luaL_Buffer
*buffer
)
392 /* deal with all characters we can have */
394 switch (qpclass
[input
[0]]) {
395 /* might be the CR of a CRLF sequence */
397 if (size
< 2) return size
;
398 if (input
[1] == '\n') {
399 luaL_addstring(buffer
, marker
);
401 } else qpquote(input
[0], buffer
);
403 /* might be a space and that has to be quoted if last in line */
405 if (size
< 3) return size
;
406 /* if it is the last, quote it and we are done */
407 if (input
[1] == '\r' && input
[2] == '\n') {
408 qpquote(input
[0], buffer
);
409 luaL_addstring(buffer
, marker
);
411 } else luaL_addchar(buffer
, input
[0]);
413 /* might have to be quoted always */
415 qpquote(input
[0], buffer
);
417 /* might never have to be quoted */
419 luaL_addchar(buffer
, input
[0]);
422 input
[0] = input
[1]; input
[1] = input
[2];
428 /*-------------------------------------------------------------------------*\
429 * Deal with the final characters
430 \*-------------------------------------------------------------------------*/
431 static size_t qppad(UC
*input
, size_t size
, luaL_Buffer
*buffer
)
434 for (i
= 0; i
< size
; i
++) {
435 if (qpclass
[input
[i
]] == QP_PLAIN
) luaL_addchar(buffer
, input
[i
]);
436 else qpquote(input
[i
], buffer
);
438 if (size
> 0) luaL_addstring(buffer
, EQCRLF
);
442 /*-------------------------------------------------------------------------*\
443 * Incrementally converts a string to quoted-printable
444 * A, B = qp(C, D, marker)
445 * Marker is the text to be used to replace CRLF sequences found in A.
446 * A is the encoded version of the largest prefix of C .. D that
447 * can be encoded without doubts.
448 * B has the remaining bytes of C .. D, *without* encoding.
449 \*-------------------------------------------------------------------------*/
450 static int mime_global_qp(lua_State
*L
)
453 size_t asize
= 0, isize
= 0;
455 const UC
*input
= (UC
*) luaL_optlstring(L
, 1, NULL
, &isize
);
456 const UC
*last
= input
+ isize
;
457 const char *marker
= luaL_optstring(L
, 3, CRLF
);
459 /* end-of-input blackhole */
465 /* make sure we don't confuse buffer stuff with arguments */
467 /* process first part of input */
468 luaL_buffinit(L
, &buffer
);
470 asize
= qpencode(*input
++, atom
, asize
, marker
, &buffer
);
471 input
= (UC
*) luaL_optlstring(L
, 2, NULL
, &isize
);
472 /* if second part is nil, we are done */
474 asize
= qppad(atom
, asize
, &buffer
);
475 luaL_pushresult(&buffer
);
476 if (!(*lua_tostring(L
, -1))) lua_pushnil(L
);
480 /* otherwise process rest of input */
481 last
= input
+ isize
;
483 asize
= qpencode(*input
++, atom
, asize
, marker
, &buffer
);
484 luaL_pushresult(&buffer
);
485 lua_pushlstring(L
, (char *) atom
, asize
);
489 /*-------------------------------------------------------------------------*\
490 * Accumulate characters until we are sure about how to deal with them.
491 * Once we are sure, output the to the buffer, in the correct form.
492 \*-------------------------------------------------------------------------*/
493 static size_t qpdecode(UC c
, UC
*input
, size_t size
, luaL_Buffer
*buffer
) {
496 /* deal with all characters we can deal */
498 /* if we have an escape character */
500 if (size
< 3) return size
;
501 /* eliminate soft line break */
502 if (input
[1] == '\r' && input
[2] == '\n') return 0;
503 /* decode quoted representation */
504 c
= qpunbase
[input
[1]]; d
= qpunbase
[input
[2]];
505 /* if it is an invalid, do not decode */
506 if (c
> 15 || d
> 15) luaL_addlstring(buffer
, (char *)input
, 3);
507 else luaL_addchar(buffer
, (char) ((c
<< 4) + d
));
510 if (size
< 2) return size
;
511 if (input
[1] == '\n') luaL_addlstring(buffer
, (char *)input
, 2);
514 if (input
[0] == '\t' || (input
[0] > 31 && input
[0] < 127))
515 luaL_addchar(buffer
, input
[0]);
520 /*-------------------------------------------------------------------------*\
521 * Incrementally decodes a string in quoted-printable
523 * A is the decoded version of the largest prefix of C .. D that
524 * can be decoded without doubts.
525 * B has the remaining bytes of C .. D, *without* decoding.
526 \*-------------------------------------------------------------------------*/
527 static int mime_global_unqp(lua_State
*L
)
529 size_t asize
= 0, isize
= 0;
531 const UC
*input
= (UC
*) luaL_optlstring(L
, 1, NULL
, &isize
);
532 const UC
*last
= input
+ isize
;
534 /* end-of-input blackhole */
540 /* make sure we don't confuse buffer stuff with arguments */
542 /* process first part of input */
543 luaL_buffinit(L
, &buffer
);
545 asize
= qpdecode(*input
++, atom
, asize
, &buffer
);
546 input
= (UC
*) luaL_optlstring(L
, 2, NULL
, &isize
);
547 /* if second part is nil, we are done */
549 luaL_pushresult(&buffer
);
550 if (!(*lua_tostring(L
, -1))) lua_pushnil(L
);
554 /* otherwise process rest of input */
555 last
= input
+ isize
;
557 asize
= qpdecode(*input
++, atom
, asize
, &buffer
);
558 luaL_pushresult(&buffer
);
559 lua_pushlstring(L
, (char *) atom
, asize
);
563 /*-------------------------------------------------------------------------*\
564 * Incrementally breaks a quoted-printed string into lines
565 * A, n = qpwrp(l, B, length)
566 * A is a copy of B, broken into lines of at most 'length' bytes.
567 * 'l' is how many bytes are left for the first line of B.
568 * 'n' is the number of bytes left in the last line of A.
569 * There are two complications: lines can't be broken in the middle
570 * of an encoded =XX, and there might be line breaks already
571 \*-------------------------------------------------------------------------*/
572 static int mime_global_qpwrp(lua_State
*L
)
575 int left
= (int) luaL_checknumber(L
, 1);
576 const UC
*input
= (UC
*) luaL_optlstring(L
, 2, NULL
, &size
);
577 const UC
*last
= input
+ size
;
578 int length
= (int) luaL_optnumber(L
, 3, 76);
580 /* end-of-input blackhole */
582 if (left
< length
) lua_pushstring(L
, EQCRLF
);
584 lua_pushnumber(L
, length
);
587 /* process all input */
588 luaL_buffinit(L
, &buffer
);
589 while (input
< last
) {
595 luaL_addstring(&buffer
, CRLF
);
600 luaL_addstring(&buffer
, EQCRLF
);
602 luaL_addchar(&buffer
, *input
);
608 luaL_addstring(&buffer
, EQCRLF
);
610 luaL_addchar(&buffer
, *input
);
616 luaL_pushresult(&buffer
);
617 lua_pushnumber(L
, left
);
621 /*-------------------------------------------------------------------------*\
622 * Here is what we do: \n, and \r are considered candidates for line
623 * break. We issue *one* new line marker if any of them is seen alone, or
624 * followed by a different one. That is, \n\n and \r\r will issue two
625 * end of line markers each, but \r\n, \n\r etc will only issue *one*
626 * marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as
627 * probably other more obscure conventions.
629 * c is the current character being processed
630 * last is the previous character
631 \*-------------------------------------------------------------------------*/
632 #define eolcandidate(c) (c == '\r' || c == '\n')
633 static int eolprocess(int c
, int last
, const char *marker
,
636 if (eolcandidate(c
)) {
637 if (eolcandidate(last
)) {
638 if (c
== last
) luaL_addstring(buffer
, marker
);
641 luaL_addstring(buffer
, marker
);
645 luaL_addchar(buffer
, (char) c
);
650 /*-------------------------------------------------------------------------*\
651 * Converts a string to uniform EOL convention.
652 * A, n = eol(o, B, marker)
653 * A is the converted version of the largest prefix of B that can be
654 * converted unambiguously. 'o' is the context returned by the previous
655 * call. 'n' is the new context.
656 \*-------------------------------------------------------------------------*/
657 static int mime_global_eol(lua_State
*L
)
659 int ctx
= luaL_checkint(L
, 1);
661 const char *input
= luaL_optlstring(L
, 2, NULL
, &isize
);
662 const char *last
= input
+ isize
;
663 const char *marker
= luaL_optstring(L
, 3, CRLF
);
665 luaL_buffinit(L
, &buffer
);
666 /* end of input blackhole */
669 lua_pushnumber(L
, 0);
672 /* process all input */
674 ctx
= eolprocess(*input
++, ctx
, marker
, &buffer
);
675 luaL_pushresult(&buffer
);
676 lua_pushnumber(L
, ctx
);
680 /*-------------------------------------------------------------------------*\
681 * Takes one byte and stuff it if needed.
682 \*-------------------------------------------------------------------------*/
683 static size_t dot(int c
, size_t state
, luaL_Buffer
*buffer
)
685 luaL_addchar(buffer
, (char) c
);
690 return (state
== 1)? 2: 0;
693 luaL_addchar(buffer
, '.');
699 /*-------------------------------------------------------------------------*\
700 * Incrementally applies smtp stuffing to a string
702 \*-------------------------------------------------------------------------*/
703 static int mime_global_dot(lua_State
*L
)
705 size_t isize
= 0, state
= (size_t) luaL_checknumber(L
, 1);
706 const char *input
= luaL_optlstring(L
, 2, NULL
, &isize
);
707 const char *last
= input
+ isize
;
709 /* end-of-input blackhole */
712 lua_pushnumber(L
, 2);
715 /* process all input */
716 luaL_buffinit(L
, &buffer
);
718 state
= dot(*input
++, state
, &buffer
);
719 luaL_pushresult(&buffer
);
720 lua_pushnumber(L
, (lua_Number
) state
);