1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 /**************************************************************************
32 **************************************************************************
34 *************************************************************************/
36 #include <comphelper/processfactory.hxx>
37 #include <osl/diagnose.h>
38 #include "osl/doublecheckedlocking.h"
39 #include <rtl/uri.hxx>
40 #include <rtl/ustrbuf.hxx>
41 #include <ucbhelper/contentidentifier.hxx>
42 #include <ucbhelper/propertyvalueset.hxx>
43 #include <ucbhelper/simpleinteractionrequest.hxx>
44 #include <ucbhelper/cancelcommandexecution.hxx>
46 #include <com/sun/star/beans/PropertyAttribute.hpp>
47 #include <com/sun/star/beans/PropertySetInfoChange.hpp>
48 #include <com/sun/star/beans/PropertySetInfoChangeEvent.hpp>
49 #include <com/sun/star/beans/PropertyValue.hpp>
50 #include <com/sun/star/io/XActiveDataSink.hpp>
51 #include <com/sun/star/io/XOutputStream.hpp>
52 #include <com/sun/star/lang/IllegalAccessException.hpp>
53 #include <com/sun/star/task/PasswordContainerInteractionHandler.hpp>
54 #include <com/sun/star/ucb/CommandEnvironment.hpp>
55 #include <com/sun/star/ucb/CommandFailedException.hpp>
56 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
57 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
58 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
59 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
60 #include "com/sun/star/ucb/InteractiveLockingLockedException.hpp"
61 #include "com/sun/star/ucb/InteractiveLockingLockExpiredException.hpp"
62 #include "com/sun/star/ucb/InteractiveLockingNotLockedException.hpp"
63 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
64 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
65 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
66 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
67 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
68 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
69 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
70 #include <com/sun/star/ucb/NameClash.hpp>
71 #include <com/sun/star/ucb/NameClashException.hpp>
72 #include <com/sun/star/ucb/OpenCommandArgument3.hpp>
73 #include <com/sun/star/ucb/OpenMode.hpp>
74 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
75 #include <com/sun/star/ucb/PropertyCommandArgument.hpp>
76 #include <com/sun/star/ucb/TransferInfo.hpp>
77 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
78 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
79 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
80 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
81 #include <com/sun/star/ucb/XCommandInfo.hpp>
82 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
83 #include <com/sun/star/uno/XComponentContext.hpp>
85 #include "webdavcontent.hxx"
86 #include "webdavprovider.hxx"
87 #include "webdavresultset.hxx"
88 #include "ContentProperties.hxx"
89 #include "NeonUri.hxx"
90 #include "UCBDeadPropertyValue.hxx"
92 using namespace com::sun::star
;
93 using namespace webdav_ucp
;
98 // Content Implementation.
104 // ctr for content on an existing webdav resource
106 const uno::Reference
< uno::XComponentContext
>& rxContext
,
107 ContentProvider
* pProvider
,
108 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
109 rtl::Reference
< DAVSessionFactory
> const & rSessionFactory
)
110 throw ( ucb::ContentCreationException
)
111 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
112 m_eResourceType( UNKNOWN
),
113 m_pProvider( pProvider
),
114 m_bTransient( false ),
116 m_bCollection( false ),
117 m_bDidGetOrHead( false )
121 m_xResAccess
.reset( new DAVResourceAccess(
124 Identifier
->getContentIdentifier() ) );
126 NeonUri
aURI( Identifier
->getContentIdentifier() );
127 m_aEscapedTitle
= aURI
.GetPathBaseName();
129 catch ( DAVException
const & )
131 throw ucb::ContentCreationException();
136 // ctr for content on an non-existing webdav resource
138 const uno::Reference
< uno::XComponentContext
>& rxContext
,
139 ContentProvider
* pProvider
,
140 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
,
141 rtl::Reference
< DAVSessionFactory
> const & rSessionFactory
,
143 throw ( ucb::ContentCreationException
)
144 : ContentImplHelper( rxContext
, pProvider
, Identifier
),
145 m_eResourceType( UNKNOWN
),
146 m_pProvider( pProvider
),
147 m_bTransient( true ),
149 m_bCollection( isCollection
),
150 m_bDidGetOrHead( false )
154 m_xResAccess
.reset( new DAVResourceAccess(
155 rxContext
, rSessionFactory
, Identifier
->getContentIdentifier() ) );
157 catch ( DAVException
const & )
159 throw ucb::ContentCreationException();
162 // Do not set m_aEscapedTitle here! Content::insert relays on this!!!
170 unlock(uno::Reference
< ucb::XCommandEnvironment
>());
175 // XInterface methods.
180 void SAL_CALL
Content::acquire()
183 ContentImplHelper::acquire();
188 void SAL_CALL
Content::release()
191 ContentImplHelper::release();
196 uno::Any SAL_CALL
Content::queryInterface( const uno::Type
& rType
)
197 throw ( uno::RuntimeException
, std::exception
)
199 // Note: isFolder may require network activities! So call it only
200 // if it is really necessary!!!
201 uno::Any aRet
= cppu::queryInterface(
203 static_cast< ucb::XContentCreator
* >( this ) );
204 if ( aRet
.hasValue() )
208 uno::Reference
< task::XInteractionHandler
> xIH(
209 task::PasswordContainerInteractionHandler::create( m_xContext
) );
211 // Supply a command env to isFolder() that contains an interaction
212 // handler that uses the password container service to obtain
213 // credentials without displaying a password gui.
215 uno::Reference
< ucb::XCommandEnvironment
> xCmdEnv(
216 ucb::CommandEnvironment::create(
219 uno::Reference
< ucb::XProgressHandler
>() ) );
221 return isFolder( xCmdEnv
) ? aRet
: uno::Any();
223 catch ( uno::RuntimeException
const & )
227 catch ( uno::Exception
const & )
232 return aRet
.hasValue() ? aRet
: ContentImplHelper::queryInterface( rType
);
237 // XTypeProvider methods.
241 XTYPEPROVIDER_COMMON_IMPL( Content
);
245 uno::Sequence
< uno::Type
> SAL_CALL
Content::getTypes()
246 throw( uno::RuntimeException
, std::exception
)
248 bool bFolder
= false;
252 = isFolder( uno::Reference
< ucb::XCommandEnvironment
>() );
254 catch ( uno::RuntimeException
const & )
258 catch ( uno::Exception
const & )
262 cppu::OTypeCollection
* pCollection
= 0;
266 static cppu::OTypeCollection
* pFolderTypes
= 0;
268 pCollection
= pFolderTypes
;
271 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
273 pCollection
= pFolderTypes
;
276 static cppu::OTypeCollection
aCollection(
277 CPPU_TYPE_REF( lang::XTypeProvider
),
278 CPPU_TYPE_REF( lang::XServiceInfo
),
279 CPPU_TYPE_REF( lang::XComponent
),
280 CPPU_TYPE_REF( ucb::XContent
),
281 CPPU_TYPE_REF( ucb::XCommandProcessor
),
282 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
283 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
284 CPPU_TYPE_REF( beans::XPropertyContainer
),
285 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
286 CPPU_TYPE_REF( container::XChild
),
287 CPPU_TYPE_REF( ucb::XContentCreator
) ); // !!
288 pCollection
= &aCollection
;
289 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
290 pFolderTypes
= pCollection
;
294 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
299 static cppu::OTypeCollection
* pDocumentTypes
= 0;
301 pCollection
= pDocumentTypes
;
304 osl::Guard
< osl::Mutex
> aGuard( osl::Mutex::getGlobalMutex() );
306 pCollection
= pDocumentTypes
;
309 static cppu::OTypeCollection
aCollection(
310 CPPU_TYPE_REF( lang::XTypeProvider
),
311 CPPU_TYPE_REF( lang::XServiceInfo
),
312 CPPU_TYPE_REF( lang::XComponent
),
313 CPPU_TYPE_REF( ucb::XContent
),
314 CPPU_TYPE_REF( ucb::XCommandProcessor
),
315 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier
),
316 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier
),
317 CPPU_TYPE_REF( beans::XPropertyContainer
),
318 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier
),
319 CPPU_TYPE_REF( container::XChild
) );
320 pCollection
= &aCollection
;
321 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
322 pDocumentTypes
= pCollection
;
326 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
330 return (*pCollection
).getTypes();
335 // XServiceInfo methods.
340 OUString SAL_CALL
Content::getImplementationName()
341 throw( uno::RuntimeException
, std::exception
)
343 return OUString( "com.sun.star.comp.ucb.WebDAVContent" );
348 uno::Sequence
< OUString
> SAL_CALL
Content::getSupportedServiceNames()
349 throw( uno::RuntimeException
, std::exception
)
351 uno::Sequence
< OUString
> aSNS( 1 );
352 aSNS
[ 0 ] = WEBDAV_CONTENT_SERVICE_NAME
;
363 OUString SAL_CALL
Content::getContentType()
364 throw( uno::RuntimeException
, std::exception
)
366 bool bFolder
= false;
370 = isFolder( uno::Reference
< ucb::XCommandEnvironment
>() );
372 catch ( uno::RuntimeException
const & )
376 catch ( uno::Exception
const & )
381 return OUString( WEBDAV_COLLECTION_TYPE
);
383 return OUString( WEBDAV_CONTENT_TYPE
);
388 // XCommandProcessor methods.
393 uno::Any SAL_CALL
Content::execute(
394 const ucb::Command
& aCommand
,
395 sal_Int32
/*CommandId*/,
396 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
397 throw( uno::Exception
,
398 ucb::CommandAbortedException
,
399 uno::RuntimeException
, std::exception
)
401 SAL_INFO( "ucb.ucp.webdav", "Content::execute: start: command: " <<
402 aCommand
.Name
<< ", env: " <<
403 (Environment
.is() ? "present" : "missing") );
407 if ( aCommand
.Name
== "getPropertyValues" )
413 uno::Sequence
< beans::Property
> Properties
;
414 if ( !( aCommand
.Argument
>>= Properties
) )
416 ucbhelper::cancelCommandExecution(
417 uno::makeAny( lang::IllegalArgumentException(
418 OUString( "Wrong argument type!" ),
419 static_cast< cppu::OWeakObject
* >( this ),
425 aRet
<<= getPropertyValues( Properties
, Environment
);
427 else if ( aCommand
.Name
== "setPropertyValues" )
433 uno::Sequence
< beans::PropertyValue
> aProperties
;
434 if ( !( aCommand
.Argument
>>= aProperties
) )
436 ucbhelper::cancelCommandExecution(
437 uno::makeAny( lang::IllegalArgumentException(
438 OUString( "Wrong argument type!" ),
439 static_cast< cppu::OWeakObject
* >( this ),
445 if ( !aProperties
.getLength() )
447 ucbhelper::cancelCommandExecution(
448 uno::makeAny( lang::IllegalArgumentException(
449 OUString( "No properties!" ),
450 static_cast< cppu::OWeakObject
* >( this ),
456 aRet
<<= setPropertyValues( aProperties
, Environment
);
458 else if ( aCommand
.Name
== "getPropertySetInfo" )
461 // getPropertySetInfo
464 // Note: Implemented by base class.
465 aRet
<<= getPropertySetInfo( Environment
,
466 false /* don't cache data */ );
468 else if ( aCommand
.Name
== "getCommandInfo" )
474 // Note: Implemented by base class.
475 aRet
<<= getCommandInfo( Environment
, false );
477 else if ( aCommand
.Name
== "open" )
483 ucb::OpenCommandArgument3 aOpenCommand
;
484 ucb::OpenCommandArgument2 aTmp
;
485 if ( !( aCommand
.Argument
>>= aTmp
) )
487 ucbhelper::cancelCommandExecution(
488 uno::makeAny( lang::IllegalArgumentException(
489 OUString( "Wrong argument type!" ),
490 static_cast< cppu::OWeakObject
* >( this ),
495 if ( !( aCommand
.Argument
>>= aOpenCommand
) )
497 // compat mode, extract Arg2 info into newer structure
498 aOpenCommand
.Mode
= aTmp
.Mode
;
499 aOpenCommand
.Priority
= aTmp
.Priority
;
500 aOpenCommand
.Sink
= aTmp
.Sink
;
501 aOpenCommand
.Properties
= aTmp
.Properties
;
502 aOpenCommand
.SortingInfo
= aTmp
.SortingInfo
;
505 aRet
= open( aOpenCommand
, Environment
);
507 if ( (aOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT
||
508 aOpenCommand
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
) &&
509 supportsExclusiveWriteLock( Environment
) )
512 else if ( aCommand
.Name
== "insert" )
518 ucb::InsertCommandArgument arg
;
519 if ( !( aCommand
.Argument
>>= arg
) )
521 ucbhelper::cancelCommandExecution(
522 uno::makeAny( lang::IllegalArgumentException(
523 OUString( "Wrong argument type!" ),
524 static_cast< cppu::OWeakObject
* >( this ),
530 insert( arg
.Data
, arg
.ReplaceExisting
, Environment
);
532 else if ( aCommand
.Name
== "delete" )
538 bool bDeletePhysical
= false;
539 aCommand
.Argument
>>= bDeletePhysical
;
541 // KSO: Ignore parameter and destroy the content, if you don't support
542 // putting objects into trashcan. ( Since we do not have a trash can
543 // service yet (src603), you actually have no other choice. )
544 // if ( bDeletePhysical )
548 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
550 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
551 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
553 xResAccess
->DESTROY( Environment
);
555 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
556 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
559 catch ( DAVException
const & e
)
561 cancelCommandExecution( e
, Environment
, true );
566 // Propagate destruction.
567 destroy( bDeletePhysical
);
569 // Remove own and all children's Additional Core Properties.
570 removeAdditionalPropertySet( true );
572 else if ( aCommand
.Name
== "transfer" && isFolder( Environment
) )
576 // ( Not available at documents )
579 ucb::TransferInfo transferArgs
;
580 if ( !( aCommand
.Argument
>>= transferArgs
) )
582 ucbhelper::cancelCommandExecution(
583 uno::makeAny( lang::IllegalArgumentException(
584 OUString( "Wrong argument type!" ),
585 static_cast< cppu::OWeakObject
* >( this ),
591 transfer( transferArgs
, Environment
);
593 else if ( aCommand
.Name
== "post" )
599 ucb::PostCommandArgument2 aArg
;
600 if ( !( aCommand
.Argument
>>= aArg
) )
602 ucbhelper::cancelCommandExecution(
603 uno::makeAny( lang::IllegalArgumentException(
604 OUString( "Wrong argument type!" ),
605 static_cast< cppu::OWeakObject
* >( this ),
611 post( aArg
, Environment
);
613 else if ( aCommand
.Name
== "lock" && supportsExclusiveWriteLock( Environment
) )
621 else if ( aCommand
.Name
== "unlock" && supportsExclusiveWriteLock( Environment
) )
627 unlock( Environment
);
629 else if ( aCommand
.Name
== "createNewContent" && isFolder( Environment
) )
635 ucb::ContentInfo aArg
;
636 if ( !( aCommand
.Argument
>>= aArg
) )
638 ucbhelper::cancelCommandExecution(
639 uno::makeAny( lang::IllegalArgumentException(
640 OUString( "Wrong argument type!" ),
641 static_cast< cppu::OWeakObject
* >( this ),
647 aRet
= uno::makeAny( createNewContent( aArg
) );
649 else if ( aCommand
.Name
== "addProperty" )
651 ucb::PropertyCommandArgument aPropArg
;
652 if ( !( aCommand
.Argument
>>= aPropArg
))
654 ucbhelper::cancelCommandExecution(
655 uno::makeAny( lang::IllegalArgumentException(
656 "Wrong argument type!",
657 static_cast< cppu::OWeakObject
* >( this ),
662 // TODO when/if XPropertyContainer is removed,
663 // the command execution can be canceled in addProperty
666 addProperty( aPropArg
, Environment
);
668 catch ( const beans::PropertyExistException
&e
)
670 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
672 catch ( const beans::IllegalTypeException
&e
)
674 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
676 catch ( const lang::IllegalArgumentException
&e
)
678 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
681 else if ( aCommand
.Name
== "removeProperty" )
684 if ( !( aCommand
.Argument
>>= sPropName
) )
686 ucbhelper::cancelCommandExecution(
687 uno::makeAny( lang::IllegalArgumentException(
688 "Wrong argument type!",
689 static_cast< cppu::OWeakObject
* >( this ),
694 // TODO when/if XPropertyContainer is removed,
695 // the command execution can be canceled in removeProperty
698 removeProperty( sPropName
, Environment
);
700 catch( const beans::UnknownPropertyException
&e
)
702 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
704 catch( const beans::NotRemoveableException
&e
)
706 ucbhelper::cancelCommandExecution( uno::makeAny( e
), Environment
);
712 // Unsupported command
715 ucbhelper::cancelCommandExecution(
716 uno::makeAny( ucb::UnsupportedCommandException(
718 static_cast< cppu::OWeakObject
* >( this ) ) ),
723 OSL_TRACE( "<<<<< Content::execute: end: command: %s",
724 OUStringToOString( aCommand
.Name
,
725 RTL_TEXTENCODING_UTF8
).getStr() );
732 void SAL_CALL
Content::abort( sal_Int32
/*CommandId*/ )
733 throw( uno::RuntimeException
, std::exception
)
737 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
739 osl::MutexGuard
aGuard( m_aMutex
);
740 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
744 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
745 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
748 catch ( DAVException
const & )
756 // XPropertyContainer methods.
760 void Content::addProperty( const ucb::PropertyCommandArgument
& aCmdArg
,
761 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
762 throw( beans::PropertyExistException
,
763 beans::IllegalTypeException
,
764 lang::IllegalArgumentException
,
765 uno::RuntimeException
,
768 // if ( m_bTransient )
771 if ( aCmdArg
.Property
.Name
.isEmpty() )
772 throw lang::IllegalArgumentException(
773 "\"addProperty\" with empty Property.Name",
774 static_cast< cppu::OWeakObject
* >( this ),
777 // Check property type.
778 if ( !UCBDeadPropertyValue::supportsType( aCmdArg
.Property
.Type
) )
780 throw beans::IllegalTypeException(
781 "\"addProperty\" unsupported Property.Type",
782 static_cast< cppu::OWeakObject
* >( this ) );
785 if ( aCmdArg
.DefaultValue
.hasValue()
786 && aCmdArg
.DefaultValue
.getValueType() != aCmdArg
.Property
.Type
)
788 throw beans::IllegalTypeException(
789 "\"addProperty\" DefaultValue does not match Property.Type",
790 static_cast< ::cppu::OWeakObject
* >( this ) );
794 // Make sure a property with the requested name does not already
795 // exist in dynamic and static(!) properties.
798 // Take into account special properties with custom namespace
799 // using <prop:the_propname xmlns:prop="the_namespace">
800 OUString aSpecialName
;
801 bool bIsSpecial
= DAVProperties::isUCBSpecialProperty(
802 aCmdArg
.Property
.Name
, aSpecialName
);
804 // Note: This requires network access!
805 if ( getPropertySetInfo( xEnv
, false /* don't cache data */ )
807 bIsSpecial
? aSpecialName
: aCmdArg
.Property
.Name
) )
809 // Property does already exist.
810 throw beans::PropertyExistException();
814 // Add a new dynamic property.
817 ProppatchValue
aValue(
818 PROPSET
, aCmdArg
.Property
.Name
, aCmdArg
.DefaultValue
);
820 std::vector
< ProppatchValue
> aProppatchValues
;
821 aProppatchValues
.push_back( aValue
);
825 // Set property value at server.
826 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
828 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
829 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
831 xResAccess
->PROPPATCH( aProppatchValues
, xEnv
);
833 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
834 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
837 // Notify propertyset info change listeners.
838 beans::PropertySetInfoChangeEvent
evt(
839 static_cast< cppu::OWeakObject
* >( this ),
840 bIsSpecial
? aSpecialName
: aCmdArg
.Property
.Name
,
841 -1, // No handle available
842 beans::PropertySetInfoChange::PROPERTY_INSERTED
);
843 notifyPropertySetInfoChange( evt
);
845 catch ( DAVException
const & e
)
847 if ( e
.getStatus() == SC_FORBIDDEN
)
849 // Support for setting arbitrary dead properties is optional!
851 // Store property locally.
852 ContentImplHelper::addProperty(
853 bIsSpecial
? aSpecialName
: aCmdArg
.Property
.Name
,
854 aCmdArg
.Property
.Attributes
, aCmdArg
.DefaultValue
);
858 if ( shouldAccessNetworkAfterException( e
) )
862 ResourceType eType
= getResourceType( xEnv
);
867 throw lang::IllegalArgumentException();
871 // Store property locally.
872 ContentImplHelper::addProperty(
873 bIsSpecial
? aSpecialName
: aCmdArg
.Property
.Name
,
874 aCmdArg
.Property
.Attributes
, aCmdArg
.DefaultValue
);
878 OSL_FAIL( "Content::addProperty - "
879 "Unsupported resource type!" );
883 catch ( uno::Exception
const & )
885 OSL_FAIL( "Content::addProperty - "
886 "Unable to determine resource type!" );
891 OSL_FAIL( "Content::addProperty - "
892 "Unable to determine resource type!" );
898 void Content::removeProperty( const OUString
& Name
,
899 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
900 throw( beans::UnknownPropertyException
,
901 beans::NotRemoveableException
,
902 uno::RuntimeException
,
906 // Try to remove property from server.
911 std::vector
< ProppatchValue
> aProppatchValues
;
912 ProppatchValue
aValue( PROPREMOVE
, Name
, uno::Any() );
913 aProppatchValues
.push_back( aValue
);
915 // Remove property value from server.
916 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
918 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
919 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
921 xResAccess
->PROPPATCH( aProppatchValues
, xEnv
);
923 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
924 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
927 // Notify propertyset info change listeners.
928 beans::PropertySetInfoChangeEvent
evt(
929 static_cast< cppu::OWeakObject
* >( this ),
931 -1, // No handle available
932 beans::PropertySetInfoChange::PROPERTY_REMOVED
);
933 notifyPropertySetInfoChange( evt
);
935 catch ( DAVException
const & e
)
937 if ( e
.getStatus() == SC_FORBIDDEN
)
939 // Support for setting arbitrary dead properties is optional!
941 // Try to remove property from local store.
942 ContentImplHelper::removeProperty( Name
);
946 if ( shouldAccessNetworkAfterException( e
) )
950 ResourceType eType
= getResourceType( xEnv
);
955 throw beans::UnknownPropertyException();
959 // Try to remove property from local store.
960 ContentImplHelper::removeProperty( Name
);
964 OSL_FAIL( "Content::removeProperty - "
965 "Unsupported resource type!" );
969 catch ( uno::Exception
const & )
971 OSL_FAIL( "Content::removeProperty - "
972 "Unable to determine resource type!" );
977 OSL_FAIL( "Content::removeProperty - "
978 "Unable to determine resource type!" );
979 // throw beans::UnknownPropertyException();
986 void SAL_CALL
Content::addProperty( const OUString
& Name
,
987 sal_Int16 Attributes
,
988 const uno::Any
& DefaultValue
)
989 throw( beans::PropertyExistException
,
990 beans::IllegalTypeException
,
991 lang::IllegalArgumentException
,
992 uno::RuntimeException
, std::exception
)
994 beans::Property aProperty
;
995 aProperty
.Name
= Name
;
996 aProperty
.Type
= DefaultValue
.getValueType();
997 aProperty
.Attributes
= Attributes
;
998 aProperty
.Handle
= -1;
1000 addProperty( ucb::PropertyCommandArgument( aProperty
, DefaultValue
),
1001 uno::Reference
< ucb::XCommandEnvironment
>());
1005 void SAL_CALL
Content::removeProperty( const OUString
& Name
)
1006 throw( beans::UnknownPropertyException
,
1007 beans::NotRemoveableException
,
1008 uno::RuntimeException
, std::exception
)
1010 removeProperty( Name
,
1011 uno::Reference
< ucb::XCommandEnvironment
>() );
1016 // XContentCreator methods.
1021 uno::Sequence
< ucb::ContentInfo
> SAL_CALL
1022 Content::queryCreatableContentsInfo()
1023 throw( uno::RuntimeException
, std::exception
)
1025 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1027 uno::Sequence
< ucb::ContentInfo
> aSeq( 2 );
1030 aSeq
.getArray()[ 0 ].Type
= WEBDAV_CONTENT_TYPE
;
1031 aSeq
.getArray()[ 0 ].Attributes
1032 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
1033 | ucb::ContentInfoAttribute::KIND_DOCUMENT
;
1035 beans::Property aProp
;
1036 m_pProvider
->getProperty(
1037 OUString( "Title" ), aProp
);
1039 uno::Sequence
< beans::Property
> aDocProps( 1 );
1040 aDocProps
.getArray()[ 0 ] = aProp
;
1041 aSeq
.getArray()[ 0 ].Properties
= aDocProps
;
1044 aSeq
.getArray()[ 1 ].Type
= WEBDAV_COLLECTION_TYPE
;
1045 aSeq
.getArray()[ 1 ].Attributes
1046 = ucb::ContentInfoAttribute::KIND_FOLDER
;
1048 uno::Sequence
< beans::Property
> aFolderProps( 1 );
1049 aFolderProps
.getArray()[ 0 ] = aProp
;
1050 aSeq
.getArray()[ 1 ].Properties
= aFolderProps
;
1056 uno::Reference
< ucb::XContent
> SAL_CALL
1057 Content::createNewContent( const ucb::ContentInfo
& Info
)
1058 throw( uno::RuntimeException
, std::exception
)
1060 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1062 if ( Info
.Type
.isEmpty() )
1063 return uno::Reference
< ucb::XContent
>();
1065 if ( ( Info
.Type
!= WEBDAV_COLLECTION_TYPE
) && ( Info
.Type
!= WEBDAV_CONTENT_TYPE
) )
1066 return uno::Reference
< ucb::XContent
>();
1068 OUString aURL
= m_xIdentifier
->getContentIdentifier();
1070 OSL_ENSURE( !aURL
.isEmpty(),
1071 "WebdavContent::createNewContent - empty identifier!" );
1073 if ( ( aURL
.lastIndexOf( '/' ) + 1 ) != aURL
.getLength() )
1077 if ( Info
.Type
== WEBDAV_COLLECTION_TYPE
)
1079 aURL
+= "New_Collection";
1080 isCollection
= true;
1084 aURL
+= "New_Content";
1085 isCollection
= false;
1088 uno::Reference
< ucb::XContentIdentifier
> xId(
1089 new ::ucbhelper::ContentIdentifier( aURL
) );
1091 // create the local content
1094 return new ::webdav_ucp::Content( m_xContext
,
1097 m_xResAccess
->getSessionFactory(),
1100 catch ( ucb::ContentCreationException
& )
1102 return uno::Reference
< ucb::XContent
>();
1108 OUString
Content::getParentURL()
1110 // <scheme>:// -> ""
1111 // <scheme>://foo -> ""
1112 // <scheme>://foo/ -> ""
1113 // <scheme>://foo/bar -> <scheme>://foo/
1114 // <scheme>://foo/bar/ -> <scheme>://foo/
1115 // <scheme>://foo/bar/abc -> <scheme>://foo/bar/
1117 OUString aURL
= m_xIdentifier
->getContentIdentifier();
1119 sal_Int32 nPos
= aURL
.lastIndexOf( '/' );
1120 if ( nPos
== ( aURL
.getLength() - 1 ) )
1122 // Trailing slash found. Skip.
1123 nPos
= aURL
.lastIndexOf( '/', nPos
);
1126 sal_Int32 nPos1
= aURL
.lastIndexOf( '/', nPos
);
1128 nPos1
= aURL
.lastIndexOf( '/', nPos1
);
1133 return OUString( aURL
.copy( 0, nPos
+ 1 ) );
1138 // Non-interface methods.
1143 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
1144 const uno::Reference
< uno::XComponentContext
>& rxContext
,
1145 const uno::Sequence
< beans::Property
>& rProperties
,
1146 const ContentProperties
& rData
,
1147 const rtl::Reference
< ::ucbhelper::ContentProviderImplHelper
>& rProvider
,
1148 const OUString
& rContentId
)
1150 // Note: Empty sequence means "get values of all supported properties".
1152 rtl::Reference
< ::ucbhelper::PropertyValueSet
> xRow
1153 = new ::ucbhelper::PropertyValueSet( rxContext
);
1155 sal_Int32 nCount
= rProperties
.getLength();
1158 uno::Reference
< beans::XPropertySet
> xAdditionalPropSet
;
1159 bool bTriedToGetAdditionalPropSet
= false;
1161 const beans::Property
* pProps
= rProperties
.getConstArray();
1162 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1164 const beans::Property
& rProp
= pProps
[ n
];
1166 // Process standard UCB, DAV and HTTP properties.
1167 const uno::Any
& rValue
= rData
.getValue( rProp
.Name
);
1168 if ( rValue
.hasValue() )
1170 xRow
->appendObject( rProp
, rValue
);
1174 // Process local Additional Properties.
1175 if ( !bTriedToGetAdditionalPropSet
&& !xAdditionalPropSet
.is() )
1178 = uno::Reference
< beans::XPropertySet
>(
1179 rProvider
->getAdditionalPropertySet( rContentId
,
1182 bTriedToGetAdditionalPropSet
= true;
1185 if ( !xAdditionalPropSet
.is() ||
1186 !xRow
->appendPropertySetValue(
1187 xAdditionalPropSet
, rProp
) )
1189 // Append empty entry.
1190 xRow
->appendVoid( rProp
);
1197 // Append all standard UCB, DAV and HTTP properties.
1198 const std::unique_ptr
< PropertyValueMap
> & xProps
= rData
.getProperties();
1200 PropertyValueMap::const_iterator it
= xProps
->begin();
1201 PropertyValueMap::const_iterator end
= xProps
->end();
1203 ContentProvider
* pProvider
1204 = static_cast< ContentProvider
* >( rProvider
.get() );
1205 beans::Property aProp
;
1209 if ( pProvider
->getProperty( (*it
).first
, aProp
) )
1210 xRow
->appendObject( aProp
, (*it
).second
.value() );
1215 // Append all local Additional Properties.
1216 uno::Reference
< beans::XPropertySet
> xSet(
1217 rProvider
->getAdditionalPropertySet( rContentId
, false ),
1219 xRow
->appendPropertySet( xSet
);
1222 return uno::Reference
< sdbc::XRow
>( xRow
.get() );
1226 uno::Reference
< sdbc::XRow
> Content::getPropertyValues(
1227 const uno::Sequence
< beans::Property
>& rProperties
,
1228 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1229 throw ( uno::Exception
, std::exception
)
1231 std::unique_ptr
< ContentProperties
> xProps
;
1232 std::unique_ptr
< ContentProperties
> xCachedProps
;
1233 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
1234 OUString aUnescapedTitle
;
1235 bool bHasAll
= false;
1236 uno::Reference
< ucb::XContentIdentifier
> xIdentifier
;
1237 rtl::Reference
< ::ucbhelper::ContentProviderImplHelper
> xProvider
;
1240 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1242 aUnescapedTitle
= NeonUri::unescape( m_aEscapedTitle
);
1243 xIdentifier
.set( m_xIdentifier
);
1244 xProvider
.set( m_xProvider
.get() );
1245 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
1247 // First, ask cache...
1248 if ( m_xCachedProps
.get() )
1250 xCachedProps
.reset( new ContentProperties( *m_xCachedProps
.get() ) );
1252 std::vector
< OUString
> aMissingProps
;
1253 if ( xCachedProps
->containsAllNames( rProperties
, aMissingProps
) )
1255 // All properties are already in cache! No server access needed.
1259 // use the cached ContentProperties instance
1260 xProps
.reset( new ContentProperties( *xCachedProps
.get() ) );
1264 if ( !m_bTransient
&& !bHasAll
)
1267 // Obtain values from server...
1270 // First, identify whether resource is DAV or not
1271 bool bNetworkAccessAllowed
= true;
1272 ResourceType eType
= getResourceType(
1273 xEnv
, xResAccess
, &bNetworkAccessAllowed
);
1277 // cache lookup... getResourceType may fill the props cache via
1279 if ( m_xCachedProps
.get() )
1282 new ContentProperties( *m_xCachedProps
.get() ) );
1284 std::vector
< OUString
> aMissingProps
;
1285 if ( xCachedProps
->containsAllNames(
1286 rProperties
, aMissingProps
) )
1288 // All properties are already in cache! No server access
1293 // use the cached ContentProperties instance
1294 xProps
.reset( new ContentProperties( *xCachedProps
.get() ) );
1299 // Only DAV resources support PROPFIND
1300 std::vector
< OUString
> aPropNames
;
1302 uno::Sequence
< beans::Property
> aProperties(
1303 rProperties
.getLength() );
1305 if ( !m_aFailedPropNames
.empty() )
1307 sal_Int32 nProps
= 0;
1308 sal_Int32 nCount
= rProperties
.getLength();
1309 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1311 const OUString
& rName
= rProperties
[ n
].Name
;
1313 std::vector
< OUString
>::const_iterator it
1314 = m_aFailedPropNames
.begin();
1315 std::vector
< OUString
>::const_iterator end
1316 = m_aFailedPropNames
.end();
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 bNetworkAccessAllowed
1420 = shouldAccessNetworkAfterException( e
);
1422 if ( !bNetworkAccessAllowed
)
1424 cancelCommandExecution( e
, xEnv
);
1432 // might trigger HTTP redirect.
1433 // Therefore, title must be updated here.
1434 NeonUri
aUri( xResAccess
->getURL() );
1435 aUnescapedTitle
= aUri
.GetPathBaseNameUnescaped();
1437 if ( eType
== UNKNOWN
)
1439 xProps
.reset( new ContentProperties( aUnescapedTitle
) );
1442 // For DAV resources we only know the Title, for non-DAV
1443 // resources we additionally know that it is a document.
1448 // new ContentProperties( aUnescapedTitle ) );
1449 xProps
->addProperty(
1450 OUString( "Title" ),
1451 uno::makeAny( aUnescapedTitle
),
1456 if ( !xProps
.get() )
1457 xProps
.reset( new ContentProperties( aUnescapedTitle
, false ) );
1459 xProps
->addProperty(
1460 OUString( "Title" ),
1461 uno::makeAny( aUnescapedTitle
),
1464 xProps
->addProperty(
1465 OUString( "IsFolder" ),
1466 uno::makeAny( false ),
1468 xProps
->addProperty(
1469 OUString( "IsDocument" ),
1470 uno::makeAny( true ),
1476 // No server access for just created (not yet committed) objects.
1477 // Only a minimal set of properties supported at this stage.
1479 xProps
.reset( new ContentProperties( aUnescapedTitle
,
1483 sal_Int32 nCount
= rProperties
.getLength();
1484 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1486 const OUString rName
= rProperties
[ n
].Name
;
1487 if ( rName
== "BaseURI" )
1489 // Add BaseURI property, if requested.
1490 xProps
->addProperty(
1491 OUString( "BaseURI" ),
1492 uno::makeAny( getBaseURI( xResAccess
) ),
1495 else if ( rName
== "CreatableContentsInfo" )
1497 // Add CreatableContentsInfo property, if requested.
1498 bool bFolder
= false;
1500 OUString( "IsFolder" ) )
1502 xProps
->addProperty(
1503 OUString( "CreatableContentsInfo" ),
1504 uno::makeAny( bFolder
1505 ? queryCreatableContentsInfo()
1506 : uno::Sequence
< ucb::ContentInfo
>() ),
1511 uno::Reference
< sdbc::XRow
> xResultRow
1512 = getPropertyValues( m_xContext
,
1516 xIdentifier
->getContentIdentifier() );
1519 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1521 if ( !m_xCachedProps
.get() )
1522 m_xCachedProps
.reset( new CachableContentProperties( *xProps
.get() ) );
1524 m_xCachedProps
->addProperties( *xProps
.get() );
1526 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
1527 m_aEscapedTitle
= NeonUri::escapeSegment( aUnescapedTitle
);
1534 uno::Sequence
< uno::Any
> Content::setPropertyValues(
1535 const uno::Sequence
< beans::PropertyValue
>& rValues
,
1536 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
1537 throw ( uno::Exception
, std::exception
)
1539 uno::Reference
< ucb::XContentIdentifier
> xIdentifier
;
1540 rtl::Reference
< ContentProvider
> xProvider
;
1542 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
1545 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1547 xProvider
.set( m_pProvider
);
1548 xIdentifier
.set( m_xIdentifier
);
1549 bTransient
= m_bTransient
;
1550 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
1553 uno::Sequence
< uno::Any
> aRet( rValues
.getLength() );
1554 uno::Sequence
< beans::PropertyChangeEvent
> aChanges( rValues
.getLength() );
1555 sal_Int32 nChanged
= 0;
1557 beans::PropertyChangeEvent aEvent
;
1558 aEvent
.Source
= static_cast< cppu::OWeakObject
* >( this );
1559 aEvent
.Further
= sal_False
;
1560 // aEvent.PropertyName =
1561 aEvent
.PropertyHandle
= -1;
1562 // aEvent.OldValue =
1563 // aEvent.NewValue =
1565 std::vector
< ProppatchValue
> aProppatchValues
;
1566 std::vector
< sal_Int32
> aProppatchPropsPositions
;
1568 uno::Reference
< ucb::XPersistentPropertySet
> xAdditionalPropSet
;
1569 bool bTriedToGetAdditionalPropSet
= false;
1571 bool bExchange
= false;
1574 sal_Int32 nTitlePos
= -1;
1576 uno::Reference
< beans::XPropertySetInfo
> xInfo
;
1578 const beans::PropertyValue
* pValues
= rValues
.getConstArray();
1579 sal_Int32 nCount
= rValues
.getLength();
1580 for ( sal_Int32 n
= 0; n
< nCount
; ++n
)
1582 const beans::PropertyValue
& rValue
= pValues
[ n
];
1583 const OUString
& rName
= rValue
.Name
;
1585 beans::Property aTmpProp
;
1586 xProvider
->getProperty( rName
, aTmpProp
);
1588 if ( aTmpProp
.Attributes
& beans::PropertyAttribute::READONLY
)
1590 // Read-only property!
1591 aRet
[ n
] <<= lang::IllegalAccessException(
1592 OUString( "Property is read-only!" ),
1593 static_cast< cppu::OWeakObject
* >( this ) );
1601 if ( rName
== "ContentType" )
1603 // Read-only property!
1604 aRet
[ n
] <<= lang::IllegalAccessException(
1605 OUString( "Property is read-only!" ),
1606 static_cast< cppu::OWeakObject
* >( this ) );
1608 else if ( rName
== "IsDocument" )
1610 // Read-only property!
1611 aRet
[ n
] <<= lang::IllegalAccessException(
1612 OUString( "Property is read-only!" ),
1613 static_cast< cppu::OWeakObject
* >( this ) );
1615 else if ( rName
== "IsFolder" )
1617 // Read-only property!
1618 aRet
[ n
] <<= lang::IllegalAccessException(
1619 OUString( "Property is read-only!" ),
1620 static_cast< cppu::OWeakObject
* >( this ) );
1622 else if ( rName
== "Title" )
1625 if ( rValue
.Value
>>= aNewValue
)
1628 if ( !aNewValue
.isEmpty() )
1632 NeonUri
aURI( xIdentifier
->getContentIdentifier() );
1633 aOldTitle
= aURI
.GetPathBaseNameUnescaped();
1635 if ( aNewValue
!= aOldTitle
)
1637 // modified title -> modified URL -> exchange !
1641 // new value will be set later...
1642 aNewTitle
= aNewValue
;
1644 // remember position within sequence of values (for
1649 catch ( DAVException
const & )
1651 aRet
[ n
] <<= lang::IllegalArgumentException(
1652 OUString( "Invalid content identifier!" ),
1653 static_cast< cppu::OWeakObject
* >( this ),
1659 aRet
[ n
] <<= lang::IllegalArgumentException(
1660 OUString( "Empty title not allowed!" ),
1661 static_cast< cppu::OWeakObject
* >( this ),
1667 aRet
[ n
] <<= beans::IllegalTypeException(
1668 OUString( "Property value has wrong type!" ),
1669 static_cast< cppu::OWeakObject
* >( this ) );
1678 OUString aSpecialName
;
1679 bool bIsSpecial
= DAVProperties::isUCBSpecialProperty(
1680 rName
, aSpecialName
);
1683 xInfo
= getPropertySetInfo( xEnv
,
1684 false /* don't cache data */ );
1686 if ( !xInfo
->hasPropertyByName(
1687 bIsSpecial
? aSpecialName
: rName
) )
1689 // Check, whether property exists. Skip otherwise.
1690 // PROPPATCH::set would add the property automatically, which
1691 // is not allowed for "setPropertyValues" command!
1692 aRet
[ n
] <<= beans::UnknownPropertyException(
1693 OUString( "Property is unknown!" ),
1694 static_cast< cppu::OWeakObject
* >( this ) );
1698 if ( rName
== "Size" )
1700 // Read-only property!
1701 aRet
[ n
] <<= lang::IllegalAccessException(
1702 OUString( "Property is read-only!" ),
1703 static_cast< cppu::OWeakObject
* >( this ) );
1705 else if ( rName
== "DateCreated" )
1707 // Read-only property!
1708 aRet
[ n
] <<= lang::IllegalAccessException(
1709 OUString( "Property is read-only!" ),
1710 static_cast< cppu::OWeakObject
* >( this ) );
1712 else if ( rName
== "DateModified" )
1714 // Read-only property!
1715 aRet
[ n
] <<= lang::IllegalAccessException(
1716 OUString( "Property is read-only!" ),
1717 static_cast< cppu::OWeakObject
* >( this ) );
1719 else if ( rName
== "MediaType" )
1721 // Read-only property!
1722 // (but could be writable, if 'getcontenttype' would be)
1723 aRet
[ n
] <<= lang::IllegalAccessException(
1724 OUString( "Property is read-only!" ),
1725 static_cast< cppu::OWeakObject
* >( this ) );
1727 if ( rName
== "CreatableContentsInfo" )
1729 // Read-only property!
1730 aRet
[ n
] <<= lang::IllegalAccessException(
1731 OUString( "Property is read-only!" ),
1732 static_cast< cppu::OWeakObject
* >( this ) );
1736 if ( getResourceType( xEnv
, xResAccess
) == DAV
)
1738 // Property value will be set on server.
1739 ProppatchValue
aValue( PROPSET
, rName
, rValue
.Value
);
1740 aProppatchValues
.push_back( aValue
);
1742 // remember position within sequence of values (for
1744 aProppatchPropsPositions
.push_back( n
);
1748 // Property value will be stored in local property store.
1749 if ( !bTriedToGetAdditionalPropSet
&&
1750 !xAdditionalPropSet
.is() )
1753 = getAdditionalPropertySet( false );
1754 bTriedToGetAdditionalPropSet
= true;
1757 if ( xAdditionalPropSet
.is() )
1762 = xAdditionalPropSet
->getPropertyValue( rName
);
1763 if ( aOldValue
!= rValue
.Value
)
1765 xAdditionalPropSet
->setPropertyValue(
1766 rName
, rValue
.Value
);
1768 aEvent
.PropertyName
= rName
;
1769 aEvent
.OldValue
= aOldValue
;
1770 aEvent
.NewValue
= rValue
.Value
;
1772 aChanges
.getArray()[ nChanged
] = aEvent
;
1776 catch ( beans::UnknownPropertyException
const & e
)
1780 catch ( lang::WrappedTargetException
const & e
)
1784 catch ( beans::PropertyVetoException
const & e
)
1788 catch ( lang::IllegalArgumentException
const & e
)
1795 aRet
[ n
] <<= uno::Exception(
1796 OUString( "No property set for storing the value!" ),
1797 static_cast< cppu::OWeakObject
* >( this ) );
1804 if ( !bTransient
&& !aProppatchValues
.empty() )
1808 // Set property values at server.
1809 xResAccess
->PROPPATCH( aProppatchValues
, xEnv
);
1811 std::vector
< ProppatchValue
>::const_iterator it
1812 = aProppatchValues
.begin();
1813 std::vector
< ProppatchValue
>::const_iterator end
1814 = aProppatchValues
.end();
1818 aEvent
.PropertyName
= (*it
).name
;
1819 aEvent
.OldValue
= uno::Any(); // @@@ to expensive to obtain!
1820 aEvent
.NewValue
= (*it
).value
;
1822 aChanges
.getArray()[ nChanged
] = aEvent
;
1828 catch ( DAVException
const & e
)
1830 // OSL_FAIL( // "Content::setPropertyValues - PROPPATCH failed!" );
1832 cancelCommandExecution( e
, xEnv
);
1839 // Assemble new content identifier...
1841 OUString aNewURL
= getParentURL();
1842 if ( aNewURL
.lastIndexOf( '/' ) != ( aNewURL
.getLength() - 1 ) )
1845 aNewURL
+= NeonUri::escapeSegment( aNewTitle
);
1847 uno::Reference
< ucb::XContentIdentifier
> xNewId
1848 = new ::ucbhelper::ContentIdentifier( aNewURL
);
1849 uno::Reference
< ucb::XContentIdentifier
> xOldId
= xIdentifier
;
1853 NeonUri
sourceURI( xOldId
->getContentIdentifier() );
1854 NeonUri
targetURI( xNewId
->getContentIdentifier() );
1855 targetURI
.SetScheme( sourceURI
.GetScheme() );
1858 sourceURI
.GetPath(), targetURI
.GetURI(), false, xEnv
);
1859 // @@@ Should check for resources that could not be moved
1860 // (due to source access or target overwrite) and send
1861 // this information through the interaction handler.
1863 // @@@ Existing content should be checked to see if it needs
1864 // to be deleted at the source
1866 // @@@ Existing content should be checked to see if it has
1867 // been overwritten at the target
1869 if ( exchangeIdentity( xNewId
) )
1871 xResAccess
->setURL( aNewURL
);
1873 // DAV resources store all additional props on server!
1874 // // Adapt Additional Core Properties.
1875 // renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1876 // xNewId->getContentIdentifier(),
1881 // Do not set new title!
1885 aRet
[ nTitlePos
] <<= uno::Exception(
1886 OUString("Exchange failed!"),
1887 static_cast< cppu::OWeakObject
* >( this ) );
1890 catch ( DAVException
const & e
)
1892 // Do not set new title!
1896 aRet
[ nTitlePos
] <<= MapDAVException( e
, true );
1900 if ( !aNewTitle
.isEmpty() )
1902 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1904 aEvent
.PropertyName
= "Title";
1905 aEvent
.OldValue
= uno::makeAny( aOldTitle
);
1906 aEvent
.NewValue
= uno::makeAny( aNewTitle
);
1908 m_aEscapedTitle
= NeonUri::escapeSegment( aNewTitle
);
1910 aChanges
.getArray()[ nChanged
] = aEvent
;
1916 aChanges
.realloc( nChanged
);
1917 notifyPropertiesChange( aChanges
);
1921 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
1922 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
1929 uno::Any
Content::open(
1930 const ucb::OpenCommandArgument3
& rArg
,
1931 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
1932 throw (uno::Exception
, std::exception
)
1936 bool bOpenFolder
= ( ( rArg
.Mode
== ucb::OpenMode::ALL
) ||
1937 ( rArg
.Mode
== ucb::OpenMode::FOLDERS
) ||
1938 ( rArg
.Mode
== ucb::OpenMode::DOCUMENTS
) );
1941 if ( isFolder( xEnv
) )
1945 uno::Reference
< ucb::XDynamicResultSet
> xSet
1946 = new DynamicResultSet( m_xContext
, this, rArg
, xEnv
);
1951 // Error: Not a folder!
1953 OUStringBuffer aMsg
;
1954 if ( getResourceType( xEnv
) == FTP
)
1957 aMsg
.appendAscii( "FTP over HTTP proxy: resource cannot "
1958 "be opened as folder! Wrong Open Mode!" );
1962 aMsg
.appendAscii( "Non-folder resource cannot be "
1963 "opened as folder! Wrong Open Mode!" );
1966 ucbhelper::cancelCommandExecution(
1968 lang::IllegalArgumentException(
1969 aMsg
.makeStringAndClear(),
1970 static_cast< cppu::OWeakObject
* >( this ),
1977 if ( rArg
.Sink
.is() )
1981 if ( ( rArg
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE
) ||
1982 ( rArg
.Mode
== ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE
) )
1984 // Currently(?) unsupported.
1985 ucbhelper::cancelCommandExecution(
1987 ucb::UnsupportedOpenModeException(
1989 static_cast< cppu::OWeakObject
* >( this ),
1990 sal_Int16( rArg
.Mode
) ) ),
1995 uno::Reference
< io::XOutputStream
> xOut
1996 = uno::Reference
< io::XOutputStream
>( rArg
.Sink
, uno::UNO_QUERY
);
2002 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2005 osl::MutexGuard
aGuard( m_aMutex
);
2008 new DAVResourceAccess( *m_xResAccess
.get() ) );
2011 xResAccess
->setFlags( rArg
.OpeningFlags
);
2012 DAVResource aResource
;
2013 std::vector
< OUString
> aHeaders
;
2015 xResAccess
->GET( xOut
, aHeaders
, aResource
, xEnv
);
2016 m_bDidGetOrHead
= true;
2019 osl::MutexGuard
aGuard( m_aMutex
);
2022 if ( !m_xCachedProps
.get())
2023 m_xCachedProps
.reset(
2024 new CachableContentProperties( aResource
) );
2026 m_xCachedProps
->addProperties( aResource
);
2029 new DAVResourceAccess( *xResAccess
.get() ) );
2032 catch ( DAVException
const & e
)
2034 cancelCommandExecution( e
, xEnv
);
2040 uno::Reference
< io::XActiveDataSink
> xDataSink
2041 = uno::Reference
< io::XActiveDataSink
>( rArg
.Sink
,
2043 if ( xDataSink
.is() )
2045 // PULL: wait for client read
2048 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2050 osl::MutexGuard
aGuard( m_aMutex
);
2053 new DAVResourceAccess( *m_xResAccess
.get() ) );
2056 xResAccess
->setFlags( rArg
.OpeningFlags
);
2058 // fill inputsream sync; return if all data present
2059 DAVResource aResource
;
2060 std::vector
< OUString
> aHeaders
;
2062 uno::Reference
< io::XInputStream
> xIn
2063 = xResAccess
->GET( aHeaders
, aResource
, xEnv
);
2064 m_bDidGetOrHead
= true;
2067 osl::MutexGuard
aGuard( m_aMutex
);
2070 if ( !m_xCachedProps
.get())
2071 m_xCachedProps
.reset(
2072 new CachableContentProperties( aResource
) );
2074 m_xCachedProps
->addProperties(
2075 aResource
.properties
);
2078 new DAVResourceAccess( *xResAccess
.get() ) );
2081 xDataSink
->setInputStream( xIn
);
2083 catch ( DAVException
const & e
)
2085 cancelCommandExecution( e
, xEnv
);
2091 // Note: aOpenCommand.Sink may contain an XStream
2092 // implementation. Support for this type of
2093 // sink is optional...
2094 ucbhelper::cancelCommandExecution(
2096 ucb::UnsupportedDataSinkException(
2098 static_cast< cppu::OWeakObject
* >( this ),
2111 const ucb::PostCommandArgument2
& rArg
,
2112 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
)
2113 throw( uno::Exception
)
2115 uno::Reference
< io::XActiveDataSink
> xSink( rArg
.Sink
, uno::UNO_QUERY
);
2120 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2122 osl::MutexGuard
aGuard( m_aMutex
);
2124 new DAVResourceAccess( *m_xResAccess
.get() ) );
2127 uno::Reference
< io::XInputStream
> xResult
2128 = xResAccess
->POST( rArg
.MediaType
,
2134 osl::MutexGuard
aGuard( m_aMutex
);
2136 new DAVResourceAccess( *xResAccess
.get() ) );
2139 xSink
->setInputStream( xResult
);
2141 catch ( DAVException
const & e
)
2143 cancelCommandExecution( e
, xEnv
, true );
2149 uno::Reference
< io::XOutputStream
> xResult( rArg
.Sink
, uno::UNO_QUERY
);
2154 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2156 osl::MutexGuard
aGuard( m_aMutex
);
2158 new DAVResourceAccess( *m_xResAccess
.get() ) );
2161 xResAccess
->POST( rArg
.MediaType
,
2168 osl::MutexGuard
aGuard( m_aMutex
);
2170 new DAVResourceAccess( *xResAccess
.get() ) );
2173 catch ( DAVException
const & e
)
2175 cancelCommandExecution( e
, xEnv
, true );
2181 ucbhelper::cancelCommandExecution(
2183 ucb::UnsupportedDataSinkException(
2185 static_cast< cppu::OWeakObject
* >( this ),
2194 void Content::queryChildren( ContentRefList
& rChildren
)
2196 // Obtain a list with a snapshot of all currently instantiated contents
2197 // from provider and extract the contents which are direct children
2200 ::ucbhelper::ContentRefList aAllContents
;
2201 m_xProvider
->queryExistingContents( aAllContents
);
2203 OUString aURL
= m_xIdentifier
->getContentIdentifier();
2204 sal_Int32 nURLPos
= aURL
.lastIndexOf( '/' );
2206 if ( nURLPos
!= ( aURL
.getLength() - 1 ) )
2208 // No trailing slash found. Append.
2212 sal_Int32 nLen
= aURL
.getLength();
2214 ::ucbhelper::ContentRefList::const_iterator it
= aAllContents
.begin();
2215 ::ucbhelper::ContentRefList::const_iterator end
= aAllContents
.end();
2219 ::ucbhelper::ContentImplHelperRef xChild
= (*it
);
2221 = xChild
->getIdentifier()->getContentIdentifier();
2223 // Is aURL a prefix of aChildURL?
2224 if ( ( aChildURL
.getLength() > nLen
) &&
2225 ( aChildURL
.startsWith( aURL
) ) )
2227 sal_Int32 nPos
= nLen
;
2228 nPos
= aChildURL
.indexOf( '/', nPos
);
2230 if ( ( nPos
== -1 ) ||
2231 ( nPos
== ( aChildURL
.getLength() - 1 ) ) )
2233 // No further slashes / only a final slash. It's a child!
2234 rChildren
.push_back(
2235 ::webdav_ucp::Content::ContentRef(
2236 static_cast< ::webdav_ucp::Content
* >(
2245 void Content::insert(
2246 const uno::Reference
< io::XInputStream
> & xInputStream
,
2247 bool bReplaceExisting
,
2248 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2249 throw( uno::Exception
)
2251 bool bTransient
, bCollection
;
2252 OUString aEscapedTitle
;
2253 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2256 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2258 bTransient
= m_bTransient
;
2259 bCollection
= m_bCollection
;
2260 aEscapedTitle
= m_aEscapedTitle
;
2261 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
2264 // Check, if all required properties are present.
2266 if ( aEscapedTitle
.isEmpty() )
2268 OSL_FAIL( "Content::insert - Title missing!" );
2270 uno::Sequence
< OUString
> aProps( 1 );
2271 aProps
[ 0 ] = "Title";
2272 ucbhelper::cancelCommandExecution(
2273 uno::makeAny( ucb::MissingPropertiesException(
2275 static_cast< cppu::OWeakObject
* >( this ),
2281 if ( !bReplaceExisting
)
2283 /* [RFC 2616] - HTTP
2285 The PUT method requests that the enclosed entity be stored under the
2286 supplied Request-URI. If the Request-URI refers to an already
2287 existing resource, the enclosed entity SHOULD be considered as a
2288 modified version of the one residing on the origin server.
2291 /* [RFC 2518] - WebDAV
2293 MKCOL creates a new collection resource at the location specified by
2294 the Request-URI. If the resource identified by the Request-URI is
2295 non-null then the MKCOL MUST fail.
2298 // ==> Complain on PUT, continue on MKCOL.
2299 if ( !bTransient
|| ( bTransient
&& !bCollection
) )
2301 ucb::UnsupportedNameClashException
aEx(
2302 OUString( "Unable to write without overwrite!" ),
2303 static_cast< cppu::OWeakObject
* >( this ),
2304 ucb::NameClash::ERROR
);
2306 uno::Reference
< task::XInteractionHandler
> xIH
;
2308 if ( Environment
.is() )
2309 xIH
= Environment
->getInteractionHandler();
2313 uno::Any
aExAsAny( uno::makeAny( aEx
) );
2315 rtl::Reference
< ucbhelper::SimpleInteractionRequest
> xRequest
2316 = new ucbhelper::SimpleInteractionRequest(
2318 ucbhelper::CONTINUATION_APPROVE
2319 | ucbhelper::CONTINUATION_DISAPPROVE
);
2320 xIH
->handle( xRequest
.get() );
2322 const sal_Int32 nResp
= xRequest
->getResponse();
2326 case ucbhelper::CONTINUATION_UNKNOWN
:
2327 // Not handled; throw.
2331 case ucbhelper::CONTINUATION_APPROVE
:
2332 // Continue -> Overwrite.
2333 bReplaceExisting
= true;
2336 case ucbhelper::CONTINUATION_DISAPPROVE
:
2338 throw ucb::CommandFailedException(
2340 uno::Reference
< uno::XInterface
>(),
2345 OSL_FAIL( "Content::insert - "
2346 "Unknown interaction selection!" );
2347 throw ucb::CommandFailedException(
2348 OUString( "Unknown interaction selection!" ),
2349 uno::Reference
< uno::XInterface
>(),
2364 // Assemble new content identifier...
2365 OUString aURL
= getParentURL();
2366 if ( aURL
.lastIndexOf( '/' ) != ( aURL
.getLength() - 1 ) )
2369 aURL
+= aEscapedTitle
;
2373 xResAccess
->setURL( aURL
);
2376 xResAccess
->MKCOL( Environment
);
2378 xResAccess
->PUT( xInputStream
, Environment
);
2380 catch ( DAVException
const & except
)
2384 if ( except
.getStatus() == SC_METHOD_NOT_ALLOWED
)
2386 // [RFC 2518] - WebDAV
2387 // 405 (Method Not Allowed) - MKCOL can only be
2388 // executed on a deleted/non-existent resource.
2390 if ( bReplaceExisting
)
2392 // Destroy old resource.
2395 xResAccess
->DESTROY( Environment
);
2397 catch ( DAVException
const & e
)
2399 cancelCommandExecution( e
, Environment
, true );
2403 // Insert (recursion!).
2404 insert( xInputStream
, bReplaceExisting
, Environment
);
2407 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2409 new DAVResourceAccess( *xResAccess
.get() ) );
2420 NeonUri
aURI( aURL
);
2421 aTitle
= aURI
.GetPathBaseNameUnescaped();
2423 catch ( DAVException
const & )
2427 ucbhelper::cancelCommandExecution(
2429 ucb::NameClashException(
2431 static_cast< cppu::OWeakObject
* >( this ),
2432 task::InteractionClassification_ERROR
,
2440 cancelCommandExecution( except
, Environment
, true );
2445 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2446 m_xIdentifier
= new ::ucbhelper::ContentIdentifier( aURL
);
2452 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2453 m_bTransient
= false;
2458 if ( !xInputStream
.is() )
2460 ucbhelper::cancelCommandExecution(
2462 ucb::MissingInputStreamException(
2464 static_cast< cppu::OWeakObject
* >( this ) ) ),
2471 xResAccess
->PUT( xInputStream
, Environment
);
2473 catch ( DAVException
const & e
)
2475 cancelCommandExecution( e
, Environment
, true );
2481 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2482 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
2487 void Content::transfer(
2488 const ucb::TransferInfo
& rArgs
,
2489 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2490 throw( uno::Exception
)
2492 uno::Reference
< ucb::XContentIdentifier
> xIdentifier
;
2493 uno::Reference
< ucb::XContentProvider
> xProvider
;
2494 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2497 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2499 xIdentifier
.set( m_xIdentifier
);
2500 xProvider
.set( m_xProvider
.get() );
2501 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
2504 OUString aTargetURI
;
2507 NeonUri
sourceURI( rArgs
.SourceURL
);
2508 NeonUri
targetURI( xIdentifier
->getContentIdentifier() );
2509 aTargetURI
= targetURI
.GetPathBaseNameUnescaped();
2511 // Check source's and target's URL scheme
2513 const OUString aScheme
= sourceURI
.GetScheme().toAsciiLowerCase();
2514 if ( aScheme
== WEBDAV_URL_SCHEME
)
2516 sourceURI
.SetScheme(
2517 OUString( HTTP_URL_SCHEME
) );
2519 else if ( aScheme
== DAV_URL_SCHEME
)
2521 sourceURI
.SetScheme(
2522 OUString( HTTP_URL_SCHEME
) );
2524 else if ( aScheme
== DAVS_URL_SCHEME
)
2526 sourceURI
.SetScheme(
2527 OUString( HTTPS_URL_SCHEME
) );
2531 if ( aScheme
!= HTTP_URL_SCHEME
&& aScheme
!= HTTPS_URL_SCHEME
)
2533 ucbhelper::cancelCommandExecution(
2535 ucb::InteractiveBadTransferURLException(
2536 OUString( "Unsupported URL scheme!" ),
2537 static_cast< cppu::OWeakObject
* >( this ) ) ),
2543 if ( targetURI
.GetScheme().toAsciiLowerCase() == WEBDAV_URL_SCHEME
)
2544 targetURI
.SetScheme(
2545 OUString( HTTP_URL_SCHEME
) );
2546 else if ( targetURI
.GetScheme().toAsciiLowerCase() == DAV_URL_SCHEME
)
2547 targetURI
.SetScheme(
2548 OUString( HTTP_URL_SCHEME
) );
2550 // @@@ This implementation of 'transfer' only works
2551 // if the source and target are located at same host.
2552 // (Neon does not support cross-server copy/move)
2554 // Check for same host
2556 if ( !sourceURI
.GetHost().isEmpty() &&
2557 ( sourceURI
.GetHost() != targetURI
.GetHost() ) )
2559 ucbhelper::cancelCommandExecution(
2560 uno::makeAny( ucb::InteractiveBadTransferURLException(
2561 OUString( "Different hosts!" ),
2562 static_cast< cppu::OWeakObject
* >( this ) ) ),
2567 OUString aTitle
= rArgs
.NewTitle
;
2569 if ( aTitle
.isEmpty() )
2570 aTitle
= sourceURI
.GetPathBaseNameUnescaped();
2572 if ( aTitle
== "/" )
2578 targetURI
.AppendPath( aTitle
);
2580 OUString aTargetURL
= xIdentifier
->getContentIdentifier();
2581 if ( ( aTargetURL
.lastIndexOf( '/' ) + 1 )
2582 != aTargetURL
.getLength() )
2585 aTargetURL
+= aTitle
;
2587 uno::Reference
< ucb::XContentIdentifier
> xTargetId
2588 = new ::ucbhelper::ContentIdentifier( aTargetURL
);
2590 DAVResourceAccess
aSourceAccess( m_xContext
,
2591 xResAccess
->getSessionFactory(),
2592 sourceURI
.GetURI() );
2594 if ( rArgs
.MoveData
== sal_True
)
2596 uno::Reference
< ucb::XContentIdentifier
> xId
2597 = new ::ucbhelper::ContentIdentifier( rArgs
.SourceURL
);
2599 // Note: The static cast is okay here, because its sure that
2600 // xProvider is always the WebDAVContentProvider.
2601 rtl::Reference
< Content
> xSource
2602 = static_cast< Content
* >(
2603 xProvider
->queryContent( xId
).get() );
2605 // [RFC 2518] - WebDAV
2606 // If a resource exists at the destination and the Overwrite
2607 // header is "T" then prior to performing the move the server
2608 // MUST perform a DELETE with "Depth: infinity" on the
2609 // destination resource. If the Overwrite header is set to
2610 // "F" then the operation will fail.
2612 aSourceAccess
.MOVE( sourceURI
.GetPath(),
2615 == ucb::NameClash::OVERWRITE
,
2620 // Propagate destruction to listeners.
2621 xSource
->destroy( true );
2624 // DAV resources store all additional props on server!
2625 // // Rename own and all children's Additional Core Properties.
2626 // renameAdditionalPropertySet( xId->getContentIdentifier(),
2627 // xTargetId->getContentIdentifier(),
2632 // [RFC 2518] - WebDAV
2633 // If a resource exists at the destination and the Overwrite
2634 // header is "T" then prior to performing the copy the server
2635 // MUST perform a DELETE with "Depth: infinity" on the
2636 // destination resource. If the Overwrite header is set to
2637 // "F" then the operation will fail.
2639 aSourceAccess
.COPY( sourceURI
.GetPath(),
2642 == ucb::NameClash::OVERWRITE
,
2645 // DAV resources store all additional props on server!
2646 // // Copy own and all children's Additional Core Properties.
2647 // copyAdditionalPropertySet( xId->getContentIdentifier(),
2648 // xTargetId->getContentIdentifier(),
2652 // Note: The static cast is okay here, because its sure that
2653 // xProvider is always the WebDAVContentProvider.
2654 rtl::Reference
< Content
> xTarget
2655 = static_cast< Content
* >(
2656 xProvider
->queryContent( xTargetId
).get() );
2658 // Announce transferred content in its new folder.
2659 xTarget
->inserted();
2661 catch ( ucb::IllegalIdentifierException
const & )
2665 catch ( DAVException
const & e
)
2667 // [RFC 2518] - WebDAV
2668 // 412 (Precondition Failed) - The server was unable to maintain
2669 // the liveness of the properties listed in the propertybehavior
2670 // XML element or the Overwrite header is "F" and the state of
2671 // the destination resource is non-null.
2673 if ( e
.getStatus() == SC_PRECONDITION_FAILED
)
2675 switch ( rArgs
.NameClash
)
2677 case ucb::NameClash::ERROR
:
2679 ucbhelper::cancelCommandExecution(
2681 ucb::NameClashException(
2683 static_cast< cppu::OWeakObject
* >( this ),
2684 task::InteractionClassification_ERROR
,
2690 case ucb::NameClash::OVERWRITE
:
2693 case ucb::NameClash::KEEP
: // deprecated
2694 case ucb::NameClash::RENAME
:
2695 case ucb::NameClash::ASK
:
2698 ucbhelper::cancelCommandExecution(
2700 ucb::UnsupportedNameClashException(
2702 static_cast< cppu::OWeakObject
* >( this ),
2703 rArgs
.NameClash
) ),
2710 cancelCommandExecution( e
, Environment
, true );
2715 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2716 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
2721 void Content::destroy( bool bDeletePhysical
)
2722 throw( uno::Exception
)
2724 // @@@ take care about bDeletePhysical -> trashcan support
2725 uno::Reference
< ucb::XContent
> xThis
= this;
2729 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2731 // Process instantiated children...
2733 ::webdav_ucp::Content::ContentRefList aChildren
;
2734 queryChildren( aChildren
);
2736 ContentRefList::const_iterator it
= aChildren
.begin();
2737 ContentRefList::const_iterator end
= aChildren
.end();
2741 (*it
)->destroy( bDeletePhysical
);
2747 bool Content::supportsExclusiveWriteLock(
2748 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2750 if ( getResourceType( Environment
) == DAV
)
2752 if ( m_xCachedProps
.get() )
2754 uno::Sequence
< ucb::LockEntry
> aSupportedLocks
;
2755 if ( m_xCachedProps
->getValue( DAVProperties::SUPPORTEDLOCK
)
2756 >>= aSupportedLocks
)
2758 for ( sal_Int32 n
= 0; n
< aSupportedLocks
.getLength(); ++n
)
2760 if ( aSupportedLocks
[ n
].Scope
2761 == ucb::LockScope_EXCLUSIVE
&&
2762 aSupportedLocks
[ n
].Type
2763 == ucb::LockType_WRITE
)
2774 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2775 throw( uno::Exception
)
2779 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2781 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2782 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
2787 <<= OUString("http://ucb.openoffice.org");
2790 ucb::LockScope_EXCLUSIVE
,
2791 ucb::LockType_WRITE
,
2792 ucb::LockDepth_ZERO
,
2794 180, // lock timeout in secs
2795 //-1, // infinite lock
2796 uno::Sequence
< OUString
>() );
2798 xResAccess
->LOCK( aLock
, Environment
);
2802 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2803 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
2806 catch ( DAVException
const & e
)
2808 cancelCommandExecution( e
, Environment
, false );
2814 void Content::unlock(
2815 const uno::Reference
< ucb::XCommandEnvironment
>& Environment
)
2816 throw( uno::Exception
)
2820 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
2822 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2823 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
2826 xResAccess
->UNLOCK( Environment
);
2830 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
2831 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
2834 catch ( DAVException
const & e
)
2836 cancelCommandExecution( e
, Environment
, false );
2842 bool Content::exchangeIdentity(
2843 const uno::Reference
< ucb::XContentIdentifier
>& xNewId
)
2848 osl::ClearableGuard
< osl::Mutex
> aGuard( m_aMutex
);
2850 uno::Reference
< ucb::XContent
> xThis
= this;
2852 // Already persistent?
2855 OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
2859 // Exchange own identitity.
2861 // Fail, if a content with given id already exists.
2862 // if ( !hasData( xNewId ) )
2864 OUString aOldURL
= m_xIdentifier
->getContentIdentifier();
2867 if ( exchange( xNewId
) )
2869 // Process instantiated children...
2871 ContentRefList aChildren
;
2872 queryChildren( aChildren
);
2874 ContentRefList::const_iterator it
= aChildren
.begin();
2875 ContentRefList::const_iterator end
= aChildren
.end();
2879 ContentRef xChild
= (*it
);
2881 // Create new content identifier for the child...
2882 uno::Reference
< ucb::XContentIdentifier
>
2883 xOldChildId
= xChild
->getIdentifier();
2884 OUString aOldChildURL
2885 = xOldChildId
->getContentIdentifier();
2886 OUString aNewChildURL
2887 = aOldChildURL
.replaceAt(
2889 aOldURL
.getLength(),
2890 xNewId
->getContentIdentifier() );
2891 uno::Reference
< ucb::XContentIdentifier
> xNewChildId
2892 = new ::ucbhelper::ContentIdentifier( aNewChildURL
);
2894 if ( !xChild
->exchangeIdentity( xNewChildId
) )
2903 OSL_FAIL( "Content::exchangeIdentity - "
2904 "Panic! Cannot exchange identity!" );
2909 bool Content::isFolder(
2910 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
2911 throw( uno::Exception
, std::exception
)
2914 osl::MutexGuard
aGuard( m_aMutex
);
2917 return m_bCollection
;
2920 uno::Sequence
< beans::Property
> aProperties( 1 );
2921 aProperties
[ 0 ].Name
= "IsFolder";
2922 aProperties
[ 0 ].Handle
= -1;
2923 uno::Reference
< sdbc::XRow
> xRow( getPropertyValues( aProperties
, xEnv
) );
2928 return xRow
->getBoolean( 1 );
2930 catch ( sdbc::SQLException
const & )
2939 uno::Any
Content::MapDAVException( const DAVException
& e
, bool bWrite
)
2941 // Map DAVException...
2942 uno::Any aException
;
2947 aURL
= getParentURL();
2948 if ( aURL
.lastIndexOf('/') != ( aURL
.getLength() - 1 ) )
2951 aURL
+= m_aEscapedTitle
;
2955 aURL
= m_xIdentifier
->getContentIdentifier();
2958 switch ( e
.getStatus() )
2962 uno::Sequence
< uno::Any
> aArgs( 1 );
2963 aArgs
[ 0 ] <<= beans::PropertyValue(
2964 OUString("Uri"), -1,
2966 beans::PropertyState_DIRECT_VALUE
);
2969 ucb::InteractiveAugmentedIOException(
2970 OUString("Not found!"),
2971 static_cast< cppu::OWeakObject
* >( this ),
2972 task::InteractionClassification_ERROR
,
2973 ucb::IOErrorCode_NOT_EXISTING
,
2981 switch ( e
.getError() )
2983 case DAVException::DAV_HTTP_ERROR
:
2987 ucb::InteractiveNetworkWriteException(
2989 static_cast< cppu::OWeakObject
* >( this ),
2990 task::InteractionClassification_ERROR
,
2994 ucb::InteractiveNetworkReadException(
2996 static_cast< cppu::OWeakObject
* >( this ),
2997 task::InteractionClassification_ERROR
,
3002 case DAVException::DAV_HTTP_LOOKUP
:
3004 ucb::InteractiveNetworkResolveNameException(
3006 static_cast< cppu::OWeakObject
* >( this ),
3007 task::InteractionClassification_ERROR
,
3011 // @@@ No matching InteractiveNetwork*Exception
3012 // case DAVException::DAV_HTTP_AUTH:
3015 // @@@ No matching InteractiveNetwork*Exception
3016 // case DAVException::DAV_HTTP_AUTHPROXY:
3019 case DAVException::DAV_HTTP_CONNECT
:
3021 ucb::InteractiveNetworkConnectException(
3023 static_cast< cppu::OWeakObject
* >( this ),
3024 task::InteractionClassification_ERROR
,
3028 // @@@ No matching InteractiveNetwork*Exception
3029 // case DAVException::DAV_HTTP_TIMEOUT:
3032 // @@@ No matching InteractiveNetwork*Exception
3033 // case DAVException::DAV_HTTP_REDIRECT:
3036 // @@@ No matching InteractiveNetwork*Exception
3037 // case DAVException::DAV_SESSION_CREATE:
3040 case DAVException::DAV_INVALID_ARG
:
3042 lang::IllegalArgumentException(
3044 static_cast< cppu::OWeakObject
* >( this ),
3048 case DAVException::DAV_LOCKED
:
3050 ucb::InteractiveLockingLockedException(
3051 OUString("Locked!"),
3052 static_cast< cppu::OWeakObject
* >( this ),
3053 task::InteractionClassification_ERROR
,
3055 sal_False
); // not SelfOwned
3058 case DAVException::DAV_LOCKED_SELF
:
3060 ucb::InteractiveLockingLockedException(
3061 OUString("Locked (self!)"),
3062 static_cast< cppu::OWeakObject
* >( this ),
3063 task::InteractionClassification_ERROR
,
3065 sal_True
); // SelfOwned
3068 case DAVException::DAV_NOT_LOCKED
:
3070 ucb::InteractiveLockingNotLockedException(
3071 OUString("Not locked!"),
3072 static_cast< cppu::OWeakObject
* >( this ),
3073 task::InteractionClassification_ERROR
,
3077 case DAVException::DAV_LOCK_EXPIRED
:
3079 ucb::InteractiveLockingLockExpiredException(
3080 OUString("Lock expired!"),
3081 static_cast< cppu::OWeakObject
* >( this ),
3082 task::InteractionClassification_ERROR
,
3088 ucb::InteractiveNetworkGeneralException(
3090 static_cast< cppu::OWeakObject
* >( this ),
3091 task::InteractionClassification_ERROR
);
3100 bool Content::shouldAccessNetworkAfterException( const DAVException
& e
)
3102 if ( ( e
.getStatus() == SC_NOT_FOUND
) ||
3103 ( e
.getError() == DAVException::DAV_HTTP_LOOKUP
) ||
3104 ( e
.getError() == DAVException::DAV_HTTP_CONNECT
) ||
3105 ( e
.getError() == DAVException::DAV_HTTP_AUTH
) ||
3106 ( e
.getError() == DAVException::DAV_HTTP_AUTHPROXY
) )
3113 void Content::cancelCommandExecution(
3114 const DAVException
& e
,
3115 const uno::Reference
< ucb::XCommandEnvironment
> & xEnv
,
3116 bool bWrite
/* = sal_False */ )
3117 throw ( uno::Exception
)
3119 ucbhelper::cancelCommandExecution( MapDAVException( e
, bWrite
), xEnv
);
3125 Content::getBaseURI( const std::unique_ptr
< DAVResourceAccess
> & rResAccess
)
3127 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
3129 // First, try to obtain value of response header "Content-Location".
3130 if ( m_xCachedProps
.get() )
3133 m_xCachedProps
->getValue( OUString( "Content-Location" ) ) >>= aLocation
;
3134 if ( !aLocation
.isEmpty() )
3138 // Do not use m_xIdentifier->getContentIdentifier() because it
3139 // for example does not reflect redirects applied to requests
3140 // done using the original URI but m_xResAccess' URI does.
3141 return rtl::Uri::convertRelToAbs( rResAccess
->getURL(),
3144 catch ( rtl::MalformedUriException
const & )
3150 return OUString( rResAccess
->getURL() );
3154 Content::ResourceType
Content::getResourceType(
3155 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
,
3156 const std::unique_ptr
< DAVResourceAccess
> & rResAccess
,
3157 bool * networkAccessAllowed
)
3158 throw ( uno::Exception
, std::exception
)
3161 osl::MutexGuard
g(m_aMutex
);
3162 if (m_eResourceType
!= UNKNOWN
) {
3163 return m_eResourceType
;
3167 ResourceType eResourceType
= UNKNOWN
;
3169 const OUString
& rURL
= rResAccess
->getURL();
3170 const OUString
aScheme(
3171 rURL
.copy( 0, rURL
.indexOf( ':' ) ).toAsciiLowerCase() );
3173 if ( aScheme
== FTP_URL_SCHEME
)
3175 eResourceType
= FTP
;
3181 // Try to fetch some frequently used property value, e.g. those
3182 // used when loading documents... along with identifying whether
3183 // this is a DAV resource.
3184 std::vector
< DAVResource
> resources
;
3185 std::vector
< OUString
> aPropNames
;
3186 uno::Sequence
< beans::Property
> aProperties( 5 );
3187 aProperties
[ 0 ].Name
= "IsFolder";
3188 aProperties
[ 1 ].Name
= "IsDocument";
3189 aProperties
[ 2 ].Name
= "IsReadOnly";
3190 aProperties
[ 3 ].Name
= "MediaType";
3191 aProperties
[ 4 ].Name
= DAVProperties::SUPPORTEDLOCK
;
3193 ContentProperties::UCBNamesToDAVNames( aProperties
, aPropNames
);
3195 rResAccess
->PROPFIND( DAVZERO
, aPropNames
, resources
, xEnv
);
3197 if ( resources
.size() == 1 )
3199 osl::MutexGuard
g(m_aMutex
);
3200 m_xCachedProps
.reset(
3201 new CachableContentProperties( resources
[ 0 ] ) );
3202 m_xCachedProps
->containsAllNames(
3203 aProperties
, m_aFailedPropNames
);
3206 eResourceType
= DAV
;
3208 catch ( DAVException
const & e
)
3210 rResAccess
->resetUri();
3212 if ( e
.getStatus() == SC_METHOD_NOT_ALLOWED
)
3214 // Status SC_METHOD_NOT_ALLOWED is a safe indicator that the
3215 // resource is NON_DAV
3216 eResourceType
= NON_DAV
;
3218 else if (networkAccessAllowed
!= 0)
3220 *networkAccessAllowed
= *networkAccessAllowed
3221 && shouldAccessNetworkAfterException(e
);
3226 osl::MutexGuard
g(m_aMutex
);
3227 if (m_eResourceType
== UNKNOWN
) {
3228 m_eResourceType
= eResourceType
;
3231 eResourceType
!= m_eResourceType
, "ucb.ucp.webdav",
3232 "different resource types for <" << rURL
<< ">: "
3233 << +eResourceType
<< " vs. " << +m_eResourceType
);
3235 return m_eResourceType
;
3239 Content::ResourceType
Content::getResourceType(
3240 const uno::Reference
< ucb::XCommandEnvironment
>& xEnv
)
3241 throw ( uno::Exception
, std::exception
)
3243 std::unique_ptr
< DAVResourceAccess
> xResAccess
;
3245 osl::MutexGuard
aGuard( m_aMutex
);
3246 xResAccess
.reset( new DAVResourceAccess( *m_xResAccess
.get() ) );
3248 Content::ResourceType
const ret
= getResourceType( xEnv
, xResAccess
);
3250 osl::Guard
< osl::Mutex
> aGuard( m_aMutex
);
3251 m_xResAccess
.reset( new DAVResourceAccess( *xResAccess
.get() ) );
3256 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */