221 lines
7.2 KiB
C++
221 lines
7.2 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 __ATLSMTPUTIL_H__
|
|
#define __ATLSMTPUTIL_H__
|
|
|
|
#pragma once
|
|
|
|
#if (defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_))
|
|
#error <atlsmtputil.h> requires <winsock2.h> -- include <winsock2.h> before you include <windows.h> or <winsock.h>
|
|
#endif
|
|
#include <winsock2.h>
|
|
#include <windows.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <tchar.h>
|
|
#include <atlstr.h>
|
|
#include <winnls.h>
|
|
#include <atlspriv.h>
|
|
|
|
//=======================================================================
|
|
//defines for SMTPMail module
|
|
//=======================================================================
|
|
|
|
//If overlapped I/O is desired, need 2.0 or greater
|
|
#define ATLSMTP_WSA_VERSION ATL_WINSOCK_VER
|
|
|
|
//The maximum number of characters on a SMTP line
|
|
#define ATLSMTP_MAX_LINE_LENGTH 1000
|
|
|
|
#define ATLSMTP_MAX_SERVER_NAME_LENGTH 256
|
|
|
|
//Encoding schemes
|
|
#define ATLSMTP_BASE64_ENCODE 0
|
|
#define ATLSMTP_UUENCODE 1
|
|
#define ATLSMTP_QP_ENCODE 2
|
|
|
|
//I/O Defines
|
|
#define ATLSMTP_READBUFFER_SIZE 4096
|
|
#define ATLSMTP_GET_LINES 100
|
|
|
|
|
|
//Miscellaneous defines
|
|
#define ATLSMTP_SEND_FILE 1
|
|
#define ATLSMTP_FORMAT_SMTP 8
|
|
|
|
#define ATLSMTP_RETCODE_LEN 3
|
|
|
|
|
|
#pragma pack(push,_ATL_PACKING)
|
|
namespace ATL
|
|
{
|
|
|
|
//=======================================================================
|
|
// Miscellaneous Utility Functions
|
|
//=======================================================================
|
|
//A list of recipients in a string must by separated by one
|
|
//of the following characters
|
|
inline BOOL AtlSmtpIsRecipientDelimiter(char ch) throw()
|
|
{
|
|
return (ch == ',' || ch == ';' || ch == ' ' || ch == '\0');
|
|
}
|
|
|
|
//Send data to hFile and wait for it to finish sending
|
|
inline BOOL AtlSmtpSendAndWait(HANDLE hFile, LPCSTR lpData, int nDataLength, LPOVERLAPPED pOverlapped) throw()
|
|
{
|
|
ATLASSERT(lpData != NULL);
|
|
ATLENSURE_RETURN_VAL(pOverlapped != NULL, FALSE);
|
|
|
|
DWORD dwWritten = 0, dwErr = 0;
|
|
int nRet = 0, nBufPos = 0;
|
|
|
|
//write all the data
|
|
do
|
|
{
|
|
//Write a chunk of data, offsetting the buffer and amount to write by what's already
|
|
//been written
|
|
nRet = WriteFile(hFile, (void*)(lpData+nBufPos), nDataLength-nBufPos, &dwWritten, pOverlapped);
|
|
if (!nRet && (dwErr = GetLastError()) != ERROR_IO_INCOMPLETE && dwErr != ERROR_IO_PENDING)
|
|
return FALSE;
|
|
|
|
//Get the result of the write operation (wait for it)
|
|
nRet = GetOverlappedResult(hFile, pOverlapped, &dwWritten, TRUE);
|
|
if (!nRet)
|
|
return FALSE;
|
|
|
|
//Need to update offsets when writing to a file
|
|
pOverlapped->Offset += dwWritten;
|
|
nBufPos += dwWritten;
|
|
|
|
} while (nBufPos < nDataLength);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//Read up to nDestLen bytes from hFile, keep reading while there's more data and there's
|
|
//room in the buffer
|
|
inline BOOL AtlSmtpReadData(__in HANDLE hFile, __out_ecount_part_z(*pnDestLen, *pnDestLen) LPSTR lpData, __inout int* pnDestLen, __in LPOVERLAPPED pOverlapped)
|
|
{
|
|
ATLASSERT(lpData != NULL);
|
|
ATLASSERT(pnDestLen != NULL);
|
|
ATLENSURE(pOverlapped != NULL);
|
|
|
|
DWORD dwRead = 0, dwErr = 0;
|
|
int nBufPos = 0;
|
|
do
|
|
{
|
|
//REad a chunk of data, offsetting the buffer and amount to read by what's already been read
|
|
int nRet = ReadFile(hFile, (void*)(lpData+nBufPos), (*pnDestLen)-nBufPos, &dwRead, pOverlapped);
|
|
if (!nRet && (dwErr = GetLastError()) != ERROR_MORE_DATA && dwErr != ERROR_IO_PENDING && dwErr != ERROR_IO_INCOMPLETE)
|
|
return FALSE;
|
|
|
|
//Get the result of the read operation (wait for it)
|
|
nRet = GetOverlappedResult(hFile, pOverlapped, &dwRead, TRUE);
|
|
if (!nRet)
|
|
return FALSE;
|
|
|
|
//Handle offsets when reading from a file
|
|
pOverlapped->Offset += dwRead;
|
|
nBufPos += dwRead;
|
|
} while (nBufPos < *pnDestLen && dwErr == ERROR_MORE_DATA);
|
|
*pnDestLen = nBufPos;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//Used in sending encoded data
|
|
//lpData is the data to be sent now
|
|
//lpPrev is a pointer to the buffer that the previous call was made on
|
|
//This allows the new buffer (lpData) to be filled while lpPrev is being sent
|
|
//If all the data in lpPrev had not finished sending, we complete the send and wait
|
|
inline BOOL AtlSmtpSendOverlapped(HANDLE hFile, LPCSTR lpData, int nDataLength, LPCSTR lpPrev, DWORD dwPrevLength, LPOVERLAPPED pOverlapped)
|
|
{
|
|
ATLASSERT(lpData != NULL);
|
|
ATLENSURE(pOverlapped != NULL);
|
|
|
|
DWORD dwWritten = 0, dwErr = 0, dwBufPos = 0;
|
|
int nRet = 0;
|
|
|
|
//Get the results of the previous call (if any)
|
|
if (lpPrev && (!GetOverlappedResult(hFile, pOverlapped, &dwWritten, FALSE) || dwWritten < dwPrevLength))
|
|
{
|
|
//If any error but IO_INCOMPLETE, return failure
|
|
if ((dwErr = GetLastError()) != ERROR_SUCCESS && dwErr != ERROR_IO_INCOMPLETE && dwErr != ERROR_IO_PENDING)
|
|
{
|
|
return FALSE;
|
|
}
|
|
//Finish writing lpPrev if we need to
|
|
while (dwBufPos < dwPrevLength)
|
|
{
|
|
//Get the result of the previous write (wait for it)
|
|
nRet = GetOverlappedResult(hFile, pOverlapped, &dwWritten, TRUE);
|
|
if (!nRet || (dwBufPos += dwWritten) == dwPrevLength)
|
|
{
|
|
if ((dwErr = GetLastError()) != ERROR_IO_INCOMPLETE && dwErr != ERROR_IO_PENDING)
|
|
break;
|
|
}
|
|
|
|
//If we are writing to a file, we need to update the offsets
|
|
pOverlapped->Offset += dwWritten;
|
|
if(dwBufPos>dwPrevLength)
|
|
{
|
|
/* shouldn't happen */
|
|
ATLASSERT(false);
|
|
break;
|
|
}
|
|
nRet = WriteFile(hFile, (void*)(lpPrev+dwBufPos), dwPrevLength-dwBufPos, &dwWritten, pOverlapped);
|
|
|
|
//If any error but IO_PENDING and IO_INCOMPLETE, break
|
|
if (!nRet && (dwErr = GetLastError()) != ERROR_IO_PENDING && dwErr != ERROR_IO_INCOMPLETE)
|
|
break;
|
|
}
|
|
if (dwBufPos < dwPrevLength)
|
|
return FALSE;
|
|
}
|
|
|
|
//Now that all the previous data has been sent, start sending the current data
|
|
nRet = WriteFile(hFile, (void*)lpData, nDataLength, &dwWritten, pOverlapped);
|
|
GetOverlappedResult(hFile, pOverlapped, &dwWritten, FALSE);
|
|
|
|
pOverlapped->Offset += dwWritten;
|
|
|
|
//If any error but IO_PENDING
|
|
if (!nRet && (dwErr = GetLastError()) != ERROR_IO_PENDING && dwErr != ERROR_IO_INCOMPLETE)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//Send a SMTP command and read the response
|
|
//return TRUE if it matches szResponse, FALSE otherwise
|
|
inline BOOL AtlSmtpSendAndCheck(__in HANDLE hFile, __in LPCSTR lpData, __in int nDataLength, __out_ecount_part(nMaxResponseLength, *pnResponseLength) LPSTR lpResponse, __out int* pnResponseLength, __in int nMaxResponseLength,
|
|
__in_z LPCSTR szResponse, __in LPOVERLAPPED pOverlapped) throw()
|
|
{
|
|
ATLASSERT(lpData != NULL);
|
|
ATLASSERT(lpResponse != NULL);
|
|
ATLASSERT(pnResponseLength != NULL);
|
|
|
|
BOOL bRet = AtlSmtpSendAndWait(hFile, lpData, nDataLength, pOverlapped);
|
|
if (bRet)
|
|
{
|
|
*pnResponseLength = nMaxResponseLength;
|
|
bRet = AtlSmtpReadData(hFile, lpResponse, pnResponseLength, pOverlapped);
|
|
}
|
|
if (!bRet || strncmp((char*)lpResponse, szResponse, ATLSMTP_RETCODE_LEN))
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
} // namespace ATL
|
|
#pragma pack(pop)
|
|
|
|
#endif // __ATLSMTPUTIL_H__
|