Click here to Skip to main content
15,895,667 members
Articles / Desktop Programming / MFC

CSmtpProxyMT 1.0

Rate me:
Please Sign up or sign in to vote.
4.93/5 (34 votes)
15 Nov 2001CPOL4 min read 131.4K   1.6K   38  
An SMTP proxy class with ability to insert signatures to outgoing mails. Does not require MFC.
#include "stdafx.h"
#include "SmtpProxyMT.h"


CSmtpProxyMT::CSmtpProxyMT()
{
	AcceptFlag=false;	
}	

CSmtpProxyMT::~CSmtpProxyMT()
{

}

int CSmtpProxyMT::StartProxy(char *server, int port, int localport)
{
	if(AcceptFlag)
		return ERR_RUNNING;
	strcpy(m_SSmtp.SmtpServer,server);
	m_SSmtp.SmtpPort=port;
	m_SSmtp.LocalPort=localport;
	AcceptFlag=true;
	StartProxyThread(this);
	return 0;
}

void CSmtpProxyMT::StartProxyThread(CSmtpProxyMT* m_pCSmtpProxyMT)
{	
	SECURITY_ATTRIBUTES sa;
	DWORD threadid=0;
	sa.nLength=sizeof(sa);
	sa.lpSecurityDescriptor=NULL;
	
	_beginthreadex((void*)&sa,0,
		(unsigned(__stdcall*)(void*))CSmtpProxyMT::SmtpProxyThread,
		(void*)m_pCSmtpProxyMT,0,(unsigned int*)&threadid);

}

DWORD CSmtpProxyMT::SmtpProxyThread(DWORD arg)
{
	CSmtpProxyMT* m_pCSmtpProxyMT=static_cast<CSmtpProxyMT*>((void*)arg);		
	return m_pCSmtpProxyMT->SmtpProxyThreadMain();	
}

DWORD CSmtpProxyMT::SmtpProxyThreadMain()
{
	WSADATA wsaData;
	sockaddr_in local;
	int wsaret=WSAStartup(0x101,&wsaData);
	if(wsaret!=0)
	{
		return ERR_WSAFAIL;
	}
	local.sin_family=AF_INET;
	local.sin_addr.s_addr=INADDR_ANY;
	local.sin_port=htons((u_short)this->m_SSmtp.LocalPort);
	SmtpServerSocket=socket(AF_INET,SOCK_STREAM,0);
	if(SmtpServerSocket==INVALID_SOCKET)
	{
		return ERR_INVALIDSOCKET;
	}
	if(bind(SmtpServerSocket,(sockaddr*)&local,sizeof(local))!=0)
	{
		return ERR_BIND;
	}
	if(listen(SmtpServerSocket,10)!=0)
	{
		return ERR_LISTEN;
	}

	SOCKET SmtpClientSocket;
	sockaddr_in from;
	int fromlen=sizeof(from);

	while(AcceptFlag)
	{
		char temp[250];
		SmtpClientSocket=accept(SmtpServerSocket,
			(struct sockaddr*)&from,&fromlen);
		if(!AcceptFlag)
			break;

		sprintf(temp,"%s",inet_ntoa(from.sin_addr));
		this->m_SSmtp.LocalSocket=SmtpClientSocket;
		this->m_SSmtp.pCSmtpProxyMT=this;

		SSmtp *pSSmtp = new SSmtp;
		m_SSmtp.CopyStruct(pSSmtp);
		StartClientThread(pSSmtp);

	}

	closesocket(SmtpServerSocket);
	WSACleanup();

	return 0;
}

void CSmtpProxyMT::SSmtp::CopyStruct(SSmtp *pSSmtp)
{
	strcpy(pSSmtp->ClientIP,ClientIP);
	pSSmtp->LocalPort=LocalPort;
	pSSmtp->LocalSocket=LocalSocket;
	pSSmtp->SmtpPort=SmtpPort;
	strcpy(pSSmtp->SmtpServer,SmtpServer);
	pSSmtp->pCSmtpProxyMT=pCSmtpProxyMT;

}
void CSmtpProxyMT::StartClientThread(SSmtp *pSSmtp)
{
	SECURITY_ATTRIBUTES sa;
	DWORD threadid=0;
	sa.nLength=sizeof(sa);
	sa.lpSecurityDescriptor=NULL;
	
	_beginthreadex((void*)&sa,0,
		(unsigned(__stdcall*)(void*))CSmtpProxyMT::SmtpClientThread,
		(void*)pSSmtp,0,(unsigned int*)&threadid);
}

DWORD CSmtpProxyMT::SmtpClientThread(DWORD arg)
{	
	SSmtp* pSSmtp=static_cast<SSmtp*>((void*)arg);
	SOCKET conn;
	struct hostent *hp;
	unsigned int addr;
	struct sockaddr_in smtp_server;
	conn=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(inet_addr((char far*)pSSmtp->SmtpServer)==INADDR_NONE)
	{
		hp=gethostbyname(pSSmtp->SmtpServer);
	}
	else
	{
		addr=inet_addr(pSSmtp->SmtpServer);
		hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
	}
	if(hp==NULL)
	{		
		closesocket(conn);
		closesocket(pSSmtp->LocalSocket);
		delete pSSmtp;
		return ERR_HOST;
	}
	smtp_server.sin_addr.s_addr=*((unsigned long*)hp->h_addr);
	smtp_server.sin_family=AF_INET;
	smtp_server.sin_port=htons(pSSmtp->SmtpPort);

	if(connect(conn,(struct sockaddr*)&smtp_server,sizeof(smtp_server)))
	{
		closesocket(conn);
		closesocket(pSSmtp->LocalSocket);
		delete pSSmtp;
		return ERR_CONNECT;
	}

	socket_pair *fromClient=new socket_pair;
	socket_pair *fromServer=new socket_pair;

	fromClient->src=fromServer->dest=pSSmtp->LocalSocket;
	fromClient->dest=fromServer->src=conn;
	fromClient->IsClient=true;
	fromServer->IsClient=false;
	fromServer->pCSmtpProxyMT=fromClient->pCSmtpProxyMT=pSSmtp->pCSmtpProxyMT;
	StartDataThread(fromClient);
	StartDataThread(fromServer);

	delete pSSmtp;
	return 0;
}


void CSmtpProxyMT::StartDataThread(socket_pair *pspair)
{
	SECURITY_ATTRIBUTES sa;
	DWORD threadid=0;
	sa.nLength=sizeof(sa);
	sa.lpSecurityDescriptor=NULL;
	
	_beginthreadex((void*)&sa,0,
		(unsigned(__stdcall*)(void*))CSmtpProxyMT::SmtpDataThread,
		(void*)pspair,0,(unsigned int*)&threadid);
}

DWORD CSmtpProxyMT::SmtpDataThread(DWORD arg)
{
	socket_pair* pspair=static_cast<socket_pair*>((void*)arg);
	char *buff=new char[10240+5120];
	int n;
	int data_stage=0;
	BOOL ExistsBoundary=false;
	char *boundary=new char[512];
	BOOL alternate=false;
	BOOL mixed=false;
	while((n=recv(pspair->src,buff,10240,0))>0)
	{		
		if(pspair->IsClient)
		{
			buff[n]=0;
			if(data_stage==3)
			{
				char *tmpbuff=new char[10240+5120];
				strcpy(tmpbuff,buff);
				if(strstr(MakeUpper(tmpbuff),"MAIL FROM:")!=NULL)
				{
					data_stage=0;
					ExistsBoundary=false;
					alternate=false;
					mixed=false;
				}
				delete tmpbuff;
			}
			if(data_stage==0)
				if(IsDataCommand(buff))
					data_stage=1;
			if(data_stage==1)
			{
				if(!alternate)
				{
					if(strstr(buff,"Content-Type: multipart/alternative")!=NULL)
						alternate=true;					
				}
				if(!mixed)
				{
					if(strstr(buff,"Content-Type: multipart/mixed")!=NULL)
						mixed=true;
				}				
				if(!ExistsBoundary)
					ExistsBoundary=FoundBoundary(boundary,buff);				
				if(ExistsBoundary)
				{
					if(alternate && !mixed)
					{
						char boundary1[512+64];
						strcpy(boundary1,"\r\n--");
						strcat(boundary1,boundary);						
						int i1=strlen(buff);
						AddToEnd(buff, boundary1,pspair->pCSmtpProxyMT->ProxySignature);
						n+=(strlen(buff)-i1);
					}
					else
					{
						char boundary1[512+64];
						strcpy(boundary1,"\r\n--");
						strcat(boundary1,boundary);
						strcat(boundary1,"--\r\n");
						char *p1;
						char *p2;
						char *buff2=new char[10240+5120];
						char *buff3=new char[10240+5120];
						strcpy(buff2,buff);
						strcpy(buff3,buff);
						if((p1=strstr(buff2,boundary1))!=NULL)
						{
							
							char sig[2048+512+512+128];
							strcpy(sig,"\r\n--");
							strcat(sig,boundary);
							strcat(sig,"\r\n");
							strcat(sig,"Content-Type: text/plain;\r\n\r\n");
							strcat(sig,pspair->pCSmtpProxyMT->ProxySignature);
							strcat(sig,"\r\n--");
							strcat(sig,boundary);
							strcat(sig,"\r\n\r\n");												
							p2=strstr(buff3,boundary1);								
							*p1=0;						
							
							strcat(buff2,sig);
							strcat(buff2,p2);
							n+=(strlen(buff2)-strlen(buff));
							strcpy(buff,buff2);
						}
						delete buff2;
						delete buff3;
					}
				}
				if(IsEndOfData(buff))
					data_stage=2;
			}
			if(data_stage==2)
			{
				if(!ExistsBoundary)
				{					
					n+=InsertTextSignature(buff,pspair->pCSmtpProxyMT->ProxySignature);
				}				
				data_stage=3;
			}
			
		}
		send(pspair->dest,buff,n,0);
	}
	shutdown(pspair->src,SD_BOTH);
	closesocket(pspair->src);
	shutdown(pspair->dest,SD_BOTH);
	closesocket(pspair->dest);
	delete boundary;
	delete buff;
	delete pspair;
	return 0;
}

