Build 0.5.0

This commit is contained in:
DavidXanatos 2020-12-07 17:34:20 +01:00
parent 618c5fd3c5
commit 4663599ffe
42 changed files with 3726 additions and 493 deletions

View File

@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [0.5.0 / 5.45.0] - 2020-12-01
## [0.5.0 / 5.45.0] - 2020-12-06
### Added
- added new notification window
@ -27,6 +27,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- added icons to box option tabs
- added box grouping
- added new debug option "DebugTrace=y" to log debug output to the trace log
- added check for updates to the new SandMan UI
- added check for updates to the legacy SbieCtrl UI
### Changed
- File migration limit can now be disabled by specifying "CopyLimitKb=-1"
@ -35,6 +37,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- reworked sandbox dletion mechaism ofthe new UI
- restructured sandbox options window
- SbieDLL.dll can now be compiled with an up to date nitll.lib
- improved automated driver self repair
### Fixed
- fixed issues migrating files > 4GB
@ -47,6 +50,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- fixed issues when a snapshot operation failed
- fixed some special cases of IpcPath and WinClass in the new UI
- fixed driver issues with WHQL passing compatybility testing
- fixed issues with classical installer
@ -118,7 +122,6 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- fixed issue deleting sandbox when located on a drive directly
## [0.4.2 / 5.43.6] - 2020-10-10
### Added
@ -130,7 +133,6 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- fixed chrome 86+ compatybility bug with chroms own sandbox
## [0.4.1 / 5.43.5] - 2020-09-12
### Added

View File

@ -108,7 +108,7 @@
<PrecompiledHeader>Use</PrecompiledHeader>
</ClCompile>
<Link>
<AdditionalDependencies>uafxcw.lib;common.lib;SbieDll.lib;ntdll.lib;psapi.lib;wininet.lib</AdditionalDependencies>
<AdditionalDependencies>uafxcw.lib;common.lib;SbieDll.lib;ntdll.lib;psapi.lib;wininet.lib;winhttp.lib</AdditionalDependencies>
<EntryPointSymbol>
</EntryPointSymbol>
<IgnoreSpecificDefaultLibraries>uafxcw.lib</IgnoreSpecificDefaultLibraries>
@ -126,7 +126,7 @@
<PrecompiledHeader>Use</PrecompiledHeader>
</ClCompile>
<Link>
<AdditionalDependencies>uafxcw.lib;common.lib;SbieDll.lib;ntdll.lib;psapi.lib;wininet.lib</AdditionalDependencies>
<AdditionalDependencies>uafxcw.lib;common.lib;SbieDll.lib;ntdll.lib;psapi.lib;wininet.lib;winhttp.lib</AdditionalDependencies>
<EntryPointSymbol>
</EntryPointSymbol>
<IgnoreSpecificDefaultLibraries>uafxcw.lib</IgnoreSpecificDefaultLibraries>
@ -143,7 +143,7 @@
<PrecompiledHeader>Use</PrecompiledHeader>
</ClCompile>
<Link>
<AdditionalDependencies>uafxcw.lib;common.lib;SbieDll.lib;ntdll.lib;psapi.lib;wininet.lib</AdditionalDependencies>
<AdditionalDependencies>uafxcw.lib;common.lib;SbieDll.lib;ntdll.lib;psapi.lib;wininet.lib;winhttp.lib</AdditionalDependencies>
<EntryPointSymbol>
</EntryPointSymbol>
<IgnoreSpecificDefaultLibraries>uafxcw.lib</IgnoreSpecificDefaultLibraries>
@ -158,7 +158,7 @@
<PrecompiledHeader>Use</PrecompiledHeader>
</ClCompile>
<Link>
<AdditionalDependencies>uafxcw.lib;common.lib;SbieDll.lib;ntdll.lib;psapi.lib;wininet.lib</AdditionalDependencies>
<AdditionalDependencies>uafxcw.lib;common.lib;SbieDll.lib;ntdll.lib;psapi.lib;wininet.lib;winhttp.lib</AdditionalDependencies>
<EntryPointSymbol>
</EntryPointSymbol>
<IgnoreSpecificDefaultLibraries>uafxcw.lib</IgnoreSpecificDefaultLibraries>
@ -167,6 +167,18 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\common\json\JSON.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\..\common\json\JSONValue.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\common\BoxOrder.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">NotUsing</PrecompiledHeader>
@ -271,11 +283,16 @@
<ClCompile Include="ThirdPartyDialog.cpp" />
<ClCompile Include="ToolTipButton.cpp" />
<ClCompile Include="TreePropSheet.cpp" />
<ClCompile Include="UpdateDialog.cpp" />
<ClCompile Include="Updater.cpp" />
<ClCompile Include="UserSettings.cpp" />
<ClCompile Include="ViewTemplateDialog.cpp" />
<ClCompile Include="WindowTitleMap.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\common\json\JSON.h" />
<ClInclude Include="..\..\common\json\JSONValue.h" />
<ClInclude Include="..\..\common\my_version.h" />
<ClInclude Include="..\common\BoxOrder.h" />
<ClInclude Include="..\common\FontStore.h" />
<ClInclude Include="..\common\Layout.h" />
@ -331,6 +348,8 @@
<ClInclude Include="ThirdPartyDialog.h" />
<ClInclude Include="ToolTipButton.h" />
<ClInclude Include="TreePropSheet.h" />
<ClInclude Include="UpdateDialog.h" />
<ClInclude Include="Updater.h" />
<ClInclude Include="UserSettings.h" />
<ClInclude Include="ViewTemplateDialog.h" />
<ClInclude Include="WindowTitleMap.h" />
@ -339,7 +358,6 @@
<ResourceCompile Include="SbieControl.rc" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\sbieweb\web\img\FrontPage\FrontPageAnimation.gif" />
<None Include="..\res\background.png" />
<None Include="..\res\bigex.ico" />
<None Include="..\res\checkmark.png" />

View File

@ -0,0 +1,210 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Manifest Include="..\res\xptheme.manifest" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="AboutDialog.cpp" />
<ClCompile Include="AlertDialog.cpp" />
<ClCompile Include="AnimatedBitmap.cpp" />
<ClCompile Include="AppPage.cpp" />
<ClCompile Include="AutoPlay.cpp" />
<ClCompile Include="BaseDialog.cpp" />
<ClCompile Include="BorderGuard.cpp" />
<ClCompile Include="Box.cpp" />
<ClCompile Include="Boxes.cpp" />
<ClCompile Include="BoxFile.cpp" />
<ClCompile Include="BoxPage.cpp" />
<ClCompile Include="BoxProc.cpp" />
<ClCompile Include="CreateDialog.cpp" />
<ClCompile Include="DeleteDialog.cpp" />
<ClCompile Include="DisableForceDialog.cpp" />
<ClCompile Include="FileListCtrl.cpp" />
<ClCompile Include="FinderDialog.cpp" />
<ClCompile Include="FindTool.c" />
<ClCompile Include="FlashingButton.cpp" />
<ClCompile Include="GettingStartedWizard.cpp" />
<ClCompile Include="InitWait.cpp" />
<ClCompile Include="LockConfigDialog.cpp" />
<ClCompile Include="MenuXP.cpp" />
<ClCompile Include="MenuXP_Draw.cpp" />
<ClCompile Include="MessageDialog.cpp" />
<ClCompile Include="MonitorDialog.cpp" />
<ClCompile Include="MyApp.cpp" />
<ClCompile Include="MyFrame.cpp" />
<ClCompile Include="MyListCtrl.cpp" />
<ClCompile Include="MyWizard.cpp" />
<ClCompile Include="ProcListCtrl.cpp" />
<ClCompile Include="ProcSettingsDialog.cpp" />
<ClCompile Include="ProgramSelector.cpp" />
<ClCompile Include="PropPageFrame.cpp" />
<ClCompile Include="PropPageFrameDefault.cpp" />
<ClCompile Include="QuickRecover.cpp" />
<ClCompile Include="RevealDialog.cpp" />
<ClCompile Include="SbieIni.cpp" />
<ClCompile Include="SetFolderDialog.cpp" />
<ClCompile Include="SetLayoutDialog.cpp" />
<ClCompile Include="ShellDialog.cpp" />
<ClCompile Include="stdafx.cpp" />
<ClCompile Include="TabbingComboBox.cpp" />
<ClCompile Include="TemplateListBox.cpp" />
<ClCompile Include="ThirdPartyDialog.cpp" />
<ClCompile Include="ToolTipButton.cpp" />
<ClCompile Include="TreePropSheet.cpp" />
<ClCompile Include="UserSettings.cpp" />
<ClCompile Include="ViewTemplateDialog.cpp" />
<ClCompile Include="WindowTitleMap.cpp" />
<ClCompile Include="..\common\BoxOrder.c">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\common\FontStore.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\common\Layout.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\common\MyGdi.c">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\common\MyMsg.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\common\RunBrowser.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\common\RunStartExe.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\common\json\JSON.cpp">
<Filter>common\json</Filter>
</ClCompile>
<ClCompile Include="..\..\common\json\JSONValue.cpp">
<Filter>common\json</Filter>
</ClCompile>
<ClCompile Include="UpdateDialog.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AboutDialog.h" />
<ClInclude Include="AlertDialog.h" />
<ClInclude Include="AnimatedBitmap.h" />
<ClInclude Include="AppPage.h" />
<ClInclude Include="AutoPlay.h" />
<ClInclude Include="BaseDialog.h" />
<ClInclude Include="BorderGuard.h" />
<ClInclude Include="Box.h" />
<ClInclude Include="Boxes.h" />
<ClInclude Include="BoxFile.h" />
<ClInclude Include="BoxPage.h" />
<ClInclude Include="BoxProc.h" />
<ClInclude Include="CreateDialog.h" />
<ClInclude Include="DeleteDialog.h" />
<ClInclude Include="DisableForceDialog.h" />
<ClInclude Include="FileListCtrl.h" />
<ClInclude Include="FinderDialog.h" />
<ClInclude Include="FindTool.h" />
<ClInclude Include="FlashingButton.h" />
<ClInclude Include="GettingStartedWizard.h" />
<ClInclude Include="InitWait.h" />
<ClInclude Include="LockConfigDialog.h" />
<ClInclude Include="MenuXP.h" />
<ClInclude Include="MenuXP_Draw.h" />
<ClInclude Include="MenuXP_Tools.h" />
<ClInclude Include="MessageDialog.h" />
<ClInclude Include="MonitorDialog.h" />
<ClInclude Include="MyApp.h" />
<ClInclude Include="MyFrame.h" />
<ClInclude Include="MyListCtrl.h" />
<ClInclude Include="MyWizard.h" />
<ClInclude Include="ProcListCtrl.h" />
<ClInclude Include="ProcSettingsDialog.h" />
<ClInclude Include="ProgramSelector.h" />
<ClInclude Include="PropPageFrame.h" />
<ClInclude Include="PropPageFrameDefault.h" />
<ClInclude Include="QuickRecover.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="RevealDialog.h" />
<ClInclude Include="SbieIni.h" />
<ClInclude Include="SetFolderDialog.h" />
<ClInclude Include="SetLayoutDialog.h" />
<ClInclude Include="ShellDialog.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="TabbingComboBox.h" />
<ClInclude Include="TemplateListBox.h" />
<ClInclude Include="ThirdPartyDialog.h" />
<ClInclude Include="ToolTipButton.h" />
<ClInclude Include="TreePropSheet.h" />
<ClInclude Include="UserSettings.h" />
<ClInclude Include="ViewTemplateDialog.h" />
<ClInclude Include="WindowTitleMap.h" />
<ClInclude Include="..\common\BoxOrder.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\common\FontStore.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\common\Layout.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\common\MyGdi.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\common\MyMsg.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\common\RunBrowser.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\common\my_version.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\common\json\JSON.h">
<Filter>common\json</Filter>
</ClInclude>
<ClInclude Include="..\..\common\json\JSONValue.h">
<Filter>common\json</Filter>
</ClInclude>
<ClInclude Include="UpdateDialog.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="SbieControl.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="..\res\FrontPageAnimation.gif" />
</ItemGroup>
<ItemGroup>
<None Include="..\res\background.png" />
<None Include="..\res\bigex.ico" />
<None Include="..\res\checkmark.png" />
<None Include="..\res\controlwin.ico" />
<None Include="..\res\cycle.png" />
<None Include="..\res\exclamation.png" />
<None Include="..\res\finder-empty.bmp" />
<None Include="..\res\finder-full.bmp" />
<None Include="..\res\finder.cur" />
<None Include="..\res\folder-minus.ico" />
<None Include="..\res\folder-plus.ico" />
<None Include="..\res\GettingStartedLegend.png" />
<None Include="..\res\initwait1.ico" />
<None Include="..\res\initwait2.ico" />
<None Include="..\res\MastheadLogo.jpg" />
<None Include="..\res\none.ico" />
<None Include="..\res\proc-empty.ico" />
<None Include="..\res\proc-full-minus.ico" />
<None Include="..\res\proc-full-plus.ico" />
<None Include="..\res\questionmark.png" />
<None Include="..\res\sandbox-delete.ico" />
<None Include="..\res\sandbox-empty-dfp.ico" />
<None Include="..\res\sandbox-empty.ico" />
<None Include="..\res\sandbox-full-dfp.ico" />
<None Include="..\res\sandbox-full.ico" />
<None Include="SbieControl.rc2" />
</ItemGroup>
<ItemGroup>
<Filter Include="common">
<UniqueIdentifier>{be66dba5-2f3c-4325-abc0-4283750262a2}</UniqueIdentifier>
</Filter>
<Filter Include="common\json">
<UniqueIdentifier>{1eb5d258-3c21-4ed6-9384-57dd80c51c36}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View File

@ -45,7 +45,8 @@
#include "apps/common/RunBrowser.h"
#include "apps/common/BoxOrder.h"
#include "common/my_version.h"
#include "Updater.h"
#include "UpdateDialog.h"
//---------------------------------------------------------------------------
// Defines
@ -87,6 +88,8 @@ static const WCHAR *_HideWindowNotify = L"HideWindowNotify";
const WCHAR *_UpdateCheckNotify = L"UpdateCheckNotify";
static const WCHAR *_ShouldDeleteNotify = L"ShouldDeleteNotify";
const WCHAR *_NextUpdateCheck = L"NextUpdateCheck";
BOOL CMyFrame::m_inTimer = FALSE;
BOOL CMyFrame::m_destroyed = FALSE;
@ -135,11 +138,15 @@ BEGIN_MESSAGE_MAP(CMyFrame, CFrameWnd)
ON_COMMAND(ID_CONF_EDIT, OnCmdConfEdit)
ON_COMMAND(ID_CONF_RELOAD, OnCmdConfReload)
ON_COMMAND(ID_HELP_SUPPORT, OnCmdHelpSupport)
ON_COMMAND(ID_HELP_TOPICS, OnCmdHelpTopics)
ON_COMMAND(ID_HELP_TUTORIAL, OnCmdHelpTutorial)
ON_COMMAND(ID_HELP_FORUM, OnCmdHelpForum)
ON_COMMAND(ID_HELP_UPDATE, OnCmdHelpUpdate)
ON_COMMAND(ID_HELP_ABOUT, OnCmdHelpAbout)
//ON_MESSAGE(WM_UPDATERESULT, OnUpdateResult)
ON_COMMAND(ID_PROCESS_TERMINATE, OnCmdTerminateProcess)
ON_UPDATE_COMMAND_UI(ID_DISABLE_FORCE, OnUpdDisableForce)
@ -962,6 +969,17 @@ void CMyFrame::OnCmdConfReload()
}
//---------------------------------------------------------------------------
// OnCmdHelpSupport
//---------------------------------------------------------------------------
void CMyFrame::OnCmdHelpSupport()
{
CRunBrowser x(this, L"https://xanasoft.com/go.php?to=donate");
}
//---------------------------------------------------------------------------
// OnCmdHelpTopics
//---------------------------------------------------------------------------
@ -997,8 +1015,17 @@ void CMyFrame::OnCmdHelpForum()
CRunBrowser::OpenForum(this);
}
//---------------------------------------------------------------------------
// OnCmdHelpUpdate
//---------------------------------------------------------------------------
void CMyFrame::OnCmdHelpUpdate()
{
CUpdateDialog dlg(this);
dlg.DoModal();
}
//---------------------------------------------------------------------------
// OnCmdHelpAbout
//---------------------------------------------------------------------------
@ -2007,6 +2034,39 @@ void CMyFrame::OnTimer(UINT_PTR nIDEvent)
if ((_counter % 600) == 0)
SaveSettings();
//
// update check
//
if (! m_hidden)
{
__int64 NextUpdateCheck;
CUserSettings::GetInstance().GetNum64(_NextUpdateCheck, NextUpdateCheck, 0);
if(NextUpdateCheck == 0)
CUserSettings::GetInstance().SetNum64(_NextUpdateCheck, time(NULL) + 7 * 24 * 60 * 60);
else if(NextUpdateCheck != -1 && time(NULL) >= NextUpdateCheck)
{
BOOL UpdateCheckNotify;
CUserSettings::GetInstance().GetBool(_UpdateCheckNotify, UpdateCheckNotify, TRUE);
if (UpdateCheckNotify)
{
static BOOLEAN update_dlg_open = FALSE;
if (!update_dlg_open) {
update_dlg_open = TRUE;
CUpdateDialog dlg(this);
if(dlg.DoModal() == 0)
CUserSettings::GetInstance().SetNum64(_NextUpdateCheck, time(NULL) + 1 * 24 * 60 * 60);
update_dlg_open = FALSE;
}
}
else
{
CUserSettings::GetInstance().SetNum64(_NextUpdateCheck, time(NULL) + 1 * 24 * 60 * 60);
CUpdater::GetInstance().CheckUpdates(this, false);
}
}
}
//
// refresh processes
//
@ -2331,3 +2391,9 @@ void CMyFrame::CheckShouldDelete(CBox &box)
}
}
}
/*LRESULT CMyFrame::OnUpdateResult(WPARAM wParam, LPARAM lParam)
{
return 0;
}*/

View File

@ -119,10 +119,13 @@ class CMyFrame : public CFrameWnd
afx_msg void OnCmdConfLock();
afx_msg void OnCmdConfEdit();
afx_msg void OnCmdConfReload();
afx_msg void OnCmdHelpSupport();
afx_msg void OnCmdHelpTopics();
afx_msg void OnCmdHelpTutorial();
afx_msg void OnCmdHelpForum();
afx_msg void OnCmdHelpUpdate();
afx_msg void OnCmdHelpAbout();
//afx_msg LRESULT OnUpdateResult(WPARAM wParam, LPARAM lParam);
afx_msg void OnCmdTerminateProcess();
afx_msg void OnUpdViewMenu(CCmdUI *pCmdUI);

View File

@ -0,0 +1,171 @@
/*
* Copyright 2020 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
// Run Browser Dialog
//---------------------------------------------------------------------------
#include "stdafx.h"
#include "UpdateDialog.h"
#include "Updater.h"
#include "common/CommonUtils.h"
#include "common/MyMsg.h"
#include "core/dll/sbiedll.h"
#include "UserSettings.h"
//---------------------------------------------------------------------------
// Message Map
//---------------------------------------------------------------------------
BEGIN_MESSAGE_MAP(CUpdateDialog, CDialog)
ON_COMMAND(IDOK, OnNow)
ON_COMMAND(ID_UPDATE_LATER, OnLater)
ON_COMMAND(ID_UPDATE_NEVER, OnNever)
ON_COMMAND(IDCANCEL, OnCancel)
END_MESSAGE_MAP()
//---------------------------------------------------------------------------
// Constructor
//---------------------------------------------------------------------------
CUpdateDialog::CUpdateDialog(CWnd *pParentWnd)
: CDialog((UINT)0, pParentWnd)
{
m_lpszTemplateName = L"UPDATE_DIALOG";
BOOLEAN LayoutRTL;
SbieDll_GetLanguage(&LayoutRTL);
if (LayoutRTL) {
m_DlgTmplCopy =
Common_DlgTmplRtl(AfxGetInstanceHandle(), m_lpszTemplateName);
if (m_DlgTmplCopy) {
m_lpszTemplateName = NULL;
InitModalIndirect((LPCDLGTEMPLATE)m_DlgTmplCopy, m_pParentWnd);
}
} else
m_DlgTmplCopy = NULL;
}
//---------------------------------------------------------------------------
// Destructor
//---------------------------------------------------------------------------
CUpdateDialog::~CUpdateDialog()
{
if (m_DlgTmplCopy) {
HeapFree(GetProcessHeap(), 0, m_DlgTmplCopy);
m_DlgTmplCopy = NULL;
}
}
//---------------------------------------------------------------------------
// OnInitDialog
//---------------------------------------------------------------------------
BOOL CUpdateDialog::OnInitDialog()
{
SetWindowText(CMyMsg(MSG_3621));
GetDlgItem(ID_UPDATE_EXPLAIN_1)->SetWindowText(CMyMsg(MSG_3622));
GetDlgItem(IDOK)->SetWindowText(CMyMsg(MSG_3623));
GetDlgItem(ID_UPDATE_LATER)->SetWindowText(CMyMsg(MSG_3624));
GetDlgItem(ID_UPDATE_NEVER)->SetWindowText(CMyMsg(MSG_3625));
GetDlgItem(IDCANCEL)->SetWindowText(CMyMsg(MSG_3002));
GetDlgItem(ID_UPDATE_SILENT)->SetWindowText(CMyMsg(MSG_3626));
GetDlgItem(ID_UPDATE_EXPLAIN_2)->SetWindowText(CMyMsg(MSG_3627));
BOOL UpdateCheckNotify;
CUserSettings::GetInstance().GetBool(_UpdateCheckNotify, UpdateCheckNotify, FALSE);
CButton *pCheckBox1 = (CButton *)GetDlgItem(ID_UPDATE_SILENT);
pCheckBox1->SetCheck(!UpdateCheckNotify ? BST_CHECKED : BST_UNCHECKED);
return TRUE;
}
//---------------------------------------------------------------------------
// OnNow
//---------------------------------------------------------------------------
void CUpdateDialog::OnNow()
{
if(!CUpdater::GetInstance().CheckUpdates(GetParent()))
CMyApp::MsgBox(NULL, MSG_3628, MB_OK);
CloseDialog();
}
//---------------------------------------------------------------------------
// OnLater
//---------------------------------------------------------------------------
void CUpdateDialog::OnLater()
{
CUserSettings::GetInstance().SetNum64(_NextUpdateCheck, time(NULL) + 7 * 24 * 60 * 60);
CloseDialog();
}
//---------------------------------------------------------------------------
// OnNever
//---------------------------------------------------------------------------
void CUpdateDialog::OnNever()
{
CUserSettings::GetInstance().SetNum64(_NextUpdateCheck, -1);
CloseDialog();
}
//---------------------------------------------------------------------------
// OnCancel
//---------------------------------------------------------------------------
void CUpdateDialog::OnCancel()
{
EndDialog(0);
}
//---------------------------------------------------------------------------
// EndDialog
//---------------------------------------------------------------------------
void CUpdateDialog::CloseDialog()
{
CButton *pCheckBox1 = (CButton *)GetDlgItem(ID_UPDATE_SILENT);
CUserSettings::GetInstance().SetBool(_UpdateCheckNotify, !pCheckBox1->GetCheck() == BST_CHECKED);
EndDialog(1);
}

View File

@ -0,0 +1,71 @@
/*
* Copyright 2020 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
// Run Browser Dialog Box
//---------------------------------------------------------------------------
#ifndef _MY_UPDATEDIALOG_H
#define _MY_UPDATEDIALOG_H
//---------------------------------------------------------------------------
// Defines
//---------------------------------------------------------------------------
#define ID_RUN_BROWSER_EXPLAIN 10111
#define ID_RUN_BROWSER_URL 10222
//---------------------------------------------------------------------------
// CUpdateDialog Class
//---------------------------------------------------------------------------
#ifndef RC_INVOKED
#include <afxcmn.h>
class CUpdateDialog : public CDialog
{
DECLARE_MESSAGE_MAP()
void *m_DlgTmplCopy;
virtual BOOL OnInitDialog();
afx_msg void OnNow();
afx_msg void OnLater();
afx_msg void OnNever();
afx_msg void OnCancel();
void CloseDialog();
public:
CUpdateDialog(CWnd *pParentWnd);
~CUpdateDialog();
};
#endif // ! RC_INVOKED
#endif // _MY_UPDATEDIALOG_H

View File

@ -0,0 +1,487 @@
/*
* Copyright 2020 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
// Updater
//---------------------------------------------------------------------------
#include "stdafx.h"
#include <winhttp.h>
#include "Updater.h"
#include "UpdateDialog.h"
#include "common/RunBrowser.h"
#include "SbieIni.h"
#include "UserSettings.h"
#define CRC_WITH_ADLER32
#include "common/crc.c"
#include "common/my_version.h"
#include "common/json/JSON.h"
#include "common/win32_ntddk.h"
//---------------------------------------------------------------------------
// Variables
//---------------------------------------------------------------------------
CUpdater *CUpdater::m_instance = NULL;
//---------------------------------------------------------------------------
// Constructor
//---------------------------------------------------------------------------
CUpdater::CUpdater()
{
m_update_pending = false;
//OSVERSIONINFOW m_osvi = { 0 };
m_osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOW);
*(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetVersion");
if (RtlGetVersion == NULL || !NT_SUCCESS(RtlGetVersion(&m_osvi)))
GetVersionExW(&m_osvi);
}
//---------------------------------------------------------------------------
// Destructor
//---------------------------------------------------------------------------
CUpdater::~CUpdater()
{
}
//---------------------------------------------------------------------------
// GetInstance
//---------------------------------------------------------------------------
CUpdater &CUpdater::GetInstance()
{
if (!m_instance)
m_instance = new CUpdater();
return *m_instance;
}
//---------------------------------------------------------------------------
// CheckUpdates
//---------------------------------------------------------------------------
bool CUpdater::CheckUpdates(CWnd *pParentWnd, bool bManual)
{
if (m_update_pending)
return false;
ULONG ThreadId;
ULONG_PTR *ThreadArgs = new ULONG_PTR[2];
ThreadArgs[0] = (ULONG_PTR)pParentWnd->m_hWnd;
ThreadArgs[1] = bManual ? 1 : 0;
CreateThread(NULL, 0, UpdaterServiceThread, ThreadArgs, 0, &ThreadId);
return true;
}
//---------------------------------------------------------------------------
// DownloadUpdateData
//---------------------------------------------------------------------------
BOOLEAN CUpdater::DownloadUpdateData(const WCHAR* Host, const WCHAR* Path, PSTR* pData, ULONG* pDataLength)
{
BOOLEAN success = FALSE;
PVOID SessionHandle = NULL;
PVOID ConnectionHandle = NULL;
PVOID RequestHandle = NULL;
{
SessionHandle = WinHttpOpen(NULL,
m_osvi.dwMajorVersion >= 8 ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!SessionHandle)
goto CleanupExit;
if (m_osvi.dwMajorVersion >= 8) {
ULONG Options = WINHTTP_DECOMPRESSION_FLAG_GZIP | WINHTTP_DECOMPRESSION_FLAG_DEFLATE;
WinHttpSetOption(SessionHandle, WINHTTP_OPTION_DECOMPRESSION, &Options, sizeof(Options));
}
}
{
ConnectionHandle = WinHttpConnect(SessionHandle, Host, 443, 0); // ssl port
if (!ConnectionHandle)
goto CleanupExit;
}
{
ULONG httpFlags = WINHTTP_FLAG_SECURE | WINHTTP_FLAG_REFRESH;
RequestHandle = WinHttpOpenRequest(ConnectionHandle,
NULL, Path, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, httpFlags);
if (!RequestHandle)
goto CleanupExit;
ULONG Options = WINHTTP_DISABLE_KEEP_ALIVE;
WinHttpSetOption(RequestHandle, WINHTTP_OPTION_DISABLE_FEATURE, &Options, sizeof(Options));
}
if (!WinHttpSendRequest(RequestHandle, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, 0))
goto CleanupExit;
if (!WinHttpReceiveResponse(RequestHandle, NULL))
goto CleanupExit;
{
PVOID result = NULL;
ULONG allocatedLength;
ULONG dataLength;
ULONG returnLength;
BYTE buffer[PAGE_SIZE];
if (pData == NULL)
goto CleanupExit;
allocatedLength = sizeof(buffer);
*pData = (PSTR)malloc(allocatedLength);
dataLength = 0;
while (WinHttpReadData(RequestHandle, buffer, PAGE_SIZE, &returnLength))
{
if (returnLength == 0)
break;
if (allocatedLength < dataLength + returnLength)
{
allocatedLength *= 2;
*pData = (PSTR)realloc(*pData, allocatedLength);
}
memcpy(*pData + dataLength, buffer, returnLength);
dataLength += returnLength;
}
if (allocatedLength < dataLength + 1)
{
allocatedLength++;
*pData = (PSTR)realloc(*pData, allocatedLength);
}
// Ensure that the buffer is null-terminated.
(*pData)[dataLength] = 0;
if (pDataLength != NULL)
*pDataLength = dataLength;
}
success = TRUE;
CleanupExit:
if (RequestHandle)
WinHttpCloseHandle(RequestHandle);
if (ConnectionHandle)
WinHttpCloseHandle(ConnectionHandle);
if (SessionHandle)
WinHttpCloseHandle(SessionHandle);
return success;
}
//---------------------------------------------------------------------------
// GetJSONStringSafe
//---------------------------------------------------------------------------
std::wstring GetJSONStringSafe(const JSONObject& root, const std::wstring& key, const std::wstring& default = L"")
{
auto I = root.find(key);
if (I == root.end() || !I->second->IsString())
return default;
return I->second->AsString();
}
//---------------------------------------------------------------------------
// QueryUpdateData
//---------------------------------------------------------------------------
BOOLEAN CUpdater::QueryUpdateData(UPDATER_DATA* Context)
{
BOOLEAN success = FALSE;
CString Path;
char* jsonString = NULL;
JSONValue* jsonObject = NULL;
JSONObject jsonRoot;
Path.Format(L"/update.php?software=sandboxie&version=%S&system=windows-%d.%d.%d-%s&language=%d&auto=%s", MY_VERSION_STRING,
#ifdef _WIN64
m_osvi.dwMajorVersion, m_osvi.dwMinorVersion, m_osvi.dwBuildNumber, L"x86_64",
#else
m_osvi.dwMajorVersion, m_osvi.dwMinorVersion, m_osvi.dwBuildNumber, L"i386",
#endif
SbieDll_GetLanguage(NULL), Context->Manual ? L"0" : L"1");
CString update_key;
CSbieIni::GetInstance().GetText(_GlobalSettings, L"UpdateKey", update_key);
if (!update_key.IsEmpty())
Path += L"&update_key=" + update_key;
if (!DownloadUpdateData(L"xanasoft.com", Path, &jsonString, NULL)) {
Context->ErrorCode = GetLastError();
goto CleanupExit;
}
jsonObject = JSON::Parse((const char*)jsonString);
if (jsonObject == NULL || !jsonObject->IsObject()) {
Context->ErrorCode = WEB_E_INVALID_JSON_STRING;
goto CleanupExit;
}
jsonRoot = jsonObject->AsObject();
Context->userMsg = GetJSONStringSafe(jsonRoot, L"userMsg").c_str();
Context->infoUrl = GetJSONStringSafe(jsonRoot, L"infoUrl").c_str();
Context->version = GetJSONStringSafe(jsonRoot, L"version").c_str();
//Context->updated = (uint64_t)jsonRoot[L"updated"]->AsNumber();
Context->updateMsg = GetJSONStringSafe(jsonRoot, L"updateMsg").c_str();
Context->updateUrl = GetJSONStringSafe(jsonRoot, L"updateUrl").c_str();
Context->downloadUrl = GetJSONStringSafe(jsonRoot, L"downloadUrl").c_str();
success = TRUE;
CleanupExit:
if (jsonString)
free(jsonString);
if (jsonObject)
delete jsonObject;
return success;
}
//---------------------------------------------------------------------------
// DownloadUpdate
//---------------------------------------------------------------------------
CString CUpdater::DownloadUpdate(const CString& downloadUrl)
{
WCHAR TempDir[MAX_PATH + 1];
if (GetTempPath(MAX_PATH, (LPWSTR)&TempDir) == 0)
return L"";
int hostPos = downloadUrl.Find(L"://") + 3;
if(hostPos < 3)
return L"";
int pathPos = downloadUrl.Find(L"/", hostPos);
if (pathPos < 0)
return L"";
CString Host = downloadUrl.Mid(hostPos, pathPos - hostPos);
CString Path = downloadUrl.Mid(pathPos);
int queryPos = downloadUrl.Find(L"?", pathPos);
if (queryPos < 0)
queryPos = downloadUrl.GetLength();
CString Name = downloadUrl.Left(queryPos);
Name = Name.Mid(Name.ReverseFind(L'/') + 1);
if (Name.IsEmpty() || Name.Right(4).CompareNoCase(L".exe") != 0)
Name = L"SandboxieInstall.exe";
char* data = NULL;
ULONG size = 0;
if (!DownloadUpdateData(Host, Path, &data, &size))
return L"";
CString FilePath = TempDir + Name;
ULONG bytesWriten = 0;
HANDLE hFile = CreateFile(FilePath, FILE_GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
//SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
WriteFile(hFile, data, size, &bytesWriten, NULL);
CloseHandle(hFile);
}
free(data);
if(bytesWriten != size)
return L"";
return FilePath;
}
//---------------------------------------------------------------------------
// UpdaterServiceThread
//---------------------------------------------------------------------------
ULONG CUpdater::UpdaterServiceThread(void *lpParameter)
{
m_instance->m_update_pending = true;
ULONG_PTR *ThreadArgs = (ULONG_PTR *)lpParameter;
HWND parent = (HWND)ThreadArgs[0];
PUPDATER_DATA pContext = new UPDATER_DATA;
pContext->Manual = ThreadArgs[1] ? TRUE : FALSE;
pContext->ErrorCode = 0;
BOOLEAN Ret = m_instance->QueryUpdateData(pContext);
if (Ret)
{
bool bNothing = true;
CStringList IgnoredUpdates;
CUserSettings::GetInstance().GetTextList(L"_IgnoreUpdate", IgnoredUpdates);
if (!pContext->userMsg.IsEmpty())
{
WCHAR MsgHash[9];
ULONG crc = CRC_Adler32((UCHAR *)(const WCHAR*)pContext->userMsg, pContext->userMsg.GetLength() * sizeof(WCHAR));
wsprintf(MsgHash, L"%08X", crc);
if (IgnoredUpdates.Find(MsgHash) == NULL)
{
bNothing = false;
CString Msg = pContext->userMsg;
int rv;
if (pContext->infoUrl.IsEmpty())
rv = CMyApp::MsgCheckBox(NULL, Msg, 0, MB_OK);
else
{
Msg += "\n \n";
Msg += CMyMsg(MSG_3641) + L"?";
rv = CMyApp::MsgCheckBox(NULL, Msg, 0, MB_YESNO);
}
if (rv < 0) {
rv = -rv;
CUserSettings::GetInstance().AppendText(L"_IgnoreUpdate", MsgHash);
}
if (rv == IDYES)
CRunBrowser dlg(NULL, pContext->infoUrl);
}
}
if (!pContext->version.IsEmpty() && pContext->version.Compare(_T(MY_VERSION_STRING)) != 0)
{
if (pContext->Manual || IgnoredUpdates.Find(pContext->version) == NULL)
{
bNothing = false;
CString Msg = pContext->updateMsg;
if (Msg.IsEmpty())
Msg = CMyMsg(MSG_3630, pContext->version);
int rv;
if (pContext->updateUrl.IsEmpty() && pContext->downloadUrl.IsEmpty())
rv = CMyApp::MsgCheckBox(NULL, Msg, 0, MB_OK);
else
{
Msg += "\n \n";
if (!pContext->downloadUrl.IsEmpty())
Msg += CMyMsg(MSG_3631);
else
Msg += CMyMsg(MSG_3641) + L"?"; // MSG_3631
rv = CMyApp::MsgCheckBox(NULL, Msg, 0, MB_YESNO);
}
if (rv < 0) {
rv = -rv;
CUserSettings::GetInstance().AppendText(L"_IgnoreUpdate", pContext->version);
}
if (rv == IDYES)
{
if (!pContext->downloadUrl.IsEmpty())
{
CString downloadPath = m_instance->DownloadUpdate(pContext->downloadUrl);
if (downloadPath.IsEmpty())
CMyApp::MsgBox(NULL, MSG_3634, MB_OK);
else
{
rv = CMyApp::MsgBox(NULL, CMyMsg(MSG_3633, pContext->version, downloadPath), MB_YESNO);
if (rv == IDYES)
{
SHELLEXECUTEINFO shex;
memzero(&shex, sizeof(SHELLEXECUTEINFO));
shex.cbSize = sizeof(SHELLEXECUTEINFO);
shex.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI;
shex.hwnd = parent;
shex.lpFile = downloadPath;
shex.lpParameters = NULL;
shex.nShow = SW_SHOWNORMAL;
shex.lpVerb = L"runas";
if (ShellExecuteEx(&shex))
CloseHandle(shex.hProcess);
}
}
}
else
CRunBrowser dlg(NULL, pContext->updateUrl);
}
}
}
if (bNothing)
{
// schedule next theck for in a week, except when the user choose never
__int64 NextUpdateCheck;
CUserSettings::GetInstance().GetNum64(_NextUpdateCheck, NextUpdateCheck, 0);
if (NextUpdateCheck != -1)
CUserSettings::GetInstance().SetNum64(_NextUpdateCheck, time(NULL) + 7 * 24 * 60 * 60);
if (pContext->Manual)
CMyApp::MsgBox(NULL, MSG_3629, MB_OK);
}
}
else if (pContext->Manual)
CMyApp::MsgBox(NULL, MSG_3634, MB_OK);
//::PostMessage(parent, WM_UPDATERESULT, Ret, (LPARAM)pContext);
delete pContext;
m_instance->m_update_pending = false;
return 0;
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2020 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
// Updater
//---------------------------------------------------------------------------
#ifndef _MY_UPDATER_H
#define _MY_UPDATER_H
//#define WM_UPDATERESULT (WM_APP + 10)
typedef struct _UPDATER_DATA
{
CString userMsg;
CString infoUrl;
CString version;
//unsigned __int64 updated;
CString updateMsg;
CString updateUrl;
CString downloadUrl;
BOOLEAN Manual;
ULONG ErrorCode;
} UPDATER_DATA, *PUPDATER_DATA;
extern const WCHAR *_UpdateCheckNotify;
extern const WCHAR *_NextUpdateCheck;
class CUpdater
{
static CUpdater *m_instance;
bool m_update_pending;
OSVERSIONINFOW m_osvi;
CUpdater();
BOOLEAN DownloadUpdateData(const WCHAR* Host, const WCHAR* Path, PSTR* pData, ULONG* dataLength);
BOOLEAN QueryUpdateData(UPDATER_DATA* Context);
CString DownloadUpdate(const CString& downloadUrl);
static ULONG UpdaterServiceThread(void *lpParameter);
public:
~CUpdater();
static CUpdater &GetInstance();
bool CheckUpdates(CWnd *pParentWnd, bool bManual = true);
};
#endif // _MY_UPDATER_H

View File

@ -46,9 +46,11 @@
#define ID_CONF_RELOAD 40037
#define ID_CONF_THIRD_PARTY 40038
#define ID_CONF_LOCK 40039
#define ID_HELP_SUPPORT 40040
#define ID_HELP_TOPICS 40041
#define ID_HELP_TUTORIAL 40042
#define ID_HELP_FORUM 40043
#define ID_HELP_UPDATE 40044
#define ID_HELP_ABOUT 40045
#define ID_PROCESS_TERMINATE 40051
#define ID_PROCESS_SETTINGS 40052

View File

@ -0,0 +1,280 @@
/*
* File JSON.cpp part of the SimpleJSON Library - http://mjpa.in/json
*
* Copyright (C) 2010 Mike Anchor
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "JSON.h"
/**
* Blocks off the public constructor
*
* @access private
*
*/
JSON::JSON()
{
}
/**
* Parses a complete JSON encoded string
* This is just a wrapper around the UNICODE Parse().
*
* @access public
*
* @param char* data The JSON text
*
* @return JSONValue* Returns a JSON Value representing the root, or NULL on error
*/
JSONValue *JSON::Parse(const char *data)
{
size_t length = strlen(data) + 1;
wchar_t *w_data = (wchar_t*)malloc(length * sizeof(wchar_t));
#if defined(WIN32) && !defined(__GNUC__)
size_t ret_value = 0;
if (mbstowcs_s(&ret_value, w_data, length, data, length) != 0)
{
free(w_data);
return NULL;
}
#elif defined(ANDROID)
// mbstowcs seems to misbehave on android
for(size_t i = 0; i<length; i++)
w_data[i] = (wchar_t)data[i];
#else
if (mbstowcs(w_data, data, length) == (size_t)-1)
{
free(w_data);
return NULL;
}
#endif
JSONValue *value = JSON::Parse(w_data);
free(w_data);
return value;
}
/**
* Parses a complete JSON encoded string (UNICODE input version)
*
* @access public
*
* @param wchar_t* data The JSON text
*
* @return JSONValue* Returns a JSON Value representing the root, or NULL on error
*/
JSONValue *JSON::Parse(const wchar_t *data)
{
// Skip any preceding whitespace, end of data = no JSON = fail
if (!SkipWhitespace(&data))
return NULL;
// We need the start of a value here now...
JSONValue *value = JSONValue::Parse(&data);
if (value == NULL)
return NULL;
// Can be white space now and should be at the end of the string then...
if (SkipWhitespace(&data))
{
delete value;
return NULL;
}
// We're now at the end of the string
return value;
}
/**
* Turns the passed in JSONValue into a JSON encode string
*
* @access public
*
* @param JSONValue* value The root value
*
* @return std::wstring Returns a JSON encoded string representation of the given value
*/
std::wstring JSON::Stringify(const JSONValue *value)
{
if (value != NULL)
return value->Stringify();
else
return L"";
}
/**
* Skips over any whitespace characters (space, tab, \r or \n) defined by the JSON spec
*
* @access protected
*
* @param wchar_t** data Pointer to a wchar_t* that contains the JSON text
*
* @return bool Returns true if there is more data, or false if the end of the text was reached
*/
bool JSON::SkipWhitespace(const wchar_t **data)
{
while (**data != 0 && (**data == L' ' || **data == L'\t' || **data == L'\r' || **data == L'\n'))
(*data)++;
return **data != 0;
}
/**
* Extracts a JSON String as defined by the spec - "<some chars>"
* Any escaped characters are swapped out for their unescaped values
*
* @access protected
*
* @param wchar_t** data Pointer to a wchar_t* that contains the JSON text
* @param std::wstring& str Reference to a std::wstring to receive the extracted string
*
* @return bool Returns true on success, false on failure
*/
bool JSON::ExtractString(const wchar_t **data, std::wstring &str)
{
str = L"";
while (**data != 0)
{
// Save the char so we can change it if need be
wchar_t next_char = **data;
// Escaping something?
if (next_char == L'\\')
{
// Move over the escape char
(*data)++;
// Deal with the escaped char
switch (**data)
{
case L'"': next_char = L'"'; break;
case L'\\': next_char = L'\\'; break;
case L'/': next_char = L'/'; break;
case L'b': next_char = L'\b'; break;
case L'f': next_char = L'\f'; break;
case L'n': next_char = L'\n'; break;
case L'r': next_char = L'\r'; break;
case L't': next_char = L'\t'; break;
case L'u':
{
// We need 5 chars (4 hex + the 'u') or its not valid
if (!simplejson_wcsnlen(*data, 5))
return false;
// Deal with the chars
next_char = 0;
for (int i = 0; i < 4; i++)
{
// Do it first to move off the 'u' and leave us on the
// final hex digit as we move on by one later on
(*data)++;
next_char <<= 4;
// Parse the hex digit
if (**data >= '0' && **data <= '9')
next_char |= (**data - '0');
else if (**data >= 'A' && **data <= 'F')
next_char |= (10 + (**data - 'A'));
else if (**data >= 'a' && **data <= 'f')
next_char |= (10 + (**data - 'a'));
else
{
// Invalid hex digit = invalid JSON
return false;
}
}
break;
}
// By the spec, only the above cases are allowed
default:
return false;
}
}
// End of the string?
else if (next_char == L'"')
{
(*data)++;
str.reserve(); // Remove unused capacity
return true;
}
// Disallowed char?
else if (next_char < L' ' && next_char != L'\t')
{
// SPEC Violation: Allow tabs due to real world cases
return false;
}
// Add the next char
str += next_char;
// Move on
(*data)++;
}
// If we're here, the string ended incorrectly
return false;
}
/**
* Parses some text as though it is an integer
*
* @access protected
*
* @param wchar_t** data Pointer to a wchar_t* that contains the JSON text
*
* @return double Returns the double value of the number found
*/
double JSON::ParseInt(const wchar_t **data)
{
double integer = 0;
while (**data != 0 && **data >= '0' && **data <= '9')
integer = integer * 10 + (*(*data)++ - '0');
return integer;
}
/**
* Parses some text as though it is a decimal
*
* @access protected
*
* @param wchar_t** data Pointer to a wchar_t* that contains the JSON text
*
* @return double Returns the double value of the decimal found
*/
double JSON::ParseDecimal(const wchar_t **data)
{
double decimal = 0.0;
double factor = 0.1;
while (**data != 0 && **data >= '0' && **data <= '9')
{
int digit = (*(*data)++ - '0');
decimal = decimal + digit * factor;
factor *= 0.1;
}
return decimal;
}

