From 015b29b74aaf16f5bdf6a90f6e7d5c1d210fe281 Mon Sep 17 00:00:00 2001 From: Michael Meeks Date: Thu, 4 Oct 2012 11:25:41 +0100 Subject: re-base on ALv2 code. Includes: clarify Option->Language UI option Patch contributed by Herbert Duerr http://svn.apache.org/viewvc?view=revision&revision=1173991 cws mba34issues01: #i117712#: fix several resource errors introduced by IAccessible2 implementation Patch contributed by Mathias Bauer http://svn.apache.org/viewvc?view=revision&revision=1173991 cws mba34issues01: #i117709#: add missing string resource Patch contributed by Mathias Bauer http://svn.apache.org/viewvc?view=revision&revision=1172348 cws mba34issues01: #i117716#: fix missing resources my removing unused code Patch contributed by Mathias Bauer http://svn.apache.org/viewvc?view=revision&revision=1172345 re-add Crystal, Tango, Oxygen icon theme listings. correct method signature Patch contributed by Jean-Louis 'Hans' Fuchs http://svn.apache.org/viewvc?view=revision&revision=1306725 i#119063 - correct serf integration Patch contributed by Oliver-Rainer Wittmann http://svn.apache.org/viewvc?view=revision&revision=1300521 i#119036 - adapt serf integration -- use transfer-encoding 'chunked' on HTTPS -- switch transfer-encoding between 'chunked' and none on 413 HTTP status code -- refactoring -- improve user experience of certification dialog - only shown once Patch contributed by Oliver-Rainer Wittmann http://svn.apache.org/viewvc?view=revision&revision=1299727 118569: Use whole certification chain for verification. Patch contributed by Andre Fischer http://svn.apache.org/viewvc?view=revision&revision=1295493 serf integration: improve credential input handling Patch contributed by Oliver-Rainer Wittmann http://svn.apache.org/viewvc?view=revision&revision=1294557 warning-free ucb/source/ucp/webdav Patch contributed by Pavel Janik http://svn.apache.org/viewvc?view=revision&revision=1294086 some refactoring to PROPPATCH and PROPFIND requests Patch contributed by Oliver-Rainer Wittmann http://svn.apache.org/viewvc?view=revision&revision=1293281 i#118569: Replace neon with serf Patch contributed by Oliver-Rainer Wittmann http://svn.apache.org/viewvc?view=revision&revision=1292832 http://svn.apache.org/viewvc?view=revision&revision=1292794 remove OS/2 conditionals for now. re-enable webdav unit tests. --- ucb/source/ucp/webdav/AprEnv.cxx | 58 + ucb/source/ucp/webdav/AprEnv.hxx | 50 + ucb/source/ucp/webdav/ContentProperties.cxx | 666 ++++ ucb/source/ucp/webdav/ContentProperties.hxx | 223 ++ ucb/source/ucp/webdav/DAVAuthListener.hxx | 49 + ucb/source/ucp/webdav/DAVAuthListenerImpl.hxx | 74 + ucb/source/ucp/webdav/DAVException.hxx | 171 ++ ucb/source/ucp/webdav/DAVProperties.cxx | 194 ++ ucb/source/ucp/webdav/DAVProperties.hxx | 57 + ucb/source/ucp/webdav/DAVRequestEnvironment.hxx | 58 + ucb/source/ucp/webdav/DAVResource.hxx | 63 + ucb/source/ucp/webdav/DAVResourceAccess.cxx | 1176 +++++++ ucb/source/ucp/webdav/DAVResourceAccess.hxx | 239 ++ ucb/source/ucp/webdav/DAVSession.hxx | 218 ++ ucb/source/ucp/webdav/DAVSessionFactory.cxx | 101 + ucb/source/ucp/webdav/DAVSessionFactory.hxx | 78 + ucb/source/ucp/webdav/DAVTypes.hxx | 81 + ucb/source/ucp/webdav/DateTimeHelper.cxx | 265 ++ ucb/source/ucp/webdav/DateTimeHelper.hxx | 58 + ucb/source/ucp/webdav/PropertyMap.hxx | 61 + ucb/source/ucp/webdav/SerfCallbacks.cxx | 113 + ucb/source/ucp/webdav/SerfCallbacks.hxx | 68 + ucb/source/ucp/webdav/SerfCopyReqProcImpl.cxx | 85 + ucb/source/ucp/webdav/SerfCopyReqProcImpl.hxx | 57 + ucb/source/ucp/webdav/SerfDeleteReqProcImpl.cxx | 70 + ucb/source/ucp/webdav/SerfDeleteReqProcImpl.hxx | 52 + ucb/source/ucp/webdav/SerfGetReqProcImpl.cxx | 187 ++ ucb/source/ucp/webdav/SerfGetReqProcImpl.hxx | 84 + ucb/source/ucp/webdav/SerfHeadReqProcImpl.cxx | 141 + ucb/source/ucp/webdav/SerfHeadReqProcImpl.hxx | 67 + ucb/source/ucp/webdav/SerfInputStream.cxx | 191 ++ ucb/source/ucp/webdav/SerfInputStream.hxx | 121 + ucb/source/ucp/webdav/SerfLockStore.cxx | 241 ++ ucb/source/ucp/webdav/SerfLockStore.hxx | 97 + ucb/source/ucp/webdav/SerfMkColReqProcImpl.cxx | 70 + ucb/source/ucp/webdav/SerfMkColReqProcImpl.hxx | 51 + ucb/source/ucp/webdav/SerfMoveReqProcImpl.cxx | 85 + ucb/source/ucp/webdav/SerfMoveReqProcImpl.hxx | 57 + ucb/source/ucp/webdav/SerfPostReqProcImpl.cxx | 140 + ucb/source/ucp/webdav/SerfPostReqProcImpl.hxx | 76 + ucb/source/ucp/webdav/SerfPropFindReqProcImpl.cxx | 198 ++ ucb/source/ucp/webdav/SerfPropFindReqProcImpl.hxx | 77 + ucb/source/ucp/webdav/SerfPropPatchReqProcImpl.cxx | 183 ++ ucb/source/ucp/webdav/SerfPropPatchReqProcImpl.hxx | 58 + ucb/source/ucp/webdav/SerfPutReqProcImpl.cxx | 101 + ucb/source/ucp/webdav/SerfPutReqProcImpl.hxx | 59 + ucb/source/ucp/webdav/SerfRequestProcessor.cxx | 553 ++++ ucb/source/ucp/webdav/SerfRequestProcessor.hxx | 182 ++ ucb/source/ucp/webdav/SerfRequestProcessorImpl.cxx | 116 + ucb/source/ucp/webdav/SerfRequestProcessorImpl.hxx | 72 + .../ucp/webdav/SerfRequestProcessorImplFac.cxx | 224 ++ .../ucp/webdav/SerfRequestProcessorImplFac.hxx | 115 + ucb/source/ucp/webdav/SerfSession.cxx | 1603 ++++++++++ ucb/source/ucp/webdav/SerfSession.hxx | 325 ++ ucb/source/ucp/webdav/SerfTypes.hxx | 37 + ucb/source/ucp/webdav/SerfUri.cxx | 279 ++ ucb/source/ucp/webdav/SerfUri.hxx | 102 + ucb/source/ucp/webdav/UCBDeadPropertyValue.cxx | 543 ++++ ucb/source/ucp/webdav/UCBDeadPropertyValue.hxx | 61 + ucb/source/ucp/webdav/ucpdav.xml | 128 + ucb/source/ucp/webdav/ucpdav1.component | 27 + ucb/source/ucp/webdav/webdavcontent.cxx | 3245 ++++++++++++++++++++ ucb/source/ucp/webdav/webdavcontent.hxx | 296 ++ ucb/source/ucp/webdav/webdavcontentcaps.cxx | 659 ++++ ucb/source/ucp/webdav/webdavdatasupplier.cxx | 507 +++ ucb/source/ucp/webdav/webdavdatasupplier.hxx | 78 + ucb/source/ucp/webdav/webdavprovider.cxx | 225 ++ ucb/source/ucp/webdav/webdavprovider.hxx | 116 + ucb/source/ucp/webdav/webdavresponseparser.cxx | 888 ++++++ ucb/source/ucp/webdav/webdavresponseparser.hxx | 43 + ucb/source/ucp/webdav/webdavresultset.cxx | 90 + ucb/source/ucp/webdav/webdavresultset.hxx | 55 + ucb/source/ucp/webdav/webdavservices.cxx | 71 + 73 files changed, 17309 insertions(+) create mode 100644 ucb/source/ucp/webdav/AprEnv.cxx create mode 100644 ucb/source/ucp/webdav/AprEnv.hxx create mode 100644 ucb/source/ucp/webdav/ContentProperties.cxx create mode 100644 ucb/source/ucp/webdav/ContentProperties.hxx create mode 100644 ucb/source/ucp/webdav/DAVAuthListener.hxx create mode 100644 ucb/source/ucp/webdav/DAVAuthListenerImpl.hxx create mode 100644 ucb/source/ucp/webdav/DAVException.hxx create mode 100644 ucb/source/ucp/webdav/DAVProperties.cxx create mode 100644 ucb/source/ucp/webdav/DAVProperties.hxx create mode 100644 ucb/source/ucp/webdav/DAVRequestEnvironment.hxx create mode 100644 ucb/source/ucp/webdav/DAVResource.hxx create mode 100644 ucb/source/ucp/webdav/DAVResourceAccess.cxx create mode 100644 ucb/source/ucp/webdav/DAVResourceAccess.hxx create mode 100644 ucb/source/ucp/webdav/DAVSession.hxx create mode 100644 ucb/source/ucp/webdav/DAVSessionFactory.cxx create mode 100644 ucb/source/ucp/webdav/DAVSessionFactory.hxx create mode 100644 ucb/source/ucp/webdav/DAVTypes.hxx create mode 100644 ucb/source/ucp/webdav/DateTimeHelper.cxx create mode 100644 ucb/source/ucp/webdav/DateTimeHelper.hxx create mode 100644 ucb/source/ucp/webdav/PropertyMap.hxx create mode 100644 ucb/source/ucp/webdav/SerfCallbacks.cxx create mode 100644 ucb/source/ucp/webdav/SerfCallbacks.hxx create mode 100644 ucb/source/ucp/webdav/SerfCopyReqProcImpl.cxx create mode 100644 ucb/source/ucp/webdav/SerfCopyReqProcImpl.hxx create mode 100644 ucb/source/ucp/webdav/SerfDeleteReqProcImpl.cxx create mode 100644 ucb/source/ucp/webdav/SerfDeleteReqProcImpl.hxx create mode 100644 ucb/source/ucp/webdav/SerfGetReqProcImpl.cxx create mode 100644 ucb/source/ucp/webdav/SerfGetReqProcImpl.hxx create mode 100644 ucb/source/ucp/webdav/SerfHeadReqProcImpl.cxx create mode 100644 ucb/source/ucp/webdav/SerfHeadReqProcImpl.hxx create mode 100644 ucb/source/ucp/webdav/SerfInputStream.cxx create mode 100644 ucb/source/ucp/webdav/SerfInputStream.hxx create mode 100644 ucb/source/ucp/webdav/SerfLockStore.cxx create mode 100644 ucb/source/ucp/webdav/SerfLockStore.hxx create mode 100644 ucb/source/ucp/webdav/SerfMkColReqProcImpl.cxx create mode 100644 ucb/source/ucp/webdav/SerfMkColReqProcImpl.hxx create mode 100644 ucb/source/ucp/webdav/SerfMoveReqProcImpl.cxx create mode 100644 ucb/source/ucp/webdav/SerfMoveReqProcImpl.hxx create mode 100644 ucb/source/ucp/webdav/SerfPostReqProcImpl.cxx create mode 100644 ucb/source/ucp/webdav/SerfPostReqProcImpl.hxx create mode 100644 ucb/source/ucp/webdav/SerfPropFindReqProcImpl.cxx create mode 100644 ucb/source/ucp/webdav/SerfPropFindReqProcImpl.hxx create mode 100644 ucb/source/ucp/webdav/SerfPropPatchReqProcImpl.cxx create mode 100644 ucb/source/ucp/webdav/SerfPropPatchReqProcImpl.hxx create mode 100644 ucb/source/ucp/webdav/SerfPutReqProcImpl.cxx create mode 100644 ucb/source/ucp/webdav/SerfPutReqProcImpl.hxx create mode 100644 ucb/source/ucp/webdav/SerfRequestProcessor.cxx create mode 100644 ucb/source/ucp/webdav/SerfRequestProcessor.hxx create mode 100644 ucb/source/ucp/webdav/SerfRequestProcessorImpl.cxx create mode 100644 ucb/source/ucp/webdav/SerfRequestProcessorImpl.hxx create mode 100644 ucb/source/ucp/webdav/SerfRequestProcessorImplFac.cxx create mode 100644 ucb/source/ucp/webdav/SerfRequestProcessorImplFac.hxx create mode 100644 ucb/source/ucp/webdav/SerfSession.cxx create mode 100644 ucb/source/ucp/webdav/SerfSession.hxx create mode 100644 ucb/source/ucp/webdav/SerfTypes.hxx create mode 100644 ucb/source/ucp/webdav/SerfUri.cxx create mode 100644 ucb/source/ucp/webdav/SerfUri.hxx create mode 100644 ucb/source/ucp/webdav/UCBDeadPropertyValue.cxx create mode 100644 ucb/source/ucp/webdav/UCBDeadPropertyValue.hxx create mode 100644 ucb/source/ucp/webdav/ucpdav.xml create mode 100644 ucb/source/ucp/webdav/ucpdav1.component create mode 100644 ucb/source/ucp/webdav/webdavcontent.cxx create mode 100644 ucb/source/ucp/webdav/webdavcontent.hxx create mode 100644 ucb/source/ucp/webdav/webdavcontentcaps.cxx create mode 100644 ucb/source/ucp/webdav/webdavdatasupplier.cxx create mode 100644 ucb/source/ucp/webdav/webdavdatasupplier.hxx create mode 100644 ucb/source/ucp/webdav/webdavprovider.cxx create mode 100644 ucb/source/ucp/webdav/webdavprovider.hxx create mode 100644 ucb/source/ucp/webdav/webdavresponseparser.cxx create mode 100644 ucb/source/ucp/webdav/webdavresponseparser.hxx create mode 100644 ucb/source/ucp/webdav/webdavresultset.cxx create mode 100644 ucb/source/ucp/webdav/webdavresultset.hxx create mode 100644 ucb/source/ucp/webdav/webdavservices.cxx (limited to 'ucb/source/ucp/webdav') diff --git a/ucb/source/ucp/webdav/AprEnv.cxx b/ucb/source/ucp/webdav/AprEnv.cxx new file mode 100644 index 000000000000..4353cee7d006 --- /dev/null +++ b/ucb/source/ucp/webdav/AprEnv.cxx @@ -0,0 +1,58 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include + +namespace apr_environment +{ + +AprEnv::AprEnv() + : mpAprPool( 0 ) +{ + apr_initialize(); + + apr_pool_create(&mpAprPool, NULL); +} + +AprEnv::~AprEnv() +{ + apr_pool_destroy(mpAprPool); + + apr_terminate(); +} + +/* static */ +AprEnv* AprEnv::getAprEnv() +{ + static AprEnv rAprEnv; + + return &rAprEnv; +} + +apr_pool_t* AprEnv::getAprPool() +{ + return mpAprPool; +} + +} // namespace apr_environment + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/AprEnv.hxx b/ucb/source/ucp/webdav/AprEnv.hxx new file mode 100644 index 000000000000..a887256bf6a4 --- /dev/null +++ b/ucb/source/ucp/webdav/AprEnv.hxx @@ -0,0 +1,50 @@ +/* -*- 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 INCLUDED_APRENV_HXX +#define INCLUDED_APRENV_HXX + +#include + +namespace apr_environment +{ + +// singleton class providing environment for APR libraries +class AprEnv +{ + public: + ~AprEnv(); + + static AprEnv* getAprEnv(); + + apr_pool_t* getAprPool(); + + private: + apr_pool_t* mpAprPool; + + AprEnv(); + +}; + +} // namespace apr_environment + +#endif // INCLUDED_APRENV_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/ContentProperties.cxx b/ucb/source/ucp/webdav/ContentProperties.cxx new file mode 100644 index 000000000000..a268acd25d73 --- /dev/null +++ b/ucb/source/ucp/webdav/ContentProperties.cxx @@ -0,0 +1,666 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ +#include +#include +#include "SerfUri.hxx" +#include "DAVResource.hxx" +#include "DAVProperties.hxx" +#include "DateTimeHelper.hxx" +#include "webdavprovider.hxx" +#include "ContentProperties.hxx" + +using namespace com::sun::star; +using namespace http_dav_ucp; + +/* +============================================================================= + + Property Mapping + +============================================================================= +HTTP (entity header) WebDAV (property) UCB (property) +============================================================================= + +Allow +Content-Encoding +Content-Language getcontentlanguage +Content-Length getcontentlength Size +Content-Location +Content-MD5 +Content-Range +Content-Type getcontenttype MediaType +Expires +Last-Modified getlastmodified DateModified + creationdate DateCreated + resourcetype IsFolder,IsDocument,ContentType + displayname +ETag (actually getetag +a response header ) + lockdiscovery + supportedlock + source + Title (always taken from URI) + +============================================================================= + +Important: HTTP headers will not be mapped to DAV properties; only to UCB + properties. (Content-Length,Content-Type,Last-Modified) +*/ + +//========================================================================= +//========================================================================= +// +// ContentProperties Implementation. +// +//========================================================================= +//========================================================================= + +// static member! +uno::Any ContentProperties::m_aEmptyAny; + +ContentProperties::ContentProperties( const DAVResource& rResource ) +: m_xProps( new PropertyValueMap ), + m_bTrailingSlash( false ) +{ + OSL_ENSURE( rResource.uri.getLength(), + "ContentProperties ctor - Empty resource URI!" ); + + // Title + try + { + SerfUri aURI( rResource.uri ); + m_aEscapedTitle = aURI.GetPathBaseName(); + + (*m_xProps)[ rtl::OUString::createFromAscii( "Title" ) ] + = PropertyValue( + uno::makeAny( aURI.GetPathBaseNameUnescaped() ), true ); + } + catch ( DAVException const & ) + { + (*m_xProps)[ rtl::OUString::createFromAscii( "Title" ) ] + = PropertyValue( + uno::makeAny( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "*** unknown ***" ) ) ), + true ); + } + + std::vector< DAVPropertyValue >::const_iterator it + = rResource.properties.begin(); + std::vector< DAVPropertyValue >::const_iterator end + = rResource.properties.end(); + + while ( it != end ) + { + addProperty( (*it) ); + ++it; + } + + if ( rResource.uri.getStr()[ rResource.uri.getLength() - 1 ] + == sal_Unicode( '/' ) ) + m_bTrailingSlash = sal_True; +} + +//========================================================================= +ContentProperties::ContentProperties( + const rtl::OUString & rTitle, sal_Bool bFolder ) +: m_xProps( new PropertyValueMap ), + m_bTrailingSlash( sal_False ) +{ + (*m_xProps)[ rtl::OUString::createFromAscii( "Title" ) ] + = PropertyValue( uno::makeAny( rTitle ), true ); + (*m_xProps)[ rtl::OUString::createFromAscii( "IsFolder" ) ] + = PropertyValue( uno::makeAny( bFolder ), true ); + (*m_xProps)[ rtl::OUString::createFromAscii( "IsDocument" ) ] + = PropertyValue( uno::makeAny( sal_Bool( !bFolder ) ), true ); +} + +//========================================================================= +ContentProperties::ContentProperties( const rtl::OUString & rTitle ) +: m_xProps( new PropertyValueMap ), + m_bTrailingSlash( sal_False ) +{ + (*m_xProps)[ rtl::OUString::createFromAscii( "Title" ) ] + = PropertyValue( uno::makeAny( rTitle ), true ); +} + +//========================================================================= +ContentProperties::ContentProperties() +: m_xProps( new PropertyValueMap ), + m_bTrailingSlash( sal_False ) +{ +} + +//========================================================================= +ContentProperties::ContentProperties( const ContentProperties & rOther ) +: m_aEscapedTitle( rOther.m_aEscapedTitle ), + m_xProps( rOther.m_xProps.get() + ? new PropertyValueMap( *rOther.m_xProps ) + : new PropertyValueMap ), + m_bTrailingSlash( rOther.m_bTrailingSlash ) +{ +} + +//========================================================================= +bool ContentProperties::contains( const rtl::OUString & rName ) const +{ + if ( get( rName ) ) + return true; + else + return false; +} + +//========================================================================= +const uno::Any & ContentProperties::getValue( + const rtl::OUString & rName ) const +{ + const PropertyValue * pProp = get( rName ); + if ( pProp ) + return pProp->value(); + else + return m_aEmptyAny; +} + +//========================================================================= +const PropertyValue * ContentProperties::get( + const rtl::OUString & rName ) const +{ + PropertyValueMap::const_iterator it = m_xProps->find( rName ); + const PropertyValueMap::const_iterator end = m_xProps->end(); + + if ( it == end ) + { + it = m_xProps->begin(); + while ( it != end ) + { + if ( (*it).first.equalsIgnoreAsciiCase( rName ) ) + return &(*it).second; + + ++it; + } + return 0; + } + else + return &(*it).second; +} + +//========================================================================= +// static +void ContentProperties::UCBNamesToDAVNames( + const uno::Sequence< beans::Property > & rProps, + std::vector< rtl::OUString > & propertyNames, + bool bIncludeUnmatched /* = true */ ) +{ + ////////////////////////////////////////////////////////////// + // Assemble list of DAV properties to obtain from server. + // Append DAV properties needed to obtain requested UCB props. + ////////////////////////////////////////////////////////////// + + // DAV UCB + // creationdate <- DateCreated + // getlastmodified <- DateModified + // getcontenttype <- MediaType + // getcontentlength <- Size + // resourcetype <- IsFolder, IsDocument, ContentType + // (taken from URI) <- Title + + sal_Bool bCreationDate = sal_False; + sal_Bool bLastModified = sal_False; + sal_Bool bContentType = sal_False; + sal_Bool bContentLength = sal_False; + sal_Bool bResourceType = sal_False; + + sal_Int32 nCount = rProps.getLength(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const beans::Property & rProp = rProps[ n ]; + + if ( rProp.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) + { + // Title is always obtained from resource's URI. + continue; + } + else if ( rProp.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) + || + ( rProp.Name == DAVProperties::CREATIONDATE ) ) + { + if ( !bCreationDate ) + { + propertyNames.push_back( DAVProperties::CREATIONDATE ); + bCreationDate = sal_True; + } + } + else if ( rProp.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) + || + ( rProp.Name == DAVProperties::GETLASTMODIFIED ) ) + { + if ( !bLastModified ) + { + propertyNames.push_back( + DAVProperties::GETLASTMODIFIED ); + bLastModified = sal_True; + } + } + else if ( rProp.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) + || + ( rProp.Name == DAVProperties::GETCONTENTTYPE ) ) + { + if ( !bContentType ) + { + propertyNames.push_back( + DAVProperties::GETCONTENTTYPE ); + bContentType = sal_True; + } + } + else if ( rProp.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "Size" ) ) + || + ( rProp.Name == DAVProperties::GETCONTENTLENGTH ) ) + { + if ( !bContentLength ) + { + propertyNames.push_back( + DAVProperties::GETCONTENTLENGTH ); + bContentLength = sal_True; + } + } + else if ( rProp.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) + || + rProp.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) + || + rProp.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) + || + ( rProp.Name == DAVProperties::RESOURCETYPE ) ) + { + if ( !bResourceType ) + { + propertyNames.push_back( DAVProperties::RESOURCETYPE ); + bResourceType = sal_True; + } + } + else + { + if ( bIncludeUnmatched ) + propertyNames.push_back( rProp.Name ); + } + } +} + +//========================================================================= +// static +void ContentProperties::UCBNamesToHTTPNames( + const uno::Sequence< beans::Property > & rProps, + std::vector< rtl::OUString > & propertyNames, + bool bIncludeUnmatched /* = true */ ) +{ + ////////////////////////////////////////////////////////////// + // Assemble list of HTTP header names to obtain from server. + // Append HTTP headers needed to obtain requested UCB props. + ////////////////////////////////////////////////////////////// + + // HTTP UCB + // Last-Modified <- DateModified + // Content-Type <- MediaType + // Content-Length <- Size + + sal_Int32 nCount = rProps.getLength(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const beans::Property & rProp = rProps[ n ]; + + if ( rProp.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) ) + { + propertyNames.push_back( + rtl::OUString::createFromAscii( "Last-Modified" ) ); + } + else if ( rProp.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ) + { + propertyNames.push_back( + rtl::OUString::createFromAscii( "Content-Type" ) ); + } + else if ( rProp.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "Size" ) ) ) + { + propertyNames.push_back( + rtl::OUString::createFromAscii( "Content-Length" ) ); + } + else + { + if ( bIncludeUnmatched ) + propertyNames.push_back( rProp.Name ); + } + } +} + +//========================================================================= +bool ContentProperties::containsAllNames( + const uno::Sequence< beans::Property >& rProps, + std::vector< rtl::OUString > & rNamesNotContained ) const +{ + rNamesNotContained.clear(); + + sal_Int32 nCount = rProps.getLength(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const rtl::OUString & rName = rProps[ n ].Name; + if ( !contains( rName ) ) + { + // Not found. + rNamesNotContained.push_back( rName ); + } + } + + return ( rNamesNotContained.size() == 0 ); +} + +//========================================================================= +void ContentProperties::addProperties( + const std::vector< rtl::OUString > & rProps, + const ContentProperties & rContentProps ) +{ + std::vector< rtl::OUString >::const_iterator it = rProps.begin(); + std::vector< rtl::OUString >::const_iterator end = rProps.end(); + + while ( it != end ) + { + const rtl::OUString & rName = (*it); + + if ( !contains( rName ) ) // ignore duplicates + { + const PropertyValue * pProp = rContentProps.get( rName ); + if ( pProp ) + { + // Add it. + addProperty( rName, pProp->value(), pProp->isCaseSensitive() ); + } + else + { + addProperty( rName, uno::Any(), false ); + } + } + ++it; + } +} + +//========================================================================= +void ContentProperties::addProperties( const ContentProperties & rProps ) +{ + PropertyValueMap::const_iterator it = rProps.m_xProps->begin(); + const PropertyValueMap::const_iterator end = rProps.m_xProps->end(); + + while ( it != end ) + { + addProperty( + (*it).first, (*it).second.value(), (*it).second.isCaseSensitive() ); + ++it; + } +} + +//========================================================================= +void ContentProperties::addProperties( + const std::vector< DAVPropertyValue > & rProps ) +{ + std::vector< DAVPropertyValue >::const_iterator it = rProps.begin(); + const std::vector< DAVPropertyValue >::const_iterator end = rProps.end(); + + while ( it != end ) + { + addProperty( (*it) ); + ++it; + } +} + +//========================================================================= +void ContentProperties::addProperty( const DAVPropertyValue & rProp ) +{ + addProperty( rProp.Name, rProp.Value, rProp.IsCaseSensitive ); +} + +//========================================================================= +void ContentProperties::addProperty( const rtl::OUString & rName, + const com::sun::star::uno::Any & rValue, + bool bIsCaseSensitive ) +{ + if ( rName.equals( DAVProperties::CREATIONDATE ) ) + { + // Map DAV:creationdate to UCP:DateCreated + rtl::OUString aValue; + rValue >>= aValue; + util::DateTime aDate; + DateTimeHelper::convert( aValue, aDate ); + + (*m_xProps)[ rtl::OUString::createFromAscii( "DateCreated" ) ] + = PropertyValue( uno::makeAny( aDate ), true ); + } + // else if ( rName.equals( DAVProperties::DISPLAYNAME ) ) + // { + // } + // else if ( rName.equals( DAVProperties::GETCONTENTLANGUAGE ) ) + // { + // } + else if ( rName.equals( DAVProperties::GETCONTENTLENGTH ) ) + { + // Map DAV:getcontentlength to UCP:Size + rtl::OUString aValue; + rValue >>= aValue; + + (*m_xProps)[ rtl::OUString::createFromAscii( "Size" ) ] + = PropertyValue( uno::makeAny( aValue.toInt64() ), true ); + } + else if ( rName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "Content-Length" ) ) ) + { + // Do NOT map Content-Lenght entity header to DAV:getcontentlength! + // Only DAV resources have this property. + + // Map Content-Length entity header to UCP:Size + rtl::OUString aValue; + rValue >>= aValue; + + (*m_xProps)[ rtl::OUString::createFromAscii( "Size" ) ] + = PropertyValue( uno::makeAny( aValue.toInt64() ), true ); + } + else if ( rName.equals( DAVProperties::GETCONTENTTYPE ) ) + { + // Map DAV:getcontenttype to UCP:MediaType (1:1) + (*m_xProps)[ rtl::OUString::createFromAscii( "MediaType" ) ] + = PropertyValue( rValue, true ); + } + else if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Content-Type" ) ) ) + { + // Do NOT map Content-Type entity header to DAV:getcontenttype! + // Only DAV resources have this property. + + // Map DAV:getcontenttype to UCP:MediaType (1:1) + (*m_xProps)[ rtl::OUString::createFromAscii( "MediaType" ) ] + = PropertyValue( rValue, true ); + } + // else if ( rName.equals( DAVProperties::GETETAG ) ) + // { + // } + else if ( rName.equals( DAVProperties::GETLASTMODIFIED ) ) + { + // Map the DAV:getlastmodified entity header to UCP:DateModified + rtl::OUString aValue; + rValue >>= aValue; + util::DateTime aDate; + DateTimeHelper::convert( aValue, aDate ); + + (*m_xProps)[ rtl::OUString::createFromAscii( "DateModified" ) ] + = PropertyValue( uno::makeAny( aDate ), true ); + } + else if ( rName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "Last-Modified" ) ) ) + { + // Do not map Last-Modified entity header to DAV:getlastmodified! + // Only DAV resources have this property. + + // Map the Last-Modified entity header to UCP:DateModified + rtl::OUString aValue; + rValue >>= aValue; + util::DateTime aDate; + DateTimeHelper::convert( aValue, aDate ); + + (*m_xProps)[ rtl::OUString::createFromAscii( "DateModified" ) ] + = PropertyValue( uno::makeAny( aDate ), true ); + } + // else if ( rName.equals( DAVProperties::LOCKDISCOVERY ) ) + // { + // } + else if ( rName.equals( DAVProperties::RESOURCETYPE ) ) + { + rtl::OUString aValue; + rValue >>= aValue; + + // Map DAV:resourceype to UCP:IsFolder, UCP:IsDocument, UCP:ContentType + sal_Bool bFolder = + aValue.equalsIgnoreAsciiCaseAsciiL( + RTL_CONSTASCII_STRINGPARAM( "collection" ) ); + + (*m_xProps)[ rtl::OUString::createFromAscii( "IsFolder" ) ] + = PropertyValue( uno::makeAny( bFolder ), true ); + (*m_xProps)[ rtl::OUString::createFromAscii( "IsDocument" ) ] + = PropertyValue( uno::makeAny( sal_Bool( !bFolder ) ), true ); + (*m_xProps)[ rtl::OUString::createFromAscii( "ContentType" ) ] + = PropertyValue( uno::makeAny( bFolder + ? rtl::OUString::createFromAscii( WEBDAV_COLLECTION_TYPE ) + : rtl::OUString::createFromAscii( WEBDAV_CONTENT_TYPE ) ), true ); + } + // else if ( rName.equals( DAVProperties::SUPPORTEDLOCK ) ) + // { + // } + + // Save property. + (*m_xProps)[ rName ] = PropertyValue( rValue, bIsCaseSensitive ); +} + +//========================================================================= +//========================================================================= +// +// CachableContentProperties Implementation. +// +//========================================================================= +//========================================================================= + +namespace +{ + bool isCachable( rtl::OUString const & rName, + bool isCaseSensitive ) + { + static rtl::OUString aNonCachableProps [] = + { + DAVProperties::LOCKDISCOVERY, + + DAVProperties::GETETAG, + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ETag" ) ), + + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DateModified" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Last-Modified" ) ), + DAVProperties::GETLASTMODIFIED, + + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Content-Length" ) ), + DAVProperties::GETCONTENTLENGTH, + + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Date" ) ) + }; + + for ( sal_uInt32 n = 0; + n < ( sizeof( aNonCachableProps ) + / sizeof( aNonCachableProps[ 0 ] ) ); + ++n ) + { + if ( isCaseSensitive ) + { + if ( rName.equals( aNonCachableProps[ n ] ) ) + return false; + } + else + if ( rName.equalsIgnoreAsciiCase( aNonCachableProps[ n ] ) ) + return false; + } + return true; + } + +} // namespace + +//========================================================================= +CachableContentProperties::CachableContentProperties( + const ContentProperties & rProps ) +{ + addProperties( rProps ); +} + +//========================================================================= +void CachableContentProperties::addProperties( + const ContentProperties & rProps ) +{ + const std::auto_ptr< PropertyValueMap > & props = rProps.getProperties(); + + PropertyValueMap::const_iterator it = props->begin(); + const PropertyValueMap::const_iterator end = props->end(); + + while ( it != end ) + { + if ( isCachable( (*it).first, (*it).second.isCaseSensitive() ) ) + m_aProps.addProperty( (*it).first, + (*it).second.value(), + (*it).second.isCaseSensitive() ); + + ++it; + } +} + +//========================================================================= +void CachableContentProperties::addProperties( + const std::vector< DAVPropertyValue > & rProps ) +{ + std::vector< DAVPropertyValue >::const_iterator it = rProps.begin(); + const std::vector< DAVPropertyValue >::const_iterator end = rProps.end(); + + while ( it != end ) + { + if ( isCachable( (*it).Name, (*it).IsCaseSensitive ) ) + m_aProps.addProperty( (*it) ); + + ++it; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/ContentProperties.hxx b/ucb/source/ucp/webdav/ContentProperties.hxx new file mode 100644 index 000000000000..6105879f1dda --- /dev/null +++ b/ucb/source/ucp/webdav/ContentProperties.hxx @@ -0,0 +1,223 @@ +/* -*- 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 _WEBDAV_UCP_CONTENTPROPERTIES_HXX +#define _WEBDAV_UCP_CONTENTPROPERTIES_HXX + +#include +#include +#include +#include +#include +#include + +namespace com { namespace sun { namespace star { namespace beans { + struct Property; +} } } } + +namespace http_dav_ucp +{ + +struct DAVResource; + +//========================================================================= + +struct equalString +{ + bool operator()( const rtl::OUString& s1, const rtl::OUString& s2 ) const + { + return !!( s1 == s2 ); + } +}; + +struct hashString +{ + size_t operator()( const rtl::OUString & rName ) const + { + return rName.hashCode(); + } +}; + +//========================================================================= +// +// PropertyValueMap. +// +//========================================================================= + +class PropertyValue +{ +private: + ::com::sun::star::uno::Any m_aValue; + bool m_bIsCaseSensitive; + +public: + PropertyValue() + : m_bIsCaseSensitive( true ) {} + + PropertyValue( const ::com::sun::star::uno::Any & rValue, + bool bIsCaseSensitive ) + : m_aValue( rValue), + m_bIsCaseSensitive( bIsCaseSensitive ) {} + + bool isCaseSensitive() const { return m_bIsCaseSensitive; } + const ::com::sun::star::uno::Any & value() const { return m_aValue; } + +}; + +typedef std::hash_map +< + rtl::OUString, + PropertyValue, + hashString, + equalString +> +PropertyValueMap; + +struct DAVResource; + +class ContentProperties +{ +public: + ContentProperties(); + + ContentProperties( const DAVResource& rResource ); + + // Mini props for transient contents. + ContentProperties( const rtl::OUString & rTitle, sal_Bool bFolder ); + + // Micro props for non-existing contents. + ContentProperties( const rtl::OUString & rTitle ); + + ContentProperties( const ContentProperties & rOther ); + + bool contains( const rtl::OUString & rName ) const; + + const com::sun::star::uno::Any & + getValue( const rtl::OUString & rName ) const; + + // Maps the UCB property names contained in rProps with their DAV property + // counterparts, if possible. All unmappable properties will be included + // unchanged in resulting vector unless bIncludeUnmatched is set to false. + // The vector filles by this method can directly be handed over to + // DAVResourceAccess::PROPFIND. The result from PROPFIND + // (vector< DAVResource >) can be used to create a ContentProperties + // instance which can map DAV properties back to UCB properties. + static void UCBNamesToDAVNames( const com::sun::star::uno::Sequence< + com::sun::star::beans::Property > & + rProps, + std::vector< rtl::OUString > & resources, + bool bIncludeUnmatched = true ); + + // Maps the UCB property names contained in rProps with their HTTP header + // counterparts, if possible. All unmappable properties will be included + // unchanged in resulting vector unless bIncludeUnmatched is set to false. + // The vector filles by this method can directly be handed over to + // DAVResourceAccess::HEAD. The result from HEAD (vector< DAVResource >) + // can be used to create a ContentProperties instance which can map header + // names back to UCB properties. + static void UCBNamesToHTTPNames( const com::sun::star::uno::Sequence< + com::sun::star::beans::Property > & + rProps, + std::vector< rtl::OUString > & resources, + bool bIncludeUnmatched = true ); + + // return true, if all properties contained in rProps are contained in + // this ContentProperties instance. Otherwiese, false will be returned. + // rNamesNotContained contain the missing names. + bool containsAllNames( + const com::sun::star::uno::Sequence< + com::sun::star::beans::Property >& rProps, + std::vector< rtl::OUString > & rNamesNotContained ) const; + + // adds all properties described by rProps that are actually contained in + // rContentProps to this instance. In case of duplicates the value + // already contained in this will left unchanged. + void addProperties( const std::vector< rtl::OUString > & rProps, + const ContentProperties & rContentProps ); + + // overwrites probably existing entries. + void addProperties( const ContentProperties & rProps ); + + // overwrites probably existing entries. + void addProperties( const std::vector< DAVPropertyValue > & rProps ); + + // overwrites probably existing entry. + void addProperty( const rtl::OUString & rName, + const com::sun::star::uno::Any & rValue, + bool bIsCaseSensitive ); + + // overwrites probably existing entry. + void addProperty( const DAVPropertyValue & rProp ); + + bool isTrailingSlash() const { return m_bTrailingSlash; } + + const rtl::OUString & getEscapedTitle() const { return m_aEscapedTitle; } + + // Not good to expose implementation details, but this is actually an + // internal class. + const std::auto_ptr< PropertyValueMap > & getProperties() const + { return m_xProps; } + +private: + ::rtl::OUString m_aEscapedTitle; + std::auto_ptr< PropertyValueMap > m_xProps; + bool m_bTrailingSlash; + + static com::sun::star::uno::Any m_aEmptyAny; + + ContentProperties & operator=( const ContentProperties & ); // n.i. + + const PropertyValue * get( const rtl::OUString & rName ) const; +}; + +class CachableContentProperties +{ +private: + ContentProperties m_aProps; + + CachableContentProperties & operator=( const CachableContentProperties & ); // n.i. + CachableContentProperties( const CachableContentProperties & ); // n.i. + +public: + CachableContentProperties( const ContentProperties & rProps ); + + void addProperties( const ContentProperties & rProps ); + + void addProperties( const std::vector< DAVPropertyValue > & rProps ); + + bool containsAllNames( + const com::sun::star::uno::Sequence< + com::sun::star::beans::Property >& rProps, + std::vector< rtl::OUString > & rNamesNotContained ) const + { return m_aProps.containsAllNames( rProps, rNamesNotContained ); } + + const com::sun::star::uno::Any & + getValue( const rtl::OUString & rName ) const + { return m_aProps.getValue( rName ); } + + operator const ContentProperties & () const { return m_aProps; } +}; + +} // namespace http_dav_ucp + +#endif /* !_WEBDAV_UCP_CONTENTPROPERTIES_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/DAVAuthListener.hxx b/ucb/source/ucp/webdav/DAVAuthListener.hxx new file mode 100644 index 000000000000..baa27bdc19ba --- /dev/null +++ b/ucb/source/ucp/webdav/DAVAuthListener.hxx @@ -0,0 +1,49 @@ +/* -*- 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 _DAVAUTHLISTENER_HXX_ +#define _DAVAUTHLISTENER_HXX_ + +#include +#include + +#include +#include + +namespace http_dav_ucp +{ + +class DAVAuthListener : public salhelper::SimpleReferenceObject +{ + public: + virtual int authenticate( + const ::rtl::OUString & inRealm, + const ::rtl::OUString & inHostName, + ::rtl::OUString & inoutUserName, + ::rtl::OUString & outPassWord, + sal_Bool bCanUseSystemCredentials, + sal_Bool bUsePreviousCredentials = sal_True ) = 0; +}; + +} // namespace http_dav_ucp + +#endif // _DAVAUTHLISTENER_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/DAVAuthListenerImpl.hxx b/ucb/source/ucp/webdav/DAVAuthListenerImpl.hxx new file mode 100644 index 000000000000..9ffe92255ef7 --- /dev/null +++ b/ucb/source/ucp/webdav/DAVAuthListenerImpl.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + + +#ifndef _DAVAUTHLISTENERIMPL_HXX_ +#define _DAVAUTHLISTENERIMPL_HXX_ + +#include "DAVAuthListener.hxx" + + +namespace http_dav_ucp +{ + +//========================================================================= + +//========================================================================= +//========================================================================= +// +// class DAVAuthListenerImpl. +// +//========================================================================= +//========================================================================= + + + class DAVAuthListener_Impl : public DAVAuthListener + { + public: + + DAVAuthListener_Impl( + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment>& xEnv, + const ::rtl::OUString & inURL ) + : m_xEnv( xEnv ), m_aURL( inURL ) + { + } + + virtual int authenticate( const ::rtl::OUString & inRealm, + const ::rtl::OUString & inHostName, + ::rtl::OUString & inoutUserName, + ::rtl::OUString & outPassWord, + sal_Bool bCanUseSystemCredentials, + sal_Bool bUsePreviousCredentials = sal_True ); + private: + + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > m_xEnv; + const rtl::OUString m_aURL; + + rtl::OUString m_aPrevPassword; + rtl::OUString m_aPrevUsername; + }; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/DAVException.hxx b/ucb/source/ucp/webdav/DAVException.hxx new file mode 100644 index 000000000000..dc0dc2fd57f2 --- /dev/null +++ b/ucb/source/ucp/webdav/DAVException.hxx @@ -0,0 +1,171 @@ +/* -*- 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 _DAVEXCEPTION_HXX_ +#define _DAVEXCEPTION_HXX_ + +#include + +namespace http_dav_ucp +{ + +///////////////////////////////////////////////////////////////////////////// +// HTTP/WebDAV status codes +///////////////////////////////////////////////////////////////////////////// + +const sal_uInt16 SC_NONE = 0; + +// 1xx (Informational - no errors) +const sal_uInt16 SC_CONTINUE = 100; +const sal_uInt16 SC_SWITCHING_PROTOCOLS = 101; +// DAV extensions +const sal_uInt16 SC_PROCESSING = 102; + +//2xx (Successful - no errors) +const sal_uInt16 SC_OK = 200; +const sal_uInt16 SC_CREATED = 201; +const sal_uInt16 SC_ACCEPTED = 202; +const sal_uInt16 SC_NON_AUTHORITATIVE_INFORMATION = 203; +const sal_uInt16 SC_NO_CONTENT = 204; +const sal_uInt16 SC_RESET_CONTENT = 205; +const sal_uInt16 SC_PARTIAL_CONTENT = 206; +// DAV extensions +const sal_uInt16 SC_MULTISTATUS = 207; + +//3xx (Redirection) +const sal_uInt16 SC_MULTIPLE_CHOICES = 300; +const sal_uInt16 SC_MOVED_PERMANENTLY = 301; +const sal_uInt16 SC_MOVED_TEMPORARILY = 302; +const sal_uInt16 SC_SEE_OTHER = 303; +const sal_uInt16 SC_NOT_MODIFIED = 304; +const sal_uInt16 SC_USE_PROXY = 305; +const sal_uInt16 SC_TEMPORARY_REDIRECT = 307; + +//4xx (Client error) +const sal_uInt16 SC_BAD_REQUEST = 400; +const sal_uInt16 SC_UNAUTHORIZED = 401; +const sal_uInt16 SC_PAYMENT_REQUIRED = 402; +const sal_uInt16 SC_FORBIDDEN = 403; +const sal_uInt16 SC_NOT_FOUND = 404; +const sal_uInt16 SC_METHOD_NOT_ALLOWED = 405; +const sal_uInt16 SC_NOT_ACCEPTABLE = 406; +const sal_uInt16 SC_PROXY_AUTHENTICATION_REQUIRED = 407; +const sal_uInt16 SC_REQUEST_TIMEOUT = 408; +const sal_uInt16 SC_CONFLICT = 409; +const sal_uInt16 SC_GONE = 410; +const sal_uInt16 SC_LENGTH_REQUIRED = 411; +const sal_uInt16 SC_PRECONDITION_FAILED = 412; +const sal_uInt16 SC_REQUEST_ENTITY_TOO_LARGE = 413; +const sal_uInt16 SC_REQUEST_URI_TOO_LONG = 414; +const sal_uInt16 SC_UNSUPPORTED_MEDIA_TYPE = 415; +const sal_uInt16 SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; +const sal_uInt16 SC_EXPECTATION_FAILED = 417; +// DAV extensions +const sal_uInt16 SC_UNPROCESSABLE_ENTITY = 422; +const sal_uInt16 SC_LOCKED = 423; +const sal_uInt16 SC_FAILED_DEPENDENCY = 424; + +//5xx (Server error) +const sal_uInt16 SC_INTERNAL_SERVER_ERROR = 500; +const sal_uInt16 SC_NOT_IMPLEMENTED = 501; +const sal_uInt16 SC_BAD_GATEWAY = 502; +const sal_uInt16 SC_SERVICE_UNAVAILABLE = 503; +const sal_uInt16 SC_GATEWAY_TIMEOUT = 504; +const sal_uInt16 SC_HTTP_VERSION_NOT_SUPPORTED = 505; +// DAV extensions +const sal_uInt16 SC_INSUFFICIENT_STORAGE = 507; + +///////////////////////////////////////////////////////////////////////////// + +class DAVException +{ + public: + enum ExceptionCode { + DAV_HTTP_ERROR = 0, // Generic error, + // mData = server error message, + // mStatusCode = HTTP status code + DAV_HTTP_LOOKUP, // Name lookup failed, + // mData = server[:port] + DAV_HTTP_NOAUTH, // No User authentication data provided - e.g., user aborts corresponding dialog + // mData = server[:port] + DAV_HTTP_AUTH, // User authentication failed on server, + // mData = server[:port] + DAV_HTTP_AUTHPROXY, // User authentication failed on proxy, + // mData = proxy server[:port] + DAV_HTTP_CONNECT, // Could not connect to server, + // mData = server[:port] + DAV_HTTP_TIMEOUT, // Connection timed out + // mData = server[:port] + DAV_HTTP_FAILED, // The precondition failed + // mData = server[:port] + DAV_HTTP_RETRY, // Retry request + // mData = server[:port] + DAV_HTTP_REDIRECT, // Request was redirected, + // mData = new URL + DAV_SESSION_CREATE, // session creation error, + // mData = server[:port] + DAV_INVALID_ARG, // invalid argument + + DAV_LOCK_EXPIRED, // DAV lock expired + + DAV_NOT_LOCKED, // not locked + + DAV_LOCKED_SELF, // locked by this OOo session + + DAV_LOCKED // locked by third party + }; + + private: + ExceptionCode mExceptionCode; + rtl::OUString mData; + sal_uInt16 mStatusCode; + + public: + DAVException( ExceptionCode inExceptionCode ) + : mExceptionCode( inExceptionCode ) + , mData() + , mStatusCode( SC_NONE ) + {}; + DAVException( ExceptionCode inExceptionCode, + const rtl::OUString & rData ) + : mExceptionCode( inExceptionCode ) + , mData( rData ) + , mStatusCode( SC_NONE ) + {}; + DAVException( ExceptionCode inExceptionCode, + const rtl::OUString & rData, + sal_uInt16 nStatusCode ) + : mExceptionCode( inExceptionCode ) + , mData( rData ) + , mStatusCode( nStatusCode ) + {}; + ~DAVException( ) {}; + + const ExceptionCode & getError() const { return mExceptionCode; } + const rtl::OUString & getData() const { return mData; } + sal_uInt16 getStatus() const { return mStatusCode; } +}; + +} // namespace http_dav_ucp + +#endif // _DAVEXCEPTION_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/DAVProperties.cxx b/ucb/source/ucp/webdav/DAVProperties.cxx new file mode 100644 index 000000000000..618c1fb4ba8f --- /dev/null +++ b/ucb/source/ucp/webdav/DAVProperties.cxx @@ -0,0 +1,194 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include +#include "DAVProperties.hxx" + +using namespace http_dav_ucp; + +const ::rtl::OUString DAVProperties::CREATIONDATE = + ::rtl::OUString::createFromAscii( "DAV:creationdate" ); +const ::rtl::OUString DAVProperties::DISPLAYNAME = + ::rtl::OUString::createFromAscii( "DAV:displayname" ); +const ::rtl::OUString DAVProperties::GETCONTENTLANGUAGE = + ::rtl::OUString::createFromAscii( "DAV:getcontentlanguage" ); +const ::rtl::OUString DAVProperties::GETCONTENTLENGTH = + ::rtl::OUString::createFromAscii( "DAV:getcontentlength" ); +const ::rtl::OUString DAVProperties::GETCONTENTTYPE = + ::rtl::OUString::createFromAscii( "DAV:getcontenttype" ); +const ::rtl::OUString DAVProperties::GETETAG = + ::rtl::OUString::createFromAscii( "DAV:getetag" ); +const ::rtl::OUString DAVProperties::GETLASTMODIFIED = + ::rtl::OUString::createFromAscii( "DAV:getlastmodified" ); +const ::rtl::OUString DAVProperties::LOCKDISCOVERY = + ::rtl::OUString::createFromAscii( "DAV:lockdiscovery" ); +const ::rtl::OUString DAVProperties::RESOURCETYPE = + ::rtl::OUString::createFromAscii( "DAV:resourcetype" ); +const ::rtl::OUString DAVProperties::SUPPORTEDLOCK = + ::rtl::OUString::createFromAscii( "DAV:supportedlock" ); + +const ::rtl::OUString DAVProperties::EXECUTABLE = + ::rtl::OUString::createFromAscii( + "http://apache.org/dav/props/executable" ); + +// ------------------------------------------------------------------- +// static +void DAVProperties::createSerfPropName( const rtl::OUString & rFullName, + SerfPropName & rName ) +{ + if ( rFullName.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "DAV:" ) ) == 0 ) + { + rName.nspace = "DAV:"; + rName.name + = strdup( rtl::OUStringToOString( + rFullName.copy( RTL_CONSTASCII_LENGTH( "DAV:" ) ), + RTL_TEXTENCODING_UTF8 ) ); + } + else if ( rFullName.compareToAscii( RTL_CONSTASCII_STRINGPARAM( + "http://apache.org/dav/props/" ) ) == 0 ) + { + rName.nspace = "http://apache.org/dav/props/"; + rName.name + = strdup( rtl::OUStringToOString( + rFullName.copy( + RTL_CONSTASCII_LENGTH( + "http://apache.org/dav/props/" ) ), + RTL_TEXTENCODING_UTF8 ) ); + } + else if ( rFullName.compareToAscii( RTL_CONSTASCII_STRINGPARAM( + "http://ucb.openoffice.org/dav/props/" ) ) == 0 ) + { + rName.nspace = "http://ucb.openoffice.org/dav/props/"; + rName.name + = strdup( rtl::OUStringToOString( + rFullName.copy( + RTL_CONSTASCII_LENGTH( + "http://ucb.openoffice.org/dav/props/" ) ), + RTL_TEXTENCODING_UTF8 ) ); + } + else if ( rFullName.compareToAscii( RTL_CONSTASCII_STRINGPARAM( + " + + sal_Int32 nStart = RTL_CONSTASCII_LENGTH( " & xEnv ) + throw ( DAVException ) +{ + initialize(); + + sal_Int64 nNewTimeout = 0; + int errorCount = 0; + bool bRetry; + do + { + bRetry = false; + try + { + DAVRequestHeaders aHeaders; + getUserRequestHeaders( xEnv, + getRequestURI(), + rtl::OUString::createFromAscii( "LOCK" ), + aHeaders ); + + nNewTimeout = m_xSession->LOCK( getRequestURI(), + nTimeout, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( + xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); + + return nNewTimeout; +} +#endif + +//========================================================================= +void DAVResourceAccess::UNLOCK( + const uno::Reference< ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ) +{ + initialize(); + + int errorCount = 0; + bool bRetry; + do + { + bRetry = false; + try + { + DAVRequestHeaders aHeaders; + getUserRequestHeaders( xEnv, + getRequestURI(), + rtl::OUString::createFromAscii( "UNLOCK" ), + aHeaders ); + + m_xSession->UNLOCK( getRequestURI(), + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +void DAVResourceAccess::setURL( const rtl::OUString & rNewURL ) + throw( DAVException ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_aURL = rNewURL; + m_aPath = rtl::OUString(); // Next initialize() will create new session. +} + +//========================================================================= +// init dav session and path +void DAVResourceAccess::initialize() + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + if ( m_aPath.getLength() == 0 ) + { + SerfUri aURI( m_aURL ); + rtl::OUString aPath( aURI.GetPath() ); + + /* #134089# - Check URI */ + if ( !aPath.getLength() ) + throw DAVException( DAVException::DAV_INVALID_ARG ); + + /* #134089# - Check URI */ + if ( !aURI.GetHost().getLength() ) + throw DAVException( DAVException::DAV_INVALID_ARG ); + + if ( !m_xSession.is() || !m_xSession->CanUse( m_aURL ) ) + { + m_xSession.clear(); + + // create new webdav session + m_xSession + = m_xSessionFactory->createDAVSession( m_aURL, m_xSMgr ); + + if ( !m_xSession.is() ) + return; + } + + // Own URI is needed for redirect cycle detection. + m_aRedirectURIs.push_back( aURI ); + + // Success. + m_aPath = aPath; + + // Not only the path has to be encoded + m_aURL = aURI.GetURI(); + } +} + +//========================================================================= +const rtl::OUString & DAVResourceAccess::getRequestURI() const +{ + OSL_ENSURE( m_xSession.is(), + "DAVResourceAccess::getRequestURI - Not initialized!" ); + + // In case a proxy is used we have to use the absolute URI for a request. + if ( m_xSession->UsesProxy() ) + return m_aURL; + + return m_aPath; +} + +//========================================================================= +// static +void DAVResourceAccess::getUserRequestHeaders( + const uno::Reference< ucb::XCommandEnvironment > & xEnv, + const rtl::OUString & rURI, + const rtl::OUString & rMethod, + DAVRequestHeaders & rRequestHeaders ) +{ + if ( xEnv.is() ) + { + uno::Reference< ucb::XWebDAVCommandEnvironment > xDAVEnv( + xEnv, uno::UNO_QUERY ); + + if ( xDAVEnv.is() ) + { + uno::Sequence< beans::NamedValue > aRequestHeaders + = xDAVEnv->getUserRequestHeaders( rURI, rMethod ); + + for ( sal_Int32 n = 0; n < aRequestHeaders.getLength(); ++n ) + { + rtl::OUString aValue; + sal_Bool isString = aRequestHeaders[ n ].Value >>= aValue; + + if ( !isString ) + { + OSL_ENSURE( isString, + "DAVResourceAccess::getUserRequestHeaders :" + "Value is not a string! Ignoring..." ); + } + + rRequestHeaders.push_back( + DAVRequestHeader( aRequestHeaders[ n ].Name, aValue ) ); + } + } + } +} + +//========================================================================= +sal_Bool DAVResourceAccess::detectRedirectCycle( + const rtl::OUString& rRedirectURL ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + SerfUri aUri( rRedirectURL ); + + std::vector< SerfUri >::const_iterator it = m_aRedirectURIs.begin(); + std::vector< SerfUri >::const_iterator end = m_aRedirectURIs.end(); + + while ( it != end ) + { + if ( aUri == (*it) ) + return sal_True; + + it++; + } + + return sal_False; +} + +//========================================================================= +void DAVResourceAccess::resetUri() +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + if ( m_aRedirectURIs.size() > 0 ) + { + std::vector< SerfUri >::const_iterator it = m_aRedirectURIs.begin(); + + SerfUri aUri( (*it) ); + m_aRedirectURIs.clear(); + setURL ( aUri.GetURI() ); + initialize(); + } +} + +//========================================================================= +sal_Bool DAVResourceAccess::handleException( DAVException & e, int errorCount ) + throw ( DAVException ) +{ + switch ( e.getError() ) + { + case DAVException::DAV_HTTP_REDIRECT: + if ( !detectRedirectCycle( e.getData() ) ) + { + // set new URL and path. + setURL( e.getData() ); + initialize(); + return sal_True; + } + return sal_False; + // --> tkr #67048# copy & paste images doesn't display. + // if we have a bad connection try again. Up to three times. + case DAVException::DAV_HTTP_ERROR: + // retry up to three times, if not a client-side error. + if ( ( e.getStatus() < 400 || e.getStatus() >= 500 || + e.getStatus() == 413 ) && + errorCount < 3 ) + { + return sal_True; + } + return sal_False; + // <-- + // --> tkr: if connection has said retry then retry! + case DAVException::DAV_HTTP_RETRY: + return sal_True; + // <-- + default: + return sal_False; // Abort + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/DAVResourceAccess.hxx b/ucb/source/ucp/webdav/DAVResourceAccess.hxx new file mode 100644 index 000000000000..792a85a354e0 --- /dev/null +++ b/ucb/source/ucp/webdav/DAVResourceAccess.hxx @@ -0,0 +1,239 @@ +/* -*- 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 _DAVRESOURCEACCESS_HXX_ +#define _DAVRESOURCEACCESS_HXX_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "DAVAuthListener.hxx" +#include "DAVException.hxx" +#include "DAVSession.hxx" +#include "DAVResource.hxx" +#include "DAVTypes.hxx" +#include "SerfUri.hxx" + +namespace http_dav_ucp +{ + +class DAVSessionFactory; + +class DAVResourceAccess +{ + osl::Mutex m_aMutex; + rtl::OUString m_aURL; + rtl::OUString m_aPath; + rtl::Reference< DAVSession > m_xSession; + rtl::Reference< DAVSessionFactory > m_xSessionFactory; + com::sun::star::uno::Reference< + com::sun::star::lang::XMultiServiceFactory > m_xSMgr; + std::vector< SerfUri > m_aRedirectURIs; + +public: + DAVResourceAccess() : m_xSessionFactory( 0 ) {} + DAVResourceAccess( const com::sun::star::uno::Reference< + com::sun::star::lang::XMultiServiceFactory > & rSMgr, + rtl::Reference< + DAVSessionFactory > const & rSessionFactory, + const rtl::OUString & rURL ); + DAVResourceAccess( const DAVResourceAccess & rOther ); + + DAVResourceAccess & operator=( const DAVResourceAccess & rOther ); + + void setURL( const rtl::OUString & rNewURL ) + throw ( DAVException ); + + void resetUri(); + + const rtl::OUString & getURL() const { return m_aURL; } + + rtl::Reference< DAVSessionFactory > getSessionFactory() const + { return m_xSessionFactory; } + + // DAV methods + // + + // allprop & named + void + PROPFIND( const Depth nDepth, + const std::vector< rtl::OUString > & rPropertyNames, + std::vector< DAVResource > & rResources, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); + + // propnames + void + PROPFIND( const Depth nDepth, + std::vector< DAVResourceInfo > & rResInfo, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); + + void + PROPPATCH( const std::vector< ProppatchValue > & rValues, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment >& xEnv ) + throw ( DAVException ); + + void + HEAD( const std::vector< rtl::OUString > & rHeaderNames, // empty == 'all' + DAVResource & rResource, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment >& xEnv ) + throw ( DAVException ); + + com::sun::star::uno::Reference< com::sun::star::io::XInputStream > + GET( const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); + + void + GET( com::sun::star::uno::Reference< + com::sun::star::io::XOutputStream > & rStream, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); + + com::sun::star::uno::Reference< com::sun::star::io::XInputStream > + GET( const std::vector< rtl::OUString > & rHeaderNames, // empty == 'all' + DAVResource & rResource, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); + + void + GET( com::sun::star::uno::Reference< + com::sun::star::io::XOutputStream > & rStream, + const std::vector< rtl::OUString > & rHeaderNames, // empty == 'all' + DAVResource & rResource, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); + + void + PUT( const com::sun::star::uno::Reference< + com::sun::star::io::XInputStream > & rStream, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); + + com::sun::star::uno::Reference< com::sun::star::io::XInputStream > + POST( const rtl::OUString & rContentType, + const rtl::OUString & rReferer, + const com::sun::star::uno::Reference< + com::sun::star::io::XInputStream > & rInputStream, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment >& xEnv ) + throw ( DAVException ); + + void + POST( const rtl::OUString & rContentType, + const rtl::OUString & rReferer, + const com::sun::star::uno::Reference< + com::sun::star::io::XInputStream > & rInputStream, + com::sun::star::uno::Reference< + com::sun::star::io::XOutputStream > & rOutputStream, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment >& xEnv ) + throw ( DAVException ); + + void + MKCOL( const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); + + void + COPY( const ::rtl::OUString & rSourcePath, + const ::rtl::OUString & rDestinationURI, + sal_Bool bOverwrite, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); + + void + MOVE( const ::rtl::OUString & rSourcePath, + const ::rtl::OUString & rDestinationURI, + sal_Bool bOverwrite, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); + + void + DESTROY( const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); + + // set new lock. + void + LOCK( com::sun::star::ucb::Lock & inLock, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw( DAVException ); + +#if 0 // currently not used, but please don't remove code + // refresh existing lock. + sal_Int64 + LOCK( sal_Int64 nTimeout, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); +#endif + + void + UNLOCK( const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); + + void + abort() + throw ( DAVException ); + + // helper + static void + getUserRequestHeaders( + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv, + const rtl::OUString & rURI, + const rtl::OUString & rMethod, + DAVRequestHeaders & rRequestHeaders ); + +private: + const rtl::OUString & getRequestURI() const; + sal_Bool detectRedirectCycle( const rtl::OUString& rRedirectURL ) + throw ( DAVException ); + sal_Bool handleException( DAVException & e, int errorCount ) + throw ( DAVException ); + void initialize() + throw ( DAVException ); +}; + +} // namespace http_dav_ucp + +#endif // _DAVRESOURCEACCESS_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/DAVSession.hxx b/ucb/source/ucp/webdav/DAVSession.hxx new file mode 100644 index 000000000000..d0e3cc90ae7a --- /dev/null +++ b/ucb/source/ucp/webdav/DAVSession.hxx @@ -0,0 +1,218 @@ +/* -*- 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 _DAVSESSION_HXX_ +#define _DAVSESSION_HXX_ + +#include +#include +#include +#include +#include "DAVException.hxx" +#include "DAVProperties.hxx" +#include "DAVResource.hxx" +#include "DAVSessionFactory.hxx" +#include "DAVTypes.hxx" +#include "DAVRequestEnvironment.hxx" + +namespace com { namespace sun { namespace star { namespace ucb { + struct Lock; +} } } } + +namespace http_dav_ucp +{ + +class DAVAuthListener; + +class DAVSession +{ +public: + inline void acquire() SAL_THROW(()) + { + osl_incrementInterlockedCount( &m_nRefCount ); + } + + void release() SAL_THROW(()) + { + if ( osl_decrementInterlockedCount( &m_nRefCount ) == 0 ) + { + m_xFactory->releaseElement( this ); + delete this; + } + } + + virtual sal_Bool CanUse( const ::rtl::OUString & inPath ) = 0; + + virtual sal_Bool UsesProxy() = 0; + + // DAV methods + // + + // NOT USED + /* + virtual void OPTIONS( const ::rtl::OUString & inPath, + DAVCapabilities & outCapabilities, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) = 0; + */ + + // allprop & named + virtual void PROPFIND( const ::rtl::OUString & inPath, + const Depth inDepth, + const std::vector< ::rtl::OUString > & inPropertyNames, + std::vector< DAVResource > & ioResources, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) = 0; + + // propnames + virtual void PROPFIND( const ::rtl::OUString & inPath, + const Depth inDepth, + std::vector< DAVResourceInfo > & ioResInfo, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) = 0; + + virtual void PROPPATCH( const ::rtl::OUString & inPath, + const std::vector< ProppatchValue > & inValues, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) = 0; + + virtual void HEAD( const ::rtl::OUString & inPath, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) = 0; + + virtual com::sun::star::uno::Reference< com::sun::star::io::XInputStream > + GET( const ::rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) = 0; + + virtual void GET( const ::rtl::OUString & inPath, + com::sun::star::uno::Reference< + com::sun::star::io::XOutputStream >& o, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) = 0; + + virtual com::sun::star::uno::Reference< com::sun::star::io::XInputStream > + GET( const ::rtl::OUString & inPath, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) = 0; + + virtual void + GET( const ::rtl::OUString & inPath, + com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& o, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) = 0; + + virtual void PUT( const ::rtl::OUString & inPath, + const com::sun::star::uno::Reference< + com::sun::star::io::XInputStream >& s, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) = 0; + + virtual com::sun::star::uno::Reference< com::sun::star::io::XInputStream > + POST( const rtl::OUString & inPath, + const rtl::OUString & rContentType, + const rtl::OUString & rReferer, + const com::sun::star::uno::Reference< + com::sun::star::io::XInputStream > & inInputStream, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) = 0; + + virtual void POST( const rtl::OUString & inPath, + const rtl::OUString & rContentType, + const rtl::OUString & rReferer, + const com::sun::star::uno::Reference< + com::sun::star::io::XInputStream > & inInputStream, + com::sun::star::uno::Reference< + com::sun::star::io::XOutputStream > & oOutputStream, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) = 0; + + virtual void MKCOL( const ::rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) = 0; + + virtual void COPY( const ::rtl::OUString & inSource, + const ::rtl::OUString & inDestination, + const DAVRequestEnvironment & rEnv, + sal_Bool inOverwrite = false ) + throw( DAVException ) = 0; + + virtual void MOVE( const ::rtl::OUString & inSource, + const ::rtl::OUString & inDestination, + const DAVRequestEnvironment & rEnv, + sal_Bool inOverwrite = false ) + throw( DAVException ) = 0; + + virtual void DESTROY( const ::rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) = 0; + + // set new lock. + virtual void LOCK( const ::rtl::OUString & inPath, + com::sun::star::ucb::Lock & inLock, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) = 0; + + // refresh existing lock. + virtual sal_Int64 LOCK( const ::rtl::OUString & inPath, + sal_Int64 nTimeout, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) = 0; + + virtual void UNLOCK( const ::rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) = 0; + + virtual void abort() + throw( DAVException ) = 0; + +protected: + rtl::Reference< DAVSessionFactory > m_xFactory; + + DAVSession( rtl::Reference< DAVSessionFactory > const & rFactory ) + : m_xFactory( rFactory ), m_nRefCount( 0 ) {} + + virtual ~DAVSession() {} + +private: + DAVSessionFactory::Map::iterator m_aContainerIt; + oslInterlockedCount m_nRefCount; + + friend class DAVSessionFactory; +#if defined WNT && _MSC_VER < 1310 + friend struct std::auto_ptr< DAVSession >; + // work around compiler bug... +#else // WNT + friend class std::auto_ptr< DAVSession >; +#endif // WNT +}; + +} // namespace http_dav_ucp + +#endif // _DAVSESSION_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/DAVSessionFactory.cxx b/ucb/source/ucp/webdav/DAVSessionFactory.cxx new file mode 100644 index 000000000000..e33eb7e1d9fb --- /dev/null +++ b/ucb/source/ucp/webdav/DAVSessionFactory.cxx @@ -0,0 +1,101 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" +#include "DAVSessionFactory.hxx" +#include "SerfSession.hxx" +#include "SerfUri.hxx" +#include + +using namespace http_dav_ucp; +using namespace com::sun::star; + +DAVSessionFactory::~DAVSessionFactory() +{ +} + +rtl::Reference< DAVSession > DAVSessionFactory::createDAVSession( + const ::rtl::OUString & inUri, + const uno::Reference< lang::XMultiServiceFactory > & rxSMgr ) + throw( DAVException ) +{ + m_xMSF = rxSMgr; + + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xProxyDecider.get() ) + m_xProxyDecider.reset( new ucbhelper::InternetProxyDecider( rxSMgr ) ); + + Map::iterator aIt( m_aMap.begin() ); + Map::iterator aEnd( m_aMap.end() ); + + while ( aIt != aEnd ) + { + if ( (*aIt).second->CanUse( inUri ) ) + break; + + ++aIt; + } + + if ( aIt == aEnd ) + { + SerfUri aURI( inUri ); + + std::auto_ptr< DAVSession > xElement( + new SerfSession( this, inUri, *m_xProxyDecider.get() ) ); + + aIt = m_aMap.insert( Map::value_type( inUri, xElement.get() ) ).first; + aIt->second->m_aContainerIt = aIt; + xElement.release(); + return aIt->second; + } + else if ( osl_incrementInterlockedCount( &aIt->second->m_nRefCount ) > 1 ) + { + rtl::Reference< DAVSession > xElement( aIt->second ); + osl_decrementInterlockedCount( &aIt->second->m_nRefCount ); + return xElement; + } + else + { + osl_decrementInterlockedCount( &aIt->second->m_nRefCount ); + aIt->second->m_aContainerIt = m_aMap.end(); + + // If URL scheme is different from http or https we definitely + // have to use a proxy and therefore can optimize the getProxy + // call a little: + SerfUri aURI( inUri ); + + aIt->second = new SerfSession( this, inUri, *m_xProxyDecider.get() ); + aIt->second->m_aContainerIt = aIt; + return aIt->second; + } +} + +void DAVSessionFactory::releaseElement( DAVSession * pElement ) SAL_THROW(()) +{ + OSL_ASSERT( pElement ); + osl::MutexGuard aGuard( m_aMutex ); + if ( pElement->m_aContainerIt != m_aMap.end() ) + m_aMap.erase( pElement->m_aContainerIt ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/DAVSessionFactory.hxx b/ucb/source/ucp/webdav/DAVSessionFactory.hxx new file mode 100644 index 000000000000..403a70fff10e --- /dev/null +++ b/ucb/source/ucp/webdav/DAVSessionFactory.hxx @@ -0,0 +1,78 @@ +/* -*- 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 _DAVSESSIONFACTORY_HXX_ +#define _DAVSESSIONFACTORY_HXX_ + +#ifdef min +#undef min // GNU libstdc++ includes which defines methods called min... +#endif +#include +#include +#include +#include +#include +#include +#include +#include "DAVException.hxx" + +using namespace com::sun::star; + +namespace com { namespace sun { namespace star { namespace lang { + class XMultiServiceFactory; +} } } } + +namespace http_dav_ucp +{ + +class DAVSession; + +class DAVSessionFactory : public salhelper::SimpleReferenceObject +{ +public: + ~DAVSessionFactory() SAL_THROW(()); + + rtl::Reference< DAVSession > + createDAVSession( const ::rtl::OUString & inUri, + const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& + rxSMgr ) + throw( DAVException ); + + ::uno::Reference< ::lang::XMultiServiceFactory > getServiceFactory() { return m_xMSF; } +private: + typedef std::map< rtl::OUString, DAVSession * > Map; + + Map m_aMap; + osl::Mutex m_aMutex; + std::auto_ptr< ucbhelper::InternetProxyDecider > m_xProxyDecider; + + ::uno::Reference< ::lang::XMultiServiceFactory > m_xMSF; + + void releaseElement( DAVSession * pElement ) SAL_THROW(()); + + friend class DAVSession; +}; + +} // namespace http_dav_ucp + +#endif // _DAVSESSIONFACTORY_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/DAVTypes.hxx b/ucb/source/ucp/webdav/DAVTypes.hxx new file mode 100644 index 000000000000..a32aee65e697 --- /dev/null +++ b/ucb/source/ucp/webdav/DAVTypes.hxx @@ -0,0 +1,81 @@ +/* -*- 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 _DAVTYPES_HXX_ +#define _DAVTYPES_HXX_ + +#include +#include + +namespace http_dav_ucp +{ +/* RFC 2518 + +15.1 Class 1 + + A class 1 compliant resource MUST meet all "MUST" requirements in all + sections of this document. + + Class 1 compliant resources MUST return, at minimum, the value "1" in + the DAV header on all responses to the OPTIONS method. + +15.2 Class 2 + + A class 2 compliant resource MUST meet all class 1 requirements and + support the LOCK method, the supportedlock property, the + lockdiscovery property, the Time-Out response header and the Lock- + Token request header. A class "2" compliant resource SHOULD also + support the Time-Out request header and the owner XML element. + + Class 2 compliant resources MUST return, at minimum, the values "1" + and "2" in the DAV header on all responses to the OPTIONS method. +*/ + +struct DAVCapabilities +{ + bool class1; + bool class2; + bool executable; // supports "executable" property (introduced by mod_dav) + + DAVCapabilities() : class1( false ), class2( false ), executable( false ) {} +}; + +enum Depth { DAVZERO = 0, DAVONE = 1, DAVINFINITY = -1 }; + +enum ProppatchOperation { PROPSET = 0, PROPREMOVE = 1 }; + +struct ProppatchValue +{ + ProppatchOperation operation; + rtl::OUString name; + com::sun::star::uno::Any value; + + ProppatchValue( const ProppatchOperation o, + const rtl::OUString & n, + const com::sun::star::uno::Any & v ) + : operation( o ), name( n ), value( v ) {} +}; + +} // namespace http_dav_ucp + +#endif // _DAVTYPES_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/DateTimeHelper.cxx b/ucb/source/ucp/webdav/DateTimeHelper.cxx new file mode 100644 index 000000000000..6958ca887674 --- /dev/null +++ b/ucb/source/ucp/webdav/DateTimeHelper.cxx @@ -0,0 +1,265 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include +#include +#include +#include "DateTimeHelper.hxx" + +using namespace com::sun::star::util; +using namespace rtl; + +using namespace http_dav_ucp; + +bool DateTimeHelper::ISO8601_To_DateTime (const OUString& s, + DateTime& dateTime) +{ + OString aDT (s.getStr(), s.getLength(), RTL_TEXTENCODING_ASCII_US); + + int year, month, day, hours, minutes, off_hours, off_minutes, fix; + double seconds; + + // 2001-01-01T12:30:00Z + int n = sscanf( aDT.getStr(), "%04d-%02d-%02dT%02d:%02d:%lfZ", + &year, &month, &day, &hours, &minutes, &seconds ); + if ( n == 6 ) + { + fix = 0; + } + else + { + // 2001-01-01T12:30:00+03:30 + n = sscanf( aDT.getStr(), "%04d-%02d-%02dT%02d:%02d:%lf+%02d:%02d", + &year, &month, &day, &hours, &minutes, &seconds, + &off_hours, &off_minutes ); + if ( n == 8 ) + { + fix = - off_hours * 3600 - off_minutes * 60; + } + else + { + // 2001-01-01T12:30:00-03:30 + n = sscanf( aDT.getStr(), "%04d-%02d-%02dT%02d:%02d:%lf-%02d:%02d", + &year, &month, &day, &hours, &minutes, &seconds, + &off_hours, &off_minutes ); + if ( n == 8 ) + { + fix = off_hours * 3600 + off_minutes * 60; + } + else + { + return false; + } + } + } + + // Convert to local time... + + oslDateTime aDateTime; + aDateTime.NanoSeconds = 0; + aDateTime.Seconds = sal::static_int_cast< sal_uInt16 >(seconds); // 0-59 + aDateTime.Minutes = sal::static_int_cast< sal_uInt16 >(minutes); // 0-59 + aDateTime.Hours = sal::static_int_cast< sal_uInt16 >(hours); // 0-23 + aDateTime.Day = sal::static_int_cast< sal_uInt16 >(day); // 1-31 + aDateTime.DayOfWeek = 0; // 0-6, 0 = Sunday + aDateTime.Month = sal::static_int_cast< sal_uInt16 >(month); // 1-12 + aDateTime.Year = sal::static_int_cast< sal_uInt16 >(year); + + TimeValue aTimeValue; + if ( osl_getTimeValueFromDateTime( &aDateTime, &aTimeValue ) ) + { + aTimeValue.Seconds += fix; + + if ( osl_getLocalTimeFromSystemTime( &aTimeValue, &aTimeValue ) ) + { + if ( osl_getDateTimeFromTimeValue( &aTimeValue, &aDateTime ) ) + { + dateTime.Year = aDateTime.Year; + dateTime.Month = aDateTime.Month; + dateTime.Day = aDateTime.Day; + dateTime.Hours = aDateTime.Hours; + dateTime.Minutes = aDateTime.Minutes; + dateTime.Seconds = aDateTime.Seconds; + + return true; + } + } + } + + return false; +} + +/* +sal_Int32 DateTimeHelper::convertDayToInt (const OUString& day) +{ + if (day.compareToAscii ("Sun") == 0) + return 0; + else if (day.compareToAscii ("Mon") == 0) + return 1; + else if (day.compareToAscii ("Tue") == 0) + return 2; + else if (day.compareToAscii ("Wed") == 0) + return 3; + else if (day.compareToAscii ("Thu") == 0) + return 4; + else if (day.compareToAscii ("Fri") == 0) + return 5; + else if (day.compareToAscii ("Sat") == 0) + return 6; + else + return -1; +} +*/ + +sal_Int32 DateTimeHelper::convertMonthToInt (const OUString& month) +{ + if (month.compareToAscii ("Jan") == 0) + return 1; + else if (month.compareToAscii ("Feb") == 0) + return 2; + else if (month.compareToAscii ("Mar") == 0) + return 3; + else if (month.compareToAscii ("Apr") == 0) + return 4; + else if (month.compareToAscii ("May") == 0) + return 5; + else if (month.compareToAscii ("Jun") == 0) + return 6; + else if (month.compareToAscii ("Jul") == 0) + return 7; + else if (month.compareToAscii ("Aug") == 0) + return 8; + else if (month.compareToAscii ("Sep") == 0) + return 9; + else if (month.compareToAscii ("Oct") == 0) + return 10; + else if (month.compareToAscii ("Nov") == 0) + return 11; + else if (month.compareToAscii ("Dec") == 0) + return 12; + else + return 0; +} + +bool DateTimeHelper::RFC2068_To_DateTime (const OUString& s, + DateTime& dateTime) +{ + int year; + int day; + int hours; + int minutes; + int seconds; + sal_Char string_month[3 + 1]; + sal_Char string_day[3 + 1]; + + sal_Int32 found = s.indexOf (','); + if (found != -1) + { + OString aDT (s.getStr(), s.getLength(), RTL_TEXTENCODING_ASCII_US); + + // RFC 1123 + found = sscanf (aDT.getStr(), "%3s, %2d %3s %4d %2d:%2d:%2d GMT", + string_day, &day, string_month, &year, &hours, &minutes, &seconds); + if (found != 7) + { + // RFC 1036 + found = sscanf (aDT.getStr(), "%3s, %2d-%3s-%2d %2d:%2d:%2d GMT", + string_day, &day, string_month, &year, &hours, &minutes, &seconds); + } + found = (found == 7) ? 1 : 0; + } + else + { + OString aDT (s.getStr(), s.getLength(), RTL_TEXTENCODING_ASCII_US); + + // ANSI C's asctime () format + found = sscanf (aDT.getStr(), "%3s %3s %d %2d:%2d:%2d %4d", + string_day, string_month, + &day, &hours, &minutes, &seconds, &year); + found = (found == 7) ? 1 : 0; + } + + if (found) + { + found = 0; + + int month = DateTimeHelper::convertMonthToInt ( + OUString::createFromAscii (string_month)); + if (month) + { + // Convert to local time... + + oslDateTime aDateTime; + aDateTime.NanoSeconds = 0; + aDateTime.Seconds = sal::static_int_cast< sal_uInt16 >(seconds); + // 0-59 + aDateTime.Minutes = sal::static_int_cast< sal_uInt16 >(minutes); + // 0-59 + aDateTime.Hours = sal::static_int_cast< sal_uInt16 >(hours); + // 0-23 + aDateTime.Day = sal::static_int_cast< sal_uInt16 >(day); + // 1-31 + aDateTime.DayOfWeek = 0; //dayofweek; // 0-6, 0 = Sunday + aDateTime.Month = sal::static_int_cast< sal_uInt16 >(month); + // 1-12 + aDateTime.Year = sal::static_int_cast< sal_uInt16 >(year); + + TimeValue aTimeValue; + if ( osl_getTimeValueFromDateTime( &aDateTime, + &aTimeValue ) ) + { + if ( osl_getLocalTimeFromSystemTime( &aTimeValue, + &aTimeValue ) ) + { + if ( osl_getDateTimeFromTimeValue( &aTimeValue, + &aDateTime ) ) + { + dateTime.Year = aDateTime.Year; + dateTime.Month = aDateTime.Month; + dateTime.Day = aDateTime.Day; + dateTime.Hours = aDateTime.Hours; + dateTime.Minutes = aDateTime.Minutes; + dateTime.Seconds = aDateTime.Seconds; + + found = 1; + } + } + } + } + } + + return (found) ? true : false; +} + +bool DateTimeHelper::convert (const OUString& s, DateTime& dateTime) +{ + if (ISO8601_To_DateTime (s, dateTime)) + return true; + else if (RFC2068_To_DateTime (s, dateTime)) + return true; + else + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/DateTimeHelper.hxx b/ucb/source/ucp/webdav/DateTimeHelper.hxx new file mode 100644 index 000000000000..ba2be763eb74 --- /dev/null +++ b/ucb/source/ucp/webdav/DateTimeHelper.hxx @@ -0,0 +1,58 @@ +/* -*- 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 _WEBDAV_DATETIME_HELPER_HXX +#define _WEBDAV_DATETIME_HELPER_HXX + +#include + +namespace com { namespace sun { namespace star { namespace util { + struct DateTime; +} } } } + +namespace rtl { + class OUString; +} + +namespace http_dav_ucp +{ + +class DateTimeHelper +{ +private: + static sal_Int32 convertMonthToInt (const ::rtl::OUString& ); + + static bool ISO8601_To_DateTime (const ::rtl::OUString&, + ::com::sun::star::util::DateTime& ); + + static bool RFC2068_To_DateTime (const ::rtl::OUString&, + ::com::sun::star::util::DateTime& ); + +public: + static bool convert (const ::rtl::OUString&, + ::com::sun::star::util::DateTime& ); +}; + +} // namespace http_dav_ucp + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/PropertyMap.hxx b/ucb/source/ucp/webdav/PropertyMap.hxx new file mode 100644 index 000000000000..2cb18e69610b --- /dev/null +++ b/ucb/source/ucp/webdav/PropertyMap.hxx @@ -0,0 +1,61 @@ +/* -*- 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 _WEBDAV_UCP_PROPERTYMAP_HXX +#define _WEBDAV_UCP_PROPERTYMAP_HXX + +#include +#include + +namespace http_dav_ucp { + +//========================================================================= + +struct equalPropertyName +{ + bool operator()( const ::com::sun::star::beans::Property & p1, + const ::com::sun::star::beans::Property & p2 ) const + { + return !!( p1.Name == p2.Name ); + } +}; + +struct hashPropertyName +{ + size_t operator()( const ::com::sun::star::beans::Property & p ) const + { + return p.Name.hashCode(); + } +}; + +typedef std::hash_set +< + ::com::sun::star::beans::Property, + hashPropertyName, + equalPropertyName +> +PropertyMap; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfCallbacks.cxx b/ucb/source/ucp/webdav/SerfCallbacks.cxx new file mode 100644 index 000000000000..007cdea70552 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfCallbacks.cxx @@ -0,0 +1,113 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include + +#include +#include + +using namespace http_dav_ucp; + +extern "C" apr_status_t Serf_ConnectSetup( apr_socket_t *skt, + serf_bucket_t **read_bkt, + serf_bucket_t **write_bkt, + void *setup_baton, + apr_pool_t *pool ) +{ + SerfSession* pSerfSession = static_cast< SerfSession* >( setup_baton ); + return pSerfSession->setupSerfConnection( skt, + read_bkt, + write_bkt, + pool ); +} + +extern "C" apr_status_t Serf_Credentials( char **username, + char **password, + serf_request_t *request, + void *baton, + int code, + const char *authn_type, + const char *realm, + apr_pool_t *pool ) +{ + SerfRequestProcessor* pReqProc = static_cast< SerfRequestProcessor* >( baton ); + return pReqProc->provideSerfCredentials( username, + password, + request, + code, + authn_type, + realm, + pool ); +} + +extern "C" apr_status_t Serf_CertificateChainValidation( + void* pSerfSession, + int nFailures, + const char** pCertificateChainBase64Encoded, + int nCertificateChainLength) +{ + return static_cast(pSerfSession) + ->verifySerfCertificateChain(nFailures, pCertificateChainBase64Encoded, nCertificateChainLength); +} + +extern "C" apr_status_t Serf_SetupRequest( serf_request_t *request, + void *setup_baton, + serf_bucket_t **req_bkt, + serf_response_acceptor_t *acceptor, + void **acceptor_baton, + serf_response_handler_t *handler, + void **handler_baton, + apr_pool_t * pool ) +{ + SerfRequestProcessor* pReqProc = static_cast< SerfRequestProcessor* >( setup_baton ); + return pReqProc->setupSerfRequest( request, + req_bkt, + acceptor, + acceptor_baton, + handler, + handler_baton, + pool ); +} + +extern "C" serf_bucket_t* Serf_AcceptResponse( serf_request_t *request, + serf_bucket_t *stream, + void *acceptor_baton, + apr_pool_t *pool ) +{ + SerfRequestProcessor* pReqProc = static_cast< SerfRequestProcessor* >( acceptor_baton ); + return pReqProc->acceptSerfResponse( request, + stream, + pool ); +} + +extern "C" apr_status_t Serf_HandleResponse( serf_request_t *request, + serf_bucket_t *response, + void *handler_baton, + apr_pool_t *pool ) +{ + SerfRequestProcessor* pReqProc = static_cast< SerfRequestProcessor* >( handler_baton ); + return pReqProc->handleSerfResponse( request, + response, + pool ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfCallbacks.hxx b/ucb/source/ucp/webdav/SerfCallbacks.hxx new file mode 100644 index 000000000000..af3be032d49a --- /dev/null +++ b/ucb/source/ucp/webdav/SerfCallbacks.hxx @@ -0,0 +1,68 @@ +/* -*- 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 INCLUDED_CALLBACKS_HXX +#define INCLUDED_CALLBACKS_HXX + +#include + +extern "C" apr_status_t Serf_ConnectSetup( apr_socket_t *skt, + serf_bucket_t **read_bkt, + serf_bucket_t **write_bkt, + void *setup_baton, + apr_pool_t *pool ); + +extern "C" apr_status_t Serf_Credentials( char **username, + char **password, + serf_request_t *request, + void *baton, + int code, + const char *authn_type, + const char *realm, + apr_pool_t *pool ); + +extern "C" apr_status_t Serf_CertificateChainValidation( + void* pSerfSession, + int nFailures, + const char** pCertificateChainBase64Encoded, + int nCertificateChainLength); + +extern "C" apr_status_t Serf_SetupRequest( serf_request_t *request, + void *setup_baton, + serf_bucket_t **req_bkt, + serf_response_acceptor_t *acceptor, + void **acceptor_baton, + serf_response_handler_t *handler, + void **handler_baton, + apr_pool_t * pool ); + +extern "C" serf_bucket_t* Serf_AcceptResponse( serf_request_t *request, + serf_bucket_t *stream, + void *acceptor_baton, + apr_pool_t *pool ); + +extern "C" apr_status_t Serf_HandleResponse( serf_request_t *request, + serf_bucket_t *response, + void *handler_baton, + apr_pool_t *pool ); + +#endif // INCLUDED_CALLBACKS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfCopyReqProcImpl.cxx b/ucb/source/ucp/webdav/SerfCopyReqProcImpl.cxx new file mode 100644 index 000000000000..70a9765a4931 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfCopyReqProcImpl.cxx @@ -0,0 +1,85 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include + +#include + +namespace http_dav_ucp +{ + +SerfCopyReqProcImpl::SerfCopyReqProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const char* inDestinationPath, + const bool inOverwrite ) + : SerfRequestProcessorImpl( inSourcePath, inRequestHeaders ) + , mDestPathStr( inDestinationPath ) + , mbOverwrite( inOverwrite ) +{ +} + +SerfCopyReqProcImpl::~SerfCopyReqProcImpl() +{ +} + +serf_bucket_t * SerfCopyReqProcImpl::createSerfRequestBucket( serf_request_t * inSerfRequest ) +{ + // create serf request + serf_bucket_t *req_bkt = serf_request_bucket_request_create( inSerfRequest, + "COPY", + getPathStr(), + 0, + serf_request_get_alloc( inSerfRequest ) ); + + // set request header fields + serf_bucket_t* hdrs_bkt = serf_bucket_request_get_headers( req_bkt ); + // general header fields provided by caller + setRequestHeaders( hdrs_bkt ); + + // COPY specific header fields + serf_bucket_headers_set( hdrs_bkt, "Destination", mDestPathStr ); + if ( mbOverwrite ) + { + serf_bucket_headers_set( hdrs_bkt, "Overwrite", "T" ); + } + else + { + serf_bucket_headers_set( hdrs_bkt, "Overwrite", "F" ); + } + + return req_bkt; +} + +void SerfCopyReqProcImpl::processChunkOfResponseData( const char* /*data*/, + apr_size_t /*len*/ ) +{ + // nothing to do; +} + +void SerfCopyReqProcImpl::handleEndOfResponseData( serf_bucket_t * /*inSerfResponseBucket*/ ) +{ + // nothing to do; +} + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfCopyReqProcImpl.hxx b/ucb/source/ucp/webdav/SerfCopyReqProcImpl.hxx new file mode 100644 index 000000000000..75631bb03519 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfCopyReqProcImpl.hxx @@ -0,0 +1,57 @@ +/* -*- 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 INCLUDED_SERFCOPYREQPROCIMPL_HXX +#define INCLUDED_SERFCOPYREQPROCIMPL_HXX + +#include + +namespace http_dav_ucp +{ + +class SerfCopyReqProcImpl : public SerfRequestProcessorImpl +{ +public: + SerfCopyReqProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const char* inDestinationPath, + const bool inOverwrite ); + + virtual ~SerfCopyReqProcImpl(); + + virtual + serf_bucket_t * createSerfRequestBucket( serf_request_t * inSerfRequest ); + +protected: + virtual + void processChunkOfResponseData( const char* data, apr_size_t len ); + + virtual + void handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ); + +private: + const char* mDestPathStr; + const bool mbOverwrite; +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFCOPYREQPROCIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfDeleteReqProcImpl.cxx b/ucb/source/ucp/webdav/SerfDeleteReqProcImpl.cxx new file mode 100644 index 000000000000..2bd60d1f6c34 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfDeleteReqProcImpl.cxx @@ -0,0 +1,70 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include + +#include + +namespace http_dav_ucp +{ + +SerfDeleteReqProcImpl::SerfDeleteReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders ) + : SerfRequestProcessorImpl( inPath, inRequestHeaders ) +{ +} + +SerfDeleteReqProcImpl::~SerfDeleteReqProcImpl() +{ +} + +serf_bucket_t * SerfDeleteReqProcImpl::createSerfRequestBucket( serf_request_t * inSerfRequest ) +{ + // create serf request + serf_bucket_t *req_bkt = serf_request_bucket_request_create( inSerfRequest, + "DELETE", + getPathStr(), + 0, + serf_request_get_alloc( inSerfRequest ) ); + + // set request header fields + serf_bucket_t* hdrs_bkt = serf_bucket_request_get_headers( req_bkt ); + // general header fields provided by caller + setRequestHeaders( hdrs_bkt ); + + return req_bkt; +} + +void SerfDeleteReqProcImpl::processChunkOfResponseData( const char* /*data*/, + apr_size_t /*len*/ ) +{ + // nothing to do; +} + +void SerfDeleteReqProcImpl::handleEndOfResponseData( serf_bucket_t * /*inSerfResponseBucket*/ ) +{ + // nothing to do; +} + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfDeleteReqProcImpl.hxx b/ucb/source/ucp/webdav/SerfDeleteReqProcImpl.hxx new file mode 100644 index 000000000000..1cf2ec15ded8 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfDeleteReqProcImpl.hxx @@ -0,0 +1,52 @@ +/* -*- 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 INCLUDED_SERFDELETEREQPROCIMPL_HXX +#define INCLUDED_SERFDELETEREQPROCIMPL_HXX + +#include + +namespace http_dav_ucp +{ + +class SerfDeleteReqProcImpl : public SerfRequestProcessorImpl +{ +public: + SerfDeleteReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders ); + + virtual ~SerfDeleteReqProcImpl(); + + virtual + serf_bucket_t * createSerfRequestBucket( serf_request_t * inSerfRequest ); + +protected: + virtual + void processChunkOfResponseData( const char* data, apr_size_t len ); + + virtual + void handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ); + +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFDELETEREQPROCIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfGetReqProcImpl.cxx b/ucb/source/ucp/webdav/SerfGetReqProcImpl.cxx new file mode 100644 index 000000000000..014af709cea6 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfGetReqProcImpl.cxx @@ -0,0 +1,187 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include + +using namespace com::sun::star; + +namespace http_dav_ucp +{ + +SerfGetReqProcImpl::SerfGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< SerfInputStream > & xioInStrm ) + : SerfRequestProcessorImpl( inPath, inRequestHeaders ) + , xInputStream( xioInStrm ) + , xOutputStream() + , mpHeaderNames( 0 ) + , mpResource( 0 ) +{ +} + +SerfGetReqProcImpl::SerfGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< SerfInputStream > & xioInStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource ) + : SerfRequestProcessorImpl( inPath, inRequestHeaders ) + , xInputStream( xioInStrm ) + , xOutputStream() + , mpHeaderNames( &inHeaderNames ) + , mpResource( &ioResource ) +{ +} + +SerfGetReqProcImpl::SerfGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > & xioOutStrm ) + : SerfRequestProcessorImpl( inPath, inRequestHeaders ) + , xInputStream() + , xOutputStream( xioOutStrm ) + , mpHeaderNames( 0 ) + , mpResource( 0 ) +{ +} + +SerfGetReqProcImpl::SerfGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > & xioOutStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource ) + : SerfRequestProcessorImpl( inPath, inRequestHeaders ) + , xInputStream() + , xOutputStream( xioOutStrm ) + , mpHeaderNames( &inHeaderNames ) + , mpResource( &ioResource ) +{ +} + +SerfGetReqProcImpl::~SerfGetReqProcImpl() +{ +} + +serf_bucket_t * SerfGetReqProcImpl::createSerfRequestBucket( serf_request_t * inSerfRequest ) +{ + // create serf request + serf_bucket_t *req_bkt = serf_request_bucket_request_create( inSerfRequest, + "GET", + getPathStr(), + 0, + serf_request_get_alloc( inSerfRequest ) ); + + // set request header fields + serf_bucket_t* hdrs_bkt = serf_bucket_request_get_headers( req_bkt ); + // general header fields provided by caller + setRequestHeaders( hdrs_bkt ); + + return req_bkt; +} + +void SerfGetReqProcImpl::processChunkOfResponseData( const char* data, + apr_size_t len ) +{ + if ( xInputStream.is() ) + { + xInputStream->AddToStream( data, len ); + } + else if ( xOutputStream.is() ) + { + const uno::Sequence< sal_Int8 > aDataSeq( (sal_Int8 *)data, len ); + xOutputStream->writeBytes( aDataSeq ); + } +} + +namespace +{ + apr_status_t Serf_ProcessResponseHeader( void* inUserData, + const char* inHeaderName, + const char* inHeaderValue ) + { + SerfGetReqProcImpl* pReqProcImpl = static_cast< SerfGetReqProcImpl* >( inUserData ); + pReqProcImpl->processSingleResponseHeader( inHeaderName, + inHeaderValue ); + + return APR_SUCCESS; + } +} // end of anonymous namespace + +void SerfGetReqProcImpl::handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ) +{ + // read response header, if requested + if ( mpHeaderNames != 0 && mpResource != 0 ) + { + serf_bucket_t* SerfHeaderBucket = serf_bucket_response_get_headers( inSerfResponseBucket ); + if ( SerfHeaderBucket != 0 ) + { + serf_bucket_headers_do( SerfHeaderBucket, + Serf_ProcessResponseHeader, + this ); + } + } +} + +void SerfGetReqProcImpl::processSingleResponseHeader( const char* inHeaderName, + const char* inHeaderValue ) +{ + rtl::OUString aHeaderName( rtl::OUString::createFromAscii( inHeaderName ) ); + + bool bStoreHeaderField = false; + + if ( mpHeaderNames->size() == 0 ) + { + // store all header fields + bStoreHeaderField = true; + } + else + { + // store only header fields which are requested + std::vector< ::rtl::OUString >::const_iterator it( mpHeaderNames->begin() ); + const std::vector< ::rtl::OUString >::const_iterator end( mpHeaderNames->end() ); + + while ( it != end ) + { + // header names are case insensitive + if ( (*it).equalsIgnoreAsciiCase( aHeaderName ) ) + { + bStoreHeaderField = true; + break; + } + else + { + ++it; + } + } + } + + if ( bStoreHeaderField ) + { + DAVPropertyValue thePropertyValue; + thePropertyValue.IsCaseSensitive = false; + thePropertyValue.Name = aHeaderName; + thePropertyValue.Value <<= rtl::OUString::createFromAscii( inHeaderValue ); + mpResource->properties.push_back( thePropertyValue ); + } +} + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfGetReqProcImpl.hxx b/ucb/source/ucp/webdav/SerfGetReqProcImpl.hxx new file mode 100644 index 000000000000..6497ecba2715 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfGetReqProcImpl.hxx @@ -0,0 +1,84 @@ +/* -*- 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 INCLUDED_SERFGETREQPROCIMPL_HXX +#define INCLUDED_SERFGETREQPROCIMPL_HXX + +#include + +#include +#include +#include + +#include +#include + +namespace http_dav_ucp +{ + +class SerfGetReqProcImpl : public SerfRequestProcessorImpl +{ +public: + SerfGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< SerfInputStream > & xioInStrm ); + + SerfGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< SerfInputStream > & xioInStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource ); + + SerfGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > & xioOutStrm ); + + SerfGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > & xioOutStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource ); + + virtual ~SerfGetReqProcImpl(); + + virtual + serf_bucket_t * createSerfRequestBucket( serf_request_t * inSerfRequest ); + + void processSingleResponseHeader( const char* inHeaderName, + const char* inHeaderValue ); + +protected: + virtual + void processChunkOfResponseData( const char* data, apr_size_t len ); + + virtual + void handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ); + +private: + com::sun::star::uno::Reference< SerfInputStream > xInputStream; + com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > xOutputStream; + const std::vector< ::rtl::OUString > * mpHeaderNames; + DAVResource* mpResource; +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFGETREQPROCIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfHeadReqProcImpl.cxx b/ucb/source/ucp/webdav/SerfHeadReqProcImpl.cxx new file mode 100644 index 000000000000..45ce6479bd73 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfHeadReqProcImpl.cxx @@ -0,0 +1,141 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include + +using namespace com::sun::star; + +namespace http_dav_ucp +{ + +SerfHeadReqProcImpl::SerfHeadReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource ) + : SerfRequestProcessorImpl( inPath, inRequestHeaders ) + , mpHeaderNames( &inHeaderNames ) + , mpResource( &ioResource ) +{ +} + +SerfHeadReqProcImpl::~SerfHeadReqProcImpl() +{ +} + +serf_bucket_t * SerfHeadReqProcImpl::createSerfRequestBucket( serf_request_t * inSerfRequest ) +{ + // create serf request + serf_bucket_t *req_bkt = serf_request_bucket_request_create( inSerfRequest, + "HEAD", + getPathStr(), + 0, + serf_request_get_alloc( inSerfRequest ) ); + + // set request header fields + serf_bucket_t* hdrs_bkt = serf_bucket_request_get_headers( req_bkt ); + // general header fields provided by caller + setRequestHeaders( hdrs_bkt ); + + return req_bkt; +} + +void SerfHeadReqProcImpl::processChunkOfResponseData( const char* /*data*/, + apr_size_t /*len*/ ) +{ + // nothing to do +} + +namespace +{ + apr_status_t Serf_ProcessResponseHeader( void* inUserData, + const char* inHeaderName, + const char* inHeaderValue ) + { + SerfHeadReqProcImpl* pReqProcImpl = static_cast< SerfHeadReqProcImpl* >( inUserData ); + pReqProcImpl->processSingleResponseHeader( inHeaderName, + inHeaderValue ); + + return APR_SUCCESS; + } +} // end of anonymous namespace + +void SerfHeadReqProcImpl::handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ) +{ + // read response header, if requested + if ( mpHeaderNames != 0 && mpResource != 0 ) + { + serf_bucket_t* SerfHeaderBucket = serf_bucket_response_get_headers( inSerfResponseBucket ); + if ( SerfHeaderBucket != 0 ) + { + serf_bucket_headers_do( SerfHeaderBucket, + Serf_ProcessResponseHeader, + this ); + } + } +} + +void SerfHeadReqProcImpl::processSingleResponseHeader( const char* inHeaderName, + const char* inHeaderValue ) +{ + rtl::OUString aHeaderName( rtl::OUString::createFromAscii( inHeaderName ) ); + + bool bStoreHeaderField = false; + + if ( mpHeaderNames->size() == 0 ) + { + // store all header fields + bStoreHeaderField = true; + } + else + { + // store only header fields which are requested + std::vector< ::rtl::OUString >::const_iterator it( mpHeaderNames->begin() ); + const std::vector< ::rtl::OUString >::const_iterator end( mpHeaderNames->end() ); + + while ( it != end ) + { + // header names are case insensitive + if ( (*it).equalsIgnoreAsciiCase( aHeaderName ) ) + { + bStoreHeaderField = true; + break; + } + else + { + ++it; + } + } + } + + if ( bStoreHeaderField ) + { + DAVPropertyValue thePropertyValue; + thePropertyValue.IsCaseSensitive = false; + thePropertyValue.Name = aHeaderName; + thePropertyValue.Value <<= rtl::OUString::createFromAscii( inHeaderValue ); + mpResource->properties.push_back( thePropertyValue ); + } +} + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfHeadReqProcImpl.hxx b/ucb/source/ucp/webdav/SerfHeadReqProcImpl.hxx new file mode 100644 index 000000000000..46039f130b49 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfHeadReqProcImpl.hxx @@ -0,0 +1,67 @@ +/* -*- 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 INCLUDED_SERFHEADREQPROCIMPL_HXX +#define INCLUDED_SERFHEADREQPROCIMPL_HXX + +#include + +#include +#include +#include + +#include +#include + +namespace http_dav_ucp +{ + +class SerfHeadReqProcImpl : public SerfRequestProcessorImpl +{ +public: + SerfHeadReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource ); + + virtual ~SerfHeadReqProcImpl(); + + virtual + serf_bucket_t * createSerfRequestBucket( serf_request_t * inSerfRequest ); + + void processSingleResponseHeader( const char* inHeaderName, + const char* inHeaderValue ); + +protected: + virtual + void processChunkOfResponseData( const char* data, apr_size_t len ); + + virtual + void handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ); + +private: + const std::vector< ::rtl::OUString > * mpHeaderNames; + DAVResource* mpResource; +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFHEADREQPROCIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfInputStream.cxx b/ucb/source/ucp/webdav/SerfInputStream.cxx new file mode 100644 index 000000000000..d8c72227aed8 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfInputStream.cxx @@ -0,0 +1,191 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" +#include "SerfInputStream.hxx" +#include + +using namespace cppu; +using namespace rtl; +using namespace com::sun::star::io; +using namespace com::sun::star::uno; +using namespace http_dav_ucp; + + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +SerfInputStream::SerfInputStream( void ) +: mLen( 0 ), + mPos( 0 ) +{ +} + +// ------------------------------------------------------------------- +// Destructor +// ------------------------------------------------------------------- +SerfInputStream::~SerfInputStream( void ) +{ +} + +// ------------------------------------------------------------------- +// AddToStream +// Allows the caller to add some data to the "end" of the stream +// ------------------------------------------------------------------- +void SerfInputStream::AddToStream( const char * inBuf, sal_Int32 inLen ) +{ + mInputBuffer.realloc( sal::static_int_cast(mLen) + inLen ); + rtl_copyMemory( mInputBuffer.getArray() + mLen, inBuf, inLen ); + mLen += inLen; +} + +// ------------------------------------------------------------------- +// queryInterface +// ------------------------------------------------------------------- +Any SerfInputStream::queryInterface( const Type &type ) + throw( RuntimeException ) +{ + Any aRet = ::cppu::queryInterface( type, + static_cast< XInputStream * >( this ), + static_cast< XSeekable * >( this ) ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( type ); +} + +// ------------------------------------------------------------------- +// readBytes +// "Reads" the specified number of bytes from the stream +// ------------------------------------------------------------------- +sal_Int32 SAL_CALL SerfInputStream::readBytes( + ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw( ::com::sun::star::io::NotConnectedException, + ::com::sun::star::io::BufferSizeExceededException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ) +{ + // Work out how much we're actually going to write + sal_Int32 theBytes2Read = nBytesToRead; + sal_Int32 theBytesLeft = sal::static_int_cast(mLen - mPos); + if ( theBytes2Read > theBytesLeft ) + theBytes2Read = theBytesLeft; + + // Realloc buffer. + aData.realloc( theBytes2Read ); + + // Write the data + rtl_copyMemory( + aData.getArray(), mInputBuffer.getConstArray() + mPos, theBytes2Read ); + + // Update our stream position for next time + mPos += theBytes2Read; + + return theBytes2Read; +} + +// ------------------------------------------------------------------- +// readSomeBytes +// ------------------------------------------------------------------- +sal_Int32 SAL_CALL SerfInputStream::readSomeBytes( + ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw( ::com::sun::star::io::NotConnectedException, + ::com::sun::star::io::BufferSizeExceededException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ) +{ + // Warning: What should this be doing ? + return readBytes( aData, nMaxBytesToRead ); +} + +// ------------------------------------------------------------------- +// skipBytes +// Moves the current stream position forward +// ------------------------------------------------------------------- +void SAL_CALL SerfInputStream::skipBytes( sal_Int32 nBytesToSkip ) + throw( ::com::sun::star::io::NotConnectedException, + ::com::sun::star::io::BufferSizeExceededException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ) +{ + mPos += nBytesToSkip; + if ( mPos >= mLen ) + mPos = mLen; +} + +// ------------------------------------------------------------------- +// available +// Returns the number of unread bytes currently remaining on the stream +// ------------------------------------------------------------------- +sal_Int32 SAL_CALL SerfInputStream::available( ) + throw( ::com::sun::star::io::NotConnectedException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ) +{ + return sal::static_int_cast(mLen - mPos); +} + +// ------------------------------------------------------------------- +// closeInput +// ------------------------------------------------------------------- +void SAL_CALL SerfInputStream::closeInput( void ) + throw( ::com::sun::star::io::NotConnectedException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ) +{ +} + +// ------------------------------------------------------------------- +// seek +// ------------------------------------------------------------------- +void SAL_CALL SerfInputStream::seek( sal_Int64 location ) + throw( ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ) +{ + if ( location < 0 ) + throw ::com::sun::star::lang::IllegalArgumentException(); + + if ( location <= mLen ) + mPos = location; + else + throw ::com::sun::star::lang::IllegalArgumentException(); +} + +// ------------------------------------------------------------------- +// getPosition +// ------------------------------------------------------------------- +sal_Int64 SAL_CALL SerfInputStream::getPosition() + throw( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ) +{ + return mPos; +} + +// ------------------------------------------------------------------- +// getLength +// ------------------------------------------------------------------- +sal_Int64 SAL_CALL SerfInputStream::getLength() + throw( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ) +{ + return mLen; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfInputStream.hxx b/ucb/source/ucp/webdav/SerfInputStream.hxx new file mode 100644 index 000000000000..2045df6913c4 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfInputStream.hxx @@ -0,0 +1,121 @@ +/* -*- 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 INCLUDED_NEONINPUTSTREAM_HXX +#define INCLUDED_NEONINPUTSTREAM_HXX + +#include +#include +#include +#include +#include + + +namespace http_dav_ucp +{ + +// ------------------------------------------------------------------- +// SerfInputStream +// A simple XInputStream implementation provided specifically for use +// by the DAVSession::GET method. +// ------------------------------------------------------------------- +class SerfInputStream : public ::com::sun::star::io::XInputStream, + public ::com::sun::star::io::XSeekable, + public ::cppu::OWeakObject +{ + private: + com::sun::star::uno::Sequence< sal_Int8 > mInputBuffer; + sal_Int64 mLen; + sal_Int64 mPos; + + public: + SerfInputStream( void ); + virtual ~SerfInputStream(); + + // Add some data to the end of the stream + void AddToStream( const char * inBuf, sal_Int32 inLen ); + + // XInterface + virtual com::sun::star::uno::Any SAL_CALL queryInterface( + const ::com::sun::star::uno::Type & type ) + throw( ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL acquire( void ) + throw () + { OWeakObject::acquire(); } + + virtual void SAL_CALL release( void ) + throw() + { OWeakObject::release(); } + + + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( + ::com::sun::star::uno::Sequence< sal_Int8 > & aData, + sal_Int32 nBytesToRead ) + throw( ::com::sun::star::io::NotConnectedException, + ::com::sun::star::io::BufferSizeExceededException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + + virtual sal_Int32 SAL_CALL readSomeBytes( + ::com::sun::star::uno::Sequence< sal_Int8 > & aData, + sal_Int32 nMaxBytesToRead ) + throw( ::com::sun::star::io::NotConnectedException, + ::com::sun::star::io::BufferSizeExceededException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) + throw( ::com::sun::star::io::NotConnectedException, + ::com::sun::star::io::BufferSizeExceededException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + + virtual sal_Int32 SAL_CALL available( void ) + throw( ::com::sun::star::io::NotConnectedException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL closeInput( void ) + throw( ::com::sun::star::io::NotConnectedException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + + // XSeekable + virtual void SAL_CALL seek( sal_Int64 location ) + throw( ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + + virtual sal_Int64 SAL_CALL getPosition() + throw( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + + virtual sal_Int64 SAL_CALL getLength() + throw( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_NEONINPUTSTREAM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfLockStore.cxx b/ucb/source/ucp/webdav/SerfLockStore.cxx new file mode 100644 index 000000000000..aa5e65c4f46e --- /dev/null +++ b/ucb/source/ucp/webdav/SerfLockStore.cxx @@ -0,0 +1,241 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include +#include +#include "rtl/ustring.hxx" +#include "osl/time.h" +#include "osl/thread.hxx" +#include "SerfSession.hxx" +#include "SerfLockStore.hxx" + +using namespace http_dav_ucp; + +namespace http_dav_ucp { + +class TickerThread : public osl::Thread +{ + bool m_bFinish; + SerfLockStore & m_rLockStore; + +public: + + TickerThread( SerfLockStore & rLockStore ) + : osl::Thread(), m_bFinish( false ), m_rLockStore( rLockStore ) {} + + void finish() { m_bFinish = true; } + +protected: + + virtual void SAL_CALL run(); +}; + +} // namespace http_dav_ucp + +// ------------------------------------------------------------------- +void TickerThread::run() +{ + OSL_TRACE( "TickerThread: start." ); + + // we have to go through the loop more often to be able to finish ~quickly + const int nNth = 25; + + int nCount = nNth; + while ( !m_bFinish ) + { + if ( nCount-- <= 0 ) + { + m_rLockStore.refreshLocks(); + nCount = nNth; + } + + TimeValue aTV; + aTV.Seconds = 0; + aTV.Nanosec = 1000000000 / nNth; + wait( aTV ); + } + + OSL_TRACE( "TickerThread: stop." ); +} + +// ------------------------------------------------------------------- +SerfLockStore::SerfLockStore() + : m_pSerfLockStore( ne_lockstore_create() ), + m_pTickerThread( 0 ) +{ + OSL_ENSURE( m_pSerfLockStore, "Unable to create neon lock store!" ); +} + +// ------------------------------------------------------------------- +SerfLockStore::~SerfLockStore() +{ + stopTicker(); + + // release active locks, if any. + OSL_ENSURE( m_aLockInfoMap.size() == 0, + "SerfLockStore::~SerfLockStore - Releasing active locks!" ); + + LockInfoMap::const_iterator it( m_aLockInfoMap.begin() ); + const LockInfoMap::const_iterator end( m_aLockInfoMap.end() ); + while ( it != end ) + { + SerfLock * pLock = (*it).first; + (*it).second.xSession->UNLOCK( pLock ); + + ne_lockstore_remove( m_pSerfLockStore, pLock ); + ne_lock_destroy( pLock ); + + ++it; + } + + ne_lockstore_destroy( m_pSerfLockStore ); +} + +// ------------------------------------------------------------------- +void SerfLockStore::startTicker() +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pTickerThread ) + { + m_pTickerThread = new TickerThread( *this ); + m_pTickerThread->create(); + } +} + +// ------------------------------------------------------------------- +void SerfLockStore::stopTicker() +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pTickerThread ) + { + m_pTickerThread->finish(); + m_pTickerThread->join(); + delete m_pTickerThread; + m_pTickerThread = 0; + } +} + +// ------------------------------------------------------------------- +void SerfLockStore::registerSession( HttpSession * pHttpSession ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + ne_lockstore_register( m_pSerfLockStore, pHttpSession ); +} + +// ------------------------------------------------------------------- +SerfLock * SerfLockStore::findByUri( rtl::OUString const & rUri ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + ne_uri aUri; + ne_uri_parse( rtl::OUStringToOString( + rUri, RTL_TEXTENCODING_UTF8 ).getStr(), &aUri ); + return ne_lockstore_findbyuri( m_pSerfLockStore, &aUri ); +} + +// ------------------------------------------------------------------- +void SerfLockStore::addLock( SerfLock * pLock, + rtl::Reference< SerfSession > const & xSession, + sal_Int32 nLastChanceToSendRefreshRequest ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + ne_lockstore_add( m_pSerfLockStore, pLock ); + m_aLockInfoMap[ pLock ] + = LockInfo( xSession, nLastChanceToSendRefreshRequest ); + + startTicker(); +} + +// ------------------------------------------------------------------- +void SerfLockStore::updateLock( SerfLock * pLock, + sal_Int32 nLastChanceToSendRefreshRequest ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + LockInfoMap::iterator it( m_aLockInfoMap.find( pLock ) ); + OSL_ENSURE( it != m_aLockInfoMap.end(), + "SerfLockStore::updateLock: lock not found!" ); + + if ( it != m_aLockInfoMap.end() ) + { + (*it).second.nLastChanceToSendRefreshRequest + = nLastChanceToSendRefreshRequest; + } +} + +// ------------------------------------------------------------------- +void SerfLockStore::removeLock( SerfLock * pLock ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + m_aLockInfoMap.erase( pLock ); + ne_lockstore_remove( m_pSerfLockStore, pLock ); + + if ( m_aLockInfoMap.size() == 0 ) + stopTicker(); +} + +// ------------------------------------------------------------------- +void SerfLockStore::refreshLocks() +{ + osl::MutexGuard aGuard( m_aMutex ); + + LockInfoMap::iterator it( m_aLockInfoMap.begin() ); + const LockInfoMap::const_iterator end( m_aLockInfoMap.end() ); + while ( it != end ) + { + LockInfo & rInfo = (*it).second; + if ( rInfo.nLastChanceToSendRefreshRequest != -1 ) + { + // 30 seconds or less remaining until lock expires? + TimeValue t1; + osl_getSystemTime( &t1 ); + if ( rInfo.nLastChanceToSendRefreshRequest - 30 + <= sal_Int32( t1.Seconds ) ) + { + // refresh the lock. + sal_Int32 nlastChanceToSendRefreshRequest = -1; + if ( rInfo.xSession->LOCK( + (*it).first, + /* out param */ nlastChanceToSendRefreshRequest ) ) + { + rInfo.nLastChanceToSendRefreshRequest + = nlastChanceToSendRefreshRequest; + } + else + { + // refresh failed. stop auto-refresh. + rInfo.nLastChanceToSendRefreshRequest = -1; + } + } + } + ++it; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfLockStore.hxx b/ucb/source/ucp/webdav/SerfLockStore.hxx new file mode 100644 index 000000000000..cc11af5e4011 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfLockStore.hxx @@ -0,0 +1,97 @@ +/* -*- 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 INCLUDED_SERFLOCKSTORE_HXX +#define INCLUDED_SERFLOCKSTORE_HXX + +#include +#include "osl/mutex.hxx" +#include "rtl/ref.hxx" +#include "SerfTypes.hxx" + +namespace http_dav_ucp +{ + +class TickerThread; +class SerfSession; + +struct ltptr +{ + bool operator()( const SerfLock * p1, const SerfLock * p2 ) const + { + return p1 < p2; + } +}; + +typedef struct _LockInfo +{ + rtl::Reference< SerfSession > xSession; + sal_Int32 nLastChanceToSendRefreshRequest; + + _LockInfo() + : nLastChanceToSendRefreshRequest( -1 ) {} + + _LockInfo( rtl::Reference< SerfSession > const & _xSession, + sal_Int32 _nLastChanceToSendRefreshRequest ) + : xSession( _xSession ), + nLastChanceToSendRefreshRequest( _nLastChanceToSendRefreshRequest ) {} + +} LockInfo; + +typedef std::map< SerfLock *, LockInfo, ltptr > LockInfoMap; + +class SerfLockStore +{ + osl::Mutex m_aMutex; +// ne_lock_store * m_pSerfLockStore; + TickerThread * m_pTickerThread; + LockInfoMap m_aLockInfoMap; + +public: + SerfLockStore(); + ~SerfLockStore(); + + void registerSession( HttpSession * pHttpSession ); + + SerfLock * findByUri( rtl::OUString const & rUri ); + + void addLock( SerfLock * pLock, + rtl::Reference< SerfSession > const & xSession, + // time in seconds since Jan 1 1970 + // -1: infinite lock, no refresh + sal_Int32 nLastChanceToSendRefreshRequest ); + + void updateLock( SerfLock * pLock, + sal_Int32 nLastChanceToSendRefreshRequest ); + + void removeLock( SerfLock * pLock ); + + void refreshLocks(); + +private: + void startTicker(); + void stopTicker(); +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFLOCKSTORE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfMkColReqProcImpl.cxx b/ucb/source/ucp/webdav/SerfMkColReqProcImpl.cxx new file mode 100644 index 000000000000..e9e7c72ed410 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfMkColReqProcImpl.cxx @@ -0,0 +1,70 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include + +#include + +namespace http_dav_ucp +{ + +SerfMkColReqProcImpl::SerfMkColReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders ) + : SerfRequestProcessorImpl( inPath,inRequestHeaders ) +{ +} + +SerfMkColReqProcImpl::~SerfMkColReqProcImpl() +{ +} + +serf_bucket_t * SerfMkColReqProcImpl::createSerfRequestBucket( serf_request_t * inSerfRequest ) +{ + // create serf request + serf_bucket_t *req_bkt = serf_request_bucket_request_create( inSerfRequest, + "MKCOL", + getPathStr(), + 0, + serf_request_get_alloc( inSerfRequest ) ); + + // set request header fields + serf_bucket_t* hdrs_bkt = serf_bucket_request_get_headers( req_bkt ); + // general header fields provided by caller + setRequestHeaders( hdrs_bkt ); + + return req_bkt; +} + +void SerfMkColReqProcImpl::processChunkOfResponseData( const char* /*data*/, + apr_size_t /*len*/ ) +{ + // nothing to do; +} + +void SerfMkColReqProcImpl::handleEndOfResponseData( serf_bucket_t * /*inSerfResponseBucket*/ ) +{ + // nothing to do; +} + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfMkColReqProcImpl.hxx b/ucb/source/ucp/webdav/SerfMkColReqProcImpl.hxx new file mode 100644 index 000000000000..3e1ded50bca4 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfMkColReqProcImpl.hxx @@ -0,0 +1,51 @@ +/* -*- 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 INCLUDED_SERFMKCOLREQPROCIMPL_HXX +#define INCLUDED_SERFMKCOLREQPROCIMPL_HXX + +#include + +namespace http_dav_ucp +{ + +class SerfMkColReqProcImpl : public SerfRequestProcessorImpl +{ +public: + SerfMkColReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders ); + + virtual ~SerfMkColReqProcImpl(); + + virtual + serf_bucket_t * createSerfRequestBucket( serf_request_t * inSerfRequest ); + +protected: + virtual + void processChunkOfResponseData( const char* data, apr_size_t len ); + + virtual + void handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ); +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFMKCOLREQPROCIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfMoveReqProcImpl.cxx b/ucb/source/ucp/webdav/SerfMoveReqProcImpl.cxx new file mode 100644 index 000000000000..39f74e37aa2b --- /dev/null +++ b/ucb/source/ucp/webdav/SerfMoveReqProcImpl.cxx @@ -0,0 +1,85 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include + +#include + +namespace http_dav_ucp +{ + +SerfMoveReqProcImpl::SerfMoveReqProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const char* inDestinationPath, + const bool inOverwrite ) + : SerfRequestProcessorImpl( inSourcePath, inRequestHeaders ) + , mDestPathStr( inDestinationPath ) + , mbOverwrite( inOverwrite ) +{ +} + +SerfMoveReqProcImpl::~SerfMoveReqProcImpl() +{ +} + +serf_bucket_t * SerfMoveReqProcImpl::createSerfRequestBucket( serf_request_t * inSerfRequest ) +{ + // create serf request + serf_bucket_t *req_bkt = serf_request_bucket_request_create( inSerfRequest, + "MOVE", + getPathStr(), + 0, + serf_request_get_alloc( inSerfRequest ) ); + + // set request header fields + serf_bucket_t* hdrs_bkt = serf_bucket_request_get_headers( req_bkt ); + // general header fields provided by caller + setRequestHeaders( hdrs_bkt ); + + // MOVE specific header fields + serf_bucket_headers_set( hdrs_bkt, "Destination", mDestPathStr ); + if ( mbOverwrite ) + { + serf_bucket_headers_set( hdrs_bkt, "Overwrite", "T" ); + } + else + { + serf_bucket_headers_set( hdrs_bkt, "Overwrite", "F" ); + } + + return req_bkt; +} + +void SerfMoveReqProcImpl::processChunkOfResponseData( const char* /*data*/, + apr_size_t /*len*/ ) +{ + // nothing to do; +} + +void SerfMoveReqProcImpl::handleEndOfResponseData( serf_bucket_t * /*inSerfResponseBucket*/ ) +{ + // nothing to do; +} + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfMoveReqProcImpl.hxx b/ucb/source/ucp/webdav/SerfMoveReqProcImpl.hxx new file mode 100644 index 000000000000..0ed5d2d85d1e --- /dev/null +++ b/ucb/source/ucp/webdav/SerfMoveReqProcImpl.hxx @@ -0,0 +1,57 @@ +/* -*- 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 INCLUDED_SERFMOVEREQPROCIMPL_HXX +#define INCLUDED_SERFMOVEREQPROCIMPL_HXX + +#include + +namespace http_dav_ucp +{ + +class SerfMoveReqProcImpl : public SerfRequestProcessorImpl +{ +public: + SerfMoveReqProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const char* inDestinationPath, + const bool inOverwrite ); + + virtual ~SerfMoveReqProcImpl(); + + virtual + serf_bucket_t * createSerfRequestBucket( serf_request_t * inSerfRequest ); + +protected: + virtual + void processChunkOfResponseData( const char* data, apr_size_t len ); + + virtual + void handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ); + +private: + const char* mDestPathStr; + const bool mbOverwrite; +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFMOVEREQPROCIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfPostReqProcImpl.cxx b/ucb/source/ucp/webdav/SerfPostReqProcImpl.cxx new file mode 100644 index 000000000000..e5d2060cd0d9 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfPostReqProcImpl.cxx @@ -0,0 +1,140 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include + +#include + +using namespace com::sun::star; + +namespace http_dav_ucp +{ + +SerfPostReqProcImpl::SerfPostReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const char* inData, + apr_size_t inDataLen, + const char* inContentType, + const char* inReferer, + const com::sun::star::uno::Reference< SerfInputStream > & xioInStrm ) + : SerfRequestProcessorImpl( inPath, inRequestHeaders ) + , mpPostData( inData ) + , mnPostDataLen( inDataLen ) + , mpContentType( inContentType ) + , mpReferer( inReferer ) + , xInputStream( xioInStrm ) + , xOutputStream() +{ +} + +SerfPostReqProcImpl::SerfPostReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const char* inData, + apr_size_t inDataLen, + const char* inContentType, + const char* inReferer, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > & xioOutStrm ) + : SerfRequestProcessorImpl( inPath, inRequestHeaders ) + , mpPostData( inData ) + , mnPostDataLen( inDataLen ) + , mpContentType( inContentType ) + , mpReferer( inReferer ) + , xInputStream() + , xOutputStream( xioOutStrm ) +{ +} + +SerfPostReqProcImpl::~SerfPostReqProcImpl() +{ +} + +serf_bucket_t * SerfPostReqProcImpl::createSerfRequestBucket( serf_request_t * inSerfRequest ) +{ + serf_bucket_alloc_t* pSerfBucketAlloc = serf_request_get_alloc( inSerfRequest ); + + // create body bucket + serf_bucket_t* body_bkt = 0; + if ( mpPostData != 0 && mnPostDataLen > 0 ) + { + body_bkt = SERF_BUCKET_SIMPLE_STRING_LEN( mpPostData, mnPostDataLen, pSerfBucketAlloc ); + if ( useChunkedEncoding() ) + { + body_bkt = serf_bucket_chunk_create( body_bkt, pSerfBucketAlloc ); + } + } + + // create serf request + serf_bucket_t *req_bkt = serf_request_bucket_request_create( inSerfRequest, + "POST", + getPathStr(), + body_bkt, + serf_request_get_alloc( inSerfRequest ) ); + + // set request header fields + serf_bucket_t* hdrs_bkt = serf_bucket_request_get_headers( req_bkt ); + // general header fields provided by caller + setRequestHeaders( hdrs_bkt ); + + // request specific header fields + if ( body_bkt != 0 ) + { + if ( useChunkedEncoding() ) + { + serf_bucket_headers_set( hdrs_bkt, "Transfer-Encoding", "chunked"); + } + serf_bucket_headers_set( hdrs_bkt, "Content-Length", + rtl::OUStringToOString( rtl::OUString::valueOf( (sal_Int32)mnPostDataLen ), RTL_TEXTENCODING_UTF8 ) ); + } + if ( mpContentType != 0 ) + { + serf_bucket_headers_set( hdrs_bkt, "Content-Type", mpContentType ); + } + if ( mpReferer != 0 ) + { + serf_bucket_headers_set( hdrs_bkt, "Referer", mpReferer ); + } + + return req_bkt; +} + +void SerfPostReqProcImpl::processChunkOfResponseData( const char* data, + apr_size_t len ) +{ + if ( xInputStream.is() ) + { + xInputStream->AddToStream( data, len ); + } + else if ( xOutputStream.is() ) + { + const uno::Sequence< sal_Int8 > aDataSeq( (sal_Int8 *)data, len ); + xOutputStream->writeBytes( aDataSeq ); + } +} + +void SerfPostReqProcImpl::handleEndOfResponseData( serf_bucket_t * /*inSerfResponseBucket*/ ) +{ + // nothing to do; +} + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfPostReqProcImpl.hxx b/ucb/source/ucp/webdav/SerfPostReqProcImpl.hxx new file mode 100644 index 000000000000..9cb6af313088 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfPostReqProcImpl.hxx @@ -0,0 +1,76 @@ +/* -*- 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 INCLUDED_SERFPOSTREQPROCIMPL_HXX +#define INCLUDED_SERFPOSTREQPROCIMPL_HXX + +#include + +#include +#include + +namespace http_dav_ucp +{ + +class SerfPostReqProcImpl : public SerfRequestProcessorImpl +{ +public: + SerfPostReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const char* inData, + apr_size_t inDataLen, + const char* inContentType, + const char* inReferer, + const com::sun::star::uno::Reference< SerfInputStream > & xioInStrm ); + + SerfPostReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const char* inData, + apr_size_t inDataLen, + const char* inContentType, + const char* inReferer, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > & xioOutStrm ); + + virtual ~SerfPostReqProcImpl(); + + virtual + serf_bucket_t * createSerfRequestBucket( serf_request_t * inSerfRequest ); + +protected: + virtual + void processChunkOfResponseData( const char* data, apr_size_t len ); + + virtual + void handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ); + +private: + const char* mpPostData; + apr_size_t mnPostDataLen; + const char* mpContentType; + const char* mpReferer; + com::sun::star::uno::Reference< SerfInputStream > xInputStream; + com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > xOutputStream; + +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFPOSTREQPROCIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfPropFindReqProcImpl.cxx b/ucb/source/ucp/webdav/SerfPropFindReqProcImpl.cxx new file mode 100644 index 000000000000..d4a3f4f419b2 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfPropFindReqProcImpl.cxx @@ -0,0 +1,198 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include +#include +#include + +#include +#include + +using namespace com::sun::star; + +namespace http_dav_ucp +{ + +SerfPropFindReqProcImpl::SerfPropFindReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const Depth inDepth, + const std::vector< ::rtl::OUString > & inPropNames, + std::vector< DAVResource > & ioResources ) + : SerfRequestProcessorImpl( inPath, inRequestHeaders ) + , mDepthStr( 0 ) + , mpPropNames( &inPropNames ) + , mpResources( &ioResources ) + , mpResInfo( 0 ) + , mbOnlyPropertyNames( false ) + , xInputStream( new SerfInputStream() ) +{ + init( inDepth ); +} + +SerfPropFindReqProcImpl::SerfPropFindReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const Depth inDepth, + std::vector< DAVResourceInfo > & ioResInfo ) + : SerfRequestProcessorImpl( inPath, inRequestHeaders ) + , mDepthStr( 0 ) + , mpPropNames( 0 ) + , mpResources( 0 ) + , mpResInfo( &ioResInfo ) + , mbOnlyPropertyNames( true ) + , xInputStream( new SerfInputStream() ) +{ + init( inDepth ); +} + +void SerfPropFindReqProcImpl::init( const Depth inDepth ) +{ + switch ( inDepth ) + { + case DAVZERO: + mDepthStr = "0"; + break; + case DAVONE: + mDepthStr = "1"; + break; + case DAVINFINITY: + mDepthStr = "infinity"; + break; + } +} + +SerfPropFindReqProcImpl::~SerfPropFindReqProcImpl() +{ +} + +#define PROPFIND_HEADER "" +#define PROPFIND_TRAILER "" + +serf_bucket_t * SerfPropFindReqProcImpl::createSerfRequestBucket( serf_request_t * inSerfRequest ) +{ + serf_bucket_alloc_t* pSerfBucketAlloc = serf_request_get_alloc( inSerfRequest ); + + // body bucket - certain properties OR all properties OR only property names + serf_bucket_t* body_bkt = 0; + rtl::OUString aBodyText; + { + // create and fill body bucket with requested properties + const int nPropCount = ( !mbOnlyPropertyNames && mpPropNames ) + ? mpPropNames->size() + : 0; + if ( nPropCount > 0 ) + { + SerfPropName thePropName; + for ( int theIndex = 0; theIndex < nPropCount; theIndex ++ ) + { + // split fullname into namespace and name! + DAVProperties::createSerfPropName( (*mpPropNames)[ theIndex ], + thePropName ); + + /* <*propname* xmlns="*propns*" /> */ + aBodyText += rtl::OUString::createFromAscii( "<" ); + aBodyText += rtl::OUString::createFromAscii( thePropName.name ); + aBodyText += rtl::OUString::createFromAscii( " xmlnx=\"" ); + aBodyText += rtl::OUString::createFromAscii( thePropName.nspace ); + aBodyText += rtl::OUString::createFromAscii( "\"/>" ); + } + + aBodyText = rtl::OUString::createFromAscii( "" ) + + aBodyText + + rtl::OUString::createFromAscii( "" ); + } + else + { + if ( mbOnlyPropertyNames ) + { + aBodyText = rtl::OUString::createFromAscii( "" ); + } + else + { + aBodyText = rtl::OUString::createFromAscii( "" ); + } + } + + aBodyText = rtl::OUString::createFromAscii( PROPFIND_HEADER ) + + aBodyText + + rtl::OUString::createFromAscii( PROPFIND_TRAILER ); + body_bkt = SERF_BUCKET_SIMPLE_STRING( rtl::OUStringToOString( aBodyText, RTL_TEXTENCODING_UTF8 ), + pSerfBucketAlloc ); + if ( useChunkedEncoding() ) + { + body_bkt = serf_bucket_chunk_create( body_bkt, pSerfBucketAlloc ); + } + } + + // create serf request + serf_bucket_t *req_bkt = serf_request_bucket_request_create( inSerfRequest, + "PROPFIND", + getPathStr(), + body_bkt, + pSerfBucketAlloc ); + + // set request header fields + serf_bucket_t* hdrs_bkt = serf_bucket_request_get_headers( req_bkt ); + // general header fields provided by caller + setRequestHeaders( hdrs_bkt ); + + // request specific header fields + serf_bucket_headers_set( hdrs_bkt, "Depth", mDepthStr ); + if ( body_bkt != 0 && aBodyText.getLength() > 0 ) + { + if ( useChunkedEncoding() ) + { + serf_bucket_headers_set( hdrs_bkt, "Transfer-Encoding", "chunked"); + } + serf_bucket_headers_set( hdrs_bkt, "Content-Type", "application/xml" ); + serf_bucket_headers_set( hdrs_bkt, "Content-Length", + rtl::OUStringToOString( rtl::OUString::valueOf( aBodyText.getLength() ), RTL_TEXTENCODING_UTF8 ) ); + } + + return req_bkt; +} + +void SerfPropFindReqProcImpl::processChunkOfResponseData( const char* data, + apr_size_t len ) +{ + if ( xInputStream.is() ) + { + xInputStream->AddToStream( data, len ); + } +} + +void SerfPropFindReqProcImpl::handleEndOfResponseData( serf_bucket_t * /*inSerfResponseBucket*/ ) +{ + if ( mbOnlyPropertyNames ) + { + const std::vector< DAVResourceInfo > rResInfo( parseWebDAVPropNameResponse( xInputStream.get() ) ); + *mpResInfo = rResInfo; + } + else + { + const std::vector< DAVResource > rResources( parseWebDAVPropFindResponse( xInputStream.get() ) ); + *mpResources = rResources; + } +} + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfPropFindReqProcImpl.hxx b/ucb/source/ucp/webdav/SerfPropFindReqProcImpl.hxx new file mode 100644 index 000000000000..92ea5a7fed91 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfPropFindReqProcImpl.hxx @@ -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 . + */ + +#ifndef INCLUDED_SERFPROPFINDREQPROCIMPL_HXX +#define INCLUDED_SERFPROPFINDREQPROCIMPL_HXX + +#include + +#include +#include +#include "DAVTypes.hxx" +#include "DAVResource.hxx" + +#include + +namespace http_dav_ucp +{ + +class SerfPropFindReqProcImpl : public SerfRequestProcessorImpl +{ +public: + SerfPropFindReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const Depth inDepth, + const std::vector< ::rtl::OUString > & inPropNames, + std::vector< DAVResource > & ioResources ); + + SerfPropFindReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const Depth inDepth, + std::vector< DAVResourceInfo > & ioResInfo ); + + virtual ~SerfPropFindReqProcImpl(); + + virtual + serf_bucket_t * createSerfRequestBucket( serf_request_t * inSerfRequest ); + +protected: + virtual + void processChunkOfResponseData( const char* data, apr_size_t len ); + + virtual + void handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ); + +private: + void init( const Depth inDepth ); + + const char* mDepthStr; + const std::vector< ::rtl::OUString > * mpPropNames; + std::vector< DAVResource > * mpResources; + std::vector< DAVResourceInfo > * mpResInfo; + + const bool mbOnlyPropertyNames; + com::sun::star::uno::Reference< SerfInputStream > xInputStream; +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFPROPFINDREQPROCIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfPropPatchReqProcImpl.cxx b/ucb/source/ucp/webdav/SerfPropPatchReqProcImpl.cxx new file mode 100644 index 000000000000..e39e3ce63360 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfPropPatchReqProcImpl.cxx @@ -0,0 +1,183 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include +#include +#include + +#include +#include + +namespace http_dav_ucp +{ + +SerfPropPatchReqProcImpl::SerfPropPatchReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const std::vector< ProppatchValue > & inProperties ) + : SerfRequestProcessorImpl( inPath, inRequestHeaders ) + , mpProperties( &inProperties ) +{ +} + +SerfPropPatchReqProcImpl::~SerfPropPatchReqProcImpl() +{ +} + +#define PROPPATCH_HEADER "" +#define PROPPATCH_TRAILER "" + +serf_bucket_t * SerfPropPatchReqProcImpl::createSerfRequestBucket( serf_request_t * inSerfRequest ) +{ + serf_bucket_alloc_t* pSerfBucketAlloc = serf_request_get_alloc( inSerfRequest ); + + // body bucket + serf_bucket_t* body_bkt = 0; + rtl::OUString aBodyText; + { + // create and fill body bucket with properties to be set or removed + static const char* OpCodes[2] = { "set", "remove" }; + const int nPropCount = ( mpProperties != 0 ) + ? mpProperties->size() + : 0; + if ( nPropCount > 0 ) + { + // <*operation code*> + ProppatchOperation lastOp = (*mpProperties)[ 0 ].operation; + aBodyText += rtl::OUString::createFromAscii( "<" ); + aBodyText += rtl::OUString::createFromAscii( OpCodes[lastOp] ); + aBodyText += rtl::OUString::createFromAscii( ">" ); + + SerfPropName thePropName; + for ( int n = 0; n < nPropCount; ++n ) + { + const ProppatchValue & rProperty = (*mpProperties)[ n ]; + // split fullname into namespace and name! + DAVProperties::createSerfPropName( rProperty.name, + thePropName ); + + if ( rProperty.operation != lastOp ) + { + // <*operation code> + aBodyText += rtl::OUString::createFromAscii( "<" ); + aBodyText += rtl::OUString::createFromAscii( OpCodes[rProperty.operation] ); + aBodyText += rtl::OUString::createFromAscii( ">" ); + } + + // <*propname* xmlns="*propns*" + aBodyText += rtl::OUString::createFromAscii( "<" ); + aBodyText += rtl::OUString::createFromAscii( thePropName.name ); + aBodyText += rtl::OUString::createFromAscii( " xmlns=\"" ); + aBodyText += rtl::OUString::createFromAscii( thePropName.nspace ); + aBodyText += rtl::OUString::createFromAscii( "\"" ); + + if ( rProperty.operation == PROPSET ) + { + // >*property value* + aBodyText += rtl::OUString::createFromAscii( ">" ); + + rtl::OUString aStringValue; + if ( DAVProperties::isUCBDeadProperty( thePropName ) ) + { + UCBDeadPropertyValue::toXML( rProperty.value, + aStringValue ); + } + else + { + rProperty.value >>= aStringValue; + } + aBodyText += aStringValue; + aBodyText += rtl::OUString::createFromAscii( "" ); + } + else + { + // /> + aBodyText += rtl::OUString::createFromAscii( "/>" ); + } + + lastOp = rProperty.operation; + } + + // + aBodyText += rtl::OUString::createFromAscii( "" ); + + // add PropPatch xml header in front + aBodyText = rtl::OUString::createFromAscii( PROPPATCH_HEADER ) + aBodyText; + + // add PropPatch xml trailer at end + aBodyText += rtl::OUString::createFromAscii( PROPPATCH_TRAILER ); + + body_bkt = SERF_BUCKET_SIMPLE_STRING( rtl::OUStringToOString( aBodyText, RTL_TEXTENCODING_UTF8 ), + pSerfBucketAlloc ); + if ( useChunkedEncoding() ) + { + body_bkt = serf_bucket_chunk_create( body_bkt, pSerfBucketAlloc ); + } + } + } + + // create serf request + serf_bucket_t *req_bkt = serf_request_bucket_request_create( inSerfRequest, + "PROPPATCH", + getPathStr(), + body_bkt, + pSerfBucketAlloc ) ; + + // set request header fields + serf_bucket_t* hdrs_bkt = serf_bucket_request_get_headers( req_bkt ); + // general header fields provided by caller + setRequestHeaders( hdrs_bkt ); + + // request specific header fields + if ( body_bkt != 0 && aBodyText.getLength() > 0 ) + { + if ( useChunkedEncoding() ) + { + serf_bucket_headers_set( hdrs_bkt, "Transfer-Encoding", "chunked"); + } + serf_bucket_headers_set( hdrs_bkt, "Content-Type", "application/xml" ); + serf_bucket_headers_set( hdrs_bkt, "Content-Length", + rtl::OUStringToOString( rtl::OUString::valueOf( aBodyText.getLength() ), RTL_TEXTENCODING_UTF8 ) ); + } + + return req_bkt; +} + +void SerfPropPatchReqProcImpl::processChunkOfResponseData( const char* /*data*/, + apr_size_t /*len*/ ) +{ + // nothing to do; +} + +void SerfPropPatchReqProcImpl::handleEndOfResponseData( serf_bucket_t * /*inSerfResponseBucket*/ ) +{ + // nothing to do; +} + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfPropPatchReqProcImpl.hxx b/ucb/source/ucp/webdav/SerfPropPatchReqProcImpl.hxx new file mode 100644 index 000000000000..c2ee2d1dac5c --- /dev/null +++ b/ucb/source/ucp/webdav/SerfPropPatchReqProcImpl.hxx @@ -0,0 +1,58 @@ +/* -*- 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 INCLUDED_SERFPROPPATCHREQPROCIMPL_HXX +#define INCLUDED_SERFPROPPATCHREQPROCIMPL_HXX + +#include + +#include +#include + +namespace http_dav_ucp +{ + +class SerfPropPatchReqProcImpl : public SerfRequestProcessorImpl +{ +public: + SerfPropPatchReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const std::vector< ProppatchValue > & inProperties ); + + virtual ~SerfPropPatchReqProcImpl(); + + virtual + serf_bucket_t * createSerfRequestBucket( serf_request_t * inSerfRequest ); + +protected: + virtual + void processChunkOfResponseData( const char* data, apr_size_t len ); + + virtual + void handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ); + +private: + const std::vector< ProppatchValue > * mpProperties; +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFPROPPATCHREQPROCIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfPutReqProcImpl.cxx b/ucb/source/ucp/webdav/SerfPutReqProcImpl.cxx new file mode 100644 index 000000000000..6934a3ca9aba --- /dev/null +++ b/ucb/source/ucp/webdav/SerfPutReqProcImpl.cxx @@ -0,0 +1,101 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include + +#include + +#include + +namespace http_dav_ucp +{ + +SerfPutReqProcImpl::SerfPutReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const char* inData, + apr_size_t inDataLen ) + : SerfRequestProcessorImpl( inPath, inRequestHeaders ) + , mpData( inData ) + , mnDataLen( inDataLen ) +{ +} + +SerfPutReqProcImpl::~SerfPutReqProcImpl() +{ +} + +serf_bucket_t * SerfPutReqProcImpl::createSerfRequestBucket( serf_request_t * inSerfRequest ) +{ + serf_bucket_alloc_t* pSerfBucketAlloc = serf_request_get_alloc( inSerfRequest ); + + // create body bucket + serf_bucket_t* body_bkt = 0; + if ( mpData != 0 && mnDataLen > 0 ) + { + body_bkt = SERF_BUCKET_SIMPLE_STRING_LEN( mpData, mnDataLen, pSerfBucketAlloc ); + if ( useChunkedEncoding() ) + { + body_bkt = serf_bucket_chunk_create( body_bkt, pSerfBucketAlloc ); + } + } + + // create serf request + serf_bucket_t *req_bkt = serf_request_bucket_request_create( inSerfRequest, + "PUT", + getPathStr(), + body_bkt, + serf_request_get_alloc( inSerfRequest ) ); + + // set request header fields + serf_bucket_t* hdrs_bkt = serf_bucket_request_get_headers( req_bkt ); + // general header fields provided by caller + setRequestHeaders( hdrs_bkt ); + + // request specific header fields + if ( body_bkt != 0 ) + { + if ( useChunkedEncoding() ) + { + serf_bucket_headers_set( hdrs_bkt, "Transfer-Encoding", "chunked"); + } + serf_bucket_headers_set( hdrs_bkt, "Content-Length", + rtl::OUStringToOString( rtl::OUString::valueOf( (sal_Int32)mnDataLen ), RTL_TEXTENCODING_UTF8 ) ); + } + + + return req_bkt; +} + +void SerfPutReqProcImpl::processChunkOfResponseData( const char* /*data*/, + apr_size_t /*len*/ ) +{ + // nothing to do; +} + +void SerfPutReqProcImpl::handleEndOfResponseData( serf_bucket_t * /*inSerfResponseBucket*/ ) +{ + // nothing to do; +} + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfPutReqProcImpl.hxx b/ucb/source/ucp/webdav/SerfPutReqProcImpl.hxx new file mode 100644 index 000000000000..64474d727358 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfPutReqProcImpl.hxx @@ -0,0 +1,59 @@ +/* -*- 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 INCLUDED_SERFPUTREQPROCIMPL_HXX +#define INCLUDED_SERFPUTREQPROCIMPL_HXX + +#include + +namespace http_dav_ucp +{ + +class SerfPutReqProcImpl : public SerfRequestProcessorImpl +{ +public: + SerfPutReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const char* inData, + apr_size_t inDataLen ); + + + virtual ~SerfPutReqProcImpl(); + + virtual + serf_bucket_t * createSerfRequestBucket( serf_request_t * inSerfRequest ); + +protected: + virtual + void processChunkOfResponseData( const char* data, apr_size_t len ); + + virtual + void handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ); + +private: + const char* mpData; + apr_size_t mnDataLen; + +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFPUTREQPROCIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfRequestProcessor.cxx b/ucb/source/ucp/webdav/SerfRequestProcessor.cxx new file mode 100644 index 000000000000..49115cc53194 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfRequestProcessor.cxx @@ -0,0 +1,553 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include +#include +#include +#include +#include + +#include + +namespace http_dav_ucp +{ + +SerfRequestProcessor::SerfRequestProcessor( SerfSession& rSerfSession, + const rtl::OUString & inPath, + const bool bUseChunkedEncoding ) + : mrSerfSession( rSerfSession ) + , mPathStr( 0 ) + , mbUseChunkedEncoding( bUseChunkedEncoding ) + , mDestPathStr( 0 ) + , mContentType( 0 ) + , mReferer( 0 ) + , mpProcImpl( 0 ) + , mbProcessingDone( false ) + , mpDAVException() + , mnHTTPStatusCode( SC_NONE ) + , mHTTPStatusCodeText() + , mRedirectLocation() + , mnSuccessfulCredentialAttempts( 0 ) + , mbInputOfCredentialsAborted( false ) + , mbSetupSerfRequestCalled( false ) + , mbAcceptSerfResponseCalled( false ) + , mbHandleSerfResponseCalled( false ) +{ + mPathStr = apr_pstrdup( mrSerfSession.getAprPool(), + rtl::OUStringToOString( inPath, RTL_TEXTENCODING_UTF8 ) ); +} + +SerfRequestProcessor::~SerfRequestProcessor() +{ + delete mpProcImpl; + delete mpDAVException; +} + +void SerfRequestProcessor::prepareProcessor() +{ + delete mpDAVException; + mpDAVException = 0; + mnHTTPStatusCode = SC_NONE; + mHTTPStatusCodeText = rtl::OUString(); + mRedirectLocation = rtl::OUString(); + + mnSuccessfulCredentialAttempts = 0; + mbInputOfCredentialsAborted = false; + mbSetupSerfRequestCalled = false; + mbAcceptSerfResponseCalled = false; + mbHandleSerfResponseCalled = false; +} + +// PROPFIND - allprop & named +bool SerfRequestProcessor::processPropFind( const Depth inDepth, + const std::vector< ::rtl::OUString > & inPropNames, + std::vector< DAVResource > & ioResources, + apr_status_t& outSerfStatus ) +{ + mpProcImpl = createPropFindReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + inDepth, + inPropNames, + ioResources ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// PROPFIND - property names +bool SerfRequestProcessor::processPropFind( const Depth inDepth, + std::vector< DAVResourceInfo > & ioResInfo, + apr_status_t& outSerfStatus ) +{ + mpProcImpl = createPropFindReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + inDepth, + ioResInfo ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// PROPPATCH +bool SerfRequestProcessor::processPropPatch( const std::vector< ProppatchValue > & inProperties, + apr_status_t& outSerfStatus ) +{ + mpProcImpl = createPropPatchReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + inProperties ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// GET +bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, + apr_status_t& outSerfStatus ) +{ + mpProcImpl = createGetReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + xioInStrm ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// GET inclusive header fields +bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + apr_status_t& outSerfStatus ) +{ + mpProcImpl = createGetReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + xioInStrm, + inHeaderNames, + ioResource ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// GET +bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, + apr_status_t& outSerfStatus ) +{ + mpProcImpl = createGetReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + xioOutStrm ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// GET inclusive header fields +bool SerfRequestProcessor::processGet( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + apr_status_t& outSerfStatus ) +{ + mpProcImpl = createGetReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + xioOutStrm, + inHeaderNames, + ioResource ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// HEAD +bool SerfRequestProcessor::processHead( const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + apr_status_t& outSerfStatus ) +{ + mpProcImpl = createHeadReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + inHeaderNames, + ioResource ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// PUT +bool SerfRequestProcessor::processPut( const char* inData, + apr_size_t inDataLen, + apr_status_t& outSerfStatus ) +{ + mpProcImpl = createPutReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + inData, + inDataLen ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// POST +bool SerfRequestProcessor::processPost( const char* inData, + apr_size_t inDataLen, + const rtl::OUString & inContentType, + const rtl::OUString & inReferer, + const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, + apr_status_t& outSerfStatus ) +{ + mContentType = apr_pstrdup( mrSerfSession.getAprPool(), + rtl::OUStringToOString( inContentType, RTL_TEXTENCODING_UTF8 ) ); + mReferer = apr_pstrdup( mrSerfSession.getAprPool(), + rtl::OUStringToOString( inReferer, RTL_TEXTENCODING_UTF8 ) ); + mpProcImpl = createPostReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + inData, + inDataLen, + mContentType, + mReferer, + xioInStrm ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// POST +bool SerfRequestProcessor::processPost( const char* inData, + apr_size_t inDataLen, + const rtl::OUString & inContentType, + const rtl::OUString & inReferer, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, + apr_status_t& outSerfStatus ) +{ + mContentType = apr_pstrdup( mrSerfSession.getAprPool(), + rtl::OUStringToOString( inContentType, RTL_TEXTENCODING_UTF8 ) ); + mReferer = apr_pstrdup( mrSerfSession.getAprPool(), + rtl::OUStringToOString( inReferer, RTL_TEXTENCODING_UTF8 ) ); + mpProcImpl = createPostReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + inData, + inDataLen, + mContentType, + mReferer, + xioOutStrm ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// DELETE +bool SerfRequestProcessor::processDelete( apr_status_t& outSerfStatus ) +{ + mpProcImpl = createDeleteReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// MKCOL +bool SerfRequestProcessor::processMkCol( apr_status_t& outSerfStatus ) +{ + mpProcImpl = createMkColReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// COPY +bool SerfRequestProcessor::processCopy( const rtl::OUString & inDestinationPath, + const bool inOverwrite, + apr_status_t& outSerfStatus ) +{ + mDestPathStr = apr_pstrdup( mrSerfSession.getAprPool(), + rtl::OUStringToOString( inDestinationPath, RTL_TEXTENCODING_UTF8 ) ); + mpProcImpl = createCopyReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + mDestPathStr, + inOverwrite ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +// MOVE +bool SerfRequestProcessor::processMove( const rtl::OUString & inDestinationPath, + const bool inOverwrite, + apr_status_t& outSerfStatus ) +{ + mDestPathStr = apr_pstrdup( mrSerfSession.getAprPool(), + rtl::OUStringToOString( inDestinationPath, RTL_TEXTENCODING_UTF8 ) ); + mpProcImpl = createMoveReqProcImpl( mPathStr, + mrSerfSession.getRequestEnvironment().m_aRequestHeaders, + mDestPathStr, + inOverwrite ); + outSerfStatus = runProcessor(); + + return outSerfStatus == APR_SUCCESS; +} + +apr_status_t SerfRequestProcessor::runProcessor() +{ + prepareProcessor(); + + // activate chunked encoding, if requested + if ( mbUseChunkedEncoding ) + { + mpProcImpl->activateChunkedEncoding(); + } + + // create serf request + serf_connection_request_create( mrSerfSession.getSerfConnection(), + Serf_SetupRequest, + this ); + + // perform serf request + mbProcessingDone = false; + apr_status_t status = APR_SUCCESS; + serf_context_t* pSerfContext = mrSerfSession.getSerfContext(); + apr_pool_t* pAprPool = mrSerfSession.getAprPool(); + while ( true ) + { + status = serf_context_run( pSerfContext, + SERF_DURATION_FOREVER, + pAprPool ); + if ( APR_STATUS_IS_TIMEUP( status ) ) + { + continue; + } + if ( status != APR_SUCCESS ) + { + break; + } + if ( mbProcessingDone ) + { + break; + } + } + + postprocessProcessor( status ); + + return status; +} + +void SerfRequestProcessor::postprocessProcessor( const apr_status_t inStatus ) +{ + if ( inStatus == APR_SUCCESS ) + { + return; + } + + switch ( inStatus ) + { + case APR_EGENERAL: + case SERF_ERROR_AUTHN_FAILED: + // general error; provides more information + { + switch ( mnHTTPStatusCode ) + { + case SC_NONE: + if ( !mbSetupSerfRequestCalled ) + { + mpDAVException = new DAVException( DAVException::DAV_HTTP_LOOKUP, + SerfUri::makeConnectionEndPointString( mrSerfSession.getHostName(), + mrSerfSession.getPort() ) ); + } + else if ( mbInputOfCredentialsAborted ) + { + mpDAVException = new DAVException( DAVException::DAV_HTTP_NOAUTH, + SerfUri::makeConnectionEndPointString( mrSerfSession.getHostName(), + mrSerfSession.getPort() ) ); + } + else + { + mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR, + mHTTPStatusCodeText, + mnHTTPStatusCode ); + } + break; + case SC_MOVED_PERMANENTLY: + case SC_MOVED_TEMPORARILY: + case SC_SEE_OTHER: + case SC_TEMPORARY_REDIRECT: + mpDAVException = new DAVException( DAVException::DAV_HTTP_REDIRECT, + mRedirectLocation ); + break; + default: + mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR, + mHTTPStatusCodeText, + mnHTTPStatusCode ); + break; + } + } + break; + + default: + mpDAVException = new DAVException( DAVException::DAV_HTTP_ERROR ); + break; + } + +} + +apr_status_t SerfRequestProcessor::provideSerfCredentials( char ** outUsername, + char ** outPassword, + serf_request_t * inRequest, + int inCode, + const char *inAuthProtocol, + const char *inRealm, + apr_pool_t *inAprPool ) +{ + // as each successful provided credentials are tried twice - see below - the + // number of real attempts is half of the value of + if ( (mnSuccessfulCredentialAttempts / 2) >= 5 || + mbInputOfCredentialsAborted ) + { + mbInputOfCredentialsAborted = true; + return SERF_ERROR_AUTHN_FAILED; + } + + // because serf keeps credentials only for a connection in case of digest authentication + // we give each successful provided credentials a second try in order to workaround the + // situation that the connection for which the credentials have been provided has been closed + // before the provided credentials could be applied for the request. + apr_status_t status = mrSerfSession.provideSerfCredentials( (mnSuccessfulCredentialAttempts % 2) == 1, + outUsername, + outPassword, + inRequest, + inCode, + inAuthProtocol, + inRealm, + inAprPool ); + if ( status != APR_SUCCESS ) + { + mbInputOfCredentialsAborted = true; + } + else + { + ++mnSuccessfulCredentialAttempts; + } + + return status; +} + +apr_status_t SerfRequestProcessor::setupSerfRequest( serf_request_t * inSerfRequest, + serf_bucket_t ** outSerfRequestBucket, + serf_response_acceptor_t * outSerfResponseAcceptor, + void ** outSerfResponseAcceptorBaton, + serf_response_handler_t * outSerfResponseHandler, + void ** outSerfResponseHandlerBaton, + apr_pool_t * /*inAprPool*/ ) +{ + mbSetupSerfRequestCalled = true; + *outSerfRequestBucket = mpProcImpl->createSerfRequestBucket( inSerfRequest ); + + // apply callbacks for accepting response and handling response + *outSerfResponseAcceptor = Serf_AcceptResponse; + *outSerfResponseAcceptorBaton = this; + *outSerfResponseHandler = Serf_HandleResponse; + *outSerfResponseHandlerBaton = this; + + return APR_SUCCESS; +} + +serf_bucket_t* SerfRequestProcessor::acceptSerfResponse( serf_request_t * inSerfRequest, + serf_bucket_t * inSerfStreamBucket, + apr_pool_t * inAprPool ) +{ + mbAcceptSerfResponseCalled = true; + return mrSerfSession.acceptSerfResponse( inSerfRequest, + inSerfStreamBucket, + inAprPool ); +} + +apr_status_t SerfRequestProcessor::handleSerfResponse( serf_request_t * inSerfRequest, + serf_bucket_t * inSerfResponseBucket, + apr_pool_t * inAprPool ) +{ + mbHandleSerfResponseCalled = true; + + // some general response handling and error handling + { + if ( !inSerfResponseBucket ) + { + /* A NULL response can come back if the request failed completely */ + mbProcessingDone = true; + return APR_EGENERAL; + } + + serf_status_line sl; + apr_status_t status = serf_bucket_response_status( inSerfResponseBucket, &sl ); + if ( status ) + { + mbProcessingDone = false; // allow another try in order to get a response + return status; + } + // TODO - check, if response status code handling is correct + mnHTTPStatusCode = ( sl.version != 0 && sl.code >= 0 ) + ? static_cast< sal_uInt16 >( sl.code ) + : SC_NONE; + if ( sl.reason ) + { + mHTTPStatusCodeText = ::rtl::OUString::createFromAscii( sl.reason ); + } + if ( ( sl.version == 0 || sl.code < 0 ) || + mnHTTPStatusCode >= 300 ) + { + if ( mnHTTPStatusCode == 301 || + mnHTTPStatusCode == 302 || + mnHTTPStatusCode == 303 || + mnHTTPStatusCode == 307 ) + { + // new location for certain redirections + serf_bucket_t *headers = serf_bucket_response_get_headers( inSerfResponseBucket ); + const char* location = serf_bucket_headers_get( headers, "Location" ); + if ( location ) + { + mRedirectLocation = rtl::OUString::createFromAscii( location ); + } + mbProcessingDone = true; + return APR_EGENERAL; + } + else if ( mrSerfSession.isHeadRequestInProgress() && + ( mnHTTPStatusCode == 401 || mnHTTPStatusCode == 407 ) ) + { + // keep going as authentication is not required on HEAD request. + // the response already contains header fields. + } + else + { + mbProcessingDone = true; + return APR_EGENERAL; + } + } + } + + // request specific processing of the response bucket + apr_status_t status = APR_SUCCESS; + mbProcessingDone = mpProcImpl->processSerfResponseBucket( inSerfRequest, + inSerfResponseBucket, + inAprPool, + status ); + + return status; +} + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfRequestProcessor.hxx b/ucb/source/ucp/webdav/SerfRequestProcessor.hxx new file mode 100644 index 000000000000..8b7fcaded928 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfRequestProcessor.hxx @@ -0,0 +1,182 @@ +/* -*- 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 INCLUDED_SERFREQUESTPROCESSOR_HXX +#define INCLUDED_SERFREQUESTPROCESSOR_HXX + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +namespace http_dav_ucp +{ + +class SerfSession; +class SerfRequestProcessorImpl; + +class SerfRequestProcessor +{ +public: + SerfRequestProcessor( SerfSession& rSerfSession, + const rtl::OUString & inPath, + const bool bUseChunkedEncoding ); + ~SerfRequestProcessor(); + + // PROPFIND - allprop & named + bool processPropFind( const Depth inDepth, + const std::vector< ::rtl::OUString > & inPropNames, + std::vector< DAVResource > & ioResources, + apr_status_t& outSerfStatus ); + + // PROPFIND - property names + bool processPropFind( const Depth inDepth, + std::vector< DAVResourceInfo > & ioResInfo, + apr_status_t& outSerfStatus ); + + // PROPPATCH + bool processPropPatch( const std::vector< ProppatchValue > & inProperties, + apr_status_t& outSerfStatus ); + + // GET + bool processGet( const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, + apr_status_t& outSerfStatus ); + + // GET inclusive header fields + bool processGet( const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + apr_status_t& outSerfStatus ); + + // GET + bool processGet( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, + apr_status_t& outSerfStatus ); + + // GET inclusive header fields + bool processGet( const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + apr_status_t& outSerfStatus ); + + // HEAD + bool processHead( const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + apr_status_t& outSerfStatus ); + + // PUT + bool processPut( const char* inData, + apr_size_t inDataLen, + apr_status_t& outSerfStatus ); + + // POST + bool processPost( const char* inData, + apr_size_t inDataLen, + const rtl::OUString & inContentType, + const rtl::OUString & inReferer, + const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, + apr_status_t& outSerfStatus ); + + // POST + bool processPost( const char* inData, + apr_size_t inDataLen, + const rtl::OUString & inContentType, + const rtl::OUString & inReferer, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, + apr_status_t& outSerfStatus ); + + // DELETE + bool processDelete( apr_status_t& outSerfStatus ); + + // MKCOL + bool processMkCol( apr_status_t& outSerfStatus ); + + // COPY + bool processCopy( const rtl::OUString & inDestinationPath, + const bool inOverwrite, + apr_status_t& outSerfStatus ); + + // MOVE + bool processMove( const rtl::OUString & inDestinationPath, + const bool inOverwrite, + apr_status_t& outSerfStatus ); + + apr_status_t provideSerfCredentials( char ** outUsername, + char ** outPassword, + serf_request_t * inRequest, + int inCode, + const char *inAuthProtocol, + const char *inRealm, + apr_pool_t *inAprPool ); + + apr_status_t setupSerfRequest( serf_request_t * inSerfRequest, + serf_bucket_t ** outSerfRequestBucket, + serf_response_acceptor_t * outSerfResponseAcceptor, + void ** outSerfResponseAcceptorBaton, + serf_response_handler_t * outSerfResponseHandler, + void ** outSerfResponseHandlerBaton, + apr_pool_t * inAprPool ); + + serf_bucket_t* acceptSerfResponse( serf_request_t * inSerfRequest, + serf_bucket_t * inSerfStreamBucket, + apr_pool_t* inAprPool ); + + apr_status_t handleSerfResponse( serf_request_t * inSerfRequest, + serf_bucket_t * inSerfResponseBucket, + apr_pool_t * inAprPool ); + +//private: + void prepareProcessor(); + apr_status_t runProcessor(); + void postprocessProcessor( const apr_status_t inStatus ); + + SerfSession& mrSerfSession; + const char* mPathStr; + const bool mbUseChunkedEncoding; + const char* mDestPathStr; + const char* mContentType; + const char* mReferer; + SerfRequestProcessorImpl* mpProcImpl; + + bool mbProcessingDone; + + DAVException* mpDAVException; + sal_uInt16 mnHTTPStatusCode; + rtl::OUString mHTTPStatusCodeText; + rtl::OUString mRedirectLocation; + + sal_uInt8 mnSuccessfulCredentialAttempts; + bool mbInputOfCredentialsAborted; + bool mbSetupSerfRequestCalled; + bool mbAcceptSerfResponseCalled; + bool mbHandleSerfResponseCalled; +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFREQUESTPROCESSOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfRequestProcessorImpl.cxx b/ucb/source/ucp/webdav/SerfRequestProcessorImpl.cxx new file mode 100644 index 000000000000..d27064c60ab7 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfRequestProcessorImpl.cxx @@ -0,0 +1,116 @@ +/* -*- 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 + +namespace http_dav_ucp +{ + +SerfRequestProcessorImpl::SerfRequestProcessorImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders ) + : mPathStr( inPath ) + , mrRequestHeaders( inRequestHeaders ) + , mbUseChunkedEncoding( false ) +{ +} + +SerfRequestProcessorImpl::~SerfRequestProcessorImpl() +{ +} + +const char* SerfRequestProcessorImpl::getPathStr() const +{ + return mPathStr; +} + +void SerfRequestProcessorImpl::activateChunkedEncoding() +{ + mbUseChunkedEncoding = true; +} + +const bool SerfRequestProcessorImpl::useChunkedEncoding() const +{ + return mbUseChunkedEncoding; +} + +void SerfRequestProcessorImpl::setRequestHeaders( serf_bucket_t* inoutSerfHeaderBucket ) +{ + DAVRequestHeaders::const_iterator aHeaderIter( mrRequestHeaders.begin() ); + const DAVRequestHeaders::const_iterator aEnd( mrRequestHeaders.end() ); + + while ( aHeaderIter != aEnd ) + { + const rtl::OString aHeader = rtl::OUStringToOString( (*aHeaderIter).first, + RTL_TEXTENCODING_UTF8 ); + const rtl::OString aValue = rtl::OUStringToOString( (*aHeaderIter).second, + RTL_TEXTENCODING_UTF8 ); + + serf_bucket_headers_set( inoutSerfHeaderBucket, + aHeader.getStr(), + aValue.getStr() ); + + ++aHeaderIter; + } + + serf_bucket_headers_set( inoutSerfHeaderBucket, "Accept-Encoding", "gzip"); +} + +bool SerfRequestProcessorImpl::processSerfResponseBucket( serf_request_t * /*inSerfRequest*/, + serf_bucket_t * inSerfResponseBucket, + apr_pool_t * /*inAprPool*/, + apr_status_t & outStatus ) +{ + const char* data; + apr_size_t len; + + while (1) { + outStatus = serf_bucket_read(inSerfResponseBucket, 8096, &data, &len); + if (SERF_BUCKET_READ_ERROR(outStatus)) + { + return true; + } + + if ( len > 0 ) + { + processChunkOfResponseData( data, len ); + } + + /* are we done yet? */ + if (APR_STATUS_IS_EOF(outStatus)) + { + handleEndOfResponseData( inSerfResponseBucket ); + + outStatus = APR_EOF; + return true; + } + + /* have we drained the response so far? */ + if ( APR_STATUS_IS_EAGAIN( outStatus ) ) + { + return false; + } + } + + /* NOTREACHED */ + return true; +} + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfRequestProcessorImpl.hxx b/ucb/source/ucp/webdav/SerfRequestProcessorImpl.hxx new file mode 100644 index 000000000000..2d0eb1bc71d0 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfRequestProcessorImpl.hxx @@ -0,0 +1,72 @@ +/* -*- 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 INCLUDED_SERFREQUESTPROCESSORIMPL_HXX +#define INCLUDED_SERFREQUESTPROCESSORIMPL_HXX + +#include + +#include +#include + +namespace http_dav_ucp +{ + +class SerfRequestProcessorImpl +{ +public: + SerfRequestProcessorImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders ); + + virtual ~SerfRequestProcessorImpl(); + + /*pure*/ virtual + serf_bucket_t * createSerfRequestBucket( serf_request_t * inSerfRequest ) = 0; + + bool processSerfResponseBucket( serf_request_t * inSerfRequest, + + serf_bucket_t * inSerfResponseBucket, + apr_pool_t * inAprPool, + apr_status_t & outStatus ); + + void activateChunkedEncoding(); + +protected: + void setRequestHeaders( serf_bucket_t* inoutSerfHeaderBucket ); + + /*pure*/ virtual + void processChunkOfResponseData( const char* data, apr_size_t len ) = 0; + + /*pure*/ virtual + void handleEndOfResponseData( serf_bucket_t * inSerfResponseBucket ) = 0; + + const char* getPathStr() const; + const bool useChunkedEncoding() const; + +private: + const char* mPathStr; + const DAVRequestHeaders& mrRequestHeaders; + bool mbUseChunkedEncoding; +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFREQUESTPROCESSORIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.cxx b/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.cxx new file mode 100644 index 000000000000..537f015451ee --- /dev/null +++ b/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.cxx @@ -0,0 +1,224 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace http_dav_ucp +{ + SerfRequestProcessorImpl* createPropFindReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const Depth inDepth, + const std::vector< ::rtl::OUString > & inPropNames, + std::vector< DAVResource > & ioResources ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfPropFindReqProcImpl( inPath, + inRequestHeaders, + inDepth, + inPropNames, + ioResources ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createPropFindReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const Depth inDepth, + std::vector< DAVResourceInfo > & ioResInfo ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfPropFindReqProcImpl( inPath, + inRequestHeaders, + inDepth, + ioResInfo ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createPropPatchReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const std::vector< ProppatchValue > & inProperties ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfPropPatchReqProcImpl( inPath, + inRequestHeaders, + inProperties ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfGetReqProcImpl( inPath, + inRequestHeaders, + xioInStrm ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource& ioResource ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfGetReqProcImpl( inPath, + inRequestHeaders, + xioInStrm, + inHeaderNames, + ioResource ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfGetReqProcImpl( inPath, + inRequestHeaders, + xioOutStrm ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference& xioOutStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource& ioResource ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfGetReqProcImpl( inPath, + inRequestHeaders, + xioOutStrm, + inHeaderNames, + ioResource ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createHeadReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource& ioResource ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfHeadReqProcImpl( inPath, + inRequestHeaders, + inHeaderNames, + ioResource ); + return pReqProcImpl; + } + + + SerfRequestProcessorImpl* createPutReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const char* inData, + apr_size_t inDataLen ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfPutReqProcImpl( inPath, + inRequestHeaders, + inData, + inDataLen ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createPostReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const char* inData, + apr_size_t inDataLen, + const char* inContentType, + const char* inReferer, + const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfPostReqProcImpl( inPath, + inRequestHeaders, + inData, + inDataLen, + inContentType, + inReferer, + xioInStrm ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createPostReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const char* inData, + apr_size_t inDataLen, + const char* inContentType, + const char* inReferer, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfPostReqProcImpl( inPath, + inRequestHeaders, + inData, + inDataLen, + inContentType, + inReferer, + xioOutStrm ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createDeleteReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfDeleteReqProcImpl( inPath, + inRequestHeaders ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createMkColReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfMkColReqProcImpl( inPath, + inRequestHeaders ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createCopyReqProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const char* inDestinationPath, + const bool inOverwrite ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfCopyReqProcImpl( inSourcePath, + inRequestHeaders, + inDestinationPath, + inOverwrite ); + return pReqProcImpl; + } + + SerfRequestProcessorImpl* createMoveReqProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const char* inDestinationPath, + const bool inOverwrite ) + { + SerfRequestProcessorImpl* pReqProcImpl = new SerfMoveReqProcImpl( inSourcePath, + inRequestHeaders, + inDestinationPath, + inOverwrite ); + return pReqProcImpl; + } + +} // namespace http_dav_ucp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.hxx b/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.hxx new file mode 100644 index 000000000000..ee6d5b540953 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfRequestProcessorImplFac.hxx @@ -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 . + */ + +#ifndef INCLUDED_SERFREQUESTPROCESSORIMPLFAC_HXX +#define INCLUDED_SERFREQUESTPROCESSORIMPLFAC_HXX + +#include +#include +#include "DAVTypes.hxx" +#include "DAVResource.hxx" + +#include +#include +#include + +namespace http_dav_ucp +{ + SerfRequestProcessorImpl* createPropFindReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const Depth inDepth, + const std::vector< ::rtl::OUString > & inPropNames, + std::vector< DAVResource > & ioResources ); + + SerfRequestProcessorImpl* createPropFindReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const Depth inDepth, + std::vector< DAVResourceInfo > & ioResInfo ); + + SerfRequestProcessorImpl* createPropPatchReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const std::vector< ProppatchValue > & inProperties ); + + SerfRequestProcessorImpl* createGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm ); + + SerfRequestProcessorImpl* createGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource& ioResource ); + + SerfRequestProcessorImpl* createGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm ); + + SerfRequestProcessorImpl* createGetReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource& ioResource ); + + SerfRequestProcessorImpl* createHeadReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource& ioResource ); + + SerfRequestProcessorImpl* createPutReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const char* inData, + apr_size_t inDataLen ); + + SerfRequestProcessorImpl* createPostReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const char* inData, + apr_size_t inDataLen, + const char* inContentType, + const char* inReferer, + const com::sun::star::uno::Reference< SerfInputStream >& xioInStrm ); + + SerfRequestProcessorImpl* createPostReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders, + const char* inData, + apr_size_t inDataLen, + const char* inContentType, + const char* inReferer, + const com::sun::star::uno::Reference< com::sun::star::io::XOutputStream >& xioOutStrm ); + + SerfRequestProcessorImpl* createDeleteReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders ); + + SerfRequestProcessorImpl* createMkColReqProcImpl( const char* inPath, + const DAVRequestHeaders& inRequestHeaders ); + + SerfRequestProcessorImpl* createCopyReqProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const char* inDestinationPath, + const bool inOverwrite ); + + SerfRequestProcessorImpl* createMoveReqProcImpl( const char* inSourcePath, + const DAVRequestHeaders& inRequestHeaders, + const char* inDestinationPath, + const bool inOverwrite ); + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFREQUESTPROCESSORIMPLFAC_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfSession.cxx b/ucb/source/ucp/webdav/SerfSession.cxx new file mode 100644 index 000000000000..0030c211bec6 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfSession.cxx @@ -0,0 +1,1603 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include +#include +#include +#include +#include "comphelper/sequence.hxx" +#include "ucbhelper/simplecertificatevalidationrequest.hxx" + +#include +#include + +#include "DAVAuthListener.hxx" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace http_dav_ucp; + + +// ------------------------------------------------------------------- +// static members! +//SerfLockStore SerfSession::m_aSerfLockStore; + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +SerfSession::SerfSession( + const rtl::Reference< DAVSessionFactory > & rSessionFactory, + const rtl::OUString& inUri, + const ucbhelper::InternetProxyDecider & rProxyDecider ) + throw ( DAVException ) + : DAVSession( rSessionFactory ) + , m_aMutex() + , m_aUri( inUri ) + , m_aProxyName() + , m_nProxyPort( 0 ) + , m_pSerfConnection( 0 ) + , m_pSerfContext( 0 ) + , m_bIsHeadRequestInProgress( false ) + , m_bUseChunkedEncoding( false ) + , m_bNoOfTransferEncodingSwitches( 0 ) + , m_rProxyDecider( rProxyDecider ) + , m_aEnv() +{ + m_pSerfContext = serf_context_create( getAprPool() ); + + m_pSerfBucket_Alloc = serf_bucket_allocator_create( getAprPool(), NULL, NULL ); +} + +// ------------------------------------------------------------------- +// Destructor +// ------------------------------------------------------------------- +SerfSession::~SerfSession( ) +{ + if ( m_pSerfConnection ) + { + serf_connection_close( m_pSerfConnection ); + m_pSerfConnection = 0; + } +} + +// ------------------------------------------------------------------- +void SerfSession::Init( const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + m_aEnv = rEnv; + Init(); +} + +// ------------------------------------------------------------------- +void SerfSession::Init() + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + bool bCreateNewSession = false; + + if ( m_pSerfConnection == 0 ) + { + const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings(); + + m_aProxyName = rProxyCfg.aName; + m_nProxyPort = rProxyCfg.nPort; + + // Not yet initialized. Create new session. + bCreateNewSession = true; + } + else + { + const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings(); + + if ( ( rProxyCfg.aName != m_aProxyName ) + || ( rProxyCfg.nPort != m_nProxyPort ) ) + { + m_aProxyName = rProxyCfg.aName; + m_nProxyPort = rProxyCfg.nPort; + + // new session needed, destroy old first + serf_connection_close( m_pSerfConnection ); + m_pSerfConnection = 0; + bCreateNewSession = true; + } + } + + if ( bCreateNewSession ) + { + // TODO - close_connection callback + apr_status_t status = serf_connection_create2( &m_pSerfConnection, + m_pSerfContext, + *(m_aUri.getAprUri()), + Serf_ConnectSetup, this, + 0 /* close connection callback */, 0 /* close connection baton */, + getAprPool() ); + + if ( m_pSerfConnection == 0 ||status != APR_SUCCESS ) + { + throw DAVException( DAVException::DAV_SESSION_CREATE, + SerfUri::makeConnectionEndPointString( m_aUri.GetHost(), m_aUri.GetPort() ) ); + } + + // Register the session with the lock store +// m_aSerfLockStore.registerSession( m_pSerfConnection ); + + if ( m_aProxyName.getLength() ) + { + apr_sockaddr_t *proxy_address = NULL; + const apr_status_t status = apr_sockaddr_info_get( &proxy_address, + rtl::OUStringToOString( m_aProxyName, RTL_TEXTENCODING_UTF8 ), + APR_UNSPEC, + static_cast(m_nProxyPort), + 0, getAprPool() ); + + if ( status != APR_SUCCESS ) + { + throw DAVException( DAVException::DAV_SESSION_CREATE, + SerfUri::makeConnectionEndPointString( m_aUri.GetHost(), m_aUri.GetPort() ) ); + } + + serf_config_proxy( m_pSerfContext, proxy_address ); + } + + + serf_config_credentials_callback( m_pSerfContext, Serf_Credentials ); + + m_bUseChunkedEncoding = isSSLNeeded(); + } +} + +apr_pool_t* SerfSession::getAprPool() +{ + return apr_environment::AprEnv::getAprEnv()->getAprPool(); +} + +serf_bucket_alloc_t* SerfSession::getSerfBktAlloc() +{ + return m_pSerfBucket_Alloc; +} + +serf_context_t* SerfSession::getSerfContext() +{ + return m_pSerfContext; +} + +SerfConnection* SerfSession::getSerfConnection() +{ + return m_pSerfConnection; +} + +bool SerfSession::isHeadRequestInProgress() +{ + return m_bIsHeadRequestInProgress; +} + +bool SerfSession::isSSLNeeded() +{ + return m_aUri.GetScheme().equalsIgnoreAsciiCase( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "https" ) ) ); +} + +char* SerfSession::getHostinfo() +{ + return m_aUri.getAprUri()->hostinfo; +} + + +// ------------------------------------------------------------------- +// virtual +sal_Bool SerfSession::CanUse( const rtl::OUString & inUri ) +{ + try + { + SerfUri theUri( inUri ); + if ( ( theUri.GetPort() == m_aUri.GetPort() ) && + ( theUri.GetHost() == m_aUri.GetHost() ) && + ( theUri.GetScheme() == m_aUri.GetScheme() ) ) + { + return sal_True; + } + } + catch ( DAVException const & ) + { + return sal_False; + } + return sal_False; +} + +// ------------------------------------------------------------------- +// virtual +sal_Bool SerfSession::UsesProxy() +{ + Init(); + return ( m_aProxyName.getLength() > 0 ); +} + +apr_status_t SerfSession::setupSerfConnection( apr_socket_t * inAprSocket, + serf_bucket_t **outSerfInputBucket, + serf_bucket_t **outSerfOutputBucket, + apr_pool_t* /*inAprPool*/ ) +{ + serf_bucket_t *tmpInputBkt; + tmpInputBkt = serf_context_bucket_socket_create( getSerfContext(), + inAprSocket, + getSerfBktAlloc() ); + + if ( isSSLNeeded() ) + { + tmpInputBkt = serf_bucket_ssl_decrypt_create( tmpInputBkt, + 0, + getSerfBktAlloc() ); + /** Set the callback that is called to authenticate the + certifcate (chain). + */ + serf_ssl_server_cert_chain_callback_set( + serf_bucket_ssl_decrypt_context_get(tmpInputBkt), + Serf_CertificateChainValidation, + this); + serf_ssl_set_hostname( serf_bucket_ssl_decrypt_context_get( tmpInputBkt ), + getHostinfo() ); + + *outSerfOutputBucket = serf_bucket_ssl_encrypt_create( *outSerfOutputBucket, + serf_bucket_ssl_decrypt_context_get( tmpInputBkt ), + getSerfBktAlloc() ); + } + + *outSerfInputBucket = tmpInputBkt; + + return APR_SUCCESS; +} + +apr_status_t SerfSession::provideSerfCredentials( bool bGiveProvidedCredentialsASecondTry, + char ** outUsername, + char ** outPassword, + serf_request_t * /*inRequest*/, + int /*inCode*/, + const char *inAuthProtocol, + const char *inRealm, + apr_pool_t *inAprPool ) +{ + DAVAuthListener * pListener = getRequestEnvironment().m_xAuthListener.get(); + if ( !pListener ) + { + // abort + return SERF_ERROR_AUTHN_FAILED; + } + + rtl::OUString theUserName; + rtl::OUString thePassWord; + try + { + SerfUri uri( getRequestEnvironment().m_aRequestURI ); + rtl::OUString aUserInfo( uri.GetUserInfo() ); + if ( aUserInfo.getLength() ) + { + sal_Int32 nPos = aUserInfo.indexOf( '@' ); + if ( nPos == -1 ) + { + theUserName = aUserInfo; + } + else + { + theUserName = aUserInfo.copy( 0, nPos ); + thePassWord = aUserInfo.copy( nPos + 1 ); + } + } + } + catch ( DAVException const & ) + { + // abort + return SERF_ERROR_AUTHN_FAILED; + } + + const bool bCanUseSystemCreds = ( ( strcasecmp( inAuthProtocol, "NTLM" ) == 0 ) || + ( strcasecmp( inAuthProtocol, "Negotiate" ) == 0 ) ); + + int theRetVal = pListener->authenticate( rtl::OUString::createFromAscii( inRealm ), + getHostName(), + theUserName, + thePassWord, + bCanUseSystemCreds, + bGiveProvidedCredentialsASecondTry ? sal_False : sal_True ); + + if ( theRetVal == 0 ) + { + *outUsername = apr_pstrdup( inAprPool, rtl::OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ) ); + *outPassword = apr_pstrdup( inAprPool, rtl::OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ) ); + } + + return theRetVal != 0 ? SERF_ERROR_AUTHN_FAILED : APR_SUCCESS; +} + +namespace { + // ------------------------------------------------------------------- + // Helper function + ::rtl::OUString GetHostnamePart( const ::rtl::OUString& _rRawString ) + { + ::rtl::OUString sPart; + ::rtl::OUString sPartId = ::rtl::OUString::createFromAscii( "CN=" ); + sal_Int32 nContStart = _rRawString.indexOf( sPartId ); + if ( nContStart != -1 ) + { + nContStart = nContStart + sPartId.getLength(); + sal_Int32 nContEnd + = _rRawString.indexOf( sal_Unicode( ',' ), nContStart ); + sPart = _rRawString.copy( nContStart, nContEnd - nContStart ); + } + return sPart; + } +} // namespace + + +apr_status_t SerfSession::verifySerfCertificateChain ( + int, + const char** pCertificateChainBase64Encoded, + int nCertificateChainLength) +{ + // Check arguments. + if (pCertificateChainBase64Encoded == NULL || nCertificateChainLength<=0) + { + OSL_ASSERT(pCertificateChainBase64Encoded != NULL); + OSL_ASSERT(nCertificateChainLength>0); + return SERF_SSL_CERT_UNKNOWN_FAILURE; + } + + // Create some crypto objects to decode and handle the base64 + // encoded certificate chain. + uno::Reference< xml::crypto::XSEInitializer > xSEInitializer; + uno::Reference< security::XCertificateContainer > xCertificateContainer; + uno::Reference< xml::crypto::XXMLSecurityContext > xSecurityContext; + uno::Reference< xml::crypto::XSecurityEnvironment > xSecurityEnv; + try + { + // Create a certificate container. + xCertificateContainer = uno::Reference< security::XCertificateContainer >( + getMSF()->createInstance( + rtl::OUString::createFromAscii( + "com.sun.star.security.CertificateContainer" ) ), + uno::UNO_QUERY_THROW); + + xSEInitializer = uno::Reference< xml::crypto::XSEInitializer >( + getMSF()->createInstance( + rtl::OUString::createFromAscii( "com.sun.star.xml.crypto.SEInitializer" ) ), + uno::UNO_QUERY_THROW); + + xSecurityContext = xSEInitializer->createSecurityContext( rtl::OUString() ); + if (xSecurityContext.is()) + xSecurityEnv = xSecurityContext->getSecurityEnvironment(); + + if ( ! xSecurityContext.is() || ! xSecurityEnv.is()) + { + // Do we have to dispose xSEInitializer or xCertificateContainer? + return SERF_SSL_CERT_UNKNOWN_FAILURE; + } + } + catch ( uno::Exception const &) + { + return SERF_SSL_CERT_UNKNOWN_FAILURE; + } + + // Decode the server certificate. + uno::Reference< security::XCertificate > xServerCertificate( + xSecurityEnv->createCertificateFromAscii( + rtl::OUString::createFromAscii(pCertificateChainBase64Encoded[0]))); + if ( ! xServerCertificate.is()) + return SERF_SSL_CERT_UNKNOWN_FAILURE; + + // Get the subject from the server certificate. + ::rtl::OUString sServerCertificateSubject (xServerCertificate->getSubjectName()); + sal_Int32 nIndex = 0; + while (nIndex >= 0) + { + const ::rtl::OUString sToken (sServerCertificateSubject.getToken(0, ',', nIndex)); + if (sToken.compareToAscii("CN=", 3) == 0) + { + sServerCertificateSubject = sToken.copy(3); + break; + } + else if (sToken.compareToAscii(" CN=", 4) == 0) + { + sServerCertificateSubject = sToken.copy(4); + break; + } + } + + // When the certificate container already contains a (trusted) + // entry for the server then we do not have to authenticate any + // certificate. + const security::CertificateContainerStatus eStatus ( + xCertificateContainer->hasCertificate( + getHostName(), sServerCertificateSubject ) ); + if (eStatus != security::CertificateContainerStatus_NOCERT) + { + return eStatus == security::CertificateContainerStatus_TRUSTED + ? APR_SUCCESS + : SERF_SSL_CERT_UNKNOWN_FAILURE; + } + + // The shortcut failed, so try to verify the whole chain. This is + // done outside the isDomainMatch() block because the result is + // used by the interaction handler. + std::vector< uno::Reference< security::XCertificate > > aChain; + for (int nIndex=1; nIndex xCertificate( + xSecurityEnv->createCertificateFromAscii( + rtl::OUString::createFromAscii(pCertificateChainBase64Encoded[nIndex]))); + if ( ! xCertificate.is()) + return SERF_SSL_CERT_UNKNOWN_FAILURE; + aChain.push_back(xCertificate); + } + const sal_Int64 nVerificationResult (xSecurityEnv->verifyCertificate( + xServerCertificate, + ::comphelper::containerToSequence(aChain))); + + // When the certificate matches the host name then we can use the + // result of the verification. + if (isDomainMatch(sServerCertificateSubject)) + { + + if (nVerificationResult == 0) + { + // Certificate (chain) is valid. + xCertificateContainer->addCertificate(getHostName(), sServerCertificateSubject, sal_True); + return APR_SUCCESS; + } + else if ((nVerificationResult & security::CertificateValidity::CHAIN_INCOMPLETE) != 0) + { + // We do not have enough information for verification, + // neither automatically (as we just discovered) nor + // manually (so there is no point in showing any dialog.) + return SERF_SSL_CERT_UNKNOWN_FAILURE; + } + else if ((nVerificationResult & + (security::CertificateValidity::INVALID | security::CertificateValidity::REVOKED)) != 0) + { + // Certificate (chain) is invalid. + xCertificateContainer->addCertificate(getHostName(), sServerCertificateSubject, sal_False); + return SERF_SSL_CERT_UNKNOWN_FAILURE; + } + else + { + // For all other we have to ask the user. + } + } + + // We have not been able to automatically verify (or falsify) the + // certificate chain. To resolve this we have to ask the user. + const uno::Reference< ucb::XCommandEnvironment > xEnv( getRequestEnvironment().m_xEnv ); + if ( xEnv.is() ) + { + uno::Reference< task::XInteractionHandler > xIH( xEnv->getInteractionHandler() ); + if ( xIH.is() ) + { + rtl::Reference< ucbhelper::SimpleCertificateValidationRequest > + xRequest( new ucbhelper::SimpleCertificateValidationRequest( + static_cast(nVerificationResult), xServerCertificate, getHostName() ) ); + xIH->handle( xRequest.get() ); + + rtl::Reference< ucbhelper::InteractionContinuation > xSelection + = xRequest->getSelection(); + + if ( xSelection.is() ) + { + uno::Reference< task::XInteractionApprove > xApprove( + xSelection.get(), uno::UNO_QUERY ); + if ( xApprove.is() ) + { + xCertificateContainer->addCertificate( getHostName(), sServerCertificateSubject, sal_True ); + return APR_SUCCESS; + } + else + { + // Don't trust cert + xCertificateContainer->addCertificate( getHostName(), sServerCertificateSubject, sal_False ); + return SERF_SSL_CERT_UNKNOWN_FAILURE; + } + } + } + else + { + // Don't trust cert + xCertificateContainer->addCertificate( getHostName(), sServerCertificateSubject, sal_False ); + return SERF_SSL_CERT_UNKNOWN_FAILURE; + } + } + + return SERF_SSL_CERT_UNKNOWN_FAILURE; +} + +serf_bucket_t* SerfSession::acceptSerfResponse( serf_request_t * inSerfRequest, + serf_bucket_t * inSerfStreamBucket, + apr_pool_t* /*inAprPool*/ ) +{ + // get the per-request bucket allocator + serf_bucket_alloc_t* SerfBktAlloc = serf_request_get_alloc( inSerfRequest ); + + // create a barrier bucket so the response doesn't eat us! + serf_bucket_t *responseBkt = serf_bucket_barrier_create( inSerfStreamBucket, + SerfBktAlloc ); + + // create response bucket + responseBkt = serf_bucket_response_create( responseBkt, + SerfBktAlloc ); + + if ( isHeadRequestInProgress() ) + { + // advise the response bucket that this was from a HEAD request and that it should not expect to see a response body. + serf_bucket_response_set_head( responseBkt ); + } + + return responseBkt; +} + +SerfRequestProcessor* SerfSession::createReqProc( const rtl::OUString & inPath ) +{ + return new SerfRequestProcessor( *this, + inPath, + m_bUseChunkedEncoding ); +} + +// ------------------------------------------------------------------- +// PROPFIND - allprop & named +// ------------------------------------------------------------------- +void SerfSession::PROPFIND( const rtl::OUString & inPath, + const Depth inDepth, + const std::vector< rtl::OUString > & inPropNames, + std::vector< DAVResource > & ioResources, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + apr_status_t status = APR_SUCCESS; + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + aReqProc->processPropFind( inDepth, + inPropNames, + ioResources, + status ); + + if ( status == APR_SUCCESS && + aReqProc->mpDAVException == 0 && + ioResources.empty() ) + { + m_aEnv = DAVRequestEnvironment(); + throw DAVException( DAVException::DAV_HTTP_ERROR, inPath, (sal_uInt16)APR_EGENERAL ); + } + HandleError( aReqProc ); +} + +// ------------------------------------------------------------------- +// PROPFIND - propnames +// ------------------------------------------------------------------- +void SerfSession::PROPFIND( const rtl::OUString & inPath, + const Depth inDepth, + std::vector< DAVResourceInfo > & ioResInfo, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + apr_status_t status = APR_SUCCESS; + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + aReqProc->processPropFind( inDepth, + ioResInfo, + status ); + + if ( status == APR_SUCCESS && + aReqProc->mpDAVException == 0 && + ioResInfo.empty() ) + { + m_aEnv = DAVRequestEnvironment(); + throw DAVException( DAVException::DAV_HTTP_ERROR, inPath, (sal_uInt16)APR_EGENERAL ); + } + HandleError( aReqProc ); +} + +// ------------------------------------------------------------------- +// PROPPATCH +// ------------------------------------------------------------------- +void SerfSession::PROPPATCH( const rtl::OUString & inPath, + const std::vector< ProppatchValue > & inValues, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + apr_status_t status = APR_SUCCESS; + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + aReqProc->processPropPatch( inValues, + status ); + + HandleError( aReqProc ); +} + +// ------------------------------------------------------------------- +// HEAD +// ------------------------------------------------------------------- +void SerfSession::HEAD( const ::rtl::OUString & inPath, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + m_bIsHeadRequestInProgress = true; + + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + ioResource.uri = inPath; + ioResource.properties.clear(); + apr_status_t status = APR_SUCCESS; + aReqProc->processHead( inHeaderNames, + ioResource, + status ); + + m_bIsHeadRequestInProgress = false; + + HandleError( aReqProc ); +} + +// ------------------------------------------------------------------- +// GET +// ------------------------------------------------------------------- +uno::Reference< io::XInputStream > +SerfSession::GET( const rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + uno::Reference< SerfInputStream > xInputStream( new SerfInputStream ); + apr_status_t status = APR_SUCCESS; + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + aReqProc->processGet( xInputStream, + status ); + + HandleError( aReqProc ); + + return uno::Reference< io::XInputStream >( xInputStream.get() ); +} + +// ------------------------------------------------------------------- +// GET +// ------------------------------------------------------------------- +void SerfSession::GET( const rtl::OUString & inPath, + uno::Reference< io::XOutputStream > & ioOutputStream, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + apr_status_t status = APR_SUCCESS; + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + aReqProc->processGet( ioOutputStream, + status ); + + HandleError( aReqProc ); +} + +// ------------------------------------------------------------------- +// GET +// ------------------------------------------------------------------- +uno::Reference< io::XInputStream > +SerfSession::GET( const rtl::OUString & inPath, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + uno::Reference< SerfInputStream > xInputStream( new SerfInputStream ); + ioResource.uri = inPath; + ioResource.properties.clear(); + apr_status_t status = APR_SUCCESS; + aReqProc->processGet( xInputStream, + inHeaderNames, + ioResource, + status ); + + HandleError( aReqProc ); + + return uno::Reference< io::XInputStream >( xInputStream.get() ); +} + + +// ------------------------------------------------------------------- +// GET +// ------------------------------------------------------------------- +void SerfSession::GET( const rtl::OUString & inPath, + uno::Reference< io::XOutputStream > & ioOutputStream, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + ioResource.uri = inPath; + ioResource.properties.clear(); + apr_status_t status = APR_SUCCESS; + aReqProc->processGet( ioOutputStream, + inHeaderNames, + ioResource, + status ); + + HandleError( aReqProc ); +} + +// ------------------------------------------------------------------- +// PUT +// ------------------------------------------------------------------- +void SerfSession::PUT( const rtl::OUString & inPath, + const uno::Reference< io::XInputStream > & inInputStream, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + uno::Sequence< sal_Int8 > aDataToSend; + if ( !getDataFromInputStream( inInputStream, aDataToSend, false ) ) + throw DAVException( DAVException::DAV_INVALID_ARG ); + apr_status_t status = APR_SUCCESS; + aReqProc->processPut( reinterpret_cast< const char * >( aDataToSend.getConstArray() ), + aDataToSend.getLength(), + status ); + + HandleError( aReqProc ); +} + +// ------------------------------------------------------------------- +// POST +// ------------------------------------------------------------------- +uno::Reference< io::XInputStream > +SerfSession::POST( const rtl::OUString & inPath, + const rtl::OUString & rContentType, + const rtl::OUString & rReferer, + const uno::Reference< io::XInputStream > & inInputStream, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + uno::Sequence< sal_Int8 > aDataToSend; + if ( !getDataFromInputStream( inInputStream, aDataToSend, true ) ) + { + throw DAVException( DAVException::DAV_INVALID_ARG ); + } + + Init( rEnv ); + + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + uno::Reference< SerfInputStream > xInputStream( new SerfInputStream ); + apr_status_t status = APR_SUCCESS; + aReqProc->processPost( reinterpret_cast< const char * >( aDataToSend.getConstArray() ), + aDataToSend.getLength(), + rContentType, + rReferer, + xInputStream, + status ); + + HandleError( aReqProc ); + return uno::Reference< io::XInputStream >( xInputStream.get() ); +} + +// ------------------------------------------------------------------- +// POST +// ------------------------------------------------------------------- +void SerfSession::POST( const rtl::OUString & inPath, + const rtl::OUString & rContentType, + const rtl::OUString & rReferer, + const uno::Reference< io::XInputStream > & inInputStream, + uno::Reference< io::XOutputStream > & oOutputStream, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + uno::Sequence< sal_Int8 > aDataToSend; + if ( !getDataFromInputStream( inInputStream, aDataToSend, true ) ) + { + throw DAVException( DAVException::DAV_INVALID_ARG ); + } + + Init( rEnv ); + + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + apr_status_t status = APR_SUCCESS; + aReqProc->processPost( reinterpret_cast< const char * >( aDataToSend.getConstArray() ), + aDataToSend.getLength(), + rContentType, + rReferer, + oOutputStream, + status ); + + HandleError( aReqProc ); +} + +// ------------------------------------------------------------------- +// MKCOL +// ------------------------------------------------------------------- +void SerfSession::MKCOL( const rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + apr_status_t status = APR_SUCCESS; + aReqProc->processMkCol( status ); + + HandleError( aReqProc ); +} + +// ------------------------------------------------------------------- +// COPY +// ------------------------------------------------------------------- +void SerfSession::COPY( const rtl::OUString & inSourceURL, + const rtl::OUString & inDestinationURL, + const DAVRequestEnvironment & rEnv, + sal_Bool inOverWrite ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + SerfUri theSourceUri( inSourceURL ); + boost::shared_ptr aReqProc( createReqProc( theSourceUri.GetPath() ) ); + apr_status_t status = APR_SUCCESS; + aReqProc->processCopy( inDestinationURL, + (inOverWrite ? true : false), + status ); + + HandleError( aReqProc ); +} + +// ------------------------------------------------------------------- +// MOVE +// ------------------------------------------------------------------- +void SerfSession::MOVE( const rtl::OUString & inSourceURL, + const rtl::OUString & inDestinationURL, + const DAVRequestEnvironment & rEnv, + sal_Bool inOverWrite ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + SerfUri theSourceUri( inSourceURL ); + boost::shared_ptr aReqProc( createReqProc( theSourceUri.GetPath() ) ); + apr_status_t status = APR_SUCCESS; + aReqProc->processMove( inDestinationURL, + (inOverWrite ? true : false), + status ); + + HandleError( aReqProc ); +} + +// ------------------------------------------------------------------- +// DESTROY +// ------------------------------------------------------------------- +void SerfSession::DESTROY( const rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + apr_status_t status = APR_SUCCESS; + aReqProc->processDelete( status ); + + HandleError( aReqProc ); +} + +// ------------------------------------------------------------------- +/* +namespace +{ + sal_Int32 lastChanceToSendRefreshRequest( TimeValue const & rStart, + int timeout ) + { + TimeValue aEnd; + osl_getSystemTime( &aEnd ); + + // Try to estimate a safe absolute time for sending the + // lock refresh request. + sal_Int32 lastChanceToSendRefreshRequest = -1; + if ( timeout != NE_TIMEOUT_INFINITE ) + { + sal_Int32 calltime = aEnd.Seconds - rStart.Seconds; + if ( calltime <= timeout ) + { + lastChanceToSendRefreshRequest + = aEnd.Seconds + timeout - calltime; + } + else + { + OSL_TRACE( "No chance to refresh lock before timeout!" ); + } + } + return lastChanceToSendRefreshRequest; + } + +} // namespace +*/ +// ------------------------------------------------------------------- +// LOCK (set new lock) +// ------------------------------------------------------------------- +void SerfSession::LOCK( const ::rtl::OUString & inPath, + ucb::Lock & /*rLock*/, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + boost::shared_ptr aReqProc( createReqProc( inPath ) ); + HandleError( aReqProc ); + /* Create a depth zero, exclusive write lock, with default timeout + * (allowing a server to pick a default). token, owner and uri are + * unset. */ + /* + SerfLock * theLock = ne_lock_create(); + + // Set the lock uri + ne_uri aUri; + ne_uri_parse( rtl::OUStringToOString( makeAbsoluteURL( inPath ), + RTL_TEXTENCODING_UTF8 ).getStr(), + &aUri ); + theLock->uri = aUri; + + // Set the lock depth + switch( rLock.Depth ) + { + case ucb::LockDepth_ZERO: + theLock->depth = NE_DEPTH_ZERO; + break; + case ucb::LockDepth_ONE: + theLock->depth = NE_DEPTH_ONE; + break; + case ucb::LockDepth_INFINITY: + theLock->depth = NE_DEPTH_INFINITE; + break; + default: + throw DAVException( DAVException::DAV_INVALID_ARG ); + } + + // Set the lock scope + switch ( rLock.Scope ) + { + case ucb::LockScope_EXCLUSIVE: + theLock->scope = ne_lockscope_exclusive; + break; + case ucb::LockScope_SHARED: + theLock->scope = ne_lockscope_shared; + break; + default: + throw DAVException( DAVException::DAV_INVALID_ARG ); + } + + // Set the lock timeout + theLock->timeout = (long)rLock.Timeout; + + // Set the lock owner + rtl::OUString aValue; + rLock.Owner >>= aValue; + theLock->owner = + ne_strdup( rtl::OUStringToOString( aValue, + RTL_TEXTENCODING_UTF8 ).getStr() ); + TimeValue startCall; + osl_getSystemTime( &startCall ); + + int theRetVal = ne_lock( m_pHttpSession, theLock ); + + if ( theRetVal == NE_OK ) + { + m_aSerfLockStore.addLock( theLock, + this, + lastChanceToSendRefreshRequest( + startCall, theLock->timeout ) ); + + uno::Sequence< rtl::OUString > aTokens( 1 ); + aTokens[ 0 ] = rtl::OUString::createFromAscii( theLock->token ); + rLock.LockTokens = aTokens; + + OSL_TRACE( "SerfSession::LOCK: created lock for %s. token: %s", + rtl::OUStringToOString( makeAbsoluteURL( inPath ), + RTL_TEXTENCODING_UTF8 ).getStr(), + theLock->token ); + } + else + { + ne_lock_destroy( theLock ); + + OSL_TRACE( "SerfSession::LOCK: obtaining lock for %s failed!", + rtl::OUStringToOString( makeAbsoluteURL( inPath ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + } + + HandleError( theRetVal, inPath, rEnv ); + */ +} + +// ------------------------------------------------------------------- +// LOCK (refresh existing lock) +// ------------------------------------------------------------------- +sal_Int64 SerfSession::LOCK( const ::rtl::OUString & /*inPath*/, + sal_Int64 nTimeout, + const DAVRequestEnvironment & /*rEnv*/ ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + return nTimeout; + /* + // Try to get the neon lock from lock store + SerfLock * theLock + = m_aSerfLockStore.findByUri( makeAbsoluteURL( inPath ) ); + if ( !theLock ) + throw DAVException( DAVException::DAV_NOT_LOCKED ); + + Init( rEnv ); + + // refresh existing lock. + theLock->timeout = static_cast< long >( nTimeout ); + + TimeValue startCall; + osl_getSystemTime( &startCall ); + + int theRetVal = ne_lock_refresh( m_pHttpSession, theLock ); + + if ( theRetVal == NE_OK ) + { + m_aSerfLockStore.updateLock( theLock, + lastChanceToSendRefreshRequest( + startCall, theLock->timeout ) ); + } + + HandleError( theRetVal, inPath, rEnv ); + + return theLock->timeout; + */ +} + +// ------------------------------------------------------------------- +// LOCK (refresh existing lock) +// ------------------------------------------------------------------- +bool SerfSession::LOCK( SerfLock * /*pLock*/, + sal_Int32 & /*rlastChanceToSendRefreshRequest*/ ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + return true; + /* + // refresh existing lock. + + TimeValue startCall; + osl_getSystemTime( &startCall ); + + if ( ne_lock_refresh( m_pHttpSession, pLock ) == NE_OK ) + { + rlastChanceToSendRefreshRequest + = lastChanceToSendRefreshRequest( startCall, pLock->timeout ); + + OSL_TRACE( "Lock successfully refreshed." ); + return true; + } + else + { + OSL_TRACE( "Lock not refreshed!" ); + return false; + } + */ +} + +// ------------------------------------------------------------------- +// UNLOCK +// ------------------------------------------------------------------- +void SerfSession::UNLOCK( const ::rtl::OUString & /*inPath*/, + const DAVRequestEnvironment & /*rEnv*/ ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + /* + // get the neon lock from lock store + SerfLock * theLock + = m_aSerfLockStore.findByUri( makeAbsoluteURL( inPath ) ); + if ( !theLock ) + throw DAVException( DAVException::DAV_NOT_LOCKED ); + + Init( rEnv ); + + int theRetVal = ne_unlock( m_pHttpSession, theLock ); + + if ( theRetVal == NE_OK ) + { + m_aSerfLockStore.removeLock( theLock ); + ne_lock_destroy( theLock ); + } + else + { + OSL_TRACE( "SerfSession::UNLOCK: unlocking of %s failed.", + rtl::OUStringToOString( makeAbsoluteURL( inPath ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + } + + HandleError( theRetVal, inPath, rEnv ); + */ +} + +// ------------------------------------------------------------------- +// UNLOCK +// ------------------------------------------------------------------- +bool SerfSession::UNLOCK( SerfLock * /*pLock*/ ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + return true; + /* + if ( ne_unlock( m_pHttpSession, pLock ) == NE_OK ) + { + OSL_TRACE( "UNLOCK succeeded." ); + return true; + } + else + { + OSL_TRACE( "UNLOCK failed!" ); + return false; + } + */ +} + +// ------------------------------------------------------------------- +void SerfSession::abort() + throw ( DAVException ) +{ + // 11.11.09 (tkr): The following code lines causing crashes if + // closing a ongoing connection. It turned out that this existing + // solution doesn't work in multi-threading environments. + // So I disabled them in 3.2. . Issue #73893# should fix it in OOo 3.3. + //if ( m_pHttpSession ) + // ne_close_connection( m_pHttpSession ); +} + +// ------------------------------------------------------------------- +const ucbhelper::InternetProxyServer & SerfSession::getProxySettings() const +{ + if ( m_aUri.GetScheme().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "http" ) ) || + m_aUri.GetScheme().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ) ) + { + return m_rProxyDecider.getProxy( m_aUri.GetScheme(), + m_aUri.GetHost(), + m_aUri.GetPort() ); + } + else + { + // TODO: figure out, if this case can occur + return m_rProxyDecider.getProxy( m_aUri.GetScheme(), + rtl::OUString() /* not used */, + -1 /* not used */ ); + } +} + +/* +// ------------------------------------------------------------------- +namespace { + +bool containsLocktoken( const uno::Sequence< ucb::Lock > & rLocks, + const char * token ) +{ + for ( sal_Int32 n = 0; n < rLocks.getLength(); ++n ) + { + const uno::Sequence< rtl::OUString > & rTokens + = rLocks[ n ].LockTokens; + for ( sal_Int32 m = 0; m < rTokens.getLength(); ++m ) + { + if ( rTokens[ m ].equalsAscii( token ) ) + return true; + } + } + return false; +} + +} // namespace +*/ + +// ------------------------------------------------------------------- +bool SerfSession::removeExpiredLocktoken( const rtl::OUString & /*inURL*/, + const DAVRequestEnvironment & /*rEnv*/ ) +{ + return true; + /* + SerfLock * theLock = m_aSerfLockStore.findByUri( inURL ); + if ( !theLock ) + return false; + + // do a lockdiscovery to check whether this lock is still valid. + try + { + // @@@ Alternative: use ne_lock_discover() => less overhead + + std::vector< DAVResource > aResources; + std::vector< rtl::OUString > aPropNames; + aPropNames.push_back( DAVProperties::LOCKDISCOVERY ); + + PROPFIND( rEnv.m_aRequestURI, DAVZERO, aPropNames, aResources, rEnv ); + + if ( aResources.size() == 0 ) + return false; + + std::vector< DAVPropertyValue >::const_iterator it + = aResources[ 0 ].properties.begin(); + std::vector< DAVPropertyValue >::const_iterator end + = aResources[ 0 ].properties.end(); + + while ( it != end ) + { + if ( (*it).Name.equals( DAVProperties::LOCKDISCOVERY ) ) + { + uno::Sequence< ucb::Lock > aLocks; + if ( !( (*it).Value >>= aLocks ) ) + return false; + + if ( !containsLocktoken( aLocks, theLock->token ) ) + { + // expired! + break; + } + + // still valid. + return false; + } + ++it; + } + + // No lockdiscovery prop in propfind result / locktoken not found + // in propfind result -> not locked + OSL_TRACE( "SerfSession::removeExpiredLocktoken: Removing " + " expired lock token for %s. token: %s", + rtl::OUStringToOString( inURL, + RTL_TEXTENCODING_UTF8 ).getStr(), + theLock->token ); + + m_aSerfLockStore.removeLock( theLock ); + ne_lock_destroy( theLock ); + return true; + } + catch ( DAVException const & ) + { + } + return false; + */ +} + +// ------------------------------------------------------------------- +// HandleError +// Common Error Handler +// ------------------------------------------------------------------- +void SerfSession::HandleError( boost::shared_ptr rReqProc ) + throw ( DAVException ) +{ + m_aEnv = DAVRequestEnvironment(); + + if ( rReqProc->mpDAVException ) + { + DAVException* mpDAVExp( rReqProc->mpDAVException ); + + serf_connection_reset( getSerfConnection() ); + + if ( mpDAVExp->getStatus() == 413 && + m_bNoOfTransferEncodingSwitches < 2 ) + { + m_bUseChunkedEncoding = !m_bUseChunkedEncoding; + ++m_bNoOfTransferEncodingSwitches; + } + + throw DAVException( mpDAVExp->getError(), + mpDAVExp->getData(), + mpDAVExp->getStatus() ); + } + + /* + // Map error code to DAVException. + switch ( nError ) + { + case NE_OK: + return; + + case NE_ERROR: // Generic error + { + rtl::OUString aText = rtl::OUString::createFromAscii( + ne_get_error( m_pHttpSession ) ); + + sal_uInt16 code = makeStatusCode( aText ); + + if ( code == SC_LOCKED ) + { + if ( m_aSerfLockStore.findByUri( + makeAbsoluteURL( inPath ) ) == 0 ) + { + // locked by 3rd party + throw DAVException( DAVException::DAV_LOCKED ); + } + else + { + // locked by ourself + throw DAVException( DAVException::DAV_LOCKED_SELF ); + } + } + + // Special handling for 400 and 412 status codes, which may indicate + // that a lock previously obtained by us has been released meanwhile + // by the server. Unfortunately, RFC is not clear at this point, + // thus server implementations behave different... + else if ( code == SC_BAD_REQUEST || code == SC_PRECONDITION_FAILED ) + { + if ( removeExpiredLocktoken( makeAbsoluteURL( inPath ), rEnv ) ) + throw DAVException( DAVException::DAV_LOCK_EXPIRED ); + } + + throw DAVException( DAVException::DAV_HTTP_ERROR, aText, code ); + } + case NE_LOOKUP: // Name lookup failed. + throw DAVException( DAVException::DAV_HTTP_LOOKUP, + SerfUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + case NE_AUTH: // User authentication failed on server + throw DAVException( DAVException::DAV_HTTP_AUTH, + SerfUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + case NE_PROXYAUTH: // User authentication failed on proxy + throw DAVException( DAVException::DAV_HTTP_AUTHPROXY, + SerfUri::makeConnectionEndPointString( + m_aProxyName, m_nProxyPort ) ); + + case NE_CONNECT: // Could not connect to server + throw DAVException( DAVException::DAV_HTTP_CONNECT, + SerfUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + case NE_TIMEOUT: // Connection timed out + throw DAVException( DAVException::DAV_HTTP_TIMEOUT, + SerfUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + case NE_FAILED: // The precondition failed + throw DAVException( DAVException::DAV_HTTP_FAILED, + SerfUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + case NE_RETRY: // Retry request (ne_end_request ONLY) + throw DAVException( DAVException::DAV_HTTP_RETRY, + SerfUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + case NE_REDIRECT: + { + SerfUri aUri( ne_redirect_location( m_pHttpSession ) ); + throw DAVException( + DAVException::DAV_HTTP_REDIRECT, aUri.GetURI() ); + } + default: + { + OSL_TRACE( "SerfSession::HandleError : Unknown Serf error code!" ); + throw DAVException( DAVException::DAV_HTTP_ERROR, + rtl::OUString::createFromAscii( + ne_get_error( m_pHttpSession ) ) ); + } + } + */ +} + +// ------------------------------------------------------------------- +// static +bool +SerfSession::getDataFromInputStream( + const uno::Reference< io::XInputStream > & xStream, + uno::Sequence< sal_Int8 > & rData, + bool bAppendTrailingZeroByte ) +{ + if ( xStream.is() ) + { + uno::Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY ); + if ( xSeekable.is() ) + { + try + { + sal_Int32 nSize + = sal::static_int_cast(xSeekable->getLength()); + sal_Int32 nRead + = xStream->readBytes( rData, nSize ); + + if ( nRead == nSize ) + { + if ( bAppendTrailingZeroByte ) + { + rData.realloc( nSize + 1 ); + rData[ nSize ] = sal_Int8( 0 ); + } + return true; + } + } + catch ( io::NotConnectedException const & ) + { + // readBytes + } + catch ( io::BufferSizeExceededException const & ) + { + // readBytes + } + catch ( io::IOException const & ) + { + // getLength, readBytes + } + } + else + { + try + { + uno::Sequence< sal_Int8 > aBuffer; + sal_Int32 nPos = 0; + + sal_Int32 nRead = xStream->readSomeBytes( aBuffer, 65536 ); + while ( nRead > 0 ) + { + if ( rData.getLength() < ( nPos + nRead ) ) + rData.realloc( nPos + nRead ); + + aBuffer.realloc( nRead ); + rtl_copyMemory( (void*)( rData.getArray() + nPos ), + (const void*)aBuffer.getConstArray(), + nRead ); + nPos += nRead; + + aBuffer.realloc( 0 ); + nRead = xStream->readSomeBytes( aBuffer, 65536 ); + } + + if ( bAppendTrailingZeroByte ) + { + rData.realloc( nPos + 1 ); + rData[ nPos ] = sal_Int8( 0 ); + } + return true; + } + catch ( io::NotConnectedException const & ) + { + // readBytes + } + catch ( io::BufferSizeExceededException const & ) + { + // readBytes + } + catch ( io::IOException const & ) + { + // readBytes + } + } + } + return false; +} + +// --------------------------------------------------------------------- +sal_Bool +SerfSession::isDomainMatch( rtl::OUString certHostName ) +{ + rtl::OUString hostName = getHostName(); + + if (hostName.equalsIgnoreAsciiCase( certHostName ) ) + return sal_True; + + if ( 0 == certHostName.indexOf( rtl::OUString::createFromAscii( "*" ) ) && + hostName.getLength() >= certHostName.getLength() ) + { + rtl::OUString cmpStr = certHostName.copy( 1 ); + + if ( hostName.matchIgnoreAsciiCase( + cmpStr, hostName.getLength() - cmpStr.getLength() ) ) + return sal_True; + } + return sal_False; +} + +/* +// --------------------------------------------------------------------- +rtl::OUString SerfSession::makeAbsoluteURL( rtl::OUString const & rURL ) const +{ + try + { + // Is URL relative or already absolute? + if ( rURL[ 0 ] != sal_Unicode( '/' ) ) + { + // absolute. + return rtl::OUString( rURL ); + } + else + { + ne_uri aUri; + memset( &aUri, 0, sizeof( aUri ) ); + + ne_fill_server_uri( m_pHttpSession, &aUri ); + aUri.path + = ne_strdup( rtl::OUStringToOString( + rURL, RTL_TEXTENCODING_UTF8 ).getStr() ); + SerfUri aSerfUri( &aUri ); + ne_uri_free( &aUri ); + return aSerfUri.GetURI(); + } + } + catch ( DAVException const & ) + { + } + // error. + return rtl::OUString(); +} +*/ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfSession.hxx b/ucb/source/ucp/webdav/SerfSession.hxx new file mode 100644 index 000000000000..73a44021cddd --- /dev/null +++ b/ucb/source/ucp/webdav/SerfSession.hxx @@ -0,0 +1,325 @@ +/* -*- 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 INCLUDED_SERFSESSION_HXX +#define INCLUDED_SERFSESSION_HXX + +#include +#include +#include +#include +#include +//#include "SerfLockStore.hxx" +#include +#include + +namespace ucbhelper { class ProxyDecider; } + +namespace http_dav_ucp +{ + +class SerfRequestProcessor; + +// ------------------------------------------------------------------- +// SerfSession +// A DAVSession implementation using the neon/expat library +// ------------------------------------------------------------------- + +class SerfSession : public DAVSession +{ +private: + osl::Mutex m_aMutex; + + SerfUri m_aUri; + + rtl::OUString m_aProxyName; + sal_Int32 m_nProxyPort; + + SerfConnection* m_pSerfConnection; + serf_context_t* m_pSerfContext; + serf_bucket_alloc_t* m_pSerfBucket_Alloc; + bool m_bIsHeadRequestInProgress; + bool m_bUseChunkedEncoding; + sal_Int16 m_bNoOfTransferEncodingSwitches; + + const ucbhelper::InternetProxyDecider & m_rProxyDecider; + + DAVRequestEnvironment m_aEnv; + +// static SerfLockStore m_aSerfLockStore; + + char* getHostinfo(); + bool isSSLNeeded(); + + SerfRequestProcessor* createReqProc( const rtl::OUString & inPath ); + +protected: + virtual ~SerfSession(); + +public: + SerfSession( const rtl::Reference< DAVSessionFactory > & rSessionFactory, + const rtl::OUString& inUri, + const ucbhelper::InternetProxyDecider & rProxyDecider ) + throw ( DAVException ); + + // Serf library callbacks + apr_status_t setupSerfConnection( apr_socket_t * inAprSocket, + serf_bucket_t **outSerfInputBucket, + serf_bucket_t **outSerfOutputBucket, + apr_pool_t* inAprPool ); + + apr_status_t provideSerfCredentials( bool bGiveProvidedCredentialsASecondTry, + char ** outUsername, + char ** outPassword, + serf_request_t * inRequest, + int inCode, + const char *inAuthProtocol, + const char *inRealm, + apr_pool_t *inAprPool ); + + apr_status_t verifySerfCertificateChain ( + int nFailures, + const char** pCertificateChainBase64Encoded, + int nCertificateChainLength); + + serf_bucket_t* acceptSerfResponse( serf_request_t * inSerfRequest, + serf_bucket_t * inSerfStreamBucket, + apr_pool_t* inAprPool ); + + // Serf-related data structures + apr_pool_t* getAprPool(); + serf_bucket_alloc_t* getSerfBktAlloc(); + serf_context_t* getSerfContext(); + SerfConnection* getSerfConnection(); + + // DAVSession methods + virtual sal_Bool CanUse( const ::rtl::OUString & inUri ); + + virtual sal_Bool UsesProxy(); + + const DAVRequestEnvironment & getRequestEnvironment() const + { return m_aEnv; } + + // allprop & named + virtual void + PROPFIND( const ::rtl::OUString & inPath, + const Depth inDepth, + const std::vector< ::rtl::OUString > & inPropNames, + std::vector< DAVResource > & ioResources, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + // propnames + virtual void + PROPFIND( const ::rtl::OUString & inPath, + const Depth inDepth, + std::vector< DAVResourceInfo >& ioResInfo, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + virtual void + PROPPATCH( const ::rtl::OUString & inPath, + const std::vector< ProppatchValue > & inValues, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + virtual void + HEAD( const ::rtl::OUString & inPath, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + bool isHeadRequestInProgress(); + + virtual com::sun::star::uno::Reference< com::sun::star::io::XInputStream > + GET( const ::rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + virtual void + GET( const ::rtl::OUString & inPath, + com::sun::star::uno::Reference< + com::sun::star::io::XOutputStream > & ioOutputStream, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + virtual com::sun::star::uno::Reference< com::sun::star::io::XInputStream > + GET( const ::rtl::OUString & inPath, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + virtual void + GET( const ::rtl::OUString & inPath, + com::sun::star::uno::Reference< + com::sun::star::io::XOutputStream > & ioOutputStream, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + virtual void + PUT( const ::rtl::OUString & inPath, + const com::sun::star::uno::Reference< + com::sun::star::io::XInputStream > & inInputStream, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + virtual com::sun::star::uno::Reference< com::sun::star::io::XInputStream > + POST( const rtl::OUString & inPath, + const rtl::OUString & rContentType, + const rtl::OUString & rReferer, + const com::sun::star::uno::Reference< + com::sun::star::io::XInputStream > & inInputStream, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + virtual void + POST( const rtl::OUString & inPath, + const rtl::OUString & rContentType, + const rtl::OUString & rReferer, + const com::sun::star::uno::Reference< + com::sun::star::io::XInputStream > & inInputStream, + com::sun::star::uno::Reference< + com::sun::star::io::XOutputStream > & oOutputStream, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + virtual void + MKCOL( const ::rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + virtual void + COPY( const ::rtl::OUString & inSourceURL, + const ::rtl::OUString & inDestinationURL, + const DAVRequestEnvironment & rEnv, + sal_Bool inOverWrite ) + throw ( DAVException ); + + virtual void + MOVE( const ::rtl::OUString & inSourceURL, + const ::rtl::OUString & inDestinationURL, + const DAVRequestEnvironment & rEnv, + sal_Bool inOverWrite ) + throw ( DAVException ); + + virtual void DESTROY( const ::rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + // set new lock. + virtual void LOCK( const ::rtl::OUString & inURL, + com::sun::star::ucb::Lock & inLock, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + // refresh existing lock. + virtual sal_Int64 LOCK( const ::rtl::OUString & inURL, + sal_Int64 nTimeout, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + virtual void UNLOCK( const ::rtl::OUString & inURL, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + // helpers + virtual void abort() + throw ( DAVException ); + + const rtl::OUString & getHostName() const { return m_aUri.GetHost(); } + int getPort() const { return m_aUri.GetPort(); } + + const ::uno::Reference< ::lang::XMultiServiceFactory > getMSF() + { return m_xFactory->getServiceFactory(); } + + sal_Bool isDomainMatch( rtl::OUString certHostName ); + +private: + friend class SerfLockStore; + + void Init( void ) + throw ( DAVException ); + + void Init( const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + void HandleError( boost::shared_ptr rReqProc ) + throw ( DAVException ); + + const ucbhelper::InternetProxyServer & getProxySettings() const; + + bool removeExpiredLocktoken( const rtl::OUString & inURL, + const DAVRequestEnvironment & rEnv ); + + // refresh lock, called by SerfLockStore::refreshLocks + bool LOCK( SerfLock * pLock, + sal_Int32 & rlastChanceToSendRefreshRequest ); + + // unlock, called by SerfLockStore::~SerfLockStore + bool UNLOCK( SerfLock * pLock ); + + /* + // low level GET implementation, used by public GET implementations + static int GET( SerfConnection * sess, + const char * uri, + //ne_block_reader reader, + bool getheaders, + void * userdata ); + + // Buffer-based PUT implementation. Serf only has file descriptor- + // based API. + static int PUT( SerfConnection * sess, + const char * uri, + const char * buffer, + size_t size ); + + // Buffer-based POST implementation. Serf only has file descriptor- + // based API. + int POST( SerfConnection * sess, + const char * uri, + const char * buffer, + //ne_block_reader reader, + void * userdata, + const rtl::OUString & rContentType, + const rtl::OUString & rReferer ); + */ + + // Helper: XInputStream -> Sequence< sal_Int8 > + static bool getDataFromInputStream( + const com::sun::star::uno::Reference< + com::sun::star::io::XInputStream > & xStream, + com::sun::star::uno::Sequence< sal_Int8 > & rData, + bool bAppendTrailingZeroByte ); + + /* + rtl::OUString makeAbsoluteURL( rtl::OUString const & rURL ) const; + */ +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFSESSION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfTypes.hxx b/ucb/source/ucp/webdav/SerfTypes.hxx new file mode 100644 index 000000000000..b396697be9f7 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfTypes.hxx @@ -0,0 +1,37 @@ +/* -*- 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 INCLUDED_SERFTYPES_HXX +#define INCLUDED_SERFTYPES_HXX + +#include + +typedef serf_connection_t SerfConnection; + +// TODO, figure out type of +typedef int SerfLock; + +// TODO, check if we need it later on +typedef struct { const char *nspace, *name; } SerfPropName; + +#endif // INCLUDED_SERFTYPES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfUri.cxx b/ucb/source/ucp/webdav/SerfUri.cxx new file mode 100644 index 000000000000..4dc38997a872 --- /dev/null +++ b/ucb/source/ucp/webdav/SerfUri.cxx @@ -0,0 +1,279 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include +#include +#include +#include +#include "SerfUri.hxx" +#include "DAVException.hxx" +#include + +#include "../inc/urihelper.hxx" + +using namespace http_dav_ucp; + +# if defined __SUNPRO_CC +# pragma enable_warn +#endif + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- + +namespace { + +inline bool matchIgnoreAsciiCase(rtl::OString const & rStr1, + sal_Char const * pStr2, + sal_Int32 nStr2Len) SAL_THROW(()) +{ + return + rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( + rStr1.getStr(), rStr1.getLength(), pStr2, nStr2Len, nStr2Len) + == 0; +} + +} + +SerfUri::SerfUri( const apr_uri_t * inUri ) + throw ( DAVException ) + : mAprUri( *inUri ) + , mURI() + , mScheme() + , mUserInfo() + , mHostName() + , mPort() + , mPath() +{ + if ( inUri == 0 ) + throw DAVException( DAVException::DAV_INVALID_ARG ); + + char * uri = apr_uri_unparse( apr_environment::AprEnv::getAprEnv()->getAprPool(), &mAprUri, 0 ); + + if ( uri == 0 ) + throw DAVException( DAVException::DAV_INVALID_ARG ); + + init( &mAprUri ); + + calculateURI(); +} + +SerfUri::SerfUri( const rtl::OUString & inUri ) + throw ( DAVException ) + : mAprUri() + , mURI() + , mScheme() + , mUserInfo() + , mHostName() + , mPort() + , mPath() +{ + if ( inUri.getLength() <= 0 ) + throw DAVException( DAVException::DAV_INVALID_ARG ); + + // #i77023# + rtl::OUString aEscapedUri( ucb_impl::urihelper::encodeURI( inUri ) ); + + rtl::OString theInputUri( + aEscapedUri.getStr(), aEscapedUri.getLength(), RTL_TEXTENCODING_UTF8 ); + + if ( apr_uri_parse( apr_environment::AprEnv::getAprEnv()->getAprPool(), + theInputUri.getStr(), &mAprUri ) != APR_SUCCESS ) + { + throw DAVException( DAVException::DAV_INVALID_ARG ); + } + if ( !mAprUri.port ) + { + mAprUri.port = apr_uri_port_of_scheme( mAprUri.scheme ); + } + if ( !mAprUri.path ) + { + mAprUri.path = "/"; + } + + init( &mAprUri ); + + calculateURI(); +} + +void SerfUri::init( const apr_uri_t * pUri ) +{ + mScheme = rtl::OStringToOUString( pUri->scheme, RTL_TEXTENCODING_UTF8 ); + mUserInfo = rtl::OStringToOUString( pUri->user, RTL_TEXTENCODING_UTF8 ); + mHostName = rtl::OStringToOUString( pUri->hostname, RTL_TEXTENCODING_UTF8 ); + mPort = pUri->port; + mPath = rtl::OStringToOUString( pUri->path, RTL_TEXTENCODING_UTF8 ); + + if ( pUri->query ) + { + mPath += rtl::OUString::createFromAscii( "?" ); + mPath += rtl::OStringToOUString( pUri->query, RTL_TEXTENCODING_UTF8 ); + } + + if ( pUri->fragment ) + { + mPath += rtl::OUString::createFromAscii( "#" ); + mPath += rtl::OStringToOUString( pUri->fragment, RTL_TEXTENCODING_UTF8 ); + } +} + +SerfUri::~SerfUri( ) +{ +} + +void SerfUri::calculateURI () +{ + rtl::OUStringBuffer aBuf( mScheme ); + aBuf.appendAscii( "://" ); + if ( mUserInfo.getLength() > 0 ) + { + aBuf.append( mUserInfo ); + aBuf.appendAscii( "@" ); + } + // Is host a numeric IPv6 address? + if ( ( mHostName.indexOf( ':' ) != -1 ) && + ( mHostName[ 0 ] != sal_Unicode( '[' ) ) ) + { + aBuf.appendAscii( "[" ); + aBuf.append( mHostName ); + aBuf.appendAscii( "]" ); + } + else + { + aBuf.append( mHostName ); + } + + // append port, but only, if not default port. + bool bAppendPort = true; + switch ( mPort ) + { + case DEFAULT_HTTP_PORT: + bAppendPort = !mScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "http" ) ); + break; + + case DEFAULT_HTTPS_PORT: + bAppendPort = !mScheme.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ); + break; + } + if ( bAppendPort ) + { + aBuf.appendAscii( ":" ); + aBuf.append( rtl::OUString::valueOf( mPort ) ); + } + aBuf.append( mPath ); + + mURI = aBuf.makeStringAndClear(); +} + +::rtl::OUString SerfUri::GetPathBaseName () const +{ + sal_Int32 nPos = mPath.lastIndexOf ('/'); + sal_Int32 nTrail = 0; + if (nPos == mPath.getLength () - 1) + { + // Trailing slash found. Skip. + nTrail = 1; + nPos = mPath.lastIndexOf ('/', nPos); + } + if (nPos != -1) + { + rtl::OUString aTemp( + mPath.copy (nPos + 1, mPath.getLength () - nPos - 1 - nTrail) ); + + // query, fragment present? + nPos = aTemp.indexOf( '?' ); + if ( nPos == -1 ) + nPos = aTemp.indexOf( '#' ); + + if ( nPos != -1 ) + aTemp = aTemp.copy( 0, nPos ); + + return aTemp; + } + else + return rtl::OUString::createFromAscii ("/"); +} + +bool SerfUri::operator== ( const SerfUri & rOther ) const +{ + return ( mURI == rOther.mURI ); +} + +::rtl::OUString SerfUri::GetPathBaseNameUnescaped () const +{ + return unescape( GetPathBaseName() ); +} + +void SerfUri::AppendPath (const rtl::OUString& rPath) +{ + if (mPath.lastIndexOf ('/') != mPath.getLength () - 1) + mPath += rtl::OUString::createFromAscii ("/"); + + mPath += rPath; + calculateURI (); +}; + +// static +rtl::OUString SerfUri::escapeSegment( const rtl::OUString& segment ) +{ + return rtl::Uri::encode( segment, + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ); +} + +// static +rtl::OUString SerfUri::unescape( const rtl::OUString& segment ) +{ + return rtl::Uri::decode( segment, + rtl_UriDecodeWithCharset, + RTL_TEXTENCODING_UTF8 ); +} + +// static +rtl::OUString SerfUri::makeConnectionEndPointString( + const rtl::OUString & rHostName, int nPort ) +{ + rtl::OUStringBuffer aBuf; + + // Is host a numeric IPv6 address? + if ( ( rHostName.indexOf( ':' ) != -1 ) && + ( rHostName[ 0 ] != sal_Unicode( '[' ) ) ) + { + aBuf.appendAscii( "[" ); + aBuf.append( rHostName ); + aBuf.appendAscii( "]" ); + } + else + { + aBuf.append( rHostName ); + } + + if ( ( nPort != DEFAULT_HTTP_PORT ) && ( nPort != DEFAULT_HTTPS_PORT ) ) + { + aBuf.appendAscii( ":" ); + aBuf.append( rtl::OUString::valueOf( sal_Int32( nPort ) ) ); + } + return aBuf.makeStringAndClear(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/SerfUri.hxx b/ucb/source/ucp/webdav/SerfUri.hxx new file mode 100644 index 000000000000..89298c09b2bb --- /dev/null +++ b/ucb/source/ucp/webdav/SerfUri.hxx @@ -0,0 +1,102 @@ +/* -*- 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 INCLUDED_SERFURI_HXX +#define INCLUDED_SERFURI_HXX + +#include +#include +#include + +namespace http_dav_ucp +{ + +#define DEFAULT_HTTP_PORT 80 +#define DEFAULT_HTTPS_PORT 443 + +// ------------------------------------------------------------------- +// SerfUri +// A URI implementation for use with the neon/expat library +// ------------------------------------------------------------------- +class SerfUri +{ + private: + apr_uri_t mAprUri; + ::rtl::OUString mURI; + ::rtl::OUString mScheme; + ::rtl::OUString mUserInfo; + ::rtl::OUString mHostName; + sal_Int32 mPort; + ::rtl::OUString mPath; + + void init( const apr_uri_t * pUri ); + void calculateURI (); + + public: + SerfUri( const ::rtl::OUString & inUri ) throw ( DAVException ); + SerfUri( const apr_uri_t * inUri ) throw ( DAVException ); + ~SerfUri( ); + + bool operator== ( const SerfUri & rOther ) const; + bool operator!= ( const SerfUri & rOther ) const + { return !operator==( rOther ); } + + apr_uri_t* getAprUri() + { + return &mAprUri; + } + const ::rtl::OUString & GetURI( void ) const + { return mURI; }; + const ::rtl::OUString & GetScheme( void ) const + { return mScheme; }; + const ::rtl::OUString & GetUserInfo( void ) const + { return mUserInfo; }; + const ::rtl::OUString & GetHost( void ) const + { return mHostName; }; + sal_Int32 GetPort( void ) const + { return mPort; }; + const ::rtl::OUString & GetPath( void ) const + { return mPath; }; + + ::rtl::OUString GetPathBaseName ( void ) const; + + ::rtl::OUString GetPathBaseNameUnescaped ( void ) const; + + void SetScheme (const ::rtl::OUString& scheme) + { mScheme = scheme; calculateURI (); }; + + void AppendPath (const ::rtl::OUString& rPath); + + static ::rtl::OUString escapeSegment( const ::rtl::OUString& segment ); + static ::rtl::OUString unescape( const ::rtl::OUString& string ); + + // "host:port", omit ":port" for port 80 and 443 + static rtl::OUString makeConnectionEndPointString( + const rtl::OUString & rHostName, + int nPort ); + rtl::OUString makeConnectionEndPointString() const + { return makeConnectionEndPointString( GetHost(), GetPort() ); } +}; + +} // namespace http_dav_ucp + +#endif // INCLUDED_SERFURI_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/UCBDeadPropertyValue.cxx b/ucb/source/ucp/webdav/UCBDeadPropertyValue.cxx new file mode 100644 index 000000000000..d284e2b75132 --- /dev/null +++ b/ucb/source/ucp/webdav/UCBDeadPropertyValue.cxx @@ -0,0 +1,543 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include +//#include +#include +#include +#include "UCBDeadPropertyValue.hxx" + +using namespace http_dav_ucp; +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////// + +struct UCBDeadPropertyValueParseContext +{ + rtl::OUString * pType; + rtl::OUString * pValue; + + UCBDeadPropertyValueParseContext() : pType( 0 ), pValue( 0 ) {} + ~UCBDeadPropertyValueParseContext() { delete pType; delete pValue; } +}; + +// static +const rtl::OUString UCBDeadPropertyValue::aTypeString + = rtl::OUString::createFromAscii( "string" ); +const rtl::OUString UCBDeadPropertyValue::aTypeLong + = rtl::OUString::createFromAscii( "long" ); +const rtl::OUString UCBDeadPropertyValue::aTypeShort + = rtl::OUString::createFromAscii( "short" ); +const rtl::OUString UCBDeadPropertyValue::aTypeBoolean + = rtl::OUString::createFromAscii( "boolean" ); +const rtl::OUString UCBDeadPropertyValue::aTypeChar + = rtl::OUString::createFromAscii( "char" ); +const rtl::OUString UCBDeadPropertyValue::aTypeByte + = rtl::OUString::createFromAscii( "byte" ); +const rtl::OUString UCBDeadPropertyValue::aTypeHyper + = rtl::OUString::createFromAscii( "hyper" ); +const rtl::OUString UCBDeadPropertyValue::aTypeFloat + = rtl::OUString::createFromAscii( "float" ); +const rtl::OUString UCBDeadPropertyValue::aTypeDouble + = rtl::OUString::createFromAscii( "double" ); + +// static +const rtl::OUString UCBDeadPropertyValue::aXMLPre + = rtl::OUString::createFromAscii( "" ); +const rtl::OUString UCBDeadPropertyValue::aXMLMid + = rtl::OUString::createFromAscii( "" ); +const rtl::OUString UCBDeadPropertyValue::aXMLEnd + = rtl::OUString::createFromAscii( "" ); + +#define STATE_TOP (1) + +#define STATE_UCBPROP (STATE_TOP) +#define STATE_TYPE (STATE_TOP + 1) +#define STATE_VALUE (STATE_TOP + 2) + +/* +////////////////////////////////////////////////////////////////////////// +extern "C" int UCBDeadPropertyValue_startelement_callback( + void *, + int parent, + const char * nspace, + const char *name, + const char ** ) +{ + if ( name != 0 ) + { + switch ( parent ) + { + case NE_XML_STATEROOT: + if ( strcmp( name, "ucbprop" ) == 0 ) + return STATE_UCBPROP; + break; + + case STATE_UCBPROP: + if ( strcmp( name, "type" ) == 0 ) + return STATE_TYPE; + else if ( strcmp( name, "value" ) == 0 ) + return STATE_VALUE; + break; + } + } + return NE_XML_DECLINE; +} + +////////////////////////////////////////////////////////////////////////// +extern "C" int UCBDeadPropertyValue_chardata_callback( + void *userdata, + int state, + const char *buf, + size_t len ) +{ + UCBDeadPropertyValueParseContext * pCtx + = static_cast< UCBDeadPropertyValueParseContext * >( userdata ); + + switch ( state ) + { + case STATE_TYPE: + OSL_ENSURE( !pCtx->pType, + "UCBDeadPropertyValue_endelement_callback - " + "Type already set!" ); + pCtx->pType + = new rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US ); + break; + + case STATE_VALUE: + OSL_ENSURE( !pCtx->pValue, + "UCBDeadPropertyValue_endelement_callback - " + "Value already set!" ); + pCtx->pValue + = new rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US ); + break; + } + return 0; // zero to continue, non-zero to abort parsing +} + +////////////////////////////////////////////////////////////////////////// +extern "C" int UCBDeadPropertyValue_endelement_callback( + void *userdata, + int state, + const char *, + const char * ) +{ + UCBDeadPropertyValueParseContext * pCtx + = static_cast< UCBDeadPropertyValueParseContext * >( userdata ); + + switch ( state ) + { + case STATE_TYPE: + if ( !pCtx->pType ) + return 1; // abort + break; + + case STATE_VALUE: + if ( !pCtx->pValue ) + return 1; // abort + break; + + case STATE_UCBPROP: + if ( !pCtx->pType || ! pCtx->pValue ) + return 1; // abort + break; + } + return 0; // zero to continue, non-zero to abort parsing +} +*/ + +////////////////////////////////////////////////////////////////////////// +static rtl::OUString encodeValue( const rtl::OUString & rValue ) +{ + // Note: I do not use the usual & + < + > encoding, because + // I want to prevent any XML parser from trying to 'understand' + // the value. This caused problems: + // + // Example: + // - Unencoded property value: xstringx<z + // PROPFIND: + // - parser replaces < by > ==> error (not well formed) + + rtl::OUStringBuffer aResult; + const sal_Unicode * pValue = rValue.getStr(); + + sal_Int32 nCount = rValue.getLength(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const sal_Unicode c = pValue[ n ]; + + if ( '%' == c ) + aResult.appendAscii( "%per;" ); + else if ( '<' == c ) + aResult.appendAscii( "%lt;" ); + else if ( '>' == c ) + aResult.appendAscii( "%gt;" ); + else + aResult.append( c ); + } + return rtl::OUString( aResult ); +} + +/* +////////////////////////////////////////////////////////////////////////// +static rtl::OUString decodeValue( const rtl::OUString & rValue ) +{ + rtl::OUStringBuffer aResult; + const sal_Unicode * pValue = rValue.getStr(); + + sal_Int32 nPos = 0; + sal_Int32 nEnd = rValue.getLength(); + + while ( nPos < nEnd ) + { + sal_Unicode c = pValue[ nPos ]; + + if ( '%' == c ) + { + nPos++; + + if ( nPos == nEnd ) + { + OSL_ENSURE( sal_False, + "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + + c = pValue[ nPos ]; + + if ( 'p' == c ) + { + // %per; + + if ( nPos > nEnd - 4 ) + { + OSL_ENSURE( sal_False, + "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + + if ( ( 'e' == pValue[ nPos + 1 ] ) + && + ( 'r' == pValue[ nPos + 2 ] ) + && + ( ';' == pValue[ nPos + 3 ] ) ) + { + aResult.append( sal_Unicode( '%' ) ); + nPos += 3; + } + else + { + OSL_ENSURE( sal_False, + "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + } + else if ( 'l' == c ) + { + // %lt; + + if ( nPos > nEnd - 3 ) + { + OSL_ENSURE( sal_False, + "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + + if ( ( 't' == pValue[ nPos + 1 ] ) + && + ( ';' == pValue[ nPos + 2 ] ) ) + { + aResult.append( sal_Unicode( '<' ) ); + nPos += 2; + } + else + { + OSL_ENSURE( sal_False, + "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + } + else if ( 'g' == c ) + { + // %gt; + + if ( nPos > nEnd - 3 ) + { + OSL_ENSURE( sal_False, + "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + + if ( ( 't' == pValue[ nPos + 1 ] ) + && + ( ';' == pValue[ nPos + 2 ] ) ) + { + aResult.append( sal_Unicode( '>' ) ); + nPos += 2; + } + else + { + OSL_ENSURE( sal_False, + "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + } + else + { + OSL_ENSURE( sal_False, + "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + } + else + aResult.append( c ); + + nPos++; + } + + return rtl::OUString( aResult ); +} +*/ + +////////////////////////////////////////////////////////////////////////// +// static +bool UCBDeadPropertyValue::supportsType( const uno::Type & rType ) +{ + if ( ( rType != getCppuType( static_cast< const rtl::OUString * >( 0 ) ) ) + && + ( rType != getCppuType( static_cast< const sal_Int32 * >( 0 ) ) ) + && + ( rType != getCppuType( static_cast< const sal_Int16 * >( 0 ) ) ) + && + ( rType != getCppuBooleanType() ) + && + ( rType != getCppuCharType() ) + && + ( rType != getCppuType( static_cast< const sal_Int8 * >( 0 ) ) ) + && + ( rType != getCppuType( static_cast< const sal_Int64 * >( 0 ) ) ) + && + ( rType != getCppuType( static_cast< const float * >( 0 ) ) ) + && + ( rType != getCppuType( static_cast< const double * >( 0 ) ) ) ) + { + return false; + } + + return true; +} + +////////////////////////////////////////////////////////////////////////// +// static +bool UCBDeadPropertyValue::createFromXML( const rtl::OString & /*rInData*/, + uno::Any & /*rOutData*/ ) +{ + bool success = false; + + /* + ne_xml_parser * parser = ne_xml_create(); + if ( parser ) + { + UCBDeadPropertyValueParseContext aCtx; + ne_xml_push_handler( parser, + UCBDeadPropertyValue_startelement_callback, + UCBDeadPropertyValue_chardata_callback, + UCBDeadPropertyValue_endelement_callback, + &aCtx ); + + ne_xml_parse( parser, rInData.getStr(), rInData.getLength() ); + + success = !ne_xml_failed( parser ); + + ne_xml_destroy( parser ); + + if ( success ) + { + if ( aCtx.pType && aCtx.pValue ) + { + // Decode aCtx.pValue! It may contain XML reserved chars. + rtl::OUString aStringValue = decodeValue( *aCtx.pValue ); + if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeString ) ) + { + rOutData <<= aStringValue; + } + else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeLong ) ) + { + rOutData <<= aStringValue.toInt32(); + } + else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeShort ) ) + { + rOutData <<= sal_Int16( aStringValue.toInt32() ); + } + else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeBoolean ) ) + { + if ( aStringValue.equalsIgnoreAsciiCase( + rtl::OUString::createFromAscii( "true" ) ) ) + rOutData <<= sal_Bool( sal_True ); + else + rOutData <<= sal_Bool( sal_False ); + } + else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeChar ) ) + { + rOutData <<= aStringValue.toChar(); + } + else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeByte ) ) + { + rOutData <<= sal_Int8( aStringValue.toChar() ); + } + else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeHyper ) ) + { + rOutData <<= aStringValue.toInt64(); + } + else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeFloat ) ) + { + rOutData <<= aStringValue.toFloat(); + } + else if ( aCtx.pType->equalsIgnoreAsciiCase( aTypeDouble ) ) + { + rOutData <<= aStringValue.toDouble(); + } + else + { + OSL_ENSURE( sal_False, + "UCBDeadPropertyValue::createFromXML - " + "Unsupported property type!" ); + success = false; + } + } + else + success = false; + } + } + */ + return success; +} + +////////////////////////////////////////////////////////////////////////// +// static +bool UCBDeadPropertyValue::toXML( const uno::Any & rInData, + rtl::OUString & rOutData ) +{ + // the_typethe_value + + // Check property type. Extract type and value as string. + + const uno::Type& rType = rInData.getValueType(); + rtl::OUString aStringValue; + rtl::OUString aStringType; + + if ( rType == getCppuType( static_cast< const rtl::OUString * >( 0 ) ) ) + { + // string + rInData >>= aStringValue; + aStringType = aTypeString; + } + else if ( rType == getCppuType( static_cast< const sal_Int32 * >( 0 ) ) ) + { + // long + sal_Int32 nValue = 0; + rInData >>= nValue; + aStringValue = rtl::OUString::valueOf( nValue ); + aStringType = aTypeLong; + } + else if ( rType == getCppuType( static_cast< const sal_Int16 * >( 0 ) ) ) + { + // short + sal_Int32 nValue = 0; + rInData >>= nValue; + aStringValue = rtl::OUString::valueOf( nValue ); + aStringType = aTypeShort; + } + else if ( rType == getCppuBooleanType() ) + { + // boolean + sal_Bool bValue = false; + rInData >>= bValue; + aStringValue = rtl::OUString::valueOf( bValue ); + aStringType = aTypeBoolean; + } + else if ( rType == getCppuCharType() ) + { + // char + sal_Unicode cValue = 0; + rInData >>= cValue; + aStringValue = rtl::OUString::valueOf( cValue ); + aStringType = aTypeChar; + } + else if ( rType == getCppuType( static_cast< const sal_Int8 * >( 0 ) ) ) + { + // byte + sal_Int8 nValue = 0; + rInData >>= nValue; + aStringValue = rtl::OUString::valueOf( sal_Unicode( nValue ) ); + aStringType = aTypeByte; + } + else if ( rType == getCppuType( static_cast< const sal_Int64 * >( 0 ) ) ) + { + // hyper + sal_Int64 nValue = 0; + rInData >>= nValue; + aStringValue = rtl::OUString::valueOf( nValue ); + aStringType = aTypeHyper; + } + else if ( rType == getCppuType( static_cast< const float * >( 0 ) ) ) + { + // float + float nValue = 0; + rInData >>= nValue; + aStringValue = rtl::OUString::valueOf( nValue ); + aStringType = aTypeFloat; + } + else if ( rType == getCppuType( static_cast< const double * >( 0 ) ) ) + { + // double + double nValue = 0; + rInData >>= nValue; + aStringValue = rtl::OUString::valueOf( nValue ); + aStringType = aTypeDouble; + } + else + { + OSL_ENSURE( sal_False, + "UCBDeadPropertyValue::toXML - " + "Unsupported property type!" ); + return false; + } + + // Encode value! It must not contain XML reserved chars! + aStringValue = encodeValue( aStringValue ); + + rOutData = aXMLPre; + rOutData += aStringType; + rOutData += aXMLMid; + rOutData += aStringValue; + rOutData += aXMLEnd; + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/UCBDeadPropertyValue.hxx b/ucb/source/ucp/webdav/UCBDeadPropertyValue.hxx new file mode 100644 index 000000000000..7ed138fa7c86 --- /dev/null +++ b/ucb/source/ucp/webdav/UCBDeadPropertyValue.hxx @@ -0,0 +1,61 @@ +/* -*- 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 _UCBDEADPROPERTYVALUE_HXX_ +#define _UCBDEADPROPERTYVALUE_HXX_ + +#include +#include + +namespace http_dav_ucp +{ + +class UCBDeadPropertyValue +{ +private: + static const rtl::OUString aTypeString; + static const rtl::OUString aTypeLong; + static const rtl::OUString aTypeShort; + static const rtl::OUString aTypeBoolean; + static const rtl::OUString aTypeChar; + static const rtl::OUString aTypeByte; + static const rtl::OUString aTypeHyper; + static const rtl::OUString aTypeFloat; + static const rtl::OUString aTypeDouble; + + static const rtl::OUString aXMLPre; + static const rtl::OUString aXMLMid; + static const rtl::OUString aXMLEnd; + +public: + static bool supportsType( const com::sun::star::uno::Type & rType ); + + static bool createFromXML( const rtl::OString & rInData, + com::sun::star::uno::Any & rOutData ); + static bool toXML( const com::sun::star::uno::Any & rInData, + rtl::OUString & rOutData ); +}; + +} + +#endif /* _UCBDEADPROPERTYVALUE_HXX_ */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/ucpdav.xml b/ucb/source/ucp/webdav/ucpdav.xml new file mode 100644 index 000000000000..6dd0498a1eca --- /dev/null +++ b/ucb/source/ucp/webdav/ucpdav.xml @@ -0,0 +1,128 @@ + + + + + + + + + ucpdav + + + + + Kai Sommerfeld + + + com.sun.star.comp.ucb.WebDAVContentProvider + + + This component implements a Content Provider for the Universal + Content Broker. It provides access to contents stored on an HTTP/WebDAV + server. + + + com.sun.star.loader.SharedLibrary + + + c++ + + + + com.sun.star.ucb.WebDAVContentProvider + + + + external + sal + cppu + cppuhelper + ucbhelper + + sal3 + cppu3 + cppuhelper3$(COM) + ucbhelper4$(COM) + + com.sun.star.beans.PropertyAttribute + com.sun.star.beans.PropertyValue + com.sun.star.beans.XPropertiesChangeNotifier + com.sun.star.beans.XPropertyAccess + com.sun.star.beans.XPropertyContainer + com.sun.star.beans.XPropertySetInfoChangeNotifier + com.sun.star.container.XChild + com.sun.star.io.XActiveDataSink + com.sun.star.io.XInputStream + com.sun.star.io.XOutputStream + com.sun.star.io.XSeekable + com.sun.star.lang.IllegalAccessException + com.sun.star.lang.XComponent + com.sun.star.lang.XMultiServiceFactory + com.sun.star.lang.XServiceInfo + com.sun.star.lang.XSingleServiceFactory + com.sun.star.lang.XTypeProvider + com.sun.star.registry.XRegistryKey + com.sun.star.sdbc.XCloseable + com.sun.star.sdbc.XColumnLocate + com.sun.star.sdbc.XResultSetMetaDataSupplier + com.sun.star.sdbc.XRow + com.sun.star.task.InteractionClassification + com.sun.star.task.XInteractionAbort + com.sun.star.task.XInteractionReply + com.sun.star.ucb.AuthenticationRequest + com.sun.star.ucb.CommandFailedException + com.sun.star.ucb.ContentCreationException + com.sun.star.ucb.ContentInfoAttribute + com.sun.star.ucb.InsertCommandArgument + com.sun.star.ucb.InteractiveAugmentedIOException + com.sun.star.ucb.InteractiveBadTransferURLException + com.sun.star.ucb.InteractiveNetworkConnectException + com.sun.star.ucb.InteractiveNetworkGeneralException + com.sun.star.ucb.InteractiveNetworkReadException + com.sun.star.ucb.InteractiveNetworkResolveNameException + com.sun.star.ucb.InteractiveNetworkWriteException + com.sun.star.ucb.Link + com.sun.star.ucb.Lock + com.sun.star.ucb.MissingInputStreamException + com.sun.star.ucb.MissingPropertiesException + com.sun.star.ucb.NameClash + com.sun.star.ucb.NameClashException + com.sun.star.ucb.OpenCommandArgument2 + com.sun.star.ucb.OpenMode + com.sun.star.ucb.PostCommandArgument2 + com.sun.star.ucb.RememberAuthentication + com.sun.star.ucb.ResultSetException + com.sun.star.ucb.TransferInfo + com.sun.star.ucb.XCommandEnvironment + com.sun.star.ucb.UnsupportedCommandException + com.sun.star.ucb.UnsupportedDataSinkException + com.sun.star.ucb.UnsupportedNameClashException + com.sun.star.ucb.UnsupportedOpenModeException + com.sun.star.ucb.XCommandInfo + com.sun.star.ucb.XCommandInfoChangeNotifier + com.sun.star.ucb.XCommandProcessor + com.sun.star.ucb.XContentAccess + com.sun.star.ucb.XContentCreator + com.sun.star.ucb.XContentProvider + com.sun.star.ucb.XDynamicResultSet + com.sun.star.ucb.XInteractionSupplyAuthentication + com.sun.star.ucb.XPersistentPropertySet + com.sun.star.uno.XAggregation + com.sun.star.util.DateTime + diff --git a/ucb/source/ucp/webdav/ucpdav1.component b/ucb/source/ucp/webdav/ucpdav1.component new file mode 100644 index 000000000000..50a3d87b28e0 --- /dev/null +++ b/ucb/source/ucp/webdav/ucpdav1.component @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/ucb/source/ucp/webdav/webdavcontent.cxx b/ucb/source/ucp/webdav/webdavcontent.cxx new file mode 100644 index 000000000000..7bfd880f9d0f --- /dev/null +++ b/ucb/source/ucp/webdav/webdavcontent.cxx @@ -0,0 +1,3245 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ + +#include +#include "osl/doublecheckedlocking.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "com/sun/star/ucb/InteractiveLockingLockedException.hpp" +#include "com/sun/star/ucb/InteractiveLockingLockExpiredException.hpp" +#include "com/sun/star/ucb/InteractiveLockingNotLockedException.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "webdavcontent.hxx" +#include "webdavprovider.hxx" +#include "webdavresultset.hxx" +#include "ContentProperties.hxx" +#include "SerfUri.hxx" +#include "UCBDeadPropertyValue.hxx" + +using namespace com::sun::star; +using namespace http_dav_ucp; + +//========================================================================= +//========================================================================= +// +// Content Implementation. +// +//========================================================================= +//========================================================================= + +//========================================================================= +// ctr for content on an existing webdav resource +Content::Content( + const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, + ContentProvider* pProvider, + const uno::Reference< ucb::XContentIdentifier >& Identifier, + rtl::Reference< DAVSessionFactory > const & rSessionFactory ) + throw ( ucb::ContentCreationException ) +: ContentImplHelper( rxSMgr, pProvider, Identifier ), + m_eResourceType( UNKNOWN ), + m_pProvider( pProvider ), + m_bTransient( false ), + m_bCollection( false ), + m_bDidGetOrHead( false ) +{ + try + { + m_xResAccess.reset( new DAVResourceAccess( + rxSMgr, + rSessionFactory, + Identifier->getContentIdentifier() ) ); + + SerfUri aURI( Identifier->getContentIdentifier() ); + m_aEscapedTitle = aURI.GetPathBaseName(); + } + catch ( DAVException const & ) + { + throw ucb::ContentCreationException(); + } +} + +//========================================================================= +// ctr for content on an non-existing webdav resource +Content::Content( + const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, + ContentProvider* pProvider, + const uno::Reference< ucb::XContentIdentifier >& Identifier, + rtl::Reference< DAVSessionFactory > const & rSessionFactory, + sal_Bool isCollection ) + throw ( ucb::ContentCreationException ) +: ContentImplHelper( rxSMgr, pProvider, Identifier ), + m_eResourceType( UNKNOWN ), + m_pProvider( pProvider ), + m_bTransient( true ), + m_bCollection( isCollection ), + m_bDidGetOrHead( false ) +{ + try + { + m_xResAccess.reset( new DAVResourceAccess( + rxSMgr, rSessionFactory, Identifier->getContentIdentifier() ) ); + } + catch ( DAVException const & ) + { + throw ucb::ContentCreationException(); + } + + // Do not set m_aEscapedTitle here! Content::insert relays on this!!! +} + +//========================================================================= +// virtual +Content::~Content() +{ +} + +//========================================================================= +// +// XInterface methods. +// +//========================================================================= + +// virtual +void SAL_CALL Content::acquire() + throw( ) +{ + ContentImplHelper::acquire(); +} + +//========================================================================= +// virtual +void SAL_CALL Content::release() + throw( ) +{ + ContentImplHelper::release(); +} + +//========================================================================= +// virtual +uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType ) + throw ( uno::RuntimeException ) +{ + // Note: isFolder may require network activities! So call it only + // if it is really necessary!!! + uno::Any aRet = cppu::queryInterface( + rType, + static_cast< ucb::XContentCreator * >( this ) ); + if ( aRet.hasValue() ) + { + try + { + uno::Reference< beans::XPropertySet > const xProps( + m_xSMgr, uno::UNO_QUERY_THROW ); + uno::Reference< uno::XComponentContext > xCtx; + xCtx.set( xProps->getPropertyValue( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ), + uno::UNO_QUERY_THROW ); + + uno::Reference< task::XInteractionHandler > xIH( + task::PasswordContainerInteractionHandler::create( xCtx ) ); + + // Supply a command env to isFolder() that contains an interaction + // handler that uses the password container service to obtain + // credentials without displaying a password gui. + + uno::Reference< ucb::XCommandEnvironment > xCmdEnv( + ucb::CommandEnvironment::create( + xCtx, + xIH, + uno::Reference< ucb::XProgressHandler >() ) ); + + return isFolder( xCmdEnv ) ? aRet : uno::Any(); + } + catch ( uno::RuntimeException const & ) + { + throw; + } + catch ( uno::Exception const & ) + { + return uno::Any(); + } + } + return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType ); +} + +//========================================================================= +// +// XTypeProvider methods. +// +//========================================================================= + +XTYPEPROVIDER_COMMON_IMPL( Content ); + +//========================================================================= +// virtual +uno::Sequence< uno::Type > SAL_CALL Content::getTypes() + throw( uno::RuntimeException ) +{ + sal_Bool bFolder = sal_False; + try + { + bFolder + = isFolder( uno::Reference< ucb::XCommandEnvironment >() ); + } + catch ( uno::RuntimeException const & ) + { + throw; + } + catch ( uno::Exception const & ) + { + } + + cppu::OTypeCollection * pCollection = 0; + + if ( bFolder ) + { + static cppu::OTypeCollection* pFolderTypes = 0; + + pCollection = pFolderTypes; + if ( !pCollection ) + { + osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); + + pCollection = pFolderTypes; + if ( !pCollection ) + { + static cppu::OTypeCollection aCollection( + CPPU_TYPE_REF( lang::XTypeProvider ), + CPPU_TYPE_REF( lang::XServiceInfo ), + CPPU_TYPE_REF( lang::XComponent ), + CPPU_TYPE_REF( ucb::XContent ), + CPPU_TYPE_REF( ucb::XCommandProcessor ), + CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ), + CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ), + CPPU_TYPE_REF( beans::XPropertyContainer ), + CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ), + CPPU_TYPE_REF( container::XChild ), + CPPU_TYPE_REF( ucb::XContentCreator ) ); // !! + pCollection = &aCollection; + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + pFolderTypes = pCollection; + } + } + else { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } + } + else + { + static cppu::OTypeCollection* pDocumentTypes = 0; + + pCollection = pDocumentTypes; + if ( !pCollection ) + { + osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); + + pCollection = pDocumentTypes; + if ( !pCollection ) + { + static cppu::OTypeCollection aCollection( + CPPU_TYPE_REF( lang::XTypeProvider ), + CPPU_TYPE_REF( lang::XServiceInfo ), + CPPU_TYPE_REF( lang::XComponent ), + CPPU_TYPE_REF( ucb::XContent ), + CPPU_TYPE_REF( ucb::XCommandProcessor ), + CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ), + CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ), + CPPU_TYPE_REF( beans::XPropertyContainer ), + CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ), + CPPU_TYPE_REF( container::XChild ) ); + pCollection = &aCollection; + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + pDocumentTypes = pCollection; + } + } + else { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } + } + + return (*pCollection).getTypes(); +} + +//========================================================================= +// +// XServiceInfo methods. +// +//========================================================================= + +// virtual +rtl::OUString SAL_CALL Content::getImplementationName() + throw( uno::RuntimeException ) +{ + return rtl::OUString::createFromAscii( + "com.sun.star.comp.ucb.WebDAVContent" ); +} + +//========================================================================= +// virtual +uno::Sequence< rtl::OUString > SAL_CALL Content::getSupportedServiceNames() + throw( uno::RuntimeException ) +{ + uno::Sequence< rtl::OUString > aSNS( 1 ); + aSNS.getArray()[ 0 ] + = rtl::OUString::createFromAscii( WEBDAV_CONTENT_SERVICE_NAME ); + return aSNS; +} + +//========================================================================= +// +// XContent methods. +// +//========================================================================= + +// virtual +rtl::OUString SAL_CALL Content::getContentType() + throw( uno::RuntimeException ) +{ + sal_Bool bFolder = sal_False; + try + { + bFolder + = isFolder( uno::Reference< ucb::XCommandEnvironment >() ); + } + catch ( uno::RuntimeException const & ) + { + throw; + } + catch ( uno::Exception const & ) + { + } + + if ( bFolder ) + return rtl::OUString::createFromAscii( WEBDAV_COLLECTION_TYPE ); + + return rtl::OUString::createFromAscii( WEBDAV_CONTENT_TYPE ); +} + +//========================================================================= +// +// XCommandProcessor methods. +// +//========================================================================= + +// virtual +uno::Any SAL_CALL Content::execute( + const ucb::Command& aCommand, + sal_Int32 /*CommandId*/, + const uno::Reference< ucb::XCommandEnvironment >& Environment ) + throw( uno::Exception, + ucb::CommandAbortedException, + uno::RuntimeException ) +{ + OSL_TRACE( ">>>>> Content::execute: start: command: %s, env: %s", + rtl::OUStringToOString( aCommand.Name, + RTL_TEXTENCODING_UTF8 ).getStr(), + Environment.is() ? "present" : "missing" ); + + uno::Any aRet; + + if ( aCommand.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ) ) + { + ////////////////////////////////////////////////////////////////// + // getPropertyValues + ////////////////////////////////////////////////////////////////// + + uno::Sequence< beans::Property > Properties; + if ( !( aCommand.Argument >>= Properties ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString::createFromAscii( + "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + aRet <<= getPropertyValues( Properties, Environment ); + } + else if ( aCommand.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ) ) + { + ////////////////////////////////////////////////////////////////// + // setPropertyValues + ////////////////////////////////////////////////////////////////// + + uno::Sequence< beans::PropertyValue > aProperties; + if ( !( aCommand.Argument >>= aProperties ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString::createFromAscii( + "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + if ( !aProperties.getLength() ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString::createFromAscii( + "No properties!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + aRet <<= setPropertyValues( aProperties, Environment ); + } + else if ( aCommand.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ) ) + { + ////////////////////////////////////////////////////////////////// + // getPropertySetInfo + ////////////////////////////////////////////////////////////////// + + // Note: Implemented by base class. + aRet <<= getPropertySetInfo( Environment, + sal_False /* don't cache data */ ); + } + else if ( aCommand.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ) ) + { + ////////////////////////////////////////////////////////////////// + // getCommandInfo + ////////////////////////////////////////////////////////////////// + + // Note: Implemented by base class. + aRet <<= getCommandInfo( Environment, sal_False ); + } + else if ( aCommand.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "open" ) ) ) + { + ////////////////////////////////////////////////////////////////// + // open + ////////////////////////////////////////////////////////////////// + + ucb::OpenCommandArgument2 aOpenCommand; + if ( !( aCommand.Argument >>= aOpenCommand ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString::createFromAscii( + "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + aRet = open( aOpenCommand, Environment ); + } + else if ( aCommand.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "insert" ) ) ) + { + ////////////////////////////////////////////////////////////////// + // insert + ////////////////////////////////////////////////////////////////// + + ucb::InsertCommandArgument arg; + if ( !( aCommand.Argument >>= arg ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString::createFromAscii( + "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + insert( arg.Data, arg.ReplaceExisting, Environment ); + } + else if ( aCommand.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "delete" ) ) ) + { + ////////////////////////////////////////////////////////////////// + // delete + ////////////////////////////////////////////////////////////////// + + sal_Bool bDeletePhysical = sal_False; + aCommand.Argument >>= bDeletePhysical; + +// KSO: Ignore parameter and destroy the content, if you don't support +// putting objects into trashcan. ( Since we do not have a trash can +// service yet (src603), you actually have no other choice. ) +// if ( bDeletePhysical ) +// { + try + { + std::auto_ptr< DAVResourceAccess > xResAccess; + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); + } + xResAccess->DESTROY( Environment ); + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); + } + } + catch ( DAVException const & e ) + { + cancelCommandExecution( e, Environment, sal_True ); + // Unreachable + } +// } + + // Propagate destruction. + destroy( bDeletePhysical ); + + // Remove own and all children's Additional Core Properties. + removeAdditionalPropertySet( sal_True ); + } + else if ( aCommand.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "transfer" ) ) + && isFolder( Environment ) ) + { + ////////////////////////////////////////////////////////////////// + // transfer + // ( Not available at documents ) + ////////////////////////////////////////////////////////////////// + + ucb::TransferInfo transferArgs; + if ( !( aCommand.Argument >>= transferArgs ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString::createFromAscii( + "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + transfer( transferArgs, Environment ); + } + else if ( aCommand.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "post" ) ) ) + { + ////////////////////////////////////////////////////////////////// + // post + ////////////////////////////////////////////////////////////////// + + ucb::PostCommandArgument2 aArg; + if ( !( aCommand.Argument >>= aArg ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString::createFromAscii( + "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + post( aArg, Environment ); + } + else if ( aCommand.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "lock" ) ) && + supportsExclusiveWriteLock( Environment ) ) + { + ////////////////////////////////////////////////////////////////// + // lock + ////////////////////////////////////////////////////////////////// + + lock( Environment ); + } + else if ( aCommand.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "unlock" ) ) && + supportsExclusiveWriteLock( Environment ) ) + { + ////////////////////////////////////////////////////////////////// + // unlock + ////////////////////////////////////////////////////////////////// + + unlock( Environment ); + } + else if ( aCommand.Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "createNewContent" ) ) && + isFolder( Environment ) ) + { + ////////////////////////////////////////////////////////////////// + // createNewContent + ////////////////////////////////////////////////////////////////// + + ucb::ContentInfo aArg; + if ( !( aCommand.Argument >>= aArg ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString::createFromAscii( + "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + aRet = uno::makeAny( createNewContent( aArg ) ); + } + else + { + ////////////////////////////////////////////////////////////////// + // Unsupported command + ////////////////////////////////////////////////////////////////// + + ucbhelper::cancelCommandExecution( + uno::makeAny( ucb::UnsupportedCommandException( + aCommand.Name, + static_cast< cppu::OWeakObject * >( this ) ) ), + Environment ); + // Unreachable + } + + OSL_TRACE( "<<<<< Content::execute: end: command: %s", + rtl::OUStringToOString( aCommand.Name, + RTL_TEXTENCODING_UTF8 ).getStr() ); + + return aRet; +} + +//========================================================================= +// virtual +void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ ) + throw( uno::RuntimeException ) +{ + try + { + std::auto_ptr< DAVResourceAccess > xResAccess; + { + osl::MutexGuard aGuard( m_aMutex ); + xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); + } + xResAccess->abort(); + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); + } + } + catch ( DAVException const & ) + { + // abort failed! + } +} + +//========================================================================= +// +// XPropertyContainer methods. +// +//========================================================================= + +// virtual +void SAL_CALL Content::addProperty( const rtl::OUString& Name, + sal_Int16 Attributes, + const uno::Any& DefaultValue ) + throw( beans::PropertyExistException, + beans::IllegalTypeException, + lang::IllegalArgumentException, + uno::RuntimeException ) +{ +// if ( m_bTransient ) +// @@@ ??? + + if ( !Name.getLength() ) + throw lang::IllegalArgumentException(); + + // Check property type. + if ( !UCBDeadPropertyValue::supportsType( DefaultValue.getValueType() ) ) + { + OSL_ENSURE( sal_False, + "Content::addProperty - Unsupported property type!" ); + throw beans::IllegalTypeException(); + } + + ////////////////////////////////////////////////////////////////////// + // 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< ucb::XCommandEnvironment > xEnv; + + // Note: This requires network access! + if ( getPropertySetInfo( xEnv, sal_False /* don't cache data */ ) + ->hasPropertyByName( Name ) ) + { + // Property does already exist. + throw beans::PropertyExistException(); + } + + ////////////////////////////////////////////////////////////////////// + // Add a new dynamic property. + ////////////////////////////////////////////////////////////////////// + + ProppatchValue aValue( PROPSET, Name, DefaultValue ); + + std::vector< ProppatchValue > aProppatchValues; + aProppatchValues.push_back( aValue ); + + try + { + // Set property value at server. + std::auto_ptr< DAVResourceAccess > xResAccess; + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); + } + xResAccess->PROPPATCH( aProppatchValues, xEnv ); + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); + } + + // Notify propertyset info change listeners. + beans::PropertySetInfoChangeEvent evt( + static_cast< cppu::OWeakObject * >( this ), + Name, + -1, // No handle available + beans::PropertySetInfoChange::PROPERTY_INSERTED ); + notifyPropertySetInfoChange( evt ); + } + catch ( DAVException const & e ) + { + if ( e.getStatus() == SC_FORBIDDEN ) + { + // Support for setting arbitrary dead properties is optional! + + // Store property locally. + ContentImplHelper::addProperty( + Name, Attributes, DefaultValue ); + } + else + { + if ( shouldAccessNetworkAfterException( e ) ) + { + try + { + const ResourceType & rType = getResourceType( xEnv ); + switch ( rType ) + { + case UNKNOWN: + case DAV: + throw lang::IllegalArgumentException(); + + case NON_DAV: + // Store property locally. + ContentImplHelper::addProperty( Name, + Attributes, + DefaultValue ); + break; + + default: + OSL_ENSURE( sal_False, + "Content::addProperty - " + "Unsupported resource type!" ); + break; + } + } + catch ( uno::Exception const & ) + { + OSL_ENSURE( sal_False, + "Content::addProperty - " + "Unable to determine resource type!" ); + } + } + else + { + OSL_ENSURE( sal_False, + "Content::addProperty - " + "Unable to determine resource type!" ); + } + } + } +} + +//========================================================================= +// virtual +void SAL_CALL Content::removeProperty( const rtl::OUString& Name ) + throw( beans::UnknownPropertyException, + beans::NotRemoveableException, + uno::RuntimeException ) +{ + // @@@ Need real command environment here, but where to get it from? + // XPropertyContainer interface should be replaced by + // XCommandProcessor commands! + uno::Reference< ucb::XCommandEnvironment > xEnv; + +#if 0 + // @@@ REMOVEABLE z.Z. nicht richtig an der PropSetInfo gesetzt!!! + try + { + beans::Property aProp + = getPropertySetInfo( xEnv, sal_False /* don't cache data */ ) + ->getPropertyByName( Name ); + + if ( !( aProp.Attributes & beans::PropertyAttribute::REMOVEABLE ) ) + { + // Not removeable! + throw beans::NotRemoveableException(); + } + } + catch ( beans::UnknownPropertyException const & ) + { + //OSL_ENSURE( sal_False, "removeProperty - Unknown property!" ); + throw; + } +#endif + + ////////////////////////////////////////////////////////////////////// + // Try to remove property from server. + ////////////////////////////////////////////////////////////////////// + + try + { + std::vector< ProppatchValue > aProppatchValues; + ProppatchValue aValue( PROPREMOVE, Name, uno::Any() ); + aProppatchValues.push_back( aValue ); + + // Remove property value from server. + std::auto_ptr< DAVResourceAccess > xResAccess; + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); + } + xResAccess->PROPPATCH( aProppatchValues, xEnv ); + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); + } + + // Notify propertyset info change listeners. + beans::PropertySetInfoChangeEvent evt( + static_cast< cppu::OWeakObject * >( this ), + Name, + -1, // No handle available + beans::PropertySetInfoChange::PROPERTY_REMOVED ); + notifyPropertySetInfoChange( evt ); + } + catch ( DAVException const & e ) + { + if ( e.getStatus() == SC_FORBIDDEN ) + { + // Support for setting arbitrary dead properties is optional! + + // Try to remove property from local store. + ContentImplHelper::removeProperty( Name ); + } + else + { + if ( shouldAccessNetworkAfterException( e ) ) + { + try + { + const ResourceType & rType = getResourceType( xEnv ); + switch ( rType ) + { + case UNKNOWN: + case DAV: + throw beans::UnknownPropertyException(); + + case NON_DAV: + // Try to remove property from local store. + ContentImplHelper::removeProperty( Name ); + break; + + default: + OSL_ENSURE( sal_False, + "Content::removeProperty - " + "Unsupported resource type!" ); + break; + } + } + catch ( uno::Exception const & ) + { + OSL_ENSURE( sal_False, + "Content::removeProperty - " + "Unable to determine resource type!" ); + } + } + else + { + OSL_ENSURE( sal_False, + "Content::removeProperty - " + "Unable to determine resource type!" ); +// throw beans::UnknownPropertyException(); + } + } + } +} + +//========================================================================= +// +// XContentCreator methods. +// +//========================================================================= + +// virtual +uno::Sequence< ucb::ContentInfo > SAL_CALL +Content::queryCreatableContentsInfo() + throw( uno::RuntimeException ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + uno::Sequence< ucb::ContentInfo > aSeq( 2 ); + + // document. + aSeq.getArray()[ 0 ].Type + = rtl::OUString::createFromAscii( WEBDAV_CONTENT_TYPE ); + aSeq.getArray()[ 0 ].Attributes + = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM + | ucb::ContentInfoAttribute::KIND_DOCUMENT; + + beans::Property aProp; + m_pProvider->getProperty( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ), aProp ); + + uno::Sequence< beans::Property > aDocProps( 1 ); + aDocProps.getArray()[ 0 ] = aProp; + aSeq.getArray()[ 0 ].Properties = aDocProps; + + // folder. + aSeq.getArray()[ 1 ].Type + = rtl::OUString::createFromAscii( WEBDAV_COLLECTION_TYPE ); + aSeq.getArray()[ 1 ].Attributes + = ucb::ContentInfoAttribute::KIND_FOLDER; + + uno::Sequence< beans::Property > aFolderProps( 1 ); + aFolderProps.getArray()[ 0 ] = aProp; + aSeq.getArray()[ 1 ].Properties = aFolderProps; + return aSeq; +} + +//========================================================================= +// virtual +uno::Reference< ucb::XContent > SAL_CALL +Content::createNewContent( const ucb::ContentInfo& Info ) + throw( uno::RuntimeException ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + if ( !Info.Type.getLength() ) + return uno::Reference< ucb::XContent >(); + + if ( ( !Info.Type.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( WEBDAV_COLLECTION_TYPE ) ) ) + && + ( !Info.Type.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( WEBDAV_CONTENT_TYPE ) ) ) ) + return uno::Reference< ucb::XContent >(); + + rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); + + OSL_ENSURE( aURL.getLength() > 0, + "WebdavContent::createNewContent - empty identifier!" ); + + if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() ) + aURL += rtl::OUString::createFromAscii( "/" ); + + sal_Bool isCollection; + if ( Info.Type.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( WEBDAV_COLLECTION_TYPE ) ) ) + { + aURL += rtl::OUString::createFromAscii( "New_Collection" ); + isCollection = sal_True; + } + else + { + aURL += rtl::OUString::createFromAscii( "New_Content" ); + isCollection = sal_False; + } + + uno::Reference< ucb::XContentIdentifier > xId( + new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ) ); + + // create the local content + try + { + return new ::http_dav_ucp::Content( m_xSMgr, + m_pProvider, + xId, + m_xResAccess->getSessionFactory(), + isCollection ); + } + catch ( ucb::ContentCreationException & ) + { + return uno::Reference< ucb::XContent >(); + } +} + +//========================================================================= +// virtual +rtl::OUString Content::getParentURL() +{ + // :// -> "" + // ://foo -> "" + // ://foo/ -> "" + // ://foo/bar -> ://foo/ + // ://foo/bar/ -> ://foo/ + // ://foo/bar/abc -> ://foo/bar/ + + rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); + + sal_Int32 nPos = aURL.lastIndexOf( '/' ); + if ( nPos == ( aURL.getLength() - 1 ) ) + { + // Trailing slash found. Skip. + nPos = aURL.lastIndexOf( '/', nPos ); + } + + sal_Int32 nPos1 = aURL.lastIndexOf( '/', nPos ); + if ( nPos1 != -1 ) + nPos1 = aURL.lastIndexOf( '/', nPos1 ); + + if ( nPos1 == -1 ) + return rtl::OUString(); + + return rtl::OUString( aURL.copy( 0, nPos + 1 ) ); +} + +//========================================================================= +// +// Non-interface methods. +// +//========================================================================= + +// static +uno::Reference< sdbc::XRow > Content::getPropertyValues( + const uno::Reference< lang::XMultiServiceFactory >& rSMgr, + const uno::Sequence< beans::Property >& rProperties, + const ContentProperties& rData, + const rtl::Reference< ::ucbhelper::ContentProviderImplHelper >& rProvider, + const rtl::OUString& rContentId ) +{ + // Note: Empty sequence means "get values of all supported properties". + + rtl::Reference< ::ucbhelper::PropertyValueSet > xRow + = new ::ucbhelper::PropertyValueSet( rSMgr ); + + sal_Int32 nCount = rProperties.getLength(); + if ( nCount ) + { + uno::Reference< beans::XPropertySet > xAdditionalPropSet; + sal_Bool bTriedToGetAdditonalPropSet = sal_False; + + const beans::Property* pProps = rProperties.getConstArray(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const beans::Property& rProp = pProps[ n ]; + + // Process standard UCB, DAV and HTTP properties. + const uno::Any & rValue = rData.getValue( rProp.Name ); + if ( rValue.hasValue() ) + { + xRow->appendObject( rProp, rValue ); + } + else + { + // Process local Additional Properties. + if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() ) + { + xAdditionalPropSet + = uno::Reference< beans::XPropertySet >( + rProvider->getAdditionalPropertySet( rContentId, + sal_False ), + uno::UNO_QUERY ); + bTriedToGetAdditonalPropSet = sal_True; + } + + if ( !xAdditionalPropSet.is() || + !xRow->appendPropertySetValue( + xAdditionalPropSet, rProp ) ) + { + // Append empty entry. + xRow->appendVoid( rProp ); + } + } + } + } + else + { + // Append all standard UCB, DAV and HTTP properties. + + const std::auto_ptr< PropertyValueMap > & xProps = rData.getProperties(); + + PropertyValueMap::const_iterator it = xProps->begin(); + PropertyValueMap::const_iterator end = xProps->end(); + + ContentProvider * pProvider + = static_cast< ContentProvider * >( rProvider.get() ); + beans::Property aProp; + + while ( it != end ) + { + if ( pProvider->getProperty( (*it).first, aProp ) ) + xRow->appendObject( aProp, (*it).second.value() ); + + ++it; + } + + // Append all local Additional Properties. + uno::Reference< beans::XPropertySet > xSet( + rProvider->getAdditionalPropertySet( rContentId, sal_False ), + uno::UNO_QUERY ); + xRow->appendPropertySet( xSet ); + } + + return uno::Reference< sdbc::XRow >( xRow.get() ); +} + +//========================================================================= +uno::Reference< sdbc::XRow > Content::getPropertyValues( + const uno::Sequence< beans::Property >& rProperties, + const uno::Reference< ucb::XCommandEnvironment >& xEnv ) + throw ( uno::Exception ) +{ + std::auto_ptr< ContentProperties > xProps; + std::auto_ptr< ContentProperties > xCachedProps; + std::auto_ptr< DAVResourceAccess > xResAccess; + rtl::OUString aUnescapedTitle; + bool bHasAll = false; + uno::Reference< lang::XMultiServiceFactory > xSMgr; + uno::Reference< ucb::XContentIdentifier > xIdentifier; + rtl::Reference< ::ucbhelper::ContentProviderImplHelper > xProvider; + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + aUnescapedTitle = SerfUri::unescape( m_aEscapedTitle ); + xSMgr.set( m_xSMgr ); + xIdentifier.set( m_xIdentifier ); + xProvider.set( m_xProvider.get() ); + xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); + + // First, ask cache... + if ( m_xCachedProps.get() ) + { + xCachedProps.reset( new ContentProperties( *m_xCachedProps.get() ) ); + + std::vector< rtl::OUString > aMissingProps; + if ( xCachedProps->containsAllNames( rProperties, aMissingProps ) ) + { + // All properties are already in cache! No server access needed. + bHasAll = true; + } + + // use the cached ContentProperties instance + xProps.reset( new ContentProperties( *xCachedProps.get() ) ); + } + } + + if ( !m_bTransient && !bHasAll ) + { + ///////////////////////////////////////////////////////////////////// + // Obtain values from server... + ///////////////////////////////////////////////////////////////////// + + // First, identify whether resource is DAV or not + const ResourceType & rType = getResourceType( xEnv, xResAccess ); + + bool bNetworkAccessAllowed = true; + + if ( DAV == rType ) + { + // cache lookup... getResourceType may fill the props cache via + // PROPFIND! + if ( m_xCachedProps.get() ) + { + xCachedProps.reset( + new ContentProperties( *m_xCachedProps.get() ) ); + + std::vector< rtl::OUString > aMissingProps; + if ( xCachedProps->containsAllNames( + rProperties, aMissingProps ) ) + { + // All properties are already in cache! No server access + // needed. + bHasAll = true; + } + + // use the cached ContentProperties instance + xProps.reset( new ContentProperties( *xCachedProps.get() ) ); + } + + if ( !bHasAll ) + { + // Only DAV resources support PROPFIND + std::vector< rtl::OUString > aPropNames; + + uno::Sequence< beans::Property > aProperties( + rProperties.getLength() ); + + if ( m_aFailedPropNames.size() > 0 ) + { + sal_Int32 nProps = 0; + sal_Int32 nCount = rProperties.getLength(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const rtl::OUString & rName = rProperties[ n ].Name; + + std::vector< rtl::OUString >::const_iterator it + = m_aFailedPropNames.begin(); + std::vector< rtl::OUString >::const_iterator end + = m_aFailedPropNames.end(); + + while ( it != end ) + { + if ( *it == rName ) + break; + + ++it; + } + + if ( it == end ) + { + aProperties[ nProps ] = rProperties[ n ]; + nProps++; + } + } + + aProperties.realloc( nProps ); + } + else + { + aProperties = rProperties; + } + + if ( aProperties.getLength() > 0 ) + ContentProperties::UCBNamesToDAVNames( + aProperties, aPropNames ); + + if ( aPropNames.size() > 0 ) + { + std::vector< DAVResource > resources; + try + { + xResAccess->PROPFIND( + DAVZERO, aPropNames, resources, xEnv ); + + if ( 1 == resources.size() ) + { + if ( xProps.get()) + xProps->addProperties( + aPropNames, + ContentProperties( resources[ 0 ] )); + else + xProps.reset( + new ContentProperties( resources[ 0 ] ) ); + } + } + catch ( DAVException const & e ) + { + bNetworkAccessAllowed + = shouldAccessNetworkAfterException( e ); + + if ( !bNetworkAccessAllowed ) + { + cancelCommandExecution( e, xEnv ); + // unreachable + } + } + } + } + } + + if ( bNetworkAccessAllowed ) + { + // All properties obtained already? + std::vector< rtl::OUString > aMissingProps; + if ( !( xProps.get() + && xProps->containsAllNames( + rProperties, aMissingProps ) ) + && !m_bDidGetOrHead ) + { + // Possibly the missing props can be obtained using a HEAD + // request. + + std::vector< rtl::OUString > aHeaderNames; + ContentProperties::UCBNamesToHTTPNames( + rProperties, + aHeaderNames, + true /* bIncludeUnmatched */ ); + + if ( aHeaderNames.size() > 0 ) + { + try + { + DAVResource resource; + xResAccess->HEAD( aHeaderNames, resource, xEnv ); + m_bDidGetOrHead = true; + + if ( xProps.get() ) + xProps->addProperties( + aMissingProps, + ContentProperties( resource ) ); + else + xProps.reset ( new ContentProperties( resource ) ); + + if ( m_eResourceType == NON_DAV ) + xProps->addProperties( aMissingProps, + ContentProperties( + aUnescapedTitle, + false ) ); + } + catch ( DAVException const & e ) + { + bNetworkAccessAllowed + = shouldAccessNetworkAfterException( e ); + + if ( !bNetworkAccessAllowed ) + { + cancelCommandExecution( e, xEnv ); + // unreachable + } + } + } + } + } + + // might trigger HTTP redirect. + // Therefore, title must be updated here. + SerfUri aUri( xResAccess->getURL() ); + aUnescapedTitle = aUri.GetPathBaseNameUnescaped(); + + if ( rType == UNKNOWN ) + { + xProps.reset( new ContentProperties( aUnescapedTitle ) ); + } + + // For DAV resources we only know the Title, for non-DAV + // resources we additionally know that it is a document. + + if ( rType == DAV ) + { + //xProps.reset( + // new ContentProperties( aUnescapedTitle ) ); + xProps->addProperty( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ), + uno::makeAny( aUnescapedTitle ), + true ); + } + else + { + if ( !xProps.get() ) + xProps.reset( new ContentProperties( aUnescapedTitle, false ) ); + else + xProps->addProperty( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ), + uno::makeAny( aUnescapedTitle ), + true ); + + xProps->addProperty( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ), + uno::makeAny( false ), + true ); + xProps->addProperty( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ), + uno::makeAny( true ), + true ); + } + } + else + { + // No server access for just created (not yet committed) objects. + // Only a minimal set of properties supported at this stage. + if (m_bTransient) + xProps.reset( new ContentProperties( aUnescapedTitle, + m_bCollection ) ); + } + + sal_Int32 nCount = rProperties.getLength(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const rtl::OUString rName = rProperties[ n ].Name; + if ( rName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "BaseURI" ) ) ) + { + // Add BaseURI property, if requested. + xProps->addProperty( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseURI" ) ), + uno::makeAny( getBaseURI( xResAccess ) ), + true ); + } + else if ( rName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) ) + { + // Add CreatableContentsInfo property, if requested. + sal_Bool bFolder = sal_False; + xProps->getValue( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ) ) + >>= bFolder; + xProps->addProperty( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "CreatableContentsInfo" ) ), + uno::makeAny( bFolder + ? queryCreatableContentsInfo() + : uno::Sequence< ucb::ContentInfo >() ), + true ); + } + } + + uno::Reference< sdbc::XRow > xResultRow + = getPropertyValues( xSMgr, + rProperties, + *xProps, + xProvider, + xIdentifier->getContentIdentifier() ); + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + if ( !m_xCachedProps.get() ) + m_xCachedProps.reset( new CachableContentProperties( *xProps.get() ) ); + else + m_xCachedProps->addProperties( *xProps.get() ); + + m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); + m_aEscapedTitle = SerfUri::escapeSegment( aUnescapedTitle ); + } + + return xResultRow; +} + +//========================================================================= +uno::Sequence< uno::Any > Content::setPropertyValues( + const uno::Sequence< beans::PropertyValue >& rValues, + const uno::Reference< ucb::XCommandEnvironment >& xEnv ) + throw ( uno::Exception ) +{ + uno::Reference< lang::XMultiServiceFactory > xSMgr; + uno::Reference< ucb::XContentIdentifier > xIdentifier; + rtl::Reference< ContentProvider > xProvider; + sal_Bool bTransient; + std::auto_ptr< DAVResourceAccess > xResAccess; + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + xProvider.set( m_pProvider ); + xIdentifier.set( m_xIdentifier ); + bTransient = m_bTransient; + xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); + xSMgr.set( m_xSMgr ); + } + + uno::Sequence< uno::Any > aRet( rValues.getLength() ); + uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() ); + sal_Int32 nChanged = 0; + + beans::PropertyChangeEvent aEvent; + aEvent.Source = static_cast< cppu::OWeakObject * >( this ); + aEvent.Further = sal_False; + // aEvent.PropertyName = + aEvent.PropertyHandle = -1; + // aEvent.OldValue = + // aEvent.NewValue = + + std::vector< ProppatchValue > aProppatchValues; + std::vector< sal_Int32 > aProppatchPropsPositions; + + uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet; + sal_Bool bTriedToGetAdditonalPropSet = sal_False; + + sal_Bool bExchange = sal_False; + rtl::OUString aNewTitle; + rtl::OUString aOldTitle; + sal_Int32 nTitlePos = -1; + + uno::Reference< beans::XPropertySetInfo > xInfo; + + const beans::PropertyValue* pValues = rValues.getConstArray(); + sal_Int32 nCount = rValues.getLength(); + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + const beans::PropertyValue& rValue = pValues[ n ]; + const rtl::OUString & rName = rValue.Name; + + beans::Property aTmpProp; + xProvider->getProperty( rName, aTmpProp ); + + if ( aTmpProp.Attributes & beans::PropertyAttribute::READONLY ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString::createFromAscii( + "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + continue; + } + + ////////////////////////////////////////////////////////////////// + // Mandatory props. + ////////////////////////////////////////////////////////////////// + + if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString::createFromAscii( + "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString::createFromAscii( + "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString::createFromAscii( + "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) + { + rtl::OUString aNewValue; + if ( rValue.Value >>= aNewValue ) + { + // No empty titles! + if ( aNewValue.getLength() > 0 ) + { + try + { + SerfUri aURI( xIdentifier->getContentIdentifier() ); + aOldTitle = aURI.GetPathBaseNameUnescaped(); + + if ( aNewValue != aOldTitle ) + { + // modified title -> modified URL -> exchange ! + if ( !bTransient ) + bExchange = sal_True; + + // new value will be set later... + aNewTitle = aNewValue; + + // remember position within sequence of values (for + // error handling). + nTitlePos = n; + } + } + catch ( DAVException const & ) + { + aRet[ n ] <<= lang::IllegalArgumentException( + rtl::OUString::createFromAscii( + "Invalid content identifier!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ); + } + } + else + { + aRet[ n ] <<= lang::IllegalArgumentException( + rtl::OUString::createFromAscii( + "Empty title not allowed!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ); + } + } + else + { + aRet[ n ] <<= beans::IllegalTypeException( + rtl::OUString::createFromAscii( + "Property value has wrong type!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + } + else + { + ////////////////////////////////////////////////////////////// + // Optional props. + ////////////////////////////////////////////////////////////// + + if ( !xInfo.is() ) + xInfo = getPropertySetInfo( xEnv, + sal_False /* don't cache data */ ); + + if ( !xInfo->hasPropertyByName( rName ) ) + { + // Check, whether property exists. Skip otherwise. + // PROPPATCH::set would add the property automatically, which + // is not allowed for "setPropertyValues" command! + aRet[ n ] <<= beans::UnknownPropertyException( + rtl::OUString::createFromAscii( + "Property is unknown!" ), + static_cast< cppu::OWeakObject * >( this ) ); + continue; + } + + if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString::createFromAscii( + "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString::createFromAscii( + "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString::createFromAscii( + "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ) + { + // Read-only property! + // (but could be writable, if 'getcontenttype' would be) + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString::createFromAscii( + "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + if ( rName.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString::createFromAscii( + "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else + { + if ( getResourceType( xEnv, xResAccess ) == DAV ) + { + // Property value will be set on server. + ProppatchValue aValue( PROPSET, rName, rValue.Value ); + aProppatchValues.push_back( aValue ); + + // remember position within sequence of values (for + // error handling). + aProppatchPropsPositions.push_back( n ); + } + else + { + // Property value will be stored in local property store. + if ( !bTriedToGetAdditonalPropSet && + !xAdditionalPropSet.is() ) + { + xAdditionalPropSet + = getAdditionalPropertySet( sal_False ); + bTriedToGetAdditonalPropSet = sal_True; + } + + if ( xAdditionalPropSet.is() ) + { + try + { + uno::Any aOldValue + = xAdditionalPropSet->getPropertyValue( rName ); + if ( aOldValue != rValue.Value ) + { + xAdditionalPropSet->setPropertyValue( + rName, rValue.Value ); + + aEvent.PropertyName = rName; + aEvent.OldValue = aOldValue; + aEvent.NewValue = rValue.Value; + + aChanges.getArray()[ nChanged ] = aEvent; + nChanged++; + } + } + catch ( beans::UnknownPropertyException const & e ) + { + aRet[ n ] <<= e; + } + catch ( lang::WrappedTargetException const & e ) + { + aRet[ n ] <<= e; + } + catch ( beans::PropertyVetoException const & e ) + { + aRet[ n ] <<= e; + } + catch ( lang::IllegalArgumentException const & e ) + { + aRet[ n ] <<= e; + } + } + else + { + aRet[ n ] <<= uno::Exception( + rtl::OUString::createFromAscii( + "No property set for storing the value!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + } + } + } + } // for + + if ( !bTransient && aProppatchValues.size() ) + { + try + { + // Set property values at server. + xResAccess->PROPPATCH( aProppatchValues, xEnv ); + + std::vector< ProppatchValue >::const_iterator it + = aProppatchValues.begin(); + std::vector< ProppatchValue >::const_iterator end + = aProppatchValues.end(); + + while ( it != end ) + { + aEvent.PropertyName = (*it).name; + aEvent.OldValue = uno::Any(); // @@@ to expensive to obtain! + aEvent.NewValue = (*it).value; + + aChanges.getArray()[ nChanged ] = aEvent; + nChanged++; + + ++it; + } + } + catch ( DAVException const & e ) + { +// OSL_ENSURE( sal_False, +// "Content::setPropertyValues - PROPPATCH failed!" ); + +#if 1 + cancelCommandExecution( e, xEnv ); + // unreachable +#else + // Note: PROPPATCH either sets ALL property values OR NOTHING. + + std::vector< sal_Int32 >::const_iterator it + = aProppatchPropsPositions.begin(); + std::vector< sal_Int32 >::const_iterator end + = aProppatchPropsPositions.end(); + + while ( it != end ) + { + // Set error. + aRet[ (*it) ] <<= MapDAVException( e, sal_True ); + ++it; + } +#endif + } + } + + if ( bExchange ) + { + // Assemble new content identifier... + + rtl::OUString aNewURL = getParentURL(); + if ( aNewURL.lastIndexOf( '/' ) != ( aNewURL.getLength() - 1 ) ) + aNewURL += rtl::OUString::createFromAscii( "/" ); + + aNewURL += SerfUri::escapeSegment( aNewTitle ); + + uno::Reference< ucb::XContentIdentifier > xNewId + = new ::ucbhelper::ContentIdentifier( xSMgr, aNewURL ); + uno::Reference< ucb::XContentIdentifier > xOldId = xIdentifier; + + try + { + SerfUri sourceURI( xOldId->getContentIdentifier() ); + SerfUri targetURI( xNewId->getContentIdentifier() ); + targetURI.SetScheme( sourceURI.GetScheme() ); + + xResAccess->MOVE( + sourceURI.GetPath(), targetURI.GetURI(), sal_False, xEnv ); + // @@@ Should check for resources that could not be moved + // (due to source access or target overwrite) and send + // this information through the interaction handler. + + // @@@ Existing content should be checked to see if it needs + // to be deleted at the source + + // @@@ Existing content should be checked to see if it has + // been overwritten at the target + + if ( exchangeIdentity( xNewId ) ) + { + xResAccess->setURL( aNewURL ); + +// DAV resources store all additional props on server! +// // Adapt Additional Core Properties. +// renameAdditionalPropertySet( xOldId->getContentIdentifier(), +// xNewId->getContentIdentifier(), +// sal_True ); + } + else + { + // Do not set new title! + aNewTitle = rtl::OUString(); + + // Set error . + aRet[ nTitlePos ] <<= uno::Exception( + rtl::OUString::createFromAscii( "Exchange failed!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + } + catch ( DAVException const & e ) + { + // Do not set new title! + aNewTitle = rtl::OUString(); + + // Set error . + aRet[ nTitlePos ] <<= MapDAVException( e, sal_True ); + } + } + + if ( aNewTitle.getLength() ) + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" ); + aEvent.OldValue = uno::makeAny( aOldTitle ); + aEvent.NewValue = uno::makeAny( aNewTitle ); + + m_aEscapedTitle = SerfUri::escapeSegment( aNewTitle ); + + aChanges.getArray()[ nChanged ] = aEvent; + nChanged++; + } + + if ( nChanged > 0 ) + { + aChanges.realloc( nChanged ); + notifyPropertiesChange( aChanges ); + } + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); + } + + return aRet; +} + +//========================================================================= +uno::Any Content::open( + const ucb::OpenCommandArgument2 & rArg, + const uno::Reference< ucb::XCommandEnvironment > & xEnv ) + throw( uno::Exception ) +{ + uno::Any aRet; + + sal_Bool bOpenFolder = ( ( rArg.Mode == ucb::OpenMode::ALL ) || + ( rArg.Mode == ucb::OpenMode::FOLDERS ) || + ( rArg.Mode == ucb::OpenMode::DOCUMENTS ) ); + if ( bOpenFolder ) + { + if ( isFolder( xEnv ) ) + { + // Open collection. + + uno::Reference< ucb::XDynamicResultSet > xSet + = new DynamicResultSet( m_xSMgr, this, rArg, xEnv ); + aRet <<= xSet; + } + else + { + // Error: Not a folder! + + rtl::OUStringBuffer aMsg; + aMsg.appendAscii( "Non-folder resource cannot be " + "opened as folder! Wrong Open Mode!" ); + + ucbhelper::cancelCommandExecution( + uno::makeAny( + lang::IllegalArgumentException( + aMsg.makeStringAndClear(), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + xEnv ); + // Unreachable + } + } + + if ( rArg.Sink.is() ) + { + // Open document. + + if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) || + ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) ) + { + // Currently(?) unsupported. + ucbhelper::cancelCommandExecution( + uno::makeAny( + ucb::UnsupportedOpenModeException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + sal_Int16( rArg.Mode ) ) ), + xEnv ); + // Unreachable + } + + rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); + uno::Reference< io::XOutputStream > xOut + = uno::Reference< io::XOutputStream >( rArg.Sink, uno::UNO_QUERY ); + if ( xOut.is() ) + { + // PUSH: write data + try + { + std::auto_ptr< DAVResourceAccess > xResAccess; + + { + osl::MutexGuard aGuard( m_aMutex ); + + xResAccess.reset( + new DAVResourceAccess( *m_xResAccess.get() ) ); + } + + DAVResource aResource; + std::vector< rtl::OUString > aHeaders; + + xResAccess->GET( xOut, aHeaders, aResource, xEnv ); + m_bDidGetOrHead = true; + + { + osl::MutexGuard aGuard( m_aMutex ); + + // cache headers. + if ( !m_xCachedProps.get()) + m_xCachedProps.reset( + new CachableContentProperties( aResource ) ); + else + m_xCachedProps->addProperties( aResource ); + + m_xResAccess.reset( + new DAVResourceAccess( *xResAccess.get() ) ); + } + } + catch ( DAVException const & e ) + { + cancelCommandExecution( e, xEnv ); + // Unreachable + } + } + else + { + uno::Reference< io::XActiveDataSink > xDataSink + = uno::Reference< io::XActiveDataSink >( rArg.Sink, + uno::UNO_QUERY ); + if ( xDataSink.is() ) + { + // PULL: wait for client read + try + { + std::auto_ptr< DAVResourceAccess > xResAccess; + { + osl::MutexGuard aGuard( m_aMutex ); + + xResAccess.reset( + new DAVResourceAccess( *m_xResAccess.get() ) ); + } + + // fill inputsream sync; return if all data present + DAVResource aResource; + std::vector< rtl::OUString > aHeaders; + + uno::Reference< io::XInputStream > xIn + = xResAccess->GET( aHeaders, aResource, xEnv ); + m_bDidGetOrHead = true; + + { + osl::MutexGuard aGuard( m_aMutex ); + + // cache headers. + if ( !m_xCachedProps.get()) + m_xCachedProps.reset( + new CachableContentProperties( aResource ) ); + else + m_xCachedProps->addProperties( + aResource.properties ); + + m_xResAccess.reset( + new DAVResourceAccess( *xResAccess.get() ) ); + } + + xDataSink->setInputStream( xIn ); + } + catch ( DAVException const & e ) + { + cancelCommandExecution( e, xEnv ); + // Unreachable + } + } + else + { + // Note: aOpenCommand.Sink may contain an XStream + // implementation. Support for this type of + // sink is optional... + ucbhelper::cancelCommandExecution( + uno::makeAny( + ucb::UnsupportedDataSinkException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + rArg.Sink ) ), + xEnv ); + // Unreachable + } + } + } + + return aRet; +} + +//========================================================================= +void Content::post( + const ucb::PostCommandArgument2 & rArg, + const uno::Reference< ucb::XCommandEnvironment > & xEnv ) + throw( uno::Exception ) +{ + uno::Reference< io::XActiveDataSink > xSink( rArg.Sink, uno::UNO_QUERY ); + if ( xSink.is() ) + { + try + { + std::auto_ptr< DAVResourceAccess > xResAccess; + { + osl::MutexGuard aGuard( m_aMutex ); + xResAccess.reset( + new DAVResourceAccess( *m_xResAccess.get() ) ); + } + + uno::Reference< io::XInputStream > xResult + = xResAccess->POST( rArg.MediaType, + rArg.Referer, + rArg.Source, + xEnv ); + + { + osl::MutexGuard aGuard( m_aMutex ); + m_xResAccess.reset( + new DAVResourceAccess( *xResAccess.get() ) ); + } + + xSink->setInputStream( xResult ); + } + catch ( DAVException const & e ) + { + cancelCommandExecution( e, xEnv, sal_True ); + // Unreachable + } + } + else + { + uno::Reference< io::XOutputStream > xResult( rArg.Sink, uno::UNO_QUERY ); + if ( xResult.is() ) + { + try + { + std::auto_ptr< DAVResourceAccess > xResAccess; + { + osl::MutexGuard aGuard( m_aMutex ); + xResAccess.reset( + new DAVResourceAccess( *m_xResAccess.get() ) ); + } + + xResAccess->POST( rArg.MediaType, + rArg.Referer, + rArg.Source, + xResult, + xEnv ); + + { + osl::MutexGuard aGuard( m_aMutex ); + m_xResAccess.reset( + new DAVResourceAccess( *xResAccess.get() ) ); + } + } + catch ( DAVException const & e ) + { + cancelCommandExecution( e, xEnv, sal_True ); + // Unreachable + } + } + else + { + ucbhelper::cancelCommandExecution( + uno::makeAny( + ucb::UnsupportedDataSinkException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + rArg.Sink ) ), + xEnv ); + // Unreachable + } + } +} + +//========================================================================= +void Content::queryChildren( ContentRefList& rChildren ) +{ + // Obtain a list with a snapshot of all currently instanciated contents + // from provider and extract the contents which are direct children + // of this content. + + ::ucbhelper::ContentRefList aAllContents; + m_xProvider->queryExistingContents( aAllContents ); + + rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); + sal_Int32 nURLPos = aURL.lastIndexOf( '/' ); + + if ( nURLPos != ( aURL.getLength() - 1 ) ) + { + // No trailing slash found. Append. + aURL += rtl::OUString::createFromAscii( "/" ); + } + + sal_Int32 nLen = aURL.getLength(); + + ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin(); + ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end(); + + while ( it != end ) + { + ::ucbhelper::ContentImplHelperRef xChild = (*it); + rtl::OUString aChildURL + = xChild->getIdentifier()->getContentIdentifier(); + + // Is aURL a prefix of aChildURL? + if ( ( aChildURL.getLength() > nLen ) && + ( aChildURL.compareTo( aURL, nLen ) == 0 ) ) + { + sal_Int32 nPos = nLen; + nPos = aChildURL.indexOf( '/', nPos ); + + if ( ( nPos == -1 ) || + ( nPos == ( aChildURL.getLength() - 1 ) ) ) + { + // No further slashes / only a final slash. It's a child! + rChildren.push_back( + ::http_dav_ucp::Content::ContentRef( + static_cast< ::http_dav_ucp::Content * >( + xChild.get() ) ) ); + } + } + ++it; + } +} + +//========================================================================= +void Content::insert( + const uno::Reference< io::XInputStream > & xInputStream, + sal_Bool bReplaceExisting, + const uno::Reference< ucb::XCommandEnvironment >& Environment ) + throw( uno::Exception ) +{ + sal_Bool bTransient, bCollection; + rtl::OUString aEscapedTitle; + std::auto_ptr< DAVResourceAccess > xResAccess; + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + bTransient = m_bTransient; + bCollection = m_bCollection; + aEscapedTitle = m_aEscapedTitle; + xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); + } + + // Check, if all required properties are present. + + if ( aEscapedTitle.getLength() == 0 ) + { + OSL_ENSURE( sal_False, "Content::insert - Title missing!" ); + + uno::Sequence< rtl::OUString > aProps( 1 ); + aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" ); + ucbhelper::cancelCommandExecution( + uno::makeAny( ucb::MissingPropertiesException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + aProps ) ), + Environment ); + // Unreachable + } + + if ( !bReplaceExisting ) + { + /* [RFC 2616] - HTTP + + The PUT method requests that the enclosed entity be stored under the + supplied Request-URI. If the Request-URI refers to an already + existing resource, the enclosed entity SHOULD be considered as a + modified version of the one residing on the origin server. + */ + + /* [RFC 2518] - WebDAV + + MKCOL creates a new collection resource at the location specified by + the Request-URI. If the resource identified by the Request-URI is + non-null then the MKCOL MUST fail. + */ + + // ==> Complain on PUT, continue on MKCOL. + if ( !bTransient || ( bTransient && !bCollection ) ) + { +#undef ERROR + ucb::UnsupportedNameClashException aEx( + rtl::OUString::createFromAscii( "Unable to write without overwrite!" ), + static_cast< cppu::OWeakObject * >( this ), + ucb::NameClash::ERROR ); + + uno::Reference< task::XInteractionHandler > xIH; + + if ( Environment.is() ) + xIH = Environment->getInteractionHandler(); + + if ( xIH.is() ) + { + uno::Any aExAsAny( uno::makeAny( aEx ) ); + + rtl::Reference< ucbhelper::SimpleInteractionRequest > xRequest + = new ucbhelper::SimpleInteractionRequest( + aExAsAny, + ucbhelper::CONTINUATION_APPROVE + | ucbhelper::CONTINUATION_DISAPPROVE ); + xIH->handle( xRequest.get() ); + + const sal_Int32 nResp = xRequest->getResponse(); + + switch ( nResp ) + { + case ucbhelper::CONTINUATION_UNKNOWN: + // Not handled; throw. + throw aEx; +// break; + + case ucbhelper::CONTINUATION_APPROVE: + // Continue -> Overwrite. + bReplaceExisting = sal_True; + break; + + case ucbhelper::CONTINUATION_DISAPPROVE: + // Abort. + throw ucb::CommandFailedException( + rtl::OUString(), + uno::Reference< uno::XInterface >(), + aExAsAny ); +// break; + + default: + OSL_ENSURE( sal_False, + "Content::insert - " + "Unknown interaction selection!" ); + throw ucb::CommandFailedException( + rtl::OUString::createFromAscii( + "Unknown interaction selection!" ), + uno::Reference< uno::XInterface >(), + aExAsAny ); +// break; + } + } + else + { + // No IH; throw. + throw aEx; + } + } + } + + if ( bTransient ) + { + // Assemble new content identifier... + rtl::OUString aURL = getParentURL(); + if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) ) + aURL += rtl::OUString::createFromAscii( "/" ); + + aURL += aEscapedTitle; + + try + { + xResAccess->setURL( aURL ); + + if ( bCollection ) + xResAccess->MKCOL( Environment ); + else + xResAccess->PUT( xInputStream, Environment ); + } + catch ( DAVException const & except ) + { + if ( bCollection ) + { + if ( except.getStatus() == SC_METHOD_NOT_ALLOWED ) + { + // [RFC 2518] - WebDAV + // 405 (Method Not Allowed) - MKCOL can only be + // executed on a deleted/non-existent resource. + + if ( bReplaceExisting ) + { + // Destroy old resource. + try + { + xResAccess->DESTROY( Environment ); + } + catch ( DAVException const & e ) + { + cancelCommandExecution( e, Environment, sal_True ); + // Unreachable + } + + // Insert (recursion!). + insert( xInputStream, bReplaceExisting, Environment ); + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_xResAccess.reset( + new DAVResourceAccess( *xResAccess.get() ) ); + } + + // Success! + return; + } + else + { + rtl::OUString aTitle; + try + { + SerfUri aURI( aURL ); + aTitle = aURI.GetPathBaseNameUnescaped(); + } + catch ( DAVException const & ) + { + } + + ucbhelper::cancelCommandExecution( + uno::makeAny( + ucb::NameClashException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + aTitle ) ), + Environment ); + // Unreachable + } + } + } + + cancelCommandExecution( except, Environment, sal_True ); + // Unreachable + } + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_xIdentifier + = new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ); + } + + inserted(); + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_bTransient = sal_False; + } + } + else + { + if ( !xInputStream.is() ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( + ucb::MissingInputStreamException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ) ) ), + Environment ); + // Unreachable + } + + try + { + xResAccess->PUT( xInputStream, Environment ); + } + catch ( DAVException const & e ) + { + cancelCommandExecution( e, Environment, sal_True ); + // Unreachable + } + } + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); + } +} + +//========================================================================= +void Content::transfer( + const ucb::TransferInfo & rArgs, + const uno::Reference< ucb::XCommandEnvironment >& Environment ) + throw( uno::Exception ) +{ + uno::Reference< lang::XMultiServiceFactory > xSMgr; + uno::Reference< ucb::XContentIdentifier > xIdentifier; + uno::Reference< ucb::XContentProvider > xProvider; + std::auto_ptr< DAVResourceAccess > xResAccess; + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + xSMgr.set( m_xSMgr ); + xIdentifier.set( m_xIdentifier ); + xProvider.set( m_xProvider.get() ); + xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); + } + + rtl::OUString aTargetURI; + try + { + SerfUri sourceURI( rArgs.SourceURL ); + SerfUri targetURI( xIdentifier->getContentIdentifier() ); + aTargetURI = targetURI.GetPathBaseNameUnescaped(); + + // Check source's and target's URL scheme + // + const rtl::OUString aScheme = sourceURI.GetScheme().toAsciiLowerCase(); + if ( aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) ) + { + sourceURI.SetScheme( + rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) ); + } + else if ( aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) ) + { + sourceURI.SetScheme( + rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) ); + } + else if ( aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) ) + { + sourceURI.SetScheme( + rtl::OUString::createFromAscii( HTTPS_URL_SCHEME ) ); + } + else + { + if ( !aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( HTTP_URL_SCHEME ) ) && + !aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( HTTPS_URL_SCHEME ) ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( + ucb::InteractiveBadTransferURLException( + rtl::OUString::createFromAscii( + "Unsupported URL scheme!" ), + static_cast< cppu::OWeakObject * >( this ) ) ), + Environment ); + // Unreachable + } + } + + if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) ) + targetURI.SetScheme( + rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) ); + else if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) ) + targetURI.SetScheme( + rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) ); + + // @@@ This implementation of 'transfer' only works + // if the source and target are located at same host. + // (Neon does not support cross-server copy/move) + + // Check for same host + // + if ( sourceURI.GetHost().getLength() && + ( sourceURI.GetHost() != targetURI.GetHost() ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( ucb::InteractiveBadTransferURLException( + rtl::OUString::createFromAscii( + "Different hosts!" ), + static_cast< cppu::OWeakObject * >( this ) ) ), + Environment ); + // Unreachable + } + + rtl::OUString aTitle = rArgs.NewTitle; + + if ( !aTitle.getLength() ) + aTitle = sourceURI.GetPathBaseNameUnescaped(); + + if ( aTitle.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "/" ) ) ) + { + // kso: ??? + aTitle = rtl::OUString(); + } + + targetURI.AppendPath( aTitle ); + + rtl::OUString aTargetURL = xIdentifier->getContentIdentifier(); + if ( ( aTargetURL.lastIndexOf( '/' ) + 1 ) + != aTargetURL.getLength() ) + aTargetURL += rtl::OUString::createFromAscii( "/" ); + + aTargetURL += aTitle; + + uno::Reference< ucb::XContentIdentifier > xTargetId + = new ::ucbhelper::ContentIdentifier( xSMgr, aTargetURL ); + + DAVResourceAccess aSourceAccess( xSMgr, + xResAccess->getSessionFactory(), + sourceURI.GetURI() ); + + if ( rArgs.MoveData == sal_True ) + { + uno::Reference< ucb::XContentIdentifier > xId + = new ::ucbhelper::ContentIdentifier( xSMgr, rArgs.SourceURL ); + + // Note: The static cast is okay here, because its sure that + // xProvider is always the WebDAVContentProvider. + rtl::Reference< Content > xSource + = static_cast< Content * >( + xProvider->queryContent( xId ).get() ); + + // [RFC 2518] - WebDAV + // If a resource exists at the destination and the Overwrite + // header is "T" then prior to performing the move the server + // MUST perform a DELETE with "Depth: infinity" on the + // destination resource. If the Overwrite header is set to + // "F" then the operation will fail. + + aSourceAccess.MOVE( sourceURI.GetPath(), + targetURI.GetURI(), + rArgs.NameClash + == ucb::NameClash::OVERWRITE, + Environment ); + + if ( xSource.is() ) + { + // Propagate destruction to listeners. + xSource->destroy( sal_True ); + } + +// DAV resources store all additional props on server! +// // Rename own and all children's Additional Core Properties. +// renameAdditionalPropertySet( xId->getContentIdentifier(), +// xTargetId->getContentIdentifier(), +// sal_True ); + } + else + { + // [RFC 2518] - WebDAV + // If a resource exists at the destination and the Overwrite + // header is "T" then prior to performing the copy the server + // MUST perform a DELETE with "Depth: infinity" on the + // destination resource. If the Overwrite header is set to + // "F" then the operation will fail. + + aSourceAccess.COPY( sourceURI.GetPath(), + targetURI.GetURI(), + rArgs.NameClash + == ucb::NameClash::OVERWRITE, + Environment ); + +// DAV resources store all additional props on server! +// // Copy own and all children's Additional Core Properties. +// copyAdditionalPropertySet( xId->getContentIdentifier(), +// xTargetId->getContentIdentifier(), +// sal_True ); + } + + // Note: The static cast is okay here, because its sure that + // xProvider is always the WebDAVContentProvider. + rtl::Reference< Content > xTarget + = static_cast< Content * >( + xProvider->queryContent( xTargetId ).get() ); + + // Announce transfered content in its new folder. + xTarget->inserted(); + } + catch ( ucb::IllegalIdentifierException const & ) + { + // queryContent + } + catch ( DAVException const & e ) + { + // [RFC 2518] - WebDAV + // 412 (Precondition Failed) - The server was unable to maintain + // the liveness of the properties listed in the propertybehavior + // XML element or the Overwrite header is "F" and the state of + // the destination resource is non-null. + + if ( e.getStatus() == SC_PRECONDITION_FAILED ) + { + switch ( rArgs.NameClash ) + { + case 0/*ucb::NameClash::ERROR*/: + { + ucbhelper::cancelCommandExecution( + uno::makeAny( + ucb::NameClashException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + aTargetURI ) ), + Environment ); + // Unreachable + } + + case ucb::NameClash::OVERWRITE: + break; + + case ucb::NameClash::KEEP: // deprecated + case ucb::NameClash::RENAME: + case ucb::NameClash::ASK: + default: + { + ucbhelper::cancelCommandExecution( + uno::makeAny( + ucb::UnsupportedNameClashException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + rArgs.NameClash ) ), + Environment ); + // Unreachable + } + } + } + + cancelCommandExecution( e, Environment, sal_True ); + // Unreachable + } + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); + } +} + +//========================================================================= +void Content::destroy( sal_Bool bDeletePhysical ) + throw( uno::Exception ) +{ + // @@@ take care about bDeletePhysical -> trashcan support + rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); + + uno::Reference< ucb::XContent > xThis = this; + + deleted(); + + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + // Process instanciated children... + + ::http_dav_ucp::Content::ContentRefList aChildren; + queryChildren( aChildren ); + + ContentRefList::const_iterator it = aChildren.begin(); + ContentRefList::const_iterator end = aChildren.end(); + + while ( it != end ) + { + (*it)->destroy( bDeletePhysical ); + ++it; + } +} + +//========================================================================= +bool Content::supportsExclusiveWriteLock( + const uno::Reference< ucb::XCommandEnvironment >& Environment ) +{ + if ( getResourceType( Environment ) == DAV ) + { + if ( m_xCachedProps.get() ) + { + uno::Sequence< ucb::LockEntry > aSupportedLocks; + if ( m_xCachedProps->getValue( DAVProperties::SUPPORTEDLOCK ) + >>= aSupportedLocks ) + { + for ( sal_Int32 n = 0; n < aSupportedLocks.getLength(); ++n ) + { + if ( aSupportedLocks[ n ].Scope + == ucb::LockScope_EXCLUSIVE && + aSupportedLocks[ n ].Type + == ucb::LockType_WRITE ) + return true; + } + } + } + } + return false; +} + +//========================================================================= +void Content::lock( + const uno::Reference< ucb::XCommandEnvironment >& Environment ) + throw( uno::Exception ) +{ + try + { + std::auto_ptr< DAVResourceAccess > xResAccess; + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); + } + + uno::Any aOwnerAny; + aOwnerAny + <<= rtl::OUString::createFromAscii( "http://ucb.openoffice.org" ); + + ucb::Lock aLock( + ucb::LockScope_EXCLUSIVE, + ucb::LockType_WRITE, + ucb::LockDepth_ZERO, + aOwnerAny, + 180, // lock timeout in secs + //-1, // infinite lock + uno::Sequence< ::rtl::OUString >() ); + + xResAccess->LOCK( aLock, Environment ); + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); + } + } + catch ( DAVException const & e ) + { + cancelCommandExecution( e, Environment, sal_False ); + // Unreachable + } +} + +//========================================================================= +void Content::unlock( + const uno::Reference< ucb::XCommandEnvironment >& Environment ) + throw( uno::Exception ) +{ + try + { + std::auto_ptr< DAVResourceAccess > xResAccess; + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); + } + + xResAccess->UNLOCK( Environment ); + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); + } + } + catch ( DAVException const & e ) + { + cancelCommandExecution( e, Environment, sal_False ); + // Unreachable + } +} + +//========================================================================= +sal_Bool Content::exchangeIdentity( + const uno::Reference< ucb::XContentIdentifier >& xNewId ) +{ + if ( !xNewId.is() ) + return sal_False; + + osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); + + uno::Reference< ucb::XContent > xThis = this; + + // Already persistent? + if ( m_bTransient ) + { + OSL_ENSURE( sal_False, "Content::exchangeIdentity - Not persistent!" ); + return sal_False; + } + + // Exchange own identitity. + + // Fail, if a content with given id already exists. +// if ( !hasData( xNewId ) ) + { + rtl::OUString aOldURL = m_xIdentifier->getContentIdentifier(); + + aGuard.clear(); + if ( exchange( xNewId ) ) + { + // Process instanciated children... + + ContentRefList aChildren; + queryChildren( aChildren ); + + ContentRefList::const_iterator it = aChildren.begin(); + ContentRefList::const_iterator end = aChildren.end(); + + while ( it != end ) + { + ContentRef xChild = (*it); + + // Create new content identifier for the child... + uno::Reference< ucb::XContentIdentifier > + xOldChildId = xChild->getIdentifier(); + rtl::OUString aOldChildURL + = xOldChildId->getContentIdentifier(); + rtl::OUString aNewChildURL + = aOldChildURL.replaceAt( + 0, + aOldURL.getLength(), + xNewId->getContentIdentifier() ); + uno::Reference< ucb::XContentIdentifier > xNewChildId + = new ::ucbhelper::ContentIdentifier( + m_xSMgr, aNewChildURL ); + + if ( !xChild->exchangeIdentity( xNewChildId ) ) + return sal_False; + + ++it; + } + return sal_True; + } + } + + OSL_ENSURE( sal_False, + "Content::exchangeIdentity - " + "Panic! Cannot exchange identity!" ); + return sal_False; +} + +//========================================================================= +sal_Bool Content::isFolder( + const uno::Reference< ucb::XCommandEnvironment >& xEnv ) + throw( uno::Exception ) +{ + { + osl::MutexGuard aGuard( m_aMutex ); + + if ( m_bTransient ) + return m_bCollection; + } + + uno::Sequence< beans::Property > aProperties( 1 ); + aProperties[ 0 ].Name = rtl::OUString::createFromAscii( "IsFolder" ); + aProperties[ 0 ].Handle = -1; + uno::Reference< sdbc::XRow > xRow( getPropertyValues( aProperties, xEnv ) ); + if ( xRow.is() ) + { + try + { + return xRow->getBoolean( 1 ); + } + catch ( sdbc::SQLException const & ) + { + } + } + + return sal_False; +} + +//========================================================================= +uno::Any Content::MapDAVException( const DAVException & e, sal_Bool bWrite ) +{ + // Map DAVException... + uno::Any aException; + + rtl::OUString aURL; + if ( m_bTransient ) + { + aURL = getParentURL(); + if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) ) + aURL += rtl::OUString::createFromAscii( "/" ); + + aURL += m_aEscapedTitle; + } + else + { + aURL = m_xIdentifier->getContentIdentifier(); + } + + switch ( e.getStatus() ) + { + case SC_NOT_FOUND: + { + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[ 0 ] <<= beans::PropertyValue( + rtl::OUString::createFromAscii("Uri"), -1, + uno::makeAny(aURL), + beans::PropertyState_DIRECT_VALUE); + + aException <<= + ucb::InteractiveAugmentedIOException( + rtl::OUString::createFromAscii( "Not found!" ), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + ucb::IOErrorCode_NOT_EXISTING, + aArgs ); + return aException; + } + default: + break; + } + + switch ( e.getError() ) + { + case DAVException::DAV_HTTP_ERROR: + { + if ( bWrite ) + aException <<= + ucb::InteractiveNetworkWriteException( + e.getData(), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + e.getData() ); + else + aException <<= + ucb::InteractiveNetworkReadException( + e.getData(), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + e.getData() ); + break; + } + + case DAVException::DAV_HTTP_LOOKUP: + aException <<= + ucb::InteractiveNetworkResolveNameException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + e.getData() ); + break; + +// @@@ No matching InteractiveNetwork*Exception +// case DAVException::DAV_HTTP_AUTH: +// break; + +// @@@ No matching InteractiveNetwork*Exception +// case DAVException::DAV_HTTP_AUTHPROXY: +// break; + + case DAVException::DAV_HTTP_CONNECT: + aException <<= + ucb::InteractiveNetworkConnectException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + e.getData() ); + break; + +// @@@ No matching InteractiveNetwork*Exception +// case DAVException::DAV_HTTP_TIMEOUT: +// break; + +// @@@ No matching InteractiveNetwork*Exception +// case DAVException::DAV_HTTP_REDIRECT: +// break; + +// @@@ No matching InteractiveNetwork*Exception +// case DAVException::DAV_SESSION_CREATE: +// break; + + case DAVException::DAV_INVALID_ARG: + aException <<= + lang::IllegalArgumentException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + -1 ); + break; + + case DAVException::DAV_LOCKED: +#if 1 + aException <<= + ucb::InteractiveLockingLockedException( + rtl::OUString::createFromAscii( "Locked!" ), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + aURL, + sal_False ); // not SelfOwned +#else + { + uno::Sequence< uno::Any > aArgs( 1 ); + aArgs[ 0 ] <<= beans::PropertyValue( + rtl::OUString::createFromAscii("Uri"), -1, + uno::makeAny(aURL), + beans::PropertyState_DIRECT_VALUE); + + aException <<= + ucb::InteractiveAugmentedIOException( + rtl::OUString::createFromAscii( "Locked!" ), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + ucb::IOErrorCode_LOCKING_VIOLATION, + aArgs ); + } +#endif + break; + + case DAVException::DAV_LOCKED_SELF: + aException <<= + ucb::InteractiveLockingLockedException( + rtl::OUString::createFromAscii( "Locked (self)!" ), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + aURL, + sal_True ); // SelfOwned + break; + + case DAVException::DAV_NOT_LOCKED: + aException <<= + ucb::InteractiveLockingNotLockedException( + rtl::OUString::createFromAscii( "Not locked!" ), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + aURL ); + break; + + case DAVException::DAV_LOCK_EXPIRED: + aException <<= + ucb::InteractiveLockingLockExpiredException( + rtl::OUString::createFromAscii( "Lock expired!" ), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + aURL ); + break; + + default: + aException <<= + ucb::InteractiveNetworkGeneralException( + rtl::OUString(), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR ); + break; + } + + return aException; +} + +//========================================================================= +// static +bool Content::shouldAccessNetworkAfterException( const DAVException & e ) +{ + if ( ( e.getStatus() == SC_NOT_FOUND ) || + ( e.getError() == DAVException::DAV_HTTP_LOOKUP ) || + ( e.getError() == DAVException::DAV_HTTP_CONNECT ) || + ( e.getError() == DAVException::DAV_HTTP_AUTH ) || + ( e.getError() == DAVException::DAV_HTTP_AUTHPROXY ) ) + return false; + + return true; +} + +//========================================================================= +void Content::cancelCommandExecution( + const DAVException & e, + const uno::Reference< ucb::XCommandEnvironment > & xEnv, + sal_Bool bWrite /* = sal_False */ ) + throw ( uno::Exception ) +{ + ucbhelper::cancelCommandExecution( MapDAVException( e, bWrite ), xEnv ); + // Unreachable +} + +//========================================================================= +const rtl::OUString +Content::getBaseURI( const std::auto_ptr< DAVResourceAccess > & rResAccess ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + // First, try to obtain value of response header "Content-Location". + if ( m_xCachedProps.get() ) + { + rtl::OUString aLocation; + m_xCachedProps->getValue( rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "Content-Location" ) ) ) >>= aLocation; + if ( aLocation.getLength() ) + { + try + { + // Do not use m_xIdentifier->getContentIdentifier() because it + // for example does not reflect redirects applied to requests + // done using the original URI but m_xResAccess' URI does. + return rtl::Uri::convertRelToAbs( rResAccess->getURL(), + aLocation ); + } + catch ( rtl::MalformedUriException const & ) + { + } + } + } + + return rtl::OUString( rResAccess->getURL() ); +} + +//========================================================================= +const Content::ResourceType & Content::getResourceType( + const uno::Reference< ucb::XCommandEnvironment >& xEnv, + const std::auto_ptr< DAVResourceAccess > & rResAccess ) + throw ( uno::Exception ) +{ + if ( m_eResourceType == UNKNOWN ) + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + ResourceType eResourceType; + eResourceType = m_eResourceType; + + const rtl::OUString & rURL = rResAccess->getURL(); + const rtl::OUString aScheme( + rURL.copy( 0, rURL.indexOf( ':' ) ).toAsciiLowerCase() ); + + try + { + // Try to fetch some frequently used property value, e.g. those + // used when loading documents... along with identifying whether + // this is a DAV resource. + std::vector< DAVResource > resources; + std::vector< rtl::OUString > aPropNames; + uno::Sequence< beans::Property > aProperties( 5 ); + aProperties[ 0 ].Name + = rtl::OUString::createFromAscii( "IsFolder" ); + aProperties[ 1 ].Name + = rtl::OUString::createFromAscii( "IsDocument" ); + aProperties[ 2 ].Name + = rtl::OUString::createFromAscii( "IsReadOnly" ); + aProperties[ 3 ].Name + = rtl::OUString::createFromAscii( "MediaType" ); + aProperties[ 4 ].Name + = DAVProperties::SUPPORTEDLOCK; + + ContentProperties::UCBNamesToDAVNames( + aProperties, aPropNames ); + + rResAccess->PROPFIND( + DAVZERO, aPropNames, resources, xEnv ); + + // TODO - is this really only one? + if ( resources.size() == 1 ) + { + m_xCachedProps.reset( + new CachableContentProperties( resources[ 0 ] ) ); + m_xCachedProps->containsAllNames( + aProperties, m_aFailedPropNames ); + } + + eResourceType = DAV; + } + catch ( DAVException const & e ) + { + rResAccess->resetUri(); + + if ( e.getStatus() == SC_METHOD_NOT_ALLOWED ) + { + // Status SC_METHOD_NOT_ALLOWED is a safe indicator that the + // resource is NON_DAV + eResourceType = NON_DAV; + } + // cancel command execution is case that no user authentication data has been provided. + if ( e.getError() == DAVException::DAV_HTTP_NOAUTH ) + { + cancelCommandExecution( e, uno::Reference< ucb::XCommandEnvironment >() ); + } + } + m_eResourceType = eResourceType; + } + return m_eResourceType; +} + +//========================================================================= +const Content::ResourceType & Content::getResourceType( + const uno::Reference< ucb::XCommandEnvironment >& xEnv ) + throw ( uno::Exception ) +{ + return getResourceType( xEnv, m_xResAccess ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/webdavcontent.hxx b/ucb/source/ucp/webdav/webdavcontent.hxx new file mode 100644 index 000000000000..1e649f3071c1 --- /dev/null +++ b/ucb/source/ucp/webdav/webdavcontent.hxx @@ -0,0 +1,296 @@ +/* -*- 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 _WEBDAV_UCP_CONTENT_HXX +#define _WEBDAV_UCP_CONTENT_HXX + +#include +#include +#include +#include +#include +#include +#include "DAVResourceAccess.hxx" +#include "PropertyMap.hxx" + +namespace com { namespace sun { namespace star { namespace beans { + struct Property; + struct PropertyValue; +} } } } + +namespace com { namespace sun { namespace star { namespace io { + class XInputStream; +} } } } + +namespace com { namespace sun { namespace star { namespace sdbc { + class XRow; +} } } } + +namespace com { namespace sun { namespace star { namespace ucb { + struct OpenCommandArgument2; + struct PostCommandArgument2; + struct TransferInfo; +} } } } + +namespace http_dav_ucp +{ + +//========================================================================= + +// UNO service name for the content. +#define WEBDAV_CONTENT_SERVICE_NAME "com.sun.star.ucb.WebDAVContent" + +//========================================================================= + +class ContentProvider; +class ContentProperties; +class CachableContentProperties; + +class Content : public ::ucbhelper::ContentImplHelper, + public com::sun::star::ucb::XContentCreator +{ + enum ResourceType + { + UNKNOWN, + NON_DAV, + DAV + }; + + std::auto_ptr< DAVResourceAccess > m_xResAccess; + std::auto_ptr< CachableContentProperties > + m_xCachedProps; // locally cached props + rtl::OUString m_aEscapedTitle; + ResourceType m_eResourceType; + ContentProvider* m_pProvider; // No need for a ref, base class holds object + bool m_bTransient; + bool m_bCollection; + bool m_bDidGetOrHead; + std::vector< rtl::OUString > m_aFailedPropNames; + +private: + virtual com::sun::star::uno::Sequence< com::sun::star::beans::Property > + getProperties( const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ); + virtual com::sun::star::uno::Sequence< com::sun::star::ucb::CommandInfo > + getCommands( const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ); + virtual ::rtl::OUString getParentURL(); + + sal_Bool isFolder( const ::com::sun::star::uno::Reference< + ::com::sun::star::ucb::XCommandEnvironment >& xEnv ) + throw ( ::com::sun::star::uno::Exception ); + + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRow > + getPropertyValues( const ::com::sun::star::uno::Sequence< + ::com::sun::star::beans::Property >& rProperties, + const ::com::sun::star::uno::Reference< + ::com::sun::star::ucb::XCommandEnvironment >& xEnv ) + throw ( ::com::sun::star::uno::Exception ); + + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > + setPropertyValues( const ::com::sun::star::uno::Sequence< + ::com::sun::star::beans::PropertyValue >& rValues, + const ::com::sun::star::uno::Reference< + ::com::sun::star::ucb::XCommandEnvironment >& xEnv ) + throw ( ::com::sun::star::uno::Exception ); + + typedef rtl::Reference< Content > ContentRef; + typedef std::list< ContentRef > ContentRefList; + void queryChildren( ContentRefList& rChildren); + + sal_Bool + exchangeIdentity( const ::com::sun::star::uno::Reference< + ::com::sun::star::ucb::XContentIdentifier >& xNewId ); + + const rtl::OUString + getBaseURI( const std::auto_ptr< DAVResourceAccess > & rResAccess ); + + const ResourceType & + getResourceType( const ::com::sun::star::uno::Reference< + ::com::sun::star::ucb::XCommandEnvironment >& xEnv ) + throw ( ::com::sun::star::uno::Exception ); + + const ResourceType & + getResourceType( const ::com::sun::star::uno::Reference< + ::com::sun::star::ucb::XCommandEnvironment >& xEnv, + const std::auto_ptr< DAVResourceAccess > & rResAccess ) + throw ( ::com::sun::star::uno::Exception ); + + // Command "open" + com::sun::star::uno::Any open( + const com::sun::star::ucb::OpenCommandArgument2 & rArg, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw( ::com::sun::star::uno::Exception ); + + // Command "post" + void post( const com::sun::star::ucb::PostCommandArgument2 & rArg, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw( ::com::sun::star::uno::Exception ); + + // Command "insert" + void insert( const ::com::sun::star::uno::Reference< + ::com::sun::star::io::XInputStream > & xInputStream, + sal_Bool bReplaceExisting, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment >& Environment ) + throw( ::com::sun::star::uno::Exception ); + + // Command "transfer" + void transfer( const ::com::sun::star::ucb::TransferInfo & rArgs, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment >& Environment ) + throw( ::com::sun::star::uno::Exception ); + + // Command "delete" + void destroy( sal_Bool bDeletePhysical ) + throw( ::com::sun::star::uno::Exception ); + + // Command "lock" + void lock( const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment >& Environment ) + throw( ::com::sun::star::uno::Exception ); + + // Command "unlock" + void unlock( const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment >& Environment ) + throw( ::com::sun::star::uno::Exception ); + + ::com::sun::star::uno::Any MapDAVException( const DAVException & e, + sal_Bool bWrite ); + void cancelCommandExecution( + const DAVException & e, + const ::com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv, + sal_Bool bWrite = sal_False ) + throw( ::com::sun::star::uno::Exception ); + + static bool shouldAccessNetworkAfterException( const DAVException & e ); + + bool supportsExclusiveWriteLock( + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment >& Environment ); + +public: + Content( const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& rxSMgr, + ContentProvider* pProvider, + const ::com::sun::star::uno::Reference< + ::com::sun::star::ucb::XContentIdentifier >& Identifier, + rtl::Reference< DAVSessionFactory > const & rSessionFactory ) + throw ( ::com::sun::star::ucb::ContentCreationException ); + Content( const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& rxSMgr, + ContentProvider* pProvider, + const ::com::sun::star::uno::Reference< + ::com::sun::star::ucb::XContentIdentifier >& Identifier, + rtl::Reference< DAVSessionFactory > const & rSessionFactory, + sal_Bool isCollection ) + throw ( ::com::sun::star::ucb::ContentCreationException ); + virtual ~Content(); + + // XInterface + XINTERFACE_DECL() + + // XTypeProvider + XTYPEPROVIDER_DECL() + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL + getImplementationName() + throw( ::com::sun::star::uno::RuntimeException ); + + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL + getSupportedServiceNames() + throw( ::com::sun::star::uno::RuntimeException ); + + // XContent + virtual rtl::OUString SAL_CALL + getContentType() + throw( com::sun::star::uno::RuntimeException ); + + // XCommandProcessor + virtual com::sun::star::uno::Any SAL_CALL + execute( const com::sun::star::ucb::Command& aCommand, + sal_Int32 CommandId, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment >& Environment ) + throw( com::sun::star::uno::Exception, + com::sun::star::ucb::CommandAbortedException, + com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL + abort( sal_Int32 CommandId ) + throw( com::sun::star::uno::RuntimeException ); + + // XPropertyContainer + virtual void SAL_CALL + addProperty( const rtl::OUString& Name, + sal_Int16 Attributes, + const com::sun::star::uno::Any& DefaultValue ) + throw( com::sun::star::beans::PropertyExistException, + com::sun::star::beans::IllegalTypeException, + com::sun::star::lang::IllegalArgumentException, + com::sun::star::uno::RuntimeException ); + + virtual void SAL_CALL + removeProperty( const rtl::OUString& Name ) + throw( com::sun::star::beans::UnknownPropertyException, + com::sun::star::beans::NotRemoveableException, + com::sun::star::uno::RuntimeException ); + + ////////////////////////////////////////////////////////////////////// + // Additional interfaces + ////////////////////////////////////////////////////////////////////// + + // XContentCreator + virtual com::sun::star::uno::Sequence< + com::sun::star::ucb::ContentInfo > SAL_CALL + queryCreatableContentsInfo() + throw( com::sun::star::uno::RuntimeException ); + virtual com::sun::star::uno::Reference< + com::sun::star::ucb::XContent > SAL_CALL + createNewContent( const com::sun::star::ucb::ContentInfo& Info ) + throw( com::sun::star::uno::RuntimeException ); + + ////////////////////////////////////////////////////////////////////// + // Non-interface methods. + ////////////////////////////////////////////////////////////////////// + + DAVResourceAccess & getResourceAccess() { return *m_xResAccess; } + + // Called from resultset data supplier. + static ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XRow > + getPropertyValues( const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& rSMgr, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::beans::Property >& rProperties, + const ContentProperties& rData, + const rtl::Reference< + ::ucbhelper::ContentProviderImplHelper >& rProvider, + const ::rtl::OUString& rContentId ); +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/webdavcontentcaps.cxx b/ucb/source/ucp/webdav/webdavcontentcaps.cxx new file mode 100644 index 000000000000..76da92893613 --- /dev/null +++ b/ucb/source/ucp/webdav/webdavcontentcaps.cxx @@ -0,0 +1,659 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "webdavcontent.hxx" +#include "webdavprovider.hxx" +#include "DAVSession.hxx" +#include "ContentProperties.hxx" + +using namespace com::sun::star; +using namespace http_dav_ucp; + +//========================================================================= +// +// ContentProvider implementation. +// +//========================================================================= + +bool ContentProvider::getProperty( + const rtl::OUString & rPropName, beans::Property & rProp, bool bStrict ) +{ + if ( !m_pProps ) + { + osl::MutexGuard aGuard( m_aMutex ); + if ( !m_pProps ) + { + m_pProps = new PropertyMap; + + ////////////////////////////////////////////////////////////// + // Fill map of known properties... + ////////////////////////////////////////////////////////////// + + // Mandatory UCB properties. + m_pProps->insert( + beans::Property( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "ContentType" ) ), + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ), + -1, + getCppuBooleanType(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ), + -1, + getCppuBooleanType(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ), + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND ) ); + + // Optional UCB properties. + + m_pProps->insert( + beans::Property( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "DateCreated" ) ), + -1, + getCppuType( static_cast< const util::DateTime * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "DateModified" ) ), + -1, + getCppuType( static_cast< const util::DateTime * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ), + -1, + getCppuType( static_cast< const sal_Int64 * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseURI" ) ), + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "CreatableContentsInfo" ) ), + -1, + getCppuType( static_cast< + const uno::Sequence< ucb::ContentInfo > * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + // Standard DAV properties. + + m_pProps->insert( + beans::Property( + DAVProperties::CREATIONDATE, + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + DAVProperties::DISPLAYNAME, + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND ) ); + + m_pProps->insert( + beans::Property( + DAVProperties::GETCONTENTLANGUAGE, + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + DAVProperties::GETCONTENTLENGTH, + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + DAVProperties::GETCONTENTTYPE , + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + DAVProperties::GETETAG, + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + DAVProperties::GETLASTMODIFIED, + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + DAVProperties::LOCKDISCOVERY, + -1, + getCppuType( static_cast< + const uno::Sequence< ucb::Lock > * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + DAVProperties::RESOURCETYPE, + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + DAVProperties::SUPPORTEDLOCK, + -1, + getCppuType( static_cast< + const uno::Sequence< + ucb::LockEntry > * >( 0 ) ), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + m_pProps->insert( + beans::Property( + DAVProperties::EXECUTABLE, + -1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND ) ); + } + } + + ////////////////////////////////////////////////////////////// + // Lookup property. + ////////////////////////////////////////////////////////////// + + beans::Property aProp; + aProp.Name = rPropName; + const PropertyMap::const_iterator it = m_pProps->find( aProp ); + if ( it != m_pProps->end() ) + { + rProp = (*it); + } + else + { + if ( bStrict ) + return false; + + // All unknown props are treated as: + rProp = beans::Property( + rPropName, + - 1, + getCppuType( static_cast< const rtl::OUString * >( 0 ) ), + beans::PropertyAttribute::BOUND ); + } + + return true; +} + +//========================================================================= +// +// Content implementation. +// +//========================================================================= + +// virtual +uno::Sequence< beans::Property > Content::getProperties( + const uno::Reference< ucb::XCommandEnvironment > & xEnv ) +{ + sal_Bool bTransient; + std::auto_ptr< DAVResourceAccess > xResAccess; + std::auto_ptr< ContentProperties > xCachedProps; + rtl::Reference< ContentProvider > xProvider; + + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + bTransient = m_bTransient; + xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); + if ( m_xCachedProps.get() ) + xCachedProps.reset( + new ContentProperties( *m_xCachedProps.get() ) ); + xProvider.set( m_pProvider ); + } + + typedef std::set< rtl::OUString > StringSet; + StringSet aPropSet; + + // No server access for just created (not yet committed) objects. + // Only a minimal set of properties supported at this stage. + if ( !bTransient ) + { + // Obtain all properties supported for this resource from server. + try + { + std::vector< DAVResourceInfo > props; + xResAccess->PROPFIND( DAVZERO, props, xEnv ); + + // Note: vector always contains exactly one resource info, because + // we used a depth of DAVZERO for PROPFIND. + aPropSet.insert( (*props.begin()).properties.begin(), + (*props.begin()).properties.end() ); + } + catch ( DAVException const & ) + { + } + } + + // Add DAV properties, map DAV properties to UCB properties. + sal_Bool bHasCreationDate = sal_False; // creationdate <-> DateCreated + sal_Bool bHasGetLastModified = sal_False; // getlastmodified <-> DateModified + sal_Bool bHasGetContentType = sal_False; // getcontenttype <-> MediaType + sal_Bool bHasGetContentLength = sal_False; // getcontentlength <-> Size + + sal_Bool bHasContentType = sal_False; + sal_Bool bHasIsDocument = sal_False; + sal_Bool bHasIsFolder = sal_False; + sal_Bool bHasTitle = sal_False; + sal_Bool bHasBaseURI = sal_False; + sal_Bool bHasDateCreated = sal_False; + sal_Bool bHasDateModified = sal_False; + sal_Bool bHasMediaType = sal_False; + sal_Bool bHasSize = sal_False; + sal_Bool bHasCreatableInfos = sal_False; + + { + std::set< rtl::OUString >::const_iterator it = aPropSet.begin(); + std::set< rtl::OUString >::const_iterator end = aPropSet.end(); + while ( it != end ) + { + if ( !bHasCreationDate && + ( (*it) == DAVProperties::CREATIONDATE ) ) + { + bHasCreationDate = sal_True; + } + else if ( !bHasGetLastModified && + ( (*it) == DAVProperties::GETLASTMODIFIED ) ) + { + bHasGetLastModified = sal_True; + } + else if ( !bHasGetContentType && + ( (*it) == DAVProperties::GETCONTENTTYPE ) ) + { + bHasGetContentType = sal_True; + } + else if ( !bHasGetContentLength && + ( (*it) == DAVProperties::GETCONTENTLENGTH ) ) + { + bHasGetContentLength = sal_True; + } + else if ( !bHasContentType && + (*it).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ) + { + bHasContentType = sal_True; + } + else if ( !bHasIsDocument && + (*it).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ) + { + bHasIsDocument = sal_True; + } + else if ( !bHasIsFolder && + (*it).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ) + { + bHasIsFolder = sal_True; + } + else if ( !bHasTitle && + (*it).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) + { + bHasTitle = sal_True; + } + else if ( !bHasBaseURI && + (*it).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "BaseURI" ) ) ) + { + bHasBaseURI = sal_True; + } + else if ( !bHasDateCreated && + (*it).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) ) + { + bHasDateCreated = sal_True; + } + else if ( !bHasDateModified && + (*it).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) ) + { + bHasDateModified = sal_True; + } + else if ( !bHasMediaType && + (*it).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ) + { + bHasMediaType = sal_True; + } + else if ( !bHasSize && + (*it).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "Size" ) ) ) + { + bHasSize = sal_True; + } + else if ( !bHasCreatableInfos && + (*it).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( + "CreatableContentsInfo" ) ) ) + { + bHasCreatableInfos = sal_True; + } + it++; + } + } + + // Add mandatory properties. + if ( !bHasContentType ) + aPropSet.insert( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ContentType" ) ) ); + + if ( !bHasIsDocument ) + aPropSet.insert( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ) ); + + if ( !bHasIsFolder ) + aPropSet.insert( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ) ); + + if ( !bHasTitle ) + { + // Always present since it can be calculated from content's URI. + aPropSet.insert( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ) ); + } + + // Add optional properties. + + if ( !bHasBaseURI ) + { + // Always present since it can be calculated from content's URI. + aPropSet.insert( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseURI" ) ) ); + } + + if ( !bHasDateCreated && bHasCreationDate ) + aPropSet.insert( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DateCreated" ) ) ); + + if ( !bHasDateModified && bHasGetLastModified ) + aPropSet.insert( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DateModified" ) ) ); + + if ( !bHasMediaType && bHasGetContentType ) + aPropSet.insert( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ) ); + + if ( !bHasSize && bHasGetContentLength ) + aPropSet.insert( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ) ); + + if ( !bHasCreatableInfos ) + aPropSet.insert( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "CreatableContentsInfo" ) ) ); + + // Add cached properties, if present and still missing. + if ( xCachedProps.get() ) + { + const std::set< rtl::OUString >::const_iterator set_end + = aPropSet.end(); + + const std::auto_ptr< PropertyValueMap > & xProps + = xCachedProps->getProperties(); + + PropertyValueMap::const_iterator map_it = xProps->begin(); + const PropertyValueMap::const_iterator map_end = xProps->end(); + + while ( map_it != map_end ) + { + if ( aPropSet.find( (*map_it).first ) == set_end ) + aPropSet.insert( (*map_it).first ); + + ++map_it; + } + } + + // std::set -> uno::Sequence + sal_Int32 nCount = aPropSet.size(); + uno::Sequence< beans::Property > aProperties( nCount ); + + std::set< rtl::OUString >::const_iterator it = aPropSet.begin(); + beans::Property aProp; + + for ( sal_Int32 n = 0; n < nCount; ++n, ++it ) + { + xProvider->getProperty( (*it), aProp ); + aProperties[ n ] = aProp; + } + + return aProperties; +} + +//========================================================================= +// virtual +uno::Sequence< ucb::CommandInfo > Content::getCommands( + const uno::Reference< ucb::XCommandEnvironment > & xEnv ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + uno::Sequence< ucb::CommandInfo > aCmdInfo( 8 ); + + /////////////////////////////////////////////////////////////// + // Mandatory commands + /////////////////////////////////////////////////////////////// + + aCmdInfo[ 0 ] = + ucb::CommandInfo( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "getCommandInfo" ) ), + -1, + getCppuVoidType() ); + aCmdInfo[ 1 ] = + ucb::CommandInfo( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "getPropertySetInfo" ) ), + -1, + getCppuVoidType() ); + aCmdInfo[ 2 ] = + ucb::CommandInfo( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "getPropertyValues" ) ), + -1, + getCppuType( static_cast< + uno::Sequence< beans::Property > * >( 0 ) ) ); + aCmdInfo[ 3 ] = + ucb::CommandInfo( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "setPropertyValues" ) ), + -1, + getCppuType( static_cast< + uno::Sequence< beans::PropertyValue > * >( 0 ) ) ); + + /////////////////////////////////////////////////////////////// + // Optional standard commands + /////////////////////////////////////////////////////////////// + + aCmdInfo[ 4 ] = + ucb::CommandInfo( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "delete" ) ), + -1, + getCppuBooleanType() ); + aCmdInfo[ 5 ] = + ucb::CommandInfo( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert" ) ), + -1, + getCppuType( static_cast< + ucb::InsertCommandArgument * >( 0 ) ) ); + aCmdInfo[ 6 ] = + ucb::CommandInfo( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "open" ) ), + -1, + getCppuType( static_cast< + ucb::OpenCommandArgument2 * >( 0 ) ) ); + + /////////////////////////////////////////////////////////////// + // New commands + /////////////////////////////////////////////////////////////// + + aCmdInfo[ 7 ] = + ucb::CommandInfo( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "post" ) ), + -1, + getCppuType( static_cast< + ucb::PostCommandArgument2 * >( 0 ) ) ); + + sal_Bool bFolder = sal_False; + + try + { + bFolder = isFolder( xEnv ); + } + catch ( uno::Exception const & ) + { + return aCmdInfo; + } + + sal_Bool bSupportsLocking = supportsExclusiveWriteLock( xEnv ); + + sal_Int32 nPos = aCmdInfo.getLength(); + sal_Int32 nMoreCmds = ( bFolder ? 2 : 0 ) + ( bSupportsLocking ? 2 : 0 ); + if ( nMoreCmds ) + aCmdInfo.realloc( nPos + nMoreCmds ); + else + return aCmdInfo; + + if ( bFolder ) + { + /////////////////////////////////////////////////////////////// + // Optional standard commands + /////////////////////////////////////////////////////////////// + + aCmdInfo[ nPos ] = + ucb::CommandInfo( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "transfer" ) ), + -1, + getCppuType( static_cast< ucb::TransferInfo * >( 0 ) ) ); + nPos++; + aCmdInfo[ nPos ] = + ucb::CommandInfo( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "createNewContent" ) ), + -1, + getCppuType( static_cast< ucb::ContentInfo * >( 0 ) ) ); + nPos++; + } + else + { + // no document-only commands at the moment. + } + + if ( bSupportsLocking ) + { + aCmdInfo[ nPos ] = + ucb::CommandInfo( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "lock" ) ), + -1, + getCppuVoidType() ); + nPos++; + aCmdInfo[ nPos ] = + ucb::CommandInfo( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "unlock" ) ), + -1, + getCppuVoidType() ); + nPos++; + } + return aCmdInfo; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/webdavdatasupplier.cxx b/ucb/source/ucp/webdav/webdavdatasupplier.cxx new file mode 100644 index 000000000000..bb4c396d4b5b --- /dev/null +++ b/ucb/source/ucp/webdav/webdavdatasupplier.cxx @@ -0,0 +1,507 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ +#include +#include +#include +#include +#include "webdavdatasupplier.hxx" +#include "webdavcontent.hxx" +#include "ContentProperties.hxx" +#ifndef _WEBDAV_SESSION_HXX +#include "DAVSession.hxx" +#endif +#include "SerfUri.hxx" + +using namespace com::sun::star; +using namespace http_dav_ucp; + +namespace http_dav_ucp +{ + +//========================================================================= +// +// struct ResultListEntry. +// +//========================================================================= + +struct ResultListEntry +{ + rtl::OUString aId; + uno::Reference< ucb::XContentIdentifier > xId; + uno::Reference< ucb::XContent > xContent; + uno::Reference< sdbc::XRow > xRow; + const ContentProperties* pData; + + ResultListEntry( const ContentProperties* pEntry ) : pData( pEntry ) {}; + ~ResultListEntry() { delete pData; } +}; + +//========================================================================= +// +// ResultList. +// +//========================================================================= + +typedef std::vector< ResultListEntry* > ResultList; + +//========================================================================= +// +// struct DataSupplier_Impl. +// +//========================================================================= + +struct DataSupplier_Impl +{ + osl::Mutex m_aMutex; + ResultList m_aResults; + rtl::Reference< Content > m_xContent; + uno::Reference< lang::XMultiServiceFactory > m_xSMgr; + sal_Int32 m_nOpenMode; + sal_Bool m_bCountFinal; + sal_Bool m_bThrowException; + + DataSupplier_Impl( + const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, + const rtl::Reference< Content >& rContent, + sal_Int32 nOpenMode ) + : m_xContent( rContent ), m_xSMgr( rxSMgr ), m_nOpenMode( nOpenMode ), + m_bCountFinal( sal_False ), m_bThrowException( sal_False ) {} + ~DataSupplier_Impl(); +}; + +//========================================================================= +DataSupplier_Impl::~DataSupplier_Impl() +{ + ResultList::const_iterator it = m_aResults.begin(); + ResultList::const_iterator end = m_aResults.end(); + + while ( it != end ) + { + delete (*it); + it++; + } +} + +} + +//========================================================================= +//========================================================================= +// +// DataSupplier Implementation. +// +//========================================================================= +//========================================================================= + +DataSupplier::DataSupplier( + const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, + const rtl::Reference< Content >& rContent, + sal_Int32 nOpenMode ) +: m_pImpl( new DataSupplier_Impl( rxSMgr, rContent, nOpenMode ) ) +{ +} + +//========================================================================= +// virtual +DataSupplier::~DataSupplier() +{ + delete m_pImpl; +} + +//========================================================================= +// virtual +rtl::OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( nIndex < m_pImpl->m_aResults.size() ) + { + rtl::OUString aId = m_pImpl->m_aResults[ nIndex ]->aId; + if ( aId.getLength() ) + { + // Already cached. + return aId; + } + } + + if ( getResult( nIndex ) ) + { + rtl::OUString aId = m_pImpl->m_xContent->getResourceAccess().getURL(); + + const ContentProperties& props + = *( m_pImpl->m_aResults[ nIndex ]->pData ); + + if ( ( aId.lastIndexOf( '/' ) + 1 ) != aId.getLength() ) + aId += rtl::OUString::createFromAscii( "/" ); + + aId += props.getEscapedTitle(); + + if ( props.isTrailingSlash() ) + aId += rtl::OUString::createFromAscii( "/" ); + + m_pImpl->m_aResults[ nIndex ]->aId = aId; + return aId; + } + return rtl::OUString(); +} + +//========================================================================= +// virtual +uno::Reference< ucb::XContentIdentifier > +DataSupplier::queryContentIdentifier( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( nIndex < m_pImpl->m_aResults.size() ) + { + uno::Reference< ucb::XContentIdentifier > xId + = m_pImpl->m_aResults[ nIndex ]->xId; + if ( xId.is() ) + { + // Already cached. + return xId; + } + } + + rtl::OUString aId = queryContentIdentifierString( nIndex ); + if ( aId.getLength() ) + { + uno::Reference< ucb::XContentIdentifier > xId + = new ::ucbhelper::ContentIdentifier( aId ); + m_pImpl->m_aResults[ nIndex ]->xId = xId; + return xId; + } + return uno::Reference< ucb::XContentIdentifier >(); +} + +//========================================================================= +// virtual +uno::Reference< ucb::XContent > +DataSupplier::queryContent( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( nIndex < m_pImpl->m_aResults.size() ) + { + uno::Reference< ucb::XContent > xContent + = m_pImpl->m_aResults[ nIndex ]->xContent; + if ( xContent.is() ) + { + // Already cached. + return xContent; + } + } + + uno::Reference< ucb::XContentIdentifier > xId + = queryContentIdentifier( nIndex ); + if ( xId.is() ) + { + try + { + uno::Reference< ucb::XContent > xContent + = m_pImpl->m_xContent->getProvider()->queryContent( xId ); + m_pImpl->m_aResults[ nIndex ]->xContent = xContent; + return xContent; + + } + catch ( ucb::IllegalIdentifierException& ) + { + } + } + return uno::Reference< ucb::XContent >(); +} + +//========================================================================= +// virtual +sal_Bool DataSupplier::getResult( sal_uInt32 nIndex ) +{ + osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( m_pImpl->m_aResults.size() > nIndex ) + { + // Result already present. + return sal_True; + } + + // Obtain values... + if ( getData() ) + { + if ( m_pImpl->m_aResults.size() > nIndex ) + { + // Result already present. + return sal_True; + } + } + + return sal_False; +} + +//========================================================================= +// virtual +sal_uInt32 DataSupplier::totalCount() +{ + // Obtain values... + getData(); + + return m_pImpl->m_aResults.size(); +} + +//========================================================================= +// virtual +sal_uInt32 DataSupplier::currentCount() +{ + return m_pImpl->m_aResults.size(); +} + +//========================================================================= +// virtual +sal_Bool DataSupplier::isCountFinal() +{ + return m_pImpl->m_bCountFinal; +} + +//========================================================================= +// virtual +uno::Reference< sdbc::XRow > DataSupplier::queryPropertyValues( + sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( nIndex < m_pImpl->m_aResults.size() ) + { + uno::Reference< sdbc::XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xRow; + if ( xRow.is() ) + { + // Already cached. + return xRow; + } + } + + if ( getResult( nIndex ) ) + { + uno::Reference< sdbc::XRow > xRow + = Content::getPropertyValues( + m_pImpl->m_xSMgr, + getResultSet()->getProperties(), + *(m_pImpl->m_aResults[ nIndex ]->pData), + rtl::Reference< ::ucbhelper::ContentProviderImplHelper >( + m_pImpl->m_xContent->getProvider().get() ), + queryContentIdentifierString( nIndex ) ); + m_pImpl->m_aResults[ nIndex ]->xRow = xRow; + return xRow; + } + + return uno::Reference< sdbc::XRow >(); +} + +//========================================================================= +// virtual +void DataSupplier::releasePropertyValues( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( nIndex < m_pImpl->m_aResults.size() ) + m_pImpl->m_aResults[ nIndex ]->xRow = uno::Reference< sdbc::XRow >(); +} + +//========================================================================= +// virtual +void DataSupplier::close() +{ +} + +//========================================================================= +// virtual +void DataSupplier::validate() + throw( ucb::ResultSetException ) +{ + if ( m_pImpl->m_bThrowException ) + throw ucb::ResultSetException(); +} + +//========================================================================= +sal_Bool DataSupplier::getData() +{ + osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( !m_pImpl->m_bCountFinal ) + { + std::vector< rtl::OUString > propertyNames; + ContentProperties::UCBNamesToDAVNames( + getResultSet()->getProperties(), propertyNames ); + + // Append "resourcetype", if not already present. It's value is + // needed to get a valid ContentProperties::pIsFolder value, which + // is needed for OpenMode handling. + + std::vector< rtl::OUString >::const_iterator it + = propertyNames.begin(); + std::vector< rtl::OUString >::const_iterator end + = propertyNames.end(); + + while ( it != end ) + { + if ( (*it).equals( DAVProperties::RESOURCETYPE ) ) + break; + + it++; + } + + if ( it == end ) + propertyNames.push_back( DAVProperties::RESOURCETYPE ); + + std::vector< DAVResource > resources; + try + { + // propfind depth 1, get property values for parent AND for each + // child + m_pImpl->m_xContent->getResourceAccess() + .PROPFIND( DAVONE, + propertyNames, + resources, + getResultSet()->getEnvironment() ); + } + catch ( DAVException & ) + { +// OSL_ENSURE( sal_False, "PROPFIND : DAVException" ); + m_pImpl->m_bThrowException = sal_True; + } + + if ( !m_pImpl->m_bThrowException ) + { + try + { + SerfUri aURI( + m_pImpl->m_xContent->getResourceAccess().getURL() ); + rtl::OUString aPath = aURI.GetPath(); + + if ( aPath.getStr()[ aPath.getLength() - 1 ] + == sal_Unicode( '/' ) ) + aPath = aPath.copy( 0, aPath.getLength() - 1 ); + + aPath = SerfUri::unescape( aPath ); + bool bFoundParent = false; + + for ( sal_uInt32 n = 0; n < resources.size(); ++n ) + { + const DAVResource & rRes = resources[ n ]; + + // Filter parent, which is contained somewhere(!) in + // the vector. + if ( !bFoundParent ) + { + try + { + SerfUri aCurrURI( rRes.uri ); + rtl::OUString aCurrPath = aCurrURI.GetPath(); + if ( aCurrPath.getStr()[ + aCurrPath.getLength() - 1 ] + == sal_Unicode( '/' ) ) + aCurrPath + = aCurrPath.copy( + 0, + aCurrPath.getLength() - 1 ); + + aCurrPath = SerfUri::unescape( aCurrPath ); + if ( aPath == aCurrPath ) + { + bFoundParent = true; + continue; + } + } + catch ( DAVException const & ) + { + // do nothing, ignore error. continue. + } + } + + ContentProperties* pContentProperties + = new ContentProperties( rRes ); + + // Check resource against open mode. + switch ( m_pImpl->m_nOpenMode ) + { + case ucb::OpenMode::FOLDERS: + { + sal_Bool bFolder = sal_False; + + const uno::Any & rValue + = pContentProperties->getValue( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "IsFolder" ) ) ); + rValue >>= bFolder; + + if ( !bFolder ) + continue; + + break; + } + + case ucb::OpenMode::DOCUMENTS: + { + sal_Bool bDocument = sal_False; + + const uno::Any & rValue + = pContentProperties->getValue( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "IsDocument" ) ) ); + rValue >>= bDocument; + + if ( !bDocument ) + continue; + + break; + } + + case ucb::OpenMode::ALL: + default: + break; + } + + m_pImpl->m_aResults.push_back( + new ResultListEntry( pContentProperties ) ); + } + } + catch ( DAVException const & ) + { + } + } + + m_pImpl->m_bCountFinal = sal_True; + + // Callback possible, because listeners may be informed! + aGuard.clear(); + getResultSet()->rowCountFinal(); + } + return !m_pImpl->m_bThrowException; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/webdavdatasupplier.hxx b/ucb/source/ucp/webdav/webdavdatasupplier.hxx new file mode 100644 index 000000000000..32db6aa01f1a --- /dev/null +++ b/ucb/source/ucp/webdav/webdavdatasupplier.hxx @@ -0,0 +1,78 @@ +/* -*- 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 _WEBDAV_UCP_DATASUPPLIER_HXX +#define _WEBDAV_UCP_DATASUPPLIER_HXX + +#include +#include +#include + +namespace http_dav_ucp { + +struct DataSupplier_Impl; +class Content; +struct DAVResource; +class ContentProperties; + +class DataSupplier : public ucbhelper::ResultSetDataSupplier +{ + DataSupplier_Impl* m_pImpl; + +private: + sal_Bool getData(); + +public: + DataSupplier( const com::sun::star::uno::Reference< + com::sun::star::lang::XMultiServiceFactory >& rxSMgr, + const rtl::Reference< Content >& rContent, + sal_Int32 nOpenMode); + + virtual ~DataSupplier(); + + virtual rtl::OUString queryContentIdentifierString( sal_uInt32 nIndex ); + virtual com::sun::star::uno::Reference< + com::sun::star::ucb::XContentIdentifier > + queryContentIdentifier( sal_uInt32 nIndex ); + virtual com::sun::star::uno::Reference< com::sun::star::ucb::XContent > + queryContent( sal_uInt32 nIndex ); + + virtual sal_Bool getResult( sal_uInt32 nIndex ); + + virtual sal_uInt32 totalCount(); + virtual sal_uInt32 currentCount(); + virtual sal_Bool isCountFinal(); + + virtual com::sun::star::uno::Reference< com::sun::star::sdbc::XRow > + queryPropertyValues( sal_uInt32 nIndex ); + virtual void releasePropertyValues( sal_uInt32 nIndex ); + + virtual void close(); + + virtual void validate() + throw( com::sun::star::ucb::ResultSetException ); +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/webdavprovider.cxx b/ucb/source/ucp/webdav/webdavprovider.cxx new file mode 100644 index 000000000000..318b9e952056 --- /dev/null +++ b/ucb/source/ucp/webdav/webdavprovider.cxx @@ -0,0 +1,225 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ +#include +#include "webdavprovider.hxx" +#include "webdavcontent.hxx" + +#include "osl/mutex.hxx" + +using namespace com::sun::star; +using namespace http_dav_ucp; + +//========================================================================= +//========================================================================= +// +// ContentProvider Implementation. +// +//========================================================================= +//========================================================================= + +ContentProvider::ContentProvider( + const uno::Reference< lang::XMultiServiceFactory >& rSMgr ) +: ::ucbhelper::ContentProviderImplHelper( rSMgr ), + m_xDAVSessionFactory( new DAVSessionFactory() ), + m_pProps( 0 ) +{ +} + +//========================================================================= +// virtual +ContentProvider::~ContentProvider() +{ + delete m_pProps; +} + +//========================================================================= +// +// XInterface methods. +// +//========================================================================= + +XINTERFACE_IMPL_3( ContentProvider, + lang::XTypeProvider, + lang::XServiceInfo, + ucb::XContentProvider ); + +//========================================================================= +// +// XTypeProvider methods. +// +//========================================================================= + +XTYPEPROVIDER_IMPL_3( ContentProvider, + lang::XTypeProvider, + lang::XServiceInfo, + ucb::XContentProvider ); + +//========================================================================= +// +// XServiceInfo methods. +// +//========================================================================= + +XSERVICEINFO_IMPL_1( ContentProvider, + rtl::OUString::createFromAscii( + "com.sun.star.comp.WebDAVContentProvider" ), + rtl::OUString::createFromAscii( + WEBDAV_CONTENT_PROVIDER_SERVICE_NAME ) ); + +//========================================================================= +// +// Service factory implementation. +// +//========================================================================= + +ONE_INSTANCE_SERVICE_FACTORY_IMPL( ContentProvider ); + +//========================================================================= +// +// XContentProvider methods. +// +//========================================================================= + +// virtual +uno::Reference< ucb::XContent > SAL_CALL +ContentProvider::queryContent( + const uno::Reference< + ucb::XContentIdentifier >& Identifier ) + throw( ucb::IllegalIdentifierException, + uno::RuntimeException ) +{ + // Check URL scheme... + + const rtl::OUString aScheme + = Identifier->getContentProviderScheme().toAsciiLowerCase(); + if ( !aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( HTTP_URL_SCHEME ) ) && + !aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( HTTPS_URL_SCHEME ) ) && + !aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) && + !aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) && + !aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) ) + throw ucb::IllegalIdentifierException(); + + // Normalize URL and create new Id, if nessacary. + rtl::OUString aURL = Identifier->getContentIdentifier(); + + // At least: + "://" + if ( aURL.getLength() < ( aScheme.getLength() + 3 ) ) + throw ucb::IllegalIdentifierException(); + + if ( ( aURL.getStr()[ aScheme.getLength() ] != sal_Unicode( ':' ) ) || + ( aURL.getStr()[ aScheme.getLength() + 1 ] != sal_Unicode( '/' ) ) || + ( aURL.getStr()[ aScheme.getLength() + 2 ] != sal_Unicode( '/' ) ) ) + throw ucb::IllegalIdentifierException(); + + uno::Reference< ucb::XContentIdentifier > xCanonicId; + + bool bNewId = false; + if ( aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) ) + { + aURL = aURL.replaceAt( 0, + WEBDAV_URL_SCHEME_LENGTH, + rtl::OUString::createFromAscii( + HTTP_URL_SCHEME ) ); + bNewId = true; + } + else if ( aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) ) + { + aURL = aURL.replaceAt( 0, + DAV_URL_SCHEME_LENGTH, + rtl::OUString::createFromAscii( + HTTP_URL_SCHEME ) ); + bNewId = true; + } + else if ( aScheme.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) ) + { + aURL = aURL.replaceAt( 0, + DAVS_URL_SCHEME_LENGTH, + rtl::OUString::createFromAscii( + HTTPS_URL_SCHEME ) ); + bNewId = true; + } + + sal_Int32 nPos = aURL.lastIndexOf( '/' ); + if ( nPos != aURL.getLength() - 1 ) + { + // Find second slash in URL. + nPos = aURL.indexOf( '/', aURL.indexOf( '/' ) + 1 ); + if ( nPos == -1 ) + throw ucb::IllegalIdentifierException(); + + nPos = aURL.indexOf( '/', nPos + 1 ); + if ( nPos == -1 ) + { + aURL += rtl::OUString::createFromAscii( "/" ); + bNewId = true; + } + } + + if ( bNewId ) + xCanonicId = new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ); + else + xCanonicId = Identifier; + + osl::MutexGuard aGuard( m_aMutex ); + + // Check, if a content with given id already exists... + uno::Reference< ucb::XContent > xContent + = queryExistingContent( xCanonicId ).get(); + if ( xContent.is() ) + return xContent; + + // Create a new content. + + try + { + xContent = new ::http_dav_ucp::Content( + m_xSMgr, this, xCanonicId, m_xDAVSessionFactory ); + registerNewContent( xContent ); + } + catch ( ucb::ContentCreationException const & ) + { + throw ucb::IllegalIdentifierException(); + } + + if ( !xContent->getIdentifier().is() ) + throw ucb::IllegalIdentifierException(); + + return xContent; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/webdavprovider.hxx b/ucb/source/ucp/webdav/webdavprovider.hxx new file mode 100644 index 000000000000..a09e420c91b2 --- /dev/null +++ b/ucb/source/ucp/webdav/webdavprovider.hxx @@ -0,0 +1,116 @@ +/* -*- 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 _WEBDAV_UCP_PROVIDER_HXX +#define _WEBDAV_UCP_PROVIDER_HXX + +#include +#include +#include "DAVSessionFactory.hxx" +#include +#include "PropertyMap.hxx" + +namespace http_dav_ucp { + +//========================================================================= + +// UNO service name for the provider. This name will be used by the UCB to +// create instances of the provider. +#define WEBDAV_CONTENT_PROVIDER_SERVICE_NAME \ + "com.sun.star.ucb.WebDAVContentProvider" +#define WEBDAV_CONTENT_PROVIDER_SERVICE_NAME_LENGTH 38 + +// URL scheme. This is the scheme the provider will be able to create +// contents for. The UCB will select the provider ( i.e. in order to create +// contents ) according to this scheme. +#define WEBDAV_URL_SCHEME \ + "vnd.sun.star.webdav" +#define WEBDAV_URL_SCHEME_LENGTH 19 + +#define HTTP_URL_SCHEME "http" +#define HTTP_URL_SCHEME_LENGTH 4 + +#define HTTPS_URL_SCHEME "https" +#define HTTPS_URL_SCHEME_LENGTH 5 + +#define DAV_URL_SCHEME "dav" +#define DAV_URL_SCHEME_LENGTH 3 + +#define DAVS_URL_SCHEME "davs" +#define DAVS_URL_SCHEME_LENGTH 4 + +#define HTTP_CONTENT_TYPE \ + "application/" HTTP_URL_SCHEME "-content" + +#define WEBDAV_CONTENT_TYPE HTTP_CONTENT_TYPE +#define WEBDAV_COLLECTION_TYPE \ + "application/" WEBDAV_URL_SCHEME "-collection" + +//========================================================================= + +class ContentProvider : public ::ucbhelper::ContentProviderImplHelper +{ + rtl::Reference< DAVSessionFactory > m_xDAVSessionFactory; + PropertyMap * m_pProps; + +public: + ContentProvider( const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& rSMgr ); + virtual ~ContentProvider(); + + // XInterface + XINTERFACE_DECL() + + // XTypeProvider + XTYPEPROVIDER_DECL() + + // XServiceInfo + XSERVICEINFO_DECL() + + // XContentProvider + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::ucb::XContent > SAL_CALL + queryContent( const ::com::sun::star::uno::Reference< + ::com::sun::star::ucb::XContentIdentifier >& Identifier ) + throw( ::com::sun::star::ucb::IllegalIdentifierException, + ::com::sun::star::uno::RuntimeException ); + + ////////////////////////////////////////////////////////////////////// + // Additional interfaces + ////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////// + // Non-interface methods. + ////////////////////////////////////////////////////////////////////// + + rtl::Reference< DAVSessionFactory > getDAVSessionFactory() + { return m_xDAVSessionFactory; } + + bool getProperty( const ::rtl::OUString & rPropName, + ::com::sun::star::beans::Property & rProp, + bool bStrict = false ); +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/webdavresponseparser.cxx b/ucb/source/ucp/webdav/webdavresponseparser.cxx new file mode 100644 index 000000000000..cc28ef1039da --- /dev/null +++ b/ucb/source/ucp/webdav/webdavresponseparser.cxx @@ -0,0 +1,888 @@ +/* -*- 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 . + */ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// +// WebDAVNamespace enum and StringToEnum converter + +namespace +{ + enum WebDAVNamespace + { + WebDAVNamespace_unknown = 0, + WebDAVNamespace_DAV, + WebDAVNamespace_ucb_openoffice_org_dav_props, + + WebDAVNamespace_last + }; + + WebDAVNamespace StrToWebDAVNamespace(const rtl::OUString& rStr) + { + static ::rtl::OUString aStrDAV(::rtl::OUString::createFromAscii("DAV:")); + static ::rtl::OUString aStrUcbOpenofficeOrgDAVProps(::rtl::OUString::createFromAscii("http://ucb.openoffice.org/dav/props/")); + + if(rStr.equals(aStrDAV)) + { + return WebDAVNamespace_DAV; + } + else if(rStr.equals(aStrUcbOpenofficeOrgDAVProps)) + { + return WebDAVNamespace_ucb_openoffice_org_dav_props; + } + + return WebDAVNamespace_unknown; + } +} // end of anonymous namespace + +////////////////////////////////////////////////////////////////////////////// +// WebDAVName enum and StringToEnum converter using hash_map + +namespace +{ + enum WebDAVName + { + WebDAVName_unknown = 0, + WebDAVName_multistatus, + WebDAVName_response, + WebDAVName_href, + WebDAVName_propstat, + WebDAVName_prop, + WebDAVName_resourcetype, + WebDAVName_collection, + WebDAVName_getcontenttype, + WebDAVName_supportedlock, + WebDAVName_lockentry, + WebDAVName_lockscope, + WebDAVName_exclusive, + WebDAVName_locktype, + WebDAVName_write, + WebDAVName_shared, + WebDAVName_status, + WebDAVName_getlastmodified, + WebDAVName_creationdate, + WebDAVName_getcontentlength, + + WebDAVName_last + }; + + WebDAVName StrToWebDAVName(const rtl::OUString& rStr) + { + typedef std::hash_map< rtl::OUString, WebDAVName, rtl::OUStringHash > WebDAVNameMapper; + typedef std::pair< rtl::OUString, WebDAVName > WebDAVNameValueType; + static WebDAVNameMapper aWebDAVNameMapperList; + + if(aWebDAVNameMapperList.empty()) + { + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("multistatus"), WebDAVName_multistatus)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("response"), WebDAVName_response)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("href"), WebDAVName_href)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("propstat"), WebDAVName_propstat)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("prop"), WebDAVName_prop)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("resourcetype"), WebDAVName_resourcetype)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("collection"), WebDAVName_collection)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("getcontenttype"), WebDAVName_getcontenttype)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("supportedlock"), WebDAVName_supportedlock)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("lockentry"), WebDAVName_lockentry)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("lockscope"), WebDAVName_lockscope)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("exclusive"), WebDAVName_exclusive)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("locktype"), WebDAVName_locktype)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("write"), WebDAVName_write)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("shared"), WebDAVName_shared)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("status"), WebDAVName_status)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("getlastmodified"), WebDAVName_getlastmodified)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("creationdate"), WebDAVName_creationdate)); + aWebDAVNameMapperList.insert(WebDAVNameValueType(rtl::OUString::createFromAscii("getcontentlength"), WebDAVName_getcontentlength)); + } + + const WebDAVNameMapper::const_iterator aResult(aWebDAVNameMapperList.find(rStr)); + + if(aResult == aWebDAVNameMapperList.end()) + { + return WebDAVName_unknown; + } + else + { + return aResult->second; + } + } +} // end of anonymous namespace + +////////////////////////////////////////////////////////////////////////////// +// WebDAVContext, holding information for each start/endElement pair + +namespace +{ + typedef std::map< ::rtl::OUString, ::rtl::OUString > NamespaceMap; + typedef std::pair< const ::rtl::OUString, ::rtl::OUString > NamespaceValueType; + + class WebDAVContext + { + private: + WebDAVContext* mpParent; + NamespaceMap maNamespaceMap; + ::rtl::OUString maWhiteSpace; + + ::rtl::OUString maNamespace; + ::rtl::OUString maName; + + WebDAVNamespace maWebDAVNamespace; + WebDAVName maWebDAVName; + + // local helpers + void parseForNamespaceTokens(const uno::Reference< xml::sax::XAttributeList >& xAttribs); + ::rtl::OUString mapNamespaceToken(const ::rtl::OUString& rToken) const; + void splitName(const ::rtl::OUString& rSource); + + public: + WebDAVContext(WebDAVContext* pParent, const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs); + ~WebDAVContext(); + + WebDAVContext* getParent() const { return mpParent; } + ::rtl::OUString& getWhiteSpace() { return maWhiteSpace; } + void setWhiteSpace(const ::rtl::OUString& rNew) { maWhiteSpace = rNew; } + + const ::rtl::OUString& getNamespace() const { return maNamespace; } + const ::rtl::OUString& getName() const { return maName; } + const WebDAVNamespace getWebDAVNamespace() const { return maWebDAVNamespace; } + const WebDAVName getWebDAVName() const { return maWebDAVName; } + }; + + void WebDAVContext::parseForNamespaceTokens(const uno::Reference< xml::sax::XAttributeList >& xAttribs) + { + const sal_Int16 nAttributes(xAttribs->getLength()); + static ::rtl::OUString aStrXmlns(::rtl::OUString::createFromAscii("xmlns")); + + for(sal_Int16 a(0); a < nAttributes; a++) + { + const ::rtl::OUString aName(xAttribs->getNameByIndex(a)); + const sal_Int32 nLen(aName.getLength()); + + if(nLen) + { + if(aName.match(aStrXmlns, 0)) + { + const sal_Int32 nIndex(aName.indexOf(sal_Unicode(':'), 0)); + + if(-1 != nIndex && nIndex + 1 < nLen) + { + const ::rtl::OUString aToken(aName.copy(nIndex + 1)); + + maNamespaceMap.insert(NamespaceValueType(aToken, xAttribs->getValueByIndex(a))); + } + } + } + } + } + + ::rtl::OUString WebDAVContext::mapNamespaceToken(const ::rtl::OUString& rToken) const + { + NamespaceMap::const_iterator iter = maNamespaceMap.find(rToken); + + if(maNamespaceMap.end() == iter) + { + if(getParent()) + { + return getParent()->mapNamespaceToken(rToken); + } + else + { + return rToken; + } + } + else + { + return (*iter).second; + } + } + + void WebDAVContext::splitName(const ::rtl::OUString& rSource) + { + const sal_Int32 nLen(rSource.getLength()); + maNamespace = ::rtl::OUString(); + maName = rSource; + + if(nLen) + { + const sal_Int32 nIndex(rSource.indexOf(sal_Unicode(':'), 0)); + + if(-1 != nIndex && nIndex > 0 && nIndex + 1 < nLen) + { + maNamespace = mapNamespaceToken(rSource.copy(0, nIndex)); + maName = rSource.copy(nIndex + 1); + } + } + } + + WebDAVContext::WebDAVContext(WebDAVContext* pParent, const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs) + : mpParent(pParent), + maNamespaceMap(), + maWhiteSpace(), + maNamespace(), + maName(), + maWebDAVNamespace(WebDAVNamespace_unknown), + maWebDAVName(WebDAVName_unknown) + { + const sal_Int16 nAttributes(xAttribs->getLength()); + + if(nAttributes) + { + // parse evtl. namespace entries + parseForNamespaceTokens(xAttribs); + } + + // split name to namespace and name + splitName(aName); + + // evaluate enums for namespace and name + maWebDAVNamespace = StrToWebDAVNamespace(maNamespace); + maWebDAVName = StrToWebDAVName(maName); + } + + WebDAVContext::~WebDAVContext() + { + } +} // end of anonymous namespace + +////////////////////////////////////////////////////////////////////////////// +// the Xml parser itself + +namespace +{ + enum WebDAVResponseParserMode + { + WebDAVResponseParserMode_PropFind = 0, + WebDAVResponseParserMode_PropName + }; + + class WebDAVResponseParser : public cppu::WeakImplHelper1< com::sun::star::xml::sax::XDocumentHandler > + { + private: + std::vector< http_dav_ucp::DAVResource > maResult_PropFind; + std::vector< http_dav_ucp::DAVResourceInfo > maResult_PropName; + + WebDAVContext* mpContext; + ::rtl::OUString maHref; + ::rtl::OUString maStatus; + std::vector< http_dav_ucp::DAVPropertyValue > maResponseProperties; + std::vector< http_dav_ucp::DAVPropertyValue > maPropStatProperties; + std::vector< ::rtl::OUString > maResponseNames; + std::vector< ::rtl::OUString > maPropStatNames; + uno::Sequence< ucb::LockEntry > maLockEntries; + ucb::LockScope maLockScope; + ucb::LockType maLockType; + WebDAVResponseParserMode meWebDAVResponseParserMode; + + // bitfield + bool mbResourceTypeCollection : 1; + bool mbLockScopeSet : 1; + bool mbLockTypeSet : 1; + + // local helpers + bool whitespaceIsAvailable() const + { + return mpContext && mpContext->getWhiteSpace().getLength(); + } + bool hasParent(WebDAVName aWebDAVName) const + { + return mpContext && mpContext->getParent() && aWebDAVName == mpContext->getParent()->getWebDAVName(); + } + bool propertyIsReady() const + { + return hasParent(WebDAVName_prop) && whitespaceIsAvailable(); + } + bool isCollectingProperties() const + { + return WebDAVResponseParserMode_PropFind == meWebDAVResponseParserMode; + } + bool isCollectingPropNames() const + { + return WebDAVResponseParserMode_PropName == meWebDAVResponseParserMode; + } + bool collectThisPropertyAsName() const + { + return isCollectingPropNames() && hasParent(WebDAVName_prop); + } + void pop_context() + { + if(mpContext) + { + WebDAVContext* pTemp = mpContext; + mpContext = mpContext->getParent(); + delete pTemp; + } + else + { + OSL_ENSURE(false, "Parser context pop without context (!)"); + } + } + + public: + WebDAVResponseParser(WebDAVResponseParserMode eWebDAVResponseParserMode); + ~WebDAVResponseParser(); + + // Methods XDocumentHandler + virtual void SAL_CALL startDocument( ) throw (xml::sax::SAXException, uno::RuntimeException); + virtual void SAL_CALL endDocument( ) throw (xml::sax::SAXException, uno::RuntimeException); + virtual void SAL_CALL startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException); + virtual void SAL_CALL endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException); + virtual void SAL_CALL characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException); + virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString& aWhitespaces ) throw (xml::sax::SAXException, uno::RuntimeException); + virtual void SAL_CALL processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) throw (xml::sax::SAXException, uno::RuntimeException); + virtual void SAL_CALL setDocumentLocator( const uno::Reference< xml::sax::XLocator >& xLocator ) throw (xml::sax::SAXException, uno::RuntimeException); + + const std::vector< http_dav_ucp::DAVResource >& getResult_PropFind() const { return maResult_PropFind; } + const std::vector< http_dav_ucp::DAVResourceInfo >& getResult_PropName() const { return maResult_PropName; } + }; + + WebDAVResponseParser::WebDAVResponseParser(WebDAVResponseParserMode eWebDAVResponseParserMode) + : maResult_PropFind(), + maResult_PropName(), + mpContext(0), + maHref(), + maStatus(), + maResponseProperties(), + maPropStatProperties(), + maResponseNames(), + maPropStatNames(), + maLockEntries(), + maLockScope(ucb::LockScope_EXCLUSIVE), + maLockType(ucb::LockType_WRITE), + meWebDAVResponseParserMode(eWebDAVResponseParserMode), + mbResourceTypeCollection(false), + mbLockScopeSet(false), + mbLockTypeSet(false) + { + } + + WebDAVResponseParser::~WebDAVResponseParser() + { + OSL_ENSURE(!mpContext, "Parser destructed with existing content (!)"); + while(mpContext) + { + pop_context(); + } + } + + void SAL_CALL WebDAVResponseParser::startDocument( ) throw (xml::sax::SAXException, uno::RuntimeException) + { + OSL_ENSURE(!mpContext, "Parser start with existing content (!)"); + } + + void SAL_CALL WebDAVResponseParser::endDocument( ) throw (xml::sax::SAXException, uno::RuntimeException) + { + OSL_ENSURE(!mpContext, "Parser end with existing content (!)"); + } + + void SAL_CALL WebDAVResponseParser::startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException) + { + const sal_Int32 nLen(aName.getLength()); + + if(nLen) + { + // create new context (push) + mpContext = new WebDAVContext(mpContext, aName, xAttribs); + + if(collectThisPropertyAsName()) + { + // When collecting property names and parent is prop there is no need + // to handle the content of this property deeper (evtl. preparations) + } + else + { + switch(mpContext->getWebDAVNamespace()) + { + default: // WebDAVNamespace_unknown, WebDAVNamespace_last or unhandled + { + break; + } + case WebDAVNamespace_DAV: + { + switch(mpContext->getWebDAVName()) + { + default: // WebDAVName_unknown, WebDAVName_last or unhandled + { + break; + } + case WebDAVName_propstat: + { + // propstat start + if(isCollectingProperties()) + { + // reset maPropStatProperties + maPropStatProperties.clear(); + } + else + { + // when collecting properties reset maPropStatNames + maPropStatNames.clear(); + } + break; + } + case WebDAVName_response: + { + // response start, reset Href and status and maResponseProperties + maHref = maStatus = ::rtl::OUString(); + + if(isCollectingProperties()) + { + // reset maResponseProperties + maResponseProperties.clear(); + } + else + { + // reset maResponseNames when collecting properties + maResponseNames.clear(); + } + break; + } + case WebDAVName_resourcetype: + { + // resourcetype start, reset collection + mbResourceTypeCollection = false; + break; + } + case WebDAVName_supportedlock: + { + // supportedlock start, reset maLockEntries + maLockEntries.realloc(0); + break; + } + case WebDAVName_lockentry: + { + // lockentry start, reset maLockEntries + mbLockScopeSet = false; + mbLockTypeSet = false; + break; + } + } + break; + } + case WebDAVNamespace_ucb_openoffice_org_dav_props: + { + break; + } + } + } + } + } + + void SAL_CALL WebDAVResponseParser::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException) + { + const sal_Int32 nLen(aName.getLength()); + OSL_ENSURE(mpContext, "Parser EndElement without content (!)"); + + if(mpContext && nLen) + { + if(collectThisPropertyAsName()) + { + // When collecting property names and parent is prop, just append the prop name + // to the collection, no need to parse deeper + maPropStatNames.push_back(mpContext->getNamespace() + mpContext->getName()); + } + else + { + switch(mpContext->getWebDAVNamespace()) + { + default: // WebDAVNamespace_unknown, WebDAVNamespace_last or unhandled + { + break; + } + case WebDAVNamespace_DAV: + { + switch(mpContext->getWebDAVName()) + { + default: // WebDAVName_unknown, WebDAVName_last or unhandled + { + break; + } + case WebDAVName_href: + { + // href end, save it if we have whitespace + if(whitespaceIsAvailable()) + { + maHref = mpContext->getWhiteSpace(); + } + break; + } + case WebDAVName_status: + { + // status end, save it if we have whitespace + if(whitespaceIsAvailable()) + { + maStatus = mpContext->getWhiteSpace(); + } + break; + } + case WebDAVName_getlastmodified: + { + // getlastmodified end, safe if content is correct + if(propertyIsReady()) + { + static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:getlastmodified")); + http_dav_ucp::DAVPropertyValue aDAVPropertyValue; + + aDAVPropertyValue.Name = aStr; + aDAVPropertyValue.Value <<= mpContext->getWhiteSpace(); + maPropStatProperties.push_back(aDAVPropertyValue); + } + break; + } + case WebDAVName_creationdate: + { + // creationdate end, safe if content is correct + if(propertyIsReady()) + { + static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:creationdate")); + http_dav_ucp::DAVPropertyValue aDAVPropertyValue; + + aDAVPropertyValue.Name = aStr; + aDAVPropertyValue.Value <<= mpContext->getWhiteSpace(); + maPropStatProperties.push_back(aDAVPropertyValue); + } + break; + } + case WebDAVName_collection: + { + // collection end, check and set + if(hasParent(WebDAVName_resourcetype)) + { + mbResourceTypeCollection = true; + } + break; + } + case WebDAVName_resourcetype: + { + // resourcetype end, check for collection + if(hasParent(WebDAVName_prop)) + { + static rtl::OUString aStrA(rtl::OUString::createFromAscii("DAV:resourcetype")); + static rtl::OUString aStrB(rtl::OUString::createFromAscii("collection")); + http_dav_ucp::DAVPropertyValue aDAVPropertyValue; + + aDAVPropertyValue.Name = aStrA; + aDAVPropertyValue.Value <<= (mbResourceTypeCollection ? aStrB : rtl::OUString()); + maPropStatProperties.push_back(aDAVPropertyValue); + } + break; + } + case WebDAVName_getcontentlength: + { + // getcontentlength end, safe if content is correct + if(propertyIsReady()) + { + static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:getcontentlength")); + http_dav_ucp::DAVPropertyValue aDAVPropertyValue; + + aDAVPropertyValue.Name = aStr; + aDAVPropertyValue.Value <<= mpContext->getWhiteSpace(); + maPropStatProperties.push_back(aDAVPropertyValue); + } + break; + } + case WebDAVName_getcontenttype: + { + // getcontenttype end, safe if content is correct + if(propertyIsReady()) + { + static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:getcontenttype")); + http_dav_ucp::DAVPropertyValue aDAVPropertyValue; + + aDAVPropertyValue.Name = aStr; + aDAVPropertyValue.Value <<= mpContext->getWhiteSpace(); + maPropStatProperties.push_back(aDAVPropertyValue); + } + break; + } + case WebDAVName_supportedlock: + { + // supportedlock end + if(hasParent(WebDAVName_prop) && maLockEntries.hasElements()) + { + static rtl::OUString aStr(rtl::OUString::createFromAscii("DAV:supportedlock")); + http_dav_ucp::DAVPropertyValue aDAVPropertyValue; + + aDAVPropertyValue.Name = aStr; + aDAVPropertyValue.Value <<= maLockEntries; + maPropStatProperties.push_back(aDAVPropertyValue); + } + break; + } + case WebDAVName_lockentry: + { + // lockentry end + if(hasParent(WebDAVName_supportedlock) && (mbLockScopeSet && mbLockTypeSet)) + { + const sal_Int32 nLength(maLockEntries.getLength()); + ucb::LockEntry aEntry; + + aEntry.Scope = maLockScope; + aEntry.Type = maLockType; + maLockEntries.realloc(nLength + 1); + maLockEntries[nLength] = aEntry; + } + break; + } + case WebDAVName_exclusive: + { + // exclusive lockscope end + if(hasParent(WebDAVName_lockscope)) + { + maLockScope = ucb::LockScope_EXCLUSIVE; + mbLockScopeSet = true; + } + break; + } + case WebDAVName_shared: + { + // shared lockscope end + if(hasParent(WebDAVName_lockscope)) + { + maLockScope = ucb::LockScope_SHARED; + mbLockScopeSet = true; + } + break; + } + case WebDAVName_write: + { + // write locktype end + if(hasParent(WebDAVName_locktype)) + { + maLockType = ucb::LockType_WRITE; + mbLockTypeSet = true; + } + break; + } + case WebDAVName_propstat: + { + // propstat end, check status + if(maStatus.getLength()) + { + static ::rtl::OUString aStrStatusOkay(::rtl::OUString::createFromAscii("HTTP/1.1 200 OK")); + + if(maStatus.equals(aStrStatusOkay)) + { + if(isCollectingProperties()) + { + if(maPropStatProperties.size()) + { + // append to maResponseProperties if okay + maResponseProperties.insert(maResponseProperties.end(), maPropStatProperties.begin(), maPropStatProperties.end()); + } + } + else + { + if(maPropStatNames.size()) + { + // when collecting properties append to + maResponseNames.insert(maResponseNames.end(), maPropStatNames.begin(), maPropStatNames.end()); + } + } + } + } + break; + } + case WebDAVName_response: + { + // respose end + if(maHref.getLength()) + { + if(isCollectingProperties()) + { + // create DAVResource when we have content + if(maResponseProperties.size()) + { + http_dav_ucp::DAVResource aDAVResource; + + aDAVResource.uri = maHref; + aDAVResource.properties = maResponseProperties; + maResult_PropFind.push_back(aDAVResource); + } + } + else + { + // when collecting properties add them to result when there are some + if(maResponseNames.size()) + { + http_dav_ucp::DAVResourceInfo aDAVResourceInfo(maHref); + + aDAVResourceInfo.properties = maResponseNames; + maResult_PropName.push_back(aDAVResourceInfo); + } + } + } + break; + } + } + break; + } + case WebDAVNamespace_ucb_openoffice_org_dav_props: + { + break; + } + } + } + + // destroy last context (pop) + pop_context(); + } + } + + void SAL_CALL WebDAVResponseParser::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException) + { + // collect whitespace over evtl. several calls in mpContext + OSL_ENSURE(mpContext, "Parser characters without content (!)"); + const sal_Int32 nLen(aChars.getLength()); + + if(mpContext && nLen) + { + // remove leading/trailing blanks and CRLF + const ::rtl::OUString aTrimmedChars(aChars.trim()); + + if(aTrimmedChars.getLength()) + { + ::rtl::OUString aNew(mpContext->getWhiteSpace()); + + if(aNew.getLength()) + { + // add one char when appending (see html1.1 spec) + aNew += ::rtl::OUString(sal_Unicode(' ')); + } + + aNew += aTrimmedChars; + mpContext->setWhiteSpace(aNew); + } + } + } + + void SAL_CALL WebDAVResponseParser::ignorableWhitespace( const ::rtl::OUString& /*aWhitespaces*/ ) throw (xml::sax::SAXException, uno::RuntimeException) + { + } + + void SAL_CALL WebDAVResponseParser::processingInstruction( const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/ ) throw (xml::sax::SAXException, uno::RuntimeException) + { + } + + void SAL_CALL WebDAVResponseParser::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& /*xLocator*/ ) throw (xml::sax::SAXException, uno::RuntimeException) + { + } +} // end of anonymous namespace + +////////////////////////////////////////////////////////////////////////////// +// wrapper for various calls to the parser + +namespace +{ + void parseWebDAVPropNameResponse( + const uno::Reference< io::XInputStream >& xInputStream, + std::vector< http_dav_ucp::DAVResource >& rPropFind, + std::vector< http_dav_ucp::DAVResourceInfo >& rPropName, + WebDAVResponseParserMode eWebDAVResponseParserMode) + { + if(xInputStream.is()) + { + try + { + // prepare ParserInputSrouce + xml::sax::InputSource myInputSource; + myInputSource.aInputStream = xInputStream; + + // get parser + uno::Reference< xml::sax::XParser > xParser( + comphelper::getProcessServiceFactory()->createInstance( + rtl::OUString::createFromAscii("com.sun.star.xml.sax.Parser") ), + uno::UNO_QUERY_THROW ); + + // create parser; connect parser and filter + WebDAVResponseParser* pWebDAVResponseParser = new WebDAVResponseParser(eWebDAVResponseParserMode); + uno::Reference< xml::sax::XDocumentHandler > xWebDAVHdl(pWebDAVResponseParser); + xParser->setDocumentHandler(xWebDAVHdl); + + // finally, parse the stream + xParser->parseStream(myInputSource); + + // get result + switch(eWebDAVResponseParserMode) + { + case WebDAVResponseParserMode_PropFind: + { + rPropFind = pWebDAVResponseParser->getResult_PropFind(); + break; + } + case WebDAVResponseParserMode_PropName: + { + rPropName = pWebDAVResponseParser->getResult_PropName(); + break; + } + } + } + catch(uno::Exception&) + { + OSL_ENSURE(false, "WebDAV Parse error (!)"); + } + } + } +} // end of anonymous namespace + +////////////////////////////////////////////////////////////////////////////// +// helper to parse a XML WebDAV response + +namespace http_dav_ucp +{ + std::vector< DAVResource > parseWebDAVPropFindResponse(const uno::Reference< io::XInputStream >& xInputStream) + { + std::vector< DAVResource > aRetval; + std::vector< DAVResourceInfo > aFoo; + + parseWebDAVPropNameResponse(xInputStream, aRetval, aFoo, WebDAVResponseParserMode_PropFind); + return aRetval; + } + + std::vector< DAVResourceInfo > parseWebDAVPropNameResponse(const uno::Reference< io::XInputStream >& xInputStream) + { + std::vector< DAVResource > aFoo; + std::vector< DAVResourceInfo > aRetval; + + parseWebDAVPropNameResponse(xInputStream, aFoo, aRetval, WebDAVResponseParserMode_PropName); + return aRetval; + } +} // namespace http_dav_ucp + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/webdavresponseparser.hxx b/ucb/source/ucp/webdav/webdavresponseparser.hxx new file mode 100644 index 000000000000..d59cb2ad7a53 --- /dev/null +++ b/ucb/source/ucp/webdav/webdavresponseparser.hxx @@ -0,0 +1,43 @@ +/* -*- 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 _WEBDAVRESPONSEPARSER_HXX_ +#define _WEBDAVRESPONSEPARSER_HXX_ + +#include +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////// + +namespace http_dav_ucp +{ + std::vector< DAVResource > parseWebDAVPropFindResponse(const com::sun::star::uno::Reference< com::sun::star::io::XInputStream >& xInputStream); + std::vector< DAVResourceInfo > parseWebDAVPropNameResponse(const com::sun::star::uno::Reference< com::sun::star::io::XInputStream >& xInputStream); +} // namespace http_dav_ucp + +////////////////////////////////////////////////////////////////////////////// + +#endif // _WEBDAVRESPONSEPARSER_HXX_ + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/webdavresultset.cxx b/ucb/source/ucp/webdav/webdavresultset.cxx new file mode 100644 index 000000000000..22232ebabfe7 --- /dev/null +++ b/ucb/source/ucp/webdav/webdavresultset.cxx @@ -0,0 +1,90 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" + +/************************************************************************** + TODO + ************************************************************************** + + - This implementation is not a dynamic result set!!! It only implements + the necessary interfaces, but never recognizes/notifies changes!!! + + *************************************************************************/ +#include "webdavresultset.hxx" +#ifndef _WEBDAV_SESSION_HXX +#include "DAVSession.hxx" +#endif + +using namespace com::sun::star; +using namespace http_dav_ucp; + +//========================================================================= +//========================================================================= +// +// DynamicResultSet Implementation. +// +//========================================================================= +//========================================================================= + +DynamicResultSet::DynamicResultSet( + const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, + const rtl::Reference< Content >& rxContent, + const ucb::OpenCommandArgument2& rCommand, + const uno::Reference< ucb::XCommandEnvironment >& rxEnv ) +: ResultSetImplHelper( rxSMgr, rCommand ), + m_xContent( rxContent ), + m_xEnv( rxEnv ) +{ +} + +//========================================================================= +// +// Non-interface methods. +// +//========================================================================= + +void DynamicResultSet::initStatic() +{ + m_xResultSet1 + = new ::ucbhelper::ResultSet( m_xSMgr, + m_aCommand.Properties, + new DataSupplier( m_xSMgr, + m_xContent, + m_aCommand.Mode ), + m_xEnv ); +} + +//========================================================================= +void DynamicResultSet::initDynamic() +{ + m_xResultSet1 + = new ::ucbhelper::ResultSet( m_xSMgr, + m_aCommand.Properties, + new DataSupplier( m_xSMgr, + m_xContent, + m_aCommand.Mode ), + m_xEnv ); + m_xResultSet2 = m_xResultSet1; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/webdavresultset.hxx b/ucb/source/ucp/webdav/webdavresultset.hxx new file mode 100644 index 000000000000..998867277308 --- /dev/null +++ b/ucb/source/ucp/webdav/webdavresultset.hxx @@ -0,0 +1,55 @@ +/* -*- 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 _WEBDAV_UCP_RESULTSET_HXX +#define _WEBDAV_UCP_RESULTSET_HXX + +#include +#include +#include "webdavcontent.hxx" +#include "webdavdatasupplier.hxx" + +namespace http_dav_ucp { + +class DynamicResultSet : public ::ucbhelper::ResultSetImplHelper +{ + rtl::Reference< Content > m_xContent; + com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > m_xEnv; + +private: + virtual void initStatic(); + virtual void initDynamic(); + +public: + DynamicResultSet( const com::sun::star::uno::Reference< + com::sun::star::lang::XMultiServiceFactory >& rxSMgr, + const rtl::Reference< Content >& rxContent, + const com::sun::star::ucb::OpenCommandArgument2& rCommand, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment >& rxEnv ); +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav/webdavservices.cxx b/ucb/source/ucp/webdav/webdavservices.cxx new file mode 100644 index 000000000000..fb8fd6e01bf9 --- /dev/null +++ b/ucb/source/ucp/webdav/webdavservices.cxx @@ -0,0 +1,71 @@ +/* -*- 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 . + */ + + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_ucb.hxx" +#include +#include +#include +#include "webdavprovider.hxx" + +using namespace com::sun::star; + +//========================================================================= +extern "C" void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +//========================================================================= +extern "C" void * SAL_CALL component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) +{ + void * pRet = 0; + + uno::Reference< lang::XMultiServiceFactory > xSMgr( + reinterpret_cast< lang::XMultiServiceFactory * >( + pServiceManager ) ); + uno::Reference< lang::XSingleServiceFactory > xFactory; + + ////////////////////////////////////////////////////////////////////// + // WebDAV Content Provider. + ////////////////////////////////////////////////////////////////////// + + if ( ::http_dav_ucp::ContentProvider::getImplementationName_Static(). + compareToAscii( pImplName ) == 0 ) + { + xFactory = ::http_dav_ucp::ContentProvider::createServiceFactory( xSMgr ); + } + + ////////////////////////////////////////////////////////////////////// + + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + + return pRet; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit