Advertisement
SirBaconBitz

Untitled

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