/* -*- 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 #include #include "dp_backend.h" #include "dp_ucb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::dp_misc; using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::ucb; namespace dp_registry { namespace backend { PackageRegistryBackend::~PackageRegistryBackend() { } void PackageRegistryBackend::disposing( lang::EventObject const & event ) throw (RuntimeException, std::exception) { Reference xPackage( event.Source, UNO_QUERY_THROW ); OUString url( xPackage->getURL() ); ::osl::MutexGuard guard( getMutex() ); if ( m_bound.erase( url ) != 1 ) { SAL_WARN("desktop.deployment", "erase(" << url << ") != 1"); } } PackageRegistryBackend::PackageRegistryBackend( Sequence const & args, Reference const & xContext ) : t_BackendBase( getMutex() ), m_xComponentContext( xContext ), m_eContext( CONTEXT_UNKNOWN ), m_readOnly( false ) { assert(xContext.is()); boost::optional cachePath; boost::optional readOnly; comphelper::unwrapArgs( args, m_context, cachePath, readOnly ); if (cachePath) m_cachePath = *cachePath; if (readOnly) m_readOnly = *readOnly; if ( m_context == "user" ) m_eContext = CONTEXT_USER; else if ( m_context == "shared" ) m_eContext = CONTEXT_SHARED; else if ( m_context == "bundled" ) m_eContext = CONTEXT_BUNDLED; else if ( m_context == "tmp" ) m_eContext = CONTEXT_TMP; else if (m_context.matchIgnoreAsciiCase("vnd.sun.star.tdoc:/")) m_eContext = CONTEXT_DOCUMENT; else m_eContext = CONTEXT_UNKNOWN; } void PackageRegistryBackend::check() { ::osl::MutexGuard guard( getMutex() ); if (rBHelper.bInDispose || rBHelper.bDisposed) { throw lang::DisposedException( "PackageRegistryBackend instance has already been disposed!", static_cast(this) ); } } void PackageRegistryBackend::disposing() { try { for ( t_string2ref::const_iterator i = m_bound.begin(); i != m_bound.end(); ++i) i->second->removeEventListener(this); m_bound.clear(); m_xComponentContext.clear(); WeakComponentImplHelperBase::disposing(); } catch (const RuntimeException &) { throw; } catch (const Exception &) { Any exc( ::cppu::getCaughtException() ); throw lang::WrappedTargetRuntimeException( "caught unexpected exception while disposing!", static_cast(this), exc ); } } // XPackageRegistry Reference PackageRegistryBackend::bindPackage( OUString const & url, OUString const & mediaType, sal_Bool bRemoved, OUString const & identifier, Reference const & xCmdEnv ) throw (deployment::DeploymentException, deployment::InvalidRemovedParameterException, ucb::CommandFailedException, lang::IllegalArgumentException, RuntimeException, std::exception) { ::osl::ResettableMutexGuard guard( getMutex() ); check(); t_string2ref::const_iterator const iFind( m_bound.find( url ) ); if (iFind != m_bound.end()) { Reference xPackage( iFind->second ); if (xPackage.is()) { if (!mediaType.isEmpty() && mediaType != xPackage->getPackageType()->getMediaType()) throw lang::IllegalArgumentException ("XPackageRegistry::bindPackage: media type does not match", static_cast(this), 1); if (xPackage->isRemoved() != bRemoved) throw deployment::InvalidRemovedParameterException( "XPackageRegistry::bindPackage: bRemoved parameter does not match", static_cast(this), xPackage->isRemoved(), xPackage); return xPackage; } } guard.clear(); Reference xNewPackage; try { xNewPackage = bindPackage_( url, mediaType, bRemoved, identifier, xCmdEnv ); } catch (const RuntimeException &) { throw; } catch (const CommandFailedException &) { throw; } catch (const deployment::DeploymentException &) { throw; } catch (const Exception &) { Any exc( ::cppu::getCaughtException() ); throw deployment::DeploymentException( "Error binding package: " + url, static_cast(this), exc ); } guard.reset(); ::std::pair< t_string2ref::iterator, bool > insertion( m_bound.insert( t_string2ref::value_type( url, xNewPackage ) ) ); if (insertion.second) { // first insertion SAL_WARN_IF( Reference(insertion.first->second) != xNewPackage, "desktop.deployment", "mismatch"); } else { // found existing entry Reference xPackage( insertion.first->second ); if (xPackage.is()) return xPackage; insertion.first->second = xNewPackage; } guard.clear(); xNewPackage->addEventListener( this ); // listen for disposing events return xNewPackage; } OUString PackageRegistryBackend::createFolder( OUString const & relUrl, Reference const & xCmdEnv) { const OUString sDataFolder = makeURL(getCachePath(), relUrl); //make sure the folder exist ucbhelper::Content dataContent; ::dp_misc::create_folder(&dataContent, sDataFolder, xCmdEnv); const OUString baseDir(sDataFolder); ::utl::TempFile aTemp(&baseDir, true); const OUString url = aTemp.GetURL(); return sDataFolder + url.copy(url.lastIndexOf('/')); } //folderURL can have the extension .tmp or .tmp_ //Before OOo 3.4 the created a tmp file with osl_createTempFile and //then created a Folder with a same name and a trailing '_' //If the folderURL has no '_' then there is no corresponding tmp file. void PackageRegistryBackend::deleteTempFolder( OUString const & folderUrl) { if (!folderUrl.isEmpty()) { erase_path( folderUrl, Reference(), false /* no throw: ignore errors */ ); if (folderUrl.endsWith("_")) { const OUString tempFile = folderUrl.copy(0, folderUrl.getLength() - 1); erase_path( tempFile, Reference(), false /* no throw: ignore errors */ ); } } } //usedFolders can contain folder names which have the extension .tmp or .tmp_ //Before OOo 3.4 we created a tmp file with osl_createTempFile and //then created a Folder with a same name and a trailing '_' //If the folderURL has no '_' then there is no corresponding tmp file. void PackageRegistryBackend::deleteUnusedFolders( OUString const & relUrl, ::std::list< OUString> const & usedFolders) { try { const OUString sDataFolder = makeURL(getCachePath(), relUrl); ::ucbhelper::Content tempFolder( sDataFolder, Reference(), m_xComponentContext); Reference xResultSet( StrTitle::createCursor( tempFolder, ::ucbhelper::INCLUDE_FOLDERS_ONLY ) ); // get all temp directories: ::std::vector tempEntries; const char tmp[] = ".tmp"; while (xResultSet->next()) { OUString title( Reference( xResultSet, UNO_QUERY_THROW )->getString( 1 /* Title */ ) ); if (title.endsWith(tmp)) tempEntries.push_back( makeURLAppendSysPathSegment(sDataFolder, title)); } for ( ::std::size_t pos = 0; pos < tempEntries.size(); ++pos ) { if (::std::find( usedFolders.begin(), usedFolders.end(), tempEntries[pos] ) == usedFolders.end()) { deleteTempFolder(tempEntries[pos]); } } } catch (const ucb::InteractiveAugmentedIOException& e) { //In case the folder containing all the data folder does not //exist yet, we ignore the exception if (e.Code != ucb::IOErrorCode_NOT_EXISTING) throw; } } Package::~Package() { } Package::Package( ::rtl::Reference const & myBackend, OUString const & url, OUString const & rName, OUString const & displayName, Reference const & xPackageType, bool bRemoved, OUString const & identifier) : t_PackageBase( getMutex() ), m_myBackend( myBackend ), m_url( url ), m_name( rName ), m_displayName( displayName ), m_xPackageType( xPackageType ), m_bRemoved(bRemoved), m_identifier(identifier) { if (m_bRemoved) { //We use the last segment of the URL SAL_WARN_IF( !m_name.isEmpty(), "desktop.deployment", "non-empty m_name"); OUString name = m_url; rtl::Bootstrap::expandMacros(name); sal_Int32 index = name.lastIndexOf('/'); if (index != -1 && index < name.getLength()) m_name = name.copy(index + 1); } } void Package::disposing() { m_myBackend.clear(); WeakComponentImplHelperBase::disposing(); } void Package::check() const { ::osl::MutexGuard guard( getMutex() ); if (rBHelper.bInDispose || rBHelper.bDisposed) { throw lang::DisposedException( "Package instance has already been disposed!", static_cast(const_cast(this))); } } // XComponent void Package::dispose() throw (RuntimeException, std::exception) { //Do not call check here. We must not throw an exception here if the object //is being disposed or is already disposed. See com.sun.star.lang.XComponent WeakComponentImplHelperBase::dispose(); } void Package::addEventListener( Reference const & xListener ) throw (RuntimeException, std::exception) { //Do not call check here. We must not throw an exception here if the object //is being disposed or is already disposed. See com.sun.star.lang.XComponent WeakComponentImplHelperBase::addEventListener( xListener ); } void Package::removeEventListener( Reference const & xListener ) throw (RuntimeException, std::exception) { //Do not call check here. We must not throw an exception here if the object //is being disposed or is already disposed. See com.sun.star.lang.XComponent WeakComponentImplHelperBase::removeEventListener( xListener ); } // XModifyBroadcaster void Package::addModifyListener( Reference const & xListener ) throw (RuntimeException, std::exception) { check(); rBHelper.addListener( ::getCppuType( &xListener ), xListener ); } void Package::removeModifyListener( Reference const & xListener ) throw (RuntimeException, std::exception) { check(); rBHelper.removeListener( ::getCppuType( &xListener ), xListener ); } void Package::checkAborted( ::rtl::Reference const & abortChannel ) { if (abortChannel.is() && abortChannel->isAborted()) { throw CommandAbortedException( "abort!", static_cast(this) ); } } // XPackage Reference Package::createAbortChannel() throw (RuntimeException, std::exception) { check(); return new AbortChannel; } sal_Bool Package::isBundle() throw (RuntimeException, std::exception) { return false; // default } ::sal_Int32 Package::checkPrerequisites( const css::uno::Reference< css::task::XAbortChannel >&, const css::uno::Reference< css::ucb::XCommandEnvironment >&, sal_Bool) throw (css::deployment::DeploymentException, css::deployment::ExtensionRemovedException, css::ucb::CommandFailedException, css::ucb::CommandAbortedException, css::uno::RuntimeException, std::exception) { if (m_bRemoved) throw deployment::ExtensionRemovedException(); return 0; } sal_Bool Package::checkDependencies( const css::uno::Reference< css::ucb::XCommandEnvironment >& ) throw (css::deployment::DeploymentException, css::deployment::ExtensionRemovedException, css::ucb::CommandFailedException, css::uno::RuntimeException, std::exception) { if (m_bRemoved) throw deployment::ExtensionRemovedException(); return true; } Sequence< Reference > Package::getBundle( Reference const &, Reference const & ) throw (deployment::DeploymentException, CommandFailedException, CommandAbortedException, lang::IllegalArgumentException, RuntimeException, std::exception) { return Sequence< Reference >(); } OUString Package::getName() throw (RuntimeException, std::exception) { return m_name; } beans::Optional Package::getIdentifier() throw (RuntimeException, std::exception) { if (m_bRemoved) return beans::Optional(true, m_identifier); return beans::Optional(); } OUString Package::getVersion() throw ( deployment::ExtensionRemovedException, RuntimeException, std::exception) { if (m_bRemoved) throw deployment::ExtensionRemovedException(); return OUString(); } OUString Package::getURL() throw (RuntimeException, std::exception) { return m_url; } OUString Package::getDisplayName() throw ( deployment::ExtensionRemovedException, RuntimeException, std::exception) { if (m_bRemoved) throw deployment::ExtensionRemovedException(); return m_displayName; } OUString Package::getDescription() throw ( deployment::ExtensionRemovedException,RuntimeException, std::exception) { if (m_bRemoved) throw deployment::ExtensionRemovedException(); return OUString(); } OUString Package::getLicenseText()throw ( deployment::DeploymentException, deployment::ExtensionRemovedException, RuntimeException, std::exception) { if (m_bRemoved) throw deployment::ExtensionRemovedException(); return OUString(); } Sequence Package::getUpdateInformationURLs() throw ( deployment::ExtensionRemovedException, RuntimeException, std::exception) { if (m_bRemoved) throw deployment::ExtensionRemovedException(); return Sequence(); } css::beans::StringPair Package::getPublisherInfo() throw ( deployment::ExtensionRemovedException, RuntimeException, std::exception) { if (m_bRemoved) throw deployment::ExtensionRemovedException(); css::beans::StringPair aEmptyPair; return aEmptyPair; } uno::Reference< css::graphic::XGraphic > Package::getIcon( sal_Bool /*bHighContrast*/ ) throw (deployment::ExtensionRemovedException, RuntimeException, std::exception ) { if (m_bRemoved) throw deployment::ExtensionRemovedException(); uno::Reference< css::graphic::XGraphic > aEmpty; return aEmpty; } Reference Package::getPackageType() throw (RuntimeException, std::exception) { return m_xPackageType; } void Package::exportTo( OUString const & destFolderURL, OUString const & newTitle, sal_Int32 nameClashAction, Reference const & xCmdEnv ) throw (deployment::ExtensionRemovedException, CommandFailedException, CommandAbortedException, ContentCreationException, RuntimeException, std::exception) { if (m_bRemoved) throw deployment::ExtensionRemovedException(); ::ucbhelper::Content destFolder( destFolderURL, xCmdEnv, getMyBackend()->getComponentContext() ); ::ucbhelper::Content sourceContent( getURL(), xCmdEnv, getMyBackend()->getComponentContext() ); bool bOk=true; try { bOk = destFolder.transferContent( sourceContent, ::ucbhelper::InsertOperation_COPY, newTitle, nameClashAction); } catch (const css::ucb::ContentCreationException&) { bOk = false; } if (!bOk) throw RuntimeException( "UCB transferContent() failed!", 0 ); } void Package::fireModified() { ::cppu::OInterfaceContainerHelper * container = rBHelper.getContainer( cppu::UnoType::get() ); if (container != 0) { Sequence< Reference > elements( container->getElements() ); lang::EventObject evt( static_cast(this) ); for ( sal_Int32 pos = 0; pos < elements.getLength(); ++pos ) { Reference xListener( elements[ pos ], UNO_QUERY ); if (xListener.is()) xListener->modified( evt ); } } } // XPackage beans::Optional< beans::Ambiguous > Package::isRegistered( Reference const & xAbortChannel, Reference const & xCmdEnv ) throw (deployment::DeploymentException, CommandFailedException, CommandAbortedException, RuntimeException, std::exception) { try { ::osl::ResettableMutexGuard guard( getMutex() ); return isRegistered_( guard, AbortChannel::get(xAbortChannel), xCmdEnv ); } catch (const RuntimeException &) { throw; } catch (const CommandFailedException &) { throw; } catch (const CommandAbortedException &) { throw; } catch (const deployment::DeploymentException &) { throw; } catch (const Exception &) { Any exc( ::cppu::getCaughtException() ); throw deployment::DeploymentException( "unexpected exception occurred!", static_cast(this), exc ); } } void Package::processPackage_impl( bool doRegisterPackage, bool startup, Reference const & xAbortChannel, Reference const & xCmdEnv ) { check(); bool action = false; try { try { ::osl::ResettableMutexGuard guard( getMutex() ); beans::Optional< beans::Ambiguous > option( isRegistered_( guard, AbortChannel::get(xAbortChannel), xCmdEnv ) ); action = (option.IsPresent && (option.Value.IsAmbiguous || (doRegisterPackage ? !option.Value.Value : option.Value.Value))); if (action) { OUString displayName = isRemoved() ? getName() : getDisplayName(); ProgressLevel progress( xCmdEnv, (doRegisterPackage ? PackageRegistryBackend::StrRegisteringPackage::get() : PackageRegistryBackend::StrRevokingPackage::get()) + displayName ); processPackage_( guard, doRegisterPackage, startup, AbortChannel::get(xAbortChannel), xCmdEnv ); } } catch (lang::IllegalArgumentException &) { Any e(cppu::getCaughtException()); throw deployment::DeploymentException( ((doRegisterPackage ? getResourceString(RID_STR_ERROR_WHILE_REGISTERING) : getResourceString(RID_STR_ERROR_WHILE_REVOKING)) + getDisplayName()), static_cast< OWeakObject * >(this), e); } catch (const RuntimeException &e) { SAL_WARN( "desktop.deployment", "unexpected RuntimeException \"" << e.Message << '"'); throw; } catch (const CommandFailedException &) { throw; } catch (const CommandAbortedException &) { throw; } catch (const deployment::DeploymentException &) { throw; } catch (const Exception &) { Any exc( ::cppu::getCaughtException() ); throw deployment::DeploymentException( (doRegisterPackage ? getResourceString(RID_STR_ERROR_WHILE_REGISTERING) : getResourceString(RID_STR_ERROR_WHILE_REVOKING)) + getDisplayName(), static_cast(this), exc ); } } catch (...) { if (action) fireModified(); throw; } if (action) fireModified(); } void Package::registerPackage( sal_Bool startup, Reference const & xAbortChannel, Reference const & xCmdEnv ) throw (deployment::DeploymentException, deployment::ExtensionRemovedException, CommandFailedException, CommandAbortedException, lang::IllegalArgumentException, RuntimeException, std::exception) { if (m_bRemoved) throw deployment::ExtensionRemovedException(); processPackage_impl( true /* register */, startup, xAbortChannel, xCmdEnv ); } void Package::revokePackage( sal_Bool startup, Reference const & xAbortChannel, Reference const & xCmdEnv ) throw (deployment::DeploymentException, CommandFailedException, CommandAbortedException, lang::IllegalArgumentException, RuntimeException, std::exception) { processPackage_impl( false /* revoke */, startup, xAbortChannel, xCmdEnv ); } PackageRegistryBackend * Package::getMyBackend() const { PackageRegistryBackend * pBackend = m_myBackend.get(); if (NULL == pBackend) { //May throw a DisposedException check(); //We should never get here... throw RuntimeException( "Failed to get the BackendImpl", static_cast(const_cast(this))); } return pBackend; } OUString Package::getRepositoryName() throw (RuntimeException, std::exception) { PackageRegistryBackend * backEnd = getMyBackend(); return backEnd->getContext(); } beans::Optional< OUString > Package::getRegistrationDataURL() throw (deployment::DeploymentException, deployment::ExtensionRemovedException, css::uno::RuntimeException, std::exception) { if (m_bRemoved) throw deployment::ExtensionRemovedException(); return beans::Optional(); } sal_Bool Package::isRemoved() throw (RuntimeException, std::exception) { return m_bRemoved; } Package::TypeInfo::~TypeInfo() { } // XPackageTypeInfo OUString Package::TypeInfo::getMediaType() throw (RuntimeException, std::exception) { return m_mediaType; } OUString Package::TypeInfo::getDescription() throw (deployment::ExtensionRemovedException, RuntimeException, std::exception) { return getShortDescription(); } OUString Package::TypeInfo::getShortDescription() throw (deployment::ExtensionRemovedException, RuntimeException, std::exception) { return m_shortDescr; } OUString Package::TypeInfo::getFileFilter() throw (RuntimeException, std::exception) { return m_fileFilter; } /************************** * Get Icon * * @param highContrast NOTE: disabled the returning of high contrast icons. * This bool is a noop now. * @param smallIcon Return the small version of the icon */ Any Package::TypeInfo::getIcon( sal_Bool /*highContrast*/, sal_Bool smallIcon ) throw (RuntimeException, std::exception) { if (! smallIcon) return Any(); const sal_uInt16 nIconId = m_smallIcon; return Any( &nIconId, cppu::UnoType::get() ); } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */