⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pop3.cpp

📁 Visual C++网络通信编程实用案例精逊配套源码 光盘中存放的是书中涉及的所有实例的源代码和经过编译后的应用程序。所有程序均经过测试
💻 CPP
字号:
// Pop3.cpp: implementation of the CPop3 class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MailPost.h"
#include "Pop3.h"

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

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPop3::CPop3()
{
	// 初始化变量
	m_sError = _T("");
	m_sock = INVALID_SOCKET;
	m_nMails = 0;
	m_nSize = 0;
	m_bList = FALSE;
	m_bState = FALSE;
	m_arSizes.RemoveAll();
	m_arHeaders.RemoveAll();
	m_bConnected = FALSE;
	m_dwTimeout = 2000;
}

CPop3::~CPop3()
{

}

BOOL CPop3::Connect(LPCTSTR strAddress, LPCTSTR strUser, LPCTSTR strPassword,UINT nPort)
{
	// 初始化本地套接字
	m_sock = socket(AF_INET, SOCK_STREAM, 0);
	if (m_sock == INVALID_SOCKET)
	{
		m_sError = _T("初始化套接字失败");
		return FALSE;
	}

	// 初始化远端套接字
	SOCKADDR_IN sockAddr;
	memset(&sockAddr,'\0',sizeof(sockAddr));
	sockAddr.sin_family = AF_INET;
	sockAddr.sin_port = htons((u_short)nPort);
	sockAddr.sin_addr.s_addr = inet_addr(strAddress);

	// 如果主机名不是IP地址,用gethostbyname获得其IP地址
	if (sockAddr.sin_addr.s_addr == INADDR_NONE)
	{
		LPHOSTENT lphost;
		lphost = gethostbyname(strAddress);
		if (lphost)
			sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
		else
		{
			m_sError = _T("无法解析地址!"); 
			return FALSE;
		}
	}
	
	// 尝试与服务器连接
	if (connect(m_sock,(SOCKADDR *)(&sockAddr),sizeof(sockAddr)) == SOCKET_ERROR)
	{
		m_sError = _T("无法与服务器建立连接!");
		return FALSE;
	}

	// 接收回应信息
	if (!GetResponse())
	{
		// 回应失败
		m_sError = _T("无法收到回应信息或收到错误信息!");
		Disconnect();
		return FALSE;
	}

	// 发送用户名
	CString strTemp;
	strTemp.Format("USER %s\r\n",strUser);
    if (!Send((LPCTSTR)strTemp,strTemp.GetLength()))
    {
		// 发送用户名失败
		m_sError = _T("发送用户名失败!");
		return FALSE;
    }

	// 接收回应信息
    if (!GetResponse())
    {
		// 接收回应信息失败
		m_sError = _T("无法收到回应信息或收到无效信息!");
		Disconnect();
		return FALSE;
    } 

    // 发送密码
	strTemp.Format("PASS %s\r\n",strPassword);
    if (!Send((LPCTSTR)strTemp,strTemp.GetLength()))
    {
		// 发送密码失败
		m_sError = _T("发送密码失败!");
		Disconnect();
		return FALSE;
    }

	// 接收回应信息
    if (!GetResponse())
    {
		// 接收回应信息失败
		m_sError = _T("无法收到回应信息或收到无效信息!");
		Disconnect();
		return FALSE;
    } 

	m_bConnected = TRUE;
	return TRUE;
}

BOOL CPop3::GetResponse(void)
{
	TCHAR chArray[1188];
	if (!ReadResponse(chArray,1188,FALSE))
	{
		return FALSE;
	}
	m_sResponse = chArray;
	return TRUE;
}

BOOL CPop3::ReadResponse(TCHAR *pChar, UINT nSize, BOOL bDouble)
{
	CString strTemp;

	// 读取回应信息
	BOOL bEnd = FALSE;
	UINT nReceived = 0;
	DWORD dwStart = ::GetTickCount();
	while (!bEnd)
	{
		// 尝试时间到
		if ((::GetTickCount() - dwStart) >	m_dwTimeout)
		{
			pChar[nReceived] = '\0';
			m_sError = _T("超时");
			// 保存当前回应的消息
			m_sResponse = pChar;
			return FALSE;
		}

		// 看套接字是否可读
		timeval timeout = {0, 0};
		fd_set fds;
		FD_ZERO(&fds);
		FD_SET(m_sock,&fds);
		int nStatus = select(0,&fds,NULL,NULL,&timeout);

		if (nStatus == SOCKET_ERROR)
		{
			// 套接字不可读
			m_sError = _T("套接字不可达");
			return FALSE;
		}
		else if (!nStatus)
		{
			// 没有接收到数据
			::Sleep(688);
			continue;
		}

		// 从套接字中接收数据
		::Sleep(288);
		nStatus = recv(m_sock,pChar + nReceived,nSize,0);
		if (nStatus == SOCKET_ERROR)
		{
			pChar[nReceived] = '\0';
			// 套接字错误
			m_sError = _T("未能从套接字中收到数据!");
			// 保存当前回应信息
			m_sResponse = pChar; 
			return FALSE; 
		}
		else if (nStatus)
		{
			// 重置计时器
			dwStart = ::GetTickCount();
			// 已收到的数据又增加了
			nReceived += nStatus;
		}

		// 将pChar设为字符串,并赋给CString型的变量
		pChar[nReceived] = '\0';
		strTemp = pChar;
								
		// 检查是否收到了结束标志
		LPCTSTR lpszComp = bDouble ? "\r\n.\r\n" : "\r\n";
		bEnd = (strTemp.Find(lpszComp) != -1);
	}

	// 去掉结束标志
	nReceived -= bDouble ? 3 : 0;
	pChar[nReceived] = '\0';

	// 检查回应信息是否有效
	strTemp = pChar;
	strTemp.MakeUpper();
	int nStart = strTemp.Find("+OK");
	if (nStart == -1)
	{
		// 收到无效信息
		m_sError = _T("回应信息无效");
		return FALSE;
	}
	// 提取有效信息
	strTemp = pChar;
	m_sResponse = strTemp.Right(strTemp.GetLength() - nStart - 3);
	
	return TRUE;
}

