1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_folders.h>
21 #include <config_features.h>
23 #include <rtl/bootstrap.hxx>
24 #include <rtl/ustring.hxx>
25 #include <sal/log.hxx>
26 #include <cppuhelper/implbase.hxx>
28 #include <comphelper/diagnose_ex.hxx>
29 #include <toolkit/helper/vclunohelper.hxx>
31 #include <comphelper/lok.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <cppuhelper/exc_hlp.hxx>
34 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
35 #include <com/sun/star/ucb/CommandAbortedException.hpp>
36 #include <com/sun/star/ucb/CommandFailedException.hpp>
37 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/beans/NamedValue.hpp>
40 #include <com/sun/star/configuration/theDefaultProvider.hpp>
41 #include <com/sun/star/deployment/DeploymentException.hpp>
42 #include <com/sun/star/deployment/XPackage.hpp>
43 #include <com/sun/star/deployment/ExtensionManager.hpp>
44 #include <com/sun/star/deployment/LicenseException.hpp>
45 #include <com/sun/star/deployment/ui/LicenseDialog.hpp>
46 #include <com/sun/star/task/OfficeRestartManager.hpp>
47 #include <com/sun/star/task/XInteractionApprove.hpp>
48 #include <com/sun/star/task/XInteractionAbort.hpp>
49 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
50 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
51 #include <com/sun/star/util/XChangesBatch.hpp>
58 using namespace desktop
;
59 using namespace com::sun::star
;
60 using namespace com::sun::star::lang
;
61 using namespace com::sun::star::task
;
62 using namespace com::sun::star::uno
;
66 //For use with XExtensionManager.synchronize
67 class SilentCommandEnv
68 : public ::cppu::WeakImplHelper
< ucb::XCommandEnvironment
,
69 task::XInteractionHandler
,
70 ucb::XProgressHandler
>
72 uno::Reference
<uno::XComponentContext
> mxContext
;
79 uno::Reference
<uno::XComponentContext
> xContext
,
81 virtual ~SilentCommandEnv() override
;
83 // XCommandEnvironment
84 virtual uno::Reference
<task::XInteractionHandler
> SAL_CALL
85 getInteractionHandler() override
;
86 virtual uno::Reference
<ucb::XProgressHandler
>
87 SAL_CALL
getProgressHandler() override
;
89 // XInteractionHandler
90 virtual void SAL_CALL
handle(
91 uno::Reference
<task::XInteractionRequest
> const & xRequest
) override
;
94 virtual void SAL_CALL
push( uno::Any
const & Status
) override
;
95 virtual void SAL_CALL
update( uno::Any
const & Status
) override
;
96 virtual void SAL_CALL
pop() override
;
100 SilentCommandEnv::SilentCommandEnv(
101 uno::Reference
<uno::XComponentContext
> xContext
,
103 mxContext(std::move( xContext
)),
104 mpDesktop( pDesktop
),
110 SilentCommandEnv::~SilentCommandEnv()
113 mpDesktop
->SetSplashScreenText(OUString());
117 Reference
<task::XInteractionHandler
> SilentCommandEnv::getInteractionHandler()
123 Reference
<ucb::XProgressHandler
> SilentCommandEnv::getProgressHandler()
129 // XInteractionHandler
130 void SilentCommandEnv::handle( Reference
< task::XInteractionRequest
> const & xRequest
)
132 deployment::LicenseException licExc
;
134 uno::Any
request( xRequest
->getRequest() );
135 bool bApprove
= true;
137 if ( request
>>= licExc
)
139 uno::Reference
< ui::dialogs::XExecutableDialog
> xDialog(
140 deployment::ui::LicenseDialog::create(
141 mxContext
, VCLUnoHelper::GetInterface( nullptr ),
142 licExc
.ExtensionName
, licExc
.Text
) );
143 sal_Int16 res
= xDialog
->execute();
144 if ( res
== ui::dialogs::ExecutableDialogResults::CANCEL
)
146 else if ( res
== ui::dialogs::ExecutableDialogResults::OK
)
154 // We approve everything here
155 uno::Sequence
< Reference
< task::XInteractionContinuation
> > conts( xRequest
->getContinuations() );
156 Reference
< task::XInteractionContinuation
> const * pConts
= conts
.getConstArray();
157 sal_Int32 len
= conts
.getLength();
159 for ( sal_Int32 pos
= 0; pos
< len
; ++pos
)
163 uno::Reference
< task::XInteractionApprove
> xInteractionApprove( pConts
[ pos
], uno::UNO_QUERY
);
164 if ( xInteractionApprove
.is() )
165 xInteractionApprove
->select();
169 uno::Reference
< task::XInteractionAbort
> xInteractionAbort( pConts
[ pos
], uno::UNO_QUERY
);
170 if ( xInteractionAbort
.is() )
171 xInteractionAbort
->select();
178 void SilentCommandEnv::push( uno::Any
const & rStatus
)
183 if (mpDesktop
&& rStatus
.hasValue() && (rStatus
>>= sText
))
186 mpDesktop
->SetSplashScreenText( sText
);
188 mpDesktop
->SetSplashScreenProgress( ++mnProgress
);
193 void SilentCommandEnv::update( uno::Any
const & rStatus
)
196 if (mpDesktop
&& rStatus
.hasValue() && (rStatus
>>= sText
))
198 mpDesktop
->SetSplashScreenText( sText
);
203 void SilentCommandEnv::pop()
211 constexpr OUString aAccessSrvc
= u
"com.sun.star.configuration.ConfigurationUpdateAccess"_ustr
;
213 static sal_Int16
impl_showExtensionDialog( uno::Reference
< uno::XComponentContext
> const &xContext
)
215 uno::Reference
< uno::XInterface
> xService
;
218 uno::Reference
< lang::XMultiComponentFactory
> xServiceManager( xContext
->getServiceManager() );
219 if( !xServiceManager
.is() )
220 throw uno::RuntimeException(
221 u
"impl_showExtensionDialog(): unable to obtain service manager from component context"_ustr
, uno::Reference
< uno::XInterface
> () );
223 xService
= xServiceManager
->createInstanceWithContext( u
"com.sun.star.deployment.ui.UpdateRequiredDialog"_ustr
, xContext
);
224 uno::Reference
< ui::dialogs::XExecutableDialog
> xExecutable( xService
, uno::UNO_QUERY
);
225 if ( xExecutable
.is() )
226 nRet
= xExecutable
->execute();
232 // Check dependencies of all packages
234 static bool impl_checkDependencies( const uno::Reference
< uno::XComponentContext
> &xContext
)
236 uno::Sequence
< uno::Sequence
< uno::Reference
< deployment::XPackage
> > > xAllPackages
;
237 uno::Reference
< deployment::XExtensionManager
> xExtensionManager
= deployment::ExtensionManager::get( xContext
);
239 if ( !xExtensionManager
.is() )
241 SAL_WARN( "desktop.app", "Could not get the Extension Manager!" );
246 xAllPackages
= xExtensionManager
->getAllExtensions( uno::Reference
< task::XAbortChannel
>(),
247 uno::Reference
< ucb::XCommandEnvironment
>() );
249 catch ( const deployment::DeploymentException
& ) { return true; }
250 catch ( const ucb::CommandFailedException
& ) { return true; }
251 catch ( const ucb::CommandAbortedException
& ) { return true; }
252 catch ( const lang::IllegalArgumentException
& e
) {
253 css::uno::Any anyEx
= cppu::getCaughtException();
254 throw css::lang::WrappedTargetRuntimeException( e
.Message
,
258 #if OSL_DEBUG_LEVEL >= 2
259 sal_Int32
const nMax
= 3;
261 sal_Int32
const nMax
= 2;
264 for (uno::Sequence
<uno::Reference
<deployment::XPackage
>> const& xPackageList
: xAllPackages
)
266 for ( sal_Int32 j
= 0; (j
<nMax
) && (j
< xPackageList
.getLength()); ++j
)
268 uno::Reference
< deployment::XPackage
> xPackage
= xPackageList
[j
];
271 bool bRegistered
= false;
273 beans::Optional
< beans::Ambiguous
< sal_Bool
> > option( xPackage
->isRegistered( uno::Reference
< task::XAbortChannel
>(),
274 uno::Reference
< ucb::XCommandEnvironment
>() ) );
275 if ( option
.IsPresent
)
277 ::beans::Ambiguous
< sal_Bool
> const & reg
= option
.Value
;
278 if ( reg
.IsAmbiguous
)
281 bRegistered
= reg
.Value
;
286 catch ( const uno::RuntimeException
& ) { throw; }
287 catch (const uno::Exception
& ) {
288 TOOLS_WARN_EXCEPTION( "desktop.app", "" );
293 bool bDependenciesValid
= false;
295 bDependenciesValid
= xPackage
->checkDependencies( uno::Reference
< ucb::XCommandEnvironment
>() );
297 catch ( const deployment::DeploymentException
& ) {}
298 if ( ! bDependenciesValid
)
310 // resets the 'check needed' flag (needed, if aborted)
312 static void impl_setNeedsCompatCheck()
315 Reference
< XMultiServiceFactory
> theConfigProvider(
316 configuration::theDefaultProvider::get(
317 comphelper::getProcessComponentContext() ) );
319 beans::NamedValue
v( u
"nodepath"_ustr
,
320 Any( u
"org.openoffice.Setup/Office"_ustr
) );
321 Sequence
< Any
> theArgs
{ Any(v
) };
322 Reference
< beans::XPropertySet
> pset(
323 theConfigProvider
->createInstanceWithArguments( aAccessSrvc
, theArgs
), UNO_QUERY_THROW
);
325 Any
value( u
"never"_ustr
);
327 pset
->setPropertyValue(u
"LastCompatibilityCheckID"_ustr
, value
);
328 Reference
< util::XChangesBatch
>( pset
, UNO_QUERY_THROW
)->commitChanges();
330 catch (const Exception
&) {}
334 // to check if we need checking the dependencies of the extensions again, we compare
335 // the build id of the office with the one of the last check
337 static bool impl_needsCompatCheck()
339 bool bNeedsCheck
= false;
340 OUString aLastCheckBuildID
;
341 OUString
aCurrentBuildID( u
"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("version") ":buildid}"_ustr
);
342 rtl::Bootstrap::expandMacros( aCurrentBuildID
);
345 Reference
< XMultiServiceFactory
> theConfigProvider(
346 configuration::theDefaultProvider::get(
347 comphelper::getProcessComponentContext() ) );
349 beans::NamedValue
v( u
"nodepath"_ustr
,
350 Any( u
"org.openoffice.Setup/Office"_ustr
) );
351 Sequence
< Any
> theArgs
{ Any(v
) };
352 Reference
< beans::XPropertySet
> pset(
353 theConfigProvider
->createInstanceWithArguments( aAccessSrvc
, theArgs
), UNO_QUERY_THROW
);
355 Any result
= pset
->getPropertyValue(u
"LastCompatibilityCheckID"_ustr
);
357 result
>>= aLastCheckBuildID
;
358 if ( aLastCheckBuildID
!= aCurrentBuildID
)
361 result
<<= aCurrentBuildID
;
362 pset
->setPropertyValue(u
"LastCompatibilityCheckID"_ustr
, result
);
363 Reference
< util::XChangesBatch
>( pset
, UNO_QUERY_THROW
)->commitChanges();
365 #if OSL_DEBUG_LEVEL >= 2
369 catch (const css::uno::Exception
&) {}
375 // Do we need to check the dependencies of the extensions?
376 // When there are unresolved issues, we can't continue with startup
377 bool Desktop::CheckExtensionDependencies()
379 if (!impl_needsCompatCheck())
384 const uno::Reference
< uno::XComponentContext
>& xContext(
385 comphelper::getProcessComponentContext());
387 bool bDependenciesValid
= impl_checkDependencies( xContext
);
391 if ( !bDependenciesValid
)
392 nRet
= impl_showExtensionDialog( xContext
);
396 impl_setNeedsCompatCheck();
403 void Desktop::SynchronizeExtensionRepositories(bool bCleanedExtensionCache
, Desktop
* pDesktop
)
405 const uno::Reference
< uno::XComponentContext
>& context(
406 comphelper::getProcessComponentContext());
407 uno::Reference
< ucb::XCommandEnvironment
> silent(
408 new SilentCommandEnv(context
, pDesktop
));
409 if (bCleanedExtensionCache
) {
410 deployment::ExtensionManager::get(context
)->reinstallDeployedExtensions(
411 true, u
"user"_ustr
, Reference
<task::XAbortChannel
>(), silent
);
412 #if !HAVE_FEATURE_MACOSX_SANDBOX
413 if (!comphelper::LibreOfficeKit::isActive())
414 task::OfficeRestartManager::get(context
)->requestRestart(
415 silent
->getInteractionHandler());
418 // reinstallDeployedExtensions above already calls syncRepositories internally
420 // Force syncing repositories on startup. There are cases where the extension
421 // registration becomes invalid which leads to extensions not starting up, although
422 // installed and active. Syncing extension repos on startup fixes that.
423 dp_misc::syncRepositories(/*force=*/true, silent
);
427 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */