Click here to Skip to main content
15,896,348 members
Articles / Desktop Programming / MFC

Exile 1.8 - The Password Manager

Rate me:
Please Sign up or sign in to vote.
4.57/5 (51 votes)
6 Mar 20058 min read 257.4K   7.4K   111  
Yet another password manager.
/********************************************************************
	Created:	27/3/2004, 14:36
	File name: 	D:\Projects\Exile\Exile\ExileDlg.cpp
	File path:	D:\Projects\Exile\Exile
	File base:	ExileDlg
	File ext:	cpp
	Author:		Gogolev Anton
*********************************************************************/

// ExileDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Exile.h"
#include "ExileDlg.h"
#include "menuflags.h"
#include "NewDialog.h"
#include "InsertCategoryDialog.h"
#include "InsertElementDialog.h"
#include "EnterPasswordDialog.h"
#include "PasswordGeneratorDialog.h"
#include "MD5HashGeneratorDialog.h"
#include "EditCategoryDialog.h"
#include "EditElementDialog.h"
#include "StoragePropertiesDialog.h"
#include "OptionsDialog.h"
#include <WindowsX.h>
#include <shlwapi.h>
#include "security.h"
#include "registry.h"
#include "messagebox.h"
#include "hotkey.h"
#include "instance.h"
#include "sort.h"
#include "ExportToXmlDialog.h"
#include "AdvancedDialog.h"
#include "xmlexportflags.h"
#include "OpenFileDialog.h"
#include "modulepath.h"
#include "shellfolder.h"
#include "../mdx/mdx.h"
#include "../Icons/Icons.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define WM_TRAYCALLBACK (WM_USER + 100)

UINT CExileDlg::m_suMessage = RegisterWindowMessage(BROADCASTMESSAGE);
const UINT_PTR g_uTimerID = 1;

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CExileDlg dialog

CExileDlg::CExileDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CExileDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CExileDlg)
	//}}AFX_DATA_INIT
	
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_pimgList = 0;
	m_pimgListSmall = 0;

	// Set up Title font
    NONCLIENTMETRICS ncm = {0};
    ncm.cbSize = sizeof(ncm);
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);

    LOGFONT lfTitle = ncm.lfMessageFont;
    lfTitle.lfWeight = FW_BOLD;
    lstrcpy(lfTitle.lfFaceName, _T("Verdana Bold"));

    HDC hDC = ::GetDC(NULL); // Gets the screen DC
    int FontSize = 12;

    lfTitle.lfHeight = 0 - GetDeviceCaps(hDC, LOGPIXELSY) * FontSize / 72;

    m_hFont = CreateFontIndirect(&lfTitle);

    ::ReleaseDC(NULL, hDC);

	//
	// Default Settings
	//
	m_nExportFlags = 0;
	m_strExportFileName.Empty();

	m_nHashOptions = 0;

	m_nPasswordLength = 0;
	m_bUppercase = m_bSpecial = m_bPunctuation = m_bLowercase = m_bDecimalDigits = FALSE;

	m_bShowPassword = FALSE;
	m_bMinimizeToTray = TRUE;
	m_bHotKeys = TRUE;
	m_bReloadLastStorage = TRUE;
	m_bAutosave = FALSE;
	m_bAutosort = FALSE;
	m_nSortOrder = 1;
	m_bSmartType = FALSE;
	m_wKeyCode = 0;
	m_wModifiers = 0;
	m_bBackup = FALSE;
	m_bMaintain = TRUE;
	m_bReloadReadonly = FALSE;
	m_bShellOpenReadonly = FALSE;
	m_strLastStorage.Empty();
	m_bClipboardErasing = FALSE;
	m_nErasingTimeout = 0;
}

void CExileDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CExileDlg)
	DDX_Control(pDX, IDC_RATINGICON, m_ctrlRatingIcon);
	DDX_Control(pDX, IDC_TREE, m_ctrlTree);
	DDX_Control(pDX, IDC_ADDRESS, m_ctrlAddress);
	DDX_Control(pDX, IDC_PASSWORD, m_ctrlPassword);
	DDX_Control(pDX, IDC_NOTES, m_ctrlNotes);
	DDX_Control(pDX, IDC_LOGIN, m_ctrlLogin);	
	DDX_Control(pDX, IDC_ITEMICON, m_ctrlItemIcon);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CExileDlg, CDialog)
	//{{AFX_MSG_MAP(CExileDlg)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_COMMAND(ID_FILE_NEW, OnFileNew)
	ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
	ON_COMMAND(ID_FILE_CLOSE, OnFileClose)
	ON_COMMAND(ID_FILE_SAVE, OnFileSave)
	ON_COMMAND(ID_FILE_SAVEAS, OnFileSaveas)
	ON_WM_DESTROY()
	ON_NOTIFY(TVN_SELCHANGED, IDC_TREE, OnSelchangedTree)
	ON_COMMAND(ID_EDIT_INSERTCATEGORY, OnEditInsertcategory)
	ON_COMMAND(ID_EDIT_INSERTELEMENT, OnEditInsertelement)
	ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
	ON_WM_CLOSE()
	ON_COMMAND(ID_TOOLS_MD5HASHGENERATOR, OnToolsMd5hashgenerator)
	ON_COMMAND(ID_TOOLS_PASSWORDGENERATOR, OnToolsPasswordgenerator)
	ON_BN_CLICKED(IDC_PASSWORD_TITLE, OnPasswordTitle)
	ON_COMMAND(ID_EDIT_DELETE, OnEditDelete)
	ON_COMMAND(ID_EDIT_EDIT, OnEditEdit)
	ON_COMMAND(ID_EDIT_STORAGEPROPERTIES, OnEditStorageproperties)	
	ON_NOTIFY(NM_RCLICK, IDC_TREE, OnRclickTree)
	ON_COMMAND(ID_TRAYMENU_RESTORE, OnTraymenuRestore)
	ON_COMMAND(ID_TRAYMENU_ENABLEHOTKEYS, OnTraymenuEnablehotkeys)
	ON_COMMAND(ID_EDIT_OPTIONS, OnEditOptions)
	ON_COMMAND(ID_CATEGORYCONTEXT_SORT_NAMEASCENDING, OnCategorycontextSortNameascending)
	ON_COMMAND(ID_CATEGORYCONTEXT_SORT_NAMEDESCENDING, OnCategorycontextSortNamedescending)
	ON_COMMAND(ID_CATEGORYCONTEXT_SORT_USERNAMEASCENDING, OnCategorycontextSortUsernameascending)
	ON_COMMAND(ID_CATEGORYCONTEXT_SORT_USERNAMEDESCENDING, OnCategorycontextSortUsernamedescending)
	ON_COMMAND(ID_CATEGORYCONTEXT_SORT_RATINGASCENDING, OnCategorycontextSortRatingascending)
	ON_COMMAND(ID_CATEGORYCONTEXT_SORT_RATINGDESCENDING, OnCategorycontextSortRatingdescending)
	ON_COMMAND(ID_FILE_EXPORT_EXPORTTOXML, OnFileExportExporttoxml)
	ON_COMMAND(ID_EDIT_ADVANCED, OnEditAdvanced)
	//}}AFX_MSG_MAP
	ON_REGISTERED_MESSAGE(m_suMessage, OnActivateApp)
	ON_MESSAGE(TCEX_ITEMDRAGGED, OnTcexItemdragged)
	ON_MESSAGE(SHLE_RBUTTONDOWN, OnShleRButtondown)
	ON_COMMAND(ID_COPY, OnCopy)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CExileDlg message handlers

