1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <cppuhelper/queryinterface.hxx>
23 #include <rtl/uri.hxx>
24 #include <sal/log.hxx>
25 #include <ucbhelper/contentidentifier.hxx>
26 #include <ucbhelper/macros.hxx>
27 #include <ucbhelper/propertyvalueset.hxx>
28 #include <ucbhelper/simpleinteractionrequest.hxx>
29 #include <ucbhelper/cancelcommandexecution.hxx>
31 #include <com/sun/star/beans/IllegalTypeException.hpp>
32 #include <com/sun/star/beans/NotRemoveableException.hpp>
33 #include <com/sun/star/beans/PropertyAttribute.hpp>
34 #include <com/sun/star/beans/PropertyExistException.hpp>
35 #include <com/sun/star/beans/PropertySetInfoChange.hpp>
36 #include <com/sun/star/beans/PropertySetInfoChangeEvent.hpp>
37 #include <com/sun/star/beans/PropertyValue.hpp>
38 #include <com/sun/star/io/XActiveDataSink.hpp>
39 #include <com/sun/star/io/XOutputStream.hpp>
40 #include <com/sun/star/lang/IllegalAccessException.hpp>
41 #include <com/sun/star/lang/IllegalArgumentException.hpp>
42 #include <com/sun/star/sdbc/SQLException.hpp>
43 #include <com/sun/star/task/PasswordContainerInteractionHandler.hpp>
44 #include <com/sun/star/ucb/CommandEnvironment.hpp>
45 #include <com/sun/star/ucb/CommandFailedException.hpp>
46 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
47 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
48 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
49 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
50 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
51 #include <com/sun/star/ucb/InteractiveLockingLockedException.hpp>
52 #include <com/sun/star/ucb/InteractiveLockingLockExpiredException.hpp>
53 #include <com/sun/star/ucb/InteractiveLockingNotLockedException.hpp>
54 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
55 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
56 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
57 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
58 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
59 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
60 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
61 #include <com/sun/star/ucb/NameClash.hpp>
62 #include <com/sun/star/ucb/NameClashException.hpp>
63 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
64 #include <com/sun/star/ucb/OpenMode.hpp>
65 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
66 #include <com/sun/star/ucb/PropertyCommandArgument.hpp>
67 #include <com/sun/star/ucb/TransferInfo.hpp>
68 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
69 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
70 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
71 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
72 #include <com/sun/star/ucb/XCommandInfo.hpp>
73 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
74 #include <com/sun/star/uno/XComponentContext.hpp>
76 #include "webdavcontent.hxx"
77 #include "webdavprovider.hxx"
78 #include "webdavresultset.hxx"
79 #include "ContentProperties.hxx"
80 #include "SerfUri.hxx"
81 #include "UCBDeadPropertyValue.hxx"
82 #include "DAVException.hxx"
83 #include "DAVProperties.hxx"
85 using namespace com::sun::star
;
86 using namespace http_dav_ucp
;
90 void lcl_sendPartialGETRequest( bool &bError
,
91 DAVException
&aLastException
,
92 const std::vector
< OUString
>& rProps
,
93 std::vector
< OUString
> &aHeaderNames
,
94 const std::unique_ptr
< DAVResourceAccess
> &xResAccess
,
95 std::unique_ptr
< ContentProperties
> &xProps
,
96 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
98 DAVResource aResource
;
99 DAVRequestHeaders aPartialGet
;
100 aPartialGet
.push_back(
103 OUString( "bytes=0-0" )));
105 bool bIsRequestSize
= std::any_of(aHeaderNames
.begin(), aHeaderNames
.end(),
106 [](const OUString
& rHeaderName
) { return rHeaderName
== "Content-Length"; });
108 if ( bIsRequestSize
)
110 // we need to know if the server accepts range requests for a resource
111 // and the range unit it uses
112 aHeaderNames
.push_back( OUString( "Accept-Ranges" ) );
113 aHeaderNames
.push_back( OUString( "Content-Range" ) );
117 uno::Reference
< io::XInputStream
> xIn
= xResAccess
->GET( aPartialGet
,
123 if ( bIsRequestSize
)
125 // the ContentProperties maps "Content-Length" to the UCB "Size" property
126 // This would have an unrealistic value of 1 byte because we did only a partial GET
127 // Solution: if "Content-Range" is present, map it with UCB "Size" property
128 OUString aAcceptRanges
, aContentRange
, aContentLength
;
129 std::vector
< DAVPropertyValue
> &aResponseProps
= aResource
.properties
;
130 for ( const auto& rResponseProp
: aResponseProps
)
132 if ( rResponseProp
.Name
== "Accept-Ranges" )
133 rResponseProp
.Value
>>= aAcceptRanges
;
134 else if ( rResponseProp
.Name
== "Content-Range" )
135 rResponseProp
.Value
>>= aContentRange
;
136 else if ( rResponseProp
.Name
== "Content-Length" )
137 rResponseProp
.Value
>>= aContentLength
;
141 if ( aContentLength
.getLength() )
143 nSize
= aContentLength
.toInt64();
146 // according to http://tools.ietf.org/html/rfc2616#section-3.12
147 // the only range unit defined is "bytes" and implementations
148 // MAY ignore ranges specified using other units.
150 aContentRange
.getLength() &&
151 aAcceptRanges
== "bytes" )
153 // Parse the Content-Range to get the size
154 // vid. http://tools.ietf.org/html/rfc2616#section-14.16
155 // Content-Range: <range unit> <bytes range>/<size>
156 sal_Int32 nSlash
= aContentRange
.lastIndexOf( '/' );
159 OUString aSize
= aContentRange
.copy( nSlash
+ 1 );
160 // "*" means that the instance-length is unknown at the time when the response was generated
163 auto it
= std::find_if(aResponseProps
.begin(), aResponseProps
.end(),
164 [](const DAVPropertyValue
& rProp
) { return rProp
.Name
== "Content-Length"; });
165 if (it
!= aResponseProps
.end())
175 xProps
->addProperties(
177 ContentProperties( aResource
) );
179 xProps
.reset ( new ContentProperties( aResource
) );
181 catch ( DAVException
const & ex
)
189 // Content Implementation.
192 // ctr for content on an existing webdav resource
194 const uno::Reference
< uno::XComponentContext
>& rxContext
,
195 ContentProvider
* pProvider
,
196 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
197 rtl::Reference
< DAVSessionFactory
> const & rSessionFactory
)
198 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
199 m_eResourceType( UNKNOWN
),
200 m_pProvider( pProvider
),
201 m_bTransient( false ),
203 m_bCollection( false ),
204 m_bDidGetOrHead( false )
208 m_xResAccess
.reset( new DAVResourceAccess(
211 Identifier
->getContentIdentifier() ) );
213 SerfUri
aURI( Identifier
->getContentIdentifier() );
214 m_aEscapedTitle
= aURI
.GetPathBaseName();
216 catch ( DAVException
const & )
218 throw ucb::ContentCreationException();
223 // ctr for content on a non-existing webdav resource
225 const uno::Reference
< uno::XComponentContext
>& rxContext
,
226 ContentProvider
* pProvider
,
227 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
228 rtl::Reference
< DAVSessionFactory
> const & rSessionFactory
,
230 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
231 m_eResourceType( UNKNOWN
),
232 m_pProvider( pProvider
),
233 m_bTransient( true ),
235 m_bCollection( isCollection
),
236 m_bDidGetOrHead( false )
240 m_xResAccess
.reset( new DAVResourceAccess(
241 rxContext
, rSessionFactory
, Identifier
->getContentIdentifier() ) );
243 catch ( DAVException
const & )
245 throw ucb::ContentCreationException();
248 // Do not set m_aEscapedTitle here! Content::insert relays on this!!!
256 unlock(uno::Reference
< ucb::XCommandEnvironment
>());
260 // XInterface methods.
264 void SAL_CALL
Content::acquire()
267 ContentImplHelper::acquire();
272 void SAL_CALL
Content::release()
275 ContentImplHelper::release();
280 uno::Any SAL_CALL
Content::queryInterface( const uno::Type
& rType
)
282 // Note: isFolder may require network activities! So call it only
283 // if it is really necessary!!!
284 uno::Any aRet
= cppu::queryInterface(
286 static_cast< ucb::XContentCreator
* >( this ) );
287 if ( aRet
.hasValue() )
291 uno::Reference
< beans::XPropertySet
> const xProps(
292 m_xContext
, uno::UNO_QUERY_THROW
);
293 uno::Reference
< uno::XComponentContext
> xCtx
;
294 xCtx
.set( xProps
->getPropertyValue( "DefaultContext" ),
295 uno::UNO_QUERY_THROW
);
297 uno::Reference
< task::XInteractionHandler
> xIH(
298 task::PasswordContainerInteractionHandler::create( xCtx
) );
300 // Supply a command env to isFolder() that contains an interaction
301 // handler that uses the password container service to obtain
302 // credentials without displaying a password gui.
304 uno::Reference
< ucb::XCommandEnvironment
> xCmdEnv(
305 ucb::CommandEnvironment::create(
308 uno::Reference
< ucb::XProgressHandler
>() ) );
310 return isFolder( xCmdEnv
) ? aRet
: uno::Any();
312 catch ( uno::RuntimeException
const & )
316 catch ( uno::Exception
const & )
321 return aRet
.hasValue() ? aRet
: ContentImplHelper::queryInterface( rType
);
325 // XTypeProvider methods.
328 XTYPEPROVIDER_COMMON_IMPL( Content
);
332 uno::Sequence
< uno::Type
> SAL_CALL
Content::getTypes()
334 bool bFolder
= false;
338 = isFolder( uno::Reference
< ucb::XCommandEnvironment
>() );
340 catch ( uno::RuntimeException
const & )
344 catch ( uno::Exception
const & )
350 static cppu::OTypeCollection
s_aFolderTypes(
351 CPPU_TYPE_REF( lang::XTypeProvider
),
352 CPPU_TYPE_REF( lang::XServiceInfo
),
353 CPPU_TYPE_REF( lang::XComponent
),
354 CPPU_TYPE_REF( ucb::XContent
),
355 CPPU_TYPE_REF( ucb::XCommandProcessor
),
356 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
357 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
358 CPPU_TYPE_REF( beans::XPropertyContainer
),
359 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
360 CPPU_TYPE_REF( container::XChild
),
361 CPPU_TYPE_REF( ucb::XContentCreator
) );
363 return s_aFolderTypes
.getTypes();
367 static cppu::OTypeCollection
s_aDocumentTypes(
368 CPPU_TYPE_REF( lang::XTypeProvider
),
369 CPPU_TYPE_REF( lang::XServiceInfo
),
370 CPPU_TYPE_REF( lang::XComponent
),
371 CPPU_TYPE_REF( ucb::XContent
),
372 CPPU_TYPE_REF( ucb::XCommandProcessor
),
373 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
374 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
375 CPPU_TYPE_REF( beans::XPropertyContainer
),
376 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
377 CPPU_TYPE_REF( container::XChild
) );
379 return s_aDocumentTypes
.getTypes();
384 // XServiceInfo methods.
388 OUString SAL_CALL
Content::getImplementationName()
390 return "com.sun.star.comp.ucb.WebDAVContent";
395 uno::Sequence
< OUString
> SAL_CALL
Content::getSupportedServiceNames()
397 uno::Sequence
<OUString
> aSNS
{ WEBDAV_CONTENT_SERVICE_NAME
};
406 OUString SAL_CALL
Content::getContentType()
408 bool bFolder
= false;
412 = isFolder( uno::Reference
< ucb::XCommandEnvironment
>() );
414 catch ( uno::RuntimeException
const & )
418 catch ( uno::Exception
const & )
423 return WEBDAV_COLLECTION_TYPE
;
425 return WEBDAV_CONTENT_TYPE
;
429 // XCommandProcessor methods.
433 uno::Any SAL_CALL
Content::execute(
434 const ucb::Command
& aCommand
,
435 sal_Int32
/*CommandId*/,
436 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
438 SAL_INFO("ucb.ucp.webdav", ">>>>> Content::execute: start: command: " << aCommand
.Name
439 << ", env: " << (Environment
.is() ? "present" : "missing") );
443 if ( aCommand
.Name
== "getPropertyValues" )
449 uno::Sequence
< beans::Property
> Properties
;
450 if ( !( aCommand
.Argument
>>= Properties
) )
452 ucbhelper::cancelCommandExecution(
453 uno::makeAny( lang::IllegalArgumentException(
454 "Wrong argument type!",
455 static_cast< cppu::OWeakObject
* >( this ),
461 aRet
<<= getPropertyValues( Properties
, Environment
);
463 else if ( aCommand
.Name
== "setPropertyValues" )
469 uno::Sequence
< beans::PropertyValue
> aProperties
;
470 if ( !( aCommand
.Argument
>>= aProperties
) )
472 ucbhelper::cancelCommandExecution(
473 uno::makeAny( lang::IllegalArgumentException(
474 "Wrong argument type!",
475 static_cast< cppu::OWeakObject
* >( this ),
481 if ( !aProperties
.getLength() )
483 ucbhelper::cancelCommandExecution(
484 uno::makeAny( lang::IllegalArgumentException(
486 static_cast< cppu::OWeakObject
* >( this ),
492 aRet
<<= setPropertyValues( aProperties
, Environment
);
494 else if ( aCommand
.Name
== "getPropertySetInfo" )
497 // getPropertySetInfo
500 // Note: Implemented by base class.
501 aRet
<<= getPropertySetInfo( Environment
,
502 false /* don't cache data */ );
504 else if ( aCommand
.Name
== "getCommandInfo" )
510 // Note: Implemented by base class.
511 aRet
<<= getCommandInfo( Environment
, false );
513 else if ( aCommand
.Name
== "open" )
519 ucb::OpenCommandArgument2 aOpenCommand
;
520 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
522 ucbhelper::cancelCommandExecution(
523 uno::makeAny( lang::IllegalArgumentException(
524 "Wrong argument type!",
525 static_cast< cppu::OWeakObject
* >( this ),
531 aRet
= open( aOpenCommand
, Environment
);
533 if ( (aOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT
||
534 aOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
) &&
535 supportsExclusiveWriteLock( Environment
) )
538 else if ( aCommand
.Name
== "insert" )
544 ucb::InsertCommandArgument arg
;
545 if ( !( aCommand
.Argument
>>= arg
) )
547 ucbhelper::cancelCommandExecution(
548 uno::makeAny( lang::IllegalArgumentException(
549 "Wrong argument type!",
550 static_cast< cppu::OWeakObject
* >( this ),
556 insert( arg
.Data
, arg
.ReplaceExisting
, Environment
);
558 else if ( aCommand
.Name
== "delete" )
564 bool bDeletePhysical
= false;
565 aCommand
.Argument
>>= bDeletePhysical
;
567 // KSO: Ignore parameter and destroy the content, if you don't support
568 // putting objects into trashcan. ( Since we do not have a trash can
569 // service yet (src603), you actually have no other choice. )
570 // if ( bDeletePhysical )
574 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
576 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
577 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
) );
579 xResAccess
->DESTROY( Environment
);
581 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
582 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
) );
585 catch ( DAVException
const & e
)
587 cancelCommandExecution( e
, Environment
, true );
592 // Propagate destruction.
593 destroy( bDeletePhysical
);
595 // Remove own and all children's Additional Core Properties.
596 removeAdditionalPropertySet();
598 else if ( aCommand
.Name
== "transfer" && isFolder( Environment
) )
602 // ( Not available at documents )
605 ucb::TransferInfo transferArgs
;
606 if ( !( aCommand
.Argument
>>= transferArgs
) )
608 ucbhelper::cancelCommandExecution(
609 uno::makeAny( lang::IllegalArgumentException(
610 "Wrong argument type!",
611 static_cast< cppu::OWeakObject
* >( this ),
617 transfer( transferArgs
, Environment
);
619 else if ( aCommand
.Name
== "post" )
625 ucb::PostCommandArgument2 aArg
;
626 if ( !( aCommand
.Argument
>>= aArg
) )
628 ucbhelper::cancelCommandExecution(
629 uno::makeAny( lang::IllegalArgumentException(
630 "Wrong argument type!",
631 static_cast< cppu::OWeakObject
* >( this ),
637 post( aArg
, Environment
);
639 else if ( aCommand
.Name
== "lock" &&
640 supportsExclusiveWriteLock( Environment
) )
648 else if ( aCommand
.Name
== "unlock" &&
649 supportsExclusiveWriteLock( Environment
) )
655 unlock( Environment
);
657 else if ( aCommand
.Name
== "createNewContent" &&
658 isFolder( Environment
) )
664 ucb::ContentInfo aArg
;
665 if ( !( aCommand
.Argument
>>= aArg
) )
667 ucbhelper::cancelCommandExecution(
668 uno::makeAny( lang::IllegalArgumentException(
669 "Wrong argument type!",
670 static_cast< cppu::OWeakObject
* >( this ),
676 aRet
<<= createNewContent( aArg
);
678 else if ( aCommand
.Name
== "addProperty" )
680 ucb::PropertyCommandArgument aPropArg
;
681 if ( !( aCommand
.Argument
>>= aPropArg
))
683 ucbhelper::cancelCommandExecution(
684 uno::makeAny( lang::IllegalArgumentException(
685 "Wrong argument type!",
686 static_cast< cppu::OWeakObject
* >( this ),
691 // TODO when/if XPropertyContainer is removed,
692 // the command execution can be canceled in addProperty
695 addProperty( aPropArg
, Environment
);
697 catch ( const beans::PropertyExistException
&e
)
699 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
701 catch ( const beans::IllegalTypeException
&e
)
703 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
705 catch ( const lang::IllegalArgumentException
&e
)
707 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
710 else if ( aCommand
.Name
== "removeProperty" )
713 if ( !( aCommand
.Argument
>>= sPropName
) )
715 ucbhelper::cancelCommandExecution(
716 uno::makeAny( lang::IllegalArgumentException(
717 "Wrong argument type!",
718 static_cast< cppu::OWeakObject
* >( this ),
723 // TODO when/if XPropertyContainer is removed,
724 // the command execution can be canceled in removeProperty
727 removeProperty( sPropName
, Environment
);
729 catch( const beans::UnknownPropertyException
&e
)
731 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
733 catch( const beans::NotRemoveableException
&e
)
735 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
741 // Unsupported command
744 ucbhelper::cancelCommandExecution(
745 uno::makeAny( ucb::UnsupportedCommandException(
747 static_cast< cppu::OWeakObject
* >( this ) ) ),
752 SAL_INFO("ucb.ucp.webdav", "<<<<< Content::execute: end: command: " << aCommand
.Name
);
758 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ )
762 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
764 osl::MutexGuard
aGuard( m_aMutex
);
765 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
) );
767 DAVResourceAccess::abort();
769 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
770 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
) );
773 catch ( DAVException
const & )
780 // XPropertyContainer methods.
783 void Content::addProperty( const css::ucb::PropertyCommandArgument
&aCmdArg
,
784 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
786 // if ( m_bTransient )
788 const beans::Property aProperty
= aCmdArg
.Property
;
789 const uno::Any aDefaultValue
= aCmdArg
.DefaultValue
;
791 // check property Name
792 if ( !aProperty
.Name
.getLength() )
793 throw lang::IllegalArgumentException(
794 "\"addProperty\" with empty Property.Name",
795 static_cast< ::cppu::OWeakObject
* >( this ),
798 // Check property type.
799 if ( !UCBDeadPropertyValue::supportsType( aProperty
.Type
) )
800 throw beans::IllegalTypeException(
801 "\"addProperty\" unsupported Property.Type",
802 static_cast< ::cppu::OWeakObject
* >( this ) );
804 // check default value
805 if ( aDefaultValue
.hasValue() && aDefaultValue
.getValueType() != aProperty
.Type
)
806 throw beans::IllegalTypeException(
807 "\"addProperty\" DefaultValue does not match Property.Type",
808 static_cast< ::cppu::OWeakObject
* >( this ) );
811 // Make sure a property with the requested name does not already
812 // exist in dynamic and static(!) properties.
815 // Take into account special properties with custom namespace
816 // using <prop:the_propname xmlns:prop="the_namespace">
817 OUString aSpecialName
;
818 bool bIsSpecial
= DAVProperties::isUCBSpecialProperty( aProperty
.Name
, aSpecialName
);
820 // Note: This requires network access!
821 if ( getPropertySetInfo( xEnv
, false /* don't cache data */ )
822 ->hasPropertyByName( bIsSpecial
? aSpecialName
: aProperty
.Name
) )
824 // Property does already exist.
825 throw beans::PropertyExistException();
829 // Add a new dynamic property.
832 ProppatchValue
aValue( PROPSET
, aProperty
.Name
, aDefaultValue
);
834 std::vector
< ProppatchValue
> aProppatchValues
;
835 aProppatchValues
.push_back( aValue
);
839 // Set property value at server.
840 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
842 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
843 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
) );
845 xResAccess
->PROPPATCH( aProppatchValues
, xEnv
);
847 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
848 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
) );
851 // Notify propertyset info change listeners.
852 beans::PropertySetInfoChangeEvent
evt(
853 static_cast< cppu::OWeakObject
* >( this ),
854 bIsSpecial
? aSpecialName
: aProperty
.Name
,
855 -1, // No handle available
856 beans::PropertySetInfoChange::PROPERTY_INSERTED
);
857 notifyPropertySetInfoChange( evt
);
859 catch ( DAVException
const & e
)
861 if ( e
.getStatus() == SC_FORBIDDEN
)
863 // Support for setting arbitrary dead properties is optional!
865 // Store property locally.
866 ContentImplHelper::addProperty( bIsSpecial
? aSpecialName
: aProperty
.Name
,
867 aProperty
.Attributes
,
872 if ( shouldAccessNetworkAfterException( e
) )
876 const ResourceType
& rType
= getResourceType( xEnv
);
881 throw lang::IllegalArgumentException();
884 // Store property locally.
885 ContentImplHelper::addProperty( bIsSpecial
? aSpecialName
: aProperty
.Name
,
886 aProperty
.Attributes
,
891 SAL_WARN( "ucb.ucp.webdav",
892 "Content::addProperty - "
893 "Unsupported resource type!" );
897 catch ( uno::Exception
const & )
899 SAL_WARN( "ucb.ucp.webdav",
900 "Content::addProperty - "
901 "Unable to determine resource type!" );
906 SAL_WARN( "ucb.ucp.webdav",
907 "Content::addProperty - "
908 "Unable to determine resource type!" );
914 void Content::removeProperty( const OUString
& Name
,
915 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
918 // @@@ REMOVABLE at the moment not properly set in the PropSetInfo
921 beans::Property aProp
922 = getPropertySetInfo( xEnv
, false /* don't cache data */ )
923 ->getPropertyByName( Name
);
925 if ( !( aProp
.Attributes
& beans::PropertyAttribute::REMOVABLE
) )
928 throw beans::NotRemoveableException();
931 catch ( beans::UnknownPropertyException
const & )
933 //SAL_WARN( "ucb.ucp.webdav", "removeProperty - Unknown property!" );
938 // Try to remove property from server.
941 std::vector
< ProppatchValue
> aProppatchValues
;
942 ProppatchValue
aValue( PROPREMOVE
, Name
, uno::Any() );
943 aProppatchValues
.push_back( aValue
);
945 // Remove property value from server.
946 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
948 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
949 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
) );
951 xResAccess
->PROPPATCH( aProppatchValues
, xEnv
);
953 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
954 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
) );
957 // Notify propertyset info change listeners.
958 beans::PropertySetInfoChangeEvent
evt(
959 static_cast< cppu::OWeakObject
* >( this ),
961 -1, // No handle available
962 beans::PropertySetInfoChange::PROPERTY_REMOVED
);
963 notifyPropertySetInfoChange( evt
);
965 catch ( DAVException
const & e
)
967 if ( e
.getStatus() == SC_FORBIDDEN
)
969 // Support for setting arbitrary dead properties is optional!
971 // Try to remove property from local store.
972 ContentImplHelper::removeProperty( Name
);
976 if ( shouldAccessNetworkAfterException( e
) )
980 const ResourceType
& rType
= getResourceType( xEnv
);
985 throw beans::UnknownPropertyException(Name
);
988 // Try to remove property from local store.
989 ContentImplHelper::removeProperty( Name
);
993 SAL_WARN( "ucb.ucp.webdav",
994 "Content::removeProperty - "
995 "Unsupported resource type!" );
999 catch ( uno::Exception
const & )
1001 SAL_WARN( "ucb.ucp.webdav",
1002 "Content::removeProperty - "
1003 "Unable to determine resource type!" );
1008 SAL_WARN( "ucb.ucp.webdav",
1009 "Content::removeProperty - "
1010 "Unable to determine resource type!" );
1011 // throw beans::UnknownPropertyException();
1018 void SAL_CALL
Content::addProperty( const OUString
& Name
,
1019 sal_Int16 Attributes
,
1020 const uno::Any
& DefaultValue
)
1022 beans::Property aProperty
;
1023 aProperty
.Name
= Name
;
1024 aProperty
.Type
= DefaultValue
.getValueType();
1025 aProperty
.Attributes
= Attributes
;
1026 aProperty
.Handle
= -1;
1028 addProperty( ucb::PropertyCommandArgument( aProperty
, DefaultValue
),
1029 uno::Reference
< ucb::XCommandEnvironment
>());
1033 void SAL_CALL
Content::removeProperty( const OUString
& Name
)
1035 removeProperty( Name
,
1036 uno::Reference
< ucb::XCommandEnvironment
>() );
1040 // XContentCreator methods.
1044 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
1045 Content::queryCreatableContentsInfo()
1047 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1049 uno::Sequence
< ucb::ContentInfo
> aSeq( 2 );
1052 aSeq
.getArray()[ 0 ].Type
= WEBDAV_CONTENT_TYPE
;
1053 aSeq
.getArray()[ 0 ].Attributes
1054 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
1055 | ucb::ContentInfoAttribute::KIND_DOCUMENT
;
1057 beans::Property aProp
;
1058 m_pProvider
->getProperty( "Title", aProp
);
1060 uno::Sequence
< beans::Property
> aDocProps( 1 );
1061 aDocProps
.getArray()[ 0 ] = aProp
;
1062 aSeq
.getArray()[ 0 ].Properties
= aDocProps
;
1065 aSeq
.getArray()[ 1 ].Type
= WEBDAV_COLLECTION_TYPE
;
1066 aSeq
.getArray()[ 1 ].Attributes
1067 = ucb::ContentInfoAttribute::KIND_FOLDER
;
1069 uno::Sequence
< beans::Property
> aFolderProps( 1 );
1070 aFolderProps
.getArray()[ 0 ] = aProp
;
1071 aSeq
.getArray()[ 1 ].Properties
= aFolderProps
;
1077 uno::Reference
< ucb::XContent
> SAL_CALL
1078 Content::createNewContent( const ucb::ContentInfo
& Info
)
1080 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1082 if ( !Info
.Type
.getLength() )
1083 return uno::Reference
< ucb::XContent
>();
1085 if ( ( Info
.Type
!= WEBDAV_COLLECTION_TYPE
)
1087 ( Info
.Type
!= WEBDAV_CONTENT_TYPE
) )
1088 return uno::Reference
< ucb::XContent
>();
1090 OUString aURL
= m_xIdentifier
->getContentIdentifier();
1092 SAL_WARN_IF( aURL
.isEmpty(), "ucb.ucp.webdav",
1093 "WebdavContent::createNewContent - empty identifier!" );
1095 if ( ( aURL
.lastIndexOf( '/' ) + 1 ) != aURL
.getLength() )
1099 if ( Info
.Type
== WEBDAV_COLLECTION_TYPE
)
1101 aURL
+= "New_Collection";
1102 isCollection
= true;
1106 aURL
+= "New_Content";
1107 isCollection
= false;
1110 uno::Reference
< ucb::XContentIdentifier
> xId(
1111 new ::ucbhelper::ContentIdentifier( aURL
) );
1113 // create the local content
1116 return new ::http_dav_ucp::Content( m_xContext
,
1119 m_xResAccess
->getSessionFactory(),
1122 catch ( ucb::ContentCreationException
& )
1124 return uno::Reference
< ucb::XContent
>();
1130 OUString
Content::getParentURL()
1132 // <scheme>:// -> ""
1133 // <scheme>://foo -> ""
1134 // <scheme>://foo/ -> ""
1135 // <scheme>://foo/bar -> <scheme>://foo/
1136 // <scheme>://foo/bar/ -> <scheme>://foo/
1137 // <scheme>://foo/bar/abc -> <scheme>://foo/bar/
1139 OUString aURL
= m_xIdentifier
->getContentIdentifier();
1141 sal_Int32 nPos
= aURL
.lastIndexOf( '/' );
1142 if ( nPos
== ( aURL
.getLength() - 1 ) )
1144 // Trailing slash found. Skip.
1145 nPos
= aURL
.lastIndexOf( '/', nPos
);
1148 sal_Int32 nPos1
= aURL
.lastIndexOf( '/', nPos
);
1150 nPos1
= aURL
.lastIndexOf( '/', nPos1
);
1155 return aURL
.copy( 0, nPos
+ 1 );
1159 // Non-interface methods.
1163 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
1164 const uno::Reference
< uno::XComponentContext
>& rxContext
,
1165 const uno::Sequence
< beans::Property
>& rProperties
,
1166 const ContentProperties
& rData
,
1167 const rtl::Reference
< ::ucbhelper::ContentProviderImplHelper
>& rProvider
,
1168 const OUString
& rContentId
)
1170 // Note: Empty sequence means "get values of all supported properties".
1172 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
1173 = new ::ucbhelper::PropertyValueSet( rxContext
);
1175 sal_Int32 nCount
= rProperties
.getLength();
1178 uno::Reference
< beans::XPropertySet
> xAdditionalPropSet
;
1179 bool bTriedToGetAdditionalPropSet
= false;
1181 const beans::Property
* pProps
= rProperties
.getConstArray();
1182 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1184 const beans::Property
& rProp
= pProps
[ n
];
1186 // Process standard UCB, DAV and HTTP properties.
1187 const uno::Any
& rValue
= rData
.getValue( rProp
.Name
);
1188 if ( rValue
.hasValue() )
1190 xRow
->appendObject( rProp
, rValue
);
1194 // Process local Additional Properties.
1195 if ( !bTriedToGetAdditionalPropSet
&& !xAdditionalPropSet
.is() )
1197 xAdditionalPropSet
=
1198 rProvider
->getAdditionalPropertySet( rContentId
,
1200 bTriedToGetAdditionalPropSet
= true;
1203 if ( !xAdditionalPropSet
.is() ||
1204 !xRow
->appendPropertySetValue(
1205 xAdditionalPropSet
, rProp
) )
1207 // Append empty entry.
1208 xRow
->appendVoid( rProp
);
1215 // Append all standard UCB, DAV and HTTP properties.
1217 const std::unique_ptr
< PropertyValueMap
> & xProps
= rData
.getProperties();
1219 ContentProvider
* pProvider
1220 = static_cast< ContentProvider
* >( rProvider
.get() );
1221 beans::Property aProp
;
1223 for ( const auto& rProp
: *xProps
)
1225 if ( pProvider
->getProperty( rProp
.first
, aProp
) )
1226 xRow
->appendObject( aProp
, rProp
.second
.value() );
1229 // Append all local Additional Properties.
1230 uno::Reference
< beans::XPropertySet
> xSet
=
1231 rProvider
->getAdditionalPropertySet( rContentId
, false );
1232 xRow
->appendPropertySet( xSet
);
1235 return uno::Reference
< sdbc::XRow
>( xRow
.get() );
1239 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
1240 const uno::Sequence
< beans::Property
>& rProperties
,
1241 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1243 std::unique_ptr
< ContentProperties
> xProps
;
1244 std::unique_ptr
< ContentProperties
> xCachedProps
;
1245 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
1246 OUString aUnescapedTitle
;
1247 bool bHasAll
= false;
1248 uno::Reference
< uno::XComponentContext
> xContext
;
1249 uno::Reference
< ucb::XContentIdentifier
> xIdentifier
;
1250 rtl::Reference
< ::ucbhelper::ContentProviderImplHelper
> xProvider
;
1253 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1255 aUnescapedTitle
= SerfUri::unescape( m_aEscapedTitle
);
1256 xContext
.set( m_xContext
);
1257 xIdentifier
.set( m_xIdentifier
);
1258 xProvider
.set( m_xProvider
.get() );
1259 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
) );
1261 // First, ask cache...
1262 if ( m_xCachedProps
.get() )
1264 xCachedProps
.reset( new ContentProperties( *m_xCachedProps
) );
1266 std::vector
< OUString
> aMissingProps
;
1267 if ( xCachedProps
->containsAllNames( rProperties
, aMissingProps
) )
1269 // All properties are already in cache! No server access needed.
1273 // use the cached ContentProperties instance
1274 xProps
.reset( new ContentProperties( *xCachedProps
) );
1278 if ( !m_bTransient
&& !bHasAll
)
1280 // Obtain values from server...
1283 // First, identify whether resource is DAV or not
1284 bool bNetworkAccessAllowed
= true;
1285 const ResourceType
& rType
= getResourceType( xEnv
, xResAccess
, &bNetworkAccessAllowed
);
1289 // cache lookup... getResourceType may fill the props cache via
1291 if ( m_xCachedProps
.get() )
1294 new ContentProperties( *m_xCachedProps
) );
1296 std::vector
< OUString
> aMissingProps
;
1297 if ( xCachedProps
->containsAllNames(
1298 rProperties
, aMissingProps
) )
1300 // All properties are already in cache! No server access
1305 // use the cached ContentProperties instance
1306 xProps
.reset( new ContentProperties( *xCachedProps
) );
1311 // Only DAV resources support PROPFIND
1312 std::vector
< OUString
> aPropNames
;
1314 uno::Sequence
< beans::Property
> aProperties(
1315 rProperties
.getLength() );
1317 if ( !m_aFailedPropNames
.empty() )
1319 sal_Int32 nProps
= 0;
1320 sal_Int32 nCount
= rProperties
.getLength();
1321 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1323 const OUString
& rName
= rProperties
[ n
].Name
;
1325 if ( std::none_of(m_aFailedPropNames
.begin(), m_aFailedPropNames
.end(),
1326 [&rName
](const OUString
& rPropName
) { return rPropName
== rName
; }) )
1328 aProperties
[ nProps
] = rProperties
[ n
];
1333 aProperties
.realloc( nProps
);
1337 aProperties
= rProperties
;
1340 if ( aProperties
.getLength() > 0 )
1341 ContentProperties::UCBNamesToDAVNames(
1342 aProperties
, aPropNames
);
1344 if ( !aPropNames
.empty() )
1346 std::vector
< DAVResource
> resources
;
1349 xResAccess
->PROPFIND(
1350 DAVZERO
, aPropNames
, resources
, xEnv
);
1352 if ( 1 == resources
.size() )
1355 xProps
->addProperties(
1357 ContentProperties( resources
[ 0 ] ));
1360 new ContentProperties( resources
[ 0 ] ) );
1363 catch ( DAVException
const & e
)
1365 bNetworkAccessAllowed
= bNetworkAccessAllowed
&&
1366 shouldAccessNetworkAfterException( e
);
1368 if ( !bNetworkAccessAllowed
)
1370 cancelCommandExecution( e
, xEnv
);
1378 if ( bNetworkAccessAllowed
)
1380 // All properties obtained already?
1381 std::vector
< OUString
> aMissingProps
;
1382 if ( !( xProps
.get()
1383 && xProps
->containsAllNames(
1384 rProperties
, aMissingProps
) )
1385 || !m_bDidGetOrHead
)
1387 // Possibly the missing props can be obtained using a HEAD
1390 std::vector
< OUString
> aHeaderNames
;
1391 ContentProperties::UCBNamesToHTTPNames(
1394 true /* bIncludeUnmatched */ );
1396 if ( !aHeaderNames
.empty() )
1400 DAVResource resource
;
1401 xResAccess
->HEAD( aHeaderNames
, resource
, xEnv
);
1402 m_bDidGetOrHead
= true;
1405 xProps
->addProperties(
1407 ContentProperties( resource
) );
1409 xProps
.reset ( new ContentProperties( resource
) );
1411 if ( m_eResourceType
== NON_DAV
)
1412 xProps
->addProperties( aMissingProps
,
1417 catch ( DAVException
const & e
)
1419 // non "general-purpose servers" may not support HEAD requests
1420 // see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1
1421 // In this case, perform a partial GET only to get the header info
1422 // vid. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
1423 // WARNING if the server does not support partial GETs,
1424 // the GET will transfer the whole content
1426 DAVException aLastException
= e
;
1428 // According to the spec. the origin server SHOULD return
1429 // * 405 (Method Not Allowed):
1430 // the method is known but not allowed for the requested resource
1431 // * 501 (Not Implemented):
1432 // the method is unrecognized or not implemented
1433 // TODO SC_NOT_FOUND is only for google-code server
1434 if ( aLastException
.getStatus() == SC_NOT_IMPLEMENTED
||
1435 aLastException
.getStatus() == SC_METHOD_NOT_ALLOWED
||
1436 aLastException
.getStatus() == SC_NOT_FOUND
)
1438 lcl_sendPartialGETRequest( bError
,
1445 m_bDidGetOrHead
= !bError
;
1450 if ( !shouldAccessNetworkAfterException( aLastException
) )
1452 cancelCommandExecution( aLastException
, xEnv
);
1461 // might trigger HTTP redirect.
1462 // Therefore, title must be updated here.
1463 SerfUri
aUri( xResAccess
->getURL() );
1464 aUnescapedTitle
= aUri
.GetPathBaseNameUnescaped();
1466 if ( rType
== UNKNOWN
)
1468 xProps
.reset( new ContentProperties( aUnescapedTitle
) );
1471 // For DAV resources we only know the Title, for non-DAV
1472 // resources we additionally know that it is a document.
1477 // new ContentProperties( aUnescapedTitle ) );
1478 xProps
->addProperty(
1480 uno::makeAny( aUnescapedTitle
),
1485 if ( !xProps
.get() )
1486 xProps
.reset( new ContentProperties( aUnescapedTitle
, false ) );
1488 xProps
->addProperty(
1490 uno::makeAny( aUnescapedTitle
),
1493 xProps
->addProperty(
1495 uno::makeAny( false ),
1497 xProps
->addProperty(
1499 uno::makeAny( true ),
1501 xProps
->addProperty(
1503 uno::makeAny( OUString(WEBDAV_CONTENT_TYPE
) ),
1509 // No server access for just created (not yet committed) objects.
1510 // Only a minimal set of properties supported at this stage.
1512 xProps
.reset( new ContentProperties( aUnescapedTitle
,
1516 sal_Int32 nCount
= rProperties
.getLength();
1517 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1519 const OUString rName
= rProperties
[ n
].Name
;
1520 if ( rName
== "BaseURI" )
1522 // Add BaseURI property, if requested.
1523 xProps
->addProperty(
1525 uno::makeAny( getBaseURI( xResAccess
) ),
1528 else if ( rName
== "CreatableContentsInfo" )
1530 // Add CreatableContentsInfo property, if requested.
1531 bool bFolder
= false;
1532 xProps
->getValue( "IsFolder" )
1534 xProps
->addProperty(
1535 "CreatableContentsInfo",
1536 uno::makeAny( bFolder
1537 ? queryCreatableContentsInfo()
1538 : uno::Sequence
< ucb::ContentInfo
>() ),
1543 uno::Reference
< sdbc::XRow
> xResultRow
1544 = getPropertyValues( xContext
,
1548 xIdentifier
->getContentIdentifier() );
1551 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1553 if ( !m_xCachedProps
.get() )
1554 m_xCachedProps
.reset( new CachableContentProperties( *xProps
) );
1556 m_xCachedProps
->addProperties( *xProps
);
1558 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
) );
1559 m_aEscapedTitle
= SerfUri::escapeSegment( aUnescapedTitle
);
1566 uno::Sequence
< uno::Any
> Content::setPropertyValues(
1567 const uno::Sequence
< beans::PropertyValue
>& rValues
,
1568 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1570 uno::Reference
< ucb::XContentIdentifier
> xIdentifier
;
1571 rtl::Reference
< ContentProvider
> xProvider
;
1573 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
1576 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1578 xProvider
.set( m_pProvider
);
1579 xIdentifier
.set( m_xIdentifier
);
1580 bTransient
= m_bTransient
;
1581 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
) );
1584 uno::Sequence
< uno::Any
> aRet( rValues
.getLength() );
1585 uno::Sequence
< beans::PropertyChangeEvent
> aChanges( rValues
.getLength() );
1586 sal_Int32 nChanged
= 0;
1588 beans::PropertyChangeEvent aEvent
;
1589 aEvent
.Source
= static_cast< cppu::OWeakObject
* >( this );
1590 aEvent
.Further
= false;
1591 // aEvent.PropertyName =
1592 aEvent
.PropertyHandle
= -1;
1593 // aEvent.OldValue =
1594 // aEvent.NewValue =
1596 std::vector
< ProppatchValue
> aProppatchValues
;
1597 std::vector
< sal_Int32
> aProppatchPropsPositions
;
1599 uno::Reference
< ucb::XPersistentPropertySet
> xAdditionalPropSet
;
1600 bool bTriedToGetAdditionalPropSet
= false;
1602 bool bExchange
= false;
1605 sal_Int32 nTitlePos
= -1;
1607 uno::Reference
< beans::XPropertySetInfo
> xInfo
;
1609 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
1610 sal_Int32 nCount
= rValues
.getLength();
1611 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1613 const beans::PropertyValue
& rValue
= pValues
[ n
];
1614 const OUString
& rName
= rValue
.Name
;
1616 beans::Property aTmpProp
;
1617 xProvider
->getProperty( rName
, aTmpProp
);
1619 if ( aTmpProp
.Attributes
& beans::PropertyAttribute::READONLY
)
1621 // Read-only property!
1622 aRet
[ n
] <<= lang::IllegalAccessException(
1623 "Property is read-only!",
1624 static_cast< cppu::OWeakObject
* >( this ) );
1632 if ( rName
== "ContentType" )
1634 // Read-only property!
1635 aRet
[ n
] <<= lang::IllegalAccessException(
1636 "Property is read-only!",
1637 static_cast< cppu::OWeakObject
* >( this ) );
1639 else if ( rName
== "IsDocument" )
1641 // Read-only property!
1642 aRet
[ n
] <<= lang::IllegalAccessException(
1643 "Property is read-only!",
1644 static_cast< cppu::OWeakObject
* >( this ) );
1646 else if ( rName
== "IsFolder" )
1648 // Read-only property!
1649 aRet
[ n
] <<= lang::IllegalAccessException(
1650 "Property is read-only!",
1651 static_cast< cppu::OWeakObject
* >( this ) );
1653 else if ( rName
== "Title" )
1656 if ( rValue
.Value
>>= aNewValue
)
1659 if ( aNewValue
.getLength() > 0 )
1663 SerfUri
aURI( xIdentifier
->getContentIdentifier() );
1664 aOldTitle
= aURI
.GetPathBaseNameUnescaped();
1666 if ( aNewValue
!= aOldTitle
)
1668 // modified title -> modified URL -> exchange !
1672 // new value will be set later...
1673 aNewTitle
= aNewValue
;
1675 // remember position within sequence of values (for
1680 catch ( DAVException
const & )
1682 aRet
[ n
] <<= lang::IllegalArgumentException(
1683 "Invalid content identifier!",
1684 static_cast< cppu::OWeakObject
* >( this ),
1690 aRet
[ n
] <<= lang::IllegalArgumentException(
1691 "Empty title not allowed!",
1692 static_cast< cppu::OWeakObject
* >( this ),
1698 aRet
[ n
] <<= beans::IllegalTypeException(
1699 "Property value has wrong type!",
1700 static_cast< cppu::OWeakObject
* >( this ) );
1709 OUString aSpecialName
;
1710 bool bIsSpecial
= DAVProperties::isUCBSpecialProperty( rName
, aSpecialName
);
1713 xInfo
= getPropertySetInfo( xEnv
,
1714 false /* don't cache data */ );
1716 if ( !xInfo
->hasPropertyByName( bIsSpecial
? aSpecialName
: rName
) )
1718 // Check, whether property exists. Skip otherwise.
1719 // PROPPATCH::set would add the property automatically, which
1720 // is not allowed for "setPropertyValues" command!
1721 aRet
[ n
] <<= beans::UnknownPropertyException(
1722 "Property is unknown!",
1723 static_cast< cppu::OWeakObject
* >( this ) );
1727 if ( rName
== "Size" )
1729 // Read-only property!
1730 aRet
[ n
] <<= lang::IllegalAccessException(
1731 "Property is read-only!",
1732 static_cast< cppu::OWeakObject
* >( this ) );
1734 else if ( rName
== "DateCreated" )
1736 // Read-only property!
1737 aRet
[ n
] <<= lang::IllegalAccessException(
1738 "Property is read-only!",
1739 static_cast< cppu::OWeakObject
* >( this ) );
1741 else if ( rName
== "DateModified" )
1743 // Read-only property!
1744 aRet
[ n
] <<= lang::IllegalAccessException(
1745 "Property is read-only!",
1746 static_cast< cppu::OWeakObject
* >( this ) );
1748 else if ( rName
== "MediaType" )
1750 // Read-only property!
1751 // (but could be writable, if 'getcontenttype' would be)
1752 aRet
[ n
] <<= lang::IllegalAccessException(
1753 "Property is read-only!",
1754 static_cast< cppu::OWeakObject
* >( this ) );
1756 if ( rName
== "CreatableContentsInfo" )
1758 // Read-only property!
1759 aRet
[ n
] <<= lang::IllegalAccessException(
1760 "Property is read-only!",
1761 static_cast< cppu::OWeakObject
* >( this ) );
1765 if ( getResourceType( xEnv
, xResAccess
) == DAV
)
1767 // Property value will be set on server.
1768 ProppatchValue
aValue( PROPSET
, rName
, rValue
.Value
);
1769 aProppatchValues
.push_back( aValue
);
1771 // remember position within sequence of values (for
1773 aProppatchPropsPositions
.push_back( n
);
1777 // Property value will be stored in local property store.
1778 if ( !bTriedToGetAdditionalPropSet
&&
1779 !xAdditionalPropSet
.is() )
1782 = getAdditionalPropertySet( false );
1783 bTriedToGetAdditionalPropSet
= true;
1786 if ( xAdditionalPropSet
.is() )
1791 = xAdditionalPropSet
->getPropertyValue( rName
);
1792 if ( aOldValue
!= rValue
.Value
)
1794 xAdditionalPropSet
->setPropertyValue(
1795 rName
, rValue
.Value
);
1797 aEvent
.PropertyName
= rName
;
1798 aEvent
.OldValue
= aOldValue
;
1799 aEvent
.NewValue
= rValue
.Value
;
1801 aChanges
.getArray()[ nChanged
] = aEvent
;
1805 catch ( beans::UnknownPropertyException
const & e
)
1809 catch ( lang::WrappedTargetException
const & e
)
1813 catch ( beans::PropertyVetoException
const & e
)
1817 catch ( lang::IllegalArgumentException
const & e
)
1824 aRet
[ n
] <<= uno::Exception(
1825 "No property set for storing the value!",
1826 static_cast< cppu::OWeakObject
* >( this ) );
1833 if ( !bTransient
&& (!aProppatchValues
.empty()) )
1837 // Set property values at server.
1838 xResAccess
->PROPPATCH( aProppatchValues
, xEnv
);
1840 for ( const auto& rProppatchValue
: aProppatchValues
)
1842 aEvent
.PropertyName
= rProppatchValue
.name
;
1843 aEvent
.OldValue
= uno::Any(); // @@@ too expensive to obtain!
1844 aEvent
.NewValue
= rProppatchValue
.value
;
1846 aChanges
.getArray()[ nChanged
] = aEvent
;
1850 catch ( DAVException
const & e
)
1852 // SAL_WARN( "ucb.ucp.webdav",
1853 // "Content::setPropertyValues - PROPPATCH failed!" );
1856 cancelCommandExecution( e
, xEnv
);
1859 // Note: PROPPATCH either sets ALL property values OR NOTHING.
1861 std::vector
< sal_Int32
>::const_iterator it
1862 = aProppatchPropsPositions
.begin();
1863 std::vector
< sal_Int32
>::const_iterator end
1864 = aProppatchPropsPositions
.end();
1869 aRet
[ (*it
) ] <<= MapDAVException( e
, true );
1878 // Assemble new content identifier...
1880 OUString aNewURL
= getParentURL();
1881 if ( aNewURL
.lastIndexOf( '/' ) != ( aNewURL
.getLength() - 1 ) )
1884 aNewURL
+= SerfUri::escapeSegment( aNewTitle
);
1886 uno::Reference
< ucb::XContentIdentifier
> xNewId
1887 = new ::ucbhelper::ContentIdentifier( aNewURL
);
1888 uno::Reference
< ucb::XContentIdentifier
> xOldId
= xIdentifier
;
1892 SerfUri
sourceURI( xOldId
->getContentIdentifier() );
1893 SerfUri
targetURI( xNewId
->getContentIdentifier() );
1894 targetURI
.SetScheme( sourceURI
.GetScheme() );
1897 sourceURI
.GetPath(), targetURI
.GetURI(), false, xEnv
);
1898 // @@@ Should check for resources that could not be moved
1899 // (due to source access or target overwrite) and send
1900 // this information through the interaction handler.
1902 // @@@ Existing content should be checked to see if it needs
1903 // to be deleted at the source
1905 // @@@ Existing content should be checked to see if it has
1906 // been overwritten at the target
1908 if ( exchangeIdentity( xNewId
) )
1910 xResAccess
->setURL( aNewURL
);
1912 // DAV resources store all additional props on server!
1913 // // Adapt Additional Core Properties.
1914 // renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1915 // xNewId->getContentIdentifier(),
1920 // Do not set new title!
1924 aRet
[ nTitlePos
] <<= uno::Exception(
1926 static_cast< cppu::OWeakObject
* >( this ) );
1929 catch ( DAVException
const & e
)
1931 // Do not set new title!
1935 aRet
[ nTitlePos
] = MapDAVException( e
, true );
1939 if ( aNewTitle
.getLength() )
1941 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1943 aEvent
.PropertyName
= "Title";
1944 aEvent
.OldValue
<<= aOldTitle
;
1945 aEvent
.NewValue
<<= aNewTitle
;
1947 m_aEscapedTitle
= SerfUri::escapeSegment( aNewTitle
);
1949 aChanges
.getArray()[ nChanged
] = aEvent
;
1955 aChanges
.realloc( nChanged
);
1956 notifyPropertiesChange( aChanges
);
1960 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1961 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
) );
1968 uno::Any
Content::open(
1969 const ucb::OpenCommandArgument2
& rArg
,
1970 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1974 bool bOpenFolder
= ( ( rArg
.Mode
== ucb::OpenMode::ALL
) ||
1975 ( rArg
.Mode
== ucb::OpenMode::FOLDERS
) ||
1976 ( rArg
.Mode
== ucb::OpenMode::DOCUMENTS
) );
1979 if ( isFolder( xEnv
) )
1983 uno::Reference
< ucb::XDynamicResultSet
> xSet
1984 = new DynamicResultSet( m_xContext
, this, rArg
, xEnv
);
1989 // Error: Not a folder!
1991 OUString
aMsg( "Non-folder resource cannot be opened as folder! Wrong Open Mode!" );
1993 ucbhelper::cancelCommandExecution(
1995 lang::IllegalArgumentException(
1997 static_cast< cppu::OWeakObject
* >( this ),
2004 if ( rArg
.Sink
.is() )
2008 if ( ( rArg
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
2009 ( rArg
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
) )
2011 // Currently(?) unsupported.
2012 ucbhelper::cancelCommandExecution(
2014 ucb::UnsupportedOpenModeException(
2016 static_cast< cppu::OWeakObject
* >( this ),
2017 sal_Int16( rArg
.Mode
) ) ),
2022 uno::Reference
< io::XOutputStream
> xOut( rArg
.Sink
, uno::UNO_QUERY
);
2028 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2031 osl::MutexGuard
aGuard( m_aMutex
);
2034 new DAVResourceAccess( *m_xResAccess
) );
2037 DAVResource aResource
;
2038 std::vector
< OUString
> aHeaders
;
2040 xResAccess
->GET( xOut
, aHeaders
, aResource
, xEnv
);
2041 m_bDidGetOrHead
= true;
2044 osl::MutexGuard
aGuard( m_aMutex
);
2047 if ( !m_xCachedProps
.get())
2048 m_xCachedProps
.reset(
2049 new CachableContentProperties( ContentProperties( aResource
) ) );
2051 m_xCachedProps
->addProperties( ContentProperties( aResource
) );
2054 new DAVResourceAccess( *xResAccess
) );
2057 catch ( DAVException
const & e
)
2059 cancelCommandExecution( e
, xEnv
);
2065 uno::Reference
< io::XActiveDataSink
> xDataSink( rArg
.Sink
, uno::UNO_QUERY
);
2066 if ( xDataSink
.is() )
2068 // PULL: wait for client read
2071 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2073 osl::MutexGuard
aGuard( m_aMutex
);
2076 new DAVResourceAccess( *m_xResAccess
) );
2079 // fill inputstream sync; return if all data present
2080 DAVResource aResource
;
2081 std::vector
< OUString
> aHeaders
;
2083 uno::Reference
< io::XInputStream
> xIn
2084 = xResAccess
->GET( aHeaders
, aResource
, xEnv
);
2085 m_bDidGetOrHead
= true;
2088 osl::MutexGuard
aGuard( m_aMutex
);
2091 if ( !m_xCachedProps
.get())
2092 m_xCachedProps
.reset(
2093 new CachableContentProperties( ContentProperties( aResource
) ) );
2095 m_xCachedProps
->addProperties(
2096 aResource
.properties
);
2099 new DAVResourceAccess( *xResAccess
) );
2102 xDataSink
->setInputStream( xIn
);
2104 catch ( DAVException
const & e
)
2106 cancelCommandExecution( e
, xEnv
);
2112 // Note: aOpenCommand.Sink may contain an XStream
2113 // implementation. Support for this type of
2114 // sink is optional...
2115 ucbhelper::cancelCommandExecution(
2117 ucb::UnsupportedDataSinkException(
2119 static_cast< cppu::OWeakObject
* >( this ),
2132 const ucb::PostCommandArgument2
& rArg
,
2133 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
2135 uno::Reference
< io::XActiveDataSink
> xSink( rArg
.Sink
, uno::UNO_QUERY
);
2140 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2142 osl::MutexGuard
aGuard( m_aMutex
);
2144 new DAVResourceAccess( *m_xResAccess
) );
2147 uno::Reference
< io::XInputStream
> xResult
2148 = xResAccess
->POST( rArg
.MediaType
,
2154 osl::MutexGuard
aGuard( m_aMutex
);
2156 new DAVResourceAccess( *xResAccess
) );
2159 xSink
->setInputStream( xResult
);
2161 catch ( DAVException
const & e
)
2163 cancelCommandExecution( e
, xEnv
, true );
2169 uno::Reference
< io::XOutputStream
> xResult( rArg
.Sink
, uno::UNO_QUERY
);
2174 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2176 osl::MutexGuard
aGuard( m_aMutex
);
2178 new DAVResourceAccess( *m_xResAccess
) );
2181 xResAccess
->POST( rArg
.MediaType
,
2188 osl::MutexGuard
aGuard( m_aMutex
);
2190 new DAVResourceAccess( *xResAccess
) );
2193 catch ( DAVException
const & e
)
2195 cancelCommandExecution( e
, xEnv
, true );
2201 ucbhelper::cancelCommandExecution(
2203 ucb::UnsupportedDataSinkException(
2205 static_cast< cppu::OWeakObject
* >( this ),
2214 void Content::queryChildren( ContentRefList
& rChildren
)
2216 // Obtain a list with a snapshot of all currently instantiated contents
2217 // from provider and extract the contents which are direct children
2220 ::ucbhelper::ContentRefList aAllContents
;
2221 m_xProvider
->queryExistingContents( aAllContents
);
2223 OUString aURL
= m_xIdentifier
->getContentIdentifier();
2224 sal_Int32 nURLPos
= aURL
.lastIndexOf( '/' );
2226 if ( nURLPos
!= ( aURL
.getLength() - 1 ) )
2228 // No trailing slash found. Append.
2232 sal_Int32 nLen
= aURL
.getLength();
2234 for ( const auto& rChild
: aAllContents
)
2236 ::ucbhelper::ContentImplHelperRef xChild
= rChild
;
2238 = xChild
->getIdentifier()->getContentIdentifier();
2240 // Is aURL a prefix of aChildURL?
2241 if ( ( aChildURL
.getLength() > nLen
) &&
2242 ( aChildURL
.startsWith( aURL
) ) )
2244 sal_Int32 nPos
= nLen
;
2245 nPos
= aChildURL
.indexOf( '/', nPos
);
2247 if ( ( nPos
== -1 ) ||
2248 ( nPos
== ( aChildURL
.getLength() - 1 ) ) )
2250 // No further slashes / only a final slash. It's a child!
2251 rChildren
.push_back(
2252 ::http_dav_ucp::Content::ContentRef(
2253 static_cast< ::http_dav_ucp::Content
* >(
2261 void Content::insert(
2262 const uno::Reference
< io::XInputStream
> & xInputStream
,
2263 bool bReplaceExisting
,
2264 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2266 bool bTransient
, bCollection
;
2267 OUString aEscapedTitle
;
2268 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2271 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2273 bTransient
= m_bTransient
;
2274 bCollection
= m_bCollection
;
2275 aEscapedTitle
= m_aEscapedTitle
;
2276 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
) );
2279 // Check, if all required properties are present.
2281 if ( aEscapedTitle
.isEmpty() )
2283 SAL_WARN( "ucb.ucp.webdav", "Content::insert - Title missing!" );
2285 uno::Sequence
<OUString
> aProps
{ "Title" };
2286 ucbhelper::cancelCommandExecution(
2287 uno::makeAny( ucb::MissingPropertiesException(
2289 static_cast< cppu::OWeakObject
* >( this ),
2295 if ( !bReplaceExisting
)
2297 /* [RFC 2616] - HTTP
2299 The PUT method requests that the enclosed entity be stored under the
2300 supplied Request-URI. If the Request-URI refers to an already
2301 existing resource, the enclosed entity SHOULD be considered as a
2302 modified version of the one residing on the origin server.
2305 /* [RFC 2518] - WebDAV
2307 MKCOL creates a new collection resource at the location specified by
2308 the Request-URI. If the resource identified by the Request-URI is
2309 non-null then the MKCOL MUST fail.
2312 // ==> Complain on PUT, continue on MKCOL.
2313 if ( !bTransient
|| !bCollection
)
2316 ucb::UnsupportedNameClashException
aEx(
2317 "Unable to write without overwrite!",
2318 static_cast< cppu::OWeakObject
* >( this ),
2319 ucb::NameClash::ERROR
);
2321 uno::Reference
< task::XInteractionHandler
> xIH
;
2323 if ( Environment
.is() )
2324 xIH
= Environment
->getInteractionHandler();
2328 uno::Any
aExAsAny( uno::makeAny( aEx
) );
2330 rtl::Reference
< ucbhelper::SimpleInteractionRequest
> xRequest
2331 = new ucbhelper::SimpleInteractionRequest(
2333 ContinuationFlags::Approve
2334 | ContinuationFlags::Disapprove
);
2335 xIH
->handle( xRequest
.get() );
2337 const ContinuationFlags nResp
= xRequest
->getResponse();
2341 case ContinuationFlags::NONE
:
2342 // Not handled; throw.
2346 case ContinuationFlags::Approve
:
2347 // Continue -> Overwrite.
2348 bReplaceExisting
= true;
2351 case ContinuationFlags::Disapprove
:
2353 throw ucb::CommandFailedException(
2355 uno::Reference
< uno::XInterface
>(),
2360 SAL_WARN( "ucb.ucp.webdav",
2361 "Content::insert - "
2362 "Unknown interaction selection!" );
2363 throw ucb::CommandFailedException(
2364 "Unknown interaction selection!",
2365 uno::Reference
< uno::XInterface
>(),
2380 // Assemble new content identifier...
2381 OUString aURL
= getParentURL();
2382 if ( aURL
.lastIndexOf( '/' ) != ( aURL
.getLength() - 1 ) )
2385 aURL
+= aEscapedTitle
;
2389 xResAccess
->setURL( aURL
);
2392 xResAccess
->MKCOL( Environment
);
2394 xResAccess
->PUT( xInputStream
, Environment
);
2396 catch ( DAVException
const & except
)
2400 if ( except
.getStatus() == SC_METHOD_NOT_ALLOWED
)
2402 // [RFC 2518] - WebDAV
2403 // 405 (Method Not Allowed) - MKCOL can only be
2404 // executed on a deleted/non-existent resource.
2406 if ( bReplaceExisting
)
2408 // Destroy old resource.
2411 xResAccess
->DESTROY( Environment
);
2413 catch ( DAVException
const & e
)
2415 cancelCommandExecution( e
, Environment
, true );
2419 // Insert (recursion!).
2420 insert( xInputStream
, bReplaceExisting
, Environment
);
2423 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2425 new DAVResourceAccess( *xResAccess
) );
2436 SerfUri
aURI( aURL
);
2437 aTitle
= aURI
.GetPathBaseNameUnescaped();
2439 catch ( DAVException
const & )
2443 ucbhelper::cancelCommandExecution(
2445 ucb::NameClashException(
2447 static_cast< cppu::OWeakObject
* >( this ),
2448 task::InteractionClassification_ERROR
,
2456 cancelCommandExecution( except
, Environment
, true );
2461 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2463 = new ::ucbhelper::ContentIdentifier( aURL
);
2469 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2470 m_bTransient
= false;
2475 if ( !xInputStream
.is() )
2477 ucbhelper::cancelCommandExecution(
2479 ucb::MissingInputStreamException(
2481 static_cast< cppu::OWeakObject
* >( this ) ) ),
2488 xResAccess
->PUT( xInputStream
, Environment
);
2490 catch ( DAVException
const & e
)
2492 cancelCommandExecution( e
, Environment
, true );
2498 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2499 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
) );
2504 void Content::transfer(
2505 const ucb::TransferInfo
& rArgs
,
2506 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2508 uno::Reference
< uno::XComponentContext
> xContext
;
2509 uno::Reference
< ucb::XContentIdentifier
> xIdentifier
;
2510 uno::Reference
< ucb::XContentProvider
> xProvider
;
2511 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2514 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2516 xContext
.set( m_xContext
);
2517 xIdentifier
.set( m_xIdentifier
);
2518 xProvider
.set( m_xProvider
.get() );
2519 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
) );
2522 OUString aTargetURI
;
2525 SerfUri
sourceURI( rArgs
.SourceURL
);
2526 SerfUri
targetURI( xIdentifier
->getContentIdentifier() );
2527 aTargetURI
= targetURI
.GetPathBaseNameUnescaped();
2529 // Check source's and target's URL scheme
2531 OUString aScheme
= sourceURI
.GetScheme().toAsciiLowerCase();
2532 if ( aScheme
== VNDSUNSTARWEBDAV_URL_SCHEME
)
2534 sourceURI
.SetScheme( HTTP_URL_SCHEME
);
2536 else if ( aScheme
== VNDSUNSTARWEBDAVS_URL_SCHEME
)
2538 sourceURI
.SetScheme( HTTPS_URL_SCHEME
);
2540 else if ( aScheme
== DAV_URL_SCHEME
)
2542 sourceURI
.SetScheme( HTTP_URL_SCHEME
);
2544 else if ( aScheme
== DAVS_URL_SCHEME
)
2546 sourceURI
.SetScheme( HTTPS_URL_SCHEME
);
2548 else if (aScheme
== WEBDAV_URL_SCHEME
)
2550 sourceURI
.SetScheme(HTTP_URL_SCHEME
);
2552 else if (aScheme
== WEBDAVS_URL_SCHEME
)
2554 sourceURI
.SetScheme(HTTPS_URL_SCHEME
);
2558 if ( aScheme
!= HTTP_URL_SCHEME
&& aScheme
!= HTTPS_URL_SCHEME
)
2560 ucbhelper::cancelCommandExecution(
2562 ucb::InteractiveBadTransferURLException(
2563 "Unsupported URL scheme!",
2564 static_cast< cppu::OWeakObject
* >( this ) ) ),
2570 aScheme
= targetURI
.GetScheme().toAsciiLowerCase();
2571 if ( aScheme
== VNDSUNSTARWEBDAV_URL_SCHEME
)
2572 targetURI
.SetScheme( HTTP_URL_SCHEME
);
2573 else if ( aScheme
== VNDSUNSTARWEBDAVS_URL_SCHEME
)
2574 targetURI
.SetScheme( HTTPS_URL_SCHEME
);
2575 else if ( aScheme
== DAV_URL_SCHEME
)
2576 targetURI
.SetScheme( HTTP_URL_SCHEME
);
2577 else if ( aScheme
== DAVS_URL_SCHEME
)
2578 targetURI
.SetScheme( HTTPS_URL_SCHEME
);
2579 else if (aScheme
== WEBDAV_URL_SCHEME
)
2580 targetURI
.SetScheme(HTTP_URL_SCHEME
);
2581 else if (aScheme
== WEBDAVS_URL_SCHEME
)
2582 targetURI
.SetScheme(HTTPS_URL_SCHEME
);
2584 // @@@ This implementation of 'transfer' only works
2585 // if the source and target are located at same host.
2586 // (Neon does not support cross-server copy/move)
2588 // Check for same host
2590 if ( sourceURI
.GetHost().getLength() &&
2591 ( sourceURI
.GetHost() != targetURI
.GetHost() ) )
2593 ucbhelper::cancelCommandExecution(
2594 uno::makeAny( ucb::InteractiveBadTransferURLException(
2596 static_cast< cppu::OWeakObject
* >( this ) ) ),
2601 OUString aTitle
= rArgs
.NewTitle
;
2603 if ( aTitle
.isEmpty() )
2604 aTitle
= sourceURI
.GetPathBaseNameUnescaped();
2606 if ( aTitle
== "/" )
2612 targetURI
.AppendPath( aTitle
);
2614 OUString aTargetURL
= xIdentifier
->getContentIdentifier();
2615 if ( ( aTargetURL
.lastIndexOf( '/' ) + 1 )
2616 != aTargetURL
.getLength() )
2619 aTargetURL
+= aTitle
;
2621 uno::Reference
< ucb::XContentIdentifier
> xTargetId
2622 = new ::ucbhelper::ContentIdentifier( aTargetURL
);
2624 DAVResourceAccess
aSourceAccess( xContext
,
2625 xResAccess
->getSessionFactory(),
2626 sourceURI
.GetURI() );
2628 if ( rArgs
.MoveData
)
2630 uno::Reference
< ucb::XContentIdentifier
> xId
2631 = new ::ucbhelper::ContentIdentifier( rArgs
.SourceURL
);
2633 // Note: The static cast is okay here, because its sure that
2634 // xProvider is always the WebDAVContentProvider.
2635 rtl::Reference
< Content
> xSource
2636 = static_cast< Content
* >(
2637 xProvider
->queryContent( xId
).get() );
2639 // [RFC 2518] - WebDAV
2640 // If a resource exists at the destination and the Overwrite
2641 // header is "T" then prior to performing the move the server
2642 // MUST perform a DELETE with "Depth: infinity" on the
2643 // destination resource. If the Overwrite header is set to
2644 // "F" then the operation will fail.
2646 aSourceAccess
.MOVE( sourceURI
.GetPath(),
2649 == ucb::NameClash::OVERWRITE
,
2654 // Propagate destruction to listeners.
2655 xSource
->destroy( true );
2658 // DAV resources store all additional props on server!
2659 // // Rename own and all children's Additional Core Properties.
2660 // renameAdditionalPropertySet( xId->getContentIdentifier(),
2661 // xTargetId->getContentIdentifier(),
2666 // [RFC 2518] - WebDAV
2667 // If a resource exists at the destination and the Overwrite
2668 // header is "T" then prior to performing the copy the server
2669 // MUST perform a DELETE with "Depth: infinity" on the
2670 // destination resource. If the Overwrite header is set to
2671 // "F" then the operation will fail.
2673 aSourceAccess
.COPY( sourceURI
.GetPath(),
2676 == ucb::NameClash::OVERWRITE
,
2679 // DAV resources store all additional props on server!
2680 // // Copy own and all children's Additional Core Properties.
2681 // copyAdditionalPropertySet( xId->getContentIdentifier(),
2682 // xTargetId->getContentIdentifier(),
2686 // Note: The static cast is okay here, because its sure that
2687 // xProvider is always the WebDAVContentProvider.
2688 rtl::Reference
< Content
> xTarget
2689 = static_cast< Content
* >(
2690 xProvider
->queryContent( xTargetId
).get() );
2692 // Announce transferred content in its new folder.
2693 xTarget
->inserted();
2695 catch ( ucb::IllegalIdentifierException
const & )
2699 catch ( DAVException
const & e
)
2701 // [RFC 2518] - WebDAV
2702 // 412 (Precondition Failed) - The server was unable to maintain
2703 // the liveness of the properties listed in the propertybehavior
2704 // XML element or the Overwrite header is "F" and the state of
2705 // the destination resource is non-null.
2707 if ( e
.getStatus() == SC_PRECONDITION_FAILED
)
2709 switch ( rArgs
.NameClash
)
2711 case 0/*ucb::NameClash::ERROR*/:
2713 ucbhelper::cancelCommandExecution(
2715 ucb::NameClashException(
2717 static_cast< cppu::OWeakObject
* >( this ),
2718 task::InteractionClassification_ERROR
,
2725 case ucb::NameClash::OVERWRITE
:
2728 case ucb::NameClash::KEEP
: // deprecated
2729 case ucb::NameClash::RENAME
:
2730 case ucb::NameClash::ASK
:
2733 ucbhelper::cancelCommandExecution(
2735 ucb::UnsupportedNameClashException(
2737 static_cast< cppu::OWeakObject
* >( this ),
2738 rArgs
.NameClash
) ),
2745 cancelCommandExecution( e
, Environment
, true );
2750 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2751 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
) );
2756 void Content::destroy( bool bDeletePhysical
)
2758 // @@@ take care about bDeletePhysical -> trashcan support
2760 uno::Reference
< ucb::XContent
> xThis
= this;
2764 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2766 // Process instantiated children...
2768 ::http_dav_ucp::Content::ContentRefList aChildren
;
2769 queryChildren( aChildren
);
2771 for ( auto& rChild
: aChildren
)
2773 rChild
->destroy( bDeletePhysical
);
2778 bool Content::supportsExclusiveWriteLock(
2779 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2781 if ( getResourceType( Environment
) == DAV
)
2783 if ( m_xCachedProps
.get() )
2785 uno::Sequence
< ucb::LockEntry
> aSupportedLocks
;
2786 if ( m_xCachedProps
->getValue( DAVProperties::SUPPORTEDLOCK
)
2787 >>= aSupportedLocks
)
2789 for ( sal_Int32 n
= 0; n
< aSupportedLocks
.getLength(); ++n
)
2791 if ( aSupportedLocks
[ n
].Scope
2792 == ucb::LockScope_EXCLUSIVE
&&
2793 aSupportedLocks
[ n
].Type
2794 == ucb::LockType_WRITE
)
2805 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2809 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2811 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2812 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
) );
2816 aOwnerAny
<<= OUString( "http://ucb.openoffice.org" );
2819 ucb::LockScope_EXCLUSIVE
,
2820 ucb::LockType_WRITE
,
2821 ucb::LockDepth_ZERO
,
2823 180, // lock timeout in secs
2824 //-1, // infinite lock
2825 uno::Sequence
< OUString
>() );
2827 xResAccess
->LOCK( aLock
, Environment
);
2831 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2832 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
) );
2835 catch ( DAVException
const & e
)
2837 cancelCommandExecution( e
, Environment
, false );
2843 void Content::unlock(
2844 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2848 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2850 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2851 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
) );
2854 xResAccess
->UNLOCK( Environment
);
2858 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2859 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
) );
2862 catch ( DAVException
const & e
)
2864 cancelCommandExecution( e
, Environment
, false );
2870 bool Content::exchangeIdentity(
2871 const uno::Reference
< ucb::XContentIdentifier
>& xNewId
)
2876 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
2878 uno::Reference
< ucb::XContent
> xThis
= this;
2880 // Already persistent?
2883 SAL_WARN( "ucb.ucp.webdav", "Content::exchangeIdentity - Not persistent!" );
2887 // Exchange own identity.
2889 // Fail, if a content with given id already exists.
2890 // if ( !hasData( xNewId ) )
2892 OUString aOldURL
= m_xIdentifier
->getContentIdentifier();
2895 if ( exchange( xNewId
) )
2897 // Process instantiated children...
2899 ContentRefList aChildren
;
2900 queryChildren( aChildren
);
2902 for ( const auto& rChild
: aChildren
)
2904 ContentRef xChild
= rChild
;
2906 // Create new content identifier for the child...
2907 uno::Reference
< ucb::XContentIdentifier
>
2908 xOldChildId
= xChild
->getIdentifier();
2909 OUString aOldChildURL
2910 = xOldChildId
->getContentIdentifier();
2911 OUString aNewChildURL
2912 = aOldChildURL
.replaceAt(
2914 aOldURL
.getLength(),
2915 xNewId
->getContentIdentifier() );
2916 uno::Reference
< ucb::XContentIdentifier
> xNewChildId
2917 = new ::ucbhelper::ContentIdentifier( aNewChildURL
);
2919 if ( !xChild
->exchangeIdentity( xNewChildId
) )
2926 SAL_WARN( "ucb.ucp.webdav",
2927 "Content::exchangeIdentity - "
2928 "Panic! Cannot exchange identity!" );
2933 bool Content::isFolder(
2934 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
2937 osl::MutexGuard
aGuard( m_aMutex
);
2940 return m_bCollection
;
2943 uno::Sequence
< beans::Property
> aProperties( 1 );
2944 aProperties
[ 0 ].Name
= "IsFolder";
2945 aProperties
[ 0 ].Handle
= -1;
2946 uno::Reference
< sdbc::XRow
> xRow( getPropertyValues( aProperties
, xEnv
) );
2951 return xRow
->getBoolean( 1 );
2953 catch ( sdbc::SQLException
const & )
2962 uno::Any
Content::MapDAVException( const DAVException
& e
, bool bWrite
)
2964 // Map DAVException...
2965 uno::Any aException
;
2970 aURL
= getParentURL();
2971 if ( aURL
.lastIndexOf( '/' ) != ( aURL
.getLength() - 1 ) )
2974 aURL
+= m_aEscapedTitle
;
2978 aURL
= m_xIdentifier
->getContentIdentifier();
2981 switch ( e
.getStatus() )
2985 uno::Sequence
< uno::Any
> aArgs( 1 );
2986 aArgs
[ 0 ] <<= beans::PropertyValue(
2989 beans::PropertyState_DIRECT_VALUE
);
2992 ucb::InteractiveAugmentedIOException(
2994 static_cast< cppu::OWeakObject
* >( this ),
2995 task::InteractionClassification_ERROR
,
2996 ucb::IOErrorCode_NOT_EXISTING
,
3004 switch ( e
.getError() )
3006 case DAVException::DAV_HTTP_ERROR
:
3010 ucb::InteractiveNetworkWriteException(
3012 static_cast< cppu::OWeakObject
* >( this ),
3013 task::InteractionClassification_ERROR
,
3017 ucb::InteractiveNetworkReadException(
3019 static_cast< cppu::OWeakObject
* >( this ),
3020 task::InteractionClassification_ERROR
,
3025 case DAVException::DAV_HTTP_LOOKUP
:
3027 ucb::InteractiveNetworkResolveNameException(
3029 static_cast< cppu::OWeakObject
* >( this ),
3030 task::InteractionClassification_ERROR
,
3034 // @@@ No matching InteractiveNetwork*Exception
3035 // case DAVException::DAV_HTTP_AUTH:
3038 // @@@ No matching InteractiveNetwork*Exception
3039 // case DAVException::DAV_HTTP_AUTHPROXY:
3042 case DAVException::DAV_HTTP_CONNECT
:
3044 ucb::InteractiveNetworkConnectException(
3046 static_cast< cppu::OWeakObject
* >( this ),
3047 task::InteractionClassification_ERROR
,
3051 // @@@ No matching InteractiveNetwork*Exception
3052 // case DAVException::DAV_HTTP_TIMEOUT:
3055 // @@@ No matching InteractiveNetwork*Exception
3056 // case DAVException::DAV_HTTP_REDIRECT:
3059 // @@@ No matching InteractiveNetwork*Exception
3060 // case DAVException::DAV_SESSION_CREATE:
3063 case DAVException::DAV_INVALID_ARG
:
3065 lang::IllegalArgumentException(
3067 static_cast< cppu::OWeakObject
* >( this ),
3071 case DAVException::DAV_LOCKED
:
3074 ucb::InteractiveLockingLockedException(
3076 static_cast< cppu::OWeakObject
* >( this ),
3077 task::InteractionClassification_ERROR
,
3079 false ); // not SelfOwned
3082 uno::Sequence
< uno::Any
> aArgs( 1 );
3083 aArgs
[ 0 ] <<= beans::PropertyValue(
3084 OUString("Uri"), -1,
3086 beans::PropertyState_DIRECT_VALUE
);
3089 ucb::InteractiveAugmentedIOException(
3090 OUString( "Locked!" ),
3091 static_cast< cppu::OWeakObject
* >( this ),
3092 task::InteractionClassification_ERROR
,
3093 ucb::IOErrorCode_LOCKING_VIOLATION
,
3099 case DAVException::DAV_LOCKED_SELF
:
3101 ucb::InteractiveLockingLockedException(
3103 static_cast< cppu::OWeakObject
* >( this ),
3104 task::InteractionClassification_ERROR
,
3106 true ); // SelfOwned
3109 case DAVException::DAV_NOT_LOCKED
:
3111 ucb::InteractiveLockingNotLockedException(
3113 static_cast< cppu::OWeakObject
* >( this ),
3114 task::InteractionClassification_ERROR
,
3118 case DAVException::DAV_LOCK_EXPIRED
:
3120 ucb::InteractiveLockingLockExpiredException(
3122 static_cast< cppu::OWeakObject
* >( this ),
3123 task::InteractionClassification_ERROR
,
3129 ucb::InteractiveNetworkGeneralException(
3131 static_cast< cppu::OWeakObject
* >( this ),
3132 task::InteractionClassification_ERROR
);
3141 bool Content::shouldAccessNetworkAfterException( const DAVException
& e
)
3143 if ( ( e
.getStatus() == SC_NOT_FOUND
) ||
3144 ( e
.getError() == DAVException::DAV_HTTP_LOOKUP
) ||
3145 ( e
.getError() == DAVException::DAV_HTTP_CONNECT
) ||
3146 ( e
.getError() == DAVException::DAV_HTTP_AUTH
) ||
3147 ( e
.getError() == DAVException::DAV_HTTP_AUTHPROXY
) )
3154 void Content::cancelCommandExecution(
3155 const DAVException
& e
,
3156 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
3157 bool bWrite
/* = false */ )
3159 ucbhelper::cancelCommandExecution( MapDAVException( e
, bWrite
), xEnv
);
3165 Content::getBaseURI( const std::unique_ptr
< DAVResourceAccess
> & rResAccess
)
3167 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
3169 // First, try to obtain value of response header "Content-Location".
3170 if ( m_xCachedProps
.get() )
3173 m_xCachedProps
->getValue( "Content-Location" ) >>= aLocation
;
3174 if ( aLocation
.getLength() )
3178 // Do not use m_xIdentifier->getContentIdentifier() because it
3179 // for example does not reflect redirects applied to requests
3180 // done using the original URI but m_xResAccess' URI does.
3181 return rtl::Uri::convertRelToAbs( rResAccess
->getURL(),
3184 catch ( rtl::MalformedUriException
const & )
3190 return rResAccess
->getURL();
3194 Content::ResourceType
Content::getResourceType(
3195 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
,
3196 const std::unique_ptr
< DAVResourceAccess
> & rResAccess
,
3197 bool * networkAccessAllowed
)
3200 osl::MutexGuard
g(m_aMutex
);
3201 if (m_eResourceType
!= UNKNOWN
) {
3202 return m_eResourceType
;
3206 ResourceType eResourceType
= UNKNOWN
;
3210 // Try to fetch some frequently used property value, e.g. those
3211 // used when loading documents... along with identifying whether
3212 // this is a DAV resource.
3213 std::vector
< DAVResource
> resources
;
3214 std::vector
< OUString
> aPropNames
;
3215 uno::Sequence
< beans::Property
> aProperties( 5 );
3216 aProperties
[ 0 ].Name
= "IsFolder";
3217 aProperties
[ 1 ].Name
= "IsDocument";
3218 aProperties
[ 2 ].Name
= "IsReadOnly";
3219 aProperties
[ 3 ].Name
= "MediaType";
3220 aProperties
[ 4 ].Name
= DAVProperties::SUPPORTEDLOCK
;
3222 ContentProperties::UCBNamesToDAVNames(
3223 aProperties
, aPropNames
);
3225 rResAccess
->PROPFIND(
3226 DAVZERO
, aPropNames
, resources
, xEnv
);
3228 // TODO - is this really only one?
3229 if ( resources
.size() == 1 )
3231 osl::MutexGuard
g(m_aMutex
);
3232 m_xCachedProps
.reset(
3233 new CachableContentProperties( ContentProperties( resources
[ 0 ] ) ) );
3234 m_xCachedProps
->containsAllNames(
3235 aProperties
, m_aFailedPropNames
);
3238 eResourceType
= DAV
;
3240 catch ( DAVException
const & e
)
3242 rResAccess
->resetUri();
3244 if ( e
.getStatus() == SC_METHOD_NOT_ALLOWED
)
3246 // Status SC_METHOD_NOT_ALLOWED is a safe indicator that the
3247 // resource is NON_DAV
3248 eResourceType
= NON_DAV
;
3250 else if (networkAccessAllowed
!= nullptr)
3252 *networkAccessAllowed
= *networkAccessAllowed
3253 && shouldAccessNetworkAfterException(e
);
3256 // cancel command execution is case that no user authentication data has been provided.
3257 if ( e
.getError() == DAVException::DAV_HTTP_NOAUTH
)
3259 cancelCommandExecution( e
, uno::Reference
< ucb::XCommandEnvironment
>() );
3263 osl::MutexGuard
g(m_aMutex
);
3264 if (m_eResourceType
== UNKNOWN
) {
3265 m_eResourceType
= eResourceType
;
3268 eResourceType
!= m_eResourceType
, "ucb.ucp.webdav",
3269 "different resource types for <" << rResAccess
->getURL() << ">: "
3270 << +eResourceType
<< " vs. " << +m_eResourceType
);
3272 return m_eResourceType
;
3276 Content::ResourceType
Content::getResourceType(
3277 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
3279 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
3281 osl::MutexGuard
aGuard( m_aMutex
);
3282 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
) );
3284 const Content::ResourceType
& ret
= getResourceType( xEnv
, xResAccess
);
3286 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
3287 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
) );
3292 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */