Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/ucb/source/ucp/cmis/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 86 kB image not shown  

Quelle  cmis_content.cxx   Sprache: C

 
/* -*- 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 <string_view>

#include <boost/make_shared.hpp>

#include <com/sun/star/beans/IllegalTypeException.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/document/CmisProperty.hpp>
#include <com/sun/star/io/XActiveDataSink.hpp>
#include <com/sun/star/io/XActiveDataStreamer.hpp>
#include <com/sun/star/lang/IllegalAccessException.hpp>
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
#include <com/sun/star/task/InteractionClassification.hpp>
#include <com/sun/star/ucb/ContentInfo.hpp>
#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
#include <com/sun/star/ucb/InsertCommandArgument2.hpp>
#include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
#include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
#include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
#include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
#include <com/sun/star/ucb/MissingInputStreamException.hpp>
#include <com/sun/star/ucb/OpenMode.hpp>
#include <com/sun/star/ucb/UnsupportedCommandException.hpp>
#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
#include <com/sun/star/ucb/XCommandInfo.hpp>
#include <com/sun/star/ucb/XDynamicResultSet.hpp>

#include <comphelper/processfactory.hxx>
#include <comphelper/sequence.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <cppuhelper/queryinterface.hxx>
#include <config_oauth2.h>
#include <o3tl/runtimetooustring.hxx>
#include <sal/log.hxx>
#include <tools/urlobj.hxx>
#include <tools/long.hxx>
#include <ucbhelper/cancelcommandexecution.hxx>
#include <ucbhelper/content.hxx>
#include <ucbhelper/contentidentifier.hxx>
#include <ucbhelper/propertyvalueset.hxx>
#include <ucbhelper/proxydecider.hxx>
#include <ucbhelper/macros.hxx>
#include <sax/tools/converter.hxx>
#include <systools/curlinit.hxx>

#include <utility>

#include "auth_provider.hxx"
#include "cmis_content.hxx"
#include "cmis_provider.hxx"
#include "cmis_resultset.hxx"
#include "cmis_strings.hxx"
#include "std_inputstream.hxx"
#include "std_outputstream.hxx"

#define OUSTR_TO_STDSTR(s) std::string( OUStringToOString( s, RTL_TEXTENCODING_UTF8 ) )
#define STD_TO_OUSTR( str ) OStringToOUString( str, RTL_TEXTENCODING_UTF8 )

using namespace com::sun::star;

namespace
{
    util::DateTime lcl_boostToUnoTime(const boost::posix_time::ptime& boostTime)
    {
        util::DateTime unoTime;
        unoTime.Year = boostTime.date().year();
        unoTime.Month = boostTime.date().month();
        unoTime.Day = boostTime.date().day();
        unoTime.Hours = boostTime.time_of_day().hours();
        unoTime.Minutes = boostTime.time_of_day().minutes();
        unoTime.Seconds = boostTime.time_of_day().seconds();

        // TODO FIXME maybe we should compile with BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
        //            to actually get nanosecond precision in boostTime?
        // use this way rather than total_nanos to avoid overflows with 32-bit long
        const tools::Long ticks = boostTime.time_of_day().fractional_seconds();
        tools::Long nanoSeconds = ticks * ( 1000000000 / boost::posix_time::time_duration::ticks_per_second());

        unoTime.NanoSeconds = nanoSeconds;

        return unoTime;
    }

    uno::Any lcl_cmisPropertyToUno( const libcmis::PropertyPtr& pProperty )
    {
        uno::Any aValue;
        switch ( pProperty->getPropertyType( )->getType( ) )
        {
            default:
            case libcmis::PropertyType::String:
                {
                    auto aCmisStrings = pProperty->getStrings( );
                    uno::Sequence< OUString > aStrings( aCmisStrings.size( ) );
                    OUString* aStringsArr = aStrings.getArray( );
                    sal_Int32 i = 0;
                    for ( const auto& rCmisStr : aCmisStrings )
                    {
                        aStringsArr[i++] = STD_TO_OUSTR( rCmisStr );
                    }
                    aValue <<= aStrings;
                }
                break;
            case libcmis::PropertyType::Integer:
                {
                    auto aCmisLongs = pProperty->getLongs( );
                    uno::Sequence< sal_Int64 > aLongs( aCmisLongs.size( ) );
                    sal_Int64* aLongsArr = aLongs.getArray( );
                    sal_Int32 i = 0;
                    for ( const auto& rCmisLong : aCmisLongs )
                    {
                        aLongsArr[i++] = rCmisLong;
                    }
                    aValue <<= aLongs;
                }
                break;
            case libcmis::PropertyType::Decimal:
                {
                    auto aCmisDoubles = pProperty->getDoubles( );
                    uno::Sequence< double > aDoubles = comphelper::containerToSequence(aCmisDoubles);
                    aValue <<= aDoubles;
                }
                break;
            case libcmis::PropertyType::Bool:
                {
                    auto aCmisBools = pProperty->getBools( );
                    uno::Sequence< sal_Bool > aBools( aCmisBools.size( ) );
                    sal_Bool* aBoolsArr = aBools.getArray( );
                    sal_Int32 i = 0;
                    for ( bool bCmisBool : aCmisBools )
                    {
                        aBoolsArr[i++] = bCmisBool;
                    }
                    aValue <<= aBools;
                }
                break;
            case libcmis::PropertyType::DateTime:
                {
                    auto aCmisTimes = pProperty->getDateTimes( );
                    uno::Sequence< util::DateTime > aTimes( aCmisTimes.size( ) );
                    util::DateTime* aTimesArr = aTimes.getArray( );
                    sal_Int32 i = 0;
                    for ( const auto& rCmisTime : aCmisTimes )
                    {
                        aTimesArr[i++] = lcl_boostToUnoTime( rCmisTime );
                    }
                    aValue <<= aTimes;
                }
                break;
        }
        return aValue;
    }

    libcmis::PropertyPtr lcl_unoToCmisProperty(const document::CmisProperty& prop )
    {
        libcmis::PropertyTypePtr propertyType( new libcmis::PropertyType( ) );

        OUString id = prop.Id;
        OUString name = prop.Name;
        bool bUpdatable = prop.Updatable;
        bool bRequired = prop.Required;
        bool bMultiValued = prop.MultiValued;
        bool bOpenChoice = prop.OpenChoice;
        uno::Any value = prop.Value;
        std::vector< std::string > values;

        libcmis::PropertyType::Type type = libcmis::PropertyType::String;
        if ( prop.Type == CMIS_TYPE_STRING )
        {
            uno::Sequence< OUString > seqValue;
            value >>= seqValue;
            std::transform(std::cbegin(seqValue), std::cend(seqValue), std::back_inserter(values),
                [](const OUString& rValue) -> std::string { return OUSTR_TO_STDSTR( rValue ); });
            type = libcmis::PropertyType::String;
        }
        else if ( prop.Type == CMIS_TYPE_BOOL )
        {
            uno::Sequence< sal_Bool > seqValue;
            value >>= seqValue;
            std::transform(std::cbegin(seqValue), std::cend(seqValue), std::back_inserter(values),
                [](const bool nValue) -> std::string { return std::string( OString::boolean( nValue ) ); });
            type = libcmis::PropertyType::Bool;
        }
        else if ( prop.Type == CMIS_TYPE_INTEGER )
        {
            uno::Sequence< sal_Int64 > seqValue;
            value >>= seqValue;
            std::transform(std::cbegin(seqValue), std::cend(seqValue), std::back_inserter(values),
                [](const sal_Int64 nValue) -> std::string { return std::string( OString::number( nValue ) ); });
            type = libcmis::PropertyType::Integer;
        }
        else if ( prop.Type == CMIS_TYPE_DECIMAL )
        {
            uno::Sequence< double > seqValue;
            value >>= seqValue;
            std::transform(std::cbegin(seqValue), std::cend(seqValue), std::back_inserter(values),
                [](const double fValue) -> std::string { return std::string( OString::number( fValue ) ); });
            type = libcmis::PropertyType::Decimal;
        }
        else if ( prop.Type == CMIS_TYPE_DATETIME )
        {
            uno::Sequence< util::DateTime > seqValue;
            value >>= seqValue;
            std::transform(std::cbegin(seqValue), std::cend(seqValue), std::back_inserter(values),
                [](const util::DateTime& rValue) -> std::string {
                    OUStringBuffer aBuffer;
                    ::sax::Converter::convertDateTime( aBuffer, rValue, nullptr );
                    return OUSTR_TO_STDSTR( aBuffer );
                });
            type = libcmis::PropertyType::DateTime;
        }

        propertyType->setId( OUSTR_TO_STDSTR( id ));
        propertyType->setDisplayName( OUSTR_TO_STDSTR( name ) );
        propertyType->setUpdatable( bUpdatable );
        propertyType->setRequired( bRequired );
        propertyType->setMultiValued( bMultiValued );
        propertyType->setOpenChoice( bOpenChoice );
        propertyType->setType( type );

        libcmis::PropertyPtr property( new libcmis::Property( std::move(propertyType),
                                                              std::move(values) ) );

        return property;
    }

    uno::Sequence< uno::Any > generateErrorArguments( const cmis::URL & rURL )
    {
        uno::Sequence< uno::Any > aArguments{ uno::Any(beans::PropertyValue(
                                                           u"Binding URL"_ustr,
                                                           - 1,
                                                           uno::Any( rURL.getBindingUrl() ),
                                                           beans::PropertyState_DIRECT_VALUE )),
                                              uno::Any(beans::PropertyValue(
                                                           u"Username"_ustr,
                                                           -1,
                                                           uno::Any( rURL.getUsername() ),
                                                           beans::PropertyState_DIRECT_VALUE )),
                                              uno::Any(beans::PropertyValue(
                                                           u"Repository Id"_ustr,
                                                           -1,
                                                           uno::Any( rURL.getRepositoryId() ),
                                                           beans::PropertyState_DIRECT_VALUE )) };

        return aArguments;
    }
}

namespace cmis
{
    Content::Content( const uno::Reference< uno::XComponentContext >& rxContext,
        ContentProvider *pProvider, const uno::Reference< ucb::XContentIdentifier >& Identifier,
        libcmis::ObjectPtr pObject )
        : ContentImplHelper( rxContext, pProvider, Identifier ),
        m_pProvider( pProvider ),
        m_pSession( nullptr ),
        m_pObject(std::move( pObject )),
        m_sURL( Identifier->getContentIdentifier( ) ),
        m_aURL( m_sURL ),
        m_bTransient( false ),
        m_bIsFolder( false )
    {
        SAL_INFO( "ucb.ucp.cmis""Content::Content() " << m_sURL );

        m_sObjectPath = m_aURL.getObjectPath( );
        m_sObjectId = m_aURL.getObjectId( );
    }

    Content::Content( const uno::Reference< uno::XComponentContext >& rxContext, ContentProvider *pProvider,
        const uno::Reference< ucb::XContentIdentifier >& Identifier,
        bool bIsFolder )
        : ContentImplHelper( rxContext, pProvider, Identifier ),
        m_pProvider( pProvider ),
        m_pSession( nullptr ),
        m_sURL( Identifier->getContentIdentifier( ) ),
        m_aURL( m_sURL ),
        m_bTransient( true ),
        m_bIsFolder( bIsFolder )
    {
        SAL_INFO( "ucb.ucp.cmis""Content::Content() " << m_sURL );

        m_sObjectPath = m_aURL.getObjectPath( );
        m_sObjectId = m_aURL.getObjectId( );
    }

    Content::~Content()
    {
    }

    libcmis::Session* Content::getSession( const uno::Reference< ucb::XCommandEnvironment >&&nbsp;xEnv )
    {
        // Set the proxy if needed. We are doing that all times as the proxy data shouldn't be cached.
        ucbhelper::InternetProxyDecider aProxyDecider( m_xContext );
        INetURLObject aBindingUrl( m_aURL.getBindingUrl( ) );
        const OUString sProxy = aProxyDecider.getProxy(
                INetURLObject::GetScheme( aBindingUrl.GetProtocol( ) ), aBindingUrl.GetHost(), aBindingUrl.GetPort() );
        libcmis::SessionFactory::setProxySettings( OUSTR_TO_STDSTR( sProxy ), std::string(), std::string(), std::string() );

        // Look for a cached session, key is binding url + repo id
        OUString sSessionId = m_aURL.getBindingUrl( ) + m_aURL.getRepositoryId( );
        if ( nullptr == m_pSession )
            m_pSession = m_pProvider->getSession( sSessionId, m_aURL.getUsername( ) );

        if ( nullptr == m_pSession )
        {
            // init libcurl callback
            libcmis::SessionFactory::setCurlInitProtocolsFunction(&::InitCurl_easy);

            // Get the auth credentials
            AuthProvider aAuthProvider(xEnv, m_xIdentifier->getContentIdentifier(), m_aURL.getBindingUrl());
            AuthProvider::setXEnv( xEnv );

            auto rUsername = OUSTR_TO_STDSTR( m_aURL.getUsername( ) );
            auto rPassword = OUSTR_TO_STDSTR( m_aURL.getPassword( ) );

            bool bSkipInitialPWAuth = false;
            if (m_aURL.getBindingUrl() == ONEDRIVE_BASE_URL
                || m_aURL.getBindingUrl() == GDRIVE_BASE_URL)
            {
                // skip the initial username and pw-auth prompt, the only supported method is the
                // auth-code-fallback one (login with your browser, copy code into the dialog)
                // TODO: if LO were to listen on localhost for the request, it would be much nicer
                // user experience
                bSkipInitialPWAuth = true;
                rPassword = aAuthProvider.getRefreshToken(rUsername);
            }

            bool bIsDone = false;

            while ( !bIsDone )
            {
                if (bSkipInitialPWAuth || aAuthProvider.authenticationQuery(rUsername, rPassword))
                {
                    // Initiate a CMIS session and register it as we found nothing
                    libcmis::OAuth2DataPtr oauth2Data;
                    if ( m_aURL.getBindingUrl( ) == GDRIVE_BASE_URL )
                    {
                        // reset the skip, so user gets a chance to cancel
                        bSkipInitialPWAuth = false;
                        libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::copyWebAuthCodeFallback);
                        oauth2Data = boost::make_shared<libcmis::OAuth2Data>(
                            GDRIVE_AUTH_URL, GDRIVE_TOKEN_URL,
                            GDRIVE_SCOPE, GDRIVE_REDIRECT_URI,
                            GDRIVE_CLIENT_ID, GDRIVE_CLIENT_SECRET );
                    }
                    if ( m_aURL.getBindingUrl().startsWith( ALFRESCO_CLOUD_BASE_URL ) )
                        oauth2Data = boost::make_shared<libcmis::OAuth2Data>(
                            ALFRESCO_CLOUD_AUTH_URL, ALFRESCO_CLOUD_TOKEN_URL,
                            ALFRESCO_CLOUD_SCOPE, ALFRESCO_CLOUD_REDIRECT_URI,
                            ALFRESCO_CLOUD_CLIENT_ID, ALFRESCO_CLOUD_CLIENT_SECRET );
                    if ( m_aURL.getBindingUrl( ) == ONEDRIVE_BASE_URL )
                    {
                        // reset the skip, so user gets a chance to cancel
                        bSkipInitialPWAuth = false;
                        libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::copyWebAuthCodeFallback);
                        oauth2Data = boost::make_shared<libcmis::OAuth2Data>(
                            ONEDRIVE_AUTH_URL, ONEDRIVE_TOKEN_URL,
                            ONEDRIVE_SCOPE, ONEDRIVE_REDIRECT_URI,
                            ONEDRIVE_CLIENT_ID, ONEDRIVE_CLIENT_SECRET );
                    }
                    try
                    {
                        m_pSession = libcmis::SessionFactory::createSession(
                            OUSTR_TO_STDSTR( m_aURL.getBindingUrl( ) ),
                            rUsername, rPassword, OUSTR_TO_STDSTR( m_aURL.getRepositoryId( ) ), false, std::move(oauth2Data) );

                        if ( m_pSession == nullptr )
                        {
                            // Fail: session was not created
                            ucbhelper::cancelCommandExecution(
                                ucb::IOErrorCode_INVALID_DEVICE,
                                generateErrorArguments(m_aURL),
                                xEnv);
                        }
                        else if ( m_pSession->getRepository() == nullptr )
                        {
                            // Fail: no repository or repository is invalid
                            ucbhelper::cancelCommandExecution(
                                ucb::IOErrorCode_INVALID_DEVICE,
                                generateErrorArguments(m_aURL),
                                xEnv,
                                u"error accessing a repository"_ustr);
                        }
                        else
                        {
                            m_pProvider->registerSession(sSessionId, m_aURL.getUsername( ), m_pSession);
                            if (m_aURL.getBindingUrl() == ONEDRIVE_BASE_URL
                                || m_aURL.getBindingUrl() == GDRIVE_BASE_URL)
                            {
                                aAuthProvider.storeRefreshToken(rUsername, rPassword,
                                                                m_pSession->getRefreshToken());
                            }
                        }

                        bIsDone = true;
                    }
                    catchconst libcmis::Exception & e )
                    {
                        if (e.getType() == "dnsFailed")
                        {
                            uno::Any ex;
                            ex <<= ucb::InteractiveNetworkResolveNameException(
                                    OStringToOUString(e.what(), RTL_TEXTENCODING_UTF8),
                                    getXWeak(),
                                    task::InteractionClassification_ERROR,
                                    m_aURL.getBindingUrl());
                            ucbhelper::cancelCommandExecution(ex, xEnv);
                        }
                        else if (e.getType() == "connectFailed" || e.getType() == "connectTimeout")
                        {
                            uno::Any ex;
                            ex <<= ucb::InteractiveNetworkConnectException(
                                    OStringToOUString(e.what(), RTL_TEXTENCODING_UTF8),
                                    getXWeak(),
                                    task::InteractionClassification_ERROR,
                                    m_aURL.getBindingUrl());
                            ucbhelper::cancelCommandExecution(ex, xEnv);
                        }
                        else if (e.getType() == "transferFailed")
                        {
                            uno::Any ex;
                            ex <<= ucb::InteractiveNetworkReadException(
                                    OStringToOUString(e.what(), RTL_TEXTENCODING_UTF8),
                                    getXWeak(),
                                    task::InteractionClassification_ERROR,
                                    m_aURL.getBindingUrl());
                            ucbhelper::cancelCommandExecution(ex, xEnv);
                        }
                        else if (e.getType() != "permissionDenied")
                        {
                            SAL_INFO("ucb.ucp.cmis""Unexpected libcmis exception: " << e.what());
                            throw;
                        }
                    }
                }
                else
                {
                    // Silently fail as the user cancelled the authentication
                    ucbhelper::cancelCommandExecution(
                                        ucb::IOErrorCode_ABORT,
                                        uno::Sequence< uno::Any >( 0 ),
                                        xEnv );
                    throw uno::RuntimeException( );
                }
            }
        }
        return m_pSession;
    }

    libcmis::ObjectTypePtr const & Content::getObjectType( const uno::Reference< ucb::XCommandEnvironment >& xEnv )
    {
        if ( nullptr == m_pObjectType.get( ) && m_bTransient )
        {
            const std::string typeId = m_bIsFolder ? "cmis:folder" : "cmis:document";
            // The type to create needs to be fetched from the possible children types
            // defined in the parent folder. Then, we'll pick up the first one we find matching
            // cmis:folder or cmis:document (depending what we need to create).
            // The easy case will work in most cases, but not on some servers (like Lotus Live)
            libcmis::Folder* pParent = nullptr;
            bool bTypeRestricted = false;
            try
            {
                pParent = dynamic_cast< libcmis::Folder* >( getObject( xEnv ).get( ) );
            }
            catch ( const libcmis::Exception& )
            {
            }

            if ( pParent )
            {
                std::map< std::string, libcmis::PropertyPtr >& aProperties = pParent->getProperties( );
                std::map< std::string, libcmis::PropertyPtr >::iterator it = aProperties.find( "cmis:allowedChildObjectTypeIds" );
                if ( it != aProperties.end( ) )
                {
                    libcmis::PropertyPtr pProperty = it->second;
                    if ( pProperty )
                    {
                        std::vector< std::string > typesIds = pProperty->getStrings( );
                        for ( const auto& rType : typesIds )
                        {
                            bTypeRestricted = true;
                            libcmis::ObjectTypePtr type = getSession( xEnv )->getType( rType );

                            // FIXME Improve performances by adding getBaseTypeId( ) method to libcmis
                            if ( type->getBaseType( )->getId( ) == typeId )
                            {
                                m_pObjectType = std::move(type);
                                break;
                            }
                        }
                    }
                }
            }

            if ( !bTypeRestricted )
                m_pObjectType = getSession( xEnv )->getType( typeId );
        }
        return m_pObjectType;
    }


    libcmis::ObjectPtr const & Content::getObject( const uno::Reference< ucb::XCommandEnvironment >& xEnv )
    {
        // can't get the session for some reason
        // the recent file opening at start up is an example.
        try
        {
            if ( !getSession( xEnv ) )
                return m_pObject;
        }
        catch ( uno::RuntimeException& )
        {
            return m_pObject;
        }
        if ( !m_pObject.get() )
        {
            if ( !m_sObjectId.isEmpty( ) )
            {
                try
                {
                    m_pObject = getSession( xEnv )->getObject( OUSTR_TO_STDSTR( m_sObjectId ) );
                }
                catch ( const libcmis::Exception& )
                {
                    SAL_INFO( "ucb.ucp.cmis""object: " << OUSTR_TO_STDSTR(m_sObjectId));
                    throw libcmis::Exception( "Object not found" );
                }
            }
            else if (!(m_sObjectPath.isEmpty() || m_sObjectPath == "/"))
            {
                try
                {
                    m_pObject = getSession( xEnv )->getObjectByPath( OUSTR_TO_STDSTR( m_sObjectPath ) );
                }
                catch ( const libcmis::Exception& )
                {
                    // In some cases, getting the object from the path doesn't work,
                    // but getting the parent from its path and the get the child in the list is OK.
                    // It's weird, but needed to handle case where the path isn't the folders/files
                    // names separated by '/' (as in Lotus Live)
                    INetURLObject aParentUrl( m_sURL );
                    std::string sName = OUSTR_TO_STDSTR( aParentUrl.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset ) );
                    aParentUrl.removeSegment( );
                    OUString sParentUrl = aParentUrl.GetMainURL( INetURLObject::DecodeMechanism::NONE );
                    // Avoid infinite recursion if sParentUrl == m_sURL
                    if (sParentUrl != m_sURL)
                    {
                        rtl::Reference<Content> xParent(new Content(m_xContext, m_pProvider, new ucbhelper::ContentIdentifier(sParentUrl)));
                        libcmis::FolderPtr pParentFolder = boost::dynamic_pointer_cast< libcmis::Folder >(xParent->getObject(xEnv));
                        if (pParentFolder)
                        {
                            std::vector< libcmis::ObjectPtr > children = pParentFolder->getChildren();
                            auto it = std::find_if(children.begin(), children.end(),
                                [&sName](const libcmis::ObjectPtr& rChild) { return rChild->getName() == sName; });
                            if (it != children.end())
                                m_pObject = *it;
                        }
                    }

                    if ( !m_pObject )
                        throw libcmis::Exception( "Object not found" );
                }
            }
            else
            {
                m_pObject = getSession( xEnv )->getRootFolder( );
                m_sObjectPath = "/";
                m_sObjectId = OUString( );
            }
        }

        return m_pObject;
    }

    bool Content::isFolder(const uno::Reference< ucb::XCommandEnvironment >& xEnv )
    {
        bool bIsFolder = false;
        try
        {
            libcmis::ObjectPtr obj = getObject( xEnv );
            if ( obj )
                bIsFolder = obj->getBaseType( ) == "cmis:folder";
        }
        catch ( const libcmis::Exception& e )
        {
            SAL_INFO( "ucb.ucp.cmis""Unexpected libcmis exception: " << e.what( ) );

            ucbhelper::cancelCommandExecution(
                            ucb::IOErrorCode_GENERAL,
                            uno::Sequence< uno::Any >( 0 ),
                            xEnv,
                            OUString::createFromAscii( e.what( ) ) );

        }
        return bIsFolder;
    }

    uno::Any Content::getBadArgExcept()
    {
        return uno::Any( lang::IllegalArgumentException(
            u"Wrong argument type!"_ustr,
            getXWeak(), -1) );
    }

    libcmis::ObjectPtr Content::updateProperties(
         const uno::Any& iCmisProps,
         const uno::Reference< ucb::XCommandEnvironment >& xEnv )
    {
        // Convert iCmisProps to Cmis Properties;
        uno::Sequence< document::CmisProperty > aPropsSeq;
        iCmisProps >>= aPropsSeq;
        std::map< std::string, libcmis::PropertyPtr > aProperties;

        for (const auto& rProp : aPropsSeq)
        {
            std::string id = OUSTR_TO_STDSTR( rProp.Id );
            libcmis::PropertyPtr prop = lcl_unoToCmisProperty( rProp );
            aProperties.insert( std::pair<std::string, libcmis::PropertyPtr>( id, prop ) );
        }
        libcmis::ObjectPtr updateObj;
        try
        {
            updateObj = getObject( xEnv )->updateProperties( aProperties );
        }
        catch ( const libcmis::Exception& e )
        {
            SAL_INFO( "ucb.ucp.cmis""Unexpected libcmis exception: "<< e.what( ) );
        }

        return updateObj;
    }

    uno::Reference< sdbc::XRow > Content::getPropertyValues(
            const uno::Sequence< beans::Property >& rProperties,
            const uno::Reference< ucb::XCommandEnvironment >& xEnv )
    {
        rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_xContext );

        forconst beans::Property& rProp : rProperties )
        {
            try
            {
                if ( rProp.Name == "IsDocument" )
                {
                    try
                    {
                        libcmis::ObjectPtr obj = getObject( xEnv );
                        if ( obj )
                            xRow->appendBoolean( rProp, obj->getBaseType( ) == "cmis:document" );
                    }
                    catch ( const libcmis::Exception& )
                    {
                        if ( m_pObjectType.get( ) )
                            xRow->appendBoolean( rProp, getObjectType( xEnv )->getBaseType()->getId( ) == "cmis:document" );
                        else
                            xRow->appendVoid( rProp );
                    }
                }
                else if ( rProp.Name == "IsFolder" )
                {
                    try
                    {
                        libcmis::ObjectPtr obj = getObject( xEnv );
                        if ( obj )
                            xRow->appendBoolean( rProp, obj->getBaseType( ) == "cmis:folder" );
                        else
                            xRow->appendBoolean( rProp, false );
                    }
                    catch ( const libcmis::Exception& )
                    {
                        if ( m_pObjectType.get( ) )
                            xRow->appendBoolean( rProp, getObjectType( xEnv )->getBaseType()->getId( ) == "cmis:folder" );
                        else
                            xRow->appendVoid( rProp );
                    }
                }
                else if ( rProp.Name == "Title" )
                {
                    OUString sTitle;
                    try
                    {
                        sTitle = STD_TO_OUSTR( getObject( xEnv )->getName() );
                    }
                    catch ( const libcmis::Exception& )
                    {
                        if ( !m_pObjectProps.empty() )
                        {
                            std::map< std::string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:name" );
                            if ( it != m_pObjectProps.end( ) )
                            {
                                std::vector< std::string > values = it->second->getStrings( );
                                if ( !values.empty() )
                                    sTitle = STD_TO_OUSTR( values.front( ) );
                            }
                        }
                    }

                    // Nothing worked... get it from the path
                    if ( sTitle.isEmpty( ) )
                    {
                        OUString sPath = m_sObjectPath;

                        // Get rid of the trailing slash problem
                        if ( sPath.endsWith("/") )
                            sPath = sPath.copy( 0, sPath.getLength() - 1 );

                        // Get the last segment
                        sal_Int32 nPos = sPath.lastIndexOf( '/' );
                        if ( nPos >= 0 )
                            sTitle = sPath.copy( nPos + 1 );
                    }

                    if ( !sTitle.isEmpty( ) )
                        xRow->appendString( rProp, sTitle );
                    else
                        xRow->appendVoid( rProp );
                }
                else if ( rProp.Name == "ObjectId" )
                {
                    OUString sId;
                    try
                    {
                        sId = STD_TO_OUSTR( getObject( xEnv )->getId() );
                    }
                    catch ( const libcmis::Exception& )
                    {
                        if ( !m_pObjectProps.empty() )
                        {
                            std::map< std::string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:objectId" );
                            if ( it != m_pObjectProps.end( ) )
                            {
                                std::vector< std::string > values = it->second->getStrings( );
                                if ( !values.empty() )
                                    sId = STD_TO_OUSTR( values.front( ) );
                            }
                        }
                    }

                    if ( !sId.isEmpty( ) )
                        xRow->appendString( rProp, sId );
                    else
                        xRow->appendVoid( rProp );
                }
                else if ( rProp.Name == "TitleOnServer" )
                {
                    xRow->appendString( rProp, m_sObjectPath);
                }
                else if ( rProp.Name == "IsReadOnly" )
                {
                    boost::shared_ptr< libcmis::AllowableActions > allowableActions = getObject( xEnv )->getAllowableActions( );
                    bool bReadOnly = false;
                    if ( !allowableActions->isAllowed( libcmis::ObjectAction::SetContentStream ) &&
                         !allowableActions->isAllowed( libcmis::ObjectAction::CheckIn ) )
                        bReadOnly = true;

                    xRow->appendBoolean( rProp, bReadOnly );
                }
                else if ( rProp.Name == "DateCreated" )
                {
                    util::DateTime aTime = lcl_boostToUnoTime( getObject( xEnv )->getCreationDate( ) );
                    xRow->appendTimestamp( rProp, aTime );
                }
                else if ( rProp.Name == "DateModified" )
                {
                    util::DateTime aTime = lcl_boostToUnoTime( getObject( xEnv )->getLastModificationDate( ) );
                    xRow->appendTimestamp( rProp, aTime );
                }
                else if ( rProp.Name == "Size" )
                {
                    try
                    {
                        libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( xEnv ).get( ) );
                        if ( nullptr != document )
                            xRow->appendLong( rProp, document->getContentLength() );
                        else
                            xRow->appendVoid( rProp );
                    }
                    catch ( const libcmis::Exception& )
                    {
                        xRow->appendVoid( rProp );
                    }
                }
                else if ( rProp.Name == "CreatableContentsInfo" )
                {
                    xRow->appendObject( rProp, uno::Any( queryCreatableContentsInfo( xEnv ) ) );
                }
                else if ( rProp.Name == "MediaType" )
                {
                    try
                    {
                        libcmis::Document* document = dynamic_cast< libcmis::Document* >( getObject( xEnv ).get( ) );
                        if ( nullptr != document )
                            xRow->appendString( rProp, STD_TO_OUSTR( document->getContentType() ) );
                        else
                            xRow->appendVoid( rProp );
                    }
                    catch ( const libcmis::Exception& )
                    {
                        xRow->appendVoid( rProp );
                    }
                }
                else if ( rProp.Name == "IsVolume" )
                {
                    xRow->appendBoolean( rProp, false );
                }
                else if ( rProp.Name == "IsRemote" )
                {
                    xRow->appendBoolean( rProp, false );
                }
                else if ( rProp.Name == "IsRemoveable" )
                {
                    xRow->appendBoolean( rProp, false );
                }
                else if ( rProp.Name == "IsFloppy" )
                {
                    xRow->appendBoolean( rProp, false );
                }
                else if ( rProp.Name == "IsCompactDisc" )
                {
                    xRow->appendBoolean( rProp, false );
                }
                else if ( rProp.Name == "IsHidden" )
                {
                    xRow->appendBoolean( rProp, false );
                }
                else if ( rProp.Name == "TargetURL" )
                {
                    xRow->appendString( rProp, u""_ustr );
                }
                else if ( rProp.Name == "BaseURI" )
                {
                    xRow->appendString( rProp, m_aURL.getBindingUrl( ) );
                }
                else if ( rProp.Name == "CmisProperties" )
                {
                    try
                    {
                        libcmis::ObjectPtr object = getObject( xEnv );
                        std::map< std::string, libcmis::PropertyPtr >& aProperties = object->getProperties( );
                        uno::Sequence< document::CmisProperty > aCmisProperties( aProperties.size( ) );
                        document::CmisProperty* pCmisProps = aCmisProperties.getArray( );
                        sal_Int32 i = 0;
                        for ( const auto& [sId, rProperty] : aProperties )
                        {
                            auto sDisplayName = rProperty->getPropertyType()->getDisplayName( );
                            bool bUpdatable = rProperty->getPropertyType()->isUpdatable( );
                            bool bRequired = rProperty->getPropertyType()->isRequired( );
                            bool bMultiValued = rProperty->getPropertyType()->isMultiValued();
                            bool bOpenChoice = rProperty->getPropertyType()->isOpenChoice();

                            pCmisProps[i].Id = STD_TO_OUSTR( sId );
                            pCmisProps[i].Name = STD_TO_OUSTR( sDisplayName );
                            pCmisProps[i].Updatable = bUpdatable;
                            pCmisProps[i].Required = bRequired;
                            pCmisProps[i].MultiValued = bMultiValued;
                            pCmisProps[i].OpenChoice = bOpenChoice;
                            pCmisProps[i].Value = lcl_cmisPropertyToUno( rProperty );
                            switch ( rProperty->getPropertyType( )->getType( ) )
                            {
                                default:
                                case libcmis::PropertyType::String:
                                    pCmisProps[i].Type = CMIS_TYPE_STRING;
                                break;
                                case libcmis::PropertyType::Integer:
                                    pCmisProps[i].Type = CMIS_TYPE_INTEGER;
                                break;
                                case libcmis::PropertyType::Decimal:
                                    pCmisProps[i].Type = CMIS_TYPE_DECIMAL;
                                break;
                                case libcmis::PropertyType::Bool:
                                    pCmisProps[i].Type = CMIS_TYPE_BOOL;
                                break;
                                case libcmis::PropertyType::DateTime:
                                    pCmisProps[i].Type = CMIS_TYPE_DATETIME;
                                break;
                            }
                            ++i;
                        }
                        xRow->appendObject( rProp.Name, uno::Any( aCmisProperties ) );
                    }
                    catch ( const libcmis::Exception& )
                    {
                        xRow->appendVoid( rProp );
                    }
                }
                else if ( rProp.Name == "IsVersionable" )
                {
                    try
                    {
                        libcmis::ObjectPtr object = getObject( xEnv );
                        bool bIsVersionable = object->getTypeDescription( )->isVersionable( );
                        xRow->appendBoolean( rProp, bIsVersionable );
                    }
                    catch ( const libcmis::Exception& )
                    {
                        xRow->appendVoid( rProp );
                    }
                }
                else if ( rProp.Name == "CanCheckOut" )
                {
                    try
                    {
                        libcmis::ObjectPtr pObject = getObject( xEnv );
                        libcmis::AllowableActionsPtr aAllowables = pObject->getAllowableActions( );
                        bool bAllowed = false;
                        if ( aAllowables )
                        {
                            bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CheckOut );
                        }
                        xRow->appendBoolean( rProp, bAllowed );
                    }
                    catch ( const libcmis::Exception& )
                    {
                        xRow->appendVoid( rProp );
                    }
                }
                else if ( rProp.Name == "CanCancelCheckOut" )
                {
                    try
                    {
                        libcmis::ObjectPtr pObject = getObject( xEnv );
                        libcmis::AllowableActionsPtr aAllowables = pObject->getAllowableActions( );
                        bool bAllowed = false;
                        if ( aAllowables )
                        {
                            bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CancelCheckOut );
                        }
                        xRow->appendBoolean( rProp, bAllowed );
                    }
                    catch ( const libcmis::Exception& )
                    {
                        xRow->appendVoid( rProp );
                    }
                }
                else if ( rProp.Name == "CanCheckIn" )
                {
                    try
                    {
                        libcmis::ObjectPtr pObject = getObject( xEnv );
                        libcmis::AllowableActionsPtr aAllowables = pObject->getAllowableActions( );
                        bool bAllowed = false;
                        if ( aAllowables )
                        {
                            bAllowed = aAllowables->isAllowed( libcmis::ObjectAction::CheckIn );
                        }
                        xRow->appendBoolean( rProp, bAllowed );
                    }
                    catch ( const libcmis::Exception& )
                    {
                        xRow->appendVoid( rProp );
                    }
                }
                else
                    SAL_INFO( "ucb.ucp.cmis""Looking for unsupported property " << rProp.Name );
            }
            catch (const libcmis::Exception&)
            {
                xRow->appendVoid( rProp );
            }
        }

        return xRow;
    }

    uno::Any Content::open(const ucb::OpenCommandArgument2 & rOpenCommand,
        const uno::Reference< ucb::XCommandEnvironment > & xEnv )
    {
        bool bIsFolder = isFolder( xEnv );

        // Handle the case of the non-existing file
        if ( !getObject( xEnv ) )
        {
            uno::Sequence< uno::Any > aArgs{ uno::Any(m_xIdentifier->getContentIdentifier()) };
            uno::Any aErr(
                ucb::InteractiveAugmentedIOException(OUString(), getXWeak(),
                    task::InteractionClassification_ERROR,
                    bIsFolder ? ucb::IOErrorCode_NOT_EXISTING_PATH : ucb::IOErrorCode_NOT_EXISTING, aArgs)
            );

            ucbhelper::cancelCommandExecution(aErr, xEnv);
        }

        uno::Any aRet;

        bool bOpenFolder = (
            ( rOpenCommand.Mode == ucb::OpenMode::ALL ) ||
            ( rOpenCommand.Mode == ucb::OpenMode::FOLDERS ) ||
            ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENTS )
         );

        if ( bOpenFolder && bIsFolder )
        {
            uno::Reference< ucb::XDynamicResultSet > xSet
                = new DynamicResultSet(m_xContext, this, rOpenCommand, xEnv );
            aRet <<= xSet;
        }
        else if ( rOpenCommand.Sink.is() )
        {
            if (
                ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
                ( rOpenCommand.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE )
               )
            {
                ucbhelper::cancelCommandExecution(
                    uno::Any ( ucb::UnsupportedOpenModeException
                        ( OUString(), getXWeak(),
                          sal_Int16( rOpenCommand.Mode ) ) ),
                        xEnv );
            }

            if ( !feedSink( rOpenCommand.Sink, xEnv ) )
            {
                // Note: rOpenCommand.Sink may contain an XStream
                //       implementation. Support for this type of
                //       sink is optional...
                SAL_INFO( "ucb.ucp.cmis""Failed to copy data to sink" );

                ucbhelper::cancelCommandExecution(
                    uno::Any (ucb::UnsupportedDataSinkException
                        ( OUString(), getXWeak(),
                          rOpenCommand.Sink ) ),
                        xEnv );
            }
        }
        else
            SAL_INFO( "ucb.ucp.cmis""Open falling through ..." );

        return aRet;
    }

    OUString Content::checkIn( const ucb::CheckinArgument& rArg,
        const uno::Reference< ucb::XCommandEnvironment > & xEnv )
    {
        ucbhelper::Content aSourceContent( rArg.SourceURL, xEnv, comphelper::getProcessComponentContext( ) );
        uno::Reference< io::XInputStream > xIn = aSourceContent.openStream( );

        libcmis::ObjectPtr object;
        try
        {
            object = getObject( xEnv );
        }
        catch ( const libcmis::Exception& e )
        {
            SAL_INFO( "ucb.ucp.cmis""Unexpected libcmis exception: " << e.what( ) );
            ucbhelper::cancelCommandExecution(
                                ucb::IOErrorCode_GENERAL,
                                uno::Sequence< uno::Any >( 0 ),
                                xEnv,
                                OUString::createFromAscii( e.what() ) );
        }

        libcmis::Document* pPwc = dynamic_cast< libcmis::Document* >( object.get( ) );
        if ( !pPwc )
        {
            ucbhelper::cancelCommandExecution(
                                ucb::IOErrorCode_GENERAL,
                                uno::Sequence< uno::Any >( 0 ),
                                xEnv,
                                u"Checkin only supported by documents"_ustr );
        }

        boost::shared_ptr< std::ostream > pOut( new std::ostringstream ( std::ios_base::binary | std::ios_base::in | std::ios_base::out ) );
        uno::Reference < io::XOutputStream > xOutput = new StdOutputStream( pOut );
        copyData( xIn, xOutput );

        std::map< std::string, libcmis::PropertyPtr > newProperties;
        libcmis::DocumentPtr pDoc;

        try
        {
            pDoc = pPwc->checkIn( rArg.MajorVersion, OUSTR_TO_STDSTR( rArg.VersionComment ), newProperties,
                                  std::move(pOut), OUSTR_TO_STDSTR( rArg.MimeType ), OUSTR_TO_STDSTR( rArg.NewTitle ) );
        }
        catch ( const libcmis::Exception& e )
        {
            SAL_INFO( "ucb.ucp.cmis""Unexpected libcmis exception: " << e.what( ) );
            ucbhelper::cancelCommandExecution(
                                ucb::IOErrorCode_GENERAL,
                                uno::Sequence< uno::Any >( 0 ),
                                xEnv,
                                OUString::createFromAscii( e.what() ) );
        }

        // Get the URL and send it back as a result
        URL aCmisUrl( m_sURL );
        std::vector< std::string > aPaths = pDoc->getPaths( );
        if ( !aPaths.empty() )
        {
            aCmisUrl.setObjectPath(STD_TO_OUSTR(aPaths.front()));
        }
        else
        {
            // We may have unfiled document depending on the server, those
            // won't have any path, use their ID instead
            aCmisUrl.setObjectId(STD_TO_OUSTR(pDoc->getId()));
        }
        return aCmisUrl.asString( );
    }

    OUString Content::checkOut( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
    {
        OUString aRet;
        try
        {
            // Checkout the document if possible
            libcmis::DocumentPtr pDoc = boost::dynamic_pointer_cast< libcmis::Document >( getObject( xEnv ) );
            if ( pDoc.get( ) == nullptr )
            {
                ucbhelper::cancelCommandExecution(
                                    ucb::IOErrorCode_GENERAL,
                                    uno::Sequence< uno::Any >( 0 ),
                                    xEnv,
                                    u"Checkout only supported by documents"_ustr );
            }
            libcmis::DocumentPtr pPwc = pDoc->checkOut( );

            // Compute the URL of the Private Working Copy (PWC)
            URL aCmisUrl( m_sURL );
            std::vector< std::string > aPaths = pPwc->getPaths( );
            if ( !aPaths.empty() )
            {
                aCmisUrl.setObjectPath(STD_TO_OUSTR(aPaths.front()));
            }
            else
            {
                // We may have unfiled PWC depending on the server, those
                // won't have any path, use their ID instead
                auto sId = pPwc->getId( );
                aCmisUrl.setObjectId( STD_TO_OUSTR( sId ) );
            }
            aRet = aCmisUrl.asString( );
        }
        catch ( const libcmis::Exception& e )
        {
            SAL_INFO( "ucb.ucp.cmis""Unexpected libcmis exception: " << e.what( ) );
            ucbhelper::cancelCommandExecution(
                                ucb::IOErrorCode_GENERAL,
                                uno::Sequence< uno::Any >( 0 ),
                                xEnv,
                                o3tl::runtimeToOUString(e.what()));
        }
        return aRet;
    }

    OUString Content::cancelCheckOut( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
    {
        OUString aRet;
        try
        {
            libcmis::DocumentPtr pPwc = boost::dynamic_pointer_cast< libcmis::Document >( getObject( xEnv ) );
            if ( pPwc.get( ) == nullptr )
            {
                ucbhelper::cancelCommandExecution(
                                    ucb::IOErrorCode_GENERAL,
                                    uno::Sequence< uno::Any >( 0 ),
                                    xEnv,
                                    u"CancelCheckout only supported by documents"_ustr );
            }
            pPwc->cancelCheckout( );

            // Get the Original document (latest version)
            std::vector< libcmis::DocumentPtr > aVersions = pPwc->getAllVersions( );
            for ( const auto& rVersion : aVersions )
            {
                libcmis::DocumentPtr pVersion = rVersion;
                std::map< std::string, libcmis::PropertyPtr > aProps = pVersion->getProperties( );
                bool bIsLatestVersion = false;
                std::map< std::string, libcmis::PropertyPtr >::iterator propIt = aProps.find( std::string"cmis:isLatestVersion" ) );
                if ( propIt != aProps.end( ) && !propIt->second->getBools( ).empty( ) )
                {
                    bIsLatestVersion = propIt->second->getBools( ).front( );
                }

                if ( bIsLatestVersion )
                {
                    // Compute the URL of the Document
                    URL aCmisUrl( m_sURL );
                    std::vector< std::string > aPaths = pVersion->getPaths( );
                    if ( !aPaths.empty() )
                    {
                        aCmisUrl.setObjectPath(STD_TO_OUSTR(aPaths.front()));
                    }
                    else
                    {
                        // We may have unfiled doc depending on the server, those
                        // won't have any path, use their ID instead
                        auto sId = pVersion->getId( );
                        aCmisUrl.setObjectId( STD_TO_OUSTR( sId ) );
                    }
                    aRet = aCmisUrl.asString( );
                    break;
                }
            }
        }
        catch ( const libcmis::Exception& e )
        {
            SAL_INFO( "ucb.ucp.cmis""Unexpected libcmis exception: " << e.what( ) );
            ucbhelper::cancelCommandExecution(
                                ucb::IOErrorCode_GENERAL,
                                uno::Sequence< uno::Any >( 0 ),
                                xEnv,
                                o3tl::runtimeToOUString(e.what()));
        }
        return aRet;
    }

    uno::Sequence< document::CmisVersion> Content::getAllVersions( const uno::Reference< ucb::XCommandEnvironment > & xEnv )
    {
        try
        {
            // get the document
            libcmis::DocumentPtr pDoc = boost::dynamic_pointer_cast< libcmis::Document >( getObject( xEnv ) );
            if ( pDoc.get( ) == nullptr )
            {
                ucbhelper::cancelCommandExecution(
                                    ucb::IOErrorCode_GENERAL,
                                    uno::Sequence< uno::Any >( 0 ),
                                    xEnv,
                                    u"Can not get the document"_ustr );
            }
            std::vector< libcmis::DocumentPtr > aCmisVersions = pDoc->getAllVersions( );
            uno::Sequence< document::CmisVersion > aVersions( aCmisVersions.size( ) );
            auto aVersionsRange = asNonConstRange(aVersions);
            int i = 0;
            for ( const auto& rVersion : aCmisVersions )
            {
                libcmis::DocumentPtr pVersion = rVersion;
                aVersionsRange[i].Id = STD_TO_OUSTR( pVersion->getId( ) );
                aVersionsRange[i].Author = STD_TO_OUSTR( pVersion->getCreatedBy( ) );
                aVersionsRange[i].TimeStamp = lcl_boostToUnoTime( pVersion->getLastModificationDate( ) );
                aVersionsRange[i].Comment = STD_TO_OUSTR( pVersion->getStringProperty("cmis:checkinComment") );
                ++i;
            }
            return aVersions;
        }
        catch ( const libcmis::Exception& e )
        {
            SAL_INFO( "ucb.ucp.cmis""Unexpected libcmis exception: " << e.what( ) );
            ucbhelper::cancelCommandExecution(
                    ucb::IOErrorCode_GENERAL,
                    uno::Sequence< uno::Any >( 0 ),
                    xEnv,
                    o3tl::runtimeToOUString(e.what()));
        }
        return uno::Sequence< document::CmisVersion > ( );
    }

    void Content::transfer( const ucb::TransferInfo& rTransferInfo,
        const uno::Reference< ucb::XCommandEnvironment > & xEnv )
    {
        // If the source isn't on the same CMIS repository, then simply copy
        INetURLObject aSourceUrl( rTransferInfo.SourceURL );
        if ( aSourceUrl.GetProtocol() != INetProtocol::Cmis )
        {
            OUString sSrcBindingUrl = URL( rTransferInfo.SourceURL ).getBindingUrl( );
            if ( sSrcBindingUrl != m_aURL.getBindingUrl( ) )
            {
                ucbhelper::cancelCommandExecution(
                    uno::Any(
                        ucb::InteractiveBadTransferURLException(
                            u"Unsupported URL scheme!"_ustr,
                            getXWeak() ) ),
                    xEnv );
            }
        }

        SAL_INFO( "ucb.ucp.cmis""TODO - Content::transfer()" );
    }

    void Content::insert( const uno::Reference< io::XInputStream > & xInputStream,
        bool bReplaceExisting, std::u16string_view rMimeType,
        const uno::Reference< ucb::XCommandEnvironment >& xEnv )
    {
        if ( !xInputStream.is() )
        {
            ucbhelper::cancelCommandExecution( uno::Any
                ( ucb::MissingInputStreamException
                  ( OUString(), getXWeak() ) ),
                xEnv );
        }

        // For transient content, the URL is the one of the parent
        if ( !m_bTransient )
            return;

        OUString sNewPath;

        // Try to get the object from the server if there is any
        libcmis::FolderPtr pFolder;
        try
        {
            pFolder = boost::dynamic_pointer_cast< libcmis::Folder >( getObject( xEnv ) );
        }
        catch ( const libcmis::Exception& )
        {
        }

        if ( pFolder == nullptr )
            return;

        libcmis::ObjectPtr object;
        std::map< std::string, libcmis::PropertyPtr >::iterator it = m_pObjectProps.find( "cmis:name" );
        if ( it == m_pObjectProps.end( ) )
        {
            ucbhelper::cancelCommandExecution( uno::Any
                ( uno::RuntimeException( u"Missing name property"_ustr,
                    getXWeak() ) ),
                xEnv );
        }
        auto newPath = OUSTR_TO_STDSTR( m_sObjectPath );
        if ( !newPath.empty( ) && newPath[ newPath.size( ) - 1 ] != '/' )
            newPath += "/";
        newPath += it->second->getStrings( ).front( );
        try
        {
            if ( !m_sObjectId.isEmpty( ) )
                object = getSession( xEnv )->getObject( OUSTR_TO_STDSTR( m_sObjectId) );
            else
                object = getSession( xEnv )->getObjectByPath( newPath );
            sNewPath = STD_TO_OUSTR( newPath );
        }
        catch ( const libcmis::Exception& )
        {
            // Nothing matched the path
        }

        if ( nullptr != object.get( ) )
        {
            // Are the base type matching?
            if ( object->getBaseType( ) != m_pObjectType->getBaseType( )->getId() )
            {
                ucbhelper::cancelCommandExecution( uno::Any
                    ( uno::RuntimeException( u"Can't change a folder into a document and vice-versa."_ustr,
                        getXWeak() ) ),
                    xEnv );
            }

            // Update the existing object if it's a document
            libcmis::Document* document = dynamic_cast< libcmis::Document* >( object.get( ) );
            if ( nullptr != document )
            {
                boost::shared_ptr< std::ostream > pOut( new std::ostringstream ( std::ios_base::binary | std::ios_base::in | std::ios_base::out ) );
                uno::Reference < io::XOutputStream > xOutput = new StdOutputStream( pOut );
                copyData( xInputStream, xOutput );
                try
                {
                    document->setContentStream( std::move(pOut), OUSTR_TO_STDSTR( rMimeType ), std::string( ), bReplaceExisting );
                }
                catch ( const libcmis::Exception& )
                {
                    ucbhelper::cancelCommandExecution( uno::Any
                        ( uno::RuntimeException( u"Error when setting document content"_ustr,
                            getXWeak() ) ),
                        xEnv );
                }
            }
        }
        else
        {
            // We need to create a brand new object... either folder or document
            bool bIsFolder = getObjectType( xEnv )->getBaseType( )->getId( ) == "cmis:folder";
            setCmisProperty( "cmis:objectTypeId", getObjectType( xEnv )->getId( ), xEnv );

            if ( bIsFolder )
            {
                try
                {
                    pFolder->createFolder( m_pObjectProps );
                    sNewPath = STD_TO_OUSTR( newPath );
                }
                catch ( const libcmis::Exception& )
                {
                    ucbhelper::cancelCommandExecution( uno::Any
                        ( uno::RuntimeException( u"Error when creating folder"_ustr,
                            getXWeak() ) ),
                        xEnv );
                }
            }
            else
            {
                boost::shared_ptr< std::ostream > pOut( new std::ostringstream ( std::ios_base::binary | std::ios_base::in | std::ios_base::out ) );
                uno::Reference < io::XOutputStream > xOutput = new StdOutputStream( pOut );
                copyData( xInputStream, xOutput );
                try
                {
                    pFolder->createDocument( m_pObjectProps, std::move(pOut), OUSTR_TO_STDSTR( rMimeType ), std::string() );
                    sNewPath = STD_TO_OUSTR( newPath );
                }
                catch ( const libcmis::Exception& )
                {
                    ucbhelper::cancelCommandExecution( uno::Any
                        ( uno::RuntimeException( u"Error when creating document"_ustr,
                            getXWeak() ) ),
                        xEnv );
                }
            }
        }

        if ( sNewPath.isEmpty( ) && m_sObjectId.isEmpty( ) )
            return;

        // Update the current content: it's no longer transient
        m_sObjectPath = sNewPath;
        URL aUrl( m_sURL );
        aUrl.setObjectPath( m_sObjectPath );
        aUrl.setObjectId( m_sObjectId );
        m_sURL = aUrl.asString( );
        m_pObject.reset( );
        m_pObjectType.reset( );
        m_pObjectProps.clear( );
        m_bTransient = false;
        inserted();
    }

    const int TRANSFER_BUFFER_SIZE = 65536;

    void Content::copyData(
        const uno::Reference< io::XInputStream >& xIn,
        const uno::Reference< io::XOutputStream >& xOut )
    {
        uno::Sequence< sal_Int8 > theData( TRANSFER_BUFFER_SIZE );

        while ( xIn->readBytes( theData, TRANSFER_BUFFER_SIZE ) > 0 )
            xOut->writeBytes( theData );

        xOut->closeOutput();
    }

    uno::Sequence< uno::Any > Content::setPropertyValues(
            const uno::Sequence< beans::PropertyValue >& rValues,
            const uno::Reference< ucb::XCommandEnvironment >& xEnv )
    {
        try
        {
            // Get the already set properties if possible
            if ( !m_bTransient && getObject( xEnv ).get( ) )
            {
                m_pObjectProps.clear( );
                m_pObjectType = getObject( xEnv )->getTypeDescription();
            }
        }
        catch ( const libcmis::Exception& e )
        {
            SAL_INFO( "ucb.ucp.cmis""Unexpected libcmis exception: " << e.what( ) );
            ucbhelper::cancelCommandExecution(
                                ucb::IOErrorCode_GENERAL,
                                uno::Sequence< uno::Any >( 0 ),
                                xEnv,
                                o3tl::runtimeToOUString(e.what()));
        }

        sal_Int32 nCount = rValues.getLength();
        uno::Sequence< uno::Any > aRet( nCount );
        auto aRetRange = asNonConstRange(aRet);
        bool bChanged = false;
        const beans::PropertyValue* pValues = rValues.getConstArray();
        for ( sal_Int32 n = 0; n < nCount; ++n )
        {
            const beans::PropertyValue& rValue = pValues[ n ];
            if ( rValue.Name == "ContentType" ||
                 rValue.Name == "MediaType" ||
                 rValue.Name == "IsDocument" ||
                 rValue.Name == "IsFolder" ||
                 rValue.Name == "Size" ||
                 rValue.Name == "CreatableContentsInfo" )
            {
                lang::IllegalAccessException e ( u"Property is read-only!"_ustr,
                       getXWeak() );
                aRetRange[ n ] <<= e;
            }
            else if ( rValue.Name == "Title" )
            {
                OUString aNewTitle;
                if (!( rValue.Value >>= aNewTitle ))
                {
                    aRetRange[ n ] <<= beans::IllegalTypeException
                        ( u"Property value has wrong type!"_ustr,
                          getXWeak() );
                    continue;
                }

                if ( aNewTitle.isEmpty() )
                {
                    aRetRange[ n ] <<= lang::IllegalArgumentException
                        ( u"Empty title not allowed!"_ustr,
                          getXWeak(), -1 );
                    continue;

                }

                setCmisProperty( "cmis:name", OUSTR_TO_STDSTR( aNewTitle ), xEnv );
                bChanged = true;
            }
            else
            {
                SAL_INFO( "ucb.ucp.cmis""Couldn't set property: " << rValue.Name );
                lang::IllegalAccessException e ( u"Property is read-only!"_ustr,
                       getXWeak() );
                aRetRange[ n ] <<= e;
            }
        }

        try
        {
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=92 G=94

¤ Dauer der Verarbeitung: 0.20 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.