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