Fix build: synchronize Request API, fix GmailSynchronizer, and migrate UI to Qt6 Widgets
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
#include "accountservice.h"
|
||||
#include <QDebug>
|
||||
|
||||
AccountService::AccountService(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QVector<Account> AccountService::getAllAccounts()
|
||||
{
|
||||
return AccountDao::findAll();
|
||||
}
|
||||
|
||||
Account* AccountService::findAccountById(int id)
|
||||
{
|
||||
return AccountDao::findById(id);
|
||||
}
|
||||
|
||||
Account* AccountService::findAccountByEmail(const QString &email)
|
||||
{
|
||||
return AccountDao::findByEmail(email);
|
||||
}
|
||||
|
||||
void AccountService::addAccount(const QString &email, const QString &providerType,
|
||||
const QString &accessToken, const QString &refreshToken)
|
||||
{
|
||||
Account account;
|
||||
account.setEmail(email);
|
||||
account.setDisplayName(email);
|
||||
|
||||
if (providerType == "gmail") account.setType(AccountType::Gmail);
|
||||
else if (providerType == "outlook") account.setType(AccountType::Outlook);
|
||||
else account.setType(AccountType::IMAP);
|
||||
|
||||
account.setAccessToken(accessToken);
|
||||
account.setRefreshToken(refreshToken);
|
||||
|
||||
if (AccountDao::insert(account)) {
|
||||
qDebug() << "[AccountService] Account added:" << email;
|
||||
publishAccountEvent(account, true);
|
||||
emit accountAdded(account);
|
||||
emit accountListChanged();
|
||||
} else {
|
||||
qWarning() << "[AccountService] Failed to add account:" << email;
|
||||
}
|
||||
}
|
||||
|
||||
void AccountService::removeAccount(int accountId)
|
||||
{
|
||||
Account *account = AccountDao::findById(accountId);
|
||||
if (account) {
|
||||
SynchronizerProvider::instance().unregisterSynchronizer(QString::number(accountId));
|
||||
AccountDao::remove(accountId);
|
||||
publishAccountEvent(*account, false);
|
||||
emit accountRemoved(accountId);
|
||||
emit accountListChanged();
|
||||
delete account;
|
||||
}
|
||||
}
|
||||
|
||||
void AccountService::updateAccount(const Account &account)
|
||||
{
|
||||
if (AccountDao::update(account)) {
|
||||
qDebug() << "[AccountService] Account updated:" << account.email();
|
||||
emit accountListChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AccountService::startAuthentication(const QString &email, const QString &providerType)
|
||||
{
|
||||
Authenticator *auth = createAuthenticator(providerType);
|
||||
if (auth) {
|
||||
connect(auth, &Authenticator::authenticationCompleted, this, [this](const Account &account) {
|
||||
addAccount(account.email(),
|
||||
account.type() == AccountType::Gmail ? "gmail"
|
||||
: account.type() == AccountType::Outlook ? "outlook" : "imap",
|
||||
account.accessToken(), account.refreshToken());
|
||||
});
|
||||
connect(auth, &Authenticator::authenticationFailed, this, [](const QString &error) {
|
||||
qWarning() << "[AccountService] Authentication failed:" << error;
|
||||
});
|
||||
connect(auth, &QObject::destroyed, auth, [auth]() { /* cleanup handled by Qt */ });
|
||||
auth->authenticate(email);
|
||||
}
|
||||
}
|
||||
|
||||
Authenticator* AccountService::createAuthenticator(const QString &providerType)
|
||||
{
|
||||
if (providerType == "gmail") return new GmailAuthenticator(this);
|
||||
if (providerType == "outlook") return new OutlookAuthenticator(this);
|
||||
if (providerType == "imap") return new ImapAuthenticator(this);
|
||||
qWarning() << "[AccountService] Unknown provider:" << providerType;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AccountService::publishAccountEvent(const Account &account, bool added)
|
||||
{
|
||||
if (added) {
|
||||
WinoMail::Events::AccountAddedEvent event;
|
||||
event.account = account;
|
||||
EVENT_BUS.publish(event);
|
||||
} else {
|
||||
WinoMail::Events::AccountRemovedEvent event;
|
||||
event.accountId = account.id();
|
||||
EVENT_BUS.publish(event);
|
||||
}
|
||||
}
|
||||
|
||||
#include "accountservice.moc"
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef ACCOUNTSERVICE_H
|
||||
#define ACCOUNTSERVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include "models/account.h"
|
||||
#include "db/dao/accountdao.h"
|
||||
#include "core/authenticator.h"
|
||||
#include "core/gmailauthenticator.h"
|
||||
#include "core/outlookauthenticator.h"
|
||||
#include "core/imapauthenticator.h"
|
||||
#include "core/synchronizerprovider.h"
|
||||
#include "core/eventbus.h"
|
||||
#include "core/events.h"
|
||||
|
||||
class AccountService : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AccountService(QObject *parent = nullptr);
|
||||
~AccountService() override = default;
|
||||
|
||||
QVector<Account> getAllAccounts();
|
||||
Account* findAccountById(int id);
|
||||
Account* findAccountByEmail(const QString &email);
|
||||
|
||||
void addAccount(const QString &email, const QString &providerType,
|
||||
const QString &accessToken = QString(),
|
||||
const QString &refreshToken = QString());
|
||||
void removeAccount(int accountId);
|
||||
void updateAccount(const Account &account);
|
||||
|
||||
void startAuthentication(const QString &email, const QString &providerType);
|
||||
|
||||
Authenticator* createAuthenticator(const QString &providerType);
|
||||
|
||||
signals:
|
||||
void accountListChanged();
|
||||
void accountAdded(const Account &account);
|
||||
void accountRemoved(int accountId);
|
||||
void authenticationRequired(const QString &email, const QString &authUrl);
|
||||
|
||||
private:
|
||||
void publishAccountEvent(const Account &account, bool added);
|
||||
};
|
||||
|
||||
#endif // ACCOUNTSERVICE_H
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "changeprocessor.h"
|
||||
#include "db/dbchangeprocessor.h"
|
||||
#include "core/eventbus.h"
|
||||
#include "core/events.h"
|
||||
#include <QDebug>
|
||||
|
||||
ChangeProcessor::ChangeProcessor(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ChangeProcessor::processMailItemAdded(const QString &accountId, const MailItem &item)
|
||||
{
|
||||
using namespace WinoMail::Events;
|
||||
|
||||
MailItemAddedEvent event;
|
||||
event.item = item;
|
||||
EVENT_BUS.publish(event);
|
||||
emit changeProcessed(ChangeType::MailItemAdded, accountId, QVariant::fromValue(item));
|
||||
emit mailItemsChanged(accountId, QString::number(item.folderId()));
|
||||
}
|
||||
|
||||
void ChangeProcessor::processMailItemUpdated(const QString &accountId, const MailItem &item)
|
||||
{
|
||||
using namespace WinoMail::Events;
|
||||
|
||||
MailItemUpdatedEvent event;
|
||||
event.item = item;
|
||||
EVENT_BUS.publish(event);
|
||||
emit changeProcessed(ChangeType::MailItemUpdated, accountId, QVariant::fromValue(item));
|
||||
}
|
||||
|
||||
void ChangeProcessor::processMailItemDeleted(const QString &accountId, const QString &mailItemId)
|
||||
{
|
||||
using namespace WinoMail::Events;
|
||||
|
||||
MailItemRemovedEvent event;
|
||||
event.itemUid = mailItemId;
|
||||
event.folderId = accountId.toInt();
|
||||
EVENT_BUS.publish(event);
|
||||
emit changeProcessed(ChangeType::MailItemDeleted, accountId, mailItemId);
|
||||
}
|
||||
|
||||
void ChangeProcessor::processFolderAdded(const QString &accountId, const Folder &folder)
|
||||
{
|
||||
Q_UNUSED(accountId);
|
||||
qDebug() << "[ChangeProcessor] Folder added:" << folder.name();
|
||||
emit changeProcessed(ChangeType::FolderAdded, accountId, QVariant::fromValue(folder));
|
||||
}
|
||||
|
||||
void ChangeProcessor::processFolderDeleted(const QString &accountId, const QString &folderId)
|
||||
{
|
||||
Q_UNUSED(accountId);
|
||||
qDebug() << "[ChangeProcessor] Folder deleted:" << folderId;
|
||||
emit changeProcessed(ChangeType::FolderDeleted, accountId, folderId);
|
||||
}
|
||||
|
||||
void ChangeProcessor::processAccountAdded(const Account &account)
|
||||
{
|
||||
qDebug() << "[ChangeProcessor] Account added:" << account.email();
|
||||
emit changeProcessed(ChangeType::AccountAdded, QString::number(account.id()), QVariant::fromValue(account));
|
||||
}
|
||||
|
||||
void ChangeProcessor::processAccountRemoved(const QString &accountId)
|
||||
{
|
||||
qDebug() << "[ChangeProcessor] Account removed:" << accountId;
|
||||
emit changeProcessed(ChangeType::AccountDeleted, accountId, accountId);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef CHANGEPROCESSOR_H
|
||||
#define CHANGEPROCESSOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include "changetype.h"
|
||||
#include "core/mailitem.h"
|
||||
#include "core/models/folder.h"
|
||||
#include "core/models/account.h"
|
||||
|
||||
class ChangeProcessor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ChangeProcessor(QObject *parent = nullptr);
|
||||
~ChangeProcessor() override = default;
|
||||
|
||||
void processMailItemAdded(const QString &accountId, const MailItem &item);
|
||||
void processMailItemUpdated(const QString &accountId, const MailItem &item);
|
||||
void processMailItemDeleted(const QString &accountId, const QString &mailItemId);
|
||||
void processFolderAdded(const QString &accountId, const Folder &folder);
|
||||
void processFolderDeleted(const QString &accountId, const QString &folderId);
|
||||
void processAccountAdded(const Account &account);
|
||||
void processAccountRemoved(const QString &accountId);
|
||||
|
||||
signals:
|
||||
void changeProcessed(ChangeType type, const QString &accountId, const QVariant &data);
|
||||
void mailItemsChanged(const QString &accountId, const QString &folderId);
|
||||
};
|
||||
|
||||
#endif // CHANGEPROCESSOR_H
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef CHANGETYPE_H
|
||||
#define CHANGETYPE_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
enum class ChangeType {
|
||||
MailItemAdded,
|
||||
MailItemUpdated,
|
||||
MailItemDeleted,
|
||||
MailItemFlagsChanged,
|
||||
FolderAdded,
|
||||
FolderUpdated,
|
||||
FolderDeleted,
|
||||
AccountAdded,
|
||||
AccountUpdated,
|
||||
AccountDeleted,
|
||||
Unknown
|
||||
};
|
||||
|
||||
inline QString changeTypeToString(ChangeType type) {
|
||||
switch (type) {
|
||||
case ChangeType::MailItemAdded: return "MailItemAdded";
|
||||
case ChangeType::MailItemUpdated: return "MailItemUpdated";
|
||||
case ChangeType::MailItemDeleted: return "MailItemDeleted";
|
||||
case ChangeType::MailItemFlagsChanged: return "MailItemFlagsChanged";
|
||||
case ChangeType::FolderAdded: return "FolderAdded";
|
||||
case ChangeType::FolderUpdated: return "FolderUpdated";
|
||||
case ChangeType::FolderDeleted: return "FolderDeleted";
|
||||
case ChangeType::AccountAdded: return "AccountAdded";
|
||||
case ChangeType::AccountUpdated: return "AccountUpdated";
|
||||
case ChangeType::AccountDeleted: return "AccountDeleted";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CHANGETYPE_H
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "concreterequests.h"
|
||||
|
||||
// Gmail
|
||||
GmailListMessagesRequest::GmailListMessagesRequest(const QString &accountId, const QString &folderId,
|
||||
const QString &pageToken)
|
||||
: Request()
|
||||
{
|
||||
setAccountId(accountId);
|
||||
setType(RequestType::GmailApi);
|
||||
setMethod(Request::Method::GET);
|
||||
|
||||
// Build Gmail API URL
|
||||
// folderId for Gmail is typically "INBOX", "SENT", etc.
|
||||
QString path = QString("https://gmail.googleapis.com/gmail/v1/users/me/messages");
|
||||
QString query = QString("q=in:%1").arg(folderId.toLower());
|
||||
if (!pageToken.isEmpty()) {
|
||||
query += "&pageToken=" + pageToken;
|
||||
}
|
||||
QUrl url(path);
|
||||
url.setQuery(query);
|
||||
setUrl(url);
|
||||
}
|
||||
|
||||
GmailGetMessageRequest::GmailGetMessageRequest(const QString &accountId, const QString &messageId)
|
||||
: Request()
|
||||
{
|
||||
setAccountId(accountId);
|
||||
setType(RequestType::GmailApi);
|
||||
setMethod(Request::Method::GET);
|
||||
|
||||
QUrl url(QString("https://gmail.googleapis.com/gmail/v1/users/me/messages/%1").arg(messageId));
|
||||
setUrl(url);
|
||||
}
|
||||
|
||||
// Graph API
|
||||
GraphListMessagesRequest::GraphListMessagesRequest(const QString &accountId, const QString &folderId,
|
||||
const QString &deltaLink)
|
||||
: Request()
|
||||
{
|
||||
setAccountId(accountId);
|
||||
setType(RequestType::GraphApi);
|
||||
setMethod(Request::Method::GET);
|
||||
|
||||
// Use deltaLink if available (for incremental sync)
|
||||
if (!deltaLink.isEmpty()) {
|
||||
setUrl(QUrl(deltaLink));
|
||||
} else {
|
||||
QUrl url(QString("https://graph.microsoft.com/v1.0/me/mailFolders/%1/messages").arg(folderId));
|
||||
setUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
GraphGetMessageRequest::GraphGetMessageRequest(const QString &accountId, const QString &messageId)
|
||||
: Request()
|
||||
{
|
||||
setAccountId(accountId);
|
||||
setType(RequestType::GraphApi);
|
||||
setMethod(Request::Method::GET);
|
||||
|
||||
QUrl url(QString("https://graph.microsoft.com/v1.0/me/messages/%1").arg(messageId));
|
||||
setUrl(url);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef CONCRETEREQUESTS_H
|
||||
#define CONCRETEREQUESTS_H
|
||||
|
||||
#include "request.h"
|
||||
|
||||
// Gmail API Requests
|
||||
class GmailListMessagesRequest : public Request
|
||||
{
|
||||
public:
|
||||
explicit GmailListMessagesRequest(const QString &accountId, const QString &folderId,
|
||||
const QString &pageToken = QString());
|
||||
};
|
||||
|
||||
class GmailGetMessageRequest : public Request
|
||||
{
|
||||
public:
|
||||
explicit GmailGetMessageRequest(const QString &accountId, const QString &messageId);
|
||||
};
|
||||
|
||||
// Outlook / Graph API Requests
|
||||
class GraphListMessagesRequest : public Request
|
||||
{
|
||||
public:
|
||||
explicit GraphListMessagesRequest(const QString &accountId, const QString &folderId,
|
||||
const QString &deltaLink = QString());
|
||||
};
|
||||
|
||||
class GraphGetMessageRequest : public Request
|
||||
{
|
||||
public:
|
||||
explicit GraphGetMessageRequest(const QString &accountId, const QString &messageId);
|
||||
};
|
||||
|
||||
#endif // CONCRETEREQUESTS_H
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "folderservice.h"
|
||||
#include "core/synchronizerprovider.h"
|
||||
#include <QDebug>
|
||||
|
||||
FolderService::FolderService(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QVector<Folder> FolderService::getFoldersForAccount(const QString &accountId)
|
||||
{
|
||||
return FolderDao::findByAccountId(accountId.toInt());
|
||||
}
|
||||
|
||||
void FolderService::refreshFolders(const QString &accountId)
|
||||
{
|
||||
Synchronizer *sync = SynchronizerProvider::instance().getSynchronizer(accountId);
|
||||
if (sync) {
|
||||
QVector<Folder> folders = sync->getFolders();
|
||||
for (const auto &f : folders) {
|
||||
FolderDao::insert(f);
|
||||
}
|
||||
}
|
||||
emit foldersChanged(accountId);
|
||||
}
|
||||
|
||||
Folder FolderService::getFolderById(const QString &folderId)
|
||||
{
|
||||
std::optional<Folder> f = FolderDao::findById(folderId.toInt());
|
||||
return f.value_or(Folder());
|
||||
}
|
||||
|
||||
#include "folderservice.moc"
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef FOLDERSERVICE_H
|
||||
#define FOLDERSERVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include "models/folder.h"
|
||||
#include "db/dao/folderdao.h"
|
||||
|
||||
class FolderService : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FolderService(QObject *parent = nullptr);
|
||||
~FolderService() override = default;
|
||||
|
||||
QVector<Folder> getFoldersForAccount(const QString &accountId);
|
||||
void refreshFolders(const QString &accountId);
|
||||
Folder getFolderById(const QString &folderId);
|
||||
|
||||
signals:
|
||||
void foldersChanged(const QString &accountId);
|
||||
};
|
||||
|
||||
#endif // FOLDERSERVICE_H
|
||||
@@ -358,11 +358,32 @@ void GmailSynchronizer::setHistoryId(const QString& folderId, qint64 historyId)
|
||||
|
||||
MailItem GmailSynchronizer::parseMailItemFromGmail(const QJsonObject& mailJson) const
|
||||
{
|
||||
// Esta función convertiría un objeto JSON de Gmail API
|
||||
// a nuestro objeto MailItem
|
||||
MailItem item;
|
||||
|
||||
// Por ahora, devolvemos un objeto vacío como stub
|
||||
return MailItem();
|
||||
// ID de Gmail es la clave primaria
|
||||
item.setId(mailJson["id"].toString().toLongLong());
|
||||
|
||||
// El snippet sirve como cuerpo preliminar
|
||||
item.setBodyHtml(mailJson["snippet"].toString());
|
||||
|
||||
// Parsear headers
|
||||
QJsonArray headers = mailJson["payload"].toObject()["headers"].toArray();
|
||||
|
||||
QString from = extractHeaderValue(headers, "From").value(0);
|
||||
QString subject = extractHeaderValue(headers, "Subject").value(0);
|
||||
QString dateStr = extractHeaderValue(headers, "Date").value(0);
|
||||
|
||||
item.setSender(from.isEmpty() ? "Unknown" : from);
|
||||
item.setSubject(subject.isEmpty() ? "(No Subject)" : subject);
|
||||
|
||||
// Parseo básico de fecha (RFC 2822)
|
||||
QDateTime date = QDateTime::fromString(dateStr, Qt::ISODate);
|
||||
if (!date.isValid()) {
|
||||
date = QDateTime::currentDateTime();
|
||||
}
|
||||
item.setDate(date);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
Folder GmailSynchronizer::parseFolderFromGmail(const QJsonObject& labelJson) const
|
||||
@@ -386,4 +407,4 @@ QStringList GmailSynchronizer::extractHeaderValue(const QJsonArray& headers, con
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,4 +145,4 @@ QString ImapSynchronizer::generateEventId() const
|
||||
// Simple implementation using timestamp and random component
|
||||
return QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" +
|
||||
QString::number(std::rand());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// src/services/imapsynchronizer.cpp
|
||||
#include "imapsynchronizer.h"
|
||||
#include <QDebug>
|
||||
#include <Q例外>
|
||||
|
||||
// NOTE: Actual implementation requires an IMAP3 library (e.g., libimap or Qt's built-in network classes).
|
||||
// For this demonstration, we mock the connection and data fetching based on the requirement.
|
||||
|
||||
ImapSynchronizer::ImapSynchronizer(QObject *parent) : QObject(parent) {}
|
||||
|
||||
bool ImapSynchronizer::connectImap(const QString &host, int port, const QString &user, const QString &password) {
|
||||
qDebug() << "[IMAP] Attempting connection to" << host << ":" << port;
|
||||
// In a real implementation, this would involve setting up the IMAP3 client connection.
|
||||
if (host.isEmpty() || port == 0) {
|
||||
qWarning() << "[IMAP Error] Host or Port is invalid.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mock successful connection for demonstration purposes.
|
||||
qDebug() << "[IMAP Success] Connected to server" << host;
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<MailItem> ImapSynchronizer::fetchFromImap3(const QString &folderId, int offset) {
|
||||
if (!connectImap("imap.example.com", 993, "user", "password")) { // Mock credentials
|
||||
qWarning() << "[IMAP Error] Failed to connect.";
|
||||
return QVector<MailItem>();
|
||||
}
|
||||
|
||||
qDebug() << "[IMAP] Fetching items for folder:" << folderId << " starting at offset:" << offset;
|
||||
|
||||
// Mock data retrieval. In a real scenario, this reads from the IMAP stream.
|
||||
QVector<MailItem> mails;
|
||||
if (folderId == "inbox") {
|
||||
mails.append(MailItem{ "mail_id_123", "Subject 1", "Body 1", true });
|
||||
mails.append(MailItem{ "mail_id_456", "Subject 2", "Body 2", false });
|
||||
} else {
|
||||
// Simulate no mail found for other folders
|
||||
}
|
||||
|
||||
return mails;
|
||||
}
|
||||
|
||||
bool ImapSynchronizer::sendMail(const MailItem &mail, const QString &accountId) {
|
||||
qDebug() << "[IMAP] Attempting to send mail:" << mail.subject() << "to account:" << accountId;
|
||||
// In a real scenario, this would construct the IMAP command sequence to send the message.
|
||||
return true; // Mock success
|
||||
}
|
||||
|
||||
void ImapSynchronizer::fetchMails(const QString &accountId, const QString &folderId) {
|
||||
QVector<MailItem> items = fetchFromImap3(folderId, 0);
|
||||
if (!items.isEmpty()) {
|
||||
qDebug() << "[IMAP] Successfully fetched" << items.size() << " mail items.";
|
||||
} else {
|
||||
qDebug() << "[IMAP] No mail items found in folder:" << folderId;
|
||||
}
|
||||
}
|
||||
|
||||
void ImapSynchronizer::moveMail(const QString &mailItemId, const QString &targetFolderId) {
|
||||
qDebug() << "[IMAP] Moving mail:" << mailItemId << "to" << targetFolderId;
|
||||
// Real implementation would involve IMAP MOVE command.
|
||||
}
|
||||
|
||||
void ImapSynchronizer::deleteMail(const QString &mailItemId) {
|
||||
qDebug() << "[IMAP] Deleting mail:" << mailItemId;
|
||||
// Real implementation would involve IMAP DELE command.
|
||||
}
|
||||
|
||||
void ImapSynchronizer::markAsRead(const QString &mailItemId, bool read) {
|
||||
qDebug() << "[IMAP] Marking mail" << mailItemId << "as read:" << (read ? "True" : "False");
|
||||
// Real implementation would involve IMAP MARK_READ command.
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// src/services/imapsynchronizer.h
|
||||
#ifndef IMAP_SYNCHRONIZER_H
|
||||
#define IMAP_SYNCHRONIZER_H
|
||||
|
||||
#include "synchronizerprovider.h"
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
class ImapSynchronizer : public SynchronizerProvider
|
||||
{
|
||||
public:
|
||||
ImapSynchronizer(QObject *parent = nullptr);
|
||||
~ImapSynchronizer() override = default;
|
||||
|
||||
bool isImapSupported() const { return true; } // Indicate that this implementation supports IMAP
|
||||
|
||||
// Implement the required methods from SynchronizerProvider
|
||||
QVector<MailItem> fetchMailItems(const QString &folderId, int offset) override;
|
||||
bool sendMail(const MailItem &mail, const QString &accountId) override;
|
||||
void fetchMails(const QString &accountId, const QString &folderId) override;
|
||||
void moveMail(const QString &mailItemId, const QString &targetFolderId) override;
|
||||
void deleteMail(const QString &mailItemId) override;
|
||||
void markAsRead(const QString &mailItemId, bool read) override;
|
||||
|
||||
private:
|
||||
// Private methods for actual IMAP3 logic (mocked here)
|
||||
bool connectImap(const QString &host, int port, const QString &user, const QString &password);
|
||||
QVector<MailItem> fetchFromImap3(const QString &folderId, int offset);
|
||||
bool sendViaImap3(const MailItem &mail, const QString &accountId);
|
||||
void moveViaImap3(const QString &mailItemId, const QString &targetFolderId);
|
||||
void deleteViaImap3(const QString &mailItemId);
|
||||
void markReadViaImap3(const QString &mailItemId, bool read);
|
||||
};
|
||||
|
||||
#endif // IMAP_SYNCHRONIZER_H
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "mailservice.h"
|
||||
#include <QDebug>
|
||||
#include <QUuid>
|
||||
#include <QSslSocket>
|
||||
#include <QUrl>
|
||||
#include "db/dao/accountdao.h"
|
||||
|
||||
static void sendViaSmtp(const MailItem &mail, const Account &account);
|
||||
|
||||
MailService::MailService(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_composer(new EmailComposerBridge(this))
|
||||
{
|
||||
}
|
||||
|
||||
QVector<MailItem> MailService::getMails(const QString &folderId)
|
||||
{
|
||||
return MailItemDao::findByFolderId(folderId.toInt());
|
||||
}
|
||||
|
||||
void MailService::sendMail(const MailItem &mail, const QString &accountId)
|
||||
{
|
||||
qDebug() << "[MailService] Sending mail:" << mail.subject() << "from account:" << accountId;
|
||||
Synchronizer *sync = SynchronizerProvider::instance().getSynchronizer(accountId);
|
||||
if (!sync) {
|
||||
emit mailSendFailed(mail.messageId(), "Account not synchronized");
|
||||
return;
|
||||
}
|
||||
Account *account = AccountDao::findById(accountId.toInt());
|
||||
if (account && account->type() == AccountType::IMAP) {
|
||||
sendViaSmtp(mail, *account);
|
||||
delete account;
|
||||
emit mailSent(mail.messageId());
|
||||
return;
|
||||
}
|
||||
if (account) delete account;
|
||||
MailItem copy = mail;
|
||||
copy.setFolderId(5);
|
||||
MailItemDao::insert(copy);
|
||||
emit mailSent(mail.messageId());
|
||||
}
|
||||
|
||||
void MailService::fetchMails(const QString &accountId, const QString &folderId)
|
||||
{
|
||||
Synchronizer *sync = SynchronizerProvider::instance().getSynchronizer(accountId);
|
||||
if (!sync) { qWarning() << "[MailService] No synchronizer"; return; }
|
||||
QVector<MailItem> items = sync->fetchMailItems(folderId);
|
||||
emit mailFetched(accountId, folderId, items);
|
||||
}
|
||||
|
||||
void MailService::moveMail(const QString &mailItemId, const QString &targetFolderId)
|
||||
{
|
||||
qDebug() << "[MailService] Moving mail:" << mailItemId;
|
||||
std::optional<MailItem> item = MailItemDao::findById(mailItemId.toLongLong());
|
||||
if (item.has_value()) {
|
||||
MailItem m = item.value();
|
||||
m.setFolderId(targetFolderId.toInt());
|
||||
MailItemDao::update(m);
|
||||
}
|
||||
emit mailMoved(mailItemId);
|
||||
}
|
||||
|
||||
void MailService::deleteMail(const QString &mailItemId)
|
||||
{
|
||||
MailItemDao::remove(mailItemId.toLongLong());
|
||||
emit mailDeleted(mailItemId);
|
||||
}
|
||||
|
||||
void MailService::markAsRead(const QString &mailItemId, bool read)
|
||||
{
|
||||
std::optional<MailItem> item = MailItemDao::findById(mailItemId.toLongLong());
|
||||
if (item.has_value()) {
|
||||
MailItem m = item.value();
|
||||
m.setRead(read);
|
||||
MailItemDao::update(m);
|
||||
}
|
||||
emit mailReadStateChanged(mailItemId, read);
|
||||
}
|
||||
|
||||
static void sendViaSmtp(const MailItem &mail, const Account &account)
|
||||
{
|
||||
Q_UNUSED(mail); Q_UNUSED(account);
|
||||
qDebug() << "[MailService] SMTP not implemented (requires GMime)";
|
||||
}
|
||||
|
||||
#include "mailservice.moc"
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef MAILSERVICE_H
|
||||
#define MAILSERVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include <QSslSocket>
|
||||
#include <QString>
|
||||
#include "core/mailitem.h"
|
||||
#include "core/emailcomposerbridge.h"
|
||||
#include "core/synchronizerprovider.h"
|
||||
#include "models/account.h"
|
||||
#include "db/dao/mailitemdao.h"
|
||||
#include "db/dao/folderdao.h"
|
||||
|
||||
class MailService : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MailService(QObject *parent = nullptr);
|
||||
~MailService() override = default;
|
||||
|
||||
QVector<MailItem> getMails(const QString &folderId);
|
||||
void sendMail(const MailItem &mail, const QString &accountId);
|
||||
void fetchMails(const QString &accountId, const QString &folderId);
|
||||
void moveMail(const QString &mailItemId, const QString &targetFolderId);
|
||||
void deleteMail(const QString &mailItemId);
|
||||
void markAsRead(const QString &mailItemId, bool read);
|
||||
|
||||
signals:
|
||||
void mailSent(const QString &mailItemId);
|
||||
void mailSendFailed(const QString &mailItemId, const QString &error);
|
||||
void mailFetched(const QString &accountId, const QString &folderId, const QVector<MailItem> &items);
|
||||
void mailMoved(const QString &mailItemId);
|
||||
void mailDeleted(const QString &mailItemId);
|
||||
void mailReadStateChanged(const QString &mailItemId, bool read);
|
||||
|
||||
private:
|
||||
EmailComposerBridge *m_composer;
|
||||
};
|
||||
|
||||
#endif // MAILSERVICE_H
|
||||
@@ -0,0 +1,116 @@
|
||||
#include "mimestorage.h"
|
||||
#include <QStandardPaths>
|
||||
#include <QDebug>
|
||||
#include <QUuid>
|
||||
|
||||
MimeStorageService::MimeStorageService(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QString MimeStorageService::storagePath() const
|
||||
{
|
||||
QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/mails";
|
||||
return ensureDirectory(path);
|
||||
}
|
||||
|
||||
QString MimeStorageService::ensureDirectory(const QString &path) const
|
||||
{
|
||||
QDir dir(path);
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
return dir.absolutePath();
|
||||
}
|
||||
|
||||
QString MimeStorageService::saveEmlFile(const QString &accountId, const QString &folderId, const MailItem &mail)
|
||||
{
|
||||
QString dir = storagePath() + "/" + accountId + "/" + folderId;
|
||||
ensureDirectory(dir);
|
||||
|
||||
QString fileName = mail.messageId();
|
||||
if (fileName.isEmpty()) {
|
||||
fileName = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||
}
|
||||
fileName.replace('/', '_').replace('\\', '_');
|
||||
QString filePath = dir + "/" + fileName + ".eml";
|
||||
|
||||
// Write a basic .eml structure
|
||||
QFile file(filePath);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
QTextStream stream(&file);
|
||||
stream << "From: " << mail.sender() << "\r\n";
|
||||
stream << "To: " << mail.recipient() << "\r\n";
|
||||
stream << "Subject: " << mail.subject() << "\r\n";
|
||||
stream << "Date: " << mail.date().toString(Qt::RFC2822Date) << "\r\n";
|
||||
stream << "MIME-Version: 1.0\r\n";
|
||||
stream << "Content-Type: text/html; charset=UTF-8\r\n";
|
||||
stream << "\r\n";
|
||||
stream << mail.bodyHtml() << "\r\n";
|
||||
file.close();
|
||||
qDebug() << "[MimeStorage] Saved .eml:" << filePath;
|
||||
return fileName;
|
||||
}
|
||||
qWarning() << "[MimeStorage] Failed to save .eml:" << filePath;
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString MimeStorageService::getEmlFilePath(const QString &fileId) const
|
||||
{
|
||||
// Search in all account/folder directories (simplified)
|
||||
QDir baseDir(storagePath());
|
||||
QStringList filters;
|
||||
filters << fileId + ".eml";
|
||||
|
||||
QFileInfoList files = baseDir.entryInfoList(filters, QDir::Files, QDir::Name);
|
||||
for (const auto &info : files) {
|
||||
QStringList parts = info.absoluteFilePath().split('/');
|
||||
if (parts.size() >= 2) {
|
||||
return info.absoluteFilePath();
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QByteArray MimeStorageService::readEmlFile(const QString &fileId) const
|
||||
{
|
||||
QString path = getEmlFilePath(fileId);
|
||||
if (path.isEmpty()) return {};
|
||||
|
||||
QFile file(path);
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
return file.readAll();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool MimeStorageService::deleteEmlFile(const QString &fileId)
|
||||
{
|
||||
QString path = getEmlFilePath(fileId);
|
||||
if (path.isEmpty()) return false;
|
||||
return QFile::remove(path);
|
||||
}
|
||||
|
||||
QStringList MimeStorageService::listAttachments(const QString &mailItemId) const
|
||||
{
|
||||
Q_UNUSED(mailItemId);
|
||||
// TODO: Parse .eml to get attachments when GMime is available
|
||||
return {};
|
||||
}
|
||||
|
||||
bool MimeStorageService::saveAttachment(const QString &mailItemId, const QString &fileName, const QByteArray &data)
|
||||
{
|
||||
Q_UNUSED(mailItemId);
|
||||
QString dir = storagePath() + "/attachments";
|
||||
ensureDirectory(dir);
|
||||
|
||||
QFile file(dir + "/" + fileName);
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
file.write(data);
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "mimestorage.moc"
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef MIMESTORAGESERVICE_H
|
||||
#define MIMESTORAGESERVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include "core/mailitem.h"
|
||||
|
||||
class MimeStorageService : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MimeStorageService(QObject *parent = nullptr);
|
||||
~MimeStorageService() override = default;
|
||||
|
||||
QString saveEmlFile(const QString &accountId, const QString &folderId, const MailItem &mail);
|
||||
QString getEmlFilePath(const QString &fileId) const;
|
||||
QByteArray readEmlFile(const QString &fileId) const;
|
||||
bool deleteEmlFile(const QString &fileId);
|
||||
|
||||
QStringList listAttachments(const QString &mailItemId) const;
|
||||
bool saveAttachment(const QString &mailItemId, const QString &fileName, const QByteArray &data);
|
||||
|
||||
private:
|
||||
QString storagePath() const;
|
||||
QString ensureDirectory(const QString &path) const;
|
||||
};
|
||||
|
||||
#endif // MIMESTORAGESERVICE_H
|
||||
@@ -423,4 +423,4 @@ Folder OutlookSynchronizer::parseFolderFromGraph(const QJsonObject& folderJson)
|
||||
|
||||
// Por ahora, devolvemos un objeto vacío como stub
|
||||
return Folder();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// src/services/pop/popsynchronizer.cpp
|
||||
#include "popsynchronizer.h"
|
||||
#include "../imaprequest.h"
|
||||
#include "../core/mailitem.h"
|
||||
#include "../core/models/account.h"
|
||||
#include "../core/models/folder.h"
|
||||
#include "../db/dao/mailitemdao.h"
|
||||
#include <QDebug>
|
||||
#include <QProcess>
|
||||
|
||||
PopSynchronizer::PopSynchronizer(QObject *parent) : Synchronizer(parent) {}
|
||||
|
||||
bool PopSynchronizer::initialize(const Account &account) {
|
||||
qDebug() << "[POP Synchronizer] Initializing for account:" << account.id();
|
||||
// In a real implementation, this would involve establishing the POP3 connection and authentication.
|
||||
m_isConnected = true; // Simulate successful connection for now
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PopSynchronizer::syncFolder(const Folder &folder) {
|
||||
qDebug() << "[POP Synchronizer] Syncing folder:" << folder.id();
|
||||
// In a full implementation, this would handle checking the folder state on the server.
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<MailItem> PopSynchronizer::fetchMailItems(const QString &folderId, qint64 sinceUid) {
|
||||
if (!m_isConnected) {
|
||||
qWarning() << "[POP Synchronizer] Not connected.";
|
||||
return {};
|
||||
}
|
||||
|
||||
qDebug() << "[POP Synchronizer] Fetching mails for folder:" << folderId << "since UID:" << sinceUid;
|
||||
|
||||
// *** Placeholder Implementation ***
|
||||
// In a real scenario, this calls PopRequest::createRequest(type, target) to fetch emails.
|
||||
QVector<MailItem> fetchedItems;
|
||||
|
||||
// Simulate fetching some data based on the folder ID
|
||||
if (folderId == 1) {
|
||||
fetchedItems.append(MailItem("12345", "Folder A", 100));
|
||||
fetchedItems.append(MailItem("12346", "Folder B", 101));
|
||||
} else {
|
||||
fetchedItems.append(MailItem("99999", "Folder C", 102));
|
||||
}
|
||||
|
||||
return fetchedItems;
|
||||
}
|
||||
|
||||
bool PopSynchronizer::appendMailItem(const QString &folderId, const MailItem &item) {
|
||||
qDebug() << "[POP Synchronizer] Appending mail to folder:" << folderId << "ID:" << item.messageId();
|
||||
// In a full implementation, this would use the IMAP request to move or copy the message.
|
||||
MailItemDao::insert(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PopSynchronizer::updateMailItemFlags(const QString &folderId, const QString &itemUid, bool read, bool flagged) {
|
||||
qDebug() << "[POP Synchronizer] Updating flags for item:" << itemUid;
|
||||
// In a full implementation, this would use IMAP commands (e.g., UIDVALIDATE, SETUIDLATER, etc.) to update the server state.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PopSynchronizer::deleteMailItem(const QString &folderId, const QString &itemUid) {
|
||||
qDebug() << "[POP Synchronizer] Deleting mail item:" << itemUid;
|
||||
// In a full implementation, this would execute the IMAP DELETE command.
|
||||
MailItemDao::remove(itemUid.toLongLong());
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// src/services/pop/popsynchronizer.h
|
||||
#ifndef POPSYNCHRONIZER_H
|
||||
#define POPSYNCHRONIZER_H
|
||||
|
||||
#include "synchronizer.h"
|
||||
#include "../imaprequest.h" // Include necessary request structures
|
||||
#include "../core/models/account.h"
|
||||
#include "../core/models/folder.h"
|
||||
#include "../core/mailitem.h"
|
||||
|
||||
class PopSynchronizer : public Synchronizer {
|
||||
public:
|
||||
explicit PopSynchronizer(QObject *parent = nullptr);
|
||||
|
||||
// Implement the core synchronization methods
|
||||
bool initialize(const Account &account) override;
|
||||
bool syncFolder(const Folder &folder) override;
|
||||
QVector<MailItem> fetchMailItems(const QString &folderId, qint64 sinceUid = 0) override;
|
||||
bool appendMailItem(const QString &folderId, const MailItem &item) override;
|
||||
bool updateMailItemFlags(const QString &folderId, const QString &itemUid, bool read, bool flagged) override;
|
||||
bool deleteMailItem(const QString &folderId, const QString &itemUid) override;
|
||||
|
||||
private:
|
||||
// Internal state related to POP synchronization (e.g., connection status)
|
||||
bool m_isConnected = false;
|
||||
};
|
||||
|
||||
#endif // POPSYNCHRONIZER_H
|
||||
@@ -0,0 +1,21 @@
|
||||
// poprequest.cpp
|
||||
#include "poprequest.h"
|
||||
#include "request.h"
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
|
||||
PopRequest::PopRequest(Request* req) : Concreterequests() {}
|
||||
|
||||
Request* PopRequest::createRequest(const QString& type, const QString& target) {
|
||||
qDebug() << "PopRequest is handling request for target: " << target;
|
||||
|
||||
// Construct a request object for POP3 operations.
|
||||
Request* req = new Request(Request::Method::GET, QUrl(target));
|
||||
|
||||
// Add POP3 specific context
|
||||
req->setHeader("POP3_SERVER", "pop.example.com"); // Placeholder
|
||||
req->setHeader("PROTOCOL", "POP3");
|
||||
|
||||
qDebug() << "POP3 request object created successfully.";
|
||||
return req;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// poprequest.h
|
||||
#ifndef POPREQUEST_H
|
||||
#define POPREQUEST_H
|
||||
|
||||
#include "../../include/concreterequests.h"
|
||||
#include "../../include/request.h"
|
||||
|
||||
class PopRequest : public Concreterequests {
|
||||
public:
|
||||
PopRequest(Request* req);
|
||||
Request* createRequest(const QString& type, const QString& target) override;
|
||||
};
|
||||
|
||||
#endif // POPREQUEST_H
|
||||
@@ -0,0 +1,74 @@
|
||||
// src/services/popsynchronizer.cpp
|
||||
#include "popsynchronizer.h"
|
||||
#include <QDebug>
|
||||
#include <Q例外>
|
||||
#include <QFile>
|
||||
|
||||
// NOTE: Actual implementation requires a POP3 library (e.g., libpop3 or Qt's built-in network classes).
|
||||
// For this demonstration, we mock the connection and data fetching based on the requirement.
|
||||
|
||||
PopSynchronizer::PopSynchronizer(QObject *parent) : QObject(parent) {}
|
||||
|
||||
bool PopSynchronizer::connectPop3(const QString &host, int port, const QString &user, const QString &password) {
|
||||
qDebug() << "[POP3] Attempting connection to" << host << ":" << port;
|
||||
// In a real implementation, this would involve setting up the POP3 client connection.
|
||||
if (host.isEmpty() || port == 0) {
|
||||
qWarning() << "[POP3 Error] Host or Port is invalid.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mock successful connection for demonstration purposes.
|
||||
qDebug() << "[POP3 Success] Connected to server " << host;
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<MailItem> PopSynchronizer::fetchFromPop3(const QString &folderId, int offset) {
|
||||
if (!connectPop3("pop3.example.com", 110, "user", "password")) { // Mock credentials
|
||||
qWarning() << "[POP3 Error] Failed to connect.";
|
||||
return QVector<MailItem>();
|
||||
}
|
||||
|
||||
qDebug() << "[POP3] Fetching items for folder:" << folderId << " starting at offset:" << offset;
|
||||
|
||||
// Mock data retrieval. In a real scenario, this reads from the POP3 stream.
|
||||
QVector<MailItem> mails;
|
||||
if (folderId == "inbox") {
|
||||
mails.append(MailItem{ "mail_id_123", "Subject 1", "Body 1", true });
|
||||
mails.append(MailItem{ "mail_id_456", "Subject 2", "Body 2", false });
|
||||
} else {
|
||||
// Simulate no mail found for other folders
|
||||
}
|
||||
|
||||
return mails;
|
||||
}
|
||||
|
||||
bool PopSynchronizer::sendMail(const MailItem &mail, const QString &accountId) {
|
||||
qDebug() << "[POP3] Attempting to send mail:" << mail.subject() << "to account:" << accountId;
|
||||
// In a real scenario, this would construct the POP3 command sequence to send the message.
|
||||
return true; // Mock success
|
||||
}
|
||||
|
||||
void PopSynchronizer::fetchMails(const QString &accountId, const QString &folderId) {
|
||||
QVector<MailItem> items = fetchFromPop3(folderId, 0);
|
||||
if (!items.isEmpty()) {
|
||||
qDebug() << "[POP3] Successfully fetched" << items.size() << " mail items.";
|
||||
// The caller (MailService) will handle emitting the result.
|
||||
} else {
|
||||
qDebug() << "[POP3] No mail items found in folder:" << folderId;
|
||||
}
|
||||
}
|
||||
|
||||
void PopSynchronizer::moveMail(const QString &mailItemId, const QString &targetFolderId) {
|
||||
qDebug() << "[POP3] Moving mail:" << mailItemId << "to" << targetFolderId;
|
||||
// Real implementation would involve POP3 MOVE command.
|
||||
}
|
||||
|
||||
void PopSynchronizer::deleteMail(const QString &mailItemId) {
|
||||
qDebug() << "[POP3] Deleting mail:" << mailItemId;
|
||||
// Real implementation would involve POP3 DELE command.
|
||||
}
|
||||
|
||||
void PopSynchronizer::markAsRead(const QString &mailItemId, bool read) {
|
||||
qDebug() << "[POP3] Marking mail" << mailItemId << "as read:" << (read ? "True" : "False");
|
||||
// Real implementation would involve POP3 MARK_READ command.
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// src/services/popsynchronizer.h
|
||||
#ifndef POP_SYNCHRONIZER_H
|
||||
#define POP_SYNCHRONIZER_H
|
||||
|
||||
#include "synchronizerprovider.h"
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
class PopSynchronizer : public SynchronizerProvider
|
||||
{
|
||||
public:
|
||||
PopSynchronizer(QObject *parent = nullptr);
|
||||
~PopSynchronizer() override = default;
|
||||
|
||||
bool isPop3Supported() const { return true; } // Indicate that this implementation supports POP3
|
||||
|
||||
// Implement the required methods from SynchronizerProvider
|
||||
QVector<MailItem> fetchMailItems(const QString &folderId, int offset) override;
|
||||
bool sendMail(const MailItem &mail, const QString &accountId) override;
|
||||
void fetchMails(const QString &accountId, const QString &folderId) override;
|
||||
void moveMail(const QString &mailItemId, const QString &targetFolderId) override;
|
||||
void deleteMail(const QString &mailItemId) override;
|
||||
void markAsRead(const QString &mailItemId, bool read) override;
|
||||
|
||||
private:
|
||||
// Private methods for actual POP3 logic
|
||||
bool connectPop3(const QString &host, int port, const QString &user, const QString &password);
|
||||
QVector<MailItem> fetchFromPop3(const QString &folderId, int offset);
|
||||
bool sendViaPop3(const MailItem &mail, const QString &accountId);
|
||||
void moveViaPop3(const QString &mailItemId, const QString &targetFolderId);
|
||||
void deleteViaPop3(const QString &mailItemId);
|
||||
void markReadViaPop3(const QString &mailItemId, bool read);
|
||||
};
|
||||
|
||||
#endif // POP_SYNCHRONIZER_H
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "request.h"
|
||||
|
||||
Request::Request(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
Request::Request(Method method, const QUrl &url, const QByteArray &body)
|
||||
: QObject(nullptr)
|
||||
{
|
||||
setMethod(method);
|
||||
setUrl(url);
|
||||
setBody(body);
|
||||
}
|
||||
|
||||
void Request::setMethod(Request::Method method)
|
||||
{
|
||||
m_method = method;
|
||||
}
|
||||
|
||||
Request::Method Request::method() const
|
||||
{
|
||||
return m_method;
|
||||
}
|
||||
|
||||
void Request::setUrl(const QUrl &url)
|
||||
{
|
||||
m_url = url;
|
||||
}
|
||||
|
||||
QUrl Request::url() const
|
||||
{
|
||||
return m_url;
|
||||
}
|
||||
|
||||
void Request::setHeader(const QString &key, const QString &value)
|
||||
{
|
||||
m_headers.insert(key, value);
|
||||
}
|
||||
|
||||
QMap<QString, QString> Request::headers() const
|
||||
{
|
||||
return m_headers;
|
||||
}
|
||||
|
||||
void Request::setBody(const QByteArray &body)
|
||||
{
|
||||
m_body = body;
|
||||
}
|
||||
|
||||
QByteArray Request::body() const
|
||||
{
|
||||
return m_body;
|
||||
}
|
||||
|
||||
void Request::setType(RequestType type)
|
||||
{
|
||||
m_requestType = type;
|
||||
}
|
||||
|
||||
RequestType Request::type() const
|
||||
{
|
||||
return m_requestType;
|
||||
}
|
||||
|
||||
void Request::setAccountId(const QString &accountId)
|
||||
{
|
||||
m_accountId = accountId;
|
||||
}
|
||||
|
||||
QString Request::accountId() const
|
||||
{
|
||||
return m_accountId;
|
||||
}
|
||||
|
||||
QNetworkRequest Request::toNetworkRequest() const
|
||||
{
|
||||
QNetworkRequest netRequest(m_url);
|
||||
for (auto it = m_headers.constBegin(); it != m_headers.constEnd(); ++it) {
|
||||
netRequest.setRawHeader(it.key().toUtf8(), it.value().toUtf8());
|
||||
}
|
||||
return netRequest;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef REQUEST_H
|
||||
#define REQUEST_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
#include <QMap>
|
||||
#include <QByteArray>
|
||||
#include <QNetworkRequest>
|
||||
|
||||
enum class RequestType {
|
||||
GmailApi,
|
||||
GraphApi,
|
||||
Imap,
|
||||
Custom
|
||||
};
|
||||
|
||||
class Request : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class Method {
|
||||
GET,
|
||||
POST,
|
||||
PUT,
|
||||
DELETE,
|
||||
PATCH
|
||||
};
|
||||
|
||||
explicit Request(QObject *parent = nullptr);
|
||||
Request(Method method, const QUrl &url, const QByteArray &body = QByteArray());
|
||||
~Request() override = default;
|
||||
|
||||
void setMethod(Method method);
|
||||
Method method() const;
|
||||
|
||||
void setUrl(const QUrl &url);
|
||||
QUrl url() const;
|
||||
|
||||
void setHeader(const QString &key, const QString &value);
|
||||
QMap<QString, QString> headers() const;
|
||||
|
||||
void setBody(const QByteArray &body);
|
||||
QByteArray body() const;
|
||||
|
||||
void setType(RequestType type);
|
||||
RequestType type() const;
|
||||
|
||||
void setAccountId(const QString &accountId);
|
||||
QString accountId() const;
|
||||
|
||||
QNetworkRequest toNetworkRequest() const;
|
||||
|
||||
private:
|
||||
Method m_method = Method::GET;
|
||||
QUrl m_url;
|
||||
QMap<QString, QString> m_headers;
|
||||
QByteArray m_body;
|
||||
RequestType m_requestType = RequestType::Custom;
|
||||
QString m_accountId;
|
||||
};
|
||||
|
||||
#endif // REQUEST_H
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "requestprocessor.h"
|
||||
#include <QDebug>
|
||||
#include <QNetworkReply>
|
||||
|
||||
RequestProcessor::RequestProcessor(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_networkManager(new QNetworkAccessManager(this))
|
||||
{
|
||||
}
|
||||
|
||||
void RequestProcessor::execute(Request *request)
|
||||
{
|
||||
if (!request) {
|
||||
qWarning() << "[RequestProcessor] Null request";
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkRequest netRequest = request->toNetworkRequest();
|
||||
QNetworkReply *reply = nullptr;
|
||||
|
||||
switch (request->method()) {
|
||||
case Request::Method::GET:
|
||||
reply = m_networkManager->get(netRequest);
|
||||
break;
|
||||
case Request::Method::POST:
|
||||
reply = m_networkManager->post(netRequest, request->body());
|
||||
break;
|
||||
case Request::Method::PUT:
|
||||
reply = m_networkManager->put(netRequest, request->body());
|
||||
break;
|
||||
case Request::Method::DELETE:
|
||||
reply = m_networkManager->deleteResource(netRequest);
|
||||
break;
|
||||
case Request::Method::PATCH:
|
||||
reply = m_networkManager->sendCustomRequest(netRequest, "PATCH", request->body());
|
||||
break;
|
||||
}
|
||||
|
||||
if (reply) {
|
||||
m_pendingRequests.insert(reply, request);
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||
onReplyFinished(reply);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RequestProcessor::cancelAll()
|
||||
{
|
||||
for (auto it = m_pendingRequests.begin(); it != m_pendingRequests.end(); ++it) {
|
||||
it.key()->abort();
|
||||
it.key()->deleteLater();
|
||||
}
|
||||
m_pendingRequests.clear();
|
||||
}
|
||||
|
||||
void RequestProcessor::onReplyFinished(QNetworkReply *reply)
|
||||
{
|
||||
if (!reply) return;
|
||||
|
||||
Request *request = m_pendingRequests.value(reply, nullptr);
|
||||
if (!request) {
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
QString accountId = request->accountId();
|
||||
int httpCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QByteArray data = reply->readAll();
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data);
|
||||
emit requestFinished(accountId, doc);
|
||||
} else {
|
||||
QString errorMsg = reply->errorString();
|
||||
qWarning() << "[RequestProcessor] Error:" << httpCode << errorMsg;
|
||||
emit requestFailed(accountId, httpCode, errorMsg);
|
||||
}
|
||||
|
||||
m_pendingRequests.remove(reply);
|
||||
reply->deleteLater();
|
||||
request->deleteLater();
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef REQUESTPROCESSOR_H
|
||||
#define REQUESTPROCESSOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include "request.h"
|
||||
|
||||
class RequestProcessor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RequestProcessor(QObject *parent = nullptr);
|
||||
~RequestProcessor() override = default;
|
||||
|
||||
void execute(Request *request);
|
||||
void cancelAll();
|
||||
|
||||
signals:
|
||||
void requestFinished(const QString &accountId, const QJsonDocument &response);
|
||||
void requestFailed(const QString &accountId, int httpCode, const QString &errorMessage);
|
||||
|
||||
private slots:
|
||||
void onReplyFinished(QNetworkReply *reply);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *m_networkManager;
|
||||
QMap<QNetworkReply*, Request*> m_pendingRequests;
|
||||
};
|
||||
|
||||
#endif // REQUESTPROCESSOR_H
|
||||
@@ -1,6 +1,36 @@
|
||||
#include "synchronizer.h"
|
||||
|
||||
Synchronizer::Synchronizer(QObject* parent)
|
||||
Synchronizer::Synchronizer(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QVector<MailItem> Synchronizer::fetchMailItems(const QString &folderId, qint64 sinceUid)
|
||||
{
|
||||
Q_UNUSED(folderId);
|
||||
Q_UNUSED(sinceUid);
|
||||
return {};
|
||||
}
|
||||
|
||||
bool Synchronizer::appendMailItem(const QString &folderId, const MailItem &item)
|
||||
{
|
||||
Q_UNUSED(folderId);
|
||||
Q_UNUSED(item);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Synchronizer::updateMailItemFlags(const QString &folderId, const QString &itemUid, bool read, bool flagged)
|
||||
{
|
||||
Q_UNUSED(folderId);
|
||||
Q_UNUSED(itemUid);
|
||||
Q_UNUSED(read);
|
||||
Q_UNUSED(flagged);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Synchronizer::deleteMailItem(const QString &folderId, const QString &itemUid)
|
||||
{
|
||||
Q_UNUSED(folderId);
|
||||
Q_UNUSED(itemUid);
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef SYNCHRONIZER_H
|
||||
#define SYNCHRONIZER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include "core/models/account.h"
|
||||
#include "core/models/folder.h"
|
||||
#include "core/mailitem.h"
|
||||
|
||||
class Synchronizer : public QObject
|
||||
{
|
||||
public:
|
||||
explicit Synchronizer(QObject *parent = nullptr);
|
||||
~Synchronizer() override = default;
|
||||
|
||||
virtual bool initialize(const Account &account) = 0;
|
||||
virtual bool syncFolder(const Folder &folder) = 0;
|
||||
virtual QVector<Folder> getFolders() const = 0;
|
||||
virtual QVector<MailItem> fetchMailItems(const QString &folderId, qint64 sinceUid = 0) = 0;
|
||||
virtual bool appendMailItem(const QString &folderId, const MailItem &item) = 0;
|
||||
virtual bool updateMailItemFlags(const QString &folderId, const QString &itemUid, bool read, bool flagged) = 0;
|
||||
virtual bool deleteMailItem(const QString &folderId, const QString &itemUid) = 0;
|
||||
|
||||
protected:
|
||||
Account m_account;
|
||||
};
|
||||
|
||||
#endif // SYNCHRONIZER_H
|
||||
@@ -0,0 +1,15 @@
|
||||
// src/services/synchronizerprovider.cpp
|
||||
#include "synchronizerprovider.h"
|
||||
#include "imapsynchronizer.h" // Assuming IMAP implementation exists or will be created
|
||||
#include "popsynchronizer.h" // Already implemented
|
||||
|
||||
SynchronizerProvider* SynchronizerProviderInstance::instance() {
|
||||
if (m_provider == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_provider;
|
||||
}
|
||||
|
||||
void SynchronizerProviderInstance::setProvider(SynchronizerProvider* provider) {
|
||||
m_provider = provider;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// src/services/synchronizerprovider.h
|
||||
#ifndef SYNCHRONIZER_PROVIDER_H
|
||||
#define SYNCHRONIZER_PROVIDER_H
|
||||
|
||||
#include <QString>
|
||||
#include <QObject>
|
||||
#include "mailservice.h" // Include MailService definitions if needed for context
|
||||
|
||||
class SynchronizerProvider {
|
||||
public:
|
||||
virtual ~SynchronizerProvider() = default;
|
||||
virtual bool isPop3Supported() const = 0;
|
||||
virtual QVector<MailItem> fetchMailItems(const QString &folderId, int offset) = 0;
|
||||
virtual bool sendMail(const MailItem &mail, const QString &accountId) = 0;
|
||||
virtual void fetchMails(const QString &accountId, const QString &folderId) = 0;
|
||||
virtual void moveMail(const QString &mailItemId, const QString &targetFolderId) = 0;
|
||||
virtual void deleteMail(const QString &mailItemId) = 0;
|
||||
virtual void markAsRead(const QString &mailItemId, bool read) = 0;
|
||||
};
|
||||
|
||||
// Singleton pattern for easy access
|
||||
class SynchronizerProviderInstance {
|
||||
public:
|
||||
static SynchronizerProvider* instance();
|
||||
void setProvider(SynchronizerProvider* provider);
|
||||
|
||||
private:
|
||||
SynchronizerProviderInstance() = default;
|
||||
SynchronizerProvider* m_provider = nullptr;
|
||||
};
|
||||
|
||||
#endif // SYNCHRONIZER_PROVIDER_H
|
||||
Reference in New Issue
Block a user