/*
 * Copyright (C) 2014-2026 CZ.NIC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#include <QDateTime>
#include <QSslCertificate>
#include <QTimeZone>

#include "src/datovka_shared/crypto/crypto.h"
#include "src/datovka_shared/crypto/crypto_funcs.h"
#include "src/datovka_shared/crypto/crypto_wrapped.h"
#include "src/datovka_shared/isds/types.h"
#include "src/datovka_shared/log/log.h"
#include "src/datovka_shared/utility/date_time.h"
#include "src/dimensions/dimensions.h"
#include "src/global.h"
#include "src/gui/dlg_signature_detail.h"
#include "src/gui/icon_container.h"
#include "src/io/message_db.h"
#include "src/io/message_db_set.h"
#include "src/isds/message_functions.h"
#include "src/settings/prefs_specific.h"
#include "ui_dlg_signature_detail.h"

static const QString dlgName("signature_detail");

DlgSignatureDetail::DlgSignatureDetail(const QByteArray &msgDER,
    const QByteArray &tstDER, bool constructedFromDb, bool dbIsVerified,
    QWidget *parent)
    : QDialog(parent),
    m_ui(new (::std::nothrow) Ui::DlgSignatureDetail),
    m_isCMS(false),
    m_msgDER(msgDER),
    m_constructedFromDb(constructedFromDb),
    m_dbIsVerified(dbIsVerified),
    m_dlgSize(),
    m_dfltSize()
{
	m_ui->setupUi(this);
	/* Tab order is defined in UI file. */

	setIcons();

	m_ui->verifyWidget->setHidden(true);
	connect(m_ui->showVerifyDetail, SIGNAL(stateChanged(int)),
	    this, SLOT(showVerificationDetail(int)));
	m_ui->certDetailWidget->setHidden(true);
	connect(m_ui->showCertDetail, SIGNAL(stateChanged(int)),
	    this, SLOT(showCertificateDetail(int)));

	/* Store envelope timestamp. */
	TstEntries timeStamps;
	if (Q_UNLIKELY(!timeStamps.addTst(DER_XML_TST, tstDER))) {
		logErrorNL("%s", "Cannot store envelope timestamp.");
	}

	{
		const enum Isds::Type::RawType rawType = Isds::guessDataRawType(msgDER);
		switch (rawType) {
		case Isds::Type::RT_CMS_SIGNED_INCOMING_MESSAGE:
		case Isds::Type::RT_CMS_SIGNED_OUTGOING_MESSAGE:
		case Isds::Type::RT_CMS_SIGNED_DELIVERYINFO:
			m_isCMS = true;
			break;
		default:
			break;
		}
	}
	/* Read timestamps from CMS container. */
	if (m_isCMS) {
		if (Q_UNLIKELY(!timeStamps.addCmsTsts(msgDER))) {
			logErrorNL("%s", "Cannot read timestamps from CMS.");
		}
	}

	/* Read timestamp times and sort archive timestamps. */
	timeStamps.sortTimestamps();

	validateMessageSignature();
	validateSigningCertificate();
	validateMessageTimestamp(timeStamps);

	/* Remember the size of the dialogue. */
	m_dlgSize = this->sizeHint();

	m_dfltSize = this->size();
	{
		const QSize newSize = Dimensions::dialogueSize(this,
		    PrefsSpecific::dlgSize(*GlobInstcs::prefsPtr, dlgName),
		    m_dfltSize);
		if (newSize.isValid()) {
			this->resize(newSize);
		}
	}
}

DlgSignatureDetail::~DlgSignatureDetail(void)
{
	PrefsSpecific::setDlgSize(*GlobInstcs::prefsPtr,
	    dlgName, this->size(), m_dfltSize);

	delete m_ui;
}

void DlgSignatureDetail::detail(const MessageDbSet &dbSet, const MsgId &msgId,
    QWidget *parent)
{
	if (Q_UNLIKELY((msgId.dmId() < 0) || !msgId.deliveryTime().isValid())) {
		Q_ASSERT(0);
		return;
	}

	/* Obtain raw message and time stamp. */
	MessageDb *messageDb = dbSet.constAccessMessageDb(msgId.deliveryTime());
	if (Q_UNLIKELY(Q_NULLPTR == messageDb)) {
		Q_ASSERT(0);
		return;
	}
	QByteArray msgDER;
	MessageDb::MsgVerificationResult vRes =
	    messageDb->isMessageVerified(msgId.dmId());
	bool isMsgVerified = (vRes == MessageDb::MSG_SIG_OK);

	switch (vRes) {
	case MessageDb::MSG_SIG_OK:
	case MessageDb::MSG_SIG_BAD:
		msgDER = messageDb->getCompleteMessageRaw(msgId.dmId());
		break;
	default:
		logWarningNL("No complete message '%s' in the database for signature verification.",
		    QString::number(msgId.dmId()).toUtf8().constData());
		break;
	}

	QByteArray tstDER(messageDb->getMessageTimestampRaw(msgId.dmId()));

	DlgSignatureDetail dlg(msgDER, tstDER, true, isMsgVerified, parent);
	dlg.exec();
}

void DlgSignatureDetail::detail(const QByteArray &msgDER,
    const QByteArray &tstDER, QWidget *parent)
{
	DlgSignatureDetail dlg(msgDER, tstDER, false, false, parent);
	dlg.exec();
}

void DlgSignatureDetail::showCertificateDetail(int checkState)
{
	m_ui->certDetailWidget->setHidden(Qt::Unchecked == checkState);
	this->setMaximumSize(m_dlgSize);
}

void DlgSignatureDetail::showVerificationDetail(int checkState)
{
	m_ui->verifyWidget->setHidden(Qt::Unchecked == checkState);
	this->setMaximumSize(m_dlgSize);
}

#define YES \
	("<span style=\"color:#008800;\"><b>" + \
	DlgSignatureDetail::tr("Yes") + "</b></span>")
#define NO \
	("<span style=\"color:#880000;\"><b>" + \
	DlgSignatureDetail::tr("No") + "</b></span>")
#define UNAVAILABLE \
	("<span style=\"color:#f7910e;\"><b>" + \
	DlgSignatureDetail::tr("Information not available") + "</b></span>")

void DlgSignatureDetail::validateMessageSignature(void)
{
	QIcon ico;
	QString resStr;

	if (Q_UNLIKELY(m_msgDER.isEmpty() || (!m_isCMS))) {
		ico = IconContainer::construcIcon(IconContainer::ICON_APP_WARNING);
		resStr = tr("Message signature is not present.");
	} else {
		bool verified = false;

		if (m_constructedFromDb) {
			verified = m_dbIsVerified;
		} else {
			verified =
			    1 == raw_msg_verify_signature(m_msgDER.data(),
			        m_msgDER.size(), 0, 0);
		}

		if (!verified) {
			ico = IconContainer::construcIcon(
			    IconContainer::ICON_APP_ERROR);
			resStr = "<b>" + tr("Valid") + ": </b>";
			resStr += NO;
		} else {
			ico = IconContainer::construcIcon(
			    IconContainer::ICON_APP_OK);
			resStr = "<b>" + tr("Valid") + ": </b>";
			resStr += YES;
		}
	}

	m_ui->mSignatureImage->setIcon(ico);
	m_ui->mSignatureStatus->setTextFormat(Qt::RichText);
	m_ui->mSignatureStatus->setText(resStr);
}

void DlgSignatureDetail::validateSigningCertificate(void)
{
	m_ui->showCertDetail->setHidden(false);
	m_ui->showVerifyDetail->setHidden(false);

	QIcon ico;
	QString resStr;

	if (Q_UNLIKELY(m_msgDER.isEmpty() || (!m_isCMS))) {
		ico = IconContainer::construcIcon(IconContainer::ICON_APP_WARNING);
		resStr = tr("Message signature is not present.");

		m_ui->cImage->setIcon(ico);
		m_ui->cStatus->setText(resStr);

		m_ui->showCertDetail->setHidden(true);
		m_ui->showVerifyDetail->setHidden(true);

		return;
	}

	struct crt_verif_outcome cvo;

	resStr = ("<b>" + tr("Valid") + ": </b>");
	if (!signingCertValid(m_msgDER, cvo)) {
		ico = IconContainer::construcIcon(
		    IconContainer::ICON_APP_ERROR);
		resStr += NO;
	} else {
		ico = IconContainer::construcIcon(
		    IconContainer::ICON_APP_OK);
		resStr += YES;
	}

	if (!PrefsSpecific::checkCrl(*GlobInstcs::prefsPtr)) {
		resStr += " <b>(" +
		    tr("Certificate revocation check is turned off!") + ")</b>";
	}

	m_ui->cImage->setIcon(ico);
	m_ui->cStatus->setTextFormat(Qt::RichText);
	m_ui->cStatus->setText(resStr);
	m_ui->cDetail->setText(QString());

	QString saId, saName;
	QSslCertificate signingCrt = signingCert(m_msgDER, saId, saName);

	resStr.clear();
	if (!signingCrt.isNull()) {
		/* TODO -- Various check results. */
		QString checkResult;

		checkResult = crypto_certificates_loaded() ? YES : NO;
		resStr = "<b>" + tr("Trusted certificates were found") +
		    ": </b>" + checkResult + "<br/>";

#if 0
		resStr += "<b>" + tr("Signing algorithm supported") +
		    ": </b>" + "n/a<br/>";
#endif

		checkResult = cvo.parent_crt_not_found ? NO : YES;
		resStr += "<b>" + tr("Trusted parent certificate found") +
		    ": </b>" + checkResult + "<br/>";

		checkResult = cvo.time_validity_fail ? NO : YES;
		resStr += "<b>" + tr("Certificate time validity is ok") +
		    ": </b>" + checkResult + "<br/>";

		if (!PrefsSpecific::checkCrl(*GlobInstcs::prefsPtr)) {
			checkResult = UNAVAILABLE;
		} else {
			checkResult = cvo.crt_revoked ? NO : YES;
		}
		resStr += "<b>" + tr("Certificate was not revoked") +
		    ": </b>" + checkResult + "<br/>";
		if (!PrefsSpecific::checkCrl(*GlobInstcs::prefsPtr)) {
			resStr += "&nbsp;&nbsp;" "<i>" +
			    tr("Certificate revocation check is turned off!") +
			    "</i><br/>";
		}

		checkResult = cvo.crt_signature_invalid ? NO : YES;
		resStr += "<b>" + tr("Certificate signature verified") +
		    ": </b>" + checkResult + "<br/>";

		m_ui->vDetail->setTextFormat(Qt::RichText);
		m_ui->vDetail->setText(resStr);
	}

	resStr.clear();
	if (!signingCrt.isNull()) {
		QStringList strList;

		/* Certificate information. */
		resStr = "<b>" + tr("Version") + ": </b>" +
		    QString(signingCrt.version()) + "<br/>";
		resStr += "<b>" + tr("Serial number") + ": </b>" +
		    QString(signingCrt.serialNumber()) + " (" +
		    QString::number( /* Convert do decimal. */
		        ("0x" + QString(signingCrt.serialNumber()).replace(
		                    ":", "")).toUInt(0, 16), 10) + ")<br/>";
		resStr += "<b>" + tr("Signature algorithm") + ": </b>" +
		    saId + " (" + saName + ")<br/>";

		resStr += "<b>" + tr("Issuer") + ": </b><br/>";
		strList = signingCrt.issuerInfo(
		    QSslCertificate::Organization);
		if (strList.size() > 0) {
			Q_ASSERT(1 == strList.size());
			resStr += "&nbsp;&nbsp;" + tr("Organisation") + ": " +
			    strList.first() + "<br/>";
		}
		strList = signingCrt.issuerInfo(
		    QSslCertificate::CommonName);
		if (strList.size() > 0) {
			Q_ASSERT(1 == strList.size());
			resStr += "&nbsp;&nbsp;" + tr("Name") + ": " +
			    strList.first() + "<br/>";
		}
		strList = signingCrt.issuerInfo(
		    QSslCertificate::CountryName);
		if (strList.size() > 0) {
			resStr += "&nbsp;&nbsp;" + tr("Country") + ": " +
			    strList.first() + "<br/>";
		}

		resStr += "<b>" + tr("Validity") + ": </b><br/>";
		/*
		 * QSslCertificate::effectiveDate() and
		 * QSslCertificate::expiryDate() tend to wrong time zone
		 * conversion.
		 */
		QDateTime incept, expir;
		if (signingCertTimes(m_msgDER, incept, expir)) {
			resStr += "&nbsp;&nbsp;" +
			    tr("Valid from") + ": " +
			    incept.toString(Utility::dateTimeDisplayFormat) + " " +
			    incept.timeZone().abbreviation(incept) + "<br/>";
			resStr += "&nbsp;&nbsp;" + tr("Valid to") + ": " +
			    expir.toString(Utility::dateTimeDisplayFormat) + " " +
			    expir.timeZone().abbreviation(expir) + "<br/>";
		}

		resStr += "<b>" + tr("Subject") + ": </b><br/>";
		strList = signingCrt.subjectInfo(
		    QSslCertificate::Organization);
		if (strList.size() > 0) {
			resStr += "&nbsp;&nbsp;" + tr("Organisation") + ": " +
			    strList.first() + "<br/>";
		}
		strList = signingCrt.subjectInfo(
		    QSslCertificate::CommonName);
		if (strList.size() > 0) {
			resStr += "&nbsp;&nbsp;" + tr("Name") + ": " +
			    strList.first() + "<br/>";
		}
		strList = signingCrt.subjectInfo(
		    QSslCertificate::SerialNumber);
		if (strList.size() > 0) {
			resStr += "&nbsp;&nbsp;" + tr("Serial number") + ": " +
			    strList.first() + "<br/>";
		}
		strList = signingCrt.subjectInfo(
		    QSslCertificate::CountryName);
		if (strList.size() > 0) {
			resStr += "&nbsp;&nbsp;" + tr("Country") + ": " +
			    strList.first() + "<br/>";
		}

		m_ui->cDetail->setTextFormat(Qt::RichText);
		m_ui->cDetail->setText(resStr);
	}
}

