aboutsummaryrefslogtreecommitdiffstats
path: root/src/mimeparser.h
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-02 17:27:07 +0200
committerDanilo M. <danix@danix.xyz>2026-08-02 17:27:07 +0200
commit35d3e4ff127b0213fa4d34f630c4a019e533a4df (patch)
tree7cf50ed64ad5886ff909ab8ab2a26d99b2d90947 /src/mimeparser.h
parentb61ce428d81871fbbc6261f274f20785db9d1c38 (diff)
downloadqtmaildir-35d3e4ff127b0213fa4d34f630c4a019e533a4df.tar.gz
qtmaildir-35d3e4ff127b0213fa4d34f630c4a019e533a4df.zip
feat: add MimeParser with GMime and safe attachment naming
Diffstat (limited to 'src/mimeparser.h')
-rw-r--r--src/mimeparser.h64
1 files changed, 64 insertions, 0 deletions
diff --git a/src/mimeparser.h b/src/mimeparser.h
new file mode 100644
index 0000000..27a239f
--- /dev/null
+++ b/src/mimeparser.h
@@ -0,0 +1,64 @@
+#pragma once
+
+#include <QByteArray>
+#include <QHash>
+#include <QList>
+#include <QString>
+
+/// An inline part referenced by a cid: URL from the HTML body.
+struct InlinePart
+{
+ QString mimeType;
+ QByteArray data;
+};
+
+struct Attachment
+{
+ QString filename; ///< As it appeared in the message. Untrusted.
+ QString mimeType;
+ QByteArray data;
+
+ /// filename reduced to a basename safe to join onto a directory.
+ /// Attacker-controlled input: a filename may contain path separators or
+ /// "..", so anything that could escape the target directory is stripped.
+ /// Returns a generated name when nothing usable remains.
+ QString safeFilename() const;
+
+ /// Writes the attachment into directory. Returns the full path written, or
+ /// an empty string on failure with *error set.
+ QString saveTo(const QString &directory, QString *error) const;
+};
+
+struct ParsedMessage
+{
+ bool ok = false;
+ QString error;
+
+ QString subject;
+ QString from;
+ QString to;
+ QString cc;
+ QString date;
+ QString messageId;
+
+ QString plainBody;
+ QString htmlBody;
+
+ QHash<QString, InlinePart> inlineParts; ///< Keyed by Content-ID, no <>.
+ QList<Attachment> attachments;
+
+ bool hasHtml() const { return !htmlBody.isEmpty(); }
+};
+
+/// Parses a single message file using GMime.
+///
+/// Hand-rolling this would mean reimplementing RFC 2047 encoded words, RFC 2231
+/// parameter continuations, transfer encodings, and charset conversion, plus
+/// tolerance for malformed real-world mail.
+class MimeParser
+{
+public:
+ MimeParser();
+
+ ParsedMessage parse(const QString &filePath) const;
+};