Line data Source code
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"
25 : #include "dp_descriptioninfoset.hxx"
26 :
27 : #include "rtl/bootstrap.hxx"
28 :
29 : using namespace ::com::sun::star;
30 : using namespace ::com::sun::star::uno;
31 :
32 :
33 : namespace dp_misc {
34 : namespace {
35 :
36 0 : int determineHighestVersion(
37 : OUString const & userVersion,
38 : OUString const & sharedVersion,
39 : OUString const & bundledVersion,
40 : OUString const & onlineVersion)
41 : {
42 0 : int index = 0;
43 0 : OUString greatest = userVersion;
44 0 : if (dp_misc::compareVersions(sharedVersion, greatest) == dp_misc::GREATER)
45 : {
46 0 : index = 1;
47 0 : greatest = sharedVersion;
48 : }
49 0 : if (dp_misc::compareVersions(bundledVersion, greatest) == dp_misc::GREATER)
50 : {
51 0 : index = 2;
52 0 : greatest = bundledVersion;
53 : }
54 0 : if (dp_misc::compareVersions(onlineVersion, greatest) == dp_misc::GREATER)
55 : {
56 0 : index = 3;
57 : }
58 0 : return index;
59 : }
60 :
61 : Sequence< Reference< xml::dom::XElement > >
62 0 : getUpdateInformation( Reference<deployment::XUpdateInformationProvider > const & updateInformation,
63 : Sequence< OUString > const & urls,
64 : OUString const & identifier,
65 : uno::Any & out_error)
66 : {
67 : try {
68 0 : return updateInformation->getUpdateInformation(urls, identifier);
69 0 : } catch (const uno::RuntimeException &) {
70 0 : throw;
71 0 : } catch (const ucb::CommandFailedException & e) {
72 0 : out_error = e.Reason;
73 0 : } catch (const ucb::CommandAbortedException &) {
74 0 : } catch (const uno::Exception & e) {
75 0 : out_error = uno::makeAny(e);
76 : }
77 : return
78 0 : Sequence<Reference< xml::dom::XElement > >();
79 : }
80 :
81 0 : void getOwnUpdateInfos(
82 : Reference<uno::XComponentContext> const & xContext,
83 : Reference<deployment::XUpdateInformationProvider > const & updateInformation,
84 : UpdateInfoMap& inout_map, std::vector<std::pair<Reference<deployment::XPackage>, uno::Any> > & out_errors,
85 : bool & out_allFound)
86 : {
87 0 : bool allHaveOwnUpdateInformation = true;
88 0 : for (UpdateInfoMap::iterator i = inout_map.begin(); i != inout_map.end(); ++i)
89 : {
90 : OSL_ASSERT(i->second.extension.is());
91 0 : Sequence<OUString> urls(i->second.extension->getUpdateInformationURLs());
92 0 : if (urls.getLength())
93 : {
94 0 : const OUString id = dp_misc::getIdentifier(i->second.extension);
95 0 : uno::Any anyError;
96 : //It is unclear from the idl if there can be a null reference returned.
97 : //However all valid information should be the same
98 : Sequence<Reference< xml::dom::XElement > >
99 0 : infos(getUpdateInformation(updateInformation, urls, id, anyError));
100 0 : if (anyError.hasValue())
101 0 : out_errors.push_back(std::make_pair(i->second.extension, anyError));
102 :
103 0 : for (sal_Int32 j = 0; j < infos.getLength(); ++j)
104 : {
105 : dp_misc::DescriptionInfoset infoset(
106 : xContext,
107 0 : Reference< xml::dom::XNode >(infos[j], UNO_QUERY_THROW));
108 0 : if (!infoset.hasDescription())
109 0 : continue;
110 0 : boost::optional< OUString > id2(infoset.getIdentifier());
111 0 : if (!id2)
112 0 : continue;
113 : OSL_ASSERT(*id2 == id);
114 0 : if (*id2 == id)
115 : {
116 0 : i->second.version = infoset.getVersion();
117 0 : i->second.info = Reference< xml::dom::XNode >(
118 0 : infos[j], UNO_QUERY_THROW);
119 : }
120 0 : break;
121 0 : }
122 : }
123 : else
124 : {
125 0 : allHaveOwnUpdateInformation &= false;
126 : }
127 0 : }
128 0 : out_allFound = allHaveOwnUpdateInformation;
129 0 : }
130 :
131 0 : void getDefaultUpdateInfos(
132 : Reference<uno::XComponentContext> const & xContext,
133 : Reference<deployment::XUpdateInformationProvider > const & updateInformation,
134 : UpdateInfoMap& inout_map,
135 : std::vector<std::pair<Reference<deployment::XPackage>, uno::Any> > & out_errors)
136 : {
137 0 : const OUString sDefaultURL(dp_misc::getExtensionDefaultUpdateURL());
138 : OSL_ASSERT(!sDefaultURL.isEmpty());
139 :
140 0 : Any anyError;
141 : Sequence< Reference< xml::dom::XElement > >
142 : infos(
143 : getUpdateInformation(
144 : updateInformation,
145 0 : Sequence< OUString >(&sDefaultURL, 1), OUString(), anyError));
146 0 : if (anyError.hasValue())
147 0 : out_errors.push_back(std::make_pair(Reference<deployment::XPackage>(), anyError));
148 0 : for (sal_Int32 i = 0; i < infos.getLength(); ++i)
149 : {
150 0 : Reference< xml::dom::XNode > node(infos[i], UNO_QUERY_THROW);
151 0 : dp_misc::DescriptionInfoset infoset(xContext, node);
152 0 : boost::optional< OUString > id(infoset.getIdentifier());
153 0 : if (!id) {
154 0 : continue;
155 : }
156 0 : UpdateInfoMap::iterator j = inout_map.find(*id);
157 0 : if (j != inout_map.end())
158 : {
159 : //skip those extension which provide its own update urls
160 0 : if (j->second.extension->getUpdateInformationURLs().getLength())
161 0 : continue;
162 0 : OUString v(infoset.getVersion());
163 : //look for the highest version in the online repository
164 0 : if (dp_misc::compareVersions(v, j->second.version) ==
165 : dp_misc::GREATER)
166 : {
167 0 : j->second.version = v;
168 0 : j->second.info = node;
169 0 : }
170 : }
171 0 : }
172 0 : }
173 :
174 0 : bool containsBundledOnly(Sequence<Reference<deployment::XPackage> > const & sameIdExtensions)
175 : {
176 : OSL_ASSERT(sameIdExtensions.getLength() == 3);
177 0 : return !sameIdExtensions[0].is() && !sameIdExtensions[1].is() && sameIdExtensions[2].is();
178 : }
179 :
180 : /** Returns true if the list of extensions are bundled extensions and there are no
181 : other extensions with the same identifier in the shared or user repository.
182 : If extensionList is NULL, then it is checked if there are only bundled extensions.
183 : */
184 0 : bool onlyBundledExtensions(
185 : Reference<deployment::XExtensionManager> const & xExtMgr,
186 : std::vector< Reference<deployment::XPackage > > const * extensionList)
187 : {
188 : OSL_ASSERT(xExtMgr.is());
189 0 : bool onlyBundled = true;
190 0 : if (extensionList)
191 : {
192 : typedef std::vector<Reference<deployment::XPackage > >::const_iterator CIT;
193 0 : for (CIT i(extensionList->begin()), aEnd(extensionList->end()); onlyBundled && i != aEnd; ++i)
194 : {
195 0 : Sequence<Reference<deployment::XPackage> > seqExt = xExtMgr->getExtensionsWithSameIdentifier(
196 0 : dp_misc::getIdentifier(*i), (*i)->getName(), Reference<ucb::XCommandEnvironment>());
197 :
198 0 : onlyBundled = containsBundledOnly(seqExt);
199 0 : }
200 : }
201 : else
202 : {
203 : const uno::Sequence< uno::Sequence< Reference<deployment::XPackage > > > seqAllExt =
204 0 : xExtMgr->getAllExtensions(Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>());
205 :
206 0 : for (int pos(0), nLen(seqAllExt.getLength()); onlyBundled && pos != nLen; ++pos)
207 : {
208 0 : onlyBundled = containsBundledOnly(seqAllExt[pos]);
209 0 : }
210 : }
211 0 : return onlyBundled;
212 : }
213 :
214 : } // anon namespace
215 :
216 :
217 0 : OUString getExtensionDefaultUpdateURL()
218 : {
219 : OUString sUrl(
220 : "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version")
221 0 : ":Version:ExtensionUpdateURL}");
222 0 : ::rtl::Bootstrap::expandMacros(sUrl);
223 0 : return sUrl;
224 : }
225 :
226 : /* returns the index of the greatest version, starting with 0
227 :
228 : */
229 0 : UPDATE_SOURCE isUpdateUserExtension(
230 : bool bReadOnlyShared,
231 : OUString const & userVersion,
232 : OUString const & sharedVersion,
233 : OUString const & bundledVersion,
234 : OUString const & onlineVersion)
235 : {
236 0 : UPDATE_SOURCE retVal = UPDATE_SOURCE_NONE;
237 0 : if (bReadOnlyShared)
238 : {
239 0 : if (!userVersion.isEmpty())
240 : {
241 : int index = determineHighestVersion(
242 0 : userVersion, sharedVersion, bundledVersion, onlineVersion);
243 0 : if (index == 1)
244 0 : retVal = UPDATE_SOURCE_SHARED;
245 0 : else if (index == 2)
246 0 : retVal = UPDATE_SOURCE_BUNDLED;
247 0 : else if (index == 3)
248 0 : retVal = UPDATE_SOURCE_ONLINE;
249 : }
250 0 : else if (!sharedVersion.isEmpty())
251 : {
252 : int index = determineHighestVersion(
253 0 : OUString(), sharedVersion, bundledVersion, onlineVersion);
254 0 : if (index == 2)
255 0 : retVal = UPDATE_SOURCE_BUNDLED;
256 0 : else if (index == 3)
257 0 : retVal = UPDATE_SOURCE_ONLINE;
258 :
259 : }
260 : }
261 : else
262 : {
263 0 : if (!userVersion.isEmpty())
264 : {
265 : int index = determineHighestVersion(
266 0 : userVersion, sharedVersion, bundledVersion, onlineVersion);
267 0 : if (index == 1)
268 0 : retVal = UPDATE_SOURCE_SHARED;
269 0 : else if (index == 2)
270 0 : retVal = UPDATE_SOURCE_BUNDLED;
271 0 : else if (index == 3)
272 0 : retVal = UPDATE_SOURCE_ONLINE;
273 : }
274 : }
275 :
276 0 : return retVal;
277 : }
278 :
279 0 : UPDATE_SOURCE isUpdateSharedExtension(
280 : bool bReadOnlyShared,
281 : OUString const & sharedVersion,
282 : OUString const & bundledVersion,
283 : OUString const & onlineVersion)
284 : {
285 0 : if (bReadOnlyShared)
286 0 : return UPDATE_SOURCE_NONE;
287 0 : UPDATE_SOURCE retVal = UPDATE_SOURCE_NONE;
288 :
289 0 : if (!sharedVersion.isEmpty())
290 : {
291 : int index = determineHighestVersion(
292 0 : OUString(), sharedVersion, bundledVersion, onlineVersion);
293 0 : if (index == 2)
294 0 : retVal = UPDATE_SOURCE_BUNDLED;
295 0 : else if (index == 3)
296 0 : retVal = UPDATE_SOURCE_ONLINE;
297 : }
298 0 : return retVal;
299 : }
300 :
301 : Reference<deployment::XPackage>
302 0 : getExtensionWithHighestVersion(
303 : Sequence<Reference<deployment::XPackage> > const & seqExt)
304 : {
305 0 : if (seqExt.getLength() == 0)
306 0 : return Reference<deployment::XPackage>();
307 :
308 0 : Reference<deployment::XPackage> greatest;
309 0 : sal_Int32 len = seqExt.getLength();
310 :
311 0 : for (sal_Int32 i = 0; i < len; i++)
312 : {
313 0 : if (!greatest.is())
314 : {
315 0 : greatest = seqExt[i];
316 0 : continue;
317 : }
318 0 : Reference<deployment::XPackage> const & current = seqExt[i];
319 : //greatest has a value
320 0 : if (! current.is())
321 0 : continue;
322 :
323 0 : if (dp_misc::compareVersions(current->getVersion(), greatest->getVersion()) == dp_misc::GREATER)
324 0 : greatest = current;
325 : }
326 0 : return greatest;
327 : }
328 :
329 0 : UpdateInfo::UpdateInfo( Reference< deployment::XPackage> const & ext):
330 0 : extension(ext)
331 : {
332 0 : }
333 :
334 :
335 :
336 0 : UpdateInfoMap getOnlineUpdateInfos(
337 : Reference<uno::XComponentContext> const &xContext,
338 : Reference<deployment::XExtensionManager> const & xExtMgr,
339 : Reference<deployment::XUpdateInformationProvider > const & updateInformation,
340 : std::vector<Reference<deployment::XPackage > > const * extensionList,
341 : std::vector<std::pair< Reference<deployment::XPackage>, uno::Any> > & out_errors)
342 : {
343 : OSL_ASSERT(xExtMgr.is());
344 0 : UpdateInfoMap infoMap;
345 0 : if (!xExtMgr.is() || onlyBundledExtensions(xExtMgr, extensionList))
346 0 : return infoMap;
347 :
348 0 : if (!extensionList)
349 : {
350 0 : const uno::Sequence< uno::Sequence< Reference<deployment::XPackage > > > seqAllExt = xExtMgr->getAllExtensions(
351 0 : Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>());
352 :
353 : //fill the UpdateInfoMap. key = extension identifier, value = UpdateInfo
354 0 : for (int pos = seqAllExt.getLength(); pos --; )
355 : {
356 0 : uno::Sequence<Reference<deployment::XPackage> > const & seqExt = seqAllExt[pos];
357 :
358 0 : Reference<deployment::XPackage> extension = getExtensionWithHighestVersion(seqExt);
359 : OSL_ASSERT(extension.is());
360 :
361 : std::pair<UpdateInfoMap::iterator, bool> insertRet = infoMap.insert(
362 : UpdateInfoMap::value_type(
363 0 : dp_misc::getIdentifier(extension), UpdateInfo(extension)));
364 : OSL_ASSERT(insertRet.second == true);
365 : (void)insertRet;
366 0 : }
367 : }
368 : else
369 : {
370 : typedef std::vector<Reference<deployment::XPackage > >::const_iterator CIT;
371 0 : for (CIT i = extensionList->begin(); i != extensionList->end(); ++i)
372 : {
373 : OSL_ASSERT(i->is());
374 : std::pair<UpdateInfoMap::iterator, bool> insertRet = infoMap.insert(
375 : UpdateInfoMap::value_type(
376 0 : dp_misc::getIdentifier(*i), UpdateInfo(*i)));
377 : OSL_ASSERT(insertRet.second == true);
378 : (void)insertRet;
379 : }
380 : }
381 :
382 : //Now find the update information for the extensions which provide their own
383 : //URLs to update information.
384 0 : bool allInfosObtained = false;
385 0 : getOwnUpdateInfos(xContext, updateInformation, infoMap, out_errors, allInfosObtained);
386 :
387 0 : if (!allInfosObtained)
388 0 : getDefaultUpdateInfos(xContext, updateInformation, infoMap, out_errors);
389 0 : return infoMap;
390 : }
391 0 : OUString getHighestVersion(
392 : OUString const & userVersion,
393 : OUString const & sharedVersion,
394 : OUString const & bundledVersion,
395 : OUString const & onlineVersion)
396 : {
397 0 : int index = determineHighestVersion(userVersion, sharedVersion, bundledVersion, onlineVersion);
398 0 : switch (index)
399 : {
400 0 : case 0: return userVersion;
401 0 : case 1: return sharedVersion;
402 0 : case 2: return bundledVersion;
403 0 : case 3: return onlineVersion;
404 : default: OSL_ASSERT(false);
405 : }
406 :
407 0 : return OUString();
408 : }
409 : } //namespace dp_misc
410 :
411 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|