LibreOffice Module desktop (master)  1
dp_manager.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 #include <config_features.h>
21 
22 #include <dp_interact.h>
23 #include <dp_registry.hxx>
24 #include <dp_shared.hxx>
25 #include <strings.hrc>
26 #include <dp_ucb.h>
27 #include <dp_platform.hxx>
28 #include "dp_manager.h"
29 #include <dp_identifier.hxx>
30 #include <rtl/ustrbuf.hxx>
31 #include <rtl/string.hxx>
32 #include <rtl/uri.hxx>
33 #include <rtl/bootstrap.hxx>
34 #include <sal/log.hxx>
35 #include <tools/urlobj.hxx>
36 #include <tools/diagnose_ex.h>
37 #include <osl/diagnose.h>
38 #include <osl/file.hxx>
39 #include <osl/security.hxx>
40 #include <cppuhelper/exc_hlp.hxx>
41 #include <comphelper/logging.hxx>
42 #include <comphelper/sequence.hxx>
43 #include <xmlscript/xml_helper.hxx>
44 #include <svl/inettype.hxx>
45 #include <com/sun/star/lang/IllegalArgumentException.hpp>
46 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
47 #include <com/sun/star/beans/UnknownPropertyException.hpp>
48 #include <com/sun/star/logging/LogLevel.hpp>
49 #include <com/sun/star/logging/FileHandler.hpp>
50 #include <com/sun/star/logging/SimpleTextFormatter.hpp>
51 #include <com/sun/star/logging/XLogger.hpp>
52 #include <com/sun/star/util/XUpdatable.hpp>
53 #include <com/sun/star/sdbc/XResultSet.hpp>
54 #include <com/sun/star/sdbc/XRow.hpp>
55 #include <com/sun/star/ucb/CommandAbortedException.hpp>
56 #include <com/sun/star/ucb/CommandFailedException.hpp>
57 #include <com/sun/star/ucb/ContentCreationException.hpp>
58 #include <com/sun/star/ucb/XContentAccess.hpp>
59 #include <com/sun/star/ucb/NameClash.hpp>
60 #include <com/sun/star/deployment/DeploymentException.hpp>
61 #include <com/sun/star/deployment/InvalidRemovedParameterException.hpp>
62 #include <com/sun/star/deployment/Prerequisites.hpp>
63 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
64 #include <unotools/tempfile.hxx>
65 
68 #include "dp_properties.hxx"
69 
70 #include <vector>
71 #include <algorithm>
72 
73 using namespace ::dp_misc;
74 using namespace ::com::sun::star;
75 using namespace ::com::sun::star::uno;
76 using namespace ::com::sun::star::ucb;
77 using namespace ::com::sun::star::logging;
78 
79 
80 namespace dp_manager {
81 
82 namespace {
83 
84 struct MatchTempDir
85 {
86  OUString m_str;
87  explicit MatchTempDir( OUString const & str ) : m_str( str ) {}
88  bool operator () ( ActivePackages::Entries::value_type const & v ) const {
89  return v.second.temporaryName.equalsIgnoreAsciiCase( m_str );
90  }
91 };
92 
93 OUString getExtensionFolder(OUString const & parentFolder,
94  Reference<ucb::XCommandEnvironment> const & xCmdEnv,
96 {
97  ::ucbhelper::Content tempFolder( parentFolder, xCmdEnv, xContext );
98  Reference<sdbc::XResultSet> xResultSet(
99  StrTitle::createCursor (tempFolder, ::ucbhelper::INCLUDE_FOLDERS_ONLY ) );
100 
101  OUString title;
102  if (xResultSet->next())
103  {
104  title = Reference<sdbc::XRow>(
105  xResultSet, UNO_QUERY_THROW )->getString(1 /* Title */ ) ;
106  }
107  return title;
108 }
109 }
110 
112  Reference<XCommandEnvironment> const & xCmdEnv )
113 {
114  if (m_activePackages.isEmpty())
115  {
116  OSL_ASSERT( m_registryCache.isEmpty() );
117  // documents temp activation:
118  m_activePackagesDB.reset( new ActivePackages );
119  ::ucbhelper::Content ucbContent;
120  if (create_ucb_content( &ucbContent, m_context, xCmdEnv,
121  false /* no throw */ ))
122  {
123  // scan for all entries in m_packagesDir:
124  Reference<sdbc::XResultSet> xResultSet(
125  StrTitle::createCursor (ucbContent, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) );
126 
127  while (xResultSet->next())
128  {
129  Reference<sdbc::XRow> xRow( xResultSet, UNO_QUERY_THROW );
130  OUString title( xRow->getString( 1 /* Title */ ) );
131  // xxx todo: remove workaround for tdoc
132  if ( title == "this_is_a_dummy_stream_just_there_as_a_workaround_for_a_temporary_limitation_of_the_storage_api_implementation" )
133  continue;
134  if ( title == "META-INF" )
135  continue;
136 
137  ::ucbhelper::Content sourceContent(
138  Reference<XContentAccess>(
139  xResultSet, UNO_QUERY_THROW )->queryContent(),
140  xCmdEnv, m_xComponentContext );
141 
142  OUString mediaType( detectMediaType( sourceContent,
143  false /* no throw */) );
144  if (!mediaType.isEmpty())
145  {
146  ActivePackages::Data dbData;
148  Sequence<css::beans::NamedValue>(),mediaType, sourceContent,
149  title, &dbData );
150 
151  insertToActivationLayerDB( title, dbData );
152  //TODO #i73136#: insertToActivationLayerDB needs id not
153  // title, but the whole m_activePackages.getLength()==0
154  // case (i.e., document-relative deployment) currently
155  // does not work, anyway.
156  }
157  }
158  }
159  }
160  else
161  {
162  // user|share:
163  OSL_ASSERT( !m_activePackages.isEmpty() );
166  if (!m_readOnly)
167  create_folder( nullptr, m_activePackages_expanded, xCmdEnv);
168 
169  OUString dbName;
170  if (m_context == "user")
171  dbName = m_activePackages_expanded + ".pmap";
172  else
173  {
174  // Create the extension data base in the user installation
175  create_folder( nullptr, m_registrationData_expanded, xCmdEnv);
176  dbName = m_registrationData_expanded + "/extensions.pmap";
177  }
178  // The data base can always be written because it is always in the user installation
179  m_activePackagesDB.reset( new ActivePackages( dbName ) );
180 
181  if (! m_readOnly && m_context != "bundled")
182  {
183  // clean up activation layer, scan for zombie temp dirs:
184  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
185 
186  ::ucbhelper::Content tempFolder( m_activePackages_expanded, xCmdEnv, m_xComponentContext );
187  Reference<sdbc::XResultSet> xResultSet(
188  StrTitle::createCursor (tempFolder,
190 
191  // get all temp directories:
192  std::vector<OUString> tempEntries;
193  std::vector<OUString> removedEntries;
194  while (xResultSet->next())
195  {
196  OUString title(
197  Reference<sdbc::XRow>(
198  xResultSet, UNO_QUERY_THROW )->getString(
199  1 /* Title */ ) );
200  if (title.endsWith("removed", &title))
201  {
202  //save the file name without the "removed" part
203  removedEntries.push_back(::rtl::Uri::encode(
204  title, rtl_UriCharClassPchar,
205  rtl_UriEncodeIgnoreEscapes,
206  RTL_TEXTENCODING_UTF8 ) );
207  }
208  else
209  {
210  tempEntries.push_back( ::rtl::Uri::encode(
211  title, rtl_UriCharClassPchar,
212  rtl_UriEncodeIgnoreEscapes,
213  RTL_TEXTENCODING_UTF8 ) );
214  }
215  }
216 
217  bool bShared = (m_context == "shared");
218  for (const OUString & tempEntry : tempEntries)
219  {
220  const MatchTempDir match( tempEntry );
221  if (std::none_of( id2temp.begin(), id2temp.end(), match ))
222  {
223  const OUString url(
224  makeURL(m_activePackages_expanded, tempEntry ) );
225 
226  //In case of shared extensions, new entries are regarded as
227  //added extensions if there is no xxx.tmpremoved file.
228  if (bShared)
229  {
230  if (std::find(removedEntries.begin(), removedEntries.end(), tempEntry) ==
231  removedEntries.end())
232  {
233  continue;
234  }
235  else
236  {
237  //Make sure only the same user removes the extension, who
238  //previously unregistered it. This is avoid races if multiple instances
239  //of OOo are running which all have write access to the shared installation.
240  //For example, a user removes the extension, but keeps OOo
241  //running. Parts of the extension may still be loaded and used by OOo.
242  //Therefore the extension is only deleted the next time the extension manager is
243  //run after restarting OOo. While OOo is still running, another user starts OOo
244  //which would deleted the extension files. If the same user starts another
245  //instance of OOo then the lock file will prevent this.
246  OUString aUserName;
247  ::osl::Security aSecurity;
248  aSecurity.getUserName( aUserName );
249  ucbhelper::Content remFileContent(
251  std::vector<sal_Int8> data = dp_misc::readFile(remFileContent);
252  OString osData(reinterpret_cast<const char*>(data.data()),
253  data.size());
254  OUString sData = OStringToOUString(
255  osData, RTL_TEXTENCODING_UTF8);
256  if (sData != aUserName)
257  continue;
258  }
259  }
260  // temp entry not needed anymore:
261  erase_path( url + "_",
263  false /* no throw: ignore errors */ );
265  false /* no throw: ignore errors */ );
266  //delete the xxx.tmpremoved file
267  erase_path(url + "removed",
269  }
270  }
271  }
272  }
273 }
274 
275 
277 {
278  if (!m_registryCache.isEmpty())
279  create_folder( nullptr, m_registryCache,
284 }
285 
286 namespace {
287 
288 osl::FileBase::RC createDirectory(OUString const & url) {
289  auto e = osl::Directory::create(url);
290  if (e != osl::FileBase::E_NOENT) {
291  return e;
292  }
293  INetURLObject o(url);
294  if (!o.removeSegment()) {
295  return osl::FileBase::E_INVAL; // anything but E_None/E_EXIST
296  }
298  if (e != osl::FileBase::E_None && e != osl::FileBase::E_EXIST) {
299  return e;
300  }
301  return osl::Directory::create(url);
302 }
303 
304 bool isMacroURLReadOnly( const OUString &rMacro )
305 {
306  OUString aDirURL( rMacro );
307  ::rtl::Bootstrap::expandMacros( aDirURL );
308 
309  ::osl::FileBase::RC aErr = createDirectory( aDirURL );
310  if ( aErr == ::osl::FileBase::E_None )
311  return false; // it will be writeable
312  if ( aErr != ::osl::FileBase::E_EXIST )
313  return true; // some serious problem creating it
314 
315  bool bError;
316  sal_uInt64 nWritten = 0;
317  OUString aFileURL( aDirURL + "/stamp.sys" );
318  ::osl::File aFile( aFileURL );
319 
320  bError = aFile.open( osl_File_OpenFlag_Read |
321  osl_File_OpenFlag_Write |
322  osl_File_OpenFlag_Create ) != ::osl::FileBase::E_None;
323  if (!bError)
324  bError = aFile.write( "1", 1, nWritten ) != ::osl::FileBase::E_None;
325  if (aFile.close() != ::osl::FileBase::E_None)
326  bError = true;
327  if (osl::File::remove( aFileURL ) != ::osl::FileBase::E_None)
328  bError = true;
329 
330  SAL_INFO(
331  "desktop.deployment",
332  "local url '" << rMacro << "' -> '" << aFileURL << "' "
333  << (bError ? "is" : "is not") << " readonly\n");
334  return bError;
335 }
336 
337 }
338 
339 Reference<deployment::XPackageManager> PackageManagerImpl::create(
340  Reference<XComponentContext> const & xComponentContext,
341  OUString const & context )
342 {
344  xComponentContext, context );
345 
346  OUString logFile, stamp;
347  if ( context == "user" ) {
348  that->m_activePackages = "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages";
349  that->m_registrationData = "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE";
350  that->m_registryCache = "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/registry";
351  logFile = "$UNO_USER_PACKAGES_CACHE/log.txt";
352  //We use the extension .sys for the file because on Windows Vista a sys
353  //(as well as exe and dll) file
354  //will not be written in the VirtualStore. For example if the process has no
355  //admin right once cannot write to the %programfiles% folder. However, when
356  //virtualization is used, the file will be written into the VirtualStore and
357  //it appears as if one could write to %programfiles%. When we test for write
358  //access to the office/shared folder for shared extensions then this typically
359  //fails because a normal user typically cannot write to this folder. However,
360  //using virtualization it appears that he/she can. Then a shared extension can
361  //be installed but is only visible for the user (because the extension is in
362  //the virtual store).
363  stamp = "$UNO_USER_PACKAGES_CACHE";
364  }
365  else if ( context == "shared" ) {
366  that->m_activePackages = "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/uno_packages";
367  that->m_registrationData = "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER";
368  that->m_registryCache = "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER/registry";
369  logFile = "$SHARED_EXTENSIONS_USER/log.txt";
370 #if !HAVE_FEATURE_READONLY_INSTALLSET
371  // The "shared" extensions are read-only when we have a
372  // read-only installset.
373  stamp = "$UNO_SHARED_PACKAGES_CACHE";
374 #endif
375  }
376  else if ( context == "bundled" ) {
377  that->m_activePackages = "vnd.sun.star.expand:$BUNDLED_EXTENSIONS";
378  that->m_registrationData = "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER";
379  that->m_registryCache = "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER/registry";
380  logFile = "$BUNDLED_EXTENSIONS_USER/log.txt";
381  //No stamp file. We assume that bundled is always readonly. It must not be
382  //modified from ExtensionManager but only by the installer
383  }
384  else if ( context == "tmp" ) {
385  that->m_activePackages = "vnd.sun.star.expand:$TMP_EXTENSIONS/extensions";
386  that->m_registrationData = "vnd.sun.star.expand:$TMP_EXTENSIONS";
387  that->m_registryCache = "vnd.sun.star.expand:$TMP_EXTENSIONS/registry";
388  stamp = "$TMP_EXTENSIONS";
389  }
390  else if (context == "bak") {
391  that->m_activePackages = "vnd.sun.star.expand:$BAK_EXTENSIONS/extensions";
392  that->m_registrationData = "vnd.sun.star.expand:$BAK_EXTENSIONS";
393  that->m_registryCache = "vnd.sun.star.expand:$BAK_EXTENSIONS/registry";
394  stamp = "$BAK_EXTENSIONS";
395  }
396 
397  else if (! context.match("vnd.sun.star.tdoc:/")) {
398  throw lang::IllegalArgumentException(
399  "invalid context given: " + context,
400  Reference<XInterface>(), static_cast<sal_Int16>(-1) );
401  }
402 
404 
405  try {
406  // There is no stamp for the bundled folder:
407  if (!stamp.isEmpty())
408  that->m_readOnly = isMacroURLReadOnly( stamp );
409 
410  if (!that->m_readOnly && !logFile.isEmpty())
411  {
412  // Initialize logger which will be used in ProgressLogImpl (created below)
413  rtl::Bootstrap::expandMacros(logFile);
414  comphelper::EventLogger logger(xComponentContext, "unopkg");
415  const Reference<XLogger> xLogger(logger.getLogger());
416  Reference<XLogFormatter> xLogFormatter(SimpleTextFormatter::create(xComponentContext));
417  Sequence < beans::NamedValue > aSeq2 { { "Formatter", Any(xLogFormatter) }, {"FileURL", Any(logFile)} };
418  Reference<XLogHandler> xFileHandler(css::logging::FileHandler::createWithSettings(xComponentContext, aSeq2));
419  xFileHandler->setLevel(LogLevel::WARNING);
420  xLogger->addLogHandler(xFileHandler);
421 
422  that->m_xLogFile.set(
423  that->m_xComponentContext->getServiceManager()
424  ->createInstanceWithArgumentsAndContext(
425  "com.sun.star.comp.deployment.ProgressLog",
426  Sequence<Any>(),
427  that->m_xComponentContext ),
428  UNO_QUERY_THROW );
429  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv, that->m_xLogFile ) );
430  }
431 
432  that->initRegistryBackends();
433  that->initActivationLayer( xCmdEnv );
434 
435  return that;
436 
437  }
438  catch (const RuntimeException &) {
439  throw;
440  }
441  catch (const Exception & e) {
442  Any exc( ::cppu::getCaughtException() );
443  throw lang::WrappedTargetRuntimeException(
444  ("[context=\"" + context + "\"] caught unexpected "
445  + exc.getValueType().getTypeName() + ": " + e.Message),
446  Reference<XInterface>(), exc );
447  }
448 }
449 
450 
452 {
453 }
454 
455 
457 {
458  ::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer(
460  if (pContainer != nullptr) {
461  pContainer->forEach<util::XModifyListener>(
462  [this] (uno::Reference<util::XModifyListener> const& xListener)
463  { return xListener->modified(lang::EventObject(static_cast<OWeakObject *>(this))); });
464  }
465 }
466 
467 
469 {
470  try {
471 // // xxx todo: guarding?
472 // ::osl::MutexGuard guard( getMutex() );
474  m_xLogFile.clear();
476  m_xRegistry.clear();
477  m_activePackagesDB.reset();
478  m_xComponentContext.clear();
479 
480  t_pm_helper::disposing();
481 
482  }
483  catch (const RuntimeException &) {
484  throw;
485  }
486  catch (const Exception &) {
487  Any exc( ::cppu::getCaughtException() );
488  throw lang::WrappedTargetRuntimeException(
489  "caught unexpected exception while disposing...",
490  static_cast<OWeakObject *>(this), exc );
491  }
492 }
493 
494 // XComponent
495 
497 {
498  //Do not call check here. We must not throw an exception here if the object
499  //is being disposed or is already disposed. See com.sun.star.lang.XComponent
500  WeakComponentImplHelperBase::dispose();
501 }
502 
503 
505  Reference<lang::XEventListener> const & xListener )
506 {
507  //Do not call check here. We must not throw an exception here if the object
508  //is being disposed or is already disposed. See com.sun.star.lang.XComponent
509  WeakComponentImplHelperBase::addEventListener( xListener );
510 }
511 
512 
514  Reference<lang::XEventListener> const & xListener )
515 {
516  //Do not call check here. We must not throw an exception here if the object
517  //is being disposed or is already disposed. See com.sun.star.lang.XComponent
518  WeakComponentImplHelperBase::removeEventListener( xListener );
519 }
520 
521 // XPackageManager
522 
524 {
525  check();
526  return m_context;
527 }
528 
529 
530 Sequence< Reference<deployment::XPackageTypeInfo> >
532 {
533  OSL_ASSERT( m_xRegistry.is() );
534  return m_xRegistry->getSupportedPackageTypes();
535 }
536 
537 
538 Reference<task::XAbortChannel> PackageManagerImpl::createAbortChannel()
539 {
540  check();
541  return new AbortChannel;
542 }
543 
544 // XModifyBroadcaster
545 
547  Reference<util::XModifyListener> const & xListener )
548 {
549  check();
550  rBHelper.addListener( cppu::UnoType<decltype(xListener)>::get(), xListener );
551 }
552 
553 
555  Reference<util::XModifyListener> const & xListener )
556 {
557  check();
558  rBHelper.removeListener( cppu::UnoType<decltype(xListener)>::get(), xListener );
559 }
560 
561 
563  ::ucbhelper::Content const & ucbContent_, bool throw_exc )
564 {
565  ::ucbhelper::Content ucbContent(ucbContent_);
566  OUString url( ucbContent.getURL() );
567  OUString mediaType;
568  if (url.match( "vnd.sun.star.tdoc:" ) || url.match( "vnd.sun.star.pkg:" ))
569  {
570  try {
571  ucbContent.getPropertyValue( "MediaType" ) >>= mediaType;
572  }
573  catch (const beans::UnknownPropertyException &) {
574  }
575  OSL_ENSURE( !mediaType.isEmpty(), "### no media-type?!" );
576  }
577  if (mediaType.isEmpty())
578  {
579  try {
580  Reference<deployment::XPackage> xPackage(
581  m_xRegistry->bindPackage(
582  url, OUString(), false, OUString(), ucbContent.getCommandEnvironment() ) );
583  const Reference<deployment::XPackageTypeInfo> xPackageType(
584  xPackage->getPackageType() );
585  OSL_ASSERT( xPackageType.is() );
586  if (xPackageType.is())
587  mediaType = xPackageType->getMediaType();
588  }
589  catch (const lang::IllegalArgumentException &) {
590  if (throw_exc)
591  throw;
592  css::uno::Any ex( cppu::getCaughtException() );
593  SAL_WARN( "desktop", exceptionToString(ex) );
594  }
595  }
596  return mediaType;
597 }
598 
599 
602  OUString const & mediaType, ::ucbhelper::Content const & sourceContent_,
603  OUString const & title, ActivePackages::Data * dbData )
604 {
605  ::ucbhelper::Content sourceContent(sourceContent_);
607  sourceContent.getCommandEnvironment() );
608 
609  OUString baseDir(m_activePackages_expanded);
610  ::utl::TempFile aTemp(&baseDir, false);
611  OUString tempEntry = aTemp.GetURL();
612  tempEntry = tempEntry.copy(tempEntry.lastIndexOf('/') + 1);
613  OUString destFolder = makeURL( m_activePackages, tempEntry) + "_";
614 
615  // prepare activation folder:
616  ::ucbhelper::Content destFolderContent;
617  create_folder( &destFolderContent, destFolder, xCmdEnv );
618 
619  // copy content into activation temp dir:
620  if (mediaType.matchIgnoreAsciiCase("application/vnd.sun.star.package-bundle") ||
621  // xxx todo: more sophisticated parsing
622  mediaType.matchIgnoreAsciiCase("application/vnd.sun.star.legacy-package-bundle"))
623  {
624  // inflate content:
625  OUStringBuffer buf;
626  if (!sourceContent.isFolder())
627  {
628  buf.append( "vnd.sun.star.zip://" );
629  buf.append( ::rtl::Uri::encode( sourceContent.getURL(),
630  rtl_UriCharClassRegName,
631  rtl_UriEncodeIgnoreEscapes,
632  RTL_TEXTENCODING_UTF8 ) );
633  }
634  else
635  {
636  //Folder. No need to unzip, just copy
637  buf.append(sourceContent.getURL());
638  }
639  buf.append( '/' );
640  sourceContent = ::ucbhelper::Content(
641  buf.makeStringAndClear(), xCmdEnv, m_xComponentContext );
642  }
643  destFolderContent.transferContent(
644  sourceContent, ::ucbhelper::InsertOperation::Copy,
645  title, NameClash::OVERWRITE );
646 
647 
648  // write to DB:
649  //bundled extensions should only be added by the synchronizeAddedExtensions
650  //functions. Moreover, there is no "temporary folder" for bundled extensions.
651  OSL_ASSERT(!(m_context == "bundled"));
652  OUString sFolderUrl = makeURLAppendSysPathSegment(destFolderContent.getURL(), title);
653  DescriptionInfoset info =
654  dp_misc::getDescriptionInfoset(sFolderUrl);
655  dbData->temporaryName = tempEntry;
656  dbData->fileName = title;
657  dbData->mediaType = mediaType;
658  dbData->version = info.getVersion();
659 
660  //No write the properties file next to the extension
661  ExtensionProperties props(sFolderUrl, properties, xCmdEnv, m_xComponentContext);
662  props.write();
663  return destFolder;
664 }
665 
666 
668  OUString const & id, ActivePackages::Data const & dbData )
669 {
670  //access to the database must be guarded. See removePackage
671  const ::osl::MutexGuard guard( getMutex() );
672  m_activePackagesDB->put( id, dbData );
673 }
674 
675 
676 /* The function returns true if there is an extension with the same id already
677  installed which needs to be uninstalled, before the new extension can be installed.
678 */
680  Reference<deployment::XPackage> const & package)
681 {
682  OUString id(dp_misc::getIdentifier(package));
683  OUString fn(package->getName());
684  bool bInstalled = false;
685  if (m_activePackagesDB->has( id, fn ))
686  {
687  bInstalled = true;
688  }
689  return bInstalled;
690 }
691 
692 // XPackageManager
693 
694 Reference<deployment::XPackage> PackageManagerImpl::importExtension(
695  Reference<deployment::XPackage> const & extension,
696  Reference<task::XAbortChannel> const & xAbortChannel,
697  Reference<XCommandEnvironment> const & xCmdEnv_ )
698 {
699  return addPackage(extension->getURL(), Sequence<beans::NamedValue>(),
700  OUString(), xAbortChannel, xCmdEnv_);
701 }
702 
703 /* The function adds an extension but does not register it!!!
704  It may not do any user interaction. This is done in XExtensionManager::addExtension
705 */
706 Reference<deployment::XPackage> PackageManagerImpl::addPackage(
707  OUString const & url,
708  css::uno::Sequence<css::beans::NamedValue> const & properties,
709  OUString const & mediaType_,
710  Reference<task::XAbortChannel> const & xAbortChannel,
711  Reference<XCommandEnvironment> const & xCmdEnv_ )
712 {
713  check();
714  if (m_readOnly)
715  {
716  OUString message;
717  if (m_context == "shared")
718  message = "You need write permissions to install a shared extension!";
719  else
720  message = "You need write permissions to install this extension!";
721  throw deployment::DeploymentException(
722  message, static_cast<OWeakObject *>(this), Any() );
723  }
725  if (m_xLogFile.is())
726  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
727  else
728  xCmdEnv.set( xCmdEnv_ );
729 
730  try {
731  ::ucbhelper::Content sourceContent;
732  (void)create_ucb_content( &sourceContent, url, xCmdEnv ); // throws exc
733  const OUString title( StrTitle::getTitle( sourceContent ) );
734  const OUString title_enc( ::rtl::Uri::encode(
735  title, rtl_UriCharClassPchar,
736  rtl_UriEncodeIgnoreEscapes,
737  RTL_TEXTENCODING_UTF8 ) );
738  OUString destFolder;
739 
740  OUString mediaType(mediaType_);
741  if (mediaType.isEmpty())
742  mediaType = detectMediaType( sourceContent );
743 
744  Reference<deployment::XPackage> xPackage;
745  // copy file:
747  DpResId(RID_STR_COPYING_PACKAGE) + title, xCmdEnv );
748  if (m_activePackages.isEmpty())
749  {
750  ::ucbhelper::Content docFolderContent;
751  create_folder( &docFolderContent, m_context, xCmdEnv );
752  // copy into document, first:
753  docFolderContent.transferContent(
754  sourceContent, ::ucbhelper::InsertOperation::Copy,
755  OUString(),
756  NameClash::ASK /* xxx todo: ASK not needed? */);
757  // set media-type:
758  ::ucbhelper::Content docContent(
759  makeURL( m_context, title_enc ), xCmdEnv, m_xComponentContext );
760  //TODO #i73136#: using title instead of id can lead to
761  // clashes, but the whole m_activePackages.getLength()==0
762  // case (i.e., document-relative deployment) currently does
763  // not work, anyway.
764  docContent.setPropertyValue("MediaType", Any(mediaType) );
765 
766  // xxx todo: obsolete in the future
767  try {
768  docFolderContent.executeCommand( "flush", Any() );
769  }
770  catch (const UnsupportedCommandException &) {
771  }
772  }
773  ActivePackages::Data dbData;
774  destFolder = insertToActivationLayer(
775  properties, mediaType, sourceContent, title, &dbData );
776 
777 
778  // bind activation package:
779  //Because every shared/user extension will be unpacked in a folder,
780  //which was created with a unique name we will always have two different
781  //XPackage objects, even if the second extension is the same.
782  //Therefore bindPackage does not need a guard here.
783  xPackage = m_xRegistry->bindPackage(
784  makeURL( destFolder, title_enc ), mediaType, false, OUString(), xCmdEnv );
785 
786  OSL_ASSERT( xPackage.is() );
787  if (xPackage.is())
788  {
789  bool install = false;
790  try
791  {
792  OUString const id = dp_misc::getIdentifier( xPackage );
793 
794  ::osl::MutexGuard g(m_addMutex);
795  if (isInstalled(xPackage))
796  {
797  //Do not guard the complete function with the getMutex
798  removePackage(id, xPackage->getName(), xAbortChannel,
799  xCmdEnv);
800  }
801  install = true;
802  insertToActivationLayerDB(id, dbData);
803  }
804  catch (...)
805  {
806  deletePackageFromCache( xPackage, destFolder );
807  throw;
808  }
809  if (!install)
810  {
811  deletePackageFromCache( xPackage, destFolder );
812  }
813  //ToDo: We should notify only if the extension is registered
814  fireModified();
815  }
816  return xPackage;
817  }
818  catch (const RuntimeException &) {
819  throw;
820  }
821  catch (const CommandFailedException & exc) {
822  logIntern( Any(exc) );
823  throw;
824  }
825  catch (const CommandAbortedException & exc) {
826  logIntern( Any(exc) );
827  throw;
828  }
829  catch (const deployment::DeploymentException & exc) {
830  logIntern( Any(exc) );
831  throw;
832  }
833  catch (const Exception &) {
834  Any exc( ::cppu::getCaughtException() );
835  logIntern( exc );
836  throw deployment::DeploymentException(
837  DpResId(RID_STR_ERROR_WHILE_ADDING) + url,
838  static_cast<OWeakObject *>(this), exc );
839  }
840 }
842  Reference<deployment::XPackage> const & xPackage,
843  OUString const & destFolder)
844 {
845  try_dispose( xPackage );
846 
847  //we remove the package from the uno cache
848  //no service from the package may be loaded at this time!!!
850  false /* no throw: ignore errors */ );
851  //rm last character '_'
852  OUString url = destFolder.copy(0, destFolder.getLength() - 1);
854  false /* no throw: ignore errors */ );
855 
856 }
857 
859  OUString const & id, OUString const & fileName,
860  Reference<task::XAbortChannel> const & /*xAbortChannel*/,
861  Reference<XCommandEnvironment> const & xCmdEnv_ )
862 {
863  check();
864 
866  if (m_xLogFile.is())
867  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
868  else
869  xCmdEnv.set( xCmdEnv_ );
870 
871  try {
872  Reference<deployment::XPackage> xPackage;
873  {
874  const ::osl::MutexGuard guard(getMutex());
875  //Check if this extension exist and throw an IllegalArgumentException
876  //if it does not
877  //If the files of the extension are already removed, or there is a
878  //different extension at the same place, for example after updating the
879  //extension, then the returned object is that which uses the database data.
880  xPackage = getDeployedPackage_(id, fileName, xCmdEnv );
881 
882 
883  //Because the extension is only removed the next time the extension
884  //manager runs after restarting OOo, we need to indicate that a
885  //shared extension was "deleted". When a user starts OOo, then it
886  //will check if something changed in the shared repository. Based on
887  //the flag file it will then recognize, that the extension was
888  //deleted and can then update the extension database of the shared
889  //extensions in the user installation.
890  if ( xPackage.is() && !m_readOnly && !xPackage->isRemoved() && (m_context == "shared"))
891  {
893  m_activePackagesDB->get( & val, id, fileName);
894  OSL_ASSERT(!val.temporaryName.isEmpty());
895  OUString url(makeURL(m_activePackages_expanded,
896  val.temporaryName + "removed"));
897  ::ucbhelper::Content contentRemoved(url, xCmdEnv, m_xComponentContext);
898  OUString aUserName;
899  ::osl::Security aSecurity;
900  aSecurity.getUserName( aUserName );
901 
902  OString stamp = OUStringToOString(aUserName, RTL_TEXTENCODING_UTF8);
903  Reference<css::io::XInputStream> xData(
905  reinterpret_cast<sal_Int8 const *>(stamp.getStr()),
906  stamp.getLength() ) );
907  contentRemoved.writeStream( xData, true /* replace existing */ );
908  }
909  m_activePackagesDB->erase( id, fileName ); // to be removed upon next start
910  //remove any cached data hold by the backend
911  m_xRegistry->packageRemoved(xPackage->getURL(), xPackage->getPackageType()->getMediaType());
912  }
913  try_dispose( xPackage );
914 
915  fireModified();
916  }
917  catch (const RuntimeException &) {
918  throw;
919  }
920  catch (const CommandFailedException & exc) {
921  logIntern( Any(exc) );
922  throw;
923  }
924  catch (const CommandAbortedException & exc) {
925  logIntern( Any(exc) );
926  throw;
927  }
928  catch (const deployment::DeploymentException & exc) {
929  logIntern( Any(exc) );
930  throw;
931  }
932  catch (const Exception &) {
933  Any exc( ::cppu::getCaughtException() );
934  logIntern( exc );
935  throw deployment::DeploymentException(
936  DpResId(RID_STR_ERROR_WHILE_REMOVING) + id,
937  static_cast<OWeakObject *>(this), exc );
938  }
939 }
940 
941 
943 {
944  OUStringBuffer buf;
945  buf.append( data.temporaryName );
946  //The bundled extensions are not contained in an additional folder
947  //with a unique name. data.temporaryName contains already the
948  //UTF8 encoded folder name. See PackageManagerImpl::synchronize
949  if (m_context != "bundled")
950  {
951  buf.append( "_/" );
952  buf.append( ::rtl::Uri::encode( data.fileName, rtl_UriCharClassPchar,
953  rtl_UriEncodeIgnoreEscapes,
954  RTL_TEXTENCODING_UTF8 ) );
955  }
956  return makeURL( m_activePackages, buf.makeStringAndClear() );
957 }
958 
959 
960 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
961  OUString const & id, OUString const & fileName,
962  Reference<XCommandEnvironment> const & xCmdEnv )
963 {
965  if (m_activePackagesDB->get( &val, id, fileName ))
966  {
967  return getDeployedPackage_( id, val, xCmdEnv );
968  }
969  throw lang::IllegalArgumentException(
970  DpResId(RID_STR_NO_SUCH_PACKAGE) + id,
971  static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
972 }
973 
974 
975 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
976  std::u16string_view id, ActivePackages::Data const & data,
977  Reference<XCommandEnvironment> const & xCmdEnv, bool ignoreAlienPlatforms )
978 {
979  if (ignoreAlienPlatforms)
980  {
981  OUString type, subType;
983  if (INetContentTypes::parse( data.mediaType, type, subType, &params ))
984  {
985  auto const iter = params.find(OString("platform"));
986  if (iter != params.end() && !platform_fits(iter->second.m_sValue))
987  throw lang::IllegalArgumentException(
988  DpResId(RID_STR_NO_SUCH_PACKAGE) + id,
989  static_cast<OWeakObject *>(this),
990  static_cast<sal_Int16>(-1) );
991  }
992  }
993  Reference<deployment::XPackage> xExtension;
994  try
995  {
996  //Ignore extensions where XPackage::checkPrerequisites failed.
997  //They must not be usable for this user.
998  if (data.failedPrerequisites == "0")
999  {
1000  xExtension = m_xRegistry->bindPackage(
1001  getDeployPath( data ), data.mediaType, false, OUString(), xCmdEnv );
1002  }
1003  }
1004  catch (const deployment::InvalidRemovedParameterException& e)
1005  {
1006  xExtension = e.Extension;
1007  }
1008  return xExtension;
1009 }
1010 
1011 
1012 Sequence< Reference<deployment::XPackage> >
1014  Reference<XCommandEnvironment> const & xCmdEnv )
1015 {
1016  std::vector< Reference<deployment::XPackage> > packages;
1017  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1018  for (auto const& elem : id2temp)
1019  {
1020  if (elem.second.failedPrerequisites != "0")
1021  continue;
1022  try {
1023  packages.push_back(
1025  elem.first, elem.second, xCmdEnv,
1026  true /* xxx todo: think of GUI:
1027  ignore other platforms than the current one */ ) );
1028  }
1029  catch (const lang::IllegalArgumentException &) {
1030  // ignore
1031  TOOLS_WARN_EXCEPTION( "desktop", "" );
1032  }
1033  catch (const deployment::DeploymentException&) {
1034  // ignore
1035  TOOLS_WARN_EXCEPTION( "desktop", "" );
1036  }
1037  }
1038  return comphelper::containerToSequence(packages);
1039 }
1040 
1041 
1042 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage(
1043  OUString const & id, OUString const & fileName,
1044  Reference<XCommandEnvironment> const & xCmdEnv_ )
1045 {
1046  check();
1048  if (m_xLogFile.is())
1049  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1050  else
1051  xCmdEnv.set( xCmdEnv_ );
1052 
1053  try {
1054  const ::osl::MutexGuard guard( getMutex() );
1055  return getDeployedPackage_( id, fileName, xCmdEnv );
1056  }
1057  catch (const RuntimeException &) {
1058  throw;
1059  }
1060  catch (const CommandFailedException & exc) {
1061  logIntern( Any(exc) );
1062  throw;
1063  }
1064  catch (const deployment::DeploymentException & exc) {
1065  logIntern( Any(exc) );
1066  throw;
1067  }
1068  catch (const Exception &) {
1069  Any exc( ::cppu::getCaughtException() );
1070  logIntern( exc );
1071  throw deployment::DeploymentException(
1072  // ought never occur...
1073  "error while accessing deployed package: " + id,
1074  static_cast<OWeakObject *>(this), exc );
1075  }
1076 }
1077 
1078 
1079 Sequence< Reference<deployment::XPackage> >
1081  Reference<task::XAbortChannel> const &,
1082  Reference<XCommandEnvironment> const & xCmdEnv_ )
1083 {
1084  check();
1086  if (m_xLogFile.is())
1087  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1088  else
1089  xCmdEnv.set( xCmdEnv_ );
1090 
1091  try {
1092  const ::osl::MutexGuard guard( getMutex() );
1093  return getDeployedPackages_( xCmdEnv );
1094  }
1095  catch (const RuntimeException &) {
1096  throw;
1097  }
1098  catch (const CommandFailedException & exc) {
1099  logIntern( Any(exc) );
1100  throw;
1101  }
1102  catch (const CommandAbortedException & exc) {
1103  logIntern( Any(exc) );
1104  throw;
1105  }
1106  catch (const deployment::DeploymentException & exc) {
1107  logIntern( Any(exc) );
1108  throw;
1109  }
1110  catch (const Exception &) {
1111  Any exc( ::cppu::getCaughtException() );
1112  logIntern( exc );
1113  throw deployment::DeploymentException(
1114  // ought never occur...
1115  "error while getting all deployed packages: " + m_context,
1116  static_cast<OWeakObject *>(this), exc );
1117  }
1118 }
1119 
1120 
1121 //ToDo: the function must not call registerPackage, do this in
1122 //XExtensionManager.reinstallDeployedExtensions
1124  sal_Bool force, Reference<task::XAbortChannel> const & /*xAbortChannel*/,
1125  Reference<XCommandEnvironment> const & xCmdEnv_ )
1126 {
1127  check();
1128  if (!force && office_is_running())
1129  throw RuntimeException(
1130  "You must close any running Office process before reinstalling packages!",
1131  static_cast<OWeakObject *>(this) );
1132 
1134  if (m_xLogFile.is())
1135  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1136  else
1137  xCmdEnv.set( xCmdEnv_ );
1138 
1139  try {
1140  ProgressLevel progress(
1141  xCmdEnv, "Reinstalling all deployed packages..." );
1142 
1144  m_xRegistry.clear();
1145  if (!m_registryCache.isEmpty())
1146  erase_path( m_registryCache, xCmdEnv );
1148  Reference<util::XUpdatable> xUpdatable( m_xRegistry, UNO_QUERY );
1149  if (xUpdatable.is())
1150  xUpdatable->update();
1151 
1152  //registering is done by the ExtensionManager service.
1153  }
1154  catch (const RuntimeException &) {
1155  throw;
1156  }
1157  catch (const CommandFailedException & exc) {
1158  logIntern( Any(exc) );
1159  throw;
1160  }
1161  catch (const CommandAbortedException & exc) {
1162  logIntern( Any(exc) );
1163  throw;
1164  }
1165  catch (const deployment::DeploymentException & exc) {
1166  logIntern( Any(exc) );
1167  throw;
1168  }
1169  catch (const Exception &) {
1170  Any exc( ::cppu::getCaughtException() );
1171  logIntern( exc );
1172  throw deployment::DeploymentException(
1173  "Error while reinstalling all previously deployed packages of context " + m_context,
1174  static_cast<OWeakObject *>(this), exc );
1175  }
1176 }
1177 
1178 
1180 {
1181  return m_readOnly;
1182 }
1184  Reference<task::XAbortChannel> const & xAbortChannel,
1186 {
1187 
1188  //find all which are in the extension data base but which
1189  //are removed already.
1190  OSL_ASSERT(!(m_context == "user"));
1191  bool bModified = false;
1192  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1193 
1194  bool bShared = (m_context == "shared");
1195 
1196  for (auto const& elem : id2temp)
1197  {
1198  try
1199  {
1200  //Get the URL to the extensions folder, first make the url for the
1201  //shared repository including the temporary name
1202  OUString url = makeURL(m_activePackages, elem.second.temporaryName);
1203  if (bShared)
1204  url = makeURLAppendSysPathSegment( url + "_", elem.second.fileName);
1205 
1206  bool bRemoved = false;
1207  //Check if the URL to the extension is still the same
1208  ::ucbhelper::Content contentExtension;
1209 
1210  if (!create_ucb_content(
1211  &contentExtension, url,
1213  {
1214  bRemoved = true;
1215  }
1216 
1217  //The folder is in the extension database, but it can still be deleted.
1218  //look for the xxx.tmpremoved file
1219  //There can also be the case that a different extension was installed
1220  //in a "temp" folder with name that is already used.
1221  if (!bRemoved && bShared)
1222  {
1223  ::ucbhelper::Content contentRemoved;
1224 
1225  if (create_ucb_content(
1226  &contentRemoved,
1228  elem.second.temporaryName + "removed",
1230  {
1231  bRemoved = true;
1232  }
1233  }
1234 
1235  if (!bRemoved)
1236  {
1237  //There may be another extensions at the same place
1238  dp_misc::DescriptionInfoset infoset =
1240  OSL_ENSURE(infoset.hasDescription() && infoset.getIdentifier(),
1241  "Extension Manager: bundled and shared extensions "
1242  "must have an identifier and a version");
1243  if (infoset.hasDescription() &&
1244  infoset.getIdentifier() &&
1245  ( elem.first != *(infoset.getIdentifier())
1246  || elem.second.version != infoset.getVersion()))
1247  {
1248  bRemoved = true;
1249  }
1250 
1251  }
1252  if (bRemoved)
1253  {
1254  Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1255  url, elem.second.mediaType, true, elem.first, xCmdEnv );
1256  OSL_ASSERT(xPackage.is()); //Even if the files are removed, we must get the object.
1257  xPackage->revokePackage(true, xAbortChannel, xCmdEnv);
1258  removePackage(xPackage->getIdentifier().Value, xPackage->getName(),
1259  xAbortChannel, xCmdEnv);
1260  bModified = true;
1261  }
1262  }
1263  catch( const uno::Exception & )
1264  {
1265  TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1266  }
1267  }
1268  return bModified;
1269 }
1270 
1271 
1273  Reference<task::XAbortChannel> const & xAbortChannel,
1275 {
1276  bool bModified = false;
1277  OSL_ASSERT(!(m_context == "user"));
1278 
1279  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1280  //check if the folder exist at all. The shared extension folder
1281  //may not exist for a normal user.
1282  bool bOk=true;
1283  try
1284  {
1285  bOk = create_ucb_content(
1287  }
1288  catch (const css::ucb::ContentCreationException&)
1289  {
1290  bOk = false;
1291  }
1292 
1293  if (!bOk)
1294  return bModified;
1295 
1297  Reference<sdbc::XResultSet> xResultSet(
1298  StrTitle::createCursor( tempFolder,
1300 
1301  while (xResultSet->next())
1302  {
1303  try
1304  {
1305  OUString title(
1306  Reference<sdbc::XRow>(
1307  xResultSet, UNO_QUERY_THROW )->getString(
1308  1 /* Title */ ) );
1309  //The temporary folders of user and shared have an '_' at then end.
1310  //But the name in ActivePackages.temporaryName is saved without.
1311  OUString title2 = title;
1312  bool bShared = (m_context == "shared");
1313  if (bShared)
1314  {
1315  OSL_ASSERT(title2.endsWith("_"));
1316  title2 = title2.copy(0, title2.getLength() -1);
1317  }
1318  OUString titleEncoded = ::rtl::Uri::encode(
1319  title2, rtl_UriCharClassPchar,
1320  rtl_UriEncodeIgnoreEscapes,
1321  RTL_TEXTENCODING_UTF8);
1322 
1323  //It is sufficient to check for the folder name, because when the administrator
1324  //installed the extension it was already checked if there is one with the
1325  //same identifier.
1326  const MatchTempDir match(titleEncoded);
1327  if (std::none_of( id2temp.begin(), id2temp.end(), match ))
1328  {
1329 
1330  // The folder was not found in the data base, so it must be
1331  // an added extension
1332  OUString url(m_activePackages_expanded + "/" + titleEncoded);
1333  OUString sExtFolder;
1334  if (bShared) //that is, shared
1335  {
1336  //Check if the extension was not "deleted" already which is indicated
1337  //by a xxx.tmpremoved file
1338  ::ucbhelper::Content contentRemoved;
1339  if (create_ucb_content(&contentRemoved, url + "removed",
1341  continue;
1342  sExtFolder = getExtensionFolder(
1343  m_activePackages_expanded + "/" + titleEncoded + "_",
1344  xCmdEnv, m_xComponentContext);
1346  url = makeURLAppendSysPathSegment(url, sExtFolder);
1347  }
1348  Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1349  url, OUString(), false, OUString(), xCmdEnv );
1350  if (xPackage.is())
1351  {
1352  OUString id = dp_misc::getIdentifier( xPackage );
1353 
1354  //Prepare the database entry
1355  ActivePackages::Data dbData;
1356 
1357  dbData.temporaryName = titleEncoded;
1358  if (bShared)
1359  dbData.fileName = sExtFolder;
1360  else
1361  dbData.fileName = title;
1362  dbData.mediaType = xPackage->getPackageType()->getMediaType();
1363  dbData.version = xPackage->getVersion();
1364  SAL_WARN_IF(
1365  dbData.version.isEmpty(), "desktop.deployment",
1366  "bundled/shared extension " << id << " at <" << url
1367  << "> has no explicit version");
1368 
1369  //We provide a special command environment that will prevent
1370  //showing a license if simple-license/@accept-by = "admin"
1371  //It will also prevent showing the license for bundled extensions
1372  //which is not supported.
1373  OSL_ASSERT(!(m_context == "user"));
1374 
1375  // shall the license be suppressed?
1376  DescriptionInfoset info =
1378  ::std::optional<dp_misc::SimpleLicenseAttributes>
1379  attr = info.getSimpleLicenseAttributes();
1381  bool bNoLicense = false;
1382  if (attr && attr->suppressIfRequired && props.isSuppressedLicense())
1383  bNoLicense = true;
1384 
1385  Reference<ucb::XCommandEnvironment> licCmdEnv(
1386  new LicenseCommandEnv(xCmdEnv->getInteractionHandler(),
1387  bNoLicense, m_context));
1388  sal_Int32 failedPrereq = xPackage->checkPrerequisites(
1389  xAbortChannel, licCmdEnv, false);
1390  //Remember that this failed. For example, the user
1391  //could have declined the license. Then the next time the
1392  //extension folder is investigated we do not want to
1393  //try to install the extension again.
1394  dbData.failedPrerequisites = OUString::number(failedPrereq);
1395  insertToActivationLayerDB(id, dbData);
1396  bModified = true;
1397  }
1398  }
1399  }
1400  catch (const uno::Exception &)
1401  {
1402  // Looks like exceptions being caught here is not an uncommon case.
1403  TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1404  }
1405  }
1406  return bModified;
1407 }
1408 
1410  Reference<task::XAbortChannel> const & xAbortChannel,
1412 {
1413  check();
1414  bool bModified = false;
1415  if (m_context == "user")
1416  return bModified;
1417  bModified |=
1418  synchronizeRemovedExtensions(xAbortChannel, xCmdEnv);
1419  bModified |= synchronizeAddedExtensions(xAbortChannel, xCmdEnv);
1420 
1421  return bModified;
1422 }
1423 
1424 Sequence< Reference<deployment::XPackage> > PackageManagerImpl::getExtensionsWithUnacceptedLicenses(
1425  Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1426 {
1427  std::vector<Reference<deployment::XPackage> > vec;
1428 
1429  try
1430  {
1431  const ::osl::MutexGuard guard( getMutex() );
1432  // clean up activation layer, scan for zombie temp dirs:
1433  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1434 
1435  bool bShared = (m_context == "shared");
1436 
1437  for (auto const& elem : id2temp)
1438  {
1439  //Get the database entry
1440  ActivePackages::Data const & dbData = elem.second;
1441  sal_Int32 failedPrereq = dbData.failedPrerequisites.toInt32();
1442  //If the installation failed for other reason then the license then we
1443  //ignore it.
1444  if (failedPrereq ^ deployment::Prerequisites::LICENSE)
1445  continue;
1446 
1447  //Prepare the URL to the extension
1448  OUString url = makeURL(m_activePackages, elem.second.temporaryName);
1449  if (bShared)
1450  url = makeURLAppendSysPathSegment( url + "_", elem.second.fileName);
1451 
1452  Reference<deployment::XPackage> p = m_xRegistry->bindPackage(
1453  url, OUString(), false, OUString(), xCmdEnv );
1454 
1455  if (p.is())
1456  vec.push_back(p);
1457 
1458  }
1459  return ::comphelper::containerToSequence(vec);
1460  }
1461  catch (const deployment::DeploymentException &)
1462  {
1463  throw;
1464  }
1465  catch (const RuntimeException&)
1466  {
1467  throw;
1468  }
1469  catch (...)
1470  {
1471  Any exc = ::cppu::getCaughtException();
1472  deployment::DeploymentException de(
1473  "PackageManagerImpl::getExtensionsWithUnacceptedLicenses",
1474  static_cast<OWeakObject*>(this), exc);
1475  exc <<= de;
1476  ::cppu::throwException(exc);
1477  }
1478 
1479  return ::comphelper::containerToSequence(vec);
1480 }
1481 
1483  css::uno::Reference<css::deployment::XPackage> const & extension,
1484  css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel,
1485  css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv )
1486 {
1487  try
1488  {
1489  if (!extension.is())
1490  return 0;
1491  if (m_context != extension->getRepositoryName())
1492  throw lang::IllegalArgumentException(
1493  "PackageManagerImpl::checkPrerequisites: extension is not from this repository.",
1494  nullptr, 0);
1495 
1496  ActivePackages::Data dbData;
1497  OUString id = dp_misc::getIdentifier(extension);
1498  if (!m_activePackagesDB->get( &dbData, id, OUString()))
1499  {
1500  throw lang::IllegalArgumentException(
1501  "PackageManagerImpl::checkPrerequisites: unknown extension",
1502  nullptr, 0);
1503 
1504  }
1505  //If the license was already displayed, then do not show it again
1506  Reference<ucb::XCommandEnvironment> _xCmdEnv = xCmdEnv;
1507  sal_Int32 prereq = dbData.failedPrerequisites.toInt32();
1508  if ( !(prereq & deployment::Prerequisites::LICENSE))
1509  _xCmdEnv = new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler());
1510 
1511  sal_Int32 failedPrereq = extension->checkPrerequisites(
1512  xAbortChannel, _xCmdEnv, false);
1513  dbData.failedPrerequisites = OUString::number(failedPrereq);
1514  insertToActivationLayerDB(id, dbData);
1515  return 0;
1516  }
1517  catch ( const deployment::DeploymentException& ) {
1518  throw;
1519  } catch ( const ucb::CommandFailedException & ) {
1520  throw;
1521  } catch ( const ucb::CommandAbortedException & ) {
1522  throw;
1523  } catch (const lang::IllegalArgumentException &) {
1524  throw;
1525  } catch (const uno::RuntimeException &) {
1526  throw;
1527  } catch (...) {
1528  uno::Any excOccurred = ::cppu::getCaughtException();
1529  deployment::DeploymentException exc(
1530  "PackageManagerImpl::checkPrerequisites: exception ",
1531  static_cast<OWeakObject*>(this), excOccurred);
1532  throw exc;
1533  }
1534 }
1535 
1536 
1538 {
1539 }
1540 
1541 
1543  Reference<XCommandEnvironment> const & xUserCmdEnv,
1544  Reference<XProgressHandler> const & xLogFile )
1545  : m_xLogFile( xLogFile )
1546 {
1547  if (xUserCmdEnv.is()) {
1548  m_xUserProgress.set( xUserCmdEnv->getProgressHandler() );
1549  m_xUserInteractionHandler.set( xUserCmdEnv->getInteractionHandler() );
1550  }
1551 }
1552 
1553 // XCommandEnvironment
1554 
1555 Reference<task::XInteractionHandler>
1557 {
1558  return m_xUserInteractionHandler;
1559 }
1560 
1561 
1564 {
1565  return this;
1566 }
1567 
1568 // XProgressHandler
1569 
1571 {
1572  if (m_xLogFile.is())
1573  m_xLogFile->push( Status );
1574  if (m_xUserProgress.is())
1575  m_xUserProgress->push( Status );
1576 }
1577 
1578 
1580 {
1581  if (m_xLogFile.is())
1582  m_xLogFile->update( Status );
1583  if (m_xUserProgress.is())
1584  m_xUserProgress->update( Status );
1585 }
1586 
1587 
1589 {
1590  if (m_xLogFile.is())
1591  m_xLogFile->pop();
1592  if (m_xUserProgress.is())
1593  m_xUserProgress->pop();
1594 }
1595 
1596 } // namespace dp_manager
1597 
1598 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::osl::Mutex & getMutex() const
Definition: dp_misc.h:43
virtual void SAL_CALL dispose() override
Definition: dp_manager.cxx:496
virtual void SAL_CALL reinstallDeployedPackages(sal_Bool force, css::uno::Reference< css::task::XAbortChannel > const &xAbortChannel, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv) override
INCLUDE_FOLDERS_AND_DOCUMENTS
const css::uno::Reference< css::logging::XLogger > & getLogger() const
void progressUpdate(OUString const &status, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv)
Definition: dp_interact.h:32
virtual css::uno::Reference< css::task::XAbortChannel > SAL_CALL createAbortChannel() override
Definition: dp_manager.cxx:538
css::uno::Reference< css::deployment::XPackageRegistry > m_xRegistry
Definition: dp_manager.h:56
virtual sal_Int32 SAL_CALL checkPrerequisites(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
exports com.sun.star. packages
virtual ~PackageManagerImpl() override
Definition: dp_manager.cxx:451
void logIntern(css::uno::Any const &status)
Definition: dp_manager.h:224
virtual ::sal_Bool SAL_CALL synchronize(css::uno::Reference< css::task::XAbortChannel > const &xAbortChannel, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv) override
css::uno::Any getPropertyValue(const OUString &rPropertyName)
virtual void SAL_CALL removeEventListener(css::uno::Reference< css::lang::XEventListener > const &xListener) override
Definition: dp_manager.cxx:513
bool office_is_running()
Definition: dp_misc.cxx:331
OUString makeURL(OUString const &baseURL, OUString const &relPath_)
appends a relative path to a url.
Definition: dp_misc.cxx:249
OUString makeURLAppendSysPathSegment(OUString const &baseURL, OUString const &segment)
appends a relative path to a url.
Definition: dp_misc.cxx:279
OUString detectMediaType(::ucbhelper::Content const &ucbContent, bool throw_exc=true)
Definition: dp_manager.cxx:562
css::uno::Reference< css::deployment::XPackageRegistry > create(css::uno::Reference< css::deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
virtual void SAL_CALL removePackage(OUString const &id, OUString const &fileName, css::uno::Reference< css::task::XAbortChannel > const &xAbortChannel, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv) override
Definition: dp_manager.cxx:858
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC std::vector< sal_Int8 > readFile(::ucbhelper::Content &ucb_content)
Definition: dp_ucb.cxx:189
static bool parse(OUString const &rMediaType, OUString &rType, OUString &rSubType, INetContentTypeParameterList *pParameters=nullptr)
bool match(const sal_Unicode *pWild, const sal_Unicode *pStr, const sal_Unicode cEscape)
OUString getVersion() const
Return the textual version representation.
static void deletePackageFromCache(css::uno::Reference< css::deployment::XPackage > const &xPackage, OUString const &destFolder)
Definition: dp_manager.cxx:841
Any SAL_CALL getCaughtException()
OUString m_str
Definition: dp_manager.cxx:86
std::vector< std::pair< OUString, Data > > Entries
void insertToActivationLayerDB(OUString const &id, ActivePackages::Data const &dbData)
Definition: dp_manager.cxx:667
virtual css::uno::Sequence< css::uno::Reference< css::deployment::XPackage > > SAL_CALL getDeployedPackages(css::uno::Reference< css::task::XAbortChannel > const &xAbortChannel, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv) override
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
virtual ::sal_Bool SAL_CALL isReadOnly() override
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC DescriptionInfoset getDescriptionInfoset(std::u16string_view sExtensionFolderURL)
creates a DescriptionInfoset object.
std::unique_ptr< ActivePackages > m_activePackagesDB
Definition: dp_manager.h:49
const css::uno::Reference< css::ucb::XCommandEnvironment > & getCommandEnvironment() const
css::uno::Reference< css::task::XInteractionHandler > m_xUserInteractionHandler
Definition: dp_manager.h:93
virtual void SAL_CALL push(css::uno::Any const &Status) override
Reference< io::XInputStream > createInputStream(std::vector< sal_Int8 > const &rInData)
#define TOOLS_WARN_EXCEPTION(area, stream)
bool isInstalled(css::uno::Reference< css::deployment::XPackage > const &package)
Definition: dp_manager.cxx:679
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC bool platform_fits(OUString const &platform_string)
css::uno::Reference< css::uno::XComponentContext > m_xComponentContext
Definition: dp_manager.h:40
OUString const & GetURL() const
virtual css::uno::Reference< css::task::XInteractionHandler > SAL_CALL getInteractionHandler() override
uno::Reference< sdbc::XRow > xRow
unsigned char sal_Bool
::std::optional< OUString > getIdentifier() const
Return the identifier.
dictionary props
const OUString & getURL() const
virtual void SAL_CALL addEventListener(css::uno::Reference< css::lang::XEventListener > const &xListener) override
Definition: dp_manager.cxx:504
virtual css::uno::Reference< css::ucb::XProgressHandler > SAL_CALL getProgressHandler() override
css::uno::Reference< css::deployment::XPackage > getDeployedPackage_(OUString const &id, OUString const &fileName, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv)
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC bool create_ucb_content(::ucbhelper::Content *ucb_content, OUString const &url, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv, bool throw_exc=true)
this class is for use in XPackageManager::checkPrerequisites
exports com.sun.star.chart2. data
OString exceptionToString(const css::uno::Any &caught)
OUString expandUnoRcUrl(OUString const &url)
Definition: dp_misc.cxx:313
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2261
void try_dispose(css::uno::Reference< css::uno::XInterface > const &x)
Definition: dp_misc.h:47
CmdEnvWrapperImpl(css::uno::Reference< css::ucb::XCommandEnvironment > const &xUserCmdEnv, css::uno::Reference< css::ucb::XProgressHandler > const &xLogFile)
css::uno::Reference< css::ucb::XProgressHandler > m_xUserProgress
Definition: dp_manager.h:91
OUString DpResId(TranslateId aId)
Definition: dp_shared.hxx:36
#define SAL_WARN_IF(condition, area, stream)
virtual css::uno::Reference< css::deployment::XPackage > SAL_CALL importExtension(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
Definition: dp_manager.cxx:694
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
#define SAL_INFO(area, stream)
virtual css::uno::Reference< css::deployment::XPackage > SAL_CALL addPackage(OUString const &url, css::uno::Sequence< css::beans::NamedValue > const &properties, OUString const &mediaType, css::uno::Reference< css::task::XAbortChannel > const &xAbortChannel, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv) override
Definition: dp_manager.cxx:706
virtual void SAL_CALL addModifyListener(css::uno::Reference< css::util::XModifyListener > const &xListener) override
Definition: dp_manager.cxx:546
static css::uno::Reference< css::deployment::XPackageManager > create(css::uno::Reference< css::uno::XComponentContext > const &xComponentContext, OUString const &context)
Definition: dp_manager.cxx:339
void transferContent(const Content &rSourceContent, InsertOperation eOperation, const OUString &rTitle, const sal_Int32 nNameClashAction, const OUString &rMimeType=OUString(), bool bMajorVersion=false, const OUString &rCommentVersion=OUString(), OUString *pResultURL=nullptr, const OUString &rDocumentId=OUString()) const
void * p
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC bool erase_path(OUString const &url, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv, bool throw_exc=true)
std::unordered_map< OString, INetContentTypeParameter > INetContentTypeParameterList
bool synchronizeAddedExtensions(css::uno::Reference< css::task::XAbortChannel > const &xAbortChannel, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv)
virtual OUString SAL_CALL getContext() override
Definition: dp_manager.cxx:523
bool createDirectory(OUString const &rURL)
css::uno::Any setPropertyValue(const OUString &rPropertyName, const css::uno::Any &rValue)
virtual css::uno::Sequence< css::uno::Reference< css::deployment::XPackageTypeInfo > > SAL_CALL getSupportedPackageTypes() override
Definition: dp_manager.cxx:531
ResultType type
#define SAL_WARN(area, stream)
css::uno::Any executeCommand(const OUString &rCommandName, const css::uno::Any &rCommandArgument)
void forEach(FuncT const &func)
OUString getDeployPath(ActivePackages::Data const &data)
Definition: dp_manager.cxx:942
PackageManagerImpl(css::uno::Reference< css::uno::XComponentContext > const &xComponentContext, OUString const &context)
Definition: dp_manager.h:118
void writeStream(const css::uno::Reference< css::io::XInputStream > &rStream, bool bReplaceExisting)
OUString getString(const Any &_rAny)
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC OUString getIdentifier(css::uno::Reference< css::deployment::XPackage > const &package)
Gets the identifier of a package.
virtual void SAL_CALL removeModifyListener(css::uno::Reference< css::util::XModifyListener > const &xListener) override
Definition: dp_manager.cxx:554
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC bool create_folder(::ucbhelper::Content *ucb_content, OUString const &url, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv, bool throw_exc=true)
INCLUDE_DOCUMENTS_ONLY
bool synchronizeRemovedExtensions(css::uno::Reference< css::task::XAbortChannel > const &xAbortChannel, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv)
OUString insertToActivationLayer(css::uno::Sequence< css::beans::NamedValue > const &properties, OUString const &mediaType,::ucbhelper::Content const &sourceContent, OUString const &title, ActivePackages::Data *dbData)
Definition: dp_manager.cxx:600
virtual void SAL_CALL update(css::uno::Any const &Status) override
void initActivationLayer(css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv)
Definition: dp_manager.cxx:111
virtual css::uno::Sequence< css::uno::Reference< css::deployment::XPackage > > SAL_CALL getExtensionsWithUnacceptedLicenses(css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv) override
this class is for use in XPackageManager::synchronize.
css::uno::Reference< css::ucb::XProgressHandler > m_xLogFile
Definition: dp_manager.h:52
virtual css::uno::Reference< css::deployment::XPackage > SAL_CALL getDeployedPackage(OUString const &id, OUString const &fileName, css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv) override
css::uno::Sequence< css::uno::Reference< css::deployment::XPackage > > getDeployedPackages_(css::uno::Reference< css::ucb::XCommandEnvironment > const &xCmdEnv)
css::uno::Reference< css::deployment::XPackageRegistry > create(OUString const &context, OUString const &cachePath, css::uno::Reference< css::uno::XComponentContext > const &xComponentContext)
virtual void SAL_CALL disposing() override
Definition: dp_manager.cxx:468
Access to the content of an XML description element.
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo