- •Курсовая работа
- •Постановка задачи
- •Выбор и настройка инструментов программирования
- •Выбор инструментов программирования
- •Установка и настройка инструментов программирования
- •Разработка графического интерфейса
- •Форма главного окна для отображения папок и сообщений
- •Дополнительные формы
- •Разработка кода
- •Разработка модульной структуры
- •Форма модального окна настроек параметров для авторизации
- •Форма модального окна отправки сообщения с вложениями
- •Разработка кода
- •Класс «ImapSettings»
- •Класс «SmtpSettings»
- •Файлы «tools.H» и «main.Cpp»
- •Класс «SendMessageDialog»
- •Класс «SettingsDialog»
- •Класс «MainWindow»
- •Руководство пользователя
- •Настройка учетной записи
- •Обновление списка папок с сообщениями
- •Отправка сообщения
- •Работа с папками
- •Работа с сообщениями
- •Заключение
- •Список литературы
- •Приложение
Работа с сообщениями
Процесс копирования сообщений представлен на рис. 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.
Список литературы
С. А. Коробов. Лекции по дисциплине «Математические методы и вычислительные алгоритмы современных систем связи».
The Qt Company. Документация Qt 6 [Электронный ресурс] URL: https://doc.qt.io/qt-6/ (дата обращения: 04.03.2022)
Страуструп, Бьярне. Программирование: принципы и практика использования C++, испр. изд. : Пер. с англ. — М. : ООО "И.Д. Вильямс", 2011. — 1248 с. : ил. — Парал. тит. англ. ISBN 978-5-8459-1705-8 (рус.).
Приложение
Сборочный файл «CMakeLists.txt»
cmake_minimum_required(VERSION 3.5)
project(MailClient VERSION 1.0 LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_LIBS ON)
find_package(Boost REQUIRED COMPONENTS regex date_time system)
cmake_policy(SET CMP0074 NEW)
find_package(Mailio REQUIRED)
set(PROJECT_SOURCES
tools.h
imap_settings.cpp
imap_settings.h
smtp_settings.cpp
smtp_settings.h
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
settings_dialog.cpp
settings_dialog.h
settings_dialog.ui
send_message_dialog.cpp
send_message_dialog.h
send_message_dialog.ui
resources.qrc
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(MailClient
MANUAL_FINALIZATION
${PROJECT_SOURCES}
)
# Define target properties for Android with Qt 6 as:
# set_property(TARGET MailClient APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else()
if(ANDROID)
add_library(MailClient SHARED
${PROJECT_SOURCES}
)
# Define properties for Android with Qt 5 after find_package() calls as:
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
else()
add_executable(MailClient
${PROJECT_SOURCES}
)
endif()
endif()
target_link_libraries(MailClient PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
if(Boost_FOUND)
target_include_directories(MailClient PUBLIC ${Boost_INCLUDE_DIRS})
target_link_libraries(MailClient PUBLIC ${Boost_LIBRARIES})
if(Mailio_FOUND)
target_link_libraries(MailClient PUBLIC mailio ${CMAKE_THREAD_LIBS_INIT})
endif()
endif()
find_package(OpenSSL REQUIRED)
target_link_libraries(MailClient PRIVATE OpenSSL::SSL)
set_target_properties(MailClient PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(MailClient)
endif()
Исходный код основных модулей
В сумме 2136 непустых строк кода.
Модуль «imap_settings.h»
#ifndef IMAPSETTINGS_H
#define IMAPSETTINGS_H
#include <mailio/imap.hpp>
class ImapSettings
{
public:
ImapSettings();
// setters
void set_server_address(const std::string &server_address);
void set_server_port(int server_port);
void set_login(const std::string &login);
void set_password(std::string password);
void set_auth_method(const mailio::imaps::auth_method_t &auth_method);
void set_autoupdate(bool autoupdate);
void set_autoupdate_interval(int interval);
// getters
std::string get_server_address() const;
int get_server_port() const;
std::string get_login() const;
std::string get_password() const;
mailio::imaps::auth_method_t get_auth_method() const;
bool get_autoupdate() const;
int get_autoupdate_interval() const;
private:
std::string server_address, login, password;
mailio::imaps::auth_method_t auth_method;
int server_port, autoupdate_interval;
bool autoupdate_enable;
};
#endif // IMAPSETTINGS_H
Модуль «imap_settings.cpp»
#include "imap_settings.h"
ImapSettings::ImapSettings()
{
}
// setters
void ImapSettings::set_server_address(const std::string &server_address)
{
this->server_address = server_address;
}
void ImapSettings::set_server_port(int server_port)
{
this->server_port = server_port;
}
void ImapSettings::set_login(const std::string &login)
{
this->login = login;
}
void ImapSettings::set_password(std::string password)
{
for (size_t i = 0, n = password.length(); i < n; ++i)
{
password[i] ^= 0x01011001 ^ i;
}
this->password = password;
}
void ImapSettings::set_auth_method(const mailio::imaps::auth_method_t &auth_method)
{
this->auth_method = auth_method;
}
void ImapSettings::set_autoupdate(bool autoupdate)
{
this->autoupdate_enable = autoupdate;
}
void ImapSettings::set_autoupdate_interval(int interval)
{
this->autoupdate_interval = interval;
}
// getters
std::string ImapSettings::get_server_address() const
{
return this->server_address;
}
int ImapSettings::get_server_port() const
{
return this->server_port;
}
std::string ImapSettings::get_login() const
{
return this->login;
}
std::string ImapSettings::get_password() const
{
std::string decoded_password(password);
for (size_t i = 0, n = decoded_password.length(); i < n; ++i)
{
decoded_password[i] ^= 0x01011001 ^ i;
}
return decoded_password;
}
mailio::imaps::auth_method_t ImapSettings::get_auth_method() const
{
return this->auth_method;
}
bool ImapSettings::get_autoupdate() const
{
return this->autoupdate_enable;
}
int ImapSettings::get_autoupdate_interval() const
{
return this->autoupdate_interval;
}
Модуль «smtp_settings.h»
#ifndef SMTPSETTINGS_H
#define SMTPSETTINGS_H
#include <mailio/smtp.hpp>
class SmtpSettings
{
public:
SmtpSettings();
// setters
void set_server_address(const std::string &server_address);
void set_server_port(int server_port);
void set_login(const std::string &login);
void set_password(std::string password);
void set_name(const std::string &name);
void set_auth_method(const mailio::smtps::auth_method_t &auth_method);
// getters
std::string get_server_address() const;
int get_server_port() const;
std::string get_login() const;
std::string get_password() const;
std::string get_name() const;
mailio::smtps::auth_method_t get_auth_method() const;
private:
std::string server_address, login, password, name;
int server_port;
mailio::smtps::auth_method_t auth_method;
};
#endif // SMTPSETTINGS_H
Модуль «smtp_settings.cpp»
#include "smtp_settings.h"
SmtpSettings::SmtpSettings()
{
}
// setters
void SmtpSettings::set_server_address(const std::string &server_address)
{
this->server_address = server_address;
}
void SmtpSettings::set_server_port(int server_port)
{
this->server_port = server_port;
}
void SmtpSettings::set_login(const std::string &login)
{
this->login = login;
}
void SmtpSettings::set_password(std::string password)
{
for (size_t i = 0, n = password.length(); i < n; ++i)
{
password[i] ^= 0x10100110 ^ i;
}
this->password = password;
}
void SmtpSettings::set_name(const std::string &name)
{
this->name = name;
}
void SmtpSettings::set_auth_method(const mailio::smtps::auth_method_t &auth_method)
{
this->auth_method = auth_method;
}
// getters
std::string SmtpSettings::get_server_address() const
{
return this->server_address;
}
int SmtpSettings::get_server_port() const
{
return this->server_port;
}
std::string SmtpSettings::get_login() const
{
return this->login;
}
std::string SmtpSettings::get_password() const
{
std::string decoded_password(password);
for (size_t i = 0, n = decoded_password.length(); i < n; ++i)
{
decoded_password[i] ^= 0x10100110 ^ i;
}
return decoded_password;
}
std::string SmtpSettings::get_name() const
{
return this->name;
}
mailio::smtps::auth_method_t SmtpSettings::get_auth_method() const
{
return this->auth_method;
}
Модуль «tools.h»
#ifndef TOOLS_H
#define TOOLS_H
#include <QList>
#include <QString>
#include <QStringConverter>
QString utf7encode(QString str)
{
auto toUtf16be = QStringEncoder(QStringConverter::Utf16BE);
QString unipart, out;
str.replace("&", "&-");
for (QChar ch : str)
{
uint16_t i16 = ch.unicode();
if (0x20 <= i16 && i16 <= 0x7f)
{
if (!unipart.isEmpty())
{
QByteArray unipart16be_bytes = (QByteArray)toUtf16be(unipart);
QString encoded_string(unipart16be_bytes.toBase64(
QByteArray::Base64Option::Base64Encoding | QByteArray::Base64Option::OmitTrailingEquals |
QByteArray::Base64Option::IgnoreBase64DecodingErrors));
out += '&' + encoded_string.replace('/', ',') + '-';
unipart.clear();
}
out += ch;
}
else
{
unipart += ch;
}
}
if (!unipart.isEmpty())
{
QByteArray unipart16be_bytes = (QByteArray)toUtf16be(unipart);
QString encoded_string(unipart16be_bytes.toBase64(QByteArray::Base64Option::Base64Encoding |
QByteArray::Base64Option::OmitTrailingEquals |
QByteArray::Base64Option::IgnoreBase64DecodingErrors));
out += '&' + encoded_string.replace('/', ',') + '-';
unipart.clear();
}
return out;
}
QString utf7decode(const QString &str)
{
auto fromUtf16be = QStringDecoder(QStringConverter::Utf16BE);
QList<QString> parts = str.split('&', Qt::KeepEmptyParts);
if (parts.empty())
{
return QString();
}
QString out = parts[0];
for (qsizetype i = 1, n = parts.size(); i < n; ++i)
{
QString part = parts[i], first, last;
qsizetype pos = part.indexOf('-');
if (pos != -1)
{
first = part.left(pos);
last = part.right(part.size() - pos - 1);
}
else
{
first = part;
}
if (first.isEmpty())
{
out += '&';
}
else
{
first = first.replace(',', '/');
QByteArray decoded_bytes =
QByteArray::fromBase64(first.toUtf8(), QByteArray::Base64Option::Base64Encoding |
QByteArray::Base64Option::OmitTrailingEquals |
QByteArray::Base64Option::IgnoreBase64DecodingErrors);
out += fromUtf16be(decoded_bytes);
}
out += last;
}
return out;
}
#endif // TOOLS_H
Модуль «send_message_dialog.h»
#ifndef SEND_MESSAGE_DIALOG_H
#define SEND_MESSAGE_DIALOG_H
#include <QCloseEvent>
#include <QDialog>
#include <mailio/message.hpp>
namespace Ui
{
class SendMessageDialog;
}
class SendMessageDialog : public QDialog
{
Q_OBJECT
public:
explicit SendMessageDialog(QWidget *parent = nullptr);
mailio::message get_message();
~SendMessageDialog() override;
private slots:
void on_add_attachment_clicked();
void on_remove_attachment_clicked();
private:
void closeEvent(QCloseEvent *event) override;
Ui::SendMessageDialog *ui;
std::list<std::tuple<std::shared_ptr<std::stringstream>, std::string, mailio::message::content_type_t>> attachments;
};
#endif // SEND_MESSAGE_DIALOG_H
Модуль «send_message_dialog.cpp»
#include <QFileDialog>
#include <QMessageBox>
#include "send_message_dialog.h"
#include "ui_send_message_dialog.h"
SendMessageDialog::SendMessageDialog(QWidget *parent) : QDialog(parent), ui(new Ui::SendMessageDialog)
{
ui->setupUi(this);
ui->attachments_table->setSortingEnabled(false);
ui->attachments_table->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents);
}
SendMessageDialog::~SendMessageDialog()
{
delete ui;
}
mailio::message SendMessageDialog::get_message()
{
QRegularExpression delim("[,;\t ]+");
mailio::message message;
QString subject = ui->subject_line_edit->text();
QStringList recipients = ui->recipients_line_edit->text().split(delim, Qt::SkipEmptyParts);
QStringList cc_recipients = ui->cc_recipients_line_edit->text().split(delim, Qt::SkipEmptyParts);
QStringList bcc_recipients = ui->bcc_recipients_line_edit->text().split(delim, Qt::SkipEmptyParts);
QString content = ui->content_text_edit->toPlainText();
message.subject(subject.toStdString());
for (auto recipient : recipients)
{
auto recipient_s = recipient.simplified().toStdString();
message.add_recipient(mailio::mail_address(recipient_s, recipient_s));
}
for (auto recipient : cc_recipients)
{
auto recipient_s = recipient.simplified().toStdString();
message.add_cc_recipient(mailio::mail_address(recipient_s, recipient_s));
}
for (auto recipient : bcc_recipients)
{
auto recipient_s = recipient.simplified().toStdString();
message.add_bcc_recipient(mailio::mail_address(recipient_s, recipient_s));
}
message.content_transfer_encoding(mailio::mime::content_transfer_encoding_t::BASE_64);
message.content_type(mailio::message::media_type_t::TEXT, "plain", "utf-8");
message.content(content.toStdString());
if (!attachments.empty())
{
std::list<std::tuple<std::istream &, std::string, mailio::message::content_type_t>> attachments_tlist;
for (auto attachment : attachments)
{
std::shared_ptr<std::stringstream> ss;
std::string filename;
mailio::message::content_type_t content_type;
std::tie(ss, filename, content_type) = attachment;
attachments_tlist.emplace_back(
std::tuple<std::istream &, std::string, mailio::message::content_type_t>(*ss, filename, content_type));
}
message.attach(attachments_tlist);
}
return message;
}
void SendMessageDialog::on_add_attachment_clicked()
{
try
{
QString filename = QFileDialog::getOpenFileName(this, "Добавить вложение", "", "All files (*.*)");
if (filename.isEmpty())
{
return;
}
std::fstream file_stream(filename.toStdWString().c_str(), std::ios::in | std::ios::binary);
if (!file_stream.is_open())
{
QMessageBox::warning(this, "Внимание", "Файл недоступен для чтения");
return;
}
file_stream.seekg(0, file_stream.end);
std::basic_istream<char>::pos_type size = file_stream.tellg();
file_stream.seekg(0, file_stream.beg);
std::string attachment_size;
constexpr size_t kb = 1 << 10, mb = kb << 10, gb = mb << 10;
if (size >= gb)
{
size = size * 100 / gb;
attachment_size = std::to_string(size / 100) + "." + std::to_string(size % 100) + " ГиБ";
}
else if (size >= mb)
{
size = size * 100 / mb;
attachment_size = std::to_string(size / 100) + "." + std::to_string(size % 100) + " МиБ";
}
else if (size >= kb)
{
size = size * 100 / kb;
attachment_size = std::to_string(size / 100) + "." + std::to_string(size % 100) + " КиБ";
}
else
{
attachment_size = std::to_string(size) + " Б";
}
std::shared_ptr<std::stringstream> ss = std::make_shared<std::stringstream>();
std::ostream &os = *ss;
os << ((std::istream &)file_stream).rdbuf();
ss->seekg(0, ss->beg);
file_stream.close();
std::string filename_s = filename.toStdString();
std::string base_filename = filename_s.substr(filename_s.find_last_of("/\\") + 1);
int new_last_index = ui->attachments_table->rowCount();
attachments.emplace_back(
std::tuple<std::shared_ptr<std::stringstream>, std::string, mailio::message::content_type_t>(
ss, base_filename, mailio::message::content_type_t(mailio::message::media_type_t::MULTIPART, "mixed")));
ui->attachments_table->setRowCount(new_last_index + 1);
ui->attachments_table->setItem(new_last_index, 0, new QTableWidgetItem(QString::fromStdString(base_filename)));
ui->attachments_table->setItem(new_last_index, 1,
new QTableWidgetItem(QString::fromStdString(attachment_size)));
ui->attachments_table->setItem(new_last_index, 2, new QTableWidgetItem(filename));
ui->attachments_table->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents);
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Внимание", "Ошибка добавления вложения");
}
}
void SendMessageDialog::on_remove_attachment_clicked()
{
try
{
if (ui->attachments_table->currentItem() != nullptr)
{
int current_row = ui->attachments_table->currentRow();
auto it = attachments.begin();
std::advance(it, current_row);
attachments.erase(it);
ui->attachments_table->removeRow(current_row);
ui->attachments_table->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents);
}
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Внимание", "Ошибка удаления вложения");
}
}
void SendMessageDialog::closeEvent(QCloseEvent *event)
{
if (QMessageBox::question(this, "Внимание", "Сообщение не будет отправлено и/или сохранено. Продолжить?",
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)
{
event->accept();
}
else
{
event->ignore();
}
}
Модуль «settings_dialog.h»
#ifndef SETTINGS_DIALOG_H
#define SETTINGS_DIALOG_H
#include <QCloseEvent>
#include <QDialog>
#include "imap_settings.h"
#include "smtp_settings.h"
namespace Ui
{
class SettingsDialog;
}
class SettingsDialog : public QDialog
{
Q_OBJECT
public:
explicit SettingsDialog(QWidget *parent = nullptr);
void set_imap_settings(const ImapSettings &arg_imap_settings);
void set_smtp_settings(const SmtpSettings &arg_smtp_settings);
ImapSettings get_imap_settings() const;
SmtpSettings get_smtp_settings() const;
~SettingsDialog() override;
private slots:
void on_mail_server_combo_box_textActivated(const QString &text);
void on_smtp_login_line_edit_textEdited(const QString &arg1);
private:
void closeEvent(QCloseEvent *event) override;
Ui::SettingsDialog *ui;
};
#endif // SETTINGS_DIALOG_H
Модуль «settings_dialog.cpp»
#include <QMessageBox>
#include "settings_dialog.h"
#include "ui_settings_dialog.h"
SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::SettingsDialog)
{
ui->setupUi(this);
this->setFixedSize(QSize(540, 360));
}
SettingsDialog::~SettingsDialog()
{
delete ui;
}
void SettingsDialog::set_imap_settings(const ImapSettings &arg_imap_settings)
{
ui->imap_server_line_edit->setText(QString::fromStdString(arg_imap_settings.get_server_address()));
ui->imap_port_spin_box->setValue(arg_imap_settings.get_server_port());
ui->imap_login_line_edit->setText(QString::fromStdString(arg_imap_settings.get_login()));
ui->imap_password_line_edit->setText(QString::fromStdString(arg_imap_settings.get_password()));
ui->autoupdate_check_box->setChecked(arg_imap_settings.get_autoupdate());
ui->autoupdate_spin_box->setValue(arg_imap_settings.get_autoupdate_interval());
mailio::imaps::auth_method_t method = arg_imap_settings.get_auth_method();
if (method == mailio::imaps::auth_method_t::LOGIN)
{
ui->imap_auth_combo_box->setCurrentText("LOGIN");
}
else if (method == mailio::imaps::auth_method_t::START_TLS)
{
ui->imap_auth_combo_box->setCurrentText("START_TLS");
}
else
{
ui->imap_auth_combo_box->setCurrentText("");
}
if (ui->imap_server_line_edit->text().contains("yandex", Qt::CaseInsensitive))
{
ui->mail_server_combo_box->setCurrentText("Yandex");
}
else if (ui->imap_server_line_edit->text().contains("gmail", Qt::CaseInsensitive))
{
ui->mail_server_combo_box->setCurrentText("Gmail");
}
else if (ui->imap_server_line_edit->text().contains("mail.ru", Qt::CaseInsensitive))
{
ui->mail_server_combo_box->setCurrentText("Mail.ru");
}
else
{
ui->mail_server_combo_box->clearEditText();
}
}
void SettingsDialog::set_smtp_settings(const SmtpSettings &arg_smtp_settings)
{
ui->smtp_server_line_edit->setText(QString::fromStdString(arg_smtp_settings.get_server_address()));
ui->smtp_port_spin_box->setValue(arg_smtp_settings.get_server_port());
ui->smtp_login_line_edit->setText(QString::fromStdString(arg_smtp_settings.get_login()));
ui->smtp_password_line_edit->setText(QString::fromStdString(arg_smtp_settings.get_password()));
ui->smtp_name_line_edit->setText(QString::fromStdString(arg_smtp_settings.get_name()));
mailio::smtps::auth_method_t method = arg_smtp_settings.get_auth_method();
if (method == mailio::smtps::auth_method_t::LOGIN)
{
ui->smtp_auth_combo_box->setCurrentText("LOGIN");
}
else if (method == mailio::smtps::auth_method_t::START_TLS)
{
ui->smtp_auth_combo_box->setCurrentText("START_TLS");
}
else if (method == mailio::smtps::auth_method_t::NONE)
{
ui->smtp_auth_combo_box->setCurrentText("NONE");
}
else
{
ui->smtp_auth_combo_box->setCurrentText("");
}
if (ui->mail_server_combo_box->currentText().isEmpty())
{
if (ui->smtp_server_line_edit->text().contains("yandex", Qt::CaseInsensitive))
{
ui->mail_server_combo_box->setCurrentText("Yandex");
}
else if (ui->smtp_server_line_edit->text().contains("gmail", Qt::CaseInsensitive))
{
ui->mail_server_combo_box->setCurrentText("Gmail");
}
else if (ui->smtp_server_line_edit->text().contains("mail.ru", Qt::CaseInsensitive))
{
ui->mail_server_combo_box->setCurrentText("Mail.ru");
}
}
}
ImapSettings SettingsDialog::get_imap_settings() const
{
ImapSettings new_imap_settings;
new_imap_settings.set_server_address(ui->imap_server_line_edit->text().toStdString());
new_imap_settings.set_server_port(ui->imap_port_spin_box->value());
new_imap_settings.set_login(ui->imap_login_line_edit->text().toStdString());
new_imap_settings.set_password(ui->imap_password_line_edit->text().toStdString());
new_imap_settings.set_autoupdate(ui->autoupdate_check_box->isChecked());
new_imap_settings.set_autoupdate_interval(ui->autoupdate_spin_box->value());
if (ui->imap_auth_combo_box->currentText() == "LOGIN")
{
new_imap_settings.set_auth_method(mailio::imaps::auth_method_t::LOGIN);
}
else if (ui->imap_auth_combo_box->currentText() == "START_TLS")
{
new_imap_settings.set_auth_method(mailio::imaps::auth_method_t::START_TLS);
}
else
{
new_imap_settings.set_auth_method(mailio::imaps::auth_method_t::LOGIN);
}
return new_imap_settings;
}
SmtpSettings SettingsDialog::get_smtp_settings() const
{
SmtpSettings new_smtp_settings;
new_smtp_settings.set_server_address(ui->smtp_server_line_edit->text().toStdString());
new_smtp_settings.set_server_port(ui->smtp_port_spin_box->value());
new_smtp_settings.set_login(ui->smtp_login_line_edit->text().toStdString());
new_smtp_settings.set_password(ui->smtp_password_line_edit->text().toStdString());
new_smtp_settings.set_name(ui->smtp_name_line_edit->text().toStdString());
if (ui->smtp_auth_combo_box->currentText() == "LOGIN")
{
new_smtp_settings.set_auth_method(mailio::smtps::auth_method_t::LOGIN);
}
else if (ui->smtp_auth_combo_box->currentText() == "START_TLS")
{
new_smtp_settings.set_auth_method(mailio::smtps::auth_method_t::START_TLS);
}
else if (ui->smtp_auth_combo_box->currentText() == "NONE")
{
new_smtp_settings.set_auth_method(mailio::smtps::auth_method_t::NONE);
}
else
{
new_smtp_settings.set_auth_method(mailio::smtps::auth_method_t::LOGIN);
}
return new_smtp_settings;
}
void SettingsDialog::on_mail_server_combo_box_textActivated(const QString &text)
{
if (text == "Yandex")
{
// imap
ui->imap_server_line_edit->setText("imap.yandex.ru");
ui->imap_port_spin_box->setValue(993);
std::string imap_login = ui->imap_login_line_edit->text().toStdString();
imap_login = imap_login.substr(0, imap_login.find('@')) + "@yandex.ru";
ui->imap_login_line_edit->setText(QString::fromStdString(imap_login));
ui->imap_auth_combo_box->setCurrentText("LOGIN");
// smtp
ui->smtp_server_line_edit->setText("smtp.yandex.ru");
ui->smtp_port_spin_box->setValue(465);
std::string smtp_login = ui->smtp_login_line_edit->text().toStdString();
smtp_login = smtp_login.substr(0, smtp_login.find('@')) + "@yandex.ru";
ui->smtp_login_line_edit->setText(QString::fromStdString(smtp_login));
ui->smtp_auth_combo_box->setCurrentText("LOGIN");
}
else if (text == "Gmail")
{
// imap
ui->imap_server_line_edit->setText("imap.gmail.com");
ui->imap_port_spin_box->setValue(993);
std::string imap_login = ui->imap_login_line_edit->text().toStdString();
imap_login = imap_login.substr(0, imap_login.find('@')) + "@gmail.com";
ui->imap_login_line_edit->setText(QString::fromStdString(imap_login));
ui->imap_auth_combo_box->setCurrentText("LOGIN");
// smtp
ui->smtp_server_line_edit->setText("smtp.gmail.com");
ui->smtp_port_spin_box->setValue(465);
std::string smtp_login = ui->smtp_login_line_edit->text().toStdString();
smtp_login = smtp_login.substr(0, smtp_login.find('@')) + "@gmail.com";
ui->smtp_login_line_edit->setText(QString::fromStdString(smtp_login));
ui->smtp_auth_combo_box->setCurrentText("LOGIN");
}
else if (text == "Mail.ru")
{
// imap
ui->imap_server_line_edit->setText("imap.mail.ru");
ui->imap_port_spin_box->setValue(993);
std::string imap_login = ui->imap_login_line_edit->text().toStdString();
imap_login = imap_login.substr(0, imap_login.find('@')) + "@mail.ru";
ui->imap_login_line_edit->setText(QString::fromStdString(imap_login));
ui->imap_auth_combo_box->setCurrentText("LOGIN");
// smtp
ui->smtp_server_line_edit->setText("smtp.mail.ru");
ui->smtp_port_spin_box->setValue(465);
std::string smtp_login = ui->smtp_login_line_edit->text().toStdString();
smtp_login = smtp_login.substr(0, smtp_login.find('@')) + "@mail.ru";
ui->smtp_login_line_edit->setText(QString::fromStdString(smtp_login));
ui->smtp_auth_combo_box->setCurrentText("LOGIN");
}
}
void SettingsDialog::on_smtp_login_line_edit_textEdited(const QString &login)
{
std::string s = login.toStdString();
s = s.substr(0, s.find('@'));
ui->smtp_name_line_edit->setText(QString::fromStdString(s));
}
void SettingsDialog::closeEvent(QCloseEvent *event)
{
if (QMessageBox::question(this, "Внимание", "Настройки не будут сохранены. Продолжить?",
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)
{
event->accept();
}
else
{
event->ignore();
}
}
Модуль «mainwindow.h»
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <mutex>
#include <unordered_map>
#include <unordered_set>
#include <QCloseEvent>
#include <QMainWindow>
#include <QTableWidget>
#include <QTextDocument>
#include <QTextDocumentFragment>
#include <QThread>
#include <QTreeWidget>
#include "imap_settings.h"
#include "smtp_settings.h"
QT_BEGIN_NAMESPACE
namespace Ui
{
class MainWindow;
}
QT_END_NAMESPACE
class ThreadForManualUpdate; // declaration for thread_for_manual_update attribute in MainWindow class
class ThreadForAutoUpdate; // declaration for thread_for_update attribute in MainWindow class
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow() override;
private slots:
void update_folders_and_messages_ui();
void on_update_folders_and_messages_triggered();
void on_set_up_account_triggered();
void on_exit_program_triggered();
void on_add_folder_triggered();
void on_rename_folder_triggered();
void on_delete_selected_folder_triggered();
void on_send_message_triggered();
void on_download_attachment_triggered();
void on_copy_selected_message_triggered();
void on_delete_selected_message_triggered();
void on_clear_all_and_disable_autoupdate_triggered();
void on_show_message_statistics_triggered();
void on_show_about_window_triggered();
void on_folders_tree_itemClicked(QTreeWidgetItem *, int);
void on_messages_table_itemClicked(QTableWidgetItem *);
void on_search_query_textChanged(const QString &);
void on_search_query_returnPressed();
private:
void update_folders_and_messages();
void folder_chosen_ui();
static int get_number_of_folders_recursive(QTreeWidgetItem *twi);
static void list_folders_recursive(
QTreeWidgetItem *twi, const mailio::imaps::mailbox_folder_t &folder, mailio::imaps &conn,
const std::list<std::string> &path, std::unordered_map<std::string, mailio::message> &messages,
std::unordered_map<std::string, unsigned long long> &messages_sizes,
std::map<std::list<std::string>, std::unordered_set<std::string>> &mailboxes_to_messages_ids,
std::unordered_map<std::string, unsigned long> &messages_ids_to_uids,
std::unordered_map<unsigned long, std::string> &uids_to_messages_ids);
static std::string get_current_datetime_as_string();
static std::string local_date_time_as_string(const boost::local_time::local_date_time &ldt);
void closeEvent(QCloseEvent *event) override;
void clear_all();
Ui::MainWindow *ui;
QTextDocument empty_text_document;
ImapSettings imap_settings;
SmtpSettings smtp_settings;
ThreadForManualUpdate *thread_for_manual_update;
ThreadForAutoUpdate *thread_for_auto_update;
std::mutex main_mutex;
QList<QTreeWidgetItem *> folders;
std::list<std::string> current_item;
std::unordered_map<std::string, unsigned long long> messages_sizes;
std::unordered_map<std::string, mailio::message> messages;
std::unordered_map<std::string, unsigned long> messages_ids_to_uids;
std::unordered_map<std::string, QTextDocument> messages_ids_to_text_documents;
std::unordered_map<unsigned long, std::string> uids_to_messages_ids;
std::map<std::list<std::string>, std::unordered_set<std::string>> mailboxes_to_messages_ids;
std::chrono::system_clock::time_point start;
const std::chrono::duration<long long int> timeout = std::chrono::seconds(5000);
bool update_status;
std::string update_status_message;
friend class ThreadForManualUpdate;
friend class ThreadForAutoUpdate;
};
class ThreadForManualUpdate : public QThread
{
Q_OBJECT
public:
explicit ThreadForManualUpdate(MainWindow *mainwindow) : mainwindow(mainwindow)
{
if (!mainwindow)
{
throw std::runtime_error("mainwindow is null");
}
}
~ThreadForManualUpdate()
{
}
void run()
{
std::lock_guard<std::mutex> main_lock(mainwindow->main_mutex);
mainwindow->update_folders_and_messages();
emit folders_and_messages_updated();
}
private:
MainWindow *mainwindow;
signals:
void folders_and_messages_updated();
};
class ThreadForAutoUpdate : public QThread
{
Q_OBJECT
public:
explicit ThreadForAutoUpdate(MainWindow *mainwindow, const ImapSettings *imap_settings)
: mainwindow(mainwindow), imap_settings(imap_settings)
{
if (!mainwindow)
{
throw std::runtime_error("mainwindow is null");
}
if (!imap_settings)
{
throw std::runtime_error("imap_settings is null");
}
}
~ThreadForAutoUpdate()
{
}
void run()
{
this->current_second = 1;
while (true)
{
if (imap_settings->get_autoupdate())
{
if (this->current_second < imap_settings->get_autoupdate_interval())
{
this->current_second += 1;
}
else
{
this->current_second = 1;
std::lock_guard<std::mutex> main_lock(mainwindow->main_mutex);
mainwindow->update_folders_and_messages();
emit folders_and_messages_updated();
}
}
else
{
this->current_second = 1;
}
QThread::sleep(1);
}
}
private:
MainWindow *mainwindow;
const ImapSettings *imap_settings;
int current_second;
signals:
void folders_and_messages_updated();
};
#endif // MAINWINDOW_H
Модуль «mainwindow.cpp»
#include <QInputDialog>
#include <QMessageBox>
#include "mainwindow.h"
#include "send_message_dialog.h"
#include "settings_dialog.h"
#include "tools.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->folders_tree->header()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents);
ui->folders_tree->setSortingEnabled(true);
ui->folders_tree->sortByColumn(0, Qt::AscendingOrder);
ui->messages_table->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents);
ui->messages_table->setSortingEnabled(true);
ui->messages_table->sortByColumn(2, Qt::DescendingOrder);
// imap initial settings
imap_settings.set_server_address("imap.yandex.ru");
imap_settings.set_server_port(993);
imap_settings.set_login("robert.wayne.alx@yandex.ru");
imap_settings.set_password("Robw12345");
imap_settings.set_autoupdate(false);
imap_settings.set_autoupdate_interval(10);
imap_settings.set_auth_method(mailio::imaps::auth_method_t::LOGIN);
// smtp initial settings
smtp_settings.set_server_address("smtp.yandex.ru");
smtp_settings.set_server_port(465);
smtp_settings.set_login("robert.wayne.alx@yandex.ru");
smtp_settings.set_password("Robw12345");
smtp_settings.set_name("robert.wayne.alx");
smtp_settings.set_auth_method(mailio::smtps::auth_method_t::LOGIN);
// other
ui->messages_table->hideColumn(ui->messages_table->columnCount() - 1);
ui->folders_tree->hideColumn(ui->folders_tree->columnCount() - 1);
ui->horizontal_splitter->setStretchFactor(0, 0);
ui->horizontal_splitter->setStretchFactor(1, 1);
this->update_status = true;
// threads for update folders and messages
thread_for_auto_update = new ThreadForAutoUpdate(this, &imap_settings);
connect(thread_for_auto_update, SIGNAL(folders_and_messages_updated()), this,
SLOT(update_folders_and_messages_ui()));
thread_for_manual_update = new ThreadForManualUpdate(this);
connect(thread_for_manual_update, SIGNAL(folders_and_messages_updated()), this,
SLOT(update_folders_and_messages_ui()));
thread_for_auto_update->start();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::update_folders_and_messages()
{
try
{
this->start = std::chrono::system_clock::now();
mailio::imaps conn = mailio::imaps(imap_settings.get_server_address(),
static_cast<unsigned>(imap_settings.get_server_port()), timeout);
conn.authenticate(imap_settings.get_login(), imap_settings.get_password(), imap_settings.get_auth_method());
mailio::imaps::mailbox_folder_t mailbox_main_folder = conn.list_folders("");
std::unordered_map<std::string, unsigned long> new_messages_ids_to_uids;
std::unordered_map<unsigned long, std::string> new_uids_to_messages_ids;
std::map<std::list<std::string>, std::unordered_set<std::string>> new_mailboxes_to_messages_ids;
QTreeWidgetItem root;
list_folders_recursive(&root, mailbox_main_folder, conn, std::list<std::string>(), this->messages,
this->messages_sizes, new_mailboxes_to_messages_ids, new_messages_ids_to_uids,
new_uids_to_messages_ids);
QList<QTreeWidgetItem *> new_folders;
for (size_t i = 0, n = root.childCount(); i < n; ++i)
{
new_folders.emplace_back(root.child(i)->clone());
}
this->messages_ids_to_uids = new_messages_ids_to_uids;
this->uids_to_messages_ids = new_uids_to_messages_ids;
this->mailboxes_to_messages_ids = new_mailboxes_to_messages_ids;
this->folders.swap(new_folders);
this->update_status = true;
this->update_status_message.clear();
}
catch (const std::exception &exc)
{
this->update_status = false;
this->update_status_message = "Список папок с сообщениями не обновлен: " + std::string(exc.what());
}
}
void MainWindow::list_folders_recursive(
QTreeWidgetItem *twi, const mailio::imaps::mailbox_folder_t &folder, mailio::imaps &conn,
const std::list<std::string> &path, std::unordered_map<std::string, mailio::message> &messages,
std::unordered_map<std::string, unsigned long long> &messages_sizes,
std::map<std::list<std::string>, std::unordered_set<std::string>> &mailboxes_to_messages_ids,
std::unordered_map<std::string, unsigned long> &messages_ids_to_uids,
std::unordered_map<unsigned long, std::string> &uids_to_messages_ids)
{
for (auto &folder : folder.folders)
{
try
{
std::list<std::string> new_list(path);
new_list.emplace_back(folder.first);
mailboxes_to_messages_ids[new_list];
QTreeWidgetItem *child = new QTreeWidgetItem();
twi->addChild(child);
child->setText(0, utf7decode(QString::fromStdString(folder.first)));
child->setText(3, QString::fromStdString(folder.first));
if (!folder.second.folders.empty())
{
list_folders_recursive(child, folder.second, conn, new_list, messages, messages_sizes,
mailboxes_to_messages_ids, messages_ids_to_uids, uids_to_messages_ids);
}
mailio::imaps::mailbox_stat_t stat;
try
{
stat = conn.select(new_list, true);
}
catch (...)
{
stat.messages_unseen = 0;
stat.messages_no = 0;
}
child->setText(1, QString::number(stat.messages_unseen));
child->setText(2, QString::number(stat.messages_no));
std::list<mailio::imaps::messages_range_t> ranges;
ranges.emplace_back(mailio::imaps::messages_range_t(1, std::optional<unsigned long>(-1)));
std::map<unsigned long, mailio::message> found_messages;
try
{
conn.fetch(ranges, found_messages, true, true, mailio::codec::line_len_policy_t::VERYLARGE);
}
catch (...)
{
child->setText(1, "-");
child->setText(2, "-");
continue;
}
if (found_messages.empty())
{
child->setText(1, "0");
child->setText(2, "0");
continue;
}
for (auto message_it = found_messages.begin(); message_it != found_messages.end(); ++message_it)
{
try
{
unsigned long uid = message_it->first;
mailio::message current_message = message_it->second;
std::string message_id = current_message.message_id();
messages_ids_to_uids[message_id] = uid;
uids_to_messages_ids[uid] = message_id;
mailboxes_to_messages_ids[new_list].insert(message_id);
if (messages.find(message_id) == messages.end())
{
// update if empty
messages[message_id] = current_message;
std::string message_source;
current_message.format(message_source);
messages_sizes[message_id] = message_source.size();
// try to get full message (may except)
try
{
conn.fetch(uid, current_message, true, false);
current_message.format(message_source, false);
QString qmessage_source = QString::fromStdString(message_source);
qmessage_source.replace("This is a MIME-encapsulated message.", "");
message_source = qmessage_source.toStdString();
messages[message_id].parse(message_source, false);
messages_sizes[message_id] = message_source.size();
if (current_message.parts().empty())
{
std::string::size_type pos = message_source.find("\r\n\r\n");
if (pos == std::string::npos)
{
continue;
}
std::string content = message_source.substr(pos + 4, std::string::npos);
messages[message_id].content(content);
}
}
catch (...)
{
// try another way
std::string new_message_id(message_id);
while (new_message_id.size() > 2)
{
new_message_id.assign(new_message_id.begin() + 1, new_message_id.end() - 1);
if (messages.find(new_message_id) != messages.end())
{
messages[new_message_id].format(message_source, false);
messages[message_id].parse(message_source, false);
messages_sizes[message_id] = message_source.size();
break;
}
}
}
}
}
catch (...)
{
}
}
}
catch (...)
{
}
}
}
void MainWindow::update_folders_and_messages_ui()
{
if (!this->update_status)
{
std::string current_datetime_s = get_current_datetime_as_string();
QString log_message = QString::fromStdString(current_datetime_s + ". " + this->update_status_message);
ui->status_bar->showMessage(log_message);
ui->logs_text_edit->appendPlainText(log_message);
return;
}
try
{
std::string update_message;
bool ok = false;
try
{
ui->folders_tree->clear();
ui->folders_tree->addTopLevelItems(this->folders);
ui->folders_tree->expandAll();
int width = 0;
for (int i = 0, n = ui->folders_tree->columnCount(); i < n; ++i)
{
width += ui->folders_tree->columnWidth(i);
}
ui->horizontal_splitter->setSizes(QList<int>{width + 10, ui->centralwidget->width() - width - 10});
std::chrono::duration<double> sec = std::chrono::system_clock::now() - this->start;
update_message = "Список папок с сообщениями обновлен, сообщения с вложениями доступны оффлайн (" +
std::to_string(sec.count()) + " сек.)";
ok = true;
}
catch (const std::exception &exc)
{
update_message = "Список папок с сообщениями не обновлен: " + std::string(exc.what());
}
std::string current_datetime_s = get_current_datetime_as_string();
QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);
ui->status_bar->showMessage(log_message);
ui->logs_text_edit->appendPlainText(log_message);
if (ok)
{
folder_chosen_ui();
}
}
catch (const std::exception &exc)
{
QString log_message =
QString::fromStdString("Ошибка обновления списка папок с сообщениями: " + std::string(exc.what()));
ui->status_bar->showMessage(log_message);
ui->logs_text_edit->appendPlainText(log_message);
}
}
void MainWindow::folder_chosen_ui()
{
try
{
QTreeWidgetItem *current_folder = ui->folders_tree->currentItem();
std::list<std::string> folder_name;
if (current_folder == nullptr)
{
if (this->current_item.empty())
{
return;
}
folder_name = this->current_item;
}
else
{
QTreeWidgetItem *current = current_folder;
while (current)
{
folder_name.emplace_front(current->text(3).toStdString());
current = current->parent();
}
this->current_item = folder_name;
}
unsigned long index = 0, n_messages = 0;
std::list<std::tuple<unsigned long, unsigned long, QTableWidgetItem *>> cells;
std::unordered_set<std::string> current_messages = this->mailboxes_to_messages_ids[folder_name];
constexpr unsigned long long kb = 1 << 10, mb = kb << 10, gb = mb << 10;
for (auto it = current_messages.begin(); it != current_messages.end(); ++it, ++index)
{
try
{
unsigned long uid = this->messages_ids_to_uids[*it];
mailio::message current_message = this->messages[*it];
std::string message_id = current_message.message_id();
QTableWidgetItem *r0item, *r1item, *r2item, *r3item, *r4item, *r5item, *r6item, *r7item;
try
{
r0item = new QTableWidgetItem(QString::fromStdString(current_message.subject()).simplified());
}
catch (...)
{
r0item = new QTableWidgetItem("[undefined]");
}
cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 0, r0item));
++n_messages;
try
{
r1item =
new QTableWidgetItem(QString::fromStdString(current_message.from_to_string()).simplified());
}
catch (...)
{
r1item = new QTableWidgetItem("[undefined]");
}
cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 1, r1item));
try
{
r2item = new QTableWidgetItem(
QString::fromStdString(local_date_time_as_string(current_message.date_time())));
}
catch (...)
{
r2item = new QTableWidgetItem("[undefined]");
}
cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 2, r2item));
try
{
r3item = new QTableWidgetItem(
QString::fromStdString(current_message.recipients_to_string()).simplified());
}
catch (...)
{
r3item = new QTableWidgetItem("[undefined]");
}
cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 3, r3item));
try
{
r4item = new QTableWidgetItem(QString::number(current_message.attachments_size()));
}
catch (...)
{
r4item = new QTableWidgetItem("[undefined]");
}
cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 4, r4item));
try
{
unsigned long long size = this->messages_sizes[message_id];
std::string size_s;
if (size >= gb)
{
size = size * 100 / gb;
size_s = std::to_string(size / 100) + "." + std::to_string(size % 100) + " ГиБ";
}
else if (size >= mb)
{
size = size * 100 / mb;
size_s = std::to_string(size / 100) + "." + std::to_string(size % 100) + " МиБ";
}
else if (size >= kb)
{
size = size * 100 / kb;
size_s = std::to_string(size / 100) + "." + std::to_string(size % 100) + " КиБ";
}
else
{
size_s = std::to_string(size) + " Б";
}
r5item = new QTableWidgetItem(QString::fromStdString(size_s));
}
catch (...)
{
r5item = new QTableWidgetItem("[undefined]");
}
cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 5, r5item));
try
{
r6item = new QTableWidgetItem(QString::number(uid));
}
catch (...)
{
r6item = new QTableWidgetItem("[undefined]");
}
cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 6, r6item));
r7item = new QTableWidgetItem(QString::fromStdString(*it));
cells.emplace_back(std::tuple<unsigned long, unsigned long, QTableWidgetItem *>(index, 7, r7item));
if (this->messages_ids_to_text_documents.find(message_id) == this->messages_ids_to_text_documents.end())
{
QString all_parts;
std::vector<mailio::mime> mimes = current_message.parts();
if (mimes.empty())
{
all_parts += QString::fromStdString(current_message.content());
}
for (const mailio::mime &mime : mimes)
{
mailio::mime::content_disposition_t content_disposition(mime.content_disposition());
if (content_disposition != mailio::mime::content_disposition_t::ATTACHMENT)
{
mailio::message::content_type_t content_type(mime.content_type());
if (content_type.type == mailio::mime::media_type_t::TEXT && content_type.subtype == "html")
{
all_parts += QString::fromStdString(mime.content());
}
else
{
all_parts +=
QTextDocumentFragment::fromPlainText(QString::fromStdString(mime.content()))
.toHtml();
}
}
}
this->messages_ids_to_text_documents[message_id].setHtml(all_parts);
}
}
catch (const std::exception &exc)
{
ui->logs_text_edit->appendPlainText(
QString::fromStdString("Ошибка чтения сообщения " + *it + ": " + std::string(exc.what())));
}
}
ui->messages_table->setSortingEnabled(false);
ui->messages_table->setRowCount(0);
ui->messages_table->setRowCount(n_messages);
unsigned long row, col;
QTableWidgetItem *item;
for (auto cell : cells)
{
std::tie(row, col, item) = cell;
ui->messages_table->setItem(row, col, item);
}
ui->messages_table->horizontalHeader()->resizeSections(QHeaderView::ResizeMode::ResizeToContents);
ui->messages_table->setSortingEnabled(true);
}
catch (const std::exception &exc)
{
QString log_message =
QString::fromStdString("Ошибка чтения сообщений выбранной папки: " + std::string(exc.what()));
ui->status_bar->showMessage(log_message);
ui->logs_text_edit->appendPlainText(log_message);
}
}
void MainWindow::on_update_folders_and_messages_triggered()
{
if (!thread_for_manual_update->isRunning())
{
thread_for_manual_update->start();
}
}
void MainWindow::on_set_up_account_triggered()
{
std::lock_guard<std::mutex> main_lock(main_mutex);
try
{
SettingsDialog new_settings_dialog;
new_settings_dialog.set_imap_settings(imap_settings);
new_settings_dialog.set_smtp_settings(smtp_settings);
if (new_settings_dialog.exec() == QDialog::Accepted)
{
ImapSettings new_imap_settings = new_settings_dialog.get_imap_settings();
SmtpSettings new_smtp_settings = new_settings_dialog.get_smtp_settings();
imap_settings = new_imap_settings;
smtp_settings = new_smtp_settings;
}
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
void MainWindow::on_exit_program_triggered()
{
std::lock_guard<std::mutex> main_lock(main_mutex);
try
{
if (QMessageBox::question(this, "Внимание", "Вы уверены, что хотите выйти?", QMessageBox::Yes | QMessageBox::No,
QMessageBox::No) == QMessageBox::Yes)
{
clear_all();
exit(0);
}
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
void MainWindow::on_add_folder_triggered()
{
std::lock_guard<std::mutex> main_lock(main_mutex);
try
{
std::list<std::string> folder_name_decoded;
QTreeWidgetItem *current = ui->folders_tree->currentItem();
while (current)
{
folder_name_decoded.emplace_front(current->text(0).toStdString());
current = current->parent();
}
std::string folder_name_s;
for (auto s : folder_name_decoded)
{
folder_name_s += "\\" + s;
}
folder_name_decoded.clear();
bool ok = false;
std::string update_message;
QString text = QInputDialog::getText(this, "Создание новой папки", "Название папки:", QLineEdit::Normal,
QString::fromStdString(folder_name_s), &ok);
if (ok && !text.isEmpty())
{
std::list<std::string> new_folder_name;
std::string new_folder_name_s;
for (auto s : text.split('\\'))
{
if (!s.isEmpty())
{
new_folder_name.emplace_back(utf7encode(s).toStdString());
new_folder_name_s += "\\" + s.toStdString();
}
}
try
{
std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
mailio::imaps conn(imap_settings.get_server_address(),
static_cast<unsigned>(imap_settings.get_server_port()), timeout);
conn.authenticate(imap_settings.get_login(), imap_settings.get_password(),
imap_settings.get_auth_method());
ok = conn.create_folder(new_folder_name);
if (!ok)
{
throw mailio::imap_error("отказано в операции сервером");
}
std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
update_message = "Папка " + new_folder_name_s + " добавлена (" + std::to_string(sec.count()) + " сек.)";
}
catch (const std::exception &exc)
{
update_message = "Папка " + new_folder_name_s + " не добавлена: " + std::string(exc.what());
}
}
else
{
update_message = "Папка не добавлена: отмена операции";
}
std::string current_datetime_s = get_current_datetime_as_string();
QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);
ui->status_bar->showMessage(log_message);
ui->logs_text_edit->appendPlainText(log_message);
if (ok)
{
main_mutex.unlock();
on_update_folders_and_messages_triggered();
}
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
void MainWindow::on_rename_folder_triggered()
{
std::lock_guard<std::mutex> main_lock(main_mutex);
try
{
if (ui->folders_tree->currentItem() == nullptr)
{
QMessageBox::warning(this, "Внимание", "Папка не выбрана");
return;
}
std::list<std::string> old_folder_name, old_folder_name_decoded;
QTreeWidgetItem *current = ui->folders_tree->currentItem();
while (current)
{
old_folder_name_decoded.emplace_front(current->text(0).toStdString());
old_folder_name.emplace_front(current->text(3).toStdString());
current = current->parent();
}
std::string old_folder_name_s;
for (auto s : old_folder_name_decoded)
{
old_folder_name_s += "\\" + s;
}
bool ok = false;
std::string update_message;
QString text =
QInputDialog::getText(this, "Переименование/перемещение папки", "Новое название папки:", QLineEdit::Normal,
QString::fromStdString(old_folder_name_s), &ok);
if (ok && !text.isEmpty())
{
try
{
std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
mailio::imaps conn(imap_settings.get_server_address(),
static_cast<unsigned>(imap_settings.get_server_port()), timeout);
conn.authenticate(imap_settings.get_login(), imap_settings.get_password(),
imap_settings.get_auth_method());
std::list<std::string> new_folder_name;
std::string new_folder_name_s;
for (auto s : text.split('\\'))
{
if (!s.isEmpty())
{
new_folder_name.emplace_back(utf7encode(s).toStdString());
new_folder_name_s += "\\" + s.toStdString();
}
}
ok = conn.rename_folder(old_folder_name, new_folder_name);
if (!ok)
{
throw mailio::imap_error("отказано в операции сервером");
}
std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
update_message = "Папка " + old_folder_name_s + " переименована -> " + new_folder_name_s + " (" +
std::to_string(sec.count()) + " сек.)";
}
catch (const std::exception &exc)
{
update_message = "Папка " + old_folder_name_s + " не переименована: " + std::string(exc.what());
}
}
else
{
update_message = "Папка " + old_folder_name_s + " не переименована: отмена операции";
}
std::string current_datetime_s = get_current_datetime_as_string();
QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);
ui->status_bar->showMessage(log_message);
ui->logs_text_edit->appendPlainText(log_message);
if (ok)
{
main_mutex.unlock();
on_update_folders_and_messages_triggered();
}
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
void MainWindow::on_delete_selected_folder_triggered()
{
std::lock_guard<std::mutex> main_lock(main_mutex);
try
{
std::list<std::string> folder_name, folder_name_decoded;
std::string folder_name_s;
QTreeWidgetItem *current = ui->folders_tree->currentItem();
while (current)
{
folder_name_decoded.emplace_front(current->text(0).toStdString());
folder_name.emplace_front(current->text(3).toStdString());
current = current->parent();
}
for (auto s : folder_name_decoded)
{
folder_name_s += "\\" + s;
};
std::string update_message;
bool ok = (QMessageBox::question(
this, "Внимание",
QString::fromStdString("Вы уверены, что хотите удалить папку " + folder_name_s + "?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes);
if (ok)
{
try
{
std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
mailio::imaps conn(imap_settings.get_server_address(),
static_cast<unsigned>(imap_settings.get_server_port()), timeout);
conn.authenticate(imap_settings.get_login(), imap_settings.get_password(),
imap_settings.get_auth_method());
ok = conn.delete_folder(folder_name);
if (!ok)
{
throw mailio::imap_error("отказано в операции сервером");
}
std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
update_message = "Папка " + folder_name_s + " удалена (" + std::to_string(sec.count()) + " сек.)";
}
catch (const std::exception &exc)
{
update_message = "Папка " + folder_name_s + " не удалена: " + std::string(exc.what());
}
}
else
{
update_message = "Папка " + folder_name_s + " не удалена: отмена операции";
}
std::string current_datetime_s = get_current_datetime_as_string();
QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);
ui->status_bar->showMessage(log_message);
ui->logs_text_edit->appendPlainText(log_message);
if (ok)
{
main_mutex.unlock();
on_update_folders_and_messages_triggered();
}
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
void MainWindow::on_send_message_triggered()
{
std::lock_guard<std::mutex> main_lock(main_mutex);
try
{
mailio::smtps conn(smtp_settings.get_server_address(), smtp_settings.get_server_port());
conn.authenticate(smtp_settings.get_login(), smtp_settings.get_password(), smtp_settings.get_auth_method());
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
return;
}
SendMessageDialog new_send_message_dialog;
try
{
while (new_send_message_dialog.exec() == QDialog::Accepted)
{
try
{
mailio::message message = new_send_message_dialog.get_message();
if (message.subject().empty())
{
QMessageBox::warning(this, "Ошибка", "Тема сообщения пуста");
continue;
}
if (message.recipients().empty() && message.cc_recipients().empty() && message.bcc_recipients().empty())
{
QMessageBox::warning(this, "Ошибка", "Получатели отсутствуют");
continue;
}
message.from(mailio::mail_address(smtp_settings.get_name(), smtp_settings.get_login()));
mailio::smtps conn(smtp_settings.get_server_address(), smtp_settings.get_server_port());
conn.authenticate(smtp_settings.get_login(), smtp_settings.get_password(),
smtp_settings.get_auth_method());
std::string status = conn.submit(message);
std::string update_message = "Сообщение отправлено, обновите "
"список папок с сообщениями";
std::string current_datetime_s = get_current_datetime_as_string();
QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);
ui->status_bar->showMessage(log_message);
ui->logs_text_edit->appendPlainText(log_message);
QMessageBox::information(this, "Информация",
"Сообщение отправлено\nОбновите список папок "
"с сообщениями\n\nОтвет сервера:\n" +
QString::fromStdString(status));
break;
}
catch (const std::exception &exc)
{
QMessageBox::warning(this, "Ошибка", exc.what());
}
}
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
void MainWindow::on_download_attachment_triggered()
{
std::lock_guard<std::mutex> main_lock(main_mutex);
try
{
QTableWidgetItem *current_item = ui->messages_table->currentItem();
if (current_item == nullptr)
{
QMessageBox::warning(this, "Внимание", "Сообщение не выбрано");
return;
}
std::string current_message_id =
ui->messages_table->item(ui->messages_table->currentRow(), 7)->text().toStdString();
if (messages.find(current_message_id) == messages.end())
{
QMessageBox::warning(this, "Внимание", "Сообщение не найдено");
return;
}
mailio::message current_message = messages[current_message_id];
size_t n_attachments = current_message.attachments_size();
if (n_attachments <= 0)
{
QMessageBox::warning(this, "Внимание", "Вложения в сообщении не найдены");
return;
}
QStringList attachment_names, attachment_names_and_sizes;
std::vector<std::shared_ptr<std::stringstream>> attachments_data_streams;
constexpr unsigned long long kb = 1 << 10, mb = kb << 10, gb = mb << 10;
for (size_t i = 1; i <= n_attachments; ++i)
{
std::string attachment_name, attachment_size;
std::shared_ptr<std::stringstream> ss = std::make_shared<std::stringstream>();
std::istream &is = *ss;
std::ostream &os = *ss;
current_message.attachment(i, os, attachment_name);
is.seekg(0, std::ios::end);
unsigned long long size = is.tellg();
is.seekg(0, std::ios::beg);
if (size >= gb)
{
size = size * 100 / gb;
attachment_size = std::to_string(size / 100) + "." + std::to_string(size % 100) + " ГиБ";
}
else if (size >= mb)
{
size = size * 100 / mb;
attachment_size = std::to_string(size / 100) + "." + std::to_string(size % 100) + " МиБ";
}
else if (size >= kb)
{
size = size * 100 / kb;
attachment_size = std::to_string(size / 100) + "." + std::to_string(size % 100) + " КиБ";
}
else
{
attachment_size = std::to_string(size) + " Б";
}
attachment_names.emplace_back(QString::fromStdString(attachment_name));
attachment_names_and_sizes.emplace_back(
QString::fromStdString(attachment_name + " (" + attachment_size + ")"));
attachments_data_streams.emplace_back(ss);
}
bool ok = false;
std::string update_message;
QString filename_with_size = QInputDialog::getItem(this, "Внимание", "Какое вложение вы хотите скачать?",
attachment_names_and_sizes, 0, false, &ok);
if (ok)
{
size_t p = 0;
if ((p = attachment_names_and_sizes.indexOf(filename_with_size)) < 0)
{
QMessageBox::warning(this, "Внимание", "Вложение не найдено");
return;
}
QString new_filename = QInputDialog::getText(this, "Внимание", "Введите путь и/или имя файла для записи",
QLineEdit::Normal, attachment_names[p], &ok);
if (ok)
{
try
{
std::ofstream file_out(new_filename.toStdWString().c_str(), std::ios::out | std::ios::binary);
file_out << ((std::istream &)*attachments_data_streams[p]).rdbuf();
file_out.close();
update_message = "Файл " + new_filename.toStdString() + " записан";
}
catch (const std::exception &exc)
{
update_message = "Ошибка записи файла на диск: " + std::string(exc.what());
}
}
else
{
update_message = "Сохранение файла отменено";
}
}
else
{
update_message = "Сохранение файла отменено";
}
std::string current_datetime_s = get_current_datetime_as_string();
QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);
ui->status_bar->showMessage(log_message);
ui->logs_text_edit->appendPlainText(log_message);
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
void MainWindow::on_copy_selected_message_triggered()
{
std::lock_guard<std::mutex> main_lock(main_mutex);
try
{
QItemSelectionModel *select = ui->messages_table->selectionModel();
if (!select->hasSelection())
{
QMessageBox::warning(this, "Внимание", "Сообщения не выбраны");
return;
}
QList<QString> folders;
for (auto folder : mailboxes_to_messages_ids)
{
QString folder_to_emplace;
for (auto s : folder.first)
{
folder_to_emplace += "\\" + utf7decode(QString::fromStdString(s));
}
folders.emplace_back(folder_to_emplace);
}
bool ok = false;
QString text =
QInputDialog::getItem(this, "Копирование сообщений в папку", "Название папки:", folders, 0, false, &ok);
if (!ok || text.isEmpty())
{
return;
}
std::list<std::string> destination_folder_name;
for (auto s : text.split('\\'))
{
if (!s.isEmpty())
{
destination_folder_name.emplace_back(utf7encode(s).toStdString());
}
}
try
{
std::string update_message;
QModelIndexList selection = select->selectedIndexes();
if (selection.count() == 0)
{
QMessageBox::warning(this, "Внимание", "Сообщения не выбраны");
return;
}
std::unordered_set<int> rows;
for (qsizetype i = 0; i < selection.count(); i++)
{
rows.insert(selection.at(i).row());
}
std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
mailio::imaps conn(imap_settings.get_server_address(),
static_cast<unsigned>(imap_settings.get_server_port()), timeout);
conn.authenticate(imap_settings.get_login(), imap_settings.get_password(), imap_settings.get_auth_method());
for (auto row : rows)
{
QTableWidgetItem *current_uid = ui->messages_table->item(row, 6);
if (current_uid == nullptr || current_uid->text().isEmpty())
{
QMessageBox::warning(this, "Внимание", "UID одного сообщения не найден");
continue;
}
ok = false;
unsigned long uid = current_uid->text().toULong(&ok);
if (!ok)
{
QMessageBox::warning(this, "Внимание", "Неверный UID у одного сообщения");
continue;
}
QTableWidgetItem *current_message_id = ui->messages_table->item(row, 7);
if (current_message_id == nullptr || current_message_id->text().isEmpty())
{
QMessageBox::warning(this, "Внимание", "Message ID одного сообщения не найден");
continue;
}
std::string current_message_id_s = current_message_id->text().toStdString();
std::string datetime_s = ui->messages_table->item(row, 2)->text().toStdString();
try
{
conn.append(destination_folder_name, this->messages[current_message_id_s]);
std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
update_message = "Сообщение #" + std::to_string(uid) + " (" + datetime_s + ") скопировано (" +
std::to_string(sec.count()) + " сек.)";
}
catch (const std::exception &exc)
{
update_message = "Сообщение #" + std::to_string(uid) + " (" + datetime_s +
") не скопировано: " + std::string(exc.what());
}
std::string current_datetime_s = get_current_datetime_as_string();
QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);
ui->status_bar->showMessage(log_message);
ui->logs_text_edit->appendPlainText(log_message);
ui->current_message->setDocument(&this->empty_text_document);
}
main_mutex.unlock();
on_update_folders_and_messages_triggered();
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
void MainWindow::on_delete_selected_message_triggered()
{
std::lock_guard<std::mutex> main_lock(main_mutex);
try
{
QTreeWidgetItem *current_folder = ui->folders_tree->currentItem();
std::list<std::string> folder_name;
if (current_folder == nullptr)
{
if (this->current_item.empty())
{
QMessageBox::warning(this, "Внимание", "Папка не выбрана");
return;
}
folder_name = this->current_item;
}
else
{
QTreeWidgetItem *current = current_folder;
while (current)
{
folder_name.emplace_front(current->text(3).toStdString());
current = current->parent();
}
this->current_item = folder_name;
}
QItemSelectionModel *select = ui->messages_table->selectionModel();
if (!select->hasSelection())
{
QMessageBox::warning(this, "Внимание", "Сообщения не выбраны");
return;
}
bool ok = (QMessageBox::question(this, "Внимание", "Вы уверены, что хотите удалить выбранные сообщения?",
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes);
if (!ok)
{
return;
}
try
{
std::string update_message;
QModelIndexList selection = select->selectedIndexes();
if (selection.count() == 0)
{
QMessageBox::warning(this, "Внимание", "Сообщения не выбраны");
return;
}
std::unordered_set<int> rows;
for (qsizetype i = 0; i < selection.count(); i++)
{
rows.insert(selection.at(i).row());
}
std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
mailio::imaps conn(imap_settings.get_server_address(),
static_cast<unsigned>(imap_settings.get_server_port()), timeout);
conn.authenticate(imap_settings.get_login(), imap_settings.get_password(), imap_settings.get_auth_method());
for (auto row : rows)
{
QTableWidgetItem *current_uid = ui->messages_table->item(row, 6);
if (current_uid == nullptr || current_uid->text().isEmpty())
{
QMessageBox::warning(this, "Внимание", "UID одного сообщения не найден");
continue;
}
ok = false;
unsigned long uid = current_uid->text().toULong(&ok);
if (!ok)
{
QMessageBox::warning(this, "Внимание", "Неверный UID у одного сообщения");
continue;
}
std::string datetime_s = ui->messages_table->item(row, 2)->text().toStdString();
try
{
conn.remove(folder_name, uid, true);
std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
update_message = "Сообщение #" + std::to_string(uid) + " (" + datetime_s + ") удалено (" +
std::to_string(sec.count()) + " сек.)";
}
catch (const std::exception &exc)
{
update_message = "Сообщение #" + std::to_string(uid) + " (" + datetime_s +
") не удалено: " + std::string(exc.what());
}
std::string current_datetime_s = get_current_datetime_as_string();
QString log_message = QString::fromStdString(current_datetime_s + ". " + update_message);
ui->status_bar->showMessage(log_message);
ui->logs_text_edit->appendPlainText(log_message);
ui->current_message->setDocument(&this->empty_text_document);
}
main_mutex.unlock();
on_update_folders_and_messages_triggered();
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
void MainWindow::on_clear_all_and_disable_autoupdate_triggered()
{
std::lock_guard<std::mutex> main_lock(main_mutex);
clear_all();
}
void MainWindow::on_show_message_statistics_triggered()
{
std::lock_guard<std::mutex> main_lock(main_mutex);
try
{
int n_folders = ui->folders_tree->topLevelItemCount(), n_messages = 0, n_unseen_messages = 0, n_attachments = 0;
for (int row = 0; row < ui->folders_tree->topLevelItemCount(); ++row)
{
n_folders += get_number_of_folders_recursive(ui->folders_tree->topLevelItem(row));
n_messages += ui->folders_tree->topLevelItem(row)->text(2).toInt();
n_unseen_messages += ui->folders_tree->topLevelItem(row)->text(1).toInt();
}
unsigned long long size = 0;
constexpr unsigned long long kb = 1 << 10, mb = kb << 10, gb = mb << 10;
for (auto message_size : this->messages_sizes)
{
size += message_size.second;
}
std::string size_s;
if (size >= gb)
{
size = size * 100 / gb;
size_s = std::to_string(size / 100) + "." + std::to_string(size % 100) + " ГиБ";
}
else if (size >= mb)
{
size = size * 100 / mb;
size_s = std::to_string(size / 100) + "." + std::to_string(size % 100) + " МиБ";
}
else if (size >= kb)
{
size = size * 100 / kb;
size_s = std::to_string(size / 100) + "." + std::to_string(size % 100) + " КиБ";
}
else
{
size_s = std::to_string(size) + " Б";
}
QString s = QString::fromStdString("Общее число папок, включая вложенные: " + std::to_string(n_folders) +
"\nОбщее число писем во всех папках: " + std::to_string(n_messages) +
"\nОбщее число непрочитанных писем: " + std::to_string(n_unseen_messages) +
"\nОбщий размер закэшированных сообщений с вложениями: " + size_s);
QMessageBox::information(this, "Статистика", s);
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
int MainWindow::get_number_of_folders_recursive(QTreeWidgetItem *twi)
{
int n = twi->childCount();
if (twi)
{
for (int c = 0, child_count = twi->childCount(); c < child_count; ++c)
{
n += get_number_of_folders_recursive(twi->child(c));
}
}
return n;
}
void MainWindow::on_show_about_window_triggered()
{
try
{
QMessageBox::about(this, "О программе",
"Курсовая работа по дисциплине ММиВА (СПбГУТ)\n"
"Тема: Разработка клиентского ПО для получения и "
"отправки почтовых сообщений\n"
"Выполнил студент группы ИКПИ-84\n"
"Коваленко Леонид\n"
"Санкт-Петербург\n"
"2022 год");
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
void MainWindow::on_folders_tree_itemClicked(QTreeWidgetItem *,
int) // not use arguments because concurrent programming!
{
std::lock_guard<std::mutex> main_lock(main_mutex);
folder_chosen_ui();
}
void MainWindow::on_messages_table_itemClicked(QTableWidgetItem *)
{
std::lock_guard<std::mutex> main_lock(main_mutex);
try
{
QTableWidgetItem *current_message_id = ui->messages_table->item(ui->messages_table->currentRow(), 7);
if (current_message_id == nullptr || current_message_id->text().isEmpty())
{
ui->current_message->setDocument(&this->empty_text_document);
ui->status_bar->showMessage("Message ID выбранного сообщения не найден");
return;
}
std::string current_message_id_s = current_message_id->text().toStdString();
if (this->messages_ids_to_text_documents.find(current_message_id_s) ==
this->messages_ids_to_text_documents.end())
{
ui->current_message->setDocument(&this->empty_text_document);
ui->status_bar->showMessage("Тело выбранного сообщения не найдено");
return;
}
ui->current_message->setDocument(&this->messages_ids_to_text_documents[current_message_id_s]);
ui->status_bar->showMessage("Сообщение открыто");
}
catch (const std::exception &exc)
{
QMessageBox::critical(this, "Ошибка", exc.what());
}
}
void MainWindow::on_search_query_textChanged(const QString &query)
{
ui->messages_table->setCurrentCell(-1, -1);
if (query == "")
{
return;
}
std::lock_guard<std::mutex> main_lock(main_mutex);
auto find_items = ui->messages_table->findItems(query, Qt::MatchContains);
std::unordered_set<int> rows;
for (qsizetype i = 0, n = find_items.size(); i < n; ++i)
{
auto item = find_items.at(i);
item->setSelected(true);
rows.insert(item->row());
}
ui->status_bar->showMessage("Найдено " + QString::number(rows.size()) + " сообщений");
}
void MainWindow::on_search_query_returnPressed()
{
MainWindow::on_search_query_textChanged(ui->search_query->text());
}
std::string MainWindow::get_current_datetime_as_string()
{
char buffer[256];
std::time_t t = std::time(nullptr);
if (std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", std::localtime(&t)))
{
return std::string(buffer);
}
return "[undefined]";
}
std::string MainWindow::local_date_time_as_string(const boost::local_time::local_date_time &ldt)
{
char buffer[256];
auto dt_tm = boost::local_time::to_tm(ldt);
if (strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &dt_tm))
{
return std::string(buffer);
}
return "[undefined]";
}
void MainWindow::closeEvent(QCloseEvent *event)
{
std::lock_guard<std::mutex> main_lock(main_mutex);
if (QMessageBox::question(this, "Внимание", "Вы уверены, что хотите выйти?", QMessageBox::Yes | QMessageBox::No,
QMessageBox::No) == QMessageBox::Yes)
{
clear_all();
event->accept();
}
else
{
event->ignore();
}
}
void MainWindow::clear_all()
{
try
{
imap_settings.set_autoupdate(false);
ui->folders_tree->clear();
ui->messages_table->clearContents();
ui->messages_table->setRowCount(0);
ui->current_message->setDocument(&this->empty_text_document);
ui->logs_text_edit->clear();
ui->search_query->clear();
ui->status_bar->clearMessage();
update_status = true;
update_status_message.clear();
folders.clear();
current_item.clear();
messages_sizes.clear();
messages.clear();
messages_ids_to_uids.clear();
messages_ids_to_text_documents.clear();
uids_to_messages_ids.clear();
mailboxes_to_messages_ids.clear();
}
catch (...)
{
}
}
Модуль «main.cpp»
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "Russian");
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Исходный код оконных форм
Оконная форма «mainwindow.ui»
<?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»
<?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>Привет, мир!
Hello, world!
</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»
<?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>
