diff --git a/CHANGELOG.md b/CHANGELOG.md index 065dc4b5..fb882791 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,16 +3,19 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## [1.0.9 / 5.55.9] - 2022-01-?? +## [1.0.9 / 5.55.9] - 2022-01-31 ### Added - sandman now causes all boxed processes to update thair path settings in real time when access options were modified - added new maintenance meu option Uninstal All to quickly remove all components when runnign in portable mode +- added option to return not to a snapshot but to an empty box state while keeping all snapshots +- Sandboxie-Plus.ini can now be placed in C:\ProgramData\Sandboxie-Plus\ folder and takes precedence (for business use) ### Changed - reworked breakout mechanism to be service based and not alow the parent process to access the broken out child process - enabled creatin of directory junctions for sandboxed processes [#1375](https://github.com/sandboxie-plus/Sandboxie/issues/1375) - changed back to set AutoRecover=y on box creation [#1554](https://github.com/sandboxie-plus/Sandboxie/discussions/1554) +- improved snapshot support [#1220](https://github.com/sandboxie-plus/Sandboxie/issues/1220) ### Fixed - fixed BreakoutProcess not working with EnableObjectFiltering=y @@ -23,6 +26,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). - fixed border issues on maximized windows introduced in the last build [#1561](https://github.com/sandboxie-plus/Sandboxie/issues/1561) - fixed a couple if index overruns (thanks 7eRoM) - fixed issues with sysnative directroy [#1403](https://github.com/sandboxie-plus/Sandboxie/issues/1403) +- fixed issue with starting sandman when running sandboxed from context menu [#1579](https://github.com/sandboxie-plus/Sandboxie/issues/1579) +- fixed dark mode flash issue with main window creation +- fixed issues with snapshot error handling diff --git a/SandboxiePlus/MiscHelpers/Common/Settings.cpp b/SandboxiePlus/MiscHelpers/Common/Settings.cpp index 744aaaeb..7f38e1a5 100644 --- a/SandboxiePlus/MiscHelpers/Common/Settings.cpp +++ b/SandboxiePlus/MiscHelpers/Common/Settings.cpp @@ -12,7 +12,7 @@ bool TestWriteRight(const QString& Path) return TestFile.remove(); } -CSettings::CSettings(const QString& AppName, QMap DefaultValues, QObject* qObject) : QObject(qObject) +CSettings::CSettings(const QString& AppName, bool bShared, QMap DefaultValues, QObject* qObject) : QObject(qObject) { m_ConfigDir = QCoreApplication::applicationDirPath(); if (!(m_bPortable = QFile::exists(m_ConfigDir + "/" + AppName + ".ini"))) @@ -20,8 +20,17 @@ CSettings::CSettings(const QString& AppName, QMap DefaultValu QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); if (dirs.isEmpty()) m_ConfigDir = QDir::homePath() + "/." + AppName; + // + // if shared is set a new ini is created in the shared location + // and if present take precedence over an ini in a user location + // howeever if the only existing ini is in a user location it will be used + // + else if(bShared && dirs.count() > 2 && ( + QFile::exists(dirs[1] + "/" + AppName + "/" + AppName + ".ini") || + !QFile::exists(dirs[0] + "/" + AppName + "/" + AppName + ".ini") )) + m_ConfigDir = dirs[1] + "/" + AppName; else - m_ConfigDir = dirs.first() + "/" + AppName; + m_ConfigDir = dirs[0] + "/" + AppName; QDir().mkpath(m_ConfigDir); } diff --git a/SandboxiePlus/MiscHelpers/Common/Settings.h b/SandboxiePlus/MiscHelpers/Common/Settings.h index bb7790f6..ddf0241b 100644 --- a/SandboxiePlus/MiscHelpers/Common/Settings.h +++ b/SandboxiePlus/MiscHelpers/Common/Settings.h @@ -97,7 +97,7 @@ public: virtual bool IsBlob() const {return true;} }; - CSettings(const QString& AppName, QMap DefaultValues = QMap(), QObject* qObject = NULL); + CSettings(const QString& AppName, bool bShared = false, QMap DefaultValues = QMap(), QObject* qObject = NULL); virtual ~CSettings(); bool SetValue(const QString& key, const QVariant& value); diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp index e20742a8..b21bbc45 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp +++ b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp @@ -51,7 +51,7 @@ CSandBox::CSandBox(const QString& BoxName, class CSbieAPI* pAPI) : CSbieIni(BoxN if (cfglvl == 0) { - SetBool("AutoRecover", false); + SetBool("AutoRecover", true); SetBool("BlockNetworkFiles", true); // recovery @@ -235,7 +235,7 @@ SB_STATUS CSandBox::RemoveBox() return RemoveSection(); } -QList CSandBox::GetSnapshots(QString* pCurrent) const +QList CSandBox::GetSnapshots(QString* pCurrent, QString* pDefault) const { QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat); @@ -259,12 +259,65 @@ QList CSandBox::GetSnapshots(QString* pCurrent) const if(pCurrent) *pCurrent = ini.value("Current/Snapshot").toString(); + if(pDefault) + *pDefault = ini.value("Current/Default").toString(); return Snapshots; } +void CSandBox::SetDefaultSnapshot(QString Default) +{ + QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat); + + ini.setValue("Current/Default", Default); + ini.sync(); +} + +QString CSandBox::GetDefaultSnapshot(QString* pCurrent) const +{ + QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat); + + if(pCurrent) + *pCurrent = ini.value("Current/Snapshot").toString(); + + return ini.value("Current/Default").toString(); +} + QStringList CSandBox__BoxSubFolders = QStringList() << "drive" << "user" << "share"; +struct SBoxDataFile +{ + SBoxDataFile(QString name, bool required, bool recursive) : Name(name), Required(required), Recursive(recursive) {} + QString Name; + bool Required; // fail on fail + bool Recursive; +}; + +QList CSandBox__BoxDataFiles = QList() + << SBoxDataFile("RegHive", true, false) +; + +bool CSandBox::IsInitialized() const +{ + if (IsEmpty()) + return false; + + foreach(const QString & BoxSubFolder, CSandBox__BoxSubFolders) { + if (QDir(m_FilePath + "\\" + BoxSubFolder).exists()) + return true; + } + foreach(const SBoxDataFile& BoxDataFile, CSandBox__BoxDataFiles) { + if (BoxDataFile.Required && QFile::exists(m_FilePath + "\\" + BoxDataFile.Name)) + return true; + } + return false; +} + +bool CSandBox::HasSnapshots() const +{ + return QFile::exists(m_FilePath + "\\Snapshots.ini"); +} + SB_STATUS CSandBox__MoveFolder(const QString& SourcePath, const QString& ParentFolder, const QString& TargetName) { SNtObject src_dir(L"\\??\\" + SourcePath.toStdWString()); @@ -282,7 +335,7 @@ SB_PROGRESS CSandBox::TakeSnapshot(const QString& Name) if (m_pAPI->HasProcesses(m_Name)) return SB_ERR(SB_SnapIsRunning, OP_CONFIRM); - if (IsEmpty()) + if (!IsInitialized()) return SB_ERR(SB_SnapIsEmpty); QStringList Snapshots = ini.childGroups(); @@ -295,10 +348,18 @@ SB_PROGRESS CSandBox::TakeSnapshot(const QString& Name) break; } - if (!QDir().mkdir(m_FilePath + "\\snapshot-" + ID)) + if (!QDir().mkpath(m_FilePath + "\\snapshot-" + ID)) return SB_ERR(SB_SnapMkDirFail); - if (!QFile::copy(m_FilePath + "\\RegHive", m_FilePath + "\\snapshot-" + ID + "\\RegHive")) - return SB_ERR(SB_SnapCopyDatFail); + + foreach(const SBoxDataFile& BoxDataFile, CSandBox__BoxDataFiles) + { + if (!QFile::copy(m_FilePath + "\\" + BoxDataFile.Name, m_FilePath + "\\snapshot-" + ID + "\\" + BoxDataFile.Name)) { + if (BoxDataFile.Required) + return SB_ERR(SB_SnapCopyDatFail); + } + else if (BoxDataFile.Required) // this one is incremental, hence delete it from the copy root, after it was copied to the snapshot + QFile::remove(m_FilePath + "\\" + BoxDataFile.Name); + } ini.setValue("Snapshot_" + ID + "/Name", Name); ini.setValue("Snapshot_" + ID + "/SnapshotDate", QDateTime::currentDateTime().toTime_t()); @@ -400,14 +461,18 @@ SB_STATUS CSandBox__MergeFolders(const CSbieProgressPtr& pProgress, const QStrin SB_STATUS CSandBox__CleanupSnapshot(const QString& Folder) { - SNtObject ntHiveFile(L"\\??\\" + (Folder + "\\RegHive").toStdWString()); - SB_STATUS status = NtDeleteFile(&ntHiveFile.attr); - if (NT_SUCCESS(status)) { - SNtObject ntSnapshotFile(L"\\??\\" + Folder.toStdWString()); - status = NtDeleteFile(&ntSnapshotFile.attr); + foreach(const SBoxDataFile& BoxDataFile, CSandBox__BoxDataFiles) + { + SNtObject ntHiveFile(L"\\??\\" + (Folder + "\\" + BoxDataFile.Name).toStdWString()); + SB_STATUS status = NtDeleteFile(&ntHiveFile.attr); + if (NT_SUCCESS(status)) { + SNtObject ntSnapshotFile(L"\\??\\" + Folder.toStdWString()); + status = NtDeleteFile(&ntSnapshotFile.attr); + } + if(BoxDataFile.Required) + if (!NT_SUCCESS(status)) + return SB_ERR(SB_SnapRmDirFail, QVariantList() << Folder, status); } - if (!NT_SUCCESS(status)) - return SB_ERR(SB_SnapRmDirFail, QVariantList() << Folder, status); return SB_OK; } @@ -485,16 +550,30 @@ SB_PROGRESS CSandBox::SelectSnapshot(const QString& ID) { QSettings ini(m_FilePath + "\\Snapshots.ini", QSettings::IniFormat); - if (!ini.childGroups().contains("Snapshot_" + ID)) + if (!ID.isEmpty() && !ini.childGroups().contains("Snapshot_" + ID)) return SB_ERR(SB_SnapNotFound); if (m_pAPI->HasProcesses(m_Name)) return SB_ERR(SB_SnapIsRunning, OP_CONFIRM); - if (!QFile::remove(m_FilePath + "\\RegHive")) - return SB_ERR(SB_SnapDelDatFail); - if (!QFile::copy(m_FilePath + "\\snapshot-" + ID + "\\RegHive", m_FilePath + "\\RegHive")) - return SB_ERR(SB_SnapCopyDatFail); + foreach(const SBoxDataFile& BoxDataFile, CSandBox__BoxDataFiles) + { + if (!QFile::exists(m_FilePath + "\\" + BoxDataFile.Name)) + continue; + + if (!QFile::remove(m_FilePath + "\\" + BoxDataFile.Name)) { + if (BoxDataFile.Required) + return SB_ERR(SB_SnapDelDatFail); + } + + if (ID.isEmpty() || BoxDataFile.Recursive) + continue; // this one is incremental, don't restore it + + if (!QFile::copy(m_FilePath + "\\snapshot-" + ID + "\\" + BoxDataFile.Name, m_FilePath + "\\" + BoxDataFile.Name)) { + if (BoxDataFile.Required) + return SB_ERR(SB_SnapCopyDatFail); + } + } ini.setValue("Current/Snapshot", ID); ini.sync(); diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h index fabf0ee6..26001a30 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h +++ b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h @@ -59,11 +59,15 @@ public: virtual bool IsEnabled() const { return m_IsEnabled; } virtual bool IsEmpty() const; + virtual bool IsInitialized() const; + virtual bool HasSnapshots() const; virtual SB_PROGRESS CleanBox(); virtual SB_STATUS RenameBox(const QString& NewName); virtual SB_STATUS RemoveBox(); - virtual QList GetSnapshots(QString* pCurrent = NULL) const; + virtual QList GetSnapshots(QString* pCurrent = NULL, QString* pDefault = NULL) const; + virtual void SetDefaultSnapshot(QString Default); + virtual QString GetDefaultSnapshot(QString* pCurrent = NULL) const; virtual SB_PROGRESS TakeSnapshot(const QString& Name); virtual SB_PROGRESS RemoveSnapshot(const QString& ID); virtual SB_PROGRESS SelectSnapshot(const QString& ID); diff --git a/SandboxiePlus/SandMan/Forms/RecoveryWindow.ui b/SandboxiePlus/SandMan/Forms/RecoveryWindow.ui index 7130da8a..7509104f 100644 --- a/SandboxiePlus/SandMan/Forms/RecoveryWindow.ui +++ b/SandboxiePlus/SandMan/Forms/RecoveryWindow.ui @@ -91,19 +91,6 @@ - - - - - 0 - 0 - - - - Delete all - - - @@ -154,6 +141,25 @@ + + + + + 0 + 0 + + + + + 75 + 0 + + + + Delete Content + + + @@ -163,7 +169,6 @@ treeFiles chkShowAll - btnDeleteAll diff --git a/SandboxiePlus/SandMan/Forms/SnapshotsWindow.ui b/SandboxiePlus/SandMan/Forms/SnapshotsWindow.ui index c8c17735..7fe9a451 100644 --- a/SandboxiePlus/SandMan/Forms/SnapshotsWindow.ui +++ b/SandboxiePlus/SandMan/Forms/SnapshotsWindow.ui @@ -60,12 +60,8 @@ Selected Snapshot Details - - - - Name: - - + + @@ -77,11 +73,25 @@ - - + + + + Name: + + - - + + + + When deleting a snapshots content, it will be returned to this snapshot instead of to none. + + + Default shapsnot + + + + + @@ -98,20 +108,6 @@ Snapshot Actions - - - - Remove Snapshot - - - - - - - Go to Snapshot - - - @@ -132,6 +128,32 @@ + + + + Remove Snapshot + + + + + + + + 0 + 0 + + + + + 0 + 23 + + + + Go to Snapshot + + + @@ -147,7 +169,6 @@ btnTake treeSnapshots - btnSelect btnRemove txtName txtInfo diff --git a/SandboxiePlus/SandMan/SandMan.cpp b/SandboxiePlus/SandMan/SandMan.cpp index 5621b40f..ffd98c16 100644 --- a/SandboxiePlus/SandMan/SandMan.cpp +++ b/SandboxiePlus/SandMan/SandMan.cpp @@ -116,10 +116,6 @@ CSandMan::CSandMan(QWidget *parent) QString appTitle = tr("Sandboxie-Plus v%1").arg(GetVersion()); - if (QFile::exists(QCoreApplication::applicationDirPath() + "\\Certificate.dat")) { - CSettingsWindow::LoadCertificate(); - } - this->setWindowTitle(appTitle); setAcceptDrops(true); @@ -303,9 +299,6 @@ CSandMan::CSandMan(QWidget *parent) m_pProgressDialog->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop); - if (!bAutoRun && g_PendingMessage.isEmpty()) - show(); - //connect(theAPI, SIGNAL(LogMessage(const QString&, bool)), this, SLOT(OnLogMessage(const QString&, bool))); connect(theAPI, SIGNAL(LogSbieMessage(quint32, const QStringList&, quint32)), this, SLOT(OnLogSbieMessage(quint32, const QStringList&, quint32))); connect(theAPI, SIGNAL(NotAuthorized(bool, bool&)), this, SLOT(OnNotAuthorized(bool, bool&)), Qt::DirectConnection); @@ -315,6 +308,9 @@ CSandMan::CSandMan(QWidget *parent) m_uTimerID = startTimer(1000); + if (!bAutoRun && g_PendingMessage.isEmpty()) + SafeShow(this); + OnStatusChanged(); if (CSbieUtils::IsRunning(CSbieUtils::eAll) || theConf->GetBool("Options/StartIfStopped", true)) { @@ -899,11 +895,20 @@ void CSandMan::OnBoxClosed(const QString& BoxName) if (!pBox->GetBool("NeverDelete", false) && pBox->GetBool("AutoDelete", false) && !pBox->IsEmpty()) { + bool DeleteShapshots = false; // if this box auto deletes first show the recovry dialog with the option to abort deletion - if(!theGUI->OpenRecovery(pBox, true)) // unless no files are found than continue silently + if(!theGUI->OpenRecovery(pBox, DeleteShapshots, true)) // unless no files are found than continue silently return; - SB_PROGRESS Status = pBox->CleanBox(); + SB_PROGRESS Status; + if (!DeleteShapshots && pBox->HasSnapshots()) { // in auto delete mdoe always return to last snapshot + QString Current; + pBox->GetDefaultSnapshot(&Current); + Status = pBox->SelectSnapshot(Current); + } + else // if there are no snapshots jut use the normal cleaning procedure + Status = pBox->CleanBox(); + if (Status.GetStatus() == OP_ASYNC) AddAsyncOp(Status.GetValue()); } @@ -932,9 +937,10 @@ void CSandMan::OnStatusChanged() if (isConnected) { QString SbiePath = theAPI->GetSbiePath(); - OnLogMessage(tr("Sbie Directory: %1").arg(SbiePath)); - OnLogMessage(tr("Sbie+ Version: %1 (%2)").arg(GetVersion()).arg(theAPI->GetVersion())); + OnLogMessage(tr("Installation Directory: %1").arg(SbiePath)); + OnLogMessage(tr("Sandboxie-Plus Version: %1 (%2)").arg(GetVersion()).arg(theAPI->GetVersion())); OnLogMessage(tr("Loaded Config: %1").arg(theAPI->GetIniPath())); + OnLogMessage(tr("Data Directory: %1").arg(QString(theConf->GetConfigDir()).replace("/","\\"))); //statusBar()->showMessage(tr("Driver version: %1").arg(theAPI->GetVersion())); @@ -1006,6 +1012,10 @@ void CSandMan::OnStatusChanged() else { g_Certificate.clear(); g_CertInfo.State = 0; + + QString CertPath = QCoreApplication::applicationDirPath() + "\\Certificate.dat"; + if(QFile::exists(CertPath)) // always delete invalid certificates + WindowsMoveFile(CertPath.replace("/", "\\"), ""); } g_FeatureFlags = theAPI->GetFeatureFlags(); @@ -1237,7 +1247,7 @@ void CSandMan::OnFileToRecover(const QString& BoxName, const QString& FilePath, m_pPopUpWindow->AddFileToRecover(FilePath, BoxPath, pBox, ProcessId); } -bool CSandMan::OpenRecovery(const CSandBoxPtr& pBox, bool bCloseEmpty) +bool CSandMan::OpenRecovery(const CSandBoxPtr& pBox, bool& DeleteShapshots, bool bCloseEmpty) { auto pBoxEx = pBox.objectCast(); if (pBoxEx->m_pRecoveryWnd != NULL) { @@ -1251,6 +1261,7 @@ bool CSandMan::OpenRecovery(const CSandBoxPtr& pBox, bool bCloseEmpty) } else if (pRecoveryWindow->exec() != 1) return false; + DeleteShapshots = pRecoveryWindow->IsDeleteShapshots(); return true; } diff --git a/SandboxiePlus/SandMan/SandMan.h b/SandboxiePlus/SandMan/SandMan.h index ead2723a..e30ab44e 100644 --- a/SandboxiePlus/SandMan/SandMan.h +++ b/SandboxiePlus/SandMan/SandMan.h @@ -122,7 +122,7 @@ public slots: void OnQueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 RequestId, const QVariantMap& Data); void OnFileToRecover(const QString& BoxName, const QString& FilePath, const QString& BoxPath, quint32 ProcessId); - bool OpenRecovery(const CSandBoxPtr& pBox, bool bCloseEmpty = false); + bool OpenRecovery(const CSandBoxPtr& pBox, bool& DeleteShapshots, bool bCloseEmpty = false); class CRecoveryWindow* ShowRecovery(const CSandBoxPtr& pBox, bool bFind = true); void UpdateSettings(); diff --git a/SandboxiePlus/SandMan/Views/SbieView.cpp b/SandboxiePlus/SandMan/Views/SbieView.cpp index 513d7a4d..58ece331 100644 --- a/SandboxiePlus/SandMan/Views/SbieView.cpp +++ b/SandboxiePlus/SandMan/Views/SbieView.cpp @@ -911,6 +911,9 @@ void CSbieView::OnSandBoxAction(QAction* Action) { for (QList>::iterator I = Settings.begin(); I != Settings.end(); ++I) { + if (I->first == "FileRootPath" && !I->second.toUpper().contains("%SANDBOX%")) + continue; // skip the FileRootPath if it does not contain a %SANDBOX% + Status = theAPI->SbieIniSet(Name, I->first, I->second, CSbieAPI::eIniInsert, false); if (Status.IsError()) break; @@ -957,6 +960,8 @@ void CSbieView::OnSandBoxAction(QAction* Action) } else if (Action == m_pMenuCleanUp) { + bool DeleteShapshots = false; + if (SandBoxes.count() == 1) { if (SandBoxes.first()->IsEmpty()) { @@ -967,18 +972,27 @@ void CSbieView::OnSandBoxAction(QAction* Action) if (theConf->GetBool("Options/ShowRecovery", false)) { // Use recovery dialog in place of the confirmation messagebox for box clean up - if(!theGUI->OpenRecovery(SandBoxes.first())) + if(!theGUI->OpenRecovery(SandBoxes.first(), DeleteShapshots)) return; } - else if(QMessageBox("Sandboxie-Plus", tr("Do you want to delete the content of the selected sandbox?"), QMessageBox::Question, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton, this).exec() != QMessageBox::Yes) - return; + else if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to delete the content of the selected sandbox?") + , tr("Also delete all Snapshots"), &DeleteShapshots, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes) != QDialogButtonBox::Yes) + return; } - else if (QMessageBox("Sandboxie-Plus", tr("Do you really want to delete the content of multiple sandboxes?"), QMessageBox::Warning, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton, this).exec() != QMessageBox::Yes) - return; + else if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you really want to delete the content of all sellected sandboxes?") + , tr("Also delete all Snapshots"), &DeleteShapshots, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes) != QDialogButtonBox::Yes) + return; foreach(const CSandBoxPtr & pBox, SandBoxes) { - SB_PROGRESS Status = pBox->CleanBox(); + SB_PROGRESS Status; + if (!DeleteShapshots && pBox->HasSnapshots()) { + QString Default = pBox->GetDefaultSnapshot(); + Status = pBox->SelectSnapshot(Default); + } + else // if there are no snapshots jut use the normal cleaning procedure + Status = pBox->CleanBox(); + if (Status.GetStatus() == OP_ASYNC) theGUI->AddAsyncOp(Status.GetValue()); else if (Status.IsError()) @@ -991,7 +1005,7 @@ void CSbieView::OnSandBoxAction(QAction* Action) { bool State = false; if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to terminate all processes in the selected sandbox(es)?") - , tr("Terminate without asking"), &State, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes, QMessageBox::Information) != QDialogButtonBox::Yes) + , tr("Terminate without asking"), &State, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes) != QDialogButtonBox::Yes) return; if (State) @@ -1067,7 +1081,7 @@ void CSbieView::OnProcessAction() bool State = false; if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to %1 %2?").arg(((QAction*)sender())->text().toLower()).arg(Processes.count() == 1 ? Processes[0]->GetProcessName() : tr("the selected processes")) - , tr("Terminate without asking"), &State, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes, QMessageBox::Information) != QDialogButtonBox::Yes) + , tr("Terminate without asking"), &State, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes) != QDialogButtonBox::Yes) return; if (State) @@ -1243,21 +1257,6 @@ QList CSbieView::GetSelectedProcesses() return List; } -/*void CSbieView::UpdateRunMenu() -{ - while (m_iMenuRun < m_pMenuRun->actions().count()) - m_pMenuRun->removeAction(m_pMenuRun->actions().at(m_iMenuRun)); - - QStringList RunOptions = theConf->ListKeys("RunOptions"); - foreach(const QString& RunOption, RunOptions) - { - StrPair NameCmd = Split2(theConf->GetString("RunOptions/" + RunOption), "|"); - - QAction* pAction = m_pMenuRun->addAction(NameCmd.first, this, SLOT(OnSandBoxAction())); - pAction->setData(NameCmd.second); - } -}*/ - void CSbieView::UpdateRunMenu(const CSandBoxPtr& pBox) { while (m_iMenuRun < m_pMenuRun->actions().count()) diff --git a/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp b/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp index a59de2a7..033a73bb 100644 --- a/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp @@ -49,6 +49,7 @@ CRecoveryWindow::CRecoveryWindow(const CSandBoxPtr& pBox, QWidget *parent) m_LastTargetIndex = 0; m_bTargetsChanged = false; m_bReloadPending = false; + m_DeleteShapshots = false; #ifdef WIN32 QStyle* pStyle = QStyleFactory::create("windows"); @@ -99,6 +100,10 @@ CRecoveryWindow::CRecoveryWindow(const CSandBoxPtr& pBox, QWidget *parent) ui.btnRecover->setPopupMode(QToolButton::MenuButtonPopup); ui.btnRecover->setMenu(pRecMenu); + QMenu* pDelMenu = new QMenu(ui.btnDeleteAll); + pDelMenu->addAction(tr("Delete evertyhign including all snapshots"), this, SLOT(OnDeleteEverything())); + ui.btnDeleteAll->setPopupMode(QToolButton::MenuButtonPopup); + ui.btnDeleteAll->setMenu(pDelMenu); restoreGeometry(theConf->GetBlob("RecoveryWindow/Window_Geometry")); @@ -145,6 +150,7 @@ int CRecoveryWindow::exec() { //QDialog::setWindowModality(Qt::WindowModal); ui.btnDeleteAll->setVisible(true); + SafeShow(this); return QDialog::exec(); } @@ -223,6 +229,12 @@ void CRecoveryWindow::OnDeleteAll() this->close(); } +void CRecoveryWindow::OnDeleteEverything() +{ + m_DeleteShapshots = true; + OnDeleteAll(); +} + void CRecoveryWindow::AddFile(const QString& FilePath, const QString& BoxPath) { ui.chkShowAll->setTristate(true); diff --git a/SandboxiePlus/SandMan/Windows/RecoveryWindow.h b/SandboxiePlus/SandMan/Windows/RecoveryWindow.h index f4f4d8e3..0cb79a77 100644 --- a/SandboxiePlus/SandMan/Windows/RecoveryWindow.h +++ b/SandboxiePlus/SandMan/Windows/RecoveryWindow.h @@ -39,6 +39,8 @@ public: CRecoveryWindow(const CSandBoxPtr& pBox, QWidget *parent = Q_NULLPTR); ~CRecoveryWindow(); + bool IsDeleteShapshots() { return m_DeleteShapshots; } + virtual void accept() {} virtual void reject() { this->close(); } @@ -56,6 +58,7 @@ private slots: void OnRecover(); void OnTargetChanged(); void OnDeleteAll(); + void OnDeleteEverything(); void OnCloseUntil(); void OnCount(quint32 fileCount, quint32 folderCount, quint64 totalSize); @@ -80,6 +83,7 @@ protected: int m_LastTargetIndex; bool m_bTargetsChanged; bool m_bReloadPending; + bool m_DeleteShapshots; private: Ui::RecoveryWindow ui; diff --git a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp index 6afe3457..7a29c341 100644 --- a/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/SettingsWindow.cpp @@ -811,7 +811,7 @@ void CSettingsWindow::CertChanged() void CSettingsWindow::LoadCertificate() { QString CertPath; - if (theAPI->IsConnected()) + if (theAPI && theAPI->IsConnected()) CertPath = theAPI->GetSbiePath() + "\\Certificate.dat"; else CertPath = QCoreApplication::applicationDirPath() + "\\Certificate.dat"; diff --git a/SandboxiePlus/SandMan/Windows/SettingsWindow.h b/SandboxiePlus/SandMan/Windows/SettingsWindow.h index 510262b6..02c3e1d8 100644 --- a/SandboxiePlus/SandMan/Windows/SettingsWindow.h +++ b/SandboxiePlus/SandMan/Windows/SettingsWindow.h @@ -96,10 +96,11 @@ union SCertInfo { quint64 State; struct { quint32 - valid : 1, - expired : 1, - outdated : 1, - reservd_1 : 5, + valid : 1, // certificate is active + expired : 1, // certificate is expired but may be active + outdated : 1, // certificate is expired, not anymore valid for the current build + business : 1, // certificate is siutable for business use + reservd_1 : 4, reservd_2 : 8, reservd_3 : 8, reservd_4 : 8; diff --git a/SandboxiePlus/SandMan/Windows/SnapshotsWindow.cpp b/SandboxiePlus/SandMan/Windows/SnapshotsWindow.cpp index a8599699..138ac35b 100644 --- a/SandboxiePlus/SandMan/Windows/SnapshotsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/SnapshotsWindow.cpp @@ -49,11 +49,18 @@ CSnapshotsWindow::CSnapshotsWindow(const CSandBoxPtr& pBox, QWidget *parent) connect(ui.treeSnapshots->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(UpdateSnapshot(const QModelIndex&))); connect(ui.treeSnapshots, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(OnSelectSnapshot())); + + QMenu* pSelMenu = new QMenu(ui.btnSelect); + pSelMenu->addAction(tr("Revert to empty box"), this, SLOT(OnSelectEmpty())); + ui.btnSelect->setPopupMode(QToolButton::MenuButtonPopup); + ui.btnSelect->setMenu(pSelMenu); + connect(ui.btnTake, SIGNAL(clicked(bool)), this, SLOT(OnTakeSnapshot())); connect(ui.btnSelect, SIGNAL(clicked(bool)), this, SLOT(OnSelectSnapshot())); connect(ui.btnRemove, SIGNAL(clicked(bool)), this, SLOT(OnRemoveSnapshot())); connect(ui.txtName, SIGNAL(textEdited(const QString&)), this, SLOT(SaveInfo())); + connect(ui.chkDefault, SIGNAL(clicked(bool)), this, SLOT(OnChangeDefault())); connect(ui.txtInfo, SIGNAL(textChanged()), this, SLOT(SaveInfo())); ui.groupBox->setEnabled(false); @@ -84,13 +91,16 @@ void CSnapshotsWindow::closeEvent(QCloseEvent *e) void CSnapshotsWindow::UpdateSnapshots(bool AndSelect) { m_SnapshotMap.clear(); - QList SnapshotList = m_pBox->GetSnapshots(&m_CurSnapshot); + QList SnapshotList = m_pBox->GetSnapshots(&m_CurSnapshot, &m_DefaultSnapshot); foreach(const SBoxSnapshot& Snapshot, SnapshotList) { QVariantMap BoxSnapshot; BoxSnapshot["ID"] = Snapshot.ID; BoxSnapshot["ParentID"] = Snapshot.Parent; - BoxSnapshot["Name"] = Snapshot.NameStr; + if(m_DefaultSnapshot == Snapshot.ID) + BoxSnapshot["Name"] = Snapshot.NameStr + tr(" (default)"); + else + BoxSnapshot["Name"] = Snapshot.NameStr; BoxSnapshot["Info"] = Snapshot.InfoStr; BoxSnapshot["Date"] = Snapshot.SnapDate; if(m_CurSnapshot == Snapshot.ID) @@ -131,6 +141,7 @@ void CSnapshotsWindow::UpdateSnapshot(const QModelIndex& Index) m_SaveInfoPending = -1; ui.txtName->setText(BoxSnapshot["Name"].toString()); + ui.chkDefault->setChecked(ID == m_DefaultSnapshot); ui.txtInfo->setPlainText(BoxSnapshot["Info"].toString()); m_SaveInfoPending = 0; @@ -173,10 +184,37 @@ void CSnapshotsWindow::OnSelectSnapshot() //QVariant ID = m_pSnapshotModel->GetItemID(ModelIndex); QVariant ID = m_pSnapshotModel->GetItemID(Index); + SelectSnapshot(ID.toString()); +} + +void CSnapshotsWindow::OnSelectEmpty() +{ + SelectSnapshot(QString()); +} + +void CSnapshotsWindow::SelectSnapshot(const QString& ID) +{ if (QMessageBox("Sandboxie-Plus", tr("Do you really want to switch the active snapshot? Doing so will delete the current state!"), QMessageBox::Question, QMessageBox::Yes, QMessageBox::No | QMessageBox::Default | QMessageBox::Escape, QMessageBox::NoButton, this).exec() != QMessageBox::Yes) return; - HandleResult(m_pBox->SelectSnapshot(ID.toString())); + HandleResult(m_pBox->SelectSnapshot(ID)); +} + +void CSnapshotsWindow::OnChangeDefault() +{ + QModelIndex Index = ui.treeSnapshots->currentIndex(); + //QModelIndex ModelIndex = m_pSortProxy->mapToSource(Index); + //QVariant ID = m_pSnapshotModel->GetItemID(ModelIndex); + QVariant ID = m_pSnapshotModel->GetItemID(Index); + + if (ui.chkDefault->isChecked()) + m_DefaultSnapshot = ID.toString(); + else + m_DefaultSnapshot.clear(); + + m_pBox->SetDefaultSnapshot(m_DefaultSnapshot); + + UpdateSnapshots(); } void CSnapshotsWindow::OnRemoveSnapshot() diff --git a/SandboxiePlus/SandMan/Windows/SnapshotsWindow.h b/SandboxiePlus/SandMan/Windows/SnapshotsWindow.h index 00dea6f0..3ba7439b 100644 --- a/SandboxiePlus/SandMan/Windows/SnapshotsWindow.h +++ b/SandboxiePlus/SandMan/Windows/SnapshotsWindow.h @@ -27,6 +27,8 @@ private slots: void OnTakeSnapshot(); void OnSelectSnapshot(); + void OnSelectEmpty(); + void OnChangeDefault(); void OnRemoveSnapshot(); void OnSaveInfo(); @@ -34,10 +36,12 @@ private slots: protected: void closeEvent(QCloseEvent *e); + void SelectSnapshot(const QString& ID); void HandleResult(SB_PROGRESS Status); CSandBoxPtr m_pBox; QString m_CurSnapshot; + QString m_DefaultSnapshot; QMap m_SnapshotMap; QVariant m_SellectedID; diff --git a/SandboxiePlus/SandMan/main.cpp b/SandboxiePlus/SandMan/main.cpp index e98319d7..1c1bd382 100644 --- a/SandboxiePlus/SandMan/main.cpp +++ b/SandboxiePlus/SandMan/main.cpp @@ -7,6 +7,7 @@ //#include "../MiscHelpers/Common/qRC4.h" #include "../MiscHelpers/Common/Common.h" #include +#include "./Windows/SettingsWindow.h" CSettings* theConf = NULL; @@ -85,10 +86,18 @@ int main(int argc, char *argv[]) else if (app.sendMessage("ShowWnd")) return 0; - theConf = new CSettings("Sandboxie-Plus"); + + if (QFile::exists(QCoreApplication::applicationDirPath() + "\\Certificate.dat")) { + CSettingsWindow::LoadCertificate(); + g_CertInfo.business = GetArguments(g_Certificate, L'\n', L':').value("TYPE").toUpper().contains("BUSINESS"); + } + + // use a shared setting location when used in a business environment for easier administration + theConf = new CSettings("Sandboxie-Plus", g_CertInfo.business); //QThreadPool::globalInstance()->setMaxThreadCount(theConf->GetInt("Options/MaxThreadPool", 10)); + CSandMan* pWnd = new CSandMan(); QObject::connect(&app, SIGNAL(messageReceived(const QString&)), pWnd, SLOT(OnMessage(const QString&)));