BOOL CPop3::Disconnect()
{
	BOOL bSuccess;
	
	// 如果还保持连接状态则断开
	if (m_bConnected)
	{
		CString strSend = "QUIT\r\n";
		// 发送断开请求
		if (!this->Send((LPCTSTR)strSend,strSend.GetLength()))
		{
			AfxMessageBox(_T("发送断开请求失败"));
			return FALSE;
		}

		bSuccess = this->GetResponse();

		// 将有关的变量复位
	    m_bConnected = FALSE;
		m_bList = FALSE;
	    m_bState = FALSE;
		m_nMails = 0;
		m_nSize = 0;
		m_arHeaders.RemoveAll();
		m_arSizes.RemoveAll();

		// 关闭套接字
		closesocket(m_sock);
		m_sock = INVALID_SOCKET;
	}

	return bSuccess;
}

BOOL CPop3::Send(LPCTSTR lpszSend, UINT nLength)
{
	return send(m_sock,lpszSend,nLength,0) != SOCKET_ERROR;
}

BOOL CPop3::ReadState()
{
	// 获得返回的状态信息
	if (!GetResponse())
	{
		// 接收返回信息失败
		m_sError = _T("接收返回信息失败!");
		return FALSE;
	}

	// 看返回的信息是否有效
	m_sResponse.MakeUpper();
	UINT nEnd = 0;
	if (m_sResponse.Find("+OK") == -1)
	{
		// 收到无效的回应信息
		m_sError = _T("返回信息无效!");
		return FALSE;
	}
	else
	{ 
		// 分析邮件数和大小,首先分析数目
		return this->ParseNumAndSize(m_nMails,m_nSize,(LPCTSTR)m_sResponse,nEnd);
	}
}

UINT CPop3::GetMailCount() const
{
	return m_nMails;
}

BOOL CPop3::ParseNumAndSize(UINT &nNum, UINT &nSize,LPCTSTR lpszBuf,UINT &nEnd)
{
	BOOL bNum = TRUE;
	for (int i = nEnd,j = -1;lpszBuf[i];i++)
	{
		if (isdigit(lpszBuf[i]))
			j = (j == -1) ? i : j;
		else
		{	
			if (j == -1)
			{
				// 还未读入数字
				continue;
			}

			// 分析完一个字段
			else if (bNum)
			{
				// 分析数目
				m_nMails = atoi(&lpszBuf[j]);
				nNum = m_nMails;
				bNum = FALSE;
				j = -1;
			}

			else
			{
				// 分析大小
				m_nSize = atoi(&lpszBuf[j]);
				nSize = m_nSize;
				nEnd = i;
				return TRUE;
			}
		}
	}
	nEnd = i;
	return FALSE;
}

BOOL CPop3::ReadList()
{
	UINT nBuf = m_nMails * 18 + 188;
	char *pBuf = new char[nBuf];
	if (!pBuf)
	{
		return FALSE;
	}
	if (!ReadResponse(pBuf,nBuf,TRUE))
	{
		return FALSE;
	}
	m_arSizes.RemoveAll();
	m_arSizes.SetSize(m_nMails);
	UINT nNum,nSize,nEnd = 0;
	while (ParseNumAndSize(nNum,nSize,m_sResponse,nEnd))
	{
		m_arSizes.SetAt(nNum - 1,nSize);
	}

	return TRUE;
}

DWORD CPop3::GetMsgSize(UINT nID) 
{
	BOOL bSuccess;
	if (!m_bList)
		bSuccess = this->List();
	if (!bSuccess)
		return 0;

	return m_arSizes.GetAt(nID);
}

BOOL CPop3::ListHeader()
{
	m_arHeaders.RemoveAll();
	m_arHeaders.SetSize(m_nMails);
	CString strTemp;
	for (UINT nMsg = 1;nMsg <= m_nMails;nMsg++)
	{
		strTemp.Format("TOP %d 0\r\n",nMsg);
		if (!Send((LPCTSTR)strTemp,strTemp.GetLength()))
		{
			m_sError = _T("发送TOP命令失败!");
			return FALSE;
		}

		if (!GetResponse())
		{
			m_sError = _T("列举邮件主题失败!");
			return FALSE;
		}
		
		strTemp = m_sResponse;
		strTemp.MakeUpper();
		
		// 查找SUBJECT段
		UINT nStart = strTemp.Find("\r\nSUBJECT:");
		if (nStart == -1)
		{
			m_arHeaders.SetAt(nMsg - 1,_T(""));			
			return TRUE;
		}
		strTemp = m_sResponse.Right(m_sResponse.GetLength() - nStart - 10);
		nStart = strTemp.Find("\r\n");
		if (nStart != -1)
			strTemp = strTemp.Left(nStart);
		strTemp.TrimLeft();
		strTemp.TrimRight();
		m_arHeaders.SetAt(nMsg - 1,strTemp);
	}

	return TRUE;
}

BOOL CPop3::Delete(UINT nIndex)
{
	CString strSend;
	strSend.Format("DELE %d\r\n",nIndex);

	// 发送DELE命令
	if (!Send((LPCTSTR)strSend,strSend.GetLength()))
	{
		// 未能成功发送
		m_sError = _T("删除邮件失败!");
		return FALSE;
	}

	// 接收返回信息
	if (!GetResponse())
	{
		m_sError = _T("收到无效信息!");
		return FALSE;
	}
	
	// 上一次STAT和LIST命令得到的信息无效
	m_bState = FALSE;
	m_bList = FALSE;
	return TRUE;
}

BOOL CPop3::RetrieveMail(UINT nIndex,CString &strMsg)
{
	CString strSend;
	strSend.Format("RETR %d\r\n",nIndex);
	if (!Send((LPCTSTR)strSend,strSend.GetLength()))
	{
		m_sError = _T("收取邮件失败!");
		return FALSE;
	}

	if (!GetResponse())
	{
		m_sError = _T("无法收到送回的邮件!");
		return FALSE;
	}

	// 以CONTENT-DISPOSITION: INLINE为起始标志
	strMsg = m_sResponse;
	strMsg.MakeUpper();
	int nStart = strMsg.Find("CONTENT-DISPOSITION: INLINE\r\n");
	strMsg = m_sResponse.Right(m_sResponse.GetLength() - nStart - 29);

	// 空行表示邮件正文
	nStart = strMsg.Find("\r\n\r\n");
	strMsg = strMsg.Right(strMsg.GetLength() - nStart - 4);
	// 空行表示邮件正文结束
	nStart = strMsg.Find("\r\n\r\n");
	if (nStart != -1)
		strMsg = strMsg.Left(nStart);
	return TRUE;
}

BOOL CPop3::List()
{
	CString strTemp = "LIST\r\n";
	if (m_bList)
		return TRUE;
	if (!Send((LPCTSTR)strTemp,strTemp.GetLength()))
	{
		// 发送失败
		m_sError = _T("查询邮箱状态失败!");
		Disconnect();
		return FALSE;
	}

	if (!ReadList())
	{
		// 接收回应信息失败
		m_sError = _T("无法收到邮件状态信息或收到无效信息!");
		Disconnect();
		return FALSE;
    }

	return TRUE;
}

BOOL CPop3::GetState()
{
	CString strTemp = "STAT\r\n";
	if (m_bState)
		return TRUE;
	if (!Send((LPCTSTR)strTemp,strTemp.GetLength()))
	{
		// 发送失败
		m_sError = _T("查询邮箱状态失败!");
		Disconnect();
		return FALSE;
	}

    if (!ReadState())
    {
		// 接收回应信息失败
		m_sError = _T("无法收到邮箱状态信息或收到无效信息!");
		Disconnect();
		return FALSE;
    }

	return TRUE;
}

LPCTSTR CPop3::GetErrorString()
{
	return (LPCTSTR)m_sError;
}

BOOL CPop3::Noop()
{
	CString strTemp = "NOOP\r\n";

	// 发送NOOP命令
	if (!Send((LPCTSTR)strTemp,strTemp.GetLength()))
	{
		// 发送失败
		m_sError = _T("进行空操作失败!");
		Disconnect();
		return FALSE;
	}

	// 接收回应信息
    if (!GetResponse())
    {
		// 接收回应信息失败
		m_sError = _T("无法收到回应信息或收到无效信息!");
		Disconnect();
		return FALSE;
    }

	return TRUE;
}

LPCTSTR CPop3::GetMailHeader(UINT nIndex)
{
	return (LPCTSTR)m_arHeaders.GetAt(nIndex);
}


BOOL CPop3::Reset()
{
	CString strTemp = "RSET\r\n";

	// 发送RSET命令
	if (!Send((LPCTSTR)strTemp,strTemp.GetLength()))
	{
		m_sError = _T("发送RSET命令失败!");
		return FALSE;
	}
	
	// 接收回应信息
	if (!GetResponse())
	{
		// 接收回应信息失败
		m_sError = _T("回应失败!");
		return FALSE;
	}

	return TRUE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -