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