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