diff --git a/mailnotification/devicepluginmailnotification.cpp b/mailnotification/devicepluginmailnotification.cpp index e9b84ee1..09336936 100644 --- a/mailnotification/devicepluginmailnotification.cpp +++ b/mailnotification/devicepluginmailnotification.cpp @@ -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(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(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); - } -} diff --git a/mailnotification/devicepluginmailnotification.h b/mailnotification/devicepluginmailnotification.h index baca9578..1b3149d1 100644 --- a/mailnotification/devicepluginmailnotification.h +++ b/mailnotification/devicepluginmailnotification.h @@ -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 m_clients; -private slots: - void testLoginFinished(const bool &success); - void sendMailFinished(const bool &success, const ActionId &actionId); - }; #endif // DEVICEPLUGINMAILNOTIFICATION_H diff --git a/mailnotification/devicepluginmailnotification.json b/mailnotification/devicepluginmailnotification.json index 56ad4833..f5934cec 100644 --- a/mailnotification/devicepluginmailnotification.json +++ b/mailnotification/devicepluginmailnotification.json @@ -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" diff --git a/mailnotification/smtpclient.cpp b/mailnotification/smtpclient.cpp index 4465f3b5..29a05b5b 100644 --- a/mailnotification/smtpclient.cpp +++ b/mailnotification/smtpclient.cpp @@ -25,8 +25,6 @@ #include -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(); } diff --git a/mailnotification/smtpclient.h b/mailnotification/smtpclient.h index 67b4257f..2b717f92 100644 --- a/mailnotification/smtpclient.h +++ b/mailnotification/smtpclient.h @@ -31,14 +31,14 @@ #include #include -#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: