From 4b11f1b48188993f65a3d039531a1c59b750e189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 29 Apr 2019 16:31:57 +0200 Subject: [PATCH] Clean up email notification plugin and prepare for improvement --- .../devicepluginmailnotification.cpp | 71 +++------- .../devicepluginmailnotification.json | 125 +----------------- mailnotification/smtpclient.cpp | 79 +++++------ mailnotification/smtpclient.h | 27 ++-- 4 files changed, 77 insertions(+), 225 deletions(-) diff --git a/mailnotification/devicepluginmailnotification.cpp b/mailnotification/devicepluginmailnotification.cpp index f526a274..08fffef7 100644 --- a/mailnotification/devicepluginmailnotification.cpp +++ b/mailnotification/devicepluginmailnotification.cpp @@ -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) diff --git a/mailnotification/devicepluginmailnotification.json b/mailnotification/devicepluginmailnotification.json index c18ed934..1c279939 100644 --- a/mailnotification/devicepluginmailnotification.json +++ b/mailnotification/devicepluginmailnotification.json @@ -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" diff --git a/mailnotification/smtpclient.cpp b/mailnotification/smtpclient.cpp index e6e9764f..9901b072 100644 --- a/mailnotification/smtpclient.cpp +++ b/mailnotification/smtpclient.cpp @@ -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(); } diff --git a/mailnotification/smtpclient.h b/mailnotification/smtpclient.h index 6f7e5ee1..3d0a6a6e 100644 --- a/mailnotification/smtpclient.h +++ b/mailnotification/smtpclient.h @@ -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();