/*
 * Copyright (C) 2014-2024 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 <QApplication>
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>

#include "src/datovka_shared/compat/compiler.h" /* macroStdMove */
#include "src/datovka_shared/html/html_export.h"
#include "src/datovka_shared/isds/type_conversion.h"
#include "src/datovka_shared/isds/type_description.h"
#include "src/datovka_shared/log/log.h"
#include "src/datovka_shared/settings/pin.h"
#include "src/datovka_shared/utility/date_time.h"
#include "src/datovka_shared/worker/pool.h"
#include "src/dimensions/dimensions.h"
#include "src/global.h"
#include "src/gui/dlg_create_account.h"
#include "src/gui/dlg_pin_input.h"
#include "src/gui/dlg_user_ext2.h"
#include "src/gui/icon_container.h"
#include "src/gui/isds_login.h"
#include "src/io/account_db.h"
#include "src/io/account_db_tables.h"
#include "src/io/account_shadow_helper.h"
#include "src/io/dbs.h"
#include "src/io/isds_helper.h"
#include "src/io/isds_sessions.h"
#include "src/io/message_db_set_container.h"
#include "src/io/message_db_set.h"
#include "src/settings/accounts.h"
#include "src/settings/prefs_specific.h"
#include "src/views/table_home_end_filter.h"
#include "src/views/table_tab_ignore_filter.h"
#include "src/worker/task_add_data_box_user2.h"
#include "src/worker/task_delete_data_box_user2.h"
#include "src/worker/task_get_data_box_users2.h"
#include "src/worker/task_get_owner_info_from_login2.h"
#include "src/worker/task_get_user_info_from_login2.h"
#include "src/worker/task_update_data_box_user2.h"
#include "ui_dlg_create_account.h"

#define PAGE_DESCRIPTION 0
#define PAGE_CREDENTIALS 1
#define PAGE_PRIVILEGES 2
#define PAGE_USERS 3

static Isds::DbOwnerInfoExt2 _owner; /* Box owner info. */
static Isds::DbUserInfoExt2 _user; /* Box user info. */

static const QString dlgName("create_account_manage");
static const QString dlgTableName("users");

/*!
 * @brief Login method order as they are listed in the dialogue.
 */
enum LoginMethodIndex {
	USER_NAME = 0,
	CERTIFICATE = 1,
	USER_CERTIFICATE = 2,
	HOTP = 3,
	TOTP = 4,
	MEP = 5
};

DlgCreateAccount::DlgCreateAccount(const AcntData &accountInfo,
    enum Action action, const QString &syncAllActName, QWidget *parent)
    : QDialog(parent),
    m_ui(new (::std::nothrow) Ui::DlgCreateAccount),
    m_accountSettingsModel(this),
    m_regularAccounts(Q_NULLPTR),
    m_shadowAccounts(Q_NULLPTR),
    m_accountInfo(),
    m_action(action),
    m_showViewPwd((ACT_ADDNEW == action) ||
        ((ACT_EDIT == action) && GlobInstcs::pinSetPtr->pinConfigured())),
    m_loginMethod(USER_NAME),
    m_certPath(),
    m_hidePwdTimer(this),
    m_viewPwdUpdate(100),
    m_viewPwdDuration(10000), /* 10 seconds */
    m_viewPwdRemainingCycles(0),
    m_usersModel(this),
    m_userListProxyModel(this),
    m_userListMenu(this),
    m_actionUserAdd(Q_NULLPTR),
    m_actionUserChangeContactAddress(Q_NULLPTR),
    m_actionUserChangePrivils(Q_NULLPTR),
    m_actionUserDelete(Q_NULLPTR),
    m_treeViewMenu(this),
    m_actionAddShadow(Q_NULLPTR),
    m_actionRemoveShadow(Q_NULLPTR)
{
	m_ui->setupUi(this);
	/* Tab order is defined in UI file. */

	m_userListProxyModel.setSortRole(UsersModel::ROLE_PROXYSORT);
	m_userListProxyModel.setSourceModel(&m_usersModel);

	m_ui->treeView->setModel(&m_accountSettingsModel);
	m_ui->userTableView->setModel(&m_userListProxyModel);

	m_ui->userTableView->setSortingEnabled(true);
	m_ui->userTableView->sortByColumn(UsersModel::COL_GIV_NAMES,
	    Qt::AscendingOrder);

	m_ui->splitter->setChildrenCollapsible(false);
	m_ui->splitter_2->setChildrenCollapsible(false);

	m_ui->addCertButton->setIcon(
	    IconContainer::construcIcon(IconContainer::ICON_FOLDER));

	m_ui->loginMethodComboBox->addItem(tr("Password"));
	m_ui->loginMethodComboBox->addItem(tr("Certificate"));
	m_ui->loginMethodComboBox->addItem(tr("Certificate + Password"));
	m_ui->loginMethodComboBox->addItem(tr("Password + Security code"));
	m_ui->loginMethodComboBox->addItem(tr("Password + Security SMS"));
	m_ui->loginMethodComboBox->addItem(tr("Mobile key"));

	m_ui->viewPwdProgress->setFixedHeight(m_ui->pwdLine->height() / 4);
	m_ui->viewPwdProgress->setTextVisible(false);
	m_ui->viewPwdProgress->setVisible(false);

	m_ui->certLabel->setEnabled(false);
	m_ui->addCertButton->setEnabled(false);

	m_ui->mepLabel->setEnabled(false);
	m_ui->mepLine->setEnabled(false);

	m_ui->syncAllCheckBox->setText(
	    tr("Synchronise this data box when '%1' is activated")
	        .arg(syncAllActName));

	m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);

	connect(m_ui->loginMethodComboBox, SIGNAL(currentIndexChanged(int)),
	    this, SLOT(activateContent(int)));
	connect(m_ui->showHidePwdButton, SIGNAL(clicked()), this,
	    SLOT(togglePwdVisibility()));
	connect(m_ui->addCertButton, SIGNAL(clicked()), this,
	    SLOT(addCertificateFile()));
	connect(m_ui->buttonBox, SIGNAL(accepted()), this,
	    SLOT(collectAccountData()));
	connect(m_ui->acntNameLine, SIGNAL(textChanged(QString)),
	    this, SLOT(checkInputFields()));
	connect(m_ui->usernameLine, SIGNAL(textChanged(QString)),
	    this, SLOT(checkInputFields()));
	connect(m_ui->pwdLine, SIGNAL(textChanged(QString)),
	    this, SLOT(checkInputFields()));
	connect(m_ui->mepLine, SIGNAL(textChanged(QString)),
	    this, SLOT(checkInputFields()));

	connect(&m_hidePwdTimer, SIGNAL(timeout()), this,
	    SLOT(updatePwdVisibilityProgress()));

	m_ui->showHidePwdButton->setVisible(m_showViewPwd);
	m_ui->showHidePwdButton->setEnabled(
	    m_showViewPwd && !m_ui->pwdLine->text().isEmpty());

	/* Set dialogue content for existing account. */
	if (ACT_ADDNEW != m_action) {
		setContent(accountInfo, FC_EDITABLE);
	} else {
		/* Change acceptance button text if a new account is created. */
		m_ui->buttonBox->button(QDialogButtonBox::Ok)->setText(
		    tr("Sign in and Add Data Box"));
	}
}

DlgCreateAccount::~DlgCreateAccount(void)
{
	delete m_ui;
}

bool DlgCreateAccount::modify(AcntData &accountInfo, enum Action action,
    const QString &syncAllActName, int properties, QWidget *parent)
{
	DlgCreateAccount dlg(accountInfo, action, syncAllActName, parent);
	dlg.m_ui->treeView->setVisible(false);
	dlg.m_ui->treeViewButton->setVisible(false);
	dlg.m_ui->verticalStackedWidget->setCurrentIndex(PAGE_CREDENTIALS);
	if (properties != FC_NONE) {
		dlg.setContent(accountInfo, properties);
	}

	const QString dlgName("create_account_modify");
	const QSize dfltSize = dlg.size();
	{
		const QSize newSize = Dimensions::dialogueSize(&dlg,
		    PrefsSpecific::dlgSize(*GlobInstcs::prefsPtr, dlgName),
		    dfltSize);
		if (newSize.isValid()) {
			dlg.resize(newSize);
		}
	}

	int ret = dlg.exec();

	PrefsSpecific::setDlgSize(*GlobInstcs::prefsPtr, dlgName,
	    dlg.size(), dfltSize);

	if (QDialog::Accepted == ret) {
		/* Store submitted data. */
		accountInfo = dlg.m_accountInfo;
		return true;
	} else {
		return false;
	}
}

bool DlgCreateAccount::modify(AcntData &accountInfo, enum Action action,
    const QString &syncAllActName, QWidget *parent)
{
	return modify(accountInfo, action, syncAllActName, FC_NONE, parent);
}

bool DlgCreateAccount::manage(AccountsMap &regularAccounts,
    AccountsMap &shadowAccounts, const QString &syncAllActName,
    QWidget *parent)
{
	if (Q_UNLIKELY(regularAccounts.isEmpty())) {
		return false;
	}

	/* Manage a copy of shadow accounts. */
	AccountsMap shadowAccountsCopy(AcntContainer::CT_SHADOW);
	shadowAccountsCopy.load(shadowAccounts);

	DlgCreateAccount dlg(AcntData(), ACT_EDIT, syncAllActName, parent);
	dlg.m_regularAccounts = &regularAccounts;
	dlg.m_shadowAccounts = &shadowAccountsCopy;
	dlg.m_accountSettingsModel.loadContent(dlg.m_regularAccounts,
	    dlg.m_shadowAccounts);
	connect(dlg.m_ui->treeView->selectionModel(),
	    SIGNAL(currentChanged(QModelIndex, QModelIndex)),
	    &dlg, SLOT(accountCurrentChanged(QModelIndex, QModelIndex)));
	dlg.m_ui->treeView->expandAll();

	dlg.m_ui->treeViewButton->setPopupMode(QToolButton::InstantPopup);
	dlg.m_actionAddShadow = dlg.m_treeViewMenu.addAction(
	    tr("Add Shadow Data Box"), &dlg, SLOT(addShadowAccount()));
	dlg.m_actionRemoveShadow = dlg.m_treeViewMenu.addAction(
	    tr("Remove Shadow Data Box"), &dlg, SLOT(removeSelectedShadowAccount()));
	dlg.m_ui->treeViewButton->setMenu(&dlg.m_treeViewMenu);

	connect(dlg.m_ui->downloadAccountInfoButton, SIGNAL(clicked()), &dlg,
	    SLOT(refreshAccountInformation()));
	dlg.m_ui->downloadAccountInfoButton->setToolTip(
	    tr("Refresh data-box information from ISDS."));

	dlg.m_ui->treeView->setCurrentIndex(dlg.m_accountSettingsModel.index(
	    AccountSettingsModel::ROW_REGULAR, 0));

	connect(dlg.m_ui->downloadUserListButton, SIGNAL(clicked()), &dlg,
	    SLOT(refreshUsersInformation()));

	dlg.m_ui->userTableView->setNarrowedLineHeight();
	dlg.m_ui->userTableView->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
	dlg.m_ui->userTableView->setSelectionMode(
	    QAbstractItemView::SingleSelection);
	dlg.m_ui->userTableView->setSelectionBehavior(
	    QAbstractItemView::SelectRows);

	dlg.m_ui->userTableView->installEventFilter(
	    new (::std::nothrow) TableHomeEndFilter(dlg.m_ui->userTableView));
	dlg.m_ui->userTableView->installEventFilter(
	    new (::std::nothrow) TableTabIgnoreFilter(dlg.m_ui->userTableView));

	connect(dlg.m_ui->userTableView->selectionModel(),
	    SIGNAL(currentChanged(QModelIndex, QModelIndex)),
	    &dlg, SLOT(userCurrentChanged(QModelIndex, QModelIndex)));

	dlg.m_ui->userListButton->setPopupMode(QToolButton::InstantPopup);
	dlg.m_actionUserAdd = dlg.m_userListMenu.addAction(
	    tr("Add User"), &dlg, SLOT(addUser()));
	dlg.m_actionUserChangeContactAddress = dlg.m_userListMenu.addAction(
	    tr("Change Contact Address"), &dlg, SLOT(modifyUserContactAddress()));
	dlg.m_actionUserChangePrivils = dlg.m_userListMenu.addAction(
	    tr("Change Privileges"), &dlg, SLOT(modifyUserPrivileges()));
	dlg.m_actionUserDelete = dlg.m_userListMenu.addAction(
	    tr("Delete User"), &dlg, SLOT(deleteUser()));
	dlg.m_ui->userListButton->setMenu(&dlg.m_userListMenu);

	const QSize dfltSize = dlg.size();
	{
		const QSize newSize = Dimensions::dialogueSize(&dlg,
		    PrefsSpecific::dlgSize(*GlobInstcs::prefsPtr, dlgName),
		    dfltSize);
		if (newSize.isValid()) {
			dlg.resize(newSize);
		}
	}

	const QString dlgVSplitterName("account");
	const QString dlgHSplitterName("user_info");
	Dimensions::setSplitterSize(dlg.m_ui->splitter,
	    PrefsSpecific::dlgSplitterSize(*GlobInstcs::prefsPtr,
	    dlgName, dlgVSplitterName));
	Dimensions::setSplitterSize(dlg.m_ui->splitter_2,
	    PrefsSpecific::dlgSplitterSize(*GlobInstcs::prefsPtr,
	    dlgName, dlgHSplitterName));

	int ret = dlg.exec();

	PrefsSpecific::setDlgSize(*GlobInstcs::prefsPtr, dlgName,
	    dlg.size(), dfltSize);

	PrefsSpecific::setDlgSplitterSize(*GlobInstcs::prefsPtr,
	    dlgName, dlgVSplitterName,
	    Dimensions::splitterSize(dlg.m_ui->splitter));
	PrefsSpecific::setDlgSplitterSize(*GlobInstcs::prefsPtr,
	    dlgName, dlgHSplitterName,
	    Dimensions::splitterSize(dlg.m_ui->splitter_2));

	PrefsSpecific::setDlgTblRelColWidths(*GlobInstcs::prefsPtr,
	    dlgName, dlgTableName,
	    Dimensions::relativeTableColumnWidths(dlg.m_ui->userTableView));
	PrefsSpecific::setDlgTblColSortOrder(*GlobInstcs::prefsPtr,
	    dlgName, dlgTableName,
	    Dimensions::tableColumnSortOrder(dlg.m_ui->userTableView));

	if (QDialog::Accepted == ret) {
		/* Collect data that might have been changed. */
		const QModelIndex current(dlg.m_ui->treeView->currentIndex());
		if ((dlg.m_shadowAccounts != Q_NULLPTR) &&
		    (AccountSettingsModel::nodeShadowAccountTop ==
		     AccountSettingsModel::nodeType(current))) {
			dlg.m_shadowAccounts->updateAccount(dlg.getContent());
		}
		/* Save edited copy when dialogue accepted. */
		shadowAccounts.load(shadowAccountsCopy);
		return true;
	} else {
		return false;
	}
}

bool DlgCreateAccount::accountExists(const AcntId &acntId,
    const AccountsMap &regularAccounts, const AccountsMap &shadowAccounts)
{
	if (Q_UNLIKELY(!acntId.isValid())) {
		Q_ASSERT(0);
		return true; /* Fake the existence of the invalid account. */
	}

	return regularAccounts.keys().contains(acntId) ||
	    shadowAccounts.acntIds().contains(acntId);
}

QString DlgCreateAccount::htmlAccountInfo(const AcntData &acntData,
    MessageDbSet *dbSet)
{
	Q_ASSERT(acntIdFromData(acntData).isValid());

	const QString acntDbKey(AccountDb::keyFromLogin(acntData.userName()));
	QString html;

	html.append(Html::Export::htmlDataboxOwnerInfoApp(
	    GlobInstcs::accntDbPtr->getOwnerInfo2(acntDbKey)));
	html.append(Html::Export::htmlDataboxUserInfoApp(
	    GlobInstcs::accntDbPtr->getUserInfo2(acntDbKey)));
	html.append(Html::Export::htmlPwdExpirDateInfoApp(qDateTimeToDbFormat(
	    GlobInstcs::accntDbPtr->getPwdExpirFromDb(acntDbKey))));
	if (dbSet != Q_NULLPTR) {
		html.append(Html::Export::htmlMsgDbLocationInfoApp(
		    dbSet->fileNames()));
	}

	return htmlMarginsApp(htmlSectionLabel(
	    acntData.isTestAccount() ?
	    tr("Test Environment Data Box") :
	    tr("Production Environment Data Box")),
	    html);
}

void DlgCreateAccount::activateContent(int loginMethodIdx)
{
	m_loginMethod = loginMethodIdx;

	switch (m_loginMethod) {
	case CERTIFICATE:
		m_ui->pwdLabel->setEnabled(false);
		m_ui->pwdLine->setEnabled(false);
		m_ui->showHidePwdButton->setEnabled(false);
		m_ui->rememberPwdCheckBox->setEnabled(false);
		m_ui->certLabel->setEnabled(true);
		m_ui->addCertButton->setEnabled(true);
		m_ui->mepLabel->setEnabled(false);
		m_ui->mepLine->setEnabled(false);
		break;
	case USER_CERTIFICATE:
		m_ui->pwdLabel->setEnabled(true);
		m_ui->pwdLine->setEnabled(true);
		m_ui->showHidePwdButton->setEnabled(m_showViewPwd);
		m_ui->rememberPwdCheckBox->setEnabled(true);
		m_ui->certLabel->setEnabled(true);
		m_ui->addCertButton->setEnabled(true);
		m_ui->mepLabel->setEnabled(false);
		m_ui->mepLine->setEnabled(false);
		break;
	case MEP:
		m_ui->pwdLabel->setEnabled(false);
		m_ui->pwdLine->setEnabled(false);
		m_ui->showHidePwdButton->setEnabled(false);
		m_ui->rememberPwdCheckBox->setEnabled(false);
		m_ui->certLabel->setEnabled(false);
		m_ui->addCertButton->setEnabled(false);
		m_ui->mepLabel->setEnabled(true);
		m_ui->mepLine->setEnabled(true);
		break;
	default:
		m_ui->pwdLabel->setEnabled(true);
		m_ui->pwdLine->setEnabled(true);
		m_ui->showHidePwdButton->setEnabled(m_showViewPwd);
		m_ui->rememberPwdCheckBox->setEnabled(true);
		m_ui->certLabel->setEnabled(false);
		m_ui->addCertButton->setEnabled(false);
		m_ui->mepLabel->setEnabled(false);
		m_ui->mepLine->setEnabled(false);
		break;
	}

	checkInputFields();
}

void DlgCreateAccount::checkInputFields(void)
{
	bool enabled = false;
	/*
	 * Allow data modification for existing accounts even when login
	 * credentials are not complete.
	 * Complete login credentials must be provided when creating new accounts.
	 */
	const bool alreadyExisting = (ACT_ADDNEW != m_action);

	switch (m_loginMethod) {
	case CERTIFICATE:
		enabled = !m_ui->acntNameLine->text().trimmed().isEmpty()
		    && !m_ui->usernameLine->text().trimmed().isEmpty()
		    && (alreadyExisting || !m_certPath.isEmpty());
		break;
	case USER_CERTIFICATE:
		enabled = !m_ui->acntNameLine->text().trimmed().isEmpty()
		    && !m_ui->usernameLine->text().trimmed().isEmpty()
		    && (alreadyExisting || !m_ui->pwdLine->text().isEmpty())
		    && (alreadyExisting || !m_certPath.isEmpty());
		break;
	case MEP:
		enabled = !m_ui->acntNameLine->text().trimmed().isEmpty()
		    && !m_ui->usernameLine->text().trimmed().isEmpty()
		    && (alreadyExisting || !m_ui->mepLine->text().isEmpty());
		break;
	default:
		enabled = !m_ui->acntNameLine->text().trimmed().isEmpty()
		    && !m_ui->usernameLine->text().trimmed().isEmpty()
		    && (alreadyExisting || !m_ui->pwdLine->text().isEmpty());
		break;
	}

	m_ui->showHidePwdButton->setEnabled(
	     m_showViewPwd && !m_ui->pwdLine->text().isEmpty());
	m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enabled);
}

void DlgCreateAccount::togglePwdVisibility(void)
{
	enum QLineEdit::EchoMode newEchoMode = QLineEdit::Password;

	switch (m_ui->pwdLine->echoMode()) {
	case QLineEdit::Normal:
		break;
	case QLineEdit::Password:
		if ((ACT_ADDNEW != m_action) &&
		    !DlgPinInput::queryPin(*GlobInstcs::pinSetPtr, false, this)) {
			return;
		}
		/* Pin was entered correctly or new account creation. */
		newEchoMode = QLineEdit::Normal;
		break;
	default:
		Q_ASSERT(0);
		break;
	}

	setPwdLineEchoMode(newEchoMode);
}

void DlgCreateAccount::updatePwdVisibilityProgress(void)
{
	--m_viewPwdRemainingCycles;

	if (Q_UNLIKELY(m_viewPwdRemainingCycles < 0)) {
		Q_ASSERT(0);
		m_viewPwdRemainingCycles = 0;
	}

	m_ui->viewPwdProgress->setValue(m_viewPwdRemainingCycles);

	if (Q_UNLIKELY(m_viewPwdRemainingCycles == 0)) {
		setPwdLineEchoMode(QLineEdit::Password);
	}
}

void DlgCreateAccount::addCertificateFile(void)
{
	const QString certFileName(QFileDialog::getOpenFileName(this,
	    tr("Open Certificate"), QString(),
	    tr("Certificate Files (*.pfx *.p12 *.pem)")));
	if (!certFileName.isEmpty()) {
		m_ui->addCertButton->setText(QFileInfo(certFileName).fileName());
		m_ui->addCertButton->setIcon(IconContainer::construcIcon(
		    IconContainer::ICON_DATOVKA_STOCK_KEY));
		m_ui->addCertButton->setToolTip(certFileName);
		m_certPath = certFileName;
		checkInputFields();
	}
}

void DlgCreateAccount::collectAccountData(void)
{
	debugSlotCall();

	/* Store the submitted settings. */
	m_accountInfo = getContent();
}

void DlgCreateAccount::accountCurrentChanged(const QModelIndex &current,
    const QModelIndex &previous)
{
	enum AccountSettingsModel::NodeType previousType =
	    AccountSettingsModel::nodeType(previous);

	switch (previousType) {
	case AccountSettingsModel::nodeShadowAccountTop:
		if (m_shadowAccounts != Q_NULLPTR) {
			m_shadowAccounts->updateAccount(getContent());
		}
		break;
	case AccountSettingsModel::nodeRegularAccountUsers:
		PrefsSpecific::setDlgTblRelColWidths(*GlobInstcs::prefsPtr,
		    dlgName, dlgTableName,
		    Dimensions::relativeTableColumnWidths(m_ui->userTableView));
		PrefsSpecific::setDlgTblColSortOrder(*GlobInstcs::prefsPtr,
		    dlgName, dlgTableName,
		    Dimensions::tableColumnSortOrder(m_ui->userTableView));
		break;
	default:
		break;
	}

	enum AccountSettingsModel::NodeType currentType =
	    AccountSettingsModel::nodeType(current);

	switch (currentType) {
	case AccountSettingsModel::nodeUnknown:
	case AccountSettingsModel::nodeRoot:
		Q_ASSERT(0);
		m_ui->verticalStackedWidget->setCurrentIndex(PAGE_DESCRIPTION);
		m_ui->descriptionLabel->setText(QString());
		break;
	case AccountSettingsModel::nodeRegular:
		m_ui->verticalStackedWidget->setCurrentIndex(PAGE_DESCRIPTION);
		setWindowTitle(tr("Regular data boxes"));
		m_ui->descriptionLabel->setText(tr(
		    "Regular data boxes are data boxes which you can see listed in the main window of the application.\n\n"
		    "Database files containing message data are associated with these data boxes."));
		break;
	case AccountSettingsModel::nodeShadow:
		m_ui->verticalStackedWidget->setCurrentIndex(PAGE_DESCRIPTION);
		setWindowTitle(tr("Shadow data boxes"));
		m_ui->descriptionLabel->setText(tr(
		    "Shadow data boxes are data boxes which exist in the background of the application.\n\n"
		    "Shadow data boxes have low access privileges and don't have any databases associated to them. "
		    "They become useful when you have access to a data box to which multiple users have access to. "
		    "In this case a data box which can only download message lists (and send messages) can be used as a shadow data box.\n\n"
		    "Data boxes which can only download message lists (and send messages) can't cause the acceptance of delivered messages. "
		    "These data boxes can then be used to automatically check whether there are newly delivered messages without accepting them."));
		break;
	case AccountSettingsModel::nodeRegularAccountTop:
		if (m_regularAccounts != Q_NULLPTR) {
			m_ui->verticalStackedWidget->setCurrentIndex(PAGE_CREDENTIALS);
			setContent(
			    m_regularAccounts->acntData(m_accountSettingsModel.acntId(current)),
			    FC_NONE);
		}
		break;
	case AccountSettingsModel::nodeShadowAccountTop:
		if (m_shadowAccounts != Q_NULLPTR) {
			m_ui->verticalStackedWidget->setCurrentIndex(PAGE_CREDENTIALS);
			setContent(
			    m_shadowAccounts->acntData(m_accountSettingsModel.acntId(current)),
			    FC_SHADOW_ACNT | FC_EDITABLE);
			/*
			 * Disable username editing.
			 * TODO -- Make it less crude.
			 */
			m_ui->usernameLine->setEnabled(false);
		}
		break;
	case AccountSettingsModel::nodeRegularAccountInfo:
		{
			m_ui->verticalStackedWidget->setCurrentIndex(PAGE_PRIVILEGES);
			const AcntId acntId(m_accountSettingsModel.acntId(current));
			loadPrivilegesContent(acntId, currentType);
			setWindowTitle(tr("Data-box info %1").arg(
			    m_regularAccounts->acntData(acntId).accountName()));
		}
		break;
	case AccountSettingsModel::nodeRegularAccountUsers:
		{
			m_ui->verticalStackedWidget->setCurrentIndex(PAGE_USERS);
			const AcntId acntId(m_accountSettingsModel.acntId(current));
			refreshUsersInformation();

			Dimensions::setRelativeTableColumnWidths(m_ui->userTableView,
			    PrefsSpecific::dlgTblRelColWidths(*GlobInstcs::prefsPtr,
			    dlgName, dlgTableName));
			Dimensions::setTableColumnSortOrder(m_ui->userTableView,
			    PrefsSpecific::dlgTblColSortOrder(*GlobInstcs::prefsPtr,
			    dlgName, dlgTableName));

			setWindowTitle(tr("Data-box users"));
		}
		break;
	case AccountSettingsModel::nodeShadowAccountInfo:
		if (m_shadowAccounts != Q_NULLPTR) {
			m_ui->verticalStackedWidget->setCurrentIndex(PAGE_PRIVILEGES);
			const AcntId acntId(m_accountSettingsModel.acntId(current));
			loadPrivilegesContent(acntId, currentType);
			setWindowTitle(tr("Data-box info %1").arg(
			    m_shadowAccounts->acntData(acntId).accountName()));
		}
		break;
	default:
		break;
	}

	m_actionRemoveShadow->setEnabled(
	    currentType == AccountSettingsModel::nodeShadowAccountTop);
}

/*!
 * @brief Download account information from ISDS and update account database.
 *
 * @param[in,out] acntData Account data may be changed when login credentials
 *                         are not sufficient or are wrong.
 * @param[in]     syncAllActionName Synchronise all action name.
 * @param[in]     parent Parent widget.
 */
static
void downloadAccountInformation(AcntData &acntData,
    const QString &syncAllActionName, QWidget *parent)
{
	{
		Gui::LogInCycle login(syncAllActionName, parent);
		if (!login.logIn(*GlobInstcs::isdsSessionsPtr, acntData)) {
			return;
		}
	}

	const AcntId acntId(acntIdFromData(acntData));

	if (!IsdsHelper::getOwnerInfoFromLogin(acntId)) {
		//TODO: return false;
	}
	if (!IsdsHelper::getUserInfoFromLogin(acntId)) {
		//TODO: return false;
	}
	const QString dbID = GlobInstcs::accntDbPtr->dbId(
	    AccountDb::keyFromLogin(acntId.username()));
	if (!IsdsHelper::getDtInfo(acntId, dbID)) {
		//TODO: return false;
	}
	if (!IsdsHelper::getPasswordInfoFromLogin(acntId)) {
		//TODO: return false;
	}
}

void DlgCreateAccount::addShadowAccount(void)
{
	AcntData newShadowSettings;
	if (!DlgCreateAccount::modify(newShadowSettings,
	        DlgCreateAccount::ACT_ADDNEW, m_ui->syncAllCheckBox->text(),
	        FC_SHADOW_ACNT, this)) {
		return;
	}

	const AcntId newShadowAcntId(acntIdFromData(newShadowSettings));
	if (accountExists(newShadowAcntId, *m_regularAccounts, *m_shadowAccounts)) {
		QMessageBox::warning(this, tr("Adding new shadow data box failed"),
		    tr("A data box using the supplied username already exists. Data box has not been added."),
		    QMessageBox::Ok);
		return;
	}

	downloadAccountInformation(newShadowSettings,
	    m_ui->syncAllCheckBox->text(), this);

	m_shadowAccounts->addAccount(newShadowSettings);

	const AcntId newAcntId = acntIdFromData(newShadowSettings);
	QModelIndex index = m_accountSettingsModel.indexShadowAccountTop(newAcntId);
	if (index.isValid()) {
		m_ui->treeView->selectionModel()->setCurrentIndex(index,
		    QItemSelectionModel::ClearAndSelect);
		m_ui->treeView->expand(index);
	}

	if (!ShadowHelper::isUsableBackgroundAccount(newAcntId,
	        *m_shadowAccounts)) {
		QMessageBox::warning(this, tr("Unusable Shadow Data Box"),
		    tr("This data box won't be used to download message lists on background. View the data-box information for more detail."),
		    QMessageBox::Ok);
	}
}

void DlgCreateAccount::removeSelectedShadowAccount(void)
{
	if (QMessageBox::Yes != QMessageBox::question(this,
	        tr("Remove Shadow Data Box?"),
		tr("Do you want to remove the shadow data box '%1'?").arg(m_ui->acntNameLine->text()),
		QMessageBox::Yes | QMessageBox::No, QMessageBox::No)) {
		return;
	}

	const QModelIndex current(m_ui->treeView->currentIndex());
	if (Q_UNLIKELY(AccountSettingsModel::nodeShadowAccountTop !=
	        AccountSettingsModel::nodeType(current))) {
		Q_ASSERT(0);
		return;
	}

	{
		const AcntId &acntId = m_accountSettingsModel.acntId(current);
		m_shadowAccounts->removeAccount(acntId);
		GlobInstcs::isdsSessionsPtr->quitSession(acntId.username());
	}

	/* Select parent node. */
	m_ui->treeView->setCurrentIndex(m_accountSettingsModel.index(
	    AccountSettingsModel::ROW_SHADOW, 0));
}

void DlgCreateAccount::refreshAccountInformation(void)
{
	m_ui->downloadAccountInfoButton->setEnabled(false);
	QApplication::processEvents();

	const QModelIndex current(m_ui->treeView->currentIndex());
	enum AccountSettingsModel::NodeType currentType =
	    AccountSettingsModel::nodeType(current);

	switch (currentType) {
	case AccountSettingsModel::nodeRegularAccountInfo:
	case AccountSettingsModel::nodeShadowAccountInfo:
		break;
	default:
		Q_ASSERT(0);
		m_ui->downloadAccountInfoButton->setEnabled(true);
		return;
		break;
	}

	const AcntId acntId(m_accountSettingsModel.acntId(current));

	{
		/* Login and download account information. */

		AcntData acntData;
		switch (currentType) {
		case AccountSettingsModel::nodeRegularAccountInfo:
			acntData = m_regularAccounts->acntData(acntId);
			break;
		case AccountSettingsModel::nodeShadowAccountInfo:
			acntData = m_shadowAccounts->acntData(acntId);
			break;
		default:
			Q_ASSERT(0);
			m_ui->downloadAccountInfoButton->setEnabled(true);
			return;
			break;
		}

		{
			AcntData newAcntData = acntData;
			downloadAccountInformation(newAcntData,
			    m_ui->syncAllCheckBox->text(), this);
			/* Store modifications. */
			if (newAcntData != acntData) {
				switch (currentType) {
				case AccountSettingsModel::nodeRegularAccountInfo:
					/* TODO -- Update regular account data. */
					break;
				case AccountSettingsModel::nodeShadowAccountInfo:
					m_shadowAccounts->updateAccount(newAcntData);
					break;
				default:
					break;
				}
			}
		}
	}

	loadPrivilegesContent(acntId, currentType);

	m_ui->downloadAccountInfoButton->setEnabled(true);
}

/*!
 * @brief Download user list from ISDS.
 *
 * @param[in,out] acntData Account data may be changed when login credentials
 *                         are not sufficient or are wrong.
 * @param[in]     syncAllActionName Synchronise all action name.
 * @param[in]     parent Parent widget.
 * @return List of account users.
 */
static
QList<Isds::DbUserInfoExt2> downloadDataBoxUsers2(AcntData &acntData,
    const QString &syncAllActionName, QWidget *parent)
{
	{
		Gui::LogInCycle login(syncAllActionName, parent);
		if (!login.logIn(*GlobInstcs::isdsSessionsPtr, acntData)) {
			return QList<Isds::DbUserInfoExt2>();
		}
	}

	const AcntId acntId(acntIdFromData(acntData));

	TaskGetDataBoxUsers2 *task =
	    new (::std::nothrow) TaskGetDataBoxUsers2(acntId);
	if (Q_UNLIKELY(task == Q_NULLPTR)) {
		return QList<Isds::DbUserInfoExt2>();
	}

	QList<Isds::DbUserInfoExt2> users;

	task->setAutoDelete(false);
	if (GlobInstcs::workPoolPtr->runSingle(task)) {

		if (task->m_success) {
			users = macroStdMove(task->m_users);
		} else {
			QMessageBox::warning(parent,
			    DlgCreateAccount::tr("Failed User List Download"),
			    DlgCreateAccount::tr("User list download failed. ISDS returns: %1")
			        .arg(task->m_isdsLongError));
		}

	}

	delete task;

	return users;
}

/*!
 * @brief Download owner info from ISDS;
 *
 * @param[in,out] acntData Account data may be changed when login credentials
 *                         are not sufficient or are wrong.
 * @param[in]     syncAllActionName Synchronise all action name.
 * @param[in]     parent Parent widget.
 * @return Owner information.
 */
static
Isds::DbOwnerInfoExt2 downloadOwnerInfoFromLogin2(AcntData &acntData,
    const QString &syncAllActionName, QWidget *parent)
{
	{
		Gui::LogInCycle login(syncAllActionName, parent);
		if (!login.logIn(*GlobInstcs::isdsSessionsPtr, acntData)) {
			return Isds::DbOwnerInfoExt2();
		}
	}

	const AcntId acntId(acntIdFromData(acntData));

	TaskGetOwnerInfoFromLogin2 *task =
	    new (::std::nothrow) TaskGetOwnerInfoFromLogin2(acntId);
	if (Q_UNLIKELY(task == Q_NULLPTR)) {
		return Isds::DbOwnerInfoExt2();
	}

	Isds::DbOwnerInfoExt2 owner;

	task->setAutoDelete(false);
	if (GlobInstcs::workPoolPtr->runSingle(task)) {

		owner = macroStdMove(task->m_owner);

	}

	delete task;

	return owner;
}

/*!
 * @brief Download user info from ISDS.
 *
 * @param[in,out] acntData Account data may be changed when login credentials
 *                         are not sufficient or are wrong.
 * @param[in]     syncAllActionName Synchronise all action name.
 * @param[in]     parent Parent widget.
 * @return Account user information.
 */
static
Isds::DbUserInfoExt2 downloadUserInfoFromLogin2(AcntData &acntData,
    const QString &syncAllActionName, QWidget *parent)
{
	{
		Gui::LogInCycle login(syncAllActionName, parent);
		if (!login.logIn(*GlobInstcs::isdsSessionsPtr, acntData)) {
			return Isds::DbUserInfoExt2();
		}
	}

	const AcntId acntId(acntIdFromData(acntData));

	TaskGetUserInfoFromLogin2 *task =
	    new (::std::nothrow) TaskGetUserInfoFromLogin2(acntId);
	if (Q_UNLIKELY(task == Q_NULLPTR)) {
		return Isds::DbUserInfoExt2();
	}

	Isds::DbUserInfoExt2 user;

	task->setAutoDelete(false);
	if (GlobInstcs::workPoolPtr->runSingle(task)) {

		user = macroStdMove(task->m_user);

	}

	delete task;

	return user;
}

/*!
 * @brief Add data-box user.
 *
 * @param[in,out] acntData Account data may be changed when login credentials
 *                         are not sufficient or are wrong.
 * @param[in]     user User data.
 * @param[out]    message Status description message or error message.
 * @param[in]     syncAllActionName Synchronise all action name.
 * @param[in]     parent Parent widget.
 * @return True on success.
 */
static
bool addDataBoxUser2(AcntData &acntData, const Isds::DbUserInfoExt2 &user,
   QString &message, const QString &syncAllActionName, QWidget *parent)
{
	{
		Gui::LogInCycle login(syncAllActionName, parent);
		if (!login.logIn(*GlobInstcs::isdsSessionsPtr, acntData)) {
			return false;
		}
	}

	const AcntId acntId(acntIdFromData(acntData));

	TaskAddDataBoxUser2 *task =
	    new (::std::nothrow) TaskAddDataBoxUser2(acntId, user);
	if (Q_UNLIKELY(task == Q_NULLPTR)) {
		return false;
	}

	bool ret = false;

	task->setAutoDelete(false);
	if (GlobInstcs::workPoolPtr->runSingle(task)) {

		ret = task->m_success;

		if (ret) {
			message = DlgCreateAccount::tr("New user has been created successfully.");
			message += "\n\n";
			message += DlgCreateAccount::tr("ISDS server returns: %1")
			    .arg(task->m_status.message());
		} else {
			message = DlgCreateAccount::tr("Couldn't create a new user.");
			message += "\n\n";
			message += DlgCreateAccount::tr("ISDS server returns: %1 %2")
			    .arg(task->m_isdsError).arg(task->m_isdsLongError);
		}

	}

	delete task;

	return ret;
}

