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