|
|
1.1 ! root 1: /* mailsrvr.c */ ! 2: ! 3: /* Synchronet Mail (SMTP/POP3) server and sendmail threads */ ! 4: ! 5: /* $Id: mailsrvr.c,v 1.45 2000/12/20 18:47:18 rswindell Exp $ */ ! 6: ! 7: /**************************************************************************** ! 8: * @format.tab-size 4 (Plain Text/Source Code File Header) * ! 9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * ! 10: * * ! 11: * Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html * ! 12: * * ! 13: * This program is free software; you can redistribute it and/or * ! 14: * modify it under the terms of the GNU General Public License * ! 15: * as published by the Free Software Foundation; either version 2 * ! 16: * of the License, or (at your option) any later version. * ! 17: * See the GNU General Public License for more details: gpl.txt or * ! 18: * http://www.fsf.org/copyleft/gpl.html * ! 19: * * ! 20: * Anonymous FTP access to the most recent released source is available at * ! 21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * ! 22: * * ! 23: * Anonymous CVS access to the development source and modification history * ! 24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: * ! 25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login * ! 26: * (just hit return, no password is necessary) * ! 27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src * ! 28: * * ! 29: * For Synchronet coding style and modification guidelines, see * ! 30: * http://www.synchro.net/source.html * ! 31: * * ! 32: * You are encouraged to submit any modifications (preferably in Unix diff * ! 33: * format) via e-mail to [email protected] * ! 34: * * ! 35: * Note: If this box doesn't appear square, then you need to fix your tabs. * ! 36: ****************************************************************************/ ! 37: ! 38: /* Platform-specific headers */ ! 39: #ifdef _WIN32 ! 40: ! 41: #include <io.h> /* open/close */ ! 42: #include <share.h> /* share open flags */ ! 43: #include <process.h> /* _beginthread */ ! 44: #include <windows.h> /* required for mmsystem.h */ ! 45: #include <mmsystem.h> /* SND_ASYNC */ ! 46: ! 47: #elif defined(__unix__) ! 48: ! 49: #include <signal.h> /* signal/SIGPIPE */ ! 50: ! 51: #endif ! 52: ! 53: ! 54: /* ANSI C Library headers */ ! 55: #include <stdio.h> ! 56: #include <stdlib.h> /* ltoa in GNU C lib */ ! 57: #include <stdarg.h> /* va_list */ ! 58: #include <string.h> /* strrchr */ ! 59: #include <ctype.h> /* isdigit */ ! 60: #include <fcntl.h> /* Open flags */ ! 61: #include <errno.h> /* errno */ ! 62: ! 63: /* Synchronet-specific headers */ ! 64: #include "sbbs.h" ! 65: #include "mailsrvr.h" ! 66: #include "crc32.h" ! 67: ! 68: /* Constants */ ! 69: #define MAIL_VERSION "1.10" ! 70: ! 71: int dns_getmx(char* name, char* mx, char* mx2, DWORD intf, DWORD ip_addr, BOOL use_tcp); ! 72: ! 73: #define SMTP_OK "250 OK" ! 74: #define SMTP_BADSEQ "503 Bad sequence of commands" ! 75: ! 76: #define TIMEOUT_THREAD_WAIT 60 /* Seconds */ ! 77: ! 78: #define STATUS_WFC "Listening" ! 79: ! 80: static const char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; ! 81: static const char *mon[]={"Jan","Feb","Mar","Apr","May","Jun" ! 82: ,"Jul","Aug","Sep","Oct","Nov","Dec"}; ! 83: ! 84: static mail_startup_t* startup=NULL; ! 85: static scfg_t scfg; ! 86: static SOCKET server_socket=INVALID_SOCKET; ! 87: static SOCKET pop3_socket=INVALID_SOCKET; ! 88: static int active_clients=0; ! 89: static int active_sendmail=0; ! 90: static BOOL sendmail_running=FALSE; ! 91: static DWORD sockets=0; ! 92: ! 93: typedef struct { ! 94: SOCKET socket; ! 95: SOCKADDR_IN client_addr; ! 96: } smtp_t,pop3_t; ! 97: ! 98: static int lprintf(char *fmt, ...) ! 99: { ! 100: va_list argptr; ! 101: char sbuf[1024]; ! 102: ! 103: if(startup==NULL || startup->lputs==NULL) ! 104: return(0); ! 105: ! 106: va_start(argptr,fmt); ! 107: vsprintf(sbuf,fmt,argptr); ! 108: va_end(argptr); ! 109: return(startup->lputs(sbuf)); ! 110: } ! 111: ! 112: #ifdef _WINSOCKAPI_ ! 113: ! 114: static WSADATA WSAData; ! 115: static BOOL WSAInitialized=FALSE; ! 116: ! 117: static BOOL winsock_startup(void) ! 118: { ! 119: int status; /* Status Code */ ! 120: ! 121: if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) { ! 122: lprintf("%s %s",WSAData.szDescription, WSAData.szSystemStatus); ! 123: WSAInitialized=TRUE; ! 124: return (TRUE); ! 125: } ! 126: ! 127: lprintf("!WinSock startup ERROR %d", status); ! 128: return (FALSE); ! 129: } ! 130: ! 131: #else /* No WINSOCK */ ! 132: ! 133: #define winsock_startup() (TRUE) ! 134: ! 135: #endif ! 136: ! 137: static void update_clients(void) ! 138: { ! 139: if(startup!=NULL && startup->clients!=NULL) ! 140: startup->clients(active_clients+active_sendmail); ! 141: } ! 142: ! 143: static void client_on(SOCKET sock, client_t* client) ! 144: { ! 145: if(startup!=NULL && startup->client_on!=NULL) ! 146: startup->client_on(TRUE,sock,client); ! 147: } ! 148: ! 149: static void client_off(SOCKET sock) ! 150: { ! 151: if(startup!=NULL && startup->client_on!=NULL) ! 152: startup->client_on(FALSE,sock,NULL); ! 153: } ! 154: ! 155: static void thread_up(void) ! 156: { ! 157: if(startup!=NULL && startup->thread_up!=NULL) ! 158: startup->thread_up(TRUE); ! 159: } ! 160: ! 161: static void thread_down(void) ! 162: { ! 163: if(startup!=NULL && startup->thread_up!=NULL) ! 164: startup->thread_up(FALSE); ! 165: } ! 166: ! 167: SOCKET mail_open_socket(int type) ! 168: { ! 169: SOCKET sock; ! 170: ! 171: sock=socket(AF_INET, type, IPPROTO_IP); ! 172: if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL) ! 173: startup->socket_open(TRUE); ! 174: if(sock!=INVALID_SOCKET) { ! 175: sockets++; ! 176: #if 0 /*def _DEBUG */ ! 177: lprintf("%04d Socket opened (%d sockets in use)",sock,sockets); ! 178: #endif ! 179: } ! 180: return(sock); ! 181: } ! 182: ! 183: int mail_close_socket(SOCKET sock) ! 184: { ! 185: int result; ! 186: ! 187: shutdown(sock,SHUT_RDWR); /* required on Unix */ ! 188: result=closesocket(sock); ! 189: if(/* result==0 && */ startup!=NULL && startup->socket_open!=NULL) ! 190: startup->socket_open(FALSE); ! 191: sockets--; ! 192: if(result!=0) ! 193: lprintf("%04d !ERROR %d closing socket",sock, ERROR_VALUE); ! 194: else { ! 195: #if 0 /*def _DEBUG */ ! 196: lprintf("%04d Socket closed (%d sockets in use)",sock,sockets); ! 197: #endif ! 198: } ! 199: ! 200: return(result); ! 201: } ! 202: ! 203: static void status(char* str) ! 204: { ! 205: if(startup!=NULL && startup->status!=NULL) ! 206: startup->status(str); ! 207: } ! 208: ! 209: static int sockprintf(SOCKET sock, char *fmt, ...) ! 210: { ! 211: int len; ! 212: int result; ! 213: va_list argptr; ! 214: char sbuf[1024]; ! 215: ! 216: va_start(argptr,fmt); ! 217: len=vsprintf(sbuf,fmt,argptr); ! 218: if(startup->options&MAIL_OPT_DEBUG_TX) ! 219: lprintf("%04d TX: %s", sock, sbuf); ! 220: strcat(sbuf,"\r\n"); ! 221: len+=2; ! 222: va_end(argptr); ! 223: while((result=send(sock,sbuf,len,0))!=len) { ! 224: if(result==SOCKET_ERROR) { ! 225: if(ERROR_VALUE==EWOULDBLOCK) { ! 226: mswait(1); ! 227: continue; ! 228: } ! 229: if(ERROR_VALUE==ECONNRESET) ! 230: lprintf("%04d Connection reset by peer on send",sock); ! 231: else if(ERROR_VALUE==ECONNABORTED) ! 232: lprintf("%04d Connection aborted by peer on send",sock); ! 233: else ! 234: lprintf("%04d !ERROR %d sending on socket",sock,ERROR_VALUE); ! 235: return(0); ! 236: } ! 237: lprintf("%04d !ERROR: short send on socket: %d instead of %d",sock,result,len); ! 238: } ! 239: return(len); ! 240: } ! 241: ! 242: static time_t checktime(void) ! 243: { ! 244: struct tm tm; ! 245: ! 246: memset(&tm,0,sizeof(tm)); ! 247: tm.tm_year=94; ! 248: tm.tm_mday=1; ! 249: return(mktime(&tm)-0x2D24BD00L); ! 250: } ! 251: ! 252: static void recverror(SOCKET socket, int rd) ! 253: { ! 254: if(rd==0) ! 255: lprintf("%04d Socket closed by peer on receive",socket); ! 256: else if(rd==SOCKET_ERROR) { ! 257: if(ERROR_VALUE==ECONNRESET) ! 258: lprintf("%04d Connection reset by peer on receive",socket); ! 259: else if(ERROR_VALUE==ECONNABORTED) ! 260: lprintf("%04d Connection aborted by peer on receive",socket); ! 261: else ! 262: lprintf("%04d !Socket error %d on receive", socket, ERROR_VALUE); ! 263: } else ! 264: lprintf("%04d !recv on socket returned unexpected value: %d",socket,rd); ! 265: } ! 266: ! 267: static int sockreadline(SOCKET socket, char* buf, int len) ! 268: { ! 269: char ch; ! 270: int i,rd=0; ! 271: time_t start; ! 272: ! 273: start=time(NULL); ! 274: ! 275: while(rd<len-1) { ! 276: i= recv(socket, &ch, 1, 0); ! 277: if(i<1) { ! 278: if(ERROR_VALUE==EWOULDBLOCK) { ! 279: if((time(NULL)-start)>startup->max_inactivity) { ! 280: lprintf("%04d !Socket inactive",socket); ! 281: return(0); ! 282: } ! 283: mswait(1); ! 284: continue; ! 285: } ! 286: recverror(socket,i); ! 287: return(i); ! 288: } ! 289: if(ch=='\n' && rd>=1) { ! 290: break; ! 291: } ! 292: buf[rd++]=ch; ! 293: } ! 294: buf[rd-1]=0; ! 295: ! 296: return(rd); ! 297: } ! 298: ! 299: /************************************************/ ! 300: /* Truncates white-space chars off end of 'str' */ ! 301: /************************************************/ ! 302: static void truncsp(char *str) ! 303: { ! 304: uint c; ! 305: ! 306: c=strlen(str); ! 307: while(c && (uchar)str[c-1]<=' ') c--; ! 308: str[c]=0; ! 309: } ! 310: ! 311: ! 312: static char* alias(char* name, char* alias) ! 313: { ! 314: int file; ! 315: char* p=name; ! 316: char* np; ! 317: char* tp; ! 318: char fname[MAX_PATH]; ! 319: FILE* fp; ! 320: ! 321: sprintf(fname,"%salias.cfg",scfg.ctrl_dir); ! 322: if((file=sopen(fname,O_RDONLY|O_BINARY,SH_DENYNO))==-1) ! 323: return(name); ! 324: ! 325: if((fp=fdopen(file,"rb"))==NULL) { ! 326: close(file); ! 327: return(name); ! 328: } ! 329: ! 330: while(!feof(fp)) { ! 331: if(!fgets(alias,80,fp)) ! 332: break; ! 333: np=alias; ! 334: while(*np && *np<=' ') np++; ! 335: if(*np==';') ! 336: continue; ! 337: tp=np; ! 338: while(*tp && *tp>' ') tp++; ! 339: if(*tp) *tp=0; ! 340: if(!stricmp(np,name)) { ! 341: np=tp+1; ! 342: while(*np && *np<=' ') np++; ! 343: p=np; ! 344: truncsp(p); ! 345: lprintf("0000 Alias: %s",p); ! 346: break; ! 347: } ! 348: } ! 349: fclose(fp); ! 350: return(p); ! 351: } ! 352: ! 353: static BOOL sockgetrsp(SOCKET socket, char* rsp, char *buf, int len) ! 354: { ! 355: int rd; ! 356: ! 357: while(1) { ! 358: rd = sockreadline(socket, buf, len); ! 359: if(rd<1) ! 360: return(FALSE); ! 361: if(buf[3]=='-') { /* Multi-line response */ ! 362: if(startup->options&MAIL_OPT_DEBUG_RX_RSP) ! 363: lprintf("%04d RX: %s",socket,buf); ! 364: continue; ! 365: } ! 366: if(strnicmp(buf,rsp,strlen(rsp))) { ! 367: lprintf("%04d !INVALID RESPONSE: '%s' Expected: '%s'", socket, buf, rsp); ! 368: return(FALSE); ! 369: } ! 370: break; ! 371: } ! 372: if(startup->options&MAIL_OPT_DEBUG_RX_RSP) ! 373: lprintf("%04d RX: %s",socket,buf); ! 374: return(TRUE); ! 375: } ! 376: ! 377: static void usermailaddr(char* addr, char* name) ! 378: { ! 379: int i; ! 380: ! 381: if(strchr(name,'.')) /* unresolved exception here Nov-06-2000 */ ! 382: sprintf(addr,"\"%s\"@",name); ! 383: else { ! 384: sprintf(addr,"%s@",name); ! 385: /* convert "first last@" to "first.last@" */ ! 386: for(i=0;addr[i];i++) ! 387: if(addr[i]==' ' || addr[i]&0x80) ! 388: addr[i]='.'; ! 389: strlwr(addr); ! 390: } ! 391: strcat(addr,scfg.sys_inetaddr); ! 392: } ! 393: ! 394: static char *msgdate(when_t when, char* buf) ! 395: { ! 396: struct tm tm; ! 397: struct tm* tm_p; ! 398: ! 399: tm_p=localtime((const time_t*)&when.time); ! 400: if(tm_p!=NULL) ! 401: tm=*tm_p; ! 402: else ! 403: memset(&tm,0,sizeof(tm)); ! 404: sprintf(buf,"%s, %d %s %d %02d:%02d:%02d %s" ! 405: ,wday[tm.tm_wday] ! 406: ,tm.tm_mday ! 407: ,mon[tm.tm_mon] ! 408: ,1900+tm.tm_year ! 409: ,tm.tm_hour ! 410: ,tm.tm_min ! 411: ,tm.tm_sec ! 412: ,zonestr(when.zone) ! 413: ); ! 414: return(buf); ! 415: } ! 416: ! 417: #define MAX_LINE_LEN 1000 ! 418: ! 419: static void sockmsgtxt(SOCKET socket, smbmsg_t* msg, char* msgtxt, char* fromaddr ! 420: ,ulong maxlines) ! 421: { ! 422: char toaddr[256]; ! 423: char date[64]; ! 424: char* p; ! 425: char* tp; ! 426: int i; ! 427: ulong line; ! 428: ! 429: /* HEADERS */ ! 430: sockprintf(socket,"Date: %s",msgdate(msg->hdr.when_written,date)); ! 431: if(fromaddr[0]=='<') ! 432: sockprintf(socket,"From: \"%s\" %s",msg->from,fromaddr); ! 433: else ! 434: sockprintf(socket,"From: \"%s\" <%s>",msg->from,fromaddr); ! 435: sockprintf(socket,"Subject: %s",msg->subj); ! 436: if(msg->to_net.type==NET_INTERNET || msg->to_net.type==NET_QWK) { ! 437: if(*((char*)msg->to_net.addr)=='<') ! 438: sockprintf(socket,"To: \"%s\" %s",msg->to,(char*)msg->to_net.addr); ! 439: else ! 440: sockprintf(socket,"To: \"%s\" <%s>",msg->to,(char*)msg->to_net.addr); ! 441: } else { ! 442: usermailaddr(toaddr,msg->to); ! 443: sockprintf(socket,"To: \"%s\" <%s>",msg->to,toaddr); ! 444: } ! 445: if(msg->replyto_net.type==NET_INTERNET) ! 446: sockprintf(socket,"Reply-To: %s",msg->replyto_net.addr); ! 447: else ! 448: sockprintf(socket,"Reply-To: %s",fromaddr); ! 449: sockprintf(socket,"Message-ID: <%08lX.%lu@%s>" ! 450: ,msg->hdr.when_written.time,msg->idx.number,scfg.sys_inetaddr); ! 451: for(i=0;i<msg->total_hfields;i++) ! 452: if(msg->hfield[i].type==RFC822HEADER) ! 453: sockprintf(socket,"%s",(char*)msg->hfield_dat[i]); ! 454: sockprintf(socket,""); /* Header Terminator */ ! 455: /* MESSAGE BODY */ ! 456: line=0; ! 457: p=msgtxt; ! 458: while(*p && line<maxlines) { ! 459: tp=strchr(p,'\n'); ! 460: if(tp) { ! 461: if(tp-p>MAX_LINE_LEN) ! 462: tp=p+MAX_LINE_LEN; ! 463: *tp=0; ! 464: } ! 465: truncsp(p); /* Takes care of '\r' or spaces */ ! 466: if(*p=='.') ! 467: i=sockprintf(socket,".%.*s",MAX_LINE_LEN,p); ! 468: else ! 469: i=sockprintf(socket,"%.*s",MAX_LINE_LEN,p); ! 470: if(!i) ! 471: break; ! 472: if(tp==NULL) ! 473: break; ! 474: p=tp+1; ! 475: line++; ! 476: mswait(1); ! 477: } ! 478: sockprintf(socket,"."); /* End of text */ ! 479: } ! 480: ! 481: static u_long resolve_ip(char *addr) ! 482: { ! 483: HOSTENT* host; ! 484: ! 485: if(isdigit(addr[0]) && strchr(addr,'.')) ! 486: return(inet_addr(addr)); ! 487: if ((host=gethostbyname(addr))==NULL) { ! 488: lprintf("0000 !ERROR resolving host name: %s",addr); ! 489: return(0); ! 490: } ! 491: return(*((ulong*)host->h_addr_list[0])); ! 492: } ! 493: ! 494: ! 495: static void pop3_thread(void* arg) ! 496: { ! 497: char* p; ! 498: char str[128]; ! 499: char buf[512]; ! 500: char host_name[128]; ! 501: char host_ip[64]; ! 502: char username[LEN_ALIAS+1]; ! 503: char password[LEN_PASS+1]; ! 504: char fromaddr[256]; ! 505: char* msgtxt; ! 506: int i; ! 507: int rd; ! 508: ulong l; ! 509: ulong lines; ! 510: ulong msgs,bytes,msgnum,msgbytes; ! 511: SOCKET socket; ! 512: HOSTENT* host; ! 513: smb_t smb; ! 514: smbmsg_t msg; ! 515: user_t user; ! 516: client_t client; ! 517: mail_t* mail; ! 518: pop3_t pop3=*(pop3_t*)arg; ! 519: ! 520: thread_up(); ! 521: ! 522: free(arg); ! 523: ! 524: socket=pop3.socket; ! 525: ! 526: if(startup->options&MAIL_OPT_DEBUG_POP3) ! 527: lprintf("%04d POP3 session thread started", socket); ! 528: ! 529: #ifdef _WIN32 ! 530: if(startup->pop3_sound[0] && !(startup->options&MAIL_OPT_MUTE)) ! 531: PlaySound(startup->pop3_sound, NULL, SND_ASYNC|SND_FILENAME); ! 532: #endif ! 533: ! 534: strcpy(host_ip,inet_ntoa(pop3.client_addr.sin_addr)); ! 535: ! 536: if(startup->options&MAIL_OPT_DEBUG_POP3) ! 537: lprintf("%04d POP3 connection accepted from: %s" ! 538: ,socket, host_ip); ! 539: ! 540: if(startup->options&MAIL_OPT_NO_HOST_LOOKUP) ! 541: host=NULL; ! 542: else ! 543: host=gethostbyaddr((char *)&pop3.client_addr.sin_addr ! 544: ,sizeof(pop3.client_addr.sin_addr),AF_INET); ! 545: ! 546: if(host!=NULL && host->h_name!=NULL) ! 547: sprintf(host_name,"%.*s",(int)sizeof(host_name)-1,host->h_name); ! 548: else ! 549: strcpy(host_name,"<no name>"); ! 550: ! 551: if(startup->options&MAIL_OPT_DEBUG_POP3) ! 552: lprintf("%04d POP3 client name: %s", socket, host_name); ! 553: ! 554: if(trashcan(&scfg,host_ip,"ip")) { ! 555: lprintf("%04d !POP3 client blocked in ip.can: %s" ! 556: ,socket, host_ip); ! 557: sockprintf(socket,"-ERR Access denied."); ! 558: mail_close_socket(socket); ! 559: thread_down(); ! 560: return; ! 561: } ! 562: ! 563: if(trashcan(&scfg,host_name,"host")) { ! 564: lprintf("%04d !POP3 client blocked in host.can: %s" ! 565: ,socket, host_name); ! 566: sockprintf(socket,"-ERR Access denied."); ! 567: mail_close_socket(socket); ! 568: thread_down(); ! 569: return; ! 570: } ! 571: ! 572: active_clients++; ! 573: update_clients(); ! 574: ! 575: /* Initialize client display */ ! 576: client.size=sizeof(client); ! 577: client.time=time(NULL); ! 578: sprintf(client.addr,"%.*s",(int)sizeof(client.addr)-1,host_ip); ! 579: sprintf(client.host,"%.*s",(int)sizeof(client.host)-1,host_name); ! 580: client.port=ntohs(pop3.client_addr.sin_port); ! 581: client.protocol="POP3"; ! 582: client.user="<unknown>"; ! 583: client_on(socket,&client); ! 584: ! 585: sprintf(str,"POP3: %s", host_ip); ! 586: status(str); ! 587: ! 588: mail=NULL; ! 589: ! 590: do { ! 591: memset(&smb,0,sizeof(smb)); ! 592: memset(&msg,0,sizeof(msg)); ! 593: ! 594: sprintf(smb.file,"%smail",scfg.data_dir); ! 595: if((i=smb_open(&smb))!=0) { ! 596: lprintf("%04d !Error %d (%s) opening %s",socket,i,smb.last_error,smb.file); ! 597: sockprintf(socket,"-ERR %d opening %s",i,smb.file); ! 598: break; ! 599: } ! 600: ! 601: sockprintf(socket,"+OK Synchronet POP3 Server for %s v%s Ready" ! 602: ,PLATFORM_DESC,MAIL_VERSION); ! 603: ! 604: if(!sockgetrsp(socket,"USER ",buf,sizeof(buf))) { ! 605: sockprintf(socket,"-ERR USER command expected"); ! 606: break; ! 607: } ! 608: p=buf+5; ! 609: while(*p && *p<=' ') p++; ! 610: sprintf(username,"%.*s",(int)sizeof(username)-1,p); ! 611: sockprintf(socket,"+OK"); ! 612: if(!sockgetrsp(socket,"PASS ",buf,sizeof(buf))) { ! 613: sockprintf(socket,"-ERR PASS command expected"); ! 614: break; ! 615: } ! 616: p=buf+5; ! 617: while(*p && *p<=' ') p++; ! 618: sprintf(password,"%.*s",(int)sizeof(password)-1,p); ! 619: user.number=matchuser(&scfg,username); ! 620: if(!user.number) { ! 621: lprintf("%04d !POP3 UNKNOWN USER: %s (password: %s)" ! 622: , socket, username, password); ! 623: sockprintf(socket,"-ERR"); ! 624: break; ! 625: } ! 626: if((i=getuserdat(&scfg, &user))!=0) { ! 627: lprintf("%04d !POP3 ERROR %d getting data on user #%u (%s)" ! 628: ,socket, i, user.number, username); ! 629: sockprintf(socket, "-ERR"); ! 630: break; ! 631: } ! 632: if(user.misc&(DELETED|INACTIVE)) { ! 633: lprintf("%04d !POP3 DELETED or INACTIVE user #%u (%s)" ! 634: ,socket, user.number, username); ! 635: sockprintf(socket, "-ERR"); ! 636: break; ! 637: } ! 638: if(stricmp(password,user.pass)) { ! 639: lprintf("%04d !POP3 WRONG PASSWORD for user %s: '%s' expected '%s'" ! 640: ,socket, username, password, user.pass); ! 641: sockprintf(socket, "-ERR"); ! 642: break; ! 643: } ! 644: ! 645: /* Update client display */ ! 646: client.user=user.alias; ! 647: client_on(socket,&client); ! 648: ! 649: if(startup->options&MAIL_OPT_DEBUG_POP3) ! 650: lprintf("%04d POP3 %s logged in", socket, user.alias); ! 651: sprintf(str,"POP3: %s",user.alias); ! 652: status(str); ! 653: ! 654: sockprintf(socket,"+OK User verified"); ! 655: ! 656: mail=loadmail(&smb,&msgs,user.number,MAIL_YOUR,0); ! 657: ! 658: for(l=bytes=0;l<msgs;l++) { ! 659: msg.hdr.number=mail[l].number; ! 660: if((i=smb_getmsgidx(&smb,&msg))!=0) { ! 661: lprintf("%04d !POP3 ERROR %d getting message index" ! 662: ,socket ,i); ! 663: break; ! 664: } ! 665: if((i=smb_lockmsghdr(&smb,&msg))!=0) { ! 666: lprintf("%04d !POP3 ERROR %d locking message header #%lu" ! 667: ,socket ,i ,msg.hdr.number); ! 668: break; ! 669: } ! 670: i=smb_getmsghdr(&smb,&msg); ! 671: smb_unlockmsghdr(&smb,&msg); ! 672: if(i!=0) { ! 673: lprintf("%04d !POP3 ERROR %d getting message header #%lu" ! 674: ,socket, i, msg.hdr.number); ! 675: break; ! 676: } ! 677: for(i=0;i<msg.hdr.total_dfields;i++) ! 678: if(msg.dfield[i].type==TEXT_BODY || msg.dfield[i].type==TEXT_TAIL) ! 679: bytes+=msg.dfield[i].length; ! 680: smb_freemsgmem(&msg); ! 681: } ! 682: ! 683: while(1) { /* TRANSACTION STATE */ ! 684: rd = sockreadline(socket, buf, sizeof(buf)); ! 685: if(rd<1) ! 686: break; ! 687: if(startup->options&MAIL_OPT_DEBUG_POP3) ! 688: lprintf("%04d POP3 RX: %s", socket, buf); ! 689: if(!stricmp(buf, "NOOP")) { ! 690: sockprintf(socket,"+OK"); ! 691: continue; ! 692: } ! 693: if(!stricmp(buf, "QUIT")) { ! 694: sockprintf(socket,"+OK"); ! 695: break; ! 696: } ! 697: if(!stricmp(buf, "STAT")) { ! 698: sockprintf(socket,"+OK %lu %lu",msgs,bytes); ! 699: continue; ! 700: } ! 701: if(!stricmp(buf, "RSET")) { ! 702: for(l=0;l<msgs;l++) { ! 703: msg.hdr.number=mail[l].number; ! 704: if((i=smb_getmsgidx(&smb,&msg))!=0) { ! 705: lprintf("%04d !POP3 ERROR %d getting message index" ! 706: ,socket, i); ! 707: break; ! 708: } ! 709: if((i=smb_lockmsghdr(&smb,&msg))!=0) { ! 710: lprintf("%04d !POP3 ERROR %d locking message header #%lu" ! 711: ,socket, i,msg.hdr.number); ! 712: break; ! 713: } ! 714: if((i=smb_getmsghdr(&smb,&msg))!=0) { ! 715: lprintf("%04d !POP3 ERROR %d getting message header #%lu" ! 716: ,socket, i, msg.hdr.number); ! 717: break; ! 718: } ! 719: msg.hdr.attr=mail[l].attr; ! 720: msg.idx.attr=msg.hdr.attr; ! 721: if((i=smb_putmsg(&smb,&msg))!=0) ! 722: lprintf("%04d !POP3 ERROR %d updating message index" ! 723: ,socket, i); ! 724: smb_unlockmsghdr(&smb,&msg); ! 725: smb_freemsgmem(&msg); ! 726: } ! 727: if(l<msgs) ! 728: sockprintf(socket,"-ERR %d messages reset (ERROR: %d)",l,i); ! 729: else ! 730: sockprintf(socket,"+OK %lu messages (%lu bytes)",msgs,bytes); ! 731: continue; ! 732: } ! 733: if(!strnicmp(buf, "LIST",4) || !strnicmp(buf,"UIDL",4)) { ! 734: p=buf+4; ! 735: while(*p && *p<=' ') p++; ! 736: if(isdigit(*p)) { ! 737: msgnum=atol(p); ! 738: if(msgnum<1 || msgnum>msgs) { ! 739: lprintf("%04d !POP3 INVALID message #%ld" ! 740: ,socket, msgnum); ! 741: sockprintf(socket,"-ERR no such message"); ! 742: continue; ! 743: } ! 744: msg.hdr.number=mail[msgnum-1].number; ! 745: if((i=smb_getmsgidx(&smb,&msg))!=0) { ! 746: lprintf("%04d !POP3 ERROR %d getting message index" ! 747: ,socket, i); ! 748: sockprintf(socket,"-ERR %d getting message index",i); ! 749: break; ! 750: } ! 751: if(msg.idx.attr&MSG_DELETE) { ! 752: lprintf("%04d !POP3 ATTEMPT to list deleted message" ! 753: ,socket); ! 754: sockprintf(socket,"-ERR message deleted"); ! 755: continue; ! 756: } ! 757: if((i=smb_lockmsghdr(&smb,&msg))!=0) { ! 758: lprintf("%04d !POP3 ERROR %d locking message header #%lu" ! 759: ,socket, i, msg.hdr.number); ! 760: sockprintf(socket,"-ERR %d locking message header",i); ! 761: continue; ! 762: } ! 763: i=smb_getmsghdr(&smb,&msg); ! 764: smb_unlockmsghdr(&smb,&msg); ! 765: if(i!=0) { ! 766: smb_freemsgmem(&msg); ! 767: lprintf("%04d !POP3 ERROR %d getting message header #%lu" ! 768: ,socket, i,msg.hdr.number); ! 769: sockprintf(socket,"-ERR %d getting message header",i); ! 770: continue; ! 771: } ! 772: if(!strnicmp(buf, "LIST",4)) { ! 773: msgbytes=0; ! 774: for(i=0;i<msg.hdr.total_dfields;i++) ! 775: if(msg.dfield[i].type==TEXT_BODY || msg.dfield[i].type==TEXT_TAIL) ! 776: msgbytes+=msg.dfield[i].length; ! 777: sockprintf(socket,"+OK %lu %lu",msgnum,msgbytes); ! 778: } else /* UIDL */ ! 779: sockprintf(socket,"+OK %lu %lu",msgnum,msg.hdr.number); ! 780: ! 781: smb_freemsgmem(&msg); ! 782: continue; ! 783: } ! 784: /* List ALL messages */ ! 785: sockprintf(socket,"+OK %lu messages (%lu bytes)",msgs,bytes); ! 786: for(l=0;l<msgs;l++) { ! 787: msg.hdr.number=mail[l].number; ! 788: if((i=smb_getmsgidx(&smb,&msg))!=0) { ! 789: lprintf("%04d !POP3 ERROR %d getting message index" ! 790: ,socket, i); ! 791: break; ! 792: } ! 793: if(msg.idx.attr&MSG_DELETE) ! 794: continue; ! 795: if((i=smb_lockmsghdr(&smb,&msg))!=0) { ! 796: lprintf("%04d !POP3 ERROR %d locking message header #%lu" ! 797: ,socket, i,msg.hdr.number); ! 798: break; ! 799: } ! 800: i=smb_getmsghdr(&smb,&msg); ! 801: smb_unlockmsghdr(&smb,&msg); ! 802: if(i!=0) { ! 803: smb_freemsgmem(&msg); ! 804: lprintf("%04d !POP3 ERROR %d getting message header #%lu" ! 805: ,socket, i,msg.hdr.number); ! 806: break; ! 807: } ! 808: if(!strnicmp(buf, "LIST",4)) { ! 809: msgbytes=0; ! 810: for(i=0;i<msg.hdr.total_dfields;i++) ! 811: if(msg.dfield[i].type==TEXT_BODY || msg.dfield[i].type==TEXT_TAIL) ! 812: msgbytes+=msg.dfield[i].length; ! 813: sockprintf(socket,"%lu %lu",l+1,msgbytes); ! 814: } else /* UIDL */ ! 815: sockprintf(socket,"%lu %lu",l+1,msg.hdr.number); ! 816: ! 817: smb_freemsgmem(&msg); ! 818: } ! 819: sockprintf(socket,"."); ! 820: continue; ! 821: } ! 822: if(!strnicmp(buf, "RETR ",5) || !strnicmp(buf,"TOP ",4)) { ! 823: sprintf(str,"POP3: %s", user.alias); ! 824: status(str); ! 825: ! 826: lines=-1; ! 827: p=buf+4; ! 828: while(*p && *p<=' ') p++; ! 829: msgnum=atol(p); ! 830: ! 831: if(!strnicmp(buf,"TOP ",4)) { ! 832: while(*p && isdigit(*p)) p++; ! 833: while(*p && *p<=' ') p++; ! 834: lines=atol(p); ! 835: } ! 836: if(msgnum<1 || msgnum>msgs) { ! 837: lprintf("%04d !POP3 %s ATTEMPTED to retrieve an INVALID message #%ld" ! 838: ,socket, user.alias, msgnum); ! 839: sockprintf(socket,"-ERR no such message"); ! 840: continue; ! 841: } ! 842: msg.hdr.number=mail[msgnum-1].number; ! 843: ! 844: lprintf("%04d POP3 %s retrieving message #%ld" ! 845: ,socket, user.alias, msg.hdr.number); ! 846: ! 847: if((i=smb_getmsgidx(&smb,&msg))!=0) { ! 848: lprintf("%04d !POP3 ERROR %d getting message index" ! 849: ,socket, i); ! 850: sockprintf(socket,"-ERR %d getting message index",i); ! 851: continue; ! 852: } ! 853: if(msg.idx.attr&MSG_DELETE) { ! 854: lprintf("%04d !POP3 ATTEMPT to retrieve deleted message" ! 855: ,socket); ! 856: sockprintf(socket,"-ERR message deleted"); ! 857: continue; ! 858: } ! 859: if((i=smb_lockmsghdr(&smb,&msg))!=0) { ! 860: lprintf("%04d !POP3 ERROR %d locking message header #%lu" ! 861: ,socket, i, msg.hdr.number); ! 862: sockprintf(socket,"-ERR %d locking message header",i); ! 863: continue; ! 864: } ! 865: if((i=smb_getmsghdr(&smb,&msg))!=0) { ! 866: smb_unlockmsghdr(&smb,&msg); ! 867: lprintf("%04d !POP3 ERROR %d getting message header #%lu" ! 868: ,socket, i, msg.hdr.number); ! 869: sockprintf(socket,"-ERR %d getting message header",i); ! 870: continue; ! 871: } ! 872: smb_unlockmsghdr(&smb,&msg); ! 873: ! 874: if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_TAILS))==NULL) { ! 875: smb_freemsgmem(&msg); ! 876: lprintf("%04d !POP3 ERROR retrieving message text for message #%lu" ! 877: ,socket, msg.hdr.number); ! 878: sockprintf(socket,"-ERR retrieving message text"); ! 879: continue; ! 880: } ! 881: ! 882: sockprintf(socket,"+OK message follows"); ! 883: if(msg.from_net.type==NET_INTERNET) ! 884: strcpy(fromaddr,msg.from_net.addr); ! 885: else if(msg.from_net.type==NET_QWK) ! 886: sprintf(fromaddr,"\"%s@%s\"@%s" ! 887: ,msg.from,(char*)msg.from_net.addr,scfg.sys_inetaddr); ! 888: else ! 889: usermailaddr(fromaddr,msg.from); /* unresolved exception here Nov-06-2000 */ ! 890: lprintf("%04d POP3 sending message text (%u bytes)" ! 891: ,socket,strlen(msgtxt)); ! 892: sockmsgtxt(socket,&msg,msgtxt,fromaddr,lines); ! 893: /* if(startup->options&MAIL_OPT_DEBUG_POP3) */ ! 894: lprintf("%04d POP3 message transfer complete",socket); ! 895: ! 896: msg.hdr.attr|=MSG_READ; ! 897: msg.idx.attr=msg.hdr.attr; ! 898: msg.hdr.netattr|=MSG_SENT; ! 899: ! 900: if((i=smb_lockmsghdr(&smb,&msg))!=0) ! 901: lprintf("%04d !POP3 ERROR %d locking message header #%lu" ! 902: ,socket, i, msg.hdr.number); ! 903: if((i=smb_putmsg(&smb,&msg))!=0) ! 904: lprintf("%04d !POP3 ERROR %d marking message #%lu as read" ! 905: ,socket, i, msg.hdr.number); ! 906: smb_unlockmsghdr(&smb,&msg); ! 907: smb_freemsgmem(&msg); ! 908: smb_freemsgtxt(msgtxt); ! 909: continue; ! 910: } ! 911: if(!strnicmp(buf, "DELE ",5)) { ! 912: p=buf+5; ! 913: while(*p && *p<=' ') p++; ! 914: msgnum=atol(p); ! 915: ! 916: if(msgnum<1 || msgnum>msgs) { ! 917: lprintf("%04d !POP3 %s ATTEMPTED to delete an INVALID message #%ld" ! 918: ,socket, user.alias, msgnum); ! 919: sockprintf(socket,"-ERR no such message"); ! 920: continue; ! 921: } ! 922: msg.hdr.number=mail[msgnum-1].number; ! 923: ! 924: lprintf("%04d POP3 %s deleting message #%ld" ! 925: ,socket, user.alias, msg.hdr.number); ! 926: ! 927: if((i=smb_getmsgidx(&smb,&msg))!=0) { ! 928: lprintf("%04d !POP3 ERROR %d getting message index" ! 929: ,socket, i); ! 930: sockprintf(socket,"-ERR %d getting message index",i); ! 931: continue; ! 932: } ! 933: if((i=smb_lockmsghdr(&smb,&msg))!=0) { ! 934: lprintf("%04d !POP3 ERROR %d locking message header #%lu" ! 935: ,socket, i,msg.hdr.number); ! 936: sockprintf(socket,"-ERR %d locking message header",i); ! 937: continue; ! 938: } ! 939: if((i=smb_getmsghdr(&smb,&msg))!=0) { ! 940: smb_unlockmsghdr(&smb,&msg); ! 941: lprintf("%04d !POP3 ERROR %d getting message header #%lu" ! 942: ,socket, i,msg.hdr.number); ! 943: sockprintf(socket,"-ERR %d getting message header",i); ! 944: continue; ! 945: } ! 946: msg.hdr.attr|=MSG_DELETE; ! 947: msg.idx.attr=msg.hdr.attr; ! 948: if((i=smb_putmsg(&smb,&msg))!=0) { ! 949: smb_unlockmsghdr(&smb,&msg); ! 950: smb_freemsgmem(&msg); ! 951: lprintf("%04d !POP3 ERROR %d marking message as read", socket, i); ! 952: sockprintf(socket,"-ERR %d marking message for deletion",i); ! 953: continue; ! 954: } ! 955: smb_unlockmsghdr(&smb,&msg); ! 956: smb_freemsgmem(&msg); ! 957: sockprintf(socket,"+OK"); ! 958: if(startup->options&MAIL_OPT_DEBUG_POP3) ! 959: lprintf("%04d POP3 message deleted", socket); ! 960: continue; ! 961: } ! 962: lprintf("%04d !POP3 UNSUPPORTED COMMAND: %s", socket, buf); ! 963: sockprintf(socket,"-ERR UNSUPPORTED COMMAND: %s",buf); ! 964: } ! 965: if(user.number) ! 966: putuserrec(&scfg,user.number,U_LASTON,8,ultoa(time(NULL),str,16)); ! 967: ! 968: } while(0); ! 969: ! 970: status(STATUS_WFC); ! 971: ! 972: /* Free up resources here */ ! 973: mail_close_socket(socket); ! 974: ! 975: if(mail!=NULL) ! 976: freemail(mail); ! 977: ! 978: smb_freemsgmem(&msg); ! 979: smb_close(&smb); ! 980: ! 981: if(startup->options&MAIL_OPT_DEBUG_POP3) ! 982: lprintf("%04d POP3 session thread terminated", socket); ! 983: ! 984: active_clients--; ! 985: update_clients(); ! 986: client_off(socket); ! 987: ! 988: thread_down(); ! 989: } ! 990: ! 991: BOOL rblchk(DWORD mail_addr_n, char* rbl_addr) ! 992: { ! 993: char name[256]; ! 994: DWORD mail_addr; ! 995: ! 996: mail_addr=ntohl(mail_addr_n); ! 997: sprintf(name,"%ld.%ld.%ld.%ld.%s" ! 998: ,mail_addr&0xff ! 999: ,(mail_addr>>8)&0xff ! 1000: ,(mail_addr>>16)&0xff ! 1001: ,(mail_addr>>24)&0xff ! 1002: ,rbl_addr ! 1003: ); ! 1004: ! 1005: if(gethostbyname(name)==NULL) ! 1006: return(FALSE); ! 1007: ! 1008: return(TRUE); ! 1009: } ! 1010: ! 1011: ! 1012: static void smtp_thread(void* arg) ! 1013: { ! 1014: int i,j,x; ! 1015: int rd; ! 1016: char str[512]; ! 1017: char buf[1024],*p,*tp; ! 1018: char hdrfield[512]; ! 1019: char alias_buf[128]; ! 1020: char reverse_path[128]; ! 1021: char date[64]; ! 1022: char month[16]; ! 1023: char rcpt_name[128]; ! 1024: char rcpt_addr[128]; ! 1025: char sender[128]={0}; ! 1026: char sender_addr[128]={0}; ! 1027: char hello_name[128]; ! 1028: char host_name[128]; ! 1029: char host_ip[64]; ! 1030: int addr_len; ! 1031: ushort xlat; ! 1032: ushort nettype=NET_NONE; ! 1033: uint usernum; ! 1034: ulong crc; ! 1035: ulong length; ! 1036: ulong offset; ! 1037: BOOL esmtp=FALSE; ! 1038: FILE* msgtxt=NULL; ! 1039: char msgtxt_fname[MAX_PATH]; ! 1040: FILE* rcptlst; ! 1041: char rcptlst_fname[MAX_PATH]; ! 1042: FILE* spy=NULL; ! 1043: SOCKET socket; ! 1044: HOSTENT* host; ! 1045: smb_t smb; ! 1046: smbmsg_t msg; ! 1047: smbmsg_t newmsg; ! 1048: user_t user; ! 1049: client_t client; ! 1050: struct tm tm; ! 1051: smtp_t smtp=*(smtp_t*)arg; ! 1052: SOCKADDR_IN server_addr; ! 1053: enum { ! 1054: SMTP_STATE_INITIAL ! 1055: ,SMTP_STATE_HELO ! 1056: ,SMTP_STATE_MAIL_FROM ! 1057: ,SMTP_STATE_RCPT_TO ! 1058: ,SMTP_STATE_DATA_HEADER ! 1059: ,SMTP_STATE_DATA_BODY ! 1060: ! 1061: } state = SMTP_STATE_INITIAL; ! 1062: ! 1063: thread_up(); ! 1064: ! 1065: free(arg); ! 1066: ! 1067: socket=smtp.socket; ! 1068: ! 1069: lprintf("%04d SMTP RX Session thread started", socket); ! 1070: ! 1071: #ifdef _WIN32 ! 1072: if(startup->inbound_sound[0] && !(startup->options&MAIL_OPT_MUTE)) ! 1073: PlaySound(startup->inbound_sound, NULL, SND_ASYNC|SND_FILENAME); ! 1074: #endif ! 1075: ! 1076: addr_len=sizeof(server_addr); ! 1077: if((i=getsockname(socket, (struct sockaddr *)&server_addr,&addr_len))!=0) { ! 1078: lprintf("%04d !SMTP ERROR %d (%d) getting address/port" ! 1079: ,socket, i, ERROR_VALUE); ! 1080: return; ! 1081: } ! 1082: ! 1083: memset(&msg,0,sizeof(smbmsg_t)); ! 1084: ! 1085: strcpy(host_ip,inet_ntoa(smtp.client_addr.sin_addr)); ! 1086: ! 1087: lprintf("%04d SMTP connection accepted from: %s", socket, host_ip); ! 1088: ! 1089: if(startup->options&MAIL_OPT_NO_HOST_LOOKUP) ! 1090: host=NULL; ! 1091: else ! 1092: host=gethostbyaddr ((char *)&smtp.client_addr.sin_addr ! 1093: ,sizeof(smtp.client_addr.sin_addr),AF_INET); ! 1094: ! 1095: if(host!=NULL && host->h_name!=NULL) ! 1096: sprintf(host_name,"%.*s",(int)sizeof(host_name)-1,host->h_name); ! 1097: else ! 1098: strcpy(host_name,"<no name>"); ! 1099: ! 1100: lprintf("%04d SMTP host name: %s", socket, host_name); ! 1101: ! 1102: strcpy(hello_name,host_name); ! 1103: ! 1104: if(trashcan(&scfg,host_ip,"ip")) { ! 1105: lprintf("%04d !SMTP server blocked in ip.can: %s" ! 1106: ,socket, host_ip); ! 1107: sockprintf(socket,"550 Access denied."); ! 1108: mail_close_socket(socket); ! 1109: thread_down(); ! 1110: return; ! 1111: } ! 1112: ! 1113: if(trashcan(&scfg,host_name,"host")) { ! 1114: lprintf("%04d !SMTP server blocked in host.can: %s" ! 1115: ,socket, host_name); ! 1116: sockprintf(socket,"550 Access denied."); ! 1117: mail_close_socket(socket); ! 1118: thread_down(); ! 1119: return; ! 1120: } ! 1121: ! 1122: /* SPAM Filters (maps.vix.com) */ ! 1123: if(startup->options&MAIL_OPT_USE_RBL ! 1124: && rblchk(smtp.client_addr.sin_addr.s_addr ! 1125: ,"rbl.maps.vix.com" ! 1126: )==TRUE) { ! 1127: lprintf("%04d !SMTP SPAM server filtered (RBL): %s [%s]" ! 1128: ,socket, host_name,host_ip); ! 1129: sockprintf(socket ! 1130: ,"571 Mail from %s refused, see http://www.mail-abuse.org/rbl" ! 1131: ,host_ip); ! 1132: mail_close_socket(socket); ! 1133: thread_down(); ! 1134: return; ! 1135: } ! 1136: if(startup->options&MAIL_OPT_USE_DUL ! 1137: && rblchk(smtp.client_addr.sin_addr.s_addr ! 1138: ,"dul.maps.vix.com" ! 1139: )==TRUE) { ! 1140: lprintf("%04d !SMTP SPAM server filtered (DUL): %s [%s]" ! 1141: ,socket, host_name,host_ip); ! 1142: sockprintf(socket ! 1143: ,"571 Mail from %s refused, see http://www.mail-abuse.org/dul" ! 1144: ,host_ip); ! 1145: mail_close_socket(socket); ! 1146: thread_down(); ! 1147: return; ! 1148: } ! 1149: if(startup->options&MAIL_OPT_USE_RSS ! 1150: && rblchk(smtp.client_addr.sin_addr.s_addr ! 1151: ,"relays.mail-abuse.org" ! 1152: )==TRUE) { ! 1153: lprintf("%04d !SMTP SPAM server filtered (RSS): %s [%s]" ! 1154: ,socket, host_name,host_ip); ! 1155: sockprintf(socket ! 1156: ,"571 Mail from %s refused, see http://www.mail-abuse.org/rss" ! 1157: ,host_ip); ! 1158: mail_close_socket(socket); ! 1159: thread_down(); ! 1160: return; ! 1161: } ! 1162: ! 1163: sprintf(rcptlst_fname,"%sSMTP%d.LST", scfg.data_dir, socket); ! 1164: rcptlst=fopen(rcptlst_fname,"w+"); ! 1165: if(rcptlst==NULL) { ! 1166: lprintf("%04d !SMTP ERROR %d creating recipient list: %s" ! 1167: ,socket, errno, rcptlst_fname); ! 1168: sockprintf(socket,"421 System error"); ! 1169: mail_close_socket(socket); ! 1170: thread_down(); ! 1171: return; ! 1172: } ! 1173: ! 1174: if(trashcan(&scfg,host_name,"smtpspy") ! 1175: || trashcan(&scfg,host_ip,"smtpspy")) { ! 1176: sprintf(str,"%sSMTPSPY.TXT", scfg.data_dir); ! 1177: spy=fopen(str,"a"); ! 1178: } ! 1179: ! 1180: active_clients++; ! 1181: update_clients(); ! 1182: ! 1183: /* Initialize client display */ ! 1184: client.size=sizeof(client); ! 1185: client.time=time(NULL); ! 1186: sprintf(client.addr,"%.*s",(int)sizeof(client.addr)-1,host_ip); ! 1187: sprintf(client.host,"%.*s",(int)sizeof(client.host)-1,host_name); ! 1188: client.port=ntohs(smtp.client_addr.sin_port); ! 1189: client.protocol="SMTP"; ! 1190: client.user="<unknown>"; ! 1191: client_on(socket,&client); ! 1192: ! 1193: sprintf(str,"SMTP: %s",host_ip); ! 1194: status(str); ! 1195: ! 1196: sockprintf(socket,"220 %s Synchronet SMTP Server for %s v%s Ready" ! 1197: ,scfg.sys_inetaddr,PLATFORM_DESC,MAIL_VERSION); ! 1198: while(1) { ! 1199: rd = sockreadline(socket, buf, sizeof(buf)); ! 1200: if(rd<1) ! 1201: break; ! 1202: if(spy!=NULL) ! 1203: fprintf(spy,"%s\n",buf); ! 1204: if(state>=SMTP_STATE_DATA_HEADER) { ! 1205: if(!strcmp(buf,".")) { ! 1206: lprintf("%04d SMTP End of message (%lu bytes)", socket, ftell(msgtxt)); ! 1207: ! 1208: if(sender[0]==0) { ! 1209: lprintf("%04d !SMTP Mail header missing 'FROM' field", socket); ! 1210: sockprintf(socket, "554 Mail header missing 'FROM' field"); ! 1211: state=SMTP_STATE_HELO; ! 1212: continue; ! 1213: } ! 1214: ! 1215: if(msgtxt!=NULL) { ! 1216: rewind(msgtxt); ! 1217: sprintf(smb.file,"%smail", scfg.data_dir); ! 1218: smb.retry_time=scfg.smb_retry_time; ! 1219: if((i=smb_open(&smb))!=0) { ! 1220: lprintf("%04d !SMTP ERROR %d (%s) opening %s" ! 1221: ,socket, i, smb.last_error, smb.file); ! 1222: sockprintf(socket, "452 Insufficient system storage"); ! 1223: continue; ! 1224: } ! 1225: ! 1226: if(smb_fgetlength(smb.shd_fp)<1) { /* Create it if it doesn't exist */ ! 1227: smb.status.max_crcs=scfg.mail_maxcrcs; ! 1228: smb.status.max_age=scfg.mail_maxage; ! 1229: smb.status.max_msgs=MAX_SYSMAIL; ! 1230: smb.status.attr=SMB_EMAIL; ! 1231: if((i=smb_create(&smb))!=0) { ! 1232: smb_close(&smb); ! 1233: lprintf("%04d !SMTP ERROR %d creating %s" ! 1234: ,socket, i, smb.file); ! 1235: sockprintf(socket, "452 Insufficient system storage"); ! 1236: continue; ! 1237: } ! 1238: } ! 1239: ! 1240: if((i=smb_locksmbhdr(&smb))!=0) { ! 1241: smb_close(&smb); ! 1242: lprintf("%04d !SMTP ERROR %d locking %s" ! 1243: ,socket, i, smb.file); ! 1244: sockprintf(socket, "452 Insufficient system storage"); ! 1245: continue; } ! 1246: ! 1247: length=filelength(fileno(msgtxt))+2; /* +2 for translation string */ ! 1248: ! 1249: if((i=smb_open_da(&smb))!=0) { ! 1250: smb_unlocksmbhdr(&smb); ! 1251: smb_close(&smb); ! 1252: lprintf("%04d !SMTP ERROR %d (%s) opening %s.sda" ! 1253: ,socket, i, smb.last_error, smb.file); ! 1254: sockprintf(socket, "452 Insufficient system storage"); ! 1255: continue; } ! 1256: ! 1257: if(scfg.sys_misc&SM_FASTMAIL) ! 1258: offset=smb_fallocdat(&smb,length,1); ! 1259: else ! 1260: offset=smb_allocdat(&smb,length,1); ! 1261: smb_close_da(&smb); ! 1262: ! 1263: smb_fseek(smb.sdt_fp,offset,SEEK_SET); ! 1264: xlat=XLAT_NONE; ! 1265: smb_fwrite(&xlat,2,smb.sdt_fp); ! 1266: x=SDT_BLOCK_LEN-2; /* Don't read/write more than 255 */ ! 1267: while(!feof(msgtxt)) { ! 1268: memset(buf,0,x); ! 1269: j=fread(buf,1,x,msgtxt); ! 1270: if(j<1) ! 1271: break; ! 1272: if((j!=x || feof(msgtxt)) && buf[j-1]=='\n' && buf[j-2]=='\r') ! 1273: buf[j-1]=buf[j-2]=0; ! 1274: if(scfg.mail_maxcrcs) { ! 1275: for(i=0;i<j;i++) ! 1276: crc=ucrc32(buf[i],crc); ! 1277: } ! 1278: smb_fwrite(buf,j,smb.sdt_fp); ! 1279: x=SDT_BLOCK_LEN; ! 1280: } ! 1281: smb_fflush(smb.sdt_fp); ! 1282: crc=~crc; ! 1283: ! 1284: if(scfg.mail_maxcrcs) { ! 1285: i=smb_addcrc(&smb,crc); ! 1286: if(i) { ! 1287: smb_freemsgdat(&smb,offset,length,1); ! 1288: smb_unlocksmbhdr(&smb); ! 1289: smb_close(&smb); ! 1290: lprintf("%04d !SMTP Duplicate message", socket); ! 1291: sockprintf(socket, "554 Duplicate Message"); ! 1292: continue; ! 1293: } ! 1294: } ! 1295: ! 1296: msg.hdr.offset=offset; ! 1297: ! 1298: smb_dfield(&msg,TEXT_BODY,length); ! 1299: ! 1300: smb_unlocksmbhdr(&smb); ! 1301: if(msg.idx.subj==0) { ! 1302: p=""; ! 1303: smb_hfield(&msg, SUBJECT, 0, p); ! 1304: msg.idx.subj=crc16(p); ! 1305: } ! 1306: rewind(rcptlst); ! 1307: while(!feof(rcptlst)) { ! 1308: if((i=smb_copymsgmem(&newmsg,&msg))!=0) { ! 1309: lprintf("%04d !SMTP ERROR %d copying message" ! 1310: ,socket, i); ! 1311: break; ! 1312: } ! 1313: if(fgets(str,sizeof(str)-1,rcptlst)==NULL) ! 1314: break; ! 1315: usernum=atoi(str); ! 1316: fgets(rcpt_name,sizeof(rcpt_name)-1,rcptlst); ! 1317: if(fgets(rcpt_addr,sizeof(rcpt_addr)-1,rcptlst)==NULL) ! 1318: break; ! 1319: truncsp(rcpt_name); ! 1320: truncsp(rcpt_addr); ! 1321: ! 1322: snprintf(hdrfield,sizeof(hdrfield), ! 1323: "Received: from %s (%s [%s])\r\n" ! 1324: " by %s [%s] (Synchronet Mail Server for %s v%s) with %s\r\n" ! 1325: " for %s; %s" ! 1326: ,host_name,hello_name,host_ip ! 1327: ,scfg.sys_inetaddr,inet_ntoa(server_addr.sin_addr) ! 1328: ,PLATFORM_DESC,MAIL_VERSION ! 1329: ,esmtp ? "ESMTP" : "SMTP" ! 1330: ,rcpt_addr,msgdate(msg.hdr.when_imported,date)); ! 1331: smb_hfield(&newmsg, RFC822HEADER, (ushort)strlen(hdrfield), hdrfield); ! 1332: ! 1333: smb_hfield(&newmsg, RECIPIENT, (ushort)strlen(rcpt_name), rcpt_name); ! 1334: ! 1335: if(rcpt_addr[0]=='#') { /* Local destination */ ! 1336: newmsg.idx.to=atoi(rcpt_addr+1); ! 1337: smb_hfield(&newmsg, RECIPIENTEXT ! 1338: ,(ushort)strlen(rcpt_addr+1), rcpt_addr+1); ! 1339: } else { ! 1340: newmsg.idx.to=0; ! 1341: nettype=NET_INTERNET; ! 1342: smb_hfield(&newmsg, RECIPIENTNETTYPE, nettype, &nettype); ! 1343: smb_hfield(&newmsg, RECIPIENTNETADDR ! 1344: ,(ushort)strlen(rcpt_addr), rcpt_addr); ! 1345: } ! 1346: ! 1347: i=smb_addmsghdr(&smb,&newmsg,SMB_SELFPACK); ! 1348: smb_freemsgmem(&newmsg); ! 1349: if(i!=0) { ! 1350: lprintf("%04d !SMTP ERROR %d adding message header" ! 1351: ,socket, i); ! 1352: break; ! 1353: } ! 1354: lprintf("%04d SMTP Created message #%ld from %s to %s <%s>" ! 1355: ,socket, newmsg.hdr.number, sender, rcpt_name, rcpt_addr); ! 1356: if(usernum) { ! 1357: sprintf(str,"\7\1n\1hOn %.24s\r\n\1m%s \1n\1msent you e-mail from: " ! 1358: "\1h%s\1n\r\n" ! 1359: ,ctime((const time_t*)&newmsg.hdr.when_imported.time) ! 1360: ,sender,sender_addr); ! 1361: if(!newmsg.idx.to) { /* Forwarding */ ! 1362: strcat(str,"\1mand it was automatically forwaded to: \1h"); ! 1363: strcat(str,user.netmail); ! 1364: strcat(str,"\1n\r\n"); ! 1365: } ! 1366: putsmsg(&scfg, usernum, str); ! 1367: } ! 1368: } ! 1369: smb_close(&smb); ! 1370: if(i) { ! 1371: smb_freemsgdat(&smb,offset,length,1); ! 1372: sockprintf(socket, "452 Insufficient system storage"); ! 1373: continue; ! 1374: } ! 1375: } ! 1376: sockprintf(socket,SMTP_OK); ! 1377: state=SMTP_STATE_HELO; ! 1378: continue; ! 1379: } ! 1380: if(buf[0]==0 && state==SMTP_STATE_DATA_HEADER) { ! 1381: state=SMTP_STATE_DATA_BODY; /* Null line separates header and body */ ! 1382: continue; ! 1383: } ! 1384: if(state==SMTP_STATE_DATA_BODY) { ! 1385: p=buf; ! 1386: if(*p=='.') p++; /* Transparency (RFC821 4.5.2) */ ! 1387: if(msgtxt!=NULL) ! 1388: fprintf(msgtxt, "%s\r\n", p); ! 1389: continue; ! 1390: } ! 1391: /* RFC822 Header parsing */ ! 1392: if(startup->options&MAIL_OPT_DEBUG_RX_HEADER) ! 1393: lprintf("%04d SMTP %s",socket, buf); ! 1394: ! 1395: if(!strnicmp(buf, "SUBJECT:",8)) { ! 1396: p=buf+8; ! 1397: while(*p && *p<=' ') p++; ! 1398: smb_hfield(&msg, SUBJECT, (ushort)strlen(p), p); ! 1399: strlwr(p); ! 1400: msg.idx.subj=crc16(p); ! 1401: continue; ! 1402: } ! 1403: if(!strnicmp(buf, "TO:",3)) { ! 1404: p=buf+3; ! 1405: while(*p && *p<=' ') p++; ! 1406: if(*p=='<') { ! 1407: p++; ! 1408: tp=strrchr(p,'>'); ! 1409: if(tp) *tp=0; ! 1410: } ! 1411: #if 0 ! 1412: if(!nettype) { ! 1413: nettype=NET_INTERNET; ! 1414: smb_hfield(&msg, RECIPIENTNETTYPE, nettype, &nettype); ! 1415: smb_hfield(&msg, RECIPIENTNETADDR, (ushort)strlen(p), p); ! 1416: } ! 1417: #endif ! 1418: continue; ! 1419: } ! 1420: if(!strnicmp(buf, "REPLY-TO:",9)) { ! 1421: p=buf+9; ! 1422: while(*p && *p<=' ') p++; ! 1423: if(*p=='<') { ! 1424: p++; ! 1425: tp=strchr(p,'>'); ! 1426: if(tp) *tp=0; ! 1427: } ! 1428: nettype=NET_INTERNET; ! 1429: smb_hfield(&msg, REPLYTONETTYPE, nettype, &nettype); ! 1430: smb_hfield(&msg, REPLYTONETADDR, (ushort)strlen(p), p); ! 1431: continue; ! 1432: } ! 1433: if(!strnicmp(buf, "FROM:",5)) { ! 1434: p=strchr(buf+5,'<'); ! 1435: if(p) { ! 1436: p++; ! 1437: tp=strchr(p,'>'); ! 1438: if(tp) *tp=0; ! 1439: sprintf(sender_addr,"%.*s",(int)sizeof(sender_addr)-1,p); ! 1440: } else { ! 1441: p=buf+5; ! 1442: while(*p && *p<=' ') p++; ! 1443: sprintf(sender_addr,"%.*s",(int)sizeof(sender_addr)-1,p); ! 1444: } ! 1445: nettype=NET_INTERNET; ! 1446: smb_hfield(&msg, SENDERNETTYPE, sizeof(nettype), &nettype); ! 1447: smb_hfield(&msg, SENDERNETADDR, (ushort)strlen(sender_addr), sender_addr); ! 1448: ! 1449: p=buf+5; ! 1450: while(*p && *p<=' ') p++; ! 1451: if(*p=='"') { ! 1452: p++; ! 1453: tp=strchr(p,'"'); ! 1454: } else if(*p=='<') { ! 1455: p++; ! 1456: tp=strchr(p,'>'); ! 1457: } else ! 1458: tp=strchr(p,'<'); ! 1459: if(tp) *tp=0; ! 1460: truncsp(p); ! 1461: sprintf(sender,"%.*s",(int)sizeof(sender)-1,p); ! 1462: smb_hfield(&msg, SENDER, (ushort)strlen(sender), sender); ! 1463: continue; ! 1464: } ! 1465: if(!strnicmp(buf, "DATE:",5)) { ! 1466: p=buf+5; ! 1467: while(*p && *p<=' ') p++; ! 1468: /* lprintf("Sent: %s",p); */ ! 1469: memset(&tm,0,sizeof(tm)); ! 1470: while(*p && !isdigit(*p)) p++; ! 1471: /* DAY */ ! 1472: tm.tm_mday=atoi(p); ! 1473: while(*p && isdigit(*p)) p++; ! 1474: /* MONTH */ ! 1475: while(*p && *p<=' ') p++; ! 1476: sprintf(month,"%3.3s",p); ! 1477: if(!stricmp(month,"jan")) ! 1478: tm.tm_mon=0; ! 1479: else if(!stricmp(month,"feb")) ! 1480: tm.tm_mon=1; ! 1481: else if(!stricmp(month,"mar")) ! 1482: tm.tm_mon=2; ! 1483: else if(!stricmp(month,"apr")) ! 1484: tm.tm_mon=3; ! 1485: else if(!stricmp(month,"may")) ! 1486: tm.tm_mon=4; ! 1487: else if(!stricmp(month,"jun")) ! 1488: tm.tm_mon=5; ! 1489: else if(!stricmp(month,"jul")) ! 1490: tm.tm_mon=6; ! 1491: else if(!stricmp(month,"aug")) ! 1492: tm.tm_mon=7; ! 1493: else if(!stricmp(month,"sep")) ! 1494: tm.tm_mon=8; ! 1495: else if(!stricmp(month,"oct")) ! 1496: tm.tm_mon=9; ! 1497: else if(!stricmp(month,"nov")) ! 1498: tm.tm_mon=10; ! 1499: else ! 1500: tm.tm_mon=11; ! 1501: p+=4; ! 1502: /* YEAR */ ! 1503: tm.tm_year=atoi(p); ! 1504: if(tm.tm_year>1900) ! 1505: tm.tm_year-=1900; ! 1506: while(*p && isdigit(*p)) p++; ! 1507: /* HOUR */ ! 1508: while(*p && *p<=' ') p++; ! 1509: tm.tm_hour=atoi(p); ! 1510: while(*p && isdigit(*p)) p++; ! 1511: /* MINUTE */ ! 1512: if(*p) p++; ! 1513: tm.tm_min=atoi(p); ! 1514: while(*p && isdigit(*p)) p++; ! 1515: /* SECONDS */ ! 1516: if(*p) p++; ! 1517: tm.tm_sec=atoi(p); ! 1518: while(*p && isdigit(*p)) p++; ! 1519: /* TIME ZONE */ ! 1520: while(*p && *p<=' ') p++; ! 1521: if(*p && (isdigit(*p) || *p=='-')) { /* HHMM or -HHMM format */ ! 1522: sprintf(str,"%.*s",*p=='-'? 3:2,p); ! 1523: msg.hdr.when_written.zone=atoi(str)*60; ! 1524: p+=(*p=='-') ? 3:2; ! 1525: msg.hdr.when_written.zone+=atoi(p); ! 1526: } ! 1527: else if(!strnicmp(p,"PDT",3)) ! 1528: msg.hdr.when_written.zone=(short)PDT; ! 1529: else if(!strnicmp(p,"MDT",3)) ! 1530: msg.hdr.when_written.zone=(short)MDT; ! 1531: else if(!strnicmp(p,"CDT",3)) ! 1532: msg.hdr.when_written.zone=(short)CDT; ! 1533: else if(!strnicmp(p,"EDT",3)) ! 1534: msg.hdr.when_written.zone=(short)EDT; ! 1535: else if(!strnicmp(p,"PST",3)) ! 1536: msg.hdr.when_written.zone=(short)PST; ! 1537: else if(!strnicmp(p,"MST",3)) ! 1538: msg.hdr.when_written.zone=(short)MST; ! 1539: else if(!strnicmp(p,"CST",3)) ! 1540: msg.hdr.when_written.zone=(short)CST; ! 1541: else if(!strnicmp(p,"EST",3)) ! 1542: msg.hdr.when_written.zone=(short)EST; ! 1543: msg.hdr.when_written.time=mktime(&tm); ! 1544: continue; ! 1545: } ! 1546: if(!strnicmp(buf, "MESSAGE-ID:",11)) { ! 1547: p=buf+11; ! 1548: while(*p && *p<=' ') p++; ! 1549: smb_hfield(&msg, RFC822MSGID, (ushort)strlen(p), p); ! 1550: continue; ! 1551: } ! 1552: if(!strnicmp(buf, "IN-REPLY-TO:",12)) { ! 1553: p=buf+12; ! 1554: while(*p && *p<=' ') p++; ! 1555: smb_hfield(&msg, RFC822REPLYID, (ushort)strlen(p), p); ! 1556: continue; ! 1557: } ! 1558: /* Fall-through */ ! 1559: smb_hfield(&msg, RFC822HEADER, (ushort)strlen(buf), buf); ! 1560: continue; ! 1561: } ! 1562: lprintf("%04d SMTP RX: %s", socket, buf); ! 1563: if(!strnicmp(buf,"HELO",4)) { ! 1564: p=buf+4; ! 1565: while(*p && *p<=' ') p++; ! 1566: sprintf(hello_name,"%.*s",(int)sizeof(hello_name)-1,p); ! 1567: sockprintf(socket,"250 %s",scfg.sys_inetaddr); ! 1568: esmtp=FALSE; ! 1569: state=SMTP_STATE_HELO; ! 1570: continue; ! 1571: } ! 1572: if(!strnicmp(buf,"EHLO",4)) { ! 1573: p=buf+4; ! 1574: while(*p && *p<=' ') p++; ! 1575: sprintf(hello_name,"%.*s",(int)sizeof(hello_name)-1,p); ! 1576: sockprintf(socket,"250 %s",scfg.sys_inetaddr); ! 1577: esmtp=TRUE; ! 1578: state=SMTP_STATE_HELO; ! 1579: continue; ! 1580: } ! 1581: if(!stricmp(buf,"QUIT")) { ! 1582: sockprintf(socket,"221 %s Service closing transmission channel",scfg.sys_inetaddr); ! 1583: break; ! 1584: } ! 1585: if(!stricmp(buf,"NOOP")) { ! 1586: sockprintf(socket, SMTP_OK); ! 1587: continue; ! 1588: } ! 1589: if(state<SMTP_STATE_HELO) { ! 1590: /* RFC 821 4.1.1 "The first command in a session must be the HELO command." */ ! 1591: lprintf("%04d !SMTP Missing HELO command",socket); ! 1592: sockprintf(socket, SMTP_BADSEQ); ! 1593: continue; ! 1594: } ! 1595: if(!stricmp(buf,"TURN")) { ! 1596: sockprintf(socket,"502 command not supported"); ! 1597: continue; ! 1598: } ! 1599: if(!stricmp(buf,"RSET")) { ! 1600: smb_freemsgmem(&msg); ! 1601: memset(&msg,0,sizeof(smbmsg_t)); /* Initialize message header */ ! 1602: reverse_path[0]=0; ! 1603: sender[0]=0; ! 1604: sender_addr[0]=0; ! 1605: sockprintf(socket,SMTP_OK); ! 1606: rewind(rcptlst); ! 1607: chsize(fileno(rcptlst),0); ! 1608: state=SMTP_STATE_HELO; ! 1609: continue; ! 1610: } ! 1611: if(!strnicmp(buf,"MAIL FROM:",10)) { ! 1612: smb_freemsgmem(&msg); ! 1613: memset(&msg,0,sizeof(smbmsg_t)); /* Initialize message header */ ! 1614: memcpy(msg.hdr.id,"SHD\x1a",4); ! 1615: msg.hdr.version=smb_ver(); ! 1616: msg.hdr.when_imported.time=time(NULL); ! 1617: msg.hdr.when_imported.zone=scfg.sys_timezone; ! 1618: p=buf+10; ! 1619: while(*p && *p<=' ') p++; ! 1620: sprintf(reverse_path,"%.*s",(int)sizeof(reverse_path)-1,p); ! 1621: sender[0]=0; ! 1622: sender_addr[0]=0; ! 1623: if(spy==NULL && trashcan(&scfg,reverse_path,"smtpspy")) { ! 1624: sprintf(str,"%sSMTPSPY.TXT", scfg.data_dir); ! 1625: spy=fopen(str,"a"); ! 1626: } ! 1627: sockprintf(socket,SMTP_OK); ! 1628: state=SMTP_STATE_MAIL_FROM; ! 1629: continue; ! 1630: } ! 1631: #if 0 /* No one uses this command */ ! 1632: if(!strnicmp(buf,"VRFY",4)) { ! 1633: p=buf+4; ! 1634: while(*p && *p<=' ') p++; ! 1635: if(*p==0) { ! 1636: sockprintf(socket,"550 No user specified."); ! 1637: continue; ! 1638: } ! 1639: #endif ! 1640: ! 1641: ! 1642: ! 1643: if(!strnicmp(buf,"RCPT TO:",8)) { ! 1644: ! 1645: if(state<SMTP_STATE_MAIL_FROM) { ! 1646: lprintf("%04d !SMTP Missing 'MAIL' command",socket); ! 1647: sockprintf(socket, SMTP_BADSEQ); ! 1648: continue; ! 1649: } ! 1650: ! 1651: sprintf(str,"%.*s",(int)sizeof(str)-1,buf+8); ! 1652: p=str; ! 1653: while(*p && *p<=' ') p++; ! 1654: ! 1655: if(*p=='<') p++; /* Skip '<' */ ! 1656: tp=strchr(str,'>'); /* Truncate '>' */ ! 1657: if(tp!=NULL) *tp=0; ! 1658: ! 1659: tp=strrchr(str,'@'); ! 1660: if(tp!=NULL) { ! 1661: ! 1662: /* RELAY */ ! 1663: if(stricmp(tp+1,scfg.sys_inetaddr) && ! 1664: resolve_ip(tp+1)!=server_addr.sin_addr.s_addr) { ! 1665: ! 1666: if(!trashcan(&scfg,host_name,"relay") && ! 1667: !trashcan(&scfg,host_ip,"relay")) { ! 1668: lprintf("%04d !SMTP ILLEGAL RELAY ATTEMPT from %s [%s] to %s" ! 1669: ,socket, host_name, host_ip, tp+1); ! 1670: sockprintf(socket, "550 Relay not allowed."); ! 1671: continue; ! 1672: } ! 1673: ! 1674: lprintf("%04d SMTP Relaying to external mail service: %s" ! 1675: ,socket, tp+1); ! 1676: ! 1677: fprintf(rcptlst,"0\n%.*s\n%.*s\n" ! 1678: ,(int)sizeof(rcpt_name)-1,p ! 1679: ,(int)sizeof(rcpt_addr)-1,p); ! 1680: ! 1681: sockprintf(socket,SMTP_OK); ! 1682: state=SMTP_STATE_RCPT_TO; ! 1683: continue; ! 1684: } ! 1685: *tp=0; /* truncate at '@' */ ! 1686: } ! 1687: while(*p && !isalnum(*p)) p++; /* Skip '<' or '"' */ ! 1688: tp=strrchr(p,'"'); ! 1689: if(tp!=NULL) *tp=0; /* truncate at '"' */ ! 1690: ! 1691: p=alias(p,alias_buf); ! 1692: ! 1693: /* RX by sysop alias */ ! 1694: if(!stricmp(p,"SYSOP") || !stricmp(p,scfg.sys_id) ! 1695: || !stricmp(p,"POSTMASTER") || !stricmp(p,scfg.sys_op)) ! 1696: usernum=1; ! 1697: else if(startup->options&MAIL_OPT_ALLOW_RX_BY_NUMBER ! 1698: && isdigit(*p)) { ! 1699: usernum=atoi(p); /* RX by user number */ ! 1700: /* verify usernum */ ! 1701: username(&scfg,usernum,str); ! 1702: if(!str[0] || !stricmp(str,"DELETED USER")) ! 1703: usernum=0; ! 1704: p=str; ! 1705: } else { ! 1706: usernum=matchuser(&scfg,p); /* RX by "user alias", "user.alias" or "user_alias" */ ! 1707: ! 1708: if(!usernum) { /* RX by "real name", "real.name", or "sysop.alias" */ ! 1709: ! 1710: /* convert "user.name" to "user name" */ ! 1711: sprintf(rcpt_name,"%.*s",sizeof(rcpt_name)-1,p); ! 1712: for(tp=rcpt_name;*tp;tp++) ! 1713: if(*tp=='.') *tp=' '; ! 1714: ! 1715: if(!stricmp(rcpt_name,scfg.sys_op)) ! 1716: usernum=1; /* RX by "sysop.alias" */ ! 1717: ! 1718: if(!usernum) /* RX by "real name" */ ! 1719: usernum=userdatdupe(&scfg, 0, U_NAME, LEN_NAME, p, FALSE); ! 1720: ! 1721: if(!usernum) /* RX by "real.name" */ ! 1722: usernum=userdatdupe(&scfg, 0, U_NAME, LEN_NAME, rcpt_name, FALSE); ! 1723: } ! 1724: } ! 1725: if(!usernum) { ! 1726: lprintf("%04d !SMTP UNKNOWN USER: %s", socket, buf+8); ! 1727: sockprintf(socket, "550 Unknown User: %s", buf+8); ! 1728: continue; ! 1729: } ! 1730: user.number=usernum; ! 1731: if((i=getuserdat(&scfg, &user))!=0) { ! 1732: lprintf("%04d !SMTP ERROR %d getting data on user #%u (%s)" ! 1733: ,socket, i, usernum, p); ! 1734: sockprintf(socket, "550 Unknown User: %s", buf+8); ! 1735: continue; ! 1736: } ! 1737: if(user.misc&(DELETED|INACTIVE)) { ! 1738: lprintf("%04d !SMTP DELETED or INACTIVE user #%u (%s)" ! 1739: ,socket, usernum, p); ! 1740: sockprintf(socket, "550 Unknown User: %s", buf+8); ! 1741: continue; ! 1742: } ! 1743: #if 0 /* implement later */ ! 1744: if(useron.etoday>=cfg.level_emailperday[useron.level] ! 1745: && !(useron.rest&FLAG('Q'))) { ! 1746: bputs(text[TooManyEmailsToday]); ! 1747: continue; } ! 1748: #endif ! 1749: ! 1750: fprintf(rcptlst,"%u\n%.*s\n",user.number,(int)sizeof(rcpt_name)-1,p); ! 1751: ! 1752: /* Forward to Internet */ ! 1753: tp=strrchr(user.netmail,'@'); ! 1754: if(scfg.sys_misc&SM_FWDTONET && user.misc&NETMAIL ! 1755: && tp && strchr(tp,'.') && !strchr(tp,'/') ! 1756: && !strstr(tp,scfg.sys_inetaddr)) { ! 1757: lprintf("%04d SMTP Forwarding to: %s" ! 1758: ,socket, user.netmail); ! 1759: fprintf(rcptlst,"%s\n",user.netmail); ! 1760: sockprintf(socket,"251 User not local; will forward to %s", user.netmail); ! 1761: } else { /* Local (no-forward) */ ! 1762: fprintf(rcptlst,"#%u\n",usernum); ! 1763: sockprintf(socket,SMTP_OK); ! 1764: } ! 1765: state=SMTP_STATE_RCPT_TO; ! 1766: continue; ! 1767: } ! 1768: if(!strnicmp(buf,"DATA",4)) { ! 1769: if(state<SMTP_STATE_RCPT_TO) { ! 1770: lprintf("%04d !SMTP Missing 'RCPT TO' command", socket); ! 1771: sockprintf(socket, SMTP_BADSEQ); ! 1772: continue; ! 1773: } ! 1774: if(msgtxt!=NULL) ! 1775: fclose(msgtxt); ! 1776: sprintf(msgtxt_fname,"%sSMTP%d.RX", scfg.data_dir, socket); ! 1777: if((msgtxt=fopen(msgtxt_fname,"w+b"))==NULL) { ! 1778: lprintf("%04d !SMTP Error %d opening %s" ! 1779: ,socket, errno, msgtxt_fname); ! 1780: sockprintf(socket, "452 Insufficient system storage"); ! 1781: continue; ! 1782: } ! 1783: sockprintf(socket, "354 send the mail data, end with <CRLF>.<CRLF>"); ! 1784: state=SMTP_STATE_DATA_HEADER; ! 1785: continue; ! 1786: } ! 1787: sockprintf(socket,"500 Syntax error"); ! 1788: lprintf("%04d !SMTP UNSUPPORTED COMMAND: %s", socket, buf); ! 1789: } ! 1790: ! 1791: /* Free up resources here */ ! 1792: mail_close_socket(socket); ! 1793: ! 1794: smb_freemsgmem(&msg); ! 1795: ! 1796: if(msgtxt!=NULL) { ! 1797: fclose(msgtxt); ! 1798: if(!(startup->options&MAIL_OPT_DEBUG_RX_BODY)) ! 1799: unlink(msgtxt_fname); ! 1800: } ! 1801: if(rcptlst!=NULL) { ! 1802: fclose(rcptlst); ! 1803: unlink(rcptlst_fname); ! 1804: } ! 1805: if(spy!=NULL) ! 1806: fclose(spy); ! 1807: ! 1808: status(STATUS_WFC); ! 1809: ! 1810: lprintf("%04d SMTP RX Session thread terminated", socket); ! 1811: active_clients--; ! 1812: update_clients(); ! 1813: client_off(socket); ! 1814: ! 1815: thread_down(); ! 1816: } ! 1817: ! 1818: BOOL bounce(smb_t* smb, smbmsg_t* msg, char* err, BOOL immediate) ! 1819: { ! 1820: char str[128],full_err[512]; ! 1821: int i; ! 1822: ushort agent=AGENT_PROCESS; ! 1823: smbmsg_t newmsg; ! 1824: ! 1825: if((i=smb_lockmsghdr(smb,msg))!=0) { ! 1826: lprintf("0000 !BOUNCE ERROR %d locking message header #%lu" ! 1827: ,i,msg->hdr.number); ! 1828: return(FALSE); ! 1829: } ! 1830: ! 1831: msg->hdr.delivery_attempts++; ! 1832: if((i=smb_putmsg(smb,msg))!=0) { ! 1833: lprintf("0000 !BOUNCE ERROR %d incrementing delivery attempt counter",i); ! 1834: smb_unlockmsghdr(smb,msg); ! 1835: return(FALSE); ! 1836: } ! 1837: ! 1838: lprintf("0000 !Delivery attempt #%u FAILED for message #%lu from %s to %s" ! 1839: ,msg->hdr.delivery_attempts, msg->hdr.number ! 1840: ,msg->from, msg->to_net.addr); ! 1841: ! 1842: if(!immediate && msg->hdr.delivery_attempts<startup->max_delivery_attempts) { ! 1843: smb_unlockmsghdr(smb,msg); ! 1844: return(TRUE); ! 1845: } ! 1846: ! 1847: lprintf("0000 !Bouncing message back to %s", msg->from); ! 1848: ! 1849: newmsg=*msg; ! 1850: /* Mark original message as deleted */ ! 1851: msg->hdr.attr|=MSG_DELETE; ! 1852: msg->idx.attr=msg->hdr.attr; ! 1853: if((i=smb_putmsg(smb,msg))!=0) { ! 1854: lprintf("0000 !BOUNCE ERROR %d deleting message",i); ! 1855: smb_unlockmsghdr(smb,msg); ! 1856: return(FALSE); ! 1857: } ! 1858: smb_unlockmsghdr(smb,msg); ! 1859: ! 1860: newmsg.hfield=NULL; ! 1861: newmsg.hfield_dat=NULL; ! 1862: newmsg.total_hfields=0; ! 1863: newmsg.idx.to=newmsg.idx.from; ! 1864: newmsg.idx.from=0; ! 1865: newmsg.hdr.delivery_attempts=0; ! 1866: ! 1867: smb_hfield(&newmsg, RECIPIENT, (ushort)strlen(newmsg.from), newmsg.from); ! 1868: if(newmsg.idx.to) { ! 1869: sprintf(str,"%u",newmsg.idx.to); ! 1870: smb_hfield(&newmsg, RECIPIENTEXT, (ushort)strlen(str), str); ! 1871: } ! 1872: smb_hfield(&newmsg, RECIPIENTAGENT, sizeof(ushort), &newmsg.from_agent); ! 1873: smb_hfield(&newmsg, RECIPIENTNETTYPE, sizeof(newmsg.from_net.type), &newmsg.from_net.type); ! 1874: if(newmsg.from_net.type) ! 1875: smb_hfield(&newmsg, RECIPIENTNETADDR, (ushort)strlen(newmsg.from_net.addr) ! 1876: ,newmsg.from_net.addr); ! 1877: strcpy(str,"Mail Delivery Subsystem"); ! 1878: smb_hfield(&newmsg, SENDER, (ushort)strlen(str), str); ! 1879: smb_hfield(&newmsg, SENDERAGENT, sizeof(agent), &agent); ! 1880: ! 1881: /* Put error message in subject for now */ ! 1882: sprintf(full_err,"Delivery failure of message to %s after %u attempts: %s" ! 1883: ,(char*)msg->to_net.addr, msg->hdr.delivery_attempts, err); ! 1884: smb_hfield(&newmsg, SUBJECT, (ushort)strlen(full_err), full_err); ! 1885: ! 1886: if((i=smb_addmsghdr(smb,&newmsg,SMB_SELFPACK))!=0) ! 1887: lprintf("0000 !BOUNCE ERROR %d adding message header",i); ! 1888: ! 1889: newmsg.dfield=NULL; /* Don't double-free the data fields */ ! 1890: newmsg.hdr.total_dfields=0; ! 1891: smb_freemsgmem(&newmsg); ! 1892: ! 1893: return(TRUE); ! 1894: } ! 1895: ! 1896: #ifdef __BORLANDC__ ! 1897: #pragma argsused ! 1898: #endif ! 1899: static void sendmail_thread(void* arg) ! 1900: { ! 1901: int i,j; ! 1902: char to[128]; ! 1903: char mx[128]; ! 1904: char mx2[128]; ! 1905: char err[128]; ! 1906: char buf[512]; ! 1907: char fromaddr[256]; ! 1908: char* server; ! 1909: char* msgtxt=NULL; ! 1910: char* p; ! 1911: ulong offset; ! 1912: ulong last_msg=0; ! 1913: ulong total_msgs; ! 1914: ulong ip_addr; ! 1915: ulong dns; ! 1916: BOOL success; ! 1917: SOCKET sock=INVALID_SOCKET; ! 1918: SOCKADDR_IN addr; ! 1919: SOCKADDR_IN server_addr; ! 1920: time_t last_scan=0; ! 1921: smb_t smb; ! 1922: smbmsg_t msg; ! 1923: ! 1924: sendmail_running=TRUE; ! 1925: ! 1926: thread_up(); ! 1927: ! 1928: lprintf("0000 SendMail thread started"); ! 1929: ! 1930: memset(&msg,0,sizeof(msg)); ! 1931: memset(&smb,0,sizeof(smb)); ! 1932: ! 1933: while(server_socket!=INVALID_SOCKET) { ! 1934: ! 1935: if(startup->options&MAIL_OPT_NO_SENDMAIL) { ! 1936: mswait(1000); ! 1937: continue; ! 1938: } ! 1939: ! 1940: if(active_sendmail!=0) { ! 1941: active_sendmail=0; ! 1942: update_clients(); ! 1943: } ! 1944: ! 1945: smb_close(&smb); ! 1946: ! 1947: if(sock!=INVALID_SOCKET) { ! 1948: mail_close_socket(sock); ! 1949: sock=INVALID_SOCKET; ! 1950: } ! 1951: ! 1952: if(msgtxt!=NULL) { ! 1953: smb_freemsgtxt(msgtxt); ! 1954: msgtxt=NULL; ! 1955: } ! 1956: ! 1957: smb_freemsgmem(&msg); ! 1958: ! 1959: mswait(3000); ! 1960: ! 1961: sprintf(smb.file,"%smail",scfg.data_dir); ! 1962: if((i=smb_open(&smb))!=0) ! 1963: continue; ! 1964: if((i=smb_locksmbhdr(&smb))!=0) ! 1965: continue; ! 1966: if((i=smb_getstatus(&smb))!=0) { ! 1967: smb_unlocksmbhdr(&smb); ! 1968: continue; ! 1969: } ! 1970: smb_unlocksmbhdr(&smb); ! 1971: if(smb.status.last_msg==last_msg && time(NULL)-last_scan<startup->rescan_frequency) ! 1972: continue; ! 1973: last_msg=smb.status.last_msg; ! 1974: last_scan=time(NULL); ! 1975: total_msgs=smb.status.total_msgs; ! 1976: smb_rewind(smb.sid_fp); ! 1977: for(offset=0;offset<total_msgs;offset++) { ! 1978: ! 1979: if(active_sendmail!=0) { ! 1980: active_sendmail=0; ! 1981: update_clients(); ! 1982: } ! 1983: ! 1984: if(sock!=INVALID_SOCKET) { ! 1985: mail_close_socket(sock); ! 1986: sock=INVALID_SOCKET; ! 1987: } ! 1988: ! 1989: if(msgtxt!=NULL) { ! 1990: smb_freemsgtxt(msgtxt); ! 1991: msgtxt=NULL; ! 1992: } ! 1993: ! 1994: smb_freemsgmem(&msg); ! 1995: ! 1996: smb_fseek(smb.sid_fp, offset*sizeof(msg.idx), SEEK_SET); ! 1997: if(smb_fread(&msg.idx, sizeof(msg.idx), smb.sid_fp) != sizeof(msg.idx)) ! 1998: break; ! 1999: if(msg.idx.attr&MSG_DELETE) /* Marked for deletion */ ! 2000: continue; ! 2001: if(msg.idx.to) /* Local */ ! 2002: continue; ! 2003: msg.offset=offset; ! 2004: ! 2005: if((i=smb_lockmsghdr(&smb,&msg))!=0) { ! 2006: lprintf("0000 !SEND ERROR %d locking message header #%lu" ! 2007: ,i,msg.idx.number); ! 2008: continue; ! 2009: } ! 2010: if((i=smb_getmsghdr(&smb,&msg))!=0) { ! 2011: smb_unlockmsghdr(&smb,&msg); ! 2012: lprintf("0000 !SEND ERROR %d reading message header #%lu" ! 2013: ,i,msg.idx.number); ! 2014: continue; ! 2015: } ! 2016: smb_unlockmsghdr(&smb,&msg); ! 2017: ! 2018: if(msg.to_net.type!=NET_INTERNET) ! 2019: continue; ! 2020: ! 2021: active_sendmail=1; ! 2022: update_clients(); ! 2023: ! 2024: lprintf("0000 SEND Message #%lu from %s to %s" ! 2025: ,msg.hdr.number, msg.from, msg.to_net.addr); ! 2026: status("SendMail"); ! 2027: #ifdef _WIN32 ! 2028: if(startup->outbound_sound[0] && !(startup->options&MAIL_OPT_MUTE)) ! 2029: PlaySound(startup->outbound_sound, NULL, SND_ASYNC|SND_FILENAME); ! 2030: #endif ! 2031: ! 2032: lprintf("0000 SEND getting message text"); ! 2033: if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_TAILS))==NULL) { ! 2034: lprintf("0000 !SEND ERROR retrieving message text"); ! 2035: continue; ! 2036: } ! 2037: ! 2038: if(startup->options&MAIL_OPT_RELAY_TX) ! 2039: server=startup->relay_server; ! 2040: else { ! 2041: sprintf(to,"%.*s",(int)sizeof(to)-1,(char*)msg.to_net.addr); ! 2042: p=strrchr(to,'>'); /* Truncate '>' */ ! 2043: if(p!=NULL) *p=0; ! 2044: ! 2045: p=strrchr(to,'@'); ! 2046: if(p==NULL) { ! 2047: lprintf("0000 !SEND INVALID destination address: %s", to); ! 2048: sprintf(err,"Invalid destination address: %s", to); ! 2049: bounce(&smb,&msg,err,TRUE); ! 2050: continue; ! 2051: } ! 2052: if((dns=resolve_ip(startup->dns_server))==0) ! 2053: continue; ! 2054: p++; ! 2055: lprintf("0000 SEND getting MX records for %s from %s",p,startup->dns_server); ! 2056: if((i=dns_getmx(p, mx, mx2, startup->interface_addr, dns ! 2057: ,startup->options&MAIL_OPT_USE_TCP_DNS ? TRUE : FALSE))!=0) { ! 2058: lprintf("0000 !SEND ERROR %d obtaining MX records for %s from %s" ! 2059: ,i,p,startup->dns_server); ! 2060: sprintf(err,"Error %d obtaining MX record for %s",i,p); ! 2061: bounce(&smb,&msg,err,FALSE); ! 2062: continue; ! 2063: } ! 2064: server=mx; ! 2065: } ! 2066: ! 2067: ! 2068: lprintf("0000 SEND opening socket"); ! 2069: if((sock=mail_open_socket(SOCK_STREAM))==INVALID_SOCKET) { ! 2070: lprintf("0000 !SEND ERROR %d opening socket", ERROR_VALUE); ! 2071: continue; ! 2072: } ! 2073: ! 2074: lprintf("%04d SEND socket opened",sock); ! 2075: ! 2076: memset(&addr,0,sizeof(addr)); ! 2077: addr.sin_addr.s_addr = htonl(startup->interface_addr); ! 2078: addr.sin_family = AF_INET; ! 2079: ! 2080: lprintf("%04d SEND binding socket",sock); ! 2081: if((i=bind(sock, (struct sockaddr *) &addr, sizeof (addr)))!=0) { ! 2082: lprintf("%04d !SEND ERROR %d (%d) binding socket", sock, i, ERROR_VALUE); ! 2083: continue; ! 2084: } ! 2085: ! 2086: strcpy(err,"UNKNOWN ERROR"); ! 2087: success=FALSE; ! 2088: for(j=0;j<2 && !success;j++) { ! 2089: if(j) { ! 2090: if(startup->options&MAIL_OPT_RELAY_TX || !mx2[0]) ! 2091: break; ! 2092: server=mx2; /* Give second mx record a try */ ! 2093: } ! 2094: ! 2095: lprintf("%04d SEND resolving SMTP host name: %s", sock, server); ! 2096: ip_addr=resolve_ip(server); ! 2097: if(!ip_addr) { ! 2098: sprintf(err,"Failed to resolve SMTP host name: %s",server); ! 2099: continue; ! 2100: } ! 2101: ! 2102: memset(&server_addr,0,sizeof(server_addr)); ! 2103: server_addr.sin_addr.s_addr = ip_addr; ! 2104: server_addr.sin_family = AF_INET; ! 2105: if(startup->options&MAIL_OPT_RELAY_TX) ! 2106: server_addr.sin_port = htons(startup->relay_port); ! 2107: else ! 2108: server_addr.sin_port = htons(IPPORT_SMTP); ! 2109: ! 2110: lprintf("%04d SEND connecting to port %u on %s [%s]" ! 2111: ,sock ! 2112: ,ntohs(server_addr.sin_port) ! 2113: ,server,inet_ntoa(server_addr.sin_addr)); ! 2114: if((i=connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)))!=0) { ! 2115: lprintf("%04d !SEND ERROR %d (%d) connecting to SMTP server: %s" ! 2116: ,sock ! 2117: ,i,ERROR_VALUE, server); ! 2118: sprintf(err,"Error %d connecting to SMTP server: %s" ! 2119: ,(int)ERROR_VALUE,server); ! 2120: continue; ! 2121: } ! 2122: success=TRUE; ! 2123: } ! 2124: if(!success) { /* Failed to send, so bounce */ ! 2125: bounce(&smb,&msg,err,FALSE); ! 2126: continue; ! 2127: } ! 2128: ! 2129: lprintf("%04d SEND connected to %s",sock,server); ! 2130: ! 2131: /* HELO */ ! 2132: if(!sockgetrsp(sock,"220",buf,sizeof(buf))) { ! 2133: sprintf(err,"%s replied with '%s' instead of 220",server,buf); ! 2134: bounce(&smb,&msg,err,buf[0]=='5'); ! 2135: continue; ! 2136: } ! 2137: sockprintf(sock,"HELO %s",scfg.sys_inetaddr); ! 2138: if(!sockgetrsp(sock,"250", buf, sizeof(buf))) { ! 2139: sprintf(err,"%s replied with '%s' instead of 250",server,buf); ! 2140: bounce(&smb,&msg,err,buf[0]=='5'); ! 2141: continue; ! 2142: } ! 2143: /* MAIL */ ! 2144: if(msg.from_net.type==NET_INTERNET) ! 2145: strcpy(fromaddr,msg.from_net.addr); ! 2146: else ! 2147: usermailaddr(fromaddr,msg.from); ! 2148: if(fromaddr[0]=='<') ! 2149: sockprintf(sock,"MAIL FROM: %s",fromaddr); ! 2150: else ! 2151: sockprintf(sock,"MAIL FROM: <%s>",fromaddr); ! 2152: if(!sockgetrsp(sock,"250", buf, sizeof(buf))) { ! 2153: sprintf(err,"%s replied with '%s' instead of 250",server,buf); ! 2154: bounce(&smb,&msg,err,buf[0]=='5'); ! 2155: continue; ! 2156: } ! 2157: /* RCPT */ ! 2158: if(*((char*)msg.to_net.addr)=='<') ! 2159: sockprintf(sock,"RCPT TO: %s", (char*)msg.to_net.addr); ! 2160: else ! 2161: sockprintf(sock,"RCPT TO: <%s>", (char*)msg.to_net.addr); ! 2162: if(!sockgetrsp(sock,"250", buf, sizeof(buf))) { ! 2163: sprintf(err,"%s replied with '%s' instead of 250",server,buf); ! 2164: bounce(&smb,&msg,err,buf[0]=='5'); ! 2165: continue; ! 2166: } ! 2167: /* DATA */ ! 2168: sockprintf(sock,"DATA"); ! 2169: if(!sockgetrsp(sock,"354", buf, sizeof(buf))) { ! 2170: sprintf(err,"%s replied with '%s' instead of 354",server,buf); ! 2171: bounce(&smb,&msg,err,buf[0]=='5'); ! 2172: continue; ! 2173: } ! 2174: lprintf("%04d SEND sending message text (%u bytes)" ! 2175: ,sock, strlen(msgtxt)); ! 2176: sockmsgtxt(sock,&msg,msgtxt,fromaddr,-1); ! 2177: if(!sockgetrsp(sock,"250", buf, sizeof(buf))) { ! 2178: sprintf(err,"%s replied with '%s' instead of 250",server,buf); ! 2179: bounce(&smb,&msg,err,buf[0]=='5'); ! 2180: continue; ! 2181: } ! 2182: lprintf("%04d SEND message transfer complete", sock); ! 2183: ! 2184: msg.hdr.attr|=MSG_DELETE; ! 2185: msg.idx.attr=msg.hdr.attr; ! 2186: if((i=smb_lockmsghdr(&smb,&msg))!=0) ! 2187: lprintf("%04d !SEND ERROR %d locking message header #%lu" ! 2188: ,sock ! 2189: ,i,msg.hdr.number); ! 2190: if((i=smb_putmsg(&smb,&msg))!=0) ! 2191: lprintf("%04d !SEND ERROR %d deleting message #%lu" ! 2192: ,sock ! 2193: ,i,msg.hdr.number); ! 2194: smb_unlockmsghdr(&smb,&msg); ! 2195: ! 2196: /* QUIT */ ! 2197: sockprintf(sock,"QUIT"); ! 2198: sockgetrsp(sock,"221", buf, sizeof(buf)); ! 2199: mail_close_socket(sock); ! 2200: sock=INVALID_SOCKET; ! 2201: } ! 2202: status(STATUS_WFC); ! 2203: } ! 2204: if(sock!=INVALID_SOCKET) ! 2205: mail_close_socket(sock); ! 2206: ! 2207: smb_freemsgtxt(msgtxt); ! 2208: smb_freemsgmem(&msg); ! 2209: smb_close(&smb); ! 2210: ! 2211: lprintf("0000 SendMail thread terminated"); ! 2212: ! 2213: sendmail_running=FALSE; ! 2214: ! 2215: thread_down(); ! 2216: } ! 2217: ! 2218: void DLLCALL mail_terminate(void) ! 2219: { ! 2220: if(server_socket!=INVALID_SOCKET) { ! 2221: lprintf("%04d MAIL Terminate: closing socket",server_socket); ! 2222: mail_close_socket(server_socket); ! 2223: server_socket=INVALID_SOCKET; ! 2224: } ! 2225: } ! 2226: ! 2227: static void cleanup(int code) ! 2228: { ! 2229: if(server_socket!=INVALID_SOCKET) { ! 2230: mail_close_socket(server_socket); ! 2231: server_socket=INVALID_SOCKET; ! 2232: } ! 2233: ! 2234: if(pop3_socket!=INVALID_SOCKET) { ! 2235: mail_close_socket(pop3_socket); ! 2236: pop3_socket=INVALID_SOCKET; ! 2237: } ! 2238: ! 2239: update_clients(); ! 2240: ! 2241: #ifdef _WINSOCKAPI_ ! 2242: if(WSAInitialized && WSACleanup()!=0) ! 2243: lprintf("0000 !WSACleanup ERROR %d",ERROR_VALUE); ! 2244: #endif ! 2245: ! 2246: lprintf("#### Mail Server thread terminated"); ! 2247: status("Down"); ! 2248: if(startup!=NULL && startup->terminated!=NULL) ! 2249: startup->terminated(code); ! 2250: thread_down(); ! 2251: } ! 2252: ! 2253: char* DLLCALL mail_ver(void) ! 2254: { ! 2255: static char ver[256]; ! 2256: char compiler[32]; ! 2257: ! 2258: COMPILER_DESC(compiler); ! 2259: ! 2260: sprintf(ver,"Synchronet Mail Server v%s%s SMBLIB v%s " ! 2261: "Compiled %s %s with %s" ! 2262: ,MAIL_VERSION ! 2263: #ifdef _DEBUG ! 2264: ," Debug" ! 2265: #else ! 2266: ,"" ! 2267: #endif ! 2268: ,smb_lib_ver() ! 2269: ,__DATE__, __TIME__, compiler ! 2270: ); ! 2271: ! 2272: return(ver); ! 2273: } ! 2274: ! 2275: void DLLCALL mail_server(void* arg) ! 2276: { ! 2277: char compiler[32]; ! 2278: SOCKADDR_IN server_addr; ! 2279: SOCKADDR_IN client_addr; ! 2280: int client_addr_len; ! 2281: SOCKET client_socket; ! 2282: int i; ! 2283: int result; ! 2284: ulong l; ! 2285: time_t t; ! 2286: time_t start; ! 2287: LINGER linger; ! 2288: fd_set socket_set; ! 2289: SOCKET high_socket_set; ! 2290: pop3_t* pop3; ! 2291: smtp_t* smtp; ! 2292: struct timeval tv; ! 2293: ! 2294: startup=(mail_startup_t*)arg; ! 2295: ! 2296: if(startup==NULL) { ! 2297: sbbs_beep(100,500); ! 2298: fprintf(stderr, "No startup structure passed!\n"); ! 2299: return; ! 2300: } ! 2301: ! 2302: if(startup->size!=sizeof(mail_startup_t)) { /* verify size */ ! 2303: sbbs_beep(100,500); ! 2304: sbbs_beep(300,500); ! 2305: sbbs_beep(100,500); ! 2306: fprintf(stderr, "Invalid startup structure!\n"); ! 2307: return; ! 2308: } ! 2309: ! 2310: if(startup->relay_port==0) ! 2311: startup->relay_port=IPPORT_SMTP; ! 2312: ! 2313: thread_up(); ! 2314: ! 2315: status("Initializing"); ! 2316: ! 2317: #ifdef __unix__ /* Ignore "Broken Pipe" signal */ ! 2318: signal(SIGPIPE,SIG_IGN); ! 2319: #endif ! 2320: ! 2321: lprintf("Synchronet Mail Server Version %s%s" ! 2322: ,MAIL_VERSION ! 2323: #ifdef _DEBUG ! 2324: ," Debug" ! 2325: #else ! 2326: ,"" ! 2327: #endif ! 2328: ); ! 2329: ! 2330: COMPILER_DESC(compiler); ! 2331: ! 2332: lprintf("Compiled %s %s with %s", __DATE__, __TIME__, compiler); ! 2333: ! 2334: lprintf("SMBLIB v%s (format %x.%02x)",smb_lib_ver(),smb_ver()>>8,smb_ver()&0xff); ! 2335: ! 2336: srand(time(NULL)); ! 2337: ! 2338: if(!(startup->options&MAIL_OPT_LOCAL_TIMEZONE)) { ! 2339: if(PUTENV("TZ=UCT0")) ! 2340: lprintf("!putenv() FAILED"); ! 2341: tzset(); ! 2342: ! 2343: if((t=checktime())!=0) { /* Check binary time */ ! 2344: lprintf("!TIME PROBLEM (%ld)",t); ! 2345: cleanup(1); ! 2346: return; ! 2347: } ! 2348: } ! 2349: ! 2350: if(!winsock_startup()) { ! 2351: cleanup(1); ! 2352: return; ! 2353: } ! 2354: ! 2355: t=time(NULL); ! 2356: lprintf("Initializing on %.24s with options: %lx" ! 2357: ,ctime(&t),startup->options); ! 2358: ! 2359: /* Initial configuration and load from CNF files */ ! 2360: memset(&scfg, 0, sizeof(scfg)); ! 2361: sprintf(scfg.ctrl_dir, "%.*s", (int)sizeof(scfg.ctrl_dir)-1 ! 2362: ,startup->ctrl_dir); ! 2363: lprintf("Loading configuration files from %s", scfg.ctrl_dir); ! 2364: if(!load_cfg(&scfg, NULL)) { ! 2365: lprintf("!Failed to load configuration files"); ! 2366: cleanup(1); ! 2367: return; ! 2368: } ! 2369: ! 2370: if(!startup->max_clients) { ! 2371: startup->max_clients=scfg.sys_nodes; ! 2372: if(startup->max_clients<10) ! 2373: startup->max_clients=10; ! 2374: } ! 2375: ! 2376: lprintf("Maximum clients: %u",startup->max_clients); ! 2377: ! 2378: if(!startup->max_inactivity) ! 2379: startup->max_inactivity=120; /* seconds */ ! 2380: ! 2381: lprintf("Maximum inactivity: %u seconds",startup->max_inactivity); ! 2382: ! 2383: active_clients=0; ! 2384: update_clients(); ! 2385: ! 2386: /* open a socket and wait for a client */ ! 2387: ! 2388: server_socket = mail_open_socket(SOCK_STREAM); ! 2389: ! 2390: if (server_socket == INVALID_SOCKET) { ! 2391: lprintf("!ERROR %d opening socket", ERROR_VALUE); ! 2392: cleanup(1); ! 2393: return; ! 2394: } ! 2395: ! 2396: lprintf("%04d SMTP socket opened",server_socket); ! 2397: ! 2398: #if 1 ! 2399: linger.l_onoff=TRUE; ! 2400: linger.l_linger=5; /* seconds */ ! 2401: ! 2402: result = setsockopt (server_socket, SOL_SOCKET, SO_LINGER ! 2403: ,(char *)&linger, sizeof(linger)); ! 2404: ! 2405: if (result != 0) { ! 2406: lprintf("%04d !ERROR %d (%d) setting socket options" ! 2407: ,server_socket, result, ERROR_VALUE); ! 2408: cleanup(1); ! 2409: return; ! 2410: } ! 2411: #endif ! 2412: ! 2413: /*****************************/ ! 2414: /* Listen for incoming calls */ ! 2415: /*****************************/ ! 2416: memset(&server_addr, 0, sizeof(server_addr)); ! 2417: ! 2418: server_addr.sin_addr.s_addr = htonl(startup->interface_addr); ! 2419: server_addr.sin_family = AF_INET; ! 2420: server_addr.sin_port = htons(startup->smtp_port); ! 2421: ! 2422: result = bind(server_socket, (struct sockaddr *) &server_addr ! 2423: ,sizeof (server_addr)); ! 2424: ! 2425: if (result != 0) { ! 2426: lprintf("%04d !ERROR %d (%d) binding SMTP socket to port %u" ! 2427: ,server_socket, result, ERROR_VALUE, startup->smtp_port); ! 2428: cleanup(1); ! 2429: return; ! 2430: } ! 2431: ! 2432: lprintf("%04d SMTP socket bound to port %u" ! 2433: ,server_socket, startup->smtp_port); ! 2434: ! 2435: result = listen (server_socket, 1); ! 2436: ! 2437: if (result != 0) { ! 2438: lprintf("%04d !ERROR %d (%d) listening on socket" ! 2439: ,server_socket, result, ERROR_VALUE); ! 2440: cleanup(1); ! 2441: return; ! 2442: } ! 2443: ! 2444: if(startup->options&MAIL_OPT_ALLOW_POP3) { ! 2445: ! 2446: /* open a socket and wait for a client */ ! 2447: ! 2448: pop3_socket = mail_open_socket(SOCK_STREAM); ! 2449: ! 2450: if (pop3_socket == INVALID_SOCKET) { ! 2451: lprintf("!ERROR %d opening POP3 socket", ERROR_VALUE); ! 2452: cleanup(1); ! 2453: return; ! 2454: } ! 2455: ! 2456: lprintf("%04d POP3 socket opened",pop3_socket); ! 2457: ! 2458: /*****************************/ ! 2459: /* Listen for incoming calls */ ! 2460: /*****************************/ ! 2461: memset(&server_addr, 0, sizeof(server_addr)); ! 2462: ! 2463: server_addr.sin_addr.s_addr = htonl(startup->interface_addr); ! 2464: server_addr.sin_family = AF_INET; ! 2465: server_addr.sin_port = htons(startup->pop3_port); ! 2466: ! 2467: result = bind(pop3_socket, (struct sockaddr *) &server_addr ! 2468: ,sizeof (server_addr)); ! 2469: ! 2470: if (result != 0) { ! 2471: lprintf("%04d !ERROR %d (%d) binding POP3 socket to port %u" ! 2472: ,pop3_socket, result, ERROR_VALUE, startup->pop3_port); ! 2473: cleanup(1); ! 2474: return; ! 2475: } ! 2476: ! 2477: lprintf("%04d POP3 socket bound to port %u" ! 2478: ,pop3_socket, startup->pop3_port); ! 2479: ! 2480: result = listen (pop3_socket, 1); ! 2481: ! 2482: if (result != 0) { ! 2483: lprintf("%04d !ERROR %d (%d) listening on POP3 socket" ! 2484: ,pop3_socket, result, ERROR_VALUE); ! 2485: cleanup(1); ! 2486: return; ! 2487: } ! 2488: } ! 2489: ! 2490: /* signal caller that we've started up successfully */ ! 2491: if(startup->started!=NULL) ! 2492: startup->started(); ! 2493: ! 2494: if(!(startup->options&MAIL_OPT_NO_SENDMAIL)) ! 2495: _beginthread (sendmail_thread, 0, NULL); ! 2496: ! 2497: lprintf("%04d Mail Server thread started",server_socket); ! 2498: status(STATUS_WFC); ! 2499: ! 2500: while (server_socket!=INVALID_SOCKET) { ! 2501: ! 2502: /* now wait for connection */ ! 2503: ! 2504: FD_ZERO(&socket_set); ! 2505: FD_SET(server_socket,&socket_set); ! 2506: high_socket_set=server_socket+1; ! 2507: if(startup->options&MAIL_OPT_ALLOW_POP3) { ! 2508: FD_SET(pop3_socket,&socket_set); ! 2509: if(pop3_socket+1>high_socket_set) ! 2510: high_socket_set=pop3_socket+1; ! 2511: } ! 2512: ! 2513: tv.tv_sec=2; ! 2514: tv.tv_usec=0; ! 2515: ! 2516: if((i=select(high_socket_set,&socket_set,NULL,NULL,&tv))<1) { ! 2517: if(i==0) { ! 2518: mswait(1); ! 2519: continue; ! 2520: } ! 2521: if(ERROR_VALUE==EINTR) ! 2522: lprintf("0000 Mail Server listening interrupted"); ! 2523: else if(ERROR_VALUE == ENOTSOCK) ! 2524: lprintf("0000 Mail Server sockets closed"); ! 2525: else ! 2526: lprintf("0000 !ERROR %d selecting sockets",ERROR_VALUE); ! 2527: break; ! 2528: } ! 2529: ! 2530: ! 2531: if(FD_ISSET(server_socket,&socket_set)) { ! 2532: ! 2533: client_addr_len = sizeof (client_addr); ! 2534: client_socket = accept(server_socket, (struct sockaddr *)&client_addr ! 2535: ,&client_addr_len); ! 2536: ! 2537: if (client_socket == INVALID_SOCKET) ! 2538: { ! 2539: if(ERROR_VALUE == ENOTSOCK) ! 2540: lprintf("%04d SMTP socket closed while listening",server_socket); ! 2541: else ! 2542: lprintf("%04d !ERROR %d accept failed", server_socket, ERROR_VALUE); ! 2543: break; ! 2544: } ! 2545: if(startup->socket_open!=NULL) ! 2546: startup->socket_open(TRUE); ! 2547: sockets++; ! 2548: ! 2549: if(active_clients>=startup->max_clients) { ! 2550: lprintf("%04d !MAXMIMUM CLIENTS (%u) reached, access denied" ! 2551: ,client_socket, startup->max_clients); ! 2552: sockprintf(client_socket,"421 Maximum active clients reached, please try again later."); ! 2553: mswait(3000); ! 2554: mail_close_socket(client_socket); ! 2555: continue; ! 2556: } ! 2557: ! 2558: l=1; ! 2559: ! 2560: if((i=ioctlsocket(client_socket, FIONBIO, &l))!=0) { ! 2561: lprintf("%04d !ERROR %d (%d) disabling blocking on socket" ! 2562: ,client_socket, i, ERROR_VALUE); ! 2563: mail_close_socket(client_socket); ! 2564: continue; ! 2565: } ! 2566: ! 2567: if((smtp=malloc(sizeof(smtp_t)))==NULL) { ! 2568: lprintf("%04d !ERROR allocating %u bytes of memory for smtp_t" ! 2569: ,client_socket, sizeof(smtp_t)); ! 2570: mail_close_socket(client_socket); ! 2571: continue; ! 2572: } ! 2573: ! 2574: smtp->socket=client_socket; ! 2575: smtp->client_addr=client_addr; ! 2576: _beginthread (smtp_thread, 0, smtp); ! 2577: } ! 2578: ! 2579: if(FD_ISSET(pop3_socket,&socket_set)) { ! 2580: ! 2581: client_addr_len = sizeof (client_addr); ! 2582: client_socket = accept(pop3_socket, (struct sockaddr *)&client_addr ! 2583: ,&client_addr_len); ! 2584: ! 2585: if (client_socket == INVALID_SOCKET) ! 2586: { ! 2587: if(ERROR_VALUE == ENOTSOCK) ! 2588: lprintf("%04d POP3 socket closed while listening",pop3_socket); ! 2589: else ! 2590: lprintf("%04d !ERROR %d accept failed", pop3_socket, ERROR_VALUE); ! 2591: break; ! 2592: } ! 2593: if(startup->socket_open!=NULL) ! 2594: startup->socket_open(TRUE); ! 2595: sockets++; ! 2596: ! 2597: if(active_clients>=startup->max_clients) { ! 2598: lprintf("%04d !MAXMIMUM CLIENTS (%u) reached, access denied" ! 2599: ,client_socket, startup->max_clients); ! 2600: sockprintf(client_socket,"-ERR Maximum active clients reached, please try again later."); ! 2601: mswait(3000); ! 2602: mail_close_socket(client_socket); ! 2603: continue; ! 2604: } ! 2605: ! 2606: ! 2607: l=1; ! 2608: ! 2609: if((i=ioctlsocket(client_socket, FIONBIO, &l))!=0) { ! 2610: lprintf("%04d !ERROR %d (%d) disabling blocking on socket" ! 2611: ,client_socket, i, ERROR_VALUE); ! 2612: sockprintf(client_socket,"-ERR System error, please try again later."); ! 2613: mswait(3000); ! 2614: mail_close_socket(client_socket); ! 2615: continue; ! 2616: } ! 2617: ! 2618: if((pop3=malloc(sizeof(pop3_t)))==NULL) { ! 2619: lprintf("%04d !ERROR allocating %u bytes of memory for pop3_t" ! 2620: ,client_socket,sizeof(pop3_t)); ! 2621: sockprintf(client_socket,"-ERR System error, please try again later."); ! 2622: mswait(3000); ! 2623: mail_close_socket(client_socket); ! 2624: continue; ! 2625: } ! 2626: ! 2627: pop3->socket=client_socket; ! 2628: pop3->client_addr=client_addr; ! 2629: ! 2630: _beginthread (pop3_thread, 0, pop3); ! 2631: } ! 2632: } ! 2633: ! 2634: if(active_clients) { ! 2635: lprintf("0000 Waiting for %d active clients to disconnect...", active_clients); ! 2636: start=time(NULL); ! 2637: while(active_clients) { ! 2638: if(time(NULL)-start>TIMEOUT_THREAD_WAIT) { ! 2639: lprintf("!TIMEOUT waiting for %u active clients ",active_clients); ! 2640: break; ! 2641: } ! 2642: mswait(100); ! 2643: } ! 2644: } ! 2645: ! 2646: if(sendmail_running) { ! 2647: lprintf("0000 Waiting for SendMail thread to terminate..."); ! 2648: start=time(NULL); ! 2649: while(sendmail_running) { ! 2650: if(time(NULL)-start>TIMEOUT_THREAD_WAIT) { ! 2651: lprintf("!TIMEOUT waiting for sendmail thread to " ! 2652: "terminate"); ! 2653: break; ! 2654: } ! 2655: mswait(100); ! 2656: } ! 2657: } ! 2658: ! 2659: cleanup(0); ! 2660: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.