File indexing completed on 2024-05-12 04:44:57

0001 /*
0002  Copyright (C) 2007 Justin Karneges <justin@affinix.com>
0003 
0004  Permission is hereby granted, free of charge, to any person obtaining a copy
0005  of this software and associated documentation files (the "Software"), to deal
0006  in the Software without restriction, including without limitation the rights
0007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0008  copies of the Software, and to permit persons to whom the Software is
0009  furnished to do so, subject to the following conditions:
0010 
0011  The above copyright notice and this permission notice shall be included in
0012  all copies or substantial portions of the Software.
0013 
0014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
0017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
0018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0020 */
0021 
0022 #include "pkcs11configdlg.h"
0023 
0024 #include "ui_pkcs11config.h"
0025 #include <QFileDialog>
0026 #include <QMessageBox>
0027 #include <QtCore>
0028 #include <QtCrypto>
0029 #include <QtGui>
0030 
0031 //----------------------------------------------------------------------------
0032 // Pkcs11ProviderConfig
0033 //----------------------------------------------------------------------------
0034 class Pkcs11ProviderConfig
0035 {
0036 public:
0037     bool    allow_protected_authentication;
0038     bool    cert_private;
0039     bool    enabled;
0040     QString library;
0041     QString name;
0042     int     private_mask;
0043     QString slotevent_method;
0044     int     slotevent_timeout;
0045 
0046     Pkcs11ProviderConfig()
0047         : allow_protected_authentication(true)
0048         , cert_private(false)
0049         , enabled(false)
0050         , private_mask(0)
0051         , slotevent_method("auto")
0052         , slotevent_timeout(0)
0053     {
0054     }
0055 
0056     QVariantMap toVariantMap() const
0057     {
0058         QVariantMap out;
0059         out["allow_protected_authentication"] = allow_protected_authentication;
0060         out["cert_private"]                   = cert_private;
0061         out["enabled"]                        = enabled;
0062         out["library"]                        = library;
0063         out["name"]                           = name;
0064         out["private_mask"]                   = private_mask;
0065         out["slotevent_method"]               = slotevent_method;
0066         out["slotevent_timeout"]              = slotevent_timeout;
0067         return out;
0068     }
0069 
0070     bool fromVariantMap(const QVariantMap &in)
0071     {
0072         allow_protected_authentication = in["allow_protected_authentication"].toBool();
0073         cert_private                   = in["cert_private"].toBool();
0074         enabled                        = in["enabled"].toBool();
0075         library                        = in["library"].toString();
0076         name                           = in["name"].toString();
0077         private_mask                   = in["private_mask"].toInt();
0078         slotevent_method               = in["slotevent_method"].toString();
0079         slotevent_timeout              = in["slotevent_timeout"].toInt();
0080         return true;
0081     }
0082 };
0083 
0084 //----------------------------------------------------------------------------
0085 // Pkcs11Config
0086 //----------------------------------------------------------------------------
0087 class Pkcs11Config
0088 {
0089 public:
0090     bool                        allow_load_rootca;
0091     bool                        allow_protected_authentication;
0092     int                         log_level;
0093     int                         pin_cache;
0094     QList<Pkcs11ProviderConfig> providers;
0095 
0096     QVariantMap orig_config;
0097 
0098     Pkcs11Config()
0099         : allow_load_rootca(false)
0100         , allow_protected_authentication(true)
0101         , log_level(0)
0102         , pin_cache(-1)
0103     {
0104     }
0105 
0106     QVariantMap toVariantMap() const
0107     {
0108         QVariantMap out = orig_config;
0109 
0110         // form type
0111         out["formtype"] = "http://affinix.com/qca/forms/qca-pkcs11#1.0";
0112 
0113         // base settings
0114         out["allow_load_rootca"]              = allow_load_rootca;
0115         out["allow_protected_authentication"] = allow_protected_authentication;
0116         out["log_level"]                      = log_level;
0117         out["pin_cache"]                      = pin_cache;
0118 
0119         // provider settings (always write at least 10 providers)
0120         for (int n = 0; n < 10 || n < providers.count(); ++n) {
0121             QString prefix = QString().sprintf("provider_%02d_", n);
0122 
0123             Pkcs11ProviderConfig provider;
0124             if (n < providers.count())
0125                 provider = providers[n];
0126 
0127             QVariantMap                     subconfig = provider.toVariantMap();
0128             QMapIterator<QString, QVariant> it(subconfig);
0129             while (it.hasNext()) {
0130                 it.next();
0131                 out.insert(prefix + it.key(), it.value());
0132             }
0133         }
0134 
0135         return out;
0136     }
0137 
0138     bool fromVariantMap(const QVariantMap &in)
0139     {
0140         if (in["formtype"] != "http://affinix.com/qca/forms/qca-pkcs11#1.0")
0141             return false;
0142 
0143         allow_load_rootca              = in["allow_load_rootca"].toBool();
0144         allow_protected_authentication = in["allow_protected_authentication"].toBool();
0145         log_level                      = in["log_level"].toInt();
0146         pin_cache                      = in["pin_cache"].toInt();
0147 
0148         for (int n = 0;; ++n) {
0149             QString prefix = QString().sprintf("provider_%02d_", n);
0150 
0151             // collect all key/values with this prefix into a
0152             //   a separate container, leaving out the prefix
0153             //   from the keys.
0154             QVariantMap                     subconfig;
0155             QMapIterator<QString, QVariant> it(in);
0156             while (it.hasNext()) {
0157                 it.next();
0158                 if (it.key().startsWith(prefix))
0159                     subconfig.insert(it.key().mid(prefix.length()), it.value());
0160             }
0161 
0162             // if there are no config items with this prefix, we're done
0163             if (subconfig.isEmpty())
0164                 break;
0165 
0166             Pkcs11ProviderConfig provider;
0167             if (!provider.fromVariantMap(subconfig))
0168                 return false;
0169 
0170             // skip unnamed entries
0171             if (provider.name.isEmpty())
0172                 continue;
0173 
0174             // skip duplicate entries
0175             bool have_name_already = false;
0176             foreach (const Pkcs11ProviderConfig &i, providers) {
0177                 if (i.name == provider.name) {
0178                     have_name_already = true;
0179                     break;
0180                 }
0181             }
0182             if (have_name_already)
0183                 continue;
0184 
0185             providers += provider;
0186         }
0187 
0188         orig_config = in;
0189         return true;
0190     }
0191 };
0192 
0193 //----------------------------------------------------------------------------
0194 // ModuleListModel
0195 //----------------------------------------------------------------------------
0196 class ModuleListModel : public QAbstractListModel
0197 {
0198     Q_OBJECT
0199 public:
0200     QList<Pkcs11ProviderConfig> list;
0201 
0202     ModuleListModel(QObject *parent = 0)
0203         : QAbstractListModel(parent)
0204     {
0205     }
0206 
0207     int rowCount(const QModelIndex &parent = QModelIndex()) const
0208     {
0209         Q_UNUSED(parent);
0210         return list.count();
0211     }
0212 
0213     QVariant data(const QModelIndex &index, int role) const
0214     {
0215         if (!index.isValid())
0216             return QVariant();
0217 
0218         if (index.row() >= list.count())
0219             return QVariant();
0220 
0221         if (role == Qt::DisplayRole)
0222             return list[index.row()].name;
0223         else if (role == Qt::EditRole)
0224             return list[index.row()].name;
0225         else
0226             return QVariant();
0227     }
0228 
0229     Qt::ItemFlags flags(const QModelIndex &index) const
0230     {
0231         if (!index.isValid())
0232             return Qt::ItemIsEnabled;
0233 
0234         return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
0235     }
0236 
0237     bool setData(const QModelIndex &index, const QVariant &value, int role)
0238     {
0239         if (index.isValid() && role == Qt::EditRole) {
0240             QString str = value.toString();
0241 
0242             if (str.isEmpty()) {
0243                 emit editFailed(index, tr("Module name cannot be blank."));
0244                 return false;
0245             }
0246 
0247             bool have_name_already = false;
0248             int  at                = index.row();
0249             for (int n = 0; n < list.count(); ++n) {
0250                 const Pkcs11ProviderConfig &i = list[n];
0251 
0252                 // skip self
0253                 if (n == at)
0254                     continue;
0255 
0256                 if (i.name == str) {
0257                     have_name_already = true;
0258                     break;
0259                 }
0260             }
0261             if (have_name_already) {
0262                 emit editFailed(index, tr("There is already a module with this name."));
0263                 return false;
0264             }
0265 
0266             list[index.row()].name = str;
0267             emit dataChanged(index, index);
0268             return true;
0269         }
0270         return false;
0271     }
0272 
0273     void addItems(const QList<Pkcs11ProviderConfig> &items)
0274     {
0275         if (items.isEmpty())
0276             return;
0277 
0278         beginInsertRows(QModelIndex(), list.size(), list.size() + items.count() - 1);
0279         list += items;
0280         endInsertRows();
0281     }
0282 
0283     void addItem(const Pkcs11ProviderConfig &i)
0284     {
0285         beginInsertRows(QModelIndex(), list.size(), list.size());
0286         list += i;
0287         endInsertRows();
0288     }
0289 
0290     void removeItem(int at)
0291     {
0292         beginRemoveRows(QModelIndex(), at, at);
0293         list.removeAt(at);
0294         endRemoveRows();
0295     }
0296 
0297 Q_SIGNALS:
0298     void editFailed(const QModelIndex &index, const QString &reasonString);
0299 };
0300 
0301 //----------------------------------------------------------------------------
0302 // Pkcs11ConfigDlg
0303 //----------------------------------------------------------------------------
0304 static QCA::Provider *get_pkcs11_provider(QVariantMap *_config = 0)
0305 {
0306     QCA::ProviderList providers = QCA::providers();
0307     providers += QCA::defaultProvider();
0308 
0309     QCA::Provider *provider = 0;
0310     QVariantMap    config;
0311     foreach (QCA::Provider *p, providers) {
0312         config = QCA::getProviderConfig(p->name());
0313         if (!config.isEmpty() && config["formtype"] == "http://affinix.com/qca/forms/qca-pkcs11#1.0") {
0314             provider = p;
0315             break;
0316         }
0317     }
0318 
0319     if (provider && _config)
0320         *_config = config;
0321 
0322     return provider;
0323 }
0324 
0325 class Pkcs11ConfigDlg::Private : public QObject
0326 {
0327     Q_OBJECT
0328 public:
0329     Pkcs11ConfigDlg *q;
0330     Ui_Pkcs11Config  ui;
0331     QString          providerName;
0332     ModuleListModel *model;
0333     Pkcs11Config     config;
0334     bool             dirty;
0335 
0336     // for safe dialog closing behavior during QListView editing
0337     bool allow_close;
0338     bool done;
0339 
0340     // for ignoring modifications that we cause when populating fields
0341     bool ignore_dataChanged;
0342 
0343     Private(Pkcs11ConfigDlg *_q, const QString &_providerName, const QVariantMap &configmap)
0344         : QObject(_q)
0345         , q(_q)
0346         , providerName(_providerName)
0347         , dirty(false)
0348         , allow_close(true)
0349         , done(false)
0350         , ignore_dataChanged(true)
0351     {
0352         ui.setupUi(q);
0353         q->resize(q->minimumSize());
0354 
0355         model = new ModuleListModel(this);
0356         qRegisterMetaType<QModelIndex>("QModelIndex");
0357         // do this queued for two reasons:
0358         //   1) if we throw an error dialog, it will occur after the
0359         //      row text has reverted, and the call stack completed
0360         //      (the latter may not be required, but it helps me
0361         //      sleep).
0362         //   2) if the user accepts/rejects the dialog while editing,
0363         //      it is easy to ensure that the signal is not processed
0364         //  (if it gets delivered at all).
0365         connect(model,
0366                 SIGNAL(editFailed(const QModelIndex &, const QString &)),
0367                 SLOT(model_editFailed(const QModelIndex &, const QString &)),
0368                 Qt::QueuedConnection);
0369 
0370         // set up widgets
0371         ui.rb_pincache_nolimit->setChecked(true);
0372         ui.sb_pincache_time->setEnabled(false);
0373         ui.sb_pincache_time->setValue(300);
0374         ui.lv_modules->setModel(model);
0375         ui.lv_modules->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked |
0376                                        QAbstractItemView::EditKeyPressed);
0377         ui.pb_remove->setEnabled(false);
0378         ui.tb_details->setEnabled(false);
0379         ui.gb_poll->setEnabled(false);
0380         ui.rb_polldefault->setChecked(true);
0381         ui.sb_pollcustom->setEnabled(false);
0382         ui.sb_pollcustom->setValue(5);
0383         ui.ck_modeauto->setChecked(true);
0384 
0385         // disable this by default, enable on dataChanged
0386         ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
0387 
0388         // general
0389         connect(ui.ck_allowroot, SIGNAL(toggled(bool)), SLOT(dataChanged()));
0390         connect(ui.ck_allowprotected, SIGNAL(toggled(bool)), SLOT(dataChanged()));
0391         connect(ui.sb_loglevel, SIGNAL(valueChanged(int)), SLOT(dataChanged()));
0392         connect(ui.gb_pincache, SIGNAL(toggled(bool)), SLOT(dataChanged()));
0393         connect(ui.rb_pincache_nolimit, SIGNAL(toggled(bool)), SLOT(dataChanged()));
0394         connect(ui.rb_pincache_time, SIGNAL(toggled(bool)), ui.sb_pincache_time, SLOT(setEnabled(bool)));
0395         connect(ui.rb_pincache_time, SIGNAL(toggled(bool)), SLOT(dataChanged()));
0396         connect(ui.sb_pincache_time, SIGNAL(valueChanged(int)), SLOT(dataChanged()));
0397 
0398         // modules
0399         connect(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), SLOT(dataChanged()));
0400         connect(ui.lv_modules->selectionModel(),
0401                 SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
0402                 SLOT(module_selectionChanged(const QItemSelection &, const QItemSelection &)));
0403         connect(ui.pb_add, SIGNAL(clicked()), SLOT(module_add()));
0404         connect(ui.pb_remove, SIGNAL(clicked()), SLOT(module_remove()));
0405         connect(ui.le_library, SIGNAL(textChanged(const QString &)), SLOT(dataChanged()));
0406         connect(ui.pb_browse, SIGNAL(clicked()), SLOT(library_browse()));
0407         connect(ui.cb_slotmethod, SIGNAL(currentIndexChanged(int)), SLOT(slotmethod_currentIndexChanged(int)));
0408         connect(ui.rb_polldefault, SIGNAL(toggled(bool)), SLOT(dataChanged()));
0409         connect(ui.rb_pollcustom, SIGNAL(toggled(bool)), ui.sb_pollcustom, SLOT(setEnabled(bool)));
0410         connect(ui.rb_pollcustom, SIGNAL(toggled(bool)), SLOT(dataChanged()));
0411         connect(ui.sb_pollcustom, SIGNAL(valueChanged(int)), SLOT(dataChanged()));
0412         connect(ui.ck_modallowprotected, SIGNAL(toggled(bool)), SLOT(dataChanged()));
0413         connect(ui.ck_certprivate, SIGNAL(toggled(bool)), SLOT(dataChanged()));
0414         connect(ui.ck_modeauto, SIGNAL(toggled(bool)), SLOT(modeauto_toggled(bool)));
0415         connect(ui.ck_modesign, SIGNAL(toggled(bool)), SLOT(modenonauto_toggled(bool)));
0416         connect(ui.ck_modesignrecover, SIGNAL(toggled(bool)), SLOT(modenonauto_toggled(bool)));
0417         connect(ui.ck_modedecrypt, SIGNAL(toggled(bool)), SLOT(modenonauto_toggled(bool)));
0418         connect(ui.ck_modeunwrap, SIGNAL(toggled(bool)), SLOT(modenonauto_toggled(bool)));
0419 
0420         // is this a valid config?
0421         if (!providerName.isEmpty() && config.fromVariantMap(configmap)) {
0422             // if so, load everything up
0423             ui.ck_allowroot->setChecked(config.allow_load_rootca);
0424             ui.ck_allowprotected->setChecked(config.allow_protected_authentication);
0425             ui.sb_loglevel->setValue(config.log_level);
0426             if (config.pin_cache != 0) {
0427                 ui.gb_pincache->setChecked(true);
0428                 if (config.pin_cache <= -1)
0429                     ui.rb_pincache_nolimit->setChecked(true);
0430                 else {
0431                     ui.rb_pincache_time->setChecked(true);
0432                     ui.sb_pincache_time->setValue(config.pin_cache);
0433                 }
0434             }
0435 
0436             model->addItems(config.providers);
0437             if (!model->list.isEmpty()) {
0438                 QModelIndex index = model->index(0);
0439                 ui.lv_modules->setCurrentIndex(index);
0440                 ui.lv_modules->selectionModel()->select(
0441                     index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current);
0442             }
0443             ui.buttonBox->setFocus();
0444             ui.buttonBox->button(QDialogButtonBox::Cancel)->setFocus();
0445         } else {
0446             // otherwise, disable everything
0447             ui.gb_general->setEnabled(false);
0448             ui.gb_modules->setEnabled(false);
0449             ui.buttonBox->setFocus();
0450             ui.buttonBox->button(QDialogButtonBox::Cancel)->setFocus();
0451         }
0452 
0453         ignore_dataChanged = false;
0454     }
0455 
0456     void save_module(int at)
0457     {
0458         // save all options (except the name, which is handled by the model)
0459         Pkcs11ProviderConfig &i = model->list[at];
0460 
0461         i.library = ui.le_library->text();
0462         i.enabled = true;
0463 
0464         int x = ui.cb_slotmethod->currentIndex();
0465         if (x == 0)
0466             i.slotevent_method = "auto";
0467         else if (x == 1)
0468             i.slotevent_method = "trigger";
0469         else // 2
0470             i.slotevent_method = "poll";
0471         if (x == 2) {
0472             if (ui.rb_polldefault->isChecked())
0473                 i.slotevent_timeout = 0;
0474             else
0475                 i.slotevent_timeout = ui.sb_pollcustom->value();
0476         } else
0477             i.slotevent_timeout = 0;
0478 
0479         i.allow_protected_authentication = ui.ck_modallowprotected->isChecked();
0480         i.cert_private                   = ui.ck_certprivate->isChecked();
0481 
0482         i.private_mask = 0;
0483         if (ui.ck_modesign->isChecked())
0484             i.private_mask |= 1;
0485         if (ui.ck_modesignrecover->isChecked())
0486             i.private_mask |= 2;
0487         if (ui.ck_modedecrypt->isChecked())
0488             i.private_mask |= 4;
0489         if (ui.ck_modeunwrap->isChecked())
0490             i.private_mask |= 8;
0491     }
0492 
0493     void save()
0494     {
0495         // save currently selected module, which may not be saved yet
0496         QItemSelection selection = ui.lv_modules->selectionModel()->selection();
0497         if (!selection.indexes().isEmpty()) {
0498             QModelIndex index = selection.indexes().first();
0499             save_module(index.row());
0500         }
0501 
0502         config.allow_load_rootca              = ui.ck_allowroot->isChecked();
0503         config.allow_protected_authentication = ui.ck_allowprotected->isChecked();
0504         config.log_level                      = ui.sb_loglevel->value();
0505         if (ui.gb_pincache->isChecked()) {
0506             if (ui.rb_pincache_nolimit->isChecked())
0507                 config.pin_cache = -1;
0508             else
0509                 config.pin_cache = ui.sb_pincache_time->value();
0510         } else
0511             config.pin_cache = 0;
0512 
0513         config.providers = model->list;
0514 
0515         QVariantMap configmap = config.toVariantMap();
0516         QCA::setProviderConfig(providerName, configmap);
0517         QCA::saveProviderConfig(providerName);
0518     }
0519 
0520 private Q_SLOTS:
0521     void model_editFailed(const QModelIndex &index, const QString &reasonString)
0522     {
0523         // if the dialog has already been dismissed, then don't
0524         //   bother with handling the editing failure
0525         if (done)
0526             return;
0527 
0528         // show error dialog, and don't allow dimissing the dialog
0529         //   during.  we need this, because the dismiss request
0530         //   can be queued, and end up being invoked during the
0531         //   QMessageBox nested eventloop.
0532         allow_close = false;
0533         QMessageBox::information(q, tr("Module Configuration"), reasonString);
0534         allow_close = true;
0535 
0536         // return to edit mode for the item
0537         ui.lv_modules->setFocus();
0538         ui.lv_modules->setCurrentIndex(index);
0539         ui.lv_modules->selectionModel()->select(
0540             index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current);
0541         ui.lv_modules->edit(index);
0542     }
0543 
0544     void dataChanged()
0545     {
0546         if (ignore_dataChanged)
0547             return;
0548 
0549         if (dirty)
0550             return;
0551 
0552         dirty = true;
0553         ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
0554     }
0555 
0556     void module_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
0557     {
0558         if (!deselected.indexes().isEmpty()) {
0559             QModelIndex index = deselected.indexes().first();
0560             save_module(index.row());
0561         }
0562 
0563         ignore_dataChanged = true;
0564 
0565         if (!selected.indexes().isEmpty()) {
0566             if (deselected.indexes().isEmpty()) {
0567                 ui.pb_remove->setEnabled(true);
0568                 ui.tb_details->setEnabled(true);
0569             }
0570 
0571             QModelIndex                 index = selected.indexes().first();
0572             const Pkcs11ProviderConfig &i     = model->list[index.row()];
0573 
0574             ui.le_library->setText(i.library);
0575 
0576             if (i.slotevent_method == "trigger")
0577                 ui.cb_slotmethod->setCurrentIndex(1);
0578             else if (i.slotevent_method == "poll") {
0579                 ui.cb_slotmethod->setCurrentIndex(2);
0580                 if (i.slotevent_timeout <= 0)
0581                     ui.rb_polldefault->setChecked(true);
0582                 else {
0583                     ui.rb_pollcustom->setChecked(true);
0584                     ui.sb_pollcustom->setValue(i.slotevent_timeout);
0585                 }
0586             } else // auto
0587                 ui.cb_slotmethod->setCurrentIndex(0);
0588             if (i.slotevent_method != "poll") {
0589                 ui.rb_polldefault->setChecked(true);
0590                 ui.sb_pollcustom->setValue(5);
0591             }
0592 
0593             ui.ck_modallowprotected->setChecked(i.allow_protected_authentication);
0594             ui.ck_certprivate->setChecked(i.cert_private);
0595 
0596             if (i.private_mask == 0)
0597                 ui.ck_modeauto->setChecked(true);
0598             else {
0599                 ui.ck_modesign->setChecked(i.private_mask & 1);
0600                 ui.ck_modesignrecover->setChecked(i.private_mask & 2);
0601                 ui.ck_modedecrypt->setChecked(i.private_mask & 4);
0602                 ui.ck_modeunwrap->setChecked(i.private_mask & 8);
0603             }
0604         } else if (selected.indexes().isEmpty() && !deselected.indexes().isEmpty()) {
0605             // restore defaults for all details widgets
0606             ui.le_library->setText(QString());
0607             ui.cb_slotmethod->setCurrentIndex(0);
0608             ui.rb_polldefault->setChecked(true);
0609             ui.sb_pollcustom->setValue(5);
0610             ui.ck_modallowprotected->setChecked(false);
0611             ui.ck_certprivate->setChecked(false);
0612             ui.ck_modeauto->setChecked(true);
0613 
0614             // flip to first page, disable
0615             ui.tb_details->setCurrentIndex(0);
0616             ui.pb_remove->setEnabled(false);
0617             ui.tb_details->setEnabled(false);
0618         }
0619 
0620         ignore_dataChanged = false;
0621     }
0622 
0623     void module_add()
0624     {
0625         // find unused default name
0626         QString name;
0627         for (int n = 1;; ++n) {
0628             if (n == 1)
0629                 name = tr("New Module");
0630             else
0631                 name = tr("New Module (%1)").arg(n);
0632 
0633             bool have_name_already = false;
0634             for (int n = 0; n < model->list.count(); ++n) {
0635                 const Pkcs11ProviderConfig &i = model->list[n];
0636                 if (i.name == name) {
0637                     have_name_already = true;
0638                     break;
0639                 }
0640             }
0641             if (!have_name_already)
0642                 break;
0643         }
0644 
0645         Pkcs11ProviderConfig i;
0646         i.name    = name;
0647         i.enabled = true;
0648         model->addItem(i);
0649 
0650         dataChanged();
0651 
0652         QModelIndex index = model->index(model->list.count() - 1);
0653 
0654         // flip to first page
0655         ui.tb_details->setCurrentIndex(0);
0656 
0657         // edit this item
0658         ui.lv_modules->setFocus();
0659         ui.lv_modules->setCurrentIndex(index);
0660         ui.lv_modules->selectionModel()->select(
0661             index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current);
0662         ui.lv_modules->edit(index);
0663     }
0664 
0665     void module_remove()
0666     {
0667         QItemSelection selection = ui.lv_modules->selectionModel()->selection();
0668         if (selection.indexes().isEmpty())
0669             return;
0670         QModelIndex index = selection.indexes().first();
0671         model->removeItem(index.row());
0672 
0673         dataChanged();
0674     }
0675 
0676     void library_browse()
0677     {
0678         QString fileName =
0679             QFileDialog::getOpenFileName(q, tr("Select PKCS#11 Module"), QString(), tr("PKCS#11 Modules (*.*)"));
0680         if (fileName.isEmpty())
0681             return;
0682 
0683         ui.le_library->setText(fileName);
0684     }
0685 
0686     void slotmethod_currentIndexChanged(int index)
0687     {
0688         if (index == 2) // Polling
0689             ui.gb_poll->setEnabled(true);
0690         else
0691             ui.gb_poll->setEnabled(false);
0692 
0693         dataChanged();
0694     }
0695 
0696     void modeauto_toggled(bool checked)
0697     {
0698         if (checked) {
0699             if (ui.ck_modesign->isChecked())
0700                 ui.ck_modesign->setChecked(false);
0701             if (ui.ck_modesignrecover->isChecked())
0702                 ui.ck_modesignrecover->setChecked(false);
0703             if (ui.ck_modedecrypt->isChecked())
0704                 ui.ck_modedecrypt->setChecked(false);
0705             if (ui.ck_modeunwrap->isChecked())
0706                 ui.ck_modeunwrap->setChecked(false);
0707         } else {
0708             if (!ui.ck_modesign->isChecked() && !ui.ck_modesignrecover->isChecked() &&
0709                 !ui.ck_modedecrypt->isChecked() && !ui.ck_modeunwrap->isChecked()) {
0710                 ui.ck_modesign->setChecked(true);
0711                 ui.ck_modesignrecover->setChecked(true);
0712                 ui.ck_modedecrypt->setChecked(true);
0713                 ui.ck_modeunwrap->setChecked(true);
0714             }
0715         }
0716 
0717         dataChanged();
0718     }
0719 
0720     void modenonauto_toggled(bool checked)
0721     {
0722         if (checked) {
0723             if (ui.ck_modeauto->isChecked())
0724                 ui.ck_modeauto->setChecked(false);
0725         } else {
0726             if (!ui.ck_modesign->isChecked() && !ui.ck_modesignrecover->isChecked() &&
0727                 !ui.ck_modedecrypt->isChecked() && !ui.ck_modeunwrap->isChecked()) {
0728                 ui.ck_modeauto->setChecked(true);
0729             }
0730         }
0731 
0732         dataChanged();
0733     }
0734 };
0735 
0736 Pkcs11ConfigDlg::Pkcs11ConfigDlg(QWidget *parent)
0737     : QDialog(parent)
0738 {
0739     QVariantMap    config;
0740     QCA::Provider *p = get_pkcs11_provider(&config);
0741     if (p)
0742         d = new Private(this, p->name(), config);
0743     else
0744         d = new Private(this, QString(), QVariantMap());
0745 }
0746 
0747 Pkcs11ConfigDlg::Pkcs11ConfigDlg(const QString &providerName, const QVariantMap &config, QWidget *parent)
0748     : QDialog(parent)
0749 {
0750     d = new Private(this, providerName, config);
0751 }
0752 
0753 Pkcs11ConfigDlg::~Pkcs11ConfigDlg()
0754 {
0755     delete d;
0756 }
0757 
0758 void Pkcs11ConfigDlg::done(int r)
0759 {
0760     if (!d->allow_close)
0761         return;
0762 
0763     d->done = true;
0764     if (r == Accepted)
0765         d->save();
0766     QDialog::done(r);
0767 }
0768 
0769 bool Pkcs11ConfigDlg::isSupported()
0770 {
0771     return (get_pkcs11_provider() ? true : false);
0772 }
0773 
0774 #include "pkcs11configdlg.moc"