View File

@ -0,0 +1,112 @@
/*
* File JSON.h part of the SimpleJSON Library - http://mjpa.in/json
*
* Copyright (C) 2010 Mike Anchor
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _JSON_H_
#define _JSON_H_
// Win32 incompatibilities
#if defined(WIN32) && !defined(__GNUC__)
#define wcsncasecmp _wcsnicmp
static inline bool isnan(double x) { return x != x; }
static inline bool isinf(double x) { return !isnan(x) && isnan(x - x); }
#endif
#include <vector>
#include <string>
#include <map>
// Linux compile fix - from quaker66
#ifdef __GNUC__
#include <cstring>
#include <cstdlib>
#endif
// Mac compile fixes - from quaker66, Lion fix by dabrahams
#if defined(__APPLE__) && __DARWIN_C_LEVEL < 200809L || (defined(WIN32) && defined(__GNUC__)) || defined(ANDROID)
#include <wctype.h>
#include <wchar.h>
static inline int wcsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n)
{
int lc1 = 0;
int lc2 = 0;
while (n--)
{
lc1 = towlower (*s1);
lc2 = towlower (*s2);
if (lc1 != lc2)
return (lc1 - lc2);
if (!lc1)
return 0;
++s1;
++s2;
}
return 0;
}
#endif
// Simple function to check a string 's' has at least 'n' characters
static inline bool simplejson_wcsnlen(const wchar_t *s, size_t n) {
if (s == 0)
return false;
const wchar_t *save = s;
while (n-- > 0)
{
if (*(save++) == 0) return false;
}
return true;
}
// Custom types
class JSONValue;
typedef std::vector<JSONValue*> JSONArray;
typedef std::map<std::wstring, JSONValue*> JSONObject;
#include "JSONValue.h"
class JSON
{
friend class JSONValue;
public:
static JSONValue* Parse(const char *data);
static JSONValue* Parse(const wchar_t *data);
static std::wstring Stringify(const JSONValue *value);
protected:
static bool SkipWhitespace(const wchar_t **data);
static bool ExtractString(const wchar_t **data, std::wstring &str);
static double ParseInt(const wchar_t **data);
static double ParseDecimal(const wchar_t **data);
private:
JSON();
};
#endif

View File

@ -0,0 +1,944 @@
/*
* File JSONValue.cpp part of the SimpleJSON Library - http://mjpa.in/json
*
* Copyright (C) 2010 Mike Anchor
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
#include <math.h>
#include "JSONValue.h"
#ifdef __MINGW32__
#define wcsncasecmp wcsnicmp
#endif
// Macros to free an array/object
#define FREE_ARRAY(x) { JSONArray::iterator iter; for (iter = x.begin(); iter != x.end(); iter++) { delete *iter; } }
#define FREE_OBJECT(x) { JSONObject::iterator iter; for (iter = x.begin(); iter != x.end(); iter++) { delete (*iter).second; } }
/**
* Parses a JSON encoded value to a JSONValue object
*
* @access protected
*
* @param wchar_t** data Pointer to a wchar_t* that contains the data
*
* @return JSONValue* Returns a pointer to a JSONValue object on success, NULL on error
*/
JSONValue *JSONValue::Parse(const wchar_t **data)
{
// Is it a string?
if (**data == '"')
{
std::wstring str;
if (!JSON::ExtractString(&(++(*data)), str))
return NULL;
else
return new JSONValue(str);
}
// Is it a boolean?
else if ((simplejson_wcsnlen(*data, 4) && wcsncasecmp(*data, L"true", 4) == 0) || (simplejson_wcsnlen(*data, 5) && wcsncasecmp(*data, L"false", 5) == 0))
{
bool value = wcsncasecmp(*data, L"true", 4) == 0;
(*data) += value ? 4 : 5;
return new JSONValue(value);
}
// Is it a null?
else if (simplejson_wcsnlen(*data, 4) && wcsncasecmp(*data, L"null", 4) == 0)
{
(*data) += 4;
return new JSONValue();
}
// Is it a number?
else if (**data == L'-' || (**data >= L'0' && **data <= L'9'))
{
// Negative?
bool neg = **data == L'-';
if (neg) (*data)++;
double number = 0.0;
// Parse the whole part of the number - only if it wasn't 0
if (**data == L'0')
(*data)++;
else if (**data >= L'1' && **data <= L'9')
number = JSON::ParseInt(data);
else
return NULL;
// Could be a decimal now...
if (**data == '.')
{
(*data)++;
// Not get any digits?
if (!(**data >= L'0' && **data <= L'9'))
return NULL;
// Find the decimal and sort the decimal place out
// Use ParseDecimal as ParseInt won't work with decimals less than 0.1
// thanks to Javier Abadia for the report & fix
double decimal = JSON::ParseDecimal(data);
// Save the number
number += decimal;
}
// Could be an exponent now...
if (**data == L'E' || **data == L'e')
{
(*data)++;
// Check signage of expo
bool neg_expo = false;
if (**data == L'-' || **data == L'+')
{
neg_expo = **data == L'-';
(*data)++;
}
// Not get any digits?
if (!(**data >= L'0' && **data <= L'9'))
return NULL;
// Sort the expo out
double expo = JSON::ParseInt(data);
for (double i = 0.0; i < expo; i++)
number = neg_expo ? (number / 10.0) : (number * 10.0);
}
// Was it neg?
if (neg) number *= -1;
return new JSONValue(number);
}
// An object?
else if (**data == L'{')
{
JSONObject object;
(*data)++;
while (**data != 0)
{
// Whitespace at the start?
if (!JSON::SkipWhitespace(data))
{
FREE_OBJECT(object);
return NULL;
}
// Special case - empty object
if (object.size() == 0 && **data == L'}')
{
(*data)++;
return new JSONValue(object);
}
// We want a string now...
std::wstring name;
if (!JSON::ExtractString(&(++(*data)), name))
{
FREE_OBJECT(object);
return NULL;
}
// More whitespace?
if (!JSON::SkipWhitespace(data))
{
FREE_OBJECT(object);
return NULL;
}
// Need a : now
if (*((*data)++) != L':')
{
FREE_OBJECT(object);
return NULL;
}
// More whitespace?
if (!JSON::SkipWhitespace(data))
{
FREE_OBJECT(object);
return NULL;
}
// The value is here
JSONValue *value = Parse(data);
if (value == NULL)
{
FREE_OBJECT(object);
return NULL;
}
// Add the name:value
if (object.find(name) != object.end())
delete object[name];
object[name] = value;
// More whitespace?
if (!JSON::SkipWhitespace(data))
{
FREE_OBJECT(object);
return NULL;
}
// End of object?
if (**data == L'}')
{
(*data)++;
return new JSONValue(object);
}
// Want a , now
if (**data != L',')
{
FREE_OBJECT(object);
return NULL;
}
(*data)++;
}
// Only here if we ran out of data
FREE_OBJECT(object);
return NULL;
}
// An array?
else if (**data == L'[')
{
JSONArray array;
(*data)++;
while (**data != 0)
{
// Whitespace at the start?
if (!JSON::SkipWhitespace(data))
{
FREE_ARRAY(array);
return NULL;
}
// Special case - empty array
if (array.size() == 0 && **data == L']')
{
(*data)++;
return new JSONValue(array);
}
// Get the value
JSONValue *value = Parse(data);
if (value == NULL)
{
FREE_ARRAY(array);
return NULL;
}
// Add the value
array.push_back(value);
// More whitespace?
if (!JSON::SkipWhitespace(data))
{
FREE_ARRAY(array);
return NULL;
}
// End of array?
if (**data == L']')
{
(*data)++;
return new JSONValue(array);
}
// Want a , now
if (**data != L',')
{
FREE_ARRAY(array);
return NULL;
}
(*data)++;
}
// Only here if we ran out of data
FREE_ARRAY(array);
return NULL;
}
// Ran out of possibilites, it's bad!
else
{
return NULL;
}
}
/**
* Basic constructor for creating a JSON Value of type NULL
*
* @access public
*/
JSONValue::JSONValue(/*NULL*/)
{
type = JSONType_Null;
}
/**
* Basic constructor for creating a JSON Value of type String
*
* @access public
*
* @param wchar_t* m_char_value The string to use as the value
*/
JSONValue::JSONValue(const wchar_t *m_char_value)
{
type = JSONType_String;
string_value = new std::wstring(std::wstring(m_char_value));
}
/**
* Basic constructor for creating a JSON Value of type String
*
* @access public
*
* @param std::wstring m_string_value The string to use as the value
*/
JSONValue::JSONValue(const std::wstring &m_string_value)
{
type = JSONType_String;
string_value = new std::wstring(m_string_value);
}
/**
* Basic constructor for creating a JSON Value of type Bool
*
* @access public
*
* @param bool m_bool_value The bool to use as the value
*/
JSONValue::JSONValue(bool m_bool_value)
{
type = JSONType_Bool;
bool_value = m_bool_value;
}
/**
* Basic constructor for creating a JSON Value of type Number
*
* @access public
*
* @param double m_number_value The number to use as the value
*/
JSONValue::JSONValue(double m_number_value)
{
type = JSONType_Number;
number_value = m_number_value;
}
/**
* Basic constructor for creating a JSON Value of type Number
*
* @access public
*
* @param int m_integer_value The number to use as the value
*/
JSONValue::JSONValue(int m_integer_value)
{
type = JSONType_Number;
number_value = (double) m_integer_value;
}
/**
* Basic constructor for creating a JSON Value of type Array
*
* @access public
*
* @param JSONArray m_array_value The JSONArray to use as the value
*/
JSONValue::JSONValue(const JSONArray &m_array_value)
{
type = JSONType_Array;
array_value = new JSONArray(m_array_value);
}
/**
* Basic constructor for creating a JSON Value of type Object
*
* @access public
*
* @param JSONObject m_object_value The JSONObject to use as the value
*/
JSONValue::JSONValue(const JSONObject &m_object_value)
{
type = JSONType_Object;
object_value = new JSONObject(m_object_value);
}
/**
* Copy constructor to perform a deep copy of array / object values
*
* @access public
*
* @param JSONValue m_source The source JSONValue that is being copied
*/
JSONValue::JSONValue(const JSONValue &m_source)
{
type = m_source.type;
switch (type)
{
case JSONType_String:
string_value = new std::wstring(*m_source.string_value);
break;
case JSONType_Bool:
bool_value = m_source.bool_value;
break;
case JSONType_Number:
number_value = m_source.number_value;
break;
case JSONType_Array:
{
JSONArray source_array = *m_source.array_value;
JSONArray::iterator iter;
array_value = new JSONArray();
for (iter = source_array.begin(); iter != source_array.end(); iter++)
array_value->push_back(new JSONValue(**iter));
break;
}
case JSONType_Object:
{
JSONObject source_object = *m_source.object_value;
object_value = new JSONObject();
JSONObject::iterator iter;
for (iter = source_object.begin(); iter != source_object.end(); iter++)
{
std::wstring name = (*iter).first;
(*object_value)[name] = new JSONValue(*((*iter).second));
}
break;
}
case JSONType_Null:
// Nothing to do.
break;
}
}
/**
* The destructor for the JSON Value object
* Handles deleting the objects in the array or the object value
*
* @access public
*/
JSONValue::~JSONValue()
{
if (type == JSONType_Array)
{
JSONArray::iterator iter;
for (iter = array_value->begin(); iter != array_value->end(); iter++)
delete *iter;
delete array_value;
}
else if (type == JSONType_Object)
{
JSONObject::iterator iter;
for (iter = object_value->begin(); iter != object_value->end(); iter++)
{
delete (*iter).second;
}
delete object_value;
}
else if (type == JSONType_String)
{
delete string_value;
}
}
/**
* Checks if the value is a NULL
*
* @access public
*
* @return bool Returns true if it is a NULL value, false otherwise
*/
bool JSONValue::IsNull() const
{
return type == JSONType_Null;
}
/**
* Checks if the value is a String
*
* @access public
*
* @return bool Returns true if it is a String value, false otherwise
*/
bool JSONValue::IsString() const
{
return type == JSONType_String;
}
/**
* Checks if the value is a Bool
*
* @access public
*
* @return bool Returns true if it is a Bool value, false otherwise
*/
bool JSONValue::IsBool() const
{
return type == JSONType_Bool;
}
/**
* Checks if the value is a Number
*
* @access public
*
* @return bool Returns true if it is a Number value, false otherwise
*/
bool JSONValue::IsNumber() const
{
return type == JSONType_Number;
}
/**
* Checks if the value is an Array
*
* @access public
*
* @return bool Returns true if it is an Array value, false otherwise
*/
bool JSONValue::IsArray() const
{
return type == JSONType_Array;
}
/**
* Checks if the value is an Object
*
* @access public
*
* @return bool Returns true if it is an Object value, false otherwise
*/
bool JSONValue::IsObject() const
{
return type == JSONType_Object;
}
/**
* Retrieves the String value of this JSONValue
* Use IsString() before using this method.
*
* @access public
*
* @return std::wstring Returns the string value
*/
const std::wstring &JSONValue::AsString() const
{
return (*string_value);
}
/**
* Retrieves the Bool value of this JSONValue
* Use IsBool() before using this method.
*
* @access public
*
* @return bool Returns the bool value
*/
bool JSONValue::AsBool() const
{
return bool_value;
}
/**
* Retrieves the Number value of this JSONValue
* Use IsNumber() before using this method.
*
* @access public
*
* @return double Returns the number value
*/
double JSONValue::AsNumber() const
{
return number_value;
}
/**
* Retrieves the Array value of this JSONValue
* Use IsArray() before using this method.
*
* @access public
*
* @return JSONArray Returns the array value
*/
const JSONArray &JSONValue::AsArray() const
{
return (*array_value);
}
/**
* Retrieves the Object value of this JSONValue
* Use IsObject() before using this method.
*
* @access public
*
* @return JSONObject Returns the object value
*/
const JSONObject &JSONValue::AsObject() const
{
return (*object_value);
}
/**
* Retrieves the number of children of this JSONValue.
* This number will be 0 or the actual number of children
* if IsArray() or IsObject().
*
* @access public
*
* @return The number of children.
*/
std::size_t JSONValue::CountChildren() const
{
switch (type)
{
case JSONType_Array:
return array_value->size();
case JSONType_Object:
return object_value->size();
default:
return 0;
}
}
/**
* Checks if this JSONValue has a child at the given index.
* Use IsArray() before using this method.
*
* @access public
*
* @return bool Returns true if the array has a value at the given index.
*/
bool JSONValue::HasChild(std::size_t index) const
{
if (type == JSONType_Array)
{
return index < array_value->size();
}
else
{
return false;
}
}
/**
* Retrieves the child of this JSONValue at the given index.
* Use IsArray() before using this method.
*
* @access public
*
* @return JSONValue* Returns JSONValue at the given index or NULL
* if it doesn't exist.
*/
JSONValue *JSONValue::Child(std::size_t index)
{
if (index < array_value->size())
{
return (*array_value)[index];
}
else
{
return NULL;
}
}
/**
* Checks if this JSONValue has a child at the given key.
* Use IsObject() before using this method.
*
* @access public
*
* @return bool Returns true if the object has a value at the given key.
*/
bool JSONValue::HasChild(const wchar_t* name) const
{
if (type == JSONType_Object)
{
return object_value->find(name) != object_value->end();
}
else
{
return false;
}
}
/**
* Retrieves the child of this JSONValue at the given key.
* Use IsObject() before using this method.
*
* @access public
*
* @return JSONValue* Returns JSONValue for the given key in the object
* or NULL if it doesn't exist.
*/
JSONValue* JSONValue::Child(const wchar_t* name)
{
JSONObject::const_iterator it = object_value->find(name);
if (it != object_value->end())
{
return it->second;
}
else
{
return NULL;
}
}
/**
* Retrieves the keys of the JSON Object or an empty vector
* if this value is not an object.
*
* @access public
*
* @return std::vector<std::wstring> A vector containing the keys.
*/
std::vector<std::wstring> JSONValue::ObjectKeys() const
{
std::vector<std::wstring> keys;
if (type == JSONType_Object)
{
JSONObject::const_iterator iter = object_value->begin();
while (iter != object_value->end())
{
keys.push_back(iter->first);
iter++;
}
}
return keys;
}
/**
* Creates a JSON encoded string for the value with all necessary characters escaped
*
* @access public
*
* @param bool prettyprint Enable prettyprint
*
* @return std::wstring Returns the JSON string
*/
std::wstring JSONValue::Stringify(bool const prettyprint) const
{
size_t const indentDepth = prettyprint ? 1 : 0;
return StringifyImpl(indentDepth);
}
/**
* Creates a JSON encoded string for the value with all necessary characters escaped
*
* @access private
*
* @param size_t indentDepth The prettyprint indentation depth (0 : no prettyprint)
*
* @return std::wstring Returns the JSON string
*/
std::wstring JSONValue::StringifyImpl(size_t const indentDepth) const
{
std::wstring ret_string;
size_t const indentDepth1 = indentDepth ? indentDepth + 1 : 0;
std::wstring const indentStr = Indent(indentDepth);
std::wstring const indentStr1 = Indent(indentDepth1);
switch (type)
{
case JSONType_Null:
ret_string = L"null";
break;
case JSONType_String:
ret_string = StringifyString(*string_value);
break;
case JSONType_Bool:
ret_string = bool_value ? L"true" : L"false";
break;
case JSONType_Number:
{
if (isinf(number_value) || isnan(number_value))
ret_string = L"null";
else
{
std::wstringstream ss;
ss.precision(15);
ss << number_value;
ret_string = ss.str();
}
break;
}
case JSONType_Array:
{
ret_string = indentDepth ? L"[\n" + indentStr1 : L"[";
JSONArray::const_iterator iter = array_value->begin();
while (iter != array_value->end())
{
ret_string += (*iter)->StringifyImpl(indentDepth1);
// Not at the end - add a separator
if (++iter != array_value->end())
ret_string += L",";
}
ret_string += indentDepth ? L"\n" + indentStr + L"]" : L"]";
break;
}
case JSONType_Object:
{
ret_string = indentDepth ? L"{\n" + indentStr1 : L"{";
JSONObject::const_iterator iter = object_value->begin();
while (iter != object_value->end())
{
ret_string += StringifyString((*iter).first);
ret_string += L":";
ret_string += (*iter).second->StringifyImpl(indentDepth1);
// Not at the end - add a separator
if (++iter != object_value->end())
ret_string += L",";
}
ret_string += indentDepth ? L"\n" + indentStr + L"}" : L"}";
break;
}
}
return ret_string;
}
/**
* Creates a JSON encoded string with all required fields escaped
* Works from http://www.ecma-internationl.org/publications/files/ECMA-ST/ECMA-262.pdf
* Section 15.12.3.
*
* @access private
*
* @param std::wstring str The string that needs to have the characters escaped
*
* @return std::wstring Returns the JSON string
*/
std::wstring JSONValue::StringifyString(const std::wstring &str)
{
std::wstring str_out = L"\"";
std::wstring::const_iterator iter = str.begin();
while (iter != str.end())
{
wchar_t chr = *iter;
if (chr == L'"' || chr == L'\\' || chr == L'/')
{
str_out += L'\\';
str_out += chr;
}
else if (chr == L'\b')
{
str_out += L"\\b";
}
else if (chr == L'\f')
{
str_out += L"\\f";
}
else if (chr == L'\n')
{
str_out += L"\\n";
}
else if (chr == L'\r')
{
str_out += L"\\r";
}
else if (chr == L'\t')
{
str_out += L"\\t";
}
else if (chr < L' ' || chr > 126)
{
str_out += L"\\u";
for (int i = 0; i < 4; i++)
{
int value = (chr >> 12) & 0xf;
if (value >= 0 && value <= 9)
str_out += (wchar_t)('0' + value);
else if (value >= 10 && value <= 15)
str_out += (wchar_t)('A' + (value - 10));
chr <<= 4;
}
}
else
{
str_out += chr;
}
iter++;
}
str_out += L"\"";
return str_out;
}
/**
* Creates the indentation string for the depth given
*
* @access private
*
* @param size_t indent The prettyprint indentation depth (0 : no indentation)
*
* @return std::wstring Returns the string
*/
std::wstring JSONValue::Indent(size_t depth)
{
const size_t indent_step = 2;
depth ? --depth : 0;
std::wstring indentStr(depth * indent_step, ' ');
return indentStr;
}

View File

@ -0,0 +1,95 @@
/*
* File JSONValue.h part of the SimpleJSON Library - http://mjpa.in/json
*
* Copyright (C) 2010 Mike Anchor
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef _JSONVALUE_H_
#define _JSONVALUE_H_
#include <vector>
#include <string>
#include "JSON.h"
class JSON;
enum JSONType { JSONType_Null, JSONType_String, JSONType_Bool, JSONType_Number, JSONType_Array, JSONType_Object };
class JSONValue
{
friend class JSON;
public:
JSONValue(/*NULL*/);
JSONValue(const wchar_t *m_char_value);
JSONValue(const std::wstring &m_string_value);
JSONValue(bool m_bool_value);
JSONValue(double m_number_value);
JSONValue(int m_integer_value);
JSONValue(const JSONArray &m_array_value);
JSONValue(const JSONObject &m_object_value);
JSONValue(const JSONValue &m_source);
~JSONValue();
bool IsNull() const;
bool IsString() const;
bool IsBool() const;
bool IsNumber() const;
bool IsArray() const;
bool IsObject() const;
const std::wstring &AsString() const;
bool AsBool() const;
double AsNumber() const;
const JSONArray &AsArray() const;
const JSONObject &AsObject() const;
std::size_t CountChildren() const;
bool HasChild(std::size_t index) const;
JSONValue *Child(std::size_t index);
bool HasChild(const wchar_t* name) const;
JSONValue *Child(const wchar_t* name);
std::vector<std::wstring> ObjectKeys() const;
std::wstring Stringify(bool const prettyprint = false) const;
protected:
static JSONValue *Parse(const wchar_t **data);
private:
static std::wstring StringifyString(const std::wstring &str);
std::wstring StringifyImpl(size_t const indentDepth) const;
static std::wstring Indent(size_t depth);
JSONType type;
union
{
bool bool_value;
double number_value;
std::wstring *string_value;
JSONArray *array_value;
JSONObject *object_value;
};
};
#endif

View File

@ -49,10 +49,23 @@ ULONG DriverAssist::StartDriverAsync(void *arg)
// get windows version
//
OSVERSIONINFO osvi;
OSVERSIONINFOW osvi;
memzero(&osvi, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOW);
*(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetVersion");
if (RtlGetVersion == NULL || !NT_SUCCESS(RtlGetVersion(&osvi)))
GetVersionExW(&osvi);
//
// get own path
//
WCHAR svcPath[MAX_PATH] = { 0 };
GetModuleFileName(NULL, svcPath, MAX_PATH);
WCHAR* pathPtr = wcsrchr(svcPath, L'\\');
if (pathPtr++)
*pathPtr = L'\0';
//
// start the driver, but only if it isn't already active
@ -76,46 +89,132 @@ ULONG DriverAssist::StartDriverAsync(void *arg)
L"\\Registry\\Machine\\System\\CurrentControlSet"
L"\\Services\\" SBIEDRV);
rc = NtLoadDriver(&uni);
if (rc == 0 || rc == STATUS_IMAGE_ALREADY_LOADED) {
ok = true;
goto driver_started;
}
//while (!IsDebuggerPresent())
// Sleep(100);
if (rc != STATUS_PRIVILEGE_NOT_HELD || rc == STATUS_ACCESS_DENIED) {
LogEvent(MSG_9234, 0x9153, rc);
goto driver_started;
}
m_instance->LogMessage_Single(MSG_2201, L"Starting Driver...");
//
// we have to enable a privilege to load the driver
//
bool PrivilegeSet = false;
bool CopyDriver = false;
bool DriverUnPacked = false;
for (; ; ) //for (int i = 0; i < 10; i++)
{
m_instance->LogMessage_Single(MSG_2201, L"Attempting to Load Driver...");
WCHAR priv_space[64];
TOKEN_PRIVILEGES *privs = (TOKEN_PRIVILEGES *)priv_space;
HANDLE hToken;
rc = NtLoadDriver(&uni);
if (rc == 0 || rc == STATUS_IMAGE_ALREADY_LOADED) {
ok = true;
break;
}
BOOL b = LookupPrivilegeValue(
L"", SE_LOAD_DRIVER_NAME, &privs->Privileges[0].Luid);
if (b) {
if (rc == STATUS_PRIVILEGE_NOT_HELD && !PrivilegeSet)
{
m_instance->LogMessage_Single(MSG_2201, L"Acquiring necessary privileges...");
privs->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
privs->PrivilegeCount = 1;
//
// we have to enable a privilege to load the driver
//
b = OpenProcessToken(
GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
if (b) {
WCHAR priv_space[64];
TOKEN_PRIVILEGES *privs = (TOKEN_PRIVILEGES *)priv_space;
HANDLE hToken;
b = AdjustTokenPrivileges(hToken, FALSE, privs, 0, NULL, NULL);
CloseHandle(hToken);
}
}
BOOL b = LookupPrivilegeValue(
L"", SE_LOAD_DRIVER_NAME, &privs->Privileges[0].Luid);
if (b) {
rc = NtLoadDriver(&uni);
if (rc == 0 || rc == STATUS_IMAGE_ALREADY_LOADED)
ok = true;
else
LogEvent(MSG_9234, 0x9153, rc);
privs->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
privs->PrivilegeCount = 1;
b = OpenProcessToken(
GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
if (b) {
b = AdjustTokenPrivileges(hToken, FALSE, privs, 0, NULL, NULL);
CloseHandle(hToken);
}
}
PrivilegeSet = true;
continue;
}
/*if (rc == STATUS_OBJECT_NAME_NOT_FOUND && DriverUnPacked)
{
m_instance->LogMessage_Single(MSG_2201, L"The provisionally driver got deleted...");
//
// The provisionally signed driver got deleted, try to restore it
//
DriverUnPacked = false;
rc == STATUS_INVALID_IMAGE_HASH;
}*/
if (rc == STATUS_OBJECT_NAME_NOT_FOUND && !CopyDriver)
{
m_instance->LogMessage_Single(MSG_2201, L"Preparing the windows 10 signed driver...");
//
// there is no driver file we have to prepare one
//
WCHAR srcPath[MAX_PATH];
wcscpy(srcPath, svcPath);
wcscat(srcPath, SBIEDRV_SYS L".w10");
WCHAR destPath[MAX_PATH];
wcscpy(destPath, svcPath);
wcscat(destPath, SBIEDRV_SYS);
CopyFile(srcPath, destPath, FALSE);
CopyDriver = true;
continue;
}
if (rc == STATUS_INVALID_IMAGE_HASH && !DriverUnPacked)
{
m_instance->LogMessage_Single(MSG_2201, L"Preparing the provisionally signed driver...");
//
// the driver signature was not accepted, try the provisionally signed driver
//
WCHAR cmd[512];
wcscpy(cmd, L"\"");
wcscat(cmd, svcPath);
wcscat(cmd, L"KmdUtil.exe");
wcscat(cmd, L"\" rc4 \"");
wcscat(cmd, svcPath);
wcscat(cmd, SBIEDRV_SYS L".rc4");
wcscat(cmd, L"\"");
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_FORCEOFFFEEDBACK;
PROCESS_INFORMATION pi;
if (CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
WaitForSingleObject(pi.hProcess, 10 * 1000);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
DriverUnPacked = true;
continue;
}
//
// we tryed all we could, log an error and break
//
LogEvent(MSG_9234, 0x9153, rc);
break;
}
//
// the driver has been started (or was started already), check

View File

@ -1,5 +1,6 @@
/*
* Copyright 2004-2020 Sandboxie Holdings, LLC
* Copyright 2020 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -32,6 +33,7 @@
#include <sddl.h>
#include <aclapi.h>
#include <dde.h>
#include "misc.h"
#define PATTERN XPATTERN
extern "C" {
@ -87,9 +89,14 @@ GuiServer::GuiServer()
m_ParentPid = 0;
m_SessionId = 0;
OSVERSIONINFO osvi = { 0 };
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
OSVERSIONINFOW osvi = { 0 };
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
/*NTSTATUS(WINAPI *RtlGetVersion)(LPOSVERSIONINFOW);
*(FARPROC*)&RtlGetVersion = GetProcAddress(_Ntdll, "RtlGetVersion");
if (RtlGetVersion != NULL)
RtlGetVersion(&osvi);
else*/
GetVersionExW(&osvi); // since windows 10 this one is lying
m_nOSVersion = osvi.dwMajorVersion * 10 + osvi.dwMinorVersion;
}
@ -999,6 +1006,16 @@ HANDLE GuiServer::GetJobObjectForAssign(const WCHAR *boxname)
| JOB_OBJECT_UILIMIT_READCLIPBOARD;
BOOL ok = FALSE; // set TRUE to skip UIRestrictions
// OpenToken BEGIN
if ((SbieApi_QueryConfBool(boxname, L"OpenToken", FALSE) || SbieApi_QueryConfBool(boxname, L"UnrestrictedToken", FALSE)))
ok = TRUE;
// OpenToken END
// OriginalToken BEGIN
if (SbieApi_QueryConfBool(boxname, L"OriginalToken", FALSE))
ok = TRUE;
// OriginalToken END
if (! ok) {
ok = SetInformationJobObject(
hJobObject, JobObjectBasicUIRestrictions,

View File

@ -38,6 +38,7 @@ SetCompressor /SOLID /FINAL lzma
!define BIN_ROOT_BASE "${SBIE_INSTALLER_PATH}"
!define SBIEDRV_SYS4 "${SBIEDRV_SYS}.rc4"
!define SBIEDRV_SYSX "${SBIEDRV_SYS}.w10"
!define OUTFILE_BOTH "${PRODUCT_NAME}Install.exe"
!define NAME_Win32 "${PRODUCT_FULL_NAME} ${VERSION} (32-bit)"
@ -431,7 +432,7 @@ InstDir_Check_Suffix:
Push -12
Pop $2
StrCpy $1 $0 "" $2
StrCmp $1 "\${SBIEDRV_SYS4}" InstDir_Suffix_Good
StrCmp $1 "\${SBIEDRV_SYS}" InstDir_Suffix_Good
Goto InstDir_ProgramFiles
@ -466,7 +467,7 @@ InstDir_Done:
StrCmp "$EXEDIR" "$WINDIR\Installer\" InstType_Remove
StrCmp "$EXEDIR\" "$WINDIR\Installer" InstType_Remove
IfFileExists $INSTDIR\${SBIEDRV_SYS4} InstType_Upgrade
IfFileExists $INSTDIR\${SBIEDRV_SYS} InstType_Upgrade
IfFileExists $INSTDIR\${SBIESVC_EXE} InstType_Upgrade
IfFileExists $INSTDIR\${SBIEDLL_DLL} InstType_Upgrade
@ -971,6 +972,9 @@ WriteLoop:
File /oname=${SBIEMSG_DLL} "${BIN_ROOT}\SbieMsg.dll"
File /oname=${SBIEDRV_SYS4} "${BIN_ROOT}\SbieDrv.sys.rc4"
File /oname=${SBIEDRV_SYSX} "${BIN_ROOT}\SbieDrv.sys.w10"
File /oname=KmdUtil.exe "${BIN_ROOT}\KmdUtil.Exe"
File /oname=SboxHostDll.dll "${BIN_ROOT}\SboxHostDll.dll"
@ -1075,7 +1079,13 @@ Function DeleteProgramFiles
Delete "$INSTDIR\${SBIEMSG_DLL}"
Delete "$INSTDIR\${SBIEDRV_SYS}"
Delete "$INSTDIR\${SBIEDRV_SYS4}"
Delete "$INSTDIR\${SBIEDRV_SYSX}"
Delete "$INSTDIR\KmdUtil.exe"
Delete "$INSTDIR\boxHostDll.dll"
Delete "$INSTDIR\${SANDBOXIE}WUAU.exe"
Delete "$INSTDIR\${SANDBOXIE}EventSys.exe"
@ -1425,7 +1435,7 @@ Driver_Silent:
; For Install and Upgrade, install the driver
;
StrCpy $0 'install ${SBIEDRV} "$INSTDIR\${SBIEDRV_SYS4}" type=kernel start=demand "msgfile=$INSTDIR\${SBIEMSG_DLL}" altitude=${FILTER_ALTITUDE}'
StrCpy $0 'install ${SBIEDRV} "$INSTDIR\${SBIEDRV_SYS}" type=kernel start=demand "msgfile=$INSTDIR\${SBIEMSG_DLL}" altitude=${FILTER_ALTITUDE}'
Push $0
Call KmdUtil

View File

@ -42,7 +42,8 @@ typedef enum _COMMAND {
CMD_START,
CMD_STOP,
CMD_SCANDLL,
CMD_SCANDLL_SILENT
CMD_SCANDLL_SILENT,
CMD_RC4
} COMMAND;
typedef enum _OPTIONS {
@ -219,7 +220,11 @@ BOOL Parse_Command_Line(
*Command = CMD_STOP;
num_args_needed = 1;
} else {
} else if (_wcsicmp(args[1], L"rc4") == 0) {
*Command = CMD_RC4;
num_args_needed = 1;
} else {
*Command = CMD_ERROR;
MessageBox(NULL, L"Invalid command", L"KmdUtil",
MB_ICONEXCLAMATION | MB_OK);
@ -238,6 +243,11 @@ BOOL Parse_Command_Line(
if (num_args_needed >= 2)
*Driver_Path = args[3];
if (*Command == CMD_RC4) {
*Driver_Path = *Driver_Name;
*Driver_Name = NULL;
}
*Options = OPT_NONE;
next_arg = num_args_needed + 2;
while (next_arg < num_args_given) {
@ -716,41 +726,46 @@ int __stdcall WinMain(
&Options))
return EXIT_FAILURE;
if (Driver_Path)
if (Command == CMD_RC4)
{
int path_len = wcslen(Driver_Path);
if (path_len > 8 && wcscmp(Driver_Path + path_len - 8, L".sys.rc4") == 0)
BOOLEAN has_rc4 = path_len > 8 && wcscmp(Driver_Path + path_len - 8, L".sys.rc4") == 0;
PWSTR Driver_Path_tmp = Driver_Path; // strip \??\ if present
if (Driver_Path_tmp[0] == L'\\' && Driver_Path_tmp[1] == L'?' && Driver_Path_tmp[2] == L'?' && Driver_Path_tmp[3] == L'\\')
Driver_Path_tmp += 4;
FILE* inFile = _wfopen(Driver_Path_tmp, L"rb");
if (inFile)
{
PWSTR Driver_Path_tmp = Driver_Path; // strip \??\ if present
if (Driver_Path_tmp[0] == L'\\' && Driver_Path_tmp[1] == L'?' && Driver_Path_tmp[2] == L'?' && Driver_Path_tmp[3] == L'\\')
Driver_Path_tmp += 4;
FILE* inFile = _wfopen(Driver_Path_tmp, L"rb");
if (inFile)
{
if (has_rc4)
Driver_Path_tmp[path_len - 4] = L'\0'; // strip .rc4
FILE* outFile = _wfopen(Driver_Path_tmp, L"wb");
if (outFile)
{
fseek(inFile, 0, SEEK_END);
DWORD fileSize = ftell(inFile);
fseek(inFile, 0, SEEK_SET);
else
wcscat(Driver_Path_tmp, L".rc4"); // add .rc4
FILE* outFile = _wfopen(Driver_Path_tmp, L"wb");
if (outFile)
{
fseek(inFile, 0, SEEK_END);
DWORD fileSize = ftell(inFile);
fseek(inFile, 0, SEEK_SET);
void* buffer = HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, fileSize);
fread(buffer, 1, fileSize, inFile);
void* buffer = HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, fileSize);
fread(buffer, 1, fileSize, inFile);
char key[] = "default_key";
rc4_sbox_t sbox;
rc4_init(&sbox, key, strlen(key));
rc4_transform(&sbox, buffer, fileSize);
char key[] = "default_key";
rc4_sbox_t sbox;
rc4_init(&sbox, key, strlen(key));
rc4_transform(&sbox, buffer, fileSize);
fwrite(buffer, 1, fileSize, outFile);
if(fwrite(buffer, 1, fileSize, outFile) == fileSize)
ok = TRUE;
fclose(outFile);
}
fclose(inFile);
fclose(outFile);
}
fclose(inFile);
}
goto exit;
}
ScMgr = OpenSCManager(
@ -795,6 +810,7 @@ int __stdcall WinMain(
if (Command == CMD_STOP)
ok = Kmd_Stop_Service(Driver_Name);
exit:
if (! ok)
return EXIT_FAILURE;

Binary file not shown.

View File

@ -138,6 +138,18 @@ void CCheckableMessageBox::setIconPixmap(const QPixmap &p)
d->pixmapLabel->setVisible(!p.isNull());
}
Qt::TextFormat CCheckableMessageBox::textFormat() const
{
return d->messageLabel->textFormat();
}
void CCheckableMessageBox::setTextFormat(Qt::TextFormat format)
{
d->messageLabel->setTextFormat(format);
d->messageLabel->setWordWrap(format == Qt::RichText
|| (format == Qt::AutoText && Qt::mightBeRichText(d->messageLabel->text())));
}
bool CCheckableMessageBox::isChecked() const
{
return d->checkBox->isChecked();

View File

@ -12,6 +12,7 @@ class MISCHELPERS_EXPORT CCheckableMessageBox : public QDialog
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText)
Q_PROPERTY(Qt::TextFormat textFormat READ textFormat WRITE setTextFormat)
Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap)
Q_PROPERTY(bool isChecked READ isChecked WRITE setChecked)
Q_PROPERTY(QString checkBoxText READ checkBoxText WRITE setCheckBoxText)
@ -35,6 +36,9 @@ public:
QString text() const;
void setText(const QString &);
Qt::TextFormat textFormat() const;
void setTextFormat(Qt::TextFormat format);
bool isChecked() const;
void setChecked(bool s);

View File

@ -0,0 +1,76 @@
#include "stdafx.h"
#include "NetworkAccessManager.h"
#include "Common.h"
CNetworkAccessManager::CNetworkAccessManager(int TimeOut, QObject* parent)
:QNetworkAccessManager(parent)
{
m_TimeOut = TimeOut;
connect(this, SIGNAL(finished(QNetworkReply*)), this, SLOT(finishedRequest(QNetworkReply*)));
#ifndef QT_NO_OPENSSL
connect(this, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(sslErrors(QNetworkReply*, const QList<QSslError>&)));
#endif
m_uTimerID = startTimer(1000);
}
CNetworkAccessManager::~CNetworkAccessManager()
{
killTimer(m_uTimerID);
}
void CNetworkAccessManager::timerEvent(QTimerEvent* pEvent)
{
if (pEvent->timerId() != m_uTimerID)
return;
foreach(QNetworkReply *pReply, m_Requests.keys())
{
if(m_Requests[pReply] < GetCurTick())
pReply->abort();
}
}
void CNetworkAccessManager::SetTimeOut(QNetworkReply *pReply)
{
m_Requests[pReply] = GetCurTick() + m_TimeOut;
}
void CNetworkAccessManager::StopTimeOut(QNetworkReply *pReply)
{
m_Requests.remove(pReply);
}
void CNetworkAccessManager::Abort(QNetworkReply *pReply)
{
pReply->abort();
StopTimeOut(pReply);
pReply->deleteLater();
}
QNetworkReply* CNetworkAccessManager::createRequest ( Operation op, const QNetworkRequest & req, QIODevice * outgoingData )
{
QNetworkReply* pReply = QNetworkAccessManager::createRequest(op, req, outgoingData);
connect(pReply, SIGNAL(downloadProgress (qint64, qint64)), this, SLOT(OnData(qint64, qint64)));
connect(pReply, SIGNAL(uploadProgress (qint64, qint64)), this, SLOT(OnData(qint64, qint64)));
SetTimeOut(pReply);
return pReply;
}
void CNetworkAccessManager::finishedRequest(QNetworkReply *pReply)
{
StopTimeOut(pReply);
}
void CNetworkAccessManager::OnData(qint64 bytesSent, qint64 bytesTotal)
{
// Reset TimeOut, as long as data are being transferred its not a timeout
SetTimeOut((QNetworkReply*)sender());
}
#ifndef QT_NO_OPENSSL
void CNetworkAccessManager::sslErrors(QNetworkReply *pReply, const QList<QSslError> &error)
{
//pReply->ignoreSslErrors();
}
#endif

View File

@ -0,0 +1,34 @@
#pragma once
#include "../mischelpers_global.h"
#include <QNetworkAccessManager>
class MISCHELPERS_EXPORT CNetworkAccessManager : public QNetworkAccessManager
{
Q_OBJECT
public:
CNetworkAccessManager(int TimeOut, QObject* parent = NULL);
~CNetworkAccessManager();
void Abort(QNetworkReply* pReply);
private slots:
void finishedRequest(QNetworkReply *pReply);
void OnData(qint64 bytesSent, qint64 bytesTotal);
#ifndef QT_NO_OPENSSL
void sslErrors(QNetworkReply *pReply, const QList<QSslError> &error);
#endif
protected:
void timerEvent(QTimerEvent* pEvent);
int m_uTimerID;
QNetworkReply* createRequest ( Operation op, const QNetworkRequest & req, QIODevice * outgoingData = 0 );
void SetTimeOut(QNetworkReply *pReply);
void StopTimeOut(QNetworkReply *pReply);
int m_TimeOut;
QMap<QNetworkReply*, quint64> m_Requests;
};

View File

@ -57,12 +57,12 @@ public slots:
if (Progress == -1)
{
if (m_pProgressBar->maximum() != 0)
m_pProgressBar->setMinimum(0);
m_pProgressBar->setMaximum(0);
}
else
{
if (m_pProgressBar->maximum() != 100)
m_pProgressBar->setMinimum(100);
m_pProgressBar->setMaximum(100);
m_pProgressBar->setValue(Progress);
}

View File

@ -191,6 +191,7 @@
<ClCompile Include="Common\MultiLineInputDialog.cpp" />
<ClCompile Include="Common\PanelView.cpp" />
<ClCompile Include="Common\qRC4.cpp" />
<ClCompile Include="Common\NetworkAccessManager.cpp" />
<ClCompile Include="Common\Settings.cpp" />
<ClCompile Include="Common\SettingsWidgets.cpp" />
<ClCompile Include="Common\SmartGridWidget.cpp" />
@ -233,6 +234,7 @@
<QtMoc Include="Common\TreeWidgetEx.h" />
<ClInclude Include="Common\IconExtreactor.h" />
<ClInclude Include="Common\qRC4.h" />
<QtMoc Include="Common\NetworkAccessManager.h" />
<ClInclude Include="Common\Xml.h" />
<ClInclude Include="MiscHelpers.h" />
<ClInclude Include="mischelpers_global.h" />

View File

@ -90,6 +90,9 @@
<ClCompile Include="Common\qRC4.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\NetworkAccessManager.cpp">
<Filter>Common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="MiscHelpers.h">
@ -186,5 +189,8 @@
<QtMoc Include="Common\TreeWidgetEx.h">
<Filter>Common</Filter>
</QtMoc>
<QtMoc Include="Common\NetworkAccessManager.h">
<Filter>Common</Filter>
</QtMoc>
</ItemGroup>
</Project>

View File

@ -181,7 +181,7 @@ QList<SBoxSnapshot> CSandBox::GetSnapshots(QString* pCurrent) const
BoxSnapshot.NameStr = ini.value(Snapshot + "/Name").toString();
BoxSnapshot.InfoStr = ini.value(Snapshot + "/Description").toString();
BoxSnapshot.SnapDate = ini.value(Snapshot + "/SnapshotDate").toDateTime();
BoxSnapshot.SnapDate = QDateTime::fromTime_t(ini.value(Snapshot + "/SnapshotDate").toULongLong());
Snapshots.append(BoxSnapshot);
}
@ -227,7 +227,7 @@ SB_PROGRESS CSandBox::TakeSnapshot(const QString& Name)
return SB_ERR(tr("Failed to copy RegHive to snapshot"));
ini.setValue("Snapshot_" + ID + "/Name", Name);
ini.setValue("Snapshot_" + ID + "/SnapshotDate", QDateTime::currentDateTime());
ini.setValue("Snapshot_" + ID + "/SnapshotDate", QDateTime::currentDateTime().toTime_t());
QString Current = ini.value("Current/Snapshot").toString();
if(!Current.isEmpty())
ini.setValue("Snapshot_" + ID + "/Parent", Current);

View File

@ -72,10 +72,11 @@ SB_STATUS CSbieUtils::Start(EComponent Component)
void CSbieUtils::Start(EComponent Component, QStringList& Ops)
{
if ((Component & eDriver) != 0 && GetServiceStatus(SBIEDRV) != SERVICE_RUNNING)
Ops.append(QString::fromWCharArray(L"kmdutil.exe|start|" SBIEDRV));
// Note: Service aways starts the driver
if ((Component & eService) != 0 && GetServiceStatus(SBIESVC) != SERVICE_RUNNING)
Ops.append(QString::fromWCharArray(L"kmdutil.exe|start|" SBIESVC));
else if ((Component & eDriver) != 0 && GetServiceStatus(SBIEDRV) != SERVICE_RUNNING)
Ops.append(QString::fromWCharArray(L"kmdutil.exe|start|" SBIEDRV));
}
SB_STATUS CSbieUtils::Stop(EComponent Component)
@ -282,12 +283,12 @@ void CSbieUtils::RemoveContextMenu()
//////////////////////////////////////////////////////////////////////////////
// Shortcuts
bool CreateShortcut(CSbieAPI* pApi, const QString &LinkPath, const QString &LinkName, const QString &boxname, const QString &arguments, const QString &iconPath, int iconIndex, const QString &workdir, BOOL run_elevated = 0)
bool CSbieUtils::CreateShortcut(CSbieAPI* pApi, const QString &LinkPath, const QString &LinkName, const QString &boxname, const QString &arguments, const QString &iconPath, int iconIndex, const QString &workdir, bool bRunElevated)
{
QString StartExe = pApi->GetStartPath();
QString StartArgs;
if (run_elevated)
if (bRunElevated)
StartArgs += "/elevated ";
StartArgs += "/box:" + boxname;
if (!arguments.isEmpty())
@ -329,35 +330,7 @@ bool CreateShortcut(CSbieAPI* pApi, const QString &LinkPath, const QString &Link
return (SUCCEEDED(hr));
}
void CreateDesktopShortcut(CSbieAPI* pApi, const QString &BoxName, const QString &LinkPath, const QString &IconPath, quint32 IconIndex, const QString &WorkDir)
{
WCHAR path[512];
HRESULT hr = SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, path);
if (hr != 0 || *path == L'\0')
return;
QString LinkName;
int pos = LinkPath.lastIndexOf(L'\\');
if (pos == -1)
return;
if (pos == 2 && LinkPath.length() == 3)
LinkName = QObject::tr("Drive %1").arg(LinkPath.left(1));
else {
LinkName = LinkPath.mid(pos + 1);
pos = LinkName.indexOf(QRegExp("[" + QRegExp::escape("\":;,*?.") + "]"));
if (pos != -1)
LinkName = LinkName.left(pos);
}
QString Path = QString::fromWCharArray(path);
if (Path.right(1) != "\\")
Path.append("\\");
Path += "[" + BoxName + "] " + LinkName;
CreateShortcut(pApi, Path, LinkName, BoxName, LinkPath , IconPath, IconIndex, WorkDir);
}
bool GetStartMenuShortcut(CSbieAPI* pApi, QString &BoxName, QString &LinkPath, QString &IconPath, quint32& IconIndex, QString &WorkDir)
bool CSbieUtils::GetStartMenuShortcut(CSbieAPI* pApi, QString &BoxName, QString &LinkPath, QString &IconPath, quint32& IconIndex, QString &WorkDir)
{
WCHAR MapName[128];
wsprintf(MapName, SANDBOXIE L"_StartMenu_WorkArea_%08X_%08X", GetCurrentProcessId(), GetTickCount());
@ -409,12 +382,4 @@ bool GetStartMenuShortcut(CSbieAPI* pApi, QString &BoxName, QString &LinkPath, Q
if (BoxName.isEmpty() || LinkPath.isEmpty())
return false;
return true;
}
void CSbieUtils::CreateDesktopShortcut(const QString& BoxName, CSbieAPI* pApi)
{
QString LinkPath, IconPath, WorkDir;
quint32 IconIndex;
if (::GetStartMenuShortcut(pApi, QString(BoxName), LinkPath, IconPath, IconIndex, WorkDir))
::CreateDesktopShortcut(pApi, BoxName, LinkPath, IconPath, IconIndex, WorkDir);
}
}

View File

@ -30,7 +30,8 @@ public:
static void AddContextMenu(const QString& StartPath);
static void RemoveContextMenu();
static void CreateDesktopShortcut(const QString& BoxName, class CSbieAPI* pApi);
static bool CreateShortcut(class CSbieAPI* pApi, const QString &LinkPath, const QString &LinkName, const QString &boxname, const QString &arguments, const QString &iconPath, int iconIndex, const QString &workdir, bool bRunElevated = false);
static bool GetStartMenuShortcut(class CSbieAPI* pApi, QString &BoxName, QString &LinkPath, QString &IconPath, quint32& IconIndex, QString &WorkDir);
private:
static SB_STATUS ElevateOps(const QStringList& Ops);

View File

@ -45,7 +45,7 @@
<enum>QTabWidget::West</enum>
</property>
<property name="currentIndex">
<number>6</number>
<number>0</number>
</property>
<widget class="QWidget" name="tabGeneral">
<attribute name="title">
@ -1300,20 +1300,7 @@ Note: Forced Programs and Force Folders settings for a sandbox do not apply to
<layout class="QGridLayout" name="gridLayout_34">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_32">
<item row="8" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="8" column="1">
<item row="9" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -1326,6 +1313,33 @@ Note: Forced Programs and Force Folders settings for a sandbox do not apply to
</property>
</spacer>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="chkPipeTrace">
<property name="text">
<string>Pipe Trace</string>
</property>
</widget>
</item>
<item row="3" column="2" rowspan="5">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Log all access events as seen by the driver to the resource access log.
This options set the event amsk to &quot;*&quot; - All access events
You can customize the logging using the ini by specifying
&quot;A&quot; - Allowed accesses
&quot;D&quot; - Denidec accesses
&quot;I&quot; - Ignore access requests
instead of &quot;*&quot;.</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_19">
<property name="font">
@ -1346,13 +1360,6 @@ Note: Forced Programs and Force Folders settings for a sandbox do not apply to
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="chkIpcTrace">
<property name="text">
<string>IPC Trace</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="chkKeyTrace">
<property name="text">
@ -1360,13 +1367,6 @@ Note: Forced Programs and Force Folders settings for a sandbox do not apply to
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="chkPipeTrace">
<property name="text">
<string>Pipe Trace</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="chkFileTrace">
<property name="text">
@ -1374,23 +1374,30 @@ Note: Forced Programs and Force Folders settings for a sandbox do not apply to
</property>
</widget>
</item>
<item row="3" column="2" rowspan="5">
<widget class="QLabel" name="label_26">
<item row="9" column="2">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="chkIpcTrace">
<property name="text">
<string>Log all access events as seen by the driver to the resource access log.
This options set the event amsk to &quot;*&quot; - All access events
You can customize the logging using the ini by specifying
&quot;A&quot; - Allowed accesses
&quot;D&quot; - Denidec accesses
&quot;I&quot; - Ignore access requests
instead of &quot;*&quot;.</string>
<string>IPC Trace</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</widget>
</item>
<item row="8" column="1" colspan="2">
<widget class="QCheckBox" name="chkDbgTrace">
<property name="text">
<string>Log Debug Output to the Trace Log</string>
</property>
</widget>
</item>
@ -1419,8 +1426,8 @@ instead of &quot;*&quot;.</string>
<rect>
<x>0</x>
<y>0</y>
<width>530</width>
<height>251</height>
<width>98</width>
<height>28</height>
</rect>
</property>
<layout class="QGridLayout" name="dbgLayout">

View File

@ -54,6 +54,36 @@
<layout class="QGridLayout" name="gridLayout_9">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_8">
<item row="5" column="1" colspan="2">
<widget class="QCheckBox" name="chkNotifications">
<property name="text">
<string>Show Notifications for relevant log Messages</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QCheckBox" name="chkShowTray">
<property name="text">
<string>Show Sys-Tray</string>
</property>
</widget>
</item>
<item row="10" column="1">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="chkDarkTheme">
<property name="text">
@ -61,14 +91,27 @@
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="chkShowTray">
<item row="10" column="0">
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="1" colspan="2">
<widget class="QCheckBox" name="chkShellMenu">
<property name="text">
<string>Show Sys-Tray</string>
<string>Add 'Run Sandboxed' to the explorer context menu</string>
</property>
</widget>
</item>
<item row="9" column="2">
<item row="10" column="2">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -81,16 +124,20 @@
</property>
</spacer>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<item row="9" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Tray options</string>
<string>On main window close:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="chkAutoStart">
<property name="text">
<string>Start with Windows</string>
</property>
</widget>
</item>
@ -104,76 +151,36 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="chkAutoStart">
<property name="text">
<string>Start with Windows</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>On main window close:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="9" column="0">
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="9" column="1">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="8" column="1">
<widget class="QComboBox" name="onClose"/>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="uiLang"/>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QCheckBox" name="chkWatchConfig">
<property name="text">
<string>Watch Sandboxie.ini for changes</string>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QCheckBox" name="chkNotifications">
<property name="text">
<string>Show Notifications for relevant log Messages</string>
<item row="7" column="0">
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="checked">
<bool>false</bool>
<property name="text">
<string>Tray options</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QComboBox" name="onClose"/>
</item>
<item row="3" column="1" colspan="2">
<widget class="QCheckBox" name="chkShellMenu">
<widget class="QCheckBox" name="chkAutoUpdate">
<property name="text">
<string>Add 'Run Sandboxed' to the explorer context menu</string>
<string>Check periodicaly for updates of Sandboxie-Plus</string>
</property>
</widget>
</item>

View File

@ -66,12 +66,65 @@ bool CSbieModel::TestProcPath(const QList<QVariant>& Path, const QString& BoxNam
return Path.size() == Index;
}
QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList)
QString CSbieModel::FindParent(const QVariant& Name, const QMap<QString, QStringList>& Groups)
{
for(auto I = Groups.begin(); I != Groups.end(); ++I)
{
if (I.value().contains(Name.toString(), Qt::CaseInsensitive))
return I.key();
}
return QString();
}
QList<QVariant> CSbieModel::MakeBoxPath(const QVariant& Name, const QMap<QString, QStringList>& Groups)
{
QString ParentID = FindParent(Name, Groups);
QList<QVariant> Path;
if (!ParentID.isEmpty() && ParentID != Name)
{
Path = MakeBoxPath(ParentID, Groups);
Path.append(ParentID);
}
return Path;
}
QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList, const QMap<QString, QStringList>& Groups)
{
QList<QVariant> Added;
QMap<QList<QVariant>, QList<STreeNode*> > New;
QHash<QVariant, STreeNode*> Old = m_Map;
foreach(const QString& Group, Groups.keys())
{
if (Group.isEmpty())
continue;
QVariant ID = Group;
QHash<QVariant, STreeNode*>::iterator I = Old.find(ID);
SSandBoxNode* pNode = I != Old.end() ? static_cast<SSandBoxNode*>(I.value()) : NULL;
if (!pNode)
{
pNode = static_cast<SSandBoxNode*>(MkNode(ID));
pNode->Values.resize(columnCount());
if (m_bTree)
pNode->Path = MakeBoxPath(ID, Groups);
pNode->pBox = NULL;
New[pNode->Path].append(pNode);
Added.append(ID);
pNode->Icon = m_BoxIcons[eYelow].first;
pNode->IsBold = true;
pNode->Values[eName].Raw = Group;
pNode->Values[eStatus].Raw = tr("Box Groupe");
}
else
{
I.value() = NULL;
}
}
foreach (const CSandBoxPtr& pBox, BoxList)
{
QVariant ID = pBox->GetName();
@ -84,6 +137,8 @@ QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList)
{
pNode = static_cast<SSandBoxNode*>(MkNode(ID));
pNode->Values.resize(columnCount());
if (m_bTree)
pNode->Path = MakeBoxPath(ID, Groups);
pNode->pBox = pBox;
New[pNode->Path].append(pNode);
Added.append(ID);
@ -102,7 +157,7 @@ QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList)
QMap<quint32, CBoxedProcessPtr> ProcessList = pBox->GetProcessList();
bool HasActive = Sync(pBox, ProcessList, New, Old, Added);
bool HasActive = Sync(pBox, pNode->Path, ProcessList, New, Old, Added);
int inUse = (HasActive ? 1 : 0);
int boxType = eYelow;
if(pBoxEx->HasLogApi())
@ -166,7 +221,7 @@ QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList)
return Added;
}
bool CSbieModel::Sync(const CSandBoxPtr& pBox, const QMap<quint32, CBoxedProcessPtr>& ProcessList, QMap<QList<QVariant>, QList<STreeNode*> >& New, QHash<QVariant, STreeNode*>& Old, QList<QVariant>& Added)
bool CSbieModel::Sync(const CSandBoxPtr& pBox, const QList<QVariant>& Path, const QMap<quint32, CBoxedProcessPtr>& ProcessList, QMap<QList<QVariant>, QList<STreeNode*> >& New, QHash<QVariant, STreeNode*>& Old, QList<QVariant>& Added)
{
QString BoxName = pBox->GetName();
@ -180,12 +235,12 @@ bool CSbieModel::Sync(const CSandBoxPtr& pBox, const QMap<quint32, CBoxedProcess
QHash<QVariant, STreeNode*>::iterator I = Old.find(ID);
SSandBoxNode* pNode = I != Old.end() ? static_cast<SSandBoxNode*>(I.value()) : NULL;
if (!pNode || (m_bTree ? !TestProcPath(pNode->Path, BoxName, pProcess, ProcessList) : !pNode->Path.isEmpty()))
if (!pNode || (m_bTree ? !TestProcPath(pNode->Path.mid(Path.length()), BoxName, pProcess, ProcessList) : !pNode->Path.isEmpty())) // todo: improve that
{
pNode = static_cast<SSandBoxNode*>(MkNode(ID));
pNode->Values.resize(columnCount());
if(m_bTree)
pNode->Path = MakeProcPath(BoxName, pProcess, ProcessList);
if (m_bTree)
pNode->Path = Path + MakeProcPath(BoxName, pProcess, ProcessList);
pNode->pBox = pBox;
pNode->pProcess = pProcess;
New[pNode->Path].append(pNode);
@ -295,6 +350,32 @@ CBoxedProcessPtr CSbieModel::GetProcess(const QModelIndex &index) const
return pNode->pProcess;
}
QVariant CSbieModel::GetID(const QModelIndex &index) const
{
if (!index.isValid())
return QVariant();
SSandBoxNode* pNode = static_cast<SSandBoxNode*>(index.internalPointer());
ASSERT(pNode);
return pNode->ID;
}
CSbieModel::ETypes CSbieModel::GetType(const QModelIndex &index) const
{
if (!index.isValid())
return eNone;
SSandBoxNode* pNode = static_cast<SSandBoxNode*>(index.internalPointer());
ASSERT(pNode);
if (pNode->pProcess)
return eProcess;
if (pNode->pBox)
return eBox;
return eGroup;
}
int CSbieModel::columnCount(const QModelIndex &parent) const
{
return eCount;

View File

@ -12,10 +12,19 @@ public:
CSbieModel(QObject *parent = 0);
~CSbieModel();
QList<QVariant> Sync(const QMap<QString, CSandBoxPtr>& BoxList);
QList<QVariant> Sync(const QMap<QString, CSandBoxPtr>& BoxList, const QMap<QString, QStringList>& Groups = QMap<QString, QStringList>());
CSandBoxPtr GetSandBox(const QModelIndex &index) const;
CBoxedProcessPtr GetProcess(const QModelIndex &index) const;
QVariant GetID(const QModelIndex &index) const;
enum ETypes
{
eNone = 0,
eGroup,
eBox,
eProcess
} GetType(const QModelIndex &index) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
@ -33,7 +42,7 @@ public:
};
protected:
bool Sync(const CSandBoxPtr& pBox, const QMap<quint32, CBoxedProcessPtr>& ProcessList, QMap<QList<QVariant>, QList<STreeNode*> >& New, QHash<QVariant, STreeNode*>& Old, QList<QVariant>& Added);
bool Sync(const CSandBoxPtr& pBox, const QList<QVariant>& Path, const QMap<quint32, CBoxedProcessPtr>& ProcessList, QMap<QList<QVariant>, QList<STreeNode*> >& New, QHash<QVariant, STreeNode*>& Old, QList<QVariant>& Added);
struct SSandBoxNode: STreeNode
{
@ -52,6 +61,9 @@ protected:
QList<QVariant> MakeProcPath(const CBoxedProcessPtr& pProcess, const QMap<quint32, CBoxedProcessPtr>& ProcessList);
bool TestProcPath(const QList<QVariant>& Path, const QString& BoxName, const CBoxedProcessPtr& pProcess, const QMap<quint32, CBoxedProcessPtr>& ProcessList, int Index = 0);
QString FindParent(const QVariant& Name, const QMap<QString, QStringList>& Groups);
QList<QVariant> MakeBoxPath(const QVariant& Name, const QMap<QString, QStringList>& Groups);
//virtual QVariant GetDefaultIcon() const;
private:

View File

@ -99,6 +99,8 @@ CSandMan::CSandMan(QWidget *parent)
connect(theAPI, SIGNAL(StatusChanged()), this, SLOT(OnStatusChanged()));
connect(theAPI, SIGNAL(BoxClosed(const QString&)), this, SLOT(OnBoxClosed(const QString&)));
m_RequestManager = NULL;
QString appTitle = tr("Sandboxie-Plus v%1").arg(GetVersion());
this->setWindowTitle(appTitle);
@ -111,15 +113,15 @@ CSandMan::CSandMan(QWidget *parent)
m_bConnectPending = false;
m_bStopPending = false;
CreateMenus();
m_pMainWidget = new QWidget();
m_pMainLayout = new QVBoxLayout(m_pMainWidget);
m_pMainLayout->setMargin(2);
m_pMainLayout->setSpacing(0);
this->setCentralWidget(m_pMainWidget);
m_pToolBar = new QToolBar();
m_pMainLayout->insertWidget(0, m_pToolBar);
CreateToolBar();
m_pLogSplitter = new QSplitter();
m_pLogSplitter->setOrientation(Qt::Vertical);
@ -181,6 +183,104 @@ CSandMan::CSandMan(QWidget *parent)
m_pApiCallLog->setEnabled(false);
//
// Tray
QIcon Icon;
Icon.addFile(":/SandMan.png");
m_pTrayIcon = new QSystemTrayIcon(Icon, this);
m_pTrayIcon->setToolTip("Sandboxie-Plus");
connect(m_pTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(OnSysTray(QSystemTrayIcon::ActivationReason)));
m_bIconEmpty = false;
m_pTrayMenu = new QMenu();
m_pTrayMenu->addAction(m_pEmptyAll);
m_pTrayMenu->addAction(m_pDisableForce);
m_pTrayMenu->addSeparator();
m_pTrayMenu->addAction(m_pExit);
bool bAutoRun = QApplication::arguments().contains("-autorun");
m_pTrayIcon->show(); // Note: qt bug; without a first show hide does not work :/
if(!bAutoRun && !theConf->GetBool("Options/ShowSysTray", true))
m_pTrayIcon->hide();
//
restoreGeometry(theConf->GetBlob("MainWindow/Window_Geometry"));
//m_pBoxTree->restoreState(theConf->GetBlob("MainWindow/BoxTree_Columns"));
m_pMessageLog->GetView()->header()->restoreState(theConf->GetBlob("MainWindow/LogList_Columns"));
QByteArray Columns = theConf->GetBlob("MainWindow/ResMonList_Columns");
if (!Columns.isEmpty())
((QTreeViewEx*)m_pResourceLog->GetView())->OnResetColumns();
else
((QTreeViewEx*)m_pResourceLog->GetView())->restoreState(Columns);
Columns = theConf->GetBlob("MainWindow/ApiLogList_Columns");
if (!Columns.isEmpty())
((QTreeViewEx*)m_pApiCallLog->GetView())->OnResetColumns();
else
((QTreeViewEx*)m_pApiCallLog->GetView())->restoreState(Columns);
m_pLogSplitter->restoreState(theConf->GetBlob("MainWindow/Log_Splitter"));
m_pPanelSplitter->restoreState(theConf->GetBlob("MainWindow/Panel_Splitter"));
m_pLogTabs->setCurrentIndex(theConf->GetInt("MainWindow/LogTab", 0));
if (theConf->GetBool("Options/NoStatusBar", false))
statusBar()->hide();
//else if (theConf->GetBool("Options/NoSizeGrip", false))
// statusBar()->setSizeGripEnabled(false);
m_pKeepTerminated->setChecked(theConf->GetBool("Options/KeepTerminated"));
m_pProgressDialog = new CProgressDialog("", this);
m_pProgressDialog->setWindowModality(Qt::ApplicationModal);
connect(m_pProgressDialog, SIGNAL(Cancel()), this, SLOT(OnCancelAsync()));
m_pPopUpWindow = new CPopUpWindow(this);
connect(m_pPopUpWindow, SIGNAL(RecoveryRequested(const QString&)), this, SLOT(OpenRecovery(const QString&)));
if (!bAutoRun)
show();
//connect(theAPI, SIGNAL(LogMessage(const QString&, bool)), this, SLOT(OnLogMessage(const QString&, bool)));
connect(theAPI, SIGNAL(LogSbieMessage(quint32, const QStringList&, quint32)), this, SLOT(OnLogSbieMessage(quint32, const QStringList&, quint32)));
connect(theAPI, SIGNAL(NotAuthorized(bool, bool&)), this, SLOT(OnNotAuthorized(bool, bool&)), Qt::DirectConnection);
connect(theAPI, SIGNAL(QueuedRequest(quint32, quint32, quint32, const QVariantMap&)), this, SLOT(OnQueuedRequest(quint32, quint32, quint32, const QVariantMap&)), Qt::QueuedConnection);
connect(theAPI, SIGNAL(FileToRecover(const QString&, const QString&, quint32)), this, SLOT(OnFileToRecover(const QString&, const QString&, quint32)), Qt::QueuedConnection);
connect(theAPI, SIGNAL(ConfigReloaded()), this, SLOT(OnIniReloaded()));
m_uTimerID = startTimer(250);
if (CSbieUtils::IsRunning(CSbieUtils::eAll) || theConf->GetBool("Options/StartIfStopped", true))
{
SB_STATUS Status = ConnectSbie();
CheckResults(QList<SB_STATUS>() << Status);
}
}
CSandMan::~CSandMan()
{
if(m_pEnableMonitoring->isChecked())
theAPI->EnableMonitor(false);
killTimer(m_uTimerID);
m_pTrayIcon->hide();
theConf->SetBlob("MainWindow/Window_Geometry", saveGeometry());
//theConf->SetBlob("MainWindow/BoxTree_Columns", m_pBoxTree->saveState());
theConf->SetBlob("MainWindow/LogList_Columns", m_pMessageLog->GetView()->header()->saveState());
theConf->SetBlob("MainWindow/ResMonList_Columns", m_pResourceLog->GetView()->header()->saveState());
theConf->SetBlob("MainWindow/ApiLogList_Columns", m_pApiCallLog->GetView()->header()->saveState());
theConf->SetBlob("MainWindow/Log_Splitter", m_pLogSplitter->saveState());
theConf->SetBlob("MainWindow/Panel_Splitter", m_pPanelSplitter->saveState());
theConf->SetValue("MainWindow/LogTab", m_pLogTabs->currentIndex());
theAPI = NULL;
theGUI = NULL;
}
void CSandMan::CreateMenus()
{
connect(menuBar(), SIGNAL(hovered(QAction*)), this, SLOT(OnMenuHover(QAction*)));
m_pMenuFile = menuBar()->addMenu(tr("&Sandbox"));
@ -236,12 +336,21 @@ CSandMan::CSandMan(QWidget *parent)
m_pMenuHelp = menuBar()->addMenu(tr("&Help"));
m_pSupport = m_pMenuHelp->addAction(tr("Support Sandboxie-Plus on Patreon"), this, SLOT(OnAbout()));
//m_pMenuHelp->addAction(tr("Support Sandboxie-Plus on Patreon"), this, SLOT(OnHelp()));
m_pSupport = m_pMenuHelp->addAction(tr("Support Sandboxie-Plus with a Donation"), this, SLOT(OnHelp()));
m_pForum = m_pMenuHelp->addAction(tr("Visit Support Forum"), this, SLOT(OnHelp()));
m_pManual = m_pMenuHelp->addAction(tr("Online Documentation"), this, SLOT(OnHelp()));
m_pMenuHelp->addSeparator();
m_pUpdate = m_pMenuHelp->addAction(tr("Check for Updates"), this, SLOT(CheckForUpdates()));
m_pMenuHelp->addSeparator();
m_pAboutQt = m_pMenuHelp->addAction(tr("About the Qt Framework"), this, SLOT(OnAbout()));
//m_pMenuHelp->addSeparator();
m_pAbout = m_pMenuHelp->addAction(QIcon(":/SandMan.png"), tr("About Sandboxie-Plus"), this, SLOT(OnAbout()));
}
void CSandMan::CreateToolBar()
{
m_pToolBar = new QToolBar();
m_pMainLayout->insertWidget(0, m_pToolBar);
m_pToolBar->addAction(m_pMenuSettings);
m_pToolBar->addSeparator();
@ -280,102 +389,9 @@ CSandMan::CSandMan(QWidget *parent)
m_pToolBar->addWidget(new QLabel(" "));
QLabel* pSupport = new QLabel("<a href=\"https://www.patreon.com/DavidXanatos\">Support Sandboxie-Plus on Patreon</a>");
pSupport->setTextInteractionFlags(Qt::TextBrowserInteraction);
connect(pSupport, SIGNAL(linkActivated(const QString&)), this, SLOT(OnAbout()));
connect(pSupport, SIGNAL(linkActivated(const QString&)), this, SLOT(OnHelp()));
m_pToolBar->addWidget(pSupport);
m_pToolBar->addWidget(new QLabel(" "));
QIcon Icon;
Icon.addFile(":/SandMan.png");
m_pTrayIcon = new QSystemTrayIcon(Icon, this);
m_pTrayIcon->setToolTip("Sandboxie-Plus");
connect(m_pTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(OnSysTray(QSystemTrayIcon::ActivationReason)));
m_bIconEmpty = false;
m_pTrayMenu = new QMenu();
m_pTrayMenu->addAction(m_pEmptyAll);
m_pTrayMenu->addAction(m_pDisableForce);
m_pTrayMenu->addSeparator();
m_pTrayMenu->addAction(m_pExit);
bool bAutoRun = QApplication::arguments().contains("-autorun");
m_pTrayIcon->show(); // Note: qt bug; without a first show hide does not work :/
if(!bAutoRun && !theConf->GetBool("Options/ShowSysTray", true))
m_pTrayIcon->hide();
restoreGeometry(theConf->GetBlob("MainWindow/Window_Geometry"));
//m_pBoxTree->restoreState(theConf->GetBlob("MainWindow/BoxTree_Columns"));
m_pMessageLog->GetView()->header()->restoreState(theConf->GetBlob("MainWindow/LogList_Columns"));
QByteArray Columns = theConf->GetBlob("MainWindow/ResMonList_Columns");
if (!Columns.isEmpty())
((QTreeViewEx*)m_pResourceLog->GetView())->OnResetColumns();
else
((QTreeViewEx*)m_pResourceLog->GetView())->restoreState(Columns);
Columns = theConf->GetBlob("MainWindow/ApiLogList_Columns");
if (!Columns.isEmpty())
((QTreeViewEx*)m_pApiCallLog->GetView())->OnResetColumns();
else
((QTreeViewEx*)m_pApiCallLog->GetView())->restoreState(Columns);
m_pLogSplitter->restoreState(theConf->GetBlob("MainWindow/Log_Splitter"));
m_pPanelSplitter->restoreState(theConf->GetBlob("MainWindow/Panel_Splitter"));
m_pLogTabs->setCurrentIndex(theConf->GetInt("MainWindow/LogTab", 0));
if (theConf->GetBool("Options/NoStatusBar", false))
statusBar()->hide();
//else if (theConf->GetBool("Options/NoSizeGrip", false))
// statusBar()->setSizeGripEnabled(false);
m_pKeepTerminated->setChecked(theConf->GetBool("Options/KeepTerminated"));
m_pProgressDialog = new CProgressDialog("Maintenance operation progress...", this);
m_pProgressDialog->setWindowModality(Qt::ApplicationModal);
connect(m_pProgressDialog, SIGNAL(Cancel()), this, SLOT(OnCancelAsync()));
m_pPopUpWindow = new CPopUpWindow(this);
connect(m_pPopUpWindow, SIGNAL(RecoveryRequested(const QString&)), this, SLOT(OpenRecovery(const QString&)));
if (!bAutoRun)
show();
//connect(theAPI, SIGNAL(LogMessage(const QString&, bool)), this, SLOT(OnLogMessage(const QString&, bool)));
connect(theAPI, SIGNAL(LogSbieMessage(quint32, const QStringList&, quint32)), this, SLOT(OnLogSbieMessage(quint32, const QStringList&, quint32)));
connect(theAPI, SIGNAL(NotAuthorized(bool, bool&)), this, SLOT(OnNotAuthorized(bool, bool&)), Qt::DirectConnection);
connect(theAPI, SIGNAL(QueuedRequest(quint32, quint32, quint32, const QVariantMap&)), this, SLOT(OnQueuedRequest(quint32, quint32, quint32, const QVariantMap&)), Qt::QueuedConnection);
connect(theAPI, SIGNAL(FileToRecover(const QString&, const QString&, quint32)), this, SLOT(OnFileToRecover(const QString&, const QString&, quint32)), Qt::QueuedConnection);
connect(theAPI, SIGNAL(ConfigReloaded()), this, SLOT(OnIniReloaded()));
m_uTimerID = startTimer(250);
if (CSbieUtils::IsRunning(CSbieUtils::eAll) || theConf->GetBool("Options/StartIfStopped", true))
{
SB_STATUS Status = ConnectSbie();
CheckResults(QList<SB_STATUS>() << Status);
}
}
CSandMan::~CSandMan()
{
if(m_pEnableMonitoring->isChecked())
theAPI->EnableMonitor(false);
killTimer(m_uTimerID);
m_pTrayIcon->hide();
theConf->SetBlob("MainWindow/Window_Geometry", saveGeometry());
//theConf->SetBlob("MainWindow/BoxTree_Columns", m_pBoxTree->saveState());
theConf->SetBlob("MainWindow/LogList_Columns", m_pMessageLog->GetView()->header()->saveState());
theConf->SetBlob("MainWindow/ResMonList_Columns", m_pResourceLog->GetView()->header()->saveState());
theConf->SetBlob("MainWindow/ApiLogList_Columns", m_pApiCallLog->GetView()->header()->saveState());
theConf->SetBlob("MainWindow/Log_Splitter", m_pLogSplitter->saveState());
theConf->SetBlob("MainWindow/Panel_Splitter", m_pPanelSplitter->saveState());
theConf->SetValue("MainWindow/LogTab", m_pLogTabs->currentIndex());
theAPI = NULL;
theGUI = NULL;
}
void CSandMan::OnExit()
@ -503,6 +519,35 @@ void CSandMan::timerEvent(QTimerEvent* pEvent)
m_pBoxView->Refresh();
OnSelectionChanged();
int iCheckUpdates = theConf->GetInt("Options/CheckForUpdates", 2);
if (iCheckUpdates != 0)
{
time_t NextUpdateCheck = theConf->GetUInt64("Options/NextCheckForUpdates", 0);
if (NextUpdateCheck == 0)
theConf->SetValue("Options/NextCheckForUpdates", QDateTime::currentDateTime().addDays(7).toTime_t());
else if(QDateTime::currentDateTime().toTime_t() >= NextUpdateCheck)
{
if (iCheckUpdates == 2)
{
bool bCheck = false;
iCheckUpdates = CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to check if there is a new version of Sandboxie-Plus?")
, tr("Don't show this message again."), &bCheck, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes, QMessageBox::Information) == QDialogButtonBox::Ok ? 1 : 0;
if (bCheck)
theConf->SetValue("Options/CheckForUpdates", iCheckUpdates);
}
if (iCheckUpdates == 0)
theConf->SetValue("Options/NextCheckForUpdates", QDateTime::currentDateTime().addDays(7).toTime_t());
else
{
theConf->SetValue("Options/NextCheckForUpdates", QDateTime::currentDateTime().addDays(1).toTime_t());
CheckForUpdates(false);
}
}
}
}
void CSandMan::OnBoxClosed(const QString& BoxName)
@ -980,6 +1025,7 @@ void CSandMan::OnReloadIni()
void CSandMan::OnIniReloaded()
{
m_pBoxView->ReloadGroups();
m_pPopUpWindow->ReloadHiddenMessages();
}
@ -1026,10 +1072,12 @@ void CSandMan::AddAsyncOp(const CSbieProgressPtr& pProgress)
m_pAsyncProgress.insert(pProgress.data(), pProgress);
connect(pProgress.data(), SIGNAL(Message(const QString&)), this, SLOT(OnAsyncMessage(const QString&)));
connect(pProgress.data(), SIGNAL(Finished()), this, SLOT(OnAsyncFinished()));
m_pProgressDialog->OnStatusMessage("");
m_pProgressDialog->show();
if (pProgress->IsFinished()) // Note: the operation runs asynchroniusly it may have already finished so we need to test for that
OnAsyncFinished(pProgress.data());
m_pProgressDialog->show();
}
void CSandMan::OnAsyncFinished()
@ -1139,6 +1187,211 @@ QString CSandMan::GetVersion()
return Version;
}
void CSandMan::CheckForUpdates(bool bManual)
{
m_pProgressDialog->OnStatusMessage(tr("Checking for updates..."));
m_pProgressDialog->show();
if(m_RequestManager == NULL)
m_RequestManager = new CNetworkAccessManager(30 * 1000, this);
QUrlQuery Query;
Query.addQueryItem("software", "sandboxie-plus");
//QString Branche = theConf->GetString("Options/ReleaseBranche");
//if (!Branche.isEmpty())
// Query.addQueryItem("branche", Branche);
Query.addQueryItem("version", GetVersion());
//Query.addQueryItem("version", QString::number(VERSION_MJR) + "." + QString::number(VERSION_MIN) + "." + QString::number(VERSION_REV) + "." + QString::number(VERSION_UPD));
Query.addQueryItem("system", "windows-" + QSysInfo::kernelVersion() + "-" + QSysInfo::currentCpuArchitecture());
Query.addQueryItem("language", QString::number(m_LanguageId));
QString UpdateKey = theAPI->GetGlobalSettings()->GetText("UpdateKey"); // theConf->GetString("Options/UpdateKey");
if (!UpdateKey.isEmpty())
Query.addQueryItem("update_key", UpdateKey);
Query.addQueryItem("auto", bManual ? "0" : "1");
QUrl Url("https://xanasoft.com/update.php");
Url.setQuery(Query);
QNetworkRequest Request = QNetworkRequest(Url);
Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
//Request.setRawHeader("Accept-Encoding", "gzip");
QNetworkReply* pReply = m_RequestManager->get(Request);
pReply->setProperty("manual", bManual);
connect(pReply, SIGNAL(finished()), this, SLOT(OnUpdateCheck()));
}
void CSandMan::OnUpdateCheck()
{
QNetworkReply* pReply = qobject_cast<QNetworkReply*>(sender());
QByteArray Reply = pReply->readAll();
bool bManual = pReply->property("manual").toBool();
pReply->deleteLater();
m_pProgressDialog->hide();
QVariantMap Data = QJsonDocument::fromJson(Reply).toVariant().toMap();
if (Data.isEmpty() || Data["error"].toBool())
{
QString Error = Data.isEmpty() ? tr("server not reachable") : Data["errorMsg"].toString();
OnLogMessage(tr("Failed to check for updates, error: %1").arg(Error), !bManual);
if (bManual)
QMessageBox::critical(this, "Sandboxie-Plus", tr("Failed to check for updates, error: %1").arg(Error));
return;
}
bool bNothing = true;
QStringList IgnoredUpdates = theConf->GetStringList("Options/IgnoredUpdates");
QString UserMsg = Data["userMsg"].toString();
if (!UserMsg.isEmpty())
{
QString MsgHash = QCryptographicHash::hash(Data["userMsg"].toByteArray(), QCryptographicHash::Md5).toHex().left(8);
if (!IgnoredUpdates.contains(MsgHash))
{
CCheckableMessageBox mb(this);
mb.setWindowTitle("Sandboxie-Plus");
QIcon ico(QLatin1String(":/SandMan.png"));
mb.setIconPixmap(ico.pixmap(64, 64));
mb.setText(UserMsg);
mb.setCheckBoxText(tr("Don't show this announcement in future."));
mb.setStandardButtons(QDialogButtonBox::Close);
mb.exec();
if (mb.isChecked())
theConf->SetValue("Options/IgnoredUpdates", IgnoredUpdates << MsgHash);
bNothing = false;
}
}
QString Version = Data["version"].toString();
if (!Version.isEmpty() && Version != GetVersion())
{
if (bManual || !IgnoredUpdates.contains(Version)) // when checked manually always show result
{
bNothing = false;
//QDateTime Updated = QDateTime::fromTime_t(Data["updated"].toULongLong());
QString UpdateMsg = Data["updateMsg"].toString();
QString UpdateUrl = Data["updateUrl"].toString();
QString DownloadUrl = Data["downloadUrl"].toString();
// 'sha256'
// 'signature'
QString FullMessage = UpdateMsg.isEmpty() ? tr("<p>There is a new version of Sandboxie-Plus available.<br /><font color='red'>New version:</font> <b>%1</b></p>").arg(Version) : UpdateMsg;
if (!DownloadUrl.isEmpty())
FullMessage += tr("<p>Do you want to download the latest version?</p>");
else if (!UpdateUrl.isEmpty())
FullMessage += tr("<p>Do you want to go to the <a href=\"%1\">download page</a>?</p>").arg(UpdateUrl);
CCheckableMessageBox mb(this);
mb.setWindowTitle("Sandboxie-Plus");
QIcon ico(QLatin1String(":/SandMan.png"));
mb.setIconPixmap(ico.pixmap(64, 64));
//mb.setTextFormat(Qt::RichText);
mb.setText(FullMessage);
mb.setCheckBoxText(tr("Ignore this update, notify me anout the next one."));
mb.setCheckBoxVisible(!bManual);
if (!UpdateUrl.isEmpty() || !DownloadUrl.isEmpty()) {
mb.setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
mb.setDefaultButton(QDialogButtonBox::Yes);
}
else
mb.setStandardButtons(QDialogButtonBox::Ok);
mb.exec();
if (mb.isChecked())
theConf->SetValue("Options/IgnoredUpdates", IgnoredUpdates << Version);
if (mb.clickedStandardButton() == QDialogButtonBox::Yes)
{
if (!DownloadUrl.isEmpty())
{
QNetworkRequest Request = QNetworkRequest(DownloadUrl);
Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
//Request.setRawHeader("Accept-Encoding", "gzip");
QNetworkReply* pReply = m_RequestManager->get(Request);
connect(pReply, SIGNAL(finished()), this, SLOT(OnUpdateDownload()));
connect(pReply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(OnUpdateProgress(qint64, qint64)));
m_pProgressDialog->OnStatusMessage(tr("Downloading new version..."));
m_pProgressDialog->show();
}
else
QDesktopServices::openUrl(UpdateUrl);
}
}
}
if (bNothing)
{
theConf->SetValue("Options/NextCheckForUpdates", QDateTime::currentDateTime().addDays(7).toTime_t());
if (bManual)
QMessageBox::information(this, "Sandboxie-Plus", tr("No new updates found, your Sandboxie-Plus is up to date."));
}
}
void CSandMan::OnUpdateProgress(qint64 bytes, qint64 bytesTotal)
{
if (bytesTotal != 0)
m_pProgressDialog->OnProgressMessage("", 100 * bytes / bytesTotal);
}
void CSandMan::OnUpdateDownload()
{
QString TempDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
if (TempDir.right(1) != "/")
TempDir += "/";
m_pProgressDialog->OnProgressMessage("", -1);
QNetworkReply* pReply = qobject_cast<QNetworkReply*>(sender());
quint64 Size = pReply->bytesAvailable();
QString Name = pReply->request().url().fileName();
if (Name.isEmpty() || Name.right(4).compare(".exe", Qt::CaseInsensitive) != 0)
Name = "Sandboxie-Plus-Install.exe";
QString FilePath = TempDir + Name;
QFile File(FilePath);
if (File.open(QFile::WriteOnly)) {
while (pReply->bytesAvailable() > 0)
File.write(pReply->read(4096));
File.close();
}
pReply->deleteLater();
m_pProgressDialog->hide();
if (File.size() != Size) {
QMessageBox::critical(this, "Sandboxie-Plus", tr("Failed to download update from: %1").arg(pReply->request().url().toString()));
return;
}
QString Message = tr("<p>New Sandboxie-Plus has been downloaded to the following location:</p><p><a href=\"%2\">%1</a></p><p>Do you want to begin the installation. If any programs are running sandboxed, they will be terminated.</p>")
.arg(FilePath).arg("File:///" + TempDir);
if (QMessageBox("Sandboxie-Plus", Message, QMessageBox::Information, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape, QMessageBox::NoButton).exec() == QMessageBox::Yes)
QProcess::startDetached(FilePath);
}
void CSandMan::OnHelp()
{
if (sender() == m_pSupport)
QDesktopServices::openUrl(QUrl("https://xanasoft.com/go.php?to=donate"));
else if (sender() == m_pForum)
QDesktopServices::openUrl(QUrl("https://xanasoft.com/go.php?to=forum"));
else if (sender() == m_pManual)
QDesktopServices::openUrl(QUrl("https://xanasoft.com/go.php?to=sbie-docs"));
else
QDesktopServices::openUrl(QUrl("https://www.patreon.com/DavidXanatos"));
}
void CSandMan::OnAbout()
{
if (sender() == m_pAbout)
@ -1172,8 +1425,6 @@ void CSandMan::OnAbout()
}
else if (sender() == m_pAboutQt)
QMessageBox::aboutQt(this);
else
QDesktopServices::openUrl(QUrl("https://www.patreon.com/DavidXanatos"));
}
void CSandMan::SetDarkTheme(bool bDark)

View File

@ -6,6 +6,7 @@
#include "../MiscHelpers/Common/TreeViewEx.h"
#include "../MiscHelpers/Common/PanelView.h"
#include "../MiscHelpers/Common/ProgressDialog.h"
#include "../MiscHelpers/Common/NetworkAccessManager.h"
#include "Models/ResMonModel.h"
#include "Models/ApiMonModel.h"
#include <QTranslator>
@ -42,6 +43,9 @@ public:
void AddAsyncOp(const CSbieProgressPtr& pProgress);
static void CheckResults(QList<SB_STATUS> Results);
QAction* GetNewAction() { return m_pNew; }
QAction* GetEmptyAllAction() { return m_pEmptyAll; }
protected:
SB_STATUS ConnectSbie();
SB_STATUS ConnectSbieImpl();
@ -64,6 +68,8 @@ protected:
QMap<CSbieProgress*, CSbieProgressPtr> m_pAsyncProgress;
CNetworkAccessManager* m_RequestManager;
public slots:
void OnMessage(const QString&);
@ -88,6 +94,8 @@ public slots:
void OnBoxClosed(const QString& BoxName);
void CheckForUpdates(bool bManual = true);
private slots:
void OnSelectionChanged();
@ -108,11 +116,19 @@ private slots:
void OnSetLogging();
void OnExit();
void OnHelp();
void OnAbout();
void OnSysTray(QSystemTrayIcon::ActivationReason Reason);
void OnUpdateCheck();
void OnUpdateProgress(qint64 bytes, qint64 bytesTotal);
void OnUpdateDownload();
private:
void CreateMenus();
void CreateToolBar();
QWidget* m_pMainWidget;
QVBoxLayout* m_pMainLayout;
@ -170,8 +186,11 @@ private:
QAction* m_pEnableLogging;
QMenu* m_pMenuHelp;
QAction* m_pAbout;
QAction* m_pSupport;
QAction* m_pForum;
QAction* m_pManual;
QAction* m_pUpdate;
QAction* m_pAbout;
QAction* m_pAboutQt;
QSystemTrayIcon* m_pTrayIcon;

