Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / desktop / source / app / check_ext_deps.cxx
blob292637a194235b5f5c551f56c9a8b3493c5945e1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
60 #include <app.hxx>
62 #include <dp_misc.h>
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;
70 namespace
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;
79 Desktop *mpDesktop;
80 sal_Int32 mnLevel;
81 sal_Int32 mnProgress;
83 public:
84 SilentCommandEnv(
85 uno::Reference<uno::XComponentContext> const & xContext,
86 Desktop* pDesktop );
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;
99 // XProgressHandler
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,
108 Desktop* pDesktop ):
109 mxContext( xContext ),
110 mpDesktop( pDesktop ),
111 mnLevel( 0 ),
112 mnProgress( 25 )
116 SilentCommandEnv::~SilentCommandEnv()
118 if (mpDesktop)
119 mpDesktop->SetSplashScreenText(OUString());
123 Reference<task::XInteractionHandler> SilentCommandEnv::getInteractionHandler()
125 return this;
129 Reference<ucb::XProgressHandler> SilentCommandEnv::getProgressHandler()
131 return this;
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 )
151 bApprove = false;
152 else if ( res == ui::dialogs::ExecutableDialogResults::OK )
153 bApprove = true;
154 else
156 OSL_ASSERT(false);
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 )
167 if ( bApprove )
169 uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY );
170 if ( xInteractionApprove.is() )
171 xInteractionApprove->select();
173 else
175 uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY );
176 if ( xInteractionAbort.is() )
177 xInteractionAbort->select();
183 // XProgressHandler
184 void SilentCommandEnv::push( uno::Any const & rStatus )
186 OUString sText;
187 mnLevel += 1;
189 if (mpDesktop && rStatus.hasValue() && (rStatus >>= sText))
191 if ( mnLevel <= 3 )
192 mpDesktop->SetSplashScreenText( sText );
193 else
194 mpDesktop->SetSplashScreenProgress( ++mnProgress );
199 void SilentCommandEnv::update( uno::Any const & rStatus )
201 OUString sText;
202 if (mpDesktop && rStatus.hasValue() && (rStatus >>= sText))
204 mpDesktop->SetSplashScreenText( sText );
209 void SilentCommandEnv::pop()
211 mnLevel -= 1;
214 } // end namespace
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;
223 sal_Int16 nRet = 0;
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();
235 return nRet;
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!" );
249 return true;
252 try {
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,
262 e.Context, anyEx );
265 #ifdef DEBUG
266 sal_Int32 const nMax = 3;
267 #else
268 sal_Int32 const nMax = 2;
269 #endif
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];
278 if ( xPackage.is() )
280 bool bRegistered = false;
281 try {
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 )
288 bRegistered = false;
289 else
290 bRegistered = reg.Value;
292 else
293 bRegistered = false;
295 catch ( const uno::RuntimeException & ) { throw; }
296 catch (const uno::Exception & ) {
297 TOOLS_WARN_EXCEPTION( "desktop.app", "" );
300 if ( bRegistered )
302 bool bDependenciesValid = false;
303 try {
304 bDependenciesValid = xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() );
306 catch ( const deployment::DeploymentException & ) {}
307 if ( ! bDependenciesValid )
309 return false;
315 return true;
319 // resets the 'check needed' flag (needed, if aborted)
321 static void impl_setNeedsCompatCheck()
323 try {
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") ) );
331 theArgs[0] <<= v;
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 );
354 try {
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") ) );
362 theArgs[0] <<= v;
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 )
371 bNeedsCheck = true;
372 result <<= aCurrentBuildID;
373 pset->setPropertyValue("LastCompatibilityCheckID", result );
374 Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
376 #ifdef DEBUG
377 bNeedsCheck = true;
378 #endif
380 catch (const css::uno::Exception&) {}
382 return bNeedsCheck;
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())
392 return false;
395 uno::Reference< uno::XComponentContext > xContext(
396 comphelper::getProcessComponentContext());
398 bool bDependenciesValid = impl_checkDependencies( xContext );
400 short nRet = 0;
402 if ( !bDependenciesValid )
403 nRet = impl_showExtensionDialog( xContext );
405 if ( nRet == -1 )
407 impl_setNeedsCompatCheck();
408 return true;
410 else
411 return false;
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());
427 #endif
428 } else {
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: */