LibreOffice Module extensions (master) 1
updatecheck.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <string_view>
23
25#include <config_folders.h>
26
27#include "updatecheck.hxx"
28
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>
39
40#include <rtl/bootstrap.hxx>
41#include <osl/process.h>
42#include <osl/file.hxx>
43#include <sal/macros.h>
44#include <sal/log.hxx>
46
47#ifdef _WIN32
49#include <objbase.h>
50#endif
51
52#include "onlinecheck.hxx"
53#include "updateprotocol.hxx"
54#include "updatecheckconfig.hxx"
55
56namespace beans = com::sun::star::beans ;
58namespace frame = com::sun::star::frame ;
59namespace lang = com::sun::star::lang ;
60namespace c3s = com::sun::star::system ;
61namespace task = com::sun::star::task ;
62namespace uno = com::sun::star::uno ;
63
64constexpr OUStringLiteral PROPERTY_TITLE = u"BubbleHeading";
65constexpr OUStringLiteral PROPERTY_TEXT = u"BubbleText";
66constexpr OUStringLiteral PROPERTY_SHOW_BUBBLE = u"BubbleVisible";
67constexpr OUStringLiteral PROPERTY_CLICK_HDL = u"MenuClickHDL";
68constexpr OUStringLiteral PROPERTY_SHOW_MENUICON = u"MenuIconVisible";
69
70// Returns the URL of the release note for the given position
71OUString getReleaseNote(const UpdateInfo& rInfo, sal_uInt8 pos, bool autoDownloadEnabled)
72{
73 for (auto const& elem : rInfo.ReleaseNotes)
74 {
75 if( pos == elem.Pos )
76 {
77 if( (pos > 2) || !autoDownloadEnabled || elem.URL2.isEmpty() )
78 return elem.URL;
79 }
80 else if( (pos == elem.Pos2) && ((1 == elem.Pos) || (2 == elem.Pos)) && autoDownloadEnabled )
81 return elem.URL2;
82 }
83
84 return OUString();
85}
86
87
88namespace
89{
90
91OUString getBuildId()
92{
93 OUString aPathVal("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}");
94 rtl::Bootstrap::expandMacros(aPathVal);
95 return aPathVal;
96}
97
98
99bool isObsoleteUpdateInfo(std::u16string_view rBuildId)
100{
101 return rBuildId != getBuildId() && !rBuildId.empty();
102}
103
104
105OUString getImageFromFileName(const OUString& aFile)
106{
107#ifndef _WIN32
108 OUString aUnpackPath;
109 if( osl_getExecutableFile(&aUnpackPath.pData) == osl_Process_E_None )
110 {
111 sal_uInt32 lastIndex = aUnpackPath.lastIndexOf('/');
112 if ( lastIndex > 0 )
113 {
114 aUnpackPath = OUString::Concat(aUnpackPath.subView( 0, lastIndex+1 )) +
115 "unpack_update";
116 }
117
118 oslFileHandle hOut = nullptr;
119 oslProcess hProcess = nullptr;
120
121 OUString aSystemPath;
122 osl::File::getSystemPathFromFileURL(aFile, aSystemPath);
123
124 oslProcessError rc = osl_executeProcess_WithRedirectedIO(
125 aUnpackPath.pData, // [in] Image name
126 &aSystemPath.pData, 1, // [in] Arguments
127 osl_Process_WAIT | osl_Process_NORMAL, // [in] Options
128 nullptr, // [in] Security
129 nullptr, // [in] Working directory
130 nullptr, 0, // [in] Environment variables
131 &hProcess, // [out] Process handle
132 nullptr, &hOut, nullptr // [out] File handles for redirected I/O
133 );
134
135 if( osl_Process_E_None == rc )
136 {
137 // Create a guard to ensure correct cleanup in its dtor in any case
138 comphelper::ScopeGuard g([hOut, hProcess] () {
139 osl_closeFile(hOut);
140 osl_freeProcessHandle(hProcess);
141 });
142
143 oslProcessInfo aInfo;
144 aInfo.Size = sizeof(oslProcessInfo);
145
146 if( osl_Process_E_None == osl_getProcessInfo(hProcess, osl_Process_EXITCODE, &aInfo) )
147 {
148 if( 0 == aInfo.Code )
149 {
150 char szBuffer[4096];
151 sal_uInt64 nBytesRead = 0;
152 const sal_uInt64 nBytesToRead = sizeof(szBuffer) - 1;
153
154 OUString aImageName;
155 while( osl_File_E_None == osl_readFile(hOut, szBuffer, nBytesToRead, &nBytesRead) )
156 {
157 char *pc = szBuffer + nBytesRead;
158 do
159 {
160 *pc = '\0'; --pc;
161 }
162 while( ('\n' == *pc) || ('\r' == *pc) );
163
164 aImageName += OUString(szBuffer, pc - szBuffer + 1, osl_getThreadTextEncoding());
165
166 if( nBytesRead < nBytesToRead )
167 break;
168 }
169
170 if( osl::FileBase::E_None == osl::FileBase::getFileURLFromSystemPath(aImageName, aImageName) )
171 return aImageName;
172 }
173 }
174 }
175 }
176#endif
177
178 return aFile;
179}
180
181
182uno::Reference< beans::XPropertySet > createMenuBarUI(
183 const uno::Reference< uno::XComponentContext >& xContext,
184 const uno::Reference< task::XJob >& xJob)
185{
186 if( !xContext.is() )
187 throw uno::RuntimeException(
188 "UpdateCheckJob: empty component context", uno::Reference< uno::XInterface > () );
189
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 > () );
194
195 uno::Reference< beans::XPropertySet > xMenuBarUI(
196 xServiceManager->createInstanceWithContext( "com.sun.star.setup.UpdateCheckUI", xContext ),
197 uno::UNO_QUERY_THROW);
198
199 xMenuBarUI->setPropertyValue( PROPERTY_CLICK_HDL, uno::Any( xJob ) );
200
201 return xMenuBarUI;
202}
203
204
205typedef sal_Bool (* OnlineCheckFunc) ();
206
207class UpdateCheckThread : public WorkerThread
208{
209
210public:
211 UpdateCheckThread( osl::Condition& rCondition,
212 const uno::Reference<uno::XComponentContext>& xContext,
213 rtl::Reference<UpdateCheck> const & controller );
214
215 virtual void SAL_CALL join() override;
216 virtual void SAL_CALL terminate() override;
217 virtual void cancel() override;
218
219 void cancelAsSoonAsPossible();
220
221protected:
222 virtual ~UpdateCheckThread() override;
223
224 virtual void SAL_CALL run() override;
225 virtual void SAL_CALL onTerminated() override;
226
227 /* Wrapper around checkForUpdates */
228 bool runCheck( bool & rbExtensionsChecked );
229
230private:
231
232 /* Used to avoid dialup login windows (on platforms we know how to double this) */
233 static bool hasInternetConnection()
234 {
235#ifdef _WIN32
237#else
238 return true;
239#endif
240 }
241
242 /* Creates a new instance of UpdateInformationProvider and returns this instance */
243 uno::Reference<deployment::XUpdateInformationProvider> createProvider()
244 {
245 osl::MutexGuard aGuard(m_aMutex);
246 m_xProvider = deployment::UpdateInformationProvider::create(m_xContext);
247 return m_xProvider;
248 };
249
250 /* Returns the remembered instance of UpdateInformationProvider if any */
251 uno::Reference<deployment::XUpdateInformationProvider> getProvider()
252 { osl::MutexGuard aGuard(m_aMutex); return m_xProvider; };
253
254 /* Releases the remembered instance of UpdateInformationProvider if any */
255 void clearProvider()
256 { osl::MutexGuard aGuard(m_aMutex); m_xProvider.clear(); };
257
258 osl::Mutex m_aMutex;
259
260protected:
261 osl::Condition& m_aCondition;
262
263private:
264 const uno::Reference<uno::XComponentContext> m_xContext;
265 uno::Reference<deployment::XUpdateInformationProvider> m_xProvider;
266 rtl::Reference<UpdateCheck> m_controller;
267 bool m_cancelAsSoonAsPossible;
268};
269
270
271class ManualUpdateCheckThread : public UpdateCheckThread
272{
273public:
274 ManualUpdateCheckThread( osl::Condition& rCondition, const uno::Reference<uno::XComponentContext>& xContext ) :
275 UpdateCheckThread(rCondition, xContext, {}) {};
276
277 virtual void SAL_CALL run() override;
278};
279
280
281class MenuBarButtonJob : public ::cppu::WeakImplHelper< task::XJob >
282{
283public:
284 explicit MenuBarButtonJob(const rtl::Reference< UpdateCheck >& rUpdateCheck);
285
286 // XJob
287 virtual uno::Any SAL_CALL execute(const uno::Sequence<beans::NamedValue>&) override;
288
289private:
290 rtl::Reference< UpdateCheck > m_aUpdateCheck;
291};
292
293class DownloadThread : public WorkerThread
294{
295public:
296 DownloadThread(
297 osl::Condition& rCondition,
298 const uno::Reference<uno::XComponentContext>& xContext,
300 const OUString& rURL );
301
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;
306
307protected:
308 virtual ~DownloadThread() override;
309
310private:
311 osl::Condition& m_aCondition;
312 const uno::Reference<uno::XComponentContext> m_xContext;
313 const OUString m_aURL;
314 Download m_aDownload;
315};
316
317
318
319UpdateCheckThread::UpdateCheckThread( osl::Condition& rCondition,
320 const uno::Reference<uno::XComponentContext>& xContext,
321 rtl::Reference<UpdateCheck> const & controller ) :
322 m_aCondition(rCondition),
323 m_xContext(xContext),
324 m_controller(controller),
325 m_cancelAsSoonAsPossible(false)
326{
327 createSuspended();
328
329 // actually run the thread
330 resume();
331}
332
333
334UpdateCheckThread::~UpdateCheckThread()
335{
336}
337
338
339void SAL_CALL
340UpdateCheckThread::terminate()
341{
342 // Cancel potentially hanging http request ..
343 cancel();
344 // .. before terminating
345 osl::Thread::terminate();
346}
347
348
349void SAL_CALL
350UpdateCheckThread::join()
351{
352 uno::Reference< deployment::XUpdateInformationProvider > xProvider(getProvider());
353
354 // do not join during an update check until #i73893# is fixed
355 if( ! xProvider.is() )
356 {
357 osl::Thread::join();
358 }
359}
360
361
362void
363UpdateCheckThread::cancel()
364{
365 uno::Reference< deployment::XUpdateInformationProvider > xProvider(getProvider());
366
367 if( xProvider.is() )
368 xProvider->cancel();
369}
370
371void UpdateCheckThread::cancelAsSoonAsPossible() {
372 {
373 osl::MutexGuard g(m_aMutex);
374 m_cancelAsSoonAsPossible = true;
375 }
376 m_aCondition.set();
377}
378
379bool
380UpdateCheckThread::runCheck( bool & rbExtensionsChecked )
381{
382 bool ret = false;
384
385 UpdateInfo aInfo;
386 rtl::Reference< UpdateCheck > aController(UpdateCheck::get());
387
388 if( checkForUpdates(aInfo, m_xContext, aController->getInteractionHandler(), createProvider()) )
389 {
390 aController->setUpdateInfo(aInfo);
391 eUIState = UpdateCheck::getUIState(aInfo);
392 ret = true;
393 }
394 else
395 aController->setCheckFailedState();
396
397 // We will only look for extension updates, when there is no 'check for office updates' dialog open
398 // and when there was no office update found
399 if ( ( eUIState != UPDATESTATE_UPDATE_AVAIL ) &&
400 ( eUIState != UPDATESTATE_UPDATE_NO_DOWNLOAD ) &&
401 !aController->isDialogShowing() &&
402 !rbExtensionsChecked )
403 {
404 bool bHasExtensionUpdates = checkForExtensionUpdates( m_xContext );
405 aController->setHasExtensionUpdates( bHasExtensionUpdates );
406 if ( bHasExtensionUpdates )
407 aController->setUIState( UPDATESTATE_EXT_UPD_AVAIL );
408 rbExtensionsChecked = true;
409 }
410
411 // joining with this thread is safe again
412 clearProvider();
413 return ret;
414}
415
416
417void SAL_CALL
418UpdateCheckThread::onTerminated()
419{
420 delete this;
421}
422
423
424void SAL_CALL
425UpdateCheckThread::run()
426{
427 osl_setThreadName("UpdateCheckThread");
428
429 TimeValue systime;
430 TimeValue nExtCheckTime;
431 osl_getSystemTime( &nExtCheckTime );
432
433 osl::Condition::Result aResult = osl::Condition::result_timeout;
434 TimeValue tv = { 10, 0 };
435
436 // Initial wait to avoid doing further time consuming tasks during start-up
437 aResult = m_aCondition.wait(&tv);
438 {
439 osl::MutexGuard g(m_aMutex);
440 if (m_cancelAsSoonAsPossible) {
441 goto done;
442 }
443 }
444
445 try {
446 bool bExtensionsChecked = false;
447
448 while( schedule() )
449 {
450 /* Use cases:
451 * a) manual check requested from auto check thread - "last check" should not be checked (one time)
452 * a1) manual check was requested in the middle of a running auto check,
453 * condition is set
454 * a2) manual check was requested while waiting for a retry,
455 * condition is set
456 * a3) manual check was requested while waiting for time to next
457 * scheduled check elapsing, condition is set
458 * a4) manual check was requested during initial wait, condition is set
459 * b) check interval got changed, condition may be set - same sub-cases as a),
460 * but "last check" should be honored
461 * c) normal auto check mode, condition not set - "last check" should be honored
462 */
463
464 // Accessing const members without synchronization
465 rtl::Reference< UpdateCheck > aController(UpdateCheck::get());
467
468 // FIXME: remember last & offset ?
469 sal_Int64 last = rModel->getLastChecked();
470 sal_Int64 offset = rModel->getCheckInterval();
471
472 rModel.clear();
473
474 // last == 0 means check immediately
475 bool checkNow = last <= 0;
476
477 // Reset the condition to avoid busy loops
478 if( osl::Condition::result_ok == aResult )
479 {
480 m_aCondition.reset();
481 aResult = osl::Condition::result_timeout;
482 checkNow = aController->isDialogShowing();
483 }
484
485 if( ! checkNow )
486 {
487 osl_getSystemTime(&systime);
488
489 // Go back to sleep until time has elapsed
490 sal_Int64 next = last + offset;
491 if( last + offset > systime.Seconds )
492 {
493 // This can not be > 32 Bit for now ..
494 tv.Seconds = static_cast< sal_Int32 > (next - systime.Seconds);
495 aResult = m_aCondition.wait(&tv);
496 {
497 osl::MutexGuard g(m_aMutex);
498 if (m_cancelAsSoonAsPossible) {
499 goto done;
500 }
501 }
502 continue;
503 }
504 }
505
506 static sal_uInt8 n = 0;
507
508 if( ! hasInternetConnection() || ! runCheck( bExtensionsChecked ) )
509 {
510 // the extension update check should be independent from the office update check
511
512 osl_getSystemTime( &systime );
513 if ( nExtCheckTime.Seconds + offset < systime.Seconds )
514 bExtensionsChecked = false;
515
516 // Increase next by 15, 60, .. minutes
517 static const sal_Int32 nRetryInterval[] = { 900, 3600, 14400, 86400 };
518
519 if( n < std::size(nRetryInterval) )
520 ++n;
521
522 tv.Seconds = nRetryInterval[n-1];
523 aResult = m_aCondition.wait(&tv);
524 {
525 osl::MutexGuard g(m_aMutex);
526 if (m_cancelAsSoonAsPossible) {
527 goto done;
528 }
529 }
530 }
531 else // reset retry counter
532 {
533 n = 0;
534 bExtensionsChecked = false;
535 }
536 }
537 }
538
539 catch(const uno::Exception&) {
540 // Silently catch all errors
541 TOOLS_WARN_EXCEPTION("extensions.update", "Caught exception, thread terminated" );
542 }
543
544done:
545 if (m_controller.is()) {
546 m_controller->notifyUpdateCheckFinished();
547 }
548}
549
550
551void SAL_CALL
552ManualUpdateCheckThread::run()
553{
554 try {
555 bool bExtensionsChecked = false;
556 runCheck( bExtensionsChecked );
557 m_aCondition.reset();
558 }
559 catch(const uno::Exception&) {
560 // Silently catch all errors
561 TOOLS_WARN_EXCEPTION("extensions.update", "Caught exception, thread terminated" );
562 }
563}
564
565
566MenuBarButtonJob::MenuBarButtonJob(const rtl::Reference< UpdateCheck >& rUpdateCheck) :
567 m_aUpdateCheck(rUpdateCheck)
568{
569};
570
571
572uno::Any SAL_CALL
573MenuBarButtonJob::execute(const uno::Sequence<beans::NamedValue>& )
574{
575 if ( m_aUpdateCheck->shouldShowExtUpdDlg() )
576 m_aUpdateCheck->showExtensionDialog();
577 else
578 m_aUpdateCheck->showDialog();
579
580 return uno::Any();
581}
582
583
584DownloadThread::DownloadThread(osl::Condition& rCondition,
585 const uno::Reference<uno::XComponentContext>& xContext,
587 const OUString& rURL) :
588 m_aCondition(rCondition),
589 m_xContext(xContext),
590 m_aURL(rURL),
591 m_aDownload(xContext, rHandler)
592{
593 createSuspended();
594}
595
596
597DownloadThread::~DownloadThread()
598{
599}
600
601
602void SAL_CALL
603DownloadThread::run()
604{
605 osl_setThreadName("DownloadThread");
606
607#ifdef _WIN32
608 int nNbCallCoInitializeExForReinit = 0;
609 // for SystemShellExecute
610 o3tl::safeCoInitializeEx(COINIT_APARTMENTTHREADED, nNbCallCoInitializeExForReinit);
611#endif
612
613 while( schedule() )
614 {
616
617 OUString aLocalFile = rModel->getLocalFileName();
618 OUString aDownloadDest = rModel->getDownloadDestination();
619
620 // release config class for now
621 rModel.clear();
622
623 static sal_uInt8 n = 0;
624 if( ! m_aDownload.start(m_aURL, aLocalFile, aDownloadDest ) )
625 {
626 // retry every 15s unless the dialog is not visible
627 TimeValue tv(15, 0);
628
629 if( ! UpdateCheck::get()->isDialogShowing() )
630 {
631 // Increase next by 1, 5, 15, 60, .. minutes
632 static const sal_Int16 nRetryInterval[] = { 60, 300, 900, 3600 };
633
634 if( n < std::size(nRetryInterval) )
635 ++n;
636
637 tv.Seconds = nRetryInterval[n-1];
638 }
639 m_aCondition.wait(&tv);
640 }
641 else
642 {
643 // reset wait period after successful download
644 n=0;
645 }
646 }
647#ifdef _WIN32
648 o3tl::safeCoUninitializeReinit(COINIT_MULTITHREADED, nNbCallCoInitializeExForReinit);
649#endif
650}
651
652
653void DownloadThread::cancel()
654{
655 m_aDownload.stop();
656 resume();
657
658 rtl::Reference< UpdateCheck > aController(UpdateCheck::get());
659 aController->cancelDownload();
660}
661
662
663void SAL_CALL DownloadThread::suspend()
664{
665 osl::Thread::suspend();
666 m_aDownload.stop();
667}
668
669
670void SAL_CALL DownloadThread::onTerminated()
671{
672 delete this;
673}
674
675
676} // anonymous namespace
677
679 : m_eState(NOT_INITIALIZED)
680 , m_eUpdateState(UPDATESTATES_COUNT)
681 , m_pThread(nullptr)
682 , m_bHasExtensionUpdate(false)
683 , m_bShowExtUpdDlg(false)
684 , m_updateCheckRunning(false)
685{
686}
687
689
690void
691UpdateCheck::initialize(const uno::Sequence< beans::NamedValue >& rValues,
692 const uno::Reference<uno::XComponentContext>& xContext)
693{
694 std::scoped_lock aGuard(m_aMutex);
695
697 {
698 NamedValueByNameAccess aNameAccess(rValues);
699 UpdateCheckROModel aModel( aNameAccess );
700 m_xContext = xContext;
701
702 OUString aUpdateEntryVersion = aModel.getUpdateEntryVersion();
703
705
706 bool obsoleteUpdateInfo = isObsoleteUpdateInfo(aUpdateEntryVersion);
707 bool bContinueDownload = false;
708 bool bDownloadAvailable = false;
709
711 m_bShowExtUpdDlg = false;
712
713 OUString aLocalFileName = aModel.getLocalFileName();
714
715 if( !aLocalFileName.isEmpty() )
716 {
717 bContinueDownload = true;
718
719 // Try to get the number of bytes already on disk
720 osl::DirectoryItem aDirectoryItem;
721 if( osl::DirectoryItem::E_None == osl::DirectoryItem::get(aLocalFileName, aDirectoryItem) )
722 {
723 osl::FileStatus aFileStatus(osl_FileStatus_Mask_FileSize);
724 if( osl::DirectoryItem::E_None == aDirectoryItem.getFileStatus(aFileStatus) )
725 {
726 sal_Int64 nDownloadSize = aModel.getDownloadSize();
727 sal_Int64 nFileSize = aFileStatus.getFileSize();
728
729 if( nDownloadSize > 0 )
730 {
731 if ( nDownloadSize <= nFileSize ) // we have already downloaded everything
732 {
733 bContinueDownload = false;
734 bDownloadAvailable = true;
735 m_aImageName = getImageFromFileName( aLocalFileName );
736 }
737 else // Calculate initial percent value.
738 {
739 sal_Int32 nPercent = static_cast<sal_Int32>(100 * nFileSize / nDownloadSize);
740 getUpdateHandler()->setProgress( nPercent );
741 }
742 }
743 }
744 }
745
746 if ( bContinueDownload )
747 {
748 bool downloadPaused = aModel.isDownloadPaused();
749
750 enableDownload(true, downloadPaused);
751 // coverity[lock_order : FALSE] - incorrect report of lock order error with std::recursive_mutex
753 }
754
755 }
756 if ( !bContinueDownload )
757 {
758 // We do this intentionally only if no download is in progress ..
759 if( obsoleteUpdateInfo )
760 {
761 // Bring-up release note for position 5 ..
762 const OUString aURL(getReleaseNote(m_aUpdateInfo, 5));
763 if( !aURL.isEmpty() )
765
766 // Data is outdated, probably due to installed update
768 aConfig->clearUpdateFound();
769 aConfig->clearLocalFileName();
770
771
773 // Remove outdated release notes
774 storeReleaseNote( 1, OUString() );
775 storeReleaseNote( 2, OUString() );
776 }
777 else
778 {
780 if ( bDownloadAvailable )
782 else
783 {
784 // coverity[lock_order : FALSE] - incorrect report of lock order error with std::recursive_mutex
786 }
787 }
788 }
789 }
790}
791
792
793void
795{
796 std::unique_lock aGuard(m_aMutex);
797
798 WorkerThread *pThread = m_pThread;
800
801 aGuard.unlock();
802
803 if( nullptr != pThread )
804 pThread->cancel();
805
806 setUIState(eUIState);
807}
808
809
810void
812{
813 std::unique_lock aGuard(m_aMutex);
815 State eState = m_eState;
816 aGuard.unlock();
817
818 if (aInfo.Sources.empty())
819 {
820 SAL_WARN("extensions.update", "download called without source");
821 return;
822 }
823
824 if( aInfo.Sources[0].IsDirect )
825 {
826 // Ignore second click of a double click
827 if( DOWNLOADING != eState )
828 {
829 shutdownThread(true);
830
831 {
832 std::scoped_lock aGuard2(m_aMutex);
833 enableDownload(true);
834 }
836 }
837 }
838 else
839 {
840 showReleaseNote(aInfo.Sources[0].URL); // Display in browser
841 }
842}
843
844
845void
847{
848 std::unique_lock aGuard(m_aMutex);
849
850 if( nullptr != m_pThread )
851 m_pThread->suspend();
852
854 aGuard.unlock();
855
856 rModel->storeDownloadPaused(true);
858}
859
860
861void
863{
864 std::unique_lock aGuard(m_aMutex);
865
866 if( nullptr != m_pThread )
867 m_pThread->resume();
868
870 aGuard.unlock();
871
872 rModel->storeDownloadPaused(false);
874}
875
876
877void
879{
880 std::unique_lock aGuard(m_aMutex);
881
882 if ( ( m_eState == DISABLED ) || ( m_eState == CHECK_SCHEDULED ) )
883 {
884 const UpdateState eUIState = getUIState( m_aUpdateInfo );
885 aGuard.unlock();
886 setUIState( eUIState, true );
887 }
888}
889
891 std::scoped_lock l(m_aMutex);
892 m_updateCheckRunning = false;
893 m_updateCheckFinished.notify_all();
894}
895
897 UpdateCheckThread * thread;
898 {
899 std::scoped_lock l(m_aMutex);
900 thread = dynamic_cast<UpdateCheckThread *>(m_pThread);
901 }
902 if (thread != nullptr) {
903 thread->cancelAsSoonAsPossible();
904 }
905 for (;;) {
906 std::unique_lock lock(m_aMutex);
908 return;
909 }
911 }
912}
913
914void
916{
917 std::unique_lock aGuard(m_aMutex);
918
919 // copy thread object pointer to stack
920 osl::Thread *pThread = m_pThread;
921 m_pThread = nullptr;
922 aGuard.unlock();
923
924 if( nullptr != pThread )
925 {
926 pThread->terminate();
927 if( join )
928 {
929 m_aCondition.set();
930 pThread->join();
931 m_aCondition.reset();
932 }
933 }
934}
935
936
937void
939{
940 if( enable )
941 {
943 m_pThread = new UpdateCheckThread(m_aCondition, m_xContext, this);
944 }
945
946 m_eState = enable ? CHECK_SCHEDULED : DISABLED;
947}
948
949
950void
951UpdateCheck::enableDownload(bool enable, bool paused)
952{
953 OSL_ASSERT(nullptr == m_pThread);
954
955 if( enable )
956 {
957 m_pThread = new DownloadThread(m_aCondition, m_xContext, this, m_aUpdateInfo.Sources[0].URL );
958 State eState = DISABLED;
959 if( !paused )
960 {
961 eState = DOWNLOADING;
962 m_pThread->resume();
963 }
964 else
965 eState = DOWNLOAD_PAUSED;
966
967 m_eState = eState;
968 }
969 else {
970 enableAutoCheck(UpdateCheckConfig::get(m_xContext)->isAutoCheckEnabled());
971 }
972
973}
974
975
976bool
977UpdateCheck::downloadTargetExists(const OUString& rFileName)
978{
979 std::unique_lock aGuard(m_aMutex);
980
983
984 bool cont = false;
985
986 if( aUpdateHandler->isVisible() )
987 {
988 cont = aUpdateHandler->showOverwriteWarning();
989 if( cont )
990 {
991 if( osl_File_E_None != osl_removeFile(rFileName.pData) )
992 {
993 // FIXME: error message
994 cont = false;
995 }
996 }
997 else
998 eUIState = getUIState(m_aUpdateInfo);
999 }
1000 else
1001 {
1002 m_aImageName = getImageFromFileName(rFileName);
1003 eUIState = UPDATESTATE_DOWNLOAD_AVAIL;
1004 }
1005
1006 if( !cont )
1007 {
1008 shutdownThread(false);
1009 enableDownload(false);
1010
1011 aGuard.unlock();
1012 setUIState(eUIState);
1013 }
1014
1015 return cont;
1016}
1017
1018
1019bool UpdateCheck::checkDownloadDestination( const OUString& rFileName )
1020{
1021 std::scoped_lock aGuard(m_aMutex);
1022
1024
1025 bool bReload = false;
1026
1027 if( aUpdateHandler->isVisible() )
1028 {
1029 bReload = aUpdateHandler->showOverwriteWarning( rFileName );
1030 }
1031
1032 return bReload;
1033}
1034
1035
1036void
1037UpdateCheck::downloadStalled(const OUString& rErrorMessage)
1038{
1039 std::unique_lock aGuard(m_aMutex);
1041 aGuard.unlock();
1042
1043 aUpdateHandler->setErrorMessage(rErrorMessage);
1045}
1046
1047
1048void
1050{
1051 std::unique_lock aGuard(m_aMutex);
1053 aGuard.unlock();
1054
1055 aUpdateHandler->setProgress(nPercent);
1057}
1058
1059
1060void
1061UpdateCheck::downloadStarted(const OUString& rLocalFileName, sal_Int64 nFileSize)
1062{
1063 if ( nFileSize > 0 )
1064 {
1065 std::scoped_lock aGuard(m_aMutex);
1066
1068 aModel->storeLocalFileName(rLocalFileName, nFileSize);
1069
1070 // Bring-up release note for position 1 ..
1071 const OUString aURL(getReleaseNote(m_aUpdateInfo, 1, aModel->isAutoDownloadEnabled()));
1072 if( !aURL.isEmpty() )
1074 }
1075}
1076
1077
1078void
1079UpdateCheck::downloadFinished(const OUString& rLocalFileName)
1080{
1081 std::unique_lock aGuard(m_aMutex);
1082
1083 // no more retries
1084 m_pThread->terminate();
1085
1086 m_aImageName = getImageFromFileName(rLocalFileName);
1087 UpdateInfo aUpdateInfo(m_aUpdateInfo);
1088
1089 aGuard.unlock();
1091
1092 // Bring-up release note for position 2 ..
1094 const OUString aURL(getReleaseNote(aUpdateInfo, 2, rModel->isAutoDownloadEnabled()));
1095 if( !aURL.isEmpty() )
1097}
1098
1099
1100void
1102{
1103 shutdownThread(true);
1104
1105 std::scoped_lock aGuard(m_aMutex);
1106 enableDownload(false);
1107
1109
1110 OUString aLocalFile(rModel->getLocalFileName());
1111 rModel->clearLocalFileName();
1112 rModel->storeDownloadPaused(false);
1113
1114 if( isObsoleteUpdateInfo(rModel->getUpdateEntryVersion()) )
1115 {
1116 rModel->clearUpdateFound(); // This wasn't done during init yet ..
1118 }
1119
1120 /*oslFileError rc =*/ osl_removeFile(aLocalFile.pData);
1121 // FIXME: error handling ..
1122
1123}
1124
1125
1126void
1128{
1129 std::unique_lock aGuard(m_aMutex);
1130
1131 bool update_found = !m_aUpdateInfo.BuildId.isEmpty();
1132 bool bSetUIState = ! m_aUpdateHandler.is();
1133
1134 UpdateState eDialogState = UPDATESTATES_COUNT;
1135
1136 switch( m_eState )
1137 {
1138 case DISABLED:
1139 case CHECK_SCHEDULED:
1140 if( forceCheck || ! update_found ) // Run check when forced or if we did not find an update yet
1141 {
1142 eDialogState = UPDATESTATE_CHECKING;
1143 bSetUIState = true;
1144 }
1145 else if(m_aUpdateInfo.Sources[0].IsDirect)
1146 eDialogState = UPDATESTATE_UPDATE_AVAIL;
1147 else
1148 eDialogState = UPDATESTATE_UPDATE_NO_DOWNLOAD;
1149 break;
1150
1151 case DOWNLOADING:
1152 eDialogState = UPDATESTATE_DOWNLOADING;
1153 break;
1154
1155 case DOWNLOAD_PAUSED:
1156 eDialogState = UPDATESTATE_DOWNLOAD_PAUSED;
1157 break;
1158
1159 case NOT_INITIALIZED:
1160 OSL_ASSERT( false );
1161 break;
1162 }
1163
1164 if( bSetUIState )
1165 {
1166 aGuard.unlock();
1167 setUIState(eDialogState, true); // suppress bubble as Dialog will be visible soon
1168 aGuard.lock();
1169 }
1170
1171 getUpdateHandler()->setVisible();
1172
1173 // Run check in separate thread ..
1174 if( UPDATESTATE_CHECKING == eDialogState )
1175 {
1176 if( DISABLED == m_eState )
1177 {
1178 // destructs itself when done, not cancellable for now ..
1179 new ManualUpdateCheckThread(m_aCondition, m_xContext);
1180 }
1181
1182 m_aCondition.set();
1183 }
1184}
1185
1186
1187void
1189{
1190 std::unique_lock aGuard(m_aMutex);
1191
1192 bool bSuppressBubble = aInfo.BuildId == m_aUpdateInfo.BuildId;
1193 m_aUpdateInfo = aInfo;
1194
1195 OSL_ASSERT(DISABLED == m_eState || CHECK_SCHEDULED == m_eState);
1196
1197 // Ignore leading non direct download if we get direct ones
1198 std::vector< DownloadSource >::iterator iter = std::find_if(m_aUpdateInfo.Sources.begin(), m_aUpdateInfo.Sources.end(),
1199 [](const DownloadSource& rSource) { return rSource.IsDirect; });
1200
1201 if( (iter != m_aUpdateInfo.Sources.begin()) &&
1202 (iter != m_aUpdateInfo.Sources.end()) &&
1203 iter->IsDirect )
1204 {
1205 m_aUpdateInfo.Sources.erase(m_aUpdateInfo.Sources.begin(), --iter);
1206 }
1207
1209 OSL_ASSERT( rModel.is() );
1210
1211 // Decide whether to use alternate release note pos ..
1212 bool autoDownloadEnabled = rModel->isAutoDownloadEnabled();
1213
1214 for (auto & elem : m_aUpdateInfo.ReleaseNotes)
1215 {
1216 if( ((1 == elem.Pos) || (2 == elem.Pos)) && autoDownloadEnabled && !elem.URL2.isEmpty())
1217 {
1218 elem.URL = elem.URL2;
1219 elem.URL2.clear();
1220 elem.Pos = elem.Pos2;
1221 elem.Pos2 = 0;
1222 }
1223 }
1224
1225 // do not move below store/clear ..
1226 rModel->updateLastChecked();
1227
1228 UpdateState eUIState;
1229 if( !m_aUpdateInfo.Sources.empty() )
1230 {
1231 rModel->storeUpdateFound(aInfo, getBuildId());
1232
1233 if( m_aUpdateInfo.Sources[0].IsDirect )
1234 {
1235 eUIState = UPDATESTATE_UPDATE_AVAIL;
1236
1237 if( rModel->isAutoDownloadEnabled() )
1238 {
1239 shutdownThread(false);
1240 eUIState = UPDATESTATE_DOWNLOADING;
1241 enableDownload(true);
1242 }
1243 }
1244 else
1246 }
1247 else
1248 {
1249 eUIState = UPDATESTATE_NO_UPDATE_AVAIL;
1250 rModel->clearUpdateFound();
1251 }
1252
1253 aGuard.unlock();
1254 setUIState(eUIState, bSuppressBubble);
1255}
1256
1257
1258void
1260{
1262}
1263
1264
1266 UpdateState& eState,
1267 bool suppressBubble )
1268{
1269 uno::Reference<beans::XPropertySet> xMenuBarUI( m_xMenuBarUI );
1270
1273
1274 if ( UPDATESTATE_EXT_UPD_AVAIL == eState )
1275 m_bShowExtUpdDlg = true;
1276 else
1277 m_bShowExtUpdDlg = false;
1278
1279 if( xMenuBarUI.is() )
1280 {
1281 if( UPDATESTATE_NO_UPDATE_AVAIL == eState )
1282 {
1283 xMenuBarUI->setPropertyValue( PROPERTY_SHOW_MENUICON, uno::Any(false) );
1284 }
1285 else
1286 {
1287 xMenuBarUI->setPropertyValue( PROPERTY_TITLE, uno::Any(rUpdateHandler->getBubbleTitle(eState)) );
1288 xMenuBarUI->setPropertyValue( PROPERTY_TEXT, uno::Any(rUpdateHandler->getBubbleText(eState)) );
1289
1290 if( ! suppressBubble && ( ! rUpdateHandler->isVisible() || rUpdateHandler->isMinimized() ) )
1291 xMenuBarUI->setPropertyValue( PROPERTY_SHOW_BUBBLE, uno::Any( true ) );
1292
1293 if( UPDATESTATE_CHECKING != eState )
1294 xMenuBarUI->setPropertyValue( PROPERTY_SHOW_MENUICON, uno::Any(true) );
1295 }
1296 }
1297}
1298
1299
1300void UpdateCheck::setUIState(UpdateState eState, bool suppressBubble)
1301{
1302 std::unique_lock aGuard(m_aMutex);
1303
1304 if( ! m_xMenuBarUI.is() &&
1305 (DISABLED != m_eState) &&
1307 (UPDATESTATE_CHECKING != eState) &&
1308 (UPDATESTATE_ERROR_CHECKING != eState)
1309 )
1310 {
1311 m_xMenuBarUI = createMenuBarUI(m_xContext, new MenuBarButtonJob(this));
1312 }
1313
1314 // Show bubble only when the status has changed
1315 if ( eState == m_eUpdateState )
1316 suppressBubble = true;
1317 else
1318 m_eUpdateState = eState;
1319
1321 OSL_ASSERT( aUpdateHandler.is() );
1322
1323 UpdateInfo aUpdateInfo(m_aUpdateInfo);
1324 OUString aImageName(m_aImageName);
1325
1326 aGuard.unlock();
1327
1328 handleMenuBarUI( aUpdateHandler, eState, suppressBubble );
1329
1330 if( (UPDATESTATE_UPDATE_AVAIL == eState)
1331 || (UPDATESTATE_DOWNLOAD_PAUSED == eState)
1332 || (UPDATESTATE_DOWNLOADING == eState) )
1333 {
1334 uno::Reference< uno::XComponentContext > xContext(m_xContext);
1335
1336 OUString aDownloadDestination =
1337 UpdateCheckConfig::get(xContext, this)->getDownloadDestination();
1338
1339 osl_getSystemPathFromFileURL(aDownloadDestination.pData, &aDownloadDestination.pData);
1340
1341 aUpdateHandler->setDownloadPath(aDownloadDestination);
1342 }
1343 else if( UPDATESTATE_DOWNLOAD_AVAIL == eState )
1344 {
1345 aUpdateHandler->setDownloadFile(aImageName);
1346 }
1347
1348 aUpdateHandler->setDescription(aUpdateInfo.Description);
1349 aUpdateHandler->setNextVersion(aUpdateInfo.Version);
1350 aUpdateHandler->setState(eState);
1351}
1352
1353
1356{
1358
1359 if( !rInfo.BuildId.isEmpty() )
1360 {
1361 if( rInfo.Sources[0].IsDirect )
1362 eUIState = UPDATESTATE_UPDATE_AVAIL;
1363 else
1365 }
1366
1367 return eUIState;
1368}
1369
1370
1371void
1372UpdateCheck::showReleaseNote(const OUString& rURL) const
1373{
1374 const uno::Reference< c3s::XSystemShellExecute > xShellExecute(
1375 c3s::SystemShellExecute::create( m_xContext ) );
1376
1377 try {
1378 xShellExecute->execute(rURL, OUString(), c3s::SystemShellExecuteFlags::URIS_ONLY);
1379 } catch(const c3s::SystemShellExecuteException&) {
1380 }
1381}
1382
1383
1384bool
1385UpdateCheck::storeReleaseNote(sal_Int8 nNum, const OUString &rURL)
1386{
1387 osl::FileBase::RC rc;
1388 OUString aTargetDir( UpdateCheckConfig::getAllUsersDirectory() + "/sun" );
1389
1390 osl::Directory::createPath( aTargetDir );
1391
1392 OUString aFileName = "releasenote" +
1393 OUString::number( nNum ) +
1394 ".url";
1395
1396 OUString aFilePath;
1397 rc = osl::FileBase::getAbsoluteFileURL( aTargetDir, aFileName, aFilePath );
1398 if ( rc != osl::FileBase::E_None ) return false;
1399
1400 osl::File::remove( aFilePath );
1401
1402 // don't store empty release notes, but delete old ones
1403 if ( rURL.isEmpty() )
1404 return true;
1405
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;
1409
1410 OString aLineBuf("[InternetShortcut]\r\n");
1411 sal_uInt64 nWritten = 0;
1412
1413 OUString aURL( rURL );
1414#ifdef _WIN32
1415 rc = aFile.write( aLineBuf.getStr(), aLineBuf.getLength(), nWritten );
1416 if ( rc != osl::FileBase::E_None ) return false;
1417 aURL = "URL=" + rURL;
1418#endif
1419 aLineBuf = OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 );
1420 rc = aFile.write( aLineBuf.getStr(), aLineBuf.getLength(), nWritten );
1421 if ( rc != osl::FileBase::E_None ) return false;
1422
1423 aFile.close();
1424 return true;
1425}
1426
1427
1429{
1430 uno::Reference< uno::XInterface > xService;
1431
1432 if( ! m_xContext.is() )
1433 throw uno::RuntimeException(
1434 "UpdateCheck::showExtensionDialog(): empty component context", uno::Reference< uno::XInterface > () );
1435
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 > () );
1440
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" );
1445}
1446
1447
1450{
1451 std::scoped_lock aGuard(m_aMutex);
1452
1453 if( ! m_aUpdateHandler.is() )
1455
1456 return m_aUpdateHandler;
1457}
1458
1459
1460uno::Reference< task::XInteractionHandler >
1462{
1463 std::scoped_lock aGuard(m_aMutex);
1464
1465 uno::Reference< task::XInteractionHandler > xHandler;
1466
1467 if( m_aUpdateHandler.is() && m_aUpdateHandler->isVisible() )
1468 xHandler = m_aUpdateHandler.get();
1469
1470 return xHandler;
1471}
1472
1473
1474bool
1476{
1477 std::scoped_lock aGuard(m_aMutex);
1478 return m_aUpdateHandler.is() && m_aUpdateHandler->isVisible();
1479};
1480
1481
1482void
1484{
1485 std::unique_lock aGuard(m_aMutex);
1486
1487 if( (CHECK_SCHEDULED == m_eState) && !enabled )
1488 shutdownThread(false);
1489
1490 if( (DISABLED == m_eState) || (CHECK_SCHEDULED == m_eState) )
1491 {
1492 enableAutoCheck(enabled);
1494 aGuard.unlock();
1495 setUIState(eState);
1496 }
1497};
1498
1499
1500void
1502{
1503 // just wake-up
1504 m_aCondition.set();
1505};
1506
1507/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool paused
css::util::URL m_aURL
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)
WorkerThread * m_pThread
css::uno::Reference< css::beans::XPropertySet > m_xMenuBarUI
void enableAutoCheck(bool enable)
void download() override
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
OUString m_aImageName
void waitForUpdateCheckFinished()
UpdateInfo m_aUpdateInfo
void notifyUpdateCheckFinished()
void initialize(const css::uno::Sequence< css::beans::NamedValue > &rValues, const css::uno::Reference< css::uno::XComponentContext > &xContext)
void cancel() override
std::recursive_mutex m_aMutex
void handleMenuBarUI(const rtl::Reference< UpdateHandler > &rUpdateHandler, UpdateState &eState, bool suppressBubble)
void cancelDownload()
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)
void pause() override
bool m_bShowExtUpdDlg
void resume() override
virtual void downloadStalled(const OUString &rErrorMessage) override
virtual void cancel()=0
#define SAL_CONFIGFILE(name)
#define TOOLS_WARN_EXCEPTION(area, stream)
URL aURL
float u
Reference< XComponentContext > m_xContext
Definition: filehandler.cxx:78
sal_Int64 n
#define SAL_WARN(area, stream)
::osl::Mutex m_aMutex
Definition: logger.cxx:98
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()
Definition: onlinecheck.cxx:30
std::vector< DownloadSource > Sources
Definition: updateinfo.hxx:54
OUString BuildId
Definition: updateinfo.hxx:51
OUString Version
Definition: updateinfo.hxx:52
std::vector< ReleaseNote > ReleaseNotes
Definition: updateinfo.hxx:55
OUString Description
Definition: updateinfo.hxx:53
unsigned char sal_uInt8
unsigned char sal_Bool
signed char sal_Int8
constexpr OUStringLiteral PROPERTY_TITLE
Definition: updatecheck.cxx:64
constexpr OUStringLiteral PROPERTY_TEXT
Definition: updatecheck.cxx:65
constexpr OUStringLiteral PROPERTY_CLICK_HDL
Definition: updatecheck.cxx:67
OUString getReleaseNote(const UpdateInfo &rInfo, sal_uInt8 pos, bool autoDownloadEnabled)
Definition: updatecheck.cxx:71
constexpr OUStringLiteral PROPERTY_SHOW_BUBBLE
Definition: updatecheck.cxx:66
constexpr OUStringLiteral PROPERTY_SHOW_MENUICON
Definition: updatecheck.cxx:68
UpdateState
Definition: updatehdl.hxx:57
@ UPDATESTATE_UPDATE_NO_DOWNLOAD
Definition: updatehdl.hxx:62
@ UPDATESTATE_ERROR_DOWNLOADING
Definition: updatehdl.hxx:66
@ UPDATESTATE_CHECKING
Definition: updatehdl.hxx:58
@ UPDATESTATE_EXT_UPD_AVAIL
Definition: updatehdl.hxx:68
@ UPDATESTATE_DOWNLOAD_PAUSED
Definition: updatehdl.hxx:65
@ UPDATESTATE_ERROR_CHECKING
Definition: updatehdl.hxx:59
@ UPDATESTATE_DOWNLOAD_AVAIL
Definition: updatehdl.hxx:67
@ UPDATESTATES_COUNT
Definition: updatehdl.hxx:69
@ UPDATESTATE_NO_UPDATE_AVAIL
Definition: updatehdl.hxx:60
@ UPDATESTATE_UPDATE_AVAIL
Definition: updatehdl.hxx:61
@ UPDATESTATE_DOWNLOADING
Definition: updatehdl.hxx:64
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)
size_t pos