Line data Source code
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 "osl/file.hxx"
21 : #include "osl/mutex.hxx"
22 :
23 : #include <rtl/bootstrap.hxx>
24 : #include <rtl/ustring.hxx>
25 : #include "cppuhelper/compbase3.hxx"
26 :
27 : #include "vcl/wrkwin.hxx"
28 : #include "vcl/timer.hxx"
29 :
30 : #include <unotools/configmgr.hxx>
31 : #include "toolkit/helper/vclunohelper.hxx"
32 :
33 : #include <comphelper/processfactory.hxx>
34 : #include <comphelper/sequence.hxx>
35 : #include <cppuhelper/bootstrap.hxx>
36 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
37 : #include <com/sun/star/beans/XPropertySet.hpp>
38 : #include <com/sun/star/beans/NamedValue.hpp>
39 : #include <com/sun/star/configuration/theDefaultProvider.hpp>
40 : #include "com/sun/star/deployment/XPackage.hpp"
41 : #include "com/sun/star/deployment/ExtensionManager.hpp"
42 : #include "com/sun/star/deployment/LicenseException.hpp"
43 : #include "com/sun/star/deployment/ui/LicenseDialog.hpp"
44 : #include <com/sun/star/task/OfficeRestartManager.hpp>
45 : #include <com/sun/star/task/XJob.hpp>
46 : #include <com/sun/star/task/XJobExecutor.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 "../deployment/inc/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::WeakImplHelper3< 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();
81 :
82 : // XCommandEnvironment
83 : virtual uno::Reference<task::XInteractionHandler > SAL_CALL
84 : getInteractionHandler() throw (uno::RuntimeException);
85 : virtual uno::Reference<ucb::XProgressHandler >
86 : SAL_CALL getProgressHandler() throw (uno::RuntimeException);
87 :
88 : // XInteractionHandler
89 : virtual void SAL_CALL handle(
90 : uno::Reference<task::XInteractionRequest > const & xRequest )
91 : throw (uno::RuntimeException);
92 :
93 : // XProgressHandler
94 : virtual void SAL_CALL push( uno::Any const & Status )
95 : throw (uno::RuntimeException);
96 : virtual void SAL_CALL update( uno::Any const & Status )
97 : throw (uno::RuntimeException);
98 : virtual void SAL_CALL pop() throw (uno::RuntimeException);
99 : };
100 :
101 : //-----------------------------------------------------------------------------
102 83 : SilentCommandEnv::SilentCommandEnv(
103 : uno::Reference<uno::XComponentContext> const & xContext,
104 : Desktop* pDesktop ):
105 : mxContext( xContext ),
106 : mpDesktop( pDesktop ),
107 : mnLevel( 0 ),
108 83 : mnProgress( 25 )
109 83 : {}
110 :
111 : //-----------------------------------------------------------------------------
112 249 : SilentCommandEnv::~SilentCommandEnv()
113 : {
114 83 : mpDesktop->SetSplashScreenText( OUString() );
115 166 : }
116 :
117 : //-----------------------------------------------------------------------------
118 256 : Reference<task::XInteractionHandler> SilentCommandEnv::getInteractionHandler()
119 : throw (uno::RuntimeException)
120 : {
121 256 : return this;
122 : }
123 :
124 : //-----------------------------------------------------------------------------
125 416 : Reference<ucb::XProgressHandler> SilentCommandEnv::getProgressHandler()
126 : throw (uno::RuntimeException)
127 : {
128 416 : return this;
129 : }
130 :
131 : //-----------------------------------------------------------------------------
132 : // XInteractionHandler
133 0 : void SilentCommandEnv::handle( Reference< task::XInteractionRequest> const & xRequest )
134 : throw (uno::RuntimeException)
135 : {
136 0 : deployment::LicenseException licExc;
137 :
138 0 : uno::Any request( xRequest->getRequest() );
139 0 : bool bApprove = true;
140 :
141 0 : if ( request >>= licExc )
142 : {
143 : uno::Reference< ui::dialogs::XExecutableDialog > xDialog(
144 : deployment::ui::LicenseDialog::create(
145 : mxContext, VCLUnoHelper::GetInterface( NULL ),
146 0 : licExc.ExtensionName, licExc.Text ) );
147 0 : sal_Int16 res = xDialog->execute();
148 0 : if ( res == ui::dialogs::ExecutableDialogResults::CANCEL )
149 0 : bApprove = false;
150 0 : else if ( res == ui::dialogs::ExecutableDialogResults::OK )
151 0 : bApprove = true;
152 : else
153 : {
154 : OSL_ASSERT(0);
155 0 : }
156 : }
157 :
158 : // We approve everything here
159 0 : uno::Sequence< Reference< task::XInteractionContinuation > > conts( xRequest->getContinuations() );
160 0 : Reference< task::XInteractionContinuation > const * pConts = conts.getConstArray();
161 0 : sal_Int32 len = conts.getLength();
162 :
163 0 : for ( sal_Int32 pos = 0; pos < len; ++pos )
164 : {
165 0 : if ( bApprove )
166 : {
167 0 : uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY );
168 0 : if ( xInteractionApprove.is() )
169 0 : xInteractionApprove->select();
170 : }
171 : else
172 : {
173 0 : uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY );
174 0 : if ( xInteractionAbort.is() )
175 0 : xInteractionAbort->select();
176 : }
177 0 : }
178 0 : }
179 :
180 : //-----------------------------------------------------------------------------
181 : // XProgressHandler
182 288 : void SilentCommandEnv::push( uno::Any const & rStatus )
183 : throw (uno::RuntimeException)
184 : {
185 288 : OUString sText;
186 288 : mnLevel += 1;
187 :
188 288 : if ( rStatus.hasValue() && ( rStatus >>= sText) )
189 : {
190 288 : if ( mnLevel <= 3 )
191 128 : mpDesktop->SetSplashScreenText( sText );
192 : else
193 160 : mpDesktop->SetSplashScreenProgress( ++mnProgress );
194 288 : }
195 288 : }
196 :
197 : //-----------------------------------------------------------------------------
198 64 : void SilentCommandEnv::update( uno::Any const & rStatus )
199 : throw (uno::RuntimeException)
200 : {
201 64 : OUString sText;
202 64 : if ( rStatus.hasValue() && ( rStatus >>= sText) )
203 : {
204 64 : mpDesktop->SetSplashScreenText( sText );
205 64 : }
206 64 : }
207 :
208 : //-----------------------------------------------------------------------------
209 288 : void SilentCommandEnv::pop() throw (uno::RuntimeException)
210 : {
211 288 : mnLevel -= 1;
212 288 : }
213 :
214 : } // end namespace
215 :
216 :
217 : static const char aAccessSrvc[] = "com.sun.star.configuration.ConfigurationUpdateAccess";
218 :
219 0 : static sal_Int16 impl_showExtensionDialog( uno::Reference< uno::XComponentContext > &xContext )
220 : {
221 0 : OUString sServiceName = "com.sun.star.deployment.ui.UpdateRequiredDialog";
222 0 : uno::Reference< uno::XInterface > xService;
223 0 : sal_Int16 nRet = 0;
224 :
225 0 : uno::Reference< lang::XMultiComponentFactory > xServiceManager( xContext->getServiceManager() );
226 0 : if( !xServiceManager.is() )
227 : throw uno::RuntimeException(
228 0 : "impl_showExtensionDialog(): unable to obtain service manager from component context", uno::Reference< uno::XInterface > () );
229 :
230 0 : xService = xServiceManager->createInstanceWithContext( sServiceName, xContext );
231 0 : uno::Reference< ui::dialogs::XExecutableDialog > xExecuteable( xService, uno::UNO_QUERY );
232 0 : if ( xExecuteable.is() )
233 0 : nRet = xExecuteable->execute();
234 :
235 0 : return nRet;
236 : }
237 :
238 : //------------------------------------------------------------------------------
239 : // Check dependencies of all packages
240 : //------------------------------------------------------------------------------
241 32 : static bool impl_checkDependencies( const uno::Reference< uno::XComponentContext > &xContext )
242 : {
243 32 : uno::Sequence< uno::Sequence< uno::Reference< deployment::XPackage > > > xAllPackages;
244 64 : uno::Reference< deployment::XExtensionManager > xExtensionManager = deployment::ExtensionManager::get( xContext );
245 :
246 32 : if ( !xExtensionManager.is() )
247 : {
248 : SAL_WARN( "desktop.app", "Could not get the Extension Manager!" );
249 0 : return true;
250 : }
251 :
252 : try {
253 96 : xAllPackages = xExtensionManager->getAllExtensions( uno::Reference< task::XAbortChannel >(),
254 64 : uno::Reference< ucb::XCommandEnvironment >() );
255 : }
256 0 : catch ( const deployment::DeploymentException & ) { return true; }
257 0 : catch ( const ucb::CommandFailedException & ) { return true; }
258 0 : catch ( const ucb::CommandAbortedException & ) { return true; }
259 0 : catch ( const lang::IllegalArgumentException & e ) {
260 0 : throw uno::RuntimeException( e.Message, e.Context );
261 : }
262 :
263 32 : sal_Int32 nMax = 2;
264 : #ifdef DEBUG
265 : nMax = 3;
266 : #endif
267 :
268 64 : for ( sal_Int32 i = 0; i < xAllPackages.getLength(); ++i )
269 : {
270 32 : uno::Sequence< uno::Reference< deployment::XPackage > > xPackageList = xAllPackages[i];
271 :
272 96 : for ( sal_Int32 j = 0; (j<nMax) && (j < xPackageList.getLength()); ++j )
273 : {
274 64 : uno::Reference< deployment::XPackage > xPackage = xPackageList[j];
275 64 : if ( xPackage.is() )
276 : {
277 0 : bool bRegistered = false;
278 : try {
279 0 : beans::Optional< beans::Ambiguous< sal_Bool > > option( xPackage->isRegistered( uno::Reference< task::XAbortChannel >(),
280 0 : uno::Reference< ucb::XCommandEnvironment >() ) );
281 0 : if ( option.IsPresent )
282 : {
283 0 : ::beans::Ambiguous< sal_Bool > const & reg = option.Value;
284 0 : if ( reg.IsAmbiguous )
285 0 : bRegistered = false;
286 : else
287 0 : bRegistered = reg.Value ? true : false;
288 : }
289 : else
290 0 : bRegistered = false;
291 : }
292 0 : catch ( const uno::RuntimeException & ) { throw; }
293 0 : catch (const uno::Exception & exc) {
294 : (void) exc;
295 : SAL_WARN( "desktop.app", "" << exc.Message );
296 : }
297 :
298 0 : if ( bRegistered )
299 : {
300 0 : bool bDependenciesValid = false;
301 : try {
302 0 : bDependenciesValid = xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() );
303 : }
304 0 : catch ( const deployment::DeploymentException & ) {}
305 0 : if ( ! bDependenciesValid )
306 : {
307 0 : return false;
308 : }
309 : }
310 : }
311 64 : }
312 32 : }
313 64 : return true;
314 : }
315 :
316 : //------------------------------------------------------------------------------
317 : // resets the 'check needed' flag (needed, if aborted)
318 : //------------------------------------------------------------------------------
319 0 : static void impl_setNeedsCompatCheck()
320 : {
321 : try {
322 : Reference< XMultiServiceFactory > theConfigProvider(
323 : configuration::theDefaultProvider::get(
324 0 : comphelper::getProcessComponentContext() ) );
325 :
326 0 : Sequence< Any > theArgs(1);
327 : beans::NamedValue v( OUString("nodepath"),
328 0 : makeAny( OUString("org.openoffice.Setup/Office") ) );
329 0 : theArgs[0] <<= v;
330 : Reference< beans::XPropertySet > pset = Reference< beans::XPropertySet >(
331 0 : theConfigProvider->createInstanceWithArguments( OUString(aAccessSrvc), theArgs ), UNO_QUERY_THROW );
332 :
333 0 : Any value = makeAny( OUString("never") );
334 :
335 0 : pset->setPropertyValue("LastCompatibilityCheckID", value );
336 0 : Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
337 : }
338 0 : catch (const Exception&) {}
339 0 : }
340 :
341 : //------------------------------------------------------------------------------
342 : // to check if we need checking the dependencies of the extensions again, we compare
343 : // the build id of the office with the one of the last check
344 : //------------------------------------------------------------------------------
345 83 : static bool impl_needsCompatCheck()
346 : {
347 83 : bool bNeedsCheck = false;
348 83 : OUString aLastCheckBuildID;
349 166 : OUString aCurrentBuildID( "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("version") ":buildid}" );
350 83 : rtl::Bootstrap::expandMacros( aCurrentBuildID );
351 :
352 : try {
353 : Reference< XMultiServiceFactory > theConfigProvider(
354 : configuration::theDefaultProvider::get(
355 83 : comphelper::getProcessComponentContext() ) );
356 :
357 166 : Sequence< Any > theArgs(1);
358 : beans::NamedValue v( OUString("nodepath"),
359 166 : makeAny( OUString("org.openoffice.Setup/Office") ) );
360 83 : theArgs[0] <<= v;
361 : Reference< beans::XPropertySet > pset = Reference< beans::XPropertySet >(
362 166 : theConfigProvider->createInstanceWithArguments( OUString(aAccessSrvc), theArgs ), UNO_QUERY_THROW );
363 :
364 166 : Any result = pset->getPropertyValue("LastCompatibilityCheckID");
365 :
366 83 : result >>= aLastCheckBuildID;
367 83 : if ( aLastCheckBuildID != aCurrentBuildID )
368 : {
369 32 : bNeedsCheck = true;
370 32 : result <<= aCurrentBuildID;
371 32 : pset->setPropertyValue("LastCompatibilityCheckID", result );
372 32 : Reference< util::XChangesBatch >( pset, UNO_QUERY_THROW )->commitChanges();
373 83 : }
374 : #ifdef DEBUG
375 : bNeedsCheck = true;
376 : #endif
377 : }
378 0 : catch (const com::sun::star::uno::Exception&) {}
379 :
380 166 : return bNeedsCheck;
381 : }
382 :
383 : //------------------------------------------------------------------------------
384 : // Do we need to check the dependencies of the extensions?
385 : // When there are unresolved issues, we can't continue with startup
386 83 : sal_Bool Desktop::CheckExtensionDependencies()
387 : {
388 83 : if (!impl_needsCompatCheck())
389 : {
390 51 : return false;
391 : }
392 :
393 32 : uno::Reference< uno::XComponentContext > xContext = comphelper_getProcessComponentContext();
394 :
395 32 : bool bDependenciesValid = impl_checkDependencies( xContext );
396 :
397 32 : short nRet = 0;
398 :
399 32 : if ( !bDependenciesValid )
400 0 : nRet = impl_showExtensionDialog( xContext );
401 :
402 32 : if ( nRet == -1 )
403 : {
404 0 : impl_setNeedsCompatCheck();
405 0 : return true;
406 : }
407 : else
408 32 : return false;
409 : }
410 :
411 83 : void Desktop::SynchronizeExtensionRepositories()
412 : {
413 : SAL_INFO( "desktop.app", "desktop (jl) ::Desktop::SynchronizeExtensionRepositories");
414 : uno::Reference< uno::XComponentContext > context(
415 83 : comphelper_getProcessComponentContext());
416 : uno::Reference< ucb::XCommandEnvironment > silent(
417 166 : new SilentCommandEnv(context, this));
418 83 : if (m_bCleanedExtensionCache) {
419 64 : deployment::ExtensionManager::get(context)->reinstallDeployedExtensions(
420 32 : true, "user", Reference<task::XAbortChannel>(), silent);
421 64 : task::OfficeRestartManager::get(context)->requestRestart(
422 32 : silent->getInteractionHandler());
423 : } else {
424 : // reinstallDeployedExtensions above already calls syncRepositories
425 : // internally:
426 51 : dp_misc::syncRepositories(false, silent);
427 83 : }
428 332 : }
429 :
430 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|