You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
637 lines
18 KiB
637 lines
18 KiB
// based on SMTP spec RFC 821
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <tchar.h>
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <wbemutil.h>
|
|
#include <ArrTempl.h>
|
|
#include <ErrorObj.h>
|
|
#include <strsafe.h>
|
|
|
|
#define SMTP_PORT 25
|
|
#define MAX_SMTP_BUFFER 0x4000 // 16K
|
|
#define MAX_SUBJECT_LINE 2048 // leave room for the encoding
|
|
#define MAX_USER_NAME 512
|
|
#define MAX_EXTRA_HEADER 1024
|
|
|
|
#define SMTP_OKAY 250 // doc'd as 'Requested mail action okay, completed'
|
|
#define INTERNAL_ERROR 554 // sorta fit in with the SMTP error codes
|
|
// doc'd as 'Transaction Failed' by the SMTP spec
|
|
|
|
#define HH_MAX_COMPUTERNAME_LENGTH 256 // because the system defined MAX_COMPUTERNAME_LENGTH isn't
|
|
|
|
#define ERROR_MESSAGE_SIZE 256
|
|
|
|
|
|
// returns true if dwRet is an SMTP error
|
|
bool IsSMTPError(DWORD dwRet)
|
|
{
|
|
return (dwRet >= 400);
|
|
}
|
|
|
|
|
|
// Helper functions
|
|
|
|
void SkipWhite(PSTR *ppS )
|
|
{
|
|
PSTR pS = *ppS;
|
|
|
|
while ( *pS && isspace(*pS) )
|
|
++pS;
|
|
|
|
*ppS = pS;
|
|
}
|
|
|
|
|
|
void SkipNonWhite(PSTR *ppS )
|
|
{
|
|
PSTR pS = *ppS;
|
|
|
|
while ( *pS && !isspace(*pS) )
|
|
++pS;
|
|
|
|
*ppS = pS;
|
|
}
|
|
|
|
|
|
// returns numeric reply code
|
|
// in general, anything >= 400 is bad.
|
|
// copies & converts reply message to messageBuf
|
|
int SMTPReceive(int Socket, WCHAR* messageBuf)
|
|
{
|
|
int nCode;
|
|
|
|
char *szBuffer = new char[MAX_SMTP_BUFFER];
|
|
if (szBuffer == NULL)
|
|
return INTERNAL_ERROR;
|
|
szBuffer[0] = '\0';
|
|
|
|
int nLen = recv( Socket, szBuffer, MAX_SMTP_BUFFER, 0);
|
|
if (nLen == SOCKET_ERROR)
|
|
{
|
|
int err = WSAGetLastError();
|
|
ERRORTRACE((LOG_ESS, "SMTPReceive failed: %d\n", err));
|
|
nCode = INTERNAL_ERROR;
|
|
|
|
}
|
|
else
|
|
{
|
|
szBuffer[nLen]=0;
|
|
if (1 != sscanf(szBuffer, " %d", &nCode))
|
|
nCode = INTERNAL_ERROR;
|
|
mbstowcs(messageBuf, szBuffer, ERROR_MESSAGE_SIZE);
|
|
messageBuf[ERROR_MESSAGE_SIZE] = L'\0';
|
|
}
|
|
|
|
if (szBuffer)
|
|
delete szBuffer;
|
|
|
|
return nCode;
|
|
}
|
|
|
|
// returns numeric reply code
|
|
// in general, anything >= 400 is bad.
|
|
DWORD SMTPTransactMailCommand(SOCKET Socket, char *cCommand)
|
|
{
|
|
DWORD dwError;
|
|
|
|
if (cCommand == NULL)
|
|
return INTERNAL_ERROR;
|
|
|
|
if(SOCKET_ERROR == send(Socket, cCommand, strlen(cCommand), 0))
|
|
{
|
|
int err = WSAGetLastError();
|
|
ERRORTRACE((LOG_ESS, "SMTPTransactMailCommand failed on command: %s (%d)\n", cCommand, err));
|
|
ErrorObj* pErrorObj = ErrorObj::GetErrorObj();
|
|
if (pErrorObj)
|
|
{
|
|
// so it gets truncated, it's long enough to tell what's happening.
|
|
WCHAR wcsCommand[256] = L"\0";
|
|
if (mbstowcs(wcsCommand, cCommand, 255) > 0)
|
|
{
|
|
wcsCommand[255] = L'\0';
|
|
if (wcslen(wcsCommand) >= 253)
|
|
StringCchCopyW(&wcsCommand[252], 4, L"...");
|
|
}
|
|
|
|
|
|
pErrorObj->ReportError(L"send", wcsCommand, NULL, err, true);
|
|
pErrorObj->Release();
|
|
}
|
|
|
|
dwError = INTERNAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
WCHAR messageBuf[ERROR_MESSAGE_SIZE +1] = L"\0";
|
|
|
|
dwError = SMTPReceive(Socket, messageBuf);
|
|
messageBuf[ERROR_MESSAGE_SIZE] = L'\0';
|
|
|
|
if(IsSMTPError(dwError))
|
|
{
|
|
ERRORTRACE((LOG_ESS, "SMTP command \"%s\" returned %d (%S)\n", cCommand, dwError, messageBuf));
|
|
|
|
ErrorObj* pErrorObj = ErrorObj::GetErrorObj();
|
|
if (pErrorObj)
|
|
{
|
|
// so it gets truncated, it's long enough to tell what's happening.
|
|
WCHAR wcsCommand[256] = L"\0";
|
|
if (mbstowcs(wcsCommand, cCommand, 255) > 0)
|
|
{
|
|
wcsCommand[255] = L'\0';
|
|
if (wcslen(wcsCommand) >= 253)
|
|
StringCchCopy(&wcsCommand[252], 4, L"...");
|
|
}
|
|
|
|
pErrorObj->ReportError(wcsCommand, NULL, messageBuf, dwError, false);
|
|
pErrorObj->Release();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
// returns 0 on success
|
|
// don't bother trying to make sense of the number otherwise
|
|
int SMTPConnect(char* szHost, SOCKET* pSocket)
|
|
{
|
|
SOCKET Socket = INVALID_SOCKET;
|
|
struct sockaddr_in Address;
|
|
struct hostent * HostEntry;
|
|
int Error = -1;
|
|
BOOL fSt = FALSE;
|
|
|
|
|
|
TCHAR cComputer[HH_MAX_COMPUTERNAME_LENGTH +2];
|
|
DWORD dwBuffSize= HH_MAX_COMPUTERNAME_LENGTH +1;
|
|
|
|
Socket = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (Socket == INVALID_SOCKET)
|
|
{
|
|
// fprintf(stderr, "Error creating socket = %d\n", GetLastError());
|
|
|
|
int err = WSAGetLastError();
|
|
ERRORTRACE((LOG_ESS, "Error creating socket = %d\n", err));
|
|
|
|
fSt = FALSE;
|
|
goto ex;
|
|
}
|
|
|
|
Address.sin_family = AF_INET;
|
|
Address.sin_port = 0;
|
|
Address.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
Error =
|
|
bind(
|
|
Socket,
|
|
(struct sockaddr *) &Address,
|
|
sizeof(Address));
|
|
|
|
if (Error)
|
|
{
|
|
int err = WSAGetLastError();
|
|
ERRORTRACE((LOG_ESS, "bind failed = %d\n", err));
|
|
fSt = FALSE;
|
|
goto ex;
|
|
}
|
|
|
|
Address.sin_family = AF_INET;
|
|
Address.sin_port = htons(SMTP_PORT);
|
|
|
|
HostEntry = gethostbyname(szHost);
|
|
if (HostEntry == NULL)
|
|
{
|
|
Error = WSAGetLastError();
|
|
ERRORTRACE((LOG_ESS, "unable to resolve host %s error = %d\n", szHost, Error));
|
|
ErrorObj* pErrorObj = ErrorObj::GetErrorObj();
|
|
if (pErrorObj)
|
|
{
|
|
WCHAR wcsHost[256] = L"\0";
|
|
if (mbstowcs(wcsHost, szHost, 255) > 0)
|
|
{
|
|
wcsHost[255] = L'\0';
|
|
if (wcslen(wcsHost) >= 253)
|
|
StringCchCopy(&wcsHost[252], 4, L"...");
|
|
}
|
|
|
|
pErrorObj->ReportError(L"gethostbyname", wcsHost, NULL, Error, true);
|
|
pErrorObj->Release();
|
|
}
|
|
|
|
fSt = FALSE;
|
|
goto ex;
|
|
}
|
|
else
|
|
{
|
|
Address.sin_addr.s_addr = *((unsigned long *) HostEntry->h_addr);
|
|
}
|
|
|
|
Error =
|
|
connect(
|
|
Socket,
|
|
(struct sockaddr *) &Address,
|
|
sizeof(Address));
|
|
|
|
if (Error)
|
|
{
|
|
int err = WSAGetLastError();
|
|
ERRORTRACE((LOG_ESS, "Error connecting to %s = %d\n", szHost, err));
|
|
ErrorObj* pErrorObj = ErrorObj::GetErrorObj();
|
|
if (pErrorObj)
|
|
{
|
|
WCHAR wcsHost[256] = L"\0";
|
|
if (mbstowcs(wcsHost, szHost, 255) > 0)
|
|
{
|
|
wcsHost[255] = L'\0';
|
|
if (wcslen(wcsHost) >= 253)
|
|
StringCchCopy(&wcsHost[252], 4, L"...");
|
|
}
|
|
|
|
pErrorObj->ReportError(L"connect", wcsHost, NULL, err, true);
|
|
pErrorObj->Release();
|
|
}
|
|
|
|
|
|
fSt = FALSE;
|
|
goto ex;
|
|
}
|
|
|
|
WCHAR messageBuf[ERROR_MESSAGE_SIZE +1] = L"\0";
|
|
|
|
Error = SMTPReceive(Socket, messageBuf);
|
|
messageBuf[ERROR_MESSAGE_SIZE] = L'\0';
|
|
|
|
if (!IsSMTPError(Error))
|
|
{
|
|
if (!GetComputerName(cComputer,&dwBuffSize))
|
|
{
|
|
ERRORTRACE((LOG_ESS, "GetComputerName failed! 0x%08X\n", GetLastError()));
|
|
return -1;
|
|
}
|
|
|
|
const int BufLen = 2*HH_MAX_COMPUTERNAME_LENGTH + 20;
|
|
char cMailCommand[BufLen];
|
|
StringCchCopyA(cMailCommand, BufLen, "HELO ");
|
|
#ifdef _UNICODE
|
|
char narrowcComputer[BufLen];
|
|
if (FAILED(StringCchPrintfA(narrowcComputer, BufLen, "%S", cComputer)))
|
|
return -1;
|
|
|
|
if (FAILED(StringCchCatA(cMailCommand, BufLen, narrowcComputer)))
|
|
return -1;
|
|
#else
|
|
if (FAILED(StringCchCatA(cMailCommand, BufLen, cComputer)))
|
|
return -1;
|
|
#endif
|
|
if (FAILED(StringCchCatA(cMailCommand, BufLen, "\r\n")))
|
|
return -1;
|
|
|
|
Error=SMTPTransactMailCommand(Socket, cMailCommand);
|
|
if(IsSMTPError(Error))
|
|
{
|
|
ErrorObj* pErrorObj = ErrorObj::GetErrorObj();
|
|
if (pErrorObj)
|
|
{
|
|
// so it gets truncated, it's long enough to tell what's happening.
|
|
WCHAR wcsCommand[256] = L"\0";
|
|
if (mbstowcs(wcsCommand, cMailCommand, 255) > 0)
|
|
{
|
|
wcsCommand[255] = L'\0';
|
|
if (wcslen(wcsCommand) >= 253)
|
|
StringCchCopyW(&wcsCommand[252], 4, L"...");
|
|
}
|
|
|
|
pErrorObj->ReportError(wcsCommand, NULL, messageBuf, Error, false);
|
|
pErrorObj->Release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fSt = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fSt = FALSE;
|
|
ERRORTRACE((LOG_ESS, "Error establishing SMTP connection (%d) (%S)\n", Error, messageBuf));
|
|
ErrorObj* pErrorObj = ErrorObj::GetErrorObj();
|
|
if (pErrorObj)
|
|
{
|
|
pErrorObj->ReportError(L"connect", NULL, messageBuf, Error, false);
|
|
pErrorObj->Release();
|
|
|
|
}
|
|
}
|
|
|
|
ex:
|
|
if(!fSt)
|
|
{
|
|
closesocket(Socket);
|
|
return Error;
|
|
}
|
|
else
|
|
{
|
|
*pSocket = Socket;
|
|
return NOERROR;
|
|
}
|
|
}
|
|
|
|
|
|
// returns SMTP reply code
|
|
DWORD SMTPDisconnect(SOCKET Socket)
|
|
{
|
|
DWORD dwError = SMTP_OKAY;
|
|
|
|
if (Socket != INVALID_SOCKET)
|
|
{
|
|
dwError=SMTPTransactMailCommand(Socket, "QUIT\r\n");
|
|
closesocket(Socket);
|
|
};
|
|
|
|
return(dwError);
|
|
}
|
|
|
|
LPSTR Months[] = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
|
LPSTR Days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
|
|
|
void GetTimeString(char *cTimeString,DWORD dwMaxSize)
|
|
{
|
|
SYSTEMTIME st;
|
|
|
|
GetSystemTime(&st);
|
|
|
|
StringCchPrintfA( cTimeString, dwMaxSize, "%s, %02d %s %4d %02d:%02d:%02d GMT",
|
|
Days[ st.wDayOfWeek ], st.wDay, Months[ st.wMonth], st.wYear, st.wHour, st.wMinute, st.wSecond);
|
|
}
|
|
|
|
|
|
// returns 0 upon success
|
|
// inputs may be zero length, but may not be NULL.
|
|
DWORD SMTPSendMailHeader(SOCKET Socket, char* szTo, char* szCc, char* szFrom, char* szSender, char* szReplyTo, char* szSubject, char* szHeaders)
|
|
{
|
|
// dang gone it! they went & made 'template' a keyword...
|
|
// const char templitt[] = "Date: %s\r\nTo: %s\r\nCc: %s\r\nFrom: %s via WMI auto-mailer\r\nReply-To: %s\r\nSubject: %s";
|
|
const char templitt[] = "Date: %s\r\nTo: %s\r\nCc: %s\r\nFrom: <%s>\r\nSender: <%s>\r\nReply-To: %s\r\nSubject: %s\r\nMIME-Version: 1.0\r\nContent-Type: multipart/mixed; boundary=\"- - =_HH_= - ---\"";
|
|
|
|
int bufLength = strlen(templitt) +strlen(szTo) +strlen(szCc)
|
|
+strlen(szFrom) +strlen(szSender) +strlen(szReplyTo)
|
|
+strlen(szSubject) +strlen(szHeaders)
|
|
+104; // to account for date string and for the trailing \r\n\r\n, and alittle fudge factor
|
|
|
|
char* pszOutputBuffer = new char[bufLength];
|
|
|
|
if (!pszOutputBuffer)
|
|
return INTERNAL_ERROR;
|
|
else
|
|
{
|
|
CDeleteMe<char> delbuf(pszOutputBuffer);
|
|
char cTimeString[100];
|
|
GetTimeString(cTimeString,100);
|
|
|
|
StringCchPrintfA(pszOutputBuffer, bufLength, templitt, cTimeString, szTo, szCc, szFrom, szSender, szReplyTo, szSubject);
|
|
|
|
if (strlen(szHeaders))
|
|
{
|
|
StringCchCatA(pszOutputBuffer, bufLength, "\r\n");
|
|
StringCchCatA(pszOutputBuffer, bufLength, szHeaders);
|
|
}
|
|
|
|
|
|
StringCchCatA(pszOutputBuffer, bufLength, "\r\n\r\n");
|
|
|
|
if (SOCKET_ERROR == send(Socket, pszOutputBuffer, strlen(pszOutputBuffer), 0))
|
|
{
|
|
int err = WSAGetLastError();
|
|
ERRORTRACE((LOG_ESS, "SMTPSendMailHeader failed (%d)\n", err));
|
|
return INTERNAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
return(NO_ERROR);
|
|
}
|
|
}
|
|
}
|
|
|
|
// returns 0 on success
|
|
// but ignores error returns from server (server returns error if it must relay recipients.
|
|
DWORD SMTPSendRecipients(SOCKET Socket, LPCSTR szRecipients)
|
|
{
|
|
char *tok;
|
|
DWORD dwError = SMTP_OKAY;
|
|
int bufLength = strlen(szRecipients) +1;
|
|
char* pParseBuffer = new char[bufLength];
|
|
|
|
if (!pParseBuffer)
|
|
dwError = INTERNAL_ERROR;
|
|
else
|
|
{
|
|
char szBuffer[1024];
|
|
CDeleteMe<char> delbuf(pParseBuffer);
|
|
|
|
StringCchCopyA(pParseBuffer, bufLength, szRecipients);
|
|
|
|
tok=strtok(pParseBuffer," ;,");
|
|
while (tok!=NULL)
|
|
{
|
|
DWORD dwErrInternal;
|
|
|
|
if (FAILED(StringCchPrintfA(szBuffer, 1024, "RCPT TO:<%s>\r\n",tok)))
|
|
return INTERNAL_ERROR;
|
|
|
|
dwErrInternal=SMTPTransactMailCommand(Socket, szBuffer);
|
|
if(IsSMTPError(dwErrInternal))
|
|
{
|
|
if ((dwErrInternal == 550) || (dwErrInternal == 551))
|
|
ERRORTRACE((LOG_ESS, "Ignoring RCPT Error, will attempt to send mail.\n"));
|
|
else
|
|
{
|
|
dwError = dwErrInternal;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
tok=strtok(NULL," ;,");
|
|
}
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
// returns 0 on success, SMTP numeric reply code otherwise
|
|
DWORD SMTPSendText(SOCKET Socket, char* szTo, char* szCc, char* szFrom, char* szSender, char* szReplyTo, char* szSubject,
|
|
char* szHeaders, char *szText)
|
|
{
|
|
DWORD dwError;
|
|
int nLen;
|
|
int nSizeToSend;
|
|
char *tmp;
|
|
|
|
dwError=SMTPTransactMailCommand(Socket, "DATA\r\n");
|
|
if (IsSMTPError(dwError))
|
|
return dwError;
|
|
|
|
dwError=SMTPSendMailHeader(Socket, szTo, szCc, szFrom, szSender, szReplyTo, szSubject, szHeaders);
|
|
if (IsSMTPError(dwError))
|
|
return dwError;
|
|
|
|
char headerFake[] = "\r\n--- - =_HH_= - ---\r\nContent-Type: text/plain; charset=\"us-ascii\"\r\nContent-Transfer-Encoding: 7bit\r\n\r\n";
|
|
if (SOCKET_ERROR == send(Socket, headerFake, strlen(headerFake), 0))
|
|
{
|
|
int err = WSAGetLastError();
|
|
ERRORTRACE((LOG_ESS, "SMTPSendText failed (%d)\n", err));
|
|
|
|
return INTERNAL_ERROR;
|
|
}
|
|
|
|
nLen=strlen(szText);
|
|
tmp=szText;
|
|
|
|
while (nLen>0)
|
|
{
|
|
nSizeToSend=min(1000,nLen);
|
|
|
|
if (SOCKET_ERROR == send(Socket, tmp, nSizeToSend, 0))
|
|
{
|
|
int err = WSAGetLastError();
|
|
ERRORTRACE((LOG_ESS, "SMTPSendText failed (%d)\n", err));
|
|
|
|
return INTERNAL_ERROR;
|
|
}
|
|
|
|
nLen-=nSizeToSend;
|
|
tmp+=nSizeToSend;
|
|
}
|
|
|
|
char trailerFake[] = "\r\n\r\n--- - =_HH_= - -----\r\n\r\n";
|
|
if (SOCKET_ERROR == send(Socket, trailerFake, strlen(trailerFake), 0))
|
|
{
|
|
int err = WSAGetLastError();
|
|
ERRORTRACE((LOG_ESS, "SMTPSendText failed (%d)\n", err));
|
|
|
|
return INTERNAL_ERROR;
|
|
}
|
|
|
|
dwError=SMTPTransactMailCommand(Socket, "\r\n.\r\n");
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
// uses SMTP verification to determine whether
|
|
// recipient actually exists (is known to this server)
|
|
// returns return value from SMTPTransactMailCommand
|
|
//-->> will return success code if passed a NULL buffer
|
|
DWORD CheckRecipients(SOCKET Socket2me, char* szRecipients)
|
|
{
|
|
DWORD dwError = SMTP_OKAY;
|
|
int bufLength = strlen(szRecipients) +1;
|
|
char* pParseBuffer = new char[bufLength];
|
|
|
|
if (!pParseBuffer)
|
|
dwError = INTERNAL_ERROR;
|
|
else
|
|
{
|
|
CDeleteMe<char> delbuf(pParseBuffer);
|
|
char *tok;
|
|
char szBuffer[1024];
|
|
|
|
StringCchCopyA(pParseBuffer, bufLength, szRecipients);
|
|
|
|
tok=strtok(pParseBuffer," ;,");
|
|
while (tok!=NULL)
|
|
{
|
|
if (FAILED(StringCchPrintfA(szBuffer, 1024, "VRFY %s\r\n",tok)))
|
|
return INTERNAL_ERROR;
|
|
|
|
dwError=SMTPTransactMailCommand(Socket2me, szBuffer);
|
|
if(IsSMTPError(dwError))
|
|
break;
|
|
|
|
tok=strtok(NULL," ;,");
|
|
}
|
|
}
|
|
|
|
// hack to disable error returns
|
|
// some servers don't handle VRFY
|
|
dwError = SMTP_OKAY;
|
|
return dwError;
|
|
|
|
}
|
|
|
|
// returns zero upon success.
|
|
DWORD SMTPSend(char* szServer, char* szTo, char* szCc, char* szBcc, char* szFrom, char* szSender,
|
|
char* szReplyTo, char* szSubject, char* szHeaders, char *szText)
|
|
{
|
|
DWORD dwError = -1;
|
|
SOCKET Socket = INVALID_SOCKET;
|
|
|
|
char szFromBuffer[1024];
|
|
if (FAILED(StringCchPrintfA(szFromBuffer, 1024, "MAIL FROM: <%s>\r\n",szFrom)))
|
|
return INTERNAL_ERROR;
|
|
|
|
// each of the functions below do their own error reporting to the log
|
|
if ( (0 == SMTPConnect(szServer, &Socket)) &&
|
|
|
|
!IsSMTPError(CheckRecipients(Socket, szTo)) &&
|
|
!IsSMTPError(CheckRecipients(Socket, szCc)) &&
|
|
!IsSMTPError(CheckRecipients(Socket, szBcc)) &&
|
|
|
|
!IsSMTPError(SMTPTransactMailCommand(Socket, szFromBuffer)) &&
|
|
|
|
!IsSMTPError(SMTPSendRecipients(Socket, szTo)) &&
|
|
!IsSMTPError(SMTPSendRecipients(Socket, szCc)) &&
|
|
!IsSMTPError(SMTPSendRecipients(Socket, szBcc)) &&
|
|
|
|
!IsSMTPError(SMTPSendText(Socket, szTo, szCc, szFrom, szSender, szReplyTo, szSubject, szHeaders, szText)) )
|
|
{
|
|
dwError = 0;
|
|
}
|
|
|
|
DWORD dwDebugError;
|
|
dwDebugError=SMTPDisconnect(Socket);
|
|
|
|
if(IsSMTPError(dwDebugError))
|
|
{
|
|
// If disconnect failed log a message, but don't interfere with
|
|
// operation
|
|
ERRORTRACE((LOG_ESS, "SMTPDisconnect returned %d\n", dwDebugError));
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
// test harness
|
|
//void main()
|
|
//{
|
|
// WSADATA WsaData;
|
|
// int Error = WSAStartup (0x101, &WsaData);
|
|
//
|
|
// if (Error == SOCKET_ERROR)
|
|
// {
|
|
// fprintf(stderr, "Error in WSAStartup = %d\n", GetLastError());
|
|
// return;
|
|
// }
|
|
//
|
|
// SMTPSend("smarthost", "[email protected]", "[email protected]", "subject", "Text");
|
|
// /*
|
|
// SOCKET Socket;
|
|
// SMTPConnect("smarthost", &Socket);
|
|
// SMTPDisconnect(Socket);
|
|
// */
|
|
//}
|