SetUnhandledExceptionFilter+Mini-dump + smtp 发送邮件

上次转过一篇SetUnhandledExceptionFilter生成Mini-dump文件分析 的文章,  使程序在崩溃是生成dump   文件, 从而使程序bug得以再好的调试.


现在在网上找到了用C++写的发送邮件功能程序, 使之可以把dump 文件发放给开发者. 测试过代码可以使用, 支持代理功能(没测试), 至少QQ邮件是可以发送的.

下面是C++代码,  C代码后面有时间再修改出来.

整个工程序放在了我的资源里面:  自己可以找找去. 如果找不到发邮件给我(420557464@qq.com)

生成dump 函数和主函数: 

#include "stdafx.h"


#include <windows.h>
#include <dbghelp.h>
#include <stdio.h>
#include <time.h>
#include "Client.h"
#pragma comment(lib, "dbghelp")
#ifndef _M_IX86
#error "The following code only works for x86!"
#endif


void DisableSetUnhandledExceptionFilter()
{
	void *addr = (void*)GetProcAddress(LoadLibrary(_T("kernel32.dll")),
		"SetUnhandledExceptionFilter");
	if (addr)
	{
		unsigned char code[16];
		int size = 0;
		code[size++] = 0x33;
		code[size++] = 0xC0;
		code[size++] = 0xC2;
		code[size++] = 0x04;
		code[size++] = 0x00;


		DWORD dwOldFlag, dwTempFlag;
		VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);
		WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);
		VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);
	}
}


LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* lpExceptionInfo)
{
	TCHAR szProgramPath[MAX_PATH] = {0};
	TCHAR szDumpFile[MAX_PATH] = {0};
	TCHAR prog_name[MAX_PATH] = {0};


	time_t rawtime;
	struct tm * timeinfo;
	time ( &rawtime );
	timeinfo = localtime ( &rawtime );


	if(GetModuleFileName(NULL, prog_name, MAX_PATH))
	{
		LPTSTR lpSlash = _tcsrchr(prog_name, '.');
		if(lpSlash)
		{
			*(lpSlash) = '_';
			*(lpSlash + 1) = '\0';
		}
	}
	_stprintf(szDumpFile, _T("%s%4d%02d%02d%02d%02d%02d.dmp"), 
								prog_name,//szProgramPath,  
								1900+timeinfo->tm_year, 
								1+timeinfo->tm_mon,  
								timeinfo->tm_mday,
								timeinfo->tm_hour,
								timeinfo->tm_min,
								timeinfo->tm_sec, 
								time(NULL));


	TCHAR szReportFile[MAX_PATH] = {0};
	_stprintf(szReportFile, _T("%sBugReport.exe"), prog_name);


	HANDLE hDumpFile = CreateFile(szDumpFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL ,NULL);
	MINIDUMP_EXCEPTION_INFORMATION stMiniDumpExceptionInfo;
	stMiniDumpExceptionInfo.ExceptionPointers = lpExceptionInfo;
	stMiniDumpExceptionInfo.ThreadId = GetCurrentThreadId();
	stMiniDumpExceptionInfo.ClientPointers = TRUE;


	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile,
		MiniDumpNormal, &stMiniDumpExceptionInfo, NULL, NULL);
	CloseHandle(hDumpFile);
	::ShellExecute(NULL, NULL, szReportFile, szDumpFile, NULL, SW_HIDE);


	
	//Use your own user-friendly ui prompt here
	//Sleep(3000);
	ClientCommandResolve(szDumpFile);
	MessageBox(NULL, _T("Oh, No! 程序居然崩溃了!"), _T("ERROR"), MB_OK);
	
	return EXCEPTION_EXECUTE_HANDLER;
}


int main()
{
	int *p = NULL;


	//ClientCommandResolve(szDumpFile);
	SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
	DisableSetUnhandledExceptionFilter();
	*p = 22;
	return 0;
}
邮件功能部分:

// Client.cpp : Defines the entry point for the console application.
//by caucy 2005.12

#include "stdafx.h"
#include "Client.h"
#include <winsock2.h>
#include <afxsock.h>
#include <assert.H>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <set>
#include <string>
#include <time.h>
#include <sys/TIMEB.H>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// The one and only application object

CWinApp theApp;
using namespace std;

#define BUFFER_BLOCK_SIZE 4096
#define DEAL_RETURN_CODE(retCode) {	if((retCode)!=0)	return retCode;}
#define DEAL_SOCK_ERROR(retCode,sock)	if((retCode)==SOCKET_ERROR || (retCode)==0)\
										{										\
											cout<<"Sock error: "<<GetLastError()<<endl;\
											closesocket(sock);					\
											return -1;							\
										}

//Auxiliary Functions
int ClientCommandResolve();
void InputLine(string & str);
int GetResponseCode(SOCKET sock,int correctCode,string& str);
BOOL ResponsedCodeFinished(const string& str);
u_long ConvertHostnameToLongHostAddress(const char * destAddress);
BOOL SendMessage(SOCKET sock, const char* buffer, int bufferLen);

//Sub-Functions in Client Command
void EncodingBase64(const char* src, char* des);
void DecodingBase64(const char* src, char* des);
void EncodingBase64Adv(const char* src, int length, char* des);
void DecodingBase64Adv(const char* src, int length, char* des);
UCHAR SixBitDecodeIndex(char a);
BOOL EncodeFileBase64(const string& filename, string& code);
BOOL ReadFileToStr(const string& filename, string& code);
void HeadTextTemple(const string& command,const string& addr,string & buffer, BOOL bPrintCommond=TRUE);
void Date(string& buffer);
void From(const string& addr,string & buffer);
void To(const vector<string >& to,string & buffer);
void Cc(const vector<string >& cc,string & buffer);
void Bcc(const vector<string >& bcc,string & buffer);

void DataHead(const string& from,
			  const vector<string >& to,
			  const vector<string >& cc,
			  const vector<string >& bcc,
			  const string & subject,
			  const string& bodytext,
	    	  const string& bodytexthtml,
			  BOOL bHtml,
			  BOOL bAttachment,
			  string& majorSplitTag,
			  string& buffer);
void DataBody(	BOOL bHtmlBody,
				BOOL bAttachment,
				const string& majorSplitTag,
				const string& bodytext,
				const string& bodytexthtml,
				const vector<string> & attachments,
				string& buffer);
void DataBody_PureText(const string& bodytext_base64, string& buffer);
void DataBody_TextAndAttachments(const string& bodytext_base64, 
								 const vector<string >& attachments,
								   const string& majorSplitTag,
								   string& buffer);
void DataBody_HtmlOnly(const string& bodytext_base64, 
					   const string& html_base64,
					   const string& majorSplitTag,
					   string& buffer);
void DataBody_HtmlAndAttachments(const string& bodytext_base64, 
								 const string& html_base64, 
								 const vector<string >& attachments,
								 const string& majorSplitTag,
								 const string& subSplitTag,
								 string& buffer);

//Agent Application Functions
int SendMail(const string& proxyServerName,
			 UINT proxyServerPort,
			 const string& proxyUser,
			 const string& proxyPass,
			 const string& serverHostName,	 
			 UINT serverPort, 
			 const string& username, 
			 const string pass,
			 const string& senderAddr,
			 const vector<string >& recptAddress,
			 const vector<string >& from, //for most mail server, it only support youself address
			 const vector<string >& to,
			 const vector<string >& cc,
			 const vector<string >& bcc,
			 const string & subject,
			 const string & bodytext,
			 const string & bodyhtml,
			 const vector<string >&attachments);
int Socks5StartIPv4(const string& proxyServerHostName,
				u_int proxyServerPort,
				const string& username, 
				const string& pass,
				u_long destAddress,
				u_int destPort,
				SOCKET& sock);
/*
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{

	ClientCommandResolve();
	return 0;
}
*/

void InputLine(string & str)
{
	char ch;
	str="";
	while((ch = getchar())!= '\n')
		str+=ch;
}

int ClientCommandResolve()
{
	string serverHostName;
	UINT serverPort=0;
	string senderAddr;
	vector<string> recptAddrs;
	string username;
	string pass;
	vector<string > from;
	vector<string > to;
	vector<string > cc;
	vector<string > bcc;
	string subject;
	string bodytext;
	string bodytexthtml;
	vector<string >attachments;
	//proxy
	string proxyServerName;
	UINT proxyServerPort;
	string proxyUser;
	string proxyPass;

//	serverPort=25;
//	username="";
//	pass="";
//	proxyServerName="";
//	proxyServerPort=;
//	proxyUser="";
//	proxyPass="";
	
	char paraCommand[BUFFER_BLOCK_SIZE];
	int  pos=0;
	int iResult;
	string str;
	string::size_type startPos;

	WSADATA wsaData;
	if(WSAStartup(MAKEWORD( 2, 2 ), &wsaData)!=0)
	{
		cerr<<"socket init error"<<endl;
		return -1;
	}
	
	while(1)
	{
		//SMTP Server host name
		if(serverHostName.length()==0)	//for testing
		while(1)
		{
			cout<<"SMTP Server Host Name:";
			cout.flush();
			InputLine(str);
			iResult=sscanf(str.c_str(),"%s",paraCommand);
			if(iResult==EOF)
			{
				cout<<"Input server host name"<<endl;
				continue;
			}
			serverHostName=paraCommand;
			break;
		}
		
		//SMPT Server Port
		if(serverPort==0)	//for testing
		while(1)
		{
			cout<<"SMTP Server Port:";
			cout.flush();
			InputLine(str);
			iResult=sscanf(str.c_str(),"%s",paraCommand);
			if(iResult!=EOF)
			{
				serverPort=atoi(paraCommand);
				if(serverPort<0)
				{
					cout<<"Invalid port."<<endl;
					continue;
				}
			}
			break;
		}

		//USER NAME
		if(username.length()==0)	//for testing
		while(1)
		{
			cout<<"USER NAME:";
			cout.flush();
			InputLine(str);
			iResult=sscanf(str.c_str(),"%s",paraCommand);
			if(iResult==EOF)
			{
				cout<<"Input user name for authentication."<<endl;
				continue;
			}
			username=paraCommand;
			break;
		}

		//PASS
		if(pass.length()==0)	//for testing
		while(1)
		{
			cout<<"PASSWORD:";
			cout.flush();
			InputLine(str);
			iResult=sscanf(str.c_str(),"%s",paraCommand);
			if(iResult==EOF)
			{
				cout<<"Input password."<<endl;
				continue;
			}
			pass=paraCommand;
			break;
		}

		//Proxy
		if(proxyServerName.length()==0)	//for testing
		{
			cout<<"Proxy?";
			cout.flush();
			InputLine(str);
			if(str=="y" || str=="Y")
			{
				cout<<"Proxy Server Addr:";
				InputLine(proxyServerName);
				cout<<"Proxy Server Port:";
				InputLine(str);
				sscanf(str.c_str(),"%d",&proxyServerPort);
				cout<<"Proxy Server Username:";
				InputLine(proxyUser);
				cout<<"Proxy Server Pass:";
				InputLine(proxyPass);
			}
		}
		cout.flush();
		//MAIL FROM
		//Though rfc822 supports muti-senders, most email server today only support authentication login.
		//So, the fact is one sender one mail.
		if(senderAddr.length()==0)	//for testing
		while(1)
		{
			cout<<"MAIL FROM:";
			cout.flush();
			InputLine(str);
			iResult=sscanf(str.c_str(),"%s",paraCommand);
			if(iResult==EOF)
			{
				cout<<"Input sender address."<<endl;
				continue;
			}
			senderAddr=paraCommand;
			break;
		}
		from.push_back(senderAddr);

/*
		//RCPT TO
		//If having multiple receivers, here using spaces to split them
		if(recptAddrs.empty())		//for testing
		while(1)
		{
			cout<<"RCPT TO:";
			cout.flush();
			InputLine(str);
			while(1)
			{
				iResult=sscanf(str.c_str(),"%s",paraCommand); 
				if(iResult==EOF)
					break;
				startPos=str.find(paraCommand,0,strlen(paraCommand));
				startPos+=strlen(paraCommand);
				str=str.substr(startPos,str.length()-startPos);
				recptAddrs.push_back(string(paraCommand));
			}
			if(recptAddrs.size()==0)
			{
				cout<<"Input receiver address."<<endl;
				continue;
			}
			break;
		}
*/
		//to
		if(to.empty())		//for testing
		{
			cout<<"To: ";
			cout.flush();
			InputLine(str);
			while(1)
			{
				if(str.length()==0)
					break;
				iResult=sscanf(str.c_str(),"%s",paraCommand);
				if(iResult==EOF)
					break;
				startPos=str.find(paraCommand,0,strlen(paraCommand));
				startPos+=strlen(paraCommand);
				str=str.substr(startPos,str.length()-startPos);
				to.push_back(string(paraCommand));
			}
		}

		//Cc
		if(cc.empty())		//for testing
		{
			cout<<"Cc: ";
			cout.flush();
			InputLine(str);
			while(1)
			{
				if(str.length()==0)
					break;
				iResult=sscanf(str.c_str(),"%s",paraCommand);
				if(iResult==EOF)
					break;
				startPos=str.find(paraCommand,0,strlen(paraCommand));
				startPos+=strlen(paraCommand);
				str=str.substr(startPos,str.length()-startPos);
				cc.push_back(string(paraCommand));
			}
		}

		//Bcc
		if(cc.empty())		//for testing
		{
			cout<<"Bcc: ";
			cout.flush();
			InputLine(str);
			while(1)
			{
				if(str.length()==0)
					break;
				iResult=sscanf(str.c_str(),"%s",paraCommand);
				if(iResult==EOF)
					break;
				startPos=str.find(paraCommand,0,strlen(paraCommand));
				startPos+=strlen(paraCommand);
				str=str.substr(startPos,str.length()-startPos);
				bcc.push_back(string(paraCommand));
			}
		}

		//Subject
		if(subject.length()==0)		//for testing
		{
			cout<<"Subject:"<<endl;
			cout.flush();
			InputLine(subject);
		}

		//DATA body: text
		if(bodytext.length()==0)		//for testing
		{
			bodytext="";
			cout<<"DATA:"<<endl;
			cout.flush();
			while(1)
			{
				InputLine(str);
				if(str=="_Quit")
					break;
				bodytext+=str+"\r\n";
			}
		}

		//DATA body: html
		//Most email reader-agents support html coded email. So we support it too.
		if(bodytexthtml.length()==0)		//for testing
		{
			cout<<"Do you want peer-agent to see a html coded email?Y/N?";
			cout.flush();
			InputLine(str);
			if(str=="Y" || str=="y")
			{
				cout<<"Input the html file's directory."<<endl;
				InputLine(str);
				if(str!="")
				{
					ReadFileToStr(str,bodytexthtml);
				}
			}
		}

		//DATA body: attachment
		if(attachments.empty())		//for testing
		{
			cout<<"Do you want to send attachments?Y/N?";
			cout.flush();
			InputLine(str);
			if(str=="Y" || str=="y")
			{
				cout<<"Input the attachment file's directory."<<endl;
				while(1)
				{
					InputLine(str);
					if(str!="")
						attachments.push_back(str);
					else
						break;
				}
			}
		}
		cout<<"Sending Mail....."<<endl;

		//regroup rectpAddres array
		set<string> stringSet;
		int i;
		for(i=0; i< to.size(); i++)
		{
			stringSet.insert(to[i]);
		}
		for(i=0; i< cc.size(); i++)
		{
			stringSet.insert(cc[i]);
		}
		for(i=0; i< bcc.size(); i++)
		{
			stringSet.insert(bcc[i]);
		}
		for(set<string >::iterator iteSet=stringSet.begin();
				iteSet!=stringSet.end(); iteSet++)
		{
			recptAddrs.push_back(*iteSet);
		}

		iResult=SendMail(proxyServerName,proxyServerPort,proxyUser,proxyPass,
						serverHostName,serverPort,username,pass,
						senderAddr,recptAddrs,
						from,to,cc, bcc,subject,bodytext,bodytexthtml,attachments);
		if(iResult==-1)
		{
			cout<<"Unsuccessfully sent this mail. Save it to file."<<endl;
			//unfinished. Here should save the transaction into file.
		}
		
		cout<<"QUIT?";
		cout.flush();
		InputLine(str);
		if(str=="y"||str=="Y")
		{
			cout<<"Bye!"<<endl;
			return -1;
		}
		recptAddrs.clear();
		from.clear();
		to.clear();
		cc.clear();
		bcc.clear();
		subject="";
		bodytext="";
		bodytexthtml="";
		attachments.clear();
	}
	return 0;
}

//for multiple response code
int GetResponseCode(SOCKET sock,int correctCode,string& str)
{
	int retCode;
	char buffer[BUFFER_BLOCK_SIZE+1];
	str="";
	while(1)
	{
		retCode=recv(sock,buffer,BUFFER_BLOCK_SIZE,0);
		if(retCode==SOCKET_ERROR || retCode==0)
			return -1;
		buffer[retCode]='\0';
		cout<<buffer;
		cout.flush();
		str+=buffer;
		if(ResponsedCodeFinished(str))
		{
			if(atoi(str.c_str())==correctCode)
				return 0;
			else
				return 1;
		}
	}
}

BOOL ResponsedCodeFinished(const string& str)
{
	if(str[str.length()-2]!='\r' || str[str.length()-1]!='\n')
		return FALSE;
	if(str[3]!='-')
		return TRUE;
	char code[4];
	int beginCode=atoi(str.c_str());
	itoa(beginCode,code,10);
	std::string::size_type pos=str.rfind(code,str.length()-1);
	return str[pos+3]==' ';
}


int SendMail(const string& proxyServerName,
			 UINT proxyServerPort,
			 const string& proxyUser,
			 const string& proxyPass,
			 const string& serverHostName,	 
			 UINT serverPort, 
			 const string& username, 
			 const string pass,
			 const string& senderAddr,
			 const vector<string >& recptAddress,
			 const vector<string >& from, //for most mail server, it only support youself address
			 const vector<string >& to,
			 const vector<string >& cc,
			 const vector<string >& bcc,
			 const string & subject,
			 const string & bodytext,
			 const string & bodyhtml,
			 const vector<string >&attachments)
{
	sockaddr_in serverAddr;
	SOCKET sock;
	hostent * host;
	char buffer[BUFFER_BLOCK_SIZE];
	int i;
	BOOL bHtml,bAttachment;
	string str;
	if(bodyhtml.length()==0)
		bHtml=FALSE;
	else
		bHtml=TRUE;
	if(attachments.size()==0)
		bAttachment=FALSE;
	else
		bAttachment=TRUE;

	if(proxyServerName.length()!=0)//using socks5 proxy
	{
		u_long addr=ConvertHostnameToLongHostAddress(serverHostName.c_str());
		if(Socks5StartIPv4(proxyServerName,proxyServerPort,proxyUser,proxyPass,addr,serverPort,sock)!=0)
		{
			cerr<<"Proxy server error!"<<endl;
		}
	}
	else
	{
		host=gethostbyname(serverHostName.c_str());
		if(host==NULL)
		{
			cout<<"Cann't resolve this host name: "<<GetLastError()<<endl;
			return -1;
		}

		sock=socket(AF_INET, SOCK_STREAM,0);
		serverAddr.sin_addr=*(struct in_addr*)host->h_addr;
		serverAddr.sin_family=AF_INET;
		serverAddr.sin_port=htons(serverPort);
		cout<<"Connecting to "<<inet_ntoa(serverAddr.sin_addr)<<endl;
		cout.flush();
		if(connect(sock,(const sockaddr*)&serverAddr,sizeof(sockaddr))==SOCKET_ERROR)
		{
			cout<<"Cannot connect to Server: "<<serverHostName.c_str()<<endl;
			cout.flush();
			closesocket(sock);
			return -1;
		}
	}
	//1. welcome words
	DEAL_RETURN_CODE(GetResponseCode(sock,220,str));

	//2. HELO.
	//We omit HELO, because most Email Server needs authentication.

	//3. EHLO
	sprintf(buffer,"EHLO %s\r\n",senderAddr.c_str());
	cout<<buffer;
	send(sock,buffer,strlen(buffer),0);
	DEAL_RETURN_CODE(GetResponseCode(sock,250,str));

	//4. AUTH LOGIN. 
	//Most authentication takes AUTH LOGIN and AUTH PLAIN. Here we take AUTH LOGIN by default.
	sprintf(buffer,"AUTH LOGIN\r\n");
	cout<<buffer;
	send(sock,buffer,strlen(buffer),0);
	DEAL_RETURN_CODE(GetResponseCode(sock,334,str));
	
	//2. USER NAME
	//User name is coded by base64.
	EncodingBase64(username.c_str(),buffer);
	strcat(buffer,"\r\n");
	cout<<buffer;
	send(sock,buffer,strlen(buffer),0);
	DEAL_RETURN_CODE(GetResponseCode(sock,334,str));

	//2. password coded by base64
	EncodingBase64(pass.c_str(),buffer);
	strcat(buffer,"\r\n");
	cout<<buffer;
	send(sock,buffer,strlen(buffer),0);
	DEAL_RETURN_CODE(GetResponseCode(sock,235,str));

	//2. MAIL FROM
	sprintf(buffer,"MAIL FROM:<%s>\r\n",senderAddr.c_str());
	cout<<buffer;
	send(sock,buffer,strlen(buffer),0);
	DEAL_RETURN_CODE(GetResponseCode(sock,250,str));

	//2. RCPT
	for(i=0;i<recptAddress.size();i++)
	{
		sprintf(buffer,"RCPT TO: <%s>\r\n",recptAddress[i].c_str());
		cout<<buffer;
		send(sock,buffer,strlen(buffer),0);
		DEAL_RETURN_CODE(GetResponseCode(sock,250,str));
	}

	//2. DATA
	sprintf(buffer,"DATA\r\n");
	cout<<buffer;
	send(sock,buffer,strlen(buffer),0);
	DEAL_RETURN_CODE(GetResponseCode(sock,354,str));
	
	string majorSplitTag;

	//DATA head
	DataHead(from[0],to,cc,bcc,subject,bodytext,bodyhtml,bHtml,bAttachment,majorSplitTag,str);
	cout<<str.c_str();
	cout.flush();
	//send(sock,str.c_str(),str.length(),0);
	SendMessage(sock,str.c_str(),str.length());

	
	//DATA body
	DataBody(bHtml,bAttachment,majorSplitTag,bodytext,bodyhtml,attachments,str);
	cout<<str.c_str();
	cout.flush();
//	send(sock,str.c_str(),str.length(),0);
	SendMessage(sock,str.c_str(),str.length());
	DEAL_RETURN_CODE(GetResponseCode(sock,250,str));
	
	//2. QUIT
	strcpy(buffer,"QUIT\r\n");
	cout<<buffer;
	send(sock,buffer,strlen(buffer),0);
	DEAL_RETURN_CODE(GetResponseCode(sock,221,str));

	closesocket(sock);
	return 0;
}

//we donnot want to allocate another buffer for src, so we write this encoding 
void EncodingBase64(const char* src, char* des)
{
	assert(src&&des);
	char sixbit_encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	while(*src!=NULL)
	{
		*des++=sixbit_encoding[(UCHAR)*src++>>2]; //6
		if(*src==NULL)
		{
			*des++=sixbit_encoding[(*(src-1)&0x3)<<4];//2+4
			*des++='=';
			*des++='=';
			break;
		}
		else
		{
			*des++=sixbit_encoding[(*(src-1)&0x3)<<4 | UCHAR(*src)>>4];//2+4
			src++;
		}
		if(*src==NULL)
		{
			*des++=sixbit_encoding[(*(src-1)&0xF)<<2];//4+2
			*des++='=';
		}
		else
		{
			*des++=sixbit_encoding[(*(src-1)&0xF)<<2 | UCHAR(*src)>>6];//4+2
			*des++=sixbit_encoding[*src&0x3F];//6
			src++;
		}
	}
	*des=NULL;
}



void EncodingBase64Adv(const char* src, int length,char* des)
{
	int i=0;
	char sixbit_encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	assert(des);
	while(i<length)
	{
		*des++=sixbit_encoding[(UCHAR)src[i++]>>2]; //6
		if(i==length)
		{
			*des++=sixbit_encoding[(src[i-1]&0x3)<<4];//2+4
			*des++='=';
			*des++='=';
			break;
		}
		else
		{
			*des++=sixbit_encoding[(src[i-1]&0x3)<<4 | UCHAR(src[i])>>4];//2+4
			i++;
		}
		if(i==length)
		{
			*des++=sixbit_encoding[(src[i-1]&0xF)<<2];//4+2
			*des++='=';
		}
		else
		{
			*des++=sixbit_encoding[(src[i-1]&0xF)<<2 | UCHAR(src[i])>>6];//4+2
			*des++=sixbit_encoding[src[i]&0x3F];//6
			i++;
		}
	}
	*des=NULL;
}

//For high efficient, pls rewrite it using looking-up table
UCHAR SixBitDecodeIndex(char a)
{
	if(a>='A'&&a<='Z')
		return a-'A';
	else if(a>='a'&&a<='z')
		return 26+a-'a';
	else if(a>='0'&&a<='9')
		return 52+a-'0';
	else if(a=='+')
		return 62;
	else if(a=='/')
		return 63;
	else if(a=='=')
		return 0;
	else
	{
		assert(FALSE);
		return -1;
	}
}

void DecodingBase64(const char* src, char* des)
{
	assert(src&&des);
	assert(strlen(src)%4==0);
	while(*src!=NULL)
	{
		*des++=SixBitDecodeIndex(*src)<<2 | SixBitDecodeIndex(*(src+1))>>4;	//6+2
		src++;
		*des++=SixBitDecodeIndex(*src)<<4 | SixBitDecodeIndex(*(src+1))>>2;//4+4
		src++;
		*des++=SixBitDecodeIndex(*src)<<6 | SixBitDecodeIndex(*(src+1));	//2+6
		src+=2;
	}
	*des=NULL;
}

void DecodingBase64Adv(const char* src, int length, char* des)
{
	int i=0;
	assert(des);
	assert(length%4==0);
	while(i<length)
	{
		*des++=SixBitDecodeIndex(src[i])<<2 | SixBitDecodeIndex(src[i+1])>>4;	//6+2
		i++;
		*des++=SixBitDecodeIndex(src[i])<<4 | SixBitDecodeIndex(src[i+1])>>2;//4+4
		i++;
		*des++=SixBitDecodeIndex(src[i])<<6 | SixBitDecodeIndex(src[i+1]);	//2+6
		i+=2;
	}
	*des=NULL;
}

void Date(string& buffer)
{
	struct tm *newtime;
	time_t aclock;
	struct _timeb tstruct;

	char str[BUFFER_BLOCK_SIZE];
	time( &aclock );
	newtime = localtime( &aclock );
	strftime( str, BUFFER_BLOCK_SIZE,"%a, %d %b %Y %X ", newtime);
	buffer=string("Date:")+str;
	
    _ftime( &tstruct );
	if(tstruct.timezone<0)
		sprintf(str,"+%.2d%.2d\r\n",-tstruct.timezone/60,-tstruct.timezone%60);
	else
		sprintf(str,"-%.2d%.2d\r\n",tstruct.timezone/60,tstruct.timezone%60);
	buffer+=str;
}


void MimeVersion(string & buffer)
{
	buffer="Mime-Version: 1.0\r\n";
}
void Subject(const string& title,string & buffer)
{
	char str[BUFFER_BLOCK_SIZE];
	string::size_type pos=0;
	BOOL bBase64=FALSE;
	WCHAR wszUserName[BUFFER_BLOCK_SIZE/2];          // Unicode user name
	int i;
	int length=MultiByteToWideChar( CP_ACP, 0, title.c_str(),title.length()+1, wszUserName,   
		sizeof(wszUserName)/sizeof(WCHAR));
	if(length==0 && title.length()!=0)
		bBase64=TRUE;
	for(i=0; i<length; i++)
	{
		if(wszUserName[i]  >= 256)
		{
			bBase64=TRUE;
			break;
		}
	}
	if(bBase64)
	{
		EncodingBase64(title.c_str(),str);
		buffer=string("Subject: ") + "=?gb2312?B?" + str + "?=\r\n";
	}
	else
	{
		buffer="Subject: "+title+"\r\n";
	}
}

void HeadTextTemple(const string& command,const string& addr,string & buffer, BOOL bPrintCommond)
{
	char str[BUFFER_BLOCK_SIZE],str2[BUFFER_BLOCK_SIZE];
	string::size_type pos=0;
	BOOL bBase64=FALSE;
	WCHAR wszUserName[BUFFER_BLOCK_SIZE/2];          // Unicode user name
	int i;
	int length=MultiByteToWideChar( CP_ACP, 0, addr.c_str(),addr.length()+1, wszUserName,   
		sizeof(wszUserName)/sizeof(WCHAR));

	buffer="";
	if(length==0)
		bBase64=TRUE;
	for(i=0; i<length; i++)
	{
		if(wszUserName[i]  >= 256)
		{
			bBase64=TRUE;
			break;
		}
	}
	if(bBase64)
	{
		if((pos=addr.find("<",pos))==string::npos)
		{
			if((pos=addr.find(" ",pos))==string::npos)
				return;
		}
		strcpy(str,addr.c_str());
		str[pos]=NULL;
		EncodingBase64(str,str2);
		if(bPrintCommond)
			buffer= command + ": \"=?gb2312?B?" + str2 + "?=\"" + (addr.c_str()+pos) + "\r\n";
		else
			buffer= string("\"=?gb2312?B?") + str2 + "?=\"" + (addr.c_str()+pos);
	}
	else
	{
		if((pos=addr.find("<",pos))==string::npos)
		{
			if(bPrintCommond)
				buffer=command + ": <" + addr + ">\r\n";
			else
				buffer=string("<") + addr + ">";
		}
		else
		{
			if(bPrintCommond)
				buffer=command + ": " + addr + "\r\n";
			else
				buffer= addr;
		}
	}
}

void From(const string& addr,string & buffer)
{
	HeadTextTemple("From", addr , buffer);
}
void To(const vector<string >& to,string & buffer)
{
	string str;
	buffer="To: ";
	for(int i=0;i<to.size();i++)
	{
		if(i!=0)
			buffer+=",";
		HeadTextTemple("To", to[i] , str, FALSE);
		buffer+=str;
	}
	buffer+="\r\n";
}
void Cc(const vector<string >& cc,string & buffer)
{
	string str;
	int i;
	buffer="";
	if(cc.size())
		buffer="Cc: ";
	for(i=0;i<cc.size();i++)
	{
		if(i!=0)
			buffer+=",";
		HeadTextTemple("Cc", cc[i] , str, FALSE);
		buffer+=str;
	}
	if(cc.size())
		buffer+="\r\n";
}
void Bcc(const vector<string >& bcc,string & buffer)
{
	string str;
	int i;
	buffer="";
	if(bcc.size())
		buffer="Bcc: ";
	for(i=0;i<bcc.size();i++)
	{
		if(i!=0)
			buffer+=",";
		HeadTextTemple("Bcc", bcc[i] , str, FALSE);
		buffer+=str;
	}
	if(bcc.size())
		buffer+="\r\n";
}

void ReplyTo(const string& addr,string & buffer)
{
	HeadTextTemple("Reply-to", addr , buffer);
}
void XMailer(string & buffer)
{
	char str[BUFFER_BLOCK_SIZE];
	EncodingBase64("自己的Mailer",str);
	buffer=string("X-mailer: =?GB2312?B?") + str +"?=\r\n";
}
void MessageID(const string& from,string & buffer)
{
	string::size_type pos=0;
	char tB[BUFFER_BLOCK_SIZE];
	string str;
	long t=time(NULL);
	if((pos=from.find('@',pos))!=string::npos)
	{
		str=from.c_str()+pos;
		if((pos=str.find('>',pos))!=string::npos)
			sprintf(tB,"Message-ID: %d%s\r\n",t,str.c_str());
		else
			sprintf(tB,"Message-ID: <%d%s>\r\n",t,str.c_str());
		buffer=tB;
	}
	else
	{
		buffer=string("Message-ID: ")+ltoa(t,tB,10) +"\r\n";
	}
}

void DataHead(const string& from,
			  const vector<string >& to,
			  const vector<string >& cc,
			  const vector<string >& bcc,
			  const string & subject,
			  const string& bodytext,
	    	  const string& bodytexthtml,
			  BOOL bHtml,
			  BOOL bAttachment,
			  string& majorSplitTag,
			  string& buffer)
{
	string str;
	majorSplitTag="====MajorSplitTag====";
	buffer="";

	Date(str);
	buffer+=str;
	From(from,str);
	buffer+=str;
	To(to,str);
	buffer+=str;
	Cc(cc,str);
	buffer+=str;
	Bcc(bcc,str);
	buffer+=str;
	Subject(subject,str);
	buffer+=str;
	MessageID(from,str);
	buffer+=str;
	XMailer(str);
	buffer+=str;
	buffer+="Mime-Version: 1.0\r\n";
	if(!bHtml && !bAttachment) //pure text and no attachment
	{
		buffer+="Content-Type: text/plain;\r\n\tcharset=\"gb2312\"\r\n";
		buffer+="Content-Transfer-Encoding: base64\r\n";
	}
	else if(!bHtml) //having attachment
	{
		buffer+="Content-Type: multipart/mixed;\r\n\tboundary=\""+majorSplitTag+"\"\r\n";
	}
	else if(!bAttachment) //html
	{
		buffer+="Content-Type: multipart/alternative;\r\n\tboundary=\""+majorSplitTag+"\"\r\n";
	}
	else	//html and attachment
	{
		buffer+="Content-Type: multipart/mixed;\r\n\tboundary=\""+majorSplitTag+"\"\r\n";
	}
	majorSplitTag="--"+majorSplitTag+"\r\n";
}

void DataBody_PureText(const string& bodytext_base64, string& buffer)
{
	buffer=bodytext_base64;
	buffer+="\r\n";
}

void DataBody_HtmlOnly(const string& bodytext_base64, 
					   const string& html_base64,
					   const string& majorSplitTag,
					   string& buffer)
{
	buffer="This is a multi-part message in MIME format.\r\n";
	buffer+="\r\n";
	buffer+=majorSplitTag;
	buffer+="Content-Type: text/plain;\r\n\tcharset=\"gb2312\"\r\n";
	buffer+="Content-Transfer-Encoding: base64\r\n";
	buffer+="\r\n";
	buffer+=bodytext_base64;
	buffer+="\r\n";
	buffer+=majorSplitTag;
	buffer+="Content-Type: text/html;\r\n\tcharset=\"gb2312\"\r\n";
	buffer+="Content-Transfer-Encoding: base64\r\n";
	buffer+="\r\n";
	buffer+=html_base64;
	buffer+="\r\n";
	buffer+=majorSplitTag;
}

void DataBody_TextAndAttachments(const string& bodytext_base64, 
								 const vector<string >& attachments,
								   const string& majorSplitTag,
								   string& buffer)
{
	int i;
	string str;
	char sDrive[_MAX_DRIVE];	char sDir[_MAX_DIR];
	char sFname[_MAX_FNAME];	char sExt[_MAX_EXT];
	char strBuffer[BUFFER_BLOCK_SIZE];

	buffer="This is a multi-part message in MIME format.\r\n";
	buffer+="\r\n";
	buffer+=majorSplitTag;
	buffer+="Content-Type: text/plain;\r\n\tcharset=\"gb2312\"\r\n";
	buffer+="Content-Transfer-Encoding: base64\r\n";
	buffer+="\r\n";
	buffer+=bodytext_base64;
	buffer+="\r\n";

	for(i=0; i<attachments.size() ;i++)
	{
		_splitpath(attachments[i].c_str(), sDrive, sDir, sFname, sExt);
		strcat(sFname,sExt);
		EncodingBase64(sFname,strBuffer);
		str=string("=?gb2312?B?") + strBuffer + "?=";

		buffer+=majorSplitTag;
		buffer+=string("Content-Type: application/octet-stream;\r\n\tname=\"") + str + "\"\r\n";
		buffer+="Content-Transfer-Encoding: base64\r\n";
		buffer+="Content-Disposition: attachment;\r\n\t";
		buffer+=string("filename=\"")+str+"\"\r\n";
		buffer+="\r\n";
		EncodeFileBase64(attachments[i],str);
		buffer+=str+"\r\n";
	}
	buffer+=majorSplitTag;
}


void DataBody_HtmlAndAttachments(const string& bodytext_base64, 
								 const string& html_base64, 
								 const vector<string >& attachments,
								 const string& majorSplitTag,
								 const string& subSplitTag,
								 string& buffer)
{
	int i;
	string str,sub;
	char sDrive[_MAX_DRIVE];	char sDir[_MAX_DIR];
	char sFname[_MAX_FNAME];	char sExt[_MAX_EXT];
	char strBuffer[BUFFER_BLOCK_SIZE];
	
	buffer="This is a multi-part message in MIME format.\r\n";
	buffer+="\r\n";
	buffer+=majorSplitTag;
	buffer+="Content-Type: multipart/alternative;\r\n\tboundary=\"" + subSplitTag + "\"\r\n";
	buffer+="\r\n";
	sub="--"+subSplitTag+"\r\n";

	buffer+=sub;
	buffer+="Content-Type: text/plain;\r\n\tcharset=\"gb2312\"\r\n";
	buffer+="Content-Transfer-Encoding: base64\r\n";
	buffer+="\r\n";
	buffer+=bodytext_base64;
	buffer+="\r\n";	
	
	buffer+=sub;
	buffer+="Content-Type: text/html;\r\n\tcharset=\"gb2312\"\r\n";
	buffer+="Content-Transfer-Encoding: base64\r\n";
	buffer+="\r\n";
	buffer+=html_base64;
	buffer+="\r\n";

	buffer+=sub;

	for(i=0; i<attachments.size() ;i++)
	{
		_splitpath(attachments[i].c_str(), sDrive, sDir, sFname, sExt);
		strcat(sFname,sExt);
		EncodingBase64(sFname,strBuffer);
		str=string("=?gb2312?B?") + strBuffer + "?=";

		buffer+=majorSplitTag;
		buffer+=string("Content-Type: application/octet-stream;\r\n\tname=\"") + str + "\"\r\n";
		buffer+="Content-Transfer-Encoding: base64\r\n";
		buffer+="Content-Disposition: attachment;\r\n\t";
		buffer+=string("filename=\"")+str+"\"\r\n";
		buffer+="\r\n";
		EncodeFileBase64(attachments[i],str);
		buffer+=str+"\r\n";
	}

	buffer+=majorSplitTag;
}


void DataBody(	BOOL bHtmlBody,
				BOOL bAttachment,
				const string& majorSplitTag,
				const string& bodytext,
				const string& bodytexthtml,
				const vector<string> & attachments,
				string& buffer)
{
	string subSplitTag;
	string attachStr;
	string bodytext_base64,bodyhtml_base64;

	int length;
	char *tBuffer;

	subSplitTag="====SubSplitTag====";

	//text base64 encode
	length=(bodytext.length()/3+1)*4;
	tBuffer= new char[length+1];
	EncodingBase64(bodytext.c_str(),tBuffer);
	bodytext_base64=tBuffer;
	delete[] tBuffer;

	//html base64 encode if it's html coded email
	if(bHtmlBody)
	{
		length=(bodytexthtml.length()/3+1)*4;
		tBuffer= new char[length+1];
		EncodingBase64Adv(bodytexthtml.c_str(), bodytexthtml.length(), tBuffer);
		bodyhtml_base64=tBuffer;
		delete[] tBuffer;
	}
	
	if(!bHtmlBody && !bAttachment)	//pure text
	{
		DataBody_PureText(bodytext_base64,buffer);
	}
	else if(!bHtmlBody)				//text and attachments
	{
		DataBody_TextAndAttachments(bodytext_base64,attachments,majorSplitTag,buffer);
	}
	else if(!bAttachment)			//text,html 
	{
		DataBody_HtmlOnly(bodytext_base64,bodyhtml_base64,majorSplitTag,buffer);
	}
	else							//text, html and attachments
	{
		DataBody_HtmlAndAttachments(bodytext_base64,bodyhtml_base64,attachments,majorSplitTag,subSplitTag,buffer);
	}
	buffer+="\r\n.\r\n";
}

BOOL EncodeFileBase64(const string& filename, string& code)
{
	ifstream file;
	filebuf *fB;
	int length;
	char buffer[3073],des[4097];
	int curLen;

	code="";

	file.open(filename.c_str(),ios::binary);
	if(file.fail())
		return FALSE;

	//get the file length
	fB=file.rdbuf();
	length=fB->pubseekoff(0,ios::end,ios::in) - fB->pubseekoff(0,ios::beg,ios::in);
	//send filelength
	fB->pubseekoff(0,ios::beg,ios::in); //file pointer location
	while(length>0)
	{
		if(length<3072)
			curLen=length;
		else
			curLen=3072;
		file.read(buffer,curLen);
//		buffer[curLen]='\0';
		EncodingBase64Adv(buffer, curLen, des);
		code+=des;
		length-=3072;
	}
	file.close();
	return TRUE;
}

BOOL ReadFileToStr(const string& filename, string& code)
{
	ifstream file;
	filebuf *fB;
	int length;
	char buffer[BUFFER_BLOCK_SIZE+1];
	int curLen;
	code="";

	file.open(filename.c_str(),ios::binary);
	if(file.fail())
		return FALSE;

	//get the file length
	fB=file.rdbuf();
	length=fB->pubseekoff(0,ios::end,ios::in) - fB->pubseekoff(0,ios::beg,ios::in);
	//send filelength
	fB->pubseekoff(0,ios::beg,ios::in); //file pointer location
	while(length>0)
	{
		if(length<BUFFER_BLOCK_SIZE)
			curLen=length;
		else
			curLen=BUFFER_BLOCK_SIZE;
		file.read(buffer,curLen);
		buffer[curLen]='\0';
		code+=buffer;
		length-=BUFFER_BLOCK_SIZE;
	}
	file.close();
	return TRUE;
}


/**********************************************************************************/
u_long ConvertHostnameToLongHostAddress(const char * destAddress)
{
	hostent * host=gethostbyname((const char *)destAddress);
	if(host==NULL)
	{
		cout<<"Cann't resolve this host name: "<<GetLastError()<<endl;
		return -1;
	}
	return ntohl((*(struct in_addr*)host->h_addr).S_un.S_addr);
}

int Socks5StartIPv4(const string& proxyServerHostName,
				u_int proxyServerPort,
				const string& username, 
				const string& pass,
				u_long destAddress,
				u_int destPort,
				SOCKET& sock)
{
	sockaddr_in serverAddr;
	int retCode;
	char buffer[BUFFER_BLOCK_SIZE];
	BYTE version=5;
	BYTE authorWay1=0;	//no authority
	BYTE authorWay2=2;	//user/pass authority
	int rsv=0;
	string addrStr;
	u_int t;
	
	sock=socket(AF_INET, SOCK_STREAM,0);
	serverAddr.sin_addr.S_un.S_addr=htonl(ConvertHostnameToLongHostAddress(proxyServerHostName.c_str()));
	serverAddr.sin_family=AF_INET;
	serverAddr.sin_port=htons(proxyServerPort);
	cout<<"Connecting to "<<inet_ntoa(serverAddr.sin_addr)<<"\tPort:"<<proxyServerPort<<endl;
	cout.flush();
	if(connect(sock,(const sockaddr*)&serverAddr,sizeof(sockaddr))==SOCKET_ERROR)
	{
		cout<<"Cannot connect to Server: "<<proxyServerHostName.c_str()<<endl;
		cout.flush();
		closesocket(sock);
		return -1;
	}

	//1. authoutication negotiation
	sprintf(buffer,"%c%c%c%c",version,2,authorWay1,authorWay2);
	send(sock,buffer,4,0);
	retCode=recv(sock,buffer,BUFFER_BLOCK_SIZE,0);
	DEAL_SOCK_ERROR(retCode,sock);
	if(char(retCode)==0xFF)
		return 1;
	buffer[retCode]='\0';
	cout<<buffer;

	//user/pass authentication
	if(buffer[1]==authorWay2)
	{
		//user name
		sprintf(buffer,"%c%c%s%c%s",char(0x01),char(username.length()),username.c_str(),
				char(pass.length()),pass.c_str());
		t=3+username.length()+pass.length();
		send(sock, buffer, t, 0);
		retCode=recv(sock,buffer,BUFFER_BLOCK_SIZE,0);
		DEAL_SOCK_ERROR(retCode,sock);
		if(char(retCode)==0xFF)
			return 1;
		buffer[retCode]='\0';
		if(buffer[1]!=0)
			return 1;
	}
	
	//1. authoutication negotiation
	addrStr=buffer;
	t=htons(destPort);
	sprintf(buffer,"%c%c%c%c%c%c%c%c%c%c",version,char(0x01),rsv,char(0x01),
		((char*)&destAddress)[3],((char*)&destAddress)[2],((char*)&destAddress)[1],((char*)&destAddress)[0],
		((char *)&t)[0],((char *)&t)[1]);
	cout<<buffer;
	send(sock,buffer,10,0);
	retCode=recv(sock,buffer,BUFFER_BLOCK_SIZE,0);
	DEAL_SOCK_ERROR(retCode,sock);
	buffer[retCode]='\0';
	if(buffer[1]!=0)
	{
		sprintf(buffer,"%x",buffer[1]);
		cout<<"Failure in negotiation: "<<buffer<<endl;
		return 1;
	}
	return 0;
}

BOOL SendMessage(SOCKET sock, const char* buffer, int bufferLen)
{
	int startPos;
	int ret;
	startPos=0;
	while(bufferLen>0)
	{
		ret=send(sock,buffer+startPos,bufferLen,0);
		if(ret==0)
			break;
		if(ret==SOCKET_ERROR)
			return FALSE;
		startPos+=ret;
		bufferLen-=ret;
	}
	return bufferLen==0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值