| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_extensions.hxx" |
| |
| #include "updatecheck.hxx" |
| |
| #include <cppuhelper/implbase1.hxx> |
| #include <com/sun/star/beans/XFastPropertySet.hpp> |
| #include <com/sun/star/lang/XComponent.hpp> |
| #include <com/sun/star/frame/XDesktop.hpp> |
| #include <com/sun/star/frame/XFrame.hpp> |
| #include <com/sun/star/frame/DispatchResultEvent.hpp> |
| #include <com/sun/star/frame/DispatchResultState.hpp> |
| #include <com/sun/star/system/SystemShellExecute.hpp> |
| #include <com/sun/star/system/SystemShellExecuteFlags.hpp> |
| #include <com/sun/star/task/XJob.hpp> |
| #include <com/sun/star/task/XJobExecutor.hpp> |
| |
| // #include <comphelper/processfactory.hxx> |
| |
| #include <rtl/ustrbuf.hxx> |
| |
| #include <rtl/bootstrap.hxx> |
| #include <osl/process.h> |
| #include <osl/module.hxx> |
| #include <osl/file.hxx> |
| |
| #ifdef WNT |
| #ifdef _MSC_VER |
| #pragma warning(push,1) // disable warnings within system headers |
| //#pragma warning(disable: 4917) |
| #endif |
| #include <objbase.h> |
| #ifdef _MSC_VER |
| #pragma warning(pop) |
| #endif |
| #endif |
| |
| #include "updateprotocol.hxx" |
| #include "updatecheckconfig.hxx" |
| |
| namespace awt = com::sun::star::awt ; |
| namespace beans = com::sun::star::beans ; |
| namespace container = com::sun::star::container ; |
| namespace deployment = com::sun::star::deployment ; |
| namespace frame = com::sun::star::frame ; |
| namespace lang = com::sun::star::lang ; |
| namespace c3s = com::sun::star::system ; |
| namespace task = com::sun::star::task ; |
| namespace util = com::sun::star::util ; |
| namespace uno = com::sun::star::uno ; |
| |
| #define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) |
| |
| #define PROPERTY_TITLE UNISTRING("BubbleHeading") |
| #define PROPERTY_TEXT UNISTRING("BubbleText") |
| #define PROPERTY_IMAGE UNISTRING("BubbleImageURL") |
| #define PROPERTY_SHOW_BUBBLE UNISTRING("BubbleVisible") |
| #define PROPERTY_CLICK_HDL UNISTRING("MenuClickHDL") |
| #define PROPERTY_DEFAULT_TITLE UNISTRING("DefaultHeading") |
| #define PROPERTY_DEFAULT_TEXT UNISTRING("DefaultText") |
| #define PROPERTY_SHOW_MENUICON UNISTRING("MenuIconVisible") |
| |
| //------------------------------------------------------------------------------ |
| |
| // Returns the URL of the release note for the given position |
| rtl::OUString getReleaseNote(const UpdateInfo& rInfo, sal_uInt8 pos, bool autoDownloadEnabled) |
| { |
| std::vector< ReleaseNote >::const_iterator iter = rInfo.ReleaseNotes.begin(); |
| while( iter != rInfo.ReleaseNotes.end() ) |
| { |
| if( pos == iter->Pos ) |
| { |
| if( (pos > 2) || !autoDownloadEnabled || ! (iter->URL2.getLength() > 0) ) |
| return iter->URL; |
| } |
| else if( (pos == iter->Pos2) && ((1 == iter->Pos) || (2 == iter->Pos)) && autoDownloadEnabled ) |
| return iter->URL2; |
| |
| ++iter; |
| } |
| |
| return rtl::OUString(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| namespace |
| { |
| |
| static inline rtl::OUString getBuildId() |
| { |
| rtl::OUString aPathVal(UNISTRING("${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":buildid}")); |
| rtl::Bootstrap::expandMacros(aPathVal); |
| return aPathVal; |
| } |
| |
| //------------------------------------------------------------------------------ |
| static inline rtl::OUString getBaseInstallation() |
| { |
| rtl::OUString aPathVal(UNISTRING("${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap") ":BaseInstallation}")); |
| rtl::Bootstrap::expandMacros(aPathVal); |
| return aPathVal; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| inline bool isObsoleteUpdateInfo(const rtl::OUString& rBuildId) |
| { |
| return sal_True != rBuildId.equals(getBuildId()) && rBuildId.getLength() > 0; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| |
| rtl::OUString getImageFromFileName(const rtl::OUString& aFile) |
| { |
| #ifndef WNT |
| rtl::OUString aUnpackPath; |
| if( osl_getExecutableFile(&aUnpackPath.pData) == osl_Process_E_None ) |
| { |
| sal_uInt32 lastIndex = aUnpackPath.lastIndexOf('/'); |
| if ( lastIndex > 0 ) |
| { |
| aUnpackPath = aUnpackPath.copy( 0, lastIndex+1 ); |
| aUnpackPath += UNISTRING( "unpack_update" ); |
| } |
| |
| oslFileHandle hOut = NULL; |
| oslProcess hProcess = NULL; |
| |
| rtl::OUString aSystemPath; |
| osl::File::getSystemPathFromFileURL(aFile, aSystemPath); |
| |
| oslProcessError rc = osl_executeProcess_WithRedirectedIO( |
| aUnpackPath.pData, // [in] Image name |
| &aSystemPath.pData, 1, // [in] Arguments |
| osl_Process_WAIT || osl_Process_NORMAL, // [in] Options |
| NULL, // [in] Security |
| NULL, // [in] Working directory |
| NULL, 0, // [in] Environment variables |
| &hProcess, // [out] Process handle |
| NULL, &hOut, NULL // [out] File handles for redirected I/O |
| ); |
| |
| if( osl_Process_E_None == rc ) |
| { |
| oslProcessInfo aInfo; |
| aInfo.Size = sizeof(oslProcessInfo); |
| |
| if( osl_Process_E_None == osl_getProcessInfo(hProcess, osl_Process_EXITCODE, &aInfo) ) |
| { |
| if( 0 == aInfo.Code ) |
| { |
| sal_Char szBuffer[4096]; |
| sal_uInt64 nBytesRead = 0; |
| const sal_uInt64 nBytesToRead = sizeof(szBuffer) - 1; |
| |
| rtl::OUString aImageName; |
| while( osl_File_E_None == osl_readFile(hOut, szBuffer, nBytesToRead, &nBytesRead) ) |
| { |
| sal_Char *pc = szBuffer + nBytesRead; |
| do |
| { |
| *pc = '\0'; --pc; |
| } |
| while( ('\n' == *pc) || ('\r' == *pc) ); |
| |
| aImageName += rtl::OUString(szBuffer, pc - szBuffer + 1, osl_getThreadTextEncoding()); |
| |
| if( nBytesRead < nBytesToRead ) |
| break; |
| } |
| |
| if( osl::FileBase::E_None == osl::FileBase::getFileURLFromSystemPath(aImageName, aImageName) ) |
| return aImageName; |
| } |
| } |
| |
| osl_closeFile(hOut); |
| osl_freeProcessHandle(hProcess); |
| } |
| } |
| #endif |
| |
| return aFile; |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| |
| static uno::Reference< beans::XPropertySet > createMenuBarUI( |
| const uno::Reference< uno::XComponentContext >& xContext, |
| const uno::Reference< task::XJob >& xJob) |
| { |
| if( !xContext.is() ) |
| throw uno::RuntimeException( |
| UNISTRING( "UpdateCheckJob: empty component context" ), uno::Reference< uno::XInterface > () ); |
| |
| uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager()); |
| if( !xServiceManager.is() ) |
| throw uno::RuntimeException( |
| UNISTRING( "UpdateCheckJob: unable to obtain service manager from component context" ), uno::Reference< uno::XInterface > () ); |
| |
| uno::Reference< beans::XPropertySet > xMenuBarUI = |
| uno::Reference< beans::XPropertySet > ( |
| xServiceManager->createInstanceWithContext( UNISTRING( "com.sun.star.setup.UpdateCheckUI" ), xContext ), |
| uno::UNO_QUERY_THROW); |
| |
| xMenuBarUI->setPropertyValue( PROPERTY_CLICK_HDL, uno::makeAny( xJob ) ); |
| |
| return xMenuBarUI; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| |
| |
| typedef sal_Bool (* OnlineCheckFunc) (); |
| |
| class UpdateCheckThread : public WorkerThread |
| { |
| |
| public: |
| UpdateCheckThread( osl::Condition& rCondition, |
| const uno::Reference<uno::XComponentContext>& xContext ); |
| |
| virtual void SAL_CALL join(); |
| virtual void SAL_CALL terminate(); |
| virtual void SAL_CALL cancel(); |
| |
| protected: |
| virtual ~UpdateCheckThread(); |
| |
| virtual void SAL_CALL run(); |
| virtual void SAL_CALL onTerminated(); |
| |
| /* Wrapper around checkForUpdates */ |
| bool runCheck( bool & rbExtensionsChecked ); |
| |
| private: |
| |
| /* Used to avoid dialup login windows (on platforms we know how to double this) */ |
| inline bool hasInternetConnection() const |
| { |
| if(m_pHasInternetConnection != NULL ) |
| return (sal_True == m_pHasInternetConnection()); |
| return true; |
| } |
| |
| /* Creates a new instance of UpdateInformationProvider and returns this instance */ |
| inline uno::Reference<deployment::XUpdateInformationProvider> createProvider() |
| { |
| osl::MutexGuard aGuard(m_aMutex); |
| m_xProvider = deployment::UpdateInformationProvider::create(m_xContext); |
| return m_xProvider; |
| }; |
| |
| /* Returns the remembered instance of UpdateInformationProvider if any */ |
| inline uno::Reference<deployment::XUpdateInformationProvider> getProvider() |
| { osl::MutexGuard aGuard(m_aMutex); return m_xProvider; }; |
| |
| /* Releases the remembered instance of UpdateInformationProvider if any */ |
| inline void clearProvider() |
| { osl::MutexGuard aGuard(m_aMutex); m_xProvider.clear(); }; |
| |
| osl::Mutex m_aMutex; |
| osl::Module m_aModule; |
| |
| protected: |
| osl::Condition& m_aCondition; |
| |
| private: |
| |
| // const |
| OnlineCheckFunc m_pHasInternetConnection; |
| |
| const uno::Reference<uno::XComponentContext> m_xContext; |
| uno::Reference<deployment::XUpdateInformationProvider> m_xProvider; |
| }; |
| |
| |
| class ManualUpdateCheckThread : public UpdateCheckThread |
| { |
| public: |
| ManualUpdateCheckThread( osl::Condition& rCondition, const uno::Reference<uno::XComponentContext>& xContext ) : |
| UpdateCheckThread(rCondition, xContext) {}; |
| |
| virtual void SAL_CALL run(); |
| }; |
| |
| |
| class MenuBarButtonJob : public ::cppu::WeakImplHelper1< task::XJob > |
| { |
| public: |
| MenuBarButtonJob(const rtl::Reference< UpdateCheck >& rUpdateCheck); |
| |
| // XJob |
| virtual uno::Any SAL_CALL execute(const uno::Sequence<beans::NamedValue>&) |
| throw (lang::IllegalArgumentException, uno::Exception); |
| |
| private: |
| rtl::Reference< UpdateCheck > m_aUpdateCheck; |
| }; |
| |
| class DownloadThread : public WorkerThread |
| { |
| public: |
| DownloadThread( |
| osl::Condition& rCondition, |
| const uno::Reference<uno::XComponentContext>& xContext, |
| const rtl::Reference< DownloadInteractionHandler >& rHandler, |
| const rtl::OUString& rURL ); |
| |
| virtual void SAL_CALL run(); |
| virtual void SAL_CALL cancel(); |
| virtual void SAL_CALL suspend(); |
| virtual void SAL_CALL onTerminated(); |
| |
| protected: |
| ~DownloadThread(); |
| |
| private: |
| osl::Condition& m_aCondition; |
| const uno::Reference<uno::XComponentContext> m_xContext; |
| const rtl::OUString m_aURL; |
| Download m_aDownload; |
| }; |
| |
| //------------------------------------------------------------------------------ |
| class ShutdownThread : public osl::Thread |
| { |
| public: |
| ShutdownThread( const uno::Reference<uno::XComponentContext>& xContext ); |
| |
| virtual void SAL_CALL run(); |
| virtual void SAL_CALL onTerminated(); |
| |
| protected: |
| ~ShutdownThread(); |
| |
| private: |
| osl::Condition m_aCondition; |
| const uno::Reference<uno::XComponentContext> m_xContext; |
| }; |
| |
| //------------------------------------------------------------------------------ |
| |
| UpdateCheckThread::UpdateCheckThread( osl::Condition& rCondition, |
| const uno::Reference<uno::XComponentContext>& xContext ) : |
| m_aCondition(rCondition), |
| m_pHasInternetConnection(NULL), |
| m_xContext(xContext) |
| { |
| |
| #ifdef WNT |
| rtl::OUString aPath; |
| if( osl_getExecutableFile(&aPath.pData) == osl_Process_E_None ) |
| { |
| sal_uInt32 lastIndex = aPath.lastIndexOf('/'); |
| if ( lastIndex > 0 ) |
| { |
| aPath = aPath.copy( 0, lastIndex+1 ); |
| aPath += UNISTRING( "onlinecheck" ); |
| } |
| |
| if ( m_aModule.load(aPath) ) |
| { |
| m_pHasInternetConnection = |
| reinterpret_cast < OnlineCheckFunc > ( |
| m_aModule.getFunctionSymbol( UNISTRING("hasInternetConnection"))); |
| } |
| } |
| #endif |
| |
| createSuspended(); |
| |
| // actually run the thread |
| resume(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| UpdateCheckThread::~UpdateCheckThread() |
| { |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| |
| void SAL_CALL |
| UpdateCheckThread::terminate() |
| { |
| // Cancel potentially hanging http request .. |
| cancel(); |
| // .. before terminating |
| osl::Thread::terminate(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void SAL_CALL |
| UpdateCheckThread::join() |
| { |
| uno::Reference< deployment::XUpdateInformationProvider > xProvider(getProvider()); |
| |
| // do not join during an update check until #i73893# is fixed |
| if( ! xProvider.is() ) |
| { |
| osl::Thread::join(); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void SAL_CALL |
| UpdateCheckThread::cancel() |
| { |
| uno::Reference< deployment::XUpdateInformationProvider > xProvider(getProvider()); |
| |
| if( xProvider.is() ) |
| xProvider->cancel(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| bool |
| UpdateCheckThread::runCheck( bool & rbExtensionsChecked ) |
| { |
| bool ret = false; |
| UpdateState eUIState = UPDATESTATE_NO_UPDATE_AVAIL; |
| |
| UpdateInfo aInfo; |
| rtl::Reference< UpdateCheck > aController(UpdateCheck::get()); |
| |
| if( checkForUpdates(aInfo, m_xContext, aController->getInteractionHandler(), createProvider()) ) |
| { |
| aController->setUpdateInfo(aInfo); |
| eUIState = aController->getUIState(aInfo); |
| ret = true; |
| } |
| else |
| aController->setCheckFailedState(); |
| |
| // We will only look for extension updates, when there is no 'check for office updates' dialog open |
| // and when there was no office update found |
| if ( ( eUIState != UPDATESTATE_UPDATE_AVAIL ) && |
| ( eUIState != UPDATESTATE_UPDATE_NO_DOWNLOAD ) && |
| !aController->isDialogShowing() && |
| !rbExtensionsChecked ) |
| { |
| bool bHasExtensionUpdates = checkForExtensionUpdates( m_xContext ); |
| aController->setHasExtensionUpdates( bHasExtensionUpdates ); |
| if ( bHasExtensionUpdates ) |
| aController->setUIState( UPDATESTATE_EXT_UPD_AVAIL ); |
| rbExtensionsChecked = true; |
| } |
| |
| // joining with this thread is safe again |
| clearProvider(); |
| return ret; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void SAL_CALL |
| UpdateCheckThread::onTerminated() |
| { |
| delete this; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void SAL_CALL |
| UpdateCheckThread::run() |
| { |
| bool bExtensionsChecked = false; |
| TimeValue systime; |
| TimeValue nExtCheckTime; |
| osl_getSystemTime( &nExtCheckTime ); |
| |
| osl::Condition::Result aResult = osl::Condition::result_timeout; |
| TimeValue tv = { 10, 0 }; |
| |
| // Initial wait to avoid doing further time consuming tasks during start-up |
| aResult = m_aCondition.wait(&tv); |
| |
| try { |
| |
| while( sal_True == schedule() ) |
| { |
| /* Use cases: |
| * a) manual check requested from auto check thread - "last check" should not be checked (one time) |
| * a1) manual check was requested in the middle of a running auto check, |
| * condition is set |
| * a2) manual check was requested while waiting for a retry, |
| * condition is set |
| * a3) manual check was requested while waiting for time to next |
| * scheduled check elapsing, condition is set |
| * a4) manual check was requested during initial wait, condition is set |
| * b) check interval got changed, condition may be set - same sub-cases as a), |
| * but "last check" should be honored |
| * c) normal auto check mode, condition not set - "last check" should be honored |
| */ |
| |
| // Accessing const members without synchronization |
| rtl::Reference< UpdateCheck > aController(UpdateCheck::get()); |
| rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext, *aController); |
| |
| // FIXME: remember last & offset ? |
| sal_Int64 last = rModel->getLastChecked(); |
| sal_Int64 offset = rModel->getCheckInterval(); |
| |
| rModel.clear(); |
| |
| // last == 0 means check immediately |
| bool checkNow = ! (last > 0); |
| |
| // Reset the condition to avoid busy loops |
| if( osl::Condition::result_ok == aResult ) |
| { |
| m_aCondition.reset(); |
| aResult = osl::Condition::result_timeout; |
| checkNow = aController->isDialogShowing(); |
| } |
| |
| if( ! checkNow ) |
| { |
| osl_getSystemTime(&systime); |
| |
| // Go back to sleep until time has elapsed |
| sal_Int64 next = last + offset; |
| if( last + offset > systime.Seconds ) |
| { |
| // This can not be > 32 Bit for now .. |
| tv.Seconds = static_cast< sal_Int32 > (next - systime.Seconds); |
| aResult = m_aCondition.wait(&tv); |
| continue; |
| } |
| } |
| |
| static sal_uInt8 n = 0; |
| |
| if( ! hasInternetConnection() || ! runCheck( bExtensionsChecked ) ) |
| { |
| // the extension update check should be independent from the office update check |
| // |
| osl_getSystemTime( &systime ); |
| if ( nExtCheckTime.Seconds + offset < systime.Seconds ) |
| bExtensionsChecked = false; |
| |
| // Increase next by 15, 60, .. minutes |
| static const sal_Int32 nRetryInterval[] = { 900, 3600, 14400, 86400 }; |
| |
| if( n < sizeof(nRetryInterval) / sizeof(sal_Int32) ) |
| ++n; |
| |
| tv.Seconds = nRetryInterval[n-1]; |
| aResult = m_aCondition.wait(&tv); |
| } |
| else // reset retry counter |
| { |
| n = 0; |
| bExtensionsChecked = false; |
| } |
| } |
| } |
| |
| catch(const uno::Exception& e) { |
| // Silently catch all errors |
| OSL_TRACE( "Caught exception: %s\n thread terminated.\n", |
| rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr() ); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void SAL_CALL |
| ManualUpdateCheckThread::run() |
| { |
| bool bExtensionsChecked = false; |
| |
| try { |
| runCheck( bExtensionsChecked ); |
| m_aCondition.reset(); |
| } |
| catch(const uno::Exception& e) { |
| // Silently catch all errors |
| OSL_TRACE( "Caught exception: %s\n thread terminated.\n", |
| rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr() ); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| MenuBarButtonJob::MenuBarButtonJob(const rtl::Reference< UpdateCheck >& rUpdateCheck) : |
| m_aUpdateCheck(rUpdateCheck) |
| { |
| }; |
| |
| //------------------------------------------------------------------------------ |
| |
| uno::Any SAL_CALL |
| MenuBarButtonJob::execute(const uno::Sequence<beans::NamedValue>& ) |
| throw (lang::IllegalArgumentException, uno::Exception) |
| { |
| if ( m_aUpdateCheck->shouldShowExtUpdDlg() ) |
| m_aUpdateCheck->showExtensionDialog(); |
| else |
| m_aUpdateCheck->showDialog(); |
| |
| return uno::Any(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| DownloadThread::DownloadThread(osl::Condition& rCondition, |
| const uno::Reference<uno::XComponentContext>& xContext, |
| const rtl::Reference< DownloadInteractionHandler >& rHandler, |
| const rtl::OUString& rURL) : |
| m_aCondition(rCondition), |
| m_xContext(xContext), |
| m_aURL(rURL), |
| m_aDownload(xContext, rHandler) |
| { |
| createSuspended(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| DownloadThread::~DownloadThread() |
| { |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void SAL_CALL |
| DownloadThread::run() |
| { |
| #ifdef WNT |
| CoUninitialize(); |
| CoInitialize( NULL ); |
| #endif |
| |
| while( schedule() ) |
| { |
| rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); |
| |
| rtl::OUString aLocalFile = rModel->getLocalFileName(); |
| rtl::OUString aDownloadDest = rModel->getDownloadDestination(); |
| |
| // release config class for now |
| rModel.clear(); |
| |
| static sal_uInt8 n = 0; |
| if( ! m_aDownload.start(m_aURL, aLocalFile, aDownloadDest ) ) |
| { |
| // retry every 15s unless the dialog is not visible |
| TimeValue tv; |
| tv.Seconds = 15; |
| |
| if( ! UpdateCheck::get()->isDialogShowing() ) |
| { |
| // Increase next by 1, 5, 15, 60, .. minutes |
| static const sal_Int16 nRetryInterval[] = { 60, 300, 900, 3600 }; |
| |
| if( n < sizeof(nRetryInterval) / sizeof(sal_Int16) ) |
| ++n; |
| |
| tv.Seconds = nRetryInterval[n-1]; |
| } |
| m_aCondition.wait(&tv); |
| } |
| else |
| { |
| // reset wait period after successful download |
| n=0; |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void SAL_CALL DownloadThread::cancel() |
| { |
| m_aDownload.stop(); |
| resume(); |
| |
| rtl::Reference< UpdateCheck > aController(UpdateCheck::get()); |
| aController->cancelDownload(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void SAL_CALL DownloadThread::suspend() |
| { |
| osl::Thread::suspend(); |
| m_aDownload.stop(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void SAL_CALL DownloadThread::onTerminated() |
| { |
| delete this; |
| } |
| |
| //------------------------------------------------------------------------------ |
| ShutdownThread::ShutdownThread( const uno::Reference<uno::XComponentContext>& xContext) : |
| m_xContext( xContext ) |
| { |
| create(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| ShutdownThread::~ShutdownThread() |
| { |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL |
| ShutdownThread::run() |
| { |
| TimeValue tv = { 0, 250 }; |
| |
| m_aCondition.wait(&tv); |
| |
| // Tell QuickStarter not to veto .. |
| uno::Reference< beans::XFastPropertySet > xQuickStarter( |
| UpdateCheck::createService(UNISTRING("com.sun.star.office.Quickstart"), m_xContext), |
| uno::UNO_QUERY |
| ); |
| |
| if (xQuickStarter.is()) |
| xQuickStarter->setFastPropertyValue(0, uno::makeAny(false)); |
| |
| // Shutdown the office |
| uno::Reference< frame::XDesktop > xDesktop( |
| UpdateCheck::createService(UNISTRING("com.sun.star.frame.Desktop"), m_xContext), |
| uno::UNO_QUERY); |
| |
| if( xDesktop.is() ) |
| xDesktop->terminate(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL ShutdownThread::onTerminated() |
| { |
| delete this; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| } // anonymous namespace |
| |
| |
| //------------------------------------------------------------------------------ |
| |
| |
| void |
| UpdateCheck::initialize(const uno::Sequence< beans::NamedValue >& rValues, |
| const uno::Reference<uno::XComponentContext>& xContext) |
| { |
| osl::MutexGuard aGuard(m_aMutex); |
| |
| if( NOT_INITIALIZED == m_eState ) |
| { |
| NamedValueByNameAccess aNameAccess(rValues); |
| UpdateCheckROModel aModel( aNameAccess ); |
| m_xContext = xContext; |
| |
| rtl::OUString aUpdateEntryVersion = aModel.getUpdateEntryVersion(); |
| |
| aModel.getUpdateEntry(m_aUpdateInfo); |
| |
| bool obsoleteUpdateInfo = isObsoleteUpdateInfo(aUpdateEntryVersion); |
| bool bContinueDownload = false; |
| bool bDownloadAvailable = false; |
| |
| m_bHasExtensionUpdate = checkForPendingUpdates( xContext ); |
| m_bShowExtUpdDlg = false; |
| |
| rtl::OUString aLocalFileName = aModel.getLocalFileName(); |
| |
| if( aLocalFileName.getLength() > 0 ) |
| { |
| bContinueDownload = true; |
| |
| // Try to get the number of bytes already on disk |
| osl::DirectoryItem aDirectoryItem; |
| if( osl::DirectoryItem::E_None == osl::DirectoryItem::get(aLocalFileName, aDirectoryItem) ) |
| { |
| osl::FileStatus aFileStatus(FileStatusMask_FileSize); |
| if( osl::DirectoryItem::E_None == aDirectoryItem.getFileStatus(aFileStatus) ) |
| { |
| sal_Int64 nDownloadSize = aModel.getDownloadSize(); |
| sal_Int64 nFileSize = aFileStatus.getFileSize(); |
| |
| if( nDownloadSize > 0 ) |
| { |
| if ( nDownloadSize <= nFileSize ) // we have already downloaded everthing |
| { |
| bContinueDownload = false; |
| bDownloadAvailable = true; |
| m_aImageName = getImageFromFileName( aLocalFileName ); |
| } |
| else // Calculate initial percent value. |
| { |
| sal_Int32 nPercent = (sal_Int32) (100 * nFileSize / nDownloadSize); |
| getUpdateHandler()->setProgress( nPercent ); |
| } |
| } |
| } |
| } |
| |
| if ( bContinueDownload ) |
| { |
| bool downloadPaused = aModel.isDownloadPaused(); |
| |
| enableDownload(true, downloadPaused); |
| setUIState(downloadPaused ? UPDATESTATE_DOWNLOAD_PAUSED : UPDATESTATE_DOWNLOADING); |
| } |
| |
| } |
| if ( !bContinueDownload ) |
| { |
| // We do this intentionally only if no download is in progress .. |
| if( obsoleteUpdateInfo ) |
| { |
| // Bring-up release note for position 5 .. |
| const rtl::OUString aURL(getReleaseNote(m_aUpdateInfo, 5)); |
| if( aURL.getLength() > 0 ) |
| showReleaseNote(aURL); |
| |
| // Data is outdated, probably due to installed update |
| rtl::Reference< UpdateCheckConfig > aConfig = UpdateCheckConfig::get( xContext, *this ); |
| aConfig->clearUpdateFound(); |
| aConfig->clearLocalFileName(); |
| |
| |
| m_aUpdateInfo = UpdateInfo(); |
| // Remove outdated release notes |
| storeReleaseNote( 1, rtl::OUString() ); |
| storeReleaseNote( 2, rtl::OUString() ); |
| } |
| else |
| { |
| enableAutoCheck(aModel.isAutoCheckEnabled()); |
| if ( bDownloadAvailable ) |
| setUIState( UPDATESTATE_DOWNLOAD_AVAIL ); |
| else |
| setUIState(getUIState(m_aUpdateInfo)); |
| } |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::cancel() |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| |
| WorkerThread *pThread = m_pThread; |
| UpdateState eUIState = getUIState(m_aUpdateInfo); |
| |
| aGuard.clear(); |
| |
| if( NULL != pThread ) |
| pThread->cancel(); |
| |
| setUIState(eUIState); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::download() |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| UpdateInfo aInfo(m_aUpdateInfo); |
| State eState = m_eState; |
| aGuard.clear(); |
| |
| if( aInfo.Sources[0].IsDirect ) |
| { |
| // Ignore second click of a double click |
| if( DOWNLOADING != eState ) |
| { |
| shutdownThread(true); |
| |
| osl::ClearableMutexGuard aGuard2(m_aMutex); |
| enableDownload(true); |
| aGuard2.clear(); |
| setUIState(UPDATESTATE_DOWNLOADING); |
| } |
| } |
| else |
| { |
| showReleaseNote(aInfo.Sources[0].URL); // Display in browser |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::install() |
| { |
| osl::MutexGuard aGuard(m_aMutex); |
| |
| const uno::Reference< c3s::XSystemShellExecute > xShellExecute( |
| c3s::SystemShellExecute::create( m_xContext ) ); |
| |
| try { |
| // Construct install command ?? |
| |
| // Store release note for position 3 and 4 |
| rtl::OUString aURL(getReleaseNote(m_aUpdateInfo, 3)); |
| storeReleaseNote(1, aURL); |
| |
| aURL = getReleaseNote(m_aUpdateInfo, 4); |
| storeReleaseNote(2, aURL); |
| |
| if( xShellExecute.is() ) |
| { |
| rtl::OUString aInstallImage(m_aImageName); |
| osl::FileBase::getSystemPathFromFileURL(aInstallImage, aInstallImage); |
| |
| rtl::OUString aParameter; |
| sal_Int32 nFlags = c3s::SystemShellExecuteFlags::DEFAULTS; |
| #if ( defined LINUX || defined SOLARIS ) |
| nFlags = 42; |
| aParameter = getBaseInstallation(); |
| if( aParameter.getLength() > 0 ) |
| osl::FileBase::getSystemPathFromFileURL(aParameter, aParameter); |
| |
| aParameter += UNISTRING(" &"); |
| #endif |
| |
| rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get( m_xContext ); |
| rModel->clearLocalFileName(); |
| |
| xShellExecute->execute(aInstallImage, aParameter, nFlags); |
| ShutdownThread *pShutdownThread = new ShutdownThread( m_xContext ); |
| (void) pShutdownThread; |
| } |
| } catch(uno::Exception&) { |
| m_aUpdateHandler->setErrorMessage( m_aUpdateHandler->getDefaultInstErrMsg() ); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::pause() |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| |
| if( NULL != m_pThread ) |
| m_pThread->suspend(); |
| |
| rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); |
| aGuard.clear(); |
| |
| rModel->storeDownloadPaused(true); |
| setUIState(UPDATESTATE_DOWNLOAD_PAUSED); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::resume() |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| |
| if( NULL != m_pThread ) |
| m_pThread->resume(); |
| |
| rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); |
| aGuard.clear(); |
| |
| rModel->storeDownloadPaused(false); |
| setUIState(UPDATESTATE_DOWNLOADING); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::closeAfterFailure() |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| |
| if ( ( m_eState == DISABLED ) || ( m_eState == CHECK_SCHEDULED ) ) |
| { |
| const UpdateState eUIState = getUIState( m_aUpdateInfo ); |
| aGuard.clear(); |
| setUIState( eUIState, true ); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::shutdownThread(bool join) |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| |
| // copy thread object pointer to stack |
| osl::Thread *pThread = m_pThread; |
| m_pThread = NULL; |
| aGuard.clear(); |
| |
| if( NULL != pThread ) |
| { |
| pThread->terminate(); |
| if( join ) |
| { |
| m_aCondition.set(); |
| pThread->join(); |
| m_aCondition.reset(); |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::enableAutoCheck(bool enable) |
| { |
| if( enable ) |
| m_pThread = new UpdateCheckThread(m_aCondition, m_xContext); |
| |
| m_eState = enable ? CHECK_SCHEDULED : DISABLED; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::enableDownload(bool enable, bool paused) |
| { |
| OSL_ASSERT(NULL == m_pThread); |
| |
| State eState = DISABLED; |
| if( enable ) |
| { |
| m_pThread = new DownloadThread(m_aCondition, m_xContext, this, m_aUpdateInfo.Sources[0].URL ); |
| if( !paused ) |
| { |
| eState = DOWNLOADING; |
| m_pThread->resume(); |
| } |
| else |
| eState = DOWNLOAD_PAUSED; |
| |
| m_eState = eState; |
| } |
| else { |
| enableAutoCheck(UpdateCheckConfig::get(m_xContext)->isAutoCheckEnabled()); |
| } |
| |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| bool |
| UpdateCheck::downloadTargetExists(const rtl::OUString& rFileName) |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| |
| rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler()); |
| UpdateState eUIState = UPDATESTATE_DOWNLOADING; |
| |
| bool cont = false; |
| |
| if( aUpdateHandler->isVisible() ) |
| { |
| cont = aUpdateHandler->showOverwriteWarning(); |
| if( cont ) |
| { |
| if( osl_File_E_None != osl_removeFile(rFileName.pData) ) |
| { |
| // FIXME: error message |
| cont = false; |
| } |
| } |
| else |
| eUIState = getUIState(m_aUpdateInfo); |
| } |
| else |
| { |
| m_aImageName = getImageFromFileName(rFileName); |
| eUIState = UPDATESTATE_DOWNLOAD_AVAIL; |
| } |
| |
| if( !cont ) |
| { |
| shutdownThread(false); |
| enableDownload(false); |
| |
| aGuard.clear(); |
| setUIState(eUIState); |
| } |
| |
| return cont; |
| } |
| |
| //------------------------------------------------------------------------------ |
| bool UpdateCheck::checkDownloadDestination( const rtl::OUString& rFileName ) |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| |
| rtl::Reference< UpdateHandler > aUpdateHandler( getUpdateHandler() ); |
| |
| bool bReload = false; |
| |
| if( aUpdateHandler->isVisible() ) |
| { |
| bReload = aUpdateHandler->showOverwriteWarning( rFileName ); |
| } |
| |
| return bReload; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::downloadStalled(const rtl::OUString& rErrorMessage) |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler()); |
| aGuard.clear(); |
| |
| aUpdateHandler->setErrorMessage(rErrorMessage); |
| setUIState(UPDATESTATE_ERROR_DOWNLOADING); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::downloadProgressAt(sal_Int8 nPercent) |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler()); |
| aGuard.clear(); |
| |
| aUpdateHandler->setProgress(nPercent); |
| setUIState(UPDATESTATE_DOWNLOADING); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::downloadStarted(const rtl::OUString& rLocalFileName, sal_Int64 nFileSize) |
| { |
| if ( nFileSize > 0 ) |
| { |
| osl::MutexGuard aGuard(m_aMutex); |
| |
| rtl::Reference< UpdateCheckConfig > aModel(UpdateCheckConfig::get(m_xContext)); |
| aModel->storeLocalFileName(rLocalFileName, nFileSize); |
| |
| // Bring-up release note for position 1 .. |
| const rtl::OUString aURL(getReleaseNote(m_aUpdateInfo, 1, aModel->isAutoDownloadEnabled())); |
| if( aURL.getLength() > 0 ) |
| showReleaseNote(aURL); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::downloadFinished(const rtl::OUString& rLocalFileName) |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| |
| // no more retries |
| m_pThread->terminate(); |
| |
| m_aImageName = getImageFromFileName(rLocalFileName); |
| UpdateInfo aUpdateInfo(m_aUpdateInfo); |
| |
| aGuard.clear(); |
| setUIState(UPDATESTATE_DOWNLOAD_AVAIL); |
| |
| // Bring-up release note for position 2 .. |
| rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get( m_xContext ); |
| const rtl::OUString aURL(getReleaseNote(aUpdateInfo, 2, rModel->isAutoDownloadEnabled())); |
| if( aURL.getLength() > 0 ) |
| showReleaseNote(aURL); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::cancelDownload() |
| { |
| shutdownThread(true); |
| |
| osl::MutexGuard aGuard(m_aMutex); |
| enableDownload(false); |
| |
| rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); |
| |
| rtl::OUString aLocalFile(rModel->getLocalFileName()); |
| rModel->clearLocalFileName(); |
| rModel->storeDownloadPaused(false); |
| |
| if( isObsoleteUpdateInfo(rModel->getUpdateEntryVersion()) ) |
| { |
| rModel->clearUpdateFound(); // This wasn't done during init yet .. |
| m_aUpdateInfo = UpdateInfo(); |
| } |
| |
| /*oslFileError rc =*/ osl_removeFile(aLocalFile.pData); |
| // FIXME: error handling .. |
| |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::showDialog(bool forceCheck) |
| { |
| osl::ResettableMutexGuard aGuard(m_aMutex); |
| |
| bool update_found = m_aUpdateInfo.BuildId.getLength() > 0; |
| bool bSetUIState = ! m_aUpdateHandler.is(); |
| |
| UpdateState eDialogState = UPDATESTATES_COUNT; |
| |
| switch( m_eState ) |
| { |
| case DISABLED: |
| case CHECK_SCHEDULED: |
| if( forceCheck || ! update_found ) // Run check when forced or if we did not find an update yet |
| { |
| eDialogState = UPDATESTATE_CHECKING; |
| bSetUIState = true; |
| } |
| else if(m_aUpdateInfo.Sources[0].IsDirect) |
| eDialogState = UPDATESTATE_UPDATE_AVAIL; |
| else |
| eDialogState = UPDATESTATE_UPDATE_NO_DOWNLOAD; |
| break; |
| |
| case DOWNLOADING: |
| eDialogState = UPDATESTATE_DOWNLOADING; |
| break; |
| |
| case DOWNLOAD_PAUSED: |
| eDialogState = UPDATESTATE_DOWNLOAD_PAUSED; |
| break; |
| |
| case NOT_INITIALIZED: |
| OSL_ASSERT( false ); |
| break; |
| } |
| |
| if( bSetUIState ) |
| { |
| aGuard.clear(); |
| setUIState(eDialogState, true); // suppress bubble as Dialog will be visible soon |
| aGuard.reset(); |
| } |
| |
| getUpdateHandler()->setVisible(true); |
| |
| // Run check in separate thread .. |
| if( UPDATESTATE_CHECKING == eDialogState ) |
| { |
| if( DISABLED == m_eState ) |
| { |
| // destructs itself when done, not cancellable for now .. |
| new ManualUpdateCheckThread(m_aCondition, m_xContext); |
| } |
| |
| m_aCondition.set(); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::setUpdateInfo(const UpdateInfo& aInfo) |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| |
| bool bSuppressBubble = (sal_True == aInfo.BuildId.equals(m_aUpdateInfo.BuildId)); |
| m_aUpdateInfo = aInfo; |
| |
| OSL_ASSERT(DISABLED == m_eState || CHECK_SCHEDULED == m_eState); |
| |
| // Ignore leading non direct download if we get direct ones |
| std::vector< DownloadSource >::iterator iter = m_aUpdateInfo.Sources.begin(); |
| while( iter != m_aUpdateInfo.Sources.end() ) |
| { |
| if( iter->IsDirect ) |
| break; |
| |
| ++iter; |
| } |
| |
| if( (iter != m_aUpdateInfo.Sources.begin()) && |
| (iter != m_aUpdateInfo.Sources.end()) && |
| iter->IsDirect ) |
| { |
| m_aUpdateInfo.Sources.erase(m_aUpdateInfo.Sources.begin(), --iter); |
| } |
| |
| rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext, *this); |
| OSL_ASSERT( rModel.is() ); |
| |
| // Decide whether to use alternate release note pos .. |
| bool autoDownloadEnabled = rModel->isAutoDownloadEnabled(); |
| |
| std::vector< ReleaseNote >::iterator iter2 = m_aUpdateInfo.ReleaseNotes.begin(); |
| while( iter2 != m_aUpdateInfo.ReleaseNotes.end() ) |
| { |
| if( ((1 == iter2->Pos) || (2 == iter2->Pos)) && autoDownloadEnabled && (iter2->URL2.getLength() > 0)) |
| { |
| iter2->URL = iter2->URL2; |
| iter2->URL2 = rtl::OUString(); |
| iter2->Pos = iter2->Pos2; |
| iter2->Pos2 = 0; |
| } |
| |
| ++iter2; |
| } |
| |
| // do not move below store/clear .. |
| rModel->updateLastChecked(); |
| |
| UpdateState eUIState; |
| if( m_aUpdateInfo.Sources.size() > 0 ) |
| { |
| rModel->storeUpdateFound(aInfo, getBuildId()); |
| |
| if( m_aUpdateInfo.Sources[0].IsDirect ) |
| { |
| eUIState = UPDATESTATE_UPDATE_AVAIL; |
| |
| if( rModel->isAutoDownloadEnabled() ) |
| { |
| shutdownThread(false); |
| eUIState = UPDATESTATE_DOWNLOADING; |
| enableDownload(true); |
| } |
| } |
| else |
| eUIState = UPDATESTATE_UPDATE_NO_DOWNLOAD; |
| } |
| else |
| { |
| eUIState = UPDATESTATE_NO_UPDATE_AVAIL; |
| rModel->clearUpdateFound(); |
| } |
| |
| aGuard.clear(); |
| setUIState(eUIState, bSuppressBubble); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::setCheckFailedState() |
| { |
| setUIState(UPDATESTATE_ERROR_CHECKING); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void UpdateCheck::handleMenuBarUI( rtl::Reference< UpdateHandler > rUpdateHandler, |
| UpdateState& eState, |
| bool suppressBubble ) |
| { |
| uno::Reference<beans::XPropertySet> xMenuBarUI( m_xMenuBarUI ); |
| |
| if ( ( UPDATESTATE_NO_UPDATE_AVAIL == eState ) && m_bHasExtensionUpdate ) |
| eState = UPDATESTATE_EXT_UPD_AVAIL; |
| |
| if ( UPDATESTATE_EXT_UPD_AVAIL == eState ) |
| m_bShowExtUpdDlg = true; |
| else |
| m_bShowExtUpdDlg = false; |
| |
| if( xMenuBarUI.is() ) |
| { |
| if( UPDATESTATE_NO_UPDATE_AVAIL == eState ) |
| { |
| xMenuBarUI->setPropertyValue( PROPERTY_SHOW_MENUICON, uno::makeAny(sal_False) ); |
| } |
| else |
| { |
| xMenuBarUI->setPropertyValue( PROPERTY_TITLE, uno::makeAny(rUpdateHandler->getBubbleTitle(eState)) ); |
| xMenuBarUI->setPropertyValue( PROPERTY_TEXT, uno::makeAny(rUpdateHandler->getBubbleText(eState)) ); |
| |
| if( ! suppressBubble && ( ! rUpdateHandler->isVisible() || rUpdateHandler->isMinimized() ) ) |
| xMenuBarUI->setPropertyValue( PROPERTY_SHOW_BUBBLE, uno::makeAny( sal_True ) ); |
| |
| if( UPDATESTATE_CHECKING != eState ) |
| xMenuBarUI->setPropertyValue( PROPERTY_SHOW_MENUICON, uno::makeAny(sal_True) ); |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| void UpdateCheck::setUIState(UpdateState eState, bool suppressBubble) |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| |
| if( ! m_xMenuBarUI.is() && |
| (DISABLED != m_eState) && |
| ( m_bHasExtensionUpdate || (UPDATESTATE_NO_UPDATE_AVAIL != eState)) && |
| (UPDATESTATE_CHECKING != eState) && |
| (UPDATESTATE_ERROR_CHECKING != eState) |
| ) |
| { |
| m_xMenuBarUI = createMenuBarUI(m_xContext, new MenuBarButtonJob(this)); |
| } |
| |
| // Show bubble only when the status has changed |
| if ( eState == m_eUpdateState ) |
| suppressBubble = true; |
| else |
| m_eUpdateState = eState; |
| |
| rtl::Reference<UpdateHandler> aUpdateHandler(getUpdateHandler()); |
| OSL_ASSERT( aUpdateHandler.is() ); |
| |
| UpdateInfo aUpdateInfo(m_aUpdateInfo); |
| rtl::OUString aImageName(m_aImageName); |
| |
| aGuard.clear(); |
| |
| handleMenuBarUI( aUpdateHandler, eState, suppressBubble ); |
| |
| if( (UPDATESTATE_UPDATE_AVAIL == eState) |
| || (UPDATESTATE_DOWNLOAD_PAUSED == eState) |
| || (UPDATESTATE_DOWNLOADING == eState) ) |
| { |
| uno::Reference< uno::XComponentContext > xContext(m_xContext); |
| |
| rtl::OUString aDownloadDestination = |
| UpdateCheckConfig::get(xContext, this)->getDownloadDestination(); |
| |
| osl_getSystemPathFromFileURL(aDownloadDestination.pData, &aDownloadDestination.pData); |
| |
| aUpdateHandler->setDownloadPath(aDownloadDestination); |
| } |
| else if( UPDATESTATE_DOWNLOAD_AVAIL == eState ) |
| { |
| aUpdateHandler->setDownloadFile(aImageName); |
| } |
| |
| aUpdateHandler->setDescription(aUpdateInfo.Description); |
| aUpdateHandler->setNextVersion(aUpdateInfo.Version); |
| aUpdateHandler->setState(eState); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| UpdateState |
| UpdateCheck::getUIState(const UpdateInfo& rInfo) |
| { |
| UpdateState eUIState = UPDATESTATE_NO_UPDATE_AVAIL; |
| |
| if( rInfo.BuildId.getLength() > 0 ) |
| { |
| if( rInfo.Sources[0].IsDirect ) |
| eUIState = UPDATESTATE_UPDATE_AVAIL; |
| else |
| eUIState = UPDATESTATE_UPDATE_NO_DOWNLOAD; |
| } |
| |
| return eUIState; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::showReleaseNote(const rtl::OUString& rURL) const |
| { |
| const uno::Reference< c3s::XSystemShellExecute > xShellExecute( |
| createService( UNISTRING( "com.sun.star.system.SystemShellExecute" ), m_xContext ), |
| uno::UNO_QUERY ); |
| |
| try { |
| |
| if( xShellExecute.is() ) |
| xShellExecute->execute(rURL, rtl::OUString(), c3s::SystemShellExecuteFlags::DEFAULTS); |
| } catch(c3s::SystemShellExecuteException&) { |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| bool |
| UpdateCheck::storeReleaseNote(sal_Int8 nNum, const rtl::OUString &rURL) |
| { |
| osl::FileBase::RC rc; |
| rtl::OUString aTargetDir( UpdateCheckConfig::getAllUsersDirectory() + UNISTRING( "/sun" ) ); |
| |
| rc = osl::Directory::createPath( aTargetDir ); |
| |
| rtl::OUString aFileName = UNISTRING("releasenote") + |
| rtl::OUString::valueOf( (sal_Int32) nNum ) + |
| UNISTRING(".url"); |
| |
| rtl::OUString aFilePath; |
| rc = osl::FileBase::getAbsoluteFileURL( aTargetDir, aFileName, aFilePath ); |
| if ( rc != osl::FileBase::E_None ) return false; |
| |
| rc = osl::File::remove( aFilePath ); |
| |
| // don't store empty release notes, but delete old ones |
| if ( rURL.getLength() == 0 ) |
| return true; |
| |
| osl::File aFile( aFilePath ); |
| rc = aFile.open( OpenFlag_Write | OpenFlag_Create ); |
| |
| if ( rc != osl::FileBase::E_None ) return false; |
| |
| rtl::OString aLineBuf("[InternetShortcut]\r\n"); |
| sal_uInt64 nWritten = 0; |
| |
| rtl::OUString aURL( rURL ); |
| #ifdef WNT |
| rc = aFile.write( aLineBuf.getStr(), aLineBuf.getLength(), nWritten ); |
| if ( rc != osl::FileBase::E_None ) return false; |
| aURL = UNISTRING("URL=") + rURL; |
| #endif |
| aLineBuf = rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ); |
| rc = aFile.write( aLineBuf.getStr(), aLineBuf.getLength(), nWritten ); |
| if ( rc != osl::FileBase::E_None ) return false; |
| |
| aFile.close(); |
| return true; |
| } |
| |
| //------------------------------------------------------------------------------ |
| void UpdateCheck::showExtensionDialog() |
| { |
| rtl::OUString sServiceName = UNISTRING("com.sun.star.deployment.ui.PackageManagerDialog"); |
| rtl::OUString sArguments = UNISTRING("SHOW_UPDATE_DIALOG"); |
| uno::Reference< uno::XInterface > xService; |
| |
| if( ! m_xContext.is() ) |
| throw uno::RuntimeException( |
| UNISTRING( "UpdateCheck::showExtensionDialog(): empty component context" ), uno::Reference< uno::XInterface > () ); |
| |
| uno::Reference< lang::XMultiComponentFactory > xServiceManager( m_xContext->getServiceManager() ); |
| if( !xServiceManager.is() ) |
| throw uno::RuntimeException( |
| UNISTRING( "UpdateCheck::showExtensionDialog(): unable to obtain service manager from component context" ), uno::Reference< uno::XInterface > () ); |
| |
| xService = xServiceManager->createInstanceWithContext( sServiceName, m_xContext ); |
| uno::Reference< task::XJobExecutor > xExecuteable( xService, uno::UNO_QUERY ); |
| if ( xExecuteable.is() ) |
| xExecuteable->trigger( sArguments ); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| rtl::Reference<UpdateHandler> |
| UpdateCheck::getUpdateHandler() |
| { |
| osl::MutexGuard aGuard(m_aMutex); |
| |
| if( ! m_aUpdateHandler.is() ) |
| m_aUpdateHandler = new UpdateHandler(m_xContext, this); |
| |
| return m_aUpdateHandler; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| uno::Reference< task::XInteractionHandler > |
| UpdateCheck::getInteractionHandler() const |
| { |
| osl::MutexGuard aGuard(m_aMutex); |
| |
| uno::Reference< task::XInteractionHandler > xHandler; |
| |
| if( m_aUpdateHandler.is() && m_aUpdateHandler->isVisible() ) |
| xHandler = m_aUpdateHandler.get(); |
| |
| return xHandler; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| uno::Reference< uno::XInterface > |
| UpdateCheck::createService(const rtl::OUString& rServiceName, |
| const uno::Reference<uno::XComponentContext>& xContext) |
| { |
| if( !xContext.is() ) |
| throw uno::RuntimeException( |
| UNISTRING( "UpdateCheckConfig: empty component context" ), |
| uno::Reference< uno::XInterface >() ); |
| |
| const uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager()); |
| |
| if( !xServiceManager.is() ) |
| throw uno::RuntimeException( |
| UNISTRING( "UpdateCheckConfig: unable to obtain service manager from component context" ), |
| uno::Reference< uno::XInterface >() ); |
| |
| return xServiceManager->createInstanceWithContext(rServiceName, xContext); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| bool |
| UpdateCheck::isDialogShowing() const |
| { |
| osl::MutexGuard aGuard(m_aMutex); |
| return sal_True == m_aUpdateHandler.is() && m_aUpdateHandler->isVisible(); |
| }; |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::autoCheckStatusChanged(bool enabled) |
| { |
| osl::ClearableMutexGuard aGuard(m_aMutex); |
| |
| if( (CHECK_SCHEDULED == m_eState) && !enabled ) |
| shutdownThread(false); |
| |
| if( (DISABLED == m_eState) || (CHECK_SCHEDULED == m_eState) ) |
| { |
| enableAutoCheck(enabled); |
| UpdateState eState = getUIState(m_aUpdateInfo); |
| aGuard.clear(); |
| setUIState(eState); |
| } |
| }; |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| UpdateCheck::autoCheckIntervalChanged() |
| { |
| // just wake-up |
| m_aCondition.set(); |
| }; |
| |
| //------------------------------------------------------------------------------ |
| |
| oslInterlockedCount SAL_CALL |
| UpdateCheck::acquire() SAL_THROW(()) |
| { |
| return ReferenceObject::acquire(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| oslInterlockedCount SAL_CALL |
| UpdateCheck::release() SAL_THROW(()) |
| { |
| return ReferenceObject::release(); |
| } |