bump product version to 5.0.4.1
[LibreOffice.git] / ucb / source / ucp / webdav-neon / webdavcontent.cxx
blobec74be984cd7a503fd809c413b32e5f85b6ac694
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 /**************************************************************************
31 TODO
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
105 Content::Content(
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 ),
115 m_bLocked( false ),
116 m_bCollection( false ),
117 m_bDidGetOrHead( false )
121 m_xResAccess.reset( new DAVResourceAccess(
122 rxContext,
123 rSessionFactory,
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
137 Content::Content(
138 const uno::Reference< uno::XComponentContext >& rxContext,
139 ContentProvider* pProvider,
140 const uno::Reference< ucb::XContentIdentifier >& Identifier,
141 rtl::Reference< DAVSessionFactory > const & rSessionFactory,
142 bool isCollection )
143 throw ( ucb::ContentCreationException )
144 : ContentImplHelper( rxContext, pProvider, Identifier ),
145 m_eResourceType( UNKNOWN ),
146 m_pProvider( pProvider ),
147 m_bTransient( true ),
148 m_bLocked( false ),
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!!!
166 // virtual
167 Content::~Content()
169 if (m_bLocked)
170 unlock(uno::Reference< ucb::XCommandEnvironment >());
175 // XInterface methods.
179 // virtual
180 void SAL_CALL Content::acquire()
181 throw( )
183 ContentImplHelper::acquire();
187 // virtual
188 void SAL_CALL Content::release()
189 throw( )
191 ContentImplHelper::release();
195 // virtual
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(
202 rType,
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(
217 m_xContext,
218 xIH,
219 uno::Reference< ucb::XProgressHandler >() ) );
221 return isFolder( xCmdEnv ) ? aRet : uno::Any();
223 catch ( uno::RuntimeException const & )
225 throw;
227 catch ( uno::Exception const & )
229 return uno::Any();
232 return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType );
237 // XTypeProvider methods.
241 XTYPEPROVIDER_COMMON_IMPL( Content );
244 // virtual
245 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
246 throw( uno::RuntimeException, std::exception )
248 bool bFolder = false;
251 bFolder
252 = isFolder( uno::Reference< ucb::XCommandEnvironment >() );
254 catch ( uno::RuntimeException const & )
256 throw;
258 catch ( uno::Exception const & )
262 cppu::OTypeCollection * pCollection = 0;
264 if ( bFolder )
266 static cppu::OTypeCollection* pFolderTypes = 0;
268 pCollection = pFolderTypes;
269 if ( !pCollection )
271 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
273 pCollection = pFolderTypes;
274 if ( !pCollection )
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;
293 else {
294 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
297 else
299 static cppu::OTypeCollection* pDocumentTypes = 0;
301 pCollection = pDocumentTypes;
302 if ( !pCollection )
304 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
306 pCollection = pDocumentTypes;
307 if ( !pCollection )
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;
325 else {
326 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
330 return (*pCollection).getTypes();
335 // XServiceInfo methods.
339 // virtual
340 OUString SAL_CALL Content::getImplementationName()
341 throw( uno::RuntimeException, std::exception )
343 return OUString( "com.sun.star.comp.ucb.WebDAVContent" );
347 // virtual
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;
353 return aSNS;
358 // XContent methods.
362 // virtual
363 OUString SAL_CALL Content::getContentType()
364 throw( uno::RuntimeException, std::exception )
366 bool bFolder = false;
369 bFolder
370 = isFolder( uno::Reference< ucb::XCommandEnvironment >() );
372 catch ( uno::RuntimeException const & )
374 throw;
376 catch ( uno::Exception const & )
380 if ( bFolder )
381 return OUString( WEBDAV_COLLECTION_TYPE );
383 return OUString( WEBDAV_CONTENT_TYPE );
388 // XCommandProcessor methods.
392 // virtual
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") );
405 uno::Any aRet;
407 if ( aCommand.Name == "getPropertyValues" )
410 // 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 ),
420 -1 ) ),
421 Environment );
422 // Unreachable
425 aRet <<= getPropertyValues( Properties, Environment );
427 else if ( aCommand.Name == "setPropertyValues" )
430 // 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 ),
440 -1 ) ),
441 Environment );
442 // Unreachable
445 if ( !aProperties.getLength() )
447 ucbhelper::cancelCommandExecution(
448 uno::makeAny( lang::IllegalArgumentException(
449 OUString( "No properties!" ),
450 static_cast< cppu::OWeakObject * >( this ),
451 -1 ) ),
452 Environment );
453 // Unreachable
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" )
471 // getCommandInfo
474 // Note: Implemented by base class.
475 aRet <<= getCommandInfo( Environment, false );
477 else if ( aCommand.Name == "open" )
480 // 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 ),
491 -1 ) ),
492 Environment );
493 // Unreachable
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 ) )
510 lock( Environment );
512 else if ( aCommand.Name == "insert" )
515 // 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 ),
525 -1 ) ),
526 Environment );
527 // Unreachable
530 insert( arg.Data, arg.ReplaceExisting, Environment );
532 else if ( aCommand.Name == "delete" )
535 // 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 )
545 // {
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 );
562 // Unreachable
564 // }
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 ) )
575 // transfer
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 ),
586 -1 ) ),
587 Environment );
588 // Unreachable
591 transfer( transferArgs, Environment );
593 else if ( aCommand.Name == "post" )
596 // 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 ),
606 -1 ) ),
607 Environment );
608 // Unreachable
611 post( aArg, Environment );
613 else if ( aCommand.Name == "lock" && supportsExclusiveWriteLock( Environment ) )
616 // lock
619 lock( Environment );
621 else if ( aCommand.Name == "unlock" && supportsExclusiveWriteLock( Environment ) )
624 // unlock
627 unlock( Environment );
629 else if ( aCommand.Name == "createNewContent" && isFolder( Environment ) )
632 // createNewContent
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 ),
642 -1 ) ),
643 Environment );
644 // Unreachable
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 ),
658 -1 ) ),
659 Environment );
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" )
683 OUString sPropName;
684 if ( !( aCommand.Argument >>= sPropName ) )
686 ucbhelper::cancelCommandExecution(
687 uno::makeAny( lang::IllegalArgumentException(
688 "Wrong argument type!",
689 static_cast< cppu::OWeakObject * >( this ),
690 -1 ) ),
691 Environment );
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 );
709 else
712 // Unsupported command
715 ucbhelper::cancelCommandExecution(
716 uno::makeAny( ucb::UnsupportedCommandException(
717 aCommand.Name,
718 static_cast< cppu::OWeakObject * >( this ) ) ),
719 Environment );
720 // Unreachable
723 OSL_TRACE( "<<<<< Content::execute: end: command: %s",
724 OUStringToOString( aCommand.Name,
725 RTL_TEXTENCODING_UTF8 ).getStr() );
727 return aRet;
731 // virtual
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() ) );
742 xResAccess->abort();
744 osl::Guard< osl::Mutex > aGuard( m_aMutex );
745 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
748 catch ( DAVException const & )
750 // abort failed!
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,
766 std::exception )
768 // if ( m_bTransient )
769 // @@@ ???
771 if ( aCmdArg.Property.Name.isEmpty() )
772 throw lang::IllegalArgumentException(
773 "\"addProperty\" with empty Property.Name",
774 static_cast< cppu::OWeakObject * >( this ),
775 -1 );
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 */ )
806 ->hasPropertyByName(
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 );
856 else
858 if ( shouldAccessNetworkAfterException( e ) )
862 ResourceType eType = getResourceType( xEnv );
863 switch ( eType )
865 case UNKNOWN:
866 case DAV:
867 throw lang::IllegalArgumentException();
869 case FTP:
870 case NON_DAV:
871 // Store property locally.
872 ContentImplHelper::addProperty(
873 bIsSpecial ? aSpecialName : aCmdArg.Property.Name,
874 aCmdArg.Property.Attributes, aCmdArg.DefaultValue );
875 break;
877 default:
878 OSL_FAIL( "Content::addProperty - "
879 "Unsupported resource type!" );
880 break;
883 catch ( uno::Exception const & )
885 OSL_FAIL( "Content::addProperty - "
886 "Unable to determine resource type!" );
889 else
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,
903 std::exception )
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 ),
930 Name,
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 );
944 else
946 if ( shouldAccessNetworkAfterException( e ) )
950 ResourceType eType = getResourceType( xEnv );
951 switch ( eType )
953 case UNKNOWN:
954 case DAV:
955 throw beans::UnknownPropertyException();
957 case FTP:
958 case NON_DAV:
959 // Try to remove property from local store.
960 ContentImplHelper::removeProperty( Name );
961 break;
963 default:
964 OSL_FAIL( "Content::removeProperty - "
965 "Unsupported resource type!" );
966 break;
969 catch ( uno::Exception const & )
971 OSL_FAIL( "Content::removeProperty - "
972 "Unable to determine resource type!" );
975 else
977 OSL_FAIL( "Content::removeProperty - "
978 "Unable to determine resource type!" );
979 // throw beans::UnknownPropertyException();
985 // virtual
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 >());
1004 // virtual
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.
1020 // virtual
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 );
1029 // document.
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;
1043 // folder.
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;
1051 return aSeq;
1055 // virtual
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() )
1074 aURL += "/";
1076 bool isCollection;
1077 if ( Info.Type == WEBDAV_COLLECTION_TYPE )
1079 aURL += "New_Collection";
1080 isCollection = true;
1082 else
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,
1095 m_pProvider,
1096 xId,
1097 m_xResAccess->getSessionFactory(),
1098 isCollection );
1100 catch ( ucb::ContentCreationException & )
1102 return uno::Reference< ucb::XContent >();
1107 // virtual
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 );
1127 if ( nPos1 != -1 )
1128 nPos1 = aURL.lastIndexOf( '/', nPos1 );
1130 if ( nPos1 == -1 )
1131 return OUString();
1133 return OUString( aURL.copy( 0, nPos + 1 ) );
1138 // Non-interface methods.
1142 // static
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();
1156 if ( nCount )
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 );
1172 else
1174 // Process local Additional Properties.
1175 if ( !bTriedToGetAdditionalPropSet && !xAdditionalPropSet.is() )
1177 xAdditionalPropSet
1178 = uno::Reference< beans::XPropertySet >(
1179 rProvider->getAdditionalPropertySet( rContentId,
1180 false ),
1181 uno::UNO_QUERY );
1182 bTriedToGetAdditionalPropSet = true;
1185 if ( !xAdditionalPropSet.is() ||
1186 !xRow->appendPropertySetValue(
1187 xAdditionalPropSet, rProp ) )
1189 // Append empty entry.
1190 xRow->appendVoid( rProp );
1195 else
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;
1207 while ( it != end )
1209 if ( pProvider->getProperty( (*it).first, aProp ) )
1210 xRow->appendObject( aProp, (*it).second.value() );
1212 ++it;
1215 // Append all local Additional Properties.
1216 uno::Reference< beans::XPropertySet > xSet(
1217 rProvider->getAdditionalPropertySet( rContentId, false ),
1218 uno::UNO_QUERY );
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.
1256 bHasAll = true;
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 );
1275 if ( eType == DAV )
1277 // cache lookup... getResourceType may fill the props cache via
1278 // PROPFIND!
1279 if ( m_xCachedProps.get() )
1281 xCachedProps.reset(
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
1289 // needed.
1290 bHasAll = true;
1293 // use the cached ContentProperties instance
1294 xProps.reset( new ContentProperties( *xCachedProps.get() ) );
1297 if ( !bHasAll )
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();
1318 while ( it != end )
1320 if ( *it == rName )
1321 break;
1323 ++it;
1326 if ( it == end )
1328 aProperties[ nProps ] = rProperties[ n ];
1329 nProps++;
1333 aProperties.realloc( nProps );
1335 else
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() )
1354 if ( xProps.get())
1355 xProps->addProperties(
1356 aPropNames,
1357 ContentProperties( resources[ 0 ] ));
1358 else
1359 xProps.reset(
1360 new ContentProperties( resources[ 0 ] ) );
1363 catch ( DAVException const & e )
1365 bNetworkAccessAllowed = bNetworkAccessAllowed
1366 && shouldAccessNetworkAfterException( e );
1368 if ( !bNetworkAccessAllowed )
1370 cancelCommandExecution( e, xEnv );
1371 // unreachable
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
1388 // request.
1390 std::vector< OUString > aHeaderNames;
1391 ContentProperties::UCBNamesToHTTPNames(
1392 rProperties,
1393 aHeaderNames,
1394 true /* bIncludeUnmatched */ );
1396 if ( !aHeaderNames.empty() )
1400 DAVResource resource;
1401 xResAccess->HEAD( aHeaderNames, resource, xEnv );
1402 m_bDidGetOrHead = true;
1404 if ( xProps.get() )
1405 xProps->addProperties(
1406 aMissingProps,
1407 ContentProperties( resource ) );
1408 else
1409 xProps.reset ( new ContentProperties( resource ) );
1411 if ( m_eResourceType == NON_DAV )
1412 xProps->addProperties( aMissingProps,
1413 ContentProperties(
1414 aUnescapedTitle,
1415 false ) );
1417 catch ( DAVException const & e )
1419 bNetworkAccessAllowed
1420 = shouldAccessNetworkAfterException( e );
1422 if ( !bNetworkAccessAllowed )
1424 cancelCommandExecution( e, xEnv );
1425 // unreachable
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.
1445 if ( eType == DAV )
1447 //xProps.reset(
1448 // new ContentProperties( aUnescapedTitle ) );
1449 xProps->addProperty(
1450 OUString( "Title" ),
1451 uno::makeAny( aUnescapedTitle ),
1452 true );
1454 else
1456 if ( !xProps.get() )
1457 xProps.reset( new ContentProperties( aUnescapedTitle, false ) );
1458 else
1459 xProps->addProperty(
1460 OUString( "Title" ),
1461 uno::makeAny( aUnescapedTitle ),
1462 true );
1464 xProps->addProperty(
1465 OUString( "IsFolder" ),
1466 uno::makeAny( false ),
1467 true );
1468 xProps->addProperty(
1469 OUString( "IsDocument" ),
1470 uno::makeAny( true ),
1471 true );
1474 else
1476 // No server access for just created (not yet committed) objects.
1477 // Only a minimal set of properties supported at this stage.
1478 if (m_bTransient)
1479 xProps.reset( new ContentProperties( aUnescapedTitle,
1480 m_bCollection ) );
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 ) ),
1493 true );
1495 else if ( rName == "CreatableContentsInfo" )
1497 // Add CreatableContentsInfo property, if requested.
1498 bool bFolder = false;
1499 xProps->getValue(
1500 OUString( "IsFolder" ) )
1501 >>= bFolder;
1502 xProps->addProperty(
1503 OUString( "CreatableContentsInfo" ),
1504 uno::makeAny( bFolder
1505 ? queryCreatableContentsInfo()
1506 : uno::Sequence< ucb::ContentInfo >() ),
1507 true );
1511 uno::Reference< sdbc::XRow > xResultRow
1512 = getPropertyValues( m_xContext,
1513 rProperties,
1514 *xProps,
1515 xProvider,
1516 xIdentifier->getContentIdentifier() );
1519 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1521 if ( !m_xCachedProps.get() )
1522 m_xCachedProps.reset( new CachableContentProperties( *xProps.get() ) );
1523 else
1524 m_xCachedProps->addProperties( *xProps.get() );
1526 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
1527 m_aEscapedTitle = NeonUri::escapeSegment( aUnescapedTitle );
1530 return xResultRow;
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;
1541 bool bTransient;
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;
1572 OUString aNewTitle;
1573 OUString aOldTitle;
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 ) );
1594 continue;
1598 // Mandatory props.
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" )
1624 OUString aNewValue;
1625 if ( rValue.Value >>= aNewValue )
1627 // No empty titles!
1628 if ( !aNewValue.isEmpty() )
1632 NeonUri aURI( xIdentifier->getContentIdentifier() );
1633 aOldTitle = aURI.GetPathBaseNameUnescaped();
1635 if ( aNewValue != aOldTitle )
1637 // modified title -> modified URL -> exchange !
1638 if ( !bTransient )
1639 bExchange = true;
1641 // new value will be set later...
1642 aNewTitle = aNewValue;
1644 // remember position within sequence of values (for
1645 // error handling).
1646 nTitlePos = n;
1649 catch ( DAVException const & )
1651 aRet[ n ] <<= lang::IllegalArgumentException(
1652 OUString( "Invalid content identifier!" ),
1653 static_cast< cppu::OWeakObject * >( this ),
1654 -1 );
1657 else
1659 aRet[ n ] <<= lang::IllegalArgumentException(
1660 OUString( "Empty title not allowed!" ),
1661 static_cast< cppu::OWeakObject * >( this ),
1662 -1 );
1665 else
1667 aRet[ n ] <<= beans::IllegalTypeException(
1668 OUString( "Property value has wrong type!" ),
1669 static_cast< cppu::OWeakObject * >( this ) );
1672 else
1675 // Optional props.
1678 OUString aSpecialName;
1679 bool bIsSpecial = DAVProperties::isUCBSpecialProperty(
1680 rName, aSpecialName );
1682 if ( !xInfo.is() )
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 ) );
1695 continue;
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 ) );
1734 else
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
1743 // error handling).
1744 aProppatchPropsPositions.push_back( n );
1746 else
1748 // Property value will be stored in local property store.
1749 if ( !bTriedToGetAdditionalPropSet &&
1750 !xAdditionalPropSet.is() )
1752 xAdditionalPropSet
1753 = getAdditionalPropertySet( false );
1754 bTriedToGetAdditionalPropSet = true;
1757 if ( xAdditionalPropSet.is() )
1761 uno::Any aOldValue
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;
1773 nChanged++;
1776 catch ( beans::UnknownPropertyException const & e )
1778 aRet[ n ] <<= e;
1780 catch ( lang::WrappedTargetException const & e )
1782 aRet[ n ] <<= e;
1784 catch ( beans::PropertyVetoException const & e )
1786 aRet[ n ] <<= e;
1788 catch ( lang::IllegalArgumentException const & e )
1790 aRet[ n ] <<= e;
1793 else
1795 aRet[ n ] <<= uno::Exception(
1796 OUString( "No property set for storing the value!" ),
1797 static_cast< cppu::OWeakObject * >( this ) );
1802 } // for
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();
1816 while ( it != 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;
1823 nChanged++;
1825 ++it;
1828 catch ( DAVException const & e )
1830 // OSL_FAIL( // "Content::setPropertyValues - PROPPATCH failed!" );
1832 cancelCommandExecution( e, xEnv );
1833 // unreachable
1837 if ( bExchange )
1839 // Assemble new content identifier...
1841 OUString aNewURL = getParentURL();
1842 if ( aNewURL.lastIndexOf( '/' ) != ( aNewURL.getLength() - 1 ) )
1843 aNewURL += "/";
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() );
1857 xResAccess->MOVE(
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(),
1877 // sal_True );
1879 else
1881 // Do not set new title!
1882 aNewTitle.clear();
1884 // Set error .
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!
1893 aNewTitle.clear();
1895 // Set error .
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;
1911 nChanged++;
1914 if ( nChanged > 0 )
1916 aChanges.realloc( nChanged );
1917 notifyPropertiesChange( aChanges );
1921 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1922 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
1925 return aRet;
1929 uno::Any Content::open(
1930 const ucb::OpenCommandArgument3 & rArg,
1931 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1932 throw (uno::Exception, std::exception)
1934 uno::Any aRet;
1936 bool bOpenFolder = ( ( rArg.Mode == ucb::OpenMode::ALL ) ||
1937 ( rArg.Mode == ucb::OpenMode::FOLDERS ) ||
1938 ( rArg.Mode == ucb::OpenMode::DOCUMENTS ) );
1939 if ( bOpenFolder )
1941 if ( isFolder( xEnv ) )
1943 // Open collection.
1945 uno::Reference< ucb::XDynamicResultSet > xSet
1946 = new DynamicResultSet( m_xContext, this, rArg, xEnv );
1947 aRet <<= xSet;
1949 else
1951 // Error: Not a folder!
1953 OUStringBuffer aMsg;
1954 if ( getResourceType( xEnv ) == FTP )
1956 // #114653#
1957 aMsg.appendAscii( "FTP over HTTP proxy: resource cannot "
1958 "be opened as folder! Wrong Open Mode!" );
1960 else
1962 aMsg.appendAscii( "Non-folder resource cannot be "
1963 "opened as folder! Wrong Open Mode!" );
1966 ucbhelper::cancelCommandExecution(
1967 uno::makeAny(
1968 lang::IllegalArgumentException(
1969 aMsg.makeStringAndClear(),
1970 static_cast< cppu::OWeakObject * >( this ),
1971 -1 ) ),
1972 xEnv );
1973 // Unreachable
1977 if ( rArg.Sink.is() )
1979 // Open document.
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(
1986 uno::makeAny(
1987 ucb::UnsupportedOpenModeException(
1988 OUString(),
1989 static_cast< cppu::OWeakObject * >( this ),
1990 sal_Int16( rArg.Mode ) ) ),
1991 xEnv );
1992 // Unreachable
1995 uno::Reference< io::XOutputStream > xOut
1996 = uno::Reference< io::XOutputStream >( rArg.Sink, uno::UNO_QUERY );
1997 if ( xOut.is() )
1999 // PUSH: write data
2002 std::unique_ptr< DAVResourceAccess > xResAccess;
2005 osl::MutexGuard aGuard( m_aMutex );
2007 xResAccess.reset(
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 );
2021 // cache headers.
2022 if ( !m_xCachedProps.get())
2023 m_xCachedProps.reset(
2024 new CachableContentProperties( aResource ) );
2025 else
2026 m_xCachedProps->addProperties( aResource );
2028 m_xResAccess.reset(
2029 new DAVResourceAccess( *xResAccess.get() ) );
2032 catch ( DAVException const & e )
2034 cancelCommandExecution( e, xEnv );
2035 // Unreachable
2038 else
2040 uno::Reference< io::XActiveDataSink > xDataSink
2041 = uno::Reference< io::XActiveDataSink >( rArg.Sink,
2042 uno::UNO_QUERY );
2043 if ( xDataSink.is() )
2045 // PULL: wait for client read
2048 std::unique_ptr< DAVResourceAccess > xResAccess;
2050 osl::MutexGuard aGuard( m_aMutex );
2052 xResAccess.reset(
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 );
2069 // cache headers.
2070 if ( !m_xCachedProps.get())
2071 m_xCachedProps.reset(
2072 new CachableContentProperties( aResource ) );
2073 else
2074 m_xCachedProps->addProperties(
2075 aResource.properties );
2077 m_xResAccess.reset(
2078 new DAVResourceAccess( *xResAccess.get() ) );
2081 xDataSink->setInputStream( xIn );
2083 catch ( DAVException const & e )
2085 cancelCommandExecution( e, xEnv );
2086 // Unreachable
2089 else
2091 // Note: aOpenCommand.Sink may contain an XStream
2092 // implementation. Support for this type of
2093 // sink is optional...
2094 ucbhelper::cancelCommandExecution(
2095 uno::makeAny(
2096 ucb::UnsupportedDataSinkException(
2097 OUString(),
2098 static_cast< cppu::OWeakObject * >( this ),
2099 rArg.Sink ) ),
2100 xEnv );
2101 // Unreachable
2106 return aRet;
2110 void Content::post(
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 );
2116 if ( xSink.is() )
2120 std::unique_ptr< DAVResourceAccess > xResAccess;
2122 osl::MutexGuard aGuard( m_aMutex );
2123 xResAccess.reset(
2124 new DAVResourceAccess( *m_xResAccess.get() ) );
2127 uno::Reference< io::XInputStream > xResult
2128 = xResAccess->POST( rArg.MediaType,
2129 rArg.Referer,
2130 rArg.Source,
2131 xEnv );
2134 osl::MutexGuard aGuard( m_aMutex );
2135 m_xResAccess.reset(
2136 new DAVResourceAccess( *xResAccess.get() ) );
2139 xSink->setInputStream( xResult );
2141 catch ( DAVException const & e )
2143 cancelCommandExecution( e, xEnv, true );
2144 // Unreachable
2147 else
2149 uno::Reference< io::XOutputStream > xResult( rArg.Sink, uno::UNO_QUERY );
2150 if ( xResult.is() )
2154 std::unique_ptr< DAVResourceAccess > xResAccess;
2156 osl::MutexGuard aGuard( m_aMutex );
2157 xResAccess.reset(
2158 new DAVResourceAccess( *m_xResAccess.get() ) );
2161 xResAccess->POST( rArg.MediaType,
2162 rArg.Referer,
2163 rArg.Source,
2164 xResult,
2165 xEnv );
2168 osl::MutexGuard aGuard( m_aMutex );
2169 m_xResAccess.reset(
2170 new DAVResourceAccess( *xResAccess.get() ) );
2173 catch ( DAVException const & e )
2175 cancelCommandExecution( e, xEnv, true );
2176 // Unreachable
2179 else
2181 ucbhelper::cancelCommandExecution(
2182 uno::makeAny(
2183 ucb::UnsupportedDataSinkException(
2184 OUString(),
2185 static_cast< cppu::OWeakObject * >( this ),
2186 rArg.Sink ) ),
2187 xEnv );
2188 // Unreachable
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
2198 // of this content.
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.
2209 aURL += "/";
2212 sal_Int32 nLen = aURL.getLength();
2214 ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin();
2215 ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
2217 while ( it != end )
2219 ::ucbhelper::ContentImplHelperRef xChild = (*it);
2220 OUString aChildURL
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 * >(
2237 xChild.get() ) ) );
2240 ++it;
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(
2274 OUString(),
2275 static_cast< cppu::OWeakObject * >( this ),
2276 aProps ) ),
2277 Environment );
2278 // Unreachable
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();
2311 if ( xIH.is() )
2313 uno::Any aExAsAny( uno::makeAny( aEx ) );
2315 rtl::Reference< ucbhelper::SimpleInteractionRequest > xRequest
2316 = new ucbhelper::SimpleInteractionRequest(
2317 aExAsAny,
2318 ucbhelper::CONTINUATION_APPROVE
2319 | ucbhelper::CONTINUATION_DISAPPROVE );
2320 xIH->handle( xRequest.get() );
2322 const sal_Int32 nResp = xRequest->getResponse();
2324 switch ( nResp )
2326 case ucbhelper::CONTINUATION_UNKNOWN:
2327 // Not handled; throw.
2328 throw aEx;
2329 // break;
2331 case ucbhelper::CONTINUATION_APPROVE:
2332 // Continue -> Overwrite.
2333 bReplaceExisting = true;
2334 break;
2336 case ucbhelper::CONTINUATION_DISAPPROVE:
2337 // Abort.
2338 throw ucb::CommandFailedException(
2339 OUString(),
2340 uno::Reference< uno::XInterface >(),
2341 aExAsAny );
2342 // break;
2344 default:
2345 OSL_FAIL( "Content::insert - "
2346 "Unknown interaction selection!" );
2347 throw ucb::CommandFailedException(
2348 OUString( "Unknown interaction selection!" ),
2349 uno::Reference< uno::XInterface >(),
2350 aExAsAny );
2351 // break;
2354 else
2356 // No IH; throw.
2357 throw aEx;
2362 if ( bTransient )
2364 // Assemble new content identifier...
2365 OUString aURL = getParentURL();
2366 if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) )
2367 aURL += "/";
2369 aURL += aEscapedTitle;
2373 xResAccess->setURL( aURL );
2375 if ( bCollection )
2376 xResAccess->MKCOL( Environment );
2377 else
2378 xResAccess->PUT( xInputStream, Environment );
2380 catch ( DAVException const & except )
2382 if ( bCollection )
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 );
2400 // Unreachable
2403 // Insert (recursion!).
2404 insert( xInputStream, bReplaceExisting, Environment );
2407 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2408 m_xResAccess.reset(
2409 new DAVResourceAccess( *xResAccess.get() ) );
2412 // Success!
2413 return;
2415 else
2417 OUString aTitle;
2420 NeonUri aURI( aURL );
2421 aTitle = aURI.GetPathBaseNameUnescaped();
2423 catch ( DAVException const & )
2427 ucbhelper::cancelCommandExecution(
2428 uno::makeAny(
2429 ucb::NameClashException(
2430 OUString(),
2431 static_cast< cppu::OWeakObject * >( this ),
2432 task::InteractionClassification_ERROR,
2433 aTitle ) ),
2434 Environment );
2435 // Unreachable
2440 cancelCommandExecution( except, Environment, true );
2441 // Unreachable
2445 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2446 m_xIdentifier = new ::ucbhelper::ContentIdentifier( aURL );
2449 inserted();
2452 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2453 m_bTransient = false;
2456 else
2458 if ( !xInputStream.is() )
2460 ucbhelper::cancelCommandExecution(
2461 uno::makeAny(
2462 ucb::MissingInputStreamException(
2463 OUString(),
2464 static_cast< cppu::OWeakObject * >( this ) ) ),
2465 Environment );
2466 // Unreachable
2471 xResAccess->PUT( xInputStream, Environment );
2473 catch ( DAVException const & e )
2475 cancelCommandExecution( e, Environment, true );
2476 // Unreachable
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 ) );
2529 else
2531 if ( aScheme != HTTP_URL_SCHEME && aScheme != HTTPS_URL_SCHEME )
2533 ucbhelper::cancelCommandExecution(
2534 uno::makeAny(
2535 ucb::InteractiveBadTransferURLException(
2536 OUString( "Unsupported URL scheme!" ),
2537 static_cast< cppu::OWeakObject * >( this ) ) ),
2538 Environment );
2539 // Unreachable
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 ) ) ),
2563 Environment );
2564 // Unreachable
2567 OUString aTitle = rArgs.NewTitle;
2569 if ( aTitle.isEmpty() )
2570 aTitle = sourceURI.GetPathBaseNameUnescaped();
2572 if ( aTitle == "/" )
2574 // kso: ???
2575 aTitle.clear();
2578 targetURI.AppendPath( aTitle );
2580 OUString aTargetURL = xIdentifier->getContentIdentifier();
2581 if ( ( aTargetURL.lastIndexOf( '/' ) + 1 )
2582 != aTargetURL.getLength() )
2583 aTargetURL += "/";
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(),
2613 targetURI.GetURI(),
2614 rArgs.NameClash
2615 == ucb::NameClash::OVERWRITE,
2616 Environment );
2618 if ( xSource.is() )
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(),
2628 // sal_True );
2630 else
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(),
2640 targetURI.GetURI(),
2641 rArgs.NameClash
2642 == ucb::NameClash::OVERWRITE,
2643 Environment );
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(),
2649 // sal_True );
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 & )
2663 // queryContent
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(
2680 uno::makeAny(
2681 ucb::NameClashException(
2682 OUString(),
2683 static_cast< cppu::OWeakObject * >( this ),
2684 task::InteractionClassification_ERROR,
2685 aTargetURI ) ),
2686 Environment );
2687 // Unreachable
2690 case ucb::NameClash::OVERWRITE:
2691 break;
2693 case ucb::NameClash::KEEP: // deprecated
2694 case ucb::NameClash::RENAME:
2695 case ucb::NameClash::ASK:
2696 default:
2698 ucbhelper::cancelCommandExecution(
2699 uno::makeAny(
2700 ucb::UnsupportedNameClashException(
2701 OUString(),
2702 static_cast< cppu::OWeakObject * >( this ),
2703 rArgs.NameClash ) ),
2704 Environment );
2705 // Unreachable
2710 cancelCommandExecution( e, Environment, true );
2711 // Unreachable
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;
2727 deleted();
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();
2739 while ( it != end )
2741 (*it)->destroy( bDeletePhysical );
2742 ++it;
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 )
2764 return true;
2769 return false;
2773 void Content::lock(
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() ) );
2785 uno::Any aOwnerAny;
2786 aOwnerAny
2787 <<= OUString("http://ucb.openoffice.org");
2789 ucb::Lock aLock(
2790 ucb::LockScope_EXCLUSIVE,
2791 ucb::LockType_WRITE,
2792 ucb::LockDepth_ZERO,
2793 aOwnerAny,
2794 180, // lock timeout in secs
2795 //-1, // infinite lock
2796 uno::Sequence< OUString >() );
2798 xResAccess->LOCK( aLock, Environment );
2799 m_bLocked = true;
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 );
2809 // Unreachable
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 );
2827 m_bLocked = false;
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 );
2837 // Unreachable
2842 bool Content::exchangeIdentity(
2843 const uno::Reference< ucb::XContentIdentifier >& xNewId )
2845 if ( !xNewId.is() )
2846 return false;
2848 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
2850 uno::Reference< ucb::XContent > xThis = this;
2852 // Already persistent?
2853 if ( m_bTransient )
2855 OSL_FAIL( "Content::exchangeIdentity - Not persistent!" );
2856 return false;
2859 // Exchange own identitity.
2861 // Fail, if a content with given id already exists.
2862 // if ( !hasData( xNewId ) )
2864 OUString aOldURL = m_xIdentifier->getContentIdentifier();
2866 aGuard.clear();
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();
2877 while ( it != 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 ) )
2895 return false;
2897 ++it;
2899 return true;
2903 OSL_FAIL( "Content::exchangeIdentity - "
2904 "Panic! Cannot exchange identity!" );
2905 return false;
2909 bool Content::isFolder(
2910 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
2911 throw( uno::Exception, std::exception )
2914 osl::MutexGuard aGuard( m_aMutex );
2916 if ( m_bTransient )
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 ) );
2924 if ( xRow.is() )
2928 return xRow->getBoolean( 1 );
2930 catch ( sdbc::SQLException const & )
2935 return false;
2939 uno::Any Content::MapDAVException( const DAVException & e, bool bWrite )
2941 // Map DAVException...
2942 uno::Any aException;
2944 OUString aURL;
2945 if ( m_bTransient )
2947 aURL = getParentURL();
2948 if ( aURL.lastIndexOf('/') != ( aURL.getLength() - 1 ) )
2949 aURL += "/";
2951 aURL += m_aEscapedTitle;
2953 else
2955 aURL = m_xIdentifier->getContentIdentifier();
2958 switch ( e.getStatus() )
2960 case SC_NOT_FOUND:
2962 uno::Sequence< uno::Any > aArgs( 1 );
2963 aArgs[ 0 ] <<= beans::PropertyValue(
2964 OUString("Uri"), -1,
2965 uno::makeAny(aURL),
2966 beans::PropertyState_DIRECT_VALUE);
2968 aException <<=
2969 ucb::InteractiveAugmentedIOException(
2970 OUString("Not found!"),
2971 static_cast< cppu::OWeakObject * >( this ),
2972 task::InteractionClassification_ERROR,
2973 ucb::IOErrorCode_NOT_EXISTING,
2974 aArgs );
2975 return aException;
2977 default:
2978 break;
2981 switch ( e.getError() )
2983 case DAVException::DAV_HTTP_ERROR:
2985 if ( bWrite )
2986 aException <<=
2987 ucb::InteractiveNetworkWriteException(
2988 e.getData(),
2989 static_cast< cppu::OWeakObject * >( this ),
2990 task::InteractionClassification_ERROR,
2991 e.getData() );
2992 else
2993 aException <<=
2994 ucb::InteractiveNetworkReadException(
2995 e.getData(),
2996 static_cast< cppu::OWeakObject * >( this ),
2997 task::InteractionClassification_ERROR,
2998 e.getData() );
2999 break;
3002 case DAVException::DAV_HTTP_LOOKUP:
3003 aException <<=
3004 ucb::InteractiveNetworkResolveNameException(
3005 OUString(),
3006 static_cast< cppu::OWeakObject * >( this ),
3007 task::InteractionClassification_ERROR,
3008 e.getData() );
3009 break;
3011 // @@@ No matching InteractiveNetwork*Exception
3012 // case DAVException::DAV_HTTP_AUTH:
3013 // break;
3015 // @@@ No matching InteractiveNetwork*Exception
3016 // case DAVException::DAV_HTTP_AUTHPROXY:
3017 // break;
3019 case DAVException::DAV_HTTP_CONNECT:
3020 aException <<=
3021 ucb::InteractiveNetworkConnectException(
3022 OUString(),
3023 static_cast< cppu::OWeakObject * >( this ),
3024 task::InteractionClassification_ERROR,
3025 e.getData() );
3026 break;
3028 // @@@ No matching InteractiveNetwork*Exception
3029 // case DAVException::DAV_HTTP_TIMEOUT:
3030 // break;
3032 // @@@ No matching InteractiveNetwork*Exception
3033 // case DAVException::DAV_HTTP_REDIRECT:
3034 // break;
3036 // @@@ No matching InteractiveNetwork*Exception
3037 // case DAVException::DAV_SESSION_CREATE:
3038 // break;
3040 case DAVException::DAV_INVALID_ARG:
3041 aException <<=
3042 lang::IllegalArgumentException(
3043 OUString(),
3044 static_cast< cppu::OWeakObject * >( this ),
3045 -1 );
3046 break;
3048 case DAVException::DAV_LOCKED:
3049 aException <<=
3050 ucb::InteractiveLockingLockedException(
3051 OUString("Locked!"),
3052 static_cast< cppu::OWeakObject * >( this ),
3053 task::InteractionClassification_ERROR,
3054 aURL,
3055 sal_False ); // not SelfOwned
3056 break;
3058 case DAVException::DAV_LOCKED_SELF:
3059 aException <<=
3060 ucb::InteractiveLockingLockedException(
3061 OUString("Locked (self!)"),
3062 static_cast< cppu::OWeakObject * >( this ),
3063 task::InteractionClassification_ERROR,
3064 aURL,
3065 sal_True ); // SelfOwned
3066 break;
3068 case DAVException::DAV_NOT_LOCKED:
3069 aException <<=
3070 ucb::InteractiveLockingNotLockedException(
3071 OUString("Not locked!"),
3072 static_cast< cppu::OWeakObject * >( this ),
3073 task::InteractionClassification_ERROR,
3074 aURL );
3075 break;
3077 case DAVException::DAV_LOCK_EXPIRED:
3078 aException <<=
3079 ucb::InteractiveLockingLockExpiredException(
3080 OUString("Lock expired!"),
3081 static_cast< cppu::OWeakObject * >( this ),
3082 task::InteractionClassification_ERROR,
3083 aURL );
3084 break;
3086 default:
3087 aException <<=
3088 ucb::InteractiveNetworkGeneralException(
3089 OUString(),
3090 static_cast< cppu::OWeakObject * >( this ),
3091 task::InteractionClassification_ERROR );
3092 break;
3095 return aException;
3099 // static
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 ) )
3107 return false;
3109 return true;
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 );
3120 // Unreachable
3124 const OUString
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() )
3132 OUString aLocation;
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(),
3142 aLocation );
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;
3177 else
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;
3229 } else {
3230 SAL_WARN_IF(
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() ) );
3253 return ret;
3256 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */