Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / desktop / source / deployment / misc / dp_update.cxx
blob38b37d1da873ff67e0695563390d5117c5d859ac
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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;
37 namespace dp_misc {
38 namespace {
40 int determineHighestVersion(
41 OUString const & userVersion,
42 OUString const & sharedVersion,
43 OUString const & bundledVersion,
44 OUString const & onlineVersion)
46 int index = 0;
47 OUString greatest = userVersion;
48 if (dp_misc::compareVersions(sharedVersion, greatest) == dp_misc::GREATER)
50 index = 1;
51 greatest = sharedVersion;
53 if (dp_misc::compareVersions(bundledVersion, greatest) == dp_misc::GREATER)
55 index = 2;
56 greatest = bundledVersion;
58 if (dp_misc::compareVersions(onlineVersion, greatest) == dp_misc::GREATER)
60 index = 3;
62 return index;
65 Sequence< Reference< xml::dom::XElement > >
66 getUpdateInformation( Reference<deployment::XUpdateInformationProvider > const & updateInformation,
67 Sequence< OUString > const & urls,
68 OUString const & identifier,
69 uno::Any & out_error)
71 try {
72 return updateInformation->getUpdateInformation(urls, identifier);
73 } catch (const uno::RuntimeException &) {
74 throw;
75 } catch (const ucb::CommandFailedException & e) {
76 out_error = e.Reason;
77 } catch (const ucb::CommandAbortedException &) {
78 } catch (const uno::Exception & e) {
79 out_error <<= e;
81 return
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,
89 bool & out_allFound)
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 );
100 uno::Any anyError;
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(
111 xContext,
112 Reference< xml::dom::XNode >(infos[j], UNO_QUERY_THROW));
113 if (!infoset.hasDescription())
114 continue;
115 boost::optional< OUString > result_id(infoset.getIdentifier());
116 if (!result_id)
117 continue;
118 SAL_INFO( "extensions.update", " found version "
119 << infoset.getVersion() << " for " << *result_id );
120 if (*result_id != search_id)
121 continue;
122 inout.second.version = infoset.getVersion();
123 inout.second.info.set(infos[j], UNO_QUERY_THROW);
124 break;
127 else
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());
144 Any anyError;
145 Sequence< Reference< xml::dom::XElement > >
146 infos(
147 getUpdateInformation(
148 updateInformation,
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());
157 if (!id) {
158 continue;
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())
165 continue;
166 OUString v(infoset.getVersion());
167 //look for the highest version in the online repository
168 if (dp_misc::compareVersions(v, j->second.version) ==
169 dp_misc::GREATER)
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;
194 if (extensionList)
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);
202 if (!bOnlyBundled)
203 break;
206 else
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]);
216 return bOnlyBundled;
219 } // anon namespace
222 OUString getExtensionDefaultUpdateURL()
224 OUString sUrl(
225 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version")
226 ":Version:ExtensionUpdateURL}");
227 ::rtl::Bootstrap::expandMacros(sUrl);
228 return 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;
242 if (bReadOnlyShared)
244 if (!userVersion.isEmpty())
246 int index = determineHighestVersion(
247 userVersion, sharedVersion, bundledVersion, onlineVersion);
248 if (index == 1)
249 retVal = UPDATE_SOURCE_SHARED;
250 else if (index == 2)
251 retVal = UPDATE_SOURCE_BUNDLED;
252 else if (index == 3)
253 retVal = UPDATE_SOURCE_ONLINE;
255 else if (!sharedVersion.isEmpty())
257 int index = determineHighestVersion(
258 OUString(), sharedVersion, bundledVersion, onlineVersion);
259 if (index == 2)
260 retVal = UPDATE_SOURCE_BUNDLED;
261 else if (index == 3)
262 retVal = UPDATE_SOURCE_ONLINE;
266 else
268 if (!userVersion.isEmpty())
270 int index = determineHighestVersion(
271 userVersion, sharedVersion, bundledVersion, onlineVersion);
272 if (index == 1)
273 retVal = UPDATE_SOURCE_SHARED;
274 else if (index == 2)
275 retVal = UPDATE_SOURCE_BUNDLED;
276 else if (index == 3)
277 retVal = UPDATE_SOURCE_ONLINE;
281 return retVal;
284 UPDATE_SOURCE isUpdateSharedExtension(
285 bool bReadOnlyShared,
286 OUString const & sharedVersion,
287 OUString const & bundledVersion,
288 OUString const & onlineVersion)
290 if (bReadOnlyShared)
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);
298 if (index == 2)
299 retVal = UPDATE_SOURCE_BUNDLED;
300 else if (index == 3)
301 retVal = UPDATE_SOURCE_ONLINE;
303 return retVal;
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++)
318 if (!greatest.is())
320 greatest = seqExt[i];
321 continue;
323 Reference<deployment::XPackage> const & current = seqExt[i];
324 //greatest has a value
325 if (! current.is())
326 continue;
328 if (dp_misc::compareVersions(current->getVersion(), greatest->getVersion()) == dp_misc::GREATER)
329 greatest = current;
331 return greatest;
334 UpdateInfo::UpdateInfo( Reference< deployment::XPackage> const & ext):
335 extension(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))
350 return infoMap;
352 if (!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);
370 else
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);
388 return infoMap;
390 OUString getHighestVersion(
391 OUString const & sharedVersion,
392 OUString const & bundledVersion,
393 OUString const & onlineVersion)
395 int index = determineHighestVersion(OUString(), sharedVersion, bundledVersion, onlineVersion);
396 switch (index)
398 case 1: return sharedVersion;
399 case 2: return bundledVersion;
400 case 3: return onlineVersion;
401 default: OSL_ASSERT(false);
404 return OUString();
406 } //namespace dp_misc
408 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */