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  destFolder += "_";
627 
628  // prepare activation folder:
629  ::ucbhelper::Content destFolderContent;
630  create_folder( &destFolderContent, destFolder, xCmdEnv );
631 
632  // copy content into activation temp dir:
633  if (mediaType.matchIgnoreAsciiCase("application/vnd.sun.star.package-bundle") ||
634  // xxx todo: more sophisticated parsing
635  mediaType.matchIgnoreAsciiCase("application/vnd.sun.star.legacy-package-bundle"))
636  {
637  // inflate content:
638  OUStringBuffer buf;
639  if (!sourceContent.isFolder())
640  {
641  buf.append( "vnd.sun.star.zip://" );
642  buf.append( ::rtl::Uri::encode( sourceContent.getURL(),
643  rtl_UriCharClassRegName,
644  rtl_UriEncodeIgnoreEscapes,
645  RTL_TEXTENCODING_UTF8 ) );
646  }
647  else
648  {
649  //Folder. No need to unzip, just copy
650  buf.append(sourceContent.getURL());
651  }
652  buf.append( '/' );
653  sourceContent = ::ucbhelper::Content(
654  buf.makeStringAndClear(), xCmdEnv, m_xComponentContext );
655  }
656  destFolderContent.transferContent(
657  sourceContent, ::ucbhelper::InsertOperation::Copy,
658  title, NameClash::OVERWRITE );
659 
660 
661  // write to DB:
662  //bundled extensions should only be added by the synchronizeAddedExtensions
663  //functions. Moreover, there is no "temporary folder" for bundled extensions.
664  OSL_ASSERT(!(m_context == "bundled"));
665  OUString sFolderUrl = makeURLAppendSysPathSegment(destFolderContent.getURL(), title);
666  DescriptionInfoset info =
667  dp_misc::getDescriptionInfoset(sFolderUrl);
668  dbData->temporaryName = tempEntry;
669  dbData->fileName = title;
670  dbData->mediaType = mediaType;
671  dbData->version = info.getVersion();
672 
673  //No write the properties file next to the extension
674  ExtensionProperties props(sFolderUrl, properties, xCmdEnv, m_xComponentContext);
675  props.write();
676  return destFolder;
677 }
678 
679 
681  OUString const & id, ActivePackages::Data const & dbData )
682 {
683  //access to the database must be guarded. See removePackage
684  const ::osl::MutexGuard guard( getMutex() );
685  m_activePackagesDB->put( id, dbData );
686 }
687 
688 
689 /* The function returns true if there is an extension with the same id already
690  installed which needs to be uninstalled, before the new extension can be installed.
691 */
693  Reference<deployment::XPackage> const & package)
694 {
695  OUString id(dp_misc::getIdentifier(package));
696  OUString fn(package->getName());
697  bool bInstalled = false;
698  if (m_activePackagesDB->has( id, fn ))
699  {
700  bInstalled = true;
701  }
702  return bInstalled;
703 }
704 
705 // XPackageManager
706 
707 Reference<deployment::XPackage> PackageManagerImpl::importExtension(
708  Reference<deployment::XPackage> const & extension,
709  Reference<task::XAbortChannel> const & xAbortChannel,
710  Reference<XCommandEnvironment> const & xCmdEnv_ )
711 {
712  return addPackage(extension->getURL(), Sequence<beans::NamedValue>(),
713  OUString(), xAbortChannel, xCmdEnv_);
714 }
715 
716 /* The function adds an extension but does not register it!!!
717  It may not do any user interaction. This is done in XExtensionManager::addExtension
718 */
719 Reference<deployment::XPackage> PackageManagerImpl::addPackage(
720  OUString const & url,
721  css::uno::Sequence<css::beans::NamedValue> const & properties,
722  OUString const & mediaType_,
723  Reference<task::XAbortChannel> const & xAbortChannel,
724  Reference<XCommandEnvironment> const & xCmdEnv_ )
725 {
726  check();
727  if (m_readOnly)
728  {
729  OUString message;
730  if (m_context == "shared")
731  message = "You need write permissions to install a shared extension!";
732  else
733  message = "You need write permissions to install this extension!";
734  throw deployment::DeploymentException(
735  message, static_cast<OWeakObject *>(this), Any() );
736  }
738  if (m_xLogFile.is())
739  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
740  else
741  xCmdEnv.set( xCmdEnv_ );
742 
743  try {
744  ::ucbhelper::Content sourceContent;
745  (void)create_ucb_content( &sourceContent, url, xCmdEnv ); // throws exc
746  const OUString title( StrTitle::getTitle( sourceContent ) );
747  const OUString title_enc( ::rtl::Uri::encode(
748  title, rtl_UriCharClassPchar,
749  rtl_UriEncodeIgnoreEscapes,
750  RTL_TEXTENCODING_UTF8 ) );
751  OUString destFolder;
752 
753  OUString mediaType(mediaType_);
754  if (mediaType.isEmpty())
755  mediaType = detectMediaType( sourceContent );
756 
757  Reference<deployment::XPackage> xPackage;
758  // copy file:
760  DpResId(RID_STR_COPYING_PACKAGE) + title, xCmdEnv );
761  if (m_activePackages.isEmpty())
762  {
763  ::ucbhelper::Content docFolderContent;
764  create_folder( &docFolderContent, m_context, xCmdEnv );
765  // copy into document, first:
766  docFolderContent.transferContent(
767  sourceContent, ::ucbhelper::InsertOperation::Copy,
768  OUString(),
769  NameClash::ASK /* xxx todo: ASK not needed? */);
770  // set media-type:
771  ::ucbhelper::Content docContent(
772  makeURL( m_context, title_enc ), xCmdEnv, m_xComponentContext );
773  //TODO #i73136#: using title instead of id can lead to
774  // clashes, but the whole m_activePackages.getLength()==0
775  // case (i.e., document-relative deployment) currently does
776  // not work, anyway.
777  docContent.setPropertyValue("MediaType", Any(mediaType) );
778 
779  // xxx todo: obsolete in the future
780  try {
781  docFolderContent.executeCommand( "flush", Any() );
782  }
783  catch (const UnsupportedCommandException &) {
784  }
785  }
786  ActivePackages::Data dbData;
787  destFolder = insertToActivationLayer(
788  properties, mediaType, sourceContent, title, &dbData );
789 
790 
791  // bind activation package:
792  //Because every shared/user extension will be unpacked in a folder,
793  //which was created with a unique name we will always have two different
794  //XPackage objects, even if the second extension is the same.
795  //Therefore bindPackage does not need a guard here.
796  xPackage = m_xRegistry->bindPackage(
797  makeURL( destFolder, title_enc ), mediaType, false, OUString(), xCmdEnv );
798 
799  OSL_ASSERT( xPackage.is() );
800  if (xPackage.is())
801  {
802  bool install = false;
803  try
804  {
805  OUString const id = dp_misc::getIdentifier( xPackage );
806 
807  ::osl::MutexGuard g(m_addMutex);
808  if (isInstalled(xPackage))
809  {
810  //Do not guard the complete function with the getMutex
811  removePackage(id, xPackage->getName(), xAbortChannel,
812  xCmdEnv);
813  }
814  install = true;
815  insertToActivationLayerDB(id, dbData);
816  }
817  catch (...)
818  {
819  deletePackageFromCache( xPackage, destFolder );
820  throw;
821  }
822  if (!install)
823  {
824  deletePackageFromCache( xPackage, destFolder );
825  }
826  //ToDo: We should notify only if the extension is registered
827  fireModified();
828  }
829  return xPackage;
830  }
831  catch (const RuntimeException &) {
832  throw;
833  }
834  catch (const CommandFailedException & exc) {
835  logIntern( Any(exc) );
836  throw;
837  }
838  catch (const CommandAbortedException & exc) {
839  logIntern( Any(exc) );
840  throw;
841  }
842  catch (const deployment::DeploymentException & exc) {
843  logIntern( Any(exc) );
844  throw;
845  }
846  catch (const Exception &) {
847  Any exc( ::cppu::getCaughtException() );
848  logIntern( exc );
849  throw deployment::DeploymentException(
850  DpResId(RID_STR_ERROR_WHILE_ADDING) + url,
851  static_cast<OWeakObject *>(this), exc );
852  }
853 }
855  Reference<deployment::XPackage> const & xPackage,
856  OUString const & destFolder)
857 {
858  try_dispose( xPackage );
859 
860  //we remove the package from the uno cache
861  //no service from the package may be loaded at this time!!!
863  false /* no throw: ignore errors */ );
864  //rm last character '_'
865  OUString url = destFolder.copy(0, destFolder.getLength() - 1);
867  false /* no throw: ignore errors */ );
868 
869 }
870 
872  OUString const & id, OUString const & fileName,
873  Reference<task::XAbortChannel> const & /*xAbortChannel*/,
874  Reference<XCommandEnvironment> const & xCmdEnv_ )
875 {
876  check();
877 
879  if (m_xLogFile.is())
880  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
881  else
882  xCmdEnv.set( xCmdEnv_ );
883 
884  try {
885  Reference<deployment::XPackage> xPackage;
886  {
887  const ::osl::MutexGuard guard(getMutex());
888  //Check if this extension exist and throw an IllegalArgumentException
889  //if it does not
890  //If the files of the extension are already removed, or there is a
891  //different extension at the same place, for example after updating the
892  //extension, then the returned object is that which uses the database data.
893  xPackage = getDeployedPackage_(id, fileName, xCmdEnv );
894 
895 
896  //Because the extension is only removed the next time the extension
897  //manager runs after restarting OOo, we need to indicate that a
898  //shared extension was "deleted". When a user starts OOo, then it
899  //will check if something changed in the shared repository. Based on
900  //the flag file it will then recognize, that the extension was
901  //deleted and can then update the extension database of the shared
902  //extensions in the user installation.
903  if ( xPackage.is() && !m_readOnly && !xPackage->isRemoved() && (m_context == "shared"))
904  {
906  m_activePackagesDB->get( & val, id, fileName);
907  OSL_ASSERT(!val.temporaryName.isEmpty());
908  OUString url(makeURL(m_activePackages_expanded,
909  val.temporaryName + "removed"));
910  ::ucbhelper::Content contentRemoved(url, xCmdEnv, m_xComponentContext);
911  OUString aUserName;
912  ::osl::Security aSecurity;
913  aSecurity.getUserName( aUserName );
914 
915  OString stamp = OUStringToOString(aUserName, RTL_TEXTENCODING_UTF8);
916  Reference<css::io::XInputStream> xData(
918  reinterpret_cast<sal_Int8 const *>(stamp.getStr()),
919  stamp.getLength() ) );
920  contentRemoved.writeStream( xData, true /* replace existing */ );
921  }
922  m_activePackagesDB->erase( id, fileName ); // to be removed upon next start
923  //remove any cached data hold by the backend
924  m_xRegistry->packageRemoved(xPackage->getURL(), xPackage->getPackageType()->getMediaType());
925  }
926  try_dispose( xPackage );
927 
928  fireModified();
929  }
930  catch (const RuntimeException &) {
931  throw;
932  }
933  catch (const CommandFailedException & exc) {
934  logIntern( Any(exc) );
935  throw;
936  }
937  catch (const CommandAbortedException & exc) {
938  logIntern( Any(exc) );
939  throw;
940  }
941  catch (const deployment::DeploymentException & exc) {
942  logIntern( Any(exc) );
943  throw;
944  }
945  catch (const Exception &) {
946  Any exc( ::cppu::getCaughtException() );
947  logIntern( exc );
948  throw deployment::DeploymentException(
949  DpResId(RID_STR_ERROR_WHILE_REMOVING) + id,
950  static_cast<OWeakObject *>(this), exc );
951  }
952 }
953 
954 
956 {
957  OUStringBuffer buf;
958  buf.append( data.temporaryName );
959  //The bundled extensions are not contained in an additional folder
960  //with a unique name. data.temporaryName contains already the
961  //UTF8 encoded folder name. See PackageManagerImpl::synchronize
962  if (m_context != "bundled")
963  {
964  buf.append( "_/" );
965  buf.append( ::rtl::Uri::encode( data.fileName, rtl_UriCharClassPchar,
966  rtl_UriEncodeIgnoreEscapes,
967  RTL_TEXTENCODING_UTF8 ) );
968  }
969  return makeURL( m_activePackages, buf.makeStringAndClear() );
970 }
971 
972 
973 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
974  OUString const & id, OUString const & fileName,
975  Reference<XCommandEnvironment> const & xCmdEnv )
976 {
978  if (m_activePackagesDB->get( &val, id, fileName ))
979  {
980  return getDeployedPackage_( id, val, xCmdEnv );
981  }
982  throw lang::IllegalArgumentException(
983  DpResId(RID_STR_NO_SUCH_PACKAGE) + id,
984  static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
985 }
986 
987 
988 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
989  OUString const & id, ActivePackages::Data const & data,
990  Reference<XCommandEnvironment> const & xCmdEnv, bool ignoreAlienPlatforms )
991 {
992  if (ignoreAlienPlatforms)
993  {
994  OUString type, subType;
996  if (INetContentTypes::parse( data.mediaType, type, subType, &params ))
997  {
998  auto const iter = params.find(OString("platform"));
999  if (iter != params.end() && !platform_fits(iter->second.m_sValue))
1000  throw lang::IllegalArgumentException(
1001  DpResId(RID_STR_NO_SUCH_PACKAGE) + id,
1002  static_cast<OWeakObject *>(this),
1003  static_cast<sal_Int16>(-1) );
1004  }
1005  }
1006  Reference<deployment::XPackage> xExtension;
1007  try
1008  {
1009  //Ignore extensions where XPackage::checkPrerequisites failed.
1010  //They must not be usable for this user.
1011  if (data.failedPrerequisites == "0")
1012  {
1013  xExtension = m_xRegistry->bindPackage(
1014  getDeployPath( data ), data.mediaType, false, OUString(), xCmdEnv );
1015  }
1016  }
1017  catch (const deployment::InvalidRemovedParameterException& e)
1018  {
1019  xExtension = e.Extension;
1020  }
1021  return xExtension;
1022 }
1023 
1024 
1025 Sequence< Reference<deployment::XPackage> >
1027  Reference<XCommandEnvironment> const & xCmdEnv )
1028 {
1029  std::vector< Reference<deployment::XPackage> > packages;
1030  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1031  for (auto const& elem : id2temp)
1032  {
1033  if (elem.second.failedPrerequisites != "0")
1034  continue;
1035  try {
1036  packages.push_back(
1038  elem.first, elem.second, xCmdEnv,
1039  true /* xxx todo: think of GUI:
1040  ignore other platforms than the current one */ ) );
1041  }
1042  catch (const lang::IllegalArgumentException &) {
1043  // ignore
1044  TOOLS_WARN_EXCEPTION( "desktop", "" );
1045  }
1046  catch (const deployment::DeploymentException&) {
1047  // ignore
1048  TOOLS_WARN_EXCEPTION( "desktop", "" );
1049  }
1050  }
1051  return comphelper::containerToSequence(packages);
1052 }
1053 
1054 
1055 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage(
1056  OUString const & id, OUString const & fileName,
1057  Reference<XCommandEnvironment> const & xCmdEnv_ )
1058 {
1059  check();
1061  if (m_xLogFile.is())
1062  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1063  else
1064  xCmdEnv.set( xCmdEnv_ );
1065 
1066  try {
1067  const ::osl::MutexGuard guard( getMutex() );
1068  return getDeployedPackage_( id, fileName, xCmdEnv );
1069  }
1070  catch (const lang::IllegalArgumentException & exc) {
1071  logIntern( Any(exc) );
1072  throw;
1073  }
1074  catch (const RuntimeException &) {
1075  throw;
1076  }
1077  catch (const CommandFailedException & exc) {
1078  logIntern( Any(exc) );
1079  throw;
1080  }
1081  catch (const deployment::DeploymentException & exc) {
1082  logIntern( Any(exc) );
1083  throw;
1084  }
1085  catch (const Exception &) {
1086  Any exc( ::cppu::getCaughtException() );
1087  logIntern( exc );
1088  throw deployment::DeploymentException(
1089  // ought never occur...
1090  "error while accessing deployed package: " + id,
1091  static_cast<OWeakObject *>(this), exc );
1092  }
1093 }
1094 
1095 
1096 Sequence< Reference<deployment::XPackage> >
1098  Reference<task::XAbortChannel> const &,
1099  Reference<XCommandEnvironment> const & xCmdEnv_ )
1100 {
1101  check();
1103  if (m_xLogFile.is())
1104  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1105  else
1106  xCmdEnv.set( xCmdEnv_ );
1107 
1108  try {
1109  const ::osl::MutexGuard guard( getMutex() );
1110  return getDeployedPackages_( xCmdEnv );
1111  }
1112  catch (const RuntimeException &) {
1113  throw;
1114  }
1115  catch (const CommandFailedException & exc) {
1116  logIntern( Any(exc) );
1117  throw;
1118  }
1119  catch (const CommandAbortedException & exc) {
1120  logIntern( Any(exc) );
1121  throw;
1122  }
1123  catch (const deployment::DeploymentException & exc) {
1124  logIntern( Any(exc) );
1125  throw;
1126  }
1127  catch (const Exception &) {
1128  Any exc( ::cppu::getCaughtException() );
1129  logIntern( exc );
1130  throw deployment::DeploymentException(
1131  // ought never occur...
1132  "error while getting all deployed packages: " + m_context,
1133  static_cast<OWeakObject *>(this), exc );
1134  }
1135 }
1136 
1137 
1138 //ToDo: the function must not call registerPackage, do this in
1139 //XExtensionManager.reinstallDeployedExtensions
1141  sal_Bool force, Reference<task::XAbortChannel> const & /*xAbortChannel*/,
1142  Reference<XCommandEnvironment> const & xCmdEnv_ )
1143 {
1144  check();
1145  if (!force && office_is_running())
1146  throw RuntimeException(
1147  "You must close any running Office process before reinstalling packages!",
1148  static_cast<OWeakObject *>(this) );
1149 
1151  if (m_xLogFile.is())
1152  xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1153  else
1154  xCmdEnv.set( xCmdEnv_ );
1155 
1156  try {
1157  ProgressLevel progress(
1158  xCmdEnv, "Reinstalling all deployed packages..." );
1159 
1161  m_xRegistry.clear();
1162  if (!m_registryCache.isEmpty())
1163  erase_path( m_registryCache, xCmdEnv );
1165  Reference<util::XUpdatable> xUpdatable( m_xRegistry, UNO_QUERY );
1166  if (xUpdatable.is())
1167  xUpdatable->update();
1168 
1169  //registering is done by the ExtensionManager service.
1170  }
1171  catch (const RuntimeException &) {
1172  throw;
1173  }
1174  catch (const CommandFailedException & exc) {
1175  logIntern( Any(exc) );
1176  throw;
1177  }
1178  catch (const CommandAbortedException & exc) {
1179  logIntern( Any(exc) );
1180  throw;
1181  }
1182  catch (const deployment::DeploymentException & exc) {
1183  logIntern( Any(exc) );
1184  throw;
1185  }
1186  catch (const Exception &) {
1187  Any exc( ::cppu::getCaughtException() );
1188  logIntern( exc );
1189  throw deployment::DeploymentException(
1190  "Error while reinstalling all previously deployed packages of context " + m_context,
1191  static_cast<OWeakObject *>(this), exc );
1192  }
1193 }
1194 
1195 
1197 {
1198  return m_readOnly;
1199 }
1201  Reference<task::XAbortChannel> const & xAbortChannel,
1203 {
1204 
1205  //find all which are in the extension data base but which
1206  //are removed already.
1207  OSL_ASSERT(!(m_context == "user"));
1208  bool bModified = false;
1209  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1210 
1211  bool bShared = (m_context == "shared");
1212 
1213  for (auto const& elem : id2temp)
1214  {
1215  try
1216  {
1217  //Get the URL to the extensions folder, first make the url for the
1218  //shared repository including the temporary name
1219  OUString url = makeURL(m_activePackages, elem.second.temporaryName);
1220  if (bShared)
1221  url = makeURLAppendSysPathSegment( url + "_", elem.second.fileName);
1222 
1223  bool bRemoved = false;
1224  //Check if the URL to the extension is still the same
1225  ::ucbhelper::Content contentExtension;
1226 
1227  if (!create_ucb_content(
1228  &contentExtension, url,
1230  {
1231  bRemoved = true;
1232  }
1233 
1234  //The folder is in the extension database, but it can still be deleted.
1235  //look for the xxx.tmpremoved file
1236  //There can also be the case that a different extension was installed
1237  //in a "temp" folder with name that is already used.
1238  if (!bRemoved && bShared)
1239  {
1240  ::ucbhelper::Content contentRemoved;
1241 
1242  if (create_ucb_content(
1243  &contentRemoved,
1245  elem.second.temporaryName + "removed",
1247  {
1248  bRemoved = true;
1249  }
1250  }
1251 
1252  if (!bRemoved)
1253  {
1254  //There may be another extensions at the same place
1255  dp_misc::DescriptionInfoset infoset =
1257  OSL_ENSURE(infoset.hasDescription() && infoset.getIdentifier(),
1258  "Extension Manager: bundled and shared extensions "
1259  "must have an identifier and a version");
1260  if (infoset.hasDescription() &&
1261  infoset.getIdentifier() &&
1262  ( elem.first != *(infoset.getIdentifier())
1263  || elem.second.version != infoset.getVersion()))
1264  {
1265  bRemoved = true;
1266  }
1267 
1268  }
1269  if (bRemoved)
1270  {
1271  Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1272  url, elem.second.mediaType, true, elem.first, xCmdEnv );
1273  OSL_ASSERT(xPackage.is()); //Even if the files are removed, we must get the object.
1274  xPackage->revokePackage(true, xAbortChannel, xCmdEnv);
1275  removePackage(xPackage->getIdentifier().Value, xPackage->getName(),
1276  xAbortChannel, xCmdEnv);
1277  bModified = true;
1278  }
1279  }
1280  catch( const uno::Exception & )
1281  {
1282  TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1283  }
1284  }
1285  return bModified;
1286 }
1287 
1288 
1290  Reference<task::XAbortChannel> const & xAbortChannel,
1292 {
1293  bool bModified = false;
1294  OSL_ASSERT(!(m_context == "user"));
1295 
1296  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1297  //check if the folder exist at all. The shared extension folder
1298  //may not exist for a normal user.
1299  bool bOk=true;
1300  try
1301  {
1302  bOk = create_ucb_content(
1304  }
1305  catch (const css::ucb::ContentCreationException&)
1306  {
1307  bOk = false;
1308  }
1309 
1310  if (!bOk)
1311  return bModified;
1312 
1314  Reference<sdbc::XResultSet> xResultSet(
1315  StrTitle::createCursor( tempFolder,
1317 
1318  while (xResultSet->next())
1319  {
1320  try
1321  {
1322  OUString title(
1323  Reference<sdbc::XRow>(
1324  xResultSet, UNO_QUERY_THROW )->getString(
1325  1 /* Title */ ) );
1326  //The temporary folders of user and shared have an '_' at then end.
1327  //But the name in ActivePackages.temporaryName is saved without.
1328  OUString title2 = title;
1329  bool bShared = (m_context == "shared");
1330  if (bShared)
1331  {
1332  OSL_ASSERT(title2.endsWith("_"));
1333  title2 = title2.copy(0, title2.getLength() -1);
1334  }
1335  OUString titleEncoded = ::rtl::Uri::encode(
1336  title2, rtl_UriCharClassPchar,
1337  rtl_UriEncodeIgnoreEscapes,
1338  RTL_TEXTENCODING_UTF8);
1339 
1340  //It is sufficient to check for the folder name, because when the administrator
1341  //installed the extension it was already checked if there is one with the
1342  //same identifier.
1343  const MatchTempDir match(titleEncoded);
1344  if (std::none_of( id2temp.begin(), id2temp.end(), match ))
1345  {
1346 
1347  // The folder was not found in the data base, so it must be
1348  // an added extension
1349  OUString url(m_activePackages_expanded + "/" + titleEncoded);
1350  OUString sExtFolder;
1351  if (bShared) //that is, shared
1352  {
1353  //Check if the extension was not "deleted" already which is indicated
1354  //by a xxx.tmpremoved file
1355  ::ucbhelper::Content contentRemoved;
1356  if (create_ucb_content(&contentRemoved, url + "removed",
1358  continue;
1359  sExtFolder = getExtensionFolder(
1360  m_activePackages_expanded + "/" + titleEncoded + "_",
1361  xCmdEnv, m_xComponentContext);
1363  url = makeURLAppendSysPathSegment(url, sExtFolder);
1364  }
1365  Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1366  url, OUString(), false, OUString(), xCmdEnv );
1367  if (xPackage.is())
1368  {
1369  OUString id = dp_misc::getIdentifier( xPackage );
1370 
1371  //Prepare the database entry
1372  ActivePackages::Data dbData;
1373 
1374  dbData.temporaryName = titleEncoded;
1375  if (bShared)
1376  dbData.fileName = sExtFolder;
1377  else
1378  dbData.fileName = title;
1379  dbData.mediaType = xPackage->getPackageType()->getMediaType();
1380  dbData.version = xPackage->getVersion();
1381  SAL_WARN_IF(
1382  dbData.version.isEmpty(), "desktop.deployment",
1383  "bundled/shared extension " << id << " at <" << url
1384  << "> has no explicit version");
1385 
1386  //We provide a special command environment that will prevent
1387  //showing a license if simple-license/@accept-by = "admin"
1388  //It will also prevent showing the license for bundled extensions
1389  //which is not supported.
1390  OSL_ASSERT(!(m_context == "user"));
1391 
1392  // shall the license be suppressed?
1393  DescriptionInfoset info =
1396  attr = info.getSimpleLicenseAttributes();
1397  ExtensionProperties props(url, xCmdEnv, m_xComponentContext);
1398  bool bNoLicense = false;
1399  if (attr && attr->suppressIfRequired && props.isSuppressedLicense())
1400  bNoLicense = true;
1401 
1402  Reference<ucb::XCommandEnvironment> licCmdEnv(
1403  new LicenseCommandEnv(xCmdEnv->getInteractionHandler(),
1404  bNoLicense, m_context));
1405  sal_Int32 failedPrereq = xPackage->checkPrerequisites(
1406  xAbortChannel, licCmdEnv, false);
1407  //Remember that this failed. For example, the user
1408  //could have declined the license. Then the next time the
1409  //extension folder is investigated we do not want to
1410  //try to install the extension again.
1411  dbData.failedPrerequisites = OUString::number(failedPrereq);
1412  insertToActivationLayerDB(id, dbData);
1413  bModified = true;
1414  }
1415  }
1416  }
1417  catch (const uno::Exception &)
1418  {
1419  // Looks like exceptions being caught here is not an uncommon case.
1420  TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1421  }
1422  }
1423  return bModified;
1424 }
1425 
1427  Reference<task::XAbortChannel> const & xAbortChannel,
1429 {
1430  check();
1431  bool bModified = false;
1432  if (m_context == "user")
1433  return bModified;
1434  bModified |=
1435  synchronizeRemovedExtensions(xAbortChannel, xCmdEnv);
1436  bModified |= synchronizeAddedExtensions(xAbortChannel, xCmdEnv);
1437 
1438  return bModified;
1439 }
1440 
1441 Sequence< Reference<deployment::XPackage> > PackageManagerImpl::getExtensionsWithUnacceptedLicenses(
1442  Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1443 {
1444  std::vector<Reference<deployment::XPackage> > vec;
1445 
1446  try
1447  {
1448  const ::osl::MutexGuard guard( getMutex() );
1449  // clean up activation layer, scan for zombie temp dirs:
1450  ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1451 
1452  bool bShared = (m_context == "shared");
1453 
1454  for (auto const& elem : id2temp)
1455  {
1456  //Get the database entry
1457  ActivePackages::Data const & dbData = elem.second;
1458  sal_Int32 failedPrereq = dbData.failedPrerequisites.toInt32();
1459  //If the installation failed for other reason then the license then we
1460  //ignore it.
1461  if (failedPrereq ^= deployment::Prerequisites::LICENSE)
1462  continue;
1463 
1464  //Prepare the URL to the extension
1465  OUString url = makeURL(m_activePackages, elem.second.temporaryName);
1466  if (bShared)
1467  url = makeURLAppendSysPathSegment( url + "_", elem.second.fileName);
1468 
1469  Reference<deployment::XPackage> p = m_xRegistry->bindPackage(
1470  url, OUString(), false, OUString(), xCmdEnv );
1471 
1472  if (p.is())
1473  vec.push_back(p);
1474 
1475  }
1476  return ::comphelper::containerToSequence(vec);
1477  }
1478  catch (const deployment::DeploymentException &)
1479  {
1480  throw;
1481  }
1482  catch (const RuntimeException&)
1483  {
1484  throw;
1485  }
1486  catch (...)
1487  {
1488  Any exc = ::cppu::getCaughtException();
1489  deployment::DeploymentException de(
1490  "PackageManagerImpl::getExtensionsWithUnacceptedLicenses",
1491  static_cast<OWeakObject*>(this), exc);
1492  exc <<= de;
1493  ::cppu::throwException(exc);
1494  }
1495 
1496  return ::comphelper::containerToSequence(vec);
1497 }
1498 
1500  css::uno::Reference<css::deployment::XPackage> const & extension,
1501  css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel,
1502  css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv )
1503 {
1504  try
1505  {
1506  if (!extension.is())
1507  return 0;
1508  if (m_context != extension->getRepositoryName())
1509  throw lang::IllegalArgumentException(
1510  "PackageManagerImpl::checkPrerequisites: extension is not from this repository.",
1511  nullptr, 0);
1512 
1513  ActivePackages::Data dbData;
1514  OUString id = dp_misc::getIdentifier(extension);
1515  if (!m_activePackagesDB->get( &dbData, id, OUString()))
1516  {
1517  throw lang::IllegalArgumentException(
1518  "PackageManagerImpl::checkPrerequisites: unknown extension",
1519  nullptr, 0);
1520 
1521  }
1522  //If the license was already displayed, then do not show it again
1523  Reference<ucb::XCommandEnvironment> _xCmdEnv = xCmdEnv;
1524  sal_Int32 prereq = dbData.failedPrerequisites.toInt32();
1525  if ( !(prereq & deployment::Prerequisites::LICENSE))
1526  _xCmdEnv = new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler());
1527 
1528  sal_Int32 failedPrereq = extension->checkPrerequisites(
1529  xAbortChannel, _xCmdEnv, false);
1530  dbData.failedPrerequisites = OUString::number(failedPrereq);
1531  insertToActivationLayerDB(id, dbData);
1532  return 0;
1533  }
1534  catch ( const deployment::DeploymentException& ) {
1535  throw;
1536  } catch ( const ucb::CommandFailedException & ) {
1537  throw;
1538  } catch ( const ucb::CommandAbortedException & ) {
1539  throw;
1540  } catch (const lang::IllegalArgumentException &) {
1541  throw;
1542  } catch (const uno::RuntimeException &) {
1543  throw;
1544  } catch (...) {
1545  uno::Any excOccurred = ::cppu::getCaughtException();
1546  deployment::DeploymentException exc(
1547  "PackageManagerImpl::checkPrerequisites: exception ",
1548  static_cast<OWeakObject*>(this), excOccurred);
1549  throw exc;
1550  }
1551 }
1552 
1553 
1555 {
1556 }
1557 
1558 
1560  Reference<XCommandEnvironment> const & xUserCmdEnv,
1561  Reference<XProgressHandler> const & xLogFile )
1562  : m_xLogFile( xLogFile )
1563 {
1564  if (xUserCmdEnv.is()) {
1565  m_xUserProgress.set( xUserCmdEnv->getProgressHandler() );
1566  m_xUserInteractionHandler.set( xUserCmdEnv->getInteractionHandler() );
1567  }
1568 }
1569 
1570 // XCommandEnvironment
1571 
1572 Reference<task::XInteractionHandler>
1574 {
1575  return m_xUserInteractionHandler;
1576 }
1577 
1578 
1581 {
1582  return this;
1583 }
1584 
1585 // XProgressHandler
1586 
1588 {
1589  if (m_xLogFile.is())
1590  m_xLogFile->push( Status );
1591  if (m_xUserProgress.is())
1592  m_xUserProgress->push( Status );
1593 }
1594 
1595 
1597 {
1598  if (m_xLogFile.is())
1599  m_xLogFile->update( Status );
1600  if (m_xUserProgress.is())
1601  m_xUserProgress->update( Status );
1602 }
1603 
1604 
1606 {
1607  if (m_xLogFile.is())
1608  m_xLogFile->pop();
1609  if (m_xUserProgress.is())
1610  m_xUserProgress->pop();
1611 }
1612 
1613 } // namespace dp_manager
1614 
1615 /* 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:871
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:854
Any SAL_CALL getCaughtException()
std::vector< std::pair< OUString, Data > > Entries
void insertToActivationLayerDB(OUString const &id, ActivePackages::Data const &dbData)
Definition: dp_manager.cxx:680
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:647
bool isInstalled(css::uno::Reference< css::deployment::XPackage > const &package)
Definition: dp_manager.cxx:692
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:1798
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:707
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:719
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:955
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