/****************************************************************************** * $Id: engine.c,v 1.27 2006/01/15 19:43:15 gareuselesinge Exp $ * This file is part of FreePOPs (http://www.freepops.org) * * This file is distributed under the terms of GNU GPL license. * ******************************************************************************/ /****************************************************************************** * File description: * Implements the politics * Notes: * These functions are called by the pop server thread and are common * to all mail engines * Authors: * Nicola Cocchiaro ******************************************************************************/ #include #include #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "popserver.h" #include "popstate.h" #include "lua.h" #include "lualib.h" #include "lauxlib.h" #include "luay.h" #include "luabox.h" #include "freepops.h" #include "log.h" #define LOG_ZONE "ENGINE" /******************************************************************************/ struct popstate_other_t { lua_State* l; //FIX maybe we need only this }; void * assign(void*x) { return x; } #define CAST(a) ((struct popstate_other_t *)a) /****** Helper functions for get_data() ********/ void size_printer(char *s_ans, size_t nbytes, int msg, struct mail_msg_t *t) { snprintf(s_ans, nbytes+1, "%d %d\r\n", msg, get_mailmessage_size(t)); } void uidl_printer(char *s_ans, size_t nbytes, int msg, struct mail_msg_t *t) { if ( get_mailmessage_uidl(t) != NULL) snprintf(s_ans, nbytes+1, "%d %s\r\n", msg, get_mailmessage_uidl(t)); else snprintf(s_ans, nbytes+1, "%d 0\r\n", msg); } size_t size_counter(struct mail_msg_t *t) { return B(get_mailmessage_size(t)); } size_t uidl_counter(struct mail_msg_t *t) { if (get_mailmessage_uidl(t) != NULL) return strlen(get_mailmessage_uidl(t)); else return 1; } //! gets requested data (sizes or uidls) from all mail messages void get_data(struct popstate_t *p, char **buffer, size_t counter(struct mail_msg_t *), void printer(char *, size_t, int, struct mail_msg_t *)) { int ind,n; size_t nbytes = 0; char *ans, *s_ans; ans = (char*)malloc(1); MALLOC_CHECK(ans); *ans = '\0'; n = get_popstate_nummesg(p); for (ind = 0; ind < n; ind++) { struct mail_msg_t *m = get_popstate_mailmessage(p,ind); if (m != NULL && !get_mailmessage_flag(m,MAILMESSAGE_DELETE)) { nbytes = B(ind+1) + counter(get_popstate_mailmessage(p,ind)) + 3 + 1; s_ans = (char*)malloc(nbytes+1); MALLOC_CHECK(s_ans); printer(s_ans, nbytes, ind+1, get_popstate_mailmessage(p,ind)); ans = (char*)realloc(ans, strlen(ans)+nbytes+1); MALLOC_CHECK(ans); strcat(ans, s_ans); free(s_ans); } } /* remove trailing \r\n */ if(strlen(ans)>1) // what if the string is empty ans[strlen(ans)-2]='\0'; *buffer = strdup(ans); free(ans); } /****************************************************************************** * starts the VM with the freepops stuff, if username is NULL only * freepops.bootstrap is called, else freepops.init(username) and init(p). */ #define FREEPOPSLUA_FILE "freepops.lua" lua_State* bootstrap(const char * username, struct popstate_t* p){ int rc = POPSERVER_ERR_UNKNOWN; lua_State* l; l = luabox_genbox(LUABOX_STANDARD|LUABOX_LOG|LUABOX_LUAFILESYSTEM); putenv("FREEPOPSLUA_PATH_UNOFFICIAL="FREEPOPSLUA_PATH_UNOFFICIAL); putenv("FREEPOPS_VERSION="VERSION); //FIXME //putenv("FREEPOPSLUA_USER_UNOFFICIAL="FREEPOPSLUA_USER_UNOFFICIAL); //open freepops module rc = luaL_loadfile(l,FREEPOPSLUA_PATH FREEPOPSLUA_FILE); if (rc != 0) { DBG("Unable to load " FREEPOPSLUA_PATH FREEPOPSLUA_FILE "\n"); luay_printstack(l); //for developing purposes luay_emptystack(l); rc = luaL_loadfile(l,"src/lua/" FREEPOPSLUA_FILE); if (rc != 0) { DBG("Unable to load src/lua/" FREEPOPSLUA_FILE "\n"); luay_printstack(l); //for developing purposes luay_emptystack(l); rc = luaL_loadfile(l,FREEPOPSLUA_FILE); if (rc != 0) { ERROR_PRINT("Unable to load " FREEPOPSLUA_FILE "\n"); luay_printstack(l); ERROR_PRINT("Unable to load " FREEPOPSLUA_FILE ". Path was '" FREEPOPSLUA_PATH ":src/lua/:./'\n"); ERROR_PRINT("Working dir is %s\n",getenv("PWD")); ERROR_PRINT("Can't bootstrap without " FREEPOPSLUA_FILE"\n"); lua_close(l); return NULL; } putenv("FREEPOPSLUA_PATH=./"); } putenv("FREEPOPSLUA_PATH=src/lua/"); } else { putenv("FREEPOPSLUA_PATH="FREEPOPSLUA_PATH); } rc = lua_pcall(l, 0, LUA_MULTRET, 0); if (rc != 0) { luay_printstack(l); lua_close(l); return NULL; } luay_emptystack(l); if (username == NULL) { luay_call(l, "s|d", "freepops.bootstrap", username, &rc); if(rc != 0){ ERROR_PRINT("Error calling freepops.bootstrap"); luay_printstack(l); lua_close(l); return NULL; } luay_emptystack(l); // add the missing lua stuff luabox_addtobox(l,LUABOX_FREEPOPS ^ (LUABOX_LOG & LUABOX_LUAFILESYSTEM)); luay_emptystack(l); } else { luay_call(l, "s|d", "freepops.init", username, &rc); if(rc != 0){ ERROR_PRINT("Error calling freepops.init('%s')", username); luay_printstack(l); lua_close(l); return NULL; } luay_emptystack(l); // add the missing lua stuff luabox_addtobox(l,LUABOX_FREEPOPS ^ (LUABOX_LOG & LUABOX_LUAFILESYSTEM)); luay_emptystack(l); luay_call(l, "p|d", "init", p, &rc); if(rc != 0){ ERROR_PRINT( "Error calling init function of lua module"); luay_printstack(l); lua_close(l); return NULL; } } return l; } /******************************************************************************/ int freepops_user(struct popstate_t*p,char* username) { int rc = POPSERVER_ERR_UNKNOWN; struct popstate_other_t * tmp = malloc(sizeof(struct popstate_other_t)); MALLOC_CHECK(tmp); new_popstate_other(p,assign,tmp); tmp->l = bootstrap(username,p); if ( tmp->l == NULL) { ERROR_PRINT("Error bootstrapping\n"); return POPSERVER_ERR_UNKNOWN; } luay_call(tmp->l,"ps|d","user",p,username,&rc); return rc; } int freepops_pass(struct popstate_t*p,char* password) { int rc = POPSERVER_ERR_UNKNOWN; if(CAST(get_popstate_other(p)) == NULL) return POPSERVER_ERR_SYNTAX; luay_call(CAST(get_popstate_other(p))->l,"ps|d","pass",p,password,&rc); return rc; } int freepops_quit(struct popstate_t*p) { int rc = POPSERVER_ERR_OK; if(CAST(get_popstate_other(p)) != NULL && CAST(get_popstate_other(p))->l != NULL ) luay_call(CAST(get_popstate_other(p))->l,"p|d","quit",p,&rc); return rc; } int freepops_quit_update(struct popstate_t*p) { int rc = POPSERVER_ERR_UNKNOWN; luay_call(CAST(get_popstate_other(p))->l,"p|d","quit_update",p,&rc); return rc; } int freepops_top(struct popstate_t*p,long int msg,long int lines,void *data) { int rc = POPSERVER_ERR_UNKNOWN; struct mail_msg_t *m = get_popstate_mailmessage(p,msg-1); if (m != NULL && get_mailmessage_flag(m,MAILMESSAGE_DELETE)) return POPSERVER_ERR_NOMSG; luay_call(CAST(get_popstate_other(p))->l,"pddp|d","top",p,msg,lines,data,&rc); return rc; } int freepops_retr(struct popstate_t*p,int msg,void* data) { int rc = POPSERVER_ERR_UNKNOWN; struct mail_msg_t *m = get_popstate_mailmessage(p,msg-1); if (m != NULL && get_mailmessage_flag(m,MAILMESSAGE_DELETE)) return POPSERVER_ERR_NOMSG; luay_call(CAST(get_popstate_other(p))->l,"pdp|d","retr",p,msg,data,&rc); return rc; } int freepops_stat(struct popstate_t*p,int *messages,int* size) { int rc = POPSERVER_ERR_UNKNOWN; *messages = * size = 0; luay_call(CAST(get_popstate_other(p))->l,"p|d","stat",p,&rc); if(rc == POPSERVER_ERR_OK) { int n,s; n = get_popstate_nummesg(p); s = get_popstate_boxsize(p); *size = s; *messages = n ; } return rc; } int freepops_uidl(struct popstate_t*p,int msg,char **buffer) { int rc = POPSERVER_ERR_UNKNOWN; struct mail_msg_t *m = get_popstate_mailmessage(p,msg-1); *buffer = NULL; if (m != NULL && get_mailmessage_flag(m,MAILMESSAGE_DELETE)) return POPSERVER_ERR_NOMSG; luay_call(CAST(get_popstate_other(p))->l,"pd|d","uidl",p,msg,&rc); if(rc == POPSERVER_ERR_OK) { int size; char* ans; const char *uidl; struct mail_msg_t*m = NULL; m=get_popstate_mailmessage(p,msg-1); if(m == NULL) { *buffer = NULL; return POPSERVER_ERR_NOMSG; } uidl = get_mailmessage_uidl(m); size = B(msg) + 1 + strlen(uidl) + 1; ans = malloc(size); MALLOC_CHECK(ans); snprintf(ans, size, "%d %s", msg, uidl); *buffer = strdup(ans); MALLOC_CHECK(*buffer); free(ans); } return rc; } int freepops_uidl_all(struct popstate_t*p,char **buffer) { int rc = POPSERVER_ERR_UNKNOWN; *buffer = NULL; luay_call(CAST(get_popstate_other(p))->l,"p|d","uidl_all",p,&rc); if(rc == POPSERVER_ERR_OK) get_data(p, buffer, uidl_counter, uidl_printer); return rc; } int freepops_list(struct popstate_t*p,int msg,char **buffer) { int rc = POPSERVER_ERR_UNKNOWN; struct mail_msg_t *m = get_popstate_mailmessage(p,msg-1); if (m != NULL && get_mailmessage_flag(m,MAILMESSAGE_DELETE)) return POPSERVER_ERR_NOMSG; luay_call(CAST(get_popstate_other(p))->l,"pd|d","list",p,msg,&rc); if(rc == POPSERVER_ERR_OK) { int size; char* ans; int size_mesg; struct mail_msg_t*m = NULL; m=get_popstate_mailmessage(p,msg-1); if(m == NULL) { *buffer = NULL; return POPSERVER_ERR_NOMSG; } size_mesg = get_mailmessage_size(m); size = B(msg) + 1 + B(size_mesg) + 1; ans = malloc(size); MALLOC_CHECK(ans); snprintf(ans, size, "%d %d", msg, size_mesg); *buffer = strdup(ans); MALLOC_CHECK(*buffer); free(ans); } return rc; } int freepops_list_all(struct popstate_t*p,char **buffer) { int rc = POPSERVER_ERR_UNKNOWN; *buffer = NULL; luay_call(CAST(get_popstate_other(p))->l,"p|d","list_all",p,&rc); if(rc == POPSERVER_ERR_OK) get_data(p, buffer, size_counter, size_printer); return rc; } int freepops_rset(struct popstate_t*p) { int rc = POPSERVER_ERR_UNKNOWN; luay_call(CAST(get_popstate_other(p))->l,"p|d","rset",p,&rc); return rc; } int freepops_dele(struct popstate_t*p,int msg) { int rc = POPSERVER_ERR_UNKNOWN; luay_call(CAST(get_popstate_other(p))->l,"pd|d","dele",p,msg,&rc); return rc; } int freepops_noop(struct popstate_t*p) { int rc = POPSERVER_ERR_UNKNOWN; luay_call(CAST(get_popstate_other(p))->l,"p|d","noop",p,&rc); return rc; } void freepops_delete_other(void *x) { if(x != NULL && CAST(x)->l != NULL) lua_close(CAST(x)->l); free(x); } /******************************************************************************/ struct popserver_functions_t freepops_functions= { user: freepops_user, pass: freepops_pass, quit: freepops_quit, quit_update:freepops_quit_update, top:freepops_top, retr:freepops_retr, stat:freepops_stat, uidl:freepops_uidl, uidl_all:freepops_uidl_all, list:freepops_list, list_all:freepops_list_all, rset:freepops_rset, dele:freepops_dele, noop:freepops_noop, delete_other:freepops_delete_other };