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)