summaryrefslogtreecommitdiffstats
path: root/mimelib/smtp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mimelib/smtp.cpp')
-rw-r--r--mimelib/smtp.cpp537
1 files changed, 537 insertions, 0 deletions
diff --git a/mimelib/smtp.cpp b/mimelib/smtp.cpp
new file mode 100644
index 0000000..a024787
--- /dev/null
+++ b/mimelib/smtp.cpp
@@ -0,0 +1,537 @@
+//=============================================================================
+// File: smtp.cpp
+// Contents: Definitions for DwSmtpClient
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+// $Revision: 1.9.20.1 $
+// $Date: 2002/12/15 15:59:44 $
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#include <mimelib/config.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <mimelib/smtp.h>
+
+#if defined(DW_UNIX)
+#include <unistd.h>
+#endif
+
+#define SMTP_PORT 25
+#define RECV_BUFFER_SIZE 8192
+#define SEND_BUFFER_SIZE 1024
+
+#if defined(DW_DEBUG_SMTP)
+# define DBG_SMTP_STMT(x) x
+#else
+# define DBG_SMTP_STMT(x)
+#endif
+
+
+DwSmtpClient::DwSmtpClient()
+{
+ mRecvBuffer = new char[RECV_BUFFER_SIZE];
+ mSendBuffer = new char[SEND_BUFFER_SIZE];
+ mNumRecvBufferChars = 0;
+ mRecvBufferPos = 0;
+ mReplyCode = 0;
+}
+
+
+DwSmtpClient::~DwSmtpClient()
+{
+ if (mRecvBuffer) {
+ delete [] mRecvBuffer;
+ mRecvBuffer = 0;
+ }
+ if (mSendBuffer) {
+ delete [] mSendBuffer;
+ mSendBuffer = 0;
+ }
+}
+
+
+int DwSmtpClient::Open(const char* aServer, DwUint16 aPort)
+{
+ mReplyCode = 0;
+ mResponse = "";
+ int err = DwProtocolClient::Open(aServer, aPort);
+ if (! err) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::ReplyCode() const
+{
+ return mReplyCode;
+}
+
+
+const DwString& DwSmtpClient::Response() const
+{
+ return mResponse;
+}
+
+
+int DwSmtpClient::Helo()
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdHelo;
+ strcpy(mSendBuffer, "HELO ");
+ gethostname(&mSendBuffer[5], SEND_BUFFER_SIZE-32);
+ mSendBuffer[5+SEND_BUFFER_SIZE-32 -1] = '\0';
+ strcat(mSendBuffer, "\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Mail(const char* aFrom)
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdMail;
+ strcpy(mSendBuffer, "MAIL FROM:<");
+ strncat(mSendBuffer, aFrom, SEND_BUFFER_SIZE-32);
+ strcat(mSendBuffer, ">\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Rcpt(const char* aTo)
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdRcpt;
+ strcpy(mSendBuffer, "RCPT TO:<");
+ strncat(mSendBuffer, aTo, SEND_BUFFER_SIZE-32);
+ strcat(mSendBuffer, ">\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Data()
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdData;
+ strcpy(mSendBuffer, "DATA\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Rset()
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdRset;
+ strcpy(mSendBuffer, "RSET\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Send(const char* aFrom)
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdSend;
+ strcpy(mSendBuffer, "SEND FROM:<");
+ strncat(mSendBuffer, aFrom, SEND_BUFFER_SIZE-32);
+ strcat(mSendBuffer, ">\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Soml(const char* aFrom)
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdSoml;
+ strcpy(mSendBuffer, "SOML FROM:<");
+ strncat(mSendBuffer, aFrom, SEND_BUFFER_SIZE-32);
+ strcat(mSendBuffer, ">\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Saml(const char* aFrom)
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdSaml;
+ strcpy(mSendBuffer, "SAML FROM:<");
+ strncat(mSendBuffer, aFrom, SEND_BUFFER_SIZE-32);
+ strcat(mSendBuffer, ">\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Vrfy(const char* aName)
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdVrfy;
+ strcpy(mSendBuffer, "VRFY ");
+ strncat(mSendBuffer, aName, SEND_BUFFER_SIZE-32);
+ strcat(mSendBuffer, "\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Expn(const char* aName)
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdExpn;
+ strcpy(mSendBuffer, "EXPN ");
+ strncat(mSendBuffer, aName, SEND_BUFFER_SIZE-32);
+ strcat(mSendBuffer, "\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Help(const char* aArg)
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdHelp;
+ strcpy(mSendBuffer, "HELP");
+ if (aArg) {
+ strcat(mSendBuffer, " ");
+ strncat(mSendBuffer, aArg, SEND_BUFFER_SIZE-32);
+ }
+ strcat(mSendBuffer, "\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Noop()
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdNoop;
+ strcpy(mSendBuffer, "NOOP\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Quit()
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdQuit;
+ strcpy(mSendBuffer, "QUIT\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::Turn()
+{
+ mReplyCode = 0;
+ mResponse = "";
+ mLastCommand = kCmdTurn;
+ strcpy(mSendBuffer, "TURN\r\n");
+ DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwSmtpClient::SendData(const DwString& aStr)
+{
+ return SendData(aStr.data(), aStr.length());
+}
+
+
+int DwSmtpClient::SendData(const char* aBuf, int aBufLen)
+{
+ mReplyCode = 0;
+ mResponse = "";
+
+ int pos = 0;
+ int len = 0;
+ const char* buf = 0;
+
+ int lastLastChar = '\r';
+ int lastChar = '\n';
+
+ while (1) {
+
+ len = SEND_BUFFER_SIZE;
+ len = (len < aBufLen - pos) ? len : aBufLen - pos;
+ if (len == 0) break;
+
+ // Look for CR LF '.'. If it is found, then we have to copy the buffer
+ // and stuff an extra '.'.
+
+ int hasCrLfDot = 0;
+ int tLastChar = lastChar;
+ int tLastLastChar = lastLastChar;
+ for (int i=0; i < len; ++i) {
+ int ch = aBuf[pos+i];
+ if (tLastLastChar == '\r' && tLastChar == '\n' && ch == '.') {
+ hasCrLfDot = 1;
+ break;
+ }
+ tLastLastChar = tLastChar;
+ tLastChar = ch;
+ }
+ if (! hasCrLfDot) {
+ lastChar = tLastChar;
+ lastLastChar = tLastLastChar;
+ buf = &aBuf[pos];
+ pos += len;
+ }
+
+ // If CR LF '.' was found, copy the chars to a different buffer and stuff
+ // the extra '.'.
+
+ else /* (hasCrLfDot) */ {
+ tLastChar = lastChar;
+ tLastLastChar = lastLastChar;
+ int iDst = 0;
+ int iSrc = 0;
+ // Implementation note: be careful to avoid overrunning the
+ // destination buffer when CR LF '.' are the last three characters
+ // of the source buffer.
+ while (iDst < SEND_BUFFER_SIZE && iSrc < len) {
+ int ch = aBuf[pos+iSrc];
+ if (tLastLastChar == '\r' && tLastChar == '\n' && ch == '.') {
+ if (iDst == SEND_BUFFER_SIZE-1) {
+ break;
+ }
+ mSendBuffer[iDst++] = '.';
+ }
+ mSendBuffer[iDst++] = (char) ch;
+ ++iSrc;
+ tLastLastChar = tLastChar;
+ tLastChar = ch;
+ }
+ lastChar = tLastChar;
+ lastLastChar = tLastLastChar;
+ len = iDst;
+ buf = mSendBuffer;
+ pos += iSrc;
+ }
+
+ // Send the buffer
+
+ int numSent = PSend(buf, len);
+ if (numSent != len) {
+ mReplyCode = 0;
+ return mReplyCode;
+ }
+ }
+
+ // Send final '.' CR LF. If CR LF are not at the end of the buffer, then
+ // send a CR LF '.' CR LF.
+
+ if (lastLastChar == '\r' && lastChar == '\n') {
+ PSend(".\r\n", 3);
+ }
+ else {
+ PSend("\r\n.\r\n", 5);
+ }
+
+ // Get the server's response
+
+ PGetResponse();
+ return mReplyCode;
+}
+
+
+void DwSmtpClient::PGetResponse()
+{
+ mReplyCode = 0;
+ char* ptr = 0;
+ int len = 0;
+ int err = 0;
+ int done = 0;
+ while (! done) {
+ err = PGetLine(&ptr, &len);
+ if (! err) {
+ mResponse.append(ptr, len);
+ if (len <= 3 || ptr[3] != '-') {
+ done = 1;
+ }
+ }
+ else {
+ done = 1;
+ }
+ }
+ if (! err) {
+ mReplyCode = strtol(ptr, NULL, 10);
+ }
+ DBG_SMTP_STMT(cout << "S: " << mResponse << flush;)
+}
+
+
+int DwSmtpClient::PGetLine(char** aPtr, int* aLen)
+{
+ // Restore the saved state
+
+ int startPos = mRecvBufferPos;
+ int pos = mRecvBufferPos;
+ int lastChar = -1;
+
+ // Keep trying until we get a complete line, detect an error, or
+ // determine that the connection has been closed
+
+ int isEndOfLineFound = 0;
+ while (1) {
+
+ // Search buffer for end of line chars. Stop when we find them or when
+ // we exhaust the buffer.
+
+ while (pos < mNumRecvBufferChars) {
+ if (lastChar == '\r' && mRecvBuffer[pos] == '\n') {
+ isEndOfLineFound = 1;
+ ++pos;
+ break;
+ }
+ lastChar = mRecvBuffer[pos];
+ ++pos;
+ }
+ if (isEndOfLineFound) {
+ *aPtr = &mRecvBuffer[startPos];
+ *aLen = pos - startPos;
+ mRecvBufferPos = pos;
+ return 0;
+ }
+
+ // If the buffer has no room, return without an error; otherwise,
+ // replenish the buffer.
+
+ // Implementation note: The standard does not allow long lines,
+ // however, that does not mean that they won't occur. The way
+ // this function deals with long lines is to return a full buffer's
+ // worth of characters as a line. The next call to this function
+ // will start where this call left off. In essence, we have
+ // *forced* a line break, but without putting in CR LF characters.
+
+ if (startPos == 0 && pos == RECV_BUFFER_SIZE) {
+ *aPtr = mRecvBuffer;
+ *aLen = RECV_BUFFER_SIZE;
+ mRecvBufferPos = pos;
+ return 0;
+ }
+ memmove(mRecvBuffer, &mRecvBuffer[startPos],
+ mNumRecvBufferChars-startPos);
+ mNumRecvBufferChars -= startPos;
+ mRecvBufferPos = mNumRecvBufferChars;
+ int bufFreeSpace = RECV_BUFFER_SIZE - mRecvBufferPos;
+ int n = PReceive(&mRecvBuffer[mRecvBufferPos], bufFreeSpace);
+ if (n == 0) {
+ // The connection has been closed or an error occurred
+ return -1;
+ }
+ mNumRecvBufferChars += n;
+ startPos = 0;
+ pos = mRecvBufferPos;
+ }
+}