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 <com/sun/star/beans/PropertyValue.hpp>
22 #include <com/sun/star/beans/XPropertyState.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 static const sal_Char
* const aUpdateEntryProperties
[] = {
76 static const sal_uInt32 nUpdateEntryProperties
= SAL_N_ELEMENTS(aUpdateEntryProperties
);
78 NamedValueByNameAccess::~NamedValueByNameAccess()
82 css::uno::Any
NamedValueByNameAccess::getValue(const sal_Char
* pName
)
84 const sal_Int32 nLen
= m_rValues
.getLength();
85 for( sal_Int32 n
=0; n
< nLen
; ++n
)
87 if( m_rValues
[n
].Name
.equalsAscii( pName
) )
88 return m_rValues
[n
].Value
;
90 return css::uno::Any();
94 UpdateCheckROModel::isAutoCheckEnabled() const
96 return m_aNameAccess
.getValue(AUTOCHECK_ENABLED
).get
<bool>();
100 UpdateCheckROModel::isDownloadPaused() const
102 return m_aNameAccess
.getValue(DOWNLOAD_PAUSED
).get
<bool>();
106 UpdateCheckROModel::getStringValue(const sal_Char
* pStr
) const
108 uno::Any
aAny( m_aNameAccess
.getValue(pStr
) );
116 OUString
UpdateCheckROModel::getLocalFileName() const
118 return getStringValue(LOCAL_FILE
);
121 sal_Int64
UpdateCheckROModel::getDownloadSize() const
123 uno::Any
aAny( m_aNameAccess
.getValue(DOWNLOAD_SIZE
) );
131 UpdateCheckROModel::getUpdateEntryVersion() const
133 return getStringValue(OLD_VERSION
);
137 UpdateCheckROModel::getUpdateEntry(UpdateInfo
& rInfo
) const
139 rInfo
.BuildId
= getStringValue(UPDATE_BUILDID
);
140 rInfo
.Version
= getStringValue(UPDATE_VERSION
);
141 rInfo
.Description
= getStringValue(UPDATE_DESCRIPTION
);
143 bool isDirectDownload
= false;
144 m_aNameAccess
.getValue(IS_DIRECT_DOWNLOAD
) >>= isDirectDownload
;
146 rInfo
.Sources
.push_back( DownloadSource( isDirectDownload
, getStringValue(DOWNLOAD_URL
) ) );
148 for(sal_Int32 n
=1; n
< 6; ++n
)
150 OUString aUStr
= getStringValue(
151 OString(OStringLiteral(RELEASE_NOTE
) + OString::number(n
)).getStr());
152 if( !aUStr
.isEmpty() )
153 rInfo
.ReleaseNotes
.push_back(ReleaseNote(static_cast<sal_Int8
>(n
), aUStr
));
157 OUString
UpdateCheckConfig::getDownloadsDirectory()
164 if (SHGetKnownFolderPath(FOLDERID_Downloads
, 0, nullptr, &szPath
) == S_OK
)
166 aRet
= o3tl::toU(szPath
);
167 CoTaskMemFree(szPath
);
168 osl::FileBase::getFileURLFromSystemPath( aRet
, aRet
);
171 // This should become a desktop specific setting in some system backend ..
173 osl::Security().getHomeDir( aHomeDir
);
174 aRet
= aHomeDir
+ "/Desktop";
176 // Set path to home directory when there is no /Desktop directory
177 osl::Directory
aDocumentsDir( aRet
);
178 if( osl::FileBase::E_None
!= aDocumentsDir
.open() )
185 OUString
UpdateCheckConfig::getAllUsersDirectory()
190 WCHAR szPath
[MAX_PATH
];
192 if (TRUE
== SHGetSpecialFolderPathW(nullptr, szPath
, CSIDL_COMMON_DOCUMENTS
, true))
194 aRet
= o3tl::toU(szPath
);
195 osl::FileBase::getFileURLFromSystemPath( aRet
, aRet
);
198 osl::FileBase::getTempDirURL(aRet
);
204 UpdateCheckConfig::UpdateCheckConfig( const uno::Reference
<container::XNameContainer
>& xContainer
,
205 const uno::Reference
<container::XNameContainer
>& xAvailableUpdates
,
206 const uno::Reference
<container::XNameContainer
>& xIgnoredUpdates
,
207 const ::rtl::Reference
< UpdateCheckConfigListener
>& rListener
) :
208 m_xContainer( xContainer
),
209 m_xAvailableUpdates( xAvailableUpdates
),
210 m_xIgnoredUpdates( xIgnoredUpdates
),
211 m_rListener( rListener
)
214 UpdateCheckConfig::~UpdateCheckConfig()
217 ::rtl::Reference
< UpdateCheckConfig
>
218 UpdateCheckConfig::get(
219 const uno::Reference
<uno::XComponentContext
>& xContext
,
220 const ::rtl::Reference
< UpdateCheckConfigListener
>& rListener
)
222 uno::Reference
< lang::XMultiServiceFactory
> xConfigProvider(
223 css::configuration::theDefaultProvider::get( xContext
) );
225 beans::PropertyValue aProperty
;
226 aProperty
.Name
= "nodepath";
227 aProperty
.Value
<<= OUString("org.openoffice.Office.Jobs/Jobs/UpdateCheck/Arguments");
229 uno::Sequence
< uno::Any
> aArgumentList( 1 );
230 aArgumentList
[0] <<= aProperty
;
232 uno::Reference
< container::XNameContainer
> xContainer(
233 xConfigProvider
->createInstanceWithArguments(
234 "com.sun.star.configuration.ConfigurationUpdateAccess", aArgumentList
),
235 uno::UNO_QUERY_THROW
);
237 aProperty
.Value
<<= OUString("/org.openoffice.Office.ExtensionManager/ExtensionUpdateData/IgnoredUpdates");
238 aArgumentList
[0] <<= aProperty
;
239 uno::Reference
< container::XNameContainer
> xIgnoredExt( xConfigProvider
->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationUpdateAccess", aArgumentList
), uno::UNO_QUERY_THROW
);
241 aProperty
.Value
<<= OUString("/org.openoffice.Office.ExtensionManager/ExtensionUpdateData/AvailableUpdates");
242 aArgumentList
[0] <<= aProperty
;
243 uno::Reference
< container::XNameContainer
> xUpdateAvail( xConfigProvider
->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationUpdateAccess", aArgumentList
), uno::UNO_QUERY_THROW
);
245 return new UpdateCheckConfig( xContainer
, xUpdateAvail
, xIgnoredExt
, rListener
);
249 UpdateCheckConfig::isAutoCheckEnabled() const
252 const_cast < UpdateCheckConfig
*> (this)->getByName( AUTOCHECK_ENABLED
) >>= nValue
;
257 UpdateCheckConfig::isAutoDownloadEnabled() const
260 const_cast < UpdateCheckConfig
*> (this)->getByName( AUTODOWNLOAD_ENABLED
) >>= nValue
;
265 UpdateCheckConfig::getUpdateEntryVersion() const
269 // getByName is defined as non const in XNameAccess
270 const_cast < UpdateCheckConfig
*> (this)->getByName( OLD_VERSION
) >>= aValue
;
276 UpdateCheckConfig::getLastChecked() const
278 sal_Int64 nValue
= 0;
280 // getByName is defined as non const in XNameAccess
281 const_cast < UpdateCheckConfig
*> (this)->getByName( LAST_CHECK
) >>= nValue
;
287 UpdateCheckConfig::getCheckInterval() const
289 sal_Int64 nValue
= 0;
291 // getByName is defined as non const in XNameAccess
292 const_cast < UpdateCheckConfig
*> (this)->getByName( CHECK_INTERVAL
) >>= nValue
;
298 UpdateCheckConfig::getLocalFileName() const
300 OUString aName
= LOCAL_FILE
;
303 if( m_xContainer
->hasByName(aName
) )
304 m_xContainer
->getByName(aName
) >>= aRet
;
310 UpdateCheckConfig::getDownloadDestination() const
312 OUString aName
= DOWNLOAD_DESTINATION
;
315 const_cast <UpdateCheckConfig
*> (this)->getByName(aName
) >>= aRet
;
321 UpdateCheckConfig::storeLocalFileName(const OUString
& rLocalFileName
, sal_Int64 nFileSize
)
323 const sal_uInt8 nItems
= 2;
324 const OUString aNameList
[nItems
] = { OUString(LOCAL_FILE
), OUString(DOWNLOAD_SIZE
) };
325 const uno::Any aValueList
[nItems
] = { uno::makeAny(rLocalFileName
), uno::makeAny(nFileSize
) };
327 for( sal_uInt8 i
=0; i
< nItems
; ++i
)
329 if( m_xContainer
->hasByName(aNameList
[i
]) )
330 m_xContainer
->replaceByName(aNameList
[i
], aValueList
[i
]);
332 m_xContainer
->insertByName(aNameList
[i
], aValueList
[i
]);
339 UpdateCheckConfig::clearLocalFileName()
341 const sal_uInt8 nItems
= 2;
342 const OUString aNameList
[nItems
] = { OUString(LOCAL_FILE
), OUString(DOWNLOAD_SIZE
) };
344 for(const auto & i
: aNameList
)
346 if( m_xContainer
->hasByName(i
) )
347 m_xContainer
->removeByName(i
);
354 UpdateCheckConfig::storeDownloadPaused(bool paused
)
356 replaceByName(DOWNLOAD_PAUSED
, uno::makeAny(paused
));
361 UpdateCheckConfig::updateLastChecked()
364 osl_getSystemTime(&systime
);
366 sal_Int64 lastCheck
= systime
.Seconds
;
368 replaceByName(LAST_CHECK
, uno::makeAny(lastCheck
));
372 UpdateCheckConfig::storeUpdateFound( const UpdateInfo
& rInfo
, const OUString
& aCurrentBuild
)
375 bool autoDownloadEnabled
= isAutoDownloadEnabled();
377 uno::Any aValues
[nUpdateEntryProperties
] =
379 uno::makeAny(rInfo
.Version
),
380 uno::makeAny(rInfo
.BuildId
),
381 uno::makeAny(rInfo
.Description
),
382 uno::makeAny(rInfo
.Sources
[0].URL
),
383 uno::makeAny(rInfo
.Sources
[0].IsDirect
),
384 uno::makeAny(getReleaseNote(rInfo
, 1, autoDownloadEnabled
) ),
385 uno::makeAny(getReleaseNote(rInfo
, 2, autoDownloadEnabled
) ),
386 uno::makeAny(getReleaseNote(rInfo
, 3, autoDownloadEnabled
) ),
387 uno::makeAny(getReleaseNote(rInfo
, 4, autoDownloadEnabled
) ),
388 uno::makeAny(getReleaseNote(rInfo
, 5, autoDownloadEnabled
) ),
389 uno::makeAny(aCurrentBuild
)
393 for( sal_uInt32 n
=0; n
< nUpdateEntryProperties
; ++n
)
395 aName
= OUString::createFromAscii(aUpdateEntryProperties
[n
]);
397 if( m_xContainer
->hasByName(aName
) )
398 m_xContainer
->replaceByName(aName
, aValues
[n
]);
400 m_xContainer
->insertByName(aName
,aValues
[n
]);
407 UpdateCheckConfig::clearUpdateFound()
411 for(const char* aUpdateEntryPropertie
: aUpdateEntryProperties
)
413 aName
= OUString::createFromAscii(aUpdateEntryPropertie
);
416 if( m_xContainer
->hasByName(aName
) )
417 m_xContainer
->removeByName(aName
);
418 } catch(const lang::WrappedTargetException
& ) {
419 // Can not remove value, probably in share layer
421 m_xContainer
->replaceByName(aName
, uno::makeAny(OUString()));
425 /* As we have removed UpdateVersionFound from the shared configuration
426 * existing entries in the user layer do not have a oor operation and
427 * thus are completely ignored (which also means they can not be removed).
433 uno::Sequence
< OUString
>
434 UpdateCheckConfig::getServiceNames()
436 uno::Sequence
< OUString
> aServiceList
{ "com.sun.star.setup.UpdateCheckConfig" };
441 UpdateCheckConfig::getImplName()
443 return OUString("vnd.sun.UpdateCheckConfig");
447 UpdateCheckConfig::getElementType()
449 return m_xContainer
->getElementType();
453 UpdateCheckConfig::hasElements()
455 return m_xContainer
->hasElements();
459 UpdateCheckConfig::getByName( const OUString
& aName
)
461 uno::Any aValue
= m_xContainer
->getByName( aName
);
463 // Provide dynamic default value
464 if( aName
== DOWNLOAD_DESTINATION
)
470 aValue
<<= getDownloadsDirectory();
475 uno::Sequence
< OUString
> SAL_CALL
476 UpdateCheckConfig::getElementNames()
478 return m_xContainer
->getElementNames();
482 UpdateCheckConfig::hasByName( const OUString
& aName
)
484 return m_xContainer
->hasByName( aName
);
488 UpdateCheckConfig::replaceByName( const OUString
& aName
, const uno::Any
& aElement
)
490 return m_xContainer
->replaceByName( aName
, aElement
);
496 UpdateCheckConfig::commitChanges()
498 uno::Reference
< util::XChangesBatch
> xChangesBatch(m_xContainer
, uno::UNO_QUERY
);
499 if( xChangesBatch
.is() && xChangesBatch
->hasPendingChanges() )
501 util::ChangesSet aChangesSet
= xChangesBatch
->getPendingChanges();
502 xChangesBatch
->commitChanges();
504 if( m_rListener
.is() )
506 const sal_Int32 nChanges
= aChangesSet
.getLength();
509 for( sal_Int32 i
=0; i
<nChanges
; ++i
)
511 aChangesSet
[i
].Accessor
>>= aString
;
512 if( aString
.endsWith(AUTOCHECK_ENABLED
"']") )
514 bool bEnabled
= false;
515 aChangesSet
[i
].Element
>>= bEnabled
;
516 m_rListener
->autoCheckStatusChanged(bEnabled
);
518 else if( aString
.endsWith(CHECK_INTERVAL
"']") )
520 m_rListener
->autoCheckIntervalChanged();
526 xChangesBatch
.set( m_xAvailableUpdates
, uno::UNO_QUERY
);
527 if( xChangesBatch
.is() && xChangesBatch
->hasPendingChanges() )
529 xChangesBatch
->commitChanges();
531 xChangesBatch
.set( m_xIgnoredUpdates
, uno::UNO_QUERY
);
532 if( xChangesBatch
.is() && xChangesBatch
->hasPendingChanges() )
534 xChangesBatch
->commitChanges();
539 UpdateCheckConfig::hasPendingChanges( )
541 uno::Reference
< util::XChangesBatch
> xChangesBatch(m_xContainer
, uno::UNO_QUERY
);
542 if( xChangesBatch
.is() )
543 return xChangesBatch
->hasPendingChanges();
548 uno::Sequence
< util::ElementChange
> SAL_CALL
549 UpdateCheckConfig::getPendingChanges( )
551 uno::Reference
< util::XChangesBatch
> xChangesBatch(m_xContainer
, uno::UNO_QUERY
);
552 if( xChangesBatch
.is() )
553 return xChangesBatch
->getPendingChanges();
555 return uno::Sequence
< util::ElementChange
>();
558 bool UpdateCheckConfig::storeExtensionVersion( const OUString
& rExtensionName
,
559 const OUString
& rVersion
)
563 if ( m_xAvailableUpdates
->hasByName( rExtensionName
) )
564 uno::Reference
< beans::XPropertySet
>( m_xAvailableUpdates
->getByName( rExtensionName
), uno::UNO_QUERY_THROW
)->setPropertyValue( PROPERTY_VERSION
, uno::Any( rVersion
) );
567 uno::Reference
< beans::XPropertySet
> elem( uno::Reference
< lang::XSingleServiceFactory
>( m_xAvailableUpdates
, uno::UNO_QUERY_THROW
)->createInstance(), uno::UNO_QUERY_THROW
);
568 elem
->setPropertyValue( PROPERTY_VERSION
, uno::Any( rVersion
) );
569 m_xAvailableUpdates
->insertByName( rExtensionName
, uno::Any( elem
) );
572 if ( m_xIgnoredUpdates
->hasByName( rExtensionName
) )
574 OUString aIgnoredVersion
;
575 uno::Any
aValue( uno::Reference
< beans::XPropertySet
>( m_xIgnoredUpdates
->getByName( rExtensionName
), uno::UNO_QUERY_THROW
)->getPropertyValue( PROPERTY_VERSION
) );
576 aValue
>>= aIgnoredVersion
;
577 if ( aIgnoredVersion
.isEmpty() ) // no version means ignore all updates
579 else if ( aIgnoredVersion
== rVersion
) // the user wanted to ignore this update
588 bool UpdateCheckConfig::checkExtensionVersion( const OUString
& rExtensionName
,
589 const OUString
& rVersion
)
591 if ( m_xAvailableUpdates
->hasByName( rExtensionName
) )
593 OUString aStoredVersion
;
594 uno::Any
aValue( uno::Reference
< beans::XPropertySet
>( m_xAvailableUpdates
->getByName( rExtensionName
), uno::UNO_QUERY_THROW
)->getPropertyValue( PROPERTY_VERSION
) );
595 aValue
>>= aStoredVersion
;
597 if ( m_xIgnoredUpdates
->hasByName( rExtensionName
) )
599 OUString aIgnoredVersion
;
600 uno::Any
aValue2( uno::Reference
< beans::XPropertySet
>( m_xIgnoredUpdates
->getByName( rExtensionName
), uno::UNO_QUERY_THROW
)->getPropertyValue( PROPERTY_VERSION
) );
601 aValue2
>>= aIgnoredVersion
;
602 if ( aIgnoredVersion
.isEmpty() ) // no version means ignore all updates
604 else if ( aIgnoredVersion
== aStoredVersion
) // the user wanted to ignore this update
606 // TODO: else delete ignored entry?
608 if ( isVersionGreater( rVersion
, aStoredVersion
) )
612 m_xAvailableUpdates
->removeByName( rExtensionName
);
620 OUString
UpdateCheckConfig::getSubVersion( const OUString
& rVersion
,
623 while ( *nIndex
< rVersion
.getLength() && rVersion
[*nIndex
] == '0')
628 return rVersion
.getToken( 0, '.', *nIndex
);
631 /// checks if the second version string is greater than the first one
632 bool UpdateCheckConfig::isVersionGreater( const OUString
& rVersion1
,
633 const OUString
& rVersion2
)
635 for ( sal_Int32 i1
= 0, i2
= 0; i1
>= 0 || i2
>= 0; )
637 OUString
sSub1( getSubVersion( rVersion1
, &i1
) );
638 OUString
sSub2( getSubVersion( rVersion2
, &i2
) );
640 if ( sSub1
.getLength() < sSub2
.getLength() ) {
642 } else if ( sSub1
.getLength() > sSub2
.getLength() ) {
644 } else if ( sSub1
< sSub2
) {
646 } else if ( sSub1
> sSub2
) {
654 UpdateCheckConfig::getImplementationName()
656 return getImplName();
660 UpdateCheckConfig::supportsService(OUString
const & serviceName
)
662 return cppu::supportsService(this, serviceName
);
665 uno::Sequence
< OUString
> SAL_CALL
666 UpdateCheckConfig::getSupportedServiceNames()
668 return getServiceNames();
671 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */