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