diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mime.c | 80 | ||||
| -rw-r--r-- | src/mime.lua | 92 |
2 files changed, 93 insertions, 79 deletions
| @@ -35,17 +35,20 @@ static int mime_global_unqp(lua_State *L); | |||
| 35 | static int mime_global_qpfmt(lua_State *L); | 35 | static int mime_global_qpfmt(lua_State *L); |
| 36 | static int mime_global_eol(lua_State *L); | 36 | static int mime_global_eol(lua_State *L); |
| 37 | 37 | ||
| 38 | static void b64fill(UC *b64unbase); | 38 | static void b64setup(UC *b64unbase); |
| 39 | static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer); | 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); | 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); | 41 | static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer); |
| 42 | 42 | ||
| 43 | static void qpfill(UC *qpclass, UC *qpunbase); | 43 | static void qpsetup(UC *qpclass, UC *qpunbase); |
| 44 | static void qpquote(UC c, luaL_Buffer *buffer); | 44 | static void qpquote(UC c, luaL_Buffer *buffer); |
| 45 | static size_t qpdecode(UC c, UC *input, size_t size, 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, | 46 | static size_t qpencode(UC c, UC *input, size_t size, |
| 47 | const char *marker, luaL_Buffer *buffer); | 47 | const char *marker, luaL_Buffer *buffer); |
| 48 | 48 | ||
| 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 | |||
| 49 | /* code support functions */ | 52 | /* code support functions */ |
| 50 | static luaL_reg func[] = { | 53 | static luaL_reg func[] = { |
| 51 | { "eol", mime_global_eol }, | 54 | { "eol", mime_global_eol }, |
| @@ -96,8 +99,27 @@ void mime_open(lua_State *L) | |||
| 96 | lua_settable(L, -3); | 99 | lua_settable(L, -3); |
| 97 | lua_pop(L, 1); | 100 | lua_pop(L, 1); |
| 98 | /* initialize lookup tables */ | 101 | /* initialize lookup tables */ |
| 99 | qpfill(qpclass, qpunbase); | 102 | qpsetup(qpclass, qpunbase); |
| 100 | b64fill(b64unbase); | 103 | b64setup(b64unbase); |
| 104 | } | ||
| 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); | ||
| 101 | } | 123 | } |
| 102 | 124 | ||
| 103 | /*=========================================================================*\ | 125 | /*=========================================================================*\ |
| @@ -105,19 +127,19 @@ void mime_open(lua_State *L) | |||
| 105 | \*=========================================================================*/ | 127 | \*=========================================================================*/ |
| 106 | /*-------------------------------------------------------------------------*\ | 128 | /*-------------------------------------------------------------------------*\ |
| 107 | * Incrementaly breaks a string into lines | 129 | * Incrementaly breaks a string into lines |
| 108 | * A, n = fmt(B, length, left) | 130 | * A, n = fmt(l, B, length, marker) |
| 109 | * A is a copy of B, broken into lines of at most 'length' bytes. | 131 | * A is a copy of B, broken into lines of at most 'length' bytes. |
| 110 | * Left is how many bytes are left in the first line of B. 'n' is the number | 132 | * 'l' is how many bytes are left for the first line of B. |
| 111 | * of bytes left in the last line of A. | 133 | * 'n' is the number of bytes left in the last line of A. |
| 134 | * Marker is the end-of-line marker. | ||
| 112 | \*-------------------------------------------------------------------------*/ | 135 | \*-------------------------------------------------------------------------*/ |
| 113 | static int mime_global_fmt(lua_State *L) | 136 | static int mime_global_fmt(lua_State *L) |
| 114 | { | 137 | { |
| 115 | size_t size = 0; | 138 | size_t size = 0; |
| 116 | const UC *input = (UC *) (lua_isnil(L, 1)? NULL: | 139 | int left = (int) luaL_checknumber(L, 1); |
| 117 | luaL_checklstring(L, 1, &size)); | 140 | const UC *input = (UC *) checklstring(L, 2, &size); |
| 118 | const UC *last = input + size; | 141 | const UC *last = input + size; |
| 119 | int length = (int) luaL_checknumber(L, 2); | 142 | int length = (int) luaL_optnumber(L, 3, 76); |
| 120 | int left = (int) luaL_optnumber(L, 3, length); | ||
| 121 | const char *marker = luaL_optstring(L, 4, CRLF); | 143 | const char *marker = luaL_optstring(L, 4, CRLF); |
| 122 | luaL_Buffer buffer; | 144 | luaL_Buffer buffer; |
| 123 | luaL_buffinit(L, &buffer); | 145 | luaL_buffinit(L, &buffer); |
| @@ -140,7 +162,7 @@ static int mime_global_fmt(lua_State *L) | |||
| 140 | /*-------------------------------------------------------------------------*\ | 162 | /*-------------------------------------------------------------------------*\ |
| 141 | * Fill base64 decode map. | 163 | * Fill base64 decode map. |
| 142 | \*-------------------------------------------------------------------------*/ | 164 | \*-------------------------------------------------------------------------*/ |
| 143 | static void b64fill(UC *b64unbase) | 165 | static void b64setup(UC *b64unbase) |
| 144 | { | 166 | { |
| 145 | int i; | 167 | int i; |
| 146 | for (i = 0; i < 255; i++) b64unbase[i] = 255; | 168 | for (i = 0; i < 255; i++) b64unbase[i] = 255; |
| @@ -255,7 +277,7 @@ static int mime_global_b64(lua_State *L) | |||
| 255 | luaL_buffinit(L, &buffer); | 277 | luaL_buffinit(L, &buffer); |
| 256 | while (input < last) | 278 | while (input < last) |
| 257 | asize = b64encode(*input++, atom, asize, &buffer); | 279 | asize = b64encode(*input++, atom, asize, &buffer); |
| 258 | input = (UC *) luaL_optlstring(L, 2, NULL, &isize); | 280 | input = (UC *) optlstring(L, 2, NULL, &isize); |
| 259 | if (input) { | 281 | if (input) { |
| 260 | last = input + isize; | 282 | last = input + isize; |
| 261 | while (input < last) | 283 | while (input < last) |
| @@ -283,7 +305,7 @@ static int mime_global_unb64(lua_State *L) | |||
| 283 | luaL_buffinit(L, &buffer); | 305 | luaL_buffinit(L, &buffer); |
| 284 | while (input < last) | 306 | while (input < last) |
| 285 | asize = b64decode(*input++, atom, asize, &buffer); | 307 | asize = b64decode(*input++, atom, asize, &buffer); |
| 286 | input = (UC *) luaL_optlstring(L, 2, NULL, &isize); | 308 | input = (UC *) optlstring(L, 2, NULL, &isize); |
| 287 | if (input) { | 309 | if (input) { |
| 288 | last = input + isize; | 310 | last = input + isize; |
| 289 | while (input < last) | 311 | while (input < last) |
| @@ -311,7 +333,7 @@ static int mime_global_unb64(lua_State *L) | |||
| 311 | * Split quoted-printable characters into classes | 333 | * Split quoted-printable characters into classes |
| 312 | * Precompute reverse map for encoding | 334 | * Precompute reverse map for encoding |
| 313 | \*-------------------------------------------------------------------------*/ | 335 | \*-------------------------------------------------------------------------*/ |
| 314 | static void qpfill(UC *qpclass, UC *qpunbase) | 336 | static void qpsetup(UC *qpclass, UC *qpunbase) |
| 315 | { | 337 | { |
| 316 | int i; | 338 | int i; |
| 317 | for (i = 0; i < 256; i++) qpclass[i] = QP_QUOTED; | 339 | for (i = 0; i < 256; i++) qpclass[i] = QP_QUOTED; |
| @@ -417,15 +439,14 @@ static int mime_global_qp(lua_State *L) | |||
| 417 | 439 | ||
| 418 | size_t asize = 0, isize = 0; | 440 | size_t asize = 0, isize = 0; |
| 419 | UC atom[3]; | 441 | UC atom[3]; |
| 420 | const UC *input = (UC *) (lua_isnil(L, 1) ? NULL: | 442 | const UC *input = (UC *) checklstring(L, 1, &isize); |
| 421 | luaL_checklstring(L, 1, &isize)); | ||
| 422 | const UC *last = input + isize; | 443 | const UC *last = input + isize; |
| 423 | const char *marker = luaL_optstring(L, 3, CRLF); | 444 | const char *marker = luaL_optstring(L, 3, CRLF); |
| 424 | luaL_Buffer buffer; | 445 | luaL_Buffer buffer; |
| 425 | luaL_buffinit(L, &buffer); | 446 | luaL_buffinit(L, &buffer); |
| 426 | while (input < last) | 447 | while (input < last) |
| 427 | asize = qpencode(*input++, atom, asize, marker, &buffer); | 448 | asize = qpencode(*input++, atom, asize, marker, &buffer); |
| 428 | input = (UC *) luaL_optlstring(L, 2, NULL, &isize); | 449 | input = (UC *) optlstring(L, 2, NULL, &isize); |
| 429 | if (input) { | 450 | if (input) { |
| 430 | last = input + isize; | 451 | last = input + isize; |
| 431 | while (input < last) | 452 | while (input < last) |
| @@ -486,14 +507,13 @@ static int mime_global_unqp(lua_State *L) | |||
| 486 | 507 | ||
| 487 | size_t asize = 0, isize = 0; | 508 | size_t asize = 0, isize = 0; |
| 488 | UC atom[3]; | 509 | UC atom[3]; |
| 489 | const UC *input = (UC *) (lua_isnil(L, 1) ? NULL: | 510 | const UC *input = (UC *) checklstring(L, 1, &isize); |
| 490 | luaL_checklstring(L, 1, &isize)); | ||
| 491 | const UC *last = input + isize; | 511 | const UC *last = input + isize; |
| 492 | luaL_Buffer buffer; | 512 | luaL_Buffer buffer; |
| 493 | luaL_buffinit(L, &buffer); | 513 | luaL_buffinit(L, &buffer); |
| 494 | while (input < last) | 514 | while (input < last) |
| 495 | asize = qpdecode(*input++, atom, asize, &buffer); | 515 | asize = qpdecode(*input++, atom, asize, &buffer); |
| 496 | input = (UC *) luaL_optlstring(L, 2, NULL, &isize); | 516 | input = (UC *) optlstring(L, 2, NULL, &isize); |
| 497 | if (input) { | 517 | if (input) { |
| 498 | last = input + isize; | 518 | last = input + isize; |
| 499 | while (input < last) | 519 | while (input < last) |
| @@ -506,21 +526,20 @@ static int mime_global_unqp(lua_State *L) | |||
| 506 | 526 | ||
| 507 | /*-------------------------------------------------------------------------*\ | 527 | /*-------------------------------------------------------------------------*\ |
| 508 | * Incrementally breaks a quoted-printed string into lines | 528 | * Incrementally breaks a quoted-printed string into lines |
| 509 | * A, n = qpfmt(B, length, left) | 529 | * A, n = qpfmt(l, B, length) |
| 510 | * A is a copy of B, broken into lines of at most 'length' bytes. | 530 | * A is a copy of B, broken into lines of at most 'length' bytes. |
| 511 | * Left is how many bytes are left in the first line of B. 'n' is the number | 531 | * 'l' is how many bytes are left for the first line of B. |
| 512 | * of bytes left in the last line of A. | 532 | * 'n' is the number of bytes left in the last line of A. |
| 513 | * There are two complications: lines can't be broken in the middle | 533 | * There are two complications: lines can't be broken in the middle |
| 514 | * of an encoded =XX, and there might be line breaks already | 534 | * of an encoded =XX, and there might be line breaks already |
| 515 | \*-------------------------------------------------------------------------*/ | 535 | \*-------------------------------------------------------------------------*/ |
| 516 | static int mime_global_qpfmt(lua_State *L) | 536 | static int mime_global_qpfmt(lua_State *L) |
| 517 | { | 537 | { |
| 518 | size_t size = 0; | 538 | size_t size = 0; |
| 519 | const UC *input = (UC *) (lua_isnil(L, 1)? NULL: | 539 | int left = (int) luaL_checknumber(L, 1); |
| 520 | luaL_checklstring(L, 1, &size)); | 540 | const UC *input = (UC *) checklstring(L, 2, &size); |
| 521 | const UC *last = input + size; | 541 | const UC *last = input + size; |
| 522 | int length = (int) luaL_checknumber(L, 2); | 542 | int length = (int) luaL_optnumber(L, 3, 76); |
| 523 | int left = (int) luaL_optnumber(L, 3, length); | ||
| 524 | luaL_Buffer buffer; | 543 | luaL_Buffer buffer; |
| 525 | luaL_buffinit(L, &buffer); | 544 | luaL_buffinit(L, &buffer); |
| 526 | while (input < last) { | 545 | while (input < last) { |
| @@ -597,15 +616,14 @@ static int mime_global_eol(lua_State *L) | |||
| 597 | { | 616 | { |
| 598 | size_t asize = 0, isize = 0; | 617 | size_t asize = 0, isize = 0; |
| 599 | UC atom[2]; | 618 | UC atom[2]; |
| 600 | const UC *input = (UC *) (lua_isnil(L, 1)? NULL: | 619 | const UC *input = (UC *) checklstring(L, 1, &isize); |
| 601 | luaL_checklstring(L, 1, &isize)); | ||
| 602 | const UC *last = input + isize; | 620 | const UC *last = input + isize; |
| 603 | const char *marker = luaL_optstring(L, 3, CRLF); | 621 | const char *marker = luaL_optstring(L, 3, CRLF); |
| 604 | luaL_Buffer buffer; | 622 | luaL_Buffer buffer; |
| 605 | luaL_buffinit(L, &buffer); | 623 | luaL_buffinit(L, &buffer); |
| 606 | while (input < last) | 624 | while (input < last) |
| 607 | asize = eolconvert(*input++, atom, asize, marker, &buffer); | 625 | asize = eolconvert(*input++, atom, asize, marker, &buffer); |
| 608 | input = (UC *) luaL_optlstring(L, 2, NULL, &isize); | 626 | input = (UC *) optlstring(L, 2, NULL, &isize); |
| 609 | if (input) { | 627 | if (input) { |
| 610 | last = input + isize; | 628 | last = input + isize; |
| 611 | while (input < last) | 629 | while (input < last) |
diff --git a/src/mime.lua b/src/mime.lua index 86b3af2..0251f6e 100644 --- a/src/mime.lua +++ b/src/mime.lua | |||
| @@ -10,75 +10,71 @@ socket.mime = mime | |||
| 10 | setmetatable(mime, { __index = _G }) | 10 | setmetatable(mime, { __index = _G }) |
| 11 | setfenv(1, mime) | 11 | setfenv(1, mime) |
| 12 | 12 | ||
| 13 | base64 = {} | 13 | -- encode, decode and wrap algorithm tables |
| 14 | qprint = {} | 14 | local et = {} |
| 15 | local dt = {} | ||
| 16 | local wt = {} | ||
| 15 | 17 | ||
| 16 | function base64.encode() | 18 | -- creates a function that chooses an algorithm from a given table |
| 17 | local unfinished = "" | 19 | local function choose(table) |
| 18 | return function(chunk) | 20 | return function(method, ...) |
| 19 | local done | 21 | local f = table[method or "nil"] |
| 20 | done, unfinished = b64(unfinished, chunk) | 22 | if not f then return nil, "unknown method (" .. tostring(method) .. ")" |
| 21 | return done | 23 | else return f(unpack(arg)) end |
| 22 | end | 24 | end |
| 23 | end | 25 | end |
| 24 | 26 | ||
| 25 | function base64.decode() | 27 | -- creates a function that cicles a filter with a given initial |
| 26 | local unfinished = "" | 28 | -- context and extra arguments |
| 29 | local function cicle(f, ctx, ...) | ||
| 27 | return function(chunk) | 30 | return function(chunk) |
| 28 | local done | 31 | local ret |
| 29 | done, unfinished = unb64(unfinished, chunk) | 32 | ret, ctx = f(ctx, chunk, unpack(arg)) |
| 30 | return done | 33 | return ret |
| 31 | end | 34 | end |
| 32 | end | 35 | end |
| 33 | 36 | ||
| 34 | function qprint.encode(mode) | 37 | -- function that choose the encoding, decoding or wrap algorithm |
| 35 | mode = (mode == "binary") and "=0D=0A" or "\13\10" | 38 | encode = choose(et) |
| 36 | local unfinished = "" | 39 | decode = choose(dt) |
| 37 | return function(chunk) | 40 | wrap = choose(wt) |
| 38 | local done | 41 | |
| 39 | done, unfinished = qp(unfinished, chunk, mode) | 42 | -- define the encoding algorithms |
| 40 | return done | 43 | et['base64'] = function() |
| 41 | end | 44 | return cicle(b64, "") |
| 42 | end | 45 | end |
| 43 | 46 | ||
| 44 | function qprint.decode() | 47 | et['quoted-printable'] = function(mode) |
| 45 | local unfinished = "" | 48 | return cicle(qp, "", (mode == "binary") and "=0D=0A" or "\13\10") |
| 46 | return function(chunk) | 49 | end |
| 47 | local done | 50 | |
| 48 | done, unfinished = unqp(unfinished, chunk) | 51 | -- define the decoding algorithms |
| 49 | return done | 52 | dt['base64'] = function() |
| 50 | end | 53 | return cicle(unb64, "") |
| 51 | end | 54 | end |
| 52 | 55 | ||
| 53 | function split(length, marker) | 56 | dt['quoted-printable'] = function() |
| 57 | return cicle(unqp, "") | ||
| 58 | end | ||
| 59 | |||
| 60 | -- define the wrap algorithms | ||
| 61 | wt['character'] = function(length) | ||
| 54 | length = length or 76 | 62 | length = length or 76 |
| 55 | local left = length | 63 | return cicle(fmt, length, length) |
| 56 | return function(chunk) | ||
| 57 | local done | ||
| 58 | done, left = fmt(chunk, length, left, marker) | ||
| 59 | return done | ||
| 60 | end | ||
| 61 | end | 64 | end |
| 65 | wt['base64'] = wt['character'] | ||
| 62 | 66 | ||
| 63 | function qprint.split(length) | 67 | wt['quoted-printable'] = function(length) |
| 64 | length = length or 76 | 68 | length = length or 76 |
| 65 | local left = length | 69 | return cicle(qpfmt, length, length) |
| 66 | return function(chunk) | ||
| 67 | local done | ||
| 68 | done, left = qpfmt(chunk, length, left) | ||
| 69 | return done | ||
| 70 | end | ||
| 71 | end | 70 | end |
| 72 | 71 | ||
| 72 | -- define the end-of-line translation function | ||
| 73 | function canonic(marker) | 73 | function canonic(marker) |
| 74 | local unfinished = "" | 74 | return cicle(eol, "", marker) |
| 75 | return function(chunk) | ||
| 76 | local done | ||
| 77 | done, unfinished = eol(unfinished, chunk, marker) | ||
| 78 | return done | ||
| 79 | end | ||
| 80 | end | 75 | end |
| 81 | 76 | ||
| 77 | -- chains several filters together | ||
| 82 | function chain(...) | 78 | function chain(...) |
| 83 | local layers = table.getn(arg) | 79 | local layers = table.getn(arg) |
| 84 | return function (chunk) | 80 | return function (chunk) |
