Newer
Older
if(msg.idx.attr&MSG_DELETE) {
lprintf("%04d !POP3 ATTEMPT to retrieve DELETED message"
,socket);
sockprintf(socket,"-ERR message deleted");
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;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
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;
}
if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_TAILS))==NULL) {
smb_freemsgmem(&msg);
lprintf("%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("%04d POP3 sending message text (%u bytes)"
,socket,strlen(msgtxt));
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("%04d !POP3 ERROR sending message text (sent %ld of %ld lines)"
,socket,lines_sent,lines);
lprintf("%04d POP3 message transfer complete (%lu lines)"
,socket,lines_sent);
msg.hdr.attr|=MSG_READ;
msg.idx.attr=msg.hdr.attr;
msg.hdr.netattr|=MSG_SENT;
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);
if((i=smb_putmsg(&smb,&msg))!=0)
lprintf("%04d !POP3 ERROR %d (%s) marking message #%lu as read"
,socket, i, smb.last_error, msg.hdr.number);
smb_unlockmsghdr(&smb,&msg);
}
smb_freemsgmem(&msg);
smb_freemsgtxt(msgtxt);
continue;
}
if(!strnicmp(buf, "DELE ",5)) {
p=buf+5;
while(*p && *p<=' ') p++;
msgnum=atol(p);
if(msgnum<1 || msgnum>msgs) {
lprintf("%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("%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 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);
,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("%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("%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 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);
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
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(sock, addr.s_addr, p);
}
fclose(fp);
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];
while(*p && *p<=' ') p++;
if(*p=='<') p++; /* Skip '<' */
truncstr(addr,">( ");
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", "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);
}
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;
IN_ADDR dnsbl_result;
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(TRUE /* setuid */);
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));
SAFECOPY(host_ip,inet_ntoa(smtp.client_addr.sin_addr));
if(trashcan(&scfg,host_ip,"ip-silent")) {
mail_close_socket(socket);
thread_down();
return;
}
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);
SAFECOPY(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;
}
active_clients++,update_clients();
/* SPAM Filters (mail-abuse.org) */
dnsbl_result.s_addr = dns_blacklisted(socket,smtp.client_addr.sin_addr,host_name,dnsbl);
if(dnsbl_result.s_addr) {
lprintf("%04d !SMTP BLACKLISTED SERVER on %s: %s [%s] = %s"
,socket, dnsbl, host_name, host_ip, inet_ntoa(dnsbl_result));
if(startup->options&MAIL_OPT_DNSBL_REFUSE) {
sprintf(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
spamlog(&scfg, "SMTP", "SESSION REFUSED", str, host_name, host_ip, NULL, NULL);
sockprintf(socket
,"550 Mail from %s refused due to listing at %s"
,host_ip, dnsbl);
mail_close_socket(socket);
lprintf("%04d !SMTP REFUSED SESSION from blacklisted server"
thread_down();
active_clients--,update_clients();
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);
active_clients--,update_clients();
if(trashcan(&scfg,host_name,"smtpspy")
|| trashcan(&scfg,host_ip,"smtpspy")) {
sprintf(str,"%sSMTPSPY.TXT", scfg.data_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 */);
sprintf(str,"SMTP: %s",host_ip);
status(str);
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<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(dnsbl_result.s_addr) {
if(startup->options&MAIL_OPT_DNSBL_IGNORE) {
lprintf("%04d !SMTP IGNORED MAIL from blacklisted server"
sprintf(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
spamlog(&scfg, "SMTP", "IGNORED", str, host_name, host_ip, rcpt_addr, reverse_path);
/* pretend we received it */
sockprintf(socket,ok_rsp);
/* tag message as spam (should this be X-DNSBL?) */
if(startup->dnsbl_hdr[0]) {
sprintf(str,"%s: %s is listed on %s as %s"
,startup->dnsbl_hdr, host_ip
,dnsbl, inet_ntoa(dnsbl_result));
smb_hfield(&msg,RFC822HEADER,strlen(str),str);
lprintf("%04d !SMTP TAGGED MAIL HEADER from blacklisted server with: %s"
,socket, startup->dnsbl_hdr);
}
if(startup->dnsbl_hdr[0] || startup->dnsbl_tag[0]) {
sprintf(str,"Listed on %s as %s", dnsbl, inet_ntoa(dnsbl_result));
spamlog(&scfg, "SMTP", "TAGGED", str, host_name, host_ip, rcpt_addr, reverse_path);
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;
strcpy(telegram_buf,str); /* can't use SAFECOPY here */

rswindell
committed
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);
while(!feof(rcptlst) && rcpt_count<startup->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 (%ld/%u bytes) from %s to %s <%s>"
,socket, length, strlen(telegram_buf), sender_addr, rcpt_name, rcpt_addr);

rswindell
committed
free(telegram_buf);
sockprintf(socket,ok_rsp);

rswindell
committed
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, SMTPREVERSEPATH, (ushort)strlen(reverse_path), reverse_path);

rswindell
committed
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=subject_crc(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,ok_rsp);
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<startup->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 %s-%s) with %s\r\n"

rswindell
committed
" for %s; %s"
,host_name,hello_name,host_ip
,startup->host_name,inet_ntoa(server_addr.sin_addr)
,revision,PLATFORM_DESC

rswindell
committed
,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, sizeof(nettype), &nettype);

rswindell
committed
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,ok_rsp);
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);
/* release time-slices every x lines */
if(startup->lines_per_yield &&
!(lines%startup->lines_per_yield))
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", "REFUSED", tmp, host_name, host_ip, rcpt_addr, reverse_path);
sockprintf(socket, "554 Subject not allowed.");
break;
}
if(dnsbl_result.s_addr && startup->dnsbl_tag[0]
&& !(startup->options&MAIL_OPT_DNSBL_IGNORE)) {
sprintf(str,"%.*s: %.*s"
,(int)sizeof(str)/2, startup->dnsbl_tag
,(int)sizeof(str)/2, p);
lprintf("%04d !SMTP TAGGED MAIL SUBJECT from blacklisted server with: %s"
,socket, startup->dnsbl_tag);
smb_hfield(&msg, SUBJECT, (ushort)strlen(p), p);
msg.idx.subj=subject_crc(p);
continue;
}
if(!strnicmp(buf, "TO:",3)) {
p=buf+3;
while(*p && *p<=' ') p++;
truncsp(p);
smb_hfield(&msg, RFC822TO, (ushort)strlen(p), p);
truncstr(p,">");
}
continue;
}
if(!strnicmp(buf, "REPLY-TO:",9)) {
p=buf+9;
while(*p && *p<=' ') p++;
truncsp(p);
smb_hfield(&msg, RFC822REPLYTO, (ushort)strlen(p), p);
truncstr(p,">");
smb_hfield(&msg, REPLYTONETTYPE, sizeof(nettype), &nettype);
smb_hfield(&msg, REPLYTONETADDR, (ushort)strlen(p), p);
continue;
}
if(!chk_email_addr(socket,buf+5,host_name,host_ip,rcpt_addr,reverse_path))
p=buf+5;
while(*p && *p<=' ') p++;
truncsp(p);
smb_hfield(&msg, RFC822FROM, (ushort)strlen(p), p);
/* Get the sender's address */
if((p=strchr(buf+5,'<'))!=NULL)
else
while(*p && *p<=' ') p++;
SAFECOPY(sender_addr,p);
truncstr(sender_addr,">( ");
/* Get the sender's "name" (if possible) */
p=buf+5;
while(*p && *p<=' ') p++;
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;
} else if(*p=='<') { /* address in brackets? */
} else /* name, then address in brackets */
tp=strchr(p,'<');
if(tp) *tp=0;
truncsp(p);
if(!strnicmp(buf, "ORGANIZATION:",13)) {
p=buf+13;
while(*p && *p<=' ') p++;
smb_hfield(&msg, SENDERORG, (ushort)strlen(p), 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",startup->host_name);
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",startup->host_name);
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",startup->host_name);
break;
}
if(!stricmp(buf,"NOOP")) {
sockprintf(socket, ok_rsp);
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, badseq_rsp);
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,ok_rsp);
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,NULL))
/* Update client display */
client.user=reverse_path;
client_on(socket,&client,TRUE /* update */);