/*!
 * @brief Delete data-box user.
 *
 * @param[in,out] acntData Account data may be changed when login credentials
 *                         are not sufficient or are wrong.
 * @param[in]     isdsID User ISDS ID.
 * @param[in]     syncAllActionName Synchronise all action name.
 * @param[in]     parent Parent widget.
 * @return True on success.
 */
static
bool deleteDataBoxUser2(AcntData &acntData, const QString &isdsID,
    const QString &syncAllActionName, QWidget *parent)
{
	{
		Gui::LogInCycle login(syncAllActionName, parent);
		if (!login.logIn(*GlobInstcs::isdsSessionsPtr, acntData)) {
			return false;
		}
	}

	const AcntId acntId(acntIdFromData(acntData));

	TaskDeleteDataBoxUser2 *task =
	    new (::std::nothrow) TaskDeleteDataBoxUser2(acntId, isdsID);
	if (Q_UNLIKELY(task == Q_NULLPTR)) {
		return false;
	}

	bool ret = false;

	task->setAutoDelete(false);
	if (GlobInstcs::workPoolPtr->runSingle(task)) {

		ret = task->m_success;

	}

	delete task;

	return ret;
}

/*!
 * @brief Update data-box user.
 *
 * @param[in,out] acntData Account data may be changed when login credentials
 *                         are not sufficient or are wrong.
 * @param[in]     isdsID User ISDS ID.
 * @param[in]     user User data.
 * @param[out]    message Status description message or error message.
 * @param[in]     syncAllActionName Synchronise all action name.
 * @param[in]     parent Parent widget.
 * @return True on success.
 */
static
bool updateDataBoxUser2(AcntData &acntData, const QString &isdsID,
    const Isds::DbUserInfoExt2 &user, QString &message,
    const QString &syncAllActionName, QWidget *parent)
{
	{
		Gui::LogInCycle login(syncAllActionName, parent);
		if (!login.logIn(*GlobInstcs::isdsSessionsPtr, acntData)) {
			return false;
		}
	}

	const AcntId acntId(acntIdFromData(acntData));

	TaskUpdateDataBoxUser2 *task =
	    new (::std::nothrow) TaskUpdateDataBoxUser2(acntId, isdsID, user);
	if (Q_UNLIKELY(task == Q_NULLPTR)) {
		return false;
	}

	bool ret = false;

	task->setAutoDelete(false);
	if (GlobInstcs::workPoolPtr->runSingle(task)) {

		ret = task->m_success;

		if (ret) {
			message = DlgCreateAccount::tr("ISDS server returns: %1")
			    .arg(task->m_status.message());
		} else {
			message = DlgCreateAccount::tr("ISDS server returns: %1 %2")
			    .arg(task->m_isdsError).arg(task->m_isdsLongError);
		}

	}

	delete task;

	return ret;
}

void DlgCreateAccount::userCurrentChanged(const QModelIndex &current,
    const QModelIndex &previous)
{
	Q_UNUSED(previous);

	if (Q_UNLIKELY(!current.isValid())) {
		m_ui->userTextInfo->setText(QString());
		return;
	}

	const QModelIndex userIndex = m_userListProxyModel.mapToSource(current);
	m_ui->userTextInfo->setText(htmlMarginsApp("",
	    Html::Export::htmlDataboxUserInfoApp(
	    m_usersModel.contentAtRow(userIndex.row()))));

	/* Don't allow modifying own permissions or deleting yourself. */
	bool yoursef =
	    m_usersModel.contentAtRow(userIndex.row()).isdsID() == _user.isdsID();

	m_actionUserChangeContactAddress->setEnabled(yoursef);
	m_actionUserChangePrivils->setEnabled(!yoursef);
	m_actionUserDelete->setEnabled(!yoursef);
}

void DlgCreateAccount::refreshUsersInformation(void)
{
	m_ui->downloadUserListButton->setEnabled(false);
	m_actionUserAdd->setEnabled(false);
	m_actionUserChangeContactAddress->setEnabled(false);
	m_actionUserChangePrivils->setEnabled(false);
	m_actionUserDelete->setEnabled(false);
	m_ui->userListInfoLabel->setText(QString());

	QApplication::processEvents();

	const QModelIndex current(m_ui->treeView->currentIndex());
	enum AccountSettingsModel::NodeType currentType =
	    AccountSettingsModel::nodeType(current);

	switch (currentType) {
	case AccountSettingsModel::nodeRegularAccountUsers:
		break;
	default:
		Q_ASSERT(0);
		m_ui->downloadUserListButton->setEnabled(true);
		return;
		break;
	}

	const AcntId acntId(m_accountSettingsModel.acntId(current));

	QList<Isds::DbUserInfoExt2> allUsers;
	Isds::DbOwnerInfoExt2 owner;
	Isds::DbUserInfoExt2 user;

	{
		/* Login and download list of users. */

		AcntData acntData;
		switch (currentType) {
		case AccountSettingsModel::nodeRegularAccountUsers:
			acntData = m_regularAccounts->acntData(acntId);
			break;
		default:
			Q_ASSERT(0);
			m_ui->downloadUserListButton->setEnabled(true);
			return;
			break;
		}

		{
			AcntData newAcntData = acntData;
			owner = downloadOwnerInfoFromLogin2(
			    newAcntData, m_ui->syncAllCheckBox->text(),
			    this);
			if (!owner.isNull()) {
				/*
				 * Don't continue if owner if couldn't be
				 * downloaded.
				 */
				user = downloadUserInfoFromLogin2(
				    newAcntData, m_ui->syncAllCheckBox->text(),
				    this);
				allUsers = downloadDataBoxUsers2(newAcntData,
				    m_ui->syncAllCheckBox->text(), this);
			}
			/* Store modifications. */
			if (newAcntData != acntData) {
				switch (currentType) {
				case AccountSettingsModel::nodeRegularAccountUsers:
					/* TODO -- Update regular account data. */
					break;
				default:
					break;
				}
			}
		}
	}

	if (!allUsers.isEmpty()) {
		m_ui->userListInfoLabel->setText(
		    tr("The list contains users who have access to this data box."));
	} else {
		m_ui->userListInfoLabel->setText(
		    tr("The list of users having access to this data box could not be obtained from the server."));
	}

	if (allUsers.size() > 0) {
		m_usersModel.setContent(allUsers, user.isdsID());
	} else if (!user.isNull()) {
		/* Always show current user if available. */
		QList<Isds::DbUserInfoExt2> list;
		list.append(user);
		m_usersModel.setContent(list, user.isdsID());
	} else {
		/* Clear the model else. */
		m_usersModel.setContent(allUsers, QString());
	}
	_owner = macroStdMove(owner);
	_user = macroStdMove(user);
	m_ui->userTextInfo->setText(QString());
	m_ui->userTextInfo->setReadOnly(true);

	m_actionUserAdd->setEnabled(allUsers.size() > 0);
	m_ui->downloadUserListButton->setEnabled(true);
}

/*!
 * @brief Construct street house address line.
 *
 * @param[in] addr Address.
 * @return Line containing of street and house number line.
 */
static
QString constructHouseLine(const Isds::AddressExt2 &addr)
{
	bool addEvNoInfo = false;
	QString houseLine;

	if (!addr.street().isEmpty()) {
		houseLine = addr.street() + QChar(' ');
	} else if (!addr.district().isEmpty()) {
		houseLine = addr.district() + QChar(' ');
	} else {
		/* Add the 'ev.no.' string if evidence number supplied. */
		addEvNoInfo = true;
	}

	QString numberInMunicipality = addr.numberInMunicipality();
	const QString &numberInStreet = addr.numberInStreet();
	if (DlgUserExt2::isEvidenceNumber(numberInMunicipality)) {
		numberInMunicipality =
		    DlgUserExt2::stripEvidenceNumber(numberInMunicipality);
		if (addEvNoInfo) {
			/* CZ: "ev. č." */
			numberInMunicipality =
			    DlgCreateAccount::tr("ev. no.") + numberInMunicipality;
		}
	}

	if ((!numberInMunicipality.isEmpty()) && (!numberInStreet.isEmpty())) {
		houseLine += numberInMunicipality + QChar('/') + numberInStreet;
	} else if (!numberInMunicipality.isEmpty()) {
		houseLine += numberInMunicipality;
	} else if (!numberInStreet.isEmpty()) {
		houseLine += numberInStreet;
	}

	return houseLine;
}

/*
 * @brief Construct address to be displayed in a brief summary.
 *
 * @param[in] user User info.
 * @return Address on several lines.
 */
static
QString constructMailAddress(const Isds::DbUserInfoExt2 &user)
{
	QString nameStr;
	{
		const Isds::PersonName2 &person = user.personName();
		if (!person.isNull()) {
			nameStr = person.givenNames() + QChar(' ') + person.lastName();
			/* CZ: Narozen(a) */
			nameStr += QChar(' ') + DlgCreateAccount::tr("Born on") +
			    QChar(' ') + user.biDate().toString(Utility::dateDisplayFormat);
		}
	}

	QString addrStr;
	{
		const QString &street = user.caStreet();
		const QString &city = user.caCity();
		const QString &zip = user.caZipCode();
		const QString &state = user.caState();
		if ((!street.isEmpty()) || (!city.isEmpty()) ||
		    (!zip.isEmpty()) || (!state.isEmpty())) {
			addrStr = nameStr;
			addrStr += QChar('\n') + street;
			addrStr += QChar('\n') + zip + QChar(' ') + city;
			addrStr += QChar('\n') + state;
			return addrStr;
		}
	}
	{
		const Isds::AddressExt2 &addr = user.address();
		if (!addr.isNull()) {
			addrStr = nameStr;
			addrStr += QChar('\n') + constructHouseLine(addr);
			addrStr += QChar('\n') + addr.zipCode() + QChar(' ') + addr.city();
			addrStr += QChar('\n') + addr.state();
			return addrStr;
		}
	}

	return QString();
}

void DlgCreateAccount::addUser(void)
{
	/* View empty user dialogue window. */
	Isds::DbUserInfoExt2 newUser;
again:
	if (!DlgUserExt2::edit(newUser, _owner, DlgUserExt2::EC_ALL, this)) {
		/* Aborted by user. */
		return;
	}

	/*
	 * Message taken from web interface:
	 *
	 * Na Vaši žádost bude zřízena nová pověřená osoba k datové schránce.
	 *
	 * Pokud se podaří tuto osobu ztotožnit s registrem obyvatel a má zpřístupněnou datovou schránku fyzické osoby, budou jí přístupové údaje dodány přímo do této datové schránky.
	 * Jinak budou přístupové údaje zaslány dopisem do vlastních rukou (se žlutým pruhem) na následující adresu:
	 *
	 * adressa
	 *
	 * Prosím ujistěte se, že adresa je správná a daná osoba je na této adrese dohledatelná.
	 * V opačném případě nebude moci být dopis s přístupovými údaji doručen a daná osoba nebude mít do schránky přístup.
	 *
	 * Poznámka: Pokud bude zjištěno, že tato osoba má v Základním registru obyvatel zadanou doručovací adresu, pak budou přístupové údaje zaslány na ni, bez ohledu na výše zadanou adresu.
	 */

	{
		QString message = tr("Because of your request a new %1 is going to be created for the data box.")
		        .arg(Isds::Description::descrUserType(newUser.userType()).toLower());
		message += "\n\n";
		message += tr("If the person can be identified in the Population register and if it owns an accessible natural person data box then the login credentials will be sent directly into this data box.");
		message += QChar(' ') + tr("Otherwise the login credentials will be sent in a letter into own hands to the address:");
		message += "\n\n";
		message += constructMailAddress(newUser);
		message += "\n\n";
		message += tr("Please ensure yourself that the address is correct and the person can be found on this address.");
		message += QChar(' ') + tr("In opposite case the letter containing the login credentials won't be able to be handed in and the given person won't gain access to the data box.");
		message += "\n\n";
		message += tr("Note: If it is found that the given person's delivery address is held in the Basic population register then the login credentials will be sent to the found address regardless to the above mentioned address.");

		if (QMessageBox::Yes != QMessageBox::question(this,
		        tr("Add a New User?"), message,
		        QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel)) {
			goto again;
		}
	}

	const QModelIndex current(m_ui->treeView->currentIndex());
	enum AccountSettingsModel::NodeType currentType =
	    AccountSettingsModel::nodeType(current);

	switch (currentType) {
	case AccountSettingsModel::nodeRegularAccountUsers:
		break;
	default:
		Q_ASSERT(0);
		return;
		break;
	}

	const AcntId acntId(m_accountSettingsModel.acntId(current));

	AcntData acntData;
	switch (currentType) {
	case AccountSettingsModel::nodeRegularAccountUsers:
		acntData = m_regularAccounts->acntData(acntId);
		break;
	default:
		Q_ASSERT(0);
		return;
		break;
	}

	bool success = false;
	QString message;
	{
		AcntData newAcntData = acntData;
		success = addDataBoxUser2(newAcntData, newUser, message,
		    m_ui->syncAllCheckBox->text(), this);
		/* Store modifications. */
		if (newAcntData != acntData) {
			switch (currentType) {
			case AccountSettingsModel::nodeRegularAccountUsers:
				/* TODO -- Update regular account data. */
				break;
			default:
				break;
			}
		}
	}

	/*
	 * Message taken from web interface:
	 *
	 * Nový uživatel datové schránky byl úspěšně založen a byla mu nastavena požadovaná práva.
	 * Kdykoliv v budoucnu můžete jeho oprávnění změnit nebo zrušit.
	 *
	 * Přihlašovací údaje budou novému uživateli zaslány poštou na adresu uvedenou v této žádosti, nebo, pokud byl ztotožněn v registru obyvatel a má zpřístupněnou datovou schránku fyzické osoby, budou dodány do jeho schránky.
	 * Teprve poté se bude moci do této datové schránky přihlásit a provádět úkony podle přidělených práv.
	 *
	 * Poznámka: První přihlášení uživatele musí proběhnout přes webový portál ISDS, kde si změní přidělené heslo.
	 * Po této operaci pak bude moci používat aplikace třetích stran k přístupu do této schránky.
	 */

	if (success) {
		if (!acntData.isTestAccount()) {
			message += "\n\n" + tr("A new data-box user has successfully been created and the requested privileges have been set.") +
			    QChar(' ') + tr("You can change or withdraw his privileges at any time in future.");
			message += "\n\n" + tr("The login credentials are going delivered to the new user in a letter to the supplied address or if he was identified in the Population register and owns an accessible natural person data box then the login credentials will be sent directly into his data box.") +
			    QChar(' ') + tr("After receiving his login credentials the user will be able to log into the data box and perform actions according to the supplied user privileges.");
			message += "\n\n" + tr("Note: The user must log into the ISDS web interface to activate the created data box and change his assigned password.") +
			    QChar(' ') + tr("After this operation he will be able to use third party applications to access the data box.");
		} else {
			/* Notify the user about the fact the message contains login credentials. */
			message += "\n\n" + tr("You are using a testing environment data box.") +
			    QChar(' ') + tr("The server response displayed above directly contains the login credentials.");
			message += "\n\n" + tr("Note: The user must log into the testing instance of the ISDS web interface to activate the created data box and change his assigned password.") +
			    QChar(' ') + tr("After this operation he will be able to use third party applications to access the data box.");
		}

		QMessageBox::information(this, tr("Adding new user succeeded"),
		    message, QMessageBox::Ok);
	} else {
		QMessageBox::warning(this, tr("Adding new user failed"),
		    message, QMessageBox::Ok);
		goto again;
		return;
	}

	/* Reload user list. */
	refreshUsersInformation();
}

void DlgCreateAccount::modifyUserContactAddress(void)
{
	/* Get information about the selected user. */
	Isds::DbUserInfoExt2 user;
	{
		QModelIndexList indexes =
		    m_ui->userTableView->selectionModel()->selectedRows(0);

		if (Q_UNLIKELY(indexes.size() != 1)) {
			return;
		}

		int userRow =
		    m_userListProxyModel.mapToSource(indexes.at(0)).row();
		user = m_usersModel.contentAtRow(userRow);
	}

	Isds::DbUserInfoExt2 modifiedUser = user;
	if (!DlgUserExt2::edit(modifiedUser, _owner, DlgUserExt2::EC_CA_ADDR, this)) {
		/* Aborted by user. */
		return;
	}

	/* Take only contact address. */
	{
		QString caStreet = modifiedUser.caStreet();
		QString caCity = modifiedUser.caCity();
		QString caZipCode = modifiedUser.caZipCode();
		QString caState = modifiedUser.caState();
		modifiedUser = user;
		modifiedUser.setCaStreet(macroStdMove(caStreet));
		modifiedUser.setCaCity(macroStdMove(caCity));
		modifiedUser.setCaZipCode(macroStdMove(caZipCode));
		modifiedUser.setCaState(macroStdMove(caState));
	}

	const QModelIndex current(m_ui->treeView->currentIndex());
	enum AccountSettingsModel::NodeType currentType =
	    AccountSettingsModel::nodeType(current);

	switch (currentType) {
	case AccountSettingsModel::nodeRegularAccountUsers:
		break;
	default:
		Q_ASSERT(0);
		return;
		break;
	}

	const AcntId acntId(m_accountSettingsModel.acntId(current));

	AcntData acntData;
	switch (currentType) {
	case AccountSettingsModel::nodeRegularAccountUsers:
		acntData = m_regularAccounts->acntData(acntId);
		break;
	default:
		Q_ASSERT(0);
		return;
		break;
	}

	bool success = false;
	QString message;
	{
		AcntData newAcntData = acntData;
		success = updateDataBoxUser2(newAcntData, modifiedUser.isdsID(),
		    modifiedUser, message, m_ui->syncAllCheckBox->text(), this);
		/* Store modifications. */
		if (newAcntData != acntData) {
			switch (currentType) {
			case AccountSettingsModel::nodeRegularAccountUsers:
				/* TODO -- Update regular account data. */
				break;
			default:
				break;
			}
		}
	}

	if (success) {
		QMessageBox::information(this, tr("User modification succeeded"),
		    message, QMessageBox::Ok);
	} else {
		QMessageBox::warning(this, tr("User modification failed"),
		    message, QMessageBox::Ok);
		return;
	}

	/* Reload user list. */
	refreshUsersInformation();
}

