33 #include <config-kleopatra.h>
49 #include <kleo/stl_util.h>
51 #include <gpgme++/key.h>
53 #include <kmime/kmime_header_parsing.h>
55 #include <KLocalizedString>
60 #include <QStackedWidget>
61 #include <QToolButton>
63 #include <QDialogButtonBox>
65 #include <QRadioButton>
66 #include <QPushButton>
67 #include <QStylePainter>
72 #include <boost/shared_ptr.hpp>
73 #include <boost/bind.hpp>
79 using namespace Kleo::Crypto;
80 using namespace Kleo::Crypto::Gui;
81 using namespace Kleo::Dialogs;
82 using namespace GpgME;
83 using namespace boost;
85 Q_DECLARE_METATYPE( GpgME::Key )
86 Q_DECLARE_METATYPE( GpgME::UserID )
97 Q_PROPERTY(
QString initialText READ initialText WRITE setInitialText )
98 Q_PROPERTY(
QIcon initialIcon READ initialIcon WRITE setInitialIcon )
100 explicit ComboBox(
QWidget * parent=0 )
108 explicit ComboBox(
const QString & initialText,
QWidget * parent=0 )
110 m_initialText( initialText ),
116 explicit ComboBox(
const QIcon & initialIcon,
const QString & initialText,
QWidget * parent=0 )
118 m_initialText( initialText ),
119 m_initialIcon( initialIcon )
124 QString initialText()
const {
return m_initialText; }
125 QIcon initialIcon()
const {
return m_initialIcon; }
128 void setInitialText(
const QString & txt ) {
129 if ( txt == m_initialText )
132 if ( currentIndex() == -1 )
135 void setInitialIcon(
const QIcon & icon ) {
136 if ( icon.
cacheKey() == m_initialIcon.cacheKey() )
138 m_initialIcon = icon;
139 if ( currentIndex() == -1 )
146 p.setPen( palette().color( QPalette::Text ) );
148 initStyleOption( &opt );
149 p.drawComplexControl( QStyle::CC_ComboBox, opt );
151 if ( currentIndex() == -1 ) {
152 opt.currentText = m_initialText;
153 opt.currentIcon = m_initialIcon;
155 p.drawControl( QStyle::CE_ComboBoxLabel, opt );
163 static QString make_initial_text(
const std::vector<Key> & keys ) {
165 return i18n(
"(no matching certificates found)");
167 return i18n(
"Please select a certificate");
170 class KeysComboBox :
public ComboBox {
173 explicit KeysComboBox(
QWidget * parent=0 )
174 : ComboBox( parent ) {}
175 explicit KeysComboBox(
const QString & initialText,
QWidget * parent=0 )
176 : ComboBox( initialText, parent ) {}
177 explicit KeysComboBox(
const std::vector<Key> & keys,
QWidget * parent=0 )
178 : ComboBox( make_initial_text( keys ), parent ) { setKeys( keys ); }
180 void setKeys(
const std::vector<Key> & keys ) {
182 Q_FOREACH(
const Key & key, keys )
186 std::vector<Key> keys()
const {
187 std::vector<Key> result;
188 result.reserve( count() );
189 for (
int i = 0, end = count() ; i != end ; ++i )
190 result.push_back( qvariant_cast<Key>( itemData(i) ) );
194 int findOrAdd(
const Key & key ) {
195 for (
int i = 0, end = count() ; i != end ; ++i )
196 if ( _detail::ByFingerprint<std::equal_to>()( key, qvariant_cast<Key>( itemData(i) ) ) )
202 void addAndSelectCertificate(
const Key & key ) {
203 setCurrentIndex( findOrAdd( key ) );
206 Key currentKey()
const {
207 return qvariant_cast<Key>( itemData( currentIndex() ) );
214 static const unsigned int NumColumns = 4;
216 Line(
const QString & toFrom,
const QString & mailbox,
const std::vector<Key> & pgp,
bool pgpAmbig,
const std::vector<Key> & cms,
bool cmsAmbig,
QWidget *
q,
QGridLayout & glay )
217 : pgpAmbiguous( pgpAmbig ),
218 cmsAmbiguous( cmsAmbig ),
219 toFromLB( new
QLabel( toFrom, q ) ),
220 mailboxLB( new
QLabel( mailbox, q ) ),
222 pgpCB( new KeysComboBox( pgp, sbox ) ),
223 cmsCB( new KeysComboBox( cms, sbox ) ),
224 noProtocolCB( new KeysComboBox( i18n(
"(please choose between OpenPGP and S/MIME first)"), sbox ) ),
237 toFromLB->setFont( bold );
239 mailboxLB->setTextFormat( Qt::PlainText );
240 toolTB->setText( i18n(
"...") );
242 pgpCB->setEnabled( !pgp.empty() );
243 cmsCB->setEnabled( !cms.empty() );
244 noProtocolCB->setEnabled(
false );
246 pgpCB->setKeys( pgp );
248 pgpCB->setCurrentIndex( -1 );
250 cmsCB->setKeys( cms );
252 cmsCB->setCurrentIndex( -1 );
254 sbox->addWidget( pgpCB );
255 sbox->addWidget( cmsCB );
256 sbox->addWidget( noProtocolCB );
257 sbox->setCurrentWidget( noProtocolCB );
260 unsigned int col = 0;
265 assert( col == NumColumns );
267 q->
connect( pgpCB, SIGNAL(currentIndexChanged(
int)), SLOT(slotCompleteChanged()) );
268 q->
connect( cmsCB, SIGNAL(currentIndexChanged(
int)), SLOT(slotCompleteChanged()) );
269 q->
connect( toolTB, SIGNAL(clicked()), SLOT(slotCertificateSelectionDialogRequested()) );
272 KeysComboBox * comboBox( Protocol proto )
const {
281 return mailboxLB->text();
284 void addAndSelectCertificate(
const Key & key )
const {
285 if ( KeysComboBox *
const cb = comboBox( key.protocol() ) ) {
286 cb->addAndSelectCertificate( key );
287 cb->setEnabled(
true );
291 void showHide( Protocol proto,
bool & first,
bool showAll,
bool op )
const {
292 if ( op && ( showAll || wasInitiallyAmbiguous( proto ) ) ) {
294 toFromLB->setVisible( first );
297 QFont font = mailboxLB->font();
298 font.
setBold( wasInitiallyAmbiguous( proto ) );
299 mailboxLB->setFont( font );
301 sbox->setCurrentIndex( proto );
315 bool wasInitiallyAmbiguous( Protocol proto )
const {
316 return proto ==
OpenPGP && pgpAmbiguous
317 || proto ==
CMS && cmsAmbiguous ;
320 bool isStillAmbiguous( Protocol proto )
const {
322 const KeysComboBox *
const cb = comboBox( proto );
323 return cb->currentIndex() == -1 ;
326 Key key( Protocol proto )
const {
328 const KeysComboBox *
const cb = comboBox( proto );
329 return cb->currentKey();
332 const QToolButton * toolButton()
const {
return toolTB; }
342 bool pgpAmbiguous : 1;
343 bool cmsAmbiguous : 1;
348 KeysComboBox * pgpCB;
349 KeysComboBox * cmsCB;
350 KeysComboBox * noProtocolCB;
368 dlg->
setCustomLabelText( i18n(
"Please select an encryption certificate for recipient \"%1\"", mailbox ) );
369 dlg->
setOptions( CertificateSelectionDialog::SingleSelection |
370 CertificateSelectionDialog::EncryptOnly |
378 dlg->
setCustomLabelText( i18n(
"Please select a signing certificate for sender \"%1\"", mailbox ) );
379 dlg->
setOptions( CertificateSelectionDialog::SingleSelection |
380 CertificateSelectionDialog::SignOnly |
381 CertificateSelectionDialog::SecretKeys |
388 sign && enc ? i18n(
"Kleopatra cannot unambiguously determine matching certificates "
389 "for all recipients/senders of the message.\n"
390 "Please select the correct certificates for each recipient:") :
391 sign ? i18n(
"Kleopatra cannot unambiguously determine matching certificates "
392 "for the sender of the message.\n"
393 "Please select the correct certificates for the sender:") :
394 enc ? i18n(
"Kleopatra cannot unambiguously determine matching certificates "
395 "for all recipients of the message.\n"
396 "Please select the correct certificates for each recipient:" ) :
402 enc ? i18n(
"Please verify that correct certificates have been selected for each recipient:") :
403 sign ? i18n(
"Please verify that the correct certificate has been selected for the sender:") :
407 class SignEncryptEMailConflictDialog::Private {
408 friend class ::Kleo::Crypto::Gui::SignEncryptEMailConflictDialog;
417 presetProtocol( UnknownProtocol ),
424 void updateTopLabelText() {
429 void showHideWidgets() {
430 const Protocol proto = q->selectedProtocol();
431 const bool quickMode = q->isQuickMode();
433 const bool needProtocolSelection = presetProtocol == UnknownProtocol ;
435 const bool needShowAllRecipientsCB =
437 needProtocolSelection ? needShowAllRecipients(
OpenPGP ) || needShowAllRecipients(
CMS ) :
438 needShowAllRecipients( proto )
441 ui.showAllRecipientsCB.setVisible( needShowAllRecipientsCB );
443 ui.pgpRB.setVisible( needProtocolSelection );
444 ui.cmsRB.setVisible( needProtocolSelection );
446 const bool showAll = !needShowAllRecipientsCB || ui.showAllRecipientsCB.isChecked();
450 Q_FOREACH(
const Line & line, ui.signers )
451 line.showHide( proto, first, showAll, sign );
452 ui.selectSigningCertificatesGB.setVisible( sign && ( showAll || !first ) );
455 Q_FOREACH( const Line & line, ui.recipients )
456 line.showHide( proto, first, showAll, encrypt );
457 ui.selectEncryptionCertificatesGB.setVisible( encrypt && ( showAll || !first ) );
460 bool needShowAllRecipients( Protocol proto )
const {
462 if (
const unsigned int num = kdtools::count_if( ui.signers, boost::bind( &Line::wasInitiallyAmbiguous, _1, proto ) ) )
463 if ( num != ui.signers.size() )
466 if (
const unsigned int num = kdtools::count_if( ui.recipients, boost::bind( &Line::wasInitiallyAmbiguous, _1, proto ) ) )
467 if ( num != ui.recipients.size() )
472 void createSendersAndRecipients() {
473 ui.clearSendersAndRecipients();
475 ui.addSelectSigningCertificatesGB();
476 Q_FOREACH(
const Sender & s, senders )
479 ui.addSelectEncryptionCertificatesGB();
480 Q_FOREACH( const
Sender & s, senders )
482 Q_FOREACH( const
Recipient & r, recipients )
486 void addSigner( const
Sender & s ) {
487 ui.addSigner( s.mailbox().prettyAddress(),
488 s.signingCertificateCandidates(
OpenPGP ),
489 s.isSigningAmbiguous(
OpenPGP ),
490 s.signingCertificateCandidates(
CMS ),
491 s.isSigningAmbiguous(
CMS ),
495 void addRecipient(
const Sender & s ) {
496 ui.addRecipient( s.
mailbox().prettyAddress(),
504 void addRecipient(
const Recipient & r ) {
505 ui.addRecipient( r.
mailbox().prettyAddress(),
513 bool isComplete( Protocol proto )
const;
516 void enableDisableOkButton() {
517 ui.setOkButtonEnabled( q->isComplete() );
519 void slotCompleteChanged() {
520 enableDisableOkButton();
522 void slotShowAllRecipientsToggled(
bool ) {
525 void slotProtocolChanged() {
527 enableDisableOkButton();
529 void slotCertificateSelectionDialogRequested() {
531 const Protocol proto = q->selectedProtocol();
533 Q_FOREACH(
const Line & l, ui.signers )
534 if ( s == l.toolButton() ) {
537 l.addAndSelectCertificate( dlg->selectedCertificate() );
541 Q_FOREACH(
const Line & l, ui.recipients )
542 if ( s == l.toolButton() ) {
545 l.addAndSelectCertificate( dlg->selectedCertificate() );
553 std::vector<Sender> senders;
554 std::vector<Recipient> recipients;
558 Protocol presetProtocol;
562 QLabel conflictTopLB, quickModeTopLB;
566 QGroupBox selectEncryptionCertificatesGB;
572 std::vector<Line> signers, recipients;
574 void setOkButtonEnabled(
bool enable ) {
581 showAllRecipientsCB( i18n(
"Show all recipients"), q ),
582 pgpRB( i18n(
"OpenPGP"), q ),
583 cmsRB( i18n(
"S/MIME"), q ),
584 selectSigningCertificatesGB( i18n(
"Select Signing Certificate"), q ),
585 selectEncryptionCertificatesGB( i18n(
"Select Encryption Certificate"), q ),
586 quickModeCB( i18n(
"Only show this dialog in case of conflicts (experimental)"), q ),
609 conflictTopLB.hide();
611 selectSigningCertificatesGB.setFlat(
true );
612 selectEncryptionCertificatesGB.setFlat(
true );
613 selectSigningCertificatesGB.setAlignment( Qt::AlignCenter );
614 selectEncryptionCertificatesGB.setAlignment( Qt::AlignCenter );
619 vlay.setSizeConstraint( QLayout::SetMinimumSize );
621 vlay.addWidget( &conflictTopLB );
622 vlay.addWidget( &quickModeTopLB );
624 hlay.addWidget( &showAllRecipientsCB );
625 hlay.addStretch( 1 );
626 hlay.addWidget( &pgpRB );
627 hlay.addWidget( &cmsRB );
628 vlay.addLayout( &hlay );
630 addSelectSigningCertificatesGB();
631 addSelectEncryptionCertificatesGB();
632 vlay.addLayout( &glay );
634 vlay.addStretch( 1 );
636 vlay.addWidget( &quickModeCB, 0, Qt::AlignCenter );
637 vlay.addWidget( &buttonBox );
639 connect( &buttonBox, SIGNAL(accepted()), q, SLOT(accept()) );
640 connect( &buttonBox, SIGNAL(rejected()), q, SLOT(reject()) );
642 connect( &showAllRecipientsCB, SIGNAL(toggled(
bool)),
643 q, SLOT(slotShowAllRecipientsToggled(
bool)) );
644 connect( &pgpRB, SIGNAL(toggled(
bool)),
645 q, SLOT(slotProtocolChanged()) );
646 connect( &cmsRB, SIGNAL(toggled(
bool)),
647 q, SLOT(slotProtocolChanged()) );
650 void clearSendersAndRecipients() {
651 std::vector<Line> sig, enc;
653 enc.swap( recipients );
654 kdtools::for_each( sig, mem_fn( &Line::kill ) );
655 kdtools::for_each( enc, mem_fn( &Line::kill ) );
660 void addSelectSigningCertificatesGB() {
661 glay.
addWidget( &selectSigningCertificatesGB, glay.
rowCount(), 0, 1, Line::NumColumns );
663 void addSelectEncryptionCertificatesGB() {
664 glay.
addWidget( &selectEncryptionCertificatesGB, glay.
rowCount(), 0, 1, Line::NumColumns );
667 void addSigner(
const QString & mailbox,
668 const std::vector<Key> & pgp,
bool pgpAmbiguous,
669 const std::vector<Key> & cms,
bool cmsAmbiguous,
QWidget * q )
671 Line line( i18n(
"From:"), mailbox, pgp, pgpAmbiguous, cms, cmsAmbiguous, q, glay );
672 signers.push_back( line );
675 void addRecipient(
const QString & mailbox,
676 const std::vector<Key> & pgp,
bool pgpAmbiguous,
677 const std::vector<Key> & cms,
bool cmsAmbiguous,
QWidget * q )
679 Line line( i18n(
"To:"), mailbox, pgp, pgpAmbiguous, cms, cmsAmbiguous, q, glay );
680 recipients.push_back( line );
687 :
QDialog( parent, f ),
d( new Private( this ) )
695 if ( p == d->presetProtocol )
701 d->presetProtocol = p;
702 d->showHideWidgets();
703 d->enableDisableOkButton();
707 if ( d->presetProtocol != UnknownProtocol )
708 return d->presetProtocol;
709 if ( d->ui.pgpRB.isChecked() )
711 if ( d->ui.cmsRB.isChecked() )
713 return UnknownProtocol;
717 setWindowTitle( i18n(
"Select Certificates For Message \"%1\"", subject ) );
721 if ( sign == d->sign )
724 d->updateTopLabelText();
725 d->showHideWidgets();
726 d->enableDisableOkButton();
730 if ( encrypt == d->encrypt )
732 d->encrypt = encrypt;
733 d->updateTopLabelText();
734 d->showHideWidgets();
735 d->enableDisableOkButton();
739 if ( senders == d->senders )
741 d->senders = senders;
742 d->createSendersAndRecipients();
743 d->showHideWidgets();
744 d->enableDisableOkButton();
748 if ( d->recipients == recipients )
750 d->recipients = recipients;
751 d->createSendersAndRecipients();
752 d->showHideWidgets();
753 d->enableDisableOkButton();
761 const bool pgp = d->isComplete(
OpenPGP );
762 const bool cms = d->isComplete(
CMS );
765 d->ui.pgpRB.setChecked(
true );
766 else if ( cms && !pgp )
767 d->ui.cmsRB.setChecked(
true );
772 return proto != UnknownProtocol && d->isComplete( proto ) ;
775 bool SignEncryptEMailConflictDialog::Private::isComplete( Protocol proto )
const {
776 return ( !sign || kdtools::none_of( ui.signers, boost::bind( &Line::isStillAmbiguous, _1, proto ) ) )
777 && ( !encrypt || kdtools::none_of( ui.recipients, boost::bind( &Line::isStillAmbiguous, _1, proto ) ) )
781 static std::vector<Key>
get_keys(
const std::vector<Line> & lines, Protocol proto ) {
782 if ( proto == UnknownProtocol )
783 return std::vector<Key>();
786 std::vector<Key> keys;
787 keys.reserve( lines.size() );
788 kdtools::transform( lines, std::back_inserter( keys ),
789 boost::bind( &Line::key, _1, proto ) );
790 kleo_assert( kdtools::none_of( keys, mem_fn( &Key::isNull ) ) );
803 d->ui.quickModeCB.setChecked( on );
807 return d->ui.quickModeCB.isChecked();
811 d->ui.conflictTopLB.setVisible( conflict );
812 d->ui.quickModeTopLB.setVisible( !conflict );
815 #include "moc_signencryptemailconflictdialog.cpp"
816 #include "signencryptemailconflictdialog.moc"
void setOptions(Options options)
void setConflict(bool conflict)
void setSenders(const std::vector< Sender > &senders)
static QString make_top_label_conflict_text(bool sign, bool enc)
void setSubject(const QString &subject)
void setCustomLabelText(const QString &text)
void setEnabled(bool enable)
static CertificateSelectionDialog * create_encryption_certificate_selection_dialog(QWidget *parent, Protocol proto, const QString &mailbox)
void setPresetProtocol(GpgME::Protocol proto)
std::vector< GpgME::Key > resolvedEncryptionKeys() const
static CertificateSelectionDialog * create_signing_certificate_selection_dialog(QWidget *parent, Protocol proto, const QString &mailbox)
const KMime::Types::Mailbox & mailbox() const
void setRecipients(const std::vector< Recipient > &recipients)
void setBold(bool enable)
const std::vector< GpgME::Key > & encryptionCertificateCandidates(GpgME::Protocol proto) const
const KMime::Types::Mailbox & mailbox() const
const std::vector< GpgME::Key > & encryptToSelfCertificateCandidates(GpgME::Protocol proto) const
static std::vector< Key > get_keys(const std::vector< Line > &lines, Protocol proto)
void setQuickMode(bool on)
bool isEncryptionAmbiguous(GpgME::Protocol proto) const
GpgME::Protocol selectedProtocol() const
#define kleo_assert_fail(cond)
static CertificateSelectionDialog * create_certificate_selection_dialog(QWidget *parent, Protocol proto)
#define kleo_assert(cond)
SignEncryptEMailConflictDialog(QWidget *parent=0, Qt::WindowFlags f=0)
void setColumnStretch(int column, int stretch)
~SignEncryptEMailConflictDialog()
static void update(const QString &fname, const QString &id)
static QString make_top_label_quickmode_text(bool sign, bool enc)
std::vector< GpgME::Key > resolvedSigningKeys() const
bool isEncryptionAmbiguous(GpgME::Protocol protocol) const
Exception-safe and convenient wrapper around QObject::blockSignals()
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
static void really_check(QAbstractButton &b, bool on)