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