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