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