diff --git a/limap.c b/limap.c index 65937dc..00cf3b3 100644 --- a/limap.c +++ b/limap.c @@ -1,44 +1,66 @@ #include "lua.h" #include "lauxlib.h" #include "lualib.h" - - #include "c-client.h" #include "imap4r1.h" #include #include -extern int errno; /* just in case */ +extern int errno; /* just in case */ #define M_LOG(a,...) syslog (LOG_NOTICE,"limap@[%s: %d]: " a "\n", __FILE__, \ - __LINE__, ##__VA_ARGS__) + __LINE__, ##__VA_ARGS__) #define M_WARN(a,...) syslog (LOG_WARNING, "limap@[%s: %d]: " a "\n", __FILE__, \ - __LINE__, ##__VA_ARGS__) + __LINE__, ##__VA_ARGS__) #define M_ERROR(a,...) syslog (LOG_ERR, "limap@[%s: %d]: " a "\n", __FILE__, \ - __LINE__, ##__VA_ARGS__) + __LINE__, ##__VA_ARGS__) + +#define add_property_string(L,k,v) \ + lua_pushstring(L,k); \ + lua_pushstring(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) { + char *p = dst; + + while (n != 0 && *p != '\0') { + p++; + n--; + } + if (n != 0) { + for (; --n != 0; p++, src++) { + if ((*p = *src) == '\0') + return p - dst; + } + *p = '\0'; + } + return (p - dst) + strlen(src); +} /* Co-routines from MAIL library */ /* Message matches a search * Accepts: MAIL stream - * message number + * message number */ void mm_searched (MAILSTREAM *stream,unsigned long msgno) { - /* dummy routine */ + /* dummy routine */ } /* Message exists (i.e. there are that many messages in the mailbox) * Accepts: MAIL stream - * message number + * message number */ void mm_exists (MAILSTREAM *stream,unsigned long number) { M_LOG("New emails found in %s: %d", stream->mailbox, number); - int * n = stream->sparep; + int * n = stream->sparep; if(!n) return; *n = number; } @@ -46,29 +68,29 @@ void mm_exists (MAILSTREAM *stream,unsigned long number) /* Message expunged * Accepts: MAIL stream - * message number + * message number */ void mm_expunged (MAILSTREAM *stream,unsigned long number) { - /* dummy routine */ + /* dummy routine */ } /* Message flags update seen * Accepts: MAIL stream - * message number + * message number */ void mm_flags (MAILSTREAM *stream,unsigned long number) { - /* dummy routine */ + /* dummy routine */ } /* Mailbox found * Accepts: MAIL stream - * hierarchy delimiter - * mailbox name - * mailbox attributes + * hierarchy delimiter + * mailbox name + * mailbox attributes */ void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes) @@ -82,7 +104,7 @@ void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes) } size_t cnt = lua_rawlen(L,-1) + 1; lua_pushnumber(L,cnt); - lua_newtable(L); + lua_newtable(L); char delim[2]; delim[0] = (char) delimiter; delim[1] = '\0'; @@ -117,21 +139,21 @@ void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes) /* Subscribe mailbox found * Accepts: MAIL stream - * hierarchy delimiter - * mailbox name - * mailbox attributes + * hierarchy delimiter + * mailbox name + * mailbox attributes */ void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes) { - /* dummy routine */ + /* dummy routine */ } /* Mailbox status * Accepts: MAIL stream - * mailbox name - * mailbox status + * mailbox name + * mailbox status */ void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) @@ -143,8 +165,8 @@ void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) } /* Notification event * Accepts: MAIL stream - * string to log - * error flag + * string to log + * error flag */ void mm_notify (MAILSTREAM *stream,char *string,long errflg) @@ -160,26 +182,26 @@ void mm_notify (MAILSTREAM *stream,char *string,long errflg) ((string[8] == 'T') || (string[8] == 't')) && ((string[9] == 'E') || (string[9] == 'e')) && (string[10] == ']')) - mm_log (string,errflg); /* just do mm_log action */ + mm_log (string,errflg); /* just do mm_log action */ } /* Log an event for the user to see * Accepts: string to log - * error flag + * error flag */ void mm_log (char *string,long errflg) { switch (errflg) { case BYE: - case NIL: /* no error */ + case NIL: /* no error */ M_LOG ("[%s]",string); break; - case PARSE: /* parsing problem */ - case WARN: /* warning */ + case PARSE: /* parsing problem */ + case WARN: /* warning */ M_WARN("warning: %s",string); break; - case ERROR: /* error */ + case ERROR: /* error */ default: M_ERROR ("%s",string); break; @@ -197,9 +219,9 @@ void mm_dlog (char *string) } /* Get user name and password for this host * Accepts: parse of network mailbox name - * where to return user name - * where to return password - * trial count + * where to return user name + * where to return password + * trial count */ void mm_login (NETMBX *mb,char *username,char *password,long trial) @@ -244,8 +266,8 @@ void mm_nocritical (MAILSTREAM *stream) /* Disk error found * Accepts: stream - * system error code - * flag indicating that mailbox may be clobbered + * system error code + * flag indicating that mailbox may be clobbered * Returns: T if user wants to abort */ @@ -352,6 +374,159 @@ static int l_mail_check(lua_State *L) return 0; } +static int l_mail_get_raw_header(lua_State* L) +{ + MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1); + if(!stream) + { + lua_pushnil(L); + return 1; + } + const int id = luaL_checknumber(L,2); + char* msg_header = mail_fetchheader_full(stream, id, NIL, NIL, 0); + lua_pushstring(L, msg_header); + return 1; +} + +static int l_mail_getnumber(lua_State* L) +{ + MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1); + if(!stream) + { + lua_pushnumber(L, -1); + return 1; + } + lua_pushnumber(L, stream->nmsgs); + return 1; +} + +static void _imap_parse_address (lua_State* L, ADDRESS *addresslist) +{ + ADDRESS *addresstmp; + addresstmp = addresslist; + int count = 1; + lua_newtable(L); + do { + lua_pushnumber(L,count); + lua_newtable(L); + if (addresstmp->personal) + { + add_property_string(L, "personal", addresstmp->personal); + } + if (addresstmp->adl) + { + add_property_string(L, "adl", addresstmp->adl); + } + if (addresstmp->mailbox) + { + add_property_string(L, "mailbox", addresstmp->mailbox); + } + if (addresstmp->host) + { + add_property_string(L, "host", addresstmp->host); + } + lua_settable(L, -3); + count++; + } while ((addresstmp = addresstmp->next)); +} + +static void _make_header_object(lua_State* L, ENVELOPE *en) +{ + + lua_newtable(L); + if (en->remail) + { + add_property_string(L, "remail", en->remail); + } + if(en->date) + { + add_property_string(L, "date", (char*)en->date); + } + if (en->subject) + { + add_property_string(L, "subject", en->subject); + } + if (en->in_reply_to) + { + add_property_string(L, "in_reply_to", en->in_reply_to); + } + if (en->message_id) + { + add_property_string(L, "message_id", en->message_id); + } + if (en->newsgroups) + { + add_property_string(L, "newsgroups", en->newsgroups); + } + if (en->followup_to) + { + add_property_string(L, "followup_to", en->followup_to); + } + if (en->references) + { + add_property_string(L, "references", en->references); + } + + if (en->to) { + lua_pushstring(L, "to"); + _imap_parse_address(L, en->to); + lua_settable(L, -3); + } + + if (en->from) { + lua_pushstring(L, "from"); + _imap_parse_address(L, en->from); + lua_settable(L, -3); + } + + if (en->cc) { + lua_pushstring(L, "cc"); + _imap_parse_address(L, en->cc); + lua_settable(L, -3); + } + + if (en->bcc) { + lua_pushstring(L, "bcc"); + _imap_parse_address(L, en->bcc); + lua_settable(L, -3); + } + + if (en->reply_to) { + lua_pushstring(L, "reply_to"); + _imap_parse_address(L, en->reply_to); + lua_settable(L, -3); + } + + if (en->sender) { + lua_pushstring(L, "sender"); + _imap_parse_address(L, en->sender); + lua_settable(L, -3); + } + + if (en->return_path) { + lua_pushstring(L, "return_path"); + _imap_parse_address(L, en->return_path); + lua_settable(L, -3); + } +} + +static int l_rfc822_parse_header(lua_State* L) +{ + ENVELOPE *en = NULL; + const char* headers = luaL_checkstring(L,1); + rfc822_parse_msg(&en, NULL, (char*)headers, strlen(headers), NULL, "UNKNOWN", NIL); + if(en) + { + _make_header_object(L, en); + free(en); + } + else + { + lua_pushnil(L); + } + return 1; +} + static int l_reopen(lua_State *L) { MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1); @@ -385,19 +560,68 @@ static int l_reopen(lua_State *L) } +static int l_mail_get_headers(lua_State* L) +{ + MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1); + if(!stream) + { + lua_pushnil(L); + return 1; + } + char tmp[MAILTMPLEN]; + unsigned int msgno; + char *t; + unsigned long i; + lua_newtable(L); + for (msgno = 1; msgno <= stream->nmsgs; msgno++) { + lua_pushnumber(L, msgno); + MESSAGECACHE * cache = mail_elt (stream, msgno); + mail_fetchstructure(stream, msgno, NIL); + tmp[0] = cache->recent ? (cache->seen ? 'R': 'N') : ' '; + tmp[1] = (cache->recent | cache->seen) ? ' ' : 'U'; + tmp[2] = cache->flagged ? 'F' : ' '; + tmp[3] = cache->answered ? 'A' : ' '; + tmp[4] = cache->deleted ? 'D' : ' '; + tmp[5] = cache->draft ? 'X' : ' '; + snprintf(tmp + 6, sizeof(tmp) - 6, "%4ld) ", cache->msgno); + mail_date(tmp+11, cache); + tmp[22] = ' '; + tmp[23] = '\0'; + mail_fetchfrom(tmp+23, stream, msgno, (long)20); + strcat(tmp, " "); + if ((i = cache->user_flags)) { + strcat(tmp, "{"); + while (i) { + strlcat(tmp, stream->user_flags[find_rightmost_bit (&i)], sizeof(tmp)); + if (i) strlcat(tmp, " ", sizeof(tmp)); + } + strlcat(tmp, "} ", sizeof(tmp)); + } + mail_fetchsubject(t = tmp + strlen(tmp), stream, msgno, (long)25); + snprintf(t += strlen(t), sizeof(tmp) - strlen(tmp), " (%ld chars)", cache->rfc822_size); + lua_pushstring(L, tmp); + lua_settable(L,-3); + } + return 1; +} + static const struct luaL_Reg _lib [] = { - {"open", l_mail_open}, + {"open", l_mail_open}, {"close", l_mail_close}, {"get_mail_boxes", l_get_mailboxes}, {"reopen", l_reopen}, {"ping", l_mail_ping}, {"check", l_mail_check}, - {NULL,NULL} + {"get_raw_header", l_mail_get_raw_header}, + {"get_nmail", l_mail_getnumber}, + {"get_headers", l_mail_get_headers}, + {"rfc822_parse_header", l_rfc822_parse_header}, + {NULL,NULL} }; int luaopen_limap(lua_State *L) { #include "linkage.c" - luaL_newlib(L, _lib); - return 1; + luaL_newlib(L, _lib); + return 1; } \ No newline at end of file diff --git a/test.lua b/test.lua index 26a87a1..4b79657 100644 --- a/test.lua +++ b/test.lua @@ -1,11 +1,11 @@ local OP_DEBUG = 0x1 local OP_READONLY = 0x2 -local OP_ANONYMOUS = 0x4 --/* anonymous open of newsgroup */ +local OP_ANONYMOUS = 0x4 --/* anonymous open of newsgroup */ local OP_SHORTCACHE = 0x8 --/* short (elt-only) caching */ -local OP_SILENT = 0x10 --/* don't pass up events (internal use) */ +local OP_SILENT = 0x10 --/* don't pass up events (internal use) */ local OP_PROTOTYPE = 0x20 --/* return driver prototype */ -local OP_HALFOPEN = 0x40 --/* half-open (IMAP connect but no select) */ -local OP_EXPUNGE= 0x80 --/* silently expunge recycle stream */ +local OP_HALFOPEN = 0x40 --/* half-open (IMAP connect but no select) */ +local OP_EXPUNGE= 0x80 --/* silently expunge recycle stream */ local imap = require("limap") @@ -15,10 +15,21 @@ local handle, box = imap.open(url,OP_HALFOPEN|OP_DEBUG) local r,v = false,nil; +function dump(obj) + if(type(obj) == "table") then + for k,v in pairs(obj) do + print(k) + dump(v) + end + else + print(obj) + end +end + if(handle) then print("mailbox openned") - local boxes = imap.get_mail_boxes(handle, box:gsub("[^}]*$",""),"*"); + local boxes = imap.get_mail_boxes(handle, box:gsub("[^}]*$",""),"*") for k, v in ipairs(boxes) do print("=================") @@ -39,6 +50,13 @@ if(handle) then print("Unable to ping") end imap.check(handle); + -- get nmail + local nmail = imap.get_nmail(handle); + print("umber of mail", nmail); + if nmail > 0 then + local headers = imap.get_headers(handle) + dump(headers) + end imap.close(handle) end \ No newline at end of file