BOOL CSmtpProxyMT::IsDataCommand(char *str)
{
	char *str1=new char[10240+5120];
	BOOL rv;
	strcpy(str1,str);
	if(strcmp(MakeUpper(str1),"DATA\r\n")==0)	
		rv= true;
	else
		rv= false;
	delete str1;
	return rv;
}

char* CSmtpProxyMT::MakeUpper(char* str)
{	
	char* tmp=str;
	while(*tmp)
	{
		if(islower(*tmp))
			*tmp=_toupper(*tmp);
		tmp++;
	}
	return str;
}

BOOL CSmtpProxyMT::IsEndOfData(char *str)
{
	if(strstr(str,"\r\n.\r\n")!=NULL)
		return true;
	else 
		return false;
}

BOOL CSmtpProxyMT::FoundBoundary(char *boundary, char *buff)
{
	char *buff1=new char[10240+5120];
	strcpy(buff1,buff);
	char *tmp=strstr(buff1,"boundary=\"");
	if(tmp==NULL)
	{
		delete buff1;
		return false;
	}
	tmp+=10;
	char *tmp1=strstr(tmp,"\"\r\n");
	if(tmp1==NULL)
	{
		delete buff1;
		return false;
	}
	*tmp1=0;
	strcpy(boundary,tmp);
	delete buff1;
	return true;
}

int CSmtpProxyMT::InsertTextSignature(char *buff, char* sig)
{
	char *tmp=strstr(buff,"\r\n.\r\n");
	*tmp=0;
	strcat(buff,sig);
	strcat(buff,"\r\n.\r\n");
	return strlen(sig);
}


BOOL CSmtpProxyMT::SetSignature(char *sig)
{
	if(strlen(sig)>2047)
		return false;
	strcpy(ProxySignature,sig);
	return true;
}


void CSmtpProxyMT::AddToEnd(char *buff, char *b, char* sig)
{
	char *newbuff1=new char[10240+5120];
	char *newbuff2=new char[10240+5120];
	strcpy(newbuff1,buff);	
	char *p1;
	int skip=1;
	for(int i=0;i<=1;i++)
	{
		p1=newbuff1;
		for(int j=0;j<skip;j++)
		{
			p1=strstr(p1,b);
			if(p1==NULL)
			{
				delete newbuff1;
				delete newbuff2;
				return;
			}
			p1++;
		}
		p1=strstr(p1,b);
		if(p1==NULL)
		{
			delete newbuff1;
			delete newbuff2;
			return;
		}
		strcpy(newbuff2,p1);
		*p1=0;
		strcat(newbuff1,sig);
		strcat(newbuff1,newbuff2);		
		skip++;
	}

	strcpy(buff,newbuff1);

	delete newbuff1;
	delete newbuff2;
}

int CSmtpProxyMT::StopProxy()
{
	if(!AcceptFlag)
		return ERR_STOPPED;
	AcceptFlag=false;
	closesocket(SmtpServerSocket);
	return OK_SUCCESS;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Nish Nishant is a technology enthusiast from Columbus, Ohio. He has over 20 years of software industry experience in various roles including Chief Technology Officer, Senior Solution Architect, Lead Software Architect, Principal Software Engineer, and Engineering/Architecture Team Leader. Nish is a 14-time recipient of the Microsoft Visual C++ MVP Award.

Nish authored C++/CLI in Action for Manning Publications in 2005, and co-authored Extending MFC Applications with the .NET Framework for Addison Wesley in 2003. In addition, he has over 140 published technology articles on CodeProject.com and another 250+ blog articles on his WordPress blog. Nish is experienced in technology leadership, solution architecture, software architecture, cloud development (AWS and Azure), REST services, software engineering best practices, CI/CD, mentoring, and directing all stages of software development.

Nish's Technology Blog : voidnish.wordpress.com

Comments and Discussions