// DenAgentDlg.cpp : implementation file
//

#include "stdafx.h"
#include "DenAgent.h"
#include "DenAgentDlg.h"
#include "DownloaderDlg.h"
#include "OptionsDlg.h"
#include "ExportDlg.h"
#include "TrayWnd.h"
#include "AutoUpdate.h"

#include "..\Inject\InjectApi.h"

#include "AddRemoveDlg.h"
#include ".\denagentdlg.h"

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

/////////////////////////////////////////////////////////////////////////////
// CDenAgentDlg dialog

CDenAgentDlg::CDenAgentDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CDenAgentDlg::IDD, pParent),
   m_pCurrentDrag ( NULL ), m_bDoingUpdate( false ), m_bDoUpdate( false )
{
	//{{AFX_DATA_INIT(CDenAgentDlg)
	//}}AFX_DATA_INIT

	// Load the icon, unload will be done automagically
	m_hIcon = AfxGetApp()->LoadIcon(IDR_TRAYICON);
}

void CDenAgentDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDenAgentDlg)
	DDX_Control(pDX, IDC_PLUGINS, m_wndPlugins);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CDenAgentDlg, CDialog)
	//{{AFX_MSG_MAP(CDenAgentDlg)
	ON_BN_CLICKED(IDC_REFRESH, OnRefresh)
	ON_BN_CLICKED(IDC_ADDREMOVE, OnAddremove)
	ON_BN_CLICKED(IDC_UPDATE, OnUpdate)
	ON_BN_CLICKED(IDC_OPTIONS, OnOptions)
	ON_NOTIFY(LVN_DELETEITEM, IDC_PLUGINS, OnDeleteitemPlugins)
	ON_NOTIFY(NM_CLICK, IDC_PLUGINS, OnClickPlugins)
	ON_NOTIFY(LVN_BEGINDRAG, IDC_PLUGINS, OnBegindragPlugins)
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_DELETE, OnBnClickedDelete)
	ON_BN_CLICKED(IDC_EXPORT, OnBnClickedExport)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDenAgentDlg message handlers

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

	SetForegroundWindow();
	BringWindowToTop();

	// Create the decal object
	HRESULT hRes = ::CoCreateInstance ( __uuidof ( Decal ), NULL, CLSCTX_INPROC_SERVER, __uuidof ( IDecal ),
		reinterpret_cast< LPVOID * > ( &m_pDecal ) );

	// Set up the list control and image list
	m_groups.Create ( IDB_GROUPS, 16, 0, RGB(255,0,255));
	m_wndPlugins.SetImageList ( &m_groups, LVSIL_SMALL );

	// Prepare the column list
	CRect rcListClient;
	m_wndPlugins.GetClientRect ( rcListClient );

	CClientDC dcList ( &m_wndPlugins );
	dcList.SelectObject ( m_wndPlugins.GetFont () );

	int nVersionWidth = dcList.GetTextExtent ( CString ( _T( "100.00.00.00001" ) ) ).cx;

	m_wndPlugins.InsertColumn ( 0, _T( "Component" ), LVCFMT_LEFT, rcListClient.Width () - nVersionWidth - 16, 0 );
	m_wndPlugins.InsertColumn ( 1, _T( "Version" ), LVCFMT_RIGHT, nVersionWidth, 1 );

	m_wndPlugins.SetExtendedStyle ( LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP );

	if ( FAILED ( hRes ) )
	{
		AfxMessageBox ( _T( "Failed to create Decal Object." ) );
		EndDialog ( IDCANCEL );
		return FALSE;
	}

	loadPluginList ();

	// Set the icon into the window for runtime
	SetIcon(m_hIcon, TRUE);	// Set big icon
	SetIcon(m_hIcon, FALSE);	// Set small icon

	TCHAR szModule[ MAX_PATH ];
	::GetModuleFileName ( NULL, szModule, MAX_PATH );

	CString strVersion;
	CDenAgentApp::getVersionString ( szModule, strVersion );
	CDenAgentApp::getVersionInfo ( szModule, iReleaseMajor, iReleaseMinor, iBuildMajor, iBuildMinor );

	SetWindowText( CString("Decal Agent ") + strVersion );

	updateFileInfo();

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CDenAgentDlg::OnRefresh() 
{
	loadPluginList ();
}

void CDenAgentDlg::OnAddremove() 
{
	CFile cf;
	CFileStatus cfs;

	RegKey key;
	CString strDecalPlugins("decalplugins.xml");

	if( key.Create( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Decal\\Agent" )) == ERROR_SUCCESS )
	{
		TCHAR szDecalDirectory[ MAX_PATH + 1];
		DWORD dwSize = MAX_PATH;

		if(key.QueryStringValue( _T( "AgentPath" ), szDecalDirectory, &dwSize )==ERROR_SUCCESS)
		{
			strDecalPlugins = CString(szDecalDirectory) + "\\decalplugins.xml";
		}
	}

	if(!cf.GetStatus(strDecalPlugins, cfs))
	{
		if(MessageBox("Your list of Decal Components is missing.\n\nWould like to Download them?", NULL, MB_YESNO)==IDYES)
			OnUpdate();
	}
	else
	{

		CTime modification_time = cfs.m_mtime;
		CTime now = CTime::GetCurrentTime ();

		if((modification_time.GetDay() < now.GetDay()) && (modification_time.GetMonth() <= now.GetMonth()) && (modification_time.GetYear() <= now.GetYear()))
			if(MessageBox("Your list of Decal Components are outdated.\n\nWould you like to Update?", NULL, MB_YESNO)==IDYES)
			{
				m_bDoingUpdate = true;
				OnUpdate();
			}
	}

	cAddRemoveDlg dlg( this );
	dlg.m_pDecal = m_pDecal;
	dlg.DoModal ();

	loadPluginList ();
}

int CDenAgentDlg::getDragInsertBefore ( CPoint &ptClient )
{
	_ASSERTE ( m_pCurrentDrag != NULL );

	CRect rc;
	m_wndPlugins.GetWindowRect ( rc );
	ScreenToClient ( rc );

	ptClient.x = ptClient.x - rc.left;
	ptClient.y = ptClient.y - rc.top;

	int nItemHit = m_wndPlugins.HitTest ( ptClient );

	if ( nItemHit != -1 )
	{
		cPlugin *pPlugin = reinterpret_cast< cPlugin * > ( m_wndPlugins.GetItemData ( nItemHit ) );
		if ( pPlugin != NULL && pPlugin->m_dragimage == m_pCurrentDrag->m_dragimage )
			return nItemHit;
	}

	return -1;
}

/////////////////////////////////////////////////////////////////////////////
// Tries to update the local copy of decal
/////////////////////////////////////////////////////////////////////////////

void CDenAgentDlg::updateDecal(_variant_t vCodeBase) {
	USES_CONVERSION;

	if (MessageBox("A New Version of Decal exists.\n\nWould you like to Update?",NULL, MB_ICONQUESTION | MB_YESNO) == IDYES) {
		ShellExecute(m_hWnd,"open",OLE2A(vCodeBase.bstrVal),0,0,0);
		EndDialog(0);
		GetParent()->DestroyWindow();
		PostQuitMessage(0);
	}
}

struct cPluginGroup
{
	LPCTSTR m_groupName,
		m_groupKey;
	int m_iconIndex;
};

void CDenAgentDlg::loadPluginList ()
{
	m_wndPlugins.SetRedraw ( FALSE );

	int nTop = m_wndPlugins.GetTopIndex ();

	// Save the original selection
	GUID idSelected = GUID_NULL;
	{
		POSITION pos = m_wndPlugins.GetFirstSelectedItemPosition ();
		if ( pos != NULL )
		{
			int nSelected = m_wndPlugins.GetNextSelectedItem ( pos );
			cPlugin *pPlugin = reinterpret_cast< cPlugin * > ( m_wndPlugins.GetItemData ( nSelected ) );
			if ( pPlugin != NULL )
			idSelected = pPlugin->m_id;
		}
	}

	// Erase the contents of the list and collection
	m_wndPlugins.DeleteAllItems ();
	CDenAgentApp::importV1Plugins ();

	USES_CONVERSION;

	static cPluginGroup _groups[] = {
		{ _T( "Plugins" ), _T( "Plugins" ), 4 },
		{ _T( "Network Filters" ), _T( "NetworkFilters" ), 1 },
		{ _T( "File Filters" ), _T( "FileFilters" ), 1 },
		{ _T( "Services" ), _T( "Services" ), 0 },
		{ _T( "Surrogates" ), _T( "Surrogates" ), 3 },
		{ _T( "Input Actions" ), _T( "InputActions" ), 2 } },
		*_end_groups = _groups + sizeof ( _groups ) / sizeof ( cPluginGroup );

	int nCount = 0;
	for ( cPluginGroup *i = _groups; i != _end_groups; ++ i )
	{
		int nGroup = m_wndPlugins.InsertItem ( LVIF_IMAGE | LVIF_TEXT, nCount ++, i->m_groupName, 0, 
			0, i->m_iconIndex, 0 );

		CComPtr<IDecalEnum> pEnum;
		HRESULT hRes = m_pDecal->get_Configuration ( _bstr_t ( i->m_groupKey ), GUID_NULL, &pEnum );
		_ASSERTE( SUCCEEDED ( hRes ) );

		while ( pEnum->Next () == S_OK )
		{
			CLSID clsid;
			hRes = pEnum->get_ComClass ( &clsid );
			_ASSERTE ( SUCCEEDED ( hRes ) );

			VARIANT_BOOL bEnabled;
			hRes = pEnum->get_Enabled ( &bEnabled );
			_ASSERTE ( SUCCEEDED ( hRes ) );

			int nState = ( clsid == idSelected ) ? LVIS_SELECTED | LVIS_FOCUSED : 0;

			LVITEM lvi = { LVIF_STATE | LVIF_IMAGE | LVIF_INDENT | LVIF_PARAM | LVIF_TEXT, nCount ++, 0,
			nState, nState, NULL, -1, ( bEnabled ) ? 6 : 5, reinterpret_cast< LPARAM > ( new cPlugin ( clsid, i->m_groupKey, !!bEnabled, i->m_iconIndex ) ), 1 };

			CComBSTR strName;
			if ( SUCCEEDED (  pEnum->get_FriendlyName( &strName ) ) )
			lvi.pszText = OLE2T ( strName );
			else
			{
			LPOLESTR szProgID;
			if ( FAILED ( ::ProgIDFromCLSID ( clsid, &szProgID ) ) )
			{
				hRes = ::StringFromCLSID ( clsid, &szProgID );
				_ASSERTE ( SUCCEEDED ( hRes ) );
			}

			// This *must* succeed
			lvi.pszText = OLE2T ( szProgID );
			::CoTaskMemFree ( szProgID );
			}

			lvi.cchTextMax = ::_tcslen ( lvi.pszText );
			int nItem = m_wndPlugins.InsertItem ( &lvi );

			// Load the version info
			CString strDLL;
			if ( !CDenAgentApp::getCOMObjectDLL ( clsid, strDLL ) )
			{
			m_wndPlugins.SetItemText ( nItem, 1, _T( "<No DLL>" ) );
			continue;
			}

			CString strDLLVersion;
			if ( !CDenAgentApp::getVersionString ( strDLL, strDLLVersion ) )
			m_wndPlugins.SetItemText ( nItem, 1, _T( "<No Version>" ) );
			else
			m_wndPlugins.SetItemText ( nItem, 1, strDLLVersion );
		}
	}

	m_wndPlugins.SetRedraw ( TRUE );
	m_wndPlugins.Invalidate ();

	// Scroll back to the top index of before
	RECT rc;
	m_wndPlugins.GetItemRect ( 0, &rc, LVIR_BOUNDS );
	m_wndPlugins.Scroll ( CSize ( 0, ( rc.bottom - rc.top ) * nTop ) );
}

void CDenAgentDlg::OnUpdate() 
{
	USES_CONVERSION;
	// Release Decal object so it can be updated.
	m_pDecal.Release();
	m_pDecal = NULL;
	CoFreeUnusedLibraries();
	RegKey key;	

	cDownloaderDlg dlg;
	bool bUpdates = false;

	if (key.Create( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Decal\\Agent" )) != ERROR_SUCCESS)
		return;

	TCHAR szURLDirectory[1024];
	TCHAR szDecalDirectory[MAX_PATH + 1];
	DWORD dwSize = 1024;

	if (key.QueryStringValue( _T( "DecalDirectory" ), szURLDirectory, &dwSize ) != ERROR_SUCCESS)
	{
		::_tcscpy(szURLDirectory, "http://decal.acdev.org");
		key.SetStringValue("DecalDirectory", "http://decal.acdev.org");
	}

	dwSize = MAX_PATH;

	if (key.QueryStringValue( _T( "AgentPath" ), szDecalDirectory, &dwSize ) == ERROR_SUCCESS) {
		// Gouru: szDecalDirectory may have trailing slash in registry, all following
		//	code assumes it does not, and adds another one. Since this could potentially
		//	cause path problems, the extra slash (if extant) is removed here
		if	(	szDecalDirectory[strlen(szDecalDirectory)-1] == '/'
			||	szDecalDirectory[strlen(szDecalDirectory)-1] == '\\'
			){
			szDecalDirectory[strlen(szDecalDirectory)-1] = 0 ;
		}

		AutoUpdate aUpdate(szDecalDirectory);

		aUpdate.initialiseFromXML(std::string(szURLDirectory));

		if (!aUpdate.performUpdate())
			MessageBox("Decal component update failed!");
	} else {
		return;
	}	

	MSXML::IXMLDOMDocumentPtr pDPDoc;

	pDPDoc.CreateInstance( __uuidof( MSXML::DOMDocument ) );
	pDPDoc->async = false;

	VARIANT_BOOL bSuccess = pDPDoc->load( "decalplugins.xml" );

	if(bSuccess)
	{
		MSXML::IXMLDOMElementPtr pNode = pDPDoc->selectSingleNode( _T("decal") );
		_variant_t vVersion = pNode->getAttribute( _T( "version" ) ), vCodeBase = pNode->getAttribute( _T( "codebase" ) );

		char *sVersion = OLE2A(vVersion.bstrVal);

		int iRemoteReleaseMajor, iRemoteReleaseMinor;
		int iRemoteBuildMajor, iRemoteBuildMinor;

		sscanf(sVersion, "%d.%d.%d.%d", &iRemoteReleaseMajor, &iRemoteReleaseMinor, &iRemoteBuildMajor, &iRemoteBuildMinor);

		if (iReleaseMajor == iRemoteReleaseMajor)
		{
			if (iReleaseMinor == iRemoteReleaseMinor)
			{
				if (iBuildMajor == iRemoteBuildMajor)
				{
					if (iBuildMinor < iRemoteBuildMinor)
						updateDecal(vCodeBase);
				}
				else if (iBuildMajor < iRemoteBuildMajor)
					updateDecal(vCodeBase);
			}
			else if (iReleaseMinor < iRemoteReleaseMinor)
				updateDecal(vCodeBase);
		}
		else if (iReleaseMajor < iRemoteReleaseMajor)
			updateDecal(vCodeBase);


		MSXML::IXMLDOMNodeListPtr pPlugins = pDPDoc->selectNodes( _T( "/decal/plugin" ) );
		for( MSXML::IXMLDOMElementPtr pPlugin = pPlugins->nextNode(); pPlugin.GetInterfacePtr() != NULL; pPlugin = pPlugins->nextNode() )
		{
			_variant_t vClsid = pPlugin->getAttribute( _T( "clsid" ) ),
			vCodebase = pPlugin->getAttribute( _T( "codebase" ) ),
			vVersion = pPlugin->getAttribute( _T( "version" ) ),
			vName = pPlugin->getAttribute( _T( "name" ) );

			DWORD dwMajor;
			DWORD dwMinor;

			convertVersion( OLE2T( vVersion.bstrVal ), dwMajor, dwMinor );

			RegKey keyPlugin;

			if( keyPlugin.Open( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Decal\\Plugins\\" ), KEY_READ ) == ERROR_SUCCESS )
			{
				keyPlugin.Close();

				if( keyPlugin.Open( HKEY_CLASSES_ROOT, CString(_T("\\CLSID\\")) + OLE2T(vClsid.bstrVal) + _T("\\InprocServer32"), KEY_READ ) != ERROR_SUCCESS ) continue;

				DWORD dwSize = MAX_PATH;
				TCHAR szDllName[MAX_PATH];

				if(keyPlugin.QueryStringValue("", szDllName, &dwSize) != ERROR_SUCCESS) continue;
				
				keyPlugin.Close();

				DWORD dwHandle;
				DWORD dwVerInfoSize = GetFileVersionInfoSize(szDllName,&dwHandle);
				if(!dwVerInfoSize) continue;

				LPBYTE pVersionData = NULL;

				pVersionData = new BYTE[dwVerInfoSize];

				if(!GetFileVersionInfo(szDllName, dwHandle, dwVerInfoSize, pVersionData))
				{
					delete [] pVersionData;
					continue;
				}

				VS_FIXEDFILEINFO* pFixedFileInfo;

				UINT uFixedInfoSize;
				if(!VerQueryValue(pVersionData, "\\", (void**) &pFixedFileInfo, &uFixedInfoSize))
				{
					delete [] pVersionData;
					continue;
				}


				if (HIWORD(pFixedFileInfo->dwFileVersionMS) == HIWORD(dwMajor))
				{
					if (LOWORD(pFixedFileInfo->dwFileVersionMS) == LOWORD(dwMajor))
					{
						if (HIWORD(pFixedFileInfo->dwFileVersionLS) == HIWORD(dwMinor))
						{
							if (LOWORD(pFixedFileInfo->dwFileVersionLS) < LOWORD(dwMinor))
								bUpdates = true;
						}
						else if (HIWORD(pFixedFileInfo->dwFileVersionLS) < HIWORD(dwMinor))
							bUpdates = true;
					}
					else if (LOWORD(pFixedFileInfo->dwFileVersionMS) < LOWORD(dwMajor))
						bUpdates = true;
				}
				else if (HIWORD(pFixedFileInfo->dwFileVersionMS) < HIWORD(dwMajor))
					bUpdates = true;

				delete [] pVersionData;
			}
		}

		if((bUpdates)  && (!m_bDoingUpdate))
		{
			if (MessageBox("Decal has detected that one or more of your plugins are out of date.\n\nWould you like to view the plugin list?",NULL, MB_ICONQUESTION | MB_YESNO) == IDYES)
			{
				HRESULT hRes = ::CoCreateInstance ( __uuidof ( Decal ), NULL, CLSCTX_INPROC_SERVER, __uuidof ( IDecal ),
					reinterpret_cast< LPVOID * > ( &m_pDecal ) );

				cAddRemoveDlg ardlg( this );
				ardlg.m_pDecal = m_pDecal;
				ardlg.DoModal();
				loadPluginList();
			}
		}
	}

	m_bDoingUpdate = false;

	updateFileInfo ();

	HRESULT hRes = ::CoCreateInstance ( __uuidof ( Decal ), NULL, CLSCTX_INPROC_SERVER, __uuidof ( IDecal ),
		reinterpret_cast< LPVOID * > ( &m_pDecal ) );
}

void CDenAgentDlg::OnOptions() 
{
	cOptionsDlg dlg;
	dlg.DoModal();
}

void CDenAgentDlg::convertVersion( LPTSTR szVersion, DWORD &dwVersionMajor, DWORD &dwVersionMinor )
{
	int wVersionParts[ 4 ],
		*i_ver = wVersionParts;

	for( TCHAR *szVersionPart = ::_tcstok( szVersion, _T( "." ) ); szVersionPart != NULL; szVersionPart = ::_tcstok( NULL, _T( "." ) ), ++ i_ver )
		::_stscanf( szVersionPart, _T( "%i" ), i_ver );

	dwVersionMajor = MAKELONG( wVersionParts[ 1 ], wVersionParts[ 0 ] );
	dwVersionMinor = MAKELONG( wVersionParts[ 3 ], wVersionParts[ 2 ] );
}

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

void CDenAgentDlg::updateFileInfo(void)
{
	struct cFiles
	{
		LPCTSTR szFilename;
		LPCTSTR szRootElement;
		LPCTSTR szVElement;
		UINT nDlgID;
	};

	static cFiles files[] = {
		{ _T( "messages.xml" ), _T("schema"), _T("revision"), IDC_MESSAGES_TEXT },
		{ _T( "memlocs.xml" ), _T(""), _T("locations"), IDC_MEMLOCS_TEXT },
		{ _T( "decalplugins.xml" ), _T(""), _T(""), IDC_DECALPLUGINS_TEXT } },
		*end_files = files + sizeof ( files ) / sizeof ( cFiles );

	for ( cFiles *i = files; i != end_files; ++ i )
	{
		CString strFileInfo;
		GetFileInfoBase ( i->szFilename, i->szRootElement, i->szVElement, strFileInfo );
		SetDlgItemText ( i->nDlgID, strFileInfo );
	}
}


/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

void CDenAgentDlg::GetFileInfoBase(LPCTSTR pszFilename, LPCTSTR pszRootElement, LPCTSTR pszVElement, CString &szFileInfo)
{
	USES_CONVERSION;

	RegKey key;
	TCHAR   szVal[MAX_PATH+1];
	DWORD   dwSize = MAX_PATH;
	static BOOL bAlreadyBuggedUser = false;

	szFileInfo = _T("file not found");

	// Open the registry key
	if(key.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Decal\\Agent")) == ERROR_SUCCESS)
	{
		// Determine the agent path
		if (key.QueryStringValue(_T("AgentPath"), szVal, &dwSize) == ERROR_SUCCESS)
		{
			CString szFilename, szAgentPath(szVal);

			// Create the filename
			szFilename.Format(_T("%s%s%s"),
				szAgentPath,
				(szAgentPath.Right(1) != _T("\\")) ?  _T("\\") : _T(""),
				pszFilename);

			// Look for the data file
			CFileStatus FileStatus;
			if (CFile::GetStatus((LPCTSTR)szFilename, FileStatus))
			{
				if (strlen(pszVElement)) {
					MSXML::IXMLDOMDocumentPtr m_pDoc;
					MSXML::IXMLDOMElementPtr pVersionElement;

					m_pDoc.CreateInstance( __uuidof( MSXML::DOMDocument ) );
					m_pDoc->async = false;

					BOOL bSuccess = m_pDoc->load( _bstr_t(szFilename) );
					if( !bSuccess )
					{
						std::string szXML;
						CDenAgentApp::DecryptXML( static_cast< LPCSTR >( szFilename ), szXML );

						if( szXML != "" )
							bSuccess = m_pDoc->loadXML( _bstr_t( szXML.c_str() ) );

						szXML = " ";
						for( int i = 0; i < 2500; ++i )
							szXML += "DIRL";
					}

					if( !bSuccess )
						return;

					if (strlen(pszRootElement)) {
						MSXML::IXMLDOMElementPtr pRootElement = m_pDoc->selectSingleNode(_T(pszRootElement));
						pVersionElement = pRootElement->selectSingleNode(_T(pszVElement));
					} else {
						pVersionElement = m_pDoc->selectSingleNode(_T(pszVElement));
					}

					if (pVersionElement) {
						_variant_t vVersion = pVersionElement->getAttribute(_T("version"));

						szFileInfo.Format(_T("%d bytes, Version %s"), (DWORD) FileStatus.m_size, OLE2T(vVersion.bstrVal));
					} else {
						CString szDateTime = FileStatus.m_mtime.Format(_T("%#m/%#d/%Y %#I:%M %p"));				
						szFileInfo.Format(_T("%d bytes, %s"), (DWORD) FileStatus.m_size, szDateTime);	
					}
				} else {
					CString szDateTime = FileStatus.m_mtime.Format(_T("%#m/%#d/%Y %#I:%M %p"));				
					szFileInfo.Format(_T("%d bytes, %s"), (DWORD) FileStatus.m_size, szDateTime);
				}
			}
		}
	}

	// This is mainly to protect me from myself :) Yes, I did almost post a bug report
	// because I didn't have XML files in and AC was crashing. --elph
	if( m_bDoUpdate )
	{
		m_bDoUpdate = false;
		OnUpdate( );
	}
	else if (szFileInfo == _T("file not found") && !bAlreadyBuggedUser) {
		::MessageBox(NULL, "One or more of your XML files were not found!\nPlease click the Update button to ensure that Decal works correctly!", "Decal", MB_OK|MB_ICONERROR);
		bAlreadyBuggedUser = true;
	}
}

void CDenAgentDlg::OnDeleteitemPlugins(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

	// Clear the plugin
	delete reinterpret_cast< cPlugin * > ( pNMListView->lParam );

	*pResult = 0;
}

void CDenAgentDlg::OnClickPlugins(NMHDR* pNMHDR, LRESULT* pResult) 
{
	*pResult = 0;
	LPNMITEMACTIVATE pItemActivate = reinterpret_cast< LPNMITEMACTIVATE > ( pNMHDR );

	if ( pItemActivate->iItem == -1 || pItemActivate->lParam == 0 )
		// A plugin item was not hit
		return;

	// Hit test to see if the icon was hit (checkbox)
	if ( pItemActivate->ptAction.x < 16 || pItemActivate->ptAction.x > 32 )
		return;

	// Invert the check
	cPlugin *pPlugin = reinterpret_cast< cPlugin * > ( m_wndPlugins.GetItemData ( pItemActivate->iItem ) );
	CComPtr< IDecalEnum > pEnum;

	if (pPlugin && SUCCEEDED ( m_pDecal->get_Configuration ( _bstr_t ( pPlugin->m_group ), pPlugin->m_id, &pEnum ) ) )
	{
		pPlugin->m_bEnabled = !pPlugin->m_bEnabled;

		// Write the registry and the icons
		pEnum->put_Enabled ( ( pPlugin->m_bEnabled ) ? VARIANT_TRUE : VARIANT_FALSE );

		LVITEM lvi = { LVIF_IMAGE, pItemActivate->iItem, 0, 0, 0, NULL, 0, 
			( pPlugin->m_bEnabled ) ? 6 : 5, };
		m_wndPlugins.SetItem ( &lvi );
	}
	else
		// Bad data in the list - refresh
		loadPluginList ();
}

void CDenAgentDlg::OnBegindragPlugins(NMHDR* pNMHDR, LRESULT* pResult) 
{
	*pResult = 0;
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

	// Check if this item is valid for dragging
	if ( pNMListView->iItem == -1 )
		return;

	cPlugin *pPlugin = reinterpret_cast< cPlugin * > ( m_wndPlugins.GetItemData ( pNMListView->iItem ) );
	if ( pPlugin == NULL )
		return;

	m_wndPlugins.SetItemState ( pNMListView->iItem, LVIS_SELECTED, LVIS_SELECTED );
	m_hDragImage = ListView_CreateDragImage ( m_wndPlugins.m_hWnd, pNMListView->iItem, &CPoint ( 0, 0 ) );

	CRect rcItem;
	m_wndPlugins.GetItemRect ( pNMListView->iItem, rcItem, LVIR_BOUNDS );

	ImageList_BeginDrag ( m_hDragImage, 0, pNMListView->ptAction.x - rcItem.left, pNMListView->ptAction.y - rcItem.top );
	ImageList_DragEnter ( m_wndPlugins.m_hWnd, pNMListView->ptAction.x, pNMListView->ptAction.y );

	m_pCurrentDrag = pPlugin;

	SetCapture ();
}

void CDenAgentDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
	if ( m_pCurrentDrag != NULL )
	{
		SetCursor ( ::LoadCursor ( NULL, ( getDragInsertBefore ( point ) == -1 ) ? IDC_NO : IDC_ARROW ) );
		ImageList_DragMove ( point.x, point.y );
	}

	CDialog::OnMouseMove(nFlags, point);
}

void CDenAgentDlg::OnLButtonUp(UINT nFlags, CPoint point) 
{
	if ( m_pCurrentDrag != NULL )
	{
		ImageList_DragLeave ( m_wndPlugins.m_hWnd );
		ImageList_EndDrag ();
		ImageList_Destroy ( m_hDragImage );

		ReleaseCapture ();

		int nInsertBefore = getDragInsertBefore ( point );
		if ( nInsertBefore != -1 )
		{
			{
			CComPtr< IDecalEnum > pEnum;
			if ( SUCCEEDED ( m_pDecal->get_Configuration ( _bstr_t ( m_pCurrentDrag->m_group ), GUID_NULL, &pEnum ) ) )
			{
				if ( SUCCEEDED ( pEnum->Skip ( m_pCurrentDrag->m_id ) ) )
					pEnum->MoveBefore ( reinterpret_cast< cPlugin * > ( m_wndPlugins.GetItemData ( nInsertBefore ) )->m_id );
			}
			}

			loadPluginList ();
		}

		m_pCurrentDrag = NULL;
	}

	CDialog::OnLButtonUp(nFlags, point);
}

void CDenAgentDlg::OnBnClickedDelete()
{
/*
	HOW TO USE THIS FEATURE
	create a string value under your plugin key called "Uninstaller"
	the value of this key should be the name of your uninstaller program,
	as listed under HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\
	for MSI installers the name will be a GUID, for others it may be a GUID or plain text
	
	that's it
	-para
*/

	USES_CONVERSION;

	int nSelMark = m_wndPlugins.GetSelectionMark();
	if ( nSelMark == -1 )
		return;
		
	cPlugin *pPlugin = reinterpret_cast< cPlugin * >(m_wndPlugins.GetItemData( nSelMark ));
	if ( pPlugin == NULL )
		return;
		
	//ask permission MB_OKCANCEL | MB_ICONEXCLAMATION = IDOK
	//_snprintf(szMsg, 512, "You are about to remove %s\nPress OK to continue", stuff)
	if ( ::MessageBox(NULL, _T("You are about to remove this plugin.\nPress OK to continue"), _T("Remove Plugin"), MB_OKCANCEL | MB_ICONEXCLAMATION) != IDOK )
		return;

	//load up the decal registry and remove this entry
	RegKey keyPlugin;
	CString decalPluginKey;
	BSTR sClsid;

	StringFromCLSID(pPlugin->m_id, &sClsid);
	if ((stricmp(pPlugin->m_group, "plugins") == 0) || (stricmp(pPlugin->m_group, "networkfilters") == 0))
	{
		decalPluginKey.Format("SOFTWARE\\Decal\\%s", pPlugin->m_group);
		
		if (keyPlugin.Open(HKEY_LOCAL_MACHINE, _T(decalPluginKey), KEY_ALL_ACCESS) == ERROR_SUCCESS)
		{
			RegKey keySub;
			if (keySub.Open(keyPlugin.m_hKey, OLE2T(sClsid), KEY_READ) == ERROR_SUCCESS)
			{
				//read the uninstaller string and fire it off
				TCHAR sUninstall[512];
				DWORD dwSize = 512;
				
				if (keySub.QueryStringValue(_T("Uninstaller"), sUninstall, &dwSize) == ERROR_SUCCESS)
				{
					RegKey keyUninstall;
					CString sUninstallKey;
					
					sUninstallKey.Format("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s", sUninstall);
					if (keyUninstall.Open(HKEY_LOCAL_MACHINE, _T(sUninstallKey), KEY_READ) == ERROR_SUCCESS)
					{
						TCHAR sUninstallPath[512];
						dwSize = 512;
						
						keyUninstall.QueryStringValue(_T("UninstallString"), sUninstallPath, &dwSize);
						keyUninstall.Close();

						//execute!
						STARTUPINFO si;
						PROCESS_INFORMATION pi;
						
						memset(&si, 0, sizeof(si));
						memset(&pi, 0, sizeof(pi));
						si.cb = sizeof(si);
						
						CreateProcess(NULL, sUninstallPath, NULL, NULL, false, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi);
					}
				} else {
					::MessageBox(NULL, _T("There was no uninstaller key defined for this object\nYou will have to uninstall it manually"), _T("Decal Error"), MB_ICONEXCLAMATION);
				}
				keySub.Close();
			}
			
			keyPlugin.DeleteSubKey(OLE2T(sClsid));
			keyPlugin.Close();
		}
		else
			::MessageBox(NULL, _T("Unable to open registry"), _T("Decal Error"), MB_ICONEXCLAMATION);
		
		//refresh
		loadPluginList();
	}
}
void CDenAgentDlg::OnBnClickedExport()
{
	cExportDlg dlg;	
	dlg.SetDecal(m_pDecal);
	dlg.DoModal();
}
