Clean up email notification plugin and prepare for improvement

This commit is contained in:
Simon Stürz 2019-04-29 16:31:57 +02:00
parent e6347ba0a9
commit 4b11f1b481
4 changed files with 77 additions and 225 deletions

View File

@ -36,11 +36,6 @@
\chapter Supported services
\section2 Google Mail
With the Google Mail Notification you can send a mail with your gmail address to a recipient. The
username is your mail address (e.g. "chuck.norris@gmail.com"). The recipient will receive the notification
from your gmail account.
\section2 Yahoo Mail
The Yahoo Mail Notification you can send a mail with your yahoo address to a recipient. The username
is your mail address (e.g. "chuck.norris@yahoo.com"). The recipient will receive the notification
@ -80,48 +75,6 @@ DevicePluginMailNotification::~DevicePluginMailNotification()
DeviceManager::DeviceSetupStatus DevicePluginMailNotification::setupDevice(Device *device)
{
// Google mail
if(device->deviceClassId() == googleMailDeviceClassId) {
SmtpClient *smtpClient = new SmtpClient(this);
smtpClient->setHost("smtp.gmail.com");
smtpClient->setPort(465);
smtpClient->setUser(device->paramValue(googleMailDeviceUserParamTypeId).toString());
// TODO: use cryptography to save password not as plain text
smtpClient->setPassword(device->paramValue(googleMailDevicePasswordParamTypeId).toString());
smtpClient->setAuthMethod(SmtpClient::AuthMethodLogin);
smtpClient->setEncryptionType(SmtpClient::EncryptionTypeSSL);
smtpClient->setSender(device->paramValue(googleMailDeviceUserParamTypeId).toString());
smtpClient->setRecipient(device->paramValue(googleMailDeviceRecipientParamTypeId).toString());
connect(smtpClient, &SmtpClient::testLoginFinished, this, &DevicePluginMailNotification::testLoginFinished);
connect(smtpClient, &SmtpClient::sendMailFinished, this, &DevicePluginMailNotification::sendMailFinished);
m_clients.insert(smtpClient,device);
smtpClient->testLogin();
return DeviceManager::DeviceSetupStatusAsync;
}
// Yahoo mail
if(device->deviceClassId() == yahooMailDeviceClassId) {
SmtpClient *smtpClient = new SmtpClient(this);
smtpClient->setHost("smtp.mail.yahoo.com");
smtpClient->setPort(465);
smtpClient->setUser(device->paramValue(yahooMailDeviceUserParamTypeId).toString());
// TODO: use cryptography to save password not as plain text
smtpClient->setPassword(device->paramValue(yahooMailDevicePasswordParamTypeId).toString());
smtpClient->setAuthMethod(SmtpClient::AuthMethodLogin);
smtpClient->setEncryptionType(SmtpClient::EncryptionTypeSSL);
smtpClient->setSender(device->paramValue(yahooMailDeviceUserParamTypeId).toString());
smtpClient->setRecipient(device->paramValue(yahooMailDeviceRecipientParamTypeId).toString());
connect(smtpClient, &SmtpClient::testLoginFinished, this, &DevicePluginMailNotification::testLoginFinished);
connect(smtpClient, &SmtpClient::sendMailFinished, this, &DevicePluginMailNotification::sendMailFinished);
m_clients.insert(smtpClient,device);
smtpClient->testLogin();
return DeviceManager::DeviceSetupStatusAsync;
}
// Custom mail
if(device->deviceClassId() == customMailDeviceClassId) {
SmtpClient *smtpClient = new SmtpClient(this);
@ -133,9 +86,9 @@ DeviceManager::DeviceSetupStatus DevicePluginMailNotification::setupDevice(Devic
smtpClient->setPassword(device->paramValue(customMailDeviceCustomPasswordParamTypeId).toString());
if(device->paramValue(customMailDeviceAuthenticationParamTypeId).toString() == "PLAIN") {
smtpClient->setAuthMethod(SmtpClient::AuthMethodPlain);
smtpClient->setAuthenticationMethod(SmtpClient::AuthenticationMethodPlain);
} else if(device->paramValue(customMailDeviceAuthenticationParamTypeId).toString() == "LOGIN") {
smtpClient->setAuthMethod(SmtpClient::AuthMethodLogin);
smtpClient->setAuthenticationMethod(SmtpClient::AuthenticationMethodLogin);
} else {
return DeviceManager::DeviceSetupStatusFailure;
}
@ -166,12 +119,22 @@ DeviceManager::DeviceSetupStatus DevicePluginMailNotification::setupDevice(Devic
DeviceManager::DeviceError DevicePluginMailNotification::executeAction(Device *device, const Action &action)
{
if(action.actionTypeId() == googleMailSendMailActionTypeId) {
SmtpClient *smtpClient = m_clients.key(device);
smtpClient->sendMail(action.param(googleMailSendMailActionSubjectParamTypeId).value().toString(), action.param(googleMailSendMailActionBodyParamTypeId).value().toString(), action.id());
return DeviceManager::DeviceErrorAsync;
if (device->deviceClassId() == customMailDeviceClassId) {
if(action.actionTypeId() == customMailNotifyActionTypeId) {
SmtpClient *smtpClient = m_clients.key(device);
if (!smtpClient) {
qCWarning(dcMailNotification()) << "Could not find SMTP client for " << device;
return DeviceManager::DeviceErrorHardwareNotAvailable;
}
smtpClient->sendMail(action.param(customMailNotifyActionTitleParamTypeId).value().toString(),
action.param(customMailNotifyActionBodyParamTypeId).value().toString(),
action.id());
return DeviceManager::DeviceErrorAsync;
}
return DeviceManager::DeviceErrorActionTypeNotFound;
}
return DeviceManager::DeviceErrorActionTypeNotFound;
return DeviceManager::DeviceErrorDeviceClassNotFound;
}
void DevicePluginMailNotification::deviceRemoved(Device *device)

View File

@ -12,7 +12,8 @@
"id": "f4844c97-7ca6-4349-904e-ff9749a9fe74",
"name": "customMail",
"displayName": "Custom mail",
"createMethods": ["user"],
"createMethods": [ "user" ],
"interfaces": [ "notifications" ],
"paramTypes": [
{
"id": "af30ce7b-fb6b-42f0-889d-20b32f8b8fa4",
@ -75,130 +76,12 @@
"actionTypes": [
{
"id": "054613b0-3666-4dad-9252-e0ebca187edc",
"name": "send",
"name": "notify",
"displayName": "send mail",
"paramTypes": [
{
"id": "2047e0f4-3d34-4214-bc8f-9ab741ae6006",
"name": "subject",
"displayName": "subject",
"type": "QString",
"inputType": "TextLine"
},
{
"id": "aeb6e79e-9862-43e1-9873-cbdce549344a",
"name": "body",
"displayName": "body",
"type": "QString",
"inputType": "TextArea"
}
]
}
]
}
]
},
{
"name": "google",
"displayName": "Google",
"id": "d02399c5-8e79-40be-8cf6-e00b55bbfe7c",
"deviceClasses": [
{
"id": "3869884a-1592-4b8f-84a7-994be18ff555",
"name": "googleMail",
"displayName": "Google mail",
"createMethods": ["user"],
"paramTypes": [
{
"id": "0a4ea3ff-ea76-4a5f-adbb-b8f79faa2156",
"name": "user",
"displayName": "user",
"type": "QString",
"inputType": "Mail"
},
{
"id": "f63f6486-5340-472a-b37c-be828111725c",
"name": "password",
"displayName": "password",
"type": "QString",
"inputType": "Password"
},
{
"id": "76697fe2-3393-4ed0-a15d-9d041502cfd3",
"name": "recipient",
"displayName": "recipient",
"type": "QString",
"inputType": "Mail"
}
],
"actionTypes": [
{
"id": "054613b0-3666-4dad-9252-e0ebca187edc",
"name": "sendMail",
"displayName": "send mail",
"paramTypes": [
{
"id": "2047e0f4-3d34-4214-bc8f-9ab741ae6006",
"name": "subject",
"displayName": "subject",
"type": "QString",
"inputType": "TextLine"
},
{
"id": "aeb6e79e-9862-43e1-9873-cbdce549344a",
"name": "body",
"displayName": "body",
"type": "QString",
"inputType": "TextArea"
}
]
}
]
}
]
},
{
"name": "yahoo",
"displayName": "Yahoo",
"id": "5eb3e1e9-25a7-4740-806e-5cfc836e4bf5",
"deviceClasses": [
{
"id": "59409e8f-0c83-414f-abd5-bbbf2758acba",
"name": "yahooMail",
"displayName": "Yahoo mail",
"createMethods": ["user"],
"paramTypes": [
{
"id": "0a4ea3ff-ea76-4a5f-adbb-b8f79faa2156",
"name": "user",
"displayName": "user",
"type": "QString",
"inputType": "Mail"
},
{
"id": "f63f6486-5340-472a-b37c-be828111725c",
"name": "password",
"displayName": "password",
"type": "QString",
"inputType": "Password"
},
{
"id": "76697fe2-3393-4ed0-a15d-9d041502cfd3",
"name": "recipient",
"displayName": "recipient",
"type": "QString",
"inputType": "Mail"
}
],
"actionTypes": [
{
"id": "054613b0-3666-4dad-9252-e0ebca187edc",
"name": "send",
"displayName": "send mail",
"paramTypes": [
{
"id": "2047e0f4-3d34-4214-bc8f-9ab741ae6006",
"name": "subject",
"name": "title",
"displayName": "subject",
"type": "QString",
"inputType": "TextLine"

View File

@ -27,30 +27,23 @@ SmtpClient::SmtpClient(QObject *parent):
QObject(parent)
{
m_socket = new QSslSocket(this);
m_state = InitState;
m_testLogin = false;
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
// error because QSslSocket has also a method called error...also QAbstractSocket or QTcpSocket don't work...
//connect(m_socket, &QSslSocket::error, this, &SmtpClient::socketError);
connect(m_socket, &QSslSocket::connected, this, &SmtpClient::connected);
connect(m_socket, &QSslSocket::readyRead, this, &SmtpClient::readData);
connect(m_socket, &QSslSocket::disconnected, this, &SmtpClient::disconnected);
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError)));
}
void SmtpClient::connectToHost()
{
switch (m_encryptionType) {
case EncryptionTypeNone:
case EncryptionTypeTLS:
m_socket->connectToHost(m_host, m_port);
break;
case EncryptionTypeSSL:
m_socket->connectToHostEncrypted(m_host, m_port);
break;
case EncryptionTypeTLS:
m_socket->connectToHost(m_host,m_port);
break;
default:
break;
}
@ -80,59 +73,68 @@ void SmtpClient::readData()
responseLine = m_socket->readLine();
response.append(responseLine);
}
responseLine.truncate( 3 );
responseLine.truncate(3);
qCDebug(dcMailNotification()) << "<--" << response << "|" << responseLine;
switch (m_state) {
case InitState:
if(responseLine == "220") {
if (responseLine == "220") {
send("EHLO localhost");
if(m_encryptionType == EncryptionTypeNone) {
if (m_encryptionType == EncryptionTypeNone) {
m_state = AuthentificationState;
break;
}
if(m_encryptionType == EncryptionTypeSSL) {
if (m_encryptionType == EncryptionTypeSSL) {
m_state = HandShakeState;
break;
}
if(m_encryptionType == EncryptionTypeTLS) {
if (m_encryptionType == EncryptionTypeTLS) {
m_state = StartTlsState;
break;
}
}
break;
case HandShakeState:
if(responseLine == "250") {
if(!m_socket->isEncrypted() && m_encryptionType != EncryptionTypeNone) {
if (responseLine == "250") {
if (!m_socket->isEncrypted() && m_encryptionType != EncryptionTypeNone) {
m_socket->startClientEncryption();
}
send("EHLO localhost");
m_state = AuthentificationState;
}
if(responseLine == "220") {
if(!m_socket->isEncrypted() && m_encryptionType != EncryptionTypeNone) {
if (responseLine == "220") {
if (!m_socket->isEncrypted() && m_encryptionType != EncryptionTypeNone) {
m_socket->startClientEncryption();
}
send("EHLO localhost");
m_state = AuthentificationState;
}
break;
case StartTlsState:
if(responseLine == "250") {
if (responseLine == "250") {
send("STARTTLS");
m_state = HandShakeState;
}
break;
case AuthentificationState:
if(responseLine == "250") {
if(m_authMethod == AuthMethodLogin) {
if (responseLine == "250") {
if (m_authenticationMethod == AuthenticationMethodLogin) {
send("AUTH LOGIN");
m_state = UserState;
break;
}
if(m_authMethod == AuthMethodPlain) {
if (m_authenticationMethod == AuthenticationMethodPlain) {
send("AUTH PLAIN " + QByteArray().append((char) 0).append(m_user).append((char) 0).append(m_password).toBase64());
// if we just want to test the Login, we are almost done here
if(!m_testLogin) {
if (!m_testLogin) {
m_state = MailState;
} else {
m_state = TestLoginFinishedState;
@ -142,16 +144,16 @@ void SmtpClient::readData()
}
break;
case UserState:
if(responseLine == "334") {
if (responseLine == "334") {
send(QByteArray().append(m_user).toBase64());
m_state = PasswordState;
}
break;
case PasswordState:
if(responseLine == "334") {
if (responseLine == "334") {
send(QByteArray().append(m_password).toBase64());
// if we just want to test the Login, we are almost done here
if(!m_testLogin) {
if (!m_testLogin) {
m_state = MailState;
} else {
m_state = TestLoginFinishedState;
@ -160,7 +162,7 @@ void SmtpClient::readData()
}
break;
case TestLoginFinishedState:
if(responseLine == "235") {
if (responseLine == "235") {
emit testLoginFinished(true);
} else {
emit testLoginFinished(false);
@ -169,38 +171,38 @@ void SmtpClient::readData()
m_testLogin = false;
break;
case MailState:
if(responseLine == "235") {
if (responseLine == "235") {
send("MAIL FROM:<" + m_sender + ">");
m_state = RcptState;
}
break;
case RcptState:
if(responseLine == "250") {
if (responseLine == "250") {
send("RCPT TO:<" + m_rcpt + ">");
m_state = DataState;
}
break;
case DataState:
if(responseLine == "250") {
if (responseLine == "250") {
send("DATA");
m_state = BodyState;
}
break;
case BodyState:
if(responseLine == "354") {
if (responseLine == "354") {
send(m_message + "\r\n.\r\n");
m_state = QuitState;
}
break;
case QuitState:
if(responseLine == "250") {
if (responseLine == "250") {
emit sendMailFinished(true, m_actionId);
send("QUIT");
m_state = CloseState;
}
break;
case CloseState:
if(responseLine == "221") {
if (responseLine == "221") {
m_socket->close();
}
// some mail server does not recognize the QUIT command...so close the connection either way
@ -208,7 +210,7 @@ void SmtpClient::readData()
break;
default:
// unexpecterd response code received...
if(m_testLogin) {
if (m_testLogin) {
emit testLoginFinished(false);
m_testLogin = false;
m_socket->close();
@ -256,9 +258,9 @@ void SmtpClient::setEncryptionType(const SmtpClient::EncryptionType &encryptionT
m_encryptionType = encryptionType;
}
void SmtpClient::setAuthMethod(const SmtpClient::AuthMethod &authMethod)
void SmtpClient::setAuthenticationMethod(const SmtpClient::AuthenticationMethod &authenticationMethod)
{
m_authMethod = authMethod;
m_authenticationMethod = authenticationMethod;
}
void SmtpClient::setUser(const QString &user)
@ -281,13 +283,14 @@ void SmtpClient::setRecipient(const QString &rcpt)
m_rcpt = rcpt;
}
void SmtpClient::socketError(QAbstractSocket::SocketError error)
void SmtpClient::onSocketError(QAbstractSocket::SocketError error)
{
qCWarning(dcMailNotification) << "Mail socket -> " << error << m_socket->errorString();
qCWarning(dcMailNotification) << "Mail socket error" << error << m_socket->errorString();
}
void SmtpClient::send(const QString &data)
{
qCDebug(dcMailNotification()) << "-->" << qUtf8Printable(data.toUtf8());
m_socket->write(data.toUtf8() + "\r\n");
m_socket->flush();
}

View File

@ -35,10 +35,11 @@ class SmtpClient : public QObject
Q_OBJECT
public:
enum AuthMethod{
AuthMethodPlain,
AuthMethodLogin
enum AuthenticationMethod{
AuthenticationMethodPlain,
AuthenticationMethodLogin
};
Q_ENUM(AuthenticationMethod)
enum SendState{
InitState,
@ -55,12 +56,14 @@ public:
QuitState,
CloseState
};
Q_ENUM(SendState)
enum EncryptionType{
EncryptionTypeNone,
EncryptionTypeSSL,
EncryptionTypeTLS
};
Q_ENUM(EncryptionType)
explicit SmtpClient(QObject *parent = 0);
@ -71,22 +74,22 @@ public:
void setHost(const QString &host);
void setPort(const int &port);
void setEncryptionType(const EncryptionType &encryptionType);
void setAuthMethod(const AuthMethod &authMethod);
void setAuthenticationMethod(const AuthenticationMethod &authenticationMethod);
void setUser(const QString &user);
void setPassword(const QString &password);
void setSender(const QString &sender);
void setRecipient(const QString &rcpt);
private:
QSslSocket *m_socket;
SendState m_state;
QString m_host;
int m_port;
QSslSocket *m_socket = nullptr;
SendState m_state = InitState;
QString m_host = "127.0.0.1";
int m_port = 25;
QString m_user;
QString m_password;
QString m_sender;
AuthMethod m_authMethod;
AuthenticationMethod m_authenticationMethod;
EncryptionType m_encryptionType;
QString m_rcpt;
QString m_subject;
@ -94,14 +97,14 @@ private:
QString m_message;
ActionId m_actionId;
bool m_testLogin;
bool m_testLogin = false;
signals:
void sendMailFinished(const bool &success, const ActionId &actionId);
void testLoginFinished(const bool &success);
private slots:
void socketError(QAbstractSocket::SocketError error);
void onSocketError(QAbstractSocket::SocketError error);
void connected();
void disconnected();
void readData();