Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / desktop / source / deployment / manager / dp_extensionmanager.cxx
blobb51f4c77b47b0d1d754aaefc451c72a53cf5313b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <cppuhelper/compbase.hxx>
22 #include <cppuhelper/supportsservice.hxx>
24 #include <cppuhelper/exc_hlp.hxx>
25 #include <rtl/bootstrap.hxx>
26 #include <com/sun/star/deployment/DeploymentException.hpp>
27 #include <com/sun/star/deployment/XExtensionManager.hpp>
28 #include <com/sun/star/deployment/thePackageManagerFactory.hpp>
29 #include <com/sun/star/deployment/XPackageManager.hpp>
30 #include <com/sun/star/deployment/XPackage.hpp>
31 #include <com/sun/star/deployment/InstallException.hpp>
32 #include <com/sun/star/deployment/VersionException.hpp>
33 #include <com/sun/star/lang/IllegalArgumentException.hpp>
34 #include <com/sun/star/lang/XServiceInfo.hpp>
35 #include <com/sun/star/beans/Optional.hpp>
36 #include <com/sun/star/task/XInteractionApprove.hpp>
37 #include <com/sun/star/beans/Ambiguous.hpp>
38 #include <com/sun/star/ucb/CommandAbortedException.hpp>
39 #include <com/sun/star/ucb/CommandFailedException.hpp>
40 #include <com/sun/star/uno/XComponentContext.hpp>
41 #include <com/sun/star/io/XInputStream.hpp>
42 #include <com/sun/star/util/XModifyBroadcaster.hpp>
43 #include <comphelper/sequence.hxx>
44 #include <utility>
45 #include <xmlscript/xml_helper.hxx>
46 #include <osl/diagnose.h>
47 #include <dp_interact.h>
48 #include <dp_misc.h>
49 #include <dp_ucb.h>
50 #include <dp_identifier.hxx>
51 #include <dp_descriptioninfoset.hxx>
52 #include "dp_extensionmanager.hxx"
53 #include "dp_commandenvironments.hxx"
54 #include "dp_properties.hxx"
56 #include <vector>
57 #include <algorithm>
58 #include <set>
59 #include <string_view>
61 namespace lang = com::sun::star::lang;
62 namespace task = com::sun::star::task;
63 namespace ucb = com::sun::star::ucb;
64 namespace uno = com::sun::star::uno;
65 namespace beans = com::sun::star::beans;
66 namespace util = com::sun::star::util;
68 using ::com::sun::star::uno::Reference;
70 namespace {
72 struct CompIdentifiers
74 bool operator() (std::vector<Reference<css::deployment::XPackage> > const & a,
75 std::vector<Reference<css::deployment::XPackage> > const & b)
77 return getName(a).compareTo(getName(b)) < 0;
80 static OUString getName(std::vector<Reference<css::deployment::XPackage> > const & a);
83 OUString CompIdentifiers::getName(std::vector<Reference<css::deployment::XPackage> > const & a)
85 OSL_ASSERT(a.size() == 3);
86 //get the first non-null reference
87 Reference<css::deployment::XPackage> extension;
88 for (auto const& elem : a)
90 if (elem.is())
92 extension = elem;
93 break;
96 OSL_ASSERT(extension.is());
97 return extension->getDisplayName();
100 void writeLastModified(OUString & url, Reference<ucb::XCommandEnvironment> const & xCmdEnv, Reference< uno::XComponentContext > const & xContext)
102 //Write the lastmodified file
103 try {
104 ::rtl::Bootstrap::expandMacros(url);
105 ::ucbhelper::Content ucbStamp(url, xCmdEnv, xContext);
106 dp_misc::erase_path( url, xCmdEnv );
107 OString stamp("1" );
108 Reference<css::io::XInputStream> xData(
109 ::xmlscript::createInputStream(
110 reinterpret_cast<sal_Int8 const *>(stamp.getStr()),
111 stamp.getLength() ) );
112 ucbStamp.writeStream( xData, true /* replace existing */ );
114 catch(...)
116 uno::Any exc(::cppu::getCaughtException());
117 throw css::deployment::DeploymentException("Failed to update" + url, nullptr, exc);
121 class ExtensionRemoveGuard
123 css::uno::Reference<css::deployment::XPackage> m_extension;
124 css::uno::Reference<css::deployment::XPackageManager> m_xPackageManager;
126 public:
127 ExtensionRemoveGuard(){};
128 ExtensionRemoveGuard(
129 css::uno::Reference<css::deployment::XPackage> extension,
130 css::uno::Reference<css::deployment::XPackageManager> xPackageManager):
131 m_extension(std::move(extension)), m_xPackageManager(std::move(xPackageManager)) {}
132 ~ExtensionRemoveGuard();
134 void set(css::uno::Reference<css::deployment::XPackage> const & extension,
135 css::uno::Reference<css::deployment::XPackageManager> const & xPackageManager) {
136 m_extension = extension;
137 m_xPackageManager = xPackageManager;
141 ExtensionRemoveGuard::~ExtensionRemoveGuard()
143 try {
144 OSL_ASSERT(!(m_extension.is() && !m_xPackageManager.is()));
145 if (m_xPackageManager.is() && m_extension.is())
146 m_xPackageManager->removePackage(
147 dp_misc::getIdentifier(m_extension), OUString(),
148 css::uno::Reference<css::task::XAbortChannel>(),
149 css::uno::Reference<css::ucb::XCommandEnvironment>());
150 } catch (...) {
151 OSL_ASSERT(false);
157 namespace dp_manager {
159 //ToDo: bundled extension
160 ExtensionManager::ExtensionManager( Reference< uno::XComponentContext > const& xContext) :
161 ::cppu::WeakComponentImplHelper< css::deployment::XExtensionManager, css::lang::XServiceInfo >(m_aMutex)
162 , m_xContext(xContext)
164 m_xPackageManagerFactory = css::deployment::thePackageManagerFactory::get(m_xContext);
165 OSL_ASSERT(m_xPackageManagerFactory.is());
167 m_repositoryNames.emplace_back("user");
168 m_repositoryNames.emplace_back("shared");
169 m_repositoryNames.emplace_back("bundled");
172 ExtensionManager::~ExtensionManager()
176 // XServiceInfo
177 OUString ExtensionManager::getImplementationName()
179 return "com.sun.star.comp.deployment.ExtensionManager";
182 sal_Bool ExtensionManager::supportsService( const OUString& ServiceName )
184 return cppu::supportsService(this, ServiceName);
187 css::uno::Sequence< OUString > ExtensionManager::getSupportedServiceNames()
189 // a private one:
190 return { "com.sun.star.comp.deployment.ExtensionManager" };
193 Reference<css::deployment::XPackageManager> ExtensionManager::getUserRepository()
195 return m_xPackageManagerFactory->getPackageManager("user");
197 Reference<css::deployment::XPackageManager> ExtensionManager::getSharedRepository()
199 return m_xPackageManagerFactory->getPackageManager("shared");
201 Reference<css::deployment::XPackageManager> ExtensionManager::getBundledRepository()
203 return m_xPackageManagerFactory->getPackageManager("bundled");
205 Reference<css::deployment::XPackageManager> ExtensionManager::getTmpRepository()
207 return m_xPackageManagerFactory->getPackageManager("tmp");
209 Reference<css::deployment::XPackageManager> ExtensionManager::getBakRepository()
211 return m_xPackageManagerFactory->getPackageManager("bak");
214 Reference<task::XAbortChannel> ExtensionManager::createAbortChannel()
216 return new dp_misc::AbortChannel;
219 css::uno::Reference<css::deployment::XPackageManager>
220 ExtensionManager::getPackageManager(std::u16string_view repository)
222 Reference<css::deployment::XPackageManager> xPackageManager;
223 if (repository == u"user")
224 xPackageManager = getUserRepository();
225 else if (repository == u"shared")
226 xPackageManager = getSharedRepository();
227 else if (repository == u"bundled")
228 xPackageManager = getBundledRepository();
229 else if (repository == u"tmp")
230 xPackageManager = getTmpRepository();
231 else if (repository == u"bak")
232 xPackageManager = getBakRepository();
233 else
234 throw lang::IllegalArgumentException(
235 "No valid repository name provided.",
236 static_cast<cppu::OWeakObject*>(this), 0);
237 return xPackageManager;
241 Enters the XPackage objects into a map. They must be all from the
242 same repository. The value type of the map is a vector, where each vector
243 represents an extension with a particular identifier. The first member
244 represents the user extension, the second the shared extension and the
245 third the bundled extension.
247 void ExtensionManager::addExtensionsToMap(
248 id2extensions & mapExt,
249 uno::Sequence<Reference<css::deployment::XPackage> > const & seqExt,
250 std::u16string_view repository)
252 //Determine the index in the vector where these extensions are to be
253 //added.
254 int index = 0;
255 for (auto const& repositoryName : m_repositoryNames)
257 if (repositoryName == repository)
258 break;
259 ++index;
262 for (const Reference<css::deployment::XPackage>& xExtension : seqExt)
264 OUString id = dp_misc::getIdentifier(xExtension);
265 id2extensions::iterator ivec = mapExt.find(id);
266 if (ivec == mapExt.end())
268 std::vector<Reference<css::deployment::XPackage> > vec(3);
269 vec[index] = xExtension;
270 mapExt[id] = vec;
272 else
274 ivec->second[index] = xExtension;
280 returns a list containing extensions with the same identifier from
281 all repositories (user, shared, bundled). If one repository does not
282 have this extension, then the list contains an empty Reference. The list
283 is ordered according to the priority of the repositories:
284 1. user
285 2. shared
286 3. bundled
288 The number of elements is always three, unless the number of repository
289 changes.
291 std::vector<Reference<css::deployment::XPackage> >
292 ExtensionManager::getExtensionsWithSameId(
293 OUString const & identifier, OUString const & fileName)
296 std::vector<Reference<css::deployment::XPackage> > extensionList;
297 Reference<css::deployment::XPackageManager> lRepos[] = {
298 getUserRepository(), getSharedRepository(), getBundledRepository() };
299 for (std::size_t i(0); i != std::size(lRepos); ++i)
301 Reference<css::deployment::XPackage> xPackage;
304 xPackage = lRepos[i]->getDeployedPackage(
305 identifier, fileName, Reference<ucb::XCommandEnvironment>());
307 catch(const lang::IllegalArgumentException &)
309 // thrown if the extension does not exist in this repository
311 extensionList.push_back(xPackage);
313 OSL_ASSERT(extensionList.size() == 3);
314 return extensionList;
317 uno::Sequence<Reference<css::deployment::XPackage> >
318 ExtensionManager::getExtensionsWithSameIdentifier(
319 OUString const & identifier,
320 OUString const & fileName,
321 Reference< ucb::XCommandEnvironment> const & /*xCmdEnv*/ )
325 std::vector<Reference<css::deployment::XPackage> > listExtensions =
326 getExtensionsWithSameId(identifier, fileName);
327 bool bHasExtension = false;
329 //throw an IllegalArgumentException if there is no extension at all.
330 for (auto const& extension : listExtensions)
331 bHasExtension |= extension.is();
332 if (!bHasExtension)
333 throw lang::IllegalArgumentException(
334 "Could not find extension: " + identifier + ", " + fileName,
335 static_cast<cppu::OWeakObject*>(this), -1);
337 return comphelper::containerToSequence(listExtensions);
339 catch ( const css::deployment::DeploymentException & )
341 throw;
343 catch ( const ucb::CommandFailedException & )
345 throw;
347 catch (css::uno::RuntimeException &)
349 throw;
351 catch (...)
353 uno::Any exc = ::cppu::getCaughtException();
354 throw css::deployment::DeploymentException(
355 "Extension Manager: exception during getExtensionsWithSameIdentifier",
356 static_cast<OWeakObject*>(this), exc);
360 bool ExtensionManager::isUserDisabled(
361 OUString const & identifier, OUString const & fileName)
363 std::vector<Reference<css::deployment::XPackage> > listExtensions;
365 try {
366 listExtensions = getExtensionsWithSameId(identifier, fileName);
367 } catch ( const lang::IllegalArgumentException & ) {
369 OSL_ASSERT(listExtensions.size() == 3);
371 return isUserDisabled( ::comphelper::containerToSequence(listExtensions) );
374 bool ExtensionManager::isUserDisabled(
375 uno::Sequence<Reference<css::deployment::XPackage> > const & seqExtSameId)
377 OSL_ASSERT(seqExtSameId.getLength() == 3);
378 Reference<css::deployment::XPackage> const & userExtension = seqExtSameId[0];
379 if (userExtension.is())
381 beans::Optional<beans::Ambiguous<sal_Bool> > reg =
382 userExtension->isRegistered(Reference<task::XAbortChannel>(),
383 Reference<ucb::XCommandEnvironment>());
384 //If the value is ambiguous, then we assume that the extension
385 //is enabled, but something went wrong during enabling. We do not
386 //automatically disable user extensions.
387 if (reg.IsPresent &&
388 ! reg.Value.IsAmbiguous && ! reg.Value.Value)
389 return true;
391 return false;
395 This method determines the active extension (XPackage.registerPackage) with a
396 particular identifier.
398 The parameter bUserDisabled determines if the user extension is disabled.
400 When the user repository contains an extension with the given identifier and
401 it is not disabled by the user, then it is always registered. Otherwise an
402 extension is only registered when there is no registered extension in one of
403 the repositories with a higher priority. That is, if the extension is from
404 the shared repository and an active extension with the same identifier is in
405 the user repository, then the extension is not registered. Similarly a
406 bundled extension is not registered if there is an active extension with the
407 same identifier in the shared or user repository.
409 void ExtensionManager::activateExtension(
410 OUString const & identifier, OUString const & fileName,
411 bool bUserDisabled,
412 bool bStartup,
413 Reference<task::XAbortChannel> const & xAbortChannel,
414 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
416 std::vector<Reference<css::deployment::XPackage> > listExtensions;
417 try {
418 listExtensions = getExtensionsWithSameId(identifier, fileName);
419 } catch (const lang::IllegalArgumentException &) {
421 OSL_ASSERT(listExtensions.size() == 3);
423 activateExtension(
424 ::comphelper::containerToSequence(listExtensions),
425 bUserDisabled, bStartup, xAbortChannel, xCmdEnv);
427 fireModified();
430 void ExtensionManager::activateExtension(
431 uno::Sequence<Reference<css::deployment::XPackage> > const & seqExt,
432 bool bUserDisabled,
433 bool bStartup,
434 Reference<task::XAbortChannel> const & xAbortChannel,
435 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
437 bool bActive = false;
438 sal_Int32 len = seqExt.getLength();
439 for (sal_Int32 i = 0; i < len; i++)
441 Reference<css::deployment::XPackage> const & aExt = seqExt[i];
442 if (aExt.is())
444 //get the registration value of the current iteration
445 beans::Optional<beans::Ambiguous<sal_Bool> > optReg =
446 aExt->isRegistered(xAbortChannel, xCmdEnv);
447 //If nothing can be registered then break
448 if (!optReg.IsPresent)
449 break;
451 //Check if this is a disabled user extension,
452 if (i == 0 && bUserDisabled)
454 aExt->revokePackage(bStartup, xAbortChannel, xCmdEnv);
455 continue;
458 //If we have already determined an active extension then we must
459 //make sure to unregister all extensions with the same id in
460 //repositories with a lower priority
461 if (bActive)
463 aExt->revokePackage(bStartup, xAbortChannel, xCmdEnv);
465 else
467 //This is the first extension in the ordered list, which becomes
468 //the active extension
469 bActive = true;
470 //Register if not already done.
471 //reregister if the value is ambiguous, which indicates that
472 //something went wrong during last registration.
473 aExt->registerPackage(bStartup, xAbortChannel, xCmdEnv);
479 Reference<css::deployment::XPackage> ExtensionManager::backupExtension(
480 OUString const & identifier, OUString const & fileName,
481 Reference<css::deployment::XPackageManager> const & xPackageManager,
482 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
484 Reference<css::deployment::XPackage> xBackup;
485 Reference<ucb::XCommandEnvironment> tmpCmdEnv(
486 new TmpRepositoryCommandEnv(xCmdEnv->getInteractionHandler()));
487 Reference<css::deployment::XPackage> xOldExtension = xPackageManager->getDeployedPackage(
488 identifier, fileName, tmpCmdEnv);
490 if (xOldExtension.is())
492 xBackup = getTmpRepository()->addPackage(
493 xOldExtension->getURL(), uno::Sequence<beans::NamedValue>(),
494 OUString(), Reference<task::XAbortChannel>(), tmpCmdEnv);
496 OSL_ENSURE(xBackup.is(), "Failed to backup extension");
498 return xBackup;
501 //The supported package types are actually determined by the registry. However
502 //creating a registry
503 //(desktop/source/deployment/registry/dp_registry.cxx:PackageRegistryImpl) will
504 //create all the backends, so that the registry can obtain from them the package
505 //types. Creating the registry will also set up the registry folder containing
506 //all the subfolders for the respective backends.
507 //Because all repositories support the same backends, we can just delegate this
508 //call to one of the repositories.
509 uno::Sequence< Reference<css::deployment::XPackageTypeInfo> >
510 ExtensionManager::getSupportedPackageTypes()
512 return getUserRepository()->getSupportedPackageTypes();
514 //Do some necessary checks and user interaction. This function does not
515 //acquire the extension manager mutex and that mutex must not be acquired
516 //when this function is called. doChecksForAddExtension does synchronous
517 //user interactions which may require acquiring the solar mutex.
518 //Returns true if the extension can be installed.
519 bool ExtensionManager::doChecksForAddExtension(
520 Reference<css::deployment::XPackageManager> const & xPackageMgr,
521 uno::Sequence<beans::NamedValue> const & properties,
522 css::uno::Reference<css::deployment::XPackage> const & xTmpExtension,
523 Reference<task::XAbortChannel> const & xAbortChannel,
524 Reference<ucb::XCommandEnvironment> const & xCmdEnv,
525 Reference<css::deployment::XPackage> & out_existingExtension )
529 Reference<css::deployment::XPackage> xOldExtension;
530 const OUString sIdentifier = dp_misc::getIdentifier(xTmpExtension);
531 const OUString sFileName = xTmpExtension->getName();
532 const OUString sDisplayName = xTmpExtension->getDisplayName();
533 const OUString sVersion = xTmpExtension->getVersion();
537 xOldExtension = xPackageMgr->getDeployedPackage(
538 sIdentifier, sFileName, xCmdEnv);
539 out_existingExtension = xOldExtension;
541 catch (const lang::IllegalArgumentException &)
544 bool bCanInstall = false;
546 //This part is not guarded against other threads removing, adding, disabling ...
547 //etc. the same extension.
548 //checkInstall is safe because it notifies the user if the extension is not yet
549 //installed in the same repository. Because addExtension has its own guard
550 //(m_addMutex), another thread cannot add the extension in the meantime.
551 //checkUpdate is called if the same extension exists in the same
552 //repository. The user is asked if they want to replace it. Another
553 //thread
554 //could already remove the extension. So asking the user was not
555 //necessary. No harm is done. The other thread may also ask the user
556 //if he wants to remove the extension. This depends on the
557 //XCommandEnvironment which it passes to removeExtension.
558 if (xOldExtension.is())
560 //throws a CommandFailedException if the user cancels
561 //the action.
562 checkUpdate(sVersion, sDisplayName,xOldExtension, xCmdEnv);
564 else
566 //throws a CommandFailedException if the user cancels
567 //the action.
568 checkInstall(sDisplayName, xCmdEnv);
570 //Prevent showing the license if requested.
571 Reference<ucb::XCommandEnvironment> _xCmdEnv(xCmdEnv);
572 ExtensionProperties props(std::u16string_view(), properties, Reference<ucb::XCommandEnvironment>(), m_xContext);
574 dp_misc::DescriptionInfoset info(dp_misc::getDescriptionInfoset(xTmpExtension->getURL()));
575 const ::std::optional<dp_misc::SimpleLicenseAttributes> licenseAttributes =
576 info.getSimpleLicenseAttributes();
578 if (licenseAttributes && licenseAttributes->suppressIfRequired
579 && props.isSuppressedLicense())
580 _xCmdEnv.set(new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler()));
582 bCanInstall = xTmpExtension->checkPrerequisites(
583 xAbortChannel, _xCmdEnv, xOldExtension.is() || props.isExtensionUpdate()) == 0;
585 return bCanInstall;
587 catch ( const css::deployment::DeploymentException& ) {
588 throw;
589 } catch ( const ucb::CommandFailedException & ) {
590 throw;
591 } catch ( const ucb::CommandAbortedException & ) {
592 throw;
593 } catch (const lang::IllegalArgumentException &) {
594 throw;
595 } catch (const uno::RuntimeException &) {
596 throw;
597 } catch (const uno::Exception &) {
598 uno::Any excOccurred = ::cppu::getCaughtException();
599 css::deployment::DeploymentException exc(
600 "Extension Manager: exception in doChecksForAddExtension",
601 static_cast<OWeakObject*>(this), excOccurred);
602 throw exc;
603 } catch (...) {
604 throw uno::RuntimeException(
605 "Extension Manager: unexpected exception in doChecksForAddExtension",
606 static_cast<OWeakObject*>(this));
610 // Only add to shared and user repository
611 Reference<css::deployment::XPackage> ExtensionManager::addExtension(
612 OUString const & url, uno::Sequence<beans::NamedValue> const & properties,
613 OUString const & repository,
614 Reference<task::XAbortChannel> const & xAbortChannel,
615 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
617 Reference<css::deployment::XPackage> xNewExtension;
618 //Determine the repository to use
619 Reference<css::deployment::XPackageManager> xPackageManager;
620 if (repository == "user")
621 xPackageManager = getUserRepository();
622 else if (repository == "shared")
623 xPackageManager = getSharedRepository();
624 else
625 throw lang::IllegalArgumentException(
626 "No valid repository name provided.",
627 static_cast<cppu::OWeakObject*>(this), 0);
628 //We must make sure that the xTmpExtension is not create twice, because this
629 //would remove the first one.
630 std::unique_lock addGuard(m_addMutex);
632 Reference<css::deployment::XPackageManager> xTmpRepository(getTmpRepository());
633 // make sure xTmpRepository is alive as long as xTmpExtension is; as
634 // the "tmp" manager is only held weakly by m_xPackageManagerFactory, it
635 // could otherwise be disposed early, which would in turn dispose
636 // xTmpExtension's PackageRegistryBackend behind its back
637 Reference<css::deployment::XPackage> xTmpExtension(
638 xTmpRepository->addPackage(
639 url, uno::Sequence<beans::NamedValue>(), OUString(), xAbortChannel,
640 new TmpRepositoryCommandEnv()));
641 if (!xTmpExtension.is()) {
642 throw css::deployment::DeploymentException(
643 ("Extension Manager: Failed to create temporary XPackage for url: "
644 + url),
645 static_cast<OWeakObject*>(this), uno::Any());
648 //Make sure the extension is removed from the tmp repository in case
649 //of an exception
650 ExtensionRemoveGuard tmpExtensionRemoveGuard(xTmpExtension, getTmpRepository());
651 ExtensionRemoveGuard bakExtensionRemoveGuard;
652 const OUString sIdentifier = dp_misc::getIdentifier(xTmpExtension);
653 const OUString sFileName = xTmpExtension->getName();
654 Reference<css::deployment::XPackage> xOldExtension;
655 Reference<css::deployment::XPackage> xExtensionBackup;
657 uno::Any excOccurred2;
658 bool bCanInstall = doChecksForAddExtension(
659 xPackageManager,
660 properties,
661 xTmpExtension,
662 xAbortChannel,
663 xCmdEnv,
664 xOldExtension );
667 bool bUserDisabled = false;
668 // In this guarded section (getMutex) we must not use the argument xCmdEnv
669 // because it may bring up dialogs (XInteractionHandler::handle) this
670 // may potentially deadlock. See issue
671 // http://qa.openoffice.org/issues/show_bug.cgi?id=114933
672 // By not providing xCmdEnv the underlying APIs will throw an exception if
673 // the XInteractionRequest cannot be handled.
674 ::osl::MutexGuard guard(m_aMutex);
676 if (bCanInstall)
680 bUserDisabled = isUserDisabled(sIdentifier, sFileName);
681 if (xOldExtension.is())
685 xOldExtension->revokePackage(
686 false, xAbortChannel, Reference<ucb::XCommandEnvironment>());
687 //save the old user extension in case the user aborts
688 xExtensionBackup = getBakRepository()->importExtension(
689 xOldExtension, Reference<task::XAbortChannel>(),
690 Reference<ucb::XCommandEnvironment>());
691 bakExtensionRemoveGuard.set(xExtensionBackup, getBakRepository());
693 catch (const lang::DisposedException &)
695 //Another thread might have removed the extension meanwhile
698 //check again dependencies but prevent user interaction,
699 //We can disregard the license, because the user must have already
700 //accepted it, when we called checkPrerequisites the first time
701 rtl::Reference<SilentCheckPrerequisitesCommandEnv> pSilentCommandEnv =
702 new SilentCheckPrerequisitesCommandEnv();
704 sal_Int32 failedPrereq = xTmpExtension->checkPrerequisites(
705 xAbortChannel, pSilentCommandEnv, true);
706 if (failedPrereq == 0)
708 xNewExtension = xPackageManager->addPackage(
709 url, properties, OUString(), xAbortChannel,
710 Reference<ucb::XCommandEnvironment>());
711 //If we add a user extension and there is already one which was
712 //disabled by a user, then the newly installed one is enabled. If we
713 //add to another repository then the user extension remains
714 //disabled.
715 bool bUserDisabled2 = bUserDisabled;
716 if (repository == "user")
717 bUserDisabled2 = false;
719 // pass the two values via variables to workaround gcc-4.3.4 specific bug (bnc#655912)
720 OUString sNewExtensionIdentifier = dp_misc::getIdentifier(xNewExtension);
721 OUString sNewExtensionFileName = xNewExtension->getName();
723 activateExtension(
724 sNewExtensionIdentifier, sNewExtensionFileName,
725 bUserDisabled2, false, xAbortChannel,
726 Reference<ucb::XCommandEnvironment>());
728 // if reached this section,
729 // this means that either the licensedialog.ui didn't popup,
730 // or user accepted the license agreement. otherwise
731 // no need to call fireModified() because user declined
732 // the license agreement therefore no change made.
735 fireModified();
737 }catch ( const css::deployment::DeploymentException& ) {
738 throw;
739 } catch ( const ucb::CommandFailedException & ) {
740 throw;
741 } catch ( const ucb::CommandAbortedException & ) {
742 throw;
743 } catch (const lang::IllegalArgumentException &) {
744 throw;
745 } catch (const uno::RuntimeException &) {
746 throw;
747 } catch (const uno::Exception &) {
748 uno::Any excOccurred = ::cppu::getCaughtException();
749 css::deployment::DeploymentException exc(
750 "Extension Manager: Exception on fireModified() "
751 "in the scope of 'if (failedPrereq == 0)'",
752 static_cast<OWeakObject*>(this), excOccurred);
753 throw exc;
754 } catch (...) {
755 throw uno::RuntimeException(
756 "Extension Manager: RuntimeException on fireModified() "
757 "in the scope of 'if (failedPrereq == 0)'",
758 static_cast<OWeakObject*>(this));
761 else
763 if (pSilentCommandEnv->m_Exception.hasValue())
764 ::cppu::throwException(pSilentCommandEnv->m_Exception);
765 else if ( pSilentCommandEnv->m_UnknownException.hasValue())
766 ::cppu::throwException(pSilentCommandEnv->m_UnknownException);
767 else
768 throw css::deployment::DeploymentException (
769 "Extension Manager: exception during addExtension, ckeckPrerequisites failed",
770 static_cast<OWeakObject*>(this), uno::Any());
773 catch ( const css::deployment::DeploymentException& ) {
774 excOccurred2 = ::cppu::getCaughtException();
775 } catch ( const ucb::CommandFailedException & ) {
776 excOccurred2 = ::cppu::getCaughtException();
777 } catch ( const ucb::CommandAbortedException & ) {
778 excOccurred2 = ::cppu::getCaughtException();
779 } catch (const lang::IllegalArgumentException &) {
780 excOccurred2 = ::cppu::getCaughtException();
781 } catch (const uno::RuntimeException &) {
782 excOccurred2 = ::cppu::getCaughtException();
783 } catch (...) {
784 excOccurred2 = ::cppu::getCaughtException();
785 css::deployment::DeploymentException exc(
786 "Extension Manager: exception during addExtension, url: "
787 + url, static_cast<OWeakObject*>(this), excOccurred2);
788 excOccurred2 <<= exc;
792 if (excOccurred2.hasValue())
794 //It does not matter what exception is thrown. We try to
795 //recover the original status.
796 //If the user aborted installation then a ucb::CommandAbortedException
797 //is thrown.
798 //Use a private AbortChannel so the user cannot interrupt.
801 if (xExtensionBackup.is())
803 xPackageManager->importExtension(
804 xExtensionBackup, Reference<task::XAbortChannel>(),
805 Reference<ucb::XCommandEnvironment>());
807 activateExtension(
808 sIdentifier, sFileName, bUserDisabled, false,
809 Reference<task::XAbortChannel>(), Reference<ucb::XCommandEnvironment>());
811 catch (...)
814 ::cppu::throwException(excOccurred2);
816 } // leaving the guarded section (getMutex())
818 return xNewExtension;
821 void ExtensionManager::removeExtension(
822 OUString const & identifier, OUString const & fileName,
823 OUString const & repository,
824 Reference<task::XAbortChannel> const & xAbortChannel,
825 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
827 uno::Any excOccurred1;
828 Reference<css::deployment::XPackage> xExtensionBackup;
829 Reference<css::deployment::XPackageManager> xPackageManager;
830 bool bUserDisabled = false;
831 ::osl::MutexGuard guard(m_aMutex);
834 //Determine the repository to use
835 if (repository == "user")
836 xPackageManager = getUserRepository();
837 else if (repository == "shared")
838 xPackageManager = getSharedRepository();
839 else
840 throw lang::IllegalArgumentException(
841 "No valid repository name provided.",
842 static_cast<cppu::OWeakObject*>(this), 0);
844 bUserDisabled = isUserDisabled(identifier, fileName);
845 //Backup the extension, in case the user cancels the action
846 xExtensionBackup = backupExtension(
847 identifier, fileName, xPackageManager, xCmdEnv);
849 //revoke the extension if it is active
850 Reference<css::deployment::XPackage> xOldExtension =
851 xPackageManager->getDeployedPackage(
852 identifier, fileName, xCmdEnv);
853 xOldExtension->revokePackage(false, xAbortChannel, xCmdEnv);
855 xPackageManager->removePackage(
856 identifier, fileName, xAbortChannel, xCmdEnv);
857 activateExtension(identifier, fileName, bUserDisabled, false,
858 xAbortChannel, xCmdEnv);
859 fireModified();
861 catch ( const css::deployment::DeploymentException& ) {
862 excOccurred1 = ::cppu::getCaughtException();
863 } catch ( const ucb::CommandFailedException & ) {
864 excOccurred1 = ::cppu::getCaughtException();
865 } catch ( const ucb::CommandAbortedException & ) {
866 excOccurred1 = ::cppu::getCaughtException();
867 } catch (const lang::IllegalArgumentException &) {
868 excOccurred1 = ::cppu::getCaughtException();
869 } catch (const uno::RuntimeException &) {
870 excOccurred1 = ::cppu::getCaughtException();
871 } catch (...) {
872 excOccurred1 = ::cppu::getCaughtException();
873 css::deployment::DeploymentException exc(
874 "Extension Manager: exception during removeExtension",
875 static_cast<OWeakObject*>(this), excOccurred1);
876 excOccurred1 <<= exc;
879 if (excOccurred1.hasValue())
881 //User aborted installation, restore the previous situation.
882 //Use a private AbortChannel so the user cannot interrupt.
885 Reference<ucb::XCommandEnvironment> tmpCmdEnv(
886 new TmpRepositoryCommandEnv(xCmdEnv->getInteractionHandler()));
887 if (xExtensionBackup.is())
889 xPackageManager->importExtension(
890 xExtensionBackup, Reference<task::XAbortChannel>(),
891 tmpCmdEnv);
892 activateExtension(
893 identifier, fileName, bUserDisabled, false,
894 Reference<task::XAbortChannel>(),
895 tmpCmdEnv);
897 getTmpRepository()->removePackage(
898 dp_misc::getIdentifier(xExtensionBackup),
899 xExtensionBackup->getName(), xAbortChannel, xCmdEnv);
900 fireModified();
903 catch (...)
906 ::cppu::throwException(excOccurred1);
909 if (xExtensionBackup.is())
910 getTmpRepository()->removePackage(
911 dp_misc::getIdentifier(xExtensionBackup),
912 xExtensionBackup->getName(), xAbortChannel, xCmdEnv);
915 // Only enable extensions from shared and user repository
916 void ExtensionManager::enableExtension(
917 Reference<css::deployment::XPackage> const & extension,
918 Reference<task::XAbortChannel> const & xAbortChannel,
919 Reference<ucb::XCommandEnvironment> const & xCmdEnv)
921 ::osl::MutexGuard guard(m_aMutex);
922 bool bUserDisabled = false;
923 uno::Any excOccurred;
926 if (!extension.is())
927 return;
928 OUString repository = extension->getRepositoryName();
929 if (repository != "user")
930 throw lang::IllegalArgumentException(
931 "No valid repository name provided.",
932 static_cast<cppu::OWeakObject*>(this), 0);
934 bUserDisabled = isUserDisabled(dp_misc::getIdentifier(extension),
935 extension->getName());
937 activateExtension(dp_misc::getIdentifier(extension),
938 extension->getName(), false, false,
939 xAbortChannel, xCmdEnv);
941 catch ( const css::deployment::DeploymentException& ) {
942 excOccurred = ::cppu::getCaughtException();
943 } catch ( const ucb::CommandFailedException & ) {
944 excOccurred = ::cppu::getCaughtException();
945 } catch ( const ucb::CommandAbortedException & ) {
946 excOccurred = ::cppu::getCaughtException();
947 } catch (const lang::IllegalArgumentException &) {
948 excOccurred = ::cppu::getCaughtException();
949 } catch (const uno::RuntimeException &) {
950 excOccurred = ::cppu::getCaughtException();
951 } catch (...) {
952 excOccurred = ::cppu::getCaughtException();
953 css::deployment::DeploymentException exc(
954 "Extension Manager: exception during enableExtension",
955 static_cast<OWeakObject*>(this), excOccurred);
956 excOccurred <<= exc;
959 if (!excOccurred.hasValue())
960 return;
964 activateExtension(dp_misc::getIdentifier(extension),
965 extension->getName(), bUserDisabled, false,
966 xAbortChannel, xCmdEnv);
968 catch (...)
971 ::cppu::throwException(excOccurred);
974 sal_Int32 ExtensionManager::checkPrerequisitesAndEnable(
975 Reference<css::deployment::XPackage> const & extension,
976 Reference<task::XAbortChannel> const & xAbortChannel,
977 Reference<ucb::XCommandEnvironment> const & xCmdEnv)
981 if (!extension.is())
982 return 0;
983 ::osl::MutexGuard guard(m_aMutex);
984 sal_Int32 ret = 0;
985 Reference<css::deployment::XPackageManager> mgr =
986 getPackageManager(extension->getRepositoryName());
987 ret = mgr->checkPrerequisites(extension, xAbortChannel, xCmdEnv);
988 if (ret)
990 //There are some unfulfilled prerequisites, try to revoke
991 extension->revokePackage(false, xAbortChannel, xCmdEnv);
993 const OUString id(dp_misc::getIdentifier(extension));
994 activateExtension(id, extension->getName(),
995 isUserDisabled(id, extension->getName()), false,
996 xAbortChannel, xCmdEnv);
997 return ret;
999 catch ( const css::deployment::DeploymentException& ) {
1000 throw;
1001 } catch ( const ucb::CommandFailedException & ) {
1002 throw;
1003 } catch ( const ucb::CommandAbortedException & ) {
1004 throw;
1005 } catch (const lang::IllegalArgumentException &) {
1006 throw;
1007 } catch (const uno::RuntimeException &) {
1008 throw;
1009 } catch (...) {
1010 uno::Any excOccurred = ::cppu::getCaughtException();
1011 css::deployment::DeploymentException exc(
1012 "Extension Manager: exception during disableExtension",
1013 static_cast<OWeakObject*>(this), excOccurred);
1014 throw exc;
1018 void ExtensionManager::disableExtension(
1019 Reference<css::deployment::XPackage> const & extension,
1020 Reference<task::XAbortChannel> const & xAbortChannel,
1021 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1023 ::osl::MutexGuard guard(m_aMutex);
1024 uno::Any excOccurred;
1025 bool bUserDisabled = false;
1028 if (!extension.is())
1029 return;
1030 const OUString repository( extension->getRepositoryName());
1031 if (repository != "user")
1032 throw lang::IllegalArgumentException(
1033 "No valid repository name provided.",
1034 static_cast<cppu::OWeakObject*>(this), 0);
1036 const OUString id(dp_misc::getIdentifier(extension));
1037 bUserDisabled = isUserDisabled(id, extension->getName());
1039 activateExtension(id, extension->getName(), true, false,
1040 xAbortChannel, xCmdEnv);
1042 catch ( const css::deployment::DeploymentException& ) {
1043 excOccurred = ::cppu::getCaughtException();
1044 } catch ( const ucb::CommandFailedException & ) {
1045 excOccurred = ::cppu::getCaughtException();
1046 } catch ( const ucb::CommandAbortedException & ) {
1047 excOccurred = ::cppu::getCaughtException();
1048 } catch (const lang::IllegalArgumentException &) {
1049 excOccurred = ::cppu::getCaughtException();
1050 } catch (const uno::RuntimeException &) {
1051 excOccurred = ::cppu::getCaughtException();
1052 } catch (...) {
1053 excOccurred = ::cppu::getCaughtException();
1054 css::deployment::DeploymentException exc(
1055 "Extension Manager: exception during disableExtension",
1056 static_cast<OWeakObject*>(this), excOccurred);
1057 excOccurred <<= exc;
1060 if (!excOccurred.hasValue())
1061 return;
1065 activateExtension(dp_misc::getIdentifier(extension),
1066 extension->getName(), bUserDisabled, false,
1067 xAbortChannel, xCmdEnv);
1069 catch (...)
1072 ::cppu::throwException(excOccurred);
1075 uno::Sequence< Reference<css::deployment::XPackage> >
1076 ExtensionManager::getDeployedExtensions(
1077 OUString const & repository,
1078 Reference<task::XAbortChannel> const &xAbort,
1079 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1081 return getPackageManager(repository)->getDeployedPackages(
1082 xAbort, xCmdEnv);
1085 Reference<css::deployment::XPackage>
1086 ExtensionManager::getDeployedExtension(
1087 OUString const & repository,
1088 OUString const & identifier,
1089 OUString const & filename,
1090 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1092 return getPackageManager(repository)->getDeployedPackage(
1093 identifier, filename, xCmdEnv);
1096 uno::Sequence< uno::Sequence<Reference<css::deployment::XPackage> > >
1097 ExtensionManager::getAllExtensions(
1098 Reference<task::XAbortChannel> const & xAbort,
1099 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1103 id2extensions mapExt;
1105 uno::Sequence<Reference<css::deployment::XPackage> > userExt =
1106 getUserRepository()->getDeployedPackages(xAbort, xCmdEnv);
1107 addExtensionsToMap(mapExt, userExt, u"user");
1108 uno::Sequence<Reference<css::deployment::XPackage> > sharedExt =
1109 getSharedRepository()->getDeployedPackages(xAbort, xCmdEnv);
1110 addExtensionsToMap(mapExt, sharedExt, u"shared");
1111 uno::Sequence<Reference<css::deployment::XPackage> > bundledExt =
1112 getBundledRepository()->getDeployedPackages(xAbort, xCmdEnv);
1113 addExtensionsToMap(mapExt, bundledExt, u"bundled");
1115 // Create the tmp repository to trigger its clean up (deletion
1116 // of old temporary data.)
1117 getTmpRepository();
1119 //copy the values of the map to a vector for sorting
1120 std::vector< std::vector<Reference<css::deployment::XPackage> > >
1121 vecExtensions;
1122 for (auto const& elem : mapExt)
1123 vecExtensions.push_back(elem.second);
1125 //sort the element according to the identifier
1126 std::sort(vecExtensions.begin(), vecExtensions.end(), CompIdentifiers());
1128 sal_Int32 j = 0;
1129 uno::Sequence< uno::Sequence<Reference<css::deployment::XPackage> > > seqSeq(vecExtensions.size());
1130 auto seqSeqRange = asNonConstRange(seqSeq);
1131 for (auto const& elem : vecExtensions)
1133 seqSeqRange[j++] = comphelper::containerToSequence(elem);
1135 return seqSeq;
1137 } catch ( const css::deployment::DeploymentException& ) {
1138 throw;
1139 } catch ( const ucb::CommandFailedException & ) {
1140 throw;
1141 } catch ( const ucb::CommandAbortedException & ) {
1142 throw;
1143 } catch (const lang::IllegalArgumentException &) {
1144 throw;
1145 } catch (const uno::RuntimeException &) {
1146 throw;
1147 } catch (...) {
1148 uno::Any exc = ::cppu::getCaughtException();
1149 throw css::deployment::DeploymentException(
1150 "Extension Manager: exception during enableExtension",
1151 static_cast<OWeakObject*>(this), exc);
1155 // Only to be called from unopkg or soffice bootstrap (with force=true in the
1156 // latter case):
1157 void ExtensionManager::reinstallDeployedExtensions(
1158 sal_Bool force, OUString const & repository,
1159 Reference<task::XAbortChannel> const & xAbortChannel,
1160 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1164 Reference<css::deployment::XPackageManager>
1165 xPackageManager = getPackageManager(repository);
1167 std::set< OUString > disabledExts;
1169 const uno::Sequence< Reference<css::deployment::XPackage> > extensions(
1170 xPackageManager->getDeployedPackages(xAbortChannel, xCmdEnv));
1171 for ( const Reference<css::deployment::XPackage>& package : extensions )
1175 beans::Optional< beans::Ambiguous< sal_Bool > > registered(
1176 package->isRegistered(xAbortChannel, xCmdEnv));
1177 if (registered.IsPresent &&
1178 !(registered.Value.IsAmbiguous ||
1179 registered.Value.Value))
1181 const OUString id = dp_misc::getIdentifier(package);
1182 OSL_ASSERT(!id.isEmpty());
1183 disabledExts.insert(id);
1186 catch (const lang::DisposedException &)
1192 ::osl::MutexGuard guard(m_aMutex);
1193 xPackageManager->reinstallDeployedPackages(
1194 force, xAbortChannel, xCmdEnv);
1195 //We must sync here, otherwise we will get exceptions when extensions
1196 //are removed.
1197 dp_misc::syncRepositories(force, xCmdEnv);
1198 const uno::Sequence< Reference<css::deployment::XPackage> > extensions(
1199 xPackageManager->getDeployedPackages(xAbortChannel, xCmdEnv));
1201 for ( const Reference<css::deployment::XPackage>& package : extensions )
1205 const OUString id = dp_misc::getIdentifier(package);
1206 const OUString fileName = package->getName();
1207 OSL_ASSERT(!id.isEmpty());
1208 activateExtension(
1209 id, fileName, disabledExts.find(id) != disabledExts.end(),
1210 true, xAbortChannel, xCmdEnv );
1212 catch (const lang::DisposedException &)
1216 } catch ( const css::deployment::DeploymentException& ) {
1217 throw;
1218 } catch ( const ucb::CommandFailedException & ) {
1219 throw;
1220 } catch ( const ucb::CommandAbortedException & ) {
1221 throw;
1222 } catch (const lang::IllegalArgumentException &) {
1223 throw;
1224 } catch (const uno::RuntimeException &) {
1225 throw;
1226 } catch (...) {
1227 uno::Any exc = ::cppu::getCaughtException();
1228 throw css::deployment::DeploymentException(
1229 "Extension Manager: exception during enableExtension",
1230 static_cast<OWeakObject*>(this), exc);
1234 sal_Bool ExtensionManager::synchronize(
1235 Reference<task::XAbortChannel> const & xAbortChannel,
1236 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1240 ::osl::MutexGuard guard(m_aMutex);
1241 OUString sSynchronizingShared(StrSyncRepository());
1242 sSynchronizingShared = sSynchronizingShared.replaceAll("%NAME", "shared");
1243 dp_misc::ProgressLevel progressShared(xCmdEnv, sSynchronizingShared);
1244 bool bModified = getSharedRepository()->synchronize(xAbortChannel, xCmdEnv);
1245 progressShared.update("\n\n");
1247 OUString sSynchronizingBundled(StrSyncRepository());
1248 sSynchronizingBundled = sSynchronizingBundled.replaceAll("%NAME", "bundled");
1249 dp_misc::ProgressLevel progressBundled(xCmdEnv, sSynchronizingBundled);
1250 bModified |= static_cast<bool>(getBundledRepository()->synchronize(xAbortChannel, xCmdEnv));
1251 progressBundled.update("\n\n");
1253 //Always determine the active extension.
1254 //TODO: Is this still necessary? (It used to be necessary for the
1255 // first-start optimization: The setup created the registration data
1256 // for the bundled extensions (share/prereg/bundled) which was copied to
1257 // the user installation when a user started OOo for the first time
1258 // after running setup. All bundled extensions were registered at that
1259 // moment. However, extensions with the same identifier could be in the
1260 // shared or user repository, in which case the respective bundled
1261 // extensions had to be revoked.)
1264 const uno::Sequence<uno::Sequence<Reference<css::deployment::XPackage> > >
1265 seqSeqExt = getAllExtensions(xAbortChannel, xCmdEnv);
1266 for (uno::Sequence<Reference<css::deployment::XPackage> > const & seqExt : seqSeqExt)
1268 activateExtension(seqExt, isUserDisabled(seqExt), true,
1269 xAbortChannel, xCmdEnv);
1272 catch (...)
1274 //We catch the exception, so we can write the lastmodified file
1275 //so we will no repeat this every time OOo starts.
1276 OSL_FAIL("Extensions Manager: synchronize");
1278 OUString lastSyncBundled("$BUNDLED_EXTENSIONS_USER/lastsynchronized");
1279 writeLastModified(lastSyncBundled, xCmdEnv, m_xContext);
1280 OUString lastSyncShared("$SHARED_EXTENSIONS_USER/lastsynchronized");
1281 writeLastModified(lastSyncShared, xCmdEnv, m_xContext);
1282 return bModified;
1283 } catch ( const css::deployment::DeploymentException& ) {
1284 throw;
1285 } catch ( const ucb::CommandFailedException & ) {
1286 throw;
1287 } catch ( const ucb::CommandAbortedException & ) {
1288 throw;
1289 } catch (const lang::IllegalArgumentException &) {
1290 throw;
1291 } catch (const uno::RuntimeException &) {
1292 throw;
1293 } catch (...) {
1294 uno::Any exc = ::cppu::getCaughtException();
1295 throw css::deployment::DeploymentException(
1296 "Extension Manager: exception in synchronize",
1297 static_cast<OWeakObject*>(this), exc);
1301 // Notify the user when a new extension is to be installed. This is only the
1302 // case when one uses the system integration to install an extension (double
1303 // clicking on .oxt file etc.)). The function must only be called if there is no
1304 // extension with the same identifier already deployed. Then the checkUpdate
1305 // function will inform the user that the extension is about to be installed In
1306 // case the user cancels the installation a CommandFailed exception is
1307 // thrown.
1308 void ExtensionManager::checkInstall(
1309 OUString const & displayName,
1310 Reference<ucb::XCommandEnvironment> const & cmdEnv)
1312 uno::Any request(
1313 css::deployment::InstallException(
1314 "Extension " + displayName +
1315 " is about to be installed.",
1316 static_cast<OWeakObject *>(this), displayName));
1317 bool approve = false, abort = false;
1318 if (! dp_misc::interactContinuation(
1319 request, cppu::UnoType<task::XInteractionApprove>::get(),
1320 cmdEnv, &approve, &abort ))
1322 OSL_ASSERT( !approve && !abort );
1323 throw css::deployment::DeploymentException(
1324 DpResId(RID_STR_ERROR_WHILE_ADDING) + displayName,
1325 static_cast<OWeakObject *>(this), request );
1327 if (abort || !approve)
1328 throw ucb::CommandFailedException(
1329 DpResId(RID_STR_ERROR_WHILE_ADDING) + displayName,
1330 static_cast<OWeakObject *>(this), request );
1333 /* The function will make the user interaction in case there is an extension
1334 installed with the same id. This function may only be called if there is already
1335 an extension.
1337 void ExtensionManager::checkUpdate(
1338 OUString const & newVersion,
1339 OUString const & newDisplayName,
1340 Reference<css::deployment::XPackage> const & oldExtension,
1341 Reference<ucb::XCommandEnvironment> const & xCmdEnv )
1343 // package already deployed, interact --force:
1344 uno::Any request(
1345 (css::deployment::VersionException(
1346 DpResId(
1347 RID_STR_PACKAGE_ALREADY_ADDED ) + newDisplayName,
1348 static_cast<OWeakObject *>(this), newVersion, newDisplayName,
1349 oldExtension ) ) );
1350 bool replace = false, abort = false;
1351 if (! dp_misc::interactContinuation(
1352 request, cppu::UnoType<task::XInteractionApprove>::get(),
1353 xCmdEnv, &replace, &abort )) {
1354 OSL_ASSERT( !replace && !abort );
1355 throw css::deployment::DeploymentException(
1356 DpResId(
1357 RID_STR_ERROR_WHILE_ADDING) + newDisplayName,
1358 static_cast<OWeakObject *>(this), request );
1360 if (abort || !replace)
1361 throw ucb::CommandFailedException(
1362 DpResId(
1363 RID_STR_PACKAGE_ALREADY_ADDED) + newDisplayName,
1364 static_cast<OWeakObject *>(this), request );
1367 uno::Sequence<Reference<css::deployment::XPackage> > SAL_CALL
1368 ExtensionManager::getExtensionsWithUnacceptedLicenses(
1369 OUString const & repository,
1370 Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1372 Reference<css::deployment::XPackageManager>
1373 xPackageManager = getPackageManager(repository);
1374 ::osl::MutexGuard guard(m_aMutex);
1375 return xPackageManager->getExtensionsWithUnacceptedLicenses(xCmdEnv);
1378 sal_Bool ExtensionManager::isReadOnlyRepository(OUString const & repository)
1380 return getPackageManager(repository)->isReadOnly();
1384 // XModifyBroadcaster
1386 void ExtensionManager::addModifyListener(
1387 Reference<util::XModifyListener> const & xListener )
1389 check();
1390 rBHelper.addListener( cppu::UnoType<decltype(xListener)>::get(), xListener );
1394 void ExtensionManager::removeModifyListener(
1395 Reference<util::XModifyListener> const & xListener )
1397 check();
1398 rBHelper.removeListener( cppu::UnoType<decltype(xListener)>::get(), xListener );
1401 void ExtensionManager::check()
1403 ::osl::MutexGuard guard( m_aMutex );
1404 if (rBHelper.bInDispose || rBHelper.bDisposed) {
1405 throw lang::DisposedException(
1406 "ExtensionManager instance has already been disposed!",
1407 static_cast<OWeakObject *>(this) );
1411 void ExtensionManager::fireModified()
1413 ::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer(
1414 cppu::UnoType<util::XModifyListener>::get() );
1415 if (pContainer != nullptr) {
1416 pContainer->forEach<util::XModifyListener>(
1417 [this] (uno::Reference<util::XModifyListener> const& xListener)
1418 { return xListener->modified(lang::EventObject(static_cast<OWeakObject *>(this))); });
1422 } // namespace dp_manager
1425 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
1426 com_sun_star_comp_deployment_ExtensionManager_get_implementation(
1427 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
1429 return cppu::acquire(new dp_manager::ExtensionManager(context));
1432 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */