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