This commit is contained in:
gemu2015 2019-09-04 20:58:17 +02:00
parent af1edb0cdb
commit ca52a38bc1
3 changed files with 510 additions and 1 deletions

302
lib/SENDMAIL/sendemail.cpp Executable file
View File

@ -0,0 +1,302 @@
#include "sendemail.h"
// enable serial debugging
//#define DEBUG_EMAIL_PORT Serial
SendEmail::SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used) :
host(host), port(port), user(user), passwd(passwd), timeout(timeout), ssl(ssl), auth_used(auth_used), client(new WiFiClientSecure())
{
}
String SendEmail::readClient()
{
String r = client->readStringUntil('\n');
r.trim();
while (client->available()) {
delay(0);
r += client->readString();
}
return r;
}
void SetSerialBaudrate(int baudrate);
bool SendEmail::send(const String& from, const String& to, const String& subject, const String& msg)
{
if (!host.length())
{
return false;
}
client->setTimeout(timeout);
// smtp connect
#ifdef DEBUG_EMAIL_PORT
SetSerialBaudrate(115200);
DEBUG_EMAIL_PORT.print("Connecting: ");
DEBUG_EMAIL_PORT.print(host);
DEBUG_EMAIL_PORT.print(":");
DEBUG_EMAIL_PORT.println(port);
#endif
#ifndef ARDUINO_ESP8266_RELEASE_2_4_2
client->setInsecure();
bool mfln = client->probeMaxFragmentLength(host.c_str(), port, 512);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.printf("MFLN supported: %s\n", mfln ? "yes" : "no");
#endif
if (mfln) {
client->setBufferSizes(512, 512);
}
#endif
if (!client->connect(host.c_str(), port))
{
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println("Connection failed");
#endif
return false;
}
String buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("220")))
{
return false;
}
buffer = F("EHLO ");
buffer += client->localIP().toString();
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("250")))
{
return false;
}
if (user.length()>0 && passwd.length()>0 )
{
//buffer = F("STARTTLS");
//client->println(buffer);
if (auth_used==1) {
// plain
#ifdef USE_PLAIN
buffer = F("AUTH PLAIN");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("334")))
{
return false;
}
char plainAuth[100];
memset(plainAuth,sizeof(plainAuth),0);
plainAuth[0] = '\0';
strcpy(&plainAuth[1], user.c_str());
strcpy(&plainAuth[2+user.length()],passwd.c_str());
const char* pA = (const char*)&plainAuth;
char buf[100];
base64_encode(buf, pA, user.length()+passwd.length()+2);
client->println(buf);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buf);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("235")))
{
return false;
}
#endif
} else {
buffer = F("AUTH LOGIN");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("334")))
{
return false;
}
base64 b;
//buffer = user;
//buffer = b.encode(buffer);
buffer = b.encode(user);
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
//DEBUG_EMAIL_PORT.println(user);
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("334")))
{
return false;
}
//buffer = this->passwd;
//buffer = b.encode(buffer);
buffer = b.encode(passwd);
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
//DEBUG_EMAIL_PORT.println(passwd);
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("235")))
{
return false;
}
}
}
// smtp send mail
buffer = F("MAIL FROM:");
buffer += from;
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("250")))
{
return false;
}
buffer = F("RCPT TO:");
buffer += to;
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("250")))
{
return false;
}
buffer = F("DATA");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = readClient();
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
if (!buffer.startsWith(F("354")))
{
return false;
}
buffer = F("From: ");
buffer += from;
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = F("To: ");
buffer += to;
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = F("Subject: ");
buffer += subject;
buffer += F("\r\n");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = msg;
client->println(buffer);
client->println('.');
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
buffer = F("QUIT");
client->println(buffer);
#ifdef DEBUG_EMAIL_PORT
DEBUG_EMAIL_PORT.println(buffer);
#endif
return true;
}
#ifdef USE_PLAIN
void SendEmail::a3_to_a4(unsigned char * a4, unsigned char * a3) {
a4[0] = (a3[0] & 0xfc) >> 2;
a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
a4[3] = (a3[2] & 0x3f);
}
int SendEmail::base64_encode(char *output, const char *input, int inputLen) {
const char* _b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int i = 0, j = 0;
int encLen = 0;
unsigned char a3[3];
unsigned char a4[4];
while(inputLen--) {
a3[i++] = *(input++);
if(i == 3) {
a3_to_a4(a4, a3);
for(i = 0; i < 4; i++) {
output[encLen++] = _b64_alphabet[a4[i]];
}
i = 0;
}
}
if(i) {
for(j = i; j < 3; j++) {
a3[j] = '\0';
}
a3_to_a4(a4, a3);
for(j = 0; j < i + 1; j++) {
output[encLen++] = _b64_alphabet[a4[j]];
}
while((i++ < 3)) {
output[encLen++] = '=';
}
}
output[encLen] = '\0';
return encLen;
}
#endif

39
lib/SENDMAIL/sendemail.h Executable file
View File

@ -0,0 +1,39 @@
#ifndef __SENDEMAIL_H
#define __SENDEMAIL_H
//#define DEBUG_EMAIL_PORT
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <base64.h>
#include <core_version.h>
class SendEmail
{
private:
const String host;
const int port;
const String user;
const String passwd;
const int timeout;
const bool ssl;
const int auth_used;
#ifndef ARDUINO_ESP8266_RELEASE_2_4_2
// use bear ssl
// #include "WiFiClientSecureLightBearSSL.h"
// BearSSL::WiFiClientSecure_light *client;
//BearSSL::WiFiClientSecure* client;
WiFiClientSecure* client;
#else
WiFiClient* client;
#endif
String readClient();
void a3_to_a4(unsigned char * a4, unsigned char * a3);
int base64_encode(char *output, const char *input, int inputLen);
public:
SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const int auth_used);
bool send(const String& from, const String& to, const String& subject, const String& msg);
~SendEmail() {client->stop(); delete client;}
};
#endif

View File

@ -1053,6 +1053,7 @@ bool HandleRootStatusRefresh(void)
#ifdef USE_SCRIPT_WEB_DISPLAY
XdrvCall(FUNC_WEB_SENSOR);
#endif
WSContentSend_P(PSTR("</table>"));
if (devices_present) {
@ -2350,6 +2351,151 @@ String UrlEncode(const String& text)
return encoded;
}
#ifdef USE_SENDMAIL
#include "sendemail.h"
//SendEmail(const String& host, const int port, const String& user, const String& passwd, const int timeout, const bool ssl);
//SendEmail::send(const String& from, const String& to, const String& subject, const String& msg)
// sendmail [server:port:user:passwd:from:to:subject] data
// sendmail [*:*:*:*:*:to:subject] data uses defines from user_config
// sendmail currently only works with core 2.4.2
#define SEND_MAIL_MINRAM 19*1024
uint16_t SendMail(char *buffer) {
uint16_t count;
char *params,*oparams;
char *mserv;
uint16_t port;
char *user;
char *pstr;
char *passwd;
char *from;
char *to;
char *subject;
char *cmd;
char secure=0,auth=0;
uint16_t status=1;
SendEmail *mail=0;
//DebugFreeMem();
// return if not enough memory
uint16_t mem=ESP.getFreeHeap();
if (mem<SEND_MAIL_MINRAM) {
return 4;
}
while (*buffer==' ') buffer++;
// copy params
oparams=(char*)calloc(strlen(buffer)+2,1);
if (!oparams) return 4;
params=oparams;
strcpy(params,buffer);
if (*params=='p') {
auth=1;
params++;
}
if (*params!='[') {
goto exit;
}
params++;
mserv=strtok(params,":");
if (!mserv) {
goto exit;
}
// port
pstr=strtok(NULL,":");
if (!pstr) {
goto exit;
}
#ifdef EMAIL_PORT
if (*pstr=='*') {
port=EMAIL_PORT;
} else {
port=atoi(pstr);
}
#else
port=atoi(pstr);
#endif
user=strtok(NULL,":");
if (!user) {
goto exit;
}
passwd=strtok(NULL,":");
if (!passwd) {
goto exit;
}
from=strtok(NULL,":");
if (!from) {
goto exit;
}
to=strtok(NULL,":");
if (!to) {
goto exit;
}
subject=strtok(NULL,"]");
if (!subject) {
goto exit;
}
cmd=subject+strlen(subject)+1;
#ifdef EMAIL_USER
if (*user=='*') {
user=(char*)EMAIL_USER;
}
#endif
#ifdef EMAIL_PASSWORD
if (*passwd=='*') {
passwd=(char*)EMAIL_PASSWORD;
}
#endif
#ifdef EMAIL_SERVER
if (*mserv=='*') {
mserv=(char*)EMAIL_SERVER;
}
#endif //USE_SENDMAIL
// auth = 0 => AUTH LOGIN 1 => PLAIN LOGIN
// 2 seconds timeout
#define MAIL_TIMEOUT 2000
mail = new SendEmail(mserv, port,user,passwd, MAIL_TIMEOUT, auth);
#ifdef EMAIL_FROM
if (*from=='*') {
from=(char*)EMAIL_FROM;
}
#endif
exit:
if (mail) {
bool result=mail->send(from,to,subject,cmd);
delete mail;
if (result==true) status=0;
}
if (oparams) free(oparams);
return status;
}
#endif
int WebSend(char *buffer)
{
// [sonoff] POWER1 ON --> Sends http://sonoff/cm?cmnd=POWER1 ON
@ -2462,17 +2608,27 @@ bool JsonWebColor(const char* dataBuf)
return true;
}
const char kWebSendStatus[] PROGMEM = D_JSON_DONE "|" D_JSON_WRONG_PARAMETERS "|" D_JSON_CONNECT_FAILED "|" D_JSON_HOST_NOT_FOUND ;
#define D_CMND_SENDMAIL "sendmail"
#define D_JSON_MEMORY_ERROR "memory error"
const char kWebSendStatus[] PROGMEM = D_JSON_DONE "|" D_JSON_WRONG_PARAMETERS "|" D_JSON_CONNECT_FAILED "|" D_JSON_HOST_NOT_FOUND "|" D_JSON_MEMORY_ERROR;
const char kWebCommands[] PROGMEM = "|" // No prefix
#ifdef USE_EMULATION
D_CMND_EMULATION "|"
#endif
#ifdef USE_SENDMAIL
D_CMND_SENDMAIL "|"
#endif
D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_WEBREFRESH "|" D_CMND_WEBSEND "|" D_CMND_WEBCOLOR "|" D_CMND_WEBSENSOR;
void (* const WebCommand[])(void) PROGMEM = {
#ifdef USE_EMULATION
&CmndEmulation,
#endif
#ifdef USE_SENDMAIL
&CmndSendmail,
#endif
&CmndWebServer, &CmndWebPassword, &CmndWeblog, &CmndWebRefresh, &CmndWebSend, &CmndWebColor, &CmndWebSensor };
@ -2500,6 +2656,18 @@ void CmndEmulation(void)
}
#endif // USE_EMULATION
#ifdef USE_SENDMAIL
void CmndSendmail(void)
{
if (XdrvMailbox.data_len > 0) {
uint8_t result = SendMail(XdrvMailbox.data);
char stemp1[20];
ResponseCmndChar(GetTextIndexed(stemp1, sizeof(stemp1), result, kWebSendStatus));
}
}
#endif // USE_SENDMAIL
void CmndWebServer(void)
{
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) {