Use pkcs11_lib_list as model for Options:pkcs11list

Change pkcs11List from QListWidget to QListView
The pkcs11_lib_list holds the data of the loaded libraries.
For the model a QList "model_data" is used to
hold indexes into QList dirs to allow duplicates,
moves and removes.

On windows it now displays the paths with \ separators.
This commit is contained in:
Christian Hohnstaedt 2020-04-03 23:52:44 +02:00
parent 6e18595bda
commit 2d0980d4f6
16 changed files with 284 additions and 232 deletions

View File

@ -27,7 +27,7 @@
#include "openssl_compat.h"
pkcs11_lib_list pkcs11::libs;
pkcs11_lib_list pkcs11::libraries;
pkcs11::pkcs11()
{
@ -44,52 +44,6 @@ pkcs11::~pkcs11()
}
}
pkcs11_lib *pkcs11::load_lib(const QString &fname)
{
if (fname.isEmpty())
return NULL;
return libs.add_lib(fname);
}
void pkcs11::reload_libs(const QString &libnames)
{
QMap<QString, pkcs11_lib *> store;
if (libnames.isEmpty()) {
remove_libs();
return;
}
for (pkcs11_lib_list::iterator i = libs.begin(); i != libs.end(); ++i)
store[(*i)->filename()] = *i;
libs.clear();
foreach(QString name, libnames.split('\n')) {
bool enable;
QString n = pkcs11_lib::name2File(name, &enable);
pkcs11_lib *l = store.take(n);
if (l) {
if (enable == l->isEnabled()) {
libs.append(l);
} else {
delete l;
l = NULL;
}
}
// NOT else
if (!l)
l = load_lib(name);
qDebug() << "REORDER:" << n << name
<< "Enabled:" << l->isEnabled()
<< "Loaded:" << l->isLoaded()
<< "Should:" << enable;
}
qDebug() << "Delete remainig Libs start";
qDeleteAll(store);
qDebug() << "Delete remainig Libs done";
}
void pkcs11::startSession(slotid slot, bool rw)
{
CK_RV rv;

View File

@ -102,43 +102,15 @@ class pkcs11
friend class pk11_attr_data;
private:
static pkcs11_lib_list libs;
slotid p11slot;
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE p11obj;
public:
static pkcs11_lib_list libraries;
pkcs11();
~pkcs11();
static bool loaded()
{
foreach(pkcs11_lib *l, libs) {
if (l->isLoaded())
return true;
}
return false;
}
static pkcs11_lib *load_lib(const QString &fname);
static pkcs11_lib *get_lib(const QString &fname)
{
return libs.get_lib(fname);
}
static bool remove_lib(QString fname)
{
return libs.remove_lib(fname);
}
static void remove_libs()
{
qDeleteAll(libs);
libs.clear();
}
static void reload_libs(const QString &libnames);
static pkcs11_lib_list get_libs()
{
return libs;
}
tkInfo tokenInfo(slotid slot);
tkInfo tokenInfo()
{
@ -150,7 +122,7 @@ class pkcs11
}
slotidList getSlotList()
{
return libs.getSlotList();
return libraries.getSlotList();
}
bool selectToken(slotid *slot, QWidget *w);

View File

@ -114,7 +114,7 @@ QList<unsigned long> pkcs11_lib::getSlotList()
return sl;
}
QString pkcs11_lib::driverInfo()
QString pkcs11_lib::driverInfo() const
{
CK_INFO info;
CK_RV rv;
@ -154,48 +154,75 @@ QString pkcs11_lib::name2File(const QString &name, bool *enabled)
if (enabled)
*enabled = ena[0] != '0';
}
return libname;
return relativePath(libname);
}
pkcs11_lib *pkcs11_lib_list::add_lib(const QString &fname)
{
foreach(pkcs11_lib *l, *this) {
if (l->isLib(fname))
int idx = -1;
pkcs11_lib *l = NULL;
if (fname.isEmpty())
return NULL;
for (int i = 0; i < libs.size(); i++) {
l = libs[i];
if (!l->isLib(fname))
continue;
if (model_data.contains(i))
return l;
idx = i;
break;
}
pkcs11_lib *l = new pkcs11_lib(fname);
append(l);
if (idx == -1) {
pkcs11_lib *l = new pkcs11_lib(fname);
idx = libs.size();
libs << l;
}
beginInsertRows(QModelIndex(), model_data.size(), model_data.size());
model_data << idx;
endInsertRows();
return l;
}
pkcs11_lib *pkcs11_lib_list::get_lib(const QString &fname)
void pkcs11_lib_list::load(const QString &list)
{
foreach(pkcs11_lib *l, *this) {
if (l->isLib(fname))
return l;
}
return NULL;
}
bool pkcs11_lib_list::remove_lib(const QString &fname)
{
for(int i=0; i<count(); i++) {
if (at(i)->isLib(fname)) {
delete takeAt(i);
return true;
beginResetModel();
QString orig = getPkcs11Provider();
QList<pkcs11_lib*> newlist;
foreach(QString name, list.split('\n')) {
pkcs11_lib *newitem = NULL;
name = name.trimmed();
if (name.isEmpty())
continue;
for (int i = 0; i < libs.size(); i++) {
if (name == libs[i]->toData()) {
newitem = libs.takeAt(i);
break;
}
}
if (!newitem) {
newitem = new pkcs11_lib(name);
}
newlist << newitem;
}
return false;
qDeleteAll(libs);
libs = newlist;
model_data.clear();
for (int i = 0; i < libs.size(); i++)
model_data << i;
endResetModel();
qDebug() << "Libs reloaded from" << orig << "to" << getPkcs11Provider();
}
slotidList pkcs11_lib_list::getSlotList()
slotidList pkcs11_lib_list::getSlotList() const
{
slotidList list;
QString ex;
bool success = false;
for (int i=0; i<count(); i++) {
pkcs11_lib *l = at(i);
foreach(pkcs11_lib *l, libs) {
if (!l->isLoaded())
continue;
try {
@ -213,6 +240,147 @@ slotidList pkcs11_lib_list::getSlotList()
throw errorEx(ex);
}
QString pkcs11_lib_list::getPkcs11Provider() const
{
QStringList prov;
foreach(int i, model_data)
prov << libs[i]->toData();
return prov.size() == 0 ? QString() : prov.join("\n");
}
void pkcs11_lib_list::remove_libs()
{
beginRemoveRows(QModelIndex(), 0, libs.size() -1);
qDeleteAll(libs);
libs.clear();
model_data.clear();
endRemoveRows();
}
bool pkcs11_lib_list::loaded() const
{
foreach(pkcs11_lib *l, libs)
if (l->isLoaded())
return true;
return false;
}
int pkcs11_lib_list::rowCount(const QModelIndex &) const
{
return model_data.size();
}
pkcs11_lib *pkcs11_lib_list::libByModelIndex(const QModelIndex &index) const
{
if (!index.isValid())
return NULL;
int idx = model_data[index.row()];
return (idx >= 0 && idx < libs.size()) ? libs[idx] : NULL;
}
QVariant pkcs11_lib_list::data(const QModelIndex &index, int role) const
{
pkcs11_lib *l = libByModelIndex(index);
if (!l)
return QVariant();
QString pixmap;
switch (role) {
case Qt::DisplayRole:
return QVariant(nativeSeparator(l->filename()));
case Qt::DecorationRole:
pixmap = l->pixmap();
if (pixmap.isEmpty()) {
QPixmap p(QSize(20, 20));
p.fill(Qt::transparent);
return QVariant(p);
}
return QVariant(QPixmap(pixmap));
case Qt::ToolTipRole:
return QVariant(l->driverInfo().trimmed());
case Qt::CheckStateRole:
return l->checked();
}
return QVariant();
}
QMap<int, QVariant> pkcs11_lib_list::itemData(const QModelIndex &index) const
{
QMap<int, QVariant> map;
if (index.isValid())
map[Qt::UserRole] = QVariant(model_data[index.row()]);
return map;
}
bool pkcs11_lib_list::setItemData(const QModelIndex &index,
const QMap<int, QVariant> &roles)
{
if (index.isValid() && roles[Qt::UserRole].isValid()) {
model_data[index.row()] = roles[Qt::UserRole].toInt();
return true;
}
return false;
}
bool pkcs11_lib_list::setData(const QModelIndex &index,
const QVariant &value, int role)
{
pkcs11_lib *l = libByModelIndex(index);
if (!l || role != Qt::CheckStateRole)
return false;
if (value == l->checked()) {
/* No changes */
return true;
}
QString file = l->toData(value == Qt::Checked);
delete l;
int idx = model_data[index.row()];
libs[idx] = new pkcs11_lib(file);
emit dataChanged(index, index);
return true;
}
Qt::ItemFlags pkcs11_lib_list::flags(const QModelIndex & index) const
{
if (index.isValid())
return Qt::ItemIsEnabled | Qt::ItemIsSelectable |
Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable;
return QAbstractListModel::flags(index) | Qt::ItemIsDropEnabled;
}
Qt::DropActions pkcs11_lib_list::supportedDropActions() const
{
return Qt::MoveAction;
}
bool pkcs11_lib_list::removeRows(int row, int count, const QModelIndex &parent)
{
if (parent.isValid() || row < 0 || row + count > model_data.size())
return false;
beginRemoveRows(parent, row, row + count - 1);
while (count-- > 0 && row < model_data.size())
model_data.removeAt(row);
endRemoveRows();
return true;
}
bool pkcs11_lib_list::insertRows(int row, int count, const QModelIndex &parent)
{
if (parent.isValid())
return false;
beginInsertRows(parent, row, row +count -1);
for (int i = 0; i < count; i++)
model_data.insert(row +i, 0);
endInsertRows();
return true;
}
const char *pk11errorString(unsigned long rv)
{
#define PK11_ERR(x) case x : return #x;

View File

@ -10,8 +10,11 @@
#include "lib/exception.h"
#include "opensc-pkcs11.h"
#include <QAbstractListModel>
#include <QString>
#include <QObject>
#include <QList>
#include <Qt>
#include <ltdl.h>
@ -30,12 +33,12 @@ class pkcs11_lib
~pkcs11_lib();
QList<unsigned long> getSlotList();
QString driverInfo();
QString filename()
QString driverInfo() const;
QString filename() const
{
return file;
}
CK_FUNCTION_LIST *ptr()
CK_FUNCTION_LIST *ptr() const
{
return p11;
}
@ -43,14 +46,28 @@ class pkcs11_lib
{
return p11 != NULL;
}
bool isEnabled() const
enum Qt::CheckState checked() const
{
return enabled;
return enabled ? Qt::Checked : Qt::Unchecked;
}
bool isLib(const QString &name)
bool isLib(const QString &name) const
{
return name2File(name) == file;
}
QString toData(int enabled) const
{
return QString("%1:%2").arg(enabled).arg(file);
}
QString toData() const
{
return toData(enabled);
}
QString pixmap() const
{
if (!enabled)
return QString();
return isLoaded() ? ":doneIco" : ":warnIco";
}
};
class slotid
@ -84,7 +101,7 @@ class slotid
if (!lib)
throw errorEx("InternalError: slotid is invalid");
}
CK_FUNCTION_LIST *p11()
CK_FUNCTION_LIST *p11() const
{
return lib->ptr();
}
@ -92,13 +109,36 @@ class slotid
typedef QList<slotid> slotidList;
class pkcs11_lib_list: public QList<pkcs11_lib*>
class pkcs11_lib_list: public QAbstractListModel
{
QList<pkcs11_lib*> libs;
QList<int> model_data;
public:
pkcs11_lib *add_lib(const QString &fname);
pkcs11_lib *get_lib(const QString &fname);
bool remove_lib(const QString &fname);
slotidList getSlotList();
void load(const QString &list);
slotidList getSlotList() const;
QString getPkcs11Provider() const;
void remove_libs();
bool loaded() const;
/* Helper for QAbstractListModel */
pkcs11_lib *libByModelIndex(const QModelIndex &index) const;
/* Reimplementation from QAbstractListModel */
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index,
int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
QMap<int, QVariant> itemData(const QModelIndex &index) const;
bool setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles);
Qt::ItemFlags flags(const QModelIndex& index) const;
Qt::DropActions supportedDropActions() const;
bool removeRows(int row, int count, const QModelIndex &p = QModelIndex());
bool insertRows(int row, int count, const QModelIndex &p = QModelIndex());
};
void pk11error(const QString &fmt, int r);

View File

@ -615,7 +615,7 @@ bool pki_scard::find_key_on_card(slotid *slot) const
* returns the slot ID in slot true on success */
bool pki_scard::prepare_card(slotid *slot) const
{
if (!pkcs11::loaded())
if (!pkcs11::libraries.loaded())
return false;
QString msg = tr("Please insert card: %1 %2 [%3] with Serial: %4").

View File

@ -385,7 +385,7 @@ void pki_x509::deleteFromToken()
pki_scard *card = dynamic_cast<pki_scard *>(privkey);
slotidList p11_slots;
if (!card || !pkcs11::loaded())
if (!card || !pkcs11::libraries.loaded())
return;
if (privkey && privkey->isToken()) {
@ -542,7 +542,7 @@ bool pki_x509::canSign() const
pki_key *privkey = getRefKey();
if (!privkey || privkey->isPubKey())
return false;
if (privkey->isToken() && !pkcs11::loaded())
if (privkey->isToken() && !pkcs11::libraries.loaded())
return false;
return isCA();
}

View File

@ -325,10 +325,13 @@ Especially EC and DSA are only defined with SHA1 in the PKCS#11 specification.</
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QListWidget" name="pkcs11List">
<widget class="QListView" name="pkcs11List">
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="dragDropOverwriteMode">
<bool>false</bool>
</property>

View File

@ -34,7 +34,7 @@ void CertTreeView::fillContextMenu(QMenu *menu, QMenu *subExport,
privkey = cert->getRefKey();
parent = cert->getSigner();
parentCanSign = parent && parent->canSign() && (parent != cert);
hasScard = pkcs11::loaded();
hasScard = pkcs11::libraries.loaded();
multi = indexes.size() > 1;

View File

@ -37,7 +37,7 @@ void KeyTreeView::fillContextMenu(QMenu *menu, QMenu *subExport,
}
}
if (!pkcs11::loaded() || multi)
if (!pkcs11::libraries.loaded() || multi)
return;
if (key->isToken()) {
@ -133,7 +133,7 @@ void KeyTreeView::toToken()
return;
pki_key *key = static_cast<pki_scard*>(currentIdx.internalPointer());
if (!key || !pkcs11::loaded() || key->isToken())
if (!key || !pkcs11::libraries.loaded() || key->isToken())
return;
pki_scard *card = NULL;

View File

@ -356,8 +356,6 @@ void MainWindow::timerEvent(QTimerEvent *event)
return;
stamp = q.value(0).toULongLong();
q.finish();
qDebug() << "Stamp" << stamp
<< "DatabaseStamp" << DbTransaction::DatabaseStamp;
if (stamp > DbTransaction::DatabaseStamp) {
SQL_PREPARE(q, "SELECT DISTINCT type FROM items WHERE stamp=?");
@ -544,8 +542,8 @@ void MainWindow::close_database()
update_history(currentDB);
pkcs11::remove_libs();
enableTokenMenu(pkcs11::loaded());
pkcs11::libraries.remove_libs();
enableTokenMenu(pkcs11::libraries.loaded());
QSqlDatabase::removeDatabase(connName);
currentDB.clear();
Settings.clear();

View File

@ -240,6 +240,5 @@ void MainWindow::setOptions()
}
delete opt;
pkcs11::reload_libs(Settings["pkcs11path"]);
enableTokenMenu(pkcs11::loaded());
load_engine();
}

View File

@ -61,9 +61,8 @@ void MainWindow::enableTokenMenu(bool enable)
void MainWindow::load_engine()
{
pkcs11::reload_libs(Settings["pkcs11path"]);
// Error(err);
enableTokenMenu(pkcs11::loaded());
pkcs11::libraries.load(Settings["pkcs11path"]);
enableTokenMenu(pkcs11::libraries.loaded());
}
void MainWindow::initResolver()
@ -218,7 +217,7 @@ void MainWindow::setItemEnabled(bool enable)
foreach(QAction *a, acList) {
a->setEnabled(enable);
}
enableTokenMenu(pkcs11::loaded());
enableTokenMenu(pkcs11::libraries.loaded());
}
void MainWindow::init_images()
@ -377,7 +376,7 @@ void MainWindow::pastePem()
void MainWindow::initToken()
{
bool ok;
if (!pkcs11::loaded())
if (!pkcs11::libraries.loaded())
return;
try {
pkcs11 p11;
@ -418,7 +417,7 @@ void MainWindow::initToken()
void MainWindow::changePin(bool so)
{
if (!pkcs11::loaded())
if (!pkcs11::libraries.loaded())
return;
try {
pkcs11 p11;
@ -439,7 +438,7 @@ void MainWindow::changeSoPin()
void MainWindow::initPin()
{
if (!pkcs11::loaded())
if (!pkcs11::libraries.loaded())
return;
try {
pkcs11 p11;
@ -462,7 +461,7 @@ void MainWindow::manageToken()
pki_x509 *cert = NULL;
ImportMulti *dlgi = NULL;
if (!pkcs11::loaded())
if (!pkcs11::libraries.loaded())
return;
try {

View File

@ -147,7 +147,7 @@ NewKey::NewKey(QWidget *parent, QString name)
updateCurves();
keyLength->setEditText(QString::number(defaultSize) + " bit");
keyDesc->setFocus();
if (pkcs11::loaded()) try {
if (pkcs11::libraries.loaded()) try {
pkcs11 p11;
p11_slots = p11.getSlotList();

View File

@ -14,11 +14,9 @@
#include <QMessageBox>
#include <QToolTip>
Options::Options(MainWindow *parent)
Options::Options(QWidget *parent)
:QDialog(parent)
{
mw = parent;
setWindowTitle(XCA_TITLE);
setupUi(this);
@ -45,7 +43,6 @@ Options::Options(MainWindow *parent)
setDnString(Settings["mandatory_dn"], extDNlist);
setDnString(Settings["explicit_dn"], expDNlist);
setupPkcs11Provider(Settings["pkcs11path"]);
suppress->setCheckState(Settings["suppress_messages"]);
noColorize->setCheckState(Settings["no_expire_colors"]);
@ -69,8 +66,10 @@ Options::Options(MainWindow *parent)
cert_expiry_num->setText(x);
serial_len->setValue(Settings["serial_len"]);
connect(pkcs11List, SIGNAL(itemClicked(QListWidgetItem *)),
this, SLOT(Pkcs11ItemChanged(QListWidgetItem *)));
pkcs11List->setModel(&pkcs11::libraries);
pkcs11List->showDropIndicator();
pkcs11List->setSelectionMode(QAbstractItemView::ExtendedSelection);
}
Options::~Options()
@ -147,7 +146,7 @@ int Options::exec()
Settings["mandatory_dn"] = getDnString(extDNlist);
Settings["explicit_dn"] = getDnString(expDNlist);
Settings["string_opt"] = string_opts[mbstring->currentIndex()];
Settings["pkcs11path"] = getPkcs11Provider();
Settings["pkcs11path"] = pkcs11::libraries.getPkcs11Provider();
Settings["cert_expiry"] = cert_expiry_num->text() +
cert_expiry_unit->currentItemData().toString();
@ -172,15 +171,8 @@ void Options::on_addButton_clicked(void)
void Options::addLib(QString fname)
{
QString status;
fname = QFileInfo(fname).canonicalFilePath();
if (fname.isEmpty() || pkcs11::get_lib(fname))
return;
pkcs11_lib *l = pkcs11::load_lib(fname);
addLibItem(fname);
pkcs11_lib *l = pkcs11::libraries.add_lib(fname);
if (searchP11 && l)
QToolTip::showText(searchP11->mapToGlobal(
@ -189,14 +181,14 @@ void Options::addLib(QString fname)
void Options::on_removeButton_clicked(void)
{
QListWidgetItem *item = pkcs11List->takeItem(pkcs11List->currentRow());
if (!item)
return;
try {
pkcs11::remove_lib(item->text());
} catch (errorEx &err) {
mw->Error(err);
}
QList<int> indexes;
foreach(QModelIndex i, pkcs11List->selectionModel()->selectedIndexes())
indexes << i.row();
/* Delete from highest to lowest index */
qSort(indexes.begin(), indexes.end(), qGreater<int>());
foreach(int i, indexes)
pkcs11List->model()->removeRow(i);
}
void Options::on_searchPkcs11_clicked(void)
@ -208,70 +200,3 @@ void Options::on_searchPkcs11_clicked(void)
}
searchP11->show();
}
void Options::Pkcs11ItemChanged(QListWidgetItem *item)
{
pkcs11List->blockSignals(true);
pkcs11_lib *l = pkcs11::get_libs().get_lib(item->text());
qDebug() << item->text() << item->checkState() << l->isEnabled() << l->isLoaded();
if ((item->checkState() == Qt::Checked) != l->isEnabled()) {
QString file = listItem2Name(item);
pkcs11::remove_lib(file);
pkcs11::load_lib(file);
updatePkcs11Item(item);
}
pkcs11List->blockSignals(false);
}
void Options::updatePkcs11Item(QListWidgetItem *item) const
{
pkcs11_lib *l = pkcs11::get_libs().get_lib(item->text());
if (!l)
return;
if (l->isEnabled()) {
item->setIcon(QPixmap(l->isLoaded() ? ":doneIco" : ":warnIco"));
} else {
QPixmap m(QSize(20,20));
m.fill(Qt::transparent);
item->setIcon(QIcon(m));
}
item->setToolTip(l->driverInfo().trimmed());
}
QListWidgetItem *Options::addLibItem(const QString &lib) const
{
pkcs11_lib *l = pkcs11::get_libs().get_lib(lib);
if (!l)
return NULL;
QListWidgetItem *item = new QListWidgetItem(lib);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
updatePkcs11Item(item);
item->setText(l->filename());
item->setCheckState(l->isEnabled() ? Qt::Checked : Qt::Unchecked);
pkcs11List->addItem(item);
return item;
}
void Options::setupPkcs11Provider(QString list)
{
foreach(QString libname, list.split('\n')) {
addLibItem(libname);
}
}
QString Options::listItem2Name(const QListWidgetItem *item) const
{
return QString("%1:%2").arg(item->checkState() == Qt::Checked)
.arg(item->text());
}
QString Options::getPkcs11Provider()
{
QStringList prov;
for (int j=0; j<pkcs11List->count(); j++) {
prov << listItem2Name(pkcs11List->item(j));
}
if (prov.count() == 0)
return QString("");
return prov.join("\n");
}

View File

@ -22,17 +22,11 @@ class Options: public QDialog, public Ui::Options
QStringList string_opts;
QString getDnString(QListWidget *w);
void setDnString(QString dn, QListWidget *w);
void setupPkcs11Provider(QString list);
QString getPkcs11Provider();
MainWindow *mw;
QString listItem2Name(const QListWidgetItem *item) const;
void updatePkcs11Item(QListWidgetItem *item) const;
public:
Options(MainWindow *parent);
Options(QWidget *parent);
~Options();
int exec();
QListWidgetItem *addLibItem(const QString &) const;
public slots:
void on_extDNadd_clicked();
@ -44,7 +38,6 @@ class Options: public QDialog, public Ui::Options
void on_removeButton_clicked(void);
void on_searchPkcs11_clicked(void);
void addLib(QString);
void Pkcs11ItemChanged(QListWidgetItem *);
};
#endif

View File

@ -26,6 +26,7 @@ SearchPkcs11::SearchPkcs11(QWidget *parent, const QString &fname)
filename->setText(nativeSeparator(fname));
setWindowTitle(XCA_TITLE);
liblist->setSelectionMode(QAbstractItemView::ExtendedSelection);
searching = NULL;
}