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 
94 {
95  OUString m_str;
96  explicit MatchTempDir( OUString const & str ) : m_str( str ) {}
97  bool operator () ( ActivePackages::Entries::value_type const & v ) const {
98  return v.second.temporaryName.equalsIgnoreAsciiCase( m_str );
99  }
100 };
101 
102 
103 namespace {
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 sal_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 lang::IllegalArgumentException & exc) {
1070  logIntern( Any(exc) );
1071  throw;
1072  }
1073  catch (const RuntimeException &) {
1074  throw;
1075  }
1076  catch (const CommandFailedException & exc) {
1077  logIntern( Any(exc) );
1078  throw;
1079  }
1080  catch (const deployment::DeploymentException & exc) {
1081  logIntern( Any(exc) );
1082  throw;
1083  }
1084  catch (const Exception &) {
1085  Any exc( ::cppu::getCaughtException() );
1086  logIntern( exc );
1087  throw deployment::DeploymentException(
1088  // ought never occur...
1089  "error while accessing deployed package: " + id,
1090  static_cast<OWeakObject *>(this), exc );
1091  }
1092 }
1093 
1094 
1095 Sequence< Reference<deployment::XPackage> >
1097  Reference<task::XAbortChannel> const &,
1098  Reference<XCommandEnvironment> const & xCmdEnv_ )
1099 {
1100  check();
1102  if (m_xLogFile.is())
1103  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1104  else
1105  xCmdEnv.set( xCmdEnv_ );
1106 
1107  try {
1108  const ::osl::MutexGuard guard( getMutex() );
1109  return getDeployedPackages_( xCmdEnv );
1110  }
1111  catch (const RuntimeException &) {
1112  throw;
1113  }
1114  catch (const CommandFailedException & exc) {
1115  logIntern( Any(exc) );
1116  throw;
1117  }
1118  catch (const CommandAbortedException & exc) {
1119  logIntern( Any(exc) );
1120  throw;
1121  }
1122  catch (const deployment::DeploymentException & exc) {
1123  logIntern( Any(exc) );
1124  throw;
1125  }
1126  catch (const Exception &) {
1127  Any exc( ::cppu::getCaughtException() );
1128  logIntern( exc );
1129  throw deployment::DeploymentException(
1130  // ought never occur...
1131  "error while getting all deployed packages: " + m_context,
1132  static_cast<OWeakObject *>(this), exc );
1133  }
1134 }
1135 
1136 
1137 //ToDo: the function must not call registerPackage, do this in
1138 //XExtensionManager.reinstallDeployedExtensions
1140  sal_Bool force, Reference<task::XAbortChannel> const & /*xAbortChannel*/,
1141  Reference<XCommandEnvironment> const & xCmdEnv_ )
1142 {
1143  check();
1144  if (!force && office_is_running())
1145  throw RuntimeException(
1146  "You must close any running Office process before reinstalling packages!",
1147  static_cast<OWeakObject *>(this) );
1148 
1150  if (m_xLogFile.is())
1151  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1152  else
1153  xCmdEnv.set( xCmdEnv_ );
1154 
1155  try {
1156  ProgressLevel progress(
1157  xCmdEnv, "Reinstalling all deployed packages..." );
1158 
1160  m_xRegistry.clear();
1161  if (!m_registryCache.isEmpty())
1162  erase_path( m_registryCache, xCmdEnv );
1164  Reference<util::XUpdatable> xUpdatable( m_xRegistry, UNO_QUERY );
1165  if (xUpdatable.is())
1166  xUpdatable->update();
1167 
1168  //registering is done by the ExtensionManager service.
1169  }
1170  catch (const RuntimeException &) {
1171  throw;
1172  }
1173  catch (const CommandFailedException & exc) {
1174  logIntern( Any(exc) );
1175  throw;
1176  }
1177  catch (const CommandAbortedException & exc) {
1178  logIntern( Any(exc) );
1179  throw;
1180  }
1181  catch (const deployment::DeploymentException & exc) {
1182  logIntern( Any(exc) );
1183  throw;
1184  }
1185  catch (const Exception &) {
1186  Any exc( ::cppu::getCaughtException() );
1187  logIntern( exc );
1188  throw deployment::DeploymentException(
1189  "Error while reinstalling all previously deployed packages of context " + m_context,
1190  static_cast<OWeakObject *>(this), exc );
1191  }
1192 }
1193 
1194 
1196 {
1197  return m_readOnly;
1198 }
1200  Reference<task::XAbortChannel> const & xAbortChannel,
1202 {
1203 
1204  //find all which are in the extension data base but which
1205  //are removed already.
1206  OSL_ASSERT(!(m_context == "user"));
1207  bool bModified = false;
1208  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1209 
1210  bool bShared = (m_context == "shared");
1211 
1212  for (auto const& elem : id2temp)
1213  {
1214  try
1215  {
1216  //Get the URL to the extensions folder, first make the url for the
1217  //shared repository including the temporary name
1218  OUString url = makeURL(m_activePackages, elem.second.temporaryName);
1219  if (bShared)
1220  url = makeURLAppendSysPathSegment( url + "_", elem.second.fileName);
1221 
1222  bool bRemoved = false;
1223  //Check if the URL to the extension is still the same
1224  ::ucbhelper::Content contentExtension;
1225 
1226  if (!create_ucb_content(
1227  &contentExtension, url,
1229  {
1230  bRemoved = true;
1231  }
1232 
1233  //The folder is in the extension database, but it can still be deleted.
1234  //look for the xxx.tmpremoved file
1235  //There can also be the case that a different extension was installed
1236  //in a "temp" folder with name that is already used.
1237  if (!bRemoved && bShared)
1238  {
1239  ::ucbhelper::Content contentRemoved;
1240 
1241  if (create_ucb_content(
1242  &contentRemoved,
1244  elem.second.temporaryName + "removed",
1246  {
1247  bRemoved = true;
1248  }
1249  }
1250 
1251  if (!bRemoved)
1252  {
1253  //There may be another extensions at the same place
1254  dp_misc::DescriptionInfoset infoset =
1256  OSL_ENSURE(infoset.hasDescription() && infoset.getIdentifier(),
1257  "Extension Manager: bundled and shared extensions "
1258  "must have an identifier and a version");
1259  if (infoset.hasDescription() &&
1260  infoset.getIdentifier() &&
1261  ( elem.first != *(infoset.getIdentifier())
1262  || elem.second.version != infoset.getVersion()))
1263  {
1264  bRemoved = true;
1265  }
1266 
1267  }
1268  if (bRemoved)
1269  {
1270  Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1271  url, elem.second.mediaType, true, elem.first, xCmdEnv );
1272  OSL_ASSERT(xPackage.is()); //Even if the files are removed, we must get the object.
1273  xPackage->revokePackage(true, xAbortChannel, xCmdEnv);
1274  removePackage(xPackage->getIdentifier().Value, xPackage->getName(),
1275  xAbortChannel, xCmdEnv);
1276  bModified = true;
1277  }
1278  }
1279  catch( const uno::Exception & )
1280  {
1281  TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1282  }
1283  }
1284  return bModified;
1285 }
1286 
1287 
1289  Reference<task::XAbortChannel> const & xAbortChannel,
1291 {
1292  bool bModified = false;
1293  OSL_ASSERT(!(m_context == "user"));
1294 
1295  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1296  //check if the folder exist at all. The shared extension folder
1297  //may not exist for a normal user.
1298  bool bOk=true;
1299  try
1300  {
1301  bOk = create_ucb_content(
1303  }
1304  catch (const css::ucb::ContentCreationException&)
1305  {
1306  bOk = false;
1307  }
1308 
1309  if (!bOk)
1310  return bModified;
1311 
1313  Reference<sdbc::XResultSet> xResultSet(
1314  StrTitle::createCursor( tempFolder,
1316 
1317  while (xResultSet->next())
1318  {
1319  try
1320  {
1321  OUString title(
1322  Reference<sdbc::XRow>(
1323  xResultSet, UNO_QUERY_THROW )->getString(
1324  1 /* Title */ ) );
1325  //The temporary folders of user and shared have an '_' at then end.
1326  //But the name in ActivePackages.temporaryName is saved without.
1327  OUString title2 = title;
1328  bool bShared = (m_context == "shared");
1329  if (bShared)
1330  {
1331  OSL_ASSERT(title2.endsWith("_"));
1332  title2 = title2.copy(0, title2.getLength() -1);
1333  }
1334  OUString titleEncoded = ::rtl::Uri::encode(
1335  title2, rtl_UriCharClassPchar,
1336  rtl_UriEncodeIgnoreEscapes,
1337  RTL_TEXTENCODING_UTF8);
1338 
1339  //It is sufficient to check for the folder name, because when the administrator
1340  //installed the extension it was already checked if there is one with the
1341  //same identifier.
1342  const MatchTempDir match(titleEncoded);
1343  if (std::none_of( id2temp.begin(), id2temp.end(), match ))
1344  {
1345 
1346  // The folder was not found in the data base, so it must be
1347  // an added extension
1348  OUString url(m_activePackages_expanded + "/" + titleEncoded);
1349  OUString sExtFolder;
1350  if (bShared) //that is, shared
1351  {
1352  //Check if the extension was not "deleted" already which is indicated
1353  //by a xxx.tmpremoved file
1354  ::ucbhelper::Content contentRemoved;
1355  if (create_ucb_content(&contentRemoved, url + "removed",
1357  continue;
1358  sExtFolder = getExtensionFolder(
1359  m_activePackages_expanded + "/" + titleEncoded + "_",
1360  xCmdEnv, m_xComponentContext);
1362  url = makeURLAppendSysPathSegment(url, sExtFolder);
1363  }
1364  Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1365  url, OUString(), false, OUString(), xCmdEnv );
1366  if (xPackage.is())
1367  {
1368  OUString id = dp_misc::getIdentifier( xPackage );
1369 
1370  //Prepare the database entry
1371  ActivePackages::Data dbData;
1372 
1373  dbData.temporaryName = titleEncoded;
1374  if (bShared)
1375  dbData.fileName = sExtFolder;
1376  else
1377  dbData.fileName = title;
1378  dbData.mediaType = xPackage->getPackageType()->getMediaType();
1379  dbData.version = xPackage->getVersion();
1380  SAL_WARN_IF(
1381  dbData.version.isEmpty(), "desktop.deployment",
1382  "bundled/shared extension " << id << " at <" << url
1383  << "> has no explicit version");
1384 
1385  //We provide a special command environment that will prevent
1386  //showing a license if simple-license/@accept-by = "admin"
1387  //It will also prevent showing the license for bundled extensions
1388  //which is not supported.
1389  OSL_ASSERT(!(m_context == "user"));
1390 
1391  // shall the license be suppressed?
1392  DescriptionInfoset info =
1395  attr = info.getSimpleLicenseAttributes();
1396  ExtensionProperties props(url, xCmdEnv, m_xComponentContext);
1397  bool bNoLicense = false;
1398  if (attr && attr->suppressIfRequired && props.isSuppressedLicense())
1399  bNoLicense = true;
1400 
1401  Reference<ucb::XCommandEnvironment> licCmdEnv(
1402  new LicenseCommandEnv(xCmdEnv->getInteractionHandler(),
1403  bNoLicense, m_context));
1404  sal_Int32 failedPrereq = xPackage->checkPrerequisites(
1405  xAbortChannel, licCmdEnv, false);
1406  //Remember that this failed. For example, the user
1407  //could have declined the license. Then the next time the
1408  //extension folder is investigated we do not want to
1409  //try to install the extension again.
1410  dbData.failedPrerequisites = OUString::number(failedPrereq);
1411  insertToActivationLayerDB(id, dbData);
1412  bModified = true;
1413  }
1414  }
1415  }
1416  catch (const uno::Exception &)
1417  {
1418  // Looks like exceptions being caught here is not an uncommon case.
1419  TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1420  }
1421  }
1422  return bModified;
1423 }
1424 
1426  Reference<task::XAbortChannel> const & xAbortChannel,
1428 {
1429  check();
1430  bool bModified = false;
1431  if (m_context == "user")
1432  return bModified;
1433  bModified |=
1434  synchronizeRemovedExtensions(xAbortChannel, xCmdEnv);
1435  bModified |= synchronizeAddedExtensions(xAbortChannel, xCmdEnv);
1436 
1437  return bModified;
1438 }
1439 
1440 Sequence< Reference<deployment::XPackage> > PackageManagerImpl::getExtensionsWithUnacceptedLicenses(
1441  Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1442 {
1443  std::vector<Reference<deployment::XPackage> > vec;
1444 
1445  try
1446  {
1447  const ::osl::MutexGuard guard( getMutex() );
1448  // clean up activation layer, scan for zombie temp dirs:
1449  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1450 
1451  bool bShared = (m_context == "shared");
1452 
1453  for (auto const& elem : id2temp)
1454  {
1455  //Get the database entry
1456  ActivePackages::Data const & dbData = elem.second;
1457  sal_Int32 failedPrereq = dbData.failedPrerequisites.toInt32();
1458  //If the installation failed for other reason then the license then we
1459  //ignore it.
1460  if (failedPrereq ^= deployment::Prerequisites::LICENSE)
1461  continue;
1462 
1463  //Prepare the URL to the extension
1464  OUString url = makeURL(m_activePackages, elem.second.temporaryName);
1465  if (bShared)
1466  url = makeURLAppendSysPathSegment( url + "_", elem.second.fileName);
1467 
1468  Reference<deployment::XPackage> p = m_xRegistry->bindPackage(
1469  url, OUString(), false, OUString(), xCmdEnv );
1470 
1471  if (p.is())
1472  vec.push_back(p);
1473 
1474  }
1475  return ::comphelper::containerToSequence(vec);
1476  }
1477  catch (const deployment::DeploymentException &)
1478  {
1479  throw;
1480  }
1481  catch (const RuntimeException&)
1482  {
1483  throw;
1484  }
1485  catch (...)
1486  {
1487  Any exc = ::cppu::getCaughtException();
1488  deployment::DeploymentException de(
1489  "PackageManagerImpl::getExtensionsWithUnacceptedLicenses",
1490  static_cast<OWeakObject*>(this), exc);
1491  exc <<= de;
1492  ::cppu::throwException(exc);
1493  }
1494 
1495  return ::comphelper::containerToSequence(vec);
1496 }
1497 
1499  css::uno::Reference<css::deployment::XPackage> const & extension,
1500  css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel,
1501  css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv )
1502 {
1503  try
1504  {
1505  if (!extension.is())
1506  return 0;
1507  if (m_context != extension->getRepositoryName())
1508  throw lang::IllegalArgumentException(
1509  "PackageManagerImpl::checkPrerequisites: extension is not from this repository.",
1510  nullptr, 0);
1511 
1512  ActivePackages::Data dbData;
1513  OUString id = dp_misc::getIdentifier(extension);
1514  if (!m_activePackagesDB->get( &dbData, id, OUString()))
1515  {
1516  throw lang::IllegalArgumentException(
1517  "PackageManagerImpl::checkPrerequisites: unknown extension",
1518  nullptr, 0);
1519 
1520  }
1521  //If the license was already displayed, then do not show it again
1522  Reference<ucb::XCommandEnvironment> _xCmdEnv = xCmdEnv;
1523  sal_Int32 prereq = dbData.failedPrerequisites.toInt32();
1524  if ( !(prereq & deployment::Prerequisites::LICENSE))
1525  _xCmdEnv = new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler());
1526 
1527  sal_Int32 failedPrereq = extension->checkPrerequisites(
1528  xAbortChannel, _xCmdEnv, false);
1529  dbData.failedPrerequisites = OUString::number(failedPrereq);
1530  insertToActivationLayerDB(id, dbData);
1531  return 0;
1532  }
1533  catch ( const deployment::DeploymentException& ) {
1534  throw;
1535  } catch ( const ucb::CommandFailedException & ) {
1536  throw;
1537  } catch ( const ucb::CommandAbortedException & ) {
1538  throw;
1539  } catch (const lang::IllegalArgumentException &) {
1540  throw;
1541  } catch (const uno::RuntimeException &) {
1542  throw;
1543  } catch (...) {
1544  uno::Any excOccurred = ::cppu::getCaughtException();
1545  deployment::DeploymentException exc(
1546  "PackageManagerImpl::checkPrerequisites: exception ",
1547  static_cast<OWeakObject*>(this), excOccurred);
1548  throw exc;
1549  }
1550 }
1551 
1552 
1554 {
1555 }
1556 
1557 
1559  Reference<XCommandEnvironment> const & xUserCmdEnv,
1560  Reference<XProgressHandler> const & xLogFile )
1561  : m_xLogFile( xLogFile )
1562 {
1563  if (xUserCmdEnv.is()) {
1564  m_xUserProgress.set( xUserCmdEnv->getProgressHandler() );
1565  m_xUserInteractionHandler.set( xUserCmdEnv->getInteractionHandler() );
1566  }
1567 }
1568 
1569 // XCommandEnvironment
1570 
1571 Reference<task::XInteractionHandler>
1573 {
1574  return m_xUserInteractionHandler;
1575 }
1576 
1577 
1580 {
1581  return this;
1582 }
1583 
1584 // XProgressHandler
1585 
1587 {
1588  if (m_xLogFile.is())
1589  m_xLogFile->push( Status );
1590  if (m_xUserProgress.is())
1591  m_xUserProgress->push( Status );
1592 }
1593 
1594 
1596 {
1597  if (m_xLogFile.is())
1598  m_xLogFile->update( Status );
1599  if (m_xUserProgress.is())
1600  m_xUserProgress->update( Status );
1601 }
1602 
1603 
1605 {
1606  if (m_xLogFile.is())
1607  m_xLogFile->pop();
1608  if (m_xUserProgress.is())
1609  m_xUserProgress->pop();
1610 }
1611 
1612 } // namespace dp_manager
1613 
1614 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::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
MatchTempDir(OUString const &str)
Definition: dp_manager.cxx:96
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:348
OUString makeURL(OUString const &baseURL, OUString const &relPath_)
appends a relative path to a url.
Definition: dp_misc.cxx:266
OUString makeURLAppendSysPathSegment(OUString const &baseURL, OUString const &segment)
appends a relative path to a url.
Definition: dp_misc.cxx:296
OUString detectMediaType(::ucbhelper::Content const &ucbContent, bool throw_exc=true)
Definition: dp_manager.cxx:574
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()
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
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
bool operator()(ActivePackages::Entries::value_type const &v) const
Definition: dp_manager.cxx:97
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:330
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:1858
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
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
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
::boost::optional< OUString > getIdentifier() const
Return the identifier.
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