1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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"
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
;
88 extern comphelper::service_decl::ServiceDecl
const serviceDecl
;
91 namespace dp_manager
{
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
);
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
) );
113 if (xResultSet
->next())
115 title
= Reference
<sdbc::XRow
>(
116 xResultSet
, UNO_QUERY_THROW
)->getString(1 /* 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" )
145 if ( title
== "META-INF" )
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
,
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.
174 OSL_ASSERT( !m_activePackages
.isEmpty() );
175 m_activePackages_expanded
= expandUnoRcUrl( m_activePackages
);
176 m_registrationData_expanded
= expandUnoRcUrl(m_registrationData
);
178 create_folder( nullptr, m_activePackages_expanded
, xCmdEnv
);
181 if (m_context
== "user")
182 dbName
= m_activePackages_expanded
+ ".pmap";
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())
208 Reference
<sdbc::XRow
>(
209 xResultSet
, UNO_QUERY_THROW
)->getString(
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
) );
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
))
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.
241 if (std::find(removedEntries
.begin(), removedEntries
.end(), tempEntry
) ==
242 removedEntries
.end())
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.
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()),
265 OUString sData
= OStringToOUString(
266 osData
, RTL_TEXTENCODING_UTF8
);
267 if (sData
!= aUserName
)
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
) );
299 osl::FileBase::RC
createDirectory(OUString
const & url
) {
300 auto e
= osl::Directory::create(url
);
301 if (e
!= osl::FileBase::E_NOENT
) {
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
) {
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
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
;
335 bError
= aFile
.write( "1", 1, nWritten
) != ::osl::FileBase::E_None
;
336 if (aFile
.close() != ::osl::FileBase::E_None
)
338 if (osl::File::remove( aFileURL
) != ::osl::FileBase::E_None
)
342 "desktop.deployment",
343 "local url '" << rMacro
<< "' -> '" << aFileURL
<< "' "
344 << (bError
? "is" : "is not") << " readonly\n");
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";
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
;
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],
439 that
->m_xComponentContext
),
441 xCmdEnv
.set( new CmdEnvWrapperImpl( xCmdEnv
, that
->m_xLogFile
) );
444 that
->initRegistryBackends();
445 that
->initActivationLayer( xCmdEnv
);
447 return xPackageManager
;
450 catch (const RuntimeException
&) {
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()
483 // // xxx todo: guarding?
484 // ::osl::MutexGuard guard( getMutex() );
485 try_dispose( m_xLogFile
);
487 try_dispose( m_xRegistry
);
489 m_activePackagesDB
.reset();
490 m_xComponentContext
.clear();
492 t_pm_helper::disposing();
495 catch (const RuntimeException
&) {
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
);
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
);
535 OUString
PackageManagerImpl::getContext()
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()
553 return new AbortChannel
;
556 // XModifyBroadcaster
558 void PackageManagerImpl::addModifyListener(
559 Reference
<util::XModifyListener
> const & xListener
)
562 rBHelper
.addListener( cppu::UnoType
<decltype(xListener
)>::get(), xListener
);
566 void PackageManagerImpl::removeModifyListener(
567 Reference
<util::XModifyListener
> const & xListener
)
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() );
580 if (url
.match( "vnd.sun.star.tdoc:" ) || url
.match( "vnd.sun.star.pkg:" ))
583 ucbContent
.getPropertyValue( "MediaType" ) >>= mediaType
;
585 catch (const beans::UnknownPropertyException
&) {
587 OSL_ENSURE( !mediaType
.isEmpty(), "### no media-type?!" );
589 if (mediaType
.isEmpty())
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
&) {
604 css::uno::Any
ex( cppu::getCaughtException() );
605 SAL_WARN( "desktop", exceptionToString(ex
) );
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"))
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
) );
648 //Folder. No need to unzip, just copy
649 buf
.append(sourceContent
.getURL());
652 sourceContent
= ::ucbhelper::Content(
653 buf
.makeStringAndClear(), xCmdEnv
, m_xComponentContext
);
655 destFolderContent
.transferContent(
656 sourceContent
, ::ucbhelper::InsertOperation::Copy
,
657 title
, NameClash::OVERWRITE
);
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
);
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
))
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_
)
729 if (m_context
== "shared")
730 message
= "You need write permissions to install a shared extension!";
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
;
738 xCmdEnv
.set( new CmdEnvWrapperImpl( xCmdEnv_
, m_xLogFile
) );
740 xCmdEnv
.set( xCmdEnv_
);
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
) );
752 OUString
mediaType(mediaType_
);
753 if (mediaType
.isEmpty())
754 mediaType
= detectMediaType( sourceContent
);
756 Reference
<deployment::XPackage
> xPackage
;
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
,
768 NameClash::ASK
/* xxx todo: ASK not needed? */);
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
776 docContent
.setPropertyValue("MediaType", Any(mediaType
) );
778 // xxx todo: obsolete in the future
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() );
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
,
814 insertToActivationLayerDB(id
, dbData
);
818 deletePackageFromCache( xPackage
, destFolder
);
823 deletePackageFromCache( xPackage
, destFolder
);
825 //ToDo: We should notify only if the extension is registered
830 catch (const RuntimeException
&) {
833 catch (const CommandFailedException
& exc
) {
834 logIntern( Any(exc
) );
837 catch (const CommandAbortedException
& exc
) {
838 logIntern( Any(exc
) );
841 catch (const deployment::DeploymentException
& exc
) {
842 logIntern( Any(exc
) );
845 catch (const Exception
&) {
846 Any
exc( ::cppu::getCaughtException() );
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_
)
877 Reference
<XCommandEnvironment
> xCmdEnv
;
879 xCmdEnv
.set( new CmdEnvWrapperImpl( xCmdEnv_
, m_xLogFile
) );
881 xCmdEnv
.set( xCmdEnv_
);
884 Reference
<deployment::XPackage
> xPackage
;
886 const ::osl::MutexGuard
guard(getMutex());
887 //Check if this extension exist and throw an IllegalArgumentException
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
);
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
);
929 catch (const RuntimeException
&) {
932 catch (const CommandFailedException
& exc
) {
933 logIntern( Any(exc
) );
936 catch (const CommandAbortedException
& exc
) {
937 logIntern( Any(exc
) );
940 catch (const deployment::DeploymentException
& exc
) {
941 logIntern( Any(exc
) );
944 catch (const Exception
&) {
945 Any
exc( ::cppu::getCaughtException() );
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
)
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")
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
, ¶ms
))
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
;
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")
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
&) {
1043 TOOLS_WARN_EXCEPTION( "desktop", "" );
1045 catch (const deployment::DeploymentException
&) {
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_
)
1059 Reference
<XCommandEnvironment
> xCmdEnv
;
1060 if (m_xLogFile
.is())
1061 xCmdEnv
.set( new CmdEnvWrapperImpl( xCmdEnv_
, m_xLogFile
) );
1063 xCmdEnv
.set( xCmdEnv_
);
1066 const ::osl::MutexGuard
guard( getMutex() );
1067 return getDeployedPackage_( id
, fileName
, xCmdEnv
);
1069 catch (const lang::IllegalArgumentException
& exc
) {
1070 logIntern( Any(exc
) );
1073 catch (const RuntimeException
&) {
1076 catch (const CommandFailedException
& exc
) {
1077 logIntern( Any(exc
) );
1080 catch (const deployment::DeploymentException
& exc
) {
1081 logIntern( Any(exc
) );
1084 catch (const Exception
&) {
1085 Any
exc( ::cppu::getCaughtException() );
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_
)
1101 Reference
<XCommandEnvironment
> xCmdEnv
;
1102 if (m_xLogFile
.is())
1103 xCmdEnv
.set( new CmdEnvWrapperImpl( xCmdEnv_
, m_xLogFile
) );
1105 xCmdEnv
.set( xCmdEnv_
);
1108 const ::osl::MutexGuard
guard( getMutex() );
1109 return getDeployedPackages_( xCmdEnv
);
1111 catch (const RuntimeException
&) {
1114 catch (const CommandFailedException
& exc
) {
1115 logIntern( Any(exc
) );
1118 catch (const CommandAbortedException
& exc
) {
1119 logIntern( Any(exc
) );
1122 catch (const deployment::DeploymentException
& exc
) {
1123 logIntern( Any(exc
) );
1126 catch (const Exception
&) {
1127 Any
exc( ::cppu::getCaughtException() );
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_
)
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
) );
1153 xCmdEnv
.set( xCmdEnv_
);
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
&) {
1173 catch (const CommandFailedException
& exc
) {
1174 logIntern( Any(exc
) );
1177 catch (const CommandAbortedException
& exc
) {
1178 logIntern( Any(exc
) );
1181 catch (const deployment::DeploymentException
& exc
) {
1182 logIntern( Any(exc
) );
1185 catch (const Exception
&) {
1186 Any
exc( ::cppu::getCaughtException() );
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( )
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
);
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))
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(
1243 m_activePackages_expanded
+ "/" +
1244 elem
.second
.temporaryName
+ "removed",
1245 Reference
<XCommandEnvironment
>(), false))
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()))
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
);
1279 catch( const uno::Exception
& )
1281 TOOLS_WARN_EXCEPTION("desktop.deployment", "");
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.
1301 bOk
= create_ucb_content(
1302 nullptr, m_activePackages_expanded
, Reference
<css::ucb::XCommandEnvironment
>(), false);
1304 catch (const css::ucb::ContentCreationException
&)
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())
1322 Reference
<sdbc::XRow
>(
1323 xResultSet
, UNO_QUERY_THROW
)->getString(
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");
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
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))
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
);
1368 OUString id
= dp_misc::getIdentifier( xPackage
);
1370 //Prepare the database entry
1371 ActivePackages::Data dbData
;
1373 dbData
.temporaryName
= titleEncoded
;
1375 dbData
.fileName
= sExtFolder
;
1377 dbData
.fileName
= title
;
1378 dbData
.mediaType
= xPackage
->getPackageType()->getMediaType();
1379 dbData
.version
= xPackage
->getVersion();
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())
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
);
1416 catch (const uno::Exception
&)
1418 // Looks like exceptions being caught here is not an uncommon case.
1419 TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1425 sal_Bool
PackageManagerImpl::synchronize(
1426 Reference
<task::XAbortChannel
> const & xAbortChannel
,
1427 Reference
<css::ucb::XCommandEnvironment
> const & xCmdEnv
)
1430 bool bModified
= false;
1431 if (m_context
== "user")
1434 synchronizeRemovedExtensions(xAbortChannel
, xCmdEnv
);
1435 bModified
|= synchronizeAddedExtensions(xAbortChannel
, xCmdEnv
);
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
1460 if (failedPrereq
^= deployment::Prerequisites::LICENSE
)
1463 //Prepare the URL to the extension
1464 OUString url
= makeURL(m_activePackages
, elem
.second
.temporaryName
);
1466 url
= makeURLAppendSysPathSegment( url
+ "_", elem
.second
.fileName
);
1468 Reference
<deployment::XPackage
> p
= m_xRegistry
->bindPackage(
1469 url
, OUString(), false, OUString(), xCmdEnv
);
1475 return ::comphelper::containerToSequence(vec
);
1477 catch (const deployment::DeploymentException
&)
1481 catch (const RuntimeException
&)
1487 Any exc
= ::cppu::getCaughtException();
1488 deployment::DeploymentException
de(
1489 "PackageManagerImpl::getExtensionsWithUnacceptedLicenses",
1490 static_cast<OWeakObject
*>(this), exc
);
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())
1507 if (m_context
!= extension
->getRepositoryName())
1508 throw lang::IllegalArgumentException(
1509 "PackageManagerImpl::checkPrerequisites: extension is not from this repository.",
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",
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
);
1533 catch ( const deployment::DeploymentException
& ) {
1535 } catch ( const ucb::CommandFailedException
& ) {
1537 } catch ( const ucb::CommandAbortedException
& ) {
1539 } catch (const lang::IllegalArgumentException
&) {
1541 } catch (const uno::RuntimeException
&) {
1544 uno::Any excOccurred
= ::cppu::getCaughtException();
1545 deployment::DeploymentException
exc(
1546 "PackageManagerImpl::checkPrerequisites: exception ",
1547 static_cast<OWeakObject
*>(this), excOccurred
);
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()
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())
1608 if (m_xUserProgress
.is())
1609 m_xUserProgress
->pop();
1612 } // namespace dp_manager
1614 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */