/*
 *  Copyright (C) 2007-2008 CMM Sigma Andrzej Chmielowiec <cmmsigma@cmmsigma.eu>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 3
 *  as published by the Free Software Foundation.
 *
 *  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.
 */

#include <QtGui>

#include <stdlib.h>
#include <string.h>
#include <QObject>

#include "STokenItem.h"
#include "STokenKeysFolderItem.h"
#include "STokenFilesFolderItem.h"

#include "GenInfoWidget.h"
#include "AdminWidget.h"
#include "LoginWidget.h"
#include "RbgWidget.h"
#include "DetInfoWidget.h"
#include "ProgressWidget.h"

#include "crd_ut10xx.h"
#include "CRD_UT10XX_threads.h"

#include "QDetailsMessageBox.h"
#include "MainWindow.h"

STokenItem::STokenItem(CRD_UT10XX_t *ut, TreeItem *parent): TreeItem(parent)
{
	mPin = 0;
	mSoPin = 0;
	mUserPin = 0;
	mPinId = -1;
	
	mUt = ut;
	
	mMainTabWidget = new QTabWidget;
	connect(mMainTabWidget, SIGNAL(currentChanged(int)), this, SLOT(currentChangedSlot(int)));
	
	// General information page.
	mGenInfoWidget = new GenInfoWidget();
	
	connect(mGenInfoWidget, SIGNAL(confSig(const char*, int, const char*, int, 
		const char*, bool)), this, SLOT(confSlot(const char*, int, const char*, 
		int, const char*, bool)));
	connect(mGenInfoWidget, SIGNAL(unLockSig(const char*)), this, 
		SLOT(unLockSlot(const char*)));
	
	// Administration and configuration page.
	mAdminWidget = new AdminWidget();
	
	connect(this, SIGNAL(soLoginSig()), mAdminWidget, SLOT(enableSoMenu()));
	connect(this, SIGNAL(userLoginSig()), mAdminWidget, SLOT(enableUserMenu()));
	connect(this, SIGNAL(logoutSig()), mAdminWidget, SLOT(disableMenu()));
	connect(mAdminWidget, SIGNAL(userPinChangeSig(const char*)), this, 
		SLOT(userPinChangeSlot(const char*)));
	connect(mAdminWidget, SIGNAL(soPinChangeSig(const char*)), this, 
		SLOT(soPinChangeSlot(const char*)));
	connect(mAdminWidget, SIGNAL(eraseSig()), this, SLOT(eraseSlot()));
	
	// Login page.
	mLoginWidget = new LoginWidget();
	
	connect(mLoginWidget, SIGNAL(soLoginSig(const char*, bool&)), this, 
		SLOT(soLoginSlot(const char*, bool&)));
	connect(mLoginWidget, SIGNAL(userLoginSig(const char*, bool&)), this, 
		SLOT(userLoginSlot(const char*, bool&)));
	connect(mLoginWidget, SIGNAL(logoutSig()), this, SLOT(logoutSlot()));
	
#	ifdef WITH_RBG
	// RBG page.
	mRbgWidget = new RbgWidget();
	
	connect(mRbgWidget, SIGNAL(generateSig(int, int, QString&)), this, 
		SLOT(rbgSlot(int, int, QString&)));
#	endif
	
#	ifdef WITH_DET_INFO
	// Detail description page.
	mDetInfoWidget = new DetInfoWidget();
#	endif
	
	setPage(mMainTabWidget);
}

STokenItem::~STokenItem()
{
}

int
STokenItem::libIndex()
{
	return (CRD_UT10XX_find_index_of(mUt));
}

void
STokenItem::refresh()
{
	static const QIcon cGenInfoIcon(QString(":img/info.png"));
	static const QIcon cAdminIcon(QString(":img/utils.png"));
	static const QIcon cLoginIcon(QString(":img/login.png"));
	static const QIcon cRbgIcon(QString(":img/random.png"));
	static const QIcon cDetInfoIcon(QString(":img/details.png"));
	
	CRD_UT10XX_info_t *info = &(mUt->info);
	
	// General information page.
	mGenInfoWidget->setInfo(mUt);
	if (mMainTabWidget->indexOf(mGenInfoWidget) == -1)
	{
		mMainTabWidget->addTab(mGenInfoWidget, cGenInfoIcon, tr("General"));
	}
	
	// Login page.
	if (sTokenState() == StateConf)
	{
		mLoginWidget->setInfo(info);
		
		if (mMainTabWidget->indexOf(mLoginWidget) == -1)
		{
			mMainTabWidget->insertTab(mMainTabWidget->indexOf(mGenInfoWidget) + 1, 
				mLoginWidget, cLoginIcon, tr("Login"));
		}
	}
	else
	{
		mMainTabWidget->removeTab(mMainTabWidget->indexOf(mLoginWidget));
	}
	
	// Administration page.
	if (sTokenState() == StateConf)
	{
		if (mMainTabWidget->indexOf(mAdminWidget) == -1)
		{
			mMainTabWidget->insertTab(mMainTabWidget->indexOf(mLoginWidget) + 1, 
				mAdminWidget, cAdminIcon, tr("Settings"));
		}
	}
	else
	{
		mMainTabWidget->removeTab(mMainTabWidget->indexOf(mAdminWidget));
	}
	
#	ifdef WITH_RBG
	// RBG page.
	if (mMainTabWidget->indexOf(mRbgWidget) == -1)
		mMainTabWidget->addTab(mRbgWidget, cRbgIcon, tr("RBG"));
#	endif
	
#	ifdef WITH_DET_INFO
	// Detail description page.
	if (mMainTabWidget->indexOf(mDetInfoWidget) == -1)
		mMainTabWidget->addTab(mDetInfoWidget, cDetInfoIcon, tr("Details"));
#	endif
	
	// Token view.
	QVariant tokenIcon;
	QVariant name;
	
	if (trUtf8(info->name).isEmpty())
		name = QString("[") + trUtf8(mUt->serial_number) + QString("]");
	else
		name = trUtf8(info->name);
	
	if (sTokenState() == StateConf && mSoPin)
		tokenIcon = QIcon(QString(":img/stoken_login_so.png"));
	
	else if (sTokenState() == StateConf && mUserPin)
		tokenIcon = QIcon(QString(":img/stoken_login_user.png"));
	
	else if (sTokenState() == StateConf)
		tokenIcon = QIcon(QString(":img/stoken.png"));
	
	else if (sTokenState() == StateLock)
		tokenIcon = QIcon(QString(":img/stoken_lock.png"));
	
	else
		tokenIcon = QIcon(QString(":img/stoken_no.png"));
	
	setData(name, Qt::DisplayRole);
	setData(tokenIcon, Qt::DecorationRole);
	
	// Child folders.
	if (sTokenState() == StateConf && childCount() == 0)
	{
		STokenKeysFolderItem *keys = new STokenKeysFolderItem(mUt, this);
		model()->appendChild(this, keys);
		
		connect(this, SIGNAL(soLoginSig()), keys, SLOT(soLoginSlot()));
		connect(this, SIGNAL(userLoginSig()), keys, SLOT(userLoginSlot()));
		connect(this, SIGNAL(logoutSig()), keys, SLOT(logoutSlot()));
		connect(keys, SIGNAL(deleteKeySig(int)), this, SLOT(deleteKeySlot(int)));
		connect(keys, SIGNAL(generateKeySig(const char*, int)), this, 
			SLOT(generateKeySlot(const char*, int)));
		connect(keys, SIGNAL(generateCertReqSig(int, QString&, QStringList&, QString&)), 
			this, SLOT(generateCertReqSlot(int, QString&, QStringList&, QString&)));
		
		STokenFilesFolderItem *files = new STokenFilesFolderItem(mUt, this);
		model()->appendChild(this, files);
		
		connect(this, SIGNAL(soLoginSig()), files, SLOT(soLoginSlot()));
		connect(this, SIGNAL(userLoginSig()), files, SLOT(userLoginSlot()));
		connect(this, SIGNAL(logoutSig()), files, SLOT(logoutSlot()));
		connect(files, SIGNAL(addFileSig(QString&, QString&)), this, 
			SLOT(addFileSlot(QString&, QString&)));
		connect(files, SIGNAL(deleteFileSig(QString&)), this, 
			SLOT(deleteFileSlot(QString&)));
		connect(files, SIGNAL(saveFileSig(QString&, QString&)), this, 
			SLOT(saveFileSlot(QString&, QString&)));
	}
	else if (sTokenState() != StateConf && childCount() != 0)
	{
		model()->deleteAllChilds(this);
	}
	
	for (int i = 0; i < childCount(); i++)
		child(i)->refresh();
	
	if (mSoPin)
		emit soLoginSig();
	
	else if (mUserPin)
		emit userLoginSig();
}

void
STokenItem::confSlot(const char *name, int soPinLim, const char *soPin, int userPinLim, 
	const char *userPin, bool upcna)
{
	bool error = false;
	
	memset(&mUt->conf, 0, sizeof(CRD_UT10XX_conf_t));
	
	if (upcna)
		mUt->conf.info |= (1 << 4);
	
	strncpy(mUt->conf.name, name, 11);
	mUt->conf.so_pin_limit = soPinLim;
	strncpy(mUt->conf.so_pin, soPin, 8);
	mUt->conf.user_pin_limit = userPinLim;
	strncpy(mUt->conf.user_pin, userPin, 8);
	
	QMessageBox::information(MainWindow::mainWnd, tr("Information"), tr("Token initialization may take up to one minute. Please be patient."));
	
	CRD_UT10XX_session_open(mUt);
	
	if (sTokenState() == StateClear)
	{
		CRD_UT10XX_thread_cmd_dev_init devInitThread(mUt);
		
		if (!error && devInitThread.execWithCursor(Qt::WaitCursor) < 0)
		{
			QMessageBox::critical(MainWindow::mainWnd, tr("Error"), devInitThread.errorString());
			error = true;
		}
	}
	
	CRD_UT10XX_thread_cmd_read_dev_info readDevInfoThread(mUt);
	
	if (!error && readDevInfoThread.execWithCursor(Qt::WaitCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), readDevInfoThread.errorString());
		error = true;
	}
	
	if (sTokenState() == StateInit)
	{
		CRD_UT10XX_thread_cmd_dev_conf devConfThread(mUt);
		
		if (!error && devConfThread.execWithCursor(Qt::WaitCursor) < 0)
		{
			QMessageBox::critical(MainWindow::mainWnd, tr("Error"), devConfThread.errorString());
			error = true;
		}
	}
	
	if (!error && readDevInfoThread.execWithCursor(Qt::WaitCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), readDevInfoThread.errorString());
		error = true;
	}
	
	CRD_UT10XX_session_close(mUt);
	
	model()->repaintItemData(this);
	model()->refresh();
}

void
STokenItem::unLockSlot(const char *soPin)
{
	bool error = false;
	
	CRD_UT10XX_session_open(mUt);
	
	CRD_UT10XX_thread_cmd_dev_unlock devUnlockThread(mUt, soPin);
	
	if (!error && devUnlockThread.execWithCursor(Qt::ArrowCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Incorrect password."));
	}
	
	CRD_UT10XX_thread_cmd_read_dev_info readDevInfoThread(mUt);
	
	if (!error && readDevInfoThread.execWithCursor(Qt::ArrowCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), readDevInfoThread.errorString());
		error = true;
	}
	
	CRD_UT10XX_session_close(mUt);
	
	model()->repaintItemData(this);
	model()->refresh();
}

void
STokenItem::soLoginSlot(const char *pin, bool &correct)
{
	CRD_UT10XX_session_open(mUt);
	
	CRD_UT10XX_thread_cmd_try_pin tryPinThread(mUt, pin, CRD_UT10XX_SO_PIN_ID);
	
	if (tryPinThread.execWithCursor(Qt::ArrowCursor) < 0)
	{
		correct = false;
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Incorrect password."));
	}
	else
	{
		correct = true;
		mPin = pin;
		mSoPin = pin;
		mUserPin = 0;
		mPinId = CRD_UT10XX_SO_PIN_ID;
	}
	
	CRD_UT10XX_thread_cmd_read_dev_info readDevInfoThread(mUt);
	
	if (readDevInfoThread.execWithCursor(Qt::ArrowCursor) < 0)
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), readDevInfoThread.errorString());
	
	CRD_UT10XX_session_close(mUt);
	
	refresh();
	
	if (correct)
	{
		QVariant tokenIcon = QIcon(QString(":img/stoken_login_so.png"));
		setData(tokenIcon, Qt::DecorationRole);
	}
	
	model()->repaintItemData(this);
	
	if (correct)
		emit soLoginSig();
}

void
STokenItem::userLoginSlot(const char *pin, bool &correct)
{
	CRD_UT10XX_session_open(mUt);
	
	CRD_UT10XX_thread_cmd_try_pin tryPinThread(mUt, pin, CRD_UT10XX_USER_PIN_ID);
	
	if (tryPinThread.execWithCursor(Qt::ArrowCursor) < 0)
	{
		correct = false;
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Incorrect password."));
	}
	else
	{
		correct = true;
		mPin = pin;
		mSoPin = 0;
		mUserPin = pin;
		mPinId = CRD_UT10XX_USER_PIN_ID;
	}
	
	CRD_UT10XX_thread_cmd_read_dev_info readDevInfoThread(mUt);
	
	if (readDevInfoThread.execWithCursor(Qt::ArrowCursor) < 0)
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), readDevInfoThread.errorString());
	
	CRD_UT10XX_session_close(mUt);
	
	refresh();
	
	if (correct)
	{
		QVariant tokenIcon = QIcon(QString(":img/stoken_login_user.png"));
		setData(tokenIcon, Qt::DecorationRole);
	}
	
	model()->repaintItemData(this);
	
	if (correct)
		emit userLoginSig();
}

void
STokenItem::logoutSlot()
{
	mPin = 0;
	mSoPin = 0;
	mUserPin = 0;
	mPinId = -1;
	refresh();
	model()->repaintItemData(this);
	
	emit logoutSig();
}

void
STokenItem::userPinChangeSlot(const char *newPin)
{
	bool error = false;
	
	CRD_UT10XX_session_open(mUt);
	
	CRD_UT10XX_thread_cmd_change_user_pin changeUserPinThread(mUt, mPin, mPinId, newPin);
	
	if (!error && changeUserPinThread.execWithCursor(Qt::WaitCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), changeUserPinThread.errorString());
		error = true;
	}
	
	CRD_UT10XX_thread_cmd_read_dev_info readDevInfoThread(mUt);
	
	if (!error && readDevInfoThread.execWithCursor(Qt::WaitCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), readDevInfoThread.errorString());
		error = true;
	}
		
	CRD_UT10XX_session_close(mUt);
	
	if (mUserPin)
		mLoginWidget->logoutSlot();
}

void
STokenItem::soPinChangeSlot(const char *newPin)
{
	bool error = false;
	
	CRD_UT10XX_session_open(mUt);
	
	CRD_UT10XX_thread_cmd_change_so_pin changeSoPinThread(mUt, mSoPin, newPin);
	
	if (!error && changeSoPinThread.execWithCursor(Qt::WaitCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), changeSoPinThread.errorString());
		error = true;
	}
	
	CRD_UT10XX_thread_cmd_read_dev_info readDevInfoThread(mUt);
	
	if (!error && readDevInfoThread.execWithCursor(Qt::WaitCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), readDevInfoThread.errorString());
		error = true;
	}
	
	CRD_UT10XX_session_close(mUt);
	
	mLoginWidget->logoutSlot();
}

void
STokenItem::eraseSlot()
{
	bool error = false;
	
	CRD_UT10XX_session_open(mUt);
	
	CRD_UT10XX_thread_cmd_dev_erase devEraseThread(mUt, mSoPin);
	
	if (!error && devEraseThread.execWithCursor(Qt::WaitCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), devEraseThread.errorString());
		error = true;
	}
	
	CRD_UT10XX_thread_cmd_read_dev_info readDevInfoThread(mUt);
	
	if (!error && readDevInfoThread.execWithCursor(Qt::WaitCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), readDevInfoThread.errorString());
		error = true;
	}
	
	CRD_UT10XX_session_close(mUt);
	
	mLoginWidget->logoutSlot();
}

void
STokenItem::generateKeySlot(const char *name, int id)
{
	bool error = false;
	
	CRD_UT10XX_session_open(mUt);
	
	CRD_UT10XX_thread_cmd_generate_key generateKeyThread(mUt, mPin, mPinId, name, id);
	
	if (!error && generateKeyThread.execWithCursor(Qt::WaitCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), generateKeyThread.errorString());
		error = true;
	}
	
	CRD_UT10XX_thread_cmd_read_dev_info readDevInfoThread(mUt);
	
	if (!error && readDevInfoThread.execWithCursor(Qt::WaitCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), readDevInfoThread.errorString());
		error = true;
	}
	
	for (int i = 0; i < 4; i++)
	{
		if (!error && CRD_UT10XX_cmd_read_key_info(mUt, i) < 0)
		{
			QMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr(CRD_UT10XX_lib_detail_error_desc(mUt)));
			error = true;
		}
	}
	
	CRD_UT10XX_session_close(mUt);
	
	refresh();
}

void
STokenItem::deleteKeySlot(int id)
{
	bool error = false;
	
	CRD_UT10XX_session_open(mUt);
	
	CRD_UT10XX_thread_cmd_delete_key deleteKeyThread(mUt, mPin, mPinId, id);
	
	if (!error && deleteKeyThread.execWithCursor(Qt::WaitCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), deleteKeyThread.errorString());
	}
	
	CRD_UT10XX_thread_cmd_read_dev_info readDevInfoThread(mUt);
	
	if (!error && readDevInfoThread.execWithCursor(Qt::WaitCursor) < 0)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), readDevInfoThread.errorString());
		error = true;
	}
	
	for (int i = 0; i < 4; i++)
	{
		CRD_UT10XX_thread_cmd_read_key_info readKeyInfoThread(mUt, i);
		
		if (!error && readKeyInfoThread.execWithCursor(Qt::WaitCursor) < 0)
		{
			QMessageBox::critical(MainWindow::mainWnd, tr("Error"), readKeyInfoThread.errorString());
			error = true;
		}
	}
	
	CRD_UT10XX_session_close(mUt);
	
	refresh();
}

void
STokenItem::generateCertReqSlot(int keyId, QString &fileName, QStringList &dn, QString &mail)
{
	CRD_UT10XX_thread_generate_cert_request generateCertRequestThread(mUt, mUserPin, 
		keyId, fileName, dn, mail);
	
	connect(&generateCertRequestThread, SIGNAL(genFinished(const QString &, const QString &)),
		this, SLOT(genReqFinished(const QString &, const QString &)));
	
	generateCertRequestThread.execWithCursor(Qt::WaitCursor);
}

#ifdef WITH_RBG
void
STokenItem::rbgSlot(int octets, int fmt, QString &fileName)
{
	int progress = 0;
	char rep[960];
	char buf[120];
	
	QFile file(fileName);
	file.open(QIODevice::WriteOnly | QIODevice::Truncate);
	
	CRD_UT10XX_session_open(mUt);
	
	QProgressDialog progressDialog(tr("Generating random bits..."), tr("Stop"), 
		0, octets, mMainTabWidget);
	
	while (octets > 0)
	{
		int towrite = octets < 120 ? octets : 120;
		
		if (CRD_UT10XX_cmd_rbg_generate_bits(mUt, buf, towrite) < 0)
		{
			QMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr(CRD_UT10XX_lib_detail_error_desc(mUt)));
			break;
		}
		
		if (fmt == RbgWidget::BinaryAsciiFmt)
		{
			for (int i = 0; i < towrite; i++)
			{
				for (int j = 0; j < 8; j++)
				{
					if ((buf[i] >> (7 - j)) & 1)
						rep[8*i + j] = '1';
					
					else
						rep[8*i + j] = '0';
				}
			}
			
			file.write(rep, 8*towrite);
		}
		else if (fmt == RbgWidget::HexAsciiFmt)
		{
			for (int i = 0; i < towrite; i++)
			{
				if ((buf[i] & 0x0F) < 10)
					rep[2*i] = '0' + (buf[i] & 0x0F);
				
				else
					rep[2*i] = 'A' - 10 + (buf[i] & 0x0F);
				
				buf[i] >>= 4;
				
				if ((buf[i] & 0x0F) < 10)
					rep[2*i + 1] = '0' + (buf[i] & 0x0F);
				
				else
					rep[2*i + 1] = 'A' - 10 + (buf[i] & 0x0F);
			}
			
			file.write(rep, 2*towrite);
		}
		else if (fmt == RbgWidget::BinaryFmt)
		{
			file.write(buf, towrite);
		}
		
		progress += towrite;
		octets -= towrite;
		
		progressDialog.setValue(progress);
		qApp->processEvents();
		
		if (progressDialog.wasCanceled())
			break;
	}
	
	CRD_UT10XX_session_close(mUt);
	
	file.close();
}
#endif

void
STokenItem::addFileSlot(QString &srcFileName, QString &dstFileName)
{
	bool error = false;
	
	CRD_UT10XX_file_t *dstFile = 0;
	QByteArray dstFileNameChars = dstFileName.toUtf8();
	
	QFile srcFile(srcFileName);
	srcFile.open(QIODevice::ReadOnly);
	QByteArray srcBytes = srcFile.readAll();
	srcFile.close();
	
	if (srcBytes.size() > 4096)
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("File %1 is too large to may be stored on token.").arg(srcFileName));
		error = true;
	}
	
	// Find file type by its extension.
	int fileType = CRD_UT10XX_FT_UNKN;
	
	if ( srcFileName.endsWith(QString(".crt"), Qt::CaseInsensitive)
		|| srcFileName.endsWith(QString(".cer"), Qt::CaseInsensitive)
		|| srcFileName.endsWith(QString(".cert"), Qt::CaseInsensitive) )
	{
		fileType = CRD_UT10XX_FT_CRT;
	}
	else if ( srcFileName.endsWith(QString(".req"), Qt::CaseInsensitive) )
	{
		fileType = CRD_UT10XX_FT_REQ;
	}
	else if ( srcFileName.endsWith(QString(".txt"), Qt::CaseInsensitive)
		|| srcFileName.endsWith(QString(".text"), Qt::CaseInsensitive) )
	{
		fileType = CRD_UT10XX_FT_TXT;
	}
	else if ( srcFileName.endsWith(QString(".html"), Qt::CaseInsensitive)
		|| srcFileName.endsWith(QString(".htm"), Qt::CaseInsensitive) )
	{
		fileType = CRD_UT10XX_FT_HTML;
	}
	else if ( srcFileName.endsWith(QString(".conf"), Qt::CaseInsensitive)
		|| srcFileName.endsWith(QString(".cnf"), Qt::CaseInsensitive) )
	{
		fileType = CRD_UT10XX_FT_CONF;
	}
	else if ( srcFileName.endsWith(QString(".bin"), Qt::CaseInsensitive) )
	{
		fileType = CRD_UT10XX_FT_BIN;
	}
	
	// Wtite file to token memory.
	CRD_UT10XX_session_open(mUt);
	
	if (!error && (dstFile = CRD_UT10XX_file_create(mUt, dstFileNameChars.data(), 
		fileType)) == 0)
	{
		QDetailsMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Cannot create file %1 on token.").arg(dstFileName), CRD_UT10XX_lib_detail_error_desc(mUt));
		error = true;
	}
	
	if (!error && (CRD_UT10XX_file_write(dstFile, srcBytes.data(), srcBytes.size()) < 0))
	{
		QDetailsMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Error writing data to file %1 on token [#1].").arg(dstFileName), 
			CRD_UT10XX_lib_detail_error_desc(mUt));
		error = true;
	}
	
	if (!error && (CRD_UT10XX_file_type_set_printable_mask(dstFile) < 0))
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Cannot check if file is printable."));
		error = true;
	}
	
	CRD_UT10XX_thread_file_flush fileFlushThread(mUt, dstFile, mPin, mPinId);
	
	if (!error && (fileFlushThread.execWithCursor(Qt::WaitCursor) < 0))
	{
		QDetailsMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Cannot save data to file %1 on token [#2].").arg(dstFileName), 
			fileFlushThread.errorString());
		error = true;
	}
	
	if (dstFile && (CRD_UT10XX_file_close(dstFile) < 0))
	{
		QDetailsMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Cannot close file %1 on token.").arg(dstFileName), 
			CRD_UT10XX_lib_detail_error_desc(mUt));
		error = true;
	}
	
	CRD_UT10XX_thread_fs_get_file_list getFileListThread(mUt);
	
	if (!error && (getFileListThread.execWithCursor(Qt::WaitCursor) < 0))
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), getFileListThread.errorString());
		error = true;
	}
	
	CRD_UT10XX_session_close(mUt);
	
	refresh();
}