View File

@ -53,6 +53,13 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
connect(m_pSbieModel, SIGNAL(ToolTipCallback(const QVariant&, QString&)), this, SLOT(OnToolTipCallback(const QVariant&, QString&)), Qt::DirectConnection);
m_pMenu->addAction(theGUI->GetNewAction());
//m_pMenu->addAction(theGUI->GetEmptyAllAction());
m_pAddGroupe = m_pMenu->addAction(QIcon(":/Actions/Group"), tr("Add Group"), this, SLOT(OnGroupAction()));
m_pDelGroupe = m_pMenu->addAction(QIcon(":/Actions/Remove"), tr("Remove Group"), this, SLOT(OnGroupAction()));
m_iMenuTop = m_pMenu->actions().count();
//m_pMenu->addSeparator();
m_pMenuRun = m_pMenu->addMenu(QIcon(":/Actions/Run"), tr("Run"));
m_pMenuRunAny = m_pMenuRun->addAction(tr("Run Program"), this, SLOT(OnSandBoxAction()));
m_pMenuRunMenu = m_pMenuRun->addAction(tr("Run from Start Menu"), this, SLOT(OnSandBoxAction()));
@ -82,6 +89,8 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
m_pMenuPresetsNoAdmin->setCheckable(true);
m_pMenuOptions = m_pMenu->addAction(QIcon(":/Actions/Options"), tr("Sandbox Options"), this, SLOT(OnSandBoxAction()));
m_pMenuRename = m_pMenu->addAction(QIcon(":/Actions/Rename"), tr("Rename Sandbox"), this, SLOT(OnSandBoxAction()));
m_iMoveTo = m_pMenu->actions().count();
m_pMenuMoveTo = m_pMenu->addMenu(QIcon(":/Actions/Group"), tr("Move to Group"));
m_pMenuRemove = m_pMenu->addAction(QIcon(":/Actions/Remove"), tr("Remove Sandbox"), this, SLOT(OnSandBoxAction()));
m_iMenuBox = m_pMenu->actions().count();
@ -123,7 +132,7 @@ CSbieView::~CSbieView()
void CSbieView::Refresh()
{
QList<QVariant> Added = m_pSbieModel->Sync(theAPI->GetAllBoxes());
QList<QVariant> Added = m_pSbieModel->Sync(theAPI->GetAllBoxes(), m_Groups);
if (m_pSbieModel->IsTree())
{
@ -168,7 +177,8 @@ void CSbieView::OnMenu(const QPoint& Point)
int iProcessCount = 0;
int iSandBoxeCount = 0;
int iSuspendedCount = 0;
foreach(const QModelIndex& Index, m_pSbieTree->selectedRows())
QModelIndexList Rows = m_pSbieTree->selectedRows();
foreach(const QModelIndex& Index, Rows)
{
QModelIndex ModelIndex = m_pSortProxy->mapToSource(Index);
pProcess = m_pSbieModel->GetProcess(ModelIndex);
@ -188,10 +198,16 @@ void CSbieView::OnMenu(const QPoint& Point)
QList<QAction*> MenuActions = m_pMenu->actions();
for (int i = 0; i < m_iMenuBox; i++)
for (int i = 0; i < m_iMenuTop; i++)
MenuActions[i]->setVisible(iSandBoxeCount == 0 && iProcessCount == 0);
m_pDelGroupe->setVisible(!Rows.isEmpty() && iSandBoxeCount == 0 && iProcessCount == 0);
for (int i = m_iMenuTop; i < m_iMenuBox; i++)
MenuActions[i]->setVisible(iSandBoxeCount > 0 && iProcessCount == 0);
m_pMenuRun->setEnabled(iSandBoxeCount == 1);
MenuActions[m_iMoveTo]->setVisible(!Rows.isEmpty() && iProcessCount == 0);
if(iSandBoxeCount == 1)
UpdateRunMenu(pBox);
@ -247,6 +263,134 @@ void CSbieView::OnMenu(const QPoint& Point)
CPanelView::OnMenu(Point);
}
int CSbieView__ParseGroup(const QString& Grouping, QMap<QString, QStringList>& m_Groups, const QString& Parent = "", int Index = 0)
{
QRegExp RegExp("[,()]", Qt::CaseInsensitive, QRegExp::RegExp);
for (; ; )
{
int pos = Grouping.indexOf(RegExp, Index);
QString Name;
if (pos == -1) {
Name = Grouping.mid(Index);
Index = Grouping.length();
}
else {
Name = Grouping.mid(Index, pos - Index);
Index = pos + 1;
}
if (!Name.isEmpty())
m_Groups[Parent].append(Name);
if (pos == -1)
break;
if (Grouping.at(pos) == "(")
Index = CSbieView__ParseGroup(Grouping, m_Groups, Name, Index);
else if (Grouping.at(pos) == ")")
break;
}
return Index;
}
void CSbieView::ReloadGroups()
{
m_Groups.clear();
QString Grouping = theAPI->GetUserSettings()->GetText("BoxDisplayOrder");
CSbieView__ParseGroup(Grouping, m_Groups);
// update move to menu
foreach(QAction* pAction, m_pMenuMoveTo->actions())
m_pMenuMoveTo->removeAction(pAction);
foreach(const QString& Group, m_Groups.keys())
{
QAction* pAction = m_pMenuMoveTo->addAction(Group.isEmpty() ? tr("[None]") : Group, this, SLOT(OnGroupAction()));
pAction->setData(Group);
}
}
QString CSbieView__SerializeGroup(QMap<QString, QStringList>& m_Groups, const QString& Parent = "")
{
QStringList Grouping;
foreach(const QString& Name, m_Groups[Parent])
{
if (m_Groups.contains(Name))
Grouping.append(Name + "(" + CSbieView__SerializeGroup(m_Groups, Name) + ")");
else
Grouping.append(Name);
}
return Grouping.join(",");
}
void CSbieView::OnGroupAction()
{
QAction* Action = qobject_cast<QAction*>(sender());
if (Action == m_pAddGroupe)
{
QString Name = QInputDialog::getText(this, "Sandboxie-Plus", tr("Please enter a new group name"), QLineEdit::Normal);
if (Name.isEmpty() || m_Groups.contains(Name))
return;
m_Groups[Name] = QStringList();
QModelIndex ModelIndex = m_pSortProxy->mapToSource(m_pSbieTree->currentIndex());
QString Parent;
if (m_pSbieModel->GetType(ModelIndex) == CSbieModel::eGroup)
Parent = m_pSbieModel->GetID(ModelIndex).toString();
if (!Parent.isEmpty())
m_Groups[Parent].append(Name);
}
else if (Action == m_pDelGroupe)
{
if (QMessageBox("Sandboxie-Plus", tr("Do you really want remove the selected group(s)?"), QMessageBox::Warning, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton).exec() != QMessageBox::Yes)
return;
foreach(const QModelIndex& Index, m_pSbieTree->selectedRows())
{
QModelIndex ModelIndex = m_pSortProxy->mapToSource(Index);
if (m_pSbieModel->GetType(ModelIndex) == CSbieModel::eGroup)
{
QString Group = m_pSbieModel->GetID(ModelIndex).toString();
m_Groups.remove(Group);
// remove from parents
for (auto I = m_Groups.begin(); I != m_Groups.end(); ++I)
I.value().removeAll(Group);
}
}
m_pSbieModel->Clear(); //todo improve that, also move boxes to grant parent?
}
else // move to groupe
{
QString Group = Action->data().toString();
foreach(const QModelIndex& Index, m_pSbieTree->selectedRows())
{
QModelIndex ModelIndex = m_pSortProxy->mapToSource(Index);
QString Name;
if (m_pSbieModel->GetType(ModelIndex) == CSbieModel::eGroup)
Name = m_pSbieModel->GetID(ModelIndex).toString();
else if (m_pSbieModel->GetType(ModelIndex) == CSbieModel::eBox)
Name = m_pSbieModel->GetSandBox(ModelIndex)->GetName();
if (Name.isEmpty() || Name == Group)
continue;
// remove from old
for (auto I = m_Groups.begin(); I != m_Groups.end(); ++I)
I.value().removeAll(Name);
// add to new
m_Groups[Group].append(Name);
}
m_pSbieModel->Clear(); //todo improve that
}
QString Grouping = CSbieView__SerializeGroup(m_Groups);
theAPI->GetUserSettings()->SetText("BoxDisplayOrder", Grouping);
}
void CSbieView::OnSandBoxAction()
{
QList<SB_STATUS> Results;
@ -337,7 +481,39 @@ void CSbieView::OnSandBoxAction()
}
else if (Action == m_pMenuMkLink)
{
CSbieUtils::CreateDesktopShortcut(SandBoxes.first()->GetName(), theAPI);
QString BoxName = SandBoxes.first()->GetName();
QString LinkPath, IconPath, WorkDir;
quint32 IconIndex;
if (!CSbieUtils::GetStartMenuShortcut(theAPI, BoxName, LinkPath, IconPath, IconIndex, WorkDir))
return;
QString LinkName;
int pos = LinkPath.lastIndexOf(L'\\');
if (pos == -1)
return;
if (pos == 2 && LinkPath.length() == 3)
LinkName = QObject::tr("Drive %1").arg(LinkPath.left(1));
else {
LinkName = LinkPath.mid(pos + 1);
pos = LinkName.indexOf(QRegExp("[" + QRegExp::escape("\":;,*?.") + "]"));
if (pos != -1)
LinkName = LinkName.left(pos);
}
QString Path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).replace("/", "\\");
//Path = QFileDialog::getExistingDirectory(this, tr("Select Directory to create Shorcut in"), Path).replace("/", "\\");
//if (Path.isEmpty())
// return;
if (Path.right(1) != "\\")
Path.append("\\");
Path += "[" + BoxName + "] " + LinkName;
Path = QFileDialog::getSaveFileName(this, tr("Create Shortcut to sandbox %1").arg(BoxName), Path, QString("Shortcut files (*.lnk)")).replace("/", "\\");
if (Path.isEmpty())
return;
CSbieUtils::CreateShortcut(theAPI, Path, LinkName, BoxName, LinkPath, IconPath, IconIndex, WorkDir);
}
else // custom run menu command
{
@ -422,13 +598,14 @@ void CSbieView::ProcessSelection(const QItemSelection& selected, const QItemSele
return;
QItemSelectionModel* selectionModel = m_pSbieTree->selectionModel();
QItemSelection selection = selectionModel->selection();
QItemSelection invalid;
/*
QModelIndex root_parent = m_pSbieTree->currentIndex().parent();
while (root_parent.isValid() && root_parent.parent().isValid())
root_parent = root_parent.parent();
QItemSelection invalid;
foreach(const QModelIndex& index, selection.indexes())
{
QModelIndex parent = index.parent();
@ -437,7 +614,16 @@ void CSbieView::ProcessSelection(const QItemSelection& selected, const QItemSele
if (parent != root_parent)
invalid.select(index, index);
}*/
int Type = m_pSbieModel->GetType(m_pSortProxy->mapToSource(m_pSbieTree->currentIndex()));
foreach(const QModelIndex& index, selection.indexes())
{
if (m_pSbieModel->GetType(m_pSortProxy->mapToSource(index)) != Type)
invalid.select(index, index);
}
selectionModel->select(invalid, QItemSelectionModel::Deselect);
}

View File

@ -22,6 +22,7 @@ signals:
public slots:
void Refresh();
void ReloadGroups();
private slots:
void OnToolTipCallback(const QVariant& ID, QString& ToolTip);
@ -29,6 +30,7 @@ private slots:
void OnDoubleClicked(const QModelIndex& index);
void ProcessSelection(const QItemSelection& selected, const QItemSelection& deselected);
void OnGroupAction();
void OnSandBoxAction();
void OnProcessAction();
@ -39,6 +41,8 @@ protected:
virtual void UpdateRunMenu(const CSandBoxPtr& pBox);
QMap<QString, QStringList> m_Groups;
private:
QVBoxLayout* m_pMainLayout;
@ -47,7 +51,9 @@ private:
CSbieModel* m_pSbieModel;
QSortFilterProxyModel* m_pSortProxy;
QAction* m_pAddGroupe;
QAction* m_pDelGroupe;
int m_iMenuTop;
QMenu* m_pMenuRun;
QAction* m_pMenuRunAny;
QAction* m_pMenuRunMenu;
@ -68,6 +74,8 @@ private:
QAction* m_pMenuRecover;
QAction* m_pMenuCleanUp;
QAction* m_pMenuRemove;
QMenu* m_pMenuMoveTo;
int m_iMoveTo;
QAction* m_pMenuRename;
int m_iMenuBox;

View File

@ -234,6 +234,7 @@ COptionsWindow::COptionsWindow(const QSharedPointer<CSbieIni>& pBox, const QStri
connect(ui.chkKeyTrace, SIGNAL(clicked(bool)), this, SLOT(OnAdvancedChanged()));
connect(ui.chkIpcTrace, SIGNAL(clicked(bool)), this, SLOT(OnAdvancedChanged()));
connect(ui.chkGuiTrace, SIGNAL(clicked(bool)), this, SLOT(OnAdvancedChanged()));
connect(ui.chkDbgTrace, SIGNAL(clicked(bool)), this, SLOT(OnAdvancedChanged()));
connect(ui.chkHideOtherBoxes, SIGNAL(clicked(bool)), this, SLOT(OnAdvancedChanged()));
connect(ui.btnAddProcess, SIGNAL(pressed()), this, SLOT(OnAddProcess()));
@ -356,7 +357,7 @@ void COptionsWindow::LoadConfig()
LoadStop();
{
ui.chkStartBlockMsg->setEnabled(ui.radStartAll->isChecked());
ui.chkStartBlockMsg->setEnabled(!ui.radStartAll->isChecked());
ui.chkStartBlockMsg->setChecked(m_pBox->GetBool("NotifyStartRunAccessDenied", true));
m_StartChanged = false;
@ -392,6 +393,7 @@ void COptionsWindow::LoadConfig()
ReadAdvancedCheck("KeyTrace", ui.chkKeyTrace, "*");
ReadAdvancedCheck("IpcTrace", ui.chkIpcTrace, "*");
ReadAdvancedCheck("GuiTrace", ui.chkGuiTrace, "*");
ui.chkDbgTrace->setChecked(m_pBox->GetBool("DebugTrace", false));
ui.chkHideOtherBoxes->setChecked(m_pBox->GetBool("HideOtherBoxes", false));
QStringList Processes = m_pBox->GetTextList("HideHostProcess", false);
@ -507,6 +509,7 @@ void COptionsWindow::SaveConfig()
WriteAdvancedCheck(ui.chkKeyTrace, "KeyTrace", "*");
WriteAdvancedCheck(ui.chkIpcTrace, "IpcTrace", "*");
WriteAdvancedCheck(ui.chkGuiTrace, "GuiTrace", "*");
WriteAdvancedCheck(ui.chkDbgTrace, "DebugTrace", "y");
WriteAdvancedCheck(ui.chkHideOtherBoxes, "HideOtherBoxes");
@ -992,7 +995,7 @@ void COptionsWindow::OnRestrictStart()
else
DelAccessEntry(eIPC, "<StartRunAccess>", eClosed, "*");
ui.chkStartBlockMsg->setEnabled(ui.radStartAll->isChecked());
ui.chkStartBlockMsg->setEnabled(!ui.radStartAll->isChecked());
//m_StartChanged = true;
}
@ -1011,6 +1014,8 @@ void COptionsWindow::OnDelStartProg()
void COptionsWindow::OnBlockINet()
{
bool Enable = ui.chkBlockINet->isChecked();
ui.chkINetBlockPrompt->setEnabled(Enable);
ui.chkINetBlockMsg->setEnabled(Enable);
if (Enable)
SetAccessEntry(eFile, "!<InternetAccess>", eClosed, "InternetAccessDevices");
else
@ -1030,14 +1035,6 @@ void COptionsWindow::OnDelINetProg()
//m_INetBlockChanged = true;
}
void COptionsWindow::OnINetBlockChanged()
{
ui.chkINetBlockPrompt->setEnabled(ui.chkBlockINet->isChecked());
ui.chkINetBlockMsg->setEnabled(ui.chkBlockINet->isChecked());
m_INetBlockChanged = true;
}
void COptionsWindow::AddProgToGroup(QTreeWidget* pTree, const QString& Groupe)
{
QString Value = SelectProgram();

View File

@ -87,7 +87,7 @@ private slots:
void OnGeneralChanged();
void OnStartChanged() { m_StartChanged = true; }
//void OnRestrictionChanged() { m_RestrictionChanged = true; }
void OnINetBlockChanged();
void OnINetBlockChanged() { m_INetBlockChanged = true; }
void OnRecoveryChanged() { m_RecoveryChanged = true; }
void OnAdvancedChanged();
void OnDebugChanged();

View File

@ -28,6 +28,13 @@ CSettingsWindow::CSettingsWindow(QWidget *parent)
ui.chkAutoStart->setChecked(IsAutorunEnabled());
switch (theConf->GetInt("Options/CheckForUpdates", 2)) {
case 0: ui.chkAutoUpdate->setCheckState(Qt::Unchecked); break;
case 1: ui.chkAutoUpdate->setCheckState(Qt::Checked); break;
case 2: ui.chkAutoUpdate->setCheckState(Qt::PartiallyChecked); break;
}
ui.chkShellMenu->setCheckState((Qt::CheckState)CSbieUtils::IsContextMenu());
ui.chkDarkTheme->setChecked(theConf->GetBool("Options/DarkTheme", false));
@ -140,6 +147,12 @@ void CSettingsWindow::apply()
AutorunEnable(ui.chkAutoStart->isChecked());
switch (ui.chkAutoUpdate->checkState()) {
case Qt::Unchecked: theConf->SetValue("Options/CheckForUpdates", 0); break;
case Qt::PartiallyChecked: theConf->SetValue("Options/CheckForUpdates", 2); break;
case Qt::Checked: theConf->SetValue("Options/CheckForUpdates", 1); break;
}
if (ui.chkShellMenu->checkState() != CSbieUtils::IsContextMenu())
{
if (ui.chkShellMenu->isChecked())

View File

@ -10,9 +10,6 @@
CSettings* theConf = NULL;
void PackDriver();
void UnPackDrivers();
int main(int argc, char *argv[])
{
#ifdef Q_OS_WIN
@ -25,11 +22,6 @@ int main(int argc, char *argv[])
QtSingleApplication app(argc, argv);
//InitConsole(false);
if (app.arguments().contains("-rc4"))
{
PackDriver();
return 0;
}
SB_STATUS Status = CSbieUtils::DoAssist();
if (Status.GetStatus()) {
@ -42,8 +34,6 @@ int main(int argc, char *argv[])
theConf = new CSettings("Sandboxie-Plus");
UnPackDrivers();
//QThreadPool::globalInstance()->setMaxThreadCount(theConf->GetInt("Options/MaxThreadPool", 10));
CSandMan* pWnd = new CSandMan();
@ -58,118 +48,3 @@ int main(int argc, char *argv[])
return ret;
}
bool TransformFile(const QString& InName, const QString& OutName, const QString& Key = "default_key")
{
QFile InFile(InName);
QFile OutFile(OutName);
if (InFile.open(QIODevice::ReadOnly))
{
if (OutFile.open(QIODevice::WriteOnly))
{
rc4_sbox_s sbox;
rc4_init(&sbox, Key.toLatin1());
OutFile.write(rc4_transform(&sbox, InFile.readAll()));
OutFile.flush();
return true;
}
}
return false;
}
bool TestFile(const QString& OutName)
{
QThread::sleep(3);
return QFile::exists(OutName);
}
void PackDriver()
{
int pos = QCoreApplication::arguments().indexOf("-rc4");
QString InName = QCoreApplication::arguments().at(pos + 1);
QString OutName = InName;
if (OutName.right(4) == ".rc4")
OutName.truncate(OutName.length() - 4);
else
OutName.append(".rc4");
if (TransformFile(InName, OutName))
printf("success\r\n");
else
printf("failed\r\n");
}
bool NotifyCert()
{
QString Caption = QObject::tr(
"<h3>Important Notie</h3>"
);
QString Text = QObject::tr(
"<p>Sandboxie requires a driver to operate (SbieDrv.sys), Windows however denies loading a driver file that has not been digitally signed using an expensive <b>EV-Code Signing Certificate</b>. "
"Such certificates cost upwards of 1000$ per year!</p>"
"<p>Luckily brave hackers have Leaked a few of these Certificates over the years, one of them was found by the author of this software and put to good use.</p>"
"<p>Unfortunately, such certificates have been abused by malware authors resulting in many Anti Malware Fools being Lazy and flagging Everything signed with them Wrongfully as Malware. "
"This Prejudice is Damaging the Open Source Ecosystem as most nonprofit developers can't afford to waste this kind of money every year only to pay that <u>Windows Kernel \"Tax\"</u>.</p>"
"<p>Therefore, the required driver is provided in an obfuscated form and before use must be unpacked. "
"<font color='red'>When doing so said said Anti Viruses will complain and attempt to destroy the freshly created file.</font> "
"Please be aware that this is a <u>false positive</u> caused by the necessary use of a compromitted certificate. "
"If this happens you will be notified and offered the option to repeat the unpacking operation, for the operation to succeed you will need to <u>configure an aproproate exemption</u>.</p>"
"<p></p>"
"<p><b>If you want the project to obtain a genuine EV-Code Signing Certificate please visit the <a href=\"https://xanasoft.com/\">Homepage</a> <font color='red'>and please donate</font></b>.</p>"
"<p></p>"
"<p>If you want to proceed with the unpacking of the driver pres YES.</p>"
);
QMessageBox *msgBox = new QMessageBox(NULL);
msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->setWindowTitle("Sandboxie-Plus");
msgBox->setText(Caption);
msgBox->setInformativeText(Text);
msgBox->setStandardButtons(QMessageBox::Yes);
msgBox->addButton(QMessageBox::No);
msgBox->setDefaultButton(QMessageBox::Yes);
QIcon ico(QLatin1String(":/SandMan.png"));
msgBox->setIconPixmap(ico.pixmap(64, 64));
return msgBox->exec() == QMessageBox::Yes;
}
void UnPackDrivers()
{
bool notifyNotOk = false;
QDir appDir(QApplication::applicationDirPath());
foreach(const QString& FileName, appDir.entryList(QStringList("*.sys.rc4"), QDir::Files))
{
QString InName = QApplication::applicationDirPath() + "/" + FileName;
QString OutName = InName.mid(0, InName.length() - 4);
QFileInfo InInfo(InName);
QFileInfo OutInfo(OutName);
if (InInfo.size() != OutInfo.size() /*|| InInfo.lastModified() > OutInfo.lastModified()*/)
{
if (theConf->GetBool("Options/NotifyUnPack", true)) {
if (!NotifyCert()) {
notifyNotOk = true;
break;
}
theConf->SetValue("Options/NotifyUnPack", false);
}
retry:
if (!TransformFile(InName, OutName))
QMessageBox::warning(NULL, "Sandboxie-Plus", QObject::tr("Failed to decrypt %1 ensure app directory is writable.").arg(FileName));
else if (!TestFile(OutName))
{
if (QMessageBox("Sandboxie-Plus",
QObject::tr("The decrypted file %1 seam to have been removed. Retry file extraction?").arg(FileName),
QMessageBox::Information, QMessageBox::Yes | QMessageBox::Default, QMessageBox::Cancel, QMessageBox::NoButton).exec() == QMessageBox::Yes)
goto retry;
notifyNotOk = true;
}
}
}
if (notifyNotOk)
QMessageBox::warning(NULL, "Sandboxie-Plus", QObject::tr("Without the Driver Sandboxie-Plus wont be able to run properly."));
}