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 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_desktop.hxx" 26 27 28 29 #include <dp_gui_handleversionexception.hxx> 30 31 #include "sal/config.h" 32 33 #include <cstddef> 34 35 #include "com/sun/star/beans/PropertyValue.hpp" 36 #include "com/sun/star/beans/NamedValue.hpp" 37 38 #include "com/sun/star/deployment/DependencyException.hpp" 39 #include "com/sun/star/deployment/LicenseException.hpp" 40 #include "com/sun/star/deployment/VersionException.hpp" 41 #include "com/sun/star/deployment/InstallException.hpp" 42 #include "com/sun/star/deployment/PlatformException.hpp" 43 44 #include "com/sun/star/deployment/ui/LicenseDialog.hpp" 45 #include "com/sun/star/deployment/DeploymentException.hpp" 46 #include "com/sun/star/deployment/UpdateInformationProvider.hpp" 47 #include "com/sun/star/deployment/XPackage.hpp" 48 49 #include "com/sun/star/task/XAbortChannel.hpp" 50 #include "com/sun/star/task/XInteractionAbort.hpp" 51 #include "com/sun/star/task/XInteractionApprove.hpp" 52 53 #include "com/sun/star/ucb/CommandAbortedException.hpp" 54 #include "com/sun/star/ucb/CommandFailedException.hpp" 55 #include "com/sun/star/ucb/XCommandEnvironment.hpp" 56 57 #include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp" 58 59 #include "com/sun/star/uno/Reference.hxx" 60 #include "com/sun/star/uno/RuntimeException.hpp" 61 #include "com/sun/star/uno/Sequence.hxx" 62 #include "com/sun/star/uno/XInterface.hpp" 63 #include "com/sun/star/uno/TypeClass.hpp" 64 #include "osl/diagnose.h" 65 #include "osl/mutex.hxx" 66 #include "rtl/ref.hxx" 67 #include "rtl/ustring.h" 68 #include "rtl/ustring.hxx" 69 #include "sal/types.h" 70 #include "ucbhelper/content.hxx" 71 #include "cppuhelper/exc_hlp.hxx" 72 #include "cppuhelper/implbase3.hxx" 73 #include "comphelper/anytostring.hxx" 74 #include "vcl/msgbox.hxx" 75 #include "toolkit/helper/vclunohelper.hxx" 76 #include "comphelper/processfactory.hxx" 77 78 #include "dp_gui.h" 79 #include "dp_gui_thread.hxx" 80 #include "dp_gui_extensioncmdqueue.hxx" 81 #include "dp_gui_dependencydialog.hxx" 82 #include "dp_gui_dialog2.hxx" 83 #include "dp_gui_shared.hxx" 84 #include "dp_gui_theextmgr.hxx" 85 #include "dp_gui_updatedialog.hxx" 86 #include "dp_gui_updateinstalldialog.hxx" 87 #include "dp_dependencies.hxx" 88 #include "dp_identifier.hxx" 89 #include "dp_version.hxx" 90 #include <dp_gui_handleversionexception.hxx> 91 92 #include <queue> 93 #include <boost/shared_ptr.hpp> 94 95 #if (defined(_MSC_VER) && (_MSC_VER < 1400)) 96 #define _WIN32_WINNT 0x0400 97 #endif 98 99 #ifdef WNT 100 #include "tools/prewin.h" 101 #include <objbase.h> 102 #include "tools/postwin.h" 103 #endif 104 105 106 using namespace ::com::sun::star; 107 using ::rtl::OUString; 108 109 namespace dp_gui { 110 111 //============================================================================== 112 113 class ProgressCmdEnv 114 : public ::cppu::WeakImplHelper3< ucb::XCommandEnvironment, 115 task::XInteractionHandler, 116 ucb::XProgressHandler > 117 { 118 uno::Reference< task::XInteractionHandler> m_xHandler; 119 uno::Reference< uno::XComponentContext > m_xContext; 120 uno::Reference< task::XAbortChannel> m_xAbortChannel; 121 122 DialogHelper *m_pDialogHelper; 123 OUString m_sTitle; 124 bool m_bAborted; 125 bool m_bWarnUser; 126 sal_Int32 m_nCurrentProgress; 127 128 void updateProgress(); 129 130 void update_( uno::Any const & Status ) throw ( uno::RuntimeException ); 131 132 public: 133 virtual ~ProgressCmdEnv(); 134 135 /** When param bAskWhenInstalling = true, then the user is asked if he 136 agrees to install this extension. In case this extension is already installed 137 then the user is also notified and asked if he wants to replace that existing 138 extension. In first case an interaction request with an InstallException 139 will be handled and in the second case a VersionException will be handled. 140 */ 141 142 ProgressCmdEnv( const uno::Reference< uno::XComponentContext > rContext, 143 DialogHelper *pDialogHelper, 144 const OUString &rTitle ) 145 : m_xContext( rContext ), 146 m_pDialogHelper( pDialogHelper ), 147 m_sTitle( rTitle ), 148 m_bAborted( false ), 149 m_bWarnUser( false ) 150 {} 151 152 Dialog * activeDialog() { return m_pDialogHelper ? m_pDialogHelper->getWindow() : NULL; } 153 154 void setTitle( const OUString& rNewTitle ) { m_sTitle = rNewTitle; } 155 void startProgress(); 156 void stopProgress(); 157 void progressSection( const OUString &rText, 158 const uno::Reference< task::XAbortChannel > &xAbortChannel = 0 ); 159 inline bool isAborted() const { return m_bAborted; } 160 inline void setWarnUser( bool bNewVal ) { m_bWarnUser = bNewVal; } 161 162 // XCommandEnvironment 163 virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler() 164 throw ( uno::RuntimeException ); 165 virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler() 166 throw ( uno::RuntimeException ); 167 168 // XInteractionHandler 169 virtual void SAL_CALL handle( uno::Reference< task::XInteractionRequest > const & xRequest ) 170 throw ( uno::RuntimeException ); 171 172 // XProgressHandler 173 virtual void SAL_CALL push( uno::Any const & Status ) 174 throw ( uno::RuntimeException ); 175 virtual void SAL_CALL update( uno::Any const & Status ) 176 throw ( uno::RuntimeException ); 177 virtual void SAL_CALL pop() throw ( uno::RuntimeException ); 178 }; 179 180 //------------------------------------------------------------------------------ 181 struct ExtensionCmd 182 { 183 enum E_CMD_TYPE { ADD, ENABLE, DISABLE, REMOVE, CHECK_FOR_UPDATES, ACCEPT_LICENSE }; 184 185 E_CMD_TYPE m_eCmdType; 186 bool m_bWarnUser; 187 OUString m_sExtensionURL; 188 OUString m_sRepository; 189 uno::Reference< deployment::XPackage > m_xPackage; 190 std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList; 191 192 ExtensionCmd( const E_CMD_TYPE eCommand, 193 const OUString &rExtensionURL, 194 const OUString &rRepository, 195 const bool bWarnUser ) 196 : m_eCmdType( eCommand ), 197 m_bWarnUser( bWarnUser ), 198 m_sExtensionURL( rExtensionURL ), 199 m_sRepository( rRepository ) {}; 200 ExtensionCmd( const E_CMD_TYPE eCommand, 201 const uno::Reference< deployment::XPackage > &rPackage ) 202 : m_eCmdType( eCommand ), 203 m_bWarnUser( false ), 204 m_xPackage( rPackage ) {}; 205 ExtensionCmd( const E_CMD_TYPE eCommand, 206 const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) 207 : m_eCmdType( eCommand ), 208 m_bWarnUser( false ), 209 m_vExtensionList( vExtensionList ) {}; 210 }; 211 212 typedef ::boost::shared_ptr< ExtensionCmd > TExtensionCmd; 213 214 //------------------------------------------------------------------------------ 215 class ExtensionCmdQueue::Thread: public dp_gui::Thread 216 { 217 public: 218 Thread( DialogHelper *pDialogHelper, 219 TheExtensionManager *pManager, 220 const uno::Reference< uno::XComponentContext > & rContext ); 221 222 void addExtension( const OUString &rExtensionURL, 223 const OUString &rRepository, 224 const bool bWarnUser ); 225 void removeExtension( const uno::Reference< deployment::XPackage > &rPackage ); 226 void enableExtension( const uno::Reference< deployment::XPackage > &rPackage, 227 const bool bEnable ); 228 void checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ); 229 void acceptLicense( const uno::Reference< deployment::XPackage > &rPackage ); 230 void stop(); 231 bool isBusy(); 232 233 static OUString searchAndReplaceAll( const OUString &rSource, 234 const OUString &rWhat, 235 const OUString &rWith ); 236 private: 237 Thread( Thread & ); // not defined 238 void operator =( Thread & ); // not defined 239 240 virtual ~Thread(); 241 242 virtual void execute(); 243 virtual void SAL_CALL onTerminated(); 244 245 void _addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 246 const OUString &rPackageURL, 247 const OUString &rRepository, 248 const bool bWarnUser ); 249 void _removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 250 const uno::Reference< deployment::XPackage > &xPackage ); 251 void _enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 252 const uno::Reference< deployment::XPackage > &xPackage ); 253 void _disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 254 const uno::Reference< deployment::XPackage > &xPackage ); 255 void _checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ); 256 void _acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 257 const uno::Reference< deployment::XPackage > &xPackage ); 258 259 enum Input { NONE, START, STOP }; 260 261 uno::Reference< uno::XComponentContext > m_xContext; 262 std::queue< TExtensionCmd > m_queue; 263 264 DialogHelper *m_pDialogHelper; 265 TheExtensionManager *m_pManager; 266 267 const OUString m_sEnablingPackages; 268 const OUString m_sDisablingPackages; 269 const OUString m_sAddingPackages; 270 const OUString m_sRemovingPackages; 271 const OUString m_sDefaultCmd; 272 const OUString m_sAcceptLicense; 273 osl::Condition m_wakeup; 274 osl::Mutex m_mutex; 275 Input m_eInput; 276 bool m_bTerminated; 277 bool m_bStopped; 278 bool m_bWorking; 279 }; 280 281 //------------------------------------------------------------------------------ 282 void ProgressCmdEnv::startProgress() 283 { 284 m_nCurrentProgress = 0; 285 286 if ( m_pDialogHelper ) 287 m_pDialogHelper->showProgress( true ); 288 } 289 290 //------------------------------------------------------------------------------ 291 void ProgressCmdEnv::stopProgress() 292 { 293 if ( m_pDialogHelper ) 294 m_pDialogHelper->showProgress( false ); 295 } 296 297 //------------------------------------------------------------------------------ 298 void ProgressCmdEnv::progressSection( const OUString &rText, 299 const uno::Reference< task::XAbortChannel > &xAbortChannel ) 300 { 301 m_xAbortChannel = xAbortChannel; 302 if (! m_bAborted) 303 { 304 m_nCurrentProgress = 0; 305 if ( m_pDialogHelper ) 306 { 307 m_pDialogHelper->updateProgress( rText, xAbortChannel ); 308 m_pDialogHelper->updateProgress( 5 ); 309 } 310 } 311 } 312 313 //------------------------------------------------------------------------------ 314 void ProgressCmdEnv::updateProgress() 315 { 316 if ( ! m_bAborted ) 317 { 318 long nProgress = ((m_nCurrentProgress*5) % 100) + 5; 319 if ( m_pDialogHelper ) 320 m_pDialogHelper->updateProgress( nProgress ); 321 } 322 } 323 324 //------------------------------------------------------------------------------ 325 ProgressCmdEnv::~ProgressCmdEnv() 326 { 327 // TODO: stop all threads and wait 328 } 329 330 331 //------------------------------------------------------------------------------ 332 // XCommandEnvironment 333 //------------------------------------------------------------------------------ 334 uno::Reference< task::XInteractionHandler > ProgressCmdEnv::getInteractionHandler() 335 throw ( uno::RuntimeException ) 336 { 337 return this; 338 } 339 340 //------------------------------------------------------------------------------ 341 uno::Reference< ucb::XProgressHandler > ProgressCmdEnv::getProgressHandler() 342 throw ( uno::RuntimeException ) 343 { 344 return this; 345 } 346 347 //------------------------------------------------------------------------------ 348 // XInteractionHandler 349 //------------------------------------------------------------------------------ 350 351 void ProgressCmdEnv::handle( uno::Reference< task::XInteractionRequest > const & xRequest ) 352 throw ( uno::RuntimeException ) 353 { 354 uno::Any request( xRequest->getRequest() ); 355 OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION ); 356 dp_misc::TRACE( OUSTR("[dp_gui_cmdenv.cxx] incoming request:\n") 357 + ::comphelper::anyToString(request) + OUSTR("\n")); 358 359 lang::WrappedTargetException wtExc; 360 deployment::DependencyException depExc; 361 deployment::LicenseException licExc; 362 deployment::VersionException verExc; 363 deployment::InstallException instExc; 364 deployment::PlatformException platExc; 365 366 // selections: 367 bool approve = false; 368 bool abort = false; 369 370 if (request >>= wtExc) { 371 // handable deployment error signalled, e.g. 372 // bundle item registration failed, notify cause only: 373 uno::Any cause; 374 deployment::DeploymentException dpExc; 375 if (wtExc.TargetException >>= dpExc) 376 cause = dpExc.Cause; 377 else { 378 ucb::CommandFailedException cfExc; 379 if (wtExc.TargetException >>= cfExc) 380 cause = cfExc.Reason; 381 else 382 cause = wtExc.TargetException; 383 } 384 update_( cause ); 385 386 // ignore intermediate errors of legacy packages, i.e. 387 // former pkgchk behaviour: 388 const uno::Reference< deployment::XPackage > xPackage( wtExc.Context, uno::UNO_QUERY ); 389 OSL_ASSERT( xPackage.is() ); 390 if ( xPackage.is() ) 391 { 392 const uno::Reference< deployment::XPackageTypeInfo > xPackageType( xPackage->getPackageType() ); 393 OSL_ASSERT( xPackageType.is() ); 394 if (xPackageType.is()) 395 { 396 approve = ( xPackage->isBundle() && 397 xPackageType->getMediaType().matchAsciiL( 398 RTL_CONSTASCII_STRINGPARAM( 399 "application/" 400 "vnd.sun.star.legacy-package-bundle") )); 401 } 402 } 403 abort = !approve; 404 } 405 else if (request >>= depExc) 406 { 407 std::vector< rtl::OUString > deps; 408 for (sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength(); 409 ++i) 410 { 411 deps.push_back( 412 dp_misc::Dependencies::getErrorText( depExc.UnsatisfiedDependencies[i]) ); 413 } 414 { 415 vos::OGuard guard(Application::GetSolarMutex()); 416 short n = DependencyDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, deps ).Execute(); 417 // Distinguish between closing the dialog and programatically 418 // canceling the dialog (headless VCL): 419 approve = n == RET_OK 420 || (n == RET_CANCEL && !Application::IsDialogCancelEnabled()); 421 } 422 } 423 else if (request >>= licExc) 424 { 425 uno::Reference< ui::dialogs::XExecutableDialog > xDialog( 426 deployment::ui::LicenseDialog::create( 427 m_xContext, VCLUnoHelper::GetInterface( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL ), 428 licExc.ExtensionName, licExc.Text ) ); 429 sal_Int16 res = xDialog->execute(); 430 if ( res == ui::dialogs::ExecutableDialogResults::CANCEL ) 431 abort = true; 432 else if ( res == ui::dialogs::ExecutableDialogResults::OK ) 433 approve = true; 434 else 435 { 436 OSL_ASSERT(0); 437 } 438 } 439 else if (request >>= verExc) 440 { 441 approve = handleVersionException( verExc, m_pDialogHelper ); 442 abort = !approve; 443 } 444 else if (request >>= instExc) 445 { 446 if ( ! m_bWarnUser ) 447 { 448 approve = true; 449 } 450 else 451 { 452 if ( m_pDialogHelper ) 453 { 454 vos::OGuard guard(Application::GetSolarMutex()); 455 456 approve = m_pDialogHelper->installExtensionWarn( instExc.displayName ); 457 } 458 else 459 approve = false; 460 abort = !approve; 461 } 462 } 463 else if (request >>= platExc) 464 { 465 vos::OGuard guard( Application::GetSolarMutex() ); 466 String sMsg( ResId( RID_STR_UNSUPPORTED_PLATFORM, *DeploymentGuiResMgr::get() ) ); 467 sMsg.SearchAndReplaceAllAscii( "%Name", platExc.package->getDisplayName() ); 468 ErrorBox box( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, WB_OK, sMsg ); 469 box.Execute(); 470 approve = true; 471 } 472 473 if (approve == false && abort == false) 474 { 475 // forward to UUI handler: 476 if (! m_xHandler.is()) { 477 // late init: 478 uno::Sequence< uno::Any > handlerArgs( 1 ); 479 handlerArgs[ 0 ] <<= beans::PropertyValue( 480 OUSTR("Context"), -1, uno::Any( m_sTitle ), 481 beans::PropertyState_DIRECT_VALUE ); 482 m_xHandler.set( m_xContext->getServiceManager() 483 ->createInstanceWithArgumentsAndContext( 484 OUSTR("com.sun.star.uui.InteractionHandler"), 485 handlerArgs, m_xContext ), uno::UNO_QUERY_THROW ); 486 } 487 m_xHandler->handle( xRequest ); 488 } 489 else 490 { 491 // select: 492 uno::Sequence< uno::Reference< task::XInteractionContinuation > > conts( 493 xRequest->getContinuations() ); 494 uno::Reference< task::XInteractionContinuation > const * pConts = conts.getConstArray(); 495 sal_Int32 len = conts.getLength(); 496 for ( sal_Int32 pos = 0; pos < len; ++pos ) 497 { 498 if (approve) { 499 uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY ); 500 if (xInteractionApprove.is()) { 501 xInteractionApprove->select(); 502 // don't query again for ongoing continuations: 503 approve = false; 504 } 505 } 506 else if (abort) { 507 uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY ); 508 if (xInteractionAbort.is()) { 509 xInteractionAbort->select(); 510 // don't query again for ongoing continuations: 511 abort = false; 512 } 513 } 514 } 515 } 516 } 517 518 //------------------------------------------------------------------------------ 519 // XProgressHandler 520 //------------------------------------------------------------------------------ 521 void ProgressCmdEnv::push( uno::Any const & rStatus ) 522 throw( uno::RuntimeException ) 523 { 524 update_( rStatus ); 525 } 526 527 //------------------------------------------------------------------------------ 528 void ProgressCmdEnv::update_( uno::Any const & rStatus ) 529 throw( uno::RuntimeException ) 530 { 531 OUString text; 532 if ( rStatus.hasValue() && !( rStatus >>= text) ) 533 { 534 if ( rStatus.getValueTypeClass() == uno::TypeClass_EXCEPTION ) 535 text = static_cast< uno::Exception const *>( rStatus.getValue() )->Message; 536 if ( text.getLength() == 0 ) 537 text = ::comphelper::anyToString( rStatus ); // fallback 538 539 const ::vos::OGuard aGuard( Application::GetSolarMutex() ); 540 const ::std::auto_ptr< ErrorBox > aBox( new ErrorBox( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, WB_OK, text ) ); 541 aBox->Execute(); 542 } 543 ++m_nCurrentProgress; 544 updateProgress(); 545 } 546 547 //------------------------------------------------------------------------------ 548 void ProgressCmdEnv::update( uno::Any const & rStatus ) 549 throw( uno::RuntimeException ) 550 { 551 update_( rStatus ); 552 } 553 554 //------------------------------------------------------------------------------ 555 void ProgressCmdEnv::pop() 556 throw( uno::RuntimeException ) 557 { 558 update_( uno::Any() ); // no message 559 } 560 561 //------------------------------------------------------------------------------ 562 ExtensionCmdQueue::Thread::Thread( DialogHelper *pDialogHelper, 563 TheExtensionManager *pManager, 564 const uno::Reference< uno::XComponentContext > & rContext ) : 565 m_xContext( rContext ), 566 m_pDialogHelper( pDialogHelper ), 567 m_pManager( pManager ), 568 m_sEnablingPackages( DialogHelper::getResourceString( RID_STR_ENABLING_PACKAGES ) ), 569 m_sDisablingPackages( DialogHelper::getResourceString( RID_STR_DISABLING_PACKAGES ) ), 570 m_sAddingPackages( DialogHelper::getResourceString( RID_STR_ADDING_PACKAGES ) ), 571 m_sRemovingPackages( DialogHelper::getResourceString( RID_STR_REMOVING_PACKAGES ) ), 572 m_sDefaultCmd( DialogHelper::getResourceString( RID_STR_ADD_PACKAGES ) ), 573 m_sAcceptLicense( DialogHelper::getResourceString( RID_STR_ACCEPT_LICENSE ) ), 574 m_eInput( NONE ), 575 m_bTerminated( false ), 576 m_bStopped( false ), 577 m_bWorking( false ) 578 { 579 OSL_ASSERT( pDialogHelper ); 580 } 581 582 //------------------------------------------------------------------------------ 583 void ExtensionCmdQueue::Thread::addExtension( const ::rtl::OUString &rExtensionURL, 584 const ::rtl::OUString &rRepository, 585 const bool bWarnUser ) 586 { 587 ::osl::MutexGuard aGuard( m_mutex ); 588 589 //If someone called stop then we do not add the extension -> game over! 590 if ( m_bStopped ) 591 return; 592 593 if ( rExtensionURL.getLength() ) 594 { 595 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ADD, rExtensionURL, rRepository, bWarnUser ) ); 596 597 m_queue.push( pEntry ); 598 m_eInput = START; 599 m_wakeup.set(); 600 } 601 } 602 603 //------------------------------------------------------------------------------ 604 void ExtensionCmdQueue::Thread::removeExtension( const uno::Reference< deployment::XPackage > &rPackage ) 605 { 606 ::osl::MutexGuard aGuard( m_mutex ); 607 608 //If someone called stop then we do not remove the extension -> game over! 609 if ( m_bStopped ) 610 return; 611 612 if ( rPackage.is() ) 613 { 614 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::REMOVE, rPackage ) ); 615 616 m_queue.push( pEntry ); 617 m_eInput = START; 618 m_wakeup.set(); 619 } 620 } 621 622 //------------------------------------------------------------------------------ 623 void ExtensionCmdQueue::Thread::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage ) 624 { 625 ::osl::MutexGuard aGuard( m_mutex ); 626 627 //If someone called stop then we do not remove the extension -> game over! 628 if ( m_bStopped ) 629 return; 630 631 if ( rPackage.is() ) 632 { 633 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ACCEPT_LICENSE, rPackage ) ); 634 635 m_queue.push( pEntry ); 636 m_eInput = START; 637 m_wakeup.set(); 638 } 639 } 640 641 //------------------------------------------------------------------------------ 642 void ExtensionCmdQueue::Thread::enableExtension( const uno::Reference< deployment::XPackage > &rPackage, 643 const bool bEnable ) 644 { 645 ::osl::MutexGuard aGuard( m_mutex ); 646 647 //If someone called stop then we do not remove the extension -> game over! 648 if ( m_bStopped ) 649 return; 650 651 if ( rPackage.is() ) 652 { 653 TExtensionCmd pEntry( new ExtensionCmd( bEnable ? ExtensionCmd::ENABLE : 654 ExtensionCmd::DISABLE, 655 rPackage ) ); 656 m_queue.push( pEntry ); 657 m_eInput = START; 658 m_wakeup.set(); 659 } 660 } 661 662 //------------------------------------------------------------------------------ 663 void ExtensionCmdQueue::Thread::checkForUpdates( 664 const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) 665 { 666 ::osl::MutexGuard aGuard( m_mutex ); 667 668 //If someone called stop then we do not update the extension -> game over! 669 if ( m_bStopped ) 670 return; 671 672 TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::CHECK_FOR_UPDATES, vExtensionList ) ); 673 m_queue.push( pEntry ); 674 m_eInput = START; 675 m_wakeup.set(); 676 } 677 678 //------------------------------------------------------------------------------ 679 //Stopping this thread will not abort the installation of extensions. 680 void ExtensionCmdQueue::Thread::stop() 681 { 682 osl::MutexGuard aGuard( m_mutex ); 683 m_bStopped = true; 684 m_eInput = STOP; 685 m_wakeup.set(); 686 } 687 688 //------------------------------------------------------------------------------ 689 bool ExtensionCmdQueue::Thread::isBusy() 690 { 691 osl::MutexGuard aGuard( m_mutex ); 692 return m_bWorking; 693 } 694 695 //------------------------------------------------------------------------------ 696 ExtensionCmdQueue::Thread::~Thread() {} 697 698 //------------------------------------------------------------------------------ 699 void ExtensionCmdQueue::Thread::execute() 700 { 701 #ifdef WNT 702 //Needed for use of the service "com.sun.star.system.SystemShellExecute" in 703 //DialogHelper::openWebBrowser 704 CoUninitialize(); 705 HRESULT r = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 706 #endif 707 for (;;) 708 { 709 if ( m_wakeup.wait() != osl::Condition::result_ok ) 710 { 711 dp_misc::TRACE( "dp_gui::ExtensionCmdQueue::Thread::run: ignored " 712 "osl::Condition::wait failure\n" ); 713 } 714 m_wakeup.reset(); 715 716 int nSize; 717 Input eInput; 718 { 719 osl::MutexGuard aGuard( m_mutex ); 720 eInput = m_eInput; 721 m_eInput = NONE; 722 nSize = m_queue.size(); 723 m_bWorking = false; 724 } 725 726 // If this thread has been woken up by anything else except start, stop 727 // then input is NONE and we wait again. 728 // We only install the extension which are currently in the queue. 729 // The progressbar will be set to show the progress of the current number 730 // of extensions. If we allowed to add extensions now then the progressbar may 731 // have reached the end while we still install newly added extensions. 732 if ( ( eInput == NONE ) || ( nSize == 0 ) ) 733 continue; 734 if ( eInput == STOP ) 735 break; 736 737 ::rtl::Reference< ProgressCmdEnv > currentCmdEnv( new ProgressCmdEnv( m_xContext, m_pDialogHelper, m_sDefaultCmd ) ); 738 739 // Do not lock the following part with addExtension. addExtension may be called in the main thread. 740 // If the message box "Do you want to install the extension (or similar)" is shown and then 741 // addExtension is called, which then blocks the main thread, then we deadlock. 742 bool bStartProgress = true; 743 744 while ( !currentCmdEnv->isAborted() && --nSize >= 0 ) 745 { 746 { 747 osl::MutexGuard aGuard( m_mutex ); 748 m_bWorking = true; 749 } 750 751 try 752 { 753 TExtensionCmd pEntry; 754 { 755 ::osl::MutexGuard queueGuard( m_mutex ); 756 pEntry = m_queue.front(); 757 m_queue.pop(); 758 } 759 760 if ( bStartProgress && ( pEntry->m_eCmdType != ExtensionCmd::CHECK_FOR_UPDATES ) ) 761 { 762 currentCmdEnv->startProgress(); 763 bStartProgress = false; 764 } 765 766 switch ( pEntry->m_eCmdType ) { 767 case ExtensionCmd::ADD : 768 _addExtension( currentCmdEnv, pEntry->m_sExtensionURL, pEntry->m_sRepository, pEntry->m_bWarnUser ); 769 break; 770 case ExtensionCmd::REMOVE : 771 _removeExtension( currentCmdEnv, pEntry->m_xPackage ); 772 break; 773 case ExtensionCmd::ENABLE : 774 _enableExtension( currentCmdEnv, pEntry->m_xPackage ); 775 break; 776 case ExtensionCmd::DISABLE : 777 _disableExtension( currentCmdEnv, pEntry->m_xPackage ); 778 break; 779 case ExtensionCmd::CHECK_FOR_UPDATES : 780 _checkForUpdates( pEntry->m_vExtensionList ); 781 break; 782 case ExtensionCmd::ACCEPT_LICENSE : 783 _acceptLicense( currentCmdEnv, pEntry->m_xPackage ); 784 break; 785 } 786 } 787 //catch ( deployment::DeploymentException &) 788 //{ 789 //} 790 //catch ( lang::IllegalArgumentException &) 791 //{ 792 //} 793 catch ( ucb::CommandAbortedException & ) 794 { 795 //This exception is thrown when the user clicks cancel on the progressbar. 796 //Then we cancel the installation of all extensions and remove them from 797 //the queue. 798 { 799 ::osl::MutexGuard queueGuard2(m_mutex); 800 while ( --nSize >= 0 ) 801 m_queue.pop(); 802 } 803 break; 804 } 805 catch ( ucb::CommandFailedException & ) 806 { 807 //This exception is thrown when a user clicked cancel in the messagebox which was 808 //startet by the interaction handler. For example the user will be asked if he/she 809 //really wants to install the extension. 810 //These interaction are run for exectly one extension at a time. Therefore we continue 811 //with installing the remaining extensions. 812 continue; 813 } 814 catch ( uno::Exception & ) 815 { 816 //Todo display the user an error 817 //see also DialogImpl::SyncPushButton::Click() 818 uno::Any exc( ::cppu::getCaughtException() ); 819 OUString msg; 820 deployment::DeploymentException dpExc; 821 if ((exc >>= dpExc) && 822 dpExc.Cause.getValueTypeClass() == uno::TypeClass_EXCEPTION) 823 { 824 // notify error cause only: 825 msg = reinterpret_cast< uno::Exception const * >( dpExc.Cause.getValue() )->Message; 826 } 827 if (msg.getLength() == 0) // fallback for debugging purposes 828 msg = ::comphelper::anyToString(exc); 829 830 const ::vos::OGuard guard( Application::GetSolarMutex() ); 831 ::std::auto_ptr<ErrorBox> box( 832 new ErrorBox( currentCmdEnv->activeDialog(), WB_OK, msg ) ); 833 if ( m_pDialogHelper ) 834 box->SetText( m_pDialogHelper->getWindow()->GetText() ); 835 box->Execute(); 836 //Continue with installation of the remaining extensions 837 } 838 { 839 osl::MutexGuard aGuard( m_mutex ); 840 m_bWorking = false; 841 } 842 } 843 844 { 845 // when leaving the while loop with break, we should set working to false, too 846 osl::MutexGuard aGuard( m_mutex ); 847 m_bWorking = false; 848 } 849 850 if ( !bStartProgress ) 851 currentCmdEnv->stopProgress(); 852 } 853 //end for 854 //enable all buttons 855 // m_pDialog->m_bAddingExtensions = false; 856 // m_pDialog->updateButtonStates(); 857 #ifdef WNT 858 CoUninitialize(); 859 #endif 860 } 861 862 //------------------------------------------------------------------------------ 863 void ExtensionCmdQueue::Thread::_addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 864 const OUString &rPackageURL, 865 const OUString &rRepository, 866 const bool bWarnUser ) 867 { 868 //check if we have a string in anyTitle. For example "unopkg gui \" caused anyTitle to be void 869 //and anyTitle.get<OUString> throws as RuntimeException. 870 uno::Any anyTitle; 871 try 872 { 873 anyTitle = ::ucbhelper::Content( rPackageURL, rCmdEnv.get() ).getPropertyValue( OUSTR("Title") ); 874 } 875 catch ( uno::Exception & ) 876 { 877 return; 878 } 879 880 OUString sName; 881 if ( ! (anyTitle >>= sName) ) 882 { 883 OSL_ENSURE(0, "Could not get file name for extension."); 884 return; 885 } 886 887 rCmdEnv->setWarnUser( bWarnUser ); 888 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); 889 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); 890 OUString sTitle = searchAndReplaceAll( m_sAddingPackages, OUSTR("%EXTENSION_NAME"), sName ); 891 rCmdEnv->progressSection( sTitle, xAbortChannel ); 892 893 try 894 { 895 xExtMgr->addExtension(rPackageURL, uno::Sequence<beans::NamedValue>(), 896 rRepository, xAbortChannel, rCmdEnv.get() ); 897 } 898 catch ( ucb::CommandFailedException & ) 899 { 900 // When the extension is already installed we'll get a dialog asking if we want to overwrite. If we then press 901 // cancel this exception is thrown. 902 } 903 catch ( ucb::CommandAbortedException & ) 904 { 905 // User clicked the cancel button 906 // TODO: handle cancel 907 } 908 rCmdEnv->setWarnUser( false ); 909 } 910 911 //------------------------------------------------------------------------------ 912 void ExtensionCmdQueue::Thread::_removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 913 const uno::Reference< deployment::XPackage > &xPackage ) 914 { 915 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); 916 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); 917 OUString sTitle = searchAndReplaceAll( m_sRemovingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); 918 rCmdEnv->progressSection( sTitle, xAbortChannel ); 919 920 OUString id( dp_misc::getIdentifier( xPackage ) ); 921 try 922 { 923 xExtMgr->removeExtension( id, xPackage->getName(), xPackage->getRepositoryName(), xAbortChannel, rCmdEnv.get() ); 924 } 925 catch ( deployment::DeploymentException & ) 926 {} 927 catch ( ucb::CommandFailedException & ) 928 {} 929 catch ( ucb::CommandAbortedException & ) 930 {} 931 932 // Check, if there are still updates to be notified via menu bar icon 933 uno::Sequence< uno::Sequence< rtl::OUString > > aItemList; 934 UpdateDialog::createNotifyJob( false, aItemList ); 935 } 936 937 //------------------------------------------------------------------------------ 938 void ExtensionCmdQueue::Thread::_checkForUpdates( 939 const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) 940 { 941 UpdateDialog* pUpdateDialog; 942 std::vector< UpdateData > vData; 943 944 const ::vos::OGuard guard( Application::GetSolarMutex() ); 945 946 pUpdateDialog = new UpdateDialog( m_xContext, m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, vExtensionList, &vData ); 947 948 pUpdateDialog->notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon 949 950 if ( ( pUpdateDialog->Execute() == RET_OK ) && !vData.empty() ) 951 { 952 // If there is at least one directly downloadable dialog then we 953 // open the install dialog. 954 ::std::vector< UpdateData > dataDownload; 955 int countWebsiteDownload = 0; 956 typedef std::vector< dp_gui::UpdateData >::const_iterator cit; 957 958 for ( cit i = vData.begin(); i < vData.end(); i++ ) 959 { 960 if ( i->sWebsiteURL.getLength() > 0 ) 961 countWebsiteDownload ++; 962 else 963 dataDownload.push_back( *i ); 964 } 965 966 short nDialogResult = RET_OK; 967 if ( !dataDownload.empty() ) 968 { 969 nDialogResult = UpdateInstallDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, dataDownload, m_xContext ).Execute(); 970 pUpdateDialog->notifyMenubar( false, true ); // Check, if there are still pending updates to be notified via menu bar icon 971 } 972 else 973 pUpdateDialog->notifyMenubar( false, false ); // Check, if there are pending updates to be notified via menu bar icon 974 975 //Now start the webbrowser and navigate to the websites where we get the updates 976 if ( RET_OK == nDialogResult ) 977 { 978 for ( cit i = vData.begin(); i < vData.end(); i++ ) 979 { 980 if ( m_pDialogHelper && ( i->sWebsiteURL.getLength() > 0 ) ) 981 m_pDialogHelper->openWebBrowser( i->sWebsiteURL, m_pDialogHelper->getWindow()->GetText() ); 982 } 983 } 984 } 985 else 986 pUpdateDialog->notifyMenubar( false, false ); // check if there updates to be notified via menu bar icon 987 988 delete pUpdateDialog; 989 } 990 991 //------------------------------------------------------------------------------ 992 void ExtensionCmdQueue::Thread::_enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 993 const uno::Reference< deployment::XPackage > &xPackage ) 994 { 995 if ( !xPackage.is() ) 996 return; 997 998 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); 999 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); 1000 OUString sTitle = searchAndReplaceAll( m_sEnablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); 1001 rCmdEnv->progressSection( sTitle, xAbortChannel ); 1002 1003 try 1004 { 1005 xExtMgr->enableExtension( xPackage, xAbortChannel, rCmdEnv.get() ); 1006 if ( m_pDialogHelper ) 1007 m_pDialogHelper->updatePackageInfo( xPackage ); 1008 } 1009 catch ( ::ucb::CommandAbortedException & ) 1010 {} 1011 } 1012 1013 //------------------------------------------------------------------------------ 1014 void ExtensionCmdQueue::Thread::_disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 1015 const uno::Reference< deployment::XPackage > &xPackage ) 1016 { 1017 if ( !xPackage.is() ) 1018 return; 1019 1020 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); 1021 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); 1022 OUString sTitle = searchAndReplaceAll( m_sDisablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); 1023 rCmdEnv->progressSection( sTitle, xAbortChannel ); 1024 1025 try 1026 { 1027 xExtMgr->disableExtension( xPackage, xAbortChannel, rCmdEnv.get() ); 1028 if ( m_pDialogHelper ) 1029 m_pDialogHelper->updatePackageInfo( xPackage ); 1030 } 1031 catch ( ::ucb::CommandAbortedException & ) 1032 {} 1033 } 1034 1035 //------------------------------------------------------------------------------ 1036 void ExtensionCmdQueue::Thread::_acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv, 1037 const uno::Reference< deployment::XPackage > &xPackage ) 1038 { 1039 if ( !xPackage.is() ) 1040 return; 1041 1042 uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager(); 1043 uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() ); 1044 OUString sTitle = searchAndReplaceAll( m_sAcceptLicense, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() ); 1045 rCmdEnv->progressSection( sTitle, xAbortChannel ); 1046 1047 try 1048 { 1049 xExtMgr->checkPrerequisitesAndEnable( xPackage, xAbortChannel, rCmdEnv.get() ); 1050 if ( m_pDialogHelper ) 1051 m_pDialogHelper->updatePackageInfo( xPackage ); 1052 } 1053 catch ( ::ucb::CommandAbortedException & ) 1054 {} 1055 } 1056 1057 //------------------------------------------------------------------------------ 1058 void ExtensionCmdQueue::Thread::onTerminated() 1059 { 1060 ::osl::MutexGuard g(m_mutex); 1061 m_bTerminated = true; 1062 } 1063 1064 //------------------------------------------------------------------------------ 1065 OUString ExtensionCmdQueue::Thread::searchAndReplaceAll( const OUString &rSource, 1066 const OUString &rWhat, 1067 const OUString &rWith ) 1068 { 1069 OUString aRet( rSource ); 1070 sal_Int32 nLen = rWhat.getLength(); 1071 1072 if ( !nLen ) 1073 return aRet; 1074 1075 sal_Int32 nIndex = rSource.indexOf( rWhat ); 1076 while ( nIndex != -1 ) 1077 { 1078 aRet = aRet.replaceAt( nIndex, nLen, rWith ); 1079 nIndex = aRet.indexOf( rWhat, nIndex + rWith.getLength() ); 1080 } 1081 return aRet; 1082 } 1083 1084 1085 //------------------------------------------------------------------------------ 1086 //------------------------------------------------------------------------------ 1087 //------------------------------------------------------------------------------ 1088 ExtensionCmdQueue::ExtensionCmdQueue( DialogHelper * pDialogHelper, 1089 TheExtensionManager *pManager, 1090 const uno::Reference< uno::XComponentContext > &rContext ) 1091 : m_thread( new Thread( pDialogHelper, pManager, rContext ) ) 1092 { 1093 m_thread->launch(); 1094 } 1095 1096 ExtensionCmdQueue::~ExtensionCmdQueue() { 1097 stop(); 1098 } 1099 1100 void ExtensionCmdQueue::addExtension( const ::rtl::OUString & extensionURL, 1101 const ::rtl::OUString & repository, 1102 const bool bWarnUser ) 1103 { 1104 m_thread->addExtension( extensionURL, repository, bWarnUser ); 1105 } 1106 1107 void ExtensionCmdQueue::removeExtension( const uno::Reference< deployment::XPackage > &rPackage ) 1108 { 1109 m_thread->removeExtension( rPackage ); 1110 } 1111 1112 void ExtensionCmdQueue::enableExtension( const uno::Reference< deployment::XPackage > &rPackage, 1113 const bool bEnable ) 1114 { 1115 m_thread->enableExtension( rPackage, bEnable ); 1116 } 1117 1118 void ExtensionCmdQueue::checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList ) 1119 { 1120 m_thread->checkForUpdates( vExtensionList ); 1121 } 1122 1123 void ExtensionCmdQueue::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage ) 1124 { 1125 m_thread->acceptLicense( rPackage ); 1126 } 1127 1128 void ExtensionCmdQueue::syncRepositories( const uno::Reference< uno::XComponentContext > &xContext ) 1129 { 1130 dp_misc::syncRepositories( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) ); 1131 } 1132 1133 void ExtensionCmdQueue::stop() 1134 { 1135 m_thread->stop(); 1136 } 1137 1138 bool ExtensionCmdQueue::isBusy() 1139 { 1140 return m_thread->isBusy(); 1141 } 1142 1143 void handleInteractionRequest( const uno::Reference< uno::XComponentContext > & xContext, 1144 const uno::Reference< task::XInteractionRequest > & xRequest ) 1145 { 1146 ::rtl::Reference< ProgressCmdEnv > xCmdEnv( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) ); 1147 xCmdEnv->handle( xRequest ); 1148 } 1149 1150 } //namespace dp_gui 1151 1152