LibreOffice Module desktop (master) 1
check_ext_deps.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <config_folders.h>
21#include <config_features.h>
22
23#include <rtl/bootstrap.hxx>
24#include <rtl/ustring.hxx>
25#include <sal/log.hxx>
27
30
31#include <comphelper/lok.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>
52
53#include <app.hxx>
54#include <utility>
55
56#include <dp_misc.h>
57
58using namespace desktop;
59using namespace com::sun::star;
60using namespace com::sun::star::lang;
61using namespace com::sun::star::task;
62using namespace com::sun::star::uno;
63
64namespace
65{
66//For use with XExtensionManager.synchronize
67class SilentCommandEnv
68 : public ::cppu::WeakImplHelper< ucb::XCommandEnvironment,
69 task::XInteractionHandler,
70 ucb::XProgressHandler >
71{
73 Desktop *mpDesktop;
74 sal_Int32 mnLevel;
75 sal_Int32 mnProgress;
76
77public:
78 SilentCommandEnv(
80 Desktop* pDesktop );
81 virtual ~SilentCommandEnv() override;
82
83 // XCommandEnvironment
85 getInteractionHandler() override;
87 SAL_CALL getProgressHandler() override;
88
89 // XInteractionHandler
90 virtual void SAL_CALL handle(
91 uno::Reference<task::XInteractionRequest > const & xRequest ) override;
92
93 // XProgressHandler
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;
97};
98
99
100SilentCommandEnv::SilentCommandEnv(
102 Desktop* pDesktop ):
103 mxContext(std::move( xContext )),
104 mpDesktop( pDesktop ),
105 mnLevel( 0 ),
106 mnProgress( 25 )
107{}
108
109
110SilentCommandEnv::~SilentCommandEnv()
111{
112 if (mpDesktop)
113 mpDesktop->SetSplashScreenText(OUString());
114}
115
116
117Reference<task::XInteractionHandler> SilentCommandEnv::getInteractionHandler()
118{
119 return this;
120}
121
122
123Reference<ucb::XProgressHandler> SilentCommandEnv::getProgressHandler()
124{
125 return this;
126}
127
128
129// XInteractionHandler
130void SilentCommandEnv::handle( Reference< task::XInteractionRequest> const & xRequest )
131{
132 deployment::LicenseException licExc;
133
134 uno::Any request( xRequest->getRequest() );
135 bool bApprove = true;
136
137 if ( request >>= licExc )
138 {
142 licExc.ExtensionName, licExc.Text ) );
143 sal_Int16 res = xDialog->execute();
144 if ( res == ui::dialogs::ExecutableDialogResults::CANCEL )
145 bApprove = false;
146 else if ( res == ui::dialogs::ExecutableDialogResults::OK )
147 bApprove = true;
148 else
149 {
150 OSL_ASSERT(false);
151 }
152 }
153
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();
158
159 for ( sal_Int32 pos = 0; pos < len; ++pos )
160 {
161 if ( bApprove )
162 {
163 uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY );
164 if ( xInteractionApprove.is() )
165 xInteractionApprove->select();
166 }
167 else
168 {
169 uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY );
170 if ( xInteractionAbort.is() )
171 xInteractionAbort->select();
172 }
173 }
174}
175
176
177// XProgressHandler
178void SilentCommandEnv::push( uno::Any const & rStatus )
179{
180 OUString sText;
181 mnLevel += 1;
182
183 if (mpDesktop && rStatus.hasValue() && (rStatus >>= sText))
184 {
185 if ( mnLevel <= 3 )
186 mpDesktop->SetSplashScreenText( sText );
187 else
188 mpDesktop->SetSplashScreenProgress( ++mnProgress );
189 }
190}
191
192
193void SilentCommandEnv::update( uno::Any const & rStatus )
194{
195 OUString sText;
196 if (mpDesktop && rStatus.hasValue() && (rStatus >>= sText))
197 {
198 mpDesktop->SetSplashScreenText( sText );
199 }
200}
201
202
203void SilentCommandEnv::pop()
204{
205 mnLevel -= 1;
206}
207
208} // end namespace
209
210
211constexpr OUStringLiteral aAccessSrvc = u"com.sun.star.configuration.ConfigurationUpdateAccess";
212
214{
216 sal_Int16 nRet = 0;
217
218 uno::Reference< lang::XMultiComponentFactory > xServiceManager( xContext->getServiceManager() );
219 if( !xServiceManager.is() )
220 throw uno::RuntimeException(
221 "impl_showExtensionDialog(): unable to obtain service manager from component context", uno::Reference< uno::XInterface > () );
222
223 xService = xServiceManager->createInstanceWithContext( "com.sun.star.deployment.ui.UpdateRequiredDialog", xContext );
224 uno::Reference< ui::dialogs::XExecutableDialog > xExecutable( xService, uno::UNO_QUERY );
225 if ( xExecutable.is() )
226 nRet = xExecutable->execute();
227
228 return nRet;
229}
230
231
232// Check dependencies of all packages
233
235{
237 uno::Reference< deployment::XExtensionManager > xExtensionManager = deployment::ExtensionManager::get( xContext );
238
239 if ( !xExtensionManager.is() )
240 {
241 SAL_WARN( "desktop.app", "Could not get the Extension Manager!" );
242 return true;
243 }
244
245 try {
246 xAllPackages = xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
248 }
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,
255 e.Context, anyEx );
256 }
257
258#ifdef DEBUG
259 sal_Int32 const nMax = 3;
260#else
261 sal_Int32 const nMax = 2;
262#endif
263
264 for ( uno::Sequence< uno::Reference< deployment::XPackage > > const & xPackageList : std::as_const(xAllPackages) )
265 {
266 for ( sal_Int32 j = 0; (j<nMax) && (j < xPackageList.getLength()); ++j )
267 {
268 uno::Reference< deployment::XPackage > xPackage = xPackageList[j];
269 if ( xPackage.is() )
270 {
271 bool bRegistered = false;
272 try {
273 beans::Optional< beans::Ambiguous< sal_Bool > > option( xPackage->isRegistered( uno::Reference< task::XAbortChannel >(),
275 if ( option.IsPresent )
276 {
277 ::beans::Ambiguous< sal_Bool > const & reg = option.Value;
278 if ( reg.IsAmbiguous )
279 bRegistered = false;
280 else
281 bRegistered = reg.Value;
282 }
283 else
284 bRegistered = false;
285 }
286 catch ( const uno::RuntimeException & ) { throw; }
287 catch (const uno::Exception & ) {
288 TOOLS_WARN_EXCEPTION( "desktop.app", "" );
289 }
290
291 if ( bRegistered )
292 {
293 bool bDependenciesValid = false;
294 try {
295 bDependenciesValid = xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() );
296 }
297 catch ( const deployment::DeploymentException & ) {}
298 if ( ! bDependenciesValid )
299 {
300 return false;
301 }
302 }
303 }
304 }
305 }
306 return true;
307}
308
309
310// resets the 'check needed' flag (needed, if aborted)
311
313{
314 try {
315 Reference< XMultiServiceFactory > theConfigProvider(
316 configuration::theDefaultProvider::get(
318
319 beans::NamedValue v( "nodepath",
320 Any( OUString("org.openoffice.Setup/Office") ) );
321 Sequence< Any > theArgs{ Any(v) };
323 theConfigProvider->createInstanceWithArguments( aAccessSrvc, theArgs ), UNO_QUERY_THROW );
324
325 Any value( OUString("never") );
326
327 pset->setPropertyValue("LastCompatibilityCheckID", value );
328 Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
329 }
330 catch (const Exception&) {}
331}
332
333
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
336
338{
339 bool bNeedsCheck = false;
340 OUString aLastCheckBuildID;
341 OUString aCurrentBuildID( "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}" );
342 rtl::Bootstrap::expandMacros( aCurrentBuildID );
343
344 try {
345 Reference< XMultiServiceFactory > theConfigProvider(
346 configuration::theDefaultProvider::get(
348
349 beans::NamedValue v( "nodepath",
350 Any( OUString("org.openoffice.Setup/Office") ) );
351 Sequence< Any > theArgs{ Any(v) };
353 theConfigProvider->createInstanceWithArguments( aAccessSrvc, theArgs ), UNO_QUERY_THROW );
354
355 Any result = pset->getPropertyValue("LastCompatibilityCheckID");
356
357 result >>= aLastCheckBuildID;
358 if ( aLastCheckBuildID != aCurrentBuildID )
359 {
360 bNeedsCheck = true;
361 result <<= aCurrentBuildID;
362 pset->setPropertyValue("LastCompatibilityCheckID", result );
363 Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
364 }
365#ifdef DEBUG
366 bNeedsCheck = true;
367#endif
368 }
369 catch (const css::uno::Exception&) {}
370
371 return bNeedsCheck;
372}
373
374
375// Do we need to check the dependencies of the extensions?
376// When there are unresolved issues, we can't continue with startup
377bool Desktop::CheckExtensionDependencies()
378{
380 {
381 return false;
382 }
383
386
387 bool bDependenciesValid = impl_checkDependencies( xContext );
388
389 short nRet = 0;
390
391 if ( !bDependenciesValid )
393
394 if ( nRet == -1 )
395 {
397 return true;
398 }
399 else
400 return false;
401}
402
403void Desktop::SynchronizeExtensionRepositories(bool bCleanedExtensionCache, Desktop* pDesktop)
404{
408 new SilentCommandEnv(context, pDesktop));
409 if (bCleanedExtensionCache) {
410 deployment::ExtensionManager::get(context)->reinstallDeployedExtensions(
411 true, "user", Reference<task::XAbortChannel>(), silent);
412#if !HAVE_FEATURE_MACOSX_SANDBOX
414 task::OfficeRestartManager::get(context)->requestRestart(
415 silent->getInteractionHandler());
416#endif
417 } else {
418 // reinstallDeployedExtensions above already calls syncRepositories internally
419
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);
424 }
425}
426
427/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static bool impl_checkDependencies(const uno::Reference< uno::XComponentContext > &xContext)
constexpr OUStringLiteral aAccessSrvc
static void impl_setNeedsCompatCheck()
static bool impl_needsCompatCheck()
static sal_Int16 impl_showExtensionDialog(uno::Reference< uno::XComponentContext > const &xContext)
static css::uno::Reference< css::awt::XWindow > GetInterface(vcl::Window *pWindow)
static void SynchronizeExtensionRepositories(bool bCleanedExtensionCache, Desktop *pDesktop=nullptr)
sal_Int16 mnLevel
Any value
#define SAL_CONFIGFILE(name)
#define TOOLS_WARN_EXCEPTION(area, stream)
uno::Reference< uno::XComponentContext > mxContext
float v
float u
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2516
#define SAL_WARN(area, stream)
@ Exception
Reference< XComponentContext > getProcessComponentContext()
Any SAL_CALL getCaughtException()
Definition: app.cxx:165
void syncRepositories(bool force, Reference< ucb::XCommandEnvironment > const &xCmdEnv)
Definition: dp_misc.cxx:493
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
bool hasValue()
JCOPY_OPTION option
Any result
bool update()
Definition: updater.cxx:286
size_t pos