Bonjour/Zerconf library

Dependencies:   mbed

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 #if 0
00027 
00028 #include <stdio.h>
00029 
00030 #define __DEBUG
00031 #include "dbg.h"
00032 
00033 #define BUF_SIZE 128
00034 #define CHUNK_SIZE 512
00035 
00036 SMTPClient::SMTPClient() : m_pMessage(NULL), m_nextState(SMTP_HELLO), 
00037 m_pCbItem(NULL), m_pCbMeth(NULL), m_watchdog(), m_timeout(0), m_posInMsg(0), m_closed(true), m_host()
00038 {
00039   setTimeout(SMTP_REQUEST_TIMEOUT);
00040 }
00041 
00042 SMTPClient::~SMTPClient()
00043 {
00044   close();
00045 }
00046 
00047 void SMTPClient::setHost(const Host& host)
00048 {
00049   m_host = host;
00050 }
00051   
00052 void SMTPClient::send(EmailMessage* pMessage)
00053 {
00054   init();
00055   m_posInMsg = 0;
00056   m_nextState = SMTP_HELLO;
00057   if( !m_pTCPSocket->connect(m_host) )
00058   {
00059     close();
00060     onResult(SMTP_DISC);
00061   }
00062 }
00063 
00064 void SMTPClient::init() //Create and setup socket if needed
00065 {
00066   close(); //Remove previous elements
00067   if(!m_closed) //Already opened
00068     return;
00069   m_nextState = SMTP_HELLO;
00070   m_pTCPSocket = new TCPSocket;
00071   m_pTCPSocket->setOnEvent(this, &SMTPClient::onTCPSocketEvent);
00072   m_closed = false;
00073 }
00074 
00075 void SMTPClient::close()
00076 {
00077   if(m_closed)
00078     return;
00079   m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else
00080   m_watchdog.detach();
00081   m_pTCPSocket->resetOnEvent();
00082   m_pTCPSocket->close();
00083   delete m_pTCPSocket;
00084   m_pTCPSocket = NULL;
00085 }
00086 
00087 int SMTPClient::rc(char* buf) //Parse return code
00088 {
00089   int rc;
00090   int len = sscanf(buf, "%d %*[^\r\n]\r\n", &rc);
00091   if(len != 1)
00092     return -1;
00093   return rc;
00094 }
00095 
00096 #define MIN(a,b) ((a)<(b))?(a):(b)
00097 void SMTPClient::process(bool moreData) //Main state-machine
00098 {
00099   char buf[BUF_SIZE] = {0};
00100   if(moreData)
00101   {
00102     if( m_nextState != SMTP_BODYMORE )
00103     {
00104       return;
00105     }
00106   }
00107   if(!moreData) //Receive next frame
00108   {
00109     m_pTCPSocket->recv(buf, BUF_SIZE - 1);
00110   }
00111   
00112   IpAddr myIp(0,0,0,0);
00113   string to;
00114   int sendLen;
00115   
00116   DBG("In state %d", m_nextState);
00117 
00118   switch(m_nextState)
00119   {
00120   case SMTP_HELLO:
00121     if( rc(buf) != 220 )
00122       { close(); onResult(SMTP_PRTCL); return; }
00123     myIp = Net::getDefaultIf()->getIp();
00124     sprintf(buf, "HELO %d.%d.%d.%d\r\n", myIp[0], myIp[1], myIp[2], myIp[3]);
00125     m_nextState = SMTP_FROM;
00126     break;
00127   case SMTP_FROM:
00128     if( rc(buf) != 250 )
00129       { close(); onResult(SMTP_PRTCL); return; }
00130     sprintf(buf, "MAIL FROM:<%s>\r\n", m_pMessage->m_from.c_str());
00131     break;
00132   case SMTP_TO:
00133     if( rc(buf) != 250 )
00134       { close(); onResult(SMTP_PRTCL); return; }
00135     to = m_pMessage->m_lTo.front();
00136     sprintf(buf, "RCPT TO:<%s>\r\n", to.c_str());
00137     m_pMessage->m_lTo.pop();
00138     if(m_pMessage->m_lTo.empty())
00139     {
00140       m_nextState = SMTP_DATA;
00141     }
00142     break;  
00143   case SMTP_DATA:
00144     if( rc(buf) != 250 )
00145       { close(); onResult(SMTP_PRTCL); return; }
00146     sprintf(buf, "DATA\r\n");
00147     break;
00148   case SMTP_BODY:
00149     if( rc(buf) != 354 )
00150       { close(); onResult(SMTP_PRTCL); return; }  
00151     m_nextState = SMTP_BODYMORE;
00152   case SMTP_BODYMORE:
00153     sendLen = 0;
00154     if( m_posInMsg < m_pMessage->m_content.length() )
00155     {
00156       sendLen = MIN( (m_pMessage->m_content.length() - m_posInMsg), CHUNK_SIZE );
00157       m_pTCPSocket->send( m_pMessage->m_content.c_str() + m_posInMsg, sendLen );
00158       m_posInMsg += sendLen;
00159     }
00160     if( m_posInMsg == m_pMessage->m_content.length() )
00161     {
00162       sprintf(buf, "\r\n.\r\n"); //EOF
00163       m_nextState = SMTP_EOF;
00164     }
00165     break;
00166   case SMTP_EOF:
00167     if( rc(buf) != 250 )
00168       { close(); onResult(SMTP_PRTCL); return; }
00169     sprintf(buf, "QUIT\r\n");
00170     m_nextState = SMTP_BYE;
00171     break;
00172   case SMTP_BYE:
00173     if( rc(buf) != 221 )
00174       { close(); onResult(SMTP_PRTCL); return; }
00175     close();
00176     onResult(SMTP_OK);
00177     break;
00178   }
00179   
00180  if( m_nextState != SMTP_BODYMORE )
00181  {
00182    m_pTCPSocket->send( buf, strlen(buf) );
00183  }
00184 }
00185 
00186 void SMTPClient::setTimeout(int ms)
00187 {
00188   m_timeout = 1000*ms;
00189   resetTimeout();
00190 }
00191 
00192 void SMTPClient::resetTimeout()
00193 {
00194   m_watchdog.detach();
00195   m_watchdog.attach_us<SMTPClient>(this, &SMTPClient::onTimeout, m_timeout);
00196 }
00197 
00198 void SMTPClient::onTimeout() //Connection has timed out
00199 {
00200   close();
00201   onResult(SMTP_TIMEOUT);
00202 }
00203   
00204 void SMTPClient::onTCPSocketEvent(TCPSocketEvent e)
00205 {
00206   switch(e)
00207   {
00208   case TCPSOCKET_READABLE:
00209     resetTimeout();
00210     process(false);
00211     break;
00212   case TCPSOCKET_WRITEABLE:
00213     resetTimeout();
00214     process(true);
00215     break;
00216   case TCPSOCKET_CONTIMEOUT:
00217   case TCPSOCKET_CONRST:
00218   case TCPSOCKET_CONABRT:
00219   case TCPSOCKET_ERROR:
00220     onResult(SMTP_DISC);
00221     DBG("\r\nConnection error in SMTP Client.\r\n");
00222     close();
00223     break;
00224   case TCPSOCKET_DISCONNECTED:
00225     if(m_nextState != SMTP_BYE)
00226     {
00227       onResult(SMTP_DISC);
00228       DBG("\r\nConnection error in SMTP Client.\r\n");
00229       close();
00230     }
00231     break;
00232   }
00233 }
00234 
00235 void SMTPClient::onResult(SMTPResult r) //Must be called by impl when the request completes
00236 {
00237   if(m_pCbItem && m_pCbMeth)
00238     (m_pCbItem->*m_pCbMeth)(r);
00239 }
00240 
00241 #endif