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 //----------------------------------------------------------------------------- 104 SilentCommandEnv::SilentCommandEnv( Desktop* pDesktop ) 105 { 106 mpDesktop = pDesktop; 107 mnLevel = 0; 108 mnProgress = 25; 109 } 110 111 //----------------------------------------------------------------------------- 112 SilentCommandEnv::~SilentCommandEnv() 113 { 114 mpDesktop->SetSplashScreenText( OUString() ); 115 } 116 117 //----------------------------------------------------------------------------- 118 Reference<task::XInteractionHandler> SilentCommandEnv::getInteractionHandler() 119 throw (uno::RuntimeException) 120 { 121 return this; 122 } 123 124 //----------------------------------------------------------------------------- 125 Reference<ucb::XProgressHandler> SilentCommandEnv::getProgressHandler() 126 throw (uno::RuntimeException) 127 { 128 return this; 129 } 130 131 //----------------------------------------------------------------------------- 132 // XInteractionHandler 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 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 //----------------------------------------------------------------------------- 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 //----------------------------------------------------------------------------- 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 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 423 void Desktop::SynchronizeExtensionRepositories() 424 { 425 RTL_LOGFILE_CONTEXT(aLog,"desktop (jl) ::Desktop::SynchronizeExtensionRepositories"); 426 dp_misc::syncRepositories( new SilentCommandEnv( this ) ); 427 } 428