QtPass 2.0.0
Developer documentation
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2014 Anne Jan Brouwer
2// SPDX-License-Identifier: GPL-3.0-or-later
8
9#include "mainwindow.h"
10#include "qtpasssettings.h"
11#include "sshauthsock.h"
12#include "util.h"
13#if SINGLE_APP
14#include "singleapplication.h"
15#endif
16
17#include <QApplication>
18#include <QDir>
19#include <QTranslator>
20#include <QtWidgets>
21
29static auto joinRemainingArgs(const QStringList &args, int start) -> QString {
30 Q_ASSERT(start >= 0 && start <= args.size());
31 return args.mid(start).join(" ");
32}
33
43static auto appendWithSpaceIfSuffixNotEmpty(QString &target,
44 const QString &suffix) -> void {
45 if (!suffix.isEmpty()) {
46 if (!target.isEmpty())
47 target += " ";
48 target += suffix;
49 }
50}
51
59auto main(int argc, char *argv[]) -> int {
60 // Before anything starts git or gpg: pass's umask for them, and no
61 // inherited variable pointing git at another repository.
63 QString text;
64#if SINGLE_APP
65 QString name = qgetenv("USER");
66 if (name.isEmpty())
67 name = qgetenv("USERNAME");
68 SingleApplication app(argc, argv, name + "QtPass");
69#else
70 QApplication app(argc, argv);
71#endif
72
73 const QStringList args = app.arguments();
74 bool consumeNextArg = false;
75 for (int i = 1; i < args.count(); ++i) {
76 const auto &arg = args.at(i);
77
78 if (arg == "--") {
79 consumeNextArg = false;
81 break;
82 }
83
84 if (consumeNextArg) {
85 consumeNextArg = false;
86 continue;
87 }
88
89 if (arg.startsWith('-')) {
90 // We only collect positional arguments into `text`.
91 // For options in the form `--option value`, skip the separate value
92 // token. Options in the form `--option=value` are fully contained in
93 // `arg`.
94 const bool optionTakesSeparateValue =
95 !arg.contains('=') && i + 1 < args.count() && arg.startsWith("--") &&
96 !arg.startsWith("---") && !args[i + 1].startsWith('-');
97 if (optionTakesSeparateValue)
98 consumeNextArg = true;
99 continue;
100 }
101
102 if (!text.isEmpty())
103 text += " ";
104 text += arg;
105 }
106
107 if ((text.indexOf("-psn_") == 0) || (text.indexOf("-session") == 0)) {
108 text.clear();
109 }
110
111#if SINGLE_APP
112 // Hand the arguments to the running instance. When that fails (the peer
113 // vanished between the probe and now) start normally instead of exiting
114 // silently, which would leave the user with a launcher click that did
115 // nothing.
116 if (app.isRunning() && app.sendMessage(text)) {
117 return 0;
118 }
119#endif
120
121 Q_INIT_RESOURCE(resources);
122 Q_INIT_RESOURCE(qmake_qmake_qm_files); // qmake names the file
123
124 QCoreApplication::setOrganizationName("IJHack");
125 QCoreApplication::setOrganizationDomain("ijhack.org");
126 QCoreApplication::setApplicationName("QtPass");
127 QCoreApplication::setApplicationVersion(VERSION);
128
129 // Probe / set SSH_AUTH_SOCK before any subprocess runs (issue #543).
130 // GUI launchers don't inherit shell-set env vars, so users with
131 // gpg-agent's SSH support get failed git push/pull until this fires.
132 SshAuthSock::initialise(QtPassSettings::load().sshAuthSockOverride);
133
134 // Setup and load translator for localization.
135 //
136 // Use the QLocale-aware load() overload so Qt walks the user's preferred
137 // language list (e.g. ar_MA -> ar, da_DK -> da) automatically. The previous
138 // single-filename form returned false on the first miss and left the app
139 // untranslated whenever the system locale carried a country suffix that
140 // didn't match any .qm file verbatim.
141 QTranslator translator;
142 if (translator.load(QLocale::system(), QStringLiteral("localization"),
143 QStringLiteral("_"), QStringLiteral(":/localization"),
144 QStringLiteral(".qm"))) {
145#if SINGLE_APP
146 SingleApplication::installTranslator(&translator);
147 SingleApplication::setLayoutDirection(
148 QObject::tr("LTR") == "RTL" ? Qt::RightToLeft : Qt::LeftToRight);
149#else
150 QApplication::installTranslator(&translator);
151 QApplication::setLayoutDirection(
152 QObject::tr("LTR") == "RTL" ? Qt::RightToLeft : Qt::LeftToRight);
153#endif
154 }
155
156 // Both must be set before the window exists: Wayland compositors read the
157 // desktop file name when the surface is created and use it to find the
158 // icon, and a window created before setWindowIcon() keeps the default one.
159 // Inside a Flatpak the desktop file is renamed to the app id.
160 QGuiApplication::setDesktopFileName(
161 qEnvironmentVariable("FLATPAK_ID", QStringLiteral("qtpass")));
162 QApplication::setWindowIcon(QIcon(":artwork/icon.png"));
163
164 MainWindow w(text);
165
166 // A cancelled first-run wizard (or otherwise unusable configuration) makes
167 // QtPass::init() report failure from the MainWindow constructor. Quitting
168 // there is a no-op before exec() runs, so bail here before the window is
169 // ever shown.
170 if (!w.initSucceeded()) {
171 return 0;
172 }
173
174 w.activateWindow();
175
176#if SINGLE_APP
177 QObject::connect(&app, &SingleApplication::messageAvailable, &w,
179#endif
180
181 // Placement is MainWindow::restoreWindow()'s job: the saved geometry when
182 // there is one, the cursor's screen otherwise. Re-centring here threw the
183 // saved position away on every start.
184 w.show();
185
186#if SINGLE_APP
187 return SingleApplication::exec();
188#else
189 return QApplication::exec();
190#endif
191}
Main application window orchestrating UI, user interactions, and external process handlers.
Definition mainwindow.h:59
void messageAvailable(const QString &message)
Handle an incoming inter-process message (single-instance mode).
auto initSucceeded() const -> bool
Return whether startup configuration succeeded.
Definition mainwindow.h:122
static auto load() -> AppSettings
Load all flat settings into an AppSettings value object.
QApplication subclass enforcing single-instance behavior via IPC.
auto isRunning() -> bool
Query whether another instance is already running.
void messageAvailable(const QString &message)
messageAvailable notification from commandline
auto sendMessage(const QString &message) -> bool
Send a message to the running instance.
static void initialise(const QString &override={})
Ensure SSH_AUTH_SOCK is set for child processes.
static void applyPassProcessDefaults()
Set up the process the way pass sets up its own, before anything runs git or gpg or writes into the s...
Definition util.cpp:106
auto main(int argc, char *argv[]) -> int
Application entry point: parses arguments and launches the main window.
Definition main.cpp:59
static auto joinRemainingArgs(const QStringList &args, int start) -> QString
Joins all arguments from index start onward into a space-separated string.
Definition main.cpp:29
static auto appendWithSpaceIfSuffixNotEmpty(QString &target, const QString &suffix) -> void
Appends a suffix to a target string, inserting a separating space if the target is not empty.
Definition main.cpp:43
MainWindow: the main application window (tree, toolbar, search, status bar, process output dock) and ...
QtPassSettings, the QSettings singleton behind every saved setting, the profiles and the Pass backend...
SingleApplication: a QApplication that keeps one QtPass instance per user via a shared-memory segment...
SshAuthSock: finding an SSH agent socket for child processes and judging a configured override.
Util: static helpers for the process environment, binary discovery, store paths, URL safety and the l...