beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luasocket / src / mime.c
blobdddd3d66ea06e0b70f71800f8f3fb571767e8887
1 /*=========================================================================*\
2 * MIME support functions
3 * LuaSocket toolkit
4 \*=========================================================================*/
5 #include <string.h>
7 #include "lua.h"
8 #include "lauxlib.h"
10 #if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
11 #include "compat-5.1.h"
12 #endif
14 #include "mime.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 },
58 { NULL, NULL }
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 /*-------------------------------------------------------------------------*\
70 * Base64 globals
71 \*-------------------------------------------------------------------------*/
72 static const UC b64base[] =
73 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
74 static UC b64unbase[256];
76 /*=========================================================================*\
77 * Exported functions
78 \*=========================================================================*/
79 /*-------------------------------------------------------------------------*\
80 * Initializes module
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);
88 lua_rawset(L, -3);
89 /* initialize lookup tables */
90 qpsetup(qpclass, qpunbase);
91 b64setup(b64unbase);
92 return 1;
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)
107 size_t size = 0;
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);
112 luaL_Buffer buffer;
113 /* end of input black-hole */
114 if (!input) {
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 */
118 else lua_pushnil(L);
119 lua_pushnumber(L, length);
120 return 2;
122 luaL_buffinit(L, &buffer);
123 while (input < last) {
124 switch (*input) {
125 case '\r':
126 break;
127 case '\n':
128 luaL_addstring(&buffer, CRLF);
129 left = length;
130 break;
131 default:
132 if (left <= 0) {
133 left = length;
134 luaL_addstring(&buffer, CRLF);
136 luaL_addchar(&buffer, *input);
137 left--;
138 break;
140 input++;
142 luaL_pushresult(&buffer);
143 lua_pushnumber(L, left);
144 return 2;
147 /*-------------------------------------------------------------------------*\
148 * Fill base64 decode map.
149 \*-------------------------------------------------------------------------*/
150 static void b64setup(UC *unbase)
152 int i;
153 for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
154 for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i;
155 unbase['='] = 0;
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,
164 luaL_Buffer *buffer)
166 input[size++] = c;
167 if (size == 3) {
168 UC code[4];
169 unsigned long value = 0;
170 value += input[0]; value <<= 8;
171 value += input[1]; value <<= 8;
172 value += input[2];
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);
178 size = 0;
180 return size;
183 /*-------------------------------------------------------------------------*\
184 * Encodes the Base64 last 1 or 2 bytes and adds padding '='
185 * Result, if any, is appended to buffer.
186 * Returns 0.
187 \*-------------------------------------------------------------------------*/
188 static size_t b64pad(const UC *input, size_t size,
189 luaL_Buffer *buffer)
191 unsigned long value = 0;
192 UC code[4] = {'=', '=', '=', '='};
193 switch (size) {
194 case 1:
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);
199 break;
200 case 2:
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);
207 break;
208 default:
209 break;
211 return 0;
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,
220 luaL_Buffer *buffer)
222 /* ignore invalid characters */
223 if (b64unbase[c] > 64) return size;
224 input[size++] = c;
225 /* decode atom */
226 if (size == 4) {
227 UC decoded[3];
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);
239 return 0;
240 /* need more data */
241 } else return size;
244 /*-------------------------------------------------------------------------*\
245 * Incrementally applies the Base64 transfer content encoding to a string
246 * A, B = b64(C, D)
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)
255 UC atom[3];
256 size_t isize = 0, asize = 0;
257 const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
258 const UC *last = input + isize;
259 luaL_Buffer buffer;
260 /* end-of-input blackhole */
261 if (!input) {
262 lua_pushnil(L);
263 lua_pushnil(L);
264 return 2;
266 /* make sure we don't confuse buffer stuff with arguments */
267 lua_settop(L, 2);
268 /* process first part of the input */
269 luaL_buffinit(L, &buffer);
270 while (input < last)
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 */
274 if (!input) {
275 size_t osize = 0;
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);
281 lua_pushnil(L);
282 return 2;
284 /* otherwise process the second part */
285 last = input + isize;
286 while (input < last)
287 asize = b64encode(*input++, atom, asize, &buffer);
288 luaL_pushresult(&buffer);
289 lua_pushlstring(L, (char *) atom, asize);
290 return 2;
293 /*-------------------------------------------------------------------------*\
294 * Incrementally removes the Base64 transfer content encoding from a string
295 * A, B = b64(C, D)
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)
301 UC atom[4];
302 size_t isize = 0, asize = 0;
303 const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
304 const UC *last = input + isize;
305 luaL_Buffer buffer;
306 /* end-of-input blackhole */
307 if (!input) {
308 lua_pushnil(L);
309 lua_pushnil(L);
310 return 2;
312 /* make sure we don't confuse buffer stuff with arguments */
313 lua_settop(L, 2);
314 /* process first part of the input */
315 luaL_buffinit(L, &buffer);
316 while (input < last)
317 asize = b64decode(*input++, atom, asize, &buffer);
318 input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
319 /* if second is nil, we are done */
320 if (!input) {
321 size_t osize = 0;
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);
326 lua_pushnil(L);
327 return 2;
329 /* otherwise, process the rest of the input */
330 last = input + isize;
331 while (input < last)
332 asize = b64decode(*input++, atom, asize, &buffer);
333 luaL_pushresult(&buffer);
334 lua_pushlstring(L, (char *) atom, asize);
335 return 2;
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)
356 int i;
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;
362 cl['\r'] = QP_CR;
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;
371 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)
391 input[size++] = c;
392 /* deal with all characters we can have */
393 while (size > 0) {
394 switch (qpclass[input[0]]) {
395 /* might be the CR of a CRLF sequence */
396 case QP_CR:
397 if (size < 2) return size;
398 if (input[1] == '\n') {
399 luaL_addstring(buffer, marker);
400 return 0;
401 } else qpquote(input[0], buffer);
402 break;
403 /* might be a space and that has to be quoted if last in line */
404 case QP_IF_LAST:
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);
410 return 0;
411 } else luaL_addchar(buffer, input[0]);
412 break;
413 /* might have to be quoted always */
414 case QP_QUOTED:
415 qpquote(input[0], buffer);
416 break;
417 /* might never have to be quoted */
418 default:
419 luaL_addchar(buffer, input[0]);
420 break;
422 input[0] = input[1]; input[1] = input[2];
423 size--;
425 return 0;
428 /*-------------------------------------------------------------------------*\
429 * Deal with the final characters
430 \*-------------------------------------------------------------------------*/
431 static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
433 size_t i;
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);
439 return 0;
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;
454 UC atom[3];
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);
458 luaL_Buffer buffer;
459 /* end-of-input blackhole */
460 if (!input) {
461 lua_pushnil(L);
462 lua_pushnil(L);
463 return 2;
465 /* make sure we don't confuse buffer stuff with arguments */
466 lua_settop(L, 3);
467 /* process first part of input */
468 luaL_buffinit(L, &buffer);
469 while (input < last)
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 */
473 if (!input) {
474 asize = qppad(atom, asize, &buffer);
475 luaL_pushresult(&buffer);
476 if (!(*lua_tostring(L, -1))) lua_pushnil(L);
477 lua_pushnil(L);
478 return 2;
480 /* otherwise process rest of input */
481 last = input + isize;
482 while (input < last)
483 asize = qpencode(*input++, atom, asize, marker, &buffer);
484 luaL_pushresult(&buffer);
485 lua_pushlstring(L, (char *) atom, asize);
486 return 2;
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) {
494 int d;
495 input[size++] = c;
496 /* deal with all characters we can deal */
497 switch (input[0]) {
498 /* if we have an escape character */
499 case '=':
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));
508 return 0;
509 case '\r':
510 if (size < 2) return size;
511 if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2);
512 return 0;
513 default:
514 if (input[0] == '\t' || (input[0] > 31 && input[0] < 127))
515 luaL_addchar(buffer, input[0]);
516 return 0;
520 /*-------------------------------------------------------------------------*\
521 * Incrementally decodes a string in quoted-printable
522 * A, B = qp(C, D)
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;
530 UC atom[3];
531 const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
532 const UC *last = input + isize;
533 luaL_Buffer buffer;
534 /* end-of-input blackhole */
535 if (!input) {
536 lua_pushnil(L);
537 lua_pushnil(L);
538 return 2;
540 /* make sure we don't confuse buffer stuff with arguments */
541 lua_settop(L, 2);
542 /* process first part of input */
543 luaL_buffinit(L, &buffer);
544 while (input < last)
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 */
548 if (!input) {
549 luaL_pushresult(&buffer);
550 if (!(*lua_tostring(L, -1))) lua_pushnil(L);
551 lua_pushnil(L);
552 return 2;
554 /* otherwise process rest of input */
555 last = input + isize;
556 while (input < last)
557 asize = qpdecode(*input++, atom, asize, &buffer);
558 luaL_pushresult(&buffer);
559 lua_pushlstring(L, (char *) atom, asize);
560 return 2;
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)
574 size_t size = 0;
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);
579 luaL_Buffer buffer;
580 /* end-of-input blackhole */
581 if (!input) {
582 if (left < length) lua_pushstring(L, EQCRLF);
583 else lua_pushnil(L);
584 lua_pushnumber(L, length);
585 return 2;
587 /* process all input */
588 luaL_buffinit(L, &buffer);
589 while (input < last) {
590 switch (*input) {
591 case '\r':
592 break;
593 case '\n':
594 left = length;
595 luaL_addstring(&buffer, CRLF);
596 break;
597 case '=':
598 if (left <= 3) {
599 left = length;
600 luaL_addstring(&buffer, EQCRLF);
602 luaL_addchar(&buffer, *input);
603 left--;
604 break;
605 default:
606 if (left <= 1) {
607 left = length;
608 luaL_addstring(&buffer, EQCRLF);
610 luaL_addchar(&buffer, *input);
611 left--;
612 break;
614 input++;
616 luaL_pushresult(&buffer);
617 lua_pushnumber(L, left);
618 return 2;
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,
634 luaL_Buffer *buffer)
636 if (eolcandidate(c)) {
637 if (eolcandidate(last)) {
638 if (c == last) luaL_addstring(buffer, marker);
639 return 0;
640 } else {
641 luaL_addstring(buffer, marker);
642 return c;
644 } else {
645 luaL_addchar(buffer, (char) c);
646 return 0;
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);
660 size_t isize = 0;
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);
664 luaL_Buffer buffer;
665 luaL_buffinit(L, &buffer);
666 /* end of input blackhole */
667 if (!input) {
668 lua_pushnil(L);
669 lua_pushnumber(L, 0);
670 return 2;
672 /* process all input */
673 while (input < last)
674 ctx = eolprocess(*input++, ctx, marker, &buffer);
675 luaL_pushresult(&buffer);
676 lua_pushnumber(L, ctx);
677 return 2;
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);
686 switch (c) {
687 case '\r':
688 return 1;
689 case '\n':
690 return (state == 1)? 2: 0;
691 case '.':
692 if (state == 2)
693 luaL_addchar(buffer, '.');
694 default:
695 return 0;
699 /*-------------------------------------------------------------------------*\
700 * Incrementally applies smtp stuffing to a string
701 * A, n = dot(l, D)
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;
708 luaL_Buffer buffer;
709 /* end-of-input blackhole */
710 if (!input) {
711 lua_pushnil(L);
712 lua_pushnumber(L, 2);
713 return 2;
715 /* process all input */
716 luaL_buffinit(L, &buffer);
717 while (input < last)
718 state = dot(*input++, state, &buffer);
719 luaL_pushresult(&buffer);
720 lua_pushnumber(L, (lua_Number) state);
721 return 2;