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