5#include "ui_usersdialog.h"
11#include <QRegularExpression>
31 connect(ui->buttonBox, &QDialogButtonBox::rejected,
this, &QDialog::reject);
41void UsersDialog::connectSignals() {
42 connect(ui->buttonBox, &QDialogButtonBox::accepted,
this,
44 connect(ui->buttonBox, &QDialogButtonBox::rejected,
this, &QDialog::reject);
45 connect(ui->listWidget, &QListWidget::itemChanged,
this,
46 &UsersDialog::itemChange);
48 ui->lineEdit->setClearButtonEnabled(
true);
54void UsersDialog::restoreDialogState() {
56 bool hasSavedGeometry = !savedGeometry.isEmpty();
57 if (hasSavedGeometry) {
58 restoreGeometry(savedGeometry);
62 }
else if (hasSavedGeometry) {
68auto UsersDialog::loadGpgKeys() ->
bool {
70 if (users.isEmpty()) {
71 QMessageBox::critical(parentWidget(), tr(
"Keylist missing"),
72 tr(
"Could not fetch list of available GPG keys"));
77 markSecretKeys(users);
83void UsersDialog::markSecretKeys(QList<UserInfo> &users) {
85 QSet<QString> secretKeyIds;
86 for (
const UserInfo &sec : secret_keys) {
87 secretKeyIds.insert(sec.key_id);
89 for (
auto &user : users) {
90 if (secretKeyIds.contains(user.key_id)) {
91 user.have_secret =
true;
96void UsersDialog::loadRecipients() {
99 m_dir.isEmpty() ?
"" : m_dir,
" ", &count);
101 QList<UserInfo> selectedUsers =
103 QSet<QString> selectedKeyIds;
104 for (
const UserInfo &sel : selectedUsers) {
105 selectedKeyIds.insert(sel.key_id);
107 for (
auto &user : m_userList) {
108 if (selectedKeyIds.contains(user.key_id)) {
113 if (count > selectedUsers.size()) {
115 m_dir.isEmpty() ?
"" : m_dir);
119 QList<UserInfo> resolvedKeys =
122 QSet<QString> resolvedKeyIds;
123 for (
const UserInfo &key : resolvedKeys) {
124 resolvedKeyIds.insert(key.key_id);
129 QSet<QString> resolvedRecipients;
130 for (
const UserInfo &key : resolvedKeys) {
131 resolvedRecipients.insert(key.key_id);
134 if (!key.name.isEmpty()) {
135 resolvedRecipients.insert(
136 key.name.section(
'@', 0, 0));
137 resolvedRecipients.insert(key.name);
141 for (
const QString &recipient : allRecipients) {
142 if (!resolvedKeyIds.contains(recipient) &&
143 !resolvedRecipients.contains(recipient) &&
144 !selectedKeyIds.contains(recipient)) {
148 i.
name =
" ?? " + tr(
"Key not found in keyring");
149 m_userList.append(i);
175 if (!isMaximized()) {
189 switch (event->key()) {
191 ui->lineEdit->clear();
202void UsersDialog::itemChange(QListWidgetItem *item) {
207 const int index = item->data(Qt::UserRole).toInt(&ok);
210 qWarning() <<
"UsersDialog::itemChange: invalid user index data for item";
214 if (index < 0 || index >= m_userList.size()) {
216 qWarning() <<
"UsersDialog::itemChange: user index out of range:" << index
217 <<
"valid range is [0," << (m_userList.size() - 1) <<
"]";
221 m_userList[index].enabled = item->checkState() == Qt::Checked;
229void UsersDialog::populateList(
const QString &filter) {
231 m_cachedDateTimeValid =
false;
233 QString patternString =
"*" + filter +
"*";
234 if (m_cachedPatternString != patternString) {
235 QRegularExpression re(
236 QRegularExpression::wildcardToRegularExpression(patternString),
237 QRegularExpression::CaseInsensitiveOption);
239 m_cachedNameFilter = re;
240 m_cachedPatternString = patternString;
243 const QRegularExpression &nameFilter = m_cachedNameFilter;
244 ui->listWidget->clear();
246 for (
int i = 0; i < m_userList.size(); ++i) {
247 const auto &user = m_userList.at(i);
248 if (!passesFilter(user, filter, nameFilter)) {
252 auto *item =
new QListWidgetItem(buildUserText(user), ui->listWidget);
253 applyUserStyling(item, user);
254 item->setCheckState(user.enabled ? Qt::Checked : Qt::Unchecked);
255 item->setData(Qt::UserRole, QVariant::fromValue(i));
256 ui->listWidget->addItem(item);
267bool UsersDialog::passesFilter(
const UserInfo &user,
const QString &filter,
268 const QRegularExpression &nameFilter)
const {
269 if (!filter.isEmpty() && !nameFilter.match(user.
name).hasMatch()) {
272 if (!user.
isValid() && !ui->checkBox->isChecked()) {
275 const bool expired = isUserExpired(user);
276 return !(expired && !ui->checkBox->isChecked());
284auto UsersDialog::isUserExpired(
const UserInfo &user)
const ->
bool {
285 if (!m_cachedDateTimeValid) {
286 m_cachedCurrentDateTime = QDateTime::currentDateTime();
287 m_cachedDateTimeValid =
true;
289 return user.
expiry.toSecsSinceEpoch() > 0 &&
290 m_cachedCurrentDateTime > user.
expiry;
298QString UsersDialog::buildUserText(
const UserInfo &user)
const {
299 QString text = user.
name +
"\n" + user.
key_id;
300 if (user.
created.toSecsSinceEpoch() > 0) {
301 text +=
" " + tr(
"created") +
" " +
302 QLocale::system().toString(user.
created, QLocale::ShortFormat);
304 if (user.
expiry.toSecsSinceEpoch() > 0) {
305 text +=
" " + tr(
"expires") +
" " +
306 QLocale::system().toString(user.
expiry, QLocale::ShortFormat);
316void UsersDialog::applyUserStyling(QListWidgetItem *item,
318 const QString originalText = item->text();
320 const QPalette palette = QApplication::palette();
321 item->setForeground(palette.color(QPalette::Link));
322 QFont font = item->font();
326 item->setBackground(Qt::darkRed);
327 item->setForeground(Qt::white);
328 item->setText(tr(
"[INVALID] ") + originalText);
329 }
else if (isUserExpired(user)) {
330 item->setForeground(Qt::darkRed);
331 item->setText(tr(
"[EXPIRED] ") + originalText);
333 item->setBackground(Qt::darkYellow);
334 item->setForeground(Qt::white);
335 item->setText(tr(
"[PARTIAL] ") + originalText);
337 item->setText(originalText);
345void UsersDialog::on_lineEdit_textChanged(
const QString &filter) {
346 populateList(filter);
352void UsersDialog::on_checkBox_clicked() { populateList(ui->lineEdit->text()); }
static auto getDialogPos(const QString &key, const QPoint &defaultValue=QVariant().toPoint()) -> QPoint
Get saved dialog position.
static auto getPass() -> Pass *
Get currently active pass backend instance.
static void setDialogPos(const QString &key, const QPoint &pos)
Save dialog position.
static auto getDialogSize(const QString &key, const QSize &defaultValue=QVariant().toSize()) -> QSize
Get saved dialog size.
static void setDialogSize(const QString &key, const QSize &size)
Save dialog size.
static void setDialogMaximized(const QString &key, const bool &maximized)
Save dialog maximized state.
static auto isDialogMaximized(const QString &key, const bool &defaultValue=QVariant().toBool()) -> bool
Get dialog maximized state.
static void setDialogGeometry(const QString &key, const QByteArray &geometry)
Save dialog geometry.
static auto getDialogGeometry(const QString &key, const QByteArray &defaultValue=QVariant().toByteArray()) -> QByteArray
Get saved dialog geometry.
~UsersDialog() override
Destructor.
void keyPressEvent(QKeyEvent *event) override
Handle key press.
void accept() override
Handle dialog acceptance.
void closeEvent(QCloseEvent *event) override
Handle close event.
UsersDialog(const QString &dir, QWidget *parent=nullptr)
Construct users dialog.
Debug utilities for QtPass.
Stores key info lines including validity, creation date and more.
bool have_secret
UserInfo::have_secret whether secret key is available (can decrypt with this key).
bool enabled
UserInfo::enabled Whether this user/key is enabled for normal use. True when the key should be treate...
QString key_id
UserInfo::key_id hexadecimal representation of the GnuPG key identifier.
auto fullyValid() const -> bool
UserInfo::fullyValid when validity is f or u. http://git.gnupg.org/cgi-bin/gitweb....
auto isValid() const -> bool
UserInfo::isValid when fullyValid or marginallyValid.
QDateTime created
UserInfo::created date/time when key was created.
QString name
UserInfo::name GPG user ID / full name.
QDateTime expiry
UserInfo::expiry date/time when key expires.