Update mailnotification plugin

This commit is contained in:
Michael Zanetti 2019-09-18 23:18:38 +02:00
parent efa2f26b26
commit 68ddae487b
5 changed files with 102 additions and 98 deletions

View File

@ -38,24 +38,40 @@ DevicePluginMailNotification::~DevicePluginMailNotification()
{ {
} }
Device::DeviceSetupStatus DevicePluginMailNotification::setupDevice(Device *device) void DevicePluginMailNotification::startPairing(DevicePairingInfo *info)
{ {
info->finish(Device::DeviceErrorNoError, QT_TR_NOOP("Please enter your username and password for the e-mail account."));
}
void DevicePluginMailNotification::confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret)
{
// Just store details, we'll do a test login in setupDevice anyways
pluginStorage()->beginGroup(info->deviceId().toString());
pluginStorage()->setValue("username", username);
pluginStorage()->setValue("password", secret);
pluginStorage()->endGroup();
info->finish(Device::DeviceErrorNoError);
}
void DevicePluginMailNotification::setupDevice(DeviceSetupInfo *info)
{
Device *device = info->device();
// Custom mail // Custom mail
if(device->deviceClassId() == customMailDeviceClassId) { if(device->deviceClassId() == customMailDeviceClassId) {
SmtpClient *smtpClient = new SmtpClient(this); SmtpClient *smtpClient = new SmtpClient(this);
smtpClient->setHost(device->paramValue(customMailDeviceSmtpParamTypeId).toString()); smtpClient->setHost(device->paramValue(customMailDeviceSmtpParamTypeId).toString());
smtpClient->setPort(static_cast<quint16>(device->paramValue(customMailDevicePortParamTypeId).toUInt())); smtpClient->setPort(static_cast<quint16>(device->paramValue(customMailDevicePortParamTypeId).toUInt()));
smtpClient->setUser(device->paramValue(customMailDeviceCustomUserParamTypeId).toString());
// TODO: use cryptography to save password not as plain text pluginStorage()->beginGroup(device->id().toString());
smtpClient->setPassword(device->paramValue(customMailDeviceCustomPasswordParamTypeId).toString()); smtpClient->setUser(pluginStorage()->value("username").toString());
smtpClient->setPassword(pluginStorage()->value("password").toString());
pluginStorage()->endGroup();
if(device->paramValue(customMailDeviceAuthenticationParamTypeId).toString() == "PLAIN") { if(device->paramValue(customMailDeviceAuthenticationParamTypeId).toString() == "PLAIN") {
smtpClient->setAuthenticationMethod(SmtpClient::AuthenticationMethodPlain); smtpClient->setAuthenticationMethod(SmtpClient::AuthenticationMethodPlain);
} else if(device->paramValue(customMailDeviceAuthenticationParamTypeId).toString() == "LOGIN") { } else if(device->paramValue(customMailDeviceAuthenticationParamTypeId).toString() == "LOGIN") {
smtpClient->setAuthenticationMethod(SmtpClient::AuthenticationMethodLogin); smtpClient->setAuthenticationMethod(SmtpClient::AuthenticationMethodLogin);
} else {
return Device::DeviceSetupStatusFailure;
} }
if(device->paramValue(customMailDeviceEncryptionParamTypeId).toString() == "NONE") { if(device->paramValue(customMailDeviceEncryptionParamTypeId).toString() == "NONE") {
@ -64,45 +80,64 @@ Device::DeviceSetupStatus DevicePluginMailNotification::setupDevice(Device *devi
smtpClient->setEncryptionType(SmtpClient::EncryptionTypeSSL); smtpClient->setEncryptionType(SmtpClient::EncryptionTypeSSL);
} else if(device->paramValue(customMailDeviceEncryptionParamTypeId).toString() == "TLS") { } else if(device->paramValue(customMailDeviceEncryptionParamTypeId).toString() == "TLS") {
smtpClient->setEncryptionType(SmtpClient::EncryptionTypeTLS); smtpClient->setEncryptionType(SmtpClient::EncryptionTypeTLS);
} else {
return Device::DeviceSetupStatusFailure;
} }
QString recipientsString = device->paramValue(customMailDeviceCustomRecipientParamTypeId).toString(); QString recipientsString = device->paramValue(customMailDeviceRecipientParamTypeId).toString();
QStringList recipients = recipientsString.split(","); QStringList recipients = recipientsString.split(",");
smtpClient->setRecipients(recipients); smtpClient->setRecipients(recipients);
smtpClient->setSender(device->paramValue(customMailDeviceCustomSenderParamTypeId).toString()); smtpClient->setSender(device->paramValue(customMailDeviceSenderParamTypeId).toString());
connect(smtpClient, &SmtpClient::testLoginFinished, this, &DevicePluginMailNotification::testLoginFinished);
connect(smtpClient, &SmtpClient::sendMailFinished, this, &DevicePluginMailNotification::sendMailFinished);
m_clients.insert(smtpClient,device);
smtpClient->testLogin(); smtpClient->testLogin();
connect(smtpClient, &SmtpClient::testLoginFinished, info, [this, smtpClient, info, device](bool success){
if (!success) {
qCWarning(dcMailNotification()) << "Email login test failed";
info->finish(Device::DeviceErrorAuthenticationFailure, QT_TR_NOOP("The email account cannot be accessed. Wrong username or password?"));
smtpClient->deleteLater();
return;
}
return Device::DeviceSetupStatusAsync; qCDebug(dcMailNotification()) << "Email login test successful.";
m_clients.insert(smtpClient,device);
info->finish(Device::DeviceErrorNoError);
});
return;
} }
return Device::DeviceSetupStatusFailure;
info->finish(Device::DeviceErrorDeviceClassNotFound);
} }
Device::DeviceError DevicePluginMailNotification::executeAction(Device *device, const Action &action) void DevicePluginMailNotification::executeAction(DeviceActionInfo *info)
{ {
Device *device = info->device();
Action action = info->action();
if (device->deviceClassId() == customMailDeviceClassId) { if (device->deviceClassId() == customMailDeviceClassId) {
if(action.actionTypeId() == customMailNotifyActionTypeId) { if(action.actionTypeId() == customMailNotifyActionTypeId) {
SmtpClient *smtpClient = m_clients.key(device); SmtpClient *smtpClient = m_clients.key(device);
if (!smtpClient) { if (!smtpClient) {
qCWarning(dcMailNotification()) << "Could not find SMTP client for " << device; qCWarning(dcMailNotification()) << "Could not find SMTP client for " << device;
return Device::DeviceErrorHardwareNotAvailable; return info->finish(Device::DeviceErrorHardwareNotAvailable);
} }
smtpClient->sendMail(action.param(customMailNotifyActionTitleParamTypeId).value().toString(), int id = smtpClient->sendMail(action.param(customMailNotifyActionTitleParamTypeId).value().toString(),
action.param(customMailNotifyActionBodyParamTypeId).value().toString(), action.param(customMailNotifyActionBodyParamTypeId).value().toString());
action.id()); connect(smtpClient, &SmtpClient::sendMailFinished, info, [info, id](bool success, int resultId){
return Device::DeviceErrorAsync; if (id != resultId) {
return; // Not the process we were waiting for
}
if (!success) {
info->finish(Device::DeviceErrorHardwareFailure, QT_TR_NOOP("Error sending email."));
return;
}
info->finish(Device::DeviceErrorNoError);
});
return;
} }
return Device::DeviceErrorActionTypeNotFound; return info->finish(Device::DeviceErrorActionTypeNotFound);
} }
return Device::DeviceErrorDeviceClassNotFound; return info->finish(Device::DeviceErrorDeviceClassNotFound);
} }
void DevicePluginMailNotification::deviceRemoved(Device *device) void DevicePluginMailNotification::deviceRemoved(Device *device)
@ -111,31 +146,3 @@ void DevicePluginMailNotification::deviceRemoved(Device *device)
m_clients.remove(smtpClient); m_clients.remove(smtpClient);
delete smtpClient; delete smtpClient;
} }
void DevicePluginMailNotification::testLoginFinished(const bool &success)
{
SmtpClient *smtpClient = static_cast<SmtpClient*>(sender());
Device *device = m_clients.value(smtpClient);
if (success) {
qCDebug(dcMailNotification()) << "Email login test successfull";
emit deviceSetupFinished(device, Device::DeviceSetupStatusSuccess);
} else {
qCWarning(dcMailNotification()) << "Email login test failed";
emit deviceSetupFinished(device, Device::DeviceSetupStatusFailure);
if(m_clients.contains(smtpClient)) {
m_clients.remove(smtpClient);
}
smtpClient->deleteLater();
}
}
void DevicePluginMailNotification::sendMailFinished(const bool &success, const ActionId &actionId)
{
if (success) {
qCDebug(dcMailNotification()) << "Email sent successfully";
emit actionExecutionFinished(actionId, Device::DeviceErrorNoError);
} else {
qCWarning(dcMailNotification()) << "Email sending failed";
emit actionExecutionFinished(actionId, Device::DeviceErrorDeviceNotFound);
}
}

View File

@ -37,17 +37,15 @@ public:
explicit DevicePluginMailNotification(); explicit DevicePluginMailNotification();
~DevicePluginMailNotification(); ~DevicePluginMailNotification();
Device::DeviceSetupStatus setupDevice(Device *device) override; void startPairing(DevicePairingInfo *info) override;
Device::DeviceError executeAction(Device *device, const Action &action) override; void confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) override;
void setupDevice(DeviceSetupInfo *info) override;
void executeAction(DeviceActionInfo *info) override;
void deviceRemoved(Device *device) override; void deviceRemoved(Device *device) override;
private: private:
QHash <SmtpClient*, Device*> m_clients; QHash <SmtpClient*, Device*> m_clients;
private slots:
void testLoginFinished(const bool &success);
void sendMailFinished(const bool &success, const ActionId &actionId);
}; };
#endif // DEVICEPLUGINMAILNOTIFICATION_H #endif // DEVICEPLUGINMAILNOTIFICATION_H

View File

@ -11,34 +11,21 @@
{ {
"id": "f4844c97-7ca6-4349-904e-ff9749a9fe74", "id": "f4844c97-7ca6-4349-904e-ff9749a9fe74",
"name": "customMail", "name": "customMail",
"displayName": "Custom mail", "displayName": "E-mail notifications",
"createMethods": [ "user" ], "createMethods": [ "user" ],
"setupMethod": "userandpassword",
"interfaces": [ "notifications" ], "interfaces": [ "notifications" ],
"paramTypes": [ "paramTypes": [
{ {
"id": "af30ce7b-fb6b-42f0-889d-20b32f8b8fa4", "id": "af30ce7b-fb6b-42f0-889d-20b32f8b8fa4",
"name": "customSender", "name": "sender",
"displayName": "Sender mail", "displayName": "Sender mail",
"type": "QString", "type": "QString",
"inputType": "Mail" "inputType": "Mail"
}, },
{
"id": "b91d0ecc-6903-4991-ae8d-f36757ce40a7",
"name": "customUser",
"displayName": "User",
"type": "QString",
"inputType": "TextLine"
},
{
"id": "ac29e643-1d18-4612-8d2f-65fb07a67182",
"name": "customPassword",
"displayName": "Password",
"type": "QString",
"inputType": "Password"
},
{ {
"id": "d657f002-9741-42e1-9fef-32eae96dacdb", "id": "d657f002-9741-42e1-9fef-32eae96dacdb",
"name": "customRecipient", "name": "recipient",
"displayName": "Recipient", "displayName": "Recipient",
"type": "QString", "type": "QString",
"inputType": "Mail" "inputType": "Mail"

View File

@ -25,8 +25,6 @@
#include <QDateTime> #include <QDateTime>
Q_LOGGING_CATEGORY(dcSmtpClient, "SmtpClient")
SmtpClient::SmtpClient(QObject *parent): SmtpClient::SmtpClient(QObject *parent):
QObject(parent) QObject(parent)
{ {
@ -55,6 +53,7 @@ void SmtpClient::connectToHost()
void SmtpClient::testLogin() void SmtpClient::testLogin()
{ {
qCDebug(dcMailNotification()) << "Starting test login";
m_testLogin = true; m_testLogin = true;
setState(StateInitialize); setState(StateInitialize);
m_socket->close(); m_socket->close();
@ -63,19 +62,19 @@ void SmtpClient::testLogin()
void SmtpClient::connected() void SmtpClient::connected()
{ {
qCDebug(dcSmtpClient()) << "Connected"; qCDebug(dcMailNotification()) << "Connected";
} }
void SmtpClient::disconnected() void SmtpClient::disconnected()
{ {
qCDebug(dcSmtpClient()) << "Disconnected"; qCDebug(dcMailNotification()) << "Disconnected";
setState(StateIdle); setState(StateIdle);
sendNextMail(); sendNextMail();
} }
void SmtpClient::onEncrypted() void SmtpClient::onEncrypted()
{ {
qCDebug(dcSmtpClient()) << "Socket encrypted"; qCDebug(dcMailNotification()) << "Socket encrypted";
send("EHLO localhost"); send("EHLO localhost");
setState(StateAuthentification); setState(StateAuthentification);
} }
@ -86,12 +85,12 @@ void SmtpClient::readData()
QString responseLine; QString responseLine;
responseLine = m_socket->readLine(); responseLine = m_socket->readLine();
qCDebug(dcSmtpClient()) << "<--" << responseLine; qCDebug(dcMailNotification()) << "<--" << responseLine;
bool responseCodeParseSuccess = false; bool responseCodeParseSuccess = false;
int responseCode = responseLine.left(3).toInt(&responseCodeParseSuccess); int responseCode = responseLine.left(3).toInt(&responseCodeParseSuccess);
if (!responseCodeParseSuccess) { if (!responseCodeParseSuccess) {
qCWarning(dcSmtpClient()) << "Could not convert status code to a valid integer" << responseLine; qCWarning(dcMailNotification()) << "Could not convert status code to a valid integer" << responseLine;
if (m_state != StateIdle) { if (m_state != StateIdle) {
handleSmtpFailure(); handleSmtpFailure();
continue; continue;
@ -102,15 +101,17 @@ void SmtpClient::readData()
} }
} }
void SmtpClient::sendMail(const QString &subject, const QString &body, const ActionId &actionId) int SmtpClient::sendMail(const QString &subject, const QString &body)
{ {
static int ids = 0;
Message message; Message message;
message.subject = subject; message.subject = subject;
message.body = body; message.body = body;
message.actionId = actionId; message.id = ids++;
m_messageQueue.enqueue(message); m_messageQueue.enqueue(message);
sendNextMail(); sendNextMail();
return message.id;
} }
void SmtpClient::setHost(const QString &host) void SmtpClient::setHost(const QString &host)
@ -163,12 +164,13 @@ void SmtpClient::setState(SmtpClient::State state)
if (m_state == state) if (m_state == state)
return; return;
qCDebug(dcSmtpClient()) << state; qCDebug(dcMailNotification()) << state;
m_state = state; m_state = state;
} }
void SmtpClient::processServerResponse(int responseCode, const QString &response) void SmtpClient::processServerResponse(int responseCode, const QString &response)
{ {
qCDebug(dcMailNotification()) << "Server response:" << responseCode << response;
switch (m_state) { switch (m_state) {
case StateIdle: case StateIdle:
// Check if we have to send an other email, otherwise we are done and remain in idle // Check if we have to send an other email, otherwise we are done and remain in idle
@ -203,7 +205,7 @@ void SmtpClient::processServerResponse(int responseCode, const QString &response
// We need a 220 befor continue // We need a 220 befor continue
if (responseCode == 220) { if (responseCode == 220) {
if (!m_socket->isEncrypted() && m_encryptionType != EncryptionTypeNone) { if (!m_socket->isEncrypted() && m_encryptionType != EncryptionTypeNone) {
qCDebug(dcSmtpClient()) << "Start client encryption..."; qCDebug(dcMailNotification()) << "Start client encryption...";
m_socket->startClientEncryption(); m_socket->startClientEncryption();
} }
} else { } else {
@ -223,12 +225,12 @@ void SmtpClient::processServerResponse(int responseCode, const QString &response
} }
break; break;
case StateAuthentification: case StateAuthentification:
// Ignore server information messages until we get a '250 ...' instead of '250-....' // Ignore server information messages of '250-....' (with dash), we need a clear "250 ..."
if (responseCode == 250 && response.at(3) != ' ') { if (responseCode == 250 && response.at(3) != ' ') {
break; break;
} }
if (responseCode == 250) { if (responseCode == 250 || responseCode == 220) {
if (m_authenticationMethod == AuthenticationMethodLogin) { if (m_authenticationMethod == AuthenticationMethodLogin) {
send("AUTH LOGIN"); send("AUTH LOGIN");
setState(StateUser); setState(StateUser);
@ -277,6 +279,11 @@ void SmtpClient::processServerResponse(int responseCode, const QString &response
} }
break; break;
case StateTestLoginFinished: case StateTestLoginFinished:
// Ignore server information messages
if (responseCode == 250) {
break;
}
if (responseCode == 235) { if (responseCode == 235) {
emit testLoginFinished(true); emit testLoginFinished(true);
} else { } else {
@ -286,12 +293,17 @@ void SmtpClient::processServerResponse(int responseCode, const QString &response
m_testLogin = false; m_testLogin = false;
break; break;
case StateMail: case StateMail:
// Ignore server information messages
if (responseCode == 250) {
break;
}
if (responseCode == 235) { if (responseCode == 235) {
send("MAIL FROM:<" + m_sender + ">"); send("MAIL FROM:<" + m_sender + ">");
// Prepare queue for recipients // Prepare queue for recipients
m_recipientsQueue.clear(); m_recipientsQueue.clear();
qCDebug(dcSmtpClient()) << "Prepare recipients list" << m_recipients; qCDebug(dcMailNotification()) << "Prepare recipients list" << m_recipients;
foreach (const QString &recipient, m_recipients) { foreach (const QString &recipient, m_recipients) {
m_recipientsQueue.enqueue(recipient.trimmed()); m_recipientsQueue.enqueue(recipient.trimmed());
} }
@ -344,7 +356,7 @@ void SmtpClient::processServerResponse(int responseCode, const QString &response
} }
if (responseCode == 250) { if (responseCode == 250) {
emit sendMailFinished(true, m_message.actionId); emit sendMailFinished(true, m_message.id);
send("QUIT"); send("QUIT");
setState(StateClose); setState(StateClose);
} else { } else {
@ -355,7 +367,7 @@ void SmtpClient::processServerResponse(int responseCode, const QString &response
if (responseCode == 221) { if (responseCode == 221) {
m_socket->close(); m_socket->close();
} else { } else {
qCDebug(dcSmtpClient()) << "The server does not handle the QUIT command. This is ok, we close the socket either way."; qCDebug(dcMailNotification()) << "The server does not handle the QUIT command. This is ok, we close the socket either way.";
} }
// some mail server does not recognize the QUIT command...so close the connection either way // some mail server does not recognize the QUIT command...so close the connection either way
@ -410,7 +422,7 @@ void SmtpClient::handleSmtpFailure()
if (m_testLogin) { if (m_testLogin) {
emit testLoginFinished(false); emit testLoginFinished(false);
} else { } else {
emit sendMailFinished(false, m_message.actionId); emit sendMailFinished(false, m_message.id);
} }
// Clean up // Clean up
@ -438,7 +450,7 @@ void SmtpClient::onSocketError(QAbstractSocket::SocketError error)
void SmtpClient::send(const QString &data) void SmtpClient::send(const QString &data)
{ {
qCDebug(dcSmtpClient()) << "-->" << data; qCDebug(dcMailNotification()) << "-->" << data;
m_socket->write(data.toUtf8() + "\r\n"); m_socket->write(data.toUtf8() + "\r\n");
m_socket->flush(); m_socket->flush();
} }

View File

@ -31,14 +31,14 @@
#include <QStringList> #include <QStringList>
#include <QLoggingCategory> #include <QLoggingCategory>
#include "devices/deviceplugin.h" //#include "devices/deviceplugin.h"
Q_DECLARE_LOGGING_CATEGORY(dcSmtpClient) Q_DECLARE_LOGGING_CATEGORY(dcSmtpClient)
struct Message { struct Message {
QString subject; QString subject;
QString body; QString body;
ActionId actionId; int id;
}; };
@ -82,7 +82,7 @@ public:
void connectToHost(); void connectToHost();
void testLogin(); void testLogin();
void sendMail(const QString &subject, const QString &body, const ActionId &actionId); int sendMail(const QString &subject, const QString &body);
void setHost(const QString &host); void setHost(const QString &host);
void setPort(const quint16 &port); void setPort(const quint16 &port);
@ -127,8 +127,8 @@ private:
void handleUnexpectedSmtpCode(int responseCode, const QString &serverMessage); void handleUnexpectedSmtpCode(int responseCode, const QString &serverMessage);
signals: signals:
void sendMailFinished(const bool &success, const ActionId &actionId); void sendMailFinished(bool success, int &id);
void testLoginFinished(const bool &success); void testLoginFinished(bool success);
private slots: private slots: