Скачиваний:
54
Добавлен:
09.03.2022
Размер:
2 Мб
Скачать
☆
    1. Работа с сообщениями

Процесс копирования сообщений представлен на рис. 5.20-5.21.

Рисунок 5.38. Выбор папки для копирования в нее выбранных двух сообщений

Рисунок 5.39. Сообщения скопированы

«[undefined]» означает дату скопированного сообщения. В случае оповещений безопасности дата на отправляется почтовым сервером.

Процесс удаления сообщений представлен на рис. 5.22-5.23.

Рисунок 5.40. Запрос на подтверждение удаления выбранных сообщений

Рисунок 5.41. Выбранные ранее сообщения удалены

Процесс загрузки вложений представлен на рис. 5.24-5.26.

Рисунок 5.42. Выбор вложения для загрузки

Рисунок 5.43. Ввод имени файла для записи

Рисунок 5.44. Файл записан

Статистика отображает размер всех сообщений с учетом вложений (рис. 5.27).

Рисунок 5.45. Отображение статистики в программе

Заключение

Программа выполняет все поставленные задачи: пользовательская настройка параметров для авторизации (IMAP и SMTP), отображение электронных сообщений (IMAP), загрузка и сохранение вложений на диск, отправка сообщений с вложенными файлами (SMTP), добавление, переименование/перемещение и удаление папок электронной почты (IMAP), копирование и удаление сообщений (IMAP).

В ходе выполнения курсовой работы была освоена работа с основными средствами языка C++, библиотек Qt и Mailio, редактором Qt Creator.

Список литературы

  1. С. А. Коробов. Лекции по дисциплине «Математические методы и вычислительные алгоритмы современных систем связи».

  2. The Qt Company. Документация Qt 6 [Электронный ресурс] URL: https://doc.qt.io/qt-6/ (дата обращения: 04.03.2022)

  3. Страуструп, Бьярне. Программирование: принципы и практика использования C++, испр. изд. : Пер. с англ. — М. : ООО "И.Д. Вильямс", 2011. — 1248 с. : ил. — Парал. тит. англ. ISBN 978-5-8459-1705-8 (рус.).

Приложение

Сборочный файл «CMakeLists.txt»

  1. cmake_minimum_required(VERSION 3.5)

  2. project(MailClient VERSION 1.0 LANGUAGES CXX)

  3. set(CMAKE_INCLUDE_CURRENT_DIR ON)

  4. set(CMAKE_AUTOUIC ON)

  5. set(CMAKE_AUTOMOC ON)

  6. set(CMAKE_AUTORCC ON)

  7. set(CMAKE_CXX_STANDARD 11)

  8. set(CMAKE_CXX_STANDARD_REQUIRED ON)

  9. find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)

  10. find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)

  11. set(Boost_USE_MULTITHREADED ON)

  12. set(Boost_USE_STATIC_LIBS ON)

  13. find_package(Boost REQUIRED COMPONENTS regex date_time system)

  14. cmake_policy(SET CMP0074 NEW)

  15. find_package(Mailio REQUIRED)

  16. set(PROJECT_SOURCES

  17. tools.h

  18. imap_settings.cpp

  19. imap_settings.h

  20. smtp_settings.cpp

  21. smtp_settings.h

  22. main.cpp

  23. mainwindow.cpp

  24. mainwindow.h

  25. mainwindow.ui

  26. settings_dialog.cpp

  27. settings_dialog.h

  28. settings_dialog.ui

  29. send_message_dialog.cpp

  30. send_message_dialog.h

  31. send_message_dialog.ui

  32. resources.qrc

  33. )

  34. if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)

  35. qt_add_executable(MailClient

  36. MANUAL_FINALIZATION

  37. ${PROJECT_SOURCES}

  38. )

  39. # Define target properties for Android with Qt 6 as:

  40. # set_property(TARGET MailClient APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR

  41. # ${CMAKE_CURRENT_SOURCE_DIR}/android)

  42. # For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation

  43. else()

  44. if(ANDROID)

  45. add_library(MailClient SHARED

  46. ${PROJECT_SOURCES}

  47. )

  48. # Define properties for Android with Qt 5 after find_package() calls as:

  49. # set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")

  50. else()

  51. add_executable(MailClient

  52. ${PROJECT_SOURCES}

  53. )

  54. endif()

  55. endif()

  56. target_link_libraries(MailClient PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)

  57. if(Boost_FOUND)

  58. target_include_directories(MailClient PUBLIC ${Boost_INCLUDE_DIRS})

  59. target_link_libraries(MailClient PUBLIC ${Boost_LIBRARIES})

  60. if(Mailio_FOUND)

  61. target_link_libraries(MailClient PUBLIC mailio ${CMAKE_THREAD_LIBS_INIT})

  62. endif()

  63. endif()

  64. find_package(OpenSSL REQUIRED)

  65. target_link_libraries(MailClient PRIVATE OpenSSL::SSL)

  66. set_target_properties(MailClient PROPERTIES

  67. MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com

  68. MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}

  69. MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}

  70. MACOSX_BUNDLE TRUE

  71. WIN32_EXECUTABLE TRUE

  72. )

  73. if(QT_VERSION_MAJOR EQUAL 6)

  74. qt_finalize_executable(MailClient)

  75. endif()

Исходный код основных модулей

В сумме 2136 непустых строк кода.

Модуль «imap_settings.h»

  1. #ifndef IMAPSETTINGS_H

  2. #define IMAPSETTINGS_H

  3. #include <mailio/imap.hpp>

  4. class ImapSettings

  5. {

  6. public:

  7. ImapSettings();

  8. // setters

  9. void set_server_address(const std::string &server_address);

  10. void set_server_port(int server_port);

  11. void set_login(const std::string &login);

  12. void set_password(std::string password);

  13. void set_auth_method(const mailio::imaps::auth_method_t &auth_method);

  14. void set_autoupdate(bool autoupdate);

  15. void set_autoupdate_interval(int interval);

  16. // getters

  17. std::string get_server_address() const;

  18. int get_server_port() const;

  19. std::string get_login() const;

  20. std::string get_password() const;

  21. mailio::imaps::auth_method_t get_auth_method() const;

  22. bool get_autoupdate() const;

  23. int get_autoupdate_interval() const;

  24. private:

  25. std::string server_address, login, password;

  26. mailio::imaps::auth_method_t auth_method;

  27. int server_port, autoupdate_interval;

  28. bool autoupdate_enable;

  29. };

  30. #endif // IMAPSETTINGS_H

Модуль «imap_settings.cpp»

  1. #include "imap_settings.h"

  2. ImapSettings::ImapSettings()

  3. {

  4. }

  5. // setters

  6. void ImapSettings::set_server_address(const std::string &server_address)

  7. {

  8. this->server_address = server_address;

  9. }

  10. void ImapSettings::set_server_port(int server_port)

  11. {

  12. this->server_port = server_port;

  13. }

  14. void ImapSettings::set_login(const std::string &login)

  15. {

  16. this->login = login;

  17. }

  18. void ImapSettings::set_password(std::string password)

  19. {

  20. for (size_t i = 0, n = password.length(); i < n; ++i)

  21. {

  22. password[i] ^= 0x01011001 ^ i;

  23. }

  24. this->password = password;

  25. }

  26. void ImapSettings::set_auth_method(const mailio::imaps::auth_method_t &auth_method)

  27. {

  28. this->auth_method = auth_method;

  29. }

  30. void ImapSettings::set_autoupdate(bool autoupdate)

  31. {

  32. this->autoupdate_enable = autoupdate;

  33. }

  34. void ImapSettings::set_autoupdate_interval(int interval)

  35. {

  36. this->autoupdate_interval = interval;

  37. }

  38. // getters

  39. std::string ImapSettings::get_server_address() const

  40. {

  41. return this->server_address;

  42. }

  43. int ImapSettings::get_server_port() const

  44. {

  45. return this->server_port;

  46. }

  47. std::string ImapSettings::get_login() const

  48. {

  49. return this->login;

  50. }

  51. std::string ImapSettings::get_password() const

  52. {

  53. std::string decoded_password(password);

  54. for (size_t i = 0, n = decoded_password.length(); i < n; ++i)

  55. {

  56. decoded_password[i] ^= 0x01011001 ^ i;

  57. }

  58. return decoded_password;

  59. }

  60. mailio::imaps::auth_method_t ImapSettings::get_auth_method() const

  61. {

  62. return this->auth_method;

  63. }

  64. bool ImapSettings::get_autoupdate() const

  65. {

  66. return this->autoupdate_enable;

  67. }

  68. int ImapSettings::get_autoupdate_interval() const

  69. {

  70. return this->autoupdate_interval;

  71. }

Модуль «smtp_settings.h»

  1. #ifndef SMTPSETTINGS_H

  2. #define SMTPSETTINGS_H

  3. #include <mailio/smtp.hpp>

  4. class SmtpSettings

  5. {

  6. public:

  7. SmtpSettings();

  8. // setters

  9. void set_server_address(const std::string &server_address);

  10. void set_server_port(int server_port);

  11. void set_login(const std::string &login);

  12. void set_password(std::string password);

  13. void set_name(const std::string &name);

  14. void set_auth_method(const mailio::smtps::auth_method_t &auth_method);

  15. // getters

  16. std::string get_server_address() const;

  17. int get_server_port() const;

  18. std::string get_login() const;

  19. std::string get_password() const;

  20. std::string get_name() const;

  21. mailio::smtps::auth_method_t get_auth_method() const;

  22. private:

  23. std::string server_address, login, password, name;

  24. int server_port;

  25. mailio::smtps::auth_method_t auth_method;

  26. };

  27. #endif // SMTPSETTINGS_H

Модуль «smtp_settings.cpp»

  1. #include "smtp_settings.h"

  2. SmtpSettings::SmtpSettings()

  3. {

  4. }

  5. // setters

  6. void SmtpSettings::set_server_address(const std::string &server_address)

  7. {

  8. this->server_address = server_address;

  9. }

  10. void SmtpSettings::set_server_port(int server_port)

  11. {

  12. this->server_port = server_port;

  13. }

  14. void SmtpSettings::set_login(const std::string &login)

  15. {

  16. this->login = login;

  17. }

  18. void SmtpSettings::set_password(std::string password)

  19. {

  20. for (size_t i = 0, n = password.length(); i < n; ++i)

  21. {

  22. password[i] ^= 0x10100110 ^ i;

  23. }

  24. this->password = password;

  25. }

  26. void SmtpSettings::set_name(const std::string &name)

  27. {

  28. this->name = name;

  29. }

  30. void SmtpSettings::set_auth_method(const mailio::smtps::auth_method_t &auth_method)

  31. {

  32. this->auth_method = auth_method;

  33. }

  34. // getters

  35. std::string SmtpSettings::get_server_address() const

  36. {

  37. return this->server_address;

  38. }

  39. int SmtpSettings::get_server_port() const

  40. {

  41. return this->server_port;

  42. }

  43. std::string SmtpSettings::get_login() const

  44. {

  45. return this->login;

  46. }

  47. std::string SmtpSettings::get_password() const

  48. {

  49. std::string decoded_password(password);

  50. for (size_t i = 0, n = decoded_password.length(); i < n; ++i)

  51. {

  52. decoded_password[i] ^= 0x10100110 ^ i;

  53. }

  54. return decoded_password;

  55. }

  56. std::string SmtpSettings::get_name() const

  57. {

  58. return this->name;

  59. }

  60. mailio::smtps::auth_method_t SmtpSettings::get_auth_method() const

  61. {

  62. return this->auth_method;

  63. }

Модуль «tools.h»

  1. #ifndef TOOLS_H

  2. #define TOOLS_H

  3. #include <QList>

  4. #include <QString>

  5. #include <QStringConverter>

  6. QString utf7encode(QString str)

  7. {

  8. auto toUtf16be = QStringEncoder(QStringConverter::Utf16BE);

  9. QString unipart, out;

  10. str.replace("&", "&-");

  11. for (QChar ch : str)

  12. {

  13. uint16_t i16 = ch.unicode();

  14. if (0x20 <= i16 && i16 <= 0x7f)

  15. {

  16. if (!unipart.isEmpty())

  17. {

  18. QByteArray unipart16be_bytes = (QByteArray)toUtf16be(unipart);

  19. QString encoded_string(unipart16be_bytes.toBase64(

  20. QByteArray::Base64Option::Base64Encoding | QByteArray::Base64Option::OmitTrailingEquals |

  21. QByteArray::Base64Option::IgnoreBase64DecodingErrors));

  22. out += '&' + encoded_string.replace('/', ',') + '-';

  23. unipart.clear();

  24. }

  25. out += ch;

  26. }

  27. else

  28. {

  29. unipart += ch;

  30. }

  31. }

  32. if (!unipart.isEmpty())

  33. {

  34. QByteArray unipart16be_bytes = (QByteArray)toUtf16be(unipart);

  35. QString encoded_string(unipart16be_bytes.toBase64(QByteArray::Base64Option::Base64Encoding |

  36. QByteArray::Base64Option::OmitTrailingEquals |

  37. QByteArray::Base64Option::IgnoreBase64DecodingErrors));

  38. out += '&' + encoded_string.replace('/', ',') + '-';

  39. unipart.clear();

  40. }

  41. return out;

  42. }

  43. QString utf7decode(const QString &str)

  44. {

  45. auto fromUtf16be = QStringDecoder(QStringConverter::Utf16BE);

  46. QList<QString> parts = str.split('&', Qt::KeepEmptyParts);

  47. if (parts.empty())

  48. {

  49. return QString();

  50. }

  51. QString out = parts[0];

  52. for (qsizetype i = 1, n = parts.size(); i < n; ++i)

  53. {

  54. QString part = parts[i], first, last;

  55. qsizetype pos = part.indexOf('-');

  56. if (pos != -1)

  57. {

  58. first = part.left(pos);

  59. last = part.right(part.size() - pos - 1);

  60. }

  61. else

  62. {

  63. first = part;

  64. }

  65. if (first.isEmpty())

  66. {

  67. out += '&';

  68. }

  69. else

  70. {

  71. first = first.replace(',', '/');

  72. QByteArray decoded_bytes =

  73. QByteArray::fromBase64(first.toUtf8(), QByteArray::Base64Option::Base64Encoding |

  74. QByteArray::Base64Option::OmitTrailingEquals |

  75. QByteArray::Base64Option::IgnoreBase64DecodingErrors);

  76. out += fromUtf16be(decoded_bytes);

  77. }

  78. out += last;

  79. }

  80. return out;

  81. }

  82. #endif // TOOLS_H

Модуль «send_message_dialog.h»

  1. #ifndef SEND_MESSAGE_DIALOG_H

  2. #define SEND_MESSAGE_DIALOG_H

  3. #include <QCloseEvent>

  4. #include <QDialog>

  5. #include <mailio/message.hpp>

  6. namespace Ui

  7. {

  8. class SendMessageDialog;

  9. }

  10. class SendMessageDialog : public QDialog

  11. {

  12. Q_OBJECT

  13. public:

  14. explicit SendMessageDialog(QWidget *parent = nullptr);

  15. mailio::message get_message();

  16. ~SendMessageDialog() override;

  17. private slots:

  18. void on_add_attachment_clicked();

  19. void on_remove_attachment_clicked();

  20. private:

  21. void closeEvent(QCloseEvent *event) override;

  22. Ui::SendMessageDialog *ui;

  23. std::list<std::tuple<std::shared_ptr<std::stringstream>, std::string, mailio::message::content_type_t>> attachments;

  24. };

  25. #endif // SEND_MESSAGE_DIALOG_H

Модуль «send_message_dialog.cpp»

  1. #include <QFileDialog>

  2. #include <QMessageBox>

  3. #include "send_message_dialog.h"

  4. #include "ui_send_message_dialog.h"

  5. SendMessageDialog::SendMessageDialog(QWidget *parent) : QDialog(parent), ui(new Ui::SendMessageDialog)

  6. {

  7. ui->setupUi(this);

  8. ui->attachments_table->setSortingEnabled(false);

  9. ui->attachments_table->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents);

  10. }

  11. SendMessageDialog::~SendMessageDialog()

  12. {

  13. delete ui;

  14. }

  15. mailio::message SendMessageDialog::get_message()

  16. {

  17. QRegularExpression delim("[,;\t ]+");

  18. mailio::message message;

  19. QString subject = ui->subject_line_edit->text();

  20. QStringList recipients = ui->recipients_line_edit->text().split(delim, Qt::SkipEmptyParts);

  21. QStringList cc_recipients = ui->cc_recipients_line_edit->text().split(delim, Qt::SkipEmptyParts);

  22. QStringList bcc_recipients = ui->bcc_recipients_line_edit->text().split(delim, Qt::SkipEmptyParts);

  23. QString content = ui->content_text_edit->toPlainText();

  24. message.subject(subject.toStdString());

  25. for (auto recipient : recipients)

  26. {

  27. auto recipient_s = recipient.simplified().toStdString();

  28. message.add_recipient(mailio::mail_address(recipient_s, recipient_s));

  29. }

  30. for (auto recipient : cc_recipients)

  31. {

  32. auto recipient_s = recipient.simplified().toStdString();

  33. message.add_cc_recipient(mailio::mail_address(recipient_s, recipient_s));

  34. }

  35. for (auto recipient : bcc_recipients)

  36. {

  37. auto recipient_s = recipient.simplified().toStdString();

  38. message.add_bcc_recipient(mailio::mail_address(recipient_s, recipient_s));

  39. }

  40. message.content_transfer_encoding(mailio::mime::content_transfer_encoding_t::BASE_64);

  41. message.content_type(mailio::message::media_type_t::TEXT, "plain", "utf-8");

  42. message.content(content.toStdString());

  43. if (!attachments.empty())

  44. {

  45. std::list<std::tuple<std::istream &, std::string, mailio::message::content_type_t>> attachments_tlist;

  46. for (auto attachment : attachments)

  47. {

  48. std::shared_ptr<std::stringstream> ss;

  49. std::string filename;

  50. mailio::message::content_type_t content_type;

  51. std::tie(ss, filename, content_type) = attachment;

  52. attachments_tlist.emplace_back(

  53. std::tuple<std::istream &, std::string, mailio::message::content_type_t>(*ss, filename, content_type));

  54. }

  55. message.attach(attachments_tlist);

  56. }

  57. return message;

  58. }

  59. void SendMessageDialog::on_add_attachment_clicked()

  60. {

  61. try

  62. {

  63. QString filename = QFileDialog::getOpenFileName(this, "Добавить вложение", "", "All files (*.*)");

  64. if (filename.isEmpty())

  65. {

  66. return;

  67. }

  68. std::fstream file_stream(filename.toStdWString().c_str(), std::ios::in | std::ios::binary);

  69. if (!file_stream.is_open())

  70. {

  71. QMessageBox::warning(this, "Внимание", "Файл недоступен для чтения");

  72. return;

  73. }

  74. file_stream.seekg(0, file_stream.end);

  75. std::basic_istream<char>::pos_type size = file_stream.tellg();

  76. file_stream.seekg(0, file_stream.beg);

  77. std::string attachment_size;

  78. constexpr size_t kb = 1 << 10, mb = kb << 10, gb = mb << 10;

  79. if (size >= gb)

  80. {

  81. size = size * 100 / gb;

  82. attachment_size = std::to_string(size / 100) + "." + std::to_string(size % 100) + " ГиБ";

  83. }

  84. else if (size >= mb)

  85. {

  86. size = size * 100 / mb;

  87. attachment_size = std::to_string(size / 100) + "." + std::to_string(size % 100) + " МиБ";

  88. }

  89. else if (size >= kb)

  90. {

  91. size = size * 100 / kb;

  92. attachment_size = std::to_string(size / 100) + "." + std::to_string(size % 100) + " КиБ";

  93. }

  94. else

  95. {

  96. attachment_size = std::to_string(size) + " Б";

  97. }

  98. std::shared_ptr<std::stringstream> ss = std::make_shared<std::stringstream>();

  99. std::ostream &os = *ss;

  100. os << ((std::istream &)file_stream).rdbuf();

  101. ss->seekg(0, ss->beg);

  102. file_stream.close();

  103. std::string filename_s = filename.toStdString();

  104. std::string base_filename = filename_s.substr(filename_s.find_last_of("/\\") + 1);

  105. int new_last_index = ui->attachments_table->rowCount();

  106. attachments.emplace_back(

  107. std::tuple<std::shared_ptr<std::stringstream>, std::string, mailio::message::content_type_t>(

  108. ss, base_filename, mailio::message::content_type_t(mailio::message::media_type_t::MULTIPART, "mixed")));

  109. ui->attachments_table->setRowCount(new_last_index + 1);

  110. ui->attachments_table->setItem(new_last_index, 0, new QTableWidgetItem(QString::fromStdString(base_filename)));

  111. ui->attachments_table->setItem(new_last_index, 1,

  112. new QTableWidgetItem(QString::fromStdString(attachment_size)));

  113. ui->attachments_table->setItem(new_last_index, 2, new QTableWidgetItem(filename));

  114. ui->attachments_table->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents);

  115. }

  116. catch (const std::exception &exc)

  117. {

  118. QMessageBox::critical(this, "Внимание", "Ошибка добавления вложения");

  119. }

  120. }

  121. void SendMessageDialog::on_remove_attachment_clicked()

  122. {

  123. try

  124. {

  125. if (ui->attachments_table->currentItem() != nullptr)

  126. {

  127. int current_row = ui->attachments_table->currentRow();

  128. auto it = attachments.begin();

  129. std::advance(it, current_row);

  130. attachments.erase(it);

  131. ui->attachments_table->removeRow(current_row);

  132. ui->attachments_table->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents);

  133. }

  134. }

  135. catch (const std::exception &exc)

  136. {

  137. QMessageBox::critical(this, "Внимание", "Ошибка удаления вложения");

  138. }

  139. }

  140. void SendMessageDialog::closeEvent(QCloseEvent *event)

  141. {

  142. if (QMessageBox::question(this, "Внимание", "Сообщение не будет отправлено и/или сохранено. Продолжить?",

  143. QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)

  144. {

  145. event->accept();

  146. }

  147. else

  148. {

  149. event->ignore();

  150. }

  151. }

Модуль «settings_dialog.h»

  1. #ifndef SETTINGS_DIALOG_H

  2. #define SETTINGS_DIALOG_H

  3. #include <QCloseEvent>

  4. #include <QDialog>

  5. #include "imap_settings.h"

  6. #include "smtp_settings.h"

  7. namespace Ui

  8. {

  9. class SettingsDialog;

  10. }

  11. class SettingsDialog : public QDialog

  12. {

  13. Q_OBJECT

  14. public:

  15. explicit SettingsDialog(QWidget *parent = nullptr);

  16. void set_imap_settings(const ImapSettings &arg_imap_settings);

  17. void set_smtp_settings(const SmtpSettings &arg_smtp_settings);

  18. ImapSettings get_imap_settings() const;

  19. SmtpSettings get_smtp_settings() const;

  20. ~SettingsDialog() override;

  21. private slots:

  22. void on_mail_server_combo_box_textActivated(const QString &text);

  23. void on_smtp_login_line_edit_textEdited(const QString &arg1);

  24. private:

  25. void closeEvent(QCloseEvent *event) override;

  26. Ui::SettingsDialog *ui;

  27. };

  28. #endif // SETTINGS_DIALOG_H

Модуль «settings_dialog.cpp»

  1. #include <QMessageBox>

  2. #include "settings_dialog.h"

  3. #include "ui_settings_dialog.h"

  4. SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::SettingsDialog)

  5. {

  6. ui->setupUi(this);

  7. this->setFixedSize(QSize(540, 360));

  8. }

  9. SettingsDialog::~SettingsDialog()

  10. {

  11. delete ui;

  12. }

  13. void SettingsDialog::set_imap_settings(const ImapSettings &arg_imap_settings)

  14. {

  15. ui->imap_server_line_edit->setText(QString::fromStdString(arg_imap_settings.get_server_address()));

  16. ui->imap_port_spin_box->setValue(arg_imap_settings.get_server_port());

  17. ui->imap_login_line_edit->setText(QString::fromStdString(arg_imap_settings.get_login()));

  18. ui->imap_password_line_edit->setText(QString::fromStdString(arg_imap_settings.get_password()));

  19. ui->autoupdate_check_box->setChecked(arg_imap_settings.get_autoupdate());

  20. ui->autoupdate_spin_box->setValue(arg_imap_settings.get_autoupdate_interval());

  21. mailio::imaps::auth_method_t method = arg_imap_settings.get_auth_method();

  22. if (method == mailio::imaps::auth_method_t::LOGIN)

  23. {

  24. ui->imap_auth_combo_box->setCurrentText("LOGIN");

  25. }

  26. else if (method == mailio::imaps::auth_method_t::START_TLS)

  27. {

  28. ui->imap_auth_combo_box->setCurrentText("START_TLS");

  29. }

  30. else

  31. {

  32. ui->imap_auth_combo_box->setCurrentText("");

  33. }

  34. if (ui->imap_server_line_edit->text().contains("yandex", Qt::CaseInsensitive))

  35. {

  36. ui->mail_server_combo_box->setCurrentText("Yandex");

  37. }

  38. else if (ui->imap_server_line_edit->text().contains("gmail", Qt::CaseInsensitive))

  39. {

  40. ui->mail_server_combo_box->setCurrentText("Gmail");

  41. }

  42. else if (ui->imap_server_line_edit->text().contains("mail.ru", Qt::CaseInsensitive))

  43. {

  44. ui->mail_server_combo_box->setCurrentText("Mail.ru");

  45. }

  46. else

  47. {

  48. ui->mail_server_combo_box->clearEditText();

  49. }

  50. }

  51. void SettingsDialog::set_smtp_settings(const SmtpSettings &arg_smtp_settings)

  52. {

  53. ui->smtp_server_line_edit->setText(QString::fromStdString(arg_smtp_settings.get_server_address()));

  54. ui->smtp_port_spin_box->setValue(arg_smtp_settings.get_server_port());

  55. ui->smtp_login_line_edit->setText(QString::fromStdString(arg_smtp_settings.get_login()));

  56. ui->smtp_password_line_edit->setText(QString::fromStdString(arg_smtp_settings.get_password()));

  57. ui->smtp_name_line_edit->setText(QString::fromStdString(arg_smtp_settings.get_name()));

  58. mailio::smtps::auth_method_t method = arg_smtp_settings.get_auth_method();

  59. if (method == mailio::smtps::auth_method_t::LOGIN)

  60. {

  61. ui->smtp_auth_combo_box->setCurrentText("LOGIN");

  62. }

  63. else if (method == mailio::smtps::auth_method_t::START_TLS)

  64. {

  65. ui->smtp_auth_combo_box->setCurrentText("START_TLS");

  66. }

  67. else if (method == mailio::smtps::auth_method_t::NONE)

  68. {

  69. ui->smtp_auth_combo_box->setCurrentText("NONE");

  70. }

  71. else

  72. {

  73. ui->smtp_auth_combo_box->setCurrentText("");

  74. }

  75. if (ui->mail_server_combo_box->currentText().isEmpty())

  76. {

  77. if (ui->smtp_server_line_edit->text().contains("yandex", Qt::CaseInsensitive))

  78. {

  79. ui->mail_server_combo_box->setCurrentText("Yandex");

  80. }

  81. else if (ui->smtp_server_line_edit->text().contains("gmail", Qt::CaseInsensitive))

  82. {

  83. ui->mail_server_combo_box->setCurrentText("Gmail");

  84. }

  85. else if (ui->smtp_server_line_edit->text().contains("mail.ru", Qt::CaseInsensitive))

  86. {

  87. ui->mail_server_combo_box->setCurrentText("Mail.ru");

  88. }

  89. }

  90. }

  91. ImapSettings SettingsDialog::get_imap_settings() const

  92. {

  93. ImapSettings new_imap_settings;

  94. new_imap_settings.set_server_address(ui->imap_server_line_edit->text().toStdString());

  95. new_imap_settings.set_server_port(ui->imap_port_spin_box->value());

  96. new_imap_settings.set_login(ui->imap_login_line_edit->text().toStdString());

  97. new_imap_settings.set_password(ui->imap_password_line_edit->text().toStdString());

  98. new_imap_settings.set_autoupdate(ui->autoupdate_check_box->isChecked());

  99. new_imap_settings.set_autoupdate_interval(ui->autoupdate_spin_box->value());

  100. if (ui->imap_auth_combo_box->currentText() == "LOGIN")

  101. {

  102. new_imap_settings.set_auth_method(mailio::imaps::auth_method_t::LOGIN);

  103. }

  104. else if (ui->imap_auth_combo_box->currentText() == "START_TLS")

  105. {

  106. new_imap_settings.set_auth_method(mailio::imaps::auth_method_t::START_TLS);

  107. }

  108. else

  109. {

  110. new_imap_settings.set_auth_method(mailio::imaps::auth_method_t::LOGIN);

  111. }

  112. return new_imap_settings;

  113. }

  114. SmtpSettings SettingsDialog::get_smtp_settings() const

  115. {

  116. SmtpSettings new_smtp_settings;

  117. new_smtp_settings.set_server_address(ui->smtp_server_line_edit->text().toStdString());

  118. new_smtp_settings.set_server_port(ui->smtp_port_spin_box->value());

  119. new_smtp_settings.set_login(ui->smtp_login_line_edit->text().toStdString());

  120. new_smtp_settings.set_password(ui->smtp_password_line_edit->text().toStdString());

  121. new_smtp_settings.set_name(ui->smtp_name_line_edit->text().toStdString());

  122. if (ui->smtp_auth_combo_box->currentText() == "LOGIN")

  123. {

  124. new_smtp_settings.set_auth_method(mailio::smtps::auth_method_t::LOGIN);

  125. }

  126. else if (ui->smtp_auth_combo_box->currentText() == "START_TLS")

  127. {

  128. new_smtp_settings.set_auth_method(mailio::smtps::auth_method_t::START_TLS);

  129. }

  130. else if (ui->smtp_auth_combo_box->currentText() == "NONE")

  131. {

  132. new_smtp_settings.set_auth_method(mailio::smtps::auth_method_t::NONE);

  133. }

  134. else

  135. {

  136. new_smtp_settings.set_auth_method(mailio::smtps::auth_method_t::LOGIN);

  137. }

  138. return new_smtp_settings;

  139. }

  140. void SettingsDialog::on_mail_server_combo_box_textActivated(const QString &text)

  141. {

  142. if (text == "Yandex")

  143. {

  144. // imap

  145. ui->imap_server_line_edit->setText("imap.yandex.ru");

  146. ui->imap_port_spin_box->setValue(993);

  147. std::string imap_login = ui->imap_login_line_edit->text().toStdString();

  148. imap_login = imap_login.substr(0, imap_login.find('@')) + "@yandex.ru";

  149. ui->imap_login_line_edit->setText(QString::fromStdString(imap_login));

  150. ui->imap_auth_combo_box->setCurrentText("LOGIN");

  151. // smtp

  152. ui->smtp_server_line_edit->setText("smtp.yandex.ru");

  153. ui->smtp_port_spin_box->setValue(465);

  154. std::string smtp_login = ui->smtp_login_line_edit->text().toStdString();

  155. smtp_login = smtp_login.substr(0, smtp_login.find('@')) + "@yandex.ru";

  156. ui->smtp_login_line_edit->setText(QString::fromStdString(smtp_login));

  157. ui->smtp_auth_combo_box->setCurrentText("LOGIN");

  158. }

  159. else if (text == "Gmail")

  160. {

  161. // imap

  162. ui->imap_server_line_edit->setText("imap.gmail.com");

  163. ui->imap_port_spin_box->setValue(993);

  164. std::string imap_login = ui->imap_login_line_edit->text().toStdString();

  165. imap_login = imap_login.substr(0, imap_login.find('@')) + "@gmail.com";

  166. ui->imap_login_line_edit->setText(QString::fromStdString(imap_login));

  167. ui->imap_auth_combo_box->setCurrentText("LOGIN");

  168. // smtp

  169. ui->smtp_server_line_edit->setText("smtp.gmail.com");

  170. ui->smtp_port_spin_box->setValue(465);

  171. std::string smtp_login = ui->smtp_login_line_edit->text().toStdString();

  172. smtp_login = smtp_login.substr(0, smtp_login.find('@')) + "@gmail.com";

  173. ui->smtp_login_line_edit->setText(QString::fromStdString(smtp_login));

  174. ui->smtp_auth_combo_box->setCurrentText("LOGIN");

  175. }

  176. else if (text == "Mail.ru")

  177. {

  178. // imap

  179. ui->imap_server_line_edit->setText("imap.mail.ru");

  180. ui->imap_port_spin_box->setValue(993);

  181. std::string imap_login = ui->imap_login_line_edit->text().toStdString();

  182. imap_login = imap_login.substr(0, imap_login.find('@')) + "@mail.ru";

  183. ui->imap_login_line_edit->setText(QString::fromStdString(imap_login));

  184. ui->imap_auth_combo_box->setCurrentText("LOGIN");

  185. // smtp

  186. ui->smtp_server_line_edit->setText("smtp.mail.ru");

  187. ui->smtp_port_spin_box->setValue(465);

  188. std::string smtp_login = ui->smtp_login_line_edit->text().toStdString();

  189. smtp_login = smtp_login.substr(0, smtp_login.find('@')) + "@mail.ru";

  190. ui->smtp_login_line_edit->setText(QString::fromStdString(smtp_login));

  191. ui->smtp_auth_combo_box->setCurrentText("LOGIN");

  192. }

  193. }

  194. void SettingsDialog::on_smtp_login_line_edit_textEdited(const QString &login)

  195. {

  196. std::string s = login.toStdString();

  197. s = s.substr(0, s.find('@'));

  198. ui->smtp_name_line_edit->setText(QString::fromStdString(s));

  199. }

  200. void SettingsDialog::closeEvent(QCloseEvent *event)

  201. {

  202. if (QMessageBox::question(this, "Внимание", "Настройки не будут сохранены. Продолжить?",

  203. QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)

  204. {

  205. event->accept();

  206. }

  207. else

  208. {

  209. event->ignore();

  210. }

  211. }

Модуль «mainwindow.h»

  1. #ifndef MAINWINDOW_H

  2. #define MAINWINDOW_H

  3. #include <mutex>

  4. #include <unordered_map>

  5. #include <unordered_set>

  6. #include <QCloseEvent>

  7. #include <QMainWindow>

  8. #include <QTableWidget>

  9. #include <QTextDocument>

  10. #include <QTextDocumentFragment>

  11. #include <QThread>

  12. #include <QTreeWidget>

  13. #include "imap_settings.h"

  14. #include "smtp_settings.h"

  15. QT_BEGIN_NAMESPACE

  16. namespace Ui

  17. {

  18. class MainWindow;

  19. }

  20. QT_END_NAMESPACE

  21. class ThreadForManualUpdate; // declaration for thread_for_manual_update attribute in MainWindow class

  22. class ThreadForAutoUpdate; // declaration for thread_for_update attribute in MainWindow class

  23. class MainWindow : public QMainWindow

  24. {

  25. Q_OBJECT

  26. public:

  27. MainWindow(QWidget *parent = nullptr);

  28. ~MainWindow() override;

  29. private slots:

  30. void update_folders_and_messages_ui();

  31. void on_update_folders_and_messages_triggered();

  32. void on_set_up_account_triggered();

  33. void on_exit_program_triggered();

  34. void on_add_folder_triggered();

  35. void on_rename_folder_triggered();

  36. void on_delete_selected_folder_triggered();

  37. void on_send_message_triggered();

  38. void on_download_attachment_triggered();

  39. void on_copy_selected_message_triggered();

  40. void on_delete_selected_message_triggered();

  41. void on_clear_all_and_disable_autoupdate_triggered();

  42. void on_show_message_statistics_triggered();

  43. void on_show_about_window_triggered();

  44. void on_folders_tree_itemClicked(QTreeWidgetItem *, int);

  45. void on_messages_table_itemClicked(QTableWidgetItem *);

  46. void on_search_query_textChanged(const QString &);

  47. void on_search_query_returnPressed();

  48. private:

  49. void update_folders_and_messages();

  50. void folder_chosen_ui();

  51. static int get_number_of_folders_recursive(QTreeWidgetItem *twi);

  52. static void list_folders_recursive(

  53. QTreeWidgetItem *twi, const mailio::imaps::mailbox_folder_t &folder, mailio::imaps &conn,

  54. const std::list<std::string> &path, std::unordered_map<std::string, mailio::message> &messages,

  55. std::unordered_map<std::string, unsigned long long> &messages_sizes,

  56. std::map<std::list<std::string>, std::unordered_set<std::string>> &mailboxes_to_messages_ids,

  57. std::unordered_map<std::string, unsigned long> &messages_ids_to_uids,

  58. std::unordered_map<unsigned long, std::string> &uids_to_messages_ids);

  59. static std::string get_current_datetime_as_string();

  60. static std::string local_date_time_as_string(const boost::local_time::local_date_time &ldt);

  61. void closeEvent(QCloseEvent *event) override;

  62. void clear_all();

  63. Ui::MainWindow *ui;

  64. QTextDocument empty_text_document;

  65. ImapSettings imap_settings;

  66. SmtpSettings smtp_settings;

  67. ThreadForManualUpdate *thread_for_manual_update;

  68. ThreadForAutoUpdate *thread_for_auto_update;

  69. std::mutex main_mutex;

  70. QList<QTreeWidgetItem *> folders;

  71. std::list<std::string> current_item;

  72. std::unordered_map<std::string, unsigned long long> messages_sizes;

  73. std::unordered_map<std::string, mailio::message> messages;

  74. std::unordered_map<std::string, unsigned long> messages_ids_to_uids;

  75. std::unordered_map<std::string, QTextDocument> messages_ids_to_text_documents;

  76. std::unordered_map<unsigned long, std::string> uids_to_messages_ids;

  77. std::map<std::list<std::string>, std::unordered_set<std::string>> mailboxes_to_messages_ids;

  78. std::chrono::system_clock::time_point start;

  79. const std::chrono::duration<long long int> timeout = std::chrono::seconds(5000);

  80. bool update_status;

  81. std::string update_status_message;

  82. friend class ThreadForManualUpdate;

  83. friend class ThreadForAutoUpdate;

  84. };

  85. class ThreadForManualUpdate : public QThread

  86. {

  87. Q_OBJECT

  88. public:

  89. explicit ThreadForManualUpdate(MainWindow *mainwindow) : mainwindow(mainwindow)

  90. {

  91. if (!mainwindow)

  92. {

  93. throw std::runtime_error("mainwindow is null");

  94. }

  95. }

  96. ~ThreadForManualUpdate()

  97. {

  98. }

  99. void run()

  100. {

  101. std::lock_guard<std::mutex> main_lock(mainwindow->main_mutex);

  102. mainwindow->update_folders_and_messages();

  103. emit folders_and_messages_updated();

  104. }

  105. private:

  106. MainWindow *mainwindow;

  107. signals:

  108. void folders_and_messages_updated();

  109. };

  110. class ThreadForAutoUpdate : public QThread

  111. {

  112. Q_OBJECT

  113. public:

  114. explicit ThreadForAutoUpdate(MainWindow *mainwindow, const ImapSettings *imap_settings)

  115. : mainwindow(mainwindow), imap_settings(imap_settings)

  116. {

  117. if (!mainwindow)

  118. {

  119. throw std::runtime_error("mainwindow is null");

  120. }

  121. if (!imap_settings)

  122. {

  123. throw std::runtime_error("imap_settings is null");

  124. }

  125. }

  126. ~ThreadForAutoUpdate()

  127. {

  128. }

  129. void run()

  130. {

  131. this->current_second = 1;

  132. while (true)

  133. {

  134. if (imap_settings->get_autoupdate())

  135. {

  136. if (this->current_second < imap_settings->get_autoupdate_interval())

  137. {

  138. this->current_second += 1;

  139. }

  140. else

  141. {

  142. this->current_second = 1;

  143. std::lock_guard<std::mutex> main_lock(mainwindow->main_mutex);

  144. mainwindow->update_folders_and_messages();

  145. emit folders_and_messages_updated();

  146. }

  147. }

  148. else

  149. {

  150. this->current_second = 1;

  151. }

  152. QThread::sleep(1);

  153. }

  154. }

  155. private:

  156. MainWindow *mainwindow;

  157. const ImapSettings *imap_settings;

  158. int current_second;

  159. signals:

  160. void folders_and_messages_updated();

  161. };

  162. #endif // MAINWINDOW_H

Модуль «mainwindow.cpp»

  1. #include <QInputDialog>

  2. #include <QMessageBox>

  3. #include "mainwindow.h"

  4. #include "send_message_dialog.h"

  5. #include "settings_dialog.h"

  6. #include "tools.h"

  7. #include "ui_mainwindow.h"

  8. MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)

  9. {

  10. ui->setupUi(this);

  11. ui->folders_tree->header()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents);

  12. ui->folders_tree->setSortingEnabled(true);

  13. ui->folders_tree->sortByColumn(0, Qt::AscendingOrder);

  14. ui->messages_table->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents);

  15. ui->messages_table->setSortingEnabled(true);

  16. ui->messages_table->sortByColumn(2, Qt::DescendingOrder);

  17. // imap initial settings

  18. imap_settings.set_server_address("imap.yandex.ru");

  19. imap_settings.set_server_port(993);

  20. imap_settings.set_login("robert.wayne.alx@yandex.ru");

  21. imap_settings.set_password("Robw12345");

  22. imap_settings.set_autoupdate(false);

  23. imap_settings.set_autoupdate_interval(10);

  24. imap_settings.set_auth_method(mailio::imaps::auth_method_t::LOGIN);

  25. // smtp initial settings

  26. smtp_settings.set_server_address("smtp.yandex.ru");

  27. smtp_settings.set_server_port(465);

  28. smtp_settings.set_login("robert.wayne.alx@yandex.ru");

  29. smtp_settings.set_password("Robw12345");

  30. smtp_settings.set_name("robert.wayne.alx");

  31. smtp_settings.set_auth_method(mailio::smtps::auth_method_t::LOGIN);

  32. // other

  33. ui->messages_table->hideColumn(ui->messages_table->columnCount() - 1);

  34. ui->folders_tree->hideColumn(ui->folders_tree->columnCount() - 1);

  35. ui->horizontal_splitter->setStretchFactor(0, 0);

  36. ui->horizontal_splitter->setStretchFactor(1, 1);

  37. this->update_status = true;

  38. // threads for update folders and messages

  39. thread_for_auto_update = new ThreadForAutoUpdate(this, &imap_settings);

  40. connect(thread_for_auto_update, SIGNAL(folders_and_messages_updated()), this,

  41. SLOT(update_folders_and_messages_ui()));

  42. thread_for_manual_update = new ThreadForManualUpdate(this);

  43. connect(thread_for_manual_update, SIGNAL(folders_and_messages_updated()), this,

  44. SLOT(update_folders_and_messages_ui()));

  45. thread_for_auto_update->start();

  46. }

  47. MainWindow::~MainWindow()

  48. {

  49. delete ui;

  50. }

  51. void MainWindow::update_folders_and_messages()

  52. {

  53. try

  54. {

  55. this->start = std::chrono::system_clock::now();

  56. mailio::imaps conn = mailio::imaps(imap_settings.get_server_address(),

  57. static_cast<unsigned>(imap_settings.get_server_port()), timeout);

  58. conn.authenticate(imap_settings.get_login(), imap_settings.get_password(), imap_settings.get_auth_method());

  59. mailio::imaps::mailbox_folder_t mailbox_main_folder = conn.list_folders("");

  60. std::unordered_map<std::string, unsigned long> new_messages_ids_to_uids;

  61. std::unordered_map<unsigned long, std::string> new_uids_to_messages_ids;

  62. std::map<std::list<std::string>, std::unordered_set<std::string>> new_mailboxes_to_messages_ids;

  63. QTreeWidgetItem root;

  64. list_folders_recursive(&root, mailbox_main_folder, conn, std::list<std::string>(), this->messages,

  65. this->messages_sizes, new_mailboxes_to_messages_ids, new_messages_ids_to_uids,

  66. new_uids_to_messages_ids);

  67. QList<QTreeWidgetItem *> new_folders;

  68. for (size_t i = 0, n = root.childCount(); i < n; ++i)

  69. {

  70. new_folders.emplace_back(root.child(i)->clone());

  71. }

  72. this->messages_ids_to_uids = new_messages_ids_to_uids;

  73. this->uids_to_messages_ids = new_uids_to_messages_ids;

  74. this->mailboxes_to_messages_ids = new_mailboxes_to_messages_ids;

  75. this->folders.swap(new_folders);

  76. this->update_status = true;

  77. this->update_status_message.clear();

  78. }

  79. catch (const std::exception &exc)

  80. {

  81. this->update_status = false;

  82. this->update_status_message = "Список папок с сообщениями не обновлен: " + std::string(exc.what());

  83. }

  84. }

  85. void MainWindow::list_folders_recursive(

  86. QTreeWidgetItem *twi, const mailio::imaps::mailbox_folder_t &folder, mailio::imaps &conn,

  87. const std::list<std::string> &path, std::unordered_map<std::string, mailio::message> &messages,

  88. std::unordered_map<std::string, unsigned long long> &messages_sizes,

  89. std::map<std::list<std::string>, std::unordered_set<std::string>> &mailboxes_to_messages_ids,

  90. std::unordered_map<std::string, unsigned long> &messages_ids_to_uids,

  91. std::unordered_map<unsigned long, std::string> &uids_to_messages_ids)

  92. {

  93. for (auto &folder : folder.folders)

  94. {

  95. try

  96. {

  97. std::list<std::string> new_list(path);

  98. new_list.emplace_back(folder.first);

  99. mailboxes_to_messages_ids[new_list];

  100. QTreeWidgetItem *child = new QTreeWidgetItem();

  101. twi->addChild(child);

  102. child->setText(0, utf7decode(QString::fromStdString(folder.first)));

  103. child->setText(3, QString::fromStdString(folder.first));

  104. if (!folder.second.folders.empty())

  105. {

  106. list_folders_recursive(child, folder.second, conn, new_list, messages, messages_sizes,

  107. mailboxes_to_messages_ids, messages_ids_to_uids, uids_to_messages_ids);

  108. }

  109. mailio::imaps::mailbox_stat_t stat;

  110. try

  111. {

  112. stat = conn.select(new_list, true);

  113. }

  114. catch (...)

  115. {

  116. stat.messages_unseen = 0;

  117. stat.messages_no = 0;

  118. }

  119. child->setText(1, QString::number(stat.messages_unseen));

  120. child->setText(2, QString::number(stat.messages_no));

  121. std::list<mailio::imaps::messages_range_t> ranges;

  122. ranges.emplace_back(mailio::imaps::messages_range_t(1, std::optional<unsigned long>(-1)));

  123. std::map<unsigned long, mailio::message> found_messages;

  124. try

  125. {

  126. conn.fetch(ranges, found_messages, true, true, mailio::codec::line_len_policy_t::VERYLARGE);

  127. }

  128. catch (...)

  129. {

  130. child->setText(1, "-");

  131. child->setText(2, "-");

  132. continue;

  133. }

  134. if (found_messages.empty())

  135. {

  136. child->setText(1, "0");

  137. child->setText(2, "0");

  138. continue;

  139. }

  140. for (auto message_it = found_messages.begin(); message_it != found_messages.end(); ++message_it)

  141. {

  142. try

  143. {

  144. unsigned long uid = message_it->first;

  145. mailio::message current_message = message_it->second;

  146. std::string message_id = current_message.message_id();

  147. messages_ids_to_uids[message_id] = uid;

  148. uids_to_messages_ids[uid] = message_id;

  149. mailboxes_to_messages_ids[new_list].insert(message_id);

  150. if (messages.find(message_id) == messages.end())

  151. {

  152. // update if empty

  153. messages[message_id] = current_message;

  154. std::string message_source;

  155. current_message.format(message_source);

  156. messages_sizes[message_id] = message_source.size();

  157. // try to get full message (may except)

  158. try

  159. {

  160. conn.fetch(uid, current_message, true, false);

  161. current_message.format(message_source, false);

  162. QString qmessage_source = QString::fromStdString(message_source);

  163. qmessage_source.replace("This is a MIME-encapsulated message.", "");

  164. message_source = qmessage_source.toStdString();

  165. messages[message_id].parse(message_source, false);

  166. messages_sizes[message_id] = message_source.size();

  167. if (current_message.parts().empty())

  168. {

  169. std::string::size_type pos = message_source.find("\r\n\r\n");

  170. if (pos == std::string::npos)

  171. {

  172. continue;

  173. }

  174. std::string content = message_source.substr(pos + 4, std::string::npos);

  175. messages[message_id].content(content);

  176. }

  177. }

  178. catch (...)

  179. {

  180. // try another way

  181. std::string new_message_id(message_id);

  182. while (new_message_id.size() > 2)

  183. {

  184. new_message_id.assign(new_message_id.begin() + 1, new_message_id.end() - 1);

  185. if (messages.find(new_message_id) != messages.end())

  186. {

  187. messages[new_message_id].format(message_source, false);

  188. messages[message_id].parse(message_source, false);

  189. messages_sizes[message_id] = message_source.size();

  190. break;

  191. }

  192. }

  193. }

  194. }

  195. }

  196. catch (...)

  197. {

  198. }

  199. }

  200. }

  201. catch (...)

  202. {

  203. }

  204. }

  205. }

  206. void MainWindow::update_folders_and_messages_ui()

  207. {

  208. if (!this->update_status)

  209. {

  210. std::string current_datetime_s = get_current_datetime_as_string();

  211. QString log_message = QString::fromStdString(current_datetime_s + ". " + this->update_status_message);

  212. ui->status_bar->showMessage(log_message);

  213. ui->logs_text_edit->appendPlainText(log_message);

  214. return;

  215. }

  216. try

  217. {

  218. std::string update_message;

  219. bool ok = false;

  220. try

  221. {

  222. ui->folders_tree->clear();

  223. ui->folders_tree->addTopLevelItems(this->folders);

  224. ui->folders_tree->expandAll();

  225. int width = 0;

  226. for (int i = 0, n = ui->folders_tree->columnCount(); i < n; ++i)

  227. {

  228. width += ui->folders_tree->columnWidth(i);

  229. }

  230. ui->horizontal_splitter->setSizes(QList<int>{width + 10, ui->centralwidget->width() - width - 10});

  231. std::chrono::duration<double> sec = std::chrono::system_clock::now() - this->start;

  232. update_message = "Список папок с сообщениями обновлен, сообщения с вложениями доступны оффлайн (" +

  233. std::to_string(sec.count()) + " сек.)";

  234. ok = true;

  235. }

  236. catch (const std::exception &exc)

  237. {

  238. update_message = "Список папок с сообщениями не обновлен: " + std::string(exc.what());

  239. }

  240. std::string current_datetime_s = get_current_datetime_as_string();

  241. QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);

  242. ui->status_bar->showMessage(log_message);

  243. ui->logs_text_edit->appendPlainText(log_message);

  244. if (ok)

  245. {

  246. folder_chosen_ui();

  247. }

  248. }

  249. catch (const std::exception &exc)

  250. {

  251. QString log_message =

  252. QString::fromStdString("Ошибка обновления списка папок с сообщениями: " + std::string(exc.what()));

  253. ui->status_bar->showMessage(log_message);

  254. ui->logs_text_edit->appendPlainText(log_message);

  255. }

  256. }

  257. void MainWindow::folder_chosen_ui()

  258. {

  259. try

  260. {

  261. QTreeWidgetItem *current_folder = ui->folders_tree->currentItem();

  262. std::list<std::string> folder_name;

  263. if (current_folder == nullptr)

  264. {

  265. if (this->current_item.empty())

  266. {

  267. return;

  268. }

  269. folder_name = this->current_item;

  270. }

  271. else

  272. {

  273. QTreeWidgetItem *current = current_folder;

  274. while (current)

  275. {

  276. folder_name.emplace_front(current->text(3).toStdString());

  277. current = current->parent();

  278. }

  279. this->current_item = folder_name;

  280. }

  281. unsigned long index = 0, n_messages = 0;

  282. std::list<std::tuple<unsigned long, unsigned long, QTableWidgetItem *>> cells;

  283. std::unordered_set<std::string> current_messages = this->mailboxes_to_messages_ids[folder_name];

  284. constexpr unsigned long long kb = 1 << 10, mb = kb << 10, gb = mb << 10;

  285. for (auto it = current_messages.begin(); it != current_messages.end(); ++it, ++index)

  286. {

  287. try

  288. {

  289. unsigned long uid = this->messages_ids_to_uids[*it];

  290. mailio::message current_message = this->messages[*it];

  291. std::string message_id = current_message.message_id();

  292. QTableWidgetItem *r0item, *r1item, *r2item, *r3item, *r4item, *r5item, *r6item, *r7item;

  293. try

  294. {

  295. r0item = new QTableWidgetItem(QString::fromStdString(current_message.subject()).simplified());

  296. }

  297. catch (...)

  298. {

  299. r0item = new QTableWidgetItem("[undefined]");

  300. }

  301. cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 0, r0item));

  302. ++n_messages;

  303. try

  304. {

  305. r1item =

  306. new QTableWidgetItem(QString::fromStdString(current_message.from_to_string()).simplified());

  307. }

  308. catch (...)

  309. {

  310. r1item = new QTableWidgetItem("[undefined]");

  311. }

  312. cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 1, r1item));

  313. try

  314. {

  315. r2item = new QTableWidgetItem(

  316. QString::fromStdString(local_date_time_as_string(current_message.date_time())));

  317. }

  318. catch (...)

  319. {

  320. r2item = new QTableWidgetItem("[undefined]");

  321. }

  322. cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 2, r2item));

  323. try

  324. {

  325. r3item = new QTableWidgetItem(

  326. QString::fromStdString(current_message.recipients_to_string()).simplified());

  327. }

  328. catch (...)

  329. {

  330. r3item = new QTableWidgetItem("[undefined]");

  331. }

  332. cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 3, r3item));

  333. try

  334. {

  335. r4item = new QTableWidgetItem(QString::number(current_message.attachments_size()));

  336. }

  337. catch (...)

  338. {

  339. r4item = new QTableWidgetItem("[undefined]");

  340. }

  341. cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 4, r4item));

  342. try

  343. {

  344. unsigned long long size = this->messages_sizes[message_id];

  345. std::string size_s;

  346. if (size >= gb)

  347. {

  348. size = size * 100 / gb;

  349. size_s = std::to_string(size / 100) + "." + std::to_string(size % 100) + " ГиБ";

  350. }

  351. else if (size >= mb)

  352. {

  353. size = size * 100 / mb;

  354. size_s = std::to_string(size / 100) + "." + std::to_string(size % 100) + " МиБ";

  355. }

  356. else if (size >= kb)

  357. {

  358. size = size * 100 / kb;

  359. size_s = std::to_string(size / 100) + "." + std::to_string(size % 100) + " КиБ";

  360. }

  361. else

  362. {

  363. size_s = std::to_string(size) + " Б";

  364. }

  365. r5item = new QTableWidgetItem(QString::fromStdString(size_s));

  366. }

  367. catch (...)

  368. {

  369. r5item = new QTableWidgetItem("[undefined]");

  370. }

  371. cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 5, r5item));

  372. try

  373. {

  374. r6item = new QTableWidgetItem(QString::number(uid));

  375. }

  376. catch (...)

  377. {

  378. r6item = new QTableWidgetItem("[undefined]");

  379. }

  380. cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 6, r6item));

  381. r7item = new QTableWidgetItem(QString::fromStdString(*it));

  382. cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 7, r7item));

  383. if (this->messages_ids_to_text_documents.find(message_id) == this->messages_ids_to_text_documents.end())

  384. {

  385. QString all_parts;

  386. std::vector<mailio::mime> mimes = current_message.parts();

  387. if (mimes.empty())

  388. {

  389. all_parts += QString::fromStdString(current_message.content());

  390. }

  391. for (const mailio::mime &mime : mimes)

  392. {

  393. mailio::mime::content_disposition_t content_disposition(mime.content_disposition());

  394. if (content_disposition != mailio::mime::content_disposition_t::ATTACHMENT)

  395. {

  396. mailio::message::content_type_t content_type(mime.content_type());

  397. if (content_type.type == mailio::mime::media_type_t::TEXT && content_type.subtype == "html")

  398. {

  399. all_parts += QString::fromStdString(mime.content());

  400. }

  401. else

  402. {

  403. all_parts +=

  404. QTextDocumentFragment::fromPlainText(QString::fromStdString(mime.content()))

  405. .toHtml();

  406. }

  407. }

  408. }

  409. this->messages_ids_to_text_documents[message_id].setHtml(all_parts);

  410. }

  411. }

  412. catch (const std::exception &exc)

  413. {

  414. ui->logs_text_edit->appendPlainText(

  415. QString::fromStdString("Ошибка чтения сообщения " + *it + ": " + std::string(exc.what())));

  416. }

  417. }

  418. ui->messages_table->setSortingEnabled(false);

  419. ui->messages_table->setRowCount(0);

  420. ui->messages_table->setRowCount(n_messages);

  421. unsigned long row, col;

  422. QTableWidgetItem *item;

  423. for (auto cell : cells)

  424. {

  425. std::tie(row, col, item) = cell;

  426. ui->messages_table->setItem(row, col, item);

  427. }

  428. ui->messages_table->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents);

  429. ui->messages_table->setSortingEnabled(true);

  430. }

  431. catch (const std::exception &exc)

  432. {

  433. QString log_message =

  434. QString::fromStdString("Ошибка чтения сообщений выбранной папки: " + std::string(exc.what()));

  435. ui->status_bar->showMessage(log_message);

  436. ui->logs_text_edit->appendPlainText(log_message);

  437. }

  438. }

  439. void MainWindow::on_update_folders_and_messages_triggered()

  440. {

  441. if (!thread_for_manual_update->isRunning())

  442. {

  443. thread_for_manual_update->start();

  444. }

  445. }

  446. void MainWindow::on_set_up_account_triggered()

  447. {

  448. std::lock_guard<std::mutex> main_lock(main_mutex);

  449. try

  450. {

  451. SettingsDialog new_settings_dialog;

  452. new_settings_dialog.set_imap_settings(imap_settings);

  453. new_settings_dialog.set_smtp_settings(smtp_settings);

  454. if (new_settings_dialog.exec() == QDialog::Accepted)

  455. {

  456. ImapSettings new_imap_settings = new_settings_dialog.get_imap_settings();

  457. SmtpSettings new_smtp_settings = new_settings_dialog.get_smtp_settings();

  458. imap_settings = new_imap_settings;

  459. smtp_settings = new_smtp_settings;

  460. }

  461. }

  462. catch (const std::exception &exc)

  463. {

  464. QMessageBox::critical(this, "Ошибка", exc.what());

  465. }

  466. }

  467. void MainWindow::on_exit_program_triggered()

  468. {

  469. std::lock_guard<std::mutex> main_lock(main_mutex);

  470. try

  471. {

  472. if (QMessageBox::question(this, "Внимание", "Вы уверены, что хотите выйти?", QMessageBox::Yes | QMessageBox::No,

  473. QMessageBox::No) == QMessageBox::Yes)

  474. {

  475. clear_all();

  476. exit(0);

  477. }

  478. }

  479. catch (const std::exception &exc)

  480. {

  481. QMessageBox::critical(this, "Ошибка", exc.what());

  482. }

  483. }

  484. void MainWindow::on_add_folder_triggered()

  485. {

  486. std::lock_guard<std::mutex> main_lock(main_mutex);

  487. try

  488. {

  489. std::list<std::string> folder_name_decoded;

  490. QTreeWidgetItem *current = ui->folders_tree->currentItem();

  491. while (current)

  492. {

  493. folder_name_decoded.emplace_front(current->text(0).toStdString());

  494. current = current->parent();

  495. }

  496. std::string folder_name_s;

  497. for (auto s : folder_name_decoded)

  498. {

  499. folder_name_s += "\\" + s;

  500. }

  501. folder_name_decoded.clear();

  502. bool ok = false;

  503. std::string update_message;

  504. QString text = QInputDialog::getText(this, "Создание новой папки", "Название папки:", QLineEdit::Normal,

  505. QString::fromStdString(folder_name_s), &ok);

  506. if (ok && !text.isEmpty())

  507. {

  508. std::list<std::string> new_folder_name;

  509. std::string new_folder_name_s;

  510. for (auto s : text.split('\\'))

  511. {

  512. if (!s.isEmpty())

  513. {

  514. new_folder_name.emplace_back(utf7encode(s).toStdString());

  515. new_folder_name_s += "\\" + s.toStdString();

  516. }

  517. }

  518. try

  519. {

  520. std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

  521. mailio::imaps conn(imap_settings.get_server_address(),

  522. static_cast<unsigned>(imap_settings.get_server_port()), timeout);

  523. conn.authenticate(imap_settings.get_login(), imap_settings.get_password(),

  524. imap_settings.get_auth_method());

  525. ok = conn.create_folder(new_folder_name);

  526. if (!ok)

  527. {

  528. throw mailio::imap_error("отказано в операции сервером");

  529. }

  530. std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;

  531. update_message = "Папка " + new_folder_name_s + " добавлена (" + std::to_string(sec.count()) + " сек.)";

  532. }

  533. catch (const std::exception &exc)

  534. {

  535. update_message = "Папка " + new_folder_name_s + " не добавлена: " + std::string(exc.what());

  536. }

  537. }

  538. else

  539. {

  540. update_message = "Папка не добавлена: отмена операции";

  541. }

  542. std::string current_datetime_s = get_current_datetime_as_string();

  543. QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);

  544. ui->status_bar->showMessage(log_message);

  545. ui->logs_text_edit->appendPlainText(log_message);

  546. if (ok)

  547. {

  548. main_mutex.unlock();

  549. on_update_folders_and_messages_triggered();

  550. }

  551. }

  552. catch (const std::exception &exc)

  553. {

  554. QMessageBox::critical(this, "Ошибка", exc.what());

  555. }

  556. }

  557. void MainWindow::on_rename_folder_triggered()

  558. {

  559. std::lock_guard<std::mutex> main_lock(main_mutex);

  560. try

  561. {

  562. if (ui->folders_tree->currentItem() == nullptr)

  563. {

  564. QMessageBox::warning(this, "Внимание", "Папка не выбрана");

  565. return;

  566. }

  567. std::list<std::string> old_folder_name, old_folder_name_decoded;

  568. QTreeWidgetItem *current = ui->folders_tree->currentItem();

  569. while (current)

  570. {

  571. old_folder_name_decoded.emplace_front(current->text(0).toStdString());

  572. old_folder_name.emplace_front(current->text(3).toStdString());

  573. current = current->parent();

  574. }

  575. std::string old_folder_name_s;

  576. for (auto s : old_folder_name_decoded)

  577. {

  578. old_folder_name_s += "\\" + s;

  579. }

  580. bool ok = false;

  581. std::string update_message;

  582. QString text =

  583. QInputDialog::getText(this, "Переименование/перемещение папки", "Новое название папки:", QLineEdit::Normal,

  584. QString::fromStdString(old_folder_name_s), &ok);

  585. if (ok && !text.isEmpty())

  586. {

  587. try

  588. {

  589. std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

  590. mailio::imaps conn(imap_settings.get_server_address(),

  591. static_cast<unsigned>(imap_settings.get_server_port()), timeout);

  592. conn.authenticate(imap_settings.get_login(), imap_settings.get_password(),

  593. imap_settings.get_auth_method());

  594. std::list<std::string> new_folder_name;

  595. std::string new_folder_name_s;

  596. for (auto s : text.split('\\'))

  597. {

  598. if (!s.isEmpty())

  599. {

  600. new_folder_name.emplace_back(utf7encode(s).toStdString());

  601. new_folder_name_s += "\\" + s.toStdString();

  602. }

  603. }

  604. ok = conn.rename_folder(old_folder_name, new_folder_name);

  605. if (!ok)

  606. {

  607. throw mailio::imap_error("отказано в операции сервером");

  608. }

  609. std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;

  610. update_message = "Папка " + old_folder_name_s + " переименована -> " + new_folder_name_s + " (" +

  611. std::to_string(sec.count()) + " сек.)";

  612. }

  613. catch (const std::exception &exc)

  614. {

  615. update_message = "Папка " + old_folder_name_s + " не переименована: " + std::string(exc.what());

  616. }

  617. }

  618. else

  619. {

  620. update_message = "Папка " + old_folder_name_s + " не переименована: отмена операции";

  621. }

  622. std::string current_datetime_s = get_current_datetime_as_string();

  623. QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);

  624. ui->status_bar->showMessage(log_message);

  625. ui->logs_text_edit->appendPlainText(log_message);

  626. if (ok)

  627. {

  628. main_mutex.unlock();

  629. on_update_folders_and_messages_triggered();

  630. }

  631. }

  632. catch (const std::exception &exc)

  633. {

  634. QMessageBox::critical(this, "Ошибка", exc.what());

  635. }

  636. }

  637. void MainWindow::on_delete_selected_folder_triggered()

  638. {

  639. std::lock_guard<std::mutex> main_lock(main_mutex);

  640. try

  641. {

  642. std::list<std::string> folder_name, folder_name_decoded;

  643. std::string folder_name_s;

  644. QTreeWidgetItem *current = ui->folders_tree->currentItem();

  645. while (current)

  646. {

  647. folder_name_decoded.emplace_front(current->text(0).toStdString());

  648. folder_name.emplace_front(current->text(3).toStdString());

  649. current = current->parent();

  650. }

  651. for (auto s : folder_name_decoded)

  652. {

  653. folder_name_s += "\\" + s;

  654. };

  655. std::string update_message;

  656. bool ok = (QMessageBox::question(

  657. this, "Внимание",

  658. QString::fromStdString("Вы уверены, что хотите удалить папку " + folder_name_s + "?"),

  659. QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes);

  660. if (ok)

  661. {

  662. try

  663. {

  664. std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

  665. mailio::imaps conn(imap_settings.get_server_address(),

  666. static_cast<unsigned>(imap_settings.get_server_port()), timeout);

  667. conn.authenticate(imap_settings.get_login(), imap_settings.get_password(),

  668. imap_settings.get_auth_method());

  669. ok = conn.delete_folder(folder_name);

  670. if (!ok)

  671. {

  672. throw mailio::imap_error("отказано в операции сервером");

  673. }

  674. std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;

  675. update_message = "Папка " + folder_name_s + " удалена (" + std::to_string(sec.count()) + " сек.)";

  676. }

  677. catch (const std::exception &exc)

  678. {

  679. update_message = "Папка " + folder_name_s + " не удалена: " + std::string(exc.what());

  680. }

  681. }

  682. else

  683. {

  684. update_message = "Папка " + folder_name_s + " не удалена: отмена операции";

  685. }

  686. std::string current_datetime_s = get_current_datetime_as_string();

  687. QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);

  688. ui->status_bar->showMessage(log_message);

  689. ui->logs_text_edit->appendPlainText(log_message);

  690. if (ok)

  691. {

  692. main_mutex.unlock();

  693. on_update_folders_and_messages_triggered();

  694. }

  695. }

  696. catch (const std::exception &exc)

  697. {

  698. QMessageBox::critical(this, "Ошибка", exc.what());

  699. }

  700. }

  701. void MainWindow::on_send_message_triggered()

  702. {

  703. std::lock_guard<std::mutex> main_lock(main_mutex);

  704. try

  705. {

  706. mailio::smtps conn(smtp_settings.get_server_address(), smtp_settings.get_server_port());

  707. conn.authenticate(smtp_settings.get_login(), smtp_settings.get_password(), smtp_settings.get_auth_method());

  708. }

  709. catch (const std::exception &exc)

  710. {

  711. QMessageBox::critical(this, "Ошибка", exc.what());

  712. return;

  713. }

  714. SendMessageDialog new_send_message_dialog;

  715. try

  716. {

  717. while (new_send_message_dialog.exec() == QDialog::Accepted)

  718. {

  719. try

  720. {

  721. mailio::message message = new_send_message_dialog.get_message();

  722. if (message.subject().empty())

  723. {

  724. QMessageBox::warning(this, "Ошибка", "Тема сообщения пуста");

  725. continue;

  726. }

  727. if (message.recipients().empty() && message.cc_recipients().empty() && message.bcc_recipients().empty())

  728. {

  729. QMessageBox::warning(this, "Ошибка", "Получатели отсутствуют");

  730. continue;

  731. }

  732. message.from(mailio::mail_address(smtp_settings.get_name(), smtp_settings.get_login()));

  733. mailio::smtps conn(smtp_settings.get_server_address(), smtp_settings.get_server_port());

  734. conn.authenticate(smtp_settings.get_login(), smtp_settings.get_password(),

  735. smtp_settings.get_auth_method());

  736. std::string status = conn.submit(message);

  737. std::string update_message = "Сообщение отправлено, обновите "

  738. "список папок с сообщениями";

  739. std::string current_datetime_s = get_current_datetime_as_string();

  740. QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);

  741. ui->status_bar->showMessage(log_message);

  742. ui->logs_text_edit->appendPlainText(log_message);

  743. QMessageBox::information(this, "Информация",

  744. "Сообщение отправлено\nОбновите список папок "

  745. "с сообщениями\n\nОтвет сервера:\n" +

  746. QString::fromStdString(status));

  747. break;

  748. }

  749. catch (const std::exception &exc)

  750. {

  751. QMessageBox::warning(this, "Ошибка", exc.what());

  752. }

  753. }

  754. }

  755. catch (const std::exception &exc)

  756. {

  757. QMessageBox::critical(this, "Ошибка", exc.what());

  758. }

  759. }

  760. void MainWindow::on_download_attachment_triggered()

  761. {

  762. std::lock_guard<std::mutex> main_lock(main_mutex);

  763. try

  764. {

  765. QTableWidgetItem *current_item = ui->messages_table->currentItem();

  766. if (current_item == nullptr)

  767. {

  768. QMessageBox::warning(this, "Внимание", "Сообщение не выбрано");

  769. return;

  770. }

  771. std::string current_message_id =

  772. ui->messages_table->item(ui->messages_table->currentRow(), 7)->text().toStdString();

  773. if (messages.find(current_message_id) == messages.end())

  774. {

  775. QMessageBox::warning(this, "Внимание", "Сообщение не найдено");

  776. return;

  777. }

  778. mailio::message current_message = messages[current_message_id];

  779. size_t n_attachments = current_message.attachments_size();

  780. if (n_attachments <= 0)

  781. {

  782. QMessageBox::warning(this, "Внимание", "Вложения в сообщении не найдены");

  783. return;

  784. }

  785. QStringList attachment_names, attachment_names_and_sizes;

  786. std::vector<std::shared_ptr<std::stringstream>> attachments_data_streams;

  787. constexpr unsigned long long kb = 1 << 10, mb = kb << 10, gb = mb << 10;

  788. for (size_t i = 1; i <= n_attachments; ++i)

  789. {

  790. std::string attachment_name, attachment_size;

  791. std::shared_ptr<std::stringstream> ss = std::make_shared<std::stringstream>();

  792. std::istream &is = *ss;

  793. std::ostream &os = *ss;

  794. current_message.attachment(i, os, attachment_name);

  795. is.seekg(0, std::ios::end);

  796. unsigned long long size = is.tellg();

  797. is.seekg(0, std::ios::beg);

  798. if (size >= gb)

  799. {

  800. size = size * 100 / gb;

  801. attachment_size = std::to_string(size / 100) + "." + std::to_string(size % 100) + " ГиБ";

  802. }

  803. else if (size >= mb)

  804. {

  805. size = size * 100 / mb;

  806. attachment_size = std::to_string(size / 100) + "." + std::to_string(size % 100) + " МиБ";

  807. }

  808. else if (size >= kb)

  809. {

  810. size = size * 100 / kb;

  811. attachment_size = std::to_string(size / 100) + "." + std::to_string(size % 100) + " КиБ";

  812. }

  813. else

  814. {

  815. attachment_size = std::to_string(size) + " Б";

  816. }

  817. attachment_names.emplace_back(QString::fromStdString(attachment_name));

  818. attachment_names_and_sizes.emplace_back(

  819. QString::fromStdString(attachment_name + " (" + attachment_size + ")"));

  820. attachments_data_streams.emplace_back(ss);

  821. }

  822. bool ok = false;

  823. std::string update_message;

  824. QString filename_with_size = QInputDialog::getItem(this, "Внимание", "Какое вложение вы хотите скачать?",

  825. attachment_names_and_sizes, 0, false, &ok);

  826. if (ok)

  827. {

  828. size_t p = 0;

  829. if ((p = attachment_names_and_sizes.indexOf(filename_with_size)) < 0)

  830. {

  831. QMessageBox::warning(this, "Внимание", "Вложение не найдено");

  832. return;

  833. }

  834. QString new_filename = QInputDialog::getText(this, "Внимание", "Введите путь и/или имя файла для записи",

  835. QLineEdit::Normal, attachment_names[p], &ok);

  836. if (ok)

  837. {

  838. try

  839. {

  840. std::ofstream file_out(new_filename.toStdWString().c_str(), std::ios::out | std::ios::binary);

  841. file_out << ((std::istream &)*attachments_data_streams[p]).rdbuf();

  842. file_out.close();

  843. update_message = "Файл " + new_filename.toStdString() + " записан";

  844. }

  845. catch (const std::exception &exc)

  846. {

  847. update_message = "Ошибка записи файла на диск: " + std::string(exc.what());

  848. }

  849. }

  850. else

  851. {

  852. update_message = "Сохранение файла отменено";

  853. }

  854. }

  855. else

  856. {

  857. update_message = "Сохранение файла отменено";

  858. }

  859. std::string current_datetime_s = get_current_datetime_as_string();

  860. QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);

  861. ui->status_bar->showMessage(log_message);

  862. ui->logs_text_edit->appendPlainText(log_message);

  863. }

  864. catch (const std::exception &exc)

  865. {

  866. QMessageBox::critical(this, "Ошибка", exc.what());

  867. }

  868. }

  869. void MainWindow::on_copy_selected_message_triggered()

  870. {

  871. std::lock_guard<std::mutex> main_lock(main_mutex);

  872. try

  873. {

  874. QItemSelectionModel *select = ui->messages_table->selectionModel();

  875. if (!select->hasSelection())

  876. {

  877. QMessageBox::warning(this, "Внимание", "Сообщения не выбраны");

  878. return;

  879. }

  880. QList<QString> folders;

  881. for (auto folder : mailboxes_to_messages_ids)

  882. {

  883. QString folder_to_emplace;

  884. for (auto s : folder.first)

  885. {

  886. folder_to_emplace += "\\" + utf7decode(QString::fromStdString(s));

  887. }

  888. folders.emplace_back(folder_to_emplace);

  889. }

  890. bool ok = false;

  891. QString text =

  892. QInputDialog::getItem(this, "Копирование сообщений в папку", "Название папки:", folders, 0, false, &ok);

  893. if (!ok || text.isEmpty())

  894. {

  895. return;

  896. }

  897. std::list<std::string> destination_folder_name;

  898. for (auto s : text.split('\\'))

  899. {

  900. if (!s.isEmpty())

  901. {

  902. destination_folder_name.emplace_back(utf7encode(s).toStdString());

  903. }

  904. }

  905. try

  906. {

  907. std::string update_message;

  908. QModelIndexList selection = select->selectedIndexes();

  909. if (selection.count() == 0)

  910. {

  911. QMessageBox::warning(this, "Внимание", "Сообщения не выбраны");

  912. return;

  913. }

  914. std::unordered_set<int> rows;

  915. for (qsizetype i = 0; i < selection.count(); i++)

  916. {

  917. rows.insert(selection.at(i).row());

  918. }

  919. std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

  920. mailio::imaps conn(imap_settings.get_server_address(),

  921. static_cast<unsigned>(imap_settings.get_server_port()), timeout);

  922. conn.authenticate(imap_settings.get_login(), imap_settings.get_password(), imap_settings.get_auth_method());

  923. for (auto row : rows)

  924. {

  925. QTableWidgetItem *current_uid = ui->messages_table->item(row, 6);

  926. if (current_uid == nullptr || current_uid->text().isEmpty())

  927. {

  928. QMessageBox::warning(this, "Внимание", "UID одного сообщения не найден");

  929. continue;

  930. }

  931. ok = false;

  932. unsigned long uid = current_uid->text().toULong(&ok);

  933. if (!ok)

  934. {

  935. QMessageBox::warning(this, "Внимание", "Неверный UID у одного сообщения");

  936. continue;

  937. }

  938. QTableWidgetItem *current_message_id = ui->messages_table->item(row, 7);

  939. if (current_message_id == nullptr || current_message_id->text().isEmpty())

  940. {

  941. QMessageBox::warning(this, "Внимание", "Message ID одного сообщения не найден");

  942. continue;

  943. }

  944. std::string current_message_id_s = current_message_id->text().toStdString();

  945. std::string datetime_s = ui->messages_table->item(row, 2)->text().toStdString();

  946. try

  947. {

  948. conn.append(destination_folder_name, this->messages[current_message_id_s]);

  949. std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;

  950. update_message = "Сообщение #" + std::to_string(uid) + " (" + datetime_s + ") скопировано (" +

  951. std::to_string(sec.count()) + " сек.)";

  952. }

  953. catch (const std::exception &exc)

  954. {

  955. update_message = "Сообщение #" + std::to_string(uid) + " (" + datetime_s +

  956. ") не скопировано: " + std::string(exc.what());

  957. }

  958. std::string current_datetime_s = get_current_datetime_as_string();

  959. QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);

  960. ui->status_bar->showMessage(log_message);

  961. ui->logs_text_edit->appendPlainText(log_message);

  962. ui->current_message->setDocument(&this->empty_text_document);

  963. }

  964. main_mutex.unlock();

  965. on_update_folders_and_messages_triggered();

  966. }

  967. catch (const std::exception &exc)

  968. {

  969. QMessageBox::critical(this, "Ошибка", exc.what());

  970. }

  971. }

  972. catch (const std::exception &exc)

  973. {

  974. QMessageBox::critical(this, "Ошибка", exc.what());

  975. }

  976. }

  977. void MainWindow::on_delete_selected_message_triggered()

  978. {

  979. std::lock_guard<std::mutex> main_lock(main_mutex);

  980. try

  981. {

  982. QTreeWidgetItem *current_folder = ui->folders_tree->currentItem();

  983. std::list<std::string> folder_name;

  984. if (current_folder == nullptr)

  985. {

  986. if (this->current_item.empty())

  987. {

  988. QMessageBox::warning(this, "Внимание", "Папка не выбрана");

  989. return;

  990. }

  991. folder_name = this->current_item;

  992. }

  993. else

  994. {

  995. QTreeWidgetItem *current = current_folder;

  996. while (current)

  997. {

  998. folder_name.emplace_front(current->text(3).toStdString());

  999. current = current->parent();

  1000. }

  1001. this->current_item = folder_name;

  1002. }

  1003. QItemSelectionModel *select = ui->messages_table->selectionModel();

  1004. if (!select->hasSelection())

  1005. {

  1006. QMessageBox::warning(this, "Внимание", "Сообщения не выбраны");

  1007. return;

  1008. }

  1009. bool ok = (QMessageBox::question(this, "Внимание", "Вы уверены, что хотите удалить выбранные сообщения?",

  1010. QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes);

  1011. if (!ok)

  1012. {

  1013. return;

  1014. }

  1015. try

  1016. {

  1017. std::string update_message;

  1018. QModelIndexList selection = select->selectedIndexes();

  1019. if (selection.count() == 0)

  1020. {

  1021. QMessageBox::warning(this, "Внимание", "Сообщения не выбраны");

  1022. return;

  1023. }

  1024. std::unordered_set<int> rows;

  1025. for (qsizetype i = 0; i < selection.count(); i++)

  1026. {

  1027. rows.insert(selection.at(i).row());

  1028. }

  1029. std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

  1030. mailio::imaps conn(imap_settings.get_server_address(),

  1031. static_cast<unsigned>(imap_settings.get_server_port()), timeout);

  1032. conn.authenticate(imap_settings.get_login(), imap_settings.get_password(), imap_settings.get_auth_method());

  1033. for (auto row : rows)

  1034. {

  1035. QTableWidgetItem *current_uid = ui->messages_table->item(row, 6);

  1036. if (current_uid == nullptr || current_uid->text().isEmpty())

  1037. {

  1038. QMessageBox::warning(this, "Внимание", "UID одного сообщения не найден");

  1039. continue;

  1040. }

  1041. ok = false;

  1042. unsigned long uid = current_uid->text().toULong(&ok);

  1043. if (!ok)

  1044. {

  1045. QMessageBox::warning(this, "Внимание", "Неверный UID у одного сообщения");

  1046. continue;

  1047. }

  1048. std::string datetime_s = ui->messages_table->item(row, 2)->text().toStdString();

  1049. try

  1050. {

  1051. conn.remove(folder_name, uid, true);

  1052. std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;

  1053. update_message = "Сообщение #" + std::to_string(uid) + " (" + datetime_s + ") удалено (" +

  1054. std::to_string(sec.count()) + " сек.)";

  1055. }

  1056. catch (const std::exception &exc)

  1057. {

  1058. update_message = "Сообщение #" + std::to_string(uid) + " (" + datetime_s +

  1059. ") не удалено: " + std::string(exc.what());

  1060. }

  1061. std::string current_datetime_s = get_current_datetime_as_string();

  1062. QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);

  1063. ui->status_bar->showMessage(log_message);

  1064. ui->logs_text_edit->appendPlainText(log_message);

  1065. ui->current_message->setDocument(&this->empty_text_document);

  1066. }

  1067. main_mutex.unlock();

  1068. on_update_folders_and_messages_triggered();

  1069. }

  1070. catch (const std::exception &exc)

  1071. {

  1072. QMessageBox::critical(this, "Ошибка", exc.what());

  1073. }

  1074. }

  1075. catch (const std::exception &exc)

  1076. {

  1077. QMessageBox::critical(this, "Ошибка", exc.what());

  1078. }

  1079. }

  1080. void MainWindow::on_clear_all_and_disable_autoupdate_triggered()

  1081. {

  1082. std::lock_guard<std::mutex> main_lock(main_mutex);

  1083. clear_all();

  1084. }

  1085. void MainWindow::on_show_message_statistics_triggered()

  1086. {

  1087. std::lock_guard<std::mutex> main_lock(main_mutex);

  1088. try

  1089. {

  1090. int n_folders = ui->folders_tree->topLevelItemCount(), n_messages = 0, n_unseen_messages = 0, n_attachments = 0;

  1091. for (int row = 0; row < ui->folders_tree->topLevelItemCount(); ++row)

  1092. {

  1093. n_folders += get_number_of_folders_recursive(ui->folders_tree->topLevelItem(row));

  1094. n_messages += ui->folders_tree->topLevelItem(row)->text(2).toInt();

  1095. n_unseen_messages += ui->folders_tree->topLevelItem(row)->text(1).toInt();

  1096. }

  1097. unsigned long long size = 0;

  1098. constexpr unsigned long long kb = 1 << 10, mb = kb << 10, gb = mb << 10;

  1099. for (auto message_size : this->messages_sizes)

  1100. {

  1101. size += message_size.second;

  1102. }

  1103. std::string size_s;

  1104. if (size >= gb)

  1105. {

  1106. size = size * 100 / gb;

  1107. size_s = std::to_string(size / 100) + "." + std::to_string(size % 100) + " ГиБ";

  1108. }

  1109. else if (size >= mb)

  1110. {

  1111. size = size * 100 / mb;

  1112. size_s = std::to_string(size / 100) + "." + std::to_string(size % 100) + " МиБ";

  1113. }

  1114. else if (size >= kb)

  1115. {

  1116. size = size * 100 / kb;

  1117. size_s = std::to_string(size / 100) + "." + std::to_string(size % 100) + " КиБ";

  1118. }

  1119. else

  1120. {

  1121. size_s = std::to_string(size) + " Б";

  1122. }

  1123. QString s = QString::fromStdString("Общее число папок, включая вложенные: " + std::to_string(n_folders) +

  1124. "\nОбщее число писем во всех папках: " + std::to_string(n_messages) +

  1125. "\nОбщее число непрочитанных писем: " + std::to_string(n_unseen_messages) +

  1126. "\nОбщий размер закэшированных сообщений с вложениями: " + size_s);

  1127. QMessageBox::information(this, "Статистика", s);

  1128. }

  1129. catch (const std::exception &exc)

  1130. {

  1131. QMessageBox::critical(this, "Ошибка", exc.what());

  1132. }

  1133. }

  1134. int MainWindow::get_number_of_folders_recursive(QTreeWidgetItem *twi)

  1135. {

  1136. int n = twi->childCount();

  1137. if (twi)

  1138. {

  1139. for (int c = 0, child_count = twi->childCount(); c < child_count; ++c)

  1140. {

  1141. n += get_number_of_folders_recursive(twi->child(c));

  1142. }

  1143. }

  1144. return n;

  1145. }

  1146. void MainWindow::on_show_about_window_triggered()

  1147. {

  1148. try

  1149. {

  1150. QMessageBox::about(this, "О программе",

  1151. "Курсовая работа по дисциплине ММиВА (СПбГУТ)\n"

  1152. "Тема: Разработка клиентского ПО для получения и "

  1153. "отправки почтовых сообщений\n"

  1154. "Выполнил студент группы ИКПИ-84\n"

  1155. "Коваленко Леонид\n"

  1156. "Санкт-Петербург\n"

  1157. "2022 год");

  1158. }

  1159. catch (const std::exception &exc)

  1160. {

  1161. QMessageBox::critical(this, "Ошибка", exc.what());

  1162. }

  1163. }

  1164. void MainWindow::on_folders_tree_itemClicked(QTreeWidgetItem *,

  1165. int) // not use arguments because concurrent programming!

  1166. {

  1167. std::lock_guard<std::mutex> main_lock(main_mutex);

  1168. folder_chosen_ui();

  1169. }

  1170. void MainWindow::on_messages_table_itemClicked(QTableWidgetItem *)

  1171. {

  1172. std::lock_guard<std::mutex> main_lock(main_mutex);

  1173. try

  1174. {

  1175. QTableWidgetItem *current_message_id = ui->messages_table->item(ui->messages_table->currentRow(), 7);

  1176. if (current_message_id == nullptr || current_message_id->text().isEmpty())

  1177. {

  1178. ui->current_message->setDocument(&this->empty_text_document);

  1179. ui->status_bar->showMessage("Message ID выбранного сообщения не найден");

  1180. return;

  1181. }

  1182. std::string current_message_id_s = current_message_id->text().toStdString();

  1183. if (this->messages_ids_to_text_documents.find(current_message_id_s) ==

  1184. this->messages_ids_to_text_documents.end())

  1185. {

  1186. ui->current_message->setDocument(&this->empty_text_document);

  1187. ui->status_bar->showMessage("Тело выбранного сообщения не найдено");

  1188. return;

  1189. }

  1190. ui->current_message->setDocument(&this->messages_ids_to_text_documents[current_message_id_s]);

  1191. ui->status_bar->showMessage("Сообщение открыто");

  1192. }

  1193. catch (const std::exception &exc)

  1194. {

  1195. QMessageBox::critical(this, "Ошибка", exc.what());

  1196. }

  1197. }

  1198. void MainWindow::on_search_query_textChanged(const QString &query)

  1199. {

  1200. ui->messages_table->setCurrentCell(-1, -1);

  1201. if (query == "")

  1202. {

  1203. return;

  1204. }

  1205. std::lock_guard<std::mutex> main_lock(main_mutex);

  1206. auto find_items = ui->messages_table->findItems(query, Qt::MatchContains);

  1207. std::unordered_set<int> rows;

  1208. for (qsizetype i = 0, n = find_items.size(); i < n; ++i)

  1209. {

  1210. auto item = find_items.at(i);

  1211. item->setSelected(true);

  1212. rows.insert(item->row());

  1213. }

  1214. ui->status_bar->showMessage("Найдено " + QString::number(rows.size()) + " сообщений");

  1215. }

  1216. void MainWindow::on_search_query_returnPressed()

  1217. {

  1218. MainWindow::on_search_query_textChanged(ui->search_query->text());

  1219. }

  1220. std::string MainWindow::get_current_datetime_as_string()

  1221. {

  1222. char buffer[256];

  1223. std::time_t t = std::time(nullptr);

  1224. if (std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", std::localtime(&t)))

  1225. {

  1226. return std::string(buffer);

  1227. }

  1228. return "[undefined]";

  1229. }

  1230. std::string MainWindow::local_date_time_as_string(const boost::local_time::local_date_time &ldt)

  1231. {

  1232. char buffer[256];

  1233. auto dt_tm = boost::local_time::to_tm(ldt);

  1234. if (strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &dt_tm))

  1235. {

  1236. return std::string(buffer);

  1237. }

  1238. return "[undefined]";

  1239. }

  1240. void MainWindow::closeEvent(QCloseEvent *event)

  1241. {

  1242. std::lock_guard<std::mutex> main_lock(main_mutex);

  1243. if (QMessageBox::question(this, "Внимание", "Вы уверены, что хотите выйти?", QMessageBox::Yes | QMessageBox::No,

  1244. QMessageBox::No) == QMessageBox::Yes)

  1245. {

  1246. clear_all();

  1247. event->accept();

  1248. }

  1249. else

  1250. {

  1251. event->ignore();

  1252. }

  1253. }

  1254. void MainWindow::clear_all()

  1255. {

  1256. try

  1257. {

  1258. imap_settings.set_autoupdate(false);

  1259. ui->folders_tree->clear();

  1260. ui->messages_table->clearContents();

  1261. ui->messages_table->setRowCount(0);

  1262. ui->current_message->setDocument(&this->empty_text_document);

  1263. ui->logs_text_edit->clear();

  1264. ui->search_query->clear();

  1265. ui->status_bar->clearMessage();

  1266. update_status = true;

  1267. update_status_message.clear();

  1268. folders.clear();

  1269. current_item.clear();

  1270. messages_sizes.clear();

  1271. messages.clear();

  1272. messages_ids_to_uids.clear();

  1273. messages_ids_to_text_documents.clear();

  1274. uids_to_messages_ids.clear();

  1275. mailboxes_to_messages_ids.clear();

  1276. }

  1277. catch (...)

  1278. {

  1279. }

  1280. }

Модуль «main.cpp»

  1. #include <QApplication>

  2. #include "mainwindow.h"

  3. int main(int argc, char *argv[])

  4. {

  5. setlocale(LC_ALL, "Russian");

  6. QApplication a(argc, argv);

  7. MainWindow w;

  8. w.show();

  9. return a.exec();

  10. }

Исходный код оконных форм

Оконная форма «mainwindow.ui»

  1. <?xml version="1.0" encoding="UTF-8"?><ui version="4.0"><class>MainWindow</class><widget class="QMainWindow" name="MainWindow"><property name="geometry"><rect><x>0</x><y>0</y><width>960</width><height>660</height></rect></property><property name="windowTitle"><string>Почтовый клиент</string></property><property name="windowIcon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/appicon.png</normaloff>:/icons/icons/appicon.png</iconset></property><widget class="QWidget" name="centralwidget"><layout class="QVBoxLayout" name="verticalLayout"><item><widget class="QSplitter" name="vertical_splitter"><property name="orientation"><enum>Qt::Vertical</enum></property><widget class="QSplitter" name="horizontal_splitter"><property name="orientation"><enum>Qt::Horizontal</enum></property><widget class="QTreeWidget" name="folders_tree"><property name="sizePolicy"><sizepolicy hsizetype="Expanding" vsizetype="Expanding"><horstretch>0</horstretch><verstretch>0</verstretch></sizepolicy></property><property name="frameShadow"><enum>QFrame::Raised</enum></property><property name="editTriggers"><set>QAbstractItemView::NoEditTriggers</set></property><property name="expandsOnDoubleClick"><bool>false</bool></property><attribute name="headerStretchLastSection"><bool>false</bool></attribute><column><property name="text"><string>Папка</string></property></column><column><property name="text"><string>Число непрочитанных</string></property></column><column><property name="text"><string>Общее число писем</string></property></column><column><property name="text"><string>Исходное название папки</string></property></column></widget><widget class="QWidget" name="messages_widget"><layout class="QVBoxLayout" name="vertical_layout_2"><item><widget class="QTableWidget" name="messages_table"><property name="sizePolicy"><sizepolicy hsizetype="Expanding" vsizetype="Expanding"><horstretch>0</horstretch><verstretch>0</verstretch></sizepolicy></property><property name="frameShadow"><enum>QFrame::Raised</enum></property><property name="editTriggers"><set>QAbstractItemView::NoEditTriggers</set></property><property name="selectionBehavior"><enum>QAbstractItemView::SelectRows</enum></property><attribute name="horizontalHeaderHighlightSections"><bool>false</bool></attribute><attribute name="horizontalHeaderShowSortIndicator" stdset="0"><bool>true</bool></attribute><attribute name="verticalHeaderHighlightSections"><bool>false</bool></attribute><column><property name="text"><string>Тема</string></property></column><column><property name="text"><string>Отправитель</string></property></column><column><property name="text"><string>Дата</string></property></column><column><property name="text"><string>Получатели</string></property></column><column><property name="text"><string>Число вложений</string></property></column><column><property name="text"><string>Размер сообщения с вложениями</string></property></column><column><property name="text"><string>UID</string></property></column><column><property name="text"><string>Message ID</string></property></column></widget></item><item><widget class="QLineEdit" name="search_query"><property name="placeholderText"><string>Поиск сообщения</string></property><property name="clearButtonEnabled"><bool>true</bool></property></widget></item></layout></widget></widget><widget class="QTextEdit" name="current_message"><property name="frameShadow"><enum>QFrame::Raised</enum></property><property name="undoRedoEnabled"><bool>false</bool></property><property name="readOnly"><bool>true</bool></property><property name="acceptRichText"><bool>false</bool></property><property name="textInteractionFlags"><set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set></property></widget><widget class="QPlainTextEdit" name="logs_text_edit"><property name="maximumSize"><size><width>16777215</width><height>100</height></size></property><property name="frameShadow"><enum>QFrame::Raised</enum></property><property name="readOnly"><bool>true</bool></property></widget></widget></item></layout></widget><widget class="QMenuBar" name="menubar"><property name="geometry"><rect><x>0</x><y>0</y><width>960</width><height>30</height></rect></property><widget class="QMenu" name="menu"><property name="title"><string>Главное</string></property><addaction name="update_folders_and_messages"/><addaction name="set_up_account"/><addaction name="separator"/><addaction name="exit_program"/></widget><widget class="QMenu" name="menu_2"><property name="title"><string>Папки</string></property><addaction name="add_folder"/><addaction name="rename_folder"/><addaction name="delete_selected_folder"/></widget><widget class="QMenu" name="menu_3"><property name="title"><string>Сообщения</string></property><addaction name="send_message"/><addaction name="download_attachment"/><addaction name="separator"/><addaction name="copy_selected_message"/><addaction name="delete_selected_message"/></widget><widget class="QMenu" name="menu_4"><property name="title"><string>Дополнительно</string></property><addaction name="clear_all_and_disable_autoupdate"/><addaction name="show_message_statistics"/><addaction name="show_about_window"/></widget><addaction name="menu"/><addaction name="menu_2"/><addaction name="menu_3"/><addaction name="menu_4"/></widget><widget class="QStatusBar" name="status_bar"/><action name="send_message"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/send_message.png</normaloff>:/icons/icons/send_message.png</iconset></property><property name="text"><string>Отправить сообщение</string></property><property name="shortcut"><string>Ctrl+M</string></property></action><action name="update_folders_and_messages"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/refresh.png</normaloff>:/icons/icons/refresh.png</iconset></property><property name="text"><string>Обновить папки с сообщениями</string></property><property name="shortcut"><string>Ctrl+R</string></property></action><action name="show_message_statistics"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/statistics.png</normaloff>:/icons/icons/statistics.png</iconset></property><property name="text"><string>Статистика</string></property><property name="shortcut"><string>Ctrl+S</string></property></action><action name="show_about_window"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/about.png</normaloff>:/icons/icons/about.png</iconset></property><property name="text"><string>О программе</string></property></action><action name="add_folder"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/add_folder.png</normaloff>:/icons/icons/add_folder.png</iconset></property><property name="text"><string>Добавить папку</string></property><property name="shortcut"><string>Ctrl+F</string></property></action><action name="delete_selected_folder"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/delete_folder.png</normaloff>:/icons/icons/delete_folder.png</iconset></property><property name="text"><string>Удалить выбранную папку</string></property></action><action name="exit_program"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/exit.png</normaloff>:/icons/icons/exit.png</iconset></property><property name="text"><string>Выйти из программы</string></property></action><action name="set_up_account"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/settings.png</normaloff>:/icons/icons/settings.png</iconset></property><property name="text"><string>Настроить учетную запись</string></property></action><action name="delete_selected_message"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/delete_message.png</normaloff>:/icons/icons/delete_message.png</iconset></property><property name="text"><string>Удалить выбранные сообщения безвозвратно</string></property></action><action name="rename_folder"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/rename_folder.png</normaloff>:/icons/icons/rename_folder.png</iconset></property><property name="text"><string>Переименовать выбранную папку</string></property></action><action name="clear_all_and_disable_autoupdate"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/delete_all.png</normaloff>:/icons/icons/delete_all.png</iconset></property><property name="text"><string>Очистить все и отключить автообновление</string></property></action><action name="download_attachment"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/get_attachment.png</normaloff>:/icons/icons/get_attachment.png</iconset></property><property name="text"><string>Скачать вложение выбранного сообщения</string></property></action><action name="copy_selected_message"><property name="icon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/copy_message.png</normaloff>:/icons/icons/copy_message.png</iconset></property><property name="text"><string>Скопировать выбранные сообщения в папку...</string></property></action></widget><tabstops><tabstop>folders_tree</tabstop><tabstop>messages_table</tabstop><tabstop>current_message</tabstop><tabstop>logs_text_edit</tabstop></tabstops><resources><include location="resources.qrc"/></resources><connections/></ui>

