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 <config_folders.h>
22 #include <com/sun/star/xml/xpath/XPathAPI.hpp>
23 #include <com/sun/star/xml/xpath/XPathException.hpp>
25 #include "updateprotocol.hxx"
26 #include "updatecheckconfig.hxx"
28 #include <com/sun/star/deployment/UpdateInformationEntry.hpp>
29 #include <com/sun/star/deployment/XPackageInformationProvider.hpp>
32 #include <rtl/ref.hxx>
33 #include <rtl/bootstrap.hxx>
34 #include <osl/diagnose.h>
36 namespace container
= css::container
;
37 namespace deployment
= css::deployment
;
38 namespace uno
= css::uno
;
39 namespace task
= css::task
;
40 namespace xml
= css::xml
;
45 uno::Sequence
< OUString
> & rRepositoryList
,
47 OUString
& rInstallSetID
)
49 rGitID
= "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("version") ":buildid}";
50 rtl::Bootstrap::expandMacros( rGitID
);
51 if ( rGitID
.isEmpty() )
54 rInstallSetID
= "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("version") ":UpdateID}";
55 rtl::Bootstrap::expandMacros( rInstallSetID
);
56 if ( rInstallSetID
.isEmpty() )
59 OUString
aValue( "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("version") ":UpdateURL}" );
60 rtl::Bootstrap::expandMacros( aValue
);
62 if( !aValue
.isEmpty() )
64 rRepositoryList
= { aValue
};
71 // Returns 'true' if successfully connected to the update server
74 UpdateInfo
& o_rUpdateInfo
,
75 uno::Reference
< uno::XComponentContext
> const & rxContext
,
76 uno::Reference
< task::XInteractionHandler
> const & rxInteractionHandler
,
77 const uno::Reference
< deployment::XUpdateInformationProvider
>& rUpdateInfoProvider
)
82 rtl::Bootstrap::get("_OS", myOS
);
83 rtl::Bootstrap::get("_ARCH", myArch
);
85 uno::Sequence
< OUString
> aRepositoryList
;
87 OUString aInstallSetID
;
89 if( ! ( getBootstrapData(aRepositoryList
, aGitID
, aInstallSetID
) && (aRepositoryList
.getLength() > 0) ) )
92 return checkForUpdates( o_rUpdateInfo
, rxContext
, rxInteractionHandler
, rUpdateInfoProvider
,
94 aRepositoryList
, aGitID
, aInstallSetID
);
99 UpdateInfo
& o_rUpdateInfo
,
100 const uno::Reference
< uno::XComponentContext
> & rxContext
,
101 const uno::Reference
< task::XInteractionHandler
> & rxInteractionHandler
,
102 const uno::Reference
< deployment::XUpdateInformationProvider
>& rUpdateInfoProvider
,
103 std::u16string_view rOS
,
104 std::u16string_view rArch
,
105 const uno::Sequence
< OUString
> &rRepositoryList
,
106 std::u16string_view rGitID
,
107 const OUString
&rInstallSetID
)
109 if( !rxContext
.is() )
110 throw uno::RuntimeException( "checkForUpdates: empty component context" );
112 OSL_ASSERT( rxContext
->getServiceManager().is() );
114 // XPath implementation
115 uno::Reference
< xml::xpath::XXPathAPI
> xXPath
= xml::xpath::XPathAPI::create(rxContext
);
117 xXPath
->registerNS( "inst", "http://update.libreoffice.org/description" );
119 if( rxInteractionHandler
.is() )
120 rUpdateInfoProvider
->setInteractionHandler(rxInteractionHandler
);
124 uno::Reference
< container::XEnumeration
> aUpdateInfoEnumeration
=
125 rUpdateInfoProvider
->getUpdateInformationEnumeration( rRepositoryList
, rInstallSetID
);
127 if ( !aUpdateInfoEnumeration
.is() )
128 return false; // something went wrong ..
130 OUString aXPathExpression
=
131 OUString::Concat("/child::inst:description[inst:os=\'")+
133 "\' and inst:arch=\'"+
135 "\' and inst:gitid!=\'"+
140 while( aUpdateInfoEnumeration
->hasMoreElements() )
142 deployment::UpdateInformationEntry aEntry
;
144 if( aUpdateInfoEnumeration
->nextElement() >>= aEntry
)
146 uno::Reference
< xml::dom::XNode
> xNode( aEntry
.UpdateDocument
);
147 uno::Reference
< xml::dom::XNodeList
> xNodeList
;
149 xNodeList
= xXPath
->selectNodeList(xNode
, aXPathExpression
150 + "/inst:update/attribute::src");
151 } catch (const css::xml::xpath::XPathException
&) {
155 sal_Int32 i
, imax
= xNodeList
->getLength();
156 for( i
= 0; i
< imax
; ++i
)
158 uno::Reference
< xml::dom::XNode
> xNode2( xNodeList
->item(i
) );
162 uno::Reference
< xml::dom::XElement
> xParent(xNode2
->getParentNode(), uno::UNO_QUERY_THROW
);
163 OUString aType
= xParent
->getAttribute("type");
164 bool bIsDirect
= !aType
.equalsIgnoreAsciiCase("text/html");
166 o_rUpdateInfo
.Sources
.push_back( DownloadSource(bIsDirect
, xNode2
->getNodeValue()) );
170 uno::Reference
< xml::dom::XNode
> xNode2
;
172 xNode2
= xXPath
->selectSingleNode(xNode
, aXPathExpression
173 + "/inst:version/text()");
174 } catch (const css::xml::xpath::XPathException
&) {
179 o_rUpdateInfo
.Version
= xNode2
->getNodeValue();
182 xNode2
= xXPath
->selectSingleNode(xNode
, aXPathExpression
183 + "/inst:buildid/text()");
184 } catch (const css::xml::xpath::XPathException
&) {
189 o_rUpdateInfo
.BuildId
= xNode2
->getNodeValue();
191 o_rUpdateInfo
.Description
= aEntry
.Description
;
195 xNodeList
= xXPath
->selectNodeList(xNode
, aXPathExpression
197 } catch (const css::xml::xpath::XPathException
&) {
200 imax
= xNodeList
->getLength();
201 for( i
= 0; i
< imax
; ++i
)
203 uno::Reference
< xml::dom::XElement
> xRelNote(xNodeList
->item(i
), uno::UNO_QUERY
);
206 sal_Int32 pos
= xRelNote
->getAttribute("pos").toInt32();
208 ReleaseNote
aRelNote(static_cast<sal_uInt8
>(pos
), xRelNote
->getAttribute("src"));
210 if( xRelNote
->hasAttribute("src2") )
212 pos
= xRelNote
->getAttribute("pos2").toInt32();
213 aRelNote
.Pos2
= static_cast<sal_Int8
>(pos
);
214 aRelNote
.URL2
= xRelNote
->getAttribute("src2");
217 o_rUpdateInfo
.ReleaseNotes
.push_back(aRelNote
);
221 if( !o_rUpdateInfo
.Sources
.empty() )
235 bool storeExtensionUpdateInfos( const uno::Reference
< uno::XComponentContext
> & rxContext
,
236 const uno::Sequence
< uno::Sequence
< OUString
> > &rUpdateInfos
)
238 bool bNotify
= false;
240 if ( rUpdateInfos
.hasElements() )
242 rtl::Reference
< UpdateCheckConfig
> aConfig
= UpdateCheckConfig::get( rxContext
);
244 for ( sal_Int32 i
= rUpdateInfos
.getLength() - 1; i
>= 0; i
-- )
246 bNotify
|= aConfig
->storeExtensionVersion( rUpdateInfos
[i
][0], rUpdateInfos
[i
][1] );
253 // Returns 'true' if there are updates for any extension
255 bool checkForExtensionUpdates( const uno::Reference
< uno::XComponentContext
> & rxContext
)
257 uno::Sequence
< uno::Sequence
< OUString
> > aUpdateList
;
259 uno::Reference
< deployment::XPackageInformationProvider
> xInfoProvider
;
262 uno::Any
aValue( rxContext
->getValueByName(
263 "/singletons/com.sun.star.deployment.PackageInformationProvider" ) );
264 OSL_VERIFY( aValue
>>= xInfoProvider
);
266 catch( const uno::Exception
& )
268 OSL_FAIL( "checkForExtensionUpdates: could not create the PackageInformationProvider!" );
271 if ( !xInfoProvider
.is() ) return false;
273 aUpdateList
= xInfoProvider
->isUpdateAvailable( OUString() );
274 bool bNotify
= storeExtensionUpdateInfos( rxContext
, aUpdateList
);
280 // Returns 'true' if there are any pending updates for any extension (offline check)
282 bool checkForPendingUpdates( const uno::Reference
< uno::XComponentContext
> & rxContext
)
284 uno::Sequence
< uno::Sequence
< OUString
> > aExtensionList
;
285 uno::Reference
< deployment::XPackageInformationProvider
> xInfoProvider
;
288 uno::Any
aValue( rxContext
->getValueByName(
289 "/singletons/com.sun.star.deployment.PackageInformationProvider" ) );
290 OSL_VERIFY( aValue
>>= xInfoProvider
);
292 catch( const uno::Exception
& )
294 OSL_FAIL( "checkForExtensionUpdates: could not create the PackageInformationProvider!" );
297 if ( !xInfoProvider
.is() ) return false;
299 bool bPendingUpdateFound
= false;
301 aExtensionList
= xInfoProvider
->getExtensionList();
302 if ( aExtensionList
.hasElements() )
304 rtl::Reference
< UpdateCheckConfig
> aConfig
= UpdateCheckConfig::get( rxContext
);
306 for ( sal_Int32 i
= aExtensionList
.getLength() - 1; i
>= 0; i
-- )
308 bPendingUpdateFound
= aConfig
->checkExtensionVersion( aExtensionList
[i
][0], aExtensionList
[i
][1] );
309 if ( bPendingUpdateFound
)
314 return bPendingUpdateFound
;
317 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */