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 <dp_update.hxx>
23 #include <dp_version.hxx>
24 #include <dp_identifier.hxx>
25 #include <dp_descriptioninfoset.hxx>
27 #include <com/sun/star/ucb/CommandAbortedException.hpp>
28 #include <com/sun/star/ucb/CommandFailedException.hpp>
29 #include <osl/diagnose.h>
30 #include <rtl/bootstrap.hxx>
31 #include <sal/log.hxx>
33 using namespace ::com::sun::star
;
34 using namespace ::com::sun::star::uno
;
40 int determineHighestVersion(
41 OUString
const & userVersion
,
42 OUString
const & sharedVersion
,
43 OUString
const & bundledVersion
,
44 OUString
const & onlineVersion
)
47 OUString greatest
= userVersion
;
48 if (dp_misc::compareVersions(sharedVersion
, greatest
) == dp_misc::GREATER
)
51 greatest
= sharedVersion
;
53 if (dp_misc::compareVersions(bundledVersion
, greatest
) == dp_misc::GREATER
)
56 greatest
= bundledVersion
;
58 if (dp_misc::compareVersions(onlineVersion
, greatest
) == dp_misc::GREATER
)
65 Sequence
< Reference
< xml::dom::XElement
> >
66 getUpdateInformation( Reference
<deployment::XUpdateInformationProvider
> const & updateInformation
,
67 Sequence
< OUString
> const & urls
,
68 OUString
const & identifier
,
72 return updateInformation
->getUpdateInformation(urls
, identifier
);
73 } catch (const uno::RuntimeException
&) {
75 } catch (const ucb::CommandFailedException
& e
) {
77 } catch (const ucb::CommandAbortedException
&) {
78 } catch (const uno::Exception
& e
) {
82 Sequence
<Reference
< xml::dom::XElement
> >();
85 void getOwnUpdateInfos(
86 Reference
<uno::XComponentContext
> const & xContext
,
87 Reference
<deployment::XUpdateInformationProvider
> const & updateInformation
,
88 UpdateInfoMap
& inout_map
, std::vector
<std::pair
<Reference
<deployment::XPackage
>, uno::Any
> > & out_errors
,
91 bool bAllHaveOwnUpdateInformation
= true;
92 for (auto & inout
: inout_map
)
94 OSL_ASSERT(inout
.second
.extension
.is());
95 Sequence
<OUString
> urls(inout
.second
.extension
->getUpdateInformationURLs());
96 if (urls
.hasElements())
98 const OUString search_id
= dp_misc::getIdentifier(inout
.second
.extension
);
99 SAL_INFO( "extensions.update", "Searching update for " << search_id
);
101 //It is unclear from the idl if there can be a null reference returned.
102 //However all valid information should be the same
103 Sequence
<Reference
< xml::dom::XElement
> >
104 infos(getUpdateInformation(updateInformation
, urls
, search_id
, anyError
));
105 if (anyError
.hasValue())
106 out_errors
.emplace_back(inout
.second
.extension
, anyError
);
108 for (sal_Int32 j
= 0; j
< infos
.getLength(); ++j
)
110 dp_misc::DescriptionInfoset
infoset(
112 Reference
< xml::dom::XNode
>(infos
[j
], UNO_QUERY_THROW
));
113 if (!infoset
.hasDescription())
115 boost::optional
< OUString
> result_id(infoset
.getIdentifier());
118 SAL_INFO( "extensions.update", " found version "
119 << infoset
.getVersion() << " for " << *result_id
);
120 if (*result_id
!= search_id
)
122 inout
.second
.version
= infoset
.getVersion();
123 inout
.second
.info
.set(infos
[j
], UNO_QUERY_THROW
);
129 bAllHaveOwnUpdateInformation
= false;
132 out_allFound
= bAllHaveOwnUpdateInformation
;
135 void getDefaultUpdateInfos(
136 Reference
<uno::XComponentContext
> const & xContext
,
137 Reference
<deployment::XUpdateInformationProvider
> const & updateInformation
,
138 UpdateInfoMap
& inout_map
,
139 std::vector
<std::pair
<Reference
<deployment::XPackage
>, uno::Any
> > & out_errors
)
141 const OUString
sDefaultURL(dp_misc::getExtensionDefaultUpdateURL());
142 OSL_ASSERT(!sDefaultURL
.isEmpty());
145 Sequence
< Reference
< xml::dom::XElement
> >
147 getUpdateInformation(
149 Sequence
< OUString
>(&sDefaultURL
, 1), OUString(), anyError
));
150 if (anyError
.hasValue())
151 out_errors
.emplace_back(Reference
<deployment::XPackage
>(), anyError
);
152 for (sal_Int32 i
= 0; i
< infos
.getLength(); ++i
)
154 Reference
< xml::dom::XNode
> node(infos
[i
], UNO_QUERY_THROW
);
155 dp_misc::DescriptionInfoset
infoset(xContext
, node
);
156 boost::optional
< OUString
> id(infoset
.getIdentifier());
160 UpdateInfoMap::iterator j
= inout_map
.find(*id
);
161 if (j
!= inout_map
.end())
163 //skip those extension which provide its own update urls
164 if (j
->second
.extension
->getUpdateInformationURLs().getLength())
166 OUString
v(infoset
.getVersion());
167 //look for the highest version in the online repository
168 if (dp_misc::compareVersions(v
, j
->second
.version
) ==
171 j
->second
.version
= v
;
172 j
->second
.info
= node
;
178 bool containsBundledOnly(Sequence
<Reference
<deployment::XPackage
> > const & sameIdExtensions
)
180 OSL_ASSERT(sameIdExtensions
.getLength() == 3);
181 return !sameIdExtensions
[0].is() && !sameIdExtensions
[1].is() && sameIdExtensions
[2].is();
184 /** Returns true if the list of extensions are bundled extensions and there are no
185 other extensions with the same identifier in the shared or user repository.
186 If extensionList is NULL, then it is checked if there are only bundled extensions.
188 bool onlyBundledExtensions(
189 Reference
<deployment::XExtensionManager
> const & xExtMgr
,
190 std::vector
< Reference
<deployment::XPackage
> > const * extensionList
)
192 OSL_ASSERT(xExtMgr
.is());
193 bool bOnlyBundled
= true;
196 for (auto const& elem
: *extensionList
)
198 Sequence
<Reference
<deployment::XPackage
> > seqExt
= xExtMgr
->getExtensionsWithSameIdentifier(
199 dp_misc::getIdentifier(elem
), elem
->getName(), Reference
<ucb::XCommandEnvironment
>());
201 bOnlyBundled
= containsBundledOnly(seqExt
);
208 const uno::Sequence
< uno::Sequence
< Reference
<deployment::XPackage
> > > seqAllExt
=
209 xExtMgr
->getAllExtensions(Reference
<task::XAbortChannel
>(), Reference
<ucb::XCommandEnvironment
>());
211 for (int pos(0), nLen(seqAllExt
.getLength()); bOnlyBundled
&& pos
!= nLen
; ++pos
)
213 bOnlyBundled
= containsBundledOnly(seqAllExt
[pos
]);
222 OUString
getExtensionDefaultUpdateURL()
225 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("version")
226 ":Version:ExtensionUpdateURL}");
227 ::rtl::Bootstrap::expandMacros(sUrl
);
231 /* returns the index of the greatest version, starting with 0
234 UPDATE_SOURCE
isUpdateUserExtension(
235 bool bReadOnlyShared
,
236 OUString
const & userVersion
,
237 OUString
const & sharedVersion
,
238 OUString
const & bundledVersion
,
239 OUString
const & onlineVersion
)
241 UPDATE_SOURCE retVal
= UPDATE_SOURCE_NONE
;
244 if (!userVersion
.isEmpty())
246 int index
= determineHighestVersion(
247 userVersion
, sharedVersion
, bundledVersion
, onlineVersion
);
249 retVal
= UPDATE_SOURCE_SHARED
;
251 retVal
= UPDATE_SOURCE_BUNDLED
;
253 retVal
= UPDATE_SOURCE_ONLINE
;
255 else if (!sharedVersion
.isEmpty())
257 int index
= determineHighestVersion(
258 OUString(), sharedVersion
, bundledVersion
, onlineVersion
);
260 retVal
= UPDATE_SOURCE_BUNDLED
;
262 retVal
= UPDATE_SOURCE_ONLINE
;
268 if (!userVersion
.isEmpty())
270 int index
= determineHighestVersion(
271 userVersion
, sharedVersion
, bundledVersion
, onlineVersion
);
273 retVal
= UPDATE_SOURCE_SHARED
;
275 retVal
= UPDATE_SOURCE_BUNDLED
;
277 retVal
= UPDATE_SOURCE_ONLINE
;
284 UPDATE_SOURCE
isUpdateSharedExtension(
285 bool bReadOnlyShared
,
286 OUString
const & sharedVersion
,
287 OUString
const & bundledVersion
,
288 OUString
const & onlineVersion
)
291 return UPDATE_SOURCE_NONE
;
292 UPDATE_SOURCE retVal
= UPDATE_SOURCE_NONE
;
294 if (!sharedVersion
.isEmpty())
296 int index
= determineHighestVersion(
297 OUString(), sharedVersion
, bundledVersion
, onlineVersion
);
299 retVal
= UPDATE_SOURCE_BUNDLED
;
301 retVal
= UPDATE_SOURCE_ONLINE
;
306 Reference
<deployment::XPackage
>
307 getExtensionWithHighestVersion(
308 Sequence
<Reference
<deployment::XPackage
> > const & seqExt
)
310 if (!seqExt
.hasElements())
311 return Reference
<deployment::XPackage
>();
313 Reference
<deployment::XPackage
> greatest
;
314 sal_Int32 len
= seqExt
.getLength();
316 for (sal_Int32 i
= 0; i
< len
; i
++)
320 greatest
= seqExt
[i
];
323 Reference
<deployment::XPackage
> const & current
= seqExt
[i
];
324 //greatest has a value
328 if (dp_misc::compareVersions(current
->getVersion(), greatest
->getVersion()) == dp_misc::GREATER
)
334 UpdateInfo::UpdateInfo( Reference
< deployment::XPackage
> const & ext
):
340 UpdateInfoMap
getOnlineUpdateInfos(
341 Reference
<uno::XComponentContext
> const &xContext
,
342 Reference
<deployment::XExtensionManager
> const & xExtMgr
,
343 Reference
<deployment::XUpdateInformationProvider
> const & updateInformation
,
344 std::vector
<Reference
<deployment::XPackage
> > const * extensionList
,
345 std::vector
<std::pair
< Reference
<deployment::XPackage
>, uno::Any
> > & out_errors
)
347 OSL_ASSERT(xExtMgr
.is());
348 UpdateInfoMap infoMap
;
349 if (!xExtMgr
.is() || onlyBundledExtensions(xExtMgr
, extensionList
))
354 const uno::Sequence
< uno::Sequence
< Reference
<deployment::XPackage
> > > seqAllExt
= xExtMgr
->getAllExtensions(
355 Reference
<task::XAbortChannel
>(), Reference
<ucb::XCommandEnvironment
>());
357 //fill the UpdateInfoMap. key = extension identifier, value = UpdateInfo
358 for (int pos
= seqAllExt
.getLength(); pos
--; )
360 uno::Sequence
<Reference
<deployment::XPackage
> > const & seqExt
= seqAllExt
[pos
];
362 Reference
<deployment::XPackage
> extension
= getExtensionWithHighestVersion(seqExt
);
363 OSL_ASSERT(extension
.is());
365 std::pair
<UpdateInfoMap::iterator
, bool> insertRet
= infoMap
.emplace(
366 dp_misc::getIdentifier(extension
), UpdateInfo(extension
));
367 OSL_ASSERT(insertRet
.second
);
372 for (auto const& elem
: *extensionList
)
374 OSL_ASSERT(elem
.is());
375 std::pair
<UpdateInfoMap::iterator
, bool> insertRet
= infoMap
.emplace(
376 dp_misc::getIdentifier(elem
), UpdateInfo(elem
));
377 OSL_ASSERT(insertRet
.second
);
381 //Now find the update information for the extensions which provide their own
382 //URLs to update information.
383 bool bAllInfosObtained
= false;
384 getOwnUpdateInfos(xContext
, updateInformation
, infoMap
, out_errors
, bAllInfosObtained
);
386 if (!bAllInfosObtained
)
387 getDefaultUpdateInfos(xContext
, updateInformation
, infoMap
, out_errors
);
390 OUString
getHighestVersion(
391 OUString
const & sharedVersion
,
392 OUString
const & bundledVersion
,
393 OUString
const & onlineVersion
)
395 int index
= determineHighestVersion(OUString(), sharedVersion
, bundledVersion
, onlineVersion
);
398 case 1: return sharedVersion
;
399 case 2: return bundledVersion
;
400 case 3: return onlineVersion
;
401 default: OSL_ASSERT(false);
406 } //namespace dp_misc
408 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */