Update ooo320-m1
[ooovba.git] / desktop / source / deployment / registry / package / dp_package.cxx
blob0b1eccf91ce2baeea8865979decc91586e4a9fce
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dp_package.cxx,v $
10 * $Revision: 1.34.16.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_desktop.hxx"
34 #include "dp_package.hrc"
35 #include "dp_backend.h"
36 #include "dp_ucb.h"
37 #include "dp_interact.h"
38 #include "dp_dependencies.hxx"
39 #include "dp_platform.hxx"
40 #include "dp_description.hxx"
41 #include "dp_descriptioninfoset.hxx"
42 #include "dp_identifier.hxx"
43 #include "rtl/uri.hxx"
44 #include "cppuhelper/exc_hlp.hxx"
45 #include "cppuhelper/implbase1.hxx"
46 #include "ucbhelper/content.hxx"
47 #include "svtools/inettype.hxx"
48 #include "comphelper/anytostring.hxx"
49 #include "comphelper/makesequence.hxx"
50 #include "comphelper/sequence.hxx"
51 #include "com/sun/star/lang/WrappedTargetException.hpp"
52 #include "com/sun/star/lang/XServiceInfo.hpp"
53 #include "com/sun/star/beans/UnknownPropertyException.hpp"
54 #include "com/sun/star/graphic/XGraphic.hpp"
55 #include "com/sun/star/graphic/XGraphicProvider.hpp"
56 #include "com/sun/star/io/XOutputStream.hpp"
57 #include "com/sun/star/io/XInputStream.hpp"
58 #include "com/sun/star/task/InteractionClassification.hpp"
59 #include "com/sun/star/task/XInteractionApprove.hpp"
60 #include "com/sun/star/ucb/XInteractionReplaceExistingData.hpp"
61 #include "com/sun/star/ucb/NameClashResolveRequest.hpp"
62 #include "com/sun/star/ucb/XContentAccess.hpp"
63 #include "com/sun/star/ucb/NameClash.hpp"
64 #include "com/sun/star/ucb/UnsupportedCommandException.hpp"
65 #include "com/sun/star/sdbc/XResultSet.hpp"
66 #include "com/sun/star/sdbc/XRow.hpp"
67 #include "com/sun/star/packages/manifest/XManifestReader.hpp"
68 #include "com/sun/star/packages/manifest/XManifestWriter.hpp"
69 #include "com/sun/star/deployment/DependencyException.hpp"
70 #include "com/sun/star/deployment/LicenseException.hpp"
71 #include "com/sun/star/deployment/LicenseIndividualAgreementException.hpp"
72 #include "com/sun/star/deployment/PlatformException.hpp"
73 #include "com/sun/star/xml/dom/XDocumentBuilder.hpp"
74 #include "com/sun/star/xml/xpath/XXPathAPI.hpp"
75 #include "com/sun/star/deployment/XPackageManager.hpp"
77 #include <vector>
78 #include <stdio.h>
81 using namespace ::dp_misc;
82 using namespace ::com::sun::star;
83 using namespace ::com::sun::star::uno;
84 using namespace ::com::sun::star::ucb;
85 namespace css = ::com::sun::star;
86 namespace cssu = ::com::sun::star::uno;
87 using ::rtl::OUString;
89 namespace dp_registry {
90 namespace backend {
91 namespace bundle {
92 namespace {
94 typedef cppu::ImplInheritanceHelper1<PackageRegistryBackend,
95 lang::XServiceInfo> ImplBaseT;
97 //==============================================================================
98 class BackendImpl : public ImplBaseT
100 class PackageImpl : public ::dp_registry::backend::Package
102 BackendImpl * getMyBackend() const;
103 /** constains the old tooltip description for the Extension Manager GUI in OOo v.2.x
104 We keep it for backward compatibility.
106 OUString m_oldDescription;
107 OUString m_url_expanded;
108 const bool m_legacyBundle;
109 Sequence< Reference<deployment::XPackage> > m_bundle;
110 Sequence< Reference<deployment::XPackage> > * m_pBundle;
112 Reference<deployment::XPackage> bindBundleItem(
113 OUString const & url, OUString const & mediaType,
114 Reference<XCommandEnvironment> const & xCmdEnv,
115 bool notifyDetectionError = true );
117 typedef ::std::vector< Reference<deployment::XPackage> > t_packagevec;
118 void scanBundle(
119 t_packagevec & bundle,
120 ::rtl::Reference<AbortChannel> const & abortChannel,
121 Reference<XCommandEnvironment> const & xCmdEnv );
122 void scanLegacyBundle(
123 t_packagevec & bundle,
124 OUString const & url,
125 ::rtl::Reference<AbortChannel> const & abortChannel,
126 Reference<XCommandEnvironment> const & xCmdEnv,
127 bool skip_registration = false );
129 bool checkPlatform(
130 css::uno::Reference< css::ucb::XCommandEnvironment > const & environment);
132 bool checkDependencies(
133 css::uno::Reference< css::ucb::XCommandEnvironment > const &
134 environment,
135 ExtensionDescription const & description);
136 // throws css::uno::RuntimeException,
137 // css::deployment::DeploymentException
139 ::sal_Bool checkLicense(
140 css::uno::Reference< css::ucb::XCommandEnvironment > const & xCmdEnv,
141 ExtensionDescription const& description, bool bInstalled,
142 OUString const & aContextName )
143 throw (css::deployment::DeploymentException,
144 css::ucb::CommandFailedException,
145 css::ucb::CommandAbortedException,
146 css::uno::RuntimeException);
147 // @throws DeploymentException
148 OUString getTextFromURL(
149 const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv,
150 const OUString& licenseUrl);
152 DescriptionInfoset getDescriptionInfoset();
154 // Package
155 virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_(
156 ::osl::ResettableMutexGuard & guard,
157 ::rtl::Reference<AbortChannel> const & abortChannel,
158 Reference<XCommandEnvironment> const & xCmdEnv );
159 virtual void processPackage_(
160 ::osl::ResettableMutexGuard & guard,
161 bool registerPackage,
162 ::rtl::Reference<AbortChannel> const & abortChannel,
163 Reference<XCommandEnvironment> const & xCmdEnv );
165 virtual void SAL_CALL disposing();
169 public:
170 PackageImpl(
171 ::rtl::Reference<PackageRegistryBackend> const & myBackend,
172 OUString const & url,
173 OUString const & name,
174 Reference<deployment::XPackageTypeInfo> const & xPackageType,
175 bool legacyBundle )
176 : Package( myBackend, url, name, name /* display-name */,
177 xPackageType ),
178 m_url_expanded( expandUnoRcUrl( url ) ),
179 m_legacyBundle( legacyBundle ),
180 m_pBundle( 0 )
183 // XPackage
184 virtual sal_Bool SAL_CALL isBundle() throw (RuntimeException);
185 virtual Sequence< Reference<deployment::XPackage> > SAL_CALL getBundle(
186 Reference<task::XAbortChannel> const & xAbortChannel,
187 Reference<XCommandEnvironment> const & xCmdEnv )
188 throw (deployment::DeploymentException,
189 CommandFailedException, CommandAbortedException,
190 lang::IllegalArgumentException, RuntimeException);
191 virtual OUString SAL_CALL getDescription() throw (RuntimeException);
192 virtual void SAL_CALL exportTo(
193 OUString const & destFolderURL, OUString const & newTitle,
194 sal_Int32 nameClashAction,
195 Reference<XCommandEnvironment> const & xCmdEnv )
196 throw (CommandFailedException, CommandAbortedException,
197 RuntimeException);
199 virtual ::sal_Bool SAL_CALL checkPrerequisites(
200 const css::uno::Reference< css::task::XAbortChannel >& xAbortChannel,
201 const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv,
202 ::sal_Bool bInstalled, OUString const & aContextName)
203 throw (css::deployment::DeploymentException,
204 css::ucb::CommandFailedException,
205 css::ucb::CommandAbortedException,
206 css::uno::RuntimeException);
208 virtual ::sal_Bool SAL_CALL checkDependencies(
209 const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv )
210 throw (css::deployment::DeploymentException,
211 css::ucb::CommandFailedException,
212 css::uno::RuntimeException);
214 virtual beans::Optional<OUString> SAL_CALL getIdentifier()
215 throw (RuntimeException);
217 virtual OUString SAL_CALL getVersion() throw (RuntimeException);
219 virtual Sequence<OUString> SAL_CALL getUpdateInformationURLs()
220 throw (RuntimeException);
222 virtual css::beans::StringPair SAL_CALL getPublisherInfo() throw (css::uno::RuntimeException);
224 virtual OUString SAL_CALL getDisplayName() throw (RuntimeException);
225 virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL getIcon( ::sal_Bool bHighContrast ) throw (css::uno::RuntimeException);
227 friend class PackageImpl;
229 Reference<deployment::XPackageRegistry> m_xRootRegistry;
230 const Reference<deployment::XPackageTypeInfo> m_xBundleTypeInfo;
231 const Reference<deployment::XPackageTypeInfo> m_xLegacyBundleTypeInfo;
232 Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos;
234 // PackageRegistryBackend
235 virtual Reference<deployment::XPackage> bindPackage_(
236 OUString const & url, OUString const & mediaType,
237 Reference<XCommandEnvironment> const & xCmdEnv );
239 virtual void SAL_CALL disposing();
241 public:
242 BackendImpl(
243 Sequence<Any> const & args,
244 Reference<XComponentContext> const & xComponentContext,
245 Reference<deployment::XPackageRegistry> const & xRootRegistry );
247 // XServiceInfo
248 virtual OUString SAL_CALL getImplementationName() throw (RuntimeException);
249 virtual sal_Bool SAL_CALL supportsService( OUString const& name )
250 throw (RuntimeException);
251 virtual Sequence<OUString> SAL_CALL getSupportedServiceNames()
252 throw (RuntimeException);
254 // XPackageRegistry
255 virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL
256 getSupportedPackageTypes() throw (RuntimeException);
258 using ImplBaseT::disposing;
261 //Used to find a XPackage with a particular URL
262 class XPackage_eq : public std::unary_function<Reference<deployment::XPackage>, bool>
264 OUString m_URL;
265 public:
266 explicit XPackage_eq(const OUString & s) : m_URL(s) {}
267 bool operator() (const Reference<deployment::XPackage> & p) const
269 return m_URL.equals(p->getURL());
273 //______________________________________________________________________________
274 BackendImpl::BackendImpl(
275 Sequence<Any> const & args,
276 Reference<XComponentContext> const & xComponentContext,
277 Reference<deployment::XPackageRegistry> const & xRootRegistry )
278 : ImplBaseT( args, xComponentContext ),
279 m_xRootRegistry( xRootRegistry ),
280 m_xBundleTypeInfo( new Package::TypeInfo(
281 OUSTR("application/vnd.sun.star.package-bundle"),
282 OUSTR("*.oxt;*.uno.pkg"),
283 getResourceString(RID_STR_PACKAGE_BUNDLE),
284 RID_IMG_DEF_PACKAGE_BUNDLE,
285 RID_IMG_DEF_PACKAGE_BUNDLE_HC ) ),
286 m_xLegacyBundleTypeInfo( new Package::TypeInfo(
287 OUSTR("application/"
288 "vnd.sun.star.legacy-package-bundle"),
289 OUSTR("*.zip"),
290 m_xBundleTypeInfo->getShortDescription(),
291 RID_IMG_DEF_PACKAGE_BUNDLE,
292 RID_IMG_DEF_PACKAGE_BUNDLE_HC ) ),
293 m_typeInfos( 2 )
295 m_typeInfos[ 0 ] = m_xBundleTypeInfo;
296 m_typeInfos[ 1 ] = m_xLegacyBundleTypeInfo;
299 //______________________________________________________________________________
300 void BackendImpl::disposing()
302 m_xRootRegistry.clear();
303 PackageRegistryBackend::disposing();
306 // XServiceInfo
307 OUString BackendImpl::getImplementationName() throw (RuntimeException)
309 return OUSTR("com.sun.star.comp.deployment.bundle.PackageRegistryBackend");
312 sal_Bool BackendImpl::supportsService( OUString const& name )
313 throw (RuntimeException)
315 return getSupportedServiceNames()[0].equals(name);
318 Sequence<OUString> BackendImpl::getSupportedServiceNames()
319 throw (RuntimeException)
321 return comphelper::makeSequence(
322 OUString::createFromAscii(BACKEND_SERVICE_NAME) );
325 // XPackageRegistry
326 //______________________________________________________________________________
327 Sequence< Reference<deployment::XPackageTypeInfo> >
328 BackendImpl::getSupportedPackageTypes() throw (RuntimeException)
330 return m_typeInfos;
335 // PackageRegistryBackend
336 //______________________________________________________________________________
337 Reference<deployment::XPackage> BackendImpl::bindPackage_(
338 OUString const & url, OUString const & mediaType_,
339 Reference<XCommandEnvironment> const & xCmdEnv )
341 OUString mediaType( mediaType_ );
342 if (mediaType.getLength() == 0)
344 // detect media-type:
345 ::ucbhelper::Content ucbContent;
346 if (create_ucb_content( &ucbContent, url, xCmdEnv ))
348 const OUString title( ucbContent.getPropertyValue(
349 StrTitle::get() ).get<OUString>() );
350 if (title.endsWithIgnoreAsciiCaseAsciiL(
351 RTL_CONSTASCII_STRINGPARAM(".oxt") ) ||
352 title.endsWithIgnoreAsciiCaseAsciiL(
353 RTL_CONSTASCII_STRINGPARAM(".uno.pkg") ))
354 mediaType = OUSTR("application/vnd.sun.star.package-bundle");
355 else if (title.endsWithIgnoreAsciiCaseAsciiL(
356 RTL_CONSTASCII_STRINGPARAM(".zip") ))
357 mediaType =
358 OUSTR("application/vnd.sun.star.legacy-package-bundle");
360 if (mediaType.getLength() == 0)
361 throw lang::IllegalArgumentException(
362 StrCannotDetectMediaType::get() + url,
363 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
366 String type, subType;
367 INetContentTypeParameterList params;
368 if (INetContentTypes::parse( mediaType, type, subType, &params ))
370 if (type.EqualsIgnoreCaseAscii("application"))
372 ::ucbhelper::Content ucbContent( url, xCmdEnv );
373 if (subType.EqualsIgnoreCaseAscii("vnd.sun.star.package-bundle")) {
374 return new PackageImpl(
375 this, url, ucbContent.getPropertyValue(
376 StrTitle::get() ).get<OUString>(),
377 m_xBundleTypeInfo, false );
379 else if (subType.EqualsIgnoreCaseAscii(
380 "vnd.sun.star.legacy-package-bundle")) {
381 return new PackageImpl(
382 this, url, ucbContent.getPropertyValue(
383 StrTitle::get() ).get<OUString>(),
384 m_xLegacyBundleTypeInfo, true );
388 throw lang::IllegalArgumentException(
389 StrUnsupportedMediaType::get() + mediaType,
390 static_cast<OWeakObject *>(this),
391 static_cast<sal_Int16>(-1) );
394 //##############################################################################
396 BackendImpl * BackendImpl::PackageImpl::getMyBackend() const
398 BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get());
399 if (NULL == pBackend)
401 //May throw a DisposedException
402 check();
403 //We should never get here...
404 throw RuntimeException(
405 OUSTR("Failed to get the BackendImpl"),
406 static_cast<OWeakObject*>(const_cast<PackageImpl *>(this)));
408 return pBackend;
410 //______________________________________________________________________________
411 void BackendImpl::PackageImpl::disposing()
413 sal_Int32 len = m_bundle.getLength();
414 Reference<deployment::XPackage> const * p = m_bundle.getConstArray();
415 for ( sal_Int32 pos = 0; pos < len; ++pos )
416 try_dispose( p[ pos ] );
417 m_bundle.realloc( 0 );
419 Package::disposing();
422 // Package
423 //______________________________________________________________________________
424 beans::Optional< beans::Ambiguous<sal_Bool> >
425 BackendImpl::PackageImpl::isRegistered_(
426 ::osl::ResettableMutexGuard &,
427 ::rtl::Reference<AbortChannel> const & abortChannel,
428 Reference<XCommandEnvironment> const & xCmdEnv )
430 const Sequence< Reference<deployment::XPackage> > bundle(
431 getBundle( abortChannel.get(), xCmdEnv ) );
432 bool reg = false;
433 bool present = false;
434 bool ambig = false;
435 for ( sal_Int32 pos = bundle.getLength(); pos--; )
437 Reference<deployment::XPackage> const & xPackage = bundle[ pos ];
438 //disregard executable (application/vnd.sun.star.executable)
439 //it will not be disabled/enabled.
440 OUString sType = xPackage->getPackageType()->getMediaType();
441 if (sType.equals(OUSTR("application/vnd.sun.star.executable")))
442 continue;
444 Reference<task::XAbortChannel> xSubAbortChannel(
445 xPackage->createAbortChannel() );
446 AbortChannel::Chain chain( abortChannel, xSubAbortChannel );
447 beans::Optional< beans::Ambiguous<sal_Bool> > option(
448 xPackage->isRegistered( xSubAbortChannel, xCmdEnv ) );
449 if (option.IsPresent)
451 beans::Ambiguous<sal_Bool> const & status = option.Value;
452 if (present)
454 if (reg != (status.Value != sal_False)) {
455 ambig = true;
456 reg = false;
457 break;
460 else
462 reg = status.Value;
463 present = true;
467 return beans::Optional< beans::Ambiguous<sal_Bool> >(
468 present, beans::Ambiguous<sal_Bool>(reg, ambig) );
471 OUString BackendImpl::PackageImpl::getTextFromURL(
472 const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv,
473 const OUString& licenseUrl)
477 ::ucbhelper::Content descContent(licenseUrl, xCmdEnv);
478 ::rtl::ByteSequence seq = dp_misc::readFile(descContent);
479 return OUString( reinterpret_cast<sal_Char const *>(
480 seq.getConstArray()), seq.getLength(), RTL_TEXTENCODING_UTF8);
482 catch (css::uno::Exception&)
484 Any exc( ::cppu::getCaughtException() );
485 throw css::deployment::DeploymentException(
486 OUSTR("Could not read file ") + licenseUrl, 0, exc);
491 DescriptionInfoset BackendImpl::PackageImpl::getDescriptionInfoset()
493 css::uno::Reference< css::xml::dom::XNode > root;
494 try {
495 root =
496 ExtensionDescription(
497 getMyBackend()->getComponentContext(), m_url_expanded,
498 css::uno::Reference< css::ucb::XCommandEnvironment >()).
499 getRootElement();
500 } catch (NoDescriptionException &) {
501 } catch (css::deployment::DeploymentException & e) {
502 throw RuntimeException(
503 (OUString(
504 RTL_CONSTASCII_USTRINGPARAM(
505 "com.sun.star.deployment.DeploymentException: ")) +
506 e.Message),
507 static_cast< OWeakObject * >(this));
509 return DescriptionInfoset(getMyBackend()->getComponentContext(), root);
512 bool BackendImpl::PackageImpl::checkPlatform(
513 css::uno::Reference< css::ucb::XCommandEnvironment > const & environment)
515 bool ret = false;
516 DescriptionInfoset info(getDescriptionInfoset());
517 Sequence<OUString> platforms(info.getSupportedPlaforms());
518 if (hasValidPlatform(platforms))
520 ret = true;
522 else
524 ret = false;
525 rtl::OUString msg(
526 RTL_CONSTASCII_USTRINGPARAM("unsupported platform"));
527 Any e(
528 css::deployment::PlatformException(
529 msg, static_cast<OWeakObject *>(this), this));
530 if (!interactContinuation(
531 e, cppu::UnoType< css::task::XInteractionApprove >::get(),
532 environment, NULL, NULL))
534 throw css::deployment::DeploymentException(
535 msg, static_cast<OWeakObject *>(this), e);
538 return ret;
542 bool BackendImpl::PackageImpl::checkDependencies(
543 css::uno::Reference< css::ucb::XCommandEnvironment > const & environment,
544 ExtensionDescription const & description)
546 css::uno::Sequence< css::uno::Reference< css::xml::dom::XElement > >
547 unsatisfied(
548 dp_misc::Dependencies::check(
549 DescriptionInfoset(
550 getMyBackend()->getComponentContext(),
551 description.getRootElement())));
552 if (unsatisfied.getLength() == 0) {
553 return true;
554 } else {
555 rtl::OUString msg(
556 RTL_CONSTASCII_USTRINGPARAM("unsatisfied dependencies"));
557 Any e(
558 css::deployment::DependencyException(
559 msg, static_cast<OWeakObject *>(this), unsatisfied));
560 if (!interactContinuation(
561 e, cppu::UnoType< css::task::XInteractionApprove >::get(),
562 environment, NULL, NULL))
564 throw css::deployment::DeploymentException(
565 msg, static_cast<OWeakObject *>(this), e);
567 return false;
571 ::sal_Bool BackendImpl::PackageImpl::checkLicense(
572 css::uno::Reference< css::ucb::XCommandEnvironment > const & xCmdEnv,
573 ExtensionDescription const & desc, bool bInstalled, OUString const & aContextName)
574 throw (css::deployment::DeploymentException,
575 css::ucb::CommandFailedException,
576 css::ucb::CommandAbortedException,
577 css::uno::RuntimeException)
579 try
581 css::uno::Reference<css::xml::dom::XNode> xRoot = desc.getRootElement();
582 css::uno::Reference<css::xml::xpath::XXPathAPI> xPath =
583 getDescriptionInfoset().getXpath();
585 css::uno::Reference<css::xml::dom::XNode> nodeSimpleLic;
586 try {
587 nodeSimpleLic = xPath->selectSingleNode(xRoot,
588 OUSTR("/desc:description/desc:registration/desc:simple-license"));
589 } catch (css::xml::xpath::XPathException &) {
590 // ignore
593 if (!nodeSimpleLic.is())
594 return true;
595 OUString sLic = getDescriptionInfoset().getLocalizedLicenseURL();
596 //If we do not get a localized licence then there is an error in the description.xml
597 //This should be handled by using a validating parser. Therefore we assume that no
598 //license is available.
599 if (sLic.getLength() == 0)
600 throw css::deployment::DeploymentException(
601 OUSTR("Could not obtain path to license. Possible error in description.xml"), 0, Any());
602 OUString sHref = desc.getExtensionRootUrl() + OUSTR("/") + sLic;
603 OUString sLicense = getTextFromURL(xCmdEnv, sHref);
604 //determine who has to agree to the license
605 css::uno::Reference<css::xml::xpath::XXPathObject> nodeAttribWho3 =
606 xPath->eval(nodeSimpleLic,
607 OUSTR("@accept-by"));
608 OUString sAccept = nodeAttribWho3->getString().trim();
609 //check correct value for attribute
610 if ( ! (sAccept.equals(OUSTR("user")) || sAccept.equals(OUSTR("admin"))))
611 throw css::deployment::DeploymentException(
612 OUSTR("Could not obtain attribute simple-lincense@accept-by or it has no valid value"), 0, Any());
614 //If if @accept-by="user" then every user needs to accept the license before it can be installed.
615 //Therefore we must prevent the installation as shared extension.
616 OSL_ASSERT(aContextName.getLength());
617 if (sAccept.equals(OUSTR("user")) && aContextName.equals(OUSTR("shared")))
619 css::deployment::LicenseIndividualAgreementException exc =
620 css::deployment::LicenseIndividualAgreementException(OUString(), 0, m_name);
622 bool approve = false;
623 bool abort = false;
624 if (! interactContinuation(
625 Any(exc), task::XInteractionApprove::static_type(), xCmdEnv, &approve, &abort ))
626 throw css::deployment::DeploymentException(
627 OUSTR("Could not interact with user."), 0, Any());
628 if (abort == true)
629 return false;
630 //We should always prevent installation
631 OSL_ASSERT(0);
634 //determine optional attribute simple-license@suppressOnUpdate
635 css::uno::Reference<css::xml::dom::XElement> elemSimpleLic(nodeSimpleLic, css::uno::UNO_QUERY_THROW);
636 sal_Bool bSuppress = sal_False;
637 if (elemSimpleLic->hasAttribute(OUSTR("suppress-on-update")))
639 if (elemSimpleLic->getAttribute(OUSTR("suppress-on-update")).equals(OUSTR("true")))
640 bSuppress = sal_True;
643 //Only use interaction if there is no version of this extension already installed
644 //and the suppress-on-update flag is not set for the new extension
645 // bInstalled | bSuppress | show license
646 //----------------------------------------
647 // 0 | 0 | 1
648 // 0 | 1 | 1
649 // 1 | 0 | 1
650 // 1 | 1 | 0
652 if ( !(bInstalled && bSuppress))
654 css::deployment::LicenseException licExc =
655 css::deployment::LicenseException(OUString(), 0, m_name, sLicense);
656 bool approve = false;
657 bool abort = false;
658 if (! interactContinuation(
659 Any(licExc), task::XInteractionApprove::static_type(), xCmdEnv, &approve, &abort ))
660 throw css::deployment::DeploymentException(
661 OUSTR("Could not interact with user."), 0, Any());
663 if (approve == true)
664 return true;
665 else
666 return false;
667 //throw css::deployment::DeploymentException(
668 // OUSTR("Extension Manager: User declined the license."),
669 // static_cast<OWeakObject*>(this),
670 // Any( css::deployment::LicenseException(OUSTR("User declined the license."), 0, m_name, sLicense)));
672 return true;
673 } catch (css::ucb::CommandFailedException&) {
674 throw;
675 } catch (css::ucb::CommandAbortedException&) {
676 throw;
677 } catch (css::deployment::DeploymentException&) {
678 throw;
679 } catch (css::uno::RuntimeException&) {
680 throw;
681 } catch (css::uno::Exception&) {
682 Any anyExc = cppu::getCaughtException();
683 throw css::deployment::DeploymentException(OUSTR("Unexpected exception"), 0, anyExc);
687 ::sal_Bool BackendImpl::PackageImpl::checkPrerequisites(
688 const css::uno::Reference< css::task::XAbortChannel >&,
689 const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv,
690 sal_Bool bInstalled, OUString const & aContextName)
691 throw (css::deployment::DeploymentException,
692 css::ucb::CommandFailedException,
693 css::ucb::CommandAbortedException,
694 css::uno::RuntimeException)
696 std::auto_ptr<ExtensionDescription> spDescription;
697 try {
698 spDescription.reset(
699 new ExtensionDescription(
700 getMyBackend()->getComponentContext(),
701 m_url_expanded,
702 xCmdEnv));
703 } catch (NoDescriptionException& ) {
704 return sal_True;
706 return checkPlatform(xCmdEnv)
707 && checkDependencies(xCmdEnv, *spDescription)
708 && checkLicense(xCmdEnv, *spDescription, bInstalled, aContextName);
711 ::sal_Bool BackendImpl::PackageImpl::checkDependencies(
712 const css::uno::Reference< css::ucb::XCommandEnvironment >& xCmdEnv )
713 throw (css::deployment::DeploymentException,
714 css::ucb::CommandFailedException,
715 css::uno::RuntimeException)
717 std::auto_ptr<ExtensionDescription> spDescription;
718 try {
719 spDescription.reset(
720 new ExtensionDescription( getMyBackend()->getComponentContext(), m_url_expanded, xCmdEnv ));
721 } catch (NoDescriptionException& ) {
722 return sal_True;
724 return checkDependencies(xCmdEnv, *spDescription);
727 beans::Optional<OUString> BackendImpl::PackageImpl::getIdentifier()
728 throw (RuntimeException)
730 return beans::Optional<OUString>(
731 true,
732 dp_misc::generateIdentifier(
733 getDescriptionInfoset().getIdentifier(), m_name));
736 OUString BackendImpl::PackageImpl::getVersion() throw (RuntimeException)
738 return getDescriptionInfoset().getVersion();
741 Sequence<OUString> BackendImpl::PackageImpl::getUpdateInformationURLs()
742 throw (RuntimeException)
744 return getDescriptionInfoset().getUpdateInformationUrls();
747 beans::StringPair BackendImpl::PackageImpl::getPublisherInfo()
748 throw (RuntimeException)
750 ::std::pair< OUString, OUString > aInfo = getDescriptionInfoset().getLocalizedPublisherNameAndURL();
751 beans::StringPair aStrPair( aInfo.first, aInfo.second );
752 return aStrPair;
755 //______________________________________________________________________________
756 uno::Reference< graphic::XGraphic > BackendImpl::PackageImpl::getIcon( sal_Bool bHighContrast )
757 throw ( RuntimeException )
759 uno::Reference< graphic::XGraphic > xGraphic;
761 OUString aIconURL = getDescriptionInfoset().getIconURL( bHighContrast );
762 if ( aIconURL.getLength() )
764 OUString aFullIconURL = m_url_expanded + OUSTR("/") + aIconURL;
766 uno::Reference< XComponentContext > xContext( getMyBackend()->getComponentContext() );
767 uno::Reference< graphic::XGraphicProvider > xGraphProvider(
768 xContext->getServiceManager()->createInstanceWithContext( OUSTR( "com.sun.star.graphic.GraphicProvider" ), xContext ),
769 uno::UNO_QUERY );
771 if ( xGraphProvider.is() )
773 uno::Sequence< beans::PropertyValue > aMediaProps( 1 );
774 aMediaProps[0].Name = OUSTR( "URL" );
775 aMediaProps[0].Value <<= aFullIconURL;
777 xGraphic = xGraphProvider->queryGraphic( aMediaProps );
781 return xGraphic;
784 //______________________________________________________________________________
785 void BackendImpl::PackageImpl::processPackage_(
786 ::osl::ResettableMutexGuard &,
787 bool doRegisterPackage,
788 ::rtl::Reference<AbortChannel> const & abortChannel,
789 Reference<XCommandEnvironment> const & xCmdEnv )
791 const Sequence< Reference<deployment::XPackage> > bundle(
792 getBundle( abortChannel.get(), xCmdEnv ) );
794 if (doRegisterPackage)
796 const sal_Int32 len = bundle.getLength();
797 for ( sal_Int32 pos = 0; pos < len; ++pos )
799 checkAborted(abortChannel);
800 Reference<deployment::XPackage> const & xPackage = bundle[ pos ];
801 Reference<task::XAbortChannel> xSubAbortChannel(
802 xPackage->createAbortChannel() );
803 AbortChannel::Chain chain( abortChannel, xSubAbortChannel );
804 try {
805 xPackage->registerPackage( xSubAbortChannel, xCmdEnv );
807 catch (RuntimeException &) {
808 throw;
810 catch (CommandAbortedException &) {
811 throw;
813 catch (Exception &) {
814 // CommandFailedException, DeploymentException:
815 Any exc( ::cppu::getCaughtException() );
816 // try to handle exception, notify:
817 bool approve = false, abort = false;
818 if (! interactContinuation(
819 Any( lang::WrappedTargetException(
820 OUSTR("bundle item registration error!"),
821 static_cast<OWeakObject *>(this), exc ) ),
822 task::XInteractionApprove::static_type(), xCmdEnv,
823 &approve, &abort )) {
824 OSL_ASSERT( !approve && !abort );
825 if (m_legacyBundle) // default for legacy packages: ignore
826 continue;
827 // no selection at all, so rethrow;
828 // no C++ rethrow after getCaughtException(),
829 // see cppuhelper/exc_hlp.hxx:
830 ::cppu::throwException(exc);
832 if (approve && !abort) // ignore error, just continue
833 continue;
836 ProgressLevel progress(
837 xCmdEnv, OUSTR("rollback...") );
838 // try rollback
839 for ( ; pos--; )
841 try {
842 bundle[ pos ]->revokePackage(
843 xSubAbortChannel, xCmdEnv );
845 catch (RuntimeException &) {
846 throw;
848 catch (CommandAbortedException &) {
849 throw;
851 catch (Exception &) {
852 // bundle rollback error:
853 OSL_ENSURE( 0, ::rtl::OUStringToOString(
854 ::comphelper::anyToString(
855 ::cppu::getCaughtException() ),
856 RTL_TEXTENCODING_UTF8 ).getStr() );
857 // ignore any errors of rollback
860 progress.update( OUSTR("rollback finished.") );
863 deployment::DeploymentException dpExc;
864 if (exc >>= dpExc) {
865 throw CommandFailedException(
866 dpExc.Message, dpExc.Context, dpExc.Cause );
868 else {
869 // rethrow CommandFailedException
870 ::cppu::throwException(exc);
875 else
877 // revoke in reverse order:
878 for ( sal_Int32 pos = bundle.getLength(); pos--; )
880 checkAborted(abortChannel);
881 Reference<deployment::XPackage> const & xPackage = bundle[ pos ];
882 Reference<task::XAbortChannel> xSubAbortChannel(
883 xPackage->createAbortChannel() );
884 AbortChannel::Chain chain( abortChannel, xSubAbortChannel );
885 try {
886 bundle[ pos ]->revokePackage( xSubAbortChannel, xCmdEnv );
888 catch (RuntimeException &) {
889 throw;
891 catch (CommandAbortedException &) {
892 throw;
894 catch (Exception &) {
895 // CommandFailedException, DeploymentException:
896 Any exc( ::cppu::getCaughtException() );
897 // try to handle exception, notify:
898 bool approve = false, abort = false;
899 if (! interactContinuation(
900 Any( lang::WrappedTargetException(
901 OUSTR("bundle item revocation error!"),
902 static_cast<OWeakObject *>(this), exc ) ),
903 task::XInteractionApprove::static_type(), xCmdEnv,
904 &approve, &abort )) {
905 OSL_ASSERT( !approve && !abort );
906 if (m_legacyBundle) // default for legacy packages: ignore
907 continue;
908 // no selection at all, so rethrow
909 // no C++ rethrow after getCaughtException(),
910 // see cppuhelper/exc_hlp.hxx:
911 ::cppu::throwException(exc);
913 // ignore errors when revoking, although abort may have been
914 // selected
920 //______________________________________________________________________________
921 OUString BackendImpl::PackageImpl::getDescription() throw (RuntimeException)
923 const OUString sRelativeURL(getDescriptionInfoset().getLocalizedDescriptionURL());
924 OUString sDescription;
925 if (sRelativeURL.getLength())
927 OUString sURL = m_url_expanded + OUSTR("/") + sRelativeURL;
928 sDescription = getTextFromURL(
929 css::uno::Reference< css::ucb::XCommandEnvironment >(), sURL);
932 if (sDescription.getLength())
933 return sDescription;
934 else if(m_oldDescription.getLength())
935 return m_oldDescription;
936 else
937 return OUString();
940 //______________________________________________________________________________
941 void BackendImpl::PackageImpl::exportTo(
942 OUString const & destFolderURL, OUString const & newTitle,
943 sal_Int32 nameClashAction, Reference<XCommandEnvironment> const & xCmdEnv )
944 throw (CommandFailedException, CommandAbortedException, RuntimeException)
946 ::ucbhelper::Content sourceContent( m_url_expanded, xCmdEnv );
947 OUString title(newTitle);
948 if (title.getLength() == 0)
949 sourceContent.getPropertyValue( StrTitle::get() ) >>= title;
950 OUString destURL( makeURL( destFolderURL, ::rtl::Uri::encode(
951 title, rtl_UriCharClassPchar,
952 rtl_UriEncodeIgnoreEscapes,
953 RTL_TEXTENCODING_UTF8 ) ) );
955 if (nameClashAction == NameClash::ASK)
957 if (create_ucb_content(
958 0, destURL, xCmdEnv, false /* no throw */ )) {
959 bool replace = false, abort = false;
960 if (! interactContinuation(
961 Any( NameClashResolveRequest(
962 OUSTR("file already exists: ") + title,
963 static_cast<OWeakObject *>(this),
964 task::InteractionClassification_QUERY,
965 destFolderURL, title, OUString() ) ),
966 XInteractionReplaceExistingData::static_type(), xCmdEnv,
967 &replace, &abort ) || !replace) {
968 return;
972 else if (nameClashAction != NameClash::OVERWRITE) {
973 throw CommandFailedException(
974 OUSTR("unsupported nameClashAction!"),
975 static_cast<OWeakObject *>(this), Any() );
977 erase_path( destURL, xCmdEnv );
979 ::rtl::OUStringBuffer buf;
980 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.zip://") );
981 buf.append( ::rtl::Uri::encode( destURL,
982 rtl_UriCharClassRegName,
983 rtl_UriEncodeIgnoreEscapes,
984 RTL_TEXTENCODING_UTF8 ) );
985 buf.append( static_cast<sal_Unicode>('/') );
986 OUString destFolder( buf.makeStringAndClear() );
988 ::ucbhelper::Content destFolderContent( destFolder, xCmdEnv );
990 // transfer every item of folder into zip:
991 Reference<sdbc::XResultSet> xResultSet(
992 sourceContent.createCursor(
993 Sequence<OUString>(),
994 ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) );
995 ProgressLevel progress( xCmdEnv, OUString() );
996 while (xResultSet->next())
998 ::ucbhelper::Content subContent(
999 Reference<XContentAccess>(
1000 xResultSet, UNO_QUERY_THROW )->queryContent(), xCmdEnv );
1001 if (! destFolderContent.transferContent(
1002 subContent, ::ucbhelper::InsertOperation_COPY,
1003 OUString(), NameClash::OVERWRITE ))
1004 throw RuntimeException( OUSTR("UCB transferContent() failed!"),
1005 static_cast<OWeakObject *>(this) );
1006 progress.update( Any() ); // animating progress bar
1010 // assure META-INF folder:
1011 ::ucbhelper::Content metainfFolderContent;
1012 create_folder( &metainfFolderContent,
1013 makeURL( destFolderContent.getURL(), OUSTR("META-INF") ),
1014 xCmdEnv );
1016 if (m_legacyBundle)
1018 // easy to migrate legacy bundles to new format:
1019 // just export them once using a .oxt name!
1020 // set detected media-types of any bundle item:
1022 // collect all manifest entries:
1023 Sequence< Reference<deployment::XPackage> > bundle;
1024 try {
1025 bundle = getBundle( Reference<task::XAbortChannel>(), xCmdEnv );
1027 // xxx todo: think about exception specs:
1028 catch (deployment::DeploymentException &) {
1029 OSL_ENSURE( 0, ::rtl::OUStringToOString(
1030 ::comphelper::anyToString(
1031 ::cppu::getCaughtException() ),
1032 RTL_TEXTENCODING_UTF8 ).getStr() );
1034 catch (lang::IllegalArgumentException & exc) {
1035 (void) exc;
1036 OSL_ENSURE( 0, ::rtl::OUStringToOString(
1037 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
1040 ::std::vector< Sequence<beans::PropertyValue> > manifest;
1041 manifest.reserve( bundle.getLength() );
1042 sal_Int32 baseURLlen = m_url_expanded.getLength();
1043 Reference<deployment::XPackage> const *pbundle = bundle.getConstArray();
1044 const OUString strMediaType = OUSTR("MediaType");
1045 const OUString strFullPath = OUSTR("FullPath");
1046 const OUString strIsFolder = OUSTR("IsFolder");
1047 for ( sal_Int32 pos = bundle.getLength(); pos--; )
1049 Reference<deployment::XPackage> const & xPackage = pbundle[ pos ];
1050 OUString url_( expandUnoRcUrl( xPackage->getURL() ) );
1051 OSL_ASSERT( url_.getLength() >= baseURLlen );
1052 OUString fullPath;
1053 if (url_.getLength() > baseURLlen)
1054 fullPath = url_.copy( baseURLlen + 1 );
1055 ::ucbhelper::Content ucbContent( url_, xCmdEnv );
1056 if (ucbContent.getPropertyValue(strIsFolder).get<bool>())
1057 fullPath += OUSTR("/");
1058 Sequence<beans::PropertyValue> attribs( 2 );
1059 beans::PropertyValue * pattribs = attribs.getArray();
1060 pattribs[ 0 ].Name = strFullPath;
1061 pattribs[ 0 ].Value <<= fullPath;
1062 pattribs[ 1 ].Name = strMediaType;
1063 const Reference<deployment::XPackageTypeInfo> xPackageType(
1064 xPackage->getPackageType() );
1065 OUString mediaType;
1066 OSL_ASSERT( xPackageType.is() );
1067 if (xPackageType.is())
1068 mediaType = xPackageType->getMediaType();
1069 else
1070 mediaType = OUSTR("unknown");
1071 pattribs[ 1 ].Value <<= mediaType;
1072 manifest.push_back( attribs );
1075 // write into pipe:
1076 Reference<XComponentContext> xContext(
1077 getMyBackend()->getComponentContext() );
1078 Reference<packages::manifest::XManifestWriter> xManifestWriter(
1079 xContext->getServiceManager()->createInstanceWithContext(
1080 OUSTR("com.sun.star.packages.manifest.ManifestWriter"),
1081 xContext ), UNO_QUERY_THROW );
1082 Reference<io::XOutputStream> xPipe(
1083 xContext->getServiceManager()->createInstanceWithContext(
1084 OUSTR("com.sun.star.io.Pipe"), xContext ), UNO_QUERY_THROW );
1085 xManifestWriter->writeManifestSequence(
1086 xPipe, comphelper::containerToSequence(manifest) );
1088 // write buffered pipe data to content:
1089 ::ucbhelper::Content manifestContent(
1090 makeURL( metainfFolderContent.getURL(), OUSTR("manifest.xml") ),
1091 xCmdEnv );
1092 manifestContent.writeStream(
1093 Reference<io::XInputStream>( xPipe, UNO_QUERY_THROW ),
1094 true /* replace existing */ );
1096 else
1098 // overwrite manifest.xml:
1099 ::ucbhelper::Content manifestContent;
1100 if ( ! create_ucb_content(
1101 &manifestContent,
1102 makeURL( m_url_expanded, OUSTR("META-INF/manifest.xml") ),
1103 xCmdEnv, false ) )
1105 OSL_ENSURE( 0, "### missing META-INF/manifest.xml file!" );
1106 return;
1109 if (! metainfFolderContent.transferContent(
1110 manifestContent, ::ucbhelper::InsertOperation_COPY,
1111 OUString(), NameClash::OVERWRITE ))
1112 throw RuntimeException( OUSTR("UCB transferContent() failed!"),
1113 static_cast<OWeakObject *>(this) );
1116 // xxx todo: maybe obsolete in the future
1117 try {
1118 destFolderContent.executeCommand( OUSTR("flush"), Any() );
1120 catch (UnsupportedCommandException &) {
1124 //______________________________________________________________________________
1125 sal_Bool BackendImpl::PackageImpl::isBundle() throw (RuntimeException)
1127 return true;
1130 //______________________________________________________________________________
1131 Sequence< Reference<deployment::XPackage> > BackendImpl::PackageImpl::getBundle(
1132 Reference<task::XAbortChannel> const & xAbortChannel,
1133 Reference<XCommandEnvironment> const & xCmdEnv )
1134 throw (deployment::DeploymentException,
1135 CommandFailedException, CommandAbortedException,
1136 lang::IllegalArgumentException, RuntimeException)
1138 Sequence< Reference<deployment::XPackage> > * pBundle = m_pBundle;
1139 if (pBundle == 0)
1141 t_packagevec bundle;
1142 try {
1143 if (m_legacyBundle)
1145 // .zip legacy packages allow script.xlb, dialog.xlb in bundle
1146 // root folder:
1147 OUString mediaType;
1148 // probe for script.xlb:
1149 if (create_ucb_content(
1150 0, makeURL( m_url_expanded, OUSTR("script.xlb") ),
1151 xCmdEnv, false /* no throw */ )) {
1152 mediaType = OUSTR("application/vnd.sun.star.basic-library");
1154 // probe for dialog.xlb:
1155 else if (create_ucb_content(
1156 0, makeURL( m_url_expanded, OUSTR("dialog.xlb") ),
1157 xCmdEnv, false /* no throw */ ))
1158 mediaType = OUSTR("application/vnd.sun.star."
1159 "dialog-library");
1161 if (mediaType.getLength() > 0) {
1162 const Reference<deployment::XPackage> xPackage(
1163 bindBundleItem( getURL(), mediaType, xCmdEnv ) );
1164 if (xPackage.is())
1165 bundle.push_back( xPackage );
1166 // continue scanning:
1168 scanLegacyBundle( bundle, getURL(),
1169 AbortChannel::get(xAbortChannel), xCmdEnv );
1171 else
1173 // .oxt:
1174 scanBundle( bundle, AbortChannel::get(xAbortChannel), xCmdEnv );
1177 catch (RuntimeException &) {
1178 throw;
1180 catch (CommandFailedException &) {
1181 throw;
1183 catch (CommandAbortedException &) {
1184 throw;
1186 catch (deployment::DeploymentException &) {
1187 throw;
1189 catch (Exception &) {
1190 Any exc( ::cppu::getCaughtException() );
1191 throw deployment::DeploymentException(
1192 OUSTR("error scanning bundle: ") + getURL(),
1193 static_cast<OWeakObject *>(this), exc );
1196 // sort: schema before config data, typelibs before components:
1197 Sequence< Reference<deployment::XPackage> > ret( bundle.size() );
1198 Reference<deployment::XPackage> * pret = ret.getArray();
1199 sal_Int32 lower_end = 0;
1200 sal_Int32 upper_end = ret.getLength();
1201 t_packagevec::const_iterator iPos( bundle.begin() );
1202 t_packagevec::const_iterator const iEnd( bundle.end() );
1203 for ( ; iPos != iEnd; ++iPos )
1205 const Reference<deployment::XPackageTypeInfo> xPackageType(
1206 (*iPos)->getPackageType() );
1207 OSL_ASSERT( xPackageType.is() );
1208 if (xPackageType.is()) {
1209 const OUString mediaType( xPackageType->getMediaType() );
1210 String type, subType;
1211 INetContentTypeParameterList params;
1212 if (INetContentTypes::parse(
1213 mediaType, type, subType, &params ) &&
1214 type.EqualsIgnoreCaseAscii("application") &&
1215 (subType.EqualsIgnoreCaseAscii(
1216 "vnd.sun.star.uno-component") ||
1217 subType.EqualsIgnoreCaseAscii(
1218 "vnd.sun.star.configuration-data")))
1220 --upper_end;
1221 pret[ upper_end ] = *iPos;
1222 continue;
1225 pret[ lower_end ] = *iPos;
1226 ++lower_end;
1228 OSL_ASSERT( lower_end == upper_end );
1230 const ::osl::MutexGuard guard( getMutex() );
1231 pBundle = m_pBundle;
1232 if (pBundle == 0) {
1233 m_bundle = ret;
1234 pBundle = &m_bundle;
1235 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
1236 m_pBundle = pBundle;
1239 else {
1240 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
1242 return *pBundle;
1245 inline bool isBundle_( OUString const & mediaType )
1247 // xxx todo: additional parsing?
1248 return mediaType.getLength() > 0 &&
1249 (mediaType.matchIgnoreAsciiCaseAsciiL(
1250 RTL_CONSTASCII_STRINGPARAM(
1251 "application/vnd.sun.star.package-bundle") ) ||
1252 mediaType.matchIgnoreAsciiCaseAsciiL(
1253 RTL_CONSTASCII_STRINGPARAM(
1254 "application/vnd.sun.star.legacy-package-bundle") ));
1257 //______________________________________________________________________________
1258 Reference<deployment::XPackage> BackendImpl::PackageImpl::bindBundleItem(
1259 OUString const & url, OUString const & mediaType,
1260 Reference<XCommandEnvironment> const & xCmdEnv,
1261 bool notifyDetectionError )
1263 // ignore any nested bundles:
1264 if (isBundle_(mediaType))
1265 return Reference<deployment::XPackage>();
1267 Reference<deployment::XPackage>xPackage;
1268 try {
1269 xPackage.set( getMyBackend()->m_xRootRegistry->bindPackage(
1270 url, mediaType, xCmdEnv ) );
1271 OSL_ASSERT( xPackage.is() );
1273 catch (RuntimeException &) {
1274 throw;
1276 catch (CommandFailedException &) {
1277 // ignore already handled error
1279 catch (Exception &) {
1280 const Any exc( ::cppu::getCaughtException() );
1281 if (notifyDetectionError ||
1282 !exc.isExtractableTo(
1283 ::getCppuType( reinterpret_cast<
1284 lang::IllegalArgumentException const *>(0) ) ))
1286 interactContinuation(
1287 Any( lang::WrappedTargetException(
1288 OUSTR("bundle item error!"),
1289 static_cast<OWeakObject *>(this), exc ) ),
1290 task::XInteractionApprove::static_type(), xCmdEnv, 0, 0 );
1294 if (xPackage.is()) {
1295 const Reference<deployment::XPackageTypeInfo> xPackageType(
1296 xPackage->getPackageType() );
1297 OSL_ASSERT( xPackageType.is() );
1298 // ignore any nested bundles:
1299 if (xPackageType.is() && isBundle_( xPackageType->getMediaType() ))
1300 xPackage.clear();
1302 return xPackage;
1305 //______________________________________________________________________________
1306 void BackendImpl::PackageImpl::scanBundle(
1307 t_packagevec & bundle,
1308 ::rtl::Reference<AbortChannel> const & abortChannel,
1309 Reference<XCommandEnvironment> const & xCmdEnv )
1311 OSL_ASSERT( !m_legacyBundle );
1313 ::ucbhelper::Content manifestContent;
1314 if (! create_ucb_content(
1315 &manifestContent,
1316 makeURL( m_url_expanded, OUSTR("META-INF/manifest.xml") ),
1317 xCmdEnv, false /* no throw */ ))
1319 OSL_ENSURE( 0, "### missing META-INF/manifest.xml file!" );
1320 return;
1324 const lang::Locale officeLocale = getOfficeLocale();
1325 OUString descrFile;
1326 lang::Locale descrFileLocale;
1328 const Reference<XComponentContext> xContext(
1329 getMyBackend()->getComponentContext() );
1330 Reference<packages::manifest::XManifestReader> xManifestReader(
1331 xContext->getServiceManager()->createInstanceWithContext(
1332 OUSTR("com.sun.star.packages.manifest.ManifestReader"),
1333 xContext ), UNO_QUERY_THROW );
1334 const Sequence< Sequence<beans::PropertyValue> > manifestSeq(
1335 xManifestReader->readManifestSequence( manifestContent.openStream() ) );
1336 const OUString packageRootURL( getURL() );
1337 for ( sal_Int32 pos = manifestSeq.getLength(); pos--; )
1339 OUString fullPath, mediaType;
1340 Sequence<beans::PropertyValue> const & attribs = manifestSeq[ pos ];
1341 for ( sal_Int32 i = attribs.getLength(); i--; )
1343 if (fullPath.getLength() > 0 && mediaType.getLength() > 0)
1344 break;
1345 if (attribs[i].Name.equalsAsciiL(
1346 RTL_CONSTASCII_STRINGPARAM("FullPath") ))
1347 attribs[i].Value >>= fullPath;
1348 else if (attribs[i].Name.equalsAsciiL(
1349 RTL_CONSTASCII_STRINGPARAM("MediaType") ))
1350 attribs[i].Value >>= mediaType;
1353 if (fullPath.getLength() == 0 || mediaType.getLength() == 0 ||
1354 mediaType.equalsAsciiL( // opt: exclude common text/xml
1355 RTL_CONSTASCII_STRINGPARAM("text/xml") ))
1356 continue;
1358 String type, subType;
1359 INetContentTypeParameterList params;
1360 if (! INetContentTypes::parse( mediaType, type, subType, &params ))
1361 continue;
1363 INetContentTypeParameter const * param = params.find(
1364 ByteString("platform") );
1365 if (param != 0 && !platform_fits( param->m_sValue ))
1366 continue;
1367 const OUString url( makeURL( packageRootURL, fullPath ) );
1369 INetContentTypeParameter const * execParam = params.find(
1370 ByteString("executable") );
1371 if (execParam!=0 && execParam->m_sValue.CompareIgnoreCaseToAscii("true")==COMPARE_EQUAL) {
1372 ::rtl::OUString expandedUrl=expandUnoRcUrl(url);
1373 oslFileError err=osl_setFileAttributes( expandedUrl.pData, osl_File_Attribute_OwnRead | osl_File_Attribute_OwnExe);
1376 if (type.EqualsIgnoreCaseAscii("application") &&
1377 subType.EqualsIgnoreCaseAscii(
1378 "octet-stream"))
1380 continue;
1383 // check for bundle description:
1384 if (type.EqualsIgnoreCaseAscii("application") &&
1385 subType.EqualsIgnoreCaseAscii(
1386 "vnd.sun.star.package-bundle-description"))
1388 // check locale:
1389 param = params.find( ByteString("locale") );
1390 if (param == 0) {
1391 if (descrFile.getLength() == 0)
1392 descrFile = url;
1394 else {
1395 // match best locale:
1396 lang::Locale locale( toLocale(param->m_sValue) );
1397 if (locale.Language == officeLocale.Language)
1399 if (descrFileLocale.Country == officeLocale.Country
1400 && locale.Country != officeLocale.Country)
1401 continue;
1402 if (descrFileLocale.Variant == officeLocale.Variant
1403 && locale.Variant != officeLocale.Variant)
1404 continue;
1405 descrFile = url;
1406 descrFileLocale = locale;
1409 continue;
1412 checkAborted( abortChannel );
1414 //We make sure that we only create one XPackage for a particular URL.
1415 //Sometime programmers insert the same URL several times in the manifest
1416 //which may lead to DisposedExceptions.
1417 if (bundle.end() == std::find_if(bundle.begin(), bundle.end(), XPackage_eq(url)))
1419 const Reference<deployment::XPackage> xPackage(
1420 bindBundleItem( url, mediaType, xCmdEnv ) );
1421 if (xPackage.is())
1422 bundle.push_back( xPackage );
1424 else
1426 fprintf(stderr, "manifest.xml contains a duplicate entry!\n");
1430 if (descrFile.getLength() > 0)
1432 ::ucbhelper::Content descrFileContent;
1433 if (create_ucb_content( &descrFileContent, descrFile,
1434 xCmdEnv, false /* no throw */ ))
1436 // patch description:
1437 ::rtl::ByteSequence bytes( readFile( descrFileContent ) );
1438 ::rtl::OUStringBuffer buf;
1439 if ( bytes.getLength() )
1441 buf.append( OUString( reinterpret_cast<sal_Char const *>(
1442 bytes.getConstArray() ),
1443 bytes.getLength(), RTL_TEXTENCODING_UTF8 ) );
1445 else
1447 buf.append( Package::getDescription() );
1449 m_oldDescription = buf.makeStringAndClear();
1454 //______________________________________________________________________________
1455 void BackendImpl::PackageImpl::scanLegacyBundle(
1456 t_packagevec & bundle,
1457 OUString const & url,
1458 ::rtl::Reference<AbortChannel> const & abortChannel,
1459 Reference<XCommandEnvironment> const & xCmdEnv,
1460 bool skip_registration )
1462 ::ucbhelper::Content ucbContent( url, xCmdEnv );
1464 // check for platform pathes:
1465 const OUString title( ucbContent.getPropertyValue(
1466 StrTitle::get() ).get<OUString>() );
1467 if (title.endsWithIgnoreAsciiCaseAsciiL(
1468 RTL_CONSTASCII_STRINGPARAM(".plt") ) &&
1469 !platform_fits( title.copy( 0, title.getLength() - 4 ) )) {
1470 return;
1472 if (title.endsWithIgnoreAsciiCaseAsciiL(
1473 RTL_CONSTASCII_STRINGPARAM("skip_registration") ))
1474 skip_registration = true;
1476 OUString ar [] = { StrTitle::get(), OUSTR("IsFolder") };
1477 Reference<sdbc::XResultSet> xResultSet(
1478 ucbContent.createCursor(
1479 Sequence<OUString>( ar, ARLEN(ar) ),
1480 ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) );
1481 while (xResultSet->next())
1483 checkAborted( abortChannel );
1485 const Reference<sdbc::XRow> xRow( xResultSet, UNO_QUERY_THROW );
1486 const OUString title_enc( ::rtl::Uri::encode(
1487 xRow->getString( 1 /* Title */ ),
1488 rtl_UriCharClassPchar,
1489 rtl_UriEncodeIgnoreEscapes,
1490 RTL_TEXTENCODING_UTF8 ) );
1491 const OUString path( makeURL( url, title_enc ) );
1493 OUString mediaType;
1494 const Reference<deployment::XPackage> xPackage(
1495 bindBundleItem( path, OUString() /* detect */, xCmdEnv,
1496 false /* ignore detection errors */ ) );
1497 if (xPackage.is()) {
1498 const Reference<deployment::XPackageTypeInfo> xPackageType(
1499 xPackage->getPackageType() );
1500 OSL_ASSERT( xPackageType.is() );
1501 if (xPackageType.is())
1502 mediaType = xPackageType->getMediaType();
1504 if (skip_registration &&
1505 // xxx todo: additional parsing?
1506 mediaType.matchIgnoreAsciiCaseAsciiL(
1507 RTL_CONSTASCII_STRINGPARAM(
1508 "application/vnd.sun.star.uno-component") ))
1509 continue;
1511 bundle.push_back( xPackage );
1514 if (mediaType.getLength() == 0 ||
1515 // script.xlb, dialog.xlb can be met everywhere:
1516 mediaType.matchIgnoreAsciiCaseAsciiL(
1517 RTL_CONSTASCII_STRINGPARAM(
1518 "application/vnd.sun.star.basic-library") ) ||
1519 mediaType.matchIgnoreAsciiCaseAsciiL(
1520 RTL_CONSTASCII_STRINGPARAM(
1521 "application/vnd.sun.star.dialog-library") ))
1523 if (xRow->getBoolean( 2 /* IsFolder */ )) { // recurse into folder:
1524 scanLegacyBundle(
1525 bundle, path, abortChannel, xCmdEnv, skip_registration );
1531 OUString BackendImpl::PackageImpl::getDisplayName() throw (RuntimeException)
1533 OUString sName = getDescriptionInfoset().getLocalizedDisplayName();
1534 if (sName.getLength() == 0)
1535 return m_displayName;
1536 else
1537 return sName;
1540 } // anon namespace
1542 //==============================================================================
1543 Reference<deployment::XPackageRegistry> create(
1544 Reference<deployment::XPackageRegistry> const & xRootRegistry,
1545 OUString const & context, OUString const & cachePath, bool readOnly,
1546 Reference<XComponentContext> const & xComponentContext )
1548 Sequence<Any> args(
1549 cachePath.getLength() == 0 ? 1 : 3 );
1550 args[ 0 ] <<= context;
1551 if (cachePath.getLength() > 0) {
1552 args[ 1 ] <<= cachePath;
1553 args[ 2 ] <<= readOnly;
1555 return new BackendImpl( args, xComponentContext, xRootRegistry );
1558 } // namespace bundle
1559 } // namespace backend
1560 } // namespace dp_registry