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