2022-08-26 19:40:12 +02:00
|
|
|
#include "lua.h"
|
|
|
|
#include "lauxlib.h"
|
|
|
|
#include "lualib.h"
|
|
|
|
#include "c-client.h"
|
|
|
|
#include "imap4r1.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
2023-06-14 15:20:16 +02:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <pthread.h>
|
2022-08-26 19:40:12 +02:00
|
|
|
extern int errno; /* just in case */
|
|
|
|
|
2023-06-14 15:20:16 +02:00
|
|
|
#define IMAP_MT "limap"
|
|
|
|
|
|
|
|
#define IMAP_ADDRESS_SIZE_BUF 10
|
|
|
|
|
|
|
|
#ifndef SENDBUFLEN
|
|
|
|
#define SENDBUFLEN 16385
|
|
|
|
#endif
|
|
|
|
|
2022-08-26 19:40:12 +02:00
|
|
|
#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__, \
|
|
|
|
__LINE__, ##__VA_ARGS__)
|
|
|
|
#define M_ERROR(a,...) syslog (LOG_ERR, "limap@[%s: %d]: " a "\n", __FILE__, \
|
|
|
|
__LINE__, ##__VA_ARGS__)
|
|
|
|
|
|
|
|
#define add_property_string(L,k,v) \
|
|
|
|
lua_pushstring(L,k); \
|
|
|
|
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);
|
|
|
|
|
2023-06-14 15:20:16 +02:00
|
|
|
|
|
|
|
static pthread_mutex_t _limap_lock;
|
|
|
|
static lua_State* __L__;
|
|
|
|
|
2022-08-26 19:40:12 +02:00
|
|
|
unsigned long find_rightmost_bit(unsigned long *valptr);
|
|
|
|
|
|
|
|
static 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 */
|
|
|
|
|
|
|
|
|
|
|
|
/* Message matches a search
|
|
|
|
* Accepts: MAIL stream
|
|
|
|
* message number
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_searched (MAILSTREAM *stream,unsigned long msgno)
|
|
|
|
{
|
|
|
|
/* dummy routine */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Message exists (i.e. there are that many messages in the mailbox)
|
|
|
|
* Accepts: MAIL stream
|
|
|
|
* message number
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_exists (MAILSTREAM *stream,unsigned long number)
|
|
|
|
{
|
|
|
|
M_LOG("New emails found in %s: %d", stream->mailbox, number);
|
2023-06-14 15:20:16 +02:00
|
|
|
lua_State * L = stream->sparep;
|
|
|
|
if(!L) return;
|
|
|
|
lua_pushnumber(L, number);
|
2022-08-26 19:40:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Message expunged
|
|
|
|
* Accepts: MAIL stream
|
|
|
|
* message number
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_expunged (MAILSTREAM *stream,unsigned long number)
|
|
|
|
{
|
|
|
|
/* dummy routine */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Message flags update seen
|
|
|
|
* Accepts: MAIL stream
|
|
|
|
* message number
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_flags (MAILSTREAM *stream,unsigned long number)
|
|
|
|
{
|
|
|
|
/* dummy routine */
|
|
|
|
}
|
|
|
|
/* Mailbox found
|
|
|
|
* Accepts: MAIL stream
|
|
|
|
* hierarchy delimiter
|
|
|
|
* mailbox name
|
|
|
|
* mailbox attributes
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
|
|
|
|
{
|
|
|
|
lua_State *L = stream->sparep;
|
|
|
|
if(!L)
|
|
|
|
return;
|
|
|
|
if(attributes & LATT_NOSELECT)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
size_t cnt = lua_rawlen(L,-1) + 1;
|
|
|
|
lua_pushnumber(L,cnt);
|
|
|
|
lua_newtable(L);
|
|
|
|
char delim[2];
|
|
|
|
delim[0] = (char) delimiter;
|
|
|
|
delim[1] = '\0';
|
|
|
|
if(!name)
|
|
|
|
return;
|
|
|
|
lua_pushstring(L, "delimiter");
|
|
|
|
lua_pushstring(L, delim);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
|
|
|
lua_pushstring(L, "name");
|
|
|
|
lua_pushstring(L, name);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
|
|
|
lua_pushstring(L, "LATT_NOINFERIORS");
|
|
|
|
lua_pushboolean(L, attributes & LATT_NOINFERIORS);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
|
|
|
lua_pushstring(L, "LATT_NOSELECT");
|
|
|
|
lua_pushboolean(L, attributes & LATT_NOSELECT);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
|
|
|
lua_pushstring(L, "LATT_MARKED");
|
|
|
|
lua_pushboolean(L, attributes & LATT_MARKED);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
|
|
|
lua_pushstring(L, "LATT_UNMARKED");
|
|
|
|
lua_pushboolean(L, attributes & LATT_UNMARKED);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Subscribe mailbox found
|
|
|
|
* Accepts: MAIL stream
|
|
|
|
* hierarchy delimiter
|
|
|
|
* mailbox name
|
|
|
|
* mailbox attributes
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
|
|
|
|
{
|
2023-06-14 15:20:16 +02:00
|
|
|
mm_list(stream,delimiter, name,attributes);
|
2022-08-26 19:40:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Mailbox status
|
|
|
|
* Accepts: MAIL stream
|
|
|
|
* mailbox name
|
|
|
|
* mailbox status
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
|
|
|
|
{
|
|
|
|
if (status->recent || status->unseen)
|
|
|
|
printf ("%lu new message(s) (%lu unseen),",status->recent,status->unseen);
|
|
|
|
else fputs ("No new messages,",stdout);
|
|
|
|
printf (" %lu total in %s\n",status->messages,mailbox);
|
|
|
|
}
|
|
|
|
/* Notification event
|
|
|
|
* Accepts: MAIL stream
|
|
|
|
* string to log
|
|
|
|
* error flag
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_notify (MAILSTREAM *stream,char *string,long errflg)
|
|
|
|
{
|
2023-06-14 15:20:16 +02:00
|
|
|
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 */
|
|
|
|
}
|
2022-08-26 19:40:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Log an event for the user to see
|
|
|
|
* Accepts: string to log
|
|
|
|
* error flag
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_log (char *string,long errflg)
|
|
|
|
{
|
2023-06-14 15:20:16 +02:00
|
|
|
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;
|
|
|
|
}
|
2022-08-26 19:40:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Log an event to debugging telemetry
|
|
|
|
* Accepts: string to log
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_dlog (char *string)
|
|
|
|
{
|
|
|
|
M_LOG ("%s",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
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_login (NETMBX *mb,char *username,char *password,long trial)
|
|
|
|
{
|
2023-06-14 15:20:16 +02:00
|
|
|
// user name
|
|
|
|
if(!lua_isstring(__L__,2))
|
2022-08-26 19:40:12 +02:00
|
|
|
{
|
2023-06-14 15:20:16 +02:00
|
|
|
return;
|
2022-08-26 19:40:12 +02:00
|
|
|
}
|
2023-06-14 15:20:16 +02:00
|
|
|
// 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);
|
2022-08-26 19:40:12 +02:00
|
|
|
}
|
|
|
|
|
2023-06-14 15:20:16 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2022-08-26 19:40:12 +02:00
|
|
|
|
|
|
|
/* About to enter critical code
|
|
|
|
* Accepts: stream
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_critical (MAILSTREAM *stream)
|
|
|
|
{
|
|
|
|
/* note in critical code */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* About to exit critical code
|
|
|
|
* Accepts: stream
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_nocritical (MAILSTREAM *stream)
|
|
|
|
{
|
|
|
|
/* note not in critical code */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Disk error found
|
|
|
|
* Accepts: stream
|
|
|
|
* system error code
|
|
|
|
* flag indicating that mailbox may be clobbered
|
|
|
|
* Returns: T if user wants to abort
|
|
|
|
*/
|
|
|
|
|
|
|
|
long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
|
|
|
|
{
|
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Log a fatal error event
|
|
|
|
* Accepts: string to log
|
|
|
|
*/
|
|
|
|
|
|
|
|
void mm_fatal (char *string)
|
|
|
|
{
|
|
|
|
M_ERROR ("FATAL: %s",string);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int l_mail_open(lua_State *L)
|
|
|
|
{
|
|
|
|
const char* mailbox = luaL_checkstring(L,1);
|
|
|
|
long flag = 0;
|
2023-06-14 15:20:16 +02:00
|
|
|
if( lua_toboolean(L,4))
|
2022-08-26 19:40:12 +02:00
|
|
|
{
|
2023-01-10 00:34:20 +01:00
|
|
|
/*half open*/
|
|
|
|
flag = flag | OP_HALFOPEN;
|
|
|
|
}
|
2023-06-14 15:20:16 +02:00
|
|
|
if( lua_toboolean(L,5))
|
2023-01-10 00:34:20 +01:00
|
|
|
{
|
|
|
|
/*debug*/
|
|
|
|
flag = flag | OP_DEBUG;
|
2022-08-26 19:40:12 +02:00
|
|
|
}
|
2023-06-14 15:20:16 +02:00
|
|
|
pthread_mutex_lock(&_limap_lock);
|
|
|
|
__L__ = L;
|
2022-08-26 19:40:12 +02:00
|
|
|
MAILSTREAM *stream = mail_open (NIL,(char*)mailbox,flag);
|
2023-06-14 15:20:16 +02:00
|
|
|
__L__ = NULL;
|
|
|
|
pthread_mutex_unlock(&_limap_lock);
|
2022-08-26 19:40:12 +02:00
|
|
|
if(!stream)
|
|
|
|
{
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
//strncpy(stream->original_mailbox, stream->mailbox, strlen(stream->mailbox));
|
2023-06-14 15:20:16 +02:00
|
|
|
/*if(stream->original_mailbox)
|
2022-08-26 19:40:12 +02:00
|
|
|
{
|
|
|
|
free(stream->original_mailbox);
|
|
|
|
}
|
2023-06-14 15:20:16 +02:00
|
|
|
stream->original_mailbox = strdup(stream->mailbox);*/
|
|
|
|
stream->sparep = (void*)L;
|
2022-08-26 19:40:12 +02:00
|
|
|
M_LOG("mailbox: %s", stream->mailbox);
|
|
|
|
M_LOG("original_mailbox: %s", stream->original_mailbox);
|
|
|
|
lua_pushlightuserdata(L, stream);
|
|
|
|
lua_pushstring(L,stream->mailbox);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_mail_close(lua_State *L)
|
|
|
|
{
|
|
|
|
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
|
|
|
|
if(!stream)
|
|
|
|
{
|
|
|
|
lua_pushboolean(L,0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
(void) mail_close(stream);
|
|
|
|
lua_pushboolean(L,1);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_get_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);
|
|
|
|
if(!stream)
|
|
|
|
{
|
|
|
|
lua_pushboolean(L,0);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
lua_newtable(L);
|
|
|
|
mail_list(stream,(char*)reference, (char*)pattern);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_mail_ping(lua_State *L)
|
|
|
|
{
|
|
|
|
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
|
|
|
|
if(!stream || mail_ping(stream) == NIL)
|
|
|
|
{
|
|
|
|
lua_pushboolean(L,0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lua_pushboolean(L,1);
|
|
|
|
}
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_mail_check(lua_State *L)
|
|
|
|
{
|
|
|
|
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
|
|
|
|
if(!stream)
|
|
|
|
{
|
2023-06-14 15:20:16 +02:00
|
|
|
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;
|
2022-08-26 19:40:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
mail_free_envelope(&en);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lua_pushnil(L);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int l_reopen(lua_State *L)
|
|
|
|
{
|
|
|
|
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
|
|
|
|
const char* mailbox = luaL_checkstring(L,2);
|
|
|
|
long flag = 0;
|
2023-01-10 00:34:20 +01:00
|
|
|
if( lua_toboolean(L,3))
|
2022-08-26 19:40:12 +02:00
|
|
|
{
|
2023-01-10 00:34:20 +01:00
|
|
|
/*half open*/
|
|
|
|
flag = flag | OP_HALFOPEN;
|
|
|
|
}
|
|
|
|
if( lua_toboolean(L,4))
|
|
|
|
{
|
|
|
|
/*debug*/
|
|
|
|
flag = flag | OP_DEBUG;
|
2022-08-26 19:40:12 +02:00
|
|
|
}
|
|
|
|
if(!stream)
|
|
|
|
{
|
|
|
|
lua_pushboolean(L,0);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
stream = mail_open (stream,(char*)mailbox,flag);
|
|
|
|
if(!stream)
|
|
|
|
{
|
|
|
|
lua_pushboolean(L,0);
|
|
|
|
return 1;
|
|
|
|
}
|
2023-06-14 15:20:16 +02:00
|
|
|
stream->sparep = (void*) L;
|
|
|
|
/*if(stream->original_mailbox)
|
2022-08-26 19:40:12 +02:00
|
|
|
{
|
|
|
|
free(stream->original_mailbox);
|
|
|
|
}
|
2023-06-14 15:20:16 +02:00
|
|
|
stream->original_mailbox = strdup(stream->mailbox);*/
|
2022-08-26 19:40:12 +02:00
|
|
|
M_LOG("mailbox: %s", stream->mailbox);
|
|
|
|
M_LOG("original_mailbox: %s", stream->original_mailbox);
|
|
|
|
lua_pushboolean(L,1);
|
|
|
|
lua_pushstring(L,stream->mailbox);
|
|
|
|
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 */
|
2023-01-10 00:34:20 +01:00
|
|
|
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);
|
2022-08-26 19:40:12 +02:00
|
|
|
mail_date(tmp, cache);
|
2023-01-10 00:34:20 +01:00
|
|
|
add_property_string(L, "mail_date", tmp);
|
|
|
|
add_property_long(L, "size", cache->rfc822_size);
|
2022-08-26 19:40:12 +02:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
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 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);
|
2023-01-10 00:34:20 +01:00
|
|
|
|
|
|
|
switch(body->type)
|
|
|
|
{
|
|
|
|
case TYPETEXT: /* unformatted text */
|
|
|
|
add_property_string(L, "type_text", "TEXT");
|
|
|
|
break;
|
|
|
|
case TYPEMULTIPART: /* multiple part */
|
|
|
|
add_property_string(L, "type_text", "MULTIPART");
|
|
|
|
break;
|
|
|
|
case TYPEMESSAGE: /* encapsulated message */
|
|
|
|
add_property_string(L, "type_text", "MESSAGE");
|
|
|
|
break;
|
|
|
|
case TYPEAPPLICATION: /* application data */
|
|
|
|
add_property_string(L, "type_text", "APPLICATION");
|
|
|
|
break;
|
|
|
|
case TYPEAUDIO: /* audio */
|
|
|
|
add_property_string(L, "type_text", "AUDIO");
|
|
|
|
break;
|
|
|
|
case TYPEIMAGE: /* static image */
|
|
|
|
add_property_string(L, "type_text", "IMAGE");
|
|
|
|
break;
|
|
|
|
case TYPEVIDEO: /* video */
|
|
|
|
add_property_string(L, "type_text", "VIDEO");
|
|
|
|
break;
|
|
|
|
case TYPEMODEL: /* model */
|
|
|
|
add_property_string(L, "type_text", "MODEL");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
add_property_string(L, "type_text", "OTHER");
|
|
|
|
break;
|
|
|
|
}
|
2022-08-26 19:40:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (body->encoding <= ENCMAX) {
|
|
|
|
add_property_long(L, "encoding", body->encoding);
|
2023-01-10 00:34:20 +01:00
|
|
|
|
|
|
|
switch(body->encoding)
|
|
|
|
{
|
|
|
|
case ENC7BIT: /* 7 bit SMTP semantic data */
|
|
|
|
add_property_string(L, "encoding_text", "7BIT");
|
|
|
|
break;
|
|
|
|
case ENC8BIT: /* 8 bit SMTP semantic data */
|
|
|
|
add_property_string(L, "encoding_text", "8BIT");
|
|
|
|
break;
|
|
|
|
case ENCBINARY: /* 8 bit binary data */
|
|
|
|
add_property_string(L, "encoding_text", "BINARY");
|
|
|
|
break;
|
|
|
|
case ENCBASE64: /* base-64 encoded data */
|
|
|
|
add_property_string(L, "encoding_text", "BASE64");
|
|
|
|
break;
|
|
|
|
case ENCQUOTEDPRINTABLE: /* human-readable 8-as-7 bit data */
|
|
|
|
add_property_string(L, "encoding_text", "QUOTEDPRINTABLE");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
add_property_string(L, "encoding_text", "OTHER");
|
|
|
|
break;
|
|
|
|
}
|
2022-08-26 19:40:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2023-01-10 00:34:20 +01:00
|
|
|
//count = 1;
|
2022-08-26 19:40:12 +02:00
|
|
|
do {
|
2023-01-10 00:34:20 +01:00
|
|
|
//lua_pushnumber(L, count);
|
|
|
|
//lua_newtable(L);
|
|
|
|
if(dpar->attribute && dpar->value)
|
|
|
|
{
|
|
|
|
add_property_string(L, dpar->attribute, dpar->value);
|
|
|
|
}
|
|
|
|
//lua_settable(L,-3);
|
|
|
|
//count++;
|
2022-08-26 19:40:12 +02:00
|
|
|
} while ((dpar = dpar->next));
|
|
|
|
lua_settable(L, -3);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((par = body->parameter)) {
|
|
|
|
lua_pushstring(L, "parameters");
|
|
|
|
lua_newtable(L);
|
2023-01-10 00:34:20 +01:00
|
|
|
//count = 1;
|
2022-08-26 19:40:12 +02:00
|
|
|
do {
|
2023-01-10 00:34:20 +01:00
|
|
|
//lua_pushnumber(L, count);
|
|
|
|
//lua_newtable(L);
|
|
|
|
if (par->attribute && par->value) {
|
|
|
|
add_property_string(L, par->attribute, par->value);
|
2022-08-26 19:40:12 +02:00
|
|
|
}
|
|
|
|
|
2023-01-10 00:34:20 +01:00
|
|
|
//lua_settable(L,-3);
|
|
|
|
//count++;
|
2022-08-26 19:40:12 +02:00
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
|
2023-01-10 00:34:20 +01:00
|
|
|
static int l_get_body_part(lua_State* L)
|
|
|
|
{
|
|
|
|
MAILSTREAM *stream = (MAILSTREAM *) lua_touserdata(L, 1);
|
|
|
|
if(!stream)
|
|
|
|
{
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
const int msgno = luaL_checknumber(L,2);
|
|
|
|
const char* part_name = luaL_checkstring(L,3);
|
|
|
|
unsigned int flags = 0;
|
|
|
|
if(lua_toboolean(L,3))
|
|
|
|
{
|
|
|
|
flags |= FT_PEEK;
|
|
|
|
}
|
|
|
|
char *body;
|
|
|
|
unsigned long len;
|
|
|
|
body = mail_fetchbody_full(stream, msgno, (char*)part_name, &len, flags);
|
|
|
|
|
|
|
|
if (!body) {
|
|
|
|
lua_pushnil(L);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
lua_pushstring(L, body);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-06-14 15:20:16 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-08-26 19:40:12 +02:00
|
|
|
static const struct luaL_Reg _lib [] = {
|
|
|
|
{"open", l_mail_open},
|
|
|
|
{"close", l_mail_close},
|
2023-06-14 15:20:16 +02:00
|
|
|
{"get_mail_boxes", l_get_mailboxes},// = PHP imap_getmailboxes, imap_list
|
2022-08-26 19:40:12 +02:00
|
|
|
{"reopen", l_reopen},
|
|
|
|
{"ping", l_mail_ping},
|
2023-06-14 15:20:16 +02:00
|
|
|
{"check", l_mail_check}, // PHP imap_check
|
|
|
|
{"get_raw_header", l_mail_get_raw_header}, // = PHP imap_fetchheader()
|
2022-08-26 19:40:12 +02:00
|
|
|
{"get_nmail", l_mail_getnumber},
|
|
|
|
{"get_headers", l_mail_get_headers},
|
2023-06-14 15:20:16 +02:00
|
|
|
{"get_header", l_mail_get_header}, // = php imap_header()
|
2022-08-26 19:40:12 +02:00
|
|
|
{"rfc822_parse_header", l_rfc822_parse_header},
|
2023-06-14 15:20:16 +02:00
|
|
|
{"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
|
|
|
|
|
2022-08-26 19:40:12 +02:00
|
|
|
{NULL,NULL}
|
|
|
|
};
|
|
|
|
|
2023-06-14 15:20:16 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-08-26 19:40:12 +02:00
|
|
|
int luaopen_limap(lua_State *L)
|
|
|
|
{
|
2023-06-14 15:20:16 +02:00
|
|
|
M_LOG("Imap module loaded");
|
2022-08-26 19:40:12 +02:00
|
|
|
#include "linkage.c"
|
2023-06-14 15:20:16 +02:00
|
|
|
pthread_mutex_init(&_limap_lock, NULL);
|
|
|
|
__L__ = NULL;
|
|
|
|
// create error stack
|
|
|
|
lua_newtable( L );
|
|
|
|
lua_setglobal( L, "limap_errors" );
|
2022-08-26 19:40:12 +02:00
|
|
|
luaL_newlib(L, _lib);
|
2023-06-14 15:20:16 +02:00
|
|
|
gc_sentinel(L, -1, l_lua_gc);
|
2022-08-26 19:40:12 +02:00
|
|
|
return 1;
|
|
|
|
}
|