xref: /AOO41X/main/desktop/source/deployment/registry/package/dp_package.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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 "dp_package.hrc"
32 #include "dp_backend.h"
33 #include "dp_ucb.h"
34 #include "dp_interact.h"
35 #include "dp_dependencies.hxx"
36 #include "dp_platform.hxx"
37 #include "dp_descriptioninfoset.hxx"
38 #include "dp_identifier.hxx"
39 #include "rtl/uri.hxx"
40 #include "cppuhelper/exc_hlp.hxx"
41 #include "cppuhelper/implbase1.hxx"
42 #include "ucbhelper/content.hxx"
43 #include "svl/inettype.hxx"
44 #include "comphelper/anytostring.hxx"
45 #include "comphelper/makesequence.hxx"
46 #include "comphelper/sequence.hxx"
47 #include "com/sun/star/lang/WrappedTargetException.hpp"
48 #include "com/sun/star/lang/XServiceInfo.hpp"
49 #include "com/sun/star/beans/UnknownPropertyException.hpp"
50 #include "com/sun/star/graphic/XGraphic.hpp"
51 #include "com/sun/star/graphic/XGraphicProvider.hpp"
52 #include "com/sun/star/io/XOutputStream.hpp"
53 #include "com/sun/star/io/XInputStream.hpp"
54 #include "com/sun/star/task/InteractionClassification.hpp"
55 #include "com/sun/star/task/XInteractionApprove.hpp"
56 #include "com/sun/star/ucb/XInteractionReplaceExistingData.hpp"
57 #include "com/sun/star/ucb/NameClashResolveRequest.hpp"
58 #include "com/sun/star/ucb/XContentAccess.hpp"
59 #include "com/sun/star/ucb/NameClash.hpp"
60 #include "com/sun/star/ucb/UnsupportedCommandException.hpp"
61 #include "com/sun/star/sdbc/XResultSet.hpp"
62 #include "com/sun/star/sdbc/XRow.hpp"
63 #include "com/sun/star/packages/manifest/XManifestReader.hpp"
64 #include "com/sun/star/packages/manifest/XManifestWriter.hpp"
65 #include "com/sun/star/deployment/DependencyException.hpp"
66 #include "com/sun/star/deployment/LicenseException.hpp"
67 #include "com/sun/star/deployment/PlatformException.hpp"
68 #include "com/sun/star/deployment/Prerequisites.hpp"
69 #include "com/sun/star/xml/dom/XDocumentBuilder.hpp"
70 #include "com/sun/star/xml/xpath/XXPathAPI.hpp"
71 #include "com/sun/star/deployment/XPackageManager.hpp"
72 #include "boost/optional.hpp"
73 #include <vector>
74 #include <stdio.h>
75 
76 #include "dp_extbackenddb.hxx"
77 using namespace ::dp_misc;
78 using namespace ::com::sun::star;
79 using namespace ::com::sun::star::uno;
80 
81 namespace css = ::com::sun::star;
82 
83 using ::rtl::OUString;
84 
85 namespace dp_registry {
86 namespace backend {
87 namespace bundle {
88 namespace {
89 
90 typedef cppu::ImplInheritanceHelper1<PackageRegistryBackend,
91                                      lang::XServiceInfo> ImplBaseT;
92 
93 //==============================================================================
94 class BackendImpl : public ImplBaseT
95 {
96     class PackageImpl : public ::dp_registry::backend::Package
97     {
98         BackendImpl * getMyBackend() const;
99         /** constains the old tooltip description for the Extension Manager GUI in OOo v.2.x
100             We keep it for backward compatibility.
101         */
102         OUString m_oldDescription;
103         OUString m_url_expanded;
104         const bool m_legacyBundle;
105         Sequence< Reference<deployment::XPackage> > m_bundle;
106         Sequence< Reference<deployment::XPackage> > * m_pBundle;
107 
108         ExtensionBackendDb::Data m_dbData;
109 
110         Reference<deployment::XPackage> bindBundleItem(
111             OUString const & url, OUString const & mediaType,
112             sal_Bool bRemoved, //that is, useing data base information
113             OUString const & identifier,
114             Reference<ucb::XCommandEnvironment> const & xCmdEnv,
115             bool notifyDetectionError = true );
116 
117         typedef ::std::vector< Reference<deployment::XPackage> > t_packagevec;
118         void scanBundle(
119             t_packagevec & bundle,
120             ::rtl::Reference<AbortChannel> const & abortChannel,
121             Reference<ucb::XCommandEnvironment> const & xCmdEnv );
122         void scanLegacyBundle(
123             t_packagevec & bundle,
124             OUString const & url,
125             ::rtl::Reference<AbortChannel> const & abortChannel,
126             Reference<ucb::XCommandEnvironment> const & xCmdEnv,
127             bool skip_registration = false );
128         ::std::vector<Reference<deployment::XPackage> > getPackagesFromDb(
129             Reference<ucb::XCommandEnvironment> const & xCmdEnv);
130         bool checkPlatform(
131             Reference<ucb::XCommandEnvironment > const &  environment);
132 
133         bool checkDependencies(
134             Reference<ucb::XCommandEnvironment > const &
135                 environment,
136             DescriptionInfoset const & description);
137             // throws css::uno::RuntimeException,
138             // css::deployment::DeploymentException
139 
140 		::sal_Bool checkLicense(
141 			Reference< ucb::XCommandEnvironment > const & xCmdEnv,
142             DescriptionInfoset const & description, bool bNoLicenseChecking)
143 				throw (deployment::DeploymentException,
144                        ucb::CommandFailedException,
145                        ucb::CommandAbortedException,
146                        RuntimeException);
147         // @throws DeploymentException
148 		OUString getTextFromURL(
149 			const Reference< ucb::XCommandEnvironment >& xCmdEnv,
150 			const OUString& licenseUrl);
151 
152         DescriptionInfoset getDescriptionInfoset();
153 
154         // Package
155         virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
156             ::osl::ResettableMutexGuard & guard,
157             ::rtl::Reference<AbortChannel> const & abortChannel,
158             Reference<ucb::XCommandEnvironment> const & xCmdEnv );
159         virtual void processPackage_(
160             ::osl::ResettableMutexGuard & guard,
161             bool registerPackage,
162             bool startup,
163             ::rtl::Reference<AbortChannel> const & abortChannel,
164             Reference<ucb::XCommandEnvironment> const & xCmdEnv );
165 
166         virtual void SAL_CALL disposing();
167 
168 
169 
170     public:
171         PackageImpl(
172             ::rtl::Reference<PackageRegistryBackend> const & myBackend,
173             OUString const & url,
174             OUString const & name,
175             Reference<deployment::XPackageTypeInfo> const & xPackageType,
176             bool legacyBundle,
177             bool bRemoved,
178             OUString const & identifier);
179 
180         // XPackage
181         virtual sal_Bool SAL_CALL isBundle() throw (RuntimeException);
182 
183         virtual Sequence< Reference<deployment::XPackage> > SAL_CALL getBundle(
184             Reference<task::XAbortChannel> const & xAbortChannel,
185             Reference<ucb::XCommandEnvironment> const & xCmdEnv )
186             throw (deployment::DeploymentException,
187                    ucb::CommandFailedException,
188                    ucb::CommandAbortedException,
189                    lang::IllegalArgumentException, RuntimeException);
190         virtual OUString SAL_CALL getDescription()
191             throw (deployment::ExtensionRemovedException, RuntimeException);
192 
193         virtual OUString SAL_CALL getLicenseText()
194             throw (deployment::ExtensionRemovedException, RuntimeException);
195 
196         virtual void SAL_CALL exportTo(
197             OUString const & destFolderURL, OUString const & newTitle,
198             sal_Int32 nameClashAction,
199             Reference<ucb::XCommandEnvironment> const & xCmdEnv )
200             throw (deployment::ExtensionRemovedException,
201                    ucb::CommandFailedException,
202                    ucb::CommandAbortedException,
203                    RuntimeException);
204 
205 	    virtual ::sal_Int32 SAL_CALL checkPrerequisites(
206 			const Reference< task::XAbortChannel >& xAbortChannel,
207 			const Reference< ucb::XCommandEnvironment >& xCmdEnv,
208             ::sal_Bool noLicenseChecking)
209 			throw (deployment::ExtensionRemovedException,
210                    deployment::DeploymentException,
211                    ucb::CommandFailedException,
212                    ucb::CommandAbortedException,
213                    RuntimeException);
214 
215 	    virtual ::sal_Bool SAL_CALL checkDependencies(
216 			const Reference< ucb::XCommandEnvironment >& xCmdEnv )
217 			throw (deployment::DeploymentException,
218                    deployment::ExtensionRemovedException,
219                    ucb::CommandFailedException,
220                    RuntimeException);
221 
222         virtual beans::Optional<OUString> SAL_CALL getIdentifier()
223             throw (RuntimeException);
224 
225         virtual OUString SAL_CALL getVersion()
226             throw (deployment::ExtensionRemovedException, RuntimeException);
227 
228         virtual Sequence<OUString> SAL_CALL getUpdateInformationURLs()
229             throw (deployment::ExtensionRemovedException, RuntimeException);
230 
231         virtual beans::StringPair SAL_CALL getPublisherInfo()
232             throw (deployment::ExtensionRemovedException, RuntimeException);
233 
234         virtual OUString SAL_CALL getDisplayName()
235             throw (deployment::ExtensionRemovedException, RuntimeException);
236 
237         virtual Reference< graphic::XGraphic > SAL_CALL
238         getIcon( ::sal_Bool bHighContrast )
239             throw (deployment::ExtensionRemovedException,
240                    RuntimeException);
241     };
242     friend class PackageImpl;
243 
244     Reference<deployment::XPackageRegistry> m_xRootRegistry;
245     const Reference<deployment::XPackageTypeInfo> m_xBundleTypeInfo;
246     const Reference<deployment::XPackageTypeInfo> m_xLegacyBundleTypeInfo;
247     Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos;
248 
249     std::auto_ptr<ExtensionBackendDb> m_backendDb;
250 
251     void addDataToDb(OUString const & url, ExtensionBackendDb::Data const & data);
252     ExtensionBackendDb::Data readDataFromDb(OUString const & url);
253     void revokeEntryFromDb(OUString const & url);
254 
255     // PackageRegistryBackend
256     virtual Reference<deployment::XPackage> bindPackage_(
257         OUString const & url, OUString const & mediaType,
258         sal_Bool bRemoved, OUString const & identifier,
259         Reference<ucb::XCommandEnvironment> const & xCmdEnv );
260 
261     virtual void SAL_CALL disposing();
262 
263 public:
264     BackendImpl(
265         Sequence<Any> const & args,
266         Reference<XComponentContext> const & xComponentContext,
267         Reference<deployment::XPackageRegistry> const & xRootRegistry );
268 
269     // XServiceInfo
270     virtual OUString SAL_CALL getImplementationName() throw (RuntimeException);
271     virtual sal_Bool SAL_CALL supportsService( OUString const& name )
272         throw (RuntimeException);
273     virtual Sequence<OUString> SAL_CALL getSupportedServiceNames()
274         throw (RuntimeException);
275 
276     // XPackageRegistry
277     virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
278     getSupportedPackageTypes() throw (RuntimeException);
279     virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType)
280         throw (deployment::DeploymentException,
281                uno::RuntimeException);
282 
283     using ImplBaseT::disposing;
284 };
285 
286 //Used to find a XPackage with a particular URL
287 class XPackage_eq : public std::unary_function<Reference<deployment::XPackage>, bool>
288 {
289     OUString m_URL;
290 public:
291     explicit XPackage_eq(const OUString & s) : m_URL(s) {}
292     bool operator() (const Reference<deployment::XPackage> & p) const
293     {
294         return m_URL.equals(p->getURL());
295     }
296 };
297 
298 //______________________________________________________________________________
299 BackendImpl::BackendImpl(
300     Sequence<Any> const & args,
301     Reference<XComponentContext> const & xComponentContext,
302     Reference<deployment::XPackageRegistry> const & xRootRegistry )
303     : ImplBaseT( args, xComponentContext ),
304       m_xRootRegistry( xRootRegistry ),
305       m_xBundleTypeInfo( new Package::TypeInfo(
306                              OUSTR("application/vnd.sun.star.package-bundle"),
307                              OUSTR("*.oxt;*.uno.pkg"),
308                              getResourceString(RID_STR_PACKAGE_BUNDLE),
309                              RID_IMG_DEF_PACKAGE_BUNDLE,
310                              RID_IMG_DEF_PACKAGE_BUNDLE_HC ) ),
311       m_xLegacyBundleTypeInfo( new Package::TypeInfo(
312                                    OUSTR("application/"
313                                          "vnd.sun.star.legacy-package-bundle"),
314                                    OUSTR("*.zip"),
315                                    m_xBundleTypeInfo->getShortDescription(),
316                                    RID_IMG_DEF_PACKAGE_BUNDLE,
317                                    RID_IMG_DEF_PACKAGE_BUNDLE_HC ) ),
318     m_typeInfos(2)
319 {
320     m_typeInfos[ 0 ] = m_xBundleTypeInfo;
321     m_typeInfos[ 1 ] = m_xLegacyBundleTypeInfo;
322 
323     if (!transientMode())
324     {
325         OUString dbFile = makeURL(getCachePath(), getImplementationName());
326         dbFile = makeURL(dbFile, OUSTR("backenddb.xml"));
327         m_backendDb.reset(
328             new ExtensionBackendDb(getComponentContext(), dbFile));
329    }
330 }
331 
332 //______________________________________________________________________________
333 void BackendImpl::disposing()
334 {
335     m_xRootRegistry.clear();
336     PackageRegistryBackend::disposing();
337 }
338 
339 // XServiceInfo
340 OUString BackendImpl::getImplementationName() throw (RuntimeException)
341 {
342     return OUSTR("com.sun.star.comp.deployment.bundle.PackageRegistryBackend");
343 }
344 
345 sal_Bool BackendImpl::supportsService( OUString const& name )
346     throw (RuntimeException)
347 {
348     return getSupportedServiceNames()[0].equals(name);
349 }
350 
351 Sequence<OUString> BackendImpl::getSupportedServiceNames()
352     throw (RuntimeException)
353 {
354     return comphelper::makeSequence(
355         OUString::createFromAscii(BACKEND_SERVICE_NAME) );
356 }
357 
358 // XPackageRegistry
359 //______________________________________________________________________________
360 Sequence< Reference<deployment::XPackageTypeInfo> >
361 BackendImpl::getSupportedPackageTypes() throw (RuntimeException)
362 {
363     return m_typeInfos;
364 }
365 
366 void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/)
367         throw (deployment::DeploymentException,
368                uno::RuntimeException)
369 {
370     //Notify the backend responsible for processing the different media
371     //types that this extension was removed.
372     ExtensionBackendDb::Data data = readDataFromDb(url);
373     for (ExtensionBackendDb::Data::ITC_ITEMS i = data.items.begin(); i != data.items.end(); i++)
374     {
375         m_xRootRegistry->packageRemoved(i->first, i->second);
376     }
377 
378     if (m_backendDb.get())
379         m_backendDb->removeEntry(url);
380 }
381 
382 
383 // PackageRegistryBackend
384 //______________________________________________________________________________
385 Reference<deployment::XPackage> BackendImpl::bindPackage_(
386     OUString const & url, OUString const & mediaType_,
387     sal_Bool bRemoved, OUString const & identifier,
388     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
389 {
390     OUString mediaType( mediaType_ );
391     if (mediaType.getLength() == 0)
392     {
393         // detect media-type:
394         ::ucbhelper::Content ucbContent;
395         if (create_ucb_content( &ucbContent, url, xCmdEnv ))
396         {
397             if (ucbContent.isFolder())
398             {
399                 //Every .oxt, uno.pkg file must contain a META-INF folder
400                 ::ucbhelper::Content metaInfContent;
401                 if (create_ucb_content(
402                     &metaInfContent, makeURL( url, OUSTR("META-INF") ),
403                     xCmdEnv, false /* no throw */ ))
404                 {
405                      mediaType = OUSTR("application/vnd.sun.star.package-bundle");
406                 }
407                 //No support of legacy bundles, because every folder could be one.
408             }
409             else
410             {
411                 const OUString title( ucbContent.getPropertyValue(
412                                           StrTitle::get() ).get<OUString>() );
413                 if (title.endsWithIgnoreAsciiCaseAsciiL(
414                         RTL_CONSTASCII_STRINGPARAM(".oxt") ) ||
415                     title.endsWithIgnoreAsciiCaseAsciiL(
416                         RTL_CONSTASCII_STRINGPARAM(".uno.pkg") ))
417                     mediaType = OUSTR("application/vnd.sun.star.package-bundle");
418                 else if (title.endsWithIgnoreAsciiCaseAsciiL(
419                              RTL_CONSTASCII_STRINGPARAM(".zip") ))
420                     mediaType =
421                         OUSTR("application/vnd.sun.star.legacy-package-bundle");
422             }
423         }
424         if (mediaType.getLength() == 0)
425             throw lang::IllegalArgumentException(
426                 StrCannotDetectMediaType::get() + url,
427                 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
428     }
429 
430     String type, subType;
431     INetContentTypeParameterList params;
432     if (INetContentTypes::parse( mediaType, type, subType, &params ))
433     {
434         if (type.EqualsIgnoreCaseAscii("application"))
435         {
436 
437             //In case a XPackage is created for a removed extension, we cannot
438             //obtain the name
439             OUString name;
440             if (!bRemoved)
441             {
442                 ::ucbhelper::Content ucbContent( url, xCmdEnv );
443                 name = ucbContent.getPropertyValue(
444                     StrTitle::get() ).get<OUString>();
445             }
446             if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.package-bundle")) {
447                 return new PackageImpl(
448                     this, url, name, m_xBundleTypeInfo, false, bRemoved,
449                     identifier);
450             }
451             else if (subType.EqualsIgnoreCaseAscii(
452                          "vnd.sun.star.legacy-package-bundle")) {
453                 return new PackageImpl(
454                     this, url, name, m_xLegacyBundleTypeInfo, true, bRemoved,
455                     identifier);
456             }
457         }
458     }
459     throw lang::IllegalArgumentException(
460         StrUnsupportedMediaType::get() + mediaType,
461         static_cast<OWeakObject *>(this),
462         static_cast<sal_Int16>(-1) );
463 }
464 
465 void BackendImpl::addDataToDb(
466     OUString const & url, ExtensionBackendDb::Data const & data)
467 {
468     if (m_backendDb.get())
469         m_backendDb->addEntry(url, data);
470 }
471 
472 ExtensionBackendDb::Data BackendImpl::readDataFromDb(
473     OUString const & url)
474 {
475     ExtensionBackendDb::Data data;
476     if (m_backendDb.get())
477         data = m_backendDb->getEntry(url);
478     return data;
479 }
480 
481 void BackendImpl::revokeEntryFromDb(OUString const & url)
482 {
483     if (m_backendDb.get())
484         m_backendDb->revokeEntry(url);
485 }
486 
487 
488 //##############################################################################
489 
490 BackendImpl::PackageImpl::PackageImpl(
491     ::rtl::Reference<PackageRegistryBackend> const & myBackend,
492     OUString const & url,
493     OUString const & name,
494     Reference<deployment::XPackageTypeInfo> const & xPackageType,
495     bool legacyBundle, bool bRemoved, OUString const & identifier)
496     : Package( myBackend, url, name, name /* display-name */,
497                xPackageType, bRemoved, identifier),
498       m_url_expanded( expandUnoRcUrl( url ) ),
499       m_legacyBundle( legacyBundle ),
500       m_pBundle( 0 )
501 {
502     if (bRemoved)
503         m_dbData = getMyBackend()->readDataFromDb(url);
504 }
505 
506 BackendImpl * BackendImpl::PackageImpl::getMyBackend() const
507 {
508     BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
509     if (NULL == pBackend)
510     {
511         //May throw a DisposedException
512         check();
513         //We should never get here...
514         throw RuntimeException(
515             OUSTR("Failed to get the BackendImpl"),
516             static_cast<OWeakObject*>(const_cast<PackageImpl *>(this)));
517     }
518     return pBackend;
519 }
520 //______________________________________________________________________________
521 void BackendImpl::PackageImpl::disposing()
522 {
523     sal_Int32 len = m_bundle.getLength();
524     Reference<deployment::XPackage> const * p = m_bundle.getConstArray();
525     for ( sal_Int32 pos = 0; pos < len; ++pos )
526         try_dispose( p[ pos ] );
527     m_bundle.realloc( 0 );
528 
529     Package::disposing();
530 }
531 
532 // Package
533 //______________________________________________________________________________
534 beans::Optional< beans::Ambiguous<sal_Bool> >
535 BackendImpl::PackageImpl::isRegistered_(
536     ::osl::ResettableMutexGuard &,
537     ::rtl::Reference<AbortChannel> const & abortChannel,
538     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
539 {
540     //In case the object was created for a removed extension (m_bRemoved = true)
541     //but the extension is not registered, then bundle will be empty. Then
542     //the return value will be Optional<...>.IsPresent= false. Althoug this is
543     //not true, this does not matter. Then registerPackage or revokePackage
544     //would never be called for the items. But since the extension is removed
545     //and not registered anyway, this does not matter.
546     const Sequence< Reference<deployment::XPackage> > bundle(
547         getBundle( abortChannel.get(), xCmdEnv ) );
548 
549     bool reg = false;
550     bool present = false;
551     bool ambig = false;
552     for ( sal_Int32 pos = bundle.getLength(); pos--; )
553     {
554         Reference<deployment::XPackage> const & xPackage = bundle[ pos ];
555         Reference<task::XAbortChannel> xSubAbortChannel(
556             xPackage->createAbortChannel() );
557         AbortChannel::Chain chain( abortChannel, xSubAbortChannel );
558         beans::Optional< beans::Ambiguous<sal_Bool> > option(
559             xPackage->isRegistered( xSubAbortChannel, xCmdEnv ) );
560 
561         //present = true if at least one bundle item has this value.
562         //reg = true if all bundle items have an option value (option.IsPresent == 1)
563         //and all have value of true (option.Value.Value == true)
564         //If not, then the bundle has the status of not registered and ambiguous.
565         if (option.IsPresent)
566         {
567             beans::Ambiguous<sal_Bool> const & status = option.Value;
568             if (present)
569             {
570                 //we never come here in the first iteration
571                 if (reg != (status.Value != sal_False)) {
572 
573                     ambig = true;
574                     reg = false;
575                     break;
576                 }
577             }
578             else
579             {
580                 //we always come here in the first iteration
581                 reg = status.Value;
582                 present = true;
583             }
584         }
585     }
586     return beans::Optional< beans::Ambiguous<sal_Bool> >(
587         present, beans::Ambiguous<sal_Bool>(reg, ambig) );
588 }
589 
590 OUString BackendImpl::PackageImpl::getTextFromURL(
591 	const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv,
592 	const OUString& licenseUrl)
593 {
594 	try
595 	{
596 		::ucbhelper::Content descContent(licenseUrl, xCmdEnv);
597         ::rtl::ByteSequence seq = dp_misc::readFile(descContent);
598         return OUString( reinterpret_cast<sal_Char const *>(
599             seq.getConstArray()), seq.getLength(), RTL_TEXTENCODING_UTF8);
600 	}
601 	catch (css::uno::Exception&)
602 	{
603 		Any exc( ::cppu::getCaughtException() );
604 			throw css::deployment::DeploymentException(
605 				OUSTR("Could not read file ") + licenseUrl, 0, exc);
606 	}
607 
608 }
609 
610 DescriptionInfoset BackendImpl::PackageImpl::getDescriptionInfoset()
611 {
612     return dp_misc::getDescriptionInfoset(m_url_expanded);
613 }
614 
615 bool BackendImpl::PackageImpl::checkPlatform(
616     css::uno::Reference< css::ucb::XCommandEnvironment > const &  environment)
617 {
618     bool ret = false;
619     DescriptionInfoset info(getDescriptionInfoset());
620     Sequence<OUString> platforms(info.getSupportedPlaforms());
621     if (hasValidPlatform(platforms))
622     {
623         ret = true;
624     }
625     else
626     {
627         ret = false;
628         rtl::OUString msg(
629             RTL_CONSTASCII_USTRINGPARAM("unsupported platform"));
630         Any e(
631             css::deployment::PlatformException(
632                 msg, static_cast<OWeakObject *>(this), this));
633         if (!interactContinuation(
634                 e, cppu::UnoType< css::task::XInteractionApprove >::get(),
635                 environment, NULL, NULL))
636         {
637             throw css::deployment::DeploymentException(
638                 msg, static_cast<OWeakObject *>(this), e);
639         }
640     }
641     return ret;
642 }
643 
644 
645 bool BackendImpl::PackageImpl::checkDependencies(
646     css::uno::Reference< css::ucb::XCommandEnvironment > const & environment,
647     DescriptionInfoset const & description)
648 {
649     css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > >
650         unsatisfied(dp_misc::Dependencies::check(description));
651 
652     if (unsatisfied.getLength() == 0) {
653         return true;
654     } else {
655         rtl::OUString msg(
656             RTL_CONSTASCII_USTRINGPARAM("unsatisfied dependencies"));
657         Any e(
658             css::deployment::DependencyException(
659                 msg, static_cast<OWeakObject *>(this), unsatisfied));
660         if (!interactContinuation(
661                 e, cppu::UnoType< css::task::XInteractionApprove >::get(),
662                 environment, NULL, NULL))
663         {
664             throw css::deployment::DeploymentException(
665                 msg, static_cast<OWeakObject *>(this), e);
666         }
667         return false;
668     }
669 }
670 
671 ::sal_Bool BackendImpl::PackageImpl::checkLicense(
672 	css::uno::Reference< css::ucb::XCommandEnvironment > const & xCmdEnv,
673 	DescriptionInfoset const & info, bool alreadyInstalled)
674 		throw (css::deployment::DeploymentException,
675 		    css::ucb::CommandFailedException,
676 		    css::ucb::CommandAbortedException,
677 			css::uno::RuntimeException)
678 {
679 	try
680 	{
681         ::boost::optional<SimpleLicenseAttributes> simplLicAttr
682             = info.getSimpleLicenseAttributes();
683        if (! simplLicAttr)
684             return true;
685 		OUString sLic = info.getLocalizedLicenseURL();
686         //If we do not get a localized licence then there is an error in the description.xml
687         //This should be handled by using a validating parser. Therefore we assume that no
688         //license is available.
689         if (sLic.getLength() == 0)
690             throw css::deployment::DeploymentException(
691                 OUSTR("Could not obtain path to license. Possible error in description.xml"), 0, Any());
692         OUString sHref = m_url_expanded + OUSTR("/") + sLic;
693    		OUString sLicense = getTextFromURL(xCmdEnv, sHref);
694 		////determine who has to agree to the license
695         //check correct value for attribute
696         if ( ! (simplLicAttr->acceptBy.equals(OUSTR("user")) || simplLicAttr->acceptBy.equals(OUSTR("admin"))))
697             throw css::deployment::DeploymentException(
698                 OUSTR("Could not obtain attribute simple-lincense@accept-by or it has no valid value"), 0, Any());
699 
700 
701         //Only use interaction if there is no version of this extension already installed
702         //and the suppress-on-update flag is not set for the new extension
703         // alreadyInstalled | bSuppressOnUpdate | show license
704         //----------------------------------------
705         //      0     |      0            |     1
706         //      0     |      1            |     1
707         //      1     |      0            |     1
708         //      1     |      1            |     0
709 
710         if ( !(alreadyInstalled && simplLicAttr->suppressOnUpdate))
711         {
712 		    css::deployment::LicenseException licExc(
713                 OUString(), 0, getDisplayName(), sLicense,
714                 simplLicAttr->acceptBy);
715 		    bool approve = false;
716 		    bool abort = false;
717 		    if (! interactContinuation(
718 			    Any(licExc), task::XInteractionApprove::static_type(), xCmdEnv, &approve, &abort ))
719 			    throw css::deployment::DeploymentException(
720 				    OUSTR("Could not interact with user."), 0, Any());
721 
722 		    if (approve == true)
723 			    return true;
724             else
725                 return false;
726                 //throw css::deployment::DeploymentException(
727                 //    OUSTR("Extension Manager: User declined the license."),
728                 //    static_cast<OWeakObject*>(this),
729                 //    Any( css::deployment::LicenseException(OUSTR("User declined the license."), 0, m_name, sLicense)));
730         }
731         return true;
732 	} catch (css::ucb::CommandFailedException&) {
733 		throw;
734 	} catch (css::ucb::CommandAbortedException&) {
735 		throw;
736 	} catch (css::deployment::DeploymentException&) {
737 		throw;
738 	} catch (css::uno::RuntimeException&) {
739 		throw;
740 	} catch (css::uno::Exception&) {
741 		Any anyExc = cppu::getCaughtException();
742 		throw css::deployment::DeploymentException(OUSTR("Unexpected exception"), 0, anyExc);
743 	}
744 }
745 
746 ::sal_Int32 BackendImpl::PackageImpl::checkPrerequisites(
747 		const css::uno::Reference< css::task::XAbortChannel >&,
748 		const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv,
749         sal_Bool alreadyInstalled)
750 		throw (css::deployment::DeploymentException,
751                css::deployment::ExtensionRemovedException,
752                css::ucb::CommandFailedException,
753                css::ucb::CommandAbortedException,
754                css::uno::RuntimeException)
755 {
756     if (m_bRemoved)
757         throw deployment::ExtensionRemovedException();
758 	DescriptionInfoset info = getDescriptionInfoset();
759     if (!info.hasDescription())
760 		return 0;
761 
762     //always return LICENSE as long as the user did not accept the license
763     //so that XExtensonManager::checkPrerequisitesAndEnable will again
764     //check the license
765     if (!checkPlatform(xCmdEnv))
766         return deployment::Prerequisites::PLATFORM |
767             deployment::Prerequisites::LICENSE;
768     else if(!checkDependencies(xCmdEnv, info))
769         return deployment::Prerequisites::DEPENDENCIES |
770             deployment::Prerequisites::LICENSE;
771     else if(!checkLicense(xCmdEnv, info, alreadyInstalled))
772         return deployment::Prerequisites::LICENSE;
773     else
774         return 0;
775 }
776 
777 ::sal_Bool BackendImpl::PackageImpl::checkDependencies(
778 		const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv )
779 		throw (deployment::DeploymentException,
780 		       deployment::ExtensionRemovedException,
781 		       ucb::CommandFailedException,
782 		       RuntimeException)
783 {
784     if (m_bRemoved)
785         throw deployment::ExtensionRemovedException();
786     DescriptionInfoset info = getDescriptionInfoset();
787     if (!info.hasDescription())
788 		return sal_True;
789 
790     return checkDependencies(xCmdEnv, info);
791 }
792 
793 beans::Optional<OUString> BackendImpl::PackageImpl::getIdentifier()
794     throw (RuntimeException)
795 {
796     OUString identifier;
797     if (m_bRemoved)
798         identifier = m_identifier;
799     else
800         identifier = dp_misc::generateIdentifier(
801             getDescriptionInfoset().getIdentifier(), m_name);
802 
803     return beans::Optional<OUString>(
804         true, identifier);
805 }
806 
807 OUString BackendImpl::PackageImpl::getVersion()
808     throw (deployment::ExtensionRemovedException, RuntimeException)
809 {
810     if (m_bRemoved)
811         throw deployment::ExtensionRemovedException();
812     return getDescriptionInfoset().getVersion();
813 }
814 
815 Sequence<OUString> BackendImpl::PackageImpl::getUpdateInformationURLs()
816     throw (deployment::ExtensionRemovedException, RuntimeException)
817 {
818     if (m_bRemoved)
819         throw deployment::ExtensionRemovedException();
820     return getDescriptionInfoset().getUpdateInformationUrls();
821 }
822 
823 beans::StringPair BackendImpl::PackageImpl::getPublisherInfo()
824     throw (deployment::ExtensionRemovedException, RuntimeException)
825 {
826     if (m_bRemoved)
827         throw deployment::ExtensionRemovedException();
828     ::std::pair< OUString, OUString > aInfo = getDescriptionInfoset().getLocalizedPublisherNameAndURL();
829     beans::StringPair aStrPair( aInfo.first, aInfo.second );
830     return aStrPair;
831 }
832 
833 //______________________________________________________________________________
834 uno::Reference< graphic::XGraphic > BackendImpl::PackageImpl::getIcon( sal_Bool bHighContrast )
835     throw (deployment::ExtensionRemovedException, RuntimeException )
836 {
837     if (m_bRemoved)
838         throw deployment::ExtensionRemovedException();
839 
840     uno::Reference< graphic::XGraphic > xGraphic;
841 
842     OUString aIconURL = getDescriptionInfoset().getIconURL( bHighContrast );
843     if ( aIconURL.getLength() )
844     {
845         OUString aFullIconURL = m_url_expanded + OUSTR("/") + aIconURL;
846 
847         uno::Reference< XComponentContext > xContext( getMyBackend()->getComponentContext() );
848         uno::Reference< graphic::XGraphicProvider > xGraphProvider(
849                         xContext->getServiceManager()->createInstanceWithContext( OUSTR( "com.sun.star.graphic.GraphicProvider" ), xContext ),
850                         uno::UNO_QUERY );
851 
852         if ( xGraphProvider.is() )
853         {
854             uno::Sequence< beans::PropertyValue > aMediaProps( 1 );
855             aMediaProps[0].Name = OUSTR( "URL" );
856             aMediaProps[0].Value <<= aFullIconURL;
857 
858             xGraphic = xGraphProvider->queryGraphic( aMediaProps );
859         }
860     }
861 
862     return xGraphic;
863 }
864 
865 //______________________________________________________________________________
866 void BackendImpl::PackageImpl::processPackage_(
867     ::osl::ResettableMutexGuard &,
868     bool doRegisterPackage,
869     bool startup,
870     ::rtl::Reference<AbortChannel> const & abortChannel,
871     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
872 {
873     const Sequence< Reference<deployment::XPackage> > bundle(
874         getBundle( abortChannel.get(), xCmdEnv ) );
875 
876     if (doRegisterPackage)
877     {
878         ExtensionBackendDb::Data data;
879         const sal_Int32 len = bundle.getLength();
880         for ( sal_Int32 pos = 0; pos < len; ++pos )
881         {
882             checkAborted(abortChannel);
883             Reference<deployment::XPackage> const & xPackage = bundle[ pos ];
884             Reference<task::XAbortChannel> xSubAbortChannel(
885                 xPackage->createAbortChannel() );
886             AbortChannel::Chain chain( abortChannel, xSubAbortChannel );
887             try {
888                 xPackage->registerPackage( startup, xSubAbortChannel, xCmdEnv );
889             }
890             catch (Exception &)
891             {
892                //We even try a rollback if the user cancelled the action (CommandAbortedException)
893                 //in order to prevent invalid database entries.
894                 Any exc( ::cppu::getCaughtException() );
895                 // try to handle exception, notify:
896                 bool approve = false, abort = false;
897                 if (! interactContinuation(
898                         Any( lang::WrappedTargetException(
899                                  OUSTR("bundle item registration error!"),
900                                  static_cast<OWeakObject *>(this), exc ) ),
901                         task::XInteractionApprove::static_type(), xCmdEnv,
902                         &approve, &abort )) {
903                     OSL_ASSERT( !approve && !abort );
904                     if (m_legacyBundle) // default for legacy packages: ignore
905                         continue;
906                     // no selection at all, so rethrow;
907                     // no C++ rethrow after getCaughtException(),
908                     // see cppuhelper/exc_hlp.hxx:
909                     ::cppu::throwException(exc);
910                 }
911                 if (approve && !abort) // ignore error, just continue
912                     continue;
913 
914                 {
915                     ProgressLevel progress(
916                         xCmdEnv, OUSTR("rollback...") );
917                     // try rollback
918                     for ( ; pos--; )
919                     {
920                         try {
921                             bundle[ pos ]->revokePackage(
922                                 xSubAbortChannel, xCmdEnv );
923                         }
924                         catch (Exception &)
925                         {
926                             OSL_ENSURE( 0, ::rtl::OUStringToOString(
927                                             ::comphelper::anyToString(
928                                                 ::cppu::getCaughtException() ),
929                                             RTL_TEXTENCODING_UTF8 ).getStr() );
930                             // ignore any errors of rollback
931                         }
932                     }
933                     progress.update( OUSTR("rollback finished.") );
934                 }
935 
936                 deployment::DeploymentException dpExc;
937                 if (exc >>= dpExc) {
938                     throw ucb::CommandFailedException(
939                         dpExc.Message, dpExc.Context, dpExc.Cause );
940                 }
941                 else {
942                     // rethrow CommandFailedException
943                     ::cppu::throwException(exc);
944                 }
945             }
946             data.items.push_back(
947                 ::std::make_pair(xPackage->getURL(),
948                                  xPackage->getPackageType()->getMediaType()));
949         }
950         getMyBackend()->addDataToDb(getURL(), data);
951     }
952     else
953     {
954         // revoke in reverse order:
955         for ( sal_Int32 pos = bundle.getLength(); pos--; )
956         {
957             checkAborted(abortChannel);
958             Reference<deployment::XPackage> const & xPackage = bundle[ pos ];
959             Reference<task::XAbortChannel> xSubAbortChannel(
960                 xPackage->createAbortChannel() );
961             AbortChannel::Chain chain( abortChannel, xSubAbortChannel );
962             try {
963                 bundle[ pos ]->revokePackage( xSubAbortChannel, xCmdEnv );
964             }
965             catch (RuntimeException &) {
966                 throw;
967             }
968             catch (ucb::CommandAbortedException &) {
969                 throw;
970             }
971             catch (Exception &) {
972                 // CommandFailedException, DeploymentException:
973                 Any exc( ::cppu::getCaughtException() );
974                 // try to handle exception, notify:
975                 bool approve = false, abort = false;
976                 if (! interactContinuation(
977                         Any( lang::WrappedTargetException(
978                                  OUSTR("bundle item revocation error!"),
979                                  static_cast<OWeakObject *>(this), exc ) ),
980                         task::XInteractionApprove::static_type(), xCmdEnv,
981                         &approve, &abort )) {
982                     OSL_ASSERT( !approve && !abort );
983                     if (m_legacyBundle) // default for legacy packages: ignore
984                         continue;
985                     // no selection at all, so rethrow
986                     // no C++ rethrow after getCaughtException(),
987                     // see cppuhelper/exc_hlp.hxx:
988                     ::cppu::throwException(exc);
989                 }
990                 // ignore errors when revoking, although abort may have been
991                 // selected
992             }
993         }
994         getMyBackend()->revokeEntryFromDb(getURL());
995     }
996 }
997 
998 //______________________________________________________________________________
999 OUString BackendImpl::PackageImpl::getDescription()
1000     throw (deployment::ExtensionRemovedException, RuntimeException)
1001 {
1002     if (m_bRemoved)
1003         throw deployment::ExtensionRemovedException();
1004 
1005     const OUString sRelativeURL(getDescriptionInfoset().getLocalizedDescriptionURL());
1006     OUString sDescription;
1007     if (sRelativeURL.getLength())
1008     {
1009         OUString sURL = m_url_expanded + OUSTR("/") + sRelativeURL;
1010 
1011         try
1012         {
1013             sDescription = getTextFromURL( css::uno::Reference< css::ucb::XCommandEnvironment >(), sURL );
1014         }
1015         catch ( css::deployment::DeploymentException& )
1016         {
1017             OSL_ENSURE( 0, ::rtl::OUStringToOString( ::comphelper::anyToString( ::cppu::getCaughtException() ), RTL_TEXTENCODING_UTF8 ).getStr() );
1018         }
1019     }
1020 
1021     if (sDescription.getLength())
1022         return sDescription;
1023     return m_oldDescription;
1024 }
1025 
1026 //______________________________________________________________________________
1027 OUString BackendImpl::PackageImpl::getLicenseText()
1028     throw (deployment::ExtensionRemovedException, RuntimeException)
1029 {
1030     if (m_bRemoved)
1031         throw deployment::ExtensionRemovedException();
1032 
1033     OUString sLicense;
1034     DescriptionInfoset aInfo = getDescriptionInfoset();
1035 
1036     ::boost::optional< SimpleLicenseAttributes > aSimplLicAttr = aInfo.getSimpleLicenseAttributes();
1037     if ( aSimplLicAttr )
1038     {
1039         OUString aLicenseURL = aInfo.getLocalizedLicenseURL();
1040 
1041         if ( aLicenseURL.getLength() )
1042         {
1043             OUString aFullURL = m_url_expanded + OUSTR("/") + aLicenseURL;
1044    		    sLicense = getTextFromURL( Reference< ucb::XCommandEnvironment >(), aFullURL);
1045    	    }
1046     }
1047 
1048      return sLicense;
1049 }
1050 
1051 //______________________________________________________________________________
1052 void BackendImpl::PackageImpl::exportTo(
1053     OUString const & destFolderURL, OUString const & newTitle,
1054     sal_Int32 nameClashAction, Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1055     throw (ucb::CommandFailedException,
1056            deployment::ExtensionRemovedException,
1057            ucb::CommandAbortedException, RuntimeException)
1058 {
1059     if (m_bRemoved)
1060         throw deployment::ExtensionRemovedException();
1061 
1062     ::ucbhelper::Content sourceContent( m_url_expanded, xCmdEnv );
1063     OUString title(newTitle);
1064     if (title.getLength() == 0)
1065         sourceContent.getPropertyValue( StrTitle::get() ) >>= title;
1066     OUString destURL( makeURL( destFolderURL, ::rtl::Uri::encode(
1067                                    title, rtl_UriCharClassPchar,
1068                                    rtl_UriEncodeIgnoreEscapes,
1069                                    RTL_TEXTENCODING_UTF8 ) ) );
1070 
1071     if (nameClashAction == ucb::NameClash::ASK)
1072     {
1073         if (create_ucb_content(
1074                 0, destURL, xCmdEnv, false /* no throw */ )) {
1075             bool replace = false, abort = false;
1076             if (! interactContinuation(
1077                     Any( ucb::NameClashResolveRequest(
1078                              OUSTR("file already exists: ") + title,
1079                              static_cast<OWeakObject *>(this),
1080                              task::InteractionClassification_QUERY,
1081                              destFolderURL, title, OUString() ) ),
1082                     ucb::XInteractionReplaceExistingData::static_type(), xCmdEnv,
1083                     &replace, &abort ) || !replace) {
1084                 return;
1085             }
1086         }
1087     }
1088     else if (nameClashAction != ucb::NameClash::OVERWRITE) {
1089         throw ucb::CommandFailedException(
1090             OUSTR("unsupported nameClashAction!"),
1091             static_cast<OWeakObject *>(this), Any() );
1092     }
1093     erase_path( destURL, xCmdEnv );
1094 
1095     ::rtl::OUStringBuffer buf;
1096     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.zip://") );
1097     buf.append( ::rtl::Uri::encode( destURL,
1098                                     rtl_UriCharClassRegName,
1099                                     rtl_UriEncodeIgnoreEscapes,
1100                                     RTL_TEXTENCODING_UTF8 ) );
1101     buf.append( static_cast<sal_Unicode>('/') );
1102     OUString destFolder( buf.makeStringAndClear() );
1103 
1104     ::ucbhelper::Content destFolderContent( destFolder, xCmdEnv );
1105     {
1106         // transfer every item of folder into zip:
1107         Reference<sdbc::XResultSet> xResultSet(
1108             sourceContent.createCursor(
1109                 Sequence<OUString>(),
1110                 ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) );
1111         ProgressLevel progress( xCmdEnv, OUString() );
1112         while (xResultSet->next())
1113         {
1114             ::ucbhelper::Content subContent(
1115                 Reference<ucb::XContentAccess>(
1116                     xResultSet, UNO_QUERY_THROW )->queryContent(), xCmdEnv );
1117             if (! destFolderContent.transferContent(
1118                     subContent, ::ucbhelper::InsertOperation_COPY,
1119                     OUString(), ucb::NameClash::OVERWRITE ))
1120                 throw RuntimeException( OUSTR("UCB transferContent() failed!"),
1121                                         static_cast<OWeakObject *>(this) );
1122             progress.update( Any() ); // animating progress bar
1123         }
1124     }
1125 
1126     // assure META-INF folder:
1127     ::ucbhelper::Content metainfFolderContent;
1128     create_folder( &metainfFolderContent,
1129                    makeURL( destFolderContent.getURL(), OUSTR("META-INF") ),
1130                    xCmdEnv );
1131 
1132     if (m_legacyBundle)
1133     {
1134         // easy to migrate legacy bundles to new format:
1135         // just export them once using a .oxt name!
1136         // set detected media-types of any bundle item:
1137 
1138         // collect all manifest entries:
1139         Sequence< Reference<deployment::XPackage> > bundle;
1140         try {
1141             bundle = getBundle( Reference<task::XAbortChannel>(), xCmdEnv );
1142         }
1143         // xxx todo: think about exception specs:
1144         catch (deployment::DeploymentException &) {
1145             OSL_ENSURE( 0, ::rtl::OUStringToOString(
1146                             ::comphelper::anyToString(
1147                                 ::cppu::getCaughtException() ),
1148                             RTL_TEXTENCODING_UTF8 ).getStr() );
1149         }
1150         catch (lang::IllegalArgumentException & exc) {
1151             (void) exc;
1152             OSL_ENSURE( 0, ::rtl::OUStringToOString(
1153                             exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
1154         }
1155 
1156         ::std::vector< Sequence<beans::PropertyValue> > manifest;
1157         manifest.reserve( bundle.getLength() );
1158         sal_Int32 baseURLlen = m_url_expanded.getLength();
1159         Reference<deployment::XPackage> const *pbundle = bundle.getConstArray();
1160         const OUString strMediaType = OUSTR("MediaType");
1161         const OUString strFullPath = OUSTR("FullPath");
1162         const OUString strIsFolder = OUSTR("IsFolder");
1163         for ( sal_Int32 pos = bundle.getLength(); pos--; )
1164         {
1165             Reference<deployment::XPackage> const & xPackage = pbundle[ pos ];
1166             OUString url_( expandUnoRcUrl( xPackage->getURL() ) );
1167             OSL_ASSERT( url_.getLength() >= baseURLlen );
1168             OUString fullPath;
1169             if (url_.getLength() > baseURLlen)
1170                 fullPath = url_.copy( baseURLlen + 1 );
1171             ::ucbhelper::Content ucbContent( url_, xCmdEnv );
1172             if (ucbContent.getPropertyValue(strIsFolder).get<bool>())
1173                 fullPath += OUSTR("/");
1174             Sequence<beans::PropertyValue> attribs( 2 );
1175             beans::PropertyValue * pattribs = attribs.getArray();
1176             pattribs[ 0 ].Name = strFullPath;
1177             pattribs[ 0 ].Value <<= fullPath;
1178             pattribs[ 1 ].Name = strMediaType;
1179             const Reference<deployment::XPackageTypeInfo> xPackageType(
1180                 xPackage->getPackageType() );
1181             OUString mediaType;
1182             OSL_ASSERT( xPackageType.is() );
1183             if (xPackageType.is())
1184                 mediaType = xPackageType->getMediaType();
1185             else
1186                 mediaType = OUSTR("unknown");
1187             pattribs[ 1 ].Value <<= mediaType;
1188             manifest.push_back( attribs );
1189         }
1190 
1191         // write into pipe:
1192         Reference<XComponentContext> xContext(
1193             getMyBackend()->getComponentContext() );
1194         Reference<packages::manifest::XManifestWriter> xManifestWriter(
1195             xContext->getServiceManager()->createInstanceWithContext(
1196                 OUSTR("com.sun.star.packages.manifest.ManifestWriter"),
1197                 xContext ), UNO_QUERY_THROW );
1198         Reference<io::XOutputStream> xPipe(
1199             xContext->getServiceManager()->createInstanceWithContext(
1200                 OUSTR("com.sun.star.io.Pipe"), xContext ), UNO_QUERY_THROW );
1201         xManifestWriter->writeManifestSequence(
1202             xPipe, comphelper::containerToSequence(manifest) );
1203 
1204         // write buffered pipe data to content:
1205         ::ucbhelper::Content manifestContent(
1206             makeURL( metainfFolderContent.getURL(), OUSTR("manifest.xml") ),
1207             xCmdEnv );
1208         manifestContent.writeStream(
1209             Reference<io::XInputStream>( xPipe, UNO_QUERY_THROW ),
1210             true /* replace existing */ );
1211     }
1212     else
1213     {
1214         // overwrite manifest.xml:
1215 		::ucbhelper::Content manifestContent;
1216 		if ( ! create_ucb_content(
1217             &manifestContent,
1218             makeURL( m_url_expanded, OUSTR("META-INF/manifest.xml") ),
1219             xCmdEnv, false ) )
1220 		{
1221 			OSL_ENSURE( 0, "### missing META-INF/manifest.xml file!" );
1222 			return;
1223 		}
1224 
1225         if (! metainfFolderContent.transferContent(
1226                 manifestContent, ::ucbhelper::InsertOperation_COPY,
1227                 OUString(), ucb::NameClash::OVERWRITE ))
1228             throw RuntimeException( OUSTR("UCB transferContent() failed!"),
1229                                     static_cast<OWeakObject *>(this) );
1230     }
1231 
1232     // xxx todo: maybe obsolete in the future
1233     try {
1234         destFolderContent.executeCommand( OUSTR("flush"), Any() );
1235     }
1236     catch (ucb::UnsupportedCommandException &) {
1237     }
1238 }
1239 
1240 //______________________________________________________________________________
1241 sal_Bool BackendImpl::PackageImpl::isBundle() throw (RuntimeException)
1242 {
1243     return true;
1244 }
1245 
1246 //______________________________________________________________________________
1247 Sequence< Reference<deployment::XPackage> > BackendImpl::PackageImpl::getBundle(
1248     Reference<task::XAbortChannel> const & xAbortChannel,
1249     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1250     throw (deployment::DeploymentException,
1251            ucb::CommandFailedException, ucb::CommandAbortedException,
1252            lang::IllegalArgumentException, RuntimeException)
1253 {
1254     Sequence< Reference<deployment::XPackage> > * pBundle = m_pBundle;
1255     if (pBundle == 0)
1256     {
1257         t_packagevec bundle;
1258         if (m_bRemoved)
1259         {
1260             bundle = getPackagesFromDb(xCmdEnv);
1261         }
1262         else
1263         {
1264             try {
1265                 if (m_legacyBundle)
1266                 {
1267                     // .zip legacy packages allow script.xlb, dialog.xlb in bundle
1268                     // root folder:
1269                     OUString mediaType;
1270                     // probe for script.xlb:
1271                     if (create_ucb_content(
1272                             0, makeURL( m_url_expanded, OUSTR("script.xlb") ),
1273                             xCmdEnv, false /* no throw */ )) {
1274                         mediaType = OUSTR("application/vnd.sun.star.basic-library");
1275                     }
1276                     // probe for dialog.xlb:
1277                     else if (create_ucb_content(
1278                                  0, makeURL( m_url_expanded, OUSTR("dialog.xlb") ),
1279                                  xCmdEnv, false /* no throw */ ))
1280                         mediaType = OUSTR("application/vnd.sun.star."
1281                                           "dialog-library");
1282 
1283                     if (mediaType.getLength() > 0) {
1284                         const Reference<deployment::XPackage> xPackage(
1285                             bindBundleItem( getURL(), mediaType, false, OUString(),
1286                                             xCmdEnv ) );
1287                         if (xPackage.is())
1288                             bundle.push_back( xPackage );
1289                         // continue scanning:
1290                     }
1291                     scanLegacyBundle( bundle, getURL(),
1292                                       AbortChannel::get(xAbortChannel), xCmdEnv );
1293                 }
1294                 else
1295                 {
1296                     // .oxt:
1297                     scanBundle( bundle, AbortChannel::get(xAbortChannel), xCmdEnv );
1298                 }
1299 
1300             }
1301             catch (RuntimeException &) {
1302                 throw;
1303             }
1304             catch (ucb::CommandFailedException &) {
1305                 throw;
1306             }
1307             catch (ucb::CommandAbortedException &) {
1308                 throw;
1309             }
1310             catch (deployment::DeploymentException &) {
1311                 throw;
1312             }
1313             catch (Exception &) {
1314                 Any exc( ::cppu::getCaughtException() );
1315                 throw deployment::DeploymentException(
1316                     OUSTR("error scanning bundle: ") + getURL(),
1317                     static_cast<OWeakObject *>(this), exc );
1318             }
1319         }
1320 
1321         // sort: schema before config data, typelibs before components:
1322         Sequence< Reference<deployment::XPackage> > ret( bundle.size() );
1323         Reference<deployment::XPackage> * pret = ret.getArray();
1324         sal_Int32 lower_end = 0;
1325         sal_Int32 upper_end = ret.getLength();
1326         t_packagevec::const_iterator iPos( bundle.begin() );
1327         t_packagevec::const_iterator const iEnd( bundle.end() );
1328         for ( ; iPos != iEnd; ++iPos )
1329         {
1330             const Reference<deployment::XPackageTypeInfo> xPackageType(
1331                 (*iPos)->getPackageType() );
1332             OSL_ASSERT( xPackageType.is() );
1333             if (xPackageType.is()) {
1334                 const OUString mediaType( xPackageType->getMediaType() );
1335                 String type, subType;
1336                 INetContentTypeParameterList params;
1337                 if (INetContentTypes::parse(
1338                         mediaType, type, subType, &params ) &&
1339                     type.EqualsIgnoreCaseAscii("application") &&
1340                     (subType.EqualsIgnoreCaseAscii(
1341                         "vnd.sun.star.uno-component") ||
1342                      subType.EqualsIgnoreCaseAscii(
1343                          "vnd.sun.star.configuration-data")))
1344                 {
1345                     --upper_end;
1346                     pret[ upper_end ] = *iPos;
1347                     continue;
1348                 }
1349             }
1350             pret[ lower_end ] = *iPos;
1351             ++lower_end;
1352         }
1353         OSL_ASSERT( lower_end == upper_end );
1354 
1355         const ::osl::MutexGuard guard( getMutex() );
1356         pBundle = m_pBundle;
1357         if (pBundle == 0) {
1358             m_bundle = ret;
1359             pBundle = &m_bundle;
1360             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
1361             m_pBundle = pBundle;
1362         }
1363     }
1364     else {
1365         OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
1366     }
1367     return *pBundle;
1368 }
1369 
1370 inline bool isBundle_( OUString const & mediaType )
1371 {
1372     // xxx todo: additional parsing?
1373     return mediaType.getLength() > 0 &&
1374         (mediaType.matchIgnoreAsciiCaseAsciiL(
1375             RTL_CONSTASCII_STRINGPARAM(
1376                 "application/vnd.sun.star.package-bundle") ) ||
1377          mediaType.matchIgnoreAsciiCaseAsciiL(
1378              RTL_CONSTASCII_STRINGPARAM(
1379                  "application/vnd.sun.star.legacy-package-bundle") ));
1380 }
1381 
1382 //______________________________________________________________________________
1383 Reference<deployment::XPackage> BackendImpl::PackageImpl::bindBundleItem(
1384     OUString const & url, OUString const & mediaType,
1385     sal_Bool bRemoved, OUString const & identifier,
1386     Reference<ucb::XCommandEnvironment> const & xCmdEnv,
1387     bool notifyDetectionError )
1388 {
1389     // ignore any nested bundles:
1390     if (isBundle_(mediaType))
1391         return Reference<deployment::XPackage>();
1392 
1393     Reference<deployment::XPackage>xPackage;
1394     try {
1395         xPackage.set( getMyBackend()->m_xRootRegistry->bindPackage(
1396                           url, mediaType, bRemoved, identifier, xCmdEnv ) );
1397         OSL_ASSERT( xPackage.is() );
1398     }
1399     catch (RuntimeException &) {
1400         throw;
1401     }
1402     catch (ucb::CommandFailedException &) {
1403         // ignore already handled error
1404     }
1405     catch (Exception &) {
1406         const Any exc( ::cppu::getCaughtException() );
1407         if (notifyDetectionError ||
1408             !exc.isExtractableTo(
1409                 ::getCppuType( reinterpret_cast<
1410                                lang::IllegalArgumentException const *>(0) ) ))
1411         {
1412             interactContinuation(
1413                 Any( lang::WrappedTargetException(
1414                          OUSTR("bundle item error!"),
1415                          static_cast<OWeakObject *>(this), exc ) ),
1416                 task::XInteractionApprove::static_type(), xCmdEnv, 0, 0 );
1417         }
1418     }
1419 
1420     if (xPackage.is()) {
1421         const Reference<deployment::XPackageTypeInfo> xPackageType(
1422             xPackage->getPackageType() );
1423         OSL_ASSERT( xPackageType.is() );
1424         // ignore any nested bundles:
1425         if (xPackageType.is() && isBundle_( xPackageType->getMediaType() ))
1426             xPackage.clear();
1427     }
1428     return xPackage;
1429 }
1430 
1431 //______________________________________________________________________________
1432 void BackendImpl::PackageImpl::scanBundle(
1433     t_packagevec & bundle,
1434     ::rtl::Reference<AbortChannel> const & abortChannel,
1435     Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1436 {
1437     OSL_ASSERT( !m_legacyBundle );
1438 
1439     ::ucbhelper::Content manifestContent;
1440     if (! create_ucb_content(
1441             &manifestContent,
1442             makeURL( m_url_expanded, OUSTR("META-INF/manifest.xml") ),
1443             xCmdEnv, false /* no throw */ ))
1444 	{
1445         OSL_ENSURE( 0, "### missing META-INF/manifest.xml file!" );
1446         return;
1447     }
1448 
1449 
1450     const lang::Locale officeLocale = getOfficeLocale();
1451     OUString descrFile;
1452     lang::Locale descrFileLocale;
1453 
1454     const Reference<XComponentContext> xContext(
1455         getMyBackend()->getComponentContext() );
1456     Reference<packages::manifest::XManifestReader> xManifestReader(
1457         xContext->getServiceManager()->createInstanceWithContext(
1458             OUSTR("com.sun.star.packages.manifest.ManifestReader"),
1459             xContext ), UNO_QUERY_THROW );
1460     const Sequence< Sequence<beans::PropertyValue> > manifestSeq(
1461         xManifestReader->readManifestSequence( manifestContent.openStream() ) );
1462     const OUString packageRootURL( getURL() );
1463     for ( sal_Int32 pos = manifestSeq.getLength(); pos--; )
1464     {
1465         OUString fullPath, mediaType;
1466         Sequence<beans::PropertyValue> const & attribs = manifestSeq[ pos ];
1467         for ( sal_Int32 i = attribs.getLength(); i--; )
1468         {
1469             if (fullPath.getLength() > 0 && mediaType.getLength() > 0)
1470                 break;
1471             if (attribs[i].Name.equalsAsciiL(
1472                     RTL_CONSTASCII_STRINGPARAM("FullPath") ))
1473                 attribs[i].Value >>= fullPath;
1474             else if (attribs[i].Name.equalsAsciiL(
1475                          RTL_CONSTASCII_STRINGPARAM("MediaType") ))
1476                 attribs[i].Value >>= mediaType;
1477         }
1478 
1479         if (fullPath.getLength() == 0 || mediaType.getLength() == 0 ||
1480             mediaType.equalsAsciiL( // opt: exclude common text/xml
1481                 RTL_CONSTASCII_STRINGPARAM("text/xml") ))
1482             continue;
1483 
1484         String type, subType;
1485         INetContentTypeParameterList params;
1486         if (! INetContentTypes::parse( mediaType, type, subType, &params ))
1487             continue;
1488 
1489         INetContentTypeParameter const * param = params.find(
1490             ByteString("platform") );
1491         if (param != 0 && !platform_fits( param->m_sValue ))
1492             continue;
1493         const OUString url( makeURL( packageRootURL, fullPath ) );
1494 
1495         // check for bundle description:
1496         if (type.EqualsIgnoreCaseAscii("application") &&
1497             subType.EqualsIgnoreCaseAscii(
1498                 "vnd.sun.star.package-bundle-description"))
1499         {
1500             // check locale:
1501             param = params.find( ByteString("locale") );
1502             if (param == 0) {
1503                 if (descrFile.getLength() == 0)
1504                     descrFile = url;
1505             }
1506             else {
1507                 // match best locale:
1508                 lang::Locale locale( toLocale(param->m_sValue) );
1509                 if (locale.Language == officeLocale.Language)
1510                 {
1511                     if (descrFileLocale.Country == officeLocale.Country
1512                         && locale.Country != officeLocale.Country)
1513                         continue;
1514                     if (descrFileLocale.Variant == officeLocale.Variant
1515                         && locale.Variant != officeLocale.Variant)
1516                         continue;
1517                     descrFile = url;
1518                     descrFileLocale = locale;
1519                 }
1520             }
1521             continue;
1522         }
1523 
1524         checkAborted( abortChannel );
1525 
1526         //We make sure that we only create one XPackage for a particular URL.
1527         //Sometime programmers insert the same URL several times in the manifest
1528         //which may lead to DisposedExceptions.
1529         if (bundle.end() == std::find_if(bundle.begin(), bundle.end(), XPackage_eq(url)))
1530         {
1531             const Reference<deployment::XPackage> xPackage(
1532                 bindBundleItem( url, mediaType, false, OUString(), xCmdEnv ) );
1533             if (xPackage.is())
1534                 bundle.push_back( xPackage );
1535         }
1536         else
1537         {
1538             fprintf(stderr, "manifest.xml contains a duplicate entry!\n");
1539         }
1540     }
1541 
1542     if (descrFile.getLength() > 0)
1543     {
1544         ::ucbhelper::Content descrFileContent;
1545         if (create_ucb_content( &descrFileContent, descrFile,
1546                                 xCmdEnv, false /* no throw */ ))
1547         {
1548             // patch description:
1549             ::rtl::ByteSequence bytes( readFile( descrFileContent ) );
1550             ::rtl::OUStringBuffer buf;
1551 			if ( bytes.getLength() )
1552 			{
1553 				buf.append( OUString( reinterpret_cast<sal_Char const *>(
1554 										  bytes.getConstArray() ),
1555 									  bytes.getLength(), RTL_TEXTENCODING_UTF8 ) );
1556 			}
1557 			else
1558 			{
1559 	            buf.append( Package::getDescription() );
1560 			}
1561             m_oldDescription = buf.makeStringAndClear();
1562         }
1563     }
1564 }
1565 
1566 //______________________________________________________________________________
1567 void BackendImpl::PackageImpl::scanLegacyBundle(
1568     t_packagevec & bundle,
1569     OUString const & url,
1570     ::rtl::Reference<AbortChannel> const & abortChannel,
1571     Reference<ucb::XCommandEnvironment> const & xCmdEnv,
1572     bool skip_registration )
1573 {
1574     ::ucbhelper::Content ucbContent( url, xCmdEnv );
1575 
1576     // check for platform pathes:
1577     const OUString title( ucbContent.getPropertyValue(
1578                               StrTitle::get() ).get<OUString>() );
1579     if (title.endsWithIgnoreAsciiCaseAsciiL(
1580             RTL_CONSTASCII_STRINGPARAM(".plt") ) &&
1581         !platform_fits( title.copy( 0, title.getLength() - 4 ) )) {
1582         return;
1583     }
1584     if (title.endsWithIgnoreAsciiCaseAsciiL(
1585             RTL_CONSTASCII_STRINGPARAM("skip_registration") ))
1586         skip_registration = true;
1587 
1588     OUString ar [] = { StrTitle::get(), OUSTR("IsFolder") };
1589     Reference<sdbc::XResultSet> xResultSet(
1590         ucbContent.createCursor(
1591             Sequence<OUString>( ar, ARLEN(ar) ),
1592             ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) );
1593     while (xResultSet->next())
1594     {
1595         checkAborted( abortChannel );
1596 
1597         const Reference<sdbc::XRow> xRow( xResultSet, UNO_QUERY_THROW );
1598         const OUString title_enc( ::rtl::Uri::encode(
1599                                       xRow->getString( 1 /* Title */ ),
1600                                       rtl_UriCharClassPchar,
1601                                       rtl_UriEncodeIgnoreEscapes,
1602                                       RTL_TEXTENCODING_UTF8 ) );
1603         const OUString path( makeURL( url, title_enc ) );
1604 
1605         OUString mediaType;
1606         const Reference<deployment::XPackage> xPackage(
1607             bindBundleItem( path, OUString() /* detect */, false, OUString(),
1608                             xCmdEnv, false /* ignore detection errors */ ) );
1609         if (xPackage.is()) {
1610             const Reference<deployment::XPackageTypeInfo> xPackageType(
1611                 xPackage->getPackageType() );
1612             OSL_ASSERT( xPackageType.is() );
1613             if (xPackageType.is())
1614                 mediaType = xPackageType->getMediaType();
1615 
1616             if (skip_registration &&
1617                 // xxx todo: additional parsing?
1618                 mediaType.matchIgnoreAsciiCaseAsciiL(
1619                     RTL_CONSTASCII_STRINGPARAM(
1620                         "application/vnd.sun.star.uno-component") ))
1621                 continue;
1622 
1623             bundle.push_back( xPackage );
1624         }
1625 
1626         if (mediaType.getLength() == 0 ||
1627             // script.xlb, dialog.xlb can be met everywhere:
1628             mediaType.matchIgnoreAsciiCaseAsciiL(
1629                 RTL_CONSTASCII_STRINGPARAM(
1630                     "application/vnd.sun.star.basic-library") ) ||
1631             mediaType.matchIgnoreAsciiCaseAsciiL(
1632                 RTL_CONSTASCII_STRINGPARAM(
1633                     "application/vnd.sun.star.dialog-library") ))
1634         {
1635             if (xRow->getBoolean( 2 /* IsFolder */ )) { // recurse into folder:
1636                 scanLegacyBundle(
1637                     bundle, path, abortChannel, xCmdEnv, skip_registration );
1638             }
1639         }
1640     }
1641 }
1642 
1643 OUString BackendImpl::PackageImpl::getDisplayName()
1644     throw (deployment::ExtensionRemovedException, RuntimeException)
1645 {
1646     if (m_bRemoved)
1647         throw deployment::ExtensionRemovedException();
1648 
1649     OUString sName = getDescriptionInfoset().getLocalizedDisplayName();
1650     if (sName.getLength() == 0)
1651         return m_displayName;
1652     else
1653         return sName;
1654 }
1655 
1656 ::std::vector<Reference<deployment::XPackage> >
1657 BackendImpl::PackageImpl::getPackagesFromDb(
1658     Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1659 {
1660     ::std::vector<Reference<deployment::XPackage> > retVector;
1661 
1662     typedef ::std::vector< ::std::pair<OUString, OUString> >::const_iterator ITC;
1663     for (ITC i = m_dbData.items.begin(); i != m_dbData.items.end(); i++)
1664     {
1665         Reference<deployment::XPackage> xExtension =
1666             bindBundleItem(i->first, i->second, true, m_identifier, xCmdEnv);
1667         OSL_ASSERT(xExtension.is());
1668         retVector.push_back(xExtension);
1669     }
1670 
1671     return retVector;
1672 }
1673 
1674 } // anon namespace
1675 
1676 //==============================================================================
1677 Reference<deployment::XPackageRegistry> create(
1678     Reference<deployment::XPackageRegistry> const & xRootRegistry,
1679     OUString const & context, OUString const & cachePath, bool readOnly,
1680     Reference<XComponentContext> const & xComponentContext )
1681 {
1682     Sequence<Any> args(
1683         cachePath.getLength() == 0 ? 1 : 3 );
1684     args[ 0 ] <<= context;
1685     if (cachePath.getLength() > 0) {
1686         args[ 1 ] <<= cachePath;
1687         args[ 2 ] <<= readOnly;
1688     }
1689     return new BackendImpl( args, xComponentContext, xRootRegistry );
1690 }
1691 
1692 } // namespace bundle
1693 } // namespace backend
1694 } // namespace dp_registry
1695 
1696