Newer
Older
/* mailsrvr.c */
/* Synchronet Mail (SMTP/POP3) server and sendmail threads */
/* $Id$ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include <io.h> /* open/close */
#include <share.h> /* share open flags */
#include <process.h> /* _beginthread */
#include <windows.h> /* required for mmsystem.h */
#include <mmsystem.h> /* SND_ASYNC */
#include <stdlib.h> /* ltoa in GNU C lib */
#include <stdarg.h> /* va_list */
#include <string.h> /* strrchr */
#include <ctype.h> /* isdigit */
#include <fcntl.h> /* Open flags */
#include <errno.h> /* errno */
#undef SBBS /* this shouldn't be defined unless building sbbs.dll/libsbbs.so */
#include "sbbs.h"
#include "mime.h"
#include "md5.h"
#include "base64.h"
#include "ini_file.h"
#include "netwrap.h" /* getNameServerList() */
#define FORWARD "forward:"
#define NO_FORWARD "local:"

rswindell
committed
int dns_getmx(char* name, char* mx, char* mx2
,DWORD intf, DWORD ip_addr, BOOL use_tcp, int timeout);
static char* ok_rsp = "250 OK";
static char* auth_ok = "235 User Authenticated";
static char* sys_error = "421 System error";
static char* sys_unavail= "421 System unavailable, try again later";
static char* badarg_rsp = "501 Bad argument";
static char* badseq_rsp = "503 Bad sequence of commands";
static char* badauth_rsp= "535 Authentication failure";
static char* badrsp_err = "%s replied with:\r\n\"%s\"\r\n"
"instead of the expected reply:\r\n\"%s ...\"";
#define TIMEOUT_THREAD_WAIT 60 /* Seconds */
#define DNSBL_THROTTLE_VALUE 5000 /* Milliseconds */
#define STATUS_WFC "Listening"
static mail_startup_t* startup=NULL;
static scfg_t scfg;
static SOCKET server_socket=INVALID_SOCKET;
static SOCKET pop3_socket=INVALID_SOCKET;
static DWORD active_clients=0;
static DWORD thread_count=0;
static BOOL sendmail_running=FALSE;
static DWORD sockets=0;
static DWORD served=0;
static BOOL terminate_server=FALSE;
static BOOL terminate_sendmail=FALSE;
static sem_t sendmail_wakeup_sem;
static char revision[16];
static time_t uptime;
static str_list_t recycle_semfiles;
static str_list_t shutdown_semfiles;
static int mailproc_count;
struct mailproc {
char cmdline[INI_MAX_VALUE_LEN];
str_list_t to;
BOOL passthru;
BOOL native;
} *mailproc_list;
typedef struct {
SOCKET socket;
SOCKADDR_IN client_addr;
} smtp_t,pop3_t;
static int lprintf(int level, char *fmt, ...)
{
va_list argptr;
char sbuf[1024];
if(startup==NULL || startup->lputs==NULL)
return(0);
va_start(argptr,fmt);
vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
sbuf[sizeof(sbuf)-1]=0;
return(startup->lputs(startup->cbdata,level,sbuf));
}
#ifdef _WINSOCKAPI_
static WSADATA WSAData;
#define SOCKLIB_DESC WSAData.szDescription
static BOOL WSAInitialized=FALSE;
static BOOL winsock_startup(void)
{
int status; /* Status Code */
if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
lprintf(LOG_INFO,"%s %s",WSAData.szDescription, WSAData.szSystemStatus);
WSAInitialized=TRUE;
lprintf(LOG_CRIT,"!WinSock startup ERROR %d", status);
return (FALSE);
}
#else /* No WINSOCK */
#define SOCKLIB_DESC NULL
#endif
static void update_clients(void)
{
if(startup!=NULL && startup->clients!=NULL)
startup->clients(startup->cbdata,active_clients+active_sendmail);
static void client_on(SOCKET sock, client_t* client, BOOL update)
if(startup!=NULL && startup->client_on!=NULL)
startup->client_on(startup->cbdata,TRUE,sock,client,update);
}
static void client_off(SOCKET sock)
{
if(startup!=NULL && startup->client_on!=NULL)
startup->client_on(startup->cbdata,FALSE,sock,NULL,FALSE);
static void thread_up(BOOL setuid)
thread_count++;
if(startup!=NULL && startup->thread_up!=NULL)
startup->thread_up(startup->cbdata,TRUE,setuid);
}
static void thread_down(void)
{
if(thread_count>0)
thread_count--;
if(startup!=NULL && startup->thread_up!=NULL)
startup->thread_up(startup->cbdata,FALSE,FALSE);
SOCKET mail_open_socket(int type, const char* protocol)
char error[256];
char section[128];
SOCKET sock;
sock=socket(AF_INET, type, IPPROTO_IP);
if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL)
startup->socket_open(startup->cbdata,TRUE);
SAFEPRINTF(section,"mail|%s",protocol);
if(set_socket_options(&scfg, sock, section, error, sizeof(error)))
lprintf(LOG_ERR,"%04d !ERROR %s",sock,error);
sockets++;
#if 0 /*def _DEBUG */
lprintf(LOG_DEBUG,"%04d Socket opened (%d sockets in use)",sock,sockets);
#endif
}
return(sock);
}

rswindell
committed
int mail_close_socket(SOCKET sock)
if(sock==INVALID_SOCKET)
return(-1);
shutdown(sock,SHUT_RDWR); /* required on Unix */
if(startup!=NULL && startup->socket_open!=NULL)
startup->socket_open(startup->cbdata,FALSE);
if(result!=0) {
if(ERROR_VALUE!=ENOTSOCK)
lprintf(LOG_ERR,"%04d !ERROR %d closing socket",sock, ERROR_VALUE);
lprintf(LOG_DEBUG,"%04d Socket closed (%d sockets in use)",sock,sockets);
#endif
return(result);
}
static void status(char* str)
{
if(startup!=NULL && startup->status!=NULL)
startup->status(startup->cbdata,str);
int sockprintf(SOCKET sock, char *fmt, ...)
int maxlen;
int result;
va_list argptr;
char sbuf[1024];
fd_set socket_set;
struct timeval tv;
len=vsnprintf(sbuf,maxlen=sizeof(sbuf)-2,fmt,argptr);
va_end(argptr);
if(len<0 || len > maxlen) /* format error or output truncated */
len=maxlen;
if(startup->options&MAIL_OPT_DEBUG_TX)
lprintf(LOG_DEBUG,"%04d TX: %.*s", sock, len, sbuf);
memcpy(sbuf+len,"\r\n",2);
if(sock==INVALID_SOCKET) {
lprintf(LOG_WARNING,"!INVALID SOCKET in call to sockprintf");
return(0);
}
/* Check socket for writability (using select) */
tv.tv_usec=0;
FD_ZERO(&socket_set);
FD_SET(sock,&socket_set);
if((result=select(sock+1,NULL,&socket_set,NULL,&tv))<1) {
lprintf(LOG_NOTICE,"%04d !TIMEOUT selecting socket for send"
lprintf(LOG_NOTICE,"%04d !ERROR %d selecting socket for send"
,sock, ERROR_VALUE);
return(0);
}
while((result=sendsocket(sock,sbuf,len))!=len) {
YIELD();
lprintf(LOG_NOTICE,"%04d Connection reset by peer on send",sock);
lprintf(LOG_NOTICE,"%04d Connection aborted by peer on send",sock);
lprintf(LOG_NOTICE,"%04d !ERROR %d sending on socket",sock,ERROR_VALUE);
lprintf(LOG_WARNING,"%04d !ERROR: short send on socket: %d instead of %d",sock,result,len);
}
return(len);
}
static time_t checktime(void)
{
struct tm tm;
memset(&tm,0,sizeof(tm));
tm.tm_year=94;
tm.tm_mday=1;

rswindell
committed
return(mktime(&tm)-0x2D24BD00L);

rswindell
committed
static void recverror(SOCKET socket, int rd, int line)
lprintf(LOG_NOTICE,"%04d Socket closed by peer on receive (line %d)"

rswindell
committed
,socket, line);
lprintf(LOG_NOTICE,"%04d Connection reset by peer on receive (line %d)"

rswindell
committed
,socket, line);
lprintf(LOG_NOTICE,"%04d Connection aborted by peer on receive (line %d)"

rswindell
committed
,socket, line);
lprintf(LOG_NOTICE,"%04d !ERROR %d receiving on socket (line %d)"

rswindell
committed
,socket, ERROR_VALUE, line);
lprintf(LOG_WARNING,"%04d !ERROR: recv on socket returned unexpected value: %d (line %d)"

rswindell
committed
,socket, rd, line);

rswindell
committed
static int sockreadline(SOCKET socket, char* buf, int len)
{
char ch;
int i,rd=0;

rswindell
committed
fd_set socket_set;
struct timeval tv;
if(socket==INVALID_SOCKET) {
lprintf(LOG_WARNING,"!INVALID SOCKET in call to sockreadline");
return(-1);

rswindell
committed
if(server_socket==INVALID_SOCKET || terminate_server) {
lprintf(LOG_WARNING,"%04d !ABORTING sockreadline",socket);
tv.tv_sec=startup->max_inactivity;

rswindell
committed
tv.tv_usec=0;
FD_ZERO(&socket_set);
FD_SET(socket,&socket_set);
i=select(socket+1,&socket_set,NULL,NULL,&tv);

rswindell
committed
if(i==0) {
if((time(NULL)-start)>startup->max_inactivity) {
lprintf(LOG_WARNING,"%04d !SOCKET INACTIVE",socket);
return(-1);

rswindell
committed
recverror(socket,i,__LINE__);
return(-1);

rswindell
committed
}
i=recv(socket, &ch, 1, 0);
if(i<1) {
recverror(socket,i,__LINE__);
return(-1);
if(ch=='\n' /* && rd>=1 */ ) { /* Mar-9-2003: terminate on sole LF */
break;
}
buf[rd++]=ch;
}
if(rd>0 && buf[rd-1]=='\r')
rd--;
buf[rd]=0;
return(rd);
}
static BOOL sockgetrsp(SOCKET socket, char* rsp, char *buf, int len)
{
int rd;
while(1) {
rd = sockreadline(socket, buf, len);
if(rd<1)
return(FALSE);
if(buf[3]=='-') { /* Multi-line response */
if(startup->options&MAIL_OPT_DEBUG_RX_RSP)
lprintf(LOG_DEBUG,"%04d RX: %s",socket,buf);
if(rsp!=NULL && strnicmp(buf,rsp,strlen(rsp))) {
lprintf(LOG_WARNING,"%04d !INVALID RESPONSE: '%s' Expected: '%s'", socket, buf, rsp);
return(FALSE);
}
break;
}
if(startup->options&MAIL_OPT_DEBUG_RX_RSP)
lprintf(LOG_DEBUG,"%04d RX: %s",socket,buf);
return(TRUE);
}
#define MAX_LINE_LEN 1000
static ulong sockmimetext(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxlines
,str_list_t file_list, char* mime_boundary)
char toaddr[256]="";
char fromaddr[256]="";
char fromhost[256];
char date[64];
char* p;
char* tp;
char* content_type=NULL;
/* HEADERS (in recommended order per RFC822 4.1) */
if(!sockprintf(socket,"Date: %s",msgdate(msg->hdr.when_written,date)))
return(0);
if((p=smb_get_hfield(msg,RFC822FROM,NULL))!=NULL)
s=sockprintf(socket,"From: %s",p); /* use original RFC822 header field */
else {
if(msg->from_net.type==NET_QWK && msg->from_net.addr!=NULL)
SAFEPRINTF2(fromaddr,"%s!%s"
,(char*)msg->from_net.addr
,usermailaddr(&scfg,fromhost,msg->from));
else if(msg->from_net.type==NET_FIDO && msg->from_net.addr!=NULL)
SAFECOPY(fromaddr,smb_faddrtoa((faddr_t *)msg->from_net.addr,NULL));
else if(msg->from_net.type!=NET_NONE && msg->from_net.addr!=NULL)
SAFECOPY(fromaddr,(char*)msg->from_net.addr);
else
usermailaddr(&scfg,fromaddr,msg->from);
if(fromaddr[0]=='<')
s=sockprintf(socket,"From: \"%s\" %s",msg->from,fromaddr);
else
s=sockprintf(socket,"From: \"%s\" <%s>",msg->from,fromaddr);
}
if(!s)
return(0);
if(msg->from_org!=NULL || msg->from_net.type==NET_NONE)
if(!sockprintf(socket,"Organization: %s"
,msg->from_org==NULL ? scfg.sys_name : msg->from_org))
return(0);
if(!sockprintf(socket,"Subject: %s",msg->subj))
return(0);
if((p=smb_get_hfield(msg,RFC822TO,NULL))!=NULL)
s=sockprintf(socket,"To: %s",p); /* use original RFC822 header field */
else {
if(strchr(msg->to,'@')!=NULL || msg->to_net.addr==NULL)
s=sockprintf(socket,"To: %s",msg->to); /* Avoid double-@ */
else if(msg->to_net.type==NET_INTERNET || msg->to_net.type==NET_QWK) {
if(strchr((char*)msg->to_net.addr,'<')!=NULL)
s=sockprintf(socket,"To: %s",(char*)msg->to_net.addr);
else
s=sockprintf(socket,"To: \"%s\" <%s>",msg->to,(char*)msg->to_net.addr);
} else {
usermailaddr(&scfg,toaddr,msg->to);
s=sockprintf(socket,"To: \"%s\" <%s>",msg->to,toaddr);
}
if(!s)
return(0);
if((p=smb_get_hfield(msg,RFC822REPLYTO,NULL))==NULL) {
if(msg->replyto_net.type==NET_INTERNET)
else if(msg->replyto!=NULL)
p=msg->replyto;
}
if(p!=NULL)
s=sockprintf(socket,"Reply-To: %s",p); /* use original RFC822 header field */
if(!s)
return(0);
if(!sockprintf(socket,"Message-ID: %s",get_msgid(&scfg,INVALID_SUB,msg)))
if(msg->reply_id!=NULL)
if(!sockprintf(socket,"In-Reply-To: %s",msg->reply_id))
return(0);
for(i=0;i<msg->total_hfields;i++) {
if(msg->hfield[i].type==RFC822HEADER) {
if(strnicmp((char*)msg->hfield_dat[i],"Content-Type:",13)==0)
content_type=msg->hfield_dat[i];
if(!sockprintf(socket,"%s",(char*)msg->hfield_dat[i]))
return(0);
/* Default MIME Content-Type for non-Internet messages */
if(msg->from_net.type!=NET_INTERNET && content_type==NULL) {
/* No content-type specified, so assume IBM code-page 437 (full ex-ASCII) */
sockprintf(socket,"Content-Type: text/plain; charset=IBM437");
sockprintf(socket,"Content-Transfer-Encoding: 8bit");
}
if(strListCount(file_list)) { /* File attachments */
mimeheaders(socket,mime_boundary);
sockprintf(socket,"");
mimeblurb(socket,mime_boundary);
sockprintf(socket,"");
mimetextpartheader(socket,mime_boundary);
if(!sockprintf(socket,"")) /* Header Terminator */
return(0);
#if 0 /* This is now handled in smb_getmsgtxt() */
for(i=0;i<msg->total_hfields;i++) { /* delivery failure notification? */
if(msg->hfield[i].type==SMTPSYSMSG || msg->hfield[i].type==SMB_COMMENT) {
if(!sockprintf(socket,"%s",(char*)msg->hfield_dat[i]))
return(0);
lines++;
}
}
#endif
while(*p && lines<maxlines) {
tp=strchr(p,'\n');
if(tp) {
if(tp-p>MAX_LINE_LEN)
tp=p+MAX_LINE_LEN;
*tp=0;
}
truncsp(p); /* Takes care of '\r' or spaces */
if(*p=='.')
i=sockprintf(socket,".%.*s",MAX_LINE_LEN,p);
else
i=sockprintf(socket,"%.*s",MAX_LINE_LEN,p);
if(!i)
break;
if(tp==NULL)
break;
p=tp+1;
/* release time-slices every x lines */
if(startup->lines_per_yield
&& !(lines%startup->lines_per_yield))
YIELD();
if(file_list!=NULL) {
for(i=0;file_list[i];i++) {
sockprintf(socket,"");
lprintf(LOG_INFO,"%04u MIME Encoding and sending %s",socket,file_list[i]);
if(!mimeattach(socket,mime_boundary,file_list[i]))
lprintf(LOG_ERR,"%04u !ERROR opening/encoding/sending %s",socket,file_list[i]);
else {
endmime(socket,mime_boundary);
if(msg->hdr.auxattr&MSG_KILLFILE)
if(remove(file_list[i])!=0)
lprintf(LOG_WARNING,"%04u !ERROR %d removing %s",socket,errno,file_list[i]);
}
sockprintf(socket,"."); /* End of text */
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
static ulong sockmsgtxt(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxlines)
{
char filepath[MAX_PATH+1];
ulong retval;
char* boundary=NULL;
unsigned i;
str_list_t file_list=NULL;
str_list_t split;
if(msg->hdr.auxattr&MSG_FILEATTACH) {
boundary = mimegetboundary();
file_list = strListInit();
/* Parse header fields */
for(i=0;i<msg->total_hfields;i++)
if(msg->hfield[i].type==FILEATTACH)
strListPush(&file_list,(char*)msg->hfield_dat[i]);
/* Parse subject (if necessary) */
if(!strListCount(file_list)) { /* filename(s) stored in subject */
split=strListSplitCopy(NULL,msg->subj," ");
if(split!=NULL) {
for(i=0;split[i];i++) {
if(msg->idx.to!=0)
SAFEPRINTF3(filepath,"%sfile/%04u.in/%s"
,scfg.data_dir,msg->idx.to,getfname(truncsp(split[i])));
else
SAFEPRINTF3(filepath,"%sfile/%04u.out/%s"
,scfg.data_dir,msg->idx.from,getfname(truncsp(split[i])));
strListPush(&file_list,filepath);
}
strListFree(&split);
}
}
}
retval = sockmimetext(socket,msg,msgtxt,maxlines,file_list,boundary);
strListFree(&file_list);
if(boundary!=NULL)
free(boundary);
return(retval);
}
static u_long resolve_ip(char *inaddr)
char* p;
char* addr;
char buf[128];
HOSTENT* host;
SAFECOPY(buf,inaddr);
addr=buf;
if(*addr=='[' && *(p=lastchar(addr))==']') { /* Support [ip_address] notation */
addr++;
*p=0;
}
if(*addr==0)
return((u_long)INADDR_NONE);
for(p=addr;*p;p++)
if(*p!='.' && !isdigit(*p))
break;
if(!(*p))
if((host=gethostbyname(inaddr))==NULL) {
lprintf(LOG_WARNING,"0000 !ERROR resolving hostname: %s",inaddr);
return((u_long)INADDR_NONE);
}
return(*((ulong*)host->h_addr_list[0]));
}
static void pop3_thread(void* arg)
{
char* p;
char str[128];
char buf[512];
char host_name[128];
char host_ip[64];
char username[LEN_ALIAS+1];
char password[LEN_PASS+1];
char challenge[256];
char digest[MD5_DIGEST_SIZE];
char* response="";
char* msgtxt;
int i;
int rd;
BOOL activity=FALSE;
long l;
long msgs,msgnum;
ulong bytes;
SOCKET socket;
HOSTENT* host;
smb_t smb;
smbmsg_t msg;
user_t user;
client_t client;
mail_t* mail;
pop3_t pop3=*(pop3_t*)arg;
SetThreadName("POP3 Thread");
thread_up(TRUE /* setuid */);
free(arg);
socket=pop3.socket;
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf(LOG_DEBUG,"%04d POP3 session thread started", socket);
if(startup->pop3_sound[0] && !(startup->options&MAIL_OPT_MUTE))
PlaySound(startup->pop3_sound, NULL, SND_ASYNC|SND_FILENAME);
SAFECOPY(host_ip,inet_ntoa(pop3.client_addr.sin_addr));
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf(LOG_INFO,"%04d POP3 connection accepted from: %s port %u"
,socket, host_ip, ntohs(pop3.client_addr.sin_port));
if(startup->options&MAIL_OPT_NO_HOST_LOOKUP)
host=NULL;
else
host=gethostbyaddr((char *)&pop3.client_addr.sin_addr
,sizeof(pop3.client_addr.sin_addr),AF_INET);
if(host!=NULL && host->h_name!=NULL)
else
strcpy(host_name,"<no name>");
if(startup->options&MAIL_OPT_DEBUG_POP3
&& !(startup->options&MAIL_OPT_NO_HOST_LOOKUP)) {
lprintf(LOG_INFO,"%04d POP3 Hostname: %s", socket, host_name);
for(i=0;host!=NULL && host->h_aliases!=NULL && host->h_aliases[i]!=NULL;i++)
lprintf(LOG_INFO,"%04d POP3 HostAlias: %s", socket, host->h_aliases[i]);
if(trashcan(&scfg,host_ip,"ip")) {
lprintf(LOG_NOTICE,"%04d !POP3 BLOCKED CLIENT IP ADDRESS: %s"
,socket, host_ip);
sockprintf(socket,"-ERR Access denied.");

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
if(trashcan(&scfg,host_name,"host")) {
lprintf(LOG_NOTICE,"%04d !POP3 BLOCKED CLIENT HOSTNAME: %s"
,socket, host_name);
sockprintf(socket,"-ERR Access denied.");

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
active_clients++, update_clients();
/* Initialize client display */
client.size=sizeof(client);
client.time=time(NULL);
SAFECOPY(client.addr,host_ip);
SAFECOPY(client.host,host_name);
client.port=ntohs(pop3.client_addr.sin_port);
client.protocol="POP3";
client.user="<unknown>";
client_on(socket,&client,FALSE /* update */);
SAFEPRINTF(str,"POP3: %s", host_ip);
do {
memset(&smb,0,sizeof(smb));
memset(&msg,0,sizeof(msg));

rswindell
committed
memset(&user,0,sizeof(user));
password[0]=0;
srand(time(NULL) ^ (DWORD)GetCurrentThreadId()); /* seed random number generator */
rand(); /* throw-away first result */
safe_snprintf(challenge,sizeof(challenge),"<%x%x%lx%lx@%.128s>"
,rand(),socket,(ulong)time(NULL),clock(),startup->host_name);
sockprintf(socket,"+OK Synchronet POP3 Server %s-%s Ready %s"
,revision,PLATFORM_DESC,challenge);
/* Requires USER command first */
for(i=3;i;i--) {
if(!sockgetrsp(socket,NULL,buf,sizeof(buf)))
break;
if(!strnicmp(buf,"USER ",5))
break;
if(!strnicmp(buf,"APOP ",5)) {
apop=TRUE;
break;
}
sockprintf(socket,"-ERR USER or APOP command expected");
if(!i || buf[0]==0) /* no USER or APOP command received */
break;
SKIP_WHITESPACE(p);
if(apop) {
if((response=strrchr(p,' '))!=NULL)
*(response++)=0;
else
response=p;
}
if(!apop) {
sockprintf(socket,"+OK");
if(!sockgetrsp(socket,"PASS ",buf,sizeof(buf))) {
sockprintf(socket,"-ERR PASS command expected");
break;
}
p=buf+5;
SKIP_WHITESPACE(p);
user.number=matchuser(&scfg,username,FALSE /*sysop_alias*/);

rswindell
committed
if(scfg.sys_misc&SM_ECHO_PW)
lprintf(LOG_WARNING,"%04d !POP3 UNKNOWN USER: %s (password: %s)"

rswindell
committed
,socket, username, password);
else
lprintf(LOG_WARNING,"%04d !POP3 UNKNOWN USER: %s"

rswindell
committed
,socket, username);
break;
}
if((i=getuserdat(&scfg, &user))!=0) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d getting data on user (%s)"
break;
}
if(user.misc&(DELETED|INACTIVE)) {
lprintf(LOG_WARNING,"%04d !POP3 DELETED or INACTIVE user #%u (%s)"
,socket, user.number, username);
if(apop) {
strlwr(user.pass); /* this is case-sensitive, so convert to lowercase */
strcat(challenge,user.pass);
MD5_calc(digest,challenge,strlen(challenge));
MD5_hex(str,digest);
if(strcmp(str,response)) {
lprintf(LOG_WARNING,"%04d !POP3 %s FAILED APOP authentication"
lprintf(LOG_DEBUG,"%04d !POP3 digest data: %s",socket,challenge);
lprintf(LOG_DEBUG,"%04d !POP3 calc digest: %s",socket,str);
lprintf(LOG_DEBUG,"%04d !POP3 resp digest: %s",socket,response);
#endif
sockprintf(socket,pop_err);
break;
}
} else if(stricmp(password,user.pass)) {

rswindell
committed
if(scfg.sys_misc&SM_ECHO_PW)
lprintf(LOG_WARNING,"%04d !POP3 FAILED Password attempt for user %s: '%s' expected '%s'"

rswindell
committed
,socket, username, password, user.pass);
else
lprintf(LOG_WARNING,"%04d !POP3 FAILED Password attempt for user %s"

rswindell
committed
,socket, username);
putuserrec(&scfg,user.number,U_COMP,LEN_COMP,host_name);
putuserrec(&scfg,user.number,U_NOTE,LEN_NOTE,host_ip);
/* Update client display */
client.user=user.alias;
client_on(socket,&client,TRUE /* update */);
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf(LOG_INFO,"%04d POP3 %s logged in %s", socket, user.alias, apop ? "via APOP":"");
SAFEPRINTF(str,"POP3: %s",user.alias);
sprintf(smb.file,"%smail",scfg.data_dir);
if(smb_islocked(&smb)) {
lprintf(LOG_WARNING,"%04d !POP3 MAIL BASE LOCKED: %s",socket,smb.last_error);
sockprintf(socket,"-ERR database locked, try again later");
break;
}
smb.retry_time=scfg.smb_retry_time;
smb.subnum=INVALID_SUB;
if((i=smb_open(&smb))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) opening %s",socket,i,smb.last_error,smb.file);
sockprintf(socket,"-ERR %d opening %s",i,smb.file);
break;
}
mail=loadmail(&smb,&msgs,user.number,MAIL_YOUR,0);
for(l=bytes=0;l<msgs;l++) {
msg.hdr.number=mail[l].number;
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
,socket, i, smb.last_error);
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
break;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
bytes+=smb_getmsgtxtlen(&msg);
if(l<msgs) {
sockprintf(socket,"-ERR message #%d: %d (%s)"
,mail[l].number,i,smb.last_error);
break;
}
sockprintf(socket,"+OK %lu messages (%lu bytes)",msgs,bytes);
while(1) { /* TRANSACTION STATE */
rd = sockreadline(socket, buf, sizeof(buf));
if(rd<0)
truncsp(buf);
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf(LOG_DEBUG,"%04d POP3 RX: %s", socket, buf);
if(!stricmp(buf, "NOOP")) {
sockprintf(socket,"+OK");
continue;
}
if(!stricmp(buf, "QUIT")) {
sockprintf(socket,"+OK");
break;
}
if(!stricmp(buf, "STAT")) {
sockprintf(socket,"+OK %lu %lu",msgs,bytes);
continue;
}
if(!stricmp(buf, "RSET")) {
if((i=smb_locksmbhdr(&smb))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) locking message base"
,socket, i, smb.last_error);
sockprintf(socket,"-ERR %d locking message base",i);
continue;
}
for(l=0;l<msgs;l++) {
msg.hdr.number=mail[l].number;
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
,socket, i, smb.last_error);
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
if((i=smb_getmsghdr(&smb,&msg))!=SMB_SUCCESS) {
smb_unlockmsghdr(&smb,&msg);
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
break;
}
msg.hdr.attr=mail[l].attr;
if((i=smb_putmsg(&smb,&msg))!=SMB_SUCCESS)
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) updating message index"
,socket, i, smb.last_error);
smb_unlockmsghdr(&smb,&msg);
smb_freemsgmem(&msg);
}
smb_unlocksmbhdr(&smb);
if(l<msgs)
sockprintf(socket,"-ERR %d messages reset (ERROR: %d)",l,i);
else
sockprintf(socket,"+OK %lu messages (%lu bytes)",msgs,bytes);
continue;
}
if(!strnicmp(buf, "LIST",4) || !strnicmp(buf,"UIDL",4)) {
p=buf+4;
SKIP_WHITESPACE(p);
if(isdigit(*p)) {
msgnum=atol(p);
if(msgnum<1 || msgnum>msgs) {
lprintf(LOG_WARNING,"%04d !POP3 INVALID message #%ld"
,socket, msgnum);
sockprintf(socket,"-ERR no such message");
continue;
}
msg.hdr.number=mail[msgnum-1].number;
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
,socket, i, smb.last_error);
sockprintf(socket,"-ERR %d getting message index",i);
break;
}
if(msg.idx.attr&MSG_DELETE) {
lprintf(LOG_WARNING,"%04d !POP3 ATTEMPT to list DELETED message"
,socket);
sockprintf(socket,"-ERR message deleted");
continue;
}
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR %d locking message header",i);
continue;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
smb_freemsgmem(&msg);
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR %d getting message header",i);
continue;
}
if(!strnicmp(buf, "LIST",4)) {
sockprintf(socket,"+OK %lu %lu",msgnum,smb_getmsgtxtlen(&msg));
} else /* UIDL */
sockprintf(socket,"+OK %lu %lu",msgnum,msg.hdr.number);
smb_freemsgmem(&msg);
continue;
}
/* List ALL messages */
sockprintf(socket,"+OK %lu messages (%lu bytes)",msgs,bytes);
for(l=0;l<msgs;l++) {
msg.hdr.number=mail[l].number;
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
,socket, i, smb.last_error);
break;
}
if(msg.idx.attr&MSG_DELETE)
continue;
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
break;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
smb_freemsgmem(&msg);
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
break;
}
if(!strnicmp(buf, "LIST",4)) {
sockprintf(socket,"%lu %lu",l+1,smb_getmsgtxtlen(&msg));
} else /* UIDL */
sockprintf(socket,"%lu %lu",l+1,msg.hdr.number);
smb_freemsgmem(&msg);
}
sockprintf(socket,".");
continue;
}
activity=TRUE;
if(!strnicmp(buf, "RETR ",5) || !strnicmp(buf,"TOP ",4)) {
SAFEPRINTF(str,"POP3: %s", user.alias);
status(str);
lines=-1;
p=buf+4;
SKIP_WHITESPACE(p);
msgnum=atol(p);
if(!strnicmp(buf,"TOP ",4)) {
SKIP_DIGIT(p);
SKIP_WHITESPACE(p);
lines=atol(p);
}
if(msgnum<1 || msgnum>msgs) {
lprintf(LOG_WARNING,"%04d !POP3 %s ATTEMPTED to retrieve an INVALID message #%ld"
,socket, user.alias, msgnum);
sockprintf(socket,"-ERR no such message");
continue;
}
msg.hdr.number=mail[msgnum-1].number;
lprintf(LOG_INFO,"%04d POP3 %s retrieving message #%ld"
,socket, user.alias, msg.hdr.number);
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
,socket, i, smb.last_error);
sockprintf(socket,"-ERR %d getting message index",i);
continue;
}
if(msg.idx.attr&MSG_DELETE) {
lprintf(LOG_WARNING,"%04d !POP3 ATTEMPT to retrieve DELETED message"
,socket);
sockprintf(socket,"-ERR message deleted");
continue;
}
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR %d locking message header",i);
continue;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR %d getting message header",i);
continue;
}
if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_ALL))==NULL) {
lprintf(LOG_ERR,"%04d !POP3 ERROR (%s) retrieving message %lu text"
,socket, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR retrieving message text");
continue;
}
sockprintf(socket,"+OK message follows");
lprintf(LOG_DEBUG,"%04d POP3 sending message text (%u bytes)"
lines_sent=sockmsgtxt(socket,&msg,msgtxt,lines);
/* if(startup->options&MAIL_OPT_DEBUG_POP3) */
if(lines!=-1 && lines_sent<lines) /* could send *more* lines */
lprintf(LOG_ERR,"%04d !POP3 ERROR sending message text (sent %ld of %ld lines)"
,socket,lines_sent,lines);
lprintf(LOG_DEBUG,"%04d POP3 message transfer complete (%lu lines)"
,socket,lines_sent);
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
if((i=smb_locksmbhdr(&smb))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) locking message base"
,socket, i, smb.last_error);
} else {
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
,socket, i, smb.last_error);
} else {
msg.hdr.attr|=MSG_READ;
msg.hdr.netattr|=MSG_SENT;
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS)
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
if((i=smb_putmsg(&smb,&msg))!=SMB_SUCCESS)
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) marking message #%lu as read"
,socket, i, smb.last_error, msg.hdr.number);
smb_unlockmsghdr(&smb,&msg);
}
smb_unlocksmbhdr(&smb);
}
smb_freemsgmem(&msg);
smb_freemsgtxt(msgtxt);
continue;
}
if(!strnicmp(buf, "DELE ",5)) {
p=buf+5;
SKIP_WHITESPACE(p);
msgnum=atol(p);
if(msgnum<1 || msgnum>msgs) {
lprintf(LOG_WARNING,"%04d !POP3 %s ATTEMPTED to delete an INVALID message #%ld"
,socket, user.alias, msgnum);
sockprintf(socket,"-ERR no such message");
continue;
}
msg.hdr.number=mail[msgnum-1].number;
lprintf(LOG_INFO,"%04d POP3 %s deleting message #%ld"
,socket, user.alias, msg.hdr.number);
if((i=smb_locksmbhdr(&smb))!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) locking message base"
,socket, i, smb.last_error);
sockprintf(socket,"-ERR %d locking message base",i);
continue;
}
if((i=smb_getmsgidx(&smb,&msg))!=SMB_SUCCESS) {
smb_unlocksmbhdr(&smb);
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message index"
,socket, i, smb.last_error);
sockprintf(socket,"-ERR %d getting message index",i);
continue;
}
if((i=smb_lockmsghdr(&smb,&msg))!=SMB_SUCCESS) {
smb_unlocksmbhdr(&smb);
lprintf(LOG_WARNING,"%04d !POP3 ERROR %d (%s) locking message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR %d locking message header",i);
continue;
}
if((i=smb_getmsghdr(&smb,&msg))!=SMB_SUCCESS) {
smb_unlocksmbhdr(&smb);
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) getting message header #%lu"
,socket, i, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR %d getting message header",i);
continue;
}
msg.hdr.attr|=MSG_DELETE;
if((i=smb_putmsg(&smb,&msg))==SMB_SUCCESS && msg.hdr.auxattr&MSG_FILEATTACH)
delfattach(&scfg,&msg);
smb_unlockmsghdr(&smb,&msg);
smb_unlocksmbhdr(&smb);
smb_freemsgmem(&msg);
if(i!=SMB_SUCCESS) {
lprintf(LOG_ERR,"%04d !POP3 ERROR %d (%s) marking message as read"
, socket, i, smb.last_error);
sockprintf(socket,"-ERR %d marking message for deletion",i);
continue;
}
sockprintf(socket,"+OK");
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf(LOG_INFO,"%04d POP3 message deleted", socket);
lprintf(LOG_WARNING,"%04d !POP3 UNSUPPORTED COMMAND from %s: '%s'"
sockprintf(socket,"-ERR UNSUPPORTED COMMAND: %s",buf);
}
if(user.number)

rswindell
committed
logoutuserdat(&scfg,&user,time(NULL),client.time);
if(activity)
lprintf(LOG_INFO,"%04d POP3 %s logged out from port %u on %s [%s]"
,socket, user.alias, ntohs(pop3.client_addr.sin_port), host_name, host_ip);
status(STATUS_WFC);
/* Free up resources here */
if(mail!=NULL)
freemail(mail);
smb_freemsgmem(&msg);
smb_close(&smb);
if(active_clients)
active_clients--, update_clients();
client_off(socket);
thread_down();
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf(LOG_DEBUG,"%04d POP3 session thread terminated (%u threads remain, %lu clients served)"
,socket, thread_count, served);
/* Must be last */
mail_close_socket(socket);
static ulong rblchk(SOCKET sock, DWORD mail_addr_n, const char* rbl_addr)
{
char name[256];
DWORD mail_addr;
HOSTENT* host;
struct in_addr dnsbl_result;
mail_addr=ntohl(mail_addr_n);
safe_snprintf(name,sizeof(name),"%ld.%ld.%ld.%ld.%.128s"
,mail_addr&0xff
,(mail_addr>>8)&0xff
,(mail_addr>>16)&0xff
,(mail_addr>>24)&0xff
,rbl_addr
);
if(startup->options&MAIL_OPT_DNSBL_DEBUG)
lprintf(LOG_DEBUG,"%04d SMTP DNSBL Query: %s",sock,name);
if((host=gethostbyname(name))==NULL)
return(0);
dnsbl_result.s_addr = *((ulong*)host->h_addr_list[0]);
lprintf(LOG_INFO,"%04d SMTP DNSBL Query: %s resolved to: %s"
,sock,name,inet_ntoa(dnsbl_result));
return(dnsbl_result.s_addr);
static ulong dns_blacklisted(SOCKET sock, IN_ADDR addr, char* host_name, char* list, char* dnsbl_ip)
{
char fname[MAX_PATH+1];
char str[256];
char* p;
char* tp;
FILE* fp;
ulong found=0;
sprintf(fname,"%sdnsbl_exempt.cfg",scfg.ctrl_dir);
if(findstr(inet_ntoa(addr),fname))
return(FALSE);
if(findstr(host_name,fname))
return(FALSE);
sprintf(fname,"%sdns_blacklist.cfg", scfg.ctrl_dir);
if((fp=fopen(fname,"r"))==NULL)
return(FALSE);
while(!feof(fp) && !found) {
if(fgets(str,sizeof(str),fp)==NULL)
break;
truncsp(str);
p=str;
SKIP_WHITESPACE(p);
if(*p==';' || *p==0) /* comment or blank line */
continue;
sprintf(list,"%.100s",p);
/* terminate */
tp = p;
FIND_WHITESPACE(tp);
*tp=0;
found = rblchk(sock, addr.s_addr, p);
}
fclose(fp);
if(found)
strcpy(dnsbl_ip, inet_ntoa(addr));
return(found);
}
static BOOL chk_email_addr(SOCKET socket, char* p, char* host_name, char* host_ip
,char* to, char* from)
{
char addr[64];
char tmp[128];
SKIP_WHITESPACE(p);
truncstr(addr,">( ");
if(!trashcan(&scfg,addr,"email"))
return(TRUE);
lprintf(LOG_NOTICE,"%04d !SMTP BLOCKED SOURCE: %s"
SAFEPRINTF(tmp,"Blocked source e-mail address: %s", addr);
spamlog(&scfg, "SMTP", "REFUSED", tmp, host_name, host_ip, to, from);
sockprintf(socket, "554 Sender not allowed.");
return(FALSE);
}
{
int file;
if(scfg.smtpmail_sem[0]==0)
return; /* do nothing */
if((file=open(scfg.smtpmail_sem,O_WRONLY|O_CREAT|O_TRUNC))!=-1)
close(file);
}
/*****************************************************************************/
/* Returns command line generated from instr with %c replacments */
/*****************************************************************************/
static char* mailcmdstr(char* instr, char* msgpath, char* lstpath, char* errpath
,char* host, char* ip, uint usernum
,char* sender, char* sender_addr, char* reverse_path, char* cmd)
{
char str[1024];
int i,j,len;
len=strlen(instr);
for(i=j=0;i<len;i++) {
if(instr[i]=='%') {
i++;
cmd[j]=0;
switch(toupper(instr[i])) {
case 'E':
strcat(cmd,errpath);
break;
case 'H':
strcat(cmd,host);
break;
case 'I':
strcat(cmd,ip);
break;
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
case 'G': /* Temp directory */
strcat(cmd,scfg.temp_dir);
break;
case 'J':
strcat(cmd,scfg.data_dir);
break;
case 'K':
strcat(cmd,scfg.ctrl_dir);
break;
case 'L':
strcat(cmd,lstpath);
break;
case 'F':
case 'M':
strcat(cmd,msgpath);
break;
case 'O': /* SysOp */
strcat(cmd,scfg.sys_op);
break;
case 'Q': /* QWK ID */
strcat(cmd,scfg.sys_id);
break;
case 'R': /* reverse path */
strcat(cmd,reverse_path);
break;
case 'S': /* sender name */
strcat(cmd,sender);
break;
case 'A': /* sender address */
strcat(cmd,sender_addr);
break;
case 'V': /* Synchronet Version */
sprintf(str,"%s%c",VERSION,REVISION);
strcat(cmd,str);
break;
case 'Z':
strcat(cmd,scfg.text_dir);
break;
case '!': /* EXEC Directory */
strcat(cmd,scfg.exec_dir);
break;
case '@': /* EXEC Directory for DOS/OS2/Win32, blank for Unix */
#ifndef __unix__
strcat(cmd,scfg.exec_dir);
#endif
break;
case '%': /* %% for percent sign */
strcat(cmd,"%");
break;
case '?': /* Platform */
#ifdef __OS2__
SAFECOPY(str,"OS2");
#else
SAFECOPY(str,PLATFORM_DESC);
#endif
strlwr(str);
strcat(cmd,str);
break;
case 'U': /* User number */
sprintf(str,"%u",usernum);
strcat(cmd,str);
break;
default: /* unknown specification */
break;
}
j=strlen(cmd);
}
else
cmd[j++]=instr[i];
}
cmd[j]=0;
return(cmd);
}
#ifdef JAVASCRIPT
static void
js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
{
char line[64];
char file[MAX_PATH+1];
char* warning;
SOCKET* sock;
if((sock=(SOCKET*)JS_GetContextPrivate(cx))==NULL)
return;
if(report==NULL) {
lprintf(LOG_ERR,"!JavaScript: %s", message);
return;
}
if(report->filename)
SAFEPRINTF(file," %s",report->filename);
else
file[0]=0;
if(report->lineno)
SAFEPRINTF(line," line %u",report->lineno);
else
line[0]=0;
if(JSREPORT_IS_WARNING(report->flags)) {
if(JSREPORT_IS_STRICT(report->flags))
warning="strict warning";
else
warning="warning";
} else
warning="";
lprintf(LOG_ERR,"%04d !JavaScript %s%s%s: %s"
,*sock, warning ,file, line, message);
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
static JSBool
js_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
uintN i=0;
int32 level=LOG_INFO;
JSString* str=NULL;
SOCKET* sock;
if((sock=(SOCKET*)JS_GetContextPrivate(cx))==NULL)
return(JS_FALSE);
if(JSVAL_IS_NUMBER(argv[i]))
JS_ValueToInt32(cx,argv[i++],&level);
for(; i<argc; i++) {
if((str=JS_ValueToString(cx, argv[i]))==NULL)
return(JS_FALSE);
lprintf(level,"%04d JavaScript: %s",*sock,JS_GetStringBytes(str));
}
if(str==NULL)
*rval = JSVAL_VOID;
else
*rval = STRING_TO_JSVAL(str);
return(JS_TRUE);
}
static JSFunctionSpec js_global_functions[] = {
{"write", js_log, 0},
{"writeln", js_log, 0},
{"print", js_log, 0},
{"log", js_log, 0},
{0}
};
static BOOL
js_mailproc(SOCKET sock, client_t* client, user_t* user
,char* cmdline
,char* msgtxt_fname, char* rcptlst_fname, char* proc_err_fname
,char* sender, char* sender_addr, char* reverse_path)
{
char* p;
char fname[MAX_PATH+1];
char path[MAX_PATH+1];
char arg[MAX_PATH+1];
BOOL success=FALSE;
JSRuntime* js_runtime=NULL;
JSContext* js_cx=NULL;
JSObject* js_glob;
JSObject* argv;
jsuint argc;
JSScript* js_script;
js_branch_t js_branch;
jsval val;
jsval rval=JSVAL_VOID;
SAFECOPY(fname,cmdline);
truncstr(fname," \t");
if(getfext(fname)==NULL) /* No extension specified, assume '.js' */
strcat(fname,".js");
SAFECOPY(path,fname);
if(getfname(path)==path) /* No path specified, assume exec_dir */
sprintf(path,"%s%s",scfg.exec_dir,fname);
do {
lprintf(LOG_DEBUG,"%04d JavaScript: Creating runtime: %lu bytes\n"
,sock, startup->js.max_bytes);
if((js_runtime = JS_NewRuntime(startup->js.max_bytes))==NULL)
break;
lprintf(LOG_DEBUG,"%04d JavaScript: Initializing context (stack: %lu bytes)\n"
,sock, startup->js.cx_stack);
if((js_cx = JS_NewContext(js_runtime, startup->js.cx_stack))==NULL)
break;
JS_SetErrorReporter(js_cx, js_ErrorReporter);
JS_SetContextPrivate(js_cx, &sock);
/* Global Object */
if((js_glob=js_CreateGlobalObject(js_cx, &scfg, NULL))==NULL)
break;
if (!JS_DefineFunctions(js_cx, js_glob, js_global_functions))
break;
/* Internal JS Object */
if(js_CreateInternalJsObject(js_cx, js_glob, &js_branch)==NULL)
break;
/* Client Object */
if(js_CreateClientObject(js_cx, js_glob, "client", client, sock)==NULL)
break;
/* System Object */
if(js_CreateSystemObject(js_cx, js_glob, &scfg, uptime, startup->host_name, SOCKLIB_DESC)==NULL)
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
break;
/* Socket Class */
if(js_CreateSocketClass(js_cx, js_glob)==NULL)
break;
/* MsgBase Class */
if(js_CreateMsgBaseClass(js_cx, js_glob, &scfg)==NULL)
break;
/* File Class */
if(js_CreateFileClass(js_cx, js_glob)==NULL)
break;
/* User class */
if(js_CreateUserClass(js_cx, js_glob, &scfg)==NULL)
break;
/* Area and "user" Objects */
if(!js_CreateUserObjects(js_cx, js_glob, &scfg, user, NULL, NULL))
break;
/* Convert command-line to argv/argc */
argv=JS_NewArrayObject(js_cx, 0, NULL);
JS_DefineProperty(js_cx, js_glob, "argv", OBJECT_TO_JSVAL(argv)
,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
p=cmdline;
FIND_WHITESPACE(p);
SKIP_WHITESPACE(p);
for(argc=0;*p;argc++) {
SAFECOPY(arg,p);
truncstr(arg," \t");
val=STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,arg));
if(!JS_SetElement(js_cx, argv, argc, &val))
break;
FIND_WHITESPACE(p);
SKIP_WHITESPACE(p);
}
JS_DefineProperty(js_cx, js_glob, "argc", INT_TO_JSVAL(argc)
,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
/* Mailproc "API" filenames */
JS_DefineProperty(js_cx, js_glob, "message_text_filename"
,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,msgtxt_fname))
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
JS_DefineProperty(js_cx, js_glob, "recipient_list_filename"
,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,rcptlst_fname))
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
JS_DefineProperty(js_cx, js_glob, "processing_error_filename"
,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,proc_err_fname))
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
JS_DefineProperty(js_cx, js_glob, "sender_name"
,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,sender))
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
JS_DefineProperty(js_cx, js_glob, "sender_address"
,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,sender_addr))
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
JS_DefineProperty(js_cx, js_glob, "reverse_path"
,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,reverse_path))
,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY);
if((js_script=JS_CompileFile(js_cx, js_glob, path))==NULL)
break;
success=JS_ExecuteScript(js_cx, js_glob, js_script, &rval);
js_EvalOnExit(js_cx, js_glob, &js_branch);
} while(0);
if(js_cx!=NULL)
JS_DestroyContext(js_cx);
if(js_runtime!=NULL)
JS_DestroyRuntime(js_runtime);
return(success);
}
#endif
static int parse_header_field(uchar* buf, smbmsg_t* msg, ushort* type)
{
char* p;
char field[128];
int len;
ushort nettype;
if(buf[0]<=' ' && *type!=UNKNOWN) { /* folded header, append to previous */
p=buf;
truncsp(p);
smb_hfield_append_str(msg,*type,"\r\n");
return smb_hfield_append_str(msg, *type, p);
}
if((p=strchr(buf,':'))==NULL)
return smb_hfield_str(msg, *type=RFC822HEADER, buf);
len=(ulong)p-(ulong)buf;
if(len>sizeof(field)-1)
len=sizeof(field)-1;
sprintf(field,"%.*s",len,buf);
truncsp(field);
p++; /* skip colon */
SKIP_WHITESPACE(p);
truncsp(p);
if(!stricmp(field, "TO"))
return smb_hfield_str(msg, *type=RFC822TO, p);
if(!stricmp(field, "REPLY-TO")) {
smb_hfield_str(msg, *type=RFC822REPLYTO, p);
if(*p=='<') {
p++;
truncstr(p,">");
}
nettype=NET_INTERNET;
smb_hfield(msg, REPLYTONETTYPE, sizeof(nettype), &nettype);
return smb_hfield_str(msg, *type=REPLYTONETADDR, p);
}
if(!stricmp(field, "FROM"))
return smb_hfield_str(msg, *type=RFC822FROM, p);
if(!stricmp(field, "ORGANIZATION"))
return smb_hfield_str(msg, *type=SENDERORG, p);
if(!stricmp(field, "DATE")) {
msg->hdr.when_written=rfc822date(p);
*type=UNKNOWN;
}
if(!stricmp(field, "MESSAGE-ID"))
return smb_hfield_str(msg, *type=RFC822MSGID, p);
if(!stricmp(field, "IN-REPLY-TO"))
return smb_hfield_str(msg, *type=RFC822REPLYID, p);
/* Fall-through */
return smb_hfield_str(msg, *type=RFC822HEADER, buf);
}
static int chk_received_hdr(SOCKET socket,const char *buf,IN_ADDR *dnsbl_result, char *dnsbl, char *dnsbl_ip)
{
char host_name[128];
IN_ADDR check_addr;
char *fromstr;
char ip[16];
char *p;
char *p2;
if(fromstr==NULL)
return(0);
strcpy(fromstr,buf);
strlwr(fromstr);
do {
p=strstr(fromstr,"from ");
if(p==NULL)
break;
p+=4;
SKIP_WHITESPACE(p);
if(*p==0)
break;
p2=host_name;
for(;*p && !isspace(*p) && p2<host_name+126;p++) {
*p2++=*p;
}
*p2=0;
p=strtok_r(fromstr,"[",&last);
if(p==NULL)
break;
p=strtok_r(NULL,"]",&last);
if(p==NULL)
break;
strncpy(ip,p,16);
ip[15]=0;
check_addr.s_addr = inet_addr(ip);
if(startup->options&MAIL_OPT_DNSBL_DEBUG)
lprintf(LOG_DEBUG,"%04d DEBUG checking %s (%s)",socket,host_name,ip);
if((dnsbl_result->s_addr=dns_blacklisted(socket,check_addr,host_name,dnsbl,dnsbl_ip))!=0)
lprintf(LOG_WARNING,"%04d !SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
,socket, dnsbl, host_name, ip, inet_ntoa(*dnsbl_result));
} while(0);
free(fromstr);
return(dnsbl_result->s_addr);
}
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
static void parse_mail_address(char* p
,char* name, size_t name_len
,char* addr, size_t addr_len)
{
char* tp;
char tmp[128];
SKIP_WHITESPACE(p);
/* Get the address */
if((tp=strchr(p,'<'))!=NULL)
tp++;
else
tp=p;
SKIP_WHITESPACE(tp);
sprintf(addr,"%.*s",addr_len,tp);
truncstr(addr,">( ");
SAFECOPY(tmp,p);
p=tmp;
/* Get the "name" (if possible) */
if((tp=strchr(p,'('))!=NULL) { /* name in parenthesis? */
p=tp+1;
tp=strchr(p,')');
} else if((tp=strchr(p,'"'))!=NULL) { /* name in quotes? */
p=tp+1;
tp=strchr(p,'"');
} else if(*p=='<') { /* address in brackets? */
p++;
tp=strchr(p,'>');
} else /* name, then address in brackets */
tp=strchr(p,'<');
if(tp) *tp=0;
sprintf(name,"%.*s",name_len,p);
truncsp(name);
}
static void smtp_thread(void* arg)
{
int i,j;
char value[INI_MAX_VALUE_LEN];
str_list_t sec_list;
char* section;
char buf[1024],*p,*tp,*cp;
char hdrfield[512];
char alias_buf[128];
char reverse_path[128];
char date[64];
char qwkid[32];
char rcpt_name[128];
char rcpt_addr[128];

rswindell
committed
char sender[128];
char sender_addr[128];
char user_name[LEN_ALIAS+1];
char user_pass[LEN_PASS+1];
char relay_list[MAX_PATH+1];
char domain_list[MAX_PATH+1];
char spam_bait[MAX_PATH+1];
char spam_block[MAX_PATH+1];
char host_name[128];
char host_ip[64];
char dnsbl_ip[64];

rswindell
committed
char* telegram_buf;
char* msgbuf;
char challenge[256];
char response[128];
char secret[64];
char md5_data[384];
char digest[MD5_DIGEST_SIZE];
char dest_host[128];
ushort dest_port;
ushort hfield_type;
ushort agent;
ulong hdr_lines=0;
ulong hdr_len=0;
ulong badcmds=0;

rswindell
committed
BOOL telegram=FALSE;
BOOL forward=FALSE;
BOOL no_forward=FALSE;
BOOL auth_login;
BOOL routed=FALSE;
BOOL dnsbl_recvhdr;
BOOL msg_handled;
uint subnum=INVALID_SUB;
char msgtxt_fname[MAX_PATH+1];
char rcptlst_fname[MAX_PATH+1];
ushort rcpt_count=0;
FILE* proc_err;
char proc_err_fname[MAX_PATH+1];
char session_id[MAX_PATH+1];
FILE* spy=NULL;
SOCKET socket;
HOSTENT* host;
int smb_error;
smb_t smb;
smbmsg_t msg;
smbmsg_t newmsg;
user_t user;
user_t relay_user;

rswindell
committed
node_t node;
client_t client;
smtp_t smtp=*(smtp_t*)arg;
SOCKADDR_IN server_addr;
IN_ADDR dnsbl_result;
BOOL* mailproc_match;
enum {
SMTP_STATE_INITIAL
,SMTP_STATE_HELO
,SMTP_STATE_DATA_HEADER
,SMTP_STATE_DATA_BODY
} state = SMTP_STATE_INITIAL;
enum {
SMTP_CMD_NONE
,SMTP_CMD_MAIL
,SMTP_CMD_SEND
,SMTP_CMD_SOML
,SMTP_CMD_SAML
} cmd = SMTP_CMD_NONE;
SetThreadName("SMTP Thread");
thread_up(TRUE /* setuid */);
free(arg);
socket=smtp.socket;
lprintf(LOG_DEBUG,"%04d SMTP RX Session thread started", socket);
if(startup->inbound_sound[0] && !(startup->options&MAIL_OPT_MUTE))
PlaySound(startup->inbound_sound, NULL, SND_ASYNC|SND_FILENAME);
addr_len=sizeof(server_addr);
if((i=getsockname(socket, (struct sockaddr *)&server_addr,&addr_len))!=0) {
lprintf(LOG_ERR,"%04d !SMTP ERROR %d (%d) getting address/port"
sockprintf(socket,sys_error);
mail_close_socket(socket);
thread_down();
if((mailproc_match=alloca(sizeof(BOOL)*mailproc_count))==NULL) {
lprintf(LOG_ERR,"%04d !SMTP ERROR allocating memory for mailproc_match", socket);
sockprintf(socket,sys_error);
mail_close_socket(socket);
thread_down();
return;
}
memset(mailproc_match,FALSE,sizeof(BOOL)*mailproc_count);
memset(&smb,0,sizeof(smb));

rswindell
committed
memset(&msg,0,sizeof(msg));
memset(&user,0,sizeof(user));
memset(&relay_user,0,sizeof(relay_user));
SAFECOPY(host_ip,inet_ntoa(smtp.client_addr.sin_addr));
lprintf(LOG_INFO,"%04d SMTP Connection accepted from: %s port %u"
, socket, host_ip, ntohs(smtp.client_addr.sin_port));
if(startup->options&MAIL_OPT_NO_HOST_LOOKUP)
host=NULL;
else
host=gethostbyaddr ((char *)&smtp.client_addr.sin_addr
,sizeof(smtp.client_addr.sin_addr),AF_INET);
if(host!=NULL && host->h_name!=NULL)
else
strcpy(host_name,"<no name>");
if(!(startup->options&MAIL_OPT_NO_HOST_LOOKUP)) {
lprintf(LOG_INFO,"%04d SMTP Hostname: %s", socket, host_name);
for(i=0;host!=NULL && host->h_aliases!=NULL && host->h_aliases[i]!=NULL;i++)
lprintf(LOG_INFO,"%04d SMTP HostAlias: %s", socket, host->h_aliases[i]);
#if 0
if(host!=NULL) {
ip=resolve_ip(host_name);
if(ip!=smtp.client_addr.sin_addr.s_addr) {
smtp.client_addr.sin_addr.s_addr=ip;
lprintf(LOG_WARNING,"%04d !SMTP DNS/IP ADDRESS MISMATCH: %s vs %s"
,socket, inet_ntoa(smtp.client_addr.sin_addr), host_ip);
sockprintf(socket,"550 DNS and IP address mismatch");
mail_close_socket(socket);
thread_down();
return;
}
}
#endif
SAFECOPY(hello_name,host_name);
sprintf(spam_bait,"%sspambait.cfg",scfg.ctrl_dir);
sprintf(spam_block,"%sspamblock.cfg",scfg.ctrl_dir);
if(trashcan(&scfg,host_ip,"ip") || findstr(host_ip,spam_block)) {
lprintf(LOG_NOTICE,"%04d !SMTP BLOCKED SERVER IP ADDRESS: %s"
,socket, host_ip);
sockprintf(socket,"550 Access denied.");

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
if(trashcan(&scfg,host_name,"host") || findstr(host_name,spam_block)) {
lprintf(LOG_NOTICE,"%04d !SMTP BLOCKED SERVER HOSTNAME: %s"
,socket, host_name);
sockprintf(socket,"550 Access denied.");

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
active_clients++, update_clients();
/* SPAM Filters (mail-abuse.org) */
dnsbl_result.s_addr = dns_blacklisted(socket,smtp.client_addr.sin_addr,host_name,dnsbl,dnsbl_ip);
if(dnsbl_result.s_addr) {
lprintf(LOG_WARNING,"%04d !SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
,socket, dnsbl, host_name, dnsbl_ip, inet_ntoa(dnsbl_result));
if(startup->options&MAIL_OPT_DNSBL_REFUSE) {
SAFEPRINTF2(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
spamlog(&scfg, "SMTP", "SESSION REFUSED", str, host_name, dnsbl_ip, NULL, NULL);
sockprintf(socket
,"550 Mail from %s refused due to listing at %s"
,dnsbl_ip, dnsbl);
mail_close_socket(socket);
lprintf(LOG_WARNING,"%04d !SMTP REFUSED SESSION from blacklisted server"
thread_down();
if(active_clients)
active_clients--, update_clients();
sprintf(smb.file,"%smail",scfg.data_dir);
if(smb_islocked(&smb)) {
lprintf(LOG_WARNING,"%04d !SMTP MAIL BASE LOCKED: %s"
,socket, smb.last_error);
sockprintf(socket,sys_unavail);
mail_close_socket(socket);
thread_down();
if(active_clients)
active_clients--, update_clients();
return;
}
srand(time(NULL) ^ (DWORD)GetCurrentThreadId()); /* seed random number generator */
rand(); /* throw-away first result */
SAFEPRINTF3(session_id,"%x%x%lx",socket,rand(),clock());
SAFEPRINTF2(rcptlst_fname,"%sSBBS_SMTP.%s.lst", scfg.temp_dir, session_id);
rcptlst=fopen(rcptlst_fname,"w+");
if(rcptlst==NULL) {
lprintf(LOG_ERR,"%04d !SMTP ERROR %d creating recipient list: %s"
,socket, errno, rcptlst_fname);
sockprintf(socket,sys_error);

rswindell
committed
mail_close_socket(socket);
if(active_clients)
active_clients--, update_clients();
if(trashcan(&scfg,host_name,"smtpspy")
|| trashcan(&scfg,host_ip,"smtpspy")) {
sprintf(str,"%ssmtpspy.txt", scfg.logs_dir);
spy=fopen(str,"a");
}
/* Initialize client display */
client.size=sizeof(client);
client.time=time(NULL);
SAFECOPY(client.addr,host_ip);
SAFECOPY(client.host,host_name);
client.port=ntohs(smtp.client_addr.sin_port);
client.protocol="SMTP";
client.user="<unknown>";
client_on(socket,&client,FALSE /* update */);
SAFEPRINTF(str,"SMTP: %s",host_ip);
sockprintf(socket,"220 %s Synchronet SMTP Server %s-%s Ready"
,startup->host_name,revision,PLATFORM_DESC);
while(1) {
rd = sockreadline(socket, buf, sizeof(buf));
if(rd<0)
truncsp(buf);
if(spy!=NULL)
fprintf(spy,"%s\n",buf);
if(relay_user.number==0 && dnsbl_result.s_addr && startup->options&MAIL_OPT_DNSBL_THROTTLE)
mswait(DNSBL_THROTTLE_VALUE);
if(state>=SMTP_STATE_DATA_HEADER) {
if(!strcmp(buf,".")) {

rswindell
committed
state=SMTP_STATE_HELO; /* RESET state machine here in case of error */

rswindell
committed
if(msgtxt==NULL) {
lprintf(LOG_ERR,"%04d !SMTP NO MESSAGE TEXT FILE POINTER?", socket);
sockprintf(socket,"554 No message text");
continue;
}
if(ftell(msgtxt)<1) {
lprintf(LOG_ERR,"%04d !SMTP INVALID MESSAGE LENGTH: %ld (%lu lines)"
, socket, ftell(msgtxt), lines);
sockprintf(socket,"554 No message text");
lprintf(LOG_INFO,"%04d SMTP End of message (body: %lu lines, %lu bytes, header: %lu lines, %lu bytes)"
, socket, lines, ftell(msgtxt)-hdr_len, hdr_lines, hdr_len);
if(telegram==TRUE) { /* Telegram */
const char* head="\1n\1h\1cInstant Message\1n from \1h\1y";
const char* tail="\1n:\r\n\1h";
rewind(msgtxt);
length=filelength(fileno(msgtxt));
p=strchr(sender_addr,'@');
if(p==NULL || resolve_ip(p+1)!=smtp.client_addr.sin_addr.s_addr)
/* Append real IP and hostname if different */
safe_snprintf(str,sizeof(str),"%s%s\r\n\1w[\1n%s\1h] (\1n%s\1h)%s"
,head,sender_addr,host_ip,host_name,tail);
else
safe_snprintf(str,sizeof(str),"%s%s%s",head,sender_addr,tail);
if((telegram_buf=(char*)malloc(length+strlen(str)+1))==NULL) {
lprintf(LOG_CRIT,"%04d !SMTP ERROR allocating %lu bytes of memory for telegram from %s"
,socket,length+strlen(str)+1,sender_addr);
sockprintf(socket, "452 Insufficient system storage");
continue;
}
strcpy(telegram_buf,str); /* can't use SAFECOPY here */
if(fread(telegram_buf+strlen(str),1,length,msgtxt)!=length) {
lprintf(LOG_ERR,"%04d !SMTP ERROR reading %lu bytes from telegram file"
,socket,length);
sockprintf(socket, "452 Insufficient system storage");
free(telegram_buf);
continue;
}
telegram_buf[length+strlen(str)]=0; /* Need ASCIIZ */
/* Send telegram to users */
sec_list=iniReadSectionList(rcptlst,NULL); /* Each section is a recipient */
for(rcpt_count=0; sec_list!=NULL
&& sec_list[rcpt_count]!=NULL
&& rcpt_count<startup->max_recipients; rcpt_count++) {
section=sec_list[rcpt_count];
SAFECOPY(rcpt_name,iniReadString(rcptlst,section ,smb_hfieldtype(RECIPIENT),"unknown",value));
usernum=iniReadInteger(rcptlst,section ,smb_hfieldtype(RECIPIENTEXT),0);
SAFECOPY(rcpt_addr,iniReadString(rcptlst,section ,smb_hfieldtype(RECIPIENTNETADDR),rcpt_name,value));
if((i=putsmsg(&scfg,usernum,telegram_buf))==0)
lprintf(LOG_INFO,"%04d SMTP Created telegram (%ld/%u bytes) from %s to %s <%s>"
,socket, length, strlen(telegram_buf), sender_addr, rcpt_name, rcpt_addr);
else
lprintf(LOG_ERR,"%04d !SMTP ERROR %d creating telegram from %s to %s <%s>"
,socket, i, sender_addr, rcpt_name, rcpt_addr);
}
iniFreeStringList(sec_list);
Loading
Loading full blame...