LibreOffice Module desktop (master)  1
dp_update.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <config_folders.h>
21 
22 #include <dp_update.hxx>
23 #include <dp_version.hxx>
24 #include <dp_identifier.hxx>
26 
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>
32 
33 using namespace ::com::sun::star;
34 using namespace ::com::sun::star::uno;
35 
36 
37 namespace dp_misc {
38 namespace {
39 
40 int determineHighestVersion(
41  OUString const & userVersion,
42  OUString const & sharedVersion,
43  OUString const & bundledVersion,
44  OUString const & onlineVersion)
45 {
46  int index = 0;
47  OUString greatest = userVersion;
48  if (dp_misc::compareVersions(sharedVersion, greatest) == dp_misc::GREATER)
49  {
50  index = 1;
51  greatest = sharedVersion;
52  }
53  if (dp_misc::compareVersions(bundledVersion, greatest) == dp_misc::GREATER)
54  {
55  index = 2;
56  greatest = bundledVersion;
57  }
58  if (dp_misc::compareVersions(onlineVersion, greatest) == dp_misc::GREATER)
59  {
60  index = 3;
61  }
62  return index;
63 }
64 
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)
70 {
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;
80  }
81  return
82  Sequence<Reference< xml::dom::XElement > >();
83 }
84 
85 void getOwnUpdateInfos(
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)
90 {
91  bool bAllHaveOwnUpdateInformation = true;
92  for (auto & inout : inout_map)
93  {
94  OSL_ASSERT(inout.second.extension.is());
95  Sequence<OUString> urls(inout.second.extension->getUpdateInformationURLs());
96  if (urls.hasElements())
97  {
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);
107 
108  for (sal_Int32 j = 0; j < infos.getLength(); ++j)
109  {
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;
125  }
126  }
127  else
128  {
129  bAllHaveOwnUpdateInformation = false;
130  }
131  }
132  out_allFound = bAllHaveOwnUpdateInformation;
133 }
134 
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)
140 {
141  const OUString sDefaultURL(dp_misc::getExtensionDefaultUpdateURL());
142  OSL_ASSERT(!sDefaultURL.isEmpty());
143 
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)
153  {
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;
159  }
160  UpdateInfoMap::iterator j = inout_map.find(*id);
161  if (j != inout_map.end())
162  {
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) ==
170  {
171  j->second.version = v;
172  j->second.info = node;
173  }
174  }
175  }
176 }
177 
178 bool containsBundledOnly(Sequence<Reference<deployment::XPackage> > const & sameIdExtensions)
179 {
180  OSL_ASSERT(sameIdExtensions.getLength() == 3);
181  return !sameIdExtensions[0].is() && !sameIdExtensions[1].is() && sameIdExtensions[2].is();
182 }
183 
188 bool onlyBundledExtensions(
189  Reference<deployment::XExtensionManager> const & xExtMgr,
190  std::vector< Reference<deployment::XPackage > > const * extensionList)
191 {
192  OSL_ASSERT(xExtMgr.is());
193  bool bOnlyBundled = true;
194  if (extensionList)
195  {
196  for (auto const& elem : *extensionList)
197  {
198  Sequence<Reference<deployment::XPackage> > seqExt = xExtMgr->getExtensionsWithSameIdentifier(
199  dp_misc::getIdentifier(elem), elem->getName(), Reference<ucb::XCommandEnvironment>());
200 
201  bOnlyBundled = containsBundledOnly(seqExt);
202  if (!bOnlyBundled)
203  break;
204  }
205  }
206  else
207  {
208  const uno::Sequence< uno::Sequence< Reference<deployment::XPackage > > > seqAllExt =
209  xExtMgr->getAllExtensions(Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>());
210 
211  for (int pos(0), nLen(seqAllExt.getLength()); bOnlyBundled && pos != nLen; ++pos)
212  {
213  bOnlyBundled = containsBundledOnly(seqAllExt[pos]);
214  }
215  }
216  return bOnlyBundled;
217 }
218 
219 } // anon namespace
220 
221 
223 {
224  OUString sUrl(
225  "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version")
226  ":Version:ExtensionUpdateURL}");
227  ::rtl::Bootstrap::expandMacros(sUrl);
228  return sUrl;
229 }
230 
231 /* returns the index of the greatest version, starting with 0
232 
233  */
235  bool bReadOnlyShared,
236  OUString const & userVersion,
237  OUString const & sharedVersion,
238  OUString const & bundledVersion,
239  OUString const & onlineVersion)
240 {
242  if (bReadOnlyShared)
243  {
244  if (!userVersion.isEmpty())
245  {
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;
254  }
255  else if (!sharedVersion.isEmpty())
256  {
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;
263 
264  }
265  }
266  else
267  {
268  if (!userVersion.isEmpty())
269  {
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;
278  }
279  }
280 
281  return retVal;
282 }
283 
285  bool bReadOnlyShared,
286  OUString const & sharedVersion,
287  OUString const & bundledVersion,
288  OUString const & onlineVersion)
289 {
290  if (bReadOnlyShared)
291  return UPDATE_SOURCE_NONE;
293 
294  if (!sharedVersion.isEmpty())
295  {
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;
302  }
303  return retVal;
304 }
305 
306 Reference<deployment::XPackage>
308  Sequence<Reference<deployment::XPackage> > const & seqExt)
309 {
310  if (!seqExt.hasElements())
311  return Reference<deployment::XPackage>();
312 
313  Reference<deployment::XPackage> greatest;
314  sal_Int32 len = seqExt.getLength();
315 
316  for (sal_Int32 i = 0; i < len; i++)
317  {
318  if (!greatest.is())
319  {
320  greatest = seqExt[i];
321  continue;
322  }
323  Reference<deployment::XPackage> const & current = seqExt[i];
324  //greatest has a value
325  if (! current.is())
326  continue;
327 
328  if (dp_misc::compareVersions(current->getVersion(), greatest->getVersion()) == dp_misc::GREATER)
329  greatest = current;
330  }
331  return greatest;
332 }
333 
334 UpdateInfo::UpdateInfo( Reference< deployment::XPackage> const & ext):
335 extension(ext)
336 {
337 }
338 
339 
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)
346 {
347  OSL_ASSERT(xExtMgr.is());
348  UpdateInfoMap infoMap;
349  if (!xExtMgr.is() || onlyBundledExtensions(xExtMgr, extensionList))
350  return infoMap;
351 
352  if (!extensionList)
353  {
354  const uno::Sequence< uno::Sequence< Reference<deployment::XPackage > > > seqAllExt = xExtMgr->getAllExtensions(
355  Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>());
356 
357  //fill the UpdateInfoMap. key = extension identifier, value = UpdateInfo
358  for (int pos = seqAllExt.getLength(); pos --; )
359  {
360  uno::Sequence<Reference<deployment::XPackage> > const & seqExt = seqAllExt[pos];
361 
362  Reference<deployment::XPackage> extension = getExtensionWithHighestVersion(seqExt);
363  OSL_ASSERT(extension.is());
364 
365  std::pair<UpdateInfoMap::iterator, bool> insertRet = infoMap.emplace(
366  dp_misc::getIdentifier(extension), UpdateInfo(extension));
367  OSL_ASSERT(insertRet.second);
368  }
369  }
370  else
371  {
372  for (auto const& elem : *extensionList)
373  {
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);
378  }
379  }
380 
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);
385 
386  if (!bAllInfosObtained)
387  getDefaultUpdateInfos(xContext, updateInformation, infoMap, out_errors);
388  return infoMap;
389 }
391  OUString const & sharedVersion,
392  OUString const & bundledVersion,
393  OUString const & onlineVersion)
394 {
395  int index = determineHighestVersion(OUString(), sharedVersion, bundledVersion, onlineVersion);
396  switch (index)
397  {
398  case 1: return sharedVersion;
399  case 2: return bundledVersion;
400  case 3: return onlineVersion;
401  default: OSL_ASSERT(false);
402  }
403 
404  return OUString();
405 }
406 } //namespace dp_misc
407 
408 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::map< OUString, UpdateInfo > UpdateInfoMap
Definition: dp_update.hxx:102
bool hasValue()
UpdateInfo(css::uno::Reference< css::deployment::XPackage > const &ext)
Definition: dp_update.cxx:334
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC Order compareVersions(OUString const &version1, OUString const &version2)
Definition: dp_version.cxx:42
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getExtensionDefaultUpdateURL()
returns the default update URL (for the update information) which is used when an extension does not ...
Definition: dp_update.cxx:222
#define SAL_CONFIGFILE(name)
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC UPDATE_SOURCE isUpdateSharedExtension(bool bReadOnlyShared, OUString const &sharedVersion, OUString const &bundledVersion, OUString const &onlineVersion)
Definition: dp_update.cxx:284
int i
tuple index
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC UPDATE_SOURCE isUpdateUserExtension(bool bReadOnlyShared, OUString const &userVersion, OUString const &sharedVersion, OUString const &bundledVersion, OUString const &onlineVersion)
Definition: dp_update.cxx:234
float v
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:1858
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC UpdateInfoMap getOnlineUpdateInfos(css::uno::Reference< css::uno::XComponentContext > const &xContext, css::uno::Reference< css::deployment::XExtensionManager > const &xExtMgr, css::uno::Reference< css::deployment::XUpdateInformationProvider > const &updateInformation, std::vector< css::uno::Reference< css::deployment::XPackage > > const *extensionList, std::vector< std::pair< css::uno::Reference< css::deployment::XPackage >, css::uno::Any > > &out_errors)
#define SAL_INFO(area, stream)
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getHighestVersion(OUString const &sharedVersion, OUString const &bundledVersion, OUString const &onlineVersion)
Definition: dp_update.cxx:390
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getIdentifier(css::uno::Reference< css::deployment::XPackage > const &package)
Gets the identifier of a package.
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC css::uno::Reference< css::deployment::XPackage > getExtensionWithHighestVersion(css::uno::Sequence< css::uno::Reference< css::deployment::XPackage > > const &seqExtensionsWithSameId)
Access to the content of an XML description element.