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