diff options
Diffstat (limited to 'desktop/source/deployment/registry/configuration')
3 files changed, 1053 insertions, 0 deletions
diff --git a/desktop/source/deployment/registry/configuration/dp_configuration.cxx b/desktop/source/deployment/registry/configuration/dp_configuration.cxx new file mode 100644 index 000000000..62d5ab88f --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configuration.cxx @@ -0,0 +1,818 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +//TODO: Large parts of this file were copied from dp_component.cxx; those parts +// should be consolidated. + +#include <config_extensions.h> + +#include <dp_backend.h> +#if HAVE_FEATURE_EXTENSIONS +#include <dp_persmap.h> +#endif +#include <dp_misc.h> +#include <dp_ucb.h> +#include <rtl/string.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <ucbhelper/content.hxx> +#include <unotools/ucbhelper.hxx> +#include <xmlscript/xml_helper.hxx> +#include <comphelper/lok.hxx> +#include <svl/inettype.hxx> +#include <o3tl/string_view.hxx> +#include <com/sun/star/configuration/Update.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <deque> +#include <memory> +#include <string_view> +#include <utility> + +#include "dp_configurationbackenddb.hxx" + +using namespace ::dp_misc; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; + +namespace dp_registry::backend::configuration { +namespace { + +class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend +{ + class PackageImpl : public ::dp_registry::backend::Package + { + BackendImpl * getMyBackend() const ; + + const bool m_isSchema; + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) override; + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) override; + + public: + PackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool isSchema, bool bRemoved, OUString const & identifier) + : Package( myBackend, url, name, name /* display-name */, + xPackageType, bRemoved, identifier), + m_isSchema( isSchema ) + {} + }; + friend class PackageImpl; + + std::deque<OUString> m_xcs_files; + std::deque<OUString> m_xcu_files; + std::deque<OUString> & getFiles( bool xcs ) { + return xcs ? m_xcs_files : m_xcu_files; + } + + bool m_configmgrini_inited; + bool m_configmgrini_modified; + std::unique_ptr<ConfigurationBackendDb> m_backendDb; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, bool bRemoved, + OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ) override; + +#if HAVE_FEATURE_EXTENSIONS + // for backwards compatibility - nil if no (compatible) back-compat db present + std::unique_ptr<PersistentMap> m_registeredPackages; +#endif + + virtual void SAL_CALL disposing() override; + + const Reference<deployment::XPackageTypeInfo> m_xConfDataTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xConfSchemaTypeInfo; + Sequence< Reference<deployment::XPackageTypeInfo> > m_typeInfos; + + void configmgrini_verify_init( + Reference<XCommandEnvironment> const & xCmdEnv ); + void configmgrini_flush( Reference<XCommandEnvironment> const & xCmdEnv ); + + /* The parameter isURL is false in the case of adding the conf:ini-entry + value from the backend db. This entry already contains the path as it + is used in the configmgr.ini. + */ + void addToConfigmgrIni( bool isSchema, bool isURL, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv ); +#if HAVE_FEATURE_EXTENSIONS + bool removeFromConfigmgrIni( bool isSchema, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv ); +#endif + void addDataToDb(OUString const & url, ConfigurationBackendDb::Data const & data); + ::std::optional<ConfigurationBackendDb::Data> readDataFromDb(std::u16string_view url); + void revokeEntryFromDb(std::u16string_view url); + bool hasActiveEntry(std::u16string_view url); + bool activateEntry(std::u16string_view url); + +public: + BackendImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > SAL_CALL + getSupportedPackageTypes() override; + virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType) override; + + using PackageRegistryBackend::disposing; +}; + + +void BackendImpl::disposing() +{ + try { + configmgrini_flush( Reference<XCommandEnvironment>() ); + + PackageRegistryBackend::disposing(); + } + catch (const RuntimeException &) { + throw; + } + catch (const Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( + "caught unexpected exception while disposing...", + static_cast<OWeakObject *>(this), exc ); + } +} + + +BackendImpl::BackendImpl( + Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ) + : PackageRegistryBackend( args, xComponentContext ), + m_configmgrini_inited( false ), + m_configmgrini_modified( false ), + m_xConfDataTypeInfo( new Package::TypeInfo( + "application/vnd.sun.star.configuration-data", + "*.xcu", + DpResId(RID_STR_CONF_DATA) + ) ), + m_xConfSchemaTypeInfo( new Package::TypeInfo( + "application/vnd.sun.star.configuration-schema", + "*.xcs", + DpResId(RID_STR_CONF_SCHEMA) + ) ), + m_typeInfos{ m_xConfDataTypeInfo, m_xConfSchemaTypeInfo } +{ + const Reference<XCommandEnvironment> xCmdEnv; + + if (transientMode()) + { + // TODO + } + else + { + OUString dbFile = makeURL(getCachePath(), "backenddb.xml"); + m_backendDb.reset( + new ConfigurationBackendDb(getComponentContext(), dbFile)); + //clean up data folders which are no longer used. + //This must not be done in the same process where the help files + //are still registers. Only after revoking and restarting OOo the folders + //can be removed. This works now, because the extension manager is a singleton + //and the backends are only create once per process. + std::vector<OUString> folders = m_backendDb->getAllDataUrls(); + deleteUnusedFolders(folders); + + configmgrini_verify_init( xCmdEnv ); + +#if HAVE_FEATURE_EXTENSIONS + std::unique_ptr<PersistentMap> pMap; + OUString aCompatURL( makeURL( getCachePath(), "registered_packages.pmap" ) ); + + // Don't create it if it doesn't exist already + if ( ::utl::UCBContentHelper::Exists( expandUnoRcUrl( aCompatURL ) ) ) + { + try + { + pMap.reset( new PersistentMap( aCompatURL ) ); + } + catch (const Exception &e) + { + OUString aStr = "Exception loading legacy package database: '" + + e.Message + + "' - ignoring file, please remove it.\n"; + dp_misc::writeConsole( aStr ); + } + } + m_registeredPackages = std::move(pMap); +#endif + } +} + +// XServiceInfo +OUString BackendImpl::getImplementationName() +{ + return "com.sun.star.comp.deployment.configuration.PackageRegistryBackend"; +} + +sal_Bool BackendImpl::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > BackendImpl::getSupportedServiceNames() +{ + return { BACKEND_SERVICE_NAME }; +} + +void BackendImpl::addDataToDb( + OUString const & url, ConfigurationBackendDb::Data const & data) +{ + if (m_backendDb) + m_backendDb->addEntry(url, data); +} + +::std::optional<ConfigurationBackendDb::Data> BackendImpl::readDataFromDb( + std::u16string_view url) +{ + ::std::optional<ConfigurationBackendDb::Data> data; + if (m_backendDb) + data = m_backendDb->getEntry(url); + return data; +} + +void BackendImpl::revokeEntryFromDb(std::u16string_view url) +{ + if (m_backendDb) + m_backendDb->revokeEntry(url); +} + +bool BackendImpl::hasActiveEntry(std::u16string_view url) +{ + if (m_backendDb) + return m_backendDb->hasActiveEntry(url); + return false; +} + +bool BackendImpl::activateEntry(std::u16string_view url) +{ + if (m_backendDb) + return m_backendDb->activateEntry(url); + return false; +} + + +// XPackageRegistry + +Sequence< Reference<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() +{ + return m_typeInfos; +} +void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/) +{ + if (m_backendDb) + m_backendDb->removeEntry(url); +} + +// PackageRegistryBackend + +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, + bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + OUString mediaType( mediaType_ ); + if (mediaType.isEmpty()) + { + // detect media-type: + ::ucbhelper::Content ucbContent; + if (create_ucb_content( &ucbContent, url, xCmdEnv )) + { + const OUString title( StrTitle::getTitle( ucbContent ) ); + if (title.endsWithIgnoreAsciiCase( ".xcu" )) { + mediaType = "application/vnd.sun.star.configuration-data"; + } + if (title.endsWithIgnoreAsciiCase( ".xcs" )) { + mediaType = "application/vnd.sun.star.configuration-schema"; + } + } + if (mediaType.isEmpty()) + throw lang::IllegalArgumentException( + StrCannotDetectMediaType() + url, + static_cast<OWeakObject *>(this), static_cast<sal_Int16>(-1) ); + } + + OUString type, subType; + INetContentTypeParameterList params; + if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) + { + if (type.equalsIgnoreAsciiCase("application")) + { + OUString name; + if (!bRemoved) + { + ::ucbhelper::Content ucbContent( url, xCmdEnv, m_xComponentContext ); + name = StrTitle::getTitle( ucbContent ); + } + + if (subType.equalsIgnoreAsciiCase( "vnd.sun.star.configuration-data")) + { + return new PackageImpl( + this, url, name, m_xConfDataTypeInfo, false /* data file */, + bRemoved, identifier); + } + else if (subType.equalsIgnoreAsciiCase( "vnd.sun.star.configuration-schema")) { + return new PackageImpl( + this, url, name, m_xConfSchemaTypeInfo, true /* schema file */, + bRemoved, identifier); + } + } + } + throw lang::IllegalArgumentException( + StrUnsupportedMediaType() + mediaType, + static_cast<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + + +void BackendImpl::configmgrini_verify_init( + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (transientMode()) + return; + const ::osl::MutexGuard guard( m_aMutex ); + if ( m_configmgrini_inited) + return; + + // common rc: + ::ucbhelper::Content ucb_content; + if (create_ucb_content( + &ucb_content, + makeURL( getCachePath(), "configmgr.ini" ), + xCmdEnv, false /* no throw */ )) + { + OUString line; + if (readLine( &line, "SCHEMA=", ucb_content, + RTL_TEXTENCODING_UTF8 )) + { + sal_Int32 index = RTL_CONSTASCII_LENGTH("SCHEMA="); + do { + OUString token( o3tl::trim(o3tl::getToken(line, 0, ' ', index )) ); + if (!token.isEmpty()) { + //The file may not exist anymore if a shared or bundled + //extension was removed, but it can still be in the configmgrini. + //After running XExtensionManager::synchronize, the configmgrini is + //cleaned up + m_xcs_files.push_back( token ); + } + } + while (index >= 0); + } + if (readLine( &line, "DATA=", ucb_content, + RTL_TEXTENCODING_UTF8 )) { + sal_Int32 index = RTL_CONSTASCII_LENGTH("DATA="); + do { + std::u16string_view token( o3tl::trim(o3tl::getToken(line, 0, ' ', index )) ); + if (!token.empty()) + { + if (token[ 0 ] == '?') + token = token.substr( 1 ); + //The file may not exist anymore if a shared or bundled + //extension was removed, but it can still be in the configmgrini. + //After running XExtensionManager::synchronize, the configmgrini is + //cleaned up + m_xcu_files.push_back( OUString(token) ); + } + } + while (index >= 0); + } + } + m_configmgrini_modified = false; + m_configmgrini_inited = true; +} + + +void BackendImpl::configmgrini_flush( + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + if (transientMode()) + return; + if (!m_configmgrini_inited || !m_configmgrini_modified) + return; + + OStringBuffer buf; + if (! m_xcs_files.empty()) + { + auto iPos( m_xcs_files.cbegin() ); + auto const iEnd( m_xcs_files.cend() ); + buf.append( "SCHEMA=" ); + while (iPos != iEnd) { + // encoded ASCII file-urls: + const OString item( + OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) ); + buf.append( item ); + ++iPos; + if (iPos != iEnd) + buf.append( ' ' ); + } + buf.append(LF); + } + if (! m_xcu_files.empty()) + { + auto iPos( m_xcu_files.cbegin() ); + auto const iEnd( m_xcu_files.cend() ); + buf.append( "DATA=" ); + while (iPos != iEnd) { + // encoded ASCII file-urls: + const OString item( + OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) ); + buf.append( item ); + ++iPos; + if (iPos != iEnd) + buf.append( ' ' ); + } + buf.append(LF); + } + + // write configmgr.ini: + const Reference<io::XInputStream> xData( + ::xmlscript::createInputStream( + reinterpret_cast<sal_Int8 const *>(buf.getStr()), + buf.getLength() ) ); + ::ucbhelper::Content ucb_content( + makeURL( getCachePath(), "configmgr.ini" ), xCmdEnv, m_xComponentContext ); + ucb_content.writeStream( xData, true /* replace existing */ ); + + m_configmgrini_modified = false; +} + + +void BackendImpl::addToConfigmgrIni( bool isSchema, bool isURL, OUString const & url_, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + const OUString rcterm( isURL ? dp_misc::makeRcTerm(url_) : url_ ); + const ::osl::MutexGuard guard( m_aMutex ); + configmgrini_verify_init( xCmdEnv ); + std::deque<OUString> & rSet = getFiles(isSchema); + if (std::find( rSet.begin(), rSet.end(), rcterm ) == rSet.end()) { + rSet.push_front( rcterm ); // prepend to list, thus overriding + // write immediately: + m_configmgrini_modified = true; + configmgrini_flush( xCmdEnv ); + } +} + +#if HAVE_FEATURE_EXTENSIONS +bool BackendImpl::removeFromConfigmgrIni( + bool isSchema, OUString const & url_, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( m_aMutex ); + configmgrini_verify_init( xCmdEnv ); + std::deque<OUString> & rSet = getFiles(isSchema); + auto i(std::find(rSet.begin(), rSet.end(), rcterm)); + if (i == rSet.end() && !isSchema) + { + //in case the xcu contained %origin% then the configmr.ini contains the + //url to the file in the user installation (e.g. $BUNDLED_EXTENSIONS_USER) + //However, m_url (getURL()) contains the URL for the file in the actual + //extension installation. + ::std::optional<ConfigurationBackendDb::Data> data = readDataFromDb(url_); + if (data) + i = std::find(rSet.begin(), rSet.end(), data->iniEntry); + } + if (i == rSet.end()) { + return false; + } + rSet.erase(i); + // write immediately: + m_configmgrini_modified = true; + configmgrini_flush( xCmdEnv ); + return true; +} +#endif + +// Package + + +BackendImpl * BackendImpl::PackageImpl::getMyBackend() const +{ + BackendImpl * pBackend = static_cast<BackendImpl *>(m_myBackend.get()); + if (nullptr == pBackend) + { + //May throw a DisposedException + check(); + //We should never get here... + throw RuntimeException( + "Failed to get the BackendImpl", + static_cast<OWeakObject*>(const_cast<PackageImpl *>(this))); + } + return pBackend; +} + +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::PackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + BackendImpl * that = getMyBackend(); + + bool bReg = false; + if (that->hasActiveEntry(getURL())) + bReg = true; + +#if HAVE_FEATURE_EXTENSIONS + const OUString url(getURL()); + if (!bReg && that->m_registeredPackages) + { + // fallback for user extension registered in berkeley DB + bReg = that->m_registeredPackages->has( + OUStringToOString( url, RTL_TEXTENCODING_UTF8 )); + } +#endif + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true, beans::Ambiguous<sal_Bool>( bReg, false ) ); +} + + +OUString encodeForXml( OUString const & text ) +{ + // encode conforming xml: + sal_Int32 len = text.getLength(); + OUStringBuffer buf; + for ( sal_Int32 pos = 0; pos < len; ++pos ) + { + sal_Unicode c = text[ pos ]; + switch (c) { + case '<': + buf.append( "<" ); + break; + case '>': + buf.append( ">" ); + break; + case '&': + buf.append( "&" ); + break; + case '\'': + buf.append( "'" ); + break; + case '\"': + buf.append( """ ); + break; + default: + buf.append( c ); + break; + } + } + return buf.makeStringAndClear(); +} + + +OUString replaceOrigin( + OUString const & url, std::u16string_view destFolder, Reference< XCommandEnvironment > const & xCmdEnv, Reference< XComponentContext > const & xContext, bool & out_replaced) +{ + // looking for %origin%: + ::ucbhelper::Content ucb_content( url, xCmdEnv, xContext ); + std::vector<sal_Int8> bytes( readFile( ucb_content ) ); + std::vector<sal_Int8> filtered( bytes.size() * 2 ); + bool use_filtered = false; + OString origin; + char const * pBytes = reinterpret_cast<char const *>( + bytes.data()); + std::size_t nBytes = bytes.size(); + size_t write_pos = 0; + while (nBytes > 0) + { + sal_Int32 index = rtl_str_indexOfChar_WithLength( pBytes, nBytes, '%' ); + if (index < 0) { + if (! use_filtered) // opt + break; + index = nBytes; + } + + if ((write_pos + index) > filtered.size()) + filtered.resize( (filtered.size() + index) * 2 ); + memcpy( filtered.data() + write_pos, pBytes, index ); + write_pos += index; + pBytes += index; + nBytes -= index; + if (nBytes == 0) + break; + + // consume %: + ++pBytes; + --nBytes; + char const * pAdd = "%"; + sal_Int32 nAdd = 1; + if (nBytes > 1 && pBytes[ 0 ] == '%') + { + // %% => % + ++pBytes; + --nBytes; + use_filtered = true; + } + else if (rtl_str_shortenedCompare_WithLength( + pBytes, nBytes, + "origin%", + RTL_CONSTASCII_LENGTH("origin%"), + RTL_CONSTASCII_LENGTH("origin%")) == 0) + { + if (origin.isEmpty()) { + // encode only once + origin = OUStringToOString( + encodeForXml( url.copy( 0, url.lastIndexOf( '/' ) ) ), + // xxx todo: encode always for UTF-8? => lookup doc-header? + RTL_TEXTENCODING_UTF8 ); + } + pAdd = origin.getStr(); + nAdd = origin.getLength(); + pBytes += RTL_CONSTASCII_LENGTH("origin%"); + nBytes -= RTL_CONSTASCII_LENGTH("origin%"); + use_filtered = true; + } + if ((write_pos + nAdd) > filtered.size()) + filtered.resize( (filtered.size() + nAdd) * 2 ); + memcpy( filtered.data() + write_pos, pAdd, nAdd ); + write_pos += nAdd; + } + if (!use_filtered) + return url; + if (write_pos < filtered.size()) + filtered.resize( write_pos ); + OUString newUrl(url); + if (!destFolder.empty()) + { + //get the file name of the xcu and add it to the url of the temporary folder + sal_Int32 i = url.lastIndexOf('/'); + newUrl = OUString::Concat(destFolder) + url.subView(i); + } + + ucbhelper::Content(newUrl, xCmdEnv, xContext).writeStream( + xmlscript::createInputStream(std::move(filtered)), true); + out_replaced = true; + return newUrl; +} + + +void BackendImpl::PackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool startup, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & xCmdEnv ) +{ + BackendImpl * that = getMyBackend(); + OUString url( getURL() ); + + if (doRegisterPackage) + { + if (getMyBackend()->activateEntry(getURL())) + { + ::std::optional<ConfigurationBackendDb::Data> data = that->readDataFromDb(url); + OSL_ASSERT(data); + that->addToConfigmgrIni( m_isSchema, false, data->iniEntry, xCmdEnv ); + } + else + { + ConfigurationBackendDb::Data data; + if (!m_isSchema) + { + const OUString sModFolder = that->createFolder(xCmdEnv); + bool out_replaced = false; + url = replaceOrigin(url, sModFolder, xCmdEnv, that->getComponentContext(), out_replaced); + if (out_replaced) + data.dataUrl = sModFolder; + else + deleteTempFolder(sModFolder); + } + //No need for live-deployment for bundled extension, because OOo + //restarts after installation + if ((that->m_eContext != Context::Bundled && !startup) + || comphelper::LibreOfficeKit::isActive()) + { + if (m_isSchema) + { + css::configuration::Update::get( + that->m_xComponentContext)->insertExtensionXcsFile( + that->m_eContext == Context::Shared, expandUnoRcUrl(url)); + } + else + { + css::configuration::Update::get( + that->m_xComponentContext)->insertExtensionXcuFile( + that->m_eContext == Context::Shared, expandUnoRcUrl(url)); + } + } + that->addToConfigmgrIni( m_isSchema, true, url, xCmdEnv ); + data.iniEntry = dp_misc::makeRcTerm(url); + that->addDataToDb(getURL(), data); + } + } + else // revoke + { +#if HAVE_FEATURE_EXTENSIONS + if (!that->removeFromConfigmgrIni(m_isSchema, url, xCmdEnv) && + that->m_registeredPackages) { + // Obsolete package database handling - should be removed for LibreOffice 4.0 + t_string2string_map entries( + that->m_registeredPackages->getEntries()); + for (auto const& entry : entries) + { + //If the xcu file was installed before the configmgr was changed + //to use the configmgr.ini, one needed to rebuild to whole directory + //structure containing the xcu, xcs files from all extensions. Now, + //we just add all other xcu/xcs files to the configmgr.ini instead of + //rebuilding the directory structure. + OUString url2( + OStringToOUString(entry.first, RTL_TEXTENCODING_UTF8)); + if (url2 != url) { + bool schema = entry.second.equalsIgnoreAsciiCase( + "vnd.sun.star.configuration-schema"); + OUString url_replaced(url2); + ConfigurationBackendDb::Data data; + if (!schema) + { + const OUString sModFolder = that->createFolder(xCmdEnv); + bool out_replaced = false; + url_replaced = replaceOrigin( + url2, sModFolder, xCmdEnv, that->getComponentContext(), out_replaced); + if (out_replaced) + data.dataUrl = sModFolder; + else + deleteTempFolder(sModFolder); + } + that->addToConfigmgrIni(schema, true, url_replaced, xCmdEnv); + data.iniEntry = dp_misc::makeRcTerm(url_replaced); + that->addDataToDb(url2, data); + } + that->m_registeredPackages->erase(entry.first); + } + try + { + ::ucbhelper::Content( + makeURL( that->getCachePath(), "registry" ), + xCmdEnv, that->getComponentContext() ).executeCommand( + "delete", Any( true /* delete physically */ ) ); + } + catch(const Exception&) + { + OSL_ASSERT(false); + } + } +#endif + ::std::optional<ConfigurationBackendDb::Data> data = that->readDataFromDb(url); + //If an xcu file was life deployed then always a data entry is written. + //If the xcu file was already in the configmr.ini then there is also + //a data entry + if (!m_isSchema && data) + { + css::configuration::Update::get( + that->m_xComponentContext)->removeExtensionXcuFile(expandUnoRcTerm(data->iniEntry)); + } + that->revokeEntryFromDb(url); + } +} + +} // anon namespace + +} // namespace dp_registry + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_deployment_configuration_PackageRegistryBackend_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args) +{ + return cppu::acquire(new dp_registry::backend::configuration::BackendImpl(args, context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.cxx b/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.cxx new file mode 100644 index 000000000..afdc8112f --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.cxx @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <cppuhelper/exc_hlp.hxx> +#include <com/sun/star/deployment/DeploymentException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/xml/xpath/XXPathAPI.hpp> + +#include "dp_configurationbackenddb.hxx" + + +using namespace ::com::sun::star::uno; + +constexpr OUStringLiteral EXTENSION_REG_NS = u"http://openoffice.org/extensionmanager/configuration-registry/2010"; +constexpr OUStringLiteral NS_PREFIX = u"conf"; +constexpr OUStringLiteral ROOT_ELEMENT_NAME = u"configuration-backend-db"; +constexpr OUStringLiteral KEY_ELEMENT_NAME = u"configuration"; + +namespace dp_registry::backend::configuration { + +ConfigurationBackendDb::ConfigurationBackendDb( + Reference<XComponentContext> const & xContext, + OUString const & url):BackendDb(xContext, url) +{ + +} + +OUString ConfigurationBackendDb::getDbNSName() +{ + return EXTENSION_REG_NS; +} + +OUString ConfigurationBackendDb::getNSPrefix() +{ + return NS_PREFIX; +} + +OUString ConfigurationBackendDb::getRootElementName() +{ + return ROOT_ELEMENT_NAME; +} + +OUString ConfigurationBackendDb::getKeyElementName() +{ + return KEY_ELEMENT_NAME; +} + + +void ConfigurationBackendDb::addEntry(OUString const & url, Data const & data) +{ + try{ + if (!activateEntry(url)) + { + Reference<css::xml::dom::XNode> helpNode + = writeKeyElement(url); + + writeSimpleElement(u"data-url", data.dataUrl, helpNode); + writeSimpleElement(u"ini-entry", data.iniEntry, helpNode); + save(); + } + } + catch ( const css::deployment::DeploymentException& ) + { + throw; + } + catch(const css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + "Extension Manager: failed to write data entry in configuration backend db: " + + m_urlDb, nullptr, exc); + } +} + + +::std::optional<ConfigurationBackendDb::Data> +ConfigurationBackendDb::getEntry(std::u16string_view url) +{ + try + { + ConfigurationBackendDb::Data retData; + Reference<css::xml::dom::XNode> aNode = getKeyElement(url); + if (aNode.is()) + { + retData.dataUrl = readSimpleElement(u"data-url", aNode); + retData.iniEntry = readSimpleElement(u"ini-entry", aNode); + } + else + { + return ::std::optional<Data>(); + } + return ::std::optional<Data>(retData); + } + catch ( const css::deployment::DeploymentException& ) + { + throw; + } + catch(const css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + "Extension Manager: failed to read data entry in configuration backend db: " + + m_urlDb, nullptr, exc); + } +} + +std::vector<OUString> ConfigurationBackendDb::getAllDataUrls() +{ + try + { + std::vector<OUString> listRet; + Reference<css::xml::dom::XDocument> doc = getDocument(); + Reference<css::xml::dom::XNode> root = doc->getFirstChild(); + + Reference<css::xml::xpath::XXPathAPI> xpathApi = getXPathAPI(); + const OUString sPrefix = getNSPrefix(); + OUString sExpression( + sPrefix + ":configuration/" + sPrefix + ":data-url/text()"); + Reference<css::xml::dom::XNodeList> nodes = + xpathApi->selectNodeList(root, sExpression); + if (nodes.is()) + { + sal_Int32 length = nodes->getLength(); + for (sal_Int32 i = 0; i < length; i++) + listRet.push_back(nodes->item(i)->getNodeValue()); + } + return listRet; + } + catch ( const css::deployment::DeploymentException& ) + { + throw; + } + catch(const css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + "Extension Manager: failed to read data entry in configuration backend db: " + + m_urlDb, nullptr, exc); + } +} + +} // namespace dp_registry::backend::configuration + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.hxx b/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.hxx new file mode 100644 index 000000000..bd48aab7b --- /dev/null +++ b/desktop/source/deployment/registry/configuration/dp_configurationbackenddb.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <rtl/ustring.hxx> +#include <rtl/string.hxx> +#include <vector> +#include <optional> +#include <string_view> + +#include <dp_backenddb.hxx> + +namespace com::sun::star::uno +{ +class XComponentContext; +} + +namespace dp_registry::backend::configuration +{ +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + */ +class ConfigurationBackendDb : public dp_registry::backend::BackendDb +{ +protected: + virtual OUString getDbNSName() override; + + virtual OUString getNSPrefix() override; + + virtual OUString getRootElementName() override; + + virtual OUString getKeyElementName() override; + +public: + struct Data + { + /* the URL to the folder containing the xcu or xcs files which contained + %origin% + */ + OUString dataUrl; + /* the URL of the xcu or xcs file which is written in to the configmgr.ini + */ + OUString iniEntry; + }; + +public: + ConfigurationBackendDb(css::uno::Reference<css::uno::XComponentContext> const& xContext, + OUString const& url); + + void addEntry(OUString const& url, Data const& data); + + ::std::optional<Data> getEntry(std::u16string_view url); + std::vector<OUString> getAllDataUrls(); +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |