windows-nt/Source/XPSP1/NT/shell/ext/webcheck/smtp.cpp
2020-09-26 16:20:57 +08:00

304 lines
6.7 KiB
C++

//
// SMTP - Simple Mail Transfer Protocol Code
//
// Implements sends mail using SMTP RFC 821.
// Julian Jiggins, 12 January 1997
//
#include "private.h"
#include <winsock.h>
#define TF_THISMODULE TF_MAILAGENT
#define IS_DIGIT(ch) InRange(ch, TEXT('0'), TEXT('9'))
//
// Function prototypes for this module
//
SOCKET Connect(char *host, char *port);
#define READ_BUF_LEN 512
//
// Read all you can from a socket
//
void Read(SOCKET sock, char * readBuffer, int bufLen)
{
int numRead;
int totalRead = 0;
do
{
numRead = recv(sock, readBuffer+totalRead, bufLen, 0);
totalRead += numRead;
}
while (0);
// while (numRead > 0);
//
// NULL terminate read string
//
readBuffer[totalRead] = 0;
}
//
// Send a string specifying an SMTP command and read in response, returning
// TRUE if it is the one expected.
// Note the SMTP protocol is designed such that only the 1 character of the
// response need be checked, but we check for the exact response (mostly cause
// I just read that bit in the RFC)
//
BOOL SendAndExpect(SOCKET sock, char * sendBuffer, char * szExpect)
{
char readBuffer[READ_BUF_LEN];
int len;
int numSent;
//
// Send string to socket
//
numSent = send(sock, sendBuffer, lstrlenA(sendBuffer), 0);
if (numSent == SOCKET_ERROR)
{
DBG_WARN("Error on send");
return FALSE;
}
//
// Now read in response
//
Read(sock, readBuffer, READ_BUF_LEN);
DBG2("Sent: %s", sendBuffer);
DBG2("Read: %s", readBuffer);
//
// Expect beginning of response to contain szExpect string
//
len = lstrlenA(szExpect);
if (CompareStringA(LOCALE_SYSTEM_DEFAULT, 0,
readBuffer, len, szExpect, len) == 2)
{
return TRUE;
}
else
{
return FALSE;
}
}
#define SMTP_221 "221"
#define SMTP_250 "250"
#define SMTP_354 "354"
#define SMTP_EOM "\r\n.\r\n"
//
// Carry out SMTP negotiation
//
BOOL SMTPSendEmail(SOCKET sock, char * szToAddress, char * szFromAddress, char *szMessage)
{
char sendBuffer[256];
char readBuffer[READ_BUF_LEN];
BOOL b = TRUE;
int r, len;
//
// Read the opening response
//
Read(sock, readBuffer, sizeof(readBuffer));
DBG(readBuffer);
//
// say Hello and specify my domain
//
b = SendAndExpect(sock, "HELO ActiveDesktop\r\n", SMTP_250);
if (!b) goto done;
//
// First special sender in MAIL command
//
wnsprintfA(sendBuffer, ARRAYSIZE(sendBuffer), "MAIL FROM:<%s>\r\n",
szFromAddress);
b = SendAndExpect(sock, sendBuffer, SMTP_250);
if (!b) goto done;
//
// Now specify recipient(s)
//
wnsprintfA(sendBuffer, ARRAYSIZE(sendBuffer), "RCPT TO:<%s>\r\n",
szToAddress);
b = SendAndExpect(sock, sendBuffer, SMTP_250);
if (!b) goto done;
//
// Now send DATA command
//
b = SendAndExpect(sock, "DATA\r\n", SMTP_354);
if (!b) goto done;
//
// Now send mail message
//
len = lstrlenA(szMessage);
r = send(sock, szMessage, len, 0);
ASSERT(r != SOCKET_ERROR);
ASSERT(r == len);
//
// Specify end of message with single period.
//
b = SendAndExpect(sock, SMTP_EOM, SMTP_250);
if (!b) goto done;
//
// Say goodbye
//
b = SendAndExpect(sock, "QUIT\r\n", SMTP_221);
done:
return b;
}
//
// Main entry point -
// start winsock dll,
// connect to socket,
// and negotiate transfer
//
SMTPSendMessage(char * szServer, char * szToAddress, char * szFromAddress, char * szMessage)
{
int err;
SOCKET sock;
BOOL b = FALSE;
WSADATA wsaData;
//
// Init the winsock dll specifying which version we want.
//
err = WSAStartup((WORD)0x0101, &wsaData);
if (err)
{
DBG_WARN("WinSock startup error");
return FALSE;
}
DBG("WinSock successfully started");
//
// Actually form the socket connection to the host on port 25
//
sock = Connect(szServer, "25");
if (sock != 0)
{
DBG("Connected");
b = SMTPSendEmail(sock, szToAddress, szFromAddress, szMessage);
}
//
// Done with winsock dll for now
//
WSACleanup();
return b;
}
#ifdef TEST
int
main(int argc, char * argv[])
{
char szMessage[1024];
BOOL b;
//
// Build message
//
lstrcpy(szMessage, "Subject: Subscription Updated: CNN Interactive\r\n");
lstrcat(szMessage, "Your subscription to CNN Interactive Subscription has been updated\r\n\r\n");
lstrcat(szMessage, "To view the subscription offline, just click here: ");
lstrcat(szMessage, "http://www.cnn.com\r\n");
lstrcat(szMessage, "\r\nThis message was sent by the IE4.0 Information Delivery Agent\r\n");
lstrcat(szMessage, "\r\n\r\n\r\nDoes this look okay guys? Julian.");
b = SMTPSendMessage("saranac", "joepe@microsoft.com", szMessage);
if (b)
DBG("Sent mail successfully");
else
DBG("Couldn't send email");
return 0;
}
#endif
SOCKET
Connect(char *host, char *port)
{
struct sockaddr_in sockaddress;
DWORD err;
SOCKET sock, connectresult;
//
// Get the socket address
//
if(IS_DIGIT(*host))
sockaddress.sin_addr.s_addr=inet_addr(host);
else
{
struct hostent *hp;
if((hp=gethostbyname(host))==NULL)
{
DBG_WARN2("Unknown host %s", host);
return 0;
}
memcpy(&sockaddress.sin_addr, hp->h_addr, sizeof(sockaddress.sin_addr));
}
//
// Get the port address
//
if(IS_DIGIT(*port))
sockaddress.sin_port=htons((USHORT)StrToIntA(port));
else
{
DBG_WARN("The port should be a number");
return 0;
}
sockaddress.sin_family=AF_INET;
//
// Create a stream style socket
//
if((sock=socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
DBG_WARN("socket error");
DBG("Trying to connect");
connectresult=connect(sock,(struct sockaddr *) &sockaddress, sizeof(sockaddress));
if (connectresult == SOCKET_ERROR)
{
switch(err = WSAGetLastError())
{
case WSAECONNREFUSED:
DBG_WARN("ERROR - CONNECTION REFUSED.");
break;
case WSAENETUNREACH:
DBG_WARN("ERROR - THE NETWORK IS NOT REACHABLE FROM THIS HOST.");
break;
case WSAEINVAL:
DBG_WARN("ERROR - The socket is not already bound to an address.");
break;
case WSAETIMEDOUT:
DBG_WARN("ERROR - Connection timed out.");
break;
default:
DBG_WARN2("Couldn't connect %d", err);
break;
}
closesocket(sock);
return 0;
}
return sock;
}