This commit is contained in:
DavidXanatos 2021-09-03 20:35:48 +02:00
parent fd171e42a8
commit 04eade2954
22 changed files with 365 additions and 165 deletions

View File

@ -4,6 +4,24 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [0.9.6 / 5.51.6] - 2021-08-??
### Added
- added ability to rename groups [#1152](https://github.com/sandboxie-plus/Sandboxie/issues/1152)
- added ability to define a custom order for the sandboxes, you can move using the move context menu, or holding alt + arow key
### Fixed
- fixed issue with create group menu [#1151](https://github.com/sandboxie-plus/Sandboxie/issues/1151)
- fixed issue when renaming a box it lost its group association
- fixed issue with thunderbird build 91+ [#1156](https://github.com/sandboxie-plus/Sandboxie/issues/1156)
- fixed an issue with file disposition handling [#1161](https://github.com/sandboxie-plus/Sandboxie/issues/1161)
### Removed
- removed "DelayLoadDll=" code from the deriver as the user mode component since opne sourcing never used that information
## [0.9.5 / 5.51.5] - 2021-08-30
### Added
@ -191,7 +209,7 @@ Fixed issue with Windows 7
-- the security-enhanced option "MsiInstallerExemptions=n" is now the default behaviour
### Fixed
- fixed issue with the "explore sandboxed" command [#972](https://github.com/sandboxie-plus/Sandboxie/issues/972)
- fixed issue with the "Explore Sandboxed" command [#972](https://github.com/sandboxie-plus/Sandboxie/issues/972)
- rolled back the switch from using NtQueryKey to NtQueryObject as it seems to break some older Windows 10 versions like 1803 [#984](https://github.com/sandboxie-plus/Sandboxie/issues/984)
-- this change was introduced to fix [#951](https://github.com/sandboxie-plus/Sandboxie/issues/951)
-- to use NtQueryObject the option "UseObjectNameForKeys=y" can be added to Sandboxie.ini
@ -320,7 +338,7 @@ Fixed issue with Windows 7
## [0.8.0 / 5.50.0] - 2021-06-13
### Added
- Sandboxie now applies by default "Close...=!<program>,..." directives to non-excluded images if they are located in a sandbox
- Normally Sandboxie applies "Close...=!<program>,..." directives to non-excluded images if they are located in a sandbox
-- added 'AlwaysCloseForBoxed=n' to disable this behaviour as it may not be always desired, and it doesn't provide extra security
- added process image information to SandMan UI
- localized template categories in the Plus UI [#727](https://github.com/sandboxie-plus/Sandboxie/issues/727)

View File

@ -21,8 +21,8 @@
#ifndef _MY_VERSION_H
#define _MY_VERSION_H
#define MY_VERSION_BINARY 5,51,5
#define MY_VERSION_STRING "5.51.5"
#define MY_VERSION_BINARY 5,51,6
#define MY_VERSION_STRING "5.51.6"
#define MY_VERSION_COMPAT "5.51.0" // this refers to the driver ABI compatibility
// These #defines are used by either Resource Compiler, or by NSIC installer

View File

@ -112,6 +112,7 @@ enum {
DLL_IMAGE_PLUGIN_CONTAINER,
DLL_IMAGE_OTHER_WEB_BROWSER,
DLL_IMAGE_OTHER_MAIL_CLIENT,
DLL_IMAGE_MOZILLA_THUNDERBIRD,
DLL_IMAGE_LAST
};

View File

@ -534,6 +534,8 @@ _FX ULONG Dll_GetImageType(const WCHAR *ImageName)
ImageType = DLL_IMAGE_GOOGLE_CHROME;
else if (_wcsicmp(L"firefox", buf) == 0)
ImageType = DLL_IMAGE_MOZILLA_FIREFOX;
else if (_wcsicmp(L"thunderbird", buf) == 0)
ImageType = DLL_IMAGE_MOZILLA_THUNDERBIRD;
else if (_wcsicmp(L"browser", buf) == 0)
ImageType = DLL_IMAGE_OTHER_WEB_BROWSER;
else if (_wcsicmp(L"mail", buf) == 0)
@ -576,6 +578,8 @@ _FX ULONG Dll_GetImageType(const WCHAR *ImageName)
L"k-meleon.exe", (WCHAR *)DLL_IMAGE_MOZILLA_FIREFOX,
L"librewolf.exe", (WCHAR *)DLL_IMAGE_MOZILLA_FIREFOX,
L"thunderbird.exe", (WCHAR *)DLL_IMAGE_MOZILLA_THUNDERBIRD,
L"wmplayer.exe", (WCHAR *)DLL_IMAGE_WINDOWS_MEDIA_PLAYER,
L"winamp.exe", (WCHAR *)DLL_IMAGE_NULLSOFT_WINAMP,
L"kmplayer.exe", (WCHAR *)DLL_IMAGE_PANDORA_KMPLAYER,
@ -603,7 +607,6 @@ _FX ULONG Dll_GetImageType(const WCHAR *ImageName)
L"Outlook.exe", (WCHAR *)DLL_IMAGE_OFFICE_OUTLOOK,
L"Excel.exe", (WCHAR *)DLL_IMAGE_OFFICE_EXCEL,
L"thunderbird.exe", (WCHAR *)DLL_IMAGE_OTHER_MAIL_CLIENT,
L"winmail.exe", (WCHAR *)DLL_IMAGE_OTHER_MAIL_CLIENT,
L"IncMail.exe", (WCHAR *)DLL_IMAGE_OTHER_MAIL_CLIENT,
L"eudora.exe", (WCHAR *)DLL_IMAGE_OTHER_MAIL_CLIENT,

View File

@ -5924,7 +5924,7 @@ _FX NTSTATUS File_SetDisposition(
// handle the request appropriately
//
if (PATH_IS_OPEN(mp_flags) || (FileFlags & FGN_IS_BOXED_PATH) != 0) {
if (PATH_IS_OPEN(mp_flags) /*|| (FileFlags & FGN_IS_BOXED_PATH) != 0*/) {
status = __sys_NtSetInformationFile(
FileHandle, IoStatusBlock,
@ -5938,7 +5938,7 @@ _FX NTSTATUS File_SetDisposition(
if (NT_SUCCESS(status) && !PATH_IS_OPEN(mp_flags)) {
BOOLEAN DeleteOnClose;
BOOLEAN DeleteOnClose = FALSE;
if (FileInformationClass == FileDispositionInformation) {

View File

@ -2132,7 +2132,7 @@ _FX NTSTATUS File_NtCloseImpl(HANDLE FileHandle)
InitializeObjectAttributes(
&objattrs, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = File_NtDeleteFileImpl(&objattrs);
File_NtDeleteFileImpl(&objattrs);
Dll_Free(DeletePath);
}

View File

@ -262,7 +262,7 @@ _FX BOOLEAN File_Init(void)
}
if (Dll_ImageType == DLL_IMAGE_MOZILLA_FIREFOX)
if (Dll_ImageType == DLL_IMAGE_MOZILLA_FIREFOX || Dll_ImageType == DLL_IMAGE_MOZILLA_THUNDERBIRD)
{
void *WriteProcessMemory =
GetProcAddress(Dll_KernelBase ? Dll_KernelBase : Dll_Kernel32,

View File

@ -1944,9 +1944,10 @@ _FX BOOLEAN Proc_CheckMailer(const WCHAR *ImagePath, BOOLEAN IsBoxedPath)
// check if image name matches a well-known email program
//
if (imgType == DLL_IMAGE_OFFICE_OUTLOOK ||
imgType == DLL_IMAGE_WINDOWS_LIVE_MAIL ||
imgType == DLL_IMAGE_OTHER_MAIL_CLIENT ||
if (imgType == DLL_IMAGE_OFFICE_OUTLOOK ||
imgType == DLL_IMAGE_WINDOWS_LIVE_MAIL ||
imgType == DLL_IMAGE_OTHER_MAIL_CLIENT ||
imgType == DLL_IMAGE_MOZILLA_THUNDERBIRD ||
0)
{
should_check_openfilepath = TRUE;

View File

@ -73,8 +73,9 @@ static LIST Dll_List;
static BOOLEAN Dll_List_Initialized = FALSE;
const WCHAR *Dll_NTDLL = L"NTDLL";
#ifdef XP_SUPPORT
const WCHAR *Dll_USER = L"USER32";
#endif
//---------------------------------------------------------------------------
// Dll_Init
@ -86,10 +87,12 @@ _FX BOOLEAN Dll_Init(void)
List_Init(&Dll_List);
Dll_List_Initialized = TRUE;
if (! Dll_Load(Dll_NTDLL)) // ntoskrnl.exe - ntdll.dll
if (! Dll_Load(Dll_NTDLL))
return FALSE;
if (! Dll_Load(Dll_USER)) // win32k.sys - w10: win32u.dll - w7: user32.dll & gdi32.dll
#ifdef XP_SUPPORT
if (! Dll_Load(Dll_USER))
return FALSE;
#endif
return TRUE;
}

View File

@ -66,8 +66,9 @@ ULONG Dll_GetNextProc(
extern const WCHAR *Dll_NTDLL;
#ifdef XP_SUPPORT
extern const WCHAR *Dll_USER;
#endif
//---------------------------------------------------------------------------

View File

@ -64,13 +64,14 @@ typedef struct _MY_CONTEXT {
} MY_CONTEXT;
typedef struct _BLOCKED_DLL {
//typedef struct _BLOCKED_DLL {
//
// LIST_ELEM list_elem;
// ULONG path_len;
// WCHAR path[4]; // padding bytes
//
//} BLOCKED_DLL;
LIST_ELEM list_elem;
ULONG path_len;
WCHAR path[4]; // padding bytes
} BLOCKED_DLL;
//---------------------------------------------------------------------------
@ -226,7 +227,7 @@ _FX BOOLEAN File_Init(void)
Api_SetFunction(API_REFRESH_FILE_PATH_LIST, File_Api_RefreshPathList);
Api_SetFunction(API_OPEN_FILE, File_Api_Open);
Api_SetFunction(API_CHECK_INTERNET_ACCESS, File_Api_CheckInternetAccess);
Api_SetFunction(API_GET_BLOCKED_DLL, File_Api_GetBlockedDll);
//Api_SetFunction(API_GET_BLOCKED_DLL, File_Api_GetBlockedDll);
return TRUE;
}
@ -930,29 +931,29 @@ _FX BOOLEAN File_InitProcess(PROCESS *proc)
//---------------------------------------------------------------------------
_FX BOOLEAN File_IsDelayLoadDll(PROCESS *proc, const WCHAR *DllName)
{
BOOLEAN retval = FALSE;
ULONG idx = 0;
Conf_AdjustUseCount(TRUE);
while (1) {
const WCHAR *value = Conf_Get(proc->box->name, L"DelayLoadDll", idx);
if (! value)
break;
//DbgPrint("Comparing <%S> vs <%S>\n", DllName, value);
if (_wcsicmp(value, DllName) == 0) {
retval = TRUE;
break;
}
++idx;
}
Conf_AdjustUseCount(FALSE);
return retval;
}
//_FX BOOLEAN File_IsDelayLoadDll(PROCESS *proc, const WCHAR *DllName)
//{
// BOOLEAN retval = FALSE;
// ULONG idx = 0;
//
// Conf_AdjustUseCount(TRUE);
//
// while (1) {
// const WCHAR *value = Conf_Get(proc->box->name, L"DelayLoadDll", idx);
// if (! value)
// break;
// //DbgPrint("Comparing <%S> vs <%S>\n", DllName, value);
// if (_wcsicmp(value, DllName) == 0) {
// retval = TRUE;
// break;
// }
// ++idx;
// }
//
// Conf_AdjustUseCount(FALSE);
//
// return retval;
//}
//---------------------------------------------------------------------------
@ -1419,32 +1420,33 @@ _FX NTSTATUS File_Generic_MyParseProc(
// has been initialized, then pretend the file does not exist,
// and add the DLL path so it can be loaded by SbieDll
//
if ((! proc->sbiedll_loaded) && status == STATUS_SUCCESS
&& (CreateOptions & FILE_DIRECTORY_FILE) == 0) {
WCHAR *backslash = wcsrchr(path, L'\\');
if (backslash && File_IsDelayLoadDll(proc, backslash + 1)) {
ULONG len = sizeof(BLOCKED_DLL) + path_len * sizeof(WCHAR);
BLOCKED_DLL *blk = Mem_Alloc(proc->pool, len);
if (blk) {
blk->path_len = path_len;
wmemcpy(blk->path, path, path_len + 1);
KeRaiseIrql(APC_LEVEL, &irql);
ExAcquireResourceExclusiveLite(proc->file_lock, TRUE);
List_Insert_After(&proc->blocked_dlls, NULL, blk);
ExReleaseResourceLite(proc->file_lock);
KeLowerIrql(irql);
}
status = STATUS_OBJECT_NAME_NOT_FOUND;
}
}
// DX: this info does not seam to be so no point in saving this data
//
//if ((! proc->sbiedll_loaded) && status == STATUS_SUCCESS
// && (CreateOptions & FILE_DIRECTORY_FILE) == 0) {
//
// WCHAR *backslash = wcsrchr(path, L'\\');
// if (backslash && File_IsDelayLoadDll(proc, backslash + 1)) {
//
// ULONG len = sizeof(BLOCKED_DLL) + path_len * sizeof(WCHAR);
// BLOCKED_DLL *blk = Mem_Alloc(proc->pool, len);
// if (blk) {
//
// blk->path_len = path_len;
// wmemcpy(blk->path, path, path_len + 1);
//
// KeRaiseIrql(APC_LEVEL, &irql);
// ExAcquireResourceExclusiveLite(proc->file_lock, TRUE);
//
// List_Insert_After(&proc->blocked_dlls, NULL, blk);
//
// ExReleaseResourceLite(proc->file_lock);
// KeLowerIrql(irql);
// }
//
// status = STATUS_OBJECT_NAME_NOT_FOUND;
// }
//}
//
// release temporary path
@ -2513,69 +2515,69 @@ get_program:
//---------------------------------------------------------------------------
_FX NTSTATUS File_Api_GetBlockedDll(PROCESS *proc, ULONG64 *parms)
{
API_GET_BLOCKED_DLL_ARGS *args = (API_GET_BLOCKED_DLL_ARGS *)parms;
WCHAR *user_buf;
ULONG user_len;
ULONG len;
NTSTATUS status;
BLOCKED_DLL *blk;
KIRQL irql;
//
// this API must be invoked by a sandboxed process
//
if (! proc)
return STATUS_NOT_IMPLEMENTED;
//
// check input buffers
//
user_buf = args->dll_name_buf.val;
user_len = args->dll_name_len.val / sizeof(WCHAR);
if ((! user_buf) || (! user_len))
return STATUS_INVALID_PARAMETER;
//
// return first blocked dll in the list
//
KeRaiseIrql(APC_LEVEL, &irql);
ExAcquireResourceExclusiveLite(proc->file_lock, TRUE);
blk = List_Head(&proc->blocked_dlls);
if (! blk)
status = STATUS_END_OF_FILE;
else {
__try {
len = blk->path_len;
if (len >= user_len)
len = user_len - 1;
ProbeForWrite(
user_buf, sizeof(WCHAR) * (len + 1), sizeof(WCHAR));
wmemcpy(user_buf, blk->path, len);
user_buf[len] = L'\0';
status = STATUS_SUCCESS;
} __except (EXCEPTION_EXECUTE_HANDLER) {
status = GetExceptionCode();
}
List_Remove(&proc->blocked_dlls, blk);
len = sizeof(BLOCKED_DLL) + blk->path_len * sizeof(WCHAR);
Mem_Free(blk, len);
}
ExReleaseResourceLite(proc->file_lock);
KeLowerIrql(irql);
return status;
}
//_FX NTSTATUS File_Api_GetBlockedDll(PROCESS *proc, ULONG64 *parms)
//{
// API_GET_BLOCKED_DLL_ARGS *args = (API_GET_BLOCKED_DLL_ARGS *)parms;
// WCHAR *user_buf;
// ULONG user_len;
// ULONG len;
// NTSTATUS status;
// BLOCKED_DLL *blk;
// KIRQL irql;
//
// //
// // this API must be invoked by a sandboxed process
// //
//
// if (! proc)
// return STATUS_NOT_IMPLEMENTED;
//
// //
// // check input buffers
// //
//
// user_buf = args->dll_name_buf.val;
// user_len = args->dll_name_len.val / sizeof(WCHAR);
// if ((! user_buf) || (! user_len))
// return STATUS_INVALID_PARAMETER;
//
// //
// // return first blocked dll in the list
// //
//
// KeRaiseIrql(APC_LEVEL, &irql);
// ExAcquireResourceExclusiveLite(proc->file_lock, TRUE);
//
// blk = List_Head(&proc->blocked_dlls);
// if (! blk)
// status = STATUS_END_OF_FILE;
// else {
//
// __try {
//
// len = blk->path_len;
// if (len >= user_len)
// len = user_len - 1;
//
// ProbeForWrite(
// user_buf, sizeof(WCHAR) * (len + 1), sizeof(WCHAR));
// wmemcpy(user_buf, blk->path, len);
// user_buf[len] = L'\0';
//
// status = STATUS_SUCCESS;
//
// } __except (EXCEPTION_EXECUTE_HANDLER) {
// status = GetExceptionCode();
// }
//
// List_Remove(&proc->blocked_dlls, blk);
//
// len = sizeof(BLOCKED_DLL) + blk->path_len * sizeof(WCHAR);
// Mem_Free(blk, len);
// }
//
// ExReleaseResourceLite(proc->file_lock);
// KeLowerIrql(irql);
//
// return status;
//}

View File

@ -59,7 +59,7 @@ NTSTATUS File_Api_Open(PROCESS *proc, ULONG64 *parms);
NTSTATUS File_Api_CheckInternetAccess(PROCESS *proc, ULONG64 *parms);
NTSTATUS File_Api_GetBlockedDll(PROCESS *proc, ULONG64 *parms);
//NTSTATUS File_Api_GetBlockedDll(PROCESS *proc, ULONG64 *parms);
//---------------------------------------------------------------------------

View File

@ -142,7 +142,7 @@ struct _PROCESS {
LIST read_file_paths; // PATTERN elements
LIST write_file_paths; // PATTERN elements
BOOLEAN always_close_for_boxed;
LIST blocked_dlls;
//LIST blocked_dlls;
ULONG file_trace;
ULONG pipe_trace;
BOOLEAN disable_file_flt;

View File

@ -113,7 +113,9 @@ QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList, cons
if (Group.isEmpty())
continue;
QVariant ID = CSbieModel__AddGroupMark(Group);
QModelIndex Index;
QHash<QVariant, STreeNode*>::iterator I = Old.find(ID);
SSandBoxNode* pNode = I != Old.end() ? static_cast<SSandBoxNode*>(I.value()) : NULL;
if (!pNode)
@ -135,7 +137,20 @@ QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList, cons
else
{
I.value() = NULL;
Index = Find(m_Root, pNode);
}
int Changed = 0;
QString ParentGroup = pNode->Path.isEmpty() ? "" : CSbieModel__RemoveGroupMark(pNode->Path.last().toString());
int OrderNumber = Groups[ParentGroup].indexOf(Group);
if (pNode->OrderNumber != OrderNumber) {
pNode->OrderNumber = OrderNumber;
Changed = 1;
}
if (Changed && Index.isValid())
emit dataChanged(createIndex(Index.row(), 0, pNode), createIndex(Index.row(), columnCount()-1, pNode));
}
foreach (const CSandBoxPtr& pBox, BoxList)
@ -171,6 +186,13 @@ QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList, cons
bool State = false;
int Changed = 0;
QString Group = pNode->Path.isEmpty() ? "" : CSbieModel__RemoveGroupMark(pNode->Path.last().toString());
int OrderNumber = Groups[Group].indexOf(pBox->GetName());
if (pNode->OrderNumber != OrderNumber) {
pNode->OrderNumber = OrderNumber;
Changed = 1;
}
QMap<quint32, CBoxedProcessPtr> ProcessList = pBox->GetProcessList();
bool inUse = Sync(pBox, pNode->Path, ProcessList, New, Old, Added);
@ -355,6 +377,14 @@ bool CSbieModel::Sync(const CSandBoxPtr& pBox, const QList<QVariant>& Path, cons
return ActiveCount != 0;
}
QVariant CSbieModel::NodeData(STreeNode* pNode, int role, int section) const
{
if (section == 0 && role == Qt::InitialSortOrderRole) {
return ((SSandBoxNode*)pNode)->OrderNumber;
}
return CTreeItemModel::NodeData(pNode, role, section);
}
CSandBoxPtr CSbieModel::GetSandBox(const QModelIndex &index) const
{
if (!index.isValid())

View File

@ -46,15 +46,18 @@ protected:
struct SSandBoxNode: STreeNode
{
SSandBoxNode(const QVariant& Id) : STreeNode(Id) { inUse = false; boxType = -1; }
SSandBoxNode(const QVariant& Id) : STreeNode(Id) { inUse = false; boxType = -1; OrderNumber = 0; }
CSandBoxPtr pBox;
bool inUse;
int boxType;
int OrderNumber;
CBoxedProcessPtr pProcess;
};
virtual QVariant NodeData(STreeNode* pNode, int role, int section) const;
virtual STreeNode* MkNode(const QVariant& Id) { return new SSandBoxNode(Id); }
QList<QVariant> MakeProcPath(const QString& BoxName, const CBoxedProcessPtr& pProcess, const QMap<quint32, CBoxedProcessPtr>& ProcessList);

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 780 B

View File

@ -60,6 +60,9 @@
<file>IconOffC.png</file>
<file>IconFullC.png</file>
<file>IconEmptyC.png</file>
<file>Actions/Duplicate.png</file>
<file>Actions/Up.png</file>
<file>Actions/Down.png</file>
</qresource>
<qresource prefix="/Boxes">
<file alias="Empty3">Boxes/sandbox-b-empty.png</file>

View File

@ -45,6 +45,11 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
m_pSbieTree->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_pSbieTree->setSortingEnabled(true);
//m_pSbieTree->setSortingEnabled(false);
m_pSbieTree->setUniformRowHeights(true);
//m_pSbieTree->header()->setSortIndicatorShown(true);
//m_pSbieTree->header()->setSectionsClickable(true);
connect(m_pSbieTree->header(), SIGNAL(sectionClicked(int)), this, SLOT(OnCustomSortByColumn(int)));
m_pSbieTree->setStyle(pStyle);
@ -64,7 +69,8 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
connect(m_pSbieModel, SIGNAL(ToolTipCallback(const QVariant&, QString&)), this, SLOT(OnToolTipCallback(const QVariant&, QString&)), Qt::DirectConnection);
m_pNewBox = m_pMenu->addAction(CSandMan::GetIcon("NewBox"), tr("Create New Box"), this, SLOT(OnGroupAction()));
m_pAddGroupe = m_pMenu->addAction(CSandMan::GetIcon("Group"), tr("Add Group"), this, SLOT(OnGroupAction()));
m_pAddGroupe = m_pMenu->addAction(CSandMan::GetIcon("Group"), tr("Create Box Group"), this, SLOT(OnGroupAction()));
m_pRenGroupe = m_pMenu->addAction(CSandMan::GetIcon("Rename"), tr("Rename Group"), this, SLOT(OnGroupAction()));
m_pDelGroupe = m_pMenu->addAction(CSandMan::GetIcon("Remove"), tr("Remove Group"), this, SLOT(OnGroupAction()));
m_iMenuTop = m_pMenu->actions().count();
//m_pMenu->addSeparator();
@ -119,7 +125,17 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
m_pMenuRename = m_pMenu->addAction(CSandMan::GetIcon("Rename"), tr("Rename Sandbox"), this, SLOT(OnSandBoxAction()));
m_iMoveTo = m_pMenu->actions().count();
m_pMenuMoveTo = m_pMenu->addMenu(CSandMan::GetIcon("Group"), tr("Move to Group"));
m_pMenuMoveTo = m_pMenu->addMenu(CSandMan::GetIcon("Group"), tr("Move Box/Group"));
m_pMenuMoveUp = m_pMenuMoveTo->addAction(CSandMan::GetIcon("Up"), tr("Move Up"), this, SLOT(OnGroupAction()));
m_pMenuMoveUp->setShortcut(QKeySequence("Alt+Up"));
m_pMenuMoveUp->setShortcutContext(Qt::WidgetWithChildrenShortcut);
this->addAction(m_pMenuMoveUp);
//m_pMenuMoveBy = m_pMenuMoveTo->addAction(tr("Move to Position"), this, SLOT(OnGroupAction())); // does not seam that intuitive for users
m_pMenuMoveDown = m_pMenuMoveTo->addAction(CSandMan::GetIcon("Down"), tr("Move Down"), this, SLOT(OnGroupAction()));
m_pMenuMoveDown->setShortcut(QKeySequence("Alt+Down"));
m_pMenuMoveDown->setShortcutContext(Qt::WidgetWithChildrenShortcut);
this->addAction(m_pMenuMoveDown);
m_pMenuMoveTo->addSeparator();
m_pMenuRemove = m_pMenu->addAction(CSandMan::GetIcon("Remove"), tr("Remove Sandbox"), this, SLOT(OnSandBoxAction()));
m_iMenuBox = m_pMenu->actions().count();
@ -175,6 +191,11 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
}
else
m_pSbieTree->restoreState(Columns);
if (theConf->GetBool("MainWindow/BoxTree_UseOrder", false)) {
m_pSortProxy->sort(0, Qt::AscendingOrder);
m_pSortProxy->setSortRole(Qt::InitialSortOrderRole);
m_pSbieTree->header()->setSortIndicatorShown(false);
}
//m_pMenu = new QMenu();
AddPanelItemsToMenu();
@ -183,6 +204,7 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
CSbieView::~CSbieView()
{
theConf->SetBlob("MainWindow/BoxTree_Columns", m_pSbieTree->saveState());
theConf->SetValue("MainWindow/BoxTree_UseOrder", m_pSortProxy->sortRole() == Qt::InitialSortOrderRole);
}
void CSbieView::Clear()
@ -231,6 +253,28 @@ void CSbieView::OnToolTipCallback(const QVariant& ID, QString& ToolTip)
}
}
void CSbieView::OnCustomSortByColumn(int column)
{
Qt::SortOrder order = m_pSbieTree->header()->sortIndicatorOrder();
//m_pSbieTree->sortByColumn(column, order);
//m_pSbieTree->header()->setSortIndicatorShown(true);
if (column == 0) {
if (m_pSortProxy->sortRole() == Qt::InitialSortOrderRole) {
m_pSortProxy->sort(0, Qt::AscendingOrder);
m_pSortProxy->setSortRole(Qt::EditRole);
m_pSbieTree->header()->setSortIndicatorShown(true);
} else if (order == Qt::DescendingOrder) {
m_pSortProxy->sort(0, Qt::AscendingOrder);
m_pSortProxy->setSortRole(Qt::InitialSortOrderRole);
m_pSbieTree->header()->setSortIndicatorShown(false);
}
}
else {
m_pSortProxy->setSortRole(Qt::EditRole);
m_pSbieTree->header()->setSortIndicatorShown(true);
}
}
void CSbieView::UpdateMenu()
{
QList<QAction*> MenuActions = m_pMenu->actions();
@ -245,6 +289,7 @@ void CSbieView::UpdateMenu()
CBoxedProcessPtr pProcess;
int iProcessCount = 0;
int iSandBoxeCount = 0;
int iGroupe = 0;
//int iSuspendedCount = 0;
QModelIndexList Rows = m_pSbieTree->selectedRows();
foreach(const QModelIndex& Index, Rows)
@ -268,12 +313,15 @@ void CSbieView::UpdateMenu()
else if (iSandBoxeCount != -1)
iSandBoxeCount++;
}
else
iGroupe++;
}
}
for (int i = 0; i < m_iMenuTop; i++)
MenuActions[i]->setVisible(iSandBoxeCount == 0 && iProcessCount == 0);
m_pRenGroupe->setVisible(iGroupe == 1 && iSandBoxeCount == 0 && iProcessCount == 0);
m_pDelGroupe->setVisible(!Rows.isEmpty() && iSandBoxeCount == 0 && iProcessCount == 0);
for (int i = m_iMenuTop; i < m_iMenuBox; i++)
@ -400,14 +448,30 @@ void CSbieView::ReloadGroups()
void CSbieView::UpdateGroupMenu()
{
// update move to menu
foreach(QAction* pAction, m_pMenuMoveTo->actions())
m_pMenuMoveTo->removeAction(pAction);
foreach(QAction * pAction, m_pMenuMoveTo->actions()) {
if (!pAction->data().toString().isNull())
m_pMenuMoveTo->removeAction(pAction);
}
foreach(const QString& Group, m_Groups.keys())
{
QAction* pAction = m_pMenuMoveTo->addAction(Group.isEmpty() ? tr("[None]") : Group, this, SLOT(OnGroupAction()));
pAction->setData(Group);
}
m_pMenuMoveTo->setEnabled(m_Groups.keys().count() > 1);
//m_pMenuMoveTo->setEnabled(m_Groups.keys().count() > 1);
}
void CSbieView::RenameGroup(const QString OldName, const QString NewName)
{
auto Group = m_Groups.take(OldName);
m_Groups.insert(NewName, Group);
for (auto I = m_Groups.begin(); I != m_Groups.end(); ++I)
{
if (I.value().removeOne(OldName))
I.value().append(NewName);
}
}
QString CSbieView__SerializeGroup(QMap<QString, QStringList>& m_Groups, const QString& Parent = "")
@ -443,6 +507,26 @@ bool CSbieView::IsParentOf(const QString& Name, const QString& Group)
return IsParentOf(Name, Parent);
}
QStringList CSbieView::GetSelectedGroups(bool bAndBoxes)
{
QStringList list;
foreach(const QModelIndex & Index, m_pSbieTree->selectedRows())
{
QModelIndex ModelIndex = m_pSortProxy->mapToSource(Index);
QString Name;
if (m_pSbieModel->GetType(ModelIndex) == CSbieModel::eGroup)
Name = m_pSbieModel->GetID(ModelIndex).toString();
else if (bAndBoxes && m_pSbieModel->GetType(ModelIndex) == CSbieModel::eBox)
Name = m_pSbieModel->GetSandBox(ModelIndex)->GetName();
if (Name.isEmpty())
continue;
list.append(Name);
}
return list;
}
void CSbieView::OnGroupAction()
{
QAction* Action = qobject_cast<QAction*>(sender());
@ -453,18 +537,38 @@ void CSbieView::OnGroupAction()
if (Name.isEmpty())
return;
QModelIndex ModelIndex = m_pSortProxy->mapToSource(m_pSbieTree->currentIndex());
QString Parent;
if (m_pSbieModel->GetType(ModelIndex) == CSbieModel::eGroup)
Parent = m_pSbieModel->GetID(ModelIndex).toString();
m_Groups[Parent].append(Name);
QStringList List = GetSelectedGroups();
if (List.isEmpty())
return;
m_Groups[List.first()].append(Name);
m_pSbieModel->Clear(); //todo improve that
}
else if (Action == m_pAddGroupe)
{
AddNewGroup();
return;
}
else if (Action == m_pRenGroupe)
{
QStringList List = GetSelectedGroups();
if (List.isEmpty())
return;
QString OldValue = List.first();
QString Value = QInputDialog::getText(this, "Sandboxie-Plus", tr("Please enter a new name for the Group."), QLineEdit::Normal, OldValue);
if (Value.isEmpty() || Value == OldValue)
return;
if (m_Groups.contains(Value)) {
QMessageBox("Sandboxie-Plus", tr("This Group name is already in use."), QMessageBox::Information, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton, this).exec();
return;
}
RenameGroup(OldValue, Value);
m_pSbieModel->Clear(); //todo improve that
}
else if (Action == m_pDelGroupe)
{
@ -493,22 +597,39 @@ void CSbieView::OnGroupAction()
m_pSbieModel->Clear(); //todo improve that, also move boxes to grant parent?
}
else if (Action == m_pMenuMoveUp /*|| Action == m_pMenuMoveBy*/ || Action == m_pMenuMoveDown)
{
int Offset = 0;
if (Action == m_pMenuMoveUp)
Offset = -1;
else if (Action == m_pMenuMoveDown)
Offset = 1;
else
Offset = QInputDialog::getInt(this, "Sandboxie-Plus", tr("Move entries by (negative values move up oositive values move down):"), 0);
if (Offset == 0)
return;
// todo: fix behavioure on multiple selelction
foreach(const QString& Name, GetSelectedGroups(true)) {
for (auto I = m_Groups.begin(); I != m_Groups.end(); ++I) {
int pos = I->indexOf(Name);
if (pos != -1) {
if ((Offset < 0 && pos > Offset + 1) ||(Offset > 0 && pos < I->count() - Offset)){
QString Temp = I.value()[pos+Offset];
I.value()[pos+Offset] = I.value()[pos];
I.value()[pos] = Temp;
}
break;
}
}
}
}
else // move to groupe
{
QString Group = Action->data().toString();
foreach(const QModelIndex& Index, m_pSbieTree->selectedRows())
foreach(const QString& Name, GetSelectedGroups(true))
{
QModelIndex ModelIndex = m_pSortProxy->mapToSource(Index);
QString Name;
if (m_pSbieModel->GetType(ModelIndex) == CSbieModel::eGroup)
Name = m_pSbieModel->GetID(ModelIndex).toString();
else if (m_pSbieModel->GetType(ModelIndex) == CSbieModel::eBox)
Name = m_pSbieModel->GetSandBox(ModelIndex)->GetName();
if (Name.isEmpty())
continue;
if (Name == Group || IsParentOf(Name, Group)) {
QMessageBox("Sandboxie-Plus", tr("A group can not be its own parent."), QMessageBox::Critical, QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton, this).exec();
continue;
@ -559,6 +680,10 @@ QString CSbieView::AddNewGroup()
m_Groups[Parent].append(Name);
QString Grouping = CSbieView__SerializeGroup(m_Groups);
theAPI->GetUserSettings()->SetText("BoxDisplayOrder", Grouping);
UpdateGroupMenu();
return Name;
}
@ -730,6 +855,8 @@ void CSbieView::OnSandBoxAction(QAction* Action)
if (Value.isEmpty() || Value == OldValue)
return;
Results.append((SandBoxes.first()->RenameBox(Value.replace(" ", "_"))));
RenameGroup(OldValue, Value);
}
else if (Action == m_pMenuRecover)
{

View File

@ -15,6 +15,7 @@ public:
virtual QList<CSandBoxPtr> GetSelectedBoxes();
virtual QList<CBoxedProcessPtr> GetSelectedProcesses();
virtual QStringList GetSelectedGroups(bool bAndBoxes = false);
//virtual void UpdateRunMenu();
@ -33,6 +34,8 @@ public slots:
private slots:
void OnToolTipCallback(const QVariant& ID, QString& ToolTip);
void OnCustomSortByColumn(int column);
void OnDoubleClicked(const QModelIndex& index);
void ProcessSelection(const QItemSelection& selected, const QItemSelection& deselected);
@ -54,6 +57,7 @@ private:
void UpdateMenu();
void UpdateGroupMenu();
void RenameGroup(const QString OldName, const QString NewName);
QString FindParent(const QString& Name);
bool IsParentOf(const QString& Name, const QString& Group);
@ -68,6 +72,7 @@ private:
QAction* m_pNewBox;
QAction* m_pAddGroupe;
QAction* m_pRenGroupe;
QAction* m_pDelGroupe;
int m_iMenuTop;
QMenu* m_pMenuRun;
@ -101,6 +106,9 @@ private:
QAction* m_pMenuRecover;
QAction* m_pMenuCleanUp;
QAction* m_pMenuRemove;
QAction* m_pMenuMoveUp;
//QAction* m_pMenuMoveBy;
QAction* m_pMenuMoveDown;
QMenu* m_pMenuMoveTo;
int m_iMoveTo;
QAction* m_pMenuRename;

View File

@ -2,7 +2,7 @@
#define VERSION_MJR 0
#define VERSION_MIN 9
#define VERSION_REV 5
#define VERSION_REV 6
#define VERSION_UPD 0
#ifndef STR