diff options
author | Saturneric <[email protected]> | 2022-01-02 23:40:04 +0000 |
---|---|---|
committer | Saturneric <[email protected]> | 2022-01-02 23:40:04 +0000 |
commit | 586b7a5211124bed6011ac71e9be51c26a542865 (patch) | |
tree | 92b9d81b6f76b2ca127221db39f9edb27e4f70cf | |
parent | <refactor>(ui): take operations apart from key details. (diff) | |
download | GpgFrontend-586b7a5211124bed6011ac71e9be51c26a542865.tar.gz GpgFrontend-586b7a5211124bed6011ac71e9be51c26a542865.zip |
<refactor>(ui): Enhanced sending email function.
-rw-r--r-- | src/ui/GpgFrontendUI.h | 6 | ||||
-rw-r--r-- | src/ui/MainWindow.cpp | 2 | ||||
-rw-r--r-- | src/ui/function/SMTPSendMailThread.cpp | 118 | ||||
-rw-r--r-- | src/ui/function/SMTPSendMailThread.h | 21 | ||||
-rw-r--r-- | src/ui/function/SMTPTestThread.cpp | 3 | ||||
-rw-r--r-- | src/ui/function/SMTPTestThread.h | 7 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowUI.cpp | 4 | ||||
-rw-r--r-- | src/ui/settings/SettingsKeyServer.cpp | 1 | ||||
-rw-r--r-- | src/ui/smtp/EmailListEditor.cpp | 102 | ||||
-rw-r--r-- | src/ui/smtp/EmailListEditor.h | 54 | ||||
-rw-r--r-- | src/ui/smtp/RecipientsPicker.cpp | 76 | ||||
-rw-r--r-- | src/ui/smtp/RecipientsPicker.h | 49 | ||||
-rw-r--r-- | src/ui/smtp/SendMailDialog.cpp | 249 | ||||
-rw-r--r-- | src/ui/smtp/SendMailDialog.h | 26 | ||||
-rw-r--r-- | src/ui/smtp/SenderPicker.cpp | 76 | ||||
-rw-r--r-- | src/ui/smtp/SenderPicker.h | 47 | ||||
-rw-r--r-- | src/ui/widgets/KeyList.cpp | 55 | ||||
-rw-r--r-- | src/ui/widgets/KeyList.h | 7 | ||||
-rw-r--r-- | src/ui/widgets/SignersPicker.cpp | 30 | ||||
-rw-r--r-- | src/ui/widgets/SignersPicker.h | 8 | ||||
m--------- | third_party/AppImageUpdate | 0 | ||||
-rw-r--r-- | ui/EmailListEditor.ui | 70 | ||||
-rw-r--r-- | ui/SendMailDialog.ui | 208 |
23 files changed, 1070 insertions, 149 deletions
diff --git a/src/ui/GpgFrontendUI.h b/src/ui/GpgFrontendUI.h index 01f82822..90e15324 100644 --- a/src/ui/GpgFrontendUI.h +++ b/src/ui/GpgFrontendUI.h @@ -25,13 +25,15 @@ #ifndef GPGFRONTEND_GPGFRONTENDUI_H #define GPGFRONTEND_GPGFRONTENDUI_H -#include "GpgFrontend.h" - #include <QtCore> #include <QtNetwork> #include <QtPrintSupport> #include <QtWidgets> +#include "GpgFrontend.h" +#include "gpg/GpgConstants.h" +#include "gpg/GpgModel.h" + #undef LIBCONFIGXX_STATIC #define LIBCONFIGXX_STATIC #include <libconfig.h++> diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp index 0411be81..422db814 100644 --- a/src/ui/MainWindow.cpp +++ b/src/ui/MainWindow.cpp @@ -296,7 +296,7 @@ void MainWindow::restoreSettings() { LOG(INFO) << "get checked key id" << key_id; key_ids_ptr->push_back(key_id); } - mKeyList->setChecked(key_ids_ptr); + mKeyList->setChecked(std::move(key_ids_ptr)); } auto& smtp = settings["smtp"]; diff --git a/src/ui/function/SMTPSendMailThread.cpp b/src/ui/function/SMTPSendMailThread.cpp index 94e97749..3e5ce9bc 100644 --- a/src/ui/function/SMTPSendMailThread.cpp +++ b/src/ui/function/SMTPSendMailThread.cpp @@ -24,6 +24,14 @@ #include "SMTPSendMailThread.h" +#include <boost/format.hpp> + +#include "gpg/function/BasicOperator.h" +#include "gpg/function/GpgKeyGetter.h" +#include "gpg/function/GpgKeyImportExporter.h" + +namespace GpgFrontend::UI { + void SMTPSendMailThread::run() { SmtpClient smtp(host_.c_str(), port_, connection_type_); @@ -32,6 +40,95 @@ void SMTPSendMailThread::run() { smtp.setPassword(password_.c_str()); } + if (encrypt_content_ && public_key_ids_ != nullptr && + !public_key_ids_->empty()) { + message.getContent().setContentType( + "multipart/encrypted; micalg=pgp-md5; " + "protocol=\"application/pgp-encrypted\""); + } + + if (attach_signature_file_ && !private_key_id_.empty()) { + message.getContent().setContentType( + "multipart/signed; micalg=pgp-md5; " + "protocol=\"application/pgp-signature\""); + } + + int index = 0; + for (auto& text : texts_) { + const auto plain_text = text->getText().toStdString(); + // encrypt + if (encrypt_content_ && public_key_ids_ != nullptr && + !public_key_ids_->empty()) { + ByteArrayPtr out_buffer = nullptr; + GpgEncrResult result; + auto in_buffer = std::make_unique<ByteArray>(plain_text); + auto keys = GpgKeyGetter::GetInstance().GetKeys(public_key_ids_); + auto err = BasicOperator::GetInstance().Encrypt( + std::move(keys), *in_buffer, out_buffer, result); + + if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) { + emit signalSMTPResult("Fail to encrypt with gpg keys"); + return; + } + text->setText(out_buffer->c_str()); + } + + send_texts_.push_back(std::move(text)); + + // sign + if (attach_signature_file_ && !private_key_id_.empty()) { + ByteArrayPtr out_buffer = nullptr; + GpgSignResult result; + + auto& plain_mime_text = send_texts_.back(); + auto in_buffer = + std::make_unique<ByteArray>(plain_mime_text->getText().toStdString()); + auto key = GpgKeyGetter::GetInstance().GetKey(private_key_id_); + auto keys = std::make_unique<KeyArgsList>(); + keys->push_back(std::move(key)); + + auto err = BasicOperator::GetInstance().Sign( + std::move(keys), *in_buffer, out_buffer, GPGME_SIG_MODE_DETACH, + result); + + if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR) { + emit signalSMTPResult("Fail to sign with gpg keys"); + return; + } + + auto sign_content_name = + boost::format("%1%_sign_%2%.asc") % private_key_id_ % index++; + + // Add MIME + send_texts_.push_back(std::make_unique<MimeText>(out_buffer->c_str())); + auto& sig_text = send_texts_.back(); + sig_text->setContentType("application/pgp-signature"); + sig_text->setEncoding(MimePart::_7Bit); + sig_text->setContentName(sign_content_name.str().c_str()); + } + } + + if (attach_public_key_file_ && !attached_public_key_ids_.empty()) { + auto key = GpgKeyGetter::GetInstance().GetKey(attached_public_key_ids_); + ByteArrayPtr out_buffer = nullptr; + GpgKeyImportExporter::GetInstance().ExportKey(key, out_buffer); + + auto public_key_file_name = + boost::format("%1%_pubkey.asc") % attached_public_key_ids_; + addFileContent(public_key_file_name.str().c_str(), out_buffer->c_str()); + auto& key_file = files_.back(); + key_file->setEncoding(MimePart::_7Bit); + key_file->setContentType("application/pgp-keys"); + } + + for (const auto& text : send_texts_) { + message.addPart(text.get()); + } + + for (const auto& file : files_) { + message.addPart(file.get()); + } + // Now we can send the mail if (!smtp.connectToHost()) { emit signalSMTPResult("Fail to connect SMTP server"); @@ -77,12 +174,29 @@ void SMTPSendMailThread::setSender(const QString& sender) { void SMTPSendMailThread::addTextContent(const QString& content) { auto text = std::make_unique<MimeText>(content); texts_.push_back(std::move(text)); - message.addPart(texts_.back().get()); } void SMTPSendMailThread::addFileContent(const QString& file_name, const QByteArray& content) { auto file = std::make_unique<MimeFile>(content, file_name); files_.push_back(std::move(file)); - message.addPart(files_.back().get()); } + +void SMTPSendMailThread::setEncryptContent( + bool encrypt_content, GpgFrontend::KeyIdArgsListPtr public_key_ids) { + this->encrypt_content_ = encrypt_content; + this->public_key_ids_ = std::move(public_key_ids); +} + +void SMTPSendMailThread::setAttachSignatureFile( + bool attach_signature_file, GpgFrontend::KeyId private_key_id) { + this->attach_signature_file_ = attach_signature_file; + this->private_key_id_ = std::move(private_key_id); +} + +void SMTPSendMailThread::setAttachPublicKey( + bool attach_public_key_file, GpgFrontend::KeyId attached_public_key_ids) { + this->attach_public_key_file_ = attach_public_key_file; + this->attached_public_key_ids_ = std::move(attached_public_key_ids); +} +} // namespace GpgFrontend::UI diff --git a/src/ui/function/SMTPSendMailThread.h b/src/ui/function/SMTPSendMailThread.h index ff417f5d..e5c9e27f 100644 --- a/src/ui/function/SMTPSendMailThread.h +++ b/src/ui/function/SMTPSendMailThread.h @@ -33,6 +33,7 @@ #include "ui/GpgFrontendUI.h" +namespace GpgFrontend::UI { class SMTPSendMailThread : public QThread { Q_OBJECT public: @@ -62,6 +63,15 @@ class SMTPSendMailThread : public QThread { void addFileContent(const QString& file_name, const QByteArray& content); + void setEncryptContent(bool encrypt_content, + GpgFrontend::KeyIdArgsListPtr public_key_ids); + + void setAttachSignatureFile(bool attach_signature_file, + GpgFrontend::KeyId private_key_id); + + void setAttachPublicKey(bool attach_public_key_file, + GpgFrontend::KeyId attached_public_key_ids); + signals: void signalSMTPResult(const QString& result); @@ -69,6 +79,7 @@ class SMTPSendMailThread : public QThread { void run() override; private: + // SMTP Options std::string host_; int port_; SmtpClient::ConnectionType connection_type_; @@ -79,7 +90,17 @@ class SMTPSendMailThread : public QThread { MimeMessage message; std::vector<std::unique_ptr<MimeText>> texts_; + std::vector<std::unique_ptr<MimeText>> send_texts_; std::vector<std::unique_ptr<MimeFile>> files_; + + // GPG Options + bool encrypt_content_ = false; + GpgFrontend::KeyIdArgsListPtr public_key_ids_; + bool attach_signature_file_ = false; + GpgFrontend::KeyId private_key_id_; + bool attach_public_key_file_ = false; + GpgFrontend::KeyId attached_public_key_ids_; }; +} // namespace GpgFrontend::UI #endif // GPGFRONTEND_SMTPSENDMAILTHREAD_H diff --git a/src/ui/function/SMTPTestThread.cpp b/src/ui/function/SMTPTestThread.cpp index 63c41a90..0eb267f2 100644 --- a/src/ui/function/SMTPTestThread.cpp +++ b/src/ui/function/SMTPTestThread.cpp @@ -23,6 +23,7 @@ */ #include "SMTPTestThread.h" +namespace GpgFrontend::UI { void SMTPTestThread::run() { SmtpClient smtp(host_.c_str(), port_, connection_type_); @@ -41,3 +42,5 @@ void SMTPTestThread::run() { smtp.quit(); emit signalSMTPTestResult("Succeed in testing connection"); } + +} // namespace GpgFrontend::UI diff --git a/src/ui/function/SMTPTestThread.h b/src/ui/function/SMTPTestThread.h index e2f2048d..db61d97d 100644 --- a/src/ui/function/SMTPTestThread.h +++ b/src/ui/function/SMTPTestThread.h @@ -32,6 +32,7 @@ #endif #include "ui/GpgFrontendUI.h" +namespace GpgFrontend::UI { class SMTPTestThread : public QThread { Q_OBJECT @@ -46,9 +47,7 @@ class SMTPTestThread : public QThread { connection_type_(connection_type), identify_(identify), username_(std::move(username)), - password_(std::move(password)) { - - } + password_(std::move(password)) {} signals: void signalSMTPTestResult(const QString& result); @@ -66,4 +65,6 @@ class SMTPTestThread : public QThread { std::string password_; }; +} // namespace GpgFrontend::UI + #endif // GPGFRONTEND_SMTPTESTTHREAD_H diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp index 0c557d16..aeed1326 100644 --- a/src/ui/main_window/MainWindowUI.cpp +++ b/src/ui/main_window/MainWindowUI.cpp @@ -258,7 +258,7 @@ void MainWindow::createActions() { /* Popup-Menu-Action for KeyList */ appendSelectedKeysAct = - new QAction(_("Append Selected Key(s) To Text"), this); + new QAction(_("Append Public Key To Text Editor"), this); appendSelectedKeysAct->setToolTip( _("Append The Selected Keys To Text in Editor")); connect(appendSelectedKeysAct, SIGNAL(triggered()), this, @@ -297,7 +297,7 @@ void MainWindow::createActions() { connect(addPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotAddPgpHeader())); #ifdef SMTP_SUPPORT - sendMailAct = new QAction(_("Send An Email"), this); + sendMailAct = new QAction(_("New Message"), this); sendMailAct->setIcon(QIcon(":email.png")); connect(sendMailAct, &QAction::triggered, this, [=]() { auto* dialog = new SendMailDialog({}, this); diff --git a/src/ui/settings/SettingsKeyServer.cpp b/src/ui/settings/SettingsKeyServer.cpp index 1d520e35..db27e003 100644 --- a/src/ui/settings/SettingsKeyServer.cpp +++ b/src/ui/settings/SettingsKeyServer.cpp @@ -95,6 +95,7 @@ KeyserverTab::KeyserverTab(QWidget* parent) const auto item = ui->keyServerListTable->item(i, 1); if (!item->isSelected()) continue; this->keyServerStrList.removeAt(i); + break; } this->refreshTable(); }); diff --git a/src/ui/smtp/EmailListEditor.cpp b/src/ui/smtp/EmailListEditor.cpp new file mode 100644 index 00000000..49399f11 --- /dev/null +++ b/src/ui/smtp/EmailListEditor.cpp @@ -0,0 +1,102 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "EmailListEditor.h" + +#include "ui_EmailListEditor.h" + +GpgFrontend::UI::EmailListEditor::EmailListEditor(const QString& email_list, + QWidget* parent) + : QDialog(parent), ui(std::make_shared<Ui_EmailListEditorDialog>()) { + ui->setupUi(this); + + QStringList email_string_list = email_list.split(';'); + + if (!email_string_list.isEmpty()) { + for (const auto& recipient : email_string_list) { + auto _recipient = recipient.trimmed(); + if (check_email_address(_recipient)) { + auto item = new QListWidgetItem(_recipient); + ui->emaillistWidget->addItem(item); + item->setFlags(item->flags() | Qt::ItemIsEditable); + } + } + } + + connect(ui->addEmailAddressButton, &QPushButton::clicked, this, [=]() { + auto item = new QListWidgetItem("new email address"); + ui->emaillistWidget->addItem(item); + item->setFlags(item->flags() | Qt::ItemIsEditable); + }); + + connect( + ui->actionDelete_Selected_Email_Address, &QAction::triggered, this, + [=]() { + const auto row_size = ui->emaillistWidget->count(); + for (int i = 0; i < row_size; i++) { + auto item = ui->emaillistWidget->item(i); + if (!item->isSelected()) continue; + delete ui->emaillistWidget->takeItem(ui->emaillistWidget->row(item)); + break; + } + }); + + ui->titleLabel->setText(_("Email List:")); + ui->tipsLabel->setText( + _("Tips: You can double-click the email address in the edit list, or " + "click the email to pop up the option menu.")); + ui->addEmailAddressButton->setText(_("Add An Email Address")); + this->setWindowTitle(_("Email List Editor")); + ui->actionDelete_Selected_Email_Address->setText(_("Delete")); + + popupMenu = new QMenu(this); + popupMenu->addAction(ui->actionDelete_Selected_Email_Address); + + this->exec(); +} + +bool GpgFrontend::UI::EmailListEditor::check_email_address( + const QString& email_address) { + return re_email.match(email_address).hasMatch(); +} + +QString GpgFrontend::UI::EmailListEditor::getEmailList() { + QString email_list; + for (int i = 0; i < ui->emaillistWidget->count(); ++i) { + QListWidgetItem* item = ui->emaillistWidget->item(i); + if (check_email_address(item->text())) { + email_list.append(item->text()); + email_list.append("; "); + } + } + return email_list; +} + +void GpgFrontend::UI::EmailListEditor::contextMenuEvent( + QContextMenuEvent* event) { + QWidget::contextMenuEvent(event); + if (ui->emaillistWidget->selectedItems().length() > 0) { + popupMenu->exec(event->globalPos()); + } +} diff --git a/src/ui/smtp/EmailListEditor.h b/src/ui/smtp/EmailListEditor.h new file mode 100644 index 00000000..d4e476a4 --- /dev/null +++ b/src/ui/smtp/EmailListEditor.h @@ -0,0 +1,54 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_EMAILLISTEDITOR_H +#define GPGFRONTEND_EMAILLISTEDITOR_H + +#include "GpgFrontendUI.h" + +class Ui_EmailListEditorDialog; + +namespace GpgFrontend::UI { +class EmailListEditor : public QDialog { + Q_OBJECT + + public: + explicit EmailListEditor(const QString& email_list, QWidget* parent); + QString getEmailList(); + + private: + std::shared_ptr<Ui_EmailListEditorDialog> ui; + QMenu* popupMenu{}; + + QRegularExpression re_email{ + R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"}; + + bool check_email_address(const QString& email_address); + + protected: + void contextMenuEvent(QContextMenuEvent* event) override; +}; +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_EMAILLISTEDITOR_H diff --git a/src/ui/smtp/RecipientsPicker.cpp b/src/ui/smtp/RecipientsPicker.cpp new file mode 100644 index 00000000..ee6ac673 --- /dev/null +++ b/src/ui/smtp/RecipientsPicker.cpp @@ -0,0 +1,76 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "RecipientsPicker.h" + +#include "ui/widgets/KeyList.h" + +GpgFrontend::UI::RecipientsPicker::RecipientsPicker( + const GpgFrontend::KeyIdArgsListPtr& current_key_ids, QWidget* parent) + : QDialog(parent) { + auto confirm_button = new QPushButton(_("Confirm")); + connect(confirm_button, SIGNAL(clicked(bool)), this, SLOT(accept())); + + // Setup KeyList + key_list_ = new KeyList(false, this); + key_list_->addListGroupTab( + _("Recipient(s)"), KeyListRow::SECRET_OR_PUBLIC_KEY, + KeyListColumn::NAME | KeyListColumn::EmailAddress, + [](const GpgKey& key) -> bool { + return !key.is_private_key() && key.CanEncrActual(); + }); + key_list_->slotRefresh(); + + auto key_ids = std::make_unique<GpgFrontend::KeyIdArgsList>(); + for (const auto& key_id : *current_key_ids) { + key_ids->push_back(key_id); + } + key_list_->setChecked(std::move(key_ids)); + + auto* vbox2 = new QVBoxLayout(); + vbox2->addWidget(new QLabel(QString(_("Select Recipient(s)")) + ": ")); + vbox2->addWidget(key_list_); + vbox2->addWidget(new QLabel( + QString(_("We use the public key provided by the recipient to encrypt " + "the text.")) + + "\n" + + _("If you want to send to multiple recipients at the same time, you can " + "select multiple keys."))); + vbox2->addWidget(confirm_button); + vbox2->addStretch(0); + setLayout(vbox2); + + this->setWindowFlags(Qt::Window | Qt::WindowTitleHint | + Qt::CustomizeWindowHint); + + this->setModal(true); + this->setWindowTitle("Recipient(s) Picker"); + this->setMinimumWidth(480); + this->exec(); +} + +GpgFrontend::KeyIdArgsListPtr +GpgFrontend::UI::RecipientsPicker::getCheckedRecipients() { + return key_list_->getChecked(); +} diff --git a/src/ui/smtp/RecipientsPicker.h b/src/ui/smtp/RecipientsPicker.h new file mode 100644 index 00000000..bf128149 --- /dev/null +++ b/src/ui/smtp/RecipientsPicker.h @@ -0,0 +1,49 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_RECIPENTSPICKER_H +#define GPGFRONTEND_RECIPENTSPICKER_H + +#include "GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class KeyList; + +class RecipientsPicker : public QDialog { + Q_OBJECT + + public: + explicit RecipientsPicker( + const GpgFrontend::KeyIdArgsListPtr& current_key_ids, + QWidget* parent = nullptr); + + GpgFrontend::KeyIdArgsListPtr getCheckedRecipients(); + + private: + KeyList* key_list_; +}; +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_RECIPENTSPICKER_H diff --git a/src/ui/smtp/SendMailDialog.cpp b/src/ui/smtp/SendMailDialog.cpp index 66bfc546..3c98dab5 100644 --- a/src/ui/smtp/SendMailDialog.cpp +++ b/src/ui/smtp/SendMailDialog.cpp @@ -24,12 +24,15 @@ #include "SendMailDialog.h" -#include <utility> - +#include "gpg/function/GpgKeyGetter.h" +#include "ui/smtp/EmailListEditor.h" +#include "ui/smtp/RecipientsPicker.h" +#include "ui/smtp/SenderPicker.h" #include "ui_SendMailDialog.h" #ifdef SMTP_SUPPORT #include "smtp/SmtpMime" +#include "ui/function/SMTPSendMailThread.h" #include "ui/settings/GlobalSettingStation.h" #endif @@ -40,7 +43,7 @@ SendMailDialog::SendMailDialog(const QString& text, QWidget* parent) // read from settings initSettings(); - if (smtpAddress.isEmpty()) { + if (smtp_address_.isEmpty()) { QMessageBox::critical( this, _("Incomplete configuration"), _("The SMTP address is empty, please go to the setting interface to " @@ -57,7 +60,7 @@ SendMailDialog::SendMailDialog(const QString& text, QWidget* parent) ui->textEdit->setText(text); ui->errorLabel->setHidden(true); - ui->senderEdit->setText(defaultSender); + ui->senderEdit->setText(default_sender_); connect(ui->ccButton, &QPushButton::clicked, [=]() { ui->ccInputWidget->setHidden(!ui->ccInputWidget->isHidden()); ui->ccEdit->clear(); @@ -72,6 +75,23 @@ SendMailDialog::SendMailDialog(const QString& text, QWidget* parent) &SendMailDialog::slotConfirm); #endif + connect(ui->senderKeySelectButton, &QPushButton::clicked, this, [=]() { + auto picker = new SenderPicker(sender_key_id_, this); + sender_key_id_ = picker->getCheckedSender(); + set_sender_value_label(); + }); + + connect(ui->recipientKeySelectButton, &QPushButton::clicked, this, [=]() { + auto picker = new RecipientsPicker(recipients_key_ids_, this); + recipients_key_ids_ = picker->getCheckedRecipients(); + set_recipients_value_label(); + }); + + connect(ui->recipientsEditButton, &QPushButton::clicked, this, [=]() { + auto editor = new EmailListEditor(ui->recipientEdit->text(), this); + ui->recipientEdit->setText(editor->getEmailList()); + }); + ui->ccButton->setText(_("CC")); ui->bccButton->setText(_("BCC")); ui->senderLabel->setText(_("Sender")); @@ -82,9 +102,15 @@ SendMailDialog::SendMailDialog(const QString& text, QWidget* parent) ui->tipsLabel->setText( _("Tips: You can fill in multiple email addresses, please separate them " "with \";\".")); - ui->sendMailButton->setText(_("Send Mail")); - - this->setWindowTitle(_("Send Mail")); + ui->sendMailButton->setText(_("Send Message")); + ui->senderKeySelectButton->setText(_("Select Sender GPG Key")); + ui->recipientKeySelectButton->setText(_("Select Recipient(s) GPG Key")); + ui->gpgOperaLabel->setText(_("GPG Operations")); + ui->attacSignatureCheckBox->setText(_("Attach signature")); + ui->attachSenderPublickeyCheckBox->setText(_("Attach sender's public key")); + ui->contentEncryptCheckBox->setText(_("Encrypt content")); + + this->setWindowTitle(_("New Message")); this->setAttribute(Qt::WA_DeleteOnClose); } @@ -155,129 +181,204 @@ void SendMailDialog::slotConfirm() { return; } - SmtpClient::ConnectionType connectionType = + SmtpClient::ConnectionType connection_type_ = SmtpClient::ConnectionType::TcpConnection; - if (connectionTypeSettings == "SSL") { - connectionType = SmtpClient::ConnectionType::SslConnection; - } else if (connectionTypeSettings == "TLS") { - connectionType = SmtpClient::ConnectionType::TlsConnection; - } else if (connectionTypeSettings == "STARTTLS") { - connectionType = SmtpClient::ConnectionType::TlsConnection; + if (connection_type_settings_ == "SSL") { + connection_type_ = SmtpClient::ConnectionType::SslConnection; + } else if (connection_type_settings_ == "TLS") { + connection_type_ = SmtpClient::ConnectionType::TlsConnection; + } else if (connection_type_settings_ == "STARTTLS") { + connection_type_ = SmtpClient::ConnectionType::TlsConnection; } else { - connectionType = SmtpClient::ConnectionType::TcpConnection; + connection_type_ = SmtpClient::ConnectionType::TcpConnection; } - SmtpClient smtp(smtpAddress, port, connectionType); - - // We need to set the username (your email address) and the password - // for smtp authentification. - - smtp.setUser(username); - smtp.setPassword(password); - - // Now we create a MimeMessage object. This will be the email. - - MimeMessage message; - - message.setSender(new EmailAddress(ui->senderEdit->text())); - for (const auto& rcpt : rcpt_string_list) { - if (!rcpt.isEmpty()) message.addRecipient(new EmailAddress(rcpt.trimmed())); - } - for (const auto& cc : cc_string_list) { - if (!cc.isEmpty()) message.addCc(new EmailAddress(cc.trimmed())); - } - for (const auto& bcc : bcc_string_list) { - if (!bcc.isEmpty()) message.addBcc(new EmailAddress(bcc.trimmed())); + auto host = smtp_address_.toStdString(); + auto port = port_; + auto connection_type = connection_type_; + bool identity_needed = identity_enable_; + auto username = username_.toStdString(); + auto password = password_.toStdString(); + auto sender_address = ui->senderEdit->text().toStdString(); + + auto thread = new SMTPSendMailThread( + host, port, connection_type, identity_needed, username, password, this); + + thread->setSender(ui->senderEdit->text()); + thread->setRecipient(ui->recipientEdit->text()); + thread->setCC(ui->ccEdit->text()); + thread->setBCC(ui->bccEdit->text()); + thread->setSubject(ui->subjectEdit->text()); + thread->addTextContent(ui->textEdit->toPlainText()); + + if (ui->contentEncryptCheckBox->checkState() == Qt::Checked) { + if (recipients_key_ids_ == nullptr) { + QMessageBox::critical( + this, _("Forbidden"), + _("You have checked the encrypted email content, but you have not " + "selected the recipient's GPG key. This is dangerous and the mail " + "will not be encrypted. So the send operation is forbidden")); + return; + } else { + auto key_ids = std::make_unique<KeyIdArgsList>(); + for (const auto& key_id : *recipients_key_ids_) + key_ids->push_back(key_id); + thread->setEncryptContent(true, std::move(key_ids)); + } } - message.setSubject(ui->subjectEdit->text()); - // Now add some text to the email. - // First we create a MimeText object. + if (ui->attacSignatureCheckBox->checkState() == Qt::Checked) { + if (sender_key_id_.empty()) { + QMessageBox::critical( + this, _("Forbidden"), + _("You checked the option to attach signature to the email, but did " + "not specify the sender's GPG Key. This will cause the content of " + "the email to be inconsistent with your expectations, so the " + "operation is prohibited.")); + return; + } else { + thread->setAttachSignatureFile(true, sender_key_id_); + } + } - MimeText text; - text.setText(ui->textEdit->toPlainText()); + if (ui->attachSenderPublickeyCheckBox->checkState() == Qt::Checked) { + if (sender_key_id_.empty()) { + QMessageBox::critical( + this, _("Forbidden"), + _("You checked the option to attach your public key to the email, " + "but did not specify the sender's GPG Key. This will cause the " + "content of " + "the email to be inconsistent " + "with your expectations, so the operation is prohibited.")); + return; + } else { + thread->setAttachPublicKey(true, sender_key_id_); + } + } - // Now add it to the mail - message.addPart(&text); + // Waiting Dialog + auto* waiting_dialog = new QProgressDialog(this); + waiting_dialog->setMaximum(0); + waiting_dialog->setMinimum(0); + auto waiting_dialog_label = + new QLabel(QString(_("Sending Email...")) + "<br /><br />" + + _("If the process does not end for a long time, please check " + "again whether your SMTP server configuration is correct.")); + waiting_dialog_label->setWordWrap(true); + waiting_dialog->setLabel(waiting_dialog_label); + waiting_dialog->resize(420, 120); + connect(thread, &SMTPSendMailThread::signalSMTPResult, this, + &SendMailDialog::slotTestSMTPConnectionResult); + connect(thread, &QThread::finished, [=]() { + waiting_dialog->finished(0); + waiting_dialog->deleteLater(); + }); + connect(waiting_dialog, &QProgressDialog::canceled, [=]() { + LOG(INFO) << "cancel clicked"; + if (thread->isRunning()) thread->terminate(); + QCoreApplication::quit(); + exit(0); + }); - // Now we can send the mail - if (!smtp.connectToHost()) { - qDebug() << "Connect to SMTP Server Failed"; - QMessageBox::critical(this, _("Fail"), _("Fail to Connect SMTP Server")); - return; - } - if (!smtp.login()) { - qDebug() << "Login to SMTP Server Failed"; - QMessageBox::critical(this, _("Fail"), _("Fail to Login into SMTP Server")); - return; - } - if (!smtp.sendMail(message)) { - qDebug() << "Send Mail to SMTP Server Failed"; - QMessageBox::critical(this, _("Fail"), - _("Fail to Send Mail to SMTP Server")); - return; - } - smtp.quit(); + // Show Waiting Dialog + waiting_dialog->show(); + waiting_dialog->setFocus(); - // Close after sending email - QMessageBox::information(this, _("Success"), - _("Succeed in Sending Mail to SMTP Server")); - deleteLater(); + thread->start(); + QEventLoop loop; + connect(thread, &QThread::finished, &loop, &QEventLoop::quit); + loop.exec(); } void SendMailDialog::initSettings() { auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); try { - ability_enable = settings.lookup("smtp.enable"); + ability_enable_ = settings.lookup("smtp.enable"); } catch (...) { LOG(ERROR) << _("Setting Operation Error") << _("save_key_checked"); } try { - identity_enable = settings.lookup("smtp.identity_enable"); + identity_enable_ = settings.lookup("smtp.identity_enable"); } catch (...) { LOG(ERROR) << _("Setting Operation Error") << _("identity_enable"); } try { - smtpAddress = settings.lookup("smtp.mail_address").c_str(); + smtp_address_ = settings.lookup("smtp.mail_address").c_str(); } catch (...) { LOG(ERROR) << _("Setting Operation Error") << _("mail_address"); } try { - username = settings.lookup("smtp.username").c_str(); + username_ = settings.lookup("smtp.username").c_str(); } catch (...) { LOG(ERROR) << _("Setting Operation Error") << _("username"); } try { - password = settings.lookup("smtp.password").c_str(); + password_ = settings.lookup("smtp.password").c_str(); } catch (...) { LOG(ERROR) << _("Setting Operation Error") << _("password"); } try { - port = settings.lookup("smtp.port"); + port_ = settings.lookup("smtp.port"); } catch (...) { LOG(ERROR) << _("Setting Operation Error") << _("port"); } try { - connectionTypeSettings = settings.lookup("smtp.connection_type").c_str(); + connection_type_settings_ = settings.lookup("smtp.connection_type").c_str(); } catch (...) { LOG(ERROR) << _("Setting Operation Error") << _("connection_type"); } try { - defaultSender = settings.lookup("smtp.default_sender").c_str(); + default_sender_ = settings.lookup("smtp.default_sender").c_str(); } catch (...) { LOG(ERROR) << _("Setting Operation Error") << _("default_sender"); } } - #endif +void SendMailDialog::set_sender_value_label() { + auto key = GpgKeyGetter::GetInstance().GetKey(sender_key_id_); + if (key.good()) { + ui->senderKeyValueLabel->setText(key.uids()->front().uid().c_str()); + } +} + +void SendMailDialog::set_recipients_value_label() { + auto keys = GpgKeyGetter::GetInstance().GetKeys(recipients_key_ids_); + std::stringstream ss; + for (const auto& key : *keys) { + if (key.good()) { + ss << key.uids()->front().uid().c_str() << ";"; + } + } + ui->recipientsKeyValueLabel->setText(ss.str().c_str()); +} + +void SendMailDialog::slotTestSMTPConnectionResult(const QString& result) { + if (result == "Fail to connect SMTP server") { + QMessageBox::critical(this, _("Fail"), _("Fail to Connect SMTP Server.")); + } else if (result == "Fail to login") { + QMessageBox::critical(this, _("Fail"), _("Fail to Login.")); + } else if (result == "Fail to send mail") { + QMessageBox::critical(this, _("Fail"), _("Fail to Login.")); + } else if (result == "Succeed in testing connection") { + QMessageBox::information(this, _("Success"), + _("Succeed in connecting and login")); + } else if (result == "Succeed in sending a test email") { + QMessageBox::information( + this, _("Success"), + _("Succeed in sending the message to the SMTP Server")); + } else { + QMessageBox::critical(this, _("Fail"), _("Unknown error.")); + } +} + } // namespace GpgFrontend::UI diff --git a/src/ui/smtp/SendMailDialog.h b/src/ui/smtp/SendMailDialog.h index 979d4f88..bf082c39 100644 --- a/src/ui/smtp/SendMailDialog.h +++ b/src/ui/smtp/SendMailDialog.h @@ -40,24 +40,34 @@ class SendMailDialog : public QDialog { void slotConfirm(); + void slotTestSMTPConnectionResult(const QString& result); + private: void initSettings(); std::shared_ptr<Ui_SendMailDialog> ui; - bool ability_enable = false; - bool identity_enable = false; - QString smtpAddress; - QString username; - QString password; - QString defaultSender; - QString connectionTypeSettings = "None"; - int port = 25; + bool ability_enable_ = false; + bool identity_enable_ = false; + QString smtp_address_; + QString username_; + QString password_; + QString default_sender_; + QString connection_type_settings_ = "None"; + int port_ = 25; + + GpgFrontend::KeyId sender_key_id_; + GpgFrontend::KeyIdArgsListPtr recipients_key_ids_ = + std::make_unique<GpgFrontend::KeyIdArgsList>(); QRegularExpression re_email{ R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"}; bool check_email_address(const QString& str); + + void set_sender_value_label(); + + void set_recipients_value_label(); }; } // namespace GpgFrontend::UI diff --git a/src/ui/smtp/SenderPicker.cpp b/src/ui/smtp/SenderPicker.cpp new file mode 100644 index 00000000..1cbd409f --- /dev/null +++ b/src/ui/smtp/SenderPicker.cpp @@ -0,0 +1,76 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#include "SenderPicker.h" + +#include "ui/widgets/KeyList.h" + +GpgFrontend::UI::SenderPicker::SenderPicker(const KeyId& current_key_id, + QWidget* parent) + : QDialog(parent) { + auto confirm_button = new QPushButton(_("Confirm")); + connect(confirm_button, SIGNAL(clicked(bool)), this, SLOT(accept())); + + // Setup KeyList + key_list_ = new KeyList(false, this); + key_list_->addListGroupTab( + _("Sender"), KeyListRow::ONLY_SECRET_KEY, + KeyListColumn::NAME | KeyListColumn::EmailAddress, + [](const GpgKey& key) -> bool { return key.CanSignActual(); }); + key_list_->slotRefresh(); + + auto key_ids = std::make_unique<GpgFrontend::KeyIdArgsList>(); + key_ids->push_back(current_key_id); + key_list_->setChecked(std::move(key_ids)); + + auto* vbox2 = new QVBoxLayout(); + vbox2->addWidget(new QLabel(QString(_("Select Sender")) + ": ")); + vbox2->addWidget(key_list_); + vbox2->addWidget(new QLabel( + QString( + _("As the sender of the mail, the private key is generally used.")) + + "\n" + + _(" The private key is generally used as a signature for the content of " + "the mail."))); + vbox2->addWidget(confirm_button); + vbox2->addStretch(0); + setLayout(vbox2); + + this->setWindowFlags(Qt::Window | Qt::WindowTitleHint | + Qt::CustomizeWindowHint); + + this->setModal(true); + this->setWindowTitle("Sender Picker"); + this->setMinimumWidth(480); + this->exec(); +} + +GpgFrontend::KeyId GpgFrontend::UI::SenderPicker::getCheckedSender() { + auto checked_keys = key_list_->getChecked(); + if (!checked_keys->empty()) { + return key_list_->getChecked()->front(); + } else { + return {}; + } +} diff --git a/src/ui/smtp/SenderPicker.h b/src/ui/smtp/SenderPicker.h new file mode 100644 index 00000000..3745bb34 --- /dev/null +++ b/src/ui/smtp/SenderPicker.h @@ -0,0 +1,47 @@ +/** + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Foobar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from gpg4usb-team. + * Their source code version also complies with GNU General Public License. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_SENDERPICKER_H +#define GPGFRONTEND_SENDERPICKER_H + +#include "GpgFrontendUI.h" + +namespace GpgFrontend::UI { + +class KeyList; + +class SenderPicker : public QDialog { + Q_OBJECT + + public: + explicit SenderPicker(const KeyId& current_key_id, QWidget* parent = nullptr); + + GpgFrontend::KeyId getCheckedSender(); + + private: + KeyList* key_list_; +}; +} // namespace GpgFrontend::UI + +#endif // GPGFRONTEND_SENDERPICKER_H diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp index fb715b2b..6dec19e7 100644 --- a/src/ui/widgets/KeyList.cpp +++ b/src/ui/widgets/KeyList.cpp @@ -79,7 +79,7 @@ void KeyList::init() { &SignalStation::signalRefreshStatusBar); setAcceptDrops(true); - + ui->refreshKeyListButton->setText(_("Refresh")); ui->syncButton->setText(_("Sync Public Key")); ui->syncButton->setToolTip(_("Sync public key with your default keyserver")); @@ -227,17 +227,14 @@ void KeyList::setChecked(const KeyIdArgsListPtr& keyIds, } } -void KeyList::setChecked(const KeyIdArgsListPtr& keyIds) { - if (ui->keyGroupTab->size().isEmpty()) return; +void KeyList::setChecked(KeyIdArgsListPtr key_ids) { auto key_list = qobject_cast<QTableWidget*>(ui->keyGroupTab->currentWidget()); - const auto& buffered_keys = - mKeyTables[ui->keyGroupTab->currentIndex()].buffered_keys; - - if (!keyIds->empty()) { - for (int i = 0; i < key_list->rowCount(); i++) { - if (std::find(keyIds->begin(), keyIds->end(), buffered_keys[i].id()) != - keyIds->end()) { - key_list->item(i, 0)->setCheckState(Qt::Checked); + if (key_list == nullptr) return; + if (!mKeyTables.empty()) { + for (auto& key_table : mKeyTables) { + if (key_table.key_list == key_list) { + key_table.SetChecked(std::move(key_ids)); + break; } } } @@ -460,31 +457,30 @@ void KeyList::slotSyncWithKeyServer() { }); } -KeyIdArgsListPtr KeyTable::GetChecked() { - auto ret = std::make_unique<KeyIdArgsList>(); +KeyIdArgsListPtr& KeyTable::GetChecked() { + LOG(INFO) << "called"; + if (checked_key_ids_ == nullptr) + checked_key_ids_ = std::make_unique<KeyIdArgsList>(); + auto& ret = checked_key_ids_; for (int i = 0; i < key_list->rowCount(); i++) { - if (key_list->item(i, 0)->checkState() == Qt::Checked) { - ret->push_back(buffered_keys[i].id()); + auto key_id = buffered_keys[i].id(); + if (key_list->item(i, 0)->checkState() == Qt::Checked && + std::find(ret->begin(), ret->end(), key_id) == ret->end()) { + ret->push_back(key_id); } } return ret; } -void KeyTable::SetChecked(const KeyIdArgsListPtr& key_ids) { - if (!key_ids->empty()) { - for (int i = 0; i < key_list->rowCount(); i++) { - if (std::find(key_ids->begin(), key_ids->end(), buffered_keys[i].id()) != - key_ids->end()) { - key_list->item(i, 0)->setCheckState(Qt::Checked); - } - } - } +void KeyTable::SetChecked(KeyIdArgsListPtr key_ids) { + LOG(INFO) << "called"; + checked_key_ids_ = std::move(key_ids); } void KeyTable::Refresh(KeyLinkListPtr m_keys) { LOG(INFO) << "Called"; - auto checked_key_list = GetChecked(); + auto& checked_key_list = GetChecked(); // while filling the table, sort enabled causes errors key_list->setSortingEnabled(false); @@ -590,7 +586,14 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) { ++row_index; } - SetChecked(checked_key_list); + if (!checked_key_list->empty()) { + for (int i = 0; i < key_list->rowCount(); i++) { + if (std::find(checked_key_list->begin(), checked_key_list->end(), + buffered_keys[i].id()) != checked_key_list->end()) { + key_list->item(i, 0)->setCheckState(Qt::Checked); + } + } + } LOG(INFO) << "End"; } diff --git a/src/ui/widgets/KeyList.h b/src/ui/widgets/KeyList.h index 617bb274..8d6fb600 100644 --- a/src/ui/widgets/KeyList.h +++ b/src/ui/widgets/KeyList.h @@ -59,6 +59,7 @@ struct KeyTable { KeyListColumn::InfoType info_type; std::vector<GpgKey> buffered_keys; std::function<bool(const GpgKey&)> filter; + KeyIdArgsListPtr checked_key_ids_; KeyTable( QTableWidget* _key_list, KeyListRow::KeyType _select_type, @@ -73,9 +74,9 @@ struct KeyTable { void Refresh(KeyLinkListPtr m_keys = nullptr); - KeyIdArgsListPtr GetChecked(); + KeyIdArgsListPtr& GetChecked(); - void SetChecked(const KeyIdArgsListPtr& key_ids); + void SetChecked(KeyIdArgsListPtr key_ids); }; class KeyList : public QWidget { @@ -102,7 +103,7 @@ class KeyList : public QWidget { static KeyIdArgsListPtr getChecked(const KeyTable& key_table); KeyIdArgsListPtr getPrivateChecked(); KeyIdArgsListPtr getAllPrivateKeys(); - void setChecked(const KeyIdArgsListPtr& keyIds); + void setChecked(KeyIdArgsListPtr key_ids); static void setChecked(const KeyIdArgsListPtr& keyIds, const KeyTable& key_table); KeyIdArgsListPtr getSelected(); diff --git a/src/ui/widgets/SignersPicker.cpp b/src/ui/widgets/SignersPicker.cpp index e769d05c..b035bf19 100644 --- a/src/ui/widgets/SignersPicker.cpp +++ b/src/ui/widgets/SignersPicker.cpp @@ -24,31 +24,31 @@ #include "ui/widgets/SignersPicker.h" +#include "ui/widgets/KeyList.h" + namespace GpgFrontend::UI { SignersPicker::SignersPicker(QWidget* parent) : QDialog(parent) { - auto confirmButton = new QPushButton(_("Confirm")); - connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(accept())); + auto confirm_button = new QPushButton(_("Confirm")); + connect(confirm_button, SIGNAL(clicked(bool)), this, SLOT(accept())); /*Setup KeyList*/ - mKeyList = new KeyList(false, this); - mKeyList->addListGroupTab( + key_list_ = new KeyList(false, this); + key_list_->addListGroupTab( _("Signers"), KeyListRow::ONLY_SECRET_KEY, KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage, - [](const GpgKey& key) -> bool { - if (!key.CanSignActual()) - return false; - else - return true; - }); - mKeyList->slotRefresh(); + [](const GpgKey& key) -> bool { return key.CanSignActual(); }); + key_list_->slotRefresh(); auto* vbox2 = new QVBoxLayout(); vbox2->addWidget(new QLabel(QString(_("Select Signer(s)")) + ": ")); - vbox2->addWidget(mKeyList); + vbox2->addWidget(key_list_); vbox2->addWidget(new QLabel( - _("If any key is selected, the default key will be used for signing."))); - vbox2->addWidget(confirmButton); + QString( + _("Please select one or more private keys you use for signing.")) + + "\n" + + _("If no key is selected, the default key will be used for signing."))); + vbox2->addWidget(confirm_button); vbox2->addStretch(0); setLayout(vbox2); @@ -62,7 +62,7 @@ SignersPicker::SignersPicker(QWidget* parent) : QDialog(parent) { } GpgFrontend::KeyIdArgsListPtr SignersPicker::getCheckedSigners() { - return mKeyList->getPrivateChecked(); + return key_list_->getPrivateChecked(); } } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/SignersPicker.h b/src/ui/widgets/SignersPicker.h index 055b6ef6..08972a76 100644 --- a/src/ui/widgets/SignersPicker.h +++ b/src/ui/widgets/SignersPicker.h @@ -25,12 +25,12 @@ #ifndef GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H #define GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H -#include "GpgFrontend.h" -#include "gpg/GpgContext.h" -#include "ui/widgets/KeyList.h" +#include "GpgFrontendUI.h" namespace GpgFrontend::UI { +class KeyList; + class SignersPicker : public QDialog { Q_OBJECT @@ -40,7 +40,7 @@ class SignersPicker : public QDialog { GpgFrontend::KeyIdArgsListPtr getCheckedSigners(); private: - KeyList* mKeyList; + KeyList* key_list_; }; } // namespace GpgFrontend::UI diff --git a/third_party/AppImageUpdate b/third_party/AppImageUpdate deleted file mode 160000 -Subproject 1b97acc55c89f742d51c3849eb62eb58464d866 diff --git a/ui/EmailListEditor.ui b/ui/EmailListEditor.ui new file mode 100644 index 00000000..5cc0ddef --- /dev/null +++ b/ui/EmailListEditor.ui @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>EmailListEditorDialog</class> + <widget class="QDialog" name="EmailListEditorDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>618</width> + <height>498</height> + </rect> + </property> + <property name="windowTitle"> + <string>Email List Editor</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="titleLabel"> + <property name="text"> + <string>Email List:</string> + </property> + </widget> + </item> + <item> + <widget class="QListWidget" name="emaillistWidget"> + <property name="editTriggers"> + <set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set> + </property> + <property name="dragEnabled"> + <bool>true</bool> + </property> + <property name="isWrapping" stdset="0"> + <bool>false</bool> + </property> + <property name="spacing"> + <number>6</number> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="addEmailAddressButton"> + <property name="text"> + <string>Add An Email Address</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="tipsLabel"> + <property name="text"> + <string>Tips: You can double-click the email address in the edit list, or click the email to pop up the option menu.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + <action name="actionDelete_Selected_Email_Address"> + <property name="text"> + <string>Delete Selected Email Address</string> + </property> + </action> + </widget> + <resources/> + <connections/> +</ui> diff --git a/ui/SendMailDialog.ui b/ui/SendMailDialog.ui index 8eb004f7..bb770f5b 100644 --- a/ui/SendMailDialog.ui +++ b/ui/SendMailDialog.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>958</width> - <height>607</height> + <width>995</width> + <height>760</height> </rect> </property> <property name="cursor"> @@ -17,7 +17,7 @@ <enum>Qt::NoContextMenu</enum> </property> <property name="windowTitle"> - <string>Send Mail</string> + <string>New Message</string> </property> <property name="sizeGripEnabled"> <bool>false</bool> @@ -80,6 +80,9 @@ <property name="text"> <string>CC</string> </property> + <property name="checkable"> + <bool>true</bool> + </property> </widget> </item> <item> @@ -87,6 +90,9 @@ <property name="text"> <string>BCC</string> </property> + <property name="checkable"> + <bool>true</bool> + </property> </widget> </item> </layout> @@ -96,7 +102,7 @@ <widget class="QWidget" name="horizontalWidget_4" native="true"> <layout class="QHBoxLayout" name="horizontalLayout_4"> <property name="spacing"> - <number>0</number> + <number>6</number> </property> <property name="leftMargin"> <number>0</number> @@ -113,7 +119,7 @@ <item> <widget class="QLabel" name="recipientLabel"> <property name="text"> - <string>Recipient</string> + <string>Recipient(s)</string> </property> <property name="margin"> <number>5</number> @@ -123,6 +129,13 @@ <item> <widget class="QLineEdit" name="recipientEdit"/> </item> + <item> + <widget class="QPushButton" name="recipientsEditButton"> + <property name="text"> + <string>Edit Recipients(s)</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -154,7 +167,7 @@ <item> <widget class="QLabel" name="subjectLabel"> <property name="text"> - <string>Subject</string> + <string>Mail Subject</string> </property> <property name="margin"> <number>5</number> @@ -168,6 +181,64 @@ </widget> </item> <item> + <widget class="QWidget" name="horizontalWidget_6" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_9"> + <property name="spacing"> + <number>6</number> + </property> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="gpgOperaLabel"> + <property name="text"> + <string>GPG Operations</string> + </property> + <property name="margin"> + <number>5</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="senderKeySelectButton"> + <property name="text"> + <string>Select Sender GPG Key</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="recipientKeySelectButton"> + <property name="text"> + <string>Select Recipient(s) GPG Key</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> <widget class="Line" name="line_4"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -178,7 +249,7 @@ <widget class="QWidget" name="ccInputWidget" native="true"> <layout class="QHBoxLayout" name="horizontalLayout_2"> <property name="spacing"> - <number>0</number> + <number>6</number> </property> <property name="leftMargin"> <number>0</number> @@ -205,6 +276,13 @@ <item> <widget class="QLineEdit" name="ccEdit"/> </item> + <item> + <widget class="QPushButton" name="ccEditButton"> + <property name="text"> + <string>Edit CC(s)</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -212,7 +290,7 @@ <widget class="QWidget" name="bccInputWidget" native="true"> <layout class="QHBoxLayout" name="horizontalLayout_3"> <property name="spacing"> - <number>0</number> + <number>6</number> </property> <property name="leftMargin"> <number>0</number> @@ -239,6 +317,13 @@ <item> <widget class="QLineEdit" name="bccEdit"/> </item> + <item> + <widget class="QPushButton" name="bccEditButton"> + <property name="text"> + <string>Edit BCC(s)</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -260,6 +345,57 @@ <widget class="QTextEdit" name="textEdit"/> </item> <item> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <item alignment="Qt::AlignLeft|Qt::AlignVCenter"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Sender GPG Key: </string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="senderKeyValueLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_10"> + <item alignment="Qt::AlignLeft|Qt::AlignVCenter"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Recipient(s) GPG Key: </string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="recipientsKeyValueLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + <item> <widget class="QLabel" name="errorLabel"> <property name="text"> <string/> @@ -267,11 +403,65 @@ </widget> </item> <item> + <widget class="Line" name="line_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> <layout class="QHBoxLayout" name="horizontalLayout_7"> + <item> + <widget class="QCheckBox" name="contentEncryptCheckBox"> + <property name="text"> + <string>Encrypt content</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="attacSignatureCheckBox"> + <property name="text"> + <string>Attach signature</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="attachSenderPublickeyCheckBox"> + <property name="text"> + <string>Attach sender's public key</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="saveDraftButton"> + <property name="text"> + <string>Save Draft</string> + </property> + </widget> + </item> <item alignment="Qt::AlignRight"> <widget class="QPushButton" name="sendMailButton"> <property name="text"> - <string>Send</string> + <string>Send Mail</string> </property> </widget> </item> |