Tasmota/lib/lib_div/lib_mail/src/ESP_Mail_Client.cpp
2021-06-03 10:59:44 +02:00

8532 lines
238 KiB
C++
Executable File

/**
* Mail Client Arduino Library for Espressif's ESP32 and ESP8266
*
* Version: 1.2.0
* Released: May 17, 2021
*
* Updates:
* - Add support ESP8266 Core SDK v3.x.x.
*
*
* This library allows Espressif's ESP32 and ESP8266 devices to send and read Email
* through the SMTP and IMAP servers.
*
* The MIT License (MIT)
* Copyright (c) 2021 K. Suwatchai (Mobizt)
*
*
* Permission is hereby granted, free of charge, to any person obtaining 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_Client_CPP
#define ESP_Mail_Client_CPP
#include "ESP_Mail_Client.h"
#if defined(ESP32)
extern "C"
{
#include <esp_err.h>
#include <esp_wifi.h>
}
#endif
bool ESP_Mail_Client::sendIMAPCommand(IMAPSession *imap, int msgIndex, int cmdCase)
{
std::string cmd;
if (imap->_uidSearch || strlen(imap->_config->fetch.uid) > 0)
appendP(cmd, esp_mail_str_142, true);
else
appendP(cmd, esp_mail_str_143, true);
char *tmp = intStr(imap->_msgNum[msgIndex]);
cmd += tmp;
delS(tmp);
appendP(cmd, esp_mail_str_147, false);
if (!imap->_config->fetch.set_seen)
{
appendP(cmd, esp_mail_str_152, false);
appendP(cmd, esp_mail_str_214, false);
}
appendP(cmd, esp_mail_str_218, false);
switch (cmdCase)
{
case 1:
appendP(cmd, esp_mail_str_269, false);
break;
case 2:
if (cPart(imap)->partNumFetchStr.length() > 0)
cmd += cPart(imap)->partNumFetchStr;
else
appendP(cmd, esp_mail_str_215, false);
appendP(cmd, esp_mail_str_156, false);
break;
case 3:
cmd += cPart(imap)->partNumFetchStr;
appendP(cmd, esp_mail_str_156, false);
break;
default:
break;
}
if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
return true;
}
bool ESP_Mail_Client::readMail(IMAPSession *imap, bool closeSession)
{
imap->checkUID();
imap->checkPath();
if (!imap->_tcpConnected)
imap->_mailboxOpened = false;
std::string buf;
std::string command;
std::string _uid;
appendP(command, esp_mail_str_27, true);
char *tmp = nullptr;
size_t readCount = 0;
imap->_multipart_levels.clear();
if (!reconnect(imap))
return false;
int cmem = ESP.getFreeHeap();
if (cmem < ESP_MAIL_MIN_MEM)
{
if (imap->_debug)
{
esp_mail_debug("");
errorStatusCB(imap, MAIL_CLIENT_ERROR_OUT_OF_MEMORY);
}
goto out;
}
//new session
if (!imap->_tcpConnected)
{
//authenticate new
if (!imapAuth(imap))
{
closeTCP(imap);
return false;
}
}
else
{
//reuse session
for (size_t i = 0; i < imap->_headers.size(); i++)
imap->_headers[i].part_headers.clear();
imap->_headers.clear();
if (strlen(imap->_config->fetch.uid) > 0)
imap->_headerOnly = false;
else
imap->_headerOnly = true;
}
imap->_rfc822_part_count = 0;
imap->_mbif._availableItems = 0;
imap->_msgNum.clear();
imap->_uidSearch = false;
imap->_mbif._searchCount = 0;
if (imap->_currentFolder.length() == 0)
return handleIMAPError(imap, IMAP_STATUS_NO_MAILBOX_FOLDER_OPENED, false);
if (!imap->_mailboxOpened || (imap->_config->fetch.set_seen && !imap->_headerOnly && imap->_readOnlyMode))
{
if (!imap->openFolder(imap->_currentFolder.c_str(), imap->_readOnlyMode && !imap->_config->fetch.set_seen))
return handleIMAPError(imap, IMAP_STATUS_OPEN_MAILBOX_FAILED, false);
}
if (imap->_headerOnly)
{
if (strlen(imap->_config->search.criteria) > 0)
{
if (imap->_readCallback)
{
imapCB(imap, "", false);
imapCBP(imap, esp_mail_str_66, false);
}
if (imap->_debug)
debugInfoP(esp_mail_str_232);
if (strposP(imap->_config->search.criteria, esp_mail_str_137, 0) != -1)
{
imap->_uidSearch = true;
appendP(command, esp_mail_str_138, false);
}
appendP(command, esp_mail_str_139, false);
for (size_t i = 0; i < strlen(imap->_config->search.criteria); i++)
{
if (imap->_config->search.criteria[i] != ' ' && imap->_config->search.criteria[i] != '\r' && imap->_config->search.criteria[i] != '\n' && imap->_config->search.criteria[i] != '$')
buf.append(1, imap->_config->search.criteria[i]);
if (imap->_config->search.criteria[i] == ' ')
{
tmp = strP(esp_mail_str_140);
char *tmp2 = strP(esp_mail_str_224);
if ((imap->_uidSearch && strcmp(buf.c_str(), tmp) == 0) || (imap->_unseen && buf.find(tmp2) != std::string::npos))
buf.clear();
delS(tmp);
delS(tmp2);
tmp = strP(esp_mail_str_141);
if (strcmp(buf.c_str(), tmp) != 0 && buf.length() > 0)
{
appendP(command, esp_mail_str_131, false);
command += buf;
}
delS(tmp);
buf.clear();
}
}
tmp = strP(esp_mail_str_223);
if (imap->_unseen && strpos(imap->_config->search.criteria, tmp, 0) == -1)
appendP(command, esp_mail_str_223, false);
delS(tmp);
if (buf.length() > 0)
{
appendP(command, esp_mail_str_131, false);
command += buf;
}
if (imapSend(imap, command.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
std::string().swap(command);
imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_search;
if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, closeSession))
return false;
if (imap->_readCallback)
{
std::string s;
appendP(s, esp_mail_str_34, true);
appendP(s, esp_mail_str_68, false);
char *tmp = intStr(imap->_config->limit.search);
s += tmp;
delS(tmp);
imapCB(imap, s.c_str(), false);
if (imap->_msgNum.size() > 0)
{
appendP(s, esp_mail_str_69, true);
tmp = intStr(imap->_mbif._searchCount);
s += tmp;
delS(tmp);
appendP(s, esp_mail_str_70, false);
imapCB(imap, s.c_str(), false);
appendP(s, esp_mail_str_71, true);
tmp = intStr(imap->_msgNum.size());
s += tmp;
delS(tmp);
appendP(s, esp_mail_str_70, false);
imapCB(imap, s.c_str(), false);
}
else
imapCBP(imap, esp_mail_str_72, false);
}
}
else
{
imap->_mbif._availableItems++;
imap->_msgNum.push_back(imap->_mbif._nextUID - 1);
imap->_headerOnly = false;
char *tmp = intStr(imap->_mbif._nextUID - 1);
_uid = tmp;
delS(tmp);
imap->_config->fetch.uid = _uid.c_str();
if (imap->_readCallback)
imapCBP(imap, esp_mail_str_73, false);
}
}
else
{
imap->_mbif._availableItems++;
imap->_msgNum.push_back(atoi(imap->_config->fetch.uid));
}
for (size_t i = 0; i < imap->_msgNum.size(); i++)
{
imap->_cMsgIdx = i;
imap->_totalRead++;
if (ESP.getFreeHeap() - (imap->_config->limit.msg_size * (i + 1)) < ESP_MAIL_MIN_MEM)
{
if (imap->_debug)
errorStatusCB(imap, MAIL_CLIENT_ERROR_OUT_OF_MEMORY);
goto out;
}
if (imap->_readCallback)
{
readCount++;
std::string s;
appendP(s, esp_mail_str_74, true);
char *tmp = intStr(imap->_totalRead);
s += tmp;
delS(tmp);
if (imap->_uidSearch || strlen(imap->_config->fetch.uid) > 0)
appendP(s, esp_mail_str_75, false);
else
appendP(s, esp_mail_str_76, false);
tmp = intStr(imap->_msgNum[i]);
s += tmp;
delS(tmp);
imapCB(imap, "", false);
imapCB(imap, s.c_str(), false);
}
if (imap->_debug)
debugInfoP(esp_mail_str_233);
std::string cmd;
if (imap->_uidSearch || strlen(imap->_config->fetch.uid) > 0)
appendP(cmd, esp_mail_str_142, true);
else
appendP(cmd, esp_mail_str_143, true);
if (imap->_debug)
debugInfoP(esp_mail_str_77);
char *tmp = intStr(imap->_msgNum[i]);
cmd += tmp;
delS(tmp);
appendP(cmd, esp_mail_str_147, false);
if (!imap->_config->fetch.set_seen)
{
appendP(cmd, esp_mail_str_152, false);
appendP(cmd, esp_mail_str_214, false);
}
appendP(cmd, esp_mail_str_218, false);
appendP(cmd, esp_mail_str_144, false);
appendP(cmd, esp_mail_str_156, false);
if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_fetch_body_header;
int err = IMAP_STATUS_BAD_COMMAND;
if (imap->_headerOnly)
err = IMAP_STATUS_IMAP_RESPONSE_FAILED;
if (!handleIMAPResponse(imap, err, closeSession))
return false;
if (!imap->_headerOnly)
{
imap->_cPartIdx = 0;
//multipart
if (cHeader(imap)->multipart)
{
struct esp_mail_imap_multipart_level_t mlevel;
mlevel.level = 1;
mlevel.fetch_rfc822_header = false;
mlevel.append_body_text = false;
imap->_multipart_levels.push_back(mlevel);
if (!fetchMultipartBodyHeader(imap, i))
return false;
}
else
{
//singlepart
if (imap->_debug)
{
std::string s;
appendP(s, esp_mail_str_81, true);
s += '1';
esp_mail_debug(s.c_str());
}
cHeader(imap)->partNumStr.clear();
if (!sendIMAPCommand(imap, i, 1))
return false;
imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_fetch_body_mime;
if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, closeSession))
return false;
}
if (imap->_config->download.text || imap->_config->download.html || imap->_config->download.attachment || imap->_config->download.inlineImg)
{
if (!_sdOk && imap->_storageType == esp_mail_file_storage_type_sd)
{
_sdOk = sdTest();
if (_sdOk)
if (!ESP_MAIL_SD_FS.exists(imap->_config->storage.saved_path))
createDirs(imap->_config->storage.saved_path);
}
else if (!_flashOk && imap->_storageType == esp_mail_file_storage_type_flash)
#if defined(ESP32)
_flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH);
#elif defined(ESP8266)
_flashOk = ESP_MAIL_FLASH_FS.begin();
#endif
}
if (cHeader(imap)->part_headers.size() > 0)
{
if (cHeader(imap)->attachment_count > 0 && imap->_readCallback)
{
std::string s;
appendP(s, esp_mail_str_34, true);
appendP(s, esp_mail_str_78, false);
char *tmp = intStr(cHeader(imap)->attachment_count);
s += tmp;
delS(tmp);
appendP(s, esp_mail_str_79, false);
imapCB(imap, s.c_str(), false);
for (size_t j = 0; j < cHeader(imap)->part_headers.size(); j++)
{
imap->_cPartIdx = j;
if (!cPart(imap)->rfc822_part && cPart(imap)->attach_type != esp_mail_att_type_none)
imapCB(imap, cPart(imap)->filename.c_str(), false);
}
}
std::string s1, s2;
int _idx1 = 0;
for (size_t j = 0; j < cHeader(imap)->part_headers.size(); j++)
{
imap->_cPartIdx = j;
if (cPart(imap)->rfc822_part)
{
s1 = cPart(imap)->partNumStr;
_idx1 = cPart(imap)->rfc822_msg_Idx;
}
else if (s1.length() > 0)
{
if (multipartMember(s1, cPart(imap)->partNumStr))
{
cPart(imap)->message_sub_type = esp_mail_imap_message_sub_type_rfc822;
cPart(imap)->rfc822_msg_Idx = _idx1;
}
}
if (cPart(imap)->multipart_sub_type == esp_mail_imap_multipart_sub_type_parallel)
s2 = cPart(imap)->partNumStr;
else if (s2.length() > 0)
{
if (multipartMember(s2, cPart(imap)->partNumStr))
{
cPart(imap)->attach_type = esp_mail_att_type_attachment;
if (cPart(imap)->filename.length() == 0)
{
if (cPart(imap)->name.length() > 0)
cPart(imap)->filename = cPart(imap)->name;
else
{
char *tmp = getUID();
cPart(imap)->filename = tmp;
appendP(cPart(imap)->filename, esp_mail_str_40, false);
delS(tmp);
}
}
}
}
}
int acnt = 0;
int ccnt = 0;
for (size_t j = 0; j < cHeader(imap)->part_headers.size(); j++)
{
imap->_cPartIdx = j;
if (cPart(imap)->rfc822_part || cPart(imap)->multipart_sub_type != esp_mail_imap_multipart_sub_type_none)
continue;
bool rfc822_body_subtype = cPart(imap)->message_sub_type == esp_mail_imap_message_sub_type_rfc822;
if (cPart(imap)->attach_type == esp_mail_att_type_none || cPart(imap)->msg_type == esp_mail_msg_type_html || cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched)
{
bool ret = ((imap->_config->enable.rfc822 || imap->_config->download.rfc822) && rfc822_body_subtype) || (!rfc822_body_subtype && ((imap->_config->enable.text && (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched)) || (imap->_config->enable.html && cPart(imap)->msg_type == esp_mail_msg_type_html) || (cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text)));
if (!ret)
continue;
if ((imap->_config->download.rfc822 && rfc822_body_subtype) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text))))
{
if (ccnt == 0)
{
imapCB(imap, "", false);
imapCBP(imap, esp_mail_str_57, false);
}
if (imap->_debug)
{
if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched)
debugInfoP(esp_mail_str_59);
else if (cPart(imap)->msg_type == esp_mail_msg_type_html)
debugInfoP(esp_mail_str_60);
}
}
else
{
if (ccnt == 0)
{
imapCB(imap, "", false);
imapCBP(imap, esp_mail_str_307, false);
}
if (imap->_debug)
{
if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched)
debugInfoP(esp_mail_str_308);
else if (cPart(imap)->msg_type == esp_mail_msg_type_html)
debugInfoP(esp_mail_str_309);
}
}
ccnt++;
if (!sendIMAPCommand(imap, i, 2))
return false;
imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_fetch_body_text;
if (!handleIMAPResponse(imap, IMAP_STATUS_IMAP_RESPONSE_FAILED, closeSession))
return false;
}
else if (cPart(imap)->attach_type != esp_mail_att_type_none && (_sdOk || _flashOk))
{
if (imap->_config->download.attachment || imap->_config->download.inlineImg)
{
if (acnt == 0)
{
imapCB(imap, "", false);
imapCBP(imap, esp_mail_str_80, false);
}
if (imap->_debug)
debugInfoP(esp_mail_str_55);
acnt++;
if (cPart(imap)->octetLen <= (int)imap->_config->limit.attachment_size)
{
if (_sdOk || _flashOk)
{
if ((int)j < (int)cHeader(imap)->part_headers.size() - 1)
if (cHeader(imap)->part_headers[j + 1].octetLen > (int)imap->_config->limit.attachment_size)
cHeader(imap)->downloaded_bytes += cHeader(imap)->part_headers[j + 1].octetLen;
if (!sendIMAPCommand(imap, i, 3))
return false;
imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_fetch_body_attachment;
if (!handleIMAPResponse(imap, IMAP_STATUS_IMAP_RESPONSE_FAILED, closeSession))
return false;
delay(0);
}
}
else
{
if ((int)j == (int)cHeader(imap)->part_headers.size() - 1)
cHeader(imap)->downloaded_bytes += cPart(imap)->octetLen;
}
}
}
}
}
if (imap->_config->download.header && !imap->_headerSaved)
{
if (imap->_readCallback)
{
imapCB(imap, "", false);
imapCBP(imap, esp_mail_str_124, false);
}
saveHeader(imap);
}
if (closeSession)
{
if (imap->_storageType == esp_mail_file_storage_type_sd)
{
if (_sdOk)
ESP_MAIL_SD_FS.end();
_sdOk = false;
}
else if (imap->_storageType == esp_mail_file_storage_type_flash)
{
if (_flashOk)
ESP_MAIL_FLASH_FS.end();
_flashOk = false;
}
}
imap->_cMsgIdx++;
}
if (imap->_debug)
{
std::string s;
appendP(s, esp_mail_str_261, true);
appendP(s, esp_mail_str_84, false);
char *tmp = intStr(ESP.getFreeHeap());
s += tmp;
delS(tmp);
esp_mail_debug(s.c_str());
}
}
out:
if (readCount < imap->_msgNum.size())
{
imap->_mbif._availableItems = readCount;
imap->_msgNum.erase(imap->_msgNum.begin() + readCount, imap->_msgNum.end());
}
if (closeSession)
{
if (!imap->closeSession())
return false;
}
else
{
if (imap->_readCallback)
{
imapCB(imap, "", false);
imapCBP(imap, esp_mail_str_87, false);
}
if (imap->_debug)
debugInfoP(esp_mail_str_88);
}
if (imap->_readCallback)
imapCB(imap, "", true);
return true;
}
bool ESP_Mail_Client::getMultipartFechCmd(IMAPSession *imap, int msgIdx, std::string &partText)
{
if (imap->_multipart_levels.size() == 0)
return false;
int cLevel = imap->_multipart_levels.size() - 1;
cHeader(imap)->partNumStr.clear();
if (imap->_uidSearch || strlen(imap->_config->fetch.uid) > 0)
appendP(partText, esp_mail_str_142, true);
else
appendP(partText, esp_mail_str_143, true);
char *tmp = intStr(imap->_msgNum[msgIdx]);
partText += tmp;
delS(tmp);
appendP(partText, esp_mail_str_147, false);
if (!imap->_config->fetch.set_seen)
{
appendP(partText, esp_mail_str_152, false);
appendP(partText, esp_mail_str_214, false);
}
appendP(partText, esp_mail_str_218, false);
for (size_t i = 0; i < imap->_multipart_levels.size(); i++)
{
if (i > 0)
{
appendP(partText, esp_mail_str_152, false);
appendP(cHeader(imap)->partNumStr, esp_mail_str_152, false);
}
tmp = intStr(imap->_multipart_levels[i].level);
partText += tmp;
cHeader(imap)->partNumStr += tmp;
delS(tmp);
}
if (imap->_multipart_levels[cLevel].fetch_rfc822_header)
{
appendP(partText, esp_mail_str_51, false);
imap->_multipart_levels[cLevel].append_body_text = true;
}
else
appendP(partText, esp_mail_str_148, false);
imap->_multipart_levels[cLevel].fetch_rfc822_header = false;
return true;
}
bool ESP_Mail_Client::multipartMember(const std::string &part, const std::string &check)
{
if (part.length() > check.length())
return false;
for (size_t i = 0; i < part.length(); i++)
if (part[i] != check[i])
return false;
return true;
}
bool ESP_Mail_Client::fetchMultipartBodyHeader(IMAPSession *imap, int msgIdx)
{
bool ret = true;
if (!connected(imap))
{
closeTCP(imap);
return false;
}
int cLevel = 0;
do
{
struct esp_mail_message_part_info_t *_cpart = &cHeader(imap)->part_headers[cHeader(imap)->message_data_count - 1];
bool rfc822_body_subtype = _cpart->message_sub_type == esp_mail_imap_message_sub_type_rfc822;
std::string cmd;
if (!getMultipartFechCmd(imap, msgIdx, cmd))
return true;
if (imap->_debug)
{
std::string s;
if (imap->_multipart_levels.size() > 1)
appendP(s, esp_mail_str_86, true);
else
appendP(s, esp_mail_str_81, true);
s += cHeader(imap)->partNumStr;
esp_mail_debug(s.c_str());
}
if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
imap->_imap_cmd = esp_mail_imap_cmd_fetch_body_mime;
ret = handleIMAPResponse(imap, IMAP_STATUS_IMAP_RESPONSE_FAILED, false);
_cpart = &cHeader(imap)->part_headers[cHeader(imap)->message_data_count - 1];
rfc822_body_subtype = _cpart->message_sub_type == esp_mail_imap_message_sub_type_rfc822;
cLevel = imap->_multipart_levels.size() - 1;
if (ret)
{
if (_cpart->multipart)
{
if (_cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_parallel || _cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_alternative || _cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_related || _cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_mixed)
{
struct esp_mail_imap_multipart_level_t mlevel;
mlevel.level = 1;
mlevel.fetch_rfc822_header = false;
mlevel.append_body_text = false;
imap->_multipart_levels.push_back(mlevel);
fetchMultipartBodyHeader(imap, msgIdx);
}
else
imap->_multipart_levels[cLevel].level++;
}
else
{
if (rfc822_body_subtype)
{
//to get additional rfc822 message header
imap->_multipart_levels[cLevel].fetch_rfc822_header = true;
fetchMultipartBodyHeader(imap, msgIdx);
}
else
{
if (imap->_multipart_levels[cLevel].append_body_text)
{
//single part rfc822 message body, append TEXT to the body fetch command
appendP(_cpart->partNumFetchStr, esp_mail_str_152, false);
appendP(_cpart->partNumFetchStr, esp_mail_str_215, false);
imap->_multipart_levels[cLevel].append_body_text = false;
}
imap->_multipart_levels[cLevel].level++;
}
}
}
} while (ret);
imap->_multipart_levels.pop_back();
if (imap->_multipart_levels.size() > 0)
{
cLevel = imap->_multipart_levels.size() - 1;
imap->_multipart_levels[cLevel].level++;
}
return true;
}
bool ESP_Mail_Client::connected(IMAPSession *imap)
{
if (!imap->_secure)
{
if (!imap->httpClient._stream())
return false;
return imap->httpClient._stream()->_ns_connected();
}
else
{
if (!imap->httpClient.stream())
return false;
return imap->httpClient.stream()->connected();
}
}
bool ESP_Mail_Client::imapAuth(IMAPSession *imap)
{
bool ssl = false;
std::string buf;
#if defined(ESP32)
imap->httpClient.setDebugCallback(NULL);
#elif defined(ESP8266)
#endif
if (imap->_config != nullptr)
{
if (strlen(imap->_config->fetch.uid) > 0)
imap->_headerOnly = false;
else
imap->_headerOnly = true;
}
imap->_totalRead = 0;
imap->_secure = true;
bool secureMode = true;
#if defined(ESP32)
if (imap->_debug)
imap->httpClient.setDebugCallback(esp_mail_debug);
#elif defined(ESP8266)
imap->httpClient.txBufDivider = 16; //minimum, tx buffer size for ssl data and request command data
imap->httpClient.rxBufDivider = 1;
if (imap->_config != nullptr)
{
if (!imap->_headerOnly && !imap->_config->enable.html && !imap->_config->enable.text && !imap->_config->download.attachment && !imap->_config->download.inlineImg && !imap->_config->download.html && !imap->_config->download.text)
imap->httpClient.rxBufDivider = 16; // minimum rx buffer size for only message header
}
#endif
if (imap->_sesson_cfg->server.port == esp_mail_imap_port_143)
{
imap->_secure = false;
secureMode = false;
}
else
secureMode = !imap->_sesson_cfg->secure.startTLS;
setSecure(imap->httpClient, imap->_sesson_cfg, imap->_caCert);
if (imap->_readCallback)
imapCBP(imap, esp_mail_str_50, false);
if (imap->_debug)
{
std::string s;
appendP(s, esp_mail_str_314, true);
s += ESP_MAIL_VERSION;
esp_mail_debug(s.c_str());
debugInfoP(esp_mail_str_225);
appendP(s, esp_mail_str_261, true);
appendP(s, esp_mail_str_211, false);
s += imap->_sesson_cfg->server.host_name;
esp_mail_debug(s.c_str());
char *tmp = intStr(imap->_sesson_cfg->server.port);
appendP(s, esp_mail_str_261, true);
appendP(s, esp_mail_str_201, false);
s += tmp;
delS(tmp);
esp_mail_debug(s.c_str());
}
imap->httpClient.begin(imap->_sesson_cfg->server.host_name, imap->_sesson_cfg->server.port);
if (!imap->httpClient.connect(secureMode))
return handleIMAPError(imap, IMAP_STATUS_SERVER_CONNECT_FAILED, false);
imap->_tcpConnected = true;
WiFiClient *stream = imap->httpClient.stream();
#if defined(ESP32)
stream->setTimeout(ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC);
#elif defined(ESP8266)
stream->setTimeout(ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC * 1000);
#endif
imap->httpClient.tcpTimeout = ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC * 1000;
if (imap->_readCallback)
imapCBP(imap, esp_mail_str_54, false);
if (imap->_debug)
debugInfoP(esp_mail_str_228);
init:
if (!imap->checkCapability())
return false;
//start TLS when needed or the server issue
if ((imap->_auth_capability.start_tls || imap->_sesson_cfg->secure.startTLS) && !ssl)
{
std::string s;
if (imap->_readCallback)
{
appendP(s, esp_mail_str_34, true);
appendP(s, esp_mail_str_209, false);
esp_mail_debug(s.c_str());
}
if (imap->_debug)
{
appendP(s, esp_mail_str_196, true);
esp_mail_debug(s.c_str());
}
imapSendP(imap, esp_mail_str_311, false);
imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_starttls;
if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, false))
return false;
if (imap->_debug)
{
debugInfoP(esp_mail_str_310);
}
//connect in secure mode
//do ssl handshaking
if (!imap->httpClient._stream()->_ns_connect_ssl())
return handleIMAPError(imap, MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP, false);
//set the secure mode
imap->_sesson_cfg->secure.startTLS = false;
ssl = true;
imap->_secure = true;
//check the capabilitiy again
goto init;
}
imap->clearMessageData();
imap->_mailboxOpened = false;
bool creds = strlen(imap->_sesson_cfg->login.email) > 0 && strlen(imap->_sesson_cfg->login.password) > 0;
bool xoauth_auth = strlen(imap->_sesson_cfg->login.accessToken) > 0 && imap->_auth_capability.xoauth2;
bool login_auth = creds;
bool plain_auth = imap->_auth_capability.plain && creds;
bool supported_auth = xoauth_auth || login_auth || plain_auth;
if (!supported_auth)
return handleIMAPError(imap, IMAP_STATUS_NO_SUPPORTED_AUTH, false);
//rfc4959
if (supported_auth)
{
if (imap->_readCallback)
{
imapCB(imap, "", false);
imapCBP(imap, esp_mail_str_56, false);
}
}
if (xoauth_auth)
{
if (!imap->_auth_capability.xoauth2)
return handleIMAPError(imap, IMAP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED, false);
if (imap->_debug)
debugInfoP(esp_mail_str_291);
std::string cmd;
appendP(cmd, esp_mail_str_292, true);
cmd += getEncodedToken(imap);
if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_auth;
if (!handleIMAPResponse(imap, IMAP_STATUS_LOGIN_FAILED, false))
return false;
}
else if (login_auth)
{
if (imap->_debug)
debugInfoP(esp_mail_str_229);
std::string cmd;
appendP(cmd, esp_mail_str_130, true);
cmd += imap->_sesson_cfg->login.email;
appendP(cmd, esp_mail_str_131, false);
cmd += imap->_sesson_cfg->login.password;
if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_login;
if (!handleIMAPResponse(imap, IMAP_STATUS_LOGIN_FAILED, true))
return false;
}
else if (plain_auth)
{
if (imap->_debug)
debugInfoP(esp_mail_str_290);
const char *usr = imap->_sesson_cfg->login.email;
const char *psw = imap->_sesson_cfg->login.password;
int len = strlen(usr) + strlen(psw) + 2;
uint8_t *tmp = new uint8_t[len];
memset(tmp, 0, len);
int p = 1;
memcpy(tmp + p, usr, strlen(usr));
p += strlen(usr) + 1;
memcpy(tmp + p, psw, strlen(psw));
p += strlen(psw);
std::string s;
appendP(s, esp_mail_str_41, true);
s += encodeBase64Str(tmp, p);
delete[] tmp;
if (imapSend(imap, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_login;
if (!handleIMAPResponse(imap, IMAP_STATUS_LOGIN_FAILED, true))
return false;
}
return true;
}
std::string ESP_Mail_Client::getEncodedToken(IMAPSession *imap)
{
std::string raw;
appendP(raw, esp_mail_str_285, true);
raw += imap->_sesson_cfg->login.email;
appendP(raw, esp_mail_str_286, false);
raw += imap->_sesson_cfg->login.accessToken;
appendP(raw, esp_mail_str_287, false);
std::string s = encodeBase64Str((const unsigned char *)raw.c_str(), raw.length());
return s;
}
bool ESP_Mail_Client::imapLogout(IMAPSession *imap)
{
if (imap->_readCallback)
{
imapCB(imap, "", false);
imapCBP(imap, esp_mail_str_85, false);
}
if (imap->_debug)
debugInfoP(esp_mail_str_234);
if (imapSendP(imap, esp_mail_str_146, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
imap->_imap_cmd = esp_mail_imap_cmd_logout;
if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, false))
return false;
if (imap->_readCallback)
{
imapCB(imap, "", false);
imapCBP(imap, esp_mail_str_187, false);
}
if (imap->_debug)
debugInfoP(esp_mail_str_235);
return true;
}
void ESP_Mail_Client::errorStatusCB(IMAPSession *imap, int error)
{
imap->_imapStatus.statusCode = error;
std::string s;
if (imap->_readCallback)
{
appendP(s, esp_mail_str_53, true);
s += imap->errorReason().c_str();
imapCB(imap, s.c_str(), false);
}
if (imap->_debug)
{
appendP(s, esp_mail_str_185, true);
s += imap->errorReason().c_str();
esp_mail_debug(s.c_str());
}
}
size_t ESP_Mail_Client::imapSendP(IMAPSession *imap, PGM_P v, bool newline)
{
if (!reconnect(imap))
{
closeTCP(imap);
return 0;
}
if (!connected(imap))
{
errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST);
return 0;
}
if (!imap->_tcpConnected)
{
errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
return 0;
}
char *tmp = strP(v);
size_t len = 0;
if (newline)
{
if (imap->_debugLevel > esp_mail_debug_level_2)
esp_mail_debug(tmp);
if (!imap->_secure)
len = imap->httpClient._ns_println(tmp);
else
len = imap->httpClient.stream()->println(tmp);
}
else
{
if (imap->_debugLevel > esp_mail_debug_level_2)
esp_mail_debug_line(tmp, false);
if (!imap->_secure)
len = imap->httpClient._ns_print(tmp);
else
len = imap->httpClient.stream()->print(tmp);
}
if (len != strlen(tmp) && len != strlen(tmp) + 2)
{
errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
len = 0;
}
delS(tmp);
return len;
}
size_t ESP_Mail_Client::imapSend(IMAPSession *imap, const char *data, bool newline)
{
if (!reconnect(imap))
{
closeTCP(imap);
return 0;
}
if (!connected(imap))
{
errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST);
return 0;
}
if (!imap->_tcpConnected)
{
errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
return 0;
}
size_t len = 0;
if (newline)
{
if (imap->_debugLevel > esp_mail_debug_level_2)
esp_mail_debug(data);
if (!imap->_secure)
len = imap->httpClient._ns_println(data);
else
len = imap->httpClient.stream()->println(data);
}
else
{
if (imap->_debugLevel > esp_mail_debug_level_2)
esp_mail_debug_line(data, false);
if (!imap->_secure)
len = imap->httpClient._ns_print(data);
else
len = imap->httpClient.stream()->print(data);
}
if (len != strlen(data) && len != strlen(data) + 2)
{
errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
len = 0;
}
return len;
}
size_t ESP_Mail_Client::imapSend(IMAPSession *imap, int data, bool newline)
{
if (!reconnect(imap))
{
closeTCP(imap);
return 0;
}
if (!connected(imap))
{
errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST);
return 0;
}
if (!imap->_tcpConnected)
{
errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
return 0;
}
char *tmp = intStr(data);
size_t len = 0;
if (newline)
{
if (imap->_debugLevel > esp_mail_debug_level_2)
esp_mail_debug(tmp);
if (!imap->_secure)
len = imap->httpClient._ns_println(tmp);
else
len = imap->httpClient.stream()->println(tmp);
}
else
{
if (imap->_debugLevel > esp_mail_debug_level_2)
esp_mail_debug_line(tmp, false);
if (!imap->_secure)
len = imap->httpClient._ns_print(tmp);
else
len = imap->httpClient.stream()->print(tmp);
}
if (len != strlen(tmp) && len != strlen(tmp) + 2)
{
errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
len = 0;
}
delS(tmp);
return len;
}
bool ESP_Mail_Client::setFlag(IMAPSession *imap, int msgUID, const char *flag, bool closeSession)
{
return _setFlag(imap, msgUID, flag, 0, closeSession);
}
bool ESP_Mail_Client::addFlag(IMAPSession *imap, int msgUID, const char *flag, bool closeSession)
{
return _setFlag(imap, msgUID, flag, 1, closeSession);
}
bool ESP_Mail_Client::removeFlag(IMAPSession *imap, int msgUID, const char *flag, bool closeSession)
{
return _setFlag(imap, msgUID, flag, 2, closeSession);
}
bool ESP_Mail_Client::_setFlag(IMAPSession *imap, int msgUID, const char *flag, uint8_t action, bool closeSession)
{
if (!reconnect(imap))
return false;
if (!imap->_tcpConnected)
{
imap->_mailboxOpened = false;
return false;
}
if (imap->_currentFolder.length() == 0)
{
if (imap->_readCallback)
debugInfoP(esp_mail_str_153);
if (imap->_debug)
{
std::string e;
appendP(e, esp_mail_str_185, true);
appendP(e, esp_mail_str_151, false);
esp_mail_debug(e.c_str());
}
}
else
{
if (imap->_readOnlyMode || !imap->_mailboxOpened)
{
if (!imap->selectFolder(imap->_currentFolder.c_str(), false))
return false;
}
}
if (imap->_readCallback)
{
imapCB(imap, "", false);
if (action == 0)
debugInfoP(esp_mail_str_157);
else if (action == 1)
debugInfoP(esp_mail_str_155);
else
debugInfoP(esp_mail_str_154);
}
if (imap->_debug)
{
if (action == 0)
debugInfoP(esp_mail_str_253);
else if (action == 1)
debugInfoP(esp_mail_str_254);
else
debugInfoP(esp_mail_str_255);
}
std::string cmd;
appendP(cmd, esp_mail_str_249, true);
char *tmp = intStr(msgUID);
cmd += tmp;
delS(tmp);
if (action == 0)
appendP(cmd, esp_mail_str_250, false);
else if (action == 1)
appendP(cmd, esp_mail_str_251, false);
else
appendP(cmd, esp_mail_str_252, false);
cmd += flag;
appendP(cmd, esp_mail_str_192, false);
if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
imap->_imap_cmd = esp_mail_imap_cmd_store;
if (!handleIMAPResponse(imap, IMAP_STATUS_PARSE_FLAG_FAILED, false))
return false;
if (closeSession)
imap->closeSession();
return true;
}
void ESP_Mail_Client::createDirs(std::string dirs)
{
std::string dir = "";
int count = 0;
for (size_t i = 0; i < dirs.length(); i++)
{
dir.append(1, dirs[i]);
count++;
if (dirs[i] == '/')
{
if (dir.length() > 0)
ESP_MAIL_SD_FS.mkdir(dir.substr(0, dir.length() - 1).c_str());
count = 0;
}
}
if (count > 0)
ESP_MAIL_SD_FS.mkdir(dir.c_str());
std::string().swap(dir);
}
bool ESP_Mail_Client::sdTest()
{
#if defined(CARD_TYPE_SD)
if (_sdConfigSet)
sdBegin(_sck, _miso, _mosi, _ss);
else
sdBegin();
#endif
#if defined(ESP32)
#if defined(CARD_TYPE_SD_MMC)
if (_sdConfigSet)
sdMMCBegin(sd_mmc_mountpoint, sd_mmc_mode1bit, sd_mmc_format_if_mount_failed);
#endif
#endif
file = ESP_MAIL_SD_FS.open(esp_mail_str_204, FILE_WRITE);
if (!file)
return false;
if (!file.write(32))
return false;
file.close();
file = ESP_MAIL_SD_FS.open(esp_mail_str_204);
if (!file)
return false;
while (file.available())
{
if (file.read() != 32)
return false;
}
file.close();
ESP_MAIL_SD_FS.remove(esp_mail_str_204);
return true;
}
std::string ESP_Mail_Client::getEncodedToken(SMTPSession *smtp)
{
std::string raw;
appendP(raw, esp_mail_str_285, true);
raw += smtp->_sesson_cfg->login.email;
appendP(raw, esp_mail_str_286, false);
raw += smtp->_sesson_cfg->login.accessToken;
appendP(raw, esp_mail_str_287, false);
return encodeBase64Str((const unsigned char *)raw.c_str(), raw.length());
}
bool ESP_Mail_Client::smtpAuth(SMTPSession *smtp)
{
if (!reconnect(smtp))
return false;
bool ssl = false;
smtp->_secure = true;
bool secureMode = true;
std::string s;
#if defined(ESP32)
smtp->httpClient.setDebugCallback(NULL);
#elif defined(ESP8266)
smtp->httpClient.rxBufDivider = 16; // minimum rx buffer for smtp status response
smtp->httpClient.txBufDivider = 8; // medium tx buffer for faster attachment/inline data transfer
#endif
if (smtp->_sesson_cfg->server.port == esp_mail_smtp_port_25)
{
smtp->_secure = false;
secureMode = false;
}
else
{
if (smtp->_sesson_cfg->server.port == esp_mail_smtp_port_587)
smtp->_sesson_cfg->secure.startTLS = true;
secureMode = !smtp->_sesson_cfg->secure.startTLS;
//to prevent to send the connection upgrade command when some server promotes
//the starttls capability even the current connection was already secured.
if (smtp->_sesson_cfg->server.port == esp_mail_smtp_port_465)
ssl = true;
}
setSecure(smtp->httpClient, smtp->_sesson_cfg, smtp->_caCert);
//Server connection attempt: no status code
if (smtp->_sendCallback)
smtpCBP(smtp, esp_mail_str_120);
if (smtp->_debug)
{
appendP(s, esp_mail_str_314, true);
s += ESP_MAIL_VERSION;
esp_mail_debug(s.c_str());
debugInfoP(esp_mail_str_236);
appendP(s, esp_mail_str_261, true);
appendP(s, esp_mail_str_211, false);
s += smtp->_sesson_cfg->server.host_name;
esp_mail_debug(s.c_str());
char *tmp = intStr(smtp->_sesson_cfg->server.port);
appendP(s, esp_mail_str_261, true);
appendP(s, esp_mail_str_201, false);
s += tmp;
delS(tmp);
esp_mail_debug(s.c_str());
}
#if defined(ESP32)
if (smtp->_debug)
smtp->httpClient.setDebugCallback(esp_mail_debug);
#endif
smtp->httpClient.begin(smtp->_sesson_cfg->server.host_name, smtp->_sesson_cfg->server.port);
if (!smtp->httpClient.connect(secureMode))
return handleSMTPError(smtp, SMTP_STATUS_SERVER_CONNECT_FAILED);
//server connected
smtp->_tcpConnected = true;
if (smtp->_debug)
debugInfoP(esp_mail_str_238);
if (smtp->_sendCallback)
{
smtpCB(smtp, "");
smtpCBP(smtp, esp_mail_str_121);
}
#if defined(ESP32)
smtp->httpClient.stream()->setTimeout(ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC);
#elif defined(ESP8266)
smtp->httpClient.stream()->setTimeout(ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC * 1000);
#endif
smtp->httpClient.tcpTimeout = ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC * 1000;
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_initial_state;
//expected status code 220 for ready to service
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_220, SMTP_STATUS_SMTP_GREETING_GET_RESPONSE_FAILED))
return false;
init:
//Sending greeting hello response
if (smtp->_sendCallback)
{
smtpCB(smtp, "");
smtpCBP(smtp, esp_mail_str_122);
}
if (smtp->_debug)
debugInfoP(esp_mail_str_239);
appendP(s, esp_mail_str_6, true);
if (strlen(smtp->_sesson_cfg->login.user_domain) > 0)
s += smtp->_sesson_cfg->login.user_domain;
else
appendP(s, esp_mail_str_44, false);
if (smtpSendP(smtp, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_greeting;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, 0))
{
appendP(s, esp_mail_str_5, true);
if (strlen(smtp->_sesson_cfg->login.user_domain) > 0)
s += smtp->_sesson_cfg->login.user_domain;
else
appendP(s, esp_mail_str_44, false);
if (smtpSend(smtp, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED))
return false;
smtp->_send_capability.esmtp = false;
smtp->_auth_capability.login = true;
}
else
smtp->_send_capability.esmtp = true;
//start TLS when needed
if ((smtp->_auth_capability.start_tls || smtp->_sesson_cfg->secure.startTLS) && !ssl)
{
//send starttls command
if (smtp->_sendCallback)
{
smtpCB(smtp, "");
smtpCBP(smtp, esp_mail_str_209);
}
if (smtp->_debug)
{
appendP(s, esp_mail_str_196, true);
esp_mail_debug(s.c_str());
}
//expected status code 250 for complete the request
//some server returns 220 to restart to initial state
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_start_tls;
smtpSendP(smtp, esp_mail_str_311, false);
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED))
return false;
if (smtp->_debug)
{
debugInfoP(esp_mail_str_310);
}
//connect using secure mode
//do ssl handshaking
if (!smtp->httpClient._stream()->_ns_connect_ssl())
return handleSMTPError(smtp, MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP);
//set the secure mode
smtp->_sesson_cfg->secure.startTLS = false;
ssl = true;
smtp->_secure = true;
//return to initial state if the response status is 220.
if (smtp->_smtpStatus.respCode == esp_mail_smtp_status_code_220)
goto init;
}
bool creds = strlen(smtp->_sesson_cfg->login.email) > 0 && strlen(smtp->_sesson_cfg->login.password) > 0;
bool xoauth_auth = strlen(smtp->_sesson_cfg->login.accessToken) > 0 && smtp->_auth_capability.xoauth2;
bool login_auth = smtp->_auth_capability.login && creds;
bool plain_auth = smtp->_auth_capability.plain && creds;
if (xoauth_auth || login_auth || plain_auth)
{
if (smtp->_sendCallback)
{
smtpCB(smtp, "", false);
smtpCBP(smtp, esp_mail_str_56, false);
}
//log in
if (xoauth_auth)
{
if (smtp->_debug)
debugInfoP(esp_mail_str_288);
if (!smtp->_auth_capability.xoauth2)
return handleSMTPError(smtp, SMTP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED, false);
if (smtpSendP(smtp, esp_mail_str_289, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
if (smtpSend(smtp, getEncodedToken(smtp).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_auth;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_235, SMTP_STATUS_AUTHEN_FAILED))
return false;
return true;
}
else if (plain_auth)
{
if (smtp->_debug)
debugInfoP(esp_mail_str_241);
if (smtp->_debug)
{
appendP(s, esp_mail_str_261, true);
s += smtp->_sesson_cfg->login.email;
esp_mail_debug(s.c_str());
appendP(s, esp_mail_str_131, false);
for (size_t i = 0; i < strlen(smtp->_sesson_cfg->login.password); i++)
appendP(s, esp_mail_str_183, false);
esp_mail_debug(s.c_str());
}
//rfc4616
const char *usr = smtp->_sesson_cfg->login.email;
const char *psw = smtp->_sesson_cfg->login.password;
int len = strlen(usr) + strlen(psw) + 2;
uint8_t *tmp = new uint8_t[len];
memset(tmp, 0, len);
int p = 1;
memcpy(tmp + p, usr, strlen(usr));
p += strlen(usr) + 1;
memcpy(tmp + p, psw, strlen(psw));
p += strlen(psw);
std::string s;
appendP(s, esp_mail_str_45, true);
appendP(s, esp_mail_str_131, false);
s += encodeBase64Str(tmp, p);
delete[] tmp;
if (smtpSend(smtp, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_auth_plain;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_235, SMTP_STATUS_USER_LOGIN_FAILED))
return false;
return true;
}
else if (login_auth)
{
if (smtp->_debug)
debugInfoP(esp_mail_str_240);
if (smtpSendP(smtp, esp_mail_str_4, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_334, SMTP_STATUS_AUTHEN_FAILED))
return false;
if (smtp->_debug)
{
appendP(s, esp_mail_str_261, true);
s += smtp->_sesson_cfg->login.email;
esp_mail_debug(s.c_str());
}
if (smtpSend(smtp, encodeBase64Str((const unsigned char *)smtp->_sesson_cfg->login.email, strlen(smtp->_sesson_cfg->login.email)).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_login_user;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_334, SMTP_STATUS_USER_LOGIN_FAILED))
return false;
if (smtp->_debug)
{
appendP(s, esp_mail_str_261, true);
for (size_t i = 0; i < strlen(smtp->_sesson_cfg->login.password); i++)
appendP(s, esp_mail_str_183, false);
esp_mail_debug(s.c_str());
}
if (smtpSend(smtp, encodeBase64Str((const unsigned char *)smtp->_sesson_cfg->login.password, strlen(smtp->_sesson_cfg->login.password)).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_login_psw;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_235, SMTP_STATUS_PASSWORD_LOGIN_FAILED))
return false;
return true;
}
}
return true;
}
void ESP_Mail_Client::mimeFromFile(const char *name, std::string &mime)
{
std::string ext = name;
size_t p = ext.find_last_of(".");
if (p != std::string::npos)
{
ext = ext.substr(p, ext.length() - p);
if (ext.length() > 0)
getMIME(ext.c_str(), mime);
}
}
bool ESP_Mail_Client::connected(SMTPSession *smtp)
{
if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure)
{
if (!smtp->httpClient._stream())
return false;
return smtp->httpClient._stream()->_ns_connected();
}
else
{
if (!smtp->httpClient.stream())
return false;
return smtp->httpClient.stream()->connected();
}
}
bool ESP_Mail_Client::setSendingResult(SMTPSession *smtp, SMTP_Message *msg, bool result)
{
if (result)
smtp->_sentSuccessCount++;
else
smtp->_sentFailedCount++;
if (smtp->_sendCallback)
{
struct esp_mail_smtp_send_status_t status;
status.completed = result;
status.timesstamp = time(nullptr);
status.subject = msg->subject;
status.recipients = msg->_rcp[0].email;
smtp->sendingResult.add(status);
smtp->_cbData._sentSuccess = smtp->_sentSuccessCount;
smtp->_cbData._sentFailed = smtp->_sentFailedCount;
}
return result;
}
bool ESP_Mail_Client::sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession)
{
if (strlen(msg->html.content) > 0 || msg->html.blob.size > 0 || strlen(msg->html.file.name) > 0)
msg->type |= esp_mail_msg_type_html;
if (strlen(msg->text.content) > 0 || msg->text.blob.size > 0 || strlen(msg->text.file.name) > 0)
msg->type |= esp_mail_msg_type_plain;
for (size_t i = 0; i < msg->_rfc822.size(); i++)
{
if (strlen(msg->_rfc822[i].html.content) > 0)
msg->_rfc822[i].type |= esp_mail_msg_type_html;
if (strlen(msg->_rfc822[i].text.content) > 0)
msg->_rfc822[i].type |= esp_mail_msg_type_plain;
}
return _sendMail(smtp, msg, closeSession);
}
void ESP_Mail_Client::getMIME(const char *ext, std::string &mime)
{
mime = "";
for (int i = 0; i < esp_mail_file_extension_maxType; i++)
{
if (strcmp_P(ext, mimeinfo[i].endsWith) == 0)
{
char *tmp = strP(mimeinfo[i].mimeType);
mime = tmp;
delS(tmp);
break;
}
}
}
size_t ESP_Mail_Client::numAtt(SMTPSession *smtp, esp_mail_attach_type type, SMTP_Message *msg)
{
size_t count = 0;
for (size_t i = 0; i < msg->_att.size(); i++)
{
if (msg->_att[i]._int.att_type == type)
count++;
}
return count;
}
bool ESP_Mail_Client::validEmail(const char *s)
{
std::string str(s);
auto at = std::find(str.begin(), str.end(), '@');
auto dot = std::find(at, str.end(), '.');
return (at != str.end()) && (dot != str.end());
}
bool ESP_Mail_Client::checkEmail(SMTPSession *smtp, SMTP_Message *msg)
{
bool validRecipient = false;
if (!validEmail(msg->sender.email))
{
errorStatusCB(smtp, SMTP_STATUS_NO_VALID_SENDER_EXISTED);
return setSendingResult(smtp, msg, false);
}
for (uint8_t i = 0; i < msg->_rcp.size(); i++)
{
if (validEmail(msg->_rcp[i].email))
validRecipient = true;
}
if (!validRecipient)
{
errorStatusCB(smtp, SMTP_STATUS_NO_VALID_RECIPIENTS_EXISTED);
return setSendingResult(smtp, msg, false);
}
return true;
}
bool ESP_Mail_Client::_sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession)
{
smtp->_smtpStatus.statusCode = 0;
smtp->_smtpStatus.respCode = 0;
smtp->_smtpStatus.text.clear();
bool rfc822MSG = false;
if (!checkEmail(smtp, msg))
return false;
smtp->_chunkedEnable = false;
smtp->_chunkCount = 0;
//new session
if (!smtp->_tcpConnected)
{
if (!smtpAuth(smtp))
{
closeTCP(smtp);
return setSendingResult(smtp, msg, false);
}
smtp->_sentSuccessCount = 0;
smtp->_sentFailedCount = 0;
smtp->sendingResult.clear();
}
else
{
//reuse session
if (smtp->_sendCallback)
{
smtpCB(smtp, "");
if (smtp->_sentSuccessCount || smtp->_sentFailedCount)
smtpCBP(smtp, esp_mail_str_267);
else
smtpCBP(smtp, esp_mail_str_208);
}
if (smtp->_debug)
{
if (smtp->_sentSuccessCount || smtp->_sentFailedCount)
debugInfoP(esp_mail_str_268);
else
debugInfoP(esp_mail_str_207);
}
}
if (smtp->_sendCallback)
{
smtpCB(smtp, "");
smtpCBP(smtp, esp_mail_str_125);
}
if (smtp->_debug)
debugInfoP(esp_mail_str_242);
std::string buf;
std::string buf2;
checkBinaryData(smtp, msg);
if (msg->priority >= esp_mail_smtp_priority_high && msg->priority <= esp_mail_smtp_priority_low)
{
char *tmp = intStr(msg->priority);
appendP(buf2, esp_mail_str_17, true);
buf2 += tmp;
delS(tmp);
appendP(buf2, esp_mail_str_34, false);
if (msg->priority == esp_mail_smtp_priority_high)
{
appendP(buf2, esp_mail_str_18, false);
appendP(buf2, esp_mail_str_21, false);
}
else if (msg->priority == esp_mail_smtp_priority_normal)
{
appendP(buf2, esp_mail_str_19, false);
appendP(buf2, esp_mail_str_22, false);
}
else if (msg->priority == esp_mail_smtp_priority_low)
{
appendP(buf2, esp_mail_str_20, false);
appendP(buf2, esp_mail_str_23, false);
}
}
appendP(buf2, esp_mail_str_10, false);
if (strlen(msg->sender.name) > 0)
buf2 += msg->sender.name;
appendP(buf2, esp_mail_str_14, false);
buf2 += msg->sender.email;
appendP(buf2, esp_mail_str_15, false);
appendP(buf2, esp_mail_str_34, false);
appendP(buf, esp_mail_str_8, true);
appendP(buf, esp_mail_str_14, false);
buf += msg->sender.email;
appendP(buf, esp_mail_str_15, false);
if (smtp->_send_capability.binaryMIME && smtp->_send_capability.chunking && msg->enable.chunking && (msg->text._int.binary || msg->html._int.binary))
appendP(buf, esp_mail_str_104, false);
if (smtpSend(smtp, buf.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_header_sender;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_SENDER_FAILED))
return setSendingResult(smtp, msg, false);
for (uint8_t i = 0; i < msg->_rcp.size(); i++)
{
if (i == 0)
{
appendP(buf2, esp_mail_str_11, false);
if (strlen(msg->_rcp[i].name) > 0)
buf2 += msg->_rcp[i].name;
appendP(buf2, esp_mail_str_14, false);
buf2 += msg->_rcp[i].email;
appendP(buf2, esp_mail_str_15, false);
}
else
{
if (strlen(msg->_rcp[i].name) > 0)
{
appendP(buf2, esp_mail_str_263, false);
buf2 += msg->_rcp[i].name;
appendP(buf2, esp_mail_str_14, false);
}
else
appendP(buf2, esp_mail_str_13, false);
buf2 += msg->_rcp[i].email;
appendP(buf2, esp_mail_str_15, false);
}
if (i == msg->_rcp.size() - 1)
appendP(buf2, esp_mail_str_34, false);
buf.clear();
//only address
appendP(buf, esp_mail_str_9, false);
appendP(buf, esp_mail_str_14, false);
buf += msg->_rcp[i].email;
appendP(buf, esp_mail_str_15, false);
//rfc3461, rfc3464
if (smtp->_send_capability.dsn)
{
if (msg->response.notify != esp_mail_smtp_notify::esp_mail_smtp_notify_never)
{
appendP(buf, esp_mail_str_262, false);
int opcnt = 0;
if (msg->response.notify && esp_mail_smtp_notify::esp_mail_smtp_notify_success)
{
if (opcnt > 0)
appendP(buf, esp_mail_str_263, false);
appendP(buf, esp_mail_str_264, false);
opcnt++;
}
if (msg->response.notify && esp_mail_smtp_notify::esp_mail_smtp_notify_failure)
{
if (opcnt > 0)
appendP(buf, esp_mail_str_263, false);
appendP(buf, esp_mail_str_265, false);
opcnt++;
}
if (msg->response.notify && esp_mail_smtp_notify::esp_mail_smtp_notify_delay)
{
if (opcnt > 0)
appendP(buf, esp_mail_str_263, false);
appendP(buf, esp_mail_str_266, false);
opcnt++;
}
}
}
if (smtpSend(smtp, buf.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_header_recipient;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED))
return setSendingResult(smtp, msg, false);
}
for (uint8_t i = 0; i < msg->_cc.size(); i++)
{
if (i == 0)
{
appendP(buf2, esp_mail_str_12, false);
appendP(buf2, esp_mail_str_14, false);
buf2 += msg->_cc[i].email;
appendP(buf2, esp_mail_str_15, false);
}
else
{
appendP(buf2, esp_mail_str_13, false);
buf2 += msg->_cc[i].email;
appendP(buf2, esp_mail_str_15, false);
}
if (i == msg->_cc.size() - 1)
appendP(buf2, esp_mail_str_34, false);
buf.clear();
appendP(buf, esp_mail_str_9, false);
appendP(buf, esp_mail_str_14, false);
buf += msg->_cc[i].email;
appendP(buf, esp_mail_str_15, false);
if (smtpSend(smtp, buf.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_header_recipient;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED))
return setSendingResult(smtp, msg, false);
}
for (uint8_t i = 0; i < msg->_bcc.size(); i++)
{
appendP(buf, esp_mail_str_9, true);
appendP(buf, esp_mail_str_14, false);
buf += msg->_bcc[i].email;
appendP(buf, esp_mail_str_15, false);
if (smtpSend(smtp, buf.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_header_recipient;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED))
return setSendingResult(smtp, msg, false);
}
if (smtp->_sendCallback)
{
smtpCB(smtp, "");
smtpCBP(smtp, esp_mail_str_126);
}
if (smtp->_debug)
debugInfoP(esp_mail_str_243);
if (smtp->_send_capability.chunking && msg->enable.chunking)
{
smtp->_chunkedEnable = true;
if (!bdat(smtp, msg, buf2.length(), false))
return false;
}
else
{
if (smtpSendP(smtp, esp_mail_str_16, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_body;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_354, SMTP_STATUS_SEND_BODY_FAILED))
return setSendingResult(smtp, msg, false);
}
if (smtpSend(smtp, buf2.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
std::string s;
appendP(s, esp_mail_str_24, true);
s += msg->subject;
appendP(s, esp_mail_str_34, false);
if (msg->_hdr.size() > 0)
{
for (uint8_t k = 0; k < msg->_hdr.size(); k++)
{
s += msg->_hdr[k];
appendP(s, esp_mail_str_34, false);
}
}
if (strlen(msg->response.reply_to) > 0)
{
appendP(s, esp_mail_str_184, false);
appendP(s, esp_mail_str_14, false);
s += msg->response.reply_to;
appendP(s, esp_mail_str_15, false);
appendP(s, esp_mail_str_34, false);
}
if (strlen(msg->response.return_path) > 0)
{
appendP(s, esp_mail_str_46, false);
appendP(s, esp_mail_str_14, false);
s += msg->response.return_path;
appendP(s, esp_mail_str_15, false);
appendP(s, esp_mail_str_34, false);
}
appendP(s, esp_mail_str_3, false);
if (!bdat(smtp, msg, s.length(), false))
return false;
if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
return sendMSGData(smtp, msg, closeSession, rfc822MSG);
}
bool ESP_Mail_Client::sendMSGData(SMTPSession *smtp, SMTP_Message *msg, bool closeSession, bool rfc822MSG)
{
std::string s;
std::string mixed = getBoundary(15);
std::string alt = getBoundary(15);
if (numAtt(smtp, esp_mail_att_type_attachment, msg) == 0 && msg->_parallel.size() == 0 && msg->_rfc822.size() == 0)
{
if (msg->type == (esp_mail_msg_type_plain | esp_mail_msg_type_html | esp_mail_msg_type_enriched) || numAtt(smtp, esp_mail_att_type_inline, msg) > 0)
{
if (!sendMSG(smtp, msg, alt))
return setSendingResult(smtp, msg, false);
}
else if (msg->type != esp_mail_msg_type_none)
{
if (!sendPartText(smtp, msg, msg->type, ""))
return setSendingResult(smtp, msg, false);
}
}
else
{
appendP(s, esp_mail_str_1, true);
s += mixed;
appendP(s, esp_mail_str_35, false);
appendP(s, esp_mail_str_33, false);
s += mixed;
appendP(s, esp_mail_str_34, false);
if (!bdat(smtp, msg, s.length(), false))
return false;
if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
if (!sendMSG(smtp, msg, alt))
return setSendingResult(smtp, msg, false);
if (!bdat(smtp, msg, 2, false))
return false;
if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
if (smtp->_sendCallback)
{
smtpCB(smtp, "");
smtpCBP(smtp, esp_mail_str_127);
}
if (smtp->_debug)
debugInfoP(esp_mail_str_244);
if (smtp->_sendCallback && numAtt(smtp, esp_mail_att_type_attachment, msg) > 0)
esp_mail_debug("");
if (!sendAttachments(smtp, msg, mixed))
return setSendingResult(smtp, msg, false);
if (!sendParallelAttachments(smtp, msg, mixed))
return setSendingResult(smtp, msg, false);
if (!sendRFC822Msg(smtp, msg, mixed, closeSession, msg->_rfc822.size() > 0))
return setSendingResult(smtp, msg, false);
appendP(s, esp_mail_str_33, true);
s += mixed;
appendP(s, esp_mail_str_33, false);
if (!bdat(smtp, msg, s.length(), false))
return false;
if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
}
if (!rfc822MSG)
{
if (smtp->_sendCallback)
{
smtpCB(smtp, "");
smtpCBP(smtp, esp_mail_str_303);
}
if (smtp->_debug)
debugInfoP(esp_mail_str_304);
if (smtp->_chunkedEnable)
{
if (!bdat(smtp, msg, 0, true))
return false;
smtp->_smtp_cmd = esp_mail_smtp_cmd_chunk_termination;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_BODY_FAILED))
return false;
}
else
{
if (smtpSendP(smtp, esp_mail_str_37, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_body;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_BODY_FAILED))
return setSendingResult(smtp, msg, false);
}
setSendingResult(smtp, msg, true);
if (closeSession)
if (!smtp->closeSession())
return false;
}
return true;
}
bool ESP_Mail_Client::sendRFC822Msg(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary, bool closeSession, bool rfc822MSG)
{
if (msg->_rfc822.size() == 0)
return true;
std::string buf;
for (uint8_t i = 0; i < msg->_rfc822.size(); i++)
{
buf.clear();
getRFC822PartHeader(smtp, buf, boundary);
getRFC822MsgEnvelope(smtp, &msg->_rfc822[i], buf);
if (!bdat(smtp, msg, buf.length(), false))
return false;
if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
if (!sendMSGData(smtp, &msg->_rfc822[i], closeSession, rfc822MSG))
return false;
}
return true;
}
void ESP_Mail_Client::getRFC822MsgEnvelope(SMTPSession *smtp, SMTP_Message *msg, std::string &buf)
{
if (strlen(msg->date) > 0)
{
appendP(buf, esp_mail_str_99, false);
buf += msg->date;
appendP(buf, esp_mail_str_34, false);
}
if (strlen(msg->from.email) > 0)
{
appendP(buf, esp_mail_str_10, false);
if (strlen(msg->from.name) > 0)
buf += msg->from.name;
appendP(buf, esp_mail_str_14, false);
buf += msg->from.email;
appendP(buf, esp_mail_str_15, false);
appendP(buf, esp_mail_str_34, false);
}
if (strlen(msg->sender.email) > 0)
{
appendP(buf, esp_mail_str_150, false);
if (strlen(msg->sender.name) > 0)
buf += msg->sender.name;
appendP(buf, esp_mail_str_14, false);
buf += msg->sender.email;
appendP(buf, esp_mail_str_15, false);
appendP(buf, esp_mail_str_34, false);
}
if (strlen(msg->response.reply_to) > 0)
{
appendP(buf, esp_mail_str_184, false);
appendP(buf, esp_mail_str_14, false);
buf += msg->response.reply_to;
appendP(buf, esp_mail_str_15, false);
appendP(buf, esp_mail_str_34, false);
}
if (strlen(msg->response.return_path) > 0)
{
appendP(buf, esp_mail_str_46, false);
appendP(buf, esp_mail_str_14, false);
buf += msg->response.return_path;
appendP(buf, esp_mail_str_15, false);
appendP(buf, esp_mail_str_34, false);
}
for (uint8_t i = 0; i < msg->_rcp.size(); i++)
{
if (i == 0)
{
appendP(buf, esp_mail_str_11, false);
if (strlen(msg->_rcp[i].name) > 0)
buf += msg->_rcp[i].name;
appendP(buf, esp_mail_str_14, false);
buf += msg->_rcp[i].email;
appendP(buf, esp_mail_str_15, false);
}
else
{
if (strlen(msg->_rcp[i].name) > 0)
{
appendP(buf, esp_mail_str_263, false);
buf += msg->_rcp[i].name;
appendP(buf, esp_mail_str_14, false);
}
else
appendP(buf, esp_mail_str_13, false);
buf += msg->_rcp[i].email;
appendP(buf, esp_mail_str_15, false);
}
if (i == msg->_rcp.size() - 1)
appendP(buf, esp_mail_str_34, false);
}
for (uint8_t i = 0; i < msg->_cc.size(); i++)
{
if (i == 0)
{
appendP(buf, esp_mail_str_12, false);
appendP(buf, esp_mail_str_14, false);
buf += msg->_cc[i].email;
appendP(buf, esp_mail_str_15, false);
}
else
{
appendP(buf, esp_mail_str_13, false);
buf += msg->_cc[i].email;
appendP(buf, esp_mail_str_15, false);
}
if (i == msg->_cc.size() - 1)
appendP(buf, esp_mail_str_34, false);
}
for (uint8_t i = 0; i < msg->_bcc.size(); i++)
{
if (i == 0)
{
appendP(buf, esp_mail_str_149, false);
appendP(buf, esp_mail_str_14, false);
buf += msg->_bcc[i].email;
appendP(buf, esp_mail_str_15, false);
}
else
{
appendP(buf, esp_mail_str_13, false);
buf += msg->_bcc[i].email;
appendP(buf, esp_mail_str_15, false);
}
if (i == msg->_bcc.size() - 1)
appendP(buf, esp_mail_str_34, false);
}
if (strlen(msg->subject) > 0)
{
appendP(buf, esp_mail_str_279, false);
buf += msg->subject;
appendP(buf, esp_mail_str_34, false);
}
if (strlen(msg->keyword) > 0)
{
appendP(buf, esp_mail_str_145, false);
buf += msg->keyword;
appendP(buf, esp_mail_str_34, false);
}
if (strlen(msg->comment) > 0)
{
appendP(buf, esp_mail_str_134, false);
buf += msg->comment;
appendP(buf, esp_mail_str_34, false);
}
if (strlen(msg->messageID) > 0)
{
appendP(buf, esp_mail_str_274, false);
appendP(buf, esp_mail_str_14, false);
buf += msg->messageID;
appendP(buf, esp_mail_str_15, false);
appendP(buf, esp_mail_str_34, false);
}
}
bool ESP_Mail_Client::bdat(SMTPSession *smtp, SMTP_Message *msg, int len, bool last)
{
if (!smtp->_chunkedEnable || !msg->enable.chunking)
return true;
smtp->_chunkCount++;
std::string bdat;
appendP(bdat, esp_mail_str_106, true);
char *tmp = intStr(len);
bdat += tmp;
if (last)
appendP(bdat, esp_mail_str_173, false);
delS(tmp);
if (smtpSend(smtp, bdat.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
if (!smtp->_send_capability.pipelining)
{
smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_body;
if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_BODY_FAILED))
return setSendingResult(smtp, msg, false);
smtp->_chunkCount = 0;
}
return true;
}
void ESP_Mail_Client::checkBinaryData(SMTPSession *smtp, SMTP_Message *msg)
{
if (msg->type & esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched || msg->type & esp_mail_msg_type_html)
{
if ((msg->type & esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched) > 0)
{
if (strlen(msg->text.transfer_encoding) > 0)
{
if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_binary) == 0)
{
msg->text._int.binary = true;
}
}
}
if ((msg->type & esp_mail_msg_type_html) > 0)
{
if (strlen(msg->html.transfer_encoding) > 0)
{
if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_binary) == 0)
{
msg->html._int.binary = true;
}
}
}
}
for (size_t i = 0; i < msg->_att.size(); i++)
{
if (strcmpP(msg->_att[i].descr.transfer_encoding, 0, esp_mail_str_166))
{
msg->_att[i]._int.binary = true;
}
}
}
bool ESP_Mail_Client::sendBlob(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att)
{
if (strcmp(att->descr.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0 && strcmp(att->descr.transfer_encoding, att->descr.content_encoding) != 0)
{
if (!sendBase64(smtp, msg, (const unsigned char *)att->blob.data, att->blob.size, att->_int.flash_blob, att->descr.filename, smtp->_sendCallback != NULL))
return false;
return true;
}
else
{
if (att->blob.size > 0)
{
size_t chunkSize = ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE;
size_t writeLen = 0;
uint8_t *buf = new uint8_t[chunkSize];
int pg = 0, _pg = 0;
while (writeLen < att->blob.size)
{
if (writeLen > att->blob.size - chunkSize)
chunkSize = att->blob.size - writeLen;
if (!bdat(smtp, msg, chunkSize, false))
break;
memcpy_P(buf, att->blob.data, chunkSize);
if (smtpSend(smtp, buf, chunkSize) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
break;
if (smtp->_sendCallback)
{
pg = (float)(100.0f * writeLen / att->blob.size);
if (pg != _pg)
uploadReport(att->descr.filename, pg);
_pg = pg;
}
writeLen += chunkSize;
}
delete[] buf;
if (smtp->_sendCallback && _pg < 100)
uploadReport(att->descr.filename, 100);
return writeLen >= att->blob.size;
}
}
return false;
}
bool ESP_Mail_Client::sendFile(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, File &file)
{
if (strcmp(att->descr.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0 && strcmp(att->descr.transfer_encoding, att->descr.content_encoding) != 0)
{
if (!sendBase64Stream(smtp, msg, file, att->descr.filename, smtp->_sendCallback != NULL))
return false;
return true;
}
else
{
if (file.size() > 0)
{
size_t chunkSize = ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE;
size_t writeLen = 0;
if (file.size() < chunkSize)
chunkSize = file.size();
uint8_t *buf = new uint8_t[chunkSize];
int pg = 0, _pg = 0;
while (writeLen < file.size() && file.available())
{
if (writeLen > file.size() - chunkSize)
chunkSize = file.size() - writeLen;
size_t readLen = file.read(buf, chunkSize);
if (readLen != chunkSize)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR);
break;
}
if (!bdat(smtp, msg, chunkSize, false))
break;
if (smtpSend(smtp, buf, chunkSize) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
break;
if (smtp->_sendCallback)
{
pg = (float)(100.0f * writeLen / file.size());
if (pg != _pg)
uploadReport(att->descr.filename, pg);
_pg = pg;
}
writeLen += chunkSize;
}
delete[] buf;
if (smtp->_sendCallback && _pg < 100)
uploadReport(att->descr.filename, 100);
return writeLen == file.size();
}
return false;
}
return false;
}
bool ESP_Mail_Client::sendParallelAttachments(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary)
{
if (msg->_parallel.size() == 0)
return true;
std::string buf;
std::string parallel = getBoundary(15);
appendP(buf, esp_mail_str_33, true);
buf += boundary;
appendP(buf, esp_mail_str_34, false);
appendP(buf, esp_mail_str_28, false);
buf += parallel;
appendP(buf, esp_mail_str_35, false);
if (!bdat(smtp, msg, buf.length(), false))
return false;
if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
if (!sendAttachments(smtp, msg, parallel, true))
return setSendingResult(smtp, msg, false);
appendP(buf, esp_mail_str_33, true);
buf += parallel;
appendP(buf, esp_mail_str_33, false);
if (!bdat(smtp, msg, buf.length(), false))
return false;
if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return setSendingResult(smtp, msg, false);
return true;
}
bool ESP_Mail_Client::sendAttachments(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary, bool parallel)
{
std::string s;
std::string buf;
int cnt = 0;
SMTP_Attachment *att = nullptr;
size_t sz = msg->_att.size();
if (parallel)
sz = msg->_parallel.size();
for (size_t i = 0; i < sz; i++)
{
if (parallel)
att = &msg->_parallel[i];
else
att = &msg->_att[i];
if (att->_int.att_type == esp_mail_att_type_attachment)
{
appendP(s, esp_mail_str_261, true);
s += att->descr.filename;
if (smtp->_sendCallback)
{
if (cnt > 0)
smtpCB(smtp, "");
smtpCB(smtp, att->descr.filename);
}
if (smtp->_debug)
esp_mail_debug(s.c_str());
cnt++;
if (att->file.storage_type == esp_mail_file_storage_type_none)
{
if (!att->blob.data)
continue;
if (smtp->_sendCallback)
smtpCB(smtp, att->descr.filename);
if (smtp->_debug)
esp_mail_debug(s.c_str());
buf.clear();
getAttachHeader(buf, boundary, att, att->blob.size);
if (!bdat(smtp, msg, buf.length(), false))
return false;
if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
if (!sendBlob(smtp, msg, att))
return false;
if (!bdat(smtp, msg, 2, false))
return false;
if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
}
else
{
if (!_sdOk && att->file.storage_type == esp_mail_file_storage_type_sd)
_sdOk = sdTest();
if (!_flashOk && att->file.storage_type == esp_mail_file_storage_type_flash)
#if defined(ESP32)
_flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH);
#elif defined(ESP8266)
_flashOk = ESP_MAIL_FLASH_FS.begin();
#endif
if ((!_sdOk && att->file.storage_type == esp_mail_file_storage_type_sd) || (!_flashOk && att->file.storage_type == esp_mail_file_storage_type_flash))
{
if (smtp->_sendCallback)
debugInfoP(esp_mail_str_158);
if (smtp->_debug)
{
std::string e;
appendP(e, esp_mail_str_185, true);
appendP(e, esp_mail_str_158, false);
esp_mail_debug(e.c_str());
}
continue;
}
if (openFileRead(smtp, msg, att, file, s, buf, boundary, false))
{
if (file)
{
if (!sendFile(smtp, msg, att, file))
return false;
if (!bdat(smtp, msg, 2, false))
return false;
if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
}
}
}
}
}
return true;
}
bool ESP_Mail_Client::openFileRead(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, File &file, std::string &s, std::string &buf, const std::string &boundary, bool inlined)
{
bool file_existed = false;
std::string filepath;
if (strlen(att->file.path) > 0)
{
if (att->file.path[0] != '/')
appendP(filepath, esp_mail_str_202, true);
filepath += att->file.path;
}
if (att->file.storage_type == esp_mail_file_storage_type_sd)
file_existed = ESP_MAIL_SD_FS.exists(filepath.c_str());
else if (att->file.storage_type == esp_mail_file_storage_type_flash)
file_existed = ESP_MAIL_FLASH_FS.exists(filepath.c_str());
if (!file_existed)
{
if (strlen(att->descr.filename) > 0)
{
filepath.clear();
if (att->descr.filename[0] != '/')
appendP(filepath, esp_mail_str_202, true);
filepath += att->descr.filename;
}
if (att->file.storage_type == esp_mail_file_storage_type_sd)
file_existed = ESP_MAIL_SD_FS.exists(filepath.c_str());
else if (att->file.storage_type == esp_mail_file_storage_type_flash)
file_existed = ESP_MAIL_FLASH_FS.exists(filepath.c_str());
}
if (!file_existed)
{
if (smtp->_sendCallback)
debugInfoP(esp_mail_str_158);
if (smtp->_debug)
{
std::string e;
appendP(e, esp_mail_str_185, true);
appendP(e, esp_mail_str_158, false);
esp_mail_debug(e.c_str());
}
}
if (file_existed)
{
buf.clear();
if (att->file.storage_type == esp_mail_file_storage_type_sd)
file = ESP_MAIL_SD_FS.open(filepath.c_str(), FILE_READ);
else if (att->file.storage_type == esp_mail_file_storage_type_flash)
#if defined(ESP32)
file = ESP_MAIL_FLASH_FS.open(filepath.c_str(), FILE_READ);
#elif defined(ESP8266)
file = ESP_MAIL_FLASH_FS.open(filepath.c_str(), "r");
#endif
if (!file)
return false;
if (inlined)
getInlineHeader(buf, boundary, att, file.size());
else
getAttachHeader(buf, boundary, att, file.size());
if (!bdat(smtp, msg, buf.length(), false))
return false;
if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
return true;
}
return false;
}
bool ESP_Mail_Client::openFileRead2(SMTPSession *smtp, SMTP_Message *msg, File &file, const char *path, esp_mail_file_storage_type storageType)
{
bool file_existed = false;
std::string filepath;
if (strlen(path) > 0)
{
if (path[0] != '/')
appendP(filepath, esp_mail_str_202, true);
filepath += path;
}
if (storageType == esp_mail_file_storage_type_sd)
file_existed = ESP_MAIL_SD_FS.exists(filepath.c_str());
else if (storageType == esp_mail_file_storage_type_flash)
file_existed = ESP_MAIL_FLASH_FS.exists(filepath.c_str());
if (!file_existed)
{
if (smtp->_sendCallback)
debugInfoP(esp_mail_str_158);
if (smtp->_debug)
{
std::string e;
appendP(e, esp_mail_str_185, true);
appendP(e, esp_mail_str_158, false);
esp_mail_debug(e.c_str());
}
}
if (file_existed)
{
if (storageType == esp_mail_file_storage_type_sd)
file = ESP_MAIL_SD_FS.open(filepath.c_str(), FILE_READ);
else if (storageType == esp_mail_file_storage_type_flash)
#if defined(ESP32)
file = ESP_MAIL_FLASH_FS.open(filepath.c_str(), FILE_READ);
#elif defined(ESP8266)
file = ESP_MAIL_FLASH_FS.open(filepath.c_str(), "r");
#endif
return true;
}
return false;
}
bool ESP_Mail_Client::sendInline(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary, byte type)
{
size_t num = numAtt(smtp, esp_mail_att_type_inline, msg) > 0;
if (num > 0)
{
if (smtp->_sendCallback)
{
smtpCB(smtp, "");
smtpCBP(smtp, esp_mail_str_167);
}
if (smtp->_debug)
debugInfoP(esp_mail_str_271);
}
std::string s;
std::string buf;
std::string related = getBoundary(15);
int cnt = 0;
SMTP_Attachment *att = nullptr;
appendP(s, esp_mail_str_33, true);
s += boundary;
appendP(s, esp_mail_str_34, false);
appendP(s, esp_mail_str_298, false);
s += related;
appendP(s, esp_mail_str_35, false);
if (!bdat(smtp, msg, s.length(), false))
return false;
if (smtpSend(smtp, s.c_str()) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
if (!sendPartText(smtp, msg, type, related.c_str()))
return false;
if (smtp->_sendCallback && numAtt(smtp, esp_mail_att_type_inline, msg) > 0)
esp_mail_debug("");
if (num > 0)
{
for (uint8_t i = 0; i < msg->_att.size(); i++)
{
att = &msg->_att[i];
if (att->_int.att_type == esp_mail_att_type_inline)
{
appendP(s, esp_mail_str_261, true);
s += att->descr.filename;
if (smtp->_sendCallback)
{
if (cnt > 0)
smtpCB(smtp, "");
smtpCB(smtp, att->descr.filename);
}
if (smtp->_debug)
esp_mail_debug(s.c_str());
cnt++;
if (att->file.storage_type == esp_mail_file_storage_type_none)
{
if (!att->blob.data)
continue;
if (smtp->_sendCallback)
smtpCB(smtp, att->descr.filename);
if (smtp->_debug)
esp_mail_debug(s.c_str());
buf.clear();
getInlineHeader(buf, related, att, att->blob.size);
if (!bdat(smtp, msg, buf.length(), false))
return false;
if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
if (!sendBlob(smtp, msg, att))
return false;
if (!bdat(smtp, msg, 2, false))
return false;
if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
}
else
{
if (!_sdOk && att->file.storage_type == esp_mail_file_storage_type_sd)
_sdOk = sdTest();
if (!_flashOk && att->file.storage_type == esp_mail_file_storage_type_flash)
#if defined(ESP32)
_flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH);
#elif defined(ESP8266)
_flashOk = ESP_MAIL_FLASH_FS.begin();
#endif
if ((!_sdOk && att->file.storage_type == esp_mail_file_storage_type_sd) || (!_flashOk && att->file.storage_type == esp_mail_file_storage_type_flash))
{
if (smtp->_sendCallback)
debugInfoP(esp_mail_str_158);
if (smtp->_debug)
{
std::string e;
appendP(e, esp_mail_str_185, true);
appendP(e, esp_mail_str_158, false);
esp_mail_debug(e.c_str());
}
continue;
}
if (openFileRead(smtp, msg, att, file, s, buf, related, true))
{
if (!file)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR);
return false;
}
if (!sendFile(smtp, msg, att, file))
return false;
if (!bdat(smtp, msg, 2, false))
return false;
if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
}
}
}
}
}
appendP(s, esp_mail_str_34, true);
appendP(s, esp_mail_str_33, false);
s += related;
appendP(s, esp_mail_str_33, false);
appendP(s, esp_mail_str_34, false);
if (!bdat(smtp, msg, s.length(), false))
return false;
if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
return true;
}
void ESP_Mail_Client::errorStatusCB(SMTPSession *smtp, int error)
{
smtp->_smtpStatus.statusCode = error;
std::string s;
if (smtp->_sendCallback)
{
appendP(s, esp_mail_str_53, true);
s += smtp->errorReason().c_str();
smtpCB(smtp, s.c_str(), false);
}
if (smtp->_debug)
{
appendP(s, esp_mail_str_185, true);
s += smtp->errorReason().c_str();
esp_mail_debug(s.c_str());
}
}
size_t ESP_Mail_Client::smtpSendP(SMTPSession *smtp, PGM_P v, bool newline)
{
if (!reconnect(smtp))
{
closeTCP(smtp);
return 0;
}
if (!connected(smtp))
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST);
return 0;
}
if (!smtp->_tcpConnected)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
return 0;
}
char *tmp = strP(v);
size_t len = 0;
if (newline)
{
if (smtp->_debugLevel > esp_mail_debug_level_2)
esp_mail_debug(tmp);
if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure)
len = smtp->httpClient._ns_println(tmp);
else
len = smtp->httpClient.stream()->println(tmp);
}
else
{
if (smtp->_debugLevel > esp_mail_debug_level_2)
esp_mail_debug_line(tmp, false);
if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure)
len = smtp->httpClient._ns_print(tmp);
else
len = smtp->httpClient.stream()->print(tmp);
}
if (len != strlen(tmp) && len != strlen(tmp) + 2)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
len = 0;
}
delS(tmp);
return len;
}
size_t ESP_Mail_Client::smtpSend(SMTPSession *smtp, const char *data, bool newline)
{
if (!reconnect(smtp))
{
closeTCP(smtp);
return 0;
}
if (!connected(smtp))
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST);
return 0;
}
if (!smtp->_tcpConnected)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
return 0;
}
size_t len = 0;
if (newline)
{
if (smtp->_debugLevel > esp_mail_debug_level_2)
esp_mail_debug(data);
if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure)
len = smtp->httpClient._ns_println(data);
else
len = smtp->httpClient.stream()->println(data);
}
else
{
if (smtp->_debugLevel > esp_mail_debug_level_2)
esp_mail_debug_line(data, false);
if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure)
len = smtp->httpClient._ns_print(data);
else
len = smtp->httpClient.stream()->print(data);
}
if (len != strlen(data) && len != strlen(data) + 2)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
len = 0;
}
return len;
}
size_t ESP_Mail_Client::smtpSend(SMTPSession *smtp, int data, bool newline)
{
if (!reconnect(smtp))
{
closeTCP(smtp);
return 0;
}
if (!connected(smtp))
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST);
return 0;
}
if (!smtp->_tcpConnected)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
return 0;
}
char *tmp = intStr(data);
size_t len = 0;
if (newline)
{
if (smtp->_debugLevel > esp_mail_debug_level_2)
esp_mail_debug(tmp);
if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure)
len = smtp->httpClient._ns_println(tmp);
else
len = smtp->httpClient.stream()->println(tmp);
}
else
{
if (smtp->_debugLevel > esp_mail_debug_level_2)
esp_mail_debug_line(tmp, false);
if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure)
len = smtp->httpClient._ns_print(tmp);
else
len = smtp->httpClient.stream()->print(tmp);
}
if (len != strlen(tmp) && len != strlen(tmp) + 2)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
len = 0;
}
delS(tmp);
return len;
}
size_t ESP_Mail_Client::smtpSend(SMTPSession *smtp, uint8_t *data, size_t size)
{
if (!reconnect(smtp))
{
closeTCP(smtp);
return 0;
}
if (!connected(smtp))
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST);
return 0;
}
if (!smtp->_tcpConnected)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
return 0;
}
size_t len = 0;
if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure)
len = smtp->httpClient._stream()->write(data, size);
else
len = smtp->httpClient.stream()->write(data, size);
if (len != size)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED);
len = 0;
}
return len;
}
bool ESP_Mail_Client::handleSMTPError(SMTPSession *smtp, int err, bool ret)
{
if (err < 0)
errorStatusCB(smtp, err);
if (smtp->_tcpConnected)
closeTCP(smtp);
return ret;
}
void ESP_Mail_Client::debugInfoP(PGM_P info)
{
char *tmp = strP(info);
esp_mail_debug(tmp);
delS(tmp);
}
bool ESP_Mail_Client::sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss)
{
_sck = sck;
_miso = miso;
_mosi = mosi;
_ss = ss;
_sdConfigSet = true;
#if defined(ESP32)
#if defined(CARD_TYPE_SD)
SPI.begin(_sck, _miso, _mosi, _ss);
return ESP_MAIL_SD_FS.begin(_ss, SPI);
#endif
#elif defined(ESP8266)
return ESP_MAIL_SD_FS.begin(_ss);
#endif
return false;
}
bool ESP_Mail_Client::sdBegin(void)
{
_sdConfigSet = false;
#if defined(ESP32)
return ESP_MAIL_SD_FS.begin();
#elif defined(ESP8266)
return ESP_MAIL_SD_FS.begin(SD_CS_PIN);
#endif
return false;
}
bool ESP_Mail_Client::sdMMCBegin(const char *mountpoint, bool mode1bit, bool format_if_mount_failed)
{
#if defined(ESP32)
#if defined(CARD_TYPE_SD_MMC)
_sdConfigSet = true;
sd_mmc_mountpoint = mountpoint;
sd_mmc_mode1bit = mode1bit;
sd_mmc_format_if_mount_failed = format_if_mount_failed;
return ESP_MAIL_SD_FS.begin(mountpoint, mode1bit, format_if_mount_failed);
#endif
#endif
return false;
}
bool ESP_Mail_Client::sendPartText(SMTPSession *smtp, SMTP_Message *msg, uint8_t type, const char *boundary)
{
std::string header;
if (strlen(boundary) > 0)
{
appendP(header, esp_mail_str_33, false);
header += boundary;
appendP(header, esp_mail_str_34, false);
}
if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched)
{
if (strlen(msg->text.content_type) > 0)
{
appendP(header, esp_mail_str_25, false);
header += msg->text.content_type;
if (strlen(msg->text.charSet) > 0)
{
appendP(header, esp_mail_str_97, false);
appendP(header, esp_mail_str_131, false);
appendP(header, esp_mail_str_168, false);
header += msg->text.charSet;
appendP(header, esp_mail_str_136, false);
}
if (msg->text.flowed)
{
appendP(header, esp_mail_str_97, false);
appendP(header, esp_mail_str_131, false);
appendP(header, esp_mail_str_270, false);
appendP(header, esp_mail_str_97, false);
appendP(header, esp_mail_str_131, false);
appendP(header, esp_mail_str_110, false);
}
if (msg->text.embed.enable)
{
appendP(header, esp_mail_str_26, false);
appendP(header, esp_mail_str_164, false);
appendP(header, esp_mail_str_136, false);
char *tmp = getUID();
msg->text._int.cid = tmp;
delS(tmp);
}
appendP(header, esp_mail_str_34, false);
}
if (strlen(msg->text.transfer_encoding) > 0)
{
appendP(header, esp_mail_str_272, false);
header += msg->text.transfer_encoding;
appendP(header, esp_mail_str_34, false);
}
}
else if (type == esp_mail_msg_type_html)
{
if (strlen(msg->text.content_type) > 0)
{
appendP(header, esp_mail_str_25, false);
header += msg->html.content_type;
if (strlen(msg->html.charSet) > 0)
{
appendP(header, esp_mail_str_97, false);
appendP(header, esp_mail_str_131, false);
appendP(header, esp_mail_str_168, false);
header += msg->html.charSet;
appendP(header, esp_mail_str_136, false);
}
if (msg->html.embed.enable)
{
appendP(header, esp_mail_str_26, false);
appendP(header, esp_mail_str_159, false);
appendP(header, esp_mail_str_136, false);
char *tmp = getUID();
msg->html._int.cid = tmp;
delS(tmp);
}
appendP(header, esp_mail_str_34, false);
}
if (strlen(msg->html.transfer_encoding) > 0)
{
appendP(header, esp_mail_str_272, false);
header += msg->html.transfer_encoding;
appendP(header, esp_mail_str_34, false);
}
}
if ((type == esp_mail_msg_type_html && msg->html.embed.enable) || ((type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) && msg->text.embed.enable))
{
if ((type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) && msg->text.embed.enable)
{
if (msg->text.embed.type == esp_mail_smtp_embed_message_type_attachment)
appendP(header, esp_mail_str_30, false);
else if (msg->text.embed.type == esp_mail_smtp_embed_message_type_inline)
appendP(header, esp_mail_str_299, false);
if (strlen(msg->text.embed.filename) > 0)
header += msg->text.embed.filename;
else
appendP(header, esp_mail_str_164, false);
appendP(header, esp_mail_str_36, false);
if (msg->text.embed.type == esp_mail_smtp_embed_message_type_inline)
{
appendP(header, esp_mail_str_300, false);
if (strlen(msg->text.embed.filename) > 0)
header += msg->text.embed.filename;
else
appendP(header, esp_mail_str_159, false);
appendP(header, esp_mail_str_34, false);
appendP(header, esp_mail_str_301, false);
header += msg->text._int.cid;
appendP(header, esp_mail_str_15, false);
appendP(header, esp_mail_str_34, false);
}
}
else if (type == esp_mail_msg_type_html && msg->html.embed.enable)
{
if (msg->html.embed.type == esp_mail_smtp_embed_message_type_attachment)
appendP(header, esp_mail_str_30, false);
else if (msg->html.embed.type == esp_mail_smtp_embed_message_type_inline)
appendP(header, esp_mail_str_299, false);
if (strlen(msg->html.embed.filename) > 0)
header += msg->html.embed.filename;
else
appendP(header, esp_mail_str_159, false);
appendP(header, esp_mail_str_36, false);
if (msg->html.embed.type == esp_mail_smtp_embed_message_type_inline)
{
appendP(header, esp_mail_str_300, false);
if (strlen(msg->html.embed.filename) > 0)
header += msg->html.embed.filename;
else
appendP(header, esp_mail_str_159, false);
appendP(header, esp_mail_str_34, false);
appendP(header, esp_mail_str_301, false);
header += msg->html._int.cid;
appendP(header, esp_mail_str_15, false);
appendP(header, esp_mail_str_34, false);
}
}
}
appendP(header, esp_mail_str_34, false);
if ((msg->text.blob.size > 0 && (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched)) || (msg->html.blob.size > 0 && type == esp_mail_msg_type_html))
{
if (!bdat(smtp, msg, header.length(), false))
return false;
if (smtpSend(smtp, header.c_str()) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
header.clear();
if (!sendBlobBody(smtp, msg, type))
return false;
}
else if ((strlen(msg->text.file.name) > 0 && (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched)) || (strlen(msg->html.file.name) > 0 && type == esp_mail_msg_type_html))
{
if (!bdat(smtp, msg, header.length(), false))
return false;
if (smtpSend(smtp, header.c_str()) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
header.clear();
if (!sendFileBody(smtp, msg, type))
return false;
}
else
encodingText(smtp, msg, type, header);
appendP(header, esp_mail_str_34, false);
if (strlen(boundary) > 0)
appendP(header, esp_mail_str_34, false);
if (!bdat(smtp, msg, header.length(), false))
return false;
if (smtpSend(smtp, header.c_str()) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
return true;
}
char *ESP_Mail_Client::getUID()
{
char *tmp = new char[36];
memset(tmp, 0, 36);
itoa(random(10000000, 20000000), tmp, 10);
return tmp;
}
bool ESP_Mail_Client::sendBlobBody(SMTPSession *smtp, SMTP_Message *msg, uint8_t type)
{
if (msg->text.blob.size == 0 && msg->html.blob.size == 0)
return true;
bool ret = true;
int bufLen = 512;
size_t pos = 0;
int pg = 0, _pg = 0;
if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched)
{
char *tmp = strP(esp_mail_str_325);
if (strlen(msg->text.transfer_encoding) > 0)
{
if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0)
{
ret = sendBase64(smtp, msg, (const unsigned char *)msg->text.blob.data, msg->text.blob.size, true, tmp, smtp->_sendCallback != NULL);
delS(tmp);
return ret;
}
}
int len = msg->text.blob.size;
int available = len;
uint8_t *buf = new uint8_t[bufLen + 1];
while (available)
{
if (available > bufLen)
available = bufLen;
memcpy_P(buf, msg->text.blob.data + pos, available);
if (!bdat(smtp, msg, available, false))
break;
if (smtpSend(smtp, buf, available) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
break;
pos += available;
len -= available;
available = len;
if (smtp->_sendCallback)
{
pg = (float)(100.0f * pos / msg->text.blob.size);
if (pg != _pg)
uploadReport(tmp, pg);
_pg = pg;
}
}
delete[] buf;
delS(tmp);
}
else if (type == esp_mail_message_type::esp_mail_msg_type_html)
{
char *tmp = strP(esp_mail_str_325);
if (strlen(msg->html.transfer_encoding) > 0)
{
if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0)
{
ret = sendBase64(smtp, msg, (const unsigned char *)msg->html.blob.data, msg->html.blob.size, true, tmp, smtp->_sendCallback != NULL);
delS(tmp);
return ret;
}
}
int len = msg->html.blob.size;
int available = len;
uint8_t *buf = new uint8_t[bufLen + 1];
while (available)
{
if (available > bufLen)
available = bufLen;
memcpy_P(buf, msg->html.blob.data + pos, available);
if (!bdat(smtp, msg, available, false))
{
ret = false;
break;
}
if (smtpSend(smtp, buf, available) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
{
ret = false;
break;
}
pos += available;
len -= available;
available = len;
if (smtp->_sendCallback)
{
pg = (float)(100.0f * pos / msg->html.blob.size);
if (pg != _pg)
uploadReport(tmp, pg);
_pg = pg;
}
}
delete[] buf;
delS(tmp);
}
return ret;
}
bool ESP_Mail_Client::sendFileBody(SMTPSession *smtp, SMTP_Message *msg, uint8_t type)
{
if (strlen(msg->text.file.name) == 0 && strlen(msg->html.file.name) == 0)
return true;
bool ret = true;
size_t chunkSize = ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE;
size_t writeLen = 0;
int pg = 0, _pg = 0;
if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched)
{
if (!openFileRead2(smtp, msg, file, msg->text.file.name, msg->text.file.type))
return false;
char *tmp = strP(esp_mail_str_326);
if (strlen(msg->text.transfer_encoding) > 0)
{
if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0)
{
ret = sendBase64Stream(smtp, msg, file, tmp, smtp->_sendCallback != NULL);
delS(tmp);
return ret;
}
}
if (file.size() > 0)
{
if (file.size() < chunkSize)
chunkSize = file.size();
uint8_t *buf = new uint8_t[chunkSize];
while (writeLen < file.size() && file.available())
{
if (writeLen > file.size() - chunkSize)
chunkSize = file.size() - writeLen;
size_t readLen = file.read(buf, chunkSize);
if (readLen != chunkSize)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR);
break;
}
if (!bdat(smtp, msg, chunkSize, false))
{
ret = false;
break;
}
if (smtpSend(smtp, buf, chunkSize) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
{
ret = false;
break;
}
if (smtp->_sendCallback)
{
pg = (float)(100.0f * writeLen / file.size());
if (pg != _pg)
uploadReport(tmp, pg);
_pg = pg;
}
writeLen += chunkSize;
}
delete[] buf;
if (smtp->_sendCallback && _pg < 100)
uploadReport(tmp, 100);
delS(tmp);
return ret && writeLen == file.size();
}
}
else if (type == esp_mail_message_type::esp_mail_msg_type_html)
{
if (!openFileRead2(smtp, msg, file, msg->html.file.name, msg->html.file.type))
return false;
char *tmp = strP(esp_mail_str_326);
if (strlen(msg->html.transfer_encoding) > 0)
{
if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0)
{
ret = sendBase64Stream(smtp, msg, file, tmp, smtp->_sendCallback != NULL);
delS(tmp);
return ret;
}
}
if (file.size() > 0)
{
if (file.size() < chunkSize)
chunkSize = file.size();
uint8_t *buf = new uint8_t[chunkSize];
while (writeLen < file.size() && file.available())
{
if (writeLen > file.size() - chunkSize)
chunkSize = file.size() - writeLen;
size_t readLen = file.read(buf, chunkSize);
if (readLen != chunkSize)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR);
break;
}
if (!bdat(smtp, msg, chunkSize, false))
{
ret = false;
break;
}
if (smtpSend(smtp, buf, chunkSize) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
{
ret = false;
break;
}
if (smtp->_sendCallback)
{
pg = (float)(100.0f * writeLen / file.size());
if (pg != _pg)
uploadReport(tmp, pg);
_pg = pg;
}
writeLen += chunkSize;
}
delete[] buf;
if (smtp->_sendCallback && _pg < 100)
uploadReport(tmp, 100);
delS(tmp);
return ret && writeLen == file.size();
}
}
return false;
}
void ESP_Mail_Client::encodingText(SMTPSession *smtp, SMTP_Message *msg, uint8_t type, std::string &content)
{
if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched)
{
std::string s = msg->text.content;
if (msg->text.flowed)
formatFlowedText(s);
if (strlen(msg->text.transfer_encoding) > 0)
{
if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0)
content += encodeBase64Str((const unsigned char *)s.c_str(), s.length());
else if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_qp) == 0)
{
char *out = newS(s.length() * 3 + 1);
encodeQP(s.c_str(), out);
content += out;
delS(out);
}
else
content += s;
}
else
content += s;
}
else if (type == esp_mail_message_type::esp_mail_msg_type_html)
{
char *tmp = nullptr;
std::string s = msg->html.content;
std::string fnd, rep;
SMTP_Attachment *att = nullptr;
for (uint8_t i = 0; i < msg->_att.size(); i++)
{
att = &msg->_att[i];
if (att->_int.att_type == esp_mail_att_type_inline)
{
std::string filename(att->descr.filename);
size_t found = filename.find_last_of("/\\");
if (found != std::string::npos)
filename = filename.substr(found + 1);
appendP(fnd, esp_mail_str_136, true);
fnd += filename;
appendP(fnd, esp_mail_str_136, false);
appendP(rep, esp_mail_str_136, true);
appendP(rep, esp_mail_str_302, false);
if (strlen(att->descr.content_id) > 0)
rep += att->descr.content_id;
else
rep += att->_int.cid;
appendP(rep, esp_mail_str_136, false);
tmp = strReplace((char *)s.c_str(), (char *)fnd.c_str(), (char *)rep.c_str());
s = tmp;
delS(tmp);
}
}
if (strlen(msg->html.transfer_encoding) > 0)
{
if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0)
content += encodeBase64Str((const unsigned char *)s.c_str(), s.length());
else if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_qp) == 0)
{
char *out = newS(strlen(msg->html.content) * 3 + 1);
encodeQP(msg->html.content, out);
content += out;
delS(out);
}
else
content += s;
}
else
content += s;
std::string().swap(s);
}
}
/* Safe string splitter to avoid strsep bugs*/
void ESP_Mail_Client::splitTk(std::string &str, std::vector<std::string> &tk, const char *delim)
{
std::size_t current, previous = 0;
current = str.find(delim, previous);
std::string s;
while (current != std::string::npos)
{
s = str.substr(previous, current - previous);
tk.push_back(s);
previous = current + strlen(delim);
current = str.find(delim, previous);
}
s = str.substr(previous, current - previous);
tk.push_back(s);
std::string().swap(s);
}
/** Add the soft line break to the long text line (rfc 3676)
* and add Format=flowed parameter in the plain text content-type header.
* We use the existing white space as a part of this soft line break
* and set delSp="no" parameter to the header.
*
* Some servers are not rfc 3676 compliant.
* This causes the text lines are wrapped instead of joined.
*
* Some mail clients trim the space before the line break
* which makes the soft line break cannot be seen.
*/
void ESP_Mail_Client::formatFlowedText(std::string &content)
{
int count = 0;
std::string qms;
int j = 0;
std::vector<std::string> tokens = std::vector<std::string>();
char *stk = strP(esp_mail_str_34);
char *qm = strP(esp_mail_str_15);
splitTk(content, tokens, stk);
content.clear();
for (size_t i = 0; i < tokens.size(); i++)
{
if (tokens[i].length() > 0)
{
j = 0;
qms.clear();
while (tokens[i][j] == qm[0])
{
qms += qm;
j++;
}
softBreak(tokens[i], qms.c_str());
if (count > 0)
content += stk;
content += tokens[i];
}
else if (count > 0)
content += stk;
count++;
}
delS(stk);
delS(qm);
tokens.clear();
}
void ESP_Mail_Client::softBreak(std::string &content, const char *quoteMarks)
{
size_t len = 0;
char *stk = strP(esp_mail_str_131);
std::vector<std::string> tokens = std::vector<std::string>();
splitTk(content, tokens, stk);
content.clear();
for (size_t i = 0; i < tokens.size(); i++)
{
if (tokens[i].length() > 0)
{
if (len + tokens[i].length() + 3 > FLOWED_TEXT_LEN)
{
/* insert soft crlf */
content += stk;
appendP(content, esp_mail_str_34, false);
/* insert quote marks */
if (strlen(quoteMarks) > 0)
content += quoteMarks;
content += tokens[i];
len = tokens[i].length();
}
else
{
if (len > 0)
{
content += stk;
len += strlen(stk);
}
content += tokens[i];
len += tokens[i].length();
}
}
}
delS(stk);
tokens.clear();
}
bool ESP_Mail_Client::sendMSG(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary)
{
std::string alt = getBoundary(15);
std::string s;
if (numAtt(smtp, esp_mail_att_type_inline, msg) > 0)
{
appendP(s, esp_mail_str_297, true);
s += alt;
appendP(s, esp_mail_str_35, false);
if (!bdat(smtp, msg, s.length(), false))
return false;
if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
if (msg->type == esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched || msg->type == esp_mail_msg_type_html)
{
if (!sendInline(smtp, msg, alt, msg->type))
return false;
}
else if (msg->type == (esp_mail_msg_type_html | esp_mail_msg_type_enriched | esp_mail_msg_type_plain))
{
if (!sendPartText(smtp, msg, esp_mail_msg_type_plain, alt.c_str()))
return false;
if (!sendInline(smtp, msg, alt, esp_mail_msg_type_html))
return false;
}
appendP(s, esp_mail_str_33, true);
s += alt;
appendP(s, esp_mail_str_33, false);
appendP(s, esp_mail_str_34, false);
if (!bdat(smtp, msg, s.length(), false))
return false;
if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
}
else
{
if (msg->type == esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched || msg->type == esp_mail_msg_type_html)
{
if (!sendPartText(smtp, msg, msg->type, ""))
return false;
}
else if (msg->type == (esp_mail_msg_type_html | esp_mail_msg_type_enriched | esp_mail_msg_type_plain))
{
appendP(s, esp_mail_str_33, true);
s += boundary;
appendP(s, esp_mail_str_34, false);
appendP(s, esp_mail_str_297, false);
s += alt;
appendP(s, esp_mail_str_35, false);
if (!bdat(smtp, msg, s.length(), false))
return false;
if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
if (!sendPartText(smtp, msg, esp_mail_msg_type_plain, alt.c_str()))
return false;
if (!sendPartText(smtp, msg, esp_mail_msg_type_html, alt.c_str()))
return false;
}
}
return true;
}
void ESP_Mail_Client::getInlineHeader(std::string &header, const std::string &boundary, SMTP_Attachment *inlineAttach, size_t size)
{
appendP(header, esp_mail_str_33, false);
header += boundary;
appendP(header, esp_mail_str_34, false);
appendP(header, esp_mail_str_25, false);
if (strlen(inlineAttach->descr.mime) == 0)
{
std::string mime;
mimeFromFile(inlineAttach->descr.filename, mime);
if (mime.length() > 0)
header += mime;
else
appendP(header, esp_mail_str_32, false);
}
else
header += inlineAttach->descr.mime;
appendP(header, esp_mail_str_26, false);
std::string filename = inlineAttach->descr.filename;
size_t found = filename.find_last_of("/\\");
if (found != std::string::npos)
filename = filename.substr(found + 1);
header += filename;
appendP(header, esp_mail_str_36, false);
appendP(header, esp_mail_str_299, false);
header += filename;
appendP(header, esp_mail_str_327, false);
char *tmp = intStr(size);
header += tmp;
delS(tmp);
appendP(header, esp_mail_str_34, false);
appendP(header, esp_mail_str_300, false);
header += filename;
appendP(header, esp_mail_str_34, false);
appendP(header, esp_mail_str_301, false);
if (strlen(inlineAttach->descr.content_id) > 0)
header += inlineAttach->descr.content_id;
else
header += inlineAttach->_int.cid;
appendP(header, esp_mail_str_15, false);
appendP(header, esp_mail_str_34, false);
if (strlen(inlineAttach->descr.transfer_encoding) > 0)
{
appendP(header, esp_mail_str_272, false);
header += inlineAttach->descr.transfer_encoding;
appendP(header, esp_mail_str_34, false);
}
appendP(header, esp_mail_str_34, false);
std::string().swap(filename);
}
void ESP_Mail_Client::getAttachHeader(std::string &header, const std::string &boundary, SMTP_Attachment *attach, size_t size)
{
appendP(header, esp_mail_str_33, false);
header += boundary;
appendP(header, esp_mail_str_34, false);
appendP(header, esp_mail_str_25, false);
if (strlen(attach->descr.mime) == 0)
{
std::string mime;
mimeFromFile(attach->descr.filename, mime);
if (mime.length() > 0)
header += mime;
else
appendP(header, esp_mail_str_32, false);
}
else
header += attach->descr.mime;
appendP(header, esp_mail_str_26, false);
std::string filename = attach->descr.filename;
size_t found = filename.find_last_of("/\\");
if (found != std::string::npos)
filename = filename.substr(found + 1);
header += filename;
appendP(header, esp_mail_str_36, false);
if (!attach->_int.parallel)
{
appendP(header, esp_mail_str_30, false);
header += filename;
appendP(header, esp_mail_str_327, false);
char *tmp = intStr(size);
header += tmp;
delS(tmp);
appendP(header, esp_mail_str_34, false);
}
if (strlen(attach->descr.transfer_encoding) > 0)
{
appendP(header, esp_mail_str_272, false);
header += attach->descr.transfer_encoding;
appendP(header, esp_mail_str_34, false);
}
appendP(header, esp_mail_str_34, false);
std::string().swap(filename);
}
void ESP_Mail_Client::getRFC822PartHeader(SMTPSession *smtp, std::string &header, const std::string &boundary)
{
appendP(header, esp_mail_str_33, false);
header += boundary;
appendP(header, esp_mail_str_34, false);
appendP(header, esp_mail_str_25, false);
appendP(header, esp_mail_str_123, false);
appendP(header, esp_mail_str_34, false);
appendP(header, esp_mail_str_98, false);
appendP(header, esp_mail_str_34, false);
}
void ESP_Mail_Client::smtpCBP(SMTPSession *smtp, PGM_P info, bool success)
{
std::string s;
appendP(s, info, true);
smtp->_cbData._info = s;
smtp->_cbData._success = success;
smtp->_sendCallback(smtp->_cbData);
std::string().swap(s);
}
void ESP_Mail_Client::smtpCB(SMTPSession *smtp, const char *info, bool success)
{
smtp->_cbData._info = info;
smtp->_cbData._success = success;
smtp->_sendCallback(smtp->_cbData);
}
void ESP_Mail_Client::imapCBP(IMAPSession *imap, PGM_P info, bool success)
{
char *tmp = strP(info);
imap->_cbData._info = tmp;
imap->_cbData._success = success;
imap->_readCallback(imap->_cbData);
delS(tmp);
}
void ESP_Mail_Client::imapCB(IMAPSession *imap, const char *info, bool success)
{
imap->_cbData._info = info;
imap->_cbData._success = success;
imap->_readCallback(imap->_cbData);
}
void ESP_Mail_Client::strcat_c(char *str, char c)
{
for (; *str; str++)
;
*str++ = c;
*str++ = 0;
}
int ESP_Mail_Client::strpos(const char *haystack, const char *needle, int offset)
{
size_t len = strlen(haystack);
size_t len2 = strlen(needle);
if (len == 0 || len < len2 || len2 == 0 || offset >= (int)len || offset < 0)
return -1;
char *_haystack = newS(len - offset + 1);
_haystack[len - offset] = 0;
strncpy(_haystack, haystack + offset, len - offset);
char *p = stristr(_haystack, needle);
int r = -1;
if (p)
r = p - _haystack + offset;
delS(_haystack);
return r;
}
char *ESP_Mail_Client::stristr(const char *str1, const char *str2)
{
const char *p1 = str1;
const char *p2 = str2;
const char *r = *p2 == 0 ? str1 : 0;
while (*p1 != 0 && *p2 != 0)
{
if (tolower((unsigned char)*p1) == tolower((unsigned char)*p2))
{
if (r == 0)
r = p1;
p2++;
}
else
{
p2 = str2;
if (r != 0)
p1 = r + 1;
if (tolower((unsigned char)*p1) == tolower((unsigned char)*p2))
{
r = p1;
p2++;
}
else
r = 0;
}
p1++;
}
return *p2 == 0 ? (char *)r : 0;
}
char *ESP_Mail_Client::rstrstr(const char *haystack, const char *needle)
{
size_t needle_length = strlen(needle);
const char *haystack_end = haystack + strlen(haystack) - needle_length;
const char *p;
size_t i;
for (p = haystack_end; p >= haystack; --p)
{
for (i = 0; i < needle_length; ++i)
{
if (p[i] != needle[i])
goto next;
}
return (char *)p;
next:;
}
return 0;
}
int ESP_Mail_Client::rstrpos(const char *haystack, const char *needle, int offset)
{
size_t len = strlen(haystack);
size_t len2 = strlen(needle);
if (len == 0 || len < len2 || len2 == 0 || offset >= (int)len)
return -1;
char *_haystack = newS(len - offset + 1);
_haystack[len - offset] = 0;
strncpy(_haystack, haystack + offset, len - offset);
char *p = rstrstr(_haystack, needle);
int r = -1;
if (p)
r = p - _haystack + offset;
delS(_haystack);
return r;
}
int ESP_Mail_Client::readLine(WiFiClient *stream, char *buf, int bufLen, bool crlf, int &count)
{
int ret = -1;
char c = 0;
char _c = 0;
int idx = 0;
if (!stream)
return idx;
while (stream->available() && idx < bufLen)
{
ret = stream->read();
if (ret > -1)
{
if (idx >= bufLen - 1)
return idx;
c = (char)ret;
strcat_c(buf, c);
idx++;
count++;
if (_c == '\r' && c == '\n')
{
if (!crlf)
{
buf[idx - 2] = 0;
idx -= 2;
}
return idx;
}
_c = c;
}
if (!stream)
return idx;
}
return idx;
}
#if defined(ESP32)
int ESP_Mail_Client::_readLine(ESP_Mail_WCS32 *stream, char *buf, int bufLen, bool crlf, int &count)
#elif defined(ESP8266)
int ESP_Mail_Client::_readLine(ESP_Mail::ESP_Mail_WCS *stream, char *buf, int bufLen, bool crlf, int &count)
#endif
{
int ret = -1;
char c = 0;
char _c = 0;
int idx = 0;
if (!stream)
return idx;
while (stream->_ns_available() && idx < bufLen)
{
ret = stream->_ns_read();
if (ret > -1)
{
if (idx >= bufLen - 1)
return idx;
c = (char)ret;
strcat_c(buf, c);
idx++;
count++;
if (_c == '\r' && c == '\n')
{
if (!crlf)
{
buf[idx - 2] = 0;
idx -= 2;
}
return idx;
}
_c = c;
}
if (!stream)
return idx;
}
return idx;
}
int ESP_Mail_Client::getMSGNUM(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, bool &endSearch, int &nump, const char *key, const char *pc)
{
int ret = -1;
char c = 0;
int idx = 0;
int num = 0;
while (available(imap) > 0 && idx < bufLen)
{
delay(0);
if (!imap->_secure)
ret = imap->httpClient._stream()->read();
else
ret = imap->httpClient.stream()->read();
if (ret > -1)
{
if (idx >= bufLen - 1)
return idx;
c = (char)ret;
if (c == '\n')
c = ' ';
strcat_c(buf, c);
idx++;
if (chunkIdx == 0)
{
if (strcmp(buf, key) == 0)
{
chunkIdx++;
return 0;
}
if (strposP(buf, esp_mail_imap_response_1, 0) > -1)
goto end_search;
}
else
{
if (c == ' ')
{
imap->_mbif._searchCount++;
if (imap->_config->enable.recent_sort)
{
imap->_msgNum.push_back(atoi(buf));
if (imap->_msgNum.size() > imap->_config->limit.search)
imap->_msgNum.erase(imap->_msgNum.begin());
}
else
{
if (imap->_msgNum.size() < imap->_config->limit.search)
imap->_msgNum.push_back(atoi(buf));
}
if (imap->_debug)
{
num = (float)(100.0f * imap->_mbif._searchCount / imap->_mbif._msgCount);
if (nump != num)
{
nump = num;
searchReport(num, pc);
}
}
chunkIdx++;
return idx;
}
else if (c == '$')
{
if (imap->_config->enable.recent_sort)
std::sort(imap->_msgNum.begin(), imap->_msgNum.end(), compFunc);
goto end_search;
}
}
}
}
return idx;
end_search:
endSearch = true;
int read = available(imap);
if (!imap->_secure)
idx = imap->httpClient._stream()->readBytes(buf + idx, read);
else
idx = imap->httpClient.stream()->readBytes(buf + idx, read);
return idx;
}
struct esp_mail_message_part_info_t *ESP_Mail_Client::cPart(IMAPSession *imap)
{
return &cHeader(imap)->part_headers[imap->_cPartIdx];
}
struct esp_mail_message_header_t *ESP_Mail_Client::cHeader(IMAPSession *imap)
{
return &imap->_headers[cIdx(imap)];
}
void ESP_Mail_Client::handleHeader(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, struct esp_mail_message_header_t &header, int &headerState, int &octetCount)
{
char *tmp = nullptr;
if (chunkIdx == 0)
{
if (strposP(buf, esp_mail_str_324, 0) != -1 && buf[0] == '*')
chunkIdx++;
tmp = subStr(buf, esp_mail_str_193, esp_mail_str_194, 0);
if (tmp)
{
octetCount = 2;
header.header_data_len = atoi(tmp);
delS(tmp);
}
}
else
{
if (octetCount > header.header_data_len + 2)
return;
if (strcmpP(buf, 0, esp_mail_str_10))
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_from;
tmp = subStr(buf, esp_mail_str_10, NULL, 0, -1);
setHeader(imap, tmp, header, headerState);
delS(tmp);
}
else if (strcmpP(buf, 0, esp_mail_str_11))
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_to;
tmp = subStr(buf, esp_mail_str_11, NULL, 0, -1);
setHeader(imap, tmp, header, headerState);
delS(tmp);
}
else if (strcmpP(buf, 0, esp_mail_str_276))
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_cc;
tmp = subStr(buf, esp_mail_str_276, NULL, 0, -1);
setHeader(imap, tmp, header, headerState);
delS(tmp);
}
else if (strcmpP(buf, 0, esp_mail_str_279))
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_subject;
tmp = subStr(buf, esp_mail_str_279, NULL, 0, -1);
setHeader(imap, tmp, header, headerState);
delS(tmp);
}
else if (strcmpP(buf, 0, esp_mail_str_25))
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_content_type;
tmp = subStr(buf, esp_mail_str_25, esp_mail_str_97, 0);
if (tmp)
{
setHeader(imap, buf, header, headerState);
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_172))
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_content_transfer_encoding;
tmp = subStr(buf, esp_mail_str_172, NULL, 0, -1);
if (tmp)
{
setHeader(imap, tmp, header, headerState);
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_190))
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_accept_language;
tmp = subStr(buf, esp_mail_str_190, NULL, 0, -1);
if (tmp)
{
setHeader(imap, tmp, header, headerState);
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_191))
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_content_language;
tmp = subStr(buf, esp_mail_str_191, NULL, 0, -1);
if (tmp)
{
setHeader(imap, tmp, header, headerState);
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_273))
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_date;
tmp = subStr(buf, esp_mail_str_273, NULL, 0, -1);
if (tmp)
{
setHeader(imap, tmp, header, headerState);
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_274))
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_msg_id;
tmp = subStr(buf, esp_mail_str_274, NULL, 0, -1);
if (tmp)
{
setHeader(imap, tmp, header, headerState);
delS(tmp);
}
}
chunkIdx++;
}
}
void ESP_Mail_Client::setHeader(IMAPSession *imap, char *buf, struct esp_mail_message_header_t &header, int state)
{
switch (state)
{
case esp_mail_imap_header_state::esp_mail_imap_state_from:
header.from += buf;
break;
case esp_mail_imap_header_state::esp_mail_imap_state_to:
header.to += buf;
break;
case esp_mail_imap_header_state::esp_mail_imap_state_cc:
header.cc += buf;
break;
case esp_mail_imap_header_state::esp_mail_imap_state_subject:
header.subject += buf;
break;
case esp_mail_imap_header_state::esp_mail_imap_state_content_type:
header.content_type += buf;
break;
case esp_mail_imap_header_state::esp_mail_imap_state_content_transfer_encoding:
header.content_transfer_encoding += buf;
break;
case esp_mail_imap_header_state::esp_mail_imap_state_accept_language:
header.accept_language += buf;
break;
case esp_mail_imap_header_state::esp_mail_imap_state_content_language:
header.content_language += buf;
break;
case esp_mail_imap_header_state::esp_mail_imap_state_date:
header.date += buf;
break;
case esp_mail_imap_header_state::esp_mail_imap_state_msg_id:
header.message_id += buf;
break;
case esp_mail_imap_header_state::esp_mail_imap_state_char_set:
header.char_set += buf;
break;
case esp_mail_imap_header_state::esp_mail_imap_state_boundary:
header.boundary += buf;
break;
default:
break;
}
}
void ESP_Mail_Client::handlePartHeader(IMAPSession *imap, char *buf, int &chunkIdx, struct esp_mail_message_part_info_t &part)
{
char *tmp = nullptr;
if (chunkIdx == 0)
{
tmp = subStr(buf, esp_mail_imap_response_7, NULL, 0, -1);
if (tmp)
{
delS(tmp);
tmp = subStr(buf, esp_mail_str_193, esp_mail_str_194, 0);
if (tmp)
{
chunkIdx++;
part.octetLen = atoi(tmp);
delS(tmp);
}
}
}
else
{
if (strcmpP(buf, 0, esp_mail_str_25))
{
tmp = subStr(buf, esp_mail_str_25, esp_mail_str_97, 0);
bool con_type = false;
if (tmp)
{
con_type = true;
part.content_type = tmp;
delS(tmp);
int p1 = strposP(part.content_type.c_str(), esp_mail_imap_composite_media_type_t::multipart, 0);
if (p1 != -1)
{
p1 += strlen(esp_mail_imap_composite_media_type_t::multipart) + 1;
part.multipart = true;
//inline or embedded images
if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::related, p1) != -1)
part.multipart_sub_type = esp_mail_imap_multipart_sub_type_related;
//multiple text formats e.g. plain, html, enriched
else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::alternative, p1) != -1)
part.multipart_sub_type = esp_mail_imap_multipart_sub_type_alternative;
//medias
else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::parallel, p1) != -1)
part.multipart_sub_type = esp_mail_imap_multipart_sub_type_parallel;
//rfc822 encapsulated
else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::digest, p1) != -1)
part.multipart_sub_type = esp_mail_imap_multipart_sub_type_digest;
else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::report, p1) != -1)
part.multipart_sub_type = esp_mail_imap_multipart_sub_type_report;
//others can be attachments
else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::mixed, p1) != -1)
part.multipart_sub_type = esp_mail_imap_multipart_sub_type_mixed;
}
p1 = strposP(part.content_type.c_str(), esp_mail_imap_composite_media_type_t::message, 0);
if (p1 != -1)
{
p1 += strlen(esp_mail_imap_composite_media_type_t::message) + 1;
if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::rfc822, p1) != -1)
part.message_sub_type = esp_mail_imap_message_sub_type_rfc822;
else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::Partial, p1) != -1)
part.message_sub_type = esp_mail_imap_message_sub_type_partial;
else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::External_Body, p1) != -1)
part.message_sub_type = esp_mail_imap_message_sub_type_external_body;
else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::delivery_status, p1) != -1)
part.message_sub_type = esp_mail_imap_message_sub_type_delivery_status;
}
p1 = strpos(part.content_type.c_str(), esp_mail_imap_descrete_media_type_t::text, 0);
if (p1 != -1)
{
p1 += strlen(esp_mail_imap_descrete_media_type_t::text) + 1;
if (strpos(part.content_type.c_str(), esp_mail_imap_media_text_sub_type_t::plain, p1) != -1)
part.msg_type = esp_mail_msg_type_plain;
else if (strpos(part.content_type.c_str(), esp_mail_imap_media_text_sub_type_t::enriched, p1) != -1)
part.msg_type = esp_mail_msg_type_enriched;
else if (strpos(part.content_type.c_str(), esp_mail_imap_media_text_sub_type_t::html, p1) != -1)
part.msg_type = esp_mail_msg_type_html;
else
part.msg_type = esp_mail_msg_type_plain;
}
}
if (con_type)
{
if (part.msg_type == esp_mail_msg_type_plain || part.msg_type == esp_mail_msg_type_enriched)
{
tmp = subStr(buf, esp_mail_str_168, esp_mail_str_136, 0);
if (tmp)
{
part.charset = tmp;
delS(tmp);
}
else
{
tmp = subStr(buf, esp_mail_str_169, NULL, 0, -1);
if (tmp)
{
part.charset = tmp;
delS(tmp);
}
}
if (strposP(buf, esp_mail_str_275, 0) > -1 || strposP(buf, esp_mail_str_270, 0) > -1)
part.plain_flowed = true;
if (strposP(buf, esp_mail_str_259, 0) > -1 || strposP(buf, esp_mail_str_257, 0) > -1)
part.plain_delsp = true;
}
if (part.charset.length() == 0)
{
tmp = subStr(buf, esp_mail_str_168, esp_mail_str_136, 0);
if (tmp)
{
part.charset = tmp;
delS(tmp);
}
else
{
tmp = subStr(buf, esp_mail_str_169, NULL, 0, -1);
if (tmp)
{
part.charset = tmp;
delS(tmp);
}
}
}
tmp = subStr(buf, esp_mail_str_170, esp_mail_str_136, 0);
if (tmp)
{
part.name = tmp;
delS(tmp);
}
else
{
tmp = subStr(buf, esp_mail_str_171, NULL, 0, -1);
if (tmp)
{
part.name = tmp;
delS(tmp);
}
}
}
}
else if (strcmpP(buf, 0, esp_mail_str_172))
{
tmp = subStr(buf, esp_mail_str_172, NULL, 0, -1);
if (tmp)
{
part.content_transfer_encoding = tmp;
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_174))
{
tmp = subStr(buf, esp_mail_str_174, NULL, 0, -1);
if (tmp)
{
part.descr = tmp;
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_175))
{
tmp = subStr(buf, esp_mail_str_175, esp_mail_str_97, 0);
if (tmp)
{
//don't count altenative part text and html as embedded contents
if (cHeader(imap)->multipart_sub_type != esp_mail_imap_multipart_sub_type_alternative)
{
part.content_disposition = tmp;
if (strcmp(tmp, esp_mail_imap_content_disposition_type_t::attachment) == 0)
part.attach_type = esp_mail_att_type_attachment;
else if (strcmp(tmp, esp_mail_imap_content_disposition_type_t::inline_) == 0)
part.attach_type = esp_mail_att_type_inline;
}
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_150))
{
tmp = subStr(buf, esp_mail_str_150, NULL, 0, -1);
if (tmp)
{
part.rfc822_header.sender = tmp;
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_10))
{
tmp = subStr(buf, esp_mail_str_10, NULL, 0, -1);
if (tmp)
{
part.rfc822_header.from = tmp;
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_11))
{
tmp = subStr(buf, esp_mail_str_11, NULL, 0, -1);
if (tmp)
{
part.rfc822_header.to = tmp;
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_12))
{
tmp = subStr(buf, esp_mail_str_12, NULL, 0, -1);
if (tmp)
{
part.rfc822_header.cc = tmp;
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_184))
{
tmp = subStr(buf, esp_mail_str_184, NULL, 0, -1);
if (tmp)
{
part.rfc822_header.reply_to = tmp;
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_134))
{
tmp = subStr(buf, esp_mail_str_134, NULL, 0, -1);
if (tmp)
{
part.rfc822_header.comment = tmp;
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_24))
{
tmp = subStr(buf, esp_mail_str_24, NULL, 0, -1);
if (tmp)
{
part.rfc822_header.subject = tmp;
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_189))
{
tmp = subStr(buf, esp_mail_str_189, NULL, 0, -1);
if (tmp)
{
part.rfc822_header.messageID = tmp;
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_46))
{
tmp = subStr(buf, esp_mail_str_46, NULL, 0, -1);
if (tmp)
{
part.rfc822_header.return_path = tmp;
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_99))
{
tmp = subStr(buf, esp_mail_str_99, NULL, 0, -1);
if (tmp)
{
part.rfc822_header.date = tmp;
delS(tmp);
}
}
else if (strcmpP(buf, 0, esp_mail_str_145))
{
tmp = subStr(buf, esp_mail_str_145, NULL, 0, -1);
if (tmp)
{
part.rfc822_header.keyword = tmp;
delS(tmp);
}
}
if (part.content_disposition.length() > 0)
{
tmp = subStr(buf, esp_mail_str_176, esp_mail_str_136, 0);
if (tmp)
{
part.filename = tmp;
delS(tmp);
}
else
{
tmp = subStr(buf, esp_mail_str_177, NULL, 0, -1);
if (tmp)
{
part.filename = tmp;
delS(tmp);
}
}
tmp = subStr(buf, esp_mail_str_178, esp_mail_str_97, 0);
if (tmp)
{
part.attach_data_size = atoi(tmp);
delS(tmp);
cHeader(imap)->total_attach_data_size += part.attach_data_size;
part.sizeProp = true;
}
else
{
tmp = subStr(buf, esp_mail_str_178, NULL, 0, -1);
if (tmp)
{
part.attach_data_size = atoi(tmp);
delS(tmp);
cHeader(imap)->total_attach_data_size += part.attach_data_size;
part.sizeProp = true;
}
}
tmp = subStr(buf, esp_mail_str_179, esp_mail_str_136, 0);
if (tmp)
{
part.creation_date = tmp;
delS(tmp);
}
else
{
tmp = subStr(buf, esp_mail_str_180, NULL, 0, -1);
if (tmp)
{
part.creation_date = tmp;
delS(tmp);
}
}
tmp = subStr(buf, esp_mail_str_181, esp_mail_str_136, 0);
if (tmp)
{
part.modification_date = tmp;
delS(tmp);
}
else
{
tmp = subStr(buf, esp_mail_str_182, NULL, 0, -1);
if (tmp)
{
part.modification_date = tmp;
delS(tmp);
}
}
}
chunkIdx++;
}
}
char *ESP_Mail_Client::subStr(const char *buf, PGM_P beginH, PGM_P endH, int beginPos, int endPos)
{
char *tmp = nullptr;
int p1 = strposP(buf, beginH, beginPos);
if (p1 != -1)
{
int p2 = -1;
if (endPos == 0)
p2 = strposP(buf, endH, p1 + strlen_P(beginH));
if (p2 == -1)
p2 = strlen(buf);
int len = p2 - p1 - strlen_P(beginH);
tmp = newS(len + 1);
memcpy(tmp, &buf[p1 + strlen_P(beginH)], len);
return tmp;
}
return nullptr;
}
void ESP_Mail_Client::handleAuth(SMTPSession *smtp, char *buf)
{
if (strposP(buf, esp_mail_smtp_response_1, 0) > -1)
{
if (strposP(buf, esp_mail_smtp_response_2, 0) > -1)
smtp->_auth_capability.login = true;
if (strposP(buf, esp_mail_smtp_response_3, 0) > -1)
smtp->_auth_capability.plain = true;
if (strposP(buf, esp_mail_smtp_response_4, 0) > -1)
smtp->_auth_capability.xoauth2 = true;
if (strposP(buf, esp_mail_smtp_response_11, 0) > -1)
smtp->_auth_capability.cram_md5 = true;
if (strposP(buf, esp_mail_smtp_response_12, 0) > -1)
smtp->_auth_capability.digest_md5 = true;
}
else if (strposP(buf, esp_mail_smtp_response_5, 0) > -1)
smtp->_auth_capability.start_tls = true;
else if (strposP(buf, esp_mail_smtp_response_6, 0) > -1)
smtp->_send_capability._8bitMIME = true;
else if (strposP(buf, esp_mail_smtp_response_7, 0) > -1)
smtp->_send_capability.binaryMIME = true;
else if (strposP(buf, esp_mail_smtp_response_8, 0) > -1)
smtp->_send_capability.chunking = true;
else if (strposP(buf, esp_mail_smtp_response_9, 0) > -1)
smtp->_send_capability.utf8 = true;
else if (strposP(buf, esp_mail_smtp_response_10, 0) > -1)
smtp->_send_capability.pipelining = true;
else if (strposP(buf, esp_mail_smtp_response_13, 0) > -1)
smtp->_send_capability.dsn = true;
}
int ESP_Mail_Client::available(SMTPSession *smtp)
{
int sz = 0;
if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure)
{
if (smtp->httpClient._stream())
sz = smtp->httpClient._stream()->_ns_available();
}
else
{
if (smtp->httpClient.stream())
sz = smtp->httpClient.stream()->available();
}
return sz;
}
bool ESP_Mail_Client::handleSMTPResponse(SMTPSession *smtp, esp_mail_smtp_status_code respCode, int errCode)
{
if (!reconnect(smtp))
return false;
bool ret = false;
char *response = nullptr;
int readLen = 0;
long dataTime = millis();
int chunkBufSize = 0;
std::string s, r;
int chunkIndex = 0;
int count = 0;
bool completedResponse = false;
smtp->_smtpStatus.statusCode = 0;
smtp->_smtpStatus.respCode = 0;
smtp->_smtpStatus.text.clear();
uint8_t minResLen = 5;
struct esp_mail_smtp_response_status_t status;
chunkBufSize = available(smtp);
while (smtp->_tcpConnected && chunkBufSize <= 0)
{
if (!reconnect(smtp, dataTime))
return false;
if (!connected(smtp))
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST);
return false;
}
chunkBufSize = available(smtp);
delay(0);
}
dataTime = millis();
if (chunkBufSize > 1)
{
while (!completedResponse)
{
delay(0);
if (!reconnect(smtp, dataTime))
return false;
if (!connected(smtp))
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST);
return false;
}
chunkBufSize = available(smtp);
if (chunkBufSize <= 0)
break;
if (chunkBufSize > 0)
{
chunkBufSize = 512;
response = newS(chunkBufSize + 1);
if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure)
readLen = _readLine(smtp->httpClient._stream(), response, chunkBufSize, false, count);
else
readLen = readLine(smtp->httpClient.stream(), response, chunkBufSize, false, count);
if (readLen)
{
if (smtp->_smtp_cmd != esp_mail_smtp_command::esp_mail_smtp_cmd_initial_state)
{
//sometimes server sent multiple lines response
//sometimes rx buffer may not ready for a while
if (strlen(response) < minResLen)
{
r += response;
chunkBufSize = 0;
while (chunkBufSize == 0)
{
delay(0);
if (!reconnect(smtp, dataTime))
return false;
chunkBufSize = available(smtp);
}
}
else
{
if (r.length() > 0)
{
r += response;
memset(response, 0, chunkBufSize);
strcpy(response, r.c_str());
}
if (smtp->_debugLevel > esp_mail_debug_level_1)
esp_mail_debug((const char *)response);
}
if (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_greeting)
handleAuth(smtp, response);
}
getResponseStatus(response, respCode, 0, status);
//get the status code again for unexpected return code
if (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_start_tls || status.respCode == 0)
getResponseStatus(response, esp_mail_smtp_status_code_0, 0, status);
ret = respCode == status.respCode;
smtp->_smtpStatus = status;
if (status.respCode > 0 && (status.respCode < 400 || status.respCode == respCode))
ret = true;
if (smtp->_debug && strlen(response) >= minResLen)
{
appendP(s, esp_mail_str_260, true);
if (smtp->_smtpStatus.respCode != esp_mail_smtp_status_code_334)
s += response;
else
{
//base64 response
size_t olen;
char *decoded = (char *)decodeBase64((const unsigned char *)status.text.c_str(), status.text.length(), &olen);
if (decoded && olen > 0)
{
olen += s.length();
s += decoded;
s[olen] = 0;
delete[] decoded;
}
}
esp_mail_debug(s.c_str());
r.clear();
}
completedResponse = smtp->_smtpStatus.respCode > 0 && status.text.length() > minResLen;
if (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_auth && smtp->_smtpStatus.respCode == esp_mail_smtp_status_code_334)
{
if (authFailed(response, readLen, chunkIndex, 4))
{
smtp->_smtpStatus.statusCode = -1;
ret = false;
}
}
chunkIndex++;
if (smtp->_chunkedEnable && smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_chunk_termination)
completedResponse = smtp->_chunkCount == chunkIndex;
}
delS(response);
}
}
if (!ret)
handleSMTPError(smtp, errCode, false);
}
return ret;
}
void ESP_Mail_Client::getResponseStatus(const char *buf, esp_mail_smtp_status_code respCode, int beginPos, struct esp_mail_smtp_response_status_t &status)
{
std::string s;
char *tmp = nullptr;
int p1 = 0;
if (respCode > esp_mail_smtp_status_code_0)
{
tmp = intStr((int)respCode);
s = tmp;
appendP(s, esp_mail_str_131, false);
delS(tmp);
p1 = strpos(buf, (const char *)s.c_str(), beginPos);
}
if (p1 != -1)
{
int ofs = s.length() - 2;
if (ofs < 0)
ofs = 1;
int p2 = strposP(buf, esp_mail_str_131, p1 + ofs);
if (p2 < 4 && p2 > -1)
{
tmp = newS(p2 + 1);
memcpy(tmp, &buf[p1], p2);
status.respCode = atoi(tmp);
delS(tmp);
p1 = p2 + 1;
p2 = strlen(buf);
if (p2 > p1)
{
tmp = newS(p2 + 1);
memcpy(tmp, &buf[p1], p2 - p1);
status.text = tmp;
delS(tmp);
}
}
}
}
void ESP_Mail_Client::closeTCP(SMTPSession *smtp)
{
if (smtp->_tcpConnected)
{
if (smtp->httpClient.stream())
{
if (connected(smtp))
{
if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure)
smtp->httpClient._stream()->stop();
else
smtp->httpClient.stream()->stop();
}
}
_lastReconnectMillis = millis();
}
smtp->_tcpConnected = false;
}
void ESP_Mail_Client::closeTCP(IMAPSession *imap)
{
if (imap->_tcpConnected)
{
if (imap->httpClient.stream())
{
if (connected(imap))
{
if (!imap->_secure)
imap->httpClient._stream()->stop();
else
imap->httpClient.stream()->stop();
}
}
_lastReconnectMillis = millis();
}
imap->_tcpConnected = false;
}
#if defined(ESP32)
void ESP_Mail_Client::setSecure(ESP_Mail_HTTPClient32 &httpClient, ESP_Mail_Session *session, std::shared_ptr<const char> caCert)
#elif defined(ESP8266)
void ESP_Mail_Client::setSecure(ESP_Mail_HTTPClient &httpClient, ESP_Mail_Session *session, std::shared_ptr<const char> caCert)
#endif
{
#if defined(ESP32)
if (httpClient._certType == -1)
{
if (strlen(session->certificate.cert_file) == 0)
{
if (caCert != nullptr)
httpClient.setCACert(caCert.get());
else
httpClient.setCACert(nullptr);
}
else
{
httpClient.setCertFile(session->certificate.cert_file, session->certificate.cert_file_storage_type);
}
}
#elif defined(ESP8266)
if (httpClient._certType == -1)
{
#ifndef USING_AXTLS
if (!MailClient._clockReady && (strlen(session->certificate.cert_file) > 0 || caCert != nullptr))
{
MailClient.setClock(MailClient._gmtOffset);
httpClient._clockReady = MailClient._clockReady;
}
#endif
if (strlen(session->certificate.cert_file) == 0)
{
if (caCert != nullptr)
httpClient.setCACert(caCert.get());
else
httpClient.setCACert(nullptr);
}
else
{
httpClient.setCertFile(session->certificate.cert_file, session->certificate.cert_file_storage_type, MailClient._sdPin);
}
}
#endif
}
bool ESP_Mail_Client::ethLinkUp()
{
bool ret = false;
#if defined(ESP32)
char *ip = strP(esp_mail_str_328);
if (strcmp(ETH.localIP().toString().c_str(), ip) != 0)
ret = ETH.linkUp();
delS(ip);
#endif
return ret;
}
bool ESP_Mail_Client::reconnect(SMTPSession *smtp, unsigned long dataTime)
{
bool status = WiFi.status() == WL_CONNECTED || ethLinkUp();
if (dataTime > 0)
{
if (millis() - dataTime > smtp->httpClient.tcpTimeout)
{
closeTCP(smtp);
errorStatusCB(smtp, MAIL_CLIENT_ERROR_READ_TIMEOUT);
return false;
}
}
if (!status)
{
if (smtp->_tcpConnected)
closeTCP(smtp);
errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST);
if (millis() - _lastReconnectMillis > _reconnectTimeout && !smtp->_tcpConnected)
{
#if defined(ESP32)
esp_wifi_connect();
#elif defined(ESP8266)
WiFi.reconnect();
#endif
_lastReconnectMillis = millis();
}
status = WiFi.status() == WL_CONNECTED || ethLinkUp();
}
return status;
}
bool ESP_Mail_Client::reconnect(IMAPSession *imap, unsigned long dataTime, bool downloadRequest)
{
bool status = WiFi.status() == WL_CONNECTED || ethLinkUp();
if (dataTime > 0)
{
if (millis() - dataTime > imap->httpClient.tcpTimeout)
{
closeTCP(imap);
if (imap->_headers.size() > 0)
{
if (downloadRequest)
{
errorStatusCB(imap, IMAP_STATUS_ERROR_DOWNLAD_TIMEOUT);
if (cHeader(imap)->part_headers.size() > 0)
cPart(imap)->download_error = imap->errorReason().c_str();
}
else
{
errorStatusCB(imap, MAIL_CLIENT_ERROR_READ_TIMEOUT);
cHeader(imap)->error_msg = imap->errorReason().c_str();
}
}
return false;
}
}
if (!status)
{
if (imap->_tcpConnected)
closeTCP(imap);
errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST);
if (imap->_headers.size() > 0)
{
if (downloadRequest)
cPart(imap)->download_error = imap->errorReason().c_str();
else
cHeader(imap)->error_msg = imap->errorReason().c_str();
}
if (millis() - _lastReconnectMillis > _reconnectTimeout && !imap->_tcpConnected)
{
#if defined(ESP32)
esp_wifi_connect();
#elif defined(ESP8266)
WiFi.reconnect();
#endif
_lastReconnectMillis = millis();
}
status = WiFi.status() == WL_CONNECTED || ethLinkUp();
}
return status;
}
void ESP_Mail_Client::delS(char *p)
{
if (p != nullptr)
delete[] p;
}
char *ESP_Mail_Client::newS(size_t len)
{
char *p = new char[len];
memset(p, 0, len);
return p;
}
char *ESP_Mail_Client::newS(char *p, size_t len)
{
delS(p);
p = newS(len);
return p;
}
char *ESP_Mail_Client::newS(char *p, size_t len, char *d)
{
delS(p);
p = newS(len);
strcpy(p, d);
return p;
}
bool ESP_Mail_Client::strcmpP(const char *buf, int ofs, PGM_P beginH)
{
char *tmp = nullptr;
if (ofs < 0)
{
int p = strposP(buf, beginH, 0);
if (p == -1)
return false;
ofs = p;
}
tmp = strP(beginH);
char *tmp2 = newS(strlen_P(beginH) + 1);
memcpy(tmp2, &buf[ofs], strlen_P(beginH));
tmp2[strlen_P(beginH)] = 0;
bool ret = (strcasecmp(tmp, tmp2) == 0);
delS(tmp);
delS(tmp2);
return ret;
}
int ESP_Mail_Client::strposP(const char *buf, PGM_P beginH, int ofs)
{
char *tmp = strP(beginH);
int p = strpos(buf, tmp, ofs);
delS(tmp);
return p;
}
char *ESP_Mail_Client::strP(PGM_P pgm)
{
size_t len = strlen_P(pgm) + 1;
char *buf = newS(len);
strcpy_P(buf, pgm);
buf[len - 1] = 0;
return buf;
}
void ESP_Mail_Client::appendP(std::string &buf, PGM_P p, bool empty)
{
if (empty)
buf.clear();
char *b = strP(p);
buf += b;
delS(b);
}
char *ESP_Mail_Client::intStr(int value)
{
char *buf = newS(36);
memset(buf, 0, 36);
itoa(value, buf, 10);
return buf;
}
int ESP_Mail_Client::available(IMAPSession *imap)
{
int sz = 0;
if (!imap->_secure)
{
if (imap->httpClient._stream())
sz = imap->httpClient._stream()->_ns_available();
}
else
{
if (imap->httpClient.stream())
sz = imap->httpClient.stream()->available();
}
return sz;
}
bool ESP_Mail_Client::handleIMAPResponse(IMAPSession *imap, int errCode, bool closeSession)
{
if (!reconnect(imap))
return false;
esp_mail_imap_response_status imapResp = esp_mail_imap_response_status::esp_mail_imap_resp_unknown;
char *response = nullptr;
int readLen = 0;
long dataTime = millis();
int chunkBufSize = available(imap);
int chunkIdx = 0;
std::string s;
bool completedResponse = false;
bool endSearch = false;
struct esp_mail_message_header_t header;
struct esp_mail_message_part_info_t part;
std::string filePath = "";
bool downloadRequest = false;
int reportState = 0;
int octetCount = 0;
int octetLength = 0;
int oCount = 0;
bool tmo = false;
int headerState = 0;
int scnt = 0;
int dcnt = -1;
char *skey = nullptr;
char *spc = nullptr;
char *lastBuf = nullptr;
char *tmp = nullptr;
bool crLF = imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text && strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_31);
while (imap->_tcpConnected && chunkBufSize <= 0)
{
if (!reconnect(imap, dataTime))
return false;
if (!connected(imap))
{
errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST);
return false;
}
chunkBufSize = available(imap);
delay(0);
}
dataTime = millis();
if (chunkBufSize > 1)
{
if (imap->_imap_cmd == esp_mail_imap_cmd_examine)
{
imap->_mbif.clear();
imap->_mbif._msgCount = 0;
imap->_nextUID = "";
}
if (imap->_imap_cmd == esp_mail_imap_cmd_search)
{
imap->_mbif._searchCount = 0;
imap->_msgNum.clear();
}
chunkBufSize = 512;
response = newS(chunkBufSize + 1);
if (imap->_imap_cmd == esp_mail_imap_command::esp_mail_imap_cmd_search)
{
skey = strP(esp_mail_imap_response_6);
spc = strP(esp_mail_str_92);
}
if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline)
lastBuf = newS(BASE64_CHUNKED_LEN + 1);
while (!completedResponse)
{
delay(0);
if (!reconnect(imap, dataTime) || !connected(imap))
{
if (imap->_imap_cmd == esp_mail_imap_command::esp_mail_imap_cmd_search)
{
delS(skey);
delS(spc);
}
if (!connected(imap))
{
errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST);
return false;
}
return false;
}
chunkBufSize = available(imap);
if (chunkBufSize > 0)
{
chunkBufSize = 512;
if (imap->_imap_cmd == esp_mail_imap_command::esp_mail_imap_cmd_search)
{
readLen = getMSGNUM(imap, response, chunkBufSize, chunkIdx, endSearch, scnt, skey, spc);
imap->_mbif._availableItems = imap->_msgNum.size();
}
else
{
if (!imap->_secure)
readLen = _readLine(imap->httpClient._stream(), response, chunkBufSize, crLF, octetCount);
else
readLen = readLine(imap->httpClient.stream(), response, chunkBufSize, crLF, octetCount);
}
if (readLen)
{
if (imap->_debugLevel > esp_mail_debug_level_1)
{
if (imap->_imap_cmd != esp_mail_imap_cmd_search && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_text && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_attachment && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_inline)
esp_mail_debug((const char *)response);
}
if (imap->_imap_cmd != esp_mail_imap_cmd_search || (imap->_imap_cmd == esp_mail_imap_cmd_search && endSearch))
imapResp = imapResponseStatus(imap, response);
if (imapResp != esp_mail_imap_response_status::esp_mail_imap_resp_unknown)
{
if (imap->_debugLevel > esp_mail_debug_level_1)
{
if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline)
esp_mail_debug((const char *)response);
}
if (imap->_imap_cmd == esp_mail_imap_cmd_close)
completedResponse = true;
else
{
//some IMAP servers advertise CAPABILITY in their responses
//try to read the next available response
memset(response, 0, chunkBufSize);
if (!imap->_secure)
readLen = _readLine(imap->httpClient._stream(), response, chunkBufSize, true, octetCount);
else
readLen = readLine(imap->httpClient.stream(), response, chunkBufSize, true, octetCount);
if (readLen)
{
completedResponse = false;
imapResp = imapResponseStatus(imap, response);
if (imapResp > esp_mail_imap_response_status::esp_mail_imap_resp_unknown)
completedResponse = true;
}
else
completedResponse = true;
}
}
else
{
if (imap->_imap_cmd == esp_mail_imap_cmd_auth)
{
if (authFailed(response, readLen, chunkIdx, 2))
completedResponse = true;
}
else if (imap->_imap_cmd == esp_mail_imap_cmd_capability)
handleCapability(imap, response, chunkIdx);
else if (imap->_imap_cmd == esp_mail_imap_cmd_list)
handleFolders(imap, response);
else if (imap->_imap_cmd == esp_mail_imap_cmd_select || imap->_imap_cmd == esp_mail_imap_cmd_examine)
handleExamine(imap, response);
else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_header)
{
char *tmp = intStr(cMSG(imap));
header.message_uid = tmp;
delS(tmp);
tmp = intStr(imap->_totalRead);
header.message_no = tmp;
delS(tmp);
int _st = headerState;
handleHeader(imap, response, readLen, chunkIdx, header, headerState, octetCount);
if (_st == headerState && headerState > 0 && octetCount <= header.header_data_len)
setHeader(imap, response, header, headerState);
}
else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_mime)
handlePartHeader(imap, response, chunkIdx, part);
else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text)
decodeText(imap, response, readLen, chunkIdx, file, filePath, downloadRequest, octetLength, octetCount, dcnt);
else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline)
{
if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_31))
{
//multi-line chunked base64 string attachment handle
if (octetCount < octetLength && readLen < BASE64_CHUNKED_LEN)
{
if (strlen(lastBuf) > 0)
{
tmp = newS(readLen + strlen(lastBuf) + 2);
strcpy(tmp, lastBuf);
strcat(tmp, response);
readLen = strlen(tmp);
tmo = handleAttachment(imap, tmp, readLen, chunkIdx, file, filePath, downloadRequest, octetCount, octetLength, oCount, reportState, dcnt);
delS(tmp);
memset(lastBuf, 0, BASE64_CHUNKED_LEN + 1);
if (!tmo)
break;
}
else if (readLen < BASE64_CHUNKED_LEN + 1)
strcpy(lastBuf, response);
}
else
{
tmo = handleAttachment(imap, response, readLen, chunkIdx, file, filePath, downloadRequest, octetCount, octetLength, oCount, reportState, dcnt);
if (!tmo)
break;
}
}
else
tmo = handleAttachment(imap, response, readLen, chunkIdx, file, filePath, downloadRequest, octetCount, octetLength, oCount, reportState, dcnt);
}
dataTime = millis();
}
}
memset(response, 0, chunkBufSize);
}
}
delS(response);
if (imap->_imap_cmd == esp_mail_imap_command::esp_mail_imap_cmd_search)
{
if (imap->_debug && scnt > 0 && scnt < 100)
searchReport(100, spc);
delS(skey);
delS(spc);
}
if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment)
delS(lastBuf);
}
if ((imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_header && header.header_data_len == 0) || imapResp == esp_mail_imap_response_status::esp_mail_imap_resp_no)
{
if (imapResp == esp_mail_imap_response_status::esp_mail_imap_resp_no)
imap->_imapStatus.statusCode = IMAP_STATUS_IMAP_RESPONSE_FAILED;
else
imap->_imapStatus.statusCode = IMAP_STATUS_NO_MESSAGE;
if (imap->_readCallback)
{
std::string s;
appendP(s, esp_mail_str_53, true);
s += imap->errorReason().c_str();
imapCB(imap, s.c_str(), false);
}
if (imap->_debug)
{
std::string s;
appendP(s, esp_mail_str_185, true);
s += imap->errorReason().c_str();
esp_mail_debug_line(s.c_str(), true);
}
return false;
}
if (imapResp == esp_mail_imap_response_status::esp_mail_imap_resp_ok)
{
if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_header)
{
char *buf = newS(header.content_type.length() + 1);
strcpy(buf, header.content_type.c_str());
header.content_type.clear();
tmp = subStr(buf, esp_mail_str_25, esp_mail_str_97, 0);
if (tmp)
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_content_type;
setHeader(imap, tmp, header, headerState);
delS(tmp);
int p1 = strposP(header.content_type.c_str(), esp_mail_imap_composite_media_type_t::multipart, 0);
if (p1 != -1)
{
p1 += strlen(esp_mail_imap_composite_media_type_t::multipart) + 1;
header.multipart = true;
//inline or embedded images
if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::related, p1) != -1)
header.multipart_sub_type = esp_mail_imap_multipart_sub_type_related;
//multiple text formats e.g. plain, html, enriched
else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::alternative, p1) != -1)
header.multipart_sub_type = esp_mail_imap_multipart_sub_type_alternative;
//medias
else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::parallel, p1) != -1)
header.multipart_sub_type = esp_mail_imap_multipart_sub_type_parallel;
//rfc822 encapsulated
else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::digest, p1) != -1)
header.multipart_sub_type = esp_mail_imap_multipart_sub_type_digest;
else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::report, p1) != -1)
header.multipart_sub_type = esp_mail_imap_multipart_sub_type_report;
//others can be attachments
else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::mixed, p1) != -1)
header.multipart_sub_type = esp_mail_imap_multipart_sub_type_mixed;
}
p1 = strposP(header.content_type.c_str(), esp_mail_imap_composite_media_type_t::message, 0);
if (p1 != -1)
{
p1 += strlen(esp_mail_imap_composite_media_type_t::message) + 1;
if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::rfc822, p1) != -1)
{
header.rfc822_part = true;
header.message_sub_type = esp_mail_imap_message_sub_type_rfc822;
}
else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::Partial, p1) != -1)
header.message_sub_type = esp_mail_imap_message_sub_type_partial;
else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::External_Body, p1) != -1)
header.message_sub_type = esp_mail_imap_message_sub_type_external_body;
else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::delivery_status, p1) != -1)
header.message_sub_type = esp_mail_imap_message_sub_type_delivery_status;
}
tmp = subStr(buf, esp_mail_str_169, NULL, 0, -1);
if (tmp)
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_char_set;
setHeader(imap, tmp, header, headerState);
delS(tmp);
}
if (header.multipart)
{
if (strcmpP(buf, 0, esp_mail_str_277))
{
tmp = subStr(buf, esp_mail_str_277, esp_mail_str_136, 0);
if (tmp)
{
headerState = esp_mail_imap_header_state::esp_mail_imap_state_boundary;
setHeader(imap, tmp, header, headerState);
delS(tmp);
}
}
}
}
delS(buf);
decodeHeader(header.from, header.from_charset);
decodeHeader(header.to, header.to_charset);
decodeHeader(header.cc, header.cc_charset);
decodeHeader(header.subject, header.subject_charset);
imap->_headers.push_back(header);
}
if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_mime)
{
//expect the octet length in the response for the existent part
if (part.octetLen > 0)
{
part.partNumStr = cHeader(imap)->partNumStr;
part.partNumFetchStr = cHeader(imap)->partNumStr;
if (cHeader(imap)->part_headers.size() > 0)
{
struct esp_mail_message_part_info_t *_part = &cHeader(imap)->part_headers[cHeader(imap)->part_headers.size() - 1];
bool rfc822_body_subtype = _part->message_sub_type == esp_mail_imap_message_sub_type_rfc822;
if (rfc822_body_subtype)
{
if (!_part->rfc822_part)
{
//additional rfc822 message header, store it to the rfc822 part header
_part->rfc822_part = true;
_part->rfc822_header = part.rfc822_header;
imap->_rfc822_part_count++;
_part->rfc822_msg_Idx = imap->_rfc822_part_count;
}
}
}
cHeader(imap)->part_headers.push_back(part);
cHeader(imap)->message_data_count = cHeader(imap)->part_headers.size();
if (part.msg_type == esp_mail_msg_type_plain || part.msg_type == esp_mail_msg_type_enriched || part.msg_type == esp_mail_msg_type_html || part.attach_type == esp_mail_att_type_none || (part.attach_type == esp_mail_att_type_attachment && imap->_config->download.attachment) || (part.attach_type == esp_mail_att_type_inline && imap->_config->download.inlineImg))
{
if (part.message_sub_type != esp_mail_imap_message_sub_type_rfc822)
{
if (part.attach_type != esp_mail_att_type_none && cHeader(imap)->multipart_sub_type != esp_mail_imap_multipart_sub_type_alternative)
cHeader(imap)->attachment_count++;
}
}
}
else
{
//nonexistent part
//return false to exit the loop without closing the connection
if (closeSession)
imap->closeSession();
return false;
}
}
if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline)
{
if (cPart(imap)->file_open_write)
file.close();
}
if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text)
cPart(imap)->text[cPart(imap)->textLen] = 0;
}
else
{
//some server responses NO and should exit (false) from MIME feching loop without
//closing the session
if (imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_mime)
return handleIMAPError(imap, errCode, false);
if (closeSession)
imap->closeSession();
return false;
}
return true;
}
void ESP_Mail_Client::saveHeader(IMAPSession *imap)
{
std::string headerFilePath;
prepareFilePath(imap, headerFilePath, true);
if (imap->_storageType == esp_mail_file_storage_type_sd && !_sdOk)
_sdOk = sdTest();
else if (imap->_storageType == esp_mail_file_storage_type_flash && !_flashOk)
#if defined(ESP32)
_flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH);
#elif defined(ESP8266)
_flashOk = ESP_MAIL_FLASH_FS.begin();
#endif
if (_sdOk || _flashOk)
{
if (file)
file.close();
if (imap->_storageType == esp_mail_file_storage_type_sd)
file = ESP_MAIL_SD_FS.open(headerFilePath.c_str(), FILE_WRITE);
else if (imap->_storageType == esp_mail_file_storage_type_flash)
#if defined(ESP32)
file = ESP_MAIL_FLASH_FS.open(headerFilePath.c_str(), FILE_WRITE);
#elif defined(ESP8266)
file = ESP_MAIL_FLASH_FS.open(headerFilePath.c_str(), "w");
#endif
if (file)
{
std::string s;
appendP(s, esp_mail_str_99, true);
file.print(s.c_str());
file.println(cHeader(imap)->date.c_str());
appendP(s, esp_mail_str_100, true);
file.print(s.c_str());
if (imap->_uidSearch)
file.println(cMSG(imap));
else
file.println();
appendP(s, esp_mail_str_101, true);
file.print(s.c_str());
file.println(cMSG(imap));
appendP(s, esp_mail_str_102, true);
file.print(s.c_str());
file.println(cHeader(imap)->accept_language.c_str());
appendP(s, esp_mail_str_103, true);
file.print(s.c_str());
file.println(cHeader(imap)->content_language.c_str());
appendP(s, esp_mail_str_10, true);
file.print(s.c_str());
file.println(cHeader(imap)->from.c_str());
appendP(s, esp_mail_str_105, true);
file.print(s.c_str());
file.println(cHeader(imap)->from_charset.c_str());
appendP(s, esp_mail_str_11, true);
file.print(s.c_str());
file.println(cHeader(imap)->to.c_str());
appendP(s, esp_mail_str_107, true);
file.print(s.c_str());
file.println(cHeader(imap)->to_charset.c_str());
appendP(s, esp_mail_str_108, true);
file.print(s.c_str());
file.println(cHeader(imap)->cc.c_str());
appendP(s, esp_mail_str_109, true);
file.print(s.c_str());
file.println(cHeader(imap)->cc_charset.c_str());
appendP(s, esp_mail_str_24, true);
file.print(s.c_str());
file.println(cHeader(imap)->subject.c_str());
appendP(s, esp_mail_str_111, true);
file.print(s.c_str());
file.println(cHeader(imap)->subject_charset.c_str());
appendP(s, esp_mail_str_112, true);
file.print(s.c_str());
file.println(cPart(imap)->charset.c_str());
if (cHeader(imap)->attachment_count > 0)
{
appendP(s, esp_mail_str_113, true);
file.print(s.c_str());
file.println(cHeader(imap)->attachment_count);
for (int j = 0; j < cHeader(imap)->attachment_count; j++)
{
if (imap->_headers[cIdx(imap)].part_headers[j].attach_type == esp_mail_att_type_none || imap->_headers[cIdx(imap)].part_headers[j].rfc822_part)
continue;
struct esp_mail_attacment_info_t att;
att.filename = imap->_headers[cIdx(imap)].part_headers[j].filename.c_str();
att.mime = imap->_headers[cIdx(imap)].part_headers[j].content_type.c_str();
att.name = imap->_headers[cIdx(imap)].part_headers[j].name.c_str();
att.size = imap->_headers[cIdx(imap)].part_headers[j].attach_data_size;
att.creationDate = imap->_headers[cIdx(imap)].part_headers[j].creation_date.c_str();
att.type = imap->_headers[cIdx(imap)].part_headers[j].attach_type;
appendP(s, esp_mail_str_114, true);
file.print(s.c_str());
file.println(j + 1);
appendP(s, esp_mail_str_115, true);
file.print(s.c_str());
file.println(att.filename);
appendP(s, esp_mail_str_116, true);
file.print(s.c_str());
file.println(att.name);
appendP(s, esp_mail_str_117, true);
file.print(s.c_str());
file.println(att.size);
appendP(s, esp_mail_str_118, true);
file.print(s.c_str());
file.println(att.mime);
appendP(s, esp_mail_str_119, true);
file.print(s.c_str());
file.println(att.creationDate);
}
}
file.close();
}
imap->_headerSaved = true;
}
}
esp_mail_imap_response_status ESP_Mail_Client::imapResponseStatus(IMAPSession *imap, char *response)
{
imap->_imapStatus.text.clear();
if (strposP(response, esp_mail_imap_response_1, 0) > -1)
return esp_mail_imap_response_status::esp_mail_imap_resp_ok;
else if (strposP(response, esp_mail_imap_response_2, 0) > -1)
{
imap->_imapStatus.text = response;
imap->_imapStatus.text = imap->_imapStatus.text.substr(strlen_P(esp_mail_imap_response_2));
return esp_mail_imap_response_status::esp_mail_imap_resp_no;
}
else if (strposP(response, esp_mail_imap_response_3, 0) > -1)
{
imap->_imapStatus.text = response;
imap->_imapStatus.text = imap->_imapStatus.text.substr(strlen_P(esp_mail_imap_response_3));
return esp_mail_imap_response_status::esp_mail_imap_resp_bad;
}
return esp_mail_imap_response_status::esp_mail_imap_resp_unknown;
}
void ESP_Mail_Client::decodeHeader(std::string &headerField, std::string &headerEnc)
{
size_t p1 = 0, p2 = 0;
while (headerField[p1] == ' ' && p1 < headerField.length() - 1)
p1++;
if (headerField[p1] == '=' && headerField[p1 + 1] == '?')
{
p2 = headerField.find("?", p1 + 2);
if (p2 != std::string::npos)
headerEnc = headerField.substr(p1 + 2, p2 - p1 - 2);
}
int bufSize = 512;
char *buf = newS(bufSize);
RFC2047Decoder.rfc2047Decode(buf, headerField.c_str(), bufSize);
if (getEncodingFromCharset(headerEnc.c_str()) == esp_mail_char_decoding_scheme_iso8859_1)
{
int len = strlen(buf);
int olen = (len + 1) * 2;
unsigned char *out = (unsigned char *)newS(olen);
decodeLatin1_UTF8(out, &olen, (unsigned char *)buf, &len);
delS(buf);
buf = (char *)out;
}
else if (getEncodingFromCharset(headerEnc.c_str()) == esp_mail_char_decoding_scheme_tis620)
{
size_t len2 = strlen(buf);
char *tmp = newS((len2 + 1) * 3);
decodeTIS620_UTF8(tmp, buf, len2);
delS(buf);
buf = tmp;
}
headerField = buf;
delS(buf);
}
esp_mail_char_decoding_scheme ESP_Mail_Client::getEncodingFromCharset(const char *enc)
{
esp_mail_char_decoding_scheme scheme = esp_mail_char_decoding_scheme_default;
if (strposP(enc, esp_mail_str_237, 0) > -1 || strposP(enc, esp_mail_str_231, 0) > -1 || strposP(enc, esp_mail_str_226, 0) > -1)
scheme = esp_mail_char_decoding_scheme_tis620;
else if (strposP(enc, esp_mail_str_227, 0) > -1)
scheme = esp_mail_char_decoding_scheme_iso8859_1;
return scheme;
}
bool ESP_Mail_Client::handleAttachment(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, File &file, std::string &filePath, bool &downloadRequest, int &octetCount, int &octetLength, int &oCount, int &reportState, int &downloadCount)
{
if (chunkIdx == 0)
{
char *tmp = subStr(buf, esp_mail_str_193, esp_mail_str_194, 0);
if (tmp)
{
octetCount = 2; //CRLF counted from first line
octetLength = atoi(tmp);
delS(tmp);
chunkIdx++;
cHeader(imap)->total_download_size += octetLength;
}
return true;
}
if (octetLength == 0)
return true;
chunkIdx++;
delay(0);
if (!cPart(imap)->file_open_write)
{
cPart(imap)->file_open_write = true;
if (imap->_storageType == esp_mail_file_storage_type_sd && !_sdOk)
_sdOk = sdTest();
else if (imap->_storageType == esp_mail_file_storage_type_flash && !_flashOk)
#if defined(ESP32)
_flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH);
#elif defined(ESP8266)
_flashOk = ESP_MAIL_FLASH_FS.begin();
#endif
if (_sdOk || _flashOk)
{
downloadRequest = true;
filePath.clear();
filePath += imap->_config->storage.saved_path;
appendP(filePath, esp_mail_str_202, false);
char *tmp = intStr(cMSG(imap));
filePath += tmp;
delS(tmp);
if (imap->_storageType == esp_mail_file_storage_type_sd)
if (!ESP_MAIL_SD_FS.exists(filePath.c_str()))
createDirs(filePath);
appendP(filePath, esp_mail_str_202, false);
filePath += cPart(imap)->filename;
if (imap->_storageType == esp_mail_file_storage_type_sd)
file = ESP_MAIL_SD_FS.open(filePath.c_str(), FILE_WRITE);
else if (imap->_storageType == esp_mail_file_storage_type_flash)
#if defined(ESP32)
file = ESP_MAIL_FLASH_FS.open(filePath.c_str(), FILE_WRITE);
#elif defined(ESP8266)
file = ESP_MAIL_FLASH_FS.open(filePath.c_str(), "w");
#endif
}
}
if (_sdOk || _flashOk)
{
int nOctet = oCount + bufLen + 2;
if (nOctet > octetLength)
{
if (imap->_readCallback)
downloadReport(imap, 100);
if (oCount < octetLength)
{
int dLen = nOctet - 2 - octetLength;
bufLen -= dLen;
buf[bufLen] = 0;
}
else
return true;
}
oCount += bufLen + 2;
if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_31))
{
size_t olen = 0;
unsigned char *decoded = decodeBase64((const unsigned char *)buf, bufLen, &olen);
if (decoded)
{
if (!cPart(imap)->sizeProp)
{
cPart(imap)->attach_data_size += olen;
cHeader(imap)->total_attach_data_size += cPart(imap)->attach_data_size;
}
file.write((const uint8_t *)decoded, olen);
delay(0);
delete[] decoded;
if (imap->_config->enable.download_status)
{
int p = 0;
if (cHeader(imap)->total_download_size > 0)
p = 100 * octetCount / cHeader(imap)->total_download_size;
if ((p != downloadCount) && (p <= 100))
{
downloadCount = p;
if (imap->_readCallback && reportState != -1)
downloadReport(imap, p);
reportState = -1;
}
else
reportState = 0;
}
}
if (!reconnect(imap))
return false;
}
else
{
//binary content
if (!cPart(imap)->sizeProp)
{
cPart(imap)->attach_data_size += bufLen;
cHeader(imap)->total_attach_data_size += cPart(imap)->attach_data_size;
}
file.write((const uint8_t *)buf, bufLen);
delay(0);
if (imap->_config->enable.download_status)
{
int p = 0;
if (cHeader(imap)->total_download_size > 0)
p = 100 * octetCount / cHeader(imap)->total_download_size;
if ((p != downloadCount) && (p <= 100))
{
downloadCount = p;
if (imap->_readCallback && reportState != -1)
downloadReport(imap, p);
reportState = -1;
}
else
reportState = 0;
}
if (!reconnect(imap))
return false;
}
}
return true;
}
void ESP_Mail_Client::downloadReport(IMAPSession *imap, int progress)
{
if (imap->_readCallback && progress % ESP_MAIL_PROGRESS_REPORT_STEP == 0)
{
std::string s;
char *tmp = intStr(progress);
appendP(s, esp_mail_str_90, true);
appendP(s, esp_mail_str_131, false);
s += cPart(imap)->filename;
appendP(s, esp_mail_str_91, false);
s += tmp;
delS(tmp);
appendP(s, esp_mail_str_92, false);
appendP(s, esp_mail_str_34, false);
esp_mail_debug_line(s.c_str(), false);
std::string().swap(s);
}
}
void ESP_Mail_Client::fetchReport(IMAPSession *imap, int progress, bool download)
{
if (imap->_readCallback && progress % ESP_MAIL_PROGRESS_REPORT_STEP == 0)
{
std::string s;
char *tmp = intStr(progress);
if (download)
appendP(s, esp_mail_str_90, true);
else
appendP(s, esp_mail_str_83, true);
appendP(s, esp_mail_str_131, false);
if (cPart(imap)->filename.length() > 0)
{
s += cPart(imap)->filename;
appendP(s, esp_mail_str_91, false);
}
s += tmp;
delS(tmp);
appendP(s, esp_mail_str_92, false);
appendP(s, esp_mail_str_34, false);
esp_mail_debug_line(s.c_str(), false);
std::string().swap(s);
}
}
void ESP_Mail_Client::searchReport(int progress, const char *percent)
{
if (progress % ESP_MAIL_PROGRESS_REPORT_STEP == 0)
{
char *tmp = intStr(progress);
std::string s;
appendP(s, esp_mail_str_261, true);
s += tmp;
s += percent;
appendP(s, esp_mail_str_34, false);
esp_mail_debug_line(s.c_str(), false);
delS(tmp);
}
}
void ESP_Mail_Client::uploadReport(const char *filename, int progress)
{
if (progress % ESP_MAIL_PROGRESS_REPORT_STEP == 0)
{
std::string s;
char *tmp = intStr(progress);
appendP(s, esp_mail_str_160, true);
s += filename;
appendP(s, esp_mail_str_91, false);
s += tmp;
delS(tmp);
appendP(s, esp_mail_str_92, false);
appendP(s, esp_mail_str_34, false);
esp_mail_debug_line(s.c_str(), false);
std::string().swap(s);
}
}
int ESP_Mail_Client::cMSG(IMAPSession *imap)
{
return imap->_msgNum[cIdx(imap)];
}
int ESP_Mail_Client::cIdx(IMAPSession *imap)
{
return imap->_cMsgIdx;
}
void ESP_Mail_Client::decodeTIS620_UTF8(char *out, const char *in, size_t len)
{
//output is the 3-byte value UTF-8
int j = 0;
for (size_t i = 0; i < len; i++)
{
if (in[i] < 0x80)
out[j++] = in[i];
else if ((in[i] >= 0xa0 && in[i] < 0xdb) || (in[i] > 0xde && in[i] < 0xfc))
{
int unicode = 0x0e00 + in[i] - 0xa0;
out[j++] = 0xe0 | ((unicode >> 12) & 0xf);
out[j++] = 0x80 | ((unicode >> 6) & 0x3f);
out[j++] = 0x80 | (unicode & 0x3f);
}
}
}
int ESP_Mail_Client::decodeLatin1_UTF8(unsigned char *out, int *outlen, const unsigned char *in, int *inlen)
{
unsigned char *outstart = out;
const unsigned char *base = in;
const unsigned char *processed = in;
unsigned char *outend = out + *outlen;
const unsigned char *inend;
unsigned int c;
int bits;
inend = in + (*inlen);
while ((in < inend) && (out - outstart + 5 < *outlen))
{
c = *in++;
/* assertion: c is a single UTF-4 value */
if (out >= outend)
break;
if (c < 0x80)
{
*out++ = c;
bits = -6;
}
else
{
*out++ = ((c >> 6) & 0x1F) | 0xC0;
bits = 0;
}
for (; bits >= 0; bits -= 6)
{
if (out >= outend)
break;
*out++ = ((c >> bits) & 0x3F) | 0x80;
}
processed = (const unsigned char *)in;
}
*outlen = out - outstart;
*inlen = processed - base;
return (0);
}
void ESP_Mail_Client::decodeText(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, File &file, std::string &filePath, bool &downloadRequest, int &octetLength, int &octetCount, int &readCount)
{
bool rfc822_body_subtype = cPart(imap)->message_sub_type == esp_mail_imap_message_sub_type_rfc822;
if (chunkIdx == 0)
{
char *tmp = subStr(buf, esp_mail_str_193, esp_mail_str_194, 0);
if (tmp)
{
octetCount = 2;
octetLength = atoi(tmp);
delS(tmp);
chunkIdx++;
cPart(imap)->octetLen = octetLength;
if ((rfc822_body_subtype && imap->_config->download.rfc822) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text))))
prepareFilePath(imap, filePath, false);
if (filePath.length() == 0)
{
if (!rfc822_body_subtype)
appendP(filePath, esp_mail_str_67, false);
else
{
appendP(filePath, esp_mail_str_82, false);
appendP(filePath, esp_mail_str_131, false);
appendP(filePath, esp_mail_str_67, false);
}
}
cPart(imap)->filename = filePath;
return;
}
else
{
if (imap->_debug)
{
char *tmp = strP(esp_mail_str_280);
esp_mail_debug_line(tmp, false);
delS(tmp);
}
}
}
delay(0);
if (octetLength == 0)
return;
if (imap->_config->download.rfc822 || imap->_config->download.html || imap->_config->download.text || (rfc822_body_subtype && imap->_config->enable.rfc822) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->enable.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->enable.text))))
{
if (imap->_readCallback && octetCount > octetLength + 2 && readCount < 100)
fetchReport(imap, 100, (imap->_config->download.rfc822 && rfc822_body_subtype) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text))));
if (octetCount <= octetLength + 2)
{
size_t olen = 0;
char *decoded = nullptr;
bool newC = true;
if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_31))
{
decoded = (char *)decodeBase64((const unsigned char *)buf, bufLen, &olen);
}
else if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_278))
{
decoded = newS(bufLen + 10);
decodeQP(buf, decoded);
olen = strlen(decoded);
}
else if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_29))
{
decoded = decode7Bit(buf);
olen = strlen(decoded);
}
else
{
//8bit and binary
newC = false;
decoded = buf;
olen = bufLen;
}
if (decoded)
{
if ((rfc822_body_subtype && imap->_config->enable.rfc822) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->enable.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->enable.text))))
{
if (getEncodingFromCharset(cPart(imap)->charset.c_str()) == esp_mail_char_decoding_scheme_iso8859_1)
{
int ilen = olen;
int olen2 = (ilen + 1) * 2;
unsigned char *tmp = (unsigned char *)newS(olen2);
decodeLatin1_UTF8(tmp, &olen2, (unsigned char *)decoded, &ilen);
delS(decoded);
olen = olen2;
decoded = (char *)tmp;
}
else if (getEncodingFromCharset(cPart(imap)->charset.c_str()) == esp_mail_char_decoding_scheme_tis620)
{
char *out = newS((olen + 1) * 3);
delS(decoded);
decodeTIS620_UTF8(out, decoded, olen);
olen = strlen(out);
decoded = out;
}
int p = 0;
if (octetLength > 0)
p = 100 * octetCount / octetLength;
if ((p != readCount) && (p <= 100))
{
readCount = p;
if (imap->_readCallback)
fetchReport(imap, p, (imap->_config->download.rfc822 && rfc822_body_subtype) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text))));
}
if (cPart(imap)->text.length() < imap->_config->limit.msg_size)
{
if (cPart(imap)->text.length() + olen < imap->_config->limit.msg_size)
{
cPart(imap)->textLen += olen;
cPart(imap)->text.append(decoded, olen);
}
else
{
int d = imap->_config->limit.msg_size - cPart(imap)->text.length();
cPart(imap)->textLen += d;
if (d > 0)
cPart(imap)->text.append(decoded, d);
}
}
}
if (filePath.length() > 0)
{
if (!cPart(imap)->file_open_write)
{
cPart(imap)->file_open_write = true;
if (_sdOk || _flashOk)
{
downloadRequest = true;
if (imap->_storageType == esp_mail_file_storage_type_sd)
file = ESP_MAIL_SD_FS.open(filePath.c_str(), FILE_WRITE);
else if (imap->_storageType == esp_mail_file_storage_type_flash)
#if defined(ESP32)
file = ESP_MAIL_FLASH_FS.open(filePath.c_str(), FILE_WRITE);
#elif defined(ESP8266)
file = ESP_MAIL_FLASH_FS.open(filePath.c_str(), "w");
#endif
}
}
if (_sdOk || _flashOk)
file.write((const uint8_t *)decoded, olen);
}
if (newC)
delS(decoded);
}
}
}
}
void ESP_Mail_Client::prepareFilePath(IMAPSession *imap, std::string &filePath, bool header)
{
bool rfc822_body_subtype = cPart(imap)->message_sub_type == esp_mail_imap_message_sub_type_rfc822;
std::string fpath = imap->_config->storage.saved_path;
appendP(fpath, esp_mail_str_202, false);
char *tmp = intStr(cMSG(imap));
fpath += tmp;
delS(tmp);
if (imap->_storageType == esp_mail_file_storage_type_sd)
if (!ESP_MAIL_SD_FS.exists(fpath.c_str()))
createDirs(fpath);
if (header)
{
appendP(fpath, esp_mail_str_203, false);
}
else
{
if (!rfc822_body_subtype)
{
appendP(fpath, esp_mail_str_161, false);
if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched)
appendP(fpath, esp_mail_str_95, false);
else if (cPart(imap)->msg_type == esp_mail_msg_type_html)
appendP(fpath, esp_mail_str_94, false);
}
else
{
appendP(fpath, esp_mail_str_163, false);
if (cPart(imap)->rfc822_msg_Idx > 0)
{
char *tmp = intStr(cPart(imap)->rfc822_msg_Idx);
fpath += tmp;
delS(tmp);
}
if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched)
appendP(fpath, esp_mail_str_95, false);
else if (cPart(imap)->msg_type == esp_mail_msg_type_html)
appendP(fpath, esp_mail_str_94, false);
else
//possible rfc822 encapsulated message which cannot fetch its header
appendP(fpath, esp_mail_str_40, false);
}
}
filePath = fpath;
}
char *ESP_Mail_Client::strReplace(char *orig, char *rep, char *with)
{
char *result = nullptr;
char *ins = nullptr;
char *tmp = nullptr;
int len_rep;
int len_with;
int len_front;
int count;
len_with = strlen(with);
len_rep = strlen(rep);
ins = orig;
for (count = 0; (tmp = strstr(ins, rep)); ++count)
ins = tmp + len_rep;
tmp = result = newS(strlen(orig) + (len_with - len_rep) * count + 1);
while (count--)
{
ins = strstr(orig, rep);
len_front = ins - orig;
tmp = strncpy(tmp, orig, len_front) + len_front;
tmp = strcpy(tmp, with) + len_with;
orig += len_front + len_rep;
}
strcpy(tmp, orig);
return result;
}
int ESP_Mail_Client::decodeChar(const char *s)
{
assert(s);
assert(*s == '=');
return 16 * hexval(*(s + 1)) + hexval(*(s + 2));
}
void ESP_Mail_Client::decodeQP(const char *buf, char *out)
{
char *tmp = strP(esp_mail_str_295);
while (*buf)
{
if (*buf != '=')
strcat_c(out, *buf++);
else if (*(buf + 1) == '\r' && *(buf + 2) == '\n')
buf += 3;
else if (*(buf + 1) == '\n')
buf += 2;
else if (!strchr(tmp, *(buf + 1)))
strcat_c(out, *buf++);
else if (!strchr(tmp, *(buf + 2)))
strcat_c(out, *buf++);
else
{
strcat_c(out, decodeChar(buf));
buf += 3;
}
}
delS(tmp);
}
std::string ESP_Mail_Client::getBoundary(size_t len)
{
char *tmp = strP(boundary_table);
char *buf = newS(len);
if (len)
{
--len;
buf[0] = tmp[0];
buf[1] = tmp[1];
for (size_t n = 2; n < len; n++)
{
int key = rand() % (int)(strlen(tmp) - 1);
buf[n] = tmp[key];
}
buf[len] = '\0';
}
std::string s = buf;
delS(buf);
delS(tmp);
return s;
}
char *ESP_Mail_Client::decode7Bit(char *buf)
{
char *out = strReplaceP(buf, imap_7bit_key1, imap_7bit_val1);
char *tmp = newS(strlen(out) + 10);
strcpy(tmp, out);
delS(out);
out = strReplaceP(tmp, imap_7bit_key2, imap_7bit_val2);
delS(tmp);
tmp = newS(strlen(out) + 10);
strcpy(tmp, out);
delS(out);
out = strReplaceP(tmp, imap_7bit_key3, imap_7bit_val3);
delS(tmp);
tmp = newS(strlen(out) + 10);
strcpy(tmp, out);
delS(out);
out = strReplaceP(tmp, imap_7bit_key4, imap_7bit_val4);
delS(tmp);
tmp = newS(strlen(out) + 10);
strcpy(tmp, out);
delS(out);
out = strReplaceP(tmp, imap_7bit_key5, imap_7bit_val5);
delS(tmp);
tmp = newS(strlen(out) + 10);
strcpy(tmp, out);
delS(out);
out = strReplaceP(tmp, imap_7bit_key6, imap_7bit_val6);
delS(tmp);
tmp = newS(strlen(out) + 10);
strcpy(tmp, out);
delS(out);
out = strReplaceP(tmp, imap_7bit_key7, imap_7bit_val7);
delS(tmp);
tmp = newS(strlen(out) + 10);
strcpy(tmp, out);
delS(out);
out = strReplaceP(tmp, imap_7bit_key8, imap_7bit_val8);
delS(tmp);
tmp = newS(strlen(out) + 10);
strcpy(tmp, out);
delS(out);
out = strReplaceP(tmp, imap_7bit_key9, imap_7bit_val9);
delS(tmp);
tmp = newS(strlen(out) + 10);
strcpy(tmp, out);
delS(out);
out = strReplaceP(tmp, imap_7bit_key10, imap_7bit_val10);
delS(tmp);
tmp = newS(strlen(out) + 10);
strcpy(tmp, out);
delS(out);
out = strReplaceP(tmp, imap_7bit_key11, imap_7bit_val11);
delS(tmp);
tmp = newS(strlen(out) + 10);
strcpy(tmp, out);
delS(out);
out = strReplaceP(tmp, imap_7bit_key12, imap_7bit_val12);
delS(tmp);
tmp = newS(strlen(out) + 10);
strcpy(tmp, out);
delS(out);
out = strReplaceP(tmp, imap_7bit_key13, imap_7bit_val13);
delS(tmp);
return out;
}
char *ESP_Mail_Client::strReplaceP(char *buf, PGM_P name, PGM_P value)
{
char *n = strP(name);
char *v = strP(value);
char *out = strReplace(buf, n, v);
delS(n);
delS(v);
return out;
}
void ESP_Mail_Client::handleCapability(IMAPSession *imap, char *buf, int &chunkIdx)
{
if (chunkIdx == 0)
{
if (strposP(buf, esp_mail_imap_response_10, 0) > -1)
{
if (strposP(buf, esp_mail_imap_response_11, 0) > -1)
imap->_auth_capability.login = true;
if (strposP(buf, esp_mail_imap_response_12, 0) > -1)
imap->_auth_capability.plain = true;
if (strposP(buf, esp_mail_imap_response_13, 0) > -1)
imap->_auth_capability.xoauth2 = true;
if (strposP(buf, esp_mail_imap_response_14, 0) > -1)
imap->_auth_capability.start_tls = true;
if (strposP(buf, esp_mail_imap_response_15, 0) > -1)
imap->_auth_capability.cram_md5 = true;
if (strposP(buf, esp_mail_imap_response_16, 0) > -1)
imap->_auth_capability.digest_md5 = true;
}
}
}
bool ESP_Mail_Client::authFailed(char *buf, int bufLen, int &chunkIdx, int ofs)
{
bool ret = false;
if (chunkIdx == 0)
{
size_t olen;
unsigned char *decoded = decodeBase64((const unsigned char *)(buf + ofs), bufLen - ofs, &olen);
if (decoded)
{
ret = strposP((char *)decoded, esp_mail_str_294, 0) > -1;
delete[] decoded;
}
chunkIdx++;
}
return ret;
}
void ESP_Mail_Client::handleFolders(IMAPSession *imap, char *buf)
{
struct esp_mail_folder_info_t fd;
char *tmp = nullptr;
int p1 = strposP(buf, esp_mail_imap_response_4, 0);
int p2 = 0;
if (p1 != -1)
{
p1 = strposP(buf, esp_mail_str_198, 0);
if (p1 != -1)
{
p2 = strposP(buf, esp_mail_str_192, p1 + 1);
if (p2 != -1)
{
tmp = newS(p2 - p1);
strncpy(tmp, buf + p1 + 1, p2 - p1 - 1);
if (tmp[p2 - p1 - 2] == '\r')
tmp[p2 - p1 - 2] = 0;
fd.attributes = tmp;
delS(tmp);
}
}
p1 = strposP(buf, esp_mail_str_136, 0);
if (p1 != -1)
{
p2 = strposP(buf, esp_mail_str_136, p1 + 1);
if (p2 != -1)
{
tmp = newS(p2 - p1);
strncpy(tmp, buf + p1 + 1, p2 - p1 - 1);
if (tmp[p2 - p1 - 2] == '\r')
tmp[p2 - p1 - 2] = 0;
fd.delimiter = tmp;
delS(tmp);
}
}
p1 = strposP(buf, esp_mail_str_131, p2);
if (p1 != -1)
{
p2 = strlen(buf);
tmp = newS(p2 - p1);
if (buf[p1 + 1] == '"')
p1++;
strncpy(tmp, buf + p1 + 1, p2 - p1 - 1);
if (tmp[p2 - p1 - 2] == '\r')
tmp[p2 - p1 - 2] = 0;
if (tmp[strlen(tmp) - 1] == '"')
tmp[strlen(tmp) - 1] = 0;
fd.name = tmp;
delS(tmp);
}
imap->_folders.add(fd);
}
}
void ESP_Mail_Client::handleExamine(IMAPSession *imap, char *buf)
{
char *tmp = nullptr;
int p1, p2;
if (imap->_mbif._msgCount == 0)
{
p1 = strposP(buf, esp_mail_str_199, 0);
if (p1 != -1)
{
tmp = newS(p1);
strncpy(tmp, buf + 2, p1 - 1);
imap->_mbif._msgCount = atoi(tmp);
delS(tmp);
return;
}
}
if (imap->_mbif._flags.size() == 0)
{
p1 = strposP(buf, esp_mail_imap_response_5, 0);
if (p1 != -1)
{
p1 = strposP(buf, esp_mail_str_198, 0);
if (p1 != -1)
{
p2 = strposP(buf, esp_mail_str_192, p1 + 1);
if (p2 != -1)
{
tmp = newS(p2 - p1);
strncpy(tmp, buf + p1 + 1, p2 - p1 - 1);
char *stk = strP(esp_mail_str_131);
char *end_token;
char *token = strtok_r(tmp, stk, &end_token);
while (token != NULL)
{
imap->_mbif.addFlag(token);
token = strtok_r(NULL, stk, &end_token);
}
if (token)
delS(token);
delS(tmp);
delS(stk);
}
}
return;
}
}
if (imap->_nextUID.length() == 0)
{
p1 = strposP(buf, esp_mail_str_200, 0);
if (p1 != -1)
{
p2 = strposP(buf, esp_mail_str_156, p1 + strlen_P(esp_mail_str_200));
if (p2 != -1)
{
tmp = newS(p2 - p1 - strlen_P(esp_mail_str_200) + 1);
strncpy(tmp, buf + p1 + strlen_P(esp_mail_str_200), p2 - p1 - strlen_P(esp_mail_str_200));
imap->_nextUID = tmp;
imap->_mbif._nextUID = atoi(tmp);
delS(tmp);
}
return;
}
}
}
bool ESP_Mail_Client::handleIMAPError(IMAPSession *imap, int err, bool ret)
{
if (err < 0)
{
errorStatusCB(imap, err);
if (imap->_headers.size() > 0)
{
if ((imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) && (imap->_config->download.attachment || imap->_config->download.inlineImg))
{
if (cHeader(imap)->part_headers.size() > 0)
cPart(imap)->download_error = imap->errorReason().c_str();
}
else
cHeader(imap)->error_msg = imap->errorReason().c_str();
cHeader(imap)->error = true;
}
}
if (imap->_tcpConnected)
closeTCP(imap);
imap->_cbData.empty();
return ret;
}
unsigned char *ESP_Mail_Client::decodeBase64(const unsigned char *src, size_t len, size_t *out_len)
{
unsigned char *out, *pos, block[4], tmp;
size_t i, count, olen;
int pad = 0;
size_t extra_pad;
unsigned char *dtable = new unsigned char[256];
memset(dtable, 0x80, 256);
for (i = 0; i < sizeof(b64_index_table) - 1; i++)
dtable[b64_index_table[i]] = (unsigned char)i;
dtable['='] = 0;
count = 0;
for (i = 0; i < len; i++)
{
if (dtable[src[i]] != 0x80)
count++;
}
if (count == 0)
goto exit;
extra_pad = (4 - count % 4) % 4;
olen = (count + extra_pad) / 4 * 3;
pos = out = (unsigned char *)malloc(olen);
if (out == NULL)
goto exit;
count = 0;
for (i = 0; i < len + extra_pad; i++)
{
unsigned char val;
if (i >= len)
val = '=';
else
val = src[i];
tmp = dtable[val];
if (tmp == 0x80)
continue;
if (val == '=')
pad++;
block[count] = tmp;
count++;
if (count == 4)
{
*pos++ = (block[0] << 2) | (block[1] >> 4);
*pos++ = (block[1] << 4) | (block[2] >> 2);
*pos++ = (block[2] << 6) | block[3];
count = 0;
if (pad)
{
if (pad == 1)
pos--;
else if (pad == 2)
pos -= 2;
else
{
free(out);
goto exit;
}
break;
}
}
}
*out_len = pos - out;
delete[] dtable;
return out;
exit:
delete[] dtable;
return nullptr;
}
std::string ESP_Mail_Client::encodeBase64Str(const unsigned char *src, size_t len)
{
return encodeBase64Str((uint8_t *)src, len);
}
std::string ESP_Mail_Client::encodeBase64Str(uint8_t *src, size_t len)
{
std::string outStr;
unsigned char *out, *pos;
const unsigned char *end, *in;
size_t olen = 4 * ((len + 2) / 3);
if (olen < len)
return outStr;
outStr.resize(olen);
out = (unsigned char *)&outStr[0];
end = src + len;
in = src;
pos = out;
while (end - in >= 3)
{
*pos++ = b64_index_table[in[0] >> 2];
*pos++ = b64_index_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
*pos++ = b64_index_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
*pos++ = b64_index_table[in[2] & 0x3f];
in += 3;
}
if (end - in)
{
*pos++ = b64_index_table[in[0] >> 2];
if (end - in == 1)
{
*pos++ = b64_index_table[(in[0] & 0x03) << 4];
*pos++ = '=';
}
else
{
*pos++ = b64_index_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
*pos++ = b64_index_table[(in[1] & 0x0f) << 2];
}
*pos++ = '=';
}
return outStr;
}
void ESP_Mail_Client::encodeQP(const char *buf, char *out)
{
int n = 0, p = 0, pos = 0;
assert(buf);
for (n = 0; *buf; buf++)
{
if (n >= 73 && *buf != 10 && *buf != 13)
{
p = sprintf(out + pos, "=\r\n");
pos += p;
n = 0;
}
if (*buf == 10 || *buf == 13)
{
strcat_c(out, *buf);
pos++;
n = 0;
}
else if (*buf < 32 || *buf == 61 || *buf > 126)
{
p = sprintf(out + pos, "=%02X", (unsigned char)*buf);
n += p;
pos += p;
}
else if (*buf != 32 || (*(buf + 1) != 10 && *(buf + 1) != 13))
{
strcat_c(out, *buf);
n++;
pos++;
}
else
{
p = sprintf(out + pos, "=20");
n += p;
pos += p;
}
}
}
bool ESP_Mail_Client::sendBase64(SMTPSession *smtp, SMTP_Message *msg, const unsigned char *data, size_t len, bool flashMem, const char *filename, bool report)
{
bool ret = false;
const unsigned char *end, *in;
size_t olen = 4 * ((len + 2) / 3);
if (olen < len)
return false;
end = data + len;
in = data;
size_t chunkSize = 936;
size_t byteAdded = 0;
size_t byteSent = 0;
int dByte = 0;
unsigned char *buf = new unsigned char[chunkSize];
memset(buf, 0, chunkSize);
unsigned char *tmp = new unsigned char[3];
int bcnt = 0;
int pg = 0, _pg = 0;
if (report)
uploadReport(filename, bcnt);
while (end - in >= 3)
{
memset(tmp, 0, 3);
if (flashMem)
memcpy_P(tmp, in, 3);
else
memcpy(tmp, in, 3);
bcnt += 3;
buf[byteAdded++] = b64_index_table[tmp[0] >> 2];
buf[byteAdded++] = b64_index_table[((tmp[0] & 0x03) << 4) | (tmp[1] >> 4)];
buf[byteAdded++] = b64_index_table[((tmp[1] & 0x0f) << 2) | (tmp[2] >> 6)];
buf[byteAdded++] = b64_index_table[tmp[2] & 0x3f];
dByte += 4;
if (dByte == BASE64_CHUNKED_LEN)
{
if (byteAdded + 1 < chunkSize)
{
buf[byteAdded++] = 0x0d;
buf[byteAdded++] = 0x0a;
}
dByte = 0;
}
if (byteAdded >= chunkSize - 4)
{
byteSent += byteAdded;
if (!bdat(smtp, msg, byteAdded, false))
goto ex;
if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
goto ex;
memset(buf, 0, chunkSize);
byteAdded = 0;
}
in += 3;
if (report)
{
pg = (float)(100.0f * bcnt / len);
if (pg != _pg)
uploadReport(filename, pg);
_pg = pg;
}
}
if (byteAdded > 0)
{
if (!bdat(smtp, msg, byteAdded, false))
goto ex;
if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
goto ex;
}
if (end - in)
{
memset(buf, 0, chunkSize);
byteAdded = 0;
memset(tmp, 0, 3);
if (flashMem)
{
if (end - in == 1)
memcpy_P(tmp, in, 1);
else
memcpy_P(tmp, in, 2);
}
else
{
if (end - in == 1)
memcpy(tmp, in, 1);
else
memcpy(tmp, in, 2);
}
buf[byteAdded++] = b64_index_table[tmp[0] >> 2];
if (end - in == 1)
{
buf[byteAdded++] = b64_index_table[(tmp[0] & 0x03) << 4];
buf[byteAdded++] = '=';
}
else
{
buf[byteAdded++] = b64_index_table[((tmp[0] & 0x03) << 4) | (tmp[1] >> 4)];
buf[byteAdded++] = b64_index_table[(tmp[1] & 0x0f) << 2];
}
buf[byteAdded++] = '=';
if (!bdat(smtp, msg, byteAdded, false))
goto ex;
if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
goto ex;
memset(buf, 0, chunkSize);
}
if (report && _pg < 100)
uploadReport(filename, 100);
ret = true;
ex:
if (report)
esp_mail_debug("");
delete[] tmp;
delete[] buf;
return ret;
}
bool ESP_Mail_Client::sendBase64Stream(SMTPSession *smtp, SMTP_Message *msg, File file, const char *filename, bool report)
{
bool ret = false;
if (!file)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR);
return false;
}
size_t chunkSize = 936;
size_t byteAdded = 0;
size_t byteSent = 0;
unsigned char *buf = new unsigned char[chunkSize];
memset(buf, 0, chunkSize);
size_t len = file.size();
size_t fbufIndex = 0;
unsigned char *fbuf = new unsigned char[3];
int dByte = 0;
int bcnt = 0;
int pg = 0, _pg = 0;
if (report)
uploadReport(filename, bcnt);
while (file.available())
{
memset(fbuf, 0, 3);
if (len - fbufIndex >= 3)
{
bcnt += 3;
size_t readLen = file.read(fbuf, 3);
if (readLen != 3)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR);
break;
}
buf[byteAdded++] = b64_index_table[fbuf[0] >> 2];
buf[byteAdded++] = b64_index_table[((fbuf[0] & 0x03) << 4) | (fbuf[1] >> 4)];
buf[byteAdded++] = b64_index_table[((fbuf[1] & 0x0f) << 2) | (fbuf[2] >> 6)];
buf[byteAdded++] = b64_index_table[fbuf[2] & 0x3f];
dByte += 4;
if (dByte == BASE64_CHUNKED_LEN)
{
if (byteAdded + 1 < chunkSize)
{
buf[byteAdded++] = 0x0d;
buf[byteAdded++] = 0x0a;
}
dByte = 0;
}
if (byteAdded >= chunkSize - 4)
{
byteSent += byteAdded;
if (!bdat(smtp, msg, byteAdded, false))
goto ex;
if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
goto ex;
memset(buf, 0, chunkSize);
byteAdded = 0;
}
fbufIndex += 3;
if (report)
{
pg = (float)(100.0f * bcnt / len);
if (pg != _pg)
uploadReport(filename, pg);
_pg = pg;
}
}
else
{
size_t readLen = file.read(fbuf, len - fbufIndex);
if (readLen != len - fbufIndex)
{
errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR);
break;
}
}
}
file.close();
if (byteAdded > 0)
{
if (!bdat(smtp, msg, byteAdded, false))
goto ex;
if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
goto ex;
}
if (len - fbufIndex > 0)
{
memset(buf, 0, chunkSize);
byteAdded = 0;
buf[byteAdded++] = b64_index_table[fbuf[0] >> 2];
if (len - fbufIndex == 1)
{
buf[byteAdded++] = b64_index_table[(fbuf[0] & 0x03) << 4];
buf[byteAdded++] = '=';
}
else
{
buf[byteAdded++] = b64_index_table[((fbuf[0] & 0x03) << 4) | (fbuf[1] >> 4)];
buf[byteAdded++] = b64_index_table[(fbuf[1] & 0x0f) << 2];
}
buf[byteAdded++] = '=';
if (!bdat(smtp, msg, byteAdded, false))
goto ex;
if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
goto ex;
}
ret = true;
if (report && _pg < 100)
uploadReport(filename, 100);
ex:
delete[] buf;
delete[] fbuf;
file.close();
return ret;
}
IMAPSession::IMAPSession() {}
IMAPSession::~IMAPSession()
{
empty();
_caCert.reset();
_caCert = nullptr;
}
bool IMAPSession::closeSession()
{
if (!_tcpConnected)
return false;
#if defined(ESP32)
/**
* The strange behavior in ESP8266 SSL client, BearSSLWiFiClientSecure
* The client disposed without memory released after the server close
* the connection due to LOGOUT command, which caused the memory leaks.
*/
if (!MailClient.imapLogout(this))
return false;
#endif
return MailClient.handleIMAPError(this, 0, true);
}
bool IMAPSession::connect(ESP_Mail_Session *sesssion, IMAP_Config *config)
{
if (_tcpConnected)
MailClient.closeTCP(this);
_sesson_cfg = sesssion;
_config = config;
_caCert = nullptr;
if (strlen(_sesson_cfg->certificate.cert_data) > 0)
_caCert = std::shared_ptr<const char>(_sesson_cfg->certificate.cert_data);
if (strlen(_sesson_cfg->certificate.cert_file) > 0)
{
if (_sesson_cfg->certificate.cert_file_storage_type == esp_mail_file_storage_type::esp_mail_file_storage_type_sd && !MailClient._sdOk)
MailClient._sdOk = MailClient.sdTest();
if (_sesson_cfg->certificate.cert_file_storage_type == esp_mail_file_storage_type::esp_mail_file_storage_type_flash && !MailClient._flashOk)
#if defined(ESP32)
MailClient._flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH);
#elif defined(ESP8266)
MailClient._flashOk = ESP_MAIL_FLASH_FS.begin();
#endif
}
return MailClient.imapAuth(this);
}
void IMAPSession::debug(int level)
{
if (level > esp_mail_debug_level_0)
{
if (level > esp_mail_debug_level_3)
level = esp_mail_debug_level_1;
_debugLevel = level;
_debug = true;
}
else
{
_debugLevel = esp_mail_debug_level_0;
_debug = false;
}
}
String IMAPSession::errorReason()
{
std::string ret;
if (_imapStatus.text.length() > 0)
return _imapStatus.text.c_str();
switch (_imapStatus.statusCode)
{
case IMAP_STATUS_SERVER_CONNECT_FAILED:
MailClient.appendP(ret, esp_mail_str_38, true);
break;
case MAIL_CLIENT_ERROR_CONNECTION_LOST:
MailClient.appendP(ret, esp_mail_str_221, true);
break;
case MAIL_CLIENT_ERROR_READ_TIMEOUT:
MailClient.appendP(ret, esp_mail_str_258, true);
break;
case MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED:
MailClient.appendP(ret, esp_mail_str_305, true);
break;
case IMAP_STATUS_NO_MESSAGE:
MailClient.appendP(ret, esp_mail_str_306, true);
break;
case IMAP_STATUS_ERROR_DOWNLAD_TIMEOUT:
MailClient.appendP(ret, esp_mail_str_93, true);
break;
case MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP:
MailClient.appendP(ret, esp_mail_str_132, true);
break;
case IMAP_STATUS_CLOSE_MAILBOX_FAILED:
MailClient.appendP(ret, esp_mail_str_188, true);
break;
case IMAP_STATUS_OPEN_MAILBOX_FAILED:
MailClient.appendP(ret, esp_mail_str_281, true);
break;
case IMAP_STATUS_LIST_MAILBOXS_FAILED:
MailClient.appendP(ret, esp_mail_str_62, true);
break;
case IMAP_STATUS_NO_SUPPORTED_AUTH:
MailClient.appendP(ret, esp_mail_str_42, true);
break;
case IMAP_STATUS_CHECK_CAPABILITIES_FAILED:
MailClient.appendP(ret, esp_mail_str_63, true);
break;
case MAIL_CLIENT_ERROR_OUT_OF_MEMORY:
MailClient.appendP(ret, esp_mail_str_186, true);
break;
case IMAP_STATUS_NO_MAILBOX_FOLDER_OPENED:
MailClient.appendP(ret, esp_mail_str_153, true);
break;
default:
break;
}
return ret.c_str();
}
bool IMAPSession::selectFolder(const char *folderName, bool readOnly)
{
if (_tcpConnected)
{
if (!openFolder(folderName, readOnly))
return false;
}
else
{
_currentFolder = folderName;
}
return true;
}
bool IMAPSession::openFolder(const char *folderName, bool readOnly)
{
if (!_tcpConnected)
return false;
if (readOnly)
return openMailbox(folderName, esp_mail_imap_auth_mode::esp_mail_imap_mode_examine, true);
else
return openMailbox(folderName, esp_mail_imap_auth_mode::esp_mail_imap_mode_select, true);
}
bool IMAPSession::getFolders(FoldersCollection &folders)
{
if (!_tcpConnected)
return false;
return getMailboxes(folders);
}
bool IMAPSession::closeFolder(const char *folderName)
{
if (!_tcpConnected)
return false;
return closeMailbox();
}
void IMAPSession::checkUID()
{
if (MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_140) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_212) ||
MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_213) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_214) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_215) ||
MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_216) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_217) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_218) ||
MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_219) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_220))
_config->fetch.uid = "*";
}
void IMAPSession::checkPath()
{
std::string path = _config->storage.saved_path;
if (path[0] != '/')
{
path = "/";
path += _config->storage.saved_path;
path = path.c_str();
}
}
bool IMAPSession::headerOnly()
{
return _headerOnly;
}
struct esp_mail_imap_msg_list_t IMAPSession::data()
{
struct esp_mail_imap_msg_list_t ret;
for (size_t i = 0; i < _headers.size(); i++)
{
if (ESP.getFreeHeap() < ESP_MAIL_MIN_MEM)
continue;
struct esp_mail_imap_msg_item_t itm;
itm.UID = _headers[i].message_uid.c_str();
itm.ID = _headers[i].message_id.c_str();
itm.msgNo = _headers[i].message_no.c_str();
itm.from = _headers[i].from.c_str();
itm.fromCharset = _headers[i].from_charset.c_str();
itm.to = _headers[i].to.c_str();
itm.toCharset = _headers[i].to_charset.c_str();
itm.cc = _headers[i].cc.c_str();
itm.ccCharset = _headers[i].cc_charset.c_str();
itm.subject = _headers[i].subject.c_str();
itm.subjectCharset = _headers[i].subject_charset.c_str();
itm.date = _headers[i].date.c_str();
itm.fetchError = _headers[i].error_msg.c_str();
getMessages(i, itm);
getRFC822Messages(i, itm);
ret.msgItems.push_back(itm);
}
return ret;
}
SelectedFolderInfo IMAPSession::selectedFolder()
{
return _mbif;
}
void IMAPSession::callback(imapStatusCallback imapCallback)
{
_readCallback = std::move(imapCallback);
}
void IMAPSession::getMessages(uint16_t messageIndex, struct esp_mail_imap_msg_item_t &msg)
{
msg.text.content = "";
msg.text.charSet = "";
msg.text.content_type = "";
msg.text.transfer_encoding = "";
msg.html.content = "";
msg.html.charSet = "";
msg.html.content_type = "";
msg.html.transfer_encoding = "";
if (messageIndex < _headers.size())
{
int sz = _headers[messageIndex].part_headers.size();
if (sz > 0)
{
for (int i = 0; i < sz; i++)
{
if (!_headers[messageIndex].part_headers[i].rfc822_part && _headers[messageIndex].part_headers[i].message_sub_type != esp_mail_imap_message_sub_type_rfc822)
{
if (_headers[messageIndex].part_headers[i].attach_type == esp_mail_att_type_none)
{
if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_plain || _headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_enriched)
{
msg.text.content = _headers[messageIndex].part_headers[i].text.c_str();
msg.text.charSet = _headers[messageIndex].part_headers[i].charset.c_str();
msg.text.content_type = _headers[messageIndex].part_headers[i].content_type.c_str();
msg.text.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str();
}
if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_html)
{
msg.html.content = _headers[messageIndex].part_headers[i].text.c_str();
msg.html.charSet = _headers[messageIndex].part_headers[i].charset.c_str();
msg.html.content_type = _headers[messageIndex].part_headers[i].content_type.c_str();
msg.html.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str();
}
}
else
{
struct esp_mail_attacment_info_t att;
att.filename = _headers[messageIndex].part_headers[i].filename.c_str();
att.mime = _headers[messageIndex].part_headers[i].content_type.c_str();
att.name = _headers[messageIndex].part_headers[i].name.c_str();
att.size = _headers[messageIndex].part_headers[i].attach_data_size;
att.creationDate = _headers[messageIndex].part_headers[i].creation_date.c_str();
att.type = _headers[messageIndex].part_headers[i].attach_type;
msg.attachments.push_back(att);
}
}
}
}
}
}
void IMAPSession::getRFC822Messages(uint16_t messageIndex, struct esp_mail_imap_msg_item_t &msg)
{
if (messageIndex < _headers.size())
{
int sz = _headers[messageIndex].part_headers.size();
int partIdx = 0;
int cIdx = 0;
IMAP_MSG_Item *_rfc822 = nullptr;
if (sz > 0)
{
for (int i = 0; i < sz; i++)
{
if (_headers[messageIndex].part_headers[i].message_sub_type == esp_mail_imap_message_sub_type_rfc822)
{
if (_headers[messageIndex].part_headers[i].rfc822_part)
{
if (partIdx > 0)
msg.rfc822.push_back(*_rfc822);
cIdx = i;
partIdx++;
_rfc822 = new IMAP_MSG_Item();
_rfc822->from = _headers[messageIndex].part_headers[i].rfc822_header.from.c_str();
_rfc822->sender = _headers[messageIndex].part_headers[i].rfc822_header.sender.c_str();
_rfc822->to = _headers[messageIndex].part_headers[i].rfc822_header.to.c_str();
_rfc822->cc = _headers[messageIndex].part_headers[i].rfc822_header.cc.c_str();
_rfc822->bcc = _headers[messageIndex].part_headers[i].rfc822_header.bcc.c_str();
_rfc822->return_path = _headers[messageIndex].part_headers[i].rfc822_header.return_path.c_str();
_rfc822->reply_to = _headers[messageIndex].part_headers[i].rfc822_header.reply_to.c_str();
_rfc822->subject = _headers[messageIndex].part_headers[i].rfc822_header.subject.c_str();
_rfc822->comment = _headers[messageIndex].part_headers[i].rfc822_header.comment.c_str();
_rfc822->keyword = _headers[messageIndex].part_headers[i].rfc822_header.keyword.c_str();
_rfc822->date = _headers[messageIndex].part_headers[i].rfc822_header.date.c_str();
_rfc822->messageID = _headers[messageIndex].part_headers[i].rfc822_header.messageID.c_str();
_rfc822->text.charSet = "";
_rfc822->text.content_type = "";
_rfc822->text.transfer_encoding = "";
_rfc822->html.charSet = "";
_rfc822->html.content_type = "";
_rfc822->html.transfer_encoding = "";
}
else
{
if (MailClient.multipartMember(_headers[messageIndex].part_headers[cIdx].partNumStr, _headers[messageIndex].part_headers[i].partNumStr))
{
if (_headers[messageIndex].part_headers[i].attach_type == esp_mail_att_type_none)
{
if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_plain || _headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_enriched)
{
_rfc822->text.charSet = _headers[messageIndex].part_headers[i].charset.c_str();
_rfc822->text.content_type = _headers[messageIndex].part_headers[i].content_type.c_str();
_rfc822->text.content = _headers[messageIndex].part_headers[i].text.c_str();
_rfc822->text.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str();
}
if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_html)
{
_rfc822->html.charSet = _headers[messageIndex].part_headers[i].charset.c_str();
_rfc822->html.content_type = _headers[messageIndex].part_headers[i].content_type.c_str();
_rfc822->html.content = _headers[messageIndex].part_headers[i].text.c_str();
_rfc822->html.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str();
}
}
else
{
struct esp_mail_attacment_info_t att;
att.filename = _headers[messageIndex].part_headers[i].filename.c_str();
att.mime = _headers[messageIndex].part_headers[i].content_type.c_str();
att.name = _headers[messageIndex].part_headers[i].name.c_str();
att.size = _headers[messageIndex].part_headers[i].attach_data_size;
att.creationDate = _headers[messageIndex].part_headers[i].creation_date.c_str();
att.type = _headers[messageIndex].part_headers[i].attach_type;
_rfc822->attachments.push_back(att);
}
}
}
}
}
if ((int)msg.rfc822.size() < partIdx && _rfc822 != nullptr)
msg.rfc822.push_back(*_rfc822);
}
}
}
bool IMAPSession::closeMailbox()
{
if (!MailClient.reconnect(this))
return false;
std::string s;
if (_readCallback)
{
MailClient.appendP(s, esp_mail_str_210, true);
s += _currentFolder;
MailClient.appendP(s, esp_mail_str_96, false);
MailClient.imapCB(this, "", false);
MailClient.imapCB(this, s.c_str(), false);
}
if (_debug)
MailClient.debugInfoP(esp_mail_str_197);
if (MailClient.imapSendP(this, esp_mail_str_195, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
_imap_cmd = esp_mail_imap_cmd_close;
if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_CLOSE_MAILBOX_FAILED, false))
return false;
_currentFolder.clear();
_mailboxOpened = false;
return true;
}
bool IMAPSession::openMailbox(const char *folder, esp_mail_imap_auth_mode mode, bool waitResponse)
{
if (!MailClient.reconnect(this))
return false;
if (_currentFolder.length() > 0)
{
if (strcmp(_currentFolder.c_str(), folder) != 0)
{
if (!closeMailbox())
return false;
}
}
_currentFolder = folder;
std::string s;
if (_readCallback)
{
MailClient.appendP(s, esp_mail_str_61, true);
s += _currentFolder;
MailClient.appendP(s, esp_mail_str_96, false);
MailClient.imapCB(this, "", false);
MailClient.imapCB(this, s.c_str(), false);
}
if (_debug)
MailClient.debugInfoP(esp_mail_str_248);
if (mode == esp_mail_imap_mode_examine)
{
MailClient.appendP(s, esp_mail_str_135, true);
_imap_cmd = esp_mail_imap_cmd_examine;
}
else if (mode == esp_mail_imap_mode_select)
{
MailClient.appendP(s, esp_mail_str_247, true);
_imap_cmd = esp_mail_imap_cmd_select;
}
s += _currentFolder;
MailClient.appendP(s, esp_mail_str_136, false);
if (MailClient.imapSend(this, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
if (waitResponse)
{
if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_OPEN_MAILBOX_FAILED, false))
return false;
}
if (mode == esp_mail_imap_mode_examine)
_readOnlyMode = true;
else if (mode == esp_mail_imap_mode_select)
_readOnlyMode = false;
_mailboxOpened = true;
return true;
}
bool IMAPSession::getMailboxes(FoldersCollection &folders)
{
_folders.clear();
if (_readCallback)
{
MailClient.imapCB(this, "", false);
MailClient.imapCBP(this, esp_mail_str_58, false);
}
if (_debug)
MailClient.debugInfoP(esp_mail_str_230);
if (MailClient.imapSendP(this, esp_mail_str_133, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_list;
if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_LIST_MAILBOXS_FAILED, false))
return false;
folders = _folders;
return true;
}
bool IMAPSession::checkCapability()
{
if (_readCallback)
{
MailClient.imapCB(this, "", false);
MailClient.imapCBP(this, esp_mail_str_64, false);
}
if (_debug)
MailClient.debugInfoP(esp_mail_str_65);
if (MailClient.imapSendP(this, esp_mail_str_2, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_capability;
if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_CHECK_CAPABILITIES_FAILED, false))
return false;
return true;
}
bool IMAPSession::createFolder(const char *folderName)
{
if (_debug)
{
MailClient.imapCB(this, "", false);
MailClient.debugInfoP(esp_mail_str_320);
}
std::string cmd;
MailClient.appendP(cmd, esp_mail_str_322, true);
cmd += folderName;
if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_create;
if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false))
return false;
return true;
}
bool IMAPSession::deleteFolder(const char *folderName)
{
if (_debug)
{
MailClient.imapCB(this, "", false);
MailClient.debugInfoP(esp_mail_str_321);
}
std::string cmd;
MailClient.appendP(cmd, esp_mail_str_323, true);
cmd += folderName;
if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_delete;
if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false))
return false;
return true;
}
bool IMAPSession::deleteMessages(MessageList *toDelete, bool expunge)
{
if (toDelete->_list.size() > 0)
{
if (!selectFolder(_currentFolder.c_str(), false))
return false;
if (_debug)
{
MailClient.imapCB(this, "", false);
MailClient.debugInfoP(esp_mail_str_316);
}
std::string cmd;
char *tmp = nullptr;
MailClient.appendP(cmd, esp_mail_str_249, true);
for (size_t i = 0; i < toDelete->_list.size(); i++)
{
if (i > 0)
MailClient.appendP(cmd, esp_mail_str_263, false);
tmp = MailClient.intStr(toDelete->_list[i]);
cmd += tmp;
MailClient.delS(tmp);
}
MailClient.appendP(cmd, esp_mail_str_315, false);
if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_store;
if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false))
return false;
if (expunge)
{
if (MailClient.imapSendP(this, esp_mail_str_317, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_expunge;
if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false))
return false;
}
}
return true;
}
bool IMAPSession::copyMessages(MessageList *toCopy, const char *dest)
{
if (toCopy->_list.size() > 0)
{
if (!selectFolder(_currentFolder.c_str(), false))
return false;
if (_debug)
{
MailClient.imapCB(this, "", false);
std::string s;
MailClient.appendP(s, esp_mail_str_318, true);
s += dest;
esp_mail_debug(s.c_str());
}
std::string cmd;
char *tmp = nullptr;
MailClient.appendP(cmd, esp_mail_str_319, true);
for (size_t i = 0; i < toCopy->_list.size(); i++)
{
if (i > 0)
MailClient.appendP(cmd, esp_mail_str_263, false);
tmp = MailClient.intStr(toCopy->_list[i]);
cmd += tmp;
MailClient.delS(tmp);
}
MailClient.appendP(cmd, esp_mail_str_131, false);
cmd += dest;
if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED)
return false;
_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_store;
if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false))
return false;
}
return true;
}
#if defined(ESP8266)
void ESP_Mail_Client::setClock(float offset)
{
if (WiFi.status() != WL_CONNECTED)
WiFi.reconnect();
time_t now = time(nullptr);
_clockReady = now > ESP_MAIL_CLIENT_VALID_TS;
if (!_clockReady)
{
char *server1 = strP(esp_mail_str_283);
char *server2 = strP(esp_mail_str_296);
configTime(offset * 3600, 0, server1, server2);
now = time(nullptr);
uint8_t attempts = 0;
while (now < ESP_MAIL_CLIENT_VALID_TS)
{
now = time(nullptr);
attempts++;
if (attempts > 200 || now > ESP_MAIL_CLIENT_VALID_TS)
break;
delay(100);
}
delS(server1);
delS(server2);
}
_clockReady = now > ESP_MAIL_CLIENT_VALID_TS;
}
#endif
void IMAPSession::empty()
{
std::string().swap(_nextUID);
clearMessageData();
}
void IMAPSession::clearMessageData()
{
for (size_t i = 0; i < _headers.size(); i++)
{
_headers[i].part_headers.clear();
std::vector<struct esp_mail_message_part_info_t>().swap(_headers[i].part_headers);
}
std::vector<struct esp_mail_message_header_t>().swap(_headers);
std::vector<uint32_t>().swap(_msgNum);
_folders.clear();
_mbif._flags.clear();
_mbif._searchCount = 0;
}
SMTPSession::SMTPSession()
{
}
SMTPSession::~SMTPSession()
{
closeSession();
_caCert.reset();
_caCert = nullptr;
}
bool SMTPSession::connect(ESP_Mail_Session *config)
{
if (_tcpConnected)
MailClient.closeTCP(this);
_sesson_cfg = config;
_caCert = nullptr;
if (strlen(_sesson_cfg->certificate.cert_data) > 0)
_caCert = std::shared_ptr<const char>(_sesson_cfg->certificate.cert_data);
if (strlen(_sesson_cfg->certificate.cert_file) > 0)
{
if (_sesson_cfg->certificate.cert_file_storage_type == esp_mail_file_storage_type::esp_mail_file_storage_type_sd && !MailClient._sdOk)
MailClient._sdOk = MailClient.sdTest();
if (_sesson_cfg->certificate.cert_file_storage_type == esp_mail_file_storage_type::esp_mail_file_storage_type_flash && !MailClient._flashOk)
#if defined(ESP32)
MailClient._flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH);
#elif defined(ESP8266)
MailClient._flashOk = ESP_MAIL_FLASH_FS.begin();
#endif
}
return MailClient.smtpAuth(this);
}
void SMTPSession::debug(int level)
{
if (level > esp_mail_debug_level_0)
{
if (level > esp_mail_debug_level_3)
level = esp_mail_debug_level_1;
_debugLevel = level;
_debug = true;
}
else
{
_debugLevel = esp_mail_debug_level_0;
_debug = false;
}
}
String SMTPSession::errorReason()
{
std::string ret;
switch (_smtpStatus.statusCode)
{
case SMTP_STATUS_SERVER_CONNECT_FAILED:
MailClient.appendP(ret, esp_mail_str_38, true);
break;
case SMTP_STATUS_SMTP_GREETING_GET_RESPONSE_FAILED:
MailClient.appendP(ret, esp_mail_str_39, true);
break;
case SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED:
MailClient.appendP(ret, esp_mail_str_39, true);
break;
case SMTP_STATUS_AUTHEN_NOT_SUPPORT:
MailClient.appendP(ret, esp_mail_str_42, true);
break;
case SMTP_STATUS_AUTHEN_FAILED:
MailClient.appendP(ret, esp_mail_str_43, true);
break;
case SMTP_STATUS_USER_LOGIN_FAILED:
MailClient.appendP(ret, esp_mail_str_43, true);
break;
case SMTP_STATUS_PASSWORD_LOGIN_FAILED:
MailClient.appendP(ret, esp_mail_str_47, true);
break;
case SMTP_STATUS_SEND_HEADER_SENDER_FAILED:
MailClient.appendP(ret, esp_mail_str_48, true);
break;
case SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED:
MailClient.appendP(ret, esp_mail_str_222, true);
break;
case SMTP_STATUS_SEND_BODY_FAILED:
MailClient.appendP(ret, esp_mail_str_49, true);
break;
case MAIL_CLIENT_ERROR_CONNECTION_LOST:
MailClient.appendP(ret, esp_mail_str_221, true);
break;
case MAIL_CLIENT_ERROR_READ_TIMEOUT:
MailClient.appendP(ret, esp_mail_str_258, true);
break;
case MAIL_CLIENT_ERROR_FILE_IO_ERROR:
MailClient.appendP(ret, esp_mail_str_282, true);
break;
case SMTP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED:
MailClient.appendP(ret, esp_mail_str_293, true);
break;
case MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED:
MailClient.appendP(ret, esp_mail_str_305, true);
break;
case MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP:
MailClient.appendP(ret, esp_mail_str_132, true);
break;
case SMTP_STATUS_NO_VALID_RECIPIENTS_EXISTED:
MailClient.appendP(ret, esp_mail_str_206, true);
break;
case SMTP_STATUS_NO_VALID_SENDER_EXISTED:
MailClient.appendP(ret, esp_mail_str_205, true);
break;
case MAIL_CLIENT_ERROR_OUT_OF_MEMORY:
MailClient.appendP(ret, esp_mail_str_186, true);
break;
case SMTP_STATUS_NO_SUPPORTED_AUTH:
MailClient.appendP(ret, esp_mail_str_42, true);
break;
default:
break;
}
if (_smtpStatus.text.length() > 0 && ret.length() == 0)
{
MailClient.appendP(ret, esp_mail_str_312, true);
char *code = MailClient.intStr(_smtpStatus.respCode);
ret += code;
MailClient.delS(code);
MailClient.appendP(ret, esp_mail_str_313, false);
ret += _smtpStatus.text;
return ret.c_str();
}
return ret.c_str();
}
bool SMTPSession::closeSession()
{
if (!_tcpConnected)
return false;
if (_sendCallback)
{
_cbData._sentSuccess = _sentSuccessCount;
_cbData._sentFailed = _sentFailedCount;
MailClient.smtpCB(this, "");
MailClient.smtpCBP(this, esp_mail_str_128);
}
if (_debug)
MailClient.debugInfoP(esp_mail_str_245);
bool ret = true;
/* Sign out */
#if defined(ESP32)
/**
* The strange behavior in ESP8266 SSL client, BearSSLWiFiClientSecure
* The client disposed without memory released after the server close
* the connection due to QUIT command, which caused the memory leaks.
*/
MailClient.smtpSendP(this, esp_mail_str_7, true);
_smtp_cmd = esp_mail_smtp_cmd_logout;
ret = MailClient.handleSMTPResponse(this, esp_mail_smtp_status_code_221, SMTP_STATUS_SEND_BODY_FAILED);
#endif
if (ret)
{
if (_sendCallback)
{
MailClient.smtpCB(this, "");
MailClient.smtpCBP(this, esp_mail_str_129, false);
}
if (_debug)
MailClient.debugInfoP(esp_mail_str_246);
if (_sendCallback)
MailClient.smtpCB(this, "", true);
}
return MailClient.handleSMTPError(this, 0, ret);
}
void SMTPSession::callback(smtpStatusCallback smtpCallback)
{
_sendCallback = std::move(smtpCallback);
}
IMAP_Status::IMAP_Status()
{
}
IMAP_Status::~IMAP_Status()
{
empty();
}
const char *IMAP_Status::info()
{
return _info.c_str();
}
bool IMAP_Status::success()
{
return _success;
}
void IMAP_Status::empty()
{
std::string().swap(_info);
}
SMTP_Status::SMTP_Status()
{
}
SMTP_Status::~SMTP_Status()
{
empty();
}
const char *SMTP_Status::info()
{
return _info.c_str();
}
bool SMTP_Status::success()
{
return _success;
}
size_t SMTP_Status::completedCount()
{
return _sentSuccess;
}
size_t SMTP_Status::failedCount()
{
return _sentFailed;
}
void SMTP_Status::empty()
{
std::string().swap(_info);
}
ESP_Mail_Client MailClient = ESP_Mail_Client();
#endif /* ESP_Mail_Client_CPP */