void DlgCreateAccount::modifyUserPrivileges(void)
{
	/* Get information about the selected user. */
	Isds::DbUserInfoExt2 user;
	{
		QModelIndexList indexes =
		    m_ui->userTableView->selectionModel()->selectedRows(0);

		if (Q_UNLIKELY(indexes.size() != 1)) {
			return;
		}

		int userRow =
		    m_userListProxyModel.mapToSource(indexes.at(0)).row();
		user = m_usersModel.contentAtRow(userRow);
	}

	Isds::DbUserInfoExt2 modifiedUser = user;
	if (!DlgUserExt2::edit(modifiedUser, _owner, DlgUserExt2::EC_PERMISSIONS, this)) {
		/* Aborted by user. */
		return;
	}

	/* Take only privileges. */
	{
		Isds::Type::Privileges privileges = modifiedUser.userPrivils();
		modifiedUser = user;
		modifiedUser.setUserPrivils(privileges);
	}

	const QModelIndex current(m_ui->treeView->currentIndex());
	enum AccountSettingsModel::NodeType currentType =
	    AccountSettingsModel::nodeType(current);

	switch (currentType) {
	case AccountSettingsModel::nodeRegularAccountUsers:
		break;
	default:
		Q_ASSERT(0);
		return;
		break;
	}

	const AcntId acntId(m_accountSettingsModel.acntId(current));

	AcntData acntData;
	switch (currentType) {
	case AccountSettingsModel::nodeRegularAccountUsers:
		acntData = m_regularAccounts->acntData(acntId);
		break;
	default:
		Q_ASSERT(0);
		return;
		break;
	}

	bool success = false;
	QString message;
	{
		AcntData newAcntData = acntData;
		success = updateDataBoxUser2(newAcntData, modifiedUser.isdsID(),
		    modifiedUser, message, m_ui->syncAllCheckBox->text(), this);
		/* Store modifications. */
		if (newAcntData != acntData) {
			switch (currentType) {
			case AccountSettingsModel::nodeRegularAccountUsers:
				/* TODO -- Update regular account data. */
				break;
			default:
				break;
			}
		}
	}

	if (success) {
		QMessageBox::information(this, tr("User modification succeeded"),
		    message, QMessageBox::Ok);
	} else {
		QMessageBox::warning(this, tr("User modification failed"),
		    message, QMessageBox::Ok);
		return;
	}

	/* Reload user list. */
	refreshUsersInformation();
}

void DlgCreateAccount::deleteUser(void)
{
	int userRow;

	/* Get information about the selected user. */
	{
		QModelIndexList indexes =
		    m_ui->userTableView->selectionModel()->selectedRows(0);

		if (Q_UNLIKELY(indexes.size() != 1)) {
			return;
		}

		userRow = m_userListProxyModel.mapToSource(indexes.at(0)).row();
	}

	if (Q_UNLIKELY(userRow < 0)) {
		Q_ASSERT(0);
		return;
	}

	/* Ask whether to delete the selected user. */
	QString isdsID;
	QString name;
	{
		const Isds::DbUserInfoExt2 &user =
		     m_usersModel.contentAtRow(userRow);
		{
			const Isds::PersonName2 &personName = user.personName();

			name = personName.givenNames() +
			    QChar(' ') + personName.lastName();
		}

		if (QMessageBox::Yes != QMessageBox::question(this,
		        tr("Delete User?"),
		        tr("Do you want to delete the user '%1'?").arg(name),
		        QMessageBox::Yes | QMessageBox::No, QMessageBox::No)) {
			return;
		}

		isdsID = user.isdsID();
	}

	const QModelIndex current(m_ui->treeView->currentIndex());
	enum AccountSettingsModel::NodeType currentType =
	    AccountSettingsModel::nodeType(current);

	switch (currentType) {
	case AccountSettingsModel::nodeRegularAccountUsers:
		break;
	default:
		Q_ASSERT(0);
		return;
		break;
	}

	const AcntId acntId(m_accountSettingsModel.acntId(current));

	AcntData acntData;
	switch (currentType) {
	case AccountSettingsModel::nodeRegularAccountUsers:
		acntData = m_regularAccounts->acntData(acntId);
		break;
	default:
		Q_ASSERT(0);
		return;
		break;
	}

	bool success = false;
	QString message;
	{
		AcntData newAcntData = acntData;
		success = deleteDataBoxUser2(newAcntData, isdsID,
		    m_ui->syncAllCheckBox->text(), this);
		/* Store modifications. */
		if (newAcntData != acntData) {
			switch (currentType) {
			case AccountSettingsModel::nodeRegularAccountUsers:
				/* TODO -- Update regular account data. */
				break;
			default:
				break;
			}
		}
	}

	if (!success) {
		QMessageBox::warning(this, tr("Adding new user failed"),
		    tr("User '%1' could not be deleted.").arg(name),
		    QMessageBox::Ok);
		return;
	}

	/* Reload user list. */
	refreshUsersInformation();
}

/*!
 * @brief Conversion function.
 *
 * @param[in] method Login method.
 * @return Combo box index.
 */
static
enum LoginMethodIndex loginMethodToIndex(enum AcntSettings::LoginMethod method)
{
	switch (method) {
	case AcntSettings::LIM_UNAME_PWD:
		return USER_NAME;
		break;
	case AcntSettings::LIM_UNAME_CRT:
		return CERTIFICATE;
		break;
	case AcntSettings::LIM_UNAME_PWD_CRT:
		return USER_CERTIFICATE;
		break;
	case AcntSettings::LIM_UNAME_PWD_HOTP:
		return HOTP;
		break;
	case AcntSettings::LIM_UNAME_PWD_TOTP:
		return TOTP;
		break;
	case AcntSettings::LIM_UNAME_MEP:
		return MEP;
		break;
	default:
		Q_ASSERT(0);
		return USER_NAME;
		break;
	}
}

/*!
 * @brief Conversion function.
 *
 * @param[in] Combo box index.
 * @return Login method.
 */
static
enum AcntSettings::LoginMethod indexToLoginMethod(int index)
{
	switch (index) {
	case USER_NAME:
		return AcntSettings::LIM_UNAME_PWD;
		break;
	case CERTIFICATE:
		return AcntSettings::LIM_UNAME_CRT;
		break;
	case USER_CERTIFICATE:
		return AcntSettings::LIM_UNAME_PWD_CRT;
		break;
	case HOTP:
		return AcntSettings::LIM_UNAME_PWD_HOTP;
		break;
	case TOTP:
		return AcntSettings::LIM_UNAME_PWD_TOTP;
		break;
	case MEP:
		return AcntSettings::LIM_UNAME_MEP;
		break;
	default:
		Q_ASSERT(0);
		return AcntSettings::LIM_UNKNOWN;
		break;
	}
}

void DlgCreateAccount::setContent(const AcntData &acntData, int properties)
{
	m_accountInfo = acntData;

	if (Q_UNLIKELY(acntData.userName().isEmpty())) {
		m_ui->infoLabel->setEnabled(false);
		m_ui->acntNameLine->clear();
		m_ui->usernameLine->clear();
		m_ui->testAcntCheckBox->setCheckState(Qt::Unchecked);
		m_ui->loginMethodComboBox->setCurrentIndex(USER_NAME);
		m_ui->pwdLine->clear();
		m_ui->rememberPwdCheckBox->setCheckState(Qt::Unchecked);
		m_ui->mepLine->clear();
		m_ui->syncAllCheckBox->setEnabled((properties & FC_EDITABLE) && (!(properties & FC_SHADOW_ACNT)));
		m_ui->syncAllCheckBox->setCheckState(Qt::Unchecked);
		return;
	}

	m_ui->infoLabel->setEnabled(true);

	QString windowTitle(this->windowTitle());

	switch (m_action) {
	case ACT_EDIT:
		windowTitle = tr("Update data box %1")
		    .arg(acntData.accountName());
		m_ui->infoLabel->setEnabled(true);
		m_ui->acntNameLine->setEnabled(true);
		break;
	case ACT_PWD:
		windowTitle = tr("Enter password for data box %1")
		    .arg(acntData.accountName());
		m_ui->infoLabel->setEnabled(false);
		m_ui->acntNameLine->setEnabled(false);
		m_ui->loginMethodComboBox->setEnabled(false);
		m_ui->addCertButton->setEnabled(false);
		break;
	case ACT_CERT:
		windowTitle = tr("Set certificate for data box %1")
		    .arg(acntData.accountName());
		m_ui->infoLabel->setEnabled(false);
		m_ui->acntNameLine->setEnabled(false);
		m_ui->loginMethodComboBox->setEnabled(false);
		m_ui->pwdLine->setEnabled(false);
		m_ui->showHidePwdButton->setEnabled(false);
		break;
	case ACT_CERTPWD:
		windowTitle = tr("Enter password/certificate for data box %1")
		    .arg(acntData.accountName());
		m_ui->infoLabel->setEnabled(false);
		m_ui->acntNameLine->setEnabled(false);
		m_ui->loginMethodComboBox->setEnabled(false);
		break;
	case ACT_MEP:
		windowTitle = tr("Enter communication code for data box %1")
		    .arg(acntData.accountName());
		m_ui->infoLabel->setEnabled(false);
		m_ui->acntNameLine->setEnabled(false);
		m_ui->loginMethodComboBox->setEnabled(false);
		break;
	default:
		Q_ASSERT(0);
		break;
	}

	setWindowTitle(windowTitle);
	m_ui->acntNameLine->setText(acntData.accountName());
	m_ui->usernameLine->setText(acntData.userName());
	m_ui->usernameLine->setEnabled((m_action == ACT_EDIT) || (m_action == ACT_ADDNEW));
	m_ui->testAcntCheckBox->setEnabled(m_action == ACT_ADDNEW);

	enum LoginMethodIndex itemIdx =
	    loginMethodToIndex(acntData.loginMethod());
	m_ui->loginMethodComboBox->setCurrentIndex(itemIdx);
	activateContent(itemIdx);

	m_ui->testAcntCheckBox->setChecked(acntData.isTestAccount());
	m_ui->pwdLine->setText(acntData.password());
	m_ui->rememberPwdCheckBox->setChecked(acntData.rememberPwd());
	m_ui->mepLine->setText(acntData.mepToken());
	m_ui->syncAllCheckBox->setChecked((!(properties & FC_SHADOW_ACNT)) && acntData.syncWithAll());

	if (!acntData.p12File().isEmpty()) {
		QFileInfo fileInfo(acntData.p12File());
		m_ui->addCertButton->setText(fileInfo.fileName());
		if (fileInfo.exists() && fileInfo.isFile() &&
		    fileInfo.isReadable()) {
			m_ui->addCertButton->setIcon(IconContainer::construcIcon(
			    IconContainer::ICON_DATOVKA_STOCK_KEY));
			m_ui->addCertButton->setToolTip(acntData.p12File());
		} else {
			m_ui->addCertButton->setIcon(IconContainer::construcIcon(
			    IconContainer::ICON_WARNING));
			m_ui->addCertButton->setToolTip(tr("File does not exists or cannot be read."));
		}
		m_certPath = QDir::toNativeSeparators(acntData.p12File());
	} else {
		m_ui->addCertButton->setIcon(IconContainer::construcIcon(
		    IconContainer::ICON_FOLDER));
		m_ui->addCertButton->setText(tr("Select File"));
		m_ui->addCertButton->setToolTip(tr("Select a certificate."));
	}

	if (!(properties & FC_EDITABLE)) {
		m_ui->infoLabel->setEnabled(false);
		m_ui->acntNameLine->setEnabled(false);
		m_ui->usernameLine->setEnabled(false);
		m_ui->testAcntCheckBox->setEnabled(false);
		m_ui->loginMethodComboBox->setEnabled(false);
		m_ui->pwdLine->setEnabled(false);
		m_ui->rememberPwdCheckBox->setEnabled(false);
		m_ui->mepLine->setEnabled(false);
		m_ui->addCertButton->setEnabled(false);
	}
	/* Disable for shadow accounts. */
	m_ui->syncAllCheckBox->setEnabled(
	    (properties & FC_EDITABLE) && (!(properties & FC_SHADOW_ACNT)));

	checkInputFields();
}

void DlgCreateAccount::loadPrivilegesContent(const AcntId &acntId,
    enum AccountSettingsModel::NodeType nodeType)
{
	switch (nodeType) {
	case AccountSettingsModel::nodeRegularAccountInfo:
		m_ui->accountInfoLabel->setVisible(m_shadowAccounts != Q_NULLPTR);
		m_ui->downloadAccountInfoButton->setVisible(true);
		if (m_shadowAccounts != Q_NULLPTR) { /* m_ui->accountInfoLabel->isVisible() */
			QList<AcntId> shadowAcnts =
			    ShadowHelper::usableBackgroundAccounts(
			        acntId, *m_regularAccounts, *m_shadowAccounts);
			if (!shadowAcnts.isEmpty()) {
				QString text = tr("The following shadow data boxes can be used by this data box:");
				foreach (const AcntId &sAcntId, shadowAcnts) {
					const AcntData acntData = m_shadowAccounts->acntData(sAcntId);
					text += "\n- " + acntData.accountName() + " (" + acntData.userName() + ")";
				}
				m_ui->accountInfoLabel->setText(text);
			} else {
				m_ui->accountInfoLabel->setText(
				    tr("There is no shadow data box available for this data box."));
			}
		}
		m_ui->accountTextInfo->setHtml(htmlAccountInfo(
		    m_regularAccounts->acntData(acntId),
		    GlobInstcs::msgDbsPtr->accessOpenedDbSet(acntId)));
		break;
	case AccountSettingsModel::nodeShadowAccountInfo:
		m_ui->accountInfoLabel->setVisible(m_shadowAccounts != Q_NULLPTR);
		m_ui->downloadAccountInfoButton->setVisible(true);
		if (m_shadowAccounts != Q_NULLPTR) { /* m_ui->accountInfoLabel->isVisible() */
			if (ShadowHelper::isUsableBackgroundAccount(acntId,
			        *m_shadowAccounts)) {
				QString text = tr(
				    "This data box can be used to download message lists in background because:\n"
				    "- It cannot download any received message because of low access privileges and thus won't cause any message to be accepted.\n"
				    "- It uses a login procedure which does not require user interaction (username and password) and all login credentials are remembered by the application."
				);
				QList<AcntId> regularAcnts =
				    ShadowHelper::availableForegroundAccounts(
				        acntId, *m_regularAccounts, *m_shadowAccounts);
				if (!regularAcnts.isEmpty()) {
					text += "\n\n" + tr("The following regular data boxes may utilise this data box:");
					foreach (const AcntId &rAcntId, regularAcnts) {
						const AcntData acntData = m_regularAccounts->acntData(rAcntId);
						text += "\n- " + acntData.accountName() + " (" + acntData.userName() + ")";
					}
				}
				m_ui->accountInfoLabel->setText(text);
			} else {
				m_ui->accountInfoLabel->setText(
				    tr("This data box won't be used to download message lists in background because it doesn't meet the following requirements:\n"
				        "- The data box must have low access privileges. It must be able to download message lists but it must be prohibited from downloading received messages.\n"
				        "- It must use a login procedure which does not require user interaction (username and password) and complete login credentials must be remembered by the application."));
			}
		}
		if (m_shadowAccounts != Q_NULLPTR) {
			m_ui->accountTextInfo->setHtml(htmlAccountInfo(
			    m_shadowAccounts->acntData(acntId),
			    GlobInstcs::msgDbsPtr->accessOpenedDbSet(acntId)));
		} else {
			m_ui->accountTextInfo->setHtml(QString());
		}
		break;
	default:
		m_ui->accountInfoLabel->setVisible(false);
		m_ui->downloadAccountInfoButton->setVisible(false);
		m_ui->accountTextInfo->setText(QString());
		m_ui->accountTextInfo->setReadOnly(true);
		return;
		break;
	}

	m_ui->accountTextInfo->setReadOnly(true);
}

void DlgCreateAccount::setPwdLineEchoMode(int echoMode)
{
	enum QLineEdit::EchoMode mode = QLineEdit::Password;
	QString buttonLabel(tr("View"));

	switch (echoMode) {
	case QLineEdit::Normal:
		mode = QLineEdit::Normal;
		buttonLabel = tr("Hide");
		break;
	case QLineEdit::Password:
		break;
	default:
		Q_ASSERT(0);
		break;
	}

	if (mode == QLineEdit::Password) {
		m_hidePwdTimer.stop();
		m_ui->viewPwdProgress->setVisible(false);
	}
	m_ui->pwdLine->setEchoMode(mode);
	m_ui->showHidePwdButton->setText(buttonLabel);
	if (mode == QLineEdit::Normal) {
		m_ui->viewPwdProgress->setVisible(true);
		m_ui->viewPwdProgress->setMinimum(0);
		m_viewPwdRemainingCycles = m_viewPwdDuration / m_viewPwdUpdate;
		m_ui->viewPwdProgress->setMaximum(m_viewPwdRemainingCycles);
		m_ui->viewPwdProgress->setValue(m_viewPwdRemainingCycles);
		m_hidePwdTimer.start(m_viewPwdUpdate);
	}
}

AcntData DlgCreateAccount::getContent(void) const
{
	AcntData newAcntSettings;

	switch (m_action) {
	case ACT_ADDNEW:
		/*
		 * Set to true only for newly created account.
		 * Don't set it to false when account is edited because a
		 * newly created account can also be edited in case the first
		 * account creation attempt failed.
		 */
		newAcntSettings._setCreatedFromScratch(true);
		break;
	case ACT_EDIT:
	case ACT_PWD:
	case ACT_CERT:
	case ACT_CERTPWD:
	case ACT_MEP:
		Q_ASSERT(!m_accountInfo.userName().isEmpty());
		newAcntSettings = m_accountInfo;
		break;
	default:
		Q_ASSERT(0);
		break;
	}

	/* Set account entries. */
	newAcntSettings.setAccountName(m_ui->acntNameLine->text().trimmed());
	newAcntSettings.setUserName(m_ui->usernameLine->text().trimmed());
	newAcntSettings.setTestAccount(m_ui->testAcntCheckBox->isChecked());
	newAcntSettings.setPassword(m_ui->pwdLine->text());
	newAcntSettings.setRememberPwd(m_ui->rememberPwdCheckBox->isChecked());
	newAcntSettings.setSyncWithAll(m_ui->syncAllCheckBox->isChecked());

	newAcntSettings.setLoginMethod(
	    indexToLoginMethod(m_ui->loginMethodComboBox->currentIndex()));
	switch (m_ui->loginMethodComboBox->currentIndex()) {
	case CERTIFICATE:
		newAcntSettings.setPassword(QString());
		newAcntSettings.setP12File(
		    QDir::fromNativeSeparators(m_certPath));
		break;
	case USER_CERTIFICATE:
		newAcntSettings.setP12File(
		    QDir::fromNativeSeparators(m_certPath));
		break;
	case USER_NAME:
	case HOTP:
	case TOTP:
		newAcntSettings.setP12File(QString());
		break;
	case MEP:
		newAcntSettings.setMepToken(m_ui->mepLine->text());
		newAcntSettings.setP12File(QString());
		break;
	default:
		Q_ASSERT(0);
		break;
	}

	return newAcntSettings;
}
