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/SystemShellExecute.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("${$OOO_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 c3s::SystemShellExecute::create( m_xContext ) ); 936 937 try { 938 // Construct install command ?? 939 940 // Store release note for position 3 and 4 941 rtl::OUString aURL(getReleaseNote(m_aUpdateInfo, 3)); 942 storeReleaseNote(1, aURL); 943 944 aURL = getReleaseNote(m_aUpdateInfo, 4); 945 storeReleaseNote(2, aURL); 946 947 if( xShellExecute.is() ) 948 { 949 rtl::OUString aInstallImage(m_aImageName); 950 osl::FileBase::getSystemPathFromFileURL(aInstallImage, aInstallImage); 951 952 rtl::OUString aParameter; 953 sal_Int32 nFlags = c3s::SystemShellExecuteFlags::DEFAULTS; 954 #if ( defined LINUX || defined SOLARIS ) 955 nFlags = 42; 956 aParameter = getBaseInstallation(); 957 if( aParameter.getLength() > 0 ) 958 osl::FileBase::getSystemPathFromFileURL(aParameter, aParameter); 959 960 aParameter += UNISTRING(" &"); 961 #endif 962 963 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get( m_xContext ); 964 rModel->clearLocalFileName(); 965 966 xShellExecute->execute(aInstallImage, aParameter, nFlags); 967 ShutdownThread *pShutdownThread = new ShutdownThread( m_xContext ); 968 (void) pShutdownThread; 969 } 970 } catch(uno::Exception&) { 971 m_aUpdateHandler->setErrorMessage( m_aUpdateHandler->getDefaultInstErrMsg() ); 972 } 973 } 974 975 //------------------------------------------------------------------------------ 976 977 void 978 UpdateCheck::pause() 979 { 980 osl::ClearableMutexGuard aGuard(m_aMutex); 981 982 if( NULL != m_pThread ) 983 m_pThread->suspend(); 984 985 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); 986 aGuard.clear(); 987 988 rModel->storeDownloadPaused(true); 989 setUIState(UPDATESTATE_DOWNLOAD_PAUSED); 990 } 991 992 //------------------------------------------------------------------------------ 993 994 void 995 UpdateCheck::resume() 996 { 997 osl::ClearableMutexGuard aGuard(m_aMutex); 998 999 if( NULL != m_pThread ) 1000 m_pThread->resume(); 1001 1002 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); 1003 aGuard.clear(); 1004 1005 rModel->storeDownloadPaused(false); 1006 setUIState(UPDATESTATE_DOWNLOADING); 1007 } 1008 1009 //------------------------------------------------------------------------------ 1010 1011 void 1012 UpdateCheck::closeAfterFailure() 1013 { 1014 osl::ClearableMutexGuard aGuard(m_aMutex); 1015 1016 if ( ( m_eState == DISABLED ) || ( m_eState == CHECK_SCHEDULED ) ) 1017 { 1018 const UpdateState eUIState = getUIState( m_aUpdateInfo ); 1019 aGuard.clear(); 1020 setUIState( eUIState, true ); 1021 } 1022 } 1023 1024 //------------------------------------------------------------------------------ 1025 1026 void 1027 UpdateCheck::shutdownThread(bool join) 1028 { 1029 osl::ClearableMutexGuard aGuard(m_aMutex); 1030 1031 // copy thread object pointer to stack 1032 osl::Thread *pThread = m_pThread; 1033 m_pThread = NULL; 1034 aGuard.clear(); 1035 1036 if( NULL != pThread ) 1037 { 1038 pThread->terminate(); 1039 if( join ) 1040 { 1041 m_aCondition.set(); 1042 pThread->join(); 1043 m_aCondition.reset(); 1044 } 1045 } 1046 } 1047 1048 //------------------------------------------------------------------------------ 1049 1050 void 1051 UpdateCheck::enableAutoCheck(bool enable) 1052 { 1053 if( enable ) 1054 m_pThread = new UpdateCheckThread(m_aCondition, m_xContext); 1055 1056 m_eState = enable ? CHECK_SCHEDULED : DISABLED; 1057 } 1058 1059 //------------------------------------------------------------------------------ 1060 1061 void 1062 UpdateCheck::enableDownload(bool enable, bool paused) 1063 { 1064 OSL_ASSERT(NULL == m_pThread); 1065 1066 State eState = DISABLED; 1067 if( enable ) 1068 { 1069 m_pThread = new DownloadThread(m_aCondition, m_xContext, this, m_aUpdateInfo.Sources[0].URL ); 1070 if( !paused ) 1071 { 1072 eState = DOWNLOADING; 1073 m_pThread->resume(); 1074 } 1075 else 1076 eState = DOWNLOAD_PAUSED; 1077 1078 m_eState = eState; 1079 } 1080 else { 1081 enableAutoCheck(UpdateCheckConfig::get(m_xContext)->isAutoCheckEnabled()); 1082 } 1083 1084 } 1085 1086 //------------------------------------------------------------------------------ 1087 1088 bool 1089 UpdateCheck::downloadTargetExists(const rtl::OUString& rFileName) 1090 { 1091 osl::ClearableMutexGuard aGuard(m_aMutex); 1092 1093 rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler()); 1094 UpdateState eUIState = UPDATESTATE_DOWNLOADING; 1095 1096 bool cont = false; 1097 1098 if( aUpdateHandler->isVisible() ) 1099 { 1100 cont = aUpdateHandler->showOverwriteWarning(); 1101 if( cont ) 1102 { 1103 if( osl_File_E_None != osl_removeFile(rFileName.pData) ) 1104 { 1105 // FIXME: error message 1106 cont = false; 1107 } 1108 } 1109 else 1110 eUIState = getUIState(m_aUpdateInfo); 1111 } 1112 else 1113 { 1114 m_aImageName = getImageFromFileName(rFileName); 1115 eUIState = UPDATESTATE_DOWNLOAD_AVAIL; 1116 } 1117 1118 if( !cont ) 1119 { 1120 shutdownThread(false); 1121 enableDownload(false); 1122 1123 aGuard.clear(); 1124 setUIState(eUIState); 1125 } 1126 1127 return cont; 1128 } 1129 1130 //------------------------------------------------------------------------------ 1131 bool UpdateCheck::checkDownloadDestination( const rtl::OUString& rFileName ) 1132 { 1133 osl::ClearableMutexGuard aGuard(m_aMutex); 1134 1135 rtl::Reference< UpdateHandler > aUpdateHandler( getUpdateHandler() ); 1136 1137 bool bReload = false; 1138 1139 if( aUpdateHandler->isVisible() ) 1140 { 1141 bReload = aUpdateHandler->showOverwriteWarning( rFileName ); 1142 } 1143 1144 return bReload; 1145 } 1146 1147 //------------------------------------------------------------------------------ 1148 1149 void 1150 UpdateCheck::downloadStalled(const rtl::OUString& rErrorMessage) 1151 { 1152 osl::ClearableMutexGuard aGuard(m_aMutex); 1153 rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler()); 1154 aGuard.clear(); 1155 1156 aUpdateHandler->setErrorMessage(rErrorMessage); 1157 setUIState(UPDATESTATE_ERROR_DOWNLOADING); 1158 } 1159 1160 //------------------------------------------------------------------------------ 1161 1162 void 1163 UpdateCheck::downloadProgressAt(sal_Int8 nPercent) 1164 { 1165 osl::ClearableMutexGuard aGuard(m_aMutex); 1166 rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler()); 1167 aGuard.clear(); 1168 1169 aUpdateHandler->setProgress(nPercent); 1170 setUIState(UPDATESTATE_DOWNLOADING); 1171 } 1172 1173 //------------------------------------------------------------------------------ 1174 1175 void 1176 UpdateCheck::downloadStarted(const rtl::OUString& rLocalFileName, sal_Int64 nFileSize) 1177 { 1178 if ( nFileSize > 0 ) 1179 { 1180 osl::MutexGuard aGuard(m_aMutex); 1181 1182 rtl::Reference< UpdateCheckConfig > aModel(UpdateCheckConfig::get(m_xContext)); 1183 aModel->storeLocalFileName(rLocalFileName, nFileSize); 1184 1185 // Bring-up release note for position 1 .. 1186 const rtl::OUString aURL(getReleaseNote(m_aUpdateInfo, 1, aModel->isAutoDownloadEnabled())); 1187 if( aURL.getLength() > 0 ) 1188 showReleaseNote(aURL); 1189 } 1190 } 1191 1192 //------------------------------------------------------------------------------ 1193 1194 void 1195 UpdateCheck::downloadFinished(const rtl::OUString& rLocalFileName) 1196 { 1197 osl::ClearableMutexGuard aGuard(m_aMutex); 1198 1199 // no more retries 1200 m_pThread->terminate(); 1201 1202 m_aImageName = getImageFromFileName(rLocalFileName); 1203 UpdateInfo aUpdateInfo(m_aUpdateInfo); 1204 1205 aGuard.clear(); 1206 setUIState(UPDATESTATE_DOWNLOAD_AVAIL); 1207 1208 // Bring-up release note for position 2 .. 1209 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get( m_xContext ); 1210 const rtl::OUString aURL(getReleaseNote(aUpdateInfo, 2, rModel->isAutoDownloadEnabled())); 1211 if( aURL.getLength() > 0 ) 1212 showReleaseNote(aURL); 1213 } 1214 1215 //------------------------------------------------------------------------------ 1216 1217 void 1218 UpdateCheck::cancelDownload() 1219 { 1220 shutdownThread(true); 1221 1222 osl::MutexGuard aGuard(m_aMutex); 1223 enableDownload(false); 1224 1225 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); 1226 1227 rtl::OUString aLocalFile(rModel->getLocalFileName()); 1228 rModel->clearLocalFileName(); 1229 rModel->storeDownloadPaused(false); 1230 1231 if( isObsoleteUpdateInfo(rModel->getUpdateEntryVersion()) ) 1232 { 1233 rModel->clearUpdateFound(); // This wasn't done during init yet .. 1234 m_aUpdateInfo = UpdateInfo(); 1235 } 1236 1237 /*oslFileError rc =*/ osl_removeFile(aLocalFile.pData); 1238 // FIXME: error handling .. 1239 1240 } 1241 1242 //------------------------------------------------------------------------------ 1243 1244 void 1245 UpdateCheck::showDialog(bool forceCheck) 1246 { 1247 osl::ResettableMutexGuard aGuard(m_aMutex); 1248 1249 bool update_found = m_aUpdateInfo.BuildId.getLength() > 0; 1250 bool bSetUIState = ! m_aUpdateHandler.is(); 1251 1252 UpdateState eDialogState = UPDATESTATES_COUNT; 1253 1254 switch( m_eState ) 1255 { 1256 case DISABLED: 1257 case CHECK_SCHEDULED: 1258 if( forceCheck || ! update_found ) // Run check when forced or if we did not find an update yet 1259 { 1260 eDialogState = UPDATESTATE_CHECKING; 1261 bSetUIState = true; 1262 } 1263 else if(m_aUpdateInfo.Sources[0].IsDirect) 1264 eDialogState = UPDATESTATE_UPDATE_AVAIL; 1265 else 1266 eDialogState = UPDATESTATE_UPDATE_NO_DOWNLOAD; 1267 break; 1268 1269 case DOWNLOADING: 1270 eDialogState = UPDATESTATE_DOWNLOADING; 1271 break; 1272 1273 case DOWNLOAD_PAUSED: 1274 eDialogState = UPDATESTATE_DOWNLOAD_PAUSED; 1275 break; 1276 1277 case NOT_INITIALIZED: 1278 OSL_ASSERT( false ); 1279 break; 1280 } 1281 1282 if( bSetUIState ) 1283 { 1284 aGuard.clear(); 1285 setUIState(eDialogState, true); // suppress bubble as Dialog will be visible soon 1286 aGuard.reset(); 1287 } 1288 1289 getUpdateHandler()->setVisible(true); 1290 1291 // Run check in separate thread .. 1292 if( UPDATESTATE_CHECKING == eDialogState ) 1293 { 1294 if( DISABLED == m_eState ) 1295 { 1296 // destructs itself when done, not cancellable for now .. 1297 new ManualUpdateCheckThread(m_aCondition, m_xContext); 1298 } 1299 1300 m_aCondition.set(); 1301 } 1302 } 1303 1304 //------------------------------------------------------------------------------ 1305 1306 void 1307 UpdateCheck::setUpdateInfo(const UpdateInfo& aInfo) 1308 { 1309 osl::ClearableMutexGuard aGuard(m_aMutex); 1310 1311 bool bSuppressBubble = (sal_True == aInfo.BuildId.equals(m_aUpdateInfo.BuildId)); 1312 m_aUpdateInfo = aInfo; 1313 1314 OSL_ASSERT(DISABLED == m_eState || CHECK_SCHEDULED == m_eState); 1315 1316 // Ignore leading non direct download if we get direct ones 1317 std::vector< DownloadSource >::iterator iter = m_aUpdateInfo.Sources.begin(); 1318 while( iter != m_aUpdateInfo.Sources.end() ) 1319 { 1320 if( iter->IsDirect ) 1321 break; 1322 1323 ++iter; 1324 } 1325 1326 if( (iter != m_aUpdateInfo.Sources.begin()) && 1327 (iter != m_aUpdateInfo.Sources.end()) && 1328 iter->IsDirect ) 1329 { 1330 m_aUpdateInfo.Sources.erase(m_aUpdateInfo.Sources.begin(), --iter); 1331 } 1332 1333 rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext, *this); 1334 OSL_ASSERT( rModel.is() ); 1335 1336 // Decide whether to use alternate release note pos .. 1337 bool autoDownloadEnabled = rModel->isAutoDownloadEnabled(); 1338 1339 std::vector< ReleaseNote >::iterator iter2 = m_aUpdateInfo.ReleaseNotes.begin(); 1340 while( iter2 != m_aUpdateInfo.ReleaseNotes.end() ) 1341 { 1342 if( ((1 == iter2->Pos) || (2 == iter2->Pos)) && autoDownloadEnabled && (iter2->URL2.getLength() > 0)) 1343 { 1344 iter2->URL = iter2->URL2; 1345 iter2->URL2 = rtl::OUString(); 1346 iter2->Pos = iter2->Pos2; 1347 iter2->Pos2 = 0; 1348 } 1349 1350 ++iter2; 1351 } 1352 1353 // do not move below store/clear .. 1354 rModel->updateLastChecked(); 1355 1356 UpdateState eUIState; 1357 if( m_aUpdateInfo.Sources.size() > 0 ) 1358 { 1359 rModel->storeUpdateFound(aInfo, getBuildId()); 1360 1361 if( m_aUpdateInfo.Sources[0].IsDirect ) 1362 { 1363 eUIState = UPDATESTATE_UPDATE_AVAIL; 1364 1365 if( rModel->isAutoDownloadEnabled() ) 1366 { 1367 shutdownThread(false); 1368 eUIState = UPDATESTATE_DOWNLOADING; 1369 enableDownload(true); 1370 } 1371 } 1372 else 1373 eUIState = UPDATESTATE_UPDATE_NO_DOWNLOAD; 1374 } 1375 else 1376 { 1377 eUIState = UPDATESTATE_NO_UPDATE_AVAIL; 1378 rModel->clearUpdateFound(); 1379 } 1380 1381 aGuard.clear(); 1382 setUIState(eUIState, bSuppressBubble); 1383 } 1384 1385 //------------------------------------------------------------------------------ 1386 1387 void 1388 UpdateCheck::setCheckFailedState() 1389 { 1390 setUIState(UPDATESTATE_ERROR_CHECKING); 1391 } 1392 1393 //------------------------------------------------------------------------------ 1394 void UpdateCheck::handleMenuBarUI( rtl::Reference< UpdateHandler > rUpdateHandler, 1395 UpdateState& eState, 1396 bool suppressBubble ) 1397 { 1398 uno::Reference<beans::XPropertySet> xMenuBarUI( m_xMenuBarUI ); 1399 1400 if ( ( UPDATESTATE_NO_UPDATE_AVAIL == eState ) && m_bHasExtensionUpdate ) 1401 eState = UPDATESTATE_EXT_UPD_AVAIL; 1402 1403 if ( UPDATESTATE_EXT_UPD_AVAIL == eState ) 1404 m_bShowExtUpdDlg = true; 1405 else 1406 m_bShowExtUpdDlg = false; 1407 1408 if( xMenuBarUI.is() ) 1409 { 1410 if( UPDATESTATE_NO_UPDATE_AVAIL == eState ) 1411 { 1412 xMenuBarUI->setPropertyValue( PROPERTY_SHOW_MENUICON, uno::makeAny(sal_False) ); 1413 } 1414 else 1415 { 1416 xMenuBarUI->setPropertyValue( PROPERTY_TITLE, uno::makeAny(rUpdateHandler->getBubbleTitle(eState)) ); 1417 xMenuBarUI->setPropertyValue( PROPERTY_TEXT, uno::makeAny(rUpdateHandler->getBubbleText(eState)) ); 1418 1419 if( ! suppressBubble && ( ! rUpdateHandler->isVisible() || rUpdateHandler->isMinimized() ) ) 1420 xMenuBarUI->setPropertyValue( PROPERTY_SHOW_BUBBLE, uno::makeAny( sal_True ) ); 1421 1422 if( UPDATESTATE_CHECKING != eState ) 1423 xMenuBarUI->setPropertyValue( PROPERTY_SHOW_MENUICON, uno::makeAny(sal_True) ); 1424 } 1425 } 1426 } 1427 1428 //------------------------------------------------------------------------------ 1429 void UpdateCheck::setUIState(UpdateState eState, bool suppressBubble) 1430 { 1431 osl::ClearableMutexGuard aGuard(m_aMutex); 1432 1433 if( ! m_xMenuBarUI.is() && 1434 (DISABLED != m_eState) && 1435 ( m_bHasExtensionUpdate || (UPDATESTATE_NO_UPDATE_AVAIL != eState)) && 1436 (UPDATESTATE_CHECKING != eState) && 1437 (UPDATESTATE_ERROR_CHECKING != eState) 1438 ) 1439 { 1440 m_xMenuBarUI = createMenuBarUI(m_xContext, new MenuBarButtonJob(this)); 1441 } 1442 1443 // Show bubble only when the status has changed 1444 if ( eState == m_eUpdateState ) 1445 suppressBubble = true; 1446 else 1447 m_eUpdateState = eState; 1448 1449 rtl::Reference<UpdateHandler> aUpdateHandler(getUpdateHandler()); 1450 OSL_ASSERT( aUpdateHandler.is() ); 1451 1452 UpdateInfo aUpdateInfo(m_aUpdateInfo); 1453 rtl::OUString aImageName(m_aImageName); 1454 1455 aGuard.clear(); 1456 1457 handleMenuBarUI( aUpdateHandler, eState, suppressBubble ); 1458 1459 if( (UPDATESTATE_UPDATE_AVAIL == eState) 1460 || (UPDATESTATE_DOWNLOAD_PAUSED == eState) 1461 || (UPDATESTATE_DOWNLOADING == eState) ) 1462 { 1463 uno::Reference< uno::XComponentContext > xContext(m_xContext); 1464 1465 rtl::OUString aDownloadDestination = 1466 UpdateCheckConfig::get(xContext, this)->getDownloadDestination(); 1467 1468 osl_getSystemPathFromFileURL(aDownloadDestination.pData, &aDownloadDestination.pData); 1469 1470 aUpdateHandler->setDownloadPath(aDownloadDestination); 1471 } 1472 else if( UPDATESTATE_DOWNLOAD_AVAIL == eState ) 1473 { 1474 aUpdateHandler->setDownloadFile(aImageName); 1475 } 1476 1477 aUpdateHandler->setDescription(aUpdateInfo.Description); 1478 aUpdateHandler->setNextVersion(aUpdateInfo.Version); 1479 aUpdateHandler->setState(eState); 1480 } 1481 1482 //------------------------------------------------------------------------------ 1483 1484 UpdateState 1485 UpdateCheck::getUIState(const UpdateInfo& rInfo) 1486 { 1487 UpdateState eUIState = UPDATESTATE_NO_UPDATE_AVAIL; 1488 1489 if( rInfo.BuildId.getLength() > 0 ) 1490 { 1491 if( rInfo.Sources[0].IsDirect ) 1492 eUIState = UPDATESTATE_UPDATE_AVAIL; 1493 else 1494 eUIState = UPDATESTATE_UPDATE_NO_DOWNLOAD; 1495 } 1496 1497 return eUIState; 1498 } 1499 1500 //------------------------------------------------------------------------------ 1501 1502 void 1503 UpdateCheck::showReleaseNote(const rtl::OUString& rURL) const 1504 { 1505 const uno::Reference< c3s::XSystemShellExecute > xShellExecute( 1506 createService( UNISTRING( "com.sun.star.system.SystemShellExecute" ), m_xContext ), 1507 uno::UNO_QUERY ); 1508 1509 try { 1510 1511 if( xShellExecute.is() ) 1512 xShellExecute->execute(rURL, rtl::OUString(), c3s::SystemShellExecuteFlags::DEFAULTS); 1513 } catch(c3s::SystemShellExecuteException&) { 1514 } 1515 } 1516 1517 //------------------------------------------------------------------------------ 1518 1519 bool 1520 UpdateCheck::storeReleaseNote(sal_Int8 nNum, const rtl::OUString &rURL) 1521 { 1522 osl::FileBase::RC rc; 1523 rtl::OUString aTargetDir( UpdateCheckConfig::getAllUsersDirectory() + UNISTRING( "/sun" ) ); 1524 1525 rc = osl::Directory::createPath( aTargetDir ); 1526 1527 rtl::OUString aFileName = UNISTRING("releasenote") + 1528 rtl::OUString::valueOf( (sal_Int32) nNum ) + 1529 UNISTRING(".url"); 1530 1531 rtl::OUString aFilePath; 1532 rc = osl::FileBase::getAbsoluteFileURL( aTargetDir, aFileName, aFilePath ); 1533 if ( rc != osl::FileBase::E_None ) return false; 1534 1535 rc = osl::File::remove( aFilePath ); 1536 1537 // don't store empty release notes, but delete old ones 1538 if ( rURL.getLength() == 0 ) 1539 return true; 1540 1541 osl::File aFile( aFilePath ); 1542 rc = aFile.open( OpenFlag_Write | OpenFlag_Create ); 1543 1544 if ( rc != osl::FileBase::E_None ) return false; 1545 1546 rtl::OString aLineBuf("[InternetShortcut]\r\n"); 1547 sal_uInt64 nWritten = 0; 1548 1549 rtl::OUString aURL( rURL ); 1550 #ifdef WNT 1551 rc = aFile.write( aLineBuf.getStr(), aLineBuf.getLength(), nWritten ); 1552 if ( rc != osl::FileBase::E_None ) return false; 1553 aURL = UNISTRING("URL=") + rURL; 1554 #endif 1555 aLineBuf = rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ); 1556 rc = aFile.write( aLineBuf.getStr(), aLineBuf.getLength(), nWritten ); 1557 if ( rc != osl::FileBase::E_None ) return false; 1558 1559 aFile.close(); 1560 return true; 1561 } 1562 1563 //------------------------------------------------------------------------------ 1564 void UpdateCheck::showExtensionDialog() 1565 { 1566 rtl::OUString sServiceName = UNISTRING("com.sun.star.deployment.ui.PackageManagerDialog"); 1567 rtl::OUString sArguments = UNISTRING("SHOW_UPDATE_DIALOG"); 1568 uno::Reference< uno::XInterface > xService; 1569 1570 if( ! m_xContext.is() ) 1571 throw uno::RuntimeException( 1572 UNISTRING( "UpdateCheck::showExtensionDialog(): empty component context" ), uno::Reference< uno::XInterface > () ); 1573 1574 uno::Reference< lang::XMultiComponentFactory > xServiceManager( m_xContext->getServiceManager() ); 1575 if( !xServiceManager.is() ) 1576 throw uno::RuntimeException( 1577 UNISTRING( "UpdateCheck::showExtensionDialog(): unable to obtain service manager from component context" ), uno::Reference< uno::XInterface > () ); 1578 1579 xService = xServiceManager->createInstanceWithContext( sServiceName, m_xContext ); 1580 uno::Reference< task::XJobExecutor > xExecuteable( xService, uno::UNO_QUERY ); 1581 if ( xExecuteable.is() ) 1582 xExecuteable->trigger( sArguments ); 1583 } 1584 1585 //------------------------------------------------------------------------------ 1586 1587 rtl::Reference<UpdateHandler> 1588 UpdateCheck::getUpdateHandler() 1589 { 1590 osl::MutexGuard aGuard(m_aMutex); 1591 1592 if( ! m_aUpdateHandler.is() ) 1593 m_aUpdateHandler = new UpdateHandler(m_xContext, this); 1594 1595 return m_aUpdateHandler; 1596 } 1597 1598 //------------------------------------------------------------------------------ 1599 1600 uno::Reference< task::XInteractionHandler > 1601 UpdateCheck::getInteractionHandler() const 1602 { 1603 osl::MutexGuard aGuard(m_aMutex); 1604 1605 uno::Reference< task::XInteractionHandler > xHandler; 1606 1607 if( m_aUpdateHandler.is() && m_aUpdateHandler->isVisible() ) 1608 xHandler = m_aUpdateHandler.get(); 1609 1610 return xHandler; 1611 } 1612 1613 //------------------------------------------------------------------------------ 1614 1615 uno::Reference< uno::XInterface > 1616 UpdateCheck::createService(const rtl::OUString& rServiceName, 1617 const uno::Reference<uno::XComponentContext>& xContext) 1618 { 1619 if( !xContext.is() ) 1620 throw uno::RuntimeException( 1621 UNISTRING( "UpdateCheckConfig: empty component context" ), 1622 uno::Reference< uno::XInterface >() ); 1623 1624 const uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager()); 1625 1626 if( !xServiceManager.is() ) 1627 throw uno::RuntimeException( 1628 UNISTRING( "UpdateCheckConfig: unable to obtain service manager from component context" ), 1629 uno::Reference< uno::XInterface >() ); 1630 1631 return xServiceManager->createInstanceWithContext(rServiceName, xContext); 1632 } 1633 1634 //------------------------------------------------------------------------------ 1635 1636 bool 1637 UpdateCheck::isDialogShowing() const 1638 { 1639 osl::MutexGuard aGuard(m_aMutex); 1640 return sal_True == m_aUpdateHandler.is() && m_aUpdateHandler->isVisible(); 1641 }; 1642 1643 //------------------------------------------------------------------------------ 1644 1645 void 1646 UpdateCheck::autoCheckStatusChanged(bool enabled) 1647 { 1648 osl::ClearableMutexGuard aGuard(m_aMutex); 1649 1650 if( (CHECK_SCHEDULED == m_eState) && !enabled ) 1651 shutdownThread(false); 1652 1653 if( (DISABLED == m_eState) || (CHECK_SCHEDULED == m_eState) ) 1654 { 1655 enableAutoCheck(enabled); 1656 UpdateState eState = getUIState(m_aUpdateInfo); 1657 aGuard.clear(); 1658 setUIState(eState); 1659 } 1660 }; 1661 1662 //------------------------------------------------------------------------------ 1663 1664 void 1665 UpdateCheck::autoCheckIntervalChanged() 1666 { 1667 // just wake-up 1668 m_aCondition.set(); 1669 }; 1670 1671 //------------------------------------------------------------------------------ 1672 1673 oslInterlockedCount SAL_CALL 1674 UpdateCheck::acquire() SAL_THROW(()) 1675 { 1676 return ReferenceObject::acquire(); 1677 } 1678 1679 //------------------------------------------------------------------------------ 1680 1681 oslInterlockedCount SAL_CALL 1682 UpdateCheck::release() SAL_THROW(()) 1683 { 1684 return ReferenceObject::release(); 1685 } 1686