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