/* vi: set sw=4 ts=4: * * Copyright (C) 2001 - 2015 Christian Hohnstaedt. * * All rights reserved. */ #include "db_base.h" #include "func.h" #include "exception.h" #include #include #include #include #include #include #include "widgets/MainWindow.h" #include "widgets/ImportMulti.h" #include "widgets/XcaDialog.h" QHash db_base::lookup; db_base::db_base(MainWindow *mw) :QAbstractItemModel(NULL) { rootItem = newPKI(); rootItem->setIntName(rootItem->getClassName()); mainwin = mw; colResizing = 0; currentIdx = QModelIndex(); class_name = "base"; } db_base::~db_base() { saveHeaderState(); delete rootItem; } pki_base *db_base::newPKI(enum pki_type type) { (void)type; return new pki_base("rootItem"); } void db_base::createSuccess(pki_base *pki) { if (!pki) return; if (pki_base::suppress_messages) return; XCA_INFO(pki->getMsg(pki_base::msg_create).arg(pki->getIntName())); } void db_base::remFromCont(QModelIndex &idx) { if (!idx.isValid()) return; pki_base *pki = static_cast(idx.internalPointer()); pki_base *parent_pki = pki->getParent(); int row = pki->row(); beginRemoveRows(parent(idx), row, row); parent_pki->takeChild(pki); endRemoveRows(); emit columnsContentChanged(); } QString db_base::sqlItemSelector() { QStringList sl; QString selector; foreach(enum pki_type pt, pkitype) sl << QString("type=%1").arg(pt); return sl.join(" OR "); } QList db_base::sqlSELECTpki(QString query, QList values) { QList x; XSqlQuery q; int i, num_values = values.size(); SQL_PREPARE(q, query); for (i=0; i < num_values; i++) { q.bindValue(i, values[i]); } q.exec(); mainwin->dbSqlError(q.lastError()); while (q.next()) x << lookupPki(q.value(0)); return x; } void db_base::loadContainer() { XSqlQuery q; QSqlError e; QString stmt; stmt = QString("SELECT id, type FROM items WHERE ") + sqlItemSelector(); q.exec(stmt); e = q.lastError(); mainwin->dbSqlError(e); while (q.next()) { enum pki_type t = (enum pki_type)q.value(1).toInt(); pki_base *pki = newPKI(t); e = pki->restoreSql(q.value(0)); if (!e.isValid()) { insertChild(rootItem, pki); lookup[q.value(0).toULongLong()] = pki; } else { mainwin->dbSqlError(e); } } QString view = mainwin->getSetting(class_name + "_hdView"); if (view.isEmpty()) { for (int i=0; i< allHeaders.count(); i++) { allHeaders[i]->reset(); } } else { allHeaders.fromData(view); } emit columnsContentChanged(); } void db_base::updateHeaders() { QString s = allHeaders.toData(); foreach(dbheader *h, allHeaders) delete h; allHeaders = getHeaders(); allHeaders.fromData(s); } dbheaderList db_base::getHeaders() { dbheaderList h; /* "No." handled in XcaProxyModel */ h << new dbheader(HD_internal_name, true, tr("Internal name")) << new dbheader(HD_counter, false, tr("No.")) << new dbheader(HD_creation, false, tr("Date"), tr("Date of creation or insertion")) << new dbheader(HD_comment, false, tr("Comment"), tr("First line of the comment field")); return h; } void db_base::saveHeaderState() { QSqlDatabase *db = mainwin->getDb(); if (db->isOpen()) mainwin->storeSetting(class_name + "_hdView", allHeaders.toData()); } void db_base::setVisualIndex(int i, int visualIndex) { if (colResizing) return; allHeaders[i]->visualIndex = visualIndex; } void db_base::sectionResized(int i, int, int newSize) { if (!allHeaders[i]->show || newSize <= 0 || colResizing) return; allHeaders[i]->size = newSize; } bool db_base::fixedHeaderSize(int sect) { return allHeaders[sect]->size != -1; } void db_base::initHeaderView(QHeaderView *hv) { int max = allHeaders.count(); colResizeStart(); for (int i=0; isetupHeaderView(i, hv); } for (int i=0; ivisualIndex == -1) continue; if (hv->visualIndex(i) != allHeaders[i]->visualIndex) { hv->moveSection(hv->visualIndex(i), allHeaders[i]->visualIndex); } } colResizeEnd(); } void db_base::sortIndicatorChanged(int logicalIndex, Qt::SortOrder order) { int max = allHeaders.count(); if (!isValidCol(logicalIndex)) return; for (int i=0; isortIndicator = -1; } allHeaders[logicalIndex]->sortIndicator = order; } QSqlError db_base::insertPKI_noTransaction(pki_base *pki) { QSqlError e = pki->insertSql(); lookup[pki->getSqlItemId().toULongLong()] = pki; inToCont(pki); mainwin->dbSqlError(e); emit columnsContentChanged(); return e; } void db_base::insertPKI(pki_base *pki) { QSqlDatabase *db = mainwin->getDb(); if (db->transaction()) { QSqlError e = insertPKI_noTransaction(pki); if (e.isValid()) db->rollback(); else db->commit(); } emit columnsContentChanged(); } QString db_base::pem2QString(QModelIndexList indexes) const { exportType::etype format; QString msg; format = clipboardFormat(indexes); foreach(QModelIndex idx, indexes) { long l; const char *p; if (idx.column() != 0) continue; BIO *bio = BIO_new(BIO_s_mem()); pki_base *pki = static_cast (idx.internalPointer()); pki->pem(bio, format); openssl_error(); l = BIO_get_mem_data(bio, &p); msg += QString::fromUtf8(p, l); BIO_free(bio); } return msg; } void db_base::pem2clipboard(QModelIndexList indexes) const { QString msg = pem2QString(indexes); QClipboard *cb = QApplication::clipboard(); if (cb->supportsSelection()) cb->setText(msg, QClipboard::Selection); cb->setText(msg); } void db_base::deletePKI(QModelIndex idx) { pki_base *pki = static_cast(idx.internalPointer()); QSqlDatabase *db = mainwin->getDb(); try { try { pki->deleteFromToken(); } catch (errorEx &err) { MainWindow::Error(err); } if (db->transaction()) { QSqlError e = pki->deleteSql(); remFromCont(idx); mainwin->dbSqlError(e); if (e.isValid()) db->rollback(); else db->commit(); mainwin->dbSqlError(e); } } catch (errorEx &err) { MainWindow::Error(err); } } void db_base::showItem(const QModelIndex &index) { showPki(static_cast(index.internalPointer())); } void db_base::showItem(const QString name) { pki_base *pki = lookupPki(name.toULongLong()); if (pki) showPki(pki); } void db_base::insertChild(pki_base *parent, pki_base *child) { QModelIndex idx = QModelIndex(); if (parent == child || parent == NULL) parent = rootItem; if (parent != rootItem) idx = index(parent); beginInsertRows(idx, 0, 0); parent->insert(0,child); endInsertRows(); } /* Does all the linking from existing keys, crls, certs * to the new imported or generated item * called before the new item will be inserted into the database */ void db_base::inToCont(pki_base *pki) { insertChild(rootItem, pki); } pki_base *db_base::getByName(QString desc) { QList list = sqlSELECTpki( QString("SELECT id FROM items WHERE name=? AND ") + sqlItemSelector(), QList() << QVariant(desc)); return list.isEmpty() ? NULL : list[0]; } pki_base *db_base::getByReference(pki_base *refpki) { if (refpki == NULL) return NULL; QList list = sqlSELECTpki( QString("SELECT item FROM %1 WHERE hash=?").arg(sqlHashTable), QList() << QVariant(refpki->hash())); foreach(pki_base *pki, list) { if (refpki->compare(pki)) return pki; } return NULL; } QList db_base::getAll() { return sqlSELECTpki(QString("SELECT item FROM %1").arg(sqlHashTable)); } pki_base *db_base::insert(pki_base *item) { insertPKI(item); return item; } void db_base::writeAll(void) { } void db_base::dump(QString dirname) { dirname += QDir::separator() + class_name; QDir d(dirname); if (!d.exists() && !d.mkdir(dirname)) { throw errorEx("Could not create directory '" + dirname + "'"); } try { FOR_ALL_pki(pki, pki_base) { pki->writeDefault(dirname); } } catch (errorEx &err) { mainwin->Error(err); } } QModelIndex db_base::index(int row, int column, const QModelIndex &parent) const { pki_base *parentItem; if(column <0) abort(); if (!parent.isValid()) parentItem = rootItem; else parentItem = static_cast(parent.internalPointer()); pki_base *childItem = parentItem->child(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); } QModelIndex db_base::index(pki_base *pki) const { if (!pki) return QModelIndex(); return createIndex(pki->row(), 0, pki); } QModelIndex db_base::parent(const QModelIndex &idx) const { if (!idx.isValid()) return QModelIndex(); pki_base *childItem = static_cast(idx.internalPointer()); pki_base *parentItem = childItem->getParent(); if (parentItem == rootItem || parentItem == NULL) return QModelIndex(); return index(parentItem); } int db_base::rowCount(const QModelIndex &parent) const { pki_base *parentItem; if (!parent.isValid()) parentItem = rootItem; else parentItem = static_cast(parent.internalPointer()); return parentItem->childCount(); } int db_base::columnCount(const QModelIndex &) const { return allHeaders.count(); } QVariant db_base::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); dbheader *hd = allHeaders[index.column()]; pki_base *item = static_cast(index.internalPointer()); switch (role) { case Qt::EditRole: case Qt::DisplayRole: return item->column_data(hd); case Qt::DecorationRole: return item->getIcon(hd); case Qt::TextAlignmentRole: return hd->isNumeric() ? Qt::AlignRight : Qt::AlignLeft; case Qt::FontRole: return QVariant(XCA_application::tableFont); case Qt::BackgroundRole: return item->bg_color(hd); case Qt::UserRole: return item->visible(); } return QVariant(); } static QVariant getHeaderViewInfo(dbheader *h) { return QVariant( #if 0 QString("H[%1] Show:%2%3 Size:%4 VI:%5 Indi:%6"). arg(sect).arg(h->show).arg(h->showDefault).arg(h->size). arg(h->visualIndex).arg(h->sortIndicator) #else h->getTooltip() #endif ); } QVariant db_base::headerData(int section, Qt::Orientation orientation, int role) const { if (!isValidCol(section)) return QVariant(); if (orientation == Qt::Horizontal) { switch (role) { case Qt::DisplayRole: return QVariant(allHeaders[section]->getName()); case Qt::ToolTipRole: return getHeaderViewInfo(allHeaders[section]); } } return QVariant(); } Qt::ItemFlags db_base::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::ItemIsEnabled; Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); defaultFlags |= Qt::ItemIsDragEnabled; if (index.column() == 0) return defaultFlags |= Qt::ItemIsEditable; return defaultFlags; } bool db_base::setData(const QModelIndex &index, const QVariant &value, int role) { QString on, nn; pki_base *item; if (index.isValid() && role == Qt::EditRole) { nn = value.toString(); item = static_cast(index.internalPointer()); on = item->getIntName(); if (nn == on) return true; updateItem(item, nn, item->getComment()); return true; } return false; } void db_base::updateItem(pki_base *pki, QString name, QString comment) { XSqlQuery q; QSqlError e; SQL_PREPARE(q, "UPDATE items SET name=?, comment=? WHERE id=?"); q.bindValue(0, name); q.bindValue(1, comment); q.bindValue(2, pki->getSqlItemId()); q.exec(); e = q.lastError(); mainwin->dbSqlError(e); if (e.isValid()) return; pki->setIntName(name); pki->setComment(comment); QModelIndex i, j; i = index(pki); j = index(i.row(), allHeaders.size(), i.parent()); emit dataChanged(i, j); } void db_base::editComment(const QModelIndex &index) { pki_base *item = static_cast(index.internalPointer()); if (!index.isValid() || !item) return; QTextEdit *t = new QTextEdit(mainwin); t->setAutoFormatting(QTextEdit::AutoNone); t->setAcceptRichText(false); t->setPlainText(item->getComment()); XcaDialog *d = new XcaDialog(mainwin, item->getType(), t, tr("Edit comment"), item->getIntName()); if (d->exec()) updateItem(item, item->getIntName(), t->toPlainText()); delete d; } void db_base::load_default(load_base &load) { QString s; QStringList slist = QFileDialog::getOpenFileNames(mainwin, load.caption, mainwin->getPath(), load.filter); if (!slist.count()) return; QString fn = slist[0]; mainwin->setPath(fn.mid(0, fn.lastIndexOf("/"))); ImportMulti *dlgi = new ImportMulti(mainwin); foreach(s, slist) { pki_base *item = NULL; try { item = load.loadItem(s); dlgi->addItem(item); } catch (errorEx &err) { MainWindow::Error(err); delete item; } } dlgi->execute(); delete dlgi; } void db_base::store(QModelIndexList indexes) { int ret; xcaWarning msg(mainwin, tr("How to export the %1 selected items"). arg(indexes.size())); msg.addButton(QMessageBox::Ok)->setText(tr("All in one PEM file")); msg.addButton(QMessageBox::Apply)->setText(tr("Each item in one file")); msg.addButton(QMessageBox::Cancel); ret = msg.exec(); if (ret == QMessageBox::Apply) { foreach(QModelIndex i, indexes) store(i); return; } else if (ret != QMessageBox::Ok) { return; } QString fn = mainwin->getPath() + QDir::separator() + "export.pem"; QString s = QFileDialog::getSaveFileName(mainwin, tr("Save %1 items in one file as").arg(indexes.size()), fn, tr("PEM files ( *.pem );; All files ( * )")); if (s.isEmpty()) return; s = nativeSeparator(s); mainwin->setPath(s.mid(0, s.lastIndexOf(QRegExp("[/\\\\]")) )); try { QString pem = pem2QString(indexes); FILE *fp = fopen_write(s); if (!fp) { throw errorEx(tr("Error opening file: '%1': %2"). arg(s).arg(strerror(errno)), class_name); } if (fwrite(pem.toLatin1(), pem.size(), 1, fp)) { /* IGNORE_RESULT */ } fclose(fp); } catch (errorEx &err) { MainWindow::Error(err); } } bool db_base::columnHidden(int col) const { if (!isValidCol(col)) return true; if (pki_x509::disable_netscape && allHeaders[col]->type == dbheader::hd_v3ext_ns) return true; return !allHeaders[col]->show; } void db_base::columnResetDefaults() { dbheader *hd; foreach(hd, allHeaders) { hd->reset(); } emit resetHeader(); } bool db_base::isNumericCol(int col) const { return isValidCol(col) ? allHeaders[col]->isNumeric() : false; } bool db_base::isValidCol(int col) const { return col >= allHeaders.size() || col < 0 ? false : true; } QMimeData *db_base::mimeData(const QModelIndexList &indexes) const { QString data = pem2QString(indexes); if (data.isEmpty()) return NULL; QMimeData *mimeData = new QMimeData(); mimeData->setText(data.toLatin1()); mimeData->setData(X_XCA_DRAG_DATA, QByteArray()); return mimeData; }