add more wrapper APIs to the module

This commit is contained in:
Dany LE 2023-06-14 15:20:16 +02:00
parent 115a068ac0
commit af3a063299
2 changed files with 801 additions and 69 deletions

804
limap.c
View File

@ -5,8 +5,18 @@
#include "imap4r1.h"
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <pthread.h>
extern int errno; /* just in case */
#define IMAP_MT "limap"
#define IMAP_ADDRESS_SIZE_BUF 10
#ifndef SENDBUFLEN
#define SENDBUFLEN 16385
#endif
#define M_LOG(a,...) syslog (LOG_NOTICE,"limap@[%s: %d]: " a "\n", __FILE__, \
__LINE__, ##__VA_ARGS__)
#define M_WARN(a,...) syslog (LOG_WARNING, "limap@[%s: %d]: " a "\n", __FILE__, \
@ -24,6 +34,10 @@ extern int errno; /* just in case */
lua_pushnumber(L,v); \
lua_settable(L,-3);
static pthread_mutex_t _limap_lock;
static lua_State* __L__;
unsigned long find_rightmost_bit(unsigned long *valptr);
static size_t strlcat(char *dst, const char *src, size_t n) {
@ -76,9 +90,9 @@ void mm_searched (MAILSTREAM *stream,unsigned long msgno)
void mm_exists (MAILSTREAM *stream,unsigned long number)
{
M_LOG("New emails found in %s: %d", stream->mailbox, number);
int * n = stream->sparep;
if(!n) return;
*n = number;
lua_State * L = stream->sparep;
if(!L) return;
lua_pushnumber(L, number);
}
@ -162,7 +176,7 @@ void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
{
/* dummy routine */
mm_list(stream,delimiter, name,attributes);
}
@ -187,18 +201,33 @@ void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
void mm_notify (MAILSTREAM *stream,char *string,long errflg)
{
if (!errflg && (string[0] == '[') &&
((string[1] == 'T') || (string[1] == 't')) &&
((string[2] == 'R') || (string[2] == 'r')) &&
((string[3] == 'Y') || (string[3] == 'y')) &&
((string[4] == 'C') || (string[4] == 'c')) &&
((string[5] == 'R') || (string[5] == 'r')) &&
((string[6] == 'E') || (string[6] == 'e')) &&
((string[7] == 'A') || (string[7] == 'a')) &&
((string[8] == 'T') || (string[8] == 't')) &&
((string[9] == 'E') || (string[9] == 'e')) &&
(string[10] == ']'))
mm_log (string,errflg); /* just do mm_log action */
lua_State* L = stream->sparep;
if (!errflg && (string[0] == '[') &&
((string[1] == 'T') || (string[1] == 't')) &&
((string[2] == 'R') || (string[2] == 'r')) &&
((string[3] == 'Y') || (string[3] == 'y')) &&
((string[4] == 'C') || (string[4] == 'c')) &&
((string[5] == 'R') || (string[5] == 'r')) &&
((string[6] == 'E') || (string[6] == 'e')) &&
((string[7] == 'A') || (string[7] == 'a')) &&
((string[8] == 'T') || (string[8] == 't')) &&
((string[9] == 'E') || (string[9] == 'e')) &&
(string[10] == ']'))
{
switch (errflg) {
case BYE:
case NIL: /* no error */
break;
default:
lua_getglobal(L, "limap_errors");
size_t len = lua_rawlen(L,-1);
lua_pushnumber(L,len+1);
lua_pushstring(L,string);
lua_settable(L,-3);
break;
}
mm_log (string,errflg); /* just do mm_log action */
}
}
/* Log an event for the user to see
@ -208,20 +237,20 @@ void mm_notify (MAILSTREAM *stream,char *string,long errflg)
void mm_log (char *string,long errflg)
{
switch (errflg) {
case BYE:
case NIL: /* no error */
M_LOG ("[%s]",string);
break;
case PARSE: /* parsing problem */
case WARN: /* warning */
M_WARN("warning: %s",string);
break;
case ERROR: /* error */
default:
M_ERROR ("%s",string);
break;
}
switch (errflg) {
case BYE:
case NIL: /* no error */
M_LOG ("[%s]",string);
break;
case PARSE: /* parsing problem */
case WARN: /* warning */
M_WARN("warning: %s",string);
break;
case ERROR: /* error */
default:
M_ERROR ("%s",string);
break;
}
}
@ -242,23 +271,56 @@ void mm_dlog (char *string)
void mm_login (NETMBX *mb,char *username,char *password,long trial)
{
if(mb->user)
// user name
if(!lua_isstring(__L__,2))
{
char * tmp = mb->user;
(void)strsep(&tmp, ";");
strncpy(username, mb->user, NETMAXUSER);
if(tmp)
{
strncpy (password,tmp,MAILTMPLEN);
}
M_LOG("host: %s", mb->host);
M_LOG("orighost: %s", mb->orighost);
M_LOG("user: %s", mb->user);
M_LOG("mailbox: %s", mb->mailbox);
M_LOG("service: %s", mb->service);
return;
}
// password
if(!lua_isstring(__L__,3))
{
return;
}
char * tmp = (char*)lua_tostring(__L__,2);
strncpy(username, tmp, NETMAXUSER);
tmp = (char*)lua_tostring(__L__,3);
strncpy (password,tmp,MAILTMPLEN);
M_LOG("host: %s", mb->host);
M_LOG("orighost: %s", mb->orighost);
M_LOG("user: %s", username);
M_LOG("mailbox: %s", mb->mailbox);
M_LOG("service: %s", mb->service);
}
void mm_getacl(MAILSTREAM *stream, char *mailbox, ACLLIST *alist)
{
/* walk through the ACLLIST */
lua_State* L = stream->sparep;
lua_newtable(L);
for(; alist; alist = alist->next) {
add_property_string(L,alist->identifier, alist->rights);
}
}
void mm_getquota(MAILSTREAM *stream, char *qroot, QUOTALIST *qlist)
{
/* put parsing code here */
lua_State* L = stream->sparep;
M_LOG("querying quota:");
lua_newtable(L);
for(; qlist; qlist = qlist->next) {
lua_pushstring(L, qlist->name);
lua_newtable(L);
add_property_long(L, "usage", qlist->usage);
add_property_long(L, "limit", qlist->limit);
lua_settable(L,-3);
M_LOG("Quota name %s: ", qlist->name);
M_LOG("Usage: %d", qlist->usage);
M_LOG("Limit: %d",qlist->limit);
}
}
/* About to enter critical code
* Accepts: stream
@ -308,28 +370,33 @@ static int l_mail_open(lua_State *L)
{
const char* mailbox = luaL_checkstring(L,1);
long flag = 0;
if( lua_toboolean(L,2))
if( lua_toboolean(L,4))
{
/*half open*/
flag = flag | OP_HALFOPEN;
}
if( lua_toboolean(L,3))
if( lua_toboolean(L,5))
{
/*debug*/
flag = flag | OP_DEBUG;
}
pthread_mutex_lock(&_limap_lock);
__L__ = L;
MAILSTREAM *stream = mail_open (NIL,(char*)mailbox,flag);
__L__ = NULL;
pthread_mutex_unlock(&_limap_lock);
if(!stream)
{
lua_pushnil(L);
return 1;
}
//strncpy(stream->original_mailbox, stream->mailbox, strlen(stream->mailbox));
if(stream->original_mailbox)
/*if(stream->original_mailbox)
{
free(stream->original_mailbox);
}
stream->original_mailbox = strdup(stream->mailbox);
stream->original_mailbox = strdup(stream->mailbox);*/
stream->sparep = (void*)L;
M_LOG("mailbox: %s", stream->mailbox);
M_LOG("original_mailbox: %s", stream->original_mailbox);
lua_pushlightuserdata(L, stream);
@ -362,7 +429,6 @@ static int l_get_mailboxes(lua_State *L)
lua_pushboolean(L,0);
return 1;
}
stream->sparep = (void*)L;
lua_newtable(L);
mail_list(stream,(char*)reference, (char*)pattern);
return 1;
@ -371,8 +437,6 @@ static int l_get_mailboxes(lua_State *L)
static int l_mail_ping(lua_State *L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
int new_mail = 0;
stream->sparep = (void*)&new_mail;
if(!stream || mail_ping(stream) == NIL)
{
lua_pushboolean(L,0);
@ -381,7 +445,6 @@ static int l_mail_ping(lua_State *L)
{
lua_pushboolean(L,1);
}
lua_pushnumber(L, new_mail);
return 2;
}
@ -390,10 +453,30 @@ static int l_mail_check(lua_State *L)
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
if(!stream)
{
return 0;
lua_pushnil(L);
return 1;
}
char date[100];
if (mail_ping (stream) == NIL) {
lua_pushnil(L);
return 1;
}
if (stream->mailbox) {
rfc822_date(date);
lua_newtable(L);
add_property_string(L, "Date", date);
add_property_string(L, "Driver", stream->dtb->name);
add_property_string(L, "Mailbox", stream->mailbox);
add_property_long(L, "Nmsgs", stream->nmsgs);
add_property_long(L, "Recent", stream->recent);
return 1;
} else {
lua_pushnil(L);
return 1;
}
mail_check(stream);
return 0;
}
static int l_mail_get_raw_header(lua_State* L)
@ -575,11 +658,12 @@ static int l_reopen(lua_State *L)
lua_pushboolean(L,0);
return 1;
}
if(stream->original_mailbox)
stream->sparep = (void*) L;
/*if(stream->original_mailbox)
{
free(stream->original_mailbox);
}
stream->original_mailbox = strdup(stream->mailbox);
stream->original_mailbox = strdup(stream->mailbox);*/
M_LOG("mailbox: %s", stream->mailbox);
M_LOG("original_mailbox: %s", stream->original_mailbox);
lua_pushboolean(L,1);
@ -924,27 +1008,621 @@ static int l_get_body_part(lua_State* L)
return 1;
}
static int l_append(lua_State* L)
{
STRING s;
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
char* folder = (char*)luaL_checkstring(L,2);
char* message = (char*)luaL_checkstring(L,3);
INIT (&s, mail_string, message,strlen(message));
if (mail_append(stream, folder, &s)) {
lua_pushboolean(L, 1);
} else {
lua_pushboolean(L, 0);
}
return 1;
}
static int l_setflag_full(lua_State* L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
char *sequence = (char*)luaL_checkstring(L,2);
char *flag = (char*)luaL_checkstring(L,3);
unsigned int flags = 0;
if(lua_toboolean(L,4))
{
flags |= ST_UID;
}
mail_setflag_full(stream, sequence, flag, flags);
lua_pushboolean(L,1);
return 1;
}
static int l_create_mailbox(lua_State * L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
char *folder = (char*)luaL_checkstring(L,2);
if (mail_create(stream, folder) == T) {
lua_pushboolean(L, 1);
} else {
lua_pushboolean(L, 0);
}
return 1;
}
static int l_delete_mailbox(lua_State* L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
char *folder = (char*)luaL_checkstring(L,2);
if (mail_delete(stream, folder) == T) {
lua_pushboolean(L, 1);
} else {
lua_pushboolean(L, 0);
}
return 1;
}
static int l_8bit(lua_State* L)
{
char* text = (char*) luaL_checkstring(L,1);
char *decode;
unsigned long newlength;
decode = (char *) rfc822_8bit((unsigned char *) text, strlen(text), &newlength);
if (decode == NULL) {
lua_pushnil(L);
}
decode[newlength] = '\0';
lua_pushstring(L, decode);
fs_give((void**) &decode);
return 1;
}
static int l_binary(lua_State* L)
{
char* text = (char*) luaL_checkstring(L,1);
char *decode;
unsigned long newlength;
decode = (char*)rfc822_binary(text, strlen(text), &newlength);
if (decode == NULL) {
lua_pushnil(L);
}
decode[newlength] = '\0';
lua_pushstring(L, decode);
fs_give((void**) &decode);
return 1;
}
static int l_clearflag_full(lua_State* L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
char *sequence = (char*)luaL_checkstring(L,2);
char *flag = (char*)luaL_checkstring(L,3);
unsigned int flags = 0;
if(lua_toboolean(L,4))
{
flags |= ST_UID;
}
mail_clearflag_full(stream, sequence, flag, flags);
lua_pushboolean(L,1);
return 1;
}
static int l_get_body_struct(lua_State* L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
unsigned int msgno = luaL_checknumber(L, 2);
char* section = (char*)luaL_checkstring(L,3);
PARAMETER *par, *dpar;
BODY *body;
body=mail_body(stream, msgno, (unsigned char*)section);
if (body == NULL) {
lua_pushnil(L);
return 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_long(L, "ifsubtype", 1);
add_property_string(L, "subtype", body->subtype);
} else {
add_property_long(L, "ifsubtype", 0);
}
if (body->description) {
add_property_long(L, "ifdescription", 1);
add_property_string(L, "description", body->description);
} else {
add_property_long(L, "ifdescription", 0);
}
if (body->id) {
add_property_long(L, "ifid", 1);
add_property_string(L, "id", body->id);
} else {
add_property_long(L, "ifid", 0);
}
if (body->size.lines) {
add_property_long(L, "lines", body->size.lines);
}
if (body->size.bytes) {
add_property_long(L, "bytes", body->size.bytes);
}
#ifdef IMAP41
if (body->disposition.type) {
add_property_long(L, "ifdisposition", 1);
add_property_string(L, "disposition", body->disposition.type);
} else {
add_property_long(L, "ifdisposition", 0);
}
if (body->disposition.parameter) {
dpar = body->disposition.parameter;
add_property_long(L, "ifdparameters", 1);
lua_pushstring(L,"dparameters");
lua_newtable(L);
int 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);
} else {
add_property_long(L, "ifdparameters", 0);
}
#endif
if ((par = body->parameter)) {
add_property_long(L, "ifparameters", 1);
lua_pushstring(L,"parameters");
lua_newtable(L);
int 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);
}
count++;
lua_settable(L,-3);
} while ((par = par->next));
lua_settable(L,-3);
} else {
add_property_long(L, "ifparameters", 0);
}
return 1;
}
static int l_expunge(lua_State* L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
mail_expunge (stream);
return 0;
}
/* {{{ _rfc822_len
* Calculate string length based on imap's rfc822_cat function.
*/
static int _rfc822_len(char *str)
{
int len;
char *p;
if (!str || !*str) {
return 0;
}
/* strings with special characters will need to be quoted, as a safety measure we
* add 2 bytes for the quotes just in case.
*/
len = strlen(str) + 2;
p = str;
/* rfc822_cat() will escape all " and \ characters, therefore we need to increase
* our buffer length to account for these characters.
*/
while ((p = strpbrk(p, "\\\""))) {
p++;
len++;
}
return len;
}
/* }}} */
/* {{{ _imap_get_address_size */
static int _imap_address_size (ADDRESS *addresslist)
{
ADDRESS *tmp;
int ret=0, num_ent=0;
tmp = addresslist;
if (tmp) do {
ret += _rfc822_len(tmp->personal);
ret += _rfc822_len(tmp->adl);
ret += _rfc822_len(tmp->mailbox);
ret += _rfc822_len(tmp->host);
num_ent++;
} while ((tmp = tmp->next));
/*
* rfc822_write_address_full() needs some extra space for '<>,', etc.
* for this perpouse we allocate additional IMAP_ADDRESS_SIZE_BUF bytes
* by default this buffer is 10 bytes long
*/
ret += (ret) ? num_ent*IMAP_ADDRESS_SIZE_BUF : 0;
return ret;
}
/* }}} */
/* {{{ _rfc822_write_address */
static void _rfc822_write_address(lua_State* L,const char* key, ADDRESS *addresslist)
{
char address[SENDBUFLEN];
if (_imap_address_size(addresslist) >= SENDBUFLEN) {
//throw_error(NULL, "Address buffer overflow");
return;
}
address[0] = 0;
rfc822_write_address(address, addresslist);
add_property_string(L, key, address);
}
/* }}} */
static int l_get_overview(lua_State* L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
unsigned int status, flags = 0L;
char *sequence = (char*)luaL_checkstring(L,2);
if(lua_toboolean(L,3))
{
flags |= ST_UID;
}
status = (flags & FT_UID)
? mail_uid_sequence(stream, (unsigned char*)sequence)
: mail_sequence(stream, (unsigned char*)sequence);
if (status) {
MESSAGECACHE *elt;
ENVELOPE *env;
unsigned long i;
lua_newtable(L);
for (i = 1; i <= stream->nmsgs; i++) {
if (((elt = mail_elt (stream, i))->sequence) &&
(env = mail_fetch_structure (stream, i, NIL, NIL))) {
lua_pushnumber(L,i);
lua_newtable(L);
if (env->subject) {
add_property_string(L, "subject", env->subject);
}
if (env->from) {
env->from->next=NULL;
_rfc822_write_address(L,"from",env->from);
}
if (env->to) {
env->to->next = NULL;
_rfc822_write_address(L,"to",env->to);
}
if (env->date) {
add_property_string(L, "date", (char*)env->date);
}
if (env->message_id) {
add_property_string(L, "message_id", env->message_id);
}
if (env->references) {
add_property_string(L, "references", env->references);
}
if (env->in_reply_to) {
add_property_string(L, "in_reply_to", env->in_reply_to);
}
add_property_long(L, "size", elt->rfc822_size);
add_property_long(L, "uid", mail_uid(stream, i));
add_property_long(L, "msgno", i);
add_property_long(L, "recent", elt->recent);
add_property_long(L, "flagged", elt->flagged);
add_property_long(L, "answered", elt->answered);
add_property_long(L, "deleted", elt->deleted);
add_property_long(L, "seen", elt->seen);
add_property_long(L, "draft", elt->draft);
add_property_long(L, "udate", mail_longdate(elt));
lua_settable(L,-3);
}
}
}
else
{
lua_pushnil(L);
}
return 1;
}
static int l_get_mime(lua_State* L)
{
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);
char* section = (char*)luaL_checkstring(L,3);
if(lua_toboolean(L,4))
{
flags |= FT_PEEK;
}
char *body;
unsigned long len;
body = mail_fetch_mime(stream, msgno, section, &len, flags);
if (!body) {
lua_pushnil(L);
return 1;
}
lua_pushstring(L,body);
return 1;
}
static int l_gc(lua_State* L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
if(!stream)
{
lua_pushboolean(L,0);
return 1;
}
unsigned int flags = GC_TEXTS | GC_ELT | GC_ENV;
mail_gc(stream, flags);
lua_pushboolean(L,1);
return 1;
}
static int l_get_quota(lua_State* L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
if(!stream)
{
lua_pushboolean(L,0);
return 1;
}
char * qroot = (char*) luaL_checkstring(L,2);
// set the callback for the GET_QUOTA function
mail_parameters(NIL, SET_QUOTA, (void *) mm_getquota);
if (!imap_getquota(stream,qroot)) {
M_ERROR("C-client imap_getquota failed");
}
if(lua_isstring(L,-1))
{
lua_pushnil(L);
}
return 1;
}
static int l_get_quotaroot(lua_State* L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
if(!stream)
{
lua_pushboolean(L,0);
return 1;
}
char * qroot = (char*) luaL_checkstring(L,2);
// set the callback for the GET_QUOTA function
mail_parameters(NIL, SET_QUOTA, (void *) mm_getquota);
if (!imap_getquotaroot(stream,qroot)) {
M_ERROR("C-client imap_getquotaroot failed");
}
if(lua_isstring(L,-1))
{
lua_pushnil(L);
}
return 1;
}
static int l_getacl(lua_State* L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
if(!stream)
{
lua_pushboolean(L,0);
return 1;
}
char * mailbox = (char*) luaL_checkstring(L,2);
/* set the callback for the GET_ACL function */
mail_parameters(NIL, SET_ACL, (void *) mm_getacl);
if (!imap_getacl(stream, mailbox))
{
M_ERROR("c-client imap_getacl failed");
}
if(lua_isstring(L,-1))
{
lua_pushnil(L);
}
return 1;
}
static int l_get_subscribed(lua_State* L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
const char* reference = luaL_checkstring(L,2);
const char* pattern = luaL_checkstring(L,3);
if(!stream)
{
lua_pushboolean(L,0);
return 1;
}
lua_newtable(L);
mail_lsub(stream,(char*)reference, (char*)pattern);
return 1;
}
static int l_scan_mailboxes(lua_State* L)
{
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
const char* reference = luaL_checkstring(L,2);
const char* pattern = luaL_checkstring(L,3);
const char* content = luaL_checkstring(L,4);
if(!stream)
{
lua_pushboolean(L,0);
return 1;
}
lua_newtable(L);
mail_scan(stream, (char*)reference, (char*)pattern, (char*)content);
return 1;
}
static int l_mail_compose(lua_State* L)
{
}
static int l_lua_gc(lua_State* L)
{
M_LOG("Imap module unloaded");
pthread_mutex_destroy(&_limap_lock);
return 0;
}
static const struct luaL_Reg _lib [] = {
{"open", l_mail_open},
{"close", l_mail_close},
{"get_mail_boxes", l_get_mailboxes},
{"get_mail_boxes", l_get_mailboxes},// = PHP imap_getmailboxes, imap_list
{"reopen", l_reopen},
{"ping", l_mail_ping},
{"check", l_mail_check},
{"get_raw_header", l_mail_get_raw_header},
{"check", l_mail_check}, // PHP imap_check
{"get_raw_header", l_mail_get_raw_header}, // = PHP imap_fetchheader()
{"get_nmail", l_mail_getnumber},
{"get_headers", l_mail_get_headers},
{"get_header", l_mail_get_header},
{"get_header", l_mail_get_header}, // = php imap_header()
{"rfc822_parse_header", l_rfc822_parse_header},
{"get_raw_body", l_get_raw_body},
{"get_structure", l_get_structure},
{"get_body_part", l_get_body_part},
{"get_raw_body", l_get_raw_body}, // = PHP imap_body
{"get_structure", l_get_structure}, // = PHP imap_fetchstructure()
{"get_body_part", l_get_body_part}, // = PHP imap_fetchbody()
{"append", l_append},
{"setflag_full", l_setflag_full}, // = PHP imap_setflag_full
{"clearflag_full", l_clearflag_full}, // = PHP clearflag_full
{"create_mailbox", l_create_mailbox}, // = PHP imap_createmailbox
{"delete_mailbox", l_delete_mailbox}, // = PHP imap_deletemailbox
{"_8bit", l_8bit}, // = PHP imap_8bit
{"binary", l_binary}, // = PHP imap_binary
{"get_body_struct", l_get_body_struct }, // = PHP imap_bodystruct
{"expunge" , l_expunge}, // = PHP imap_expunge
{"get_overview", l_get_overview}, // = PHP imap_fetch_overview
{"get_mime", l_get_mime}, // = PHP imap_fetchmime
{"gc", l_gc}, // = PHP imap_gc
{"get_quota", l_get_quota}, // = PHP imap_get_quota
{"get_quotaroot", l_get_quotaroot}, // = PHP imap_get_quotaroot
{"get_acl", l_getacl}, // = PHP imap_getacl,
{"get_subscribed", l_get_subscribed}, // = PHP imap_getsubscribed, imap_listsubscribed, imap_lsub
{"scan_mailboxes", l_scan_mailboxes}, // = PHP imap_listscan,
// {"mail_compose", l_mail_compose}, TODO
{NULL,NULL}
};
/*
cleanup in a c module
https://lua-l.lua.narkive.com/09DuVpEl/cleanup-in-a-c-module
The sentinel userdata above will call the cleanup code as soon as it is collected;
to prevent collection until the module is destroyed, we need to add a reference that links the module to the sentinel.
We're using the LUA_REGISTRYINDEX to store this in a way that is hidden from Lua scripts.
We create a weak-valued table in the registry called "__gc_sentinels" (if it doesn't already exist),
and use weak-referencing so that existence of the module in this table will not stop it from being collected.
For most uses of Lua, this won't matter since modules usually only get unloaded when the lua_State is closed;
but we had a situation where we needed to manually unload modules sometimes.
*/
static void gc_sentinel(lua_State * L, int idx, lua_CFunction callback) {
lua_pushvalue(L, idx); // value @idx
lua_newuserdata(L, sizeof(void *)); // sentinel userdata
lua_newtable(L); // userdata metatable with __gc = callback
lua_pushcfunction(L, callback);
lua_setfield(L, -2, "__gc");
lua_setmetatable(L, -2);
/* check for (weak-valued) sentinel table; create if needed */
lua_getfield(L, LUA_REGISTRYINDEX, "__gc_limap_sentinels");
if (lua_isnoneornil(L, -1)) {
lua_pop(L, 1);
lua_newtable(L);
// make weak-keyed
lua_pushstring(L, "v");
lua_setfield(L, -2, "__mode");
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
lua_pushvalue(L, -1);
lua_setmetatable(L, -2);
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, "__gc_limap_sentinels");
}
lua_insert(L, -3);
lua_insert(L, -2);
lua_settable(L, -3); // lua::sentinel[value @idx] = sentinel userdata
lua_pop(L, 1); // lua::sentinel
}
int luaopen_limap(lua_State *L)
{
M_LOG("Imap module loaded");
#include "linkage.c"
pthread_mutex_init(&_limap_lock, NULL);
__L__ = NULL;
// create error stack
lua_newtable( L );
lua_setglobal( L, "limap_errors" );
luaL_newlib(L, _lib);
gc_sentinel(L, -1, l_lua_gc);
return 1;
}

