diff --git a/comphelper/source/misc/backupfilehelper.cxx b/comphelper/source/misc/backupfilehelper.cxx
index 518a5e954b00..dd0c1ef3100b 100644
--- a/comphelper/source/misc/backupfilehelper.cxx
+++ b/comphelper/source/misc/backupfilehelper.cxx
@@ -225,6 +225,18 @@ namespace
return false;
}
+ bool dirExists(const OUString& rDirURL)
+ {
+ if (!rDirURL.isEmpty())
+ {
+ osl::Directory aDirectory(rDirURL);
+
+ return (osl::FileBase::E_None == aDirectory.open());
+ }
+
+ return false;
+ }
+
void scanDirsAndFiles(
const OUString& rDirURL,
std::set< OUString >& rDirs,
@@ -269,6 +281,39 @@ namespace
}
}
}
+
+ bool deleteDirRecursively(const OUString& rDirURL)
+ {
+ std::set< OUString > aDirs;
+ std::set< std::pair< OUString, OUString > > aFiles;
+
+ scanDirsAndFiles(
+ rDirURL,
+ aDirs,
+ aFiles);
+
+ for (const auto& dir : aDirs)
+ {
+ const OUString aNewDirURL(rDirURL + "/" + dir);
+
+ deleteDirRecursively(aNewDirURL);
+ }
+
+ for (const auto& file : aFiles)
+ {
+ OUString aNewFileURL(rDirURL + "/" + file.first);
+
+ if (!file.second.isEmpty())
+ {
+ aNewFileURL += ".";
+ aNewFileURL += file.second;
+ }
+
+ osl::File::remove(aNewFileURL);
+ }
+
+ return osl::FileBase::E_None == osl::Directory::remove(rDirURL);
+ }
}
namespace
@@ -434,6 +479,11 @@ namespace
return true;
}
+
+ bool isEnabled() const
+ {
+ return REGISTERED == meState;
+ }
};
typedef ::std::vector< ExtensionInfoEntry > ExtensionInfoEntryVector;
@@ -578,6 +628,91 @@ namespace
return bRetval;
}
+
+ bool areThereEnabledExtensions() const
+ {
+ for (const auto& a : maEntries)
+ {
+ if (a.isEnabled())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ static void disableAll()
+ {
+ // create content from current extension configuration
+ uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
+ uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ uno::Reference< deployment::XExtensionManager > m_xExtensionManager = deployment::ExtensionManager::get(xContext);
+
+ try
+ {
+ xAllPackages = m_xExtensionManager->getAllExtensions(uno::Reference< task::XAbortChannel >(),
+ uno::Reference< ucb::XCommandEnvironment >());
+ }
+ catch (const deployment::DeploymentException &)
+ {
+ return;
+ }
+ catch (const ucb::CommandFailedException &)
+ {
+ return;
+ }
+ catch (const ucb::CommandAbortedException &)
+ {
+ return;
+ }
+ catch (const lang::IllegalArgumentException & e)
+ {
+ throw uno::RuntimeException(e.Message, e.Context);
+ }
+
+ for (sal_Int32 i = 0; i < xAllPackages.getLength(); ++i)
+ {
+ uno::Sequence< uno::Reference< deployment::XPackage > > xPackageList = xAllPackages[i];
+
+ for (sal_Int32 j = 0; j < xPackageList.getLength(); ++j)
+ {
+ uno::Reference< deployment::XPackage > xPackage = xPackageList[j];
+
+ if (xPackage.is())
+ {
+ const beans::Optional< beans::Ambiguous< sal_Bool > > option(
+ xPackage->isRegistered(uno::Reference< task::XAbortChannel >(),
+ uno::Reference< ucb::XCommandEnvironment >()));
+ bool bEnabled(false);
+
+ if (option.IsPresent)
+ {
+ ::beans::Ambiguous< sal_Bool > const& reg = option.Value;
+
+ if (!reg.IsAmbiguous)
+ {
+ bEnabled = reg.Value;
+ }
+ }
+
+ if (bEnabled)
+ {
+ try
+ {
+ m_xExtensionManager->disableExtension(
+ xPackage,
+ uno::Reference< task::XAbortChannel >(),
+ uno::Reference< ucb::XCommandEnvironment >());
+ }
+ catch (const ::ucb::CommandAbortedException &)
+ {
+ }
+ }
+ }
+ }
+ }
+ }
};
}
@@ -1272,7 +1407,7 @@ namespace comphelper
maDirs(),
maFiles(),
mnNumBackups(2),
- mnMode(0),
+ mnMode(1),
mbActive(false),
mbExtensions(true),
mbCompress(true)
@@ -1386,12 +1521,20 @@ namespace comphelper
maUserConfigBaseURL,
aPackURL);
}
+ }
- // Try Push of ExtensionInfo
- if (mbExtensions)
- {
- bDidPush |= tryPush_extensionInfo(aPackURL);
- }
+ return bDidPush;
+ }
+
+ bool BackupFileHelper::tryPushExtensionInfo()
+ {
+ bool bDidPush(false);
+
+ if (mbActive && mbExtensions)
+ {
+ const OUString aPackURL(getPackURL());
+
+ bDidPush = tryPush_extensionInfo(aPackURL);
}
return bDidPush;
@@ -1417,12 +1560,20 @@ namespace comphelper
maUserConfigBaseURL,
aPackURL);
}
+ }
- // try for ExtensionInfo
- if (mbExtensions)
- {
- bPopPossible |= isPopPossible_extensionInfo(aPackURL);
- }
+ return bPopPossible;
+ }
+
+ bool BackupFileHelper::isPopPossibleExtensionInfo()
+ {
+ bool bPopPossible(false);
+
+ if (mbActive && mbExtensions)
+ {
+ const OUString aPackURL(getPackURL());
+
+ bPopPossible = isPopPossible_extensionInfo(aPackURL);
}
return bPopPossible;
@@ -1449,11 +1600,25 @@ namespace comphelper
aPackURL);
}
- // try for ExtensionInfo
- if (mbExtensions)
+ if (bDidPop)
{
- bDidPop |= tryPop_extensionInfo(aPackURL);
+ // try removal of evtl. empty directory
+ osl::Directory::remove(aPackURL);
}
+ }
+
+ return bDidPop;
+ }
+
+ bool BackupFileHelper::tryPopExtensionInfo()
+ {
+ bool bDidPop(false);
+
+ if (mbActive && mbExtensions)
+ {
+ const OUString aPackURL(getPackURL());
+
+ bDidPop = tryPop_extensionInfo(aPackURL);
if (bDidPop)
{
@@ -1465,6 +1630,53 @@ namespace comphelper
return bDidPop;
}
+ bool BackupFileHelper::isTryDisableAllExtensionsPossible()
+ {
+ // return true if there is an eabled extension that can be disabled
+ ExtensionInfo aCurrentExtensionInfo;
+
+ aCurrentExtensionInfo.createCurrent();
+ return aCurrentExtensionInfo.areThereEnabledExtensions();
+ }
+
+ void BackupFileHelper::tryDisableAllExtensions()
+ {
+ // disable all still enabled extensions. No need to
+ // createCurrent() again, just do it now
+ ExtensionInfo::disableAll();
+ }
+
+ bool BackupFileHelper::isTryResetCustomizationsPossible()
+ {
+ // return true if not all of the customization selection dirs are deleted
+ return
+ dirExists(maUserConfigBaseURL + "/config") || // UI config stuff
+ dirExists(maUserConfigBaseURL + "/registry") || // most of the registry stuff
+ dirExists(maUserConfigBaseURL + "/psprint") || // not really needed, can be abandoned
+ dirExists(maUserConfigBaseURL + "/store") || // not really needed, can be abandoned
+ dirExists(maUserConfigBaseURL + "/temp") || // not really needed, can be abandoned
+ dirExists(maUserConfigBaseURL + "/pack") || // own backup dir
+ fileExists(maUserConfigBaseURL + "/registrymodifications.xcu"); // personal registry stuff
+ }
+
+ void BackupFileHelper::tryResetCustomizations()
+ {
+ // delete all of the customization selection dirs
+ deleteDirRecursively(maUserConfigBaseURL + "/config");
+ deleteDirRecursively(maUserConfigBaseURL + "/registry");
+ deleteDirRecursively(maUserConfigBaseURL + "/psprint");
+ deleteDirRecursively(maUserConfigBaseURL + "/store");
+ deleteDirRecursively(maUserConfigBaseURL + "/temp");
+ deleteDirRecursively(maUserConfigBaseURL + "/pack");
+ osl::File::remove(maUserConfigBaseURL + "/registrymodifications.xcu");
+ }
+
+ void BackupFileHelper::tryResetUserProfile()
+ {
+ // completely delete the current UserProfile
+ deleteDirRecursively(maUserConfigBaseURL);
+ }
+
/////////////////// helpers ///////////////////////
const rtl::OUString BackupFileHelper::getPackURL() const
@@ -1839,25 +2051,29 @@ namespace comphelper
return;
}
+ // Information about the configuration and the role/purpose of directories in
+ // the UserConfiguration is taken from: https://wiki.documentfoundation.org/UserProfile
+
// fill dir and file info list to work with dependent on work mode
switch (mnMode)
{
case 0:
{
- // add registrymodifications (the orig file in maInitialBaseURL)
+ // simple mode: add just registrymodifications
+ // (the orig file in maInitialBaseURL)
maFiles.insert(std::pair< OUString, OUString >(maRegModName, maExt));
break;
}
case 1:
{
- // add registrymodifications (the orig file in maInitialBaseURL)
- maFiles.insert(std::pair< OUString, OUString >(maRegModName, maExt));
-
- // Add a selection of dirs containing User-Defined and thus
- // valuable configuration information (see https://wiki.documentfoundation.org/UserProfile).
+ // defined mode: Add a selection of dirs containing User-Defined and thus
+ // valuable configuration information.
// This is clearly discussable in every single point and may be adapted/corrected
// over time. Main focus is to secure User-Defined/adapted values
+ // add registrymodifications (the orig file in maInitialBaseURL)
+ maFiles.insert(std::pair< OUString, OUString >(maRegModName, maExt));
+
// User-defined substitution table (Tools/AutoCorrect)
maDirs.insert("autocorr");
@@ -1891,6 +2107,7 @@ namespace comphelper
// Questionable - where and how is Extension stuff held and how
// does this interact with enabled/disabled states which are extra handled?
// Keep out of business until deeper evaluated
+ //
// maDirs.insert("extensions");
// maDirs.insert("uno-packages");
break;
@@ -1913,6 +2130,10 @@ namespace comphelper
// not really needed, can be abandoned
maDirs.erase("temp");
+
+ // exclude own backup dir to avoid recursion
+ maDirs.erase("pack");
+
break;
}
}
diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index cd3fbfa96326..6be6d6139bfa 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -951,64 +951,23 @@ void Desktop::HandleBootstrapErrors(
}
else if ( aBootstrapError == BE_OFFICECONFIG_BROKEN )
{
- bool bFireOriginalError(true);
- comphelper::BackupFileHelper aBackupFileHelper;
-
- // crerate BackupFileHelper and check if active and if pop is possible
- if (aBackupFileHelper.isPopPossible())
- {
- // for linux (and probably others?) we need to instantiate XDesktop2
- // to be able to open a *.ui-file based dialog, so do this here locally.
- // does no harm on win, so better always do this (in error case only anyways)
- Reference< XComponentContext > xLocalContext = ::comphelper::getProcessComponentContext();
- Reference< XDesktop2 > xDesktop = css::frame::Desktop::create(xLocalContext);
-
- ScopedVclPtrInstance< MessageDialog > aQueryShouldRestore(
- Application::GetDefDialogParent(),
- "QueryTryToRestoreConfigurationDialog",
- "desktop/ui/querytrytorestoreconfigurationdialog.ui");
-
- if (aQueryShouldRestore.get())
- {
- if (!aErrorMessage.isEmpty())
- {
- OUString aPrimaryText(aQueryShouldRestore->get_primary_text());
-
- aPrimaryText += "\n(\"" + aErrorMessage + "\")";
- aQueryShouldRestore->set_primary_text(aPrimaryText);
- }
-
- if (RET_YES == aQueryShouldRestore->Execute())
- {
- aBackupFileHelper.tryPop();
- bFireOriginalError = false;
- }
- }
- }
-
// set flag at BackupFileHelper to be able to know if _exit was called and
// actions are executed after this. This method we are in will not return,
// but end up in a _exit() call
comphelper::BackupFileHelper::setExitWasCalled();
- if (bFireOriginalError)
- {
- OUString msg(
- GetMsgString(
- STR_CONFIG_ERR_ACCESS_GENERAL,
- ("A general error occurred while accessing your central"
- " configuration.")));
- if (!aErrorMessage.isEmpty()) {
- msg += "\n(\"" + aErrorMessage + "\")";
- }
- FatalError(MakeStartupErrorMessage(msg));
- }
- else
- {
- // Already presented all information to the user.
- // just do what FatalError does at it's end
- _exit(EXITHELPER_FATAL_ERROR);
+ // enter safe mode, too
+ sfx2::SafeMode::putFlag();
+
+ OUString msg(
+ GetMsgString(
+ STR_CONFIG_ERR_ACCESS_GENERAL,
+ ("A general error occurred while accessing your central"
+ " configuration. SafeMode is initiated.")));
+ if (!aErrorMessage.isEmpty()) {
+ msg += "\n(\"" + aErrorMessage + "\")";
}
+ FatalError(MakeStartupErrorMessage(msg));
}
else if ( aBootstrapError == BE_USERINSTALL_FAILED )
{
@@ -1824,6 +1783,7 @@ int Desktop::doShutdown()
comphelper::BackupFileHelper aBackupFileHelper;
aBackupFileHelper.tryPush();
+ aBackupFileHelper.tryPushExtensionInfo();
}
// The acceptors in the AcceptorMap must be released (in DeregisterServices)
diff --git a/desktop/uiconfig/ui/querytrytorestoreconfigurationdialog.ui b/desktop/uiconfig/ui/querytrytorestoreconfigurationdialog.ui
deleted file mode 100644
index 4c332d1889d6..000000000000
--- a/desktop/uiconfig/ui/querytrytorestoreconfigurationdialog.ui
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
diff --git a/include/comphelper/backupfilehelper.hxx b/include/comphelper/backupfilehelper.hxx
index b1913f901822..24978c7a8706 100644
--- a/include/comphelper/backupfilehelper.hxx
+++ b/include/comphelper/backupfilehelper.hxx
@@ -106,15 +106,21 @@ namespace comphelper
*
* @return bool
* returns true if a new backup was actually created
+ *
+ * tryPushExtensionInfo is the specialized version for ExtensionInfo
*/
bool tryPush();
+ bool tryPushExtensionInfo();
/** finds out if a restore is possible
*
* @return bool
* returns true if a restore to an older backup is possible
+ *
+ * isPopPossibleExtensionInfo is the specialized version for ExtensionInfo
*/
bool isPopPossible();
+ bool isPopPossibleExtensionInfo();
/** tries to execute a restore. Will overwrite the base file
* in that case and take one version off the 'stack' of copies.
@@ -123,8 +129,25 @@ namespace comphelper
*
* @return bool
* returns true if a restore was actually created
+ *
+ * tryPopExtensionInfo is the specialized version for ExtensionInfo
*/
bool tryPop();
+ bool tryPopExtensionInfo();
+
+ /** tries to iterate the extensions and to disable all of them
+ */
+ static bool isTryDisableAllExtensionsPossible();
+ static void tryDisableAllExtensions();
+
+ /** resets User-Customizations like Settings and UserInterface modifications
+ */
+ bool isTryResetCustomizationsPossible();
+ void tryResetCustomizations();
+
+ /** resets the whole UserProfile
+ */
+ void tryResetUserProfile();
private:
// internal helper methods
diff --git a/instsetoo_native/CustomTarget_setup.mk b/instsetoo_native/CustomTarget_setup.mk
index 5ce472632cdf..2b9429c3c9f6 100644
--- a/instsetoo_native/CustomTarget_setup.mk
+++ b/instsetoo_native/CustomTarget_setup.mk
@@ -108,7 +108,7 @@ $(call gb_CustomTarget_get_workdir,instsetoo_native/setup)/$(call gb_Helper_get_
# SecureUserConfig : boolean - switches securing on/off - default false
# SecureUserConfigCompress : boolean - defines if backup data will be compressed - default true
# SecureUserConfigNumCopies : integer - defines how many compressed copies of saved content will be kept - default 2
-# SecureUserConfigMode: integer - defines what to secure, default is 0
+# SecureUserConfigMode: integer - defines what to secure, default is 1
# 0 : only registrymodifications.xcu
# 1 : a selected amount of user-defined configs
# 2 : everything in the user config directory
@@ -131,7 +131,7 @@ $(call gb_CustomTarget_get_workdir,instsetoo_native/setup)/$(call gb_Helper_get_
&& echo 'SecureUserConfig=true' \
&& echo 'SecureUserConfigCompress=true' \
&& echo 'SecureUserConfigNumCopies=2' \
- && echo 'SecureUserConfigMode=0' \
+ && echo 'SecureUserConfigMode=1' \
&& echo 'SecureUserConfigExtensions=true' \
) > $@
diff --git a/svx/source/dialog/SafeModeDialog.cxx b/svx/source/dialog/SafeModeDialog.cxx
index 53d99119e51d..a2e6ca2c3cfa 100644
--- a/svx/source/dialog/SafeModeDialog.cxx
+++ b/svx/source/dialog/SafeModeDialog.cxx
@@ -22,26 +22,63 @@
using namespace css;
-SafeModeDialog::SafeModeDialog(vcl::Window* pParent):
- Dialog(pParent, "SafeModeDialog", "svx/ui/safemodedialog.ui")
+SafeModeDialog::SafeModeDialog(vcl::Window* pParent)
+: Dialog(pParent, "SafeModeDialog", "svx/ui/safemodedialog.ui"),
+
+ mpBtnContinue(),
+ mpBtnQuit(),
+ mpBtnRestart(),
+
+ mpCBCheckProfilesafeConfig(),
+ mpCBCheckProfilesafeExtensions(),
+ mpCBDisableAllExtensions(),
+ mpCBResetCustomizations(),
+ mpCBResetWholeUserProfile(),
+
+ maBackupFileHelper()
{
get(mpBtnContinue, "btn_continue");
get(mpBtnQuit, "btn_quit");
get(mpBtnRestart, "btn_restart");
- get(mpCBCustomizations, "check_customizations");
- get(mpCBExtensions, "check_extensions");
- get(mpCBFull, "check_full");
+
+ get(mpCBCheckProfilesafeConfig, "check_profilesafe_config");
+ get(mpCBCheckProfilesafeExtensions, "check_profilesafe_extensions");
+ get(mpCBDisableAllExtensions, "check_disable_all_extensions");
+ get(mpCBResetCustomizations, "check_reset_customizations");
+ get(mpCBResetWholeUserProfile, "check_reset_whole_userprofile");
mpBtnContinue->SetClickHdl(LINK(this, SafeModeDialog, BtnHdl));
mpBtnQuit->SetClickHdl(LINK(this, SafeModeDialog, BtnHdl));
mpBtnRestart->SetClickHdl(LINK(this, SafeModeDialog, BtnHdl));
- mpCBCustomizations->SetToggleHdl(LINK(this, SafeModeDialog, CheckBoxHdl));
- mpCBExtensions->SetToggleHdl(LINK(this, SafeModeDialog, CheckBoxHdl));
- mpCBFull->SetToggleHdl(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mpCBCheckProfilesafeConfig->SetToggleHdl(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mpCBCheckProfilesafeExtensions->SetToggleHdl(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mpCBDisableAllExtensions->SetToggleHdl(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mpCBResetCustomizations->SetToggleHdl(LINK(this, SafeModeDialog, CheckBoxHdl));
+ mpCBResetWholeUserProfile->SetToggleHdl(LINK(this, SafeModeDialog, CheckBoxHdl));
// Disable restart btn until some checkbox is active
mpBtnRestart->Disable();
+
+ if (!maBackupFileHelper.isPopPossible())
+ {
+ mpCBCheckProfilesafeConfig->Disable();
+ }
+
+ if (!maBackupFileHelper.isPopPossibleExtensionInfo())
+ {
+ mpCBCheckProfilesafeExtensions->Disable();
+ }
+
+ if (comphelper::BackupFileHelper::isTryDisableAllExtensionsPossible())
+ {
+ mpCBDisableAllExtensions->Disable();
+ }
+
+ if (maBackupFileHelper.isTryResetCustomizationsPossible())
+ {
+ mpCBResetCustomizations->Disable();
+ }
}
SafeModeDialog::~SafeModeDialog()
@@ -54,9 +91,12 @@ void SafeModeDialog::dispose()
mpBtnContinue.clear();
mpBtnQuit.clear();
mpBtnRestart.clear();
- mpCBCustomizations.clear();
- mpCBExtensions.clear();
- mpCBFull.clear();
+
+ mpCBCheckProfilesafeConfig.clear();
+ mpCBCheckProfilesafeExtensions.clear();
+ mpCBDisableAllExtensions.clear();
+ mpCBResetCustomizations.clear();
+ mpCBResetWholeUserProfile.clear();
Dialog::dispose();
}
@@ -80,7 +120,37 @@ void SafeModeDialog::terminateOffice()
void SafeModeDialog::applyChanges()
{
- // TODO: Apply apply changes
+ if (mpCBCheckProfilesafeConfig->IsChecked())
+ {
+ // reset UserConfiguration to last known working state
+ // ProfileSafeMode/BackupFileHelper
+ maBackupFileHelper.tryPop();
+ }
+
+ if (mpCBCheckProfilesafeExtensions->IsChecked())
+ {
+ // reset State of installed Extensions to last known working state
+ // ProfileSafeMode/BackupFileHelper
+ maBackupFileHelper.tryPopExtensionInfo();
+ }
+
+ if (mpCBDisableAllExtensions->IsChecked())
+ {
+ // Disable all extensions
+ comphelper::BackupFileHelper::tryDisableAllExtensions();
+ }
+
+ if (mpCBResetCustomizations->IsChecked())
+ {
+ // Reset customizations (Settings and UserInterface modifications)
+ maBackupFileHelper.tryResetCustomizations();
+ }
+
+ if (mpCBResetWholeUserProfile->IsChecked())
+ {
+ // Reset the whole UserProfile
+ maBackupFileHelper.tryResetUserProfile();
+ }
// Then restart
css::task::OfficeRestartManager::get(comphelper::getProcessComponentContext())->requestRestart(
@@ -106,7 +176,13 @@ IMPL_LINK(SafeModeDialog, BtnHdl, Button*, pBtn, void)
IMPL_LINK(SafeModeDialog, CheckBoxHdl, CheckBox&, /*pCheckBox*/, void)
{
- bool bEnable = mpCBCustomizations->IsChecked() || mpCBExtensions->IsChecked() || mpCBFull->IsChecked();
+ const bool bEnable(
+ mpCBCheckProfilesafeConfig->IsChecked() ||
+ mpCBCheckProfilesafeExtensions->IsChecked() ||
+ mpCBDisableAllExtensions->IsChecked() ||
+ mpCBResetCustomizations->IsChecked() ||
+ mpCBResetWholeUserProfile->IsChecked());
+
mpBtnRestart->Enable(bEnable);
}
diff --git a/svx/source/dialog/SafeModeDialog.hxx b/svx/source/dialog/SafeModeDialog.hxx
index dd0036ef7e19..6f2e4af6d600 100644
--- a/svx/source/dialog/SafeModeDialog.hxx
+++ b/svx/source/dialog/SafeModeDialog.hxx
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
class SafeModeDialog : public Dialog
{
@@ -34,12 +35,17 @@ private:
VclPtr