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