BOOL CExileDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	// when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE); // Set big icon
	SetIcon(m_hIcon, FALSE); // Set small icon

	::MdxInitialize();

	m_hAccel = ::LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCELERATOR));

	//
	// Loading settings
	//
	LoadSettings();

	// SmartType
	if(m_bSmartType)
	{
		::RegisterHotKey(*this, 0, MapModifiers(m_wModifiers), m_wKeyCode);
	} // if

	if(m_bMaintain)
		MaintainFileAssociations();

	// Icons
	m_pimgList = new CImageList();
	m_pimgList->Create(32, 32, ILC_COLOR8 | ILC_MASK, 15, 5);

	// Small ones
	m_pimgListSmall = new CImageList();
	m_pimgListSmall->Create(16, 16, ILC_COLOR8 | ILC_MASK, 15, 5);

	HINSTANCE hIcons = (HINSTANCE)::GetModuleHandle(_T("icons.dll"));

	for(UINT uIcon = IconsGetIconIndex(); uIcon < IconsGetIconIndex() + IconsGetIconCount(); ++uIcon)
	{
		m_pimgList->Add(::LoadIcon(hIcons, MAKEINTRESOURCE(uIcon)));
		m_pimgListSmall->Add(::LoadIcon(hIcons, MAKEINTRESOURCE(uIcon)));
	} // for

	// Rating icons
	m_pimgRating = new CImageList();
	m_pimgRating->Create(16, 16, ILC_COLOR8 | ILC_MASK, 11, 1);

	m_pimgRating->Add((HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_COLD), 
		IMAGE_ICON, 16, 16, 0));
	m_pimgRating->Add((HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_BELOWINSIGNIFICANT), 
		IMAGE_ICON, 16, 16, 0));
	m_pimgRating->Add((HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_INSIGNIFICANT), 
		IMAGE_ICON, 16, 16, 0));
	m_pimgRating->Add((HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_UNIMPORTANT), 
		IMAGE_ICON, 16, 16, 0));
	m_pimgRating->Add((HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_BELOWNORMAL), 
		IMAGE_ICON, 16, 16, 0));
	m_pimgRating->Add((HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_NORMAL), 
		IMAGE_ICON, 16, 16, 0));
	m_pimgRating->Add((HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_IMPORTANT), 
		IMAGE_ICON, 16, 16, 0));
	m_pimgRating->Add((HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_ABOVEIMPORTANT), 
		IMAGE_ICON, 16, 16, 0));
	m_pimgRating->Add((HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_VERYIMPORTANT), 
		IMAGE_ICON, 16, 16, 0));
	m_pimgRating->Add((HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_BELOWCRITICAL), 
		IMAGE_ICON, 16, 16, 0));
	m_pimgRating->Add((HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_CRITICAL), 
		IMAGE_ICON, 16, 16, 0));

	// Setting up title font
	GetDlgItem(IDC_TITLE_TITLE)->ModifyStyle(0, SS_ENDELLIPSIS, 0); // If title doesn't fit
	SetWindowFont(GetDlgItem(IDC_TITLE_TITLE)->GetSafeHwnd(), m_hFont, TRUE);
	
	// Grouping controls
	m_gcControls.AddControl(TITLE, GetDlgItem(IDC_TITLE_TITLE)->GetSafeHwnd());
	
	m_gcControls.AddControl(CATEGORY, GetDlgItem(IDC_TITLE_TITLE)->GetSafeHwnd());
	m_gcControls.AddControl(CATEGORY, GetDlgItem(IDC_DESCRIPTION_TITLE)->GetSafeHwnd());

	m_gcControls.AddControl(ELEMENT_INDETAIL, GetDlgItem(IDC_LOGIN_TITLE)->GetSafeHwnd());
	m_gcControls.AddControl(ELEMENT_INDETAIL, GetDlgItem(IDC_PASSWORD_TITLE)->GetSafeHwnd());
	m_gcControls.AddControl(ELEMENT_INDETAIL, GetDlgItem(IDC_LOGIN)->GetSafeHwnd());
	m_gcControls.AddControl(ELEMENT_INDETAIL, GetDlgItem(IDC_PASSWORD)->GetSafeHwnd());
	m_gcControls.AddControl(ELEMENT_INDETAIL, GetDlgItem(IDC_ADDRESS_TITLE)->GetSafeHwnd());
	m_gcControls.AddControl(ELEMENT_INDETAIL, GetDlgItem(IDC_NOTES_TITLE)->GetSafeHwnd());
	m_gcControls.AddControl(ELEMENT_INDETAIL, GetDlgItem(IDC_ADDRESS)->GetSafeHwnd());
	m_gcControls.AddControl(ELEMENT_INDETAIL, GetDlgItem(IDC_NOTES)->GetSafeHwnd());
	m_gcControls.AddControl(ELEMENT_INDETAIL, GetDlgItem(IDC_MODESWITCH)->GetSafeHwnd());
	m_gcControls.AddControl(ELEMENT_INDETAIL, GetDlgItem(IDC_INFO_TITLE)->GetSafeHwnd());
	m_gcControls.AddControl(ELEMENT_INDETAIL, GetDlgItem(IDC_RATINGICON)->GetSafeHwnd());

	// Cosmetic stuff
	m_ctrlTree.SetImageList(m_pimgListSmall, TVSIL_NORMAL);
	m_ctrlDescription.SubclassDlgItem(IDC_DESCRIPTION_TITLE, this);
	m_ctrlPasswordLink.SubclassDlgItem(IDC_PASSWORD_TITLE, this);
	m_ctrlPasswordLink.SetTextColor(RGB(0, 0, 192));
	m_ctrlKeyInfo.SubclassDlgItem(IDC_KEYINFO_TITLE, this);
	m_ctrlInfo.SubclassDlgItem(IDC_INFO_TITLE, this);
	AddTrayIcon(IDR_MAINFRAME);

	CBitmap bmSwitch;
	bmSwitch.LoadBitmap(IDB_SWITCH);

	m_pimgSwitch = new CImageList();
	m_pimgSwitch->Create(186, 21, ILC_COLOR16 | ILC_MASK, 4, 1);
	m_pimgSwitch->Add(&bmSwitch, RGB(255, 0, 255));	

	// By default
	m_gcControls.SwitchControls(TITLE, CGroupedControls::SWS_SHOW, CGroupedControls::SWS_HIDE);
	SwitchMenu(MF_EDIT_ALL | MF_FILE_SAVE | MF_FILE_SAVEAS | MF_FILE_CLOSE | MF_FILE_EXPORT_XML, FALSE);

	m_bDirty = FALSE;
	m_kiKeyInfo.nKeySize = 0;
	m_kiKeyInfo.pbKey = 0;
	m_hRc5 = 0;
	m_nSelection = EF_CATEGORY;

	CCommandLineInfo &rcmdInfo = ((CExileApp *)AfxGetApp())->GetCommandLineInfo();

	//
	// Command line
	//
	if(!rcmdInfo.m_strFileName.IsEmpty())
	{
		m_strStorageName = rcmdInfo.m_strFileName;
		m_bReadOnly = m_bShellOpenReadonly;
		LoadStorage(FALSE);
	} // if
	else
	{
		if(m_bReloadLastStorage) 
		{
			m_bReadOnly = m_bReloadReadonly;
			m_strStorageName = m_strLastStorage;

			if(!m_strStorageName.IsEmpty())
				LoadStorage(FALSE);
		} // if
	} // else
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon.  For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CExileDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CExileDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CExileDlg::SwitchMenu(long lItems, BOOL bSwitchOn)
{
	CMenu *pMenu = AfxGetApp()->GetMainWnd()->GetMenu();

	// File
	if(lItems & MF_FILE_NEW)
		pMenu->EnableMenuItem(ID_FILE_NEW, MF_BYCOMMAND | (bSwitchOn ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
	if(lItems & MF_FILE_OPEN)
		pMenu->EnableMenuItem(ID_FILE_OPEN, MF_BYCOMMAND | (bSwitchOn ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
	if(lItems & MF_FILE_CLOSE)
		pMenu->EnableMenuItem(ID_FILE_CLOSE, MF_BYCOMMAND | (bSwitchOn ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
	if(lItems & MF_FILE_SAVE)
		pMenu->EnableMenuItem(ID_FILE_SAVE, MF_BYCOMMAND | (bSwitchOn ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
	if(lItems & MF_FILE_SAVEAS)
		pMenu->EnableMenuItem(ID_FILE_SAVEAS, MF_BYCOMMAND | (bSwitchOn ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
	if(lItems & MF_FILE_EXPORT_XML)
		pMenu->EnableMenuItem(ID_FILE_EXPORT_EXPORTTOXML, MF_BYCOMMAND | (bSwitchOn ? MF_ENABLED : MF_DISABLED | MF_GRAYED));

	// Edit
	if(lItems & MF_EDIT_INSERTCATEGORY)
		pMenu->EnableMenuItem(ID_EDIT_INSERTCATEGORY, MF_BYCOMMAND | (bSwitchOn ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
	if(lItems & MF_EDIT_INSERTELEMENT)
		pMenu->EnableMenuItem(ID_EDIT_INSERTELEMENT, MF_BYCOMMAND | (bSwitchOn ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
	if(lItems & MF_EDIT_EDIT)
		pMenu->EnableMenuItem(ID_EDIT_EDIT, MF_BYCOMMAND | (bSwitchOn ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
	if(lItems & MF_EDIT_DELETE)
		pMenu->EnableMenuItem(ID_EDIT_DELETE, MF_BYCOMMAND | (bSwitchOn ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
	if(lItems & MF_EDIT_STORAGEPROPERTIES)
		pMenu->EnableMenuItem(ID_EDIT_STORAGEPROPERTIES, MF_BYCOMMAND | (bSwitchOn ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
	if(lItems & MF_EDIT_ADVANCED)
		pMenu->EnableMenuItem(ID_EDIT_ADVANCED, MF_BYCOMMAND | (bSwitchOn ? MF_ENABLED : MF_DISABLED | MF_GRAYED));
}

void CExileDlg::OnFileNew() 
{
	CreateStorage();
}

void CExileDlg::OnFileOpen() 
{
	LoadStorage(TRUE);
}

void CExileDlg::OnFileClose() 
{
	CloseStorage();
}

void CExileDlg::OnFileSave() 
{
	SaveStorage(FALSE);
}

void CExileDlg::OnFileSaveas() 
{
	SaveStorage(TRUE);
}

void CExileDlg::CreateStorage()
{
	CNewDialog dlgNew;

	ProcessDirtyStorage();

	//
	// Settings
	//
	dlgNew.m_bDecimalDigits = m_bDecimalDigits;
	dlgNew.m_bLowercase = m_bLowercase;
	dlgNew.m_bPunctuation = m_bPunctuation;
	dlgNew.m_bSpecial = m_bSpecial;
	dlgNew.m_bUppercase = m_bUppercase;
	dlgNew.m_nPasswordLength = m_nPasswordLength;

	if(IDOK == dlgNew.DoModal()) 
	{
		BeginWaitCursor();
		CloseStorage();

		m_lIndex = 0;
		m_strStorageName.Empty();

		GeneratePrivateKey(dlgNew.m_strUserName, dlgNew.m_strMasterPassword, dlgNew.m_nKeySize, m_kiKeyInfo);

		m_kiKeyInfo.nRounds = dlgNew.m_nRounds;

		// Acquiring new crypting context and setting a new key
		if(::Rc5ValidContext(m_hRc5))
			::Rc5ReleaseContext(m_hRc5);

		if(!::Rc5AcquireContext(m_hRc5, m_kiKeyInfo.nKeySize / 8, m_kiKeyInfo.nRounds))
		{
			MessageBoxEx(*this, IDS_RC5ACQUIRECONTEXTFAILED, IDS_TITLE);
			CleanPrivateData();
			EndWaitCursor();
			return;
		} // if

		if(!::Rc5SetBinaryPrivateKey(m_hRc5, m_kiKeyInfo.pbKey))
		{
			MessageBoxEx(*this, IDS_RC5SETBINARYPRIVATEKEYFAILED, IDS_TITLE);
			CleanPrivateData();
			EndWaitCursor();
			return;
		} // if

		// So now we can delete key buffer in order not
		// to expose it anymore
		FreeBuffer(m_kiKeyInfo.pbKey, m_kiKeyInfo.nKeySize / 8);

		//////////////////////////////////////////////////////////////////////////
		// Now adding to tree and to map
		m_ctrlTree.DeleteAllItems();

		TV_INSERTSTRUCT tvi;

		tvi.hParent = 0; // Root item
		tvi.hInsertAfter = TVI_ROOT;
		tvi.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
		tvi.item.cchTextMax = dlgNew.m_strUserName.GetLength() + 1;
		tvi.item.pszText = dlgNew.m_strUserName.LockBuffer();
		tvi.item.lParam = SetDropTarget(m_lIndex);
		tvi.item.iImage = 11; // Keys
		tvi.item.iSelectedImage = 11;

		m_ctrlTree.InsertItem(&tvi);

		// Adding to map
		ENTRY eItem;
		CString strDescription;
		strDescription.LoadString(IDS_ROOTDESCRIPTION);

		eItem.nFlags = EF_CATEGORY | EF_ROOTCATEGORY;
		eItem.lID = m_lIndex;
		eItem.lIconID = 11;
		eItem.lReserved = 0;
		memset(&(eItem.pePrivate.abReserved), 0, sizeof(eItem.pePrivate.abReserved));
#ifdef _UNICODE
		wcscpy(eItem.pePrivate.szName, dlgNew.m_strUserName.LockBuffer());
		wcscpy(eItem.pePrivate.szNotes, strDescription.LockBuffer());
		wcscpy(eItem.pePrivate.szAddress, _T(""));
		wcscpy(eItem.pePrivate.szLogin, _T(""));
		wcscpy(eItem.pePrivate.szPassword, _T(""));
#else
		strcpy(eItem.pePrivate.szName, dlgNew.m_strUserName.LockBuffer());
		strcpy(eItem.pePrivate.szNotes, strDescription.LockBuffer());
		strcpy(eItem.pePrivate.szAddress, _T(""));
		strcpy(eItem.pePrivate.szLogin, _T(""));
		strcpy(eItem.pePrivate.szPassword, _T(""));
#endif // _UNICODE

		// Yep!
		EncryptPrivateEntry(eItem.pePrivate, m_hRc5);
		m_mEntries[m_lIndex++] = eItem;

		dlgNew.m_strUserName.UnlockBuffer();
		CleanString(dlgNew.m_strMasterPassword);
		CleanString(dlgNew.m_strUserName);

		SwitchMenu(MF_FILE_ALL, TRUE);
		SetKeyInfo(m_kiKeyInfo.nKeySize);

		ProcessSortOrder();

		SetDirty(TRUE);

		EndWaitCursor();

		//
		// Settings
		//
		m_bDecimalDigits = dlgNew.m_bDecimalDigits;
		m_bLowercase = dlgNew.m_bLowercase;
		m_bPunctuation = dlgNew.m_bPunctuation;
		m_bSpecial = dlgNew.m_bSpecial;
		m_bUppercase = dlgNew.m_bUppercase;
		m_nPasswordLength = dlgNew.m_nPasswordLength;
	} // if
}

void CExileDlg::ProcessDirtyStorage()
{
	if(m_bDirty)
	{
		CString strTitle, strText;
		strTitle.LoadString(IDS_TITLE);
		strText.Format(IDS_SAVEDIRTYSTORAGE, m_strStorageName.IsEmpty() ? "<Untitled Storage>" : m_strStorageName);

		if(IDYES == ::MessageBox(*this, strText, strTitle, MB_YESNO | MB_ICONQUESTION))
			SaveStorage(m_bReadOnly);
	} // if
}

void CExileDlg::CloseStorage()
{
	if(m_mEntries.empty())
		return;

	BeginWaitCursor();

	// Unregistering hot keys and clearing entries contents
	UnregisterHotKeys();

	MENTRY::iterator emi = m_mEntries.begin();
	while(m_mEntries.end() != emi) 
	{
		CleanBuffer(&(emi->second), sizeof(ENTRY));
		++emi;
	} // while

	m_strLastStorage = m_strStorageName;

	m_strStorageName.Empty();
	m_ctrlTree.DeleteAllItems();
	m_mEntries.clear();

	SwitchMenu(MF_EDIT_ALL, FALSE);
	SwitchMenu(MF_FILE_SAVE | MF_FILE_CLOSE | MF_FILE_SAVEAS | MF_FILE_EXPORT_XML, FALSE);
	m_gcControls.SwitchControls(TITLE, CGroupedControls::SWS_SHOW, CGroupedControls::SWS_HIDE);
	SetTitle();
	SetKeyInfo(0);
	SetDirty(FALSE);

	CString strTitle;
	strTitle.LoadString(IDS_TITLE);

	m_ctrlItemIcon.SetIcon(m_hIcon);
	SetTitle(strTitle.LockBuffer());

	EndWaitCursor();
}

void CExileDlg::SaveStorage(BOOL bSaveAs)
{
	// If no name has been specified
	if((m_strStorageName.IsEmpty()) || bSaveAs)
	{
		CString strFilter, strExt;
		strFilter.LoadString(IDS_FILTER);
		strExt.LoadString(IDS_EXTENSION);

		CFileDialog dlgSave(FALSE, strExt, 0, OFN_HIDEREADONLY | OFN_NONETWORKBUTTON | OFN_OVERWRITEPROMPT, 
			strFilter, this);

		if(IDCANCEL == dlgSave.DoModal()) 
			return;

		if((m_bReadOnly) && (dlgSave.GetPathName() == m_strStorageName))
		{
			MessageBoxEx(*this, IDS_CANTSAVETOREADONLY, IDS_TITLE);
			return;
		} // if

		m_strStorageName = dlgSave.GetPathName();
	} // if

	CString strExt = m_strStorageName.Right(3); // Extension
	strExt.MakeUpper();

	if(_T("XML") == strExt)
	{
		SaveStorageXml();
	} // if
	else
	{
		SaveStorageSerial();
	} // else

	SetTitle();
}

void CExileDlg::LoadStorage(BOOL bShowDialog)
{
	if(bShowDialog) 
	{
		CString strFilter, strExt;
		strFilter.LoadString(IDS_FILTER);
		strExt.LoadString(IDS_EXTENSION);

		CFileDialog dlgOpen(TRUE, strExt, 0, OFN_NONETWORKBUTTON, strFilter, this);
//		COpenFileDialog dlgOpen(TRUE, strExt, 0, OFN_HIDEREADONLY | OFN_NONETWORKBUTTON, strFilter, this);

		if(IDCANCEL == dlgOpen.DoModal()) 
			return;

		ProcessDirtyStorage();
		CloseStorage();	

		m_strStorageName = dlgOpen.GetPathName();
		m_bReadOnly = dlgOpen.m_ofn.Flags & OFN_READONLY;
//		m_bReadOnly = dlgOpen.m_bReadOnly;
	} // if	

	CString strExt = m_strStorageName.Right(3);
	strExt.MakeUpper();

	if(_T("XML") == strExt)
	{
		LoadStorageXml();
	} // if
	else
	{
		LoadStorageSerial();
	} // else
}

void CExileDlg::CleanPrivateData()
{
	if(m_kiKeyInfo.nKeySize) 
	{
		FreeBuffer(m_kiKeyInfo.pbKey, m_kiKeyInfo.nKeySize / 8);
		m_kiKeyInfo.nKeySize = 0;
	} // if
}

void CExileDlg::OnDestroy() 
{
	// Saving settings
	BeginWaitCursor();

	SaveSettings();

	if(m_bMaintain)
		MaintainFileAssociations();

	//
	// Uninitializing
	//

	RemoveTrayIcon(IDR_MAINFRAME);

	// SmartType
	if(m_bSmartType)
	{
		::UnregisterHotKey(*this, 0);
	} // if

	EndWaitCursor();

	CDialog::OnDestroy();

	DestroyAcceleratorTable(m_hAccel);

	// Image lists
	m_pimgList->DeleteImageList();
	delete m_pimgList;

	m_pimgListSmall->DeleteImageList();
	delete m_pimgListSmall;

	m_pimgSwitch->DeleteImageList();
	delete m_pimgSwitch;

	m_pimgRating->DeleteImageList();
	delete m_pimgRating;

	::MdxUninitialize();	
}

void CExileDlg::OnSelchangedTree(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

	ShowEntry(pNMTreeView->itemNew.hItem);
	
	*pResult = 0; // Ignored
}

void CExileDlg::ShowEntry(HTREEITEM hItem)
{
	// Find an item
	TV_ITEM tvi;

	tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
	tvi.hItem = hItem;

	if(m_ctrlTree.GetItem(&tvi))
	{
		// Look up in a map
		MENTRY::iterator ei = m_mEntries.find(GetItemParam(tvi.lParam));

		if(m_mEntries.end() != ei) 
		{
			// Now determine its type
			if(ei->second.nFlags & EF_CATEGORY) 
			{
				// Controls
				m_gcControls.HideControls(ELEMENT_INDETAIL);
				m_gcControls.DisableControls(ELEMENT_INDETAIL);
				m_gcControls.ShowControls(CATEGORY);

				SwitchMenu(MF_EDIT_ALL & (~MF_EDIT_ADVANCED), TRUE);
				if(0 == ei->second.lID)
					SwitchMenu(MF_EDIT_DELETE, FALSE); // Can't delete Root item

				DecryptPrivateEntry(ei->second.pePrivate, m_hRc5);

				// Show information
				SetTitle(ei->second.pePrivate.szName);
				SetDescription(ei->second.pePrivate.szNotes);

				// Icons
				m_ctrlItemIcon.SetIcon(m_pimgList->ExtractIcon(ei->second.lIconID));
				m_ctrlRatingIcon.SetIcon(m_pimgRating->ExtractIcon(ei->second.pePrivate.exData.cRating));

				EncryptPrivateEntry(ei->second.pePrivate, m_hRc5);

				m_nSelection = EF_CATEGORY;
			} // if
			else if(ei->second.nFlags & EF_ELEMENT) 
			{
				// Controls
				m_gcControls.HideControls(CATEGORY);
				m_gcControls.ShowControls(TITLE);
				m_gcControls.EnableControls(ELEMENT_INDETAIL);
				m_gcControls.ShowControls(ELEMENT_INDETAIL);

				SwitchMenu(MF_EDIT_ALL, FALSE);
				SwitchMenu(MF_EDIT_EDIT | MF_EDIT_DELETE | MF_EDIT_STORAGEPROPERTIES | MF_EDIT_ADVANCED, TRUE);

				DecryptPrivateEntry(ei->second.pePrivate, m_hRc5);

				// Show information
				SetTitle(ei->second.pePrivate.szName);
				SetLogin(ei->second.pePrivate.szLogin);
				SetPassword(ei->second.pePrivate.szPassword);
				SetAddress(ei->second.pePrivate.szAddress);
				SetNotes(ei->second.pePrivate.szNotes);

				CString strInfo;

				if((ei->second.pePrivate.exData.wModifiers) && (ei->second.pePrivate.exData.wVKCode))
				{
					if(m_bHotKeys)
					{
						strInfo.Format(IDS_HOTKEYINFO, GetModifiersString(MapModifiers(ei->second.pePrivate.exData.wModifiers)),
							(TCHAR)ei->second.pePrivate.exData.wVKCode);
					} // if
					else
					{
						strInfo.Format(IDS_INACTIVEHOTKEYINFO, GetModifiersString(MapModifiers(ei->second.pePrivate.exData.wModifiers)),
							(TCHAR)ei->second.pePrivate.exData.wVKCode);
					} // else
				} // if
				else
				{
					strInfo.LoadString(IDS_NOHOTKEYINFO);
				} // else

				SetInfo(strInfo.LockBuffer());

				// Icons
				m_ctrlItemIcon.SetIcon(m_pimgList->ExtractIcon(ei->second.lIconID));
				m_ctrlRatingIcon.SetIcon(m_pimgRating->ExtractIcon(ei->second.pePrivate.exData.cRating));

				m_nSelection = EF_ELEMENT;

				EncryptPrivateEntry(ei->second.pePrivate, m_hRc5);
			} // if
		} // if
	} // if
	else
	{
		// Controls, etc.
		m_gcControls.HideControls(ELEMENT_INDETAIL);
		m_gcControls.HideControls(CATEGORY);
		m_gcControls.ShowControls(TITLE);

		// Menu
		SwitchMenu(MF_EDIT_ALL, FALSE);

		CString strTitle;
		strTitle.LoadString(IDS_TITLE);

		SetTitle(strTitle.LockBuffer());

		m_ctrlItemIcon.SetIcon(m_hIcon);
	} // else
}

void CExileDlg::SetDescription(TCHAR *pszDescription)
{
	SetDlgItemText(IDC_DESCRIPTION_TITLE, pszDescription);
}

void CExileDlg::EncryptPrivateEntry(PRIVATEENTRY &rpePrivate, HRC5CONTEXT hRc5)
{
	// Both ANSI and Unicode
	::Rc5EncryptBlock(hRc5, (RC5_WORD *)&rpePrivate, (RC5_WORD *)&rpePrivate, sizeof(PRIVATEENTRY) / 8);
}

void CExileDlg::DecryptPrivateEntry(PRIVATEENTRY &rpePrivate, HRC5CONTEXT hRc5)
{
	// Both ANSI and Unicode
	::Rc5DecryptBlock(hRc5, (RC5_WORD *)&rpePrivate, (RC5_WORD *)&rpePrivate, sizeof(PRIVATEENTRY) / 8);
}

void CExileDlg::InsertCategory()
{
	// Have to be sure that user has selected Category
	TV_ITEM tvi;

	tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
	tvi.hItem = m_ctrlTree.GetSelectedItem();

	if(!m_ctrlTree.GetItem(&tvi))
		return;

	// Look up in a map
	MENTRY::iterator ei = m_mEntries.find(GetItemParam(tvi.lParam));
	if(m_mEntries.end() == ei)
		return;

	// Now determine its type
	if(!(ei->second.nFlags & EF_CATEGORY))
		return;

	CInsertCategoryDialog dlgIns;
	dlgIns.SetImageList(m_pimgList);

	if(IDOK == dlgIns.DoModal()) 
	{
		BeginWaitCursor();

		TV_INSERTSTRUCT tvi;
		HTREEITEM hRoot;

		tvi.hParent = hRoot = m_ctrlTree.GetSelectedItem();
		tvi.hInsertAfter = TVI_LAST;
		tvi.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
		tvi.item.cchTextMax = dlgIns.m_strCategoryName.GetLength() + 1;
		tvi.item.pszText = dlgIns.m_strCategoryName.LockBuffer();
		tvi.item.lParam = SetDropTarget(m_lIndex);
		tvi.item.iImage = dlgIns.GetIconID();
		tvi.item.iSelectedImage = dlgIns.GetIconID();

		m_ctrlTree.InsertItem(&tvi);

		// Adding to map
		ENTRY eItem;

		eItem.nFlags = EF_CATEGORY;
		eItem.lID = m_lIndex;
		eItem.lIconID = dlgIns.GetIconID();
		eItem.lReserved = 0;
		memset(&(eItem.pePrivate.abReserved), 0, sizeof(eItem.pePrivate.abReserved));
#ifdef _UNICODE
		wcscpy(eItem.pePrivate.szName, dlgIns.m_strCategoryName.LockBuffer());
		wcscpy(eItem.pePrivate.szNotes, dlgIns.m_strDescription.LockBuffer());
		wcscpy(eItem.pePrivate.szAddress, _T(""));
		wcscpy(eItem.pePrivate.szLogin, _T(""));
		wcscpy(eItem.pePrivate.szPassword, _T(""));
#else
		strcpy(eItem.pePrivate.szName, dlgIns.m_strCategoryName.LockBuffer());
		strcpy(eItem.pePrivate.szNotes, dlgIns.m_strDescription.LockBuffer());
		strcpy(eItem.pePrivate.szAddress, _T(""));
		strcpy(eItem.pePrivate.szLogin, _T(""));
		strcpy(eItem.pePrivate.szPassword, _T(""));
#endif // _UNICODE

		// Yep!
		EncryptPrivateEntry(eItem.pePrivate, m_hRc5);
		m_mEntries[m_lIndex++] = eItem;

		CleanString(dlgIns.m_strCategoryName);
		CleanString(dlgIns.m_strDescription);

		SetDirty(TRUE);
		SortItems(hRoot);

		EndWaitCursor();
	} // if
}

void CExileDlg::OnEditInsertcategory() 
{
	InsertCategory();
}

void CExileDlg::InsertElement()
{
	// Have to be sure that user has selected Category
	TV_ITEM tvi;

	tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
	tvi.hItem = m_ctrlTree.GetSelectedItem();

	if(!m_ctrlTree.GetItem(&tvi))
		return;

	// Look up in a map
	MENTRY::iterator ei = m_mEntries.find(GetItemParam(tvi.lParam));
	if(m_mEntries.end() == ei)
		return;

	// Now determine its type
	if(!(ei->second.nFlags & EF_CATEGORY))
		return;

	CInsertElementDialog dlgIns;
	dlgIns.SetImageList(m_pimgList);

	//
	// Settings
	//
	dlgIns.m_bDecimalDigits = m_bDecimalDigits;
	dlgIns.m_bLowercase = m_bLowercase;
	dlgIns.m_bPunctuation = m_bPunctuation;
	dlgIns.m_bSpecial = m_bSpecial;
	dlgIns.m_bUppercase = m_bUppercase;
	dlgIns.m_nPasswordLength = m_nPasswordLength;

	if(IDOK == dlgIns.DoModal()) 
	{
		BeginWaitCursor();

		TV_INSERTSTRUCT tvi;
		HTREEITEM hRoot;

		tvi.hParent = hRoot = m_ctrlTree.GetSelectedItem();
		tvi.hInsertAfter = TVI_LAST;
		tvi.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
		tvi.item.cchTextMax = dlgIns.m_strElementName.GetLength() + 1;
		tvi.item.pszText = dlgIns.m_strElementName.LockBuffer();
		tvi.item.lParam = m_lIndex; // Element is not a drop target obviously
		tvi.item.iImage = dlgIns.GetIconID();
		tvi.item.iSelectedImage = dlgIns.GetIconID();

		m_ctrlTree.InsertItem(&tvi);

		// Adding to map
		ENTRY eItem;

		eItem.nFlags = EF_ELEMENT;
		eItem.lID = m_lIndex;
		eItem.lIconID = dlgIns.GetIconID();
		eItem.lReserved = 0;
		// Hot key
		eItem.pePrivate.exData.wVKCode = dlgIns.m_wVKCode;
		eItem.pePrivate.exData.wModifiers = dlgIns.m_wModifiers;

		if((eItem.pePrivate.exData.wVKCode) && (eItem.pePrivate.exData.wModifiers) && m_bHotKeys)
		{
			// m_lIndex is guaranteed to be uinque within a particular session
			::RegisterHotKey(GetSafeHwnd(), (int)m_lIndex, MapModifiers(eItem.pePrivate.exData.wModifiers), 
				eItem.pePrivate.exData.wVKCode);
		} // if
		
#ifdef _UNICODE
		wcscpy(eItem.pePrivate.szName, dlgIns.m_strElementName.LockBuffer());
		wcscpy(eItem.pePrivate.szNotes, dlgIns.m_strNotes.LockBuffer());
		wcscpy(eItem.pePrivate.szAddress, dlgIns.m_strAddress.LockBuffer());
		wcscpy(eItem.pePrivate.szLogin, dlgIns.m_strLogin.LockBuffer());
		wcscpy(eItem.pePrivate.szPassword, dlgIns.m_strPassword.LockBuffer());
#else
		strcpy(eItem.pePrivate.szName, dlgIns.m_strElementName.LockBuffer());
		strcpy(eItem.pePrivate.szNotes, dlgIns.m_strNotes.LockBuffer());
		strcpy(eItem.pePrivate.szAddress, dlgIns.m_strAddress.LockBuffer());
		strcpy(eItem.pePrivate.szLogin, dlgIns.m_strLogin.LockBuffer());
		strcpy(eItem.pePrivate.szPassword, dlgIns.m_strPassword.LockBuffer());
#endif // _UNICODE

		// Yep!
		EncryptPrivateEntry(eItem.pePrivate, m_hRc5);
		m_mEntries[m_lIndex++] = eItem;

		CleanString(dlgIns.m_strElementName);
		CleanString(dlgIns.m_strLogin);
		CleanString(dlgIns.m_strPassword);
		CleanString(dlgIns.m_strAddress);
		CleanString(dlgIns.m_strNotes);

		SetDirty(TRUE);
		SortItems(hRoot);

		EndWaitCursor();

		//
		// Settings
		//
		m_bDecimalDigits = dlgIns.m_bDecimalDigits;
		m_bLowercase = dlgIns.m_bLowercase;
		m_bPunctuation = dlgIns.m_bPunctuation;
		m_bSpecial = dlgIns.m_bSpecial;
		m_bUppercase = dlgIns.m_bUppercase;
		m_nPasswordLength = dlgIns.m_nPasswordLength;
	} // if
}

void CExileDlg::OnEditInsertelement() 
{
	InsertElement();
}

void CExileDlg::SetTitle()
{
	CString strTitle;
	strTitle.LoadString(IDS_TITLE);
	
	if(!m_strStorageName.IsEmpty()) 
	{
		TCHAR szPath[MAX_PATH], szResult[MAX_PATH];

#ifdef _UNICODE
		wcscpy(szPath, m_strStorageName.LockBuffer());
#else
		strcpy(szPath, m_strStorageName.LockBuffer());
#endif // _UNICODE

		m_strStorageName.UnlockBuffer();

		PathCompactPathEx(szResult, szPath, 46, 0);

		strTitle += _T(" - ") + CString(szResult);

		if(m_bDirty)
			strTitle += _T(" *");

		if(m_bReadOnly)
			strTitle += _T(" - Read Only");
	} // else

	AfxGetMainWnd()->SetWindowText(strTitle);
}

void CExileDlg::SetTitle(TCHAR *pszTitle)
{
	CDC *pDC = GetDlgItem(IDC_TITLE_TITLE)->GetDC();

	if(pDC)
	{
	} // if

	ReleaseDC(pDC);
	
	SetDlgItemText(IDC_TITLE_TITLE, pszTitle);
}

void CExileDlg::SaveTree(VTREE &rvTree, HTREEITEM hRoot)
{
	TV_ITEM tvi;
	HTREEITEM hItem = hRoot;

	do 
	{
		// Save current item
		tvi.mask = TVIF_PARAM | TVIF_HANDLE;
		tvi.hItem = hItem;

		if(m_ctrlTree.GetItem(&tvi))
		{
			rvTree.push_back(GetItemParam(tvi.lParam)); // Raw value

			// If this item has chilren, save them too
			if(m_ctrlTree.ItemHasChildren(hItem))
			{
				// Insert proper tokens
				rvTree.push_back(TST_LEFTBRACKET);
				SaveTree(rvTree, m_ctrlTree.GetChildItem(hItem));
				rvTree.push_back(TST_RIGHTBRACKET);
			} // if
		} // if

		// Proceed with siblings
		hItem = m_ctrlTree.GetNextSiblingItem(hItem);
	} 
	while(0 != hItem);
}

void CExileDlg::OnAppAbout() 
{
	CAboutDlg dlgAbout;
	
	dlgAbout.DoModal();
}

void CExileDlg::LoadTree(VTREE &rvTree, HTREEITEM hRoot)
{
	if(rvTree.empty())
		return;

	// Starting from the beginning of the vector
	VTREE::iterator ti = rvTree.begin();
	MENTRY::iterator emi;
	HTREEITEM hItem = hRoot;

	do 
	{
		// If item we found is a token
		if(TST_LEFTBRACKET == *ti) 
		{
			ti = rvTree.erase(ti);
			LoadTree(rvTree, hItem);
		} // if
		else if(TST_RIGHTBRACKET == *ti) 
		{
			ti = rvTree.erase(ti);
			return;
		} // else if
		else if(m_mEntries.end() != (emi = m_mEntries.find(*ti))) // Otherwise
		{
			// We have to decrypt an entry, add an item to the tree and encrypt the item again
			DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);

			// Adding
			TV_INSERTSTRUCT tvIns;

			tvIns.hParent = hRoot;
			tvIns.hInsertAfter = 0;
			tvIns.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE;
			tvIns.item.hItem = 0;
			tvIns.item.state = 0;
			tvIns.item.cchTextMax = nNameLength;
			tvIns.item.pszText = emi->second.pePrivate.szName;
			tvIns.item.lParam = (emi->second.nFlags & EF_CATEGORY ? SetDropTarget(emi->second.lID) : emi->second.lID);
			tvIns.item.iImage = emi->second.lIconID;
			tvIns.item.iSelectedImage = emi->second.lIconID;

			hItem = m_ctrlTree.InsertItem(&tvIns);

			EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);

			if(!rvTree.empty())
				ti = rvTree.erase(ti);
		} // else if		
	} 
	while(!rvTree.empty());
}

void CExileDlg::SetLogin(TCHAR *pszLogin)
{
	SetDlgItemText(IDC_LOGIN, pszLogin);
}

void CExileDlg::SetPassword(TCHAR *pszPassword)
{
	if(m_bShowPassword)
		SetDlgItemText(IDC_PASSWORD, pszPassword);
	else
		SetDlgItemText(IDC_PASSWORD, _T("**********")); // Not using SetPasswordChar() or whatever...
}

void CExileDlg::CompactString(CDC *pDC, TCHAR *pszString, int nWidth)
{
#ifdef _UNICODE
#else
#endif // _UNICODE
}

void CExileDlg::OnClose() 
{
	if(m_bAutosave && (!m_mEntries.empty()) && m_bDirty)
	{
		SaveStorage(FALSE);
	} // if
	else
		ProcessDirtyStorage();

	CloseStorage();
	
	CDialog::OnClose();
}

void CExileDlg::OnToolsMd5hashgenerator() 
{
	CMD5HashGeneratorDialog dlgMdx;

	//
	// Setings
	//
	dlgMdx.m_nHashOptions = m_nHashOptions;

	dlgMdx.DoModal();

	//
	// Back
	//
	m_nHashOptions = dlgMdx.m_nHashOptions;
}

void CExileDlg::OnToolsPasswordgenerator() 
{
	CPasswordGeneratorDialog dlgPassword;

	//
	// Transferring settings
	//
	dlgPassword.m_bDecimalDigits = m_bDecimalDigits;
	dlgPassword.m_bLowercase = m_bLowercase;
	dlgPassword.m_bPunctuation = m_bPunctuation;
	dlgPassword.m_bSpecial = m_bSpecial;
	dlgPassword.m_bUppercase = m_bUppercase;
	dlgPassword.m_nPasswordLength = m_nPasswordLength;

	dlgPassword.DoModal();

	//
	// And back
	//
	m_bDecimalDigits = dlgPassword.m_bDecimalDigits;
	m_bLowercase = dlgPassword.m_bLowercase;
	m_bPunctuation = dlgPassword.m_bPunctuation;
	m_bSpecial = dlgPassword.m_bSpecial;
	m_bUppercase = dlgPassword.m_bUppercase;
	m_nPasswordLength = dlgPassword.m_nPasswordLength;
}

void CExileDlg::OnPasswordTitle() 
{
	m_bShowPassword = !m_bShowPassword;
	ShowEntry(m_ctrlTree.GetSelectedItem());
}

void CExileDlg::OnEditDelete() 
{
	DeleteItem(m_ctrlTree.GetSelectedItem());
}

void CExileDlg::OnEditEdit() 
{
	// See what we have to edit
	if(m_ctrlTree.GetSelectedItem())
	{
		TV_ITEM tvi;
		tvi.mask = TVIF_PARAM | TVIF_HANDLE;
		tvi.hItem = m_ctrlTree.GetSelectedItem();

		if(m_ctrlTree.GetItem(&tvi)) 
		{
			MENTRY::iterator emi = m_mEntries.find(GetItemParam(tvi.lParam));

			if(m_mEntries.end() != emi) 
			{
				// If it is a category, edit one
				if(emi->second.nFlags & EF_CATEGORY) 
				{
					EditCategory(m_ctrlTree.GetSelectedItem());
				} // if
				else if(emi->second.nFlags & EF_ELEMENT)
				{
					EditElement(m_ctrlTree.GetSelectedItem());
				} // else
			} // if
		} // if		
	} // if
}

void CExileDlg::OnEditStorageproperties() 
{
	CStoragePropertiesDialog dlgProps;

	dlgProps.m_nKeySize = m_kiKeyInfo.nKeySize;
	dlgProps.m_nRounds = m_kiKeyInfo.nRounds;

	if(IDOK == dlgProps.DoModal()) 
	{
		// Need to recrypt from old context to a newly acquired one		
		BeginWaitCursor();

		HRC5CONTEXT hRc5 = 0;

		GeneratePrivateKey(dlgProps.m_strUserName, dlgProps.m_strMasterPassword, dlgProps.m_nKeySize, m_kiKeyInfo);

		m_kiKeyInfo.nRounds = dlgProps.m_nRounds;

		// Acquiring new crypting context and setting a new key
		if(!::Rc5AcquireContext(hRc5, m_kiKeyInfo.nKeySize / 8, m_kiKeyInfo.nRounds))
		{
			MessageBoxEx(*this, IDS_RC5ACQUIRECONTEXTFAILED, IDS_TITLE);
			CleanPrivateData();
			EndWaitCursor();
			return;
		} // if

		if(!::Rc5SetBinaryPrivateKey(hRc5, m_kiKeyInfo.pbKey))
		{
			MessageBoxEx(*this, IDS_RC5SETBINARYPRIVATEKEYFAILED, IDS_TITLE);
			CleanPrivateData();
			EndWaitCursor();
			return;
		} // if

		// So now we can delete key buffer in order not
		// to expose it anymore
		FreeBuffer(m_kiKeyInfo.pbKey, m_kiKeyInfo.nKeySize / 8);

		// Recrypting entries
		MENTRY::iterator emi = m_mEntries.begin();

		for( ; m_mEntries.end() != emi; ++emi)
		{
			::Rc5RecryptBlock(m_hRc5, hRc5, (RC5_WORD *)&(emi->second.pePrivate), 
				(RC5_WORD *)&(emi->second.pePrivate), sizeof(PRIVATEENTRY) / 8);
		} // for

		// Freeing old context
		::Rc5ReleaseContext(m_hRc5);
		m_hRc5 = hRc5;

		ProcessSortOrder();
		SetDirty(TRUE);

		EndWaitCursor();
	} // if
}

void CExileDlg::DeleteItem(HTREEITEM hItem)
{
	if(hItem) 
	{
		TV_ITEM tvi;
		tvi.mask = TVIF_PARAM | TVIF_HANDLE;
		tvi.hItem = hItem;

		if(m_ctrlTree.GetItem(&tvi)) 
		{
			MENTRY::iterator emi = m_mEntries.find(GetItemParam(tvi.lParam));

			if(m_mEntries.end() != emi) 
			{
				// If it is a category, ask if we really want to delete
				if(emi->second.nFlags & EF_CATEGORY) 
				{
					CString strTitle, strText;
					strTitle.LoadString(IDS_TITLE);
					strText.LoadString(IDS_CONFIRMDELETECATEGORY);

					if(IDNO == ::MessageBox(*this, strText, strTitle, MB_YESNO | MB_ICONQUESTION))
						return;
				} // if
				else if(emi->second.nFlags & EF_ELEMENT)
				{
					if(IDNO == MessageBoxEx(*this, IDS_CONFIRMDELETEELEMENT, IDS_TITLE, MB_YESNO | MB_ICONQUESTION))
						return;
				} // else if

				DeleteItems(hItem, TRUE);
			} // if
		} // if
	} // if
}

void CExileDlg::DeleteItems(HTREEITEM hRoot, BOOL bFirstCall)
{
	if(!hRoot)
		return;

	HTREEITEM hItem = hRoot;
	MENTRY::iterator emi;
	TV_ITEM tvi;
	
	do 
	{
		tvi.mask = TVIF_PARAM | TVIF_HANDLE;
		tvi.hItem = hItem;

		if(m_ctrlTree.GetItem(&tvi)) 
		{
			if(m_ctrlTree.ItemHasChildren(hItem))
				DeleteItems(m_ctrlTree.GetChildItem(hItem), FALSE);

			// Deleting this item
			if(m_mEntries.end() != (emi = m_mEntries.find(GetItemParam(tvi.lParam))))
			{
				HTREEITEM hCurrent = hItem;

				// When DeleteItems() is called for the first time,
				// delete only this particular items without siblings.
				if(!bFirstCall)
					hItem = m_ctrlTree.GetNextSiblingItem(hItem);
				else
					hItem = 0;

				CleanBuffer(&emi->second, sizeof(ENTRY));
				m_mEntries.erase(emi);
				
				m_ctrlTree.DeleteItem(hCurrent);

				SetDirty(TRUE);
			} // if
		} // if		
	} 
	while(hItem);
}

void CExileDlg::EditElement(HTREEITEM hItem)
{
	TV_ITEM tvi;
	HTREEITEM hRoot;
	tvi.mask = TVIF_PARAM | TVIF_HANDLE;
	tvi.hItem = hRoot = m_ctrlTree.GetSelectedItem();

	if(m_ctrlTree.GetItem(&tvi)) 
	{
		MENTRY::iterator emi = m_mEntries.find(GetItemParam(tvi.lParam));

		if(m_mEntries.end() != emi) 
		{
			if(!(emi->second.nFlags & EF_ELEMENT))
				return;

			DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);

			CEditElementDialog dlgEdit;
			dlgEdit.SetImageList(m_pimgList);

			dlgEdit.m_strElementName = emi->second.pePrivate.szName;
			dlgEdit.m_strLogin = emi->second.pePrivate.szLogin;
			dlgEdit.m_strPassword = emi->second.pePrivate.szPassword;
			dlgEdit.m_strAddress = emi->second.pePrivate.szAddress;
			dlgEdit.m_strNotes = emi->second.pePrivate.szNotes;
			dlgEdit.m_wModifiers = emi->second.pePrivate.exData.wModifiers;
			dlgEdit.m_wVKCode = emi->second.pePrivate.exData.wVKCode;
			dlgEdit.SetIconID(emi->second.lIconID);
			dlgEdit.SetRating(emi->second.pePrivate.exData.cRating);

			//
			// Password Generator
			//
			dlgEdit.m_bDecimalDigits = m_bDecimalDigits;
			dlgEdit.m_bLowercase = m_bLowercase;
			dlgEdit.m_bPunctuation = m_bPunctuation;
			dlgEdit.m_bSpecial = m_bSpecial;
			dlgEdit.m_bUppercase = m_bUppercase;
			dlgEdit.m_nPasswordLength = m_nPasswordLength;

			if((emi->second.pePrivate.exData.wModifiers)  && (emi->second.pePrivate.exData.wVKCode))
			{
				// Unregister hot key in case something happens
				::UnregisterHotKey(GetSafeHwnd(), emi->second.lID);
			} // if			

			if(IDOK == dlgEdit.DoModal())
			{
				// Changing map info
				emi->second.lIconID = dlgEdit.GetIconID();
				emi->second.pePrivate.exData.wModifiers = dlgEdit.m_wModifiers;
				emi->second.pePrivate.exData.wVKCode = dlgEdit.m_wVKCode;
				emi->second.pePrivate.exData.cRating = dlgEdit.GetRating();
#ifdef _UNICODE
				wcscpy(emi->second.pePrivate.szName, dlgEdit.m_strElementName.LockBuffer());
				wcscpy(emi->second.pePrivate.szNotes, dlgEdit.m_strNotes.LockBuffer());
				wcscpy(emi->second.pePrivate.szAddress, dlgEdit.m_strAddress.LockBuffer());
				wcscpy(emi->second.pePrivate.szLogin, dlgEdit.m_strLogin.LockBuffer());
				wcscpy(emi->second.pePrivate.szPassword, dlgEdit.m_strPassword.LockBuffer());
#else
				strcpy(emi->second.pePrivate.szName, dlgEdit.m_strElementName.LockBuffer());
				strcpy(emi->second.pePrivate.szNotes, dlgEdit.m_strNotes.LockBuffer());
				strcpy(emi->second.pePrivate.szAddress, dlgEdit.m_strAddress.LockBuffer());
				strcpy(emi->second.pePrivate.szLogin, dlgEdit.m_strLogin.LockBuffer());
				strcpy(emi->second.pePrivate.szPassword, dlgEdit.m_strPassword.LockBuffer());
#endif // _UNICODE

				// Hot key
				if((emi->second.pePrivate.exData.wModifiers) && (emi->second.pePrivate.exData.wVKCode) && m_bHotKeys)
				{
					if(!::RegisterHotKey(GetSafeHwnd(), emi->second.lID, 
						MapModifiers(emi->second.pePrivate.exData.wModifiers),
						emi->second.pePrivate.exData.wVKCode))
						TRACE("Failed to register hot key for %s\n", emi->second.pePrivate.szName);
				} // if

				// Renaming tree item
				tvi.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
				tvi.cchTextMax = dlgEdit.m_strElementName.GetLength() + 1;
				tvi.pszText = dlgEdit.m_strElementName.LockBuffer();		
				tvi.iImage = dlgEdit.GetIconID();
				tvi.iSelectedImage = dlgEdit.GetIconID();
				tvi.hItem = m_ctrlTree.GetSelectedItem();

				m_ctrlTree.SetItem(&tvi);

				SetDirty(TRUE);
				SortItems(hRoot);

				//
				// Password Generator
				//
				m_bDecimalDigits = dlgEdit.m_bDecimalDigits;
				m_bLowercase = dlgEdit.m_bLowercase;
				m_bPunctuation = dlgEdit.m_bPunctuation;
				m_bSpecial = dlgEdit.m_bSpecial;
				m_bUppercase = dlgEdit.m_bUppercase;
				m_nPasswordLength = dlgEdit.m_nPasswordLength;
			} // if

			EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);

			// After it was encrypted back
			ShowEntry(m_ctrlTree.GetSelectedItem());
		} // if
	} // if	
}

void CExileDlg::EditCategory(HTREEITEM hItem)
{
	TV_ITEM tvi;
	HTREEITEM hRoot;
	tvi.mask = TVIF_PARAM | TVIF_HANDLE;
	tvi.hItem = hRoot = m_ctrlTree.GetSelectedItem();

	if(m_ctrlTree.GetItem(&tvi)) 
	{
		MENTRY::iterator emi = m_mEntries.find(GetItemParam(tvi.lParam));

		if(m_mEntries.end() != emi) 
		{
			if(!(emi->second.nFlags & EF_CATEGORY))
				return;

			DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);

			CEditCategoryDialog dlgEdit;
			dlgEdit.SetImageList(m_pimgList);

			dlgEdit.m_strCategoryName = emi->second.pePrivate.szName;
			dlgEdit.m_strDescription = emi->second.pePrivate.szNotes;
			dlgEdit.SetIconID(emi->second.lIconID);
			dlgEdit.SetRating(emi->second.pePrivate.exData.cRating);

			if(IDOK == dlgEdit.DoModal())
			{
				// Changing map info
				emi->second.lIconID = dlgEdit.GetIconID();
				emi->second.pePrivate.exData.cRating = dlgEdit.GetRating();
#ifdef _UNICODE
				wcscpy(emi->second.pePrivate.szName, dlgEdit.m_strCategoryName.LockBuffer());
				wcscpy(emi->second.pePrivate.szNotes, dlgEdit.m_strDescription.LockBuffer());
#else
				strcpy(emi->second.pePrivate.szName, dlgEdit.m_strCategoryName.LockBuffer());
				strcpy(emi->second.pePrivate.szNotes, dlgEdit.m_strDescription.LockBuffer());
#endif // _UNICODE

				// Renaming tree item
				tvi.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
				tvi.cchTextMax = dlgEdit.m_strCategoryName.GetLength() + 1;
				tvi.pszText = dlgEdit.m_strCategoryName.LockBuffer();		
				tvi.iImage = dlgEdit.GetIconID();
				tvi.iSelectedImage = dlgEdit.GetIconID();
				tvi.hItem = m_ctrlTree.GetSelectedItem();

				m_ctrlTree.SetItem(&tvi);

				SetDirty(TRUE);
				SortItems(hRoot);
			} // if

			EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);

			// After it was encrypted back
			ShowEntry(m_ctrlTree.GetSelectedItem());
		} // if
	} // if	
}

void CExileDlg::SetDirty(BOOL bDirty)
{
	m_bDirty = bDirty;
	SetTitle();
}

void CExileDlg::OnRclickTree(NMHDR* pNMHDR, LRESULT* pResult) 
{
	// Sort of "IntelliMenu" - depends on the item selected
	HTREEITEM hItem;
	CPoint ptCur;
	CMenu mCtx, *pmCtx = 0;

	::GetCursorPos(&ptCur);	
	m_ctrlTree.ScreenToClient(&ptCur);

	hItem = m_ctrlTree.HitTest(ptCur, 0);
	
	if(hItem)
	{		
		TV_ITEM tvi;
		tvi.mask = TVIF_PARAM | TVIF_HANDLE;
		tvi.hItem = hItem;

		if(m_ctrlTree.GetItem(&tvi)) 
		{
			MENTRY::iterator emi = m_mEntries.find(GetItemParam(tvi.lParam));

			if(m_mEntries.end() != emi)
			{
				m_ctrlTree.SelectItem(hItem);
				
				if(emi->second.nFlags & EF_ROOTCATEGORY)
				{
					mCtx.LoadMenu(IDR_ROOT_CONTEXT);
					pmCtx = mCtx.GetSubMenu(0);
				} // if
				else if(emi->second.nFlags & EF_CATEGORY) 
				{
					mCtx.LoadMenu(IDR_CATEGORY_CONTEXT);
					pmCtx = mCtx.GetSubMenu(0);
				} // else if
				else if(emi->second.nFlags & EF_ELEMENT)
				{
					mCtx.LoadMenu(IDR_ELEMENT_CONTEXT);
					pmCtx = mCtx.GetSubMenu(0);
				} // else if

				m_ctrlTree.ClientToScreen(&ptCur);

				if(0 != pmCtx)
				{
					pmCtx->TrackPopupMenu(TPM_LEFTALIGN, ptCur.x, ptCur.y, this);
				} // if
			} // if
		} // if
	} // if

	*pResult = 0;
}

void CExileDlg::SetAddress(TCHAR *pszAddress)
{
	SetDlgItemText(IDC_ADDRESS, pszAddress);
}

void CExileDlg::SetNotes(TCHAR *pszNotes)
{
	SetDlgItemText(IDC_NOTES, pszNotes);
}

BOOL CExileDlg::PreTranslateMessage(MSG* pMsg) 
{
	if(TranslateAccelerator(m_hWnd, m_hAccel, pMsg))
		return TRUE;

	return CDialog::PreTranslateMessage(pMsg);
}

void CExileDlg::SetKeyInfo(int nKeySize)
{
	CString strKI;

	switch(nKeySize) 
	{
	case 1024:
		strKI.LoadString(IDS_KEY1024);
		break;
	case 512:
		strKI.LoadString(IDS_KEY512);
		break;
	case 256:
		strKI.LoadString(IDS_KEY256);
		break;
	case 128:
		strKI.LoadString(IDS_KEY128);
		break;
	default:
		break;
	} // switch

	// TODO: Remove if want to see this
	// SetDlgItemText(IDC_KEYINFO_TITLE, strKI);
}

LRESULT CExileDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	MENTRY::iterator emi;
	HWND hForeground = 0; 
	HWND hFocused = 0;
	DWORD dwForegroungThreadID = 0;
	DWORD dwCurrentTreadID = 0;
	TCHAR szWindowTitle[nWindowTitleLength];

	switch(message) 
	{
	case WM_TIMER:
		if(g_uTimerID == wParam)
			PerformAutoCleanClipboard();

		return 0; // Processed
	case WM_SIZE:
		if((SIZE_MINIMIZED == wParam) && m_bMinimizeToTray) // Minimizing to tray
			TrayWindow(TRUE);
		else
			return CDialog::WindowProc(message, wParam, lParam);

		return 0; // Processed.
	case WM_TRAYCALLBACK:
		if(IDR_MAINFRAME != wParam)
			break;

		if(WM_LBUTTONDBLCLK == lParam)
			TrayWindow(FALSE); // Restoring

		if(WM_RBUTTONDOWN == lParam)
			ShowTrayMenu();
		return 0; // Processed
	case WM_HOTKEY:
		// wParam contains hotkey identifier, which is actually element index,
		// so we have to decrypt appropriate entry and send message to
		// focused window to set window text with a password.
		// wParam == 0 is a SmartType hot key
		if((0 == wParam) && (m_bSmartType))
		{
			// Invoking SmartType. Retrieving target window title
			hForeground = ::GetForegroundWindow();
			if(!hForeground)
				return 0;
			
			if(!(::GetWindowText(::GetAncestor(hForeground, GA_ROOT), szWindowTitle, nWindowTitleLength)))
				return 0;

			TRACE("Activating SmartType for %s\n", szWindowTitle);

			// Searching through Advanced items
			MADVANCED::iterator ami = m_mAdvanced.begin();			

			for( ; m_mAdvanced.end() != ami; ++ami)
			{
#ifdef _UNICODE
				if((!wcscmp(szWindowTitle, ami->second.sti.szWindowTitle)) && (ami->second.sti.bEnabled)) 
#else
				if((!strcmp(szWindowTitle, ami->second.sti.szWindowTitle)) && (ami->second.sti.bEnabled)) 
#endif // _UNICODE
				{
					dwForegroungThreadID = ::GetWindowThreadProcessId(hForeground, NULL);
					dwCurrentTreadID = ::GetCurrentThreadId();

					// Sharing input focus
					if(::AttachThreadInput(dwCurrentTreadID, dwForegroungThreadID, TRUE))
					{
						MENTRY::iterator emi = m_mEntries.find(ami->second.lID);

						if(m_mEntries.end() != emi)
						{
							DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);

							hFocused = ::GetDlgItem(hForeground, ami->second.sti.nLoginCtrlID);
							::SendMessage(hFocused, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)emi->second.pePrivate.szLogin);

							hFocused = ::GetDlgItem(hForeground, ami->second.sti.nPasswordCtrlID);
							::SendMessage(hFocused, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)emi->second.pePrivate.szPassword);

							EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);
						} // if

						::AttachThreadInput(dwCurrentTreadID, dwForegroungThreadID, FALSE);
					} // if

					return 0;
				} // if
			} // for

			// If we got here than nothing suitable is found
			::MessageBeep(MB_ICONEXCLAMATION);

			return 0;
		} // if

		// Otherwise we send a password to a
		// focused window

		if(m_mEntries.end() == (emi = m_mEntries.find((long)wParam)))
			break;		

		// We need to attach that thread to our process
		 hForeground = ::GetForegroundWindow();
		dwForegroungThreadID = ::GetWindowThreadProcessId(hForeground, NULL);
		dwCurrentTreadID = ::GetCurrentThreadId();

		// Sharing input focus
		if(::AttachThreadInput(dwCurrentTreadID, dwForegroungThreadID, TRUE))
		{
			hFocused = ::GetFocus();
		
			// Sending password
			DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);

			::SendMessage(hFocused, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)emi->second.pePrivate.szPassword);

			EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);			

			::AttachThreadInput(dwCurrentTreadID, dwForegroungThreadID, FALSE);
		} // if
		return 0;
	default:
		break;
	} // switch

	return CDialog::WindowProc(message, wParam, lParam);
}

void CExileDlg::TrayWindow(BOOL bMode)
{
	if(bMode) 
	{
		ShowWindow(SW_MINIMIZE);
		ShowWindow(SW_HIDE);
		m_bMaximized = FALSE;
	} // if
	else 
	{
		ShowWindow(SW_SHOW);
		ShowWindow(SW_RESTORE);
		m_bMaximized = TRUE;
	} // else
}

void CExileDlg::AddTrayIcon(UINT nIconID)
{
	NOTIFYICONDATA nid = { 0 };
	CString str;
	str.LoadString(IDS_TITLE);

	nid.cbSize = sizeof(nid);
	nid.hIcon = AfxGetApp()->LoadIcon(nIconID);
	nid.hWnd = GetSafeHwnd();
	lstrcpyn(nid.szTip, str.LockBuffer(), sizeof(nid.szTip) / sizeof(nid.szTip[0]));
	nid.uCallbackMessage = WM_TRAYCALLBACK;
	nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
	nid.uID = nIconID; // Icon ID to operate with

	Shell_NotifyIcon(NIM_ADD, &nid);
}

void CExileDlg::ShowTrayMenu()
{
	CMenu mCtx;
	mCtx.LoadMenu(IDR_TRAYMENU);

	CMenu *pmCtx = mCtx.GetSubMenu(0);
	CPoint pt;

	::GetCursorPos(&pt);
	::SetForegroundWindow(GetSafeHwnd());

	pmCtx->EnableMenuItem(ID_TRAYMENU_RESTORE, MF_BYCOMMAND | (m_bMaximized ? MF_DISABLED | MF_GRAYED : MF_ENABLED));
	pmCtx->EnableMenuItem(ID_FILE_CLOSE, MF_BYCOMMAND | (m_mEntries.empty() ? MF_DISABLED | MF_GRAYED : MF_ENABLED));
	pmCtx->CheckMenuItem(ID_TRAYMENU_ENABLEHOTKEYS, MF_BYCOMMAND | (m_bHotKeys ? MF_CHECKED : MF_UNCHECKED));

	pmCtx->TrackPopupMenu(TPM_RIGHTALIGN, pt.x, pt.y, this);
}

void CExileDlg::OnTraymenuRestore() 
{
	TrayWindow(FALSE);
}

void CExileDlg::RemoveTrayIcon(UINT nIconID)
{
	NOTIFYICONDATA nid;
	
	nid.cbSize = sizeof(nid);
	nid.hWnd = GetSafeHwnd();
	nid.uID = nIconID;

	Shell_NotifyIcon(NIM_DELETE, &nid);
}

void CExileDlg::ConvertStorage(long lVersion)
{
	TRACE("Converting from version %d.%d to %d.%d\n", HIWORD(lVersion), LOWORD(lVersion), 
		HIWORD(STORAGEVERSION), LOWORD(STORAGEVERSION));
	
	MENTRY::iterator ei = m_mEntries.begin();

	switch(lVersion) 
	{
	case MAKELONG(0, 1): // From 1.0
		// This for this version we had 48 bytes reserved in abReserved and
		// they must be set to zero to avoid problems
		for(; ei != m_mEntries.end(); ++ei)
		{
			DecryptPrivateEntry(ei->second.pePrivate, m_hRc5);
			memset((void *)&(ei->second.pePrivate.abReserved), 0, sizeof(ei->second.pePrivate.abReserved));
			ei->second.lReserved = 0;
			ei->second.pePrivate.exData.cRating = 5;
			EncryptPrivateEntry(ei->second.pePrivate, m_hRc5);
		} // for
		break;
	case MAKELONG(1, 1): // From 1.1
		// Set Rating to Medium for all items
		for(; ei != m_mEntries.end(); ++ei)
		{
			DecryptPrivateEntry(ei->second.pePrivate, m_hRc5);
			ei->second.pePrivate.exData.cRating = 5;
			ei->second.lReserved = 0;
			EncryptPrivateEntry(ei->second.pePrivate, m_hRc5);
		} // for
		break;
	case MAKELONG(4, 1): // From 1.4
		// For the time being no conversion is required
		break;
	default:
		break;
	} // switch
}

void CExileDlg::RegisterHotKeys()
{
	// Unregistering hot keys
	MENTRY::iterator emi = m_mEntries.begin();

	while(m_mEntries.end() != emi) 
	{
		DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);
		
		if((emi->second.pePrivate.exData.wModifiers)  && (emi->second.pePrivate.exData.wVKCode))
		{
			if(!::RegisterHotKey(GetSafeHwnd(), emi->second.lID, MapModifiers(emi->second.pePrivate.exData.wModifiers),
				emi->second.pePrivate.exData.wVKCode))
				TRACE("Failed to register hot key for %s\n", emi->second.pePrivate.szName);
			else
				TRACE("Successfully registered hot key for %s\n", emi->second.pePrivate.szName);
		} // if

		EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);

		++emi;
	} // while
}

void CExileDlg::UnregisterHotKeys()
{
	// Unregistering hot keys
	MENTRY::iterator emi = m_mEntries.begin();

	while(m_mEntries.end() != emi) 
	{
		DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);
		
		if((emi->second.pePrivate.exData.wModifiers)  && (emi->second.pePrivate.exData.wVKCode))
		{
			::UnregisterHotKey(GetSafeHwnd(), emi->second.lID);
		} // if

		EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);

		++emi;
	} // while
}

void CExileDlg::OnTraymenuEnablehotkeys() 
{
	m_bHotKeys = !m_bHotKeys;

	if(m_bHotKeys) 
	{
		RegisterHotKeys();
	} // if
	else 
	{
		UnregisterHotKeys();
	} // else

	// To update information
	ShowEntry(m_ctrlTree.GetSelectedItem());
}

void CExileDlg::OnEditOptions() 
{
	COptionsDialog dlgOpt;

	dlgOpt.m_bMinimizeToTray = m_bMinimizeToTray;
	dlgOpt.m_bReloadLastStorage = m_bReloadLastStorage;
	dlgOpt.m_bAutosave = m_bAutosave;
	dlgOpt.m_bAutosort = m_bAutosort;
	dlgOpt.m_bSmartType = m_bSmartType;
	dlgOpt.SetHotKey(m_wModifiers, m_wKeyCode);
	dlgOpt.SetSortOrder(m_nSortOrder);
	dlgOpt.m_bBackup = m_bBackup;
	dlgOpt.m_bMaintainFileAssociations = m_bMaintain;
	dlgOpt.m_strStorageName = m_strStorageName;
	dlgOpt.m_bReloadReadonly = m_bReloadReadonly;
	dlgOpt.m_bShellOpenReadOnly = m_bShellOpenReadonly;
	dlgOpt.m_bClipboardErasing = m_bClipboardErasing;
	dlgOpt.m_nErasingTimeout = m_nErasingTimeout;

	// Unregistering SmartType hot key
	if(m_bSmartType)
	{
		::UnregisterHotKey(*this, 0);
	} // if

	if(IDOK == dlgOpt.DoModal()) 
	{
		m_nErasingTimeout = dlgOpt.m_nErasingTimeout;
		m_bClipboardErasing = dlgOpt.m_bClipboardErasing;
		m_bShellOpenReadonly = dlgOpt.m_bShellOpenReadOnly;
		m_bMinimizeToTray = dlgOpt.m_bMinimizeToTray;
		m_bReloadLastStorage = dlgOpt.m_bReloadLastStorage;
		m_bAutosave = dlgOpt.m_bAutosave;
		m_bAutosort = dlgOpt.m_bAutosort;
		m_bSmartType = dlgOpt.m_bSmartType;
		dlgOpt.GetHotKey(m_wModifiers, m_wKeyCode);
		m_nSortOrder = dlgOpt.GetSortOrder();
		m_bBackup = dlgOpt.m_bBackup;
		m_bReloadReadonly = dlgOpt.m_bReloadReadonly;
		if(m_bMaintain = dlgOpt.m_bMaintainFileAssociations)
			MaintainFileAssociations();

		// Registering hot key
		if(m_bSmartType)
		{
			::RegisterHotKey(*this, 0, MapModifiers(m_wModifiers), m_wKeyCode);
		} // if

		ProcessSortOrder();
	} // if
}

LRESULT CExileDlg::OnActivateApp(WPARAM wParam, LPARAM lParam)
{
	// Bring from tray
	if(!m_bMaximized)
		TrayWindow(FALSE);

	if(!IsWindowVisible())
		ShowWindow(SW_SHOW);

	if(IsIconic())
		ShowWindow(SW_RESTORE);

	SetForegroundWindow();
	
	return 1;
}

void CExileDlg::SetInfo(TCHAR *pszInfo)
{
	SetDlgItemText(IDC_INFO_TITLE, pszInfo);
}

LRESULT CExileDlg::OnTcexItemdragged(WPARAM wParam, LPARAM lParam)
{
	SetDirty(TRUE);
	return 0; // Ignored
}

void CExileDlg::OnCategorycontextSortNameascending() 
{
	HTREEITEM hParent = m_ctrlTree.GetSelectedItem();

	if(!hParent)
		return;

	BeginWaitCursor();

	// Some information on how to sort stuff we have
	SORTPARAMETERS spSort = { &m_mEntries, m_hRc5, SetAscending(0) };
	TV_SORTCB cbSort = { hParent, CompareNames, (LPARAM)&spSort }; 

	m_ctrlTree.SortChildrenCB((LPTVSORTCB)&cbSort);

	SetDirty(TRUE);

	EndWaitCursor();
}

void CExileDlg::OnCategorycontextSortNamedescending() 
{
	HTREEITEM hParent = m_ctrlTree.GetSelectedItem();

	if(!hParent)
		return;

	BeginWaitCursor();

	// Some information on how to sort stuff we have
	SORTPARAMETERS spSort = { &m_mEntries, m_hRc5, SetDescending(0) };
	TV_SORTCB cbSort = { hParent, CompareNames, (LPARAM)&spSort }; 

	m_ctrlTree.SortChildrenCB((LPTVSORTCB)&cbSort);

	SetDirty(TRUE);

	EndWaitCursor();
}

void CExileDlg::OnCategorycontextSortUsernameascending() 
{
	HTREEITEM hParent = m_ctrlTree.GetSelectedItem();

	if(!hParent)
		return;

	BeginWaitCursor();

	// Some information on how to sort stuff we have
	SORTPARAMETERS spSort = { &m_mEntries, m_hRc5, SetAscending(0) };
	TV_SORTCB cbSort = { hParent, CompareUsernames, (LPARAM)&spSort }; 

	m_ctrlTree.SortChildrenCB((LPTVSORTCB)&cbSort);

	SetDirty(TRUE);

	EndWaitCursor();
}

void CExileDlg::OnCategorycontextSortUsernamedescending() 
{
	HTREEITEM hParent = m_ctrlTree.GetSelectedItem();

	if(!hParent)
		return;

	BeginWaitCursor();

	// Some information on how to sort stuff we have
	SORTPARAMETERS spSort = { &m_mEntries, m_hRc5, SetDescending(0) };
	TV_SORTCB cbSort = { hParent, CompareUsernames, (LPARAM)&spSort }; 

	m_ctrlTree.SortChildrenCB((LPTVSORTCB)&cbSort);

	SetDirty(TRUE);

	EndWaitCursor();
}

void CExileDlg::OnCategorycontextSortRatingascending() 
{
	HTREEITEM hParent = m_ctrlTree.GetSelectedItem();

	if(!hParent)
		return;

	BeginWaitCursor();

	// Some information on how to sort stuff we have
	SORTPARAMETERS spSort = { &m_mEntries, m_hRc5, SetAscending(0) };
	TV_SORTCB cbSort = { hParent, CompareRatings, (LPARAM)&spSort }; 

	m_ctrlTree.SortChildrenCB((LPTVSORTCB)&cbSort);

	SetDirty(TRUE);

	EndWaitCursor();
}

void CExileDlg::OnCategorycontextSortRatingdescending() 
{
	HTREEITEM hParent = m_ctrlTree.GetSelectedItem();

	if(!hParent)
		return;

	BeginWaitCursor();

	// Some information on how to sort stuff we have
	SORTPARAMETERS spSort = { &m_mEntries, m_hRc5, SetDescending(0) };
	TV_SORTCB cbSort = { hParent, CompareRatings, (LPARAM)&spSort }; 

	m_ctrlTree.SortChildrenCB((LPTVSORTCB)&cbSort);

	SetDirty(TRUE);

	EndWaitCursor();	
}

int CExileDlg::CompareNames(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	LPSORTPARAMETERS lpSort = (LPSORTPARAMETERS)lParamSort;
	int nOrder = 0;

	MENTRY::iterator emi1 = lpSort->lpmEntries->find(GetItemParam(lParam1)), 
		emi2 = lpSort->lpmEntries->find(GetItemParam(lParam2));

	if((lpSort->lpmEntries->end() == emi1) || (lpSort->lpmEntries->end() == emi2))
		return 0;

	// Analyzing names
	DecryptPrivateEntry(emi1->second.pePrivate, lpSort->hRc5);
	DecryptPrivateEntry(emi2->second.pePrivate, lpSort->hRc5);

	if(IsAscending(lpSort->lParam))
	{
#ifdef _UNICODE
		nOrder = wcscmp(emi1->second.pePrivate.szName, emi2->second.pePrivate.szName);
#else
		nOrder = strcmp(emi1->second.pePrivate.szName, emi2->second.pePrivate.szName);
#endif // _UNICODE
	} // if
	else
	{
#ifdef _UNICODE
		nOrder = wcscmp(emi2->second.pePrivate.szName, emi1->second.pePrivate.szName);
#else
		nOrder = strcmp(emi2->second.pePrivate.szName, emi1->second.pePrivate.szName);
#endif // _UNICODE
	} // else

	EncryptPrivateEntry(emi1->second.pePrivate, lpSort->hRc5);
	EncryptPrivateEntry(emi2->second.pePrivate, lpSort->hRc5);

	return nOrder;
}

int CExileDlg::CompareUsernames(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	LPSORTPARAMETERS lpSort = (LPSORTPARAMETERS)lParamSort;
	int nOrder = 0;

	MENTRY::iterator emi1 = lpSort->lpmEntries->find(GetItemParam(lParam1)), 
		emi2 = lpSort->lpmEntries->find(GetItemParam(lParam2));

	if((lpSort->lpmEntries->end() == emi1) || (lpSort->lpmEntries->end() == emi2))
		return 0;

	// Analyzing user names (logins)
	DecryptPrivateEntry(emi1->second.pePrivate, lpSort->hRc5);
	DecryptPrivateEntry(emi2->second.pePrivate, lpSort->hRc5);

	if(IsAscending(lpSort->lParam))
	{
#ifdef _UNICODE
		nOrder = wcscmp(emi1->second.pePrivate.szLogin, emi2->second.pePrivate.szLogin);
#else
		nOrder = strcmp(emi1->second.pePrivate.szLogin, emi2->second.pePrivate.szLogin);
#endif // _UNICODE
	} // if
	else
	{
#ifdef _UNICODE
		nOrder = wcscmp(emi2->second.pePrivate.szLogin, emi1->second.pePrivate.szLogin);
#else
		nOrder = strcmp(emi2->second.pePrivate.szLogin, emi1->second.pePrivate.szLogin);
#endif // _UNICODE
	} // else

	EncryptPrivateEntry(emi1->second.pePrivate, lpSort->hRc5);
	EncryptPrivateEntry(emi2->second.pePrivate, lpSort->hRc5);

	return nOrder;
}

int CALLBACK CExileDlg::CompareRatings(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	LPSORTPARAMETERS lpSort = (LPSORTPARAMETERS)lParamSort;
	int nOrder = 0;

	MENTRY::iterator emi1 = lpSort->lpmEntries->find(GetItemParam(lParam1)), 
		emi2 = lpSort->lpmEntries->find(GetItemParam(lParam2));

	if((lpSort->lpmEntries->end() == emi1) || (lpSort->lpmEntries->end() == emi2))
		return 0;

	// Analyzing ratings
	DecryptPrivateEntry(emi1->second.pePrivate, lpSort->hRc5);
	DecryptPrivateEntry(emi2->second.pePrivate, lpSort->hRc5);

	if(IsAscending(lpSort->lParam))
	{
		nOrder = (int)(emi1->second.pePrivate.exData.cRating - emi2->second.pePrivate.exData.cRating);
	} // if
	else
	{
		nOrder = (int)(emi2->second.pePrivate.exData.cRating - emi1->second.pePrivate.exData.cRating);
	} // else

	EncryptPrivateEntry(emi1->second.pePrivate, lpSort->hRc5);
	EncryptPrivateEntry(emi2->second.pePrivate, lpSort->hRc5);

	return nOrder;
}

void CExileDlg::SortItems(HTREEITEM hRoot)
{
	if(!m_bAutosort)
		return;

	BeginWaitCursor();

	TV_SORTCB cbSort = { hRoot, m_soSortOrder.pfnCompare, (LPARAM)&(m_soSortOrder.spSort) }; 
	m_ctrlTree.SortChildrenCB((LPTVSORTCB)&cbSort);

	EndWaitCursor();
}

void CExileDlg::ProcessSortOrder()
{
	// Setting up SORTORDER
	if((m_nSortOrder < 0) || (m_nSortOrder > sizeof(g_aSortOrder) / sizeof(g_aSortOrder[0])))
		return;

	m_soSortOrder = g_aSortOrder[m_nSortOrder];
	m_soSortOrder.spSort.hRc5 = m_hRc5;
	m_soSortOrder.spSort.lpmEntries = &m_mEntries;

	switch(m_nSortOrder)
	{
	case 0:
	case 1:
		m_soSortOrder.pfnCompare = CompareNames;
		break;
	case 2:
	case 3:
		m_soSortOrder.pfnCompare = CompareUsernames;
		break;
	case 4:
	case 5:
		m_soSortOrder.pfnCompare = CompareRatings;
		break;
	default:
		break;
	} // switch
}

LRESULT CExileDlg::OnShleRButtondown(WPARAM wParam, LPARAM lParam)
{
	if(IDC_PASSWORD_TITLE == wParam)
	{
		TRACE("RClick on Password Title\n");

		// Copying password to clipboard
		HTREEITEM hItem = m_ctrlTree.GetSelectedItem();

		if(!hItem)
			return 0;

		TV_ITEM tvi;
		tvi.mask = TVIF_HANDLE | TVIF_PARAM;
		tvi.hItem = hItem;

		if(!m_ctrlTree.GetItem(&tvi))
			return 0;

		MENTRY::iterator emi = m_mEntries.find(tvi.lParam);

		if(m_mEntries.end() == emi)
			return 0;

		// Opening clipboard
		if(!::OpenClipboard(GetSafeHwnd()))
		{
			return 0;
		} // if

		::EmptyClipboard();

		DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);

		// Copying password to shared memory...
		HGLOBAL hPassword;
		LPTSTR lpszPassword;

#ifdef _UNICODE
		hPassword = ::GlobalAlloc(GMEM_MOVEABLE, (wcslen(emi->second.pePrivate.szPassword) + 1) * sizeof(TCHAR));

		lpszPassword = (LPTSTR)::GlobalLock(hPassword);
		wcscpy(lpszPassword, emi->second.pePrivate.szPassword);
		::GlobalUnlock(hPassword);
#else
		hPassword = ::GlobalAlloc(GMEM_MOVEABLE, (strlen(emi->second.pePrivate.szPassword) + 1) * sizeof(TCHAR));

		lpszPassword = (LPTSTR)::GlobalLock(hPassword);
		strcpy(lpszPassword, emi->second.pePrivate.szPassword);
		::GlobalUnlock(hPassword);
#endif // _UNICODE

		::SetClipboardData(CF_TEXT, hPassword);

		::CloseClipboard();

		EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);
	} // if

	return 0;
}

void CExileDlg::SaveStorageXml()
{
	MSXML2::IXMLDOMDocument2Ptr pXMLDoc;
    MSXML2::IXMLDOMNodePtr pXMLNode;
    MSXML2::IXMLDOMProcessingInstructionPtr pXMLPI;
    MSXML2::IXMLDOMCommentPtr pXMLC;

	if(FAILED(pXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30))))
    {
        // TODO: Message
        return;
    } // if

    pXMLPI = pXMLDoc->createProcessingInstruction("xml", "version='1.0'");
    if(0 != pXMLPI)
        pXMLDoc->appendChild(pXMLPI);

    // Adding comments
    pXMLC = pXMLDoc->createComment("octalforty Exile XML Password Storage.");
    if(0 != pXMLC)
        pXMLDoc->appendChild(pXMLC);

    pXMLC = pXMLDoc->createComment("Copyright (C) 2004 octalforty studios. All rights reserved.");
    if(0 != pXMLC)
        pXMLDoc->appendChild(pXMLC);

    // Creating root item with attributes which hold key-related information
    MSXML2::IXMLDOMElementPtr pXMLE = pXMLDoc->createElement("password-storage");
    if(0 != pXMLE)
    {        
        // Storage version
        MSXML2::IXMLDOMAttributePtr pXMLA = pXMLDoc->createAttribute("version");
        if(0 != pXMLA)
        {
            pXMLA->value = STORAGEVERSION; // In decimal, not <major>.<minor>
            pXMLE->setAttributeNode(pXMLA);
        } // if

        // Storage flags
        pXMLA = pXMLDoc->createAttribute("flags");
        if(0 != pXMLA)
        {
#ifdef _UNICODE
            pXMLA->value = SF_UNICODE_VERSION;
#else            
            pXMLA->value = SF_ANSI_VERSION;
#endif // _UNICODE
            pXMLE->setAttributeNode(pXMLA);
        } // if

        // Key size (in bits)
        pXMLA = pXMLDoc->createAttribute("keysize");
        if(0 != pXMLA)
        {
            pXMLA->value = (long)m_kiKeyInfo.nKeySize;
            pXMLE->setAttributeNode(pXMLA);
        } // if

        // Encryption rounds
        pXMLA = pXMLDoc->createAttribute("rounds");
        if(0 != pXMLA)
        {
            pXMLA->value = (long)m_kiKeyInfo.nRounds;
            pXMLE->setAttributeNode(pXMLA);
        } // if

        // <User Name> + <Master Password> hash
        pXMLA = pXMLDoc->createAttribute("passwordhash");
        if(0 != pXMLA)
        {
            TCHAR szHash[64];
#ifdef _UNICODE
            swprintf(szHash, _T("%08x%08x%08x%08x"), m_kiKeyInfo.hsPassword.wA,
                m_kiKeyInfo.hsPassword.wB, m_kiKeyInfo.hsPassword.wC, m_kiKeyInfo.hsPassword.wD);
#else            
            sprintf(szHash, _T("%08x%08x%08x%08x"), m_kiKeyInfo.hsPassword.wA,
                m_kiKeyInfo.hsPassword.wB, m_kiKeyInfo.hsPassword.wC, m_kiKeyInfo.hsPassword.wD);
#endif // _UNICODE

            pXMLA->value = szHash;
            pXMLE->setAttributeNode(pXMLA);
        } // if

        // Index
        pXMLA = pXMLDoc->createAttribute("index");
        if(0 != pXMLA)
        {
            pXMLA->value = m_lIndex;
            pXMLE->setAttributeNode(pXMLA);
        } // if

		// Structured view
		SaveTreeXml(pXMLDoc, pXMLE, m_ctrlTree.GetRootItem(), 1);
		pXMLE->appendChild(pXMLDoc->createTextNode("\n"));

		pXMLDoc->appendChild(pXMLE);
    } // if

    if(FAILED(pXMLDoc->save(m_strStorageName.LockBuffer())))
    {
    } // if

	m_strStorageName.UnlockBuffer();
}

MSXML2::IXMLDOMElementPtr CExileDlg::SaveTreeXml(MSXML2::IXMLDOMDocument2Ptr pXMLDoc, MSXML2::IXMLDOMElementPtr pXMLElement, 
										 HTREEITEM hRoot, int nIndent)
{
	TV_ITEM tvi;
	HTREEITEM hItem = hRoot;
	MSXML2::IXMLDOMElementPtr pXE;
	MSXML2::IXMLDOMAttributePtr pXA;

	do 
	{
		// Save current item
		tvi.mask = TVIF_PARAM | TVIF_HANDLE;
		tvi.hItem = hItem;		

		if(m_ctrlTree.GetItem(&tvi))
		{
			MENTRY::iterator emi = m_mEntries.find(GetItemParam(tvi.lParam));
			
			if(m_mEntries.end() == emi)
				return 0;

			DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);

			// Adding information about this particular item			
			if(emi->second.nFlags & EF_CATEGORY)
			{
				pXMLElement->appendChild(pXMLDoc->createTextNode("\n"));				
				pXE = pXMLDoc->createElement("category");				

				// Writing attributes
				// Item ID
				pXA = pXMLDoc->createAttribute("id");
				if(0 != pXA)
				{
					pXA->value = emi->second.lID;
					pXE->setAttributeNode(pXA);
				} // if

				// Item flags
				pXA = pXMLDoc->createAttribute("flags");
				if(0 != pXA)
				{
					pXA->value = (long)emi->second.nFlags;
					pXE->setAttributeNode(pXA);
				} // if

				// Entry icon
				pXA = pXMLDoc->createAttribute("icon");
				if(0 != pXA)
				{
					pXA->value = emi->second.lIconID;
					pXE->setAttributeNode(pXA);
				} // if

				pXE->appendChild(pXMLDoc->createTextNode(emi->second.pePrivate.szName));

				// If this item has chilren, save them too
				if(m_ctrlTree.ItemHasChildren(hItem))
				{
					SaveTreeXml(pXMLDoc, pXE, m_ctrlTree.GetChildItem(hItem), nIndent + 1);					
					pXE->appendChild(pXMLDoc->createTextNode("\n"));
					pXE->appendChild(pXMLDoc->createTextNode(Indent(nIndent).LockBuffer()));
				} // if								
				
				pXMLElement->appendChild(pXMLDoc->createTextNode(Indent(nIndent).LockBuffer()));
				pXMLElement->appendChild(pXE);
			} // if
			else if(emi->second.nFlags & EF_ELEMENT)
			{
				pXMLElement->appendChild(pXMLDoc->createTextNode("\n"));
				pXMLElement->appendChild(pXMLDoc->createTextNode(Indent(nIndent).LockBuffer()));
				pXE = pXMLDoc->createElement("element");

				// Writing attributes
				// Item ID
				pXA = pXMLDoc->createAttribute("id");
				if(0 != pXA)
				{
					pXA->value = emi->second.lID;
					pXE->setAttributeNode(pXA);
				} // if

				// Item flags
				pXA = pXMLDoc->createAttribute("flags");
				if(0 != pXA)
				{
					pXA->value = (long)emi->second.nFlags;
					pXE->setAttributeNode(pXA);
				} // if

				// Entry icon
				pXA = pXMLDoc->createAttribute("icon");
				if(0 != pXA)
				{
					pXA->value = emi->second.lIconID;
					pXE->setAttributeNode(pXA);
				} // if
				
				pXE->appendChild(pXMLDoc->createTextNode(emi->second.pePrivate.szName));
				pXMLElement->appendChild(pXE);
			} // else if
			
			EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);
		} // if

		// Proceed with siblings
		hItem = m_ctrlTree.GetNextSiblingItem(hItem);
	} 
	while(0 != hItem);
	
	return pXMLElement;
}

