Newer
Older
lprintf("%04d POP3 %s deleting message #%ld"
,socket, user.alias, msg.hdr.number);
if((i=smb_getmsgidx(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message index"
,socket, i);
sockprintf(socket,"-ERR %d getting message index",i);
continue;
}
if((i=smb_lockmsghdr(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d locking message header #%lu"
,socket, i,msg.hdr.number);
sockprintf(socket,"-ERR %d locking message header",i);
continue;
}
if((i=smb_getmsghdr(&smb,&msg))!=0) {
smb_unlockmsghdr(&smb,&msg);

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message header #%lu"
,socket, i,msg.hdr.number);
sockprintf(socket,"-ERR %d getting message header",i);
continue;
}
msg.hdr.attr|=MSG_DELETE;
msg.idx.attr=msg.hdr.attr;
if((i=smb_putmsg(&smb,&msg))!=0) {
smb_unlockmsghdr(&smb,&msg);
smb_freemsgmem(&msg);

rswindell
committed
lprintf("%04d !POP3 ERROR %d marking message as read", socket, i);
sockprintf(socket,"-ERR %d marking message for deletion",i);
continue;
}
if(msg.hdr.auxattr&MSG_FILEATTACH)
delfattach(&scfg,&msg);
smb_unlockmsghdr(&smb,&msg);
smb_freemsgmem(&msg);
sockprintf(socket,"+OK");
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf("%04d POP3 message deleted", socket);
lprintf("%04d !POP3 UNSUPPORTED COMMAND from %s: '%s'"
,socket, user.alias, buf);
sockprintf(socket,"-ERR UNSUPPORTED COMMAND: %s",buf);
}
if(user.number)

