Files
Work/smtp/SMTP.CPP
2024-08-07 09:16:27 -04:00

345 lines
12 KiB
C++

#include <smtp/smtp.hpp>
#include <socket/hostent.hpp>
#include <socket/servent.hpp>
SMTPClient::SMTPClient(void)
: mSpace(" ")
{
createCmds();
}
SMTPClient::~SMTPClient()
{
mSMTPControl.destroy();
}
BOOL SMTPClient::open(const String &hostName)
{
HostEnt hostEntry;
ServEnt serverEntry;
Block<String> responseLines;
INETSocketAddress internetSocketAddress;
if(hostName.isNull())return FALSE;
if(mSMTPControl.isConnected())mSMTPControl.destroy();
message(String("trying ")+hostName+String("..."));
if(!mWSASystem.isInitialized()){message("WINSOCK initialization failure.");return FALSE;}
InternetAddress internetAddress(hostName);
if(!internetAddress.isZero()){if(!hostEntry.hostByAddress(internetAddress)){message(String("no DNS entry for ")+hostName+String("."));return FALSE;}}
else if(!hostEntry.hostByName(hostName)){message(String("no DNS entry for ")+hostName+String("."));return FALSE;}
if(!internetAddress.isZero()){if(!hostEntry.hostByAddress(internetAddress)){message(String("no DNS entry for ")+hostName);return FALSE;}}
else if(!hostEntry.hostByName(hostName)){message(String("no DNS entry for ")+hostName);return FALSE;}
message(String("connect...")+String("'")+hostEntry.hostName()+String("' (")+(String)(hostEntry.addresses())[0]+String(")"));
internetSocketAddress.internetAddress((hostEntry.addresses())[0]);
if(serverEntry.serviceByName("smtp","tcp"))
{
if(!mSMTPControl.create()){message("unable to create socket.");return FALSE;}
internetSocketAddress.family(PF_INET);
internetSocketAddress.port(serverEntry.port());
}
else
{
if(!mSMTPControl.create()){message("unable to create socket.");return FALSE;}
internetSocketAddress.family(PF_INET);
internetSocketAddress.port(htons(SMTPPort));
}
if(!mSMTPControl.connect(internetSocketAddress)){message("unable to connect to smtp server");return FALSE;}
mSMTPControl.getSocketName(internetSocketAddress);
if(!mSMTPControl.isConnected())return FALSE;
if(!mSMTPControl.receive(responseLines)||!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckConnect))
{
mSMTPControl.destroy();
return FALSE;
}
return TRUE;
}
BOOL SMTPClient::helo(const String &domainName)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected()||domainName.isNull())return FALSE;
controlData=mSMTPCmds[Helo];
controlData+=mSpace;
controlData+=domainName;
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckHelo))return FALSE;
return TRUE;
}
BOOL SMTPClient::quit(void)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected())return FALSE;
controlData=mSMTPCmds[Quit];
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckQuit))return FALSE;
return TRUE;
}
BOOL SMTPClient::mail(const String &reversePath)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected()||reversePath.isNull())return FALSE;
controlData=mSMTPCmds[Mail];
controlData+=mSpace;
controlData+=mSMTPCmds[From];
controlData+=reversePath;
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckMail))return FALSE;
return TRUE;
}
BOOL SMTPClient::rcpt(const String &forwardPath)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected()||forwardPath.isNull())return FALSE;
controlData=mSMTPCmds[Recipient];
controlData+=mSpace;
controlData+=mSMTPCmds[To];
controlData+=forwardPath;
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckRecipient))return FALSE;
return TRUE;
}
BOOL SMTPClient::data(const Block<String> &mailData)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected()||!mailData.size())return FALSE;
controlData=mSMTPCmds[Data];
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckData))return FALSE;
for(int lineIndex=0;lineIndex<mailData.size();lineIndex++)mSMTPControl.send(((Block<String>&)mailData)[lineIndex]);
mSMTPControl.send(".");
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckData))return FALSE;
return TRUE;
}
BOOL SMTPClient::verify(const String &forwardPath)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected()||forwardPath.isNull())return FALSE;
controlData=mSMTPCmds[Verify];
controlData+=mSpace;
controlData+=forwardPath;
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckVerify))return FALSE;
return TRUE;
}
BOOL SMTPClient::expand(const String &mailList)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected()||mailList.isNull())return FALSE;
controlData=mSMTPCmds[Expand];
controlData+=mSpace;
controlData+=mailList;
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckExpand))return FALSE;
return TRUE;
}
BOOL SMTPClient::send(const String &reversePath)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected()||reversePath.isNull())return FALSE;
controlData=mSMTPCmds[Send];
controlData+=mSpace;
controlData+=mSMTPCmds[From];
controlData+=reversePath;
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckSend))return FALSE;
return TRUE;
}
BOOL SMTPClient::sendOrMail(const String &reversePath)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected()||reversePath.isNull())return FALSE;
controlData=mSMTPCmds[SendOrMail];
controlData+=mSpace;
controlData+=mSMTPCmds[From];
controlData+=reversePath;
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckSendOrMail))return FALSE;
return TRUE;
}
BOOL SMTPClient::sendAndMail(const String &reversePath)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected()||reversePath.isNull())return FALSE;
controlData=mSMTPCmds[SendAndMail];
controlData+=mSpace;
controlData+=mSMTPCmds[From];
controlData+=reversePath;
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckSendAndMail))return FALSE;
return TRUE;
}
BOOL SMTPClient::reset(void)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected())return FALSE;
controlData=mSMTPCmds[Reset];
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckReset))return FALSE;
return TRUE;
}
BOOL SMTPClient::help(const String &commandName)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected())return FALSE;
controlData=mSMTPCmds[Help];
if(!commandName.isNull())
{
controlData+=mSpace;
controlData+=commandName;
}
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckHelp))return FALSE;
return TRUE;
}
BOOL SMTPClient::noop(void)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected())return FALSE;
controlData=mSMTPCmds[Noop];
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckNoop))return FALSE;
return TRUE;
}
BOOL SMTPClient::turn(void)
{
String controlData;
Block<String> responseLines;
if(!mSMTPControl.isConnected())return FALSE;
controlData=mSMTPCmds[Turn];
if(!putControlData(controlData,FALSE))return FALSE;
if(!mSMTPControl.receive(responseLines))return FALSE;
message(responseLines);
if(!responseLines.size()||!isInResponse(responseLines.size()>1?responseLines[0].betweenString(0,'-'):responseLines[0].betweenString(0,' '),SMTPResponse::AckTurn))return FALSE;
return TRUE;
}
void SMTPClient::createCmds(void)
{
mSMTPCmds.remove();
mSMTPCmds.insert(&String("HELO"));
mSMTPCmds.insert(&String("QUIT"));
mSMTPCmds.insert(&String("MAIL"));
mSMTPCmds.insert(&String("FROM:"));
mSMTPCmds.insert(&String("RCPT"));
mSMTPCmds.insert(&String("TO:"));
mSMTPCmds.insert(&String("DATA"));
mSMTPCmds.insert(&String("VRFY"));
mSMTPCmds.insert(&String("EXPN"));
mSMTPCmds.insert(&String("SEND"));
mSMTPCmds.insert(&String("SOML"));
mSMTPCmds.insert(&String("SAML"));
mSMTPCmds.insert(&String("TURN"));
mSMTPCmds.insert(&String("RSET"));
mSMTPCmds.insert(&String("HELP"));
mSMTPCmds.insert(&String("NOOP"));
}
WORD SMTPClient::putControlData(const String &stringData,WORD waitForResponse)
{
if(!mSMTPControl.isConnected())return FALSE;
if(!mSMTPControl.send(stringData))
{
mSMTPControl.destroy();
String errorString(String("error sending '")+stringData+String("' to SMTP server."));
message(errorString);
errorString+="\n";
::OutputDebugString(errorString);
return FALSE;
}
if(waitForResponse&&!getControlData())
{
mSMTPControl.destroy();
String errorString(String("error reading result of '")+stringData+String("' command from NNTP server."));
message(errorString);
errorString+="\n";
::OutputDebugString(errorString);
return FALSE;
}
return TRUE;
}
WORD SMTPClient::getControlData(void)
{
Block<String> responseStrings;
mSMTPControl.receive(responseStrings);
return responseStrings.size();
}
// virtuals
void SMTPClient::message(const String &messageString)
{
}
void SMTPClient::message(Block<String> &messageStrings)
{
}