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 <cppuhelper/implbase1.hxx> 32 33 #include "comphelper/servicedecl.hxx" 34 #include "cppuhelper/exc_hlp.hxx" 35 #include "rtl/bootstrap.hxx" 36 #include "com/sun/star/deployment/ExtensionManager.hpp" 37 #include "com/sun/star/deployment/XExtensionManager.hpp" 38 #include "com/sun/star/deployment/thePackageManagerFactory.hpp" 39 #include "com/sun/star/deployment/XPackageManager.hpp" 40 #include "com/sun/star/deployment/XPackageManagerFactory.hpp" 41 #include "com/sun/star/deployment/XPackage.hpp" 42 #include "com/sun/star/deployment/InstallException.hpp" 43 #include "com/sun/star/deployment/VersionException.hpp" 44 #include "com/sun/star/deployment/LicenseException.hpp" 45 #include "com/sun/star/lang/XServiceInfo.hpp" 46 #include "com/sun/star/registry/XRegistryKey.hpp" 47 #include "com/sun/star/beans/Optional.hpp" 48 #include "com/sun/star/task/XInteractionApprove.hpp" 49 #include "com/sun/star/beans/Ambiguous.hpp" 50 #include "com/sun/star/uno/XComponentContext.hpp" 51 #include "com/sun/star/io/XInputStream.hpp" 52 #include "com/sun/star/util/XModifyBroadcaster.hpp" 53 #include "comphelper/sequence.hxx" 54 #include "xmlscript/xml_helper.hxx" 55 #include "osl/diagnose.h" 56 #include "dp_interact.h" 57 #include "dp_resource.h" 58 #include "dp_ucb.h" 59 #include "dp_identifier.hxx" 60 #include "dp_descriptioninfoset.hxx" 61 #include "dp_extensionmanager.hxx" 62 #include "dp_commandenvironments.hxx" 63 #include "dp_properties.hxx" 64 #include "boost/bind.hpp" 65 66 #include <list> 67 #include <hash_map> 68 #include <algorithm> 69 70 namespace deploy = com::sun::star::deployment; 71 namespace lang = com::sun::star::lang; 72 namespace registry = com::sun::star::registry; 73 namespace task = com::sun::star::task; 74 namespace ucb = com::sun::star::ucb; 75 namespace uno = com::sun::star::uno; 76 namespace beans = com::sun::star::beans; 77 namespace util = com::sun::star::util; 78 namespace css = com::sun::star; 79 80 81 //#define OUSTR(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) 82 83 using ::com::sun::star::uno::Reference; 84 using ::rtl::OUString; 85 86 namespace { 87 88 struct CompIdentifiers 89 { 90 bool operator() (::std::vector<Reference<deploy::XPackage> > const & a, 91 ::std::vector<Reference<deploy::XPackage> > const & b) 92 { 93 94 if (getName(a).compareTo(getName(b)) < 0) 95 return true; 96 return false; 97 } 98 99 OUString getName(::std::vector<Reference<deploy::XPackage> > const & a); 100 }; 101 102 OUString CompIdentifiers::getName(::std::vector<Reference<deploy::XPackage> > const & a) 103 { 104 OSL_ASSERT(a.size() == 3); 105 //get the first non-null reference 106 Reference<deploy::XPackage> extension; 107 ::std::vector<Reference<deploy::XPackage> >::const_iterator it = a.begin(); 108 for (; it != a.end(); it++) 109 { 110 if (it->is()) 111 { 112 extension = *it; 113 break; 114 } 115 } 116 OSL_ASSERT(extension.is()); 117 return extension->getDisplayName(); 118 } 119 120 void writeLastModified(OUString & url, Reference<ucb::XCommandEnvironment> const & xCmdEnv) 121 { 122 //Write the lastmodified file 123 try { 124 ::rtl::Bootstrap::expandMacros(url); 125 ::ucbhelper::Content ucbStamp(url, xCmdEnv ); 126 dp_misc::erase_path( url, xCmdEnv ); 127 ::rtl::OString stamp("1" ); 128 Reference<css::io::XInputStream> xData( 129 ::xmlscript::createInputStream( 130 ::rtl::ByteSequence( 131 reinterpret_cast<sal_Int8 const *>(stamp.getStr()), 132 stamp.getLength() ) ) ); 133 ucbStamp.writeStream( xData, true /* replace existing */ ); 134 } 135 catch(...) 136 { 137 uno::Any exc(::cppu::getCaughtException()); 138 throw deploy::DeploymentException( 139 OUSTR("Failed to update") + url, 0, exc); 140 } 141 } 142 143 class ExtensionRemoveGuard 144 { 145 css::uno::Reference<css::deployment::XPackage> m_extension; 146 css::uno::Reference<css::deployment::XPackageManager> m_xPackageManager; 147 148 public: 149 ExtensionRemoveGuard( 150 css::uno::Reference<css::deployment::XPackage> const & extension, 151 css::uno::Reference<css::deployment::XPackageManager> const & xPackageManager): 152 m_extension(extension), m_xPackageManager(xPackageManager) {} 153 ~ExtensionRemoveGuard(); 154 155 void reset(css::uno::Reference<css::deployment::XPackage> const & extension) { 156 m_extension = extension; 157 } 158 }; 159 160 ExtensionRemoveGuard::~ExtensionRemoveGuard() 161 { 162 try { 163 if (m_xPackageManager.is() && m_extension.is()) 164 m_xPackageManager->removePackage( 165 dp_misc::getIdentifier(m_extension), ::rtl::OUString(), 166 css::uno::Reference<css::task::XAbortChannel>(), 167 css::uno::Reference<css::ucb::XCommandEnvironment>()); 168 } catch (...) { 169 OSL_ASSERT(0); 170 } 171 } 172 173 } //end namespace 174 175 namespace dp_manager { 176 177 178 179 //------------------------------------------------------------------------------ 180 181 //ToDo: bundled extension 182 ExtensionManager::ExtensionManager( Reference< uno::XComponentContext > const& xContext) : 183 ::cppu::WeakComponentImplHelper1< css::deployment::XExtensionManager >(getMutex()), 184 m_xContext( xContext ) 185 { 186 m_xPackageManagerFactory = deploy::thePackageManagerFactory::get(m_xContext); 187 OSL_ASSERT(m_xPackageManagerFactory.is()); 188 189 m_repositoryNames.push_back(OUSTR("user")); 190 m_repositoryNames.push_back(OUSTR("shared")); 191 m_repositoryNames.push_back(OUSTR("bundled")); 192 } 193 194 //------------------------------------------------------------------------------ 195 196 ExtensionManager::~ExtensionManager() 197 { 198 } 199 200 Reference<deploy::XPackageManager> ExtensionManager::getUserRepository() 201 { 202 return m_xPackageManagerFactory->getPackageManager(OUSTR("user")); 203 } 204 Reference<deploy::XPackageManager> ExtensionManager::getSharedRepository() 205 { 206 return m_xPackageManagerFactory->getPackageManager(OUSTR("shared")); 207 } 208 Reference<deploy::XPackageManager> ExtensionManager::getBundledRepository() 209 { 210 return m_xPackageManagerFactory->getPackageManager(OUSTR("bundled")); 211 } 212 Reference<deploy::XPackageManager> ExtensionManager::getTmpRepository() 213 { 214 return m_xPackageManagerFactory->getPackageManager(OUSTR("tmp")); 215 } 216 217 Reference<task::XAbortChannel> ExtensionManager::createAbortChannel() 218 throw (uno::RuntimeException) 219 { 220 return new dp_misc::AbortChannel; 221 } 222 223 css::uno::Reference<css::deployment::XPackageManager> 224 ExtensionManager::getPackageManager(::rtl::OUString const & repository) 225 throw (css::lang::IllegalArgumentException) 226 { 227 Reference<deploy::XPackageManager> xPackageManager; 228 if (repository.equals(OUSTR("user"))) 229 xPackageManager = getUserRepository(); 230 else if (repository.equals(OUSTR("shared"))) 231 xPackageManager = getSharedRepository(); 232 else if (repository.equals(OUSTR("bundled"))) 233 xPackageManager = getBundledRepository(); 234 else 235 throw lang::IllegalArgumentException( 236 OUSTR("No valid repository name provided."), 237 static_cast<cppu::OWeakObject*>(this), 0); 238 return xPackageManager; 239 } 240 241 242 /* 243 Enters the XPackage objects into a map. They must be all from the 244 same repository. The value type of the map is a vector, where each vector 245 represents an extension with a particular identifier. The first member 246 is represents the user extension, the second the shared extension and the 247 third the bundled extension. 248 */ 249 void ExtensionManager::addExtensionsToMap( 250 id2extensions & mapExt, 251 uno::Sequence<Reference<deploy::XPackage> > const & seqExt, 252 OUString const & repository) 253 { 254 //Determine the index in the vector where these extensions are to be 255 //added. 256 ::std::list<OUString>::const_iterator citNames = 257 m_repositoryNames.begin(); 258 int index = 0; 259 for (;citNames != m_repositoryNames.end(); citNames++, index++) 260 { 261 if (citNames->equals(repository)) 262 break; 263 } 264 265 for (int i = 0; i < seqExt.getLength(); i++) 266 { 267 Reference<deploy::XPackage> const & xExtension = seqExt[i]; 268 OUString id = dp_misc::getIdentifier(xExtension); 269 id2extensions::iterator ivec = mapExt.find(id); 270 if (ivec == mapExt.end()) 271 { 272 ::std::vector<Reference<deploy::XPackage> > vec(3); 273 vec[index] = xExtension; 274 mapExt[id] = vec; 275 } 276 else 277 { 278 ivec->second[index] = xExtension; 279 } 280 } 281 } 282 283 /* 284 returns a list containing extensions with the same identifier from 285 all repositories (user, shared, bundled) If one repository does not 286 have this extension, then the list contains an empty Referenc. The list 287 is ordered according to the priority of the repostories: 288 1. user 289 2. shared 290 3. bundled 291 292 The number of elements is always three, unless the number of repository 293 changes. 294 */ 295 ::std::list<Reference<deploy::XPackage> > 296 ExtensionManager::getExtensionsWithSameId( 297 OUString const & identifier, OUString const & fileName, 298 Reference< ucb::XCommandEnvironment> const & /*xCmdEnv*/) 299 300 { 301 ::std::list<Reference<deploy::XPackage> > extensionList; 302 try 303 { //will throw an exception if the extension does not exist 304 extensionList.push_back(getUserRepository()->getDeployedPackage( 305 identifier, fileName, Reference<ucb::XCommandEnvironment>())); 306 } catch(lang::IllegalArgumentException &) 307 { 308 extensionList.push_back(Reference<deploy::XPackage>()); 309 } 310 try 311 { 312 extensionList.push_back(getSharedRepository()->getDeployedPackage( 313 identifier, fileName, Reference<ucb::XCommandEnvironment>())); 314 } catch (lang::IllegalArgumentException &) 315 { 316 extensionList.push_back(Reference<deploy::XPackage>()); 317 } 318 try 319 { 320 extensionList.push_back(getBundledRepository()->getDeployedPackage( 321 identifier, fileName, Reference<ucb::XCommandEnvironment>())); 322 } catch (lang::IllegalArgumentException &) 323 { 324 extensionList.push_back(Reference<deploy::XPackage>()); 325 } 326 OSL_ASSERT(extensionList.size() == 3); 327 return extensionList; 328 } 329 330 uno::Sequence<Reference<deploy::XPackage> > 331 ExtensionManager::getExtensionsWithSameIdentifier( 332 OUString const & identifier, 333 OUString const & fileName, 334 Reference< ucb::XCommandEnvironment> const & xCmdEnv ) 335 throw ( 336 deploy::DeploymentException, 337 ucb::CommandFailedException, 338 lang::IllegalArgumentException, 339 uno::RuntimeException) 340 { 341 try 342 { 343 ::std::list<Reference<deploy::XPackage> > listExtensions = 344 getExtensionsWithSameId( 345 identifier, fileName, xCmdEnv); 346 sal_Bool bHasExtension = false; 347 348 //throw an IllegalArgumentException if there is no extension at all. 349 typedef ::std::list<Reference<deploy::XPackage> >::const_iterator CIT; 350 for (CIT i = listExtensions.begin(); i != listExtensions.end(); i++) 351 bHasExtension |= i->is(); 352 if (!bHasExtension) 353 throw lang::IllegalArgumentException( 354 OUSTR("Could not find extension: ") + identifier + OUSTR(", ") + fileName, 355 static_cast<cppu::OWeakObject*>(this), -1); 356 357 return comphelper::containerToSequence< 358 Reference<deploy::XPackage>, 359 ::std::list<Reference<deploy::XPackage> > 360 > (listExtensions); 361 } 362 catch (deploy::DeploymentException & ) 363 { 364 throw; 365 } 366 catch ( ucb::CommandFailedException & ) 367 { 368 throw; 369 } 370 catch (lang::IllegalArgumentException &) 371 { 372 throw; 373 } 374 catch (...) 375 { 376 uno::Any exc = ::cppu::getCaughtException(); 377 throw deploy::DeploymentException( 378 OUSTR("Extension Manager: exception during getExtensionsWithSameIdentifier"), 379 static_cast<OWeakObject*>(this), exc); 380 } 381 } 382 383 384 385 bool ExtensionManager::isUserDisabled( 386 OUString const & identifier, OUString const & fileName) 387 { 388 ::std::list<Reference<deploy::XPackage> > listExtensions; 389 390 try { 391 listExtensions = getExtensionsWithSameId(identifier, fileName); 392 } catch (lang::IllegalArgumentException & ) { 393 } 394 OSL_ASSERT(listExtensions.size() == 3); 395 396 return isUserDisabled( ::comphelper::containerToSequence< 397 Reference<deploy::XPackage>, 398 ::std::list<Reference<deploy::XPackage> > 399 > (listExtensions)); 400 } 401 402 bool ExtensionManager::isUserDisabled( 403 uno::Sequence<Reference<deploy::XPackage> > const & seqExtSameId) 404 { 405 OSL_ASSERT(seqExtSameId.getLength() == 3); 406 Reference<deploy::XPackage> const & userExtension = seqExtSameId[0]; 407 if (userExtension.is()) 408 { 409 beans::Optional<beans::Ambiguous<sal_Bool> > reg = 410 userExtension->isRegistered(Reference<task::XAbortChannel>(), 411 Reference<ucb::XCommandEnvironment>()); 412 //If the value is ambiguous is than we assume that the extension 413 //is enabled, but something went wrong during enabling. We do not 414 //automatically disable user extensions. 415 if (reg.IsPresent && 416 ! reg.Value.IsAmbiguous && ! reg.Value.Value) 417 return true; 418 } 419 return false; 420 } 421 422 /* 423 This method determines the active extension (XPackage.registerPackage) with a 424 particular identifier. 425 426 The parameter bUserDisabled determines if the user extension is disabled. 427 428 When the user repository contains an extension with the given identifier and 429 it is not disabled by the user, then it is always registered. Otherwise an 430 extension is only registered when there is no registered extension in one of 431 the repositories with a higher priority. That is, if the extension is from 432 the shared repository and an active extension with the same identifer is in 433 the user repository, then the extension is not registered. Similarly a 434 bundled extension is not registered if there is an active extension with the 435 same identifier in the shared or user repository. 436 */ 437 void ExtensionManager::activateExtension( 438 OUString const & identifier, OUString const & fileName, 439 bool bUserDisabled, 440 bool bStartup, 441 Reference<task::XAbortChannel> const & xAbortChannel, 442 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 443 { 444 ::std::list<Reference<deploy::XPackage> > listExtensions; 445 try { 446 listExtensions = getExtensionsWithSameId(identifier, fileName); 447 } catch (lang::IllegalArgumentException &) { 448 } 449 OSL_ASSERT(listExtensions.size() == 3); 450 451 activateExtension( 452 ::comphelper::containerToSequence< 453 Reference<deploy::XPackage>, 454 ::std::list<Reference<deploy::XPackage> > 455 > (listExtensions), 456 bUserDisabled, bStartup, xAbortChannel, xCmdEnv); 457 458 fireModified(); 459 } 460 461 void ExtensionManager::activateExtension( 462 uno::Sequence<Reference<deploy::XPackage> > const & seqExt, 463 bool bUserDisabled, 464 bool bStartup, 465 Reference<task::XAbortChannel> const & xAbortChannel, 466 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 467 { 468 bool bActive = false; 469 sal_Int32 len = seqExt.getLength(); 470 for (sal_Int32 i = 0; i < len; i++) 471 { 472 Reference<deploy::XPackage> const & aExt = seqExt[i]; 473 if (aExt.is()) 474 { 475 //get the registration value of the current iteration 476 beans::Optional<beans::Ambiguous<sal_Bool> > optReg = 477 aExt->isRegistered(xAbortChannel, xCmdEnv); 478 //If nothing can be registered then break 479 if (!optReg.IsPresent) 480 break; 481 482 //Check if this is a disabled user extension, 483 if (i == 0 && bUserDisabled) 484 { 485 aExt->revokePackage(xAbortChannel, xCmdEnv); 486 continue; 487 } 488 489 //If we have already determined an active extension then we must 490 //make sure to unregister all extensions with the same id in 491 //repositories with a lower priority 492 if (bActive) 493 { 494 aExt->revokePackage(xAbortChannel, xCmdEnv); 495 } 496 else 497 { 498 //This is the first extension in the ordered list, which becomes 499 //the active extension 500 bActive = true; 501 //Register if not already done. 502 //reregister if the value is ambiguous, which indicates that 503 //something went wrong during last registration. 504 aExt->registerPackage(bStartup, xAbortChannel, xCmdEnv); 505 } 506 } 507 } 508 } 509 510 Reference<deploy::XPackage> ExtensionManager::backupExtension( 511 OUString const & identifier, OUString const & fileName, 512 Reference<deploy::XPackageManager> const & xPackageManager, 513 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 514 { 515 Reference<deploy::XPackage> xBackup; 516 Reference<ucb::XCommandEnvironment> tmpCmdEnv( 517 new TmpRepositoryCommandEnv(xCmdEnv->getInteractionHandler())); 518 Reference<deploy::XPackage> xOldExtension; 519 xOldExtension = xPackageManager->getDeployedPackage( 520 identifier, fileName, tmpCmdEnv); 521 522 if (xOldExtension.is()) 523 { 524 xBackup = getTmpRepository()->addPackage( 525 xOldExtension->getURL(), uno::Sequence<beans::NamedValue>(), 526 OUString(), Reference<task::XAbortChannel>(), tmpCmdEnv); 527 528 OSL_ENSURE(xBackup.is(), "Failed to backup extension"); 529 } 530 return xBackup; 531 } 532 533 //The supported package types are actually determined by the registry. However 534 //creating a registry 535 //(desktop/source/deployment/registry/dp_registry.cxx:PackageRegistryImpl) will 536 //create all the backends, so that the registry can obtain from them the package 537 //types. Creating the registry will also set up the registry folder containing 538 //all the subfolders for the respective backends. 539 //Because all repositories support the same backends, we can just delegate this 540 //call to one of the repositories. 541 uno::Sequence< Reference<deploy::XPackageTypeInfo> > 542 ExtensionManager::getSupportedPackageTypes() 543 throw (uno::RuntimeException) 544 { 545 return getUserRepository()->getSupportedPackageTypes(); 546 } 547 //Do some necessary checks and user interaction. This function does not 548 //aquire the extension manager mutex and that mutex must not be aquired 549 //when this function is called. doChecksForAddExtension does synchronous 550 //user interactions which may require aquiring the solar mutex. 551 //Returns true if the extension can be installed. 552 bool ExtensionManager::doChecksForAddExtension( 553 Reference<deploy::XPackageManager> const & xPackageMgr, 554 uno::Sequence<beans::NamedValue> const & properties, 555 css::uno::Reference<css::deployment::XPackage> const & xTmpExtension, 556 Reference<task::XAbortChannel> const & xAbortChannel, 557 Reference<ucb::XCommandEnvironment> const & xCmdEnv, 558 Reference<deploy::XPackage> & out_existingExtension ) 559 throw (deploy::DeploymentException, 560 ucb::CommandFailedException, 561 ucb::CommandAbortedException, 562 lang::IllegalArgumentException, 563 uno::RuntimeException) 564 { 565 try 566 { 567 Reference<deploy::XPackage> xOldExtension; 568 const OUString sIdentifier = dp_misc::getIdentifier(xTmpExtension); 569 const OUString sFileName = xTmpExtension->getName(); 570 const OUString sDisplayName = xTmpExtension->getDisplayName(); 571 const OUString sVersion = xTmpExtension->getVersion(); 572 573 try 574 { 575 xOldExtension = xPackageMgr->getDeployedPackage( 576 sIdentifier, sFileName, xCmdEnv); 577 out_existingExtension = xOldExtension; 578 } 579 catch (lang::IllegalArgumentException &) 580 { 581 } 582 bool bCanInstall = false; 583 584 //This part is not guarded against other threads removing, adding, disabling ... 585 //etc. the same extension. 586 //checkInstall is safe because it notifies the user if the extension is not yet 587 //installed in the same repository. Because addExtension has its own guard 588 //(m_addMutex), another thread cannot add the extension in the meantime. 589 //checkUpdate is called if the same extension exists in the same 590 //repository. The user is asked if they want to replace it. Another 591 //thread 592 //could already remove the extension. So asking the user was not 593 //necessary. No harm is done. The other thread may also ask the user 594 //if he wants to remove the extension. This depends on the 595 //XCommandEnvironment which it passes to removeExtension. 596 if (xOldExtension.is()) 597 { 598 //throws a CommandFailedException if the user cancels 599 //the action. 600 checkUpdate(sVersion, sDisplayName,xOldExtension, xCmdEnv); 601 } 602 else 603 { 604 //throws a CommandFailedException if the user cancels 605 //the action. 606 checkInstall(sDisplayName, xCmdEnv); 607 } 608 //Prevent showing the license if requested. 609 Reference<ucb::XCommandEnvironment> _xCmdEnv(xCmdEnv); 610 ExtensionProperties props(OUString(), properties, Reference<ucb::XCommandEnvironment>()); 611 612 dp_misc::DescriptionInfoset info(dp_misc::getDescriptionInfoset(xTmpExtension->getURL())); 613 const ::boost::optional<dp_misc::SimpleLicenseAttributes> licenseAttributes = 614 info.getSimpleLicenseAttributes(); 615 616 if (licenseAttributes && licenseAttributes->suppressIfRequired 617 && props.isSuppressedLicense()) 618 _xCmdEnv = Reference<ucb::XCommandEnvironment>( 619 new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler())); 620 621 bCanInstall = xTmpExtension->checkPrerequisites( 622 xAbortChannel, _xCmdEnv, xOldExtension.is() || props.isExtensionUpdate()) == 0 ? true : false; 623 624 return bCanInstall; 625 } 626 catch (deploy::DeploymentException& ) { 627 throw; 628 } catch (ucb::CommandFailedException & ) { 629 throw; 630 } catch (ucb::CommandAbortedException & ) { 631 throw; 632 } catch (lang::IllegalArgumentException &) { 633 throw; 634 } catch (uno::RuntimeException &) { 635 throw; 636 } catch (uno::Exception &) { 637 uno::Any excOccurred = ::cppu::getCaughtException(); 638 deploy::DeploymentException exc( 639 OUSTR("Extension Manager: exception in doChecksForAddExtension"), 640 static_cast<OWeakObject*>(this), excOccurred); 641 throw exc; 642 } catch (...) { 643 throw uno::RuntimeException( 644 OUSTR("Extension Manager: unexpected exception in doChecksForAddExtension"), 645 static_cast<OWeakObject*>(this)); 646 } 647 } 648 649 // Only add to shared and user repository 650 Reference<deploy::XPackage> ExtensionManager::addExtension( 651 OUString const & url, uno::Sequence<beans::NamedValue> const & properties, 652 OUString const & repository, 653 Reference<task::XAbortChannel> const & xAbortChannel, 654 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 655 throw (deploy::DeploymentException, 656 ucb::CommandFailedException, 657 ucb::CommandAbortedException, 658 lang::IllegalArgumentException, 659 uno::RuntimeException) 660 { 661 Reference<deploy::XPackage> xNewExtension; 662 //Determine the repository to use 663 Reference<deploy::XPackageManager> xPackageManager; 664 if (repository.equals(OUSTR("user"))) 665 xPackageManager = getUserRepository(); 666 else if (repository.equals(OUSTR("shared"))) 667 xPackageManager = getSharedRepository(); 668 else 669 throw lang::IllegalArgumentException( 670 OUSTR("No valid repository name provided."), 671 static_cast<cppu::OWeakObject*>(this), 0); 672 //We must make sure that the xTmpExtension is not create twice, because this 673 //would remove the first one. 674 ::osl::MutexGuard addGuard(m_addMutex); 675 676 Reference<deploy::XPackage> xTmpExtension = 677 getTempExtension(url, xAbortChannel, xCmdEnv); 678 //Make sure the extension is removed from the tmp repository in case 679 //of an exception 680 ExtensionRemoveGuard tmpExtensionRemoveGuard(xTmpExtension, getTmpRepository()); 681 const OUString sIdentifier = dp_misc::getIdentifier(xTmpExtension); 682 const OUString sFileName = xTmpExtension->getName(); 683 Reference<deploy::XPackage> xOldExtension; 684 Reference<deploy::XPackage> xExtensionBackup; 685 686 uno::Any excOccurred2; 687 bool bUserDisabled = false; 688 bool bCanInstall = doChecksForAddExtension( 689 xPackageManager, 690 properties, 691 xTmpExtension, 692 xAbortChannel, 693 xCmdEnv, 694 xOldExtension ); 695 696 { 697 // In this garded section (getMutex) we must not use the argument xCmdEnv 698 // because it may bring up dialogs (XInteractionHandler::handle) this 699 //may potententially deadlock. See issue 700 //http://qa.openoffice.org/issues/show_bug.cgi?id=114933 701 //By not providing xCmdEnv the underlying APIs will throw an exception if 702 //the XInteractionRequest cannot be handled 703 ::osl::MutexGuard guard(getMutex()); 704 705 if (bCanInstall) 706 { 707 try 708 { 709 bUserDisabled = isUserDisabled(sIdentifier, sFileName); 710 if (xOldExtension.is()) 711 { 712 try 713 { 714 xOldExtension->revokePackage( 715 xAbortChannel, Reference<ucb::XCommandEnvironment>()); 716 //save the old user extension in case the user aborts 717 //store the extension in the tmp repository, this will overwrite 718 //xTmpPackage (same identifier). Do not let the user abort or 719 //interact 720 //importing the old extension in the tmp repository will remove 721 //the xTmpExtension 722 //no command environment supplied, only this class shall interact 723 //with the user! 724 xExtensionBackup = getTmpRepository()->importExtension( 725 xOldExtension, Reference<task::XAbortChannel>(), 726 Reference<ucb::XCommandEnvironment>()); 727 tmpExtensionRemoveGuard.reset(xExtensionBackup); 728 //xTmpExtension will later be used to check the dependencies 729 //again. However, only xExtensionBackup will be later removed 730 //from the tmp repository 731 xTmpExtension = xExtensionBackup; 732 OSL_ASSERT(xTmpExtension.is()); 733 } 734 catch (lang::DisposedException &) 735 { 736 //Another thread might have removed the extension meanwhile 737 } 738 } 739 //check again dependencies but prevent user interaction, 740 //We can disregard the license, because the user must have already 741 //accepted it, whe we called checkPrerequisites the first time 742 SilentCheckPrerequisitesCommandEnv * pSilentCommandEnv = 743 new SilentCheckPrerequisitesCommandEnv(); 744 Reference<ucb::XCommandEnvironment> silentCommandEnv(pSilentCommandEnv); 745 746 sal_Int32 failedPrereq = xTmpExtension->checkPrerequisites( 747 xAbortChannel, silentCommandEnv, true); 748 if (failedPrereq == 0) 749 { 750 xNewExtension = xPackageManager->addPackage( 751 url, properties, OUString(), xAbortChannel, 752 Reference<ucb::XCommandEnvironment>()); 753 //If we add a user extension and there is already one which was 754 //disabled by a user, then the newly installed one is enabled. If we 755 //add to another repository then the user extension remains 756 //disabled. 757 bool bUserDisabled2 = bUserDisabled; 758 if (repository.equals(OUSTR("user"))) 759 bUserDisabled2 = false; 760 761 ::rtl::OUString const name(xNewExtension->getName()); 762 activateExtension( 763 dp_misc::getIdentifier(xNewExtension), 764 name, bUserDisabled2, false, xAbortChannel, 765 Reference<ucb::XCommandEnvironment>()); 766 } 767 else 768 { 769 if (pSilentCommandEnv->m_Exception.hasValue()) 770 ::cppu::throwException(pSilentCommandEnv->m_Exception); 771 else if ( pSilentCommandEnv->m_UnknownException.hasValue()) 772 ::cppu::throwException(pSilentCommandEnv->m_UnknownException); 773 else 774 throw deploy::DeploymentException ( 775 OUSTR("Extension Manager: exception during addExtension, ckeckPrerequisites failed"), 776 static_cast<OWeakObject*>(this), uno::Any()); 777 } 778 } 779 catch (deploy::DeploymentException& ) { 780 excOccurred2 = ::cppu::getCaughtException(); 781 } catch (ucb::CommandFailedException & ) { 782 excOccurred2 = ::cppu::getCaughtException(); 783 } catch (ucb::CommandAbortedException & ) { 784 excOccurred2 = ::cppu::getCaughtException(); 785 } catch (lang::IllegalArgumentException &) { 786 excOccurred2 = ::cppu::getCaughtException(); 787 } catch (uno::RuntimeException &) { 788 excOccurred2 = ::cppu::getCaughtException(); 789 } catch (...) { 790 excOccurred2 = ::cppu::getCaughtException(); 791 deploy::DeploymentException exc( 792 OUSTR("Extension Manager: exception during addExtension, url: ") 793 + url, static_cast<OWeakObject*>(this), excOccurred2); 794 excOccurred2 <<= exc; 795 } 796 } 797 798 if (excOccurred2.hasValue()) 799 { 800 //It does not matter what exception is thrown. We try to 801 //recover the original status. 802 //If the user aborted installation then a ucb::CommandAbortedException 803 //is thrown. 804 //Use a private AbortChannel so the user cannot interrupt. 805 try 806 { 807 if (xExtensionBackup.is()) 808 { 809 Reference<deploy::XPackage> xRestored = 810 xPackageManager->importExtension( 811 xExtensionBackup, Reference<task::XAbortChannel>(), 812 Reference<ucb::XCommandEnvironment>()); 813 } 814 activateExtension( 815 sIdentifier, sFileName, bUserDisabled, false, 816 Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>()); 817 } 818 catch (...) 819 { 820 } 821 ::cppu::throwException(excOccurred2); 822 } 823 } // leaving the garded section (getMutex()) 824 825 try 826 { 827 fireModified(); 828 829 }catch (deploy::DeploymentException& ) { 830 throw; 831 } catch (ucb::CommandFailedException & ) { 832 throw; 833 } catch (ucb::CommandAbortedException & ) { 834 throw; 835 } catch (lang::IllegalArgumentException &) { 836 throw; 837 } catch (uno::RuntimeException &) { 838 throw; 839 } catch (uno::Exception &) { 840 uno::Any excOccurred = ::cppu::getCaughtException(); 841 deploy::DeploymentException exc( 842 OUSTR("Extension Manager: exception in doChecksForAddExtension"), 843 static_cast<OWeakObject*>(this), excOccurred); 844 throw exc; 845 } catch (...) { 846 throw uno::RuntimeException( 847 OUSTR("Extension Manager: unexpected exception in doChecksForAddExtension"), 848 static_cast<OWeakObject*>(this)); 849 } 850 851 return xNewExtension; 852 } 853 854 void ExtensionManager::removeExtension( 855 OUString const & identifier, OUString const & fileName, 856 OUString const & repository, 857 Reference<task::XAbortChannel> const & xAbortChannel, 858 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 859 throw (deploy::DeploymentException, 860 ucb::CommandFailedException, 861 ucb::CommandAbortedException, 862 lang::IllegalArgumentException, 863 uno::RuntimeException) 864 { 865 uno::Any excOccurred1; 866 Reference<deploy::XPackage> xExtensionBackup; 867 Reference<deploy::XPackageManager> xPackageManager; 868 bool bUserDisabled = false; 869 ::osl::MutexGuard guard(getMutex()); 870 try 871 { 872 //Determine the repository to use 873 if (repository.equals(OUSTR("user"))) 874 xPackageManager = getUserRepository(); 875 else if (repository.equals(OUSTR("shared"))) 876 xPackageManager = getSharedRepository(); 877 else 878 throw lang::IllegalArgumentException( 879 OUSTR("No valid repository name provided."), 880 static_cast<cppu::OWeakObject*>(this), 0); 881 882 bUserDisabled = isUserDisabled(identifier, fileName); 883 //Backup the extension, in case the user cancels the action 884 xExtensionBackup = backupExtension( 885 identifier, fileName, xPackageManager, xCmdEnv); 886 887 //revoke the extension if it is active 888 Reference<deploy::XPackage> xOldExtension = 889 xPackageManager->getDeployedPackage( 890 identifier, fileName, xCmdEnv); 891 xOldExtension->revokePackage(xAbortChannel, xCmdEnv); 892 893 xPackageManager->removePackage( 894 identifier, fileName, xAbortChannel, xCmdEnv); 895 activateExtension(identifier, fileName, bUserDisabled, false, 896 xAbortChannel, xCmdEnv); 897 fireModified(); 898 } 899 catch (deploy::DeploymentException& ) { 900 excOccurred1 = ::cppu::getCaughtException(); 901 } catch (ucb::CommandFailedException & ) { 902 excOccurred1 = ::cppu::getCaughtException(); 903 } catch (ucb::CommandAbortedException & ) { 904 excOccurred1 = ::cppu::getCaughtException(); 905 } catch (lang::IllegalArgumentException &) { 906 excOccurred1 = ::cppu::getCaughtException(); 907 } catch (uno::RuntimeException &) { 908 excOccurred1 = ::cppu::getCaughtException(); 909 } catch (...) { 910 excOccurred1 = ::cppu::getCaughtException(); 911 deploy::DeploymentException exc( 912 OUSTR("Extension Manager: exception during removeEtension"), 913 static_cast<OWeakObject*>(this), excOccurred1); 914 excOccurred1 <<= exc; 915 } 916 917 if (excOccurred1.hasValue()) 918 { 919 //User aborted installation, restore the previous situation. 920 //Use a private AbortChannel so the user cannot interrupt. 921 try 922 { 923 Reference<ucb::XCommandEnvironment> tmpCmdEnv( 924 new TmpRepositoryCommandEnv(xCmdEnv->getInteractionHandler())); 925 if (xExtensionBackup.is()) 926 { 927 Reference<deploy::XPackage> xRestored = 928 xPackageManager->importExtension( 929 xExtensionBackup, Reference<task::XAbortChannel>(), 930 tmpCmdEnv); 931 activateExtension( 932 identifier, fileName, bUserDisabled, false, 933 Reference<task::XAbortChannel>(), 934 tmpCmdEnv); 935 936 getTmpRepository()->removePackage( 937 dp_misc::getIdentifier(xExtensionBackup), 938 xExtensionBackup->getName(), xAbortChannel, xCmdEnv); 939 fireModified(); 940 } 941 } 942 catch (...) 943 { 944 } 945 ::cppu::throwException(excOccurred1); 946 } 947 948 if (xExtensionBackup.is()) 949 getTmpRepository()->removePackage( 950 dp_misc::getIdentifier(xExtensionBackup), 951 xExtensionBackup->getName(), xAbortChannel, xCmdEnv); 952 } 953 954 // Only enable extensions from shared and user repository 955 void ExtensionManager::enableExtension( 956 Reference<deploy::XPackage> const & extension, 957 Reference<task::XAbortChannel> const & xAbortChannel, 958 Reference<ucb::XCommandEnvironment> const & xCmdEnv) 959 throw (deploy::DeploymentException, 960 ucb::CommandFailedException, 961 ucb::CommandAbortedException, 962 lang::IllegalArgumentException, 963 uno::RuntimeException) 964 { 965 ::osl::MutexGuard guard(getMutex()); 966 bool bUserDisabled = false; 967 uno::Any excOccurred; 968 try 969 { 970 if (!extension.is()) 971 return; 972 OUString repository = extension->getRepositoryName(); 973 if (!repository.equals(OUSTR("user"))) 974 throw lang::IllegalArgumentException( 975 OUSTR("No valid repository name provided."), 976 static_cast<cppu::OWeakObject*>(this), 0); 977 978 bUserDisabled = isUserDisabled(dp_misc::getIdentifier(extension), 979 extension->getName()); 980 981 activateExtension(dp_misc::getIdentifier(extension), 982 extension->getName(), false, false, 983 xAbortChannel, xCmdEnv); 984 } 985 catch (deploy::DeploymentException& ) { 986 excOccurred = ::cppu::getCaughtException(); 987 } catch (ucb::CommandFailedException & ) { 988 excOccurred = ::cppu::getCaughtException(); 989 } catch (ucb::CommandAbortedException & ) { 990 excOccurred = ::cppu::getCaughtException(); 991 } catch (lang::IllegalArgumentException &) { 992 excOccurred = ::cppu::getCaughtException(); 993 } catch (uno::RuntimeException &) { 994 excOccurred = ::cppu::getCaughtException(); 995 } catch (...) { 996 excOccurred = ::cppu::getCaughtException(); 997 deploy::DeploymentException exc( 998 OUSTR("Extension Manager: exception during enableExtension"), 999 static_cast<OWeakObject*>(this), excOccurred); 1000 excOccurred <<= exc; 1001 } 1002 1003 if (excOccurred.hasValue()) 1004 { 1005 try 1006 { 1007 activateExtension(dp_misc::getIdentifier(extension), 1008 extension->getName(), bUserDisabled, false, 1009 xAbortChannel, xCmdEnv); 1010 } 1011 catch (...) 1012 { 1013 } 1014 ::cppu::throwException(excOccurred); 1015 } 1016 } 1017 1018 /** 1019 */ 1020 sal_Int32 ExtensionManager::checkPrerequisitesAndEnable( 1021 Reference<deploy::XPackage> const & extension, 1022 Reference<task::XAbortChannel> const & xAbortChannel, 1023 Reference<ucb::XCommandEnvironment> const & xCmdEnv) 1024 throw (deploy::DeploymentException, 1025 ucb::CommandFailedException, 1026 ucb::CommandAbortedException, 1027 lang::IllegalArgumentException, 1028 uno::RuntimeException) 1029 { 1030 try 1031 { 1032 if (!extension.is()) 1033 return 0; 1034 ::osl::MutexGuard guard(getMutex()); 1035 sal_Int32 ret = 0; 1036 Reference<deploy::XPackageManager> mgr = 1037 getPackageManager(extension->getRepositoryName()); 1038 ret = mgr->checkPrerequisites(extension, xAbortChannel, xCmdEnv); 1039 if (ret) 1040 { 1041 //There are some unfulfilled prerequisites, try to revoke 1042 extension->revokePackage(xAbortChannel, xCmdEnv); 1043 } 1044 const OUString id(dp_misc::getIdentifier(extension)); 1045 activateExtension(id, extension->getName(), 1046 isUserDisabled(id, extension->getName()), false, 1047 xAbortChannel, xCmdEnv); 1048 return ret; 1049 } 1050 catch (deploy::DeploymentException& ) { 1051 throw; 1052 } catch (ucb::CommandFailedException & ) { 1053 throw; 1054 } catch (ucb::CommandAbortedException & ) { 1055 throw; 1056 } catch (lang::IllegalArgumentException &) { 1057 throw; 1058 } catch (uno::RuntimeException &) { 1059 throw; 1060 } catch (...) { 1061 uno::Any excOccurred = ::cppu::getCaughtException(); 1062 deploy::DeploymentException exc( 1063 OUSTR("Extension Manager: exception during disableExtension"), 1064 static_cast<OWeakObject*>(this), excOccurred); 1065 throw exc; 1066 } 1067 } 1068 1069 1070 void ExtensionManager::disableExtension( 1071 Reference<deploy::XPackage> const & extension, 1072 Reference<task::XAbortChannel> const & xAbortChannel, 1073 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 1074 throw (deploy::DeploymentException, 1075 ucb::CommandFailedException, 1076 ucb::CommandAbortedException, 1077 lang::IllegalArgumentException, 1078 uno::RuntimeException) 1079 { 1080 ::osl::MutexGuard guard(getMutex()); 1081 uno::Any excOccurred; 1082 bool bUserDisabled = false; 1083 try 1084 { 1085 if (!extension.is()) 1086 return; 1087 const OUString repository( extension->getRepositoryName()); 1088 if (!repository.equals(OUSTR("user"))) 1089 throw lang::IllegalArgumentException( 1090 OUSTR("No valid repository name provided."), 1091 static_cast<cppu::OWeakObject*>(this), 0); 1092 1093 const OUString id(dp_misc::getIdentifier(extension)); 1094 bUserDisabled = isUserDisabled(id, extension->getName()); 1095 1096 activateExtension(id, extension->getName(), true, false, 1097 xAbortChannel, xCmdEnv); 1098 } 1099 catch (deploy::DeploymentException& ) { 1100 excOccurred = ::cppu::getCaughtException(); 1101 } catch (ucb::CommandFailedException & ) { 1102 excOccurred = ::cppu::getCaughtException(); 1103 } catch (ucb::CommandAbortedException & ) { 1104 excOccurred = ::cppu::getCaughtException(); 1105 } catch (lang::IllegalArgumentException &) { 1106 excOccurred = ::cppu::getCaughtException(); 1107 } catch (uno::RuntimeException &) { 1108 excOccurred = ::cppu::getCaughtException(); 1109 } catch (...) { 1110 excOccurred = ::cppu::getCaughtException(); 1111 deploy::DeploymentException exc( 1112 OUSTR("Extension Manager: exception during disableExtension"), 1113 static_cast<OWeakObject*>(this), excOccurred); 1114 excOccurred <<= exc; 1115 } 1116 1117 if (excOccurred.hasValue()) 1118 { 1119 try 1120 { 1121 activateExtension(dp_misc::getIdentifier(extension), 1122 extension->getName(), bUserDisabled, false, 1123 xAbortChannel, xCmdEnv); 1124 } 1125 catch (...) 1126 { 1127 } 1128 ::cppu::throwException(excOccurred); 1129 } 1130 } 1131 1132 uno::Sequence< Reference<deploy::XPackage> > 1133 ExtensionManager::getDeployedExtensions( 1134 OUString const & repository, 1135 Reference<task::XAbortChannel> const &xAbort, 1136 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 1137 throw (deploy::DeploymentException, 1138 ucb::CommandFailedException, 1139 ucb::CommandAbortedException, 1140 lang::IllegalArgumentException, 1141 uno::RuntimeException) 1142 { 1143 return getPackageManager(repository)->getDeployedPackages( 1144 xAbort, xCmdEnv); 1145 } 1146 1147 Reference<deploy::XPackage> 1148 ExtensionManager::getDeployedExtension( 1149 OUString const & repository, 1150 OUString const & identifier, 1151 OUString const & filename, 1152 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 1153 throw (deploy::DeploymentException, 1154 ucb::CommandFailedException, 1155 lang::IllegalArgumentException, 1156 uno::RuntimeException) 1157 { 1158 return getPackageManager(repository)->getDeployedPackage( 1159 identifier, filename, xCmdEnv); 1160 } 1161 1162 uno::Sequence< uno::Sequence<Reference<deploy::XPackage> > > 1163 ExtensionManager::getAllExtensions( 1164 Reference<task::XAbortChannel> const & xAbort, 1165 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 1166 throw (deploy::DeploymentException, 1167 ucb::CommandFailedException, 1168 ucb::CommandAbortedException, 1169 lang::IllegalArgumentException, 1170 uno::RuntimeException) 1171 { 1172 try 1173 { 1174 id2extensions mapExt; 1175 1176 uno::Sequence<Reference<deploy::XPackage> > userExt = 1177 getUserRepository()->getDeployedPackages(xAbort, xCmdEnv); 1178 addExtensionsToMap(mapExt, userExt, OUSTR("user")); 1179 uno::Sequence<Reference<deploy::XPackage> > sharedExt = 1180 getSharedRepository()->getDeployedPackages(xAbort, xCmdEnv); 1181 addExtensionsToMap(mapExt, sharedExt, OUSTR("shared")); 1182 uno::Sequence<Reference<deploy::XPackage> > bundledExt = 1183 getBundledRepository()->getDeployedPackages(xAbort, xCmdEnv); 1184 addExtensionsToMap(mapExt, bundledExt, OUSTR("bundled")); 1185 1186 //copy the values of the map to a vector for sorting 1187 ::std::vector< ::std::vector<Reference<deploy::XPackage> > > 1188 vecExtensions; 1189 id2extensions::const_iterator mapIt = mapExt.begin(); 1190 for (;mapIt != mapExt.end(); mapIt++) 1191 vecExtensions.push_back(mapIt->second); 1192 1193 //sort the element according to the identifier 1194 ::std::sort(vecExtensions.begin(), vecExtensions.end(), CompIdentifiers()); 1195 1196 ::std::vector< ::std::vector<Reference<deploy::XPackage> > >::const_iterator 1197 citVecVec = vecExtensions.begin(); 1198 sal_Int32 j = 0; 1199 uno::Sequence< uno::Sequence<Reference<deploy::XPackage> > > seqSeq(vecExtensions.size()); 1200 for (;citVecVec != vecExtensions.end(); citVecVec++, j++) 1201 { 1202 seqSeq[j] = comphelper::containerToSequence(*citVecVec); 1203 } 1204 return seqSeq; 1205 1206 } catch (deploy::DeploymentException& ) { 1207 throw; 1208 } catch (ucb::CommandFailedException & ) { 1209 throw; 1210 } catch (ucb::CommandAbortedException & ) { 1211 throw; 1212 } catch (lang::IllegalArgumentException &) { 1213 throw; 1214 } catch (uno::RuntimeException &) { 1215 throw; 1216 } catch (...) { 1217 uno::Any exc = ::cppu::getCaughtException(); 1218 throw deploy::DeploymentException( 1219 OUSTR("Extension Manager: exception during enableExtension"), 1220 static_cast<OWeakObject*>(this), exc); 1221 } 1222 } 1223 1224 //only to be called from unopkg!!! 1225 void ExtensionManager::reinstallDeployedExtensions( 1226 OUString const & repository, 1227 Reference<task::XAbortChannel> const & xAbortChannel, 1228 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 1229 throw (deploy::DeploymentException, 1230 ucb::CommandFailedException, ucb::CommandAbortedException, 1231 lang::IllegalArgumentException, uno::RuntimeException) 1232 { 1233 try 1234 { 1235 Reference<deploy::XPackageManager> 1236 xPackageManager = getPackageManager(repository); 1237 1238 ::osl::MutexGuard guard(getMutex()); 1239 xPackageManager->reinstallDeployedPackages(xAbortChannel, xCmdEnv); 1240 //We must sync here, otherwise we will get exceptions when extensions 1241 //are removed. 1242 dp_misc::syncRepositories(xCmdEnv); 1243 const uno::Sequence< Reference<deploy::XPackage> > extensions( 1244 xPackageManager->getDeployedPackages(xAbortChannel, xCmdEnv)); 1245 1246 for ( sal_Int32 pos = 0; pos < extensions.getLength(); ++pos ) 1247 { 1248 try 1249 { 1250 const OUString id = dp_misc::getIdentifier(extensions[ pos ]); 1251 const OUString fileName = extensions[ pos ]->getName(); 1252 OSL_ASSERT(id.getLength()); 1253 activateExtension(id, fileName, false, true, xAbortChannel, xCmdEnv ); 1254 } 1255 catch (lang::DisposedException &) 1256 { 1257 } 1258 } 1259 } catch (deploy::DeploymentException& ) { 1260 throw; 1261 } catch (ucb::CommandFailedException & ) { 1262 throw; 1263 } catch (ucb::CommandAbortedException & ) { 1264 throw; 1265 } catch (lang::IllegalArgumentException &) { 1266 throw; 1267 } catch (uno::RuntimeException &) { 1268 throw; 1269 } catch (...) { 1270 uno::Any exc = ::cppu::getCaughtException(); 1271 throw deploy::DeploymentException( 1272 OUSTR("Extension Manager: exception during enableExtension"), 1273 static_cast<OWeakObject*>(this), exc); 1274 } 1275 } 1276 1277 /** Works on the bundled repository. That is using the variables 1278 BUNDLED_EXTENSIONS and BUNDLED_EXTENSIONS_USER. 1279 */ 1280 void ExtensionManager::synchronizeBundledPrereg( 1281 Reference<task::XAbortChannel> const & xAbortChannel, 1282 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 1283 throw (deploy::DeploymentException, 1284 uno::RuntimeException) 1285 { 1286 try 1287 { 1288 String sSynchronizingBundled(StrSyncRepository::get()); 1289 sSynchronizingBundled.SearchAndReplaceAllAscii( "%NAME", OUSTR("bundled")); 1290 dp_misc::ProgressLevel progressBundled(xCmdEnv, sSynchronizingBundled); 1291 1292 Reference<deploy::XPackageManagerFactory> xPackageManagerFactory( 1293 deploy::thePackageManagerFactory::get(m_xContext)); 1294 1295 Reference<deploy::XPackageManager> xMgr = 1296 xPackageManagerFactory->getPackageManager(OUSTR("bundled_prereg")); 1297 xMgr->synchronize(xAbortChannel, xCmdEnv); 1298 progressBundled.update(OUSTR("\n\n")); 1299 1300 uno::Sequence<Reference<deploy::XPackage> > extensions = xMgr->getDeployedPackages( 1301 xAbortChannel, xCmdEnv); 1302 try 1303 { 1304 for (sal_Int32 i = 0; i < extensions.getLength(); i++) 1305 { 1306 extensions[i]->registerPackage(true, xAbortChannel, xCmdEnv); 1307 } 1308 } 1309 catch (...) 1310 { 1311 OSL_ASSERT(0); 1312 } 1313 OUString lastSyncBundled(RTL_CONSTASCII_USTRINGPARAM( 1314 "$BUNDLED_EXTENSIONS_PREREG/lastsynchronized")); 1315 writeLastModified(lastSyncBundled, xCmdEnv); 1316 1317 } catch (deploy::DeploymentException& ) { 1318 throw; 1319 } catch (ucb::CommandFailedException & ) { 1320 throw; 1321 } catch (ucb::CommandAbortedException & ) { 1322 throw; 1323 } catch (lang::IllegalArgumentException &) { 1324 throw; 1325 } catch (uno::RuntimeException &) { 1326 throw; 1327 } catch (...) { 1328 uno::Any exc = ::cppu::getCaughtException(); 1329 throw deploy::DeploymentException( 1330 OUSTR("Extension Manager: exception in synchronize"), 1331 static_cast<OWeakObject*>(this), exc); 1332 } 1333 } 1334 1335 sal_Bool ExtensionManager::synchronize( 1336 Reference<task::XAbortChannel> const & xAbortChannel, 1337 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 1338 throw (deploy::DeploymentException, 1339 ucb::CommandFailedException, 1340 ucb::CommandAbortedException, 1341 lang::IllegalArgumentException, 1342 uno::RuntimeException) 1343 { 1344 try 1345 { 1346 sal_Bool bModified = sal_False; 1347 1348 ::osl::MutexGuard guard(getMutex()); 1349 String sSynchronizingShared(StrSyncRepository::get()); 1350 sSynchronizingShared.SearchAndReplaceAllAscii( "%NAME", OUSTR("shared")); 1351 dp_misc::ProgressLevel progressShared(xCmdEnv, sSynchronizingShared); 1352 bModified = getSharedRepository()->synchronize(xAbortChannel, xCmdEnv); 1353 progressShared.update(OUSTR("\n\n")); 1354 1355 String sSynchronizingBundled(StrSyncRepository::get()); 1356 sSynchronizingBundled.SearchAndReplaceAllAscii( "%NAME", OUSTR("bundled")); 1357 dp_misc::ProgressLevel progressBundled(xCmdEnv, sSynchronizingBundled); 1358 bModified |= getBundledRepository()->synchronize(xAbortChannel, xCmdEnv); 1359 progressBundled.update(OUSTR("\n\n")); 1360 1361 //Always determine the active extension. This is necessary for the 1362 //first-start optimization. The setup creates the registration data for the 1363 //bundled extensions (brand_layer/share/prereg/bundled), which is copied to the user 1364 //installation (user_installation/extension/bundled) when a user starts OOo 1365 //for the first time after running setup. All bundled extensions are registered 1366 //at that moment. However, extensions with the same identifier can be in the 1367 //shared or user repository, in which case the respective bundled extensions must 1368 //be revoked. 1369 try 1370 { 1371 const uno::Sequence<uno::Sequence<Reference<deploy::XPackage> > > 1372 seqSeqExt = getAllExtensions(xAbortChannel, xCmdEnv); 1373 for (sal_Int32 i = 0; i < seqSeqExt.getLength(); i++) 1374 { 1375 uno::Sequence<Reference<deploy::XPackage> > const & seqExt = 1376 seqSeqExt[i]; 1377 activateExtension(seqExt, isUserDisabled(seqExt), true, 1378 xAbortChannel, xCmdEnv); 1379 } 1380 } 1381 catch (...) 1382 { 1383 //We catch the exception, so we can write the lastmodified file 1384 //so we will no repeat this everytime OOo starts. 1385 OSL_ENSURE(0, "Extensions Manager: synchronize"); 1386 } 1387 OUString lastSyncBundled(RTL_CONSTASCII_USTRINGPARAM( 1388 "$BUNDLED_EXTENSIONS_USER/lastsynchronized")); 1389 writeLastModified(lastSyncBundled, xCmdEnv); 1390 OUString lastSyncShared(RTL_CONSTASCII_USTRINGPARAM( 1391 "$SHARED_EXTENSIONS_USER/lastsynchronized")); 1392 writeLastModified(lastSyncShared, xCmdEnv); 1393 return bModified; 1394 } catch (deploy::DeploymentException& ) { 1395 throw; 1396 } catch (ucb::CommandFailedException & ) { 1397 throw; 1398 } catch (ucb::CommandAbortedException & ) { 1399 throw; 1400 } catch (lang::IllegalArgumentException &) { 1401 throw; 1402 } catch (uno::RuntimeException &) { 1403 throw; 1404 } catch (...) { 1405 uno::Any exc = ::cppu::getCaughtException(); 1406 throw deploy::DeploymentException( 1407 OUSTR("Extension Manager: exception in synchronize"), 1408 static_cast<OWeakObject*>(this), exc); 1409 } 1410 } 1411 1412 // Notify the user when a new extension is to be installed. This is only the 1413 // case when one uses the system integration to install an extension (double 1414 // clicking on .oxt file etc.)). The function must only be called if there is no 1415 // extension with the same identifier already deployed. Then the checkUpdate 1416 // function will inform the user that the extension is about to be installed In 1417 // case the user cancels the installation a CommandFailed exception is 1418 // thrown. 1419 void ExtensionManager::checkInstall( 1420 OUString const & displayName, 1421 Reference<ucb::XCommandEnvironment> const & cmdEnv) 1422 { 1423 uno::Any request( 1424 deploy::InstallException( 1425 OUSTR("Extension ") + displayName + 1426 OUSTR(" is about to be installed."), 1427 static_cast<OWeakObject *>(this), displayName)); 1428 bool approve = false, abort = false; 1429 if (! dp_misc::interactContinuation( 1430 request, task::XInteractionApprove::static_type(), 1431 cmdEnv, &approve, &abort )) 1432 { 1433 OSL_ASSERT( !approve && !abort ); 1434 throw deploy::DeploymentException( 1435 dp_misc::getResourceString(RID_STR_ERROR_WHILE_ADDING) + displayName, 1436 static_cast<OWeakObject *>(this), request ); 1437 } 1438 if (abort || !approve) 1439 throw ucb::CommandFailedException( 1440 dp_misc::getResourceString(RID_STR_ERROR_WHILE_ADDING) + displayName, 1441 static_cast<OWeakObject *>(this), request ); 1442 } 1443 1444 /* The function will make the user interaction in case there is an extension 1445 installed with the same id. This function may only be called if there is already 1446 an extension. 1447 */ 1448 void ExtensionManager::checkUpdate( 1449 OUString const & newVersion, 1450 OUString const & newDisplayName, 1451 Reference<deploy::XPackage> const & oldExtension, 1452 Reference<ucb::XCommandEnvironment> const & xCmdEnv ) 1453 { 1454 // package already deployed, interact --force: 1455 uno::Any request( 1456 (deploy::VersionException( 1457 dp_misc::getResourceString( 1458 RID_STR_PACKAGE_ALREADY_ADDED ) + newDisplayName, 1459 static_cast<OWeakObject *>(this), newVersion, newDisplayName, 1460 oldExtension ) ) ); 1461 bool replace = false, abort = false; 1462 if (! dp_misc::interactContinuation( 1463 request, task::XInteractionApprove::static_type(), 1464 xCmdEnv, &replace, &abort )) { 1465 OSL_ASSERT( !replace && !abort ); 1466 throw deploy::DeploymentException( 1467 dp_misc::getResourceString( 1468 RID_STR_ERROR_WHILE_ADDING) + newDisplayName, 1469 static_cast<OWeakObject *>(this), request ); 1470 } 1471 if (abort || !replace) 1472 throw ucb::CommandFailedException( 1473 dp_misc::getResourceString( 1474 RID_STR_PACKAGE_ALREADY_ADDED) + newDisplayName, 1475 static_cast<OWeakObject *>(this), request ); 1476 } 1477 1478 Reference<deploy::XPackage> ExtensionManager::getTempExtension( 1479 OUString const & url, 1480 Reference<task::XAbortChannel> const & xAbortChannel, 1481 Reference<ucb::XCommandEnvironment> const & /*xCmdEnv*/) 1482 1483 { 1484 Reference<ucb::XCommandEnvironment> tmpCmdEnvA(new TmpRepositoryCommandEnv()); 1485 Reference<deploy::XPackage> xTmpPackage = getTmpRepository()->addPackage( 1486 url, uno::Sequence<beans::NamedValue>(),OUString(), xAbortChannel, tmpCmdEnvA); 1487 if (!xTmpPackage.is()) 1488 { 1489 throw deploy::DeploymentException( 1490 OUSTR("Extension Manager: Failed to create temporary XPackage for url: ") + url, 1491 static_cast<OWeakObject*>(this), uno::Any()); 1492 1493 } 1494 return xTmpPackage; 1495 } 1496 1497 uno::Sequence<Reference<deploy::XPackage> > SAL_CALL 1498 ExtensionManager::getExtensionsWithUnacceptedLicenses( 1499 OUString const & repository, 1500 Reference<ucb::XCommandEnvironment> const & xCmdEnv) 1501 throw (deploy::DeploymentException, 1502 uno::RuntimeException) 1503 { 1504 Reference<deploy::XPackageManager> 1505 xPackageManager = getPackageManager(repository); 1506 ::osl::MutexGuard guard(getMutex()); 1507 return xPackageManager->getExtensionsWithUnacceptedLicenses(xCmdEnv); 1508 } 1509 1510 sal_Bool ExtensionManager::isReadOnlyRepository(::rtl::OUString const & repository) 1511 throw (uno::RuntimeException) 1512 { 1513 return getPackageManager(repository)->isReadOnly(); 1514 } 1515 //------------------------------------------------------------------------------ 1516 //------------------------------------------------------------------------------ 1517 //------------------------------------------------------------------------------ 1518 1519 namespace sdecl = comphelper::service_decl; 1520 sdecl::class_<ExtensionManager> servicePIP; 1521 extern sdecl::ServiceDecl const serviceDecl( 1522 servicePIP, 1523 // a private one: 1524 "com.sun.star.comp.deployment.ExtensionManager", 1525 "com.sun.star.comp.deployment.ExtensionManager"); 1526 1527 //------------------------------------------------------------------------------ 1528 bool singleton_entries( 1529 uno::Reference< registry::XRegistryKey > const & xRegistryKey ) 1530 { 1531 try { 1532 uno::Reference< registry::XRegistryKey > xKey( 1533 xRegistryKey->createKey( 1534 serviceDecl.getImplementationName() + 1535 // xxx todo: use future generated function to get singleton name 1536 OUSTR("/UNO/SINGLETONS/" 1537 "com.sun.star.deployment.ExtensionManager") ) ); 1538 xKey->setStringValue( serviceDecl.getSupportedServiceNames()[0] ); 1539 return true; 1540 } 1541 catch (registry::InvalidRegistryException & exc) { 1542 (void) exc; // avoid warnings 1543 OSL_ENSURE( 0, ::rtl::OUStringToOString( 1544 exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() ); 1545 return false; 1546 } 1547 } 1548 1549 // XModifyBroadcaster 1550 //______________________________________________________________________________ 1551 void ExtensionManager::addModifyListener( 1552 Reference<util::XModifyListener> const & xListener ) 1553 throw (uno::RuntimeException) 1554 { 1555 check(); 1556 rBHelper.addListener( ::getCppuType( &xListener ), xListener ); 1557 } 1558 1559 //______________________________________________________________________________ 1560 void ExtensionManager::removeModifyListener( 1561 Reference<util::XModifyListener> const & xListener ) 1562 throw (uno::RuntimeException) 1563 { 1564 check(); 1565 rBHelper.removeListener( ::getCppuType( &xListener ), xListener ); 1566 } 1567 1568 void ExtensionManager::check() 1569 { 1570 ::osl::MutexGuard guard( getMutex() ); 1571 if (rBHelper.bInDispose || rBHelper.bDisposed) { 1572 throw lang::DisposedException( 1573 OUSTR("ExtensionManager instance has already been disposed!"), 1574 static_cast<OWeakObject *>(this) ); 1575 } 1576 } 1577 1578 void ExtensionManager::fireModified() 1579 { 1580 ::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer( 1581 util::XModifyListener::static_type() ); 1582 if (pContainer != 0) { 1583 pContainer->forEach<util::XModifyListener>( 1584 boost::bind(&util::XModifyListener::modified, _1, 1585 lang::EventObject(static_cast<OWeakObject *>(this))) ); 1586 } 1587 } 1588 1589 } // namespace dp_manager 1590 1591 1592