rswindell
committed
logoutuserdat(&scfg,&user,time(NULL),client.time);
if(activity)
lprintf("%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);
active_clients--;
update_clients();
client_off(socket);
thread_down();
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf("%04d POP3 session thread terminated (%u threads remain)"
,socket, thread_count);
/* Must be last */
mail_close_socket(socket);
static BOOL rblchk(DWORD mail_addr_n, char* rbl_addr)
{
char name[256];
DWORD mail_addr;
mail_addr=ntohl(mail_addr_n);
,mail_addr&0xff
,(mail_addr>>8)&0xff
,(mail_addr>>16)&0xff
,(mail_addr>>24)&0xff
,rbl_addr
);
if(gethostbyname(name)==NULL)
return(FALSE);
return(TRUE);
}
static BOOL chk_email_addr(SOCKET socket, char* p, char* host_name, char* host_ip, char* to)
{
char addr[64];
char tmp[128];
char* tp;
while(*p && *p<=' ') p++;
if(*p=='<') p++; /* Skip '<' */
tp=strchr(addr,'>');
if(tp!=NULL) *tp=0;
if(!trashcan(&scfg,addr,"email"))
return(TRUE);
lprintf("%04d !SMTP BLOCKED SOURCE: %s"
sprintf(tmp,"Blocked source e-mail address: %s", addr);
spamlog(&scfg, "SMTP", tmp, host_name, host_ip, to);
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);
}
static void smtp_thread(void* arg)
{
int i,j,x;
int rd;
char str[512];
char buf[1024],*p,*tp,*cp;
char hdrfield[512];
char alias_buf[128];
char reverse_path[128];
char date[64];
char rcpt_name[128];
char rcpt_addr[128];

rswindell
committed
char sender[128];
char sender_addr[128];
char relay_list[MAX_PATH+1];
char domain_list[MAX_PATH+1];
char host_name[128];
char host_ip[64];

rswindell
committed
char* telegram_buf;
char* msgbuf;
char dest_host[128];
ushort dest_port;
int addr_len;
ushort xlat;
uint usernum;
ulong crc;
ulong length;
ulong offset;
ulong badcmds=0;

rswindell
committed
BOOL telegram=FALSE;
uint subnum=INVALID_SUB;
char msgtxt_fname[MAX_PATH+1];
char rcptlst_fname[MAX_PATH+1];
ushort rcpt_count=0;
FILE* spy=NULL;
SOCKET socket;
HOSTENT* host;
smb_t smb;
smbmsg_t msg;
smbmsg_t newmsg;
user_t user;

rswindell
committed
node_t node;
client_t client;
smtp_t smtp=*(smtp_t*)arg;
SOCKADDR_IN server_addr;
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;
thread_up();
free(arg);
socket=smtp.socket;
lprintf("%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) {

rswindell
committed
lprintf("%04d !SMTP ERROR %d (%d) getting address/port"
sockprintf(socket,"421 System error");
mail_close_socket(socket);
thread_down();
memset(&smb,0,sizeof(smb));

rswindell
committed
memset(&msg,0,sizeof(msg));
memset(&user,0,sizeof(user));
strcpy(host_ip,inet_ntoa(smtp.client_addr.sin_addr));
lprintf("%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("%04d SMTP hostname: %s", socket, host_name);
strcpy(hello_name,host_name);
if(trashcan(&scfg,host_ip,"ip")) {
lprintf("%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")) {
lprintf("%04d !SMTP BLOCKED SERVER HOSTNAME: %s"
,socket, host_name);
sockprintf(socket,"550 Access denied.");

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
/* SPAM Filters (mail-abuse.org) */
if(startup->options&MAIL_OPT_USE_RBL
&& rblchk(smtp.client_addr.sin_addr.s_addr
,"blackholes.mail-abuse.org"

rswindell
committed
lprintf("%04d !SMTP SPAM server filtered (RBL): %s [%s]"
,socket, host_name, host_ip);
spamlog(&scfg, "SMTP", "Listed on RBL (http://mail-abuse.org/rbl)"
,"571 Mail from %s refused, see http://mail-abuse.org/rbl"

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
if(startup->options&MAIL_OPT_USE_DUL
&& rblchk(smtp.client_addr.sin_addr.s_addr
,"dialups.mail-abuse.org"

rswindell
committed
lprintf("%04d !SMTP SPAM server filtered (DUL): %s [%s]"
,socket, host_name, host_ip);
spamlog(&scfg, "SMTP", "Listed on DUL (http://mail-abuse.org/dul)"
,"571 Mail from %s refused, see http://mail-abuse.org/dul"

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
if(startup->options&MAIL_OPT_USE_RSS
&& rblchk(smtp.client_addr.sin_addr.s_addr
,"relays.mail-abuse.org"
)==TRUE) {

rswindell
committed
lprintf("%04d !SMTP SPAM server filtered (RSS): %s [%s]"
,socket, host_name, host_ip);
spamlog(&scfg, "SMTP", "Listed on RSS (http://mail-abuse.org/rss)"
,"571 Mail from %s refused, see http://mail-abuse.org/rss"

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
sprintf(rcptlst_fname,"%sSMTP%d.LST", scfg.data_dir, socket);
rcptlst=fopen(rcptlst_fname,"w+");
if(rcptlst==NULL) {

rswindell
committed
lprintf("%04d !SMTP ERROR %d creating recipient list: %s"
,socket, errno, rcptlst_fname);
sockprintf(socket,"421 System error");

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
if(trashcan(&scfg,host_name,"smtpspy")
|| trashcan(&scfg,host_ip,"smtpspy")) {
sprintf(str,"%sSMTPSPY.TXT", scfg.data_dir);
spy=fopen(str,"a");
}
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(smtp.client_addr.sin_port);
client.protocol="SMTP";
client.user="<unknown>";
client_on(socket,&client,FALSE /* update */);
sprintf(str,"SMTP: %s",host_ip);
status(str);
sockprintf(socket,"220 %s Synchronet SMTP Server for %s v%s Ready"
,scfg.sys_inetaddr,PLATFORM_DESC,MAIL_VERSION);
while(1) {
rd = sockreadline(socket, buf, sizeof(buf));
if(rd<1)
break;
truncsp(buf);
if(spy!=NULL)
fprintf(spy,"%s\n",buf);
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("%04d !SMTP NO MESSAGE TEXT FILE POINTER?", socket);
sockprintf(socket,"554 No message text");
continue;
}
if(ftell(msgtxt)<1) {
lprintf("%04d !SMTP INVALID MESSAGE LENGTH: %ld (%lu lines)"
, socket, ftell(msgtxt), lines);
sockprintf(socket,"554 No message text");
lprintf("%04d SMTP End of message (%lu lines, %lu bytes)"
, socket, lines, ftell(msgtxt));

rswindell
committed
if(telegram==TRUE) { /* Telegram */
const char* head="\1n\1h\1cInstant Message\1n from \1h\1y";
const char* tail="\1n:\r\n\1h";

rswindell
committed
length=filelength(fileno(msgtxt));
if(p==NULL || resolve_ip(p+1)!=smtp.client_addr.sin_addr.s_addr)
/* Append real IP and hostname if different */
sprintf(str,"%s%s\r\n\1w[\1n%s\1h] (\1n%s\1h)%s"
,head,sender_addr,host_ip,host_name,tail);
sprintf(str,"%s%s%s",head,sender_addr,tail);

rswindell
committed
if((telegram_buf=(char*)malloc(length+strlen(str)+1))==NULL) {
lprintf("%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");

rswindell
committed
continue;

rswindell
committed
strcpy(telegram_buf,str);
if(fread(telegram_buf+strlen(str),1,length,msgtxt)!=length) {
lprintf("%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 */

rswindell
committed
/* Send telegram to users */
rewind(rcptlst);
rcpt_count=0;
while(!feof(rcptlst) && rcpt_count<MAX_RECIPIENTS) {

rswindell
committed
if(fgets(str,sizeof(str)-1,rcptlst)==NULL)
break;
usernum=atoi(str);
if(fgets(rcpt_name,sizeof(rcpt_name)-1,rcptlst)==NULL)
break;

rswindell
committed
truncsp(rcpt_name);
if(fgets(rcpt_addr,sizeof(rcpt_addr)-1,rcptlst)==NULL)
break;

rswindell
committed
truncsp(rcpt_addr);
putsmsg(&scfg,usernum,telegram_buf);
lprintf("%04d SMTP Created telegram from %s to %s <%s>"
,socket, sender_addr, rcpt_name, rcpt_addr);

rswindell
committed
free(telegram_buf);
sockprintf(socket,SMTP_OK);
telegram=FALSE;
continue;
}
if(sender[0]==0) {
lprintf("%04d !SMTP MISSING mail header 'FROM' field", socket);
sockprintf(socket, "554 Mail header missing 'FROM' field");
subnum=INVALID_SUB;

rswindell
committed
continue;
}
nettype=NET_INTERNET;
smb_hfield(&msg, SENDER, (ushort)strlen(sender), sender);
smb_hfield(&msg, SENDERNETTYPE, sizeof(nettype), &nettype);
smb_hfield(&msg, SENDERNETADDR, (ushort)strlen(sender_addr), sender_addr);
if(msg.idx.subj==0) {
p="";
smb_hfield(&msg, SUBJECT, 0, p);
msg.idx.subj=crc16(p);
}

rswindell
committed
rewind(msgtxt);
length=filelength(fileno(msgtxt));
if(subnum!=INVALID_SUB) { /* Message Base */
if(rcpt_name[0]==0)
strcpy(rcpt_name,"All");
smb_hfield(&msg, RECIPIENT, (ushort)strlen(rcpt_name), rcpt_name);
if((msgbuf=(char*)malloc(length+1))==NULL) {
lprintf("%04d !SMTP ERROR allocating %d bytes of memory"
,socket,length+1);
sockprintf(socket, "452 Insufficient system storage");
subnum=INVALID_SUB;
continue;
}
fread(msgbuf,length,1,msgtxt);
msgbuf[length]=0; /* ASCIIZ */
smb.subnum=subnum;
if((i=savemsg(&scfg, &smb, &msg, msgbuf))!=0) {
lprintf("%04d !SMTP ERROR %d (%s) saving message"
,socket,i,smb.last_error);
sockprintf(socket, "452 ERROR %d (%s) saving message"
,i,smb.last_error);
} else {
lprintf("%04d SMTP %s posted a message on %s"
,socket, sender_addr, scfg.sub[subnum]->sname);
sockprintf(socket,SMTP_OK);
signal_smtp_sem();
}
free(msgbuf);
smb_close(&smb);
subnum=INVALID_SUB;
continue;
}
/* E-mail */

rswindell
committed
sprintf(smb.file,"%smail", scfg.data_dir);
smb.retry_time=scfg.smb_retry_time;
smb.subnum=INVALID_SUB;

rswindell
committed
if((i=smb_open(&smb))!=0) {
lprintf("%04d !SMTP ERROR %d (%s) opening %s"
,socket, i, smb.last_error, smb.file);
sockprintf(socket, "452 Insufficient system storage");
continue;
}

rswindell
committed
if(smb_fgetlength(smb.shd_fp)<1) { /* Create it if it doesn't exist */
smb.status.max_crcs=scfg.mail_maxcrcs;
smb.status.max_age=scfg.mail_maxage;
smb.status.max_msgs=MAX_SYSMAIL;
smb.status.attr=SMB_EMAIL;
if((i=smb_create(&smb))!=0) {

rswindell
committed
lprintf("%04d !SMTP ERROR %d creating %s"
,socket, i, smb.file);
sockprintf(socket, "452 Insufficient system storage");

rswindell
committed
continue;
}
}

rswindell
committed
if((i=smb_locksmbhdr(&smb))!=0) {
smb_close(&smb);
lprintf("%04d !SMTP ERROR %d locking %s"
,socket, i, smb.file);
sockprintf(socket, "452 Insufficient system storage");
continue;
}
length+=sizeof(xlat); /* +2 for translation string */

rswindell
committed
if((i=smb_open_da(&smb))!=0) {
smb_unlocksmbhdr(&smb);
smb_close(&smb);
lprintf("%04d !SMTP ERROR %d (%s) opening %s.sda"
,socket, i, smb.last_error, smb.file);
sockprintf(socket, "452 Insufficient system storage");
continue;
}

rswindell
committed
if(scfg.sys_misc&SM_FASTMAIL)
offset=smb_fallocdat(&smb,length,1);
else
offset=smb_allocdat(&smb,length,1);
smb_fseek(smb.sdt_fp,offset,SEEK_SET);
xlat=XLAT_NONE;
smb_fwrite(&xlat,2,smb.sdt_fp);
x=SDT_BLOCK_LEN-2; /* Don't read/write more than 255 */
while(!feof(msgtxt)) {
memset(buf,0,x);
j=fread(buf,1,x,msgtxt);
if(j<1)
break;
if(j>1 && (j!=x || feof(msgtxt)) && buf[j-1]=='\n' && buf[j-2]=='\r')

rswindell
committed
buf[j-1]=buf[j-2]=0;

rswindell
committed
for(i=0;i<j;i++)
crc=ucrc32(buf[i],crc);

rswindell
committed
smb_fwrite(buf,j,smb.sdt_fp);
x=SDT_BLOCK_LEN;
}
smb_fflush(smb.sdt_fp);
crc=~crc;

rswindell
committed
if(scfg.mail_maxcrcs) {
i=smb_addcrc(&smb,crc);
if(i) {
smb_freemsgdat(&smb,offset,length,1);
smb_unlocksmbhdr(&smb);
smb_close_da(&smb);

rswindell
committed
smb_close(&smb);
lprintf("%04d !SMTP DUPLICATE MESSAGE", socket);
sockprintf(socket, "554 Duplicate Message");
continue;
}
}

rswindell
committed
msg.hdr.offset=offset;

rswindell
committed
smb_dfield(&msg,TEXT_BODY,length);

rswindell
committed
smb_unlocksmbhdr(&smb);
rewind(rcptlst);
rcpt_count=0;
while(!feof(rcptlst) && rcpt_count<MAX_RECIPIENTS) {

rswindell
committed
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
if((i=smb_copymsgmem(&newmsg,&msg))!=0) {
lprintf("%04d !SMTP ERROR %d copying message"
,socket, i);
break;
}
if(fgets(str,sizeof(str)-1,rcptlst)==NULL)
break;
usernum=atoi(str);
fgets(rcpt_name,sizeof(rcpt_name)-1,rcptlst);
if(fgets(rcpt_addr,sizeof(rcpt_addr)-1,rcptlst)==NULL)
break;
truncsp(rcpt_name);
truncsp(rcpt_addr);
snprintf(hdrfield,sizeof(hdrfield),
"Received: from %s (%s [%s])\r\n"
" by %s [%s] (Synchronet Mail Server for %s v%s) with %s\r\n"
" for %s; %s"
,host_name,hello_name,host_ip
,scfg.sys_inetaddr,inet_ntoa(server_addr.sin_addr)
,PLATFORM_DESC,MAIL_VERSION
,esmtp ? "ESMTP" : "SMTP"
,rcpt_name,msgdate(msg.hdr.when_imported,date));

rswindell
committed
smb_hfield(&newmsg, RFC822HEADER, (ushort)strlen(hdrfield), hdrfield);
smb_hfield(&newmsg, RECIPIENT, (ushort)strlen(rcpt_name), rcpt_name);
if(rcpt_addr[0]=='#') { /* Local destination */
newmsg.idx.to=atoi(rcpt_addr+1);
smb_hfield(&newmsg, RECIPIENTEXT
,(ushort)strlen(rcpt_addr+1), rcpt_addr+1);
} else {
newmsg.idx.to=0;
nettype=NET_INTERNET;
smb_hfield(&newmsg, RECIPIENTNETTYPE, nettype, &nettype);
smb_hfield(&newmsg, RECIPIENTNETADDR
,(ushort)strlen(rcpt_addr), rcpt_addr);
}

rswindell
committed
i=smb_addmsghdr(&smb,&newmsg,SMB_SELFPACK);
smb_freemsgmem(&newmsg);
if(i!=0) {
lprintf("%04d !SMTP ERROR %d adding message header"
,socket, i);
break;

rswindell
committed
lprintf("%04d SMTP Created message #%ld from %s to %s <%s>"
,socket, newmsg.hdr.number, sender, rcpt_name, rcpt_addr);
if(usernum) {
sprintf(str,"\7\1n\1hOn %.24s\r\n\1m%s \1n\1msent you e-mail from: "
"\1h%s\1n\r\n"
,timestr(&scfg,(time_t*)&newmsg.hdr.when_imported.time,tmp)

rswindell
committed
,sender,sender_addr);
if(!newmsg.idx.to) { /* Forwarding */
strcat(str,"\1mand it was automatically forwaded to: \1h");
strcat(str,user.netmail);
strcat(str,"\1n\r\n");
}
putsmsg(&scfg, usernum, str);
rcpt_count++;
if(rcpt_count<1) {
smb_freemsgdat(&smb,offset,length,0);

rswindell
committed
sockprintf(socket, "452 Insufficient system storage");
}
else {
if(rcpt_count>1)
smb_incdat(&smb,offset,length,(ushort)(rcpt_count-1));
sockprintf(socket,SMTP_OK);
signal_smtp_sem();
}
smb_close_da(&smb);
smb_close(&smb);
continue;
}
if(buf[0]==0 && state==SMTP_STATE_DATA_HEADER) {
state=SMTP_STATE_DATA_BODY; /* Null line separates header and body */
continue;
}
if(state==SMTP_STATE_DATA_BODY) {
p=buf;
if(*p=='.') p++; /* Transparency (RFC821 4.5.2) */
if(msgtxt!=NULL)
fprintf(msgtxt, "%s\r\n", p);
lines++;
if(!(lines%LINES_PER_YIELD)) /* release time-slices every x lines */
mswait(1);
continue;
}
/* RFC822 Header parsing */
if(startup->options&MAIL_OPT_DEBUG_RX_HEADER)
lprintf("%04d SMTP %s",socket, buf);
if(!strnicmp(buf, "SUBJECT:",8)) {
p=buf+8;
while(*p && *p<=' ') p++;
lprintf("%04d !SMTP BLOCKED SUBJECT (%s) from: %s"
sprintf(tmp,"Blocked subject (%s) from: %s"
spamlog(&scfg, "SMTP", tmp, host_name, host_ip, rcpt_addr);
sockprintf(socket, "554 Subject not allowed.");
break;
}
smb_hfield(&msg, SUBJECT, (ushort)strlen(p), p);
strlwr(p);
msg.idx.subj=crc16(p);
continue;
}
if(!strnicmp(buf, "TO:",3)) {
p=buf+3;
while(*p && *p<=' ') p++;
if(*p=='<') {
p++;
tp=strrchr(p,'>');
if(tp) *tp=0;
smb_hfield(&msg, RFC822TO, (ushort)strlen(p), p);
continue;
}
if(!strnicmp(buf, "REPLY-TO:",9)) {
p=buf+9;
while(*p && *p<=' ') p++;
if(*p=='<') {
p++;
tp=strchr(p,'>');
if(tp) *tp=0;
}
nettype=NET_INTERNET;
smb_hfield(&msg, REPLYTONETTYPE, nettype, &nettype);
smb_hfield(&msg, REPLYTONETADDR, (ushort)strlen(p), p);
continue;
}
if(!chk_email_addr(socket,buf+5,host_name,host_ip,rcpt_addr))
p=strchr(buf+5,'<');
if(p) {
p++;
tp=strchr(p,'>');
if(tp) *tp=0;
} else {
p=buf+5;
while(*p && *p<=' ') p++;
}
p=buf+5;
while(*p && *p<=' ') p++;
if(*p=='"') {
p++;
tp=strchr(p,'"');
} else if(*p=='<') {
p++;
tp=strchr(p,'>');
} else
tp=strchr(p,'<');
if(tp) *tp=0;
truncsp(p);
continue;
}
if(!strnicmp(buf, "DATE:",5)) {
p=buf+5;
msg.hdr.when_written=rfc822date(p);
continue;
}
if(!strnicmp(buf, "MESSAGE-ID:",11)) {
p=buf+11;
while(*p && *p<=' ') p++;
smb_hfield(&msg, RFC822MSGID, (ushort)strlen(p), p);
continue;
}
if(!strnicmp(buf, "IN-REPLY-TO:",12)) {
p=buf+12;
while(*p && *p<=' ') p++;
smb_hfield(&msg, RFC822REPLYID, (ushort)strlen(p), p);
continue;
}
/* Fall-through */
smb_hfield(&msg, RFC822HEADER, (ushort)strlen(buf), buf);
continue;
}
lprintf("%04d SMTP RX: %s", socket, buf);
if(!strnicmp(buf,"HELO",4)) {
p=buf+4;
while(*p && *p<=' ') p++;
sockprintf(socket,"250 %s",scfg.sys_inetaddr);
esmtp=FALSE;
state=SMTP_STATE_HELO;

rswindell
committed
telegram=FALSE;
subnum=INVALID_SUB;
continue;
}
if(!strnicmp(buf,"EHLO",4)) {
p=buf+4;
while(*p && *p<=' ') p++;
sockprintf(socket,"250 %s",scfg.sys_inetaddr);
esmtp=TRUE;
state=SMTP_STATE_HELO;

rswindell
committed
telegram=FALSE;
subnum=INVALID_SUB;
continue;
}
if(!stricmp(buf,"QUIT")) {
sockprintf(socket,"221 %s Service closing transmission channel",scfg.sys_inetaddr);
break;
}
if(!stricmp(buf,"NOOP")) {
sockprintf(socket, SMTP_OK);
badcmds=0;
continue;
}
if(state<SMTP_STATE_HELO) {
/* RFC 821 4.1.1 "The first command in a session must be the HELO command." */
lprintf("%04d !SMTP MISSING 'HELO' command",socket);
sockprintf(socket, SMTP_BADSEQ);
continue;
}
if(!stricmp(buf,"TURN")) {
sockprintf(socket,"502 command not supported");
badcmds=0;
continue;
}
if(!stricmp(buf,"RSET")) {
smb_freemsgmem(&msg);
memset(&msg,0,sizeof(smbmsg_t)); /* Initialize message header */
reverse_path[0]=0;
state=SMTP_STATE_HELO;

rswindell
committed
telegram=FALSE;
subnum=INVALID_SUB;
/* reset recipient list */
rewind(rcptlst);
chsize(fileno(rcptlst),0);
rcpt_count=0;
sockprintf(socket,SMTP_OK);
badcmds=0;
if(!strnicmp(buf,"MAIL FROM:",10)
|| !strnicmp(buf,"SEND FROM:",10) /* Send a Message (Telegram) to a local ONLINE user */
|| !strnicmp(buf,"SOML FROM:",10) /* Send OR Mail a Message to a local user */
|| !strnicmp(buf,"SAML FROM:",10) /* Send AND Mail a Message to a local user */
) {
if(!chk_email_addr(socket,p,host_name,host_ip,NULL))
/* Update client display */
client.user=reverse_path;
client_on(socket,&client,TRUE /* update */);
/* Setup state */
if(!strnicmp(buf,"MAIL FROM:",10))
cmd=SMTP_CMD_MAIL;
else if(!strnicmp(buf,"SEND FROM:",10))
cmd=SMTP_CMD_SEND;
else if(!strnicmp(buf,"SOML FROM:",10))
cmd=SMTP_CMD_SOML;
else if(!strnicmp(buf,"SAML FROM:",10))
cmd=SMTP_CMD_SAML;
/* reset recipient list */
rewind(rcptlst);
chsize(fileno(rcptlst),0);
rcpt_count=0;
/* Initialize message header */
memset(&msg,0,sizeof(smbmsg_t));
msg.hdr.version=smb_ver();
msg.hdr.when_imported.time=time(NULL);
msg.hdr.when_imported.zone=scfg.sys_timezone;

rswindell
committed
sockprintf(socket,SMTP_OK);
badcmds=0;

rswindell
committed
continue;
}
#if 0 /* No one uses this command */
if(!strnicmp(buf,"VRFY",4)) {
p=buf+4;
while(*p && *p<=' ') p++;
if(*p==0) {
sockprintf(socket,"550 No user specified.");
continue;
}
#endif
/* Add to Recipient list */
if(!strnicmp(buf,"RCPT TO:",8)) {
lprintf("%04d !SMTP MISSING 'MAIL' command",socket);
sockprintf(socket, SMTP_BADSEQ);
continue;
}

rswindell
committed
if(spy==NULL && trashcan(&scfg,reverse_path,"smtpspy")) {
sprintf(str,"%sSMTPSPY.TXT", scfg.data_dir);
spy=fopen(str,"a");
}
if(*p=='<') p++; /* Skip '<' */
tp=strchr(str,'>'); /* Truncate '>' */
if(tp!=NULL) *tp=0;
rcpt_name[0]=0;
/* Check recipient counter */
if(rcpt_count>=MAX_RECIPIENTS) {
lprintf("%04d !SMTP MAXIMUM RECIPIENTS (%d) REACHED"
,socket, MAX_RECIPIENTS);
sprintf(tmp,"Maximum recipient count (%d) from: %s"
,MAX_RECIPIENTS, reverse_path);
spamlog(&scfg, "SMTP", tmp, host_name, host_ip, rcpt_addr);
sockprintf(socket, "552 Too many recipients");
continue;
}
/* Check for blocked recipients */
if(trashcan(&scfg,rcpt_addr,"email")) {
lprintf("%04d !SMTP BLOCKED RECIPIENT (%s) from: %s"
,socket, rcpt_addr, reverse_path);
sprintf(str,"Blocked recipient e-mail address from: %s"
,reverse_path);
spamlog(&scfg, "SMTP", str, host_name, host_ip, rcpt_addr);
sockprintf(socket, "550 Unknown User:%s", buf+8);
continue;
}
/* Check for full address aliases */
p=alias(&scfg,p,alias_buf);
if(p==alias_buf)
lprintf("%04d SMTP ADDRESS ALIAS: %s",socket,p);
tp=strrchr(p,'@');
if(cmd==SMTP_CMD_MAIL && tp!=NULL) {
dest_port=server_addr.sin_port;
cp=strrchr(dest_host,':');
if(cp!=NULL) {
*cp=0;
dest_port=atoi(cp+1);
}
sprintf(domain_list,"%sdomains.cfg",scfg.ctrl_dir);
if((stricmp(dest_host,scfg.sys_inetaddr)!=0
&& resolve_ip(dest_host)!=server_addr.sin_addr.s_addr
&& findstr(&scfg,dest_host,domain_list)==FALSE)
|| dest_port!=server_addr.sin_port) {
sprintf(relay_list,"%srelay.cfg",scfg.ctrl_dir);
if(p!=alias_buf /* forced relay by alias */ &&
!findstr(&scfg,host_name,relay_list) &&
!findstr(&scfg,host_ip,relay_list)) {
lprintf("%04d !SMTP ILLEGAL RELAY ATTEMPT from %s [%s] to %s"
,socket, reverse_path, host_ip, p);
sprintf(tmp,"Relay attempt from: %s to: %s"
spamlog(&scfg, "SMTP", tmp, host_name, host_ip, rcpt_addr);
sockprintf(socket, "550 Relay not allowed.");
continue;
}
lprintf("%04d SMTP Relaying to external mail service: %s"
,socket, tp+1);
fprintf(rcptlst,"0\n%.*s\n%.*s\n"
sockprintf(socket,SMTP_OK);
rcpt_count++;
while(*p && !isalnum(*p)) p++; /* Skip '<' or '"' */
tp=strrchr(p,'"');
if(tp!=NULL) *tp=0; /* truncate at '"' */
p=alias(&scfg,p,name_alias_buf);
if(p==name_alias_buf)
lprintf("%04d SMTP NAME ALIAS: %s",socket,p);
if(!strnicmp(p,"sub:",4)) { /* Post on a sub-board */
p+=4;
for(i=0;i<scfg.total_subs;i++)
if(!stricmp(p,scfg.sub[i]->code))
break;
if(i>=scfg.total_subs) {
lprintf("%04d !SMTP UNKNOWN SUB-BOARD: %s", socket, p);
sockprintf(socket, "550 Unknown sub-board: %s", p);
continue;
}
subnum=i;
sockprintf(socket,SMTP_OK);
state=SMTP_STATE_RCPT_TO;