Newer
Older
lprintf("%04d POP3 %s deleting message #%ld"
,socket, user.alias, msg.hdr.number);
if((i=smb_getmsgidx(&smb,&msg))!=0) {
lprintf("%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))!=0) {
lprintf("%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))!=0) {
smb_unlockmsghdr(&smb,&msg);
lprintf("%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;
msg.idx.attr=msg.hdr.attr;
if((i=smb_putmsg(&smb,&msg))!=0) {
smb_unlockmsghdr(&smb,&msg);
smb_freemsgmem(&msg);
lprintf("%04d !POP3 ERROR %d (%s) marking message as read"
, socket, i, smb.last_error);
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, const 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);
}
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
static BOOL dns_blacklisted(DWORD addr, char* list)
{
char fname[MAX_PATH+1];
char str[256];
char* p;
char* tp;
FILE* fp;
BOOL found=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)-1,fp)==NULL)
break;
truncsp(str);
p=str;
while(*p && *p<=' ') p++;
if(*p==';') /* comment */
continue;
sprintf(list,"%.100s",p);
/* terminate */
tp = p;
while(*tp && *tp>' ') tp++;
*tp=0;
found = rblchk(addr, p);
}
fclose(fp);
return(found);
}
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;
ulong length;
ulong offset;
ulong badcmds=0;

rswindell
committed
BOOL telegram=FALSE;
BOOL forward=FALSE;
BOOL no_forward=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;
user_t relay_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;
}
if(dns_blacklisted(smtp.client_addr.sin_addr.s_addr,tmp)==TRUE) {
lprintf("%04d !SMTP SPAM server filtered (%s): %s [%s]"
,socket, tmp, host_name, host_ip);
sprintf(str,"Listed on %s",tmp);
spamlog(&scfg, "SMTP", str, host_name, host_ip, NULL);
sockprintf(socket
,"571 Mail from %s refused"
,host_ip);
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) {
lprintf("%04d !SMTP ERROR %d (%s) creating %s"
,socket, i, smb.last_error, 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 (%s) locking %s"
,socket, i, smb.last_error, smb.file);

rswindell
committed
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 ERROR %d ADDING MESSAGE: %s"
, socket, i, smb.last_error);

rswindell
committed
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
if((i=smb_copymsgmem(&newmsg,&msg))!=0) {
lprintf("%04d !SMTP ERROR %d (%s) copying message"
,socket, i, smb.last_error);

rswindell
committed
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 (%s) adding message header"
,socket, i, smb.last_error);

rswindell
committed
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;
forward=FALSE;
no_forward=FALSE;
if(!strnicmp(p,FORWARD,strlen(FORWARD))) {
forward=TRUE; /* force forward to user's netmail address */
p+=strlen(FORWARD);
}
if(!strnicmp(p,NO_FORWARD,strlen(NO_FORWARD))) {
no_forward=TRUE; /* do not forward to user's netmail address */
p+=strlen(NO_FORWARD);
}
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) {