Dependents:   TimeZoneDemo EthernetJackTestCode MMEx_Challenge ntp_mem ... more

Committer:
segundo
Date:
Tue Nov 09 20:54:15 2010 +0000
Revision:
0:ac1725ba162c
Child:
5:fa27dde97304

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
segundo 0:ac1725ba162c 1
segundo 0:ac1725ba162c 2 /*
segundo 0:ac1725ba162c 3 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
segundo 0:ac1725ba162c 4
segundo 0:ac1725ba162c 5 Permission is hereby granted, free of charge, to any person obtaining a copy
segundo 0:ac1725ba162c 6 of this software and associated documentation files (the "Software"), to deal
segundo 0:ac1725ba162c 7 in the Software without restriction, including without limitation the rights
segundo 0:ac1725ba162c 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
segundo 0:ac1725ba162c 9 copies of the Software, and to permit persons to whom the Software is
segundo 0:ac1725ba162c 10 furnished to do so, subject to the following conditions:
segundo 0:ac1725ba162c 11
segundo 0:ac1725ba162c 12 The above copyright notice and this permission notice shall be included in
segundo 0:ac1725ba162c 13 all copies or substantial portions of the Software.
segundo 0:ac1725ba162c 14
segundo 0:ac1725ba162c 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
segundo 0:ac1725ba162c 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
segundo 0:ac1725ba162c 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
segundo 0:ac1725ba162c 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
segundo 0:ac1725ba162c 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
segundo 0:ac1725ba162c 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
segundo 0:ac1725ba162c 21 THE SOFTWARE.
segundo 0:ac1725ba162c 22 */
segundo 0:ac1725ba162c 23
segundo 0:ac1725ba162c 24 #include "SMTPClient.h"
segundo 0:ac1725ba162c 25
segundo 0:ac1725ba162c 26 /*
segundo 0:ac1725ba162c 27 Provided as reference only, this code has not been tested.
segundo 0:ac1725ba162c 28 */
segundo 0:ac1725ba162c 29 #if 0
segundo 0:ac1725ba162c 30
segundo 0:ac1725ba162c 31 #include <stdio.h>
segundo 0:ac1725ba162c 32
segundo 0:ac1725ba162c 33 #define __DEBUG
segundo 0:ac1725ba162c 34 #include "dbg.h"
segundo 0:ac1725ba162c 35
segundo 0:ac1725ba162c 36 #define BUF_SIZE 128
segundo 0:ac1725ba162c 37 #define CHUNK_SIZE 512
segundo 0:ac1725ba162c 38
segundo 0:ac1725ba162c 39 SMTPClient::SMTPClient() : m_pMessage(NULL), m_nextState(SMTP_HELLO),
segundo 0:ac1725ba162c 40 m_pCbItem(NULL), m_pCbMeth(NULL), m_watchdog(), m_timeout(0), m_posInMsg(0), m_closed(true), m_host()
segundo 0:ac1725ba162c 41 {
segundo 0:ac1725ba162c 42 setTimeout(SMTP_REQUEST_TIMEOUT);
segundo 0:ac1725ba162c 43 }
segundo 0:ac1725ba162c 44
segundo 0:ac1725ba162c 45 SMTPClient::~SMTPClient()
segundo 0:ac1725ba162c 46 {
segundo 0:ac1725ba162c 47 close();
segundo 0:ac1725ba162c 48 }
segundo 0:ac1725ba162c 49
segundo 0:ac1725ba162c 50 void SMTPClient::setHost(const Host& host)
segundo 0:ac1725ba162c 51 {
segundo 0:ac1725ba162c 52 m_host = host;
segundo 0:ac1725ba162c 53 }
segundo 0:ac1725ba162c 54
segundo 0:ac1725ba162c 55 void SMTPClient::send(EmailMessage* pMessage)
segundo 0:ac1725ba162c 56 {
segundo 0:ac1725ba162c 57 init();
segundo 0:ac1725ba162c 58 m_posInMsg = 0;
segundo 0:ac1725ba162c 59 m_nextState = SMTP_HELLO;
segundo 0:ac1725ba162c 60 if( !m_pTCPSocket->connect(m_host) )
segundo 0:ac1725ba162c 61 {
segundo 0:ac1725ba162c 62 close();
segundo 0:ac1725ba162c 63 onResult(SMTP_DISC);
segundo 0:ac1725ba162c 64 }
segundo 0:ac1725ba162c 65 }
segundo 0:ac1725ba162c 66
segundo 0:ac1725ba162c 67 void SMTPClient::init() //Create and setup socket if needed
segundo 0:ac1725ba162c 68 {
segundo 0:ac1725ba162c 69 close(); //Remove previous elements
segundo 0:ac1725ba162c 70 if(!m_closed) //Already opened
segundo 0:ac1725ba162c 71 return;
segundo 0:ac1725ba162c 72 m_nextState = SMTP_HELLO;
segundo 0:ac1725ba162c 73 m_pTCPSocket = new TCPSocket;
segundo 0:ac1725ba162c 74 m_pTCPSocket->setOnEvent(this, &SMTPClient::onTCPSocketEvent);
segundo 0:ac1725ba162c 75 m_closed = false;
segundo 0:ac1725ba162c 76 }
segundo 0:ac1725ba162c 77
segundo 0:ac1725ba162c 78 void SMTPClient::close()
segundo 0:ac1725ba162c 79 {
segundo 0:ac1725ba162c 80 if(m_closed)
segundo 0:ac1725ba162c 81 return;
segundo 0:ac1725ba162c 82 m_closed = true; //Prevent recursive calling or calling on an object being destructed by someone else
segundo 0:ac1725ba162c 83 m_watchdog.detach();
segundo 0:ac1725ba162c 84 m_pTCPSocket->resetOnEvent();
segundo 0:ac1725ba162c 85 m_pTCPSocket->close();
segundo 0:ac1725ba162c 86 delete m_pTCPSocket;
segundo 0:ac1725ba162c 87 m_pTCPSocket = NULL;
segundo 0:ac1725ba162c 88 }
segundo 0:ac1725ba162c 89
segundo 0:ac1725ba162c 90 int SMTPClient::rc(char* buf) //Parse return code
segundo 0:ac1725ba162c 91 {
segundo 0:ac1725ba162c 92 int rc;
segundo 0:ac1725ba162c 93 int len = sscanf(buf, "%d %*[^\r\n]\r\n", &rc);
segundo 0:ac1725ba162c 94 if(len != 1)
segundo 0:ac1725ba162c 95 return -1;
segundo 0:ac1725ba162c 96 return rc;
segundo 0:ac1725ba162c 97 }
segundo 0:ac1725ba162c 98
segundo 0:ac1725ba162c 99 #define MIN(a,b) ((a)<(b))?(a):(b)
segundo 0:ac1725ba162c 100 void SMTPClient::process(bool moreData) //Main state-machine
segundo 0:ac1725ba162c 101 {
segundo 0:ac1725ba162c 102 char buf[BUF_SIZE] = {0};
segundo 0:ac1725ba162c 103 if(moreData)
segundo 0:ac1725ba162c 104 {
segundo 0:ac1725ba162c 105 if( m_nextState != SMTP_BODYMORE )
segundo 0:ac1725ba162c 106 {
segundo 0:ac1725ba162c 107 return;
segundo 0:ac1725ba162c 108 }
segundo 0:ac1725ba162c 109 }
segundo 0:ac1725ba162c 110 if(!moreData) //Receive next frame
segundo 0:ac1725ba162c 111 {
segundo 0:ac1725ba162c 112 m_pTCPSocket->recv(buf, BUF_SIZE - 1);
segundo 0:ac1725ba162c 113 }
segundo 0:ac1725ba162c 114
segundo 0:ac1725ba162c 115 IpAddr myIp(0,0,0,0);
segundo 0:ac1725ba162c 116 string to;
segundo 0:ac1725ba162c 117 int sendLen;
segundo 0:ac1725ba162c 118
segundo 0:ac1725ba162c 119 DBG("In state %d", m_nextState);
segundo 0:ac1725ba162c 120
segundo 0:ac1725ba162c 121 switch(m_nextState)
segundo 0:ac1725ba162c 122 {
segundo 0:ac1725ba162c 123 case SMTP_HELLO:
segundo 0:ac1725ba162c 124 if( rc(buf) != 220 )
segundo 0:ac1725ba162c 125 { close(); onResult(SMTP_PRTCL); return; }
segundo 0:ac1725ba162c 126 myIp = Net::getDefaultIf()->getIp();
segundo 0:ac1725ba162c 127 sprintf(buf, "HELO %d.%d.%d.%d\r\n", myIp[0], myIp[1], myIp[2], myIp[3]);
segundo 0:ac1725ba162c 128 m_nextState = SMTP_FROM;
segundo 0:ac1725ba162c 129 break;
segundo 0:ac1725ba162c 130 case SMTP_FROM:
segundo 0:ac1725ba162c 131 if( rc(buf) != 250 )
segundo 0:ac1725ba162c 132 { close(); onResult(SMTP_PRTCL); return; }
segundo 0:ac1725ba162c 133 sprintf(buf, "MAIL FROM:<%s>\r\n", m_pMessage->m_from.c_str());
segundo 0:ac1725ba162c 134 break;
segundo 0:ac1725ba162c 135 case SMTP_TO:
segundo 0:ac1725ba162c 136 if( rc(buf) != 250 )
segundo 0:ac1725ba162c 137 { close(); onResult(SMTP_PRTCL); return; }
segundo 0:ac1725ba162c 138 to = m_pMessage->m_lTo.front();
segundo 0:ac1725ba162c 139 sprintf(buf, "RCPT TO:<%s>\r\n", to.c_str());
segundo 0:ac1725ba162c 140 m_pMessage->m_lTo.pop();
segundo 0:ac1725ba162c 141 if(m_pMessage->m_lTo.empty())
segundo 0:ac1725ba162c 142 {
segundo 0:ac1725ba162c 143 m_nextState = SMTP_DATA;
segundo 0:ac1725ba162c 144 }
segundo 0:ac1725ba162c 145 break;
segundo 0:ac1725ba162c 146 case SMTP_DATA:
segundo 0:ac1725ba162c 147 if( rc(buf) != 250 )
segundo 0:ac1725ba162c 148 { close(); onResult(SMTP_PRTCL); return; }
segundo 0:ac1725ba162c 149 sprintf(buf, "DATA\r\n");
segundo 0:ac1725ba162c 150 break;
segundo 0:ac1725ba162c 151 case SMTP_BODY:
segundo 0:ac1725ba162c 152 if( rc(buf) != 354 )
segundo 0:ac1725ba162c 153 { close(); onResult(SMTP_PRTCL); return; }
segundo 0:ac1725ba162c 154 m_nextState = SMTP_BODYMORE;
segundo 0:ac1725ba162c 155 case SMTP_BODYMORE:
segundo 0:ac1725ba162c 156 sendLen = 0;
segundo 0:ac1725ba162c 157 if( m_posInMsg < m_pMessage->m_content.length() )
segundo 0:ac1725ba162c 158 {
segundo 0:ac1725ba162c 159 sendLen = MIN( (m_pMessage->m_content.length() - m_posInMsg), CHUNK_SIZE );
segundo 0:ac1725ba162c 160 m_pTCPSocket->send( m_pMessage->m_content.c_str() + m_posInMsg, sendLen );
segundo 0:ac1725ba162c 161 m_posInMsg += sendLen;
segundo 0:ac1725ba162c 162 }
segundo 0:ac1725ba162c 163 if( m_posInMsg == m_pMessage->m_content.length() )
segundo 0:ac1725ba162c 164 {
segundo 0:ac1725ba162c 165 sprintf(buf, "\r\n.\r\n"); //EOF
segundo 0:ac1725ba162c 166 m_nextState = SMTP_EOF;
segundo 0:ac1725ba162c 167 }
segundo 0:ac1725ba162c 168 break;
segundo 0:ac1725ba162c 169 case SMTP_EOF:
segundo 0:ac1725ba162c 170 if( rc(buf) != 250 )
segundo 0:ac1725ba162c 171 { close(); onResult(SMTP_PRTCL); return; }
segundo 0:ac1725ba162c 172 sprintf(buf, "QUIT\r\n");
segundo 0:ac1725ba162c 173 m_nextState = SMTP_BYE;
segundo 0:ac1725ba162c 174 break;
segundo 0:ac1725ba162c 175 case SMTP_BYE:
segundo 0:ac1725ba162c 176 if( rc(buf) != 221 )
segundo 0:ac1725ba162c 177 { close(); onResult(SMTP_PRTCL); return; }
segundo 0:ac1725ba162c 178 close();
segundo 0:ac1725ba162c 179 onResult(SMTP_OK);
segundo 0:ac1725ba162c 180 break;
segundo 0:ac1725ba162c 181 }
segundo 0:ac1725ba162c 182
segundo 0:ac1725ba162c 183 if( m_nextState != SMTP_BODYMORE )
segundo 0:ac1725ba162c 184 {
segundo 0:ac1725ba162c 185 m_pTCPSocket->send( buf, strlen(buf) );
segundo 0:ac1725ba162c 186 }
segundo 0:ac1725ba162c 187 }
segundo 0:ac1725ba162c 188
segundo 0:ac1725ba162c 189 void SMTPClient::setTimeout(int ms)
segundo 0:ac1725ba162c 190 {
segundo 0:ac1725ba162c 191 m_timeout = 1000*ms;
segundo 0:ac1725ba162c 192 resetTimeout();
segundo 0:ac1725ba162c 193 }
segundo 0:ac1725ba162c 194
segundo 0:ac1725ba162c 195 void SMTPClient::resetTimeout()
segundo 0:ac1725ba162c 196 {
segundo 0:ac1725ba162c 197 m_watchdog.detach();
segundo 0:ac1725ba162c 198 m_watchdog.attach_us<SMTPClient>(this, &SMTPClient::onTimeout, m_timeout);
segundo 0:ac1725ba162c 199 }
segundo 0:ac1725ba162c 200
segundo 0:ac1725ba162c 201 void SMTPClient::onTimeout() //Connection has timed out
segundo 0:ac1725ba162c 202 {
segundo 0:ac1725ba162c 203 close();
segundo 0:ac1725ba162c 204 onResult(SMTP_TIMEOUT);
segundo 0:ac1725ba162c 205 }
segundo 0:ac1725ba162c 206
segundo 0:ac1725ba162c 207 void SMTPClient::onTCPSocketEvent(TCPSocketEvent e)
segundo 0:ac1725ba162c 208 {
segundo 0:ac1725ba162c 209 switch(e)
segundo 0:ac1725ba162c 210 {
segundo 0:ac1725ba162c 211 case TCPSOCKET_READABLE:
segundo 0:ac1725ba162c 212 resetTimeout();
segundo 0:ac1725ba162c 213 process(false);
segundo 0:ac1725ba162c 214 break;
segundo 0:ac1725ba162c 215 case TCPSOCKET_WRITEABLE:
segundo 0:ac1725ba162c 216 resetTimeout();
segundo 0:ac1725ba162c 217 process(true);
segundo 0:ac1725ba162c 218 break;
segundo 0:ac1725ba162c 219 case TCPSOCKET_CONTIMEOUT:
segundo 0:ac1725ba162c 220 case TCPSOCKET_CONRST:
segundo 0:ac1725ba162c 221 case TCPSOCKET_CONABRT:
segundo 0:ac1725ba162c 222 case TCPSOCKET_ERROR:
segundo 0:ac1725ba162c 223 onResult(SMTP_DISC);
segundo 0:ac1725ba162c 224 DBG("\r\nConnection error in SMTP Client.\r\n");
segundo 0:ac1725ba162c 225 close();
segundo 0:ac1725ba162c 226 break;
segundo 0:ac1725ba162c 227 case TCPSOCKET_DISCONNECTED:
segundo 0:ac1725ba162c 228 if(m_nextState != SMTP_BYE)
segundo 0:ac1725ba162c 229 {
segundo 0:ac1725ba162c 230 onResult(SMTP_DISC);
segundo 0:ac1725ba162c 231 DBG("\r\nConnection error in SMTP Client.\r\n");
segundo 0:ac1725ba162c 232 close();
segundo 0:ac1725ba162c 233 }
segundo 0:ac1725ba162c 234 break;
segundo 0:ac1725ba162c 235 }
segundo 0:ac1725ba162c 236 }
segundo 0:ac1725ba162c 237
segundo 0:ac1725ba162c 238 void SMTPClient::onResult(SMTPResult r) //Must be called by impl when the request completes
segundo 0:ac1725ba162c 239 {
segundo 0:ac1725ba162c 240 if(m_pCbItem && m_pCbMeth)
segundo 0:ac1725ba162c 241 (m_pCbItem->*m_pCbMeth)(r);
segundo 0:ac1725ba162c 242 }
segundo 0:ac1725ba162c 243
segundo 0:ac1725ba162c 244 #endif