Webserver+3d print

Dependents:   Nucleo

Committer:
Sergunb
Date:
Sat Feb 04 18:15:49 2017 +0000
Revision:
0:8918a71cdbe9
nothing else

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sergunb 0:8918a71cdbe9 1 /**
Sergunb 0:8918a71cdbe9 2 * @file smtp_client.c
Sergunb 0:8918a71cdbe9 3 * @brief SMTP client (Simple Mail Transfer Protocol)
Sergunb 0:8918a71cdbe9 4 *
Sergunb 0:8918a71cdbe9 5 * @section License
Sergunb 0:8918a71cdbe9 6 *
Sergunb 0:8918a71cdbe9 7 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
Sergunb 0:8918a71cdbe9 8 *
Sergunb 0:8918a71cdbe9 9 * This file is part of CycloneTCP Open.
Sergunb 0:8918a71cdbe9 10 *
Sergunb 0:8918a71cdbe9 11 * This program is free software; you can redistribute it and/or
Sergunb 0:8918a71cdbe9 12 * modify it under the terms of the GNU General Public License
Sergunb 0:8918a71cdbe9 13 * as published by the Free Software Foundation; either version 2
Sergunb 0:8918a71cdbe9 14 * of the License, or (at your option) any later version.
Sergunb 0:8918a71cdbe9 15 *
Sergunb 0:8918a71cdbe9 16 * This program is distributed in the hope that it will be useful,
Sergunb 0:8918a71cdbe9 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Sergunb 0:8918a71cdbe9 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Sergunb 0:8918a71cdbe9 19 * GNU General Public License for more details.
Sergunb 0:8918a71cdbe9 20 *
Sergunb 0:8918a71cdbe9 21 * You should have received a copy of the GNU General Public License
Sergunb 0:8918a71cdbe9 22 * along with this program; if not, write to the Free Software Foundation,
Sergunb 0:8918a71cdbe9 23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Sergunb 0:8918a71cdbe9 24 *
Sergunb 0:8918a71cdbe9 25 * @section Description
Sergunb 0:8918a71cdbe9 26 *
Sergunb 0:8918a71cdbe9 27 * SMTP is designed as a mail transport and delivery protocol. Refer to
Sergunb 0:8918a71cdbe9 28 * the following RFCs for complete details:
Sergunb 0:8918a71cdbe9 29 * - RFC 5321: Simple Mail Transfer Protocol
Sergunb 0:8918a71cdbe9 30 * - RFC 4954: SMTP Service Extension for Authentication
Sergunb 0:8918a71cdbe9 31 * - RFC 3207: SMTP Service Extension for Secure SMTP over TLS
Sergunb 0:8918a71cdbe9 32 *
Sergunb 0:8918a71cdbe9 33 * @author Oryx Embedded SARL (www.oryx-embedded.com)
Sergunb 0:8918a71cdbe9 34 * @version 1.7.6
Sergunb 0:8918a71cdbe9 35 **/
Sergunb 0:8918a71cdbe9 36
Sergunb 0:8918a71cdbe9 37 //Switch to the appropriate trace level
Sergunb 0:8918a71cdbe9 38 #define TRACE_LEVEL SMTP_TRACE_LEVEL
Sergunb 0:8918a71cdbe9 39
Sergunb 0:8918a71cdbe9 40 //Dependencies
Sergunb 0:8918a71cdbe9 41 #include <string.h>
Sergunb 0:8918a71cdbe9 42 #include <ctype.h>
Sergunb 0:8918a71cdbe9 43 #include <stdlib.h>
Sergunb 0:8918a71cdbe9 44 #include "core/net.h"
Sergunb 0:8918a71cdbe9 45 #include "smtp/smtp_client.h"
Sergunb 0:8918a71cdbe9 46 #include "core/socket.h"
Sergunb 0:8918a71cdbe9 47 #include "str.h"
Sergunb 0:8918a71cdbe9 48 #include "debug.h"
Sergunb 0:8918a71cdbe9 49
Sergunb 0:8918a71cdbe9 50 //Check TCP/IP stack configuration
Sergunb 0:8918a71cdbe9 51 #if (SMTP_CLIENT_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 52
Sergunb 0:8918a71cdbe9 53
Sergunb 0:8918a71cdbe9 54 /**
Sergunb 0:8918a71cdbe9 55 * @brief Send a mail to the specified recipients
Sergunb 0:8918a71cdbe9 56 * @param[in] authInfo Authentication information
Sergunb 0:8918a71cdbe9 57 * @param[in] mail Mail contents
Sergunb 0:8918a71cdbe9 58 * @return Error code
Sergunb 0:8918a71cdbe9 59 **/
Sergunb 0:8918a71cdbe9 60
Sergunb 0:8918a71cdbe9 61 error_t smtpSendMail(const SmtpAuthInfo *authInfo, const SmtpMail *mail)
Sergunb 0:8918a71cdbe9 62 {
Sergunb 0:8918a71cdbe9 63 error_t error;
Sergunb 0:8918a71cdbe9 64 uint_t i;
Sergunb 0:8918a71cdbe9 65 uint_t replyCode;
Sergunb 0:8918a71cdbe9 66 IpAddr serverIpAddr;
Sergunb 0:8918a71cdbe9 67 SmtpClientContext *context;
Sergunb 0:8918a71cdbe9 68
Sergunb 0:8918a71cdbe9 69 //Check parameters
Sergunb 0:8918a71cdbe9 70 if(authInfo == NULL || mail == NULL)
Sergunb 0:8918a71cdbe9 71 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 72 //Make sure the server name is valid
Sergunb 0:8918a71cdbe9 73 if(authInfo->serverName == NULL)
Sergunb 0:8918a71cdbe9 74 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 75
Sergunb 0:8918a71cdbe9 76 //Debug message
Sergunb 0:8918a71cdbe9 77 TRACE_INFO("Sending a mail to %s port %" PRIu16 "...\r\n",
Sergunb 0:8918a71cdbe9 78 authInfo->serverName, authInfo->serverPort);
Sergunb 0:8918a71cdbe9 79
Sergunb 0:8918a71cdbe9 80 //The specified SMTP server can be either an IP or a host name
Sergunb 0:8918a71cdbe9 81 error = getHostByName(authInfo->interface,
Sergunb 0:8918a71cdbe9 82 authInfo->serverName, &serverIpAddr, 0);
Sergunb 0:8918a71cdbe9 83 //Unable to resolve server name?
Sergunb 0:8918a71cdbe9 84 if(error)
Sergunb 0:8918a71cdbe9 85 return ERROR_NAME_RESOLUTION_FAILED;
Sergunb 0:8918a71cdbe9 86
Sergunb 0:8918a71cdbe9 87 //Allocate a memory buffer to hold the SMTP client context
Sergunb 0:8918a71cdbe9 88 context = osAllocMem(sizeof(SmtpClientContext));
Sergunb 0:8918a71cdbe9 89 //Failed to allocate memory?
Sergunb 0:8918a71cdbe9 90 if(context == NULL)
Sergunb 0:8918a71cdbe9 91 return ERROR_OUT_OF_MEMORY;
Sergunb 0:8918a71cdbe9 92
Sergunb 0:8918a71cdbe9 93 //Open a TCP socket
Sergunb 0:8918a71cdbe9 94 context->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
Sergunb 0:8918a71cdbe9 95 //Failed to open socket?
Sergunb 0:8918a71cdbe9 96 if(!context->socket)
Sergunb 0:8918a71cdbe9 97 {
Sergunb 0:8918a71cdbe9 98 //Free previously allocated resources
Sergunb 0:8918a71cdbe9 99 osFreeMem(context);
Sergunb 0:8918a71cdbe9 100 //Report an error
Sergunb 0:8918a71cdbe9 101 return ERROR_OPEN_FAILED;
Sergunb 0:8918a71cdbe9 102 }
Sergunb 0:8918a71cdbe9 103
Sergunb 0:8918a71cdbe9 104 #if (SMTP_CLIENT_TLS_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 105 //Do not use SSL/TLS for the moment
Sergunb 0:8918a71cdbe9 106 context->tlsContext = NULL;
Sergunb 0:8918a71cdbe9 107 #endif
Sergunb 0:8918a71cdbe9 108
Sergunb 0:8918a71cdbe9 109 //Start of exception handling block
Sergunb 0:8918a71cdbe9 110 do
Sergunb 0:8918a71cdbe9 111 {
Sergunb 0:8918a71cdbe9 112 //Bind the socket to a particular network interface?
Sergunb 0:8918a71cdbe9 113 if(authInfo->interface)
Sergunb 0:8918a71cdbe9 114 {
Sergunb 0:8918a71cdbe9 115 //Associate the socket with the relevant interface
Sergunb 0:8918a71cdbe9 116 error = socketBindToInterface(context->socket, authInfo->interface);
Sergunb 0:8918a71cdbe9 117 //Any error to report?
Sergunb 0:8918a71cdbe9 118 if(error)
Sergunb 0:8918a71cdbe9 119 break;
Sergunb 0:8918a71cdbe9 120 }
Sergunb 0:8918a71cdbe9 121
Sergunb 0:8918a71cdbe9 122 //Set timeout for blocking operations
Sergunb 0:8918a71cdbe9 123 error = socketSetTimeout(context->socket, SMTP_CLIENT_DEFAULT_TIMEOUT);
Sergunb 0:8918a71cdbe9 124 //Any error to report?
Sergunb 0:8918a71cdbe9 125 if(error)
Sergunb 0:8918a71cdbe9 126 break;
Sergunb 0:8918a71cdbe9 127
Sergunb 0:8918a71cdbe9 128 //Connect to the SMTP server
Sergunb 0:8918a71cdbe9 129 error = socketConnect(context->socket, &serverIpAddr, authInfo->serverPort);
Sergunb 0:8918a71cdbe9 130 //Connection to server failed?
Sergunb 0:8918a71cdbe9 131 if(error)
Sergunb 0:8918a71cdbe9 132 break;
Sergunb 0:8918a71cdbe9 133
Sergunb 0:8918a71cdbe9 134 #if (SMTP_CLIENT_TLS_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 135 //Open a secure SSL/TLS session?
Sergunb 0:8918a71cdbe9 136 if(authInfo->useTls)
Sergunb 0:8918a71cdbe9 137 {
Sergunb 0:8918a71cdbe9 138 //Initialize TLS context
Sergunb 0:8918a71cdbe9 139 context->tlsContext = tlsInit();
Sergunb 0:8918a71cdbe9 140 //Initialization failed?
Sergunb 0:8918a71cdbe9 141 if(context->tlsContext == NULL)
Sergunb 0:8918a71cdbe9 142 {
Sergunb 0:8918a71cdbe9 143 //Unable to allocate memory
Sergunb 0:8918a71cdbe9 144 error = ERROR_OUT_OF_MEMORY;
Sergunb 0:8918a71cdbe9 145 //Stop immediately
Sergunb 0:8918a71cdbe9 146 break;
Sergunb 0:8918a71cdbe9 147 }
Sergunb 0:8918a71cdbe9 148
Sergunb 0:8918a71cdbe9 149 //Bind TLS to the relevant socket
Sergunb 0:8918a71cdbe9 150 error = tlsSetSocket(context->tlsContext, context->socket);
Sergunb 0:8918a71cdbe9 151 //Any error to report?
Sergunb 0:8918a71cdbe9 152 if(error)
Sergunb 0:8918a71cdbe9 153 break;
Sergunb 0:8918a71cdbe9 154
Sergunb 0:8918a71cdbe9 155 //Select client operation mode
Sergunb 0:8918a71cdbe9 156 error = tlsSetConnectionEnd(context->tlsContext, TLS_CONNECTION_END_CLIENT);
Sergunb 0:8918a71cdbe9 157 //Any error to report?
Sergunb 0:8918a71cdbe9 158 if(error)
Sergunb 0:8918a71cdbe9 159 break;
Sergunb 0:8918a71cdbe9 160
Sergunb 0:8918a71cdbe9 161 //Set the PRNG algorithm to be used
Sergunb 0:8918a71cdbe9 162 error = tlsSetPrng(context->tlsContext, authInfo->prngAlgo, authInfo->prngContext);
Sergunb 0:8918a71cdbe9 163 //Any error to report?
Sergunb 0:8918a71cdbe9 164 if(error)
Sergunb 0:8918a71cdbe9 165 break;
Sergunb 0:8918a71cdbe9 166
Sergunb 0:8918a71cdbe9 167 //Perform TLS handshake
Sergunb 0:8918a71cdbe9 168 error = tlsConnect(context->tlsContext);
Sergunb 0:8918a71cdbe9 169 //Failed to established a TLS session?
Sergunb 0:8918a71cdbe9 170 if(error)
Sergunb 0:8918a71cdbe9 171 break;
Sergunb 0:8918a71cdbe9 172 }
Sergunb 0:8918a71cdbe9 173 #endif
Sergunb 0:8918a71cdbe9 174
Sergunb 0:8918a71cdbe9 175 //Wait for the connection greeting reply
Sergunb 0:8918a71cdbe9 176 error = smtpSendCommand(context, NULL, &replyCode, NULL);
Sergunb 0:8918a71cdbe9 177 //Any communication error to report?
Sergunb 0:8918a71cdbe9 178 if(error)
Sergunb 0:8918a71cdbe9 179 break;
Sergunb 0:8918a71cdbe9 180
Sergunb 0:8918a71cdbe9 181 //Check whether the greeting message was properly received
Sergunb 0:8918a71cdbe9 182 if(!SMTP_REPLY_CODE_2YZ(replyCode))
Sergunb 0:8918a71cdbe9 183 {
Sergunb 0:8918a71cdbe9 184 //An unexpected response was received...
Sergunb 0:8918a71cdbe9 185 error = ERROR_UNEXPECTED_RESPONSE;
Sergunb 0:8918a71cdbe9 186 //Stop immediately
Sergunb 0:8918a71cdbe9 187 break;
Sergunb 0:8918a71cdbe9 188 }
Sergunb 0:8918a71cdbe9 189
Sergunb 0:8918a71cdbe9 190 //Clear security features
Sergunb 0:8918a71cdbe9 191 context->authLoginSupported = FALSE;
Sergunb 0:8918a71cdbe9 192 context->authPlainSupported = FALSE;
Sergunb 0:8918a71cdbe9 193 context->authCramMd5Supported = FALSE;
Sergunb 0:8918a71cdbe9 194 context->startTlsSupported = FALSE;
Sergunb 0:8918a71cdbe9 195
Sergunb 0:8918a71cdbe9 196 //Send EHLO command and parse server response
Sergunb 0:8918a71cdbe9 197 error = smtpSendCommand(context, "EHLO [127.0.0.1]\r\n",
Sergunb 0:8918a71cdbe9 198 &replyCode, smtpEhloReplyCallback);
Sergunb 0:8918a71cdbe9 199 //Any communication error to report?
Sergunb 0:8918a71cdbe9 200 if(error)
Sergunb 0:8918a71cdbe9 201 break;
Sergunb 0:8918a71cdbe9 202
Sergunb 0:8918a71cdbe9 203 //Check SMTP response code
Sergunb 0:8918a71cdbe9 204 if(!SMTP_REPLY_CODE_2YZ(replyCode))
Sergunb 0:8918a71cdbe9 205 {
Sergunb 0:8918a71cdbe9 206 //An unexpected response was received...
Sergunb 0:8918a71cdbe9 207 error = ERROR_UNEXPECTED_RESPONSE;
Sergunb 0:8918a71cdbe9 208 //Stop immediately
Sergunb 0:8918a71cdbe9 209 break;
Sergunb 0:8918a71cdbe9 210 }
Sergunb 0:8918a71cdbe9 211
Sergunb 0:8918a71cdbe9 212 #if (SMTP_CLIENT_TLS_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 213 //Check whether the STARTTLS command is supported
Sergunb 0:8918a71cdbe9 214 if(context->startTlsSupported && !context->tlsContext)
Sergunb 0:8918a71cdbe9 215 {
Sergunb 0:8918a71cdbe9 216 //Send STARTTLS command
Sergunb 0:8918a71cdbe9 217 error = smtpSendCommand(context, "STARTTLS\r\n", &replyCode, NULL);
Sergunb 0:8918a71cdbe9 218 //Any communication error to report?
Sergunb 0:8918a71cdbe9 219 if(error)
Sergunb 0:8918a71cdbe9 220 break;
Sergunb 0:8918a71cdbe9 221
Sergunb 0:8918a71cdbe9 222 //Check SMTP response code
Sergunb 0:8918a71cdbe9 223 if(!SMTP_REPLY_CODE_2YZ(replyCode))
Sergunb 0:8918a71cdbe9 224 {
Sergunb 0:8918a71cdbe9 225 //An unexpected response was received...
Sergunb 0:8918a71cdbe9 226 error = ERROR_UNEXPECTED_RESPONSE;
Sergunb 0:8918a71cdbe9 227 //Stop immediately
Sergunb 0:8918a71cdbe9 228 break;
Sergunb 0:8918a71cdbe9 229 }
Sergunb 0:8918a71cdbe9 230
Sergunb 0:8918a71cdbe9 231 //Initialize TLS context
Sergunb 0:8918a71cdbe9 232 context->tlsContext = tlsInit();
Sergunb 0:8918a71cdbe9 233 //Initialization failed?
Sergunb 0:8918a71cdbe9 234 if(context->tlsContext == NULL)
Sergunb 0:8918a71cdbe9 235 {
Sergunb 0:8918a71cdbe9 236 //Unable to allocate memory
Sergunb 0:8918a71cdbe9 237 error = ERROR_OUT_OF_MEMORY;
Sergunb 0:8918a71cdbe9 238 //Stop immediately
Sergunb 0:8918a71cdbe9 239 break;
Sergunb 0:8918a71cdbe9 240 }
Sergunb 0:8918a71cdbe9 241
Sergunb 0:8918a71cdbe9 242 //Bind TLS to the relevant socket
Sergunb 0:8918a71cdbe9 243 error = tlsSetSocket(context->tlsContext, context->socket);
Sergunb 0:8918a71cdbe9 244 //Any error to report?
Sergunb 0:8918a71cdbe9 245 if(error)
Sergunb 0:8918a71cdbe9 246 break;
Sergunb 0:8918a71cdbe9 247
Sergunb 0:8918a71cdbe9 248 //Select client operation mode
Sergunb 0:8918a71cdbe9 249 error = tlsSetConnectionEnd(context->tlsContext, TLS_CONNECTION_END_CLIENT);
Sergunb 0:8918a71cdbe9 250 //Any error to report?
Sergunb 0:8918a71cdbe9 251 if(error)
Sergunb 0:8918a71cdbe9 252 break;
Sergunb 0:8918a71cdbe9 253
Sergunb 0:8918a71cdbe9 254 //Set the PRNG algorithm to be used
Sergunb 0:8918a71cdbe9 255 error = tlsSetPrng(context->tlsContext, authInfo->prngAlgo, authInfo->prngContext);
Sergunb 0:8918a71cdbe9 256 //Any error to report?
Sergunb 0:8918a71cdbe9 257 if(error)
Sergunb 0:8918a71cdbe9 258 break;
Sergunb 0:8918a71cdbe9 259
Sergunb 0:8918a71cdbe9 260 //Perform TLS handshake
Sergunb 0:8918a71cdbe9 261 error = tlsConnect(context->tlsContext);
Sergunb 0:8918a71cdbe9 262 //Failed to established a TLS session?
Sergunb 0:8918a71cdbe9 263 if(error)
Sergunb 0:8918a71cdbe9 264 break;
Sergunb 0:8918a71cdbe9 265
Sergunb 0:8918a71cdbe9 266 //Clear security features
Sergunb 0:8918a71cdbe9 267 context->authLoginSupported = FALSE;
Sergunb 0:8918a71cdbe9 268 context->authPlainSupported = FALSE;
Sergunb 0:8918a71cdbe9 269 context->authCramMd5Supported = FALSE;
Sergunb 0:8918a71cdbe9 270
Sergunb 0:8918a71cdbe9 271 //Send EHLO command and parse server response
Sergunb 0:8918a71cdbe9 272 error = smtpSendCommand(context, "EHLO [127.0.0.1]\r\n",
Sergunb 0:8918a71cdbe9 273 &replyCode, smtpEhloReplyCallback);
Sergunb 0:8918a71cdbe9 274 //Any communication error to report?
Sergunb 0:8918a71cdbe9 275 if(error)
Sergunb 0:8918a71cdbe9 276 break;
Sergunb 0:8918a71cdbe9 277
Sergunb 0:8918a71cdbe9 278 //Check SMTP response code
Sergunb 0:8918a71cdbe9 279 if(!SMTP_REPLY_CODE_2YZ(replyCode))
Sergunb 0:8918a71cdbe9 280 {
Sergunb 0:8918a71cdbe9 281 //An unexpected response was received...
Sergunb 0:8918a71cdbe9 282 error = ERROR_UNEXPECTED_RESPONSE;
Sergunb 0:8918a71cdbe9 283 //Stop immediately
Sergunb 0:8918a71cdbe9 284 break;
Sergunb 0:8918a71cdbe9 285 }
Sergunb 0:8918a71cdbe9 286 }
Sergunb 0:8918a71cdbe9 287 #endif
Sergunb 0:8918a71cdbe9 288
Sergunb 0:8918a71cdbe9 289 //Authentication requires a valid user name and password
Sergunb 0:8918a71cdbe9 290 if(authInfo->userName && authInfo->password)
Sergunb 0:8918a71cdbe9 291 {
Sergunb 0:8918a71cdbe9 292 #if (SMTP_CLIENT_LOGIN_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 293 //LOGIN authentication mechanism supported?
Sergunb 0:8918a71cdbe9 294 if(context->authLoginSupported)
Sergunb 0:8918a71cdbe9 295 {
Sergunb 0:8918a71cdbe9 296 //Perform LOGIN authentication
Sergunb 0:8918a71cdbe9 297 error = smtpSendAuthLogin(context, authInfo);
Sergunb 0:8918a71cdbe9 298 //Authentication failed?
Sergunb 0:8918a71cdbe9 299 if(error)
Sergunb 0:8918a71cdbe9 300 break;
Sergunb 0:8918a71cdbe9 301 }
Sergunb 0:8918a71cdbe9 302 else
Sergunb 0:8918a71cdbe9 303 #endif
Sergunb 0:8918a71cdbe9 304 #if (SMTP_CLIENT_PLAIN_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 305 //PLAIN authentication mechanism supported?
Sergunb 0:8918a71cdbe9 306 if(context->authPlainSupported)
Sergunb 0:8918a71cdbe9 307 {
Sergunb 0:8918a71cdbe9 308 //Perform PLAIN authentication
Sergunb 0:8918a71cdbe9 309 error = smtpSendAuthPlain(context, authInfo);
Sergunb 0:8918a71cdbe9 310 //Authentication failed?
Sergunb 0:8918a71cdbe9 311 if(error)
Sergunb 0:8918a71cdbe9 312 break;
Sergunb 0:8918a71cdbe9 313 }
Sergunb 0:8918a71cdbe9 314 else
Sergunb 0:8918a71cdbe9 315 #endif
Sergunb 0:8918a71cdbe9 316 #if (SMTP_CLIENT_CRAM_MD5_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 317 //CRAM-MD5 authentication mechanism supported?
Sergunb 0:8918a71cdbe9 318 if(context->authCramMd5Supported)
Sergunb 0:8918a71cdbe9 319 {
Sergunb 0:8918a71cdbe9 320 //Perform CRAM-MD5 authentication
Sergunb 0:8918a71cdbe9 321 error = smtpSendAuthCramMd5(context, authInfo);
Sergunb 0:8918a71cdbe9 322 //Authentication failed?
Sergunb 0:8918a71cdbe9 323 if(error)
Sergunb 0:8918a71cdbe9 324 break;
Sergunb 0:8918a71cdbe9 325 }
Sergunb 0:8918a71cdbe9 326 else
Sergunb 0:8918a71cdbe9 327 #endif
Sergunb 0:8918a71cdbe9 328 //No authentication mechanism supported?
Sergunb 0:8918a71cdbe9 329 {
Sergunb 0:8918a71cdbe9 330 //Skip authentication step
Sergunb 0:8918a71cdbe9 331 }
Sergunb 0:8918a71cdbe9 332 }
Sergunb 0:8918a71cdbe9 333
Sergunb 0:8918a71cdbe9 334 //Format the MAIL FROM command (a null return path must be accepted)
Sergunb 0:8918a71cdbe9 335 if(mail->from.addr)
Sergunb 0:8918a71cdbe9 336 sprintf(context->buffer, "MAIL FROM:<%s>\r\n", mail->from.addr);
Sergunb 0:8918a71cdbe9 337 else
Sergunb 0:8918a71cdbe9 338 strcpy(context->buffer, "MAIL FROM:<>\r\n");
Sergunb 0:8918a71cdbe9 339
Sergunb 0:8918a71cdbe9 340 //Send the command to the server
Sergunb 0:8918a71cdbe9 341 error = smtpSendCommand(context, context->buffer, &replyCode, NULL);
Sergunb 0:8918a71cdbe9 342 //Any communication error to report?
Sergunb 0:8918a71cdbe9 343 if(error)
Sergunb 0:8918a71cdbe9 344 break;
Sergunb 0:8918a71cdbe9 345
Sergunb 0:8918a71cdbe9 346 //Check SMTP response code
Sergunb 0:8918a71cdbe9 347 if(!SMTP_REPLY_CODE_2YZ(replyCode))
Sergunb 0:8918a71cdbe9 348 {
Sergunb 0:8918a71cdbe9 349 //An unexpected response was received...
Sergunb 0:8918a71cdbe9 350 error = ERROR_UNEXPECTED_RESPONSE;
Sergunb 0:8918a71cdbe9 351 //Stop immediately
Sergunb 0:8918a71cdbe9 352 break;
Sergunb 0:8918a71cdbe9 353 }
Sergunb 0:8918a71cdbe9 354
Sergunb 0:8918a71cdbe9 355 //Format the RCPT TO command
Sergunb 0:8918a71cdbe9 356 for(i = 0; i < mail->recipientCount; i++)
Sergunb 0:8918a71cdbe9 357 {
Sergunb 0:8918a71cdbe9 358 //Skip recipient addresses that are not valid
Sergunb 0:8918a71cdbe9 359 if(!mail->recipients[i].addr)
Sergunb 0:8918a71cdbe9 360 continue;
Sergunb 0:8918a71cdbe9 361
Sergunb 0:8918a71cdbe9 362 //Format the RCPT TO command
Sergunb 0:8918a71cdbe9 363 sprintf(context->buffer, "RCPT TO:<%s>\r\n", mail->recipients[i].addr);
Sergunb 0:8918a71cdbe9 364 //Send the command to the server
Sergunb 0:8918a71cdbe9 365 error = smtpSendCommand(context, context->buffer, &replyCode, NULL);
Sergunb 0:8918a71cdbe9 366 //Any communication error to report?
Sergunb 0:8918a71cdbe9 367 if(error)
Sergunb 0:8918a71cdbe9 368 break;
Sergunb 0:8918a71cdbe9 369
Sergunb 0:8918a71cdbe9 370 //Check SMTP response code
Sergunb 0:8918a71cdbe9 371 if(!SMTP_REPLY_CODE_2YZ(replyCode))
Sergunb 0:8918a71cdbe9 372 {
Sergunb 0:8918a71cdbe9 373 //An unexpected response was received...
Sergunb 0:8918a71cdbe9 374 error = ERROR_UNEXPECTED_RESPONSE;
Sergunb 0:8918a71cdbe9 375 //Stop immediately
Sergunb 0:8918a71cdbe9 376 break;
Sergunb 0:8918a71cdbe9 377 }
Sergunb 0:8918a71cdbe9 378 }
Sergunb 0:8918a71cdbe9 379
Sergunb 0:8918a71cdbe9 380 //Propagate exception if necessary
Sergunb 0:8918a71cdbe9 381 if(error)
Sergunb 0:8918a71cdbe9 382 break;
Sergunb 0:8918a71cdbe9 383
Sergunb 0:8918a71cdbe9 384 //Send message body
Sergunb 0:8918a71cdbe9 385 error = smtpSendData(context, mail);
Sergunb 0:8918a71cdbe9 386 //Any error to report?
Sergunb 0:8918a71cdbe9 387 if(error)
Sergunb 0:8918a71cdbe9 388 break;
Sergunb 0:8918a71cdbe9 389
Sergunb 0:8918a71cdbe9 390 //End of exception handling block
Sergunb 0:8918a71cdbe9 391 } while(0);
Sergunb 0:8918a71cdbe9 392
Sergunb 0:8918a71cdbe9 393 //Check status code
Sergunb 0:8918a71cdbe9 394 if(error == NO_ERROR ||
Sergunb 0:8918a71cdbe9 395 error == ERROR_UNEXPECTED_RESPONSE ||
Sergunb 0:8918a71cdbe9 396 error == ERROR_AUTHENTICATION_FAILED)
Sergunb 0:8918a71cdbe9 397 {
Sergunb 0:8918a71cdbe9 398 //Properly disconnect from the SMTP server
Sergunb 0:8918a71cdbe9 399 smtpSendCommand(context, "QUIT\r\n", &replyCode, NULL);
Sergunb 0:8918a71cdbe9 400 }
Sergunb 0:8918a71cdbe9 401
Sergunb 0:8918a71cdbe9 402 #if (SMTP_CLIENT_TLS_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 403 if(context->tlsContext != NULL)
Sergunb 0:8918a71cdbe9 404 {
Sergunb 0:8918a71cdbe9 405 //Gracefully close SSL/TLS session
Sergunb 0:8918a71cdbe9 406 tlsShutdown(context->tlsContext);
Sergunb 0:8918a71cdbe9 407 //Release SSL/TLS context
Sergunb 0:8918a71cdbe9 408 tlsFree(context->tlsContext);
Sergunb 0:8918a71cdbe9 409 }
Sergunb 0:8918a71cdbe9 410 #endif
Sergunb 0:8918a71cdbe9 411
Sergunb 0:8918a71cdbe9 412 //Close socket
Sergunb 0:8918a71cdbe9 413 socketClose(context->socket);
Sergunb 0:8918a71cdbe9 414 //Clean up previously allocated resources
Sergunb 0:8918a71cdbe9 415 osFreeMem(context);
Sergunb 0:8918a71cdbe9 416
Sergunb 0:8918a71cdbe9 417 //Return status code
Sergunb 0:8918a71cdbe9 418 return error;
Sergunb 0:8918a71cdbe9 419 }
Sergunb 0:8918a71cdbe9 420
Sergunb 0:8918a71cdbe9 421
Sergunb 0:8918a71cdbe9 422 /**
Sergunb 0:8918a71cdbe9 423 * @brief Callback function to parse EHLO response
Sergunb 0:8918a71cdbe9 424 * @param[in] context SMTP client context
Sergunb 0:8918a71cdbe9 425 * @param[in] replyLine Response line
Sergunb 0:8918a71cdbe9 426 * @param[in] replyCode Response code
Sergunb 0:8918a71cdbe9 427 * @return Error code
Sergunb 0:8918a71cdbe9 428 **/
Sergunb 0:8918a71cdbe9 429
Sergunb 0:8918a71cdbe9 430 error_t smtpEhloReplyCallback(SmtpClientContext *context,
Sergunb 0:8918a71cdbe9 431 char_t *replyLine, uint_t replyCode)
Sergunb 0:8918a71cdbe9 432 {
Sergunb 0:8918a71cdbe9 433 char_t *p;
Sergunb 0:8918a71cdbe9 434 char_t *token;
Sergunb 0:8918a71cdbe9 435
Sergunb 0:8918a71cdbe9 436 //The line must be at least 4 characters long
Sergunb 0:8918a71cdbe9 437 if(strlen(replyLine) < 4)
Sergunb 0:8918a71cdbe9 438 return NO_ERROR;
Sergunb 0:8918a71cdbe9 439
Sergunb 0:8918a71cdbe9 440 //Skip the response code and the separator
Sergunb 0:8918a71cdbe9 441 replyLine += 4;
Sergunb 0:8918a71cdbe9 442
Sergunb 0:8918a71cdbe9 443 //Get the first keyword
Sergunb 0:8918a71cdbe9 444 token = strtok_r(replyLine, " ", &p);
Sergunb 0:8918a71cdbe9 445 //Check whether the response line is empty
Sergunb 0:8918a71cdbe9 446 if(token == NULL)
Sergunb 0:8918a71cdbe9 447 return ERROR_INVALID_SYNTAX;
Sergunb 0:8918a71cdbe9 448
Sergunb 0:8918a71cdbe9 449 //The AUTH keyword contains a space-separated list of
Sergunb 0:8918a71cdbe9 450 //names of available authentication mechanisms
Sergunb 0:8918a71cdbe9 451 if(!strcasecmp(token, "AUTH"))
Sergunb 0:8918a71cdbe9 452 {
Sergunb 0:8918a71cdbe9 453 //Process the rest of the line
Sergunb 0:8918a71cdbe9 454 while(1)
Sergunb 0:8918a71cdbe9 455 {
Sergunb 0:8918a71cdbe9 456 //Get the next keyword
Sergunb 0:8918a71cdbe9 457 token = strtok_r(NULL, " ", &p);
Sergunb 0:8918a71cdbe9 458 //Unable to find the next token?
Sergunb 0:8918a71cdbe9 459 if(token == NULL)
Sergunb 0:8918a71cdbe9 460 break;
Sergunb 0:8918a71cdbe9 461
Sergunb 0:8918a71cdbe9 462 //LOGIN authentication mechanism supported?
Sergunb 0:8918a71cdbe9 463 if(!strcasecmp(token, "LOGIN"))
Sergunb 0:8918a71cdbe9 464 context->authLoginSupported = TRUE;
Sergunb 0:8918a71cdbe9 465 //PLAIN authentication mechanism supported?
Sergunb 0:8918a71cdbe9 466 else if(!strcasecmp(token, "PLAIN"))
Sergunb 0:8918a71cdbe9 467 context->authPlainSupported = TRUE;
Sergunb 0:8918a71cdbe9 468 //CRAM-MD5 authentication mechanism supported?
Sergunb 0:8918a71cdbe9 469 else if(!strcasecmp(token, "CRAM-MD5"))
Sergunb 0:8918a71cdbe9 470 context->authCramMd5Supported = TRUE;
Sergunb 0:8918a71cdbe9 471 }
Sergunb 0:8918a71cdbe9 472 }
Sergunb 0:8918a71cdbe9 473 //The STARTTLS keyword is used to tell the SMTP client
Sergunb 0:8918a71cdbe9 474 //that the SMTP server allows use of TLS
Sergunb 0:8918a71cdbe9 475 else if(!strcasecmp(token, "STARTTLS"))
Sergunb 0:8918a71cdbe9 476 {
Sergunb 0:8918a71cdbe9 477 //STARTTLS use is allowed
Sergunb 0:8918a71cdbe9 478 context->startTlsSupported = TRUE;
Sergunb 0:8918a71cdbe9 479 }
Sergunb 0:8918a71cdbe9 480
Sergunb 0:8918a71cdbe9 481 //Successful processing
Sergunb 0:8918a71cdbe9 482 return NO_ERROR;
Sergunb 0:8918a71cdbe9 483 }
Sergunb 0:8918a71cdbe9 484
Sergunb 0:8918a71cdbe9 485
Sergunb 0:8918a71cdbe9 486 /**
Sergunb 0:8918a71cdbe9 487 * @brief Authentication using LOGIN mechanism
Sergunb 0:8918a71cdbe9 488 * @param[in] context SMTP client context
Sergunb 0:8918a71cdbe9 489 * @param[in] authInfo Authentication information
Sergunb 0:8918a71cdbe9 490 * @return Error code
Sergunb 0:8918a71cdbe9 491 **/
Sergunb 0:8918a71cdbe9 492
Sergunb 0:8918a71cdbe9 493 error_t smtpSendAuthLogin(SmtpClientContext *context, const SmtpAuthInfo *authInfo)
Sergunb 0:8918a71cdbe9 494 {
Sergunb 0:8918a71cdbe9 495 #if (SMTP_CLIENT_LOGIN_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 496 error_t error;
Sergunb 0:8918a71cdbe9 497 uint_t replyCode;
Sergunb 0:8918a71cdbe9 498
Sergunb 0:8918a71cdbe9 499 //Send AUTH LOGIN command
Sergunb 0:8918a71cdbe9 500 error = smtpSendCommand(context, "AUTH LOGIN\r\n", &replyCode, NULL);
Sergunb 0:8918a71cdbe9 501
Sergunb 0:8918a71cdbe9 502 //Any communication error to report?
Sergunb 0:8918a71cdbe9 503 if(error)
Sergunb 0:8918a71cdbe9 504 return error;
Sergunb 0:8918a71cdbe9 505 //Check SMTP reply code
Sergunb 0:8918a71cdbe9 506 if(!SMTP_REPLY_CODE_3YZ(replyCode))
Sergunb 0:8918a71cdbe9 507 return ERROR_AUTHENTICATION_FAILED;
Sergunb 0:8918a71cdbe9 508
Sergunb 0:8918a71cdbe9 509 //Encode the user name with Base64 algorithm
Sergunb 0:8918a71cdbe9 510 base64Encode(authInfo->userName, strlen(authInfo->userName), context->buffer, NULL);
Sergunb 0:8918a71cdbe9 511 //Add a line feed
Sergunb 0:8918a71cdbe9 512 strcat(context->buffer, "\r\n");
Sergunb 0:8918a71cdbe9 513
Sergunb 0:8918a71cdbe9 514 //Send the resulting string
Sergunb 0:8918a71cdbe9 515 error = smtpSendCommand(context, context->buffer, &replyCode, NULL);
Sergunb 0:8918a71cdbe9 516 //Any communication error to report?
Sergunb 0:8918a71cdbe9 517 if(error)
Sergunb 0:8918a71cdbe9 518 return error;
Sergunb 0:8918a71cdbe9 519
Sergunb 0:8918a71cdbe9 520 //Check SMTP reply code
Sergunb 0:8918a71cdbe9 521 if(!SMTP_REPLY_CODE_3YZ(replyCode))
Sergunb 0:8918a71cdbe9 522 return ERROR_AUTHENTICATION_FAILED;
Sergunb 0:8918a71cdbe9 523
Sergunb 0:8918a71cdbe9 524 //Encode the password with Base64 algorithm
Sergunb 0:8918a71cdbe9 525 base64Encode(authInfo->password, strlen(authInfo->password), context->buffer, NULL);
Sergunb 0:8918a71cdbe9 526 //Add a line feed
Sergunb 0:8918a71cdbe9 527 strcat(context->buffer, "\r\n");
Sergunb 0:8918a71cdbe9 528
Sergunb 0:8918a71cdbe9 529 //Send the resulting string
Sergunb 0:8918a71cdbe9 530 error = smtpSendCommand(context, context->buffer, &replyCode, NULL);
Sergunb 0:8918a71cdbe9 531 //Any communication error to report?
Sergunb 0:8918a71cdbe9 532 if(error)
Sergunb 0:8918a71cdbe9 533 return error;
Sergunb 0:8918a71cdbe9 534
Sergunb 0:8918a71cdbe9 535 //Check SMTP reply code
Sergunb 0:8918a71cdbe9 536 if(!SMTP_REPLY_CODE_2YZ(replyCode))
Sergunb 0:8918a71cdbe9 537 return ERROR_AUTHENTICATION_FAILED;
Sergunb 0:8918a71cdbe9 538
Sergunb 0:8918a71cdbe9 539 //Successful authentication
Sergunb 0:8918a71cdbe9 540 return NO_ERROR;
Sergunb 0:8918a71cdbe9 541 #else
Sergunb 0:8918a71cdbe9 542 //LOGIN authentication is not supported
Sergunb 0:8918a71cdbe9 543 return ERROR_AUTHENTICATION_FAILED;
Sergunb 0:8918a71cdbe9 544 #endif
Sergunb 0:8918a71cdbe9 545 }
Sergunb 0:8918a71cdbe9 546
Sergunb 0:8918a71cdbe9 547
Sergunb 0:8918a71cdbe9 548 /**
Sergunb 0:8918a71cdbe9 549 * @brief Authentication using PLAIN mechanism
Sergunb 0:8918a71cdbe9 550 * @param[in] context SMTP client context
Sergunb 0:8918a71cdbe9 551 * @param[in] authInfo Authentication information
Sergunb 0:8918a71cdbe9 552 * @return Error code
Sergunb 0:8918a71cdbe9 553 **/
Sergunb 0:8918a71cdbe9 554
Sergunb 0:8918a71cdbe9 555 error_t smtpSendAuthPlain(SmtpClientContext *context, const SmtpAuthInfo *authInfo)
Sergunb 0:8918a71cdbe9 556 {
Sergunb 0:8918a71cdbe9 557 #if (SMTP_CLIENT_PLAIN_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 558 error_t error;
Sergunb 0:8918a71cdbe9 559 uint_t n;
Sergunb 0:8918a71cdbe9 560 uint_t replyCode;
Sergunb 0:8918a71cdbe9 561
Sergunb 0:8918a71cdbe9 562 //Authorization identity
Sergunb 0:8918a71cdbe9 563 strcpy(context->buffer, authInfo->userName);
Sergunb 0:8918a71cdbe9 564 n = strlen(authInfo->userName) + 1;
Sergunb 0:8918a71cdbe9 565 //Authentication identity
Sergunb 0:8918a71cdbe9 566 strcpy(context->buffer + n, authInfo->userName);
Sergunb 0:8918a71cdbe9 567 n += strlen(authInfo->userName) + 1;
Sergunb 0:8918a71cdbe9 568 //Password
Sergunb 0:8918a71cdbe9 569 strcpy(context->buffer + n, authInfo->password);
Sergunb 0:8918a71cdbe9 570 n += strlen(authInfo->password);
Sergunb 0:8918a71cdbe9 571
Sergunb 0:8918a71cdbe9 572 //Base64 encoding
Sergunb 0:8918a71cdbe9 573 base64Encode(context->buffer, n, context->buffer2, NULL);
Sergunb 0:8918a71cdbe9 574 //Format the AUTH PLAIN command
Sergunb 0:8918a71cdbe9 575 sprintf(context->buffer, "AUTH PLAIN %s\r\n", context->buffer2);
Sergunb 0:8918a71cdbe9 576
Sergunb 0:8918a71cdbe9 577 //Send the command to the server
Sergunb 0:8918a71cdbe9 578 error = smtpSendCommand(context, context->buffer, &replyCode, NULL);
Sergunb 0:8918a71cdbe9 579 //Any communication error to report?
Sergunb 0:8918a71cdbe9 580 if(error)
Sergunb 0:8918a71cdbe9 581 return error;
Sergunb 0:8918a71cdbe9 582
Sergunb 0:8918a71cdbe9 583 //Check SMTP reply code
Sergunb 0:8918a71cdbe9 584 if(!SMTP_REPLY_CODE_2YZ(replyCode))
Sergunb 0:8918a71cdbe9 585 return ERROR_AUTHENTICATION_FAILED;
Sergunb 0:8918a71cdbe9 586
Sergunb 0:8918a71cdbe9 587 //Successful authentication
Sergunb 0:8918a71cdbe9 588 return NO_ERROR;
Sergunb 0:8918a71cdbe9 589 #else
Sergunb 0:8918a71cdbe9 590 //PLAIN authentication is not supported
Sergunb 0:8918a71cdbe9 591 return ERROR_AUTHENTICATION_FAILED;
Sergunb 0:8918a71cdbe9 592 #endif
Sergunb 0:8918a71cdbe9 593 }
Sergunb 0:8918a71cdbe9 594
Sergunb 0:8918a71cdbe9 595
Sergunb 0:8918a71cdbe9 596 /**
Sergunb 0:8918a71cdbe9 597 * @brief Authentication using CRAM-MD5 mechanism
Sergunb 0:8918a71cdbe9 598 * @param[in] context SMTP client context
Sergunb 0:8918a71cdbe9 599 * @param[in] authInfo Authentication information
Sergunb 0:8918a71cdbe9 600 * @return Error code
Sergunb 0:8918a71cdbe9 601 **/
Sergunb 0:8918a71cdbe9 602
Sergunb 0:8918a71cdbe9 603 error_t smtpSendAuthCramMd5(SmtpClientContext *context, const SmtpAuthInfo *authInfo)
Sergunb 0:8918a71cdbe9 604 {
Sergunb 0:8918a71cdbe9 605 #if (SMTP_CLIENT_CRAM_MD5_AUTH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 606 //Hex conversion table
Sergunb 0:8918a71cdbe9 607 static const char_t hexDigit[] =
Sergunb 0:8918a71cdbe9 608 {
Sergunb 0:8918a71cdbe9 609 '0', '1', '2', '3', '4', '5', '6', '7',
Sergunb 0:8918a71cdbe9 610 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
Sergunb 0:8918a71cdbe9 611 };
Sergunb 0:8918a71cdbe9 612
Sergunb 0:8918a71cdbe9 613 //Local variables
Sergunb 0:8918a71cdbe9 614 error_t error;
Sergunb 0:8918a71cdbe9 615 uint_t n;
Sergunb 0:8918a71cdbe9 616 uint_t replyCode;
Sergunb 0:8918a71cdbe9 617
Sergunb 0:8918a71cdbe9 618 //Alias pointers
Sergunb 0:8918a71cdbe9 619 uint8_t *challenge = (uint8_t *) context->buffer2;
Sergunb 0:8918a71cdbe9 620 uint8_t *digest = (uint8_t *) context->buffer;
Sergunb 0:8918a71cdbe9 621 char_t *textDigest = (char_t *) context->buffer2;
Sergunb 0:8918a71cdbe9 622
Sergunb 0:8918a71cdbe9 623 //Send AUTH CRAM-MD5 command
Sergunb 0:8918a71cdbe9 624 error = smtpSendCommand(context, "AUTH CRAM-MD5\r\n", &replyCode, NULL);
Sergunb 0:8918a71cdbe9 625 //Any communication error to report?
Sergunb 0:8918a71cdbe9 626 if(error)
Sergunb 0:8918a71cdbe9 627 return error;
Sergunb 0:8918a71cdbe9 628
Sergunb 0:8918a71cdbe9 629 //Check SMTP reply code
Sergunb 0:8918a71cdbe9 630 if(!SMTP_REPLY_CODE_3YZ(replyCode))
Sergunb 0:8918a71cdbe9 631 return ERROR_AUTHENTICATION_FAILED;
Sergunb 0:8918a71cdbe9 632
Sergunb 0:8918a71cdbe9 633 //Compute the length of the response
Sergunb 0:8918a71cdbe9 634 n = strlen(context->buffer);
Sergunb 0:8918a71cdbe9 635 //Unexpected response from the SMTP server?
Sergunb 0:8918a71cdbe9 636 if(n <= 4)
Sergunb 0:8918a71cdbe9 637 return ERROR_INVALID_SYNTAX;
Sergunb 0:8918a71cdbe9 638
Sergunb 0:8918a71cdbe9 639 //Decrypt the Base64 encoded challenge
Sergunb 0:8918a71cdbe9 640 error = base64Decode(context->buffer + 4, n - 4, challenge, &n);
Sergunb 0:8918a71cdbe9 641 //Decoding failed?
Sergunb 0:8918a71cdbe9 642 if(error)
Sergunb 0:8918a71cdbe9 643 return error;
Sergunb 0:8918a71cdbe9 644
Sergunb 0:8918a71cdbe9 645 //Compute HMAC using MD5
Sergunb 0:8918a71cdbe9 646 error = hmacCompute(MD5_HASH_ALGO, authInfo->password,
Sergunb 0:8918a71cdbe9 647 strlen(authInfo->password), challenge, n, digest);
Sergunb 0:8918a71cdbe9 648 //HMAC computation failed?
Sergunb 0:8918a71cdbe9 649 if(error)
Sergunb 0:8918a71cdbe9 650 return error;
Sergunb 0:8918a71cdbe9 651
Sergunb 0:8918a71cdbe9 652 //Convert the digest to text
Sergunb 0:8918a71cdbe9 653 for(n = 0; n < MD5_DIGEST_SIZE; n++)
Sergunb 0:8918a71cdbe9 654 {
Sergunb 0:8918a71cdbe9 655 //Convert upper nibble
Sergunb 0:8918a71cdbe9 656 textDigest[n * 2] = hexDigit[(digest[n] >> 4) & 0x0F];
Sergunb 0:8918a71cdbe9 657 //Then convert lower nibble
Sergunb 0:8918a71cdbe9 658 textDigest[n * 2 + 1] = hexDigit[digest[n] & 0x0F];
Sergunb 0:8918a71cdbe9 659 }
Sergunb 0:8918a71cdbe9 660
Sergunb 0:8918a71cdbe9 661 //Properly terminate the string
Sergunb 0:8918a71cdbe9 662 textDigest[MD5_DIGEST_SIZE * 2] = '\0';
Sergunb 0:8918a71cdbe9 663 //Concatenate the user name and the text representation of the digest
Sergunb 0:8918a71cdbe9 664 sprintf(context->buffer, "%s %s", authInfo->userName, textDigest);
Sergunb 0:8918a71cdbe9 665 //Encode the resulting string with Base64 algorithm
Sergunb 0:8918a71cdbe9 666 base64Encode(context->buffer, strlen(context->buffer), context->buffer2, NULL);
Sergunb 0:8918a71cdbe9 667 //Add a line feed
Sergunb 0:8918a71cdbe9 668 strcat(context->buffer2, "\r\n");
Sergunb 0:8918a71cdbe9 669
Sergunb 0:8918a71cdbe9 670 //Transmit the Base64 encoded string
Sergunb 0:8918a71cdbe9 671 error = smtpSendCommand(context, context->buffer2, &replyCode, NULL);
Sergunb 0:8918a71cdbe9 672 //Any communication error to report?
Sergunb 0:8918a71cdbe9 673 if(error)
Sergunb 0:8918a71cdbe9 674 return error;
Sergunb 0:8918a71cdbe9 675
Sergunb 0:8918a71cdbe9 676 //Check SMTP reply code
Sergunb 0:8918a71cdbe9 677 if(!SMTP_REPLY_CODE_2YZ(replyCode))
Sergunb 0:8918a71cdbe9 678 return ERROR_AUTHENTICATION_FAILED;
Sergunb 0:8918a71cdbe9 679
Sergunb 0:8918a71cdbe9 680 //Successful authentication
Sergunb 0:8918a71cdbe9 681 return NO_ERROR;
Sergunb 0:8918a71cdbe9 682 #else
Sergunb 0:8918a71cdbe9 683 //CRAM-MD5 authentication is not supported
Sergunb 0:8918a71cdbe9 684 return ERROR_AUTHENTICATION_FAILED;
Sergunb 0:8918a71cdbe9 685 #endif
Sergunb 0:8918a71cdbe9 686 }
Sergunb 0:8918a71cdbe9 687
Sergunb 0:8918a71cdbe9 688
Sergunb 0:8918a71cdbe9 689 /**
Sergunb 0:8918a71cdbe9 690 * @brief Send message body
Sergunb 0:8918a71cdbe9 691 * @param[in] context SMTP client context
Sergunb 0:8918a71cdbe9 692 * @param[in] mail Mail contents
Sergunb 0:8918a71cdbe9 693 * @return Error code
Sergunb 0:8918a71cdbe9 694 **/
Sergunb 0:8918a71cdbe9 695
Sergunb 0:8918a71cdbe9 696 error_t smtpSendData(SmtpClientContext *context, const SmtpMail *mail)
Sergunb 0:8918a71cdbe9 697 {
Sergunb 0:8918a71cdbe9 698 error_t error;
Sergunb 0:8918a71cdbe9 699 bool_t first;
Sergunb 0:8918a71cdbe9 700 uint_t i;
Sergunb 0:8918a71cdbe9 701 uint_t replyCode;
Sergunb 0:8918a71cdbe9 702 char_t *p;
Sergunb 0:8918a71cdbe9 703
Sergunb 0:8918a71cdbe9 704 //Send DATA command
Sergunb 0:8918a71cdbe9 705 error = smtpSendCommand(context, "DATA\r\n", &replyCode, NULL);
Sergunb 0:8918a71cdbe9 706 //Any communication error to report?
Sergunb 0:8918a71cdbe9 707 if(error)
Sergunb 0:8918a71cdbe9 708 return error;
Sergunb 0:8918a71cdbe9 709
Sergunb 0:8918a71cdbe9 710 //Check SMTP reply code
Sergunb 0:8918a71cdbe9 711 if(!SMTP_REPLY_CODE_3YZ(replyCode))
Sergunb 0:8918a71cdbe9 712 return ERROR_UNEXPECTED_RESPONSE;
Sergunb 0:8918a71cdbe9 713
Sergunb 0:8918a71cdbe9 714 //Point to the beginning of the buffer
Sergunb 0:8918a71cdbe9 715 p = context->buffer;
Sergunb 0:8918a71cdbe9 716
Sergunb 0:8918a71cdbe9 717 //Current date and time
Sergunb 0:8918a71cdbe9 718 if(mail->dateTime && mail->dateTime[0] != '\0')
Sergunb 0:8918a71cdbe9 719 p += sprintf(p, "Date: %s\r\n", mail->dateTime);
Sergunb 0:8918a71cdbe9 720
Sergunb 0:8918a71cdbe9 721 //Sender address
Sergunb 0:8918a71cdbe9 722 if(mail->from.addr)
Sergunb 0:8918a71cdbe9 723 {
Sergunb 0:8918a71cdbe9 724 //A friendly name may be associated with the sender address
Sergunb 0:8918a71cdbe9 725 if(mail->from.name && mail->from.name[0] != '\0')
Sergunb 0:8918a71cdbe9 726 p += sprintf(p, "From: \"%s\" <%s>\r\n", mail->from.name, mail->from.addr);
Sergunb 0:8918a71cdbe9 727 else
Sergunb 0:8918a71cdbe9 728 p += sprintf(p, "From: %s\r\n", mail->from.addr);
Sergunb 0:8918a71cdbe9 729 }
Sergunb 0:8918a71cdbe9 730
Sergunb 0:8918a71cdbe9 731 //Recipients
Sergunb 0:8918a71cdbe9 732 for(i = 0, first = TRUE; i < mail->recipientCount; i++)
Sergunb 0:8918a71cdbe9 733 {
Sergunb 0:8918a71cdbe9 734 //Skip recipient addresses that are not valid
Sergunb 0:8918a71cdbe9 735 if(!mail->recipients[i].addr)
Sergunb 0:8918a71cdbe9 736 continue;
Sergunb 0:8918a71cdbe9 737
Sergunb 0:8918a71cdbe9 738 //Check recipient type
Sergunb 0:8918a71cdbe9 739 if(mail->recipients[i].type & SMTP_RCPT_TYPE_TO)
Sergunb 0:8918a71cdbe9 740 {
Sergunb 0:8918a71cdbe9 741 //The first item of the list requires special processing
Sergunb 0:8918a71cdbe9 742 p += sprintf(p, first ? "To: " : ", ");
Sergunb 0:8918a71cdbe9 743
Sergunb 0:8918a71cdbe9 744 //A friendly name may be associated with the address
Sergunb 0:8918a71cdbe9 745 if(mail->recipients[i].name && mail->recipients[i].name[0] != '\0')
Sergunb 0:8918a71cdbe9 746 p += sprintf(p, "\"%s\" <%s>", mail->recipients[i].name, mail->recipients[i].addr);
Sergunb 0:8918a71cdbe9 747 else
Sergunb 0:8918a71cdbe9 748 p += sprintf(p, "%s", mail->recipients[i].addr);
Sergunb 0:8918a71cdbe9 749
Sergunb 0:8918a71cdbe9 750 //Prepare to add a new item to the list
Sergunb 0:8918a71cdbe9 751 first = FALSE;
Sergunb 0:8918a71cdbe9 752 }
Sergunb 0:8918a71cdbe9 753 }
Sergunb 0:8918a71cdbe9 754
Sergunb 0:8918a71cdbe9 755 //Properly terminate the line with CRLF
Sergunb 0:8918a71cdbe9 756 if(!first)
Sergunb 0:8918a71cdbe9 757 p += sprintf(p, "\r\n");
Sergunb 0:8918a71cdbe9 758
Sergunb 0:8918a71cdbe9 759 //Carbon copy
Sergunb 0:8918a71cdbe9 760 for(i = 0, first = TRUE; i < mail->recipientCount; i++)
Sergunb 0:8918a71cdbe9 761 {
Sergunb 0:8918a71cdbe9 762 //Skip recipient addresses that are not valid
Sergunb 0:8918a71cdbe9 763 if(!mail->recipients[i].addr)
Sergunb 0:8918a71cdbe9 764 continue;
Sergunb 0:8918a71cdbe9 765
Sergunb 0:8918a71cdbe9 766 //Check recipient type
Sergunb 0:8918a71cdbe9 767 if(mail->recipients[i].type & SMTP_RCPT_TYPE_CC)
Sergunb 0:8918a71cdbe9 768 {
Sergunb 0:8918a71cdbe9 769 //The first item of the list requires special processing
Sergunb 0:8918a71cdbe9 770 p += sprintf(p, first ? "Cc: " : ", ");
Sergunb 0:8918a71cdbe9 771
Sergunb 0:8918a71cdbe9 772 //A friendly name may be associated with the address
Sergunb 0:8918a71cdbe9 773 if(mail->recipients[i].name && mail->recipients[i].name[0] != '\0')
Sergunb 0:8918a71cdbe9 774 p += sprintf(p, "\"%s\" <%s>", mail->recipients[i].name, mail->recipients[i].addr);
Sergunb 0:8918a71cdbe9 775 else
Sergunb 0:8918a71cdbe9 776 p += sprintf(p, "%s", mail->recipients[i].addr);
Sergunb 0:8918a71cdbe9 777
Sergunb 0:8918a71cdbe9 778 //Prepare to add a new item to the list
Sergunb 0:8918a71cdbe9 779 first = FALSE;
Sergunb 0:8918a71cdbe9 780 }
Sergunb 0:8918a71cdbe9 781 }
Sergunb 0:8918a71cdbe9 782
Sergunb 0:8918a71cdbe9 783 //Properly terminate the line with CRLF
Sergunb 0:8918a71cdbe9 784 if(!first)
Sergunb 0:8918a71cdbe9 785 p += sprintf(p, "\r\n");
Sergunb 0:8918a71cdbe9 786
Sergunb 0:8918a71cdbe9 787 //Subject
Sergunb 0:8918a71cdbe9 788 if(mail->subject)
Sergunb 0:8918a71cdbe9 789 p += sprintf(p, "Subject: %s\r\n", mail->subject);
Sergunb 0:8918a71cdbe9 790
Sergunb 0:8918a71cdbe9 791 //The header and the body are separated by an empty line
Sergunb 0:8918a71cdbe9 792 sprintf(p, "\r\n");
Sergunb 0:8918a71cdbe9 793
Sergunb 0:8918a71cdbe9 794 //Debug message
Sergunb 0:8918a71cdbe9 795 TRACE_DEBUG(context->buffer);
Sergunb 0:8918a71cdbe9 796 TRACE_DEBUG(mail->body);
Sergunb 0:8918a71cdbe9 797 TRACE_DEBUG("\r\n.\r\n");
Sergunb 0:8918a71cdbe9 798
Sergunb 0:8918a71cdbe9 799 //Send message header
Sergunb 0:8918a71cdbe9 800 error = smtpWrite(context, context->buffer, strlen(context->buffer), 0);
Sergunb 0:8918a71cdbe9 801 //Any communication error to report?
Sergunb 0:8918a71cdbe9 802 if(error)
Sergunb 0:8918a71cdbe9 803 return error;
Sergunb 0:8918a71cdbe9 804
Sergunb 0:8918a71cdbe9 805 //Send message body
Sergunb 0:8918a71cdbe9 806 error = smtpWrite(context, mail->body, strlen(mail->body), 0);
Sergunb 0:8918a71cdbe9 807 //Any communication error to report?
Sergunb 0:8918a71cdbe9 808 if(error)
Sergunb 0:8918a71cdbe9 809 return error;
Sergunb 0:8918a71cdbe9 810
Sergunb 0:8918a71cdbe9 811 //Indicate the end of the mail data by sending a line containing only a "."
Sergunb 0:8918a71cdbe9 812 error = smtpSendCommand(context, "\r\n.\r\n", &replyCode, NULL);
Sergunb 0:8918a71cdbe9 813 //Any communication error to report?
Sergunb 0:8918a71cdbe9 814 if(error)
Sergunb 0:8918a71cdbe9 815 return error;
Sergunb 0:8918a71cdbe9 816
Sergunb 0:8918a71cdbe9 817 //Check SMTP reply code
Sergunb 0:8918a71cdbe9 818 if(!SMTP_REPLY_CODE_2YZ(replyCode))
Sergunb 0:8918a71cdbe9 819 return ERROR_UNEXPECTED_RESPONSE;
Sergunb 0:8918a71cdbe9 820
Sergunb 0:8918a71cdbe9 821 //Successful operation
Sergunb 0:8918a71cdbe9 822 return NO_ERROR;
Sergunb 0:8918a71cdbe9 823 }
Sergunb 0:8918a71cdbe9 824
Sergunb 0:8918a71cdbe9 825
Sergunb 0:8918a71cdbe9 826 /**
Sergunb 0:8918a71cdbe9 827 * @brief Send SMTP command and wait for a reply
Sergunb 0:8918a71cdbe9 828 * @param[in] context SMTP client context
Sergunb 0:8918a71cdbe9 829 * @param[in] command Command line
Sergunb 0:8918a71cdbe9 830 * @param[out] replyCode SMTP server reply code
Sergunb 0:8918a71cdbe9 831 * @param[in] callback Optional callback to parse each line of the reply
Sergunb 0:8918a71cdbe9 832 * @return Error code
Sergunb 0:8918a71cdbe9 833 **/
Sergunb 0:8918a71cdbe9 834
Sergunb 0:8918a71cdbe9 835 error_t smtpSendCommand(SmtpClientContext *context, const char_t *command,
Sergunb 0:8918a71cdbe9 836 uint_t *replyCode, SmtpReplyCallback callback)
Sergunb 0:8918a71cdbe9 837 {
Sergunb 0:8918a71cdbe9 838 error_t error;
Sergunb 0:8918a71cdbe9 839 size_t length;
Sergunb 0:8918a71cdbe9 840 char_t *line;
Sergunb 0:8918a71cdbe9 841
Sergunb 0:8918a71cdbe9 842 //Any command line to send?
Sergunb 0:8918a71cdbe9 843 if(command)
Sergunb 0:8918a71cdbe9 844 {
Sergunb 0:8918a71cdbe9 845 //Debug message
Sergunb 0:8918a71cdbe9 846 TRACE_DEBUG("SMTP client: %s", command);
Sergunb 0:8918a71cdbe9 847
Sergunb 0:8918a71cdbe9 848 //Send the command to the SMTP server
Sergunb 0:8918a71cdbe9 849 error = smtpWrite(context, command, strlen(command), SOCKET_FLAG_WAIT_ACK);
Sergunb 0:8918a71cdbe9 850 //Failed to send command?
Sergunb 0:8918a71cdbe9 851 if(error)
Sergunb 0:8918a71cdbe9 852 return error;
Sergunb 0:8918a71cdbe9 853 }
Sergunb 0:8918a71cdbe9 854
Sergunb 0:8918a71cdbe9 855 //Multiline replies are allowed for any command
Sergunb 0:8918a71cdbe9 856 while(1)
Sergunb 0:8918a71cdbe9 857 {
Sergunb 0:8918a71cdbe9 858 //Wait for a response from the server
Sergunb 0:8918a71cdbe9 859 error = smtpRead(context, context->buffer,
Sergunb 0:8918a71cdbe9 860 SMTP_CLIENT_MAX_LINE_LENGTH - 1, &length, SOCKET_FLAG_BREAK_CRLF);
Sergunb 0:8918a71cdbe9 861
Sergunb 0:8918a71cdbe9 862 //The remote server did not respond as expected?
Sergunb 0:8918a71cdbe9 863 if(error)
Sergunb 0:8918a71cdbe9 864 return error;
Sergunb 0:8918a71cdbe9 865
Sergunb 0:8918a71cdbe9 866 //Properly terminate the string with a NULL character
Sergunb 0:8918a71cdbe9 867 context->buffer[length] = '\0';
Sergunb 0:8918a71cdbe9 868 //Remove all leading and trailing whitespace from the response
Sergunb 0:8918a71cdbe9 869 line = strTrimWhitespace(context->buffer);
Sergunb 0:8918a71cdbe9 870
Sergunb 0:8918a71cdbe9 871 //Debug message
Sergunb 0:8918a71cdbe9 872 TRACE_DEBUG("SMTP server: %s\r\n", line);
Sergunb 0:8918a71cdbe9 873
Sergunb 0:8918a71cdbe9 874 //Check the length of the response
Sergunb 0:8918a71cdbe9 875 if(strlen(line) < 3)
Sergunb 0:8918a71cdbe9 876 return ERROR_INVALID_SYNTAX;
Sergunb 0:8918a71cdbe9 877 //All replies begin with a three digit numeric code
Sergunb 0:8918a71cdbe9 878 if(!isdigit((uint8_t) line[0]) || !isdigit((uint8_t) line[1]) || !isdigit((uint8_t) line[2]))
Sergunb 0:8918a71cdbe9 879 return ERROR_INVALID_SYNTAX;
Sergunb 0:8918a71cdbe9 880 //A hyphen or a space character must follow the response code
Sergunb 0:8918a71cdbe9 881 if(line[3] != '-' && line[3] != ' ' && line[3] != '\0')
Sergunb 0:8918a71cdbe9 882 return ERROR_INVALID_SYNTAX;
Sergunb 0:8918a71cdbe9 883
Sergunb 0:8918a71cdbe9 884 //Get the server response code
Sergunb 0:8918a71cdbe9 885 *replyCode = strtoul(line, NULL, 10);
Sergunb 0:8918a71cdbe9 886
Sergunb 0:8918a71cdbe9 887 //Any callback function to call?
Sergunb 0:8918a71cdbe9 888 if(callback)
Sergunb 0:8918a71cdbe9 889 {
Sergunb 0:8918a71cdbe9 890 //Invoke callback function to parse the response line
Sergunb 0:8918a71cdbe9 891 error = callback(context, line, *replyCode);
Sergunb 0:8918a71cdbe9 892 //Check status code
Sergunb 0:8918a71cdbe9 893 if(error)
Sergunb 0:8918a71cdbe9 894 return error;
Sergunb 0:8918a71cdbe9 895 }
Sergunb 0:8918a71cdbe9 896
Sergunb 0:8918a71cdbe9 897 //A hyphen follows the response code for all but the last line
Sergunb 0:8918a71cdbe9 898 if(line[3] != '-')
Sergunb 0:8918a71cdbe9 899 break;
Sergunb 0:8918a71cdbe9 900 }
Sergunb 0:8918a71cdbe9 901
Sergunb 0:8918a71cdbe9 902 //Successful processing
Sergunb 0:8918a71cdbe9 903 return NO_ERROR;
Sergunb 0:8918a71cdbe9 904 }
Sergunb 0:8918a71cdbe9 905
Sergunb 0:8918a71cdbe9 906
Sergunb 0:8918a71cdbe9 907 /**
Sergunb 0:8918a71cdbe9 908 * @brief Send data to the SMTP server
Sergunb 0:8918a71cdbe9 909 * @param[in] context SMTP client context
Sergunb 0:8918a71cdbe9 910 * @param[in] data Pointer to a buffer containing the data to be transmitted
Sergunb 0:8918a71cdbe9 911 * @param[in] length Number of bytes to be transmitted
Sergunb 0:8918a71cdbe9 912 * @param[in] flags Set of flags that influences the behavior of this function
Sergunb 0:8918a71cdbe9 913 **/
Sergunb 0:8918a71cdbe9 914
Sergunb 0:8918a71cdbe9 915 error_t smtpWrite(SmtpClientContext *context, const void *data, size_t length, uint_t flags)
Sergunb 0:8918a71cdbe9 916 {
Sergunb 0:8918a71cdbe9 917 #if (SMTP_CLIENT_TLS_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 918 //Check whether a secure connection is being used
Sergunb 0:8918a71cdbe9 919 if(context->tlsContext != NULL)
Sergunb 0:8918a71cdbe9 920 {
Sergunb 0:8918a71cdbe9 921 //Use SSL/TLS to transmit data to the SMTP server
Sergunb 0:8918a71cdbe9 922 return tlsWrite(context->tlsContext, data, length, NULL, flags);
Sergunb 0:8918a71cdbe9 923 }
Sergunb 0:8918a71cdbe9 924 else
Sergunb 0:8918a71cdbe9 925 #endif
Sergunb 0:8918a71cdbe9 926 {
Sergunb 0:8918a71cdbe9 927 //Transmit data to the SMTP server
Sergunb 0:8918a71cdbe9 928 return socketSend(context->socket, data, length, NULL, flags);
Sergunb 0:8918a71cdbe9 929 }
Sergunb 0:8918a71cdbe9 930 }
Sergunb 0:8918a71cdbe9 931
Sergunb 0:8918a71cdbe9 932
Sergunb 0:8918a71cdbe9 933 /**
Sergunb 0:8918a71cdbe9 934 * @brief Receive data from the SMTP server
Sergunb 0:8918a71cdbe9 935 * @param[in] context SMTP client context
Sergunb 0:8918a71cdbe9 936 * @param[out] data Buffer into which received data will be placed
Sergunb 0:8918a71cdbe9 937 * @param[in] size Maximum number of bytes that can be received
Sergunb 0:8918a71cdbe9 938 * @param[out] received Actual number of bytes that have been received
Sergunb 0:8918a71cdbe9 939 * @param[in] flags Set of flags that influences the behavior of this function
Sergunb 0:8918a71cdbe9 940 * @return Error code
Sergunb 0:8918a71cdbe9 941 **/
Sergunb 0:8918a71cdbe9 942
Sergunb 0:8918a71cdbe9 943 error_t smtpRead(SmtpClientContext *context, void *data, size_t size, size_t *received, uint_t flags)
Sergunb 0:8918a71cdbe9 944 {
Sergunb 0:8918a71cdbe9 945 #if (SMTP_CLIENT_TLS_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 946 //Check whether a secure connection is being used
Sergunb 0:8918a71cdbe9 947 if(context->tlsContext != NULL)
Sergunb 0:8918a71cdbe9 948 {
Sergunb 0:8918a71cdbe9 949 //Use SSL/TLS to receive data from the SMTP server
Sergunb 0:8918a71cdbe9 950 return tlsRead(context->tlsContext, data, size, received, flags);
Sergunb 0:8918a71cdbe9 951 }
Sergunb 0:8918a71cdbe9 952 else
Sergunb 0:8918a71cdbe9 953 #endif
Sergunb 0:8918a71cdbe9 954 {
Sergunb 0:8918a71cdbe9 955 //Receive data from the SMTP server
Sergunb 0:8918a71cdbe9 956 return socketReceive(context->socket, data, size, received, flags);
Sergunb 0:8918a71cdbe9 957 }
Sergunb 0:8918a71cdbe9 958 }
Sergunb 0:8918a71cdbe9 959
Sergunb 0:8918a71cdbe9 960 #endif
Sergunb 0:8918a71cdbe9 961