Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34348606
newkeyapprovaldialog.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
27 KB
Subscribers
None
newkeyapprovaldialog.cpp
View Options
/* -*- c++ -*-
newkeyapprovaldialog.cpp
This file is part of libkleopatra, the KDE keymanagement library
SPDX-FileCopyrightText: 2018 Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include
"newkeyapprovaldialog.h"
#include
"kleo/defaultkeyfilter.h"
#include
"keyselectioncombo.h"
#include
"progressdialog.h"
#include
"utils/formatting.h"
#include
"libkleo_debug.h"
#include
<QApplication>
#include
<QButtonGroup>
#include
<QDesktopWidget>
#include
<QDialogButtonBox>
#include
<QGroupBox>
#include
<QLabel>
#include
<QMap>
#include
<QPushButton>
#include
<QRadioButton>
#include
<QScrollArea>
#include
<QToolTip>
#include
<QVBoxLayout>
#include
<QGpgME/DefaultKeyGenerationJob>
#include
<QGpgME/CryptoConfig>
#include
<QGpgME/Protocol>
#include
<gpgme++/keygenerationresult.h>
#include
<gpgme++/key.h>
#include
<KLocalizedString>
#include
<KMessageBox>
using
namespace
Kleo
;
namespace
{
class
OpenPGPFilter
:
public
DefaultKeyFilter
{
public
:
OpenPGPFilter
()
:
DefaultKeyFilter
()
{
setIsOpenPGP
(
DefaultKeyFilter
::
Set
);
setCanEncrypt
(
DefaultKeyFilter
::
Set
);
}
};
static
std
::
shared_ptr
<
KeyFilter
>
s_pgpFilter
=
std
::
shared_ptr
<
KeyFilter
>
(
new
OpenPGPFilter
);
class
OpenPGPSignFilter
:
public
DefaultKeyFilter
{
public
:
OpenPGPSignFilter
()
:
DefaultKeyFilter
()
{
/* Also list unusable keys to make it transparent why they are unusable */
setDisabled
(
DefaultKeyFilter
::
NotSet
);
setRevoked
(
DefaultKeyFilter
::
NotSet
);
setExpired
(
DefaultKeyFilter
::
NotSet
);
setCanSign
(
DefaultKeyFilter
::
Set
);
setHasSecret
(
DefaultKeyFilter
::
Set
);
setIsOpenPGP
(
DefaultKeyFilter
::
Set
);
}
};
static
std
::
shared_ptr
<
KeyFilter
>
s_pgpSignFilter
=
std
::
shared_ptr
<
KeyFilter
>
(
new
OpenPGPSignFilter
);
class
SMIMEFilter
:
public
DefaultKeyFilter
{
public
:
SMIMEFilter
()
:
DefaultKeyFilter
()
{
setIsOpenPGP
(
DefaultKeyFilter
::
NotSet
);
setCanEncrypt
(
DefaultKeyFilter
::
Set
);
}
};
static
std
::
shared_ptr
<
KeyFilter
>
s_smimeFilter
=
std
::
shared_ptr
<
KeyFilter
>
(
new
SMIMEFilter
);
class
SMIMESignFilter
:
public
DefaultKeyFilter
{
public
:
SMIMESignFilter
()
:
DefaultKeyFilter
()
{
setDisabled
(
DefaultKeyFilter
::
NotSet
);
setRevoked
(
DefaultKeyFilter
::
NotSet
);
setExpired
(
DefaultKeyFilter
::
NotSet
);
setCanSign
(
DefaultKeyFilter
::
Set
);
setIsOpenPGP
(
DefaultKeyFilter
::
NotSet
);
setHasSecret
(
DefaultKeyFilter
::
Set
);
}
};
static
std
::
shared_ptr
<
KeyFilter
>
s_smimeSignFilter
=
std
::
shared_ptr
<
KeyFilter
>
(
new
SMIMESignFilter
);
static
std
::
shared_ptr
<
KeyFilter
>
s_defaultFilter
=
std
::
shared_ptr
<
KeyFilter
>
(
new
DefaultKeyFilter
);
class
SignFilter
:
public
DefaultKeyFilter
{
public
:
SignFilter
()
:
DefaultKeyFilter
()
{
setHasSecret
(
DefaultKeyFilter
::
Set
);
}
};
static
std
::
shared_ptr
<
KeyFilter
>
s_signFilter
=
std
::
shared_ptr
<
KeyFilter
>
(
new
SignFilter
);
/* Some decoration and a button to remove the filter for a keyselectioncombo */
class
ComboWidget
:
public
QWidget
{
Q_OBJECT
public
:
explicit
ComboWidget
(
KeySelectionCombo
*
combo
)
:
mCombo
(
combo
),
mFilterBtn
(
new
QPushButton
),
mFromOverride
(
GpgME
::
UnknownProtocol
)
{
auto
hLay
=
new
QHBoxLayout
(
this
);
auto
infoBtn
=
new
QPushButton
;
infoBtn
->
setIcon
(
QIcon
::
fromTheme
(
QStringLiteral
(
"help-contextual"
)));
infoBtn
->
setIconSize
(
QSize
(
22
,
22
));
infoBtn
->
setFlat
(
true
);
hLay
->
addWidget
(
infoBtn
);
hLay
->
addWidget
(
combo
,
1
);
hLay
->
addWidget
(
mFilterBtn
,
0
);
connect
(
infoBtn
,
&
QPushButton
::
clicked
,
this
,
[
this
,
infoBtn
]
()
{
QToolTip
::
showText
(
infoBtn
->
mapToGlobal
(
QPoint
())
+
QPoint
(
infoBtn
->
width
(),
0
),
mCombo
->
currentData
(
Qt
::
ToolTipRole
).
toString
(),
infoBtn
,
QRect
(),
30000
);
});
// Assume that combos start out with a filter
mFilterBtn
->
setIcon
(
QIcon
::
fromTheme
(
QStringLiteral
(
"kt-remove-filters"
)));
mFilterBtn
->
setToolTip
(
i18n
(
"Remove Filter"
));
// FIXME: This is ugly to enforce but otherwise the
// icon is broken.
combo
->
setMinimumHeight
(
22
);
mFilterBtn
->
setMinimumHeight
(
23
);
connect
(
mFilterBtn
,
&
QPushButton
::
clicked
,
this
,
[
this
]
()
{
const
QString
curFilter
=
mCombo
->
idFilter
();
if
(
curFilter
.
isEmpty
())
{
mCombo
->
setIdFilter
(
mLastIdFilter
);
mLastIdFilter
=
QString
();
mFilterBtn
->
setIcon
(
QIcon
::
fromTheme
(
QStringLiteral
(
"kt-remove-filters"
)));
mFilterBtn
->
setToolTip
(
i18n
(
"Remove Filter"
));
}
else
{
mLastIdFilter
=
curFilter
;
mFilterBtn
->
setIcon
(
QIcon
::
fromTheme
(
QStringLiteral
(
"kt-add-filters"
)));
mFilterBtn
->
setToolTip
(
i18n
(
"Add Filter"
));
mCombo
->
setIdFilter
(
QString
());
}
});
}
KeySelectionCombo
*
combo
()
{
return
mCombo
;
}
GpgME
::
Protocol
fromOverride
()
const
{
return
mFromOverride
;
}
void
setFromOverride
(
GpgME
::
Protocol
proto
)
{
mFromOverride
=
proto
;
}
private
:
KeySelectionCombo
*
mCombo
;
QPushButton
*
mFilterBtn
;
QString
mLastIdFilter
;
GpgME
::
Protocol
mFromOverride
;
};
static
enum
GpgME
::
UserID
::
Validity
keyValidity
(
const
GpgME
::
Key
&
key
)
{
enum
GpgME
::
UserID
::
Validity
validity
=
GpgME
::
UserID
::
Validity
::
Unknown
;
for
(
const
auto
&
uid
:
key
.
userIDs
())
{
if
(
validity
==
GpgME
::
UserID
::
Validity
::
Unknown
||
validity
>
uid
.
validity
())
{
validity
=
uid
.
validity
();
}
}
return
validity
;
}
static
bool
key_has_addr
(
const
GpgME
::
Key
&
key
,
const
QString
&
addr
)
{
for
(
const
auto
&
uid
:
key
.
userIDs
())
{
if
(
QString
::
fromStdString
(
uid
.
addrSpec
()).
toLower
()
==
addr
.
toLower
())
{
return
true
;
}
}
return
false
;
}
}
// namespace
class
NewKeyApprovalDialog
::
Private
{
private
:
enum
Action
{
Unset
,
GenerateKey
,
IgnoreKey
,
};
public
:
Private
(
NewKeyApprovalDialog
*
pub
,
GpgME
::
Protocol
forcedProtocol
,
GpgME
::
Protocol
presetProtocol
,
const
QString
&
sender
,
bool
allowMixed
)
:
mProto
(
forcedProtocol
),
mSender
(
sender
),
mAllowMixed
(
allowMixed
),
q
(
pub
)
{
// We do the translation here to avoid having the same string multiple times.
mGenerateTooltip
=
i18nc
(
"@info:tooltip for a 'Generate new key pair' action "
"in a combobox when a user does not yet have an OpenPGP or S/MIME key."
,
"Generate a new key using your E-Mail address.<br/><br/>"
"The key is necessary to decrypt and sign E-Mails. "
"You will be asked for a passphrase to protect this key and the protected key "
"will be stored in your home directory."
);
mMainLay
=
new
QVBoxLayout
;
QDialogButtonBox
*
btnBox
=
new
QDialogButtonBox
(
QDialogButtonBox
::
Ok
|
QDialogButtonBox
::
Cancel
);
mOkButton
=
btnBox
->
button
(
QDialogButtonBox
::
Ok
);
QObject
::
connect
(
btnBox
,
&
QDialogButtonBox
::
accepted
,
q
,
[
this
]
()
{
accepted
();
});
QObject
::
connect
(
btnBox
,
&
QDialogButtonBox
::
rejected
,
q
,
&
QDialog
::
reject
);
mScrollArea
=
new
QScrollArea
;
mScrollArea
->
setWidget
(
new
QWidget
);
mScrollLayout
=
new
QVBoxLayout
;
mScrollArea
->
widget
()
->
setLayout
(
mScrollLayout
);
mScrollArea
->
setWidgetResizable
(
true
);
mScrollArea
->
setSizeAdjustPolicy
(
QAbstractScrollArea
::
AdjustToContentsOnFirstShow
);
mScrollArea
->
setFrameStyle
(
QFrame
::
NoFrame
);
mScrollLayout
->
setContentsMargins
(
0
,
0
,
0
,
0
);
q
->
setWindowTitle
(
i18nc
(
"@title:window"
,
"Security approval"
));
auto
fmtLayout
=
new
QHBoxLayout
;
mFormatBtns
=
new
QButtonGroup
;
auto
pgpBtn
=
new
QRadioButton
(
i18n
(
"OpenPGP"
));
auto
smimeBtn
=
new
QRadioButton
(
i18n
(
"S/MIME"
));
mFormatBtns
->
addButton
(
pgpBtn
,
1
);
mFormatBtns
->
addButton
(
smimeBtn
,
2
);
mFormatBtns
->
setExclusive
(
true
);
fmtLayout
->
addStretch
(
-1
);
fmtLayout
->
addWidget
(
pgpBtn
);
fmtLayout
->
addWidget
(
smimeBtn
);
mMainLay
->
addLayout
(
fmtLayout
);
// Handle force / preset
if
(
forcedProtocol
==
GpgME
::
OpenPGP
)
{
pgpBtn
->
setChecked
(
true
);
pgpBtn
->
setVisible
(
false
);
smimeBtn
->
setVisible
(
false
);
}
else
if
(
forcedProtocol
==
GpgME
::
CMS
)
{
smimeBtn
->
setChecked
(
true
);
pgpBtn
->
setVisible
(
false
);
smimeBtn
->
setVisible
(
false
);
}
else
if
(
presetProtocol
==
GpgME
::
CMS
)
{
smimeBtn
->
setChecked
(
true
);
}
else
if
(
!
mAllowMixed
)
{
pgpBtn
->
setChecked
(
true
);
}
else
if
(
mAllowMixed
)
{
smimeBtn
->
setVisible
(
false
);
pgpBtn
->
setVisible
(
false
);
}
updateFilter
();
QObject
::
connect
(
mFormatBtns
,
static_cast
<
void
(
QButtonGroup
::*
)(
QAbstractButton
*
,
bool
)
>
(
&
QButtonGroup
::
buttonToggled
),
q
,
[
this
](
QAbstractButton
*
,
bool
)
{
updateFilter
();
});
mMainLay
->
addWidget
(
mScrollArea
);
mComplianceLbl
=
new
QLabel
;
mComplianceLbl
->
setVisible
(
false
);
auto
btnLayout
=
new
QHBoxLayout
;
btnLayout
->
addWidget
(
mComplianceLbl
);
btnLayout
->
addWidget
(
btnBox
);
mMainLay
->
addLayout
(
btnLayout
);
q
->
setLayout
(
mMainLay
);
}
~
Private
()
=
default
;
void
generateKey
(
KeySelectionCombo
*
combo
)
{
const
auto
&
addr
=
combo
->
property
(
"address"
).
toString
();
auto
job
=
new
QGpgME
::
DefaultKeyGenerationJob
(
q
);
auto
progress
=
new
Kleo
::
ProgressDialog
(
job
,
i18n
(
"Generating key for '%1'..."
,
addr
)
+
QStringLiteral
(
"
\n\n
"
)
+
i18n
(
"This can take several minutes."
),
q
);
progress
->
setWindowFlags
(
progress
->
windowFlags
()
&
~
Qt
::
WindowContextHelpButtonHint
);
progress
->
setWindowTitle
(
i18nc
(
"@title:window"
,
"Key generation"
));
progress
->
setModal
(
true
);
progress
->
setAutoClose
(
true
);
progress
->
setMinimumDuration
(
0
);
progress
->
setValue
(
0
);
mRunningJobs
<<
job
;
connect
(
job
,
&
QGpgME
::
DefaultKeyGenerationJob
::
result
,
q
,
[
this
,
job
,
combo
]
(
const
GpgME
::
KeyGenerationResult
&
result
)
{
handleKeyGenResult
(
result
,
job
,
combo
);
});
job
->
start
(
addr
,
QString
());
return
;
}
void
handleKeyGenResult
(
const
GpgME
::
KeyGenerationResult
&
result
,
QGpgME
::
Job
*
job
,
KeySelectionCombo
*
combo
)
{
mLastError
=
result
.
error
();
if
(
!
mLastError
||
mLastError
.
isCanceled
())
{
combo
->
setDefaultKey
(
QString
::
fromLatin1
(
result
.
fingerprint
()),
GpgME
::
OpenPGP
);
connect
(
combo
,
&
KeySelectionCombo
::
keyListingFinished
,
q
,
[
this
,
job
]
()
{
mRunningJobs
.
removeAll
(
job
);
});
combo
->
refreshKeys
();
}
else
{
mRunningJobs
.
removeAll
(
job
);
}
}
void
checkAccepted
()
{
if
(
mLastError
||
mLastError
.
isCanceled
())
{
KMessageBox
::
error
(
q
,
QString
::
fromLocal8Bit
(
mLastError
.
asString
()),
i18n
(
"Operation Failed"
));
mRunningJobs
.
clear
();
return
;
}
if
(
!
mRunningJobs
.
empty
())
{
return
;
}
/* Save the keys */
bool
isPGP
=
mFormatBtns
->
checkedId
()
==
1
;
bool
isSMIME
=
mFormatBtns
->
checkedId
()
==
2
;
mAcceptedEnc
.
clear
();
mAcceptedSig
.
clear
();
for
(
const
auto
combo
:
qAsConst
(
mEncCombos
))
{
const
auto
&
addr
=
combo
->
property
(
"address"
).
toString
();
const
auto
&
key
=
combo
->
currentKey
();
if
(
!
combo
->
isVisible
())
{
continue
;
}
if
(
isSMIME
&&
key
.
protocol
()
!=
GpgME
::
CMS
)
{
continue
;
}
if
(
isPGP
&&
key
.
protocol
()
!=
GpgME
::
OpenPGP
)
{
continue
;
}
if
(
mAcceptedEnc
.
contains
(
addr
))
{
mAcceptedEnc
[
addr
].
push_back
(
key
);
}
else
{
std
::
vector
<
GpgME
::
Key
>
vec
;
vec
.
push_back
(
key
);
mAcceptedEnc
.
insert
(
addr
,
vec
);
}
}
for
(
const
auto
combo
:
qAsConst
(
mSigningCombos
))
{
const
auto
key
=
combo
->
currentKey
();
if
(
!
combo
->
isVisible
())
{
continue
;
}
if
(
isSMIME
&&
key
.
protocol
()
!=
GpgME
::
CMS
)
{
continue
;
}
if
(
isPGP
&&
key
.
protocol
()
!=
GpgME
::
OpenPGP
)
{
continue
;
}
mAcceptedSig
.
push_back
(
combo
->
currentKey
());
}
q
->
accept
();
}
void
accepted
()
{
// We can assume everything was validly resolved, otherwise
// the OK button would have been disabled.
// Handle custom items now.
for
(
auto
combo
:
qAsConst
(
mAllCombos
))
{
auto
act
=
combo
->
currentData
(
Qt
::
UserRole
).
toInt
();
if
(
act
==
GenerateKey
)
{
generateKey
(
combo
);
// Only generate once
return
;
}
}
checkAccepted
();
}
void
updateFilter
()
{
const
bool
isPGP
=
!
mAllowMixed
&&
mFormatBtns
->
checkedId
()
==
1
;
const
bool
isSMIME
=
!
mAllowMixed
&&
mFormatBtns
->
checkedId
()
==
2
;
if
(
isSMIME
)
{
mCurEncFilter
=
s_smimeFilter
;
mCurSigFilter
=
s_smimeSignFilter
;
}
else
if
(
isPGP
)
{
mCurEncFilter
=
s_pgpFilter
;
mCurSigFilter
=
s_pgpSignFilter
;
}
else
{
mCurEncFilter
=
s_defaultFilter
;
mCurSigFilter
=
s_signFilter
;
}
for
(
auto
combo
:
qAsConst
(
mSigningCombos
))
{
combo
->
setKeyFilter
(
mCurSigFilter
);
auto
widget
=
qobject_cast
<
ComboWidget
*>
(
combo
->
parentWidget
());
if
(
!
widget
)
{
qCDebug
(
LIBKLEO_LOG
)
<<
"Failed to find signature combo widget"
;
continue
;
}
widget
->
setVisible
(
mAllowMixed
||
widget
->
fromOverride
()
==
GpgME
::
UnknownProtocol
||
((
isSMIME
&&
widget
->
fromOverride
()
==
GpgME
::
CMS
)
||
(
isPGP
&&
widget
->
fromOverride
()
==
GpgME
::
OpenPGP
)));
}
for
(
auto
combo
:
qAsConst
(
mEncCombos
))
{
combo
->
setKeyFilter
(
mCurEncFilter
);
auto
widget
=
qobject_cast
<
ComboWidget
*>
(
combo
->
parentWidget
());
if
(
!
widget
)
{
qCDebug
(
LIBKLEO_LOG
)
<<
"Failed to find combo widget"
;
continue
;
}
widget
->
setVisible
(
mAllowMixed
||
widget
->
fromOverride
()
==
GpgME
::
UnknownProtocol
||
((
isSMIME
&&
widget
->
fromOverride
()
==
GpgME
::
CMS
)
||
(
isPGP
&&
widget
->
fromOverride
()
==
GpgME
::
OpenPGP
)));
}
}
ComboWidget
*
createSigningCombo
(
const
QString
&
addr
,
const
GpgME
::
Key
&
key
)
{
auto
combo
=
new
KeySelectionCombo
();
#ifndef NDEBUG
combo
->
setObjectName
(
QStringLiteral
(
"signing key"
));
#endif
combo
->
setKeyFilter
(
mCurSigFilter
);
if
(
!
key
.
isNull
())
{
if
(
mAllowMixed
)
{
// do not set the key for a specific protocol if mixed protocols are allowed
combo
->
setDefaultKey
(
QString
::
fromLatin1
(
key
.
primaryFingerprint
()));
}
else
{
combo
->
setDefaultKey
(
QString
::
fromLatin1
(
key
.
primaryFingerprint
()),
key
.
protocol
());
}
}
if
(
key
.
isNull
()
&&
mProto
!=
GpgME
::
CMS
)
{
combo
->
appendCustomItem
(
QIcon
::
fromTheme
(
QStringLiteral
(
"document-new"
)),
i18n
(
"Generate a new key pair"
),
GenerateKey
,
mGenerateTooltip
);
}
combo
->
appendCustomItem
(
QIcon
::
fromTheme
(
QStringLiteral
(
"emblem-unavailable"
)),
i18n
(
"Don't confirm identity and integrity"
),
IgnoreKey
,
i18nc
(
"@info:tooltip for not selecting a key for signing."
,
"The E-Mail will not be cryptographically signed."
));
mSigningCombos
<<
combo
;
mAllCombos
<<
combo
;
combo
->
setProperty
(
"address"
,
addr
);
connect
(
combo
,
&
KeySelectionCombo
::
currentKeyChanged
,
q
,
[
this
]
()
{
updateOkButton
();
});
connect
(
combo
,
QOverload
<
int
>::
of
(
&
QComboBox
::
currentIndexChanged
),
q
,
[
this
]
()
{
updateOkButton
();
});
return
new
ComboWidget
(
combo
);
}
void
addSigningKeys
(
const
QMap
<
QString
,
std
::
vector
<
GpgME
::
Key
>
>
&
resolved
,
const
QStringList
&
unresolved
)
{
if
(
resolved
.
empty
()
&&
unresolved
.
empty
())
{
return
;
}
for
(
const
QString
&
addr
:
resolved
.
keys
())
{
auto
group
=
new
QGroupBox
(
i18nc
(
"Caption for signing key selection"
,
"Confirm identity '%1' as:"
,
addr
));
group
->
setAlignment
(
Qt
::
AlignLeft
);
mScrollLayout
->
addWidget
(
group
);
auto
sigLayout
=
new
QVBoxLayout
;
group
->
setLayout
(
sigLayout
);
for
(
const
auto
&
key
:
resolved
[
addr
])
{
auto
comboWidget
=
createSigningCombo
(
addr
,
key
);
if
(
key_has_addr
(
key
,
addr
))
{
comboWidget
->
combo
()
->
setIdFilter
(
addr
);
}
if
(
resolved
[
addr
].
size
()
>
1
)
{
comboWidget
->
setFromOverride
(
key
.
protocol
());
}
sigLayout
->
addWidget
(
comboWidget
);
}
}
for
(
const
QString
&
addr
:
qAsConst
(
unresolved
))
{
auto
group
=
new
QGroupBox
(
i18nc
(
"Caption for signing key selection, no key found"
,
"No key found for the address '%1':"
,
addr
));
group
->
setAlignment
(
Qt
::
AlignLeft
);
mScrollLayout
->
addWidget
(
group
);
auto
sigLayout
=
new
QHBoxLayout
;
group
->
setLayout
(
sigLayout
);
auto
comboWidget
=
createSigningCombo
(
addr
,
GpgME
::
Key
());
comboWidget
->
combo
()
->
setIdFilter
(
addr
);
sigLayout
->
addWidget
(
comboWidget
);
}
}
void
addEncryptionAddr
(
const
QString
&
addr
,
const
std
::
vector
<
GpgME
::
Key
>
&
keys
,
QGridLayout
*
encGrid
)
{
encGrid
->
addWidget
(
new
QLabel
(
addr
),
encGrid
->
rowCount
(),
0
);
for
(
const
auto
&
key
:
keys
)
{
auto
combo
=
new
KeySelectionCombo
(
false
);
#ifndef NDEBUG
combo
->
setObjectName
(
QStringLiteral
(
"encryption key"
));
#endif
combo
->
setKeyFilter
(
mCurEncFilter
);
if
(
!
key
.
isNull
())
{
if
(
mAllowMixed
)
{
// do not set the key for a specific protocol if mixed protocols are allowed
combo
->
setDefaultKey
(
QString
::
fromLatin1
(
key
.
primaryFingerprint
()));
}
else
{
combo
->
setDefaultKey
(
QString
::
fromLatin1
(
key
.
primaryFingerprint
()),
key
.
protocol
());
}
}
if
(
mSender
==
addr
&&
key
.
isNull
())
{
combo
->
appendCustomItem
(
QIcon
::
fromTheme
(
QStringLiteral
(
"document-new"
)),
i18n
(
"Generate a new key pair"
),
GenerateKey
,
mGenerateTooltip
);
}
combo
->
appendCustomItem
(
QIcon
::
fromTheme
(
QStringLiteral
(
"emblem-unavailable"
)),
i18n
(
"No key. Recipient will be unable to decrypt."
),
IgnoreKey
,
i18nc
(
"@info:tooltip for No Key selected for a specific recipient."
,
"Do not select a key for this recipient.<br/><br/>"
"The recipient will receive the encrypted E-Mail, but it can only "
"be decrypted with the other keys selected in this dialog."
));
if
(
key
.
isNull
()
||
key_has_addr
(
key
,
addr
))
{
combo
->
setIdFilter
(
addr
);
}
connect
(
combo
,
&
KeySelectionCombo
::
currentKeyChanged
,
q
,
[
this
]
()
{
updateOkButton
();
});
connect
(
combo
,
QOverload
<
int
>::
of
(
&
QComboBox
::
currentIndexChanged
),
q
,
[
this
]
()
{
updateOkButton
();
});
mEncCombos
<<
combo
;
mAllCombos
<<
combo
;
combo
->
setProperty
(
"address"
,
addr
);
auto
comboWidget
=
new
ComboWidget
(
combo
);
if
(
keys
.
size
()
>
1
)
{
comboWidget
->
setFromOverride
(
key
.
protocol
());
}
encGrid
->
addWidget
(
comboWidget
,
encGrid
->
rowCount
(),
0
,
1
,
2
);
}
}
void
addEncryptionKeys
(
const
QMap
<
QString
,
std
::
vector
<
GpgME
::
Key
>
>
&
resolved
,
const
QStringList
&
unresolved
)
{
if
(
resolved
.
empty
()
&&
unresolved
.
empty
())
{
return
;
}
auto
group
=
new
QGroupBox
(
i18n
(
"Encrypt to:"
));
group
->
setAlignment
(
Qt
::
AlignLeft
);
auto
encGrid
=
new
QGridLayout
;
group
->
setLayout
(
encGrid
);
mScrollLayout
->
addWidget
(
group
);
for
(
const
QString
&
addr
:
resolved
.
keys
())
{
addEncryptionAddr
(
addr
,
resolved
[
addr
],
encGrid
);
}
std
::
vector
<
GpgME
::
Key
>
dummy
;
dummy
.
push_back
(
GpgME
::
Key
());
for
(
const
QString
&
addr
:
unresolved
)
{
addEncryptionAddr
(
addr
,
dummy
,
encGrid
);
}
encGrid
->
setColumnStretch
(
1
,
-1
);
mScrollLayout
->
addStretch
(
-1
);
}
void
updateOkButton
()
{
static
QString
origOkText
=
mOkButton
->
text
();
bool
isGenerate
=
false
;
bool
isAllIgnored
=
true
;
// Check if generate is selected.
for
(
auto
combo
:
mAllCombos
)
{
auto
act
=
combo
->
currentData
(
Qt
::
UserRole
).
toInt
();
if
(
act
==
GenerateKey
)
{
mOkButton
->
setText
(
i18n
(
"Generate"
));
isGenerate
=
true
;
}
if
(
act
!=
IgnoreKey
)
{
isAllIgnored
=
false
;
}
}
// If we don't encrypt the ok button is always enabled. But otherwise
// we only enable it if we encrypt to at least one recipient.
if
(
!
mEncCombos
.
size
())
{
mOkButton
->
setEnabled
(
true
);
}
else
{
mOkButton
->
setEnabled
(
!
isAllIgnored
);
}
if
(
!
isGenerate
)
{
mOkButton
->
setText
(
origOkText
);
}
if
(
Formatting
::
complianceMode
()
!=
QLatin1String
(
"de-vs"
))
{
return
;
}
// Handle compliance
bool
de_vs
=
true
;
bool
isPGP
=
mFormatBtns
->
checkedId
()
==
1
;
bool
isSMIME
=
mFormatBtns
->
checkedId
()
==
2
;
for
(
const
auto
combo
:
qAsConst
(
mEncCombos
))
{
const
auto
&
key
=
combo
->
currentKey
();
if
(
!
combo
->
isVisible
())
{
continue
;
}
if
(
isSMIME
&&
key
.
protocol
()
!=
GpgME
::
CMS
)
{
continue
;
}
if
(
isPGP
&&
key
.
protocol
()
!=
GpgME
::
OpenPGP
)
{
continue
;
}
if
(
!
Formatting
::
isKeyDeVs
(
key
)
||
keyValidity
(
key
)
<
GpgME
::
UserID
::
Validity
::
Full
)
{
de_vs
=
false
;
break
;
}
}
if
(
de_vs
)
{
for
(
const
auto
combo
:
qAsConst
(
mSigningCombos
))
{
const
auto
key
=
combo
->
currentKey
();
if
(
!
combo
->
isVisible
())
{
continue
;
}
if
(
isSMIME
&&
key
.
protocol
()
!=
GpgME
::
CMS
)
{
continue
;
}
if
(
isPGP
&&
key
.
protocol
()
!=
GpgME
::
OpenPGP
)
{
continue
;
}
if
(
!
Formatting
::
isKeyDeVs
(
key
)
||
keyValidity
(
key
)
<
GpgME
::
UserID
::
Validity
::
Full
)
{
de_vs
=
false
;
break
;
}
}
}
mOkButton
->
setIcon
(
QIcon
::
fromTheme
(
de_vs
?
QStringLiteral
(
"security-high"
)
:
QStringLiteral
(
"security-medium"
)));
mOkButton
->
setStyleSheet
(
QStringLiteral
(
"background-color: "
)
+
(
de_vs
?
QStringLiteral
(
"#D5FAE2"
)
// KColorScheme(QPalette::Active, KColorScheme::View).background(KColorScheme::PositiveBackground).color().name()
:
QStringLiteral
(
"#FAE9EB"
)));
//KColorScheme(QPalette::Active, KColorScheme::View).background(KColorScheme::NegativeBackground).color().name()));
mComplianceLbl
->
setText
(
de_vs
?
i18nc
(
"%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant"
,
"%1 communication possible."
,
Formatting
::
deVsString
())
:
i18nc
(
"%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant"
,
"%1 communication not possible."
,
Formatting
::
deVsString
()));
mComplianceLbl
->
setVisible
(
true
);
}
void
selectionChanged
()
{
bool
isPGP
=
false
;
bool
isCMS
=
false
;
for
(
const
auto
combo
:
mEncCombos
)
{
isPGP
|=
combo
->
currentKey
().
protocol
()
==
GpgME
::
OpenPGP
;
isCMS
|=
combo
->
currentKey
().
protocol
()
==
GpgME
::
CMS
;
if
(
isPGP
&&
isCMS
)
{
break
;
}
}
}
GpgME
::
Protocol
mProto
;
QList
<
KeySelectionCombo
*>
mSigningCombos
;
QList
<
KeySelectionCombo
*>
mEncCombos
;
QList
<
KeySelectionCombo
*>
mAllCombos
;
QScrollArea
*
mScrollArea
;
QVBoxLayout
*
mScrollLayout
;
QPushButton
*
mOkButton
;
QVBoxLayout
*
mMainLay
;
QButtonGroup
*
mFormatBtns
;
std
::
shared_ptr
<
KeyFilter
>
mCurSigFilter
;
std
::
shared_ptr
<
KeyFilter
>
mCurEncFilter
;
QString
mSender
;
bool
mAllowMixed
;
NewKeyApprovalDialog
*
q
;
QList
<
QGpgME
::
Job
*>
mRunningJobs
;
GpgME
::
Error
mLastError
;
QLabel
*
mComplianceLbl
;
QMap
<
QString
,
std
::
vector
<
GpgME
::
Key
>
>
mAcceptedEnc
;
std
::
vector
<
GpgME
::
Key
>
mAcceptedSig
;
QString
mGenerateTooltip
;
};
NewKeyApprovalDialog
::
NewKeyApprovalDialog
(
const
QMap
<
QString
,
std
::
vector
<
GpgME
::
Key
>
>
&
resolvedSigningKeys
,
const
QMap
<
QString
,
std
::
vector
<
GpgME
::
Key
>
>
&
resolvedRecp
,
const
QStringList
&
unresolvedSigKeys
,
const
QStringList
&
unresolvedRecp
,
const
QString
&
sender
,
bool
allowMixed
,
GpgME
::
Protocol
forcedProtocol
,
GpgME
::
Protocol
presetProtocol
,
QWidget
*
parent
,
Qt
::
WindowFlags
f
)
:
QDialog
(
parent
,
f
),
d
(
new
Private
(
this
,
forcedProtocol
,
presetProtocol
,
sender
,
allowMixed
))
{
d
->
addSigningKeys
(
resolvedSigningKeys
,
unresolvedSigKeys
);
d
->
addEncryptionKeys
(
resolvedRecp
,
unresolvedRecp
);
d
->
updateFilter
();
d
->
updateOkButton
();
const
auto
size
=
sizeHint
();
const
auto
desk
=
QApplication
::
desktop
()
->
screenGeometry
(
this
);
resize
(
QSize
(
desk
.
width
()
/
3
,
qMin
(
size
.
height
(),
desk
.
height
()
/
2
)));
}
Kleo
::
NewKeyApprovalDialog
::~
NewKeyApprovalDialog
()
=
default
;
std
::
vector
<
GpgME
::
Key
>
NewKeyApprovalDialog
::
signingKeys
()
{
return
d
->
mAcceptedSig
;
}
QMap
<
QString
,
std
::
vector
<
GpgME
::
Key
>
>
NewKeyApprovalDialog
::
encryptionKeys
()
{
return
d
->
mAcceptedEnc
;
}
#include
"newkeyapprovaldialog.moc"
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Thu, Jan 1, 2:22 AM (21 h, 2 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
98/c6/18b09f9dfc712a273f4be4119ffb
Attached To
rLIBKLEO Libkleo
Event Timeline
Log In to Comment