Оконная форма «send_message_dialog.ui»

  1. <?xml version="1.0" encoding="UTF-8"?><ui version="4.0"><class>SendMessageDialog</class><widget class="QDialog" name="SendMessageDialog"><property name="geometry"><rect><x>0</x><y>0</y><width>832</width><height>585</height></rect></property><property name="windowTitle"><string>Отправить сообщение</string></property><property name="windowIcon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/send_message.png</normaloff>:/icons/icons/send_message.png</iconset></property><property name="sizeGripEnabled"><bool>true</bool></property><property name="modal"><bool>true</bool></property><layout class="QFormLayout" name="formLayout"><property name="fieldGrowthPolicy"><enum>QFormLayout::AllNonFixedFieldsGrow</enum></property><property name="rowWrapPolicy"><enum>QFormLayout::DontWrapRows</enum></property><property name="horizontalSpacing"><number>10</number></property><property name="verticalSpacing"><number>10</number></property><property name="leftMargin"><number>10</number></property><property name="topMargin"><number>10</number></property><property name="rightMargin"><number>10</number></property><property name="bottomMargin"><number>10</number></property><item row="0" column="0"><widget class="QLabel" name="subject_label"><property name="text"><string>Тема сообщения:</string></property></widget></item><item row="0" column="1"><widget class="QLineEdit" name="subject_line_edit"><property name="text"><string>Привет, мир! Hello, world!</string></property></widget></item><item row="1" column="0"><widget class="QLabel" name="recipients_label"><property name="text"><string>Получатели:</string></property></widget></item><item row="1" column="1"><widget class="QLineEdit" name="recipients_line_edit"><property name="text"><string>robert.wayne.alx@yandex.ru, robert.wayne.alx@ya.ru</string></property></widget></item><item row="2" column="0"><widget class="QLabel" name="cc_recipients_label"><property name="text"><string>Получатели копии:</string></property></widget></item><item row="2" column="1"><widget class="QLineEdit" name="cc_recipients_line_edit"><property name="text"><string>robert.wayne.alx@yandex.by, robert.wayne.alx@yandex.com</string></property></widget></item><item row="3" column="0"><widget class="QLabel" name="bcc_recipients_label"><property name="text"><string>Получатели скрытой копии:</string></property></widget></item><item row="3" column="1"><widget class="QLineEdit" name="bcc_recipients_line_edit"><property name="text"><string>robert.wayne.alx@yandex.ua, robert.wayne.alx@yandex.kz</string></property></widget></item><item row="6" column="0"><widget class="QLabel" name="content_label"><property name="text"><string>Текст сообщения:</string></property></widget></item><item row="7" column="0" colspan="2"><widget class="QPlainTextEdit" name="content_text_edit"><property name="minimumSize"><size><width>0</width><height>0</height></size></property><property name="frameShadow"><enum>QFrame::Raised</enum></property><property name="lineWrapMode"><enum>QPlainTextEdit::NoWrap</enum></property><property name="plainText"><string>Привет, мир!

  2. Hello, world!

  3. </string></property></widget></item><item row="12" column="0"><widget class="QLabel" name="attachment_label"><property name="text"><string>Вложения:</string></property></widget></item><item row="12" column="1"><widget class="QWidget" name="widget" native="true"><property name="sizePolicy"><sizepolicy hsizetype="Preferred" vsizetype="Preferred"><horstretch>0</horstretch><verstretch>0</verstretch></sizepolicy></property><property name="minimumSize"><size><width>0</width><height>40</height></size></property><layout class="QHBoxLayout" name="horizontalLayout"><property name="spacing"><number>10</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="QPushButton" name="add_attachment"><property name="minimumSize"><size><width>0</width><height>30</height></size></property><property name="text"><string>Добавить вложение</string></property></widget></item><item><widget class="QPushButton" name="remove_attachment"><property name="minimumSize"><size><width>0</width><height>30</height></size></property><property name="text"><string>Удалить вложение</string></property></widget></item></layout></widget></item><item row="13" column="0" colspan="2"><widget class="QTableWidget" name="attachments_table"><property name="frameShadow"><enum>QFrame::Raised</enum></property><property name="editTriggers"><set>QAbstractItemView::NoEditTriggers</set></property><property name="selectionMode"><enum>QAbstractItemView::SingleSelection</enum></property><property name="selectionBehavior"><enum>QAbstractItemView::SelectRows</enum></property><attribute name="horizontalHeaderHighlightSections"><bool>false</bool></attribute><attribute name="horizontalHeaderShowSortIndicator" stdset="0"><bool>false</bool></attribute><attribute name="verticalHeaderHighlightSections"><bool>false</bool></attribute><column><property name="text"><string>Имя файла</string></property></column><column><property name="text"><string>Размер файла</string></property></column><column><property name="text"><string>Путь к файлу</string></property></column></widget></item><item row="15" column="0" colspan="2"><widget class="QDialogButtonBox" name="button_box"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="standardButtons"><set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set></property></widget></item><item row="4" column="1"><widget class="QLabel" name="note_label"><property name="text"><string>(получатели указываются через запятую либо пробел)</string></property><property name="alignment"><set>Qt::AlignCenter</set></property></widget></item></layout></widget><resources><include location="resources.qrc"/></resources><connections><connection><sender>button_box</sender><signal>accepted()</signal><receiver>SendMessageDialog</receiver><slot>accept()</slot><hints><hint type="sourcelabel"><x>248</x><y>254</y></hint><hint type="destinationlabel"><x>157</x><y>274</y></hint></hints></connection><connection><sender>button_box</sender><signal>rejected()</signal><receiver>SendMessageDialog</receiver><slot>reject()</slot><hints><hint type="sourcelabel"><x>316</x><y>260</y></hint><hint type="destinationlabel"><x>286</x><y>274</y></hint></hints></connection></connections></ui>

