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 #include <cppuhelper/implbase3.hxx>
28 
29 #include "comphelper/servicedecl.hxx"
30 
31 #include "com/sun/star/deployment/UpdateInformationProvider.hpp"
32 #include "com/sun/star/deployment/XPackage.hpp"
33 #include "com/sun/star/deployment/XPackageInformationProvider.hpp"
34 #include "com/sun/star/deployment/ExtensionManager.hpp"
35 #include "com/sun/star/deployment/XUpdateInformationProvider.hpp"
36 #include "com/sun/star/lang/XServiceInfo.hpp"
37 #include "com/sun/star/registry/XRegistryKey.hpp"
38 #include "com/sun/star/task/XAbortChannel.hpp"
39 #include "com/sun/star/uno/XComponentContext.hpp"
40 #include "com/sun/star/ucb/XCommandEnvironment.hpp"
41 #include "com/sun/star/xml/dom/XElement.hpp"
42 #include "com/sun/star/xml/dom/XNode.hpp"
43 
44 #include "com/sun/star/uno/Reference.hxx"
45 #include "rtl/ustring.hxx"
46 #include "ucbhelper/content.hxx"
47 
48 #include "dp_dependencies.hxx"
49 #include "dp_descriptioninfoset.hxx"
50 #include "dp_identifier.hxx"
51 #include "dp_version.hxx"
52 #include "dp_misc.h"
53 #include "dp_update.hxx"
54 
55 namespace beans      = com::sun::star::beans ;
56 namespace deployment = com::sun::star::deployment ;
57 namespace lang       = com::sun::star::lang ;
58 namespace registry   = com::sun::star::registry ;
59 namespace task       = com::sun::star::task ;
60 namespace css_ucb    = com::sun::star::ucb ;
61 namespace uno        = com::sun::star::uno ;
62 namespace xml = com::sun::star::xml ;
63 
64 #define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s))
65 
66 namespace dp_info {
67 
68 class PackageInformationProvider :
69         public ::cppu::WeakImplHelper1< deployment::XPackageInformationProvider >
70 
71 {
72     public:
73                  PackageInformationProvider( uno::Reference< uno::XComponentContext >const& xContext);
74     virtual     ~PackageInformationProvider();
75 
76     static uno::Sequence< rtl::OUString > getServiceNames();
77     static rtl::OUString getImplName();
78 
79     // XPackageInformationProvider
80     virtual rtl::OUString SAL_CALL getPackageLocation( const rtl::OUString& extensionId )
81         throw ( uno::RuntimeException );
82     virtual uno::Sequence< uno::Sequence< rtl::OUString > > SAL_CALL isUpdateAvailable( const rtl::OUString& extensionId )
83         throw ( uno::RuntimeException );
84     virtual uno::Sequence< uno::Sequence< rtl::OUString > > SAL_CALL getExtensionList()
85         throw ( uno::RuntimeException );
86 //---------
87 private:
88 
89     uno::Reference< uno::XComponentContext> mxContext;
90 
91     rtl::OUString getPackageLocation( const rtl::OUString& repository,
92                                       const rtl::OUString& _sExtensionId );
93 
94     uno::Reference< deployment::XUpdateInformationProvider > mxUpdateInformation;
95 };
96 
97 //------------------------------------------------------------------------------
98 
99 PackageInformationProvider::PackageInformationProvider( uno::Reference< uno::XComponentContext > const& xContext) :
100     mxContext( xContext ),
101     mxUpdateInformation( deployment::UpdateInformationProvider::create( xContext ) )
102 {
103 }
104 
105 //------------------------------------------------------------------------------
106 
107 PackageInformationProvider::~PackageInformationProvider()
108 {
109 }
110 
111 //------------------------------------------------------------------------------
112 rtl::OUString PackageInformationProvider::getPackageLocation(
113     const rtl::OUString & repository,
114     const rtl::OUString& _rExtensionId )
115 {
116     rtl::OUString aLocationURL;
117     uno::Reference<deployment::XExtensionManager> xManager =
118         deployment::ExtensionManager::get(mxContext);
119 
120     if ( xManager.is() )
121     {
122         const uno::Sequence< uno::Reference< deployment::XPackage > > packages(
123                 xManager->getDeployedExtensions(
124                     repository,
125                     uno::Reference< task::XAbortChannel >(),
126                     uno::Reference< css_ucb::XCommandEnvironment > () ) );
127 
128         for ( int pos = packages.getLength(); pos--; )
129         {
130             try
131             {
132                 const rtl::OUString aName = packages[ pos ]->getName();
133                 const beans::Optional< rtl::OUString > aID = packages[ pos ]->getIdentifier();
134                 if ( aID.IsPresent && aID.Value.compareTo( _rExtensionId ) == 0 )
135                 {
136                     aLocationURL = packages[ pos ]->getURL();
137                     break;
138                 }
139             }
140             catch ( uno::RuntimeException & ) {}
141         }
142     }
143 
144     return aLocationURL;
145 }
146 
147 //------------------------------------------------------------------------------
148 //------------------------------------------------------------------------------
149 //------------------------------------------------------------------------------
150 
151 rtl::OUString SAL_CALL
152 PackageInformationProvider::getPackageLocation( const rtl::OUString& _sExtensionId )
153     throw ( uno::RuntimeException )
154 {
155     rtl::OUString aLocationURL = getPackageLocation( UNISTRING("user"), _sExtensionId );
156 
157     if ( aLocationURL.getLength() == 0 )
158     {
159         aLocationURL = getPackageLocation( UNISTRING("shared"), _sExtensionId );
160     }
161     if ( aLocationURL.getLength() == 0 )
162     {
163         aLocationURL = getPackageLocation( UNISTRING("bundled"), _sExtensionId );
164     }
165     if ( aLocationURL.getLength() )
166     {
167         ::ucbhelper::Content aContent( aLocationURL, NULL );
168         aLocationURL = aContent.getURL();
169     }
170     return aLocationURL;
171 }
172 
173 //------------------------------------------------------------------------------
174 
175 uno::Sequence< uno::Sequence< rtl::OUString > > SAL_CALL
176 PackageInformationProvider::isUpdateAvailable( const rtl::OUString& _sExtensionId )
177     throw ( uno::RuntimeException )
178 {
179     uno::Sequence< uno::Sequence< rtl::OUString > > aList;
180 
181     uno::Reference<deployment::XExtensionManager> extMgr =
182         deployment::ExtensionManager::get(mxContext);
183 
184     if (!extMgr.is())
185     {
186         OSL_ASSERT(0);
187         return aList;
188     }
189     std::vector<std::pair<uno::Reference<deployment::XPackage>, uno::Any > > errors;
190     dp_misc::UpdateInfoMap updateInfoMap;
191     if (_sExtensionId.getLength())
192     {
193         std::vector<uno::Reference<deployment::XPackage> > vecExtensions;
194         uno::Reference<deployment::XPackage> extension;
195         try
196         {
197             extension = dp_misc::getExtensionWithHighestVersion(
198                 extMgr->getExtensionsWithSameIdentifier(
199                     _sExtensionId, _sExtensionId, uno::Reference<css_ucb::XCommandEnvironment>()));
200             vecExtensions.push_back(extension);
201         }
202         catch (lang::IllegalArgumentException &)
203         {
204             OSL_ASSERT(0);
205         }
206         updateInfoMap = dp_misc::getOnlineUpdateInfos(
207             mxContext, extMgr, mxUpdateInformation, &vecExtensions, errors);
208     }
209     else
210     {
211         updateInfoMap = dp_misc::getOnlineUpdateInfos(
212             mxContext, extMgr, mxUpdateInformation, NULL, errors);
213     }
214 
215     int nCount = 0;
216     for (dp_misc::UpdateInfoMap::iterator i(updateInfoMap.begin()); i != updateInfoMap.end(); i++)
217     {
218         dp_misc::UpdateInfo const & info = i->second;
219 
220         rtl::OUString sOnlineVersion;
221         if (info.info.is())
222         {
223             // check, if there are unsatisfied dependencies and ignore this online update
224             dp_misc::DescriptionInfoset infoset(mxContext, info.info);
225             uno::Sequence< uno::Reference< xml::dom::XElement > >
226                 ds( dp_misc::Dependencies::check( infoset ) );
227             if ( ! ds.getLength() )
228                 sOnlineVersion = info.version;
229         }
230 
231         rtl::OUString sVersionUser;
232         rtl::OUString sVersionShared;
233         rtl::OUString sVersionBundled;
234         uno::Sequence< uno::Reference< deployment::XPackage> > extensions;
235         try {
236             extensions = extMgr->getExtensionsWithSameIdentifier(
237                 dp_misc::getIdentifier(info.extension), info.extension->getName(),
238                 uno::Reference<css_ucb::XCommandEnvironment>());
239         } catch (lang::IllegalArgumentException& ) {
240             OSL_ASSERT(0);
241         }
242         OSL_ASSERT(extensions.getLength() == 3);
243         if (extensions[0].is() )
244             sVersionUser = extensions[0]->getVersion();
245         if (extensions[1].is() )
246             sVersionShared = extensions[1]->getVersion();
247         if (extensions[2].is() )
248             sVersionBundled = extensions[2]->getVersion();
249 
250         bool bSharedReadOnly = extMgr->isReadOnlyRepository(OUSTR("shared"));
251 
252         dp_misc::UPDATE_SOURCE sourceUser = dp_misc::isUpdateUserExtension(
253             bSharedReadOnly, sVersionUser, sVersionShared, sVersionBundled, sOnlineVersion);
254         dp_misc::UPDATE_SOURCE sourceShared = dp_misc::isUpdateSharedExtension(
255             bSharedReadOnly, sVersionShared, sVersionBundled, sOnlineVersion);
256 
257         rtl::OUString updateVersionUser;
258         rtl::OUString updateVersionShared;
259         if (sourceUser != dp_misc::UPDATE_SOURCE_NONE)
260             updateVersionUser = dp_misc::getHighestVersion(
261                 rtl::OUString(), sVersionShared, sVersionBundled, sOnlineVersion);
262         if (sourceShared  != dp_misc::UPDATE_SOURCE_NONE)
263             updateVersionShared = dp_misc::getHighestVersion(
264                 rtl::OUString(), rtl::OUString(), sVersionBundled, sOnlineVersion);
265         rtl::OUString updateVersion;
266         if (dp_misc::compareVersions(updateVersionUser, updateVersionShared) == dp_misc::GREATER)
267             updateVersion = updateVersionUser;
268         else
269             updateVersion = updateVersionShared;
270         if (updateVersion.getLength())
271         {
272 
273             rtl::OUString aNewEntry[2];
274             aNewEntry[0] = i->first;
275             aNewEntry[1] = updateVersion;
276             aList.realloc( ++nCount );
277             aList[ nCount-1 ] = ::uno::Sequence< rtl::OUString >( aNewEntry, 2 );
278         }
279     }
280     return aList;
281 }
282 
283 //------------------------------------------------------------------------------
284 uno::Sequence< uno::Sequence< rtl::OUString > > SAL_CALL PackageInformationProvider::getExtensionList()
285     throw ( uno::RuntimeException )
286 {
287     const uno::Reference<deployment::XExtensionManager> mgr =
288         deployment::ExtensionManager::get(mxContext);
289 
290     if (!mgr.is())
291         return uno::Sequence< uno::Sequence< rtl::OUString > >();
292 
293     const uno::Sequence< uno::Sequence< uno::Reference<deployment::XPackage > > >
294         allExt =  mgr->getAllExtensions(
295             uno::Reference< task::XAbortChannel >(),
296             uno::Reference< css_ucb::XCommandEnvironment > () );
297 
298     uno::Sequence< uno::Sequence< rtl::OUString > > retList;
299 
300     sal_Int32 cAllIds = allExt.getLength();
301     retList.realloc(cAllIds);
302 
303     for (sal_Int32 i = 0; i < cAllIds; i++)
304     {
305         //The inner sequence contains extensions with the same identifier from
306         //all the different repositories, that is user, share, bundled.
307         const uno::Sequence< uno::Reference< deployment::XPackage > > &
308             seqExtension = allExt[i];
309         sal_Int32 cExt = seqExtension.getLength();
310         OSL_ASSERT(cExt == 3);
311         for (sal_Int32 j = 0; j < cExt; j++)
312         {
313             //ToDo according to the old code the first found extenions is used
314             //even if another one with the same id has a better version.
315             uno::Reference< deployment::XPackage > const & xExtension( seqExtension[j] );
316             if (xExtension.is())
317             {
318                 rtl::OUString aNewEntry[2];
319                 aNewEntry[0] = dp_misc::getIdentifier(xExtension);
320                 aNewEntry[1] = xExtension->getVersion();
321                 retList[i] = ::uno::Sequence< rtl::OUString >( aNewEntry, 2 );
322                 break;
323             }
324         }
325     }
326     return retList;
327 }
328 
329 
330 //------------------------------------------------------------------------------
331 //------------------------------------------------------------------------------
332 //------------------------------------------------------------------------------
333 
334 namespace sdecl = comphelper::service_decl;
335 sdecl::class_<PackageInformationProvider> servicePIP;
336 extern sdecl::ServiceDecl const serviceDecl(
337     servicePIP,
338     // a private one:
339     "com.sun.star.comp.deployment.PackageInformationProvider",
340     "com.sun.star.comp.deployment.PackageInformationProvider" );
341 
342 //------------------------------------------------------------------------------
343 bool singleton_entries(
344     uno::Reference< registry::XRegistryKey > const & xRegistryKey )
345 {
346     try {
347         uno::Reference< registry::XRegistryKey > xKey(
348             xRegistryKey->createKey(
349                 serviceDecl.getImplementationName() +
350                 // xxx todo: use future generated function to get singleton name
351                 UNISTRING("/UNO/SINGLETONS/"
352                       "com.sun.star.deployment.PackageInformationProvider") ) );
353         xKey->setStringValue( serviceDecl.getSupportedServiceNames()[0] );
354         return true;
355     }
356     catch (registry::InvalidRegistryException & exc) {
357         (void) exc; // avoid warnings
358         OSL_ENSURE( 0, ::rtl::OUStringToOString(
359                         exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
360         return false;
361     }
362 }
363 
364 } // namespace dp_info
365 
366 
367