1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_extensions.hxx" 30 31 #include "updatecheck.hxx" 32 33 #include <cppuhelper/implbase1.hxx> 34 #include <com/sun/star/beans/XFastPropertySet.hpp> 35 #include <com/sun/star/lang/XComponent.hpp> 36 #include <com/sun/star/frame/XDesktop.hpp> 37 #include <com/sun/star/frame/XFrame.hpp> 38 #include <com/sun/star/frame/DispatchResultEvent.hpp> 39 #include <com/sun/star/frame/DispatchResultState.hpp> 40 #include <com/sun/star/system/XSystemShellExecute.hpp> 41 #include <com/sun/star/system/SystemShellExecuteFlags.hpp> 42 #include <com/sun/star/task/XJob.hpp> 43 #include <com/sun/star/task/XJobExecutor.hpp> 44 45 // #include <comphelper/processfactory.hxx> 46 47 #include <rtl/ustrbuf.hxx> 48 49 #include <rtl/bootstrap.hxx> 50 #include <osl/process.h> 51 #include <osl/module.hxx> 52 #include <osl/file.hxx> 53 54 #ifdef WNT 55 #ifdef _MSC_VER 56 #pragma warning(push,1) // disable warnings within system headers 57 //#pragma warning(disable: 4917) 58 #endif 59 #include <objbase.h> 60 #ifdef _MSC_VER 61 #pragma warning(pop) 62 #endif 63 #endif 64 65 #include "updateprotocol.hxx" 66 #include "updatecheckconfig.hxx" 67 68 namespace awt = com::sun::star::awt ; 69 namespace beans = com::sun::star::beans ; 70 namespace container = com::sun::star::container ; 71 namespace deployment = com::sun::star::deployment ; 72 namespace frame = com::sun::star::frame ; 73 namespace lang = com::sun::star::lang ; 74 namespace c3s = com::sun::star::system ; 75 namespace task = com::sun::star::task ; 76 namespace util = com::sun::star::util ; 77 namespace uno = com::sun::star::uno ; 78 79 #define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) 80 81 #define PROPERTY_TITLE UNISTRING("BubbleHeading") 82 #define PROPERTY_TEXT UNISTRING("BubbleText") 83 #define PROPERTY_IMAGE UNISTRING("BubbleImageURL") 84 #define PROPERTY_SHOW_BUBBLE UNISTRING("BubbleVisible") 85 #define PROPERTY_CLICK_HDL UNISTRING("MenuClickHDL") 86 #define PROPERTY_DEFAULT_TITLE UNISTRING("DefaultHeading") 87 #define PROPERTY_DEFAULT_TEXT UNISTRING("DefaultText") 88 #define PROPERTY_SHOW_MENUICON UNISTRING("MenuIconVisible") 89 90 //------------------------------------------------------------------------------ 91 92 // Returns the URL of the release note for the given position 93 rtl::OUString getReleaseNote(const UpdateInfo& rInfo, sal_uInt8 pos, bool autoDownloadEnabled) 94 { 95 std::vector< ReleaseNote >::const_iterator iter = rInfo.ReleaseNotes.begin(); 96 while( iter != rInfo.ReleaseNotes.end() ) 97 { 98 if( pos == iter->Pos ) 99 { 100 if( (pos > 2) || !autoDownloadEnabled || ! (iter->URL2.getLength() > 0) ) 101 return iter->URL; 102 } 103 else if( (pos == iter->Pos2) && ((1 == iter->Pos) || (2 == iter->Pos)) && autoDownloadEnabled ) 104 return iter->URL2; 105 106 ++iter; 107 } 108 109 return rtl::OUString(); 110 } 111 112 //------------------------------------------------------------------------------ 113 114 namespace 115 { 116 117 static inline rtl::OUString getBuildId() 118 { 119 rtl::OUString aPathVal(UNISTRING("${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":buildid}")); 120 rtl::Bootstrap::expandMacros(aPathVal); 121 return aPathVal; 122 } 123 124 //------------------------------------------------------------------------------ 125 static inline rtl::OUString getBaseInstallation() 126 { 127 rtl::OUString aPathVal(UNISTRING("${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap") ":BaseInstallation}")); 128 rtl::Bootstrap::expandMacros(aPathVal); 129 return aPathVal; 130 } 131 132 //------------------------------------------------------------------------------ 133 134 inline bool isObsoleteUpdateInfo(const rtl::OUString& rBuildId) 135 { 136 return sal_True != rBuildId.equals(getBuildId()) && rBuildId.getLength() > 0; 137 } 138 139 140 //------------------------------------------------------------------------------ 141 142 rtl::OUString getImageFromFileName(const rtl::OUString& aFile) 143 { 144 #ifndef WNT 145 rtl::OUString aUnpackPath; 146 if( osl_getExecutableFile(&aUnpackPath.pData) == osl_Process_E_None ) 147 { 148 sal_uInt32 lastIndex = aUnpackPath.lastIndexOf('/'); 149 if ( lastIndex > 0 ) 150 { 151 aUnpackPath = aUnpackPath.copy( 0, lastIndex+1 ); 152 aUnpackPath += UNISTRING( "unpack_update" ); 153 } 154 155 oslFileHandle hOut = NULL; 156 oslProcess hProcess = NULL; 157 158 rtl::OUString aSystemPath; 159 osl::File::getSystemPathFromFileURL(aFile, aSystemPath); 160 161 oslProcessError rc = osl_executeProcess_WithRedirectedIO( 162 aUnpackPath.pData, // [in] Image name 163 &aSystemPath.pData, 1, // [in] Arguments 164 osl_Process_WAIT || osl_Process_NORMAL, // [in] Options 165 NULL, // [in] Security 166 NULL, // [in] Working directory 167 NULL, 0, // [in] Environment variables 168 &hProcess, // [out] Process handle 169 NULL, &hOut, NULL // [out] File handles for redirected I/O 170 ); 171 172 if( osl_Process_E_None == rc ) 173 { 174 oslProcessInfo aInfo; 175 aInfo.Size = sizeof(oslProcessInfo); 176 177 if( osl_Process_E_None == osl_getProcessInfo(hProcess, osl_Process_EXITCODE, &aInfo) ) 178 { 179 if( 0 == aInfo.Code ) 180 { 181 sal_Char szBuffer[4096]; 182 sal_uInt64 nBytesRead = 0; 183 const sal_uInt64 nBytesToRead = sizeof(szBuffer) - 1; 184 185 rtl::OUString aImageName; 186 while( osl_File_E_None == osl_readFile(hOut, szBuffer, nBytesToRead, &nBytesRead) ) 187 { 188 sal_Char *pc = szBuffer + nBytesRead; 189 do 190 { 191 *pc = '\0'; --pc; 192 } 193 while( ('\n' == *pc) || ('\r' == *pc) ); 194 195 aImageName += rtl::OUString(szBuffer, pc - szBuffer + 1, osl_getThreadTextEncoding()); 196 197 if( nBytesRead < nBytesToRead ) 198 break; 199 } 200 201 if( osl::FileBase::E_None == osl::FileBase::getFileURLFromSystemPath(aImageName, aImageName) ) 202 return aImageName; 203 } 204 } 205 206 osl_closeFile(hOut); 207 osl_freeProcessHandle(hProcess); 208 } 209 } 210 #endif 211 212 return aFile; 213 } 214 215 216 //------------------------------------------------------------------------------ 217 218 static uno::Reference< beans::XPropertySet > createMenuBarUI( 219 const uno::Reference< uno::XComponentContext >& xContext, 220 const uno::Reference< task::XJob >& xJob) 221 { 222 if( !xContext.is() ) 223 throw uno::RuntimeException( 224 UNISTRING( "UpdateCheckJob: empty component context" ), uno::Reference< uno::XInterface > () ); 225 226 uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager()); 227 if( !xServiceManager.is() ) 228 throw uno::RuntimeException( 229 UNISTRING( "UpdateCheckJob: unable to obtain service manager from component context" ), uno::Reference< uno::XInterface > () ); 230 231 uno::Reference< beans::XPropertySet > xMenuBarUI = 232 uno::Reference< beans::XPropertySet > ( 233 xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.setup.UpdateCheckUI" ), xContext ), 234 uno::UNO_QUERY_THROW); 235 236 xMenuBarUI->setPropertyValue( PROPERTY_CLICK_HDL, uno::makeAny( xJob ) ); 237 238 return xMenuBarUI; 239 } 240 241 //------------------------------------------------------------------------------ 242 243 244 245 typedef sal_Bool (* OnlineCheckFunc) (); 246 247 class UpdateCheckThread : public WorkerThread 248 { 249 250 public: 251 UpdateCheckThread( osl::Condition& rCondition, 252 const uno::Reference<uno::XComponentContext>& xContext ); 253 254 virtual void SAL_CALL join(); 255 virtual void SAL_CALL terminate(); 256 virtual void SAL_CALL cancel(); 257 258 protected: 259 virtual ~UpdateCheckThread(); 260 261 virtual void SAL_CALL run(); 262 virtual void SAL_CALL onTerminated(); 263 264 /* Wrapper around checkForUpdates */ 265 bool runCheck( bool & rbExtensionsChecked ); 266 267 private: 268 269 /* Used to avoid dialup login windows (on platforms we know how to double this) */ 270 inline bool hasInternetConnection() const 271 { 272 if(m_pHasInternetConnection != NULL ) 273 return (sal_True == m_pHasInternetConnection()); 274 return true; 275 } 276 277 /* Creates a new instance of UpdateInformationProvider and returns this instance */ 278 inline uno::Reference<deployment::XUpdateInformationProvider> createProvider() 279 { 280 osl::MutexGuard aGuard(m_aMutex); 281 m_xProvider = deployment::UpdateInformationProvider::create(m_xContext); 282 return m_xProvider; 283 }; 284 285 /* Returns the remembered instance of UpdateInformationProvider if any */ 286 inline uno::Reference<deployment::XUpdateInformationProvider> getProvider() 287 { osl::MutexGuard aGuard(m_aMutex); return m_xProvider; }; 288 289 /* Releases the remembered instance of UpdateInformationProvider if any */ 290 inline void clearProvider() 291 { osl::MutexGuard aGuard(m_aMutex); m_xProvider.clear(); }; 292 293 osl::Mutex m_aMutex; 294 osl::Module m_aModule; 295 296 protected: 297 osl::Condition& m_aCondition; 298 299 private: 300 301 // const 302 OnlineCheckFunc m_pHasInternetConnection; 303 304 const uno::Reference<uno::XComponentContext> m_xContext; 305 uno::Reference<deployment::XUpdateInformationProvider> m_xProvider; 306 }; 307 308 309 class ManualUpdateCheckThread : public UpdateCheckThread 310 { 311 public: 312 ManualUpdateCheckThread( osl::Condition& rCondition, const uno::Reference<uno::XComponentContext>& xContext ) : 313 UpdateCheckThread(rCondition, xContext) {}; 314 315 virtual void SAL_CALL run(); 316 }; 317 318 319 class MenuBarButtonJob : public ::cppu::WeakImplHelper1< task::XJob > 320 { 321 public: 322 MenuBarButtonJob(const rtl::Reference< UpdateCheck >& rUpdateCheck); 323 324 // XJob 325 virtual uno::Any SAL_CALL execute(const uno::Sequence<beans::NamedValue>&) 326 throw (lang::IllegalArgumentException, uno::Exception); 327 328 private: 329 rtl::Reference< UpdateCheck > m_aUpdateCheck; 330 }; 331 332 class DownloadThread : public WorkerThread 333 { 334 public: 335 DownloadThread( 336 osl::Condition& rCondition, 337 const uno::Reference<uno::XComponentContext>& xContext, 338 const rtl::Reference< DownloadInteractionHandler >& rHandler, 339 const rtl::OUString& rURL ); 340 341 virtual void SAL_CALL run(); 342 virtual void SAL_CALL cancel(); 343 virtual void SAL_CALL suspend(); 344 virtual void SAL_CALL onTerminated(); 345 346 protected: 347 ~DownloadThread(); 348 349 private: 350 osl::Condition& m_aCondition; 351 const uno::Reference<uno::XComponentContext> m_xContext; 352 const rtl::OUString m_aURL; 353 Download m_aDownload; 354 }; 355 356 //------------------------------------------------------------------------------ 357 class ShutdownThread : public osl::Thread 358 { 359 public: 360 ShutdownThread( const uno::Reference<uno::XComponentContext>& xContext ); 361 362 virtual void SAL_CALL run(); 363 virtual void SAL_CALL onTerminated(); 364 365 protected: 366 ~ShutdownThread(); 367 368 private: 369 osl::Condition m_aCondition; 370 const uno::Reference<uno::XComponentContext> m_xContext; 371 }; 372 373 //------------------------------------------------------------------------------ 374 375 UpdateCheckThread::UpdateCheckThread( osl::Condition& rCondition, 376 const uno::Reference<uno::XComponentContext>& xContext ) : 377 m_aCondition(rCondition), 378 m_pHasInternetConnection(NULL), 379 m_xContext(xContext) 380 { 381 382 #ifdef WNT 383 rtl::OUString aPath; 384 if( osl_getExecutableFile(&aPath.pData) == osl_Process_E_None ) 385 { 386 sal_uInt32 lastIndex = aPath.lastIndexOf('/'); 387 if ( lastIndex > 0 ) 388 { 389 aPath = aPath.copy( 0, lastIndex+1 ); 390 aPath += UNISTRING( "onlinecheck" ); 391 } 392 393 if ( m_aModule.load(aPath) ) 394 { 395 m_pHasInternetConnection = 396 reinterpret_cast < OnlineCheckFunc > ( 397 m_aModule.getFunctionSymbol( UNISTRING("hasInternetConnection"))); 398 } 399 } 400 #endif 401 402 createSuspended(); 403 404 // actually run the thread 405 resume(); 406 } 407 408 //------------------------------------------------------------------------------ 409 410 UpdateCheckThread::~UpdateCheckThread() 411 { 412 } 413 414 //------------------------------------------------------------------------------ 415 416 417 void SAL_CALL 418 UpdateCheckThread::terminate() 419 { 420 // Cancel potentially hanging http request .. 421 cancel(); 422 // .. before terminating 423 osl::Thread::terminate(); 424 } 425 426 //------------------------------------------------------------------------------ 427 428 void SAL_CALL 429 UpdateCheckThread::join() 430 { 431 uno::Reference< deployment::XUpdateInformationProvider > xProvider(getProvider()); 432 433 // do not join during an update check until #i73893# is fixed 434 if( ! xProvider.is() ) 435 { 436 osl::Thread::join(); 437 } 438 } 439 440 //------------------------------------------------------------------------------ 441 442 void SAL_CALL 443 UpdateCheckThread::cancel() 444 { 445 uno::Reference< deployment::XUpdateInformationProvider > xProvider(getProvider()); 446 447 if( xProvider.is() ) 448 xProvider->cancel(); 449 } 450 451 //------------------------------------------------------------------------------ 452 453 bool 454 UpdateCheckThread::runCheck( bool & rbExtensionsChecked ) 455 { 456 bool ret = false; 457 UpdateState eUIState = UPDATESTATE_NO_UPDATE_AVAIL; 458 459 UpdateInfo aInfo; 460 rtl::Reference< UpdateCheck > aController(UpdateCheck::get()); 461 462 if( checkForUpdates(aInfo, m_xContext, aController->getInteractionHandler(), createProvider()) ) 463 { 464 aController->setUpdateInfo(aInfo); 465 eUIState = aController->getUIState(aInfo); 466 ret = true; 467 } 468 else 469 aController->setCheckFailedState(); 470 471 // We will only look for extension updates, when there is no 'check for office updates' dialog open 472 // and when there was no office update found 473 if ( ( eUIState != UPDATESTATE_UPDATE_AVAIL ) && 474 ( eUIState != UPDATESTATE_UPDATE_NO_DOWNLOAD ) && 475 !aController->isDialogShowing() && 476 !rbExtensionsChecked ) 477 { 478 bool bHasExtensionUpdates = checkForExtensionUpdates( m_xContext ); 479 aController->setHasExtensionUpdates( bHasExtensionUpdates ); 480 if ( bHasExtensionUpdates ) 481 aController->setUIState( UPDATESTATE_EXT_UPD_AVAIL ); 482 rbExtensionsChecked = true; 483 } 484 485 // joining with this thread is safe again 486 clearProvider(); 487 return ret; 488 } 489 490 //------------------------------------------------------------------------------ 491 492 void SAL_CALL 493 UpdateCheckThread::onTerminated() 494 { 495 delete this; 496 } 497 498 //------------------------------------------------------------------------------ 499 500 void SAL_CALL 501 UpdateCheckThread::run() 502 { 503 bool bExtensionsChecked = false; 504 TimeValue systime; 505 TimeValue nExtCheckTime; 506 osl_getSystemTime( &nExtCheckTime ); 507 508 osl::Condition::Result aResult = osl::Condition::result_timeout; 509 TimeValue tv = { 10, 0 }; 510 511 // Initial wait to avoid doing further time consuming tasks during start-up 512 aResult = m_aCondition.wait(&tv); 513 514 try { 515 516 while( sal_True == schedule() ) 517 { 518 /* Use cases: 519 * a) manual check requested from auto check thread - "last check" should not be checked (one time) 520 * a1) manual check was requested in the middle of a running auto check, 521 * condition is set 522 * a2) manual check was requested while waiting for a retry, 523 * condition is set 524 * a3) manual check was requested while waiting for time to next 525 * scheduled check elapsing, condition is set 526 * a4) manual check was requested during initial wait, condition is set 527 * b) check interval got changed, condition may be set - same sub-cases as a), 528 * but "last check" should be honored 529 * c) normal auto check mode, condition not set - "last check" should be honored 530 */ 531 532 // Accessing const members without synchronization 533 rtl::Reference< UpdateCheck > aController(UpdateCheck::get()); 534 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext, *aController); 535 536 // FIXME: remember last & offset ? 537 sal_Int64 last = rModel->getLastChecked(); 538 sal_Int64 offset = rModel->getCheckInterval(); 539 540 rModel.clear(); 541 542 // last == 0 means check immediately 543 bool checkNow = ! (last > 0); 544 545 // Reset the condition to avoid busy loops 546 if( osl::Condition::result_ok == aResult ) 547 { 548 m_aCondition.reset(); 549 aResult = osl::Condition::result_timeout; 550 checkNow = aController->isDialogShowing(); 551 } 552 553 if( ! checkNow ) 554 { 555 osl_getSystemTime(&systime); 556 557 // Go back to sleep until time has elapsed 558 sal_Int64 next = last + offset; 559 if( last + offset > systime.Seconds ) 560 { 561 // This can not be > 32 Bit for now .. 562 tv.Seconds = static_cast< sal_Int32 > (next - systime.Seconds); 563 aResult = m_aCondition.wait(&tv); 564 continue; 565 } 566 } 567 568 static sal_uInt8 n = 0; 569 570 if( ! hasInternetConnection() || ! runCheck( bExtensionsChecked ) ) 571 { 572 // the extension update check should be independent from the office update check 573 // 574 osl_getSystemTime( &systime ); 575 if ( nExtCheckTime.Seconds + offset < systime.Seconds ) 576 bExtensionsChecked = false; 577 578 // Increase next by 15, 60, .. minutes 579 static const sal_Int32 nRetryInterval[] = { 900, 3600, 14400, 86400 }; 580 581 if( n < sizeof(nRetryInterval) / sizeof(sal_Int32) ) 582 ++n; 583 584 tv.Seconds = nRetryInterval[n-1]; 585 aResult = m_aCondition.wait(&tv); 586 } 587 else // reset retry counter 588 { 589 n = 0; 590 bExtensionsChecked = false; 591 } 592 } 593 } 594 595 catch(const uno::Exception& e) { 596 // Silently catch all errors 597 OSL_TRACE( "Caught exception: %s\n thread terminated.\n", 598 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr() ); 599 } 600 } 601 602 //------------------------------------------------------------------------------ 603 604 void SAL_CALL 605 ManualUpdateCheckThread::run() 606 { 607 bool bExtensionsChecked = false; 608 609 try { 610 runCheck( bExtensionsChecked ); 611 m_aCondition.reset(); 612 } 613 catch(const uno::Exception& e) { 614 // Silently catch all errors 615 OSL_TRACE( "Caught exception: %s\n thread terminated.\n", 616 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr() ); 617 } 618 } 619 620 //------------------------------------------------------------------------------ 621 622 MenuBarButtonJob::MenuBarButtonJob(const rtl::Reference< UpdateCheck >& rUpdateCheck) : 623 m_aUpdateCheck(rUpdateCheck) 624 { 625 }; 626 627 //------------------------------------------------------------------------------ 628 629 uno::Any SAL_CALL 630 MenuBarButtonJob::execute(const uno::Sequence<beans::NamedValue>& ) 631 throw (lang::IllegalArgumentException, uno::Exception) 632 { 633 if ( m_aUpdateCheck->shouldShowExtUpdDlg() ) 634 m_aUpdateCheck->showExtensionDialog(); 635 else 636 m_aUpdateCheck->showDialog(); 637 638 return uno::Any(); 639 } 640 641 //------------------------------------------------------------------------------ 642 643 DownloadThread::DownloadThread(osl::Condition& rCondition, 644 const uno::Reference<uno::XComponentContext>& xContext, 645 const rtl::Reference< DownloadInteractionHandler >& rHandler, 646 const rtl::OUString& rURL) : 647 m_aCondition(rCondition), 648 m_xContext(xContext), 649 m_aURL(rURL), 650 m_aDownload(xContext, rHandler) 651 { 652 createSuspended(); 653 } 654 655 //------------------------------------------------------------------------------ 656 657 DownloadThread::~DownloadThread() 658 { 659 } 660 661 //------------------------------------------------------------------------------ 662 663 void SAL_CALL 664 DownloadThread::run() 665 { 666 #ifdef WNT 667 CoUninitialize(); 668 CoInitialize( NULL ); 669 #endif 670 671 while( schedule() ) 672 { 673 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); 674 675 rtl::OUString aLocalFile = rModel->getLocalFileName(); 676 rtl::OUString aDownloadDest = rModel->getDownloadDestination(); 677 678 // release config class for now 679 rModel.clear(); 680 681 static sal_uInt8 n = 0; 682 if( ! m_aDownload.start(m_aURL, aLocalFile, aDownloadDest ) ) 683 { 684 // retry every 15s unless the dialog is not visible 685 TimeValue tv; 686 tv.Seconds = 15; 687 688 if( ! UpdateCheck::get()->isDialogShowing() ) 689 { 690 // Increase next by 1, 5, 15, 60, .. minutes 691 static const sal_Int16 nRetryInterval[] = { 60, 300, 900, 3600 }; 692 693 if( n < sizeof(nRetryInterval) / sizeof(sal_Int16) ) 694 ++n; 695 696 tv.Seconds = nRetryInterval[n-1]; 697 } 698 m_aCondition.wait(&tv); 699 } 700 else 701 { 702 // reset wait period after successful download 703 n=0; 704 } 705 } 706 } 707 708 //------------------------------------------------------------------------------ 709 710 void SAL_CALL DownloadThread::cancel() 711 { 712 m_aDownload.stop(); 713 resume(); 714 715 rtl::Reference< UpdateCheck > aController(UpdateCheck::get()); 716 aController->cancelDownload(); 717 } 718 719 //------------------------------------------------------------------------------ 720 721 void SAL_CALL DownloadThread::suspend() 722 { 723 osl::Thread::suspend(); 724 m_aDownload.stop(); 725 } 726 727 //------------------------------------------------------------------------------ 728 729 void SAL_CALL DownloadThread::onTerminated() 730 { 731 delete this; 732 } 733 734 //------------------------------------------------------------------------------ 735 ShutdownThread::ShutdownThread( const uno::Reference<uno::XComponentContext>& xContext) : 736 m_xContext( xContext ) 737 { 738 create(); 739 } 740 741 //------------------------------------------------------------------------------ 742 ShutdownThread::~ShutdownThread() 743 { 744 } 745 746 //------------------------------------------------------------------------------ 747 void SAL_CALL 748 ShutdownThread::run() 749 { 750 TimeValue tv = { 0, 250 }; 751 752 m_aCondition.wait(&tv); 753 754 // Tell QuickStarter not to veto .. 755 uno::Reference< beans::XFastPropertySet > xQuickStarter( 756 UpdateCheck::createService(UNISTRING("com.sun.star.office.Quickstart"), m_xContext), 757 uno::UNO_QUERY 758 ); 759 760 if (xQuickStarter.is()) 761 xQuickStarter->setFastPropertyValue(0, uno::makeAny(false)); 762 763 // Shutdown the office 764 uno::Reference< frame::XDesktop > xDesktop( 765 UpdateCheck::createService(UNISTRING("com.sun.star.frame.Desktop"), m_xContext), 766 uno::UNO_QUERY); 767 768 if( xDesktop.is() ) 769 xDesktop->terminate(); 770 } 771 772 //------------------------------------------------------------------------------ 773 void SAL_CALL ShutdownThread::onTerminated() 774 { 775 delete this; 776 } 777 778 //------------------------------------------------------------------------------ 779 780 } // anonymous namespace 781 782 783 //------------------------------------------------------------------------------ 784 785 786 void 787 UpdateCheck::initialize(const uno::Sequence< beans::NamedValue >& rValues, 788 const uno::Reference<uno::XComponentContext>& xContext) 789 { 790 osl::MutexGuard aGuard(m_aMutex); 791 792 if( NOT_INITIALIZED == m_eState ) 793 { 794 NamedValueByNameAccess aNameAccess(rValues); 795 UpdateCheckROModel aModel( aNameAccess ); 796 m_xContext = xContext; 797 798 rtl::OUString aUpdateEntryVersion = aModel.getUpdateEntryVersion(); 799 800 aModel.getUpdateEntry(m_aUpdateInfo); 801 802 bool obsoleteUpdateInfo = isObsoleteUpdateInfo(aUpdateEntryVersion); 803 bool bContinueDownload = false; 804 bool bDownloadAvailable = false; 805 806 m_bHasExtensionUpdate = checkForPendingUpdates( xContext ); 807 m_bShowExtUpdDlg = false; 808 809 rtl::OUString aLocalFileName = aModel.getLocalFileName(); 810 811 if( aLocalFileName.getLength() > 0 ) 812 { 813 bContinueDownload = true; 814 815 // Try to get the number of bytes already on disk 816 osl::DirectoryItem aDirectoryItem; 817 if( osl::DirectoryItem::E_None == osl::DirectoryItem::get(aLocalFileName, aDirectoryItem) ) 818 { 819 osl::FileStatus aFileStatus(FileStatusMask_FileSize); 820 if( osl::DirectoryItem::E_None == aDirectoryItem.getFileStatus(aFileStatus) ) 821 { 822 sal_Int64 nDownloadSize = aModel.getDownloadSize(); 823 sal_Int64 nFileSize = aFileStatus.getFileSize(); 824 825 if( nDownloadSize > 0 ) 826 { 827 if ( nDownloadSize <= nFileSize ) // we have already downloaded everthing 828 { 829 bContinueDownload = false; 830 bDownloadAvailable = true; 831 m_aImageName = getImageFromFileName( aLocalFileName ); 832 } 833 else // Calculate initial percent value. 834 { 835 sal_Int32 nPercent = (sal_Int32) (100 * nFileSize / nDownloadSize); 836 getUpdateHandler()->setProgress( nPercent ); 837 } 838 } 839 } 840 } 841 842 if ( bContinueDownload ) 843 { 844 bool downloadPaused = aModel.isDownloadPaused(); 845 846 enableDownload(true, downloadPaused); 847 setUIState(downloadPaused ? UPDATESTATE_DOWNLOAD_PAUSED : UPDATESTATE_DOWNLOADING); 848 } 849 850 } 851 if ( !bContinueDownload ) 852 { 853 // We do this intentionally only if no download is in progress .. 854 if( obsoleteUpdateInfo ) 855 { 856 // Bring-up release note for position 5 .. 857 const rtl::OUString aURL(getReleaseNote(m_aUpdateInfo, 5)); 858 if( aURL.getLength() > 0 ) 859 showReleaseNote(aURL); 860 861 // Data is outdated, probably due to installed update 862 rtl::Reference< UpdateCheckConfig > aConfig = UpdateCheckConfig::get( xContext, *this ); 863 aConfig->clearUpdateFound(); 864 aConfig->clearLocalFileName(); 865 866 867 m_aUpdateInfo = UpdateInfo(); 868 // Remove outdated release notes 869 storeReleaseNote( 1, rtl::OUString() ); 870 storeReleaseNote( 2, rtl::OUString() ); 871 } 872 else 873 { 874 enableAutoCheck(aModel.isAutoCheckEnabled()); 875 if ( bDownloadAvailable ) 876 setUIState( UPDATESTATE_DOWNLOAD_AVAIL ); 877 else 878 setUIState(getUIState(m_aUpdateInfo)); 879 } 880 } 881 } 882 } 883 884 //------------------------------------------------------------------------------ 885 886 void 887 UpdateCheck::cancel() 888 { 889 osl::ClearableMutexGuard aGuard(m_aMutex); 890 891 WorkerThread *pThread = m_pThread; 892 UpdateState eUIState = getUIState(m_aUpdateInfo); 893 894 aGuard.clear(); 895 896 if( NULL != pThread ) 897 pThread->cancel(); 898 899 setUIState(eUIState); 900 } 901 902 //------------------------------------------------------------------------------ 903 904 void 905 UpdateCheck::download() 906 { 907 osl::ClearableMutexGuard aGuard(m_aMutex); 908 UpdateInfo aInfo(m_aUpdateInfo); 909 State eState = m_eState; 910 aGuard.clear(); 911 912 if( aInfo.Sources[0].IsDirect ) 913 { 914 // Ignore second click of a double click 915 if( DOWNLOADING != eState ) 916 { 917 shutdownThread(true); 918 919 osl::ClearableMutexGuard aGuard2(m_aMutex); 920 enableDownload(true); 921 aGuard2.clear(); 922 setUIState(UPDATESTATE_DOWNLOADING); 923 } 924 } 925 else 926 { 927 showReleaseNote(aInfo.Sources[0].URL); // Display in browser 928 } 929 } 930 931 //------------------------------------------------------------------------------ 932 933 void 934 UpdateCheck::install() 935 { 936 osl::MutexGuard aGuard(m_aMutex); 937 938 const uno::Reference< c3s::XSystemShellExecute > xShellExecute( 939 createService( UNISTRING( "com.sun.star.system.SystemShellExecute" ), m_xContext ), 940 uno::UNO_QUERY ); 941 942 try { 943 // Construct install command ?? 944 945 // Store release note for position 3 and 4 946 rtl::OUString aURL(getReleaseNote(m_aUpdateInfo, 3)); 947 storeReleaseNote(1, aURL); 948 949 aURL = getReleaseNote(m_aUpdateInfo, 4); 950 storeReleaseNote(2, aURL); 951 952 if( xShellExecute.is() ) 953 { 954 rtl::OUString aInstallImage(m_aImageName); 955 osl::FileBase::getSystemPathFromFileURL(aInstallImage, aInstallImage); 956 957 rtl::OUString aParameter; 958 sal_Int32 nFlags = c3s::SystemShellExecuteFlags::DEFAULTS; 959 #if ( defined LINUX || defined SOLARIS ) 960 nFlags = 42; 961 aParameter = getBaseInstallation(); 962 if( aParameter.getLength() > 0 ) 963 osl::FileBase::getSystemPathFromFileURL(aParameter, aParameter); 964 965 aParameter += UNISTRING(" &"); 966 #endif 967 968 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get( m_xContext ); 969 rModel->clearLocalFileName(); 970 971 xShellExecute->execute(aInstallImage, aParameter, nFlags); 972 ShutdownThread *pShutdownThread = new ShutdownThread( m_xContext ); 973 (void) pShutdownThread; 974 } 975 } catch(uno::Exception&) { 976 m_aUpdateHandler->setErrorMessage( m_aUpdateHandler->getDefaultInstErrMsg() ); 977 } 978 } 979 980 //------------------------------------------------------------------------------ 981 982 void 983 UpdateCheck::pause() 984 { 985 osl::ClearableMutexGuard aGuard(m_aMutex); 986 987 if( NULL != m_pThread ) 988 m_pThread->suspend(); 989 990 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); 991 aGuard.clear(); 992 993 rModel->storeDownloadPaused(true); 994 setUIState(UPDATESTATE_DOWNLOAD_PAUSED); 995 } 996 997 //------------------------------------------------------------------------------ 998 999 void 1000 UpdateCheck::resume() 1001 { 1002 osl::ClearableMutexGuard aGuard(m_aMutex); 1003 1004 if( NULL != m_pThread ) 1005 m_pThread->resume(); 1006 1007 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); 1008 aGuard.clear(); 1009 1010 rModel->storeDownloadPaused(false); 1011 setUIState(UPDATESTATE_DOWNLOADING); 1012 } 1013 1014 //------------------------------------------------------------------------------ 1015 1016 void 1017 UpdateCheck::closeAfterFailure() 1018 { 1019 osl::ClearableMutexGuard aGuard(m_aMutex); 1020 1021 if ( ( m_eState == DISABLED ) || ( m_eState == CHECK_SCHEDULED ) ) 1022 { 1023 const UpdateState eUIState = getUIState( m_aUpdateInfo ); 1024 aGuard.clear(); 1025 setUIState( eUIState, true ); 1026 } 1027 } 1028 1029 //------------------------------------------------------------------------------ 1030 1031 void 1032 UpdateCheck::shutdownThread(bool join) 1033 { 1034 osl::ClearableMutexGuard aGuard(m_aMutex); 1035 1036 // copy thread object pointer to stack 1037 osl::Thread *pThread = m_pThread; 1038 m_pThread = NULL; 1039 aGuard.clear(); 1040 1041 if( NULL != pThread ) 1042 { 1043 pThread->terminate(); 1044 if( join ) 1045 { 1046 m_aCondition.set(); 1047 pThread->join(); 1048 m_aCondition.reset(); 1049 } 1050 } 1051 } 1052 1053 //------------------------------------------------------------------------------ 1054 1055 void 1056 UpdateCheck::enableAutoCheck(bool enable) 1057 { 1058 if( enable ) 1059 m_pThread = new UpdateCheckThread(m_aCondition, m_xContext); 1060 1061 m_eState = enable ? CHECK_SCHEDULED : DISABLED; 1062 } 1063 1064 //------------------------------------------------------------------------------ 1065 1066 void 1067 UpdateCheck::enableDownload(bool enable, bool paused) 1068 { 1069 OSL_ASSERT(NULL == m_pThread); 1070 1071 State eState = DISABLED; 1072 if( enable ) 1073 { 1074 m_pThread = new DownloadThread(m_aCondition, m_xContext, this, m_aUpdateInfo.Sources[0].URL ); 1075 if( !paused ) 1076 { 1077 eState = DOWNLOADING; 1078 m_pThread->resume(); 1079 } 1080 else 1081 eState = DOWNLOAD_PAUSED; 1082 1083 m_eState = eState; 1084 } 1085 else { 1086 enableAutoCheck(UpdateCheckConfig::get(m_xContext)->isAutoCheckEnabled()); 1087 } 1088 1089 } 1090 1091 //------------------------------------------------------------------------------ 1092 1093 bool 1094 UpdateCheck::downloadTargetExists(const rtl::OUString& rFileName) 1095 { 1096 osl::ClearableMutexGuard aGuard(m_aMutex); 1097 1098 rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler()); 1099 UpdateState eUIState = UPDATESTATE_DOWNLOADING; 1100 1101 bool cont = false; 1102 1103 if( aUpdateHandler->isVisible() ) 1104 { 1105 cont = aUpdateHandler->showOverwriteWarning(); 1106 if( cont ) 1107 { 1108 if( osl_File_E_None != osl_removeFile(rFileName.pData) ) 1109 { 1110 // FIXME: error message 1111 cont = false; 1112 } 1113 } 1114 else 1115 eUIState = getUIState(m_aUpdateInfo); 1116 } 1117 else 1118 { 1119 m_aImageName = getImageFromFileName(rFileName); 1120 eUIState = UPDATESTATE_DOWNLOAD_AVAIL; 1121 } 1122 1123 if( !cont ) 1124 { 1125 shutdownThread(false); 1126 enableDownload(false); 1127 1128 aGuard.clear(); 1129 setUIState(eUIState); 1130 } 1131 1132 return cont; 1133 } 1134 1135 //------------------------------------------------------------------------------ 1136 bool UpdateCheck::checkDownloadDestination( const rtl::OUString& rFileName ) 1137 { 1138 osl::ClearableMutexGuard aGuard(m_aMutex); 1139 1140 rtl::Reference< UpdateHandler > aUpdateHandler( getUpdateHandler() ); 1141 1142 bool bReload = false; 1143 1144 if( aUpdateHandler->isVisible() ) 1145 { 1146 bReload = aUpdateHandler->showOverwriteWarning( rFileName ); 1147 } 1148 1149 return bReload; 1150 } 1151 1152 //------------------------------------------------------------------------------ 1153 1154 void 1155 UpdateCheck::downloadStalled(const rtl::OUString& rErrorMessage) 1156 { 1157 osl::ClearableMutexGuard aGuard(m_aMutex); 1158 rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler()); 1159 aGuard.clear(); 1160 1161 aUpdateHandler->setErrorMessage(rErrorMessage); 1162 setUIState(UPDATESTATE_ERROR_DOWNLOADING); 1163 } 1164 1165 //------------------------------------------------------------------------------ 1166 1167 void 1168 UpdateCheck::downloadProgressAt(sal_Int8 nPercent) 1169 { 1170 osl::ClearableMutexGuard aGuard(m_aMutex); 1171 rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler()); 1172 aGuard.clear(); 1173 1174 aUpdateHandler->setProgress(nPercent); 1175 setUIState(UPDATESTATE_DOWNLOADING); 1176 } 1177 1178 //------------------------------------------------------------------------------ 1179 1180 void 1181 UpdateCheck::downloadStarted(const rtl::OUString& rLocalFileName, sal_Int64 nFileSize) 1182 { 1183 if ( nFileSize > 0 ) 1184 { 1185 osl::MutexGuard aGuard(m_aMutex); 1186 1187 rtl::Reference< UpdateCheckConfig > aModel(UpdateCheckConfig::get(m_xContext)); 1188 aModel->storeLocalFileName(rLocalFileName, nFileSize); 1189 1190 // Bring-up release note for position 1 .. 1191 const rtl::OUString aURL(getReleaseNote(m_aUpdateInfo, 1, aModel->isAutoDownloadEnabled())); 1192 if( aURL.getLength() > 0 ) 1193 showReleaseNote(aURL); 1194 } 1195 } 1196 1197 //------------------------------------------------------------------------------ 1198 1199 void 1200 UpdateCheck::downloadFinished(const rtl::OUString& rLocalFileName) 1201 { 1202 osl::ClearableMutexGuard aGuard(m_aMutex); 1203 1204 // no more retries 1205 m_pThread->terminate(); 1206 1207 m_aImageName = getImageFromFileName(rLocalFileName); 1208 UpdateInfo aUpdateInfo(m_aUpdateInfo); 1209 1210 aGuard.clear(); 1211 setUIState(UPDATESTATE_DOWNLOAD_AVAIL); 1212 1213 // Bring-up release note for position 2 .. 1214 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get( m_xContext ); 1215 const rtl::OUString aURL(getReleaseNote(aUpdateInfo, 2, rModel->isAutoDownloadEnabled())); 1216 if( aURL.getLength() > 0 ) 1217 showReleaseNote(aURL); 1218 } 1219 1220 //------------------------------------------------------------------------------ 1221 1222 void 1223 UpdateCheck::cancelDownload() 1224 { 1225 shutdownThread(true); 1226 1227 osl::MutexGuard aGuard(m_aMutex); 1228 enableDownload(false); 1229 1230 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); 1231 1232 rtl::OUString aLocalFile(rModel->getLocalFileName()); 1233 rModel->clearLocalFileName(); 1234 rModel->storeDownloadPaused(false); 1235 1236 if( isObsoleteUpdateInfo(rModel->getUpdateEntryVersion()) ) 1237 { 1238 rModel->clearUpdateFound(); // This wasn't done during init yet .. 1239 m_aUpdateInfo = UpdateInfo(); 1240 } 1241 1242 /*oslFileError rc =*/ osl_removeFile(aLocalFile.pData); 1243 // FIXME: error handling .. 1244 1245 } 1246 1247 //------------------------------------------------------------------------------ 1248 1249 void 1250 UpdateCheck::showDialog(bool forceCheck) 1251 { 1252 osl::ResettableMutexGuard aGuard(m_aMutex); 1253 1254 bool update_found = m_aUpdateInfo.BuildId.getLength() > 0; 1255 bool bSetUIState = ! m_aUpdateHandler.is(); 1256 1257 UpdateState eDialogState = UPDATESTATES_COUNT; 1258 1259 switch( m_eState ) 1260 { 1261 case DISABLED: 1262 case CHECK_SCHEDULED: 1263 if( forceCheck || ! update_found ) // Run check when forced or if we did not find an update yet 1264 { 1265 eDialogState = UPDATESTATE_CHECKING; 1266 bSetUIState = true; 1267 } 1268 else if(m_aUpdateInfo.Sources[0].IsDirect) 1269 eDialogState = UPDATESTATE_UPDATE_AVAIL; 1270 else 1271 eDialogState = UPDATESTATE_UPDATE_NO_DOWNLOAD; 1272 break; 1273 1274 case DOWNLOADING: 1275 eDialogState = UPDATESTATE_DOWNLOADING; 1276 break; 1277 1278 case DOWNLOAD_PAUSED: 1279 eDialogState = UPDATESTATE_DOWNLOAD_PAUSED; 1280 break; 1281 1282 case NOT_INITIALIZED: 1283 OSL_ASSERT( false ); 1284 break; 1285 } 1286 1287 if( bSetUIState ) 1288 { 1289 aGuard.clear(); 1290 setUIState(eDialogState, true); // suppress bubble as Dialog will be visible soon 1291 aGuard.reset(); 1292 } 1293 1294 getUpdateHandler()->setVisible(true); 1295 1296 // Run check in separate thread .. 1297 if( UPDATESTATE_CHECKING == eDialogState ) 1298 { 1299 if( DISABLED == m_eState ) 1300 { 1301 // destructs itself when done, not cancellable for now .. 1302 new ManualUpdateCheckThread(m_aCondition, m_xContext); 1303 } 1304 1305 m_aCondition.set(); 1306 } 1307 } 1308 1309 //------------------------------------------------------------------------------ 1310 1311 void 1312 UpdateCheck::setUpdateInfo(const UpdateInfo& aInfo) 1313 { 1314 osl::ClearableMutexGuard aGuard(m_aMutex); 1315 1316 bool bSuppressBubble = (sal_True == aInfo.BuildId.equals(m_aUpdateInfo.BuildId)); 1317 m_aUpdateInfo = aInfo; 1318 1319 OSL_ASSERT(DISABLED == m_eState || CHECK_SCHEDULED == m_eState); 1320 1321 // Ignore leading non direct download if we get direct ones 1322 std::vector< DownloadSource >::iterator iter = m_aUpdateInfo.Sources.begin(); 1323 while( iter != m_aUpdateInfo.Sources.end() ) 1324 { 1325 if( iter->IsDirect ) 1326 break; 1327 1328 ++iter; 1329 } 1330 1331 if( (iter != m_aUpdateInfo.Sources.begin()) && 1332 (iter != m_aUpdateInfo.Sources.end()) && 1333 iter->IsDirect ) 1334 { 1335 m_aUpdateInfo.Sources.erase(m_aUpdateInfo.Sources.begin(), --iter); 1336 } 1337 1338 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext, *this); 1339 OSL_ASSERT( rModel.is() ); 1340 1341 // Decide whether to use alternate release note pos .. 1342 bool autoDownloadEnabled = rModel->isAutoDownloadEnabled(); 1343 1344 std::vector< ReleaseNote >::iterator iter2 = m_aUpdateInfo.ReleaseNotes.begin(); 1345 while( iter2 != m_aUpdateInfo.ReleaseNotes.end() ) 1346 { 1347 if( ((1 == iter2->Pos) || (2 == iter2->Pos)) && autoDownloadEnabled && (iter2->URL2.getLength() > 0)) 1348 { 1349 iter2->URL = iter2->URL2; 1350 iter2->URL2 = rtl::OUString(); 1351 iter2->Pos = iter2->Pos2; 1352 iter2->Pos2 = 0; 1353 } 1354 1355 ++iter2; 1356 } 1357 1358 // do not move below store/clear .. 1359 rModel->updateLastChecked(); 1360 1361 UpdateState eUIState; 1362 if( m_aUpdateInfo.Sources.size() > 0 ) 1363 { 1364 rModel->storeUpdateFound(aInfo, getBuildId()); 1365 1366 if( m_aUpdateInfo.Sources[0].IsDirect ) 1367 { 1368 eUIState = UPDATESTATE_UPDATE_AVAIL; 1369 1370 if( rModel->isAutoDownloadEnabled() ) 1371 { 1372 shutdownThread(false); 1373 eUIState = UPDATESTATE_DOWNLOADING; 1374 enableDownload(true); 1375 } 1376 } 1377 else 1378 eUIState = UPDATESTATE_UPDATE_NO_DOWNLOAD; 1379 } 1380 else 1381 { 1382 eUIState = UPDATESTATE_NO_UPDATE_AVAIL; 1383 rModel->clearUpdateFound(); 1384 } 1385 1386 aGuard.clear(); 1387 setUIState(eUIState, bSuppressBubble); 1388 } 1389 1390 //------------------------------------------------------------------------------ 1391 1392 void 1393 UpdateCheck::setCheckFailedState() 1394 { 1395 setUIState(UPDATESTATE_ERROR_CHECKING); 1396 } 1397 1398 //------------------------------------------------------------------------------ 1399 void UpdateCheck::handleMenuBarUI( rtl::Reference< UpdateHandler > rUpdateHandler, 1400 UpdateState& eState, 1401 bool suppressBubble ) 1402 { 1403 uno::Reference<beans::XPropertySet> xMenuBarUI( m_xMenuBarUI ); 1404 1405 if ( ( UPDATESTATE_NO_UPDATE_AVAIL == eState ) && m_bHasExtensionUpdate ) 1406 eState = UPDATESTATE_EXT_UPD_AVAIL; 1407 1408 if ( UPDATESTATE_EXT_UPD_AVAIL == eState ) 1409 m_bShowExtUpdDlg = true; 1410 else 1411 m_bShowExtUpdDlg = false; 1412 1413 if( xMenuBarUI.is() ) 1414 { 1415 if( UPDATESTATE_NO_UPDATE_AVAIL == eState ) 1416 { 1417 xMenuBarUI->setPropertyValue( PROPERTY_SHOW_MENUICON, uno::makeAny(sal_False) ); 1418 } 1419 else 1420 { 1421 xMenuBarUI->setPropertyValue( PROPERTY_TITLE, uno::makeAny(rUpdateHandler->getBubbleTitle(eState)) ); 1422 xMenuBarUI->setPropertyValue( PROPERTY_TEXT, uno::makeAny(rUpdateHandler->getBubbleText(eState)) ); 1423 1424 if( ! suppressBubble && ( ! rUpdateHandler->isVisible() || rUpdateHandler->isMinimized() ) ) 1425 xMenuBarUI->setPropertyValue( PROPERTY_SHOW_BUBBLE, uno::makeAny( sal_True ) ); 1426 1427 if( UPDATESTATE_CHECKING != eState ) 1428 xMenuBarUI->setPropertyValue( PROPERTY_SHOW_MENUICON, uno::makeAny(sal_True) ); 1429 } 1430 } 1431 } 1432 1433 //------------------------------------------------------------------------------ 1434 void UpdateCheck::setUIState(UpdateState eState, bool suppressBubble) 1435 { 1436 osl::ClearableMutexGuard aGuard(m_aMutex); 1437 1438 if( ! m_xMenuBarUI.is() && 1439 (DISABLED != m_eState) && 1440 ( m_bHasExtensionUpdate || (UPDATESTATE_NO_UPDATE_AVAIL != eState)) && 1441 (UPDATESTATE_CHECKING != eState) && 1442 (UPDATESTATE_ERROR_CHECKING != eState) 1443 ) 1444 { 1445 m_xMenuBarUI = createMenuBarUI(m_xContext, new MenuBarButtonJob(this)); 1446 } 1447 1448 // Show bubble only when the status has changed 1449 if ( eState == m_eUpdateState ) 1450 suppressBubble = true; 1451 else 1452 m_eUpdateState = eState; 1453 1454 rtl::Reference<UpdateHandler> aUpdateHandler(getUpdateHandler()); 1455 OSL_ASSERT( aUpdateHandler.is() ); 1456 1457 UpdateInfo aUpdateInfo(m_aUpdateInfo); 1458 rtl::OUString aImageName(m_aImageName); 1459 1460 aGuard.clear(); 1461 1462 handleMenuBarUI( aUpdateHandler, eState, suppressBubble ); 1463 1464 if( (UPDATESTATE_UPDATE_AVAIL == eState) 1465 || (UPDATESTATE_DOWNLOAD_PAUSED == eState) 1466 || (UPDATESTATE_DOWNLOADING == eState) ) 1467 { 1468 uno::Reference< uno::XComponentContext > xContext(m_xContext); 1469 1470 rtl::OUString aDownloadDestination = 1471 UpdateCheckConfig::get(xContext, this)->getDownloadDestination(); 1472 1473 osl_getSystemPathFromFileURL(aDownloadDestination.pData, &aDownloadDestination.pData); 1474 1475 aUpdateHandler->setDownloadPath(aDownloadDestination); 1476 } 1477 else if( UPDATESTATE_DOWNLOAD_AVAIL == eState ) 1478 { 1479 aUpdateHandler->setDownloadFile(aImageName); 1480 } 1481 1482 aUpdateHandler->setDescription(aUpdateInfo.Description); 1483 aUpdateHandler->setNextVersion(aUpdateInfo.Version); 1484 aUpdateHandler->setState(eState); 1485 } 1486 1487 //------------------------------------------------------------------------------ 1488 1489 UpdateState 1490 UpdateCheck::getUIState(const UpdateInfo& rInfo) 1491 { 1492 UpdateState eUIState = UPDATESTATE_NO_UPDATE_AVAIL; 1493 1494 if( rInfo.BuildId.getLength() > 0 ) 1495 { 1496 if( rInfo.Sources[0].IsDirect ) 1497 eUIState = UPDATESTATE_UPDATE_AVAIL; 1498 else 1499 eUIState = UPDATESTATE_UPDATE_NO_DOWNLOAD; 1500 } 1501 1502 return eUIState; 1503 } 1504 1505 //------------------------------------------------------------------------------ 1506 1507 void 1508 UpdateCheck::showReleaseNote(const rtl::OUString& rURL) const 1509 { 1510 const uno::Reference< c3s::XSystemShellExecute > xShellExecute( 1511 createService( UNISTRING( "com.sun.star.system.SystemShellExecute" ), m_xContext ), 1512 uno::UNO_QUERY ); 1513 1514 try { 1515 1516 if( xShellExecute.is() ) 1517 xShellExecute->execute(rURL, rtl::OUString(), c3s::SystemShellExecuteFlags::DEFAULTS); 1518 } catch(c3s::SystemShellExecuteException&) { 1519 } 1520 } 1521 1522 //------------------------------------------------------------------------------ 1523 1524 bool 1525 UpdateCheck::storeReleaseNote(sal_Int8 nNum, const rtl::OUString &rURL) 1526 { 1527 osl::FileBase::RC rc; 1528 rtl::OUString aTargetDir( UpdateCheckConfig::getAllUsersDirectory() + UNISTRING( "/sun" ) ); 1529 1530 rc = osl::Directory::createPath( aTargetDir ); 1531 1532 rtl::OUString aFileName = UNISTRING("releasenote") + 1533 rtl::OUString::valueOf( (sal_Int32) nNum ) + 1534 UNISTRING(".url"); 1535 1536 rtl::OUString aFilePath; 1537 rc = osl::FileBase::getAbsoluteFileURL( aTargetDir, aFileName, aFilePath ); 1538 if ( rc != osl::FileBase::E_None ) return false; 1539 1540 rc = osl::File::remove( aFilePath ); 1541 1542 // don't store empty release notes, but delete old ones 1543 if ( rURL.getLength() == 0 ) 1544 return true; 1545 1546 osl::File aFile( aFilePath ); 1547 rc = aFile.open( OpenFlag_Write | OpenFlag_Create ); 1548 1549 if ( rc != osl::FileBase::E_None ) return false; 1550 1551 rtl::OString aLineBuf("[InternetShortcut]\r\n"); 1552 sal_uInt64 nWritten = 0; 1553 1554 rtl::OUString aURL( rURL ); 1555 #ifdef WNT 1556 rc = aFile.write( aLineBuf.getStr(), aLineBuf.getLength(), nWritten ); 1557 if ( rc != osl::FileBase::E_None ) return false; 1558 aURL = UNISTRING("URL=") + rURL; 1559 #endif 1560 aLineBuf = rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ); 1561 rc = aFile.write( aLineBuf.getStr(), aLineBuf.getLength(), nWritten ); 1562 if ( rc != osl::FileBase::E_None ) return false; 1563 1564 aFile.close(); 1565 return true; 1566 } 1567 1568 //------------------------------------------------------------------------------ 1569 void UpdateCheck::showExtensionDialog() 1570 { 1571 rtl::OUString sServiceName = UNISTRING("com.sun.star.deployment.ui.PackageManagerDialog"); 1572 rtl::OUString sArguments = UNISTRING("SHOW_UPDATE_DIALOG"); 1573 uno::Reference< uno::XInterface > xService; 1574 1575 if( ! m_xContext.is() ) 1576 throw uno::RuntimeException( 1577 UNISTRING( "UpdateCheck::showExtensionDialog(): empty component context" ), uno::Reference< uno::XInterface > () ); 1578 1579 uno::Reference< lang::XMultiComponentFactory > xServiceManager( m_xContext->getServiceManager() ); 1580 if( !xServiceManager.is() ) 1581 throw uno::RuntimeException( 1582 UNISTRING( "UpdateCheck::showExtensionDialog(): unable to obtain service manager from component context" ), uno::Reference< uno::XInterface > () ); 1583 1584 xService = xServiceManager->createInstanceWithContext( sServiceName, m_xContext ); 1585 uno::Reference< task::XJobExecutor > xExecuteable( xService, uno::UNO_QUERY ); 1586 if ( xExecuteable.is() ) 1587 xExecuteable->trigger( sArguments ); 1588 } 1589 1590 //------------------------------------------------------------------------------ 1591 1592 rtl::Reference<UpdateHandler> 1593 UpdateCheck::getUpdateHandler() 1594 { 1595 osl::MutexGuard aGuard(m_aMutex); 1596 1597 if( ! m_aUpdateHandler.is() ) 1598 m_aUpdateHandler = new UpdateHandler(m_xContext, this); 1599 1600 return m_aUpdateHandler; 1601 } 1602 1603 //------------------------------------------------------------------------------ 1604 1605 uno::Reference< task::XInteractionHandler > 1606 UpdateCheck::getInteractionHandler() const 1607 { 1608 osl::MutexGuard aGuard(m_aMutex); 1609 1610 uno::Reference< task::XInteractionHandler > xHandler; 1611 1612 if( m_aUpdateHandler.is() && m_aUpdateHandler->isVisible() ) 1613 xHandler = m_aUpdateHandler.get(); 1614 1615 return xHandler; 1616 } 1617 1618 //------------------------------------------------------------------------------ 1619 1620 uno::Reference< uno::XInterface > 1621 UpdateCheck::createService(const rtl::OUString& rServiceName, 1622 const uno::Reference<uno::XComponentContext>& xContext) 1623 { 1624 if( !xContext.is() ) 1625 throw uno::RuntimeException( 1626 UNISTRING( "UpdateCheckConfig: empty component context" ), 1627 uno::Reference< uno::XInterface >() ); 1628 1629 const uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager()); 1630 1631 if( !xServiceManager.is() ) 1632 throw uno::RuntimeException( 1633 UNISTRING( "UpdateCheckConfig: unable to obtain service manager from component context" ), 1634 uno::Reference< uno::XInterface >() ); 1635 1636 return xServiceManager->createInstanceWithContext(rServiceName, xContext); 1637 } 1638 1639 //------------------------------------------------------------------------------ 1640 1641 bool 1642 UpdateCheck::isDialogShowing() const 1643 { 1644 osl::MutexGuard aGuard(m_aMutex); 1645 return sal_True == m_aUpdateHandler.is() && m_aUpdateHandler->isVisible(); 1646 }; 1647 1648 //------------------------------------------------------------------------------ 1649 1650 void 1651 UpdateCheck::autoCheckStatusChanged(bool enabled) 1652 { 1653 osl::ClearableMutexGuard aGuard(m_aMutex); 1654 1655 if( (CHECK_SCHEDULED == m_eState) && !enabled ) 1656 shutdownThread(false); 1657 1658 if( (DISABLED == m_eState) || (CHECK_SCHEDULED == m_eState) ) 1659 { 1660 enableAutoCheck(enabled); 1661 UpdateState eState = getUIState(m_aUpdateInfo); 1662 aGuard.clear(); 1663 setUIState(eState); 1664 } 1665 }; 1666 1667 //------------------------------------------------------------------------------ 1668 1669 void 1670 UpdateCheck::autoCheckIntervalChanged() 1671 { 1672 // just wake-up 1673 m_aCondition.set(); 1674 }; 1675 1676 //------------------------------------------------------------------------------ 1677 1678 oslInterlockedCount SAL_CALL 1679 UpdateCheck::acquire() SAL_THROW(()) 1680 { 1681 return ReferenceObject::acquire(); 1682 } 1683 1684 //------------------------------------------------------------------------------ 1685 1686 oslInterlockedCount SAL_CALL 1687 UpdateCheck::release() SAL_THROW(()) 1688 { 1689 return ReferenceObject::release(); 1690 } 1691