📄 pop3.cpp
字号:
/*
Module : POP3.CPP
Purpose: Implementation for a MFC class encapsulation of the POP3 protocol
Created: PJN / 04-05-1998
History: PJN / 27-06-1998 1) Fixed a potential buffer overflow problem in Delete
and Retrieve functions when a large message number was
specified.
2) Improve the ReadResponse code by a) passing the
readability check onto the scoket class and b) Sleeping
for 100 ms prior to looping around waiting for new
response data
3) Classes are now fully Unicode compliant. Unicode
build configurations are also now included.
4) Now supports the TOP POP3 command which can be
issued using the GetHeader function.
PJN / 04-01-1999 1) Properly UNICODE enabled the code
Copyright (c) 1998 by PJ Naughter.
All rights reserved.
*/
//////////////// Includes ////////////////////////////////////////////
#include "stdafx.h"
#include <afxpriv.h>
#include "pop3.h"
//////////////// Macros //////////////////////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////// Implementation //////////////////////////////////////
CPop3Message::CPop3Message()
{
m_pszMessage = NULL;
}
CPop3Message::~CPop3Message()
{
if (m_pszMessage)
{
delete [] m_pszMessage;
m_pszMessage = NULL;
}
}
CPop3Socket::CPop3Socket()
{
m_hSocket = INVALID_SOCKET; //default to an invalid scoket descriptor
}
CPop3Socket::~CPop3Socket()
{
Close();
}
BOOL CPop3Socket::Create()
{
m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
return (m_hSocket != INVALID_SOCKET);
}
BOOL CPop3Socket::Connect(LPCTSTR pszHostAddress, int nPort)
{
//For correct operation of the T2A macro, see MFC Tech Note 59
USES_CONVERSION;
//must have been created first
ASSERT(m_hSocket != INVALID_SOCKET);
//Determine if the address is in dotted notation
SOCKADDR_IN sockAddr;
ZeroMemory(&sockAddr, sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons((u_short)nPort);
char* pszAsciiHostAddress = T2A((LPTSTR) pszHostAddress);
sockAddr.sin_addr.s_addr = inet_addr(pszAsciiHostAddress);
//If the address is not dotted notation, then do a DNS
//lookup of it.
if (sockAddr.sin_addr.s_addr == INADDR_NONE)
{
LPHOSTENT lphost;
lphost = gethostbyname(pszAsciiHostAddress);
if (lphost != NULL)
sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
else
{
WSASetLastError(WSAEINVAL);
return FALSE;
}
}
//Call the protected version which takes an address
//in the form of a standard C style struct.
return Connect((SOCKADDR*)&sockAddr, sizeof(sockAddr));
}
BOOL CPop3Socket::Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen)
{
return (connect(m_hSocket, lpSockAddr, nSockAddrLen) != SOCKET_ERROR);
}
BOOL CPop3Socket::Send(LPCSTR pszBuf, int nBuf)
{
//must have been created first
ASSERT(m_hSocket != INVALID_SOCKET);
return (send(m_hSocket, pszBuf, nBuf, 0) != SOCKET_ERROR);
}
int CPop3Socket::Receive(LPSTR pszBuf, int nBuf)
{
//must have been created first
ASSERT(m_hSocket != INVALID_SOCKET);
return recv(m_hSocket, pszBuf, nBuf, 0);
}
void CPop3Socket::Close()
{
if (m_hSocket != INVALID_SOCKET)
{
VERIFY(SOCKET_ERROR != closesocket(m_hSocket));
m_hSocket = INVALID_SOCKET;
}
}
BOOL CPop3Socket::IsReadible(BOOL& bReadible)
{
timeval timeout = {0, 0};
fd_set fds;
FD_ZERO(&fds);
FD_SET(m_hSocket, &fds);
int nStatus = select(0, &fds, NULL, NULL, &timeout);
if (nStatus == SOCKET_ERROR)
{
return FALSE;
}
else
{
bReadible = !(nStatus == 0);
return TRUE;
}
}
CPop3Connection::CPop3Connection()
{
m_nNumberOfMails = 0;
m_bListRetrieved = FALSE;
m_bStatRetrieved = FALSE;
m_bUIDLRetrieved = FALSE;
m_msgSizes.RemoveAll();
m_bConnected = FALSE;
#ifdef _DEBUG
m_dwTimeout = 20000; //default timeout of 20 seconds when debugging
#else
m_dwTimeout = 2000; //default timeout of 2 seconds for normal release code
#endif
}
CPop3Connection::~CPop3Connection()
{
if (m_bConnected)
Disconnect();
}
BOOL CPop3Connection::Connect(LPCTSTR pszHostName, LPCTSTR pszUser, LPCTSTR pszPassword, int nPort)
{
//For correct operation of the T2A macro, see MFC Tech Note 59
USES_CONVERSION;
//Create the socket
if (!m_Pop.Create())
{
TRACE(_T("Failed to create client socket\n"));
return FALSE;
}
//Connect to the POP3 Host
if (!m_Pop.Connect(pszHostName, nPort))
{
TRACE(_T("Could not connect to the POP3 mailbox\n"));
return FALSE;
}
else
{
//We're now connected !!
m_bConnected = TRUE;
//check the response
if (!ReadCommandResponse())
{
Disconnect();
return FALSE;
}
//Send the POP3 username and check the response
char sBuf[128];
char* pszAsciiUser = T2A((LPTSTR) pszUser);
ASSERT(strlen(pszAsciiUser) < 100);
sprintf(sBuf, "USER %s\r\n", pszAsciiUser);
int nCmdLength = strlen(sBuf);
if (!m_Pop.Send(sBuf, nCmdLength))
{
Disconnect();
return FALSE;
}
if (!ReadCommandResponse())
{
Disconnect();
return FALSE;
}
//Send the POP3 password and check the response
char* pszAsciiPassword = T2A((LPTSTR) pszPassword);
ASSERT(strlen(pszAsciiPassword) < 100);
sprintf(sBuf, "PASS %s\r\n", pszAsciiPassword);
nCmdLength = strlen(sBuf);
if (!m_Pop.Send(sBuf, nCmdLength))
{
Disconnect();
return FALSE;
}
if (!ReadCommandResponse())
{
Disconnect();
return FALSE;
}
return TRUE;
}
}
BOOL CPop3Connection::Disconnect()
{
BOOL bSuccess = FALSE;
//disconnect from the POP3 server if connected
if (m_bConnected)
{
char sBuf[10];
strcpy(sBuf, "QUIT\r\n");
int nCmdLength = strlen(sBuf);
if (!m_Pop.Send(sBuf, nCmdLength))
TRACE(_T("Failed in call to send QUIT command\n"));
//Check the reponse
bSuccess = ReadCommandResponse();
//Reset all the state variables
m_bConnected = FALSE;
m_bListRetrieved = FALSE;
m_bStatRetrieved = FALSE;
m_bUIDLRetrieved = FALSE;
}
else
TRACE(_T("Already disconnected\n"));
//free up our socket
m_Pop.Close();
return bSuccess;
}
BOOL CPop3Connection::Delete(int nMsg)
{
//Must be connected to perform a delete
ASSERT(m_bConnected);
//if we haven't executed the LIST command then do it now
if (!m_bListRetrieved)
List();
//Send the DELE command along with the message ID
char sBuf[20];
sprintf(sBuf, "DELE %d\r\n", nMsg);
int nCmdLength = strlen(sBuf);
if (!m_Pop.Send(sBuf, nCmdLength))
{
TRACE(_T("Failed in call to send DELE command\n"));
return FALSE;
}
return ReadCommandResponse();
}
BOOL CPop3Connection::Statistics(int& nNumberOfMails, int& nTotalMailSize)
{
//Must be connected to perform a "STAT"
ASSERT(m_bConnected);
//Send the STAT command
char sBuf[10];
strcpy(sBuf, "STAT\r\n");
int nCmdLength = strlen(sBuf);
if (!m_Pop.Send(sBuf, nCmdLength))
{
TRACE(_T("Failed in call to send STAT command\n"));
return FALSE;
}
return ReadStatResponse(nNumberOfMails, nTotalMailSize);
}
BOOL CPop3Connection::GetMessageSize(int nMsg, DWORD& dwSize)
{
BOOL bSuccess = TRUE;
//if we haven't executed the LIST command then do it now
if (!m_bListRetrieved)
bSuccess = List();
//nMsg must be in the correct range
ASSERT((nMsg > 0) && (nMsg <= m_msgSizes.GetSize()));
//retrieve the size from the message size array
dwSize = m_msgSizes.GetAt(nMsg - 1);
return bSuccess;
}
BOOL CPop3Connection::GetMessageID(int nMsg, CString& sID)
{
BOOL bSuccess = TRUE;
//if we haven't executed the UIDL command then do it now
if (!m_bUIDLRetrieved)
bSuccess = UIDL();
//nMsg must be in the correct range
ASSERT((nMsg > 0) && (nMsg <= m_msgIDs.GetSize()));
//retrieve the size from the message size array
sID = m_msgIDs.GetAt(nMsg - 1);
return bSuccess;
}
BOOL CPop3Connection::List()
{
//Must be connected to perform a "LIST"
ASSERT(m_bConnected);
//if we haven't executed the STAT command then do it now
int nNumberOfMails = m_nNumberOfMails;
int nTotalMailSize;
if (!m_bStatRetrieved)
{
if (!Statistics(nNumberOfMails, nTotalMailSize))
return FALSE;
else
m_bStatRetrieved = TRUE;
}
//Send the LIST command
char sBuf[10];
strcpy(sBuf, "LIST\r\n");
int nCmdLength = strlen(sBuf);
if (!m_Pop.Send(sBuf, nCmdLength))
{
TRACE(_T("Failed in call to send LIST command\n"));
return FALSE;
}
//And check the response
m_bListRetrieved = ReadListResponse(nNumberOfMails);
return m_bListRetrieved;
}
BOOL CPop3Connection::UIDL()
{
//Must be connected to perform a "UIDL"
ASSERT(m_bConnected);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -