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