Files
Slnkdwf/ATL90/include/atlsmtpconnection.h
Jos Groot Lipman 0e37d774d2 Merge SLNKDWF64 branch
svn path=/Slnkdwf/trunk/; revision=23911
2015-01-21 12:09:31 +00:00

927 lines
22 KiB
C++

// This is a part of the Active Template Library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Active Template Library Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Active Template Library product.
#ifndef __ATLSMTPCONNECTION_H__
#define __ATLSMTPCONNECTION_H__
#pragma once
#ifndef _ATL_NO_DEFAULT_LIBS
#pragma comment(lib, "ws2_32.lib")
#endif // !_ATL_NO_DEFAULT_LIBS
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <atlstr.h>
#include <atlcoll.h>
#include <atlfile.h>
#include <atlmime.h>
#include <atlspriv.h>
#include <atlsmtputil.h>
#include <atlsocket.h>
// SMTP Return Codes
#define ATLSMTP_MAIL_SUCCESS 250
#define ATLSMTP_RCPT_SUCCESS 250
#define ATLSMTP_RCPT_NOT_LOCAL 251
#define ATLSMTP_DATA_INTERMEDIATE 354
#define ATLSMTP_CONN_SUCC "220"
#define ATLSMTP_HELO_SUCC "250"
#define ATLSMTP_MAIL_SUCC "250"
#define ATLSMTP_RCPT_SUCC "250"
#define ATLSMTP_RCPT_NLOC "251"
#define ATLSMTP_DATA_INTM "354"
#define ATLSMTP_DATA_SUCC "250"
#define ATLSMTP_RSET_SUCC "250"
// SMTP flags
#define ATLSMTP_DUMP_SENDER 1
#define ATLSMTP_DUMP_RECIPS 2
#define ATLSMTP_FOR_SEND 4
struct CSMTPWSAStartup
{
private:
bool m_bInit;
public:
CSMTPWSAStartup() throw()
:m_bInit(false)
{
Init();
}
~CSMTPWSAStartup() throw()
{
Uninit();
}
bool Init() throw()
{
if (m_bInit)
return true;
WSADATA wsadata;
if (WSAStartup(ATLSMTP_WSA_VERSION, &wsadata))
return false;
m_bInit = true;
ATLASSERT(wsadata.wHighVersion >= 2);
return true;
}
bool Uninit() throw()
{
if (m_bInit)
if (WSACleanup())
return false;
m_bInit = false;
return true;
}
};
__declspec(selectany) CSMTPWSAStartup _g_smtp_init;
#pragma pack(push,_ATL_PACKING)
namespace ATL {
class CSMTPConnection
{
protected:
// the socket
SOCKET m_hSocket;
// the OVERLAPPED struct
OVERLAPPED m_Overlapped;
public:
CSMTPConnection() throw()
:m_hSocket(INVALID_SOCKET)
{
// initialize the OVERLAPPED struct
memset(&m_Overlapped, 0, sizeof(OVERLAPPED));
}
~CSMTPConnection() throw()
{
Disconnect();
}
// Attempt to connect to the socket
// lpszHostName - the host name to connect to
BOOL Connect(LPCTSTR lpszHostName, DWORD dwTimeout = 10000) throw()
{
ATLASSERT(lpszHostName != NULL);
// If we're already connected
if (Connected())
{
return FALSE;
}
if (!_g_smtp_init.Init())
{
return FALSE;
}
CSocketAddr address;
if (address.FindAddr(lpszHostName, IPPORT_SMTP, 0, PF_UNSPEC, SOCK_STREAM, 0))
{
return FALSE;
}
ADDRINFOT *pAI;
BOOL bRet = FALSE;
int nIndex = 0;
while ((pAI = address.GetAddrInfo(nIndex++)) != NULL)
{
// create the socket
m_hSocket = WSASocket(pAI->ai_family, pAI->ai_socktype, pAI->ai_protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
if (m_hSocket == INVALID_SOCKET)
{
return FALSE;
}
bRet = FALSE;
WSAEVENT hEventConnect = WSACreateEvent();
if (hEventConnect != NULL)
{
if (SOCKET_ERROR != WSAEventSelect(m_hSocket, hEventConnect, FD_CONNECT))
{
if (WSAConnect(m_hSocket, pAI->ai_addr, (int)pAI->ai_addrlen,
NULL, NULL, NULL, NULL))
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
DWORD dwWait = WaitForSingleObject((HANDLE) hEventConnect, dwTimeout);
if (dwWait == WAIT_OBJECT_0)
{
// make sure there were no connection errors.
WSANETWORKEVENTS wse;
ZeroMemory(&wse, sizeof(wse));
WSAEnumNetworkEvents(m_hSocket, NULL, &wse);
if (wse.iErrorCode[FD_CONNECT_BIT]==0)
{
bRet = TRUE;
}
}
}
}
}
// we're done with the event
WSACloseEvent(hEventConnect);
}
if (bRet)
{
break;
}
shutdown(m_hSocket, SD_BOTH);
closesocket(m_hSocket);
m_hSocket = INVALID_SOCKET;
}
// Create an event for asynchronous I/O
if (bRet)
{
ATLASSUME(m_Overlapped.hEvent == NULL);
m_Overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
if (m_Overlapped.hEvent == NULL)
{
bRet = FALSE;
}
}
char szBuf[ATLSMTP_MAX_LINE_LENGTH+1];
int nBufLen = ATLSMTP_MAX_LINE_LENGTH;
if (bRet)
{
// See if the connect returns success
bRet = AtlSmtpReadData((HANDLE)m_hSocket, szBuf, &nBufLen, &m_Overlapped);
if (bRet)
{
if (strncmp(szBuf, ATLSMTP_CONN_SUCC, ATLSMTP_RETCODE_LEN))
{
bRet = FALSE;
}
}
}
char szLocalHost[ATLSMTP_MAX_SERVER_NAME_LENGTH+1];
// gethostname should return 0 on success
if (bRet && gethostname(szLocalHost, ATLSMTP_MAX_SERVER_NAME_LENGTH))
{
bRet = FALSE;
}
// Send HELO command and get reply
if (bRet)
{
nBufLen = sprintf_s(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "HELO %s\r\n", szLocalHost);
if (nBufLen > 0)
{
bRet = AtlSmtpSendAndCheck((HANDLE)m_hSocket, szBuf, nBufLen, szBuf, &nBufLen,
ATLSMTP_MAX_LINE_LENGTH, ATLSMTP_HELO_SUCC, &m_Overlapped);
}
else
{
bRet = FALSE;
}
}
if (!bRet)
{
if (m_Overlapped.hEvent != NULL)
CloseHandle(m_Overlapped.hEvent);
shutdown(m_hSocket, SD_BOTH);
closesocket(m_hSocket);
m_hSocket = INVALID_SOCKET;
}
return bRet;
}
// Disconnect the socket
inline BOOL Disconnect() throw()
{
if (!Connected())
{
return FALSE;
}
// shutdown should return 0 on success
if (shutdown(m_hSocket, SD_BOTH))
{
return FALSE;
}
// closesocket should return 0 on success
if (closesocket(m_hSocket))
{
return FALSE;
}
// close the handle to the overlapped event
CloseHandle(m_Overlapped.hEvent);
m_hSocket = INVALID_SOCKET;
memset((void*)&m_Overlapped, 0, sizeof(OVERLAPPED));
return TRUE;
}
// Are we connected?
inline BOOL Connected() throw()
{
return (m_hSocket != INVALID_SOCKET ? TRUE : FALSE);
}
// Send a message from a file
// lpszFileName - the file containing the message
// lpszRecipients - the recipients to send to (optional - if not specified, the recipients specified
// in the file will be used
// lpszSender - the sender (optional - if not specified, the recipients specified in the file
// will be used
BOOL SendMessage(LPCTSTR lpszFileName, LPCTSTR lpszRecipients = NULL, LPCTSTR lpszSender = NULL) throw()
{
if (!Connected())
{
return FALSE;
}
//Try to open the file
CAtlFile readFile;
if (FAILED(readFile.Create(lpszFileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL)))
{
return FALSE;
}
char szBuf[ATLSMTP_MAX_LINE_LENGTH+1];
int nBufLen = ATLSMTP_MAX_LINE_LENGTH;
BOOL bDumpedSender = FALSE;
//If the caller specifies the sender, rather than having an existing one in the file...
if (lpszSender)
{
nBufLen = sprintf_s(szBuf, ATLSMTP_MAX_LINE_LENGTH+1,
"MAIL FROM:<%s>\r\n", (LPCSTR) CT2CA(lpszSender));
if ((nBufLen < 0) ||
(!AtlSmtpSendAndCheck((HANDLE)m_hSocket, szBuf, nBufLen, szBuf, &nBufLen, ATLSMTP_MAX_LINE_LENGTH,
ATLSMTP_MAIL_SUCC, &m_Overlapped)))
{
return FALSE;
}
bDumpedSender = TRUE;
}
nBufLen = ATLSMTP_MAX_LINE_LENGTH;
#ifdef ATLSMTP_DOUBLE_BUFFERED
char buffer1[ATLSMTP_READBUFFER_SIZE];
char buffer2[ATLSMTP_READBUFFER_SIZE];
char* currBuffer = buffer1;
char* prevBuffer = NULL;
int nCurrBuffer = 0;
DWORD dwPrevLength = 0;
DWORD dwWritten = 0;
#else
char bakBuffer[ATLSMTP_READBUFFER_SIZE];
char* currBuffer = bakBuffer;
#endif // ATLSMTP_DOUBLE_BUFFERED
DWORD dwRead = 0;
DWORD dwBytesInBuffer = 0;
DWORD dwBufPos = 0;
//first handle the MAIL FROM and RCPT TO commands
BOOL bDumpedRecipients = FALSE;
BOOL bRet = TRUE;
while (bRet)
{
int nRetCode = 0;
//if we have dumped the sender, and we have extra recipients to send,
//and we haven't alredy done so, do it
if (lpszRecipients && !bDumpedRecipients && bDumpedSender)
{
bRet = DumpRecipients((HANDLE)m_hSocket, CT2A(lpszRecipients), &m_Overlapped, ATLSMTP_FOR_SEND);
}
if (bRet)
{
dwRead = 0;
BOOL bFullLine = FALSE;
bRet = ReadLine(readFile, currBuffer, szBuf, &dwBytesInBuffer, &dwBufPos,
ATLSMTP_READBUFFER_SIZE, ATLSMTP_MAX_LINE_LENGTH, &dwRead, &bFullLine);
if (dwRead == 0 || bFullLine == FALSE)
bRet = FALSE;
}
if (bRet)
{
bRet = AtlSmtpSendAndWait((HANDLE)m_hSocket, szBuf, (int)(dwRead), &m_Overlapped);
}
if (bRet)
{
nBufLen = ATLSMTP_MAX_LINE_LENGTH;
bRet = AtlSmtpReadData((HANDLE)m_hSocket, szBuf, &nBufLen, &m_Overlapped);
}
if (bRet)
{
nRetCode = atoi(szBuf);
//if the command is equal to ATLSMTP_MAIL_SUCC (or RCPT_SUCC: they are equivalent)
if (nRetCode == ATLSMTP_MAIL_SUCCESS || nRetCode == ATLSMTP_RCPT_NOT_LOCAL || nRetCode == ATLSMTP_RCPT_SUCCESS)
{
bDumpedSender = TRUE;
continue;
}
//If the command is equal to the data intermediate success code,
//break out of the loop
if (nRetCode == ATLSMTP_DATA_INTERMEDIATE)
break;
}
//otherwise, we got an error code
CancelMessage();
return FALSE;
}
dwRead = dwBytesInBuffer;
currBuffer+= dwBufPos;
DWORD dwErr = 0;
do
{
dwErr = 0;
//Try to send the data
#ifdef ATLSMTP_DOUBLE_BUFFERED
if (!AtlSmtpSendOverlapped((HANDLE)m_hSocket, currBuffer, dwRead, prevBuffer, dwPrevLength, &m_Overlapped))
{
bRet = FALSE;
break;
}
#else
if (!AtlSmtpSendAndWait((HANDLE)m_hSocket, currBuffer, dwRead, &m_Overlapped))
{
bRet = FALSE;
break;
}
#endif // ATLSMTP_DOUBLE_BUFFERED
//swap the current and previous buffer
#ifdef ATLSMTP_DOUBLE_BUFFERED
prevBuffer = currBuffer;
currBuffer = (nCurrBuffer == 0 ? buffer2 : buffer1);
nCurrBuffer = (nCurrBuffer == 0 ? 1 : 0);
dwPrevLength = dwBytesInBuffer;
#else
currBuffer = bakBuffer;
#endif // ATLSMTP_DOUBLE_BUFFERED
if (FAILED(readFile.Read(currBuffer, ATLSMTP_READBUFFER_SIZE, dwRead)))
{
bRet = FALSE;
break;
}
} while (dwRead != 0);
//ensure that the last of the data is sent
#ifdef ATLSMTP_DOUBLE_BUFFERED
if (!GetOverlappedResult((HANDLE)m_hSocket, &m_Overlapped, &dwWritten, TRUE))
{
if ((dwErr = GetLastError()) != ERROR_IO_PENDING && dwErr != ERROR_IO_INCOMPLETE)
bRet = FALSE;
else if (dwWritten < dwPrevLength)
bRet = AtlSmtpSendAndWait((HANDLE)m_hSocket, prevBuffer+dwWritten, dwPrevLength-dwWritten, &m_Overlapped);
}
#endif // ATLSMTP_DOUBLE_BUFFERED
if (bRet)
{
// End the message with a CRLF.CRLF
nBufLen = sprintf_s(szBuf, _countof(szBuf), "\r\n.\r\n");
if (!AtlSmtpSendAndCheck((HANDLE)m_hSocket, szBuf, nBufLen,
szBuf, &nBufLen, ATLSMTP_MAX_LINE_LENGTH, ATLSMTP_DATA_SUCC, &m_Overlapped))
{
bRet = FALSE;
}
}
return bRet;
}
// Send the message
// msg - the CMimeMessage to send
// lpszSender - the sender
inline BOOL SendMessage(CMimeMessage& msg, LPCTSTR lpszRecipients = NULL, LPCTSTR lpszSender = NULL) throw()
{
if (!Connected())
{
return FALSE;
}
char szBuf[ATLSMTP_MAX_LINE_LENGTH+1];
//Send MAIL FROM command and get reply
int nBufLen = sprintf_s(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "MAIL FROM:<%s>\r\n",
(lpszSender ? (LPCSTR) CT2CA(lpszSender) : msg.GetSender()));
if ((nBufLen < 0) ||
(!AtlSmtpSendAndCheck((HANDLE)m_hSocket, szBuf, nBufLen,
szBuf, &nBufLen, ATLSMTP_MAX_LINE_LENGTH, ATLSMTP_MAIL_SUCC, &m_Overlapped)))
{
return FALSE;
}
BOOL bRet = TRUE;
if (!lpszRecipients)
{
LPSTR lpszRecipientsA = NULL;
DWORD dwLen = msg.GetRequiredRecipientsStringLength();
lpszRecipientsA = static_cast<LPSTR>(calloc(sizeof(char),dwLen));
if (!lpszRecipientsA || msg.GetRecipientsString(lpszRecipientsA, &dwLen) == FALSE)
{
bRet = FALSE;
}
if (bRet)
bRet = DumpRecipients((HANDLE)m_hSocket, lpszRecipientsA, &m_Overlapped, ATLSMTP_FOR_SEND);
free(lpszRecipientsA);
}
else
{
bRet = DumpRecipients((HANDLE)m_hSocket, CT2CA(lpszRecipients),
&m_Overlapped, ATLSMTP_FOR_SEND);
}
//Begin the data output
if (bRet)
{
nBufLen = sprintf_s(szBuf, _countof(szBuf), "DATA\r\n");
bRet = AtlSmtpSendAndCheck((HANDLE)m_hSocket, szBuf, nBufLen,
szBuf, &nBufLen, ATLSMTP_MAX_LINE_LENGTH, ATLSMTP_DATA_INTM, &m_Overlapped);
}
if (!bRet)
CancelMessage();
//Attempt to write the data to the socket
if (bRet)
{
bRet = msg.WriteData((HANDLE)m_hSocket, &m_Overlapped, NULL, ATLSMTP_FORMAT_SMTP);
}
if (bRet)
{
//End the message with a <CRLF>.<CRLF>
nBufLen = sprintf_s(szBuf, _countof(szBuf), "\r\n.\r\n");
if (!AtlSmtpSendAndCheck((HANDLE)m_hSocket, szBuf, nBufLen,
szBuf, &nBufLen, ATLSMTP_MAX_LINE_LENGTH, ATLSMTP_DATA_SUCC, &m_Overlapped))
{
return FALSE;
}
}
return bRet;
}
// Send a chunk of raw data
inline BOOL SendRaw(LPCTSTR lpszRawData, DWORD dwLen, LPCTSTR lpszRecipients, LPCTSTR lpszSender) throw()
{
ATLASSERT(lpszRawData != NULL);
ATLASSERT(lpszRecipients != NULL);
ATLASSERT(lpszSender != NULL);
if (!Connected())
return FALSE;
char szBuf[ATLSMTP_MAX_LINE_LENGTH+1];
//Send MAIL FROM command and get reply
int nBufLen = sprintf_s(szBuf, ATLSMTP_MAX_LINE_LENGTH+1,
"MAIL FROM:<%s>\r\n", (LPCSTR) CT2CA(lpszSender));
if ((nBufLen < 0) ||
(!AtlSmtpSendAndCheck((HANDLE)m_hSocket, szBuf, nBufLen,
szBuf, &nBufLen, ATLSMTP_MAX_LINE_LENGTH, ATLSMTP_MAIL_SUCC, &m_Overlapped)))
{
return FALSE;
}
BOOL bRet = DumpRecipients((HANDLE)m_hSocket, CT2CA(lpszRecipients),
&m_Overlapped, ATLSMTP_FOR_SEND);
// Begin the data output
if (bRet)
{
nBufLen = sprintf_s(szBuf, _countof(szBuf), "DATA\r\n");
bRet = AtlSmtpSendAndCheck((HANDLE)m_hSocket, szBuf, nBufLen,
szBuf, &nBufLen, ATLSMTP_MAX_LINE_LENGTH, ATLSMTP_DATA_INTM, &m_Overlapped);
}
if (!bRet)
CancelMessage();
if (bRet)
{
bRet = AtlSmtpSendAndWait((HANDLE)m_hSocket, (LPSTR)(lpszRawData), dwLen, &m_Overlapped);
}
if (bRet)
{
//End the message with a <CRLF>.<CRLF>
nBufLen = sprintf_s(szBuf, _countof(szBuf), "\r\n.\r\n");
if (!AtlSmtpSendAndCheck((HANDLE)m_hSocket, szBuf, nBufLen,
szBuf, &nBufLen, ATLSMTP_MAX_LINE_LENGTH, ATLSMTP_DATA_SUCC, &m_Overlapped))
{
return FALSE;
}
}
return bRet;
}
inline BOOL SendSimple(LPCTSTR lpszRecipients, LPCTSTR lpszSender, LPCTSTR lpszSubject, LPCTSTR lpszBody, int nTextLen = -1) throw()
{
CMimeMessage msg;
BOOL bRet = msg.SetSubject(lpszSubject);
if (bRet)
bRet = msg.AddText(lpszBody, nTextLen);
CFixedStringT<CString, MAX_PATH> strRecip;
LPCTSTR szTmp = lpszRecipients;
LPCTSTR szTmp2 = lpszRecipients;
while (*szTmp && bRet)
{
if (AtlSmtpIsRecipientDelimiter((char) *szTmp2))
{
_ATLTRY
{
strRecip.SetString(szTmp, (int)(szTmp2-szTmp));
bRet = msg.AddRecipient((LPCTSTR) strRecip);
if (*szTmp2)
{
while (*szTmp2 && AtlSmtpIsRecipientDelimiter((char) *szTmp2))
{
szTmp2++;
}
}
szTmp = szTmp2;
}
_ATLCATCHALL()
{
bRet = FALSE;
}
}
else
{
szTmp2++;
}
}
if (bRet)
bRet = SendMessage(msg, lpszRecipients, lpszSender);
return bRet;
}
// Save a MIME message to a file
// lpszFileName - the file name
// lpszRecipients - the recipients string (optional)
// lpszSender - the sender (optional)
// dwFlags - the flags (optional)
inline BOOL WriteToFile(LPCTSTR lpszFileName, CMimeMessage& msg, LPCTSTR lpszRecipients = NULL,
LPCTSTR lpszSender = NULL, DWORD dwFlags = 0) throw()
{
//Try to create/open the file
HANDLE hFile = CreateFile(lpszFileName, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return FALSE;
}
// Use CHandle to close the file handle
// (CAtlFile does not allow for overlapped I/O)
CHandle hdlFile(hFile);
//Create and initialize the OVERLAPPED struct
OVERLAPPED writeOverlapped;
memset((void*)&writeOverlapped, 0, sizeof(OVERLAPPED));
writeOverlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
if (writeOverlapped.hEvent == NULL)
{
return FALSE;
}
// Use CHandle to close the event handle
CHandle hdlEvent(writeOverlapped.hEvent);
char szBuf[ATLSMTP_MAX_LINE_LENGTH+1];
BOOL bRet = TRUE;
int nBufLen = 0;
//if writing to file for purposes of sending, write out the
//commands as well
if (lpszSender || (dwFlags & ATLSMTP_DUMP_SENDER))
{
nBufLen = sprintf_s(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "MAIL FROM:<%s>\r\n",
(lpszSender ? (LPCSTR) CT2CA(lpszSender) : msg.GetSender()));
if (nBufLen > 0)
{
bRet = AtlSmtpSendAndWait(hFile, szBuf, nBufLen, &writeOverlapped);
}
else
{
bRet = FALSE;
}
}
if (bRet && (lpszRecipients || (dwFlags & ATLSMTP_DUMP_RECIPS)))
{
if (!lpszRecipients)
{
LPSTR lpszRecipientsA = NULL;
DWORD dwLen = msg.GetRequiredRecipientsStringLength();
lpszRecipientsA = static_cast<LPSTR>(calloc(sizeof(char),dwLen));
if (!lpszRecipientsA || msg.GetRecipientsString(lpszRecipientsA, &dwLen) == FALSE)
{
bRet = FALSE;
}
if (bRet)
bRet = DumpRecipients(hFile, lpszRecipientsA, &writeOverlapped);
free(lpszRecipientsA);
}
else
{
bRet = DumpRecipients(hFile, CT2CA(lpszRecipients), &writeOverlapped);
}
}
if (bRet)
{
nBufLen = sprintf_s(szBuf, _countof(szBuf), "DATA\r\n");
bRet = AtlSmtpSendAndWait(hFile, szBuf, nBufLen, &writeOverlapped);
}
if (bRet)
{
bRet = msg.WriteData(hFile, &writeOverlapped, NULL, ATLSMTP_FORMAT_SMTP);
}
return bRet;
}
protected:
// disallow copy construction
CSMTPConnection(const CSMTPConnection&) throw()
{
ATLASSERT(FALSE);
}
// disallow assignment
const CSMTPConnection& operator=(const CSMTPConnection&) throw()
{
ATLASSERT(FALSE);
return *this;
}
// Tell the server we are aborting the message
inline BOOL CancelMessage() throw()
{
char szBuf[ATLSMTP_MAX_LINE_LENGTH+1];
int nBufLen = 0;
nBufLen = sprintf_s(szBuf, _countof(szBuf), "RSET\r\n");
if (!AtlSmtpSendAndCheck((HANDLE)m_hSocket, szBuf, nBufLen, szBuf, &nBufLen, ATLSMTP_MAX_LINE_LENGTH,
ATLSMTP_RSET_SUCC, &m_Overlapped))
{
Disconnect();
return FALSE;
}
return TRUE;
}
// Dump the recipients to hFile
// lpszRecipients - the recipients string
// pOverlapped - the OVERALAPPED struct
// dwFlags - the flags
inline BOOL DumpRecipients(HANDLE hFile, LPCSTR lpszRecipients, LPOVERLAPPED pOverlapped, DWORD dwFlags = 0)
{
ATLENSURE(lpszRecipients != NULL);
ATLASSERT(pOverlapped != NULL);
char rcptBuf[ATLSMTP_MAX_LINE_LENGTH-12+1];
char szBuf[ATLSMTP_MAX_LINE_LENGTH+1];
LPSTR tmpBuf = rcptBuf;
char ch;
BOOL bRet = TRUE;
int nMaxLength = ATLSMTP_MAX_LINE_LENGTH;
int nRetCode = 0;
size_t nCnt = 0;
do
{
ch = *lpszRecipients;
if (ch)
lpszRecipients++;
if (AtlSmtpIsRecipientDelimiter(ch))
{
*tmpBuf = 0;
int nBufLen = sprintf_s(szBuf, ATLSMTP_MAX_LINE_LENGTH,
"RCPT TO:<%s>\r\n", rcptBuf);
if (nBufLen > 0)
{
bRet = AtlSmtpSendAndWait(hFile, szBuf, nBufLen, pOverlapped);
}
else
{
bRet = FALSE;
}
if (bRet && (dwFlags & ATLSMTP_FOR_SEND))
{
bRet = AtlSmtpReadData(hFile, szBuf, &nMaxLength, pOverlapped);
nRetCode = atoi(szBuf);
if (!bRet || (nRetCode != ATLSMTP_RCPT_SUCCESS && nRetCode != ATLSMTP_RCPT_NOT_LOCAL))
{
bRet = FALSE;
break;
}
}
tmpBuf = rcptBuf;
nCnt = 0;
nMaxLength = ATLSMTP_MAX_LINE_LENGTH;
while (isspace(static_cast<unsigned char>(*lpszRecipients)))
lpszRecipients++;
continue;
}
if (nCnt >= sizeof(rcptBuf)-1)
{
// recipient string too long
bRet = FALSE;
break;
}
*tmpBuf++ = ch;
nCnt++;
} while (ch != '\0');
return bRet;
}
// Implementation - used from ReadLine
// fills pBuf with up to dwMaxLen bytes
BOOL FillBuffer(__in HANDLE hFile, __out_ecount_part(dwMaxLen, *pdwLen) LPSTR pBuf, __in DWORD dwMaxLen, __out LPDWORD pdwLen) throw()
{
ATLASSERT(hFile != INVALID_HANDLE_VALUE);
ATLASSERT(pdwLen != NULL);
DWORD dwRead = 0;
DWORD dwTotalRead = 0;
int nRet = 0;
do
{
nRet = ReadFile(hFile, pBuf, dwMaxLen-dwTotalRead, &dwRead, NULL);
if (!nRet && GetLastError() != ERROR_HANDLE_EOF)
{
return FALSE;
}
if (dwRead == 0)
break;
dwTotalRead+= dwRead;
} while (dwTotalRead < dwMaxLen);
*pdwLen = dwTotalRead;
return TRUE;
}
// Implementation
// Read a line (terminated by LF) from hFile
BOOL ReadLine(__in HANDLE hFile, __out_ecount_part_z(dwMaxSrcLen, *pdwSrcLen) LPSTR pSrc, __out_ecount_part_z(dwMaxDestLen, *pdwRead) LPSTR pDest, __inout LPDWORD pdwSrcLen, __inout LPDWORD pdwBufPos, __in DWORD dwMaxSrcLen,
__in DWORD dwMaxDestLen, __out_opt LPDWORD pdwRead=NULL, __out_opt LPBOOL pbFullLine=NULL)
{
ATLENSURE(hFile != INVALID_HANDLE_VALUE);
ATLENSURE(pSrc != NULL);
ATLENSURE(pDest != NULL);
ATLENSURE(pdwSrcLen != NULL);
ATLENSURE(pdwBufPos != NULL);
BOOL bRet = TRUE;
DWORD dwLen = 0;
DWORD dwBufPos = 0;
DWORD dwSrcLen = *pdwSrcLen;
LPSTR pSrcCurrent = pSrc + *pdwBufPos;
while (bRet && dwLen < dwMaxDestLen)
{
if (dwSrcLen == 0)
{
if (!FillBuffer(hFile, pSrc, dwMaxSrcLen, pdwSrcLen) || *pdwSrcLen == 0)
break;
dwBufPos = 0;
*pdwBufPos = 0;
dwSrcLen = *pdwSrcLen;
pSrcCurrent = pSrc;
}
--dwSrcLen;
*pDest = *pSrcCurrent++;
dwLen++;
dwBufPos++;
if (*pDest == '\n')
{
break;
}
pDest++;
}
*pdwSrcLen = dwSrcLen;
if (pbFullLine)
{
if (*pDest != '\n')
*pbFullLine = FALSE;
else
*pbFullLine = TRUE;
}
if (pdwRead)
*pdwRead = dwLen;
*pdwBufPos += dwBufPos;
return bRet;
}
}; // class CSMTPConnection
} // namespace ATL
#pragma pack(pop)
#endif // __ATLSMTPCONNECTION_H__