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