/* vi: set sw=4 ts=4: * * Copyright (C) 2001 - 2015 Christian Hohnstaedt. * * All rights reserved. */ //#define MDEBUG #include "MainWindow.h" #include "ImportMulti.h" #include "lib/Passwd.h" #include "lib/entropy.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lib/exception.h" #include "lib/pki_evp.h" #include "lib/pki_scard.h" #include "lib/pki_pkcs12.h" #include "lib/pki_multi.h" #include "lib/load_obj.h" #include "lib/pass_info.h" #include "lib/func.h" #include "lib/pkcs11.h" #include "lib/builtin_curves.h" #include "ui_About.h" #include "PwDialog.h" QPixmap *MainWindow::keyImg = NULL, *MainWindow::csrImg = NULL, *MainWindow::certImg = NULL, *MainWindow::tempImg = NULL, *MainWindow::nsImg = NULL, *MainWindow::revImg = NULL, *MainWindow::appIco = NULL, *MainWindow::scardImg = NULL, *MainWindow::doneIco = NULL, *MainWindow::warnIco = NULL; db_key *MainWindow::keys = NULL; db_x509req *MainWindow::reqs = NULL; db_x509 *MainWindow::certs = NULL; db_temp *MainWindow::temps = NULL; db_crl *MainWindow::crls = NULL; NIDlist *MainWindow::eku_nid = NULL; NIDlist *MainWindow::dn_nid = NULL; QString MainWindow::mandatory_dn; QString MainWindow::explicit_dn; QString MainWindow::explicit_dn_default = QString("C,ST,L,O,OU,CN,emailAddress"); OidResolver *MainWindow::resolver = NULL; void MainWindow::enableTokenMenu(bool enable) { foreach(QWidget *w, scardList) { w->setEnabled(enable); } } void MainWindow::load_engine() { try { pkcs11::load_libs(pkcs11path, false); } catch (errorEx &err) { Error(err); } enableTokenMenu(pkcs11::loaded()); } void MainWindow::initResolver() { bool shown = false; QString search; if (resolver) { shown = resolver->isVisible(); search = resolver->input->text(); delete resolver; } resolver = new OidResolver(NULL); resolver->setWindowTitle(XCA_TITLE); if (shown) resolver->searchOid(search); } MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent) { dbindex = new QLabel(); dbindex->setFrameStyle(QFrame::Plain | QFrame::NoFrame); dbindex->setMargin(6); dn_translations_setup(); statusBar()->addWidget(dbindex, 1); setupUi(this); setWindowTitle(XCA_TITLE); initResolver(); wdList << keyButtons << reqButtons << certButtons << tempButtons << crlButtons; historyMenu = NULL; init_menu(); setItemEnabled(false); init_images(); homedir = getHomeDir(); #ifdef MDEBUG CRYPTO_malloc_debug_init(); CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); fprintf(stderr, "malloc() debugging on.\n"); #endif ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); EVP_add_digest_alias(SN_sha1,SN_ecdsa_with_SHA1); EVP_add_digest_alias(SN_sha224,SN_ecdsa_with_SHA224); EVP_add_digest_alias(SN_sha256,SN_ecdsa_with_SHA256); EVP_add_digest_alias(SN_sha256,SN_dsa_with_SHA256); EVP_add_digest_alias(SN_sha384,SN_ecdsa_with_SHA384); EVP_add_digest_alias(SN_sha512,SN_ecdsa_with_SHA512); /* read in all our own OIDs */ initOIDs(); eku_nid = read_nidlist("eku.txt"); dn_nid = read_nidlist("dn.txt"); setAcceptDrops(true); searchEdit = new QLineEdit(); searchEdit->setPlaceholderText(tr("Search")); keyView->setMainwin(this, searchEdit); reqView->setMainwin(this, searchEdit); certView->setMainwin(this, searchEdit); tempView->setMainwin(this, searchEdit); crlView->setMainwin(this, searchEdit); } void MainWindow::dropEvent(QDropEvent *event) { QList urls = event->mimeData()->urls(); QUrl u; QStringList files; foreach(u, urls) { QString s = u.toLocalFile(); files << s; } openURLs(files); event->acceptProposedAction(); } void MainWindow::openURLs(QStringList &files) { urlsToOpen = files; QTimer::singleShot(100, this, SLOT(openURLs())); } void MainWindow::openURLs() { QStringList failed; QString s; ImportMulti *dlgi = new ImportMulti(this); foreach(s, urlsToOpen) { pki_multi *pki = probeAnything(s); if (pki && !pki->count()) failed << s; dlgi->addItem(pki); } urlsToOpen.clear(); dlgi->execute(1, failed); delete dlgi; } void MainWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasUrls()) event->acceptProposedAction(); } void MainWindow::setItemEnabled(bool enable) { foreach(QWidget *w, wdList) { w->setEnabled(enable); } foreach(QWidget *w, wdMenuList) { w->setEnabled(enable); } foreach(QAction *a, acList) { a->setEnabled(enable); } enableTokenMenu(pkcs11::loaded()); } /* creates a new nid list from the given filename */ NIDlist *MainWindow::read_nidlist(QString name) { NIDlist nl; name = QDir::separator() + name; /* first try $HOME/xca/ */ nl = readNIDlist(getUserSettingsDir() + name); #if !defined(Q_OS_WIN32) #if !defined(Q_OS_MAC) if (nl.count() == 0){ /* next is /etx/xca/... */ nl = readNIDlist(QString(ETC) + name); } #endif #endif if (nl.count() == 0) { /* look at /usr/(local/)share/xca/ */ nl = readNIDlist(getPrefix() + name); } return new NIDlist(nl); } void MainWindow::init_images() { keyImg = loadImg("bigkey.png"); csrImg = loadImg("bigcsr.png"); certImg = loadImg("bigcert.png"); tempImg = loadImg("bigtemp.png"); nsImg = loadImg("netscape.png"); revImg = loadImg("bigcrl.png"); scardImg = loadImg("bigscard.png"); appIco = loadImg("key.xpm"); doneIco = loadImg("done.png"); warnIco = loadImg("warn.png"); bigKey->setPixmap(*keyImg); bigCsr->setPixmap(*csrImg); bigCert->setPixmap(*certImg); bigTemp->setPixmap(*tempImg); bigRev->setPixmap(*revImg); setWindowIcon(*appIco); pki_evp::icon[0] = loadImg("key.png"); pki_evp::icon[1] = loadImg("halfkey.png"); pki_scard::icon[0] = loadImg("scard.png"); pki_x509req::icon[0] = loadImg("req.png"); pki_x509req::icon[1] = loadImg("reqkey.png"); pki_x509req::icon[2] = loadImg("spki.png"); pki_x509req::icon[3] = doneIco; pki_x509::icon[0] = loadImg("validcert.png"); pki_x509::icon[1] = loadImg("validcertkey.png"); pki_x509::icon[2] = loadImg("invalidcert.png"); pki_x509::icon[3] = loadImg("invalidcertkey.png"); pki_x509::icon[4] = doneIco; pki_temp::icon = loadImg("template.png"); pki_crl::icon = loadImg("crl.png"); } void MainWindow::read_cmdline(int argc, char *argv[]) { int cnt = 1, opt = 0, force_load = 0, export_index = 0; char *arg = NULL; exitApp = 0; QStringList failed; ImportMulti *dlgi = new ImportMulti(this); while (cnt < argc) { arg = argv[cnt]; if (arg[0] == '-') { // option opt = 1; switch (arg[1]) { case 'c': case 'r': case 'k': case 'p': case '7': case 'l': case 't': case 'P': break; case 'd': force_load=1; break; case 'i': export_index=1; break; case 'I': export_index=2; break; case 'v': cmd_version(); opt=0; break; case 'x': exitApp = 1; opt=0; break; case 'h': cmd_help(NULL); opt=0; break; default: cmd_help(CCHAR(tr("no such option: %1").arg(arg))); } if (arg[2] != '\0' && opt==1) { arg+=2; } else { cnt++; continue; } } QString file = filename2QString(arg); if (force_load) { if (changeDB(file) == 2) exitApp = 1; force_load = 0; } else if (export_index) { if (exportIndex(file, (export_index == 2)) == 2) exitApp = 1; export_index = 0; } else { int ret; pki_multi *pki = probeAnything(file, &ret); if (!pki && ret == 2) exitApp = 1; if (pki && !pki->count()) failed << file; dlgi->addItem(pki); } cnt++; } dlgi->execute(1, failed); /* force showing of import dialog */ if (dlgi->result() == QDialog::Rejected) exitApp = 1; delete dlgi; } void MainWindow::loadPem() { load_pem l; if (keys) keys->load_default(l); } bool MainWindow::pastePem(QString text) { bool success = false; QByteArray pemdata = text.toLatin1(); if (pemdata.size() == 0) return false; pki_multi *pem = NULL; ImportMulti *dlgi = NULL; try { pem = new pki_multi(); dlgi = new ImportMulti(this); pem->fromPEMbyteArray(pemdata, QString("paste")); success = pem->count() != 0; dlgi->addItem(pem); pem = NULL; dlgi->execute(1); } catch (errorEx &err) { Error(err); } if (dlgi) delete dlgi; if (pem) delete pem; return success; } void MainWindow::pastePem() { Ui::About ui; QClipboard *cb = QApplication::clipboard(); QString text; text = cb->text(QClipboard::Selection); if (text.isEmpty()) text = cb->text(QClipboard::Clipboard); if (!text.isEmpty()) if (pastePem(text)) return; QDialog *input = new QDialog(this, 0); ui.setupUi(input); delete ui.textbox; QTextEdit *textbox = new QTextEdit(input); ui.vboxLayout->addWidget(textbox); ui.button->setText(tr("Import PEM data")); input->setWindowTitle(XCA_TITLE); textbox->setPlainText(text); if (input->exec()) { text = textbox->toPlainText(); if (!text.isEmpty()) pastePem(text); } delete input; } void MainWindow::initToken() { bool ok; if (!pkcs11::loaded()) return; try { pkcs11 p11; slotid slot; Passwd pin; int ret; if (!p11.selectToken(&slot, this)) return; tkInfo ti = p11.tokenInfo(slot); QString slotname = QString("%1 (#%2)"). arg(ti.label()).arg(ti.serial()); pass_info p(XCA_TITLE, tr("Please enter the original SO PIN (PUK) of the token '%1'"). arg(slotname) + "\n" + ti.pinInfo()); p.setPin(); if (ti.tokenInitialized()) { ret = PwDialog::execute(&p, &pin, false); } else { p.setDescription(tr("Please enter the new SO PIN (PUK) for the token '%1'"). arg(slotname) + "\n" + ti.pinInfo()); ret = PwDialog::execute(&p, &pin, true); } if (ret != 1) return; QString label = QInputDialog::getText(this, XCA_TITLE, tr("The new label of the token '%1'"). arg(slotname), QLineEdit::Normal, QString(), &ok); if (!ok) return; p11.initToken(slot, pin.constUchar(), pin.size(), label); } catch (errorEx &err) { Error(err); } } void MainWindow::changePin(bool so) { if (!pkcs11::loaded()) return; try { pkcs11 p11; slotid slot; if (!p11.selectToken(&slot, this)) return; p11.changePin(slot, so); } catch (errorEx &err) { Error(err); } } void MainWindow::changeSoPin() { changePin(true); } void MainWindow::initPin() { if (!pkcs11::loaded()) return; try { pkcs11 p11; slotid slot; if (!p11.selectToken(&slot, this)) return; p11.initPin(slot); } catch (errorEx &err) { Error(err); } } void MainWindow::manageToken() { pkcs11 p11; slotid slot; pki_scard *card = NULL; pki_x509 *cert = NULL; ImportMulti *dlgi = NULL; if (!pkcs11::loaded()) return; try { if (!p11.selectToken(&slot, this)) return; ImportMulti *dlgi = new ImportMulti(this); dlgi->tokenInfo(slot); QList objects; QList ml = p11.mechanismList(slot); if (ml.count() == 0) ml << CKM_SHA1_RSA_PKCS; pk11_attlist atts(pk11_attr_ulong(CKA_CLASS, CKO_PUBLIC_KEY)); p11.startSession(slot); p11.getRandom(); objects = p11.objectList(atts); for (int j=0; j< objects.count(); j++) { card = new pki_scard(""); try { card->load_token(p11, objects[j]); card->setMech_list(ml); dlgi->addItem(card); } catch (errorEx &err) { Error(err); delete card; } card = NULL; } atts.reset(); atts << pk11_attr_ulong(CKA_CLASS, CKO_CERTIFICATE) << pk11_attr_ulong(CKA_CERTIFICATE_TYPE,CKC_X_509); objects = p11.objectList(atts); for (int j=0; j< objects.count(); j++) { cert = new pki_x509(""); try { cert->load_token(p11, objects[j]); cert->setTrust(2); dlgi->addItem(cert); } catch (errorEx &err) { Error(err); delete cert; } cert = NULL; } if (dlgi->entries() == 0) { tkInfo ti = p11.tokenInfo(); XCA_INFO(tr("The token '%1' did not contain any keys or certificates").arg(ti.label())); } else { dlgi->execute(true); } } catch (errorEx &err) { Error(err); } if (card) delete card; if (cert) delete cert; if (dlgi) delete dlgi; } MainWindow::~MainWindow() { close_database(); ERR_free_strings(); EVP_cleanup(); OBJ_cleanup(); if (eku_nid) delete eku_nid; if (dn_nid) delete dn_nid; delete dbindex; #ifdef MDEBUG fprintf(stderr, "Memdebug:\n"); CRYPTO_mem_leaks_fp(stderr); #endif } void MainWindow::closeEvent(QCloseEvent *e) { if (resolver) { delete resolver; } QMainWindow::closeEvent(e); } QString makeSalt(void) { unsigned char rand[2]; char saltbuf[10]; Entropy::get(rand, 2); snprintf(saltbuf, 10, "S%02X%02X", rand[0], rand[1]); return QString(saltbuf); } int MainWindow::checkOldGetNewPass(Passwd &pass) { QString passHash; db mydb(dbfile); if (!mydb.find(setting, "pwhash")) { char *cpass; pass_info p(tr("Current Password"), tr("Please enter the current database password"), this); if ((cpass = (char *)mydb.load(NULL))) { passHash = cpass; free(cpass); } /* Try empty password */ if (pki_evp::sha512passwd(pass, passHash) != passHash) { /* Not the empty password, check it */ if (PwDialog::execute(&p, &pass, false) != 1) return 0; } if (pki_evp::sha512passwd(pass, passHash) != passHash) { XCA_WARN(tr("The entered password is wrong")); return 0; } } pass_info p(tr("New Password"), tr("Please enter the new password " "to encrypt your private keys in the database-file"), this); return PwDialog::execute(&p, &pass, true) != 1 ? 0 : 1; } void MainWindow::changeDbPass() { Passwd pass; QString tempn = dbfile + "{recrypt}"; if (!checkOldGetNewPass(pass)) return; try { if (!QFile::copy(dbfile, tempn)) throw errorEx("Could not create temporary file: " + tempn); QString passhash = updateDbPassword(tempn, pass); QFile new_file(tempn); /* closing the database erases 'dbfile' */ QString dbfile_bkup = dbfile; close_database(); db mydb(dbfile_bkup); if (mydb.mv(new_file)) throw errorEx(QString("Failed to rename %1 to %2"). arg(tempn).arg(dbfile_bkup)); dbfile = dbfile_bkup; pki_evp::passHash = passhash; pki_evp::passwd = pass; init_database(); } catch (errorEx &ex) { QFile::remove(tempn); Error(ex); } } QString MainWindow::updateDbPassword(QString newdb, Passwd pass) { db mydb(newdb); QString salt = makeSalt(); QString passhash = pki_evp::sha512passwd(pass, salt); mydb.set((const unsigned char *)CCHAR(passhash), passhash.length()+1, 1, setting, "pwhash"); QList klist; mydb.first(); while (mydb.find(asym_key, QString()) == 0) { QString s; pki_evp *key; unsigned char *p; db_header_t head; p = mydb.load(&head); if (!p) throw errorEx("Failed to load item"); key = new pki_evp(); if (key->getVersion() < head.version) { int v = key->getVersion(); free(p); delete key; throw errorEx(QString("Item[%1]: Version %2 " "> known version: %3 -> ignored") .arg(head.name).arg(head.version).arg(v) ); } key->setIntName(QString::fromUtf8(head.name)); try { key->fromData(p, &head); } catch (errorEx &err) { err.appendString(key->getIntName()); free(p); delete key; throw err; } free(p); if (key && key->getOwnPass() == pki_key::ptCommon && !key->isPubKey()) { EVP_PKEY *evp = key->decryptKey(); key->set_evp_key(evp); key->encryptKey(pass.constData()); klist << key; } else if (key) delete key; if (mydb.next()) break; } for (int i=0; i< klist.count(); i++) { pki_evp *key = klist[i]; QByteArray ba = key->toData(); mydb.set((const unsigned char*)ba.constData(), ba.count(), key->getVersion(), key->getType(), key->getIntName()); delete key; } return passhash; } int MainWindow::initPass() { db mydb(dbfile); char *pass; pki_evp::passHash = QString(); QString salt; int ret; pass_info p(tr("New Password"), tr("Please enter a password, " "that will be used to encrypt your private keys " "in the database file:\n%1"). arg(compressFilename(dbfile)), this); if (!mydb.find(setting, "pwhash")) { if ((pass = (char *)mydb.load(NULL))) { pki_evp::passHash = pass; free(pass); } } if (pki_evp::passHash.isEmpty()) { ret = PwDialog::execute(&p, &pki_evp::passwd, true, true); if (ret != 1) return ret; salt = makeSalt(); pki_evp::passHash = pki_evp::sha512passwd(pki_evp::passwd,salt); mydb.set((const unsigned char *)CCHAR(pki_evp::passHash), pki_evp::passHash.length()+1, 1, setting, "pwhash"); } else { ret = 0; while (pki_evp::sha512passwd(pki_evp::passwd, pki_evp::passHash) != pki_evp::passHash) { if (ret) XCA_WARN( tr("Password verify error, please try again")); p.setTitle(tr("Password")); p.setDescription(tr("Please enter the password for unlocking the database:\n%1").arg(compressFilename(dbfile))); ret = PwDialog::execute(&p, &pki_evp::passwd, false, true); if (ret != 1) { pki_evp::passwd = QByteArray(); return ret; } if (pki_evp::passHash.left(1) == "S") continue; /* Start automatic update from md5 to salted sha512 * if the password is correct. my md5 hash does not * start with 'S', while my new hash does. */ if (pki_evp::md5passwd(pki_evp::passwd) == pki_evp::passHash ) { salt = makeSalt(); pki_evp::passHash = pki_evp::sha512passwd( pki_evp::passwd, salt); mydb.set((const unsigned char *)CCHAR( pki_evp::passHash), pki_evp::passHash.length() +1, 1, setting, "pwhash"); } } } if (pki_evp::passwd.isNull()) pki_evp::passwd = ""; return 1; } void MainWindow::Error(errorEx &err) { if (err.isEmpty()) return; QString msg = tr("The following error occurred:") + "\n" + err.getString(); xcaWarning box(NULL, msg); box.addButton(QMessageBox::Apply)->setText(tr("Copy to Clipboard")); box.addButton(QMessageBox::Ok); if (box.exec() == QMessageBox::Apply) { QClipboard *cb = QApplication::clipboard(); cb->setText(msg); if (cb->supportsSelection()) cb->setText(msg, QClipboard::Selection); } } QString MainWindow::getPath() { return workingdir; } void MainWindow::setPath(QString str) { db mydb(dbfile); workingdir = str; mydb.set((const unsigned char *)CCHAR(str), str.length()+1, 1, setting, "workingdir"); } void MainWindow::setDefaultKey(QString str) { db mydb(dbfile); mydb.set((const unsigned char *)CCHAR(str), str.length()+1, 1, setting, "defaultkey"); } void MainWindow::connNewX509(NewX509 *nx) { connect( nx, SIGNAL(genKey(QString)), keys, SLOT(newItem(QString)) ); connect( keys, SIGNAL(keyDone(QString)), nx, SLOT(newKeyDone(QString)) ); connect( nx, SIGNAL(showReq(QString)), reqs, SLOT(showItem(QString))); } void MainWindow::importAnything(QString file) { ImportMulti *dlgi = new ImportMulti(this); QStringList failed; pki_multi *pki = probeAnything(file); if (pki && !pki->count()) failed << file; dlgi->addItem(pki); dlgi->execute(1, failed); delete dlgi; } pki_multi *MainWindow::probeAnything(QString file, int *ret) { pki_multi *pki = new pki_multi(); try { if (file.endsWith(".xdb")) { try { int r; db *mydb = new db(file); mydb->verify_magic(); delete mydb; r = changeDB(file); delete pki; if (ret) *ret = r; return NULL; } catch (errorEx &err) { } } pki->probeAnything(file); } catch (errorEx &err) { Error(err); } return pki; } void MainWindow::exportIndex() { exportIndex(NULL, false); } void MainWindow::exportIndexHierarchy() { exportIndex(NULL, true); } int MainWindow::exportIndex(QString fname, bool hierarchy) { if (fname == NULL || fname.isEmpty()) { QString filter = tr("Certificate Index ( index.txt )") + ";;" + tr("All files ( * )"); fname = QFileDialog::getSaveFileName(this, QString(), fname, filter, NULL); if (fname.isEmpty()) return 1; nativeSeparator(fname); } if (certs == NULL) { open_default_db(); if (certs == NULL) return 2; } bool needChangeView = hierarchy && !certs->treeview; if (needChangeView) { certView->changeView(); } certs->writeIndex(fname, hierarchy); if (needChangeView) { certView->changeView(); } return 0; } void MainWindow::generateDHparam() { DH *dh = NULL; FILE *fp = NULL; QProgressBar *bar = NULL; bool ok; int num = QInputDialog::getDouble(this, XCA_TITLE, tr("Diffie-Hellman parameters are needed for different applications, but not handled by XCA.\nPlease enter the DH parameter bits"), 1024, 1024, 4096, 0, &ok); #if OPENSSL_VERSION_NUMBER >= 0x10100000L BN_GENCB *cb = NULL; #endif if (!ok) return; /* * 1024: 6 sec * 2048: 38 sec * 4096: 864 sec */ Entropy::seed_rng(); try { QStatusBar *status = statusBar(); bar = new QProgressBar(); check_oom(bar); bar->setMinimum(0); bar->setMaximum(100); status->addPermanentWidget(bar, 1); #if OPENSSL_VERSION_NUMBER >= 0x10100000L cb = BN_GENCB_new(); if (!cb) throw errorEx(""); BN_GENCB_set_old(cb, inc_progress_bar, bar); dh = DH_new(); DH_generate_parameters_ex(dh, num, 2, cb); #else dh = DH_generate_parameters(num, 2, inc_progress_bar, bar); #endif status->removeWidget(bar); openssl_error(); QString fname = QString("%1/dh%2.pem").arg(homedir).arg(num); fname = QFileDialog::getSaveFileName(this, QString(), fname, "All files ( * )", NULL); if (fname == "") throw errorEx(""); fp = fopen_write(fname); if (fp == NULL) { throw errorEx(tr("Error opening file: '%1': %2"). arg(fname).arg(strerror(errno))); } PEM_write_DHparams(fp, dh); openssl_error(); } catch (errorEx &err) { Error(err); } if (dh) DH_free(dh); if (fp) fclose(fp); #if OPENSSL_VERSION_NUMBER >= 0x10100000L if (cb) BN_GENCB_free(cb); #endif if (bar) delete bar; } void MainWindow::changeEvent(QEvent *event) { if (event->type() == QEvent::LanguageChange) { QList models; retranslateUi(this); dn_translations_setup(); init_menu(); update_history_menu(); models << keys << reqs << certs << crls << temps; foreach(db_base *model, models) { if (model) model->updateHeaders(); } if (!dbfile.isEmpty()) dbindex->setText(tr("Database") + ": " + dbfile); } QMainWindow::changeEvent(event); } void MainWindow::keyPressEvent(QKeyEvent *e) { if (e->modifiers() != Qt::ControlModifier) { QMainWindow::keyPressEvent(e); return; } int siz = XCA_application::tableFont.pointSize(); QList views; switch (e->key()) { case Qt::Key_Plus: XCA_application::tableFont.setPointSize(siz +1); break; case Qt::Key_Minus: if (siz > 4) { XCA_application::tableFont.setPointSize(siz -1); } break; case Qt::Key_V: if (e->modifiers() == Qt::ControlModifier) { pastePem(); break; } /* FALLTHROUGH */ default: QMainWindow::keyPressEvent(e); return; } views << keyView << reqView << certView << crlView << tempView; foreach(XcaTreeView *v, views) { if (v) { v->header()->resizeSections( QHeaderView::ResizeToContents); v->reset(); } } update(); }