1 /* vi: set sw=4 ts=4:
2  *
3  * Copyright (C) 2001 - 2015 Christian Hohnstaedt.
4  *
5  * All rights reserved.
6  */
7 
8 
9 //#define MDEBUG
10 #include "MainWindow.h"
11 #include "XcaApplication.h"
12 #include "ImportMulti.h"
13 #include "dhgen.h"
14 
15 #include <QApplication>
16 #include <QClipboard>
17 #include <QFileDialog>
18 #include <QLabel>
19 #include <QLineEdit>
20 #include <QTextBrowser>
21 #include <QStatusBar>
22 #include <QList>
23 #include <QTimer>
24 #include <QThread>
25 #include <QMimeData>
26 #include <QInputDialog>
27 
28 #include <openssl/err.h>
29 
30 #include "lib/Passwd.h"
31 #include "lib/database_model.h"
32 #include "lib/exception.h"
33 #include "lib/pki_evp.h"
34 #include "lib/pki_multi.h"
35 #include "lib/pki_scard.h"
36 #include "XcaDialog.h"
37 #include "XcaWarning.h"
38 #include "PwDialog.h"
39 #include "OpenDb.h"
40 #include "OidResolver.h"
41 
42 OidResolver *MainWindow::resolver = NULL;
43 
enableTokenMenu(bool enable)44 void MainWindow::enableTokenMenu(bool enable)
45 {
46 	foreach(QWidget *w, scardList) {
47 		w->setEnabled(enable);
48 	}
49 }
50 
initResolver()51 void MainWindow::initResolver()
52 {
53 	bool shown = false;
54 	QString search;
55 
56 	if (resolver) {
57 		shown = resolver->isVisible();
58 		search = resolver->input->text();
59 		delete resolver;
60 	}
61 	resolver = new OidResolver(NULL);
62 	resolver->setWindowTitle(XCA_TITLE);
63 	if (shown)
64 		resolver->searchOid(search);
65 }
66 
MainWindow()67 MainWindow::MainWindow() : QMainWindow()
68 {
69 	dbindex = new QLabel();
70 	dbindex->setFrameStyle(QFrame::Plain | QFrame::NoFrame);
71 	dbindex->setMargin(6);
72 
73 	dn_translations_setup();
74 	statusBar()->addWidget(dbindex, 1);
75 
76 	setupUi(this);
77 	setWindowTitle(XCA_TITLE);
78 
79 	OpenDb::checkSqLite();
80 	initResolver();
81 
82 	wdList << keyButtons << reqButtons << certButtons <<
83 		tempButtons <<	crlButtons;
84 
85 	QStringList drivers = QSqlDatabase::drivers();
86 	foreach(QString driver, drivers) {
87 		QSqlDatabase d = QSqlDatabase::addDatabase(driver, driver +"_C");
88 		qDebug() << "DB driver:" << driver;
89 	}
90 
91 	historyMenu = NULL;
92 	helpdlg = new Help();
93 	init_menu();
94 	setItemEnabled(false);
95 
96 	init_images();
97 	homedir = getHomeDir();
98 
99 #ifdef MDEBUG
100 	CRYPTO_malloc_debug_init();
101 	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
102 	qWarning() << "malloc() debugging on.";
103 #endif
104 
105 	ERR_load_crypto_strings();
106 	OpenSSL_add_all_algorithms();
107 
108 	EVP_add_digest_alias(SN_sha1,SN_ecdsa_with_SHA1);
109 	EVP_add_digest_alias(SN_sha224,SN_ecdsa_with_SHA224);
110 	EVP_add_digest_alias(SN_sha256,SN_ecdsa_with_SHA256);
111 	EVP_add_digest_alias(SN_sha256,SN_dsa_with_SHA256);
112 	EVP_add_digest_alias(SN_sha384,SN_ecdsa_with_SHA384);
113 	EVP_add_digest_alias(SN_sha512,SN_ecdsa_with_SHA512);
114 
115 	setAcceptDrops(true);
116 
117 	searchEdit = new QLineEdit();
118 	searchEdit->setPlaceholderText(tr("Search"));
119 
120 	keyView->setIconSize(QPixmap(":keyIco").size());
121 	reqView->setIconSize(QPixmap(":reqIco").size());
122 	certView->setIconSize(QPixmap(":validcertIco").size());
123 	tempView->setIconSize(QPixmap(":templateIco").size());
124 	crlView->setIconSize(QPixmap(":crlIco").size());
125 
126 	views << keyView << reqView << certView << crlView << tempView;
127 
128 	foreach(XcaTreeView *v, views)
129 		v->setMainwin(this, searchEdit);
130 
131 	dhgen = NULL;
132 	dhgenBar = new QProgressBar();
133 	check_oom(dhgenBar);
134 	dhgenBar->setMinimum(0);
135 	dhgenBar->setMaximum(0);
136 }
137 
dropEvent(QDropEvent * event)138 void MainWindow::dropEvent(QDropEvent *event)
139 {
140 	if (event->mimeData()->hasUrls()) {
141 		QList<QUrl> urls = event->mimeData()->urls();
142 		QUrl u;
143 		QStringList files;
144 
145 		foreach(u, urls) {
146 			QString s = u.toLocalFile();
147 			files << s;
148 		}
149 		openURLs(files);
150 		event->acceptProposedAction();
151 	} else if (event->mimeData()->hasText()) {
152 		event->acceptProposedAction();
153 		pastePem(event->mimeData()->text());
154 	}
155 }
156 
openURLs(QStringList & files)157 void MainWindow::openURLs(QStringList &files)
158 {
159 	urlsToOpen = files;
160 	QTimer::singleShot(100, this, SLOT(openURLs()));
161 }
162 
openURLs()163 void MainWindow::openURLs()
164 {
165 	foreach(QString file, urlsToOpen) {
166 		if (file.endsWith(".xdb") ||
167 		    !database_model::splitRemoteDbName(file).isEmpty())
168 		{
169 			init_database(file);
170 			if (Database.isOpen()) {
171 				urlsToOpen.removeAll(file);
172 				break;
173 			}
174 		}
175 	}
176 	importAnything(urlsToOpen);
177 	urlsToOpen.clear();
178 }
179 
dragEnterEvent(QDragEnterEvent * event)180 void MainWindow::dragEnterEvent(QDragEnterEvent *event)
181 {
182 	if (event->mimeData()->hasFormat(X_XCA_DRAG_DATA))
183 		return;
184 
185 	if (event->mimeData()->hasUrls() || event->mimeData()->hasText())
186 		event->acceptProposedAction();
187 }
188 
setItemEnabled(bool enable)189 void MainWindow::setItemEnabled(bool enable)
190 {
191 	foreach(QWidget *w, wdList) {
192 		w->setEnabled(enable);
193 	}
194 	foreach(QWidget *w, wdMenuList) {
195 		w->setEnabled(enable);
196 	}
197 	foreach(QAction *a, acList) {
198 		a->setEnabled(enable);
199 	}
200 	enableTokenMenu(pkcs11::libraries.loaded());
201 }
202 
init_images()203 void MainWindow::init_images()
204 {
205 	bigKey->setPixmap(QPixmap(":keyImg"));
206 	bigCsr->setPixmap(QPixmap(":csrImg"));
207 	bigCert->setPixmap(QPixmap(":certImg"));
208 	bigTemp->setPixmap(QPixmap(":tempImg"));
209 	bigRev->setPixmap(QPixmap(":revImg"));
210 	setWindowIcon(QPixmap(":appIco"));
211 }
212 
loadPem()213 void MainWindow::loadPem()
214 {
215 	load_pem l;
216 	db_key *keys = Database.model<db_key>();
217 	if (keys)
218 		keys->load_default(l);
219 }
220 
pastePem(QString text,bool silent)221 bool MainWindow::pastePem(QString text, bool silent)
222 {
223 	bool success = false;
224 	QByteArray pemdata = text.toLatin1();
225 	if (pemdata.size() == 0)
226 		return false;
227 
228 	pki_multi *pem = NULL;
229 	try {
230 		pem = new pki_multi();
231 		pem->fromPEMbyteArray(pemdata, QString());
232 		success = pem->failed_files.count() == 0;
233 		importMulti(pem, 1);
234 	}
235 	catch (errorEx &err) {
236 		delete pem;
237 		if (!silent)
238 			XCA_ERROR(err);
239 	}
240 	return success;
241 }
242 
pastePem()243 void MainWindow::pastePem()
244 {
245 	QClipboard *cb = QApplication::clipboard();
246 	QString text;
247 
248 	text = cb->text(QClipboard::Selection);
249 	if (text.isEmpty())
250 		text = cb->text(QClipboard::Clipboard);
251 
252 	if (!text.isEmpty())
253 		if (pastePem(text, true))
254 			return;
255 
256 
257 	QTextEdit *textbox = new QTextEdit();
258 	textbox->setPlainText(text);
259 	XcaDialog *input = new XcaDialog(this, x509, textbox,
260 			tr("Import PEM data"), QString());
261 	input->noSpacer();
262 	if (input->exec()) {
263 		text = textbox->toPlainText();
264 		if (!text.isEmpty())
265 			pastePem(text);
266 	}
267 	delete input;
268 }
269 
initToken()270 void MainWindow::initToken()
271 {
272 	bool ok;
273 	if (!pkcs11::libraries.loaded())
274 		return;
275 	try {
276 		pkcs11 p11;
277 		slotid slot;
278 		Passwd pin;
279 		int ret;
280 
281 		if (!p11.selectToken(&slot, this))
282 			return;
283 
284 		tkInfo ti = p11.tokenInfo(slot);
285 		QString slotname = QString("%1 (#%2)").
286 			arg(ti.label()).arg(ti.serial());
287 
288 		pass_info p(XCA_TITLE,
289 			tr("Please enter the original SO PIN (PUK) of the token '%1'").
290 			arg(slotname) + "\n" + ti.pinInfo());
291 		p.setPin();
292 		if (ti.tokenInitialized()) {
293 			ret = PwDialog::execute(&p, &pin, false);
294 		} else {
295 			p.setDescription(tr("Please enter the new SO PIN (PUK) for the token '%1'").
296 			arg(slotname) + "\n" + ti.pinInfo());
297 			ret = PwDialog::execute(&p, &pin, true);
298 		}
299 		if (ret != 1)
300 			return;
301 		QString label = QInputDialog::getText(this, XCA_TITLE,
302 			tr("The new label of the token '%1'").
303 			arg(slotname), QLineEdit::Normal, QString(), &ok);
304 		if (!ok)
305 			return;
306 		p11.initToken(slot, pin.constUchar(), pin.size(), label);
307 	} catch (errorEx &err) {
308 		XCA_ERROR(err);
309         }
310 }
311 
changePin(bool so)312 void MainWindow::changePin(bool so)
313 {
314 	if (!pkcs11::libraries.loaded())
315 		return;
316 	try {
317 		pkcs11 p11;
318 		slotid slot;
319 
320 		if (!p11.selectToken(&slot, this))
321 			return;
322 		p11.changePin(slot, so);
323 	} catch (errorEx &err) {
324 		XCA_ERROR(err);
325         }
326 }
327 
changeSoPin()328 void MainWindow::changeSoPin()
329 {
330 	changePin(true);
331 }
332 
initPin()333 void MainWindow::initPin()
334 {
335 	if (!pkcs11::libraries.loaded())
336 		return;
337 	try {
338 		pkcs11 p11;
339 		slotid slot;
340 
341 		if (!p11.selectToken(&slot, this))
342 			return;
343 		p11.initPin(slot);
344 	} catch (errorEx &err) {
345 		XCA_ERROR(err);
346         }
347 }
348 
349 
manageToken()350 void MainWindow::manageToken()
351 {
352 	pkcs11 p11;
353 	slotid slot;
354 	pki_scard *card = NULL;
355 	pki_x509 *cert = NULL;
356 	ImportMulti *dlgi = NULL;
357 
358 	if (!pkcs11::libraries.loaded())
359 		return;
360 
361 	try {
362 		if (!p11.selectToken(&slot, this))
363 			return;
364 
365 		ImportMulti *dlgi = new ImportMulti(this);
366 
367 		dlgi->tokenInfo(slot);
368 		QList<CK_OBJECT_HANDLE> objects;
369 
370 		QList<CK_MECHANISM_TYPE> ml = p11.mechanismList(slot);
371 		if (ml.count() == 0)
372 			ml << CKM_SHA1_RSA_PKCS;
373 		pk11_attlist atts(pk11_attr_ulong(CKA_CLASS,
374 				CKO_PUBLIC_KEY));
375 
376 		p11.startSession(slot);
377 		p11.getRandom();
378 		objects = p11.objectList(atts);
379 
380 		for (int j=0; j< objects.count(); j++) {
381 			card = new pki_scard("");
382 			try {
383 				card->load_token(p11, objects[j]);
384 				card->setMech_list(ml);
385 				dlgi->addItem(card);
386 			} catch (errorEx &err) {
387 				XCA_ERROR(err);
388 				delete card;
389 			}
390 			card = NULL;
391 		}
392 		atts.reset();
393 		atts << pk11_attr_ulong(CKA_CLASS, CKO_CERTIFICATE) <<
394 			pk11_attr_ulong(CKA_CERTIFICATE_TYPE,CKC_X_509);
395 		objects = p11.objectList(atts);
396 
397 		for (int j=0; j< objects.count(); j++) {
398 			cert = new pki_x509("");
399 			try {
400 				cert->load_token(p11, objects[j]);
401 				dlgi->addItem(cert);
402 			} catch (errorEx &err) {
403 				XCA_ERROR(err);
404 				delete cert;
405 			}
406 			cert = NULL;
407 		}
408 		if (dlgi->entries() == 0) {
409 			tkInfo ti = p11.tokenInfo();
410 			XCA_INFO(tr("The token '%1' did not contain any keys or certificates").arg(ti.label()));
411 		} else {
412 			dlgi->execute(true);
413 		}
414 	} catch (errorEx &err) {
415 		XCA_ERROR(err);
416         }
417 	delete card;
418 	delete cert;
419 	delete dlgi;
420 }
421 
~MainWindow()422 MainWindow::~MainWindow()
423 {
424 	ERR_free_strings();
425 	EVP_cleanup();
426 	OBJ_cleanup();
427 	delete dbindex;
428 	delete helpdlg;
429 #ifdef MDEBUG
430 	fprintf(stderr, "Memdebug:\n");
431 	CRYPTO_mem_leaks_fp(stderr);
432 #endif
433 }
434 
closeEvent(QCloseEvent * e)435 void MainWindow::closeEvent(QCloseEvent *e)
436 {
437 	if (dhgen) {
438 		if (!XCA_YESNO("Abort Diffie-Hellmann parameter generation?")){
439 			e->ignore();
440 			return;
441 		}
442 		dhgen->terminate();
443 	}
444 	delete resolver;
445 	resolver = NULL;
446 	delete helpdlg;
447 	helpdlg = NULL;
448 	close_database();
449 	QMainWindow::closeEvent(e);
450 }
451 
checkOldGetNewPass(Passwd & pass)452 int MainWindow::checkOldGetNewPass(Passwd &pass)
453 {
454 	QString passHash = Settings["pwhash"];
455 	if (!passHash.isEmpty()) {
456 		pass_info p(tr("Current Password"),
457 			tr("Please enter the current database password"), this);
458 
459 		/* Try empty password */
460 		if (pki_evp::sha512passwT(pass, passHash) != passHash) {
461 			/* Not the empty password, check it */
462 			if (PwDialog::execute(&p, &pass, false) != 1)
463 				return 0;
464 		}
465 
466 		if (pki_evp::sha512passwT(pass, passHash) != passHash) {
467 			XCA_WARN(tr("The entered password is wrong"));
468 			return 0;
469 		}
470 	}
471 
472 	pass_info p(tr("New Password"), tr("Please enter the new password "
473 			"to encrypt your private keys in the database-file"),
474 			this);
475 
476 	return PwDialog::execute(&p, &pass, true) != 1 ? 0 : 1;
477 }
478 
changeDbPass()479 void MainWindow::changeDbPass()
480 {
481 	Passwd pass;
482 	XSqlQuery q;
483 	QSqlDatabase db = QSqlDatabase::database();
484 
485 	if (!checkOldGetNewPass(pass))
486 		return;
487 
488 	QString salt = Entropy::makeSalt();
489 	QString passhash = pki_evp::sha512passwT(pass, salt);
490 	QList<pki_evp*> key_list = Store.sqlSELECTpki<pki_evp>(
491 		"SELECT item FROM private_keys WHERE ownPass=0");
492 
493 	try {
494 		Transaction;
495 		if (!TransBegin()) {
496 			errorEx e(tr("Transaction start failed"));
497 			XCA_ERROR(e);
498 			return;
499 		}
500 		foreach(pki_evp *key, key_list) {
501 			EVP_PKEY *evp = key->decryptKey();
502 			key->set_evp_key(evp);
503 			key->encryptKey(pass.constData());
504 			key->sqlUpdatePrivateKey();
505 		}
506 		Settings["pwhash"] = passhash;
507 		TransCommit();
508 		pki_evp::passHash = passhash;
509 		pki_evp::passwd = pass;
510 	} catch (errorEx &e) {
511 		XCA_ERROR(e);
512 	}
513 }
514 
importAnything(QString file)515 void MainWindow::importAnything(QString file)
516 {
517 	importAnything(QStringList(file));
518 }
519 
importAnything(const QStringList & files)520 void MainWindow::importAnything(const QStringList &files)
521 {
522 	pki_multi *multi = new pki_multi();
523 
524 	foreach(QString s, files)
525 		multi->probeAnything(s);
526 
527 	importMulti(multi, 1);
528 }
529 
importMulti(pki_multi * multi,int force)530 void MainWindow::importMulti(pki_multi *multi, int force)
531 {
532 	if (!multi)
533 		return;
534 
535 	QStringList failed_files = multi->failed_files;
536 	ImportMulti *dlgi = new ImportMulti(this);
537 
538 	// dlgi->addItem() deletes "multi" if appropriate
539 	dlgi->addItem(multi);
540 	dlgi->execute(force, failed_files);
541 	delete dlgi;
542 }
543 
openRemoteSqlDB()544 void MainWindow::openRemoteSqlDB()
545 {
546 	OpenDb *opendb = new OpenDb(this, QString());
547 	QString descriptor;
548 	Passwd pass;
549 	DbMap params;
550 
551 	if (opendb->exec()) {
552 		descriptor = opendb->getDescriptor();
553 		pass = opendb->dbPassword->text().toLatin1();
554 		params = database_model::splitRemoteDbName(descriptor);
555 	}
556 	delete opendb;
557 
558 	if (descriptor.isEmpty())
559 		return;
560 
561 	init_database(descriptor, pass);
562 }
563 
init_database(const QString & name,const Passwd & pass)564 enum open_result MainWindow::init_database(const QString &name,
565 					   const Passwd &pass)
566 {
567 	close_database();
568 	try {
569 		Database.open(name, pass);
570 		return setup_open_database();
571 	} catch (errorEx &err) {
572 		XCA_ERROR(err);
573 		return open_abort;
574 	} catch (enum open_result r) {
575 		return r;
576 	}
577 	return pw_ok;
578 }
579 
setup_open_database()580 enum open_result MainWindow::setup_open_database()
581 {
582 	if (!Database.isOpen())
583 		return open_abort;
584 
585 	if (!database_model::isRemoteDB(Database.name()))
586 		homedir = QFileInfo(Database.name()).canonicalPath();
587 
588 	setItemEnabled(true);
589 	dbindex->setText(tr("Database") + ": " +
590 			 compressFilename(Database.name()));
591 	set_geometry(Settings["mw_geometry"]);
592 
593 	if (pki_evp::passwd.isNull())
594 		XCA_INFO(tr("Using or exporting private keys will not be possible without providing the correct password"));
595 
596 	enableTokenMenu(pkcs11::libraries.loaded());
597 
598 	hashBox hb(this);
599 	if (hb.isInsecure()) {
600 		XCA_WARN(tr("The currently used default hash '%1' is insecure. Please select at least 'SHA 224' for security reasons.").arg(hb.currentHashName()));
601 		setOptions();
602 	}
603 
604 	keyView->setModel(Database.model<db_key>());
605 	reqView->setModel(Database.model<db_x509req>());
606 	certView->setModel(Database.model<db_x509>());
607 	tempView->setModel(Database.model<db_temp>());
608 	crlView->setModel(Database.model<db_crl>());
609 
610 	searchEdit->setText("");
611 	searchEdit->show();
612 	statusBar()->addWidget(searchEdit, 1);
613 
614 	connect(tempView, SIGNAL(newCert(pki_temp *)),
615 		Database.model<db_x509>(), SLOT(newCert(pki_temp *)));
616 	connect(tempView, SIGNAL(newReq(pki_temp *)),
617 		Database.model<db_x509req>(), SLOT(newItem(pki_temp *)));
618 
619 	return pw_ok;
620 }
621 
set_geometry(QString geo)622 void MainWindow::set_geometry(QString geo)
623 {
624 	QStringList sl = geo.split(",");
625 	if (sl.size() != 3)
626 		return;
627 	resize(sl[0].toInt(), sl[1].toInt());
628 	int i = sl[2].toInt();
629 	if (i != -1)
630 		tabView->setCurrentIndex(i);
631 }
632 
close_database()633 void MainWindow::close_database()
634 {
635 	if (!Database.isOpen())
636 		return;
637 
638 	Settings["mw_geometry"] = QString("%1,%2,%3")
639 			.arg(size().width())
640 			.arg(size().height())
641 			.arg(tabView->currentIndex());
642 
643 	history.addEntry(Database.name());
644 	foreach(XcaTreeView *v, views)
645 		v->setModel(NULL);
646 	Database.close();
647 
648 	setItemEnabled(false);
649 	dbindex->clear();
650 	update_history_menu();
651 	enableTokenMenu(pkcs11::libraries.loaded());
652 }
653 
exportIndex()654 void MainWindow::exportIndex()
655 {
656 	exportIndex(QFileDialog::getSaveFileName(this, XCA_TITLE,
657 				Settings["workingdir"],
658 				tr("Certificate Index ( index.txt )") + ";;" +
659 					tr("All files ( * )")),
660 			false);
661 }
662 
exportIndexHierarchy()663 void MainWindow::exportIndexHierarchy()
664 {
665 	exportIndex(QFileDialog::getExistingDirectory(
666 		this, XCA_TITLE, Settings["workingdir"]), true);
667 }
668 
exportIndex(const QString & fname,bool hierarchy) const669 void MainWindow::exportIndex(const QString &fname, bool hierarchy) const
670 {
671 	qDebug() << fname << hierarchy;
672 	if (fname.isEmpty() || !Database.isOpen())
673 		return;
674 	db_x509 *certs = Database.model<db_x509>();
675 	certs->writeIndex(fname, hierarchy);
676 }
677 
generateDHparamDone()678 void MainWindow::generateDHparamDone()
679 {
680 	statusBar()->removeWidget(dhgenBar);
681 	errorEx e(dhgen->error);
682 	if (e.isEmpty())
683 		XCA_INFO(tr("Diffie-Hellman parameters saved as: %1")
684 			.arg(dhgen->filename()));
685 	else
686 		XCA_ERROR(e);
687 	dhgen->deleteLater();
688 	dhgen = NULL;
689 }
690 
generateDHparam()691 void MainWindow::generateDHparam()
692 {
693 	bool ok;
694 	int bits;
695 
696 	if (dhgen)
697 		return;
698 
699 	bits = 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"),
700 		1024, 1024, 4096, 0, &ok);
701 	if (!ok)
702 		return;
703 
704 	/*
705 	 * 1024:   6 sec
706 	 * 2048:  38 sec
707 	 * 4096: 864 sec
708 	 */
709 
710 	Entropy::seed_rng();
711 	try {
712 		QString fname = QString("%1/dh%2.pem").arg(homedir).arg(bits);
713 		fname = QFileDialog::getSaveFileName(this, QString(),
714 			fname, tr("All files ( * )"), NULL);
715 		if (fname == "")
716 			throw errorEx("");
717 		dhgen = new DHgen(fname, bits);
718 		check_oom(dhgen);
719 		statusBar()->addPermanentWidget(dhgenBar, 1);
720 		dhgenBar->show();
721 		dhgen->start(QThread::LowestPriority);
722 		connect(dhgen, SIGNAL(finished()),
723 			this, SLOT(generateDHparamDone()));
724 	} catch (errorEx &err) {
725 		XCA_ERROR(err);
726 	}
727 }
728 
changeEvent(QEvent * event)729 void MainWindow::changeEvent(QEvent *event)
730 {
731 	if (event->type() == QEvent::LanguageChange) {
732 		retranslateUi(this);
733 		dn_translations_setup();
734 		init_menu();
735 		foreach(db_base *model, Database.getModels())
736 			model->updateHeaders();
737 
738 		if (Database.isOpen())
739 			dbindex->setText(tr("Database") + ": " +
740 					Database.name());
741 		searchEdit->setPlaceholderText(tr("Search"));
742 	}
743 	QMainWindow::changeEvent(event);
744 }
745 
keyPressEvent(QKeyEvent * e)746 void MainWindow::keyPressEvent(QKeyEvent *e)
747 {
748 	if (e->modifiers() != Qt::ControlModifier) {
749 		QMainWindow::keyPressEvent(e);
750 		return;
751 	}
752 	int siz = XcaApplication::tableFont.pointSize();
753 
754 	switch (e->key()) {
755 	case Qt::Key_Plus:
756 		XcaApplication::tableFont.setPointSize(siz +1);
757 		break;
758 	case Qt::Key_Minus:
759 		if (siz > 4) {
760 			XcaApplication::tableFont.setPointSize(siz -1);
761 		}
762 		break;
763 	case Qt::Key_V:
764 		if (e->modifiers() == Qt::ControlModifier) {
765 			pastePem();
766 			break;
767 		}
768 		/* FALLTHROUGH */
769 	default:
770 		QMainWindow::keyPressEvent(e);
771 		return;
772 	}
773 	foreach(XcaTreeView *v, views) {
774 		if (v) {
775 			v->header()->resizeSections(
776 					QHeaderView::ResizeToContents);
777 			v->reset();
778 		}
779 	}
780 	update();
781 }
782 
dump_database()783 void MainWindow::dump_database()
784 {
785 	QString dirname = QFileDialog::getExistingDirectory(
786 				NULL, XCA_TITLE, Settings["workingdir"]);
787 	try {
788 		Database.dump(dirname);
789 	} catch (errorEx &err) {
790 		XCA_ERROR(err);
791 	}
792 }
793 
default_database()794 void MainWindow::default_database()
795 {
796 	Database.as_default();
797 }
798