2026-06-04 18:29:16 +02:00
|
|
|
#include <gmime/gmime.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
// Undefine macros that conflict with Qt's signals/slots
|
|
|
|
|
#ifdef public
|
|
|
|
|
#undef public
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef signals
|
|
|
|
|
#undef signals
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef slots
|
|
|
|
|
#undef slots
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef emit
|
|
|
|
|
#undef emit
|
|
|
|
|
#endif
|
|
|
|
|
|
2026-05-24 00:02:19 +02:00
|
|
|
#include "emailmanager.h"
|
2026-05-17 03:08:16 +02:00
|
|
|
#include <QDir>
|
|
|
|
|
#include <QStandardPaths>
|
|
|
|
|
#include "../db/dao/mailitemdao.h"
|
2026-05-24 00:02:19 +02:00
|
|
|
#include <QFile>
|
2026-05-24 21:01:05 +02:00
|
|
|
#include <QMessageBox>
|
2026-05-17 03:08:16 +02:00
|
|
|
|
2026-06-04 18:29:16 +02:00
|
|
|
/* Helper: recursively find a part with given subtype */
|
|
|
|
|
static GMimeObject *find_part_by_subtype(GMimeObject *obj, const char *subtype)
|
|
|
|
|
{
|
|
|
|
|
if (!obj)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
GMimeContentType *ctype = g_mime_object_get_content_type(obj);
|
|
|
|
|
if (ctype &&
|
|
|
|
|
g_ascii_strcasecmp(g_mime_content_type_get_media_subtype(ctype), subtype) == 0)
|
|
|
|
|
return obj;
|
|
|
|
|
|
|
|
|
|
if (GMIME_IS_MULTIPART(obj)) {
|
|
|
|
|
GMimeMultipart *multipart = GMIME_MULTIPART(obj);
|
|
|
|
|
guint count = g_mime_multipart_get_count(multipart);
|
|
|
|
|
for (guint i = 0; i < count; ++i) {
|
|
|
|
|
GMimeObject *part = g_mime_multipart_get_part(multipart, i);
|
|
|
|
|
GMimeObject *found = find_part_by_subtype(part, subtype);
|
|
|
|
|
if (found)
|
|
|
|
|
return found;
|
|
|
|
|
g_object_unref(part);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper: extract content as QString */
|
|
|
|
|
static QString extract_content_as_string(GMimeObject *obj)
|
|
|
|
|
{
|
|
|
|
|
GMimeStream *stream = g_mime_stream_mem_new();
|
|
|
|
|
g_mime_object_write_to_stream(obj, nullptr, stream);
|
|
|
|
|
GMimeStreamMem *mem = GMIME_STREAM_MEM(stream);
|
|
|
|
|
GByteArray *array = g_mime_stream_mem_get_byte_array(mem);
|
|
|
|
|
const char *data = reinterpret_cast<const char*>(array->data);
|
|
|
|
|
gsize size = array->len;
|
|
|
|
|
QString result = QString::fromUtf8(data, size);
|
|
|
|
|
g_object_unref(stream);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-17 03:08:16 +02:00
|
|
|
EmailManager::EmailManager(QObject *parent)
|
|
|
|
|
: QObject(parent)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MailItem EmailManager::getMailItemById(qint64 id) const
|
|
|
|
|
{
|
2026-05-24 00:02:19 +02:00
|
|
|
auto optItem = MailItemDao::findById(id);
|
2026-06-04 18:29:16 +02:00
|
|
|
return optItem.has_value() ? optItem.value() : MailItem();
|
2026-05-17 03:08:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString EmailManager::getStorageDirectory() const
|
|
|
|
|
{
|
|
|
|
|
QString storagePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
|
|
|
|
QDir dir(storagePath);
|
2026-06-04 18:29:16 +02:00
|
|
|
if (!dir.exists())
|
|
|
|
|
dir.mkpath(".");
|
2026-05-17 03:08:16 +02:00
|
|
|
return storagePath;
|
2026-05-24 00:02:19 +02:00
|
|
|
}
|
|
|
|
|
|
2026-05-24 21:01:05 +02:00
|
|
|
QString EmailManager::getEmailHtmlById(qint64 id) const
|
|
|
|
|
{
|
|
|
|
|
MailItem item = getMailItemById(id);
|
2026-06-04 18:29:16 +02:00
|
|
|
if (item.id() == 0)
|
2026-05-24 21:01:05 +02:00
|
|
|
return "<html><body><h2>Error: Email not found</h2></body></html>";
|
2026-06-04 18:29:16 +02:00
|
|
|
|
2026-05-24 21:01:05 +02:00
|
|
|
QString storageDir = getStorageDirectory();
|
|
|
|
|
QString fileName = item.fileId();
|
2026-06-04 18:29:16 +02:00
|
|
|
if (fileName.isEmpty())
|
2026-05-24 21:01:05 +02:00
|
|
|
return "<html><body><h2>Error: Email file ID is empty</h2></body></html>";
|
2026-06-04 18:29:16 +02:00
|
|
|
|
2026-05-24 21:01:05 +02:00
|
|
|
QString filePath = storageDir + QDir::separator() + fileName + ".eml";
|
|
|
|
|
return convertEmlToHtml(filePath);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-24 00:02:19 +02:00
|
|
|
QString EmailManager::convertEmlToHtml(const QString& emlFilePath) const
|
|
|
|
|
{
|
2026-06-04 18:29:16 +02:00
|
|
|
static bool initialized = false;
|
|
|
|
|
if (!initialized) {
|
|
|
|
|
g_mime_init();
|
|
|
|
|
initialized = true;
|
2026-05-24 00:02:19 +02:00
|
|
|
}
|
2026-06-04 18:29:16 +02:00
|
|
|
|
|
|
|
|
FILE *fp = fopen(emlFilePath.toLocal8Bit().constData(), "r");
|
|
|
|
|
if (!fp)
|
2026-05-24 00:02:19 +02:00
|
|
|
return "<html><body><h2>Error: Cannot open email file</h2></body></html>";
|
2026-06-04 18:29:16 +02:00
|
|
|
|
|
|
|
|
GMimeStream *istream = g_mime_stream_fs_new(fileno(fp));
|
|
|
|
|
GMimeParser *parser = g_mime_parser_new_with_stream(istream);
|
|
|
|
|
GMimeMessage *message = g_mime_parser_construct_message(parser, nullptr);
|
|
|
|
|
g_object_unref(parser);
|
|
|
|
|
g_object_unref(istream);
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
|
|
if (!message)
|
|
|
|
|
return "<html><body><h2>Error: Failed to parse email message</h2></body></html>";
|
|
|
|
|
|
|
|
|
|
/* Try to get HTML part */
|
|
|
|
|
GMimeObject *htmlPart = find_part_by_subtype(GMIME_OBJECT(message), "html");
|
|
|
|
|
if (htmlPart) {
|
|
|
|
|
QString html = extract_content_as_string(htmlPart);
|
|
|
|
|
g_object_unref(htmlPart);
|
|
|
|
|
g_object_unref(message);
|
|
|
|
|
return html;
|
2026-05-24 00:02:19 +02:00
|
|
|
}
|
2026-06-04 18:29:16 +02:00
|
|
|
|
|
|
|
|
/* Fallback to plain text */
|
|
|
|
|
GMimeObject *textPart = find_part_by_subtype(GMIME_OBJECT(message), "plain");
|
|
|
|
|
if (textPart) {
|
|
|
|
|
QString plain = extract_content_as_string(textPart);
|
|
|
|
|
g_object_unref(textPart);
|
|
|
|
|
g_object_unref(message);
|
|
|
|
|
QString escaped = plain;
|
|
|
|
|
escaped.replace("&", "&").replace("<", "<").replace(">", ">");
|
|
|
|
|
return QString("<html><body style='font-family:monospace;'><pre>%1</pre></body></html>")
|
|
|
|
|
.arg(escaped);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No displayable part */
|
|
|
|
|
g_object_unref(message);
|
|
|
|
|
return "<html><body><h2>Error: No displayable content in email</h2></body></html>";
|
2026-05-24 21:01:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool EmailManager::sendEmail(const QString& to, const QString& subject, const QString& body)
|
|
|
|
|
{
|
2026-06-04 18:29:16 +02:00
|
|
|
/* TODO: Implement real sending via RequestProcessor */
|
|
|
|
|
QMessageBox::information(nullptr, "Send Email",
|
2026-05-24 21:01:05 +02:00
|
|
|
QString("To: %1\nSubject: %2\nBody: %3").arg(to, subject, body));
|
|
|
|
|
return true;
|
2026-05-17 03:08:16 +02:00
|
|
|
}
|