📄 smtp.c
字号:
//===================================================================
// Asoka USA Corporation
// 文件名 :SMTP.cpp
// 作 者 :charlie(刘翔)
// 版 本 :
// 完成日期:2006-01-08
// 说 明 :此文件是用来实现SMTP协议处理
// 其 它 :
// 函数列表: Data
// Mail
// Connect
// ......
//
//
// 历史记录:
// 作者:
// 修改内容:
//
// 2. ...
//////////////////////////////////////////////////////////////////////////
// SMTP.cpp: implementation of the CSMTP class.
//
//////////////////////////////////////////////////////////////////////
#include "SMTP.h"
#include "Base64Coder.h"
#include <malloc.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <memory.h>
#include <unistd.h>
#include <netdb.h>
BOOL Mail(SMTP struMail);
char* GetHost();
void SetHost(char* Host);
//发送DATA命令信息
BOOL Data(SMTP struMail);
//// 发送TO命令信息
BOOL SetTo(SMTP struMail);
//发送MAIL命令信息
BOOL MailCMD(char* from);
//和SMTP服务器断开连接
BOOL Disconnect();
//和SMTP服务器进行连接
//BOOL Connect();
// 该函数是通过扩展SMTP会话方式连接服务器的
BOOL ConnectSrvSMTP(const char* pszLocalName, const char* pszUsername, const char* pszPassword);
// 使用AUTH LOGIN命令协商登录,即需要对用户名进行编码
BOOL AuthLogin(const char* pszUsername, const char* pszPassword);
//检查指定命令的响应信息
BOOL ReadCommandResponse(int nExpectedCode);
//检查邮件服务器的详细响应信息
BOOL ReadResponse(char* pszBuffer, int nInitialBufSize, char* pszTerminator, int nExpectedCode, char** ppszOverFlowBuffer, int nGrowBy);
char* GetError(char* Response);
//检查邮件服务器的响应信息
BOOL CheckResponse(int Type);
BOOL ProcedureCMD(int Type, char* buf);
char* T2A(char* lp);
//获取文件的内容信息
char* GetFileBody(char* strFileName, int* nBodySize);
//获取附件的头信息
char* GetAttachmentHeader(int* nHeaderSize, char* strFileName);
//发送指定信息的邮件
BOOL SendMailInfo(SMTP struMail);
//发送邮件的附件信息
BOOL SendAttachment(SMTP struMail);
//发送附件的尾信息
char* GetFooter(int* nFooterSize);
//发送邮件头信息
BOOL SendMIMEHead(SMTP struMail);
//MIME信息中需要增加邮件头中的MIME信息
BOOL GetMIMEHead(char* strMIMEHeadInfo);
//发送邮件的邮件头信息
BOOL SendHeader(SMTP struMail);
//判断是否是带附件的邮件
void ISMIME(SMTP struMail);
//检查邮件信息的合法性
BOOL CheckMailInfo(SMTP struMail);
//设置邮件的发送人信息
void SetSenderName(SMTP* struMail, char* strSenderName);
//对SUBJECT信息进行编码处理
char* EnSubJectCodeString(char* sText);
//对邮件体BODY信息进行编码处理
void EnBodyCodeString(char* sText, char* strEncode);
//初始化SMTP信息
void Initialize(SMTP *EmailSMTP);
//设置附件的文件信息
void SetFile(SMTP* struMail, char* strFileName);
//设置邮件的标题信息
void SetMailSubject(SMTP* struMail, char* strMailSubject);
//设置邮件的正文信息
void SetMailText(SMTP* struMail, char* strMailText);
//设置用户的帐号信息
void SetUSERID(SMTP* struMail, char* strUSERID);
//设置用户的密码信息
void SetPWD(SMTP* struMail, char* strPWD);
//设置邮件的SMPT服务器信息
void SetSMTPServer(SMTP* struMail, char* strSMTPServer);
//设置邮件的目的址信息
void SetSendTo(SMTP* struMail, char* strSendTo);
//设置邮件的源地址信息
void SetSendFrom(SMTP* struMail, char* strSendFrom);
//对指定的字符串进行BASE64编码
void EnCodeString(char* strSoure,char* strEnCode);
BOOL IsSameWeek(char* strWeek, int weekly);
//根据Quoted printable编码规则对数据进行编码处理
void QuotedPrintableEncode(char* sText, char* strEncode);
char HexDigit(int nDigit);
char* substr(char* pstrChar, int iBegin, int nLength);
//查找指定字符串
int find(char* pstrChar, const char* strSoure);
//查询函数
int rfind(char* strData, const char* strSoure);
BOOL Create();
BOOL ConnectServer(const char* pszHostAddress, int nPort);
BOOL ConnectSvr(const struct sockaddr* lpSockAddr, int nSockAddrLen);
BOOL SendDate(const char* pszBuf, int nBuf);
void CloseSocket();
int Receive(char* pszBuf, int nBuf);
//BOOL IsReadable(BOOL bReadible);
static BOOL g_bMIME = TFALSE;
static int g_hSocket = -1;
static int g_NoOfTo = 0; //发送的目的地址的个数
static char g_ErrorMessage[128];
static char g_Host[128]; //主机信息
static int g_nLastCommandResponseCode = 0;
static char g_sLastCommandResponse[128];
static int g_dwTimeout = 0; //超时时间
static BOOL g_bConnected = TFALSE;
static char g_strBoundary[128]; //Boundary信息,MIME中定义的数据
static char g_strEncode[128]; //编码方式,MIME中定义的数据
static char g_stCharset[128]; //charset信息,MIME中定义的数据
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
void Initialize(SMTP *EmailSMTP)
{
//重新初始化全局变量
g_NoOfTo = 0;
g_dwTimeout = 120; //超时时间设置为120秒
g_bMIME = TFALSE;
g_bConnected = TFALSE;
memset(g_strBoundary, 0, 128);
memset(g_strEncode, 0, 128);
memset(g_stCharset, 0, 128);
strcpy(g_strBoundary, "18ac0781-9ae4-4a2a-b5f7-5479635efb6b");
strcpy(g_strEncode ,"base64");
strcpy(g_stCharset, "gb2312");
g_hSocket = -1;
//初始化SMTP结构
memset(EmailSMTP->m_strFile, 0, 128);
memset(EmailSMTP->m_strSendFrom, 0, 64);
memset(EmailSMTP->m_strSendTo, 0, 64);
memset(EmailSMTP->m_strSMTPServer, 0, 64);
memset(EmailSMTP->m_strPWD, 0, 64);
memset(EmailSMTP->m_strUSERID, 0, 64);
memset(EmailSMTP->m_strMailText, 0, 64);
memset(EmailSMTP->m_strMailSubject, 0, 64);
memset(EmailSMTP->m_strSenderName, 0, 64);
}
char* T2A(char* lp)
{
return lp;
}
// 读取主机信息
char* GetHost( )
{
return g_Host;
}
//设置主机信息
void SetHost(char* Host)
{
memset(g_Host, 0, 128);
strcpy(g_Host, Host);
}
//连接SMTP服务器
BOOL ConnectSMTP(SMTP struMail)
{
// printf("begin Connect!\n");
//char* From= NULL;
//char* strtemp = NULL;
//char* Host = NULL;
//int nPos = 0;
char sHostName[100];
BOOL bConnectOk = TFALSE;
//char* strUsername = NULL;
//char* strPassword = NULL;
/*
nPos = find(struMail.m_strSendFrom, "@");
From = substr(struMail.m_strSendFrom, 0, nPos);
strcat(From, struMail.m_strSMTPServer);
*/
// SMTP端口默认是25
if (!ConnectServer(struMail.m_strSMTPServer, 25))
{
strcpy(g_ErrorMessage, "Server cannot be connected");
printf("Server cannot be connected!\n");
return TFALSE;
}
else
{
// printf("Connect successfully!\n");
//检查返回的值是否是220
if(CheckResponse(CONNECTION_CHECK) == TFALSE)
{
return TFALSE;
}
//获得本地机器名
memset(sHostName, 0, 100);
gethostname(sHostName, sizeof(sHostName));
// 进行下一步连接,即进行SMTP会话,采用鉴权方式进行会话
bConnectOk = ConnectSrvSMTP(sHostName, struMail.m_strUSERID , struMail.m_strPWD );
if(bConnectOk == TFALSE)
{
printf("ConnectESMTP fail!\n");
return TFALSE;
}
return TTRUE;
}
}
// 该函数是通过扩展SMTP会话方式连接服务器的
BOOL ConnectSrvSMTP(const char* pszLocalName, const char* pszUsername, const char* pszPassword)
{
char sBuf[128];
char* pszData = NULL;
BOOL bLoginOk = TFALSE;
int nCmdLength = 0;
//验证参数
if((pszLocalName == NULL) || (pszUsername == NULL)|| (pszPassword == NULL))
{
return TFALSE;
}
//发送EHLO命令
memset(sBuf, 0, 128);
strcpy(sBuf, "EHLO ");
strcat(sBuf, pszLocalName);
strcat(sBuf, "\r\n");
pszData = T2A(sBuf);
nCmdLength = strlen(pszData);
if (!SendDate(pszData, nCmdLength))
{
return TFALSE;
}
//检查Hello命令的响应 250
if(CheckResponse(HELLO_CHECK)==TFALSE)
{
return TFALSE;
}
//进行帐号密码验证
bLoginOk = AuthLogin(pszUsername, pszPassword);
if(bLoginOk == TFALSE)
{
return TFALSE;
}
return bLoginOk;
}
// 使用AUTH LOGIN命令协商登录,即需要对用户名进行编码
BOOL AuthLogin(const char* pszUsername, const char* pszPassword)
{
char sBuf[128];
int nCmdLength = 0;
char* pszData = NULL;
char* temp = NULL;
char* pTmp = NULL;
char* sLastCommandString = NULL;
char* pszLastCommandString = NULL;
Base64Coder Coder;
Base64Coder CoderPWD;
//验证参数
if((pszUsername == NULL)|| (pszPassword == NULL))
{
return TFALSE;
}
//发送AUTH LOGIN命令
temp = (char*)malloc(100);
//检查分配内存是否成功
if(temp == NULL)
{
return TFALSE;
}
memset(sBuf, 0, 128);
strcpy(sBuf, "AUTH LOGIN\r\n");
pszData = T2A(sBuf);
nCmdLength = strlen(pszData);
if (!SendDate(pszData, nCmdLength))
{
printf("An unexpected error occurred while sending the AUTH command\n");
free(temp);
temp = NULL;
return TFALSE;
}
//初始化
//检查Hello命令的响应 334
if (!ReadCommandResponse(334))
{
printf("Server does not support AUTH LOGIN!\n");
free(temp);
temp = NULL;
return TFALSE;
}
else
{
//发送base64编码后的用户名
sLastCommandString = (char*)malloc(1024);
if(sLastCommandString == NULL)
{
free(temp);
temp = NULL;
return TFALSE;
}
strcpy(sLastCommandString , g_sLastCommandResponse);
//需要进行数据测试
sLastCommandString = substr(sLastCommandString, 4, strlen(sLastCommandString) -4);
pszLastCommandString = T2A(sLastCommandString);
Base64CoderInit(&Coder);
_Init(&Coder);
Decode(&Coder, pszLastCommandString);
if (strcmp(DecodedMessage(Coder), "Username:") == 0)
{
Encode(&Coder, T2A((char*)pszUsername));
memset(temp, 0, 100);
sprintf(temp, "%s\r\n", EncodedMessage(Coder));
strcpy(sBuf, (const char*)temp);
pszData = T2A((char*)sBuf);
nCmdLength = strlen(pszData);
if (!SendDate(pszData, nCmdLength))
{
printf("An unexpected error occurred while sending the username\n");
free(sLastCommandString);
sLastCommandString = NULL;
free(temp);
temp = NULL;
return TFALSE;
}
}
else
{
printf("An unexpected request received when expecting username request");
free(sLastCommandString);
sLastCommandString = NULL;
free(temp);
temp = NULL;
return TFALSE;
}
}
//重新分配内存资源
free(sLastCommandString);
sLastCommandString = NULL;
sLastCommandString = (char*)malloc(1024);
if(sLastCommandString == NULL)
{
return TFALSE;
}
//检查返回用户名返回码
if (!ReadCommandResponse(334))
{
printf("Server did not response correctly to AUTH LOGIN username field!\n");
free(sLastCommandString);
sLastCommandString = NULL;
free(temp);
temp = NULL;
return TFALSE;
}
else
{
//发送密码到服务器
memset(sLastCommandString, 0, 1024);
strcpy(sLastCommandString, g_sLastCommandResponse);
pTmp = substr(sLastCommandString, 4, strlen(sLastCommandString) -4);
pszLastCommandString = T2A(pTmp);
Base64CoderInit(&CoderPWD);
_Init(&CoderPWD);
Decode(&CoderPWD, pszLastCommandString);
if (strcmp(DecodedMessage(CoderPWD), "Password:") == 0)
{
Encode(&CoderPWD, T2A((char*)pszPassword));
memset(temp, 0, 100);
sprintf(temp, "%s\r\n", EncodedMessage(CoderPWD));
strcpy(sBuf, (const char*)temp);
pszData = T2A(sBuf);
nCmdLength = strlen(pszData);
if (!SendDate(pszData, nCmdLength))
{
printf("An unexpected error occurred while sending the password\n");
free(sLastCommandString);
sLastCommandString = NULL;
free(temp);
temp = NULL;
return TFALSE;
}
//检查是否成功
if (!ReadCommandResponse(235))
{
printf("AUTH LOGIN authentication was unsuccessful\n");
free(sLastCommandString);
sLastCommandString = NULL;
free(temp);
temp = NULL;
return TFALSE;
}
// printf("Test Password successfully!\n");
}
else
{
printf("An unexpected request received when expecting password request\n");
free(sLastCommandString);
sLastCommandString = NULL;
free(temp);
temp = NULL;
return TFALSE;
}
}
free(sLastCommandString);
sLastCommandString = NULL;
free(temp);
temp = NULL;
return TTRUE;
}
// 发送"QUIT"命令到SMTP服务器:
BOOL Disconnect()
{
char buf[256];
memset(buf, 0, 256);
sprintf (buf, "QUIT \r\n");
//发送QUIT命令
if(SendDate(buf, strlen (buf)) == TFALSE)
{
return TFALSE;
}
//检查是否正常退出
if (CheckResponse(QUIT_CHECK) == TFALSE)
{
return TFALSE;
}
else
{
return TTRUE;
}
}
// 发送"MAIL" 命令到SMTP服务器:
BOOL MailCMD(char* from)
{
char buf[256];
memset(buf, 0, 256);
sprintf(buf, "MAIL FROM:<%s>\r\n", from);
//发送MAIL命令
if(SendDate(buf, strlen (buf)) == TFALSE)
{
return TFALSE;
}
//检查MAIL命令是否正常处理
if (CheckResponse(MAIL_CHECK) == TFALSE)
{
return TFALSE;
}
else
{
return TTRUE;
}
}
// 发送TO命令信息
BOOL SetTo(SMTP struMail)
{
char buf[256];
memset(buf, 0, 256);
sprintf (buf, "RCPT TO:<%s>\r\n", struMail.m_strSendTo);
//发送TO命令
if(SendDate(buf, strlen (buf)) == TFALSE)
{
return TFALSE;
}
//检查TO命令是否正常处理
if (CheckResponse(RCPT_CHECK) == TFALSE)
{
return TFALSE;
}
return TTRUE;
}
// 发送"DATA" 命令到 SMTP 服务器:
//进行扩展,可以发送文件
BOOL Data(SMTP struMail)
{
char buf[256];
//char* Subject = NULL;
//char* Body = NULL;
//char* strFileName = NULL;
memset(buf, 0, 256);
//发送DATA命令
sprintf(buf, "DATA\r\n");
SendDate(buf, strlen (buf));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -