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 .
20 #include <osl/diagnose.h>
21 #include <osl/doublecheckedlocking.h>
22 #include <rtl/uri.hxx>
23 #include <rtl/ustrbuf.hxx>
24 #include <ucbhelper/contentidentifier.hxx>
25 #include <ucbhelper/propertyvalueset.hxx>
26 #include <ucbhelper/simpleinteractionrequest.hxx>
27 #include <ucbhelper/cancelcommandexecution.hxx>
29 #include <com/sun/star/beans/PropertyAttribute.hpp>
30 #include <com/sun/star/beans/PropertySetInfoChange.hpp>
31 #include <com/sun/star/beans/PropertySetInfoChangeEvent.hpp>
32 #include <com/sun/star/beans/PropertyValue.hpp>
33 #include <com/sun/star/io/XActiveDataSink.hpp>
34 #include <com/sun/star/io/XOutputStream.hpp>
35 #include <com/sun/star/lang/IllegalAccessException.hpp>
36 #include <com/sun/star/task/PasswordContainerInteractionHandler.hpp>
37 #include <com/sun/star/ucb/CommandEnvironment.hpp>
38 #include <com/sun/star/ucb/CommandFailedException.hpp>
39 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
40 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
41 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
42 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
43 #include <com/sun/star/ucb/InteractiveLockingLockedException.hpp>
44 #include <com/sun/star/ucb/InteractiveLockingLockExpiredException.hpp>
45 #include <com/sun/star/ucb/InteractiveLockingNotLockedException.hpp>
46 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
47 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
48 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
49 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
50 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
51 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
52 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
53 #include <com/sun/star/ucb/NameClash.hpp>
54 #include <com/sun/star/ucb/NameClashException.hpp>
55 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
56 #include <com/sun/star/ucb/OpenMode.hpp>
57 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
58 #include <com/sun/star/ucb/PropertyCommandArgument.hpp>
59 #include <com/sun/star/ucb/TransferInfo.hpp>
60 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
61 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
62 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
63 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
64 #include <com/sun/star/ucb/XCommandInfo.hpp>
65 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
66 #include <com/sun/star/uno/XComponentContext.hpp>
68 #include "webdavcontent.hxx"
69 #include "webdavprovider.hxx"
70 #include "webdavresultset.hxx"
71 #include "ContentProperties.hxx"
72 #include "SerfUri.hxx"
73 #include "UCBDeadPropertyValue.hxx"
75 using namespace com::sun::star
;
76 using namespace http_dav_ucp
;
80 static void lcl_sendPartialGETRequest( bool &bError
,
81 DAVException
&aLastException
,
82 const std::vector
< rtl::OUString
>& rProps
,
83 std::vector
< rtl::OUString
> &aHeaderNames
,
84 const boost::scoped_ptr
< DAVResourceAccess
> &xResAccess
,
85 boost::scoped_ptr
< ContentProperties
> &xProps
,
86 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
88 bool bIsRequestSize
= false;
89 DAVResource aResource
;
90 DAVRequestHeaders aPartialGet
;
91 aPartialGet
.push_back(
94 OUString( "bytes=0-0" )));
96 for ( std::vector
< rtl::OUString
>::const_iterator it
= aHeaderNames
.begin();
97 it
!= aHeaderNames
.end(); ++it
)
99 if ( *it
== "Content-Length" )
101 bIsRequestSize
= true;
106 if ( bIsRequestSize
)
108 // we need to know if the server accepts range requests for a resource
109 // and the range unit it uses
110 aHeaderNames
.push_back( OUString( "Accept-Ranges" ) );
111 aHeaderNames
.push_back( OUString( "Content-Range" ) );
115 uno::Reference
< io::XInputStream
> xIn
= xResAccess
->GET( aPartialGet
,
121 if ( bIsRequestSize
)
123 // the ContentProperties maps "Content-Length" to the UCB "Size" property
124 // This would have an unrealistic value of 1 byte because we did only a partial GET
125 // Solution: if "Content-Range" is present, map it with UCB "Size" property
126 rtl::OUString aAcceptRanges
, aContentRange
, aContentLength
;
127 std::vector
< DAVPropertyValue
> &aResponseProps
= aResource
.properties
;
128 for ( std::vector
< DAVPropertyValue
>::const_iterator it
= aResponseProps
.begin();
129 it
!= aResponseProps
.end(); ++it
)
131 if ( it
->Name
== "Accept-Ranges" )
132 it
->Value
>>= aAcceptRanges
;
133 else if ( it
->Name
== "Content-Range" )
134 it
->Value
>>= aContentRange
;
135 else if ( it
->Name
== "Content-Length" )
136 it
->Value
>>= aContentLength
;
140 if ( aContentLength
.getLength() )
142 nSize
= aContentLength
.toInt64();
145 // according to http://tools.ietf.org/html/rfc2616#section-3.12
146 // the only range unit defined is "bytes" and implementations
147 // MAY ignore ranges specified using other units.
149 aContentRange
.getLength() &&
150 aAcceptRanges
== "bytes" )
152 // Parse the Content-Range to get the size
153 // vid. http://tools.ietf.org/html/rfc2616#section-14.16
154 // Content-Range: <range unit> <bytes range>/<size>
155 sal_Int32 nSlash
= aContentRange
.lastIndexOf( '/' );
158 rtl::OUString aSize
= aContentRange
.copy( nSlash
+ 1 );
159 // "*" means that the instance-length is unknown at the time when the response was generated
162 for ( std::vector
< DAVPropertyValue
>::iterator it
= aResponseProps
.begin();
163 it
!= aResponseProps
.end(); ++it
)
165 if (it
->Name
== "Content-Length")
177 xProps
->addProperties(
179 ContentProperties( aResource
) );
181 xProps
.reset ( new ContentProperties( aResource
) );
183 catch ( DAVException
const & ex
)
193 // Content Implementation.
199 // ctr for content on an existing webdav resource
201 const uno::Reference
< uno::XComponentContext
>& rxContext
,
202 ContentProvider
* pProvider
,
203 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
204 rtl::Reference
< DAVSessionFactory
> const & rSessionFactory
)
205 throw ( ucb::ContentCreationException
)
206 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
207 m_eResourceType( UNKNOWN
),
208 m_pProvider( pProvider
),
209 m_bTransient( false ),
211 m_bCollection( false ),
212 m_bDidGetOrHead( false )
216 m_xResAccess
.reset( new DAVResourceAccess(
219 Identifier
->getContentIdentifier() ) );
221 SerfUri
aURI( Identifier
->getContentIdentifier() );
222 m_aEscapedTitle
= aURI
.GetPathBaseName();
224 catch ( DAVException
const & )
226 throw ucb::ContentCreationException();
231 // ctr for content on an non-existing webdav resource
233 const uno::Reference
< uno::XComponentContext
>& rxContext
,
234 ContentProvider
* pProvider
,
235 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
236 rtl::Reference
< DAVSessionFactory
> const & rSessionFactory
,
238 throw ( ucb::ContentCreationException
)
239 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
240 m_eResourceType( UNKNOWN
),
241 m_pProvider( pProvider
),
242 m_bTransient( true ),
244 m_bCollection( isCollection
),
245 m_bDidGetOrHead( false )
249 m_xResAccess
.reset( new DAVResourceAccess(
250 rxContext
, rSessionFactory
, Identifier
->getContentIdentifier() ) );
252 catch ( DAVException
const & )
254 throw ucb::ContentCreationException();
257 // Do not set m_aEscapedTitle here! Content::insert relays on this!!!
265 unlock(uno::Reference
< ucb::XCommandEnvironment
>());
270 // XInterface methods.
275 void SAL_CALL
Content::acquire()
278 ContentImplHelper::acquire();
283 void SAL_CALL
Content::release()
286 ContentImplHelper::release();
291 uno::Any SAL_CALL
Content::queryInterface( const uno::Type
& rType
)
292 throw ( uno::RuntimeException
, std::exception
)
294 // Note: isFolder may require network activities! So call it only
295 // if it is really necessary!!!
296 uno::Any aRet
= cppu::queryInterface(
298 static_cast< ucb::XContentCreator
* >( this ) );
299 if ( aRet
.hasValue() )
303 uno::Reference
< beans::XPropertySet
> const xProps(
304 m_xContext
, uno::UNO_QUERY_THROW
);
305 uno::Reference
< uno::XComponentContext
> xCtx
;
306 xCtx
.set( xProps
->getPropertyValue(
307 OUString( "DefaultContext" ) ),
308 uno::UNO_QUERY_THROW
);
310 uno::Reference
< task::XInteractionHandler
> xIH(
311 task::PasswordContainerInteractionHandler::create( xCtx
) );
313 // Supply a command env to isFolder() that contains an interaction
314 // handler that uses the password container service to obtain
315 // credentials without displaying a password gui.
317 uno::Reference
< ucb::XCommandEnvironment
> xCmdEnv(
318 ucb::CommandEnvironment::create(
321 uno::Reference
< ucb::XProgressHandler
>() ) );
323 return isFolder( xCmdEnv
) ? aRet
: uno::Any();
325 catch ( uno::RuntimeException
const & )
329 catch ( uno::Exception
const & )
334 return aRet
.hasValue() ? aRet
: ContentImplHelper::queryInterface( rType
);
339 // XTypeProvider methods.
343 XTYPEPROVIDER_COMMON_IMPL( Content
);
347 uno::Sequence
< uno::Type
> SAL_CALL
Content::getTypes()
348 throw( uno::RuntimeException
, std::exception
)
350 bool bFolder
= false;
354 = isFolder( uno::Reference
< ucb::XCommandEnvironment
>() );
356 catch ( uno::RuntimeException
const & )
360 catch ( uno::Exception
const & )
364 cppu::OTypeCollection
* pCollection
= 0;
368 static cppu::OTypeCollection
* pFolderTypes
= 0;
370 pCollection
= pFolderTypes
;
373 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
375 pCollection
= pFolderTypes
;
378 static cppu::OTypeCollection
aCollection(
379 CPPU_TYPE_REF( lang::XTypeProvider
),
380 CPPU_TYPE_REF( lang::XServiceInfo
),
381 CPPU_TYPE_REF( lang::XComponent
),
382 CPPU_TYPE_REF( ucb::XContent
),
383 CPPU_TYPE_REF( ucb::XCommandProcessor
),
384 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
385 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
386 CPPU_TYPE_REF( beans::XPropertyContainer
),
387 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
388 CPPU_TYPE_REF( container::XChild
),
389 CPPU_TYPE_REF( ucb::XContentCreator
) ); // !!
390 pCollection
= &aCollection
;
391 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
392 pFolderTypes
= pCollection
;
396 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
401 static cppu::OTypeCollection
* pDocumentTypes
= 0;
403 pCollection
= pDocumentTypes
;
406 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
408 pCollection
= pDocumentTypes
;
411 static cppu::OTypeCollection
aCollection(
412 CPPU_TYPE_REF( lang::XTypeProvider
),
413 CPPU_TYPE_REF( lang::XServiceInfo
),
414 CPPU_TYPE_REF( lang::XComponent
),
415 CPPU_TYPE_REF( ucb::XContent
),
416 CPPU_TYPE_REF( ucb::XCommandProcessor
),
417 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
418 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
419 CPPU_TYPE_REF( beans::XPropertyContainer
),
420 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
421 CPPU_TYPE_REF( container::XChild
) );
422 pCollection
= &aCollection
;
423 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
424 pDocumentTypes
= pCollection
;
428 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
432 return (*pCollection
).getTypes();
437 // XServiceInfo methods.
442 OUString SAL_CALL
Content::getImplementationName()
443 throw( uno::RuntimeException
)
445 return OUString( "com.sun.star.comp.ucb.WebDAVContent" );
450 uno::Sequence
< OUString
> SAL_CALL
Content::getSupportedServiceNames()
451 throw( uno::RuntimeException
)
453 uno::Sequence
< OUString
> aSNS( 1 );
454 aSNS
.getArray()[ 0 ] = WEBDAV_CONTENT_SERVICE_NAME
;
465 OUString SAL_CALL
Content::getContentType()
466 throw( uno::RuntimeException
)
468 bool bFolder
= false;
472 = isFolder( uno::Reference
< ucb::XCommandEnvironment
>() );
474 catch ( uno::RuntimeException
const & )
478 catch ( uno::Exception
const & )
483 return OUString( WEBDAV_COLLECTION_TYPE
);
485 return OUString( WEBDAV_CONTENT_TYPE
);
490 // XCommandProcessor methods.
495 uno::Any SAL_CALL
Content::execute(
496 const ucb::Command
& aCommand
,
497 sal_Int32
/*CommandId*/,
498 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
499 throw( uno::Exception
,
500 ucb::CommandAbortedException
,
501 uno::RuntimeException
)
503 SAL_INFO("ucb.ucp.webdav", ">>>>> Content::execute: start: command: " << aCommand
.Name
504 << ", env: " << (Environment
.is() ? "present" : "missing") );
508 if ( aCommand
.Name
== "getPropertyValues" )
514 uno::Sequence
< beans::Property
> Properties
;
515 if ( !( aCommand
.Argument
>>= Properties
) )
517 ucbhelper::cancelCommandExecution(
518 uno::makeAny( lang::IllegalArgumentException(
519 OUString( "Wrong argument type!" ),
520 static_cast< cppu::OWeakObject
* >( this ),
526 aRet
<<= getPropertyValues( Properties
, Environment
);
528 else if ( aCommand
.Name
== "setPropertyValues" )
534 uno::Sequence
< beans::PropertyValue
> aProperties
;
535 if ( !( aCommand
.Argument
>>= aProperties
) )
537 ucbhelper::cancelCommandExecution(
538 uno::makeAny( lang::IllegalArgumentException(
539 OUString( "Wrong argument type!" ),
540 static_cast< cppu::OWeakObject
* >( this ),
546 if ( !aProperties
.getLength() )
548 ucbhelper::cancelCommandExecution(
549 uno::makeAny( lang::IllegalArgumentException(
550 OUString( "No properties!" ),
551 static_cast< cppu::OWeakObject
* >( this ),
557 aRet
<<= setPropertyValues( aProperties
, Environment
);
559 else if ( aCommand
.Name
== "getPropertySetInfo" )
562 // getPropertySetInfo
565 // Note: Implemented by base class.
566 aRet
<<= getPropertySetInfo( Environment
,
567 false /* don't cache data */ );
569 else if ( aCommand
.Name
== "getCommandInfo" )
575 // Note: Implemented by base class.
576 aRet
<<= getCommandInfo( Environment
, false );
578 else if ( aCommand
.Name
== "open" )
584 ucb::OpenCommandArgument2 aOpenCommand
;
585 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
587 ucbhelper::cancelCommandExecution(
588 uno::makeAny( lang::IllegalArgumentException(
589 OUString( "Wrong argument type!" ),
590 static_cast< cppu::OWeakObject
* >( this ),
596 aRet
= open( aOpenCommand
, Environment
);
598 if ( (aOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT
||
599 aOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
) &&
600 supportsExclusiveWriteLock( Environment
) )
603 else if ( aCommand
.Name
== "insert" )
609 ucb::InsertCommandArgument arg
;
610 if ( !( aCommand
.Argument
>>= arg
) )
612 ucbhelper::cancelCommandExecution(
613 uno::makeAny( lang::IllegalArgumentException(
614 OUString( "Wrong argument type!" ),
615 static_cast< cppu::OWeakObject
* >( this ),
621 insert( arg
.Data
, arg
.ReplaceExisting
, Environment
);
623 else if ( aCommand
.Name
== "delete" )
629 bool bDeletePhysical
= false;
630 aCommand
.Argument
>>= bDeletePhysical
;
632 // KSO: Ignore parameter and destroy the content, if you don't support
633 // putting objects into trashcan. ( Since we do not have a trash can
634 // service yet (src603), you actually have no other choice. )
635 // if ( bDeletePhysical )
639 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
641 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
642 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
644 xResAccess
->DESTROY( Environment
);
646 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
647 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
650 catch ( DAVException
const & e
)
652 cancelCommandExecution( e
, Environment
, true );
657 // Propagate destruction.
658 destroy( bDeletePhysical
);
660 // Remove own and all children's Additional Core Properties.
661 removeAdditionalPropertySet( true );
663 else if ( aCommand
.Name
== "transfer" && isFolder( Environment
) )
667 // ( Not available at documents )
670 ucb::TransferInfo transferArgs
;
671 if ( !( aCommand
.Argument
>>= transferArgs
) )
673 ucbhelper::cancelCommandExecution(
674 uno::makeAny( lang::IllegalArgumentException(
675 OUString( "Wrong argument type!" ),
676 static_cast< cppu::OWeakObject
* >( this ),
682 transfer( transferArgs
, Environment
);
684 else if ( aCommand
.Name
== "post" )
690 ucb::PostCommandArgument2 aArg
;
691 if ( !( aCommand
.Argument
>>= aArg
) )
693 ucbhelper::cancelCommandExecution(
694 uno::makeAny( lang::IllegalArgumentException(
695 OUString( "Wrong argument type!" ),
696 static_cast< cppu::OWeakObject
* >( this ),
702 post( aArg
, Environment
);
704 else if ( aCommand
.Name
== "lock" &&
705 supportsExclusiveWriteLock( Environment
) )
713 else if ( aCommand
.Name
== "unlock" &&
714 supportsExclusiveWriteLock( Environment
) )
720 unlock( Environment
);
722 else if ( aCommand
.Name
== "createNewContent" &&
723 isFolder( Environment
) )
729 ucb::ContentInfo aArg
;
730 if ( !( aCommand
.Argument
>>= aArg
) )
732 ucbhelper::cancelCommandExecution(
733 uno::makeAny( lang::IllegalArgumentException(
734 OUString( "Wrong argument type!" ),
735 static_cast< cppu::OWeakObject
* >( this ),
741 aRet
= uno::makeAny( createNewContent( aArg
) );
743 else if ( aCommand
.Name
== "addProperty" )
745 ucb::PropertyCommandArgument aPropArg
;
746 if ( !( aCommand
.Argument
>>= aPropArg
))
748 ucbhelper::cancelCommandExecution(
749 uno::makeAny( lang::IllegalArgumentException(
750 OUString( "Wrong argument type!" ),
751 static_cast< cppu::OWeakObject
* >( this ),
756 // TODO when/if XPropertyContainer is removed,
757 // the command execution can be canceled in addProperty
760 addProperty( aPropArg
, Environment
);
762 catch ( const beans::PropertyExistException
&e
)
764 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
766 catch ( const beans::IllegalTypeException
&e
)
768 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
770 catch ( const lang::IllegalArgumentException
&e
)
772 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
775 else if ( aCommand
.Name
== "removeProperty" )
777 rtl::OUString sPropName
;
778 if ( !( aCommand
.Argument
>>= sPropName
) )
780 ucbhelper::cancelCommandExecution(
781 uno::makeAny( lang::IllegalArgumentException(
782 OUString( "Wrong argument type!" ),
783 static_cast< cppu::OWeakObject
* >( this ),
788 // TODO when/if XPropertyContainer is removed,
789 // the command execution can be canceled in removeProperty
792 removeProperty( sPropName
, Environment
);
794 catch( const beans::UnknownPropertyException
&e
)
796 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
798 catch( const beans::NotRemoveableException
&e
)
800 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
806 // Unsupported command
809 ucbhelper::cancelCommandExecution(
810 uno::makeAny( ucb::UnsupportedCommandException(
812 static_cast< cppu::OWeakObject
* >( this ) ) ),
817 SAL_INFO("ucb.ucp.webdav", "<<<<< Content::execute: end: command: " << aCommand
.Name
);
823 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ )
824 throw( uno::RuntimeException
)
828 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
830 osl::MutexGuard
aGuard( m_aMutex
);
831 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
835 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
836 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
839 catch ( DAVException
const & )
847 // XPropertyContainer methods.
851 void Content::addProperty( const com::sun::star::ucb::PropertyCommandArgument
&aCmdArg
,
852 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
853 throw( beans::PropertyExistException
,
854 beans::IllegalTypeException
,
855 lang::IllegalArgumentException
,
856 uno::RuntimeException
)
858 // if ( m_bTransient )
860 const beans::Property aProperty
= aCmdArg
.Property
;
861 const uno::Any aDefaultValue
= aCmdArg
.DefaultValue
;
863 // check property Name
864 if ( !aProperty
.Name
.getLength() )
865 throw lang::IllegalArgumentException(
866 OUString( "\"addProperty\" with empty Property.Name"),
867 static_cast< ::cppu::OWeakObject
* >( this ),
870 // Check property type.
871 if ( !UCBDeadPropertyValue::supportsType( aProperty
.Type
) )
872 throw beans::IllegalTypeException(
873 OUString( "\"addProperty\" unsupported Property.Type"),
874 static_cast< ::cppu::OWeakObject
* >( this ) );
876 // check default value
877 if ( aDefaultValue
.hasValue() && aDefaultValue
.getValueType() != aProperty
.Type
)
878 throw beans::IllegalTypeException(
879 OUString( "\"addProperty\" DefaultValue does not match Property.Type"),
880 static_cast< ::cppu::OWeakObject
* >( this ) );
883 // Make sure a property with the requested name does not already
884 // exist in dynamic and static(!) properties.
887 // Take into account special properties with custom namespace
888 // using <prop:the_propname xmlns:prop="the_namespace">
889 rtl::OUString aSpecialName
;
890 bool bIsSpecial
= DAVProperties::isUCBSpecialProperty( aProperty
.Name
, aSpecialName
);
892 // Note: This requires network access!
893 if ( getPropertySetInfo( xEnv
, false /* don't cache data */ )
894 ->hasPropertyByName( bIsSpecial
? aSpecialName
: aProperty
.Name
) )
896 // Property does already exist.
897 throw beans::PropertyExistException();
901 // Add a new dynamic property.
904 ProppatchValue
aValue( PROPSET
, aProperty
.Name
, aDefaultValue
);
906 std::vector
< ProppatchValue
> aProppatchValues
;
907 aProppatchValues
.push_back( aValue
);
911 // Set property value at server.
912 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
914 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
915 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
917 xResAccess
->PROPPATCH( aProppatchValues
, xEnv
);
919 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
920 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
923 // Notify propertyset info change listeners.
924 beans::PropertySetInfoChangeEvent
evt(
925 static_cast< cppu::OWeakObject
* >( this ),
926 bIsSpecial
? aSpecialName
: aProperty
.Name
,
927 -1, // No handle available
928 beans::PropertySetInfoChange::PROPERTY_INSERTED
);
929 notifyPropertySetInfoChange( evt
);
931 catch ( DAVException
const & e
)
933 if ( e
.getStatus() == SC_FORBIDDEN
)
935 // Support for setting arbitrary dead properties is optional!
937 // Store property locally.
938 ContentImplHelper::addProperty( bIsSpecial
? aSpecialName
: aProperty
.Name
,
939 aProperty
.Attributes
,
944 if ( shouldAccessNetworkAfterException( e
) )
948 const ResourceType
& rType
= getResourceType( xEnv
);
953 throw lang::IllegalArgumentException();
956 // Store property locally.
957 ContentImplHelper::addProperty( bIsSpecial
? aSpecialName
: aProperty
.Name
,
958 aProperty
.Attributes
,
963 SAL_WARN( "ucb.ucp.webdav",
964 "Content::addProperty - "
965 "Unsupported resource type!" );
969 catch ( uno::Exception
const & )
971 SAL_WARN( "ucb.ucp.webdav",
972 "Content::addProperty - "
973 "Unable to determine resource type!" );
978 SAL_WARN( "ucb.ucp.webdav",
979 "Content::addProperty - "
980 "Unable to determine resource type!" );
986 void Content::removeProperty( const rtl::OUString
& Name
,
987 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
988 throw( beans::UnknownPropertyException
,
989 beans::NotRemoveableException
,
990 uno::RuntimeException
)
993 // @@@ REMOVABLE at the moment not properly set in the PropSetInfo
996 beans::Property aProp
997 = getPropertySetInfo( xEnv
, false /* don't cache data */ )
998 ->getPropertyByName( Name
);
1000 if ( !( aProp
.Attributes
& beans::PropertyAttribute::REMOVABLE
) )
1003 throw beans::NotRemoveableException();
1006 catch ( beans::UnknownPropertyException
const & )
1008 //SAL_WARN( "ucb.ucp.webdav", "removeProperty - Unknown property!" );
1013 // Try to remove property from server.
1016 std::vector
< ProppatchValue
> aProppatchValues
;
1017 ProppatchValue
aValue( PROPREMOVE
, Name
, uno::Any() );
1018 aProppatchValues
.push_back( aValue
);
1020 // Remove property value from server.
1021 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
1023 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1024 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
1026 xResAccess
->PROPPATCH( aProppatchValues
, xEnv
);
1028 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1029 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
1032 // Notify propertyset info change listeners.
1033 beans::PropertySetInfoChangeEvent
evt(
1034 static_cast< cppu::OWeakObject
* >( this ),
1036 -1, // No handle available
1037 beans::PropertySetInfoChange::PROPERTY_REMOVED
);
1038 notifyPropertySetInfoChange( evt
);
1040 catch ( DAVException
const & e
)
1042 if ( e
.getStatus() == SC_FORBIDDEN
)
1044 // Support for setting arbitrary dead properties is optional!
1046 // Try to remove property from local store.
1047 ContentImplHelper::removeProperty( Name
);
1051 if ( shouldAccessNetworkAfterException( e
) )
1055 const ResourceType
& rType
= getResourceType( xEnv
);
1060 throw beans::UnknownPropertyException();
1063 // Try to remove property from local store.
1064 ContentImplHelper::removeProperty( Name
);
1068 SAL_WARN( "ucb.ucp.webdav",
1069 "Content::removeProperty - "
1070 "Unsupported resource type!" );
1074 catch ( uno::Exception
const & )
1076 SAL_WARN( "ucb.ucp.webdav",
1077 "Content::removeProperty - "
1078 "Unable to determine resource type!" );
1083 SAL_WARN( "ucb.ucp.webdav",
1084 "Content::removeProperty - "
1085 "Unable to determine resource type!" );
1086 // throw beans::UnknownPropertyException();
1093 void SAL_CALL
Content::addProperty( const rtl::OUString
& Name
,
1094 sal_Int16 Attributes
,
1095 const uno::Any
& DefaultValue
)
1096 throw( beans::PropertyExistException
,
1097 beans::IllegalTypeException
,
1098 lang::IllegalArgumentException
,
1099 uno::RuntimeException
)
1101 beans::Property aProperty
;
1102 aProperty
.Name
= Name
;
1103 aProperty
.Type
= DefaultValue
.getValueType();
1104 aProperty
.Attributes
= Attributes
;
1105 aProperty
.Handle
= -1;
1107 addProperty( ucb::PropertyCommandArgument( aProperty
, DefaultValue
),
1108 uno::Reference
< ucb::XCommandEnvironment
>());
1112 void SAL_CALL
Content::removeProperty( const rtl::OUString
& Name
)
1113 throw( beans::UnknownPropertyException
,
1114 beans::NotRemoveableException
,
1115 uno::RuntimeException
)
1117 removeProperty( Name
,
1118 uno::Reference
< ucb::XCommandEnvironment
>() );
1123 // XContentCreator methods.
1128 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
1129 Content::queryCreatableContentsInfo()
1130 throw( uno::RuntimeException
)
1132 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1134 uno::Sequence
< ucb::ContentInfo
> aSeq( 2 );
1137 aSeq
.getArray()[ 0 ].Type
= OUString( WEBDAV_CONTENT_TYPE
);
1138 aSeq
.getArray()[ 0 ].Attributes
1139 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
1140 | ucb::ContentInfoAttribute::KIND_DOCUMENT
;
1142 beans::Property aProp
;
1143 m_pProvider
->getProperty(
1144 OUString( "Title" ), aProp
);
1146 uno::Sequence
< beans::Property
> aDocProps( 1 );
1147 aDocProps
.getArray()[ 0 ] = aProp
;
1148 aSeq
.getArray()[ 0 ].Properties
= aDocProps
;
1151 aSeq
.getArray()[ 1 ].Type
= OUString( WEBDAV_COLLECTION_TYPE
);
1152 aSeq
.getArray()[ 1 ].Attributes
1153 = ucb::ContentInfoAttribute::KIND_FOLDER
;
1155 uno::Sequence
< beans::Property
> aFolderProps( 1 );
1156 aFolderProps
.getArray()[ 0 ] = aProp
;
1157 aSeq
.getArray()[ 1 ].Properties
= aFolderProps
;
1163 uno::Reference
< ucb::XContent
> SAL_CALL
1164 Content::createNewContent( const ucb::ContentInfo
& Info
)
1165 throw( uno::RuntimeException
)
1167 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1169 if ( !Info
.Type
.getLength() )
1170 return uno::Reference
< ucb::XContent
>();
1172 if ( ( Info
.Type
!= WEBDAV_COLLECTION_TYPE
)
1174 ( Info
.Type
!= WEBDAV_CONTENT_TYPE
) )
1175 return uno::Reference
< ucb::XContent
>();
1177 OUString aURL
= m_xIdentifier
->getContentIdentifier();
1179 SAL_WARN_IF( aURL
.isEmpty(), "ucb.ucp.webdav",
1180 "WebdavContent::createNewContent - empty identifier!" );
1182 if ( ( aURL
.lastIndexOf( '/' ) + 1 ) != aURL
.getLength() )
1186 if ( Info
.Type
== WEBDAV_COLLECTION_TYPE
)
1188 aURL
+= "New_Collection";
1189 isCollection
= true;
1193 aURL
+= "New_Content";
1194 isCollection
= false;
1197 uno::Reference
< ucb::XContentIdentifier
> xId(
1198 new ::ucbhelper::ContentIdentifier( aURL
) );
1200 // create the local content
1203 return new ::http_dav_ucp::Content( m_xContext
,
1206 m_xResAccess
->getSessionFactory(),
1209 catch ( ucb::ContentCreationException
& )
1211 return uno::Reference
< ucb::XContent
>();
1217 OUString
Content::getParentURL()
1219 // <scheme>:// -> ""
1220 // <scheme>://foo -> ""
1221 // <scheme>://foo/ -> ""
1222 // <scheme>://foo/bar -> <scheme>://foo/
1223 // <scheme>://foo/bar/ -> <scheme>://foo/
1224 // <scheme>://foo/bar/abc -> <scheme>://foo/bar/
1226 OUString aURL
= m_xIdentifier
->getContentIdentifier();
1228 sal_Int32 nPos
= aURL
.lastIndexOf( '/' );
1229 if ( nPos
== ( aURL
.getLength() - 1 ) )
1231 // Trailing slash found. Skip.
1232 nPos
= aURL
.lastIndexOf( '/', nPos
);
1235 sal_Int32 nPos1
= aURL
.lastIndexOf( '/', nPos
);
1237 nPos1
= aURL
.lastIndexOf( '/', nPos1
);
1242 return OUString( aURL
.copy( 0, nPos
+ 1 ) );
1247 // Non-interface methods.
1252 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
1253 const uno::Reference
< uno::XComponentContext
>& rxContext
,
1254 const uno::Sequence
< beans::Property
>& rProperties
,
1255 const ContentProperties
& rData
,
1256 const rtl::Reference
< ::ucbhelper::ContentProviderImplHelper
>& rProvider
,
1257 const OUString
& rContentId
)
1259 // Note: Empty sequence means "get values of all supported properties".
1261 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
1262 = new ::ucbhelper::PropertyValueSet( rxContext
);
1264 sal_Int32 nCount
= rProperties
.getLength();
1267 uno::Reference
< beans::XPropertySet
> xAdditionalPropSet
;
1268 bool bTriedToGetAdditionalPropSet
= false;
1270 const beans::Property
* pProps
= rProperties
.getConstArray();
1271 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1273 const beans::Property
& rProp
= pProps
[ n
];
1275 // Process standard UCB, DAV and HTTP properties.
1276 const uno::Any
& rValue
= rData
.getValue( rProp
.Name
);
1277 if ( rValue
.hasValue() )
1279 xRow
->appendObject( rProp
, rValue
);
1283 // Process local Additional Properties.
1284 if ( !bTriedToGetAdditionalPropSet
&& !xAdditionalPropSet
.is() )
1287 = uno::Reference
< beans::XPropertySet
>(
1288 rProvider
->getAdditionalPropertySet( rContentId
,
1291 bTriedToGetAdditionalPropSet
= true;
1294 if ( !xAdditionalPropSet
.is() ||
1295 !xRow
->appendPropertySetValue(
1296 xAdditionalPropSet
, rProp
) )
1298 // Append empty entry.
1299 xRow
->appendVoid( rProp
);
1306 // Append all standard UCB, DAV and HTTP properties.
1308 const boost::scoped_ptr
< PropertyValueMap
> & xProps
= rData
.getProperties();
1310 PropertyValueMap::const_iterator it
= xProps
->begin();
1311 PropertyValueMap::const_iterator end
= xProps
->end();
1313 ContentProvider
* pProvider
1314 = static_cast< ContentProvider
* >( rProvider
.get() );
1315 beans::Property aProp
;
1319 if ( pProvider
->getProperty( (*it
).first
, aProp
) )
1320 xRow
->appendObject( aProp
, (*it
).second
.value() );
1325 // Append all local Additional Properties.
1326 uno::Reference
< beans::XPropertySet
> xSet(
1327 rProvider
->getAdditionalPropertySet( rContentId
, false ),
1329 xRow
->appendPropertySet( xSet
);
1332 return uno::Reference
< sdbc::XRow
>( xRow
.get() );
1336 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
1337 const uno::Sequence
< beans::Property
>& rProperties
,
1338 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1339 throw ( uno::Exception
)
1341 boost::scoped_ptr
< ContentProperties
> xProps
;
1342 boost::scoped_ptr
< ContentProperties
> xCachedProps
;
1343 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
1344 OUString aUnescapedTitle
;
1345 bool bHasAll
= false;
1346 uno::Reference
< uno::XComponentContext
> xContext
;
1347 uno::Reference
< ucb::XContentIdentifier
> xIdentifier
;
1348 rtl::Reference
< ::ucbhelper::ContentProviderImplHelper
> xProvider
;
1351 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1353 aUnescapedTitle
= SerfUri::unescape( m_aEscapedTitle
);
1354 xContext
.set( m_xContext
);
1355 xIdentifier
.set( m_xIdentifier
);
1356 xProvider
.set( m_xProvider
.get() );
1357 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
1359 // First, ask cache...
1360 if ( m_xCachedProps
.get() )
1362 xCachedProps
.reset( new ContentProperties( *m_xCachedProps
.get() ) );
1364 std::vector
< OUString
> aMissingProps
;
1365 if ( xCachedProps
->containsAllNames( rProperties
, aMissingProps
) )
1367 // All properties are already in cache! No server access needed.
1371 // use the cached ContentProperties instance
1372 xProps
.reset( new ContentProperties( *xCachedProps
.get() ) );
1376 if ( !m_bTransient
&& !bHasAll
)
1378 // Obtain values from server...
1381 // First, identify whether resource is DAV or not
1382 bool bNetworkAccessAllowed
= true;
1383 const ResourceType
& rType
= getResourceType( xEnv
, xResAccess
, &bNetworkAccessAllowed
);
1387 // cache lookup... getResourceType may fill the props cache via
1389 if ( m_xCachedProps
.get() )
1392 new ContentProperties( *m_xCachedProps
.get() ) );
1394 std::vector
< OUString
> aMissingProps
;
1395 if ( xCachedProps
->containsAllNames(
1396 rProperties
, aMissingProps
) )
1398 // All properties are already in cache! No server access
1403 // use the cached ContentProperties instance
1404 xProps
.reset( new ContentProperties( *xCachedProps
.get() ) );
1409 // Only DAV resources support PROPFIND
1410 std::vector
< OUString
> aPropNames
;
1412 uno::Sequence
< beans::Property
> aProperties(
1413 rProperties
.getLength() );
1415 if ( !m_aFailedPropNames
.empty() )
1417 sal_Int32 nProps
= 0;
1418 sal_Int32 nCount
= rProperties
.getLength();
1419 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1421 const OUString
& rName
= rProperties
[ n
].Name
;
1423 std::vector
< OUString
>::const_iterator it
1424 = m_aFailedPropNames
.begin();
1425 std::vector
< OUString
>::const_iterator end
1426 = m_aFailedPropNames
.end();
1438 aProperties
[ nProps
] = rProperties
[ n
];
1443 aProperties
.realloc( nProps
);
1447 aProperties
= rProperties
;
1450 if ( aProperties
.getLength() > 0 )
1451 ContentProperties::UCBNamesToDAVNames(
1452 aProperties
, aPropNames
);
1454 if ( !aPropNames
.empty() )
1456 std::vector
< DAVResource
> resources
;
1459 xResAccess
->PROPFIND(
1460 DAVZERO
, aPropNames
, resources
, xEnv
);
1462 if ( 1 == resources
.size() )
1465 xProps
->addProperties(
1467 ContentProperties( resources
[ 0 ] ));
1470 new ContentProperties( resources
[ 0 ] ) );
1473 catch ( DAVException
const & e
)
1475 bNetworkAccessAllowed
= bNetworkAccessAllowed
&&
1476 shouldAccessNetworkAfterException( e
);
1478 if ( !bNetworkAccessAllowed
)
1480 cancelCommandExecution( e
, xEnv
);
1488 if ( bNetworkAccessAllowed
)
1490 // All properties obtained already?
1491 std::vector
< OUString
> aMissingProps
;
1492 if ( !( xProps
.get()
1493 && xProps
->containsAllNames(
1494 rProperties
, aMissingProps
) )
1495 || !m_bDidGetOrHead
)
1497 // Possibly the missing props can be obtained using a HEAD
1500 std::vector
< OUString
> aHeaderNames
;
1501 ContentProperties::UCBNamesToHTTPNames(
1504 true /* bIncludeUnmatched */ );
1506 if ( !aHeaderNames
.empty() )
1510 DAVResource resource
;
1511 xResAccess
->HEAD( aHeaderNames
, resource
, xEnv
);
1512 m_bDidGetOrHead
= true;
1515 xProps
->addProperties(
1517 ContentProperties( resource
) );
1519 xProps
.reset ( new ContentProperties( resource
) );
1521 if ( m_eResourceType
== NON_DAV
)
1522 xProps
->addProperties( aMissingProps
,
1527 catch ( DAVException
const & e
)
1529 // non "general-purpose servers" may not support HEAD requests
1530 // see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1
1531 // In this case, perform a partial GET only to get the header info
1532 // vid. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
1533 // WARNING if the server does not support partial GETs,
1534 // the GET will transfer the whole content
1536 DAVException aLastException
= e
;
1538 // According to the spec. the origin server SHOULD return
1539 // * 405 (Method Not Allowed):
1540 // the method is known but not allowed for the requested resource
1541 // * 501 (Not Implemented):
1542 // the method is unrecognized or not implemented
1543 // TODO SC_NOT_FOUND is only for google-code server
1544 if ( aLastException
.getStatus() == SC_NOT_IMPLEMENTED
||
1545 aLastException
.getStatus() == SC_METHOD_NOT_ALLOWED
||
1546 aLastException
.getStatus() == SC_NOT_FOUND
)
1548 lcl_sendPartialGETRequest( bError
,
1555 m_bDidGetOrHead
= !bError
;
1560 if ( !(bNetworkAccessAllowed
1561 = shouldAccessNetworkAfterException( aLastException
)) )
1563 cancelCommandExecution( aLastException
, xEnv
);
1572 // might trigger HTTP redirect.
1573 // Therefore, title must be updated here.
1574 SerfUri
aUri( xResAccess
->getURL() );
1575 aUnescapedTitle
= aUri
.GetPathBaseNameUnescaped();
1577 if ( rType
== UNKNOWN
)
1579 xProps
.reset( new ContentProperties( aUnescapedTitle
) );
1582 // For DAV resources we only know the Title, for non-DAV
1583 // resources we additionally know that it is a document.
1588 // new ContentProperties( aUnescapedTitle ) );
1589 xProps
->addProperty(
1590 OUString( "Title" ),
1591 uno::makeAny( aUnescapedTitle
),
1596 if ( !xProps
.get() )
1597 xProps
.reset( new ContentProperties( aUnescapedTitle
, false ) );
1599 xProps
->addProperty(
1600 OUString( "Title" ),
1601 uno::makeAny( aUnescapedTitle
),
1604 xProps
->addProperty(
1605 OUString( "IsFolder" ),
1606 uno::makeAny( false ),
1608 xProps
->addProperty(
1609 OUString( "IsDocument" ),
1610 uno::makeAny( true ),
1612 xProps
->addProperty(
1613 OUString( "ContentType" ),
1614 uno::makeAny( OUString(WEBDAV_CONTENT_TYPE
) ),
1620 // No server access for just created (not yet committed) objects.
1621 // Only a minimal set of properties supported at this stage.
1623 xProps
.reset( new ContentProperties( aUnescapedTitle
,
1627 sal_Int32 nCount
= rProperties
.getLength();
1628 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1630 const OUString rName
= rProperties
[ n
].Name
;
1631 if ( rName
== "BaseURI" )
1633 // Add BaseURI property, if requested.
1634 xProps
->addProperty(
1635 OUString( "BaseURI" ),
1636 uno::makeAny( getBaseURI( xResAccess
) ),
1639 else if ( rName
== "CreatableContentsInfo" )
1641 // Add CreatableContentsInfo property, if requested.
1642 bool bFolder
= false;
1644 OUString( "IsFolder" ) )
1646 xProps
->addProperty(
1647 OUString( "CreatableContentsInfo" ),
1648 uno::makeAny( bFolder
1649 ? queryCreatableContentsInfo()
1650 : uno::Sequence
< ucb::ContentInfo
>() ),
1655 uno::Reference
< sdbc::XRow
> xResultRow
1656 = getPropertyValues( xContext
,
1660 xIdentifier
->getContentIdentifier() );
1663 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1665 if ( !m_xCachedProps
.get() )
1666 m_xCachedProps
.reset( new CachableContentProperties( *xProps
.get() ) );
1668 m_xCachedProps
->addProperties( *xProps
.get() );
1670 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
1671 m_aEscapedTitle
= SerfUri::escapeSegment( aUnescapedTitle
);
1678 uno::Sequence
< uno::Any
> Content::setPropertyValues(
1679 const uno::Sequence
< beans::PropertyValue
>& rValues
,
1680 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1681 throw ( uno::Exception
)
1683 uno::Reference
< ucb::XContentIdentifier
> xIdentifier
;
1684 rtl::Reference
< ContentProvider
> xProvider
;
1686 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
1689 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1691 xProvider
.set( m_pProvider
);
1692 xIdentifier
.set( m_xIdentifier
);
1693 bTransient
= m_bTransient
;
1694 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
1697 uno::Sequence
< uno::Any
> aRet( rValues
.getLength() );
1698 uno::Sequence
< beans::PropertyChangeEvent
> aChanges( rValues
.getLength() );
1699 sal_Int32 nChanged
= 0;
1701 beans::PropertyChangeEvent aEvent
;
1702 aEvent
.Source
= static_cast< cppu::OWeakObject
* >( this );
1703 aEvent
.Further
= false;
1704 // aEvent.PropertyName =
1705 aEvent
.PropertyHandle
= -1;
1706 // aEvent.OldValue =
1707 // aEvent.NewValue =
1709 std::vector
< ProppatchValue
> aProppatchValues
;
1710 std::vector
< sal_Int32
> aProppatchPropsPositions
;
1712 uno::Reference
< ucb::XPersistentPropertySet
> xAdditionalPropSet
;
1713 bool bTriedToGetAdditionalPropSet
= false;
1715 bool bExchange
= false;
1718 sal_Int32 nTitlePos
= -1;
1720 uno::Reference
< beans::XPropertySetInfo
> xInfo
;
1722 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
1723 sal_Int32 nCount
= rValues
.getLength();
1724 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1726 const beans::PropertyValue
& rValue
= pValues
[ n
];
1727 const OUString
& rName
= rValue
.Name
;
1729 beans::Property aTmpProp
;
1730 xProvider
->getProperty( rName
, aTmpProp
);
1732 if ( aTmpProp
.Attributes
& beans::PropertyAttribute::READONLY
)
1734 // Read-only property!
1735 aRet
[ n
] <<= lang::IllegalAccessException(
1736 OUString( "Property is read-only!" ),
1737 static_cast< cppu::OWeakObject
* >( this ) );
1745 if ( rName
== "ContentType" )
1747 // Read-only property!
1748 aRet
[ n
] <<= lang::IllegalAccessException(
1749 OUString( "Property is read-only!" ),
1750 static_cast< cppu::OWeakObject
* >( this ) );
1752 else if ( rName
== "IsDocument" )
1754 // Read-only property!
1755 aRet
[ n
] <<= lang::IllegalAccessException(
1756 OUString( "Property is read-only!" ),
1757 static_cast< cppu::OWeakObject
* >( this ) );
1759 else if ( rName
== "IsFolder" )
1761 // Read-only property!
1762 aRet
[ n
] <<= lang::IllegalAccessException(
1763 OUString( "Property is read-only!" ),
1764 static_cast< cppu::OWeakObject
* >( this ) );
1766 else if ( rName
== "Title" )
1769 if ( rValue
.Value
>>= aNewValue
)
1772 if ( aNewValue
.getLength() > 0 )
1776 SerfUri
aURI( xIdentifier
->getContentIdentifier() );
1777 aOldTitle
= aURI
.GetPathBaseNameUnescaped();
1779 if ( aNewValue
!= aOldTitle
)
1781 // modified title -> modified URL -> exchange !
1785 // new value will be set later...
1786 aNewTitle
= aNewValue
;
1788 // remember position within sequence of values (for
1793 catch ( DAVException
const & )
1795 aRet
[ n
] <<= lang::IllegalArgumentException(
1796 OUString( "Invalid content identifier!" ),
1797 static_cast< cppu::OWeakObject
* >( this ),
1803 aRet
[ n
] <<= lang::IllegalArgumentException(
1804 OUString( "Empty title not allowed!" ),
1805 static_cast< cppu::OWeakObject
* >( this ),
1811 aRet
[ n
] <<= beans::IllegalTypeException(
1812 OUString( "Property value has wrong type!" ),
1813 static_cast< cppu::OWeakObject
* >( this ) );
1822 rtl::OUString aSpecialName
;
1823 bool bIsSpecial
= DAVProperties::isUCBSpecialProperty( rName
, aSpecialName
);
1826 xInfo
= getPropertySetInfo( xEnv
,
1827 false /* don't cache data */ );
1829 if ( !xInfo
->hasPropertyByName( bIsSpecial
? aSpecialName
: rName
) )
1831 // Check, whether property exists. Skip otherwise.
1832 // PROPPATCH::set would add the property automatically, which
1833 // is not allowed for "setPropertyValues" command!
1834 aRet
[ n
] <<= beans::UnknownPropertyException(
1835 OUString( "Property is unknown!" ),
1836 static_cast< cppu::OWeakObject
* >( this ) );
1840 if ( rName
== "Size" )
1842 // Read-only property!
1843 aRet
[ n
] <<= lang::IllegalAccessException(
1844 OUString( "Property is read-only!" ),
1845 static_cast< cppu::OWeakObject
* >( this ) );
1847 else if ( rName
== "DateCreated" )
1849 // Read-only property!
1850 aRet
[ n
] <<= lang::IllegalAccessException(
1851 OUString( "Property is read-only!" ),
1852 static_cast< cppu::OWeakObject
* >( this ) );
1854 else if ( rName
== "DateModified" )
1856 // Read-only property!
1857 aRet
[ n
] <<= lang::IllegalAccessException(
1858 OUString( "Property is read-only!" ),
1859 static_cast< cppu::OWeakObject
* >( this ) );
1861 else if ( rName
== "MediaType" )
1863 // Read-only property!
1864 // (but could be writable, if 'getcontenttype' would be)
1865 aRet
[ n
] <<= lang::IllegalAccessException(
1866 OUString( "Property is read-only!" ),
1867 static_cast< cppu::OWeakObject
* >( this ) );
1869 if ( rName
== "CreatableContentsInfo" )
1871 // Read-only property!
1872 aRet
[ n
] <<= lang::IllegalAccessException(
1873 OUString( "Property is read-only!" ),
1874 static_cast< cppu::OWeakObject
* >( this ) );
1878 if ( getResourceType( xEnv
, xResAccess
) == DAV
)
1880 // Property value will be set on server.
1881 ProppatchValue
aValue( PROPSET
, rName
, rValue
.Value
);
1882 aProppatchValues
.push_back( aValue
);
1884 // remember position within sequence of values (for
1886 aProppatchPropsPositions
.push_back( n
);
1890 // Property value will be stored in local property store.
1891 if ( !bTriedToGetAdditionalPropSet
&&
1892 !xAdditionalPropSet
.is() )
1895 = getAdditionalPropertySet( false );
1896 bTriedToGetAdditionalPropSet
= true;
1899 if ( xAdditionalPropSet
.is() )
1904 = xAdditionalPropSet
->getPropertyValue( rName
);
1905 if ( aOldValue
!= rValue
.Value
)
1907 xAdditionalPropSet
->setPropertyValue(
1908 rName
, rValue
.Value
);
1910 aEvent
.PropertyName
= rName
;
1911 aEvent
.OldValue
= aOldValue
;
1912 aEvent
.NewValue
= rValue
.Value
;
1914 aChanges
.getArray()[ nChanged
] = aEvent
;
1918 catch ( beans::UnknownPropertyException
const & e
)
1922 catch ( lang::WrappedTargetException
const & e
)
1926 catch ( beans::PropertyVetoException
const & e
)
1930 catch ( lang::IllegalArgumentException
const & e
)
1937 aRet
[ n
] <<= uno::Exception(
1938 OUString( "No property set for storing the value!" ),
1939 static_cast< cppu::OWeakObject
* >( this ) );
1946 if ( !bTransient
&& (!aProppatchValues
.empty()) )
1950 // Set property values at server.
1951 xResAccess
->PROPPATCH( aProppatchValues
, xEnv
);
1953 std::vector
< ProppatchValue
>::const_iterator it
1954 = aProppatchValues
.begin();
1955 std::vector
< ProppatchValue
>::const_iterator end
1956 = aProppatchValues
.end();
1960 aEvent
.PropertyName
= (*it
).name
;
1961 aEvent
.OldValue
= uno::Any(); // @@@ to expensive to obtain!
1962 aEvent
.NewValue
= (*it
).value
;
1964 aChanges
.getArray()[ nChanged
] = aEvent
;
1970 catch ( DAVException
const & e
)
1972 // SAL_WARN( "ucb.ucp.webdav",
1973 // "Content::setPropertyValues - PROPPATCH failed!" );
1976 cancelCommandExecution( e
, xEnv
);
1979 // Note: PROPPATCH either sets ALL property values OR NOTHING.
1981 std::vector
< sal_Int32
>::const_iterator it
1982 = aProppatchPropsPositions
.begin();
1983 std::vector
< sal_Int32
>::const_iterator end
1984 = aProppatchPropsPositions
.end();
1989 aRet
[ (*it
) ] <<= MapDAVException( e
, true );
1998 // Assemble new content identifier...
2000 OUString aNewURL
= getParentURL();
2001 if ( aNewURL
.lastIndexOf( '/' ) != ( aNewURL
.getLength() - 1 ) )
2004 aNewURL
+= SerfUri::escapeSegment( aNewTitle
);
2006 uno::Reference
< ucb::XContentIdentifier
> xNewId
2007 = new ::ucbhelper::ContentIdentifier( aNewURL
);
2008 uno::Reference
< ucb::XContentIdentifier
> xOldId
= xIdentifier
;
2012 SerfUri
sourceURI( xOldId
->getContentIdentifier() );
2013 SerfUri
targetURI( xNewId
->getContentIdentifier() );
2014 targetURI
.SetScheme( sourceURI
.GetScheme() );
2017 sourceURI
.GetPath(), targetURI
.GetURI(), false, xEnv
);
2018 // @@@ Should check for resources that could not be moved
2019 // (due to source access or target overwrite) and send
2020 // this information through the interaction handler.
2022 // @@@ Existing content should be checked to see if it needs
2023 // to be deleted at the source
2025 // @@@ Existing content should be checked to see if it has
2026 // been overwritten at the target
2028 if ( exchangeIdentity( xNewId
) )
2030 xResAccess
->setURL( aNewURL
);
2032 // DAV resources store all additional props on server!
2033 // // Adapt Additional Core Properties.
2034 // renameAdditionalPropertySet( xOldId->getContentIdentifier(),
2035 // xNewId->getContentIdentifier(),
2040 // Do not set new title!
2044 aRet
[ nTitlePos
] <<= uno::Exception(
2045 OUString( "Exchange failed!" ),
2046 static_cast< cppu::OWeakObject
* >( this ) );
2049 catch ( DAVException
const & e
)
2051 // Do not set new title!
2055 aRet
[ nTitlePos
] <<= MapDAVException( e
, true );
2059 if ( aNewTitle
.getLength() )
2061 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2063 aEvent
.PropertyName
= "Title";
2064 aEvent
.OldValue
= uno::makeAny( aOldTitle
);
2065 aEvent
.NewValue
= uno::makeAny( aNewTitle
);
2067 m_aEscapedTitle
= SerfUri::escapeSegment( aNewTitle
);
2069 aChanges
.getArray()[ nChanged
] = aEvent
;
2075 aChanges
.realloc( nChanged
);
2076 notifyPropertiesChange( aChanges
);
2080 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2081 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
2088 uno::Any
Content::open(
2089 const ucb::OpenCommandArgument2
& rArg
,
2090 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
2091 throw( uno::Exception
)
2095 bool bOpenFolder
= ( ( rArg
.Mode
== ucb::OpenMode::ALL
) ||
2096 ( rArg
.Mode
== ucb::OpenMode::FOLDERS
) ||
2097 ( rArg
.Mode
== ucb::OpenMode::DOCUMENTS
) );
2100 if ( isFolder( xEnv
) )
2104 uno::Reference
< ucb::XDynamicResultSet
> xSet
2105 = new DynamicResultSet( m_xContext
, this, rArg
, xEnv
);
2110 // Error: Not a folder!
2112 OUStringBuffer aMsg
;
2113 aMsg
.appendAscii( "Non-folder resource cannot be "
2114 "opened as folder! Wrong Open Mode!" );
2116 ucbhelper::cancelCommandExecution(
2118 lang::IllegalArgumentException(
2119 aMsg
.makeStringAndClear(),
2120 static_cast< cppu::OWeakObject
* >( this ),
2127 if ( rArg
.Sink
.is() )
2131 if ( ( rArg
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
2132 ( rArg
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
) )
2134 // Currently(?) unsupported.
2135 ucbhelper::cancelCommandExecution(
2137 ucb::UnsupportedOpenModeException(
2139 static_cast< cppu::OWeakObject
* >( this ),
2140 sal_Int16( rArg
.Mode
) ) ),
2145 uno::Reference
< io::XOutputStream
> xOut
2146 = uno::Reference
< io::XOutputStream
>( rArg
.Sink
, uno::UNO_QUERY
);
2152 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
2155 osl::MutexGuard
aGuard( m_aMutex
);
2158 new DAVResourceAccess( *m_xResAccess
.get() ) );
2161 DAVResource aResource
;
2162 std::vector
< OUString
> aHeaders
;
2164 xResAccess
->GET( xOut
, aHeaders
, aResource
, xEnv
);
2165 m_bDidGetOrHead
= true;
2168 osl::MutexGuard
aGuard( m_aMutex
);
2171 if ( !m_xCachedProps
.get())
2172 m_xCachedProps
.reset(
2173 new CachableContentProperties( aResource
) );
2175 m_xCachedProps
->addProperties( aResource
);
2178 new DAVResourceAccess( *xResAccess
.get() ) );
2181 catch ( DAVException
const & e
)
2183 cancelCommandExecution( e
, xEnv
);
2189 uno::Reference
< io::XActiveDataSink
> xDataSink
2190 = uno::Reference
< io::XActiveDataSink
>( rArg
.Sink
,
2192 if ( xDataSink
.is() )
2194 // PULL: wait for client read
2197 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
2199 osl::MutexGuard
aGuard( m_aMutex
);
2202 new DAVResourceAccess( *m_xResAccess
.get() ) );
2205 // fill inputsream sync; return if all data present
2206 DAVResource aResource
;
2207 std::vector
< OUString
> aHeaders
;
2209 uno::Reference
< io::XInputStream
> xIn
2210 = xResAccess
->GET( aHeaders
, aResource
, xEnv
);
2211 m_bDidGetOrHead
= true;
2214 osl::MutexGuard
aGuard( m_aMutex
);
2217 if ( !m_xCachedProps
.get())
2218 m_xCachedProps
.reset(
2219 new CachableContentProperties( aResource
) );
2221 m_xCachedProps
->addProperties(
2222 aResource
.properties
);
2225 new DAVResourceAccess( *xResAccess
.get() ) );
2228 xDataSink
->setInputStream( xIn
);
2230 catch ( DAVException
const & e
)
2232 cancelCommandExecution( e
, xEnv
);
2238 // Note: aOpenCommand.Sink may contain an XStream
2239 // implementation. Support for this type of
2240 // sink is optional...
2241 ucbhelper::cancelCommandExecution(
2243 ucb::UnsupportedDataSinkException(
2245 static_cast< cppu::OWeakObject
* >( this ),
2258 const ucb::PostCommandArgument2
& rArg
,
2259 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
2260 throw( uno::Exception
)
2262 uno::Reference
< io::XActiveDataSink
> xSink( rArg
.Sink
, uno::UNO_QUERY
);
2267 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
2269 osl::MutexGuard
aGuard( m_aMutex
);
2271 new DAVResourceAccess( *m_xResAccess
.get() ) );
2274 uno::Reference
< io::XInputStream
> xResult
2275 = xResAccess
->POST( rArg
.MediaType
,
2281 osl::MutexGuard
aGuard( m_aMutex
);
2283 new DAVResourceAccess( *xResAccess
.get() ) );
2286 xSink
->setInputStream( xResult
);
2288 catch ( DAVException
const & e
)
2290 cancelCommandExecution( e
, xEnv
, true );
2296 uno::Reference
< io::XOutputStream
> xResult( rArg
.Sink
, uno::UNO_QUERY
);
2301 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
2303 osl::MutexGuard
aGuard( m_aMutex
);
2305 new DAVResourceAccess( *m_xResAccess
.get() ) );
2308 xResAccess
->POST( rArg
.MediaType
,
2315 osl::MutexGuard
aGuard( m_aMutex
);
2317 new DAVResourceAccess( *xResAccess
.get() ) );
2320 catch ( DAVException
const & e
)
2322 cancelCommandExecution( e
, xEnv
, true );
2328 ucbhelper::cancelCommandExecution(
2330 ucb::UnsupportedDataSinkException(
2332 static_cast< cppu::OWeakObject
* >( this ),
2341 void Content::queryChildren( ContentRefList
& rChildren
)
2343 // Obtain a list with a snapshot of all currently instantiated contents
2344 // from provider and extract the contents which are direct children
2347 ::ucbhelper::ContentRefList aAllContents
;
2348 m_xProvider
->queryExistingContents( aAllContents
);
2350 OUString aURL
= m_xIdentifier
->getContentIdentifier();
2351 sal_Int32 nURLPos
= aURL
.lastIndexOf( '/' );
2353 if ( nURLPos
!= ( aURL
.getLength() - 1 ) )
2355 // No trailing slash found. Append.
2359 sal_Int32 nLen
= aURL
.getLength();
2361 ::ucbhelper::ContentRefList::const_iterator it
= aAllContents
.begin();
2362 ::ucbhelper::ContentRefList::const_iterator end
= aAllContents
.end();
2366 ::ucbhelper::ContentImplHelperRef xChild
= (*it
);
2368 = xChild
->getIdentifier()->getContentIdentifier();
2370 // Is aURL a prefix of aChildURL?
2371 if ( ( aChildURL
.getLength() > nLen
) &&
2372 ( aChildURL
.startsWith( aURL
) ) )
2374 sal_Int32 nPos
= nLen
;
2375 nPos
= aChildURL
.indexOf( '/', nPos
);
2377 if ( ( nPos
== -1 ) ||
2378 ( nPos
== ( aChildURL
.getLength() - 1 ) ) )
2380 // No further slashes / only a final slash. It's a child!
2381 rChildren
.push_back(
2382 ::http_dav_ucp::Content::ContentRef(
2383 static_cast< ::http_dav_ucp::Content
* >(
2392 void Content::insert(
2393 const uno::Reference
< io::XInputStream
> & xInputStream
,
2394 bool bReplaceExisting
,
2395 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2396 throw( uno::Exception
)
2398 bool bTransient
, bCollection
;
2399 OUString aEscapedTitle
;
2400 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
2403 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2405 bTransient
= m_bTransient
;
2406 bCollection
= m_bCollection
;
2407 aEscapedTitle
= m_aEscapedTitle
;
2408 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
2411 // Check, if all required properties are present.
2413 if ( aEscapedTitle
.isEmpty() )
2415 SAL_WARN( "ucb.ucp.webdav", "Content::insert - Title missing!" );
2417 uno::Sequence
< OUString
> aProps( 1 );
2418 aProps
[ 0 ] = "Title";
2419 ucbhelper::cancelCommandExecution(
2420 uno::makeAny( ucb::MissingPropertiesException(
2422 static_cast< cppu::OWeakObject
* >( this ),
2428 if ( !bReplaceExisting
)
2430 /* [RFC 2616] - HTTP
2432 The PUT method requests that the enclosed entity be stored under the
2433 supplied Request-URI. If the Request-URI refers to an already
2434 existing resource, the enclosed entity SHOULD be considered as a
2435 modified version of the one residing on the origin server.
2438 /* [RFC 2518] - WebDAV
2440 MKCOL creates a new collection resource at the location specified by
2441 the Request-URI. If the resource identified by the Request-URI is
2442 non-null then the MKCOL MUST fail.
2445 // ==> Complain on PUT, continue on MKCOL.
2446 if ( !bTransient
|| ( bTransient
&& !bCollection
) )
2449 ucb::UnsupportedNameClashException
aEx(
2450 OUString( "Unable to write without overwrite!" ),
2451 static_cast< cppu::OWeakObject
* >( this ),
2452 ucb::NameClash::ERROR
);
2454 uno::Reference
< task::XInteractionHandler
> xIH
;
2456 if ( Environment
.is() )
2457 xIH
= Environment
->getInteractionHandler();
2461 uno::Any
aExAsAny( uno::makeAny( aEx
) );
2463 rtl::Reference
< ucbhelper::SimpleInteractionRequest
> xRequest
2464 = new ucbhelper::SimpleInteractionRequest(
2466 ucbhelper::CONTINUATION_APPROVE
2467 | ucbhelper::CONTINUATION_DISAPPROVE
);
2468 xIH
->handle( xRequest
.get() );
2470 const sal_Int32 nResp
= xRequest
->getResponse();
2474 case ucbhelper::CONTINUATION_UNKNOWN
:
2475 // Not handled; throw.
2479 case ucbhelper::CONTINUATION_APPROVE
:
2480 // Continue -> Overwrite.
2481 bReplaceExisting
= true;
2484 case ucbhelper::CONTINUATION_DISAPPROVE
:
2486 throw ucb::CommandFailedException(
2488 uno::Reference
< uno::XInterface
>(),
2493 SAL_WARN( "ucb.ucp.webdav",
2494 "Content::insert - "
2495 "Unknown interaction selection!" );
2496 throw ucb::CommandFailedException(
2497 OUString( "Unknown interaction selection!" ),
2498 uno::Reference
< uno::XInterface
>(),
2513 // Assemble new content identifier...
2514 OUString aURL
= getParentURL();
2515 if ( aURL
.lastIndexOf( '/' ) != ( aURL
.getLength() - 1 ) )
2518 aURL
+= aEscapedTitle
;
2522 xResAccess
->setURL( aURL
);
2525 xResAccess
->MKCOL( Environment
);
2527 xResAccess
->PUT( xInputStream
, Environment
);
2529 catch ( DAVException
const & except
)
2533 if ( except
.getStatus() == SC_METHOD_NOT_ALLOWED
)
2535 // [RFC 2518] - WebDAV
2536 // 405 (Method Not Allowed) - MKCOL can only be
2537 // executed on a deleted/non-existent resource.
2539 if ( bReplaceExisting
)
2541 // Destroy old resource.
2544 xResAccess
->DESTROY( Environment
);
2546 catch ( DAVException
const & e
)
2548 cancelCommandExecution( e
, Environment
, true );
2552 // Insert (recursion!).
2553 insert( xInputStream
, bReplaceExisting
, Environment
);
2556 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2558 new DAVResourceAccess( *xResAccess
.get() ) );
2569 SerfUri
aURI( aURL
);
2570 aTitle
= aURI
.GetPathBaseNameUnescaped();
2572 catch ( DAVException
const & )
2576 ucbhelper::cancelCommandExecution(
2578 ucb::NameClashException(
2580 static_cast< cppu::OWeakObject
* >( this ),
2581 task::InteractionClassification_ERROR
,
2589 cancelCommandExecution( except
, Environment
, true );
2594 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2596 = new ::ucbhelper::ContentIdentifier( aURL
);
2602 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2603 m_bTransient
= false;
2608 if ( !xInputStream
.is() )
2610 ucbhelper::cancelCommandExecution(
2612 ucb::MissingInputStreamException(
2614 static_cast< cppu::OWeakObject
* >( this ) ) ),
2621 xResAccess
->PUT( xInputStream
, Environment
);
2623 catch ( DAVException
const & e
)
2625 cancelCommandExecution( e
, Environment
, true );
2631 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2632 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
2637 void Content::transfer(
2638 const ucb::TransferInfo
& rArgs
,
2639 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2640 throw( uno::Exception
)
2642 uno::Reference
< uno::XComponentContext
> xContext
;
2643 uno::Reference
< ucb::XContentIdentifier
> xIdentifier
;
2644 uno::Reference
< ucb::XContentProvider
> xProvider
;
2645 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
2648 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2650 xContext
.set( m_xContext
);
2651 xIdentifier
.set( m_xIdentifier
);
2652 xProvider
.set( m_xProvider
.get() );
2653 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
2656 OUString aTargetURI
;
2659 SerfUri
sourceURI( rArgs
.SourceURL
);
2660 SerfUri
targetURI( xIdentifier
->getContentIdentifier() );
2661 aTargetURI
= targetURI
.GetPathBaseNameUnescaped();
2663 // Check source's and target's URL scheme
2665 const OUString aScheme
= sourceURI
.GetScheme().toAsciiLowerCase();
2666 if ( aScheme
== WEBDAV_URL_SCHEME
)
2668 sourceURI
.SetScheme(
2669 OUString( HTTP_URL_SCHEME
) );
2671 else if ( aScheme
== DAV_URL_SCHEME
)
2673 sourceURI
.SetScheme(
2674 OUString( HTTP_URL_SCHEME
) );
2676 else if ( aScheme
== DAVS_URL_SCHEME
)
2678 sourceURI
.SetScheme(
2679 OUString( HTTPS_URL_SCHEME
) );
2683 if ( aScheme
!= HTTP_URL_SCHEME
&& aScheme
!= HTTPS_URL_SCHEME
)
2685 ucbhelper::cancelCommandExecution(
2687 ucb::InteractiveBadTransferURLException(
2688 OUString( "Unsupported URL scheme!" ),
2689 static_cast< cppu::OWeakObject
* >( this ) ) ),
2695 if ( targetURI
.GetScheme().toAsciiLowerCase() == WEBDAV_URL_SCHEME
)
2696 targetURI
.SetScheme(
2697 OUString( HTTP_URL_SCHEME
) );
2698 else if ( targetURI
.GetScheme().toAsciiLowerCase() == DAV_URL_SCHEME
)
2699 targetURI
.SetScheme(
2700 OUString( HTTP_URL_SCHEME
) );
2702 // @@@ This implementation of 'transfer' only works
2703 // if the source and target are located at same host.
2704 // (Neon does not support cross-server copy/move)
2706 // Check for same host
2708 if ( sourceURI
.GetHost().getLength() &&
2709 ( sourceURI
.GetHost() != targetURI
.GetHost() ) )
2711 ucbhelper::cancelCommandExecution(
2712 uno::makeAny( ucb::InteractiveBadTransferURLException(
2713 OUString( "Different hosts!" ),
2714 static_cast< cppu::OWeakObject
* >( this ) ) ),
2719 OUString aTitle
= rArgs
.NewTitle
;
2721 if ( aTitle
.isEmpty() )
2722 aTitle
= sourceURI
.GetPathBaseNameUnescaped();
2724 if ( aTitle
== "/" )
2730 targetURI
.AppendPath( aTitle
);
2732 OUString aTargetURL
= xIdentifier
->getContentIdentifier();
2733 if ( ( aTargetURL
.lastIndexOf( '/' ) + 1 )
2734 != aTargetURL
.getLength() )
2737 aTargetURL
+= aTitle
;
2739 uno::Reference
< ucb::XContentIdentifier
> xTargetId
2740 = new ::ucbhelper::ContentIdentifier( aTargetURL
);
2742 DAVResourceAccess
aSourceAccess( xContext
,
2743 xResAccess
->getSessionFactory(),
2744 sourceURI
.GetURI() );
2746 if ( rArgs
.MoveData
== sal_True
)
2748 uno::Reference
< ucb::XContentIdentifier
> xId
2749 = new ::ucbhelper::ContentIdentifier( rArgs
.SourceURL
);
2751 // Note: The static cast is okay here, because its sure that
2752 // xProvider is always the WebDAVContentProvider.
2753 rtl::Reference
< Content
> xSource
2754 = static_cast< Content
* >(
2755 xProvider
->queryContent( xId
).get() );
2757 // [RFC 2518] - WebDAV
2758 // If a resource exists at the destination and the Overwrite
2759 // header is "T" then prior to performing the move the server
2760 // MUST perform a DELETE with "Depth: infinity" on the
2761 // destination resource. If the Overwrite header is set to
2762 // "F" then the operation will fail.
2764 aSourceAccess
.MOVE( sourceURI
.GetPath(),
2767 == ucb::NameClash::OVERWRITE
,
2772 // Propagate destruction to listeners.
2773 xSource
->destroy( true );
2776 // DAV resources store all additional props on server!
2777 // // Rename own and all children's Additional Core Properties.
2778 // renameAdditionalPropertySet( xId->getContentIdentifier(),
2779 // xTargetId->getContentIdentifier(),
2784 // [RFC 2518] - WebDAV
2785 // If a resource exists at the destination and the Overwrite
2786 // header is "T" then prior to performing the copy the server
2787 // MUST perform a DELETE with "Depth: infinity" on the
2788 // destination resource. If the Overwrite header is set to
2789 // "F" then the operation will fail.
2791 aSourceAccess
.COPY( sourceURI
.GetPath(),
2794 == ucb::NameClash::OVERWRITE
,
2797 // DAV resources store all additional props on server!
2798 // // Copy own and all children's Additional Core Properties.
2799 // copyAdditionalPropertySet( xId->getContentIdentifier(),
2800 // xTargetId->getContentIdentifier(),
2804 // Note: The static cast is okay here, because its sure that
2805 // xProvider is always the WebDAVContentProvider.
2806 rtl::Reference
< Content
> xTarget
2807 = static_cast< Content
* >(
2808 xProvider
->queryContent( xTargetId
).get() );
2810 // Announce transferred content in its new folder.
2811 xTarget
->inserted();
2813 catch ( ucb::IllegalIdentifierException
const & )
2817 catch ( DAVException
const & e
)
2819 // [RFC 2518] - WebDAV
2820 // 412 (Precondition Failed) - The server was unable to maintain
2821 // the liveness of the properties listed in the propertybehavior
2822 // XML element or the Overwrite header is "F" and the state of
2823 // the destination resource is non-null.
2825 if ( e
.getStatus() == SC_PRECONDITION_FAILED
)
2827 switch ( rArgs
.NameClash
)
2829 case 0/*ucb::NameClash::ERROR*/:
2831 ucbhelper::cancelCommandExecution(
2833 ucb::NameClashException(
2835 static_cast< cppu::OWeakObject
* >( this ),
2836 task::InteractionClassification_ERROR
,
2842 case ucb::NameClash::OVERWRITE
:
2845 case ucb::NameClash::KEEP
: // deprecated
2846 case ucb::NameClash::RENAME
:
2847 case ucb::NameClash::ASK
:
2850 ucbhelper::cancelCommandExecution(
2852 ucb::UnsupportedNameClashException(
2854 static_cast< cppu::OWeakObject
* >( this ),
2855 rArgs
.NameClash
) ),
2862 cancelCommandExecution( e
, Environment
, true );
2867 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2868 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
2873 void Content::destroy( bool bDeletePhysical
)
2874 throw( uno::Exception
)
2876 // @@@ take care about bDeletePhysical -> trashcan support
2878 uno::Reference
< ucb::XContent
> xThis
= this;
2882 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2884 // Process instantiated children...
2886 ::http_dav_ucp::Content::ContentRefList aChildren
;
2887 queryChildren( aChildren
);
2889 ContentRefList::const_iterator it
= aChildren
.begin();
2890 ContentRefList::const_iterator end
= aChildren
.end();
2894 (*it
)->destroy( bDeletePhysical
);
2900 bool Content::supportsExclusiveWriteLock(
2901 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2903 if ( getResourceType( Environment
) == DAV
)
2905 if ( m_xCachedProps
.get() )
2907 uno::Sequence
< ucb::LockEntry
> aSupportedLocks
;
2908 if ( m_xCachedProps
->getValue( DAVProperties::SUPPORTEDLOCK
)
2909 >>= aSupportedLocks
)
2911 for ( sal_Int32 n
= 0; n
< aSupportedLocks
.getLength(); ++n
)
2913 if ( aSupportedLocks
[ n
].Scope
2914 == ucb::LockScope_EXCLUSIVE
&&
2915 aSupportedLocks
[ n
].Type
2916 == ucb::LockType_WRITE
)
2927 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2928 throw( uno::Exception
)
2932 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
2934 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2935 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
2939 aOwnerAny
<<= OUString( "http://ucb.openoffice.org" );
2942 ucb::LockScope_EXCLUSIVE
,
2943 ucb::LockType_WRITE
,
2944 ucb::LockDepth_ZERO
,
2946 180, // lock timeout in secs
2947 //-1, // infinite lock
2948 uno::Sequence
< OUString
>() );
2950 xResAccess
->LOCK( aLock
, Environment
);
2954 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2955 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
2958 catch ( DAVException
const & e
)
2960 cancelCommandExecution( e
, Environment
, false );
2966 void Content::unlock(
2967 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2968 throw( uno::Exception
)
2972 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
2974 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2975 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
2978 xResAccess
->UNLOCK( Environment
);
2982 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2983 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
2986 catch ( DAVException
const & e
)
2988 cancelCommandExecution( e
, Environment
, false );
2994 bool Content::exchangeIdentity(
2995 const uno::Reference
< ucb::XContentIdentifier
>& xNewId
)
3000 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
3002 uno::Reference
< ucb::XContent
> xThis
= this;
3004 // Already persistent?
3007 SAL_WARN( "ucb.ucp.webdav", "Content::exchangeIdentity - Not persistent!" );
3011 // Exchange own identitity.
3013 // Fail, if a content with given id already exists.
3014 // if ( !hasData( xNewId ) )
3016 OUString aOldURL
= m_xIdentifier
->getContentIdentifier();
3019 if ( exchange( xNewId
) )
3021 // Process instantiated children...
3023 ContentRefList aChildren
;
3024 queryChildren( aChildren
);
3026 ContentRefList::const_iterator it
= aChildren
.begin();
3027 ContentRefList::const_iterator end
= aChildren
.end();
3031 ContentRef xChild
= (*it
);
3033 // Create new content identifier for the child...
3034 uno::Reference
< ucb::XContentIdentifier
>
3035 xOldChildId
= xChild
->getIdentifier();
3036 OUString aOldChildURL
3037 = xOldChildId
->getContentIdentifier();
3038 OUString aNewChildURL
3039 = aOldChildURL
.replaceAt(
3041 aOldURL
.getLength(),
3042 xNewId
->getContentIdentifier() );
3043 uno::Reference
< ucb::XContentIdentifier
> xNewChildId
3044 = new ::ucbhelper::ContentIdentifier( aNewChildURL
);
3046 if ( !xChild
->exchangeIdentity( xNewChildId
) )
3055 SAL_WARN( "ucb.ucp.webdav",
3056 "Content::exchangeIdentity - "
3057 "Panic! Cannot exchange identity!" );
3062 bool Content::isFolder(
3063 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
3064 throw( uno::Exception
)
3067 osl::MutexGuard
aGuard( m_aMutex
);
3070 return m_bCollection
;
3073 uno::Sequence
< beans::Property
> aProperties( 1 );
3074 aProperties
[ 0 ].Name
= "IsFolder";
3075 aProperties
[ 0 ].Handle
= -1;
3076 uno::Reference
< sdbc::XRow
> xRow( getPropertyValues( aProperties
, xEnv
) );
3081 return xRow
->getBoolean( 1 );
3083 catch ( sdbc::SQLException
const & )
3092 uno::Any
Content::MapDAVException( const DAVException
& e
, bool bWrite
)
3094 // Map DAVException...
3095 uno::Any aException
;
3100 aURL
= getParentURL();
3101 if ( aURL
.lastIndexOf( '/' ) != ( aURL
.getLength() - 1 ) )
3104 aURL
+= m_aEscapedTitle
;
3108 aURL
= m_xIdentifier
->getContentIdentifier();
3111 switch ( e
.getStatus() )
3115 uno::Sequence
< uno::Any
> aArgs( 1 );
3116 aArgs
[ 0 ] <<= beans::PropertyValue(
3117 OUString("Uri"), -1,
3119 beans::PropertyState_DIRECT_VALUE
);
3122 ucb::InteractiveAugmentedIOException(
3123 OUString( "Not found!" ),
3124 static_cast< cppu::OWeakObject
* >( this ),
3125 task::InteractionClassification_ERROR
,
3126 ucb::IOErrorCode_NOT_EXISTING
,
3134 switch ( e
.getError() )
3136 case DAVException::DAV_HTTP_ERROR
:
3140 ucb::InteractiveNetworkWriteException(
3142 static_cast< cppu::OWeakObject
* >( this ),
3143 task::InteractionClassification_ERROR
,
3147 ucb::InteractiveNetworkReadException(
3149 static_cast< cppu::OWeakObject
* >( this ),
3150 task::InteractionClassification_ERROR
,
3155 case DAVException::DAV_HTTP_LOOKUP
:
3157 ucb::InteractiveNetworkResolveNameException(
3159 static_cast< cppu::OWeakObject
* >( this ),
3160 task::InteractionClassification_ERROR
,
3164 // @@@ No matching InteractiveNetwork*Exception
3165 // case DAVException::DAV_HTTP_AUTH:
3168 // @@@ No matching InteractiveNetwork*Exception
3169 // case DAVException::DAV_HTTP_AUTHPROXY:
3172 case DAVException::DAV_HTTP_CONNECT
:
3174 ucb::InteractiveNetworkConnectException(
3176 static_cast< cppu::OWeakObject
* >( this ),
3177 task::InteractionClassification_ERROR
,
3181 // @@@ No matching InteractiveNetwork*Exception
3182 // case DAVException::DAV_HTTP_TIMEOUT:
3185 // @@@ No matching InteractiveNetwork*Exception
3186 // case DAVException::DAV_HTTP_REDIRECT:
3189 // @@@ No matching InteractiveNetwork*Exception
3190 // case DAVException::DAV_SESSION_CREATE:
3193 case DAVException::DAV_INVALID_ARG
:
3195 lang::IllegalArgumentException(
3197 static_cast< cppu::OWeakObject
* >( this ),
3201 case DAVException::DAV_LOCKED
:
3204 ucb::InteractiveLockingLockedException(
3205 OUString( "Locked!" ),
3206 static_cast< cppu::OWeakObject
* >( this ),
3207 task::InteractionClassification_ERROR
,
3209 false ); // not SelfOwned
3212 uno::Sequence
< uno::Any
> aArgs( 1 );
3213 aArgs
[ 0 ] <<= beans::PropertyValue(
3214 OUString("Uri"), -1,
3216 beans::PropertyState_DIRECT_VALUE
);
3219 ucb::InteractiveAugmentedIOException(
3220 OUString( "Locked!" ),
3221 static_cast< cppu::OWeakObject
* >( this ),
3222 task::InteractionClassification_ERROR
,
3223 ucb::IOErrorCode_LOCKING_VIOLATION
,
3229 case DAVException::DAV_LOCKED_SELF
:
3231 ucb::InteractiveLockingLockedException(
3232 OUString( "Locked (self)!" ),
3233 static_cast< cppu::OWeakObject
* >( this ),
3234 task::InteractionClassification_ERROR
,
3236 true ); // SelfOwned
3239 case DAVException::DAV_NOT_LOCKED
:
3241 ucb::InteractiveLockingNotLockedException(
3242 OUString( "Not locked!" ),
3243 static_cast< cppu::OWeakObject
* >( this ),
3244 task::InteractionClassification_ERROR
,
3248 case DAVException::DAV_LOCK_EXPIRED
:
3250 ucb::InteractiveLockingLockExpiredException(
3251 OUString( "Lock expired!" ),
3252 static_cast< cppu::OWeakObject
* >( this ),
3253 task::InteractionClassification_ERROR
,
3259 ucb::InteractiveNetworkGeneralException(
3261 static_cast< cppu::OWeakObject
* >( this ),
3262 task::InteractionClassification_ERROR
);
3271 bool Content::shouldAccessNetworkAfterException( const DAVException
& e
)
3273 if ( ( e
.getStatus() == SC_NOT_FOUND
) ||
3274 ( e
.getError() == DAVException::DAV_HTTP_LOOKUP
) ||
3275 ( e
.getError() == DAVException::DAV_HTTP_CONNECT
) ||
3276 ( e
.getError() == DAVException::DAV_HTTP_AUTH
) ||
3277 ( e
.getError() == DAVException::DAV_HTTP_AUTHPROXY
) )
3284 void Content::cancelCommandExecution(
3285 const DAVException
& e
,
3286 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
3287 bool bWrite
/* = false */ )
3288 throw ( uno::Exception
)
3290 ucbhelper::cancelCommandExecution( MapDAVException( e
, bWrite
), xEnv
);
3296 Content::getBaseURI( const boost::scoped_ptr
< DAVResourceAccess
> & rResAccess
)
3298 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
3300 // First, try to obtain value of response header "Content-Location".
3301 if ( m_xCachedProps
.get() )
3304 m_xCachedProps
->getValue( OUString(
3305 "Content-Location" ) ) >>= aLocation
;
3306 if ( aLocation
.getLength() )
3310 // Do not use m_xIdentifier->getContentIdentifier() because it
3311 // for example does not reflect redirects applied to requests
3312 // done using the original URI but m_xResAccess' URI does.
3313 return rtl::Uri::convertRelToAbs( rResAccess
->getURL(),
3316 catch ( rtl::MalformedUriException
const & )
3322 return OUString( rResAccess
->getURL() );
3326 Content::ResourceType
Content::getResourceType(
3327 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
,
3328 const boost::scoped_ptr
< DAVResourceAccess
> & rResAccess
,
3329 bool * networkAccessAllowed
)
3330 throw ( uno::Exception
)
3333 osl::MutexGuard
g(m_aMutex
);
3334 if (m_eResourceType
!= UNKNOWN
) {
3335 return m_eResourceType
;
3339 ResourceType eResourceType
= UNKNOWN
;
3343 // Try to fetch some frequently used property value, e.g. those
3344 // used when loading documents... along with identifying whether
3345 // this is a DAV resource.
3346 std::vector
< DAVResource
> resources
;
3347 std::vector
< OUString
> aPropNames
;
3348 uno::Sequence
< beans::Property
> aProperties( 5 );
3349 aProperties
[ 0 ].Name
= "IsFolder";
3350 aProperties
[ 1 ].Name
= "IsDocument";
3351 aProperties
[ 2 ].Name
= "IsReadOnly";
3352 aProperties
[ 3 ].Name
= "MediaType";
3353 aProperties
[ 4 ].Name
= DAVProperties::SUPPORTEDLOCK
;
3355 ContentProperties::UCBNamesToDAVNames(
3356 aProperties
, aPropNames
);
3358 rResAccess
->PROPFIND(
3359 DAVZERO
, aPropNames
, resources
, xEnv
);
3361 // TODO - is this really only one?
3362 if ( resources
.size() == 1 )
3364 osl::MutexGuard
g(m_aMutex
);
3365 m_xCachedProps
.reset(
3366 new CachableContentProperties( resources
[ 0 ] ) );
3367 m_xCachedProps
->containsAllNames(
3368 aProperties
, m_aFailedPropNames
);
3371 eResourceType
= DAV
;
3373 catch ( DAVException
const & e
)
3375 rResAccess
->resetUri();
3377 if ( e
.getStatus() == SC_METHOD_NOT_ALLOWED
)
3379 // Status SC_METHOD_NOT_ALLOWED is a safe indicator that the
3380 // resource is NON_DAV
3381 eResourceType
= NON_DAV
;
3383 else if (networkAccessAllowed
!= 0)
3385 *networkAccessAllowed
= *networkAccessAllowed
3386 && shouldAccessNetworkAfterException(e
);
3389 // cancel command execution is case that no user authentication data has been provided.
3390 if ( e
.getError() == DAVException::DAV_HTTP_NOAUTH
)
3392 cancelCommandExecution( e
, uno::Reference
< ucb::XCommandEnvironment
>() );
3396 osl::MutexGuard
g(m_aMutex
);
3397 if (m_eResourceType
== UNKNOWN
) {
3398 m_eResourceType
= eResourceType
;
3401 eResourceType
!= m_eResourceType
, "ucb.ucp.webdav",
3402 "different resource types for <" << rResAccess
->getURL() << ">: "
3403 << +eResourceType
<< " vs. " << +m_eResourceType
);
3405 return m_eResourceType
;
3409 Content::ResourceType
Content::getResourceType(
3410 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
3411 throw ( uno::Exception
)
3413 boost::scoped_ptr
< DAVResourceAccess
> xResAccess
;
3415 osl::MutexGuard
aGuard( m_aMutex
);
3416 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
3418 const Content::ResourceType
& ret
= getResourceType( xEnv
, xResAccess
);
3420 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
3421 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
3426 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */