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