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>
71 #include <boost/shared_ptr.hpp>
72 #include <boost/bind.hpp>
77 using namespace Kleo::Crypto;
78 using namespace Kleo::Crypto::Gui;
79 using namespace Kleo::Dialogs;
80 using namespace GpgME;
81 using namespace boost;
83 Q_DECLARE_METATYPE( GpgME::Key )
84 Q_DECLARE_METATYPE( GpgME::UserID )
93 class ComboBox :
public QComboBox {
95 Q_PROPERTY( QString initialText READ initialText WRITE setInitialText )
96 Q_PROPERTY( QIcon initialIcon READ initialIcon WRITE setInitialIcon )
98 explicit ComboBox(
QWidget * parent=0 )
99 : QComboBox( parent ),
106 explicit ComboBox(
const QString & initialText,
QWidget * parent=0 )
107 : QComboBox( parent ),
108 m_initialText( initialText ),
114 explicit ComboBox(
const QIcon & initialIcon,
const QString & initialText,
QWidget * parent=0 )
115 : QComboBox( parent ),
116 m_initialText( initialText ),
117 m_initialIcon( initialIcon )
122 QString initialText()
const {
return m_initialText; }
123 QIcon initialIcon()
const {
return m_initialIcon; }
126 void setInitialText(
const QString & txt ) {
127 if ( txt == m_initialText )
130 if ( currentIndex() == -1 )
133 void setInitialIcon(
const QIcon & icon ) {
134 if ( icon.cacheKey() == m_initialIcon.cacheKey() )
136 m_initialIcon = icon;
137 if ( currentIndex() == -1 )
142 void paintEvent( QPaintEvent * ) {
143 QStylePainter p(
this );
144 p.setPen( palette().color( QPalette::Text ) );
145 QStyleOptionComboBox opt;
146 initStyleOption( &opt );
147 p.drawComplexControl( QStyle::CC_ComboBox, opt );
149 if ( currentIndex() == -1 ) {
150 opt.currentText = m_initialText;
151 opt.currentIcon = m_initialIcon;
153 p.drawControl( QStyle::CE_ComboBoxLabel, opt );
157 QString m_initialText;
161 static QString make_initial_text(
const std::vector<Key> & keys ) {
163 return i18n(
"(no matching certificates found)");
165 return i18n(
"Please select a certificate");
168 class KeysComboBox :
public ComboBox {
171 explicit KeysComboBox(
QWidget * parent=0 )
172 : ComboBox( parent ) {}
173 explicit KeysComboBox(
const QString & initialText,
QWidget * parent=0 )
174 : ComboBox( initialText, parent ) {}
175 explicit KeysComboBox(
const std::vector<Key> & keys,
QWidget * parent=0 )
176 : ComboBox( make_initial_text( keys ), parent ) { setKeys( keys ); }
178 void setKeys(
const std::vector<Key> & keys ) {
180 Q_FOREACH(
const Key & key, keys )
184 std::vector<Key> keys()
const {
185 std::vector<Key> result;
186 result.reserve( count() );
187 for (
int i = 0, end = count() ; i != end ; ++i )
188 result.push_back( qvariant_cast<Key>( itemData(i) ) );
192 int findOrAdd(
const Key & key ) {
193 for (
int i = 0, end = count() ; i != end ; ++i )
194 if ( _detail::ByFingerprint<std::equal_to>()( key, qvariant_cast<Key>( itemData(i) ) ) )
200 void addAndSelectCertificate(
const Key & key ) {
201 setCurrentIndex( findOrAdd( key ) );
204 Key currentKey()
const {
205 return qvariant_cast<Key>( itemData( currentIndex() ) );
212 static const unsigned int NumColumns = 4;
214 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 )
215 : pgpAmbiguous( pgpAmbig ),
216 cmsAmbiguous( cmsAmbig ),
217 toFromLB( new QLabel( toFrom, q ) ),
218 mailboxLB( new QLabel( mailbox, q ) ),
219 sbox( new QStackedWidget( q ) ),
220 pgpCB( new KeysComboBox( pgp, sbox ) ),
221 cmsCB( new KeysComboBox( cms, sbox ) ),
222 noProtocolCB( new KeysComboBox( i18n(
"(please choose between OpenPGP and S/MIME first)"), sbox ) ),
223 toolTB( new QToolButton( q ) )
234 bold.setBold(
true );
235 toFromLB->setFont( bold );
237 mailboxLB->setTextFormat( Qt::PlainText );
238 toolTB->setText( i18n(
"...") );
240 pgpCB->setEnabled( !pgp.empty() );
241 cmsCB->setEnabled( !cms.empty() );
242 noProtocolCB->setEnabled(
false );
244 pgpCB->setKeys( pgp );
246 pgpCB->setCurrentIndex( -1 );
248 cmsCB->setKeys( cms );
250 cmsCB->setCurrentIndex( -1 );
252 sbox->addWidget( pgpCB );
253 sbox->addWidget( cmsCB );
254 sbox->addWidget( noProtocolCB );
255 sbox->setCurrentWidget( noProtocolCB );
257 const int row = glay.rowCount();
258 unsigned int col = 0;
259 glay.addWidget( toFromLB, row, col++ );
260 glay.addWidget( mailboxLB, row, col++ );
261 glay.addWidget( sbox, row, col++ );
262 glay.addWidget( toolTB, row, col++ );
263 assert( col == NumColumns );
265 q->connect( pgpCB, SIGNAL(currentIndexChanged(
int)), SLOT(slotCompleteChanged()) );
266 q->connect( cmsCB, SIGNAL(currentIndexChanged(
int)), SLOT(slotCompleteChanged()) );
267 q->connect( toolTB, SIGNAL(clicked()), SLOT(slotCertificateSelectionDialogRequested()) );
270 KeysComboBox * comboBox( Protocol proto )
const {
278 QString mailboxText()
const {
279 return mailboxLB->text();
282 void addAndSelectCertificate(
const Key & key )
const {
283 if ( KeysComboBox *
const cb = comboBox( key.protocol() ) ) {
284 cb->addAndSelectCertificate( key );
285 cb->setEnabled(
true );
289 void showHide( Protocol proto,
bool & first,
bool showAll,
bool op )
const {
290 if ( op && ( showAll || wasInitiallyAmbiguous( proto ) ) ) {
292 toFromLB->setVisible( first );
295 QFont font = mailboxLB->font();
296 font.setBold( wasInitiallyAmbiguous( proto ) );
297 mailboxLB->setFont( font );
299 sbox->setCurrentIndex( proto );
313 bool wasInitiallyAmbiguous( Protocol proto )
const {
314 return proto ==
OpenPGP && pgpAmbiguous
315 || proto ==
CMS && cmsAmbiguous ;
318 bool isStillAmbiguous( Protocol proto )
const {
320 const KeysComboBox *
const cb = comboBox( proto );
321 return cb->currentIndex() == -1 ;
324 Key key( Protocol proto )
const {
326 const KeysComboBox *
const cb = comboBox( proto );
327 return cb->currentKey();
330 const QToolButton * toolButton()
const {
return toolTB; }
340 bool pgpAmbiguous : 1;
341 bool cmsAmbiguous : 1;
345 QStackedWidget * sbox;
346 KeysComboBox * pgpCB;
347 KeysComboBox * cmsCB;
348 KeysComboBox * noProtocolCB;
349 QToolButton * toolTB;
366 dlg->
setCustomLabelText( i18n(
"Please select an encryption certificate for recipient \"%1\"", mailbox ) );
367 dlg->
setOptions( CertificateSelectionDialog::SingleSelection |
368 CertificateSelectionDialog::EncryptOnly |
376 dlg->
setCustomLabelText( i18n(
"Please select a signing certificate for sender \"%1\"", mailbox ) );
377 dlg->
setOptions( CertificateSelectionDialog::SingleSelection |
378 CertificateSelectionDialog::SignOnly |
379 CertificateSelectionDialog::SecretKeys |
386 sign && enc ? i18n(
"Kleopatra cannot unambiguously determine matching certificates "
387 "for all recipients/senders of the message.\n"
388 "Please select the correct certificates for each recipient:") :
389 sign ? i18n(
"Kleopatra cannot unambiguously determine matching certificates "
390 "for the sender of the message.\n"
391 "Please select the correct certificates for the sender:") :
392 enc ? i18n(
"Kleopatra cannot unambiguously determine matching certificates "
393 "for all recipients of the message.\n"
394 "Please select the correct certificates for each recipient:" ) :
400 enc ? i18n(
"Please verify that correct certificates have been selected for each recipient:") :
401 sign ? i18n(
"Please verify that the correct certificate has been selected for the sender:") :
405 class SignEncryptEMailConflictDialog::Private {
406 friend class ::Kleo::Crypto::Gui::SignEncryptEMailConflictDialog;
415 presetProtocol( UnknownProtocol ),
422 void updateTopLabelText() {
427 void showHideWidgets() {
428 const Protocol proto = q->selectedProtocol();
429 const bool quickMode = q->isQuickMode();
431 const bool needProtocolSelection = presetProtocol == UnknownProtocol ;
433 const bool needShowAllRecipientsCB =
435 needProtocolSelection ? needShowAllRecipients(
OpenPGP ) || needShowAllRecipients(
CMS ) :
436 needShowAllRecipients( proto )
439 ui.showAllRecipientsCB.setVisible( needShowAllRecipientsCB );
441 ui.pgpRB.setVisible( needProtocolSelection );
442 ui.cmsRB.setVisible( needProtocolSelection );
444 const bool showAll = !needShowAllRecipientsCB || ui.showAllRecipientsCB.isChecked();
448 Q_FOREACH(
const Line & line, ui.signers )
449 line.showHide( proto, first, showAll, sign );
450 ui.selectSigningCertificatesGB.setVisible( sign && ( showAll || !first ) );
453 Q_FOREACH( const Line & line, ui.recipients )
454 line.showHide( proto, first, showAll, encrypt );
455 ui.selectEncryptionCertificatesGB.setVisible( encrypt && ( showAll || !first ) );
458 bool needShowAllRecipients( Protocol proto )
const {
460 if (
const unsigned int num = kdtools::count_if( ui.signers, boost::bind( &Line::wasInitiallyAmbiguous, _1, proto ) ) )
461 if ( num != ui.signers.size() )
464 if (
const unsigned int num = kdtools::count_if( ui.recipients, boost::bind( &Line::wasInitiallyAmbiguous, _1, proto ) ) )
465 if ( num != ui.recipients.size() )
470 void createSendersAndRecipients() {
471 ui.clearSendersAndRecipients();
473 ui.addSelectSigningCertificatesGB();
474 Q_FOREACH(
const Sender & s, senders )
477 ui.addSelectEncryptionCertificatesGB();
478 Q_FOREACH( const
Sender & s, senders )
480 Q_FOREACH( const
Recipient & r, recipients )
484 void addSigner( const
Sender & s ) {
485 ui.addSigner( s.mailbox().prettyAddress(),
486 s.signingCertificateCandidates(
OpenPGP ),
487 s.isSigningAmbiguous(
OpenPGP ),
488 s.signingCertificateCandidates(
CMS ),
489 s.isSigningAmbiguous(
CMS ),
493 void addRecipient(
const Sender & s ) {
494 ui.addRecipient( s.
mailbox().prettyAddress(),
502 void addRecipient(
const Recipient & r ) {
503 ui.addRecipient( r.
mailbox().prettyAddress(),
511 bool isComplete( Protocol proto )
const;
514 void enableDisableOkButton() {
515 ui.setOkButtonEnabled( q->isComplete() );
517 void slotCompleteChanged() {
518 enableDisableOkButton();
520 void slotShowAllRecipientsToggled(
bool ) {
523 void slotProtocolChanged() {
525 enableDisableOkButton();
527 void slotCertificateSelectionDialogRequested() {
528 const QObject *
const s = q->sender();
529 const Protocol proto = q->selectedProtocol();
530 QPointer<CertificateSelectionDialog> dlg;
531 Q_FOREACH(
const Line & l, ui.signers )
532 if ( s == l.toolButton() ) {
535 l.addAndSelectCertificate( dlg->selectedCertificate() );
539 Q_FOREACH(
const Line & l, ui.recipients )
540 if ( s == l.toolButton() ) {
543 l.addAndSelectCertificate( dlg->selectedCertificate() );
551 std::vector<Sender> senders;
552 std::vector<Recipient> recipients;
556 Protocol presetProtocol;
560 QLabel conflictTopLB, quickModeTopLB;
561 QCheckBox showAllRecipientsCB;
562 QRadioButton pgpRB, cmsRB;
563 QGroupBox selectSigningCertificatesGB;
564 QGroupBox selectEncryptionCertificatesGB;
565 QCheckBox quickModeCB;
566 QDialogButtonBox buttonBox;
570 std::vector<Line> signers, recipients;
572 void setOkButtonEnabled(
bool enable ) {
579 showAllRecipientsCB( i18n(
"Show all recipients"), q ),
580 pgpRB( i18n(
"OpenPGP"), q ),
581 cmsRB( i18n(
"S/MIME"), q ),
582 selectSigningCertificatesGB( i18n(
"Select Signing Certificate"), q ),
583 selectEncryptionCertificatesGB( i18n(
"Select Encryption Certificate"), q ),
584 quickModeCB( i18n(
"Only show this dialog in case of conflicts (experimental)"), q ),
585 buttonBox( QDialogButtonBox::
Ok|QDialogButtonBox::Cancel, Qt::Horizontal, q ),
605 q->setWindowTitle( i18n(
"Select Certificates For Message") );
607 conflictTopLB.hide();
609 selectSigningCertificatesGB.setFlat(
true );
610 selectEncryptionCertificatesGB.setFlat(
true );
611 selectSigningCertificatesGB.setAlignment( Qt::AlignCenter );
612 selectEncryptionCertificatesGB.setAlignment( Qt::AlignCenter );
614 glay.setColumnStretch( 2, 1 );
615 glay.setColumnStretch( 3, 1 );
617 vlay.setSizeConstraint( QLayout::SetMinimumSize );
619 vlay.addWidget( &conflictTopLB );
620 vlay.addWidget( &quickModeTopLB );
622 hlay.addWidget( &showAllRecipientsCB );
623 hlay.addStretch( 1 );
624 hlay.addWidget( &pgpRB );
625 hlay.addWidget( &cmsRB );
626 vlay.addLayout( &hlay );
628 addSelectSigningCertificatesGB();
629 addSelectEncryptionCertificatesGB();
630 vlay.addLayout( &glay );
632 vlay.addStretch( 1 );
634 vlay.addWidget( &quickModeCB, 0, Qt::AlignCenter );
635 vlay.addWidget( &buttonBox );
637 connect( &buttonBox, SIGNAL(accepted()), q, SLOT(accept()) );
638 connect( &buttonBox, SIGNAL(rejected()), q, SLOT(reject()) );
640 connect( &showAllRecipientsCB, SIGNAL(toggled(
bool)),
641 q, SLOT(slotShowAllRecipientsToggled(
bool)) );
642 connect( &pgpRB, SIGNAL(toggled(
bool)),
643 q, SLOT(slotProtocolChanged()) );
644 connect( &cmsRB, SIGNAL(toggled(
bool)),
645 q, SLOT(slotProtocolChanged()) );
648 void clearSendersAndRecipients() {
649 std::vector<Line> sig, enc;
651 enc.swap( recipients );
652 kdtools::for_each( sig, mem_fn( &Line::kill ) );
653 kdtools::for_each( enc, mem_fn( &Line::kill ) );
654 glay.removeWidget( &selectSigningCertificatesGB );
655 glay.removeWidget( &selectEncryptionCertificatesGB );
658 void addSelectSigningCertificatesGB() {
659 glay.addWidget( &selectSigningCertificatesGB, glay.rowCount(), 0, 1, Line::NumColumns );
661 void addSelectEncryptionCertificatesGB() {
662 glay.addWidget( &selectEncryptionCertificatesGB, glay.rowCount(), 0, 1, Line::NumColumns );
665 void addSigner(
const QString & mailbox,
666 const std::vector<Key> & pgp,
bool pgpAmbiguous,
667 const std::vector<Key> & cms,
bool cmsAmbiguous,
QWidget * q )
669 Line line( i18n(
"From:"), mailbox, pgp, pgpAmbiguous, cms, cmsAmbiguous, q, glay );
670 signers.push_back( line );
673 void addRecipient(
const QString & mailbox,
674 const std::vector<Key> & pgp,
bool pgpAmbiguous,
675 const std::vector<Key> & cms,
bool cmsAmbiguous,
QWidget * q )
677 Line line( i18n(
"To:"), mailbox, pgp, pgpAmbiguous, cms, cmsAmbiguous, q, glay );
678 recipients.push_back( line );
685 :
QDialog( parent, f ),
d( new Private( this ) )
693 if ( p == d->presetProtocol )
699 d->presetProtocol = p;
700 d->showHideWidgets();
701 d->enableDisableOkButton();
705 if ( d->presetProtocol != UnknownProtocol )
706 return d->presetProtocol;
707 if ( d->ui.pgpRB.isChecked() )
709 if ( d->ui.cmsRB.isChecked() )
711 return UnknownProtocol;
715 setWindowTitle( i18n(
"Select Certificates For Message \"%1\"", subject ) );
719 if ( sign == d->sign )
722 d->updateTopLabelText();
723 d->showHideWidgets();
724 d->enableDisableOkButton();
728 if ( encrypt == d->encrypt )
730 d->encrypt = encrypt;
731 d->updateTopLabelText();
732 d->showHideWidgets();
733 d->enableDisableOkButton();
737 if ( senders == d->senders )
739 d->senders = senders;
740 d->createSendersAndRecipients();
741 d->showHideWidgets();
742 d->enableDisableOkButton();
746 if ( d->recipients == recipients )
748 d->recipients = recipients;
749 d->createSendersAndRecipients();
750 d->showHideWidgets();
751 d->enableDisableOkButton();
759 const bool pgp = d->isComplete(
OpenPGP );
760 const bool cms = d->isComplete(
CMS );
763 d->ui.pgpRB.setChecked(
true );
764 else if ( cms && !pgp )
765 d->ui.cmsRB.setChecked(
true );
770 return proto != UnknownProtocol && d->isComplete( proto ) ;
773 bool SignEncryptEMailConflictDialog::Private::isComplete( Protocol proto )
const {
774 return ( !sign || kdtools::none_of( ui.signers, boost::bind( &Line::isStillAmbiguous, _1, proto ) ) )
775 && ( !encrypt || kdtools::none_of( ui.recipients, boost::bind( &Line::isStillAmbiguous, _1, proto ) ) )
779 static std::vector<Key>
get_keys(
const std::vector<Line> & lines, Protocol proto ) {
780 if ( proto == UnknownProtocol )
781 return std::vector<Key>();
784 std::vector<Key> keys;
785 keys.reserve( lines.size() );
786 kdtools::transform( lines, std::back_inserter( keys ),
787 boost::bind( &Line::key, _1, proto ) );
788 kleo_assert( kdtools::none_of( keys, mem_fn( &Key::isNull ) ) );
801 d->ui.quickModeCB.setChecked( on );
805 return d->ui.quickModeCB.isChecked();
809 d->ui.conflictTopLB.setVisible( conflict );
810 d->ui.quickModeTopLB.setVisible( !conflict );
813 #include "moc_signencryptemailconflictdialog.cpp"
814 #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)
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)
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)
~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()
static void really_check(QAbstractButton &b, bool on)