1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "updatecheckconfig.hxx"
21 #include "updatecheck.hxx"
22 #include <com/sun/star/beans/PropertyValue.hpp>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/configuration/theDefaultProvider.hpp>
25 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
26 #include <cppuhelper/supportsservice.hxx>
27 #include <osl/security.hxx>
29 #include <osl/file.hxx>
30 #include <sal/macros.h>
31 #include <o3tl/char16_t2wchar_t.hxx>
38 namespace container
= com::sun::star::container
;
39 namespace beans
= com::sun::star::beans
;
40 namespace lang
= com::sun::star::lang
;
41 namespace util
= com::sun::star::util
;
42 namespace uno
= com::sun::star::uno
;
44 #define LAST_CHECK "LastCheck"
45 #define UPDATE_VERSION "UpdateVersion"
46 #define UPDATE_BUILDID "UpdateBuildId"
47 #define UPDATE_DESCRIPTION "UpdateDescription"
48 #define DOWNLOAD_URL "DownloadURL"
49 #define IS_DIRECT_DOWNLOAD "IsDirectDownload"
50 #define OLD_VERSION "UpdateFoundFor"
51 #define AUTOCHECK_ENABLED "AutoCheckEnabled"
52 #define AUTODOWNLOAD_ENABLED "AutoDownloadEnabled"
53 #define CHECK_INTERVAL "CheckInterval"
54 #define LOCAL_FILE "LocalFile"
55 #define DOWNLOAD_SIZE "DownloadSize"
56 #define DOWNLOAD_PAUSED "DownloadPaused"
57 #define DOWNLOAD_DESTINATION "DownloadDestination"
58 #define RELEASE_NOTE "ReleaseNote"
60 #define PROPERTY_VERSION "Version"
62 const char * const aUpdateEntryProperties
[] = {
76 const sal_uInt32 nUpdateEntryProperties
= SAL_N_ELEMENTS(aUpdateEntryProperties
);
78 css::uno::Any
NamedValueByNameAccess::getValue(const char * pName
)
80 const sal_Int32 nLen
= m_rValues
.getLength();
81 for( sal_Int32 n
=0; n
< nLen
; ++n
)
83 if( m_rValues
[n
].Name
.equalsAscii( pName
) )
84 return m_rValues
[n
].Value
;
86 return css::uno::Any();
90 UpdateCheckROModel::isAutoCheckEnabled() const
92 return m_aNameAccess
.getValue(AUTOCHECK_ENABLED
).get
<bool>();
96 UpdateCheckROModel::isDownloadPaused() const
98 return m_aNameAccess
.getValue(DOWNLOAD_PAUSED
).get
<bool>();
102 UpdateCheckROModel::getStringValue(const char * pStr
) const
104 uno::Any
aAny( m_aNameAccess
.getValue(pStr
) );
112 OUString
UpdateCheckROModel::getLocalFileName() const
114 return getStringValue(LOCAL_FILE
);
117 sal_Int64
UpdateCheckROModel::getDownloadSize() const
119 uno::Any
aAny( m_aNameAccess
.getValue(DOWNLOAD_SIZE
) );
127 UpdateCheckROModel::getUpdateEntryVersion() const
129 return getStringValue(OLD_VERSION
);
133 UpdateCheckROModel::getUpdateEntry(UpdateInfo
& rInfo
) const
135 rInfo
.BuildId
= getStringValue(UPDATE_BUILDID
);
136 rInfo
.Version
= getStringValue(UPDATE_VERSION
);
137 rInfo
.Description
= getStringValue(UPDATE_DESCRIPTION
);
139 bool isDirectDownload
= false;
140 m_aNameAccess
.getValue(IS_DIRECT_DOWNLOAD
) >>= isDirectDownload
;
142 rInfo
.Sources
.push_back( DownloadSource( isDirectDownload
, getStringValue(DOWNLOAD_URL
) ) );
144 for(sal_Int32 n
=1; n
< 6; ++n
)
146 OUString aUStr
= getStringValue(
147 OString(OString::Concat(RELEASE_NOTE
) + OString::number(n
)).getStr());
148 if( !aUStr
.isEmpty() )
149 rInfo
.ReleaseNotes
.push_back(ReleaseNote(static_cast<sal_Int8
>(n
), aUStr
));
153 OUString
UpdateCheckConfig::getDownloadsDirectory()
160 if (SHGetKnownFolderPath(FOLDERID_Downloads
, 0, nullptr, &szPath
) == S_OK
)
162 aRet
= o3tl::toU(szPath
);
163 CoTaskMemFree(szPath
);
164 osl::FileBase::getFileURLFromSystemPath( aRet
, aRet
);
167 // This should become a desktop specific setting in some system backend ..
169 osl::Security().getHomeDir( aHomeDir
);
170 aRet
= aHomeDir
+ "/Desktop";
172 // Set path to home directory when there is no /Desktop directory
173 osl::Directory
aDocumentsDir( aRet
);
174 if( osl::FileBase::E_None
!= aDocumentsDir
.open() )
181 OUString
UpdateCheckConfig::getAllUsersDirectory()
186 WCHAR szPath
[MAX_PATH
];
188 if (TRUE
== SHGetSpecialFolderPathW(nullptr, szPath
, CSIDL_COMMON_DOCUMENTS
, true))
190 aRet
= o3tl::toU(szPath
);
191 osl::FileBase::getFileURLFromSystemPath( aRet
, aRet
);
194 osl::FileBase::getTempDirURL(aRet
);
200 UpdateCheckConfig::UpdateCheckConfig( const uno::Reference
<container::XNameContainer
>& xContainer
,
201 const uno::Reference
<container::XNameContainer
>& xAvailableUpdates
,
202 const uno::Reference
<container::XNameContainer
>& xIgnoredUpdates
,
203 const ::rtl::Reference
< UpdateCheckConfigListener
>& rListener
) :
204 m_xContainer( xContainer
),
205 m_xAvailableUpdates( xAvailableUpdates
),
206 m_xIgnoredUpdates( xIgnoredUpdates
),
207 m_rListener( rListener
)
210 UpdateCheckConfig::~UpdateCheckConfig()
213 ::rtl::Reference
< UpdateCheckConfig
>
214 UpdateCheckConfig::get(
215 const uno::Reference
<uno::XComponentContext
>& xContext
,
216 const ::rtl::Reference
< UpdateCheckConfigListener
>& rListener
)
218 uno::Reference
< lang::XMultiServiceFactory
> xConfigProvider(
219 css::configuration::theDefaultProvider::get( xContext
) );
221 beans::PropertyValue aProperty
;
222 aProperty
.Name
= "nodepath";
223 aProperty
.Value
<<= OUString("org.openoffice.Office.Jobs/Jobs/UpdateCheck/Arguments");
225 uno::Sequence
< uno::Any
> aArgumentList
{ uno::Any(aProperty
) };
227 uno::Reference
< container::XNameContainer
> xContainer(
228 xConfigProvider
->createInstanceWithArguments(
229 "com.sun.star.configuration.ConfigurationUpdateAccess", aArgumentList
),
230 uno::UNO_QUERY_THROW
);
232 aProperty
.Value
<<= OUString("/org.openoffice.Office.ExtensionManager/ExtensionUpdateData/IgnoredUpdates");
233 aArgumentList
= { uno::Any(aProperty
) };
234 uno::Reference
< container::XNameContainer
> xIgnoredExt( xConfigProvider
->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationUpdateAccess", aArgumentList
), uno::UNO_QUERY_THROW
);
236 aProperty
.Value
<<= OUString("/org.openoffice.Office.ExtensionManager/ExtensionUpdateData/AvailableUpdates");
237 aArgumentList
= { uno::Any(aProperty
) };
238 uno::Reference
< container::XNameContainer
> xUpdateAvail( xConfigProvider
->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationUpdateAccess", aArgumentList
), uno::UNO_QUERY_THROW
);
240 return new UpdateCheckConfig( xContainer
, xUpdateAvail
, xIgnoredExt
, rListener
);
244 UpdateCheckConfig::isAutoCheckEnabled() const
247 const_cast < UpdateCheckConfig
*> (this)->getByName( AUTOCHECK_ENABLED
) >>= nValue
;
252 UpdateCheckConfig::isAutoDownloadEnabled() const
255 const_cast < UpdateCheckConfig
*> (this)->getByName( AUTODOWNLOAD_ENABLED
) >>= nValue
;
260 UpdateCheckConfig::getUpdateEntryVersion() const
264 // getByName is defined as non const in XNameAccess
265 const_cast < UpdateCheckConfig
*> (this)->getByName( OLD_VERSION
) >>= aValue
;
271 UpdateCheckConfig::getLastChecked() const
273 sal_Int64 nValue
= 0;
275 // getByName is defined as non const in XNameAccess
276 const_cast < UpdateCheckConfig
*> (this)->getByName( LAST_CHECK
) >>= nValue
;
282 UpdateCheckConfig::getCheckInterval() const
284 sal_Int64 nValue
= 0;
286 // getByName is defined as non const in XNameAccess
287 const_cast < UpdateCheckConfig
*> (this)->getByName( CHECK_INTERVAL
) >>= nValue
;
293 UpdateCheckConfig::getLocalFileName() const
295 OUString aName
= LOCAL_FILE
;
298 if( m_xContainer
->hasByName(aName
) )
299 m_xContainer
->getByName(aName
) >>= aRet
;
305 UpdateCheckConfig::getDownloadDestination() const
309 const_cast <UpdateCheckConfig
*> (this)->getByName(DOWNLOAD_DESTINATION
) >>= aRet
;
315 UpdateCheckConfig::storeLocalFileName(const OUString
& rLocalFileName
, sal_Int64 nFileSize
)
317 const sal_uInt8 nItems
= 2;
318 const OUString aNameList
[nItems
] = { OUString(LOCAL_FILE
), OUString(DOWNLOAD_SIZE
) };
319 const uno::Any aValueList
[nItems
] = { uno::Any(rLocalFileName
), uno::Any(nFileSize
) };
321 for( sal_uInt8 i
=0; i
< nItems
; ++i
)
323 if( m_xContainer
->hasByName(aNameList
[i
]) )
324 m_xContainer
->replaceByName(aNameList
[i
], aValueList
[i
]);
326 m_xContainer
->insertByName(aNameList
[i
], aValueList
[i
]);
333 UpdateCheckConfig::clearLocalFileName()
335 const sal_uInt8 nItems
= 2;
336 const OUString aNameList
[nItems
] = { OUString(LOCAL_FILE
), OUString(DOWNLOAD_SIZE
) };
338 for(const auto & i
: aNameList
)
340 if( m_xContainer
->hasByName(i
) )
341 m_xContainer
->removeByName(i
);
348 UpdateCheckConfig::storeDownloadPaused(bool paused
)
350 replaceByName(DOWNLOAD_PAUSED
, uno::Any(paused
));
355 UpdateCheckConfig::updateLastChecked()
358 osl_getSystemTime(&systime
);
360 sal_Int64 lastCheck
= systime
.Seconds
;
362 replaceByName(LAST_CHECK
, uno::Any(lastCheck
));
366 UpdateCheckConfig::storeUpdateFound( const UpdateInfo
& rInfo
, const OUString
& aCurrentBuild
)
369 bool autoDownloadEnabled
= isAutoDownloadEnabled();
371 uno::Any aValues
[nUpdateEntryProperties
] =
373 uno::Any(rInfo
.Version
),
374 uno::Any(rInfo
.BuildId
),
375 uno::Any(rInfo
.Description
),
376 uno::Any(rInfo
.Sources
[0].URL
),
377 uno::Any(rInfo
.Sources
[0].IsDirect
),
378 uno::Any(getReleaseNote(rInfo
, 1, autoDownloadEnabled
) ),
379 uno::Any(getReleaseNote(rInfo
, 2, autoDownloadEnabled
) ),
380 uno::Any(getReleaseNote(rInfo
, 3, autoDownloadEnabled
) ),
381 uno::Any(getReleaseNote(rInfo
, 4, autoDownloadEnabled
) ),
382 uno::Any(getReleaseNote(rInfo
, 5, autoDownloadEnabled
) ),
383 uno::Any(aCurrentBuild
)
387 for( sal_uInt32 n
=0; n
< nUpdateEntryProperties
; ++n
)
389 aName
= OUString::createFromAscii(aUpdateEntryProperties
[n
]);
391 if( m_xContainer
->hasByName(aName
) )
392 m_xContainer
->replaceByName(aName
, aValues
[n
]);
394 m_xContainer
->insertByName(aName
,aValues
[n
]);
401 UpdateCheckConfig::clearUpdateFound()
405 for(const char* aUpdateEntryProperty
: aUpdateEntryProperties
)
407 aName
= OUString::createFromAscii(aUpdateEntryProperty
);
410 if( m_xContainer
->hasByName(aName
) )
411 m_xContainer
->removeByName(aName
);
412 } catch(const lang::WrappedTargetException
& ) {
413 // Can not remove value, probably in share layer
415 m_xContainer
->replaceByName(aName
, uno::Any(OUString()));
419 /* As we have removed UpdateVersionFound from the shared configuration
420 * existing entries in the user layer do not have a oor operation and
421 * thus are completely ignored (which also means they can not be removed).
428 UpdateCheckConfig::getElementType()
430 return m_xContainer
->getElementType();
434 UpdateCheckConfig::hasElements()
436 return m_xContainer
->hasElements();
440 UpdateCheckConfig::getByName( const OUString
& aName
)
442 uno::Any aValue
= m_xContainer
->getByName( aName
);
444 // Provide dynamic default value
445 if( aName
== DOWNLOAD_DESTINATION
)
451 aValue
<<= getDownloadsDirectory();
456 uno::Sequence
< OUString
> SAL_CALL
457 UpdateCheckConfig::getElementNames()
459 return m_xContainer
->getElementNames();
463 UpdateCheckConfig::hasByName( const OUString
& aName
)
465 return m_xContainer
->hasByName( aName
);
469 UpdateCheckConfig::replaceByName( const OUString
& aName
, const uno::Any
& aElement
)
471 return m_xContainer
->replaceByName( aName
, aElement
);
477 UpdateCheckConfig::commitChanges()
479 uno::Reference
< util::XChangesBatch
> xChangesBatch(m_xContainer
, uno::UNO_QUERY
);
480 if( xChangesBatch
.is() && xChangesBatch
->hasPendingChanges() )
482 util::ChangesSet aChangesSet
= xChangesBatch
->getPendingChanges();
483 xChangesBatch
->commitChanges();
485 if( m_rListener
.is() )
487 const sal_Int32 nChanges
= aChangesSet
.getLength();
490 for( sal_Int32 i
=0; i
<nChanges
; ++i
)
492 aChangesSet
[i
].Accessor
>>= aString
;
493 if( aString
.endsWith(AUTOCHECK_ENABLED
"']") )
495 bool bEnabled
= false;
496 aChangesSet
[i
].Element
>>= bEnabled
;
497 m_rListener
->autoCheckStatusChanged(bEnabled
);
499 else if( aString
.endsWith(CHECK_INTERVAL
"']") )
501 m_rListener
->autoCheckIntervalChanged();
507 xChangesBatch
.set( m_xAvailableUpdates
, uno::UNO_QUERY
);
508 if( xChangesBatch
.is() && xChangesBatch
->hasPendingChanges() )
510 xChangesBatch
->commitChanges();
512 xChangesBatch
.set( m_xIgnoredUpdates
, uno::UNO_QUERY
);
513 if( xChangesBatch
.is() && xChangesBatch
->hasPendingChanges() )
515 xChangesBatch
->commitChanges();
520 UpdateCheckConfig::hasPendingChanges( )
522 uno::Reference
< util::XChangesBatch
> xChangesBatch(m_xContainer
, uno::UNO_QUERY
);
523 if( xChangesBatch
.is() )
524 return xChangesBatch
->hasPendingChanges();
529 uno::Sequence
< util::ElementChange
> SAL_CALL
530 UpdateCheckConfig::getPendingChanges( )
532 uno::Reference
< util::XChangesBatch
> xChangesBatch(m_xContainer
, uno::UNO_QUERY
);
533 if( xChangesBatch
.is() )
534 return xChangesBatch
->getPendingChanges();
536 return uno::Sequence
< util::ElementChange
>();
539 bool UpdateCheckConfig::storeExtensionVersion( const OUString
& rExtensionName
,
540 const OUString
& rVersion
)
544 if ( m_xAvailableUpdates
->hasByName( rExtensionName
) )
545 uno::Reference
< beans::XPropertySet
>( m_xAvailableUpdates
->getByName( rExtensionName
), uno::UNO_QUERY_THROW
)->setPropertyValue( PROPERTY_VERSION
, uno::Any( rVersion
) );
548 uno::Reference
< beans::XPropertySet
> elem( uno::Reference
< lang::XSingleServiceFactory
>( m_xAvailableUpdates
, uno::UNO_QUERY_THROW
)->createInstance(), uno::UNO_QUERY_THROW
);
549 elem
->setPropertyValue( PROPERTY_VERSION
, uno::Any( rVersion
) );
550 m_xAvailableUpdates
->insertByName( rExtensionName
, uno::Any( elem
) );
553 if ( m_xIgnoredUpdates
->hasByName( rExtensionName
) )
555 OUString aIgnoredVersion
;
556 uno::Any
aValue( uno::Reference
< beans::XPropertySet
>( m_xIgnoredUpdates
->getByName( rExtensionName
), uno::UNO_QUERY_THROW
)->getPropertyValue( PROPERTY_VERSION
) );
557 aValue
>>= aIgnoredVersion
;
558 if ( aIgnoredVersion
.isEmpty() ) // no version means ignore all updates
560 else if ( aIgnoredVersion
== rVersion
) // the user wanted to ignore this update
569 bool UpdateCheckConfig::checkExtensionVersion( const OUString
& rExtensionName
,
570 const OUString
& rVersion
)
572 if ( m_xAvailableUpdates
->hasByName( rExtensionName
) )
574 OUString aStoredVersion
;
575 uno::Any
aValue( uno::Reference
< beans::XPropertySet
>( m_xAvailableUpdates
->getByName( rExtensionName
), uno::UNO_QUERY_THROW
)->getPropertyValue( PROPERTY_VERSION
) );
576 aValue
>>= aStoredVersion
;
578 if ( m_xIgnoredUpdates
->hasByName( rExtensionName
) )
580 OUString aIgnoredVersion
;
581 uno::Any
aValue2( uno::Reference
< beans::XPropertySet
>( m_xIgnoredUpdates
->getByName( rExtensionName
), uno::UNO_QUERY_THROW
)->getPropertyValue( PROPERTY_VERSION
) );
582 aValue2
>>= aIgnoredVersion
;
583 if ( aIgnoredVersion
.isEmpty() ) // no version means ignore all updates
585 else if ( aIgnoredVersion
== aStoredVersion
) // the user wanted to ignore this update
587 // TODO: else delete ignored entry?
589 if ( isVersionGreater( rVersion
, aStoredVersion
) )
593 m_xAvailableUpdates
->removeByName( rExtensionName
);
601 OUString
UpdateCheckConfig::getSubVersion( const OUString
& rVersion
,
604 while ( *nIndex
< rVersion
.getLength() && rVersion
[*nIndex
] == '0')
609 return rVersion
.getToken( 0, '.', *nIndex
);
612 /// checks if the second version string is greater than the first one
613 bool UpdateCheckConfig::isVersionGreater( const OUString
& rVersion1
,
614 const OUString
& rVersion2
)
616 for ( sal_Int32 i1
= 0, i2
= 0; i1
>= 0 || i2
>= 0; )
618 OUString
sSub1( getSubVersion( rVersion1
, &i1
) );
619 OUString
sSub2( getSubVersion( rVersion2
, &i2
) );
621 if ( sSub1
.getLength() < sSub2
.getLength() ) {
623 } else if ( sSub1
.getLength() > sSub2
.getLength() ) {
625 } else if ( sSub1
< sSub2
) {
627 } else if ( sSub1
> sSub2
) {
635 UpdateCheckConfig::getImplementationName()
637 return "vnd.sun.UpdateCheckConfig";
641 UpdateCheckConfig::supportsService(OUString
const & serviceName
)
643 return cppu::supportsService(this, serviceName
);
646 uno::Sequence
< OUString
> SAL_CALL
647 UpdateCheckConfig::getSupportedServiceNames()
649 return { "com.sun.star.setup.UpdateCheckConfig" };
652 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
653 extensions_update_UpdateCheckConfig_get_implementation(
654 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
656 return cppu::acquire(UpdateCheckConfig::get(context
, *UpdateCheck::get()).get());
660 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */