25#include <config_folders.h>
30#include <com/sun/star/beans/XFastPropertySet.hpp>
31#include <com/sun/star/deployment/UpdateInformationProvider.hpp>
32#include <com/sun/star/frame/Desktop.hpp>
33#include <com/sun/star/office/Quickstart.hpp>
34#include <com/sun/star/system/SystemShellExecute.hpp>
35#include <com/sun/star/system/SystemShellExecuteException.hpp>
36#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
37#include <com/sun/star/task/XJob.hpp>
38#include <com/sun/star/task/XJobExecutor.hpp>
40#include <rtl/bootstrap.hxx>
41#include <osl/process.h>
42#include <osl/file.hxx>
60namespace c3s = com::sun::star::system ;
77 if( (
pos > 2) || !autoDownloadEnabled || elem.URL2.isEmpty() )
80 else if( (
pos == elem.Pos2) && ((1 == elem.Pos) || (2 == elem.Pos)) && autoDownloadEnabled )
93 OUString aPathVal(
"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE(
"version")
":buildid}");
94 rtl::Bootstrap::expandMacros(aPathVal);
99bool isObsoleteUpdateInfo(std::u16string_view rBuildId)
101 return rBuildId != getBuildId() && !rBuildId.empty();
105OUString getImageFromFileName(
const OUString& aFile)
108 OUString aUnpackPath;
109 if( osl_getExecutableFile(&aUnpackPath.pData) == osl_Process_E_None )
111 sal_uInt32 lastIndex = aUnpackPath.lastIndexOf(
'/');
114 aUnpackPath = OUString::Concat(aUnpackPath.subView( 0, lastIndex+1 )) +
118 oslFileHandle hOut =
nullptr;
119 oslProcess hProcess =
nullptr;
121 OUString aSystemPath;
122 osl::File::getSystemPathFromFileURL(aFile, aSystemPath);
124 oslProcessError rc = osl_executeProcess_WithRedirectedIO(
126 &aSystemPath.pData, 1,
127 osl_Process_WAIT | osl_Process_NORMAL,
132 nullptr, &hOut,
nullptr
135 if( osl_Process_E_None == rc )
140 osl_freeProcessHandle(hProcess);
143 oslProcessInfo aInfo;
144 aInfo.Size =
sizeof(oslProcessInfo);
146 if( osl_Process_E_None == osl_getProcessInfo(hProcess, osl_Process_EXITCODE, &aInfo) )
148 if( 0 == aInfo.Code )
151 sal_uInt64 nBytesRead = 0;
152 const sal_uInt64 nBytesToRead =
sizeof(szBuffer) - 1;
155 while( osl_File_E_None == osl_readFile(hOut, szBuffer, nBytesToRead, &nBytesRead) )
157 char *
pc = szBuffer + nBytesRead;
162 while( (
'\n' == *pc) || (
'\r' == *
pc) );
164 aImageName += OUString(szBuffer, pc - szBuffer + 1, osl_getThreadTextEncoding());
166 if( nBytesRead < nBytesToRead )
170 if( osl::FileBase::E_None == osl::FileBase::getFileURLFromSystemPath(aImageName, aImageName) )
182uno::Reference< beans::XPropertySet > createMenuBarUI(
183 const uno::Reference< uno::XComponentContext >& xContext,
184 const uno::Reference< task::XJob >& xJob)
187 throw uno::RuntimeException(
188 "UpdateCheckJob: empty component context", uno::Reference< uno::XInterface > () );
190 uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager());
191 if( !xServiceManager.is() )
192 throw uno::RuntimeException(
193 "UpdateCheckJob: unable to obtain service manager from component context", uno::Reference< uno::XInterface > () );
195 uno::Reference< beans::XPropertySet > xMenuBarUI(
196 xServiceManager->createInstanceWithContext(
"com.sun.star.setup.UpdateCheckUI", xContext ),
197 uno::UNO_QUERY_THROW);
205typedef sal_Bool (* OnlineCheckFunc) ();
211 UpdateCheckThread( osl::Condition& rCondition,
212 const uno::Reference<uno::XComponentContext>& xContext,
215 virtual void SAL_CALL
join()
override;
216 virtual void SAL_CALL terminate()
override;
217 virtual void cancel()
override;
219 void cancelAsSoonAsPossible();
222 virtual ~UpdateCheckThread()
override;
224 virtual void SAL_CALL
run()
override;
225 virtual void SAL_CALL onTerminated()
override;
228 bool runCheck(
bool & rbExtensionsChecked );
233 static bool hasInternetConnection()
243 uno::Reference<deployment::XUpdateInformationProvider> createProvider()
246 m_xProvider = deployment::UpdateInformationProvider::create(
m_xContext);
251 uno::Reference<deployment::XUpdateInformationProvider> getProvider()
252 { osl::MutexGuard aGuard(
m_aMutex);
return m_xProvider; };
256 { osl::MutexGuard aGuard(
m_aMutex); m_xProvider.clear(); };
261 osl::Condition& m_aCondition;
264 const uno::Reference<uno::XComponentContext>
m_xContext;
265 uno::Reference<deployment::XUpdateInformationProvider> m_xProvider;
267 bool m_cancelAsSoonAsPossible;
271class ManualUpdateCheckThread :
public UpdateCheckThread
274 ManualUpdateCheckThread( osl::Condition& rCondition,
const uno::Reference<uno::XComponentContext>& xContext ) :
275 UpdateCheckThread(rCondition, xContext, {}) {};
277 virtual void SAL_CALL
run()
override;
281class MenuBarButtonJob :
public ::cppu::WeakImplHelper< task::XJob >
287 virtual uno::Any SAL_CALL execute(
const uno::Sequence<beans::NamedValue>&)
override;
297 osl::Condition& rCondition,
298 const uno::Reference<uno::XComponentContext>& xContext,
300 const OUString& rURL );
302 virtual void SAL_CALL
run()
override;
303 virtual void cancel()
override;
304 virtual void SAL_CALL suspend()
override;
305 virtual void SAL_CALL onTerminated()
override;
308 virtual ~DownloadThread()
override;
311 osl::Condition& m_aCondition;
312 const uno::Reference<uno::XComponentContext>
m_xContext;
319UpdateCheckThread::UpdateCheckThread( osl::Condition& rCondition,
320 const uno::Reference<uno::XComponentContext>& xContext,
322 m_aCondition(rCondition),
324 m_controller(controller),
325 m_cancelAsSoonAsPossible(false)
334UpdateCheckThread::~UpdateCheckThread()
340UpdateCheckThread::terminate()
345 osl::Thread::terminate();
350UpdateCheckThread::join()
352 uno::Reference< deployment::XUpdateInformationProvider > xProvider(getProvider());
355 if( ! xProvider.is() )
363UpdateCheckThread::cancel()
365 uno::Reference< deployment::XUpdateInformationProvider > xProvider(getProvider());
371void UpdateCheckThread::cancelAsSoonAsPossible() {
374 m_cancelAsSoonAsPossible =
true;
380UpdateCheckThread::runCheck(
bool & rbExtensionsChecked )
390 aController->setUpdateInfo(aInfo);
395 aController->setCheckFailedState();
401 !aController->isDialogShowing() &&
402 !rbExtensionsChecked )
405 aController->setHasExtensionUpdates( bHasExtensionUpdates );
406 if ( bHasExtensionUpdates )
408 rbExtensionsChecked =
true;
418UpdateCheckThread::onTerminated()
425UpdateCheckThread::run()
427 osl_setThreadName(
"UpdateCheckThread");
430 TimeValue nExtCheckTime;
431 osl_getSystemTime( &nExtCheckTime );
433 osl::Condition::Result aResult = osl::Condition::result_timeout;
434 TimeValue tv = { 10, 0 };
437 aResult = m_aCondition.wait(&tv);
440 if (m_cancelAsSoonAsPossible) {
446 bool bExtensionsChecked =
false;
469 sal_Int64
last = rModel->getLastChecked();
470 sal_Int64 offset = rModel->getCheckInterval();
475 bool checkNow =
last <= 0;
478 if( osl::Condition::result_ok == aResult )
480 m_aCondition.reset();
481 aResult = osl::Condition::result_timeout;
482 checkNow = aController->isDialogShowing();
487 osl_getSystemTime(&systime);
490 sal_Int64 next =
last + offset;
491 if( last + offset > systime.Seconds )
494 tv.Seconds =
static_cast< sal_Int32
> (next - systime.Seconds);
495 aResult = m_aCondition.wait(&tv);
498 if (m_cancelAsSoonAsPossible) {
508 if( ! hasInternetConnection() || ! runCheck( bExtensionsChecked ) )
512 osl_getSystemTime( &systime );
513 if ( nExtCheckTime.Seconds + offset < systime.Seconds )
514 bExtensionsChecked =
false;
517 static const sal_Int32 nRetryInterval[] = { 900, 3600, 14400, 86400 };
519 if( n < std::size(nRetryInterval) )
522 tv.Seconds = nRetryInterval[
n-1];
523 aResult = m_aCondition.wait(&tv);
526 if (m_cancelAsSoonAsPossible) {
534 bExtensionsChecked =
false;
539 catch(
const uno::Exception&) {
545 if (m_controller.is()) {
546 m_controller->notifyUpdateCheckFinished();
552ManualUpdateCheckThread::run()
555 bool bExtensionsChecked =
false;
556 runCheck( bExtensionsChecked );
557 m_aCondition.reset();
559 catch(
const uno::Exception&) {
567 m_aUpdateCheck(rUpdateCheck)
573MenuBarButtonJob::execute(
const uno::Sequence<beans::NamedValue>& )
575 if ( m_aUpdateCheck->shouldShowExtUpdDlg() )
576 m_aUpdateCheck->showExtensionDialog();
578 m_aUpdateCheck->showDialog();
584DownloadThread::DownloadThread(osl::Condition& rCondition,
585 const uno::Reference<uno::XComponentContext>& xContext,
587 const OUString& rURL) :
588 m_aCondition(rCondition),
591 m_aDownload(xContext, rHandler)
597DownloadThread::~DownloadThread()
605 osl_setThreadName(
"DownloadThread");
608 int nNbCallCoInitializeExForReinit = 0;
610 o3tl::safeCoInitializeEx(COINIT_APARTMENTTHREADED, nNbCallCoInitializeExForReinit);
617 OUString aLocalFile = rModel->getLocalFileName();
618 OUString aDownloadDest = rModel->getDownloadDestination();
624 if( ! m_aDownload.start(m_aURL, aLocalFile, aDownloadDest ) )
629 if( ! UpdateCheck::get()->isDialogShowing() )
632 static const sal_Int16 nRetryInterval[] = { 60, 300, 900, 3600 };
634 if( n < std::size(nRetryInterval) )
637 tv.Seconds = nRetryInterval[
n-1];
639 m_aCondition.wait(&tv);
648 o3tl::safeCoUninitializeReinit(COINIT_MULTITHREADED, nNbCallCoInitializeExForReinit);
653void DownloadThread::cancel()
659 aController->cancelDownload();
663void SAL_CALL DownloadThread::suspend()
665 osl::Thread::suspend();
670void SAL_CALL DownloadThread::onTerminated()
679 : m_eState(NOT_INITIALIZED)
682 , m_bHasExtensionUpdate(false)
683 , m_bShowExtUpdDlg(false)
684 , m_updateCheckRunning(false)
692 const uno::Reference<uno::XComponentContext>& xContext)
706 bool obsoleteUpdateInfo = isObsoleteUpdateInfo(aUpdateEntryVersion);
707 bool bContinueDownload =
false;
708 bool bDownloadAvailable =
false;
715 if( !aLocalFileName.isEmpty() )
717 bContinueDownload =
true;
720 osl::DirectoryItem aDirectoryItem;
721 if( osl::DirectoryItem::E_None == osl::DirectoryItem::get(aLocalFileName, aDirectoryItem) )
723 osl::FileStatus aFileStatus(osl_FileStatus_Mask_FileSize);
724 if( osl::DirectoryItem::E_None == aDirectoryItem.getFileStatus(aFileStatus) )
727 sal_Int64 nFileSize = aFileStatus.getFileSize();
729 if( nDownloadSize > 0 )
731 if ( nDownloadSize <= nFileSize )
733 bContinueDownload =
false;
734 bDownloadAvailable =
true;
739 sal_Int32 nPercent =
static_cast<sal_Int32
>(100 * nFileSize / nDownloadSize);
746 if ( bContinueDownload )
756 if ( !bContinueDownload )
759 if( obsoleteUpdateInfo )
763 if( !
aURL.isEmpty() )
768 aConfig->clearUpdateFound();
769 aConfig->clearLocalFileName();
780 if ( bDownloadAvailable )
803 if(
nullptr != pThread )
820 SAL_WARN(
"extensions.update",
"download called without source");
824 if( aInfo.
Sources[0].IsDirect )
856 rModel->storeDownloadPaused(
true);
872 rModel->storeDownloadPaused(
false);
897 UpdateCheckThread * thread;
900 thread =
dynamic_cast<UpdateCheckThread *
>(
m_pThread);
902 if (thread !=
nullptr) {
903 thread->cancelAsSoonAsPossible();
924 if(
nullptr != pThread )
926 pThread->terminate();
986 if( aUpdateHandler->isVisible() )
988 cont = aUpdateHandler->showOverwriteWarning();
991 if( osl_File_E_None != osl_removeFile(rFileName.pData) )
1025 bool bReload =
false;
1027 if( aUpdateHandler->isVisible() )
1029 bReload = aUpdateHandler->showOverwriteWarning( rFileName );
1043 aUpdateHandler->setErrorMessage(rErrorMessage);
1055 aUpdateHandler->setProgress(nPercent);
1063 if ( nFileSize > 0 )
1068 aModel->storeLocalFileName(rLocalFileName, nFileSize);
1072 if( !
aURL.isEmpty() )
1094 const OUString
aURL(
getReleaseNote(aUpdateInfo, 2, rModel->isAutoDownloadEnabled()));
1095 if( !
aURL.isEmpty() )
1110 OUString aLocalFile(rModel->getLocalFileName());
1111 rModel->clearLocalFileName();
1112 rModel->storeDownloadPaused(
false);
1114 if( isObsoleteUpdateInfo(rModel->getUpdateEntryVersion()) )
1116 rModel->clearUpdateFound();
1120 osl_removeFile(aLocalFile.pData);
1140 if( forceCheck || ! update_found )
1160 OSL_ASSERT(
false );
1209 OSL_ASSERT( rModel.is() );
1212 bool autoDownloadEnabled = rModel->isAutoDownloadEnabled();
1216 if( ((1 == elem.Pos) || (2 == elem.Pos)) && autoDownloadEnabled && !elem.URL2.isEmpty())
1218 elem.URL = elem.URL2;
1220 elem.Pos = elem.Pos2;
1226 rModel->updateLastChecked();
1231 rModel->storeUpdateFound(aInfo, getBuildId());
1237 if( rModel->isAutoDownloadEnabled() )
1250 rModel->clearUpdateFound();
1267 bool suppressBubble )
1269 uno::Reference<beans::XPropertySet> xMenuBarUI(
m_xMenuBarUI );
1279 if( xMenuBarUI.is() )
1290 if( ! suppressBubble && ( ! rUpdateHandler->isVisible() || rUpdateHandler->isMinimized() ) )
1316 suppressBubble =
true;
1321 OSL_ASSERT( aUpdateHandler.is() );
1334 uno::Reference< uno::XComponentContext > xContext(
m_xContext);
1336 OUString aDownloadDestination =
1339 osl_getSystemPathFromFileURL(aDownloadDestination.pData, &aDownloadDestination.pData);
1341 aUpdateHandler->setDownloadPath(aDownloadDestination);
1345 aUpdateHandler->setDownloadFile(aImageName);
1348 aUpdateHandler->setDescription(aUpdateInfo.
Description);
1349 aUpdateHandler->setNextVersion(aUpdateInfo.
Version);
1350 aUpdateHandler->setState(eState);
1359 if( !rInfo.
BuildId.isEmpty() )
1361 if( rInfo.
Sources[0].IsDirect )
1374 const uno::Reference< c3s::XSystemShellExecute > xShellExecute(
1375 c3s::SystemShellExecute::create(
m_xContext ) );
1378 xShellExecute->execute(rURL, OUString(), c3s::SystemShellExecuteFlags::URIS_ONLY);
1379 }
catch(
const c3s::SystemShellExecuteException&) {
1387 osl::FileBase::RC rc;
1390 osl::Directory::createPath( aTargetDir );
1392 OUString aFileName =
"releasenote" +
1393 OUString::number( nNum ) +
1397 rc = osl::FileBase::getAbsoluteFileURL( aTargetDir, aFileName, aFilePath );
1398 if ( rc != osl::FileBase::E_None )
return false;
1400 osl::File::remove( aFilePath );
1403 if ( rURL.isEmpty() )
1406 osl::File aFile( aFilePath );
1407 rc = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
1408 if ( rc != osl::FileBase::E_None )
return false;
1410 OString aLineBuf(
"[InternetShortcut]\r\n");
1411 sal_uInt64 nWritten = 0;
1413 OUString
aURL( rURL );
1415 rc = aFile.write( aLineBuf.getStr(), aLineBuf.getLength(), nWritten );
1416 if ( rc != osl::FileBase::E_None )
return false;
1417 aURL =
"URL=" + rURL;
1420 rc = aFile.write( aLineBuf.getStr(), aLineBuf.getLength(), nWritten );
1421 if ( rc != osl::FileBase::E_None )
return false;
1430 uno::Reference< uno::XInterface > xService;
1433 throw uno::RuntimeException(
1434 "UpdateCheck::showExtensionDialog(): empty component context", uno::Reference< uno::XInterface > () );
1436 uno::Reference< lang::XMultiComponentFactory > xServiceManager(
m_xContext->getServiceManager() );
1437 if( !xServiceManager.is() )
1438 throw uno::RuntimeException(
1439 "UpdateCheck::showExtensionDialog(): unable to obtain service manager from component context", uno::Reference< uno::XInterface > () );
1441 xService = xServiceManager->createInstanceWithContext(
"com.sun.star.deployment.ui.PackageManagerDialog",
m_xContext );
1442 uno::Reference< task::XJobExecutor > xExecutable( xService, uno::UNO_QUERY );
1443 if ( xExecutable.is() )
1444 xExecutable->trigger(
"SHOW_UPDATE_DIALOG" );
1460uno::Reference< task::XInteractionHandler >
1465 uno::Reference< task::XInteractionHandler > xHandler;
static OUString getAllUsersDirectory()
static ::rtl::Reference< UpdateCheckConfig > get(const css::uno::Reference< css::uno::XComponentContext > &xContext, const ::rtl::Reference< UpdateCheckConfigListener > &rListener=::rtl::Reference< UpdateCheckConfigListener >())
void getUpdateEntry(UpdateInfo &rInfo) const
OUString getUpdateEntryVersion() const
sal_Int64 getDownloadSize() const
OUString getLocalFileName() const
bool isDownloadPaused() const
bool isAutoCheckEnabled() const
void enableDownload(bool enable, bool paused=false)
rtl::Reference< UpdateHandler > getUpdateHandler()
void showDialog(bool forceCheck=false)
css::uno::Reference< css::beans::XPropertySet > m_xMenuBarUI
void enableAutoCheck(bool enable)
virtual ~UpdateCheck() override
virtual bool downloadTargetExists(const OUString &rFileName) override
bool m_bHasExtensionUpdate
virtual void downloadFinished(const OUString &rLocalFileName) override
virtual void downloadStarted(const OUString &rLocalFileName, sal_Int64 nFileSize) override
css::uno::Reference< css::task::XInteractionHandler > getInteractionHandler() const
void showReleaseNote(const OUString &rURL) const
bool isDialogShowing() const
void waitForUpdateCheckFinished()
void notifyUpdateCheckFinished()
void initialize(const css::uno::Sequence< css::beans::NamedValue > &rValues, const css::uno::Reference< css::uno::XComponentContext > &xContext)
std::recursive_mutex m_aMutex
void handleMenuBarUI(const rtl::Reference< UpdateHandler > &rUpdateHandler, UpdateState &eState, bool suppressBubble)
void setCheckFailedState()
static UpdateState getUIState(const UpdateInfo &rInfo)
virtual void downloadProgressAt(sal_Int8 nProcent) override
osl::Condition m_aCondition
virtual bool checkDownloadDestination(const OUString &rFile) override
std::condition_variable_any m_updateCheckFinished
void setUpdateInfo(const UpdateInfo &aInfo)
static bool storeReleaseNote(sal_Int8 nNum, const OUString &rURL)
void closeAfterFailure() override
rtl::Reference< UpdateHandler > m_aUpdateHandler
css::uno::Reference< css::uno::XComponentContext > m_xContext
UpdateState m_eUpdateState
virtual void autoCheckIntervalChanged() override
void shutdownThread(bool join)
virtual void autoCheckStatusChanged(bool enabled) override
void showExtensionDialog()
bool m_updateCheckRunning
void setUIState(UpdateState eState, bool suppressBubble=false)
virtual void downloadStalled(const OUString &rErrorMessage) override
#define SAL_CONFIGFILE(name)
#define TOOLS_WARN_EXCEPTION(area, stream)
Reference< XComponentContext > m_xContext
#define SAL_WARN(area, stream)
def run(arg=None, arg2=-1)
void SC_DLLPUBLIC join(const ScDocument *pDoc, ::std::vector< ScTokenRef > &rTokens, const ScTokenRef &pToken, const ScAddress &rPos)
std::shared_ptr< osl::Mutex > const & lock()
constexpr OUStringLiteral last
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
bool WNT_hasInternetConnection()
std::vector< DownloadSource > Sources
std::vector< ReleaseNote > ReleaseNotes
constexpr OUStringLiteral PROPERTY_TITLE
constexpr OUStringLiteral PROPERTY_TEXT
constexpr OUStringLiteral PROPERTY_CLICK_HDL
OUString getReleaseNote(const UpdateInfo &rInfo, sal_uInt8 pos, bool autoDownloadEnabled)
constexpr OUStringLiteral PROPERTY_SHOW_BUBBLE
constexpr OUStringLiteral PROPERTY_SHOW_MENUICON
@ UPDATESTATE_UPDATE_NO_DOWNLOAD
@ UPDATESTATE_ERROR_DOWNLOADING
@ UPDATESTATE_EXT_UPD_AVAIL
@ UPDATESTATE_DOWNLOAD_PAUSED
@ UPDATESTATE_ERROR_CHECKING
@ UPDATESTATE_DOWNLOAD_AVAIL
@ UPDATESTATE_NO_UPDATE_AVAIL
@ UPDATESTATE_UPDATE_AVAIL
@ UPDATESTATE_DOWNLOADING
bool checkForPendingUpdates(const uno::Reference< uno::XComponentContext > &rxContext)
bool checkForExtensionUpdates(const uno::Reference< uno::XComponentContext > &rxContext)
bool checkForUpdates(UpdateInfo &o_rUpdateInfo, uno::Reference< uno::XComponentContext > const &rxContext, uno::Reference< task::XInteractionHandler > const &rxInteractionHandler, const uno::Reference< deployment::XUpdateInformationProvider > &rUpdateInfoProvider)