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