Newer
Older
/* convert "user.name" to "user name" */
sprintf(rcpt_name,"%.*s",sizeof(rcpt_name)-1,p);
for(tp=rcpt_name;*tp;tp++)
if(*tp=='.') *tp=' ';
if(!stricmp(rcpt_name,scfg.sys_op))
usernum=1; /* RX by "sysop.alias" */
if(!usernum) /* RX by "real name" */
usernum=userdatdupe(&scfg, 0, U_NAME, LEN_NAME, p, FALSE);
if(!usernum) /* RX by "real.name" */
usernum=userdatdupe(&scfg, 0, U_NAME, LEN_NAME, rcpt_name, FALSE);
lprintf("%04d !SMTP UNKNOWN USER:%s", socket, buf+8);
sockprintf(socket, "550 Unknown User:%s", buf+8);
continue;
}
user.number=usernum;
if((i=getuserdat(&scfg, &user))!=0) {

rswindell
committed
lprintf("%04d !SMTP ERROR %d getting data on user #%u (%s)"
sockprintf(socket, "550 Unknown User:%s", buf+8);
continue;
}
if(user.misc&(DELETED|INACTIVE)) {

rswindell
committed
lprintf("%04d !SMTP DELETED or INACTIVE user #%u (%s)"
sockprintf(socket, "550 Unknown User:%s", buf+8);
if(cmd==SMTP_CMD_SEND) { /* Check if user online */

rswindell
committed
for(i=0;i<scfg.sys_nodes;i++) {
getnodedat(&scfg, i+1, &node, 0);
if(node.status==NODE_INUSE && node.useron==user.number
&& !(node.misc&NODE_POFF))
break;
}
if(i>=scfg.sys_nodes) {
lprintf("%04d !Attempt to send telegram to unavailable user #%u (%s)"
,socket, user.number, user.alias);
sockprintf(socket,"450 User unavailable");
continue;
}
}

rswindell
committed
if(useron.etoday>=cfg.level_emailperday[useron.level]
&& !(useron.rest&FLAG('Q'))) {
bputs(text[TooManyEmailsToday]);
continue;
}

rswindell
committed
} else
telegram=TRUE;
fprintf(rcptlst,"%u\n%.*s\n"
,user.number,(int)sizeof(rcpt_name)-1,rcpt_addr);
/* Forward to Internet */
tp=strrchr(user.netmail,'@');

rswindell
committed
if(!telegram
&& scfg.sys_misc&SM_FWDTONET
&& user.misc&NETMAIL
&& tp && strchr(tp,'.') && !strchr(tp,'/')
&& !strstr(tp,scfg.sys_inetaddr)) {
lprintf("%04d SMTP Forwarding to: %s"
,socket, user.netmail);
fprintf(rcptlst,"%s\n",user.netmail);
sockprintf(socket,"251 User not local; will forward to %s", user.netmail);
} else { /* Local (no-forward) */
fprintf(rcptlst,"#%u\n",usernum);
sockprintf(socket,SMTP_OK);
}
continue;
}
if(!strnicmp(buf,"DATA",4)) {
lprintf("%04d !SMTP MISSING 'RCPT TO' command", socket);
sockprintf(socket, SMTP_BADSEQ);
continue;
}
if(msgtxt!=NULL)
fclose(msgtxt);
sprintf(msgtxt_fname,"%sSMTP%d.RX", scfg.data_dir, socket);
if((msgtxt=fopen(msgtxt_fname,"w+b"))==NULL) {
,socket, errno, msgtxt_fname);
sockprintf(socket, "452 Insufficient system storage");
continue;
}

rswindell
committed
/* These vars are potentially over-written by parsing an RFC822 header */
/* get sender_addr */
p=strchr(reverse_path,'<');
if(p==NULL)
p=reverse_path;
else
p++;
strcpy(sender_addr,p);
p=strchr(sender_addr,'>');
if(p!=NULL)
*p=0;
/* get sender */
strcpy(sender,sender_addr);
p=strchr(sender,'@');
if(p!=NULL)
*p=0;
else
sender[0]=0;
sockprintf(socket, "354 send the mail data, end with <CRLF>.<CRLF>");

rswindell
committed
if(telegram)
state=SMTP_STATE_DATA_BODY; /* No RFC headers in Telegrams */
else
state=SMTP_STATE_DATA_HEADER;
continue;
}
sockprintf(socket,"500 Syntax error");
lprintf("%04d !SMTP UNSUPPORTED COMMAND: '%s'", socket, buf);
}
/* Free up resources here */

rswindell
committed
mail_close_socket(socket);
smb_freemsgmem(&msg);
if(msgtxt!=NULL) {
fclose(msgtxt);
if(!(startup->options&MAIL_OPT_DEBUG_RX_BODY))
unlink(msgtxt_fname);
}
if(rcptlst!=NULL) {
fclose(rcptlst);
unlink(rcptlst_fname);
}
if(spy!=NULL)
fclose(spy);
status(STATUS_WFC);
lprintf("%04d SMTP RX Session thread terminated", socket);
active_clients--;
update_clients();
client_off(socket);
thread_down();
}
BOOL bounce(smb_t* smb, smbmsg_t* msg, char* err, BOOL immediate)
{
char str[128],full_err[512];
int i;
ushort agent=AGENT_PROCESS;
smbmsg_t newmsg;
if((i=smb_lockmsghdr(smb,msg))!=0) {
lprintf("0000 !BOUNCE ERROR %d locking message header #%lu"
,i,msg->hdr.number);
return(FALSE);
}
msg->hdr.delivery_attempts++;
if((i=smb_putmsg(smb,msg))!=0) {
lprintf("0000 !BOUNCE ERROR %d incrementing delivery attempt counter",i);
smb_unlockmsghdr(smb,msg);
return(FALSE);
}
lprintf("0000 !Delivery attempt #%u FAILED for message #%lu from %s to %s"
,msg->hdr.delivery_attempts, msg->hdr.number
,msg->from, msg->to_net.addr);
if(!immediate && msg->hdr.delivery_attempts<startup->max_delivery_attempts) {
smb_unlockmsghdr(smb,msg);
return(TRUE);
}
lprintf("0000 !Bouncing message back to %s", msg->from);
newmsg=*msg;
/* Mark original message as deleted */
msg->hdr.attr|=MSG_DELETE;
msg->idx.attr=msg->hdr.attr;
if((i=smb_putmsg(smb,msg))!=0) {
lprintf("0000 !BOUNCE ERROR %d deleting message",i);
smb_unlockmsghdr(smb,msg);
return(FALSE);
}
smb_unlockmsghdr(smb,msg);
newmsg.hfield=NULL;
newmsg.hfield_dat=NULL;
newmsg.total_hfields=0;
newmsg.idx.to=newmsg.idx.from;
newmsg.idx.from=0;
newmsg.hdr.delivery_attempts=0;
smb_hfield(&newmsg, RECIPIENT, (ushort)strlen(newmsg.from), newmsg.from);
if(newmsg.idx.to) {
sprintf(str,"%u",newmsg.idx.to);
smb_hfield(&newmsg, RECIPIENTEXT, (ushort)strlen(str), str);
}
smb_hfield(&newmsg, RECIPIENTAGENT, sizeof(ushort), &newmsg.from_agent);
smb_hfield(&newmsg, RECIPIENTNETTYPE, sizeof(newmsg.from_net.type), &newmsg.from_net.type);
if(newmsg.from_net.type)
smb_hfield(&newmsg, RECIPIENTNETADDR, (ushort)strlen(newmsg.from_net.addr)
,newmsg.from_net.addr);
strcpy(str,"Mail Delivery Subsystem");
smb_hfield(&newmsg, SENDER, (ushort)strlen(str), str);
smb_hfield(&newmsg, SENDERAGENT, sizeof(agent), &agent);
/* Put error message in subject for now */
sprintf(full_err,"Delivery failure of message to %s after %u attempts: %s"
,(char*)msg->to_net.addr, msg->hdr.delivery_attempts, err);
smb_hfield(&newmsg, SUBJECT, (ushort)strlen(full_err), full_err);
if((i=smb_addmsghdr(smb,&newmsg,SMB_SELFPACK))!=0)
lprintf("0000 !BOUNCE ERROR %d adding message header",i);
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
newmsg.dfield=NULL; /* Don't double-free the data fields */
newmsg.hdr.total_dfields=0;
smb_freemsgmem(&newmsg);
return(TRUE);
}
#ifdef __BORLANDC__
#pragma argsused
#endif
static void sendmail_thread(void* arg)
{
int i,j;
char to[128];
char mx[128];
char mx2[128];
char err[128];
char buf[512];
char fromaddr[256];
char* server;
char* msgtxt=NULL;
char* p;
ulong offset;
ulong last_msg=0;
ulong total_msgs;
ulong ip_addr;
ulong dns;
BOOL success;
SOCKET sock=INVALID_SOCKET;
SOCKADDR_IN addr;
SOCKADDR_IN server_addr;
time_t last_scan=0;
smb_t smb;
smbmsg_t msg;
sendmail_running=TRUE;
thread_up();
lprintf("0000 SendMail thread started");
memset(&msg,0,sizeof(msg));
memset(&smb,0,sizeof(smb));
while(server_socket!=INVALID_SOCKET) {
if(startup->options&MAIL_OPT_NO_SENDMAIL) {
mswait(1000);
continue;
}
if(active_sendmail!=0) {
active_sendmail=0;
update_clients();
}
smb_close(&smb);
if(sock!=INVALID_SOCKET) {

rswindell
committed
mail_close_socket(sock);
sock=INVALID_SOCKET;
}
if(msgtxt!=NULL) {
smb_freemsgtxt(msgtxt);
msgtxt=NULL;
}
smb_freemsgmem(&msg);

rswindell
committed
sprintf(smb.file,"%smail",scfg.data_dir);
if((i=smb_open(&smb))!=0)
continue;
if((i=smb_locksmbhdr(&smb))!=0)
continue;
if((i=smb_getstatus(&smb))!=0) {
smb_unlocksmbhdr(&smb);
continue;
}
smb_unlocksmbhdr(&smb);
if(smb.status.last_msg==last_msg && time(NULL)-last_scan<startup->rescan_frequency)
continue;
last_msg=smb.status.last_msg;
last_scan=time(NULL);
total_msgs=smb.status.total_msgs;
smb_rewind(smb.sid_fp);
for(offset=0;offset<total_msgs;offset++) {
if(server_socket==INVALID_SOCKET) /* server stopped */
break;
if(active_sendmail!=0) {
active_sendmail=0;
update_clients();
}
if(sock!=INVALID_SOCKET) {

rswindell
committed
mail_close_socket(sock);
sock=INVALID_SOCKET;
}
if(msgtxt!=NULL) {
smb_freemsgtxt(msgtxt);
msgtxt=NULL;
}
smb_freemsgmem(&msg);
smb_fseek(smb.sid_fp, offset*sizeof(msg.idx), SEEK_SET);
if(smb_fread(&msg.idx, sizeof(msg.idx), smb.sid_fp) != sizeof(msg.idx))
break;
if(msg.idx.attr&MSG_DELETE) /* Marked for deletion */
continue;
if(msg.idx.to) /* Local */
continue;
msg.offset=offset;
if((i=smb_lockmsghdr(&smb,&msg))!=0) {
lprintf("0000 !SEND ERROR %d locking message header #%lu"
,i,msg.idx.number);
continue;
}
if((i=smb_getmsghdr(&smb,&msg))!=0) {
smb_unlockmsghdr(&smb,&msg);
lprintf("0000 !SEND ERROR %d reading message header #%lu"
,i,msg.idx.number);
continue;
}
smb_unlockmsghdr(&smb,&msg);
if(msg.to_net.type!=NET_INTERNET)
continue;
active_sendmail=1;
update_clients();
lprintf("0000 SEND Message #%lu from %s to %s"
,msg.hdr.number, msg.from, msg.to_net.addr);
status("SendMail");
if(startup->outbound_sound[0] && !(startup->options&MAIL_OPT_MUTE))
PlaySound(startup->outbound_sound, NULL, SND_ASYNC|SND_FILENAME);
lprintf("0000 SEND getting message text");
if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_TAILS))==NULL) {
lprintf("0000 !SEND ERROR (%s) retrieving message text",smb.last_error);
continue;
}
if(startup->options&MAIL_OPT_RELAY_TX)
server=startup->relay_server;
else {
sprintf(to,"%.*s",(int)sizeof(to)-1,(char*)msg.to_net.addr);
p=strrchr(to,'>'); /* Truncate '>' */
if(p!=NULL) *p=0;
p=strrchr(to,'@');
if(p==NULL) {
lprintf("0000 !SEND INVALID destination address: %s", to);
sprintf(err,"Invalid destination address: %s", to);
bounce(&smb,&msg,err,TRUE);
continue;
}
if((dns=resolve_ip(startup->dns_server))==0)
continue;
p++;
lprintf("0000 SEND getting MX records for %s from %s",p,startup->dns_server);
if((i=dns_getmx(p, mx, mx2, startup->interface_addr, dns

rswindell
committed
,startup->options&MAIL_OPT_USE_TCP_DNS ? TRUE : FALSE
,TIMEOUT_THREAD_WAIT/2))!=0) {
lprintf("0000 !SEND ERROR %d obtaining MX records for %s from %s"
,i,p,startup->dns_server);
sprintf(err,"Error %d obtaining MX record for %s",i,p);
bounce(&smb,&msg,err,FALSE);
continue;
}
server=mx;
}
lprintf("0000 SEND opening socket");

rswindell
committed
if((sock=mail_open_socket(SOCK_STREAM))==INVALID_SOCKET) {
lprintf("0000 !SEND ERROR %d opening socket", ERROR_VALUE);
lprintf("%04d SEND socket opened",sock);
memset(&addr,0,sizeof(addr));
addr.sin_addr.s_addr = htonl(startup->interface_addr);
addr.sin_family = AF_INET;
lprintf("%04d SEND binding socket",sock);
if((i=bind(sock, (struct sockaddr *) &addr, sizeof (addr)))!=0) {
lprintf("%04d !SEND ERROR %d (%d) binding socket", sock, i, ERROR_VALUE);
continue;
}
strcpy(err,"UNKNOWN ERROR");
success=FALSE;
for(j=0;j<2 && !success;j++) {
if(j) {
if(startup->options&MAIL_OPT_RELAY_TX || !mx2[0])
break;
server=mx2; /* Give second mx record a try */
}
lprintf("%04d SEND resolving SMTP host name: %s", sock, server);
ip_addr=resolve_ip(server);
if(!ip_addr) {
sprintf(err,"Failed to resolve SMTP host name: %s",server);
continue;
}
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET;

rswindell
committed
if(startup->options&MAIL_OPT_RELAY_TX)
server_addr.sin_port = htons(startup->relay_port);
else
server_addr.sin_port = htons(IPPORT_SMTP);
lprintf("%04d SEND connecting to port %u on %s [%s]"

rswindell
committed
,ntohs(server_addr.sin_port)
,server,inet_ntoa(server_addr.sin_addr));
if((i=connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)))!=0) {
lprintf("%04d !SEND ERROR %d (%d) connecting to SMTP server: %s"
sprintf(err,"Error %d connecting to SMTP server: %s"
,(int)ERROR_VALUE,server);
continue;
}
success=TRUE;
}
if(!success) { /* Failed to send, so bounce */
bounce(&smb,&msg,err,FALSE);
continue;
}
lprintf("%04d SEND connected to %s",sock,server);
/* HELO */
if(!sockgetrsp(sock,"220",buf,sizeof(buf))) {
sprintf(err,"%s replied with '%s' instead of 220",server,buf);
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
sockprintf(sock,"HELO %s",scfg.sys_inetaddr);
if(!sockgetrsp(sock,"250", buf, sizeof(buf))) {
sprintf(err,"%s replied with '%s' instead of 250",server,buf);
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
/* MAIL */
if(msg.from_net.type==NET_INTERNET)
strcpy(fromaddr,msg.from_net.addr);
else
usermailaddr(&scfg,fromaddr,msg.from);
if(fromaddr[0]=='<')
sockprintf(sock,"MAIL FROM: %s",fromaddr);
else
sockprintf(sock,"MAIL FROM: <%s>",fromaddr);
if(!sockgetrsp(sock,"250", buf, sizeof(buf))) {
sprintf(err,"%s replied with '%s' instead of 250",server,buf);
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
/* RCPT */
if(*((char*)msg.to_net.addr)=='<')
sockprintf(sock,"RCPT TO: %s", (char*)msg.to_net.addr);
else
sockprintf(sock,"RCPT TO: <%s>", (char*)msg.to_net.addr);
if(!sockgetrsp(sock,"25", buf, sizeof(buf))) {
sprintf(err,"%s replied with '%s' instead of 25*",server,buf);
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
/* DATA */
sockprintf(sock,"DATA");
if(!sockgetrsp(sock,"354", buf, sizeof(buf))) {
sprintf(err,"%s replied with '%s' instead of 354",server,buf);
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
lprintf("%04d SEND sending message text (%u bytes)"
,sock, strlen(msgtxt));
sockmsgtxt(sock,&msg,msgtxt,fromaddr,-1);
if(!sockgetrsp(sock,"250", buf, sizeof(buf))) {
sprintf(err,"%s replied with '%s' instead of 250",server,buf);
bounce(&smb,&msg,err,buf[0]=='5');
continue;
}
lprintf("%04d SEND message transfer complete", sock);
msg.hdr.attr|=MSG_DELETE;
msg.idx.attr=msg.hdr.attr;
if((i=smb_lockmsghdr(&smb,&msg))!=0)
lprintf("%04d !SEND ERROR %d locking message header #%lu"
,i,msg.hdr.number);
if((i=smb_putmsg(&smb,&msg))!=0)
lprintf("%04d !SEND ERROR %d deleting message #%lu"
,i,msg.hdr.number);
smb_unlockmsghdr(&smb,&msg);
/* QUIT */
sockprintf(sock,"QUIT");
sockgetrsp(sock,"221", buf, sizeof(buf));

rswindell
committed
mail_close_socket(sock);
sock=INVALID_SOCKET;
}
status(STATUS_WFC);
}
if(sock!=INVALID_SOCKET)

rswindell
committed
mail_close_socket(sock);
smb_freemsgtxt(msgtxt);
smb_freemsgmem(&msg);
smb_close(&smb);
lprintf("0000 SendMail thread terminated");
sendmail_running=FALSE;
thread_down();
}
void DLLCALL mail_terminate(void)
{
if(server_socket!=INVALID_SOCKET) {
lprintf("%04d MAIL Terminate: closing socket",server_socket);

rswindell
committed
mail_close_socket(server_socket);
server_socket=INVALID_SOCKET;
}
}
static void cleanup(int code)
{
if(server_socket!=INVALID_SOCKET) {

rswindell
committed
mail_close_socket(server_socket);
server_socket=INVALID_SOCKET;
}
if(pop3_socket!=INVALID_SOCKET) {

rswindell
committed
mail_close_socket(pop3_socket);
pop3_socket=INVALID_SOCKET;
}
update_clients();
#ifdef _WINSOCKAPI_
if(WSAInitialized && WSACleanup()!=0)
lprintf("0000 !WSACleanup ERROR %d",ERROR_VALUE);
lprintf("#### Mail Server thread terminated");
status("Down");
if(startup!=NULL && startup->terminated!=NULL)
startup->terminated(code);
thread_down();
}
const char* DLLCALL mail_ver(void)
{
static char ver[256];
char compiler[32];

rswindell
committed
COMPILER_DESC(compiler);
sprintf(ver,"Synchronet Mail Server v%s%s SMBLIB v%s "
"Compiled %s %s with %s"
,MAIL_VERSION
#ifdef _DEBUG
," Debug"
#else
,""
#endif
,smb_lib_ver()
,__DATE__, __TIME__, compiler
);
return(ver);
}
void DLLCALL mail_server(void* arg)
{
char compiler[32];
SOCKADDR_IN server_addr;
SOCKADDR_IN client_addr;
int client_addr_len;
SOCKET client_socket;
int i;
int result;
ulong l;
time_t t;
time_t start;
LINGER linger;
fd_set socket_set;
SOCKET high_socket_set;
pop3_t* pop3;
smtp_t* smtp;

rswindell
committed
struct timeval tv;
startup=(mail_startup_t*)arg;
if(startup==NULL) {
sbbs_beep(100,500);
fprintf(stderr, "No startup structure passed!\n");
return;
}
if(startup->size!=sizeof(mail_startup_t)) { /* verify size */
sbbs_beep(100,500);
sbbs_beep(300,500);
sbbs_beep(100,500);
fprintf(stderr, "Invalid startup structure!\n");
return;
}
/* Setup intelligent defaults */
if(startup->relay_port==0) startup->relay_port=IPPORT_SMTP;
if(startup->smtp_port==0) startup->smtp_port=IPPORT_SMTP;
if(startup->pop3_port==0) startup->pop3_port=110;
if(startup->rescan_frequency==0) startup->rescan_frequency=3600; /* 60 minutes */
if(startup->max_delivery_attempts==0) startup->max_delivery_attempts=50;
if(startup->max_inactivity==0) startup->max_inactivity=120; /* seconds */

rswindell
committed
thread_up();
status("Initializing");
memset(&scfg, 0, sizeof(scfg));
#ifdef __unix__ /* Ignore "Broken Pipe" signal */
signal(SIGPIPE,SIG_IGN);
#endif
lprintf("Synchronet Mail Server Version %s%s"
,MAIL_VERSION
#ifdef _DEBUG
," Debug"
#else
,""
#endif
);

rswindell
committed
COMPILER_DESC(compiler);
lprintf("Compiled %s %s with %s", __DATE__, __TIME__, compiler);
lprintf("SMBLIB v%s (format %x.%02x)",smb_lib_ver(),smb_ver()>>8,smb_ver()&0xff);
srand(time(NULL));

rswindell
committed
if(!(startup->options&MAIL_OPT_LOCAL_TIMEZONE)) {
if(PUTENV("TZ=UCT0"))
lprintf("!putenv() FAILED");
tzset();
if((t=checktime())!=0) { /* Check binary time */
lprintf("!TIME PROBLEM (%ld)",t);
cleanup(1);
return;
}
}
if(!winsock_startup()) {
cleanup(1);
return;
}
lprintf("Initializing on %.24s with options: %lx"
,ctime(&t),startup->options);
/* Initial configuration and load from CNF files */
sprintf(scfg.ctrl_dir, "%.*s", (int)sizeof(scfg.ctrl_dir)-1
,startup->ctrl_dir);
lprintf("Loading configuration files from %s", scfg.ctrl_dir);
scfg.size=sizeof(scfg);
if(!load_cfg(&scfg, NULL, TRUE)) {
lprintf("!Failed to load configuration files");
cleanup(1);
return;
}
if(startup->max_clients==0) {
startup->max_clients=scfg.sys_nodes;
if(startup->max_clients<10)
startup->max_clients=10;
}
lprintf("Maximum clients: %u",startup->max_clients);
lprintf("Maximum inactivity: %u seconds",startup->max_inactivity);
active_clients=0;
update_clients();
/* open a socket and wait for a client */

rswindell
committed
server_socket = mail_open_socket(SOCK_STREAM);
if (server_socket == INVALID_SOCKET) {
lprintf("!ERROR %d opening socket", ERROR_VALUE);
cleanup(1);
return;
}
lprintf("%04d SMTP socket opened",server_socket);
#if 1
linger.l_onoff=TRUE;
linger.l_linger=5; /* seconds */
result = setsockopt (server_socket, SOL_SOCKET, SO_LINGER
,(char *)&linger, sizeof(linger));
if (result != 0) {
lprintf("%04d !ERROR %d (%d) setting socket options"
,server_socket, result, ERROR_VALUE);
cleanup(1);
return;
}
#endif
/*****************************/
/* Listen for incoming calls */
/*****************************/
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(startup->smtp_port);
result = bind(server_socket, (struct sockaddr *) &server_addr
,sizeof (server_addr));
if (result != 0) {
lprintf("%04d !ERROR %d (%d) binding SMTP socket to port %u"
,server_socket, result, ERROR_VALUE, startup->smtp_port);
lprintf("%04d %s",server_socket, BIND_FAILURE_HELP);
cleanup(1);
return;
}
lprintf("%04d SMTP socket bound to port %u"
,server_socket, startup->smtp_port);
result = listen (server_socket, 1);
if (result != 0) {
lprintf("%04d !ERROR %d (%d) listening on socket"
,server_socket, result, ERROR_VALUE);
cleanup(1);
return;
}
if(startup->options&MAIL_OPT_ALLOW_POP3) {
/* open a socket and wait for a client */

rswindell
committed
pop3_socket = mail_open_socket(SOCK_STREAM);
if (pop3_socket == INVALID_SOCKET) {
lprintf("!ERROR %d opening POP3 socket", ERROR_VALUE);
cleanup(1);
return;
}
lprintf("%04d POP3 socket opened",pop3_socket);
/*****************************/
/* Listen for incoming calls */
/*****************************/
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_addr.s_addr = htonl(startup->interface_addr);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(startup->pop3_port);
result = bind(pop3_socket, (struct sockaddr *) &server_addr
,sizeof (server_addr));
if (result != 0) {
lprintf("%04d !ERROR %d (%d) binding POP3 socket to port %u"
,pop3_socket, result, ERROR_VALUE, startup->pop3_port);
lprintf("%04d %s",pop3_socket,BIND_FAILURE_HELP);
cleanup(1);
return;
}
lprintf("%04d POP3 socket bound to port %u"
,pop3_socket, startup->pop3_port);
result = listen (pop3_socket, 1);
if (result != 0) {
lprintf("%04d !ERROR %d (%d) listening on POP3 socket"
,pop3_socket, result, ERROR_VALUE);
cleanup(1);
return;
}
}
/* signal caller that we've started up successfully */
if(startup->started!=NULL)
startup->started();
if(!(startup->options&MAIL_OPT_NO_SENDMAIL))
_beginthread (sendmail_thread, 0, NULL);
lprintf("%04d Mail Server thread started",server_socket);
status(STATUS_WFC);
while (server_socket!=INVALID_SOCKET) {
/* now wait for connection */
FD_ZERO(&socket_set);
FD_SET(server_socket,&socket_set);
high_socket_set=server_socket+1;
if(startup->options&MAIL_OPT_ALLOW_POP3) {
FD_SET(pop3_socket,&socket_set);
if(pop3_socket+1>high_socket_set)
high_socket_set=pop3_socket+1;
}

rswindell
committed
tv.tv_sec=2;
tv.tv_usec=0;
if((i=select(high_socket_set,&socket_set,NULL,NULL,&tv))<1) {
if(i==0) {
mswait(1);
continue;
lprintf("0000 Mail Server listening interrupted");
lprintf("0000 Mail Server sockets closed");
lprintf("0000 !ERROR %d selecting sockets",ERROR_VALUE);
break;
}
if(FD_ISSET(server_socket,&socket_set)) {
client_addr_len = sizeof (client_addr);
client_socket = accept(server_socket, (struct sockaddr *)&client_addr
,&client_addr_len);
if (client_socket == INVALID_SOCKET)
{
lprintf("%04d SMTP socket closed while listening",server_socket);
lprintf("%04d !ERROR %d accept failed", server_socket, ERROR_VALUE);
break;
}
if(startup->socket_open!=NULL)
startup->socket_open(TRUE);
sockets++;
if(active_clients>=startup->max_clients) {
lprintf("%04d !MAXMIMUM CLIENTS (%u) reached, access denied"
,client_socket, startup->max_clients);
sockprintf(client_socket,"421 Maximum active clients reached, please try again later.");

rswindell
committed
mail_close_socket(client_socket);
continue;
}
l=1;
if((i=ioctlsocket(client_socket, FIONBIO, &l))!=0) {
lprintf("%04d !ERROR %d (%d) disabling blocking on socket"
,client_socket, i, ERROR_VALUE);

rswindell
committed
mail_close_socket(client_socket);
continue;
}
if((smtp=malloc(sizeof(smtp_t)))==NULL) {
lprintf("%04d !ERROR allocating %u bytes of memory for smtp_t"
,client_socket, sizeof(smtp_t));

rswindell
committed
mail_close_socket(client_socket);
continue;
}
smtp->socket=client_socket;
smtp->client_addr=client_addr;
_beginthread (smtp_thread, 0, smtp);
}
if(FD_ISSET(pop3_socket,&socket_set)) {
client_addr_len = sizeof (client_addr);
client_socket = accept(pop3_socket, (struct sockaddr *)&client_addr
,&client_addr_len);
if (client_socket == INVALID_SOCKET)
{
lprintf("%04d POP3 socket closed while listening",pop3_socket);
lprintf("%04d !ERROR %d accept failed", pop3_socket, ERROR_VALUE);
break;
}
if(startup->socket_open!=NULL)
startup->socket_open(TRUE);
sockets++;
if(active_clients>=startup->max_clients) {
lprintf("%04d !MAXMIMUM CLIENTS (%u) reached, access denied"
,client_socket, startup->max_clients);
sockprintf(client_socket,"-ERR Maximum active clients reached, please try again later.");

rswindell
committed
mail_close_socket(client_socket);
continue;
}
l=1;
if((i=ioctlsocket(client_socket, FIONBIO, &l))!=0) {
lprintf("%04d !ERROR %d (%d) disabling blocking on socket"
,client_socket, i, ERROR_VALUE);
sockprintf(client_socket,"-ERR System error, please try again later.");

rswindell
committed
mail_close_socket(client_socket);
continue;
}
if((pop3=malloc(sizeof(pop3_t)))==NULL) {
lprintf("%04d !ERROR allocating %u bytes of memory for pop3_t"
,client_socket,sizeof(pop3_t));
sockprintf(client_socket,"-ERR System error, please try again later.");

rswindell
committed
mail_close_socket(client_socket);
continue;
}
pop3->socket=client_socket;
pop3->client_addr=client_addr;
_beginthread (pop3_thread, 0, pop3);
}
}
if(active_clients) {
lprintf("0000 Waiting for %d active clients to disconnect...", active_clients);
start=time(NULL);
while(active_clients) {
if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
lprintf("!TIMEOUT waiting for %u active clients ",active_clients);
break;
}
}
}
if(sendmail_running) {
lprintf("0000 Waiting for SendMail thread to terminate...");