mxrecord.cpp
/*
** All functions are displayed to implemented belonging to MXRecord class
*/
#include<iostream>
#include<winsock2.h>
#include"mxrecord.h"
using namespace std;
// MXRecord structor function
MXRecord::MXRecord( char * emailaddress )
{
// allocate buff space
memset( this->buff,'\0',512 );
memset( this->receiver,'\0',512 );
this->errorCode =0; // initialize errorCode
this->pemailAddress = emailaddress;
} //End MXRecord();
//MXRecord destructor function
MXRecord::~MXRecord()
{
} //~MXRecord()
//return errorCode value
//errorCode can describle error information when using class
// sending email class will be used the errorCode
int MXRecord::getErrorCode() const
{
return this->errorCode;
} //End getErrorCode()
//handle sending and receiving dns package
// handle parse response package at the same time
//all the result will be stored in mailExchanger and preference vector
//Warning: pay attention to bit pointer
void MXRecord::getResourceRecord()
{
// get resource record according to this->emailAddress
this->divideEmail( this->pemailAddress );
//每次进行处理下一个动作之前看前一个动作是否正常完成
if( this->errorCode < 0 )
return ;
//开始装DNS数据报
char *pbitptr = buff;//使用bitptr指针来指示每一个字节的地址
//装载header
*((unsigned short*)pbitptr) = htons(1000); //ID
pbitptr += 2;
*((unsigned short*)pbitptr) = htons(0x0100); //Flag pcode
pbitptr += 2;
*((unsigned short*)pbitptr) = htons(1); //qdcont
pbitptr+= 2;
*((unsigned short*)pbitptr) = htons(0); //ancount
pbitptr+= 2;
*((unsigned short*)pbitptr) = htons(0); //nscount
pbitptr+= 2;
*((unsigned short*)pbitptr) = htons(0); //arcount
pbitptr+= 2;
register int skipByte = 0;
//装载查询的部分
for( int i = 1;i <= this->sectionLength.size(); i++ )
{
//装载每一个label的长度
register unsigned short len = this->sectionLength.at( i-1 );
skipByte += len;
*pbitptr = len;
//装载对应的label
pbitptr++;
for( int j = 0; j < len;j++ )
{
*pbitptr = this->sectionString.at( i-1 ).at( j );
pbitptr++;
} //End for loop
} //End for loop
//装载最后的0
*pbitptr = 0;
//装载qtype = mx
pbitptr++;
*((unsigned short*)pbitptr) = htons(0x0f);
//装载qclass = in
pbitptr += 2;
*((unsigned short*)pbitptr) = htons(0x01);
pbitptr += 2;
int totalByte = pbitptr - buff;
//发送socket数据报
WSADATA wsadata;
if( WSAStartup( MAKEWORD( 2, 0),&wsadata ) != 0 )
{
this->errorCode = -2;
return ;
}
int sockfd;
if( ( sockfd = socket(AF_INET,SOCK_DGRAM,0 )) == -1 )
{
this->errorCode = -2;
return;
}
struct sockaddr_in localDNS;
struct sockaddr_in dnsserver;
int sockaddrLen = sizeof( struct sockaddr);
localDNS.sin_family = AF_INET;
localDNS.sin_port = htons(53);
localDNS.sin_addr.s_addr = inet_addr( "202.96.154.15" ); //DNS server ip
// localDNS.sin_addr.s_addr = inet_addr( "202.96.128.68" ); //DNS server ip
if( (sendto(sockfd,buff,totalByte,0,(struct sockaddr*)&localDNS,sizeof( struct sockaddr)))!= totalByte )
{
this->errorCode = -3;
return;
}
if( (recvfrom( sockfd,this->receiver,512,0,(struct sockaddr*)&dnsserver,&sockaddrLen)) == 0)
{
this->errorCode = -4;
return;
}
//检查收到的数据报是否是自己发送的
pbitptr = this->receiver;
if( ntohs( *(unsigned short*)pbitptr) != 1000)
{
this->errorCode = -5;
return;
}
//检查DNS服务器处理的结果
pbitptr += 2;
int rcode = 0xf & ntohs(*(unsigned short*)pbitptr);
if( rcode != 0 )
{
this->errorCode = -6;
return;
}
pbitptr += 2;//qncount;
pbitptr += 2; //ancount
int answer = ntohs(*((unsigned short*)pbitptr));
if( answer == 0 )
{
this->errorCode = -7;
return;
}
//authorative
pbitptr += 2;
//additional
pbitptr += 2;
pbitptr += 2;// query section
skipByte += sectionLength.size();
skipByte++;
pbitptr +=skipByte;
pbitptr += 4; // rr section
//处理每一个MX record
register char * ptemparory = pbitptr;
for( int index = 1; index <= answer;index++ )
{
pbitptr = ptemparory;
pbitptr += 2; //skip name offset
pbitptr += 2; //skip type
pbitptr += 2; //skip class
pbitptr += 4; //skip ttl
register int isizeOfRdata = ntohs(*((unsigned short*)pbitptr));
pbitptr +=2; //skip rdlength
register int ipreference = ntohs(*((unsigned short*)pbitptr));
this->preference.push_back( ipreference );
pbitptr +=2; //skip preference
register char pMailExchanger[100];
memset( pMailExchanger,'\0',100 );
register char*pguard = pMailExchanger;
for( int bytes = 1; bytes <= isizeOfRdata-2;)
{
register int sectionLength = *pbitptr;
if( sectionLength == 0 )
{
pguard --;
*pguard = '\0';
bytes+=2;
//bitptr++;
this->mailExchanger.push_back( pMailExchanger );
}
else
if( sectionLength == -64 ) //offset
{
bytes += 2; //表示现在要去处理便移量
pbitptr++;
register int offset = (unsigned short)*pbitptr;
register char* poff = this->receiver + offset; //找到offset的地址
//在指针的地方不知道有多少个字符,故用while循环
while( *poff != 0)
{
poff++;
register int partlength = *poff;
for( int k = 1; k <= partlength; k++ )
{
*pguard = *poff;
poff++;
pguard++;
} //处理每一个label
*pguard = '.';
pguard++;
} //End while loop
pguard--;
*pguard = '\0';
this->mailExchanger.push_back( pMailExchanger );
}
else //一般情况
{
for( int i = 1;i <= sectionLength; i++ )
{
bytes++;
pbitptr++;
*pguard = *pbitptr;
pguard++;
} //处理完一个label
bytes++;
pbitptr++;
*pguard = '.';
pguard++;
} //结束一般情况
} //结束一个 mail exchanger
ptemparory += 10;
ptemparory += isizeOfRdata;
} //End for loop
if( closesocket( sockfd ) != 0 )
{
this->errorCode = -8;
return;
}
WSACleanup();
this->errorCode = 1;
return ;
} //End getResourceRecord()
//根据email地址,把@后面的域名去出来,同时还要分解为数据报的格式
//比如:yahoo.com.cn
//数据报格式为 5yahoo3com2cn0
//处理的结果放置在setionLength 和sectionString 中,分别存储长度和对应的字符
void MXRecord::divideEmail( char *emailaddress )
{
register string temString = emailaddress;
//检查域名的格式,是否有一个'.'符号
int location = temString.find_first_of( '@', 0 );
if( location == -1 )
{
this->errorCode = -1;
return ;
}
//除去@字符,只保留后面的域名
temString = temString.substr( location + 1 );
//开始分解域名,把每个'.'分开的label放置到sectionString中,同时把对应的长度放置到sectionLength中
location = temString.find_first_of( '.' , 0 );
//检查域名的格式,是否有一个'.'符号
if( location == -1 )
{
this->errorCode = -1;
return ;
}
while( location != -1 )
{
this->sectionLength.push_back( location );//store length
this->sectionString.push_back( temString.substr( 0, location ) ); //store characters
temString = temString.substr( location + 1 );
location = temString.find_first_of( '.' , 0 );
} //End while loop
//保存最后的字符数和对应的字符
sectionLength.push_back( temString.size() );
sectionString.push_back( temString );
return;
} //End diviedEmail()
//testing class
void MXRecord::display()
{
getResourceRecord();
int errorcode = this->getErrorCode();
cout <<"Error code = " << errorcode << endl;
cout << "email = " << this->pemailAddress << endl;
int sectionlength = this->sectionLength.size();
cout << "section length = " << sectionlength << endl;
int stringlength = this->sectionString.size();
cout << "section string = " << stringlength << endl;
for( int i = 0; i< sectionlength; i++)
cout << this->sectionLength.at(i) << " " ;
cout << endl;
for( int j = 0; j< stringlength; j++ )
cout << this->sectionString.at(j) << " " ;
int length = this->preference.size();
cout << "preference length " << length << endl;
cout << "preferencer is " << this->preference.at(0) << endl;
cout << endl << endl;
} //End display()
//all functions belonging to Email class are displayed as follows
//constructor
Email::Email( char *emailaddress,struct TaskInformation information ):MXRecord( emailaddress )
{
this->pdomainName = emailaddress;
//initialize all memeber of task information
this->taskInformation.endedTime = information.endedTime;
this->taskInformation.errorCode = information.errorCode;
this->taskInformation.leftPlace = information.leftPlace;
this->taskInformation.startedTime = information.startedTime;
this->taskInformation.taskName = information.taskName;
this->taskInformation.title = information.title;
this->taskInformation.usedPlace = information.usedPlace;
this->taskInformation.userName = information.userName;
this->responseCode = 20 ;
} //Email()
//destructor
Email::~Email()
{
} //End ~Email()
//send email to sender address
void Email::sendEmail()
{
getResourceRecord();
int errorcode = getErrorCode();
if( errorcode != 1 )
{
this->responseCode = errorcode;
return;
}
WSADATA wsaData;
if(WSAStartup( MAKEWORD( 2, 0 ),&wsaData) != 0)
{
this->responseCode = 2;
return;
}
int sock;
if( (sock=socket( AF_INET,SOCK_STREAM,0)) == -1 )
{
this->responseCode = 2;
return;
}
sockaddr_in smtpIP;
smtpIP.sin_family = AF_INET;
smtpIP.sin_port = htons( 25 );
// 循环遍历每一个 Mail exchanger,如果有一个发送成功,就终止发送,
int loop = mailExchanger.size();
if( loop == 0 )
{
this->responseCode = 3;
return;
}
else
{
register string domainname = this->getDomainName();
for( int index = 1 ; index <= loop; index++ )
{
register struct hostent *phost = gethostbyname( mailExchanger.at( index-1 ).data() );
register struct in_addr *paddr = ( struct in_addr *)*phost->h_addr_list;
smtpIP.sin_addr.s_addr = inet_addr( inet_ntoa(*paddr) );
char recvbuff[256];
memset(recvbuff, 0, sizeof(recvbuff));
char sendbuff[256];
memset(sendbuff, 0, sizeof(sendbuff));
register int len;
register int rval;
//connect smtp server
if (connect(sock, (sockaddr*)&smtpIP, sizeof( sockaddr ) ) != 0 )
{
this->responseCode = 4; //连接SMTP服务器失败
return ;
}
//send email
strcpy(sendbuff, "EHLO ");
strcat(sendbuff, domainname.data());
strcat(sendbuff, "\r\n");
len = strlen(sendbuff);
rval = send(sock, sendbuff, len, 0 );
rval = recv(sock, recvbuff, sizeof(recvbuff), 0); //modified
rval = recv(sock, recvbuff, sizeof(recvbuff), 0); //modified
if (rval == -1 )
{
this->responseCode = 5; //接收数据失败
return ;
}
if (strstr(recvbuff, "250") == NULL )
{
this->responseCode = 6; //SMTP服务器处理此命令失败
return;
}
//send email
strcpy(sendbuff ,"MAIL FROM:" );
strcat(sendbuff,"<
support@gbvsystem.com>");
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
rval = send(sock,sendbuff,len,0 );
rval = recv(sock,recvbuff,sizeof( recvbuff), 0 );
if (rval == -1 )
{
this->responseCode = 5; //接收数据失败
return ;
}
if (strstr( recvbuff,"250" ) == NULL )
{
this->responseCode = 7; //SMTP服务器处理此命令失败
return;
}
// receiver address
strcpy(sendbuff,"RCPT TO:" );
strcat(sendbuff,"<" );
strcat(sendbuff,this->pdomainName );
strcat(sendbuff,">" );
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
rval = send(sock,sendbuff,len ,0 );
rval = recv( sock,recvbuff ,sizeof( recvbuff) -1 , 0 );
if (rval == -1 )
{
this->responseCode = 5; //接收数据失败
return ;
}
if(strstr(recvbuff,"250" ) == NULL )
{
this->responseCode = 8; //SMTP服务器处理此命令失败
return;
}
//send data
strcpy(sendbuff,"DATA" );
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
rval = send(sock,sendbuff,len, 0 );
rval = recv(sock,recvbuff,sizeof(recvbuff), 0 );
if (rval == -1 )
{
this->responseCode = 5; //接收数据失败
return ;
}
if (strstr(recvbuff,"354" ) == NULL )
{
this->responseCode = 9; //SMTP服务器处理此命令失败
return;
}
strcpy(sendbuff,"FROM:<");
strcat(sendbuff,"
support@gbvsystem.com" );
strcat(sendbuff,">\r\n");
len = strlen(sendbuff );
rval = send(sock,sendbuff ,len ,0 );
strcpy(sendbuff ,"SUBJECT:" );
strcat(sendbuff,this->taskInformation.title );
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
rval = send(sock, sendbuff,len ,0 );
strcpy(sendbuff,"TO:<" );
strcat(sendbuff,this->pdomainName );
strcat(sendbuff,">\r\n" );
strcpy( sendbuff ,"" );
strcat( sendbuff ,"\r\n" );
len = strlen( sendbuff );
send( sock ,sendbuff,len ,0 );
strcpy(sendbuff,"Hello ");
strcat(sendbuff, this->taskInformation.userName );
len = strlen(sendbuff );
send(sock,sendbuff,len ,0 );
strcpy(sendbuff,"" );
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
send(sock,sendbuff ,len, 0 );
strcpy(sendbuff, "TasK Name " );
strcat(sendbuff, this->taskInformation.taskName );
len = strlen(sendbuff );
send(sock,sendbuff ,len ,0 );
strcpy(sendbuff,"" );
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
send(sock,sendbuff,len, 0 );
if (this->taskInformation.errorCode == 0 )
{
// 3 line for task failed
strcpy(sendbuff, "Task " );
strcat(sendbuff, " Failed" );
len = strlen(sendbuff );
send(sock,sendbuff,len ,0 );
strcpy(sendbuff,"" );
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
send(sock,sendbuff,len, 0 );
}
else
{
// task succeeded
// 3 line
strcpy(sendbuff, "Used Place " );
strcat(sendbuff, this->taskInformation.usedPlace );
len = strlen(sendbuff );
send(sock,sendbuff,len ,0 );
strcpy(sendbuff,"" );
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
send(sock,sendbuff ,len, 0 );
//4 line
strcpy(sendbuff, "Left Space " );
strcat(sendbuff, this->taskInformation.leftPlace );
len = strlen(sendbuff );
send(sock,sendbuff ,len ,0 );
strcpy(sendbuff,"" );
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
send(sock,sendbuff ,len, 0 );
//5 line
strcpy(sendbuff, "Start Time " );
strcat(sendbuff, this->taskInformation.startedTime );
len = strlen(sendbuff );
send(sock,sendbuff,len,0 );
strcpy(sendbuff,"" );
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
send(sock,sendbuff,len, 0 );
// 6 line
strcpy(sendbuff, "End Time " );
strcat(sendbuff, this->taskInformation.endedTime );
len = strlen(sendbuff );
send(sock,sendbuff,len,0 );
strcpy(sendbuff,"" );
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
send(sock,sendbuff,len, 0 );
}
// last line of email
strcpy(sendbuff, "Best guard " );
len = strlen(sendbuff );
send(sock,sendbuff,len ,0 );
strcpy(sendbuff,"" );
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
send(sock,sendbuff,len, 0 );
strcpy( sendbuff, "GBV SYSTEM " );
len = strlen(sendbuff );
send(sock,sendbuff,len,0 );
strcpy(sendbuff,"" );
strcat(sendbuff,"\r\n" );
len = strlen(sendbuff );
send(sock,sendbuff,len, 0 );
strcpy(sendbuff, "\r\n.\r\n" );
len = strlen(sendbuff );
rval = send(sock,sendbuff,len, 0 );
rval = recv(sock,recvbuff,sizeof( recvbuff) ,0 );
if (rval == -1 )
{
this->responseCode = 5; //接收数据失败
return ;
}
if (strstr(recvbuff,"250" ) == NULL )
{
this->responseCode = 10; //SMTP服务器处理此命令失败
return;
}
strcpy( sendbuff ,"QUIT\r\n" );
len = strlen( sendbuff );
rval = send(sock,sendbuff,len, 0 );
rval = recv( sock ,recvbuff ,sizeof( recvbuff ),0 );
if (rval == -1 )
{
this->responseCode = 5; //接收数据失败
return ;
}
if (strstr( recvbuff ,"221" ) != NULL )
{
this->responseCode = 1; //发送EMAIL成功
break; ;
}
else
{
this->responseCode = 11; //SMTP服务器处理此命令失败
return;
}
} //End for loop
} //发送邮件结束
return;
} //End sendEmail()
//get domain name via email address
string Email::getDomainName()
{
register string temString = pdomainName;
int location = temString.find_first_of( '@', 0 );
temString = temString.substr( location + 1 );
return temString;
}//End getDomainName()
//return response code
int Email::getResponseCode() const
{
return this->responseCode ;
} //End getResponseCode()
//only to test email class
void Email::display()
{
sendEmail();
int errorcode = getResponseCode();
cout << "Response code = "<<errorcode << endl;
return;
} //End display()