1094 lines
31 KiB
C++
1094 lines
31 KiB
C++
/**
|
|
*
|
|
* The Network Upgradable Arduino Secure TCP Client Class, ESP_Mail_TCPClient.h v1.0.1
|
|
*
|
|
* Created August 27, 2023
|
|
*
|
|
* The MIT License (MIT)
|
|
* Copyright (c) 2023 K. Suwatchai (Mobizt)
|
|
*
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person returning a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#ifndef ESP_MAIL_TCPCLIENT_H
|
|
#define ESP_MAIL_TCPCLIENT_H
|
|
|
|
#include "ESP_Mail_Client_Version.h"
|
|
#if !VALID_VERSION_CHECK(30409)
|
|
#error "Mixed versions compilation."
|
|
#endif
|
|
|
|
#pragma GCC diagnostic ignored "-Wunused-variable"
|
|
#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
|
|
|
|
#include "ESP_Mail_Const.h"
|
|
|
|
#if defined(ESP32) && (defined(ENABLE_SMTP) || defined(ENABLE_IMAP))
|
|
#include "IPAddress.h"
|
|
#include "lwip/sockets.h"
|
|
#endif
|
|
|
|
#if defined(ESP32)
|
|
|
|
#include "ESP8266WiFi.h"
|
|
#if defined(ESP_MAIL_WIFI_IS_AVAILABLE)
|
|
#define WIFI_HAS_HOST_BY_NAME
|
|
#endif
|
|
#include "extras/WiFiClientImpl.h"
|
|
#define BASE_WIFICLIENT WiFiClientImpl
|
|
|
|
#elif defined(ESP_MAIL_WIFI_IS_AVAILABLE)
|
|
#include "WiFiClient.h"
|
|
#define BASE_WIFICLIENT WiFiClient
|
|
#endif
|
|
|
|
#include "SSLClient/ESP_SSLClient.h"
|
|
|
|
class ESP_Mail_TCPClient
|
|
{
|
|
public:
|
|
ESP_Mail_TCPClient()
|
|
{
|
|
#if !defined(ESP_MAIL_DISABLE_SSL)
|
|
_tcp_client = new ESP_SSLClient();
|
|
#endif
|
|
}
|
|
|
|
~ESP_Mail_TCPClient()
|
|
{
|
|
clear();
|
|
#if !defined(ESP_MAIL_DISABLE_SSL)
|
|
if (_tcp_client)
|
|
delete _tcp_client;
|
|
_tcp_client = nullptr;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Set the client.
|
|
* @param client The Client interface.
|
|
*/
|
|
void setClient(Client *client)
|
|
{
|
|
clear();
|
|
_basic_client = client;
|
|
_client_type = esp_mail_client_type_external_basic_client;
|
|
}
|
|
|
|
/** Assign TinyGsm Clients.
|
|
*
|
|
* @param client The pointer to TinyGsmClient.
|
|
* @param modem The pointer to TinyGsm modem object. Modem should be initialized and/or set mode before transfering data
|
|
* @param pin The SIM pin.
|
|
* @param apn The GPRS APN (Access Point Name).
|
|
* @param user The GPRS user.
|
|
* @param password The GPRS password.
|
|
*/
|
|
void setGSMClient(Client *client, void *modem = nullptr, const char *pin = nullptr, const char *apn = nullptr, const char *user = nullptr, const char *password = nullptr)
|
|
{
|
|
#if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE)
|
|
_pin = pin;
|
|
_apn = apn;
|
|
_user = user;
|
|
_password = password;
|
|
_modem = modem;
|
|
_client_type = esp_mail_client_type_external_gsm_client;
|
|
_basic_client = client;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Set Root CA certificate to verify.
|
|
* @param caCert The certificate.
|
|
*/
|
|
void setCACert(const char *caCert)
|
|
{
|
|
#if !defined(ESP_MAIL_DISABLE_SSL)
|
|
if (caCert)
|
|
{
|
|
if (_x509)
|
|
delete _x509;
|
|
|
|
_x509 = new X509List(caCert);
|
|
_tcp_client->setTrustAnchors(_x509);
|
|
|
|
setCertType(esp_mail_cert_type_data);
|
|
setTA(true);
|
|
}
|
|
else
|
|
{
|
|
setCertType(esp_mail_cert_type_none);
|
|
setInSecure();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Set Root CA certificate to verify.
|
|
* @param certFile The certificate file path.
|
|
* @param storageType The storage type mb_fs_mem_storage_type_flash or mb_fs_mem_storage_type_sd.
|
|
* @return true when certificate loaded successfully.
|
|
*/
|
|
bool setCertFile(const char *certFile, mb_fs_mem_storage_type storageType)
|
|
{
|
|
#if !defined(ESP_MAIL_DISABLE_SSL)
|
|
if (!_mbfs)
|
|
return false;
|
|
|
|
if (_clock_ready && strlen(certFile) > 0)
|
|
{
|
|
MB_String filename = certFile;
|
|
if (filename.length() > 0)
|
|
{
|
|
if (filename[0] != '/')
|
|
filename.prepend('/');
|
|
}
|
|
|
|
int len = _mbfs->open(filename, storageType, mb_fs_open_mode_read);
|
|
if (len > -1)
|
|
{
|
|
uint8_t *der = (uint8_t *)_mbfs->newP(len);
|
|
if (_mbfs->available(storageType))
|
|
_mbfs->read(storageType, der, len);
|
|
_mbfs->close(storageType);
|
|
|
|
if (_x509)
|
|
delete _x509;
|
|
|
|
_x509 = new X509List(der, len);
|
|
_tcp_client->setTrustAnchors(_x509);
|
|
setTA(true);
|
|
_mbfs->delP(&der);
|
|
|
|
setCertType(esp_mail_cert_type_file);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return getCertType() == esp_mail_cert_type_file;
|
|
}
|
|
|
|
/**
|
|
* Set TCP connection time out in seconds.
|
|
* @param timeoutSec The time out in seconds.
|
|
*/
|
|
void setTimeout(uint32_t timeoutSec)
|
|
{
|
|
_tcp_client->setTimeout(timeoutSec * 1000);
|
|
}
|
|
|
|
/** Set the BearSSL IO buffer size.
|
|
*
|
|
* @param rx The BearSSL receive buffer size in bytes.
|
|
* @param tx The BearSSL trasmit buffer size in bytes.
|
|
*/
|
|
void setIOBufferSize(int rx, int tx)
|
|
{
|
|
_rx_size = rx;
|
|
_tx_size = tx;
|
|
}
|
|
|
|
/**
|
|
* Get the ethernet link status.
|
|
* @return true for link up or false for link down.
|
|
*/
|
|
bool ethLinkUp()
|
|
{
|
|
bool ret = false;
|
|
|
|
#if !defined(ESP_MAIL_DISABLE_NATIVE_ETHERNET) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP))
|
|
|
|
#if defined(ESP_MAIL_ETH_IS_AVAILABLE)
|
|
|
|
#if defined(ESP32)
|
|
if (validIP(ETH.localIP()))
|
|
{
|
|
ETH.linkUp();
|
|
ret = true;
|
|
}
|
|
#elif defined(ESP8266)
|
|
|
|
#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP)
|
|
if (!_session_config)
|
|
return false;
|
|
#endif
|
|
|
|
#if defined(ESP8266) && defined(ESP8266_CORE_SDK_V3_X_X)
|
|
|
|
#if defined(INC_ENC28J60_LWIP)
|
|
if (_session_config->spi_ethernet_module.enc28j60)
|
|
{
|
|
ret = _session_config->spi_ethernet_module.enc28j60->status() == WL_CONNECTED;
|
|
goto ex;
|
|
}
|
|
#endif
|
|
#if defined(INC_W5100_LWIP)
|
|
if (_session_config->spi_ethernet_module.w5100)
|
|
{
|
|
ret = _session_config->spi_ethernet_module.w5100->status() == WL_CONNECTED;
|
|
goto ex;
|
|
}
|
|
#endif
|
|
#if defined(INC_W5500_LWIP)
|
|
if (_session_config->spi_ethernet_module.w5500)
|
|
{
|
|
ret = _session_config->spi_ethernet_module.w5500->status() == WL_CONNECTED;
|
|
goto ex;
|
|
}
|
|
#endif
|
|
#elif defined(MB_ARDUINO_PICO)
|
|
|
|
#endif
|
|
|
|
return ret;
|
|
|
|
#if defined(INC_ENC28J60_LWIP) || defined(INC_W5100_LWIP) || defined(INC_W5500_LWIP)
|
|
ex:
|
|
#endif
|
|
// workaround for ESP8266 Ethernet
|
|
delayMicroseconds(0);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Checking for valid IP.
|
|
* @return true for valid.
|
|
*/
|
|
bool validIP(IPAddress ip)
|
|
{
|
|
char buf[16];
|
|
sprintf(buf, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
|
|
return strcmp(buf, "0.0.0.0") != 0;
|
|
}
|
|
|
|
/**
|
|
* Ethernet DNS workaround.
|
|
*/
|
|
void ethDNSWorkAround()
|
|
{
|
|
|
|
#if !defined(ESP_MAIL_DISABLE_NATIVE_ETHERNET) && (defined(ENABLE_SMTP) || defined(ENABLE_IMAP))
|
|
if (!_session_config)
|
|
return;
|
|
|
|
#if defined(ESP8266_CORE_SDK_V3_X_X)
|
|
|
|
#if defined(INC_ENC28J60_LWIP)
|
|
if (_session_config->spi_ethernet_module.enc28j60)
|
|
goto ex;
|
|
#endif
|
|
#if defined(INC_W5100_LWIP)
|
|
if (_session_config->spi_ethernet_module.w5100)
|
|
goto ex;
|
|
#endif
|
|
#if defined(INC_W5500_LWIP)
|
|
if (_session_config->spi_ethernet_module.w5500)
|
|
goto ex;
|
|
#endif
|
|
|
|
#elif defined(MB_ARDUINO_PICO)
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
#if defined(INC_ENC28J60_LWIP) || defined(INC_W5100_LWIP) || defined(INC_W5500_LWIP)
|
|
ex:
|
|
#if defined(ESP_MAIL_WIFI_IS_AVAILABLE)
|
|
BASE_WIFICLIENT client;
|
|
client.connect(_session_config->server.host_name.c_str(), _session_config->server.port);
|
|
client.stop();
|
|
#endif
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Get the network status.
|
|
* @return true for connected or false for not connected.
|
|
*/
|
|
bool networkReady()
|
|
{
|
|
|
|
// We will not invoke the network status request when device has built-in WiFi or Ethernet and it is connected.
|
|
if (_client_type == esp_mail_client_type_external_gsm_client)
|
|
{
|
|
_network_status = gprsConnected();
|
|
if (!_network_status)
|
|
gprsConnect();
|
|
}
|
|
else if (WiFI_CONNECTED || ethLinkUp())
|
|
_network_status = true;
|
|
else if (_client_type == esp_mail_client_type_external_basic_client)
|
|
{
|
|
if (!_network_status_cb)
|
|
_last_error = 1;
|
|
else
|
|
_network_status_cb();
|
|
}
|
|
|
|
return _network_status;
|
|
}
|
|
|
|
/**
|
|
* Reconnect the network.
|
|
*/
|
|
void networkReconnect()
|
|
{
|
|
|
|
if (_client_type == esp_mail_client_type_external_basic_client)
|
|
{
|
|
#if defined(ESP_MAIL_HAS_WIFI_DISCONNECT)
|
|
// We can reconnect WiFi when device connected via built-in WiFi that supports reconnect
|
|
if (WiFI_CONNECTED)
|
|
{
|
|
WiFi.reconnect();
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
if (_network_connection_cb)
|
|
_network_connection_cb();
|
|
}
|
|
else if (_client_type == esp_mail_client_type_external_gsm_client)
|
|
{
|
|
gprsDisconnect();
|
|
gprsConnect();
|
|
}
|
|
else if (_client_type == esp_mail_client_type_internal_basic_client)
|
|
{
|
|
|
|
#if defined(ESP_MAIL_WIFI_IS_AVAILABLE)
|
|
#if defined(ESP32) || defined(ESP8266)
|
|
WiFi.reconnect();
|
|
#else
|
|
if (_wifi_multi && _wifi_multi->credentials.size())
|
|
_wifi_multi->reconnect();
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Disconnect the network.
|
|
*/
|
|
void networkDisconnect() {}
|
|
|
|
/**
|
|
* Get the Client type.
|
|
* @return The esp_mail_client_type enum value.
|
|
*/
|
|
esp_mail_client_type type() { return _client_type; }
|
|
|
|
/**
|
|
* Get the Client initialization status.
|
|
* @return The initialization status.
|
|
*/
|
|
bool isInitialized()
|
|
{
|
|
bool rdy = true;
|
|
#if !defined(ESP_MAIL_WIFI_IS_AVAILABLE)
|
|
if (_client_type == esp_mail_client_type_external_basic_client &&
|
|
(!_network_connection_cb || !_network_status_cb))
|
|
rdy = false;
|
|
else if (_client_type != esp_mail_client_type_external_basic_client ||
|
|
_client_type != esp_mail_client_type_external_gsm_client)
|
|
rdy = false;
|
|
#else
|
|
// assume external client is WiFiClient and network status request callback is not required
|
|
// when device was connected to network using on board WiFi
|
|
if (_client_type == esp_mail_client_type_external_basic_client &&
|
|
(!_network_connection_cb || (!_network_status_cb && !WiFI_CONNECTED && !ethLinkUp())))
|
|
{
|
|
rdy = false;
|
|
}
|
|
|
|
#endif
|
|
|
|
if (!rdy)
|
|
{
|
|
#if !defined(SILENT_MODE) && (defined(ENABLE_SMTP) || defined(ENABLE_IMAP))
|
|
if (_debug_level > 0)
|
|
{
|
|
if (!_network_connection_cb)
|
|
esp_mail_debug_print_tag(esp_mail_error_client_str_2 /* "network connection callback is required" */, esp_mail_debug_tag_type_error, true);
|
|
if (!WiFI_CONNECTED && !ethLinkUp())
|
|
{
|
|
if (!_network_status_cb)
|
|
esp_mail_debug_print_tag(esp_mail_error_client_str_3 /* "network connection status callback is required" */, esp_mail_debug_tag_type_error, true);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return rdy;
|
|
}
|
|
|
|
/**
|
|
* Set Root CA certificate to verify.
|
|
* @param name The host name.
|
|
* @param ip The ip address result.
|
|
* @return 1 for success or 0 for failed.
|
|
*/
|
|
int hostByName(const char *name, IPAddress &ip)
|
|
{
|
|
#if defined(ESP_MAIL_WIFI_IS_AVAILABLE)
|
|
return WiFiHelper::hostByName(name, ip);
|
|
#else
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Store the host name and port.
|
|
* @param host The host name to connect.
|
|
* @param port The port to connect.
|
|
* @return true.
|
|
*/
|
|
bool begin(const char *host, uint16_t port)
|
|
{
|
|
_host = host;
|
|
_port = port;
|
|
#if !defined(ESP_MAIL_DISABLE_SSL)
|
|
_tcp_client->setBufferSizes(_rx_size >= _minRXTXBufSize && _rx_size <= _maxRXBufSize ? _rx_size : _maxRXBufSize / rxBufDivider,
|
|
_tx_size >= _minRXTXBufSize && _tx_size <= _maxTXBufSize ? _tx_size : _maxTXBufSize / txBufDivider);
|
|
#endif
|
|
_last_error = 0;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Start TCP connection using stored host name and port.
|
|
* @param secure The secure mode option.
|
|
* @param verify The Root CA certificate verification option.
|
|
* @return true for success or false for error.
|
|
*/
|
|
|
|
bool connect(bool secured, bool verify)
|
|
{
|
|
bool ret = false;
|
|
|
|
#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP)
|
|
_last_error = 0;
|
|
|
|
#if !defined(ESP_MAIL_DISABLE_SSL)
|
|
_tcp_client->enableSSL(secured);
|
|
setSecure(secured);
|
|
setVerify(verify);
|
|
#endif
|
|
|
|
if (connected())
|
|
{
|
|
flush();
|
|
return true;
|
|
}
|
|
|
|
if (!_basic_client)
|
|
{
|
|
if (_client_type == esp_mail_client_type_external_basic_client)
|
|
{
|
|
_last_error = 1;
|
|
return false;
|
|
}
|
|
else if (_client_type != esp_mail_client_type_external_gsm_client)
|
|
{
|
|
// Device has no built-in WiFi, external client required.
|
|
#if defined(ESP_MAIL_WIFI_IS_AVAILABLE)
|
|
_basic_client = new BASE_WIFICLIENT();
|
|
_client_type = esp_mail_client_type_internal_basic_client;
|
|
#else
|
|
_last_error = 1;
|
|
return false;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if defined(ESP_MAIL_DISABLE_SSL)
|
|
_tcp_client = _basic_client;
|
|
#else
|
|
_tcp_client->setClient(_basic_client);
|
|
#endif
|
|
|
|
if (!_tcp_client->connect(_host.c_str(), _port))
|
|
return false;
|
|
|
|
#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) && (defined(ESP32) || defined(ESP8266) || defined(MB_ARDUINO_PICO))
|
|
if (_client_type == esp_mail_client_type_internal_basic_client)
|
|
reinterpret_cast<BASE_WIFICLIENT *>(_basic_client)->setNoDelay(true);
|
|
#endif
|
|
|
|
// For TCP keepalive should work in ESP8266 core > 3.1.2.
|
|
// https://github.com/esp8266/Arduino/pull/8940
|
|
|
|
// Not currently supported by WiFiClientSecure in Arduino Pico core
|
|
|
|
if (_client_type == esp_mail_client_type_internal_basic_client)
|
|
{
|
|
if (isKeepAliveSet())
|
|
{
|
|
#if defined(ESP_MAIL_WIFI_IS_AVAILABLE)
|
|
|
|
#if defined(ESP8266)
|
|
if (_tcpKeepIdleSeconds == 0 || _tcpKeepIntervalSeconds == 0 || _tcpKeepCount == 0)
|
|
reinterpret_cast<BASE_WIFICLIENT *>(_basic_client)->disableKeepAlive();
|
|
else
|
|
reinterpret_cast<BASE_WIFICLIENT *>(_basic_client)->keepAlive(_tcpKeepIdleSeconds, _tcpKeepIntervalSeconds, _tcpKeepCount);
|
|
|
|
#elif defined(ESP32)
|
|
|
|
if (_tcpKeepIdleSeconds == 0 || _tcpKeepIntervalSeconds == 0 || _tcpKeepCount == 0)
|
|
{
|
|
_tcpKeepIdleSeconds = 0;
|
|
_tcpKeepIntervalSeconds = 0;
|
|
_tcpKeepCount = 0;
|
|
}
|
|
|
|
bool success = setOption(TCP_KEEPIDLE, &_tcpKeepIdleSeconds) > -1 &&
|
|
setOption(TCP_KEEPINTVL, &_tcpKeepIntervalSeconds) > -1 &&
|
|
setOption(TCP_KEEPCNT, &_tcpKeepCount) > -1;
|
|
if (!success)
|
|
_isKeepAlive = false;
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
}
|
|
|
|
ret = connected();
|
|
if (!ret)
|
|
stop();
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Upgrade the current connection by setting up the SSL and perform the SSL handshake.
|
|
*
|
|
* @param verify The Root CA certificate verification option
|
|
* @return operating result.
|
|
*/
|
|
|
|
bool connectSSL(bool verify)
|
|
{
|
|
#if !defined(ESP_MAIL_DISABLE_SSL)
|
|
_tcp_client->setDebugLevel(2);
|
|
|
|
bool ret = _tcp_client->connected();
|
|
|
|
if (ret)
|
|
{
|
|
setVerify(verify);
|
|
ret = _tcp_client->connectSSL(_host.c_str(), _port);
|
|
if (ret)
|
|
_secured = true;
|
|
}
|
|
|
|
if (!ret)
|
|
stop();
|
|
|
|
return ret;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Stop TCP connection.
|
|
*/
|
|
void stop()
|
|
{
|
|
if (_tcp_client)
|
|
_tcp_client->stop();
|
|
}
|
|
|
|
/**
|
|
* Get the TCP connection status.
|
|
* @return true for connected or false for not connected.
|
|
*/
|
|
bool connected() { return _tcp_client && _tcp_client->connected(); };
|
|
|
|
/**
|
|
* The TCP data write function.
|
|
* @param data The data to write.
|
|
* @param len The length of data to write.
|
|
* @return The size of data that was successfully written or 0 for error.
|
|
*/
|
|
int write(uint8_t *data, int len)
|
|
{
|
|
if (!_tcp_client)
|
|
return TCP_CLIENT_ERROR_NOT_INITIALIZED;
|
|
|
|
if (!data)
|
|
return TCP_CLIENT_ERROR_SEND_DATA_FAILED;
|
|
|
|
if (len == 0)
|
|
return TCP_CLIENT_ERROR_SEND_DATA_FAILED;
|
|
|
|
if (!networkReady())
|
|
return TCP_CLIENT_ERROR_NOT_CONNECTED;
|
|
|
|
if (!connect(isSecure(), isVerify()))
|
|
return TCP_CLIENT_ERROR_CONNECTION_REFUSED;
|
|
|
|
int toSend = _chunkSize;
|
|
int sent = 0;
|
|
while (sent < len)
|
|
{
|
|
if (sent + toSend > len)
|
|
toSend = len - sent;
|
|
|
|
if ((int)_tcp_client->write(data + sent, toSend) != toSend)
|
|
return TCP_CLIENT_ERROR_SEND_DATA_FAILED;
|
|
|
|
sent += toSend;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
/**
|
|
* The TCP data send function.
|
|
* @param data The data to send.
|
|
* @return The size of data that was successfully sent or 0 for error.
|
|
*/
|
|
int send(const char *data) { return write((uint8_t *)data, strlen(data)); }
|
|
|
|
/**
|
|
* The TCP data print function.
|
|
* @param data The data to print.
|
|
* @return The size of data that was successfully print or 0 for error.
|
|
*/
|
|
int print(const char *data) { return send(data); }
|
|
|
|
/**
|
|
* The TCP data print function.
|
|
* @param data The data to print.
|
|
* @return The size of data that was successfully print or 0 for error.
|
|
*/
|
|
int print(int data)
|
|
{
|
|
char buf[64];
|
|
memset(buf, 0, 64);
|
|
sprintf(buf, (const char *)FPSTR("%d"), data);
|
|
int ret = send(buf);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* The TCP data print with new line function.
|
|
* @param data The data to print.
|
|
* @return The size of data that was successfully print or 0 for error.
|
|
*/
|
|
int println(const char *data)
|
|
{
|
|
int len = send(data);
|
|
if (len < 0)
|
|
return len;
|
|
int sz = send((const char *)FPSTR("\r\n"));
|
|
if (sz < 0)
|
|
return sz;
|
|
return len + sz;
|
|
}
|
|
|
|
/**
|
|
* The TCP data print with new line function.
|
|
* @param data The data to print.
|
|
* @return The size of data that was successfully print or 0 for error.
|
|
*/
|
|
int println(int data)
|
|
{
|
|
char buf[64];
|
|
memset(buf, 0, 64);
|
|
sprintf(buf, (const char *)FPSTR("%d\r\n"), data);
|
|
int ret = send(buf);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Get available data size to read.
|
|
* @return The avaiable data size.
|
|
*/
|
|
int available()
|
|
{
|
|
if (!_basic_client)
|
|
return TCP_CLIENT_ERROR_NOT_INITIALIZED;
|
|
|
|
return _tcp_client->available();
|
|
}
|
|
|
|
/**
|
|
* The TCP data read function.
|
|
* @return The read value or -1 for error.
|
|
*/
|
|
int read()
|
|
{
|
|
if (!_basic_client)
|
|
return TCP_CLIENT_ERROR_NOT_INITIALIZED;
|
|
|
|
return _tcp_client->read();
|
|
}
|
|
|
|
/**
|
|
* The TCP data read function.
|
|
* @param buf The data buffer.
|
|
* @param len The length of data that read.
|
|
* @return The size of data that was successfully read or negative value for error.
|
|
*/
|
|
int readBytes(uint8_t *buf, int len)
|
|
{
|
|
if (!_basic_client)
|
|
return TCP_CLIENT_ERROR_NOT_INITIALIZED;
|
|
|
|
return _tcp_client->read(buf, len);
|
|
}
|
|
|
|
/**
|
|
* The TCP data read function.
|
|
* @param buf The data buffer.
|
|
* @param len The length of data that read.
|
|
* @return The size of data that was successfully read or negative value for error.
|
|
*/
|
|
int readBytes(char *buf, int len)
|
|
{
|
|
return readBytes((uint8_t *)buf, len);
|
|
}
|
|
|
|
/**
|
|
* Wait for all receive buffer data read.
|
|
*/
|
|
void flush()
|
|
{
|
|
if (_tcp_client)
|
|
_tcp_client->flush();
|
|
}
|
|
|
|
/**
|
|
* Set the network connection request callback.
|
|
* @param networkConnectionCB The callback function that handles the network connection.
|
|
*/
|
|
void networkConnectionRequestCallback(NetworkConnectionRequestCallback networkConnectionCB)
|
|
{
|
|
_network_connection_cb = networkConnectionCB;
|
|
}
|
|
|
|
/**
|
|
* Set the network status request callback.
|
|
* @param networkStatusCB The callback function that calls the setNetworkStatus function to set the network status.
|
|
*/
|
|
void networkStatusRequestCallback(NetworkStatusRequestCallback networkStatusCB)
|
|
{
|
|
_network_status_cb = networkStatusCB;
|
|
}
|
|
|
|
/**
|
|
* Set the network status which should call in side the networkStatusRequestCallback function.
|
|
* @param status The status of network.
|
|
*/
|
|
void setNetworkStatus(bool status)
|
|
{
|
|
_network_status = status;
|
|
}
|
|
|
|
void setMBFS(MB_FS *mbfs) { _mbfs = mbfs; }
|
|
|
|
#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP)
|
|
void setSession(Session_Config *session_config)
|
|
{
|
|
_session_config = session_config;
|
|
}
|
|
#endif
|
|
|
|
void setClockReady(bool rdy)
|
|
{
|
|
_clock_ready = rdy;
|
|
}
|
|
|
|
void setCertType(esp_mail_cert_type type) { _cert_type = type; }
|
|
|
|
esp_mail_cert_type getCertType() { return _cert_type; }
|
|
|
|
void setDebugLevel(int debug) { _debug_level = debug; }
|
|
|
|
unsigned long tcpTimeout()
|
|
{
|
|
if (_tcp_client)
|
|
return 1000 * _tcp_client->getTimeout();
|
|
return 0;
|
|
}
|
|
|
|
void disconnect(){};
|
|
|
|
void keepAlive(int tcpKeepIdleSeconds, int tcpKeepIntervalSeconds, int tcpKeepCount)
|
|
{
|
|
_tcpKeepIdleSeconds = tcpKeepIdleSeconds;
|
|
_tcpKeepIntervalSeconds = tcpKeepIntervalSeconds;
|
|
_tcpKeepCount = tcpKeepCount;
|
|
_isKeepAlive = tcpKeepIdleSeconds > 0 && tcpKeepIntervalSeconds > 0 && tcpKeepCount > 0;
|
|
}
|
|
|
|
bool isKeepAliveSet() { return _tcpKeepIdleSeconds > -1 && _tcpKeepIntervalSeconds > -1 && _tcpKeepCount > -1; };
|
|
|
|
bool isKeepAlive() { return _isKeepAlive; };
|
|
|
|
void clear()
|
|
{
|
|
#if !defined(ESP_MAIL_DISABLE_SSL)
|
|
if (_basic_client && _client_type == esp_mail_client_type_internal_basic_client)
|
|
{
|
|
#if defined(ESP_MAIL_WIFI_IS_AVAILABLE)
|
|
delete (BASE_WIFICLIENT *)_basic_client;
|
|
#else
|
|
delete _basic_client;
|
|
#endif
|
|
_basic_client = nullptr;
|
|
}
|
|
#else
|
|
_basic_client = nullptr;
|
|
#endif
|
|
_client_type = esp_mail_client_type_undefined;
|
|
}
|
|
|
|
void setWiFi(esp_mail_wifi_credentials_t *wifi) { _wifi_multi = wifi; }
|
|
|
|
bool gprsConnect()
|
|
{
|
|
#if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE)
|
|
TinyGsm *gsmModem = (TinyGsm *)_modem;
|
|
if (gsmModem)
|
|
{
|
|
// Unlock your SIM card with a PIN if needed
|
|
if (_pin.length() && gsmModem->getSimStatus() != 3)
|
|
gsmModem->simUnlock(_pin.c_str());
|
|
|
|
#if defined(TINY_GSM_MODEM_XBEE)
|
|
// The XBee must run the gprsConnect function BEFORE waiting for network!
|
|
gsmModem->gprsConnect(_apn.c_str(), _user.c_str(), _password.c_str());
|
|
#endif
|
|
|
|
#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP))
|
|
if (_debug_level > 0 && _last_error == 0)
|
|
esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR("Waiting for network..."), esp_mail_debug_tag_type_info, false);
|
|
#endif
|
|
if (!gsmModem->waitForNetwork())
|
|
{
|
|
#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP))
|
|
if (_debug_level > 0 && _last_error == 0)
|
|
esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR(" fail"), esp_mail_debug_tag_type_info, true, false);
|
|
#endif
|
|
_last_error = 1;
|
|
_network_status = false;
|
|
return false;
|
|
}
|
|
|
|
#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP))
|
|
if (_debug_level > 0 && _last_error == 0)
|
|
esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR(" success"), esp_mail_debug_tag_type_info, true, false);
|
|
#endif
|
|
|
|
if (gsmModem->isNetworkConnected())
|
|
{
|
|
#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP))
|
|
if (_debug_level > 0 && _last_error == 0)
|
|
{
|
|
esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR("Connecting to "), esp_mail_debug_tag_type_info, false);
|
|
esp_mail_debug_print_tag(_apn.c_str(), esp_mail_debug_tag_type_info, false, false);
|
|
}
|
|
#endif
|
|
_network_status = gsmModem->gprsConnect(_apn.c_str(), _user.c_str(), _password.c_str()) &&
|
|
gsmModem->isGprsConnected();
|
|
|
|
#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP))
|
|
if (_debug_level > 0 && _last_error == 0)
|
|
{
|
|
if (_network_status)
|
|
esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR(" success"), esp_mail_debug_tag_type_info, true, false);
|
|
else
|
|
esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR(" fail"), esp_mail_debug_tag_type_info, true, false);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (!_network_status)
|
|
_last_error = 1;
|
|
|
|
return _network_status;
|
|
}
|
|
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bool gprsConnected()
|
|
{
|
|
#if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE)
|
|
TinyGsm *gsmModem = (TinyGsm *)_modem;
|
|
_network_status = gsmModem && gsmModem->isGprsConnected();
|
|
#endif
|
|
return _network_status;
|
|
}
|
|
|
|
bool gprsDisconnect()
|
|
{
|
|
#if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE)
|
|
TinyGsm *gsmModem = (TinyGsm *)_modem;
|
|
_network_status = gsmModem && gsmModem->gprsDisconnect();
|
|
#endif
|
|
return !_network_status;
|
|
}
|
|
|
|
bool gprsGetTime(int &year, int &month, int &day, int &hour, int &min, int &sec, float &timezone)
|
|
{
|
|
#if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE) && defined(TINY_GSM_MODEM_HAS_TIME)
|
|
|
|
if (!gprsConnected())
|
|
return 0;
|
|
|
|
TinyGsm *gsmModem = (TinyGsm *)_modem;
|
|
year = 0;
|
|
month = 0;
|
|
day = 0;
|
|
hour = 0;
|
|
min = 0;
|
|
sec = 0;
|
|
timezone = 0;
|
|
for (int8_t i = 5; i; i--)
|
|
{
|
|
if (gsmModem->getNetworkTime(&year, &month, &day, &hour, &min, &sec, &timezone))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
int setOption(int option, int *value)
|
|
{
|
|
#if defined(ESP32) && defined(ESP_MAIL_WIFI_IS_AVAILABLE)
|
|
// Actually we wish to use setSocketOption directly but it is ambiguous in old ESP32 core v1.0.x.;
|
|
// Use setOption instead for old core support.
|
|
return reinterpret_cast<BASE_WIFICLIENT *>(_basic_client)->setOption(option, value);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
void setTA(bool hasTA)
|
|
{
|
|
_has_ta = hasTA;
|
|
}
|
|
|
|
void setSecure(bool secure)
|
|
{
|
|
_secured = secure;
|
|
}
|
|
|
|
void setInSecure()
|
|
{
|
|
#if !defined(ESP_MAIL_DISABLE_SSL)
|
|
_use_insecure = true;
|
|
setTA(false);
|
|
#endif
|
|
}
|
|
|
|
void setVerify(bool verify)
|
|
{
|
|
#if !defined(ESP_MAIL_DISABLE_SSL)
|
|
if (_has_ta)
|
|
_use_insecure = !verify;
|
|
|
|
if (_use_insecure)
|
|
_tcp_client->setInsecure();
|
|
#endif
|
|
}
|
|
|
|
bool isSecure()
|
|
{
|
|
return _secured;
|
|
}
|
|
|
|
bool isVerify()
|
|
{
|
|
return !_use_insecure;
|
|
}
|
|
|
|
int rxBufDivider = 16;
|
|
int txBufDivider = 32;
|
|
|
|
private:
|
|
// lwIP TCP Keepalive idle in seconds.
|
|
int _tcpKeepIdleSeconds = -1;
|
|
// lwIP TCP Keepalive interval in seconds.
|
|
int _tcpKeepIntervalSeconds = -1;
|
|
// lwIP TCP Keepalive count.
|
|
int _tcpKeepCount = -1;
|
|
bool _isKeepAlive = false;
|
|
|
|
uint16_t _bsslRxSize = 1024;
|
|
uint16_t _bsslTxSize = 1024;
|
|
const int _maxRXBufSize = 16384; // SSL full supported 16 kB
|
|
const int _maxTXBufSize = 16384;
|
|
const int _minRXTXBufSize = 512;
|
|
#if defined(ESP_MAIL_DISABLE_SSL)
|
|
Client *_tcp_client = nullptr;
|
|
#else
|
|
ESP_SSLClient *_tcp_client = nullptr;
|
|
X509List *_x509 = nullptr;
|
|
#endif
|
|
|
|
MB_String _host;
|
|
uint16_t _port = 443;
|
|
|
|
MB_FS *_mbfs = nullptr;
|
|
Client *_basic_client = nullptr;
|
|
esp_mail_wifi_credentials_t *_wifi_multi = nullptr;
|
|
#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP)
|
|
Session_Config *_session_config = nullptr;
|
|
#endif
|
|
NetworkConnectionRequestCallback _network_connection_cb = NULL;
|
|
NetworkStatusRequestCallback _network_status_cb = NULL;
|
|
#if defined(ESP_MAIL_HAS_WIFIMULTI)
|
|
WiFiMulti *_multi = nullptr;
|
|
#endif
|
|
#if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE)
|
|
MB_String _pin, _apn, _user, _password;
|
|
void *_modem = nullptr;
|
|
#endif
|
|
|
|
bool _has_ta = false;
|
|
bool _secured = false;
|
|
bool _use_insecure = false;
|
|
int _debug_level = 0;
|
|
int _chunkSize = 1024;
|
|
bool _clock_ready = false;
|
|
int _last_error = 0;
|
|
volatile bool _network_status = false;
|
|
int _rx_size = -1, _tx_size = -1;
|
|
|
|
esp_mail_cert_type _cert_type = esp_mail_cert_type_undefined;
|
|
esp_mail_client_type _client_type = esp_mail_client_type_undefined;
|
|
};
|
|
|
|
#endif |