// 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 #include #include #include #include #include #include #include #include #include #include // 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) { #if _SECURE_ATL nBufLen = sprintf_s(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "HELO %s\r\n", szLocalHost); #else nBufLen = _snprintf(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "HELO %s\r\n", szLocalHost); #endif 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) { #if _SECURE_ATL nBufLen = sprintf_s(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "MAIL FROM:<%s>\r\n", (LPCSTR) CT2CA(lpszSender)); #else nBufLen = _snprintf(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "MAIL FROM:<%s>\r\n", (LPCSTR) CT2CA(lpszSender)); #endif 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 #if _SECURE_ATL nBufLen = sprintf_s(szBuf, _countof(szBuf), "\r\n.\r\n"); #else nBufLen = sprintf(szBuf, "\r\n.\r\n"); #endif 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 #if _SECURE_ATL int nBufLen = sprintf_s(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "MAIL FROM:<%s>\r\n", (lpszSender ? (LPCSTR) CT2CA(lpszSender) : msg.GetSender())); #else int nBufLen = _snprintf(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "MAIL FROM:<%s>\r\n", (lpszSender ? (LPCSTR) CT2CA(lpszSender) : msg.GetSender())); #endif 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(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) { #if _SECURE_ATL nBufLen = sprintf_s(szBuf, _countof(szBuf), "DATA\r\n"); #else nBufLen = sprintf(szBuf, "DATA\r\n"); #endif 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 . #if _SECURE_ATL nBufLen = sprintf_s(szBuf, _countof(szBuf), "\r\n.\r\n"); #else nBufLen = sprintf(szBuf, "\r\n.\r\n"); #endif 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 #if _SECURE_ATL int nBufLen = sprintf_s(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "MAIL FROM:<%s>\r\n", (LPCSTR) CT2CA(lpszSender)); #else int nBufLen = _snprintf(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "MAIL FROM:<%s>\r\n", (LPCSTR) CT2CA(lpszSender)); #endif 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) { #if _SECURE_ATL nBufLen = sprintf_s(szBuf, _countof(szBuf), "DATA\r\n"); #else nBufLen = sprintf(szBuf, "DATA\r\n"); #endif 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 . #if _SECURE_ATL nBufLen = sprintf_s(szBuf, _countof(szBuf), "\r\n.\r\n"); #else nBufLen = sprintf(szBuf, "\r\n.\r\n"); #endif 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 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)) { #if _SECURE_ATL nBufLen = sprintf_s(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "MAIL FROM:<%s>\r\n", (lpszSender ? (LPCSTR) CT2CA(lpszSender) : msg.GetSender())); #else nBufLen = _snprintf(szBuf, ATLSMTP_MAX_LINE_LENGTH+1, "MAIL FROM:<%s>\r\n", (lpszSender ? (LPCSTR) CT2CA(lpszSender) : msg.GetSender())); #endif 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(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) { #if _SECURE_ATL nBufLen = sprintf_s(szBuf, _countof(szBuf), "DATA\r\n"); #else nBufLen = sprintf(szBuf, "DATA\r\n"); #endif 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; #if _SECURE_ATL nBufLen = sprintf_s(szBuf, _countof(szBuf), "RSET\r\n"); #else nBufLen = sprintf(szBuf, "RSET\r\n"); #endif 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; #if _SECURE_ATL int nBufLen = sprintf_s(szBuf, ATLSMTP_MAX_LINE_LENGTH, "RCPT TO:<%s>\r\n", rcptBuf); #else int nBufLen = _snprintf(szBuf, ATLSMTP_MAX_LINE_LENGTH, "RCPT TO:<%s>\r\n", rcptBuf); #endif 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(*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__