Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/* mailsrvr.c */
/* Synchronet Mail (SMTP/POP3) server and sendmail threads */
/* $Id$ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2000 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include <io.h> /* open/close */
#include <share.h> /* share open flags */
#include <process.h> /* _beginthread */
#include <windows.h> /* required for mmsystem.h */
#include <mmsystem.h> /* SND_ASYNC */
#elif defined(__unix__)
#include <signal.h> /* signal/SIGPIPE */
#include <stdlib.h> /* ltoa in GNU C lib */
#include <stdarg.h> /* va_list */
#include <string.h> /* strrchr */
#include <ctype.h> /* isdigit */
#include <fcntl.h> /* Open flags */
#include <errno.h> /* errno */
#include "sbbs.h"
#include "mime.h"

rswindell
committed
int dns_getmx(char* name, char* mx, char* mx2
,DWORD intf, DWORD ip_addr, BOOL use_tcp, int timeout);
#define SMTP_OK "250 OK"
#define SMTP_BADSEQ "503 Bad sequence of commands"

rswindell
committed
#define TIMEOUT_THREAD_WAIT 30 /* Seconds */
#define MAX_RECIPIENTS 1000 /* 0xffff = abs max */
#define STATUS_WFC "Listening"
static const char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
static const char *mon[]={"Jan","Feb","Mar","Apr","May","Jun"
,"Jul","Aug","Sep","Oct","Nov","Dec"};
static mail_startup_t* startup=NULL;
static scfg_t scfg;
static SOCKET server_socket=INVALID_SOCKET;
static SOCKET pop3_socket=INVALID_SOCKET;
static int active_clients=0;
static int active_sendmail=0;
static BOOL sendmail_running=FALSE;
static DWORD sockets=0;
typedef struct {
SOCKET socket;
SOCKADDR_IN client_addr;
} smtp_t,pop3_t;
static int lprintf(char *fmt, ...)
{
va_list argptr;
char sbuf[1024];
if(startup==NULL || startup->lputs==NULL)
return(0);

rswindell
committed
#if defined(_WIN32)
if(IsBadCodePtr((FARPROC)startup->lputs))
return(0);
#endif
va_start(argptr,fmt);
vsprintf(sbuf,fmt,argptr);
va_end(argptr);
return(startup->lputs(sbuf));
}
#ifdef _WINSOCKAPI_
static WSADATA WSAData;
static BOOL WSAInitialized=FALSE;
static BOOL winsock_startup(void)
{
int status; /* Status Code */
if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
lprintf("%s %s",WSAData.szDescription, WSAData.szSystemStatus);
WSAInitialized=TRUE;
return (TRUE);
}
lprintf("!WinSock startup ERROR %d", status);
return (FALSE);
}
#else /* No WINSOCK */
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#endif
static void update_clients(void)
{
if(startup!=NULL && startup->clients!=NULL)
startup->clients(active_clients+active_sendmail);
}
static void client_on(SOCKET sock, client_t* client)
{
if(startup!=NULL && startup->client_on!=NULL)
startup->client_on(TRUE,sock,client);
}
static void client_off(SOCKET sock)
{
if(startup!=NULL && startup->client_on!=NULL)
startup->client_on(FALSE,sock,NULL);
}
static void thread_up(void)
{
if(startup!=NULL && startup->thread_up!=NULL)
startup->thread_up(TRUE);
}
static void thread_down(void)
{
if(startup!=NULL && startup->thread_up!=NULL)
startup->thread_up(FALSE);
}

rswindell
committed
SOCKET mail_open_socket(int type)
sock=socket(AF_INET, type, IPPROTO_IP);
if(sock!=INVALID_SOCKET && startup!=NULL && startup->socket_open!=NULL)
startup->socket_open(TRUE);
if(sock!=INVALID_SOCKET) {
sockets++;
#if 0 /*def _DEBUG */
lprintf("%04d Socket opened (%d sockets in use)",sock,sockets);
#endif
}
return(sock);
}

rswindell
committed
int mail_close_socket(SOCKET sock)
shutdown(sock,SHUT_RDWR); /* required on Unix */
result=closesocket(sock);
if(/* result==0 && */ startup!=NULL && startup->socket_open!=NULL)
startup->socket_open(FALSE);
sockets--;
if(result!=0) {
if(ERROR_VALUE!=ENOTSOCK)
lprintf("%04d !ERROR %d closing socket",sock, ERROR_VALUE);
}
lprintf("%04d Socket closed (%d sockets in use)",sock,sockets);
#endif
return(result);
}
static void status(char* str)
{
if(startup!=NULL && startup->status!=NULL)
startup->status(str);
}
int sockprintf(SOCKET sock, char *fmt, ...)
{
int len;
int result;
va_list argptr;
char sbuf[1024];
fd_set socket_set;
struct timeval tv;
va_start(argptr,fmt);
len=vsprintf(sbuf,fmt,argptr);
if(startup->options&MAIL_OPT_DEBUG_TX)
lprintf("%04d TX: %s", sock, sbuf);
strcat(sbuf,"\r\n");
len+=2;
va_end(argptr);
/* Check socket for writability (using select) */
tv.tv_sec=60;
tv.tv_usec=0;
FD_ZERO(&socket_set);
FD_SET(sock,&socket_set);
if((result=select(sock+1,NULL,&socket_set,NULL,&tv))<1) {
lprintf("%04d !ERROR %d (%d) selecting socket for send"
,sock, result, ERROR_VALUE, sock);
return(0);
}
while((result=sendsocket(sock,sbuf,len))!=len) {
lprintf("%04d Connection reset by peer on send",sock);
else if(ERROR_VALUE==ECONNABORTED)
lprintf("%04d Connection aborted by peer on send",sock);
lprintf("%04d !ERROR %d sending on socket",sock,ERROR_VALUE);
lprintf("%04d !ERROR: short send on socket: %d instead of %d",sock,result,len);
}
return(len);
}
static time_t checktime(void)
{
struct tm tm;
memset(&tm,0,sizeof(tm));
tm.tm_year=94;
tm.tm_mday=1;

rswindell
committed
return(mktime(&tm)-0x2D24BD00L);

rswindell
committed
static void recverror(SOCKET socket, int rd, int line)

rswindell
committed
lprintf("%04d Socket closed by peer on receive (line %d)"
,socket, line);

rswindell
committed
lprintf("%04d Connection reset by peer on receive (line %d)"
,socket, line);

rswindell
committed
lprintf("%04d Connection aborted by peer on receive (line %d)"
,socket, line);

rswindell
committed
lprintf("%04d !ERROR %d receiving on socket (line %d)"
,socket, ERROR_VALUE, line);

rswindell
committed
lprintf("%04d !ERROR: recv on socket returned unexpected value: %d (line %d)"
,socket, rd, line);

rswindell
committed
static int sockreadline(SOCKET socket, char* buf, int len)
{
char ch;
int i,rd=0;

rswindell
committed
fd_set socket_set;
struct timeval tv;
time_t start;
start=time(NULL);
while(rd<len-1) {

rswindell
committed
tv.tv_sec=0;
tv.tv_usec=0;
FD_ZERO(&socket_set);
FD_SET(socket,&socket_set);
i=select(socket+1,&socket_set,NULL,NULL,&tv);

rswindell
committed
if(i==0) {
if((time(NULL)-start)>startup->max_inactivity) {

rswindell
committed
recverror(socket,i,__LINE__);
return(i);
}
i=recv(socket, &ch, 1, 0);
if(i<1) {
recverror(socket,i,__LINE__);
return(i);
}
if(ch=='\n' && rd>=1) {
break;
}
buf[rd++]=ch;
}
buf[rd-1]=0;
return(rd);
}
/************************************************/
/* Truncates white-space chars off end of 'str' */
/************************************************/
static void truncsp(char *str)
{
uint c;
c=strlen(str);
while(c && (uchar)str[c-1]<=' ') c--;
str[c]=0;
}
static BOOL sockgetrsp(SOCKET socket, char* rsp, char *buf, int len)
{
int rd;
while(1) {
rd = sockreadline(socket, buf, len);
if(rd<1)
return(FALSE);
if(buf[3]=='-') { /* Multi-line response */
if(startup->options&MAIL_OPT_DEBUG_RX_RSP)
lprintf("%04d RX: %s",socket,buf);
continue;
}
if(strnicmp(buf,rsp,strlen(rsp))) {
lprintf("%04d !INVALID RESPONSE: '%s' Expected: '%s'", socket, buf, rsp);
return(FALSE);
}
break;
}
if(startup->options&MAIL_OPT_DEBUG_RX_RSP)
lprintf("%04d RX: %s",socket,buf);
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
return(TRUE);
}
static char *msgdate(when_t when, char* buf)
{
struct tm tm;
struct tm* tm_p;
tm_p=localtime((const time_t*)&when.time);
if(tm_p!=NULL)
tm=*tm_p;
else
memset(&tm,0,sizeof(tm));
sprintf(buf,"%s, %d %s %d %02d:%02d:%02d %s"
,wday[tm.tm_wday]
,tm.tm_mday
,mon[tm.tm_mon]
,1900+tm.tm_year
,tm.tm_hour
,tm.tm_min
,tm.tm_sec
,zonestr(when.zone)
);
return(buf);
}
#define MAX_LINE_LEN 1000
static void sockmsgtxt(SOCKET socket, smbmsg_t* msg, char* msgtxt, char* fromaddr
,ulong maxlines)
{
char toaddr[256];
char date[64];
char filepath[MAX_PATH+1]="";
char* boundary=NULL;
int i;
ulong line;
/* HEADERS */
sockprintf(socket,"Date: %s",msgdate(msg->hdr.when_written,date));
if(fromaddr[0]=='<')
sockprintf(socket,"From: \"%s\" %s",msg->from,fromaddr);
else
sockprintf(socket,"From: \"%s\" <%s>",msg->from,fromaddr);
sockprintf(socket,"Subject: %s",msg->subj);
if(msg->to_net.type==NET_INTERNET || msg->to_net.type==NET_QWK) {
if(*((char*)msg->to_net.addr)=='<')
sockprintf(socket,"To: \"%s\" %s",msg->to,(char*)msg->to_net.addr);
else
sockprintf(socket,"To: \"%s\" <%s>",msg->to,(char*)msg->to_net.addr);
} else {
usermailaddr(&scfg,toaddr,msg->to);
sockprintf(socket,"To: \"%s\" <%s>",msg->to,toaddr);
}
if(msg->replyto_net.type==NET_INTERNET)
sockprintf(socket,"Reply-To: %s",msg->replyto_net.addr);
else
sockprintf(socket,"Reply-To: %s",fromaddr);
sockprintf(socket,"Message-ID: <%08lX.%lu@%s>"
,msg->hdr.when_written.time,msg->idx.number,scfg.sys_inetaddr);
for(i=0;i<msg->total_hfields;i++) {
if(msg->hfield[i].type==RFC822HEADER)
sockprintf(socket,"%s",(char*)msg->hfield_dat[i]);
else if(msg->hdr.auxattr&MSG_FILEATTACH && msg->hfield[i].type==FILEATTACH)
strncpy(filepath,(char*)msg->hfield_dat[i],sizeof(filepath)-1);
}
if(msg->hdr.auxattr&MSG_FILEATTACH) {
if(filepath[0]==0) { /* filename stored in subject */
if(msg->idx.to!=0)
snprintf(filepath,sizeof(filepath)-1,"%sfile/%04u.in/%s"
,scfg.data_dir,msg->idx.to,msg->subj);
else
snprintf(filepath,sizeof(filepath)-1,"%sfile/%04u.out/%s"
,scfg.data_dir,msg->idx.from,msg->subj);
}
boundary=mimegetboundary();
mimeheaders(socket,boundary);
sockprintf(socket,"");
mimeblurb(socket,boundary);
sockprintf(socket,"");
mimetextpartheader(socket,boundary);
}
sockprintf(socket,""); /* Header Terminator */
/* MESSAGE BODY */
line=0;
p=msgtxt;
while(*p && line<maxlines) {
tp=strchr(p,'\n');
if(tp) {
if(tp-p>MAX_LINE_LEN)
tp=p+MAX_LINE_LEN;
*tp=0;
}
truncsp(p); /* Takes care of '\r' or spaces */
if(*p=='.')
i=sockprintf(socket,".%.*s",MAX_LINE_LEN,p);
else
i=sockprintf(socket,"%.*s",MAX_LINE_LEN,p);
if(!i)
break;
if(tp==NULL)
break;
p=tp+1;
line++;
if(msg->hdr.auxattr&MSG_FILEATTACH) {
sockprintf(socket,"");
lprintf("%04u MIME Encoding %s",socket,filepath);
if(!mimeattach(socket,boundary,filepath))
lprintf("%04u !ERROR opening/encoding %s",socket,filepath);
endmime(socket,boundary);
}
sockprintf(socket,"."); /* End of text */
if(boundary) FREE(boundary);
static u_long resolve_ip(char *addr)
char* p;
HOSTENT* host;
for(p=addr;*p;p++)
if(*p!='.' && !isdigit(*p))
break;
if(!(*p))
if ((host=gethostbyname(addr))==NULL) {
lprintf("0000 !ERROR resolving hostname: %s",addr);
return(0);
}
return(*((ulong*)host->h_addr_list[0]));
}
static void pop3_thread(void* arg)
{
char* p;
char str[128];
char buf[512];
char host_name[128];
char host_ip[64];
char username[LEN_ALIAS+1];
char password[LEN_PASS+1];
char fromaddr[256];
char* msgtxt;
int i;
int rd;
BOOL activity=FALSE;
ulong l;
ulong lines;
ulong msgs,bytes,msgnum,msgbytes;
SOCKET socket;
HOSTENT* host;
smb_t smb;
smbmsg_t msg;
user_t user;
client_t client;
mail_t* mail;
pop3_t pop3=*(pop3_t*)arg;
thread_up();
free(arg);
socket=pop3.socket;
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf("%04d POP3 session thread started", socket);
if(startup->pop3_sound[0] && !(startup->options&MAIL_OPT_MUTE))
PlaySound(startup->pop3_sound, NULL, SND_ASYNC|SND_FILENAME);
strcpy(host_ip,inet_ntoa(pop3.client_addr.sin_addr));
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf("%04d POP3 connection accepted from: %s port %u"
,socket, host_ip, ntohs(pop3.client_addr.sin_port));
if(startup->options&MAIL_OPT_NO_HOST_LOOKUP)
host=NULL;
else
host=gethostbyaddr((char *)&pop3.client_addr.sin_addr
,sizeof(pop3.client_addr.sin_addr),AF_INET);
if(host!=NULL && host->h_name!=NULL)
sprintf(host_name,"%.*s",(int)sizeof(host_name)-1,host->h_name);
else
strcpy(host_name,"<no name>");
if(startup->options&MAIL_OPT_DEBUG_POP3
&& !(startup->options&MAIL_OPT_NO_HOST_LOOKUP))
lprintf("%04d POP3 client name: %s", socket, host_name);
if(trashcan(&scfg,host_ip,"ip")) {
lprintf("%04d !POP3 BLOCKED CLIENT IP ADDRESS: %s"
,socket, host_ip);
sockprintf(socket,"-ERR Access denied.");

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
if(trashcan(&scfg,host_name,"host")) {
lprintf("%04d !POP3 BLOCKED CLIENT HOSTNAME: %s"
,socket, host_name);
sockprintf(socket,"-ERR Access denied.");

rswindell
committed
mail_close_socket(socket);
thread_down();
return;
}
active_clients++;
update_clients();
/* Initialize client display */
client.size=sizeof(client);
client.time=time(NULL);
sprintf(client.addr,"%.*s",(int)sizeof(client.addr)-1,host_ip);
sprintf(client.host,"%.*s",(int)sizeof(client.host)-1,host_name);
client.port=ntohs(pop3.client_addr.sin_port);
client.protocol="POP3";
client.user="<unknown>";
client_on(socket,&client);
sprintf(str,"POP3: %s", host_ip);
status(str);
do {
memset(&smb,0,sizeof(smb));
memset(&msg,0,sizeof(msg));

rswindell
committed
memset(&user,0,sizeof(user));

rswindell
committed
sprintf(smb.file,"%smail",scfg.data_dir);
lprintf("%04d !ERROR %d (%s) opening %s",socket,i,smb.last_error,smb.file);
sockprintf(socket,"-ERR %d opening %s",i,smb.file);
break;
}
sockprintf(socket,"+OK Synchronet POP3 Server for %s v%s Ready"
,PLATFORM_DESC,MAIL_VERSION);
if(!sockgetrsp(socket,"USER ",buf,sizeof(buf))) {
sockprintf(socket,"-ERR USER command expected");
break;
}
p=buf+5;
while(*p && *p<=' ') p++;
sprintf(username,"%.*s",(int)sizeof(username)-1,p);
sockprintf(socket,"+OK");
if(!sockgetrsp(socket,"PASS ",buf,sizeof(buf))) {
sockprintf(socket,"-ERR PASS command expected");
break;
}
p=buf+5;
while(*p && *p<=' ') p++;
sprintf(password,"%.*s",(int)sizeof(password)-1,p);
user.number=matchuser(&scfg,username,FALSE /*sysop_alias*/);

rswindell
committed
if(scfg.sys_misc&SM_ECHO_PW)
lprintf("%04d !POP3 UNKNOWN USER: %s (password: %s)"
,socket, username, password);
else
lprintf("%04d !POP3 UNKNOWN USER: %s"
,socket, username);
sockprintf(socket,"-ERR");
break;
}
if((i=getuserdat(&scfg, &user))!=0) {
lprintf("%04d !POP3 ERROR %d getting data on user (%s)"
,socket, i, username);
sockprintf(socket, "-ERR");
break;
}
if(user.misc&(DELETED|INACTIVE)) {

rswindell
committed
lprintf("%04d !POP3 DELETED or INACTIVE user #%u (%s)"
,socket, user.number, username);
sockprintf(socket, "-ERR");
break;
}
if(stricmp(password,user.pass)) {

rswindell
committed
if(scfg.sys_misc&SM_ECHO_PW)
lprintf("%04d !POP3 FAILED Password attempt for user %s: '%s' expected '%s'"
,socket, username, password, user.pass);
else
lprintf("%04d !POP3 FAILED Password attempt for user %s"
,socket, username);
sockprintf(socket, "-ERR");
break;
}
/* Update client display */
client.user=user.alias;
client_on(socket,&client);
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf("%04d POP3 %s logged in", socket, user.alias);
sprintf(str,"POP3: %s",user.alias);
status(str);
sockprintf(socket,"+OK User verified");
mail=loadmail(&smb,&msgs,user.number,MAIL_YOUR,0);
for(l=bytes=0;l<msgs;l++) {
msg.hdr.number=mail[l].number;
if((i=smb_getmsgidx(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message index"
,socket ,i);
break;
}
if((i=smb_lockmsghdr(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d locking message header #%lu"
,socket ,i ,msg.hdr.number);
break;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message header #%lu"
,socket, i, msg.hdr.number);
break;
}
for(i=0;i<msg.hdr.total_dfields;i++)
if(msg.dfield[i].type==TEXT_BODY || msg.dfield[i].type==TEXT_TAIL)
bytes+=msg.dfield[i].length;
smb_freemsgmem(&msg);
}
while(1) { /* TRANSACTION STATE */
rd = sockreadline(socket, buf, sizeof(buf));
if(rd<1)
break;
truncsp(buf);
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf("%04d POP3 RX: %s", socket, buf);
if(!stricmp(buf, "NOOP")) {
sockprintf(socket,"+OK");
continue;
}
if(!stricmp(buf, "QUIT")) {
sockprintf(socket,"+OK");
break;
}
if(!stricmp(buf, "STAT")) {
sockprintf(socket,"+OK %lu %lu",msgs,bytes);
continue;
}
if(!stricmp(buf, "RSET")) {
for(l=0;l<msgs;l++) {
msg.hdr.number=mail[l].number;
if((i=smb_getmsgidx(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message index"
,socket, i);
break;
}
if((i=smb_lockmsghdr(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d locking message header #%lu"
,socket, i,msg.hdr.number);
break;
}
if((i=smb_getmsghdr(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message header #%lu"
,socket, i, msg.hdr.number);
break;
}
msg.hdr.attr=mail[l].attr;
msg.idx.attr=msg.hdr.attr;
if((i=smb_putmsg(&smb,&msg))!=0)

rswindell
committed
lprintf("%04d !POP3 ERROR %d updating message index"
,socket, i);
smb_unlockmsghdr(&smb,&msg);
smb_freemsgmem(&msg);
}
if(l<msgs)
sockprintf(socket,"-ERR %d messages reset (ERROR: %d)",l,i);
else
sockprintf(socket,"+OK %lu messages (%lu bytes)",msgs,bytes);
continue;
}
if(!strnicmp(buf, "LIST",4) || !strnicmp(buf,"UIDL",4)) {
p=buf+4;
while(*p && *p<=' ') p++;
if(isdigit(*p)) {
msgnum=atol(p);
if(msgnum<1 || msgnum>msgs) {

rswindell
committed
lprintf("%04d !POP3 INVALID message #%ld"
,socket, msgnum);
sockprintf(socket,"-ERR no such message");
continue;
}
msg.hdr.number=mail[msgnum-1].number;
if((i=smb_getmsgidx(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message index"
,socket, i);
sockprintf(socket,"-ERR %d getting message index",i);
break;
}
if(msg.idx.attr&MSG_DELETE) {
lprintf("%04d !POP3 ATTEMPT to list DELETED message"
,socket);
sockprintf(socket,"-ERR message deleted");
continue;
}
if((i=smb_lockmsghdr(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d locking message header #%lu"
,socket, i, msg.hdr.number);
sockprintf(socket,"-ERR %d locking message header",i);
continue;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
smb_freemsgmem(&msg);

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message header #%lu"
,socket, i,msg.hdr.number);
sockprintf(socket,"-ERR %d getting message header",i);
continue;
}
if(!strnicmp(buf, "LIST",4)) {
msgbytes=0;
for(i=0;i<msg.hdr.total_dfields;i++)
if(msg.dfield[i].type==TEXT_BODY || msg.dfield[i].type==TEXT_TAIL)
msgbytes+=msg.dfield[i].length;
sockprintf(socket,"+OK %lu %lu",msgnum,msgbytes);
} else /* UIDL */
sockprintf(socket,"+OK %lu %lu",msgnum,msg.hdr.number);
smb_freemsgmem(&msg);
continue;
}
/* List ALL messages */
sockprintf(socket,"+OK %lu messages (%lu bytes)",msgs,bytes);
for(l=0;l<msgs;l++) {
msg.hdr.number=mail[l].number;
if((i=smb_getmsgidx(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message index"
,socket, i);
break;
}
if(msg.idx.attr&MSG_DELETE)
continue;
if((i=smb_lockmsghdr(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d locking message header #%lu"
,socket, i,msg.hdr.number);
break;
}
i=smb_getmsghdr(&smb,&msg);
smb_unlockmsghdr(&smb,&msg);
if(i!=0) {
smb_freemsgmem(&msg);

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message header #%lu"
,socket, i,msg.hdr.number);
break;
}
if(!strnicmp(buf, "LIST",4)) {
msgbytes=0;
for(i=0;i<msg.hdr.total_dfields;i++)
if(msg.dfield[i].type==TEXT_BODY || msg.dfield[i].type==TEXT_TAIL)
msgbytes+=msg.dfield[i].length;
sockprintf(socket,"%lu %lu",l+1,msgbytes);
} else /* UIDL */
sockprintf(socket,"%lu %lu",l+1,msg.hdr.number);
smb_freemsgmem(&msg);
}
sockprintf(socket,".");
continue;
}
activity=TRUE;
if(!strnicmp(buf, "RETR ",5) || !strnicmp(buf,"TOP ",4)) {
sprintf(str,"POP3: %s", user.alias);
status(str);
lines=-1;
p=buf+4;
while(*p && *p<=' ') p++;
msgnum=atol(p);
if(!strnicmp(buf,"TOP ",4)) {
while(*p && isdigit(*p)) p++;
while(*p && *p<=' ') p++;
lines=atol(p);
}
if(msgnum<1 || msgnum>msgs) {
lprintf("%04d !POP3 %s ATTEMPTED to retrieve an INVALID message #%ld"
,socket, user.alias, msgnum);
sockprintf(socket,"-ERR no such message");
continue;
}
msg.hdr.number=mail[msgnum-1].number;
lprintf("%04d POP3 %s retrieving message #%ld"
,socket, user.alias, msg.hdr.number);
if((i=smb_getmsgidx(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message index"
,socket, i);
sockprintf(socket,"-ERR %d getting message index",i);
continue;
}
if(msg.idx.attr&MSG_DELETE) {
lprintf("%04d !POP3 ATTEMPT to retrieve DELETED message"
,socket);
sockprintf(socket,"-ERR message deleted");
continue;
}
if((i=smb_lockmsghdr(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d locking message header #%lu"
,socket, i, msg.hdr.number);
sockprintf(socket,"-ERR %d locking message header",i);
continue;
}
if((i=smb_getmsghdr(&smb,&msg))!=0) {
smb_unlockmsghdr(&smb,&msg);

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message header #%lu"
,socket, i, msg.hdr.number);
sockprintf(socket,"-ERR %d getting message header",i);
continue;
}
smb_unlockmsghdr(&smb,&msg);
if((msgtxt=smb_getmsgtxt(&smb,&msg,GETMSGTXT_TAILS))==NULL) {
smb_freemsgmem(&msg);
lprintf("%04d !POP3 ERROR (%s) retrieving message %lu text"
,socket, smb.last_error, msg.hdr.number);
sockprintf(socket,"-ERR retrieving message text");
continue;
}
sockprintf(socket,"+OK message follows");
if(msg.from_net.type==NET_INTERNET)
strcpy(fromaddr,msg.from_net.addr);
else if(msg.from_net.type==NET_QWK)
sprintf(fromaddr,"\"%s@%s\"@%s"
,msg.from,(char*)msg.from_net.addr,scfg.sys_inetaddr);
usermailaddr(&scfg,fromaddr,msg.from); /* unresolved exception here Nov-06-2000 */
lprintf("%04d POP3 sending message text (%u bytes)"
,socket,strlen(msgtxt));
sockmsgtxt(socket,&msg,msgtxt,fromaddr,lines);
/* if(startup->options&MAIL_OPT_DEBUG_POP3) */
lprintf("%04d POP3 message transfer complete",socket);
msg.hdr.attr|=MSG_READ;
msg.idx.attr=msg.hdr.attr;
msg.hdr.netattr|=MSG_SENT;
if((i=smb_lockmsghdr(&smb,&msg))!=0)

rswindell
committed
lprintf("%04d !POP3 ERROR %d locking message header #%lu"
,socket, i, msg.hdr.number);
if((i=smb_putmsg(&smb,&msg))!=0)

rswindell
committed
lprintf("%04d !POP3 ERROR %d marking message #%lu as read"
,socket, i, msg.hdr.number);
smb_unlockmsghdr(&smb,&msg);
smb_freemsgmem(&msg);
smb_freemsgtxt(msgtxt);
continue;
}
if(!strnicmp(buf, "DELE ",5)) {
p=buf+5;
while(*p && *p<=' ') p++;
msgnum=atol(p);
if(msgnum<1 || msgnum>msgs) {
lprintf("%04d !POP3 %s ATTEMPTED to delete an INVALID message #%ld"
,socket, user.alias, msgnum);
sockprintf(socket,"-ERR no such message");
continue;
}
msg.hdr.number=mail[msgnum-1].number;
lprintf("%04d POP3 %s deleting message #%ld"
,socket, user.alias, msg.hdr.number);
if((i=smb_getmsgidx(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message index"
,socket, i);
sockprintf(socket,"-ERR %d getting message index",i);
continue;
}
if((i=smb_lockmsghdr(&smb,&msg))!=0) {

rswindell
committed
lprintf("%04d !POP3 ERROR %d locking message header #%lu"
,socket, i,msg.hdr.number);
sockprintf(socket,"-ERR %d locking message header",i);
continue;
}
if((i=smb_getmsghdr(&smb,&msg))!=0) {
smb_unlockmsghdr(&smb,&msg);

rswindell
committed
lprintf("%04d !POP3 ERROR %d getting message header #%lu"
,socket, i,msg.hdr.number);
sockprintf(socket,"-ERR %d getting message header",i);
continue;
}
msg.hdr.attr|=MSG_DELETE;
msg.idx.attr=msg.hdr.attr;
if((i=smb_putmsg(&smb,&msg))!=0) {
smb_unlockmsghdr(&smb,&msg);
smb_freemsgmem(&msg);

rswindell
committed
lprintf("%04d !POP3 ERROR %d marking message as read", socket, i);
sockprintf(socket,"-ERR %d marking message for deletion",i);
continue;
}
if(msg.hdr.auxattr&MSG_FILEATTACH)
delfattach(&scfg,&msg);
smb_unlockmsghdr(&smb,&msg);
smb_freemsgmem(&msg);
sockprintf(socket,"+OK");
if(startup->options&MAIL_OPT_DEBUG_POP3)
lprintf("%04d POP3 message deleted", socket);
lprintf("%04d !POP3 UNSUPPORTED COMMAND from %s: '%s'"