From 03ded70913f957460f90608465e4d0a182879074 Mon Sep 17 00:00:00 2001 From: Michael Meeks Date: Thu, 4 Oct 2012 17:17:53 +0100 Subject: rename ucb/source/ucp/webdav to webdav-neon --- ucb/source/ucp/webdav-neon/ContentProperties.cxx | 621 ++++ ucb/source/ucp/webdav-neon/ContentProperties.hxx | 224 ++ ucb/source/ucp/webdav-neon/DAVAuthListener.hxx | 55 + ucb/source/ucp/webdav-neon/DAVAuthListenerImpl.hxx | 80 + ucb/source/ucp/webdav-neon/DAVException.hxx | 169 ++ ucb/source/ucp/webdav-neon/DAVProperties.cxx | 187 ++ ucb/source/ucp/webdav-neon/DAVProperties.hxx | 65 + .../ucp/webdav-neon/DAVRequestEnvironment.hxx | 65 + ucb/source/ucp/webdav-neon/DAVResource.hxx | 70 + ucb/source/ucp/webdav-neon/DAVResourceAccess.cxx | 1237 ++++++++ ucb/source/ucp/webdav-neon/DAVResourceAccess.hxx | 259 ++ ucb/source/ucp/webdav-neon/DAVSession.hxx | 225 ++ ucb/source/ucp/webdav-neon/DAVSessionFactory.cxx | 107 + ucb/source/ucp/webdav-neon/DAVSessionFactory.hxx | 90 + ucb/source/ucp/webdav-neon/DAVTypes.hxx | 88 + ucb/source/ucp/webdav-neon/DateTimeHelper.cxx | 250 ++ ucb/source/ucp/webdav-neon/DateTimeHelper.hxx | 65 + ucb/source/ucp/webdav-neon/LinkSequence.cxx | 218 ++ ucb/source/ucp/webdav-neon/LinkSequence.hxx | 54 + ucb/source/ucp/webdav-neon/LockEntrySequence.cxx | 241 ++ ucb/source/ucp/webdav-neon/LockEntrySequence.hxx | 51 + ucb/source/ucp/webdav-neon/LockSequence.cxx | 366 +++ ucb/source/ucp/webdav-neon/LockSequence.hxx | 51 + ucb/source/ucp/webdav-neon/NeonHeadRequest.cxx | 134 + ucb/source/ucp/webdav-neon/NeonHeadRequest.hxx | 55 + ucb/source/ucp/webdav-neon/NeonInputStream.cxx | 195 ++ ucb/source/ucp/webdav-neon/NeonInputStream.hxx | 127 + ucb/source/ucp/webdav-neon/NeonLockStore.cxx | 246 ++ ucb/source/ucp/webdav-neon/NeonLockStore.hxx | 105 + ucb/source/ucp/webdav-neon/NeonPropFindRequest.cxx | 340 +++ ucb/source/ucp/webdav-neon/NeonPropFindRequest.hxx | 65 + ucb/source/ucp/webdav-neon/NeonSession.cxx | 2214 ++++++++++++++ ucb/source/ucp/webdav-neon/NeonSession.hxx | 300 ++ ucb/source/ucp/webdav-neon/NeonTypes.hxx | 49 + ucb/source/ucp/webdav-neon/NeonUri.cxx | 337 +++ ucb/source/ucp/webdav-neon/NeonUri.hxx | 105 + ucb/source/ucp/webdav-neon/PropertyMap.hxx | 68 + .../ucp/webdav-neon/UCBDeadPropertyValue.cxx | 522 ++++ .../ucp/webdav-neon/UCBDeadPropertyValue.hxx | 68 + ucb/source/ucp/webdav-neon/ucpdav1.component | 34 + .../ucp/webdav-neon/warnings_guard_ne_locks.h | 55 + ucb/source/ucp/webdav-neon/webdavcontent.cxx | 3170 ++++++++++++++++++++ ucb/source/ucp/webdav-neon/webdavcontent.hxx | 308 ++ ucb/source/ucp/webdav-neon/webdavcontentcaps.cxx | 656 ++++ ucb/source/ucp/webdav-neon/webdavdatasupplier.cxx | 506 ++++ ucb/source/ucp/webdav-neon/webdavdatasupplier.hxx | 83 + ucb/source/ucp/webdav-neon/webdavprovider.cxx | 214 ++ ucb/source/ucp/webdav-neon/webdavprovider.hxx | 127 + ucb/source/ucp/webdav-neon/webdavresultset.cxx | 93 + ucb/source/ucp/webdav-neon/webdavresultset.hxx | 62 + ucb/source/ucp/webdav-neon/webdavservices.cxx | 69 + 51 files changed, 15145 insertions(+) create mode 100644 ucb/source/ucp/webdav-neon/ContentProperties.cxx create mode 100644 ucb/source/ucp/webdav-neon/ContentProperties.hxx create mode 100644 ucb/source/ucp/webdav-neon/DAVAuthListener.hxx create mode 100644 ucb/source/ucp/webdav-neon/DAVAuthListenerImpl.hxx create mode 100644 ucb/source/ucp/webdav-neon/DAVException.hxx create mode 100644 ucb/source/ucp/webdav-neon/DAVProperties.cxx create mode 100644 ucb/source/ucp/webdav-neon/DAVProperties.hxx create mode 100644 ucb/source/ucp/webdav-neon/DAVRequestEnvironment.hxx create mode 100644 ucb/source/ucp/webdav-neon/DAVResource.hxx create mode 100644 ucb/source/ucp/webdav-neon/DAVResourceAccess.cxx create mode 100644 ucb/source/ucp/webdav-neon/DAVResourceAccess.hxx create mode 100644 ucb/source/ucp/webdav-neon/DAVSession.hxx create mode 100644 ucb/source/ucp/webdav-neon/DAVSessionFactory.cxx create mode 100644 ucb/source/ucp/webdav-neon/DAVSessionFactory.hxx create mode 100644 ucb/source/ucp/webdav-neon/DAVTypes.hxx create mode 100644 ucb/source/ucp/webdav-neon/DateTimeHelper.cxx create mode 100644 ucb/source/ucp/webdav-neon/DateTimeHelper.hxx create mode 100644 ucb/source/ucp/webdav-neon/LinkSequence.cxx create mode 100644 ucb/source/ucp/webdav-neon/LinkSequence.hxx create mode 100644 ucb/source/ucp/webdav-neon/LockEntrySequence.cxx create mode 100644 ucb/source/ucp/webdav-neon/LockEntrySequence.hxx create mode 100644 ucb/source/ucp/webdav-neon/LockSequence.cxx create mode 100644 ucb/source/ucp/webdav-neon/LockSequence.hxx create mode 100644 ucb/source/ucp/webdav-neon/NeonHeadRequest.cxx create mode 100644 ucb/source/ucp/webdav-neon/NeonHeadRequest.hxx create mode 100644 ucb/source/ucp/webdav-neon/NeonInputStream.cxx create mode 100644 ucb/source/ucp/webdav-neon/NeonInputStream.hxx create mode 100644 ucb/source/ucp/webdav-neon/NeonLockStore.cxx create mode 100644 ucb/source/ucp/webdav-neon/NeonLockStore.hxx create mode 100644 ucb/source/ucp/webdav-neon/NeonPropFindRequest.cxx create mode 100644 ucb/source/ucp/webdav-neon/NeonPropFindRequest.hxx create mode 100644 ucb/source/ucp/webdav-neon/NeonSession.cxx create mode 100644 ucb/source/ucp/webdav-neon/NeonSession.hxx create mode 100644 ucb/source/ucp/webdav-neon/NeonTypes.hxx create mode 100644 ucb/source/ucp/webdav-neon/NeonUri.cxx create mode 100644 ucb/source/ucp/webdav-neon/NeonUri.hxx create mode 100644 ucb/source/ucp/webdav-neon/PropertyMap.hxx create mode 100644 ucb/source/ucp/webdav-neon/UCBDeadPropertyValue.cxx create mode 100644 ucb/source/ucp/webdav-neon/UCBDeadPropertyValue.hxx create mode 100644 ucb/source/ucp/webdav-neon/ucpdav1.component create mode 100644 ucb/source/ucp/webdav-neon/warnings_guard_ne_locks.h create mode 100644 ucb/source/ucp/webdav-neon/webdavcontent.cxx create mode 100644 ucb/source/ucp/webdav-neon/webdavcontent.hxx create mode 100644 ucb/source/ucp/webdav-neon/webdavcontentcaps.cxx create mode 100644 ucb/source/ucp/webdav-neon/webdavdatasupplier.cxx create mode 100644 ucb/source/ucp/webdav-neon/webdavdatasupplier.hxx create mode 100644 ucb/source/ucp/webdav-neon/webdavprovider.cxx create mode 100644 ucb/source/ucp/webdav-neon/webdavprovider.hxx create mode 100644 ucb/source/ucp/webdav-neon/webdavresultset.cxx create mode 100644 ucb/source/ucp/webdav-neon/webdavresultset.hxx create mode 100644 ucb/source/ucp/webdav-neon/webdavservices.cxx (limited to 'ucb/source/ucp/webdav-neon') diff --git a/ucb/source/ucp/webdav-neon/ContentProperties.cxx b/ucb/source/ucp/webdav-neon/ContentProperties.cxx new file mode 100644 index 000000000000..dc9b03fe43cd --- /dev/null +++ b/ucb/source/ucp/webdav-neon/ContentProperties.cxx @@ -0,0 +1,621 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ +#include +#include +#include "NeonUri.hxx" +#include "DAVResource.hxx" +#include "DAVProperties.hxx" +#include "DateTimeHelper.hxx" +#include "webdavprovider.hxx" +#include "ContentProperties.hxx" + +using namespace com::sun::star; +using namespace webdav_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.isEmpty(), + "ContentProperties ctor - Empty resource URI!" ); + + // Title + try + { + NeonUri aURI( rResource.uri ); + m_aEscapedTitle = aURI.GetPathBaseName(); + + (*m_xProps)[ rtl::OUString("Title") ] + = PropertyValue( + uno::makeAny( aURI.GetPathBaseNameUnescaped() ), true ); + } + catch ( DAVException const & ) + { + (*m_xProps)[ rtl::OUString("Title") ] + = PropertyValue( + uno::makeAny( + rtl::OUString( + "*** 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("Title") ] + = PropertyValue( uno::makeAny( rTitle ), true ); + (*m_xProps)[ rtl::OUString("IsFolder") ] + = PropertyValue( uno::makeAny( bFolder ), true ); + (*m_xProps)[ rtl::OUString("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("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 == "Title" ) + { + // Title is always obtained from resource's URI. + continue; + } + else if ( rProp.Name == "DateCreated" || rProp.Name == DAVProperties::CREATIONDATE ) + { + if ( !bCreationDate ) + { + propertyNames.push_back( DAVProperties::CREATIONDATE ); + bCreationDate = sal_True; + } + } + else if ( rProp.Name == "DateModified" || rProp.Name == DAVProperties::GETLASTMODIFIED ) + { + if ( !bLastModified ) + { + propertyNames.push_back( + DAVProperties::GETLASTMODIFIED ); + bLastModified = sal_True; + } + } + else if ( rProp.Name == "MediaType" || rProp.Name == DAVProperties::GETCONTENTTYPE ) + { + if ( !bContentType ) + { + propertyNames.push_back( + DAVProperties::GETCONTENTTYPE ); + bContentType = sal_True; + } + } + else if ( rProp.Name == "Size" || rProp.Name == DAVProperties::GETCONTENTLENGTH ) + { + if ( !bContentLength ) + { + propertyNames.push_back( + DAVProperties::GETCONTENTLENGTH ); + bContentLength = sal_True; + } + } + else if ( rProp.Name == "ContentType" || rProp.Name == "IsDocument" || rProp.Name == "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 == "DateModified" ) + { + propertyNames.push_back( + rtl::OUString("Last-Modified") ); + } + else if ( rProp.Name == "MediaType" ) + { + propertyNames.push_back( + rtl::OUString("Content-Type") ); + } + else if ( rProp.Name == "Size" ) + { + propertyNames.push_back( + rtl::OUString("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.empty() ); +} + +//========================================================================= +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::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("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("Size") ] + = PropertyValue( uno::makeAny( aValue.toInt64() ), true ); + } + else if ( rName == "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("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("MediaType") ] + = PropertyValue( rValue, true ); + } + else if ( rName == "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("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("DateModified") ] + = PropertyValue( uno::makeAny( aDate ), true ); + } + else if ( rName == "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("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("IsFolder") ] + = PropertyValue( uno::makeAny( bFolder ), true ); + (*m_xProps)[ rtl::OUString("IsDocument") ] + = PropertyValue( uno::makeAny( sal_Bool( !bFolder ) ), true ); + (*m_xProps)[ rtl::OUString("ContentType") ] + = PropertyValue( uno::makeAny( bFolder + ? rtl::OUString( WEBDAV_COLLECTION_TYPE ) + : rtl::OUString( WEBDAV_CONTENT_TYPE ) ), true ); + } + // else if ( rName.equals( DAVProperties::SOURCE ) ) + // { + // } + // 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( "ETag" ), + + rtl::OUString( "DateModified" ), + rtl::OUString( "Last-Modified" ), + DAVProperties::GETLASTMODIFIED, + + rtl::OUString( "Size" ), + rtl::OUString( "Content-Length" ), + DAVProperties::GETCONTENTLENGTH, + + rtl::OUString( "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 ) +{ + SAL_WNODEPRECATED_DECLARATIONS_PUSH + const std::auto_ptr< PropertyValueMap > & props = rProps.getProperties(); + SAL_WNODEPRECATED_DECLARATIONS_POP + + 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-neon/ContentProperties.hxx b/ucb/source/ucp/webdav-neon/ContentProperties.hxx new file mode 100644 index 000000000000..4f64c016823a --- /dev/null +++ b/ucb/source/ucp/webdav-neon/ContentProperties.hxx @@ -0,0 +1,224 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#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 webdav_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 boost::unordered_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 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 webdav_ucp + +#endif /* !_WEBDAV_UCP_CONTENTPROPERTIES_HXX */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/DAVAuthListener.hxx b/ucb/source/ucp/webdav-neon/DAVAuthListener.hxx new file mode 100644 index 000000000000..7e4a34b56564 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/DAVAuthListener.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _DAVAUTHLISTENER_HXX_ +#define _DAVAUTHLISTENER_HXX_ + +#include +#include + +#include +#include + +namespace webdav_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 ) = 0; +}; + +} // namespace webdav_ucp + +#endif // _DAVAUTHLISTENER_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/DAVAuthListenerImpl.hxx b/ucb/source/ucp/webdav-neon/DAVAuthListenerImpl.hxx new file mode 100644 index 000000000000..db5f44655659 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/DAVAuthListenerImpl.hxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DAVAUTHLISTENERIMPL_HXX_ +#define _DAVAUTHLISTENERIMPL_HXX_ + +#include "DAVAuthListener.hxx" + + +namespace webdav_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 ); + 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-neon/DAVException.hxx b/ucb/source/ucp/webdav-neon/DAVException.hxx new file mode 100644 index 000000000000..376f7ff337ed --- /dev/null +++ b/ucb/source/ucp/webdav-neon/DAVException.hxx @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DAVEXCEPTION_HXX_ +#define _DAVEXCEPTION_HXX_ + +#include + +namespace webdav_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_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 ), 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 webdav_ucp + +#endif // _DAVEXCEPTION_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/DAVProperties.cxx b/ucb/source/ucp/webdav-neon/DAVProperties.cxx new file mode 100644 index 000000000000..4b89cef5dcdc --- /dev/null +++ b/ucb/source/ucp/webdav-neon/DAVProperties.cxx @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include +#include "DAVProperties.hxx" + +using namespace webdav_ucp; + +const ::rtl::OUString DAVProperties::CREATIONDATE("DAV:creationdate"); +const ::rtl::OUString DAVProperties::DISPLAYNAME("DAV:displayname"); +const ::rtl::OUString DAVProperties::GETCONTENTLANGUAGE("DAV:getcontentlanguage"); +const ::rtl::OUString DAVProperties::GETCONTENTLENGTH("DAV:getcontentlength"); +const ::rtl::OUString DAVProperties::GETCONTENTTYPE("DAV:getcontenttype"); +const ::rtl::OUString DAVProperties::GETETAG("DAV:getetag"); +const ::rtl::OUString DAVProperties::GETLASTMODIFIED("DAV:getlastmodified"); +const ::rtl::OUString DAVProperties::LOCKDISCOVERY("DAV:lockdiscovery"); +const ::rtl::OUString DAVProperties::RESOURCETYPE("DAV:resourcetype"); +const ::rtl::OUString DAVProperties::SOURCE("DAV:source"); +const ::rtl::OUString DAVProperties::SUPPORTEDLOCK("DAV:supportedlock"); + +const ::rtl::OUString DAVProperties::EXECUTABLE("http://apache.org/dav/props/executable"); + +// ------------------------------------------------------------------- +// static +void DAVProperties::createNeonPropName( const rtl::OUString & rFullName, + NeonPropName & 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 ).getStr() ); + } + 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 ).getStr() ); + } + 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 ).getStr() ); + } + else if ( rFullName.compareToAscii( RTL_CONSTASCII_STRINGPARAM( + " + + sal_Int32 nStart = RTL_CONSTASCII_LENGTH( " & xEnv ) + throw( DAVException ) +{ + initialize(); + + bool bRetry; + int errorCount = 0; + do + { + bRetry = false; + try + { + DAVRequestHeaders aHeaders; + getUserRequestHeaders( xEnv, + getRequestURI(), + rtl::OUString( "OPTIONS" ), + aHeaders ); + + m_xSession->OPTIONS( getRequestURI(), + rCapabilities, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} +#endif + +//========================================================================= +void DAVResourceAccess::PROPFIND( + const Depth nDepth, + const std::vector< rtl::OUString > & rPropertyNames, + std::vector< DAVResource > & rResources, + 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( "PROPFIND" ), + aHeaders ); + + m_xSession->PROPFIND( getRequestURI(), + nDepth, + rPropertyNames, + rResources, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +void DAVResourceAccess::PROPFIND( + const Depth nDepth, + std::vector< DAVResourceInfo > & rResInfo, + 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( "PROPFIND" ), + aHeaders ); + + m_xSession->PROPFIND( getRequestURI(), + nDepth, + rResInfo, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ) ; + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +void DAVResourceAccess::PROPPATCH( + const std::vector< ProppatchValue >& rValues, + 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( "PROPPATCH" ), + aHeaders ); + + m_xSession->PROPPATCH( getRequestURI(), + rValues, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +void DAVResourceAccess::HEAD( + const std::vector< rtl::OUString > & rHeaderNames, + DAVResource & rResource, + 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("HEAD"), + aHeaders ); + + m_xSession->HEAD( getRequestURI(), + rHeaderNames, + rResource, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +uno::Reference< io::XInputStream > DAVResourceAccess::GET( + const uno::Reference< ucb::XCommandEnvironment > & xEnv ) + throw( DAVException ) +{ + initialize(); + + uno::Reference< io::XInputStream > xStream; + int errorCount = 0; + bool bRetry; + do + { + bRetry = false; + try + { + DAVRequestHeaders aHeaders; + getUserRequestHeaders( xEnv, + getRequestURI(), + rtl::OUString("GET"), + aHeaders ); + + xStream = m_xSession->GET( getRequestURI(), + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( + xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); + + return xStream; +} + +//========================================================================= +void DAVResourceAccess::GET( + uno::Reference< io::XOutputStream > & rStream, + 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("GET"), + aHeaders ); + + m_xSession->GET( getRequestURI(), + rStream, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +uno::Reference< io::XInputStream > DAVResourceAccess::GET( + const std::vector< rtl::OUString > & rHeaderNames, + DAVResource & rResource, + const uno::Reference< ucb::XCommandEnvironment > & xEnv ) + throw( DAVException ) +{ + initialize(); + + uno::Reference< io::XInputStream > xStream; + int errorCount = 0; + bool bRetry; + do + { + bRetry = false; + try + { + DAVRequestHeaders aHeaders; + getUserRequestHeaders( xEnv, + getRequestURI(), + rtl::OUString("GET"), + aHeaders ); + + xStream = m_xSession->GET( getRequestURI(), + rHeaderNames, + rResource, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( + xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); + + return xStream; +} + +//========================================================================= +void DAVResourceAccess::GET( + uno::Reference< io::XOutputStream > & rStream, + const std::vector< rtl::OUString > & rHeaderNames, + DAVResource & rResource, + const uno::Reference< ucb::XCommandEnvironment > & xEnv ) + throw( DAVException ) +{ + initialize(); + + bool bRetry; + int errorCount = 0; + do + { + bRetry = false; + try + { + DAVRequestHeaders aHeaders; + getUserRequestHeaders( xEnv, + getRequestURI(), + rtl::OUString("GET"), + aHeaders ); + + m_xSession->GET( getRequestURI(), + rStream, + rHeaderNames, + rResource, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +void DAVResourceAccess::abort() + throw( DAVException ) +{ + // 17.11.09 (tkr): abort currently disabled caused by issue i106766 + // initialize(); + // m_xSession->abort(); + OSL_TRACE( "Not implemented. -> #i106766#" ); +} + +//========================================================================= +namespace { + + void resetInputStream( const uno::Reference< io::XInputStream > & rStream ) + throw( DAVException ) + { + try + { + uno::Reference< io::XSeekable > xSeekable( + rStream, uno::UNO_QUERY ); + if ( xSeekable.is() ) + { + xSeekable->seek( 0 ); + return; + } + } + catch ( lang::IllegalArgumentException const & ) + { + } + catch ( io::IOException const & ) + { + } + + throw DAVException( DAVException::DAV_INVALID_ARG ); + } + +} // namespace + +//========================================================================= +void DAVResourceAccess::PUT( + const uno::Reference< io::XInputStream > & rStream, + const uno::Reference< ucb::XCommandEnvironment > & xEnv ) + throw( DAVException ) +{ + initialize(); + + // Make stream seekable, if it not. Needed, if request must be retried. + uno::Reference< io::XInputStream > xSeekableStream + = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( + rStream, m_xSMgr ); + + int errorCount = 0; + bool bRetry = false; + do + { + if ( bRetry ) + resetInputStream( xSeekableStream ); + + bRetry = false; + try + { + DAVRequestHeaders aHeaders; + getUserRequestHeaders( xEnv, + getRequestURI(), + rtl::OUString("PUT"), + aHeaders ); + + m_xSession->PUT( getRequestURI(), + xSeekableStream, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +uno::Reference< io::XInputStream > DAVResourceAccess::POST( + const rtl::OUString & rContentType, + const rtl::OUString & rReferer, + const uno::Reference< io::XInputStream > & rInputStream, + const uno::Reference< ucb::XCommandEnvironment >& xEnv ) + throw ( DAVException ) +{ + initialize(); + + // Make stream seekable, if it not. Needed, if request must be retried. + uno::Reference< io::XInputStream > xSeekableStream + = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( + rInputStream, m_xSMgr ); + + uno::Reference< io::XInputStream > xStream; + int errorCount = 0; + bool bRetry = false; + do + { + if ( bRetry ) + { + resetInputStream( xSeekableStream ); + bRetry = false; + } + + try + { + DAVRequestHeaders aHeaders; + getUserRequestHeaders( xEnv, + getRequestURI(), + rtl::OUString("POST"), + aHeaders ); + + xStream = m_xSession->POST( getRequestURI(), + rContentType, + rReferer, + xSeekableStream, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( + xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + + if ( e.getError() == DAVException::DAV_HTTP_REDIRECT ) + { + // #i74980# - Upon POST redirect, do a GET. + return GET( xEnv ); + } + } + } + while ( bRetry ); + + return xStream; +} + +//========================================================================= +void DAVResourceAccess::POST( + const rtl::OUString & rContentType, + const rtl::OUString & rReferer, + const uno::Reference< io::XInputStream > & rInputStream, + uno::Reference< io::XOutputStream > & rOutputStream, + const uno::Reference< ucb::XCommandEnvironment >& xEnv ) + throw ( DAVException ) +{ + initialize(); + + // Make stream seekable, if it not. Needed, if request must be retried. + uno::Reference< io::XInputStream > xSeekableStream + = comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( + rInputStream, m_xSMgr ); + + int errorCount = 0; + bool bRetry = false; + do + { + if ( bRetry ) + { + resetInputStream( xSeekableStream ); + bRetry = false; + } + + try + { + DAVRequestHeaders aHeaders; + getUserRequestHeaders( xEnv, + getRequestURI(), + rtl::OUString("POST"), + aHeaders ); + + m_xSession->POST( getRequestURI(), + rContentType, + rReferer, + xSeekableStream, + rOutputStream, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + + if ( e.getError() == DAVException::DAV_HTTP_REDIRECT ) + { + // #i74980# - Upon POST redirect, do a GET. + GET( rOutputStream, xEnv ); + return; + } + } + } + while ( bRetry ); +} + +//========================================================================= +void DAVResourceAccess::MKCOL( + 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("MKCOL"), + aHeaders ); + + m_xSession->MKCOL( getRequestURI(), + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +void DAVResourceAccess::COPY( + const ::rtl::OUString & rSourcePath, + const ::rtl::OUString & rDestinationURI, + sal_Bool bOverwrite, + 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("COPY"), + aHeaders ); + + m_xSession->COPY( rSourcePath, + rDestinationURI, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ), + bOverwrite ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +void DAVResourceAccess::MOVE( + const ::rtl::OUString & rSourcePath, + const ::rtl::OUString & rDestinationURI, + sal_Bool bOverwrite, + 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("MOVE"), + aHeaders ); + + m_xSession->MOVE( rSourcePath, + rDestinationURI, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ), + bOverwrite ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +void DAVResourceAccess::DESTROY( + 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( "DESTROY" ), + aHeaders ); + + m_xSession->DESTROY( getRequestURI(), + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +// set new lock. +void DAVResourceAccess::LOCK( + ucb::Lock & inLock, + 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("LOCK"), + aHeaders ); + + m_xSession->LOCK( getRequestURI(), + inLock, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +#if 0 // currently not used, but please don't remove code +//========================================================================= +// refresh existing lock. +sal_Int64 DAVResourceAccess::LOCK( + sal_Int64 nTimeout, + const uno::Reference< ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ) +{ + initialize(); + + sal_Int64 nNewTimeout = 0; + int errorCount = 0; + bool bRetry; + do + { + bRetry = false; + try + { + DAVRequestHeaders aHeaders; + getUserRequestHeaders( xEnv, + getRequestURI(), + rtl::OUString("LOCK"), + aHeaders ); + + nNewTimeout = m_xSession->LOCK( getRequestURI(), + nTimeout, + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( + xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const 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("UNLOCK"), + aHeaders ); + + m_xSession->UNLOCK( getRequestURI(), + DAVRequestEnvironment( + getRequestURI(), + new DAVAuthListener_Impl( xEnv, m_aURL ), + aHeaders, xEnv ) ); + } + catch ( const DAVException & e ) + { + errorCount++; + bRetry = handleException( e, errorCount ); + if ( !bRetry ) + throw; + } + } + while ( bRetry ); +} + +//========================================================================= +void DAVResourceAccess::setFlags( const uno::Sequence< beans::NamedValue >& rFlags ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + m_aFlags = rFlags; +} + +//========================================================================= +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.isEmpty() ) + { + NeonUri aURI( m_aURL ); + rtl::OUString aPath( aURI.GetPath() ); + + /* #134089# - Check URI */ + if ( aPath.isEmpty() ) + throw DAVException( DAVException::DAV_INVALID_ARG ); + + /* #134089# - Check URI */ + if ( aURI.GetHost().isEmpty() ) + throw DAVException( DAVException::DAV_INVALID_ARG ); + + if ( !m_xSession.is() || !m_xSession->CanUse( m_aURL, m_aFlags ) ) + { + m_xSession.clear(); + + // create new webdav session + m_xSession + = m_xSessionFactory->createDAVSession( m_aURL, m_aFlags, 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 ) ); + } + } + } + + // Make sure a User-Agent header is always included, as at least + // en.wikipedia.org:80 forces back 403 "Scripts should use an informative + // User-Agent string with contact information, or they may be IP-blocked + // without notice" otherwise: + for ( DAVRequestHeaders::iterator i(rRequestHeaders.begin()); + i != rRequestHeaders.end(); ++i ) + { + if ( i->first.equalsIgnoreAsciiCase( "User-Agent" ) ) + { + return; + } + } + rRequestHeaders.push_back( + DAVRequestHeader( "User-Agent", "LibreOffice" ) ); +} + +//========================================================================= +sal_Bool DAVResourceAccess::detectRedirectCycle( + const rtl::OUString& rRedirectURL ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + NeonUri aUri( rRedirectURL ); + + std::vector< NeonUri >::const_iterator it = m_aRedirectURIs.begin(); + std::vector< NeonUri >::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.empty() ) + { + std::vector< NeonUri >::const_iterator it = m_aRedirectURIs.begin(); + + NeonUri aUri( (*it) ); + m_aRedirectURIs.clear(); + setURL ( aUri.GetURI() ); + initialize(); + } +} + +//========================================================================= +sal_Bool DAVResourceAccess::handleException( const 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; + // #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 ) && + errorCount < 3 ) + { + return sal_True; + } + return sal_False; + // 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-neon/DAVResourceAccess.hxx b/ucb/source/ucp/webdav-neon/DAVResourceAccess.hxx new file mode 100644 index 000000000000..30770b06e3c1 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/DAVResourceAccess.hxx @@ -0,0 +1,259 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DAVRESOURCEACCESS_HXX_ +#define _DAVRESOURCEACCESS_HXX_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "DAVAuthListener.hxx" +#include "DAVException.hxx" +#include "DAVSession.hxx" +#include "DAVResource.hxx" +#include "DAVTypes.hxx" +#include "NeonUri.hxx" + +namespace webdav_ucp +{ + +class DAVSessionFactory; + +class DAVResourceAccess +{ + osl::Mutex m_aMutex; + rtl::OUString m_aURL; + rtl::OUString m_aPath; + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > m_aFlags; + rtl::Reference< DAVSession > m_xSession; + rtl::Reference< DAVSessionFactory > m_xSessionFactory; + com::sun::star::uno::Reference< + com::sun::star::lang::XMultiServiceFactory > m_xSMgr; + std::vector< NeonUri > 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 setFlags( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rFlags ) + throw ( DAVException ); + + 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 + // + +#if 0 // currently not used, but please don't remove code + void + OPTIONS( DAVCapabilities & rCapabilities, + const com::sun::star::uno::Reference< + com::sun::star::ucb::XCommandEnvironment > & xEnv ) + throw ( DAVException ); +#endif + + // 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( const DAVException & e, int errorCount ) + throw ( DAVException ); + void initialize() + throw ( DAVException ); +}; + +} // namespace webdav_ucp + +#endif // _DAVRESOURCEACCESS_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/DAVSession.hxx b/ucb/source/ucp/webdav-neon/DAVSession.hxx new file mode 100644 index 000000000000..120879d91bf8 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/DAVSession.hxx @@ -0,0 +1,225 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#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 beans { + struct NamedValue; +} } } } + +namespace com { namespace sun { namespace star { namespace ucb { + struct Lock; +} } } } + +namespace webdav_ucp +{ + +class DAVSession +{ +public: + inline void acquire() SAL_THROW(()) + { + osl_atomic_increment( &m_nRefCount ); + } + + void release() SAL_THROW(()) + { + if ( osl_atomic_decrement( &m_nRefCount ) == 0 ) + { + m_xFactory->releaseElement( this ); + delete this; + } + } + + virtual sal_Bool CanUse( const ::rtl::OUString & inPath, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rFlags ) = 0; + + virtual sal_Bool UsesProxy() = 0; + + // DAV methods + // + + 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 webdav_ucp + +#endif // _DAVSESSION_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/DAVSessionFactory.cxx b/ucb/source/ucp/webdav-neon/DAVSessionFactory.cxx new file mode 100644 index 000000000000..661799ae58d8 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/DAVSessionFactory.cxx @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "DAVSessionFactory.hxx" +#include "NeonSession.hxx" +#include "NeonUri.hxx" +#include + +using namespace webdav_ucp; +using namespace com::sun::star; + +DAVSessionFactory::~DAVSessionFactory() +{ +} + +rtl::Reference< DAVSession > DAVSessionFactory::createDAVSession( + const ::rtl::OUString & inUri, + const uno::Sequence< beans::NamedValue >& rFlags, + 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, rFlags ) ) + break; + + ++aIt; + } + + if ( aIt == aEnd ) + { + NeonUri aURI( inUri ); + + std::auto_ptr< DAVSession > xElement( + new NeonSession( this, inUri, rFlags, *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_atomic_increment( &aIt->second->m_nRefCount ) > 1 ) + { + rtl::Reference< DAVSession > xElement( aIt->second ); + osl_atomic_decrement( &aIt->second->m_nRefCount ); + return xElement; + } + else + { + osl_atomic_decrement( &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: + NeonUri aURI( inUri ); + + aIt->second = new NeonSession( this, inUri, rFlags, *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-neon/DAVSessionFactory.hxx b/ucb/source/ucp/webdav-neon/DAVSessionFactory.hxx new file mode 100644 index 000000000000..4e642c42af86 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/DAVSessionFactory.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#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 beans { + struct NamedValue; +} } } } + +namespace com { namespace sun { namespace star { namespace lang { + class XMultiServiceFactory; +} } } } + +namespace webdav_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::Sequence< ::com::sun::star::beans::NamedValue >& rFlags, + 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 webdav_ucp + +#endif // _DAVSESSIONFACTORY_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/DAVTypes.hxx b/ucb/source/ucp/webdav-neon/DAVTypes.hxx new file mode 100644 index 000000000000..fcdfc2cda72c --- /dev/null +++ b/ucb/source/ucp/webdav-neon/DAVTypes.hxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DAVTYPES_HXX_ +#define _DAVTYPES_HXX_ + +#include +#include + +namespace webdav_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 webdav_ucp + +#endif // _DAVTYPES_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/DateTimeHelper.cxx b/ucb/source/ucp/webdav-neon/DateTimeHelper.cxx new file mode 100644 index 000000000000..f47e29714880 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/DateTimeHelper.cxx @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include +#include +#include +#include "DateTimeHelper.hxx" + +using namespace com::sun::star::util; + +using namespace webdav_ucp; + +using ::rtl::OUString; +using ::rtl::OString; + +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::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-neon/DateTimeHelper.hxx b/ucb/source/ucp/webdav-neon/DateTimeHelper.hxx new file mode 100644 index 000000000000..6964bc620a18 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/DateTimeHelper.hxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#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 webdav_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 webdav_ucp + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/LinkSequence.cxx b/ucb/source/ucp/webdav-neon/LinkSequence.cxx new file mode 100644 index 000000000000..26c5673eeab8 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/LinkSequence.cxx @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include +#include + +#include "LinkSequence.hxx" + +using namespace webdav_ucp; +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////// + +struct LinkSequenceParseContext +{ + ucb::Link * pLink; + bool hasSource; + bool hasDestination; + + LinkSequenceParseContext() + : pLink( 0 ), hasSource( false ), hasDestination( false ) {} + ~LinkSequenceParseContext() { delete pLink; } +}; + +#define STATE_TOP (1) + +#define STATE_LINK (STATE_TOP) +#define STATE_DST (STATE_TOP + 1) +#define STATE_SRC (STATE_TOP + 2) + +////////////////////////////////////////////////////////////////////////// +extern "C" int LinkSequence_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, "link" ) == 0 ) + return STATE_LINK; + break; + + case STATE_LINK: + if ( strcmp( name, "dst" ) == 0 ) + return STATE_DST; + else if ( strcmp( name, "src" ) == 0 ) + return STATE_SRC; + break; + } + } + return NE_XML_DECLINE; +} + +////////////////////////////////////////////////////////////////////////// +extern "C" int LinkSequence_chardata_callback( + void *userdata, + int state, + const char *buf, + size_t len ) +{ + LinkSequenceParseContext * pCtx + = static_cast< LinkSequenceParseContext * >( userdata ); + if ( !pCtx->pLink ) + pCtx->pLink = new ucb::Link; + + switch ( state ) + { + case STATE_DST: + pCtx->pLink->Destination + = rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US ); + pCtx->hasDestination = true; + break; + + case STATE_SRC: + pCtx->pLink->Source + = rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US ); + pCtx->hasSource = true; + break; + } + return 0; // zero to continue, non-zero to abort parsing +} + +////////////////////////////////////////////////////////////////////////// +extern "C" int LinkSequence_endelement_callback( + void *userdata, + int state, + const char *, + const char * ) +{ + LinkSequenceParseContext * pCtx + = static_cast< LinkSequenceParseContext * >( userdata ); + if ( !pCtx->pLink ) + pCtx->pLink = new ucb::Link; + + switch ( state ) + { + case STATE_LINK: + if ( !pCtx->hasDestination || !pCtx->hasSource ) + return 1; // abort + break; + } + return 0; // zero to continue, non-zero to abort parsing +} + +////////////////////////////////////////////////////////////////////////// +// static +bool LinkSequence::createFromXML( const rtl::OString & rInData, + uno::Sequence< ucb::Link > & rOutData ) +{ + const sal_Int32 TOKEN_LENGTH = 7; // + bool success = true; + + // rInData may contain multiple ... tags. + sal_Int32 nCount = 0; + sal_Int32 nStart = 0; + sal_Int32 nEnd = rInData.indexOf( "" ); + while ( nEnd > -1 ) + { + ne_xml_parser * parser = ne_xml_create(); + if ( !parser ) + { + success = false; + break; + } + + LinkSequenceParseContext aCtx; + ne_xml_push_handler( parser, + LinkSequence_startelement_callback, + LinkSequence_chardata_callback, + LinkSequence_endelement_callback, + &aCtx ); + + ne_xml_parse( parser, + rInData.getStr() + nStart, + nEnd - nStart + TOKEN_LENGTH ); + + success = !ne_xml_failed( parser ); + + ne_xml_destroy( parser ); + + if ( !success ) + break; + + if ( aCtx.pLink ) + { + nCount++; + if ( nCount > rOutData.getLength() ) + rOutData.realloc( rOutData.getLength() + 1 ); + + rOutData[ nCount - 1 ] = *aCtx.pLink; + } + + nStart = nEnd + TOKEN_LENGTH; + nEnd = rInData.indexOf( "", nStart ); + } + + return success; +} + +////////////////////////////////////////////////////////////////////////// +// static +bool LinkSequence::toXML( const uno::Sequence< ucb::Link > & rInData, + rtl::OUString & rOutData ) +{ + // valuevalue.... + + sal_Int32 nCount = rInData.getLength(); + if ( nCount ) + { + rtl::OUString aPre( "" ); + rtl::OUString aMid( "" ); + rtl::OUString aEnd( "" ); + + for ( sal_Int32 n = 0; n < nCount; ++n ) + { + rOutData += aPre; + rOutData += rInData[ n ].Source; + rOutData += aMid; + rOutData += rInData[ n ].Destination; + rOutData += aEnd; + } + return true; + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/LinkSequence.hxx b/ucb/source/ucp/webdav-neon/LinkSequence.hxx new file mode 100644 index 000000000000..109ea8de33dd --- /dev/null +++ b/ucb/source/ucp/webdav-neon/LinkSequence.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _LINKSEQUENCE_HXX_ +#define _LINKKSEQUENCE_HXX_ + +#include +#include +#include + +namespace webdav_ucp +{ + +class LinkSequence +{ +public: + static bool createFromXML( const rtl::OString & rInData, + com::sun::star::uno::Sequence< + com::sun::star::ucb::Link > & rOutData ); + static bool toXML( const com::sun::star::uno::Sequence< + com::sun::star::ucb::Link > & rInData, + rtl::OUString & rOutData ); +}; + +} + +#endif /* _LINKSEQUENCE_HXX_ */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/LockEntrySequence.cxx b/ucb/source/ucp/webdav-neon/LockEntrySequence.cxx new file mode 100644 index 000000000000..075af0132ee8 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/LockEntrySequence.cxx @@ -0,0 +1,241 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include +#include +#include "LockEntrySequence.hxx" + +using namespace webdav_ucp; +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////// + +struct LockEntrySequenceParseContext +{ + ucb::LockEntry * pEntry; + bool hasScope; + bool hasType; + + LockEntrySequenceParseContext() + : pEntry( 0 ), hasScope( false ), hasType( false ) {} + ~LockEntrySequenceParseContext() { delete pEntry; } +}; + +#define STATE_TOP (1) + +#define STATE_LOCKENTRY (STATE_TOP) +#define STATE_LOCKSCOPE (STATE_TOP + 1) +#define STATE_EXCLUSIVE (STATE_TOP + 2) +#define STATE_SHARED (STATE_TOP + 3) +#define STATE_LOCKTYPE (STATE_TOP + 4) +#define STATE_WRITE (STATE_TOP + 5) + +////////////////////////////////////////////////////////////////////////// +extern "C" int LockEntrySequence_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, "lockentry" ) == 0 ) + return STATE_LOCKENTRY; + break; + + case STATE_LOCKENTRY: + if ( strcmp( name, "lockscope" ) == 0 ) + return STATE_LOCKSCOPE; + else if ( strcmp( name, "locktype" ) == 0 ) + return STATE_LOCKTYPE; + +#define IIS_BUGS_WORKAROUND + +#ifdef IIS_BUGS_WORKAROUND + /* IIS (6) returns XML violating RFC 4918 + for DAV:supportedlock property value. + + + + + + + + + + + Bother... + */ + else if ( strcmp( name, "exclusive" ) == 0 ) + return STATE_EXCLUSIVE; + else if ( strcmp( name, "shared" ) == 0 ) + return STATE_SHARED; + else if ( strcmp( name, "write" ) == 0 ) + return STATE_WRITE; +#endif + break; + + case STATE_LOCKSCOPE: + if ( strcmp( name, "exclusive" ) == 0 ) + return STATE_EXCLUSIVE; + else if ( strcmp( name, "shared" ) == 0 ) + return STATE_SHARED; + break; + + case STATE_LOCKTYPE: + if ( strcmp( name, "write" ) == 0 ) + return STATE_WRITE; + break; + } + } + return NE_XML_DECLINE; +} + +////////////////////////////////////////////////////////////////////////// +extern "C" int LockEntrySequence_chardata_callback( + void *, + int, + const char *, + size_t ) +{ + return 0; // zero to continue, non-zero to abort parsing +} + +////////////////////////////////////////////////////////////////////////// +extern "C" int LockEntrySequence_endelement_callback( + void *userdata, + int state, + const char *, + const char * ) +{ + LockEntrySequenceParseContext * pCtx + = static_cast< LockEntrySequenceParseContext * >( userdata ); + if ( !pCtx->pEntry ) + pCtx->pEntry = new ucb::LockEntry; + + switch ( state ) + { + case STATE_EXCLUSIVE: + pCtx->pEntry->Scope = ucb::LockScope_EXCLUSIVE; + pCtx->hasScope = true; + break; + + case STATE_SHARED: + pCtx->pEntry->Scope = ucb::LockScope_SHARED; + pCtx->hasScope = true; + break; + + case STATE_WRITE: + pCtx->pEntry->Type = ucb::LockType_WRITE; + pCtx->hasType = true; + break; + + case STATE_LOCKSCOPE: + if ( !pCtx->hasScope ) + return 1; // abort + break; + + case STATE_LOCKTYPE: + if ( !pCtx->hasType ) + return 1; // abort + break; + + case STATE_LOCKENTRY: + if ( !pCtx->hasType || !pCtx->hasScope ) + return 1; // abort + break; + + default: + break; + } + return 0; // zero to continue, non-zero to abort parsing +} + +////////////////////////////////////////////////////////////////////////// +// static +bool LockEntrySequence::createFromXML( const rtl::OString & rInData, + uno::Sequence< + ucb::LockEntry > & rOutData ) +{ + const sal_Int32 TOKEN_LENGTH = 12; // + bool success = true; + + // rInData may contain multiple ... tags. + sal_Int32 nCount = 0; + sal_Int32 nStart = 0; + sal_Int32 nEnd = rInData.indexOf( "" ); + while ( nEnd > -1 ) + { + ne_xml_parser * parser = ne_xml_create(); + if ( !parser ) + { + success = false; + break; + } + + LockEntrySequenceParseContext aCtx; + ne_xml_push_handler( parser, + LockEntrySequence_startelement_callback, + LockEntrySequence_chardata_callback, + LockEntrySequence_endelement_callback, + &aCtx ); + + ne_xml_parse( parser, + rInData.getStr() + nStart, + nEnd - nStart + TOKEN_LENGTH ); + + success = !ne_xml_failed( parser ); + + ne_xml_destroy( parser ); + + if ( !success ) + break; + + if ( aCtx.pEntry ) + { + nCount++; + if ( nCount > rOutData.getLength() ) + rOutData.realloc( rOutData.getLength() + 2 ); + + rOutData[ nCount - 1 ] = *aCtx.pEntry; + } + + nStart = nEnd + TOKEN_LENGTH; + nEnd = rInData.indexOf( "", nStart ); + } + + rOutData.realloc( nCount ); + return success; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/LockEntrySequence.hxx b/ucb/source/ucp/webdav-neon/LockEntrySequence.hxx new file mode 100644 index 000000000000..7c91f4e6cf23 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/LockEntrySequence.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _LOCKENTRYSEQUENCE_HXX_ +#define _LOCKENTRYSEQUENCE_HXX_ + +#include +#include +#include + +namespace webdav_ucp +{ + +class LockEntrySequence +{ +public: + static bool createFromXML( const rtl::OString & rInData, + com::sun::star::uno::Sequence< + com::sun::star::ucb::LockEntry > & rOutData ); +}; + +} + +#endif /* _LOCKENTRYSEQUENCE_HXX_ */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/LockSequence.cxx b/ucb/source/ucp/webdav-neon/LockSequence.cxx new file mode 100644 index 000000000000..3b31b1f9fa11 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/LockSequence.cxx @@ -0,0 +1,366 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include +#include +#include "LockSequence.hxx" + +using namespace webdav_ucp; +using namespace com::sun::star; + +#define BEEHIVE_BUGS_WORKAROUND + +////////////////////////////////////////////////////////////////////////// + +struct LockSequenceParseContext +{ + ucb::Lock * pLock; + bool hasLockScope; + bool hasLockType; + bool hasDepth; + bool hasHREF; + bool hasTimeout; + + LockSequenceParseContext() + : pLock( 0 ), hasLockScope( false ), hasLockType( false ), + hasDepth( false ), hasHREF( false ), hasTimeout( false ) {} + + ~LockSequenceParseContext() { delete pLock; } +}; + +#define STATE_TOP (1) + +#define STATE_ACTIVELOCK (STATE_TOP) +#define STATE_LOCKSCOPE (STATE_TOP + 1) +#define STATE_LOCKTYPE (STATE_TOP + 2) +#define STATE_DEPTH (STATE_TOP + 3) +#define STATE_OWNER (STATE_TOP + 4) +#define STATE_TIMEOUT (STATE_TOP + 5) +#define STATE_LOCKTOKEN (STATE_TOP + 6) +#define STATE_EXCLUSIVE (STATE_TOP + 7) +#define STATE_SHARED (STATE_TOP + 8) +#define STATE_WRITE (STATE_TOP + 9) +#define STATE_HREF (STATE_TOP + 10) + +////////////////////////////////////////////////////////////////////////// +extern "C" int LockSequence_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, "activelock" ) == 0 ) + return STATE_ACTIVELOCK; + break; + + case STATE_ACTIVELOCK: + if ( strcmp( name, "lockscope" ) == 0 ) + return STATE_LOCKSCOPE; + else if ( strcmp( name, "locktype" ) == 0 ) + return STATE_LOCKTYPE; + else if ( strcmp( name, "depth" ) == 0 ) + return STATE_DEPTH; + else if ( strcmp( name, "owner" ) == 0 ) + return STATE_OWNER; + else if ( strcmp( name, "timeout" ) == 0 ) + return STATE_TIMEOUT; + else if ( strcmp( name, "locktoken" ) == 0 ) + return STATE_LOCKTOKEN; + break; + + case STATE_LOCKSCOPE: + if ( strcmp( name, "exclusive" ) == 0 ) + return STATE_EXCLUSIVE; + else if ( strcmp( name, "shared" ) == 0 ) + return STATE_SHARED; + break; + + case STATE_LOCKTYPE: + if ( strcmp( name, "write" ) == 0 ) + return STATE_WRITE; + break; + + case STATE_LOCKTOKEN: + if ( strcmp( name, "href" ) == 0 ) + return STATE_HREF; + break; + + case STATE_OWNER: + // owner elem contains ANY. Accept anything; no state change. + return STATE_OWNER; + } + } + return NE_XML_DECLINE; +} + +////////////////////////////////////////////////////////////////////////// +extern "C" int LockSequence_chardata_callback( + void *userdata, + int state, +#ifdef BEEHIVE_BUGS_WORKAROUND + const char *buf1, +#else + const char *buf, +#endif + size_t len ) +{ + LockSequenceParseContext * pCtx + = static_cast< LockSequenceParseContext * >( userdata ); + if ( !pCtx->pLock ) + pCtx->pLock = new ucb::Lock; + +#ifdef BEEHIVE_BUGS_WORKAROUND + // Beehive sends XML values containing trailing newlines. + if ( buf1[ len - 1 ] == 0x0a ) + len--; + + char * buf = new char[ len + 1 ](); + strncpy( buf, buf1, len ); +#endif + + switch ( state ) + { + case STATE_DEPTH: + if ( rtl_str_compareIgnoreAsciiCase_WithLength( + buf, len, "0", 1 ) == 0 ) + { + pCtx->pLock->Depth = ucb::LockDepth_ZERO; + pCtx->hasDepth = true; + } + else if ( rtl_str_compareIgnoreAsciiCase_WithLength( + buf, len, "1", 1 ) == 0 ) + { + pCtx->pLock->Depth = ucb::LockDepth_ONE; + pCtx->hasDepth = true; + } + else if ( rtl_str_compareIgnoreAsciiCase_WithLength( + buf, len, "infinity", 8 ) == 0 ) + { + pCtx->pLock->Depth = ucb::LockDepth_INFINITY; + pCtx->hasDepth = true; + } + else + OSL_FAIL( "LockSequence_chardata_callback - Unknown depth!" ); + break; + + case STATE_OWNER: + { + // collect raw XML data... (owner contains ANY) + rtl::OUString aValue; + pCtx->pLock->Owner >>= aValue; + aValue += rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US ); + pCtx->pLock->Owner <<= aValue; + break; + } + + case STATE_TIMEOUT: + // + // RFC2518, RFC2616: + // + // TimeType = ("Second-" DAVTimeOutVal | "Infinite" | Other) + // DAVTimeOutVal = 1*digit + // Other = "Extend" field-value + // field-value = *( field-content | LWS ) + // field-content = + + if ( rtl_str_compareIgnoreAsciiCase_WithLength( + buf, len, "Infinite", 8 ) == 0 ) + { + pCtx->pLock->Timeout = sal_Int64( -1 ); + pCtx->hasTimeout = true; + } + else if ( rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( + buf, len, "Second-", 7, 7 ) == 0 ) + { + pCtx->pLock->Timeout + = rtl::OString( buf + 7, len - 7 ).toInt64(); + pCtx->hasTimeout = true; + } +// else if ( rtl_str_shortenedCompareIgnoreCase_WithLength( +// buf, len, "Extend", 6, 6 ) == 0 ) +// { +// @@@ +// } + else + { + pCtx->pLock->Timeout = sal_Int64( -1 ); + pCtx->hasTimeout = true; + OSL_FAIL( "LockSequence_chardata_callback - Unknown timeout!" ); + } + break; + + case STATE_HREF: + { + // collect hrefs. + sal_Int32 nPos = pCtx->pLock->LockTokens.getLength(); + pCtx->pLock->LockTokens.realloc( nPos + 1 ); + pCtx->pLock->LockTokens[ nPos ] + = rtl::OUString( buf, len, RTL_TEXTENCODING_ASCII_US ); + pCtx->hasHREF = true; + break; + } + + } + +#ifdef BEEHIVE_BUGS_WORKAROUND + delete [] buf; +#endif + + return 0; // zero to continue, non-zero to abort parsing +} + +////////////////////////////////////////////////////////////////////////// +extern "C" int LockSequence_endelement_callback( + void *userdata, + int state, + const char *, + const char * ) +{ + LockSequenceParseContext * pCtx + = static_cast< LockSequenceParseContext * >( userdata ); + if ( !pCtx->pLock ) + pCtx->pLock = new ucb::Lock; + + switch ( state ) + { + case STATE_EXCLUSIVE: + pCtx->pLock->Scope = ucb::LockScope_EXCLUSIVE; + pCtx->hasLockScope = true; + break; + + case STATE_SHARED: + pCtx->pLock->Scope = ucb::LockScope_SHARED; + pCtx->hasLockScope = true; + break; + + case STATE_WRITE: + pCtx->pLock->Type = ucb::LockType_WRITE; + pCtx->hasLockType = true; + break; + + case STATE_DEPTH: + if ( !pCtx->hasDepth ) + return 1; // abort + break; + + case STATE_HREF: + if ( !pCtx->hasHREF ) + return 1; // abort + break; + + case STATE_TIMEOUT: + if ( !pCtx->hasTimeout ) + return 1; // abort + break; + + case STATE_LOCKSCOPE: + if ( !pCtx->hasLockScope ) + return 1; // abort + break; + + case STATE_LOCKTYPE: + if ( !pCtx->hasLockType ) + return 1; // abort + break; + + case STATE_ACTIVELOCK: + if ( !pCtx->hasLockType || !pCtx->hasDepth ) + return 1; // abort + break; + + default: + break; + } + return 0; // zero to continue, non-zero to abort parsing +} + +////////////////////////////////////////////////////////////////////////// +// static +bool LockSequence::createFromXML( const rtl::OString & rInData, + uno::Sequence< ucb::Lock > & rOutData ) +{ + const sal_Int32 TOKEN_LENGTH = 13; // + bool success = true; + + // rInData may contain multiple ... tags. + sal_Int32 nCount = 0; + sal_Int32 nStart = 0; + sal_Int32 nEnd = rInData.indexOf( "" ); + while ( nEnd > -1 ) + { + ne_xml_parser * parser = ne_xml_create(); + if ( !parser ) + { + success = false; + break; + } + + LockSequenceParseContext aCtx; + ne_xml_push_handler( parser, + LockSequence_startelement_callback, + LockSequence_chardata_callback, + LockSequence_endelement_callback, + &aCtx ); + + ne_xml_parse( parser, + rInData.getStr() + nStart, + nEnd - nStart + TOKEN_LENGTH ); + + success = !ne_xml_failed( parser ); + + ne_xml_destroy( parser ); + + if ( !success ) + break; + + if ( aCtx.pLock ) + { + nCount++; + if ( nCount > rOutData.getLength() ) + rOutData.realloc( rOutData.getLength() + 1 ); + + rOutData[ nCount - 1 ] = *aCtx.pLock; + } + + nStart = nEnd + TOKEN_LENGTH; + nEnd = rInData.indexOf( "", nStart ); + } + + return success; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/LockSequence.hxx b/ucb/source/ucp/webdav-neon/LockSequence.hxx new file mode 100644 index 000000000000..746d72176c73 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/LockSequence.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _LOCKSEQUENCE_HXX_ +#define _LOCKSEQUENCE_HXX_ + +#include +#include +#include + +namespace webdav_ucp +{ + +class LockSequence +{ +public: + static bool createFromXML( const rtl::OString & rInData, + com::sun::star::uno::Sequence< + com::sun::star::ucb::Lock > & rOutData ); +}; + +} + +#endif /* _LOCKSEQUENCE_HXX_ */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/NeonHeadRequest.cxx b/ucb/source/ucp/webdav-neon/NeonHeadRequest.cxx new file mode 100644 index 000000000000..2db9be5314be --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonHeadRequest.cxx @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include +#include +#include +#include "NeonHeadRequest.hxx" + +using namespace webdav_ucp; +using namespace com::sun::star; + +namespace { + +void process_headers( ne_request * req, + DAVResource & rResource, + const std::vector< ::rtl::OUString > & rHeaderNames ) +{ + void * cursor = NULL; + const char * name, *value; + + while ( ( cursor = ne_response_header_iterate( req, cursor, + &name, &value ) ) != NULL ) { + rtl::OUString aHeaderName( rtl::OUString::createFromAscii( name ) ); + rtl::OUString aHeaderValue( rtl::OUString::createFromAscii( value ) ); + + // Note: Empty vector means that all headers are requested. + bool bIncludeIt = ( rHeaderNames.empty() ); + + if ( !bIncludeIt ) + { + // Check whether this header was requested. + std::vector< ::rtl::OUString >::const_iterator it( + rHeaderNames.begin() ); + const std::vector< ::rtl::OUString >::const_iterator end( + rHeaderNames.end() ); + + while ( it != end ) + { + if ( (*it) == aHeaderName ) + break; + + ++it; + } + + if ( it != end ) + bIncludeIt = true; + } + + if ( bIncludeIt ) + { + // Create & set the PropertyValue + DAVPropertyValue thePropertyValue; + thePropertyValue.Name = aHeaderName; + thePropertyValue.IsCaseSensitive = false; + thePropertyValue.Value <<= aHeaderValue; + + // Add the newly created PropertyValue + rResource.properties.push_back( thePropertyValue ); + } + } +} + +} // namespace + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- + +extern osl::Mutex aGlobalNeonMutex; + +NeonHeadRequest::NeonHeadRequest( HttpSession * inSession, + const rtl::OUString & inPath, + const std::vector< ::rtl::OUString > & + inHeaderNames, + DAVResource & ioResource, + int & nError ) +{ + ioResource.uri = inPath; + ioResource.properties.clear(); + + // Create and dispatch HEAD request. Install catcher for all response + // header fields. + ne_request * req = ne_request_create( inSession, + "HEAD", + rtl::OUStringToOString( + inPath, + RTL_TEXTENCODING_UTF8 ).getStr() ); + + { + osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex ); + nError = ne_request_dispatch( req ); + } + + process_headers( req, ioResource, inHeaderNames ); + + if ( nError == NE_OK && ne_get_status( req )->klass != 2 ) + nError = NE_ERROR; + + ne_request_destroy( req ); +} + +// ------------------------------------------------------------------- +// Destructor +// ------------------------------------------------------------------- +NeonHeadRequest::~NeonHeadRequest() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/NeonHeadRequest.hxx b/ucb/source/ucp/webdav-neon/NeonHeadRequest.hxx new file mode 100644 index 000000000000..b0a9fea47c53 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonHeadRequest.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _NEONHEADREQUEST_HXX_ +#define _NEONHEADREQUEST_HXX_ + +#include +#include "NeonTypes.hxx" +#include "DAVResource.hxx" + +namespace webdav_ucp +{ + +class NeonHeadRequest +{ +public: + // named / allprop + NeonHeadRequest( HttpSession* inSession, + const rtl::OUString & inPath, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource, + int & nError ); + ~NeonHeadRequest(); +}; + +} // namespace webdav_ucp + +#endif // _NEONHEADREQUEST_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/NeonInputStream.cxx b/ucb/source/ucp/webdav-neon/NeonInputStream.cxx new file mode 100644 index 000000000000..882fa2520b4f --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonInputStream.cxx @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include + +#include "NeonInputStream.hxx" + +using namespace cppu; +using namespace com::sun::star::io; +using namespace com::sun::star::uno; +using namespace webdav_ucp; + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +NeonInputStream::NeonInputStream( void ) +: mLen( 0 ), + mPos( 0 ) +{ +} + +// ------------------------------------------------------------------- +// Destructor +// ------------------------------------------------------------------- +NeonInputStream::~NeonInputStream( void ) +{ +} + +// ------------------------------------------------------------------- +// AddToStream +// Allows the caller to add some data to the "end" of the stream +// ------------------------------------------------------------------- +void NeonInputStream::AddToStream( const char * inBuf, sal_Int32 inLen ) +{ + mInputBuffer.realloc( sal::static_int_cast(mLen) + inLen ); + memcpy( mInputBuffer.getArray() + mLen, inBuf, inLen ); + mLen += inLen; +} + +// ------------------------------------------------------------------- +// queryInterface +// ------------------------------------------------------------------- +Any NeonInputStream::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 NeonInputStream::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 + memcpy( + aData.getArray(), mInputBuffer.getConstArray() + mPos, theBytes2Read ); + + // Update our stream position for next time + mPos += theBytes2Read; + + return theBytes2Read; +} + +// ------------------------------------------------------------------- +// readSomeBytes +// ------------------------------------------------------------------- +sal_Int32 SAL_CALL NeonInputStream::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 NeonInputStream::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 NeonInputStream::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 NeonInputStream::closeInput( void ) + throw( ::com::sun::star::io::NotConnectedException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ) +{ +} + +// ------------------------------------------------------------------- +// seek +// ------------------------------------------------------------------- +void SAL_CALL NeonInputStream::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 NeonInputStream::getPosition() + throw( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ) +{ + return mPos; +} + +// ------------------------------------------------------------------- +// getLength +// ------------------------------------------------------------------- +sal_Int64 SAL_CALL NeonInputStream::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-neon/NeonInputStream.hxx b/ucb/source/ucp/webdav-neon/NeonInputStream.hxx new file mode 100644 index 000000000000..597b1122414e --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonInputStream.hxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _NEONINPUTSTREAM_HXX_ +#define _NEONINPUTSTREAM_HXX_ + +#include +#include +#include +#include +#include + + +namespace webdav_ucp +{ + +// ------------------------------------------------------------------- +// NeonInputStream +// A simple XInputStream implementation provided specifically for use +// by the DAVSession::GET method. +// ------------------------------------------------------------------- +class NeonInputStream : 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: + NeonInputStream( void ); + virtual ~NeonInputStream(); + + // 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 webdav_ucp +#endif // _NEONINPUTSTREAM_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/NeonLockStore.cxx b/ucb/source/ucp/webdav-neon/NeonLockStore.cxx new file mode 100644 index 000000000000..77e62589f26f --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonLockStore.cxx @@ -0,0 +1,246 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "warnings_guard_ne_locks.h" +#include +#include "rtl/ustring.hxx" +#include "osl/time.h" +#include "osl/thread.hxx" +#include "salhelper/thread.hxx" +#include "NeonSession.hxx" +#include "NeonLockStore.hxx" + +using namespace webdav_ucp; + +namespace webdav_ucp { + +class TickerThread : public salhelper::Thread +{ + bool m_bFinish; + NeonLockStore & m_rLockStore; + +public: + + TickerThread( NeonLockStore & rLockStore ) + : Thread( "NeonTickerThread" ), m_bFinish( false ), + m_rLockStore( rLockStore ) {} + + void finish() { m_bFinish = true; } + +private: + + virtual void execute(); +}; + +} // namespace webdav_ucp + +// ------------------------------------------------------------------- +void TickerThread::execute() +{ + 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; + salhelper::Thread::wait( aTV ); + } + + OSL_TRACE( "TickerThread: stop." ); +} + +// ------------------------------------------------------------------- +NeonLockStore::NeonLockStore() + : m_pNeonLockStore( ne_lockstore_create() ) +{ + OSL_ENSURE( m_pNeonLockStore, "Unable to create neon lock store!" ); +} + +// ------------------------------------------------------------------- +NeonLockStore::~NeonLockStore() +{ + stopTicker(); + + // release active locks, if any. + OSL_ENSURE( m_aLockInfoMap.empty(), + "NeonLockStore::~NeonLockStore - Releasing active locks!" ); + + LockInfoMap::const_iterator it( m_aLockInfoMap.begin() ); + const LockInfoMap::const_iterator end( m_aLockInfoMap.end() ); + while ( it != end ) + { + NeonLock * pLock = (*it).first; + (*it).second.xSession->UNLOCK( pLock ); + + ne_lockstore_remove( m_pNeonLockStore, pLock ); + ne_lock_destroy( pLock ); + + ++it; + } + + ne_lockstore_destroy( m_pNeonLockStore ); +} + +// ------------------------------------------------------------------- +void NeonLockStore::startTicker() +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_pTickerThread.is() ) + { + m_pTickerThread = new TickerThread( *this ); + m_pTickerThread->launch(); + } +} + +// ------------------------------------------------------------------- +void NeonLockStore::stopTicker() +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pTickerThread.is() ) + { + m_pTickerThread->finish(); + m_pTickerThread->join(); + m_pTickerThread.clear(); + } +} + +// ------------------------------------------------------------------- +void NeonLockStore::registerSession( HttpSession * pHttpSession ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + ne_lockstore_register( m_pNeonLockStore, pHttpSession ); +} + +// ------------------------------------------------------------------- +NeonLock * NeonLockStore::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_pNeonLockStore, &aUri ); +} + +// ------------------------------------------------------------------- +void NeonLockStore::addLock( NeonLock * pLock, + rtl::Reference< NeonSession > const & xSession, + sal_Int32 nLastChanceToSendRefreshRequest ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + ne_lockstore_add( m_pNeonLockStore, pLock ); + m_aLockInfoMap[ pLock ] + = LockInfo( xSession, nLastChanceToSendRefreshRequest ); + + startTicker(); +} + +// ------------------------------------------------------------------- +void NeonLockStore::updateLock( NeonLock * pLock, + sal_Int32 nLastChanceToSendRefreshRequest ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + LockInfoMap::iterator it( m_aLockInfoMap.find( pLock ) ); + OSL_ENSURE( it != m_aLockInfoMap.end(), + "NeonLockStore::updateLock: lock not found!" ); + + if ( it != m_aLockInfoMap.end() ) + { + (*it).second.nLastChanceToSendRefreshRequest + = nLastChanceToSendRefreshRequest; + } +} + +// ------------------------------------------------------------------- +void NeonLockStore::removeLock( NeonLock * pLock ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + m_aLockInfoMap.erase( pLock ); + ne_lockstore_remove( m_pNeonLockStore, pLock ); + + if ( m_aLockInfoMap.empty() ) + stopTicker(); +} + +// ------------------------------------------------------------------- +void NeonLockStore::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-neon/NeonLockStore.hxx b/ucb/source/ucp/webdav-neon/NeonLockStore.hxx new file mode 100644 index 000000000000..c8f0f0fcba99 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonLockStore.hxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef INCLUDED_NEONLOCKSTORE_HXX +#define INCLUDED_NEONLOCKSTORE_HXX + +#include +#include "warnings_guard_ne_locks.h" +#include "osl/mutex.hxx" +#include "rtl/ref.hxx" +#include "NeonTypes.hxx" + +namespace webdav_ucp +{ + +class TickerThread; +class NeonSession; + +struct ltptr +{ + bool operator()( const NeonLock * p1, const NeonLock * p2 ) const + { + return p1 < p2; + } +}; + +typedef struct _LockInfo +{ + rtl::Reference< NeonSession > xSession; + sal_Int32 nLastChanceToSendRefreshRequest; + + _LockInfo() + : nLastChanceToSendRefreshRequest( -1 ) {} + + _LockInfo( rtl::Reference< NeonSession > const & _xSession, + sal_Int32 _nLastChanceToSendRefreshRequest ) + : xSession( _xSession ), + nLastChanceToSendRefreshRequest( _nLastChanceToSendRefreshRequest ) {} + +} LockInfo; + +typedef std::map< NeonLock *, LockInfo, ltptr > LockInfoMap; + +class NeonLockStore +{ + osl::Mutex m_aMutex; + ne_lock_store * m_pNeonLockStore; + rtl::Reference< TickerThread > m_pTickerThread; + LockInfoMap m_aLockInfoMap; + +public: + NeonLockStore(); + ~NeonLockStore(); + + void registerSession( HttpSession * pHttpSession ); + + NeonLock * findByUri( rtl::OUString const & rUri ); + + void addLock( NeonLock * pLock, + rtl::Reference< NeonSession > const & xSession, + // time in seconds since Jan 1 1970 + // -1: infinite lock, no refresh + sal_Int32 nLastChanceToSendRefreshRequest ); + + void updateLock( NeonLock * pLock, + sal_Int32 nLastChanceToSendRefreshRequest ); + + void removeLock( NeonLock * pLock ); + + void refreshLocks(); + +private: + void startTicker(); + void stopTicker(); +}; + +} // namespace webdav_ucp + +#endif // INCLUDED_NEONLOCKSTORE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/NeonPropFindRequest.cxx b/ucb/source/ucp/webdav-neon/NeonPropFindRequest.cxx new file mode 100644 index 000000000000..7bba69d63984 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonPropFindRequest.cxx @@ -0,0 +1,340 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include "osl/diagnose.h" +#include "rtl/strbuf.hxx" +#include "NeonTypes.hxx" +#include "DAVException.hxx" +#include "DAVProperties.hxx" +#include "NeonPropFindRequest.hxx" +#include "LinkSequence.hxx" +#include "LockSequence.hxx" +#include "LockEntrySequence.hxx" +#include "UCBDeadPropertyValue.hxx" + +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; +using namespace std; +using namespace webdav_ucp; + +using ::rtl::OUString; +using ::rtl::OString; +using ::rtl::OStringToOUString; + +// ------------------------------------------------------------------- +namespace +{ + // strip "DAV:" namespace from XML snippets to avoid + // parser error (undeclared namespace) later on. + rtl::OString stripDavNamespace( const rtl::OString & in ) + { + const rtl::OString inXML( in.toAsciiLowerCase() ); + + rtl::OStringBuffer buf; + sal_Int32 start = 0; + sal_Int32 end = inXML.indexOf( "dav:" ); + while ( end != -1 ) + { + if ( inXML[ end - 1 ] == '<' || + inXML[ end - 1 ] == '/' ) + { + // copy from original buffer - preserve case. + buf.append( in.copy( start, end - start ) ); + } + else + { + // copy from original buffer - preserve case. + buf.append( in.copy( start, end - start + 4 ) ); + } + start = end + 4; + end = inXML.indexOf( "dav:", start ); + } + buf.append( inXML.copy( start ) ); + + return rtl::OString( buf.makeStringAndClear() ); + } +} + +// ------------------------------------------------------------------- +extern "C" int NPFR_propfind_iter( void* userdata, + const NeonPropName* pname, + const char* value, + const HttpStatus* status ) +{ + /* + HTTP Response Status Classes: + + - 1: Informational - Request received, continuing process + + - 2: Success - The action was successfully received, + understood, and accepted + + - 3: Redirection - Further action must be taken in order to + complete the request + + - 4: Client Error - The request contains bad syntax or cannot + be fulfilled + + - 5: Server Error - The server failed to fulfill an apparently + valid request + */ + + if ( status->klass > 2 ) + return 0; // Error getting this property. Go on. + + // Create & set the PropertyValue + DAVPropertyValue thePropertyValue; + thePropertyValue.IsCaseSensitive = true; + + OSL_ENSURE( pname->nspace, "NPFR_propfind_iter - No namespace!" ); + + DAVProperties::createUCBPropName( pname->nspace, + pname->name, + thePropertyValue.Name ); + bool bHasValue = false; + if ( DAVProperties::isUCBDeadProperty( *pname ) ) + { + // DAV dead property added by WebDAV UCP? + if ( UCBDeadPropertyValue::createFromXML( + value, thePropertyValue.Value ) ) + { + OSL_ENSURE( thePropertyValue.Value.hasValue(), + "NPFR_propfind_iter - No value!" ); + bHasValue = true; + } + } + + if ( !bHasValue ) + { + if ( rtl_str_compareIgnoreAsciiCase( + pname->name, "resourcetype" ) == 0 ) + { + OString aValue( value ); + aValue = aValue.trim(); // #107358# remove leading/trailing spaces + if ( !aValue.isEmpty() ) + { + aValue = stripDavNamespace( aValue ).toAsciiLowerCase(); + if ( aValue.compareTo( + RTL_CONSTASCII_STRINGPARAM( "name, "supportedlock" ) == 0 ) + { + Sequence< LockEntry > aEntries; + LockEntrySequence::createFromXML( + stripDavNamespace( value ), aEntries ); + thePropertyValue.Value <<= aEntries; + } + else if ( rtl_str_compareIgnoreAsciiCase( + pname->name, "lockdiscovery" ) == 0 ) + { + Sequence< Lock > aLocks; + LockSequence::createFromXML( + stripDavNamespace( value ), aLocks ); + thePropertyValue.Value <<= aLocks; + } + else if ( rtl_str_compareIgnoreAsciiCase( pname->name, "source" ) == 0 ) + { + Sequence< Link > aLinks; + LinkSequence::createFromXML( + stripDavNamespace( value ), aLinks ); + thePropertyValue.Value <<= aLinks; + } + else + { + thePropertyValue.Value + <<= OStringToOUString( value, RTL_TEXTENCODING_UTF8 ); + } + } + + // Add the newly created PropertyValue + DAVResource* theResource = static_cast< DAVResource * >( userdata ); + theResource->properties.push_back( thePropertyValue ); + + return 0; // Go on. +} + +// ------------------------------------------------------------------- +extern "C" void NPFR_propfind_results( void* userdata, + const ne_uri* uri, + const NeonPropFindResultSet* set ) +{ + // @@@ href is not the uri! DAVResource ctor wants uri! + + DAVResource theResource( + OStringToOUString( uri->path, RTL_TEXTENCODING_UTF8 ) ); + + ne_propset_iterate( set, NPFR_propfind_iter, &theResource ); + + // Add entry to resources list. + vector< DAVResource > * theResources + = static_cast< vector< DAVResource > * >( userdata ); + theResources->push_back( theResource ); +} +// ------------------------------------------------------------------- +extern "C" int NPFR_propnames_iter( void* userdata, + const NeonPropName* pname, + const char* /*value*/, + const HttpStatus* /*status*/ ) +{ + OUString aFullName; + DAVProperties::createUCBPropName( pname->nspace, + pname->name, + aFullName ); + + DAVResourceInfo* theResource = static_cast< DAVResourceInfo * >( userdata ); + theResource->properties.push_back( aFullName ); + return 0; +} + +// ------------------------------------------------------------------- +extern "C" void NPFR_propnames_results( void* userdata, + const ne_uri* uri, + const NeonPropFindResultSet* results ) +{ + // @@@ href is not the uri! DAVResourceInfo ctor wants uri! + // Create entry for the resource. + DAVResourceInfo theResource( + OStringToOUString( uri->path, RTL_TEXTENCODING_UTF8 ) ); + + // Fill entry. + ne_propset_iterate( results, NPFR_propnames_iter, &theResource ); + + // Add entry to resources list. + vector< DAVResourceInfo > * theResources + = static_cast< vector< DAVResourceInfo > * >( userdata ); + theResources->push_back( theResource ); +} + +extern osl::Mutex aGlobalNeonMutex; + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- + +NeonPropFindRequest::NeonPropFindRequest( HttpSession* inSession, + const char* inPath, + const Depth inDepth, + const vector< OUString >& inPropNames, + vector< DAVResource >& ioResources, + int & nError ) +{ + // Generate the list of properties we're looking for + int thePropCount = inPropNames.size(); + if ( thePropCount > 0 ) + { + NeonPropName* thePropNames = new NeonPropName[ thePropCount + 1 ]; + int theIndex; + + for ( theIndex = 0; theIndex < thePropCount; theIndex ++ ) + { + // Split fullname into namespace and name! + DAVProperties::createNeonPropName( + inPropNames[ theIndex ], thePropNames[ theIndex ] ); + } + thePropNames[ theIndex ].nspace = NULL; + thePropNames[ theIndex ].name = NULL; + + { + osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex ); + nError = ne_simple_propfind( inSession, + inPath, + inDepth, + thePropNames, + NPFR_propfind_results, + &ioResources ); + } + + for ( theIndex = 0; theIndex < thePropCount; theIndex ++ ) + free( (void *)thePropNames[ theIndex ].name ); + + delete [] thePropNames; + } + else + { + // ALLPROP + osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex ); + nError = ne_simple_propfind( inSession, + inPath, + inDepth, + NULL, // 0 == allprop + NPFR_propfind_results, + &ioResources ); + } + + // #87585# - Sometimes neon lies (because some servers lie). + if ( ( nError == NE_OK ) && ioResources.empty() ) + nError = NE_ERROR; +} + +// ------------------------------------------------------------------- +// Constructor +// - obtains property names +// ------------------------------------------------------------------- + +NeonPropFindRequest::NeonPropFindRequest( + HttpSession* inSession, + const char* inPath, + const Depth inDepth, + std::vector< DAVResourceInfo > & ioResInfo, + int & nError ) +{ + { + osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex ); + nError = ne_propnames( inSession, + inPath, + inDepth, + NPFR_propnames_results, + &ioResInfo ); + } + + // #87585# - Sometimes neon lies (because some servers lie). + if ( ( nError == NE_OK ) && ioResInfo.empty() ) + nError = NE_ERROR; +} + +// ------------------------------------------------------------------- +// Destructor +// ------------------------------------------------------------------- +NeonPropFindRequest::~NeonPropFindRequest( ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/NeonPropFindRequest.hxx b/ucb/source/ucp/webdav-neon/NeonPropFindRequest.hxx new file mode 100644 index 000000000000..9febb56faf0c --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonPropFindRequest.hxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _NEONPROPFINDREQUEST_HXX_ +#define _NEONPROPFINDREQUEST_HXX_ + +#include +#include +#include "NeonTypes.hxx" +#include "DAVTypes.hxx" +#include "DAVResource.hxx" + +namespace webdav_ucp +{ + +class NeonPropFindRequest +{ +public: + // named / allprop + NeonPropFindRequest( HttpSession* inSession, + const char* inPath, + const Depth inDepth, + const std::vector< ::rtl::OUString > & inPropNames, + std::vector< DAVResource > & ioResources, + int & nError ); + // propnames + NeonPropFindRequest( HttpSession* inSession, + const char* inPath, + const Depth inDepth, + std::vector< DAVResourceInfo > & ioResInfo, + int & nError ); + + ~NeonPropFindRequest(); +}; + +} // namespace webdav_ucp + +#endif // _NEONPROPFINDREQUEST_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/NeonSession.cxx b/ucb/source/ucp/webdav-neon/NeonSession.cxx new file mode 100644 index 000000000000..b3a737fb5fa6 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonSession.cxx @@ -0,0 +1,2214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include +#include +#include +#include "osl/diagnose.h" +#include "osl/time.h" +#include +#include +#include +#include +#include + +#if NEON_VERSION < 0x0260 +// old neon versions forgot to set this +extern "C" { +#endif +#include +#if NEON_VERSION < 0x0260 +} +#endif + +#include "libxml/parser.h" +#include "rtl/ustrbuf.hxx" +#include "comphelper/sequence.hxx" +#include +#include "ucbhelper/simplecertificatevalidationrequest.hxx" + +#include "DAVAuthListener.hxx" +#include "NeonTypes.hxx" +#include "NeonSession.hxx" +#include "NeonInputStream.hxx" +#include "NeonPropFindRequest.hxx" +#include "NeonHeadRequest.hxx" +#include "NeonUri.hxx" +#include "LinkSequence.hxx" +#include "UCBDeadPropertyValue.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace com::sun::star; +using namespace webdav_ucp; + +#define SEINITIALIZER_COMPONENT "com.sun.star.xml.crypto.SEInitializer" + +#ifndef EOL +# define EOL "\r\n" +#endif + +// ------------------------------------------------------------------- +// RequestData +// ------------------------------------------------------------------- + +struct RequestData +{ + // POST + rtl::OUString aContentType; + rtl::OUString aReferer; + + RequestData() {} + RequestData( const rtl::OUString & rContentType, + const rtl::OUString & rReferer ) + : aContentType( rContentType ), aReferer( rReferer ) {} +}; + +// ------------------------------------------------------------------- +// RequestDataMap +// ------------------------------------------------------------------- + +struct equalPtr +{ + bool operator()( const ne_request* p1, const ne_request* p2 ) const + { + return p1 == p2; + } +}; + +struct hashPtr +{ + size_t operator()( const ne_request* p ) const + { + return (size_t)p; + } +}; + +typedef boost::unordered_map +< + ne_request*, + RequestData, + hashPtr, + equalPtr +> +RequestDataMap; + +// ------------------------------------------------------------------- +// Helper fuction +// ------------------------------------------------------------------- +static sal_uInt16 makeStatusCode( const rtl::OUString & rStatusText ) +{ + // Extract status code from session error string. Unfortunately + // neon provides no direct access to the status code... + + if ( rStatusText.getLength() < 3 ) + { + OSL_FAIL( + "makeStatusCode - status text string to short!" ); + return 0; + } + + sal_Int32 nPos = rStatusText.indexOf( ' ' ); + if ( nPos == -1 ) + { + OSL_FAIL( "makeStatusCode - wrong status text format!" ); + return 0; + } + + return sal_uInt16( rStatusText.copy( 0, nPos ).toInt32() ); +} + +// ------------------------------------------------------------------- +static bool noKeepAlive( const uno::Sequence< beans::NamedValue >& rFlags ) +{ + if ( !rFlags.hasElements() ) + return false; + + // find "KeepAlive" property + const beans::NamedValue* pAry(rFlags.getConstArray()); + const sal_Int32 nLen(rFlags.getLength()); + const beans::NamedValue* pValue( + std::find_if(pAry,pAry+nLen, + boost::bind(comphelper::TNamedValueEqualFunctor(), + _1, + rtl::OUString("KeepAlive")))); + if ( pValue != pAry+nLen && !pValue->Value.get() ) + return true; + + return false; +} + +// ------------------------------------------------------------------- +struct NeonRequestContext +{ + uno::Reference< io::XOutputStream > xOutputStream; + rtl::Reference< NeonInputStream > xInputStream; + const std::vector< ::rtl::OUString > * pHeaderNames; + DAVResource * pResource; + + NeonRequestContext( uno::Reference< io::XOutputStream > & xOutStrm ) + : xOutputStream( xOutStrm ), xInputStream( 0 ), + pHeaderNames( 0 ), pResource( 0 ) {} + + NeonRequestContext( const rtl::Reference< NeonInputStream > & xInStrm ) + : xOutputStream( 0 ), xInputStream( xInStrm ), + pHeaderNames( 0 ), pResource( 0 ) {} + + NeonRequestContext( uno::Reference< io::XOutputStream > & xOutStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource ) + : xOutputStream( xOutStrm ), xInputStream( 0 ), + pHeaderNames( &inHeaderNames ), pResource( &ioResource ) {} + + NeonRequestContext( const rtl::Reference< NeonInputStream > & xInStrm, + const std::vector< ::rtl::OUString > & inHeaderNames, + DAVResource & ioResource ) + : xOutputStream( 0 ), xInputStream( xInStrm ), + pHeaderNames( &inHeaderNames ), pResource( &ioResource ) {} +}; + +//-------------------------------------------------------------------- +//-------------------------------------------------------------------- +// +// Callback functions +// +//-------------------------------------------------------------------- +//-------------------------------------------------------------------- + +// ------------------------------------------------------------------- +// ResponseBlockReader +// A simple Neon response_block_reader for use with an XInputStream +// ------------------------------------------------------------------- + +extern "C" int NeonSession_ResponseBlockReader(void * inUserData, + const char * inBuf, + size_t inLen ) +{ + // neon sometimes calls this function with (inLen == 0)... + if ( inLen > 0 ) + { + NeonRequestContext * pCtx + = static_cast< NeonRequestContext * >( inUserData ); + + rtl::Reference< NeonInputStream > xInputStream( + pCtx->xInputStream ); + + if ( xInputStream.is() ) + xInputStream->AddToStream( inBuf, inLen ); + } + return 0; +} + +// ------------------------------------------------------------------- +// ResponseBlockWriter +// A simple Neon response_block_reader for use with an XOutputStream +// ------------------------------------------------------------------- + +extern "C" int NeonSession_ResponseBlockWriter( void * inUserData, + const char * inBuf, + size_t inLen ) +{ + // neon calls this function with (inLen == 0)... + if ( inLen > 0 ) + { + NeonRequestContext * pCtx + = static_cast< NeonRequestContext * >( inUserData ); + uno::Reference< io::XOutputStream > xOutputStream + = pCtx->xOutputStream; + + if ( xOutputStream.is() ) + { + const uno::Sequence< sal_Int8 > aSeq( (sal_Int8 *)inBuf, inLen ); + xOutputStream->writeBytes( aSeq ); + } + } + return 0; +} + +// ------------------------------------------------------------------- +extern "C" int NeonSession_NeonAuth( void * inUserData, +#ifdef NE_FEATURE_SSPI + const char * inAuthProtocol, +#endif + const char * inRealm, + int attempt, + char * inoutUserName, + char * inoutPassWord ) +{ +/* The callback used to request the username and password in the given + * realm. The username and password must be copied into the buffers + * which are both of size NE_ABUFSIZ. The 'attempt' parameter is zero + * on the first call to the callback, and increases by one each time + * an attempt to authenticate fails. + * + * The callback must return zero to indicate that authentication + * should be attempted with the username/password, or non-zero to + * cancel the request. (if non-zero, username and password are + * ignored.) */ + + NeonSession * theSession = static_cast< NeonSession * >( inUserData ); + DAVAuthListener * pListener + = theSession->getRequestEnvironment().m_xAuthListener.get(); + if ( !pListener ) + { + // abort + return -1; + } + rtl::OUString theUserName; + rtl::OUString thePassWord; + + if ( attempt == 0 ) + { + // neon does not handle username supplied with request URI (for + // instance when doing FTP over proxy - last checked: 0.23.5 ) + + try + { + NeonUri uri( theSession->getRequestEnvironment().m_aRequestURI ); + rtl::OUString aUserInfo( uri.GetUserInfo() ); + if ( !aUserInfo.isEmpty() ) + { + 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 -1; + } + } + else + { + // username buffer is prefilled with user name from last attempt. + theUserName = rtl::OUString::createFromAscii( inoutUserName ); + // @@@ Neon does not initialize password buffer (last checked: 0.22.0). + //thePassWord = rtl::OUString::createFromAscii( inoutPassWord ); + } + + bool bCanUseSystemCreds = false; + +#ifdef NE_FEATURE_SSPI + bCanUseSystemCreds + = (attempt == 0) && // avoid endless loops + ne_has_support( NE_FEATURE_SSPI ) && // Windows-only feature. + ( ( ne_strcasecmp( inAuthProtocol, "NTLM" ) == 0 ) || + ( ne_strcasecmp( inAuthProtocol, "Negotiate" ) == 0 ) ); +#endif + + int theRetVal = pListener->authenticate( + rtl::OUString::createFromAscii( inRealm ), + theSession->getHostName(), + theUserName, + thePassWord, + bCanUseSystemCreds); + + rtl::OString aUser( + rtl::OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ) ); + if ( aUser.getLength() > ( NE_ABUFSIZ - 1 ) ) + { + OSL_FAIL( + "NeonSession_NeonAuth - username to long!" ); + return -1; + } + + rtl::OString aPass( + rtl::OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ) ); + if ( aPass.getLength() > ( NE_ABUFSIZ - 1 ) ) + { + OSL_FAIL( + "NeonSession_NeonAuth - password to long!" ); + return -1; + } + + strcpy( inoutUserName, // #100211# - checked + rtl::OUStringToOString( theUserName, RTL_TEXTENCODING_UTF8 ).getStr() ); + + strcpy( inoutPassWord, // #100211# - checked + rtl::OUStringToOString( thePassWord, RTL_TEXTENCODING_UTF8 ).getStr() ); + + return theRetVal; +} + +// ------------------------------------------------------------------- + +namespace { + // ------------------------------------------------------------------- + // Helper function + ::rtl::OUString GetHostnamePart( const ::rtl::OUString& _rRawString ) + { + ::rtl::OUString sPart; + ::rtl::OUString sPartId("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 + +// ------------------------------------------------------------------- +extern "C" int NeonSession_CertificationNotify( void *userdata, + int failures, + const ne_ssl_certificate *cert ) +{ + OSL_ASSERT( cert ); + + NeonSession * pSession = static_cast< NeonSession * >( userdata ); + uno::Reference< security::XCertificateContainer > xCertificateContainer; + try + { + xCertificateContainer + = uno::Reference< security::XCertificateContainer >( + pSession->getMSF()->createInstance( + rtl::OUString( "com.sun.star.security.CertificateContainer" ) ), + uno::UNO_QUERY ); + } + catch ( uno::Exception const & ) + { + } + + if ( !xCertificateContainer.is() ) + return 1; + + failures = 0; + + char * dn = ne_ssl_readable_dname( ne_ssl_cert_subject( cert ) ); + rtl::OUString cert_subject( dn, strlen( dn ), RTL_TEXTENCODING_UTF8, 0 ); + + ne_free( dn ); + + security::CertificateContainerStatus certificateContainer( + xCertificateContainer->hasCertificate( + pSession->getHostName(), cert_subject ) ); + + if ( certificateContainer != security::CertificateContainerStatus_NOCERT ) + return + certificateContainer == security::CertificateContainerStatus_TRUSTED + ? 0 + : 1; + + uno::Reference< xml::crypto::XSEInitializer > xSEInitializer; + try + { + xSEInitializer = uno::Reference< xml::crypto::XSEInitializer >( + pSession->getMSF()->createInstance( + rtl::OUString( SEINITIALIZER_COMPONENT ) ), + uno::UNO_QUERY ); + } + catch ( uno::Exception const & ) + { + } + + if ( !xSEInitializer.is() ) + return 1; + + uno::Reference< xml::crypto::XXMLSecurityContext > xSecurityContext( + xSEInitializer->createSecurityContext( rtl::OUString() ) ); + + uno::Reference< xml::crypto::XSecurityEnvironment > xSecurityEnv( + xSecurityContext->getSecurityEnvironment() ); + + //The end entity certificate + char * eeCertB64 = ne_ssl_cert_export( cert ); + + rtl::OString sEECertB64( eeCertB64 ); + + uno::Reference< security::XCertificate > xEECert( + xSecurityEnv->createCertificateFromAscii( + rtl::OStringToOUString( sEECertB64, RTL_TEXTENCODING_ASCII_US ) ) ); + + ne_free( eeCertB64 ); + eeCertB64 = 0; + + std::vector< uno::Reference< security::XCertificate > > vecCerts; + const ne_ssl_certificate * issuerCert = cert; + do + { + //get the intermediate certificate + //the returned value is const ! Therfore it does not need to be freed + //with ne_ssl_cert_free, which takes a non-const argument + issuerCert = ne_ssl_cert_signedby( issuerCert ); + if ( NULL == issuerCert ) + break; + + char * imCertB64 = ne_ssl_cert_export( issuerCert ); + rtl::OString sInterMediateCertB64( imCertB64 ); + ne_free( imCertB64 ); + + uno::Reference< security::XCertificate> xImCert( + xSecurityEnv->createCertificateFromAscii( + rtl::OStringToOUString( sInterMediateCertB64, RTL_TEXTENCODING_ASCII_US ) ) ); + if ( xImCert.is() ) + vecCerts.push_back( xImCert ); + } + while ( 1 ); + + sal_Int64 certValidity = xSecurityEnv->verifyCertificate( xEECert, + ::comphelper::containerToSequence( vecCerts ) ); + + if ( pSession->isDomainMatch( + GetHostnamePart( xEECert.get()->getSubjectName() ) ) ) + { + // if host name matched with certificate then look if the + // certificate was ok + if( certValidity == security::CertificateValidity::VALID ) + return 0; + } + + const uno::Reference< ucb::XCommandEnvironment > xEnv( + pSession->getRequestEnvironment().m_xEnv ); + if ( xEnv.is() ) + { + failures = static_cast< int >( certValidity ); + + uno::Reference< task::XInteractionHandler > xIH( + xEnv->getInteractionHandler() ); + if ( xIH.is() ) + { + rtl::Reference< ucbhelper::SimpleCertificateValidationRequest > + xRequest( new ucbhelper::SimpleCertificateValidationRequest( + (sal_Int32)failures, xEECert, pSession->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( + pSession->getHostName(), cert_subject, sal_True ); + return 0; + } + else + { + // Don't trust cert + xCertificateContainer->addCertificate( + pSession->getHostName(), cert_subject, sal_False ); + return 1; + } + } + } + else + { + // Don't trust cert + xCertificateContainer->addCertificate( + pSession->getHostName(), cert_subject, sal_False ); + return 1; + } + } + return 1; +} + +// ------------------------------------------------------------------- +extern "C" void NeonSession_PreSendRequest( ne_request * req, + void * userdata, + ne_buffer * headers ) +{ + // userdata -> value returned by 'create' + + NeonSession * pSession = static_cast< NeonSession * >( userdata ); + if ( pSession ) + { + // If there is a proxy server in between, it shall never use + // cached data. We always want 'up-to-date' data. + ne_buffer_concat( headers, "Pragma: no-cache", EOL, NULL ); + // alternative, but understoud by HTTP 1.1 servers only: + // ne_buffer_concat( headers, "Cache-Control: max-age=0", EOL, NULL ); + + const RequestDataMap * pRequestData + = static_cast< const RequestDataMap* >( + pSession->getRequestData() ); + + RequestDataMap::const_iterator it = pRequestData->find( req ); + if ( it != pRequestData->end() ) + { + if ( !(*it).second.aContentType.isEmpty() ) + { + char * pData = headers->data; + if ( strstr( pData, "Content-Type:" ) == NULL ) + { + rtl::OString aType + = rtl::OUStringToOString( (*it).second.aContentType, + RTL_TEXTENCODING_UTF8 ); + ne_buffer_concat( headers, "Content-Type: ", + aType.getStr(), EOL, NULL ); + } + } + + if ( !(*it).second.aReferer.isEmpty() ) + { + char * pData = headers->data; + if ( strstr( pData, "Referer:" ) == NULL ) + { + rtl::OString aReferer + = rtl::OUStringToOString( (*it).second.aReferer, + RTL_TEXTENCODING_UTF8 ); + ne_buffer_concat( headers, "Referer: ", + aReferer.getStr(), EOL, NULL ); + } + } + } + + const DAVRequestHeaders & rHeaders + = pSession->getRequestEnvironment().m_aRequestHeaders; + + DAVRequestHeaders::const_iterator it1( rHeaders.begin() ); + const DAVRequestHeaders::const_iterator end1( rHeaders.end() ); + + while ( it1 != end1 ) + { + rtl::OString aHeader + = rtl::OUStringToOString( (*it1).first, + RTL_TEXTENCODING_UTF8 ); + rtl::OString aValue + = rtl::OUStringToOString( (*it1).second, + RTL_TEXTENCODING_UTF8 ); + ne_buffer_concat( headers, aHeader.getStr(), ": ", + aValue.getStr(), EOL, NULL ); + + ++it1; + } + } +} + +// ------------------------------------------------------------------- +// static members! +bool NeonSession::m_bGlobalsInited = false; +//See https://bugzilla.redhat.com/show_bug.cgi?id=544619#c4 +//neon is threadsafe, but uses gnutls which is only thread-safe +//if initialized to be thread-safe. cups, unfortunately, generally +//initializes it first, and as non-thread-safe, leaving the entire +//stack unsafe +osl::Mutex aGlobalNeonMutex; +NeonLockStore NeonSession::m_aNeonLockStore; + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- +NeonSession::NeonSession( + const rtl::Reference< DAVSessionFactory > & rSessionFactory, + const rtl::OUString& inUri, + const uno::Sequence< beans::NamedValue >& rFlags, + const ucbhelper::InternetProxyDecider & rProxyDecider ) + throw ( DAVException ) +: DAVSession( rSessionFactory ), + m_aFlags( rFlags ), + m_pHttpSession( 0 ), + m_pRequestData( new RequestDataMap ), + m_rProxyDecider( rProxyDecider ) +{ + NeonUri theUri( inUri ); + m_aScheme = theUri.GetScheme(); + m_aHostName = theUri.GetHost(); + m_nPort = theUri.GetPort(); +} + +// ------------------------------------------------------------------- +// Destructor +// ------------------------------------------------------------------- +NeonSession::~NeonSession( ) +{ + if ( m_pHttpSession ) + { + { + osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex ); + ne_session_destroy( m_pHttpSession ); + } + m_pHttpSession = 0; + } + delete static_cast< RequestDataMap * >( m_pRequestData ); +} + +// ------------------------------------------------------------------- +void NeonSession::Init( const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + m_aEnv = rEnv; + Init(); +} + +// ------------------------------------------------------------------- +void NeonSession::Init() + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + bool bCreateNewSession = false; + + if ( m_pHttpSession == 0 ) + { + // Ensure that Neon sockets are initialized + osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex ); + if ( !m_bGlobalsInited ) + { + if ( ne_sock_init() != 0 ) + throw DAVException( DAVException::DAV_SESSION_CREATE, + NeonUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + // #122205# - libxml2 needs to be initialized once if used by + // multithreaded programs like OOo. + xmlInitParser(); +#if 0 + // for more debug flags see ne_utils.h; NE_DEBUGGING must be defined + // while compiling neon in order to actually activate neon debug + // output. + ne_debug_init( stderr, NE_DBG_FLUSH + | NE_DBG_HTTP + // | NE_DBG_HTTPBODY + // | NE_DBG_HTTPAUTH + // | NE_DBG_XML + // | NE_DBG_XMLPARSE + // | NE_DBG_LOCKS + ); +#endif + m_bGlobalsInited = true; + } + + const ucbhelper::InternetProxyServer & rProxyCfg = getProxySettings(); + + m_aProxyName = rProxyCfg.aName; + m_nProxyPort = rProxyCfg.nPort; + + // Not yet initialized. Create new session. + bCreateNewSession = true; + } + else + { + // #112271# Check whether proxy settings are still valid (They may + // change at any time). If not, create new Neon session. + + 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 + { + osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex ); + ne_session_destroy( m_pHttpSession ); + } + m_pHttpSession = 0; + bCreateNewSession = true; + } + } + + if ( bCreateNewSession ) + { + // @@@ For FTP over HTTP proxy inUserInfo is needed to be able to + // build the complete request URI (including user:pass), but + // currently (0.22.0) neon does not allow to pass the user info + // to the session + + { + osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex ); + m_pHttpSession = ne_session_create( + rtl::OUStringToOString( m_aScheme, RTL_TEXTENCODING_UTF8 ).getStr(), + /* theUri.GetUserInfo(), + @@@ for FTP via HTTP proxy, but not supported by Neon */ + rtl::OUStringToOString( m_aHostName, RTL_TEXTENCODING_UTF8 ).getStr(), + m_nPort ); + } + + if ( m_pHttpSession == 0 ) + throw DAVException( DAVException::DAV_SESSION_CREATE, + NeonUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + // Register the session with the lock store + m_aNeonLockStore.registerSession( m_pHttpSession ); + + if ( m_aScheme.equalsIgnoreAsciiCase( + rtl::OUString( "https" ) ) ) + { + // Set a failure callback for certificate check + ne_ssl_set_verify( + m_pHttpSession, NeonSession_CertificationNotify, this); + } + + // Add hooks (i.e. for adding additional headers to the request) + +#if 0 + /* Hook called when a request is created. */ + //typedef void (*ne_create_request_fn)(ne_request *req, void *userdata, + // const char *method, const char *path); + + ne_hook_create_request( m_pHttpSession, create_req_hook_fn, this ); +#endif + + /* Hook called before the request is sent. 'header' is the raw HTTP + * header before the trailing CRLF is added: add in more here. */ + //typedef void (*ne_pre_send_fn)(ne_request *req, void *userdata, + // ne_buffer *header); + + ne_hook_pre_send( m_pHttpSession, NeonSession_PreSendRequest, this ); +#if 0 + /* Hook called after the request is sent. May return: + * NE_OK everything is okay + * NE_RETRY try sending the request again. + * anything else signifies an error, and the request is failed. The + * return code is passed back the _dispatch caller, so the session error + * must also be set appropriately (ne_set_error). + */ + //typedef int (*ne_post_send_fn)(ne_request *req, void *userdata, + // const ne_status *status); + + ne_hook_post_send( m_pHttpSession, post_send_req_hook_fn, this ); + + /* Hook called when the request is destroyed. */ + //typedef void (*ne_destroy_req_fn)(ne_request *req, void *userdata); + + ne_hook_destroy_request( m_pHttpSession, destroy_req_hook_fn, this ); + + /* Hook called when the session is destroyed. */ + //typedef void (*ne_destroy_sess_fn)(void *userdata); + + ne_hook_destroy_session( m_pHttpSession, destroy_sess_hook_fn, this ); +#endif + + if ( !m_aProxyName.isEmpty() ) + { + ne_session_proxy( m_pHttpSession, + rtl::OUStringToOString( + m_aProxyName, + RTL_TEXTENCODING_UTF8 ).getStr(), + m_nProxyPort ); + } + + // avoid KeepAlive? + if ( noKeepAlive(m_aFlags) ) + ne_set_session_flag( m_pHttpSession, NE_SESSFLAG_PERSIST, 0 ); + + // Register for redirects. + ne_redirect_register( m_pHttpSession ); + + // authentication callbacks. +#if NEON_VERSION >= 0x0260 + ne_add_server_auth( m_pHttpSession, NE_AUTH_ALL, NeonSession_NeonAuth, this ); + ne_add_proxy_auth ( m_pHttpSession, NE_AUTH_ALL, NeonSession_NeonAuth, this ); +#else + ne_set_server_auth( m_pHttpSession, NeonSession_NeonAuth, this ); + ne_set_proxy_auth ( m_pHttpSession, NeonSession_NeonAuth, this ); +#endif + } +} + +// ------------------------------------------------------------------- +// virtual +sal_Bool NeonSession::CanUse( const rtl::OUString & inUri, + const uno::Sequence< beans::NamedValue >& rFlags ) +{ + try + { + NeonUri theUri( inUri ); + if ( ( theUri.GetPort() == m_nPort ) && + ( theUri.GetHost() == m_aHostName ) && + ( theUri.GetScheme() == m_aScheme ) && + ( rFlags == m_aFlags ) ) + return sal_True; + } + catch ( DAVException const & ) + { + return sal_False; + } + return sal_False; +} + +// ------------------------------------------------------------------- +// virtual +sal_Bool NeonSession::UsesProxy() +{ + Init(); + return !m_aProxyName.isEmpty() ; +} + +// ------------------------------------------------------------------- +// OPTIONS +// ------------------------------------------------------------------- +void NeonSession::OPTIONS( const rtl::OUString & inPath, + DAVCapabilities & outCapabilities, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + HttpServerCapabilities servercaps; + memset( &servercaps, 0, sizeof( servercaps ) ); + + int theRetVal = ne_options( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr(), + &servercaps ); + + HandleError( theRetVal, inPath, rEnv ); + + outCapabilities.class1 = !!servercaps.dav_class1; + outCapabilities.class2 = !!servercaps.dav_class2; + outCapabilities.executable = !!servercaps.dav_executable; +} + +// ------------------------------------------------------------------- +// PROPFIND - allprop & named +// ------------------------------------------------------------------- +void NeonSession::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 ); + + int theRetVal = NE_OK; + NeonPropFindRequest theRequest( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr(), + inDepth, + inPropNames, + ioResources, + theRetVal ); + + HandleError( theRetVal, inPath, rEnv ); +} + +// ------------------------------------------------------------------- +// PROPFIND - propnames +// ------------------------------------------------------------------- +void NeonSession::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 ); + + int theRetVal = NE_OK; + NeonPropFindRequest theRequest( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr(), + inDepth, + ioResInfo, + theRetVal ); + + HandleError( theRetVal, inPath, rEnv ); +} + +// ------------------------------------------------------------------- +// PROPPATCH +// ------------------------------------------------------------------- +void NeonSession::PROPPATCH( const rtl::OUString & inPath, + const std::vector< ProppatchValue > & inValues, + const DAVRequestEnvironment & rEnv ) + throw( DAVException ) +{ + /* @@@ Which standard live properties can be set by the client? + This is a known WebDAV RFC issue ( verified: 04/10/2001 ) + --> http://www.ics.uci.edu/pub/ietf/webdav/protocol/issues.html + + mod_dav implementation: + + creationdate r ( File System prop ) + displayname w + getcontentlanguage r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS ) + getcontentlength r ( File System prop ) + getcontenttype r ( #ifdef DAV_DISABLE_WRITEABLE_PROPS ) + getetag r ( File System prop ) + getlastmodified r ( File System prop ) + lockdiscovery r + resourcetype r + source w + supportedlock r + executable w ( #ifndef WIN32 ) + + All dead properties are of course writable. + */ + + int theRetVal = NE_OK; + + int n; // for the "for" loop + + // Generate the list of properties we want to set. + int nPropCount = inValues.size(); + ne_proppatch_operation* pItems + = new ne_proppatch_operation[ nPropCount + 1 ]; + for ( n = 0; n < nPropCount; ++n ) + { + const ProppatchValue & rValue = inValues[ n ]; + + // Split fullname into namespace and name! + ne_propname * pName = new ne_propname; + DAVProperties::createNeonPropName( rValue.name, *pName ); + pItems[ n ].name = pName; + + if ( rValue.operation == PROPSET ) + { + pItems[ n ].type = ne_propset; + + rtl::OUString aStringValue; + if ( DAVProperties::isUCBDeadProperty( *pName ) ) + { + // DAV dead property added by WebDAV UCP? + if ( !UCBDeadPropertyValue::toXML( rValue.value, + aStringValue ) ) + { + // Error! + pItems[ n ].value = 0; + theRetVal = NE_ERROR; + nPropCount = n + 1; + break; + } + } + else if ( !( rValue.value >>= aStringValue ) ) + { + // complex properties... + if ( rValue.name == DAVProperties::SOURCE ) + { + uno::Sequence< ucb::Link > aLinks; + if ( rValue.value >>= aLinks ) + { + LinkSequence::toXML( aLinks, aStringValue ); + } + else + { + // Error! + pItems[ n ].value = 0; + theRetVal = NE_ERROR; + nPropCount = n + 1; + break; + } + } + else + { + OSL_FAIL( "NeonSession::PROPPATCH - unsupported type!" ); + // Error! + pItems[ n ].value = 0; + theRetVal = NE_ERROR; + nPropCount = n + 1; + break; + } + } + pItems[ n ].value + = strdup( rtl::OUStringToOString( aStringValue, + RTL_TEXTENCODING_UTF8 ).getStr() ); + } + else + { + pItems[ n ].type = ne_propremove; + pItems[ n ].value = 0; + } + } + + if ( theRetVal == NE_OK ) + { + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + pItems[ n ].name = 0; + + theRetVal = ne_proppatch( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr(), + pItems ); + } + + for ( n = 0; n < nPropCount; ++n ) + { + free( (void *)pItems[ n ].name->name ); + delete pItems[ n ].name; + free( (void *)pItems[ n ].value ); + } + + delete [] pItems; + + HandleError( theRetVal, inPath, rEnv ); +} + +// ------------------------------------------------------------------- +// HEAD +// ------------------------------------------------------------------- +void NeonSession::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 ); + + int theRetVal = NE_OK; + NeonHeadRequest theRequest( m_pHttpSession, + inPath, + inHeaderNames, + ioResource, + theRetVal ); + + HandleError( theRetVal, inPath, rEnv ); +} + +// ------------------------------------------------------------------- +// GET +// ------------------------------------------------------------------- +uno::Reference< io::XInputStream > +NeonSession::GET( const rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream ); + NeonRequestContext aCtx( xInputStream ); + int theRetVal = GET( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr(), + NeonSession_ResponseBlockReader, + false, + &aCtx ); + + HandleError( theRetVal, inPath, rEnv ); + + return uno::Reference< io::XInputStream >( xInputStream.get() ); +} + +// ------------------------------------------------------------------- +// GET +// ------------------------------------------------------------------- +void NeonSession::GET( const rtl::OUString & inPath, + uno::Reference< io::XOutputStream > & ioOutputStream, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + NeonRequestContext aCtx( ioOutputStream ); + int theRetVal = GET( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr(), + NeonSession_ResponseBlockWriter, + false, + &aCtx ); + + HandleError( theRetVal, inPath, rEnv ); +} + +// ------------------------------------------------------------------- +// GET +// ------------------------------------------------------------------- +uno::Reference< io::XInputStream > +NeonSession::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 ); + + ioResource.uri = inPath; + ioResource.properties.clear(); + + rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream ); + NeonRequestContext aCtx( xInputStream, inHeaderNames, ioResource ); + int theRetVal = GET( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr(), + NeonSession_ResponseBlockReader, + true, + &aCtx ); + + HandleError( theRetVal, inPath, rEnv ); + + return uno::Reference< io::XInputStream >( xInputStream.get() ); +} + +// ------------------------------------------------------------------- +// GET +// ------------------------------------------------------------------- +void NeonSession::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 ); + + ioResource.uri = inPath; + ioResource.properties.clear(); + + NeonRequestContext aCtx( ioOutputStream, inHeaderNames, ioResource ); + int theRetVal = GET( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr(), + NeonSession_ResponseBlockWriter, + true, + &aCtx ); + + HandleError( theRetVal, inPath, rEnv ); +} + +// ------------------------------------------------------------------- +// PUT +// ------------------------------------------------------------------- +void NeonSession::PUT( const rtl::OUString & inPath, + 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, false ) ) + throw DAVException( DAVException::DAV_INVALID_ARG ); + + Init( rEnv ); + + int theRetVal = PUT( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr(), + reinterpret_cast< const char * >( + aDataToSend.getConstArray() ), + aDataToSend.getLength() ); + + HandleError( theRetVal, inPath, rEnv ); +} + +// ------------------------------------------------------------------- +// POST +// ------------------------------------------------------------------- +uno::Reference< io::XInputStream > +NeonSession::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 ); + + rtl::Reference< NeonInputStream > xInputStream( new NeonInputStream ); + NeonRequestContext aCtx( xInputStream ); + int theRetVal = POST( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr(), + reinterpret_cast< const char * >( + aDataToSend.getConstArray() ), + NeonSession_ResponseBlockReader, + &aCtx, + rContentType, + rReferer ); + + HandleError( theRetVal, inPath, rEnv ); + + return uno::Reference< io::XInputStream >( xInputStream.get() ); +} + +// ------------------------------------------------------------------- +// POST +// ------------------------------------------------------------------- +void NeonSession::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 ); + + NeonRequestContext aCtx( oOutputStream ); + int theRetVal = POST( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr(), + reinterpret_cast< const char * >( + aDataToSend.getConstArray() ), + NeonSession_ResponseBlockWriter, + &aCtx, + rContentType, + rReferer ); + + HandleError( theRetVal, inPath, rEnv ); +} + +// ------------------------------------------------------------------- +// MKCOL +// ------------------------------------------------------------------- +void NeonSession::MKCOL( const rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + int theRetVal = ne_mkcol( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr() ); + + HandleError( theRetVal, inPath, rEnv ); +} + +// ------------------------------------------------------------------- +// COPY +// ------------------------------------------------------------------- +void NeonSession::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 ); + + NeonUri theSourceUri( inSourceURL ); + NeonUri theDestinationUri( inDestinationURL ); + + int theRetVal = ne_copy( m_pHttpSession, + inOverWrite ? 1 : 0, + NE_DEPTH_INFINITE, + rtl::OUStringToOString( + theSourceUri.GetPath(), + RTL_TEXTENCODING_UTF8 ).getStr(), + rtl::OUStringToOString( + theDestinationUri.GetPath(), + RTL_TEXTENCODING_UTF8 ).getStr() ); + + HandleError( theRetVal, inSourceURL, rEnv ); +} + +// ------------------------------------------------------------------- +// MOVE +// ------------------------------------------------------------------- +void NeonSession::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 ); + + NeonUri theSourceUri( inSourceURL ); + NeonUri theDestinationUri( inDestinationURL ); + int theRetVal = ne_move( m_pHttpSession, + inOverWrite ? 1 : 0, + rtl::OUStringToOString( + theSourceUri.GetPath(), + RTL_TEXTENCODING_UTF8 ).getStr(), + rtl::OUStringToOString( + theDestinationUri.GetPath(), + RTL_TEXTENCODING_UTF8 ).getStr() ); + + HandleError( theRetVal, inSourceURL, rEnv ); +} + +// ------------------------------------------------------------------- +// DESTROY +// ------------------------------------------------------------------- +void NeonSession::DESTROY( const rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + int theRetVal = ne_delete( m_pHttpSession, + rtl::OUStringToOString( + inPath, RTL_TEXTENCODING_UTF8 ).getStr() ); + + HandleError( theRetVal, inPath, rEnv ); +} + +// ------------------------------------------------------------------- +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 NeonSession::LOCK( const ::rtl::OUString & inPath, + ucb::Lock & rLock, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + Init( rEnv ); + + /* Create a depth zero, exclusive write lock, with default timeout + * (allowing a server to pick a default). token, owner and uri are + * unset. */ + NeonLock * 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_aNeonLockStore.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( "NeonSession::LOCK: created lock for %s. token: %s", + rtl::OUStringToOString( makeAbsoluteURL( inPath ), + RTL_TEXTENCODING_UTF8 ).getStr(), + theLock->token ); + } + else + { + ne_lock_destroy( theLock ); + + OSL_TRACE( "NeonSession::LOCK: obtaining lock for %s failed!", + rtl::OUStringToOString( makeAbsoluteURL( inPath ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + } + + HandleError( theRetVal, inPath, rEnv ); +} + +// ------------------------------------------------------------------- +// LOCK (refresh existing lock) +// ------------------------------------------------------------------- +sal_Int64 NeonSession::LOCK( const ::rtl::OUString & inPath, + sal_Int64 nTimeout, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + // Try to get the neon lock from lock store + NeonLock * theLock + = m_aNeonLockStore.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_aNeonLockStore.updateLock( theLock, + lastChanceToSendRefreshRequest( + startCall, theLock->timeout ) ); + } + + HandleError( theRetVal, inPath, rEnv ); + + return theLock->timeout; +} + +// ------------------------------------------------------------------- +// LOCK (refresh existing lock) +// ------------------------------------------------------------------- +bool NeonSession::LOCK( NeonLock * pLock, + sal_Int32 & rlastChanceToSendRefreshRequest ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + +#if OSL_DEBUG_LEVEL > 0 + char * p = ne_uri_unparse( &(pLock->uri) ); + OSL_TRACE( "NeonSession::LOCK: Refreshing lock for %s.", p ); + ne_free( p ); +#endif + + // 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 NeonSession::UNLOCK( const ::rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + + // get the neon lock from lock store + NeonLock * theLock + = m_aNeonLockStore.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_aNeonLockStore.removeLock( theLock ); + ne_lock_destroy( theLock ); + } + else + { + OSL_TRACE( "NeonSession::UNLOCK: unlocking of %s failed.", + rtl::OUStringToOString( makeAbsoluteURL( inPath ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + } + + HandleError( theRetVal, inPath, rEnv ); +} + +// ------------------------------------------------------------------- +// UNLOCK +// ------------------------------------------------------------------- +bool NeonSession::UNLOCK( NeonLock * pLock ) +{ + osl::Guard< osl::Mutex > theGuard( m_aMutex ); + +#if OSL_DEBUG_LEVEL > 0 + char * p = ne_uri_unparse( &(pLock->uri) ); + OSL_TRACE( "NeonSession::UNLOCK: Unlocking %s.", p ); + ne_free( p ); +#endif + + if ( ne_unlock( m_pHttpSession, pLock ) == NE_OK ) + { + OSL_TRACE( "UNLOCK succeeded." ); + return true; + } + else + { + OSL_TRACE( "UNLOCK failed!" ); + return false; + } +} + +// ------------------------------------------------------------------- +void NeonSession::abort() + throw ( DAVException ) +{ + if ( m_pHttpSession ) + { + osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex ); + ne_close_connection( m_pHttpSession ); + } +} + +// ------------------------------------------------------------------- +const ucbhelper::InternetProxyServer & NeonSession::getProxySettings() const +{ + if ( m_aScheme == "http" || m_aScheme == "https" ) + { + return m_rProxyDecider.getProxy( m_aScheme, + m_aHostName, + m_nPort ); + } + else + { + return m_rProxyDecider.getProxy( m_aScheme, + 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 NeonSession::removeExpiredLocktoken( const rtl::OUString & inURL, + const DAVRequestEnvironment & rEnv ) +{ + NeonLock * theLock = m_aNeonLockStore.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.empty() ) + 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( "NeonSession::removeExpiredLocktoken: Removing " + " expired lock token for %s. token: %s", + rtl::OUStringToOString( inURL, + RTL_TEXTENCODING_UTF8 ).getStr(), + theLock->token ); + + m_aNeonLockStore.removeLock( theLock ); + ne_lock_destroy( theLock ); + return true; + } + catch ( DAVException const & ) + { + } + return false; +} + +// ------------------------------------------------------------------- +// HandleError +// Common Error Handler +// ------------------------------------------------------------------- +void NeonSession::HandleError( int nError, + const rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ) +{ + m_aEnv = DAVRequestEnvironment(); + + // 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_aNeonLockStore.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, + NeonUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + case NE_AUTH: // User authentication failed on server + throw DAVException( DAVException::DAV_HTTP_AUTH, + NeonUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + case NE_PROXYAUTH: // User authentication failed on proxy + throw DAVException( DAVException::DAV_HTTP_AUTHPROXY, + NeonUri::makeConnectionEndPointString( + m_aProxyName, m_nProxyPort ) ); + + case NE_CONNECT: // Could not connect to server + throw DAVException( DAVException::DAV_HTTP_CONNECT, + NeonUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + case NE_TIMEOUT: // Connection timed out + throw DAVException( DAVException::DAV_HTTP_TIMEOUT, + NeonUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + case NE_FAILED: // The precondition failed + throw DAVException( DAVException::DAV_HTTP_FAILED, + NeonUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + case NE_RETRY: // Retry request (ne_end_request ONLY) + throw DAVException( DAVException::DAV_HTTP_RETRY, + NeonUri::makeConnectionEndPointString( + m_aHostName, m_nPort ) ); + + case NE_REDIRECT: + { + NeonUri aUri( ne_redirect_location( m_pHttpSession ) ); + throw DAVException( + DAVException::DAV_HTTP_REDIRECT, aUri.GetURI() ); + } + default: + { + OSL_TRACE( "NeonSession::HandleError : Unknown Neon error code!" ); + throw DAVException( DAVException::DAV_HTTP_ERROR, + rtl::OUString::createFromAscii( + ne_get_error( m_pHttpSession ) ) ); + } + } +} + +// ------------------------------------------------------------------- +namespace { + +void runResponseHeaderHandler( void * userdata, + const char * value ) +{ + rtl::OUString aHeader( rtl::OUString::createFromAscii( value ) ); + sal_Int32 nPos = aHeader.indexOf( ':' ); + + if ( nPos != -1 ) + { + rtl::OUString aHeaderName( aHeader.copy( 0, nPos ) ); + + NeonRequestContext * pCtx + = static_cast< NeonRequestContext * >( userdata ); + + // Note: Empty vector means that all headers are requested. + bool bIncludeIt = ( pCtx->pHeaderNames->empty() ); + + if ( !bIncludeIt ) + { + // Check whether this header was requested. + std::vector< ::rtl::OUString >::const_iterator it( + pCtx->pHeaderNames->begin() ); + const std::vector< ::rtl::OUString >::const_iterator end( + pCtx->pHeaderNames->end() ); + + while ( it != end ) + { + // header names are case insensitive + if ( (*it).equalsIgnoreAsciiCase( aHeaderName ) ) + { + aHeaderName = (*it); + break; + } + ++it; + } + + if ( it != end ) + bIncludeIt = true; + } + + if ( bIncludeIt ) + { + // Create & set the PropertyValue + DAVPropertyValue thePropertyValue; + thePropertyValue.IsCaseSensitive = false; + thePropertyValue.Name = aHeaderName; + + if ( nPos < aHeader.getLength() ) + thePropertyValue.Value <<= aHeader.copy( nPos + 1 ).trim(); + + // Add the newly created PropertyValue + pCtx->pResource->properties.push_back( thePropertyValue ); + } + } +} + +} // namespace + +// ------------------------------------------------------------------- +// static +int NeonSession::GET( ne_session * sess, + const char * uri, + ne_block_reader reader, + bool getheaders, + void * userdata ) +{ + //struct get_context ctx; + ne_request * req = ne_request_create( sess, "GET", uri ); + int ret; + + ne_decompress * dc + = ne_decompress_reader( req, ne_accept_2xx, reader, userdata ); + + { + osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex ); + ret = ne_request_dispatch( req ); + } + + if ( getheaders ) + { + void *cursor = NULL; + const char *name, *value; + while ( ( cursor = ne_response_header_iterate( + req, cursor, &name, &value ) ) != NULL ) + { + char buffer[8192]; + + ne_snprintf(buffer, sizeof buffer, "%s: %s", name, value); + runResponseHeaderHandler(userdata, buffer); + } + } + + if ( ret == NE_OK && ne_get_status( req )->klass != 2 ) + ret = NE_ERROR; + + if ( dc != 0 ) + ne_decompress_destroy(dc); + + ne_request_destroy( req ); + return ret; +} + +// ------------------------------------------------------------------- +// static +int NeonSession::PUT( ne_session * sess, + const char * uri, + const char * buffer, + size_t size) +{ + ne_request * req = ne_request_create( sess, "PUT", uri ); + int ret; + + ne_lock_using_resource( req, uri, 0 ); + ne_lock_using_parent( req, uri ); + + ne_set_request_body_buffer( req, buffer, size ); + + { + osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex ); + ret = ne_request_dispatch( req ); + } + + if ( ret == NE_OK && ne_get_status( req )->klass != 2 ) + ret = NE_ERROR; + + ne_request_destroy( req ); + return ret; +} + +// ------------------------------------------------------------------- +int NeonSession::POST( ne_session * sess, + const char * uri, + const char * buffer, + ne_block_reader reader, + void * userdata, + const rtl::OUString & rContentType, + const rtl::OUString & rReferer ) +{ + ne_request * req = ne_request_create( sess, "POST", uri ); + //struct get_context ctx; + int ret; + + RequestDataMap * pData = 0; + + if ( !rContentType.isEmpty() || !rReferer.isEmpty() ) + { + // Remember contenttype and referer. Data will be added to HTTP request + // header in in 'PreSendRequest' callback. + pData = static_cast< RequestDataMap* >( m_pRequestData ); + (*pData)[ req ] = RequestData( rContentType, rReferer ); + } + + //ctx.total = -1; + //ctx.fd = fd; + //ctx.error = 0; + //ctx.session = sess; + + ///* Read the value of the Content-Length header into ctx.total */ + //ne_add_response_header_handler( req, "Content-Length", + // ne_handle_numeric_header, &ctx.total ); + + ne_add_response_body_reader( req, ne_accept_2xx, reader, userdata ); + + ne_set_request_body_buffer( req, buffer, strlen( buffer ) ); + + { + osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex ); + ret = ne_request_dispatch( req ); + } + + //if ( ctx.error ) + // ret = NE_ERROR; + //else + if ( ret == NE_OK && ne_get_status( req )->klass != 2 ) + ret = NE_ERROR; + + ne_request_destroy( req ); + + if ( pData ) + { + // Remove request data from session's list. + RequestDataMap::iterator it = pData->find( req ); + if ( it != pData->end() ) + pData->erase( it ); + } + + return ret; +} + +// ------------------------------------------------------------------- +// static +bool +NeonSession::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 ); + memcpy( (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 +NeonSession::isDomainMatch( rtl::OUString certHostName ) +{ + rtl::OUString hostName = getHostName(); + + if (hostName.equalsIgnoreAsciiCase( certHostName ) ) + return sal_True; + + if ( 0 == certHostName.indexOf( '*' ) && + 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 NeonSession::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() ); + NeonUri aNeonUri( &aUri ); + ne_uri_free( &aUri ); + return aNeonUri.GetURI(); + } + } + catch ( DAVException const & ) + { + } + // error. + return rtl::OUString(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/NeonSession.hxx b/ucb/source/ucp/webdav-neon/NeonSession.hxx new file mode 100644 index 000000000000..f15eac408c4e --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonSession.hxx @@ -0,0 +1,300 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _NEONSESSION_HXX_ +#define _NEONSESSION_HXX_ + +#include +#include +#include "DAVSession.hxx" +#include "NeonTypes.hxx" +#include "NeonLockStore.hxx" +#include + +namespace ucbhelper { class ProxyDecider; } + +namespace webdav_ucp +{ + +// ------------------------------------------------------------------- +// NeonSession +// A DAVSession implementation using the neon/expat library +// ------------------------------------------------------------------- + +class NeonSession : public DAVSession +{ +private: + osl::Mutex m_aMutex; + rtl::OUString m_aScheme; + rtl::OUString m_aHostName; + rtl::OUString m_aProxyName; + sal_Int32 m_nPort; + sal_Int32 m_nProxyPort; + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > m_aFlags; + HttpSession * m_pHttpSession; + void * m_pRequestData; + const ucbhelper::InternetProxyDecider & m_rProxyDecider; + + // @@@ This should really be per-request data. But Neon currently + // (0.23.5) has no interface for passing per-request user data. + // Theoretically, a NeonSession instance could handle multiple requests + // at a time --currently it doesn't. Thus this is not an issue at the + // moment. + DAVRequestEnvironment m_aEnv; + + static bool m_bGlobalsInited; + static NeonLockStore m_aNeonLockStore; + +protected: + virtual ~NeonSession(); + +public: + NeonSession( const rtl::Reference< DAVSessionFactory > & rSessionFactory, + const rtl::OUString& inUri, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rFlags, + const ucbhelper::InternetProxyDecider & rProxyDecider ) + throw ( DAVException ); + + // DAVSession methods + virtual sal_Bool CanUse( const ::rtl::OUString & inPath, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rFlags ); + + virtual sal_Bool UsesProxy(); + + const DAVRequestEnvironment & getRequestEnvironment() const + { return m_aEnv; } + + virtual void + OPTIONS( const ::rtl::OUString & inPath, + DAVCapabilities & outCapabilities, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + // 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 ); + + 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_aHostName; } + + const ::uno::Reference< ::lang::XMultiServiceFactory > getMSF() + { return m_xFactory->getServiceFactory(); } + + const void * getRequestData() const { return m_pRequestData; } + + sal_Bool isDomainMatch( rtl::OUString certHostName ); + +private: + friend class NeonLockStore; + + void Init( void ) + throw ( DAVException ); + + void Init( const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + // ret: true => retry request. + void HandleError( int nError, + const rtl::OUString & inPath, + const DAVRequestEnvironment & rEnv ) + throw ( DAVException ); + + const ucbhelper::InternetProxyServer & getProxySettings() const; + + bool removeExpiredLocktoken( const rtl::OUString & inURL, + const DAVRequestEnvironment & rEnv ); + + // refresh lock, called by NeonLockStore::refreshLocks + bool LOCK( NeonLock * pLock, + sal_Int32 & rlastChanceToSendRefreshRequest ); + + // unlock, called by NeonLockStore::~NeonLockStore + bool UNLOCK( NeonLock * pLock ); + + // low level GET implementation, used by public GET implementations + static int GET( ne_session * sess, + const char * uri, + ne_block_reader reader, + bool getheaders, + void * userdata ); + + // Buffer-based PUT implementation. Neon only has file descriptor- + // based API. + static int PUT( ne_session * sess, + const char * uri, + const char * buffer, + size_t size ); + + // Buffer-based POST implementation. Neon only has file descriptor- + // based API. + int POST( ne_session * 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 webdav_ucp + +#endif // _NEONSESSION_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/NeonTypes.hxx b/ucb/source/ucp/webdav-neon/NeonTypes.hxx new file mode 100644 index 000000000000..d6c27417439c --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonTypes.hxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _NEONTYPES_HXX_ +#define _NEONTYPES_HXX_ + +#include +#include +#include +#include +#include "warnings_guard_ne_locks.h" + +typedef ne_session HttpSession; +typedef ne_status HttpStatus; +typedef ne_server_capabilities HttpServerCapabilities; + +typedef ne_propname NeonPropName; +typedef ne_prop_result_set NeonPropFindResultSet; + +typedef struct ne_lock NeonLock; + +#endif // _NEONTYPES_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/NeonUri.cxx b/ucb/source/ucp/webdav-neon/NeonUri.cxx new file mode 100644 index 000000000000..530306c2badc --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonUri.cxx @@ -0,0 +1,337 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include +#include +#include +#include +#include "ne_alloc.h" +#include "NeonUri.hxx" +#include "DAVException.hxx" + +#include "../inc/urihelper.hxx" + +using namespace webdav_ucp; + +# if defined __SUNPRO_CC +// FIXME: not sure whether initializing a ne_uri statically is supposed to work +// the string fields of ne_uri are char*, not const char* +# pragma disable_warn +# endif + +#if defined __GNUC__ +#define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +/* Diagnostics pragma was introduced with gcc-4.2.1 */ +#if GCC_VERSION >= 40201 +#pragma GCC diagnostic ignored "-Wwrite-strings" +#endif +#endif + +namespace { + +const ne_uri g_sUriDefaultsHTTP = { "http", + NULL, + NULL, + DEFAULT_HTTP_PORT, + NULL, + NULL, + NULL }; +const ne_uri g_sUriDefaultsHTTPS = { "https", + NULL, + NULL, + DEFAULT_HTTPS_PORT, + NULL, + NULL, + NULL }; +const ne_uri g_sUriDefaultsFTP = { "ftp", + NULL, + NULL, + DEFAULT_FTP_PORT, + NULL, + NULL, + NULL }; +} // namespace + +# if defined __SUNPRO_CC +# pragma enable_warn +#endif + +// ------------------------------------------------------------------- +// Constructor +// ------------------------------------------------------------------- + +namespace { + +//TODO! rtl::OString::matchIgnoreAsciiCaseAsciiL() missing +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; +} + +} + +NeonUri::NeonUri( const ne_uri * inUri ) + throw ( DAVException ) +{ + if ( inUri == 0 ) + throw DAVException( DAVException::DAV_INVALID_ARG ); + + char * uri = ne_uri_unparse( inUri ); + + if ( uri == 0 ) + throw DAVException( DAVException::DAV_INVALID_ARG ); + + init( rtl::OString( uri ), inUri ); + ne_free( uri ); + + calculateURI(); +} + +NeonUri::NeonUri( const rtl::OUString & inUri ) + throw ( DAVException ) +{ + if ( inUri.isEmpty() ) + 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 ); + + ne_uri theUri; + if ( ne_uri_parse( theInputUri.getStr(), &theUri ) != 0 ) + { + ne_uri_free( &theUri ); + throw DAVException( DAVException::DAV_INVALID_ARG ); + } + + init( theInputUri, &theUri ); + ne_uri_free( &theUri ); + + calculateURI(); +} + +void NeonUri::init( const rtl::OString & rUri, const ne_uri * pUri ) +{ + // Complete URI. + const ne_uri * pUriDefs + = matchIgnoreAsciiCase( rUri, + RTL_CONSTASCII_STRINGPARAM( "ftp:" ) ) ? + &g_sUriDefaultsFTP : + matchIgnoreAsciiCase( rUri, + RTL_CONSTASCII_STRINGPARAM( "https:" ) ) ? + &g_sUriDefaultsHTTPS : + &g_sUriDefaultsHTTP; + + mScheme = rtl::OStringToOUString( + pUri->scheme ? pUri->scheme : pUriDefs->scheme, + RTL_TEXTENCODING_UTF8 ); + mUserInfo = rtl::OStringToOUString( + pUri->userinfo ? pUri->userinfo : pUriDefs->userinfo, + RTL_TEXTENCODING_UTF8 ); + mHostName = rtl::OStringToOUString( + pUri->host ? pUri->host : pUriDefs->host, + RTL_TEXTENCODING_UTF8 ); + mPort = pUri->port > 0 ? pUri->port : pUriDefs->port; + mPath = rtl::OStringToOUString( + pUri->path ? pUri->path : pUriDefs->path, + RTL_TEXTENCODING_UTF8 ); + + if ( pUri->query ) + { + mPath += rtl::OUString("?"); + mPath += rtl::OStringToOUString( + pUri->query, RTL_TEXTENCODING_UTF8 ); + } + + if ( pUri->fragment ) + { + mPath += rtl::OUString("#"); + mPath += rtl::OStringToOUString( + pUri->fragment, RTL_TEXTENCODING_UTF8 ); + } +} + +// ------------------------------------------------------------------- +// Destructor +// ------------------------------------------------------------------- +NeonUri::~NeonUri( ) +{ +} + +void NeonUri::calculateURI () +{ + rtl::OUStringBuffer aBuf( mScheme ); + aBuf.appendAscii( "://" ); + if ( !mUserInfo.isEmpty() ) + { + //TODO! differentiate between empty and missing userinfo + 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 != "http"; + break; + + case DEFAULT_HTTPS_PORT: + bAppendPort = mScheme != "https"; + break; + + case DEFAULT_FTP_PORT: + bAppendPort = mScheme != "ftp"; + break; + } + if ( bAppendPort ) + { + aBuf.appendAscii( ":" ); + aBuf.append( rtl::OUString::valueOf( mPort ) ); + } + aBuf.append( mPath ); + + mURI = aBuf.makeStringAndClear(); +} + +::rtl::OUString NeonUri::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(RTL_CONSTASCII_USTRINGPARAM ("/")); +} + +bool NeonUri::operator== ( const NeonUri & rOther ) const +{ + return ( mURI == rOther.mURI ); +} + +::rtl::OUString NeonUri::GetPathBaseNameUnescaped () const +{ + return unescape( GetPathBaseName() ); +} + +void NeonUri::AppendPath (const rtl::OUString& rPath) +{ + if (mPath.lastIndexOf ('/') != mPath.getLength () - 1) + mPath += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("/")); + + mPath += rPath; + calculateURI (); +}; + +// static +rtl::OUString NeonUri::escapeSegment( const rtl::OUString& segment ) +{ + return rtl::Uri::encode( segment, + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ); +} + +// static +rtl::OUString NeonUri::unescape( const rtl::OUString& segment ) +{ + return rtl::Uri::decode( segment, + rtl_UriDecodeWithCharset, + RTL_TEXTENCODING_UTF8 ); +} + +// static +rtl::OUString NeonUri::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-neon/NeonUri.hxx b/ucb/source/ucp/webdav-neon/NeonUri.hxx new file mode 100644 index 000000000000..06d59317affb --- /dev/null +++ b/ucb/source/ucp/webdav-neon/NeonUri.hxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _NEONURI_HXX_ +#define _NEONURI_HXX_ + +#include +#include +#include + +namespace webdav_ucp +{ + +#define DEFAULT_HTTP_PORT 80 +#define DEFAULT_HTTPS_PORT 443 +#define DEFAULT_FTP_PORT 21 + +// ------------------------------------------------------------------- +// NeonUri +// A URI implementation for use with the neon/expat library +// ------------------------------------------------------------------- +class NeonUri +{ + private: + ::rtl::OUString mURI; + ::rtl::OUString mScheme; + ::rtl::OUString mUserInfo; + ::rtl::OUString mHostName; + sal_Int32 mPort; + ::rtl::OUString mPath; + + void init( const rtl::OString & rUri, const ne_uri * pUri ); + void calculateURI (); + + public: + NeonUri( const ::rtl::OUString & inUri ) throw ( DAVException ); + NeonUri( const ne_uri * inUri ) throw ( DAVException ); + ~NeonUri( ); + + bool operator== ( const NeonUri & rOther ) const; + bool operator!= ( const NeonUri & rOther ) const + { return !operator==( rOther ); } + + 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 webdav_ucp + +#endif // _NEONURI_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/PropertyMap.hxx b/ucb/source/ucp/webdav-neon/PropertyMap.hxx new file mode 100644 index 000000000000..ca1cb03d8968 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/PropertyMap.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _WEBDAV_UCP_PROPERTYMAP_HXX +#define _WEBDAV_UCP_PROPERTYMAP_HXX + +#include +#include + +namespace webdav_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 boost::unordered_set +< + ::com::sun::star::beans::Property, + hashPropertyName, + equalPropertyName +> +PropertyMap; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/UCBDeadPropertyValue.cxx b/ucb/source/ucp/webdav-neon/UCBDeadPropertyValue.cxx new file mode 100644 index 000000000000..780e45f35461 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/UCBDeadPropertyValue.cxx @@ -0,0 +1,522 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#include +#include +#include +#include +#include "UCBDeadPropertyValue.hxx" + +using namespace webdav_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("string"); +const rtl::OUString UCBDeadPropertyValue::aTypeLong("long"); +const rtl::OUString UCBDeadPropertyValue::aTypeShort("short"); +const rtl::OUString UCBDeadPropertyValue::aTypeBoolean("boolean"); +const rtl::OUString UCBDeadPropertyValue::aTypeChar("char"); +const rtl::OUString UCBDeadPropertyValue::aTypeByte("byte"); +const rtl::OUString UCBDeadPropertyValue::aTypeHyper("hyper"); +const rtl::OUString UCBDeadPropertyValue::aTypeFloat("float"); +const rtl::OUString UCBDeadPropertyValue::aTypeDouble("double"); + +// static +const rtl::OUString UCBDeadPropertyValue::aXMLPre(""); +const rtl::OUString UCBDeadPropertyValue::aXMLMid(""); +const rtl::OUString UCBDeadPropertyValue::aXMLEnd(""); + +#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 aResult.makeStringAndClear(); +} + +////////////////////////////////////////////////////////////////////////// +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_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + + c = pValue[ nPos ]; + + if ( 'p' == c ) + { + // %per; + + if ( nPos > nEnd - 4 ) + { + OSL_FAIL( "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_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + } + else if ( 'l' == c ) + { + // %lt; + + if ( nPos > nEnd - 3 ) + { + OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + + if ( ( 't' == pValue[ nPos + 1 ] ) + && + ( ';' == pValue[ nPos + 2 ] ) ) + { + aResult.append( sal_Unicode( '<' ) ); + nPos += 2; + } + else + { + OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + } + else if ( 'g' == c ) + { + // %gt; + + if ( nPos > nEnd - 3 ) + { + OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + + if ( ( 't' == pValue[ nPos + 1 ] ) + && + ( ';' == pValue[ nPos + 2 ] ) ) + { + aResult.append( sal_Unicode( '>' ) ); + nPos += 2; + } + else + { + OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + } + else + { + OSL_FAIL( "UCBDeadPropertyValue::decodeValue - syntax error!" ); + return rtl::OUString(); + } + } + else + aResult.append( c ); + + nPos++; + } + + return aResult.makeStringAndClear(); +} + +////////////////////////////////////////////////////////////////////////// +// 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("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_FAIL( "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_FAIL( "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-neon/UCBDeadPropertyValue.hxx b/ucb/source/ucp/webdav-neon/UCBDeadPropertyValue.hxx new file mode 100644 index 000000000000..c56a3f93b270 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/UCBDeadPropertyValue.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _UCBDEADPROPERTYVALUE_HXX_ +#define _UCBDEADPROPERTYVALUE_HXX_ + +#include +#include + +namespace webdav_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-neon/ucpdav1.component b/ucb/source/ucp/webdav-neon/ucpdav1.component new file mode 100644 index 000000000000..5abdc1b27b92 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/ucpdav1.component @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/ucb/source/ucp/webdav-neon/warnings_guard_ne_locks.h b/ucb/source/ucp/webdav-neon/warnings_guard_ne_locks.h new file mode 100644 index 000000000000..44fa99da7e21 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/warnings_guard_ne_locks.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Version: MPL 1.1 / GPLv3+ / LGPLv3+ + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License or as specified alternatively below. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * Major Contributor(s): + * Copyright (C) 2011 Red Hat, Inc., Eike Rathke + * (initial developer) + * + * All Rights Reserved. + * + * For minor contributions see the git repository. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 3 or later (the "GPLv3+"), or + * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), + * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable + * instead of those above. + */ + +#ifndef INCLUDED_WARNINGS_GUARD_NE_LOCKS_H +#define INCLUDED_WARNINGS_GUARD_NE_LOCKS_H + +// Because the GCC system_header mechanism doesn't work in .c/.cxx compilation +// units and more important affects the rest of the current include file, the +// warnings guard is separated into this header file on its own. + +/* + Silence down this WaE: + /usr/include/neon/ne_locks.h:125:51: warning: 'int ne_lock(ne_session*, ne_lock*)' + hides constructor for 'struct ne_lock' [-Wshadow] +*/ + +#ifdef _MSC_VER +#pragma warning(push, 1) +#elif defined __GNUC__ +#pragma GCC system_header +#endif +#include +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif // INCLUDED_WARNINGS_GUARD_NE_LOCKS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/webdav-neon/webdavcontent.cxx b/ucb/source/ucp/webdav-neon/webdavcontent.cxx new file mode 100644 index 000000000000..bfabf8cedfac --- /dev/null +++ b/ucb/source/ucp/webdav-neon/webdavcontent.cxx @@ -0,0 +1,3170 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ + +#include +#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 "NeonUri.hxx" +#include "UCBDeadPropertyValue.hxx" + +using namespace com::sun::star; +using namespace webdav_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() ) ); + + NeonUri 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< uno::XComponentContext > xCtx( + comphelper::getComponentContext( m_xSMgr ) ); + + 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( "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( 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( WEBDAV_COLLECTION_TYPE ); + + return rtl::OUString( 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 == "getPropertyValues" ) + { + ////////////////////////////////////////////////////////////////// + // getPropertyValues + ////////////////////////////////////////////////////////////////// + + uno::Sequence< beans::Property > Properties; + if ( !( aCommand.Argument >>= Properties ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString( "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + aRet <<= getPropertyValues( Properties, Environment ); + } + else if ( aCommand.Name == "setPropertyValues" ) + { + ////////////////////////////////////////////////////////////////// + // setPropertyValues + ////////////////////////////////////////////////////////////////// + + uno::Sequence< beans::PropertyValue > aProperties; + if ( !( aCommand.Argument >>= aProperties ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString( "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + if ( !aProperties.getLength() ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString( "No properties!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + aRet <<= setPropertyValues( aProperties, Environment ); + } + else if ( aCommand.Name == "getPropertySetInfo" ) + { + ////////////////////////////////////////////////////////////////// + // getPropertySetInfo + ////////////////////////////////////////////////////////////////// + + // Note: Implemented by base class. + aRet <<= getPropertySetInfo( Environment, + sal_False /* don't cache data */ ); + } + else if ( aCommand.Name == "getCommandInfo" ) + { + ////////////////////////////////////////////////////////////////// + // getCommandInfo + ////////////////////////////////////////////////////////////////// + + // Note: Implemented by base class. + aRet <<= getCommandInfo( Environment, sal_False ); + } + else if ( aCommand.Name == "open" ) + { + ////////////////////////////////////////////////////////////////// + // open + ////////////////////////////////////////////////////////////////// + + ucb::OpenCommandArgument3 aOpenCommand; + ucb::OpenCommandArgument2 aTmp; + if ( !( aCommand.Argument >>= aTmp ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString( "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + if ( !( aCommand.Argument >>= aOpenCommand ) ) + { + // compat mode, extract Arg2 info into newer structure + aOpenCommand.Mode = aTmp.Mode; + aOpenCommand.Priority = aTmp.Priority; + aOpenCommand.Sink = aTmp.Sink; + aOpenCommand.Properties = aTmp.Properties; + aOpenCommand.SortingInfo = aTmp.SortingInfo; + } + + aRet = open( aOpenCommand, Environment ); + } + else if ( aCommand.Name == "insert" ) + { + ////////////////////////////////////////////////////////////////// + // insert + ////////////////////////////////////////////////////////////////// + + ucb::InsertCommandArgument arg; + if ( !( aCommand.Argument >>= arg ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString( "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + insert( arg.Data, arg.ReplaceExisting, Environment ); + } + else if ( aCommand.Name == "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 + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + { + 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 == "transfer" && isFolder( Environment ) ) + { + ////////////////////////////////////////////////////////////////// + // transfer + // ( Not available at documents ) + ////////////////////////////////////////////////////////////////// + + ucb::TransferInfo transferArgs; + if ( !( aCommand.Argument >>= transferArgs ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString( "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + transfer( transferArgs, Environment ); + } + else if ( aCommand.Name == "post" ) + { + ////////////////////////////////////////////////////////////////// + // post + ////////////////////////////////////////////////////////////////// + + ucb::PostCommandArgument2 aArg; + if ( !( aCommand.Argument >>= aArg ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString( "Wrong argument type!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + post( aArg, Environment ); + } + else if ( aCommand.Name == "lock" && supportsExclusiveWriteLock( Environment ) ) + { + ////////////////////////////////////////////////////////////////// + // lock + ////////////////////////////////////////////////////////////////// + + lock( Environment ); + } + else if ( aCommand.Name == "unlock" && supportsExclusiveWriteLock( Environment ) ) + { + ////////////////////////////////////////////////////////////////// + // unlock + ////////////////////////////////////////////////////////////////// + + unlock( Environment ); + } + else if ( aCommand.Name == "createNewContent" && isFolder( Environment ) ) + { + ////////////////////////////////////////////////////////////////// + // createNewContent + ////////////////////////////////////////////////////////////////// + + ucb::ContentInfo aArg; + if ( !( aCommand.Argument >>= aArg ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( lang::IllegalArgumentException( + rtl::OUString( "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 + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + { + 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.isEmpty() ) + throw lang::IllegalArgumentException(); + + // Check property type. + if ( !UCBDeadPropertyValue::supportsType( DefaultValue.getValueType() ) ) + { + OSL_FAIL( "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. + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + { + 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 FTP: + case NON_DAV: + // Store property locally. + ContentImplHelper::addProperty( Name, + Attributes, + DefaultValue ); + break; + + default: + OSL_FAIL( "Content::addProperty - " + "Unsupported resource type!" ); + break; + } + } + catch ( uno::Exception const & ) + { + OSL_FAIL( "Content::addProperty - " + "Unable to determine resource type!" ); + } + } + else + { + OSL_FAIL( "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; + + ////////////////////////////////////////////////////////////////////// + // 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. + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + { + 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 FTP: + case NON_DAV: + // Try to remove property from local store. + ContentImplHelper::removeProperty( Name ); + break; + + default: + OSL_FAIL( "Content::removeProperty - " + "Unsupported resource type!" ); + break; + } + } + catch ( uno::Exception const & ) + { + OSL_FAIL( "Content::removeProperty - " + "Unable to determine resource type!" ); + } + } + else + { + OSL_FAIL( "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( WEBDAV_CONTENT_TYPE ); + aSeq.getArray()[ 0 ].Attributes + = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM + | ucb::ContentInfoAttribute::KIND_DOCUMENT; + + beans::Property aProp; + m_pProvider->getProperty( + rtl::OUString( "Title" ), aProp ); + + uno::Sequence< beans::Property > aDocProps( 1 ); + aDocProps.getArray()[ 0 ] = aProp; + aSeq.getArray()[ 0 ].Properties = aDocProps; + + // folder. + aSeq.getArray()[ 1 ].Type + = rtl::OUString( 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.isEmpty() ) + return uno::Reference< ucb::XContent >(); + + if ( ( Info.Type != WEBDAV_COLLECTION_TYPE ) && ( Info.Type != WEBDAV_CONTENT_TYPE ) ) + return uno::Reference< ucb::XContent >(); + + rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); + + OSL_ENSURE( !aURL.isEmpty(), + "WebdavContent::createNewContent - empty identifier!" ); + + if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() ) + aURL += rtl::OUString("/"); + + sal_Bool isCollection; + if ( Info.Type == WEBDAV_COLLECTION_TYPE ) + { + aURL += rtl::OUString("New_Collection"); + isCollection = sal_True; + } + else + { + aURL += rtl::OUString("New_Content"); + isCollection = sal_False; + } + + uno::Reference< ucb::XContentIdentifier > xId( + new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ) ); + + // create the local content + try + { + return new ::webdav_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. + SAL_WNODEPRECATED_DECLARATIONS_PUSH + const std::auto_ptr< PropertyValueMap > & xProps = rData.getProperties(); + SAL_WNODEPRECATED_DECLARATIONS_POP + + 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 ) +{ + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< ContentProperties > xProps; + std::auto_ptr< ContentProperties > xCachedProps; + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + 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 = NeonUri::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.empty() ) + { + 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.empty() ) + { + 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.empty() ) + { + 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. + NeonUri 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( "Title" ), + uno::makeAny( aUnescapedTitle ), + true ); + } + else + { + if ( !xProps.get() ) + xProps.reset( new ContentProperties( aUnescapedTitle, false ) ); + else + xProps->addProperty( + rtl::OUString( "Title" ), + uno::makeAny( aUnescapedTitle ), + true ); + + xProps->addProperty( + rtl::OUString( "IsFolder" ), + uno::makeAny( false ), + true ); + xProps->addProperty( + rtl::OUString( "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 == "BaseURI" ) + { + // Add BaseURI property, if requested. + xProps->addProperty( + rtl::OUString( "BaseURI" ), + uno::makeAny( getBaseURI( xResAccess ) ), + true ); + } + else if ( rName == "CreatableContentsInfo" ) + { + // Add CreatableContentsInfo property, if requested. + sal_Bool bFolder = sal_False; + xProps->getValue( + rtl::OUString( "IsFolder" ) ) + >>= bFolder; + xProps->addProperty( + rtl::OUString( "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 = NeonUri::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; + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + + { + 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( "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + continue; + } + + ////////////////////////////////////////////////////////////////// + // Mandatory props. + ////////////////////////////////////////////////////////////////// + + if ( rName == "ContentType" ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString( "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rName == "IsDocument" ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString( "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rName == "IsFolder" ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString( "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rName == "Title" ) + { + rtl::OUString aNewValue; + if ( rValue.Value >>= aNewValue ) + { + // No empty titles! + if ( !aNewValue.isEmpty() ) + { + try + { + NeonUri 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( "Invalid content identifier!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ); + } + } + else + { + aRet[ n ] <<= lang::IllegalArgumentException( + rtl::OUString( "Empty title not allowed!" ), + static_cast< cppu::OWeakObject * >( this ), + -1 ); + } + } + else + { + aRet[ n ] <<= beans::IllegalTypeException( + rtl::OUString( "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( "Property is unknown!" ), + static_cast< cppu::OWeakObject * >( this ) ); + continue; + } + + if ( rName == "Size" ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString( "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rName == "DateCreated" ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString( "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rName == "DateModified" ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString( "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + else if ( rName == "MediaType" ) + { + // Read-only property! + // (but could be writable, if 'getcontenttype' would be) + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString( "Property is read-only!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + if ( rName == "CreatableContentsInfo" ) + { + // Read-only property! + aRet[ n ] <<= lang::IllegalAccessException( + rtl::OUString( "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( "No property set for storing the value!" ), + static_cast< cppu::OWeakObject * >( this ) ); + } + } + } + } + } // for + + if ( !bTransient && !aProppatchValues.empty() ) + { + 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_FAIL( // "Content::setPropertyValues - PROPPATCH failed!" ); + + cancelCommandExecution( e, xEnv ); + // unreachable + } + } + + if ( bExchange ) + { + // Assemble new content identifier... + + rtl::OUString aNewURL = getParentURL(); + if ( aNewURL.lastIndexOf( '/' ) != ( aNewURL.getLength() - 1 ) ) + aNewURL += rtl::OUString("/"); + + aNewURL += NeonUri::escapeSegment( aNewTitle ); + + uno::Reference< ucb::XContentIdentifier > xNewId + = new ::ucbhelper::ContentIdentifier( xSMgr, aNewURL ); + uno::Reference< ucb::XContentIdentifier > xOldId = xIdentifier; + + try + { + NeonUri sourceURI( xOldId->getContentIdentifier() ); + NeonUri 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("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.isEmpty() ) + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + aEvent.PropertyName = rtl::OUString("Title"); + aEvent.OldValue = uno::makeAny( aOldTitle ); + aEvent.NewValue = uno::makeAny( aNewTitle ); + + m_aEscapedTitle = NeonUri::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::OpenCommandArgument3 & 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; + if ( getResourceType( xEnv ) == FTP ) + { + // #114653# + aMsg.appendAscii( "FTP over HTTP proxy: resource cannot " + "be opened as folder! Wrong Open Mode!" ); + } + else + { + 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 + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + + { + osl::MutexGuard aGuard( m_aMutex ); + + xResAccess.reset( + new DAVResourceAccess( *m_xResAccess.get() ) ); + } + + xResAccess->setFlags( rArg.OpeningFlags ); + 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 + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + { + osl::MutexGuard aGuard( m_aMutex ); + + xResAccess.reset( + new DAVResourceAccess( *m_xResAccess.get() ) ); + } + + xResAccess->setFlags( rArg.OpeningFlags ); + + // 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 + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + { + 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 + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + { + 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("/"); + } + + 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( + ::webdav_ucp::Content::ContentRef( + static_cast< ::webdav_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; + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + + { + 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.isEmpty() ) + { + OSL_FAIL( "Content::insert - Title missing!" ); + + uno::Sequence< rtl::OUString > aProps( 1 ); + aProps[ 0 ] = rtl::OUString("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 ) ) + { + ucb::UnsupportedNameClashException aEx( + rtl::OUString( "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_FAIL( "Content::insert - " + "Unknown interaction selection!" ); + throw ucb::CommandFailedException( + rtl::OUString( "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("/"); + + 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 + { + NeonUri 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; + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + + { + 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 + { + NeonUri sourceURI( rArgs.SourceURL ); + NeonUri targetURI( xIdentifier->getContentIdentifier() ); + aTargetURI = targetURI.GetPathBaseNameUnescaped(); + + // Check source's and target's URL scheme + // + const rtl::OUString aScheme = sourceURI.GetScheme().toAsciiLowerCase(); + if ( aScheme == WEBDAV_URL_SCHEME ) + { + sourceURI.SetScheme( + rtl::OUString( HTTP_URL_SCHEME ) ); + } + else if ( aScheme == DAV_URL_SCHEME ) + { + sourceURI.SetScheme( + rtl::OUString( HTTP_URL_SCHEME ) ); + } + else if ( aScheme == DAVS_URL_SCHEME ) + { + sourceURI.SetScheme( + rtl::OUString( HTTPS_URL_SCHEME ) ); + } + else + { + if ( aScheme != HTTP_URL_SCHEME && aScheme != HTTPS_URL_SCHEME ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( + ucb::InteractiveBadTransferURLException( + rtl::OUString( "Unsupported URL scheme!" ), + static_cast< cppu::OWeakObject * >( this ) ) ), + Environment ); + // Unreachable + } + } + + if ( targetURI.GetScheme().toAsciiLowerCase() == WEBDAV_URL_SCHEME ) + targetURI.SetScheme( + rtl::OUString( HTTP_URL_SCHEME ) ); + else if ( targetURI.GetScheme().toAsciiLowerCase() == DAV_URL_SCHEME ) + targetURI.SetScheme( + rtl::OUString( 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().isEmpty() && + ( sourceURI.GetHost() != targetURI.GetHost() ) ) + { + ucbhelper::cancelCommandExecution( + uno::makeAny( ucb::InteractiveBadTransferURLException( + rtl::OUString( "Different hosts!" ), + static_cast< cppu::OWeakObject * >( this ) ) ), + Environment ); + // Unreachable + } + + rtl::OUString aTitle = rArgs.NewTitle; + + if ( aTitle.isEmpty() ) + aTitle = sourceURI.GetPathBaseNameUnescaped(); + + if ( aTitle == "/" ) + { + // kso: ??? + aTitle = rtl::OUString(); + } + + targetURI.AppendPath( aTitle ); + + rtl::OUString aTargetURL = xIdentifier->getContentIdentifier(); + if ( ( aTargetURL.lastIndexOf( '/' ) + 1 ) + != aTargetURL.getLength() ) + aTargetURL += rtl::OUString("/"); + + 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 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... + + ::webdav_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 + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + { + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); + } + + uno::Any aOwnerAny; + aOwnerAny + <<= rtl::OUString("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 + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + SAL_WNODEPRECATED_DECLARATIONS_POP + { + 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_FAIL( "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_FAIL( "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("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(static_cast('/')); + + 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("Uri"), -1, + uno::makeAny(aURL), + beans::PropertyState_DIRECT_VALUE); + + aException <<= + ucb::InteractiveAugmentedIOException( + rtl::OUString("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: + aException <<= + ucb::InteractiveLockingLockedException( + rtl::OUString("Locked!"), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + aURL, + sal_False ); // not SelfOwned + break; + + case DAVException::DAV_LOCKED_SELF: + aException <<= + ucb::InteractiveLockingLockedException( + rtl::OUString("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("Not locked!"), + static_cast< cppu::OWeakObject * >( this ), + task::InteractionClassification_ERROR, + aURL ); + break; + + case DAVException::DAV_LOCK_EXPIRED: + aException <<= + ucb::InteractiveLockingLockExpiredException( + rtl::OUString("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 +} + +//========================================================================= +SAL_WNODEPRECATED_DECLARATIONS_PUSH +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( "Content-Location" ) ) >>= aLocation; + if ( !aLocation.isEmpty() ) + { + 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() ); + + if ( aScheme == FTP_URL_SCHEME ) + { + eResourceType = FTP; + } + else + { + 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("IsFolder"); + aProperties[ 1 ].Name + = rtl::OUString("IsDocument"); + aProperties[ 2 ].Name + = rtl::OUString("IsReadOnly"); + aProperties[ 3 ].Name + = rtl::OUString("MediaType"); + aProperties[ 4 ].Name + = DAVProperties::SUPPORTEDLOCK; + + ContentProperties::UCBNamesToDAVNames( + aProperties, aPropNames ); + + rResAccess->PROPFIND( + DAVZERO, aPropNames, resources, xEnv ); + + 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; + } + } + } + m_eResourceType = eResourceType; + } + return m_eResourceType; +} +SAL_WNODEPRECATED_DECLARATIONS_POP + +//========================================================================= +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-neon/webdavcontent.hxx b/ucb/source/ucp/webdav-neon/webdavcontent.hxx new file mode 100644 index 000000000000..790e0de83a0d --- /dev/null +++ b/ucb/source/ucp/webdav-neon/webdavcontent.hxx @@ -0,0 +1,308 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#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 OpenCommandArgument3; + struct PostCommandArgument2; + struct TransferInfo; +} } } } + +namespace webdav_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, + FTP, + 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 ); + + SAL_WNODEPRECATED_DECLARATIONS_PUSH + const rtl::OUString + getBaseURI( const std::auto_ptr< DAVResourceAccess > & rResAccess ); + SAL_WNODEPRECATED_DECLARATIONS_POP + + const ResourceType & + getResourceType( const ::com::sun::star::uno::Reference< + ::com::sun::star::ucb::XCommandEnvironment >& xEnv ) + throw ( ::com::sun::star::uno::Exception ); + + SAL_WNODEPRECATED_DECLARATIONS_PUSH + 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 ); + SAL_WNODEPRECATED_DECLARATIONS_POP + + // Command "open" + com::sun::star::uno::Any open( + const com::sun::star::ucb::OpenCommandArgument3 & 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-neon/webdavcontentcaps.cxx b/ucb/source/ucp/webdav-neon/webdavcontentcaps.cxx new file mode 100644 index 000000000000..478dc66a4bb4 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/webdavcontentcaps.cxx @@ -0,0 +1,656 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ + +#include +#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 webdav_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::SOURCE, + -1, + getCppuType( static_cast< + const uno::Sequence< ucb::Link > * >( 0 ) ), + beans::PropertyAttribute::BOUND ) ); + + 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; + SAL_WNODEPRECATED_DECLARATIONS_PUSH + std::auto_ptr< DAVResourceAccess > xResAccess; + std::auto_ptr< ContentProperties > xCachedProps; + SAL_WNODEPRECATED_DECLARATIONS_POP + 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) == "ContentType" ) + { + bHasContentType = sal_True; + } + else if ( !bHasIsDocument && (*it) == "IsDocument" ) + { + bHasIsDocument = sal_True; + } + else if ( !bHasIsFolder && (*it) == "IsFolder" ) + { + bHasIsFolder = sal_True; + } + else if ( !bHasTitle && (*it) == "Title" ) + { + bHasTitle = sal_True; + } + else if ( !bHasBaseURI && (*it) == "BaseURI" ) + { + bHasBaseURI = sal_True; + } + else if ( !bHasDateCreated && (*it) == "DateCreated" ) + { + bHasDateCreated = sal_True; + } + else if ( !bHasDateModified && (*it) == "DateModified" ) + { + bHasDateModified = sal_True; + } + else if ( !bHasMediaType && (*it) == "MediaType" ) + { + bHasMediaType = sal_True; + } + else if ( !bHasSize && (*it) == "Size" ) + { + bHasSize = sal_True; + } + else if ( !bHasCreatableInfos && (*it) == "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(); + + SAL_WNODEPRECATED_DECLARATIONS_PUSH + const std::auto_ptr< PropertyValueMap > & xProps + = xCachedProps->getProperties(); + SAL_WNODEPRECATED_DECLARATIONS_POP + + 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-neon/webdavdatasupplier.cxx b/ucb/source/ucp/webdav-neon/webdavdatasupplier.cxx new file mode 100644 index 000000000000..f5f662062973 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/webdavdatasupplier.cxx @@ -0,0 +1,506 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ +#include +#include +#include +#include +#include "webdavdatasupplier.hxx" +#include "webdavcontent.hxx" +#include "ContentProperties.hxx" +#include "DAVSession.hxx" +#include "NeonUri.hxx" + +using namespace com::sun::star; +using namespace webdav_ucp; + +namespace webdav_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.isEmpty() ) + { + // 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("/"); + + aId += props.getEscapedTitle(); + + if ( props.isTrailingSlash() ) + aId += rtl::OUString("/"); + + 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.isEmpty() ) + { + 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_FAIL( "PROPFIND : DAVException" ); + m_pImpl->m_bThrowException = sal_True; + } + + if ( !m_pImpl->m_bThrowException ) + { + try + { + NeonUri 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 = NeonUri::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 + { + NeonUri aCurrURI( rRes.uri ); + rtl::OUString aCurrPath = aCurrURI.GetPath(); + if ( aCurrPath.getStr()[ + aCurrPath.getLength() - 1 ] + == sal_Unicode( '/' ) ) + aCurrPath + = aCurrPath.copy( + 0, + aCurrPath.getLength() - 1 ); + + aCurrPath = NeonUri::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( "IsFolder" ) ); + rValue >>= bFolder; + + if ( !bFolder ) + continue; + + break; + } + + case ucb::OpenMode::DOCUMENTS: + { + sal_Bool bDocument = sal_False; + + const uno::Any & rValue + = pContentProperties->getValue( + rtl::OUString( "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-neon/webdavdatasupplier.hxx b/ucb/source/ucp/webdav-neon/webdavdatasupplier.hxx new file mode 100644 index 000000000000..582bab2d698c --- /dev/null +++ b/ucb/source/ucp/webdav-neon/webdavdatasupplier.hxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _WEBDAV_UCP_DATASUPPLIER_HXX +#define _WEBDAV_UCP_DATASUPPLIER_HXX + +#include +#include +#include + +namespace webdav_ucp { + +struct DataSupplier_Impl; +class Content; + +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-neon/webdavprovider.cxx b/ucb/source/ucp/webdav-neon/webdavprovider.cxx new file mode 100644 index 000000000000..fd7371d7428d --- /dev/null +++ b/ucb/source/ucp/webdav-neon/webdavprovider.cxx @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/************************************************************************** + TODO + ************************************************************************** + + *************************************************************************/ +#include +#include "webdavprovider.hxx" +#include "webdavcontent.hxx" + +#include "osl/mutex.hxx" + +using namespace com::sun::star; +using namespace webdav_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( "com.sun.star.comp.WebDAVContentProvider" ), + rtl::OUString( 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 != HTTP_URL_SCHEME && aScheme != HTTPS_URL_SCHEME && aScheme != WEBDAV_URL_SCHEME + && aScheme != DAV_URL_SCHEME && aScheme != DAVS_URL_SCHEME && aScheme != FTP_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 == WEBDAV_URL_SCHEME ) + { + aURL = aURL.replaceAt( 0, + WEBDAV_URL_SCHEME_LENGTH, + rtl::OUString( HTTP_URL_SCHEME ) ); + bNewId = true; + } + else if ( aScheme == DAV_URL_SCHEME ) + { + aURL = aURL.replaceAt( 0, + DAV_URL_SCHEME_LENGTH, + rtl::OUString( HTTP_URL_SCHEME ) ); + bNewId = true; + } + else if ( aScheme == DAVS_URL_SCHEME ) + { + aURL = aURL.replaceAt( 0, + DAVS_URL_SCHEME_LENGTH, + rtl::OUString( 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("/"); + 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 ::webdav_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-neon/webdavprovider.hxx b/ucb/source/ucp/webdav-neon/webdavprovider.hxx new file mode 100644 index 000000000000..6001a1c6b655 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/webdavprovider.hxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _WEBDAV_UCP_PROVIDER_HXX +#define _WEBDAV_UCP_PROVIDER_HXX + +#include +#include +#include "DAVSessionFactory.hxx" +#include +#include "PropertyMap.hxx" + +namespace webdav_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 FTP_URL_SCHEME "ftp" + +#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-neon/webdavresultset.cxx b/ucb/source/ucp/webdav-neon/webdavresultset.cxx new file mode 100644 index 000000000000..e74354855f86 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/webdavresultset.cxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +/************************************************************************** + TODO + ************************************************************************** + + - This implementation is not a dynamic result set!!! It only implements + the necessary interfaces, but never recognizes/notifies changes!!! + + *************************************************************************/ +#include "webdavresultset.hxx" +#include "DAVSession.hxx" + +using namespace com::sun::star; +using namespace webdav_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-neon/webdavresultset.hxx b/ucb/source/ucp/webdav-neon/webdavresultset.hxx new file mode 100644 index 000000000000..06749bcd9867 --- /dev/null +++ b/ucb/source/ucp/webdav-neon/webdavresultset.hxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _WEBDAV_UCP_RESULTSET_HXX +#define _WEBDAV_UCP_RESULTSET_HXX + +#include +#include +#include "webdavcontent.hxx" +#include "webdavdatasupplier.hxx" + +namespace webdav_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-neon/webdavservices.cxx b/ucb/source/ucp/webdav-neon/webdavservices.cxx new file mode 100644 index 000000000000..c88eb6f241cd --- /dev/null +++ b/ucb/source/ucp/webdav-neon/webdavservices.cxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include +#include +#include +#include "webdavprovider.hxx" + +using namespace com::sun::star; + +//========================================================================= +extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL ucpdav1_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 ( ::webdav_ucp::ContentProvider::getImplementationName_Static(). + compareToAscii( pImplName ) == 0 ) + { + xFactory = ::webdav_ucp::ContentProvider::createServiceFactory( xSMgr ); + } + + ////////////////////////////////////////////////////////////////////// + + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + + return pRet; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit