diff --git a/limap.c b/limap.c index 00cf3b3..694d172 100644 --- a/limap.c +++ b/limap.c @@ -19,9 +19,14 @@ extern int errno; /* just in case */ lua_pushstring(L,v); \ lua_settable(L,-3); +#define add_property_long(L,k,v) \ + lua_pushstring(L,k); \ + lua_pushnumber(L,v); \ + lua_settable(L,-3); + unsigned long find_rightmost_bit(unsigned long *valptr); -size_t strlcat(char *dst, const char *src, size_t n) { +static size_t strlcat(char *dst, const char *src, size_t n) { char *p = dst; while (n != 0 && *p != '\0') { @@ -38,6 +43,17 @@ size_t strlcat(char *dst, const char *src, size_t n) { return (p - dst) + strlen(src); } +static void str_trim(char* str, const char delim) +{ + if(!str || strlen(str) == 0) return; + char * p = str; + int l = strlen(p); + while(l > 0 && p[l - 1] == delim) + p[--l] = 0; + while(* p && (* p) == delim ) ++p, --l; + memmove(str, p, l + 1); +} + /* Co-routines from MAIL library */ @@ -518,7 +534,7 @@ static int l_rfc822_parse_header(lua_State* L) if(en) { _make_header_object(L, en); - free(en); + mail_free_envelope(&en); } else { @@ -559,6 +575,61 @@ static int l_reopen(lua_State *L) return 2; } +static int l_mail_get_header(lua_State* L) +{ + char tmp[MAILTMPLEN + 1]; + MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1); + if(!stream) + { + lua_pushnil(L); + return 1; + } + const int msgno = luaL_checknumber(L,2); + MESSAGECACHE *cache; + ENVELOPE *en; + + if (mail_fetchstructure(stream, msgno, NIL)) { + cache = mail_elt(stream, msgno); + } else { + lua_pushnil(L); + return 1; + } + + en = mail_fetchenvelope(stream, msgno); + + /* call a function to parse all the text, so that we can use the + same function to parse text from other sources */ + _make_header_object(L, en); + //free(en); + + /* now run through properties that are only going to be returned + from a server, not text headers */ + add_property_string(L, "Recent", cache->recent ? (cache->seen ? "R": "N") : " "); + add_property_string(L, "Unseen", (cache->recent | cache->seen) ? " " : "U"); + add_property_string(L, "Flagged", cache->flagged ? "F" : " "); + add_property_string(L, "Answered", cache->answered ? "A" : " "); + add_property_string(L, "Deleted", cache->deleted ? "D" : " "); + add_property_string(L, "Draft", cache->draft ? "X" : " "); + add_property_long(L, "Msgno", cache->msgno); + mail_date(tmp, cache); + add_property_string(L, "MailDate", tmp); + add_property_long(L, "Size", cache->rfc822_size); + add_property_long(L, "udate", mail_longdate(cache)); + + if (en->from) { + tmp[0] = 0x00; + mail_fetchfrom(tmp, stream, msgno, sizeof(tmp)); + str_trim(tmp, ' '); + add_property_string(L, "fetchfrom", tmp); + } + if (en->subject) { + tmp[0] = 0x00; + mail_fetchsubject(tmp, stream, msgno, sizeof(tmp)); + str_trim(tmp, ' '); + add_property_string(L, "fetchsubject", tmp); + } + return 1; +} static int l_mail_get_headers(lua_State* L) { @@ -605,6 +676,163 @@ static int l_mail_get_headers(lua_State* L) return 1; } +static int l_get_raw_body(lua_State* L) +{ + char tmp[MAILTMPLEN + 1]; + MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1); + if(!stream) + { + lua_pushnil(L); + return 1; + } + unsigned int flags = 0; + const int msgno = luaL_checknumber(L,2); + if(lua_toboolean(L,3)) + { + flags |= FT_PEEK; + } + char *body; + unsigned long body_len = 0; + body = mail_fetchtext_full(stream, msgno, &body_len, flags); + if (body_len == 0) { + lua_pushnil(L); + } else { + lua_pushstring(L, body); + } + return 1; +} +static void _imap_add_body(lua_State* L, BODY *body) +{ + PARAMETER *par, *dpar; + PART *part; + int count = 1; + lua_newtable(L); + + if (body->type <= TYPEMAX) { + add_property_long(L, "type", body->type); + } + + if (body->encoding <= ENCMAX) { + add_property_long(L, "encoding", body->encoding); + } + + if (body->subtype) { + add_property_string(L, "subtype", body->subtype); + } + + if (body->description) { + add_property_string(L, "description", body->description); + } + + if (body->id) { + add_property_string(L, "id", body->id); + } + if (body->size.lines) { + add_property_long(L, "lines", body->size.lines); + } + + if (body->size.bytes) { + add_property_long(L, "bytes", body->size.bytes); + } + + if (body->md5) { + add_property_string(L, "md5", body->md5); + } + + if (body->location) { + add_property_string(L, "location", body->location); + } + + if (body->disposition.type) { + add_property_string(L, "disposition", body->disposition.type); + } + + if (body->disposition.parameter) { + dpar = body->disposition.parameter; + lua_pushstring(L, "dparameters"); + lua_newtable(L); + count = 1; + do { + lua_pushnumber(L, count); + lua_newtable(L); + add_property_string(L, "attribute", dpar->attribute); + add_property_string(L, "value", dpar->value); + lua_settable(L,-3); + count++; + } while ((dpar = dpar->next)); + lua_settable(L, -3); + } + + if ((par = body->parameter)) { + lua_pushstring(L, "parameters"); + lua_newtable(L); + count = 1; + do { + lua_pushnumber(L, count); + lua_newtable(L); + if (par->attribute) { + add_property_string(L, "attribute", par->attribute); + } + if (par->value) { + add_property_string(L, "value", par->value); + } + + lua_settable(L,-3); + count++; + } while ((par = par->next)); + lua_settable(L, -3); + } + /* multipart message ? */ + if (body->type == TYPEMULTIPART) { + lua_pushstring(L, "parts"); + lua_newtable(L); + count = 1; + for (part = body->nested.part; part; part = part->next) { + lua_pushnumber(L, count); + _imap_add_body(L, &part->body); + lua_settable(L, -3); + count++; + } + lua_settable(L, -3); + } + + /* encapsulated message ? */ + if ((body->type == TYPEMESSAGE) && (!strcasecmp(body->subtype, "rfc822"))) { + lua_pushstring(L, "message"); + lua_newtable(L); + + lua_pushstring(L, "header"); + _make_header_object(L,body->nested.msg->env); + lua_settable(L, -3); + + lua_pushstring(L, "body"); + _imap_add_body(L, body->nested.msg->body); + lua_settable(L, -3); + + lua_settable(L, -3); + } +} +static int l_get_structure(lua_State* L) +{ + MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1); + BODY *body; + if(!stream) + { + lua_pushnil(L); + return 1; + } + const int msgno = luaL_checknumber(L,2); + mail_fetchstructure_full(stream, msgno, &body , 0); + + if (!body) { + lua_pushnil(L); + return 1; + } + + _imap_add_body(L, body); + return 1; +} + static const struct luaL_Reg _lib [] = { {"open", l_mail_open}, {"close", l_mail_close}, @@ -615,7 +843,10 @@ static const struct luaL_Reg _lib [] = { {"get_raw_header", l_mail_get_raw_header}, {"get_nmail", l_mail_getnumber}, {"get_headers", l_mail_get_headers}, + {"get_header", l_mail_get_header}, {"rfc822_parse_header", l_rfc822_parse_header}, + {"get_raw_body", l_get_raw_body}, + {"get_structure", l_get_structure}, {NULL,NULL} }; diff --git a/test.lua b/test.lua index 4b79657..00249de 100644 --- a/test.lua +++ b/test.lua @@ -22,7 +22,7 @@ function dump(obj) dump(v) end else - print(obj) + print("[",obj,"]") end end @@ -58,5 +58,15 @@ if(handle) then local headers = imap.get_headers(handle) dump(headers) end + print("===============================") + local header = imap.get_header(handle, nmail-3) + dump(header) + print("===============================") + local raw_body = imap.get_raw_body(handle, nmail-3, true) -- peak the message without set it to seen + print(raw_body) + print("===============================") + local structure = imap.get_structure(handle, nmail-3) + dump(structure) + imap.close(handle) end \ No newline at end of file