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 : using ::rtl::OUString;
30 : using ::rtl::OString;
31 :
32 :
33 : namespace dp_misc {
34 : namespace {
35 :
36 0 : int determineHighestVersion(
37 : ::rtl::OUString const & userVersion,
38 : ::rtl::OUString const & sharedVersion,
39 : ::rtl::OUString const & bundledVersion,
40 : ::rtl::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 : 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 rtl::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 : ::rtl::OUString sUrl(
220 : RTL_CONSTASCII_USTRINGPARAM(
221 : "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("version")
222 0 : ":Version:ExtensionUpdateURL}"));
223 0 : ::rtl::Bootstrap::expandMacros(sUrl);
224 0 : return sUrl;
225 : }
226 :
227 : /* returns the index of the greatest version, starting with 0
228 :
229 : */
230 0 : UPDATE_SOURCE isUpdateUserExtension(
231 : bool bReadOnlyShared,
232 : ::rtl::OUString const & userVersion,
233 : ::rtl::OUString const & sharedVersion,
234 : ::rtl::OUString const & bundledVersion,
235 : ::rtl::OUString const & onlineVersion)
236 : {
237 0 : UPDATE_SOURCE retVal = UPDATE_SOURCE_NONE;
238 0 : if (bReadOnlyShared)
239 : {
240 0 : if (!userVersion.isEmpty())
241 : {
242 : int index = determineHighestVersion(
243 0 : userVersion, sharedVersion, bundledVersion, onlineVersion);
244 0 : if (index == 1)
245 0 : retVal = UPDATE_SOURCE_SHARED;
246 0 : else if (index == 2)
247 0 : retVal = UPDATE_SOURCE_BUNDLED;
248 0 : else if (index == 3)
249 0 : retVal = UPDATE_SOURCE_ONLINE;
250 : }
251 0 : else if (!sharedVersion.isEmpty())
252 : {
253 : int index = determineHighestVersion(
254 0 : OUString(), sharedVersion, bundledVersion, onlineVersion);
255 0 : if (index == 2)
256 0 : retVal = UPDATE_SOURCE_BUNDLED;
257 0 : else if (index == 3)
258 0 : retVal = UPDATE_SOURCE_ONLINE;
259 :
260 : }
261 : }
262 : else
263 : {
264 0 : if (!userVersion.isEmpty())
265 : {
266 : int index = determineHighestVersion(
267 0 : userVersion, sharedVersion, bundledVersion, onlineVersion);
268 0 : if (index == 1)
269 0 : retVal = UPDATE_SOURCE_SHARED;
270 0 : else if (index == 2)
271 0 : retVal = UPDATE_SOURCE_BUNDLED;
272 0 : else if (index == 3)
273 0 : retVal = UPDATE_SOURCE_ONLINE;
274 : }
275 : }
276 :
277 0 : return retVal;
278 : }
279 :
280 0 : UPDATE_SOURCE isUpdateSharedExtension(
281 : bool bReadOnlyShared,
282 : ::rtl::OUString const & sharedVersion,
283 : ::rtl::OUString const & bundledVersion,
284 : ::rtl::OUString const & onlineVersion)
285 : {
286 0 : if (bReadOnlyShared)
287 0 : return UPDATE_SOURCE_NONE;
288 0 : UPDATE_SOURCE retVal = UPDATE_SOURCE_NONE;
289 :
290 0 : if (!sharedVersion.isEmpty())
291 : {
292 : int index = determineHighestVersion(
293 0 : OUString(), sharedVersion, bundledVersion, onlineVersion);
294 0 : if (index == 2)
295 0 : retVal = UPDATE_SOURCE_BUNDLED;
296 0 : else if (index == 3)
297 0 : retVal = UPDATE_SOURCE_ONLINE;
298 : }
299 0 : return retVal;
300 : }
301 :
302 : Reference<deployment::XPackage>
303 0 : getExtensionWithHighestVersion(
304 : Sequence<Reference<deployment::XPackage> > const & seqExt)
305 : {
306 0 : if (seqExt.getLength() == 0)
307 0 : return Reference<deployment::XPackage>();
308 :
309 0 : Reference<deployment::XPackage> greatest;
310 0 : sal_Int32 len = seqExt.getLength();
311 :
312 0 : for (sal_Int32 i = 0; i < len; i++)
313 : {
314 0 : if (!greatest.is())
315 : {
316 0 : greatest = seqExt[i];
317 0 : continue;
318 : }
319 0 : Reference<deployment::XPackage> const & current = seqExt[i];
320 : //greatest has a value
321 0 : if (! current.is())
322 0 : continue;
323 :
324 0 : if (dp_misc::compareVersions(current->getVersion(), greatest->getVersion()) == dp_misc::GREATER)
325 0 : greatest = current;
326 : }
327 0 : return greatest;
328 : }
329 :
330 0 : UpdateInfo::UpdateInfo( Reference< deployment::XPackage> const & ext):
331 0 : extension(ext)
332 : {
333 0 : }
334 :
335 :
336 :
337 0 : UpdateInfoMap getOnlineUpdateInfos(
338 : Reference<uno::XComponentContext> const &xContext,
339 : Reference<deployment::XExtensionManager> const & xExtMgr,
340 : Reference<deployment::XUpdateInformationProvider > const & updateInformation,
341 : std::vector<Reference<deployment::XPackage > > const * extensionList,
342 : std::vector<std::pair< Reference<deployment::XPackage>, uno::Any> > & out_errors)
343 : {
344 : OSL_ASSERT(xExtMgr.is());
345 0 : UpdateInfoMap infoMap;
346 0 : if (!xExtMgr.is() || onlyBundledExtensions(xExtMgr, extensionList))
347 : return infoMap;
348 :
349 0 : if (!extensionList)
350 : {
351 0 : const uno::Sequence< uno::Sequence< Reference<deployment::XPackage > > > seqAllExt = xExtMgr->getAllExtensions(
352 0 : Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>());
353 :
354 : //fill the UpdateInfoMap. key = extension identifier, value = UpdateInfo
355 0 : for (int pos = seqAllExt.getLength(); pos --; )
356 : {
357 0 : uno::Sequence<Reference<deployment::XPackage> > const & seqExt = seqAllExt[pos];
358 :
359 0 : Reference<deployment::XPackage> extension = getExtensionWithHighestVersion(seqExt);
360 : OSL_ASSERT(extension.is());
361 :
362 : std::pair<UpdateInfoMap::iterator, bool> insertRet = infoMap.insert(
363 : UpdateInfoMap::value_type(
364 0 : dp_misc::getIdentifier(extension), UpdateInfo(extension)));
365 : OSL_ASSERT(insertRet.second == true);
366 : (void)insertRet;
367 0 : }
368 : }
369 : else
370 : {
371 : typedef std::vector<Reference<deployment::XPackage > >::const_iterator CIT;
372 0 : for (CIT i = extensionList->begin(); i != extensionList->end(); ++i)
373 : {
374 : OSL_ASSERT(i->is());
375 : std::pair<UpdateInfoMap::iterator, bool> insertRet = infoMap.insert(
376 : UpdateInfoMap::value_type(
377 0 : dp_misc::getIdentifier(*i), UpdateInfo(*i)));
378 : OSL_ASSERT(insertRet.second == true);
379 : (void)insertRet;
380 : }
381 : }
382 :
383 : //Now find the update information for the extensions which provide their own
384 : //URLs to update information.
385 0 : bool allInfosObtained = false;
386 0 : getOwnUpdateInfos(xContext, updateInformation, infoMap, out_errors, allInfosObtained);
387 :
388 0 : if (!allInfosObtained)
389 0 : getDefaultUpdateInfos(xContext, updateInformation, infoMap, out_errors);
390 0 : return infoMap;
391 : }
392 0 : OUString getHighestVersion(
393 : ::rtl::OUString const & userVersion,
394 : ::rtl::OUString const & sharedVersion,
395 : ::rtl::OUString const & bundledVersion,
396 : ::rtl::OUString const & onlineVersion)
397 : {
398 0 : int index = determineHighestVersion(userVersion, sharedVersion, bundledVersion, onlineVersion);
399 0 : switch (index)
400 : {
401 0 : case 0: return userVersion;
402 0 : case 1: return sharedVersion;
403 0 : case 2: return bundledVersion;
404 0 : case 3: return onlineVersion;
405 : default: OSL_ASSERT(0);
406 : }
407 :
408 0 : return OUString();
409 : }
410 : } //namespace dp_misc
411 :
412 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|