3769 lines
124 KiB
C++
3769 lines
124 KiB
C++
#include "stdafx.h"
|
|
#include "SandMan.h"
|
|
#include "../MiscHelpers/Common/Common.h"
|
|
#include "../MiscHelpers/Common/ExitDialog.h"
|
|
#include "../MiscHelpers/Common/SortFilterProxyModel.h"
|
|
#include "Views/SbieView.h"
|
|
#include "../MiscHelpers/Common/CheckableMessageBox.h"
|
|
#include <QWinEventNotifier>
|
|
#include "./Dialogs/MultiErrorDialog.h"
|
|
#include "../QSbieAPI/SbieUtils.h"
|
|
#include "../QSbieAPI/Sandboxie/BoxBorder.h"
|
|
#include "../QSbieAPI/Sandboxie/SbieTemplates.h"
|
|
#include "Windows/SettingsWindow.h"
|
|
#include "Windows/RecoveryWindow.h"
|
|
#include <QtConcurrent>
|
|
#include "../MiscHelpers/Common/SettingsWidgets.h"
|
|
#include "Windows/OptionsWindow.h"
|
|
#include <QProxyStyle>
|
|
#include "../MiscHelpers/Common/TreeItemModel.h"
|
|
#include "../MiscHelpers/Common/ListItemModel.h"
|
|
#include "Views/TraceView.h"
|
|
#include "Windows/SelectBoxWindow.h"
|
|
#include "../UGlobalHotkey/uglobalhotkeys.h"
|
|
#include "Wizards/SetupWizard.h"
|
|
#include "Helpers/WinAdmin.h"
|
|
#include "../MiscHelpers/Common/OtherFunctions.h"
|
|
#include "../MiscHelpers/Common/Common.h"
|
|
#include "Windows/SupportDialog.h"
|
|
#include "../MiscHelpers/Archive/Archive.h"
|
|
#include "../MiscHelpers/Archive/ArchiveFS.h"
|
|
#include "Views/FileView.h"
|
|
#include "OnlineUpdater.h"
|
|
#include "../MiscHelpers/Common/NeonEffect.h"
|
|
#include <QVariantAnimation>
|
|
#include <QSessionManager>
|
|
#include "Helpers/FullScreen.h"
|
|
#include "Helpers/WinHelper.h"
|
|
#include "../QSbieAPI/Helpers/DbgHelper.h"
|
|
#include "Wizards/BoxAssistant.h"
|
|
#include "Engine/BoxEngine.h"
|
|
#include "AddonManager.h"
|
|
|
|
CSbiePlusAPI* theAPI = NULL;
|
|
|
|
#include <wtypes.h>
|
|
#include <QAbstractNativeEventFilter>
|
|
#include <dbt.h>
|
|
|
|
class CNativeEventFilter : public QAbstractNativeEventFilter
|
|
{
|
|
public:
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result)
|
|
#else
|
|
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result)
|
|
#endif
|
|
{
|
|
if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG")
|
|
{
|
|
MSG *msg = static_cast<MSG *>(message);
|
|
|
|
//if(msg->message != 275 && msg->message != 1025)
|
|
// qDebug() << msg->message;
|
|
|
|
if (msg->message == WM_NOTIFY)
|
|
{
|
|
//return true;
|
|
}
|
|
else if (msg->message == WM_DEVICECHANGE)
|
|
{
|
|
if (msg->wParam == DBT_DEVICEARRIVAL // Drive letter added
|
|
|| msg->wParam == DBT_DEVICEREMOVECOMPLETE) // Drive letter removed
|
|
{
|
|
/*DEV_BROADCAST_HDR* deviceBroadcast = (DEV_BROADCAST_HDR*)msg->lParam;
|
|
if (deviceBroadcast->dbch_devicetype == DBT_DEVTYP_VOLUME) {
|
|
}*/
|
|
if (theAPI)
|
|
theAPI->UpdateDriveLetters();
|
|
}
|
|
/*else if ((msg->wParam & 0xFF80) == 0xAA00 && msg->lParam == 'xobs')
|
|
{
|
|
UCHAR driveNumber = (UCHAR)(msg->wParam & 0x1F);
|
|
if (driveNumber < 26) {
|
|
}
|
|
}
|
|
else if (msg->wParam == DBT_DEVNODES_CHANGED) // hardware changed
|
|
{
|
|
}*/
|
|
}
|
|
else if (msg->message == WM_SETTINGCHANGE)
|
|
{
|
|
if (theGUI && theConf->GetInt("Options/UseDarkTheme", 2) == 2)
|
|
theGUI->UpdateTheme();
|
|
}
|
|
else if (msg->message == WM_SHOWWINDOW && msg->wParam)
|
|
{
|
|
QWidget* pWidget = QWidget::find((WId)msg->hwnd);
|
|
if (theGUI && pWidget && (pWidget->windowType() | Qt::Dialog) == Qt::Dialog)
|
|
theGUI->UpdateTitleTheme(msg->hwnd);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
HWND MainWndHandle = NULL;
|
|
|
|
CSandMan* theGUI = NULL;
|
|
|
|
extern QString g_PendingMessage;
|
|
|
|
|
|
CSandMan::CSandMan(QWidget *parent)
|
|
: QMainWindow(parent)
|
|
{
|
|
#if defined(Q_OS_WIN)
|
|
MainWndHandle = (HWND)QWidget::winId();
|
|
|
|
QApplication::instance()->installNativeEventFilter(new CNativeEventFilter);
|
|
#endif
|
|
|
|
CArchive::Init();
|
|
|
|
theGUI = this;
|
|
|
|
m_DarkTheme = false;
|
|
m_FusionTheme = false;
|
|
|
|
QDesktopServices::setUrlHandler("http", this, "OpenUrl");
|
|
QDesktopServices::setUrlHandler("https", this, "OpenUrl");
|
|
QDesktopServices::setUrlHandler("sbie", this, "OpenUrl");
|
|
|
|
m_StartMenuUpdatePending = false;
|
|
|
|
m_ThemeUpdatePending = false;
|
|
m_DefaultStyle = QApplication::style()->objectName();
|
|
m_DefaultPalett = QApplication::palette();
|
|
m_DefaultFontSize = QApplication::font().pointSizeF();
|
|
|
|
m_DarkPalett.setColor(QPalette::Light, QColor(96, 96, 96));
|
|
m_DarkPalett.setColor(QPalette::Midlight, QColor(64, 64, 64));
|
|
m_DarkPalett.setColor(QPalette::Mid, QColor(48, 48, 48));
|
|
m_DarkPalett.setColor(QPalette::Dark, QColor(53, 53, 53));
|
|
m_DarkPalett.setColor(QPalette::Shadow, QColor(25, 25, 25));
|
|
m_DarkPalett.setColor(QPalette::Window, QColor(53, 53, 53));
|
|
m_DarkPalett.setColor(QPalette::WindowText, Qt::white);
|
|
m_DarkPalett.setColor(QPalette::Base, QColor(25, 25, 25));
|
|
m_DarkPalett.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
|
|
m_DarkPalett.setColor(QPalette::ToolTipBase, Qt::lightGray);
|
|
m_DarkPalett.setColor(QPalette::ToolTipText, Qt::white);
|
|
m_DarkPalett.setColor(QPalette::Text, Qt::white);
|
|
m_DarkPalett.setColor(QPalette::Button, QColor(53, 53, 53));
|
|
m_DarkPalett.setColor(QPalette::ButtonText, Qt::white);
|
|
m_DarkPalett.setColor(QPalette::BrightText, Qt::red);
|
|
m_DarkPalett.setColor(QPalette::Link, QColor(218, 130, 42));
|
|
m_DarkPalett.setColor(QPalette::LinkVisited, QColor(218, 130, 42));
|
|
m_DarkPalett.setColor(QPalette::Highlight, QColor(42, 130, 218));
|
|
m_DarkPalett.setColor(QPalette::HighlightedText, Qt::black);
|
|
m_DarkPalett.setColor(QPalette::PlaceholderText, QColor(96, 96, 96));
|
|
m_DarkPalett.setColor(QPalette::Disabled, QPalette::WindowText, Qt::darkGray);
|
|
m_DarkPalett.setColor(QPalette::Disabled, QPalette::Text, Qt::darkGray);
|
|
m_DarkPalett.setColor(QPalette::Disabled, QPalette::Light, Qt::black);
|
|
m_DarkPalett.setColor(QPalette::Disabled, QPalette::ButtonText, Qt::darkGray);
|
|
|
|
LoadLanguage();
|
|
|
|
if (!theConf->IsWritable()) {
|
|
QMessageBox::critical(this, "Sandboxie-Plus", tr("WARNING: Sandboxie-Plus.ini in %1 cannot be written to, settings will not be saved.").arg(theConf->GetConfigDir()));
|
|
}
|
|
|
|
m_bExit = false;
|
|
|
|
theAPI = new CSbiePlusAPI(this);
|
|
connect(theAPI, SIGNAL(StatusChanged()), this, SLOT(OnStatusChanged()));
|
|
|
|
connect(theAPI, SIGNAL(BoxAdded(const CSandBoxPtr&)), this, SLOT(OnBoxAdded(const CSandBoxPtr&)));
|
|
connect(theAPI, SIGNAL(BoxClosed(const CSandBoxPtr&)), this, SLOT(OnBoxClosed(const CSandBoxPtr&)));
|
|
connect(theAPI, SIGNAL(BoxCleaned(CSandBoxPlus*)), this, SLOT(OnBoxCleaned(CSandBoxPlus*)));
|
|
|
|
|
|
#ifdef INSIDER_BUILD
|
|
QString appTitle = tr("Sandboxie-Plus Insider [%1]").arg(QString(__DATE__));
|
|
#else
|
|
QString appTitle = tr("Sandboxie-Plus v%1").arg(GetVersion());
|
|
#endif
|
|
|
|
this->setWindowTitle(appTitle);
|
|
|
|
setAcceptDrops(true);
|
|
|
|
m_pBoxBorder = new CBoxBorder(theAPI, this);
|
|
|
|
m_SbieTemplates = new CSbieTemplatesEx(theAPI, this);
|
|
|
|
|
|
|
|
m_bConnectPending = false;
|
|
m_bStopPending = false;
|
|
|
|
|
|
m_pUpdater = new COnlineUpdater(this);
|
|
|
|
m_AddonManager = new CAddonManager(this);
|
|
|
|
|
|
m_pMainWidget = new QWidget(this);
|
|
|
|
m_pMenuBar = menuBar();
|
|
connect(m_pMenuBar, SIGNAL(hovered(QAction*)), this, SLOT(OnMenuHover(QAction*)));
|
|
|
|
QWidget* pMenuWidget = new QWidget(this);
|
|
m_pMenuLayout = new QHBoxLayout(pMenuWidget);
|
|
m_pMenuLayout->setContentsMargins(0, 0, 0, 0);
|
|
//m_pMenuLayout->addWidget(m_pMenuBar);
|
|
m_pMenuLayout->setMenuBar(m_pMenuBar);
|
|
//m_pMenuLayout->addWidget(m_pLabel);
|
|
//m_pMenuLayout->addStretch(10);
|
|
setMenuWidget(pMenuWidget);
|
|
|
|
CreateUI();
|
|
setCentralWidget(m_pMainWidget);
|
|
|
|
m_pTraceInfo = new QLabel();
|
|
m_pDisabledForce = new QLabel();
|
|
m_pDisabledRecovery = new QLabel();
|
|
m_pDisabledMessages = new QLabel();
|
|
statusBar()->addPermanentWidget(m_pTraceInfo);
|
|
statusBar()->addPermanentWidget(m_pDisabledForce);
|
|
statusBar()->addPermanentWidget(m_pDisabledRecovery);
|
|
statusBar()->addPermanentWidget(m_pDisabledMessages);
|
|
OnDisablePopUp(); // update statusbar
|
|
|
|
|
|
|
|
m_pHotkeyManager = new UGlobalHotkeys(this);
|
|
connect(m_pHotkeyManager, SIGNAL(activated(size_t)), SLOT(OnHotKey(size_t)));
|
|
SetupHotKeys();
|
|
|
|
//for (int i = 0; i < eMaxColor; i++) {
|
|
// m_BoxIcons[i].Empty = QIcon(QString(":/Boxes/Empty%1").arg(i));
|
|
// m_BoxIcons[i].InUse = QIcon(QString(":/Boxes/Full%1").arg(i));
|
|
//}
|
|
|
|
m_BoxColors[CSandBoxPlus::eHardenedPlus] = qRgb(238,35,4);
|
|
m_BoxColors[CSandBoxPlus::eHardened] = qRgb(247,125,2);
|
|
m_BoxColors[CSandBoxPlus::eDefaultPlus] = qRgb(1,133,248);
|
|
m_BoxColors[CSandBoxPlus::eDefault] = qRgb(246,246,2);
|
|
m_BoxColors[CSandBoxPlus::eAppBoxPlus] = qRgb(3,232,232);
|
|
m_BoxColors[CSandBoxPlus::eAppBox] = qRgb(0,253,0);
|
|
m_BoxColors[CSandBoxPlus::eInsecure] = qRgb(244,3,244);
|
|
m_BoxColors[CSandBoxPlus::eOpen] = qRgb(255,255,255);
|
|
|
|
CreateTrayIcon();
|
|
|
|
LoadState();
|
|
|
|
m_pProgressDialog = new CProgressDialog("");
|
|
m_pProgressDialog->setWindowModality(Qt::ApplicationModal);
|
|
connect(m_pProgressDialog, SIGNAL(Cancel()), this, SLOT(OnCancelAsync()));
|
|
m_pProgressModal = false;
|
|
|
|
m_pPopUpWindow = new CPopUpWindow();
|
|
|
|
bool bAlwaysOnTop = theConf->GetBool("Options/AlwaysOnTop", false);
|
|
this->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop);
|
|
m_pPopUpWindow->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop);
|
|
m_pProgressDialog->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop);
|
|
|
|
//connect(theAPI, SIGNAL(LogMessage(const QString&, bool)), this, SLOT(OnLogMessage(const QString&, bool)));
|
|
connect(theAPI, SIGNAL(LogSbieMessage(quint32, const QStringList&, quint32)), this, SLOT(OnLogSbieMessage(quint32, const QStringList&, quint32)));
|
|
connect(theAPI, SIGNAL(NotAuthorized(bool, bool&)), this, SLOT(OnNotAuthorized(bool, bool&)), Qt::DirectConnection);
|
|
connect(theAPI, SIGNAL(QueuedRequest(quint32, quint32, quint32, const QVariantMap&)), this, SLOT(OnQueuedRequest(quint32, quint32, quint32, const QVariantMap&)), Qt::QueuedConnection);
|
|
connect(theAPI, SIGNAL(FileToRecover(const QString&, const QString&, const QString&, quint32)), this, SLOT(OnFileToRecover(const QString&, const QString&, const QString&, quint32)), Qt::QueuedConnection);
|
|
connect(theAPI, SIGNAL(ConfigReloaded()), this, SLOT(OnIniReloaded()));
|
|
|
|
connect(qApp, &QGuiApplication::commitDataRequest, this, &CSandMan::commitData);
|
|
|
|
m_uTimerID = startTimer(1000);
|
|
|
|
bool bAutoRun = QApplication::arguments().contains("-autorun");
|
|
if (!bAutoRun && g_PendingMessage.isEmpty())
|
|
SafeShow(this);
|
|
|
|
OnStatusChanged();
|
|
if (CSbieUtils::IsRunning(CSbieUtils::eAll) || theConf->GetBool("Options/StartIfStopped", true))
|
|
{
|
|
SB_RESULT(void*) Status = ConnectSbie();
|
|
HandleMaintenance(Status);
|
|
}
|
|
|
|
connect(CSymbolProvider::Instance(), SIGNAL(StatusChanged(const QString&)), this, SLOT(OnSymbolStatus(const QString&)));
|
|
|
|
//qApp->setWindowIcon(GetIcon("IconEmptyDC", false));
|
|
}
|
|
|
|
CSandMan::~CSandMan()
|
|
{
|
|
m_pPopUpWindow->close();
|
|
delete m_pPopUpWindow;
|
|
|
|
if(theAPI->IsMonitoring())
|
|
theAPI->EnableMonitor(false);
|
|
|
|
delete m_pBoxBorder;
|
|
|
|
killTimer(m_uTimerID);
|
|
|
|
m_pTrayIcon->show();
|
|
m_pTrayIcon->hide();
|
|
|
|
StoreState();
|
|
|
|
theAPI = NULL;
|
|
|
|
theGUI = NULL;
|
|
}
|
|
|
|
void CSandMan::LoadState(bool bFull)
|
|
{
|
|
if (bFull) {
|
|
setWindowState(Qt::WindowNoState);
|
|
restoreGeometry(theConf->GetBlob("MainWindow/Window_Geometry"));
|
|
restoreState(theConf->GetBlob("MainWindow/Window_State"));
|
|
}
|
|
|
|
//m_pBoxTree->restoreState(theConf->GetBlob("MainWindow/BoxTree_Columns"));
|
|
if(m_pMessageLog) m_pMessageLog->GetView()->header()->restoreState(theConf->GetBlob("MainWindow/LogList_Columns"));
|
|
if(m_pRecoveryLog) m_pRecoveryLog->GetView()->header()->restoreState(theConf->GetBlob("MainWindow/RecoveryLog_Columns"));
|
|
if(m_pLogSplitter) m_pLogSplitter->restoreState(theConf->GetBlob("MainWindow/Log_Splitter"));
|
|
if(m_pPanelSplitter) m_pPanelSplitter->restoreState(theConf->GetBlob("MainWindow/Panel_Splitter"));
|
|
if(m_pLogTabs) m_pLogTabs->setCurrentIndex(theConf->GetInt("MainWindow/LogTab", 0));
|
|
}
|
|
|
|
void CSandMan::StoreState()
|
|
{
|
|
theConf->SetBlob("MainWindow/Window_Geometry", saveGeometry());
|
|
theConf->SetBlob("MainWindow/Window_State", saveState());
|
|
|
|
//theConf->SetBlob("MainWindow/BoxTree_Columns", m_pBoxTree->saveState());
|
|
if(m_pMessageLog) theConf->SetBlob("MainWindow/LogList_Columns", m_pMessageLog->GetView()->header()->saveState());
|
|
if(m_pRecoveryLog) theConf->SetBlob("MainWindow/RecoveryLog_Columns", m_pRecoveryLog->GetView()->header()->saveState());
|
|
if(m_pLogSplitter) theConf->SetBlob("MainWindow/Log_Splitter", m_pLogSplitter->saveState());
|
|
if(m_pPanelSplitter) theConf->SetBlob("MainWindow/Panel_Splitter", m_pPanelSplitter->saveState());
|
|
if(m_pLogTabs) theConf->SetValue("MainWindow/LogTab", m_pLogTabs->currentIndex());
|
|
}
|
|
|
|
QIcon CSandMan::GetIcon(const QString& Name, int iAction)
|
|
{
|
|
int iNoIcons = theConf->GetInt("Options/NoIcons", 2);
|
|
if (iNoIcons == 2)
|
|
iNoIcons = theConf->GetInt("Options/ViewMode", 1) == 2 ? 1 : 0;
|
|
if(iAction && iNoIcons)
|
|
return QIcon();
|
|
|
|
QString Path = QApplication::applicationDirPath() + "/Icons/" + Name + ".png";
|
|
if(QFile::exists(Path))
|
|
return QIcon(Path);
|
|
return QIcon((iAction == 1 ? ":/Actions/" : ":/") + Name + ".png");
|
|
}
|
|
|
|
void CSandMan::CreateUI()
|
|
{
|
|
SetUITheme();
|
|
|
|
// Clear old ToolBar references.
|
|
m_pNewBoxButton = nullptr;
|
|
m_pCleanUpButton = nullptr;
|
|
m_pEditIniButton = nullptr;
|
|
|
|
int iViewMode = theConf->GetInt("Options/ViewMode", 1);
|
|
|
|
if(iViewMode == 2)
|
|
CreateOldMenus();
|
|
else
|
|
CreateMenus(iViewMode == 1);
|
|
|
|
m_pMainLayout = new QVBoxLayout(m_pMainWidget);
|
|
m_pMainLayout->setContentsMargins(2,2,2,2);
|
|
m_pMainLayout->setSpacing(0);
|
|
|
|
if(iViewMode == 1)
|
|
CreateToolBar(false);
|
|
else {
|
|
m_pSeparator = NULL;
|
|
CreateLabel();
|
|
m_pMenuLayout->addWidget(m_pLabel);
|
|
UpdateLabel();
|
|
}
|
|
|
|
CreateView(iViewMode);
|
|
|
|
if (iViewMode != 2) {
|
|
m_pMenuBrowse->setChecked(theConf->GetBool("Options/ShowFilePanel", false));
|
|
m_pFileView->setVisible(m_pMenuBrowse->isChecked());
|
|
}
|
|
|
|
foreach(QAction * pAction, m_pViewMode->actions())
|
|
pAction->setChecked(pAction->data().toInt() == iViewMode);
|
|
|
|
statusBar()->setVisible(iViewMode == 1);
|
|
|
|
if(m_pKeepTerminated) m_pKeepTerminated->setChecked(theConf->GetBool("Options/KeepTerminated"));
|
|
if(m_pShowAllSessions) m_pShowAllSessions->setChecked(theConf->GetBool("Options/ShowAllSessions"));
|
|
|
|
m_pWndTopMost->setChecked(theConf->GetBool("Options/AlwaysOnTop", false));
|
|
|
|
|
|
// pizza background
|
|
int iUsePizza = theConf->GetInt("Options/UseBackground", 2);
|
|
if (iUsePizza == 2)
|
|
iUsePizza = theConf->GetInt("Options/ViewMode", 1) == 2 ? 1 : 0;
|
|
if (iUsePizza)
|
|
{
|
|
QPalette pizzaPalete = GetBoxView()->GetTree()->palette(); // QPalette pizzaPalete = QApplication::palette();
|
|
SetPaleteTexture(pizzaPalete, QPalette::Base, QImage(":/Assets/background.png"));
|
|
GetBoxView()->GetTree()->setPalette(pizzaPalete); // QApplication::setPalette(pizzaPalete);
|
|
GetFileView()->GetTree()->setPalette(pizzaPalete); // QApplication::setPalette(pizzaPalete);
|
|
}
|
|
}
|
|
|
|
void CSandMan::CreateMaintenanceMenu()
|
|
{
|
|
m_pMaintenance = m_pMenuFile->addMenu(CSandMan::GetIcon("Maintenance"), tr("&Maintenance"));
|
|
m_pConnect = m_pMaintenance->addAction(CSandMan::GetIcon("Connect"), tr("Connect"), this, SLOT(OnMaintenance()));
|
|
m_pDisconnect = m_pMaintenance->addAction(CSandMan::GetIcon("Disconnect"), tr("Disconnect"), this, SLOT(OnMaintenance()));
|
|
m_pMaintenance->addSeparator();
|
|
m_pStopAll = m_pMaintenance->addAction(CSandMan::GetIcon("Stop"), tr("Stop All"), this, SLOT(OnMaintenance()));
|
|
m_pMaintenanceItems = m_pMaintenance->addMenu(CSandMan::GetIcon("ManMaintenance"), tr("&Advanced"));
|
|
m_pInstallDrv = m_pMaintenanceItems->addAction(tr("Install Driver"), this, SLOT(OnMaintenance()));
|
|
m_pStartDrv = m_pMaintenanceItems->addAction(tr("Start Driver"), this, SLOT(OnMaintenance()));
|
|
m_pStopDrv = m_pMaintenanceItems->addAction(tr("Stop Driver"), this, SLOT(OnMaintenance()));
|
|
m_pUninstallDrv = m_pMaintenanceItems->addAction(tr("Uninstall Driver"), this, SLOT(OnMaintenance()));
|
|
m_pMaintenanceItems->addSeparator();
|
|
m_pInstallSvc = m_pMaintenanceItems->addAction(tr("Install Service"), this, SLOT(OnMaintenance()));
|
|
m_pStartSvc = m_pMaintenanceItems->addAction(tr("Start Service"), this, SLOT(OnMaintenance()));
|
|
m_pStopSvc = m_pMaintenanceItems->addAction(tr("Stop Service"), this, SLOT(OnMaintenance()));
|
|
m_pUninstallSvc = m_pMaintenanceItems->addAction(tr("Uninstall Service"), this, SLOT(OnMaintenance()));
|
|
m_pMaintenance->addSeparator();
|
|
m_pSetupWizard = m_pMaintenance->addAction(CSandMan::GetIcon("Wizard"), tr("Setup Wizard"), this, SLOT(OnMaintenance()));
|
|
//m_pUpdateCore = m_pMaintenance->addAction(CSandMan::GetIcon("Install"), tr("Update Core Files"), this, SLOT(OnMaintenance()));
|
|
if(theGUI->IsFullyPortable())
|
|
m_pUninstallAll = m_pMaintenance->addAction(CSandMan::GetIcon("Uninstall"), tr("Uninstall All"), this, SLOT(OnMaintenance()));
|
|
}
|
|
|
|
void CSandMan::CreateViewBaseMenu()
|
|
{
|
|
m_pViewMode = new QActionGroup(m_pMenuView);
|
|
MakeAction(m_pViewMode, m_pMenuView, tr("Simple View"), 0);
|
|
MakeAction(m_pViewMode, m_pMenuView, tr("Advanced View"), 1);
|
|
MakeAction(m_pViewMode, m_pMenuView, tr("Vintage View (like SbieCtrl)"), 2);
|
|
connect(m_pViewMode, SIGNAL(triggered(QAction*)), this, SLOT(OnViewMode(QAction*)));
|
|
|
|
m_pMenuView->addSeparator();
|
|
m_pWndTopMost = m_pMenuView->addAction(tr("Always on Top"), this, SLOT(OnAlwaysTop()));
|
|
m_pWndTopMost->setCheckable(true);
|
|
}
|
|
|
|
void CSandMan::CreateHelpMenu(bool bAdvanced)
|
|
{
|
|
m_pMenuHelp = m_pMenuBar->addMenu(tr("&Help"));
|
|
//m_pMenuHelp->addAction(tr("Support Sandboxie-Plus on Patreon"), this, SLOT(OnHelp()));
|
|
//m_pSupport = m_pMenuHelp->addAction(tr("Support Sandboxie-Plus with Donations"), this, SLOT(OnHelp()));
|
|
//if (!bAdvanced) {
|
|
// m_pMenuHelp->removeAction(m_pSupport);
|
|
// m_pMenuBar->addAction(m_pSupport);
|
|
//}
|
|
m_pContribution = m_pMenuHelp->addAction(CSandMan::GetIcon("Support"), tr("Contribute to Sandboxie-Plus"), this, SLOT(OnHelp()));
|
|
m_pBoxAssistant = m_pMenuHelp->addAction(CSandMan::GetIcon("FirstAid"), tr("Troubleshooting Wizard"), this, SLOT(OnBoxAssistant()));
|
|
m_pManual = m_pMenuHelp->addAction(CSandMan::GetIcon("Help"), tr("Online Documentation"), this, SLOT(OnHelp()));
|
|
m_pForum = m_pMenuHelp->addAction(CSandMan::GetIcon("Forum"), tr("Visit Support Forum"), this, SLOT(OnHelp()));
|
|
m_pMenuHelp->addSeparator();
|
|
m_pUpdate = m_pMenuHelp->addAction(CSandMan::GetIcon("Update"), tr("Check for Updates"), this, SLOT(CheckForUpdates()));
|
|
m_pMenuHelp->addSeparator();
|
|
m_pAboutQt = m_pMenuHelp->addAction(tr("About the Qt Framework"), this, SLOT(OnAbout()));
|
|
m_pAbout = m_pMenuHelp->addAction(CSandMan::GetIcon("IconFull", 2), tr("About Sandboxie-Plus"), this, SLOT(OnAbout()));
|
|
}
|
|
|
|
void CSandMan::CreateMenus(bool bAdvanced)
|
|
{
|
|
m_pMenuBar->clear();
|
|
|
|
m_pMenuFile = m_pMenuBar->addMenu(tr("&Sandbox"));
|
|
m_pNewBox = m_pMenuFile->addAction(CSandMan::GetIcon("NewBox"), tr("Create New Box"), this, SLOT(OnSandBoxAction()));
|
|
m_pNewGroup = m_pMenuFile->addAction(CSandMan::GetIcon("Group"), tr("Create Box Group"), this, SLOT(OnSandBoxAction()));
|
|
m_pImportBox = m_pMenuFile->addAction(CSandMan::GetIcon("UnPackBox"), tr("Import Box"), this, SLOT(OnSandBoxAction()));
|
|
m_pMenuFile->addSeparator();
|
|
m_pRunBoxed = m_pMenuFile->addAction(CSandMan::GetIcon("Run"), tr("Run Sandboxed"), this, SLOT(OnSandBoxAction()));
|
|
m_pEmptyAll = m_pMenuFile->addAction(CSandMan::GetIcon("EmptyAll"), tr("Terminate All Processes"), this, SLOT(OnEmptyAll()));
|
|
m_pMenuFile->addSeparator();
|
|
m_pWndFinder = m_pMenuFile->addAction(CSandMan::GetIcon("finder"), tr("Is Window Sandboxed?"), this, SLOT(OnWndFinder()));
|
|
|
|
if(bAdvanced || theGUI->IsFullyPortable())
|
|
CreateMaintenanceMenu();
|
|
else {
|
|
m_pMaintenance = NULL;
|
|
m_pConnect = NULL;
|
|
m_pDisconnect = NULL;
|
|
m_pMaintenanceItems = NULL;
|
|
m_pInstallDrv = NULL;
|
|
m_pStartDrv = NULL;
|
|
m_pStopDrv = NULL;
|
|
m_pUninstallDrv = NULL;
|
|
m_pInstallSvc = NULL;
|
|
m_pStartSvc = NULL;
|
|
m_pStopSvc = NULL;
|
|
m_pUninstallSvc = NULL;
|
|
m_pStopAll = NULL;
|
|
m_pUninstallAll = NULL;
|
|
m_pSetupWizard = NULL;
|
|
//m_pUpdateCore = NULL;
|
|
}
|
|
|
|
m_pMenuFile->addSeparator();
|
|
m_pExit = m_pMenuFile->addAction(CSandMan::GetIcon("Exit"), tr("Exit"), this, SLOT(OnExit()));
|
|
|
|
|
|
m_pMenuView = m_pMenuBar->addMenu(tr("&View"));
|
|
|
|
CreateViewBaseMenu();
|
|
|
|
if(bAdvanced) {
|
|
m_pMenuView->addSeparator();
|
|
|
|
m_pShowHidden = m_pMenuView->addAction(tr("Show Hidden Boxes"));
|
|
m_pShowHidden->setCheckable(true);
|
|
m_pShowAllSessions = m_pMenuView->addAction(tr("Show All Sessions"), this, SLOT(OnProcView()));
|
|
m_pShowAllSessions->setCheckable(true);
|
|
}
|
|
else {
|
|
m_pShowHidden = NULL;
|
|
m_pShowAllSessions = NULL;
|
|
}
|
|
|
|
m_pMenuView->addSeparator();
|
|
m_pMenuBrowse = m_pMenuView->addAction(CSandMan::GetIcon("Explore"), tr("Show File Panel"), this, SLOT(OnProcView()));
|
|
m_pMenuBrowse->setCheckable(true);
|
|
m_pMenuBrowse->setShortcut(QKeySequence("Ctrl+D"));
|
|
m_pMenuBrowse->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
|
this->addAction(m_pMenuBrowse);
|
|
|
|
m_pMenuView->addSeparator();
|
|
|
|
m_pRefreshAll = m_pMenuView->addAction(CSandMan::GetIcon("Refresh"), tr("Refresh View"), this, SLOT(OnRefresh()));
|
|
m_pRefreshAll->setShortcut(QKeySequence("F5"));
|
|
m_pRefreshAll->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
|
this->addAction(m_pRefreshAll);
|
|
|
|
if(bAdvanced) {
|
|
m_pCleanUpMenu = m_pMenuView->addMenu(CSandMan::GetIcon("Clean"), tr("Clean Up"));
|
|
m_pCleanUpProcesses = m_pCleanUpMenu->addAction(tr("Cleanup Processes"), this, SLOT(OnCleanUp()));
|
|
m_pCleanUpMenu->addSeparator();
|
|
m_pCleanUpMsgLog = m_pCleanUpMenu->addAction(tr("Cleanup Message Log"), this, SLOT(OnCleanUp()));
|
|
m_pCleanUpTrace = m_pCleanUpMenu->addAction(tr("Cleanup Trace Log"), this, SLOT(OnCleanUp()));
|
|
m_pCleanUpRecovery = m_pCleanUpMenu->addAction(tr("Cleanup Recovery Log"), this, SLOT(OnCleanUp()));
|
|
|
|
m_pKeepTerminated = m_pMenuView->addAction(CSandMan::GetIcon("Keep"), tr("Keep terminated"), this, SLOT(OnProcView()));
|
|
m_pKeepTerminated->setCheckable(true);
|
|
}
|
|
else {
|
|
m_pCleanUpMenu = NULL;
|
|
m_pCleanUpProcesses = NULL;
|
|
m_pCleanUpMsgLog = NULL;
|
|
m_pCleanUpTrace = NULL;
|
|
m_pCleanUpRecovery = NULL;
|
|
|
|
m_pKeepTerminated = NULL;
|
|
}
|
|
m_pMenuView->addSeparator();
|
|
m_pEnableMonitoring = m_pMenuView->addAction(CSandMan::GetIcon("SetLogging"), tr("Trace Logging"), this, SLOT(OnMonitoring()));
|
|
if (bAdvanced)
|
|
m_pEnableMonitoring->setCheckable(true);
|
|
if (!bAdvanced)
|
|
m_pMenuView->addAction(CSandMan::GetIcon("Recover"), tr("Recovery Log"), this, SLOT(OnRecoveryLog()));
|
|
|
|
|
|
m_pMenuOptions = m_pMenuBar->addMenu(tr("&Options"));
|
|
m_pMenuSettings = m_pMenuOptions->addAction(CSandMan::GetIcon("Settings"), tr("Global Settings"), this, SLOT(OnSettings()));
|
|
|
|
m_pMenuOptions->addSeparator();
|
|
m_pDisableForce = m_pMenuOptions->addAction(CSandMan::GetIcon("PauseForce"), tr("Pause Forcing Programs"), this, SLOT(OnDisableForce()));
|
|
m_pDisableForce->setCheckable(true);
|
|
m_pDisableForce2 = new QAction(CSandMan::GetIcon("PauseForce"), tr("Pause Forcing Programs"));
|
|
m_pDisableForce2->setCheckable(true);
|
|
connect(m_pDisableForce2, SIGNAL(triggered()), this, SLOT(OnDisableForce2()));
|
|
if(bAdvanced) {
|
|
m_pDisableRecovery = m_pMenuOptions->addAction(GetIcon("DisableRecovery"), tr("Disable File Recovery"), this, SLOT(OnDisablePopUp()));
|
|
m_pDisableRecovery->setCheckable(true);
|
|
m_pDisableRecovery->setChecked(theConf->GetBool("UIConfig/DisabledRecovery", false));
|
|
m_pDisableMessages = m_pMenuOptions->addAction(GetIcon("DisableMessagePopup"), tr("Disable Message Popup"), this, SLOT(OnDisablePopUp()));
|
|
m_pDisableMessages->setCheckable(true);
|
|
m_pDisableMessages->setChecked(theConf->GetBool("UIConfig/DisableMessages", false));
|
|
}
|
|
else {
|
|
m_pDisableRecovery = NULL;
|
|
m_pDisableMessages = NULL;
|
|
}
|
|
|
|
m_pMenuOptions->addSeparator();
|
|
m_pEditIni = m_pMenuOptions->addAction(CSandMan::GetIcon("Editor"), tr("Edit Sandboxie.ini"), this, SLOT(OnEditIni()));
|
|
m_pEditIni->setProperty("ini", "sbie");
|
|
if (bAdvanced) {
|
|
m_pEditIni2 = m_pMenuOptions->addAction(CSandMan::GetIcon("Editor2"), tr("Edit Templates.ini"), this, SLOT(OnEditIni()));
|
|
m_pEditIni2->setProperty("ini", "tmpl");
|
|
m_pEditIni3 = m_pMenuOptions->addAction(CSandMan::GetIcon("Editor4"), tr("Edit Sandboxie-Plus.ini"), this, SLOT(OnEditIni()));
|
|
m_pEditIni3->setProperty("ini", "plus");
|
|
} else
|
|
m_pEditIni2 = m_pEditIni3 = NULL;
|
|
m_pReloadIni = m_pMenuOptions->addAction(CSandMan::GetIcon("ReloadIni"), tr("Reload configuration"), this, SLOT(OnReloadIni()));
|
|
|
|
m_pMenuOptions->addSeparator();
|
|
m_pMenuResetMsgs = m_pMenuOptions->addAction(tr("Reset all hidden messages"), this, SLOT(OnResetMsgs()));
|
|
m_pMenuResetGUI = m_pMenuOptions->addAction(tr("Reset all GUI options"), this, SLOT(OnResetGUI()));
|
|
m_pMenuResetGUI->setShortcut(QKeySequence("Ctrl+Shift+R"));
|
|
m_pMenuResetGUI->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
|
this->addAction(m_pMenuResetGUI);
|
|
|
|
CreateHelpMenu(bAdvanced);
|
|
|
|
// for old menu
|
|
m_pSandbox = NULL;
|
|
}
|
|
|
|
void CSandMan::CreateOldMenus()
|
|
{
|
|
m_pMenuBar->clear();
|
|
|
|
m_pMenuFile = m_pMenuBar->addMenu(tr("&File"));
|
|
m_pRunBoxed = m_pMenuFile->addAction(CSandMan::GetIcon("Run"), tr("Run Sandboxed"), this, SLOT(OnSandBoxAction()));
|
|
m_pEmptyAll = m_pMenuFile->addAction(CSandMan::GetIcon("EmptyAll"), tr("Terminate All Processes"), this, SLOT(OnEmptyAll()));
|
|
m_pDisableForce = m_pMenuFile->addAction(CSandMan::GetIcon("PauseForce"), tr("Pause Forcing Programs"), this, SLOT(OnDisableForce()));
|
|
m_pDisableForce->setCheckable(true);
|
|
m_pDisableForce2 = new QAction(CSandMan::GetIcon("PauseForce"), tr("Pause Forcing Programs"));
|
|
m_pDisableForce2->setCheckable(true);
|
|
connect(m_pDisableForce2, SIGNAL(triggered()), this, SLOT(OnDisableForce2()));
|
|
//m_pDisableRecovery = m_pMenuFile->addAction(tr("Disable File Recovery"));
|
|
//m_pDisableRecovery->setCheckable(true);
|
|
m_pDisableRecovery = NULL;
|
|
//m_pDisableMessages = m_pMenuFile->addAction(tr("Disable Message Popup"));
|
|
//m_pDisableMessages->setCheckable(true);
|
|
m_pDisableMessages = NULL;
|
|
m_pMenuFile->addSeparator();
|
|
m_pWndFinder = m_pMenuFile->addAction(CSandMan::GetIcon("finder"), tr("Is Window Sandboxed?"), this, SLOT(OnWndFinder()));
|
|
m_pEnableMonitoring = m_pMenuFile->addAction(CSandMan::GetIcon("SetLogging"), tr("Resource Access Monitor"), this, SLOT(OnMonitoring()));
|
|
|
|
m_pMenuFile->addSeparator();
|
|
|
|
if(theGUI->IsFullyPortable())
|
|
CreateMaintenanceMenu();
|
|
else {
|
|
m_pMaintenance = NULL;
|
|
m_pConnect = NULL;
|
|
m_pDisconnect = NULL;
|
|
m_pMaintenanceItems = NULL;
|
|
m_pInstallDrv = NULL;
|
|
m_pStartDrv = NULL;
|
|
m_pStopDrv = NULL;
|
|
m_pUninstallDrv = NULL;
|
|
m_pInstallSvc = NULL;
|
|
m_pStartSvc = NULL;
|
|
m_pStopSvc = NULL;
|
|
m_pUninstallSvc = NULL;
|
|
m_pStopAll = NULL;
|
|
m_pUninstallAll = NULL;
|
|
m_pSetupWizard = NULL;
|
|
//m_pUpdateCore = NULL;
|
|
}
|
|
|
|
m_pExit = m_pMenuFile->addAction(CSandMan::GetIcon("Exit"), tr("Exit"), this, SLOT(OnExit()));
|
|
|
|
m_pMenuView = m_pMenuBar->addMenu(tr("&View"));
|
|
|
|
CreateViewBaseMenu();
|
|
|
|
m_pMenuView->addSeparator();
|
|
QActionGroup* m_pView = new QActionGroup(m_pMenuView);
|
|
MakeAction(m_pView, m_pMenuView, tr("Programs"), 0);
|
|
MakeAction(m_pView, m_pMenuView, tr("Files and Folders"), 1);
|
|
m_pView->actions().first()->setChecked(true);
|
|
connect(m_pView, SIGNAL(triggered(QAction*)), this, SLOT(OnView(QAction*)));
|
|
m_pMenuView->addSeparator();
|
|
m_pMenuView->addAction(CSandMan::GetIcon("Recover"), tr("Recovery Log"), this, SLOT(OnRecoveryLog()));
|
|
|
|
m_pMenuBrowse = NULL;
|
|
//m_pMenuView->addSeparator();
|
|
//m_pRefreshAll = m_pMenuView->addAction(CSandMan::GetIcon("Refresh"), tr("Refresh View"), this, SLOT(OnRefresh()));
|
|
//m_pRefreshAll->setShortcut(QKeySequence("F5"));
|
|
//m_pRefreshAll->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
|
//this->addAction(m_pRefreshAll);
|
|
m_pRefreshAll = NULL;
|
|
|
|
m_pCleanUpMenu = NULL;
|
|
m_pCleanUpProcesses = NULL;
|
|
m_pCleanUpMsgLog = NULL;
|
|
m_pCleanUpTrace = NULL;
|
|
m_pCleanUpRecovery = NULL;
|
|
m_pKeepTerminated = NULL;
|
|
|
|
m_pSandbox = m_pMenuBar->addMenu(tr("&Sandbox"));
|
|
|
|
connect(m_pSandbox, SIGNAL(hovered(QAction*)), this, SLOT(OnBoxMenuHover(QAction*)));
|
|
|
|
m_pSandbox->addSeparator();
|
|
m_pNewBox = m_pSandbox->addAction(CSandMan::GetIcon("NewBox"), tr("Create New Sandbox"), this, SLOT(OnSandBoxAction()));
|
|
m_pNewGroup = m_pSandbox->addAction(CSandMan::GetIcon("Group"), tr("Create New Group"), this, SLOT(OnSandBoxAction()));
|
|
m_pImportBox = m_pSandbox->addAction(CSandMan::GetIcon("UnPackBox"), tr("Import Sandbox"), this, SLOT(OnSandBoxAction()));
|
|
|
|
QAction* m_pSetContainer = m_pSandbox->addAction(CSandMan::GetIcon("Advanced"), tr("Set Container Folder"), this, SLOT(OnSettingsAction()));
|
|
m_pSetContainer->setData(CSettingsWindow::eAdvanced);
|
|
|
|
m_pArrangeGroups = m_pSandbox->addAction(tr("Set Layout and Groups"), this, SLOT(OnSettingsAction()));
|
|
|
|
m_pShowHidden = m_pSandbox->addAction(tr("Reveal Hidden Boxes"));
|
|
m_pShowHidden->setCheckable(true);
|
|
//m_pShowAllSessions = m_pSandbox->addAction(tr("Show Boxes From All Sessions"), this, SLOT(OnProcView()));
|
|
//m_pShowAllSessions->setCheckable(true);
|
|
m_pShowAllSessions = NULL;
|
|
|
|
m_pMenuOptions = m_pMenuBar->addMenu(tr("&Configure"));
|
|
m_pMenuSettings = m_pMenuOptions->addAction(CSandMan::GetIcon("Settings"), tr("Global Settings"), this, SLOT(OnSettings()));
|
|
m_pMenuOptions->addSeparator();
|
|
|
|
QAction* m_pProgramAlert = m_pMenuOptions->addAction(CSandMan::GetIcon("Alarm"), tr("Program Alerts"), this, SLOT(OnSettingsAction()));
|
|
m_pProgramAlert->setData(CSettingsWindow::eProgCtrl);
|
|
QAction* m_pWindowsShell = m_pMenuOptions->addAction(CSandMan::GetIcon("Shell"), tr("Windows Shell Integration"), this, SLOT(OnSettingsAction()));
|
|
m_pWindowsShell->setData(CSettingsWindow::eShell);
|
|
QAction* m_pCompatibility = m_pMenuOptions->addAction(CSandMan::GetIcon("Compatibility"), tr("Software Compatibility"), this, SLOT(OnSettingsAction()));
|
|
m_pCompatibility->setData(CSettingsWindow::eSoftCompat);
|
|
|
|
m_pMenuResetMsgs = m_pMenuOptions->addAction(tr("Reset all hidden messages"), this, SLOT(OnResetMsgs()));
|
|
m_pMenuResetGUI = m_pMenuOptions->addAction(tr("Reset all GUI options"), this, SLOT(OnResetGUI()));
|
|
m_pMenuResetGUI->setShortcut(QKeySequence("Ctrl+Shift+R"));
|
|
m_pMenuResetGUI->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
|
this->addAction(m_pMenuResetGUI);
|
|
m_pMenuOptions->addSeparator();
|
|
QAction* m_pConfigLock = m_pMenuOptions->addAction(CSandMan::GetIcon("Lock"), tr("Lock Configuration"), this, SLOT(OnSettingsAction()));
|
|
m_pConfigLock->setData(CSettingsWindow::eConfigLock);
|
|
m_pEditIni = m_pMenuOptions->addAction(CSandMan::GetIcon("Editor"), tr("Edit Sandboxie.ini"), this, SLOT(OnEditIni()));
|
|
m_pEditIni->setProperty("ini", "sbie");
|
|
m_pEditIni2 = m_pEditIni3 = NULL;
|
|
m_pReloadIni = m_pMenuOptions->addAction(CSandMan::GetIcon("ReloadIni"), tr("Reload configuration"), this, SLOT(OnReloadIni()));
|
|
|
|
CreateHelpMenu(false);
|
|
|
|
}
|
|
|
|
void CSandMan::OnView(QAction* pAction)
|
|
{
|
|
int iView = pAction->data().toInt();
|
|
if(m_pViewStack) m_pViewStack->setCurrentIndex(iView);
|
|
|
|
if (iView == 1) { // files
|
|
m_pBoxCombo->clear();
|
|
foreach(const CSandBoxPtr & pBox, theAPI->GetAllBoxes())
|
|
m_pBoxCombo->addItem(tr("Sandbox %1").arg(pBox->GetName().replace("_", "")), pBox->GetName());
|
|
m_pBoxCombo->setCurrentIndex(m_pBoxCombo->findData(theAPI->GetGlobalSettings()->GetText("DefaultBox", "DefaultBox")));
|
|
}
|
|
}
|
|
|
|
void CSandMan::SetToolBarItemsConfig(const QSet<QString>& items)
|
|
{
|
|
QStringList list;
|
|
for (auto item : items) list.append(item);
|
|
theConf->SetValue(ToolBarConfigKey, list);
|
|
}
|
|
|
|
QSet<QString> CSandMan::GetToolBarItemsConfig()
|
|
{
|
|
auto list = theConf->GetStringList(ToolBarConfigKey, DefaultToolBarItems);
|
|
|
|
QSet<QString> validSet;
|
|
|
|
for (auto item : GetAvailableToolBarActions()) {
|
|
if (!item.scriptName.isEmpty()) validSet.insert(item.scriptName);
|
|
}
|
|
|
|
// remove invalid and obsolete items
|
|
QSet<QString> items;
|
|
for (auto item : list) {
|
|
auto trimmed = item.trimmed();
|
|
if (validSet.contains(trimmed))
|
|
items.insert(trimmed);
|
|
else
|
|
// m_pMessageLog exists, but UI does not
|
|
// AddLogMessage(tr("Invalid toolbar item in sandboxie-plus.ini: %1").arg(item));
|
|
;
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
QList<ToolBarAction> CSandMan::GetAvailableToolBarActions()
|
|
{
|
|
// Assumes Advanced-Mode and (menu-)actions have been created.
|
|
// Return items in toolbar display order
|
|
|
|
return QList<ToolBarAction> {
|
|
ToolBarAction{ "NewBoxMenu", nullptr, tr("New-Box Menu") }, //tr: Name of button in toolbar for showing actions new box, new group, import},
|
|
ToolBarAction{ "NewBox", m_pNewBox },
|
|
ToolBarAction{ "NewGroup", m_pNewGroup },
|
|
ToolBarAction{ "ImportBox", m_pImportBox },
|
|
ToolBarAction{ "", nullptr }, // separator
|
|
ToolBarAction{ "RunBoxed", m_pRunBoxed },
|
|
ToolBarAction{ "IsBoxed", m_pWndFinder },
|
|
ToolBarAction{ "TerminateAll", m_pEmptyAll },
|
|
ToolBarAction{ "", nullptr }, // separator
|
|
ToolBarAction{ "CleanUpMenu", nullptr, tr("Cleanup") }, //tr: Name of button in toolbar for cleanup-all action
|
|
ToolBarAction{ "KeepTerminated", m_pKeepTerminated },
|
|
ToolBarAction{ "Refresh", m_pRefreshAll },
|
|
ToolBarAction{ "", nullptr }, // separator
|
|
ToolBarAction{ "BrowseFiles", m_pMenuBrowse },
|
|
ToolBarAction{ "", nullptr }, // separator
|
|
ToolBarAction{ "Settings", m_pMenuSettings },
|
|
ToolBarAction{ "", nullptr }, // separator
|
|
ToolBarAction{ "EditIniMenu", nullptr, tr("Edit-ini Menu") }, //tr: Name of button in toolbar for showing edit-ini files actions},
|
|
ToolBarAction{ "EditIni", m_pEditIni },
|
|
ToolBarAction{ "EditTemplates", m_pEditIni2 },
|
|
ToolBarAction{ "EditPlusIni", m_pEditIni3 },
|
|
ToolBarAction{ "ReloadIni", m_pReloadIni },
|
|
ToolBarAction{ "", nullptr }, // separator
|
|
ToolBarAction{ "EnableMonitor", m_pEnableMonitoring },
|
|
ToolBarAction{ "", nullptr }, // separator
|
|
ToolBarAction{ "DisableForce", m_pDisableForce2},
|
|
ToolBarAction{ "DisableRecovery", m_pDisableRecovery },
|
|
ToolBarAction{ "DisableMessages", m_pDisableMessages },
|
|
ToolBarAction{ "", nullptr }, // separator
|
|
ToolBarAction{ "Connect", m_pConnect },
|
|
ToolBarAction{ "Disconnect", m_pDisconnect },
|
|
ToolBarAction{ "StopAll", m_pStopAll },
|
|
// ToolBarAction{"SetupWizard", m_pSetupWizard},
|
|
// ToolBarAction{"UninstallAll", m_pUninstallAll}, // removed because not always valid in menu system
|
|
ToolBarAction{ "", nullptr }, // separator
|
|
ToolBarAction{ "CheckForUpdates", m_pUpdate },
|
|
ToolBarAction{ "About", m_pAbout },
|
|
ToolBarAction{ "", nullptr }, // separator
|
|
ToolBarAction{ "Exit", m_pExit },
|
|
ToolBarAction{ "", nullptr }, // separator
|
|
ToolBarAction{ "Contribute", m_pContribution }
|
|
};
|
|
}
|
|
|
|
void CSandMan::OnResetToolBarMenuConfig()
|
|
{
|
|
theConf->SetValue(ToolBarConfigKey, DefaultToolBarItems);
|
|
CreateToolBar(true);
|
|
}
|
|
|
|
void CSandMan::OnToolBarMenuItemClicked(const QString& scriptName)
|
|
{
|
|
// Toggles content of config. Ignores menu item state. Menu is immediately rebuilt with toolbar update.
|
|
auto items = GetToolBarItemsConfig();
|
|
if (!items.remove(scriptName)) items.insert(scriptName);
|
|
SetToolBarItemsConfig(items);
|
|
CreateToolBar(true);
|
|
}
|
|
|
|
void CSandMan::CreateToolBarConfigMenu(const QList<ToolBarAction>& actions, const QSet<QString>& currentItems)
|
|
{
|
|
auto m_pToolBarContextMenu = new QMenu(tr("Toolbar Items"), m_pToolBar);
|
|
|
|
m_pToolBarContextMenu->addAction(tr("Reset Toolbar"), this, &CSandMan::OnResetToolBarMenuConfig);
|
|
m_pToolBarContextMenu->addSeparator();
|
|
|
|
for (auto sa : actions)
|
|
{
|
|
if (sa.scriptName == nullptr) {
|
|
m_pToolBarContextMenu->addSeparator();
|
|
continue;
|
|
}
|
|
|
|
QString text = sa.scriptName;
|
|
if (!sa.nameOverride.isEmpty())
|
|
text = sa.nameOverride;
|
|
else if (sa.action)
|
|
text = sa.action->text(); // tr: already localised
|
|
else
|
|
qDebug() << "ERROR: Missing display name for " << sa.scriptName;
|
|
|
|
auto scriptName = sa.scriptName;
|
|
auto menuAction = m_pToolBarContextMenu->addAction(text, this, [scriptName, this]() {
|
|
OnToolBarMenuItemClicked(scriptName);
|
|
}
|
|
);
|
|
menuAction->setCheckable(true);
|
|
menuAction->setChecked(currentItems.contains(sa.scriptName));
|
|
}
|
|
|
|
m_pToolBar->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
QObject::connect(m_pToolBar, &QToolBar::customContextMenuRequested, this,
|
|
[m_pToolBarContextMenu, this](const QPoint& p) {
|
|
m_pToolBarContextMenu->exec(mapToGlobal(p));
|
|
}
|
|
);
|
|
}
|
|
|
|
void CSandMan::CreateToolBar(bool rebuild)
|
|
{
|
|
// Assumes UI is in Advanced-Mode and menus have been built.
|
|
|
|
auto pOldToolBar = m_pToolBar;
|
|
m_pToolBar = new QToolBar();
|
|
m_pMainLayout->insertWidget(0, m_pToolBar);
|
|
if (rebuild) {
|
|
m_pLabel->deleteLater(); // should really be owned by m_pToolBar, not m_pMainWidget
|
|
m_pMainLayout->removeWidget(pOldToolBar);
|
|
pOldToolBar->deleteLater();
|
|
m_pNewBoxButton = nullptr; // deleted by pOldToolBar
|
|
m_pEditIniButton = nullptr;
|
|
m_pCleanUpButton = nullptr;
|
|
}
|
|
|
|
auto items = GetToolBarItemsConfig();
|
|
auto scriptableActions = GetAvailableToolBarActions();
|
|
CreateToolBarConfigMenu(scriptableActions, items);
|
|
|
|
// Prevent leading, trailing, or consecutive separators
|
|
bool needsSeparator = false; // true if we need to add a separator before the next action
|
|
bool latestIsAction = false; // true if the most recent toolbar item is not a separator
|
|
|
|
for (auto sa : scriptableActions)
|
|
{
|
|
if (sa.scriptName.isEmpty()) {
|
|
// only trigger if we just added an action
|
|
if (latestIsAction) needsSeparator = true;
|
|
continue;
|
|
}
|
|
|
|
if (!items.contains(sa.scriptName)) continue;
|
|
|
|
if (needsSeparator) {
|
|
m_pToolBar->addSeparator();
|
|
needsSeparator = false;
|
|
}
|
|
|
|
latestIsAction = true;
|
|
|
|
if (sa.action)
|
|
{
|
|
m_pToolBar->addAction(sa.action);
|
|
}
|
|
else if (sa.scriptName == "CleanUpMenu")
|
|
{
|
|
auto but = new QToolButton();
|
|
but->setIcon(CSandMan::GetIcon("Clean"));
|
|
but->setToolTip(tr("Cleanup"));
|
|
but->setText(tr("Cleanup"));
|
|
but->setPopupMode(QToolButton::MenuButtonPopup);
|
|
but->setMenu(m_pCleanUpMenu);
|
|
QObject::connect(but, SIGNAL(clicked(bool)), this, SLOT(OnCleanUp()));
|
|
m_pCleanUpButton = but;
|
|
m_pToolBar->addWidget(but);
|
|
}
|
|
else if (sa.scriptName == "NewBoxMenu")
|
|
{
|
|
auto but = new QToolButton();
|
|
but->setIcon(CSandMan::GetIcon("NewBox"));
|
|
but->setToolTip(tr("Create New Box"));
|
|
but->setText(tr("Create New Box"));
|
|
but->setPopupMode(QToolButton::MenuButtonPopup);
|
|
auto menu = new QMenu(but);
|
|
menu->addAction(m_pNewBox);
|
|
menu->addAction(m_pNewGroup);
|
|
menu->addAction(m_pImportBox);
|
|
but->setMenu(menu);
|
|
QObject::connect(but, &QToolButton::clicked, this, [this]() {GetBoxView()->AddNewBox();});
|
|
m_pNewBoxButton = but;
|
|
m_pToolBar->addWidget(but);
|
|
}
|
|
else if (sa.scriptName == "EditIniMenu")
|
|
{
|
|
auto but = new QToolButton();
|
|
but->setIcon(CSandMan::GetIcon("Editor"));
|
|
but->setToolTip(tr("Edit Sandboxie.ini"));
|
|
but->setText(tr("Edit Sandboxie.ini"));
|
|
but->setPopupMode(QToolButton::MenuButtonPopup);
|
|
auto menu = new QMenu(but);
|
|
menu->addAction(m_pEditIni);
|
|
menu->addAction(m_pEditIni2);
|
|
menu->addAction(m_pEditIni3);
|
|
but->setMenu(menu);
|
|
QObject::connect(but, &QToolButton::clicked, this, [this]() {OnEditIni();});
|
|
m_pEditIniButton = but;
|
|
m_pToolBar->addWidget(but);
|
|
}
|
|
else
|
|
{
|
|
qDebug() << "ERROR: You forgot to handle ToolBarAction scriptName " << sa.scriptName;
|
|
}
|
|
}
|
|
|
|
// Contribute-Label
|
|
|
|
QWidget* pSpacer = new QWidget();
|
|
pSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
m_pToolBar->addWidget(pSpacer);
|
|
|
|
//m_pToolBar->addAction(m_pMenuElevate);
|
|
|
|
m_pSeparator = m_pToolBar->addSeparator();
|
|
CreateLabel();
|
|
m_pToolBar->addWidget(m_pLabel);
|
|
UpdateLabel();
|
|
}
|
|
|
|
void CSandMan::CreateLabel()
|
|
{
|
|
m_pLabel = new QLabel(m_pMainWidget);
|
|
m_pLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
|
connect(m_pLabel, SIGNAL(linkActivated(const QString&)), this, SLOT(OpenUrl(const QString&)));
|
|
|
|
m_pLabel->setAlignment(Qt::AlignCenter);
|
|
m_pLabel->setContentsMargins(24, 0, 24, 0);
|
|
|
|
QFont fnt = m_pLabel->font();
|
|
fnt.setBold(true);
|
|
//fnt.setWeight(QFont::DemiBold);
|
|
m_pLabel->setFont(fnt);
|
|
}
|
|
|
|
void CSandMan::UpdateLabel()
|
|
{
|
|
QString LabelText;
|
|
QString LabelTip;
|
|
|
|
if (!theConf->GetString("Updater/PendingUpdate").isEmpty())
|
|
{
|
|
QString FilePath = theConf->GetString("Updater/InstallerPath");
|
|
if (!FilePath.isEmpty() && QFile::exists(FilePath)) {
|
|
LabelText = tr("<a href=\"sbie://update/installer\" style=\"color: red;\">There is a new Sandboxie-Plus release %1 ready</a>").arg(theConf->GetString("Updater/InstallerVersion"));
|
|
LabelTip = tr("Click to run installer");
|
|
}
|
|
else if (!theConf->GetString("Updater/UpdateVersion").isEmpty()){
|
|
LabelText = tr("<a href=\"sbie://update/apply\" style=\"color: red;\">There is a new Sandboxie-Plus update %1 ready</a>").arg(theConf->GetString("Updater/UpdateVersion"));
|
|
LabelTip = tr("Click to apply update");
|
|
}
|
|
else {
|
|
LabelText = tr("<a href=\"sbie://update/check\" style=\"color: red;\">There is a new Sandboxie-Plus update v%1 available</a>").arg(theConf->GetString("Updater/PendingUpdate"));
|
|
LabelTip = tr("Click to download update");
|
|
}
|
|
|
|
//auto neon = new CNeonEffect(10, 4, 180); // 140
|
|
//m_pLabel->setGraphicsEffect(NULL);
|
|
}
|
|
else if (g_Certificate.isEmpty())
|
|
{
|
|
LabelText = tr("<a href=\"https://sandboxie-plus.com/go.php?to=patreon\">Support Sandboxie-Plus on Patreon</a>");
|
|
LabelTip = tr("Click to open web browser");
|
|
|
|
//auto neon = new CNeonEffect(10, 4, 240);
|
|
auto neon = new CNeonEffect(10, 4);
|
|
//neon->setGlowColor(Qt::green);
|
|
neon->setHue(240);
|
|
/*if(m_DarkTheme)
|
|
neon->setColor(QColor(218, 130, 42));
|
|
else
|
|
neon->setColor(Qt::blue);*/
|
|
m_pLabel->setGraphicsEffect(neon);
|
|
|
|
/*auto glowAni = new QVariantAnimation(neon);
|
|
glowAni->setDuration(10000);
|
|
glowAni->setLoopCount(-1);
|
|
glowAni->setStartValue(0);
|
|
glowAni->setEndValue(360);
|
|
glowAni->setEasingCurve(QEasingCurve::InQuad);
|
|
connect(glowAni, &QVariantAnimation::valueChanged, [neon](const QVariant &value) {
|
|
neon->setHue(value.toInt());
|
|
qDebug() << value.toInt();
|
|
});
|
|
glowAni->start();*/
|
|
|
|
/*auto glowAni = new QVariantAnimation(neon);
|
|
glowAni->setDuration(3000);
|
|
glowAni->setLoopCount(-1);
|
|
glowAni->setStartValue(5);
|
|
glowAni->setEndValue(20);
|
|
glowAni->setEasingCurve(QEasingCurve::InQuad);
|
|
connect(glowAni, &QVariantAnimation::valueChanged, [neon](const QVariant &value) {
|
|
neon->setBlurRadius(value.toInt());
|
|
qDebug() << value.toInt();
|
|
});
|
|
glowAni->start();*/
|
|
|
|
/*auto glowAni = new QVariantAnimation(neon);
|
|
glowAni->setDuration(3000);
|
|
glowAni->setLoopCount(-1);
|
|
glowAni->setStartValue(1);
|
|
glowAni->setEndValue(20);
|
|
glowAni->setEasingCurve(QEasingCurve::InQuad);
|
|
connect(glowAni, &QVariantAnimation::valueChanged, [neon](const QVariant &value) {
|
|
neon->setGlow(value.toInt());
|
|
qDebug() << value.toInt();
|
|
});
|
|
glowAni->start();*/
|
|
|
|
/*auto glowAni = new QVariantAnimation(neon);
|
|
glowAni->setDuration(3000);
|
|
glowAni->setLoopCount(-1);
|
|
glowAni->setStartValue(5);
|
|
glowAni->setEndValue(25);
|
|
glowAni->setEasingCurve(QEasingCurve::InQuad);
|
|
connect(glowAni, &QVariantAnimation::valueChanged, [neon](const QVariant &value) {
|
|
int iValue = value.toInt();
|
|
if (iValue >= 15)
|
|
iValue = 30 - iValue;
|
|
neon->setGlow(iValue);
|
|
neon->setBlurRadius(iValue);
|
|
});
|
|
glowAni->start();*/
|
|
|
|
}
|
|
|
|
if(m_pSeparator) m_pSeparator->setVisible(!LabelText.isEmpty());
|
|
m_pLabel->setVisible(!LabelText.isEmpty());
|
|
m_pLabel->setText(LabelText);
|
|
m_pLabel->setToolTip(LabelTip);
|
|
}
|
|
|
|
void CSandMan::CreateView(int iViewMode)
|
|
{
|
|
m_pBoxView = new CSbieView();
|
|
connect(m_pBoxView, SIGNAL(BoxSelected()), this, SLOT(OnBoxSelected()));
|
|
m_pFileView = new CFileView();
|
|
|
|
if (iViewMode != 1) {
|
|
m_pRecoveryLogWnd = new CRecoveryLogWnd(m_pMainWidget);
|
|
connect(this, SIGNAL(Closed()), m_pRecoveryLogWnd, SLOT(close()));
|
|
}
|
|
else
|
|
m_pRecoveryLogWnd = NULL;
|
|
|
|
if (iViewMode == 2)
|
|
{
|
|
m_pViewStack = new QStackedLayout();
|
|
m_pViewStack->addWidget(m_pBoxView);
|
|
|
|
QWidget* pFileView = new QWidget();
|
|
QGridLayout* pFileLayout = new QGridLayout(pFileView);
|
|
pFileLayout->setContentsMargins(0,0,0,0);
|
|
|
|
pFileLayout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 0, 1, 1);
|
|
|
|
m_pBoxCombo = new QComboBox();
|
|
connect(m_pBoxCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnBoxSelected()));
|
|
pFileLayout->addWidget(m_pBoxCombo, 0, 1);
|
|
|
|
pFileLayout->addWidget(m_pFileView, 1, 0, 1, 2);
|
|
|
|
m_pViewStack->addWidget(pFileView);
|
|
|
|
|
|
m_pMainLayout->addLayout(m_pViewStack);
|
|
|
|
m_pPanelSplitter = NULL;
|
|
m_pLogSplitter = NULL;
|
|
|
|
m_pLogTabs = NULL;
|
|
|
|
m_pMessageLog = NULL;
|
|
m_pTraceView = NULL;
|
|
m_pRecoveryLog = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
m_pViewStack = NULL;
|
|
m_pBoxCombo = NULL;
|
|
|
|
if (iViewMode == 1)
|
|
{
|
|
m_pLogSplitter = new QSplitter();
|
|
m_pLogSplitter->setOrientation(Qt::Vertical);
|
|
m_pMainLayout->addWidget(m_pLogSplitter);
|
|
}
|
|
|
|
m_pPanelSplitter = new QSplitter();
|
|
m_pPanelSplitter->setOrientation(Qt::Horizontal);
|
|
if (iViewMode == 1)
|
|
m_pLogSplitter->addWidget(m_pPanelSplitter);
|
|
else
|
|
m_pMainLayout->addWidget(m_pPanelSplitter);
|
|
|
|
m_pPanelSplitter->addWidget(m_pBoxView);
|
|
m_pPanelSplitter->addWidget(m_pFileView);
|
|
|
|
m_pPanelSplitter->setCollapsible(0, false);
|
|
//m_pPanelSplitter->setCollapsible(1, false);
|
|
|
|
if (iViewMode == 1)
|
|
{
|
|
m_pLogTabs = new QTabWidget();
|
|
m_pLogSplitter->addWidget(m_pLogTabs);
|
|
|
|
// Message Log
|
|
m_pMessageLog = new CPanelWidgetEx();
|
|
m_pMessageLog->GetTree()->setItemDelegate(new CTreeItemDelegate());
|
|
|
|
m_pMessageLog->GetTree()->setAlternatingRowColors(theConf->GetBool("Options/AltRowColors", false));
|
|
|
|
//m_pMessageLog->GetView()->setItemDelegate(theGUI->GetItemDelegate());
|
|
((QTreeWidgetEx*)m_pMessageLog->GetView())->setHeaderLabels(tr("Time|Message").split("|"));
|
|
((QTreeWidgetEx*)m_pMessageLog->GetView())->setColumnFixed(1, true);
|
|
|
|
m_pMessageLog->GetMenu()->insertAction(m_pMessageLog->GetMenu()->actions()[0], m_pCleanUpMsgLog);
|
|
m_pMessageLog->GetMenu()->insertSeparator(m_pMessageLog->GetMenu()->actions()[0]);
|
|
|
|
m_pMessageLog->GetView()->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
m_pMessageLog->GetView()->setSortingEnabled(false);
|
|
|
|
m_pLogTabs->addTab(m_pMessageLog, tr("Sbie Messages"));
|
|
//
|
|
|
|
m_pTraceView = new CTraceView(false, this);
|
|
|
|
m_pTraceView->AddAction(m_pCleanUpTrace);
|
|
|
|
m_pLogTabs->addTab(m_pTraceView, tr("Trace Log"));
|
|
|
|
|
|
// Recovery Log
|
|
m_pRecoveryLog = new CPanelWidgetEx();
|
|
m_pRecoveryLog->GetTree()->setItemDelegate(new CTreeItemDelegate());
|
|
|
|
m_pRecoveryLog->GetTree()->setAlternatingRowColors(theConf->GetBool("Options/AltRowColors", false));
|
|
|
|
//m_pRecoveryLog->GetView()->setItemDelegate(theGUI->GetItemDelegate());
|
|
((QTreeWidgetEx*)m_pRecoveryLog->GetView())->setHeaderLabels(tr("Time|Box Name|File Path").split("|"));
|
|
((QTreeWidgetEx*)m_pRecoveryLog->GetView())->setColumnFixed(1, true);
|
|
((QTreeWidgetEx*)m_pRecoveryLog->GetView())->setColumnFixed(2, true);
|
|
|
|
m_pRecoveryLog->GetMenu()->insertAction(m_pRecoveryLog->GetMenu()->actions()[0], m_pCleanUpRecovery);
|
|
m_pRecoveryLog->GetMenu()->insertSeparator(m_pRecoveryLog->GetMenu()->actions()[0]);
|
|
|
|
m_pRecoveryLog->GetView()->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
m_pRecoveryLog->GetView()->setSortingEnabled(false);
|
|
|
|
m_pLogTabs->addTab(m_pRecoveryLog, tr("Recovery Log"));
|
|
//
|
|
}
|
|
else {
|
|
m_pLogSplitter = NULL;
|
|
|
|
m_pLogTabs = NULL;
|
|
|
|
m_pMessageLog = NULL;
|
|
m_pTraceView = NULL;
|
|
m_pRecoveryLog = NULL;
|
|
}
|
|
}
|
|
|
|
void CSandMan::CheckForUpdates(bool bManual)
|
|
{
|
|
m_pUpdater->CheckForUpdates(bManual);
|
|
}
|
|
|
|
#include "SandManTray.cpp"
|
|
|
|
void CSandMan::OnExit()
|
|
{
|
|
m_bExit = true;
|
|
close();
|
|
}
|
|
|
|
void CSandMan::closeEvent(QCloseEvent *e)
|
|
{
|
|
if (!m_bExit)// && !theAPI->IsConnected())
|
|
{
|
|
if (m_pTrayIcon->isVisible())
|
|
{
|
|
StoreState();
|
|
hide();
|
|
|
|
if (theAPI->GetGlobalSettings()->GetBool("ForgetPassword", false))
|
|
theAPI->ClearPassword();
|
|
|
|
e->ignore();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
CExitDialog ExitDialog(tr("Do you want to close Sandboxie Manager?"));
|
|
if (!ExitDialog.exec())
|
|
{
|
|
e->ignore();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
emit Closed();
|
|
|
|
if (IsFullyPortable() && theAPI->IsConnected())
|
|
{
|
|
int PortableStop = theConf->GetInt("Options/PortableStop", -1);
|
|
if (PortableStop == -1)
|
|
{
|
|
bool State = false;
|
|
auto Ret = CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Sandboxie-Plus was running in portable mode, now it has to clean up the created services. This will prompt for administrative privileges.\n\nDo you want to do the clean up?")
|
|
, tr("Don't show this message again."), &State, QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel, QDialogButtonBox::Yes, QMessageBox::Question);
|
|
|
|
if (Ret == QDialogButtonBox::Cancel)
|
|
{
|
|
e->ignore();
|
|
return;
|
|
}
|
|
|
|
PortableStop = (Ret == QDialogButtonBox::Yes) ? 1 : 0;
|
|
|
|
if (State)
|
|
theConf->SetValue("Options/PortableStop", PortableStop);
|
|
}
|
|
|
|
if (PortableStop == 1) {
|
|
SB_RESULT(void*) Status = StopSbie(true);
|
|
// don't care for Status we quit here anyway
|
|
}
|
|
}
|
|
|
|
QApplication::quit();
|
|
}
|
|
|
|
void CSandMan::commitData(QSessionManager& manager)
|
|
{
|
|
//if (manager.allowsInteraction())
|
|
//{
|
|
// manager.cancel();
|
|
// return;
|
|
//}
|
|
|
|
m_pBoxView->SaveState();
|
|
m_pFileView->SaveState();
|
|
StoreState();
|
|
theConf->Sync();
|
|
}
|
|
|
|
QIcon CSandMan::GetBoxIcon(int boxType, bool inUse)// , int iBusy)
|
|
{
|
|
//EBoxColors color = eYellow;
|
|
int iViewMode = theConf->GetInt("Options/ViewMode", 1);
|
|
if (iViewMode != 2) {
|
|
return GetColorIcon(m_BoxColors[boxType], inUse);
|
|
/*switch (boxType) {
|
|
case CSandBoxPlus::eHardenedPlus: color = eRed; break;
|
|
case CSandBoxPlus::eHardened: color = eOrang; break;
|
|
case CSandBoxPlus::eDefaultPlus: color = eBlue; break;
|
|
case CSandBoxPlus::eDefault: color = eYellow; break;
|
|
case CSandBoxPlus::eAppBoxPlus: color = eCyan; break;
|
|
case CSandBoxPlus::eAppBox: color = eGreen; break;
|
|
case CSandBoxPlus::eInsecure: color = eMagenta; break;
|
|
case CSandBoxPlus::eOpen: color = eWhite; break;
|
|
}*/
|
|
}
|
|
//if (inBusy)
|
|
// return m_BoxIcons[color].Busy;
|
|
/*if (inUse)
|
|
return m_BoxIcons[color].InUse;
|
|
return m_BoxIcons[color].Empty;*/
|
|
return GetColorIcon(m_BoxColors[CSandBoxPlus::eDefault], inUse);
|
|
}
|
|
|
|
QIcon CSandMan::GetColorIcon(QColor boxColor, bool inUse/*, bool bOut*/)
|
|
{
|
|
static QPixmap Sand;
|
|
if(Sand.isNull())
|
|
Sand = QPixmap(":/Boxes/Sand");
|
|
|
|
static QPixmap Frame;
|
|
if(Frame.isNull())
|
|
Frame = QPixmap(":/Boxes/Frame");
|
|
|
|
static QPixmap Items;
|
|
if(Items.isNull())
|
|
Items = QPixmap(":/Boxes/Items");
|
|
|
|
static QPixmap Out;
|
|
if(Out.isNull())
|
|
Out = QPixmap(":/Boxes/Out");
|
|
|
|
QRgb rgb = boxColor.rgba();
|
|
QImage MySand = Sand.toImage();
|
|
//if (!bOut) {
|
|
for (QRgb* c = (QRgb*)MySand.bits(); c != (QRgb*)(MySand.bits() + MySand.sizeInBytes()); c++) {
|
|
if (*c == 0xFFFFFFFF)
|
|
*c = rgb;
|
|
}
|
|
//}
|
|
|
|
QPixmap result(32, 32);
|
|
result.fill(Qt::transparent); // force alpha channel
|
|
QPainter painter(&result);
|
|
//if (bOut) {
|
|
// QImage MyOut = Out.toImage();
|
|
// for (QRgb* c = (QRgb*)MyOut.bits(); c != (QRgb*)(MyOut.bits() + MyOut.sizeInBytes()); c++) {
|
|
// *c = rgb;
|
|
// }
|
|
// painter.drawPixmap(0, 0, QPixmap::fromImage(MyOut));
|
|
//}
|
|
painter.drawPixmap(0, 0, QPixmap::fromImage(MySand));
|
|
painter.drawPixmap(0, 0, Frame);
|
|
if (inUse)
|
|
{
|
|
//rgb = change_hsv_c(rgb, -60, 2, 1); // yellow -> red
|
|
|
|
my_rgb rgb1 = { (double)qRed(rgb), (double)qGreen(rgb), (double)qBlue(rgb) };
|
|
my_hsv hsv = rgb2hsv(rgb1);
|
|
|
|
if((hsv.h >= 30 && hsv.h < 150) || (hsv.h >= 210 && hsv.h < 330)) hsv.h -= 60;
|
|
else if(hsv.h >= 150 && hsv.h < 210) hsv.h += 120;
|
|
else if((hsv.h >= 330 && hsv.h < 360) || (hsv.h >= 0 && hsv.h < 30)) hsv.h -= 240;
|
|
|
|
if (hsv.h < 0) hsv.h += 360;
|
|
else if (hsv.h >= 360) hsv.h -= 360;
|
|
hsv.s = 1; // make the content always fully saturated
|
|
|
|
my_rgb rgb2 = hsv2rgb(hsv);
|
|
rgb = qRgb(rgb2.r, rgb2.g, rgb2.b);
|
|
|
|
QImage MyItems = Items.toImage();
|
|
for (QRgb* c = (QRgb*)MyItems.bits(); c != (QRgb*)(MyItems.bits() + MyItems.sizeInBytes()); c++) {
|
|
if (*c == 0xFF000000)
|
|
*c = rgb;
|
|
}
|
|
painter.drawPixmap(0, 0, QPixmap::fromImage(MyItems));
|
|
}
|
|
|
|
return QIcon(result);
|
|
}
|
|
|
|
QIcon CSandMan::MakeIconBusy(const QIcon& Icon, int Index)
|
|
{
|
|
static QPixmap overlay;
|
|
if(overlay.isNull())
|
|
overlay = QPixmap(":/Boxes/Busy");
|
|
|
|
QPixmap base = Icon.pixmap(32, 32);
|
|
QPixmap result(base.width(), base.height());
|
|
result.fill(Qt::transparent); // force alpha channel
|
|
QPainter painter(&result);
|
|
painter.drawPixmap(0, 0, base);
|
|
|
|
QTransform rm;
|
|
rm.rotate(90 * (Index % 4));
|
|
painter.drawPixmap(8, 8, overlay.transformed(rm));
|
|
return QIcon(result);
|
|
}
|
|
|
|
QIcon CSandMan::IconAddOverlay(const QIcon& Icon, const QString& Name, int Size)
|
|
{
|
|
QPixmap overlay = QPixmap(Name).scaled(Size, Size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
|
|
|
QPixmap base = Icon.pixmap(32, 32).scaled(32, 32, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
|
QPixmap result(base.width(), base.height());
|
|
result.fill(Qt::transparent); // force alpha channel
|
|
QPainter painter(&result);
|
|
painter.drawPixmap(0, 0, base);
|
|
|
|
painter.drawPixmap(32 - Size, 32 - Size, overlay);
|
|
return QIcon(result);
|
|
}
|
|
|
|
QString CSandMan::GetBoxDescription(int boxType)
|
|
{
|
|
QString Info;
|
|
|
|
switch (boxType) {
|
|
case CSandBoxPlus::eHardenedPlus:
|
|
case CSandBoxPlus::eHardened:
|
|
Info = tr("This box provides <a href=\"sbie://docs/security-mode\">enhanced security isolation</a>, it is suitable to test untrusted software.");
|
|
break;
|
|
case CSandBoxPlus::eDefaultPlus:
|
|
case CSandBoxPlus::eDefault:
|
|
Info = tr("This box provides standard isolation, it is suitable to run your software to enhance security.");
|
|
break;
|
|
case CSandBoxPlus::eAppBoxPlus:
|
|
case CSandBoxPlus::eAppBox:
|
|
Info = tr("This box does not enforce isolation, it is intended to be used as an <a href=\"sbie://docs/compartment-mode\">application compartment</a> for software virtualization only.");
|
|
break;
|
|
}
|
|
|
|
if(boxType == CSandBoxPlus::eHardenedPlus || boxType == CSandBoxPlus::eDefaultPlus || boxType == CSandBoxPlus::eAppBoxPlus)
|
|
Info.append(tr("<br /><br />This box <a href=\"sbie://docs/privacy-mode\">prevents access to all user data</a> locations, except explicitly granted in the Resource Access options."));
|
|
|
|
return Info;
|
|
}
|
|
|
|
bool CSandMan::IsFullyPortable()
|
|
{
|
|
QString SbiePath = theAPI->GetSbiePath();
|
|
QString IniPath = theAPI->GetIniPath();
|
|
if (IniPath.indexOf(SbiePath, 0, Qt::CaseInsensitive) == 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool CSandMan::KeepTerminated()
|
|
{
|
|
if (CBoxEngine::GetInstanceCount() > 0)
|
|
return true;
|
|
return m_pKeepTerminated && m_pKeepTerminated->isChecked();
|
|
}
|
|
|
|
bool CSandMan::IsSilentMode()
|
|
{
|
|
if (!theConf->GetBool("Options/CheckSilentMode", true))
|
|
return false;
|
|
return IsFullScreenMode();
|
|
}
|
|
|
|
QWidget* g_GUIParent = NULL;
|
|
|
|
int CSandMan::SafeExec(QDialog* pDialog)
|
|
{
|
|
QWidget* pPrevParent = g_GUIParent;
|
|
g_GUIParent = pDialog;
|
|
SafeShow(pDialog);
|
|
int ret = pDialog->exec();
|
|
g_GUIParent = pPrevParent;
|
|
return ret;
|
|
}
|
|
|
|
void CSandMan::OnMessage(const QString& MsgData)
|
|
{
|
|
QStringList Messages = MsgData.split("\n");
|
|
QString Message = Messages[0];
|
|
if (Message == "ShowWnd")
|
|
{
|
|
if (!isVisible())
|
|
show();
|
|
setWindowState(Qt::WindowActive);
|
|
SetForegroundWindow(MainWndHandle);
|
|
}
|
|
else if (Message.left(4) == "Run:")
|
|
{
|
|
QString BoxName;
|
|
QString CmdLine = Message.mid(4);
|
|
|
|
if (CmdLine.contains("\\start.exe", Qt::CaseInsensitive)) {
|
|
int pos = CmdLine.indexOf("/box:", 0, Qt::CaseInsensitive);
|
|
int pos2 = CmdLine.indexOf(" ", pos);
|
|
if (pos != -1 && pos2 != -1) {
|
|
BoxName = CmdLine.mid(pos + 5, pos2 - (pos + 5));
|
|
CmdLine = CmdLine.mid(pos2 + 1);
|
|
}
|
|
}
|
|
|
|
QString WrkDir;
|
|
for (int i = 1; i < Messages.length(); i++) {
|
|
if (Messages[i].left(5) == "From:") {
|
|
WrkDir = Messages[i].mid(5);
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (int i = 1; i < Messages.length(); i++) {
|
|
if (Messages[i].left(3) == "In:") {
|
|
BoxName = Messages[i].mid(3);
|
|
break;
|
|
}
|
|
}
|
|
|
|
CSupportDialog::CheckSupport(true);
|
|
|
|
if (BoxName.isEmpty() && theConf->GetBool("Options/RunInDefaultBox", false) && (QGuiApplication::queryKeyboardModifiers() & Qt::ControlModifier) == 0)
|
|
BoxName = theAPI->GetGlobalSettings()->GetText("DefaultBox", "DefaultBox");
|
|
|
|
if (!BoxName.isEmpty())
|
|
RunStart(BoxName, CmdLine, false, WrkDir);
|
|
else
|
|
RunSandboxed(QStringList(CmdLine), BoxName, WrkDir);
|
|
}
|
|
else if (Message.left(3) == "Op:")
|
|
{
|
|
QString Op = Message.mid(3);
|
|
|
|
SB_RESULT(void*) Status;
|
|
if (Op == "Connect")
|
|
Status = ConnectSbie();
|
|
else if (Op == "Disconnect")
|
|
Status = DisconnectSbie();
|
|
else if (Op == "Shutdown")
|
|
Status = StopSbie();
|
|
else if (Op == "EmptyAll")
|
|
Status = theAPI->TerminateAll();
|
|
else
|
|
Status = SB_ERR(SB_Message, QVariantList () << (tr("Unknown operation '%1' requested via command line").arg(Op)));
|
|
|
|
HandleMaintenance(Status);
|
|
}
|
|
}
|
|
|
|
void CSandMan::dragEnterEvent(QDragEnterEvent* e)
|
|
{
|
|
if (e->mimeData()->hasUrls()) {
|
|
e->acceptProposedAction();
|
|
}
|
|
}
|
|
|
|
bool CSandMan::RunSandboxed(const QStringList& Commands, QString BoxName, const QString& WrkDir)
|
|
{
|
|
if (BoxName.isEmpty())
|
|
BoxName = theAPI->GetGlobalSettings()->GetText("DefaultBox", "DefaultBox");
|
|
CSelectBoxWindow* pSelectBoxWindow = new CSelectBoxWindow(Commands, BoxName, WrkDir, g_GUIParent);
|
|
connect(this, SIGNAL(Closed()), pSelectBoxWindow, SLOT(close()));
|
|
//pSelectBoxWindow->show();
|
|
return SafeExec(pSelectBoxWindow) == 1;
|
|
}
|
|
|
|
SB_RESULT(quint32) CSandMan::RunStart(const QString& BoxName, const QString& Command, bool Elevated, const QString& WorkingDir, QProcess* pProcess)
|
|
{
|
|
auto pBoxEx = theAPI->GetBoxByName(BoxName).objectCast<CSandBoxPlus>();
|
|
|
|
return theAPI->RunStart(BoxName, Command, Elevated, WorkingDir, pProcess);
|
|
}
|
|
|
|
void CSandMan::dropEvent(QDropEvent* e)
|
|
{
|
|
QStringList Commands;
|
|
foreach(const QUrl & url, e->mimeData()->urls()) {
|
|
if (url.isLocalFile())
|
|
Commands.append(url.toLocalFile().replace("/", "\\"));
|
|
}
|
|
|
|
QString BoxName;
|
|
QList<CSandBoxPtr> Boxes = m_pBoxView->GetSelectedBoxes();
|
|
if (Boxes.count() == 1)
|
|
BoxName = Boxes.first()->GetName();
|
|
|
|
QTimer::singleShot(0, this, [Commands, BoxName, this]() { RunSandboxed(Commands, BoxName); });
|
|
}
|
|
|
|
void CSandMan::timerEvent(QTimerEvent* pEvent)
|
|
{
|
|
if (pEvent->timerId() != m_uTimerID)
|
|
return;
|
|
|
|
bool bForceProcessDisabled = false;
|
|
bool bIconBusy = false;
|
|
bool bConnected = false;
|
|
|
|
if (theAPI->IsConnected())
|
|
{
|
|
SB_STATUS Status = theAPI->ReloadBoxes();
|
|
|
|
UpdateProcesses();
|
|
|
|
bForceProcessDisabled = theAPI->AreForceProcessDisabled();
|
|
m_pDisableForce->setChecked(bForceProcessDisabled);
|
|
m_pDisableForce2->setChecked(bForceProcessDisabled);
|
|
|
|
if (m_pTraceView)
|
|
{
|
|
bool bIsMonitoring = theAPI->IsMonitoring();
|
|
m_pEnableMonitoring->setChecked(bIsMonitoring);
|
|
int iTraceCount = theAPI->GetTraceCount();
|
|
if (!bIsMonitoring && iTraceCount > 0)
|
|
bIsMonitoring = true; // don't disable the view as long as there are entries shown
|
|
if (bIsMonitoring && m_pTraceView)
|
|
m_pTraceInfo->setText(QString::number(iTraceCount));
|
|
m_pTraceView->SetEnabled(bIsMonitoring);
|
|
}
|
|
|
|
QMap<quint32, CBoxedProcessPtr> Processes = theAPI->GetAllProcesses();
|
|
int ActiveProcesses = 0;
|
|
if (KeepTerminated()) {
|
|
foreach(const CBoxedProcessPtr & Process, Processes) {
|
|
if (!Process->IsTerminated())
|
|
ActiveProcesses++;
|
|
}
|
|
}
|
|
else
|
|
ActiveProcesses = Processes.count();
|
|
|
|
|
|
if (theAPI->IsBusy() || m_iDeletingContent > 0)
|
|
bIconBusy = true;
|
|
|
|
if (m_iIconDisabled != (bForceProcessDisabled ? 1 : 0)) {
|
|
QString Str1 = tr("No Force Process");
|
|
m_pDisabledForce->setText(m_pDisableForce->isChecked() ? Str1 : QString(Str1.length(), ' '));
|
|
}
|
|
|
|
bool bUpdatePending = !theConf->GetString("Updater/PendingUpdate").isEmpty();
|
|
if (m_pDismissUpdate) {
|
|
if (bUpdatePending) {
|
|
if (m_pDismissUpdate->isChecked())
|
|
bUpdatePending = false;
|
|
else if (!m_pDismissUpdate->isVisible())
|
|
m_pDismissUpdate->setVisible(true);
|
|
}
|
|
else if (m_pDismissUpdate->isChecked())
|
|
m_pDismissUpdate->setChecked(false);
|
|
if (!bUpdatePending && m_pDismissUpdate->isVisible())
|
|
m_pDismissUpdate->setVisible(false);
|
|
}
|
|
|
|
if (m_bIconEmpty != (ActiveProcesses == 0) || m_bIconBusy != bIconBusy || m_iIconDisabled != (bForceProcessDisabled ? 1 : 0) || bUpdatePending || m_bIconSun)
|
|
{
|
|
m_bIconEmpty = (ActiveProcesses == 0);
|
|
m_bIconBusy = bIconBusy;
|
|
m_iIconDisabled = (bForceProcessDisabled ? 1 : 0);
|
|
|
|
m_bIconSun = bUpdatePending ? !m_bIconSun : false;
|
|
m_pTrayIcon->setIcon(GetTrayIcon(true, m_bIconSun));
|
|
m_pTrayIcon->setToolTip(GetTrayText());
|
|
}
|
|
}
|
|
|
|
if (!isVisible() || windowState().testFlag(Qt::WindowMinimized))
|
|
return;
|
|
|
|
//QUERY_USER_NOTIFICATION_STATE NState; // todo
|
|
//if (SHQueryUserNotificationState(&NState) == S_OK)
|
|
// ;
|
|
|
|
theAPI->UpdateWindowMap();
|
|
|
|
m_pBoxView->Refresh();
|
|
|
|
if(!IsSilentMode()) // do not check for updates when in presentation/game mode
|
|
m_pUpdater->Process();
|
|
|
|
if (!m_MissingTemplates.isEmpty())
|
|
{
|
|
if (m_MissingTemplates[0] == "") {
|
|
m_MissingTemplates.clear();
|
|
return;
|
|
}
|
|
|
|
int CleanupTemplates = theConf->GetInt("Options/AutoCleanupTemplates", -1);
|
|
if (CleanupTemplates == -1)
|
|
{
|
|
bool State = false;
|
|
CleanupTemplates = CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Some compatibility templates (%1) are missing, probably deleted, do you want to remove them from all boxes?")
|
|
.arg(m_MissingTemplates.join(", "))
|
|
, tr("Don't show this message again."), &State, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes, QMessageBox::Information) == QDialogButtonBox::Yes ? 1 : 0;
|
|
|
|
if (State)
|
|
theConf->SetValue("Options/AutoCleanupTemplates", CleanupTemplates);
|
|
}
|
|
|
|
if (CleanupTemplates)
|
|
{
|
|
foreach(const QString& Template, m_MissingTemplates)
|
|
{
|
|
theAPI->GetGlobalSettings()->DelValue("Template", Template);
|
|
foreach(const CSandBoxPtr& pBox, theAPI->GetAllBoxes())
|
|
pBox->DelValue("Template", Template);
|
|
}
|
|
|
|
OnLogMessage(tr("Cleaned up removed templates..."));
|
|
}
|
|
m_MissingTemplates.clear();
|
|
|
|
m_MissingTemplates.append("");
|
|
}
|
|
}
|
|
|
|
void CSandMan::OnBoxSelected()
|
|
{
|
|
CSandBoxPtr pBox;
|
|
if (m_pPanelSplitter) {
|
|
QList<CSandBoxPtr> boxes = m_pBoxView->GetSelectedBoxes();
|
|
if (m_pPanelSplitter->sizes().at(1) > 0 && m_pFileView->isVisible() && boxes.count() == 1)
|
|
pBox = boxes.first();
|
|
}
|
|
|
|
// for vintage mode
|
|
if (m_pBoxCombo && m_pViewStack->currentIndex() == 1) {
|
|
QString Name = m_pBoxCombo->currentData().toString();
|
|
if (Name.isEmpty())
|
|
Name = theAPI->GetGlobalSettings()->GetText("DefaultBox", "DefaultBox");
|
|
pBox = theAPI->GetBoxByName(Name);
|
|
}
|
|
|
|
if (!pBox.isNull()) {
|
|
if (!m_pFileView->isEnabled()) m_pFileView->setEnabled(true);
|
|
if (pBox != m_pFileView->GetBox()) m_pFileView->SetBox(pBox);
|
|
}
|
|
else if (m_pFileView->isEnabled()) {
|
|
m_pFileView->setEnabled(false);
|
|
m_pFileView->SetBox(CSandBoxPtr());
|
|
}
|
|
}
|
|
|
|
SB_STATUS CSandMan::DeleteBoxContent(const CSandBoxPtr& pBox, EDelMode Mode, bool DeleteSnapshots)
|
|
{
|
|
SB_STATUS Ret = SB_OK;
|
|
|
|
if (Mode != eAuto) {
|
|
Ret = pBox->TerminateAll();
|
|
if (Ret.IsError())
|
|
return Ret;
|
|
}
|
|
|
|
auto pBoxEx = pBox.objectCast<CSandBoxPlus>();
|
|
|
|
if (Mode != eForDelete) {
|
|
|
|
//
|
|
// schedule async OnBoxDelete triggers and clean up
|
|
//
|
|
|
|
if (theConf->GetBool("Options/UseAsyncBoxOps", false) || theGUI->IsSilentMode())
|
|
return pBoxEx->DeleteContentAsync(DeleteSnapshots);
|
|
}
|
|
|
|
m_iDeletingContent++;
|
|
|
|
if (Mode != eForDelete) {
|
|
|
|
//
|
|
// execute OnBoxDelete triggers
|
|
//
|
|
|
|
foreach(const QString & Value, pBox->GetTextList("OnBoxDelete", true, false, true)) {
|
|
QString Value2 = pBox->Expand(Value);
|
|
CSbieProgressPtr pProgress = CSbieUtils::RunCommand(Value2, true);
|
|
if (!pProgress.isNull()) {
|
|
AddAsyncOp(pProgress, true, tr("Executing OnBoxDelete: %1").arg(Value2));
|
|
if (pProgress->IsCanceled()) {
|
|
Ret = CSbieStatus(SB_Canceled);
|
|
goto finish;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
//
|
|
// delete content synchronously
|
|
//
|
|
|
|
SB_PROGRESS Status;
|
|
if (Mode != eForDelete && !DeleteSnapshots && pBox->HasSnapshots()) { // in auto delete mode always return to last snapshot
|
|
QString Current;
|
|
QString Default = pBox->GetDefaultSnapshot(&Current);
|
|
Status = pBox->SelectSnapshot(Mode == eAuto ? Current : Default);
|
|
}
|
|
else // if there are no snapshots just use the normal cleaning procedure
|
|
Status = pBox->CleanBox();
|
|
|
|
Ret = Status;
|
|
if (Status.GetStatus() == OP_ASYNC) {
|
|
Ret = AddAsyncOp(Status.GetValue(), true, tr("Auto Deleting %1 Content").arg(pBox->GetName()));
|
|
OnBoxCleaned(qobject_cast<CSandBoxPlus*>(pBox.data()));
|
|
}
|
|
}
|
|
|
|
finish:
|
|
m_iDeletingContent--;
|
|
return Ret;
|
|
}
|
|
|
|
void CSandMan::UpdateProcesses()
|
|
{
|
|
theAPI->UpdateProcesses(KeepTerminated() ? -1 : 1500, ShowAllSessions()); // keep for 1.5 sec
|
|
}
|
|
|
|
void CSandMan::OnBoxAdded(const CSandBoxPtr& pBox)
|
|
{
|
|
connect(pBox.data(), SIGNAL(StartMenuChanged()), this, SLOT(OnStartMenuChanged()));
|
|
}
|
|
|
|
void CSandMan::EnumBoxLinks(QMap<QString, QMap<QString,SBoxLink> > &BoxLinks, const QString& Prefix, const QString& Folder, bool bWithSubDirs)
|
|
{
|
|
QRegularExpression exp("/\\[[0-9Sa-zA-Z_]+\\] ");
|
|
|
|
QStringList Files = ListDir(Folder, QStringList() << "*.lnk" << "*.url" << "*.pif", bWithSubDirs);
|
|
foreach(QString File, Files)
|
|
{
|
|
auto result = exp.match(File);
|
|
if(!result.hasMatch())
|
|
continue;
|
|
|
|
int pos = result.capturedStart() + 1;
|
|
int len = result.capturedLength() - 1;
|
|
QString BoxName = File.mid(pos + 1, len - 3);
|
|
|
|
SBoxLink BoxLink;
|
|
BoxLink.RelPath = (Prefix + "/" + QString(File).remove(pos, len));
|
|
BoxLink.FullPath = Folder + "/" + File;
|
|
|
|
QVariantMap Link = ResolveShortcut(BoxLink.FullPath);
|
|
BoxLink.Target = Link["Arguments"].toString().trimmed();
|
|
if (BoxLink.Target.left(4) == "/box") {
|
|
if(int pos = BoxLink.Target.indexOf(" ") + 1)
|
|
BoxLink.Target = BoxLink.Target.mid(pos).trimmed();
|
|
}
|
|
|
|
BoxLinks[BoxName.toLower()].insert(BoxLink.RelPath.toLower(), BoxLink);
|
|
}
|
|
}
|
|
|
|
void CSandMan::CleanupShortcutPath(const QString& Path)
|
|
{
|
|
QRegularExpression exp("\\[[0-9Sa-zA-Z_]+\\] ");
|
|
|
|
StrPair PathName = Split2(Path, "/", true);
|
|
if (PathName.first.indexOf(exp) != -1) {
|
|
if (ListDir(PathName.first).isEmpty())
|
|
{
|
|
QDir().rmdir(PathName.first);
|
|
//qDebug() << "delete dir" << PathName.first;
|
|
CleanupShortcutPath(PathName.first);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSandMan::DeleteShortcut(const QString& Path)
|
|
{
|
|
QFile::remove(Path);
|
|
//qDebug() << "delete link" << Path;
|
|
CleanupShortcutPath(Path);
|
|
}
|
|
|
|
void CSandMan::CleanUpStartMenu(QMap<QString, QMap<QString, SBoxLink> >& BoxLinks)
|
|
{
|
|
for (auto I = BoxLinks.begin(); I != BoxLinks.end(); ++I) {
|
|
for (auto J = I->begin(); J != I->end(); ++J) {
|
|
//qDebug() << "Delete Shortcut" << J.value();
|
|
OnLogMessage(tr("Removed Shortcut: %1").arg(J.key()));
|
|
DeleteShortcut(J->FullPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSandMan::ClearStartMenu()
|
|
{
|
|
QMap<QString, QMap<QString, SBoxLink> > BoxLinks;
|
|
EnumBoxLinks(BoxLinks, "Programs", QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation));
|
|
EnumBoxLinks(BoxLinks, "Desktop", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), false);
|
|
|
|
CleanUpStartMenu(BoxLinks);
|
|
}
|
|
|
|
bool CSandMan__MatchLinkTarget(QString L, QString R)
|
|
{
|
|
if (L == R)
|
|
return true;
|
|
if (L.left(1) == "\"" && L == "\"" + R + "\"")
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void CSandMan::SyncStartMenu()
|
|
{
|
|
m_StartMenuUpdatePending = false;
|
|
|
|
int Mode = theConf->GetInt("Options/IntegrateStartMenu", 0);
|
|
if (Mode == 0)
|
|
return;
|
|
|
|
QMap<QString, QMap<QString, SBoxLink> > BoxLinks;
|
|
EnumBoxLinks(BoxLinks, "Programs", QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation));
|
|
EnumBoxLinks(BoxLinks, "Desktop", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), false);
|
|
|
|
QMap<QString, CSandBoxPtr> Boxes = theAPI->GetAllBoxes();
|
|
foreach(const CSandBoxPtr & pBox, Boxes)
|
|
{
|
|
CSandBoxPlus* pBoxEx = (CSandBoxPlus*)pBox.data();
|
|
|
|
QMap<QString, SBoxLink>& CurLinks = BoxLinks[pBoxEx->GetName().toLower()];
|
|
|
|
foreach(const CSandBoxPlus::SLink & Link, pBoxEx->GetStartMenu())
|
|
{
|
|
QString Location;
|
|
QString Prefix;
|
|
StrPair LocPath = Split2(Link.Folder, "/");
|
|
if (Mode == 2) // deep integration
|
|
{
|
|
if (LocPath.first == "Programs")
|
|
Location = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
|
|
else if (LocPath.first == "Desktop")
|
|
Location = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
|
else
|
|
continue;
|
|
}
|
|
else //if(Mode == 1) // contained integration
|
|
{
|
|
Prefix = "Programs\\Sandboxie-Plus\\";
|
|
Location = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + "\\Sandboxie-Plus";
|
|
Location += "\\" + LocPath.first;
|
|
}
|
|
|
|
QString Folder;
|
|
if (LocPath.second.isEmpty()) {
|
|
Folder = Location;
|
|
Location += "\\[" + pBoxEx->GetName() + "] ";
|
|
} else {
|
|
Location += "\\[" + pBoxEx->GetName() + "] " + LocPath.second + "\\";
|
|
Folder = Location;
|
|
}
|
|
|
|
QString Key = QString(Prefix + Link.Folder + "\\" + Link.Name + ".lnk").replace("\\", "/").toLower();
|
|
SBoxLink BoxLink = CurLinks.take(Key);
|
|
if (BoxLink.FullPath.isEmpty() || !CSandMan__MatchLinkTarget(BoxLink.Target, Link.Target)) {
|
|
//qDebug() << "CreateShortcut" << Location + Link.Name;
|
|
if (!BoxLink.FullPath.isEmpty()) {
|
|
QFile::remove(BoxLink.FullPath);
|
|
OnLogMessage(tr("Updated Shortcut to: %1").arg(Key));
|
|
} else
|
|
OnLogMessage(tr("Added Shortcut to: %1").arg(Key));
|
|
QDir().mkpath(Folder);
|
|
QString StartExe = theAPI->GetSbiePath() + "\\SandMan.exe";
|
|
CSbieUtils::CreateShortcut(StartExe, Location + Link.Name,
|
|
Link.Name, pBoxEx->GetName(), Link.Target, Link.Icon.isEmpty() ? Link.Target : Link.Icon, Link.IconIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
CleanUpStartMenu(BoxLinks);
|
|
}
|
|
|
|
void CSandMan::OnStartMenuChanged()
|
|
{
|
|
if (!m_StartMenuUpdatePending)
|
|
{
|
|
m_StartMenuUpdatePending = true;
|
|
QTimer::singleShot(1000, this, SLOT(SyncStartMenu()));
|
|
}
|
|
}
|
|
|
|
void CSandMan::OnBoxClosed(const CSandBoxPtr& pBox)
|
|
{
|
|
if (!pBox->GetBool("NeverDelete", false))
|
|
{
|
|
if (pBox->GetBool("AutoDelete", false))
|
|
{
|
|
bool DeleteSnapshots = false;
|
|
// if this box auto deletes first show the recovry dialog with the option to abort deletion
|
|
if (!theGUI->OpenRecovery(pBox, DeleteSnapshots, true)) // unless no files are found than continue silently
|
|
return;
|
|
|
|
if (theConf->GetBool("Options/AutoBoxOpsNotify", false))
|
|
OnLogMessage(tr("Auto deleting content of %1").arg(pBox->GetName()), true);
|
|
|
|
DeleteBoxContent(pBox, eAuto, DeleteSnapshots);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSandMan::OnBoxCleaned(CSandBoxPlus* pBoxEx)
|
|
{
|
|
if (pBoxEx->GetBool("AutoRemove", false))
|
|
{
|
|
if (theConf->GetBool("Options/AutoBoxOpsNotify", false))
|
|
OnLogMessage(tr("Auto removing sandbox %1").arg(pBoxEx->GetName()), true);
|
|
|
|
pBoxEx->RemoveBox();
|
|
return;
|
|
}
|
|
}
|
|
|
|
void CSandMan::OnStatusChanged()
|
|
{
|
|
#ifdef INSIDER_BUILD
|
|
QString appTitle = tr("Sandboxie-Plus Insider [%1]").arg(QString(__DATE__));
|
|
#else
|
|
QString appTitle = tr("Sandboxie-Plus v%1").arg(GetVersion());
|
|
#endif
|
|
|
|
bool bConnected = theAPI->IsConnected();
|
|
m_pConnect->setEnabled(!bConnected);
|
|
m_pDisconnect->setEnabled(bConnected);
|
|
|
|
if (bConnected)
|
|
{
|
|
bool bPortable = IsFullyPortable();
|
|
|
|
QString SbiePath = theAPI->GetSbiePath();
|
|
OnLogMessage(tr("%1 Directory: %2").arg(bPortable ? tr("Application") : tr("Installation")).arg(SbiePath));
|
|
OnLogMessage(tr("Sandboxie-Plus Version: %1 (%2)").arg(GetVersion()).arg(theAPI->GetVersion()));
|
|
OnLogMessage(tr("Current Config: %1").arg(theAPI->GetIniPath()));
|
|
OnLogMessage(tr("Data Directory: %1").arg(QString(theConf->GetConfigDir()).replace("/","\\")));
|
|
|
|
//statusBar()->showMessage(tr("Driver version: %1").arg(theAPI->GetVersion()));
|
|
|
|
//appTitle.append(tr(" - Driver: v%1").arg(theAPI->GetVersion()));
|
|
if (bPortable)
|
|
{
|
|
//appTitle.append(tr(" - Portable"));
|
|
|
|
QString BoxPath = QDir::cleanPath(QApplication::applicationDirPath() + "/../Sandbox").replace("/", "\\");
|
|
|
|
int PortableRootDir = theConf->GetInt("Options/PortableRootDir", 2);
|
|
if (PortableRootDir == 2)
|
|
{
|
|
QString NtBoxRoot = theAPI->GetGlobalSettings()->GetText("FileRootPath", "\\??\\%SystemDrive%\\Sandbox\\%USER%\\%SANDBOX%", false, false).replace("GlobalSettings", "[BoxName]");
|
|
|
|
bool State = false;
|
|
PortableRootDir = CCheckableMessageBox::question(this, "Sandboxie-Plus",
|
|
tr("Sandboxie-Plus was started in portable mode, do you want to put the Sandbox folder into its parent directory?\nYes will choose: %1\nNo will choose: %2")
|
|
.arg(BoxPath + "\\[BoxName]")
|
|
.arg(theAPI->Nt2DosPath(NtBoxRoot))
|
|
, tr("Don't show this message again."), &State, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes, QMessageBox::Information) == QDialogButtonBox::Yes ? 1 : 0;
|
|
|
|
if (State)
|
|
theConf->SetValue("Options/PortableRootDir", PortableRootDir);
|
|
}
|
|
|
|
if (PortableRootDir)
|
|
theAPI->GetGlobalSettings()->SetText("FileRootPath", BoxPath + "\\%SANDBOX%");
|
|
}
|
|
|
|
if (SbiePath.compare(QApplication::applicationDirPath().replace("/", "\\"), Qt::CaseInsensitive) == 0)
|
|
{
|
|
QString AgentCmd = theAPI->GetUserSettings()->GetText("SbieCtrl_AutoStartAgent");
|
|
if (AgentCmd.isEmpty() || AgentCmd == "SandMan.exe")
|
|
theAPI->GetUserSettings()->SetText("SbieCtrl_AutoStartAgent", "SandMan.exe -autorun");
|
|
|
|
QString cmd = CSbieUtils::GetContextMenuStartCmd();
|
|
if (!cmd.isEmpty() && !cmd.contains("SandMan.exe", Qt::CaseInsensitive))
|
|
CSettingsWindow::AddContextMenu();
|
|
}
|
|
|
|
m_pBoxView->Clear();
|
|
m_pBoxView->ReloadUserConfig();
|
|
m_pPopUpWindow->ReloadHiddenMessages();
|
|
|
|
theAPI->WatchIni(true, theConf->GetBool("Options/WatchIni", true));
|
|
|
|
if (!theAPI->ReloadCert().IsError())
|
|
CSettingsWindow::LoadCertificate();
|
|
else {
|
|
g_Certificate.clear();
|
|
|
|
QString CertPath = QCoreApplication::applicationDirPath() + "\\Certificate.dat";
|
|
if(QFile::exists(CertPath)) // always delete invalid certificates
|
|
WindowsMoveFile(CertPath.replace("/", "\\"), "");
|
|
}
|
|
UpdateCertState();
|
|
|
|
uchar UsageFlags = 0;
|
|
if (theAPI->GetSecureParam("UsageFlags", &UsageFlags, sizeof(UsageFlags))) {
|
|
if (!g_CertInfo.business) {
|
|
if ((UsageFlags & (2 | 1)) != 0) {
|
|
if(g_CertInfo.valid)
|
|
appTitle.append(tr(" for Personal use"));
|
|
else
|
|
appTitle.append(tr(" - for Non-Commercial use ONLY"));
|
|
}
|
|
}
|
|
}
|
|
else { // migrate value form ini to registry // todo remove in later builds
|
|
int BusinessUse = theConf->GetInt("Options/BusinessUse", 2);
|
|
if (BusinessUse == 1) {
|
|
UsageFlags = 1;
|
|
theAPI->SetSecureParam("UsageFlags", &UsageFlags, sizeof(UsageFlags));
|
|
}
|
|
}
|
|
|
|
g_FeatureFlags = theAPI->GetFeatureFlags();
|
|
|
|
SB_STATUS Status = theAPI->ReloadBoxes(true);
|
|
|
|
if (!Status.IsError()) {
|
|
|
|
auto AllBoxes = theAPI->GetAllBoxes();
|
|
|
|
m_pBoxView->ClearUserUIConfig(AllBoxes);
|
|
|
|
foreach(const QString & Key, theConf->ListKeys("SizeCache")) {
|
|
if (!AllBoxes.contains(Key.toLower()) || !theConf->GetBool("Options/WatchBoxSize", false))
|
|
theConf->DelValue("SizeCache/" + Key);
|
|
}
|
|
|
|
QString DefaultBox = theAPI->GetGlobalSettings()->GetText("DefaultBox", "DefaultBox");
|
|
if (!AllBoxes.contains(DefaultBox.toLower())) {
|
|
OnLogMessage(tr("Default sandbox not found; creating: %1").arg(DefaultBox));
|
|
theAPI->CreateBox(DefaultBox);
|
|
}
|
|
|
|
if (theConf->GetBool("Options/CleanUpOnStart", false)) {
|
|
|
|
//
|
|
// clean up Auto Delete boxes after reboot
|
|
//
|
|
|
|
theAPI->UpdateProcesses(0, ShowAllSessions());
|
|
|
|
foreach(const CSandBoxPtr & pBox, AllBoxes) {
|
|
if (pBox->GetActiveProcessCount() == 0)
|
|
OnBoxClosed(pBox);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isVisible())
|
|
CheckSupport();
|
|
|
|
int WizardLevel = abs(theConf->GetInt("Options/WizardLevel", 0));
|
|
if (WizardLevel < (theConf->GetInt("Options/CheckForUpdates", 2) != 1 ? SETUP_LVL_2 : SETUP_LVL_1)) {
|
|
if (!CSetupWizard::ShowWizard(WizardLevel)) { // if user canceled, mark that and do not show again, until there is something new
|
|
if(QMessageBox::question(NULL, "Sandboxie-Plus", tr("Do you want the setup wizard to be omitted?"), QMessageBox::Yes, QMessageBox::No | QMessageBox::Default) == QMessageBox::Yes)
|
|
theConf->SetValue("Options/WizardLevel", -SETUP_LVL_CURRENT);
|
|
}
|
|
}
|
|
|
|
if (theConf->GetBool("Options/AutoRunSoftCompat", true))
|
|
CheckCompat(this, "OpenCompat");
|
|
}
|
|
else
|
|
{
|
|
appTitle.append(tr(" - NOT connected"));
|
|
|
|
m_pBoxView->Clear();
|
|
|
|
theAPI->WatchIni(false);
|
|
|
|
theAPI->StopMonitor();
|
|
}
|
|
|
|
this->setWindowTitle(appTitle);
|
|
|
|
UpdateState();
|
|
}
|
|
|
|
void CSandMan::CheckCompat(QObject* receiver, const char* member)
|
|
{
|
|
QElapsedTimer* timer = new QElapsedTimer();
|
|
timer->start();
|
|
|
|
C7zFileEngineHandler IssueFS("issue");
|
|
QFile File(CBoxAssistant::GetIssueDir(IssueFS) + "AppCompatibility.js");
|
|
if (File.open(QFile::ReadOnly)) {
|
|
CBoxEngine* pEngine = new CBoxEngine(this);
|
|
pEngine->RunScript(File.readAll(), "AppCompatibility.js"); // note: script runs asynchronously
|
|
QPointer<QObject> pObj = receiver; // QPointer tracks lifetime of receiver
|
|
connect(pEngine, &CBoxEngine::finished, this, [pEngine, this, timer, pObj, member]() {
|
|
|
|
m_SbieTemplates->SetCheckResult(pEngine->GetResult().toStringList());
|
|
|
|
qDebug() << "Compatibility Check took" << timer->elapsed() << "ms";
|
|
delete timer;
|
|
pEngine->deleteLater(); // script done
|
|
|
|
if(pObj) QMetaObject::invokeMethod(pObj, member);
|
|
});
|
|
return;
|
|
}
|
|
|
|
m_SbieTemplates->RunCheck();
|
|
|
|
qDebug() << "Template Check took" << timer->elapsed() << "ms";
|
|
delete timer;
|
|
|
|
QMetaObject::invokeMethod(receiver, member);
|
|
}
|
|
|
|
void CSandMan::OpenCompat()
|
|
{
|
|
if (m_SbieTemplates->GetCheckState())
|
|
{
|
|
CSettingsWindow* pSettingsWindow = new CSettingsWindow(this);
|
|
connect(pSettingsWindow, SIGNAL(OptionsChanged(bool)), this, SLOT(UpdateSettings(bool)));
|
|
pSettingsWindow->showTab(CSettingsWindow::eSoftCompat);
|
|
}
|
|
}
|
|
|
|
void CSandMan::UpdateState()
|
|
{
|
|
bool isConnected = theAPI->IsConnected();
|
|
|
|
//m_pSupport->setVisible(g_Certificate.isEmpty());
|
|
|
|
m_pTrayIcon->setIcon(GetTrayIcon(isConnected));
|
|
m_pTrayIcon->setToolTip(GetTrayText(isConnected));
|
|
m_bIconEmpty = true;
|
|
m_iIconDisabled = -1;
|
|
m_bIconBusy = false;
|
|
m_bIconSun = false;
|
|
|
|
m_pRunBoxed->setEnabled(isConnected);
|
|
m_pNewBox->setEnabled(isConnected);
|
|
m_pNewGroup->setEnabled(isConnected);
|
|
m_pImportBox->setEnabled(isConnected);
|
|
m_pEmptyAll->setEnabled(isConnected);
|
|
m_pDisableForce->setEnabled(isConnected);
|
|
m_pDisableForce2->setEnabled(isConnected);
|
|
|
|
//m_pCleanUpMenu->setEnabled(isConnected);
|
|
//m_pCleanUpButton->setEnabled(isConnected);
|
|
//m_pKeepTerminated->setEnabled(isConnected);
|
|
|
|
m_pEditIni->setEnabled(isConnected);
|
|
if(m_pEditIni2) m_pEditIni2->setEnabled(isConnected);
|
|
m_pReloadIni->setEnabled(isConnected);
|
|
if(m_pEnableMonitoring) m_pEnableMonitoring->setEnabled(isConnected);
|
|
|
|
if (m_pNewBoxButton) m_pNewBoxButton->setEnabled(isConnected);
|
|
if (m_pEditIniButton) m_pEditIniButton->setEnabled(isConnected);
|
|
if (m_pCleanUpButton) m_pCleanUpButton->setEnabled(isConnected);
|
|
}
|
|
|
|
void CSandMan::OnMenuHover(QAction* action)
|
|
{
|
|
//if (!m_pMenuBar->actions().contains(action))
|
|
// return; // ignore sub menus
|
|
|
|
|
|
if (m_pMenuBar->actions().at(0) == action && m_pMaintenance)
|
|
{
|
|
m_pMaintenanceItems->setEnabled(!theAPI->IsConnected());
|
|
|
|
bool DrvInstalled = CSbieUtils::IsInstalled(CSbieUtils::eDriver);
|
|
bool DrvLoaded = CSbieUtils::IsRunning(CSbieUtils::eDriver);
|
|
m_pInstallDrv->setEnabled(!DrvInstalled);
|
|
m_pStartDrv->setEnabled(!DrvLoaded);
|
|
m_pStopDrv->setEnabled(DrvLoaded);
|
|
m_pUninstallDrv->setEnabled(DrvInstalled);
|
|
|
|
bool SvcInstalled = CSbieUtils::IsInstalled(CSbieUtils::eService);
|
|
bool SvcStarted = CSbieUtils::IsRunning(CSbieUtils::eService);
|
|
m_pInstallSvc->setEnabled(!SvcInstalled);
|
|
m_pStartSvc->setEnabled(!SvcStarted && DrvInstalled);
|
|
m_pStopSvc->setEnabled(SvcStarted);
|
|
m_pUninstallSvc->setEnabled(SvcInstalled);
|
|
|
|
//m_pMenuStopAll - always enabled
|
|
}
|
|
|
|
if (m_pMenuBar->actions().at(2) == action && m_pSandbox)
|
|
CreateBoxMenu(m_pSandbox);
|
|
}
|
|
|
|
void CSandMan::CheckSupport()
|
|
{
|
|
if (CSupportDialog::CheckSupport())
|
|
return;
|
|
|
|
static bool ReminderShown = false;
|
|
if (!ReminderShown && (g_CertInfo.expired || g_CertInfo.about_to_expire) && !theConf->GetBool("Options/NoSupportCheck", false))
|
|
{
|
|
ReminderShown = true;
|
|
CSettingsWindow* pSettingsWindow = new CSettingsWindow(this);
|
|
connect(pSettingsWindow, SIGNAL(OptionsChanged(bool)), this, SLOT(UpdateSettings(bool)));
|
|
pSettingsWindow->showTab(CSettingsWindow::eSupport);
|
|
}
|
|
}
|
|
|
|
#define HK_PANIC 1
|
|
|
|
void CSandMan::SetupHotKeys()
|
|
{
|
|
m_pHotkeyManager->unregisterAllHotkeys();
|
|
|
|
if (theConf->GetBool("Options/EnablePanicKey", false))
|
|
m_pHotkeyManager->registerHotkey(theConf->GetString("Options/PanicKeySequence", "Shift+Pause"), HK_PANIC);
|
|
}
|
|
|
|
void CSandMan::OnHotKey(size_t id)
|
|
{
|
|
switch (id)
|
|
{
|
|
case HK_PANIC:
|
|
theAPI->TerminateAll();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CSandMan::OnLogMessage(const QString& Message, bool bNotify)
|
|
{
|
|
AddLogMessage(Message);
|
|
|
|
if (bNotify) {
|
|
statusBar()->showMessage(Message);
|
|
m_pTrayIcon->showMessage("Sandboxie-Plus", Message);
|
|
}
|
|
}
|
|
|
|
void CSandMan::AddLogMessage(const QString& Message)
|
|
{
|
|
if (!m_pMessageLog)
|
|
return;
|
|
|
|
AddLogMessage(QDateTime::currentDateTime(), Message);
|
|
}
|
|
|
|
void CSandMan::AddLogMessage(const QDateTime& TimeStamp, const QString& Message)
|
|
{
|
|
int last = m_pMessageLog->GetTree()->topLevelItemCount();
|
|
if (last > 0) {
|
|
QTreeWidgetItem* pItem = m_pMessageLog->GetTree()->topLevelItem(last-1);
|
|
if (pItem->data(1, Qt::UserRole).toString() == Message) {
|
|
int Count = pItem->data(0, Qt::UserRole).toInt();
|
|
if (Count == 0)
|
|
Count = 1;
|
|
Count++;
|
|
pItem->setData(0, Qt::UserRole, Count);
|
|
QLabel* pLabel = (QLabel*)m_pMessageLog->GetTree()->itemWidget(pItem, 1);
|
|
if(pLabel)
|
|
pLabel->setText(Message + tr(" (%1)").arg(Count));
|
|
else
|
|
pItem->setText(1, Message + tr(" (%1)").arg(Count));
|
|
return;
|
|
}
|
|
}
|
|
|
|
QTreeWidgetItem* pItem = new QTreeWidgetItem(); // Time|Message
|
|
pItem->setText(0, TimeStamp.toString("hh:mm:ss.zzz"));
|
|
pItem->setData(1, Qt::UserRole, Message);
|
|
m_pMessageLog->GetTree()->addTopLevelItem(pItem);
|
|
if (Message.contains("</a>")) {
|
|
QLabel* pLabel = new QLabel(Message);
|
|
pLabel->setContentsMargins(3, 0, 0, 0);
|
|
pLabel->setAutoFillBackground(true);
|
|
connect(pLabel, SIGNAL(linkActivated(const QString&)), theGUI, SLOT(OpenUrl(const QString&)));
|
|
m_pMessageLog->GetTree()->setItemWidget(pItem, 1, pLabel);
|
|
|
|
QRegularExpression tagExp("<[^>]*>");
|
|
QString TextMessage = Message;
|
|
TextMessage.remove(tagExp);
|
|
pItem->setText(1, TextMessage);
|
|
}
|
|
else
|
|
pItem->setText(1, Message);
|
|
|
|
|
|
m_pMessageLog->GetView()->verticalScrollBar()->setValue(m_pMessageLog->GetView()->verticalScrollBar()->maximum());
|
|
}
|
|
|
|
QString CSandMan::FormatSbieMessage(quint32 MsgCode, const QStringList& MsgData, quint32 ProcessId, bool bNoLink)
|
|
{
|
|
QString Message;
|
|
if (MsgCode != 0) {
|
|
Message = theAPI->GetSbieMsgStr(MsgCode, m_LanguageId);
|
|
if (!bNoLink) {
|
|
Message.insert(8, "</a>");
|
|
Message.prepend("<a href=\"https://sandboxie-plus.com/go.php?to=sbie-sbie" + QString::number(MsgCode & 0xFFFF) + "\">");
|
|
}
|
|
}
|
|
else if(MsgData.size() > 0)
|
|
Message = MsgData[0];
|
|
|
|
for (int i = 1; i < MsgData.size(); i++)
|
|
Message = Message.arg(MsgData[i]);
|
|
|
|
if (ProcessId != 4) // if it's not from the driver, add the pid
|
|
{
|
|
CBoxedProcessPtr pProcess = theAPI->GetProcessById(ProcessId);
|
|
if(pProcess.isNull())
|
|
Message.prepend(tr("PID %1: ").arg(ProcessId));
|
|
else
|
|
Message.prepend(tr("%1 (%2): ").arg(pProcess->GetProcessName()).arg(ProcessId));
|
|
}
|
|
|
|
return Message;
|
|
}
|
|
|
|
void CSandMan::OnLogSbieMessage(quint32 MsgCode, const QStringList& MsgData, quint32 ProcessId)
|
|
{
|
|
if ((MsgCode & 0xFFFF) == 2198 ) // file migration progress
|
|
{
|
|
if (!IsDisableMessages() && theConf->GetBool("Options/ShowMigrationProgress", true))
|
|
m_pPopUpWindow->ShowProgress(MsgCode, MsgData, ProcessId);
|
|
return;
|
|
}
|
|
|
|
if ((MsgCode & 0xFFFF) == 1411) // removed/missing template
|
|
{
|
|
if(MsgData.size() >= 3 && !m_MissingTemplates.contains(MsgData[2]))
|
|
m_MissingTemplates.append(MsgData[2]);
|
|
}
|
|
|
|
if ((MsgCode & 0xFFFF) == 6004) // certificate error
|
|
{
|
|
static quint64 iLastCertWarning = 0;
|
|
if (iLastCertWarning + 60 < QDateTime::currentDateTime().toSecsSinceEpoch()) { // reset after 60 seconds
|
|
iLastCertWarning = QDateTime::currentDateTime().toSecsSinceEpoch();
|
|
|
|
QString Message;
|
|
if (!MsgData[2].isEmpty())
|
|
Message = tr("The program %1 started in box %2 will be terminated in 5 minutes because the box was configured to use features exclusively available to project supporters.").arg(MsgData[2]).arg(MsgData[1]);
|
|
else
|
|
Message = tr("The box %1 is configured to use features exclusively available to project supporters, these presets will be ignored.").arg(MsgData[1]);
|
|
Message.append(tr("<br /><a href=\"https://sandboxie-plus.com/go.php?to=sbie-get-cert\">Become a project supporter</a>, and receive a <a href=\"https://sandboxie-plus.com/go.php?to=sbie-cert\">supporter certificate</a>"));
|
|
|
|
QMessageBox msgBox(this);
|
|
msgBox.setTextFormat(Qt::RichText);
|
|
msgBox.setIcon(QMessageBox::Critical);
|
|
msgBox.setWindowTitle("Sandboxie-Plus");
|
|
msgBox.setText(Message);
|
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
|
msgBox.exec();
|
|
/*msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
|
if (msgBox.exec() == QDialogButtonBox::Yes) {
|
|
OpenUrl(QUrl("https://sandboxie-plus.com/go.php?to=sbie-get-cert"));
|
|
}*/
|
|
|
|
//bCertWarning = false;
|
|
}
|
|
// return;
|
|
}
|
|
|
|
m_MessageLog.append(SSbieMsg{ QDateTime::currentDateTime(), MsgCode, MsgData, ProcessId });
|
|
|
|
QString Message = FormatSbieMessage(MsgCode, MsgData, ProcessId);
|
|
OnLogMessage(Message);
|
|
|
|
if ((MsgCode & 0xFFFF) == 6004) // certificate error
|
|
return; // don't pop that one up
|
|
|
|
if ((MsgCode & 0xFFFF) == 2111) // process open denided
|
|
return; // don't pop that one up
|
|
|
|
if(MsgCode != 0 && theConf->GetBool("Options/ShowNotifications", true) && !IsDisableMessages())
|
|
m_pPopUpWindow->AddLogMessage(Message, MsgCode, MsgData, ProcessId);
|
|
}
|
|
|
|
void CSandMan::SaveMessageLog(QIODevice* pFile)
|
|
{
|
|
foreach(const SSbieMsg& Msg, m_MessageLog)
|
|
pFile->write((Msg.TimeStamp.toString("hh:mm:ss.zzz") + "\t" + FormatSbieMessage(Msg.MsgCode, Msg.MsgData, Msg.ProcessId)).toLatin1() + "\n");
|
|
}
|
|
|
|
bool CSandMan::CheckCertificate(QWidget* pWidget)
|
|
{
|
|
if (g_CertInfo.valid)
|
|
return true;
|
|
|
|
//if ((g_FeatureFlags & CSbieAPI::eSbieFeatureCert) == 0) {
|
|
// OnLogMessage(tr("The supporter certificate is expired"));
|
|
// return false;
|
|
//}
|
|
|
|
QMessageBox msgBox(pWidget);
|
|
msgBox.setTextFormat(Qt::RichText);
|
|
msgBox.setIcon(QMessageBox::Information);
|
|
msgBox.setWindowTitle("Sandboxie-Plus");
|
|
msgBox.setText(tr("The selected feature set is only available to project supporters. Processes started in a box with this feature set enabled without a supporter certificate will be terminated after 5 minutes.<br />"
|
|
"<a href=\"https://sandboxie-plus.com/go.php?to=sbie-get-cert\">Become a project supporter</a>, and receive a <a href=\"https://sandboxie-plus.com/go.php?to=sbie-cert\">supporter certificate</a>"));
|
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
|
msgBox.exec();
|
|
/*msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
|
if (msgBox.exec() == QDialogButtonBox::Yes) {
|
|
OpenUrl(QUrl("https://sandboxie-plus.com/go.php?to=sbie-get-cert"));
|
|
}*/
|
|
|
|
return false;
|
|
}
|
|
|
|
void CSandMan::UpdateCertState()
|
|
{
|
|
g_CertInfo.State = theAPI->GetCertState();
|
|
if (g_CertInfo.valid)
|
|
{
|
|
auto Args = GetArguments(g_Certificate, L'\n', L':');
|
|
QString Type = Args.value("TYPE").toUpper();
|
|
if (Type.contains("CONTRIBUTOR") || Type.contains("GREAT_PATREON") || Type.contains("HUGE"))
|
|
g_CertInfo.insider = true;
|
|
|
|
// behave as if there would be no certificate at all
|
|
if (theConf->GetBool("Debug/IgnoreCertificate", false))
|
|
g_CertInfo.State = 0;
|
|
else
|
|
{
|
|
// simulate certificate being about to expire in 3 days from now
|
|
if (theConf->GetBool("Debug/CertFakeAboutToExpire", false))
|
|
g_CertInfo.expirers_in_sec = 3 * 24 * 3600;
|
|
|
|
// simulate certificate having expired but being in the grace period
|
|
if (theConf->GetBool("Debug/CertFakeGracePeriode", false))
|
|
g_CertInfo.grace_period = 1;
|
|
|
|
// simulate a subscription type certificate having expired
|
|
if (theConf->GetBool("Debug/CertFakeOld", false)) {
|
|
g_CertInfo.valid = 0;
|
|
g_CertInfo.expired = 1;
|
|
}
|
|
|
|
// simulate a perpetual use certificate being outside the update window
|
|
if (theConf->GetBool("Debug/CertFakeExpired", false)) {
|
|
// still valid
|
|
g_CertInfo.expired = 1;
|
|
}
|
|
|
|
// simulate a perpetual use certificate being outside the update window
|
|
// and having been applied to a version built after the update window has ended
|
|
if (theConf->GetBool("Debug/CertFakeOutdated", false)) {
|
|
g_CertInfo.valid = 0;
|
|
g_CertInfo.expired = 1;
|
|
g_CertInfo.outdated = 1;
|
|
}
|
|
|
|
// simulate this being a business certificate - only contributors and other insiders
|
|
if (g_CertInfo.insider && theConf->GetBool("Debug/CertFakeBusiness", false))
|
|
g_CertInfo.business = 1;
|
|
|
|
// simulate this being a evaluation certificate
|
|
if (theConf->GetBool("Debug/CertFakeEvaluation", false))
|
|
g_CertInfo.evaluation = 1;
|
|
}
|
|
}
|
|
|
|
if (g_CertInfo.evaluation)
|
|
{
|
|
if (g_CertInfo.expired)
|
|
OnLogMessage(tr("The evaluation period has expired!!!"));
|
|
}
|
|
else
|
|
{
|
|
g_CertInfo.about_to_expire = g_CertInfo.expirers_in_sec > 0 && g_CertInfo.expirers_in_sec < (60 * 60 * 24 * 30);
|
|
if (g_CertInfo.outdated)
|
|
OnLogMessage(tr("The supporter certificate is not valid for this build, please get an updated certificate"));
|
|
// outdated always implicates it is no longer valid
|
|
else if (g_CertInfo.expired) // may be still valid for the current and older builds
|
|
OnLogMessage(tr("The supporter certificate has expired%1, please get an updated certificate")
|
|
.arg(!g_CertInfo.outdated ? tr(", but it remains valid for the current build") : ""));
|
|
else if (g_CertInfo.about_to_expire)
|
|
OnLogMessage(tr("The supporter certificate will expire in %1 days, please get an updated certificate").arg(g_CertInfo.expirers_in_sec / (60 * 60 * 24)));
|
|
}
|
|
|
|
emit CertUpdated();
|
|
}
|
|
|
|
void CSandMan::OnQueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 RequestId, const QVariantMap& Data)
|
|
{
|
|
if (Data["id"].toInt() == 0)
|
|
{
|
|
QVariantMap Ret;
|
|
Ret["retval"] = (theAPI->IsStarting(ClientPid) || CSupportDialog::ShowDialog()) ? 1 : 0;
|
|
theAPI->SendReplyData(RequestId, Ret);
|
|
return;
|
|
}
|
|
m_pPopUpWindow->AddUserPrompt(RequestId, Data, ClientPid);
|
|
}
|
|
|
|
#include "SandManRecovery.cpp"
|
|
|
|
int CSandMan::ShowQuestion(const QString& question, const QString& checkBoxText, bool* checkBoxSetting, int buttons, int defaultButton, int type, QWidget* pParent)
|
|
{
|
|
return CCheckableMessageBox::question(pParent, "Sandboxie-Plus", question, checkBoxText, checkBoxSetting, (QDialogButtonBox::StandardButtons)buttons, (QDialogButtonBox::StandardButton)defaultButton, (QMessageBox::Icon)type);
|
|
}
|
|
|
|
void CSandMan::ShowMessage(const QString& message, int type)
|
|
{
|
|
QMessageBox mb(this);
|
|
mb.setWindowTitle("Sandboxie-Plus");
|
|
mb.setIconPixmap(QMessageBox::standardIcon((QMessageBox::Icon)type));
|
|
mb.setText(message);
|
|
mb.exec();
|
|
QTimer::singleShot(10, [this]() {
|
|
this->raise();
|
|
});
|
|
}
|
|
|
|
void CSandMan::OnNotAuthorized(bool bLoginRequired, bool& bRetry)
|
|
{
|
|
if (!bLoginRequired)
|
|
{
|
|
QMessageBox::warning(this, "Sandboxie-Plus", tr("Only Administrators can change the config."));
|
|
return;
|
|
}
|
|
|
|
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(FormatError(Status)));
|
|
}
|
|
LoginOpen = false;
|
|
}
|
|
|
|
void CSandMan::OnBoxDblClick(QTreeWidgetItem* pItem)
|
|
{
|
|
m_pBoxView->ShowOptions(pItem->data(0, Qt::UserRole).toString());
|
|
}
|
|
|
|
void CSandMan::OnSandBoxAction()
|
|
{
|
|
QAction* pAction = qobject_cast<QAction*>(sender());
|
|
|
|
if (pAction == m_pNewBox)
|
|
GetBoxView()->AddNewBox();
|
|
else if (pAction == m_pNewGroup)
|
|
GetBoxView()->AddNewGroup();
|
|
else if (pAction == m_pImportBox)
|
|
GetBoxView()->ImportSandbox();
|
|
else if (pAction == m_pRunBoxed)
|
|
RunSandboxed(QStringList() << "run_dialog");
|
|
}
|
|
|
|
void CSandMan::OnEmptyAll()
|
|
{
|
|
if (theConf->GetInt("Options/WarnTerminateAll", -1) == -1)
|
|
{
|
|
bool State = false;
|
|
if(CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Do you want to terminate all processes in all sandboxes?")
|
|
, tr("Terminate all without asking"), &State, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes, QMessageBox::Information) != QDialogButtonBox::Yes)
|
|
return;
|
|
|
|
if (State)
|
|
theConf->SetValue("Options/WarnTerminateAll", 1);
|
|
}
|
|
|
|
theAPI->TerminateAll();
|
|
}
|
|
|
|
void CSandMan::OnDisableForce()
|
|
{
|
|
bool Status = m_pDisableForce->isChecked();
|
|
int Seconds = 0;
|
|
if (Status)
|
|
{
|
|
int LastValue = theAPI->GetGlobalSettings()->GetNum("ForceDisableSeconds", 60);
|
|
|
|
bool bOK = false;
|
|
Seconds = QInputDialog::getInt(this, "Sandboxie-Plus", tr("Please enter the duration, in seconds, for disabling Forced Programs rules."), LastValue, 0, INT_MAX, 1, &bOK);
|
|
if (!bOK)
|
|
return;
|
|
}
|
|
theAPI->DisableForceProcess(Status, Seconds);
|
|
}
|
|
|
|
void CSandMan::OnDisableForce2()
|
|
{
|
|
bool Status = m_pDisableForce2->isChecked();
|
|
theAPI->DisableForceProcess(Status);
|
|
}
|
|
|
|
void CSandMan::OnDisablePopUp()
|
|
{
|
|
QString Str2 = tr("No Recovery");
|
|
if (m_pDisableRecovery) {
|
|
m_pDisabledRecovery->setText(m_pDisableRecovery->isChecked() ? Str2 : QString(Str2.length(), ' '));
|
|
theConf->SetValue("UIConfig/DisabledRecovery", m_pDisableRecovery->isChecked());
|
|
}
|
|
|
|
QString Str3 = tr("No Messages");
|
|
if (m_pDisableMessages) {
|
|
m_pDisabledMessages->setText(m_pDisableMessages->isChecked() ? Str3 : QString(Str3.length(), ' '));
|
|
theConf->SetValue("UIConfig/DisableMessages", m_pDisableMessages->isChecked());
|
|
}
|
|
}
|
|
|
|
SB_RESULT(void*) CSandMan::ConnectSbie()
|
|
{
|
|
SB_RESULT(void*) Status;
|
|
if (!CSbieUtils::IsRunning(CSbieUtils::eAll))
|
|
{
|
|
if (!CSbieUtils::IsInstalled(CSbieUtils::eAll))
|
|
{
|
|
int PortableStart = theConf->GetInt("Options/PortableStart", -1);
|
|
if (PortableStart == -1)
|
|
{
|
|
bool State = false;
|
|
PortableStart = CCheckableMessageBox::question(this, "Sandboxie-Plus", tr("Sandboxie-Plus was started in portable mode and it needs to create necessary services. This will prompt for administrative privileges.")
|
|
, tr("Don't show this message again."), &State, QDialogButtonBox::Ok | QDialogButtonBox::Cancel, QDialogButtonBox::Ok, QMessageBox::Information) == QDialogButtonBox::Ok ? 1 : 0;
|
|
|
|
if (State)
|
|
theConf->SetValue("Options/PortableStart", PortableStart);
|
|
}
|
|
|
|
if(!PortableStart)
|
|
return SB_OK;
|
|
}
|
|
|
|
Status = CSbieUtils::Start(CSbieUtils::eAll);
|
|
}
|
|
|
|
if (Status.GetStatus() == OP_ASYNC) {
|
|
m_bConnectPending = true;
|
|
return Status;
|
|
}
|
|
if (Status.IsError())
|
|
return Status;
|
|
|
|
return ConnectSbieImpl();
|
|
}
|
|
|
|
SB_STATUS CSandMan::ConnectSbieImpl()
|
|
{
|
|
SB_STATUS Status = theAPI->Connect(g_PendingMessage.isEmpty(), theConf->GetBool("Options/UseInteractiveQueue", true));
|
|
|
|
if (!g_PendingMessage.isEmpty()) {
|
|
OnMessage(g_PendingMessage);
|
|
PostQuitMessage(0);
|
|
}
|
|
|
|
if (Status.GetStatus() == 0xC0000038L /*STATUS_DEVICE_ALREADY_ATTACHED*/) {
|
|
OnLogMessage(tr("CAUTION: Another agent (probably SbieCtrl.exe) is already managing this Sandboxie session, please close it first and reconnect to take over."));
|
|
Status = SB_OK;
|
|
}
|
|
else if (Status.GetStatus() == 0xC000A000L /*STATUS_INVALID_SIGNATURE*/) {
|
|
QMessageBox::critical(this, "Sandboxie-Plus", tr("<b>ERROR:</b> The Sandboxie-Plus Manager (SandMan.exe) does not have a valid signature (SandMan.exe.sig). Please download a trusted release from the <a href=\"https://sandboxie-plus.com/go.php?to=sbie-get\">official Download page</a>."));
|
|
Status = SB_OK;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
SB_STATUS CSandMan::DisconnectSbie()
|
|
{
|
|
return theAPI->Disconnect();
|
|
}
|
|
|
|
SB_RESULT(void*) CSandMan::StopSbie(bool andRemove)
|
|
{
|
|
SB_RESULT(void*) Status;
|
|
|
|
if (theAPI->IsConnected()) {
|
|
Status = theAPI->TerminateAll();
|
|
theAPI->Disconnect();
|
|
}
|
|
if (!Status.IsError()) {
|
|
if(andRemove)
|
|
Status = CSbieUtils::Uninstall(CSbieUtils::eAll); // it stops it first of course
|
|
else
|
|
Status = CSbieUtils::Stop(CSbieUtils::eAll);
|
|
if (Status.GetStatus() == OP_ASYNC)
|
|
m_bStopPending = true;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
void CSandMan::OnMaintenance()
|
|
{
|
|
SB_RESULT(void*) Status;
|
|
if (sender() == m_pConnect)
|
|
Status = ConnectSbie();
|
|
else if (sender() == m_pDisconnect)
|
|
Status = DisconnectSbie();
|
|
else if (sender() == m_pStopAll)
|
|
Status = StopSbie();
|
|
|
|
// advanced
|
|
else if (sender() == m_pInstallDrv)
|
|
Status = CSbieUtils::Install(CSbieUtils::eDriver);
|
|
else if (sender() == m_pStartDrv)
|
|
Status = CSbieUtils::Start(CSbieUtils::eDriver);
|
|
else if (sender() == m_pStopDrv)
|
|
Status = CSbieUtils::Stop(CSbieUtils::eDriver);
|
|
else if (sender() == m_pUninstallDrv)
|
|
Status = CSbieUtils::Uninstall(CSbieUtils::eDriver);
|
|
|
|
else if (sender() == m_pInstallSvc)
|
|
Status = CSbieUtils::Install(CSbieUtils::eService);
|
|
else if (sender() == m_pStartSvc)
|
|
Status = CSbieUtils::Start(CSbieUtils::eService);
|
|
else if (sender() == m_pStopSvc)
|
|
Status = CSbieUtils::Stop(CSbieUtils::eService);
|
|
else if (sender() == m_pUninstallSvc)
|
|
Status = CSbieUtils::Uninstall(CSbieUtils::eService);
|
|
|
|
else if (sender() == m_pSetupWizard) {
|
|
CSetupWizard::ShowWizard();
|
|
return;
|
|
}
|
|
|
|
//else if (sender() == m_pUpdateCore) {
|
|
// // todo
|
|
// return;
|
|
//}
|
|
|
|
// uninstall
|
|
else if (sender() == m_pUninstallAll) {
|
|
|
|
Status = StopSbie(true);
|
|
|
|
CSetupWizard::ShellUninstall();
|
|
}
|
|
|
|
HandleMaintenance(Status);
|
|
}
|
|
|
|
void CSandMan::HandleMaintenance(SB_RESULT(void*) Status)
|
|
{
|
|
if (Status.GetStatus() == OP_ASYNC) {
|
|
|
|
HANDLE hProcess = Status.GetValue();
|
|
QWinEventNotifier* processFinishedNotifier = new QWinEventNotifier(hProcess);
|
|
processFinishedNotifier->setEnabled(true);
|
|
connect(processFinishedNotifier, &QWinEventNotifier::activated, this, [processFinishedNotifier, this, hProcess]() {
|
|
processFinishedNotifier->setEnabled(false);
|
|
processFinishedNotifier->deleteLater();
|
|
|
|
DWORD dwStatus = 0;
|
|
GetExitCodeProcess(hProcess, & dwStatus);
|
|
|
|
if (dwStatus != 0)
|
|
{
|
|
if(m_bStopPending)
|
|
QMessageBox::warning(this, tr("Sandboxie-Plus - Error"), tr("Failed to stop all Sandboxie components"));
|
|
else if(m_bConnectPending)
|
|
QMessageBox::warning(this, tr("Sandboxie-Plus - Error"), tr("Failed to start required Sandboxie components"));
|
|
|
|
OnLogMessage(tr("Maintenance operation failed (%1)").arg((quint32)dwStatus));
|
|
CheckResults(QList<SB_STATUS>() << SB_ERR(dwStatus), this);
|
|
}
|
|
else
|
|
{
|
|
OnLogMessage(tr("Maintenance operation completed"));
|
|
if (m_bConnectPending) {
|
|
|
|
QTimer::singleShot(1000, [this]() {
|
|
SB_STATUS Status = this->ConnectSbieImpl();
|
|
CheckResults(QList<SB_STATUS>() << Status, this);
|
|
if (Status.IsError())
|
|
theAPI->LoadEventLog();
|
|
});
|
|
}
|
|
}
|
|
m_pProgressDialog->hide();
|
|
//statusBar()->showMessage(tr("Maintenance operation completed"), 3000);
|
|
m_bConnectPending = false;
|
|
m_bStopPending = false;
|
|
|
|
CloseHandle(hProcess);
|
|
});
|
|
|
|
//statusBar()->showMessage(tr("Executing maintenance operation, please wait..."));
|
|
m_pProgressDialog->OnStatusMessage(tr("Executing maintenance operation, please wait..."));
|
|
SafeShow(m_pProgressDialog);
|
|
|
|
return;
|
|
}
|
|
|
|
CheckResults(QList<SB_STATUS>() << Status, this);
|
|
}
|
|
|
|
void CSandMan::OnViewMode(QAction* pAction)
|
|
{
|
|
int iViewMode = pAction->data().toInt();
|
|
theConf->SetValue("Options/ViewMode", iViewMode);
|
|
UpdateSettings(true);
|
|
}
|
|
|
|
void CSandMan::OnAlwaysTop()
|
|
{
|
|
StoreState();
|
|
bool bAlwaysOnTop = m_pWndTopMost->isChecked();
|
|
theConf->SetValue("Options/AlwaysOnTop", bAlwaysOnTop);
|
|
this->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop);
|
|
LoadState();
|
|
SafeShow(this); // why is this needed?
|
|
|
|
m_pPopUpWindow->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop);
|
|
m_pProgressDialog->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop);
|
|
}
|
|
|
|
void CSandMan::OnRefresh()
|
|
{
|
|
if (!theAPI->IsConnected())
|
|
return;
|
|
|
|
theAPI->ReloadBoxes(true);
|
|
|
|
QMap<QString, CSandBoxPtr> Boxes = theAPI->GetAllBoxes();
|
|
foreach(const CSandBoxPtr & pBox, Boxes) {
|
|
pBox.objectCast<CSandBoxPlus>()->UpdateSize();
|
|
if (theConf->GetBool("Options/ScanStartMenu", true))
|
|
pBox.objectCast<CSandBoxPlus>()->ScanStartMenu();
|
|
}
|
|
}
|
|
|
|
void CSandMan::OnCleanUp()
|
|
{
|
|
if (sender() == m_pCleanUpMsgLog || sender() == m_pCleanUpButton) {
|
|
m_MessageLog.clear();
|
|
if (m_pMessageLog) m_pMessageLog->GetTree()->clear();
|
|
}
|
|
|
|
if (sender() == m_pCleanUpTrace || sender() == m_pCleanUpButton)
|
|
if (m_pTraceView) {
|
|
m_pTraceView->Clear();
|
|
m_pTraceInfo->clear();
|
|
}
|
|
|
|
if (sender() == m_pCleanUpRecovery || sender() == m_pCleanUpButton)
|
|
if(m_pRecoveryLog) m_pRecoveryLog->GetTree()->clear();
|
|
|
|
if (sender() == m_pCleanUpProcesses || sender() == m_pCleanUpButton)
|
|
theAPI->UpdateProcesses(0, ShowAllSessions());
|
|
}
|
|
|
|
void CSandMan::OnProcView()
|
|
{
|
|
if(m_pKeepTerminated) theConf->SetValue("Options/KeepTerminated", m_pKeepTerminated->isChecked());
|
|
if(m_pShowAllSessions) theConf->SetValue("Options/ShowAllSessions", m_pShowAllSessions->isChecked());
|
|
|
|
if (m_pMenuBrowse) {
|
|
theConf->SetValue("Options/ShowFilePanel", m_pMenuBrowse->isChecked());
|
|
m_pFileView->setVisible(m_pMenuBrowse->isChecked());
|
|
|
|
if (m_pMenuBrowse->isChecked()) {
|
|
QTimer::singleShot(10, [&] {
|
|
auto Sizes = m_pPanelSplitter->sizes();
|
|
if (Sizes.at(1) == 0) {
|
|
Sizes[1] = 100;
|
|
m_pPanelSplitter->setSizes(Sizes);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSandMan::OnSettings()
|
|
{
|
|
static CSettingsWindow* pSettingsWindow = NULL;
|
|
if (pSettingsWindow == NULL) {
|
|
pSettingsWindow = new CSettingsWindow();
|
|
connect(this, SIGNAL(Closed()), pSettingsWindow, SLOT(close()));
|
|
connect(pSettingsWindow, SIGNAL(OptionsChanged(bool)), this, SLOT(UpdateSettings(bool)));
|
|
connect(pSettingsWindow, &CSettingsWindow::Closed, [this]() {
|
|
pSettingsWindow = NULL;
|
|
});
|
|
SafeShow(pSettingsWindow);
|
|
}
|
|
else {
|
|
pSettingsWindow->setWindowState((pSettingsWindow->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
|
|
SetForegroundWindow((HWND)pSettingsWindow->winId());
|
|
}
|
|
}
|
|
|
|
// for old menu
|
|
void CSandMan::OnSettingsAction()
|
|
{
|
|
QAction* pAction = qobject_cast<QAction*>(sender());
|
|
|
|
if (pAction == m_pArrangeGroups)
|
|
{
|
|
QMessageBox *msgBox = new QMessageBox(this);
|
|
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
|
msgBox->setWindowTitle("Sandboxie-Plus");
|
|
msgBox->setText(tr("In the Plus UI, this functionality has been integrated into the main sandbox list view."));
|
|
msgBox->setInformativeText(tr("Using the box/group context menu, you can move boxes and groups to other groups. You can also use drag and drop to move the items around. "
|
|
"Alternatively, you can also use the arrow keys while holding ALT down to move items up and down within their group.<br />"
|
|
"You can create new boxes and groups from the Sandbox menu."));
|
|
QPixmap pic(":/Assets/LayoutAndGroups.png");
|
|
msgBox->setIconPixmap(pic.scaled(pic.width() * 3/4, pic.height() * 3/4, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
|
SafeExec(msgBox);
|
|
}
|
|
else
|
|
{
|
|
CSettingsWindow* pSettingsWindow = new CSettingsWindow(this);
|
|
connect(pSettingsWindow, SIGNAL(OptionsChanged(bool)), this, SLOT(UpdateSettings(bool)));
|
|
int Tab = pAction->data().toInt();
|
|
pSettingsWindow->showTab(Tab, true);
|
|
}
|
|
}
|
|
|
|
void CSandMan::UpdateSettings(bool bRebuildUI)
|
|
{
|
|
if(m_pTrayBoxes) m_pTrayBoxes->clear(); // force refresh
|
|
|
|
//GetBoxView()->UpdateRunMenu();
|
|
|
|
SetupHotKeys();
|
|
|
|
if (theConf->GetInt("Options/SysTrayIcon", 1))
|
|
m_pTrayIcon->show();
|
|
else
|
|
m_pTrayIcon->hide();
|
|
|
|
|
|
if (bRebuildUI)
|
|
{
|
|
StoreState();
|
|
|
|
RebuildUI();
|
|
}
|
|
}
|
|
|
|
void CSandMan::RebuildUI()
|
|
{
|
|
LoadLanguage();
|
|
|
|
if(m_pRefreshAll) this->removeAction(m_pRefreshAll);
|
|
if(m_pMenuBrowse) this->removeAction(m_pMenuBrowse);
|
|
if(m_pMenuResetGUI) this->removeAction(m_pMenuResetGUI);
|
|
|
|
m_pMainWidget->deleteLater();
|
|
m_pMainWidget = new QWidget(this);
|
|
setCentralWidget(m_pMainWidget);
|
|
|
|
m_pLabel->deleteLater();
|
|
|
|
CreateUI();
|
|
|
|
m_pTrayMenu->deleteLater();
|
|
CreateTrayMenu();
|
|
|
|
LoadState(false);
|
|
|
|
GetBoxView()->ReloadUserConfig();
|
|
|
|
UpdateState();
|
|
|
|
if(m_pTrayBoxes) m_pTrayBoxes->setStyle(QStyleFactory::create(m_DefaultStyle));
|
|
}
|
|
|
|
void CSandMan::OnResetMsgs()
|
|
{
|
|
auto Ret = QMessageBox("Sandboxie-Plus", tr("Do you also want to reset hidden message boxes (yes), or only all log messages (no)?"),
|
|
QMessageBox::Question, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape, this).exec();
|
|
if (Ret == QMessageBox::Cancel)
|
|
return;
|
|
|
|
if (Ret == QMessageBox::Yes)
|
|
{
|
|
theConf->DelValue("Options/WarnDeleteV2");
|
|
|
|
theConf->DelValue("Options/PortableStop");
|
|
theConf->DelValue("Options/PortableStart");
|
|
theConf->DelValue("Options/PortableRootDir");
|
|
|
|
theConf->DelValue("Options/NoEditInfo");
|
|
theConf->DelValue("Options/NoEditWarn");
|
|
|
|
theConf->DelValue("Options/BoxedExplorerInfo");
|
|
theConf->DelValue("Options/ExplorerInfo");
|
|
|
|
theConf->DelValue("Options/OpenUrlsSandboxed");
|
|
|
|
theConf->DelValue("Options/AutoCleanupTemplates");
|
|
theConf->DelValue("Options/WarnTerminateAll");
|
|
theConf->DelValue("Options/WarnTerminate");
|
|
|
|
theConf->DelValue("Options/InfoMkLink");
|
|
|
|
theConf->DelValue("Options/WarnOpenCOM");
|
|
|
|
theConf->DelValue("Options/WarnWizardOnClose");
|
|
}
|
|
|
|
theAPI->GetUserSettings()->UpdateTextList("SbieCtrl_HideMessage", QStringList(), true);
|
|
m_pPopUpWindow->ReloadHiddenMessages();
|
|
}
|
|
|
|
void CSandMan::OnResetGUI()
|
|
{
|
|
foreach(const QString& Option, theConf->ListKeys("RecoveryWindow"))
|
|
theConf->DelValue("RecoveryWindow/" + Option);
|
|
|
|
foreach(const QString& Option, theConf->ListKeys("MainWindow"))
|
|
theConf->DelValue("MainWindow/" + Option);
|
|
|
|
foreach(const QString& Option, theConf->ListKeys("SettingsWindow"))
|
|
theConf->DelValue("SettingsWindow/" + Option);
|
|
|
|
foreach(const QString& Option, theConf->ListKeys("OptionsWindow"))
|
|
theConf->DelValue("OptionsWindow/" + Option);
|
|
|
|
theConf->DelValue("ErrorWindow/Window_Geometry");
|
|
theConf->DelValue("PopUpWindow/Window_Geometry");
|
|
theConf->DelValue("TraceWindow/Window_Geometry");
|
|
theConf->DelValue("SelectBoxWindow/Window_Geometry");
|
|
theConf->DelValue("SnapshotsWindow/Window_Geometry");
|
|
theConf->DelValue("FileBrowserWindow/Window_Geometry");
|
|
theConf->DelValue("RecoveryLogWindow/Window_Geometry");
|
|
|
|
// theConf->SetValue("Options/DPIScaling", 1);
|
|
theConf->SetValue("Options/FontScaling", 100);
|
|
|
|
RebuildUI();
|
|
}
|
|
|
|
void CSandMan::OnEditIni()
|
|
{
|
|
QString ini = ((QAction*)sender())->property("ini").toString();
|
|
|
|
QString IniPath;
|
|
bool bPlus;
|
|
if (bPlus = (ini == "plus"))
|
|
{
|
|
IniPath = QString(theConf->GetConfigDir() + "/Sandboxie-Plus.ini").replace("/", "\\");
|
|
}
|
|
else if (ini == "tmpl")
|
|
{
|
|
IniPath = theAPI->GetSbiePath() + "\\Templates.ini";
|
|
|
|
if (theConf->GetBool("Options/NoEditWarn", true)) {
|
|
bool State = false;
|
|
CCheckableMessageBox::question(this, "Sandboxie-Plus",
|
|
tr("You are about to edit the Templates.ini, this is generally not recommended.\n"
|
|
"This file is part of Sandboxie and all change done to it will be reverted next time Sandboxie is updated.")
|
|
, tr("Don't show this message again."), &State, QDialogButtonBox::Ok, QDialogButtonBox::Ok, QMessageBox::Warning);
|
|
|
|
if (State)
|
|
theConf->SetValue("Options/NoEditWarn", false);
|
|
}
|
|
}
|
|
else //if (ini == "sbie")
|
|
{
|
|
IniPath = theAPI->GetIniPath();
|
|
|
|
if (theConf->GetBool("Options/NoEditInfo", true)) {
|
|
bool State = false;
|
|
CCheckableMessageBox::question(this, "Sandboxie-Plus",
|
|
theConf->GetBool("Options/WatchIni", true)
|
|
? tr("The changes will be applied automatically whenever the file gets saved.")
|
|
: tr("The changes will be applied automatically as soon as the editor is closed.")
|
|
, tr("Don't show this message again."), &State, QDialogButtonBox::Ok, QDialogButtonBox::Ok, QMessageBox::Information);
|
|
|
|
if (State)
|
|
theConf->SetValue("Options/NoEditInfo", false);
|
|
}
|
|
}
|
|
|
|
bool bIsWritable = bPlus;
|
|
if (!bIsWritable) {
|
|
QFile File(IniPath);
|
|
if (File.open(QFile::ReadWrite)) {
|
|
bIsWritable = true;
|
|
File.close();
|
|
}
|
|
// todo: warn user about file not being protected
|
|
}
|
|
|
|
std::wstring Editor = theConf->GetString("Options/Editor", "notepad.exe").toStdWString();
|
|
std::wstring iniPath = L"\"" + IniPath.toStdWString() + L"\"";
|
|
|
|
SHELLEXECUTEINFO si = { 0 };
|
|
si.cbSize = sizeof(SHELLEXECUTEINFO);
|
|
si.fMask = SEE_MASK_NOCLOSEPROCESS;
|
|
si.hwnd = NULL;
|
|
si.lpVerb = bIsWritable ? NULL : L"runas"; // plus ini does not require admin privileges
|
|
si.lpFile = Editor.c_str();
|
|
si.lpParameters = iniPath.c_str();
|
|
si.lpDirectory = NULL;
|
|
si.nShow = SW_SHOW;
|
|
si.hInstApp = NULL;
|
|
ShellExecuteEx(&si);
|
|
//WaitForSingleObject(si.hProcess, INFINITE);
|
|
//CloseHandle(si.hProcess);
|
|
|
|
if (!bPlus && theConf->GetBool("Options/WatchIni", true))
|
|
return; // if the ini is watched don't double reload
|
|
|
|
QWinEventNotifier* processFinishedNotifier = new QWinEventNotifier(si.hProcess);
|
|
processFinishedNotifier->setEnabled(true);
|
|
connect(processFinishedNotifier, &QWinEventNotifier::activated, this, [processFinishedNotifier, this, si, bPlus]() {
|
|
processFinishedNotifier->setEnabled(false);
|
|
processFinishedNotifier->deleteLater();
|
|
if (bPlus)
|
|
theConf->Sync();
|
|
else
|
|
this->OnReloadIni();
|
|
CloseHandle(si.hProcess);
|
|
});
|
|
}
|
|
|
|
void CSandMan::OnReloadIni()
|
|
{
|
|
theAPI->ReloadConfig(true);
|
|
}
|
|
|
|
void CSandMan::OnIniReloaded()
|
|
{
|
|
OnLogSbieMessage(0, QStringList() << tr("Sandboxie config has been reloaded") << "" << "", 4);
|
|
|
|
m_pBoxView->ReloadUserConfig();
|
|
m_pPopUpWindow->ReloadHiddenMessages();
|
|
|
|
g_FeatureFlags = theAPI->GetFeatureFlags();
|
|
|
|
if (theAPI->GetGlobalSettings()->GetBool("MonitorStackTrace", false)) {
|
|
QString SymPath = theConf->GetString("Options/Debug");
|
|
if (SymPath.isEmpty()){
|
|
SymPath = "SRV*C:\\Symbols*https://msdl.microsoft.com/download/symbols";
|
|
theConf->SetValue("Options/Debug", SymPath);
|
|
}
|
|
CSymbolProvider::Instance()->SetSymPath(SymPath);
|
|
}
|
|
}
|
|
|
|
void CSandMan::OnMonitoring()
|
|
{
|
|
if (m_pTraceView)
|
|
{
|
|
theAPI->EnableMonitor(m_pEnableMonitoring->isChecked());
|
|
|
|
if(m_pEnableMonitoring->isChecked() && !m_pToolBar->isVisible())
|
|
m_pLogTabs->show();
|
|
|
|
if(m_pEnableMonitoring->isChecked())
|
|
m_pKeepTerminated->setChecked(true);
|
|
else
|
|
m_pKeepTerminated->setChecked(theConf->GetBool("Options/KeepTerminated"));
|
|
}
|
|
else
|
|
{
|
|
theAPI->EnableMonitor(true);
|
|
|
|
static CTraceWindow* pTraceWindow = NULL;
|
|
if (!pTraceWindow) {
|
|
pTraceWindow = new CTraceWindow();
|
|
connect(this, SIGNAL(Closed()), pTraceWindow, SLOT(close()));
|
|
//pTraceWindow->setAttribute(Qt::WA_DeleteOnClose);
|
|
connect(pTraceWindow, &CTraceWindow::Closed, [&]() {
|
|
pTraceWindow = NULL;
|
|
});
|
|
SafeShow(pTraceWindow);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSandMan::OnSymbolStatus(const QString& Message)
|
|
{
|
|
statusBar()->showMessage(Message, 30*1000);
|
|
}
|
|
|
|
SB_STATUS CSandMan::AddAsyncOp(const CSbieProgressPtr& pProgress, bool bWait, const QString& InitialMsg, QWidget* pParent)
|
|
{
|
|
m_pAsyncProgress.insert(pProgress.data(), qMakePair(pProgress, pParent));
|
|
connect(pProgress.data(), SIGNAL(Message(const QString&)), this, SLOT(OnAsyncMessage(const QString&)));
|
|
connect(pProgress.data(), SIGNAL(Progress(int)), this, SLOT(OnAsyncProgress(int)));
|
|
connect(pProgress.data(), SIGNAL(Finished()), this, SLOT(OnAsyncFinished()));
|
|
|
|
m_pProgressDialog->OnStatusMessage(InitialMsg);
|
|
if (bWait) {
|
|
m_pProgressModal = true;
|
|
m_pProgressDialog->exec(); // safe exec breaks the closing
|
|
m_pProgressModal = false;
|
|
}
|
|
else
|
|
SafeShow(m_pProgressDialog);
|
|
|
|
if (pProgress->IsFinished()) // Note: since the operation runs asynchronously, it may have already finished, so we need to test for that
|
|
OnAsyncFinished(pProgress.data());
|
|
|
|
if (pProgress->IsCanceled())
|
|
return CSbieStatus(SB_Canceled);
|
|
return SB_OK;
|
|
}
|
|
|
|
void CSandMan::OnAsyncFinished()
|
|
{
|
|
OnAsyncFinished(qobject_cast<CSbieProgress*>(sender()));
|
|
}
|
|
|
|
void CSandMan::OnAsyncFinished(CSbieProgress* pSender)
|
|
{
|
|
auto Pair = m_pAsyncProgress.take(pSender);
|
|
CSbieProgressPtr pProgress = Pair.first;
|
|
if (pProgress.isNull())
|
|
return;
|
|
disconnect(pProgress.data() , SIGNAL(Finished()), this, SLOT(OnAsyncFinished()));
|
|
|
|
SB_STATUS Status = pProgress->GetStatus();
|
|
if(Status.IsError())
|
|
CheckResults(QList<SB_STATUS>() << Status, Pair.second.data());
|
|
|
|
if (m_pAsyncProgress.isEmpty()) {
|
|
if(m_pProgressModal)
|
|
m_pProgressDialog->close();
|
|
else
|
|
m_pProgressDialog->hide();
|
|
}
|
|
}
|
|
|
|
void CSandMan::OnAsyncMessage(const QString& Text)
|
|
{
|
|
m_pProgressDialog->OnStatusMessage(Text);
|
|
}
|
|
|
|
void CSandMan::OnAsyncProgress(int Progress)
|
|
{
|
|
m_pProgressDialog->OnProgressMessage("", Progress);
|
|
}
|
|
|
|
void CSandMan::OnCancelAsync()
|
|
{
|
|
foreach(auto Pair, m_pAsyncProgress)
|
|
Pair.first->Cancel();
|
|
}
|
|
|
|
QString CSandMan::FormatError(const SB_STATUS& Error)
|
|
{
|
|
//QString Text = Error.GetText();
|
|
//if (!Text.isEmpty())
|
|
// return Text;
|
|
|
|
QString Message;
|
|
switch (Error.GetMsgCode())
|
|
{
|
|
case SB_Generic: return tr("Error Status: 0x%1 (%2)").arg((quint32)Error.GetStatus(), 8, 16, QChar('0')).arg(
|
|
(Error.GetArgs().isEmpty() || Error.GetArgs().first().toString().isEmpty()) ? tr("Unknown") : Error.GetArgs().first().toString().trimmed());
|
|
case SB_Message: Message = "%1"; break;
|
|
case SB_NeedAdmin: Message = tr("Administrator rights are required for this operation."); break;
|
|
case SB_ExecFail: Message = tr("Failed to execute: %1"); break;
|
|
case SB_DriverFail: Message = tr("Failed to connect to the driver"); break;
|
|
case SB_ServiceFail: Message = tr("Failed to communicate with Sandboxie Service: %1"); break;
|
|
case SB_Incompatible: Message = tr("An incompatible Sandboxie %1 was found. Compatible versions: %2"); break;
|
|
case SB_PathFail: Message = tr("Can't find Sandboxie installation path."); break;
|
|
case SB_FailedCopyConf: Message = tr("Failed to copy configuration from sandbox %1: %2"); break;
|
|
case SB_AlreadyExists: Message = tr("A sandbox of the name %1 already exists"); break;
|
|
case SB_DeleteFailed: Message = tr("Failed to delete sandbox %1: %2"); break;
|
|
case SB_NameLenLimit: Message = tr("The sandbox name can not be longer than 32 characters."); break;
|
|
case SB_BadNameDev: Message = tr("The sandbox name can not be a device name."); break;
|
|
case SB_BadNameChar: Message = tr("The sandbox name can contain only letters, digits and underscores which are displayed as spaces."); break;
|
|
case SB_FailedKillAll: Message = tr("Failed to terminate all processes"); break;
|
|
case SB_DeleteProtect: Message = tr("Delete protection is enabled for the sandbox"); break;
|
|
case SB_DeleteNotEmpty: Message = tr("All sandbox processes must be stopped before the box content can be deleted"); break;
|
|
case SB_DeleteError: Message = tr("Error deleting sandbox folder: %1"); break;
|
|
case SB_RemNotStopped: Message = tr("All processes in a sandbox must be stopped before it can be renamed."); break;
|
|
//case SB_RemNotEmpty: Message = tr("A sandbox must be emptied before it can be renamed."); break;
|
|
case SB_DelNotEmpty: Message = tr("A sandbox must be emptied before it can be deleted."); break;
|
|
case SB_FailedMoveDir: Message = tr("Failed to move directory '%1' to '%2'"); break;
|
|
case SB_FailedMoveImage:Message = tr("Failed to move box image '%1' to '%2'"); break;
|
|
case SB_SnapIsRunning: Message = tr("This Snapshot operation can not be performed while processes are still running in the box."); break;
|
|
case SB_SnapMkDirFail: Message = tr("Failed to create directory for new snapshot"); break;
|
|
case SB_SnapCopyDatFail:Message = tr("Failed to copy box data files"); break;
|
|
case SB_SnapNotFound: Message = tr("Snapshot not found"); break;
|
|
case SB_SnapMergeFail: Message = tr("Error merging snapshot directories '%1' with '%2', the snapshot has not been fully merged."); break;
|
|
case SB_SnapRmDirFail: Message = tr("Failed to remove old snapshot directory '%1'"); break;
|
|
case SB_SnapIsShared: Message = tr("Can't remove a snapshot that is shared by multiple later snapshots"); break;
|
|
case SB_SnapDelDatFail: Message = tr("Failed to remove old box data files"); break;
|
|
case SB_NotAuthorized: Message = tr("You are not authorized to update configuration in section '%1'"); break;
|
|
case SB_ConfigFailed: Message = tr("Failed to set configuration setting %1 in section %2: %3"); break;
|
|
case SB_SnapIsEmpty: Message = tr("Can not create snapshot of an empty sandbox"); break;
|
|
case SB_NameExists: Message = tr("A sandbox with that name already exists"); break;
|
|
case SB_PasswordBad: Message = tr("The config password must not be longer than 64 characters"); break;
|
|
case SB_Canceled: Message = tr("The operation was canceled by the user"); break;
|
|
case SB_DeleteNoMount: Message = tr("The content of an unmounted sandbox can not be deleted"); break;
|
|
|
|
case SB_OtherError: Message = tr("%1"); break;
|
|
|
|
case SBX_7zNotReady: Message = tr("Import/Export not available, 7z.dll could not be loaded"); break;
|
|
case SBX_7zCreateFailed: Message = tr("Failed to create the box archive"); break;
|
|
case SBX_7zOpenFailed: Message = tr("Failed to open the 7z archive"); break;
|
|
case SBX_7zExtractFailed: Message = tr("Failed to unpack the box archive"); break;
|
|
case SBX_NotBoxArchive: Message = tr("The selected 7z file is NOT a box archive"); break;
|
|
|
|
default: return tr("Unknown Error Status: 0x%1").arg((quint32)Error.GetStatus(), 8, 16, QChar('0'));
|
|
}
|
|
|
|
foreach(const QVariant& Arg, Error.GetArgs())
|
|
Message = Message.arg(Arg.toString()); // todo: make quint32 hex and so on
|
|
|
|
return Message;
|
|
}
|
|
|
|
void CSandMan::CheckResults(QList<SB_STATUS> Results, QWidget* pParent, bool bAsync)
|
|
{
|
|
QStringList Errors;
|
|
for (QList<SB_STATUS>::iterator I = Results.begin(); I != Results.end(); ++I) {
|
|
if (I->IsError() && I->GetStatus() != OP_CANCELED)
|
|
Errors.append(FormatError(*I));
|
|
}
|
|
|
|
if (bAsync) {
|
|
foreach(const QString &Error, Errors)
|
|
theGUI->OnLogMessage(Error, true);
|
|
}
|
|
else if (Errors.count() == 1)
|
|
QMessageBox::warning(pParent ? pParent : this, tr("Sandboxie-Plus - Error"), Errors.first());
|
|
else if (Errors.count() > 1) {
|
|
CMultiErrorDialog Dialog(tr("Operation failed for %1 item(s).").arg(Errors.size()), Errors, pParent ? pParent : this);
|
|
Dialog.exec();
|
|
}
|
|
}
|
|
|
|
void CSandMan::OnBoxAssistant()
|
|
{
|
|
CBoxAssistant::ShowAssistant();
|
|
}
|
|
|
|
void CSandMan::OpenUrl(const QUrl& url)
|
|
{
|
|
QString scheme = url.scheme();
|
|
QString host = url.host();
|
|
QString path = url.path();
|
|
QString query = url.query();
|
|
|
|
if (scheme == "addon") {
|
|
m_AddonManager->TryInstallAddon(host, qobject_cast<QWidget*>(sender()));
|
|
return;
|
|
}
|
|
|
|
if (scheme == "sbie") {
|
|
if (path == "/check")
|
|
m_pUpdater->CheckForUpdates(true);
|
|
else if (path == "/installer")
|
|
m_pUpdater->RunInstaller(false);
|
|
else if (path == "/apply")
|
|
m_pUpdater->ApplyUpdate(false);
|
|
else if (path == "/cert")
|
|
m_pUpdater->UpdateCert();
|
|
else
|
|
OpenUrl("https://sandboxie-plus.com/sandboxie" + path);
|
|
return;
|
|
}
|
|
|
|
int iSandboxed = theConf->GetInt("Options/OpenUrlsSandboxed", 2);
|
|
|
|
if (iSandboxed == 2)
|
|
{
|
|
bool bCheck = false;
|
|
QString Message = tr("Do you want to open %1 in a sandboxed (yes) or unsandboxed (no) Web browser?").arg(url.toString());
|
|
QDialogButtonBox::StandardButton Ret = CCheckableMessageBox::question(this, "Sandboxie-Plus", Message , tr("Remember choice for later."),
|
|
&bCheck, QDialogButtonBox::Yes | QDialogButtonBox::No | QDialogButtonBox::Cancel, QDialogButtonBox::Yes, QMessageBox::Question);
|
|
if (Ret == QDialogButtonBox::Cancel) return;
|
|
iSandboxed = Ret == QDialogButtonBox::Yes ? 1 : 0;
|
|
if(bCheck) theConf->SetValue("Options/OpenUrlsSandboxed", iSandboxed);
|
|
}
|
|
|
|
if (iSandboxed) RunSandboxed(QStringList(url.toString()));
|
|
else ShellExecute(MainWndHandle, NULL, url.toString().toStdWString().c_str(), NULL, NULL, SW_SHOWNORMAL);
|
|
}
|
|
|
|
bool CSandMan::IsWFPEnabled() const
|
|
{
|
|
return (g_FeatureFlags & CSbieAPI::eSbieFeatureWFP) != 0;
|
|
}
|
|
|
|
QString CSandMan::GetVersion()
|
|
{
|
|
QString Version = QString::number(VERSION_MJR) + "." + QString::number(VERSION_MIN) //.rightJustified(2, '0')
|
|
//#if VERSION_REV > 0 || VERSION_MJR == 0
|
|
+ "." + QString::number(VERSION_REV)
|
|
//#endif
|
|
#if VERSION_UPD > 0
|
|
+ QChar('a' + VERSION_UPD - 1)
|
|
#endif
|
|
;
|
|
return Version;
|
|
}
|
|
|
|
void CSandMan::SetUITheme()
|
|
{
|
|
m_ThemeUpdatePending = false;
|
|
|
|
|
|
bool bDark;
|
|
int iDark = theConf->GetInt("Options/UseDarkTheme", 2);
|
|
if (iDark == 2) {
|
|
QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", QSettings::NativeFormat);
|
|
bDark = (settings.value("AppsUseLightTheme") == 0);
|
|
} else
|
|
bDark = (iDark == 1);
|
|
|
|
if (bDark)
|
|
QApplication::setPalette(m_DarkPalett);
|
|
else
|
|
QApplication::setPalette(m_DefaultPalett);
|
|
m_DarkTheme = bDark;
|
|
|
|
|
|
bool bFusion;
|
|
int iFusion = theConf->GetInt("Options/UseFusionTheme", 2);
|
|
if (iFusion == 2)
|
|
bFusion = bDark;
|
|
else
|
|
bFusion = (iFusion == 1);
|
|
|
|
if (bFusion)
|
|
QApplication::setStyle(QStyleFactory::create("Fusion"));
|
|
else {
|
|
int iViewMode = theConf->GetInt("Options/ViewMode", 1);
|
|
QApplication::setStyle(QStyleFactory::create((bDark || iViewMode == 2) ? "Windows" : m_DefaultStyle));
|
|
}
|
|
m_FusionTheme = bFusion;
|
|
|
|
|
|
CTreeItemModel::SetDarkMode(bDark);
|
|
//CListItemModel::SetDarkMode(bDark); // not used
|
|
CPopUpWindow::SetDarkMode(bDark);
|
|
CPanelView::SetDarkMode(bDark);
|
|
CFinder::SetDarkMode(bDark);
|
|
|
|
|
|
QFont font = QApplication::font();
|
|
double newFontSize = m_DefaultFontSize * theConf->GetInt("Options/FontScaling", 100) / 100.0;
|
|
if (newFontSize != font.pointSizeF()) {
|
|
font.setPointSizeF(newFontSize);
|
|
QApplication::setFont(font);
|
|
}
|
|
|
|
#if defined(Q_OS_WIN)
|
|
foreach(QWidget * pWidget, QApplication::topLevelWidgets())
|
|
{
|
|
if (pWidget->isVisible())
|
|
SetTitleTheme((HWND)pWidget->winId());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CSandMan::SetTitleTheme(const HWND& hwnd)
|
|
{
|
|
static const int CurrentVersion = QSettings("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
|
|
QSettings::NativeFormat).value("CurrentBuild").toInt();
|
|
if (CurrentVersion < 17763) // Windows 10 1809 -
|
|
return;
|
|
|
|
HMODULE dwmapi = GetModuleHandle(L"dwmapi.dll");
|
|
if (dwmapi)
|
|
{
|
|
typedef HRESULT(WINAPI* P_DwmSetWindowAttribute)(HWND, DWORD, LPCVOID, DWORD);
|
|
P_DwmSetWindowAttribute pDwmSetWindowAttribute = reinterpret_cast<P_DwmSetWindowAttribute>(GetProcAddress(dwmapi, "DwmSetWindowAttribute"));
|
|
if (pDwmSetWindowAttribute)
|
|
{
|
|
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1
|
|
#define DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 19
|
|
#endif
|
|
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
|
|
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
|
|
#endif
|
|
BOOL bDark = m_DarkTheme;
|
|
pDwmSetWindowAttribute(hwnd,
|
|
CurrentVersion >= 18985 ? DWMWA_USE_IMMERSIVE_DARK_MODE : DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1,
|
|
&bDark,
|
|
sizeof(bDark));
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSandMan::UpdateTheme()
|
|
{
|
|
if (!m_ThemeUpdatePending)
|
|
{
|
|
m_ThemeUpdatePending = true;
|
|
QTimer::singleShot(500, this, SLOT(SetUITheme()));
|
|
}
|
|
}
|
|
|
|
void CSandMan::UpdateTitleTheme(const HWND& hwnd)
|
|
{
|
|
SetTitleTheme(hwnd);
|
|
}
|
|
|
|
void CSandMan::LoadLanguage()
|
|
{
|
|
m_Language = theConf->GetString("Options/UiLanguage");
|
|
if(m_Language.isEmpty())
|
|
m_Language = QLocale::system().name();
|
|
|
|
if (m_Language.compare("native", Qt::CaseInsensitive) == 0)
|
|
#ifdef _DEBUG
|
|
m_Language = "en";
|
|
#else
|
|
m_Language.clear();
|
|
#endif
|
|
|
|
m_LanguageId = LocaleNameToLCID(m_Language.toStdWString().c_str(), 0);
|
|
if (!m_LanguageId)
|
|
m_LanguageId = 1033; // default to English
|
|
|
|
LoadLanguage(m_Language, "sandman", 0);
|
|
LoadLanguage(m_Language, "qt", 1);
|
|
|
|
QTreeViewEx::m_ResetColumns = tr("Reset Columns");
|
|
CPanelView::m_CopyCell = tr("Copy Cell");
|
|
CPanelView::m_CopyRow = tr("Copy Row");
|
|
CPanelView::m_CopyPanel = tr("Copy Panel");
|
|
CFinder::m_CaseInsensitive = tr("Case Sensitive");
|
|
CFinder::m_RegExpStr = tr("RegExp");
|
|
CFinder::m_Highlight = tr("Highlight");
|
|
CFinder::m_CloseStr = tr("Close");
|
|
CFinder::m_FindStr = tr("&Find ...");
|
|
CFinder::m_AllColumns = tr("All columns");
|
|
}
|
|
|
|
void CSandMan::LoadLanguage(const QString& Lang, const QString& Module, int Index)
|
|
{
|
|
qApp->removeTranslator(&m_Translator[Index]);
|
|
|
|
if (Lang.isEmpty())
|
|
return;
|
|
|
|
QString LangAux = Lang; // Short version as fallback
|
|
LangAux.truncate(LangAux.lastIndexOf('_'));
|
|
|
|
QString LangDir;
|
|
C7zFileEngineHandler LangFS("lang", this);
|
|
if (LangFS.Open(QApplication::applicationDirPath() + "/translations.7z"))
|
|
LangDir = LangFS.Prefix() + "/";
|
|
else
|
|
LangDir = QApplication::applicationDirPath() + "/translations/";
|
|
|
|
QString LangPath = LangDir + Module + "_";
|
|
bool bAux = false;
|
|
if (QFile::exists(LangPath + Lang + ".qm") || (bAux = QFile::exists(LangPath + LangAux + ".qm")))
|
|
{
|
|
if(m_Translator[Index].load(LangPath + (bAux ? LangAux : Lang) + ".qm", LangDir))
|
|
qApp->installTranslator(&m_Translator[Index]);
|
|
}
|
|
}
|
|
|
|
void CSandMan::OnHelp()
|
|
{
|
|
//if (sender() == m_pSupport)
|
|
// QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=donate"));
|
|
//else
|
|
if (sender() == m_pContribution)
|
|
QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=sbie-contribute"));
|
|
else if (sender() == m_pManual)
|
|
QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=sbie-docs"));
|
|
else if (sender() == m_pForum)
|
|
QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=sbie-forum"));
|
|
else
|
|
QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=patreon"));
|
|
}
|
|
|
|
void CSandMan::OnAbout()
|
|
{
|
|
if (sender() == m_pAbout)
|
|
{
|
|
QString AboutCaption = tr(
|
|
"<h3>About Sandboxie-Plus</h3>"
|
|
"<p>Version %1</p>"
|
|
"<p>Copyright (c) 2020-2023 by DavidXanatos</p>"
|
|
).arg(theGUI->GetVersion());
|
|
|
|
QString CertInfo;
|
|
if (!g_Certificate.isEmpty()) {
|
|
CertInfo = tr("This copy of Sandboxie+ is certified for: %1").arg(GetArguments(g_Certificate, L'\n', L':').value("NAME"));
|
|
} else {
|
|
CertInfo = tr("Sandboxie+ is free for personal and non-commercial use.");
|
|
}
|
|
|
|
QString AboutText = tr(
|
|
"Sandboxie-Plus is an open source continuation of Sandboxie.<br />"
|
|
"Visit <a href=\"https://sandboxie-plus.com\">sandboxie-plus.com</a> for more information.<br />"
|
|
"<br />"
|
|
"%3<br />"
|
|
"<br />"
|
|
"Driver version: %1<br />"
|
|
"Features: %2<br />"
|
|
"<br />"
|
|
"Icons from <a href=\"https://icons8.com\">icons8.com</a>"
|
|
).arg(theAPI->GetVersion()).arg(theAPI->GetFeatureStr()).arg(CertInfo);
|
|
|
|
QMessageBox *msgBox = new QMessageBox(this);
|
|
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
|
msgBox->setWindowTitle(tr("About Sandboxie-Plus"));
|
|
msgBox->setText(AboutCaption);
|
|
msgBox->setInformativeText(AboutText);
|
|
|
|
QIcon ico(QLatin1String(":/SandMan.png"));
|
|
msgBox->setIconPixmap(ico.pixmap(128, 128));
|
|
|
|
SafeExec(msgBox);
|
|
}
|
|
else if (sender() == m_pAboutQt)
|
|
QMessageBox::aboutQt(this);
|
|
}
|
|
|
|
// Make sure that QPlatformTheme strings won't be marked as vanished in all .ts files, even after running lupdate
|
|
|
|
static const char* platform_strings[] = {
|
|
QT_TRANSLATE_NOOP("QPlatformTheme", "OK"),
|
|
QT_TRANSLATE_NOOP("QPlatformTheme", "Apply"),
|
|
QT_TRANSLATE_NOOP("QPlatformTheme", "Cancel"),
|
|
QT_TRANSLATE_NOOP("QPlatformTheme", "&Yes"),
|
|
QT_TRANSLATE_NOOP("QPlatformTheme", "&No"),
|
|
};
|
|
|
|
// Make sure that CSandBox strings won't be marked as vanished in all .ts files, even after running lupdate
|
|
|
|
static const char* CSandBox_strings[] = {
|
|
QT_TRANSLATE_NOOP("CSandBox", "Waiting for folder: %1"),
|
|
QT_TRANSLATE_NOOP("CSandBox", "Deleting folder: %1"),
|
|
QT_TRANSLATE_NOOP("CSandBox", "Merging folders: %1 >> %2"),
|
|
QT_TRANSLATE_NOOP("CSandBox", "Finishing Snapshot Merge..."),
|
|
};
|
|
|
|
|
|
#include "SbieFindWnd.cpp"
|