Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / desktop / source / deployment / manager / dp_manager.cxx
blobac814592daf8715e500c81a517ca02c26191bf38
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_features.h>
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>
42 #include <cppuhelper/interfacecontainer.hxx>
43 #include <comphelper/logging.hxx>
44 #include <comphelper/servicedecl.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>
73 #include <dp_descriptioninfoset.hxx>
74 #include "dp_commandenvironments.hxx"
75 #include "dp_properties.hxx"
77 #include <vector>
78 #include <list>
79 #include <algorithm>
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;
87 namespace dp_log {
88 extern comphelper::service_decl::ServiceDecl const serviceDecl;
91 namespace dp_manager {
93 struct MatchTempDir
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 );
103 namespace {
104 OUString getExtensionFolder(OUString const & parentFolder,
105 Reference<ucb::XCommandEnvironment> const & xCmdEnv,
106 Reference<uno::XComponentContext> const & xContext)
108 ::ucbhelper::Content tempFolder( parentFolder, xCmdEnv, xContext );
109 Reference<sdbc::XResultSet> xResultSet(
110 StrTitle::createCursor (tempFolder, ::ucbhelper::INCLUDE_FOLDERS_ONLY ) );
112 OUString title;
113 if (xResultSet->next())
115 title = Reference<sdbc::XRow>(
116 xResultSet, UNO_QUERY_THROW )->getString(1 /* Title */ ) ;
118 return title;
122 void PackageManagerImpl::initActivationLayer(
123 Reference<XCommandEnvironment> const & xCmdEnv )
125 if (m_activePackages.isEmpty())
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 */ ))
134 // scan for all entries in m_packagesDir:
135 Reference<sdbc::XResultSet> xResultSet(
136 StrTitle::createCursor (ucbContent, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS ) );
138 while (xResultSet->next())
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;
148 ::ucbhelper::Content sourceContent(
149 Reference<XContentAccess>(
150 xResultSet, UNO_QUERY_THROW )->queryContent(),
151 xCmdEnv, m_xComponentContext );
153 OUString mediaType( detectMediaType( sourceContent,
154 false /* no throw */) );
155 if (!mediaType.isEmpty())
157 ActivePackages::Data dbData;
158 insertToActivationLayer(
159 Sequence<css::beans::NamedValue>(),mediaType, sourceContent,
160 title, &dbData );
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.
171 else
173 // user|share:
174 OSL_ASSERT( !m_activePackages.isEmpty() );
175 m_activePackages_expanded = expandUnoRcUrl( m_activePackages );
176 m_registrationData_expanded = expandUnoRcUrl(m_registrationData);
177 if (!m_readOnly)
178 create_folder( nullptr, m_activePackages_expanded, xCmdEnv);
180 OUString dbName;
181 if (m_context == "user")
182 dbName = m_activePackages_expanded + ".pmap";
183 else
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";
189 // The data base can always be written because it is always in the user installation
190 m_activePackagesDB.reset( new ActivePackages( dbName ) );
192 if (! m_readOnly && m_context != "bundled")
194 // clean up activation layer, scan for zombie temp dirs:
195 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
197 ::ucbhelper::Content tempFolder( m_activePackages_expanded, xCmdEnv, m_xComponentContext );
198 Reference<sdbc::XResultSet> xResultSet(
199 StrTitle::createCursor (tempFolder,
200 ::ucbhelper::INCLUDE_DOCUMENTS_ONLY ) );
202 // get all temp directories:
203 std::vector<OUString> tempEntries;
204 std::vector<OUString> removedEntries;
205 while (xResultSet->next())
207 OUString title(
208 Reference<sdbc::XRow>(
209 xResultSet, UNO_QUERY_THROW )->getString(
210 1 /* Title */ ) );
211 if (title.endsWith("removed", &title))
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 ) );
219 else
221 tempEntries.push_back( ::rtl::Uri::encode(
222 title, rtl_UriCharClassPchar,
223 rtl_UriEncodeIgnoreEscapes,
224 RTL_TEXTENCODING_UTF8 ) );
228 bool bShared = (m_context == "shared");
229 for (const OUString & tempEntry : tempEntries)
231 const MatchTempDir match( tempEntry );
232 if (std::none_of( id2temp.begin(), id2temp.end(), match ))
234 const OUString url(
235 makeURL(m_activePackages_expanded, tempEntry ) );
237 //In case of shared extensions, new entries are regarded as
238 //added extensions if there is no xxx.tmpremoved file.
239 if (bShared)
241 if (std::find(removedEntries.begin(), removedEntries.end(), tempEntry) ==
242 removedEntries.end())
244 continue;
246 else
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(
261 url + "removed", Reference<XCommandEnvironment>(), m_xComponentContext);
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;
271 // temp entry not needed anymore:
272 erase_path( url + "_",
273 Reference<XCommandEnvironment>(),
274 false /* no throw: ignore errors */ );
275 erase_path( url, Reference<XCommandEnvironment>(),
276 false /* no throw: ignore errors */ );
277 //delete the xxx.tmpremoved file
278 erase_path(url + "removed",
279 Reference<XCommandEnvironment>(), false);
287 void PackageManagerImpl::initRegistryBackends()
289 if (!m_registryCache.isEmpty())
290 create_folder( nullptr, m_registryCache,
291 Reference<XCommandEnvironment>(), false);
292 m_xRegistry.set( ::dp_registry::create(
293 m_context, m_registryCache,
294 m_xComponentContext ) );
297 namespace {
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;
304 INetURLObject o(url);
305 if (!o.removeSegment()) {
306 return osl::FileBase::E_INVAL; // anything but E_None/E_EXIST
308 e = createDirectory(o.GetMainURL(INetURLObject::DecodeMechanism::NONE));
309 if (e != osl::FileBase::E_None && e != osl::FileBase::E_EXIST) {
310 return e;
312 return osl::Directory::create(url);
315 bool isMacroURLReadOnly( const OUString &rMacro )
317 OUString aDirURL( rMacro );
318 ::rtl::Bootstrap::expandMacros( aDirURL );
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
326 bool bError;
327 sal_uInt64 nWritten = 0;
328 OUString aFileURL( aDirURL + "/stamp.sys" );
329 ::osl::File aFile( aFileURL );
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;
341 SAL_INFO(
342 "desktop.deployment",
343 "local url '" << rMacro << "' -> '" << aFileURL << "' "
344 << (bError ? "is" : "is not") << " readonly\n");
345 return bError;
350 Reference<deployment::XPackageManager> PackageManagerImpl::create(
351 Reference<XComponentContext> const & xComponentContext,
352 OUString const & context )
354 PackageManagerImpl * that = new PackageManagerImpl(
355 xComponentContext, context );
356 Reference<deployment::XPackageManager> xPackageManager( that );
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";
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
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
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";
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";
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) );
415 Reference<XCommandEnvironment> xCmdEnv;
417 try {
418 // There is no stamp for the bundled folder:
419 if (!stamp.isEmpty())
420 that->m_readOnly = isMacroURLReadOnly( stamp );
422 if (!that->m_readOnly && !logFile.isEmpty())
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);
434 that->m_xLogFile.set(
435 that->m_xComponentContext->getServiceManager()
436 ->createInstanceWithArgumentsAndContext(
437 dp_log::serviceDecl.getSupportedServiceNames()[0],
438 Sequence<Any>(),
439 that->m_xComponentContext ),
440 UNO_QUERY_THROW );
441 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv, that->m_xLogFile ) );
444 that->initRegistryBackends();
445 that->initActivationLayer( xCmdEnv );
447 return xPackageManager;
450 catch (const RuntimeException &) {
451 throw;
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 );
463 PackageManagerImpl::~PackageManagerImpl()
468 void PackageManagerImpl::fireModified()
470 ::cppu::OInterfaceContainerHelper * pContainer = rBHelper.getContainer(
471 cppu::UnoType<util::XModifyListener>::get() );
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))); });
480 void PackageManagerImpl::disposing()
482 try {
483 // // xxx todo: guarding?
484 // ::osl::MutexGuard guard( getMutex() );
485 try_dispose( m_xLogFile );
486 m_xLogFile.clear();
487 try_dispose( m_xRegistry );
488 m_xRegistry.clear();
489 m_activePackagesDB.reset();
490 m_xComponentContext.clear();
492 t_pm_helper::disposing();
495 catch (const RuntimeException &) {
496 throw;
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 );
506 // XComponent
508 void PackageManagerImpl::dispose()
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();
516 void PackageManagerImpl::addEventListener(
517 Reference<lang::XEventListener> const & xListener )
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 );
525 void PackageManagerImpl::removeEventListener(
526 Reference<lang::XEventListener> const & xListener )
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 );
533 // XPackageManager
535 OUString PackageManagerImpl::getContext()
537 check();
538 return m_context;
542 Sequence< Reference<deployment::XPackageTypeInfo> >
543 PackageManagerImpl::getSupportedPackageTypes()
545 OSL_ASSERT( m_xRegistry.is() );
546 return m_xRegistry->getSupportedPackageTypes();
550 Reference<task::XAbortChannel> PackageManagerImpl::createAbortChannel()
552 check();
553 return new AbortChannel;
556 // XModifyBroadcaster
558 void PackageManagerImpl::addModifyListener(
559 Reference<util::XModifyListener> const & xListener )
561 check();
562 rBHelper.addListener( cppu::UnoType<decltype(xListener)>::get(), xListener );
566 void PackageManagerImpl::removeModifyListener(
567 Reference<util::XModifyListener> const & xListener )
569 check();
570 rBHelper.removeListener( cppu::UnoType<decltype(xListener)>::get(), xListener );
574 OUString PackageManagerImpl::detectMediaType(
575 ::ucbhelper::Content const & ucbContent_, bool throw_exc )
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:" ))
582 try {
583 ucbContent.getPropertyValue( "MediaType" ) >>= mediaType;
585 catch (const beans::UnknownPropertyException &) {
587 OSL_ENSURE( !mediaType.isEmpty(), "### no media-type?!" );
589 if (mediaType.isEmpty())
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();
601 catch (const lang::IllegalArgumentException &) {
602 if (throw_exc)
603 throw;
604 css::uno::Any ex( cppu::getCaughtException() );
605 SAL_WARN( "desktop", exceptionToString(ex) );
608 return mediaType;
612 OUString PackageManagerImpl::insertToActivationLayer(
613 Sequence<beans::NamedValue> const & properties,
614 OUString const & mediaType, ::ucbhelper::Content const & sourceContent_,
615 OUString const & title, ActivePackages::Data * dbData )
617 ::ucbhelper::Content sourceContent(sourceContent_);
618 Reference<XCommandEnvironment> xCmdEnv(
619 sourceContent.getCommandEnvironment() );
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) + "_";
627 // prepare activation folder:
628 ::ucbhelper::Content destFolderContent;
629 create_folder( &destFolderContent, destFolder, xCmdEnv );
631 // copy content into activation temp dir:
632 if (mediaType.matchIgnoreAsciiCase("application/vnd.sun.star.package-bundle") ||
633 // xxx todo: more sophisticated parsing
634 mediaType.matchIgnoreAsciiCase("application/vnd.sun.star.legacy-package-bundle"))
636 // inflate content:
637 OUStringBuffer buf;
638 if (!sourceContent.isFolder())
640 buf.append( "vnd.sun.star.zip://" );
641 buf.append( ::rtl::Uri::encode( sourceContent.getURL(),
642 rtl_UriCharClassRegName,
643 rtl_UriEncodeIgnoreEscapes,
644 RTL_TEXTENCODING_UTF8 ) );
646 else
648 //Folder. No need to unzip, just copy
649 buf.append(sourceContent.getURL());
651 buf.append( '/' );
652 sourceContent = ::ucbhelper::Content(
653 buf.makeStringAndClear(), xCmdEnv, m_xComponentContext );
655 destFolderContent.transferContent(
656 sourceContent, ::ucbhelper::InsertOperation::Copy,
657 title, NameClash::OVERWRITE );
660 // write to DB:
661 //bundled extensions should only be added by the synchronizeAddedExtensions
662 //functions. Moreover, there is no "temporary folder" for bundled extensions.
663 OSL_ASSERT(!(m_context == "bundled"));
664 OUString sFolderUrl = makeURLAppendSysPathSegment(destFolderContent.getURL(), title);
665 DescriptionInfoset info =
666 dp_misc::getDescriptionInfoset(sFolderUrl);
667 dbData->temporaryName = tempEntry;
668 dbData->fileName = title;
669 dbData->mediaType = mediaType;
670 dbData->version = info.getVersion();
672 //No write the properties file next to the extension
673 ExtensionProperties props(sFolderUrl, properties, xCmdEnv, m_xComponentContext);
674 props.write();
675 return destFolder;
679 void PackageManagerImpl::insertToActivationLayerDB(
680 OUString const & id, ActivePackages::Data const & dbData )
682 //access to the database must be guarded. See removePackage
683 const ::osl::MutexGuard guard( getMutex() );
684 m_activePackagesDB->put( id, dbData );
688 /* The function returns true if there is an extension with the same id already
689 installed which needs to be uninstalled, before the new extension can be installed.
691 bool PackageManagerImpl::isInstalled(
692 Reference<deployment::XPackage> const & package)
694 OUString id(dp_misc::getIdentifier(package));
695 OUString fn(package->getName());
696 bool bInstalled = false;
697 if (m_activePackagesDB->has( id, fn ))
699 bInstalled = true;
701 return bInstalled;
704 // XPackageManager
706 Reference<deployment::XPackage> PackageManagerImpl::importExtension(
707 Reference<deployment::XPackage> const & extension,
708 Reference<task::XAbortChannel> const & xAbortChannel,
709 Reference<XCommandEnvironment> const & xCmdEnv_ )
711 return addPackage(extension->getURL(), Sequence<beans::NamedValue>(),
712 OUString(), xAbortChannel, xCmdEnv_);
715 /* The function adds an extension but does not register it!!!
716 It may not do any user interaction. This is done in XExtensionManager::addExtension
718 Reference<deployment::XPackage> PackageManagerImpl::addPackage(
719 OUString const & url,
720 css::uno::Sequence<css::beans::NamedValue> const & properties,
721 OUString const & mediaType_,
722 Reference<task::XAbortChannel> const & xAbortChannel,
723 Reference<XCommandEnvironment> const & xCmdEnv_ )
725 check();
726 if (m_readOnly)
728 OUString message;
729 if (m_context == "shared")
730 message = "You need write permissions to install a shared extension!";
731 else
732 message = "You need write permissions to install this extension!";
733 throw deployment::DeploymentException(
734 message, static_cast<OWeakObject *>(this), Any() );
736 Reference<XCommandEnvironment> xCmdEnv;
737 if (m_xLogFile.is())
738 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
739 else
740 xCmdEnv.set( xCmdEnv_ );
742 try {
743 ::ucbhelper::Content sourceContent;
744 (void)create_ucb_content( &sourceContent, url, xCmdEnv ); // throws exc
745 const OUString title( StrTitle::getTitle( sourceContent ) );
746 const OUString title_enc( ::rtl::Uri::encode(
747 title, rtl_UriCharClassPchar,
748 rtl_UriEncodeIgnoreEscapes,
749 RTL_TEXTENCODING_UTF8 ) );
750 OUString destFolder;
752 OUString mediaType(mediaType_);
753 if (mediaType.isEmpty())
754 mediaType = detectMediaType( sourceContent );
756 Reference<deployment::XPackage> xPackage;
757 // copy file:
758 progressUpdate(
759 DpResId(RID_STR_COPYING_PACKAGE) + title, xCmdEnv );
760 if (m_activePackages.isEmpty())
762 ::ucbhelper::Content docFolderContent;
763 create_folder( &docFolderContent, m_context, xCmdEnv );
764 // copy into document, first:
765 docFolderContent.transferContent(
766 sourceContent, ::ucbhelper::InsertOperation::Copy,
767 OUString(),
768 NameClash::ASK /* xxx todo: ASK not needed? */);
769 // set media-type:
770 ::ucbhelper::Content docContent(
771 makeURL( m_context, title_enc ), xCmdEnv, m_xComponentContext );
772 //TODO #i73136#: using title instead of id can lead to
773 // clashes, but the whole m_activePackages.getLength()==0
774 // case (i.e., document-relative deployment) currently does
775 // not work, anyway.
776 docContent.setPropertyValue("MediaType", Any(mediaType) );
778 // xxx todo: obsolete in the future
779 try {
780 docFolderContent.executeCommand( "flush", Any() );
782 catch (const UnsupportedCommandException &) {
785 ActivePackages::Data dbData;
786 destFolder = insertToActivationLayer(
787 properties, mediaType, sourceContent, title, &dbData );
790 // bind activation package:
791 //Because every shared/user extension will be unpacked in a folder,
792 //which was created with a unique name we will always have two different
793 //XPackage objects, even if the second extension is the same.
794 //Therefore bindPackage does not need a guard here.
795 xPackage = m_xRegistry->bindPackage(
796 makeURL( destFolder, title_enc ), mediaType, false, OUString(), xCmdEnv );
798 OSL_ASSERT( xPackage.is() );
799 if (xPackage.is())
801 bool install = false;
804 OUString const id = dp_misc::getIdentifier( xPackage );
806 ::osl::MutexGuard g(m_addMutex);
807 if (isInstalled(xPackage))
809 //Do not guard the complete function with the getMutex
810 removePackage(id, xPackage->getName(), xAbortChannel,
811 xCmdEnv);
813 install = true;
814 insertToActivationLayerDB(id, dbData);
816 catch (...)
818 deletePackageFromCache( xPackage, destFolder );
819 throw;
821 if (!install)
823 deletePackageFromCache( xPackage, destFolder );
825 //ToDo: We should notify only if the extension is registered
826 fireModified();
828 return xPackage;
830 catch (const RuntimeException &) {
831 throw;
833 catch (const CommandFailedException & exc) {
834 logIntern( Any(exc) );
835 throw;
837 catch (const CommandAbortedException & exc) {
838 logIntern( Any(exc) );
839 throw;
841 catch (const deployment::DeploymentException & exc) {
842 logIntern( Any(exc) );
843 throw;
845 catch (const Exception &) {
846 Any exc( ::cppu::getCaughtException() );
847 logIntern( exc );
848 throw deployment::DeploymentException(
849 DpResId(RID_STR_ERROR_WHILE_ADDING) + url,
850 static_cast<OWeakObject *>(this), exc );
853 void PackageManagerImpl::deletePackageFromCache(
854 Reference<deployment::XPackage> const & xPackage,
855 OUString const & destFolder)
857 try_dispose( xPackage );
859 //we remove the package from the uno cache
860 //no service from the package may be loaded at this time!!!
861 erase_path( destFolder, Reference<XCommandEnvironment>(),
862 false /* no throw: ignore errors */ );
863 //rm last character '_'
864 OUString url = destFolder.copy(0, destFolder.getLength() - 1);
865 erase_path( url, Reference<XCommandEnvironment>(),
866 false /* no throw: ignore errors */ );
870 void PackageManagerImpl::removePackage(
871 OUString const & id, OUString const & fileName,
872 Reference<task::XAbortChannel> const & /*xAbortChannel*/,
873 Reference<XCommandEnvironment> const & xCmdEnv_ )
875 check();
877 Reference<XCommandEnvironment> xCmdEnv;
878 if (m_xLogFile.is())
879 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
880 else
881 xCmdEnv.set( xCmdEnv_ );
883 try {
884 Reference<deployment::XPackage> xPackage;
886 const ::osl::MutexGuard guard(getMutex());
887 //Check if this extension exist and throw an IllegalArgumentException
888 //if it does not
889 //If the files of the extension are already removed, or there is a
890 //different extension at the same place, for example after updating the
891 //extension, then the returned object is that which uses the database data.
892 xPackage = getDeployedPackage_(id, fileName, xCmdEnv );
895 //Because the extension is only removed the next time the extension
896 //manager runs after restarting OOo, we need to indicate that a
897 //shared extension was "deleted". When a user starts OOo, then it
898 //will check if something changed in the shared repository. Based on
899 //the flag file it will then recognize, that the extension was
900 //deleted and can then update the extension database of the shared
901 //extensions in the user installation.
902 if ( xPackage.is() && !m_readOnly && !xPackage->isRemoved() && (m_context == "shared"))
904 ActivePackages::Data val;
905 m_activePackagesDB->get( & val, id, fileName);
906 OSL_ASSERT(!val.temporaryName.isEmpty());
907 OUString url(makeURL(m_activePackages_expanded,
908 val.temporaryName + "removed"));
909 ::ucbhelper::Content contentRemoved(url, xCmdEnv, m_xComponentContext);
910 OUString aUserName;
911 ::osl::Security aSecurity;
912 aSecurity.getUserName( aUserName );
914 OString stamp = OUStringToOString(aUserName, RTL_TEXTENCODING_UTF8);
915 Reference<css::io::XInputStream> xData(
916 ::xmlscript::createInputStream(
917 reinterpret_cast<sal_Int8 const *>(stamp.getStr()),
918 stamp.getLength() ) );
919 contentRemoved.writeStream( xData, true /* replace existing */ );
921 m_activePackagesDB->erase( id, fileName ); // to be removed upon next start
922 //remove any cached data hold by the backend
923 m_xRegistry->packageRemoved(xPackage->getURL(), xPackage->getPackageType()->getMediaType());
925 try_dispose( xPackage );
927 fireModified();
929 catch (const RuntimeException &) {
930 throw;
932 catch (const CommandFailedException & exc) {
933 logIntern( Any(exc) );
934 throw;
936 catch (const CommandAbortedException & exc) {
937 logIntern( Any(exc) );
938 throw;
940 catch (const deployment::DeploymentException & exc) {
941 logIntern( Any(exc) );
942 throw;
944 catch (const Exception &) {
945 Any exc( ::cppu::getCaughtException() );
946 logIntern( exc );
947 throw deployment::DeploymentException(
948 DpResId(RID_STR_ERROR_WHILE_REMOVING) + id,
949 static_cast<OWeakObject *>(this), exc );
954 OUString PackageManagerImpl::getDeployPath( ActivePackages::Data const & data )
956 OUStringBuffer buf;
957 buf.append( data.temporaryName );
958 //The bundled extensions are not contained in an additional folder
959 //with a unique name. data.temporaryName contains already the
960 //UTF8 encoded folder name. See PackageManagerImpl::synchronize
961 if (m_context != "bundled")
963 buf.append( "_/" );
964 buf.append( ::rtl::Uri::encode( data.fileName, rtl_UriCharClassPchar,
965 rtl_UriEncodeIgnoreEscapes,
966 RTL_TEXTENCODING_UTF8 ) );
968 return makeURL( m_activePackages, buf.makeStringAndClear() );
972 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
973 OUString const & id, OUString const & fileName,
974 Reference<XCommandEnvironment> const & xCmdEnv )
976 ActivePackages::Data val;
977 if (m_activePackagesDB->get( &val, id, fileName ))
979 return getDeployedPackage_( id, val, xCmdEnv );
981 throw lang::IllegalArgumentException(
982 DpResId(RID_STR_NO_SUCH_PACKAGE) + id,
983 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
987 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
988 OUString const & id, ActivePackages::Data const & data,
989 Reference<XCommandEnvironment> const & xCmdEnv, bool ignoreAlienPlatforms )
991 if (ignoreAlienPlatforms)
993 OUString type, subType;
994 INetContentTypeParameterList params;
995 if (INetContentTypes::parse( data.mediaType, type, subType, &params ))
997 auto const iter = params.find(OString("platform"));
998 if (iter != params.end() && !platform_fits(iter->second.m_sValue))
999 throw lang::IllegalArgumentException(
1000 DpResId(RID_STR_NO_SUCH_PACKAGE) + id,
1001 static_cast<OWeakObject *>(this),
1002 static_cast<sal_Int16>(-1) );
1005 Reference<deployment::XPackage> xExtension;
1008 //Ignore extensions where XPackage::checkPrerequisites failed.
1009 //They must not be usable for this user.
1010 if (data.failedPrerequisites == "0")
1012 xExtension = m_xRegistry->bindPackage(
1013 getDeployPath( data ), data.mediaType, false, OUString(), xCmdEnv );
1016 catch (const deployment::InvalidRemovedParameterException& e)
1018 xExtension = e.Extension;
1020 return xExtension;
1024 Sequence< Reference<deployment::XPackage> >
1025 PackageManagerImpl::getDeployedPackages_(
1026 Reference<XCommandEnvironment> const & xCmdEnv )
1028 std::vector< Reference<deployment::XPackage> > packages;
1029 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1030 for (auto const& elem : id2temp)
1032 if (elem.second.failedPrerequisites != "0")
1033 continue;
1034 try {
1035 packages.push_back(
1036 getDeployedPackage_(
1037 elem.first, elem.second, xCmdEnv,
1038 true /* xxx todo: think of GUI:
1039 ignore other platforms than the current one */ ) );
1041 catch (const lang::IllegalArgumentException &) {
1042 // ignore
1043 TOOLS_WARN_EXCEPTION( "desktop", "" );
1045 catch (const deployment::DeploymentException&) {
1046 // ignore
1047 TOOLS_WARN_EXCEPTION( "desktop", "" );
1050 return comphelper::containerToSequence(packages);
1054 Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage(
1055 OUString const & id, OUString const & fileName,
1056 Reference<XCommandEnvironment> const & xCmdEnv_ )
1058 check();
1059 Reference<XCommandEnvironment> xCmdEnv;
1060 if (m_xLogFile.is())
1061 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1062 else
1063 xCmdEnv.set( xCmdEnv_ );
1065 try {
1066 const ::osl::MutexGuard guard( getMutex() );
1067 return getDeployedPackage_( id, fileName, xCmdEnv );
1069 catch (const lang::IllegalArgumentException & exc) {
1070 logIntern( Any(exc) );
1071 throw;
1073 catch (const RuntimeException &) {
1074 throw;
1076 catch (const CommandFailedException & exc) {
1077 logIntern( Any(exc) );
1078 throw;
1080 catch (const deployment::DeploymentException & exc) {
1081 logIntern( Any(exc) );
1082 throw;
1084 catch (const Exception &) {
1085 Any exc( ::cppu::getCaughtException() );
1086 logIntern( exc );
1087 throw deployment::DeploymentException(
1088 // ought never occur...
1089 "error while accessing deployed package: " + id,
1090 static_cast<OWeakObject *>(this), exc );
1095 Sequence< Reference<deployment::XPackage> >
1096 PackageManagerImpl::getDeployedPackages(
1097 Reference<task::XAbortChannel> const &,
1098 Reference<XCommandEnvironment> const & xCmdEnv_ )
1100 check();
1101 Reference<XCommandEnvironment> xCmdEnv;
1102 if (m_xLogFile.is())
1103 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1104 else
1105 xCmdEnv.set( xCmdEnv_ );
1107 try {
1108 const ::osl::MutexGuard guard( getMutex() );
1109 return getDeployedPackages_( xCmdEnv );
1111 catch (const RuntimeException &) {
1112 throw;
1114 catch (const CommandFailedException & exc) {
1115 logIntern( Any(exc) );
1116 throw;
1118 catch (const CommandAbortedException & exc) {
1119 logIntern( Any(exc) );
1120 throw;
1122 catch (const deployment::DeploymentException & exc) {
1123 logIntern( Any(exc) );
1124 throw;
1126 catch (const Exception &) {
1127 Any exc( ::cppu::getCaughtException() );
1128 logIntern( exc );
1129 throw deployment::DeploymentException(
1130 // ought never occur...
1131 "error while getting all deployed packages: " + m_context,
1132 static_cast<OWeakObject *>(this), exc );
1137 //ToDo: the function must not call registerPackage, do this in
1138 //XExtensionManager.reinstallDeployedExtensions
1139 void PackageManagerImpl::reinstallDeployedPackages(
1140 sal_Bool force, Reference<task::XAbortChannel> const & /*xAbortChannel*/,
1141 Reference<XCommandEnvironment> const & xCmdEnv_ )
1143 check();
1144 if (!force && office_is_running())
1145 throw RuntimeException(
1146 "You must close any running Office process before reinstalling packages!",
1147 static_cast<OWeakObject *>(this) );
1149 Reference<XCommandEnvironment> xCmdEnv;
1150 if (m_xLogFile.is())
1151 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1152 else
1153 xCmdEnv.set( xCmdEnv_ );
1155 try {
1156 ProgressLevel progress(
1157 xCmdEnv, "Reinstalling all deployed packages..." );
1159 try_dispose( m_xRegistry );
1160 m_xRegistry.clear();
1161 if (!m_registryCache.isEmpty())
1162 erase_path( m_registryCache, xCmdEnv );
1163 initRegistryBackends();
1164 Reference<util::XUpdatable> xUpdatable( m_xRegistry, UNO_QUERY );
1165 if (xUpdatable.is())
1166 xUpdatable->update();
1168 //registering is done by the ExtensionManager service.
1170 catch (const RuntimeException &) {
1171 throw;
1173 catch (const CommandFailedException & exc) {
1174 logIntern( Any(exc) );
1175 throw;
1177 catch (const CommandAbortedException & exc) {
1178 logIntern( Any(exc) );
1179 throw;
1181 catch (const deployment::DeploymentException & exc) {
1182 logIntern( Any(exc) );
1183 throw;
1185 catch (const Exception &) {
1186 Any exc( ::cppu::getCaughtException() );
1187 logIntern( exc );
1188 throw deployment::DeploymentException(
1189 "Error while reinstalling all previously deployed packages of context " + m_context,
1190 static_cast<OWeakObject *>(this), exc );
1195 sal_Bool SAL_CALL PackageManagerImpl::isReadOnly( )
1197 return m_readOnly;
1199 bool PackageManagerImpl::synchronizeRemovedExtensions(
1200 Reference<task::XAbortChannel> const & xAbortChannel,
1201 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
1204 //find all which are in the extension data base but which
1205 //are removed already.
1206 OSL_ASSERT(!(m_context == "user"));
1207 bool bModified = false;
1208 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1210 bool bShared = (m_context == "shared");
1212 for (auto const& elem : id2temp)
1216 //Get the URL to the extensions folder, first make the url for the
1217 //shared repository including the temporary name
1218 OUString url = makeURL(m_activePackages, elem.second.temporaryName);
1219 if (bShared)
1220 url = makeURLAppendSysPathSegment( url + "_", elem.second.fileName);
1222 bool bRemoved = false;
1223 //Check if the URL to the extension is still the same
1224 ::ucbhelper::Content contentExtension;
1226 if (!create_ucb_content(
1227 &contentExtension, url,
1228 Reference<XCommandEnvironment>(), false))
1230 bRemoved = true;
1233 //The folder is in the extension database, but it can still be deleted.
1234 //look for the xxx.tmpremoved file
1235 //There can also be the case that a different extension was installed
1236 //in a "temp" folder with name that is already used.
1237 if (!bRemoved && bShared)
1239 ::ucbhelper::Content contentRemoved;
1241 if (create_ucb_content(
1242 &contentRemoved,
1243 m_activePackages_expanded + "/" +
1244 elem.second.temporaryName + "removed",
1245 Reference<XCommandEnvironment>(), false))
1247 bRemoved = true;
1251 if (!bRemoved)
1253 //There may be another extensions at the same place
1254 dp_misc::DescriptionInfoset infoset =
1255 dp_misc::getDescriptionInfoset(url);
1256 OSL_ENSURE(infoset.hasDescription() && infoset.getIdentifier(),
1257 "Extension Manager: bundled and shared extensions "
1258 "must have an identifier and a version");
1259 if (infoset.hasDescription() &&
1260 infoset.getIdentifier() &&
1261 ( elem.first != *(infoset.getIdentifier())
1262 || elem.second.version != infoset.getVersion()))
1264 bRemoved = true;
1268 if (bRemoved)
1270 Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1271 url, elem.second.mediaType, true, elem.first, xCmdEnv );
1272 OSL_ASSERT(xPackage.is()); //Even if the files are removed, we must get the object.
1273 xPackage->revokePackage(true, xAbortChannel, xCmdEnv);
1274 removePackage(xPackage->getIdentifier().Value, xPackage->getName(),
1275 xAbortChannel, xCmdEnv);
1276 bModified = true;
1279 catch( const uno::Exception & )
1281 TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1284 return bModified;
1288 bool PackageManagerImpl::synchronizeAddedExtensions(
1289 Reference<task::XAbortChannel> const & xAbortChannel,
1290 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
1292 bool bModified = false;
1293 OSL_ASSERT(!(m_context == "user"));
1295 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1296 //check if the folder exist at all. The shared extension folder
1297 //may not exist for a normal user.
1298 bool bOk=true;
1301 bOk = create_ucb_content(
1302 nullptr, m_activePackages_expanded, Reference<css::ucb::XCommandEnvironment>(), false);
1304 catch (const css::ucb::ContentCreationException&)
1306 bOk = false;
1309 if (!bOk)
1310 return bModified;
1312 ::ucbhelper::Content tempFolder( m_activePackages_expanded, xCmdEnv, m_xComponentContext );
1313 Reference<sdbc::XResultSet> xResultSet(
1314 StrTitle::createCursor( tempFolder,
1315 ::ucbhelper::INCLUDE_FOLDERS_ONLY ) );
1317 while (xResultSet->next())
1321 OUString title(
1322 Reference<sdbc::XRow>(
1323 xResultSet, UNO_QUERY_THROW )->getString(
1324 1 /* Title */ ) );
1325 //The temporary folders of user and shared have an '_' at then end.
1326 //But the name in ActivePackages.temporaryName is saved without.
1327 OUString title2 = title;
1328 bool bShared = (m_context == "shared");
1329 if (bShared)
1331 OSL_ASSERT(title2.endsWith("_"));
1332 title2 = title2.copy(0, title2.getLength() -1);
1334 OUString titleEncoded = ::rtl::Uri::encode(
1335 title2, rtl_UriCharClassPchar,
1336 rtl_UriEncodeIgnoreEscapes,
1337 RTL_TEXTENCODING_UTF8);
1339 //It is sufficient to check for the folder name, because when the administrator
1340 //installed the extension it was already checked if there is one with the
1341 //same identifier.
1342 const MatchTempDir match(titleEncoded);
1343 if (std::none_of( id2temp.begin(), id2temp.end(), match ))
1346 // The folder was not found in the data base, so it must be
1347 // an added extension
1348 OUString url(m_activePackages_expanded + "/" + titleEncoded);
1349 OUString sExtFolder;
1350 if (bShared) //that is, shared
1352 //Check if the extension was not "deleted" already which is indicated
1353 //by a xxx.tmpremoved file
1354 ::ucbhelper::Content contentRemoved;
1355 if (create_ucb_content(&contentRemoved, url + "removed",
1356 Reference<XCommandEnvironment>(), false))
1357 continue;
1358 sExtFolder = getExtensionFolder(
1359 m_activePackages_expanded + "/" + titleEncoded + "_",
1360 xCmdEnv, m_xComponentContext);
1361 url = makeURLAppendSysPathSegment(m_activePackages_expanded, title);
1362 url = makeURLAppendSysPathSegment(url, sExtFolder);
1364 Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1365 url, OUString(), false, OUString(), xCmdEnv );
1366 if (xPackage.is())
1368 OUString id = dp_misc::getIdentifier( xPackage );
1370 //Prepare the database entry
1371 ActivePackages::Data dbData;
1373 dbData.temporaryName = titleEncoded;
1374 if (bShared)
1375 dbData.fileName = sExtFolder;
1376 else
1377 dbData.fileName = title;
1378 dbData.mediaType = xPackage->getPackageType()->getMediaType();
1379 dbData.version = xPackage->getVersion();
1380 SAL_WARN_IF(
1381 dbData.version.isEmpty(), "desktop.deployment",
1382 "bundled/shared extension " << id << " at <" << url
1383 << "> has no explicit version");
1385 //We provide a special command environment that will prevent
1386 //showing a license if simple-license/@accept-by = "admin"
1387 //It will also prevent showing the license for bundled extensions
1388 //which is not supported.
1389 OSL_ASSERT(!(m_context == "user"));
1391 // shall the license be suppressed?
1392 DescriptionInfoset info =
1393 dp_misc::getDescriptionInfoset(url);
1394 ::boost::optional<dp_misc::SimpleLicenseAttributes>
1395 attr = info.getSimpleLicenseAttributes();
1396 ExtensionProperties props(url, xCmdEnv, m_xComponentContext);
1397 bool bNoLicense = false;
1398 if (attr && attr->suppressIfRequired && props.isSuppressedLicense())
1399 bNoLicense = true;
1401 Reference<ucb::XCommandEnvironment> licCmdEnv(
1402 new LicenseCommandEnv(xCmdEnv->getInteractionHandler(),
1403 bNoLicense, m_context));
1404 sal_Int32 failedPrereq = xPackage->checkPrerequisites(
1405 xAbortChannel, licCmdEnv, false);
1406 //Remember that this failed. For example, the user
1407 //could have declined the license. Then the next time the
1408 //extension folder is investigated we do not want to
1409 //try to install the extension again.
1410 dbData.failedPrerequisites = OUString::number(failedPrereq);
1411 insertToActivationLayerDB(id, dbData);
1412 bModified = true;
1416 catch (const uno::Exception &)
1418 // Looks like exceptions being caught here is not an uncommon case.
1419 TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1422 return bModified;
1425 sal_Bool PackageManagerImpl::synchronize(
1426 Reference<task::XAbortChannel> const & xAbortChannel,
1427 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
1429 check();
1430 bool bModified = false;
1431 if (m_context == "user")
1432 return bModified;
1433 bModified |=
1434 synchronizeRemovedExtensions(xAbortChannel, xCmdEnv);
1435 bModified |= synchronizeAddedExtensions(xAbortChannel, xCmdEnv);
1437 return bModified;
1440 Sequence< Reference<deployment::XPackage> > PackageManagerImpl::getExtensionsWithUnacceptedLicenses(
1441 Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1443 std::vector<Reference<deployment::XPackage> > vec;
1447 const ::osl::MutexGuard guard( getMutex() );
1448 // clean up activation layer, scan for zombie temp dirs:
1449 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1451 bool bShared = (m_context == "shared");
1453 for (auto const& elem : id2temp)
1455 //Get the database entry
1456 ActivePackages::Data const & dbData = elem.second;
1457 sal_Int32 failedPrereq = dbData.failedPrerequisites.toInt32();
1458 //If the installation failed for other reason then the license then we
1459 //ignore it.
1460 if (failedPrereq ^= deployment::Prerequisites::LICENSE)
1461 continue;
1463 //Prepare the URL to the extension
1464 OUString url = makeURL(m_activePackages, elem.second.temporaryName);
1465 if (bShared)
1466 url = makeURLAppendSysPathSegment( url + "_", elem.second.fileName);
1468 Reference<deployment::XPackage> p = m_xRegistry->bindPackage(
1469 url, OUString(), false, OUString(), xCmdEnv );
1471 if (p.is())
1472 vec.push_back(p);
1475 return ::comphelper::containerToSequence(vec);
1477 catch (const deployment::DeploymentException &)
1479 throw;
1481 catch (const RuntimeException&)
1483 throw;
1485 catch (...)
1487 Any exc = ::cppu::getCaughtException();
1488 deployment::DeploymentException de(
1489 "PackageManagerImpl::getExtensionsWithUnacceptedLicenses",
1490 static_cast<OWeakObject*>(this), exc);
1491 exc <<= de;
1492 ::cppu::throwException(exc);
1495 return ::comphelper::containerToSequence(vec);
1498 sal_Int32 PackageManagerImpl::checkPrerequisites(
1499 css::uno::Reference<css::deployment::XPackage> const & extension,
1500 css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel,
1501 css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv )
1505 if (!extension.is())
1506 return 0;
1507 if (m_context != extension->getRepositoryName())
1508 throw lang::IllegalArgumentException(
1509 "PackageManagerImpl::checkPrerequisites: extension is not from this repository.",
1510 nullptr, 0);
1512 ActivePackages::Data dbData;
1513 OUString id = dp_misc::getIdentifier(extension);
1514 if (!m_activePackagesDB->get( &dbData, id, OUString()))
1516 throw lang::IllegalArgumentException(
1517 "PackageManagerImpl::checkPrerequisites: unknown extension",
1518 nullptr, 0);
1521 //If the license was already displayed, then do not show it again
1522 Reference<ucb::XCommandEnvironment> _xCmdEnv = xCmdEnv;
1523 sal_Int32 prereq = dbData.failedPrerequisites.toInt32();
1524 if ( !(prereq & deployment::Prerequisites::LICENSE))
1525 _xCmdEnv = new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler());
1527 sal_Int32 failedPrereq = extension->checkPrerequisites(
1528 xAbortChannel, _xCmdEnv, false);
1529 dbData.failedPrerequisites = OUString::number(failedPrereq);
1530 insertToActivationLayerDB(id, dbData);
1531 return 0;
1533 catch ( const deployment::DeploymentException& ) {
1534 throw;
1535 } catch ( const ucb::CommandFailedException & ) {
1536 throw;
1537 } catch ( const ucb::CommandAbortedException & ) {
1538 throw;
1539 } catch (const lang::IllegalArgumentException &) {
1540 throw;
1541 } catch (const uno::RuntimeException &) {
1542 throw;
1543 } catch (...) {
1544 uno::Any excOccurred = ::cppu::getCaughtException();
1545 deployment::DeploymentException exc(
1546 "PackageManagerImpl::checkPrerequisites: exception ",
1547 static_cast<OWeakObject*>(this), excOccurred);
1548 throw exc;
1553 PackageManagerImpl::CmdEnvWrapperImpl::~CmdEnvWrapperImpl()
1558 PackageManagerImpl::CmdEnvWrapperImpl::CmdEnvWrapperImpl(
1559 Reference<XCommandEnvironment> const & xUserCmdEnv,
1560 Reference<XProgressHandler> const & xLogFile )
1561 : m_xLogFile( xLogFile )
1563 if (xUserCmdEnv.is()) {
1564 m_xUserProgress.set( xUserCmdEnv->getProgressHandler() );
1565 m_xUserInteractionHandler.set( xUserCmdEnv->getInteractionHandler() );
1569 // XCommandEnvironment
1571 Reference<task::XInteractionHandler>
1572 PackageManagerImpl::CmdEnvWrapperImpl::getInteractionHandler()
1574 return m_xUserInteractionHandler;
1578 Reference<XProgressHandler>
1579 PackageManagerImpl::CmdEnvWrapperImpl::getProgressHandler()
1581 return this;
1584 // XProgressHandler
1586 void PackageManagerImpl::CmdEnvWrapperImpl::push( Any const & Status )
1588 if (m_xLogFile.is())
1589 m_xLogFile->push( Status );
1590 if (m_xUserProgress.is())
1591 m_xUserProgress->push( Status );
1595 void PackageManagerImpl::CmdEnvWrapperImpl::update( Any const & Status )
1597 if (m_xLogFile.is())
1598 m_xLogFile->update( Status );
1599 if (m_xUserProgress.is())
1600 m_xUserProgress->update( Status );
1604 void PackageManagerImpl::CmdEnvWrapperImpl::pop()
1606 if (m_xLogFile.is())
1607 m_xLogFile->pop();
1608 if (m_xUserProgress.is())
1609 m_xUserProgress->pop();
1612 } // namespace dp_manager
1614 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */