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