void
STokenItem::deleteFileSlot(QString &fileName)
{
	bool error = false;
	
	CRD_UT10XX_file_t *file = 0;
	QByteArray fileNameChars = fileName.toUtf8();
	
	CRD_UT10XX_session_open(mUt);
	
	CRD_UT10XX_thread_file_open fileOpenThread(mUt, fileNameChars.data());
	
	if (!error && (fileOpenThread.execWithCursor(Qt::WaitCursor) < 0))
	{
		QDetailsMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Cannot open file %1 on token.").arg(fileName), 
			fileOpenThread.errorString());
		error = true;
	}
	
	file = fileOpenThread.fileHandle();
	CRD_UT10XX_thread_file_delete fileDeleteThread(mUt, file, mPin, mPinId);
	
	if (!error && (fileDeleteThread.execWithCursor(Qt::WaitCursor) < 0))
	{
		QDetailsMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Cannot delete file %1 from token.").arg(fileName), 
			fileDeleteThread.errorString());
		error = true;
	}
	
	CRD_UT10XX_thread_fs_get_file_list getFileListThread(mUt);
	
	if (!error && (getFileListThread.execWithCursor(Qt::WaitCursor) < 0))
	{
		QMessageBox::critical(MainWindow::mainWnd, tr("Error"), getFileListThread.errorString());
		error = true;
	}
	
	CRD_UT10XX_session_close(mUt);
	
	refresh();
}

void
STokenItem::saveFileSlot(QString &srcFileName, QString &dstFileName)
{
	bool error = false;
	int readed = 0;
	char buf[1024];
	
	CRD_UT10XX_file_t *srcFile = 0;
	QByteArray srcFileNameChars = srcFileName.toUtf8();
	
	QFile dstFile(dstFileName);
	dstFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
	
	CRD_UT10XX_session_open(mUt);
	
	CRD_UT10XX_thread_file_open fileOpenThread(mUt, srcFileNameChars.data());
	
	if (!error && (fileOpenThread.execWithCursor(Qt::WaitCursor) < 0))
	{
		QDetailsMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Cannot open file %1 on token.").arg(srcFileName), 
			fileOpenThread.errorString());
		error = true;
	}
	
	srcFile = fileOpenThread.fileHandle();
	
	while (!error && (readed = CRD_UT10XX_file_read(srcFile, buf, sizeof(buf))))
	{
		if (readed < 0)
		{
			QDetailsMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Cannot read file %1 on token.").arg(srcFileName), 
				CRD_UT10XX_lib_detail_error_desc(mUt));
			error = true;
		}
		else
		{
			dstFile.write(buf, readed);
		}
	}
	
	if (srcFile && (CRD_UT10XX_file_close(srcFile) < 0))
	{
		QDetailsMessageBox::critical(MainWindow::mainWnd, tr("Error"), tr("Cannot close file %1 on token.").arg(srcFileName), 
			CRD_UT10XX_lib_detail_error_desc(mUt));
		error = true;
	}
	
	CRD_UT10XX_session_close(mUt);
	
	dstFile.close();
}

int
STokenItem::sTokenState()
{
	if (mUt->info.info & 0x04)
		return StateLock;
	
	else if (mUt->info.info & 0x02)
		return StateConf;
	
	else if (mUt->info.info & 0x01)
		return StateInit;
	
	else
		return StateClear;
}

void
STokenItem::genReqFinished(const QString &fileName, const QString &mail)
{
	if(mail.isEmpty())
		return;

	QWidget *top = mMainTabWidget;
	while (top->parentWidget() != 0)
		top = top->parentWidget();

	MainWindow *wnd = static_cast<MainWindow *>(top);
	wnd->sendRequest(fileName, mail);
}

void
STokenItem::displayContextMenu(const QModelIndex &index)
{
	QMenu *menu = new QMenu();
	menu->addAction(QIcon(QString(":img/login.png")), tr("Login"), this, SLOT(loginPageSlot()));
	menu->exec(QCursor::pos());
}

void
STokenItem::currentChangedSlot(int index)
{
	if(mMainTabWidget->currentWidget() == mLoginWidget)
	{
		mLoginWidget->focus2PIN();
	}
}

void
STokenItem::loginPageSlot()
{
	mMainTabWidget->setCurrentWidget(mLoginWidget);
}
