diff options
Diffstat (limited to 'ucbhelper/source')
26 files changed, 8774 insertions, 0 deletions
diff --git a/ucbhelper/source/client/activedatasink.cxx b/ucbhelper/source/client/activedatasink.cxx new file mode 100644 index 0000000000..96e75f565b --- /dev/null +++ b/ucbhelper/source/client/activedatasink.cxx @@ -0,0 +1,40 @@ +/* -*- 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 <ucbhelper/activedatasink.hxx> + +using namespace com::sun::star; + +namespace ucbhelper +{ +// ActiveDataSink Implementation. +// XActiveDataSink methods. + +// virtual +void SAL_CALL ActiveDataSink::setInputStream(const uno::Reference<io::XInputStream>& aStream) +{ + m_xStream = aStream; +} + +// virtual +uno::Reference<io::XInputStream> SAL_CALL ActiveDataSink::getInputStream() { return m_xStream; } + +} // namespace ucbhelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/client/activedatastreamer.cxx b/ucbhelper/source/client/activedatastreamer.cxx new file mode 100644 index 0000000000..fe6be13536 --- /dev/null +++ b/ucbhelper/source/client/activedatastreamer.cxx @@ -0,0 +1,41 @@ +/* -*- 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 "activedatastreamer.hxx" + +using namespace com::sun::star; + +namespace ucbhelper +{ +// ActiveDataStreamer Implementation. + +// XActiveDataStreamer methods. + +// virtual +void SAL_CALL ActiveDataStreamer::setStream(const uno::Reference<io::XStream>& xStream) +{ + m_xStream = xStream; +} + +// virtual +uno::Reference<io::XStream> SAL_CALL ActiveDataStreamer::getStream() { return m_xStream; } + +} // namespace ucbhelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/client/activedatastreamer.hxx b/ucbhelper/source/client/activedatastreamer.hxx new file mode 100644 index 0000000000..84ee10ac96 --- /dev/null +++ b/ucbhelper/source/client/activedatastreamer.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ + +#ifndef UCBHELPER_SOURCE_CLIENT_ACTIVEDATASTREAMER_HXX +#define UCBHELPER_SOURCE_CLIENT_ACTIVEDATASTREAMER_HXX + +#include <com/sun/star/io/XActiveDataStreamer.hpp> +#include <cppuhelper/implbase.hxx> + +namespace ucbhelper +{ +/** + * This class implements the interface css::io::XActiveDataStreamer. + * Instances of this class can be passed with the parameters of an + * "open" command. + */ + +class ActiveDataStreamer final : public cppu::WeakImplHelper<css::io::XActiveDataStreamer> +{ + css::uno::Reference<css::io::XStream> m_xStream; + +public: + // XActiveDataStreamer methods. + virtual void SAL_CALL setStream(const css::uno::Reference<css::io::XStream>& xStream) override; + virtual css::uno::Reference<css::io::XStream> SAL_CALL getStream() override; +}; + +} /* namespace ucbhelper */ + +#endif /* ! UCBHELPER_SOURCE_CLIENT_ACTIVEDATASTREAMER_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/client/commandenvironment.cxx b/ucbhelper/source/client/commandenvironment.cxx new file mode 100644 index 0000000000..37956b2c46 --- /dev/null +++ b/ucbhelper/source/client/commandenvironment.cxx @@ -0,0 +1,77 @@ +/* -*- 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 <ucbhelper/commandenvironment.hxx> +#include <com/sun/star/uno/Reference.hxx> + +using namespace com::sun::star::lang; +using namespace com::sun::star::task; +using namespace com::sun::star::ucb; +using namespace com::sun::star::uno; + +namespace com::sun::star::task { class XInteractionHandler; } +namespace com::sun::star::ucb { class XProgressHandler; } + +namespace ucbhelper +{ +// struct CommandEnvironment_Impl. + +struct CommandEnvironment_Impl +{ + Reference< XInteractionHandler > m_xInteractionHandler; + Reference< XProgressHandler > m_xProgressHandler; + + CommandEnvironment_Impl( const Reference< XInteractionHandler >& rxInteractionHandler, + const Reference< XProgressHandler >& rxProgressHandler ) + : m_xInteractionHandler( rxInteractionHandler ) + , m_xProgressHandler( rxProgressHandler ) {} +}; + +// CommandEnvironment Implementation. + +CommandEnvironment::CommandEnvironment( + const Reference< XInteractionHandler >& rxInteractionHandler, + const Reference< XProgressHandler >& rxProgressHandler ) + : m_pImpl( new CommandEnvironment_Impl( rxInteractionHandler, + rxProgressHandler ) ) +{ +} + +// virtual +CommandEnvironment::~CommandEnvironment() +{ +} + +// XCommandEnvironment methods. + +// virtual +Reference< XInteractionHandler > SAL_CALL CommandEnvironment::getInteractionHandler() +{ + return m_pImpl->m_xInteractionHandler; +} + +// virtual +Reference< XProgressHandler > SAL_CALL CommandEnvironment::getProgressHandler() +{ + return m_pImpl->m_xProgressHandler; +} + +} /* namespace ucbhelper */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/client/content.cxx b/ucbhelper/source/client/content.cxx new file mode 100644 index 0000000000..8feab846ba --- /dev/null +++ b/ucbhelper/source/client/content.cxx @@ -0,0 +1,1353 @@ +/* -*- 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 <sal/config.h> + +#include <cassert> + +#include <o3tl/unreachable.hxx> +#include <osl/diagnose.h> +#include <mutex> +#include <sal/log.hxx> +#include <salhelper/simplereferenceobject.hxx> +#include <cppuhelper/weak.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/ucb/CheckinArgument.hpp> +#include <com/sun/star/ucb/ContentCreationError.hpp> +#include <com/sun/star/ucb/ContentCreationException.hpp> +#include <com/sun/star/ucb/IllegalIdentifierException.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/ucb/Command.hpp> +#include <com/sun/star/ucb/ContentAction.hpp> +#include <com/sun/star/ucb/OpenCommandArgument2.hpp> +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <com/sun/star/ucb/XContentCreator.hpp> +#include <com/sun/star/ucb/XContentEventListener.hpp> +#include <com/sun/star/ucb/XDynamicResultSet.hpp> +#include <com/sun/star/ucb/SortedDynamicResultSetFactory.hpp> +#include <com/sun/star/ucb/UniversalContentBroker.hpp> +#include <com/sun/star/ucb/XUniversalContentBroker.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <ucbhelper/content.hxx> +#include <ucbhelper/activedatasink.hxx> +#include "activedatastreamer.hxx" +#include <ucbhelper/cancelcommandexecution.hxx> + +namespace com::sun::star::ucb { class XCommandEnvironment; } +namespace com::sun::star::ucb { class XContentProvider; } +namespace com::sun::star::sdbc { class XResultSet; } + +using namespace com::sun::star::container; +using namespace com::sun::star::beans; +using namespace com::sun::star::io; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::task; +using namespace com::sun::star::ucb; +using namespace com::sun::star::uno; + +namespace ucbhelper +{ + +namespace { + +class EmptyInputStream : public ::cppu::WeakImplHelper< XInputStream > +{ +public: + virtual sal_Int32 SAL_CALL readBytes( + Sequence< sal_Int8 > & data, sal_Int32 nBytesToRead ) override; + virtual sal_Int32 SAL_CALL readSomeBytes( + Sequence< sal_Int8 > & data, sal_Int32 nMaxBytesToRead ) override; + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override; + virtual sal_Int32 SAL_CALL available() override; + virtual void SAL_CALL closeInput() override; +}; + +} + +sal_Int32 EmptyInputStream::readBytes( + Sequence< sal_Int8 > & data, sal_Int32 ) +{ + data.realloc( 0 ); + return 0; +} + +sal_Int32 EmptyInputStream::readSomeBytes( + Sequence< sal_Int8 > & data, sal_Int32 ) +{ + data.realloc( 0 ); + return 0; +} + +void EmptyInputStream::skipBytes( sal_Int32 ) +{ +} + +sal_Int32 EmptyInputStream::available() +{ + return 0; +} + +void EmptyInputStream::closeInput() +{ +} + + + +namespace { + +class ContentEventListener_Impl : public cppu::OWeakObject, + public XContentEventListener +{ + Content_Impl& m_rContent; + +public: + explicit ContentEventListener_Impl( Content_Impl& rContent ) + : m_rContent( rContent ) {} + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + // XContentEventListener + virtual void SAL_CALL contentEvent( const ContentEvent& evt ) override; + + // XEventListener ( base of XContentEventListener ) + virtual void SAL_CALL disposing( const EventObject& Source ) override; +}; + +} + + + +class Content_Impl : public salhelper::SimpleReferenceObject +{ +friend ContentEventListener_Impl; + + mutable OUString m_aURL; + Reference< XComponentContext > m_xCtx; + Reference< XContent > m_xContent; + Reference< XCommandProcessor > m_xCommandProcessor; + Reference< XCommandEnvironment > m_xEnv; + Reference< XContentEventListener > m_xContentEventListener; + mutable std::mutex m_aMutex; + +private: + void reinit( const Reference< XContent >& xContent ); + void disposing(const EventObject& Source); + const Reference< XContent > & getContent_NoLock(); + const OUString& getURL_NoLock() const; + +public: + Content_Impl() {}; + Content_Impl( const Reference< XComponentContext >& rCtx, + const Reference< XContent >& rContent, + const Reference< XCommandEnvironment >& rEnv ); + + virtual ~Content_Impl() override; + + const OUString& getURL() const; + Reference< XContent > getContent(); + Reference< XCommandProcessor > getCommandProcessor(); + Reference< XComponentContext > const & getComponentContext() const + { assert(m_xCtx.is()); return m_xCtx; } + + Any executeCommand( const Command& rCommand ); + + inline const Reference< XCommandEnvironment >& getEnvironment() const; + inline void setEnvironment( + const Reference< XCommandEnvironment >& xNewEnv ); + + void inserted(); +}; + + +// Helpers. + +/// @throws ContentCreationException +/// @throws RuntimeException +static void ensureContentProviderForURL( const Reference< XUniversalContentBroker >& rBroker, + const OUString & rURL ) +{ + Reference< XContentProvider > xProv + = rBroker->queryContentProvider( rURL ); + if ( !xProv.is() ) + { + throw ContentCreationException( + "No Content Provider available for URL: " + rURL, + Reference< XInterface >(), + ContentCreationError_NO_CONTENT_PROVIDER ); + } +} + +/// @throws ContentCreationException +/// @throws RuntimeException +static Reference< XContentIdentifier > getContentIdentifierThrow( + const Reference< XUniversalContentBroker > & rBroker, + const OUString & rURL) +{ + Reference< XContentIdentifier > xId + = rBroker->createContentIdentifier( rURL ); + + if (!xId.is()) + { + ensureContentProviderForURL( rBroker, rURL ); + + throw ContentCreationException( + "Unable to create Content Identifier!", + Reference< XInterface >(), + ContentCreationError_IDENTIFIER_CREATION_FAILED ); + } + + return xId; +} + +/// @throws RuntimeException +static Reference< XContentIdentifier > getContentIdentifierNoThrow( + const Reference< XUniversalContentBroker > & rBroker, + const OUString & rURL) +{ + return rBroker->createContentIdentifier(rURL); +} + +/// @throws ContentCreationException +/// @throws RuntimeException +static Reference< XContent > getContentThrow( + const Reference< XUniversalContentBroker > & rBroker, + const Reference< XContentIdentifier > & xId) +{ + Reference< XContent > xContent; + OUString msg; + try + { + xContent = rBroker->queryContent( xId ); + } + catch ( IllegalIdentifierException const & e ) + { + msg = e.Message; + // handled below. + } + + if ( !xContent.is() ) + { + ensureContentProviderForURL( rBroker, xId->getContentIdentifier() ); + + throw ContentCreationException( + "Unable to create Content for <" + xId->getContentIdentifier() + ">: " + msg, + Reference< XInterface >(), + ContentCreationError_CONTENT_CREATION_FAILED ); + } + + return xContent; +} + +/// @throws RuntimeException +static Reference< XContent > getContentNoThrow( + const Reference< XUniversalContentBroker > & rBroker, + const Reference< XContentIdentifier > & xId) +{ + Reference< XContent > xContent; + try + { + xContent = rBroker->queryContent( xId ); + } + catch ( IllegalIdentifierException const & e ) + { + SAL_WARN("ucbhelper", "getContentNoThrow: " << e); + } + + return xContent; +} + + +// Content Implementation. + + +Content::Content() +: m_xImpl( new Content_Impl ) +{ +} + + +Content::Content( const OUString& rURL, + const Reference< XCommandEnvironment >& rEnv, + const Reference< XComponentContext >& rCtx ) +{ + Reference< XUniversalContentBroker > pBroker( + UniversalContentBroker::create( rCtx ) ); + + Reference< XContentIdentifier > xId + = getContentIdentifierThrow(pBroker, rURL); + + Reference< XContent > xContent = getContentThrow(pBroker, xId); + + m_xImpl = new Content_Impl( rCtx, xContent, rEnv ); +} + + +Content::Content( const Reference< XContent >& rContent, + const Reference< XCommandEnvironment >& rEnv, + const Reference< XComponentContext >& rCtx ) +{ + m_xImpl = new Content_Impl( rCtx, rContent, rEnv ); +} + + +Content::Content( const Content& rOther ) +{ + m_xImpl = rOther.m_xImpl; +} + +Content::Content( Content&& rOther ) noexcept +{ + m_xImpl = std::move(rOther.m_xImpl); +} + +// static +bool Content::create( const OUString& rURL, + const Reference< XCommandEnvironment >& rEnv, + const Reference< XComponentContext >& rCtx, + Content& rContent ) +{ + Reference< XUniversalContentBroker > pBroker( + UniversalContentBroker::create( rCtx ) ); + + Reference< XContentIdentifier > xId + = getContentIdentifierNoThrow(pBroker, rURL); + if ( !xId.is() ) + return false; + + Reference< XContent > xContent = getContentNoThrow(pBroker, xId); + if ( !xContent.is() ) + return false; + + rContent.m_xImpl + = new Content_Impl( rCtx, xContent, rEnv ); + + return true; +} + + +Content::~Content() +{ +} + + +Content& Content::operator=( const Content& rOther ) +{ + m_xImpl = rOther.m_xImpl; + return *this; +} + +Content& Content::operator=( Content&& rOther ) noexcept +{ + m_xImpl = std::move(rOther.m_xImpl); + return *this; +} + +Reference< XContent > Content::get() const +{ + return m_xImpl->getContent(); +} + + +const OUString& Content::getURL() const +{ + return m_xImpl->getURL(); +} + + +const Reference< XCommandEnvironment >& Content::getCommandEnvironment() const +{ + return m_xImpl->getEnvironment(); +} + + +void Content::setCommandEnvironment( + const Reference< XCommandEnvironment >& xNewEnv ) +{ + m_xImpl->setEnvironment( xNewEnv ); +} + + +Reference< XCommandInfo > Content::getCommands() +{ + Command aCommand; + aCommand.Name = "getCommandInfo"; + aCommand.Handle = -1; // n/a + aCommand.Argument = Any(); + + Any aResult = m_xImpl->executeCommand( aCommand ); + + Reference< XCommandInfo > xInfo; + aResult >>= xInfo; + return xInfo; +} + + +Reference< XPropertySetInfo > Content::getProperties() +{ + static constexpr OUStringLiteral sgetPropertySetInfo = u"getPropertySetInfo"; + Command aCommand; + aCommand.Name = sgetPropertySetInfo; + aCommand.Handle = -1; // n/a + aCommand.Argument = Any(); + + Any aResult = m_xImpl->executeCommand( aCommand ); + + Reference< XPropertySetInfo > xInfo; + aResult >>= xInfo; + return xInfo; +} + + +Any Content::getPropertyValue( const OUString& rPropertyName ) +{ + Sequence<OUString> aNames { rPropertyName }; + + Sequence< Any > aRet = getPropertyValues( aNames ); + return aRet.getConstArray()[ 0 ]; +} + + +Any Content::setPropertyValue( const OUString& rName, + const Any& rValue ) +{ + Sequence<OUString> aNames { rName }; + + Sequence< Any > aValues( 1 ); + aValues.getArray()[ 0 ] = rValue; + + Sequence< Any > aErrors = setPropertyValues( aNames, aValues ); + return aErrors.getConstArray()[ 0 ]; +} + + +Sequence< Any > Content::getPropertyValues( + const Sequence< OUString >& rPropertyNames ) +{ + Reference< XRow > xRow = getPropertyValuesInterface( rPropertyNames ); + + sal_Int32 nCount = rPropertyNames.getLength(); + Sequence< Any > aValues( nCount ); + + if ( xRow.is() ) + { + Any* pValues = aValues.getArray(); + + for ( sal_Int32 n = 0; n < nCount; ++n ) + pValues[ n ] = xRow->getObject( n + 1, Reference< XNameAccess >() ); + } + + return aValues; +} + + +Reference< XRow > Content::getPropertyValuesInterface( + const Sequence< OUString >& rPropertyNames ) +{ + sal_Int32 nCount = rPropertyNames.getLength(); + Sequence< Property > aProps( nCount ); + Property* pProps = aProps.getArray(); + + const OUString* pNames = rPropertyNames.getConstArray(); + + for ( sal_Int32 n = 0; n< nCount; ++n ) + { + Property& rProp = pProps[ n ]; + + rProp.Name = pNames[ n ]; + rProp.Handle = -1; // n/a +// rProp.Type = +// rProp.Attributes = ; + } + + static constexpr OUStringLiteral sgetPropertyValues = u"getPropertyValues"; + Command aCommand; + aCommand.Name = sgetPropertyValues; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aProps; + + Any aResult = m_xImpl->executeCommand( aCommand ); + + Reference< XRow > xRow; + aResult >>= xRow; + return xRow; +} + + +Sequence< Any > Content::setPropertyValues( + const Sequence< OUString >& rPropertyNames, + const Sequence< Any >& rValues ) +{ + if ( rPropertyNames.getLength() != rValues.getLength() ) + { + ucbhelper::cancelCommandExecution( + Any( IllegalArgumentException( + "Length of property names sequence and value " + "sequence are unequal!", + get(), + -1 ) ), + m_xImpl->getEnvironment() ); + // Unreachable + } + + sal_Int32 nCount = rValues.getLength(); + Sequence< PropertyValue > aProps( nCount ); + PropertyValue* pProps = aProps.getArray(); + + const OUString* pNames = rPropertyNames.getConstArray(); + const Any* pValues = rValues.getConstArray(); + + for ( sal_Int32 n = 0; n< nCount; ++n ) + { + PropertyValue& rProp = pProps[ n ]; + + rProp.Name = pNames[ n ]; + rProp.Handle = -1; // n/a + rProp.Value = pValues[ n ]; +// rProp.State = ; + } + + Command aCommand; + aCommand.Name = "setPropertyValues"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aProps; + + Any aResult = m_xImpl->executeCommand( aCommand ); + + Sequence< Any > aErrors; + aResult >>= aErrors; + return aErrors; +} + + +Any Content::executeCommand( const OUString& rCommandName, + const Any& rCommandArgument ) +{ + Command aCommand; + aCommand.Name = rCommandName; + aCommand.Handle = -1; // n/a + aCommand.Argument = rCommandArgument; + + return m_xImpl->executeCommand( aCommand ); +} + + +Any Content::createCursorAny( const Sequence< OUString >& rPropertyNames, + ResultSetInclude eMode ) +{ + sal_Int32 nCount = rPropertyNames.getLength(); + Sequence< Property > aProps( nCount ); + Property* pProps = aProps.getArray(); + const OUString* pNames = rPropertyNames.getConstArray(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + Property& rProp = pProps[ n ]; + rProp.Name = pNames[ n ]; + rProp.Handle = -1; // n/a + } + + OpenCommandArgument2 aArg; + aArg.Mode = ( eMode == INCLUDE_FOLDERS_ONLY ) + ? OpenMode::FOLDERS + : ( eMode == INCLUDE_DOCUMENTS_ONLY ) + ? OpenMode::DOCUMENTS : OpenMode::ALL; + aArg.Priority = 0; // unused + aArg.Sink.clear(); // unused + aArg.Properties = aProps; + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + return m_xImpl->executeCommand( aCommand ); +} + + +Reference< XResultSet > Content::createCursor( + const Sequence< OUString >& rPropertyNames, + ResultSetInclude eMode ) +{ + Any aCursorAny = createCursorAny( rPropertyNames, eMode ); + + Reference< XDynamicResultSet > xDynSet; + Reference< XResultSet > aResult; + + aCursorAny >>= xDynSet; + if ( xDynSet.is() ) + aResult = xDynSet->getStaticResultSet(); + + OSL_ENSURE( aResult.is(), "Content::createCursor - no cursor!" ); + + if ( !aResult.is() ) + { + // Former, the open command directly returned a XResultSet. + aCursorAny >>= aResult; + + OSL_ENSURE( !aResult.is(), + "Content::createCursor - open-Command must " + "return a Reference< XDynnamicResultSet >!" ); + } + + return aResult; +} + + +Reference< XDynamicResultSet > Content::createDynamicCursor( + const Sequence< OUString >& rPropertyNames, + ResultSetInclude eMode ) +{ + Reference< XDynamicResultSet > aResult; + createCursorAny( rPropertyNames, eMode ) >>= aResult; + + OSL_ENSURE( aResult.is(), "Content::createDynamicCursor - no cursor!" ); + + return aResult; +} + + +Reference< XResultSet > Content::createSortedCursor( + const Sequence< OUString >& rPropertyNames, + const Sequence< NumberedSortingInfo >& rSortInfo, + const Reference< XAnyCompareFactory >& rAnyCompareFactory, + ResultSetInclude eMode ) +{ + Reference< XResultSet > aResult; + Reference< XDynamicResultSet > aDynSet; + + Any aCursorAny = createCursorAny( rPropertyNames, eMode ); + + aCursorAny >>= aDynSet; + + if( aDynSet.is() ) + { + Reference< XDynamicResultSet > aDynResult; + + if( m_xImpl->getComponentContext().is() ) + { + Reference< XSortedDynamicResultSetFactory > aSortFactory = + SortedDynamicResultSetFactory::create( m_xImpl->getComponentContext()); + + aDynResult = aSortFactory->createSortedDynamicResultSet( aDynSet, + rSortInfo, + rAnyCompareFactory ); + } + + OSL_ENSURE( aDynResult.is(), "Content::createSortedCursor - no sorted cursor!" ); + + if( aDynResult.is() ) + aResult = aDynResult->getStaticResultSet(); + else + aResult = aDynSet->getStaticResultSet(); + } + + OSL_ENSURE( aResult.is(), "Content::createSortedCursor - no cursor!" ); + + if ( !aResult.is() ) + { + // Former, the open command directly returned a XResultSet. + aCursorAny >>= aResult; + + OSL_ENSURE( !aResult.is(), + "Content::createCursor - open-Command must " + "return a Reference< XDynnamicResultSet >!" ); + } + + return aResult; +} + + +Reference< XInputStream > Content::openStream() +{ + if ( !isDocument() ) + return Reference< XInputStream >(); + + Reference< XActiveDataSink > xSink = new ActiveDataSink; + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT; + aArg.Priority = 0; // unused + aArg.Sink = xSink; + aArg.Properties = Sequence< Property >( 0 ); // unused + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + return xSink->getInputStream(); +} + + +Reference< XInputStream > Content::openStreamNoLock() +{ + if ( !isDocument() ) + return Reference< XInputStream >(); + + Reference< XActiveDataSink > xSink = new ActiveDataSink; + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT_SHARE_DENY_NONE; + aArg.Priority = 0; // unused + aArg.Sink = xSink; + aArg.Properties = Sequence< Property >( 0 ); // unused + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + return xSink->getInputStream(); +} + + +Reference< XStream > Content::openWriteableStream() +{ + if ( !isDocument() ) + return Reference< XStream >(); + + Reference< XActiveDataStreamer > xStreamer = new ActiveDataStreamer; + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT; + aArg.Priority = 0; // unused + aArg.Sink = xStreamer; + aArg.Properties = Sequence< Property >( 0 ); // unused + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + return xStreamer->getStream(); +} + + +Reference< XStream > Content::openWriteableStreamNoLock() +{ + if ( !isDocument() ) + return Reference< XStream >(); + + Reference< XActiveDataStreamer > xStreamer = new ActiveDataStreamer; + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT_SHARE_DENY_NONE; + aArg.Priority = 0; // unused + aArg.Sink = xStreamer; + aArg.Properties = Sequence< Property >( 0 ); // unused + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + return xStreamer->getStream(); +} + + +bool Content::openStream( const Reference< XActiveDataSink >& rSink ) +{ + if ( !isDocument() ) + return false; + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT; + aArg.Priority = 0; // unused + aArg.Sink = rSink; + aArg.Properties = Sequence< Property >( 0 ); // unused + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + return true; +} + + +bool Content::openStream( const Reference< XOutputStream >& rStream ) +{ + if ( !isDocument() ) + return false; + + OpenCommandArgument2 aArg; + aArg.Mode = OpenMode::DOCUMENT; + aArg.Priority = 0; // unused + aArg.Sink = rStream; + aArg.Properties = Sequence< Property >( 0 ); // unused + + Command aCommand; + aCommand.Name = "open"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + return true; +} + + +void Content::writeStream( const Reference< XInputStream >& rStream, + bool bReplaceExisting ) +{ + InsertCommandArgument aArg; + aArg.Data = rStream.is() ? rStream : new EmptyInputStream; + aArg.ReplaceExisting = bReplaceExisting; + + Command aCommand; + aCommand.Name = "insert"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aArg; + + m_xImpl->executeCommand( aCommand ); + + m_xImpl->inserted(); +} + + +Sequence< ContentInfo > Content::queryCreatableContentsInfo() +{ + // First, try it using "CreatableContentsInfo" property -> the "new" way. + Sequence< ContentInfo > aInfo; + if ( getPropertyValue( + "CreatableContentsInfo" ) + >>= aInfo ) + return aInfo; + + // Second, try it using XContentCreator interface -> the "old" way (not + // providing the chance to supply an XCommandEnvironment. + Reference< XContentCreator > xCreator( m_xImpl->getContent(), UNO_QUERY ); + if ( xCreator.is() ) + aInfo = xCreator->queryCreatableContentsInfo(); + + return aInfo; +} + + +bool Content::insertNewContent( const OUString& rContentType, + const Sequence< OUString >& + rPropertyNames, + const Sequence< Any >& rPropertyValues, + Content& rNewContent ) +{ + return insertNewContent( rContentType, + rPropertyNames, + rPropertyValues, + new EmptyInputStream, + rNewContent ); +} + + +bool Content::insertNewContent( const OUString& rContentType, + const Sequence< OUString >& + rPropertyNames, + const Sequence< Any >& rPropertyValues, + const Reference< XInputStream >& rData, + Content& rNewContent ) +{ + if ( rContentType.isEmpty() ) + return false; + + // First, try it using "createNewContent" command -> the "new" way. + ContentInfo aInfo; + aInfo.Type = rContentType; + aInfo.Attributes = 0; + + Command aCommand; + aCommand.Name = "createNewContent"; + aCommand.Handle = -1; // n/a + aCommand.Argument <<= aInfo; + + Reference< XContent > xNew; + try + { + m_xImpl->executeCommand( aCommand ) >>= xNew; + } + catch ( RuntimeException const & ) + { + throw; + } + catch ( Exception const & ) + { + } + + if ( !xNew.is() ) + { + // Second, try it using XContentCreator interface -> the "old" + // way (not providing the chance to supply an XCommandEnvironment. + Reference< XContentCreator > xCreator( m_xImpl->getContent(), UNO_QUERY ); + + if ( !xCreator.is() ) + return false; + + xNew = xCreator->createNewContent( aInfo ); + + if ( !xNew.is() ) + return false; + } + + Content aNewContent( + xNew, m_xImpl->getEnvironment(), m_xImpl->getComponentContext() ); + aNewContent.setPropertyValues( rPropertyNames, rPropertyValues ); + aNewContent.executeCommand( "insert", + Any( + InsertCommandArgument( + rData.is() ? rData : new EmptyInputStream, + false /* ReplaceExisting */ ) ) ); + aNewContent.m_xImpl->inserted(); + + rNewContent = aNewContent; + return true; +} + + +void Content::transferContent( const Content& rSourceContent, + InsertOperation eOperation, + const OUString & rTitle, + const sal_Int32 nNameClashAction, + const OUString & rMimeType, + bool bMajorVersion, + const OUString & rVersionComment, + OUString* pResultURL, + const OUString & rDocumentId ) const +{ + Reference< XUniversalContentBroker > pBroker( + UniversalContentBroker::create( m_xImpl->getComponentContext() ) ); + + // Execute command "globalTransfer" at UCB. + + TransferCommandOperation eTransOp = TransferCommandOperation(); + OUString sCommand( "globalTransfer" ); + bool bCheckIn = false; + switch ( eOperation ) + { + case InsertOperation::Copy: + eTransOp = TransferCommandOperation_COPY; + break; + + case InsertOperation::Move: + eTransOp = TransferCommandOperation_MOVE; + break; + + case InsertOperation::Checkin: + eTransOp = TransferCommandOperation_COPY; + sCommand = "checkin"; + bCheckIn = true; + break; + } + Command aCommand; + aCommand.Name = sCommand; + aCommand.Handle = -1; // n/a + + if ( !bCheckIn ) + { + GlobalTransferCommandArgument2 aTransferArg( + eTransOp, + rSourceContent.getURL(), // SourceURL + getURL(), // TargetFolderURL, + rTitle, + nNameClashAction, + rMimeType, + rDocumentId ); + aCommand.Argument <<= aTransferArg; + } + else + { + CheckinArgument aCheckinArg( bMajorVersion, rVersionComment, + rSourceContent.getURL(), getURL(), rTitle, rMimeType ); + aCommand.Argument <<= aCheckinArg; + } + + Any aRet = pBroker->execute( aCommand, 0, m_xImpl->getEnvironment() ); + if ( pResultURL != nullptr ) + aRet >>= *pResultURL; +} + + +bool Content::isFolder() +{ + bool bFolder = false; + if ( getPropertyValue("IsFolder") + >>= bFolder ) + return bFolder; + + ucbhelper::cancelCommandExecution( + Any( UnknownPropertyException( + "Unable to retrieve value of property 'IsFolder'!", + get() ) ), + m_xImpl->getEnvironment() ); + + O3TL_UNREACHABLE; +} + + +bool Content::isDocument() +{ + bool bDoc = false; + if ( getPropertyValue("IsDocument") + >>= bDoc ) + return bDoc; + + ucbhelper::cancelCommandExecution( + Any( UnknownPropertyException( + "Unable to retrieve value of property 'IsDocument'!", + get() ) ), + m_xImpl->getEnvironment() ); + + O3TL_UNREACHABLE; +} + +void Content::lock() +{ + Command aCommand; + aCommand.Name = "lock"; + aCommand.Handle = -1; // n/a + + m_xImpl->executeCommand( aCommand ); + +} + +void Content::unlock() +{ + + Command aCommand; + aCommand.Name = "unlock"; + aCommand.Handle = -1; // n/a + + m_xImpl->executeCommand( aCommand ); + +} + + +// Content_Impl Implementation. + + +Content_Impl::Content_Impl( const Reference< XComponentContext >& rCtx, + const Reference< XContent >& rContent, + const Reference< XCommandEnvironment >& rEnv ) +: m_xCtx( rCtx ), + m_xContent( rContent ), + m_xEnv( rEnv ) +{ + assert(rCtx.is()); + if ( m_xContent.is() ) + { + m_xContentEventListener = new ContentEventListener_Impl( *this ); + m_xContent->addContentEventListener( m_xContentEventListener ); + +#if OSL_DEBUG_LEVEL > 0 + // Only done on demand in product version for performance reasons, + // but a nice debug helper. + getURL(); +#endif + } +} + + +void Content_Impl::reinit( const Reference< XContent >& xContent ) +{ + std::unique_lock aGuard( m_aMutex ); + + m_xCommandProcessor = nullptr; + + // #92581# - Don't reset m_aURL!!! + + if ( m_xContent.is() ) + { + try + { + m_xContent->removeContentEventListener( m_xContentEventListener ); + } + catch ( RuntimeException const & ) + { + } + } + + if ( xContent.is() ) + { + m_xContent = xContent; + m_xContent->addContentEventListener( m_xContentEventListener ); + +#if OSL_DEBUG_LEVEL > 0 + // Only done on demand in product version for performance reasons, + // but a nice debug helper. + getURL_NoLock(); +#endif + } + else + { + // We need m_xContent's URL in order to be able to create the + // content object again if demanded ( --> Content_Impl::getContent() ) + getURL_NoLock(); + + m_xContent = nullptr; + } +} + + +// virtual +Content_Impl::~Content_Impl() +{ + if ( m_xContent.is() ) + { + try + { + m_xContent->removeContentEventListener( m_xContentEventListener ); + } + catch ( RuntimeException const & ) + { + } + } +} + + +void Content_Impl::disposing( const EventObject& Source ) +{ + Reference<XContent> xContent; + + { + std::unique_lock aGuard( m_aMutex ); + if(Source.Source != m_xContent) + return; + + xContent = m_xContent; + + m_aURL.clear(); + m_xCommandProcessor = nullptr; + m_xContent = nullptr; + } + + if ( xContent.is() ) + { + try + { + xContent->removeContentEventListener( m_xContentEventListener ); + } + catch ( RuntimeException const & ) + { + } + } +} + + +const OUString& Content_Impl::getURL() const +{ + if ( m_aURL.isEmpty() && m_xContent.is() ) + { + std::unique_lock aGuard( m_aMutex ); + + return getURL_NoLock(); + } + + return m_aURL; +} + +const OUString& Content_Impl::getURL_NoLock() const +{ + if ( m_aURL.isEmpty() && m_xContent.is() ) + { + Reference< XContentIdentifier > xId = m_xContent->getIdentifier(); + if ( xId.is() ) + m_aURL = xId->getContentIdentifier(); + } + + return m_aURL; +} + +Reference< XContent > Content_Impl::getContent() +{ + if ( !m_xContent.is() && !m_aURL.isEmpty() ) + { + std::unique_lock aGuard( m_aMutex ); + return getContent_NoLock(); + } + return m_xContent; +} + +const Reference< XContent > & Content_Impl::getContent_NoLock() +{ + if ( !m_xContent.is() && !m_aURL.isEmpty() ) + { + Reference< XUniversalContentBroker > pBroker( + UniversalContentBroker::create( getComponentContext() ) ); + + OSL_ENSURE( pBroker->queryContentProviders().hasElements(), + "Content Broker not configured (no providers)!" ); + + Reference< XContentIdentifier > xId + = pBroker->createContentIdentifier( m_aURL ); + + OSL_ENSURE( xId.is(), "No Content Identifier!" ); + + if ( xId.is() ) + { + try + { + m_xContent = pBroker->queryContent( xId ); + } + catch ( IllegalIdentifierException const & ) + { + } + + if ( m_xContent.is() ) + m_xContent->addContentEventListener( + m_xContentEventListener ); + } + } + + return m_xContent; +} + + +Reference< XCommandProcessor > Content_Impl::getCommandProcessor() +{ + if ( !m_xCommandProcessor.is() ) + { + std::unique_lock aGuard( m_aMutex ); + + if ( !m_xCommandProcessor.is() ) + m_xCommandProcessor.set( getContent_NoLock(), UNO_QUERY ); + } + + return m_xCommandProcessor; +} + + +Any Content_Impl::executeCommand( const Command& rCommand ) +{ + Reference< XCommandProcessor > xProc = getCommandProcessor(); + if ( !xProc.is() ) + return Any(); + + // Execute command + return xProc->execute( rCommand, 0, m_xEnv ); +} + + +inline const Reference< XCommandEnvironment >& + Content_Impl::getEnvironment() const +{ + return m_xEnv; +} + + +inline void Content_Impl::setEnvironment( + const Reference< XCommandEnvironment >& xNewEnv ) +{ + std::unique_lock aGuard( m_aMutex ); + m_xEnv = xNewEnv; +} + + +void Content_Impl::inserted() +{ + // URL might have changed during 'insert' => recalculate in next getURL() + std::unique_lock aGuard( m_aMutex ); + m_aURL.clear(); +} + + +// ContentEventListener_Impl Implementation. + + +// XInterface methods. + +void SAL_CALL ContentEventListener_Impl::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL ContentEventListener_Impl::release() + noexcept +{ + OWeakObject::release(); +} + +css::uno::Any SAL_CALL ContentEventListener_Impl::queryInterface( const css::uno::Type & rType ) +{ + css::uno::Any aRet = cppu::queryInterface( rType, + static_cast< XContentEventListener* >(this), + static_cast< XEventListener* >(this) + ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + +// XContentEventListener methods. + + +// virtual +void SAL_CALL ContentEventListener_Impl::contentEvent( const ContentEvent& evt ) +{ + if ( evt.Source != m_rContent.m_xContent ) + return; + + switch ( evt.Action ) + { + case ContentAction::DELETED: + m_rContent.reinit( Reference< XContent >() ); + break; + + case ContentAction::EXCHANGED: + m_rContent.reinit( evt.Content ); + break; + + default: + break; + } +} + + +// XEventListenr methods. + + +// virtual +void SAL_CALL ContentEventListener_Impl::disposing( const EventObject& Source ) +{ + m_rContent.disposing(Source); +} + +} /* namespace ucbhelper */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/client/interceptedinteraction.cxx b/ucbhelper/source/client/interceptedinteraction.cxx new file mode 100644 index 0000000000..96b3fd32cb --- /dev/null +++ b/ucbhelper/source/client/interceptedinteraction.cxx @@ -0,0 +1,138 @@ +/* -*- 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 <ucbhelper/interceptedinteraction.hxx> + +#include <osl/diagnose.h> + +namespace ucbhelper{ + +InterceptedInteraction::InterceptedInteraction() +{ +} + +void InterceptedInteraction::setInterceptedHandler(const css::uno::Reference< css::task::XInteractionHandler >& xInterceptedHandler) +{ + m_xInterceptedHandler = xInterceptedHandler; +} + +void InterceptedInteraction::setInterceptions(::std::vector< InterceptedRequest >&& lInterceptions) +{ + m_lInterceptions = std::move(lInterceptions); +} + +InterceptedInteraction::EInterceptionState InterceptedInteraction::intercepted( + const InterceptedRequest&, + const css::uno::Reference< css::task::XInteractionRequest >&) +{ + // default behaviour! see impl_interceptRequest() for further information ... + return E_NOT_INTERCEPTED; +} + +css::uno::Reference< css::task::XInteractionContinuation > InterceptedInteraction::extractContinuation(const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > >& lContinuations, + const css::uno::Type& aType ) +{ + const css::uno::Reference< css::task::XInteractionContinuation >* pContinuations = std::find_if(lContinuations.begin(), lContinuations.end(), + [&aType](const css::uno::Reference< css::task::XInteractionContinuation >& rContinuation) { + css::uno::Reference< css::uno::XInterface > xCheck(rContinuation, css::uno::UNO_QUERY); + return xCheck->queryInterface(aType).hasValue(); + }); + if (pContinuations != lContinuations.end()) + return *pContinuations; + + return css::uno::Reference< css::task::XInteractionContinuation >(); +} + +void SAL_CALL InterceptedInteraction::handle(const css::uno::Reference< css::task::XInteractionRequest >& xRequest) +{ + impl_handleDefault(xRequest); +} + +void InterceptedInteraction::impl_handleDefault(const css::uno::Reference< css::task::XInteractionRequest >& xRequest) +{ + EInterceptionState eState = impl_interceptRequest(xRequest); + + switch(eState) + { + case E_NOT_INTERCEPTED: + { + // Non of the intercepted requests match to the given one. + // => forward request to the internal wrapped handler - if there is one. + if (m_xInterceptedHandler.is()) + m_xInterceptedHandler->handle(xRequest); + } + break; + + case E_NO_CONTINUATION_FOUND: + { + // Runtime error! The defined continuation could not be located + // inside the set of available continuations of the incoming request. + // What's wrong - the interception list or the request? + OSL_FAIL("InterceptedInteraction::handle()\nCould intercept this interaction request - but can't locate the right continuation!"); + } + break; + + case E_INTERCEPTED: + break; + } +} + +InterceptedInteraction::EInterceptionState InterceptedInteraction::impl_interceptRequest(const css::uno::Reference< css::task::XInteractionRequest >& xRequest) +{ + css::uno::Any aRequest = xRequest->getRequest(); + const css::uno::Type& aRequestType = aRequest.getValueType(); + css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations = xRequest->getContinuations(); + + // check against the list of static requests + auto pIt = std::find_if(m_lInterceptions.begin(), m_lInterceptions.end(), + [&aRequestType](const InterceptedRequest& rInterception) { + // check the request + // don't change intercepted and request type here -> it will check the wrong direction! + return rInterception.Request.getValueType().isAssignableFrom(aRequestType); + }); + + if (pIt != m_lInterceptions.end()) // intercepted ... + { + const InterceptedRequest& rInterception = *pIt; + + // Call they might existing derived class, so they can handle that by its own. + // If it's not interested on that (maybe it's not overwritten and the default implementation + // returns E_NOT_INTERCEPTED as default) -> search required continuation + EInterceptionState eState = intercepted(rInterception, xRequest); + if (eState != E_NOT_INTERCEPTED) + return eState; + + css::uno::Reference< css::task::XInteractionContinuation > xContinuation = InterceptedInteraction::extractContinuation(lContinuations, rInterception.Continuation); + if (xContinuation.is()) + { + xContinuation->select(); + return E_INTERCEPTED; + } + + // Can be reached only, if the request does not support the given continuation! + // => RuntimeError!? + return E_NO_CONTINUATION_FOUND; + } + + return E_NOT_INTERCEPTED; +} + +} // namespace ucbhelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/client/proxydecider.cxx b/ucbhelper/source/client/proxydecider.cxx new file mode 100644 index 0000000000..8acc15716a --- /dev/null +++ b/ucbhelper/source/client/proxydecider.cxx @@ -0,0 +1,916 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> +#include <utility> +#include <vector> +#include <deque> + +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <rtl/ref.hxx> +#include <osl/socket.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/util/XChangesListener.hpp> +#include <com/sun/star/util/XChangesNotifier.hpp> +#include <cppuhelper/implbase.hxx> +#include <ucbhelper/proxydecider.hxx> +#include <o3tl/string_view.hxx> + +#ifdef _WIN32 +#include <o3tl/char16_t2wchar_t.hxx> +#define WIN32_LEAN_AND_MEAN +#include <Windows.h> +#include <Winhttp.h> +#include <process.h> +#endif + +using namespace com::sun::star; +using namespace ucbhelper; + +constexpr OUString CONFIG_ROOT_KEY = u"org.openoffice.Inet/Settings"_ustr; +constexpr OUString PROXY_TYPE_KEY = u"ooInetProxyType"_ustr; +constexpr OUString NO_PROXY_LIST_KEY = u"ooInetNoProxy"_ustr; +constexpr OUString HTTP_PROXY_NAME_KEY = u"ooInetHTTPProxyName"_ustr; +constexpr OUString HTTP_PROXY_PORT_KEY = u"ooInetHTTPProxyPort"_ustr; +constexpr OUString HTTPS_PROXY_NAME_KEY = u"ooInetHTTPSProxyName"_ustr; +constexpr OUString HTTPS_PROXY_PORT_KEY = u"ooInetHTTPSProxyPort"_ustr; + + +namespace ucbhelper +{ + + +namespace proxydecider_impl +{ + +namespace { + +// A simple case ignoring wildcard matcher. +class WildCard +{ +private: + OString m_aWildString; + +public: + explicit WildCard( std::u16string_view rWildCard ) + : m_aWildString( + OUStringToOString( + rWildCard, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() ) {} + + bool Matches( std::u16string_view rStr ) const; +}; + +} + +namespace { + +class HostnameCache +{ + typedef std::pair< OUString, OUString > HostListEntry; + + std::deque< HostListEntry > m_aHostList; + +public: + bool get( std::u16string_view rKey, OUString & rValue ) const + { + for (auto const& host : m_aHostList) + { + if ( host.first == rKey ) + { + rValue = host.second; + return true; + } + } + return false; + } + + void put( const OUString & rKey, const OUString & rValue ) + { + static constexpr sal_uInt32 nCapacity = 256; + + if ( m_aHostList.size() == nCapacity ) + m_aHostList.resize( nCapacity / 2 ); + + m_aHostList.push_front( HostListEntry( rKey, rValue ) ); + } +}; + +} + +class InternetProxyDecider_Impl : + public cppu::WeakImplHelper< util::XChangesListener > +{ + // see officecfg/registry/schema/org/openoffice/Inet.xcs for the definition of these values + enum class ProxyType { NoProxy, Automatic, Manual }; + mutable osl::Mutex m_aMutex; + InternetProxyServer m_aHttpProxy; + InternetProxyServer m_aHttpsProxy; + const InternetProxyServer m_aEmptyProxy; + ProxyType m_nProxyType; + uno::Reference< util::XChangesNotifier > m_xNotifier; + typedef std::pair< WildCard, WildCard > NoProxyListEntry; + std::vector< NoProxyListEntry > m_aNoProxyList; + mutable HostnameCache m_aHostnames; + +private: + bool shouldUseProxy( std::u16string_view rHost, + sal_Int32 nPort, + bool bUseFullyQualified ) const; +public: + explicit InternetProxyDecider_Impl( + const uno::Reference< uno::XComponentContext >& rxContext ); + + void dispose(); + + InternetProxyServer getProxy(const OUString& rProtocol, + const OUString & rHost, + sal_Int32 nPort ) const; + + // XChangesListener + virtual void SAL_CALL changesOccurred( const util::ChangesEvent& Event ) override; + + // XEventListener ( base of XChangesLisetenr ) + virtual void SAL_CALL disposing( const lang::EventObject& Source ) override; + +private: + void setNoProxyList( const OUString & rNoProxyList ); +}; + + +// WildCard Implementation. + + +bool WildCard::Matches( std::u16string_view rString ) const +{ + OString aString + = OUStringToOString( rString, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase(); + const char * pStr = aString.getStr(); + const char * pWild = m_aWildString.getStr(); + + int pos = 0; + int flag = 0; + + while ( *pWild || flag ) + { + switch ( *pWild ) + { + case '?': + if ( *pStr == '\0' ) + return false; + break; + + default: + if ( ( *pWild == '\\' ) && ( ( *( pWild + 1 ) == '?' ) + || ( *( pWild + 1 ) == '*') ) ) + pWild++; + if ( *pWild != *pStr ) + if ( !pos ) + return false; + else + pWild += pos; + else + break; + + [[fallthrough]]; + + case '*': + while ( *pWild == '*' ) + pWild++; + if ( *pWild == '\0' ) + return true; + flag = 1; + pos = 0; + if ( *pStr == '\0' ) + return ( *pWild == '\0' ); + while ( *pStr && *pStr != *pWild ) + { + if ( *pWild == '?' ) { + pWild++; + while ( *pWild == '*' ) + pWild++; + } + pStr++; + if ( *pStr == '\0' ) + return ( *pWild == '\0' ); + } + break; + } + if ( *pWild != '\0' ) + pWild++; + if ( *pStr != '\0' ) + pStr++; + else + flag = 0; + if ( flag ) + pos--; + } + return ( *pStr == '\0' ) && ( *pWild == '\0' ); +} + + +static bool getConfigStringValue( + const uno::Reference< container::XNameAccess > & xNameAccess, + const OUString& key, + OUString & value ) +{ + try + { + if ( !( xNameAccess->getByName( key ) >>= value ) ) + { + OSL_FAIL( "InternetProxyDecider - " + "Error getting config item value!" ); + return false; + } + } + catch ( lang::WrappedTargetException const & ) + { + return false; + } + catch ( container::NoSuchElementException const & ) + { + return false; + } + return true; +} + + +static bool getConfigInt32Value( + const uno::Reference< container::XNameAccess > & xNameAccess, + const OUString& key, + sal_Int32 & value ) +{ + try + { + uno::Any aValue = xNameAccess->getByName( key ); + if ( aValue.hasValue() && !( aValue >>= value ) ) + { + OSL_FAIL( "InternetProxyDecider - " + "Error getting config item value!" ); + return false; + } + } + catch ( lang::WrappedTargetException const & ) + { + return false; + } + catch ( container::NoSuchElementException const & ) + { + return false; + } + return true; +} + + +// InternetProxyDecider_Impl Implementation. + + +InternetProxyDecider_Impl::InternetProxyDecider_Impl( + const uno::Reference< uno::XComponentContext >& rxContext ) + : m_nProxyType( ProxyType::NoProxy ), + m_aHostnames() +{ + try + { + + // Read proxy configuration from config db. + + + uno::Reference< lang::XMultiServiceFactory > xConfigProv = + configuration::theDefaultProvider::get( rxContext ); + + uno::Sequence< uno::Any > aArguments{ uno::Any(CONFIG_ROOT_KEY) }; + uno::Reference< uno::XInterface > xInterface( + xConfigProv->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", + aArguments ) ); + + OSL_ENSURE( xInterface.is(), + "InternetProxyDecider - No config access!" ); + + if ( xInterface.is() ) + { + uno::Reference< container::XNameAccess > xNameAccess( + xInterface, uno::UNO_QUERY ); + OSL_ENSURE( xNameAccess.is(), + "InternetProxyDecider - No name access!" ); + + if ( xNameAccess.is() ) + { + // *** Proxy type *** + sal_Int32 tmp = 0; + getConfigInt32Value( + xNameAccess, PROXY_TYPE_KEY, tmp ); + m_nProxyType = static_cast<ProxyType>(tmp); + + // *** No proxy list *** + OUString aNoProxyList; + getConfigStringValue( + xNameAccess, NO_PROXY_LIST_KEY, aNoProxyList ); + setNoProxyList( aNoProxyList ); + + // *** HTTP *** + getConfigStringValue( + xNameAccess, HTTP_PROXY_NAME_KEY, m_aHttpProxy.aName ); + + m_aHttpProxy.nPort = -1; + getConfigInt32Value( + xNameAccess, HTTP_PROXY_PORT_KEY, m_aHttpProxy.nPort ); + if ( m_aHttpProxy.nPort == -1 ) + m_aHttpProxy.nPort = 80; // standard HTTP port. + + // *** HTTPS *** + getConfigStringValue( + xNameAccess, HTTPS_PROXY_NAME_KEY, m_aHttpsProxy.aName ); + + m_aHttpsProxy.nPort = -1; + getConfigInt32Value( + xNameAccess, HTTPS_PROXY_PORT_KEY, m_aHttpsProxy.nPort ); + if ( m_aHttpsProxy.nPort == -1 ) + m_aHttpsProxy.nPort = 443; // standard HTTPS port. + } + + // Register as listener for config changes. + + m_xNotifier.set( xInterface, uno::UNO_QUERY ); + + OSL_ENSURE( m_xNotifier.is(), + "InternetProxyDecider - No notifier!" ); + + if ( m_xNotifier.is() ) + m_xNotifier->addChangesListener( this ); + } + } + catch ( uno::Exception const & ) + { + // createInstance, createInstanceWithArguments + OSL_FAIL( "InternetProxyDecider - Exception!" ); + } +} + +void InternetProxyDecider_Impl::dispose() +{ + uno::Reference< util::XChangesNotifier > xNotifier; + + if ( m_xNotifier.is() ) + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + if ( m_xNotifier.is() ) + { + xNotifier = m_xNotifier; + m_xNotifier.clear(); + } + } + + // Do this unguarded! + if ( xNotifier.is() ) + xNotifier->removeChangesListener( this ); +} + + +bool InternetProxyDecider_Impl::shouldUseProxy( std::u16string_view rHost, + sal_Int32 nPort, + bool bUseFullyQualified ) const +{ + OUStringBuffer aBuffer; + + if ( ( rHost.find( ':' ) != std::u16string_view::npos ) && + ( rHost[ 0 ] != '[' ) ) + { + // host is given as numeric IPv6 address + aBuffer.append( OUString::Concat("[") + rHost + "]" ); + } + else + { + // host is given either as numeric IPv4 address or non-numeric hostname + aBuffer.append( rHost ); + } + + aBuffer.append( ":" + OUString::number( nPort ) ); + + for (auto const& noProxy : m_aNoProxyList) + { + if ( bUseFullyQualified ) + { + if ( noProxy.second.Matches( aBuffer ) ) + return false; + } + else + { + if ( noProxy.first.Matches( aBuffer ) ) + return false; + } + } + + return true; +} + +namespace +{ +#ifdef _WIN32 +struct GetPACProxyData +{ + const OUString& m_rProtocol; + const OUString& m_rHost; + sal_Int32 m_nPort; + bool m_bAutoDetect = false; + OUString m_sAutoConfigUrl; + InternetProxyServer m_ProxyServer; + + GetPACProxyData(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort) + : m_rProtocol(rProtocol) + , m_rHost(rHost) + , m_nPort(nPort) + { + } +}; + +// Tries to get proxy configuration using WinHttpGetProxyForUrl, which supports Web Proxy Auto-Discovery +// (WPAD) protocol and manually configured address to get Proxy Auto-Configuration (PAC) file. +// The WinINet/WinHTTP functions cannot correctly run in a STA COM thread, so use a dedicated thread +unsigned __stdcall GetPACProxyThread(void* lpParameter) +{ + assert(lpParameter); + GetPACProxyData* pData = static_cast<GetPACProxyData*>(lpParameter); + + OUString url(pData->m_rProtocol + "://" + pData->m_rHost + ":" + + OUString::number(pData->m_nPort)); + + HINTERNET hInternet = WinHttpOpen(L"Mozilla 5.0", WINHTTP_ACCESS_TYPE_NO_PROXY, + WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); + DWORD nError = GetLastError(); + if (!hInternet) + return nError; + + WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions{}; + if (pData->m_bAutoDetect) + { + AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT; + AutoProxyOptions.dwAutoDetectFlags + = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A; + } + if (!pData->m_sAutoConfigUrl.isEmpty()) + { + AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL; + AutoProxyOptions.lpszAutoConfigUrl = o3tl::toW(pData->m_sAutoConfigUrl.getStr()); + } + // First, try without autologon. According to + // https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/web/winhttp/WinhttpProxySample/GetProxy.cpp + // autologon prevents caching, and so causes repetitive network traffic. + AutoProxyOptions.fAutoLogonIfChallenged = FALSE; + WINHTTP_PROXY_INFO ProxyInfo{}; + bool bResult + = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()), &AutoProxyOptions, &ProxyInfo); + nError = GetLastError(); + if (!bResult && nError == ERROR_WINHTTP_LOGIN_FAILURE) + { + AutoProxyOptions.fAutoLogonIfChallenged = TRUE; + bResult = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()), + &AutoProxyOptions, &ProxyInfo); + nError = GetLastError(); + } + WinHttpCloseHandle(hInternet); + if (bResult) + { + if (ProxyInfo.lpszProxyBypass) + GlobalFree(ProxyInfo.lpszProxyBypass); + if (ProxyInfo.lpszProxy) + { + OUString sProxyResult(o3tl::toU(ProxyInfo.lpszProxy)); + GlobalFree(ProxyInfo.lpszProxy); + // Get the first of possibly multiple results + sProxyResult = sProxyResult.getToken(0, ';'); + sal_Int32 nPortSepPos = sProxyResult.indexOf(':'); + if (nPortSepPos != -1) + { + pData->m_ProxyServer.nPort = o3tl::toInt32(sProxyResult.subView(nPortSepPos + 1)); + sProxyResult = sProxyResult.copy(0, nPortSepPos); + } + else + { + pData->m_ProxyServer.nPort = 0; + } + pData->m_ProxyServer.aName = sProxyResult; + } + } + + return nError; +} + +InternetProxyServer GetPACProxy(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort) +{ + GetPACProxyData aData(rProtocol, rHost, nPort); + + // WinHTTP only supports http(s), so don't try for other protocols + if (!(rProtocol.equalsIgnoreAsciiCase("http") || rProtocol.equalsIgnoreAsciiCase("https"))) + return aData.m_ProxyServer; + + // Only try to get configuration from PAC (with all the overhead, including new thread) + // if configured to do so + { + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG aProxyConfig{}; + bool bResult = WinHttpGetIEProxyConfigForCurrentUser(&aProxyConfig); + if (aProxyConfig.lpszProxy) + GlobalFree(aProxyConfig.lpszProxy); + if (aProxyConfig.lpszProxyBypass) + GlobalFree(aProxyConfig.lpszProxyBypass); + // Don't try WPAD if AutoDetection or AutoConfig script URL are not configured + if (!bResult || !(aProxyConfig.fAutoDetect || aProxyConfig.lpszAutoConfigUrl)) + return aData.m_ProxyServer; + aData.m_bAutoDetect = aProxyConfig.fAutoDetect; + if (aProxyConfig.lpszAutoConfigUrl) + { + aData.m_sAutoConfigUrl = o3tl::toU(aProxyConfig.lpszAutoConfigUrl); + GlobalFree(aProxyConfig.lpszAutoConfigUrl); + } + } + + HANDLE hThread = reinterpret_cast<HANDLE>( + _beginthreadex(nullptr, 0, GetPACProxyThread, &aData, 0, nullptr)); + if (hThread) + { + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + } + return aData.m_ProxyServer; +} + +#else // .. _WIN32 + +// Read the settings from the OS which are stored in env vars +// +InternetProxyServer GetUnixSystemProxy(const OUString & rProtocol) +{ + // TODO this could be improved to read the "no_proxy" env variable + InternetProxyServer aProxy; + OUString protocolLower = rProtocol.toAsciiLowerCase() + "_proxy"; + OString protocolLowerStr = OUStringToOString( protocolLower, RTL_TEXTENCODING_ASCII_US ); + const char* pEnvProxy = getenv(protocolLowerStr.getStr()); + if (!pEnvProxy) + return aProxy; + // expecting something like "https://example.ct:80" + OUString tmp = OUString::createFromAscii(pEnvProxy); + if (tmp.getLength() < (rProtocol.getLength() + 3)) + return aProxy; + sal_Int32 x = tmp.indexOf("://"); + sal_Int32 at = tmp.indexOf('@', x == -1 ? 0 : x + 3); + x = tmp.indexOf(':', at == -1 ? x == -1 ? 0 : x + 3 : at + 1); + if (x == -1) + return aProxy; + int nPort = o3tl::toInt32(tmp.subView(x + 1)); + if (nPort == 0) + return aProxy; + aProxy.aName = tmp.copy(0, x); + aProxy.nPort = nPort; + return aProxy; +} + +#endif // else .. _WIN32 +} + +InternetProxyServer InternetProxyDecider_Impl::getProxy( + const OUString & rProtocol, + const OUString & rHost, + sal_Int32 nPort ) const +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + if ( m_nProxyType == ProxyType::NoProxy ) + { + // Never use proxy. + return m_aEmptyProxy; + } + + // If get from system + if (m_nProxyType == ProxyType::Automatic && !rHost.isEmpty()) + { +#ifdef _WIN32 + InternetProxyServer aProxy(GetPACProxy(rProtocol, rHost, nPort)); +#else + InternetProxyServer aProxy(GetUnixSystemProxy(rProtocol)); +#endif // _WIN32 + if (!aProxy.aName.isEmpty()) + return aProxy; + } + + if ( !rHost.isEmpty() && !m_aNoProxyList.empty() ) + { + + // First, try direct hostname match - #110515# + + + if ( !shouldUseProxy( rHost, nPort, false ) ) + return m_aEmptyProxy; + + + // Second, try match against full qualified hostname - #104401# + + + OUString aHost; + + if ( ( rHost.getLength() > 1 ) && + ( rHost[ 0 ] == '[' )) + { + // host is given as numeric IPv6 address. name resolution + // functions need hostname without square brackets. + aHost = rHost.copy( 1, rHost.getLength() - 2 ); + } + else + { + aHost = rHost; + } + + OUString aFullyQualifiedHost; + if ( !m_aHostnames.get( aHost, aFullyQualifiedHost ) ) + { + // This might be quite expensive (DNS lookup). + const osl::SocketAddr aAddr( aHost, nPort ); + aFullyQualifiedHost = aAddr.getHostname().toAsciiLowerCase(); + m_aHostnames.put( aHost, aFullyQualifiedHost ); + } + + // Error resolving name? -> fallback. + if ( aFullyQualifiedHost.isEmpty() ) + aFullyQualifiedHost = aHost; + + if ( aFullyQualifiedHost != aHost ) + { + if ( !shouldUseProxy( aFullyQualifiedHost, nPort, false ) ) + return m_aEmptyProxy; + } + + + // Third, try match of fully qualified entries in no-proxy list + // against full qualified hostname + + // Example: + // list: staroffice-doc -> full: xyz.germany.sun.com + // in: staroffice-doc.germany.sun.com -> full: xyz.germany.sun.com + + + if ( !shouldUseProxy( aFullyQualifiedHost, nPort, true ) ) + return m_aEmptyProxy; + } + + if (rProtocol.toAsciiLowerCase() == "https") + { + if ( !m_aHttpsProxy.aName.isEmpty() ) + return m_aHttpsProxy; + } + else if ( !m_aHttpProxy.aName.isEmpty() ) + { + // All other protocols use the HTTP proxy. + return m_aHttpProxy; + } + return m_aEmptyProxy; +} + +// virtual +void SAL_CALL InternetProxyDecider_Impl::changesOccurred( + const util::ChangesEvent& Event ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + for ( const util::ElementChange& rElem : Event.Changes ) + { + OUString aKey; + if ( ( rElem.Accessor >>= aKey ) && !aKey.isEmpty() ) + { + if ( aKey == PROXY_TYPE_KEY ) + { + sal_Int32 tmp; + if ( !( rElem.Element >>= tmp ) ) + { + OSL_FAIL( "InternetProxyDecider - changesOccurred - " + "Error getting config item value!" ); + } + else + m_nProxyType = static_cast<ProxyType>(tmp); + } + else if ( aKey == NO_PROXY_LIST_KEY ) + { + OUString aNoProxyList; + if ( !( rElem.Element >>= aNoProxyList ) ) + { + OSL_FAIL( "InternetProxyDecider - changesOccurred - " + "Error getting config item value!" ); + } + + setNoProxyList( aNoProxyList ); + } + else if ( aKey == HTTP_PROXY_NAME_KEY ) + { + if ( !( rElem.Element >>= m_aHttpProxy.aName ) ) + { + OSL_FAIL( "InternetProxyDecider - changesOccurred - " + "Error getting config item value!" ); + } + } + else if ( aKey == HTTP_PROXY_PORT_KEY ) + { + if ( !( rElem.Element >>= m_aHttpProxy.nPort ) ) + { + OSL_FAIL( "InternetProxyDecider - changesOccurred - " + "Error getting config item value!" ); + } + + if ( m_aHttpProxy.nPort == -1 ) + m_aHttpProxy.nPort = 80; // standard HTTP port. + } + else if ( aKey == HTTPS_PROXY_NAME_KEY ) + { + if ( !( rElem.Element >>= m_aHttpsProxy.aName ) ) + { + OSL_FAIL( "InternetProxyDecider - changesOccurred - " + "Error getting config item value!" ); + } + } + else if ( aKey == HTTPS_PROXY_PORT_KEY ) + { + if ( !( rElem.Element >>= m_aHttpsProxy.nPort ) ) + { + OSL_FAIL( "InternetProxyDecider - changesOccurred - " + "Error getting config item value!" ); + } + + if ( m_aHttpsProxy.nPort == -1 ) + m_aHttpsProxy.nPort = 443; // standard HTTPS port. + } + } + } +} + + +// virtual +void SAL_CALL InternetProxyDecider_Impl::disposing(const lang::EventObject&) +{ + if ( m_xNotifier.is() ) + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + if ( m_xNotifier.is() ) + m_xNotifier.clear(); + } +} + + +void InternetProxyDecider_Impl::setNoProxyList( + const OUString & rNoProxyList ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + m_aNoProxyList.clear(); + + if ( rNoProxyList.isEmpty() ) + return; + + // List of connection endpoints hostname[:port], + // separated by semicolon. Wildcards allowed. + + sal_Int32 nPos = 0; + sal_Int32 nEnd = rNoProxyList.indexOf( ';' ); + sal_Int32 nLen = rNoProxyList.getLength(); + + do + { + if ( nEnd == -1 ) + nEnd = nLen; + + OUString aToken = rNoProxyList.copy( nPos, nEnd - nPos ); + + if ( !aToken.isEmpty() ) + { + OUString aServer; + OUString aPort; + + // numerical IPv6 address? + bool bIPv6Address = false; + sal_Int32 nClosedBracketPos = aToken.indexOf( ']' ); + if ( nClosedBracketPos == -1 ) + nClosedBracketPos = 0; + else + bIPv6Address = true; + + sal_Int32 nColonPos = aToken.indexOf( ':', nClosedBracketPos ); + if ( nColonPos == -1 ) + { + // No port given, server pattern equals current token + aPort = "*"; + if ( aToken.indexOf( '*' ) == -1 ) + { + // pattern describes exactly one server + aServer = aToken; + } + + aToken += ":*"; + } + else + { + // Port given, extract server pattern + sal_Int32 nAsteriskPos = aToken.indexOf( '*' ); + aPort = aToken.copy( nColonPos + 1 ); + if ( nAsteriskPos < nColonPos ) + { + // pattern describes exactly one server + aServer = aToken.copy( 0, nColonPos ); + } + } + + OUStringBuffer aFullyQualifiedHost; + if ( !aServer.isEmpty() ) + { + // Remember fully qualified server name if current list + // entry specifies exactly one non-fully qualified server + // name. + + // remove square brackets from host name in case it's + // a numerical IPv6 address. + if ( bIPv6Address ) + aServer = aServer.copy( 1, aServer.getLength() - 2 ); + + // This might be quite expensive (DNS lookup). + const osl::SocketAddr aAddr( aServer, 0 ); + OUString aTmp = aAddr.getHostname().toAsciiLowerCase(); + if ( aTmp != aServer.toAsciiLowerCase() ) + { + if ( bIPv6Address ) + aFullyQualifiedHost.append( "[" + aTmp + "]" ); + else + aFullyQualifiedHost.append( aTmp ); + aFullyQualifiedHost.append( ":" + aPort ); + } + } + + m_aNoProxyList.emplace_back( WildCard( aToken ), + WildCard( aFullyQualifiedHost ) ); + } + + if ( nEnd != nLen ) + { + nPos = nEnd + 1; + nEnd = rNoProxyList.indexOf( ';', nPos ); + } + } + while ( nEnd != nLen ); +} + +} // namespace proxydecider_impl + + +// InternetProxyDecider Implementation. + + +InternetProxyDecider::InternetProxyDecider( + const uno::Reference< uno::XComponentContext>& rxContext ) +: m_xImpl( new proxydecider_impl::InternetProxyDecider_Impl( rxContext ) ) +{ +} + + +InternetProxyDecider::~InternetProxyDecider() +{ + // Break circular reference between config listener and notifier. + m_xImpl->dispose(); +} + + +OUString InternetProxyDecider::getProxy( + const OUString & rProtocol, + const OUString & rHost, + sal_Int32 nPort ) const +{ + InternetProxyServer ret(m_xImpl->getProxy(rProtocol, rHost, nPort)); + + if (ret.aName.isEmpty() || ret.nPort == -1) + { + return ret.aName; + } + + return ret.aName + ":" + OUString::number(ret.nPort); +} + +} // namespace ucbhelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/authenticationfallback.cxx b/ucbhelper/source/provider/authenticationfallback.cxx new file mode 100644 index 0000000000..04491520bd --- /dev/null +++ b/ucbhelper/source/provider/authenticationfallback.cxx @@ -0,0 +1,31 @@ +/* -*- 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/. + */ + +#include <ucbhelper/authenticationfallback.hxx> +#include <com/sun/star/ucb/AuthenticationFallbackRequest.hpp> + +using namespace com::sun::star; +using namespace ucbhelper; + +AuthenticationFallbackRequest::AuthenticationFallbackRequest( + const OUString & rInstructions, + const OUString & rURL ) +{ + + ucb::AuthenticationFallbackRequest aRequest; + aRequest.instructions = rInstructions; + aRequest.url = rURL; + + setRequest( uno::Any( aRequest ) ); + m_xAuthFallback = new InteractionAuthFallback( this ); + + setContinuations({ new InteractionAbort(this), m_xAuthFallback }); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/cancelcommandexecution.cxx b/ucbhelper/source/provider/cancelcommandexecution.cxx new file mode 100644 index 0000000000..57166e49b0 --- /dev/null +++ b/ucbhelper/source/provider/cancelcommandexecution.cxx @@ -0,0 +1,115 @@ +/* -*- 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 <osl/diagnose.h> +#include <rtl/ref.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <com/sun/star/ucb/CommandFailedException.hpp> +#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <ucbhelper/interactionrequest.hxx> +#include <ucbhelper/cancelcommandexecution.hxx> +#include "simpleioerrorrequest.hxx" + +using namespace com::sun::star; + +namespace ucbhelper +{ + + +void cancelCommandExecution( const uno::Any & rException, + const uno::Reference< + ucb::XCommandEnvironment > & xEnv ) +{ + if ( xEnv.is() ) + { + uno::Reference< + task::XInteractionHandler > xIH = xEnv->getInteractionHandler(); + if ( xIH.is() ) + { + rtl::Reference< ucbhelper::InteractionRequest > xRequest + = new ucbhelper::InteractionRequest( rException ); + + xRequest->setContinuations({ new ucbhelper::InteractionAbort(xRequest.get()) }); + + xIH->handle( xRequest ); + + rtl::Reference< ucbhelper::InteractionContinuation > xSelection + = xRequest->getSelection(); + + if ( xSelection.is() ) + throw ucb::CommandFailedException( + OUString(), + uno::Reference< uno::XInterface >(), + rException ); + } + } + + cppu::throwException( rException ); + OSL_FAIL( "Return from cppu::throwException call!!!" ); + throw uno::RuntimeException(); +} + + +void cancelCommandExecution( const ucb::IOErrorCode eError, + const uno::Sequence< uno::Any > & rArgs, + const uno::Reference< + ucb::XCommandEnvironment > & xEnv, + const OUString & rMessage, + const uno::Reference< + ucb::XCommandProcessor > & xContext ) +{ + if ( !xEnv ) + { + // Fast path + + ucb::InteractiveAugmentedIOException aRequest( + rMessage, xContext, task::InteractionClassification_ERROR, eError, rArgs); + cppu::throwException( uno::Any( aRequest ) ); + } + else + { + rtl::Reference< ucbhelper::SimpleIOErrorRequest > xRequest + = new ucbhelper::SimpleIOErrorRequest( + eError, rArgs, rMessage, xContext ); + uno::Reference< + task::XInteractionHandler > xIH = xEnv->getInteractionHandler(); + if ( xIH.is() ) + { + xIH->handle( xRequest ); + + rtl::Reference< ucbhelper::InteractionContinuation > xSelection + = xRequest->getSelection(); + + if ( xSelection.is() ) + throw ucb::CommandFailedException( OUString(), + xContext, + xRequest->getRequest() ); + } + cppu::throwException( xRequest->getRequest() ); + } + + OSL_FAIL( "Return from cppu::throwException call!!!" ); + throw uno::RuntimeException(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/contenthelper.cxx b/ucbhelper/source/provider/contenthelper.cxx new file mode 100644 index 0000000000..1e5147f6fb --- /dev/null +++ b/ucbhelper/source/provider/contenthelper.cxx @@ -0,0 +1,863 @@ +/* -*- 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 <sal/config.h> + +#include <com/sun/star/lang/NoSupportException.hpp> +#include <com/sun/star/ucb/ContentAction.hpp> +#include <com/sun/star/ucb/IllegalIdentifierException.hpp> +#include <com/sun/star/ucb/XPersistentPropertySet.hpp> +#include <com/sun/star/beans/IllegalTypeException.hpp> +#include <com/sun/star/beans/NotRemoveableException.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyExistException.hpp> +#include <com/sun/star/beans/PropertySetInfoChange.hpp> +#include <comphelper/interfacecontainer3.hxx> +#include <cppuhelper/interfacecontainer.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <ucbhelper/contenthelper.hxx> +#include <ucbhelper/contentidentifier.hxx> +#include "contentinfo.hxx" +#include <ucbhelper/providerhelper.hxx> +#include <ucbhelper/macros.hxx> + +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <rtl/ref.hxx> + +#include <unordered_map> +#include <utility> + +using namespace com::sun::star; + +namespace ucbhelper_impl +{ + +namespace { + +class PropertyEventSequence +{ + uno::Sequence< beans::PropertyChangeEvent > m_aSeq; + sal_uInt32 m_nPos; + +public: + explicit PropertyEventSequence( sal_uInt32 nSize ) + : m_aSeq( nSize ), m_nPos( 0 ) {}; + + void append( const beans::PropertyChangeEvent& rEvt ) + { m_aSeq.getArray()[ m_nPos ] = rEvt; ++m_nPos; } + + const uno::Sequence< beans::PropertyChangeEvent >& getEvents() + { m_aSeq.realloc( m_nPos ); return m_aSeq; } +}; + +} + +typedef void* XPropertiesChangeListenerPtr; // -> Compiler problems! + +namespace { + +struct equalPtr +{ + bool operator()( const XPropertiesChangeListenerPtr& rp1, + const XPropertiesChangeListenerPtr& rp2 ) const + { + return ( rp1 == rp2 ); + } +}; + +struct hashPtr +{ + size_t operator()( const XPropertiesChangeListenerPtr& rp ) const + { + return reinterpret_cast<size_t>(rp); + } +}; + +} + +typedef std::unordered_map +< + XPropertiesChangeListenerPtr, + PropertyEventSequence, + hashPtr, + equalPtr +> +PropertiesEventListenerMap; + +typedef cppu::OMultiTypeInterfaceContainerHelperVar<OUString> + PropertyChangeListeners; + +struct ContentImplHelper_Impl +{ + rtl::Reference< ::ucbhelper::PropertySetInfo > m_xPropSetInfo; + rtl::Reference< ::ucbhelper::CommandProcessorInfo > m_xCommandsInfo; + std::unique_ptr<cppu::OInterfaceContainerHelper> m_pDisposeEventListeners; + std::unique_ptr<comphelper::OInterfaceContainerHelper3<css::ucb::XContentEventListener>> + m_pContentEventListeners; + std::unique_ptr<comphelper::OInterfaceContainerHelper3<beans::XPropertySetInfoChangeListener>> + m_pPropSetChangeListeners; + std::unique_ptr<cppu::OInterfaceContainerHelper> m_pCommandChangeListeners; + std::unique_ptr<PropertyChangeListeners> m_pPropertyChangeListeners; +}; + +} // namespace ucbhelper_impl + +using namespace ucbhelper_impl; + +namespace ucbhelper { + +ContentImplHelper::ContentImplHelper( + uno::Reference< uno::XComponentContext > xContext, + rtl::Reference< ContentProviderImplHelper > xProvider, + uno::Reference< + css::ucb::XContentIdentifier > Identifier ) +: m_pImpl( new ContentImplHelper_Impl ), + m_xContext(std::move( xContext )), + m_xIdentifier(std::move( Identifier )), + m_xProvider(std::move( xProvider )), + m_nCommandId( 0 ) +{ +} + +// virtual +ContentImplHelper::~ContentImplHelper() +{ +} + +void SAL_CALL ContentImplHelper::release() + noexcept +{ + // #144882# - Call to OWeakObject::release may destroy m_xProvider. + // Prevent this. + rtl::Reference< ContentProviderImplHelper > xKeepProviderAlive( + m_xProvider ); + + osl::MutexGuard aGuard( m_xProvider->m_aMutex ); + OWeakObject::release(); +} + +uno::Any SAL_CALL ContentImplHelper::queryInterface( const uno::Type & rType ) +{ + css::uno::Any aRet = cppu::queryInterface( rType, + static_cast< lang::XTypeProvider * >(this), + static_cast< lang::XServiceInfo * >(this), + static_cast< lang::XComponent * >(this), + static_cast< css::ucb::XContent * >(this), + static_cast< css::ucb::XCommandProcessor * >(this), + static_cast< beans::XPropertiesChangeNotifier * >(this), + static_cast< css::ucb::XCommandInfoChangeNotifier * >(this), + static_cast< beans::XPropertyContainer * >(this), + static_cast< beans::XPropertySetInfoChangeNotifier * >(this), + static_cast< container::XChild * >(this)); + return aRet.hasValue() ? aRet : cppu::OWeakObject::queryInterface( rType ); +} + +XTYPEPROVIDER_IMPL_10( ContentImplHelper, + lang::XTypeProvider, + lang::XServiceInfo, + lang::XComponent, + css::ucb::XContent, + css::ucb::XCommandProcessor, + beans::XPropertiesChangeNotifier, + css::ucb::XCommandInfoChangeNotifier, + beans::XPropertyContainer, + beans::XPropertySetInfoChangeNotifier, + container::XChild ); + +// virtual +sal_Bool SAL_CALL ContentImplHelper::supportsService( + const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +// virtual +void SAL_CALL ContentImplHelper::dispose() +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pImpl->m_pDisposeEventListeners && + m_pImpl->m_pDisposeEventListeners->getLength() ) + { + lang::EventObject aEvt; + aEvt.Source = static_cast< lang::XComponent * >( this ); + m_pImpl->m_pDisposeEventListeners->disposeAndClear( aEvt ); + } + + if ( m_pImpl->m_pContentEventListeners && + m_pImpl->m_pContentEventListeners->getLength() ) + { + lang::EventObject aEvt; + aEvt.Source = static_cast< css::ucb::XContent * >( this ); + m_pImpl->m_pContentEventListeners->disposeAndClear( aEvt ); + } + + if ( m_pImpl->m_pPropSetChangeListeners && + m_pImpl->m_pPropSetChangeListeners->getLength() ) + { + lang::EventObject aEvt; + aEvt.Source + = static_cast< beans::XPropertySetInfoChangeNotifier * >( this ); + m_pImpl->m_pPropSetChangeListeners->disposeAndClear( aEvt ); + } + + if ( m_pImpl->m_pCommandChangeListeners && + m_pImpl->m_pCommandChangeListeners->getLength() ) + { + lang::EventObject aEvt; + aEvt.Source = static_cast< css::ucb::XCommandInfoChangeNotifier * >( this ); + m_pImpl->m_pCommandChangeListeners->disposeAndClear( aEvt ); + } + + if ( m_pImpl->m_pPropertyChangeListeners ) + { + lang::EventObject aEvt; + aEvt.Source + = static_cast< beans::XPropertiesChangeNotifier * >( this ); + m_pImpl->m_pPropertyChangeListeners->disposeAndClear( aEvt ); + } +} + +// virtual +void SAL_CALL ContentImplHelper::addEventListener( + const uno::Reference< lang::XEventListener >& Listener ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pImpl->m_pDisposeEventListeners ) + m_pImpl->m_pDisposeEventListeners.reset( + new cppu::OInterfaceContainerHelper( m_aMutex )); + + m_pImpl->m_pDisposeEventListeners->addInterface( Listener ); +} + +// virtual +void SAL_CALL ContentImplHelper::removeEventListener( + const uno::Reference< lang::XEventListener >& Listener ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pImpl->m_pDisposeEventListeners ) + m_pImpl->m_pDisposeEventListeners->removeInterface( Listener ); +} + +// virtual +uno::Reference< css::ucb::XContentIdentifier > SAL_CALL +ContentImplHelper::getIdentifier() +{ + return m_xIdentifier; +} + +// virtual +void SAL_CALL ContentImplHelper::addContentEventListener( + const uno::Reference< css::ucb::XContentEventListener >& Listener ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pImpl->m_pContentEventListeners ) + m_pImpl->m_pContentEventListeners.reset( + new comphelper::OInterfaceContainerHelper3<css::ucb::XContentEventListener>( m_aMutex )); + + m_pImpl->m_pContentEventListeners->addInterface( Listener ); +} + +// virtual +void SAL_CALL ContentImplHelper::removeContentEventListener( + const uno::Reference< css::ucb::XContentEventListener >& Listener ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pImpl->m_pContentEventListeners ) + m_pImpl->m_pContentEventListeners->removeInterface( Listener ); +} + +// virtual +sal_Int32 SAL_CALL ContentImplHelper::createCommandIdentifier() +{ + osl::MutexGuard aGuard( m_aMutex ); + + // Just increase counter on every call to generate an identifier. + return ++m_nCommandId; +} + +// virtual +void SAL_CALL ContentImplHelper::addPropertiesChangeListener( + const uno::Sequence< OUString >& PropertyNames, + const uno::Reference< beans::XPropertiesChangeListener >& Listener ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pImpl->m_pPropertyChangeListeners ) + m_pImpl->m_pPropertyChangeListeners.reset( + new PropertyChangeListeners( m_aMutex )); + + if ( !PropertyNames.hasElements() ) + { + // Note: An empty sequence means a listener for "all" properties. + m_pImpl->m_pPropertyChangeListeners->addInterface( + OUString(), Listener ); + } + else + { + for ( const OUString& rName : PropertyNames ) + { + if ( !rName.isEmpty() ) + m_pImpl->m_pPropertyChangeListeners->addInterface( + rName, Listener ); + } + } +} + +// virtual +void SAL_CALL ContentImplHelper::removePropertiesChangeListener( + const uno::Sequence< OUString >& PropertyNames, + const uno::Reference< beans::XPropertiesChangeListener >& Listener ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pImpl->m_pPropertyChangeListeners ) + return; + + if ( !PropertyNames.hasElements() ) + { + // Note: An empty sequence means a listener for "all" properties. + m_pImpl->m_pPropertyChangeListeners->removeInterface( + OUString(), Listener ); + } + else + { + for ( const OUString& rName : PropertyNames ) + { + if ( !rName.isEmpty() ) + m_pImpl->m_pPropertyChangeListeners->removeInterface( + rName, Listener ); + } + } +} + +// virtual +void SAL_CALL ContentImplHelper::addCommandInfoChangeListener( + const uno::Reference< css::ucb::XCommandInfoChangeListener >& Listener ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pImpl->m_pCommandChangeListeners ) + m_pImpl->m_pCommandChangeListeners.reset( + new cppu::OInterfaceContainerHelper( m_aMutex )); + + m_pImpl->m_pCommandChangeListeners->addInterface( Listener ); +} + +// virtual +void SAL_CALL ContentImplHelper::removeCommandInfoChangeListener( + const uno::Reference< css::ucb::XCommandInfoChangeListener >& Listener ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pImpl->m_pCommandChangeListeners ) + m_pImpl->m_pCommandChangeListeners->removeInterface( Listener ); +} + +// virtual +void SAL_CALL ContentImplHelper::addProperty( + const OUString& Name, + sal_Int16 Attributes, + const uno::Any& DefaultValue ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + // Make sure a property with the requested name does not already + // exist in dynamic and static(!) properties. + + // @@@ Need real command environment here, but where to get it from? + // XPropertyContainer interface should be replaced by + // XCommandProcessor commands! + uno::Reference< css::ucb::XCommandEnvironment > xEnv; + + if ( getPropertySetInfo( xEnv )->hasPropertyByName( Name ) ) + { + // Property does already exist. + throw beans::PropertyExistException(); + } + + // Add a new dynamic property. + // Open/create persistent property set. + uno::Reference< css::ucb::XPersistentPropertySet > xSet( + getAdditionalPropertySet( true ) ); + + OSL_ENSURE( xSet.is(), + "ContentImplHelper::addProperty - No property set!" ); + + if ( !xSet.is() ) + return; + + uno::Reference< beans::XPropertyContainer > xContainer( + xSet, uno::UNO_QUERY ); + + OSL_ENSURE( + xContainer.is(), + "ContentImplHelper::addProperty - No property container!" ); + + if ( !xContainer.is() ) + return; + + // Property is always removable. + Attributes |= beans::PropertyAttribute::REMOVABLE; + + try + { + xContainer->addProperty( Name, Attributes, DefaultValue ); + } + catch ( beans::PropertyExistException const & ) + { + OSL_FAIL( "ContentImplHelper::addProperty - Exists!" ); + throw; + } + catch ( beans::IllegalTypeException const & ) + { + OSL_FAIL( "ContentImplHelper::addProperty - Wrong Type!" ); + throw; + } + catch ( lang::IllegalArgumentException const & ) + { + OSL_FAIL( "ContentImplHelper::addProperty - Illegal Arg!" ); + throw; + } + + // Success! + + if ( m_pImpl->m_xPropSetInfo.is() ) + { + // Info cached in propertyset info is invalid now! + m_pImpl->m_xPropSetInfo->reset(); + } + + // Notify propertyset info change listeners. + if ( m_pImpl->m_pPropSetChangeListeners && + m_pImpl->m_pPropSetChangeListeners->getLength() ) + { + beans::PropertySetInfoChangeEvent evt( + getXWeak(), + Name, + -1, // No handle available + beans::PropertySetInfoChange::PROPERTY_INSERTED ); + notifyPropertySetInfoChange( evt ); + } +} + +// virtual +void SAL_CALL ContentImplHelper::removeProperty( const OUString& Name ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + try + { + // @@@ Need real command environment here, but where to get it from? + // XPropertyContainer interface should be replaced by + // XCommandProcessor commands! + uno::Reference< css::ucb::XCommandEnvironment > xEnv; + + beans::Property aProp + = getPropertySetInfo( xEnv )->getPropertyByName( Name ); + + if ( !( aProp.Attributes & beans::PropertyAttribute::REMOVABLE ) ) + { + // Not removable! + throw beans::NotRemoveableException(); + } + } + catch ( beans::UnknownPropertyException const & ) + { + OSL_FAIL( "ContentImplHelper::removeProperty - Unknown!" ); + throw; + } + + // Try to remove property from dynamic property set. + // Open persistent property set, if exists. + uno::Reference< css::ucb::XPersistentPropertySet > xSet( + getAdditionalPropertySet( false ) ); + if ( !xSet.is() ) + return; + + uno::Reference< beans::XPropertyContainer > xContainer( + xSet, uno::UNO_QUERY ); + + OSL_ENSURE( + xContainer.is(), + "ContentImplHelper::removeProperty - No property container!" ); + + if ( !xContainer.is() ) + return; + + try + { + xContainer->removeProperty( Name ); + } + catch ( beans::UnknownPropertyException const & ) + { + OSL_FAIL( "ContentImplHelper::removeProperty - Unknown!" ); + throw; + } + catch ( beans::NotRemoveableException const & ) + { + OSL_FAIL( + "ContentImplHelper::removeProperty - Unremovable!" ); + throw; + } + + xContainer = nullptr; + + // Success! + + if ( !xSet->getPropertySetInfo()->getProperties().hasElements() ) + { + // Remove empty propertyset from registry. + uno::Reference< css::ucb::XPropertySetRegistry > + xReg = xSet->getRegistry(); + if ( xReg.is() ) + { + OUString aKey( xSet->getKey() ); + xSet = nullptr; + xReg->removePropertySet( aKey ); + } + } + + if ( m_pImpl->m_xPropSetInfo.is() ) + { + // Info cached in propertyset info is invalid now! + m_pImpl->m_xPropSetInfo->reset(); + } + + // Notify propertyset info change listeners. + if ( m_pImpl->m_pPropSetChangeListeners && + m_pImpl->m_pPropSetChangeListeners->getLength() ) + { + beans::PropertySetInfoChangeEvent evt( + getXWeak(), + Name, + -1, // No handle available + beans::PropertySetInfoChange::PROPERTY_REMOVED ); + notifyPropertySetInfoChange( evt ); + } +} + +// virtual +void SAL_CALL ContentImplHelper::addPropertySetInfoChangeListener( + const uno::Reference< beans::XPropertySetInfoChangeListener >& Listener ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pImpl->m_pPropSetChangeListeners ) + m_pImpl->m_pPropSetChangeListeners.reset( + new comphelper::OInterfaceContainerHelper3<beans::XPropertySetInfoChangeListener>( m_aMutex )); + + m_pImpl->m_pPropSetChangeListeners->addInterface( Listener ); +} + +// virtual +void SAL_CALL ContentImplHelper::removePropertySetInfoChangeListener( + const uno::Reference< beans::XPropertySetInfoChangeListener >& Listener ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pImpl->m_pPropSetChangeListeners ) + m_pImpl->m_pPropSetChangeListeners->removeInterface( Listener ); +} + +// virtual +uno::Reference< uno::XInterface > SAL_CALL ContentImplHelper::getParent() +{ + uno::Reference< uno::XInterface > xParent; + OUString aURL = getParentURL(); + + if ( !aURL.isEmpty() ) + { + uno::Reference< css::ucb::XContentIdentifier > xId( + new ContentIdentifier( aURL ) ); + try + { + xParent.set( m_xProvider->queryContent( xId ) ); + } + catch ( css::ucb::IllegalIdentifierException const & ) + { + } + } + + return xParent; +} + +// virtual +void SAL_CALL ContentImplHelper::setParent( + const uno::Reference< uno::XInterface >& ) +{ + throw lang::NoSupportException(); +} + +uno::Reference< css::ucb::XPersistentPropertySet > +ContentImplHelper::getAdditionalPropertySet( bool bCreate ) +{ + // Get propertyset from provider. + return m_xProvider->getAdditionalPropertySet( + m_xIdentifier->getContentIdentifier(), bCreate ); +} + +bool ContentImplHelper::renameAdditionalPropertySet( + const OUString& rOldKey, + const OUString& rNewKey ) +{ + return m_xProvider->renameAdditionalPropertySet( + rOldKey, rNewKey, true/*bRecursive*/ ); +} + +bool ContentImplHelper::copyAdditionalPropertySet( + const OUString& rSourceKey, + const OUString& rTargetKey ) +{ + return m_xProvider->copyAdditionalPropertySet( + rSourceKey, rTargetKey, true/*bRecursive*/ ); +} + +bool ContentImplHelper::removeAdditionalPropertySet() +{ + return m_xProvider->removeAdditionalPropertySet( + m_xIdentifier->getContentIdentifier(), true/*bRecursive*/ ); +} + +void ContentImplHelper::notifyPropertiesChange( + const uno::Sequence< beans::PropertyChangeEvent >& evt ) const +{ + if ( !m_pImpl->m_pPropertyChangeListeners ) + return; + + sal_Int32 nCount = evt.getLength(); + if ( !nCount ) + return; + + // First, notify listeners interested in changes of every property. + cppu::OInterfaceContainerHelper* pAllPropsContainer + = m_pImpl->m_pPropertyChangeListeners->getContainer( + OUString() ); + if ( pAllPropsContainer ) + { + cppu::OInterfaceIteratorHelper aIter( *pAllPropsContainer ); + while ( aIter.hasMoreElements() ) + { + // Propagate event. + static_cast< beans::XPropertiesChangeListener* >( + aIter.next())->propertiesChange( evt ); + } + } + + PropertiesEventListenerMap aListeners; + + for ( const beans::PropertyChangeEvent& rEvent : evt ) + { + const OUString& rName = rEvent.PropertyName; + + cppu::OInterfaceContainerHelper* pPropsContainer + = m_pImpl->m_pPropertyChangeListeners->getContainer( rName ); + if ( pPropsContainer ) + { + cppu::OInterfaceIteratorHelper aIter( *pPropsContainer ); + while ( aIter.hasMoreElements() ) + { + PropertyEventSequence* p = nullptr; + + beans::XPropertiesChangeListener* pListener = + static_cast< beans::XPropertiesChangeListener * >( + aIter.next() ); + PropertiesEventListenerMap::iterator it = + aListeners.find( pListener ); + if ( it == aListeners.end() ) + { + // Not in map - create and insert new entry. + p = &aListeners.emplace( pListener, PropertyEventSequence(nCount)).first->second; + } + else + p = &it->second; + + if ( p ) + p->append( rEvent ); + } + } + } + + // Notify listeners. + PropertiesEventListenerMap::iterator it = aListeners.begin(); + while ( !aListeners.empty() ) + { + beans::XPropertiesChangeListener* pListener = + static_cast< beans::XPropertiesChangeListener * >( (*it).first ); + PropertyEventSequence pSeq = std::move(it->second); + + // Remove current element. + aListeners.erase( it ); + + // Propagate event. + pListener->propertiesChange( pSeq.getEvents() ); + + it = aListeners.begin(); + } +} + +void ContentImplHelper::notifyPropertySetInfoChange( + const beans::PropertySetInfoChangeEvent& evt ) const +{ + if ( !m_pImpl->m_pPropSetChangeListeners ) + return; + + // Notify event listeners. + m_pImpl->m_pPropSetChangeListeners->notifyEach( &beans::XPropertySetInfoChangeListener::propertySetInfoChange, evt ); +} + +void ContentImplHelper::notifyContentEvent( + const css::ucb::ContentEvent& evt ) const +{ + if ( !m_pImpl->m_pContentEventListeners ) + return; + + // Notify event listeners. + m_pImpl->m_pContentEventListeners->notifyEach( &css::ucb::XContentEventListener::contentEvent, evt); +} + +void ContentImplHelper::inserted() +{ + // Content is not yet registered at provider. + m_xProvider->registerNewContent( this ); + + // If the parent content is currently not instantiated, there can be + // no listeners interested in changes ;-) + + rtl::Reference< ContentImplHelper > xParent + = m_xProvider->queryExistingContent( getParentURL() ); + + if ( xParent.is() ) + { + css::ucb::ContentEvent aEvt( + xParent->getXWeak(), // Source + css::ucb::ContentAction::INSERTED, // Action + this, // Content + xParent->getIdentifier() ); // Id + xParent->notifyContentEvent( aEvt ); + } +} + +void ContentImplHelper::deleted() +{ + uno::Reference< css::ucb::XContent > xThis = this; + + rtl::Reference< ContentImplHelper > xParent + = m_xProvider->queryExistingContent( getParentURL() ); + + if ( xParent.is() ) + { + // Let parent notify "REMOVED" event. + css::ucb::ContentEvent aEvt( + xParent->getXWeak(), + css::ucb::ContentAction::REMOVED, + this, + xParent->getIdentifier() ); + xParent->notifyContentEvent( aEvt ); + } + + // Notify "DELETED" event. + css::ucb::ContentEvent aEvt1( + getXWeak(), + css::ucb::ContentAction::DELETED, + this, + getIdentifier() ); + notifyContentEvent( aEvt1 ); + + m_xProvider->removeContent( this ); +} + +bool ContentImplHelper::exchange( + const uno::Reference< css::ucb::XContentIdentifier >& rNewId ) +{ + uno::Reference< css::ucb::XContent > xThis = this; + + osl::ClearableMutexGuard aGuard( m_aMutex ); + + rtl::Reference< ContentImplHelper > xContent + = m_xProvider->queryExistingContent( rNewId ); + if ( xContent.is() ) + { + // @@@ + // Big trouble. Another object with the new identity exists. + // How shall I mutate to / merge with the other object? + return false; + } + + uno::Reference< css::ucb::XContentIdentifier > xOldId + = getIdentifier(); + + // Re-insert at provider. + m_xProvider->removeContent( this ); + m_xIdentifier = rNewId; + m_xProvider->registerNewContent( this ); + + aGuard.clear(); + + // Notify "EXCHANGED" event. + css::ucb::ContentEvent aEvt( + getXWeak(), + css::ucb::ContentAction::EXCHANGED, + this, + xOldId ); + notifyContentEvent( aEvt ); + return true; +} + +uno::Reference< css::ucb::XCommandInfo > +ContentImplHelper::getCommandInfo( + const uno::Reference< css::ucb::XCommandEnvironment > & xEnv, + bool bCache ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pImpl->m_xCommandsInfo.is() ) + m_pImpl->m_xCommandsInfo + = new CommandProcessorInfo( xEnv, this ); + else if ( !bCache ) + m_pImpl->m_xCommandsInfo->reset(); + + return m_pImpl->m_xCommandsInfo; +} + +uno::Reference< beans::XPropertySetInfo > +ContentImplHelper::getPropertySetInfo( + const uno::Reference< css::ucb::XCommandEnvironment > & xEnv, + bool bCache ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pImpl->m_xPropSetInfo.is() ) + m_pImpl->m_xPropSetInfo + = new PropertySetInfo( xEnv, this ); + else if ( !bCache ) + m_pImpl->m_xPropSetInfo->reset(); + + return m_pImpl->m_xPropSetInfo; +} + +} // namespace ucbhelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/contentidentifier.cxx b/ucbhelper/source/provider/contentidentifier.cxx new file mode 100644 index 0000000000..2a5da953d9 --- /dev/null +++ b/ucbhelper/source/provider/contentidentifier.cxx @@ -0,0 +1,91 @@ +/* -*- 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 <ucbhelper/contentidentifier.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::ucb; + + +namespace ucbhelper +{ + +struct ContentIdentifier_Impl +{ + OUString m_aContentId; + OUString m_aProviderScheme; + + explicit ContentIdentifier_Impl( const OUString& rURL ); +}; + + +// ContentIdentifier_Impl Implementation. + + +ContentIdentifier_Impl::ContentIdentifier_Impl(const OUString& rURL ) +{ + // Normalize URL scheme ( it's case insensitive ). + + // The content provider scheme is the part before the first ':' + // within the content id. + sal_Int32 nPos = rURL.indexOf( ':' ); + if ( nPos != -1 ) + { + OUString aScheme( rURL.copy( 0, nPos ) ); + m_aProviderScheme = aScheme.toAsciiLowerCase(); + m_aContentId = rURL.replaceAt( 0, nPos, aScheme ); + } +} + + +// ContentIdentifier Implementation. + + +ContentIdentifier::ContentIdentifier( const OUString& rURL ) + : m_pImpl( new ContentIdentifier_Impl( rURL ) ) +{ +} + + +// virtual +ContentIdentifier::~ContentIdentifier() +{ +} + + +// XContentIdentifier methods. + + +// virtual +OUString SAL_CALL ContentIdentifier::getContentIdentifier() +{ + return m_pImpl->m_aContentId; +} + + +// virtual +OUString SAL_CALL ContentIdentifier::getContentProviderScheme() +{ + return m_pImpl->m_aProviderScheme; +} + +} /* namespace ucbhelper */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/contentinfo.cxx b/ucbhelper/source/provider/contentinfo.cxx new file mode 100644 index 0000000000..1e513604eb --- /dev/null +++ b/ucbhelper/source/provider/contentinfo.cxx @@ -0,0 +1,318 @@ +/* -*- 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 <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/ucb/UnsupportedCommandException.hpp> +#include <com/sun/star/ucb/XPersistentPropertySet.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> + +#include <ucbhelper/contenthelper.hxx> +#include <utility> +#include "contentinfo.hxx" + +using namespace com::sun::star; + + +// PropertySetInfo Implementation. + + +namespace ucbhelper { + +PropertySetInfo::PropertySetInfo( + uno::Reference< css::ucb::XCommandEnvironment > xEnv, + ContentImplHelper* pContent ) +: m_xEnv(std::move( xEnv )), + m_pContent( pContent ) +{ +} + + +// virtual +PropertySetInfo::~PropertySetInfo() +{ +} + + +// XPropertySetInfo methods. + + +// virtual +uno::Sequence< beans::Property > SAL_CALL PropertySetInfo::getProperties() +{ + std::unique_lock aGuard( m_aMutex ); + return getPropertiesImpl(); +} + +const uno::Sequence< beans::Property > & PropertySetInfo::getPropertiesImpl() +{ + if ( m_xProps ) + return *m_xProps; + + // Get info for core ( native) properties. + + try + { + m_xProps = m_pContent->getProperties( m_xEnv ); + } + catch ( uno::RuntimeException const & ) + { + throw; + } + catch ( uno::Exception const & ) + { + m_xProps.emplace(); + } + + // Get info for additional properties. + + uno::Reference< css::ucb::XPersistentPropertySet > + xSet ( m_pContent->getAdditionalPropertySet( false ) ); + + if ( xSet.is() ) + { + // Get property set info. + uno::Reference< beans::XPropertySetInfo > xInfo( + xSet->getPropertySetInfo() ); + if ( xInfo.is() ) + { + const uno::Sequence< beans::Property >& rAddProps + = xInfo->getProperties(); + sal_Int32 nAddProps = rAddProps.getLength(); + if ( nAddProps > 0 ) + { + sal_Int32 nPos = m_xProps->getLength(); + m_xProps->realloc( nPos + nAddProps ); + + std::copy(rAddProps.begin(), rAddProps.end(), + std::next(m_xProps->getArray(), nPos)); + } + } + } + return *m_xProps; +} + + +// virtual +beans::Property SAL_CALL PropertySetInfo::getPropertyByName( + const OUString& aName ) +{ + beans::Property aProp; + if ( queryProperty( aName, aProp ) ) + return aProp; + + throw beans::UnknownPropertyException(aName); +} + + +// virtual +sal_Bool SAL_CALL PropertySetInfo::hasPropertyByName( + const OUString& Name ) +{ + beans::Property aProp; + return queryProperty( Name, aProp ); +} + + +// Non-Interface methods. + + +void PropertySetInfo::reset() +{ + std::unique_lock aGuard( m_aMutex ); + m_xProps.reset(); +} + + +bool PropertySetInfo::queryProperty( + std::u16string_view rName, beans::Property& rProp ) +{ + std::unique_lock aGuard( m_aMutex ); + + getPropertiesImpl(); + + const beans::Property* pProps = m_xProps->getConstArray(); + sal_Int32 nCount = m_xProps->getLength(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const beans::Property& rCurrProp = pProps[ n ]; + if ( rCurrProp.Name == rName ) + { + rProp = rCurrProp; + return true; + } + } + + return false; +} + + +// CommandProcessorInfo Implementation. + + +CommandProcessorInfo::CommandProcessorInfo( + uno::Reference< css::ucb::XCommandEnvironment > xEnv, + ContentImplHelper* pContent ) +: m_xEnv(std::move( xEnv )), + m_pContent( pContent ) +{ +} + + +// virtual +CommandProcessorInfo::~CommandProcessorInfo() +{ +} + + +// XCommandInfo methods. + + +// virtual +uno::Sequence< css::ucb::CommandInfo > SAL_CALL CommandProcessorInfo::getCommands() +{ + std::unique_lock aGuard( m_aMutex ); + return getCommandsImpl(); +} + +const uno::Sequence< css::ucb::CommandInfo > & CommandProcessorInfo::getCommandsImpl() +{ + if ( m_xCommands ) + return *m_xCommands; + + // Get info for commands. + + try + { + m_xCommands = m_pContent->getCommands( m_xEnv ); + } + catch ( uno::RuntimeException const & ) + { + throw; + } + catch ( uno::Exception const & ) + { + m_xCommands.emplace(); + } + return *m_xCommands; +} + + +// virtual +css::ucb::CommandInfo SAL_CALL +CommandProcessorInfo::getCommandInfoByName( + const OUString& Name ) +{ + css::ucb::CommandInfo aInfo; + if ( queryCommand( Name, aInfo ) ) + return aInfo; + + throw css::ucb::UnsupportedCommandException(); +} + + +// virtual +css::ucb::CommandInfo SAL_CALL +CommandProcessorInfo::getCommandInfoByHandle( sal_Int32 Handle ) +{ + css::ucb::CommandInfo aInfo; + if ( queryCommand( Handle, aInfo ) ) + return aInfo; + + throw css::ucb::UnsupportedCommandException(); +} + + +// virtual +sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByName( + const OUString& Name ) +{ + css::ucb::CommandInfo aInfo; + return queryCommand( Name, aInfo ); +} + + +// virtual +sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByHandle( sal_Int32 Handle ) +{ + css::ucb::CommandInfo aInfo; + return queryCommand( Handle, aInfo ); +} + + +// Non-Interface methods. + + +void CommandProcessorInfo::reset() +{ + std::unique_lock aGuard( m_aMutex ); + m_xCommands.reset(); +} + + +bool CommandProcessorInfo::queryCommand( + std::u16string_view rName, + css::ucb::CommandInfo& rCommand ) +{ + std::unique_lock aGuard( m_aMutex ); + + getCommandsImpl(); + + const css::ucb::CommandInfo* pCommands + = m_xCommands->getConstArray(); + sal_Int32 nCount = m_xCommands->getLength(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const css::ucb::CommandInfo& rCurrCommand = pCommands[ n ]; + if ( rCurrCommand.Name == rName ) + { + rCommand = rCurrCommand; + return true; + } + } + + return false; +} + + +bool CommandProcessorInfo::queryCommand( + sal_Int32 nHandle, + css::ucb::CommandInfo& rCommand ) +{ + std::unique_lock aGuard( m_aMutex ); + + getCommandsImpl(); + + const css::ucb::CommandInfo* pCommands = m_xCommands->getConstArray(); + sal_Int32 nCount = m_xCommands->getLength(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const css::ucb::CommandInfo& rCurrCommand = pCommands[ n ]; + if ( rCurrCommand.Handle == nHandle ) + { + rCommand = rCurrCommand; + return true; + } + } + + return false; +} + +} // namespace ucbhelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/contentinfo.hxx b/ucbhelper/source/provider/contentinfo.hxx new file mode 100644 index 0000000000..b24a291ccb --- /dev/null +++ b/ucbhelper/source/provider/contentinfo.hxx @@ -0,0 +1,119 @@ +/* -*- 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 . + */ + +#ifndef UCBHELPER_SOURCE_PROVIDER_CONTENTINFO_HXX +#define UCBHELPER_SOURCE_PROVIDER_CONTENTINFO_HXX + +#include <optional> +#include <com/sun/star/ucb/XCommandInfo.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <cppuhelper/implbase.hxx> + +#include <mutex> + +namespace com::sun::star::ucb { class XCommandEnvironment; } + +namespace ucbhelper { + + + + +class ContentImplHelper; + +/** + * This class provides a propertyset info ( the complete implementation of + * the interface XPropertySetInfo ) for an object derived from class + * ucb::ContentImplHelper. The implementation takes care about Additional + * Core Properties that may have been added to the content. + */ +class PropertySetInfo : + public cppu::WeakImplHelper<css::beans::XPropertySetInfo> +{ + css::uno::Reference< css::ucb::XCommandEnvironment > + m_xEnv; + std::optional<css::uno::Sequence< css::beans::Property >> + m_xProps; + std::mutex m_aMutex; + ContentImplHelper* m_pContent; + +private: + bool queryProperty( std::u16string_view rName, + css::beans::Property& rProp ); + const css::uno::Sequence< css::beans::Property > & getPropertiesImpl(); + +public: + PropertySetInfo( css::uno::Reference< css::ucb::XCommandEnvironment > xEnv, + ContentImplHelper* pContent ); + virtual ~PropertySetInfo() override; + + // XPropertySetInfo + virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties() override; + virtual css::beans::Property SAL_CALL getPropertyByName( const OUString& aName ) override; + virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override; + + // Non-Interface methods. + void reset(); +}; + + + + +/** + * This class provides a command info ( the complete implementation of + * the interface XCommandInfo ) for an object derived from class + * ucb::ContentImplHelper. + */ +class CommandProcessorInfo : + public cppu::WeakImplHelper<css::ucb::XCommandInfo> +{ + css::uno::Reference< css::ucb::XCommandEnvironment > + m_xEnv; + std::optional<css::uno::Sequence< css::ucb::CommandInfo >> + m_xCommands; + std::mutex m_aMutex; + ContentImplHelper* m_pContent; + +private: + bool queryCommand( std::u16string_view rName, + css::ucb::CommandInfo& rCommand ); + bool queryCommand( sal_Int32 nHandle, + css::ucb::CommandInfo& rCommand ); + const css::uno::Sequence< css::ucb::CommandInfo > & getCommandsImpl(); + +public: + CommandProcessorInfo( css::uno::Reference< css::ucb::XCommandEnvironment > xEnv, + ContentImplHelper* pContent ); + virtual ~CommandProcessorInfo() override; + + // XCommandInfo + virtual css::uno::Sequence< css::ucb::CommandInfo > SAL_CALL getCommands() override; + virtual css::ucb::CommandInfo SAL_CALL getCommandInfoByName( const OUString& Name ) override; + virtual css::ucb::CommandInfo SAL_CALL getCommandInfoByHandle( sal_Int32 Handle ) override; + virtual sal_Bool SAL_CALL hasCommandByName( const OUString& Name ) override; + virtual sal_Bool SAL_CALL hasCommandByHandle( sal_Int32 Handle ) override; + + // Non-Interface methods. + void reset(); +}; + +} // namespace ucbhelper + +#endif /* ! UCBHELPER_SOURCE_PROVIDER_CONTENTINFO_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/interactionrequest.cxx b/ucbhelper/source/provider/interactionrequest.cxx new file mode 100644 index 0000000000..0ac7ec9499 --- /dev/null +++ b/ucbhelper/source/provider/interactionrequest.cxx @@ -0,0 +1,626 @@ +/* -*- 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 <ucbhelper/interactionrequest.hxx> + +#include <rtl/ref.hxx> +#include <osl/diagnose.h> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <utility> + +using namespace com::sun::star; +using namespace ucbhelper; + + +// InteractionRequest Implementation. + + +namespace ucbhelper +{ + +struct InteractionRequest_Impl +{ + rtl::Reference< InteractionContinuation > m_xSelection; + css::uno::Any m_aRequest; + css::uno::Sequence< + css::uno::Reference< + css::task::XInteractionContinuation > > m_aContinuations; + + InteractionRequest_Impl() {} + explicit InteractionRequest_Impl( uno::Any aRequest ) + : m_aRequest(std::move( aRequest )) {} +}; + +} + + +InteractionRequest::InteractionRequest() +: m_pImpl( new InteractionRequest_Impl ) +{ +} + + +InteractionRequest::InteractionRequest( const uno::Any & rRequest ) +: m_pImpl( new InteractionRequest_Impl( rRequest ) ) +{ +} + + +// virtual +InteractionRequest::~InteractionRequest() +{ +} + + +void InteractionRequest::setRequest( const uno::Any & rRequest ) +{ + m_pImpl->m_aRequest = rRequest; +} + + +void InteractionRequest::setContinuations( + const uno::Sequence< uno::Reference< + task::XInteractionContinuation > > & rContinuations ) +{ + m_pImpl->m_aContinuations = rContinuations; +} + + +rtl::Reference< InteractionContinuation > const & +InteractionRequest::getSelection() const +{ + return m_pImpl->m_xSelection; +} + + +void InteractionRequest::setSelection( + const rtl::Reference< InteractionContinuation > & rxSelection ) +{ + m_pImpl->m_xSelection = rxSelection; +} + + +// XInterface methods. + + +// XInteractionRequest methods. + + +// virtual +uno::Any SAL_CALL InteractionRequest::getRequest() +{ + return m_pImpl->m_aRequest; +} + + +// virtual +uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL +InteractionRequest::getContinuations() +{ + return m_pImpl->m_aContinuations; +} + + +// InteractionContinuation Implementation. + + +InteractionContinuation::InteractionContinuation( + InteractionRequest * pRequest ) +: m_pRequest( pRequest ) +{ +} + + +// virtual +InteractionContinuation::~InteractionContinuation() +{ +} + + +void InteractionContinuation::recordSelection() +{ + m_pRequest->setSelection( this ); +} + + +// InteractionAbort Implementation. + + +// XInterface methods. + + +// virtual +uno::Any SAL_CALL +InteractionAbort::queryInterface( const uno::Type & rType ) +{ + uno::Any aRet = cppu::queryInterface( rType, + static_cast< lang::XTypeProvider * >( this ), + static_cast< task::XInteractionContinuation * >( this ), + static_cast< task::XInteractionAbort * >( this ) ); + + return aRet.hasValue() + ? aRet : InteractionContinuation::queryInterface( rType ); +} + + +// XTypeProvider methods. + + +// virtual +uno::Sequence< sal_Int8 > SAL_CALL InteractionAbort::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + + +// virtual +uno::Sequence< uno::Type > SAL_CALL InteractionAbort::getTypes() +{ + static cppu::OTypeCollection s_aCollection( + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<task::XInteractionAbort>::get() ); + + return s_aCollection.getTypes(); +} + + +// XInteractionContinuation methods. + + +// virtual +void SAL_CALL InteractionAbort::select() +{ + recordSelection(); +} + + +// InteractionRetry Implementation. + + +// XInterface methods. + + +// virtual +uno::Any SAL_CALL +InteractionRetry::queryInterface( const uno::Type & rType ) +{ + uno::Any aRet = cppu::queryInterface( rType, + static_cast< lang::XTypeProvider * >( this ), + static_cast< task::XInteractionContinuation * >( this ), + static_cast< task::XInteractionRetry * >( this ) ); + + return aRet.hasValue() + ? aRet : InteractionContinuation::queryInterface( rType ); +} + + +// XTypeProvider methods. + + +// virtual +uno::Sequence< sal_Int8 > SAL_CALL InteractionRetry::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + + +// virtual +uno::Sequence< uno::Type > SAL_CALL InteractionRetry::getTypes() +{ + static cppu::OTypeCollection s_aCollection( + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<task::XInteractionRetry>::get() ); + + return s_aCollection.getTypes(); +} + + +// XInteractionContinuation methods. + + +// virtual +void SAL_CALL InteractionRetry::select() +{ + recordSelection(); +} + + +// InteractionApprove Implementation. + + +// XInterface methods. + + +// virtual +uno::Any SAL_CALL +InteractionApprove::queryInterface( const uno::Type & rType ) +{ + uno::Any aRet = cppu::queryInterface( rType, + static_cast< lang::XTypeProvider * >( this ), + static_cast< task::XInteractionContinuation * >( this ), + static_cast< task::XInteractionApprove * >( this ) ); + + return aRet.hasValue() + ? aRet : InteractionContinuation::queryInterface( rType ); +} + + +// XTypeProvider methods. + + +// virtual +uno::Sequence< sal_Int8 > SAL_CALL InteractionApprove::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + + +// virtual +uno::Sequence< uno::Type > SAL_CALL InteractionApprove::getTypes() +{ + static cppu::OTypeCollection s_aCollection( + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<task::XInteractionApprove>::get() ); + + return s_aCollection.getTypes(); +} + + +// XInteractionContinuation methods. + + +// virtual +void SAL_CALL InteractionApprove::select() +{ + recordSelection(); +} + + +// InteractionDisapprove Implementation. + + +// XInterface methods. + + +// virtual +uno::Any SAL_CALL +InteractionDisapprove::queryInterface( const uno::Type & rType ) +{ + uno::Any aRet = cppu::queryInterface( rType, + static_cast< lang::XTypeProvider * >( this ), + static_cast< task::XInteractionContinuation * >( this ), + static_cast< task::XInteractionDisapprove * >( this ) ); + + return aRet.hasValue() + ? aRet : InteractionContinuation::queryInterface( rType ); +} + + +// XTypeProvider methods. + + +// virtual +uno::Sequence< sal_Int8 > SAL_CALL InteractionDisapprove::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + + +// virtual +uno::Sequence< uno::Type > SAL_CALL InteractionDisapprove::getTypes() +{ + static cppu::OTypeCollection s_aCollection( + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<task::XInteractionDisapprove>::get() ); + + return s_aCollection.getTypes(); +} + + +// XInteractionContinuation methods. + + +// virtual +void SAL_CALL InteractionDisapprove::select() +{ + recordSelection(); +} + + +// InteractionSupplyAuthentication Implementation. + + +// XInterface methods. + + +// virtual +uno::Any SAL_CALL +InteractionSupplyAuthentication::queryInterface( const uno::Type & rType ) +{ + uno::Any aRet = cppu::queryInterface( rType, + static_cast< lang::XTypeProvider * >( this ), + static_cast< task::XInteractionContinuation * >( this ), + static_cast< ucb::XInteractionSupplyAuthentication * >( this ), + static_cast< ucb::XInteractionSupplyAuthentication2 * >( this )); + + return aRet.hasValue() + ? aRet : InteractionContinuation::queryInterface( rType ); +} + + +// XTypeProvider methods. + + +// virtual +uno::Sequence< sal_Int8 > SAL_CALL +InteractionSupplyAuthentication::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + + +// virtual +uno::Sequence< uno::Type > SAL_CALL InteractionSupplyAuthentication::getTypes() +{ + static cppu::OTypeCollection s_aCollection( + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<ucb::XInteractionSupplyAuthentication2>::get() ); + + return s_aCollection.getTypes(); +} + + +// XInteractionContinuation methods. + + +// virtual +void SAL_CALL InteractionSupplyAuthentication::select() +{ + recordSelection(); +} + + +// XInteractionSupplyAuthentication methods. + + +// virtual +sal_Bool SAL_CALL +InteractionSupplyAuthentication::canSetRealm() +{ + return m_bCanSetRealm; +} + + +// virtual +void SAL_CALL +InteractionSupplyAuthentication::setRealm( const OUString& Realm ) +{ + OSL_ENSURE( m_bCanSetPassword, + "InteractionSupplyAuthentication::setRealm - Not supported!" ); + + if ( m_bCanSetRealm ) + m_aRealm = Realm; +} + + +// virtual +sal_Bool SAL_CALL +InteractionSupplyAuthentication::canSetUserName() +{ + return m_bCanSetUserName; +} + + +// virtual +void SAL_CALL +InteractionSupplyAuthentication::setUserName( const OUString& UserName ) +{ + OSL_ENSURE( m_bCanSetUserName, + "InteractionSupplyAuthentication::setUserName - Not supported!" ); + + if ( m_bCanSetUserName ) + m_aUserName = UserName; +} + + +// virtual +sal_Bool SAL_CALL +InteractionSupplyAuthentication::canSetPassword() +{ + return m_bCanSetPassword; +} + + +// virtual +void SAL_CALL +InteractionSupplyAuthentication::setPassword( const OUString& Password ) +{ + OSL_ENSURE( m_bCanSetPassword, + "InteractionSupplyAuthentication::setPassword - Not supported!" ); + + if ( m_bCanSetPassword ) + m_aPassword = Password; +} + + +// virtual +uno::Sequence< ucb::RememberAuthentication > SAL_CALL +InteractionSupplyAuthentication::getRememberPasswordModes( + ucb::RememberAuthentication& Default ) +{ + Default = m_eDefaultRememberPasswordMode; + return m_aRememberPasswordModes; +} + + +// virtual +void SAL_CALL +InteractionSupplyAuthentication::setRememberPassword( + ucb::RememberAuthentication Remember ) +{ + m_eRememberPasswordMode = Remember; +} + + +// virtual +sal_Bool SAL_CALL +InteractionSupplyAuthentication::canSetAccount() +{ + return m_bCanSetAccount; +} + + +// virtual +void SAL_CALL +InteractionSupplyAuthentication::setAccount( const OUString& /*Account*/ ) +{ + OSL_ENSURE( m_bCanSetAccount, + "InteractionSupplyAuthentication::setAccount - Not supported!" ); +} + + +// virtual +uno::Sequence< ucb::RememberAuthentication > SAL_CALL +InteractionSupplyAuthentication::getRememberAccountModes( + ucb::RememberAuthentication& Default ) +{ + Default = m_eDefaultRememberAccountMode; + return m_aRememberAccountModes; +} + + +// virtual +void SAL_CALL InteractionSupplyAuthentication::setRememberAccount( + ucb::RememberAuthentication ) +{ +} + + +// XInteractionSupplyAuthentication2 methods. + + +// virtual +sal_Bool SAL_CALL +InteractionSupplyAuthentication::canUseSystemCredentials( + sal_Bool& Default ) +{ + Default = false; + return m_bCanUseSystemCredentials; +} + + +// virtual +void SAL_CALL InteractionSupplyAuthentication::setUseSystemCredentials( + sal_Bool UseSystemCredentials ) +{ + if ( m_bCanUseSystemCredentials ) + m_bUseSystemCredentials = UseSystemCredentials; +} + + +// InteractionReplaceExistingData Implementation. + + +// XInterface methods. + + +// virtual +uno::Any SAL_CALL +InteractionReplaceExistingData::queryInterface( const uno::Type & rType ) +{ + uno::Any aRet = cppu::queryInterface( rType, + static_cast< lang::XTypeProvider * >( this ), + static_cast< task::XInteractionContinuation * >( this ), + static_cast< ucb::XInteractionReplaceExistingData * >( this ) ); + + return aRet.hasValue() + ? aRet : InteractionContinuation::queryInterface( rType ); +} + + +// XTypeProvider methods. + + +// virtual +uno::Sequence< sal_Int8 > SAL_CALL +InteractionReplaceExistingData::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + + +// virtual +uno::Sequence< uno::Type > SAL_CALL InteractionReplaceExistingData::getTypes() +{ + static cppu::OTypeCollection s_aCollection( + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<ucb::XInteractionReplaceExistingData>::get() ); + + return s_aCollection.getTypes(); +} + + +// XInteractionContinuation methods. + + +// virtual +void SAL_CALL InteractionReplaceExistingData::select() +{ + recordSelection(); +} + +// InteractionAuthFallback Implementation + +// XInterface methods. + +// virtual +uno::Any SAL_CALL +InteractionAuthFallback::queryInterface( const uno::Type & rType ) +{ + uno::Any aRet = cppu::queryInterface( rType, + static_cast< task::XInteractionContinuation * >( this ), + static_cast< ucb::XInteractionAuthFallback * >( this )); + + return aRet.hasValue() + ? aRet : InteractionContinuation::queryInterface( rType ); +} + +// XInteractionContinuation methods. + +// virtual +void SAL_CALL InteractionAuthFallback::select() +{ + recordSelection(); +} + +// XInteractionAuthFallback methods + +// virtual +void SAL_CALL InteractionAuthFallback::setCode( const OUString& code ) +{ + m_aCode = code; +} + +const OUString& InteractionAuthFallback::getCode() const +{ + return m_aCode; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/propertyvalueset.cxx b/ucbhelper/source/provider/propertyvalueset.cxx new file mode 100644 index 0000000000..b019d3b9c8 --- /dev/null +++ b/ucbhelper/source/provider/propertyvalueset.cxx @@ -0,0 +1,680 @@ +/* -*- 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 <vector> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/script/CannotConvertException.hpp> +#include <com/sun/star/script/Converter.hpp> + +#include <osl/diagnose.h> +#include <ucbhelper/propertyvalueset.hxx> +#include <o3tl/safeint.hxx> +#include <o3tl/typed_flags_set.hxx> + +using namespace com::sun::star::beans; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::lang; +using namespace com::sun::star::script; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::uno; +using namespace com::sun::star::util; + +enum class PropsSet { + NONE = 0x00000000, + String = 0x00000001, + Boolean = 0x00000002, + Byte = 0x00000004, + Short = 0x00000008, + Int = 0x00000010, + Long = 0x00000020, + Float = 0x00000040, + Double = 0x00000080, + Bytes = 0x00000100, + Date = 0x00000200, + Time = 0x00000400, + Timestamp = 0x00000800, + BinaryStream = 0x00001000, + CharacterStream = 0x00002000, + Ref = 0x00004000, + Blob = 0x00008000, + Clob = 0x00010000, + Array = 0x00020000, + Object = 0x00040000 +}; +namespace o3tl { + template<> struct typed_flags<PropsSet> : is_typed_flags<PropsSet, 0x0007ffff> {}; +} + +namespace ucbhelper_impl +{ + + +struct PropertyValue +{ + OUString sPropertyName; + + PropsSet nPropsSet; + PropsSet nOrigValue; + + OUString aString; // getString + bool bBoolean; // getBoolean + sal_Int8 nByte; // getByte + sal_Int16 nShort; // getShort + sal_Int32 nInt; // getInt + sal_Int64 nLong; // getLong + float nFloat; // getFloat + double nDouble; // getDouble + + Sequence< sal_Int8 > aBytes; // getBytes + Date aDate; // getDate + Time aTime; // getTime + DateTime aTimestamp; // getTimestamp + Reference< XInputStream > xBinaryStream; // getBinaryStream + Reference< XInputStream > xCharacterStream; // getCharacterStream + Reference< XRef > xRef; // getRef + Reference< XBlob > xBlob; // getBlob + Reference< XClob > xClob; // getClob + Reference< XArray > xArray; // getArray + Any aObject; // getObject + + PropertyValue() + : nPropsSet( PropsSet::NONE ), nOrigValue( PropsSet::NONE ), + bBoolean(false), + nByte(0), + nShort(0), + nInt(0), + nLong(0), + nFloat(0.0), + nDouble(0.0) + {} +}; +} // namespace ucbhelper_impl + +using namespace ucbhelper_impl; + +namespace ucbhelper +{ + +class PropertyValues : public std::vector< ucbhelper_impl::PropertyValue > {}; + +} // namespace ucbhelper + + +namespace ucbhelper { + + +// PropertyValueSet Implementation. + + +PropertyValueSet::PropertyValueSet( + const Reference< XComponentContext >& rxContext ) +: m_xContext( rxContext ), + m_pValues( new PropertyValues ), + m_bWasNull( false ), + m_bTriedToGetTypeConverter( false ) + +{ +} + + +// virtual +PropertyValueSet::~PropertyValueSet() +{ +} + + +// XRow methods. + + +template <class T, T ucbhelper_impl::PropertyValue::*_member_name_> +T PropertyValueSet::getValue(PropsSet nTypeName, sal_Int32 columnIndex) +{ + std::unique_lock aGuard( m_aMutex ); + + T aValue {}; /* default ctor */ + + m_bWasNull = true; + + if ( ( columnIndex < 1 ) || ( o3tl::make_unsigned(columnIndex) > m_pValues->size() ) ) + { + OSL_FAIL( "PropertyValueSet - index out of range!" ); + return aValue; + } + ucbhelper_impl::PropertyValue& rValue = (*m_pValues)[ columnIndex - 1 ]; + + if ( rValue.nOrigValue == PropsSet::NONE ) + return aValue; + + if ( rValue.nPropsSet & nTypeName ) + { + /* Values is present natively... */ + aValue = rValue.*_member_name_; + m_bWasNull = false; + return aValue; + } + + if ( !(rValue.nPropsSet & PropsSet::Object) ) + { + /* Value is not (yet) available as Any. Create it. */ + getObject( columnIndex, Reference< XNameAccess >() ); + } + + if ( rValue.nPropsSet & PropsSet::Object ) + { + /* Value is available as Any. */ + + if ( rValue.aObject.hasValue() ) + { + /* Try to convert into native value. */ + if ( rValue.aObject >>= aValue ) + { + rValue.*_member_name_ = aValue; + rValue.nPropsSet |= nTypeName; + m_bWasNull = false; + } + else + { + /* Last chance. Try type converter service... */ + + Reference< XTypeConverter > xConverter = getTypeConverter(); + if ( xConverter.is() ) + { + try + { + Any aConvAny = xConverter->convertTo( + rValue.aObject, + cppu::UnoType<T>::get() ); + + if ( aConvAny >>= aValue ) + { + rValue.*_member_name_ = aValue; + rValue.nPropsSet |= nTypeName; + m_bWasNull = false; + } + } + catch (const IllegalArgumentException&) + { + } + catch (const CannotConvertException&) + { + } + } + } + } + } + + return aValue; +} + + +// virtual +sal_Bool SAL_CALL PropertyValueSet::wasNull() +{ + // This method can not be implemented correctly!!! Imagine different + // threads doing a getXYZ - wasNull calling sequence on the same + // implementation object... + return m_bWasNull; +} + + +// virtual +OUString SAL_CALL PropertyValueSet::getString( sal_Int32 columnIndex ) +{ + return getValue<OUString, &ucbhelper_impl::PropertyValue::aString>(PropsSet::String, columnIndex); +} + + +// virtual +sal_Bool SAL_CALL PropertyValueSet::getBoolean( sal_Int32 columnIndex ) +{ + return getValue<bool, &ucbhelper_impl::PropertyValue::bBoolean>(PropsSet::Boolean, columnIndex); +} + + +// virtual +sal_Int8 SAL_CALL PropertyValueSet::getByte( sal_Int32 columnIndex ) +{ + return getValue<sal_Int8, &ucbhelper_impl::PropertyValue::nByte>(PropsSet::Byte, columnIndex); +} + + +// virtual +sal_Int16 SAL_CALL PropertyValueSet::getShort( sal_Int32 columnIndex ) +{ + return getValue<sal_Int16, &ucbhelper_impl::PropertyValue::nShort>(PropsSet::Short, columnIndex); +} + + +// virtual +sal_Int32 SAL_CALL PropertyValueSet::getInt( sal_Int32 columnIndex ) +{ + return getValue<sal_Int32, &ucbhelper_impl::PropertyValue::nInt>(PropsSet::Int, columnIndex); +} + + +// virtual +sal_Int64 SAL_CALL PropertyValueSet::getLong( sal_Int32 columnIndex ) +{ + return getValue<sal_Int64, &ucbhelper_impl::PropertyValue::nLong>(PropsSet::Long, columnIndex); +} + + +// virtual +float SAL_CALL PropertyValueSet::getFloat( sal_Int32 columnIndex ) +{ + return getValue<float, &ucbhelper_impl::PropertyValue::nFloat>(PropsSet::Float, columnIndex); +} + + +// virtual +double SAL_CALL PropertyValueSet::getDouble( sal_Int32 columnIndex ) +{ + return getValue<double, &ucbhelper_impl::PropertyValue::nDouble>(PropsSet::Double, columnIndex); +} + + +// virtual +Sequence< sal_Int8 > SAL_CALL +PropertyValueSet::getBytes( sal_Int32 columnIndex ) +{ + return getValue<Sequence< sal_Int8 >, &ucbhelper_impl::PropertyValue::aBytes>(PropsSet::Bytes, columnIndex); +} + + +// virtual +Date SAL_CALL PropertyValueSet::getDate( sal_Int32 columnIndex ) +{ + return getValue<Date, &ucbhelper_impl::PropertyValue::aDate>(PropsSet::Date, columnIndex); +} + + +// virtual +Time SAL_CALL PropertyValueSet::getTime( sal_Int32 columnIndex ) +{ + return getValue<Time, &ucbhelper_impl::PropertyValue::aTime>(PropsSet::Time, columnIndex); +} + + +// virtual +DateTime SAL_CALL PropertyValueSet::getTimestamp( sal_Int32 columnIndex ) +{ + return getValue<DateTime, &ucbhelper_impl::PropertyValue::aTimestamp>(PropsSet::Timestamp, columnIndex); +} + + +// virtual +Reference< XInputStream > SAL_CALL +PropertyValueSet::getBinaryStream( sal_Int32 columnIndex ) +{ + return getValue<Reference< XInputStream >, &ucbhelper_impl::PropertyValue::xBinaryStream>(PropsSet::BinaryStream, columnIndex); +} + + +// virtual +Reference< XInputStream > SAL_CALL +PropertyValueSet::getCharacterStream( sal_Int32 columnIndex ) +{ + return getValue<Reference< XInputStream >, &ucbhelper_impl::PropertyValue::xCharacterStream>(PropsSet::CharacterStream, columnIndex); +} + + +// virtual +Any SAL_CALL PropertyValueSet::getObject( + sal_Int32 columnIndex, + const Reference< XNameAccess >& ) +{ + std::unique_lock aGuard( m_aMutex ); + + Any aValue; + + m_bWasNull = true; + + if ( ( columnIndex < 1 ) + || ( o3tl::make_unsigned(columnIndex) > m_pValues->size() ) ) + { + OSL_FAIL( "PropertyValueSet - index out of range!" ); + } + else + { + ucbhelper_impl::PropertyValue& rValue + = (*m_pValues)[ columnIndex - 1 ]; + + if ( rValue.nPropsSet & PropsSet::Object ) + { + // Values is present natively... + aValue = rValue.aObject; + m_bWasNull = false; + } + else + { + // Make Any from original value. + + switch ( rValue.nOrigValue ) + { + case PropsSet::NONE: + break; + + case PropsSet::String: + aValue <<= rValue.aString; + break; + + case PropsSet::Boolean: + aValue <<= rValue.bBoolean; + break; + + case PropsSet::Byte: + aValue <<= rValue.nByte; + break; + + case PropsSet::Short: + aValue <<= rValue.nShort; + break; + + case PropsSet::Int: + aValue <<= rValue.nInt; + break; + + case PropsSet::Long: + aValue <<= rValue.nLong; + break; + + case PropsSet::Float: + aValue <<= rValue.nFloat; + break; + + case PropsSet::Double: + aValue <<= rValue.nDouble; + break; + + case PropsSet::Bytes: + aValue <<= rValue.aBytes; + break; + + case PropsSet::Date: + aValue <<= rValue.aDate; + break; + + case PropsSet::Time: + aValue <<= rValue.aTime; + break; + + case PropsSet::Timestamp: + aValue <<= rValue.aTimestamp; + break; + + case PropsSet::BinaryStream: + aValue <<= rValue.xBinaryStream; + break; + + case PropsSet::CharacterStream: + aValue <<= rValue.xCharacterStream; + break; + + case PropsSet::Ref: + aValue <<= rValue.xRef; + break; + + case PropsSet::Blob: + aValue <<= rValue.xBlob; + break; + + case PropsSet::Clob: + aValue <<= rValue.xClob; + break; + + case PropsSet::Array: + aValue <<= rValue.xArray; + break; + + case PropsSet::Object: + // Fall-through is intended! + default: + OSL_FAIL( "PropertyValueSet::getObject - " + "Wrong original type" ); + break; + } + + if ( aValue.hasValue() ) + { + rValue.aObject = aValue; + rValue.nPropsSet |= PropsSet::Object; + m_bWasNull = false; + } + } + } + + return aValue; +} + + +// virtual +Reference< XRef > SAL_CALL PropertyValueSet::getRef( sal_Int32 columnIndex ) +{ + return getValue<Reference< XRef >, &ucbhelper_impl::PropertyValue::xRef>(PropsSet::Ref, columnIndex); +} + + +// virtual +Reference< XBlob > SAL_CALL PropertyValueSet::getBlob( sal_Int32 columnIndex ) +{ + return getValue<Reference< XBlob >, &ucbhelper_impl::PropertyValue::xBlob>(PropsSet::Blob, columnIndex); +} + + +// virtual +Reference< XClob > SAL_CALL PropertyValueSet::getClob( sal_Int32 columnIndex ) +{ + return getValue<Reference< XClob >, &ucbhelper_impl::PropertyValue::xClob>(PropsSet::Clob, columnIndex); +} + + +// virtual +Reference< XArray > SAL_CALL PropertyValueSet::getArray( sal_Int32 columnIndex ) +{ + return getValue<Reference< XArray >, &ucbhelper_impl::PropertyValue::xArray>(PropsSet::Array, columnIndex); +} + + +// XColumnLocate methods. + + +// virtual +sal_Int32 SAL_CALL PropertyValueSet::findColumn( const OUString& columnName ) +{ + std::unique_lock aGuard( m_aMutex ); + + if ( !columnName.isEmpty() ) + { + sal_Int32 nCount = m_pValues->size(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + if ( (*m_pValues)[ n ].sPropertyName == columnName ) + return n + 1; // Index is 1-based. + } + } + return 0; +} + + +// Non-interface methods. + + +const Reference< XTypeConverter >& PropertyValueSet::getTypeConverter() +{ + std::unique_lock aGuard( m_aMutex ); + + if ( !m_bTriedToGetTypeConverter && !m_xTypeConverter.is() ) + { + m_bTriedToGetTypeConverter = true; + m_xTypeConverter = Converter::create(m_xContext); + + OSL_ENSURE( m_xTypeConverter.is(), + "PropertyValueSet::getTypeConverter() - " + "Service 'com.sun.star.script.Converter' n/a!" ); + } + return m_xTypeConverter; +} + + +template <class T, T ucbhelper_impl::PropertyValue::*_member_name_> +void PropertyValueSet::appendValue(const OUString& rPropName, PropsSet nTypeName, const T& rValue) +{ + std::unique_lock aGuard( m_aMutex ); + + ucbhelper_impl::PropertyValue aNewValue; + aNewValue.sPropertyName = rPropName; + aNewValue.nPropsSet = nTypeName; + aNewValue.nOrigValue = nTypeName; + aNewValue.*_member_name_ = rValue; + + m_pValues->push_back( aNewValue ); +} + + +void PropertyValueSet::appendString( const OUString& rPropName, + const OUString& rValue ) +{ + appendValue<OUString, &ucbhelper_impl::PropertyValue::aString>(rPropName, PropsSet::String, rValue); +} + + +void PropertyValueSet::appendBoolean( const OUString& rPropName, + bool bValue ) +{ + appendValue<bool, &ucbhelper_impl::PropertyValue::bBoolean>(rPropName, PropsSet::Boolean, bValue); +} + + +void PropertyValueSet::appendLong( const OUString& rPropName, + sal_Int64 nValue ) +{ + appendValue<sal_Int64, &ucbhelper_impl::PropertyValue::nLong>(rPropName, PropsSet::Long, nValue); +} + + +void PropertyValueSet::appendTimestamp( const OUString& rPropName, + const DateTime& rValue ) +{ + appendValue<DateTime, &ucbhelper_impl::PropertyValue::aTimestamp>(rPropName, PropsSet::Timestamp, rValue); +} + + +void PropertyValueSet::appendObject( const OUString& rPropName, + const Any& rValue ) +{ + appendValue<Any, &ucbhelper_impl::PropertyValue::aObject>(rPropName, PropsSet::Object, rValue); +} + + +void PropertyValueSet::appendVoid( const OUString& rPropName ) +{ + appendValue<Any, &ucbhelper_impl::PropertyValue::aObject>(rPropName, PropsSet::NONE, Any()); +} + + +void PropertyValueSet::appendPropertySet( + const Reference< XPropertySet >& rxSet ) +{ + if ( !rxSet.is() ) + return; + + Reference< XPropertySetInfo > xInfo = rxSet->getPropertySetInfo(); + if ( !xInfo.is() ) + return; + + const Sequence< Property > aProps = xInfo->getProperties(); + + Reference< XPropertyAccess > xPropertyAccess( rxSet, UNO_QUERY ); + if ( xPropertyAccess.is() ) + { + // Efficient: Get all prop values with one ( remote) call. + + const Sequence< css::beans::PropertyValue > aPropValues + = xPropertyAccess->getPropertyValues(); + + for ( const css::beans::PropertyValue& rPropValue : aPropValues ) + { + // Find info for current property value. + auto pProp = std::find_if(aProps.begin(), aProps.end(), + [&rPropValue](const Property& rProp) { return rProp.Name == rPropValue.Name; }); + if (pProp != aProps.end()) + { + // Found! + appendObject( *pProp, rPropValue.Value ); + } + } + } + else + { + // Get every single prop value with one ( remote) call. + + for ( const Property& rProp : aProps ) + { + try + { + Any aValue = rxSet->getPropertyValue( rProp.Name ); + + if ( aValue.hasValue() ) + appendObject( rProp, aValue ); + } + catch (const UnknownPropertyException&) + { + } + catch (const WrappedTargetException&) + { + } + } + } +} + + +bool PropertyValueSet::appendPropertySetValue( + const Reference< XPropertySet >& rxSet, + const Property& rProperty ) +{ + if ( rxSet.is() ) + { + try + { + Any aValue = rxSet->getPropertyValue( rProperty.Name ); + if ( aValue.hasValue() ) + { + appendObject( rProperty, aValue ); + return true; + } + } + catch (const UnknownPropertyException&) + { + } + catch (const WrappedTargetException&) + { + } + } + + // Error. + return false; +} + +} // namespace ucbhelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/providerhelper.cxx b/ucbhelper/source/provider/providerhelper.cxx new file mode 100644 index 0000000000..a15ba5457b --- /dev/null +++ b/ucbhelper/source/provider/providerhelper.cxx @@ -0,0 +1,497 @@ +/* -*- 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 <sal/config.h> + +#include <com/sun/star/beans/IllegalTypeException.hpp> +#include <com/sun/star/beans/PropertyExistException.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/ucb/Store.hpp> +#include <com/sun/star/ucb/XPropertySetRegistry.hpp> +#include <com/sun/star/ucb/XPropertySetRegistryFactory.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <ucbhelper/contenthelper.hxx> +#include <ucbhelper/providerhelper.hxx> + +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <cppuhelper/weakref.hxx> + +#include <unordered_map> +#include <utility> + +using namespace com::sun::star; + +namespace ucbhelper_impl +{ + +typedef std::unordered_map +< + OUString, + uno::WeakReference< ucb::XContent > +> +Contents; + +struct ContentProviderImplHelper_Impl +{ + uno::Reference< css::ucb::XPropertySetRegistry > m_xPropertySetRegistry; + Contents m_aContents; +}; + +} // namespace ucbhelper_impl + +namespace ucbhelper { + +ContentProviderImplHelper::ContentProviderImplHelper( + uno::Reference< uno::XComponentContext > xContext ) +: m_pImpl( new ucbhelper_impl::ContentProviderImplHelper_Impl ), + m_xContext(std::move( xContext )) +{ +} + +// virtual +ContentProviderImplHelper::~ContentProviderImplHelper() +{ +} + +// virtual +sal_Bool SAL_CALL ContentProviderImplHelper::supportsService( + const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +// virtual +sal_Int32 SAL_CALL ContentProviderImplHelper::compareContentIds( + const uno::Reference< css::ucb::XContentIdentifier >& Id1, + const uno::Reference< css::ucb::XContentIdentifier >& Id2 ) +{ + // Simply do a string compare. + + OUString aURL1( Id1->getContentIdentifier() ); + OUString aURL2( Id2->getContentIdentifier() ); + + return aURL1.compareTo( aURL2 ); +} + +void ContentProviderImplHelper::cleanupRegisteredContents() +{ + osl::MutexGuard aGuard( m_aMutex ); + + ucbhelper_impl::Contents::iterator it + = m_pImpl->m_aContents.begin(); + while( it != m_pImpl->m_aContents.end() ) + { + uno::Reference< ucb::XContent > xContent( (*it).second ); + if ( !xContent.is() ) + { + ucbhelper_impl::Contents::iterator tmp = it; + ++it; + m_pImpl->m_aContents.erase( tmp ); + } + else + { + ++it; + } + } +} + +void ContentProviderImplHelper::removeContent( ContentImplHelper* pContent ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + cleanupRegisteredContents(); + + const OUString aURL( + pContent->getIdentifier()->getContentIdentifier() ); + + ucbhelper_impl::Contents::iterator it = m_pImpl->m_aContents.find( aURL ); + + if ( it != m_pImpl->m_aContents.end() ) + m_pImpl->m_aContents.erase( it ); +} + +rtl::Reference< ContentImplHelper > +ContentProviderImplHelper::queryExistingContent( + const uno::Reference< css::ucb::XContentIdentifier >& Identifier ) +{ + return queryExistingContent( Identifier->getContentIdentifier() ); +} + +rtl::Reference< ContentImplHelper > +ContentProviderImplHelper::queryExistingContent( const OUString& rURL ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + cleanupRegisteredContents(); + + // Check, if a content with given id already exists... + + ucbhelper_impl::Contents::const_iterator it + = m_pImpl->m_aContents.find( rURL ); + if ( it != m_pImpl->m_aContents.end() ) + { + uno::Reference< ucb::XContent > xContent( (*it).second ); + if ( xContent.is() ) + { + return rtl::Reference< ContentImplHelper >( + static_cast< ContentImplHelper * >( xContent.get() ) ); + } + } + return rtl::Reference< ContentImplHelper >(); +} + +void ContentProviderImplHelper::queryExistingContents( + ContentRefList& rContents ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + cleanupRegisteredContents(); + + for ( const auto& rContent : m_pImpl->m_aContents ) + { + uno::Reference< ucb::XContent > xContent( rContent.second ); + if ( xContent.is() ) + { + rContents.emplace_back( + static_cast< ContentImplHelper * >( xContent.get() ) ); + } + } +} + +void ContentProviderImplHelper::registerNewContent( + const uno::Reference< ucb::XContent > & xContent ) +{ + if ( !xContent.is() ) + return; + + osl::MutexGuard aGuard( m_aMutex ); + + cleanupRegisteredContents(); + + const OUString aURL( + xContent->getIdentifier()->getContentIdentifier() ); + ucbhelper_impl::Contents::const_iterator it + = m_pImpl->m_aContents.find( aURL ); + if ( it == m_pImpl->m_aContents.end() ) + m_pImpl->m_aContents[ aURL ] = xContent; +} + +uno::Reference< css::ucb::XPropertySetRegistry > +ContentProviderImplHelper::getAdditionalPropertySetRegistry() +{ + // Get propertyset registry. + + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pImpl->m_xPropertySetRegistry.is() ) + { + uno::Reference< css::ucb::XPropertySetRegistryFactory > + xRegFac = css::ucb::Store::create( m_xContext ); + + // Open/create a registry. + m_pImpl->m_xPropertySetRegistry + = xRegFac->createPropertySetRegistry( OUString() ); + + OSL_ENSURE( m_pImpl->m_xPropertySetRegistry.is(), + "ContentProviderImplHelper::getAdditionalPropertySet - " + "Error opening registry!" ); + } + + return m_pImpl->m_xPropertySetRegistry; +} + +uno::Reference< css::ucb::XPersistentPropertySet > +ContentProviderImplHelper::getAdditionalPropertySet( + const OUString& rKey, bool bCreate ) +{ + // Get propertyset registry. + getAdditionalPropertySetRegistry(); + + if ( m_pImpl->m_xPropertySetRegistry.is() ) + { + // Open/create persistent property set. + return m_pImpl->m_xPropertySetRegistry->openPropertySet( + rKey, bCreate ); + } + + return uno::Reference< css::ucb::XPersistentPropertySet >(); +} + +bool ContentProviderImplHelper::renameAdditionalPropertySet( + const OUString& rOldKey, + const OUString& rNewKey, + bool bRecursive ) +{ + if ( rOldKey == rNewKey ) + return true; + + osl::MutexGuard aGuard( m_aMutex ); + + if ( bRecursive ) + { + // Get propertyset registry. + getAdditionalPropertySetRegistry(); + + if ( !m_pImpl->m_xPropertySetRegistry.is() ) + return false; + + uno::Reference< container::XNameAccess > xNameAccess( + m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY ); + if ( !xNameAccess.is() ) + return false; + + const uno::Sequence< OUString > aKeys + = xNameAccess->getElementNames(); + if ( aKeys.hasElements() ) + { + OUString aOldKeyWithSlash = rOldKey; + OUString aOldKeyWithoutSlash; + if ( !aOldKeyWithSlash.endsWith("/") ) + { + aOldKeyWithSlash += "/"; + aOldKeyWithoutSlash = rOldKey; + } + else if ( !rOldKey.isEmpty() ) + aOldKeyWithoutSlash + = rOldKey.copy( 0, rOldKey.getLength() - 1 ); + + for ( const OUString& rKey : aKeys ) + { + if ( rKey.startsWith( aOldKeyWithSlash ) + || rKey == aOldKeyWithoutSlash ) + { + OUString aNewKey + = rKey.replaceAt( + 0, rOldKey.getLength(), rNewKey ); + if ( !renameAdditionalPropertySet( + rKey, aNewKey, false ) ) + return false; + } + } + } + } + else + { + // Get old property set, if exists. + uno::Reference< css::ucb::XPersistentPropertySet > xOldSet + = getAdditionalPropertySet( rOldKey, false ); + if ( xOldSet.is() ) + { + // Rename property set. + uno::Reference< container::XNamed > xNamed( + xOldSet, uno::UNO_QUERY ); + if ( !xNamed.is() ) + return false; + + // ??? throws no exceptions and has no return value ??? + xNamed->setName( rNewKey ); + } + } + return true; +} + +bool ContentProviderImplHelper::copyAdditionalPropertySet( + const OUString& rSourceKey, + const OUString& rTargetKey, + bool bRecursive ) +{ + if ( rSourceKey == rTargetKey ) + return true; + + osl::MutexGuard aGuard( m_aMutex ); + + if ( bRecursive ) + { + // Get propertyset registry. + getAdditionalPropertySetRegistry(); + + if ( !m_pImpl->m_xPropertySetRegistry.is() ) + return false; + + uno::Reference< container::XNameAccess > xNameAccess( + m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY ); + if ( !xNameAccess.is() ) + return false; + + const uno::Sequence< OUString > aKeys + = xNameAccess->getElementNames(); + if ( aKeys.hasElements() ) + { + OUString aSrcKeyWithSlash = rSourceKey; + OUString aSrcKeyWithoutSlash; + if ( !aSrcKeyWithSlash.endsWith("/") ) + { + aSrcKeyWithSlash += "/"; + aSrcKeyWithoutSlash = rSourceKey; + } + else if ( !rSourceKey.isEmpty() ) + aSrcKeyWithoutSlash = rSourceKey.copy( + 0, rSourceKey.getLength() - 1 ); + + for ( const OUString& rKey : aKeys ) + { + if ( rKey.startsWith(aSrcKeyWithSlash ) + || rKey == aSrcKeyWithoutSlash ) + { + OUString aNewKey + = rKey.replaceAt( + 0, rSourceKey.getLength(), rTargetKey ); + if ( !copyAdditionalPropertySet( + rKey, aNewKey, false ) ) + return false; + } + } + } + } + else + { + // Get old property set, if exists. + uno::Reference< css::ucb::XPersistentPropertySet > + xOldPropSet = getAdditionalPropertySet( rSourceKey, false ); + if ( !xOldPropSet.is() ) + return false; + + uno::Reference< beans::XPropertySetInfo > xPropSetInfo + = xOldPropSet->getPropertySetInfo(); + if ( !xPropSetInfo.is() ) + return false; + + uno::Reference< beans::XPropertyAccess > xOldPropAccess( + xOldPropSet, uno::UNO_QUERY ); + if ( !xOldPropAccess.is() ) + return false; + + // Obtain all values from old set. + const uno::Sequence< beans::PropertyValue > aValues + = xOldPropAccess->getPropertyValues(); + + const uno::Sequence< beans::Property > aProps + = xPropSetInfo->getProperties(); + + if ( aValues.hasElements() ) + { + // Fail, if property set with new key already exists. + uno::Reference< css::ucb::XPersistentPropertySet > + xNewPropSet + = getAdditionalPropertySet( rTargetKey, false ); + if ( xNewPropSet.is() ) + return false; + + // Create new, empty set. + xNewPropSet = getAdditionalPropertySet( rTargetKey, true ); + if ( !xNewPropSet.is() ) + return false; + + uno::Reference< beans::XPropertyContainer > xNewPropContainer( + xNewPropSet, uno::UNO_QUERY ); + if ( !xNewPropContainer.is() ) + return false; + + for ( const beans::PropertyValue& rValue : aValues ) + { + sal_Int16 nAttribs = 0; + auto pProp = std::find_if(aProps.begin(), aProps.end(), + [&rValue](const beans::Property& rProp) { return rProp.Name == rValue.Name; }); + if (pProp != aProps.end()) + nAttribs = pProp->Attributes; + + try + { + xNewPropContainer->addProperty( + rValue.Name, nAttribs, rValue.Value ); + } + catch ( beans::PropertyExistException & ) + { + } + catch ( beans::IllegalTypeException & ) + { + } + catch ( lang::IllegalArgumentException & ) + { + } + } + } + } + return true; +} + +bool ContentProviderImplHelper::removeAdditionalPropertySet( + const OUString& rKey, bool bRecursive ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( bRecursive ) + { + // Get propertyset registry. + getAdditionalPropertySetRegistry(); + + if ( !m_pImpl->m_xPropertySetRegistry.is() ) + return false; + + uno::Reference< container::XNameAccess > xNameAccess( + m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY ); + if ( !xNameAccess.is() ) + return false; + + const uno::Sequence< OUString > aKeys + = xNameAccess->getElementNames(); + if ( aKeys.hasElements() ) + { + OUString aKeyWithSlash = rKey; + OUString aKeyWithoutSlash; + if ( !aKeyWithSlash.endsWith("/") ) + { + aKeyWithSlash += "/"; + aKeyWithoutSlash = rKey; + } + else if ( !rKey.isEmpty() ) + aKeyWithoutSlash + = rKey.copy( 0, rKey.getLength() - 1 ); + + for ( const OUString& rCurrKey : aKeys ) + { + if ( rCurrKey.startsWith(aKeyWithSlash ) + || rCurrKey == aKeyWithoutSlash ) + { + if ( !removeAdditionalPropertySet( + rCurrKey, false ) ) + return false; + } + } + } + } + else + { + // Get propertyset registry. + getAdditionalPropertySetRegistry(); + + if ( !m_pImpl->m_xPropertySetRegistry.is() ) + return false; + + m_pImpl->m_xPropertySetRegistry->removePropertySet( rKey ); + } + return true; +} + +} // namespace ucbhelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/registerucb.cxx b/ucbhelper/source/provider/registerucb.cxx new file mode 100644 index 0000000000..baf0e5b3f6 --- /dev/null +++ b/ucbhelper/source/provider/registerucb.cxx @@ -0,0 +1,139 @@ +/* -*- 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 <ucbhelper/registerucb.hxx> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/ucb/DuplicateProviderException.hpp> +#include <com/sun/star/ucb/XContentProviderManager.hpp> +#include <com/sun/star/ucb/XParameterizedContentProvider.hpp> +#include <com/sun/star/ucb/ContentProviderProxyFactory.hpp> +#include <com/sun/star/ucb/XContentProviderFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> + +#include <osl/diagnose.h> + +using namespace com::sun::star; + +namespace ucbhelper { + +bool +registerAtUcb( + uno::Reference< ucb::XContentProviderManager > const & rManager, + uno::Reference< uno::XComponentContext > const & rxContext, + OUString const & rName, + OUString const & rArguments, + OUString const & rTemplate) +{ + OSL_ENSURE(rxContext.is(), + "ucb::registerAtUcb(): No service factory"); + + bool bNoProxy = rArguments.startsWith("{noproxy}"); + OUString + aProviderArguments(bNoProxy ? + rArguments. + copy(RTL_CONSTASCII_LENGTH("{noproxy}")) : + rArguments); + + uno::Reference< ucb::XContentProvider > xProvider; + + if (!rName.isEmpty()) + { + // First, try to instantiate proxy for provider: + if (!bNoProxy) + { + uno::Reference< ucb::XContentProviderFactory > xProxyFactory; + try + { + xProxyFactory = ucb::ContentProviderProxyFactory::create( rxContext ); + } + catch (uno::Exception const &) {} + OSL_ENSURE(xProxyFactory.is(), "No ContentProviderProxyFactory"); + if (xProxyFactory.is()) + xProvider = xProxyFactory->createContentProvider(rName); + } + + // Then, try to instantiate provider directly: + if (!xProvider.is()) + try + { + xProvider.set( + rxContext->getServiceManager()->createInstanceWithContext(rName, rxContext), + uno::UNO_QUERY); + } + catch (uno::RuntimeException const &) { throw; } + catch (uno::Exception const &) {} + } + + uno::Reference< ucb::XParameterizedContentProvider > + xParameterized(xProvider, uno::UNO_QUERY); + if (xParameterized.is()) + { + uno::Reference< ucb::XContentProvider > xInstance; + try + { + xInstance = xParameterized->registerInstance(rTemplate, + aProviderArguments, + true); + //@@@ if this call replaces an old instance, the commit-or- + // rollback code below will not work + } + catch (lang::IllegalArgumentException const &) {} + + if (xInstance.is()) + xProvider = xInstance; + } + + bool bSuccess = false; + if (rManager.is() && (rName.isEmpty() || xProvider.is())) + { + try + { + rManager->registerContentProvider(xProvider, rTemplate, true); + bSuccess = true; + } + catch (ucb::DuplicateProviderException const &) + { + if (xParameterized.is()) + try + { + xParameterized->deregisterInstance(rTemplate, + aProviderArguments); + } + catch (lang::IllegalArgumentException const &) {} + } + catch (...) + { + if (xParameterized.is()) + try + { + xParameterized->deregisterInstance(rTemplate, + aProviderArguments); + } + catch (lang::IllegalArgumentException const &) {} + catch (uno::RuntimeException const &) {} + throw; + } + } + return bSuccess; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/resultset.cxx b/ucbhelper/source/provider/resultset.cxx new file mode 100644 index 0000000000..61682f4fd5 --- /dev/null +++ b/ucbhelper/source/provider/resultset.cxx @@ -0,0 +1,1486 @@ +/* -*- 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 <memory> +#include <mutex> +#include <comphelper/interfacecontainer4.hxx> +#include <comphelper/multiinterfacecontainer4.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <ucbhelper/resultset.hxx> +#include <ucbhelper/resultsetmetadata.hxx> +#include <ucbhelper/macros.hxx> +#include <utility> +#include <osl/diagnose.h> + +using namespace com::sun::star; + + +namespace ucbhelper_impl +{ + +namespace { + +struct PropertyInfo +{ + const char* pName; + sal_Int32 nHandle; + sal_Int16 nAttributes; + const uno::Type& (*pGetCppuType)(); +}; + +} + +static const uno::Type& sal_Int32_getCppuType() +{ + return cppu::UnoType<sal_Int32>::get(); +} + +static const uno::Type& sal_Bool_getCppuType() +{ + return cppu::UnoType<bool>::get(); +} + +const PropertyInfo aPropertyTable[] = +{ + { "IsRowCountFinal", + 1000, + beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, + &sal_Bool_getCppuType + }, + { "RowCount", + 1001, + beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, + &sal_Int32_getCppuType + }, + { nullptr, + 0, + 0, + nullptr + } +}; + +#define RESULTSET_PROPERTY_COUNT 2 + + + +namespace { + +class PropertySetInfo : + public cppu::OWeakObject, + public lang::XTypeProvider, + public beans::XPropertySetInfo +{ + uno::Sequence< beans::Property > m_aProps; + +private: + bool queryProperty( + std::u16string_view aName, beans::Property& rProp ) const; + +public: + PropertySetInfo( + const PropertyInfo* pProps, + sal_Int32 nProps ); + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + // XTypeProvider + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // XPropertySetInfo + virtual uno::Sequence< beans::Property > SAL_CALL getProperties() override; + virtual beans::Property SAL_CALL getPropertyByName( + const OUString& aName ) override; + virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override; +}; + +} + +typedef comphelper::OMultiTypeInterfaceContainerHelperVar4<OUString, css::beans::XPropertyChangeListener> + PropertyChangeListeners; + +} // namespace ucbhelper_impl + +using namespace ucbhelper_impl; + +namespace ucbhelper +{ + + +// struct ResultSet_Impl. + + +struct ResultSet_Impl +{ + uno::Reference< uno::XComponentContext > m_xContext; + uno::Reference< css::ucb::XCommandEnvironment > m_xEnv; + uno::Reference< beans::XPropertySetInfo > m_xPropSetInfo; + uno::Reference< sdbc::XResultSetMetaData > m_xMetaData; + uno::Sequence< beans::Property > m_aProperties; + rtl::Reference< ResultSetDataSupplier > m_xDataSupplier; + std::mutex m_aMutex; + comphelper::OInterfaceContainerHelper4<lang::XEventListener> m_aDisposeEventListeners; + std::unique_ptr<PropertyChangeListeners> m_pPropertyChangeListeners; + sal_Int32 m_nPos; + bool m_bWasNull; + bool m_bAfterLast; + + inline ResultSet_Impl( + uno::Reference< uno::XComponentContext > xContext, + const uno::Sequence< beans::Property >& rProperties, + rtl::Reference< ResultSetDataSupplier > xDataSupplier, + uno::Reference< css::ucb::XCommandEnvironment > xEnv ); +}; + +inline ResultSet_Impl::ResultSet_Impl( + uno::Reference< uno::XComponentContext > xContext, + const uno::Sequence< beans::Property >& rProperties, + rtl::Reference< ResultSetDataSupplier > xDataSupplier, + uno::Reference< css::ucb::XCommandEnvironment > xEnv ) +: m_xContext(std::move( xContext )), + m_xEnv(std::move( xEnv )), + m_aProperties( rProperties ), + m_xDataSupplier(std::move( xDataSupplier )), + m_nPos( 0 ), // Position is one-based. Zero means: before first element. + m_bWasNull( false ), + m_bAfterLast( false ) +{ +} + + +// ResultSet Implementation. + + +ResultSet::ResultSet( + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Sequence< beans::Property >& rProperties, + const rtl::Reference< ResultSetDataSupplier >& rDataSupplier ) +: m_pImpl( new ResultSet_Impl( + rxContext, + rProperties, + rDataSupplier, + uno::Reference< css::ucb::XCommandEnvironment >() ) ) +{ + rDataSupplier->m_pResultSet = this; +} + + +ResultSet::ResultSet( + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Sequence< beans::Property >& rProperties, + const rtl::Reference< ResultSetDataSupplier >& rDataSupplier, + const uno::Reference< css::ucb::XCommandEnvironment >& rxEnv ) +: m_pImpl( new ResultSet_Impl( rxContext, rProperties, rDataSupplier, rxEnv ) ) +{ + rDataSupplier->m_pResultSet = this; +} + + +// virtual +ResultSet::~ResultSet() +{ +} + + +// XServiceInfo methods. + +OUString SAL_CALL ResultSet::getImplementationName() +{ + return "ResultSet"; +} + +sal_Bool SAL_CALL ResultSet::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +css::uno::Sequence< OUString > SAL_CALL ResultSet::getSupportedServiceNames() +{ + return { RESULTSET_SERVICE_NAME }; +} + + +// XComponent methods. + + +// virtual +void SAL_CALL ResultSet::dispose() +{ + std::unique_lock aGuard( m_pImpl->m_aMutex ); + + if ( m_pImpl->m_aDisposeEventListeners.getLength(aGuard) ) + { + lang::EventObject aEvt; + aEvt.Source = static_cast< lang::XComponent * >( this ); + m_pImpl->m_aDisposeEventListeners.disposeAndClear( aGuard, aEvt ); + } + + if ( m_pImpl->m_pPropertyChangeListeners ) + { + lang::EventObject aEvt; + aEvt.Source = static_cast< beans::XPropertySet * >( this ); + m_pImpl->m_pPropertyChangeListeners->disposeAndClear( aGuard, aEvt ); + } + + m_pImpl->m_xDataSupplier->close(); +} + + +// virtual +void SAL_CALL ResultSet::addEventListener( + const uno::Reference< lang::XEventListener >& Listener ) +{ + std::unique_lock aGuard( m_pImpl->m_aMutex ); + + m_pImpl->m_aDisposeEventListeners.addInterface( aGuard, Listener ); +} + + +// virtual +void SAL_CALL ResultSet::removeEventListener( + const uno::Reference< lang::XEventListener >& Listener ) +{ + std::unique_lock aGuard( m_pImpl->m_aMutex ); + + m_pImpl->m_aDisposeEventListeners.removeInterface( aGuard, Listener ); +} + + +// XResultSetMetaDataSupplier methods. + + +// virtual +uno::Reference< sdbc::XResultSetMetaData > SAL_CALL ResultSet::getMetaData() +{ + std::unique_lock aGuard( m_pImpl->m_aMutex ); + + if ( !m_pImpl->m_xMetaData.is() ) + m_pImpl->m_xMetaData = new ResultSetMetaData( m_pImpl->m_xContext, + m_pImpl->m_aProperties ); + + return m_pImpl->m_xMetaData; +} + + +// XResultSet methods. + + +// virtual +sal_Bool SAL_CALL ResultSet::next() +{ + // Note: Cursor is initially positioned before the first row. + // First call to 'next()' moves it to first row. + + std::unique_lock aGuard( m_pImpl->m_aMutex ); + + if ( m_pImpl->m_bAfterLast ) + { + m_pImpl->m_xDataSupplier->validate(); + return false; + } + + // getResult works zero-based! + if ( !m_pImpl->m_xDataSupplier->getResult( m_pImpl->m_nPos ) ) + { + m_pImpl->m_bAfterLast = true; + m_pImpl->m_xDataSupplier->validate(); + return false; + } + + m_pImpl->m_nPos++; + m_pImpl->m_xDataSupplier->validate(); + return true; +} + + +// virtual +sal_Bool SAL_CALL ResultSet::isBeforeFirst() +{ + if ( m_pImpl->m_bAfterLast ) + { + m_pImpl->m_xDataSupplier->validate(); + return false; + } + + // getResult works zero-based! + if ( !m_pImpl->m_xDataSupplier->getResult( 0 ) ) + { + m_pImpl->m_xDataSupplier->validate(); + return false; + } + + m_pImpl->m_xDataSupplier->validate(); + return ( m_pImpl->m_nPos == 0 ); +} + + +// virtual +sal_Bool SAL_CALL ResultSet::isAfterLast() +{ + m_pImpl->m_xDataSupplier->validate(); + return m_pImpl->m_bAfterLast; +} + + +// virtual +sal_Bool SAL_CALL ResultSet::isFirst() +{ + if ( m_pImpl->m_bAfterLast ) + { + m_pImpl->m_xDataSupplier->validate(); + return false; + } + + m_pImpl->m_xDataSupplier->validate(); + return ( m_pImpl->m_nPos == 1 ); +} + + +// virtual +sal_Bool SAL_CALL ResultSet::isLast() +{ + if ( m_pImpl->m_bAfterLast ) + { + m_pImpl->m_xDataSupplier->validate(); + return false; + } + + sal_Int32 nCount = m_pImpl->m_xDataSupplier->totalCount(); + if ( !nCount ) + { + m_pImpl->m_xDataSupplier->validate(); + return false; + } + + m_pImpl->m_xDataSupplier->validate(); + return ( m_pImpl->m_nPos == nCount ); +} + + +// virtual +void SAL_CALL ResultSet::beforeFirst() +{ + std::unique_lock aGuard( m_pImpl->m_aMutex ); + m_pImpl->m_bAfterLast = false; + m_pImpl->m_nPos = 0; + m_pImpl->m_xDataSupplier->validate(); +} + + +// virtual +void SAL_CALL ResultSet::afterLast() +{ + std::unique_lock aGuard( m_pImpl->m_aMutex ); + m_pImpl->m_bAfterLast = true; + m_pImpl->m_xDataSupplier->validate(); +} + + +// virtual +sal_Bool SAL_CALL ResultSet::first() +{ + // getResult works zero-based! + if ( m_pImpl->m_xDataSupplier->getResult( 0 ) ) + { + std::unique_lock aGuard( m_pImpl->m_aMutex ); + m_pImpl->m_bAfterLast = false; + m_pImpl->m_nPos = 1; + m_pImpl->m_xDataSupplier->validate(); + return true; + } + + m_pImpl->m_xDataSupplier->validate(); + return false; +} + + +// virtual +sal_Bool SAL_CALL ResultSet::last() +{ + sal_Int32 nCount = m_pImpl->m_xDataSupplier->totalCount(); + if ( nCount ) + { + std::unique_lock aGuard( m_pImpl->m_aMutex ); + m_pImpl->m_bAfterLast = false; + m_pImpl->m_nPos = nCount; + m_pImpl->m_xDataSupplier->validate(); + return true; + } + + m_pImpl->m_xDataSupplier->validate(); + return false; +} + + +// virtual +sal_Int32 SAL_CALL ResultSet::getRow() +{ + if ( m_pImpl->m_bAfterLast ) + { + m_pImpl->m_xDataSupplier->validate(); + return 0; + } + + m_pImpl->m_xDataSupplier->validate(); + return m_pImpl->m_nPos; +} + + +// virtual +sal_Bool SAL_CALL ResultSet::absolute( sal_Int32 row ) +{ +/* + If the row number is positive, the cursor moves to the given row number + with respect to the beginning of the result set. The first row is row 1, + the second is row 2, and so on. + + If the given row number is negative, the cursor moves to an absolute row + position with respect to the end of the result set. For example, calling + absolute( -1 ) positions the cursor on the last row, absolute( -2 ) + indicates the next-to-last row, and so on. + + An attempt to position the cursor beyond the first/last row in the result + set leaves the cursor before/after the first/last row, respectively. + + Calling absolute( 1 ) is the same as calling first(). + + Calling absolute( -1 ) is the same as calling last(). +*/ + if ( row < 0 ) + { + sal_Int32 nCount = m_pImpl->m_xDataSupplier->totalCount(); + + if ( ( row * -1 ) > nCount ) + { + std::unique_lock aGuard( m_pImpl->m_aMutex ); + m_pImpl->m_bAfterLast = false; + m_pImpl->m_nPos = 0; + m_pImpl->m_xDataSupplier->validate(); + return false; + } + else // |row| <= nCount + { + std::unique_lock aGuard( m_pImpl->m_aMutex ); + m_pImpl->m_bAfterLast = false; + m_pImpl->m_nPos = ( nCount + row + 1 ); + m_pImpl->m_xDataSupplier->validate(); + return true; + } + } + else if ( row == 0 ) + { + // @throws SQLException + // ... if row is 0 ... + throw sdbc::SQLException(); + } + else // row > 0 + { + sal_Int32 nCount = m_pImpl->m_xDataSupplier->totalCount(); + + if ( row <= nCount ) + { + std::unique_lock aGuard( m_pImpl->m_aMutex ); + m_pImpl->m_bAfterLast = false; + m_pImpl->m_nPos = row; + m_pImpl->m_xDataSupplier->validate(); + return true; + } + else // row > nCount + { + std::unique_lock aGuard( m_pImpl->m_aMutex ); + m_pImpl->m_bAfterLast = true; + m_pImpl->m_xDataSupplier->validate(); + return false; + } + } + + // unreachable... +} + + +// virtual +sal_Bool SAL_CALL ResultSet::relative( sal_Int32 rows ) +{ +/* + Attempting to move beyond the first/last row in the result set + positions the cursor before/after the first/last row. + + Calling relative( 0 ) is valid, but does not change the cursor position. + + Calling relative( 1 ) is different from calling next() because it makes + sense to call next() when there is no current row, for example, when + the cursor is positioned before the first row or after the last row of + the result set. +*/ + if ( m_pImpl->m_bAfterLast || ( m_pImpl->m_nPos == 0 ) ) + { + // "No current row". + throw sdbc::SQLException(); + } + + if ( rows < 0 ) + { + if ( ( m_pImpl->m_nPos + rows ) > 0 ) + { + std::unique_lock aGuard( m_pImpl->m_aMutex ); + m_pImpl->m_bAfterLast = false; + m_pImpl->m_nPos = ( m_pImpl->m_nPos + rows ); + m_pImpl->m_xDataSupplier->validate(); + return true; + } + else + { + std::unique_lock aGuard( m_pImpl->m_aMutex ); + m_pImpl->m_bAfterLast = false; + m_pImpl->m_nPos = 0; + m_pImpl->m_xDataSupplier->validate(); + return false; + } + } + else if ( rows == 0 ) + { + // nop. + m_pImpl->m_xDataSupplier->validate(); + return true; + } + else // rows > 0 + { + sal_Int32 nCount = m_pImpl->m_xDataSupplier->totalCount(); + if ( ( m_pImpl->m_nPos + rows ) <= nCount ) + { + std::unique_lock aGuard( m_pImpl->m_aMutex ); + m_pImpl->m_bAfterLast = false; + m_pImpl->m_nPos = ( m_pImpl->m_nPos + rows ); + m_pImpl->m_xDataSupplier->validate(); + return true; + } + else + { + std::unique_lock aGuard( m_pImpl->m_aMutex ); + m_pImpl->m_bAfterLast = true; + m_pImpl->m_xDataSupplier->validate(); + return false; + } + } + + // unreachable... +} + + +// virtual +sal_Bool SAL_CALL ResultSet::previous() +{ +/* + previous() is not the same as relative( -1 ) because it makes sense + to call previous() when there is no current row. +*/ + std::unique_lock aGuard( m_pImpl->m_aMutex ); + + if ( m_pImpl->m_bAfterLast ) + { + m_pImpl->m_bAfterLast = false; + sal_Int32 nCount = m_pImpl->m_xDataSupplier->totalCount(); + m_pImpl->m_nPos = nCount; + } + else if ( m_pImpl->m_nPos ) + m_pImpl->m_nPos--; + + if ( m_pImpl->m_nPos ) + { + m_pImpl->m_xDataSupplier->validate(); + return true; + } + + m_pImpl->m_xDataSupplier->validate(); + return false; +} + + +// virtual +void SAL_CALL ResultSet::refreshRow() +{ + std::unique_lock aGuard( m_pImpl->m_aMutex ); + if ( m_pImpl->m_bAfterLast || ( m_pImpl->m_nPos == 0 ) ) + return; + + m_pImpl->m_xDataSupplier->releasePropertyValues( m_pImpl->m_nPos ); + m_pImpl->m_xDataSupplier->validate(); +} + + +// virtual +sal_Bool SAL_CALL ResultSet::rowUpdated() +{ + m_pImpl->m_xDataSupplier->validate(); + return false; +} + + +// virtual +sal_Bool SAL_CALL ResultSet::rowInserted() +{ + m_pImpl->m_xDataSupplier->validate(); + return false; +} + + +// virtual +sal_Bool SAL_CALL ResultSet::rowDeleted() +{ + m_pImpl->m_xDataSupplier->validate(); + return false; +} + + +// virtual +uno::Reference< uno::XInterface > SAL_CALL ResultSet::getStatement() +{ +/* + returns the Statement that produced this ResultSet object. If the + result set was generated some other way, ... this method returns null. +*/ + m_pImpl->m_xDataSupplier->validate(); + return uno::Reference< uno::XInterface >(); +} + + +// XRow methods. + + +// virtual +sal_Bool SAL_CALL ResultSet::wasNull() +{ + // This method can not be implemented correctly!!! Imagine different + // threads doing a getXYZ - wasNull calling sequence on the same + // implementation object... + + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_xDataSupplier->validate(); + return xValues->wasNull(); + } + } + + m_pImpl->m_xDataSupplier->validate(); + return m_pImpl->m_bWasNull; +} + + +// virtual +OUString SAL_CALL ResultSet::getString( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getString( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return OUString(); +} + + +// virtual +sal_Bool SAL_CALL ResultSet::getBoolean( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getBoolean( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return false; +} + + +// virtual +sal_Int8 SAL_CALL ResultSet::getByte( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getByte( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return 0; +} + + +// virtual +sal_Int16 SAL_CALL ResultSet::getShort( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getShort( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return 0; +} + + +// virtual +sal_Int32 SAL_CALL ResultSet::getInt( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getInt( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return 0; +} + + +// virtual +sal_Int64 SAL_CALL ResultSet::getLong( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getLong( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return 0; +} + + +// virtual +float SAL_CALL ResultSet::getFloat( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getFloat( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return 0; +} + + +// virtual +double SAL_CALL ResultSet::getDouble( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getDouble( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return 0; +} + + +// virtual +uno::Sequence< sal_Int8 > SAL_CALL +ResultSet::getBytes( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getBytes( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return uno::Sequence< sal_Int8 >(); +} + + +// virtual +util::Date SAL_CALL ResultSet::getDate( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getDate( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return util::Date(); +} + + +// virtual +util::Time SAL_CALL ResultSet::getTime( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getTime( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return util::Time(); +} + + +// virtual +util::DateTime SAL_CALL +ResultSet::getTimestamp( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getTimestamp( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return util::DateTime(); +} + + +// virtual +uno::Reference< io::XInputStream > SAL_CALL +ResultSet::getBinaryStream( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getBinaryStream( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return uno::Reference< io::XInputStream >(); +} + + +// virtual +uno::Reference< io::XInputStream > SAL_CALL +ResultSet::getCharacterStream( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getCharacterStream( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return uno::Reference< io::XInputStream >(); +} + + +// virtual +uno::Any SAL_CALL ResultSet::getObject( + sal_Int32 columnIndex, + const uno::Reference< container::XNameAccess >& typeMap ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getObject( columnIndex, typeMap ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return uno::Any(); +} + + +// virtual +uno::Reference< sdbc::XRef > SAL_CALL +ResultSet::getRef( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getRef( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return uno::Reference< sdbc::XRef >(); +} + + +// virtual +uno::Reference< sdbc::XBlob > SAL_CALL +ResultSet::getBlob( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getBlob( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return uno::Reference< sdbc::XBlob >(); +} + + +// virtual +uno::Reference< sdbc::XClob > SAL_CALL +ResultSet::getClob( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getClob( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return uno::Reference< sdbc::XClob >(); +} + + +// virtual +uno::Reference< sdbc::XArray > SAL_CALL +ResultSet::getArray( sal_Int32 columnIndex ) +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + { + uno::Reference< sdbc::XRow > xValues + = m_pImpl->m_xDataSupplier->queryPropertyValues( + m_pImpl->m_nPos - 1 ); + if ( xValues.is() ) + { + m_pImpl->m_bWasNull = false; + m_pImpl->m_xDataSupplier->validate(); + return xValues->getArray( columnIndex ); + } + } + + m_pImpl->m_bWasNull = true; + m_pImpl->m_xDataSupplier->validate(); + return uno::Reference< sdbc::XArray >(); +} + + +// XCloseable methods. + + +// virtual +void SAL_CALL ResultSet::close() +{ + m_pImpl->m_xDataSupplier->close(); + m_pImpl->m_xDataSupplier->validate(); +} + + +// XContentAccess methods. + + +// virtual +OUString SAL_CALL ResultSet::queryContentIdentifierString() +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + return m_pImpl->m_xDataSupplier->queryContentIdentifierString( + m_pImpl->m_nPos - 1 ); + + return OUString(); +} + + +// virtual +uno::Reference< css::ucb::XContentIdentifier > SAL_CALL +ResultSet::queryContentIdentifier() +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + return m_pImpl->m_xDataSupplier->queryContentIdentifier( + m_pImpl->m_nPos - 1 ); + + return uno::Reference< css::ucb::XContentIdentifier >(); +} + + +// virtual +uno::Reference< css::ucb::XContent > SAL_CALL +ResultSet::queryContent() +{ + if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast ) + return m_pImpl->m_xDataSupplier->queryContent( m_pImpl->m_nPos - 1 ); + + return uno::Reference< css::ucb::XContent >(); +} + + +// XPropertySet methods. + + +// virtual +uno::Reference< beans::XPropertySetInfo > SAL_CALL +ResultSet::getPropertySetInfo() +{ + std::unique_lock aGuard( m_pImpl->m_aMutex ); + + if ( !m_pImpl->m_xPropSetInfo.is() ) + m_pImpl->m_xPropSetInfo + = new PropertySetInfo( aPropertyTable, + RESULTSET_PROPERTY_COUNT ); + return m_pImpl->m_xPropSetInfo; +} + + +// virtual +void SAL_CALL ResultSet::setPropertyValue( const OUString& aPropertyName, + const uno::Any& ) +{ + if ( aPropertyName == "RowCount" ) + { + // property is read-only. + throw lang::IllegalArgumentException(); + } + else if ( aPropertyName == "IsRowCountFinal" ) + { + // property is read-only. + throw lang::IllegalArgumentException(); + } + else + { + throw beans::UnknownPropertyException(aPropertyName); + } +} + + +// virtual +uno::Any SAL_CALL ResultSet::getPropertyValue( + const OUString& PropertyName ) +{ + uno::Any aValue; + + if ( PropertyName == "RowCount" ) + { + aValue <<= m_pImpl->m_xDataSupplier->currentCount(); + } + else if ( PropertyName == "IsRowCountFinal" ) + { + aValue <<= m_pImpl->m_xDataSupplier->isCountFinal(); + } + else + { + throw beans::UnknownPropertyException(PropertyName); + } + + return aValue; +} + + +// virtual +void SAL_CALL ResultSet::addPropertyChangeListener( + const OUString& aPropertyName, + const uno::Reference< beans::XPropertyChangeListener >& xListener ) +{ + // Note: An empty property name means a listener for "all" properties. + + std::unique_lock aGuard( m_pImpl->m_aMutex ); + + if ( !aPropertyName.isEmpty() && + aPropertyName != "RowCount" && + aPropertyName != "IsRowCountFinal" ) + throw beans::UnknownPropertyException(aPropertyName); + + if ( !m_pImpl->m_pPropertyChangeListeners ) + m_pImpl->m_pPropertyChangeListeners.reset( + new PropertyChangeListeners()); + + m_pImpl->m_pPropertyChangeListeners->addInterface(aGuard, + aPropertyName, xListener ); +} + + +// virtual +void SAL_CALL ResultSet::removePropertyChangeListener( + const OUString& aPropertyName, + const uno::Reference< beans::XPropertyChangeListener >& xListener ) +{ + std::unique_lock aGuard( m_pImpl->m_aMutex ); + + if ( !aPropertyName.isEmpty() && + aPropertyName != "RowCount" && + aPropertyName != "IsRowCountFinal" ) + throw beans::UnknownPropertyException(aPropertyName); + + if ( m_pImpl->m_pPropertyChangeListeners ) + m_pImpl->m_pPropertyChangeListeners->removeInterface(aGuard, + aPropertyName, xListener ); + +} + + +// virtual +void SAL_CALL ResultSet::addVetoableChangeListener( + const OUString&, + const uno::Reference< beans::XVetoableChangeListener >& ) +{ + // No constrained props, at the moment. +} + + +// virtual +void SAL_CALL ResultSet::removeVetoableChangeListener( + const OUString&, + const uno::Reference< beans::XVetoableChangeListener >& ) +{ + // No constrained props, at the moment. +} + + +// Non-interface methods. + + +void ResultSet::propertyChanged( const beans::PropertyChangeEvent& rEvt ) const +{ + std::unique_lock aGuard( m_pImpl->m_aMutex ); + + if ( !m_pImpl->m_pPropertyChangeListeners ) + return; + + // Notify listeners interested especially in the changed property. + comphelper::OInterfaceContainerHelper4<beans::XPropertyChangeListener>* pPropsContainer + = m_pImpl->m_pPropertyChangeListeners->getContainer(aGuard, + rEvt.PropertyName ); + if ( pPropsContainer ) + { + pPropsContainer->notifyEach(aGuard, &beans::XPropertyChangeListener::propertyChange, rEvt); + } + + // Notify listeners interested in all properties. + pPropsContainer + = m_pImpl->m_pPropertyChangeListeners->getContainer( aGuard, OUString() ); + if ( pPropsContainer ) + { + pPropsContainer->notifyEach( aGuard, &beans::XPropertyChangeListener::propertyChange, rEvt); + } +} + + +void ResultSet::rowCountChanged( sal_uInt32 nOld, sal_uInt32 nNew ) +{ + OSL_ENSURE( nOld < nNew, "ResultSet::rowCountChanged - nOld >= nNew!" ); + + if ( !m_pImpl->m_pPropertyChangeListeners ) + return; + + propertyChanged( + beans::PropertyChangeEvent( + getXWeak(), + "RowCount", + false, + 1001, + uno::Any( nOld ), // old value + uno::Any( nNew ) ) ); // new value +} + + +void ResultSet::rowCountFinal() +{ + if ( !m_pImpl->m_pPropertyChangeListeners ) + return; + + propertyChanged( + beans::PropertyChangeEvent( + getXWeak(), + "IsRowCountFinal", + false, + 1000, + uno:: Any( false ), // old value + uno::Any( true ) ) ); // new value +} + + +const uno::Sequence< beans::Property >& ResultSet::getProperties() const +{ + return m_pImpl->m_aProperties; +} + + +const uno::Reference< css::ucb::XCommandEnvironment >& +ResultSet::getEnvironment() const +{ + return m_pImpl->m_xEnv; +} + +} // namespace ucbhelper + +namespace ucbhelper_impl { + + +// PropertySetInfo Implementation. + + +PropertySetInfo::PropertySetInfo( + const PropertyInfo* pProps, + sal_Int32 nProps ) + : m_aProps( nProps ) +{ + + if ( !nProps ) + return; + + const PropertyInfo* pEntry = pProps; + beans::Property* pProperties = m_aProps.getArray(); + + for ( sal_Int32 n = 0; n < nProps; ++n ) + { + beans::Property& rProp = pProperties[ n ]; + + rProp.Name = OUString::createFromAscii( pEntry->pName ); + rProp.Handle = pEntry->nHandle; + rProp.Type = pEntry->pGetCppuType(); + rProp.Attributes = pEntry->nAttributes; + + pEntry++; + } +} + + + +// XInterface methods. +void SAL_CALL PropertySetInfo::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL PropertySetInfo::release() + noexcept +{ + OWeakObject::release(); +} + +css::uno::Any SAL_CALL PropertySetInfo::queryInterface( + const css::uno::Type & rType ) +{ + css::uno::Any aRet = cppu::queryInterface( rType, + static_cast< lang::XTypeProvider* >(this), + static_cast< beans::XPropertySetInfo* >(this) + ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + +// XTypeProvider methods. + + +XTYPEPROVIDER_IMPL_2( PropertySetInfo, + lang::XTypeProvider, + beans::XPropertySetInfo ); + + +// XPropertySetInfo methods. + + +// virtual +uno::Sequence< beans::Property > SAL_CALL PropertySetInfo::getProperties() +{ + return m_aProps; +} + + +// virtual +beans::Property SAL_CALL PropertySetInfo::getPropertyByName( + const OUString& aName ) +{ + beans::Property aProp; + if ( queryProperty( aName, aProp ) ) + return aProp; + + throw beans::UnknownPropertyException(aName); +} + + +// virtual +sal_Bool SAL_CALL PropertySetInfo::hasPropertyByName( + const OUString& Name ) +{ + beans::Property aProp; + return queryProperty( Name, aProp ); +} + + +bool PropertySetInfo::queryProperty( + std::u16string_view aName, beans::Property& rProp ) const +{ + sal_Int32 nCount = m_aProps.getLength(); + const beans::Property* pProps = m_aProps.getConstArray(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const beans::Property& rCurr = pProps[ n ]; + if ( rCurr.Name == aName ) + { + rProp = rCurr; + return true; + } + } + + return false; +} + +} // namespace ucbhelper_impl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/resultsethelper.cxx b/ucbhelper/source/provider/resultsethelper.cxx new file mode 100644 index 0000000000..788e6811a1 --- /dev/null +++ b/ucbhelper/source/provider/resultsethelper.cxx @@ -0,0 +1,252 @@ +/* -*- 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 + - This implementation is far away from completion. It has no interface + for changes notifications etc. + */ + +#include <com/sun/star/ucb/ListActionType.hpp> +#include <com/sun/star/ucb/ListenerAlreadySetException.hpp> +#include <com/sun/star/ucb/ServiceNotFoundException.hpp> +#include <com/sun/star/ucb/WelcomeDynamicResultSetStruct.hpp> +#include <com/sun/star/ucb/CachedDynamicResultSetStubFactory.hpp> +#include <com/sun/star/ucb/XSourceInitialization.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <ucbhelper/resultsethelper.hxx> +#include <utility> + +#include <osl/diagnose.h> + +using namespace com::sun::star; + + +// ResultSetImplHelper Implementation. + + +namespace ucbhelper { + + +ResultSetImplHelper::ResultSetImplHelper( + uno::Reference< uno::XComponentContext > xContext, + css::ucb::OpenCommandArgument2 aCommand ) +: m_bStatic( false ), + m_bInitDone( false ), + m_aCommand(std::move( aCommand )), + m_xContext(std::move( xContext )) +{ +} + + +// virtual +ResultSetImplHelper::~ResultSetImplHelper() +{ +} + + +// XServiceInfo methods. + +OUString SAL_CALL ResultSetImplHelper::getImplementationName() +{ + return "ResultSetImplHelper"; +} + +sal_Bool SAL_CALL ResultSetImplHelper::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +css::uno::Sequence< OUString > SAL_CALL ResultSetImplHelper::getSupportedServiceNames() +{ + return { DYNAMICRESULTSET_SERVICE_NAME }; +} + +// XComponent methods. + + +// virtual +void SAL_CALL ResultSetImplHelper::dispose() +{ + std::unique_lock aGuard( m_aMutex ); + + if ( m_aDisposeEventListeners.getLength(aGuard) ) + { + lang::EventObject aEvt; + aEvt.Source = static_cast< lang::XComponent * >( this ); + m_aDisposeEventListeners.disposeAndClear( aGuard, aEvt ); + } +} + + +// virtual +void SAL_CALL ResultSetImplHelper::addEventListener( + const uno::Reference< lang::XEventListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + + m_aDisposeEventListeners.addInterface( aGuard, Listener ); +} + + +// virtual +void SAL_CALL ResultSetImplHelper::removeEventListener( + const uno::Reference< lang::XEventListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + + m_aDisposeEventListeners.removeInterface( aGuard, Listener ); +} + + +// XDynamicResultSet methods. + + +// virtual +uno::Reference< sdbc::XResultSet > SAL_CALL +ResultSetImplHelper::getStaticResultSet() +{ + std::unique_lock aGuard( m_aMutex ); + + if ( m_xListener.is() ) + throw css::ucb::ListenerAlreadySetException(); + + init( true ); + return m_xResultSet1; +} + + +// virtual +void SAL_CALL ResultSetImplHelper::setListener( + const uno::Reference< css::ucb::XDynamicResultSetListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + + if ( m_bStatic || m_xListener.is() ) + throw css::ucb::ListenerAlreadySetException(); + + m_xListener = Listener; + + + // Create "welcome event" and send it to listener. + + + // Note: We only have the implementation for a static result set at the + // moment (src590). The dynamic result sets passed to the listener + // are a fake. This implementation will never call "notify" at the + // listener to propagate any changes!!! + + init( false ); + + uno::Any aInfo; + aInfo <<= css::ucb::WelcomeDynamicResultSetStruct( + m_xResultSet1 /* "old" */, + m_xResultSet2 /* "new" */ ); + + uno::Sequence< css::ucb::ListAction > aActions { + css::ucb::ListAction( + 0, // Position; not used + 0, // Count; not used + css::ucb::ListActionType::WELCOME, + aInfo ) }; + aGuard.unlock(); + + Listener->notify( + css::ucb::ListEvent( + getXWeak(), aActions ) ); +} + + +// virtual +sal_Int16 SAL_CALL ResultSetImplHelper::getCapabilities() +{ + // ! css::ucb::ContentResultSetCapability::SORTED + return 0; +} + + +// virtual +void SAL_CALL ResultSetImplHelper::connectToCache( + const uno::Reference< css::ucb::XDynamicResultSet > & xCache ) +{ + if ( m_xListener.is() ) + throw css::ucb::ListenerAlreadySetException(); + + if ( m_bStatic ) + throw css::ucb::ListenerAlreadySetException(); + + uno::Reference< css::ucb::XSourceInitialization > xTarget( xCache, uno::UNO_QUERY ); + if ( xTarget.is() ) + { + uno::Reference< css::ucb::XCachedDynamicResultSetStubFactory > xStubFactory; + try + { + xStubFactory + = css::ucb::CachedDynamicResultSetStubFactory::create( + m_xContext ); + } + catch ( uno::Exception const & ) + { + } + + if ( xStubFactory.is() ) + { + xStubFactory->connectToCache( + this, xCache, m_aCommand.SortingInfo, nullptr ); + return; + } + } + throw css::ucb::ServiceNotFoundException(); +} + + +// Non-interface methods. + + +void ResultSetImplHelper::init( bool bStatic ) +{ + if ( m_bInitDone ) + return; + + if ( bStatic ) + { + // virtual... derived class fills m_xResultSet1 + initStatic(); + + OSL_ENSURE( m_xResultSet1.is(), + "ResultSetImplHelper::init - No 1st result set!" ); + m_bStatic = true; + } + else + { + // virtual... derived class fills m_xResultSet1 and m_xResultSet2 + initDynamic(); + + OSL_ENSURE( m_xResultSet1.is(), + "ResultSetImplHelper::init - No 1st result set!" ); + OSL_ENSURE( m_xResultSet2.is(), + "ResultSetImplHelper::init - No 2nd result set!" ); + m_bStatic = false; + } + m_bInitDone = true; +} + +} // namespace ucbhelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/resultsetmetadata.cxx b/ucbhelper/source/provider/resultsetmetadata.cxx new file mode 100644 index 0000000000..759aaf1e70 --- /dev/null +++ b/ucbhelper/source/provider/resultsetmetadata.cxx @@ -0,0 +1,397 @@ +/* -*- 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 <osl/diagnose.h> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/XArray.hpp> +#include <com/sun/star/sdbc/XBlob.hpp> +#include <com/sun/star/sdbc/XClob.hpp> +#include <com/sun/star/sdbc/XRef.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/ucb/PropertiesManager.hpp> +#include <ucbhelper/resultsetmetadata.hxx> +#include <mutex> + +using namespace com::sun::star::beans; +using namespace com::sun::star::io; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::ucb; +using namespace com::sun::star::uno; +using namespace com::sun::star::util; + + +namespace ucbhelper_impl { + +struct ResultSetMetaData_Impl +{ + std::mutex m_aMutex; + std::vector< ::ucbhelper::ResultSetColumnData > m_aColumnData; + bool m_bObtainedTypes; + + explicit ResultSetMetaData_Impl( sal_Int32 nSize ) + : m_aColumnData( nSize ), m_bObtainedTypes( false ) {} + + explicit ResultSetMetaData_Impl( + std::vector< ::ucbhelper::ResultSetColumnData >&& rColumnData ) + : m_aColumnData( std::move(rColumnData) ), m_bObtainedTypes( false ) {} +}; + +} + +using namespace ucbhelper_impl; + +namespace ucbhelper { + + +// ResultSetMetaData Implementation. + + +ResultSetMetaData::ResultSetMetaData( + const Reference< XComponentContext >& rxContext, + const Sequence< Property >& rProps ) +: m_pImpl( new ResultSetMetaData_Impl( rProps.getLength() ) ), + m_xContext( rxContext ), + m_aProps( rProps ) +{ +} + + +ResultSetMetaData::ResultSetMetaData( + const Reference< XComponentContext >& rxContext, + const Sequence< Property >& rProps, + std::vector< ResultSetColumnData >&& rColumnData ) +: m_pImpl( new ResultSetMetaData_Impl( std::move(rColumnData) ) ), + m_xContext( rxContext ), + m_aProps( rProps ) +{ + OSL_ENSURE( m_pImpl->m_aColumnData.size() == sal_uInt32( rProps.getLength() ), + "ResultSetMetaData ctor - different array sizes!" ); +} + + +// virtual +ResultSetMetaData::~ResultSetMetaData() +{ +} + + +// XResultSetMetaData methods. + + +// virtual +sal_Int32 SAL_CALL ResultSetMetaData::getColumnCount() +{ + return m_aProps.getLength(); +} + + +// virtual +sal_Bool SAL_CALL ResultSetMetaData::isAutoIncrement( sal_Int32 /*column*/ ) +{ + /* + Checks whether column is automatically numbered, which makes it + read-only. + */ + return false; +} + + +// virtual +sal_Bool SAL_CALL ResultSetMetaData::isCaseSensitive( sal_Int32 column ) +{ + if ( ( column < 1 ) || ( column > m_aProps.getLength() ) ) + return false; + + return m_pImpl->m_aColumnData[ column - 1 ].isCaseSensitive; +} + + +// virtual +sal_Bool SAL_CALL ResultSetMetaData::isSearchable( sal_Int32 /*column*/ ) +{ + return false; +} + + +// virtual +sal_Bool SAL_CALL ResultSetMetaData::isCurrency( sal_Int32 /*column*/ ) +{ + return false; +} + + +// virtual +sal_Int32 SAL_CALL ResultSetMetaData::isNullable( sal_Int32 /*column*/ ) +{ + return ColumnValue::NULLABLE; +} + + +// virtual +sal_Bool SAL_CALL ResultSetMetaData::isSigned( sal_Int32 /*column*/ ) +{ + return false; +} + + +// virtual +sal_Int32 SAL_CALL ResultSetMetaData::getColumnDisplaySize( sal_Int32 /*column*/ ) +{ + /* + Gets the normal maximum width in characters for column. + */ + return 16; +} + + +// virtual +OUString SAL_CALL ResultSetMetaData::getColumnLabel( sal_Int32 column ) +{ + /* + Gets the suggested column title for column, to be used in print- + outs and displays. + */ + + if ( ( column < 1 ) || ( column > m_aProps.getLength() ) ) + return OUString(); + + return m_aProps.getConstArray()[ column - 1 ].Name; +} + + +// virtual +OUString SAL_CALL ResultSetMetaData::getColumnName( sal_Int32 column ) +{ + /* + Gets the name of column. + */ + + if ( ( column < 1 ) || ( column > m_aProps.getLength() ) ) + return OUString(); + + return m_aProps.getConstArray()[ column - 1 ].Name; +} + + +// virtual +OUString SAL_CALL ResultSetMetaData::getSchemaName( sal_Int32 /*column*/ ) +{ + /* + Gets the schema name for the table from which column of this + result set was derived. + Because this feature is not widely supported, the return value + for many DBMSs will be an empty string. + */ + return OUString(); +} + + +// virtual +sal_Int32 SAL_CALL ResultSetMetaData::getPrecision( sal_Int32 /*column*/ ) +{ + return -1; +} + + +// virtual +sal_Int32 SAL_CALL ResultSetMetaData::getScale( sal_Int32 /*column*/ ) +{ + return 0; +} + + +// virtual +OUString SAL_CALL ResultSetMetaData::getTableName( sal_Int32 /*column*/ ) +{ + /* + Gets the name of the table from which column of this result set + was derived or "" if there is none (for example, for a join). + Because this feature is not widely supported, the return value + for many DBMSs will be an empty string. + */ + return OUString(); +} + + +// virtual +OUString SAL_CALL ResultSetMetaData::getCatalogName( sal_Int32 /*column*/ ) +{ + /* + Gets the catalog name for the table from which column of this + result set was derived. + Because this feature is not widely supported, the return value + for many DBMSs will be an empty string. + */ + return OUString(); +} + + +// virtual +sal_Int32 SAL_CALL ResultSetMetaData::getColumnType( sal_Int32 column ) +{ + /* + Gets the JDBC type for the value stored in column. ... The STRUCT + and DISTINCT type codes are always returned for structured and + distinct types, regardless of whether the value will be mapped + according to the standard mapping or be a custom mapping. + */ + + if ( ( column < 1 ) || ( column > m_aProps.getLength() ) ) + return DataType::SQLNULL; + + if ( m_aProps.getConstArray()[ column - 1 ].Type + == cppu::UnoType<void>::get() ) + { + // No type given. Try UCB's Properties Manager... + + std::unique_lock aGuard( m_pImpl->m_aMutex ); + + if ( !m_pImpl->m_bObtainedTypes ) + { + try + { + Reference< XPropertySetInfo > xInfo = PropertiesManager::create( m_xContext ); + // Less (remote) calls... + + const Sequence< Property > aProps = xInfo->getProperties(); + + for ( Property& rProp : asNonConstRange(m_aProps) ) + { + auto pProp = std::find_if(aProps.begin(), aProps.end(), + [&rProp](const Property& rProp1) { return rProp.Name == rProp1.Name; }); + if (pProp != aProps.end()) + { + // Found... + rProp.Type = pProp->Type; + } + } + } + catch ( RuntimeException& ) + { + throw; + } + catch ( Exception& ) + { + // createInstance + } + + m_pImpl->m_bObtainedTypes = true; + } + } + + const Type& rType = m_aProps.getConstArray()[ column - 1 ].Type; + sal_Int32 nType = DataType::OTHER; + + if ( rType == cppu::UnoType<OUString>::get() ) + nType = DataType::VARCHAR; // XRow::getString + else if ( rType == cppu::UnoType<bool>::get() ) + nType = DataType::BIT; // XRow::getBoolean + else if ( rType == cppu::UnoType<sal_Int32>::get() ) + nType = DataType::INTEGER; // XRow::getInt + else if ( rType == cppu::UnoType<sal_Int64>::get() ) + nType = DataType::BIGINT; // XRow::getLong + else if ( rType == cppu::UnoType<sal_Int16>::get() ) + nType = DataType::SMALLINT; // XRow::getShort + else if ( rType == cppu::UnoType<sal_Int8>::get() ) + nType = DataType::TINYINT; // XRow::getByte + else if ( rType == cppu::UnoType<float>::get() ) + nType = DataType::REAL; // XRow::getFloat + else if ( rType == cppu::UnoType<double>::get() ) + nType = DataType::DOUBLE; // XRow::getDouble + else if ( rType == cppu::UnoType<Sequence<sal_Int8>>::get() ) + nType = DataType::VARBINARY;// XRow::getBytes + else if ( rType == cppu::UnoType<Date>::get() ) + nType = DataType::DATE; // XRow::getDate + else if ( rType == cppu::UnoType<Time>::get() ) + nType = DataType::TIME; // XRow::getTime + else if ( rType == cppu::UnoType<DateTime>::get() ) + nType = DataType::TIMESTAMP;// XRow::getTimestamp + else if ( rType == cppu::UnoType<XInputStream>::get() ) + nType = DataType::LONGVARBINARY; // XRow::getBinaryStream +// nType = DataType::LONGVARCHAR; // XRow::getCharacterStream + else if ( rType == cppu::UnoType<XClob>::get() ) + nType = DataType::CLOB; // XRow::getClob + else if ( rType == cppu::UnoType<XBlob>::get() ) + nType = DataType::BLOB; // XRow::getBlob + else if ( rType == cppu::UnoType<XArray>::get() ) + nType = DataType::ARRAY;// XRow::getArray + else if ( rType == cppu::UnoType<XRef>::get() ) + nType = DataType::REF;// XRow::getRef + else + nType = DataType::OBJECT;// XRow::getObject + + return nType; +} + + +// virtual +OUString SAL_CALL ResultSetMetaData::getColumnTypeName( sal_Int32 /*column*/ ) +{ + /* + Gets the type name used by this particular data source for the + values stored in column. If the type code for the type of value + stored in column is STRUCT, DISTINCT or JAVA_OBJECT, this method + returns a fully-qualified SQL type name. + */ + return OUString(); +} + + +// virtual +sal_Bool SAL_CALL ResultSetMetaData::isReadOnly( sal_Int32 /*column*/ ) +{ + return true; +} + + +// virtual +sal_Bool SAL_CALL ResultSetMetaData::isWritable( sal_Int32 /*column*/ ) +{ + return false; +} + + +// virtual +sal_Bool SAL_CALL ResultSetMetaData::isDefinitelyWritable( sal_Int32 /*column*/ ) +{ + return false; +} + + +// virtual +OUString SAL_CALL ResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ ) +{ + /* + Returns the fully-qualified name of the service whose instances + are manufactured if XResultSet::getObject is called to retrieve + a value from the column. + */ + return OUString(); +} + +} // namespace ucbhelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/simpleauthenticationrequest.cxx b/ucbhelper/source/provider/simpleauthenticationrequest.cxx new file mode 100644 index 0000000000..972864d9aa --- /dev/null +++ b/ucbhelper/source/provider/simpleauthenticationrequest.cxx @@ -0,0 +1,147 @@ +/* -*- 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 <com/sun/star/ucb/URLAuthenticationRequest.hpp> +#include <ucbhelper/simpleauthenticationrequest.hxx> + +using namespace com::sun::star; +using namespace ucbhelper; + + +SimpleAuthenticationRequest::SimpleAuthenticationRequest( + const OUString & rURL, + const OUString & rServerName, + const OUString & rRealm, + const OUString & rUserName, + const OUString & rPassword, + bool bAllowUseSystemCredentials, + bool bAllowSessionStoring ) +{ + + // Fill request... + ucb::URLAuthenticationRequest aRequest; +// aRequest.Message = // OUString +// aRequest.Context = // XInterface + aRequest.Classification = task::InteractionClassification_ERROR; + aRequest.ServerName = rServerName; +// aRequest.Diagnostic = // OUString + aRequest.HasRealm = !rRealm.isEmpty(); + if ( aRequest.HasRealm ) + aRequest.Realm = rRealm; + aRequest.HasUserName = true; + aRequest.UserName = rUserName; + aRequest.HasPassword = true; + aRequest.Password = rPassword; + aRequest.HasAccount = false; + aRequest.URL = rURL; + + initialize(aRequest, + false, + true, + true, + aRequest.HasAccount, + bAllowUseSystemCredentials, + bAllowSessionStoring ); +} + + +SimpleAuthenticationRequest::SimpleAuthenticationRequest( + const OUString & rURL, + const OUString & rServerName, + EntityType eRealmType, + const OUString & rRealm, + EntityType eUserNameType, + const OUString & rUserName, + EntityType ePasswordType, + const OUString & rPassword) +{ + // Fill request... + ucb::URLAuthenticationRequest aRequest; +// aRequest.Message = // OUString +// aRequest.Context = // XInterface + aRequest.Classification = task::InteractionClassification_ERROR; + aRequest.ServerName = rServerName; +// aRequest.Diagnostic = // OUString + aRequest.HasRealm = eRealmType != ENTITY_NA; + if ( aRequest.HasRealm ) + aRequest.Realm = rRealm; + aRequest.HasUserName = eUserNameType != ENTITY_NA; + if ( aRequest.HasUserName ) + aRequest.UserName = rUserName; + aRequest.HasPassword = ePasswordType != ENTITY_NA; + if ( aRequest.HasPassword ) + aRequest.Password = rPassword; + aRequest.HasAccount = false; + aRequest.URL = rURL; + + initialize(aRequest, + eRealmType == ENTITY_MODIFY, + eUserNameType == ENTITY_MODIFY, + ePasswordType == ENTITY_MODIFY, + false, + false, + true ); +} + + +void SimpleAuthenticationRequest::initialize( + const ucb::URLAuthenticationRequest & rRequest, + bool bCanSetRealm, + bool bCanSetUserName, + bool bCanSetPassword, + bool bCanSetAccount, + bool bAllowUseSystemCredentials, + bool bAllowSessionStoring ) +{ + setRequest( uno::Any( rRequest ) ); + + // Fill continuations... + unsigned int nSize = 2; + + if( bAllowSessionStoring ) + nSize++; + + uno::Sequence< ucb::RememberAuthentication > aRememberModes( nSize ); + auto it = aRememberModes.getArray(); + *it++ = ucb::RememberAuthentication_NO; + + if( bAllowSessionStoring ) + *it++ = ucb::RememberAuthentication_SESSION; + + *it = ucb::RememberAuthentication_PERSISTENT; + + m_xAuthSupplier + = new InteractionSupplyAuthentication( + this, + bCanSetRealm, + bCanSetUserName, + bCanSetPassword, + bCanSetAccount, + aRememberModes, // rRememberPasswordModes + ucb::RememberAuthentication_SESSION, // eDefaultRememberPasswordMode + aRememberModes, // rRememberAccountModes + ucb::RememberAuthentication_SESSION, // eDefaultRememberAccountMode + bAllowUseSystemCredentials // bCanUseSystemCredentials, + ); + + setContinuations( + { new InteractionAbort(this), new InteractionRetry(this), m_xAuthSupplier }); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/simplecertificatevalidationrequest.cxx b/ucbhelper/source/provider/simplecertificatevalidationrequest.cxx new file mode 100644 index 0000000000..e1dba7a35d --- /dev/null +++ b/ucbhelper/source/provider/simplecertificatevalidationrequest.cxx @@ -0,0 +1,42 @@ +/* -*- 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 <com/sun/star/ucb/CertificateValidationRequest.hpp> +#include <ucbhelper/simplecertificatevalidationrequest.hxx> + +using namespace com::sun::star; +using namespace ucbhelper; + + +SimpleCertificateValidationRequest::SimpleCertificateValidationRequest( sal_Int32 lCertificateValidity, + const css::uno::Reference<css::security::XCertificate>& certificate, + const OUString & hostname) +{ + // Fill request... + ucb::CertificateValidationRequest aRequest; + aRequest.CertificateValidity = lCertificateValidity; + aRequest.Certificate = certificate; + aRequest.HostName = hostname; + + setRequest( uno::Any( aRequest ) ); + + setContinuations({ new InteractionAbort(this), new InteractionApprove(this) }); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/simpleinteractionrequest.cxx b/ucbhelper/source/provider/simpleinteractionrequest.cxx new file mode 100644 index 0000000000..d846be5d35 --- /dev/null +++ b/ucbhelper/source/provider/simpleinteractionrequest.cxx @@ -0,0 +1,92 @@ +/* -*- 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 <ucbhelper/simpleinteractionrequest.hxx> +#include <comphelper/sequence.hxx> + +#include <osl/diagnose.h> +#include <rtl/ref.hxx> + +using namespace com::sun::star; +using namespace ucbhelper; + + +SimpleInteractionRequest::SimpleInteractionRequest( + const uno::Any & rRequest, + const ContinuationFlags nContinuations ) +: InteractionRequest( rRequest ) +{ + // Set continuations. + OSL_ENSURE( nContinuations != ContinuationFlags::NONE, + "SimpleInteractionRequest - No continuation!" ); + + std::vector< uno::Reference< task::XInteractionContinuation > > aContinuations; + if ( nContinuations & ContinuationFlags::Abort ) + { + aContinuations.push_back( new InteractionAbort( this ) ); + } + if ( nContinuations & ContinuationFlags::Retry ) + { + aContinuations.push_back( new InteractionRetry( this ) ); + } + if ( nContinuations & ContinuationFlags::Approve ) + { + aContinuations.push_back( new InteractionApprove( this ) ); + } + if ( nContinuations & ContinuationFlags::Disapprove ) + { + aContinuations.push_back( new InteractionDisapprove( this ) ); + } + setContinuations( comphelper::containerToSequence(aContinuations) ); +} + + +ContinuationFlags SimpleInteractionRequest::getResponse() const +{ + rtl::Reference< InteractionContinuation > xSelection = getSelection(); + if ( xSelection.is() ) + { + InteractionContinuation * pSelection = xSelection.get(); + + uno::Reference< task::XInteractionAbort > xAbort( + pSelection, uno::UNO_QUERY ); + if ( xAbort.is() ) + return ContinuationFlags::Abort; + + uno::Reference< task::XInteractionRetry > xRetry( + pSelection, uno::UNO_QUERY ); + if ( xRetry.is() ) + return ContinuationFlags::Retry; + + uno::Reference< task::XInteractionApprove > xApprove( + pSelection, uno::UNO_QUERY ); + if ( xApprove.is() ) + return ContinuationFlags::Approve; + + uno::Reference< task::XInteractionDisapprove > xDisapprove( + pSelection, uno::UNO_QUERY ); + if ( xDisapprove.is() ) + return ContinuationFlags::Disapprove; + + OSL_FAIL( "SimpleInteractionRequest::getResponse - Unknown continuation!" ); + } + return ContinuationFlags::NONE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/simpleioerrorrequest.cxx b/ucbhelper/source/provider/simpleioerrorrequest.cxx new file mode 100644 index 0000000000..0c0857f915 --- /dev/null +++ b/ucbhelper/source/provider/simpleioerrorrequest.cxx @@ -0,0 +1,44 @@ +/* -*- 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 <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include "simpleioerrorrequest.hxx" + +using namespace com::sun::star; +using namespace ucbhelper; + + +SimpleIOErrorRequest::SimpleIOErrorRequest( + const ucb::IOErrorCode eError, + const uno::Sequence< uno::Any > & rArgs, + const OUString & rMessage, + const uno::Reference< ucb::XCommandProcessor > & xContext ) +{ + // Fill request... + ucb::InteractiveAugmentedIOException aRequest( + rMessage, xContext, task::InteractionClassification_ERROR, eError, rArgs); + + setRequest( uno::Any( aRequest ) ); + + // Fill continuations... + setContinuations({ new InteractionAbort(this) }); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/simpleioerrorrequest.hxx b/ucbhelper/source/provider/simpleioerrorrequest.hxx new file mode 100644 index 0000000000..134f10a9aa --- /dev/null +++ b/ucbhelper/source/provider/simpleioerrorrequest.hxx @@ -0,0 +1,65 @@ +/* -*- 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 . + */ + +#ifndef UCBHELPER_SOURCE_PROVIDER_SIMPLEIOERRORREQUEST_HXX +#define UCBHELPER_SOURCE_PROVIDER_SIMPLEIOERRORREQUEST_HXX + +#include <com/sun/star/ucb/IOErrorCode.hpp> +#include <ucbhelper/interactionrequest.hxx> + +namespace com::sun::star::ucb { class XCommandProcessor; } + +namespace ucbhelper { + +/** + * This class implements a simple IO error interaction request. Instances + * can be passed directly to XInteractionHandler::handle(...). Each + * instance contains an InteractiveIOException and one interaction + * continuation: "Abort". + * + * @see css::ucb::InteractiveIOException + * @see InteractionAbort + */ +class SimpleIOErrorRequest final : public ucbhelper::InteractionRequest +{ +public: + /** + * Constructor. + * + * @param xContext contains the command processor that executes the + * command related to the request. + * + * @param eError is the error code to pass along with the request. + * + * qparam rArgs are additional parameters according to the specification + * of the error code. Refer to com/sun/star/ucb/IOErrorCode.idl + * for details. + */ + SimpleIOErrorRequest( const css::ucb::IOErrorCode eError, + const css::uno::Sequence< css::uno::Any > & rArgs, + const OUString & rMessage, + const css::uno::Reference< css::ucb::XCommandProcessor > & xContext + ); +}; + +} // namespace ucbhelper + +#endif /* ! UCBHELPER_SOURCE_PROVIDER_SIMPLEIOERRORREQUEST_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucbhelper/source/provider/simplenameclashresolverequest.cxx b/ucbhelper/source/provider/simplenameclashresolverequest.cxx new file mode 100644 index 0000000000..652bdcdbb1 --- /dev/null +++ b/ucbhelper/source/provider/simplenameclashresolverequest.cxx @@ -0,0 +1,157 @@ +/* -*- 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 <com/sun/star/ucb/NameClashResolveRequest.hpp> +#include <com/sun/star/ucb/XInteractionSupplyName.hpp> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <ucbhelper/simplenameclashresolverequest.hxx> + +using namespace com::sun::star; + +namespace ucbhelper { + +/** + * This class implements a standard interaction continuation, namely the + * interface XInteractionSupplyName. Instances of this class can be passed + * along with an interaction request to indicate the possibility to + * supply a new name. + */ +class InteractionSupplyName : public InteractionContinuation, + public css::lang::XTypeProvider, + public css::ucb::XInteractionSupplyName +{ + OUString m_aName; + +public: + explicit InteractionSupplyName( InteractionRequest * pRequest ) + : InteractionContinuation( pRequest ) {} + + // XInterface + virtual css::uno::Any SAL_CALL + queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL + getTypes() override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL + getImplementationId() override; + + // XInteractionContinuation + virtual void SAL_CALL select() override; + + // XInteractionSupplyName + virtual void SAL_CALL setName( const OUString& Name ) override; + + // Non-interface methods. + + /** + * This method returns the name that was supplied by the interaction + * handler. + * + * @return the name. + */ + const OUString & getName() const { return m_aName; } +}; + +void SAL_CALL InteractionSupplyName::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL InteractionSupplyName::release() + noexcept +{ + OWeakObject::release(); +} + +uno::Any SAL_CALL +InteractionSupplyName::queryInterface( const uno::Type & rType ) +{ + uno::Any aRet = cppu::queryInterface( rType, + static_cast< lang::XTypeProvider * >( this ), + static_cast< task::XInteractionContinuation * >( this ), + static_cast< ucb::XInteractionSupplyName * >( this ) ); + + return aRet.hasValue() + ? aRet : InteractionContinuation::queryInterface( rType ); +} + +uno::Sequence< sal_Int8 > SAL_CALL InteractionSupplyName::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +uno::Sequence< uno::Type > SAL_CALL InteractionSupplyName::getTypes() +{ + static cppu::OTypeCollection s_aCollection( + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<ucb::XInteractionSupplyName>::get() ); + + return s_aCollection.getTypes(); +} + +void SAL_CALL InteractionSupplyName::select() +{ + recordSelection(); +} + +void SAL_CALL +InteractionSupplyName::setName( const OUString& Name ) +{ + m_aName = Name; +} + +SimpleNameClashResolveRequest::~SimpleNameClashResolveRequest() {} + +SimpleNameClashResolveRequest::SimpleNameClashResolveRequest( + const OUString & rTargetFolderURL, + const OUString & rClashingName ) +{ + // Fill request... + ucb::NameClashResolveRequest aRequest; +// aRequest.Message = // OUString +// aRequest.Context = // XInterface + aRequest.Classification = task::InteractionClassification_QUERY; + aRequest.TargetFolderURL = rTargetFolderURL; + aRequest.ClashingName = rClashingName; + aRequest.ProposedNewName = OUString(); + + setRequest( uno::Any( aRequest ) ); + + // Fill continuations... + m_xNameSupplier = new InteractionSupplyName( this ); + + setContinuations({ new InteractionAbort(this), m_xNameSupplier, + new InteractionReplaceExistingData(this) }); +} + +OUString const & SimpleNameClashResolveRequest::getNewName() const +{ + return m_xNameSupplier->getName(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |