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