Newer
Older
}
smb_unlockmsghdr(&smb,&msg);
if(msg.to_net.type!=NET_INTERNET)
continue;
active_sendmail=1;
update_clients();
lprintf("0000 SendMail: 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 SendMail: getting message text");
if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_TAILS))==NULL) {
lprintf("0000 !SendMail: ERROR retrieving message text");
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 !SendMail: 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 SendMail: getting MX records for %s from %s",p,startup->dns_server);
if((i=dns_getmx(p, mx, mx2, startup->interface_addr, dns
,startup->options&MAIL_OPT_USE_TCP_DNS ? TRUE : FALSE))!=0) {
lprintf("0000 !SendMail: 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 SendMail: opening socket");

rswindell
committed
if((sock=mail_open_socket(SOCK_STREAM))==INVALID_SOCKET) {
lprintf("0000 !SendMail: ERROR %d opening socket", ERROR_VALUE);
lprintf("%04d SendMail: socket opened",sock);
memset(&addr,0,sizeof(addr));
addr.sin_addr.s_addr = htonl(startup->interface_addr);
addr.sin_family = AF_INET;
lprintf("%04d SendMail: binding socket",sock);
if((i=bind(sock, (struct sockaddr *) &addr, sizeof (addr)))!=0) {
lprintf("%04d !SendMail: 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 SendMail: 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 SendMail: connecting to port %u on %s [%s]"
,sock

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 !SendMail: ERROR %d (%d) connecting to SMTP server: %s"
,sock
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 SendMail: connected to %s",sock,server);
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
/* 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(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,"250", buf, sizeof(buf))) {
sprintf(err,"%s replied with '%s' instead of 250",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 SendMail: sending message text",sock);
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 SendMail: transfer successful",sock);
msg.hdr.attr|=MSG_DELETE;
msg.idx.attr=msg.hdr.attr;
if((i=smb_lockmsghdr(&smb,&msg))!=0)
lprintf("%04d !SendMail: ERROR %d locking message header #%lu"
,sock
,i,msg.hdr.number);
if((i=smb_putmsg(&smb,&msg))!=0)
lprintf("%04d !SendMail: ERROR %d deleting message #%lu"
,sock
,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();
}
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;
}

rswindell
committed
if(startup->relay_port==0)
startup->relay_port=IPPORT_SMTP;
thread_up();
status("Initializing");
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));
#ifndef __MINGW32__
if(PUTENV("TZ=UCT0"))
lprintf("!putenv() FAILED");
tzset();
if((t=checktime())!=0) { /* Check binary time */
lprintf("!TIME PROBLEM (%08lx)",t);
cleanup(1);
return;
}
if(!winsock_startup()) {
cleanup(1);
return;
}
t=time(NULL);
lprintf("Initializing on %s",ctime(&t));
/* Initial configuration and load from CNF files */
memset(&scfg, 0, sizeof(scfg));
sprintf(scfg.ctrl_dir, "%.*s", (int)sizeof(scfg.ctrl_dir)-1
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
,startup->ctrl_dir);
lprintf("Loading configuration files from %s", scfg.ctrl_dir);
if(!load_cfg(&scfg, NULL)) {
lprintf("!Failed to load configuration files");
cleanup(1);
return;
}
if(!startup->max_clients) {
startup->max_clients=scfg.sys_nodes;
if(startup->max_clients<10)
startup->max_clients=10;
}
lprintf("Maximum clients: %u",startup->max_clients);
if(!startup->max_inactivity)
startup->max_inactivity=120; /* seconds */
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);
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);
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();
_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...");
start=time(NULL);
while(sendmail_running) {
if(time(NULL)-start>TIMEOUT_THREAD_WAIT) {
lprintf("!TIMEOUT waiting for sendmail thread to "
"terminate");
break;
}