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