diff --git a/CHANGELOG.md b/CHANGELOG.md
index f504f77ccc..1bbdc92739 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,28 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
+## [0.3.5 / 5.42.1] - 2020-07-19
+
+### Added
+- Added settings window
+- added translationsupport
+- added dark theme
+- added auto start option
+- added sandbox options
+- added debug option "NoAddProcessToJob=y"
+
+### Changed
+- improved empty sandbox tray icon
+- improved message parsing
+- updated homepage links
+
+### Fixed
+- fixed ini issue with sandman.exe when renaming sandboxes
+- fixed ini auto reload bug introduced in the last build
+- fixed issue when hooking delayd loaded libraries
+
+
+
## [0.3 / 5.42] - 2020-07-04
### Added
diff --git a/Sandboxie/apps/common/RunBrowser.cpp b/Sandboxie/apps/common/RunBrowser.cpp
index 9d45f98be3..a4b29798d5 100644
--- a/Sandboxie/apps/common/RunBrowser.cpp
+++ b/Sandboxie/apps/common/RunBrowser.cpp
@@ -134,7 +134,7 @@ void CRunBrowser::OnNo()
CString CRunBrowser::GetTopicUrl(const CString &topic)
{
- return L"https://www.sandboxie.com/index.php?" + topic;
+ return L"https://xanasoft.com/Sandboxie/" + topic;
}
@@ -155,5 +155,5 @@ void CRunBrowser::OpenHelp(CWnd *pParentWnd, const CString &topic)
void CRunBrowser::OpenForum(CWnd *pParentWnd)
{
- CRunBrowser x(pParentWnd, L"http://forums.sandboxie.com/phpBB3/");
+ CRunBrowser x(pParentWnd, L"https://forum.xanasoft.com/");
}
diff --git a/Sandboxie/apps/control/LockConfigDialog.cpp b/Sandboxie/apps/control/LockConfigDialog.cpp
index cbb90a494a..82d617929f 100644
--- a/Sandboxie/apps/control/LockConfigDialog.cpp
+++ b/Sandboxie/apps/control/LockConfigDialog.cpp
@@ -246,11 +246,11 @@ void CLockConfigDialog::OnOK()
ini.SetRestrictions(
isEditAdminOnly, isForceDisableAdminOnly, isForgetPassword);
- if ((*m_NewPassword) || isEditAdminOnly) {
- int rv = CMyApp::MsgBox(this, MSG_4269, MB_YESNO);
- if (rv == IDYES)
- CRunBrowser::OpenHelp(this, L"ConfigurationProtection");
- }
+ //if ((*m_NewPassword) || isEditAdminOnly) {
+ // int rv = CMyApp::MsgBox(this, MSG_4269, MB_YESNO);
+ // if (rv == IDYES)
+ // CRunBrowser::OpenHelp(this, L"ConfigurationProtection");
+ //}
EndDialog(0);
}
diff --git a/Sandboxie/apps/control/MyFrame.cpp b/Sandboxie/apps/control/MyFrame.cpp
index 5a9bc5eb25..9e68376a69 100644
--- a/Sandboxie/apps/control/MyFrame.cpp
+++ b/Sandboxie/apps/control/MyFrame.cpp
@@ -223,7 +223,8 @@ CMyFrame::CMyFrame(BOOL ForceVisible, BOOL ForceSync)
AdjustSizePosition(left, top, width, height);
ULONG exStyle = (CMyApp::m_LayoutRTL) ? WS_EX_LAYOUTRTL : 0;
- CreateEx( exStyle, (LPCTSTR)CMyApp::m_atom, CMyApp::m_appTitle,
+ CString strTitle = CMyApp::m_appTitle + " - xanasoft.com";
+ CreateEx( exStyle, (LPCTSTR)CMyApp::m_atom, strTitle,
WS_OVERLAPPEDWINDOW | WS_CAPTION | WS_SYSMENU,
left, top, width, height,
NULL, NULL, NULL);
diff --git a/Sandboxie/common/my_version.h b/Sandboxie/common/my_version.h
index 73140ed22c..37a84097ac 100644
--- a/Sandboxie/common/my_version.h
+++ b/Sandboxie/common/my_version.h
@@ -20,8 +20,8 @@
#ifndef _MY_VERSION_H
#define _MY_VERSION_H
-#define MY_VERSION_BINARY 5,42,0
-#define MY_VERSION_STRING "5.42.0"
+#define MY_VERSION_BINARY 5,42,1
+#define MY_VERSION_STRING "5.42.1"
#define MY_VERSION_COMPAT "5.42"
// These #defines are used by either Resource Compiler, or by NSIC installer
diff --git a/Sandboxie/core/dll/SboxDll32.def b/Sandboxie/core/dll/SboxDll32.def
index c8b219e23d..3cdd716fb7 100644
--- a/Sandboxie/core/dll/SboxDll32.def
+++ b/Sandboxie/core/dll/SboxDll32.def
@@ -27,7 +27,7 @@ SbieApi_GetHomePath=_SbieApi_GetHomePath@16
SbieApi_GetUnmountHive=_SbieApi_GetUnmountHive@4
SbieApi_GetVersion=_SbieApi_GetVersion@4
;;; SbieApi_GetWork=_SbieApi_GetWork@12
-SbieApi_GetMessage=_SbieApi_GetMessage@20
+SbieApi_GetMessage=_SbieApi_GetMessage@24
SbieApi_HookTramp=_SbieApi_HookTramp@8
diff --git a/Sandboxie/core/dll/dllhook.c b/Sandboxie/core/dll/dllhook.c
index e9cd2abd61..82a2c78445 100644
--- a/Sandboxie/core/dll/dllhook.c
+++ b/Sandboxie/core/dll/dllhook.c
@@ -178,6 +178,12 @@ skip_e9_rewrite: ;
SourceFunc = (void *)target;
}
+ //
+ // this simplification fails for delay loaded libraries, see coments about SetSecurityInfo,
+ // resulting in an endless loop, so just dont do that
+ //
+
+#if 0
//
// 64-bit only: if the function begins with 'jmp qword ptr [x]'
// (6 bytes) then replace the value at x, rather than overwrite
@@ -216,6 +222,7 @@ skip_e9_rewrite: ;
return orig_addr;
}
+#endif
#endif _WIN64
diff --git a/Sandboxie/core/drv/process.c b/Sandboxie/core/drv/process.c
index 0c9e85dda5..edda776694 100644
--- a/Sandboxie/core/drv/process.c
+++ b/Sandboxie/core/drv/process.c
@@ -1024,7 +1024,7 @@ _FX void Process_NotifyProcess_Create(
// don't put the process into a job if OpenWinClass=*
//
- if (new_proc->open_all_win_classes) {
+ if (new_proc->open_all_win_classes || Conf_Get_Boolean(box->name, L"NoAddProcessToJob", 0, FALSE)) {
add_process_to_job = FALSE;
}
diff --git a/Sandboxie/install/ParseVersion.bat b/Sandboxie/install/ParseVersion.bat
index 25221c7aa9..11017a031a 100644
--- a/Sandboxie/install/ParseVersion.bat
+++ b/Sandboxie/install/ParseVersion.bat
@@ -12,7 +12,7 @@ echo. > %OUTPUT%
for /F "tokens=3*" %%A in ('findstr /R "^#define.SBIE_INSTALLER_PATH\>" %INPUT%') do ( echo ^^!define SBIE_INSTALLER_PATH %%A) >> %OUTPUT%
-for /F "tokens=3*" %%A in ('findstr /R "^#define.MY_VERSION_STRING_EX\>" %INPUT%') do ( echo ^^!define VERSION %%A) >> %OUTPUT%
+for /F "tokens=3*" %%A in ('findstr /R "^#define.MY_VERSION_STRING\>" %INPUT%') do ( echo ^^!define VERSION %%A) >> %OUTPUT%
for /F "tokens=3*" %%A in ('findstr /R "^#define.MY_PRODUCT_NAME_STRING\>" %INPUT%') do ( set C=%%A %%B& echo ^^!define PRODUCT_FULL_NAME !C! & set C=!C: =!& echo ^^!define PRODUCT_NAME !C!) >> %OUTPUT%
diff --git a/Sandboxie/install/SandboxieVS.nsi b/Sandboxie/install/SandboxieVS.nsi
index ff83f5ea37..7d178c8674 100644
--- a/Sandboxie/install/SandboxieVS.nsi
+++ b/Sandboxie/install/SandboxieVS.nsi
@@ -28,7 +28,9 @@ SetCompressor /SOLID /FINAL lzma
; these are the build-time config settings. Need to be cmd line args or something better.
; pick either 32 or 64 bit
;!define _BUILDARCH Win32
-!define _BUILDARCH x64
+;!define _BUILDARCH x64
+!define _BUILDARCH "$%SBIE_BUILDARCH%"
+
; uncomment this line if you want to make the special versions that download VC Redist
;!define INCLUDE_VCREDIST_DNLD
diff --git a/SandboxiePlus/MiscHelpers/Common/ComboInputDialog.cpp b/SandboxiePlus/MiscHelpers/Common/ComboInputDialog.cpp
index d90f3572bc..dc77e2448c 100644
--- a/SandboxiePlus/MiscHelpers/Common/ComboInputDialog.cpp
+++ b/SandboxiePlus/MiscHelpers/Common/ComboInputDialog.cpp
@@ -132,6 +132,11 @@ void CComboInputDialog::setValue(const QString &t)
d->combo->setCurrentIndex(idx);
}
+int CComboInputDialog::findValue(const QString &t) const
+{
+ return d->combo->findText(t);
+}
+
QVariant CComboInputDialog::data() const
{
return d->combo->currentData();
@@ -142,6 +147,11 @@ void CComboInputDialog::setData(const QVariant & v)
d->combo->setCurrentIndex(d->combo->findData(v));
}
+int CComboInputDialog::findData(const QVariant & v) const
+{
+ return d->combo->findData(v);
+}
+
QPixmap CComboInputDialog::iconPixmap() const
{
if (const QPixmap *p = d->pixmapLabel->pixmap())
diff --git a/SandboxiePlus/MiscHelpers/Common/ComboInputDialog.h b/SandboxiePlus/MiscHelpers/Common/ComboInputDialog.h
index bee2a39407..b2667c208c 100644
--- a/SandboxiePlus/MiscHelpers/Common/ComboInputDialog.h
+++ b/SandboxiePlus/MiscHelpers/Common/ComboInputDialog.h
@@ -28,10 +28,11 @@ class MISCHELPERS_EXPORT CComboInputDialog: public QDialog
QString value() const;
void setValue(const QString &);
+ int findValue(const QString &) const;
QVariant data() const;
void setData(const QVariant &);
-
+ int findData(const QVariant &) const;
QDialogButtonBox::StandardButtons standardButtons() const;
void setStandardButtons(QDialogButtonBox::StandardButtons s);
diff --git a/SandboxiePlus/QSbieAPI/QSbieAPI.vcxproj b/SandboxiePlus/QSbieAPI/QSbieAPI.vcxproj
index bce3bbe30e..73d4ea12fb 100644
--- a/SandboxiePlus/QSbieAPI/QSbieAPI.vcxproj
+++ b/SandboxiePlus/QSbieAPI/QSbieAPI.vcxproj
@@ -185,9 +185,10 @@
+
-
+
@@ -203,7 +204,8 @@
-
+
+
diff --git a/SandboxiePlus/QSbieAPI/QSbieAPI.vcxproj.filters b/SandboxiePlus/QSbieAPI/QSbieAPI.vcxproj.filters
index 418e655f6f..10d33791c2 100644
--- a/SandboxiePlus/QSbieAPI/QSbieAPI.vcxproj.filters
+++ b/SandboxiePlus/QSbieAPI/QSbieAPI.vcxproj.filters
@@ -39,12 +39,15 @@
Sandboxie
-
- Sandboxie
-
SbieAPI
+
+ Sandboxie
+
+
+ Sandboxie
+
@@ -78,7 +81,10 @@
SbieAPI
-
+
+ Sandboxie
+
+
Sandboxie
diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp
index d2d0c8f71f..e8ffadf09d 100644
--- a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp
+++ b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp
@@ -23,7 +23,7 @@
//{
//};
-CSandBox::CSandBox(const QString& BoxName, class CSbieAPI* pAPI) : CIniSection(BoxName, pAPI)
+CSandBox::CSandBox(const QString& BoxName, class CSbieAPI* pAPI) : CSbieIni(BoxName, pAPI)
{
//m = new SSandBox;
@@ -41,7 +41,7 @@ CSandBox::CSandBox(const QString& BoxName, class CSbieAPI* pAPI) : CIniSection(B
}
else
{
- SetBool("AutoRecover", true);
+ SetBool("AutoRecover", false);
SetBool("BlockNetworkFiles", true);
//SetDefaultTemplates6(*this); // why 6?
diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h
index e32a1989b3..c6fa475a2f 100644
--- a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h
+++ b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h
@@ -21,9 +21,9 @@
#include "../qsbieapi_global.h"
#include "BoxedProcess.h"
-#include "IniSection.h"
+#include "SbieIni.h"
-class QSBIEAPI_EXPORT CSandBox : public CIniSection
+class QSBIEAPI_EXPORT CSandBox : public CSbieIni
{
Q_OBJECT
public:
@@ -32,8 +32,6 @@ class QSBIEAPI_EXPORT CSandBox : public CIniSection
virtual void UpdateDetails();
- virtual QString GetName() const { return m_Name; }
-
virtual QString GetFileRoot() const { return m_FilePath; }
virtual QString GetRegRoot() const { return m_RegPath; }
virtual QString GetIpcRoot() const { return m_IpcPath; }
diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/IniSection.cpp b/SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.cpp
similarity index 57%
rename from SandboxiePlus/QSbieAPI/Sandboxie/IniSection.cpp
rename to SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.cpp
index 4403455032..3c88b64213 100644
--- a/SandboxiePlus/QSbieAPI/Sandboxie/IniSection.cpp
+++ b/SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.cpp
@@ -16,7 +16,7 @@
* along with this program. If not, see .
*/
#include "stdafx.h"
-#include "IniSection.h"
+#include "SbieIni.h"
#include "../SbieAPI.h"
#include
@@ -25,39 +25,39 @@ typedef long NTSTATUS;
#include "..\..\Sandboxie\core\drv\api_flags.h"
-CIniSection::CIniSection(const QString& Section, class CSbieAPI* pAPI, QObject* parent) : QObject(parent)
+CSbieIni::CSbieIni(const QString& Section, class CSbieAPI* pAPI, QObject* parent) : QObject(parent)
{
m_Name = Section;
m_pAPI = pAPI;
}
-CIniSection::~CIniSection()
+CSbieIni::~CSbieIni()
{
}
-SB_STATUS CIniSection::SetText(const QString& Setting, const QString& Value)
+SB_STATUS CSbieIni::SetText(const QString& Setting, const QString& Value)
{
if (GetText(Setting) == Value)
return SB_OK;
return m_pAPI->SbieIniSet(m_Name, Setting, Value);
}
-SB_STATUS CIniSection::SetNum(const QString& Setting, int Value)
+SB_STATUS CSbieIni::SetNum(const QString& Setting, int Value)
{
return SetText(Setting, QString::number(Value));
}
-SB_STATUS CIniSection::SetNum64(const QString& Setting, __int64 Value)
+SB_STATUS CSbieIni::SetNum64(const QString& Setting, __int64 Value)
{
return SetText(Setting, QString::number(Value));
}
-SB_STATUS CIniSection::SetBool(const QString& Setting, bool Value)
+SB_STATUS CSbieIni::SetBool(const QString& Setting, bool Value)
{
return SetText(Setting, Value ? "y" : "n");
}
-QString CIniSection::GetText(const QString& Setting, const QString& Default) const
+QString CSbieIni::GetText(const QString& Setting, const QString& Default) const
{
int flags = (m_Name.isEmpty() ? 0 : CONF_GET_NO_GLOBAL) | CONF_GET_NO_EXPAND;
QString Value = m_pAPI->SbieIniGet(m_Name, Setting, flags);
@@ -65,7 +65,7 @@ QString CIniSection::GetText(const QString& Setting, const QString& Default) con
return Value;
}
-int CIniSection::GetNum(const QString& Setting, int Default) const
+int CSbieIni::GetNum(const QString& Setting, int Default) const
{
QString StrValue = GetText(Setting);
bool ok;
@@ -74,7 +74,7 @@ int CIniSection::GetNum(const QString& Setting, int Default) const
return Value;
}
-__int64 CIniSection::GetNum64(const QString& Setting, __int64 Default) const
+__int64 CSbieIni::GetNum64(const QString& Setting, __int64 Default) const
{
QString StrValue = GetText(Setting);
bool ok;
@@ -83,7 +83,7 @@ __int64 CIniSection::GetNum64(const QString& Setting, __int64 Default) const
return Value;
}
-bool CIniSection::GetBool(const QString& Setting, bool Default) const
+bool CSbieIni::GetBool(const QString& Setting, bool Default) const
{
QString StrValue = GetText(Setting);
if (StrValue.compare("y", Qt::CaseInsensitive) == 0)
@@ -93,15 +93,15 @@ bool CIniSection::GetBool(const QString& Setting, bool Default) const
return Default;
}
-QStringList CIniSection::GetTextList(const QString &Setting, bool withBrackets)
+QStringList CSbieIni::GetTextList(const QString &Setting, bool withTemplates) const
{
QStringList TextList;
int flags = (m_Name.isEmpty() ? 0 : CONF_GET_NO_GLOBAL) | CONF_GET_NO_EXPAND;
- if (withBrackets)
+ if (!withTemplates)
flags |= CONF_GET_NO_TEMPLS;
- for(int index = 0; ; index++)
+ for (int index = 0; ; index++)
{
QString Value = m_pAPI->SbieIniGet(m_Name, Setting, index | flags);
if (Value.isNull())
@@ -112,35 +112,80 @@ QStringList CIniSection::GetTextList(const QString &Setting, bool withBrackets)
return TextList;
}
-SB_STATUS CIniSection::InsertText(const QString& Setting, const QString& Value)
+SB_STATUS CSbieIni::UpdateTextList(const QString &Setting, const QStringList& List)
+{
+ QStringList OldSettings = GetTextList(Setting);
+ QStringList NewSettings;
+ foreach(const QString& Value, List) {
+ if (!OldSettings.removeOne(Value))
+ NewSettings.append(Value);
+ }
+ // delete removed or changed settings
+ foreach(const QString& Value, OldSettings)
+ DelValue(Setting, Value);
+ // add new or changed settings
+ foreach(const QString& Value, NewSettings)
+ InsertText(Setting, Value);
+ return SB_OK;
+}
+
+QStringList CSbieIni::GetTemplates() const
+{
+ QStringList Templates;
+
+ for (int tmpl_index = 0; ; tmpl_index++)
+ {
+ QString TmplName = m_pAPI->SbieIniGet(m_Name, "Template", tmpl_index | CONF_GET_NO_TEMPLS);
+ if (TmplName.isNull())
+ break;
+ Templates.append(TmplName);
+ }
+
+ return Templates;
+}
+
+QStringList CSbieIni::GetTextListTmpl(const QString &Setting, const QString& Template) const
+{
+ QStringList TextList;
+
+ for (int index = 0; ; index++)
+ {
+ QString Value = m_pAPI->SbieIniGet("Template_" + Template, Setting, index | CONF_GET_NO_GLOBAL);
+ if (Value.isNull())
+ break;
+ TextList.append(Value);
+ }
+
+ return TextList;
+}
+
+SB_STATUS CSbieIni::InsertText(const QString& Setting, const QString& Value)
{
return m_pAPI->SbieIniSet(m_Name, Setting, Value, CSbieAPI::eIniInsert);
}
-SB_STATUS CIniSection::AppendText(const QString& Setting, const QString& Value)
+SB_STATUS CSbieIni::AppendText(const QString& Setting, const QString& Value)
{
return m_pAPI->SbieIniSet(m_Name, Setting, Value, CSbieAPI::eIniAppend);
}
-SB_STATUS CIniSection::DelValue(const QString& Setting, const QString& Value)
+SB_STATUS CSbieIni::DelValue(const QString& Setting, const QString& Value)
{
return m_pAPI->SbieIniSet(m_Name, Setting, Value, CSbieAPI::eIniDelete);
}
-
-SB_STATUS CIniSection::RenameSection( const QString& NewName, bool deleteOld) // Note: deleteOld is used when duplicating a box
+QList> CSbieIni::GetIniSection(qint32* pStatus, bool withTemplates) const
{
- if (m_Name.isEmpty() || NewName.isEmpty())
- return SB_ERR();
- bool SameName = (bool)(NewName.compare(m_Name, Qt::CaseInsensitive) == 0);
-
qint32 status = STATUS_SUCCESS;
- // Get all Settigns
+ int flags = CONF_GET_NO_EXPAND;
+ if (!withTemplates)
+ flags |= CONF_GET_NO_TEMPLS;
+
QList> Settings;
for (int setting_index = 0; ; setting_index++)
{
- QString setting_name = m_pAPI->SbieIniGet(m_Name, NULL, setting_index | CONF_GET_NO_TEMPLS | CONF_GET_NO_EXPAND, &status);
+ QString setting_name = m_pAPI->SbieIniGet(m_Name, "", setting_index | flags, &status);
if (status == STATUS_RESOURCE_NAME_NOT_FOUND) {
status = STATUS_SUCCESS;
break;
@@ -150,7 +195,7 @@ SB_STATUS CIniSection::RenameSection( const QString& NewName, bool deleteOld) //
for (int value_index = 0; ; value_index++)
{
- QString setting_value = m_pAPI->SbieIniGet(m_Name, setting_name, value_index | CONF_GET_NO_GLOBAL | CONF_GET_NO_TEMPLS | CONF_GET_NO_EXPAND, &status);
+ QString setting_value = m_pAPI->SbieIniGet(m_Name, setting_name, value_index | CONF_GET_NO_GLOBAL | flags, &status);
if (status == STATUS_RESOURCE_NAME_NOT_FOUND) {
status = STATUS_SUCCESS;
break;
@@ -165,13 +210,27 @@ SB_STATUS CIniSection::RenameSection( const QString& NewName, bool deleteOld) //
break;
}
+ if (pStatus) *pStatus = status;
+ return Settings;
+}
+
+SB_STATUS CSbieIni::RenameSection( const QString& NewName, bool deleteOld) // Note: deleteOld is used when duplicating a box
+{
+ qint32 status = STATUS_SUCCESS;
+
+ if (m_Name.isEmpty() || NewName.isEmpty())
+ return SB_ERR();
+ bool SameName = (bool)(NewName.compare(m_Name, Qt::CaseInsensitive) == 0);
+
+ // Get all Settigns
+ QList> Settings = GetIniSection(&status);
if (status != STATUS_SUCCESS)
return SB_ERR(CSbieAPI::tr("Failed to copy configuration from sandbox %1: %2").arg(m_Name).arg(status, 8, 16), status);
// check if such a box already exists
if (!SameName)
{
- m_pAPI->SbieIniGet(NewName, NULL, CONF_GET_NO_EXPAND, &status);
+ m_pAPI->SbieIniGet(NewName, "", CONF_GET_NO_EXPAND, &status);
if (status != STATUS_RESOURCE_NAME_NOT_FOUND)
return SB_ERR(CSbieAPI::tr("A sandbox of the name %1 already exists").arg(NewName));
}
@@ -185,7 +244,7 @@ SB_STATUS CIniSection::RenameSection( const QString& NewName, bool deleteOld) //
// Apply all Settigns
for (QList>::iterator I = Settings.begin(); I != Settings.end(); ++I)
{
- SB_STATUS Status = m_pAPI->SbieIniSet(NewName, I->first, I->second);
+ SB_STATUS Status = m_pAPI->SbieIniSet(NewName, I->first, I->second, CSbieAPI::eIniInsert);
if (Status.IsError())
return Status;
}
@@ -206,7 +265,7 @@ SB_STATUS CIniSection::RenameSection( const QString& NewName, bool deleteOld) //
return SB_OK;
}
-SB_STATUS CIniSection::RemoveSection()
+SB_STATUS CSbieIni::RemoveSection()
{
return m_pAPI->SbieIniSet(m_Name, "*", "");
}
\ No newline at end of file
diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/IniSection.h b/SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.h
similarity index 64%
rename from SandboxiePlus/QSbieAPI/Sandboxie/IniSection.h
rename to SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.h
index bcd80c534a..a3e5b27acc 100644
--- a/SandboxiePlus/QSbieAPI/Sandboxie/IniSection.h
+++ b/SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.h
@@ -5,12 +5,14 @@
#include "../SbieError.h"
-class QSBIEAPI_EXPORT CIniSection: public QObject
+class QSBIEAPI_EXPORT CSbieIni: public QObject
{
Q_OBJECT
public:
- CIniSection(const QString& Section, class CSbieAPI* pAPI, QObject* parent = 0);
- virtual ~CIniSection();
+ CSbieIni(const QString& Section, class CSbieAPI* pAPI, QObject* parent = 0);
+ virtual ~CSbieIni();
+
+ virtual QString GetName() const { return m_Name; }
virtual SB_STATUS SetText(const QString& Setting, const QString& Value);
virtual SB_STATUS SetNum(const QString& Setting, int Value);
@@ -22,16 +24,23 @@ class QSBIEAPI_EXPORT CIniSection: public QObject
virtual __int64 GetNum64(const QString& Setting, __int64 Default = 0) const;
virtual bool GetBool(const QString& Setting, bool Default = false) const;
- virtual QStringList GetTextList(const QString &Setting, bool withBrackets = false);
+ virtual QStringList GetTextList(const QString &Setting, bool withTemplates = true) const;
+ virtual SB_STATUS UpdateTextList(const QString &Setting, const QStringList& List);
+ virtual QStringList GetTemplates() const;
+ virtual QStringList GetTextListTmpl(const QString &Setting, const QString& Template) const;
virtual SB_STATUS InsertText(const QString& Setting, const QString& Value);
virtual SB_STATUS AppendText(const QString& Setting, const QString& Value);
virtual SB_STATUS DelValue(const QString& Setting, const QString& Value);
+ virtual QList> GetIniSection(qint32* pStatus = NULL, bool withTemplates = false) const;
+
virtual SB_STATUS RenameSection(const QString& NewName, bool deleteOld = true);
virtual SB_STATUS RemoveSection();
+ CSbieAPI* GetAPI() { return m_pAPI; }
+
protected:
QString m_Name;
diff --git a/SandboxiePlus/QSbieAPI/SbieAPI.cpp b/SandboxiePlus/QSbieAPI/SbieAPI.cpp
index 6ab7ccc5d8..0c8398a346 100644
--- a/SandboxiePlus/QSbieAPI/SbieAPI.cpp
+++ b/SandboxiePlus/QSbieAPI/SbieAPI.cpp
@@ -72,7 +72,7 @@ struct SSbieAPI
ULONG SizeofPortMsg;
ULONG CallSeqNumber;
- QString Password; // todo: suppor lcoked configurations
+ QString Password;
ULONG sessionId;
@@ -111,6 +111,8 @@ CSbieAPI::CSbieAPI(QObject* parent) : QThread(parent)
{
m = new SSbieAPI();
+ m_pGlobalSection = new CSbieIni("GlobalSettings", this, this);
+
m_bReloadPending = false;
connect(&m_IniWatcher, SIGNAL(fileChanged(const QString&)), this, SLOT(OnIniChanged(const QString&)));
@@ -398,6 +400,11 @@ SB_STATUS CSbieAPI__CallServer(SSbieAPI* m, MSG_HEADER* req, MSG_HEADER** prpl)
SB_STATUS CSbieAPI::CallServer(void* req, void* rpl) const
{
+ //
+ // Note: Once we open a port to the server from a threat the service will remember it we can't reconnect after disconnection
+ // So for every new connection we need a new threat, we achive this by letting our monitor threat issue all requests
+ //
+
while (InterlockedCompareExchange(&m->SvcLock, SVC_OP_STATE_PREP, SVC_OP_STATE_IDLE) != SVC_OP_STATE_IDLE)
QThread::msleep(1);
@@ -535,6 +542,7 @@ void CSbieAPI::OnIniChanged(const QString &path)
void CSbieAPI::OnReloadConfig()
{
+ m_bReloadPending = false;
ReloadConfig();
}
@@ -668,7 +676,9 @@ SB_STATUS CSbieAPI::ReloadBoxes()
SB_STATUS CSbieAPI::SbieIniSet(void *RequestBuf, void *pPasswordWithinRequestBuf, const QString& SectionName, const QString& SettingName)
{
+retry:
m->Password.toWCharArray((WCHAR*)pPasswordWithinRequestBuf); // fix-me: potential overflow
+ ((WCHAR*)pPasswordWithinRequestBuf)[m->Password.length()] = L'\0';
MSG_HEADER *rpl = NULL;
SB_STATUS Status = CSbieAPI::CallServer((MSG_HEADER *)RequestBuf, &rpl);
@@ -679,8 +689,17 @@ SB_STATUS CSbieAPI::SbieIniSet(void *RequestBuf, void *pPasswordWithinRequestBuf
free(rpl);
if (status == 0)
return SB_OK;
- if (status == STATUS_LOGON_NOT_GRANTED || status == STATUS_WRONG_PASSWORD)
+ if (status == STATUS_LOGON_NOT_GRANTED || status == STATUS_WRONG_PASSWORD)
+ {
+ if (((MSG_HEADER *)RequestBuf)->msgid != MSGID_SBIE_INI_TEST_PASSWORD)
+ {
+ bool bRetry = false;
+ emit NotAuthorized(status == STATUS_WRONG_PASSWORD, bRetry);
+ if (bRetry)
+ goto retry;
+ }
return SB_ERR(CSbieAPI::tr("You are not authorized to update configuration in section '%1'").arg(SectionName), status);
+ }
return SB_ERR(CSbieAPI::tr("Failed to set configuration setting %1 in section %2: %3").arg(SettingName).arg(SectionName).arg(status, 8, 16), status);
}
@@ -1179,6 +1198,43 @@ bool CSbieAPI::IsBoxEnabled(const QString& BoxName)
return NT_SUCCESS(m->IoControl(parms));
}
+bool CSbieAPI::IsConfigLocked()
+{
+ return m->Password.isEmpty() && !SbieIniGet("GlobalSettings", "EditPassword", 0).isEmpty();
+}
+
+SB_STATUS CSbieAPI::UnlockConfig(const QString& Password)
+{
+ SBIE_INI_PASSWORD_REQ *req = (SBIE_INI_PASSWORD_REQ *)malloc(REQUEST_LEN);
+ req->h.msgid = MSGID_SBIE_INI_TEST_PASSWORD;
+ req->h.length = sizeof(SBIE_INI_PASSWORD_REQ);
+ m->Password = Password;
+ SB_STATUS Status = SbieIniSet(req, req->old_password, "GlobalSettings", "*");
+ if (Status.IsError())
+ m->Password.clear();
+ free(req);
+ return Status;
+}
+
+SB_STATUS CSbieAPI::LockConfig(const QString& NewPassword)
+{
+ SBIE_INI_PASSWORD_REQ *req = (SBIE_INI_PASSWORD_REQ *)malloc(REQUEST_LEN);
+ req->h.msgid = MSGID_SBIE_INI_SET_PASSWORD;
+ req->h.length = sizeof(SBIE_INI_PASSWORD_REQ);
+ m->Password.toWCharArray(req->new_password); // fix-me: potential overflow
+ req->new_password[m->Password.length()] = L'\0';
+ SB_STATUS Status = SbieIniSet(req, req->old_password, "GlobalSettings", "*");
+ if (!Status.IsError())
+ m->Password = NewPassword;
+ free(req);
+ return Status;
+}
+
+void CSbieAPI::ClearPassword()
+{
+ m->Password.clear();
+}
+
///////////////////////////////////////////////////////////////////////////////
// Log
//
@@ -1213,7 +1269,7 @@ bool CSbieAPI::GetLog()
wchar_t* Buffer[4*1024];
ULONG Length = ARRAYSIZE(Buffer);
- ULONG MessageId = 0;
+ ULONG MsgCode = 0;
ULONG ProcessId = 0;
ULONG MessageNum = m->lastMessageNum;
@@ -1225,7 +1281,7 @@ bool CSbieAPI::GetLog()
args->func_code = API_GET_MESSAGE;
args->msg_num.val = &MessageNum;
args->session_id.val = m->sessionId;
- args->msgid.val = &MessageId;
+ args->msgid.val = &MsgCode;
args->msgtext.val = &msgtext;
args->process_id.val = &ProcessId;
@@ -1237,7 +1293,7 @@ bool CSbieAPI::GetLog()
// we missed something
m->lastMessageNum = MessageNum;
- if (MessageId == 0)
+ if (MsgCode == 0)
return true; // empty dummy message for maintaining sequence consistency
WCHAR *str1 = (WCHAR*)msgtext.Buffer;
@@ -1245,7 +1301,36 @@ bool CSbieAPI::GetLog()
WCHAR *str2 = str1 + str1_len + 1;
ULONG str2_len = wcslen(str2);
- QString Message = CSbieAPI__FormatSbieMsg(m, MessageId, str1, str2);
+ //
+ // 0xTFFFMMMM
+ //
+ // T = ttcr
+ // tt = 00 - Ok
+ // tt = 01 - Info
+ // tt = 10 - Warning
+ // tt = 11 - Error
+ // c = unused
+ // r = reserved
+ //
+ // FFF = 0x000 UIstr
+ // FFF = 0x101 POPUP
+ // FFF = 0x102 EVENT
+ //
+ // MMMM = Message Code
+ //
+ quint8 Severity = MsgCode >> 30;
+ quint16 Facility = (MsgCode >> 16) & 0x0FFF;
+ quint16 MessageId= MsgCode & 0xFFFF;
+
+ if (MessageId == 2199) // Auto Recovery notification
+ {
+ QString TempStr = QString::fromWCharArray(str1);
+ int TempPos = TempStr.indexOf(" ");
+ FileToRecover(TempStr.left(TempPos), Nt2DosPath(TempStr.mid(TempPos + 1)));
+ return true;
+ }
+
+ QString Message = CSbieAPI__FormatSbieMsg(m, MsgCode, str1, str2);
if(ProcessId != 4) // if its not from the driver add the pid
Message += tr(" by process: %1").arg(ProcessId);
emit LogMessage(Message);
@@ -1253,6 +1338,45 @@ bool CSbieAPI::GetLog()
return true;
}
+///////////////////////////////////////////////////////////////////////////////
+// Forced Processes
+//
+
+SB_STATUS CSbieAPI::DisableForceProcess(bool Set)
+{
+ //m_pGlobalSection->SetNum("ForceDisableSeconds", Seconds);
+
+ ULONG uEnable = Set ? TRUE : FALSE;
+
+ __declspec(align(8)) ULONG64 parms[API_NUM_ARGS];
+ API_DISABLE_FORCE_PROCESS_ARGS* args = (API_DISABLE_FORCE_PROCESS_ARGS*)parms;
+
+ memset(parms, 0, sizeof(parms));
+ args->func_code = API_DISABLE_FORCE_PROCESS;
+ args->set_flag.val = &uEnable; // NewState
+ args->get_flag.val = NULL; // OldState
+
+ NTSTATUS status = m->IoControl(parms);
+ if (!NT_SUCCESS(status))
+ return SB_ERR(status);
+ return SB_OK;
+}
+
+bool CSbieAPI::AreForceProcessDisabled()
+{
+ ULONG uEnabled = FALSE;
+
+ __declspec(align(8)) ULONG64 parms[API_NUM_ARGS];
+ API_DISABLE_FORCE_PROCESS_ARGS* args = (API_DISABLE_FORCE_PROCESS_ARGS*)parms;
+
+ memset(parms, 0, sizeof(parms));
+ args->func_code = API_DISABLE_FORCE_PROCESS;
+ args->set_flag.val = NULL; // NewState
+ args->get_flag.val = &uEnabled; // OldState
+
+ return NT_SUCCESS(m->IoControl(parms)) && uEnabled;
+}
+
///////////////////////////////////////////////////////////////////////////////
// Monitor
//
@@ -1326,6 +1450,15 @@ bool CSbieAPI::GetMonitor()
return true;
}
+///////////////////////////////////////////////////////////////////////////////
+// Other
+//
+
+QString CSbieAPI::GetSbieMessage(int MessageId, const QString& arg1, const QString& arg2) const
+{
+ return CSbieAPI__FormatSbieMsg(m, MessageId, arg1.toStdWString().c_str(), arg2.toStdWString().c_str());
+}
+
///////////////////////////////////////////////////////////////////////////////
//
//
diff --git a/SandboxiePlus/QSbieAPI/SbieAPI.h b/SandboxiePlus/QSbieAPI/SbieAPI.h
index 83c1bcda0c..1ec3587005 100644
--- a/SandboxiePlus/QSbieAPI/SbieAPI.h
+++ b/SandboxiePlus/QSbieAPI/SbieAPI.h
@@ -108,6 +108,15 @@ class QSBIEAPI_EXPORT CSbieAPI : public QThread
virtual QString SbieIniGet(const QString& Section, const QString& Setting, quint32 Index = 0, qint32* ErrCode = NULL);
virtual SB_STATUS SbieIniSet(const QString& Section, const QString& Setting, const QString& Value, ESetMode Mode = eIniUpdate);
virtual bool IsBoxEnabled(const QString& BoxName);
+ virtual CSbieIni* GetGlobalSettings() const { return m_pGlobalSection; }
+ virtual bool IsConfigLocked();
+ virtual SB_STATUS UnlockConfig(const QString& Password);
+ virtual SB_STATUS LockConfig(const QString& NewPassword);
+ virtual void ClearPassword();
+
+ // Forced Processes
+ virtual SB_STATUS DisableForceProcess(bool Set);
+ virtual bool AreForceProcessDisabled();
// Monitor
virtual SB_STATUS EnableMonitor(bool Enable);
@@ -116,9 +125,14 @@ class QSBIEAPI_EXPORT CSbieAPI : public QThread
virtual QList GetResLog() const { QReadLocker Lock(&m_ResLogMutex); return m_ResLogList; }
virtual void ClearResLog() { QWriteLocker Lock(&m_ResLogMutex); m_ResLogList.clear(); }
+ // Other
+ virtual QString GetSbieMessage(int MessageId, const QString& arg1 = QString(), const QString& arg2 = QString()) const;
+
signals:
void StatusChanged();
void LogMessage(const QString& Message, bool bNotify = true);
+ void FileToRecover(const QString& BoxName, const QString& FilePath);
+ void NotAuthorized(bool bLoginRequired, bool &bRetry);
private slots:
//virtual void OnMonitorEntry(quint64 ProcessId, quint32 Type, const QString& Value);
@@ -169,6 +183,8 @@ private slots:
bool m_bTerminate;
+ CSbieIni* m_pGlobalSection;
+
private:
mutable QMutex m_ThreadMutex;
mutable QWaitCondition m_ThreadWait;
diff --git a/SandboxiePlus/SandMan/Forms/OptionsWindow.ui b/SandboxiePlus/SandMan/Forms/OptionsWindow.ui
new file mode 100644
index 0000000000..5961a002a7
--- /dev/null
+++ b/SandboxiePlus/SandMan/Forms/OptionsWindow.ui
@@ -0,0 +1,1126 @@
+
+
+ OptionsWindow
+
+
+
+ 0
+ 0
+ 614
+ 397
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ SandboxiePlus Options
+
+
+ -
+
+
-
+
+
+
+ true
+
+
+
+ QTabWidget::West
+
+
+ 0
+
+
+
+ General Options
+
+
+
-
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 75
+ true
+
+
+
+ Appearance
+
+
+
+ -
+
+
+ Copy file size limit:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 75
+ 16777215
+
+
+
+
+ -
+
+
+
+ 75
+ true
+
+
+
+ File Mrigration
+
+
+
+ -
+
+
+ Issue message 2102 when a file is too large
+
+
+
+ -
+
+
+ kilobytes
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ Sandbox Indicator in title:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Sandboxed window border:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+ Program Groups
+
+
+ -
+
+
-
+
+
+ You can group programs together and give them a group name. Program groups can be used with some of the settings instead of program names.
+
+
+ true
+
+
+
+ -
+
+
+ Add Group
+
+
+
+ -
+
+
+ Add Program
+
+
+
+ -
+
+
+ Remove
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ true
+
+
+
+ Name
+
+
+
+
+
+
+
+
+
+
+ Forced Programs
+
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+ -
+
+
-
+
+
+ Remove
+
+
+
+ -
+
+
+ Force Folder
+
+
+
+ -
+
+
+ true
+
+
+
+ Type
+
+
+
+
+ Path
+
+
+
+
+ -
+
+
+ Programs enteres here, or programs started from entered locations, will be put in this sandbox automatically, unless thay are explicitly started in an otehr sandbox.
+
+
+ true
+
+
+
+ -
+
+
+ Force Program
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Show Templates
+
+
+
+
+
+
+
+
+
+ Stop Behavioure
+
+
+ -
+
+
-
+
+
+ Remove Progam
+
+
+
+ -
+
+
+ Lingering programs will be automatically terminated is thay are still running after all other processes have terminated.
+
+If leader processes are defined all others are threated as lingering processes.
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Add Leader Program
+
+
+
+ -
+
+
+ Add Lingering Program
+
+
+
+ -
+
+
+ true
+
+
+
+ Type
+
+
+
+
+ Path
+
+
+
+
+ -
+
+
+ Show Templates
+
+
+
+
+
+
+
+
+
+ Start Restrictions
+
+
+ -
+
+
-
+
+
+ Add Program
+
+
+
+ -
+
+
+ true
+
+
+
+ Name
+
+
+
+
+ -
+
+
+ Issue message 1308 when a program fails to start
+
+
+
+ -
+
+
+ Note: Programs installed to this sandbox wont be able to start at all.
+
+
+ true
+
+
+
+ -
+
+
+ Remove Program
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Allow only sellected programs to start in this sandbox.
+
+
+
+
+
+
+
+
+
+ Other Restrictions
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 75
+ true
+
+
+
+ Protect the system from sandboxed processes
+
+
+ General restrictions
+
+
+
+ -
+
+
+
+ 75
+ true
+
+
+
+ Protect the sandbox integrity itself
+
+
+ Sandbox protection
+
+
+
+ -
+
+
+ Drop elevated privileges from processes
+
+
+
+ -
+
+
+ Block network files and folders, unless pecifically opened.
+
+
+
+ -
+
+
+ Don't open default COM objects
+
+
+
+ -
+
+
+ Limit access to the emulated service controll manager to privileged processes
+
+
+
+ -
+
+
+ Start the sandboxed RpcSs as a SYSTEM process
+
+
+
+ -
+
+
+ Protect sandboxed SYSTEM processes from unprivileged unsandboxed processes
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+
+
+
+
+ Internet Access
+
+
+ -
+
+
-
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Remove Program
+
+
+
+ -
+
+
+ Issue message 1307 when a program are denied internet
+
+
+
+ -
+
+
+ Add Program
+
+
+
+ -
+
+
+ true
+
+
+
+ Name
+
+
+
+
+ -
+
+
+ Block internet access for all programs except those added to the list.
+
+
+
+ -
+
+
+ Note: Programs installed to this sandbox wont be able access the internet at all.
+
+
+
+
+
+
+
+
+
+ Resource Access
+
+
+ -
+
+
-
+
+
+ true
+
+
+
+ Type
+
+
+
+
+ Program
+
+
+
+
+ Access
+
+
+
+
+ Path
+
+
+
+
+ -
+
+
+ Add Reg Key
+
+
+
+ -
+
+
+ Add File/Folder
+
+
+
+ -
+
+
+ Remove
+
+
+
+ -
+
+
+ Add Wnd Class
+
+
+
+ -
+
+
+ Add COM Object
+
+
+
+ -
+
+
+ Add IPC Path
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Move Up
+
+
+
+ -
+
+
+ Move Down
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Show Templates
+
+
+
+ -
+
+
+ Configure which processec can access what resoutrces.
+Double click on an entry to edit it.
+Note: Not all access modes are available to processes instaleld into a sandbox.
+
+
+
+
+
+
+
+
+
+ Advanced Options
+
+
+ -
+
+
-
+
+
+
+ 75
+ true
+
+
+
+ Allow only sellected users to use this sandbox
+
+
+ User restrictions
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Delete command:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Add User
+
+
+
+ -
+
+
+ -
+
+
+ Auto delete content when last sandboxed process terminates
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Protect this sandbox from deletion or emptying
+
+
+
+ -
+
+
+
+ 75
+ true
+
+
+
+ Delete options
+
+
+
+ -
+
+
+ Remove User
+
+
+
+
+
+
+
+
+
+ App Templates
+
+
+ -
+
+
-
+
+
+ This list contains a large amount of sandbox comatybility enchancing templates
+
+
+ true
+
+
+
+ -
+
+
+ -
+
+
+ true
+
+
+
+ Category
+
+
+
+
+ Name
+
+
+
+
+ -
+
+
+ Filter Categories
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
+
+
+
+ Edit ini Section
+
+
+ -
+
+
+ Edit ini
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+ Cancel
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ false
+
+
+ Save
+
+
+
+ -
+
+
+ QPlainTextEdit::NoWrap
+
+
+
+
+
+
+
+ -
+
+
+ QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+
+
diff --git a/SandboxiePlus/SandMan/Forms/SettingsWindow.ui b/SandboxiePlus/SandMan/Forms/SettingsWindow.ui
new file mode 100644
index 0000000000..ab68058095
--- /dev/null
+++ b/SandboxiePlus/SandMan/Forms/SettingsWindow.ui
@@ -0,0 +1,362 @@
+
+
+ SettingsWindow
+
+
+
+ 0
+ 0
+ 573
+ 451
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 16777215
+ 16777215
+
+
+
+ SandboxiePlus Settings
+
+
+ -
+
+
-
+
+
+
+ true
+
+
+
+ QTabWidget::North
+
+
+ 1
+
+
+
+ General Options
+
+
+
-
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Show Sys-Tray
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+
+ 75
+ true
+
+
+
+ Tray options
+
+
+
+ -
+
+
+ Restart required (!)
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Start with Windows
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ Use Dark Theme
+
+
+
+ -
+
+
+ Show Notifications for relevant log Messages
+
+
+ false
+
+
+
+ -
+
+
+ On main window close:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Watch Sandboxie.ini for changes
+
+
+
+
+
+
+
+
+
+ Advanced Options
+
+
+ -
+
+
-
+
+
+ Only Administrator user accounts can use Disable Forced Programs command
+
+
+
+ -
+
+
+ Only Administrator user accounts can make changes
+
+
+
+ -
+
+
+
+ 75
+ true
+
+
+
+ Config protection
+
+
+
+ -
+
+
+ Password must be entered in order to make changes
+
+
+
+ -
+
+
+ Change Password
+
+
+
+ -
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ -
+
+
+
+ 75
+ true
+
+
+
+ Sandbox default
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Sandbox file system root:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Sandbox ipc root:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ -
+
+
+ Sandbox registry root:
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ Separate user folders
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Clear password when main window becomes hidden
+
+
+
+
+
+
+
+
+
+ -
+
+
+ QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+
+
diff --git a/SandboxiePlus/SandMan/Helpers/WinAdmin.cpp b/SandboxiePlus/SandMan/Helpers/WinAdmin.cpp
new file mode 100644
index 0000000000..7843f5668c
--- /dev/null
+++ b/SandboxiePlus/SandMan/Helpers/WinAdmin.cpp
@@ -0,0 +1,129 @@
+#include "stdafx.h"
+#include "WinAdmin.h"
+
+#include
+#include
+#include
+
+bool IsElevated()
+{
+ bool fRet = false;
+ HANDLE hToken = NULL;
+ if(OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken))
+ {
+ TOKEN_ELEVATION Elevation;
+ DWORD cbSize = sizeof(TOKEN_ELEVATION);
+ if(GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof( Elevation ), &cbSize))
+ fRet = Elevation.TokenIsElevated;
+ }
+ if(hToken)
+ CloseHandle(hToken);
+ return fRet;
+}
+
+int RunElevated(const wstring& Params, bool bGetCode)
+{
+ wchar_t szPath[MAX_PATH];
+ if (!GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)))
+ return -3;
+ return RunElevated(wstring(szPath), Params, bGetCode);
+}
+
+int RunElevated(const wstring& binaryPath, const wstring& Params, bool bGetCode)
+{
+ // Launch itself as admin
+ SHELLEXECUTEINFO sei = { sizeof(sei) };
+ sei.fMask = SEE_MASK_NOCLOSEPROCESS;
+ sei.lpVerb = L"runas";
+ sei.lpFile = binaryPath.c_str();
+ sei.lpParameters = Params.c_str();
+ sei.hwnd = NULL;
+ sei.nShow = SW_NORMAL;
+ if (!ShellExecuteEx(&sei))
+ {
+ DWORD dwError = GetLastError();
+ if (dwError == ERROR_CANCELLED)
+ return -2; // The user refused to allow privileges elevation.
+ }
+ else
+ {
+ if (bGetCode)
+ {
+ WaitForSingleObject(sei.hProcess, 10000);
+ DWORD ExitCode = -4;
+ BOOL success = GetExitCodeProcess(sei.hProcess, &ExitCode);
+ CloseHandle(sei.hProcess);
+ return success ? ExitCode : -4;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+int RestartElevated(int &argc, char **argv)
+{
+ wstring Params;
+ for (int i = 1; i < argc; i++)
+ {
+ if (i > 1)
+ Params.append(L" ");
+ Params.append(L"\"" + wstring_convert>().from_bytes(argv[i]) + L"\"");
+ }
+ return RunElevated(Params);
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// AutoRun
+
+#define APP_NAME L"SandboxiePlus"
+
+#define AUTO_RUN_KEY_NAME APP_NAME L"_AutoRun"
+
+bool IsAutorunEnabled()
+{
+ bool result = false;
+
+ HKEY hkey = nullptr;
+ if (RegOpenKeyEx (HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS)
+ {
+ WCHAR buffer[MAX_PATH] = {0};
+ DWORD size = _countof (buffer);
+
+ if (RegQueryValueEx (hkey, AUTO_RUN_KEY_NAME, nullptr, nullptr, (LPBYTE)buffer, &size) == ERROR_SUCCESS)
+ {
+ result = true; // todo: check path
+ }
+
+ RegCloseKey (hkey);
+ }
+
+ return result;
+}
+
+bool AutorunEnable (bool is_enable)
+{
+ bool result = false;
+
+ HKEY hkey = nullptr;
+ if (RegOpenKeyEx (HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_ALL_ACCESS, &hkey) == ERROR_SUCCESS)
+ {
+ if (is_enable)
+ {
+ wchar_t szPath[MAX_PATH];
+ if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)))
+ {
+ wstring path = L"\"" + wstring(szPath) + L"\" -autorun";
+
+ result = (RegSetValueEx(hkey, AUTO_RUN_KEY_NAME, 0, REG_SZ, (LPBYTE)path.c_str(), DWORD((path.length() + 1) * sizeof(WCHAR))) == ERROR_SUCCESS);
+ }
+ }
+ else
+ {
+ result = (RegDeleteValue (hkey, AUTO_RUN_KEY_NAME) == ERROR_SUCCESS);
+ }
+
+ RegCloseKey (hkey);
+ }
+
+ return false;
+}
\ No newline at end of file
diff --git a/SandboxiePlus/SandMan/Helpers/WinAdmin.h b/SandboxiePlus/SandMan/Helpers/WinAdmin.h
new file mode 100644
index 0000000000..1195504a12
--- /dev/null
+++ b/SandboxiePlus/SandMan/Helpers/WinAdmin.h
@@ -0,0 +1,9 @@
+#pragma once
+
+bool IsElevated();
+int RunElevated(const wstring& Params, bool bGetCode = false);
+int RunElevated(const wstring& binaryPath, const wstring& Params, bool bGetCode = false);
+int RestartElevated(int &argc, char **argv);
+
+bool IsAutorunEnabled();
+bool AutorunEnable(bool is_enable);
diff --git a/SandboxiePlus/SandMan/Resources/Actions/SetLogging.png b/SandboxiePlus/SandMan/Resources/Actions/SetLogging.png
index f769c08377..1ffcc1ee38 100644
Binary files a/SandboxiePlus/SandMan/Resources/Actions/SetLogging.png and b/SandboxiePlus/SandMan/Resources/Actions/SetLogging.png differ
diff --git a/SandboxiePlus/SandMan/Resources/Actions/config.png b/SandboxiePlus/SandMan/Resources/Actions/config.png
new file mode 100644
index 0000000000..72f9f8cde2
Binary files /dev/null and b/SandboxiePlus/SandMan/Resources/Actions/config.png differ
diff --git a/SandboxiePlus/SandMan/Resources/Actions/empty_all.png b/SandboxiePlus/SandMan/Resources/Actions/empty_all.png
index 7637be6f3e..4da90db371 100644
Binary files a/SandboxiePlus/SandMan/Resources/Actions/empty_all.png and b/SandboxiePlus/SandMan/Resources/Actions/empty_all.png differ
diff --git a/SandboxiePlus/SandMan/Resources/SandMan.png b/SandboxiePlus/SandMan/Resources/SandMan.png
index 973fbab3b9..4e5bdc1bec 100644
Binary files a/SandboxiePlus/SandMan/Resources/SandMan.png and b/SandboxiePlus/SandMan/Resources/SandMan.png differ
diff --git a/SandboxiePlus/SandMan/Resources/SandMan.qrc b/SandboxiePlus/SandMan/Resources/SandMan.qrc
index f56f6ff768..f22b1aff4a 100644
--- a/SandboxiePlus/SandMan/Resources/SandMan.qrc
+++ b/SandboxiePlus/SandMan/Resources/SandMan.qrc
@@ -25,6 +25,7 @@
Actions/Stop.png
Actions/Advanced.png
Actions/Service.png
+ Actions/config.png
Boxes/sandbox-b-empty.png
diff --git a/SandboxiePlus/SandMan/Resources/SandMan2.png b/SandboxiePlus/SandMan/Resources/SandMan2.png
index baf2b6f347..75a9e15c84 100644
Binary files a/SandboxiePlus/SandMan/Resources/SandMan2.png and b/SandboxiePlus/SandMan/Resources/SandMan2.png differ
diff --git a/SandboxiePlus/SandMan/SandMan.cpp b/SandboxiePlus/SandMan/SandMan.cpp
index b825a9ab34..c2056ec668 100644
--- a/SandboxiePlus/SandMan/SandMan.cpp
+++ b/SandboxiePlus/SandMan/SandMan.cpp
@@ -10,6 +10,7 @@
#include "./Dialogs/MultiErrorDialog.h"
#include "../QSbieAPI/SbieUtils.h"
#include "../QSbieAPI/Sandboxie/BoxBorder.h"
+#include "Windows/SettingsWindow.h"
CSbiePlusAPI* theAPI = NULL;
@@ -81,6 +82,13 @@ CSandMan::CSandMan(QWidget *parent)
theGUI = this;
+ m_DefaultStyle = QApplication::style()->objectName();
+ m_DefaultPalett = QApplication::palette();
+
+ LoadLanguage();
+ if (theConf->GetBool("Options/DarkTheme", false))
+ SetDarkTheme(true);
+
m_bExit = false;
theAPI = new CSbiePlusAPI(this);
@@ -114,47 +122,6 @@ CSandMan::CSandMan(QWidget *parent)
m_pPanelSplitter->setOrientation(Qt::Horizontal);
m_pLogSplitter->addWidget(m_pPanelSplitter);
- /*
- // Box Tree
- m_pBoxModel = new CSbieModel();
- m_pBoxModel->SetTree(true);
- m_pBoxModel->SetUseIcons(true);
-
- m_pSortProxy = new CSortFilterProxyModel(false, this);
- m_pSortProxy->setSortRole(Qt::EditRole);
- m_pSortProxy->setSourceModel(m_pBoxModel);
- m_pSortProxy->setDynamicSortFilter(true);
-
- m_pBoxTree = new QTreeViewEx();
- //m_pBoxTree->setItemDelegate(theGUI->GetItemDelegate());
-
- m_pBoxTree->setModel(m_pSortProxy);
-
- m_pBoxTree->setSelectionMode(QAbstractItemView::ExtendedSelection);
-#ifdef WIN32
- QStyle* pStyle = QStyleFactory::create("windows");
- m_pBoxTree->setStyle(pStyle);
-#endif
- m_pBoxTree->setSortingEnabled(true);
-
- m_pBoxTree->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(m_pBoxTree, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OnMenu(const QPoint &)));
-
- //connect(theGUI, SIGNAL(ReloadPanels()), m_pWindowModel, SLOT(Clear()));
-
- m_pBoxTree->setColumnReset(2);
- connect(m_pBoxTree, SIGNAL(ResetColumns()), this, SLOT(OnResetColumns()));
- connect(m_pBoxTree, SIGNAL(ColumnChanged(int, bool)), this, SLOT(OnColumnsChanged()));
-
- //m_pSplitter->addWidget(CFinder::AddFinder(m_pBoxTree, m_pSortProxy));
- //m_pSplitter->setCollapsible(0, false);
- //
-
- //connect(m_pBoxTree, SIGNAL(clicked(const QModelIndex&)), this, SLOT(OnItemSelected(const QModelIndex&)));
- //connect(m_pBoxTree->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(OnItemSelected(QModelIndex)));
-
- m_pPanelSplitter->addWidget(m_pBoxTree);
- */
m_pBoxView = new CSbieView();
m_pPanelSplitter->addWidget(m_pBoxView);
@@ -246,6 +213,8 @@ CSandMan::CSandMan(QWidget *parent)
m_pKeepTerminated->setCheckable(true);
m_pMenuOptions = menuBar()->addMenu(tr("&Options"));
+ m_pMenuSettings = m_pMenuOptions->addAction(MakeActionIcon(":/Actions/Settings"), tr("Global Settings"), this, SLOT(OnSettings()));
+ m_pMenuOptions->addSeparator();
m_pEditIni = m_pMenuOptions->addAction(QIcon(":/Actions/EditIni"), tr("Edit ini file"), this, SLOT(OnEditIni()));
m_pReloadIni = m_pMenuOptions->addAction(QIcon(":/Actions/ReloadIni"), tr("Reload ini file"), this, SLOT(OnReloadIni()));
m_pMenuOptions->addSeparator();
@@ -264,6 +233,8 @@ CSandMan::CSandMan(QWidget *parent)
m_pAbout = m_pMenuHelp->addAction(QIcon(":/SandMan.png"), tr("About Sandboxie-Plus"), this, SLOT(OnAbout()));
+ m_pToolBar->addAction(m_pMenuSettings);
+ m_pToolBar->addSeparator();
//m_pToolBar->addAction(m_pMenuNew);
//m_pToolBar->addAction(m_pMenuEmptyAll);
@@ -341,18 +312,22 @@ CSandMan::CSandMan(QWidget *parent)
if (theConf->GetBool("Options/NoStatusBar", false))
statusBar()->hide();
- else if (theConf->GetBool("Options/NoSizeGrip", false))
- statusBar()->setSizeGripEnabled(false);
+ //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);
+ if (!bAutoRun)
+ show();
+
if (CSbieUtils::IsRunning(CSbieUtils::eAll) || theConf->GetBool("Options/StartIfStopped", true))
ConnectSbie();
connect(theAPI, SIGNAL(LogMessage(const QString&, bool)), this, SLOT(OnLogMessage(const QString&, bool)));
+ connect(theAPI, SIGNAL(NotAuthorized(bool, bool&)), this, SLOT(OnNotAuthorized(bool, bool&)), Qt::DirectConnection);
m_uTimerID = startTimer(250);
}
@@ -395,6 +370,9 @@ void CSandMan::closeEvent(QCloseEvent *e)
{
hide();
+ if (theAPI->GetGlobalSettings()->GetBool("ForgetPassword", false))
+ theAPI->ClearPassword();
+
e->ignore();
return;
}
@@ -486,8 +464,6 @@ void CSandMan::timerEvent(QTimerEvent* pEvent)
theAPI->UpdateProcesses(m_pKeepTerminated->isChecked());
}
- m_pBoxView->Refresh();
-
if (m_bIconEmpty != (theAPI->TotalProcesses() == 0))
{
m_bIconEmpty = (theAPI->TotalProcesses() == 0);
@@ -496,16 +472,10 @@ void CSandMan::timerEvent(QTimerEvent* pEvent)
m_pTrayIcon->setIcon(Icon);
}
- /*QList Added = m_pBoxModel->Sync(theAPI->GetAllBoxes());
+ if (!isVisible() || windowState().testFlag(Qt::WindowMinimized))
+ return;
- if (m_pBoxModel->IsTree())
- {
- QTimer::singleShot(100, this, [this, Added]() {
- foreach(const QVariant ID, Added) {
- m_pBoxTree->expand(m_pSortProxy->mapFromSource(m_pBoxModel->FindIndex(ID)));
- }
- });
- }*/
+ m_pBoxView->Refresh();
OnSelectionChanged();
}
@@ -605,7 +575,7 @@ void CSandMan::OnLogMessage(const QString& Message, bool bNotify)
if (bNotify)
{
- int iNotify = theConf->GetInt("Options/Notifications", 1);
+ int iNotify = theConf->GetInt("Options/ShowNotifications", 1);
if (iNotify & 1)
m_pTrayIcon->showMessage("Sandboxie-Plus", Message);
if (iNotify & 2)
@@ -613,25 +583,36 @@ void CSandMan::OnLogMessage(const QString& Message, bool bNotify)
}
}
-/*
-void CSandMan::OnResetColumns()
+void CSandMan::OnNotAuthorized(bool bLoginRequired, bool& bRetry)
{
- for (int i = 0; i < m_pBoxModel->columnCount(); i++)
- m_pBoxTree->SetColumnHidden(i, false);
-}
+ if (!bLoginRequired)
+ {
+ QMessageBox::warning(this, "Sandboxie-Plus", tr("Only Administrators can change the config."));
+ return;
+ }
-void CSandMan::OnColumnsChanged()
-{
- m_pBoxModel->Sync(theAPI->GetAllBoxes());
+ static bool LoginOpen = false;
+ if (LoginOpen)
+ return;
+ LoginOpen = true;
+ for (;;)
+ {
+ QString Value = QInputDialog::getText(this, "Sandboxie-Plus", tr("Please enter the configuration password."), QLineEdit::Password);
+ if (Value.isEmpty())
+ break;
+ SB_STATUS Status = theAPI->UnlockConfig(Value);
+ if (!Status.IsError()) {
+ bRetry = true;
+ break;
+ }
+ QMessageBox::warning(this, "Sandboxie-Plus", tr("Login Failed: %1").arg(Status.GetText()));
+ }
+ LoginOpen = false;
}
-void CSandMan::OnMenu(const QPoint& Point)
-{
-}*/
-
void CSandMan::OnNewBox()
{
- QString Value = QInputDialog::getText(this, "Sandboxie-Plus", "Please enter a name for the new Sandbox.", QLineEdit::Normal, "NewBox");
+ QString Value = QInputDialog::getText(this, "Sandboxie-Plus", tr("Please enter a name for the new Sandbox."), QLineEdit::Normal, "NewBox");
if (Value.isEmpty())
return;
theAPI->CreateBox(Value);
@@ -784,6 +765,23 @@ void CSandMan::OnSetKeep()
theAPI->UpdateProcesses(false);
}
+void CSandMan::OnSettings()
+{
+ CSettingsWindow* pSettingsWindow = new CSettingsWindow(this);
+ connect(pSettingsWindow, SIGNAL(OptionsChanged()), this, SLOT(UpdateSettings()));
+ pSettingsWindow->show();
+}
+
+void CSandMan::UpdateSettings()
+{
+ SetDarkTheme(theConf->GetBool("Options/DarkTheme", false));
+
+ if (theConf->GetBool("Options/ShowSysTray", true))
+ m_pTrayIcon->show();
+ else
+ m_pTrayIcon->hide();
+}
+
void CSandMan::OnEditIni()
{
if (theConf->GetBool("Options/NoEditInfo", true))
@@ -901,7 +899,12 @@ void CSandMan::OnSysTray(QSystemTrayIcon::ActivationReason Reason)
{
if(TriggerSet)
NullifyTrigger = true;
+
hide();
+
+ if (theAPI->GetGlobalSettings()->GetBool("ForgetPassword", false))
+ theAPI->ClearPassword();
+
break;
}
show();
@@ -976,6 +979,62 @@ void CSandMan::OnAbout()
QDesktopServices::openUrl(QUrl("https://www.patreon.com/DavidXanatos"));
}
+void CSandMan::SetDarkTheme(bool bDark)
+{
+ if (bDark)
+ {
+ QApplication::setStyle(QStyleFactory::create("Fusion"));
+ QPalette palette;
+ palette.setColor(QPalette::Window, QColor(53, 53, 53));
+ palette.setColor(QPalette::WindowText, Qt::white);
+ palette.setColor(QPalette::Base, QColor(25, 25, 25));
+ palette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
+ palette.setColor(QPalette::ToolTipBase, Qt::white);
+ palette.setColor(QPalette::ToolTipText, Qt::white);
+ palette.setColor(QPalette::Text, Qt::white);
+ palette.setColor(QPalette::Button, QColor(53, 53, 53));
+ palette.setColor(QPalette::ButtonText, Qt::white);
+ palette.setColor(QPalette::BrightText, Qt::red);
+ palette.setColor(QPalette::Link, QColor(218, 130, 42));
+ palette.setColor(QPalette::Highlight, QColor(42, 130, 218));
+ palette.setColor(QPalette::HighlightedText, Qt::black);
+ QApplication::setPalette(palette);
+ }
+ else
+ {
+ QApplication::setStyle(QStyleFactory::create(m_DefaultStyle));
+ QApplication::setPalette(m_DefaultPalett);
+ }
+
+ CTreeItemModel::SetDarkMode(bDark);
+ CListItemModel::SetDarkMode(bDark);
+}
+
+void CSandMan::LoadLanguage()
+{
+ qApp->removeTranslator(&m_Translator);
+ m_Translation.clear();
+
+ QString Lang = theConf->GetString("Options/Language");
+ if (!Lang.isEmpty())
+ {
+ QString LangAux = Lang; // Short version as fallback
+ LangAux.truncate(LangAux.lastIndexOf('_'));
+
+ QString LangPath = QApplication::applicationDirPath() + "/translations/taskexplorer_";
+ bool bAux = false;
+ if (QFile::exists(LangPath + Lang + ".qm") || (bAux = QFile::exists(LangPath + LangAux + ".qm")))
+ {
+ QFile File(LangPath + (bAux ? LangAux : Lang) + ".qm");
+ File.open(QFile::ReadOnly);
+ m_Translation = File.readAll();
+ }
+
+ if (!m_Translation.isEmpty() && m_Translator.load((const uchar*)m_Translation.data(), m_Translation.size()))
+ qApp->installTranslator(&m_Translator);
+ }
+}
+
//////////////////////////////////////////////////////////////////////////////////////////
//
/*
diff --git a/SandboxiePlus/SandMan/SandMan.h b/SandboxiePlus/SandMan/SandMan.h
index f220ede9c3..619d113f3c 100644
--- a/SandboxiePlus/SandMan/SandMan.h
+++ b/SandboxiePlus/SandMan/SandMan.h
@@ -8,10 +8,11 @@
#include "../MiscHelpers/Common/ProgressDialog.h"
#include "Models/ResMonModel.h"
#include "Models/ApiMonModel.h"
+#include
#define VERSION_MJR 0
#define VERSION_MIN 3
-#define VERSION_REV 0
+#define VERSION_REV 5
#define VERSION_UPD 0
@@ -60,13 +61,13 @@ public slots:
void OnStatusChanged();
void OnLogMessage(const QString& Message, bool bNotify = false);
+ void OnNotAuthorized(bool bLoginRequired, bool& bRetry);
+
+ void UpdateSettings();
+
private slots:
void OnSelectionChanged();
- //void OnResetColumns();
- //void OnColumnsChanged();
- //void OnMenu(const QPoint& Point);
-
void OnMenuHover(QAction* action);
void OnNewBox();
@@ -76,6 +77,7 @@ private slots:
void OnCleanUp();
void OnSetKeep();
+ void OnSettings();
void OnEditIni();
void OnReloadIni();
void OnSetMonitoring();
@@ -96,9 +98,6 @@ private slots:
QSplitter* m_pLogSplitter;
- //QTreeViewEx* m_pBoxTree;
- //CSbieModel* m_pBoxModel;
- //QSortFilterProxyModel* m_pSortProxy;
CSbieView* m_pBoxView;
@@ -139,6 +138,7 @@ private slots:
QAction* m_pKeepTerminated;
QMenu* m_pMenuOptions;
+ QAction* m_pMenuSettings;
QAction* m_pEditIni;
QAction* m_pReloadIni;
QAction* m_pEnableMonitoring;
@@ -156,6 +156,14 @@ private slots:
bool m_bExit;
CProgressDialog* m_pProgressDialog;
+
+ void SetDarkTheme(bool bDark);
+ QString m_DefaultStyle;
+ QPalette m_DefaultPalett;
+
+ void LoadLanguage();
+ QTranslator m_Translator;
+ QByteArray m_Translation;
};
extern CSandMan* theGUI;
\ No newline at end of file
diff --git a/SandboxiePlus/SandMan/SandMan.vcxproj b/SandboxiePlus/SandMan/SandMan.vcxproj
index 232e5294ee..5fc75e951c 100644
--- a/SandboxiePlus/SandMan/SandMan.vcxproj
+++ b/SandboxiePlus/SandMan/SandMan.vcxproj
@@ -193,7 +193,9 @@
+
+
@@ -205,14 +207,20 @@
Create
+
+
+
+
+
+
@@ -226,6 +234,10 @@
+
+
+
+
diff --git a/SandboxiePlus/SandMan/SandMan.vcxproj.filters b/SandboxiePlus/SandMan/SandMan.vcxproj.filters
index a237d55736..7335e4f919 100644
--- a/SandboxiePlus/SandMan/SandMan.vcxproj.filters
+++ b/SandboxiePlus/SandMan/SandMan.vcxproj.filters
@@ -35,6 +35,12 @@
{6accf3ae-da17-4c0f-ba83-214e3874b029}
+
+ {20d5954b-be86-4a34-948d-00954dcfd07b}
+
+
+ {d0068730-c9fb-49ef-90ec-8ecd2131ae47}
+
@@ -64,6 +70,18 @@
SandMan
+
+ Models
+
+
+ Helpers
+
+
+ Windows
+
+
+ Windows
+
@@ -72,6 +90,9 @@
Resource Files
+
+ Helpers
+
@@ -95,6 +116,15 @@
SandMan
+
+ Models
+
+
+ Windows
+
+
+ Windows
+
@@ -111,4 +141,12 @@
Resource Files
+
+
+ Form Files
+
+
+ Form Files
+
+
\ No newline at end of file
diff --git a/SandboxiePlus/SandMan/SbiePlusAPI.cpp b/SandboxiePlus/SandMan/SbiePlusAPI.cpp
index f49c016b3d..c2100fd31a 100644
--- a/SandboxiePlus/SandMan/SbiePlusAPI.cpp
+++ b/SandboxiePlus/SandMan/SbiePlusAPI.cpp
@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "SbiePlusAPI.h"
+#include "..\MiscHelpers\Common\Common.h"
CSbiePlusAPI::CSbiePlusAPI(QObject* parent) : CSbieAPI(parent)
@@ -120,14 +121,14 @@ void CSandBoxPlus::SetLogApi(bool bEnable)
void CSandBoxPlus::SetINetBlock(bool bEnable)
{
if (bEnable)
- DelValue("ClosedFilePath", "InternetAccessDevices");
+ DelValue("ClosedFilePath", "!,InternetAccessDevices");
else
InsertText("ClosedFilePath", "InternetAccessDevices");
}
void CSandBoxPlus::SetAllowShares(bool bEnable)
{
- SetBool("BlockNetworkFiles", bEnable);
+ SetBool("BlockNetworkFiles", !bEnable);
}
void CSandBoxPlus::SetDropRights(bool bEnable)
diff --git a/SandboxiePlus/SandMan/Views/SbieView.cpp b/SandboxiePlus/SandMan/Views/SbieView.cpp
index 65e93c20cd..0be4a0f883 100644
--- a/SandboxiePlus/SandMan/Views/SbieView.cpp
+++ b/SandboxiePlus/SandMan/Views/SbieView.cpp
@@ -4,6 +4,7 @@
#include "../QSbieAPI/SbieAPI.h"
#include "../../MiscHelpers/Common/SortFilterProxyModel.h"
#include "../../MiscHelpers/Common/Settings.h"
+#include "../Windows/OptionsWindow.h"
CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
{
@@ -32,6 +33,7 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
m_pSbieTree->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_pSbieTree, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OnMenu(const QPoint &)));
+ connect(m_pSbieTree, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(OnDoubleClicked(const QModelIndex&)));
connect(m_pSbieTree->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(ProcessSelection(QItemSelection, QItemSelection)));
//connect(theGUI, SIGNAL(ReloadPanels()), m_pSbieModel, SLOT(Clear()));
@@ -62,7 +64,7 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
m_pMenuPresetsShares->setCheckable(true);
m_pMenuPresetsNoAdmin = m_pMenuPresets->addAction(tr("Drop Admin Rights"), this, SLOT(OnSandBoxAction()));
m_pMenuPresetsNoAdmin->setCheckable(true);
-
+ m_pMenuOptions = m_pMenu->addAction(tr("Sandbox Options"), this, SLOT(OnSandBoxAction()));
m_pMenuRename = m_pMenu->addAction(tr("Rename Sandbox"), this, SLOT(OnSandBoxAction()));
m_pMenuRemove = m_pMenu->addAction(tr("Remove Sandbox"), this, SLOT(OnSandBoxAction()));
m_iMenuBox = m_pMenu->actions().count();
@@ -168,6 +170,7 @@ void CSbieView::OnMenu(const QPoint& Point)
m_pMenuPresetsShares->setChecked(pBox && pBox.objectCast()->HasSharesAccess());
m_pMenuPresetsNoAdmin->setChecked(pBox && pBox.objectCast()->IsDropRights());
+ m_pMenuOptions->setEnabled(iSandBoxeCount == 1);
for (int i = m_iMenuBox; i < m_iMenuProc; i++)
MenuActions[i]->setVisible(iProcessCount > 0 && iSandBoxeCount == 0);
@@ -207,11 +210,15 @@ void CSbieView::OnSandBoxAction()
SandBoxes.first().objectCast()->SetAllowShares(m_pMenuPresetsShares->isChecked());
else if (Action == m_pMenuPresetsNoAdmin)
SandBoxes.first().objectCast()->SetDropRights(m_pMenuPresetsNoAdmin->isChecked());
-
+ else if (Action == m_pMenuOptions)
+ {
+ COptionsWindow* pOptionsWindow = new COptionsWindow(SandBoxes.first(), SandBoxes.first()->GetName(), this);
+ pOptionsWindow->show();
+ }
else if (Action == m_pMenuRename)
{
QString OldValue = SandBoxes.first()->GetName().replace("_", " ");
- QString Value = QInputDialog::getText(this, "Sandboxie-Plus", "Please enter a new name for the Sandbox.", QLineEdit::Normal, OldValue);
+ QString Value = QInputDialog::getText(this, "Sandboxie-Plus", tr("Please enter a new name for the Sandbox."), QLineEdit::Normal, OldValue);
if (Value.isEmpty() || Value == OldValue)
return;
Results.append((SandBoxes.first()->RenameBox(Value)));
@@ -281,6 +288,17 @@ void CSbieView::OnProcessAction()
CSandMan::CheckResults(Results);
}
+void CSbieView::OnDoubleClicked(const QModelIndex& index)
+{
+ QModelIndex ModelIndex = m_pSortProxy->mapToSource(index);
+ CSandBoxPtr pBox = m_pSbieModel->GetSandBox(ModelIndex);
+ if (pBox.isNull())
+ return;
+
+ COptionsWindow* pOptionsWindow = new COptionsWindow(pBox, pBox->GetName(), this);
+ pOptionsWindow->show();
+}
+
void CSbieView::ProcessSelection(const QItemSelection& selected, const QItemSelection& deselected)
{
if (selected.empty())
diff --git a/SandboxiePlus/SandMan/Views/SbieView.h b/SandboxiePlus/SandMan/Views/SbieView.h
index 8c3e41a3c5..9e8c7a480d 100644
--- a/SandboxiePlus/SandMan/Views/SbieView.h
+++ b/SandboxiePlus/SandMan/Views/SbieView.h
@@ -21,6 +21,7 @@ public slots:
private slots:
void OnToolTipCallback(const QVariant& ID, QString& ToolTip);
+ void OnDoubleClicked(const QModelIndex& index);
void ProcessSelection(const QItemSelection& selected, const QItemSelection& deselected);
void OnSandBoxAction();
@@ -52,6 +53,7 @@ private slots:
QAction* m_pMenuPresetsINet;
QAction* m_pMenuPresetsShares;
QAction* m_pMenuPresetsNoAdmin;
+ QAction* m_pMenuOptions;
QAction* m_pMenuEmptyBox;
QAction* m_pMenuCleanUp;
QAction* m_pMenuRemove;
diff --git a/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp b/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp
new file mode 100644
index 0000000000..3f5753fe60
--- /dev/null
+++ b/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp
@@ -0,0 +1,1502 @@
+#include "stdafx.h"
+#include "OptionsWindow.h"
+#include "SandMan.h"
+#include "../MiscHelpers/Common/Settings.h"
+#include "../MiscHelpers/Common/Common.h"
+#include "../MiscHelpers/Common/ComboInputDialog.h"
+#include "Helpers/WinAdmin.h"
+#include
+
+class CustomTabStyle : public QProxyStyle {
+public:
+ QSize sizeFromContents(ContentsType type, const QStyleOption* option,
+ const QSize& size, const QWidget* widget) const {
+ QSize s = QProxyStyle::sizeFromContents(type, option, size, widget);
+ if (type == QStyle::CT_TabBarTab) {
+ s.transpose();
+ s.setHeight(s.height() * 15 / 10);
+ }
+ return s;
+ }
+
+ void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const {
+ if (element == CE_TabBarTabLabel) {
+ if (const QStyleOptionTab* tab = qstyleoption_cast(option)) {
+ QStyleOptionTab opt(*tab);
+ opt.shape = QTabBar::RoundedNorth;
+ QProxyStyle::drawControl(element, &opt, painter, widget);
+ return;
+ }
+ }
+ QProxyStyle::drawControl(element, option, painter, widget);
+ }
+};
+
+
+COptionsWindow::COptionsWindow(const QSharedPointer& pBox, const QString& Name, QWidget *parent)
+ : QMainWindow(parent)
+{
+ m_pBox = pBox;
+
+ m_Template = pBox->GetName().left(9).compare("Template_", Qt::CaseInsensitive) == 0;
+ bool ReadOnly = /*pBox->GetAPI()->IsConfigLocked() ||*/ (m_Template && pBox->GetName().mid(9, 6).compare("Local_", Qt::CaseInsensitive) != 0);
+
+
+ QWidget* centralWidget = new QWidget();
+ ui.setupUi(centralWidget);
+ this->setCentralWidget(centralWidget);
+ this->setWindowTitle(tr("Sandboxie Plus - '%1' Options").arg(Name));
+
+ ui.tabs->setTabPosition(QTabWidget::West);
+ ui.tabs->tabBar()->setStyle(new CustomTabStyle());
+
+ if (m_Template)
+ {
+ ui.tabGeneral->setEnabled(false);
+ ui.tabStart->setEnabled(false);
+ ui.tabRestrictions->setEnabled(false);
+ ui.tabInternet->setEnabled(false);
+ ui.tabAdvanced->setEnabled(false);
+ ui.tabTemplates->setEnabled(false);
+
+ for (int i = 0; i < ui.tabs->count(); i++)
+ ui.tabs->setTabEnabled(i, ui.tabs->widget(i)->isEnabled());
+
+ ui.tabs->setCurrentIndex(ui.tabs->indexOf(ui.tabAccess));
+
+ ui.chkShowForceTmpl->setEnabled(false);
+ ui.chkShowStopTmpl->setEnabled(false);
+ ui.chkShowAccessTmpl->setEnabled(false);
+ }
+
+ m_ConfigDirty = true;
+
+ // General
+ ui.cmbBoxIndicator->addItem(tr("Don't alter the window title"), "-");
+ ui.cmbBoxIndicator->addItem(tr("Display [#] indicator only"), "n");
+ ui.cmbBoxIndicator->addItem(tr("Display box name in title"), "y");
+
+ ui.cmbBoxBorder->addItem(tr("Border disabled"), "off");
+ ui.cmbBoxBorder->addItem(tr("Show only when title is in focus"), "ttl");
+ ui.cmbBoxBorder->addItem(tr("Always show"), "on");
+
+ connect(ui.cmbBoxIndicator, SIGNAL(currentIndexChanged(int)), this, SLOT(OnGeneralChanged()));
+ connect(ui.cmbBoxBorder, SIGNAL(currentIndexChanged(int)), this, SLOT(OnGeneralChanged()));
+ connect(ui.btnBorderColor, SIGNAL(pressed()), this, SLOT(OnPickColor()));
+ connect(ui.txtCopyLimit, SIGNAL(textChanged(const QString&)), this, SLOT(OnGeneralChanged()));
+ connect(ui.chkNoCopyWarn, SIGNAL(clicked(bool)), this, SLOT(OnGeneralChanged()));
+ //
+
+ // Groupes
+ connect(ui.btnAddGroup, SIGNAL(pressed()), this, SLOT(OnAddGroup()));
+ connect(ui.btnAddProg, SIGNAL(pressed()), this, SLOT(OnAddProg()));
+ connect(ui.btnDelProg, SIGNAL(pressed()), this, SLOT(OnDelProg()));
+ //
+
+ // Force
+ connect(ui.btnForceProg, SIGNAL(pressed()), this, SLOT(OnForceProg()));
+ connect(ui.btnForceDir, SIGNAL(pressed()), this, SLOT(OnForceDir()));
+ connect(ui.btnDelForce, SIGNAL(pressed()), this, SLOT(OnDelForce()));
+ connect(ui.chkShowForceTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowForceTmpl()));
+ //
+
+ // Stop
+ connect(ui.btnAddLingering, SIGNAL(pressed()), this, SLOT(OnAddLingering()));
+ connect(ui.btnAddLeader, SIGNAL(pressed()), this, SLOT(OnAddLeader()));
+ connect(ui.btnDelStopProg, SIGNAL(pressed()), this, SLOT(OnDelStopProg()));
+ connect(ui.chkShowStopTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowStopTmpl()));
+ //
+
+ // Start
+ connect(ui.chkRestrictStart, SIGNAL(clicked(bool)), this, SLOT(OnRestrictStart()));
+ connect(ui.btnAddStartProg, SIGNAL(pressed()), this, SLOT(OnAddStartProg()));
+ connect(ui.btnDelStartProg, SIGNAL(pressed()), this, SLOT(OnDelStartProg()));
+ connect(ui.chkStartBlockMsg, SIGNAL(clicked(bool)), this, SLOT(OnStartChanged()));
+ //
+
+ // Restrictions
+ connect(ui.chkBlockShare, SIGNAL(clicked(bool)), this, SLOT(OnRestrictionChanged()));
+ connect(ui.chkDropRights, SIGNAL(clicked(bool)), this, SLOT(OnRestrictionChanged()));
+ connect(ui.chkNoDefaultCOM, SIGNAL(clicked(bool)), this, SLOT(OnRestrictionChanged()));
+ connect(ui.chkProtectSCM, SIGNAL(clicked(bool)), this, SLOT(OnRestrictionChanged()));
+ connect(ui.chkProtectRpcSs, SIGNAL(clicked(bool)), this, SLOT(OnRestrictionChanged()));
+ connect(ui.chkProtectSystem, SIGNAL(clicked(bool)), this, SLOT(OnRestrictionChanged()));
+ //
+
+ // INet
+ connect(ui.chkBlockINet, SIGNAL(clicked(bool)), this, SLOT(OnBlockINet()));
+ connect(ui.btnAddINetProg, SIGNAL(pressed()), this, SLOT(OnAddINetProg()));
+ connect(ui.btnDelINetProg, SIGNAL(pressed()), this, SLOT(OnDelINetProg()));
+ connect(ui.chkINetBlockMsg, SIGNAL(clicked(bool)), this, SLOT(OnINetBlockChanged()));
+ //
+
+ // Access
+ connect(ui.btnAddFile, SIGNAL(pressed()), this, SLOT(OnAddFile()));
+ connect(ui.btnAddKey, SIGNAL(pressed()), this, SLOT(OnAddKey()));
+ connect(ui.btnAddIPC, SIGNAL(pressed()), this, SLOT(OnAddIPC()));
+ connect(ui.btnAddClsId, SIGNAL(pressed()), this, SLOT(OnAddClsId()));
+ connect(ui.btnAddCOM, SIGNAL(pressed()), this, SLOT(OnAddCOM()));
+ // todo: add priority by order
+ ui.btnMoveUp->setVisible(false);
+ ui.btnMoveDown->setVisible(false);
+ connect(ui.chkShowAccessTmpl, SIGNAL(clicked(bool)), this, SLOT(OnShowAccessTmpl()));
+ connect(ui.btnDelAccess, SIGNAL(pressed()), this, SLOT(OnDelAccess()));
+
+ connect(ui.treeAccess, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(OnAccessItemClicked(QTreeWidgetItem*, int)));
+ connect(ui.treeAccess, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnAccessItemDoubleClicked(QTreeWidgetItem*, int)));
+ //
+
+ // Advanced
+ ui.cmbEmptyCmd->addItem("%SystemRoot%\\System32\\cmd.exe /c RMDIR /s /q \"%SANDBOX%\"");
+
+ connect(ui.chkProtectBox, SIGNAL(clicked(bool)), this, SLOT(OnAdvancedChanged()));
+ connect(ui.chkAutoEmpty, SIGNAL(clicked(bool)), this, SLOT(OnAdvancedChanged()));
+ connect(ui.cmbEmptyCmd, SIGNAL(currentTextChanged(const QString&)), this, SLOT(OnAdvancedChanged()));
+ connect(ui.btnAddUser, SIGNAL(pressed()), this, SLOT(OnAddUser()));
+ connect(ui.btnDelUser, SIGNAL(pressed()), this, SLOT(OnDelUser()));
+ //
+
+ // Templates
+ connect(ui.cmbCategories, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFilterTemplates()));
+ connect(ui.treeTemplates, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(OnTemplateClicked(QTreeWidgetItem*, int)));
+ connect(ui.treeTemplates, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(OnTemplateDoubleClicked(QTreeWidgetItem*, int)));
+ //
+
+ connect(ui.tabs, SIGNAL(currentChanged(int)), this, SLOT(OnTab()));
+
+ // edit
+ connect(ui.btnEditIni, SIGNAL(pressed()), this, SLOT(OnEditIni()));
+ connect(ui.btnSaveIni, SIGNAL(pressed()), this, SLOT(OnSaveIni()));
+ connect(ui.btnCancelEdit, SIGNAL(pressed()), this, SLOT(OnCancelEdit()));
+ //
+
+ connect(ui.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(pressed()), this, SLOT(accept()));
+ connect(ui.buttonBox->button(QDialogButtonBox::Apply), SIGNAL(pressed()), this, SLOT(apply()));
+ connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ if (ReadOnly) {
+ ui.btnEditIni->setEnabled(false);
+ ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+ ui.buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
+ }
+
+ OnTab(); // -> LoadConfig();
+
+ restoreGeometry(theConf->GetBlob("OptionsWindow/Window_Geometry"));
+}
+
+COptionsWindow::~COptionsWindow()
+{
+ theConf->SetBlob("OptionsWindow/Window_Geometry",saveGeometry());
+}
+
+void COptionsWindow::closeEvent(QCloseEvent *e)
+{
+ this->deleteLater();
+}
+
+void COptionsWindow::LoadConfig()
+{
+ m_ConfigDirty = false;
+
+ {
+ QString BoxNameTitle = m_pBox->GetText("BoxNameTitle", "n");
+ ui.cmbBoxIndicator->setCurrentIndex(ui.cmbBoxIndicator->findData(BoxNameTitle.toLower()));
+
+ QStringList BorderCfg = m_pBox->GetText("BorderColor").split(",");
+ ui.cmbBoxBorder->setCurrentIndex(ui.cmbBoxBorder->findData(BorderCfg.size() >= 2 ? BorderCfg[1].toLower() : "on"));
+ m_BorderColor = QColor("#" + BorderCfg[0].mid(5, 2) + BorderCfg[0].mid(3, 2) + BorderCfg[0].mid(1, 2));
+ ui.btnBorderColor->setStyleSheet("background-color: " + m_BorderColor.name());
+
+ ui.txtCopyLimit->setText(QString::number(m_pBox->GetNum("CopyLimitKb", 80 * 1024)));
+ ui.chkNoCopyWarn->setChecked(!m_pBox->GetBool("CopyLimitSilent", false));
+
+ m_GeneralChanged = false;
+ }
+
+ LoadGroups();
+
+ LoadForced();
+
+ LoadStop();
+
+ {
+ ui.chkStartBlockMsg->setChecked(m_pBox->GetBool("NotifyStartRunAccessDenied", true));
+
+ m_StartChanged = false;
+ }
+
+ {
+ ui.chkBlockShare->setChecked(m_pBox->GetBool("BlockNetworkFiles", true));
+ ui.chkDropRights->setChecked(m_pBox->GetBool("DropAdminRights", false));
+ ui.chkNoDefaultCOM->setChecked(!m_pBox->GetBool("OpenDefaultClsid", true));
+ ui.chkProtectSCM->setChecked(!m_pBox->GetBool("UnrestrictedSCM", false));
+ ui.chkProtectRpcSs->setChecked(m_pBox->GetBool("ProtectRpcSs", false));
+ ui.chkProtectSystem->setChecked(!m_pBox->GetBool("ExposeBoxedSystem", false));
+
+ m_RestrictionChanged = false;
+ }
+
+ {
+ ui.chkINetBlockMsg->setChecked(m_pBox->GetBool("NotifyInternetAccessDenied", true));
+
+ m_INetBlockChanged = false;
+ }
+
+ LoadAccessList();
+
+ {
+ ui.chkProtectBox->setChecked(m_pBox->GetBool("NeverDelete", false));
+ ui.chkAutoEmpty->setChecked(m_pBox->GetBool("AutoDelete", false));
+ ui.cmbEmptyCmd->setCurrentText(m_pBox->GetText("DeleteCommand", ""));
+
+ QStringList Users = m_pBox->GetText("Enabled").split(",");
+ ui.lstUsers->clear();
+ if (Users.count() > 1)
+ ui.lstUsers->addItems(Users.mid(1));
+
+ m_AdvancedChanged = false;
+ }
+
+ {
+ LoadTemplates();
+ m_TemplatesChanged = false;
+ }
+}
+
+void COptionsWindow::SaveConfig()
+{
+ if (m_GeneralChanged)
+ {
+ m_pBox->SetText("BoxNameTitle", ui.cmbBoxIndicator->currentData().toString());
+
+ QStringList BorderCfg;
+ BorderCfg.append(QString("#%1,%2,%3").arg(m_BorderColor.blue(), 2, 16, QChar('0')).arg(m_BorderColor.green(), 2, 16, QChar('0')).arg(m_BorderColor.red(), 2, 16, QChar('0')));
+ BorderCfg.append(ui.cmbBoxBorder->currentData().toString());
+ //BorderCfg.append(5) // width
+ m_pBox->SetText("BorderColor", BorderCfg.join(","));
+
+ m_pBox->SetNum("CopyLimitKb", ui.txtCopyLimit->text().toInt());
+ m_pBox->SetBool("CopyLimitSilent", ui.chkNoCopyWarn->isChecked());
+
+ m_GeneralChanged = false;
+ }
+
+ if (m_GroupsChanged)
+ SaveGroups();
+
+ if (m_ForcedChanged)
+ SaveForced();
+
+ if (m_StopChanged)
+ SaveStop();
+
+ if (m_StartChanged)
+ {
+ m_pBox->SetBool("NotifyStartRunAccessDenied", ui.chkStartBlockMsg->isChecked());
+
+ m_StartChanged = false;
+ }
+
+ if (m_RestrictionChanged)
+ {
+ m_pBox->SetBool("BlockNetworkFiles", ui.chkBlockShare->isChecked());
+ m_pBox->SetBool("DropAdminRights", ui.chkDropRights->isChecked());
+ m_pBox->SetBool("OpenDefaultClsid", ui.chkNoDefaultCOM->isChecked());
+ m_pBox->SetBool("UnrestrictedSCM", ui.chkProtectSCM->isChecked());
+ m_pBox->SetBool("ProtectRpcSs", ui.chkProtectRpcSs->isChecked());
+ m_pBox->SetBool("ExposeBoxedSystem", ui.chkProtectSystem->isChecked());
+
+ m_RestrictionChanged = false;
+ }
+
+ if (m_INetBlockChanged)
+ {
+ m_pBox->SetBool("NotifyInternetAccessDenied", ui.chkINetBlockMsg->isChecked());
+
+ m_INetBlockChanged = false;
+ }
+
+ if (m_AccessChanged)
+ SaveAccessList();
+
+ if (m_AdvancedChanged)
+ {
+ m_pBox->SetBool("NeverDelete", ui.chkProtectBox->isChecked());
+ m_pBox->SetBool("AutoDelete", ui.chkAutoEmpty->isChecked());
+ m_pBox->SetText("DeleteCommand", ui.cmbEmptyCmd->currentText());
+
+ QStringList Users;
+ for (int i = 0; i < ui.lstUsers->count(); i++)
+ Users.append(ui.lstUsers->item(i)->text());
+ m_pBox->SetText("Enabled", Users.count() > 0 ? "y," + Users.join(",") : "y");
+
+ m_AdvancedChanged = false;
+ }
+
+ if (m_TemplatesChanged)
+ SaveTemplates();
+}
+
+void COptionsWindow::apply()
+{
+ if (!ui.btnEditIni->isEnabled())
+ SaveIniSection();
+ else
+ SaveConfig();
+
+ LoadConfig();
+
+ emit OptionsChanged();
+}
+
+void COptionsWindow::accept()
+{
+ apply();
+
+ this->close();
+}
+
+void COptionsWindow::reject()
+{
+ this->close();
+}
+
+void COptionsWindow::OnGeneralChanged()
+{
+ m_GeneralChanged = true;
+
+ ui.lblCopyLimit->setText(tr("kilobytes (%1)").arg(FormatSize(ui.txtCopyLimit->text().toInt() * 1024)));
+}
+
+void COptionsWindow::OnPickColor()
+{
+ QColor color = QColorDialog::getColor(m_BorderColor, this, "Select color");
+ if (!color.isValid())
+ return;
+ m_GeneralChanged = true;
+ m_BorderColor = color;
+ ui.btnBorderColor->setStyleSheet("background-color: " + m_BorderColor.name());
+}
+
+void COptionsWindow::SetProgramItem(QString Program, QTreeWidgetItem* pItem, int Column)
+{
+ pItem->setData(Column, Qt::UserRole, Program);
+ if (Program.left(1) == "<")
+ Program = tr("Group: %1").arg(Program.mid(1, Program.length() - 2));
+ pItem->setText(Column, Program);
+}
+
+void COptionsWindow::LoadGroups()
+{
+ m_TemplateGroups.clear();
+ ui.treeGroups->clear();
+
+ QMultiMap GroupMap; // if we have a duplicate we want to know it
+ QSet LocalGroups;
+
+ QStringList ProcessGroups = m_pBox->GetTextList("ProcessGroup", m_Template);
+ foreach(const QString& Group, ProcessGroups)
+ {
+ QStringList Entries = Group.split(",");
+ QString GroupName = Entries.takeFirst();
+ GroupMap.insertMulti(GroupName, Entries);
+ LocalGroups.insert(GroupName);
+ }
+
+ foreach(const QString& Template, m_pBox->GetTemplates())
+ {
+ foreach(const QString& Group, m_pBox->GetTextListTmpl("ProcessGroup", Template))
+ {
+ m_TemplateGroups.insert(Group);
+ QStringList Entries = Group.split(",");
+ QString GroupName = Entries.takeFirst();
+ if (LocalGroups.contains(GroupName))
+ continue; // local group definitions overwrite template once
+ GroupMap.insertMulti(GroupName, Entries);
+ }
+ }
+
+ for(QMultiMap::iterator I = GroupMap.begin(); I != GroupMap.end(); ++I)
+ {
+ QString GroupName = I.key();
+ QStringList Entries = I.value();
+ QTreeWidgetItem* pItem = new QTreeWidgetItem();
+ pItem->setData(0, Qt::UserRole, GroupName);
+ if (GroupName.length() > 2)
+ GroupName = GroupName.mid(1, GroupName.length() - 2);
+ pItem->setText(0, GroupName);
+ for (int i = 1; i < Entries.count(); i++)
+ {
+ QTreeWidgetItem* pSubItem = new QTreeWidgetItem();
+ SetProgramItem(Entries[i], pSubItem, 0);
+ pItem->addChild(pSubItem);
+ }
+ ui.treeGroups->addTopLevelItem(pItem);
+ }
+ ui.treeGroups->expandAll();
+
+ m_GroupsChanged = false;
+}
+
+void COptionsWindow::SaveGroups()
+{
+ QStringList ProcessGroups;
+ for (int i = 0; i < ui.treeGroups->topLevelItemCount(); i++)
+ {
+ QTreeWidgetItem* pItem = ui.treeGroups->topLevelItem(i);
+ QString GroupName = pItem->data(0, Qt::UserRole).toString();
+ QStringList Programs;
+ for (int j = 0; j < pItem->childCount(); j++)
+ Programs.append(pItem->child(j)->data(0, Qt::UserRole).toString());
+ QString Group = GroupName + "," + Programs.join(",");
+ if (m_TemplateGroups.contains(Group))
+ continue; // don't save unchanged groups to local config
+ ProcessGroups.append(Group);
+ }
+
+ m_pBox->UpdateTextList("ProcessGroup", ProcessGroups);
+
+ m_GroupsChanged = false;
+}
+
+void COptionsWindow::OnAddGroup()
+{
+ QString Value = QInputDialog::getText(this, "Sandboxie-Plus", tr("Please enter a name for the new group"), QLineEdit::Normal, "NewGroup");
+ if (Value.isEmpty())
+ return;
+
+ for (int i = 0; i < ui.treeGroups->topLevelItemCount(); i++) {
+ QTreeWidgetItem* pItem = ui.treeGroups->topLevelItem(i);
+ if (pItem->text(0).compare(Value, Qt::CaseInsensitive) == 0)
+ return;
+ }
+
+ QTreeWidgetItem* pItem = new QTreeWidgetItem();
+ pItem->setText(0, Value);
+ pItem->setData(0, Qt::UserRole, "<" + Value + ">");
+ ui.treeGroups->addTopLevelItem(pItem);
+
+ m_GroupsChanged = true;
+}
+
+QString COptionsWindow::SelectProgram(bool bOrGroup)
+{
+ CComboInputDialog progDialog(this);
+ progDialog.setText(tr("Enter program:"));
+ progDialog.setEditable(true);
+
+ if (bOrGroup)
+ {
+ for (int i = 0; i < ui.treeGroups->topLevelItemCount(); i++) {
+ QTreeWidgetItem* pItem = ui.treeGroups->topLevelItem(i);
+ progDialog.addItem(tr("Group: %1").arg(pItem->text(0)), pItem->data(0, Qt::UserRole).toString());
+ }
+ }
+
+ progDialog.setValue("");
+
+ if (!progDialog.exec())
+ return QString();
+
+ QString Program = progDialog.value();
+ int Index = progDialog.findValue(Program);
+ if (Index != -1)
+ Program = progDialog.data().toString();
+
+ return Program;
+}
+
+void COptionsWindow::OnAddProg()
+{
+ QTreeWidgetItem* pItem = ui.treeGroups->currentItem();
+ while (pItem && pItem->parent())
+ pItem = pItem->parent();
+
+ if (!pItem)
+ {
+ QMessageBox::warning(this, "SandboxiePlus", tr("Please sellect group first."));
+ return;
+ }
+
+ QString Value = SelectProgram();
+ if (Value.isEmpty())
+ return;
+
+ QTreeWidgetItem* pSubItem = new QTreeWidgetItem();
+ SetProgramItem(Value, pSubItem, 0);
+ pItem->addChild(pSubItem);
+
+ m_GroupsChanged = true;
+}
+
+void COptionsWindow::OnDelProg()
+{
+ QTreeWidgetItem* pItem = ui.treeGroups->currentItem();
+ if (!pItem)
+ return;
+
+ delete pItem;
+
+ m_GroupsChanged = true;
+}
+
+void COptionsWindow::CopyGroupToList(const QString& Groupe, QTreeWidget* pTree)
+{
+ pTree->clear();
+
+ for (int i = 0; i < ui.treeGroups->topLevelItemCount(); i++)
+ {
+ QTreeWidgetItem* pItem = ui.treeGroups->topLevelItem(i);
+ if (pItem->data(0, Qt::UserRole).toString().compare(Groupe, Qt::CaseInsensitive) == 0)
+ {
+ for (int j = 0; j < pItem->childCount(); j++)
+ {
+ QString Value = pItem->child(j)->data(0, Qt::UserRole).toString();
+
+ QTreeWidgetItem* pSubItem = new QTreeWidgetItem();
+ SetProgramItem(Value, pSubItem, 0);
+ pTree->addTopLevelItem(pSubItem);
+ }
+ break;
+ }
+ }
+}
+
+void COptionsWindow::LoadForced()
+{
+ ui.treeForced->clear();
+
+ foreach(const QString& Value, m_pBox->GetTextList("ForceProcess", m_Template))
+ AddForcedEntry(Value, 1);
+
+ foreach(const QString& Value, m_pBox->GetTextList("ForceFolder", m_Template))
+ AddForcedEntry(Value, 2);
+
+ if (ui.chkShowForceTmpl->isChecked())
+ {
+ foreach(const QString& Template, m_pBox->GetTemplates())
+ {
+ foreach(const QString& Value, m_pBox->GetTextListTmpl("ForceProcess", Template))
+ AddForcedEntry(Value, 1, Template);
+
+ foreach(const QString& Value, m_pBox->GetTextListTmpl("ForceFolder", Template))
+ AddForcedEntry(Value, 2, Template);
+ }
+ }
+
+ m_ForcedChanged = false;
+}
+
+void COptionsWindow::AddForcedEntry(const QString& Name, int type, const QString& Template)
+{
+ QTreeWidgetItem* pItem = new QTreeWidgetItem();
+ pItem->setText(0, (type == 1 ? tr("Process") : tr("Folder")) + (Template.isEmpty() ? "" : (" (" + Template + ")")));
+ pItem->setData(0, Qt::UserRole, Template.isEmpty() ? type : -1);
+ SetProgramItem(Name, pItem, 1);
+ ui.treeForced->addTopLevelItem(pItem);
+}
+
+void COptionsWindow::SaveForced()
+{
+ QStringList ForceProcess;
+ QStringList ForceFolder;
+ for (int i = 0; i < ui.treeForced->topLevelItemCount(); i++)
+ {
+ QTreeWidgetItem* pItem = ui.treeForced->topLevelItem(i);
+ int Type = pItem->data(0, Qt::UserRole).toInt();
+ if (Type == -1)
+ continue; // entry from template
+ switch (Type)
+ {
+ case 1: ForceProcess.append(pItem->data(1, Qt::UserRole).toString()); break;
+ case 2: ForceFolder.append(pItem->data(1, Qt::UserRole).toString()); break;
+ }
+ }
+
+ m_pBox->UpdateTextList("ForceProcess", ForceProcess);
+ m_pBox->UpdateTextList("ForceFolder", ForceFolder);
+
+ m_ForcedChanged = false;
+}
+
+void COptionsWindow::OnForceProg()
+{
+ QString Value = SelectProgram();
+ if (Value.isEmpty())
+ return;
+ AddForcedEntry(Value, 1);
+ m_ForcedChanged = true;
+}
+
+void COptionsWindow::OnForceDir()
+{
+ QString Value = QFileDialog::getExistingDirectory(this, tr("Select Directory"));
+ if (Value.isEmpty())
+ return;
+ AddForcedEntry(Value, 2);
+ m_ForcedChanged = true;
+}
+
+void COptionsWindow::OnDelForce()
+{
+ DeleteAccessEntry(ui.treeForced->currentItem());
+ m_ForcedChanged = true;
+}
+
+void COptionsWindow::LoadStop()
+{
+ ui.treeStop->clear();
+
+ foreach(const QString& Value, m_pBox->GetTextList("LingerProcess", m_Template))
+ AddStopEntry(Value, 1);
+
+ foreach(const QString& Value, m_pBox->GetTextList("LeaderProcess", m_Template))
+ AddStopEntry(Value, 2);
+
+ if (ui.chkShowStopTmpl->isChecked())
+ {
+ foreach(const QString& Template, m_pBox->GetTemplates())
+ {
+ foreach(const QString& Value, m_pBox->GetTextListTmpl("LingerProcess", Template))
+ AddStopEntry(Value, 1, Template);
+
+ foreach(const QString& Value, m_pBox->GetTextListTmpl("LeaderProcess", Template))
+ AddStopEntry(Value, 2, Template);
+ }
+ }
+
+ m_StopChanged = false;
+}
+
+void COptionsWindow::AddStopEntry(const QString& Name, int type, const QString& Template)
+{
+ QTreeWidgetItem* pItem = new QTreeWidgetItem();
+ pItem->setText(0, (type == 1 ? tr("Lingerer") : tr("Leader")) + (Template.isEmpty() ? "" : (" (" + Template + ")")));
+ pItem->setData(0, Qt::UserRole, Template.isEmpty() ? type : -1);
+ SetProgramItem(Name, pItem, 1);
+ ui.treeStop->addTopLevelItem(pItem);
+}
+
+void COptionsWindow::SaveStop()
+{
+ QStringList LingerProcess;
+ QStringList LeaderProcess;
+ for (int i = 0; i < ui.treeForced->topLevelItemCount(); i++)
+ {
+ QTreeWidgetItem* pItem = ui.treeForced->topLevelItem(i);
+ int Type = pItem->data(0, Qt::UserRole).toInt();
+ if (Type == -1)
+ continue; // entry from template
+ switch (Type)
+ {
+ case 1: LingerProcess.append(pItem->data(1, Qt::UserRole).toString()); break;
+ case 2: LeaderProcess.append(pItem->data(1, Qt::UserRole).toString()); break;
+ }
+ }
+
+ m_pBox->UpdateTextList("LingerProcess", LingerProcess);
+ m_pBox->UpdateTextList("LeaderProcess", LeaderProcess);
+
+ m_StopChanged = false;
+}
+
+void COptionsWindow::OnAddLingering()
+{
+ QString Value = SelectProgram();
+ if (Value.isEmpty())
+ return;
+ AddStopEntry(Value, 1);
+ m_StopChanged = true;
+}
+
+void COptionsWindow::OnAddLeader()
+{
+ QString Value = SelectProgram();
+ if (Value.isEmpty())
+ return;
+ AddStopEntry(Value, 2);
+ m_StopChanged = true;
+}
+
+void COptionsWindow::OnDelStopProg()
+{
+ DeleteAccessEntry(ui.treeStop->currentItem());
+ m_StopChanged = true;
+}
+
+void COptionsWindow::OnRestrictStart()
+{
+ bool Enable = ui.chkRestrictStart->isChecked();
+ if (Enable)
+ SetAccessEntry(eIPC, "!", eClosed, "*");
+ else
+ DelAccessEntry(eIPC, "!", eClosed, "*");
+ //m_StartChanged = true;
+}
+
+void COptionsWindow::OnAddStartProg()
+{
+ AddProgToGroup(ui.treeStart, "");
+ //m_StartChanged = true;
+}
+
+void COptionsWindow::OnDelStartProg()
+{
+ DelProgFromGroup(ui.treeStart, "");
+ //m_StartChanged = true;
+}
+
+void COptionsWindow::OnBlockINet()
+{
+ bool Enable = ui.chkBlockINet->isChecked();
+ if (Enable)
+ SetAccessEntry(eFile, "!", eClosed, "InternetAccessDevices");
+ else
+ DelAccessEntry(eFile, "!", eClosed, "InternetAccessDevices");
+ //m_INetBlockChanged = true;
+}
+
+void COptionsWindow::OnAddINetProg()
+{
+ AddProgToGroup(ui.treeINet, "");
+ //m_INetBlockChanged = true;
+}
+
+void COptionsWindow::OnDelINetProg()
+{
+ DelProgFromGroup(ui.treeINet, "");
+ //m_INetBlockChanged = true;
+}
+
+void COptionsWindow::AddProgToGroup(QTreeWidget* pTree, const QString& Groupe)
+{
+ QString Value = SelectProgram();
+ if (Value.isEmpty())
+ return;
+
+ QTreeWidgetItem* pItem = new QTreeWidgetItem();
+ SetProgramItem(Value, pItem, 0);
+ pTree->addTopLevelItem(pItem);
+
+ AddProgToGroup(Value, Groupe);
+}
+
+void COptionsWindow::AddProgToGroup(const QString& Value, const QString& Groupe)
+{
+ QTreeWidgetItem* pGroupItem = NULL;
+ for (int i = 0; i < ui.treeGroups->topLevelItemCount(); i++)
+ {
+ QTreeWidgetItem* pCurItem = ui.treeGroups->topLevelItem(i);
+ if (pCurItem->data(0, Qt::UserRole).toString().compare(Groupe, Qt::CaseInsensitive) == 0)
+ {
+ pGroupItem = pCurItem;
+ break;
+ }
+ }
+
+ if (!pGroupItem)
+ {
+ pGroupItem = new QTreeWidgetItem();
+ pGroupItem->setText(0, Groupe.mid(1, Groupe.length()-2));
+ pGroupItem->setData(0, Qt::UserRole, Groupe);
+ ui.treeGroups->addTopLevelItem(pGroupItem);
+ }
+
+ QTreeWidgetItem* pProgItem = new QTreeWidgetItem();
+ SetProgramItem(Value, pProgItem, 0);
+ pGroupItem->addChild(pProgItem);
+
+ m_GroupsChanged = true;
+}
+
+void COptionsWindow::DelProgFromGroup(QTreeWidget* pTree, const QString& Groupe)
+{
+ QTreeWidgetItem* pItem = pTree->currentItem();
+ if (!pItem)
+ return;
+
+ QString Value = pItem->data(0, Qt::UserRole).toString();
+
+ delete pItem;
+
+ for (int i = 0; i < ui.treeGroups->topLevelItemCount(); i++)
+ {
+ QTreeWidgetItem* pGroupItem = ui.treeGroups->topLevelItem(i);
+ if (pGroupItem->data(0, Qt::UserRole).toString().compare(Groupe, Qt::CaseInsensitive) == 0)
+ {
+ for (int j = 0; j < pGroupItem->childCount(); j++)
+ {
+ QTreeWidgetItem* pProgItem = pGroupItem->child(j);
+ if (pProgItem->data(0, Qt::UserRole).toString().compare(Value, Qt::CaseInsensitive) == 0)
+ {
+ delete pProgItem;
+ m_GroupsChanged = true;
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
+QTreeWidgetItem* COptionsWindow::GetAccessEntry(EAccessType Type, const QString& Program, EAccessMode Mode, const QString& Path)
+{
+ for (int i = 0; i < ui.treeAccess->topLevelItemCount(); i++)
+ {
+ QTreeWidgetItem* pItem = ui.treeAccess->topLevelItem(i);
+ if (pItem->data(0, Qt::UserRole).toInt() == Type
+ && pItem->data(1, Qt::UserRole).toString().compare(Program, Qt::CaseInsensitive) == 0
+ && pItem->data(2, Qt::UserRole).toInt() == Mode
+ && pItem->data(3, Qt::UserRole).toString().compare(Path, Qt::CaseInsensitive) == 0)
+ return pItem;
+ }
+ return NULL;
+}
+
+void COptionsWindow::SetAccessEntry(EAccessType Type, const QString& Program, EAccessMode Mode, const QString& Path)
+{
+ if (GetAccessEntry(Type, Program, Mode, Path) != NULL)
+ return; // already set
+ AddAccessEntry(Type, Mode, Program, Path);
+}
+
+void COptionsWindow::DelAccessEntry(EAccessType Type, const QString& Program, EAccessMode Mode, const QString& Path)
+{
+ if(QTreeWidgetItem* pItem = GetAccessEntry(Type, Program, Mode, Path))
+ {
+ delete pItem;
+ m_AccessChanged = true;
+ }
+}
+
+QString COptionsWindow::AccessTypeToName(EAccessEntry Type)
+{
+ switch (Type)
+ {
+ case eOpenFilePath: return "OpenFilePath";
+ case eOpenPipePath: return "OpenPipePath";
+ case eClosedFilePath: return "ClosedFilePath";
+ case eReadFilePath: return "ReadFilePath";
+ case eWriteFilePath: return "WriteFilePath";
+
+ case eOpenKeyPath: return "OpenKeyPath";
+ case eClosedKeyPath: return "ClosedKeyPath";
+ case eReadKeyPath: return "ReadKeyPath";
+ case eWriteKeyPath: return "WriteKeyPath";
+
+ case eOpenIpcPath: return "OpenIpcPath";
+ case eClosedIpcPath: return "ClosedIpcPath";
+
+ case eOpenWinClass: return "OpenWinClass";
+
+ case eOpenClsid: return "OpenClsid";
+ }
+ return "Unknown";
+}
+
+void COptionsWindow::LoadAccessList()
+{
+ ui.treeAccess->clear();
+
+ for (int i = 0; i < eMaxAccessType; i++)
+ {
+ foreach(const QString& Value, m_pBox->GetTextList(AccessTypeToName((EAccessEntry)i), m_Template))
+ ParseAndAddAccessEntry((EAccessEntry)i, Value);
+ }
+
+ if (ui.chkShowAccessTmpl->isChecked())
+ {
+ foreach(const QString& Template, m_pBox->GetTemplates())
+ {
+ for (int i = 0; i < eMaxAccessType; i++)
+ {
+ foreach(const QString& Value, m_pBox->GetTextListTmpl(AccessTypeToName((EAccessEntry)i), Template))
+ ParseAndAddAccessEntry((EAccessEntry)i, Value, Template);
+ }
+ }
+ }
+
+ m_AccessChanged = false;
+}
+
+void COptionsWindow::ParseAndAddAccessEntry(EAccessEntry EntryType, const QString& Value, const QString& Template)
+{
+ EAccessType Type;
+ EAccessMode Mode;
+ switch (EntryType)
+ {
+ case eOpenFilePath: Type = eFile; Mode = eDirect; break;
+ case eOpenPipePath: Type = eFile; Mode = eFull; break;
+ case eClosedFilePath: Type = eFile; Mode = eClosed; break;
+ case eReadFilePath: Type = eFile; Mode = eReadOnly; break;
+ case eWriteFilePath: Type = eFile; Mode = eWriteOnly; break;
+
+ case eOpenKeyPath: Type = eKey; Mode = eDirect; break;
+ case eClosedKeyPath: Type = eKey; Mode = eClosed; break;
+ case eReadKeyPath: Type = eKey; Mode = eReadOnly; break;
+ case eWriteKeyPath: Type = eKey; Mode = eWriteOnly; break;
+
+ case eOpenIpcPath: Type = eIPC; Mode = eDirect; break;
+ case eClosedIpcPath: Type = eIPC; Mode = eClosed; break;
+
+ case eOpenWinClass: Type = eWndCls; Mode = eDirect; break;
+
+ case eOpenClsid: Type = eClsId; Mode = eDirect; break;
+
+ default: return;
+ }
+
+ QStringList Values = Value.split(",");
+ if (Values.count() >= 2)
+ AddAccessEntry(Type, Mode, Values[0], Values[1], Template);
+ else // all programs
+ AddAccessEntry(Type, Mode, "", Values[0], Template);
+}
+
+QString COptionsWindow::GetAccessModeStr(EAccessMode Mode)
+{
+ switch (Mode)
+ {
+ case eDirect: return "Direct";
+ case eFull: return "Full";
+ case eClosed: return "Closed";
+ case eReadOnly: return "Read Only";
+ case eWriteOnly: return "Write Only";
+ }
+ return "Unknown";
+}
+
+QString COptionsWindow::GetAccessTypeStr(EAccessType Type)
+{
+ switch (Type)
+ {
+ case eFile: return "File/Folder";
+ case eKey: return "Registry";
+ case eIPC: return "IPC Path";
+ case eWndCls: return "Wnd Class";
+ case eClsId: return "COM Object";
+ }
+ return "Unknown";
+}
+
+void COptionsWindow::AddAccessEntry(EAccessType Type, EAccessMode Mode, QString Program, const QString& Path, const QString& Template)
+{
+ QTreeWidgetItem* pItem = new QTreeWidgetItem();
+
+ pItem->setText(0, GetAccessTypeStr(Type) + (Template.isEmpty() ? "" : " (" + Template + ")"));
+ pItem->setData(0, Qt::UserRole, !Template.isEmpty() ? -1 : (int)Type);
+
+ pItem->setData(1, Qt::UserRole, Program);
+ if (Program.isEmpty())
+ Program = tr("All Programs");
+ bool Not = Program.left(1) == "!";
+ if (Not)
+ Program.remove(0, 1);
+ if (Program.left(1) == "<")
+ Program = tr("Group: %1").arg(Program.mid(1, Program.length() - 2));
+ pItem->setText(1, (Not ? "NOT " : "") + Program);
+
+ pItem->setText(2, GetAccessModeStr(Mode));
+ pItem->setData(2, Qt::UserRole, (int)Mode);
+
+ pItem->setText(3, Path);
+ pItem->setData(3, Qt::UserRole, Path);
+
+ ui.treeAccess->addTopLevelItem(pItem);
+}
+
+QString COptionsWindow::MakeAccessStr(EAccessType Type, EAccessMode Mode)
+{
+ switch (Type)
+ {
+ case eFile:
+ switch (Mode)
+ {
+ case eDirect: return "OpenFilePath";
+ case eFull: return "OpenPipePath";
+ case eClosed: return "ClosedFilePath";
+ case eReadOnly: return "ReadFilePath";
+ case eWriteOnly: return "WriteFilePath";
+ }
+ break;
+ case eKey:
+ switch (Mode)
+ {
+ case eDirect: return "OpenKeyPath";
+ case eClosed: return "ClosedKeyPath";
+ case eReadOnly: return "ReadKeyPath";
+ case eWriteOnly: return "WriteKeyPath";
+ }
+ break;
+ case eIPC:
+ switch (Mode)
+ {
+ case eDirect: return "OpenIpcPath";
+ case eClosed: return "ClosedIpcPath";
+ }
+ break;
+ case eWndCls:
+ switch (Mode)
+ {
+ case eDirect: return "OpenWinClass";
+ }
+ break;
+ case eClsId:
+ switch (Mode)
+ {
+ case eDirect: return "OpenClsid";
+ }
+ break;
+ }
+ return "Unknown";
+}
+
+void COptionsWindow::SaveAccessList()
+{
+ QMultiMap AccessMap;
+ for (int i = 0; i < ui.treeAccess->topLevelItemCount(); i++)
+ {
+ QTreeWidgetItem* pItem = ui.treeAccess->topLevelItem(i);
+ int Type = pItem->data(0, Qt::UserRole).toInt();
+ if (Type == -1)
+ continue; // entry from template
+ int Mode = pItem->data(2, Qt::UserRole).toInt();
+ QString Program = pItem->data(1, Qt::UserRole).toString();
+ QString Value = pItem->data(3, Qt::UserRole).toString();
+ if (Program.isEmpty())
+ Value.prepend(Program + ",");
+ AccessMap.insertMulti(MakeAccessStr((EAccessType)Type, (EAccessMode)Mode), Value);
+ }
+
+ foreach(const QString& Key, AccessMap.uniqueKeys())
+ m_pBox->UpdateTextList(Key, AccessMap.values(Key));
+
+ m_AccessChanged = false;
+}
+
+void COptionsWindow::OnAccessItemClicked(QTreeWidgetItem* pItem, int Column)
+{
+ if (Column != 0)
+ return;
+
+ QWidget* pProgram = ui.treeAccess->itemWidget(pItem, 1);
+ if (!pProgram)
+ return;
+
+ QHBoxLayout* pLayout = (QHBoxLayout*)pProgram->layout();
+ QToolButton* pNot = (QToolButton*)pLayout->itemAt(0)->widget();
+ QComboBox* pCombo = (QComboBox*)pLayout->itemAt(1)->widget();
+
+ QComboBox* pMode = (QComboBox*)ui.treeAccess->itemWidget(pItem, 2);
+ QLineEdit* pPath = (QLineEdit*)ui.treeAccess->itemWidget(pItem, 3);
+
+ QString Program = pCombo->currentText();
+ int Index = pCombo->findText(Program);
+ if(Index != -1)
+ Program = pCombo->itemData(Index, Qt::UserRole).toString();
+
+ pItem->setText(1, (pNot->isChecked() ? "NOT " : "") + pCombo->currentText());
+ pItem->setData(1, Qt::UserRole, (pNot->isChecked() ? "!" : "") + Program);
+ pItem->setText(2, GetAccessModeStr((EAccessMode)pMode->currentData().toInt()));
+ pItem->setData(2, Qt::UserRole, pMode->currentData());
+ pItem->setText(3, pPath->text());
+ pItem->setData(3, Qt::UserRole, pPath->text());
+
+ ui.treeAccess->setItemWidget(pItem, 1, NULL);
+ ui.treeAccess->setItemWidget(pItem, 2, NULL);
+ ui.treeAccess->setItemWidget(pItem, 3, NULL);
+
+ m_AccessChanged = true;
+}
+
+QList COptionsWindow::GetAccessModes(EAccessType Type)
+{
+ switch (Type)
+ {
+ case eFile: return QList() << eDirect << eFull << eClosed << eReadOnly << eWriteOnly;
+ case eKey: return QList() << eDirect << eClosed << eReadOnly << eWriteOnly;
+ case eIPC: return QList() << eDirect << eClosed;
+ }
+ return QList() << eDirect;
+}
+
+void COptionsWindow::OnAccessItemDoubleClicked(QTreeWidgetItem* pItem, int Column)
+{
+ if (Column == 0)
+ return;
+
+ int Type = pItem->data(0, Qt::UserRole).toInt();
+ if (Type == -1) {
+ QMessageBox::warning(this, "SandboxiePlus", tr("Template values can not be edited."));
+ return;
+ }
+
+ QString Program = pItem->data(1, Qt::UserRole).toString();
+
+ QWidget* pProgram = new QWidget();
+ pProgram->setAutoFillBackground(true);
+ QHBoxLayout* pLayout = new QHBoxLayout();
+ pLayout->setMargin(0);
+ pLayout->setSpacing(0);
+ pProgram->setLayout(pLayout);
+ QToolButton* pNot = new QToolButton(pProgram);
+ pNot->setText("!");
+ pNot->setCheckable(true);
+ if (Program.left(1) == "!"){
+ pNot->setChecked(true);
+ Program.remove(0, 1);
+ }
+ pLayout->addWidget(pNot);
+ QComboBox* pCombo = new QComboBox(pProgram);
+ pCombo->addItem(tr("All Programs"), "");
+
+ // todo: add recently ran programs or programs from other configs
+
+ for (int i = 0; i < ui.treeGroups->topLevelItemCount(); i++) {
+ QTreeWidgetItem* pItem = ui.treeGroups->topLevelItem(i);
+ pCombo->addItem(tr("Group: %1").arg(pItem->text(0)), "<" + pItem->text(0) + ">");
+ }
+
+ pCombo->setEditable(true);
+ int Index = pCombo->findData(Program);
+ pCombo->setCurrentIndex(Index);
+ if(Index == -1)
+ pCombo->setCurrentText(Program);
+ pLayout->addWidget(pCombo);
+
+ ui.treeAccess->setItemWidget(pItem, 1, pProgram);
+
+ QComboBox* pMode = new QComboBox();
+ foreach(EAccessMode Mode, GetAccessModes((EAccessType)Type))
+ pMode->addItem(GetAccessModeStr(Mode), (int)Mode);
+ pMode->setCurrentIndex(pMode->findData(pItem->data(2, Qt::UserRole)));
+ ui.treeAccess->setItemWidget(pItem, 2, pMode);
+
+ QLineEdit* pPath = new QLineEdit();
+ pPath->setText(pItem->data(3, Qt::UserRole).toString());
+ ui.treeAccess->setItemWidget(pItem, 3, pPath);
+}
+
+void COptionsWindow::DeleteAccessEntry(QTreeWidgetItem* pItem)
+{
+ if (!pItem)
+ return;
+
+ if (pItem->data(0, Qt::UserRole).toInt() == -1) {
+ QMessageBox::warning(this, "SandboxiePlus", tr("Template values can not be removed."));
+ return;
+ }
+
+ delete pItem;
+}
+
+void COptionsWindow::OnDelAccess()
+{
+ DeleteAccessEntry(ui.treeAccess->currentItem());
+ m_AccessChanged = true;
+}
+
+void COptionsWindow::OnAdvancedChanged()
+{
+ m_AdvancedChanged = true;
+
+ ui.chkAutoEmpty->setEnabled(!ui.chkProtectBox->isChecked());
+ ui.cmbEmptyCmd->setEnabled(!ui.chkProtectBox->isChecked());
+}
+
+#include
+#include
+
+void COptionsWindow::OnAddUser()
+{
+ QStringList Users;
+
+ IDsObjectPicker *pObjectPicker = NULL;
+ HRESULT hr = CoCreateInstance(CLSID_DsObjectPicker, NULL, CLSCTX_INPROC_SERVER, IID_IDsObjectPicker, (void **)&pObjectPicker);
+ if (FAILED(hr))
+ return;
+
+ DSOP_SCOPE_INIT_INFO ScopeInit;
+ memset(&ScopeInit, 0, sizeof(DSOP_SCOPE_INIT_INFO));
+ ScopeInit.cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
+ ScopeInit.flType = DSOP_SCOPE_TYPE_TARGET_COMPUTER | DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN;
+ ScopeInit.flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE | DSOP_SCOPE_FLAG_DEFAULT_FILTER_USERS | DSOP_SCOPE_FLAG_DEFAULT_FILTER_GROUPS;
+ ScopeInit.FilterFlags.Uplevel.flBothModes = DSOP_FILTER_USERS | DSOP_FILTER_WELL_KNOWN_PRINCIPALS | DSOP_FILTER_BUILTIN_GROUPS
+ | DSOP_FILTER_UNIVERSAL_GROUPS_SE | DSOP_FILTER_GLOBAL_GROUPS_SE | DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE;
+ ScopeInit.FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_USERS | DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS | DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS;
+
+ DSOP_INIT_INFO InitInfo;
+ memset(&InitInfo, 0, sizeof(InitInfo));
+ InitInfo.cbSize = sizeof(InitInfo);
+ InitInfo.pwzTargetComputer = NULL;
+ InitInfo.cDsScopeInfos = 1;
+ InitInfo.aDsScopeInfos = &ScopeInit;
+ InitInfo.flOptions = DSOP_FLAG_MULTISELECT;
+
+ hr = pObjectPicker->Initialize(&InitInfo);
+
+ if (SUCCEEDED(hr))
+ {
+ IDataObject *pDataObject = NULL;
+ hr = pObjectPicker->InvokeDialog((HWND)this->winId(), &pDataObject);
+ if (SUCCEEDED(hr) && pDataObject)
+ {
+ FORMATETC formatEtc;
+ formatEtc.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
+ formatEtc.ptd = NULL;
+ formatEtc.dwAspect = DVASPECT_CONTENT;
+ formatEtc.lindex = -1;
+ formatEtc.tymed = TYMED_HGLOBAL;
+
+ STGMEDIUM stgMedium;
+ hr = pDataObject->GetData(&formatEtc, &stgMedium);
+ if (SUCCEEDED(hr))
+ {
+ PDS_SELECTION_LIST pResults = (PDS_SELECTION_LIST)GlobalLock(stgMedium.hGlobal);
+ if (pResults)
+ {
+ for (ULONG i = 0; i < pResults->cItems; i++)
+ Users.append(QString::fromWCharArray(pResults->aDsSelection[i].pwzName));
+ GlobalUnlock(stgMedium.hGlobal);
+ }
+ }
+ pDataObject->Release();
+ }
+ }
+ pObjectPicker->Release();
+
+
+ if (Users.isEmpty())
+ return;
+
+ ui.lstUsers->addItems(Users);
+}
+
+void COptionsWindow::OnDelUser()
+{
+ foreach(QListWidgetItem* pItem, ui.lstUsers->selectedItems())
+ delete pItem;
+}
+
+void COptionsWindow::LoadTemplates()
+{
+ m_AllTemplates.clear();
+ ui.cmbCategories->clear();
+
+ QStringList Templates;
+ for (int index = 0; ; index++)
+ {
+ QString Value = m_pBox->GetAPI()->SbieIniGet("", "", index);
+ if (Value.isNull())
+ break;
+ Templates.append(Value);
+ }
+
+ for (QStringList::iterator I = Templates.begin(); I != Templates.end();)
+ {
+ if (I->left(9).compare("Template_", Qt::CaseInsensitive) != 0 || *I == "Template_KnownConflicts") {
+ I = Templates.erase(I);
+ continue;
+ }
+
+ QString Name = *I++;
+ QString Category = m_pBox->GetAPI()->SbieIniGet(Name, "Tmpl.Class", 0x40000000L); // CONF_GET_NO_GLOBAL);
+ QString Title = m_pBox->GetAPI()->SbieIniGet(Name, "Tmpl.Title", 0x40000000L); // CONF_GET_NO_GLOBAL);
+
+ if (Title.left(1) == "#")
+ {
+ int End = Title.mid(1).indexOf(",");
+ if (End == -1) End = Title.length() - 1;
+ int MsgNum = Title.mid(1, End).toInt();
+ Title = m_pBox->GetAPI()->GetSbieMessage(MsgNum, Title.mid(End+2));
+ }
+ if (Title.isEmpty()) Title = Name;
+ //else Title += " (" + Name + ")";
+ if (Title == "-")
+ continue; // skip separators
+
+ m_AllTemplates.insertMulti(Category, qMakePair(Name, Title));
+ }
+
+ ui.cmbCategories->addItem(tr("All Categories"), "");
+ ui.cmbCategories->setCurrentIndex(0);
+ foreach(const QString& Category, m_AllTemplates.uniqueKeys())
+ {
+ if (Category.isEmpty())
+ continue;
+ ui.cmbCategories->addItem(Category, Category);
+ }
+
+ m_GlobalTemplates = m_pBox->GetAPI()->GetGlobalSettings()->GetTextList("Template", false);
+ m_BoxTemplates = m_pBox->GetTextList("Template", false);
+
+ ShowTemplates();
+}
+
+void COptionsWindow::ShowTemplates()
+{
+ ui.treeTemplates->clear();
+
+ QString Category = ui.cmbCategories->currentData().toString();
+
+ for (QMultiMap>::iterator I = m_AllTemplates.begin(); I != m_AllTemplates.end(); ++I)
+ {
+ if (!Category.isEmpty() && I.key().compare(Category, Qt::CaseInsensitive) != 0)
+ continue;
+
+ QString Name = I.value().first.mid(9);
+
+ QTreeWidgetItem* pItem = new QTreeWidgetItem();
+ pItem->setText(0, I.key());
+ pItem->setData(1, Qt::UserRole, I.value().first);
+ pItem->setText(1, I.value().second);
+ //pItem->setFlags(pItem->flags() | Qt::ItemIsUserCheckable);
+ if(m_GlobalTemplates.contains(Name))
+ pItem->setCheckState(1, Qt::PartiallyChecked);
+ else if (m_BoxTemplates.contains(Name))
+ pItem->setCheckState(1, Qt::Checked);
+ else
+ pItem->setCheckState(1, Qt::Unchecked);
+ ui.treeTemplates->addTopLevelItem(pItem);
+ }
+}
+
+void COptionsWindow::OnTemplateClicked(QTreeWidgetItem* pItem, int Column)
+{
+ QString Name = pItem->data(1, Qt::UserRole).toString().mid(9);
+ if (m_GlobalTemplates.contains(Name)) {
+ QMessageBox::warning(this, "SandboxiePlus", tr("This template is enabled globally to configure it use the global options."));
+ pItem->setCheckState(1, Qt::PartiallyChecked);
+ return;
+ }
+
+ if (pItem->checkState(1) == Qt::Checked) {
+ if (!m_BoxTemplates.contains(Name)) {
+ m_BoxTemplates.append(Name);
+ m_TemplatesChanged = true;
+ }
+ }
+ else if (pItem->checkState(1) == Qt::Unchecked) {
+ if (m_BoxTemplates.contains(Name)) {
+ m_BoxTemplates.removeAll(Name);
+ m_TemplatesChanged = true;
+ }
+ }
+}
+
+void COptionsWindow::OnTemplateDoubleClicked(QTreeWidgetItem* pItem, int Column)
+{
+ QSharedPointer pTemplate = QSharedPointer(new CSbieIni(pItem->data(1, Qt::UserRole).toString(), m_pBox->GetAPI()));
+
+ COptionsWindow* pOptionsWindow = new COptionsWindow(pTemplate, pItem->text(1), this);
+ pOptionsWindow->show();
+}
+
+void COptionsWindow::SaveTemplates()
+{
+ m_pBox->UpdateTextList("Template", m_BoxTemplates);
+
+ m_TemplatesChanged = false;
+}
+
+void COptionsWindow::OnTab()
+{
+ if (ui.tabs->currentWidget() == ui.tabEdit)
+ {
+ LoadIniSection();
+ ui.txtIniSection->setReadOnly(true);
+ }
+ else
+ {
+ if (m_ConfigDirty)
+ LoadConfig();
+
+ if (ui.tabs->currentWidget() == ui.tabStart)
+ {
+ ui.chkRestrictStart->setChecked(GetAccessEntry(eIPC, "!", eClosed, "*") != NULL);
+ CopyGroupToList("", ui.treeStart);
+ }
+ else if (ui.tabs->currentWidget() == ui.tabInternet)
+ {
+ ui.chkBlockINet->setChecked(GetAccessEntry(eFile, "!", eClosed, "InternetAccessDevices") != NULL);
+ CopyGroupToList("", ui.treeINet);
+ }
+ }
+}
+
+void COptionsWindow::SetIniEdit(bool bEnable)
+{
+ for (int i = 0; i < ui.tabs->count() - 1; i++) {
+ bool Enabled = ui.tabs->widget(i)->isEnabled();
+ ui.tabs->setTabEnabled(i, !bEnable && Enabled);
+ ui.tabs->widget(i)->setEnabled(Enabled);
+ }
+ ui.btnSaveIni->setEnabled(bEnable);
+ ui.btnCancelEdit->setEnabled(bEnable);
+ ui.txtIniSection->setReadOnly(!bEnable);
+ ui.btnEditIni->setEnabled(!bEnable);
+}
+
+void COptionsWindow::OnEditIni()
+{
+ SetIniEdit(true);
+}
+
+void COptionsWindow::OnSaveIni()
+{
+ SaveIniSection();
+ SetIniEdit(false);
+}
+
+void COptionsWindow::OnCancelEdit()
+{
+ SetIniEdit(false);
+}
+
+void COptionsWindow::LoadIniSection()
+{
+ QString Section;
+
+ m_Settings = m_pBox->GetIniSection(NULL, m_Template);
+
+ for (QList>::const_iterator I = m_Settings.begin(); I != m_Settings.end(); ++I)
+ Section += I->first + "=" + I->second + "\n";
+
+ ui.txtIniSection->setPlainText(Section);
+}
+
+void COptionsWindow::SaveIniSection()
+{
+ m_ConfigDirty = true;
+
+ // Note: an incremental update would be more elegat but it would change the entry order in the ini,
+ // hence its better for the user to fully rebuild the section each time.
+ //
+ for (QList>::const_iterator I = m_Settings.begin(); I != m_Settings.end(); ++I)
+ m_pBox->DelValue(I->first, I->second);
+
+ //QList> NewSettings;
+ //QList> OldSettings = m_Settings;
+
+ QStringList Section = SplitStr(ui.txtIniSection->toPlainText(), "\n");
+ foreach(const QString& Line, Section)
+ {
+ if (Line.isEmpty())
+ return;
+ StrPair Settings = Split2(Line, "=");
+
+ //if (!OldSettings.removeOne(Settings))
+ // NewSettings.append(Settings);
+
+ m_pBox->InsertText(Settings.first, Settings.second);
+ }
+
+ //for (QList>::const_iterator I = OldSettings.begin(); I != OldSettings.end(); ++I)
+ // m_pBox->DelValue(I->first, I->second);
+ //
+ //for (QList>::const_iterator I = NewSettings.begin(); I != NewSettings.end(); ++I)
+ // m_pBox->InsertText(I->first, I->second);
+
+ LoadIniSection();
+}
\ No newline at end of file
diff --git a/SandboxiePlus/SandMan/Windows/OptionsWindow.h b/SandboxiePlus/SandMan/Windows/OptionsWindow.h
new file mode 100644
index 0000000000..32bd81996d
--- /dev/null
+++ b/SandboxiePlus/SandMan/Windows/OptionsWindow.h
@@ -0,0 +1,196 @@
+#pragma once
+
+#include
+#include "ui_OptionsWindow.h"
+#include "SbiePlusAPI.h"
+
+class COptionsWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ COptionsWindow(const QSharedPointer& pBox, const QString& Name, QWidget *parent = Q_NULLPTR);
+ ~COptionsWindow();
+
+signals:
+ void OptionsChanged();
+
+public slots:
+ void apply();
+ void accept();
+ void reject();
+
+private slots:
+
+ void OnPickColor();
+
+ void OnAddGroup();
+ void OnAddProg();
+ void OnDelProg();
+
+ void OnForceProg();
+ void OnForceDir();
+ void OnDelForce();
+ void OnShowForceTmpl() { LoadForced(); }
+
+ void OnAddLingering();
+ void OnAddLeader();
+ void OnDelStopProg();
+ void OnShowStopTmpl() { LoadStop(); }
+
+ void OnRestrictStart();
+ void OnAddStartProg();
+ void OnDelStartProg();
+
+ void OnBlockINet();
+ void OnAddINetProg();
+ void OnDelINetProg();
+
+ void OnAccessItemClicked(QTreeWidgetItem* pItem, int Column);
+ void OnAccessItemDoubleClicked(QTreeWidgetItem* pItem, int Column);
+
+ void OnAddFile() { AddAccessEntry(eFile, eDirect, "", ""); }
+ void OnAddKey() { AddAccessEntry(eKey, eDirect, "", ""); }
+ void OnAddIPC() { AddAccessEntry(eIPC, eDirect, "", ""); }
+ void OnAddClsId() { AddAccessEntry(eWndCls, eDirect, "", ""); }
+ void OnAddCOM() { AddAccessEntry(eClsId, eDirect, "", ""); }
+ void OnDelAccess();
+ void OnShowAccessTmpl() { LoadAccessList(); }
+
+ void OnAddUser();
+ void OnDelUser();
+
+ void OnFilterTemplates() { ShowTemplates(); }
+ void OnTemplateClicked(QTreeWidgetItem* pItem, int Column);
+ void OnTemplateDoubleClicked(QTreeWidgetItem* pItem, int Column);
+
+ void OnTab();
+
+ void OnGeneralChanged();
+ void OnStartChanged() { m_StartChanged = true; }
+ void OnRestrictionChanged() { m_RestrictionChanged = true; }
+ void OnINetBlockChanged() { m_INetBlockChanged = true; }
+ void OnAdvancedChanged();
+
+ void SetIniEdit(bool bEnable);
+ void OnEditIni();
+ void OnSaveIni();
+ void OnCancelEdit();
+
+protected:
+ void closeEvent(QCloseEvent *e);
+
+ enum EAccessEntry
+ {
+ eOpenFilePath,
+ eOpenPipePath,
+ eClosedFilePath,
+ eReadFilePath,
+ eWriteFilePath,
+
+ eOpenKeyPath,
+ eClosedKeyPath,
+ eReadKeyPath,
+ eWriteKeyPath,
+
+ eOpenIpcPath,
+ eClosedIpcPath,
+
+ eOpenWinClass,
+
+ eOpenClsid,
+
+ eMaxAccessType
+ };
+
+ enum EAccessType
+ {
+ eFile,
+ eKey,
+ eIPC,
+ eWndCls,
+ eClsId
+ };
+
+ enum EAccessMode
+ {
+ eDirect,
+ eFull,
+ eClosed,
+ eReadOnly,
+ eWriteOnly
+ };
+
+ void SetProgramItem(QString Program, QTreeWidgetItem* pItem, int Column);
+
+ QString SelectProgram(bool bOrGroup = true);
+
+ void CopyGroupToList(const QString& Groupe, QTreeWidget* pTree);
+ QTreeWidgetItem* GetAccessEntry(EAccessType Type, const QString& Program, EAccessMode Mode, const QString& Path);
+ void SetAccessEntry(EAccessType Type, const QString& Program, EAccessMode Mode, const QString& Path);
+ void DelAccessEntry(EAccessType Type, const QString& Program, EAccessMode Mode, const QString& Path);
+ void AddProgToGroup(QTreeWidget* pTree, const QString& Groupe);
+ void AddProgToGroup(const QString& Value, const QString& Groupe);
+ void DelProgFromGroup(QTreeWidget* pTree, const QString& Groupe);
+
+ void LoadConfig();
+ void SaveConfig();
+
+ void LoadGroups();
+ void SaveGroups();
+
+ void LoadForced();
+ void AddForcedEntry(const QString& Name, int type, const QString& Template = QString());
+ void SaveForced();
+
+ void LoadStop();
+ void AddStopEntry(const QString& Name, int type, const QString& Template = QString());
+ void SaveStop();
+
+ QString AccessTypeToName(EAccessEntry Type);
+ void LoadAccessList();
+ QString GetAccessTypeStr(EAccessType Type);
+ QString GetAccessModeStr(EAccessMode Mode);
+ void ParseAndAddAccessEntry(EAccessEntry EntryType, const QString& Value, const QString& Template = QString());
+ void AddAccessEntry(EAccessType Type, EAccessMode Mode, QString Program, const QString& Path, const QString& Template = QString());
+ QString MakeAccessStr(EAccessType Type, EAccessMode Mode);
+ void SaveAccessList();
+ QList GetAccessModes(EAccessType Type);
+ void DeleteAccessEntry(QTreeWidgetItem* pItem);
+
+ void LoadTemplates();
+ void ShowTemplates();
+ void SaveTemplates();
+
+ void LoadIniSection();
+ void SaveIniSection();
+
+ bool m_ConfigDirty;
+ QColor m_BorderColor;
+
+ bool m_GeneralChanged;
+ bool m_GroupsChanged;
+ bool m_ForcedChanged;
+ bool m_StopChanged;
+ bool m_StartChanged;
+ bool m_RestrictionChanged;
+ bool m_INetBlockChanged;
+ bool m_AccessChanged;
+ bool m_TemplatesChanged;
+ bool m_AdvancedChanged;
+
+ bool m_Template;
+
+ QSet m_TemplateGroups;
+
+ QMultiMap> m_AllTemplates;
+ QStringList m_GlobalTemplates;
+ QStringList m_BoxTemplates;
+
+ QList> m_Settings;
+
+ QSharedPointer m_pBox;
+
+private:
+ Ui::OptionsWindow ui;
+};
diff --git a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp
new file mode 100644
index 0000000000..0ab181268d
--- /dev/null
+++ b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp
@@ -0,0 +1,168 @@
+#include "stdafx.h"
+#include "SettingsWindow.h"
+#include "SandMan.h"
+#include "../MiscHelpers/Common/Settings.h"
+#include "Helpers/WinAdmin.h"
+
+
+CSettingsWindow::CSettingsWindow(QWidget *parent)
+ : QMainWindow(parent)
+{
+ QWidget* centralWidget = new QWidget();
+ ui.setupUi(centralWidget);
+ this->setCentralWidget(centralWidget);
+ this->setWindowTitle(tr("Sandboxie Plus - Settings"));
+
+ ui.uiLang->addItem("International Englisch", "");
+ QDir langDir(QApplication::applicationDirPath() + "/translations/");
+ foreach(const QString& langFile, langDir.entryList(QStringList("taskexplorer_*.qm"), QDir::Files))
+ {
+ QString Code = langFile.mid(13, langFile.length() - 13 - 3);
+ QLocale Locale(Code);
+ QString Lang = Locale.nativeLanguageName();
+ ui.uiLang->addItem(Lang, Code);
+ }
+ ui.uiLang->setCurrentIndex(ui.uiLang->findData(theConf->GetString("Options/Language")));
+
+ ui.chkAutoStart->setChecked(IsAutorunEnabled());
+
+ ui.chkDarkTheme->setChecked(theConf->GetBool("Options/DarkTheme", false));
+
+ ui.chkNotifications->setChecked(theConf->GetBool("Options/ShowNotifications", true));
+
+ ui.chkWatchConfig->setChecked(theConf->GetBool("Options/WatchIni", true));
+
+ ui.onClose->addItem(tr("Close to Tray"), "ToTray");
+ ui.onClose->addItem(tr("Prompt before Close"), "Prompt");
+ ui.onClose->addItem(tr("Close"), "Close");
+ ui.onClose->setCurrentIndex(ui.onClose->findData(theConf->GetString("Options/OnClose", "ToTray")));
+
+ ui.chkShowTray->setChecked(theConf->GetBool("Options/ShowSysTray", true));
+
+ connect(ui.chkShowTray, SIGNAL(stateChanged(int)), this, SLOT(OnChange()));
+ //connect(ui.chkUseCycles, SIGNAL(stateChanged(int)), this, SLOT(OnChange()));
+
+
+ ui.fileRoot->setText(theAPI->GetGlobalSettings()->GetText("FileRootPath"));
+ ui.chkSeparateUserFolders->setChecked(theAPI->GetGlobalSettings()->GetBool("SeparateUserFolders", true));
+ ui.regRoot->setText(theAPI->GetGlobalSettings()->GetText("KeyRootPath"));
+ ui.ipcRoot->setText(theAPI->GetGlobalSettings()->GetText("IpcRootPath"));
+
+ ui.chkAdminOnly->setChecked(theAPI->GetGlobalSettings()->GetBool("EditAdminOnly", false));
+ ui.chkPassRequired->setChecked(!theAPI->GetGlobalSettings()->GetText("EditPassword", "").isEmpty());
+ connect(ui.chkPassRequired, SIGNAL(stateChanged(int)), this, SLOT(OnChange()));
+ connect(ui.btnSetPassword, SIGNAL(pressed()), this, SLOT(OnSetPassword()));
+ ui.chkAdminOnlyFP->setChecked(theAPI->GetGlobalSettings()->GetBool("ForceDisableAdminOnly", false));
+ ui.chkClearPass->setChecked(theAPI->GetGlobalSettings()->GetBool("ForgetPassword", false));
+
+ connect(ui.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(pressed()), this, SLOT(accept()));
+ connect(ui.buttonBox->button(QDialogButtonBox::Apply), SIGNAL(pressed()), this, SLOT(apply()));
+ connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ restoreGeometry(theConf->GetBlob("SettingsWindow/Window_Geometry"));
+
+ OnChange();
+}
+
+CSettingsWindow::~CSettingsWindow()
+{
+ theConf->SetBlob("SettingsWindow/Window_Geometry",saveGeometry());
+}
+
+void CSettingsWindow::closeEvent(QCloseEvent *e)
+{
+ this->deleteLater();
+}
+
+void CSettingsWindow::apply()
+{
+ theConf->SetValue("Options/Language", ui.uiLang->currentData());
+
+ theConf->SetValue("Options/DarkTheme", ui.chkDarkTheme->isChecked());
+
+ AutorunEnable(ui.chkAutoStart->isChecked());
+
+ theConf->SetValue("Options/ShowNotifications", ui.chkNotifications->isChecked());
+
+ theConf->SetValue("Options/WatchIni", ui.chkWatchConfig->isChecked());
+
+ theConf->SetValue("Options/OnClose", ui.onClose->currentData());
+
+ theConf->SetValue("Options/ShowSysTray", ui.chkShowTray->isChecked());
+
+ if (ui.fileRoot->text().isEmpty())
+ ui.fileRoot->setText("\\??\\%SystemDrive%\\Sandbox\\%USER%\\%SANDBOX%");
+ theAPI->GetGlobalSettings()->SetText("FileRootPath", ui.fileRoot->text());
+ theAPI->GetGlobalSettings()->SetBool("SeparateUserFolders", ui.chkSeparateUserFolders->isChecked());
+
+ if (ui.regRoot->text().isEmpty())
+ ui.regRoot->setText("\\REGISTRY\\USER\\Sandbox_%USER%_%SANDBOX%");
+ theAPI->GetGlobalSettings()->SetText("KeyRootPath", ui.regRoot->text());
+
+ if (ui.ipcRoot->text().isEmpty())
+ ui.ipcRoot->setText("\\Sandbox\\%USER%\\%SANDBOX%\\Session_%SESSION%");
+ theAPI->GetGlobalSettings()->SetText("IpcRootPath", ui.ipcRoot->text());
+
+
+ theAPI->GetGlobalSettings()->SetBool("EditAdminOnly", ui.chkAdminOnly->isChecked());
+
+ bool isPassSet = !theAPI->GetGlobalSettings()->GetText("EditPassword", "").isEmpty();
+ if (ui.chkPassRequired->isChecked())
+ {
+ if (!isPassSet && m_NewPassword.isEmpty())
+ OnSetPassword(); // request password entry if it wasn't already
+ if (!m_NewPassword.isEmpty()) {
+ theAPI->LockConfig(m_NewPassword); // set new/changed password
+ m_NewPassword.clear();
+ }
+ }
+ else if (isPassSet)
+ theAPI->LockConfig(QString()); // clear password
+
+ theAPI->GetGlobalSettings()->SetBool("ForceDisableAdminOnly", ui.chkAdminOnlyFP->isChecked());
+ theAPI->GetGlobalSettings()->SetBool("ForgetPassword", ui.chkClearPass->isChecked());
+
+ emit OptionsChanged();
+}
+
+void CSettingsWindow::accept()
+{
+ apply();
+
+ this->close();
+}
+
+void CSettingsWindow::reject()
+{
+ this->close();
+}
+
+void CSettingsWindow::OnChange()
+{
+ //ui.chkLinuxStyle->setEnabled(!ui.chkUseCycles->isChecked());
+
+ QStandardItemModel *model = qobject_cast(ui.onClose->model());
+ QStandardItem *item = model->item(0);
+ item->setFlags((!ui.chkShowTray->isChecked()) ? item->flags() & ~Qt::ItemIsEnabled : item->flags() | Qt::ItemIsEnabled);
+
+ ui.btnSetPassword->setEnabled(ui.chkPassRequired->isChecked());
+}
+
+void CSettingsWindow::OnSetPassword()
+{
+retry:
+ QString Value1 = QInputDialog::getText(this, "Sandboxie-Plus", tr("Please enter the new configuration password."), QLineEdit::Password);
+ if (Value1.isEmpty())
+ return;
+
+ QString Value2 = QInputDialog::getText(this, "Sandboxie-Plus", tr("Please re enter the new configuration password."), QLineEdit::Password);
+ if (Value2.isEmpty())
+ return;
+
+ if (Value1 != Value2) {
+ QMessageBox::warning(this, "Sandboxie-Plus", tr("Passwords did not match, please retry."));
+ goto retry;
+ }
+
+ m_NewPassword = Value1;
+}
\ No newline at end of file
diff --git a/SandboxiePlus/SandMan/Windows/SettingsWindow.h b/SandboxiePlus/SandMan/Windows/SettingsWindow.h
new file mode 100644
index 0000000000..c9c8ddedc5
--- /dev/null
+++ b/SandboxiePlus/SandMan/Windows/SettingsWindow.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include
+#include "ui_SettingsWindow.h"
+
+class CSettingsWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ CSettingsWindow(QWidget *parent = Q_NULLPTR);
+ ~CSettingsWindow();
+
+signals:
+ void OptionsChanged();
+
+public slots:
+ void apply();
+ void accept();
+ void reject();
+
+private slots:
+ void OnChange();
+ void OnSetPassword();
+
+protected:
+ void closeEvent(QCloseEvent *e);
+
+ QString m_NewPassword;
+
+private:
+ Ui::SettingsWindow ui;
+};
diff --git a/SandboxiePlus/SandMan/main.cpp b/SandboxiePlus/SandMan/main.cpp
index 1127d2eeee..2a5cbf92fd 100644
--- a/SandboxiePlus/SandMan/main.cpp
+++ b/SandboxiePlus/SandMan/main.cpp
@@ -49,8 +49,6 @@ int main(int argc, char *argv[])
CSandMan* pWnd = new CSandMan();
QObject::connect(&app, SIGNAL(messageReceived(const QString&)), pWnd, SLOT(OnMessage(const QString&)));
- pWnd->show();
-
int ret = app.exec();
delete pWnd;