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