上次转过一篇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;
}