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