317 lines
8.7 KiB
C++
317 lines
8.7 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1995
|
|
//
|
|
// File: smtp.cxx
|
|
//
|
|
// Contents: Contains the command to send SMTP mail
|
|
//
|
|
// Stolen from KrisK's mail.exe tool.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "headers.hxx"
|
|
|
|
#include <iostream.h>
|
|
#include <winsock2.h>
|
|
|
|
HRESULT
|
|
CScriptHost::SendSMTPMail(BSTR bstrFrom,
|
|
BSTR bstrTo,
|
|
BSTR bstrCC,
|
|
BSTR bstrSubject,
|
|
BSTR bstrMessage,
|
|
BSTR bstrSMTPHost,
|
|
long *plError)
|
|
{
|
|
char achRecvBuf[2048];
|
|
unsigned short port = 25;
|
|
struct sockaddr_in Ser;
|
|
struct hostent * hp;
|
|
WSADATA wsaData;
|
|
SOCKET conn_socket = INVALID_SOCKET;
|
|
int iRet;
|
|
int iLen;
|
|
char achSendBuf[1024];
|
|
char * pch;
|
|
char * aszToList[30];
|
|
int cToList = 0;
|
|
char * aszCCList[30];
|
|
int cCCList = 0;
|
|
SYSTEMTIME stUT;
|
|
int i;
|
|
|
|
ANSIString szFrom(bstrFrom);
|
|
ANSIString szTo(bstrTo);
|
|
ANSIString szCC(bstrCC);
|
|
ANSIString szSubject(bstrSubject);
|
|
ANSIString szMessage(bstrMessage);
|
|
ANSIString szSMTPHost(bstrSMTPHost);
|
|
|
|
// ************** Parse the ToList into individual recipients
|
|
pch = szTo;
|
|
|
|
while (*pch && cToList < 30)
|
|
{
|
|
// Strip leading spaces from recipient name and terminate preceding
|
|
// name string.
|
|
if (isspace(*pch))
|
|
{
|
|
*pch=0;
|
|
pch++;
|
|
}
|
|
// Add a name to the array and increment the number of recipients.
|
|
else
|
|
{
|
|
aszToList[cToList++] = pch;
|
|
|
|
// Move beginning of string to next name in ToList.
|
|
do
|
|
{
|
|
pch++;
|
|
} while (isgraph(*pch));
|
|
}
|
|
}
|
|
|
|
// Parse the CCList into individual recipients
|
|
pch = szCC;
|
|
|
|
// Parse CCList into rgRecipDescStruct.
|
|
while (*pch && cCCList < 30)
|
|
{
|
|
// Strip leading spaces from recipient name and terminate preceding
|
|
// name string.
|
|
if (isspace(*pch))
|
|
{
|
|
*pch=0;
|
|
pch++;
|
|
}
|
|
// Add a name to the array and increment the number of recipients.
|
|
else
|
|
{
|
|
aszCCList[cCCList++] = pch;
|
|
|
|
// Move beginning of string to next name in CCList.
|
|
do
|
|
{
|
|
pch++;
|
|
} while (isgraph(*pch));
|
|
}
|
|
}
|
|
|
|
// ************** Initialize Windows Sockets
|
|
|
|
// BUGBUG -- Make error return code meaningful
|
|
|
|
iRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
if (iRet != 0)
|
|
{
|
|
*plError = iRet;
|
|
return S_OK;
|
|
}
|
|
|
|
hp = gethostbyname(szSMTPHost);
|
|
if (hp == NULL)
|
|
goto WSAError;
|
|
|
|
memset(&Ser,0,sizeof(Ser));
|
|
memcpy(&(Ser.sin_addr),hp->h_addr,hp->h_length);
|
|
|
|
Ser.sin_family = hp->h_addrtype;
|
|
Ser.sin_port = htons(port);
|
|
|
|
// Open a socket
|
|
conn_socket = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (conn_socket == INVALID_SOCKET)
|
|
goto WSAError;
|
|
|
|
// ************** Connect to the SMTP host
|
|
|
|
iRet = connect(conn_socket, (struct sockaddr*)&Ser, sizeof(Ser));
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
// Get the server's initial response
|
|
iRet = recv(conn_socket, achRecvBuf, sizeof(achRecvBuf), 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
// We expect code 220: "Service Ready"
|
|
if (strncmp(achRecvBuf, "220", 3) != 0)
|
|
goto ACKError;
|
|
|
|
// ************** Send the mail command
|
|
|
|
iLen = wsprintfA(achSendBuf, "MAIL FROM: <%s>\r\n", szFrom);
|
|
iRet = send(conn_socket, achSendBuf, iLen, 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
iRet = recv(conn_socket, achRecvBuf, sizeof(achRecvBuf), 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
// We expect code 250: "Requested mail action OK, completed"
|
|
if (strncmp(achRecvBuf, "250", 3) != 0)
|
|
goto ACKError;
|
|
|
|
// ************** Send the recipient list (combination of TO and CC)
|
|
|
|
for (i = 0; i < cToList; i++)
|
|
{
|
|
iLen = wsprintfA(achSendBuf, "RCPT TO: <%s>\r\n", aszToList[i]);
|
|
|
|
iRet = send(conn_socket, achSendBuf, iLen, 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
iRet = recv(conn_socket, achRecvBuf, sizeof(achRecvBuf), 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
// We expect code 250: "Requested mail action OK, completed"
|
|
if (strncmp(achRecvBuf, "250", 3) != 0)
|
|
goto ACKError;
|
|
}
|
|
|
|
for (i = 0; i < cCCList; i++)
|
|
{
|
|
iLen = wsprintfA(achSendBuf, "RCPT TO: <%s>\r\n", aszCCList[i]);
|
|
|
|
iRet = send(conn_socket, achSendBuf, iLen, 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
iRet = recv(conn_socket, achRecvBuf, sizeof(achRecvBuf), 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
// We expect code 250: "Requested mail action OK, completed"
|
|
if (strncmp(achRecvBuf, "250", 3) != 0)
|
|
goto ACKError;
|
|
}
|
|
|
|
// ************** Send the mail headers
|
|
|
|
iLen = wsprintfA(achSendBuf, "DATA\r\n");
|
|
iRet = send(conn_socket, achSendBuf, iLen, 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
iRet = recv(conn_socket, achRecvBuf, sizeof(achRecvBuf), 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
// We expect code 354: "Start mail input; End with ."
|
|
if (strncmp(achRecvBuf, "354", 3) != 0)
|
|
goto ACKError;
|
|
|
|
GetSystemTime(&stUT);
|
|
|
|
GetDateFormatA(LOCALE_NEUTRAL,
|
|
0,
|
|
&stUT,
|
|
"dd MMM yy",
|
|
achRecvBuf,
|
|
sizeof(achRecvBuf));
|
|
|
|
wsprintfA(achSendBuf,
|
|
"Date: %s %02d:%02d UT\r\n",
|
|
achRecvBuf,
|
|
stUT.wHour,
|
|
stUT.wMinute);
|
|
|
|
iRet = send(conn_socket, achSendBuf, strlen(achSendBuf), 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
wsprintfA(achSendBuf, "From: <%s>\r\n", szFrom);
|
|
|
|
wsprintfA(&achSendBuf[strlen(achSendBuf)], "Subject: %s\r\n", szSubject);
|
|
|
|
wsprintfA(&achSendBuf[strlen(achSendBuf)], "To: ");
|
|
|
|
for (i = 0; i < cToList; i++)
|
|
{
|
|
wsprintfA(&achSendBuf[strlen(achSendBuf)],
|
|
"<%s>%s",
|
|
aszToList[i],
|
|
(i == cToList-1) ? "\r\n" : ",\r\n ");
|
|
}
|
|
|
|
if (cCCList > 0)
|
|
{
|
|
wsprintfA(&achSendBuf[strlen(achSendBuf)], "cc: ", szFrom);
|
|
|
|
for (i = 0; i < cCCList; i++)
|
|
{
|
|
wsprintfA(&achSendBuf[strlen(achSendBuf)],
|
|
"<%s>%s",
|
|
aszCCList[i],
|
|
(i == cCCList-1) ? "\r\n" : ",\r\n ");
|
|
}
|
|
}
|
|
|
|
wsprintfA(&achSendBuf[strlen(achSendBuf)], "Reply-To: <%s>\r\n\r\n", szFrom);
|
|
|
|
/*
|
|
BUGBUG -- Perhaps support HTML formatted mail in the future?
|
|
if ( html )
|
|
str += "MIME-Version: 1.0\r\nContent-Type: text/html;\r\n charset=\"iso-8859-1\"\r\nSUBJECT: "+ title + "\r\n\r\n"+ message +"\r\n.\r\n";
|
|
*/
|
|
|
|
|
|
iRet = send(conn_socket, achSendBuf, strlen(achSendBuf), 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
// ************** Send the message body
|
|
|
|
iRet = send(conn_socket, szMessage, strlen(szMessage), 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
// ************** Close the connection
|
|
|
|
strcpy(achSendBuf, "\r\n.\r\n");
|
|
|
|
iRet = send(conn_socket, achSendBuf, strlen(achSendBuf), 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
iRet = recv(conn_socket, achRecvBuf, sizeof(achRecvBuf), 0);
|
|
if (iRet == SOCKET_ERROR)
|
|
goto WSAError;
|
|
|
|
// We expect code 250: "Requested mail action OK, completed"
|
|
if (strncmp(achRecvBuf, "250", 3) != 0)
|
|
goto ACKError;
|
|
|
|
|
|
strcpy(achSendBuf, "QUIT\r\n");
|
|
|
|
send(conn_socket, achSendBuf, strlen(achSendBuf), 0);
|
|
|
|
Cleanup:
|
|
if (conn_socket != INVALID_SOCKET)
|
|
{
|
|
closesocket(conn_socket);
|
|
}
|
|
|
|
WSACleanup();
|
|
|
|
return S_OK;
|
|
|
|
ACKError:
|
|
// BUGBUG -- Preserve entire string that was returned
|
|
achRecvBuf[3] = '\0';
|
|
*plError = atoi(achRecvBuf);
|
|
goto Cleanup;
|
|
|
|
WSAError:
|
|
*plError = WSAGetLastError();
|
|
|
|
goto Cleanup;
|
|
}
|