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>
26 #include <cppuhelper/implbase.hxx>
27 
28 #include <tools/diagnose_ex.h>
30 
31 #include <comphelper/lok.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>
52 
53 #include <app.hxx>
54 
55 #include <dp_misc.h>
56 
57 using namespace desktop;
58 using namespace com::sun::star;
59 using namespace com::sun::star::lang;
60 using namespace com::sun::star::task;
61 using namespace com::sun::star::uno;
62 
63 namespace
64 {
65 //For use with XExtensionManager.synchronize
66 class SilentCommandEnv
67  : public ::cppu::WeakImplHelper< ucb::XCommandEnvironment,
68  task::XInteractionHandler,
69  ucb::XProgressHandler >
70 {
71  uno::Reference<uno::XComponentContext> mxContext;
72  Desktop *mpDesktop;
73  sal_Int32 mnLevel;
74  sal_Int32 mnProgress;
75 
76 public:
77  SilentCommandEnv(
78  uno::Reference<uno::XComponentContext> const & xContext,
79  Desktop* pDesktop );
80  virtual ~SilentCommandEnv() override;
81 
82  // XCommandEnvironment
83  virtual uno::Reference<task::XInteractionHandler > SAL_CALL
84  getInteractionHandler() override;
85  virtual uno::Reference<ucb::XProgressHandler >
86  SAL_CALL getProgressHandler() override;
87 
88  // XInteractionHandler
89  virtual void SAL_CALL handle(
90  uno::Reference<task::XInteractionRequest > const & xRequest ) override;
91 
92  // XProgressHandler
93  virtual void SAL_CALL push( uno::Any const & Status ) override;
94  virtual void SAL_CALL update( uno::Any const & Status ) override;
95  virtual void SAL_CALL pop() override;
96 };
97 
98 
99 SilentCommandEnv::SilentCommandEnv(
100  uno::Reference<uno::XComponentContext> const & xContext,
101  Desktop* pDesktop ):
102  mxContext( xContext ),
103  mpDesktop( pDesktop ),
104  mnLevel( 0 ),
105  mnProgress( 25 )
106 {}
107 
108 
109 SilentCommandEnv::~SilentCommandEnv()
110 {
111  if (mpDesktop)
112  mpDesktop->SetSplashScreenText(OUString());
113 }
114 
115 
116 Reference<task::XInteractionHandler> SilentCommandEnv::getInteractionHandler()
117 {
118  return this;
119 }
120 
121 
122 Reference<ucb::XProgressHandler> SilentCommandEnv::getProgressHandler()
123 {
124  return this;
125 }
126 
127 
128 // XInteractionHandler
129 void SilentCommandEnv::handle( Reference< task::XInteractionRequest> const & xRequest )
130 {
131  deployment::LicenseException licExc;
132 
133  uno::Any request( xRequest->getRequest() );
134  bool bApprove = true;
135 
136  if ( request >>= licExc )
137  {
138  uno::Reference< ui::dialogs::XExecutableDialog > xDialog(
141  licExc.ExtensionName, licExc.Text ) );
142  sal_Int16 res = xDialog->execute();
143  if ( res == ui::dialogs::ExecutableDialogResults::CANCEL )
144  bApprove = false;
145  else if ( res == ui::dialogs::ExecutableDialogResults::OK )
146  bApprove = true;
147  else
148  {
149  OSL_ASSERT(false);
150  }
151  }
152 
153  // We approve everything here
154  uno::Sequence< Reference< task::XInteractionContinuation > > conts( xRequest->getContinuations() );
155  Reference< task::XInteractionContinuation > const * pConts = conts.getConstArray();
156  sal_Int32 len = conts.getLength();
157 
158  for ( sal_Int32 pos = 0; pos < len; ++pos )
159  {
160  if ( bApprove )
161  {
162  uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY );
163  if ( xInteractionApprove.is() )
164  xInteractionApprove->select();
165  }
166  else
167  {
168  uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY );
169  if ( xInteractionAbort.is() )
170  xInteractionAbort->select();
171  }
172  }
173 }
174 
175 
176 // XProgressHandler
177 void SilentCommandEnv::push( uno::Any const & rStatus )
178 {
179  OUString sText;
180  mnLevel += 1;
181 
182  if (mpDesktop && rStatus.hasValue() && (rStatus >>= sText))
183  {
184  if ( mnLevel <= 3 )
185  mpDesktop->SetSplashScreenText( sText );
186  else
187  mpDesktop->SetSplashScreenProgress( ++mnProgress );
188  }
189 }
190 
191 
192 void SilentCommandEnv::update( uno::Any const & rStatus )
193 {
194  OUString sText;
195  if (mpDesktop && rStatus.hasValue() && (rStatus >>= sText))
196  {
197  mpDesktop->SetSplashScreenText( sText );
198  }
199 }
200 
201 
202 void SilentCommandEnv::pop()
203 {
204  mnLevel -= 1;
205 }
206 
207 } // end namespace
208 
209 
210 const char aAccessSrvc[] = "com.sun.star.configuration.ConfigurationUpdateAccess";
211 
212 static sal_Int16 impl_showExtensionDialog( uno::Reference< uno::XComponentContext > const &xContext )
213 {
214  uno::Reference< uno::XInterface > xService;
215  sal_Int16 nRet = 0;
216 
217  uno::Reference< lang::XMultiComponentFactory > xServiceManager( xContext->getServiceManager() );
218  if( !xServiceManager.is() )
219  throw uno::RuntimeException(
220  "impl_showExtensionDialog(): unable to obtain service manager from component context", uno::Reference< uno::XInterface > () );
221 
222  xService = xServiceManager->createInstanceWithContext( "com.sun.star.deployment.ui.UpdateRequiredDialog", xContext );
223  uno::Reference< ui::dialogs::XExecutableDialog > xExecuteable( xService, uno::UNO_QUERY );
224  if ( xExecuteable.is() )
225  nRet = xExecuteable->execute();
226 
227  return nRet;
228 }
229 
230 
231 // Check dependencies of all packages
232 
233 static bool impl_checkDependencies( const uno::Reference< uno::XComponentContext > &xContext )
234 {
235  uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
236  uno::Reference< deployment::XExtensionManager > xExtensionManager = deployment::ExtensionManager::get( xContext );
237 
238  if ( !xExtensionManager.is() )
239  {
240  SAL_WARN( "desktop.app", "Could not get the Extension Manager!" );
241  return true;
242  }
243 
244  try {
245  xAllPackages = xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
246  uno::Reference< ucb::XCommandEnvironment >() );
247  }
248  catch ( const deployment::DeploymentException & ) { return true; }
249  catch ( const ucb::CommandFailedException & ) { return true; }
250  catch ( const ucb::CommandAbortedException & ) { return true; }
251  catch ( const lang::IllegalArgumentException & e ) {
252  css::uno::Any anyEx = cppu::getCaughtException();
253  throw css::lang::WrappedTargetRuntimeException( e.Message,
254  e.Context, anyEx );
255  }
256 
257 #ifdef DEBUG
258  sal_Int32 const nMax = 3;
259 #else
260  sal_Int32 const nMax = 2;
261 #endif
262 
263  for ( uno::Sequence< uno::Reference< deployment::XPackage > > const & xPackageList : std::as_const(xAllPackages) )
264  {
265  for ( sal_Int32 j = 0; (j<nMax) && (j < xPackageList.getLength()); ++j )
266  {
267  uno::Reference< deployment::XPackage > xPackage = xPackageList[j];
268  if ( xPackage.is() )
269  {
270  bool bRegistered = false;
271  try {
272  beans::Optional< beans::Ambiguous< sal_Bool > > option( xPackage->isRegistered( uno::Reference< task::XAbortChannel >(),
273  uno::Reference< ucb::XCommandEnvironment >() ) );
274  if ( option.IsPresent )
275  {
276  ::beans::Ambiguous< sal_Bool > const & reg = option.Value;
277  if ( reg.IsAmbiguous )
278  bRegistered = false;
279  else
280  bRegistered = reg.Value;
281  }
282  else
283  bRegistered = false;
284  }
285  catch ( const uno::RuntimeException & ) { throw; }
286  catch (const uno::Exception & ) {
287  TOOLS_WARN_EXCEPTION( "desktop.app", "" );
288  }
289 
290  if ( bRegistered )
291  {
292  bool bDependenciesValid = false;
293  try {
294  bDependenciesValid = xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() );
295  }
296  catch ( const deployment::DeploymentException & ) {}
297  if ( ! bDependenciesValid )
298  {
299  return false;
300  }
301  }
302  }
303  }
304  }
305  return true;
306 }
307 
308 
309 // resets the 'check needed' flag (needed, if aborted)
310 
312 {
313  try {
314  Reference< XMultiServiceFactory > theConfigProvider(
315  configuration::theDefaultProvider::get(
317 
318  Sequence< Any > theArgs(1);
319  beans::NamedValue v( "nodepath",
320  makeAny( OUString("org.openoffice.Setup/Office") ) );
321  theArgs[0] <<= v;
323  theConfigProvider->createInstanceWithArguments( aAccessSrvc, theArgs ), UNO_QUERY_THROW );
324 
325  Any value = makeAny( 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  Sequence< Any > theArgs(1);
350  beans::NamedValue v( "nodepath",
351  makeAny( OUString("org.openoffice.Setup/Office") ) );
352  theArgs[0] <<= v;
354  theConfigProvider->createInstanceWithArguments( aAccessSrvc, theArgs ), UNO_QUERY_THROW );
355 
356  Any result = pset->getPropertyValue("LastCompatibilityCheckID");
357 
358  result >>= aLastCheckBuildID;
359  if ( aLastCheckBuildID != aCurrentBuildID )
360  {
361  bNeedsCheck = true;
362  result <<= aCurrentBuildID;
363  pset->setPropertyValue("LastCompatibilityCheckID", result );
364  Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
365  }
366 #ifdef DEBUG
367  bNeedsCheck = true;
368 #endif
369  }
370  catch (const css::uno::Exception&) {}
371 
372  return bNeedsCheck;
373 }
374 
375 
376 // Do we need to check the dependencies of the extensions?
377 // When there are unresolved issues, we can't continue with startup
378 bool Desktop::CheckExtensionDependencies()
379 {
380  if (!impl_needsCompatCheck())
381  {
382  return false;
383  }
384 
385  uno::Reference< uno::XComponentContext > xContext(
387 
388  bool bDependenciesValid = impl_checkDependencies( xContext );
389 
390  short nRet = 0;
391 
392  if ( !bDependenciesValid )
393  nRet = impl_showExtensionDialog( xContext );
394 
395  if ( nRet == -1 )
396  {
398  return true;
399  }
400  else
401  return false;
402 }
403 
404 void Desktop::SynchronizeExtensionRepositories(bool bCleanedExtensionCache, Desktop* pDesktop)
405 {
406  uno::Reference< uno::XComponentContext > context(
408  uno::Reference< ucb::XCommandEnvironment > silent(
409  new SilentCommandEnv(context, pDesktop));
410  if (bCleanedExtensionCache) {
411  deployment::ExtensionManager::get(context)->reinstallDeployedExtensions(
412  true, "user", Reference<task::XAbortChannel>(), silent);
413 #if !HAVE_FEATURE_MACOSX_SANDBOX
415  task::OfficeRestartManager::get(context)->requestRestart(
416  silent->getInteractionHandler());
417 #endif
418  } else {
419  // reinstallDeployedExtensions above already calls syncRepositories internally
420 
421  // Force syncing repositories on startup. There are cases where the extension
422  // registration becomes invalid which leads to extensions not starting up, although
423  // installed and active. Syncing extension repos on startup fixes that.
424  dp_misc::syncRepositories(/*force=*/true, silent);
425  }
426 }
427 
428 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool hasValue()
bool update()
Definition: updater.cxx:284
sal_Int16 mnLevel
uno::Reference< uno::XComponentContext > mxContext
static bool impl_checkDependencies(const uno::Reference< uno::XComponentContext > &xContext)
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)
Definition: app.cxx:161
JCOPY_OPTION option
Any SAL_CALL getCaughtException()
size_t pos
static bool impl_needsCompatCheck()
#define SAL_CONFIGFILE(name)
#define TOOLS_WARN_EXCEPTION(area, stream)
static sal_Int16 impl_showExtensionDialog(uno::Reference< uno::XComponentContext > const &xContext)
static void impl_setNeedsCompatCheck()
const char aAccessSrvc[]
float v
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2105
static void SynchronizeExtensionRepositories(bool bCleanedExtensionCache, Desktop *pDesktop=nullptr)
Reference< XComponentContext > getProcessComponentContext()
Any value
Any result
#define SAL_WARN(area, stream)
static css::uno::Reference< css::awt::XWindow > GetInterface(vcl::Window *pWindow)
css::uno::Any SAL_CALL makeAny(const SharedUNOComponent< INTERFACE, COMPONENT > &value)