diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-29 16:52:59 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-29 16:52:59 +0200 |
| commit | e168af8d7d9a500759565719f16ed188ba8a8bcd (patch) | |
| tree | 0246e655d2bcc1051d9e70c263f39692dd3d6e55 /src/launchselectors.h | |
| parent | d2793dd583041941348d5a984764160ddd48102b (diff) | |
| download | qtmaildir-e168af8d7d9a500759565719f16ed188ba8a8bcd.tar.gz qtmaildir-e168af8d7d9a500759565719f16ed188ba8a8bcd.zip | |
feat: parse the launch selectors as a value type
--account, --thread and --message, plus the payload that crosses the socket.
A value type with no GUI dependency: it is parsed before QApplication exists
and both halves need tests no window has to be built for.
QDataStream rather than a line-based payload, because a Message-ID may contain
a newline. Every read is status-checked, which is what catches a truncated
payload: a short read otherwise leaves the fields default-constructed and a
half-written id would be applied as an empty one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'src/launchselectors.h')
| -rw-r--r-- | src/launchselectors.h | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/src/launchselectors.h b/src/launchselectors.h new file mode 100644 index 0000000..b1ac043 --- /dev/null +++ b/src/launchselectors.h @@ -0,0 +1,89 @@ +/* + * qtmaildir - a Qt6 mail client for notmuch-indexed Maildirs + * Copyright (C) 2026 Danilo M. <danix@danix.xyz> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include <QByteArray> +#include <QMetaType> +#include <QString> +#include <QStringList> + +/// What a launch asked the window to show (item 200). +/// +/// A value type with no Qt GUI dependency, deliberately: it is parsed before +/// QApplication exists, it crosses a socket, and both halves need tests that +/// no window has to be built for. +/// +/// The three selectors COMPOSE rather than excluding each other. "Open this +/// message, in this account's view" is one request, and nothing about it is +/// contradictory. +struct LaunchSelectors +{ + /// An account key as written in the config, e.g. `work` from + /// `[account.work]`. Validated against the configured accounts by the + /// window, not here: this unit knows nothing about a Config. + QString account; + + /// A notmuch thread id. + QString threadId; + + /// A Message-ID, with or without the angle brackets. + QString messageId; + + bool isEmpty() const + { + return account.isEmpty() && threadId.isEmpty() && messageId.isEmpty(); + } + + /// Longest payload accepted off the socket. + /// + /// A local socket hands over whatever the peer sends, and the peer here is + /// another copy of this program running as the same user, so this is not a + /// defence against an attacker. It is what stops a confused or truncated + /// writer from being read as an unbounded selector. Three ids and an + /// account key are a few hundred bytes; 64 KiB is room to spare. + static constexpr int kMaxPayloadBytes = 64 * 1024; + + /// Parses a command line, `arguments[0]` being the program name. + /// + /// Takes a QStringList rather than argc/argv so it can be called before + /// QCoreApplication exists, which is what lets --version keep answering on + /// a machine where the GUI cannot open. + /// + /// On an unknown option, returns an empty result and sets \p error. The + /// caller prints it; it is NOT fatal to the window, since a typo should + /// not cost the user their mail client. + static LaunchSelectors parse(const QStringList &arguments, QString *error); + + /// The help text, for `--help`. Translatable prose; the option NAMES are + /// wire format and are never translated. + static QString helpText(const QString &versionDisplay); + + /// Serialises for the socket. The inverse of fromPayload(). + QByteArray toPayload() const; + + /// Parses a socket payload. On anything malformed, oversized or truncated, + /// returns an empty result and sets \p error. + static LaunchSelectors fromPayload(const QByteArray &payload, + QString *error); +}; + +/// Declared in the header that DEFINES the type, as types.h and threaddigest.h +/// do for theirs. A consumer declaring it instead would leave any other +/// consumer without it, and QSignalSpy needs it to carry the type. +Q_DECLARE_METATYPE(LaunchSelectors) |
