diff --git a/pri/build_opts.pri b/pri/build_opts.pri index bdb683e4a..dd777741f 100644 --- a/pri/build_opts.pri +++ b/pri/build_opts.pri @@ -58,7 +58,7 @@ mac:qtHaveModule(macextras) { win32 { RC_ICONS = ../../resources/graphics/rssguard.ico QMAKE_TARGET_COMPANY = $$APP_AUTHOR - QMAKE_TARGET_DESCRIPTION = $$APP_NAME ($$APP_TYPE) + QMAKE_TARGET_DESCRIPTION = $$APP_NAME QMAKE_TARGET_COPYRIGHT = $$APP_COPYRIGHT QMAKE_TARGET_PRODUCT = $$APP_NAME diff --git a/pri/vars.pri b/pri/vars.pri index 662116e5b..cb9e61fde 100644 --- a/pri/vars.pri +++ b/pri/vars.pri @@ -4,7 +4,7 @@ APP_REVERSE_NAME = "com.github.rssguard" APP_LOW_H_NAME = ".rssguard" APP_AUTHOR = "Martin Rotter" APP_COPYRIGHT = "(C) 2011-2020 $$APP_AUTHOR" -APP_VERSION = "3.7.0" +APP_VERSION = "3.7.1" APP_LONG_NAME = "$$APP_NAME $$APP_VERSION" APP_EMAIL = "rotter.martinos@gmail.com" APP_URL = "https://github.com/martinrotter/rssguard" diff --git a/src/librssguard/miscellaneous/application.cpp b/src/librssguard/miscellaneous/application.cpp index 29cfe240e..dd0ed7f02 100755 --- a/src/librssguard/miscellaneous/application.cpp +++ b/src/librssguard/miscellaneous/application.cpp @@ -523,6 +523,7 @@ void Application::onFeedUpdatesProgress(const Feed* feed, int current, int total void Application::onFeedUpdatesFinished(const FeedDownloadResults& results) { if (!results.updatedFeeds().isEmpty()) { // Now, inform about results via GUI message/notification. - qApp->showGuiMessage(tr("New messages downloaded"), results.overview(10), QSystemTrayIcon::NoIcon, nullptr, false); + qApp->showGuiMessage(tr("New messages downloaded"), results.overview(10), QSystemTrayIcon::MessageIcon::NoIcon, + nullptr, false); } } diff --git a/src/librssguard/services/gmail/definitions.h b/src/librssguard/services/gmail/definitions.h index 828375e1d..e5e05696d 100644 --- a/src/librssguard/services/gmail/definitions.h +++ b/src/librssguard/services/gmail/definitions.h @@ -7,6 +7,7 @@ #define GMAIL_OAUTH_TOKEN_URL "https://accounts.google.com/o/oauth2/token" #define GMAIL_OAUTH_SCOPE "https://mail.google.com/" +#define GMAIL_API_SEND_MESSAGE "https://www.googleapis.com/upload/gmail/v1/users/me/messages/send?uploadType=multipart" #define GMAIL_API_BATCH_UPD_LABELS "https://www.googleapis.com/gmail/v1/users/me/messages/batchModify" #define GMAIL_API_GET_ATTACHMENT "https://www.googleapis.com/gmail/v1/users/me/messages/%1/attachments/%2" #define GMAIL_API_LABELS_LIST "https://www.googleapis.com/gmail/v1/users/me/labels" diff --git a/src/librssguard/services/gmail/gmailserviceroot.cpp b/src/librssguard/services/gmail/gmailserviceroot.cpp index 9863439de..321bc94d0 100644 --- a/src/librssguard/services/gmail/gmailserviceroot.cpp +++ b/src/librssguard/services/gmail/gmailserviceroot.cpp @@ -33,7 +33,7 @@ GmailServiceRoot::GmailServiceRoot(GmailNetworkFactory* network, RootItem* paren GmailServiceRoot::~GmailServiceRoot() = default; void GmailServiceRoot::updateTitle() { - setTitle(m_network->userName() + QSL(" (Gmail)")); + setTitle(m_network->username() + QSL(" (Gmail)")); } RootItem* GmailServiceRoot::obtainNewTreeForSyncIn() const { @@ -78,7 +78,7 @@ void GmailServiceRoot::saveAccountDataToDatabase() { QSqlDatabase database = qApp->database()->connection(metaObject()->className()); if (accountId() != NO_PARENT_CATEGORY) { - if (DatabaseQueries::overwriteGmailAccount(database, m_network->userName(), + if (DatabaseQueries::overwriteGmailAccount(database, m_network->username(), m_network->oauth()->clientId(), m_network->oauth()->clientSecret(), m_network->oauth()->redirectUrl(), @@ -95,7 +95,7 @@ void GmailServiceRoot::saveAccountDataToDatabase() { if (saved) { if (DatabaseQueries::createGmailAccount(database, id_to_assign, - m_network->userName(), + m_network->username(), m_network->oauth()->clientId(), m_network->oauth()->clientSecret(), m_network->oauth()->redirectUrl(), diff --git a/src/librssguard/services/gmail/gui/emailrecipientcontrol.cpp b/src/librssguard/services/gmail/gui/emailrecipientcontrol.cpp index 2ea9f84e0..4debf41dc 100644 --- a/src/librssguard/services/gmail/gui/emailrecipientcontrol.cpp +++ b/src/librssguard/services/gmail/gui/emailrecipientcontrol.cpp @@ -35,3 +35,11 @@ EmailRecipientControl::EmailRecipientControl(const QString& recipient, QWidget* setLayout(lay); } + +QString EmailRecipientControl::recipientAddress() const { + return m_txtRecipient->text(); +} + +RecipientType EmailRecipientControl::recipientType() const { + return RecipientType(m_cmbRecipientType->currentData(Qt::ItemDataRole::UserRole).toInt()); +} diff --git a/src/librssguard/services/gmail/gui/emailrecipientcontrol.h b/src/librssguard/services/gmail/gui/emailrecipientcontrol.h index 4eeed1ee1..3431035a9 100644 --- a/src/librssguard/services/gmail/gui/emailrecipientcontrol.h +++ b/src/librssguard/services/gmail/gui/emailrecipientcontrol.h @@ -5,6 +5,8 @@ #include +#include "services/gmail/definitions.h" + class QComboBox; class QLineEdit; class PlainToolButton; @@ -15,6 +17,10 @@ class EmailRecipientControl : public QWidget { public: explicit EmailRecipientControl(const QString& recipient, QWidget* parent = nullptr); + public: + QString recipientAddress() const; + RecipientType recipientType() const; + signals: void removalRequested(); diff --git a/src/librssguard/services/gmail/gui/formaddeditemail.cpp b/src/librssguard/services/gmail/gui/formaddeditemail.cpp index 5ec1ce261..74d0f1b73 100644 --- a/src/librssguard/services/gmail/gui/formaddeditemail.cpp +++ b/src/librssguard/services/gmail/gui/formaddeditemail.cpp @@ -2,11 +2,15 @@ #include "services/gmail/gui/formaddeditemail.h" +#include "3rd-party/mimesis/mimesis.hpp" +#include "exceptions/applicationexception.h" #include "gui/guiutilities.h" +#include "gui/messagebox.h" #include "miscellaneous/application.h" #include "miscellaneous/iconfactory.h" #include "services/gmail/gmailserviceroot.h" #include "services/gmail/gui/emailrecipientcontrol.h" +#include "services/gmail/network/gmailnetworkfactory.h" FormAddEditEmail::FormAddEditEmail(GmailServiceRoot* root, QWidget* parent) : QDialog(parent), m_root(root) { m_ui.setupUi(this); @@ -22,6 +26,11 @@ FormAddEditEmail::FormAddEditEmail(GmailServiceRoot* root, QWidget* parent) : QD connect(m_ui.m_btnAdder, &PlainToolButton::clicked, this, [=]() { addRecipientRow(); }); + + connect(m_ui.m_buttonBox->button(QDialogButtonBox::StandardButton::Ok), + &QPushButton::clicked, + this, + &FormAddEditEmail::onOkClicked); } void FormAddEditEmail::execForAdd() { @@ -38,10 +47,95 @@ void FormAddEditEmail::removeRecipientRow() { sndr->deleteLater(); } +void FormAddEditEmail::onOkClicked() { + Mimesis::Message msg; + auto username = m_root->network()->username(); + + if (!username.endsWith(QSL("@gmail.com"))) { + username += QSL("@gmail.com"); + } + + msg["From"] = username.toStdString(); + + auto recipients = recipientControls(); + QStringList rec_to, rec_cc, rec_bcc, rec_repl; + + for (EmailRecipientControl* ctrl : recipients) { + switch (ctrl->recipientType()) { + case RecipientType::Cc: + rec_cc << ctrl->recipientAddress(); + break; + + case RecipientType::To: + rec_to << ctrl->recipientAddress(); + break; + + case RecipientType::Bcc: + rec_bcc << ctrl->recipientAddress(); + break; + + case RecipientType::ReplyTo: + rec_repl << ctrl->recipientAddress(); + break; + } + } + + if (!rec_cc.isEmpty()) { + msg["Cc"] = rec_cc.join(',').toStdString(); + } + + if (!rec_to.isEmpty()) { + msg["To"] = rec_to.join(',').toStdString(); + } + + if (!rec_bcc.isEmpty()) { + msg["Bcc"] = rec_bcc.join(',').toStdString(); + } + + if (!rec_repl.isEmpty()) { + msg["Reply-To"] = rec_repl.join(',').toStdString(); + } + + msg["Subject"] = m_ui.m_txtSubject->text().toStdString(); + msg.set_plain(m_ui.m_txtMessage->toPlainText().toStdString()); + + if (m_originalMessage == nullptr) { + // Send completely new message. + } + else { + // TODO: Reply to existing message. + } + + try { + m_root->network()->sendEmail(msg); + accept(); + } + catch (const ApplicationException& ex) { + MessageBox::show(this, QMessageBox::Icon::Critical, + tr("E-mail NOT sent"), tr("Your e-mail message wasn't sent."), + QString(), + ex.message()); + } +} + void FormAddEditEmail::addRecipientRow(const QString& recipient) { auto* mail_rec = new EmailRecipientControl(recipient, this); connect(mail_rec, &EmailRecipientControl::removalRequested, this, &FormAddEditEmail::removeRecipientRow); - m_ui.m_layout->insertRow(m_ui.m_layout->indexOf(m_ui.m_txtMessage) - 1, mail_rec); + m_ui.m_layout->insertRow(m_ui.m_layout->count() - 5, mail_rec); +} + +QList FormAddEditEmail::recipientControls() const { + QList list; + + for (int i = 0; i < m_ui.m_layout->count(); i++) { + auto* wdg = qobject_cast(m_ui.m_layout->itemAt(i)->widget()); + + if (wdg != nullptr) { + list.append(wdg); + } + } + + return list; } diff --git a/src/librssguard/services/gmail/gui/formaddeditemail.h b/src/librssguard/services/gmail/gui/formaddeditemail.h index 3dbf28ad6..854353aea 100644 --- a/src/librssguard/services/gmail/gui/formaddeditemail.h +++ b/src/librssguard/services/gmail/gui/formaddeditemail.h @@ -12,6 +12,7 @@ namespace Ui { } class GmailServiceRoot; +class Message; class EmailRecipientControl; class FormAddEditEmail : public QDialog { @@ -25,13 +26,18 @@ class FormAddEditEmail : public QDialog { private slots: void removeRecipientRow(); + void onOkClicked(); void addRecipientRow(const QString& recipient = QString()); + private: + QList recipientControls() const; + private: GmailServiceRoot* m_root; Ui::FormAddEditEmail m_ui; QList m_recipientControls; + Message* m_originalMessage; }; #endif // FORMADDEDITEMAIL_H diff --git a/src/librssguard/services/gmail/gui/formaddeditemail.ui b/src/librssguard/services/gmail/gui/formaddeditemail.ui index 5216e45ac..65f44e610 100644 --- a/src/librssguard/services/gmail/gui/formaddeditemail.ui +++ b/src/librssguard/services/gmail/gui/formaddeditemail.ui @@ -6,27 +6,37 @@ 0 0 - 552 - 491 + 423 + 310 Write e-mail message - - - - From - - - - - - - Name and address of this e-mail message sender - - + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + ... + + + + @@ -51,29 +61,22 @@ - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - ... - - - - + + + + Subject + + + m_txtSubject + + + + + + + Title of your message + + @@ -84,24 +87,13 @@
plaintoolbutton.h
+ + m_btnAdder + m_txtSubject + m_txtMessage + - - m_buttonBox - accepted() - FormAddEditEmail - accept() - - - 248 - 254 - - - 157 - 274 - - - m_buttonBox rejected() diff --git a/src/librssguard/services/gmail/gui/formeditgmailaccount.cpp b/src/librssguard/services/gmail/gui/formeditgmailaccount.cpp index 46b85c593..f24fa3db9 100644 --- a/src/librssguard/services/gmail/gui/formeditgmailaccount.cpp +++ b/src/librssguard/services/gmail/gui/formeditgmailaccount.cpp @@ -170,7 +170,7 @@ void FormEditGmailAccount::execForEdit(GmailServiceRoot* existing_root) { m_ui.m_txtAppKey->lineEdit()->setText(existing_root->network()->oauth()->clientSecret()); m_ui.m_txtRedirectUrl->lineEdit()->setText(existing_root->network()->oauth()->redirectUrl()); - m_ui.m_txtUsername->lineEdit()->setText(existing_root->network()->userName()); + m_ui.m_txtUsername->lineEdit()->setText(existing_root->network()->username()); m_ui.m_spinLimitMessages->setValue(existing_root->network()->batchSize()); exec(); diff --git a/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp b/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp index dac5a4cee..67f9f991c 100644 --- a/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp +++ b/src/librssguard/services/gmail/network/gmailnetworkfactory.cpp @@ -3,6 +3,7 @@ #include "services/gmail/network/gmailnetworkfactory.h" #include "definitions/definitions.h" +#include "exceptions/applicationexception.h" #include "gui/dialogs/formmain.h" #include "gui/tabwidget.h" #include "miscellaneous/application.h" @@ -39,7 +40,7 @@ OAuth2Service* GmailNetworkFactory::oauth() const { return m_oauth2; } -QString GmailNetworkFactory::userName() const { +QString GmailNetworkFactory::username() const { return m_username; } @@ -51,6 +52,27 @@ void GmailNetworkFactory::setBatchSize(int batch_size) { m_batchSize = batch_size; } +void GmailNetworkFactory::sendEmail(const Mimesis::Message& msg) { + QString bearer = m_oauth2->bearer().toLocal8Bit(); + + if (bearer.isEmpty()) { + throw ApplicationException(tr("you aren't logged in")); + } + + QString rfc_email = QString::fromStdString(msg.to_string()); + QString json = QSL("{\"raw\": \"%1\"}").arg(QString(rfc_email.toUtf8().toBase64(QByteArray::Base64Option::Base64UrlEncoding))); + QByteArray input_data = json.toUtf8(); + QList> headers; + QByteArray out; + auto xx = NetworkFactory::performNetworkOperation(GMAIL_API_SEND_MESSAGE, + DOWNLOAD_TIMEOUT, + input_data, + out, + QNetworkAccessManager::Operation::PostOperation, + headers); + int a = 5; +} + void GmailNetworkFactory::initializeOauth() { connect(m_oauth2, &OAuth2Service::tokensRetrieveError, this, &GmailNetworkFactory::onTokensError); connect(m_oauth2, &OAuth2Service::authFailed, this, &GmailNetworkFactory::onAuthFailed); diff --git a/src/librssguard/services/gmail/network/gmailnetworkfactory.h b/src/librssguard/services/gmail/network/gmailnetworkfactory.h index f6f207e8d..8d791dc03 100644 --- a/src/librssguard/services/gmail/network/gmailnetworkfactory.h +++ b/src/librssguard/services/gmail/network/gmailnetworkfactory.h @@ -7,6 +7,7 @@ #include "core/message.h" +#include "3rd-party/mimesis/mimesis.hpp" #include "services/abstract/feed.h" #include "services/abstract/rootitem.h" @@ -27,17 +28,14 @@ class GmailNetworkFactory : public QObject { OAuth2Service* oauth() const; - QString userName() const; + QString username() const; void setUsername(const QString& username); // Gets/sets the amount of messages to obtain during single feed update. int batchSize() const; void setBatchSize(int batch_size); - // Returns tree of feeds/categories. - // Top-level root of the tree is not needed here. - // Returned items do not have primary IDs assigned. - //RootItem* feedsCategories(); + void sendEmail(const Mimesis::Message& msg); Downloader* downloadAttachment(const QString& msg_id, const QString& attachment_id);