View File

@ -10,13 +10,15 @@ local OP_EXPUNGE= 0x80 --/* silently expunge recycle stream */
local imap = require("limap")
local passwd = os.getenv("IMAP_PWD")
local url = string.format("{iohub.dev:143/imap/tls-sslv23/novalidate-cert/user=mrsang;%s}",passwd);
local handle, box = imap.open(url,true, true) -- half open and debug on
local url = "{iohub.dev:993/imap/ssl/novalidate-cert}"
--local url = string.format("{iohub.dev:993/imap/ssl/novalidate-cert/user=dany@iohub.dev;%s}",passwd);
local handle, box = imap.open(url,"dany@iohub.dev", passwd, true, true) -- half open and debug on
local r,v = false,nil;
function dump(obj)
if(type(obj) == "table") then
print("dump", obj, " size: ", #obj)
for k,v in pairs(obj) do
print(k)
dump(v)
@ -38,21 +40,24 @@ if(handle) then
end
end
r, box = imap.reopen(handle,box:gsub("[^}]*$","INBOX"), false, true) -- half open off, debug on
print(box)
if r then
print("new box opened", box)
else
print("reopen failed")
end
r,v = imap.ping(handle)
v,r = imap.ping(handle)
if r then
print("Alive", v)
else
print("Unable to ping")
end
imap.check(handle);
local mbdata = imap.check(handle)
dump(mbdata)
-- get nmail
local nmail = imap.get_nmail(handle);
print("umber of mail", nmail);
local nmail = imap.get_nmail(handle)
print("umber of mail", nmail)
if nmail > 0 then
local headers = imap.get_headers(handle)
@ -68,5 +73,54 @@ if(handle) then
local structure = imap.get_structure(handle, nmail)
dump(structure)
-- append message to a mail box
--if imap.append(handle, box:gsub("[^}]*$","Drafts"),
-- "From: dany@iohub.dev\r\n"
-- .. "To: xsang.le@gmail.com\r\n"
-- .. "Subject: test\r\n"
-- .. "\r\n"
-- .. "this is a test message, please ignore\r\n") then
-- print("Message appended")
--else
-- print("Error append message")
--end
-- get body structure
print("########## Get body section 1 structure")
local bstruct = imap.get_body_struct(handle, nmail,"1" )
dump(bstruct)
print("########## fetch overview messages")
local ov = imap.get_overview(handle,string.format("1:%d", nmail), false)
dump(ov)
print("########## fetch mime")
local mime = imap.get_mime(handle,nmail,"1", true) -- peak the message without set it to seen
dump(mime)
--print("########## get quota")
--local quota = imap.get_quota(handle,"user.dany")
--dump(quota)
--print("########## get quota root")
--local quota = imap.get_quotaroot(handle,"INBOX")
--dump(quota)
--print("########## get ACL")
--local acl = imap.get_acl(handle,box)
--dump(acl)
print("#mail subscriber")
local sub = imap.get_subscribed(handle, box:gsub("[^}]*$",""), "*")
dump(sub)
--print("#mailbox scan")
--local sub = imap.scan_mailboxes(handle, box:gsub("[^}]*$",""), "*", "Junk")
--dump(sub)
print("######### ERROR stack")
dump(limap_errors)
print("Close handle")
imap.close(handle)
end