NetServices Stack source

Dependents:   HelloWorld ServoInterfaceBoardExample1 4180_Lab4

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SMTPClient.cpp Source File

SMTPClient.cpp

00001 
00002 /*
00003 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
00004  
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to deal
00007 in the Software without restriction, including without limitation the rights
00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009 copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011  
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014  
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00018 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00020 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00021 THE SOFTWARE.
00022 */
00023 
00024 #include "SMTPClient.h"
00025 
00026 /*
00027   Provided as reference only, this code has not been tested.
00028 */
00029 #if 0
00030 
00031 #include <stdio.h>
00032 
00033 #define __DEBUG
00034 #include "dbg.h"
00035 
00036 #define BUF_SIZE 128
00037 #define CHUNK_SIZE 512
00038 
00039 SMTPClient::SMTPClient() : m_pMessage(NULL), m_nextState(SMTP_HELLO), 
00040 m_pCbItem(NULL), m_pCbMeth(NULL), m_watchdog(), m_timeout(0), m_posInMsg(0), m_closed(true), m_host()
00041 {
00042   setTimeout(SMTP_REQUEST_TIMEOUT);
00043 }
00044 
00045 SMTPClient::~SMTPClient()
00046 {
00047   close();
00048 }
00049 
00050 void SMTPClient::setHost(const Host& host)
00051 {
00052   m_host = host;
00053 }
00054   
00055 void SMTPClient::send(EmailMessage* pMessage)
00056 {
00057   init();
00058   m_posInMsg = 0;
00059   m_nextState = SMTP_HELLO;
00060   if( !m_pTCPSocket->connect(m_host) )
00061   {
00062     close();
00063     onResult(SMTP_DISC);
00064   }
00065 }
00066 
00067 void SMTPClient::init() //Create and setup socket if needed
00068 {
00069   close(); //Remove previous elements
00070   if(!m_closed) //Already opened
00071     return;
00072   m_nextState = SMTP_HELLO;
00073   m_pTCPSocket = new TCPSocket;
00074   m_pTCPSocket->setOnEvent(this, &SMTPClient::onTCPSocketEvent);
00075   m_closed = false;
00076 }
00077 
00078 void SMTPClient::close()
00079 {
00080   if(m_closed)
00081     return;
00082   m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else
00083   m_watchdog.detach();
00084   m_pTCPSocket->resetOnEvent();
00085   m_pTCPSocket->close();
00086   delete m_pTCPSocket;
00087   m_pTCPSocket = NULL;
00088 }
00089 
00090 int SMTPClient::rc(char* buf) //Parse return code
00091 {
00092   int rc;
00093   int len = sscanf(buf, "%d %*[^\r\n]\r\n", &rc);
00094   if(len != 1)
00095     return -1;
00096   return rc;
00097 }
00098 
00099 #define MIN(a,b) ((a)<(b))?(a):(b)
00100 void SMTPClient::process(bool moreData) //Main state-machine
00101 {
00102   char buf[BUF_SIZE] = {0};
00103   if(moreData)
00104   {
00105     if( m_nextState != SMTP_BODYMORE )
00106     {
00107       return;
00108     }
00109   }
00110   if(!moreData) //Receive next frame
00111   {
00112     m_pTCPSocket->recv(buf, BUF_SIZE - 1);
00113   }
00114   
00115   IpAddr myIp(0,0,0,0);
00116   string to;
00117   int sendLen;
00118   
00119   DBG("In state %d", m_nextState);
00120 
00121   switch(m_nextState)
00122   {
00123   case SMTP_HELLO:
00124     if( rc(buf) != 220 )
00125       { close(); onResult(SMTP_PRTCL); return; }
00126     myIp = Net::getDefaultIf()->getIp();
00127     sprintf(buf, "HELO %d.%d.%d.%d\r\n", myIp[0], myIp[1], myIp[2], myIp[3]);
00128     m_nextState = SMTP_FROM;
00129     break;
00130   case SMTP_FROM:
00131     if( rc(buf) != 250 )
00132       { close(); onResult(SMTP_PRTCL); return; }
00133     sprintf(buf, "MAIL FROM:<%s>\r\n", m_pMessage->m_from.c_str());
00134     break;
00135   case SMTP_TO:
00136     if( rc(buf) != 250 )
00137       { close(); onResult(SMTP_PRTCL); return; }
00138     to = m_pMessage->m_lTo.front();
00139     sprintf(buf, "RCPT TO:<%s>\r\n", to.c_str());
00140     m_pMessage->m_lTo.pop();
00141     if(m_pMessage->m_lTo.empty())
00142     {
00143       m_nextState = SMTP_DATA;
00144     }
00145     break;  
00146   case SMTP_DATA:
00147     if( rc(buf) != 250 )
00148       { close(); onResult(SMTP_PRTCL); return; }
00149     sprintf(buf, "DATA\r\n");
00150     break;
00151   case SMTP_BODY:
00152     if( rc(buf) != 354 )
00153       { close(); onResult(SMTP_PRTCL); return; }  
00154     m_nextState = SMTP_BODYMORE;
00155   case SMTP_BODYMORE:
00156     sendLen = 0;
00157     if( m_posInMsg < m_pMessage->m_content.length() )
00158     {
00159       sendLen = MIN( (m_pMessage->m_content.length() - m_posInMsg), CHUNK_SIZE );
00160       m_pTCPSocket->send( m_pMessage->m_content.c_str() + m_posInMsg, sendLen );
00161       m_posInMsg += sendLen;
00162     }
00163     if( m_posInMsg == m_pMessage->m_content.length() )
00164     {
00165       sprintf(buf, "\r\n.\r\n"); //EOF
00166       m_nextState = SMTP_EOF;
00167     }
00168     break;
00169   case SMTP_EOF:
00170     if( rc(buf) != 250 )
00171       { close(); onResult(SMTP_PRTCL); return; }
00172     sprintf(buf, "QUIT\r\n");
00173     m_nextState = SMTP_BYE;
00174     break;
00175   case SMTP_BYE:
00176     if( rc(buf) != 221 )
00177       { close(); onResult(SMTP_PRTCL); return; }
00178     close();
00179     onResult(SMTP_OK);
00180     break;
00181   }
00182   
00183  if( m_nextState != SMTP_BODYMORE )
00184  {
00185    m_pTCPSocket->send( buf, strlen(buf) );
00186  }
00187 }
00188 
00189 void SMTPClient::setTimeout(int ms)
00190 {
00191   m_timeout = 1000*ms;
00192   resetTimeout();
00193 }
00194 
00195 void SMTPClient::resetTimeout()
00196 {
00197   m_watchdog.detach();
00198   m_watchdog.attach_us<SMTPClient>(this, &SMTPClient::onTimeout, m_timeout);
00199 }
00200 
00201 void SMTPClient::onTimeout() //Connection has timed out
00202 {
00203   close();
00204   onResult(SMTP_TIMEOUT);
00205 }
00206   
00207 void SMTPClient::onTCPSocketEvent(TCPSocketEvent e)
00208 {
00209   switch(e)
00210   {
00211   case TCPSOCKET_READABLE:
00212     resetTimeout();
00213     process(false);
00214     break;
00215   case TCPSOCKET_WRITEABLE:
00216     resetTimeout();
00217     process(true);
00218     break;
00219   case TCPSOCKET_CONTIMEOUT:
00220   case TCPSOCKET_CONRST:
00221   case TCPSOCKET_CONABRT:
00222   case TCPSOCKET_ERROR:
00223     onResult(SMTP_DISC);
00224     DBG("\r\nConnection error in SMTP Client.\r\n");
00225     close();
00226     break;
00227   case TCPSOCKET_DISCONNECTED:
00228     if(m_nextState != SMTP_BYE)
00229     {
00230       onResult(SMTP_DISC);
00231       DBG("\r\nConnection error in SMTP Client.\r\n");
00232       close();
00233     }
00234     break;
00235   }
00236 }
00237 
00238 void SMTPClient::onResult(SMTPResult r) //Must be called by impl when the request completes
00239 {
00240   if(m_pCbItem && m_pCbMeth)
00241     (m_pCbItem->*m_pCbMeth)(r);
00242 }
00243 
00244 #endif