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