Darran Shepherd
/
AutoIpNetStack
Net stack with AutoIP enabled
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Tue Jul 12 2022 15:37:05 by 1.7.2