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  Reference<deployment::XPackageManager> xPackageManager( that );
346 
347  OUString logFile, stamp;
348  if ( context == "user" ) {
349  that->m_activePackages = "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages";
350  that->m_registrationData = "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE";
351  that->m_registryCache = "vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/registry";
352  logFile = "$UNO_USER_PACKAGES_CACHE/log.txt";
353  //We use the extension .sys for the file because on Windows Vista a sys
354  //(as well as exe and dll) file
355  //will not be written in the VirtualStore. For example if the process has no
356  //admin right once cannot write to the %programfiles% folder. However, when
357  //virtualization is used, the file will be written into the VirtualStore and
358  //it appears as if one could write to %programfiles%. When we test for write
359  //access to the office/shared folder for shared extensions then this typically
360  //fails because a normal user typically cannot write to this folder. However,
361  //using virtualization it appears that he/she can. Then a shared extension can
362  //be installed but is only visible for the user (because the extension is in
363  //the virtual store).
364  stamp = "$UNO_USER_PACKAGES_CACHE";
365  }
366  else if ( context == "shared" ) {
367  that->m_activePackages = "vnd.sun.star.expand:$UNO_SHARED_PACKAGES_CACHE/uno_packages";
368  that->m_registrationData = "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER";
369  that->m_registryCache = "vnd.sun.star.expand:$SHARED_EXTENSIONS_USER/registry";
370  logFile = "$SHARED_EXTENSIONS_USER/log.txt";
371 #if !HAVE_FEATURE_READONLY_INSTALLSET
372  // The "shared" extensions are read-only when we have a
373  // read-only installset.
374  stamp = "$UNO_SHARED_PACKAGES_CACHE";
375 #endif
376  }
377  else if ( context == "bundled" ) {
378  that->m_activePackages = "vnd.sun.star.expand:$BUNDLED_EXTENSIONS";
379  that->m_registrationData = "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER";
380  that->m_registryCache = "vnd.sun.star.expand:$BUNDLED_EXTENSIONS_USER/registry";
381  logFile = "$BUNDLED_EXTENSIONS_USER/log.txt";
382  //No stamp file. We assume that bundled is always readonly. It must not be
383  //modified from ExtensionManager but only by the installer
384  }
385  else if ( context == "tmp" ) {
386  that->m_activePackages = "vnd.sun.star.expand:$TMP_EXTENSIONS/extensions";
387  that->m_registrationData = "vnd.sun.star.expand:$TMP_EXTENSIONS";
388  that->m_registryCache = "vnd.sun.star.expand:$TMP_EXTENSIONS/registry";
389  stamp = "$TMP_EXTENSIONS";
390  }
391  else if (context == "bak") {
392  that->m_activePackages = "vnd.sun.star.expand:$BAK_EXTENSIONS/extensions";
393  that->m_registrationData = "vnd.sun.star.expand:$BAK_EXTENSIONS";
394  that->m_registryCache = "vnd.sun.star.expand:$BAK_EXTENSIONS/registry";
395  stamp = "$BAK_EXTENSIONS";
396  }
397 
398  else if (! context.match("vnd.sun.star.tdoc:/")) {
399  throw lang::IllegalArgumentException(
400  "invalid context given: " + context,
401  Reference<XInterface>(), static_cast<sal_Int16>(-1) );
402  }
403 
405 
406  try {
407  // There is no stamp for the bundled folder:
408  if (!stamp.isEmpty())
409  that->m_readOnly = isMacroURLReadOnly( stamp );
410 
411  if (!that->m_readOnly && !logFile.isEmpty())
412  {
413  // Initialize logger which will be used in ProgressLogImpl (created below)
414  rtl::Bootstrap::expandMacros(logFile);
415  comphelper::EventLogger logger(xComponentContext, "unopkg");
416  const Reference<XLogger> xLogger(logger.getLogger());
417  Reference<XLogFormatter> xLogFormatter(SimpleTextFormatter::create(xComponentContext));
418  Sequence < beans::NamedValue > aSeq2 { { "Formatter", Any(xLogFormatter) }, {"FileURL", Any(logFile)} };
419  Reference<XLogHandler> xFileHandler(css::logging::FileHandler::createWithSettings(xComponentContext, aSeq2));
420  xFileHandler->setLevel(LogLevel::WARNING);
421  xLogger->addLogHandler(xFileHandler);
422 
423  that->m_xLogFile.set(
424  that->m_xComponentContext->getServiceManager()
425  ->createInstanceWithArgumentsAndContext(
426  "com.sun.star.comp.deployment.ProgressLog",
427  Sequence<Any>(),
428  that->m_xComponentContext ),
429  UNO_QUERY_THROW );
430  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv, that->m_xLogFile ) );
431  }
432 
433  that->initRegistryBackends();
434  that->initActivationLayer( xCmdEnv );
435 
436  return xPackageManager;
437 
438  }
439  catch (const RuntimeException &) {
440  throw;
441  }
442  catch (const Exception & e) {
443  Any exc( ::cppu::getCaughtException() );
444  throw lang::WrappedTargetRuntimeException(
445  ("[context=\"" + context + "\"] caught unexpected "
446  + exc.getValueType().getTypeName() + ": " + e.Message),
447  Reference<XInterface>(), exc );
448  }
449 }
450 
451 
453 {
454 }
455 
456 
458 {
459  ::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer(
461  if (pContainer != nullptr) {
462  pContainer->forEach<util::XModifyListener>(
463  [this] (uno::Reference<util::XModifyListener> const& xListener)
464  { return xListener->modified(lang::EventObject(static_cast<OWeakObject *>(this))); });
465  }
466 }
467 
468 
470 {
471  try {
472 // // xxx todo: guarding?
473 // ::osl::MutexGuard guard( getMutex() );
475  m_xLogFile.clear();
477  m_xRegistry.clear();
478  m_activePackagesDB.reset();
479  m_xComponentContext.clear();
480 
481  t_pm_helper::disposing();
482 
483  }
484  catch (const RuntimeException &) {
485  throw;
486  }
487  catch (const Exception &) {
488  Any exc( ::cppu::getCaughtException() );
489  throw lang::WrappedTargetRuntimeException(
490  "caught unexpected exception while disposing...",
491  static_cast<OWeakObject *>(this), exc );
492  }
493 }
494 
495 // XComponent
496 
498 {
499  //Do not call check here. We must not throw an exception here if the object
500  //is being disposed or is already disposed. See com.sun.star.lang.XComponent
501  WeakComponentImplHelperBase::dispose();
502 }
503 
504 
506  Reference<lang::XEventListener> const & xListener )
507 {
508  //Do not call check here. We must not throw an exception here if the object
509  //is being disposed or is already disposed. See com.sun.star.lang.XComponent
510  WeakComponentImplHelperBase::addEventListener( xListener );
511 }
512 
513 
515  Reference<lang::XEventListener> const & xListener )
516 {
517  //Do not call check here. We must not throw an exception here if the object
518  //is being disposed or is already disposed. See com.sun.star.lang.XComponent
519  WeakComponentImplHelperBase::removeEventListener( xListener );
520 }
521 
522 // XPackageManager
523 
525 {
526  check();
527  return m_context;
528 }
529 
530 
531 Sequence< Reference<deployment::XPackageTypeInfo> >
533 {
534  OSL_ASSERT( m_xRegistry.is() );
535  return m_xRegistry->getSupportedPackageTypes();
536 }
537 
538 
539 Reference<task::XAbortChannel> PackageManagerImpl::createAbortChannel()
540 {
541  check();
542  return new AbortChannel;
543 }
544 
545 // XModifyBroadcaster
546 
548  Reference<util::XModifyListener> const & xListener )
549 {
550  check();
551  rBHelper.addListener( cppu::UnoType<decltype(xListener)>::get(), xListener );
552 }
553 
554 
556  Reference<util::XModifyListener> const & xListener )
557 {
558  check();
559  rBHelper.removeListener( cppu::UnoType<decltype(xListener)>::get(), xListener );
560 }
561 
562 
564  ::ucbhelper::Content const & ucbContent_, bool throw_exc )
565 {
566  ::ucbhelper::Content ucbContent(ucbContent_);
567  OUString url( ucbContent.getURL() );
568  OUString mediaType;
569  if (url.match( "vnd.sun.star.tdoc:" ) || url.match( "vnd.sun.star.pkg:" ))
570  {
571  try {
572  ucbContent.getPropertyValue( "MediaType" ) >>= mediaType;
573  }
574  catch (const beans::UnknownPropertyException &) {
575  }
576  OSL_ENSURE( !mediaType.isEmpty(), "### no media-type?!" );
577  }
578  if (mediaType.isEmpty())
579  {
580  try {
581  Reference<deployment::XPackage> xPackage(
582  m_xRegistry->bindPackage(
583  url, OUString(), false, OUString(), ucbContent.getCommandEnvironment() ) );
584  const Reference<deployment::XPackageTypeInfo> xPackageType(
585  xPackage->getPackageType() );
586  OSL_ASSERT( xPackageType.is() );
587  if (xPackageType.is())
588  mediaType = xPackageType->getMediaType();
589  }
590  catch (const lang::IllegalArgumentException &) {
591  if (throw_exc)
592  throw;
593  css::uno::Any ex( cppu::getCaughtException() );
594  SAL_WARN( "desktop", exceptionToString(ex) );
595  }
596  }
597  return mediaType;
598 }
599 
600 
603  OUString const & mediaType, ::ucbhelper::Content const & sourceContent_,
604  OUString const & title, ActivePackages::Data * dbData )
605 {
606  ::ucbhelper::Content sourceContent(sourceContent_);
608  sourceContent.getCommandEnvironment() );
609 
610  OUString baseDir(m_activePackages_expanded);
611  ::utl::TempFile aTemp(&baseDir, false);
612  OUString tempEntry = aTemp.GetURL();
613  tempEntry = tempEntry.copy(tempEntry.lastIndexOf('/') + 1);
614  OUString destFolder = makeURL( m_activePackages, tempEntry) + "_";
615 
616  // prepare activation folder:
617  ::ucbhelper::Content destFolderContent;
618  create_folder( &destFolderContent, destFolder, xCmdEnv );
619 
620  // copy content into activation temp dir:
621  if (mediaType.matchIgnoreAsciiCase("application/vnd.sun.star.package-bundle") ||
622  // xxx todo: more sophisticated parsing
623  mediaType.matchIgnoreAsciiCase("application/vnd.sun.star.legacy-package-bundle"))
624  {
625  // inflate content:
626  OUStringBuffer buf;
627  if (!sourceContent.isFolder())
628  {
629  buf.append( "vnd.sun.star.zip://" );
630  buf.append( ::rtl::Uri::encode( sourceContent.getURL(),
631  rtl_UriCharClassRegName,
632  rtl_UriEncodeIgnoreEscapes,
633  RTL_TEXTENCODING_UTF8 ) );
634  }
635  else
636  {
637  //Folder. No need to unzip, just copy
638  buf.append(sourceContent.getURL());
639  }
640  buf.append( '/' );
641  sourceContent = ::ucbhelper::Content(
642  buf.makeStringAndClear(), xCmdEnv, m_xComponentContext );
643  }
644  destFolderContent.transferContent(
645  sourceContent, ::ucbhelper::InsertOperation::Copy,
646  title, NameClash::OVERWRITE );
647 
648 
649  // write to DB:
650  //bundled extensions should only be added by the synchronizeAddedExtensions
651  //functions. Moreover, there is no "temporary folder" for bundled extensions.
652  OSL_ASSERT(!(m_context == "bundled"));
653  OUString sFolderUrl = makeURLAppendSysPathSegment(destFolderContent.getURL(), title);
654  DescriptionInfoset info =
655  dp_misc::getDescriptionInfoset(sFolderUrl);
656  dbData->temporaryName = tempEntry;
657  dbData->fileName = title;
658  dbData->mediaType = mediaType;
659  dbData->version = info.getVersion();
660 
661  //No write the properties file next to the extension
662  ExtensionProperties props(sFolderUrl, properties, xCmdEnv, m_xComponentContext);
663  props.write();
664  return destFolder;
665 }
666 
667 
669  OUString const & id, ActivePackages::Data const & dbData )
670 {
671  //access to the database must be guarded. See removePackage
672  const ::osl::MutexGuard guard( getMutex() );
673  m_activePackagesDB->put( id, dbData );
674 }
675 
676 
677 /* The function returns true if there is an extension with the same id already
678  installed which needs to be uninstalled, before the new extension can be installed.
679 */
681  Reference<deployment::XPackage> const & package)
682 {
683  OUString id(dp_misc::getIdentifier(package));
684  OUString fn(package->getName());
685  bool bInstalled = false;
686  if (m_activePackagesDB->has( id, fn ))
687  {
688  bInstalled = true;
689  }
690  return bInstalled;
691 }
692 
693 // XPackageManager
694 
695 Reference<deployment::XPackage> PackageManagerImpl::importExtension(
696  Reference<deployment::XPackage> const & extension,
697  Reference<task::XAbortChannel> const & xAbortChannel,
698  Reference<XCommandEnvironment> const & xCmdEnv_ )
699 {
700  return addPackage(extension->getURL(), Sequence<beans::NamedValue>(),
701  OUString(), xAbortChannel, xCmdEnv_);
702 }
703 
704 /* The function adds an extension but does not register it!!!
705  It may not do any user interaction. This is done in XExtensionManager::addExtension
706 */
707 Reference<deployment::XPackage> PackageManagerImpl::addPackage(
708  OUString const & url,
709  css::uno::Sequence<css::beans::NamedValue> const & properties,
710  OUString const & mediaType_,
711  Reference<task::XAbortChannel> const & xAbortChannel,
712  Reference<XCommandEnvironment> const & xCmdEnv_ )
713 {
714  check();
715  if (m_readOnly)
716  {
717  OUString message;
718  if (m_context == "shared")
719  message = "You need write permissions to install a shared extension!";
720  else
721  message = "You need write permissions to install this extension!";
722  throw deployment::DeploymentException(
723  message, static_cast<OWeakObject *>(this), Any() );
724  }
726  if (m_xLogFile.is())
727  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
728  else
729  xCmdEnv.set( xCmdEnv_ );
730 
731  try {
732  ::ucbhelper::Content sourceContent;
733  (void)create_ucb_content( &sourceContent, url, xCmdEnv ); // throws exc
734  const OUString title( StrTitle::getTitle( sourceContent ) );
735  const OUString title_enc( ::rtl::Uri::encode(
736  title, rtl_UriCharClassPchar,
737  rtl_UriEncodeIgnoreEscapes,
738  RTL_TEXTENCODING_UTF8 ) );
739  OUString destFolder;
740 
741  OUString mediaType(mediaType_);
742  if (mediaType.isEmpty())
743  mediaType = detectMediaType( sourceContent );
744 
745  Reference<deployment::XPackage> xPackage;
746  // copy file:
748  DpResId(RID_STR_COPYING_PACKAGE) + title, xCmdEnv );
749  if (m_activePackages.isEmpty())
750  {
751  ::ucbhelper::Content docFolderContent;
752  create_folder( &docFolderContent, m_context, xCmdEnv );
753  // copy into document, first:
754  docFolderContent.transferContent(
755  sourceContent, ::ucbhelper::InsertOperation::Copy,
756  OUString(),
757  NameClash::ASK /* xxx todo: ASK not needed? */);
758  // set media-type:
759  ::ucbhelper::Content docContent(
760  makeURL( m_context, title_enc ), xCmdEnv, m_xComponentContext );
761  //TODO #i73136#: using title instead of id can lead to
762  // clashes, but the whole m_activePackages.getLength()==0
763  // case (i.e., document-relative deployment) currently does
764  // not work, anyway.
765  docContent.setPropertyValue("MediaType", Any(mediaType) );
766 
767  // xxx todo: obsolete in the future
768  try {
769  docFolderContent.executeCommand( "flush", Any() );
770  }
771  catch (const UnsupportedCommandException &) {
772  }
773  }
774  ActivePackages::Data dbData;
775  destFolder = insertToActivationLayer(
776  properties, mediaType, sourceContent, title, &dbData );
777 
778 
779  // bind activation package:
780  //Because every shared/user extension will be unpacked in a folder,
781  //which was created with a unique name we will always have two different
782  //XPackage objects, even if the second extension is the same.
783  //Therefore bindPackage does not need a guard here.
784  xPackage = m_xRegistry->bindPackage(
785  makeURL( destFolder, title_enc ), mediaType, false, OUString(), xCmdEnv );
786 
787  OSL_ASSERT( xPackage.is() );
788  if (xPackage.is())
789  {
790  bool install = false;
791  try
792  {
793  OUString const id = dp_misc::getIdentifier( xPackage );
794 
795  ::osl::MutexGuard g(m_addMutex);
796  if (isInstalled(xPackage))
797  {
798  //Do not guard the complete function with the getMutex
799  removePackage(id, xPackage->getName(), xAbortChannel,
800  xCmdEnv);
801  }
802  install = true;
803  insertToActivationLayerDB(id, dbData);
804  }
805  catch (...)
806  {
807  deletePackageFromCache( xPackage, destFolder );
808  throw;
809  }
810  if (!install)
811  {
812  deletePackageFromCache( xPackage, destFolder );
813  }
814  //ToDo: We should notify only if the extension is registered
815  fireModified();
816  }
817  return xPackage;
818  }
819  catch (const RuntimeException &) {
820  throw;
821  }
822  catch (const CommandFailedException & exc) {
823  logIntern( Any(exc) );
824  throw;
825  }
826  catch (const CommandAbortedException & exc) {
827  logIntern( Any(exc) );
828  throw;
829  }
830  catch (const deployment::DeploymentException & exc) {
831  logIntern( Any(exc) );
832  throw;
833  }
834  catch (const Exception &) {
835  Any exc( ::cppu::getCaughtException() );
836  logIntern( exc );
837  throw deployment::DeploymentException(
838  DpResId(RID_STR_ERROR_WHILE_ADDING) + url,
839  static_cast<OWeakObject *>(this), exc );
840  }
841 }
843  Reference<deployment::XPackage> const & xPackage,
844  OUString const & destFolder)
845 {
846  try_dispose( xPackage );
847 
848  //we remove the package from the uno cache
849  //no service from the package may be loaded at this time!!!
851  false /* no throw: ignore errors */ );
852  //rm last character '_'
853  OUString url = destFolder.copy(0, destFolder.getLength() - 1);
855  false /* no throw: ignore errors */ );
856 
857 }
858 
860  OUString const & id, OUString const & fileName,
861  Reference<task::XAbortChannel> const & /*xAbortChannel*/,
862  Reference<XCommandEnvironment> const & xCmdEnv_ )
863 {
864  check();
865 
867  if (m_xLogFile.is())
868  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
869  else
870  xCmdEnv.set( xCmdEnv_ );
871 
872  try {
873  Reference<deployment::XPackage> xPackage;
874  {
875  const ::osl::MutexGuard guard(getMutex());
876  //Check if this extension exist and throw an IllegalArgumentException
877  //if it does not
878  //If the files of the extension are already removed, or there is a
879  //different extension at the same place, for example after updating the
880  //extension, then the returned object is that which uses the database data.
881  xPackage = getDeployedPackage_(id, fileName, xCmdEnv );
882 
883 
884  //Because the extension is only removed the next time the extension
885  //manager runs after restarting OOo, we need to indicate that a
886  //shared extension was "deleted". When a user starts OOo, then it
887  //will check if something changed in the shared repository. Based on
888  //the flag file it will then recognize, that the extension was
889  //deleted and can then update the extension database of the shared
890  //extensions in the user installation.
891  if ( xPackage.is() && !m_readOnly && !xPackage->isRemoved() && (m_context == "shared"))
892  {
894  m_activePackagesDB->get( & val, id, fileName);
895  OSL_ASSERT(!val.temporaryName.isEmpty());
896  OUString url(makeURL(m_activePackages_expanded,
897  val.temporaryName + "removed"));
898  ::ucbhelper::Content contentRemoved(url, xCmdEnv, m_xComponentContext);
899  OUString aUserName;
900  ::osl::Security aSecurity;
901  aSecurity.getUserName( aUserName );
902 
903  OString stamp = OUStringToOString(aUserName, RTL_TEXTENCODING_UTF8);
904  Reference<css::io::XInputStream> xData(
906  reinterpret_cast<sal_Int8 const *>(stamp.getStr()),
907  stamp.getLength() ) );
908  contentRemoved.writeStream( xData, true /* replace existing */ );
909  }
910  m_activePackagesDB->erase( id, fileName ); // to be removed upon next start
911  //remove any cached data hold by the backend
912  m_xRegistry->packageRemoved(xPackage->getURL(), xPackage->getPackageType()->getMediaType());
913  }
914  try_dispose( xPackage );
915 
916  fireModified();
917  }
918  catch (const RuntimeException &) {
919  throw;
920  }
921  catch (const CommandFailedException & exc) {
922  logIntern( Any(exc) );
923  throw;
924  }
925  catch (const CommandAbortedException & exc) {
926  logIntern( Any(exc) );
927  throw;
928  }
929  catch (const deployment::DeploymentException & exc) {
930  logIntern( Any(exc) );
931  throw;
932  }
933  catch (const Exception &) {
934  Any exc( ::cppu::getCaughtException() );
935  logIntern( exc );
936  throw deployment::DeploymentException(
937  DpResId(RID_STR_ERROR_WHILE_REMOVING) + id,
938  static_cast<OWeakObject *>(this), exc );
939  }
940 }
941 
942 
944 {
945  OUStringBuffer buf;
946  buf.append( data.temporaryName );
947  //The bundled extensions are not contained in an additional folder
948  //with a unique name. data.temporaryName contains already the
949  //UTF8 encoded folder name. See PackageManagerImpl::synchronize
950  if (m_context != "bundled")
951  {
952  buf.append( "_/" );
953  buf.append( ::rtl::Uri::encode( data.fileName, rtl_UriCharClassPchar,
954  rtl_UriEncodeIgnoreEscapes,
955  RTL_TEXTENCODING_UTF8 ) );
956  }
957  return makeURL( m_activePackages, buf.makeStringAndClear() );
958 }
959 
960 
961 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
962  OUString const & id, OUString const & fileName,
963  Reference<XCommandEnvironment> const & xCmdEnv )
964 {
966  if (m_activePackagesDB->get( &val, id, fileName ))
967  {
968  return getDeployedPackage_( id, val, xCmdEnv );
969  }
970  throw lang::IllegalArgumentException(
971  DpResId(RID_STR_NO_SUCH_PACKAGE) + id,
972  static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
973 }
974 
975 
976 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
977  OUString const & id, ActivePackages::Data const & data,
978  Reference<XCommandEnvironment> const & xCmdEnv, bool ignoreAlienPlatforms )
979 {
980  if (ignoreAlienPlatforms)
981  {
982  OUString type, subType;
984  if (INetContentTypes::parse( data.mediaType, type, subType, &params ))
985  {
986  auto const iter = params.find(OString("platform"));
987  if (iter != params.end() && !platform_fits(iter->second.m_sValue))
988  throw lang::IllegalArgumentException(
989  DpResId(RID_STR_NO_SUCH_PACKAGE) + id,
990  static_cast<OWeakObject *>(this),
991  static_cast<sal_Int16>(-1) );
992  }
993  }
994  Reference<deployment::XPackage> xExtension;
995  try
996  {
997  //Ignore extensions where XPackage::checkPrerequisites failed.
998  //They must not be usable for this user.
999  if (data.failedPrerequisites == "0")
1000  {
1001  xExtension = m_xRegistry->bindPackage(
1002  getDeployPath( data ), data.mediaType, false, OUString(), xCmdEnv );
1003  }
1004  }
1005  catch (const deployment::InvalidRemovedParameterException& e)
1006  {
1007  xExtension = e.Extension;
1008  }
1009  return xExtension;
1010 }
1011 
1012 
1013 Sequence< Reference<deployment::XPackage> >
1015  Reference<XCommandEnvironment> const & xCmdEnv )
1016 {
1017  std::vector< Reference<deployment::XPackage> > packages;
1018  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1019  for (auto const& elem : id2temp)
1020  {
1021  if (elem.second.failedPrerequisites != "0")
1022  continue;
1023  try {
1024  packages.push_back(
1026  elem.first, elem.second, xCmdEnv,
1027  true /* xxx todo: think of GUI:
1028  ignore other platforms than the current one */ ) );
1029  }
1030  catch (const lang::IllegalArgumentException &) {
1031  // ignore
1032  TOOLS_WARN_EXCEPTION( "desktop", "" );
1033  }
1034  catch (const deployment::DeploymentException&) {
1035  // ignore
1036  TOOLS_WARN_EXCEPTION( "desktop", "" );
1037  }
1038  }
1039  return comphelper::containerToSequence(packages);
1040 }
1041 
1042 
1043 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage(
1044  OUString const & id, OUString const & fileName,
1045  Reference<XCommandEnvironment> const & xCmdEnv_ )
1046 {
1047  check();
1049  if (m_xLogFile.is())
1050  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1051  else
1052  xCmdEnv.set( xCmdEnv_ );
1053 
1054  try {
1055  const ::osl::MutexGuard guard( getMutex() );
1056  return getDeployedPackage_( id, fileName, xCmdEnv );
1057  }
1058  catch (const RuntimeException &) {
1059  throw;
1060  }
1061  catch (const CommandFailedException & exc) {
1062  logIntern( Any(exc) );
1063  throw;
1064  }
1065  catch (const deployment::DeploymentException & exc) {
1066  logIntern( Any(exc) );
1067  throw;
1068  }
1069  catch (const Exception &) {
1070  Any exc( ::cppu::getCaughtException() );
1071  logIntern( exc );
1072  throw deployment::DeploymentException(
1073  // ought never occur...
1074  "error while accessing deployed package: " + id,
1075  static_cast<OWeakObject *>(this), exc );
1076  }
1077 }
1078 
1079 
1080 Sequence< Reference<deployment::XPackage> >
1082  Reference<task::XAbortChannel> const &,
1083  Reference<XCommandEnvironment> const & xCmdEnv_ )
1084 {
1085  check();
1087  if (m_xLogFile.is())
1088  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1089  else
1090  xCmdEnv.set( xCmdEnv_ );
1091 
1092  try {
1093  const ::osl::MutexGuard guard( getMutex() );
1094  return getDeployedPackages_( xCmdEnv );
1095  }
1096  catch (const RuntimeException &) {
1097  throw;
1098  }
1099  catch (const CommandFailedException & exc) {
1100  logIntern( Any(exc) );
1101  throw;
1102  }
1103  catch (const CommandAbortedException & exc) {
1104  logIntern( Any(exc) );
1105  throw;
1106  }
1107  catch (const deployment::DeploymentException & exc) {
1108  logIntern( Any(exc) );
1109  throw;
1110  }
1111  catch (const Exception &) {
1112  Any exc( ::cppu::getCaughtException() );
1113  logIntern( exc );
1114  throw deployment::DeploymentException(
1115  // ought never occur...
1116  "error while getting all deployed packages: " + m_context,
1117  static_cast<OWeakObject *>(this), exc );
1118  }
1119 }
1120 
1121 
1122 //ToDo: the function must not call registerPackage, do this in
1123 //XExtensionManager.reinstallDeployedExtensions
1125  sal_Bool force, Reference<task::XAbortChannel> const & /*xAbortChannel*/,
1126  Reference<XCommandEnvironment> const & xCmdEnv_ )
1127 {
1128  check();
1129  if (!force && office_is_running())
1130  throw RuntimeException(
1131  "You must close any running Office process before reinstalling packages!",
1132  static_cast<OWeakObject *>(this) );
1133 
1135  if (m_xLogFile.is())
1136  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1137  else
1138  xCmdEnv.set( xCmdEnv_ );
1139 
1140  try {
1141  ProgressLevel progress(
1142  xCmdEnv, "Reinstalling all deployed packages..." );
1143 
1145  m_xRegistry.clear();
1146  if (!m_registryCache.isEmpty())
1147  erase_path( m_registryCache, xCmdEnv );
1149  Reference<util::XUpdatable> xUpdatable( m_xRegistry, UNO_QUERY );
1150  if (xUpdatable.is())
1151  xUpdatable->update();
1152 
1153  //registering is done by the ExtensionManager service.
1154  }
1155  catch (const RuntimeException &) {
1156  throw;
1157  }
1158  catch (const CommandFailedException & exc) {
1159  logIntern( Any(exc) );
1160  throw;
1161  }
1162  catch (const CommandAbortedException & exc) {
1163  logIntern( Any(exc) );
1164  throw;
1165  }
1166  catch (const deployment::DeploymentException & exc) {
1167  logIntern( Any(exc) );
1168  throw;
1169  }
1170  catch (const Exception &) {
1171  Any exc( ::cppu::getCaughtException() );
1172  logIntern( exc );
1173  throw deployment::DeploymentException(
1174  "Error while reinstalling all previously deployed packages of context " + m_context,
1175  static_cast<OWeakObject *>(this), exc );
1176  }
1177 }
1178 
1179 
1181 {
1182  return m_readOnly;
1183 }
1185  Reference<task::XAbortChannel> const & xAbortChannel,
1187 {
1188 
1189  //find all which are in the extension data base but which
1190  //are removed already.
1191  OSL_ASSERT(!(m_context == "user"));
1192  bool bModified = false;
1193  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1194 
1195  bool bShared = (m_context == "shared");
1196 
1197  for (auto const& elem : id2temp)
1198  {
1199  try
1200  {
1201  //Get the URL to the extensions folder, first make the url for the
1202  //shared repository including the temporary name
1203  OUString url = makeURL(m_activePackages, elem.second.temporaryName);
1204  if (bShared)
1205  url = makeURLAppendSysPathSegment( url + "_", elem.second.fileName);
1206 
1207  bool bRemoved = false;
1208  //Check if the URL to the extension is still the same
1209  ::ucbhelper::Content contentExtension;
1210 
1211  if (!create_ucb_content(
1212  &contentExtension, url,
1214  {
1215  bRemoved = true;
1216  }
1217 
1218  //The folder is in the extension database, but it can still be deleted.
1219  //look for the xxx.tmpremoved file
1220  //There can also be the case that a different extension was installed
1221  //in a "temp" folder with name that is already used.
1222  if (!bRemoved && bShared)
1223  {
1224  ::ucbhelper::Content contentRemoved;
1225 
1226  if (create_ucb_content(
1227  &contentRemoved,
1229  elem.second.temporaryName + "removed",
1231  {
1232  bRemoved = true;
1233  }
1234  }
1235 
1236  if (!bRemoved)
1237  {
1238  //There may be another extensions at the same place
1239  dp_misc::DescriptionInfoset infoset =
1241  OSL_ENSURE(infoset.hasDescription() && infoset.getIdentifier(),
1242  "Extension Manager: bundled and shared extensions "
1243  "must have an identifier and a version");
1244  if (infoset.hasDescription() &&
1245  infoset.getIdentifier() &&
1246  ( elem.first != *(infoset.getIdentifier())
1247  || elem.second.version != infoset.getVersion()))
1248  {
1249  bRemoved = true;
1250  }
1251 
1252  }
1253  if (bRemoved)
1254  {
1255  Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1256  url, elem.second.mediaType, true, elem.first, xCmdEnv );
1257  OSL_ASSERT(xPackage.is()); //Even if the files are removed, we must get the object.
1258  xPackage->revokePackage(true, xAbortChannel, xCmdEnv);
1259  removePackage(xPackage->getIdentifier().Value, xPackage->getName(),
1260  xAbortChannel, xCmdEnv);
1261  bModified = true;
1262  }
1263  }
1264  catch( const uno::Exception & )
1265  {
1266  TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1267  }
1268  }
1269  return bModified;
1270 }
1271 
1272 
1274  Reference<task::XAbortChannel> const & xAbortChannel,
1276 {
1277  bool bModified = false;
1278  OSL_ASSERT(!(m_context == "user"));
1279 
1280  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1281  //check if the folder exist at all. The shared extension folder
1282  //may not exist for a normal user.
1283  bool bOk=true;
1284  try
1285  {
1286  bOk = create_ucb_content(
1288  }
1289  catch (const css::ucb::ContentCreationException&)
1290  {
1291  bOk = false;
1292  }
1293 
1294  if (!bOk)
1295  return bModified;
1296 
1298  Reference<sdbc::XResultSet> xResultSet(
1299  StrTitle::createCursor( tempFolder,
1301 
1302  while (xResultSet->next())
1303  {
1304  try
1305  {
1306  OUString title(
1307  Reference<sdbc::XRow>(
1308  xResultSet, UNO_QUERY_THROW )->getString(
1309  1 /* Title */ ) );
1310  //The temporary folders of user and shared have an '_' at then end.
1311  //But the name in ActivePackages.temporaryName is saved without.
1312  OUString title2 = title;
1313  bool bShared = (m_context == "shared");
1314  if (bShared)
1315  {
1316  OSL_ASSERT(title2.endsWith("_"));
1317  title2 = title2.copy(0, title2.getLength() -1);
1318  }
1319  OUString titleEncoded = ::rtl::Uri::encode(
1320  title2, rtl_UriCharClassPchar,
1321  rtl_UriEncodeIgnoreEscapes,
1322  RTL_TEXTENCODING_UTF8);
1323 
1324  //It is sufficient to check for the folder name, because when the administrator
1325  //installed the extension it was already checked if there is one with the
1326  //same identifier.
1327  const MatchTempDir match(titleEncoded);
1328  if (std::none_of( id2temp.begin(), id2temp.end(), match ))
1329  {
1330 
1331  // The folder was not found in the data base, so it must be
1332  // an added extension
1333  OUString url(m_activePackages_expanded + "/" + titleEncoded);
1334  OUString sExtFolder;
1335  if (bShared) //that is, shared
1336  {
1337  //Check if the extension was not "deleted" already which is indicated
1338  //by a xxx.tmpremoved file
1339  ::ucbhelper::Content contentRemoved;
1340  if (create_ucb_content(&contentRemoved, url + "removed",
1342  continue;
1343  sExtFolder = getExtensionFolder(
1344  m_activePackages_expanded + "/" + titleEncoded + "_",
1345  xCmdEnv, m_xComponentContext);
1347  url = makeURLAppendSysPathSegment(url, sExtFolder);
1348  }
1349  Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1350  url, OUString(), false, OUString(), xCmdEnv );
1351  if (xPackage.is())
1352  {
1353  OUString id = dp_misc::getIdentifier( xPackage );
1354 
1355  //Prepare the database entry
1356  ActivePackages::Data dbData;
1357 
1358  dbData.temporaryName = titleEncoded;
1359  if (bShared)
1360  dbData.fileName = sExtFolder;
1361  else
1362  dbData.fileName = title;
1363  dbData.mediaType = xPackage->getPackageType()->getMediaType();
1364  dbData.version = xPackage->getVersion();
1365  SAL_WARN_IF(
1366  dbData.version.isEmpty(), "desktop.deployment",
1367  "bundled/shared extension " << id << " at <" << url
1368  << "> has no explicit version");
1369 
1370  //We provide a special command environment that will prevent
1371  //showing a license if simple-license/@accept-by = "admin"
1372  //It will also prevent showing the license for bundled extensions
1373  //which is not supported.
1374  OSL_ASSERT(!(m_context == "user"));
1375 
1376  // shall the license be suppressed?
1377  DescriptionInfoset info =
1379  ::std::optional<dp_misc::SimpleLicenseAttributes>
1380  attr = info.getSimpleLicenseAttributes();
1382  bool bNoLicense = false;
1383  if (attr && attr->suppressIfRequired && props.isSuppressedLicense())
1384  bNoLicense = true;
1385 
1386  Reference<ucb::XCommandEnvironment> licCmdEnv(
1387  new LicenseCommandEnv(xCmdEnv->getInteractionHandler(),
1388  bNoLicense, m_context));
1389  sal_Int32 failedPrereq = xPackage->checkPrerequisites(
1390  xAbortChannel, licCmdEnv, false);
1391  //Remember that this failed. For example, the user
1392  //could have declined the license. Then the next time the
1393  //extension folder is investigated we do not want to
1394  //try to install the extension again.
1395  dbData.failedPrerequisites = OUString::number(failedPrereq);
1396  insertToActivationLayerDB(id, dbData);
1397  bModified = true;
1398  }
1399  }
1400  }
1401  catch (const uno::Exception &)
1402  {
1403  // Looks like exceptions being caught here is not an uncommon case.
1404  TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1405  }
1406  }
1407  return bModified;
1408 }
1409 
1411  Reference<task::XAbortChannel> const & xAbortChannel,
1413 {
1414  check();
1415  bool bModified = false;
1416  if (m_context == "user")
1417  return bModified;
1418  bModified |=
1419  synchronizeRemovedExtensions(xAbortChannel, xCmdEnv);
1420  bModified |= synchronizeAddedExtensions(xAbortChannel, xCmdEnv);
1421 
1422  return bModified;
1423 }
1424 
1425 Sequence< Reference<deployment::XPackage> > PackageManagerImpl::getExtensionsWithUnacceptedLicenses(
1426  Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1427 {
1428  std::vector<Reference<deployment::XPackage> > vec;
1429 
1430  try
1431  {
1432  const ::osl::MutexGuard guard( getMutex() );
1433  // clean up activation layer, scan for zombie temp dirs:
1434  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1435 
1436  bool bShared = (m_context == "shared");
1437 
1438  for (auto const& elem : id2temp)
1439  {
1440  //Get the database entry
1441  ActivePackages::Data const & dbData = elem.second;
1442  sal_Int32 failedPrereq = dbData.failedPrerequisites.toInt32();
1443  //If the installation failed for other reason then the license then we
1444  //ignore it.
1445  if (failedPrereq ^ deployment::Prerequisites::LICENSE)
1446  continue;
1447 
1448  //Prepare the URL to the extension
1449  OUString url = makeURL(m_activePackages, elem.second.temporaryName);
1450  if (bShared)
1451  url = makeURLAppendSysPathSegment( url + "_", elem.second.fileName);
1452 
1453  Reference<deployment::XPackage> p = m_xRegistry->bindPackage(
1454  url, OUString(), false, OUString(), xCmdEnv );
1455 
1456  if (p.is())
1457  vec.push_back(p);
1458 
1459  }
1460  return ::comphelper::containerToSequence(vec);
1461  }
1462  catch (const deployment::DeploymentException &)
1463  {
1464  throw;
1465  }
1466  catch (const RuntimeException&)
1467  {
1468  throw;
1469  }
1470  catch (...)
1471  {
1472  Any exc = ::cppu::getCaughtException();
1473  deployment::DeploymentException de(
1474  "PackageManagerImpl::getExtensionsWithUnacceptedLicenses",
1475  static_cast<OWeakObject*>(this), exc);
1476  exc <<= de;
1477  ::cppu::throwException(exc);
1478  }
1479 
1480  return ::comphelper::containerToSequence(vec);
1481 }
1482 
1484  css::uno::Reference<css::deployment::XPackage> const & extension,
1485  css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel,
1486  css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv )
1487 {
1488  try
1489  {
1490  if (!extension.is())
1491  return 0;
1492  if (m_context != extension->getRepositoryName())
1493  throw lang::IllegalArgumentException(
1494  "PackageManagerImpl::checkPrerequisites: extension is not from this repository.",
1495  nullptr, 0);
1496 
1497  ActivePackages::Data dbData;
1498  OUString id = dp_misc::getIdentifier(extension);
1499  if (!m_activePackagesDB->get( &dbData, id, OUString()))
1500  {
1501  throw lang::IllegalArgumentException(
1502  "PackageManagerImpl::checkPrerequisites: unknown extension",
1503  nullptr, 0);
1504 
1505  }
1506  //If the license was already displayed, then do not show it again
1507  Reference<ucb::XCommandEnvironment> _xCmdEnv = xCmdEnv;
1508  sal_Int32 prereq = dbData.failedPrerequisites.toInt32();
1509  if ( !(prereq & deployment::Prerequisites::LICENSE))
1510  _xCmdEnv = new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler());
1511 
1512  sal_Int32 failedPrereq = extension->checkPrerequisites(
1513  xAbortChannel, _xCmdEnv, false);
1514  dbData.failedPrerequisites = OUString::number(failedPrereq);
1515  insertToActivationLayerDB(id, dbData);
1516  return 0;
1517  }
1518  catch ( const deployment::DeploymentException& ) {
1519  throw;
1520  } catch ( const ucb::CommandFailedException & ) {
1521  throw;
1522  } catch ( const ucb::CommandAbortedException & ) {
1523  throw;
1524  } catch (const lang::IllegalArgumentException &) {
1525  throw;
1526  } catch (const uno::RuntimeException &) {
1527  throw;
1528  } catch (...) {
1529  uno::Any excOccurred = ::cppu::getCaughtException();
1530  deployment::DeploymentException exc(
1531  "PackageManagerImpl::checkPrerequisites: exception ",
1532  static_cast<OWeakObject*>(this), excOccurred);
1533  throw exc;
1534  }
1535 }
1536 
1537 
1539 {
1540 }
1541 
1542 
1544  Reference<XCommandEnvironment> const & xUserCmdEnv,
1545  Reference<XProgressHandler> const & xLogFile )
1546  : m_xLogFile( xLogFile )
1547 {
1548  if (xUserCmdEnv.is()) {
1549  m_xUserProgress.set( xUserCmdEnv->getProgressHandler() );
1550  m_xUserInteractionHandler.set( xUserCmdEnv->getInteractionHandler() );
1551  }
1552 }
1553 
1554 // XCommandEnvironment
1555 
1556 Reference<task::XInteractionHandler>
1558 {
1559  return m_xUserInteractionHandler;
1560 }
1561 
1562 
1565 {
1566  return this;
1567 }
1568 
1569 // XProgressHandler
1570 
1572 {
1573  if (m_xLogFile.is())
1574  m_xLogFile->push( Status );
1575  if (m_xUserProgress.is())
1576  m_xUserProgress->push( Status );
1577 }
1578 
1579 
1581 {
1582  if (m_xLogFile.is())
1583  m_xLogFile->update( Status );
1584  if (m_xUserProgress.is())
1585  m_xUserProgress->update( Status );
1586 }
1587 
1588 
1590 {
1591  if (m_xLogFile.is())
1592  m_xLogFile->pop();
1593  if (m_xUserProgress.is())
1594  m_xUserProgress->pop();
1595 }
1596 
1597 } // namespace dp_manager
1598 
1599 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::osl::Mutex & getMutex() const
Definition: dp_misc.h:39
virtual void SAL_CALL dispose() override
Definition: dp_manager.cxx:497
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:539
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:452
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:514
bool office_is_running()
Definition: dp_misc.cxx:333
OUString makeURL(OUString const &baseURL, OUString const &relPath_)
appends a relative path to a url.
Definition: dp_misc.cxx:251
OUString makeURLAppendSysPathSegment(OUString const &baseURL, OUString const &segment)
appends a relative path to a url.
Definition: dp_misc.cxx:281
OUString detectMediaType(::ucbhelper::Content const &ucbContent, bool throw_exc=true)
Definition: dp_manager.cxx:563
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:859
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:842
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:668
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
uno::Reference< sdbc::XRow > xRow
virtual ::sal_Bool SAL_CALL isReadOnly() override
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:680
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
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:505
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:315
DESKTOP_DEPLOYMENTMISC_DLLPUBLIC DescriptionInfoset getDescriptionInfoset(OUString const &sExtensionFolderURL)
creates a DescriptionInfoset object.
OString OUStringToOString(const OUString &str, ConnectionSettings const *settings)
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2178
void try_dispose(css::uno::Reference< css::uno::XInterface > const &x)
Definition: dp_misc.h:43
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
#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:695
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:707
virtual void SAL_CALL addModifyListener(css::uno::Reference< css::util::XModifyListener > const &xListener) override
Definition: dp_manager.cxx:547
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:524
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:532
ResultType type
OUString DpResId(const char *pId)
Definition: dp_shared.hxx:36
#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:943
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:555
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:601
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:469
Access to the content of an XML description element.
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo