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 <osl/file.hxx>
25 #include <rtl/bootstrap.hxx>
26 #include <rtl/ustring.hxx>
27 #include <sal/log.hxx>
28 #include <cppuhelper/implbase.hxx>
30 #include <vcl/timer.hxx>
32 #include <unotools/configmgr.hxx>
33 #include <tools/diagnose_ex.h>
34 #include <toolkit/helper/vclunohelper.hxx>
36 #include <comphelper/lok.hxx>
37 #include <comphelper/processfactory.hxx>
38 #include <cppuhelper/bootstrap.hxx>
39 #include <cppuhelper/exc_hlp.hxx>
40 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
41 #include <com/sun/star/ucb/CommandAbortedException.hpp>
42 #include <com/sun/star/ucb/CommandFailedException.hpp>
43 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/beans/NamedValue.hpp>
46 #include <com/sun/star/configuration/theDefaultProvider.hpp>
47 #include <com/sun/star/deployment/DeploymentException.hpp>
48 #include <com/sun/star/deployment/XPackage.hpp>
49 #include <com/sun/star/deployment/ExtensionManager.hpp>
50 #include <com/sun/star/deployment/LicenseException.hpp>
51 #include <com/sun/star/deployment/ui/LicenseDialog.hpp>
52 #include <com/sun/star/task/OfficeRestartManager.hpp>
53 #include <com/sun/star/task/XJob.hpp>
54 #include <com/sun/star/task/XInteractionApprove.hpp>
55 #include <com/sun/star/task/XInteractionAbort.hpp>
56 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
57 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
58 #include <com/sun/star/util/XChangesBatch.hpp>
64 using namespace desktop
;
65 using namespace com::sun::star
;
66 using namespace com::sun::star::lang
;
67 using namespace com::sun::star::task
;
68 using namespace com::sun::star::uno
;
72 //For use with XExtensionManager.synchronize
73 class SilentCommandEnv
74 : public ::cppu::WeakImplHelper
< ucb::XCommandEnvironment
,
75 task::XInteractionHandler
,
76 ucb::XProgressHandler
>
78 uno::Reference
<uno::XComponentContext
> mxContext
;
85 uno::Reference
<uno::XComponentContext
> const & xContext
,
87 virtual ~SilentCommandEnv() override
;
89 // XCommandEnvironment
90 virtual uno::Reference
<task::XInteractionHandler
> SAL_CALL
91 getInteractionHandler() override
;
92 virtual uno::Reference
<ucb::XProgressHandler
>
93 SAL_CALL
getProgressHandler() override
;
95 // XInteractionHandler
96 virtual void SAL_CALL
handle(
97 uno::Reference
<task::XInteractionRequest
> const & xRequest
) override
;
100 virtual void SAL_CALL
push( uno::Any
const & Status
) override
;
101 virtual void SAL_CALL
update( uno::Any
const & Status
) override
;
102 virtual void SAL_CALL
pop() override
;
106 SilentCommandEnv::SilentCommandEnv(
107 uno::Reference
<uno::XComponentContext
> const & xContext
,
109 mxContext( xContext
),
110 mpDesktop( pDesktop
),
116 SilentCommandEnv::~SilentCommandEnv()
119 mpDesktop
->SetSplashScreenText(OUString());
123 Reference
<task::XInteractionHandler
> SilentCommandEnv::getInteractionHandler()
129 Reference
<ucb::XProgressHandler
> SilentCommandEnv::getProgressHandler()
135 // XInteractionHandler
136 void SilentCommandEnv::handle( Reference
< task::XInteractionRequest
> const & xRequest
)
138 deployment::LicenseException licExc
;
140 uno::Any
request( xRequest
->getRequest() );
141 bool bApprove
= true;
143 if ( request
>>= licExc
)
145 uno::Reference
< ui::dialogs::XExecutableDialog
> xDialog(
146 deployment::ui::LicenseDialog::create(
147 mxContext
, VCLUnoHelper::GetInterface( nullptr ),
148 licExc
.ExtensionName
, licExc
.Text
) );
149 sal_Int16 res
= xDialog
->execute();
150 if ( res
== ui::dialogs::ExecutableDialogResults::CANCEL
)
152 else if ( res
== ui::dialogs::ExecutableDialogResults::OK
)
160 // We approve everything here
161 uno::Sequence
< Reference
< task::XInteractionContinuation
> > conts( xRequest
->getContinuations() );
162 Reference
< task::XInteractionContinuation
> const * pConts
= conts
.getConstArray();
163 sal_Int32 len
= conts
.getLength();
165 for ( sal_Int32 pos
= 0; pos
< len
; ++pos
)
169 uno::Reference
< task::XInteractionApprove
> xInteractionApprove( pConts
[ pos
], uno::UNO_QUERY
);
170 if ( xInteractionApprove
.is() )
171 xInteractionApprove
->select();
175 uno::Reference
< task::XInteractionAbort
> xInteractionAbort( pConts
[ pos
], uno::UNO_QUERY
);
176 if ( xInteractionAbort
.is() )
177 xInteractionAbort
->select();
184 void SilentCommandEnv::push( uno::Any
const & rStatus
)
189 if (mpDesktop
&& rStatus
.hasValue() && (rStatus
>>= sText
))
192 mpDesktop
->SetSplashScreenText( sText
);
194 mpDesktop
->SetSplashScreenProgress( ++mnProgress
);
199 void SilentCommandEnv::update( uno::Any
const & rStatus
)
202 if (mpDesktop
&& rStatus
.hasValue() && (rStatus
>>= sText
))
204 mpDesktop
->SetSplashScreenText( sText
);
209 void SilentCommandEnv::pop()
217 static const char aAccessSrvc
[] = "com.sun.star.configuration.ConfigurationUpdateAccess";
219 static sal_Int16
impl_showExtensionDialog( uno::Reference
< uno::XComponentContext
> const &xContext
)
221 OUString sServiceName
= "com.sun.star.deployment.ui.UpdateRequiredDialog";
222 uno::Reference
< uno::XInterface
> xService
;
225 uno::Reference
< lang::XMultiComponentFactory
> xServiceManager( xContext
->getServiceManager() );
226 if( !xServiceManager
.is() )
227 throw uno::RuntimeException(
228 "impl_showExtensionDialog(): unable to obtain service manager from component context", uno::Reference
< uno::XInterface
> () );
230 xService
= xServiceManager
->createInstanceWithContext( sServiceName
, xContext
);
231 uno::Reference
< ui::dialogs::XExecutableDialog
> xExecuteable( xService
, uno::UNO_QUERY
);
232 if ( xExecuteable
.is() )
233 nRet
= xExecuteable
->execute();
239 // Check dependencies of all packages
241 static bool impl_checkDependencies( const uno::Reference
< uno::XComponentContext
> &xContext
)
243 uno::Sequence
< uno::Sequence
< uno::Reference
< deployment::XPackage
> > > xAllPackages
;
244 uno::Reference
< deployment::XExtensionManager
> xExtensionManager
= deployment::ExtensionManager::get( xContext
);
246 if ( !xExtensionManager
.is() )
248 SAL_WARN( "desktop.app", "Could not get the Extension Manager!" );
253 xAllPackages
= xExtensionManager
->getAllExtensions( uno::Reference
< task::XAbortChannel
>(),
254 uno::Reference
< ucb::XCommandEnvironment
>() );
256 catch ( const deployment::DeploymentException
& ) { return true; }
257 catch ( const ucb::CommandFailedException
& ) { return true; }
258 catch ( const ucb::CommandAbortedException
& ) { return true; }
259 catch ( const lang::IllegalArgumentException
& e
) {
260 css::uno::Any anyEx
= cppu::getCaughtException();
261 throw css::lang::WrappedTargetRuntimeException( e
.Message
,
266 sal_Int32
const nMax
= 3;
268 sal_Int32
const nMax
= 2;
271 for ( sal_Int32 i
= 0; i
< xAllPackages
.getLength(); ++i
)
273 uno::Sequence
< uno::Reference
< deployment::XPackage
> > xPackageList
= xAllPackages
[i
];
275 for ( sal_Int32 j
= 0; (j
<nMax
) && (j
< xPackageList
.getLength()); ++j
)
277 uno::Reference
< deployment::XPackage
> xPackage
= xPackageList
[j
];
280 bool bRegistered
= false;
282 beans::Optional
< beans::Ambiguous
< sal_Bool
> > option( xPackage
->isRegistered( uno::Reference
< task::XAbortChannel
>(),
283 uno::Reference
< ucb::XCommandEnvironment
>() ) );
284 if ( option
.IsPresent
)
286 ::beans::Ambiguous
< sal_Bool
> const & reg
= option
.Value
;
287 if ( reg
.IsAmbiguous
)
290 bRegistered
= reg
.Value
;
295 catch ( const uno::RuntimeException
& ) { throw; }
296 catch (const uno::Exception
& ) {
297 TOOLS_WARN_EXCEPTION( "desktop.app", "" );
302 bool bDependenciesValid
= false;
304 bDependenciesValid
= xPackage
->checkDependencies( uno::Reference
< ucb::XCommandEnvironment
>() );
306 catch ( const deployment::DeploymentException
& ) {}
307 if ( ! bDependenciesValid
)
319 // resets the 'check needed' flag (needed, if aborted)
321 static void impl_setNeedsCompatCheck()
324 Reference
< XMultiServiceFactory
> theConfigProvider(
325 configuration::theDefaultProvider::get(
326 comphelper::getProcessComponentContext() ) );
328 Sequence
< Any
> theArgs(1);
329 beans::NamedValue
v( "nodepath",
330 makeAny( OUString("org.openoffice.Setup/Office") ) );
332 Reference
< beans::XPropertySet
> pset(
333 theConfigProvider
->createInstanceWithArguments( aAccessSrvc
, theArgs
), UNO_QUERY_THROW
);
335 Any value
= makeAny( OUString("never") );
337 pset
->setPropertyValue("LastCompatibilityCheckID", value
);
338 Reference
< util::XChangesBatch
>( pset
, UNO_QUERY_THROW
)->commitChanges();
340 catch (const Exception
&) {}
344 // to check if we need checking the dependencies of the extensions again, we compare
345 // the build id of the office with the one of the last check
347 static bool impl_needsCompatCheck()
349 bool bNeedsCheck
= false;
350 OUString aLastCheckBuildID
;
351 OUString
aCurrentBuildID( "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("version") ":buildid}" );
352 rtl::Bootstrap::expandMacros( aCurrentBuildID
);
355 Reference
< XMultiServiceFactory
> theConfigProvider(
356 configuration::theDefaultProvider::get(
357 comphelper::getProcessComponentContext() ) );
359 Sequence
< Any
> theArgs(1);
360 beans::NamedValue
v( "nodepath",
361 makeAny( OUString("org.openoffice.Setup/Office") ) );
363 Reference
< beans::XPropertySet
> pset(
364 theConfigProvider
->createInstanceWithArguments( aAccessSrvc
, theArgs
), UNO_QUERY_THROW
);
366 Any result
= pset
->getPropertyValue("LastCompatibilityCheckID");
368 result
>>= aLastCheckBuildID
;
369 if ( aLastCheckBuildID
!= aCurrentBuildID
)
372 result
<<= aCurrentBuildID
;
373 pset
->setPropertyValue("LastCompatibilityCheckID", result
);
374 Reference
< util::XChangesBatch
>( pset
, UNO_QUERY_THROW
)->commitChanges();
380 catch (const css::uno::Exception
&) {}
386 // Do we need to check the dependencies of the extensions?
387 // When there are unresolved issues, we can't continue with startup
388 bool Desktop::CheckExtensionDependencies()
390 if (!impl_needsCompatCheck())
395 uno::Reference
< uno::XComponentContext
> xContext(
396 comphelper::getProcessComponentContext());
398 bool bDependenciesValid
= impl_checkDependencies( xContext
);
402 if ( !bDependenciesValid
)
403 nRet
= impl_showExtensionDialog( xContext
);
407 impl_setNeedsCompatCheck();
414 void Desktop::SynchronizeExtensionRepositories(bool bCleanedExtensionCache
, Desktop
* pDesktop
)
416 uno::Reference
< uno::XComponentContext
> context(
417 comphelper::getProcessComponentContext());
418 uno::Reference
< ucb::XCommandEnvironment
> silent(
419 new SilentCommandEnv(context
, pDesktop
));
420 if (bCleanedExtensionCache
) {
421 deployment::ExtensionManager::get(context
)->reinstallDeployedExtensions(
422 true, "user", Reference
<task::XAbortChannel
>(), silent
);
423 #if !HAVE_FEATURE_MACOSX_SANDBOX
424 if (!comphelper::LibreOfficeKit::isActive())
425 task::OfficeRestartManager::get(context
)->requestRestart(
426 silent
->getInteractionHandler());
429 // reinstallDeployedExtensions above already calls syncRepositories internally
431 // Force syncing repositories on startup. There are cases where the extension
432 // registration becomes invalid which leads to extensions not starting up, although
433 // installed and active. Syncing extension repos on startup fixes that.
434 dp_misc::syncRepositories(/*force=*/true, silent
);
438 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */