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