Update mailnotification plugin

master
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
if(device->deviceClassId() == customMailDeviceClassId) {
SmtpClient *smtpClient = new SmtpClient(this);
smtpClient->setHost(device->paramValue(customMailDeviceSmtpParamTypeId).toString());
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
smtpClient->setPassword(device->paramValue(customMailDeviceCustomPasswordParamTypeId).toString());
pluginStorage()->beginGroup(device->id().toString());
smtpClient->setUser(pluginStorage()->value("username").toString());
smtpClient->setPassword(pluginStorage()->value("password").toString());
pluginStorage()->endGroup();
if(device->paramValue(customMailDeviceAuthenticationParamTypeId).toString() == "PLAIN") {
smtpClient->setAuthenticationMethod(SmtpClient::AuthenticationMethodPlain);
} else if(device->paramValue(customMailDeviceAuthenticationParamTypeId).toString() == "LOGIN") {
smtpClient->setAuthenticationMethod(SmtpClient::AuthenticationMethodLogin);
} else {
return Device::DeviceSetupStatusFailure;
}
if(device->paramValue(customMailDeviceEncryptionParamTypeId).toString() == "NONE") {
@ -64,45 +80,64 @@ Device::DeviceSetupStatus DevicePluginMailNotification::setupDevice(Device *devi
smtpClient->setEncryptionType(SmtpClient::EncryptionTypeSSL);
} else if(device->paramValue(customMailDeviceEncryptionParamTypeId).toString() == "TLS") {
smtpClient->setEncryptionType(SmtpClient::EncryptionTypeTLS);
} else {
return Device::DeviceSetupStatusFailure;
}
QString recipientsString = device->paramValue(customMailDeviceCustomRecipientParamTypeId).toString();
QString recipientsString = device->paramValue(customMailDeviceRecipientParamTypeId).toString();
QStringList recipients = recipientsString.split(",");
smtpClient->setRecipients(recipients);
smtpClient->setSender(device->paramValue(customMailDeviceCustomSenderParamTypeId).toString());
connect(smtpClient, &SmtpClient::testLoginFinished, this, &DevicePluginMailNotification::testLoginFinished);
connect(smtpClient, &SmtpClient::sendMailFinished, this, &DevicePluginMailNotification::sendMailFinished);
m_clients.insert(smtpClient,device);
smtpClient->setSender(device->paramValue(customMailDeviceSenderParamTypeId).toString());
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(action.actionTypeId() == customMailNotifyActionTypeId) {
SmtpClient *smtpClient = m_clients.key(device);
if (!smtpClient) {
qCWarning(dcMailNotification()) << "Could not find SMTP client for " << device;
return Device::DeviceErrorHardwareNotAvailable;
return info->finish(Device::DeviceErrorHardwareNotAvailable);
}
smtpClient->sendMail(action.param(customMailNotifyActionTitleParamTypeId).value().toString(),
action.param(customMailNotifyActionBodyParamTypeId).value().toString(),
action.id());
return Device::DeviceErrorAsync;
int id = smtpClient->sendMail(action.param(customMailNotifyActionTitleParamTypeId).value().toString(),
action.param(customMailNotifyActionBodyParamTypeId).value().toString());
connect(smtpClient, &SmtpClient::sendMailFinished, info, [info, id](bool success, int resultId){
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)
@ -111,31 +146,3 @@ void DevicePluginMailNotification::deviceRemoved(Device *device)
m_clients.remove(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();
~DevicePluginMailNotification();
Device::DeviceSetupStatus setupDevice(Device *device) override;
Device::DeviceError executeAction(Device *device, const Action &action) override;
void startPairing(DevicePairingInfo *info) 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;
private:
QHash <SmtpClient*, Device*> m_clients;
private slots:
void testLoginFinished(const bool &success);
void sendMailFinished(const bool &success, const ActionId &actionId);
};
#endif // DEVICEPLUGINMAILNOTIFICATION_H

View File

@ -11,34 +11,21 @@
{
"id": "f4844c97-7ca6-4349-904e-ff9749a9fe74",
"name": "customMail",
"displayName": "Custom mail",
"displayName": "E-mail notifications",
"createMethods": [ "user" ],
"setupMethod": "userandpassword",
"interfaces": [ "notifications" ],
"paramTypes": [
{
"id": "af30ce7b-fb6b-42f0-889d-20b32f8b8fa4",
"name": "customSender",
"name": "sender",
"displayName": "Sender mail",
"type": "QString",
"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",
"name": "customRecipient",
"name": "recipient",
"displayName": "Recipient",
"type": "QString",
"inputType": "Mail"

View File

@ -25,8 +25,6 @@
#include <QDateTime>
Q_LOGGING_CATEGORY(dcSmtpClient, "SmtpClient")
SmtpClient::SmtpClient(QObject *parent):
QObject(parent)
{
@ -55,6 +53,7 @@ void SmtpClient::connectToHost()
void SmtpClient::testLogin()
{
qCDebug(dcMailNotification()) << "Starting test login";
m_testLogin = true;
setState(StateInitialize);
m_socket->close();
@ -63,19 +62,19 @@ void SmtpClient::testLogin()
void SmtpClient::connected()
{
qCDebug(dcSmtpClient()) << "Connected";
qCDebug(dcMailNotification()) << "Connected";
}
void SmtpClient::disconnected()
{
qCDebug(dcSmtpClient()) << "Disconnected";
qCDebug(dcMailNotification()) << "Disconnected";
setState(StateIdle);
sendNextMail();
}
void SmtpClient::onEncrypted()
{
qCDebug(dcSmtpClient()) << "Socket encrypted";
qCDebug(dcMailNotification()) << "Socket encrypted";
send("EHLO localhost");
setState(StateAuthentification);
}
@ -86,12 +85,12 @@ void SmtpClient::readData()
QString responseLine;
responseLine = m_socket->readLine();
qCDebug(dcSmtpClient()) << "<--" << responseLine;
qCDebug(dcMailNotification()) << "<--" << responseLine;
bool responseCodeParseSuccess = false;
int responseCode = responseLine.left(3).toInt(&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) {
handleSmtpFailure();
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.subject = subject;
message.body = body;
message.actionId = actionId;
message.id = ids++;
m_messageQueue.enqueue(message);
sendNextMail();
return message.id;
}
void SmtpClient::setHost(const QString &host)
@ -163,12 +164,13 @@ void SmtpClient::setState(SmtpClient::State state)
if (m_state == state)
return;
qCDebug(dcSmtpClient()) << state;
qCDebug(dcMailNotification()) << state;
m_state = state;
}
void SmtpClient::processServerResponse(int responseCode, const QString &response)
{
qCDebug(dcMailNotification()) << "Server response:" << responseCode << response;
switch (m_state) {
case StateIdle:
// 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
if (responseCode == 220) {
if (!m_socket->isEncrypted() && m_encryptionType != EncryptionTypeNone) {
qCDebug(dcSmtpClient()) << "Start client encryption...";
qCDebug(dcMailNotification()) << "Start client encryption...";
m_socket->startClientEncryption();
}
} else {
@ -223,12 +225,12 @@ void SmtpClient::processServerResponse(int responseCode, const QString &response
}
break;
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) != ' ') {
break;
}
if (responseCode == 250) {
if (responseCode == 250 || responseCode == 220) {
if (m_authenticationMethod == AuthenticationMethodLogin) {
send("AUTH LOGIN");
setState(StateUser);
@ -277,6 +279,11 @@ void SmtpClient::processServerResponse(int responseCode, const QString &response
}
break;
case StateTestLoginFinished:
// Ignore server information messages
if (responseCode == 250) {
break;
}
if (responseCode == 235) {
emit testLoginFinished(true);
} else {
@ -286,12 +293,17 @@ void SmtpClient::processServerResponse(int responseCode, const QString &response
m_testLogin = false;
break;
case StateMail:
// Ignore server information messages
if (responseCode == 250) {
break;
}
if (responseCode == 235) {
send("MAIL FROM:<" + m_sender + ">");
// Prepare queue for recipients
m_recipientsQueue.clear();
qCDebug(dcSmtpClient()) << "Prepare recipients list" << m_recipients;
qCDebug(dcMailNotification()) << "Prepare recipients list" << m_recipients;
foreach (const QString &recipient, m_recipients) {
m_recipientsQueue.enqueue(recipient.trimmed());
}
@ -344,7 +356,7 @@ void SmtpClient::processServerResponse(int responseCode, const QString &response
}
if (responseCode == 250) {
emit sendMailFinished(true, m_message.actionId);
emit sendMailFinished(true, m_message.id);
send("QUIT");
setState(StateClose);
} else {
@ -355,7 +367,7 @@ void SmtpClient::processServerResponse(int responseCode, const QString &response
if (responseCode == 221) {
m_socket->close();
} 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
@ -410,7 +422,7 @@ void SmtpClient::handleSmtpFailure()
if (m_testLogin) {
emit testLoginFinished(false);
} else {
emit sendMailFinished(false, m_message.actionId);
emit sendMailFinished(false, m_message.id);
}
// Clean up
@ -438,7 +450,7 @@ void SmtpClient::onSocketError(QAbstractSocket::SocketError error)
void SmtpClient::send(const QString &data)
{
qCDebug(dcSmtpClient()) << "-->" << data;
qCDebug(dcMailNotification()) << "-->" << data;
m_socket->write(data.toUtf8() + "\r\n");
m_socket->flush();
}

View File

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