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( data.temporaryName );
945 //The bundled extensions are not contained in an additional folder
946 //with a unique name. data.temporaryName contains already the
947 //UTF8 encoded folder name. See PackageManagerImpl::synchronize
948 if (m_context != "bundled")
949 {
950 buf.append( "_/"
951 + ::rtl::Uri::encode( data.fileName, rtl_UriCharClassPchar,
952 rtl_UriEncodeIgnoreEscapes,
953 RTL_TEXTENCODING_UTF8 ) );
954 }
955 return makeURL( m_activePackages, buf.makeStringAndClear() );
956}
957
958
959Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
960 OUString const & id, OUString const & fileName,
961 Reference<XCommandEnvironment> const & xCmdEnv )
962{
964 if (m_activePackagesDB->get( &val, id, fileName ))
965 {
966 return getDeployedPackage_( id, val, xCmdEnv );
967 }
968 throw lang::IllegalArgumentException(
969 DpResId(RID_STR_NO_SUCH_PACKAGE) + id,
970 static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) );
971}
972
973
974Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage_(
975 std::u16string_view id, ActivePackages::Data const & data,
976 Reference<XCommandEnvironment> const & xCmdEnv, bool ignoreAlienPlatforms )
977{
978 if (ignoreAlienPlatforms)
979 {
980 OUString type, subType;
982 if (INetContentTypes::parse( data.mediaType, type, subType, &params ))
983 {
984 auto const iter = params.find(OString("platform"));
985 if (iter != params.end() && !platform_fits(iter->second.m_sValue))
986 throw lang::IllegalArgumentException(
987 DpResId(RID_STR_NO_SUCH_PACKAGE) + id,
988 static_cast<OWeakObject *>(this),
989 static_cast<sal_Int16>(-1) );
990 }
991 }
992 Reference<deployment::XPackage> xExtension;
993 try
994 {
995 //Ignore extensions where XPackage::checkPrerequisites failed.
996 //They must not be usable for this user.
997 if (data.failedPrerequisites == "0")
998 {
999 xExtension = m_xRegistry->bindPackage(
1000 getDeployPath( data ), data.mediaType, false, OUString(), xCmdEnv );
1001 }
1002 }
1003 catch (const deployment::InvalidRemovedParameterException& e)
1004 {
1005 xExtension = e.Extension;
1006 }
1007 return xExtension;
1008}
1009
1010
1011Sequence< Reference<deployment::XPackage> >
1013 Reference<XCommandEnvironment> const & xCmdEnv )
1014{
1015 std::vector< Reference<deployment::XPackage> > packages;
1016 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1017 for (auto const& elem : id2temp)
1018 {
1019 if (elem.second.failedPrerequisites != "0")
1020 continue;
1021 try {
1022 packages.push_back(
1024 elem.first, elem.second, xCmdEnv,
1025 true /* xxx todo: think of GUI:
1026 ignore other platforms than the current one */ ) );
1027 }
1028 catch (const lang::IllegalArgumentException &) {
1029 // ignore
1030 TOOLS_WARN_EXCEPTION( "desktop", "" );
1031 }
1032 catch (const deployment::DeploymentException&) {
1033 // ignore
1034 TOOLS_WARN_EXCEPTION( "desktop", "" );
1035 }
1036 }
1037 return comphelper::containerToSequence(packages);
1038}
1039
1040
1041Reference<deployment::XPackage> PackageManagerImpl::getDeployedPackage(
1042 OUString const & id, OUString const & fileName,
1043 Reference<XCommandEnvironment> const & xCmdEnv_ )
1044{
1045 check();
1046 Reference<XCommandEnvironment> xCmdEnv;
1047 if (m_xLogFile.is())
1048 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1049 else
1050 xCmdEnv.set( xCmdEnv_ );
1051
1052 try {
1053 const ::osl::MutexGuard guard( m_aMutex );
1054 return getDeployedPackage_( id, fileName, xCmdEnv );
1055 }
1056 catch (const RuntimeException &) {
1057 throw;
1058 }
1059 catch (const CommandFailedException & exc) {
1060 logIntern( Any(exc) );
1061 throw;
1062 }
1063 catch (const deployment::DeploymentException & exc) {
1064 logIntern( Any(exc) );
1065 throw;
1066 }
1067 catch (const Exception &) {
1068 Any exc( ::cppu::getCaughtException() );
1069 logIntern( exc );
1070 throw deployment::DeploymentException(
1071 // ought never occur...
1072 "error while accessing deployed package: " + id,
1073 static_cast<OWeakObject *>(this), exc );
1074 }
1075}
1076
1077
1078Sequence< Reference<deployment::XPackage> >
1080 Reference<task::XAbortChannel> const &,
1081 Reference<XCommandEnvironment> const & xCmdEnv_ )
1082{
1083 check();
1084 Reference<XCommandEnvironment> xCmdEnv;
1085 if (m_xLogFile.is())
1086 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1087 else
1088 xCmdEnv.set( xCmdEnv_ );
1089
1090 try {
1091 const ::osl::MutexGuard guard( m_aMutex );
1092 return getDeployedPackages_( xCmdEnv );
1093 }
1094 catch (const RuntimeException &) {
1095 throw;
1096 }
1097 catch (const CommandFailedException & exc) {
1098 logIntern( Any(exc) );
1099 throw;
1100 }
1101 catch (const CommandAbortedException & exc) {
1102 logIntern( Any(exc) );
1103 throw;
1104 }
1105 catch (const deployment::DeploymentException & exc) {
1106 logIntern( Any(exc) );
1107 throw;
1108 }
1109 catch (const Exception &) {
1110 Any exc( ::cppu::getCaughtException() );
1111 logIntern( exc );
1112 throw deployment::DeploymentException(
1113 // ought never occur...
1114 "error while getting all deployed packages: " + m_context,
1115 static_cast<OWeakObject *>(this), exc );
1116 }
1117}
1118
1119
1120//ToDo: the function must not call registerPackage, do this in
1121//XExtensionManager.reinstallDeployedExtensions
1123 sal_Bool force, Reference<task::XAbortChannel> const & /*xAbortChannel*/,
1124 Reference<XCommandEnvironment> const & xCmdEnv_ )
1125{
1126 check();
1127 if (!force && office_is_running())
1128 throw RuntimeException(
1129 "You must close any running Office process before reinstalling packages!",
1130 static_cast<OWeakObject *>(this) );
1131
1132 Reference<XCommandEnvironment> xCmdEnv;
1133 if (m_xLogFile.is())
1134 xCmdEnv.set( new CmdEnvWrapperImpl( xCmdEnv_, m_xLogFile ) );
1135 else
1136 xCmdEnv.set( xCmdEnv_ );
1137
1138 try {
1139 ProgressLevel progress(
1140 xCmdEnv, "Reinstalling all deployed packages..." );
1141
1143 m_xRegistry.clear();
1144 if (!m_registryCache.isEmpty())
1145 erase_path( m_registryCache, xCmdEnv );
1147 Reference<util::XUpdatable> xUpdatable( m_xRegistry, UNO_QUERY );
1148 if (xUpdatable.is())
1149 xUpdatable->update();
1150
1151 //registering is done by the ExtensionManager service.
1152 }
1153 catch (const RuntimeException &) {
1154 throw;
1155 }
1156 catch (const CommandFailedException & exc) {
1157 logIntern( Any(exc) );
1158 throw;
1159 }
1160 catch (const CommandAbortedException & exc) {
1161 logIntern( Any(exc) );
1162 throw;
1163 }
1164 catch (const deployment::DeploymentException & exc) {
1165 logIntern( Any(exc) );
1166 throw;
1167 }
1168 catch (const Exception &) {
1169 Any exc( ::cppu::getCaughtException() );
1170 logIntern( exc );
1171 throw deployment::DeploymentException(
1172 "Error while reinstalling all previously deployed packages of context " + m_context,
1173 static_cast<OWeakObject *>(this), exc );
1174 }
1175}
1176
1177
1179{
1180 return m_readOnly;
1181}
1183 Reference<task::XAbortChannel> const & xAbortChannel,
1184 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
1185{
1186
1187 //find all which are in the extension data base but which
1188 //are removed already.
1189 OSL_ASSERT(!(m_context == "user"));
1190 bool bModified = false;
1191 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1192
1193 bool bShared = (m_context == "shared");
1194
1195 for (auto const& elem : id2temp)
1196 {
1197 try
1198 {
1199 //Get the URL to the extensions folder, first make the url for the
1200 //shared repository including the temporary name
1201 OUString url = makeURL(m_activePackages, elem.second.temporaryName);
1202 if (bShared)
1203 url = makeURLAppendSysPathSegment( Concat2View(url + "_"), elem.second.fileName);
1204
1205 bool bRemoved = false;
1206 //Check if the URL to the extension is still the same
1207 ::ucbhelper::Content contentExtension;
1208
1209 if (!create_ucb_content(
1210 &contentExtension, url,
1211 Reference<XCommandEnvironment>(), false))
1212 {
1213 bRemoved = true;
1214 }
1215
1216 //The folder is in the extension database, but it can still be deleted.
1217 //look for the xxx.tmpremoved file
1218 //There can also be the case that a different extension was installed
1219 //in a "temp" folder with name that is already used.
1220 if (!bRemoved && bShared)
1221 {
1222 ::ucbhelper::Content contentRemoved;
1223
1225 &contentRemoved,
1227 elem.second.temporaryName + "removed",
1228 Reference<XCommandEnvironment>(), false))
1229 {
1230 bRemoved = true;
1231 }
1232 }
1233
1234 if (!bRemoved)
1235 {
1236 //There may be another extensions at the same place
1239 OSL_ENSURE(infoset.hasDescription() && infoset.getIdentifier(),
1240 "Extension Manager: bundled and shared extensions "
1241 "must have an identifier and a version");
1242 if (infoset.hasDescription() &&
1243 infoset.getIdentifier() &&
1244 ( elem.first != *(infoset.getIdentifier())
1245 || elem.second.version != infoset.getVersion()))
1246 {
1247 bRemoved = true;
1248 }
1249
1250 }
1251 if (bRemoved)
1252 {
1253 Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1254 url, elem.second.mediaType, true, elem.first, xCmdEnv );
1255 OSL_ASSERT(xPackage.is()); //Even if the files are removed, we must get the object.
1256 xPackage->revokePackage(true, xAbortChannel, xCmdEnv);
1257 removePackage(xPackage->getIdentifier().Value, xPackage->getName(),
1258 xAbortChannel, xCmdEnv);
1259 bModified = true;
1260 }
1261 }
1262 catch( const uno::Exception & )
1263 {
1264 TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1265 }
1266 }
1267 return bModified;
1268}
1269
1270
1272 Reference<task::XAbortChannel> const & xAbortChannel,
1273 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
1274{
1275 bool bModified = false;
1276 OSL_ASSERT(!(m_context == "user"));
1277
1278 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1279 //check if the folder exist at all. The shared extension folder
1280 //may not exist for a normal user.
1281 bool bOk=true;
1282 try
1283 {
1284 bOk = create_ucb_content(
1285 nullptr, m_activePackages_expanded, Reference<css::ucb::XCommandEnvironment>(), false);
1286 }
1287 catch (const css::ucb::ContentCreationException&)
1288 {
1289 bOk = false;
1290 }
1291
1292 if (!bOk)
1293 return bModified;
1294
1296 Reference<sdbc::XResultSet> xResultSet(
1297 StrTitle::createCursor( tempFolder,
1298 ::ucbhelper::INCLUDE_FOLDERS_ONLY ) );
1299
1300 while (xResultSet->next())
1301 {
1302 try
1303 {
1304 OUString title(
1305 Reference<sdbc::XRow>(
1306 xResultSet, UNO_QUERY_THROW )->getString(
1307 1 /* Title */ ) );
1308 //The temporary folders of user and shared have an '_' at then end.
1309 //But the name in ActivePackages.temporaryName is saved without.
1310 OUString title2 = title;
1311 bool bShared = (m_context == "shared");
1312 if (bShared)
1313 {
1314 OSL_ASSERT(title2.endsWith("_"));
1315 title2 = title2.copy(0, title2.getLength() -1);
1316 }
1317 OUString titleEncoded = ::rtl::Uri::encode(
1318 title2, rtl_UriCharClassPchar,
1319 rtl_UriEncodeIgnoreEscapes,
1320 RTL_TEXTENCODING_UTF8);
1321
1322 //It is sufficient to check for the folder name, because when the administrator
1323 //installed the extension it was already checked if there is one with the
1324 //same identifier.
1325 const MatchTempDir match(titleEncoded);
1326 if (std::none_of( id2temp.begin(), id2temp.end(), match ))
1327 {
1328
1329 // The folder was not found in the data base, so it must be
1330 // an added extension
1331 OUString url(m_activePackages_expanded + "/" + titleEncoded);
1332 OUString sExtFolder;
1333 if (bShared) //that is, shared
1334 {
1335 //Check if the extension was not "deleted" already which is indicated
1336 //by a xxx.tmpremoved file
1337 ::ucbhelper::Content contentRemoved;
1338 if (create_ucb_content(&contentRemoved, url + "removed",
1339 Reference<XCommandEnvironment>(), false))
1340 continue;
1341 sExtFolder = getExtensionFolder(
1342 m_activePackages_expanded + "/" + titleEncoded + "_",
1343 xCmdEnv, m_xComponentContext);
1345 url = makeURLAppendSysPathSegment(url, sExtFolder);
1346 }
1347 Reference<deployment::XPackage> xPackage = m_xRegistry->bindPackage(
1348 url, OUString(), false, OUString(), xCmdEnv );
1349 if (xPackage.is())
1350 {
1351 OUString id = dp_misc::getIdentifier( xPackage );
1352
1353 //Prepare the database entry
1354 ActivePackages::Data dbData;
1355
1356 dbData.temporaryName = titleEncoded;
1357 if (bShared)
1358 dbData.fileName = sExtFolder;
1359 else
1360 dbData.fileName = title;
1361 dbData.mediaType = xPackage->getPackageType()->getMediaType();
1362 dbData.version = xPackage->getVersion();
1364 dbData.version.isEmpty(), "desktop.deployment",
1365 "bundled/shared extension " << id << " at <" << url
1366 << "> has no explicit version");
1367
1368 //We provide a special command environment that will prevent
1369 //showing a license if simple-license/@accept-by = "admin"
1370 //It will also prevent showing the license for bundled extensions
1371 //which is not supported.
1372 OSL_ASSERT(!(m_context == "user"));
1373
1374 // shall the license be suppressed?
1375 DescriptionInfoset info =
1377 ::std::optional<dp_misc::SimpleLicenseAttributes>
1378 attr = info.getSimpleLicenseAttributes();
1380 bool bNoLicense = false;
1381 if (attr && attr->suppressIfRequired && props.isSuppressedLicense())
1382 bNoLicense = true;
1383
1384 Reference<ucb::XCommandEnvironment> licCmdEnv(
1385 new LicenseCommandEnv(xCmdEnv->getInteractionHandler(),
1386 bNoLicense, m_context));
1387 sal_Int32 failedPrereq = xPackage->checkPrerequisites(
1388 xAbortChannel, licCmdEnv, false);
1389 //Remember that this failed. For example, the user
1390 //could have declined the license. Then the next time the
1391 //extension folder is investigated we do not want to
1392 //try to install the extension again.
1393 dbData.failedPrerequisites = OUString::number(failedPrereq);
1394 insertToActivationLayerDB(id, dbData);
1395 bModified = true;
1396 }
1397 }
1398 }
1399 catch (const uno::Exception &)
1400 {
1401 // Looks like exceptions being caught here is not an uncommon case.
1402 TOOLS_WARN_EXCEPTION("desktop.deployment", "");
1403 }
1404 }
1405 return bModified;
1406}
1407
1409 Reference<task::XAbortChannel> const & xAbortChannel,
1410 Reference<css::ucb::XCommandEnvironment> const & xCmdEnv)
1411{
1412 check();
1413 bool bModified = false;
1414 if (m_context == "user")
1415 return bModified;
1416 bModified |=
1417 synchronizeRemovedExtensions(xAbortChannel, xCmdEnv);
1418 bModified |= synchronizeAddedExtensions(xAbortChannel, xCmdEnv);
1419
1420 return bModified;
1421}
1422
1423Sequence< Reference<deployment::XPackage> > PackageManagerImpl::getExtensionsWithUnacceptedLicenses(
1424 Reference<ucb::XCommandEnvironment> const & xCmdEnv)
1425{
1426 std::vector<Reference<deployment::XPackage> > vec;
1427
1428 try
1429 {
1430 const ::osl::MutexGuard guard( m_aMutex );
1431 // clean up activation layer, scan for zombie temp dirs:
1432 ActivePackages::Entries id2temp( m_activePackagesDB->getEntries() );
1433
1434 bool bShared = (m_context == "shared");
1435
1436 for (auto const& elem : id2temp)
1437 {
1438 //Get the database entry
1439 ActivePackages::Data const & dbData = elem.second;
1440 sal_Int32 failedPrereq = dbData.failedPrerequisites.toInt32();
1441 //If the installation failed for other reason then the license then we
1442 //ignore it.
1443 if (failedPrereq ^ deployment::Prerequisites::LICENSE)
1444 continue;
1445
1446 //Prepare the URL to the extension
1447 OUString url = makeURL(m_activePackages, elem.second.temporaryName);
1448 if (bShared)
1449 url = makeURLAppendSysPathSegment( Concat2View(url + "_"), elem.second.fileName);
1450
1451 Reference<deployment::XPackage> p = m_xRegistry->bindPackage(
1452 url, OUString(), false, OUString(), xCmdEnv );
1453
1454 if (p.is())
1455 vec.push_back(p);
1456
1457 }
1458 return ::comphelper::containerToSequence(vec);
1459 }
1460 catch (const deployment::DeploymentException &)
1461 {
1462 throw;
1463 }
1464 catch (const RuntimeException&)
1465 {
1466 throw;
1467 }
1468 catch (...)
1469 {
1470 Any exc = ::cppu::getCaughtException();
1471 deployment::DeploymentException de(
1472 "PackageManagerImpl::getExtensionsWithUnacceptedLicenses",
1473 static_cast<OWeakObject*>(this), exc);
1474 exc <<= de;
1475 ::cppu::throwException(exc);
1476 }
1477
1478 return ::comphelper::containerToSequence(vec);
1479}
1480
1482 css::uno::Reference<css::deployment::XPackage> const & extension,
1483 css::uno::Reference<css::task::XAbortChannel> const & xAbortChannel,
1484 css::uno::Reference<css::ucb::XCommandEnvironment> const & xCmdEnv )
1485{
1486 try
1487 {
1488 if (!extension.is())
1489 return 0;
1490 if (m_context != extension->getRepositoryName())
1491 throw lang::IllegalArgumentException(
1492 "PackageManagerImpl::checkPrerequisites: extension is not from this repository.",
1493 nullptr, 0);
1494
1495 ActivePackages::Data dbData;
1496 OUString id = dp_misc::getIdentifier(extension);
1497 if (!m_activePackagesDB->get( &dbData, id, OUString()))
1498 {
1499 throw lang::IllegalArgumentException(
1500 "PackageManagerImpl::checkPrerequisites: unknown extension",
1501 nullptr, 0);
1502
1503 }
1504 //If the license was already displayed, then do not show it again
1505 Reference<ucb::XCommandEnvironment> _xCmdEnv = xCmdEnv;
1506 sal_Int32 prereq = dbData.failedPrerequisites.toInt32();
1507 if ( !(prereq & deployment::Prerequisites::LICENSE))
1508 _xCmdEnv = new NoLicenseCommandEnv(xCmdEnv->getInteractionHandler());
1509
1510 sal_Int32 failedPrereq = extension->checkPrerequisites(
1511 xAbortChannel, _xCmdEnv, false);
1512 dbData.failedPrerequisites = OUString::number(failedPrereq);
1513 insertToActivationLayerDB(id, dbData);
1514 return 0;
1515 }
1516 catch ( const deployment::DeploymentException& ) {
1517 throw;
1518 } catch ( const ucb::CommandFailedException & ) {
1519 throw;
1520 } catch ( const ucb::CommandAbortedException & ) {
1521 throw;
1522 } catch (const lang::IllegalArgumentException &) {
1523 throw;
1524 } catch (const uno::RuntimeException &) {
1525 throw;
1526 } catch (...) {
1527 uno::Any excOccurred = ::cppu::getCaughtException();
1528 deployment::DeploymentException exc(
1529 "PackageManagerImpl::checkPrerequisites: exception ",
1530 static_cast<OWeakObject*>(this), excOccurred);
1531 throw exc;
1532 }
1533}
1534
1535
1537{
1538}
1539
1540
1542 Reference<XCommandEnvironment> const & xUserCmdEnv,
1543 Reference<XProgressHandler> const & xLogFile )
1544 : m_xLogFile( xLogFile )
1545{
1546 if (xUserCmdEnv.is()) {
1547 m_xUserProgress.set( xUserCmdEnv->getProgressHandler() );
1548 m_xUserInteractionHandler.set( xUserCmdEnv->getInteractionHandler() );
1549 }
1550}
1551
1552// XCommandEnvironment
1553
1554Reference<task::XInteractionHandler>
1556{
1557 return m_xUserInteractionHandler;
1558}
1559
1560
1561Reference<XProgressHandler>
1563{
1564 return this;
1565}
1566
1567// XProgressHandler
1568
1570{
1571 if (m_xLogFile.is())
1572 m_xLogFile->push( Status );
1573 if (m_xUserProgress.is())
1574 m_xUserProgress->push( Status );
1575}
1576
1577
1579{
1580 if (m_xLogFile.is())
1581 m_xLogFile->update( Status );
1582 if (m_xUserProgress.is())
1583 m_xUserProgress->update( Status );
1584}
1585
1586
1588{
1589 if (m_xLogFile.is())
1590 m_xLogFile->pop();
1591 if (m_xUserProgress.is())
1592 m_xUserProgress->pop();
1593}
1594
1595} // namespace dp_manager
1596
1597/* 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:555
float v
std::unordered_map< OString, INetContentTypeParameter > INetContentTypeParameterList
static uno::Reference< css::uno::XComponentContext > xContext
Definition: init.cxx:2642
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:253
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:315
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:331
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:283
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)