/*!
 * @brief Read timestamp information and generate data to be displayed.
 *
 * @param[in] utcTstTime Timestamping time.
 * @param[in] tstValid Whether timstamp has been successfully validated.
 * @param[in] tstDER Raw time-stamp data.
 * @param[out] tImage Verification pictogram.
 * @param[out] tStatus Verification result.
 * @param[out] tDetail Verification detail.
 */
static
void timestampOverview(qint64 utcTstTime, bool tstValid, const QByteArray &tstDER,
    QPushButton &tImage, QLabel &tStatus, QLabel &tDetail)
{
	QIcon ico;
	QString resStr;
	QString detailStr;

	if (Q_UNLIKELY(tstDER.isEmpty())) {
		ico = IconContainer::construcIcon(IconContainer::ICON_APP_WARNING);
		resStr = DlgSignatureDetail::tr("Time stamp not present.");
	} else {
		QDateTime tstTime;

		if (utcTstTime >= 0) {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
			tstTime = QDateTime::fromSecsSinceEpoch(utcTstTime);
#else /* < Qt-5.8 */
			tstTime = QDateTime::fromMSecsSinceEpoch(utcTstTime * 1000);
#endif /* >= Qt-5.8 */
		}
		resStr = "<b>" + DlgSignatureDetail::tr("Valid") + ": </b>";
		if (!tstValid) {
			ico = IconContainer::construcIcon(
			    IconContainer::ICON_APP_ERROR);
			resStr += NO;
		} else {
			ico = IconContainer::construcIcon(
			    IconContainer::ICON_APP_OK);
			resStr += YES;
		}

		detailStr = "<b>" + DlgSignatureDetail::tr("Time") + ": </b> " +
		    tstTime.toString(Utility::dateTimeDisplayFormat) + " " +
		    tstTime.timeZone().abbreviation(tstTime) + "<br/>";

		QString o, ou, n, c;
		signingCertIssuerInfo(tstDER, o, ou, n, c);

		detailStr += "<b>" + DlgSignatureDetail::tr("Issuer") + ": </b><br/>";
		if (!o.isEmpty()) {
			detailStr += "&nbsp;&nbsp;" + DlgSignatureDetail::tr("Organisation") +
			    ": " + o + "<br/>";
		}
		if (!ou.isEmpty()) {
			detailStr += "&nbsp;&nbsp;" +
			    DlgSignatureDetail::tr("Organisational unit") + ": " + ou + "<br/>";
		}
		if (!n.isEmpty()) {
			detailStr += "&nbsp;&nbsp;" + DlgSignatureDetail::tr("Name") + ": " +
			    n + "<br/>";
		}
		if (!c.isEmpty()) {
			detailStr += "&nbsp;&nbsp;" + DlgSignatureDetail::tr("Country") + ": " +
			    c + "<br/>";
		}

		QDateTime incept, expir;
		if (signingCertTimes(tstDER, incept, expir)) {
			detailStr += "<b>" + DlgSignatureDetail::tr("Validity") + ": </b><br/>";
			detailStr += "&nbsp;&nbsp;" + DlgSignatureDetail::tr("Valid from") + ": " +
			    incept.toString(Utility::dateTimeDisplayFormat) + " " +
			    incept.timeZone().abbreviation(incept) + "<br/>";
			detailStr += "&nbsp;&nbsp;" + DlgSignatureDetail::tr("Valid to") + ": " +
			    expir.toString(Utility::dateTimeDisplayFormat) + " " +
			    expir.timeZone().abbreviation(expir) + "<br/>";
		}

	}

	tImage.setIcon(ico);
	tStatus.setTextFormat(Qt::RichText);
	tStatus.setText(resStr);

	tDetail.setAlignment(Qt::AlignLeft);
	tDetail.setTextFormat(Qt::RichText);
	tDetail.setText(detailStr);
}

/*!
 * @brief Generate tab timestamp content.
 *
 * @param[in] utcTstTime Timestamping time.
 * @param[in] tstValid Whether timstamp has been successfully validated.
 * @param[in] entry Timestamp entry.
 * @param[in] idx Tab counter - user to create object names.
 * @return Pointer to tab content.
 */
static
QWidget *newTab(qint64 utcTstTime, bool tstValid, const struct der_data_list_entry *entry, int idx)
{
	if (Q_UNLIKELY(NULL == entry)) {
		return Q_NULLPTR;
	}

	QFont font1;
	font1.setBold(false);

	QWidget *tab = new (::std::nothrow) QWidget();
	if (Q_UNLIKELY(Q_NULLPTR == tab)) {
		return NULL;
	}

	tab->setObjectName(QString("tab_%1_envelope").arg(idx));
	QVBoxLayout *verticalLayout_00 = new (::std::nothrow) QVBoxLayout(tab);
	verticalLayout_00->setObjectName(QString("tab_%1_verticalLayout_00").arg(idx));
	QHBoxLayout *horizontalLayout_00 = new (::std::nothrow) QHBoxLayout();
	horizontalLayout_00->setObjectName(QString("tab_%1_horizontalLayout_00").arg(idx));
	QLabel *tStatus = new (::std::nothrow) QLabel(tab);
	tStatus->setObjectName(QString("tab_%1_tStatus").arg(idx));
	tStatus->setFont(font1);

	horizontalLayout_00->addWidget(tStatus);

	QSpacerItem *tHorizontalSpacer = new (::std::nothrow) QSpacerItem(40, 20, QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Minimum);

	horizontalLayout_00->addItem(tHorizontalSpacer);

	QPushButton *tImage = new (::std::nothrow) QPushButton(tab);
	tImage->setObjectName(QString("tab_%1_tImage").arg(idx));

	horizontalLayout_00->addWidget(tImage);

	verticalLayout_00->addLayout(horizontalLayout_00);

	QHBoxLayout *horizontalLayout_01 = new (::std::nothrow) QHBoxLayout();
	horizontalLayout_01->setObjectName(QString("tab_%1_horizontalLayout_01").arg(idx));
	QLabel *label_00 = new (::std::nothrow) QLabel(tab);
	label_00->setObjectName(QString("tab_%1_label_00").arg(idx));
	label_00->setMinimumSize(QSize(15, 0));
	label_00->setFont(font1);

	horizontalLayout_01->addWidget(label_00);

	QLabel *tDetail = new (::std::nothrow) QLabel(tab);
	tDetail->setObjectName(QString("tab_%1_tDetail").arg(idx));
	tDetail->setFont(font1);

	horizontalLayout_01->addWidget(tDetail);

	QSpacerItem *horizontalSpacer_00 = new (::std::nothrow) QSpacerItem(40, 20, QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Minimum);

	horizontalLayout_01->addItem(horizontalSpacer_00);

	verticalLayout_00->addLayout(horizontalLayout_01);

	timestampOverview(utcTstTime, tstValid,
	    (NULL != entry)
	        ? QByteArray::fromRawData((const char *)entry->der.data, entry->der.size)
	        : QByteArray(),
	    *tImage, *tStatus, *tDetail);

	return tab;
}

/*!
 * @brief Generate time string from UTC time.
 *
 * @param[in] utc_time UTC time.
 * @return Time string.
 */
static
QString utcToDisplay(qint64 utc_time)
{
	QDateTime tstTime;
#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
	tstTime = QDateTime::fromSecsSinceEpoch(utc_time);
#else /* < Qt-5.8 */
	tstTime = QDateTime::fromMSecsSinceEpoch(utc_time * 1000);
#endif /* >= Qt-5.8 */
	return tstTime.toString(Utility::dateTimeDisplayFormat) + " " +
	    tstTime.timeZone().abbreviation(tstTime);
}

void DlgSignatureDetail::validateMessageTimestamp(const TstEntries &timeStamps)
{
	/* Always show envelope timestamp tab. */
	{
		const qint64 tst_utc_time = timeStamps.envelopeTstTime();
		const bool tst_valid = timeStamps.envelopeTstValid();
		const struct der_data_list_entry *tst_entry = timeStamps.envelopeTst();

		timestampOverview(tst_utc_time, tst_valid,
		    (NULL != tst_entry)
		        ? QByteArray::fromRawData((const char *)tst_entry->der.data, tst_entry->der.size)
		        : QByteArray(),
		    *m_ui->tImage, *m_ui->tStatus, *m_ui->tDetail);
		m_ui->tabWidget->setTabToolTip(0, /* Fist tab. */
		    tr("%1\nTime stamp stored in the envelope.")
		        .arg((tst_utc_time >= 0) ? utcToDisplay(tst_utc_time) : QString()));
	}

	int num_tabs = 1;
	{
		const qint64 tst_utc_time = timeStamps.signatureTstTime();
		const bool tst_valid = timeStamps.signatureTstValid();
		const struct der_data_list_entry *tst_entry = timeStamps.signatureTst();

		if (NULL != tst_entry) {
			QWidget *tab = newTab(tst_utc_time, tst_valid, tst_entry, num_tabs);
			if (Q_NULLPTR != tab) {
				m_ui->tabWidget->addTab(tab, QString());
				int tabIdx = m_ui->tabWidget->indexOf(tab);
				m_ui->tabWidget->setTabText(tabIdx,
				    tr("Signature"));
				m_ui->tabWidget->setTabToolTip(tabIdx,
				    tr("%1\nSignature time stamp stored in the CMS container.")
				        .arg((tst_utc_time >= 0) ? utcToDisplay(tst_utc_time) : QString()));

				++num_tabs;
			}
		}
	}

	QList<qint64> keys = timeStamps.sortedArchiveTstTimes();
	int archive_idx = 0;
	for (const qint64 tst_utc_time : keys) {
		const bool tst_valid = timeStamps.archiveTstValid(tst_utc_time);
		const struct der_data_list_entry *tst_entry = timeStamps.archiveTst(tst_utc_time);

		if (NULL != tst_entry) {
			QWidget *tab = newTab(tst_utc_time, tst_valid, tst_entry, num_tabs);
			if (Q_NULLPTR != tab) {
				m_ui->tabWidget->addTab(tab, QString());
				int tabIdx = m_ui->tabWidget->indexOf(tab);
				m_ui->tabWidget->setTabText(tabIdx,
				    tr("Archive %1").arg(archive_idx + 1));
				m_ui->tabWidget->setTabToolTip(tabIdx,
				    tr("%1\nArchive time stamp number %2 in the CMS container.")
				        .arg((tst_utc_time >= 0) ? utcToDisplay(tst_utc_time) : QString())
				        .arg(archive_idx + 1));

				++num_tabs;
				++archive_idx;
			}
		}
	}

	/* Select last tab. */
	m_ui->tabWidget->setCurrentIndex(num_tabs - 1);
}

void DlgSignatureDetail::setIcons(void)
{
	const QIcon ico(
	    IconContainer::construcIcon(IconContainer::ICON_APP_WARNING));
	m_ui->tImage->setIcon(ico);
	m_ui->cImage->setIcon(ico);
	m_ui->mSignatureImage->setIcon(ico);
}
