diff options
Diffstat (limited to 'src/mime.c')
-rw-r--r-- | src/mime.c | 138 |
1 files changed, 65 insertions, 73 deletions
@@ -10,6 +10,7 @@ | |||
10 | #include <lauxlib.h> | 10 | #include <lauxlib.h> |
11 | 11 | ||
12 | #include "luasocket.h" | 12 | #include "luasocket.h" |
13 | #include "auxiliar.h" | ||
13 | #include "mime.h" | 14 | #include "mime.h" |
14 | 15 | ||
15 | /*=========================================================================*\ | 16 | /*=========================================================================*\ |
@@ -45,18 +46,16 @@ 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 qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer); |
46 | static size_t qpencode(UC c, UC *input, size_t size, | 47 | static size_t qpencode(UC c, UC *input, size_t size, |
47 | const char *marker, luaL_Buffer *buffer); | 48 | const char *marker, luaL_Buffer *buffer); |
48 | 49 | static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer); | |
49 | static const char *checklstring(lua_State *L, int n, size_t *l); | ||
50 | static const char *optlstring(lua_State *L, int n, const char *v, size_t *l); | ||
51 | 50 | ||
52 | /* code support functions */ | 51 | /* code support functions */ |
53 | static luaL_reg func[] = { | 52 | static luaL_reg func[] = { |
53 | { "b64", mime_global_b64 }, | ||
54 | { "eol", mime_global_eol }, | 54 | { "eol", mime_global_eol }, |
55 | { "qp", mime_global_qp }, | 55 | { "qp", mime_global_qp }, |
56 | { "unqp", mime_global_unqp }, | ||
57 | { "qpwrp", mime_global_qpwrp }, | 56 | { "qpwrp", mime_global_qpwrp }, |
58 | { "b64", mime_global_b64 }, | ||
59 | { "unb64", mime_global_unb64 }, | 57 | { "unb64", mime_global_unb64 }, |
58 | { "unqp", mime_global_unqp }, | ||
60 | { "wrp", mime_global_wrp }, | 59 | { "wrp", mime_global_wrp }, |
61 | { NULL, NULL } | 60 | { NULL, NULL } |
62 | }; | 61 | }; |
@@ -82,17 +81,10 @@ static UC b64unbase[256]; | |||
82 | /*-------------------------------------------------------------------------*\ | 81 | /*-------------------------------------------------------------------------*\ |
83 | * Initializes module | 82 | * Initializes module |
84 | \*-------------------------------------------------------------------------*/ | 83 | \*-------------------------------------------------------------------------*/ |
85 | void mime_open(lua_State *L) | 84 | int mime_open(lua_State *L) |
86 | { | 85 | { |
87 | lua_pushstring(L, LUASOCKET_LIBNAME); | 86 | lua_pushstring(L, LUASOCKET_LIBNAME); |
88 | lua_gettable(L, LUA_GLOBALSINDEX); | 87 | lua_gettable(L, LUA_GLOBALSINDEX); |
89 | if (lua_isnil(L, -1)) { | ||
90 | lua_pop(L, 1); | ||
91 | lua_newtable(L); | ||
92 | lua_pushstring(L, LUASOCKET_LIBNAME); | ||
93 | lua_pushvalue(L, -2); | ||
94 | lua_settable(L, LUA_GLOBALSINDEX); | ||
95 | } | ||
96 | lua_pushstring(L, "mime"); | 88 | lua_pushstring(L, "mime"); |
97 | lua_newtable(L); | 89 | lua_newtable(L); |
98 | luaL_openlib(L, NULL, func, 0); | 90 | luaL_openlib(L, NULL, func, 0); |
@@ -101,25 +93,7 @@ void mime_open(lua_State *L) | |||
101 | /* initialize lookup tables */ | 93 | /* initialize lookup tables */ |
102 | qpsetup(qpclass, qpunbase); | 94 | qpsetup(qpclass, qpunbase); |
103 | b64setup(b64unbase); | 95 | b64setup(b64unbase); |
104 | } | 96 | return 0; |
105 | |||
106 | /*-------------------------------------------------------------------------*\ | ||
107 | * Check if a string was provided. We accept false also. | ||
108 | \*-------------------------------------------------------------------------*/ | ||
109 | static const char *checklstring(lua_State *L, int n, size_t *l) | ||
110 | { | ||
111 | if (lua_isnil(L, n) || (lua_isboolean(L, n) && !lua_toboolean(L, n))) { | ||
112 | *l = 0; | ||
113 | return NULL; | ||
114 | } else return luaL_checklstring(L, n, l); | ||
115 | } | ||
116 | |||
117 | static const char *optlstring(lua_State *L, int n, const char *v, size_t *l) | ||
118 | { | ||
119 | if (lua_isnil(L, n) || (lua_isboolean(L, n) && !lua_toboolean(L, n))) { | ||
120 | *l = 0; | ||
121 | return NULL; | ||
122 | } else return luaL_optlstring(L, n, v, l); | ||
123 | } | 97 | } |
124 | 98 | ||
125 | /*=========================================================================*\ | 99 | /*=========================================================================*\ |
@@ -127,31 +101,42 @@ static const char *optlstring(lua_State *L, int n, const char *v, size_t *l) | |||
127 | \*=========================================================================*/ | 101 | \*=========================================================================*/ |
128 | /*-------------------------------------------------------------------------*\ | 102 | /*-------------------------------------------------------------------------*\ |
129 | * Incrementaly breaks a string into lines | 103 | * Incrementaly breaks a string into lines |
130 | * A, n = wrp(l, B, length, marker) | 104 | * A, n = wrp(l, B, length) |
131 | * A is a copy of B, broken into lines of at most 'length' bytes. | 105 | * A is a copy of B, broken into lines of at most 'length' bytes. |
132 | * 'l' is how many bytes are left for the first line of B. | 106 | * 'l' is how many bytes are left for the first line of B. |
133 | * 'n' is the number of bytes left in the last line of A. | 107 | * 'n' is the number of bytes left in the last line of A. |
134 | * Marker is the end-of-line marker. | ||
135 | \*-------------------------------------------------------------------------*/ | 108 | \*-------------------------------------------------------------------------*/ |
136 | static int mime_global_wrp(lua_State *L) | 109 | static int mime_global_wrp(lua_State *L) |
137 | { | 110 | { |
138 | size_t size = 0; | 111 | size_t size = 0; |
139 | int left = (int) luaL_checknumber(L, 1); | 112 | int left = (int) luaL_checknumber(L, 1); |
140 | const UC *input = (UC *) checklstring(L, 2, &size); | 113 | const UC *input = (UC *) aux_optlstring(L, 2, NULL, &size); |
141 | const UC *last = input + size; | 114 | const UC *last = input + size; |
142 | int length = (int) luaL_optnumber(L, 3, 76); | 115 | int length = (int) luaL_optnumber(L, 3, 76); |
143 | const char *marker = luaL_optstring(L, 4, CRLF); | ||
144 | luaL_Buffer buffer; | 116 | luaL_Buffer buffer; |
145 | luaL_buffinit(L, &buffer); | 117 | luaL_buffinit(L, &buffer); |
146 | while (input < last) { | 118 | while (input < last) { |
147 | luaL_putchar(&buffer, *input++); | 119 | switch (*input) { |
148 | if (--left <= 0) { | 120 | case CR: |
149 | luaL_addstring(&buffer, marker); | 121 | break; |
150 | left = length; | 122 | case LF: |
123 | luaL_addstring(&buffer, CRLF); | ||
124 | left = length; | ||
125 | break; | ||
126 | default: | ||
127 | if (left <= 0) { | ||
128 | left = length; | ||
129 | luaL_addstring(&buffer, CRLF); | ||
130 | } | ||
131 | luaL_putchar(&buffer, *input); | ||
132 | left--; | ||
133 | break; | ||
151 | } | 134 | } |
135 | input++; | ||
152 | } | 136 | } |
137 | /* if in last chunk and last line wasn't terminated, add a line-break */ | ||
153 | if (!input && left < length) { | 138 | if (!input && left < length) { |
154 | luaL_addstring(&buffer, marker); | 139 | luaL_addstring(&buffer, CRLF); |
155 | left = length; | 140 | left = length; |
156 | } | 141 | } |
157 | luaL_pushresult(&buffer); | 142 | luaL_pushresult(&buffer); |
@@ -235,7 +220,6 @@ static size_t b64pad(const UC *input, size_t size, | |||
235 | static size_t b64decode(UC c, UC *input, size_t size, | 220 | static size_t b64decode(UC c, UC *input, size_t size, |
236 | luaL_Buffer *buffer) | 221 | luaL_Buffer *buffer) |
237 | { | 222 | { |
238 | |||
239 | /* ignore invalid characters */ | 223 | /* ignore invalid characters */ |
240 | if (b64unbase[c] > 64) return size; | 224 | if (b64unbase[c] > 64) return size; |
241 | input[size++] = c; | 225 | input[size++] = c; |
@@ -277,7 +261,7 @@ static int mime_global_b64(lua_State *L) | |||
277 | luaL_buffinit(L, &buffer); | 261 | luaL_buffinit(L, &buffer); |
278 | while (input < last) | 262 | while (input < last) |
279 | asize = b64encode(*input++, atom, asize, &buffer); | 263 | asize = b64encode(*input++, atom, asize, &buffer); |
280 | input = (UC *) optlstring(L, 2, NULL, &isize); | 264 | input = (UC *) aux_optlstring(L, 2, NULL, &isize); |
281 | if (input) { | 265 | if (input) { |
282 | last = input + isize; | 266 | last = input + isize; |
283 | while (input < last) | 267 | while (input < last) |
@@ -305,12 +289,14 @@ static int mime_global_unb64(lua_State *L) | |||
305 | luaL_buffinit(L, &buffer); | 289 | luaL_buffinit(L, &buffer); |
306 | while (input < last) | 290 | while (input < last) |
307 | asize = b64decode(*input++, atom, asize, &buffer); | 291 | asize = b64decode(*input++, atom, asize, &buffer); |
308 | input = (UC *) optlstring(L, 2, NULL, &isize); | 292 | input = (UC *) aux_optlstring(L, 2, NULL, &isize); |
309 | if (input) { | 293 | if (input) { |
310 | last = input + isize; | 294 | last = input + isize; |
311 | while (input < last) | 295 | while (input < last) |
312 | asize = b64decode(*input++, atom, asize, &buffer); | 296 | asize = b64decode(*input++, atom, asize, &buffer); |
313 | } | 297 | } |
298 | /* if !input we are done. if atom > 0, the remaning is invalid. we just | ||
299 | * return it undecoded. */ | ||
314 | luaL_pushresult(&buffer); | 300 | luaL_pushresult(&buffer); |
315 | lua_pushlstring(L, (char *) atom, asize); | 301 | lua_pushlstring(L, (char *) atom, asize); |
316 | return 2; | 302 | return 2; |
@@ -416,7 +402,7 @@ static size_t qpencode(UC c, UC *input, size_t size, | |||
416 | /*-------------------------------------------------------------------------*\ | 402 | /*-------------------------------------------------------------------------*\ |
417 | * Deal with the final characters | 403 | * Deal with the final characters |
418 | \*-------------------------------------------------------------------------*/ | 404 | \*-------------------------------------------------------------------------*/ |
419 | static void qppad(UC *input, size_t size, luaL_Buffer *buffer) | 405 | static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer) |
420 | { | 406 | { |
421 | size_t i; | 407 | size_t i; |
422 | for (i = 0; i < size; i++) { | 408 | for (i = 0; i < size; i++) { |
@@ -424,12 +410,13 @@ static void qppad(UC *input, size_t size, luaL_Buffer *buffer) | |||
424 | else qpquote(input[i], buffer); | 410 | else qpquote(input[i], buffer); |
425 | } | 411 | } |
426 | luaL_addstring(buffer, EQCRLF); | 412 | luaL_addstring(buffer, EQCRLF); |
413 | return 0; | ||
427 | } | 414 | } |
428 | 415 | ||
429 | /*-------------------------------------------------------------------------*\ | 416 | /*-------------------------------------------------------------------------*\ |
430 | * Incrementally converts a string to quoted-printable | 417 | * Incrementally converts a string to quoted-printable |
431 | * A, B = qp(C, D, marker) | 418 | * A, B = qp(C, D, marker) |
432 | * Crlf is the text to be used to replace CRLF sequences found in A. | 419 | * Marker is the text to be used to replace CRLF sequences found in A. |
433 | * A is the encoded version of the largest prefix of C .. D that | 420 | * A is the encoded version of the largest prefix of C .. D that |
434 | * can be encoded without doubts. | 421 | * can be encoded without doubts. |
435 | * B has the remaining bytes of C .. D, *without* encoding. | 422 | * B has the remaining bytes of C .. D, *without* encoding. |
@@ -439,19 +426,20 @@ static int mime_global_qp(lua_State *L) | |||
439 | 426 | ||
440 | size_t asize = 0, isize = 0; | 427 | size_t asize = 0, isize = 0; |
441 | UC atom[3]; | 428 | UC atom[3]; |
442 | const UC *input = (UC *) checklstring(L, 1, &isize); | 429 | const UC *input = (UC *) aux_optlstring(L, 1, NULL, &isize); |
443 | const UC *last = input + isize; | 430 | const UC *last = input + isize; |
444 | const char *marker = luaL_optstring(L, 3, CRLF); | 431 | const char *marker = luaL_optstring(L, 3, CRLF); |
445 | luaL_Buffer buffer; | 432 | luaL_Buffer buffer; |
446 | luaL_buffinit(L, &buffer); | 433 | luaL_buffinit(L, &buffer); |
447 | while (input < last) | 434 | while (input < last) |
448 | asize = qpencode(*input++, atom, asize, marker, &buffer); | 435 | asize = qpencode(*input++, atom, asize, marker, &buffer); |
449 | input = (UC *) optlstring(L, 2, NULL, &isize); | 436 | input = (UC *) aux_optlstring(L, 2, NULL, &isize); |
450 | if (input) { | 437 | if (input) { |
451 | last = input + isize; | 438 | last = input + isize; |
452 | while (input < last) | 439 | while (input < last) |
453 | asize = qpencode(*input++, atom, asize, marker, &buffer); | 440 | asize = qpencode(*input++, atom, asize, marker, &buffer); |
454 | } else qppad(atom, asize, &buffer); | 441 | } else |
442 | asize = qppad(atom, asize, &buffer); | ||
455 | luaL_pushresult(&buffer); | 443 | luaL_pushresult(&buffer); |
456 | lua_pushlstring(L, (char *) atom, asize); | 444 | lua_pushlstring(L, (char *) atom, asize); |
457 | return 2; | 445 | return 2; |
@@ -507,13 +495,13 @@ static int mime_global_unqp(lua_State *L) | |||
507 | 495 | ||
508 | size_t asize = 0, isize = 0; | 496 | size_t asize = 0, isize = 0; |
509 | UC atom[3]; | 497 | UC atom[3]; |
510 | const UC *input = (UC *) checklstring(L, 1, &isize); | 498 | const UC *input = (UC *) aux_optlstring(L, 1, NULL, &isize); |
511 | const UC *last = input + isize; | 499 | const UC *last = input + isize; |
512 | luaL_Buffer buffer; | 500 | luaL_Buffer buffer; |
513 | luaL_buffinit(L, &buffer); | 501 | luaL_buffinit(L, &buffer); |
514 | while (input < last) | 502 | while (input < last) |
515 | asize = qpdecode(*input++, atom, asize, &buffer); | 503 | asize = qpdecode(*input++, atom, asize, &buffer); |
516 | input = (UC *) optlstring(L, 2, NULL, &isize); | 504 | input = (UC *) aux_optlstring(L, 2, NULL, &isize); |
517 | if (input) { | 505 | if (input) { |
518 | last = input + isize; | 506 | last = input + isize; |
519 | while (input < last) | 507 | while (input < last) |
@@ -537,38 +525,39 @@ static int mime_global_qpwrp(lua_State *L) | |||
537 | { | 525 | { |
538 | size_t size = 0; | 526 | size_t size = 0; |
539 | int left = (int) luaL_checknumber(L, 1); | 527 | int left = (int) luaL_checknumber(L, 1); |
540 | const UC *input = (UC *) checklstring(L, 2, &size); | 528 | const UC *input = (UC *) aux_optlstring(L, 2, NULL, &size); |
541 | const UC *last = input + size; | 529 | const UC *last = input + size; |
542 | int length = (int) luaL_optnumber(L, 3, 76); | 530 | int length = (int) luaL_optnumber(L, 3, 76); |
543 | luaL_Buffer buffer; | 531 | luaL_Buffer buffer; |
544 | luaL_buffinit(L, &buffer); | 532 | luaL_buffinit(L, &buffer); |
545 | while (input < last) { | 533 | while (input < last) { |
546 | left--; | ||
547 | switch (*input) { | 534 | switch (*input) { |
548 | case '=': | 535 | case CR: |
549 | /* if there's no room in this line for the quoted char, | ||
550 | * output a soft line break now */ | ||
551 | if (left <= 3) { | ||
552 | luaL_addstring(&buffer, EQCRLF); | ||
553 | left = length; | ||
554 | } | ||
555 | break; | ||
556 | /* \r\n starts a new line */ | ||
557 | case CR: | ||
558 | break; | 536 | break; |
559 | case LF: | 537 | case LF: |
560 | left = length; | 538 | left = length; |
539 | luaL_addstring(&buffer, CRLF); | ||
561 | break; | 540 | break; |
562 | default: | 541 | case '=': |
563 | /* if in last column, output a soft line break */ | 542 | if (left <= 3) { |
564 | if (left <= 1) { | 543 | left = length; |
565 | luaL_addstring(&buffer, EQCRLF); | 544 | luaL_addstring(&buffer, EQCRLF); |
545 | } | ||
546 | luaL_putchar(&buffer, *input); | ||
547 | left--; | ||
548 | break; | ||
549 | default: | ||
550 | if (left <= 1) { | ||
566 | left = length; | 551 | left = length; |
552 | luaL_addstring(&buffer, EQCRLF); | ||
567 | } | 553 | } |
554 | luaL_putchar(&buffer, *input); | ||
555 | left--; | ||
556 | break; | ||
568 | } | 557 | } |
569 | luaL_putchar(&buffer, *input); | ||
570 | input++; | 558 | input++; |
571 | } | 559 | } |
560 | /* if in last chunk and last line wasn't terminated, add a soft-break */ | ||
572 | if (!input && left < length) { | 561 | if (!input && left < length) { |
573 | luaL_addstring(&buffer, EQCRLF); | 562 | luaL_addstring(&buffer, EQCRLF); |
574 | left = length; | 563 | left = length; |
@@ -579,10 +568,10 @@ static int mime_global_qpwrp(lua_State *L) | |||
579 | } | 568 | } |
580 | 569 | ||
581 | /*-------------------------------------------------------------------------*\ | 570 | /*-------------------------------------------------------------------------*\ |
582 | * Here is what we do: \n, \r and \f are considered candidates for line | 571 | * Here is what we do: \n, and \r are considered candidates for line |
583 | * break. We issue *one* new line marker if any of them is seen alone, or | 572 | * break. We issue *one* new line marker if any of them is seen alone, or |
584 | * followed by a different one. That is, \n\n, \r\r and \f\f will issue two | 573 | * followed by a different one. That is, \n\n and \r\r will issue two |
585 | * end of line markers each, but \r\n, \n\r, \r\f etc will only issue *one* | 574 | * end of line markers each, but \r\n, \n\r etc will only issue *one* |
586 | * marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as | 575 | * marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as |
587 | * probably other more obscure conventions. | 576 | * probably other more obscure conventions. |
588 | \*-------------------------------------------------------------------------*/ | 577 | \*-------------------------------------------------------------------------*/ |
@@ -616,21 +605,24 @@ static int mime_global_eol(lua_State *L) | |||
616 | { | 605 | { |
617 | size_t asize = 0, isize = 0; | 606 | size_t asize = 0, isize = 0; |
618 | UC atom[2]; | 607 | UC atom[2]; |
619 | const UC *input = (UC *) checklstring(L, 1, &isize); | 608 | const UC *input = (UC *) aux_optlstring(L, 1, NULL, &isize); |
620 | const UC *last = input + isize; | 609 | const UC *last = input + isize; |
621 | const char *marker = luaL_optstring(L, 3, CRLF); | 610 | const char *marker = luaL_optstring(L, 3, CRLF); |
622 | luaL_Buffer buffer; | 611 | luaL_Buffer buffer; |
623 | luaL_buffinit(L, &buffer); | 612 | luaL_buffinit(L, &buffer); |
624 | while (input < last) | 613 | while (input < last) |
625 | asize = eolconvert(*input++, atom, asize, marker, &buffer); | 614 | asize = eolconvert(*input++, atom, asize, marker, &buffer); |
626 | input = (UC *) optlstring(L, 2, NULL, &isize); | 615 | input = (UC *) aux_optlstring(L, 2, NULL, &isize); |
627 | if (input) { | 616 | if (input) { |
628 | last = input + isize; | 617 | last = input + isize; |
629 | while (input < last) | 618 | while (input < last) |
630 | asize = eolconvert(*input++, atom, asize, marker, &buffer); | 619 | asize = eolconvert(*input++, atom, asize, marker, &buffer); |
631 | /* if there is something in atom, it's one character, and it | 620 | /* if there is something in atom, it's one character, and it |
632 | * is a candidate. so we output a new line */ | 621 | * is a candidate. so we output a new line */ |
633 | } else if (asize > 0) luaL_addstring(&buffer, marker); | 622 | } else if (asize > 0) { |
623 | luaL_addstring(&buffer, marker); | ||
624 | asize = 0; | ||
625 | } | ||
634 | luaL_pushresult(&buffer); | 626 | luaL_pushresult(&buffer); |
635 | lua_pushlstring(L, (char *) atom, asize); | 627 | lua_pushlstring(L, (char *) atom, asize); |
636 | return 2; | 628 | return 2; |