Оконная форма «settings_dialog.ui»

  1. <?xml version="1.0" encoding="UTF-8"?><ui version="4.0"><class>SettingsDialog</class><widget class="QDialog" name="SettingsDialog"><property name="geometry"><rect><x>0</x><y>0</y><width>540</width><height>360</height></rect></property><property name="windowTitle"><string>Настройки</string></property><property name="windowIcon"><iconset resource="resources.qrc"><normaloff>:/icons/icons/settings.png</normaloff>:/icons/icons/settings.png</iconset></property><property name="modal"><bool>true</bool></property><widget class="QDialogButtonBox" name="button_box"><property name="geometry"><rect><x>329</x><y>315</y><width>201</width><height>35</height></rect></property><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="standardButtons"><set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set></property></widget><widget class="QLineEdit" name="imap_server_line_edit"><property name="geometry"><rect><x>80</x><y>80</y><width>170</width><height>30</height></rect></property></widget><widget class="QLabel" name="imap_label"><property name="geometry"><rect><x>10</x><y>50</y><width>240</width><height>24</height></rect></property><property name="text"><string>Настройки IMAP</string></property><property name="alignment"><set>Qt::AlignCenter</set></property></widget><widget class="QLabel" name="imap_server_label"><property name="geometry"><rect><x>10</x><y>80</y><width>70</width><height>25</height></rect></property><property name="text"><string>Сервер:</string></property></widget><widget class="QLabel" name="imap_port_label"><property name="geometry"><rect><x>10</x><y>120</y><width>70</width><height>25</height></rect></property><property name="text"><string>Порт:</string></property></widget><widget class="QComboBox" name="mail_server_combo_box"><property name="geometry"><rect><x>340</x><y>10</y><width>190</width><height>30</height></rect></property><item><property name="text"><string>Yandex</string></property></item><item><property name="text"><string>Gmail</string></property></item><item><property name="text"><string>Mail.ru</string></property></item></widget><widget class="QLabel" name="imap_password_label"><property name="geometry"><rect><x>10</x><y>200</y><width>70</width><height>25</height></rect></property><property name="text"><string>Пароль:</string></property></widget><widget class="QLabel" name="imap_login_label"><property name="geometry"><rect><x>10</x><y>160</y><width>70</width><height>25</height></rect></property><property name="text"><string>Логин:</string></property></widget><widget class="QLineEdit" name="imap_password_line_edit"><property name="geometry"><rect><x>80</x><y>200</y><width>170</width><height>30</height></rect></property><property name="echoMode"><enum>QLineEdit::Password</enum></property></widget><widget class="QLineEdit" name="imap_login_line_edit"><property name="geometry"><rect><x>80</x><y>160</y><width>170</width><height>30</height></rect></property><property name="clearButtonEnabled"><bool>false</bool></property></widget><widget class="QLabel" name="smtp_label"><property name="geometry"><rect><x>290</x><y>50</y><width>240</width><height>24</height></rect></property><property name="text"><string>Настройки SMTP</string></property><property name="alignment"><set>Qt::AlignCenter</set></property></widget><widget class="QLabel" name="smtp_port_label"><property name="geometry"><rect><x>290</x><y>120</y><width>70</width><height>25</height></rect></property><property name="text"><string>Порт:</string></property></widget><widget class="QLineEdit" name="smtp_password_line_edit"><property name="geometry"><rect><x>360</x><y>200</y><width>170</width><height>30</height></rect></property><property name="echoMode"><enum>QLineEdit::Password</enum></property></widget><widget class="QLabel" name="smtp_server_label"><property name="geometry"><rect><x>290</x><y>80</y><width>70</width><height>25</height></rect></property><property name="text"><string>Сервер:</string></property></widget><widget class="QLabel" name="smtp_login_label"><property name="geometry"><rect><x>290</x><y>160</y><width>70</width><height>25</height></rect></property><property name="text"><string>Логин:</string></property></widget><widget class="QLineEdit" name="smtp_login_line_edit"><property name="geometry"><rect><x>360</x><y>160</y><width>170</width><height>30</height></rect></property></widget><widget class="QLabel" name="smtp_password_label"><property name="geometry"><rect><x>290</x><y>200</y><width>70</width><height>25</height></rect></property><property name="text"><string>Пароль:</string></property></widget><widget class="QLineEdit" name="smtp_server_line_edit"><property name="geometry"><rect><x>360</x><y>80</y><width>170</width><height>30</height></rect></property></widget><widget class="QSpinBox" name="autoupdate_spin_box"><property name="geometry"><rect><x>170</x><y>280</y><width>60</width><height>30</height></rect></property><property name="alignment"><set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set></property><property name="correctionMode"><enum>QAbstractSpinBox::CorrectToNearestValue</enum></property><property name="minimum"><number>1</number></property><property name="maximum"><number>86400</number></property></widget><widget class="QCheckBox" name="autoupdate_check_box"><property name="geometry"><rect><x>10</x><y>280</y><width>171</width><height>30</height></rect></property><property name="text"><string>Автообновление:</string></property></widget><widget class="QLabel" name="seconds_label"><property name="geometry"><rect><x>230</x><y>285</y><width>25</width><height>25</height></rect></property><property name="text"><string>с.</string></property><property name="alignment"><set>Qt::AlignCenter</set></property></widget><widget class="QLabel" name="mail_server_label"><property name="geometry"><rect><x>20</x><y>10</y><width>310</width><height>30</height></rect></property><property name="text"><string>Выставить настройки автоматически:</string></property></widget><widget class="QSpinBox" name="imap_port_spin_box"><property name="geometry"><rect><x>80</x><y>120</y><width>171</width><height>30</height></rect></property><property name="correctionMode"><enum>QAbstractSpinBox::CorrectToNearestValue</enum></property><property name="minimum"><number>0</number></property><property name="maximum"><number>65535</number></property><property name="value"><number>993</number></property></widget><widget class="QSpinBox" name="smtp_port_spin_box"><property name="geometry"><rect><x>360</x><y>120</y><width>171</width><height>30</height></rect></property><property name="correctionMode"><enum>QAbstractSpinBox::CorrectToNearestValue</enum></property><property name="minimum"><number>0</number></property><property name="maximum"><number>65535</number></property><property name="value"><number>465</number></property></widget><widget class="QComboBox" name="imap_auth_combo_box"><property name="geometry"><rect><x>80</x><y>240</y><width>170</width><height>30</height></rect></property><item><property name="text"><string>START_TLS</string></property></item><item><property name="text"><string>LOGIN</string></property></item></widget><widget class="QLabel" name="imap_auth_label"><property name="geometry"><rect><x>10</x><y>240</y><width>70</width><height>25</height></rect></property><property name="text"><string>Auth:</string></property></widget><widget class="QLabel" name="smtp_auth_label"><property name="geometry"><rect><x>290</x><y>240</y><width>70</width><height>25</height></rect></property><property name="text"><string>Auth:</string></property></widget><widget class="QComboBox" name="smtp_auth_combo_box"><property name="geometry"><rect><x>360</x><y>240</y><width>170</width><height>30</height></rect></property><item><property name="text"><string>START_TLS</string></property></item><item><property name="text"><string>LOGIN</string></property></item><item><property name="text"><string>NONE</string></property></item></widget><widget class="QLabel" name="smtp_name_label"><property name="geometry"><rect><x>290</x><y>280</y><width>70</width><height>25</height></rect></property><property name="text"><string>Имя:</string></property></widget><widget class="QLineEdit" name="smtp_name_line_edit"><property name="geometry"><rect><x>360</x><y>280</y><width>170</width><height>30</height></rect></property></widget></widget><tabstops><tabstop>mail_server_combo_box</tabstop><tabstop>imap_server_line_edit</tabstop><tabstop>imap_port_spin_box</tabstop><tabstop>imap_login_line_edit</tabstop><tabstop>imap_password_line_edit</tabstop><tabstop>imap_auth_combo_box</tabstop><tabstop>autoupdate_check_box</tabstop><tabstop>autoupdate_spin_box</tabstop><tabstop>smtp_server_line_edit</tabstop><tabstop>smtp_port_spin_box</tabstop><tabstop>smtp_login_line_edit</tabstop><tabstop>smtp_password_line_edit</tabstop><tabstop>smtp_auth_combo_box</tabstop><tabstop>smtp_name_line_edit</tabstop></tabstops><resources><include location="resources.qrc"/></resources><connections><connection><sender>button_box</sender><signal>accepted()</signal><receiver>SettingsDialog</receiver><slot>accept()</slot><hints><hint type="sourcelabel"><x>248</x><y>254</y></hint><hint type="destinationlabel"><x>157</x><y>274</y></hint></hints></connection><connection><sender>button_box</sender><signal>rejected()</signal><receiver>SettingsDialog</receiver><slot>reject()</slot><hints><hint type="sourcelabel"><x>316</x><y>260</y></hint><hint type="destinationlabel"><x>286</x><y>274</y></hint></hints></connection></connections></ui>

Соседние файлы в папке Готовая курсовая работа