mbed Weather Platform firmware http://mbed.org/users/okini3939/notebook/mbed-weather-platform-firmware/
Dependencies: ChaNFSSD EthernetNetIf I2CLEDDisp Agentbed ChaNFSUSB ILinterpreter mbed BMP085 WeatherMeters ConfigFile ChaNFS I2CLCD
TinyNet/TinySMTP.cpp@3:058292da2cee, 2011-09-07 (annotated)
- Committer:
- okini3939
- Date:
- Wed Sep 07 16:03:54 2011 +0000
- Revision:
- 3:058292da2cee
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
okini3939 | 3:058292da2cee | 1 | /* |
okini3939 | 3:058292da2cee | 2 | * mbed Tiny SMTP Client |
okini3939 | 3:058292da2cee | 3 | * Copyright (c) 2011 Hiroshi Suga |
okini3939 | 3:058292da2cee | 4 | * Released under the MIT License: http://mbed.org/license/mit |
okini3939 | 3:058292da2cee | 5 | */ |
okini3939 | 3:058292da2cee | 6 | |
okini3939 | 3:058292da2cee | 7 | /** @file |
okini3939 | 3:058292da2cee | 8 | * @brief Tiny SMTP Client |
okini3939 | 3:058292da2cee | 9 | */ |
okini3939 | 3:058292da2cee | 10 | |
okini3939 | 3:058292da2cee | 11 | #include "mbed.h" |
okini3939 | 3:058292da2cee | 12 | #include "EthernetNetIf.h" |
okini3939 | 3:058292da2cee | 13 | #include "TCPSocket.h" |
okini3939 | 3:058292da2cee | 14 | #include "DNSRequest.h" |
okini3939 | 3:058292da2cee | 15 | #include "TinySMTP.h" |
okini3939 | 3:058292da2cee | 16 | |
okini3939 | 3:058292da2cee | 17 | #define STATUS_NONE 0 |
okini3939 | 3:058292da2cee | 18 | #define STATUS_READABLE 1 |
okini3939 | 3:058292da2cee | 19 | #define STATUS_CONNECTED 2 |
okini3939 | 3:058292da2cee | 20 | #define STATUS_ERROR 3 |
okini3939 | 3:058292da2cee | 21 | #define STATUS_DISCONNECTED 4 |
okini3939 | 3:058292da2cee | 22 | |
okini3939 | 3:058292da2cee | 23 | static TCPSocket *smtp; |
okini3939 | 3:058292da2cee | 24 | static volatile int tcp_ready, tcp_readable, tcp_writable; |
okini3939 | 3:058292da2cee | 25 | static volatile int dns_status; |
okini3939 | 3:058292da2cee | 26 | |
okini3939 | 3:058292da2cee | 27 | |
okini3939 | 3:058292da2cee | 28 | // Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com) |
okini3939 | 3:058292da2cee | 29 | static int base64enc(const char *input, unsigned int length, char *output, int outputlen) { |
okini3939 | 3:058292da2cee | 30 | static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
okini3939 | 3:058292da2cee | 31 | unsigned int c, c1, c2, c3; |
okini3939 | 3:058292da2cee | 32 | |
okini3939 | 3:058292da2cee | 33 | if (outputlen < (((length-1)/3)+1)<<2) return -1; |
okini3939 | 3:058292da2cee | 34 | |
okini3939 | 3:058292da2cee | 35 | for(unsigned int i = 0, j = 0; i<length; i+=3,j+=4) { |
okini3939 | 3:058292da2cee | 36 | c1 = ((((unsigned char)*((unsigned char *)&input[i])))); |
okini3939 | 3:058292da2cee | 37 | c2 = (length>i+1)?((((unsigned char)*((unsigned char *)&input[i+1])))):0; |
okini3939 | 3:058292da2cee | 38 | c3 = (length>i+2)?((((unsigned char)*((unsigned char *)&input[i+2])))):0; |
okini3939 | 3:058292da2cee | 39 | |
okini3939 | 3:058292da2cee | 40 | c = ((c1 & 0xFC) >> 2); |
okini3939 | 3:058292da2cee | 41 | output[j+0] = base64[c]; |
okini3939 | 3:058292da2cee | 42 | c = ((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4); |
okini3939 | 3:058292da2cee | 43 | output[j+1] = base64[c]; |
okini3939 | 3:058292da2cee | 44 | c = ((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6); |
okini3939 | 3:058292da2cee | 45 | output[j+2] = (length>i+1)?base64[c]:'='; |
okini3939 | 3:058292da2cee | 46 | c = (c3 & 0x3F); |
okini3939 | 3:058292da2cee | 47 | output[j+3] = (length>i+2)?base64[c]:'='; |
okini3939 | 3:058292da2cee | 48 | } |
okini3939 | 3:058292da2cee | 49 | output[(((length-1)/3)+1)<<2] = '\0'; |
okini3939 | 3:058292da2cee | 50 | return 0; |
okini3939 | 3:058292da2cee | 51 | } |
okini3939 | 3:058292da2cee | 52 | |
okini3939 | 3:058292da2cee | 53 | |
okini3939 | 3:058292da2cee | 54 | void isr_smtp (TCPSocketEvent e) { |
okini3939 | 3:058292da2cee | 55 | |
okini3939 | 3:058292da2cee | 56 | #ifdef DEBUG |
okini3939 | 3:058292da2cee | 57 | printf("tcp(%d)\r\n", e); |
okini3939 | 3:058292da2cee | 58 | #endif |
okini3939 | 3:058292da2cee | 59 | switch(e) { |
okini3939 | 3:058292da2cee | 60 | case TCPSOCKET_CONNECTED: |
okini3939 | 3:058292da2cee | 61 | tcp_ready = 1; |
okini3939 | 3:058292da2cee | 62 | break; |
okini3939 | 3:058292da2cee | 63 | |
okini3939 | 3:058292da2cee | 64 | case TCPSOCKET_READABLE: //Incoming data |
okini3939 | 3:058292da2cee | 65 | tcp_readable = 1; |
okini3939 | 3:058292da2cee | 66 | break; |
okini3939 | 3:058292da2cee | 67 | |
okini3939 | 3:058292da2cee | 68 | case TCPSOCKET_WRITEABLE: //We can send data |
okini3939 | 3:058292da2cee | 69 | tcp_writable = 1; |
okini3939 | 3:058292da2cee | 70 | break; |
okini3939 | 3:058292da2cee | 71 | |
okini3939 | 3:058292da2cee | 72 | case TCPSOCKET_CONTIMEOUT: |
okini3939 | 3:058292da2cee | 73 | case TCPSOCKET_CONRST: |
okini3939 | 3:058292da2cee | 74 | case TCPSOCKET_CONABRT: |
okini3939 | 3:058292da2cee | 75 | case TCPSOCKET_ERROR: |
okini3939 | 3:058292da2cee | 76 | case TCPSOCKET_DISCONNECTED: |
okini3939 | 3:058292da2cee | 77 | tcp_ready = 0; |
okini3939 | 3:058292da2cee | 78 | break; |
okini3939 | 3:058292da2cee | 79 | } |
okini3939 | 3:058292da2cee | 80 | } |
okini3939 | 3:058292da2cee | 81 | |
okini3939 | 3:058292da2cee | 82 | int wait_smtp (int code) { |
okini3939 | 3:058292da2cee | 83 | Timer timeout; |
okini3939 | 3:058292da2cee | 84 | int i; |
okini3939 | 3:058292da2cee | 85 | char buf[1500]; |
okini3939 | 3:058292da2cee | 86 | |
okini3939 | 3:058292da2cee | 87 | // wait responce |
okini3939 | 3:058292da2cee | 88 | timeout.reset(); |
okini3939 | 3:058292da2cee | 89 | timeout.start(); |
okini3939 | 3:058292da2cee | 90 | while (timeout.read_ms() < SMTP_TIMEOUT) { |
okini3939 | 3:058292da2cee | 91 | if (tcp_readable) break; |
okini3939 | 3:058292da2cee | 92 | Net::poll(); |
okini3939 | 3:058292da2cee | 93 | } |
okini3939 | 3:058292da2cee | 94 | timeout.stop(); |
okini3939 | 3:058292da2cee | 95 | if (! tcp_readable) return -1; |
okini3939 | 3:058292da2cee | 96 | // recv |
okini3939 | 3:058292da2cee | 97 | i = smtp->recv(buf, sizeof(buf)); |
okini3939 | 3:058292da2cee | 98 | if (i < sizeof(buf) - 1) tcp_readable = 0; |
okini3939 | 3:058292da2cee | 99 | buf[i] = 0; |
okini3939 | 3:058292da2cee | 100 | #ifdef DEBUG |
okini3939 | 3:058292da2cee | 101 | printf(buf); |
okini3939 | 3:058292da2cee | 102 | #endif |
okini3939 | 3:058292da2cee | 103 | |
okini3939 | 3:058292da2cee | 104 | // check return code |
okini3939 | 3:058292da2cee | 105 | if (atoi(buf) == code) return 0; |
okini3939 | 3:058292da2cee | 106 | |
okini3939 | 3:058292da2cee | 107 | return -1; |
okini3939 | 3:058292da2cee | 108 | } |
okini3939 | 3:058292da2cee | 109 | |
okini3939 | 3:058292da2cee | 110 | static void isr_dns (DNSReply r) { |
okini3939 | 3:058292da2cee | 111 | |
okini3939 | 3:058292da2cee | 112 | #ifdef DEBUG |
okini3939 | 3:058292da2cee | 113 | printf("dns(%d)\r\n", r); |
okini3939 | 3:058292da2cee | 114 | #endif |
okini3939 | 3:058292da2cee | 115 | if (DNS_FOUND) { |
okini3939 | 3:058292da2cee | 116 | dns_status = 1; |
okini3939 | 3:058292da2cee | 117 | } else { |
okini3939 | 3:058292da2cee | 118 | dns_status = -1; |
okini3939 | 3:058292da2cee | 119 | } |
okini3939 | 3:058292da2cee | 120 | } |
okini3939 | 3:058292da2cee | 121 | |
okini3939 | 3:058292da2cee | 122 | int sendmail (char *to, char *from, char *data, Host *host, char *user, char *pwd) { |
okini3939 | 3:058292da2cee | 123 | TCPSocketErr err; |
okini3939 | 3:058292da2cee | 124 | Timer timeout; |
okini3939 | 3:058292da2cee | 125 | int ret = -1; |
okini3939 | 3:058292da2cee | 126 | |
okini3939 | 3:058292da2cee | 127 | smtp = new TCPSocket; |
okini3939 | 3:058292da2cee | 128 | tcp_ready = 0; |
okini3939 | 3:058292da2cee | 129 | tcp_readable = 0; |
okini3939 | 3:058292da2cee | 130 | tcp_writable = 0; |
okini3939 | 3:058292da2cee | 131 | |
okini3939 | 3:058292da2cee | 132 | smtp->setOnEvent(isr_smtp); |
okini3939 | 3:058292da2cee | 133 | |
okini3939 | 3:058292da2cee | 134 | // connect |
okini3939 | 3:058292da2cee | 135 | if (host->getIp().isNull()) { |
okini3939 | 3:058292da2cee | 136 | DNSRequest dns; |
okini3939 | 3:058292da2cee | 137 | dns_status = 0; |
okini3939 | 3:058292da2cee | 138 | dns.setOnReply(isr_dns); |
okini3939 | 3:058292da2cee | 139 | if (dns.resolve(host) != DNS_OK) goto exit; |
okini3939 | 3:058292da2cee | 140 | timeout.reset(); |
okini3939 | 3:058292da2cee | 141 | timeout.start(); |
okini3939 | 3:058292da2cee | 142 | while (timeout.read_ms() < SMTP_TIMEOUT) { |
okini3939 | 3:058292da2cee | 143 | if (dns_status) break; |
okini3939 | 3:058292da2cee | 144 | Net::poll(); |
okini3939 | 3:058292da2cee | 145 | } |
okini3939 | 3:058292da2cee | 146 | timeout.stop(); |
okini3939 | 3:058292da2cee | 147 | if (dns_status <= 0) goto exit; |
okini3939 | 3:058292da2cee | 148 | #ifdef DEBUG |
okini3939 | 3:058292da2cee | 149 | printf("%s [%d.%d.%d.%d]\r\n", host->getName(), (unsigned char)host->getIp()[0], (unsigned char)host->getIp()[1], (unsigned char)host->getIp()[2], (unsigned char)host->getIp()[3]); |
okini3939 | 3:058292da2cee | 150 | #endif |
okini3939 | 3:058292da2cee | 151 | } |
okini3939 | 3:058292da2cee | 152 | if (! host->getPort()) { |
okini3939 | 3:058292da2cee | 153 | host->setPort(SMTP_PORT); |
okini3939 | 3:058292da2cee | 154 | } |
okini3939 | 3:058292da2cee | 155 | |
okini3939 | 3:058292da2cee | 156 | err = smtp->connect(*host); |
okini3939 | 3:058292da2cee | 157 | if (err != TCPSOCKET_OK) goto exit; |
okini3939 | 3:058292da2cee | 158 | |
okini3939 | 3:058292da2cee | 159 | // wait connect |
okini3939 | 3:058292da2cee | 160 | timeout.reset(); |
okini3939 | 3:058292da2cee | 161 | timeout.start(); |
okini3939 | 3:058292da2cee | 162 | while (timeout.read_ms() < SMTP_TIMEOUT) { |
okini3939 | 3:058292da2cee | 163 | if (tcp_ready) break; |
okini3939 | 3:058292da2cee | 164 | Net::poll(); |
okini3939 | 3:058292da2cee | 165 | } |
okini3939 | 3:058292da2cee | 166 | timeout.stop(); |
okini3939 | 3:058292da2cee | 167 | if (! tcp_ready) goto exit; |
okini3939 | 3:058292da2cee | 168 | if (wait_smtp(220)) goto exit; |
okini3939 | 3:058292da2cee | 169 | |
okini3939 | 3:058292da2cee | 170 | // send request |
okini3939 | 3:058292da2cee | 171 | wait_ms(100); |
okini3939 | 3:058292da2cee | 172 | smtp->send("EHLO mbed\r\n", 11); |
okini3939 | 3:058292da2cee | 173 | if (wait_smtp(250)) goto exit; |
okini3939 | 3:058292da2cee | 174 | |
okini3939 | 3:058292da2cee | 175 | if (user && pwd) { |
okini3939 | 3:058292da2cee | 176 | // smtp auth |
okini3939 | 3:058292da2cee | 177 | char tmp[80], buf[100]; |
okini3939 | 3:058292da2cee | 178 | int len; |
okini3939 | 3:058292da2cee | 179 | snprintf(tmp, sizeof(tmp), "%s%c%s%c%s", user, 0, user, 0, pwd); |
okini3939 | 3:058292da2cee | 180 | len = strlen(user) * 2 + strlen(pwd) + 2; |
okini3939 | 3:058292da2cee | 181 | base64enc(tmp, len, buf, sizeof(buf)); |
okini3939 | 3:058292da2cee | 182 | smtp->send("AUTH PLAIN ", 11); |
okini3939 | 3:058292da2cee | 183 | smtp->send(buf, strlen(buf)); |
okini3939 | 3:058292da2cee | 184 | smtp->send("\r\n", 2); |
okini3939 | 3:058292da2cee | 185 | if (wait_smtp(235)) goto quit; |
okini3939 | 3:058292da2cee | 186 | } |
okini3939 | 3:058292da2cee | 187 | |
okini3939 | 3:058292da2cee | 188 | smtp->send("MAIL FROM: ", 11); |
okini3939 | 3:058292da2cee | 189 | smtp->send(from, strlen(from)); |
okini3939 | 3:058292da2cee | 190 | smtp->send("\r\n", 2); |
okini3939 | 3:058292da2cee | 191 | if (wait_smtp(250)) goto quit; |
okini3939 | 3:058292da2cee | 192 | |
okini3939 | 3:058292da2cee | 193 | smtp->send("RCPT TO: ", 9); |
okini3939 | 3:058292da2cee | 194 | smtp->send(to, strlen(to)); |
okini3939 | 3:058292da2cee | 195 | smtp->send("\r\n", 2); |
okini3939 | 3:058292da2cee | 196 | if (wait_smtp(250)) goto quit; |
okini3939 | 3:058292da2cee | 197 | |
okini3939 | 3:058292da2cee | 198 | smtp->send("DATA\r\n", 6); |
okini3939 | 3:058292da2cee | 199 | if (wait_smtp(354)) goto quit; |
okini3939 | 3:058292da2cee | 200 | |
okini3939 | 3:058292da2cee | 201 | // mail data |
okini3939 | 3:058292da2cee | 202 | smtp->send(data, strlen(data)); |
okini3939 | 3:058292da2cee | 203 | smtp->send("\r\n.\r\n", 5); |
okini3939 | 3:058292da2cee | 204 | if (wait_smtp(250)) goto quit; |
okini3939 | 3:058292da2cee | 205 | ret = 0; |
okini3939 | 3:058292da2cee | 206 | |
okini3939 | 3:058292da2cee | 207 | quit: |
okini3939 | 3:058292da2cee | 208 | smtp->send("QUIT\r\n", 6); |
okini3939 | 3:058292da2cee | 209 | if (wait_smtp(221)) goto exit; |
okini3939 | 3:058292da2cee | 210 | |
okini3939 | 3:058292da2cee | 211 | exit: |
okini3939 | 3:058292da2cee | 212 | smtp->resetOnEvent(); |
okini3939 | 3:058292da2cee | 213 | smtp->close(); |
okini3939 | 3:058292da2cee | 214 | delete smtp; |
okini3939 | 3:058292da2cee | 215 | |
okini3939 | 3:058292da2cee | 216 | return ret; |
okini3939 | 3:058292da2cee | 217 | } |