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