CString CExileDlg::Indent(int nIndent)
{
	CString s;
	for( ; nIndent; --nIndent)
		s += '\t';
	return s;
}

void CExileDlg::OnFileExportExporttoxml() 
{
	CExportToXmlDialog dlgExport;

	dlgExport.SetExportFlags(m_nExportFlags);
	dlgExport.m_strFileName = m_strExportFileName;

	if(IDOK == dlgExport.DoModal())
	{
		ExportXml(dlgExport.m_strFileName, dlgExport.GetExportFlags());
	} // if

	m_nExportFlags = dlgExport.GetExportFlags();
	m_strExportFileName = dlgExport.m_strFileName;
}

void CExileDlg::ExportXml(CString strFileName, unsigned int nExportFlags)
{
	MSXML2::IXMLDOMDocument2Ptr pXMLDoc;
    MSXML2::IXMLDOMNodePtr pXMLNode;
    MSXML2::IXMLDOMProcessingInstructionPtr pXMLPI;
    MSXML2::IXMLDOMCommentPtr pXMLC;

	if(FAILED(pXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30))))
    {
        // TODO: Message
        return;
    } // if

    pXMLPI = pXMLDoc->createProcessingInstruction("xml", "version='1.0'");
    if(0 != pXMLPI)
        pXMLDoc->appendChild(pXMLPI);

    // Adding comments
    pXMLC = pXMLDoc->createComment("Copyright (C) 2004 octalforty studios. All rights reserved.");
    if(0 != pXMLC)
        pXMLDoc->appendChild(pXMLC);

    // Creating root item
    MSXML2::IXMLDOMElementPtr pXMLE = pXMLDoc->createElement("passwordStorage");
    if(0 != pXMLE)
    {        
		// Structured view
		ExportTreeXml(pXMLDoc, pXMLE, m_ctrlTree.GetRootItem(), 1, nExportFlags);
		pXMLE->appendChild(pXMLDoc->createTextNode("\n"));

		pXMLDoc->appendChild(pXMLE);
    } // if

    if(FAILED(pXMLDoc->save(strFileName.LockBuffer())))
    {
    } // if

	strFileName.UnlockBuffer();
}

MSXML2::IXMLDOMElementPtr CExileDlg::ExportTreeXml(MSXML2::IXMLDOMDocument2Ptr pXMLDoc, MSXML2::IXMLDOMElementPtr pXMLElement, 
										   HTREEITEM hRoot, int nIndent, unsigned int nExportFlags)
{
	TV_ITEM tvi;
	HTREEITEM hItem = hRoot;
	MSXML2::IXMLDOMElementPtr pXE;
	MSXML2::IXMLDOMAttributePtr pXA;

	do 
	{
		// Save current item
		tvi.mask = TVIF_PARAM | TVIF_HANDLE;
		tvi.hItem = hItem;		

		if(m_ctrlTree.GetItem(&tvi))
		{
			MENTRY::iterator emi = m_mEntries.find(GetItemParam(tvi.lParam));
			
			if(m_mEntries.end() == emi)
				return 0;			

			// Adding information about this particular item			
			if(emi->second.nFlags & EF_CATEGORY)
			{
				DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);

				pXMLElement->appendChild(pXMLDoc->createTextNode("\n"));				
				pXE = pXMLDoc->createElement("category");

				// Writing attributes necessary

				// Category Name
				if(ExportCategoryName(nExportFlags))
				{
					pXA = pXMLDoc->createAttribute("categoryName");
					if(0 != pXA)
					{
						pXA->value = emi->second.pePrivate.szName;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				// Category Description
				if(ExportCategoryDescription(nExportFlags))
				{
					pXA = pXMLDoc->createAttribute("categoryDescription");
					if(0 != pXA)
					{
						pXA->value = emi->second.pePrivate.szNotes;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				// Category Icon
				if(ExportCategoryDescription(nExportFlags))
				{
					pXA = pXMLDoc->createAttribute("categoryIcon");
					if(0 != pXA)
					{
						pXA->value = emi->second.lIconID;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				// Category Rating
				if(ExportCategoryDescription(nExportFlags))
				{
					pXA = pXMLDoc->createAttribute("categoryRating");
					if(0 != pXA)
					{
						pXA->value = g_aRatings[emi->second.pePrivate.exData.cRating].szName;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				//pXE->appendChild(pXMLDoc->createTextNode(emi->second.pePrivate.szName));

				// Before any recursive calls
				EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);

				// If this item has chilren, save them too
				if(m_ctrlTree.ItemHasChildren(hItem))
				{
					ExportTreeXml(pXMLDoc, pXE, m_ctrlTree.GetChildItem(hItem), nIndent + 1, nExportFlags);					
					pXE->appendChild(pXMLDoc->createTextNode("\n"));
					pXE->appendChild(pXMLDoc->createTextNode(Indent(nIndent).LockBuffer()));
				} // if								
				
				pXMLElement->appendChild(pXMLDoc->createTextNode(Indent(nIndent).LockBuffer()));
				pXMLElement->appendChild(pXE);
			} // if
			else if(emi->second.nFlags & EF_ELEMENT)
			{
				DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);

				MADVANCED::iterator ami = m_mAdvanced.find(emi->second.lID);

				pXMLElement->appendChild(pXMLDoc->createTextNode("\n"));
				pXMLElement->appendChild(pXMLDoc->createTextNode(Indent(nIndent).LockBuffer()));
				pXE = pXMLDoc->createElement("element");

				// Writing attributes

				// Element Name
				if(ExportElementName(nExportFlags))
				{
					pXA = pXMLDoc->createAttribute("elementName");
					if(0 != pXA)
					{
						pXA->value = emi->second.pePrivate.szName;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				// Login
				if(ExportLogin(nExportFlags))
				{
					pXA = pXMLDoc->createAttribute("login");
					if(0 != pXA)
					{
						pXA->value = emi->second.pePrivate.szLogin;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				// Password
				if(ExportPassword(nExportFlags))
				{
					pXA = pXMLDoc->createAttribute("password");
					if(0 != pXA)
					{
						pXA->value = emi->second.pePrivate.szPassword;
						pXE->setAttributeNode(pXA);
					} // if
				} // if
				
				// Address
				if(ExportAddress(nExportFlags))
				{
					pXA = pXMLDoc->createAttribute("address");
					if(0 != pXA)
					{
						pXA->value = emi->second.pePrivate.szAddress;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				// Notes
				if(ExportNotes(nExportFlags))
				{
					pXA = pXMLDoc->createAttribute("notes");
					if(0 != pXA)
					{
						pXA->value = emi->second.pePrivate.szNotes;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				// Element Rating
				if(ExportElementRating(nExportFlags))
				{
					pXA = pXMLDoc->createAttribute("elementRating");
					if(0 != pXA)
					{
						pXA->value = g_aRatings[emi->second.pePrivate.exData.cRating].szName;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				// Element Icon
				if(ExportElementIcon(nExportFlags))
				{
					pXA = pXMLDoc->createAttribute("elementIcon");
					if(0 != pXA)
					{
						pXA->value = emi->second.lIconID;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				// SmartType
				if((ExportSmartType(nExportFlags)) && (m_mAdvanced.end() != ami))
				{
					pXA = pXMLDoc->createAttribute("SmartType");
					if(0 != pXA)
					{
						pXA->value = (long)ami->second.sti.bEnabled;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				// Target Window Title
				if((ExportTargetWindowTitle(nExportFlags)) && (m_mAdvanced.end() != ami))
				{
					pXA = pXMLDoc->createAttribute("targetWindowTitle");
					if(0 != pXA)
					{
						pXA->value = ami->second.sti.szWindowTitle;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				// Login Control ID
				if((ExportLoginControlID(nExportFlags)) && (m_mAdvanced.end() != ami))
				{
					pXA = pXMLDoc->createAttribute("loginControlID");
					if(0 != pXA)
					{
						pXA->value = (long)ami->second.sti.nLoginCtrlID;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				// Password Control ID
				if((ExportLoginControlID(nExportFlags)) && (m_mAdvanced.end() != ami))
				{
					pXA = pXMLDoc->createAttribute("passwordControlID");
					if(0 != pXA)
					{
						pXA->value = (long)ami->second.sti.nPasswordCtrlID;
						pXE->setAttributeNode(pXA);
					} // if
				} // if

				//pXE->appendChild(pXMLDoc->createTextNode(emi->second.pePrivate.szName));
				pXMLElement->appendChild(pXE);

				EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);
			} // else if			
		} // if

		// Proceed with siblings
		hItem = m_ctrlTree.GetNextSiblingItem(hItem);
	} 
	while(0 != hItem);
	
	return pXMLElement;
}

void CExileDlg::SaveStorageSerial()
{
	// Now freely saving
	CFile fStg;
	CFileException eFe;

	// Creating backup of a storage
	if(m_bBackup)
	{
		CString strDest = m_strStorageName.Left(m_strStorageName.Find(_T('.'))) + CString("_backup.pws");

		if(!::CopyFile(m_strStorageName, strDest, FALSE))
		{
			MessageBoxEx(*this, IDS_BACKUPSTORAGEFAILED, IDS_TITLE);
		} // if
	} // if

	if(!fStg.Open(m_strStorageName, CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive, &eFe)) 
	{
		MessageBoxEx(*this, IDS_CREATESTORAGEFAILED, IDS_TITLE);
		return;
	} // if

	BeginWaitCursor();

	// Traversing tree
	VTREE vTree;
	SaveTree(vTree, m_ctrlTree.GetRootItem());

	// Writing header
	STORAGEHEADER sth;

	// See typedefs.h
	sth.lTag = STORAGETAG;
	sth.lVersion = STORAGEVERSION;
	sth.lAdvanced = m_mAdvanced.size();
#ifdef _UNICODE
	sth.lFlags = SF_UNICODE_VERSION;
#else
	sth.lFlags = SF_ANSI_VERSION;
#endif // _UNICODE
	
	sth.nKeySize = m_kiKeyInfo.nKeySize;
	sth.nRounds = m_kiKeyInfo.nRounds;
	sth.hsPassword = m_kiKeyInfo.hsPassword;
	sth.lIndex = m_lIndex;
	sth.lElements = m_mEntries.size();
	sth.lNodes = vTree.size();

	fStg.Write((void *)&sth, sizeof(STORAGEHEADER));

	// Now writing tree structure information
	LONG *plTree = new LONG[vTree.size()];
	for(size_t s = 0; s < vTree.size(); ++s)
	{
		plTree[s] = vTree[s];
	} // for

	fStg.Write((void *)plTree, sizeof(LONG) * vTree.size());

	FreeBuffer(plTree, sizeof(LONG) * vTree.size());

	// And Private entries...
	MENTRY::iterator emi = m_mEntries.begin();

	while(m_mEntries.end() != emi) 
	{
		fStg.Write((void *)&emi->second, sizeof(ENTRY));
		++emi;
	} // while

	// Advanced stuff
	MADVANCED::iterator ami = m_mAdvanced.begin();

	while(m_mAdvanced.end() != ami)
	{
		fStg.Write((void *)&(ami->second), sizeof(ADVANCED));
		++ami;
	} // while

	// Done
	fStg.Close();

	SetDirty(FALSE);

	EndWaitCursor();
}

void CExileDlg::LoadStorageSerial()
{
	// Loading Storage
	CFile fStg;
	CFileException eFe;

	if(!fStg.Open(m_strStorageName, CFile::modeRead | CFile::shareExclusive, &eFe)) 
	{
		MessageBoxEx(*this, IDS_STORAGEOPENFAILED, IDS_TITLE);
		m_strStorageName.Empty();
		return;
	} // if

	// Reading header and asking for a password
	STORAGEHEADER sth;
	fStg.Read((void *)&sth, sizeof(STORAGEHEADER));

	// This section is common for all versions of storage files
	if(STORAGETAG == sth.lTag)
	{
#ifdef _UNICODE
		if(!(SF_UNICODE_VERSION & sth.lFlags))
		{
			MessageBoxEx(*this, IDS_NOTAUNICODEVERSION, IDS_TITLE);
			return;
		} // if
#else
		if(!(SF_ANSI_VERSION & sth.lFlags))
		{
			MessageBoxEx(*this, IDS_NOTANANSIVERSION, IDS_TITLE);
			return;
		} // if
#endif // _UNICODE

		MDXHASH hsPassword;
		CEnterPasswordDialog dlgPassword;

		do 
		{
			CleanString(dlgPassword.m_strUserName);
			CleanString(dlgPassword.m_strMasterPassword);

			dlgPassword.m_strMasterPassword.Empty();
			dlgPassword.m_strUserName.Empty();

			if(IDOK == dlgPassword.DoModal()) 
			{
				GeneratePasswordHash(dlgPassword.m_strUserName, dlgPassword.m_strMasterPassword, hsPassword);
			} // if
			else
				return;
		} 
		while(!::MdxEqualHashes(sth.hsPassword, hsPassword));

		BeginWaitCursor();

		// Key info
		m_kiKeyInfo.nKeySize = sth.nKeySize;
		m_kiKeyInfo.nRounds = sth.nRounds;
		m_kiKeyInfo.pbKey = 0;

		GeneratePrivateKey(dlgPassword.m_strUserName, dlgPassword.m_strMasterPassword, sth.nKeySize, m_kiKeyInfo);

		// Acquiring new context
		if(::Rc5ValidContext(m_hRc5))
			::Rc5ReleaseContext(m_hRc5);

		if(!::Rc5AcquireContext(m_hRc5, m_kiKeyInfo.nKeySize / 8, m_kiKeyInfo.nRounds))
		{
			MessageBoxEx(*this, IDS_RC5ACQUIRECONTEXTFAILED, IDS_TITLE);
			CleanPrivateData();
			EndWaitCursor();
			return;
		} // if

		if(!::Rc5SetBinaryPrivateKey(m_hRc5, m_kiKeyInfo.pbKey))
		{
			MessageBoxEx(*this, IDS_RC5SETBINARYPRIVATEKEYFAILED, IDS_TITLE);
			CleanPrivateData();
			EndWaitCursor();
			return;
		} // if

		// So now we can delete key buffer in order not
		// to expose it anymore
		FreeBuffer(m_kiKeyInfo.pbKey, m_kiKeyInfo.nKeySize / 8);
		CleanString(dlgPassword.m_strMasterPassword);
		CleanString(dlgPassword.m_strUserName);
		
		// Now reading items
		m_ctrlTree.DeleteAllItems();
		m_mEntries.clear();

		m_lIndex = sth.lIndex;

		// Tree structure
		size_t sBuffer = sizeof(LONG) * sth.lNodes;
		LONG *plBuffer = new LONG[sth.lNodes];
		VTREE vTree;

		fStg.Read((void *)plBuffer, sBuffer);

		for(long l = 0; l < sth.lNodes; ++l)
			vTree.push_back(plBuffer[l]);

		FreeBuffer(plBuffer, sBuffer);

		// Items
		sBuffer = sizeof(ENTRY) * sth.lElements;			
		ENTRY *pBufer = new ENTRY[sth.lElements];
		
		fStg.Read((void *)pBufer, sBuffer);

		for(l = 0; l < sth.lElements; ++l)
			m_mEntries[pBufer[l].lID] = pBufer[l];

		FreeBuffer(pBufer, sBuffer);

		// If the storage we're opening has version 1.5 and above, read
		// required number of ADVANCED structures
		if((sth.lVersion >= MAKELONG(5, 1)) && (sth.lAdvanced > 0))
		{
			sBuffer = sizeof(ADVANCED) * sth.lAdvanced;
			ADVANCED *paBuffer = new ADVANCED[sth.lAdvanced];

			fStg.Read((void *)paBuffer, sBuffer);

			for(l = 0; l < sth.lAdvanced; ++l)
				m_mAdvanced[paBuffer[l].lID] = paBuffer[l];

			FreeBuffer(paBuffer, sBuffer);
		} // if

		// Convert items to our version if required
		if(STORAGEVERSION > sth.lVersion) // Converting from older versions
		{
			ConvertStorage(sth.lVersion);
		} // if

		if(m_bHotKeys)
			RegisterHotKeys();

		// Restoring tree structure
		LoadTree(vTree, 0);

		SwitchMenu(MF_FILE_ALL, TRUE);		
		SwitchMenu(MF_FILE_SAVE, !m_bReadOnly);

		SetTitle();
		SetKeyInfo(m_kiKeyInfo.nKeySize);

		ProcessSortOrder();

		EndWaitCursor();
	} // if
	else
		MessageBoxEx(*this, IDS_WRONGFORMAT, IDS_TITLE);
}

void CExileDlg::LoadStorageXml()
{
	MSXML2::IXMLDOMDocument2Ptr pXMLDoc;

	if(FAILED(pXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30))))
	{
		// TODO: Message
		return;
	} // if

	if(VARIANT_FALSE == pXMLDoc->load(m_strStorageName.LockBuffer()))
	{
		m_strStorageName.UnlockBuffer();
		return;
	} // if

	m_strStorageName.UnlockBuffer();

	// Root element
	MSXML2::IXMLDOMElementPtr pXMLElem = pXMLDoc->documentElement;

	if(0 == pXMLElem)
	{
		// TODO: Message
		return;
	} // if

	if(_bstr_t("password-storage") != pXMLElem->tagName)
	{
		MessageBoxEx(*this, IDS_XMLOPENFAILED, IDS_TITLE);
		return;
	} // if

	MSXML2::IXMLDOMNamedNodeMapPtr pXMLNNM;
	MSXML2::IXMLDOMNodePtr pXMLN;

	pXMLElem->get_attributes(&pXMLNNM);	

	// Setting up key info

	if(0 != (pXMLN = pXMLNNM->getNamedItem("version")))
	{
		
		long lVersion = atol(pXMLN->text);
	} // if
}

void CExileDlg::OnEditAdvanced() 
{
	// See what we have to edit
	if(m_ctrlTree.GetSelectedItem())
	{
		TV_ITEM tvi;
		tvi.mask = TVIF_PARAM | TVIF_HANDLE;
		tvi.hItem = m_ctrlTree.GetSelectedItem();

		if(m_ctrlTree.GetItem(&tvi)) 
		{
			MENTRY::iterator emi = m_mEntries.find(GetItemParam(tvi.lParam));

			if(m_mEntries.end() != emi) 
			{
				if(emi->second.nFlags & EF_ELEMENT)
				{
					EditElementAdvanced(m_ctrlTree.GetSelectedItem());
				} // else
			} // if
		} // if		
	} // if
}

void CExileDlg::EditElementAdvanced(HTREEITEM hItem)
{
	TV_ITEM tvi;
	HTREEITEM hRoot;
	tvi.mask = TVIF_PARAM | TVIF_HANDLE;
	tvi.hItem = hRoot = m_ctrlTree.GetSelectedItem();

	if(m_ctrlTree.GetItem(&tvi)) 
	{
		MENTRY::iterator emi = m_mEntries.find(GetItemParam(tvi.lParam));

		if(m_mEntries.end() != emi) 
		{
			if(!(emi->second.nFlags & EF_ELEMENT))
				return;

			CAdvancedDialog dlgAdv;

			// Loading Advanced settings for this item
			MADVANCED::iterator ami = m_mAdvanced.find(emi->second.lID);
			if(m_mAdvanced.end() != ami)
			{
				dlgAdv.m_bEnable = ami->second.sti.bEnabled;
				dlgAdv.m_nLogin = ami->second.sti.nLoginCtrlID;
				dlgAdv.m_nPassword = ami->second.sti.nPasswordCtrlID;
				dlgAdv.m_strWindowTitle = ami->second.sti.szWindowTitle;
			} // if
			else
			{
				dlgAdv.m_bEnable = FALSE;
				dlgAdv.m_nLogin = 0;
				dlgAdv.m_nPassword = 0;
				dlgAdv.m_strWindowTitle.Empty();

				// Inserting new ADVANCED thing
				ADVANCED adv;
				memset(&adv, 0, sizeof(ADVANCED));
				adv.lID = emi->second.lID;

				m_mAdvanced[emi->second.lID] = adv;
			} // else

			if(IDOK == dlgAdv.DoModal())
			{
				// Creating new STI
				SMARTTYPEINFO sti;

				sti.bEnabled = dlgAdv.m_bEnable;
				sti.nLoginCtrlID = dlgAdv.m_nLogin;
				sti.nPasswordCtrlID = dlgAdv.m_nPassword;
#ifdef _UNICODE
				wcscpy(sti.szWindowTitle, dlgAdv.m_strWindowTitle.LockBuffer());
#else
				strcpy(sti.szWindowTitle, dlgAdv.m_strWindowTitle.LockBuffer());
#endif // _UNICODE

				m_mAdvanced[emi->second.lID].sti = sti;

				SetDirty(TRUE);
			} // if
		} // if
	} // if	
}

void CExileDlg::MaintainFileAssociations()
{
	TCHAR szModule[MAX_PATH];

	if(!GetModuleFileName(0, szModule, MAX_PATH)) // Failure
		return;

	BeginWaitCursor();

	CRegistry reg;
	CString strCmd;

	reg.SetRootKey(HKEY_CLASSES_ROOT);	

	// Add entry in HKEY_CLASSES_ROOT about
	// .pws file type...
	reg.CreateKey(".pws");
	reg.WriteString("", "octalforty.Exile.PasswordStorage");

	reg.CreateKey("octalforty.Exile.PasswordStorage");
	reg.WriteString("", "octalforty Exile Password Storage"); // Document type name

	reg.CreateKey("octalforty.Exile.PasswordStorage\\Shell");
	reg.WriteString("", "Open"); // Default action

	strCmd.Format("\"%s\", 0", szModule);

	reg.CreateKey("octalforty.Exile.PasswordStorage\\DefaultIcon");
	reg.WriteString("", strCmd); // Default icon

	reg.CreateKey("octalforty.Exile.PasswordStorage\\Shell\\Open");
	reg.WriteString("", "&Open"); // Command string

	strCmd.Format("\"%s\" \"%%1\"", szModule);

	reg.CreateKey("octalforty.Exile.PasswordStorage\\Shell\\Open\\Command");
	reg.WriteString("", strCmd); // Command itself

	EndWaitCursor();
}

void CExileDlg::OnCopy()
{
	// What exactly do we have to copy
	CWnd* pWnd = GetFocus();

	if(!pWnd)
		return;

	CString strCopy;

	// 
	// Searching for required item
	//
	HTREEITEM hItem = m_ctrlTree.GetSelectedItem();

	if(!hItem)
		return;

	TV_ITEM tvi;
	tvi.mask = TVIF_HANDLE | TVIF_PARAM;
	tvi.hItem = hItem;

	if(!m_ctrlTree.GetItem(&tvi))
		return;

	MENTRY::iterator emi = m_mEntries.find(tvi.lParam);

	if(m_mEntries.end() == emi)
		return;

	if(*pWnd == *GetDlgItem(IDC_LOGIN))
	{
		DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);
		strCopy = emi->second.pePrivate.szLogin;
		EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);
	} // if
	else if(*pWnd == *GetDlgItem(IDC_PASSWORD))
	{
		DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);
		strCopy = emi->second.pePrivate.szPassword;
		EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);
	} // else if
	else if(*pWnd == *GetDlgItem(IDC_ADDRESS))
	{
		DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);
		strCopy = emi->second.pePrivate.szAddress;
		EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);
	} // else if
	else if(*pWnd == *GetDlgItem(IDC_NOTES))
	{
		DecryptPrivateEntry(emi->second.pePrivate, m_hRc5);
		strCopy = emi->second.pePrivate.szNotes;
		EncryptPrivateEntry(emi->second.pePrivate, m_hRc5);
	} // else if
	else
		return;

	//
	// If we got here we have something to send to Clipboard
	//
	CopyToClipboard(strCopy);

	CleanString(strCopy);
}

void CExileDlg::SaveSettings()
{
	MSXML2::IXMLDOMDocument2Ptr pXMLDoc;
    MSXML2::IXMLDOMNodePtr pXMLNode;
    MSXML2::IXMLDOMProcessingInstructionPtr pXMLPI;
    MSXML2::IXMLDOMCommentPtr pXMLC;

	if(FAILED(pXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30))))
    {
        // TODO: Message
        return;
    } // if

    pXMLPI = pXMLDoc->createProcessingInstruction(_T("xml"), _T("version='1.0'	encoding='UTF-8'"));
    if(0 != pXMLPI)
        pXMLDoc->appendChild(pXMLPI);

    // Adding comments
	pXMLC = pXMLDoc->createComment("Generated by octalforty Exile 1.7");
    if(0 != pXMLC)
        pXMLDoc->appendChild(pXMLC);
    pXMLC = pXMLDoc->createComment("Copyright (C) 2004 octalforty studios. All rights reserved.");
    if(0 != pXMLC)
        pXMLDoc->appendChild(pXMLC);

    // Creating root item
    MSXML2::IXMLDOMElementPtr pXMLE = pXMLDoc->createElement("configuration");
    if(0 != pXMLE)
    {
		pXMLE->appendChild(pXMLDoc->createTextNode(_T("\n\t")));

		//
		// General Settings
		//
		MSXML2::IXMLDOMElementPtr pElement = pXMLDoc->createElement("configurationGeneral");
		if(pElement)
		{
			pElement->setAttribute(_T("showPassword"), _variant_t((short)m_bShowPassword, VT_I2));					
			pElement->setAttribute(_T("maintainFileAssociations"), _variant_t((short)m_bMaintain, VT_I2));
			pElement->setAttribute(_T("enableHotKeys"), _variant_t((short)m_bHotKeys, VT_I2));			
			pElement->setAttribute(_T("minimizeToTray"), _variant_t((short)m_bMinimizeToTray, VT_I2));			

			pXMLE->appendChild(pElement);
			pXMLE->appendChild(pXMLDoc->createTextNode(_T("\n")));
		} // if

		pXMLE->appendChild(pXMLDoc->createTextNode(_T("\t")));

		//
		// Storage Settings
		//
		pElement = pXMLDoc->createElement("configurationStorage");
		if(pElement)
		{
			pElement->setAttribute(_T("createBackup"), _variant_t((short)m_bBackup, VT_I2));
			pElement->setAttribute(_T("autoSave"), _variant_t((short)m_bAutosave, VT_I2));	
			pElement->setAttribute(_T("shellOpenReadOnly"), _variant_t((short)m_bShellOpenReadonly, VT_I2));			
			pElement->setAttribute(_T("reloadLastStorage"), _variant_t((short)m_bReloadLastStorage, VT_I2));			
			pElement->setAttribute(_T("lastStorage"), _T(m_strLastStorage.LockBuffer()));
			pElement->setAttribute(_T("reloadReadOnly"), _variant_t((short)m_bReloadReadonly, VT_I2));

			pXMLE->appendChild(pElement);
			pXMLE->appendChild(pXMLDoc->createTextNode(_T("\n")));
		} // if

		pXMLE->appendChild(pXMLDoc->createTextNode(_T("\t")));

		//
		// SmartType Settings
		//
		pElement = pXMLDoc->createElement("configurationSmartType");
		if(pElement)
		{
			pElement->setAttribute(_T("smartType"), _variant_t((short)m_bSmartType, VT_I2));			
			pElement->setAttribute(_T("smartTypeModifier"), _variant_t((long)m_wModifiers, VT_I4));
			pElement->setAttribute(_T("smartTypeVKey"), _variant_t((long)m_wKeyCode, VT_I4));

			pXMLE->appendChild(pElement);
			pXMLE->appendChild(pXMLDoc->createTextNode(_T("\n")));
		} // if

		pXMLE->appendChild(pXMLDoc->createTextNode(_T("\t")));

		// Sorting Settings
		pElement = pXMLDoc->createElement("configurationSorting");
		if(pElement)
		{
			pElement->setAttribute(_T("autoSort"), _variant_t((short)m_bAutosort, VT_I2));			
			pElement->setAttribute(_T("autoSortOrder"), _variant_t((long)m_nSortOrder, VT_I4));

			pXMLE->appendChild(pElement);
			pXMLE->appendChild(pXMLDoc->createTextNode(_T("\n")));
		} // if

		pXMLE->appendChild(pXMLDoc->createTextNode(_T("\t")));

		//
		// Clipboard Settings
		//
		pElement = pXMLDoc->createElement("configurationClipboard");
		if(pElement)
		{
			pElement->setAttribute(_T("eraseClipboard"), _variant_t((short)m_bClipboardErasing, VT_I2));			
			pElement->setAttribute(_T("eraseClipboardTimeout"), _variant_t((long)m_nErasingTimeout, VT_I4));

			pXMLE->appendChild(pElement);
			pXMLE->appendChild(pXMLDoc->createTextNode(_T("\n")));
		} // if

		pXMLE->appendChild(pXMLDoc->createTextNode(_T("\t")));

		//
		// Password Generator
		//
		pElement = pXMLDoc->createElement("configurationPasswordGenerator");
		if(pElement)
		{
			pElement->setAttribute(_T("decimalDigits"), _variant_t((short)m_bDecimalDigits, VT_I2));
			pElement->setAttribute(_T("lowercaseCharacters"), _variant_t((short)m_bLowercase, VT_I2));
			pElement->setAttribute(_T("punctuationMarks"), _variant_t((short)m_bPunctuation, VT_I2));
			pElement->setAttribute(_T("specialCharacters"), _variant_t((short)m_bSpecial, VT_I2));
			pElement->setAttribute(_T("uppercaseCharacters"), _variant_t((short)m_bUppercase, VT_I2));
			pElement->setAttribute(_T("passwordLength"), _variant_t((long)m_nPasswordLength, VT_I4));

			pXMLE->appendChild(pElement);
			pXMLE->appendChild(pXMLDoc->createTextNode(_T("\n")));
		} // if

		pXMLE->appendChild(pXMLDoc->createTextNode(_T("\t")));

		//
		// Hash Generator
		//
		pElement = pXMLDoc->createElement("configurationHashGenerator");
		if(pElement)
		{
			pElement->setAttribute(_T("hashOptions"), _variant_t((long)m_nHashOptions, VT_I4));

			pXMLE->appendChild(pElement);
			pXMLE->appendChild(pXMLDoc->createTextNode(_T("\n")));
		} // if

		pXMLE->appendChild(pXMLDoc->createTextNode(_T("\t")));

		//
		// Export To Xml
		//
		pElement = pXMLDoc->createElement("configurationExportToXml");
		if(pElement)
		{
			pElement->setAttribute(_T("exportFlags"), _variant_t((long)m_nExportFlags, VT_I4));
			pElement->setAttribute(_T("exportFileName"), _variant_t(m_strExportFileName.LockBuffer()));

			pXMLE->appendChild(pElement);
			pXMLE->appendChild(pXMLDoc->createTextNode(_T("\n")));
		} // if	

		pXMLDoc->appendChild(pXMLE);
    } // if

    if(FAILED(pXMLDoc->save(_variant_t(CombinePathName(GetShellFolder(CSIDL_PERSONAL), _T("exile.xml"))))))
    {
		// TODO : Message
    } // if
}

void CExileDlg::CopyToClipboard(CString &rString)
{
	//
	// Opening clipboard
	//
	if(!::OpenClipboard(GetSafeHwnd()))
		return;

	::EmptyClipboard();

	//
	// Copying to shared memory...
	//
	HGLOBAL hData;
	LPTSTR lpszData;

#ifdef _UNICODE
	hData = ::GlobalAlloc(GMEM_MOVEABLE, (rString.GetLength() + 1) * sizeof(TCHAR));

	lpszData = (LPTSTR)::GlobalLock(hData);
	wcscpy(lpszData, rString.LockBuffer());
	::GlobalUnlock(hData);
#else
	hData = ::GlobalAlloc(GMEM_MOVEABLE, (rString.GetLength() + 1) * sizeof(TCHAR));

	lpszData = (LPTSTR)::GlobalLock(hData);
	strcpy(lpszData, rString.LockBuffer());
	::GlobalUnlock(hData);
#endif // _UNICODE

	::SetClipboardData(CF_TEXT, hData);

	::CloseClipboard();

	//
	// Auto clean
	//
	AutoCleanClipboard();
}

void CExileDlg::LoadSettings()
{
	MSXML2::IXMLDOMDocument2Ptr pXMLDoc;
    MSXML2::IXMLDOMNodePtr pNode;
	MSXML2::IXMLDOMNodeListPtr pNodes;

    MSXML2::IXMLDOMProcessingInstructionPtr pXMLPI;
    MSXML2::IXMLDOMCommentPtr pXMLC;

	if(FAILED(pXMLDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30))))
    {
        // TODO: Message
        return;
    } // if
    
	if(VARIANT_FALSE == pXMLDoc->load(_variant_t(CombinePathName(GetShellFolder(CSIDL_PERSONAL), _T("exile.xml")))))
	{
		// TODO: Message
		return;
	} // if

	if(0 == (pNodes = pXMLDoc->documentElement->childNodes))
	{
		// TODO: Message
		return;
	} // if

	//
	// Loading General Settings
	//
	if(FAILED(pNodes->get_item(0, &pNode)))
	{
		// TODO: Message
		return;
	} // if

	if(_bstr_t(_T("configurationGeneral")) != pNode->nodeName)
	{
		// TODO : Message
		return;
	} // if

	m_bShowPassword = XmlReadBool(pNode, _T("showPassword"));
	m_bMaintain = XmlReadBool(pNode, _T("maintainFileAssociations"));
	m_bHotKeys = XmlReadBool(pNode, _T("enableHotKeys"));
	m_bMinimizeToTray = XmlReadBool(pNode, _T("minimizeToTray"));

	//
	// Storage Settings
	//
	if(FAILED(pNodes->get_item(1, &pNode)))
	{
		// TODO: Message
		return;
	} // if

	if(_bstr_t(_T("configurationStorage")) != pNode->nodeName)
	{
		// TODO : Message
		return;
	} // if

	m_bBackup = XmlReadBool(pNode, _T("createBackup"));
	m_bAutosave = XmlReadBool(pNode, _T("autoSave"));
	m_bShellOpenReadonly = XmlReadBool(pNode, _T("shellOpenReadOnly"));
	m_bReloadLastStorage = XmlReadBool(pNode, _T("reloadLastStorage"));
	m_bReloadReadonly = XmlReadBool(pNode, _T("reloadReadOnly"));
	m_strStorageName = m_strLastStorage = XmlReadString(pNode, _T("lastStorage"));

	//
	// SmartType Settings
	//
	if(FAILED(pNodes->get_item(2, &pNode)))
	{
		// TODO: Message
		return;
	} // if

	if(_bstr_t(_T("configurationSmartType")) != pNode->nodeName)
	{
		// TODO : Message
		return;
	} // if

	m_bSmartType = XmlReadBool(pNode, _T("smartType"));
	m_wModifiers = (WORD)XmlReadLong(pNode, _T("smartTypeModifier"));
	m_wKeyCode = (WORD)XmlReadLong(pNode, _T("smartTypeVKey"));

	//
	// Sorting Settings
	//
	if(FAILED(pNodes->get_item(3, &pNode)))
	{
		// TODO: Message
		return;
	} // if

	if(_bstr_t(_T("configurationSorting")) != pNode->nodeName)
	{
		// TODO : Message
		return;
	} // if

	m_bAutosort = XmlReadBool(pNode, _T("autoSort"));
	m_nSortOrder = (int)XmlReadLong(pNode, _T("autoSortOrder"));

	//
	// Clipboard Settings
	//
	if(FAILED(pNodes->get_item(4, &pNode)))
	{
		// TODO: Message
		return;
	} // if

	if(_bstr_t(_T("configurationClipboard")) != pNode->nodeName)
	{
		// TODO : Message
		return;
	} // if

	m_bClipboardErasing = XmlReadBool(pNode, _T("eraseClipboard"));
	m_nErasingTimeout = (int)XmlReadLong(pNode, _T("eraseClipboardTimeout"));

	//
	// Password Generator Settings
	//
	if(FAILED(pNodes->get_item(5, &pNode)))
	{
		// TODO: Message
		return;
	} // if

	if(_bstr_t(_T("configurationPasswordGenerator")) != pNode->nodeName)
	{
		// TODO : Message
		return;
	} // if

	m_bDecimalDigits = XmlReadBool(pNode, _T("decimalDigits"));
	m_bLowercase = XmlReadBool(pNode, _T("lowercaseCharacters"));
	m_bPunctuation = XmlReadBool(pNode, _T("punctuationMarks"));
	m_bSpecial = XmlReadBool(pNode, _T("specialCharacters"));
	m_bUppercase = XmlReadBool(pNode, _T("uppercaseCharacters"));
	m_nPasswordLength = (int)XmlReadLong(pNode, _T("passwordLength"));

	//
	// Hash Generator Settings
	//
	if(FAILED(pNodes->get_item(6, &pNode)))
	{
		// TODO: Message
		return;
	} // if

	if(_bstr_t(_T("configurationHashGenerator")) != pNode->nodeName)
	{
		// TODO : Message
		return;
	} // if

	m_nHashOptions = (int)XmlReadLong(pNode, _T("hashOptions"));

	//
	// Export To Xml Settings
	//
	if(FAILED(pNodes->get_item(7, &pNode)))
	{
		// TODO: Message
		return;
	} // if

	if(_bstr_t(_T("configurationExportToXml")) != pNode->nodeName)
	{
		// TODO : Message
		return;
	} // if

	m_nExportFlags = (int)XmlReadLong(pNode, _T("exportFlags"));
	m_strExportFileName = XmlReadString(pNode, _T("exportFileName"));
}

BOOL CExileDlg::XmlReadBool(MSXML2::IXMLDOMNodePtr pNode, LPCTSTR pszAttribute, BOOL bDefault)
{
	MSXML2::IXMLDOMNamedNodeMapPtr pNodes;
	MSXML2::IXMLDOMNodePtr pAttribute;

	if(0 == (pNodes = pNode->attributes))
		return bDefault;

	// 
	// Reading attribute required
	//
	_variant_t vt;

	if(0 == (pAttribute = pNodes->getNamedItem(_bstr_t(pszAttribute))))
		return bDefault;

	if(FAILED(pAttribute->get_nodeValue(&vt)))
		return bDefault;

	vt.ChangeType(VT_I2);
	return vt.boolVal;
}

CString CExileDlg::XmlReadString(MSXML2::IXMLDOMNodePtr pNode, LPCTSTR pszAttribute, CString strDefault)
{
	MSXML2::IXMLDOMNamedNodeMapPtr pNodes;
	MSXML2::IXMLDOMNodePtr pAttribute;

	if(0 == (pNodes = pNode->attributes))
		return strDefault;

	// 
	// Reading attribute required
	//
	_variant_t vt;

	if(0 == (pAttribute = pNodes->getNamedItem(_bstr_t(pszAttribute))))
		return strDefault;

	if(FAILED(pAttribute->get_nodeValue(&vt)))
		return strDefault;
	
	return CString(vt.bstrVal);
}

LONG CExileDlg::XmlReadLong(MSXML2::IXMLDOMNodePtr pNode, LPCTSTR pszAttribute, LONG lDefault)
{
	MSXML2::IXMLDOMNamedNodeMapPtr pNodes;
	MSXML2::IXMLDOMNodePtr pAttribute;

	if(0 == (pNodes = pNode->attributes))
		return lDefault;

	// 
	// Reading attribute required
	//
	_variant_t vt;

	if(0 == (pAttribute = pNodes->getNamedItem(_bstr_t(pszAttribute))))
		return lDefault;

	if(FAILED(pAttribute->get_nodeValue(&vt)))
		return lDefault;

	vt.ChangeType(VT_I4);
	return LONG(vt.lVal);
}

void CExileDlg::AutoCleanClipboard()
{
	if((!m_bClipboardErasing) || (0 == m_nErasingTimeout ))
		return;

	//
	// Setting up timer
	//
	::SetTimer(*this, g_uTimerID, m_nErasingTimeout * 1000, 0);
}

void CExileDlg::PerformAutoCleanClipboard()
{
	//
	// Removing timer and erasing clipboard
	//
	::KillTimer(*this, g_uTimerID);

	if(!::OpenClipboard(GetSafeHwnd()))
		return;

	::EmptyClipboard();
	::CloseClipboard();
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Russian Federation Russian Federation
I'll think about it later on...

Comments and Discussions