• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KIO

cacertificatespage.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE project
00002     Copyright (C) 2010 Andreas Hartmetz <ahartmetz@gmail.com>
00003 
00004     This library is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU Library General Public
00006     License as published by the Free Software Foundation; either
00007     version 2 of the License, or (at your option) any later version.
00008 
00009     This program is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program; if not, write to the Free Software
00016     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017     02110-1301, USA.
00018 */
00019 
00020 #include "cacertificatespage.h"
00021 #include "displaycertdialog_p.h"
00022 
00023 #include <ksslcertificatemanager.h>
00024 #include <ksslcertificatemanager_p.h>
00025 
00026 #include <kdebug.h>
00027 #include <kfiledialog.h>
00028 
00029 #include <QList>
00030 #include <QSslCertificate>
00031 #include <QtGui/QTreeWidgetItem>
00032 #include <QtGui/QStandardItemModel>
00033 
00034 enum Columns {
00035     OrgCnColumn = 0,
00036     OrgUnitColumn,
00037     HiddenSortColumn
00038 };
00039 
00040 
00041 static QString nonemptyIssuer(const QSslCertificate &cert)
00042 {
00043     QString issuerText;
00044     static const QSslCertificate::SubjectInfo fields[3] = {
00045                      QSslCertificate::Organization,
00046                      QSslCertificate::CommonName,
00047                      QSslCertificate::OrganizationalUnitName
00048     };
00049     for (int i = 0; i < 3; i++) {
00050         issuerText = cert.issuerInfo(fields[i]);
00051         if (!issuerText.isEmpty()) {
00052             return issuerText;
00053         }
00054     }
00055     return issuerText;
00056 }
00057 
00058 
00059 class CaCertificateItem : public QTreeWidgetItem
00060 {
00061 public:
00062     CaCertificateItem(QTreeWidgetItem *parent, const QSslCertificate &cert, bool isEnabled)
00063      : QTreeWidgetItem(parent, m_type),
00064        m_cert(cert)
00065     {
00066        setEnabled(isEnabled);
00067     }
00068 
00069     QVariant data(int column, int role) const
00070     {
00071         switch (role) {
00072         case Qt::DisplayRole:
00073             switch (column) {
00074             case OrgCnColumn:
00075             case HiddenSortColumn: {
00076                 QString subjectText = m_cert.issuerInfo(QSslCertificate::CommonName);
00077                 if (column == HiddenSortColumn) {
00078                     return subjectText.toLower();
00079                 }
00080                 return subjectText; }
00081             case OrgUnitColumn:
00082                 return m_cert.issuerInfo(QSslCertificate::OrganizationalUnitName);
00083             }
00084         }
00085 
00086         return QTreeWidgetItem::data(column, role);
00087     }
00088 
00089     bool isEnabled() const
00090     {
00091         return data(OrgCnColumn, Qt::CheckStateRole).toInt() == Qt::Checked;
00092     }
00093 
00094     void setEnabled(bool enabled)
00095     {
00096         setData(OrgCnColumn, Qt::CheckStateRole, enabled ? Qt::Checked : Qt::Unchecked);
00097     }
00098 
00099     static const int m_type = QTreeWidgetItem::UserType;
00100     QSslCertificate m_cert;
00101 };
00102 
00103 CaCertificatesPage::CaCertificatesPage(QWidget *parent)
00104  : m_firstShowEvent(true),
00105    m_blockItemChanged(false)
00106 {
00107     m_ui.setupUi(this);
00108     connect(m_ui.displaySelection, SIGNAL(clicked()), SLOT(displaySelectionClicked()));
00109     connect(m_ui.disableSelection, SIGNAL(clicked()), SLOT(disableSelectionClicked()));
00110     connect(m_ui.enableSelection, SIGNAL(clicked()), SLOT(enableSelectionClicked()));
00111     connect(m_ui.removeSelection, SIGNAL(clicked()), SLOT(removeSelectionClicked()));
00112     connect(m_ui.add, SIGNAL(clicked()), SLOT(addCertificateClicked()));
00113     connect(m_ui.treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)),
00114             SLOT(itemChanged(QTreeWidgetItem *, int)));
00115     connect(m_ui.treeWidget, SIGNAL(itemSelectionChanged()),
00116             SLOT(itemSelectionChanged()));
00117 
00118     m_ui.treeWidget->setColumnCount(HiddenSortColumn + 1);
00119     m_ui.treeWidget->setColumnHidden(HiddenSortColumn, true);
00120 }
00121 
00122 
00123 void CaCertificatesPage::load()
00124 {
00125     m_ui.treeWidget->clear();
00126     m_ui.treeWidget->sortByColumn(-1);  // disable during mass insertion
00127     m_knownCertificates.clear();
00128 
00129     m_systemCertificatesParent = new QTreeWidgetItem(m_ui.treeWidget);
00130     m_systemCertificatesParent->setText(0, i18n("System certificates"));
00131     // make system certificates come first in the sorted view
00132     m_systemCertificatesParent->setText(HiddenSortColumn, QLatin1String("a"));
00133     m_systemCertificatesParent->setExpanded(true);
00134     m_systemCertificatesParent->setFlags(m_systemCertificatesParent->flags() & ~Qt::ItemIsSelectable);
00135 
00136     m_userCertificatesParent = new QTreeWidgetItem(m_ui.treeWidget);
00137     m_userCertificatesParent->setText(0, i18n("User-added certificates"));
00138     m_userCertificatesParent->setText(HiddenSortColumn, QLatin1String("b"));
00139     m_userCertificatesParent->setExpanded(true);
00140     m_userCertificatesParent->setFlags(m_userCertificatesParent->flags() & ~Qt::ItemIsSelectable);
00141 
00142     QList<KSslCaCertificate> caCerts = _allKsslCaCertificates(KSslCertificateManager::self());
00143     kDebug(7029) << "# certs:" << caCerts.count();
00144     foreach (const KSslCaCertificate &caCert, caCerts) {
00145         addCertificateItem(caCert);
00146     }
00147 
00148     m_ui.treeWidget->sortByColumn(HiddenSortColumn, Qt::AscendingOrder);
00149 }
00150 
00151 void CaCertificatesPage::showEvent(QShowEvent *event)
00152 {
00153     if (m_firstShowEvent) {
00154         // TODO use QTextMetrics
00155         m_ui.treeWidget->setColumnWidth(OrgCnColumn, 420);
00156         m_firstShowEvent = false;
00157     }
00158     QWidget::showEvent(event);
00159 }
00160 
00161 void CaCertificatesPage::save()
00162 {
00163     QList<KSslCaCertificate> newState;
00164 
00165     KSslCaCertificate::Store store = KSslCaCertificate::SystemStore;
00166     QTreeWidgetItem *grandParent = m_systemCertificatesParent;
00167 
00168     for (int i = 0; i < 2; i++) {
00169         for (int j = 0; j < grandParent->childCount(); j++) {
00170 
00171             QTreeWidgetItem *parentItem = grandParent->child(j);
00172             for (int k = 0; k < parentItem->childCount(); k++) {
00173                 CaCertificateItem *item = static_cast<CaCertificateItem *>(parentItem->child(k));
00174                 newState += KSslCaCertificate(item->m_cert, store, !item->isEnabled());
00175             }
00176         }
00177         store = KSslCaCertificate::UserStore;
00178         grandParent = m_userCertificatesParent;
00179     }
00180 
00181     kDebug(7029) << "# certs:" << newState.count();
00182     _setAllKsslCaCertificates(KSslCertificateManager::self(), newState);
00183     emit changed(false);
00184 }
00185 
00186 
00187 void CaCertificatesPage::defaults()
00188 {
00189     //### is that all?
00190     load();
00191     emit changed(false);
00192 }
00193 
00194 // private slot
00195 void CaCertificatesPage::itemSelectionChanged()
00196 {
00197     kDebug(7029) << m_ui.treeWidget->selectionModel()->hasSelection();
00198     int numRemovable = 0;
00199     int numEnabled = 0;
00200     int numDisplayable = 0;
00201     foreach(const QTreeWidgetItem *twItem, m_ui.treeWidget->selectedItems()) {
00202         const CaCertificateItem *item = dynamic_cast<const CaCertificateItem *>(twItem);
00203         Q_ASSERT(item);
00204         if (item) {
00205             numDisplayable++;
00206             if (item->parent()->parent() == m_userCertificatesParent) {
00207                 numRemovable++;
00208             }
00209             if (item->isEnabled()) {
00210                 numEnabled++;
00211             }
00212         }
00213     }
00214     m_ui.displaySelection->setEnabled(numDisplayable);
00215     m_ui.removeSelection->setEnabled(numRemovable);
00216     m_ui.disableSelection->setEnabled(numEnabled);
00217     m_ui.enableSelection->setEnabled(numDisplayable > numEnabled); // the rest is disabled
00218 }
00219 
00220 // private slot
00221 void CaCertificatesPage::displaySelectionClicked()
00222 {
00223     QList<QSslCertificate> certs;
00224     foreach(const QTreeWidgetItem *twItem, m_ui.treeWidget->selectedItems()) {
00225         const CaCertificateItem *item = dynamic_cast<const CaCertificateItem *>(twItem);
00226         Q_ASSERT(item);
00227         if (item) {
00228             certs += item->m_cert;
00229         }
00230     }
00231     DisplayCertDialog dc(this);
00232     dc.setCertificates(certs);
00233     dc.exec();
00234 }
00235 
00236 // private slot
00237 void CaCertificatesPage::disableSelectionClicked()
00238 {
00239     enableDisableSelectionClicked(false);
00240 }
00241 
00242 // private slot
00243 void CaCertificatesPage::enableSelectionClicked()
00244 {
00245     enableDisableSelectionClicked(true);
00246 }
00247 
00248 void CaCertificatesPage::enableDisableSelectionClicked(bool isEnable)
00249 {
00250     const bool prevBlockItemChanged = m_blockItemChanged;
00251     m_blockItemChanged = true;
00252     foreach(QTreeWidgetItem *twItem, m_ui.treeWidget->selectedItems()) {
00253         CaCertificateItem *item = dynamic_cast<CaCertificateItem *>(twItem);
00254         Q_ASSERT(item);
00255         if (item) {
00256             item->setEnabled(isEnable);
00257         }
00258     }
00259     emit changed(true);
00260     m_blockItemChanged = prevBlockItemChanged;
00261     // now make sure that the buttons are enabled as appropriate
00262     itemSelectionChanged();
00263 }
00264 
00265 
00266 // private slot
00267 void CaCertificatesPage::removeSelectionClicked()
00268 {
00269     bool didRemove = false;
00270     foreach(QTreeWidgetItem *twItem, m_ui.treeWidget->selectedItems()) {
00271         const CaCertificateItem *item = dynamic_cast<const CaCertificateItem *>(twItem);
00272         Q_ASSERT(item);
00273         if (!item || item->parent()->parent() != m_userCertificatesParent) {
00274             continue;
00275         }
00276         QTreeWidgetItem *parent = item->parent();
00277         m_knownCertificates.remove(item->m_cert.digest().toHex());
00278         delete item;
00279         didRemove = true;
00280         if (parent->childCount() == 0) {
00281             delete parent;
00282         }
00283     }
00284     if (didRemove) {
00285         emit changed(true);
00286     }
00287 }
00288 
00289 // private slot
00290 void CaCertificatesPage::addCertificateClicked()
00291 {
00292     QStringList certFiles
00293       = KFileDialog::getOpenFileNames(KUrl(), QLatin1String("application/x-x509-ca-cert"),
00294                                       this, i18n("Pick Certificates"));
00295 
00296     QList<QSslCertificate> certs;
00297     foreach (const QString &certFile, certFiles) {
00298         // trying both formats is easiest to program and most user-friendly if somewhat sloppy
00299         const int prevCertCount = certs.count();
00300         certs += QSslCertificate::fromPath(certFile, QSsl::Pem);
00301         if (prevCertCount == certs.count()) {
00302             certs += QSslCertificate::fromPath(certFile, QSsl::Der);
00303         }
00304         if (prevCertCount == certs.count()) {
00305             kDebug(7029) << "failed to load certificate file" << certFile;
00306         }
00307     }
00308 
00309     bool didAddCertificates = false;
00310     foreach (const QSslCertificate &cert, certs) {
00311         KSslCaCertificate caCert(cert, KSslCaCertificate::UserStore, false);
00312         if (!addCertificateItem(caCert)) {
00313             // ### tell the user?
00314         } else {
00315             didAddCertificates = true;
00316         }
00317     }
00318     if (didAddCertificates) {
00319         emit changed(true);
00320     }
00321 }
00322 
00323 // private slot
00324 void CaCertificatesPage::itemChanged(QTreeWidgetItem *item, int column)
00325 {
00326     if (m_blockItemChanged) {
00327         return;
00328     }
00329     kDebug(7029);
00330     // we could try to emit changed(false) if everything was changed back to status quo
00331 
00332     // a click on the checkbox of an unselected item first invokes itemSelectionChanged(),
00333     // then itemChanged(). we'll have to rerun the checks in itemSelectionChanged().
00334     itemSelectionChanged();
00335     emit changed(true);
00336 }
00337 
00338 static QTreeWidgetItem *findImmediateChild(QTreeWidgetItem *parent, const QString &issuerText)
00339 {
00340     for (int i = 0; i < parent->childCount(); i ++) {
00341         QTreeWidgetItem *candidate = parent->child(i);
00342         if (candidate->text(OrgCnColumn) == issuerText) {
00343             return candidate;
00344         }
00345     }
00346     return 0;
00347 }
00348 
00349 bool CaCertificatesPage::addCertificateItem(const KSslCaCertificate &caCert)
00350 {
00351     if (m_knownCertificates.contains(caCert.certHash)) {
00352         kDebug(7029) << "CaCertificatesPage::addCertificateItem(): refusing duplicate";
00353         return false;
00354     }
00355     const bool prevBlockItemChanged = m_blockItemChanged;
00356     m_blockItemChanged = true;
00357     QTreeWidgetItem *grandParent = caCert.store == KSslCaCertificate::SystemStore ?
00358                                             m_systemCertificatesParent : m_userCertificatesParent;
00359     const QString issuerOrganization = nonemptyIssuer(caCert.cert);
00360 
00361     QTreeWidgetItem *parent = findImmediateChild(grandParent, issuerOrganization);
00362     if (!parent) {
00363         parent = new QTreeWidgetItem(grandParent);
00364         parent->setText(OrgCnColumn, issuerOrganization);
00365         parent->setText(HiddenSortColumn, issuerOrganization.toLower());
00366         parent->setExpanded(true);
00367         parent->setFlags(parent->flags() & ~Qt::ItemIsSelectable);
00368     }
00369 
00370     CaCertificateItem *it = new CaCertificateItem(parent, caCert.cert, !caCert.isBlacklisted);
00371     m_knownCertificates.insert(caCert.certHash);
00372     m_blockItemChanged = prevBlockItemChanged;
00373     return true;
00374 }
00375 
00376 #include "cacertificatespage.moc"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal