update dev300-m58
[ooovba.git] / ucb / source / ucp / webdav / webdavcontent.cxx
blob4df4b4c21172d72ee6f5facdc0e420e7f1379fe2
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: webdavcontent.cxx,v $
10 * $Revision: 1.65.12.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_ucb.hxx"
34 /**************************************************************************
35 TODO
36 **************************************************************************
38 *************************************************************************/
39 #include <osl/diagnose.h>
40 #include <osl/thread.hxx>
42 #include "osl/doublecheckedlocking.h"
43 #include <rtl/uri.hxx>
44 #include <rtl/ustrbuf.hxx>
45 #include "com/sun/star/task/XPasswordContainer.hpp"
46 #include "com/sun/star/task/NoMasterException.hpp"
47 #include <com/sun/star/beans/PropertyAttribute.hpp>
48 #include <com/sun/star/beans/PropertySetInfoChange.hpp>
49 #include <com/sun/star/beans/PropertySetInfoChangeEvent.hpp>
50 #include <com/sun/star/beans/PropertyValue.hpp>
51 #include <com/sun/star/io/XActiveDataSink.hpp>
52 #include <com/sun/star/io/XActiveDataStreamer.hpp>
53 #include <com/sun/star/io/XOutputStream.hpp>
54 #include <com/sun/star/lang/IllegalAccessException.hpp>
55 #include "com/sun/star/ucb/AuthenticationRequest.hpp"
56 #include <com/sun/star/ucb/CommandFailedException.hpp>
57 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
58 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
59 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
60 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
61 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
62 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
63 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
64 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
65 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
66 #include <com/sun/star/ucb/NameClash.hpp>
67 #include <com/sun/star/ucb/NameClashException.hpp>
68 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
69 #include <com/sun/star/ucb/OpenMode.hpp>
70 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
71 #include <com/sun/star/ucb/TransferInfo.hpp>
72 #include <com/sun/star/ucb/XCommandInfo.hpp>
73 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
74 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
75 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
76 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
77 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
78 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
79 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
80 #include <ucbhelper/contentidentifier.hxx>
81 #include <ucbhelper/propertyvalueset.hxx>
82 #include <ucbhelper/simpleinteractionrequest.hxx>
83 #include <ucbhelper/cancelcommandexecution.hxx>
84 #include "webdavcontent.hxx"
85 #include "webdavprovider.hxx"
86 #include "webdavresultset.hxx"
87 #include "ContentProperties.hxx"
88 #include "NeonUri.hxx"
89 #include "UCBDeadPropertyValue.hxx"
91 #include "NeonInputStream.hxx"
93 using namespace com::sun::star;
94 using namespace webdav_ucp;
96 //=========================================================================
97 //=========================================================================
99 // CommandEnvironment_Impl Implementation.
101 //=========================================================================
102 //=========================================================================
104 class CommandEnvironment_Impl : public cppu::OWeakObject,
105 public ucb::XCommandEnvironment,
106 public task::XInteractionHandler
108 public:
110 CommandEnvironment_Impl(
111 const uno::Reference< lang::XMultiServiceFactory >& xSMgr )
112 : m_xSMgr( xSMgr )
116 // XInterface
117 XINTERFACE_DECL()
119 // XCommandEnvironment
120 virtual uno::Reference< task::XInteractionHandler > SAL_CALL
121 getInteractionHandler( )
122 throw (uno::RuntimeException)
124 return this;
127 virtual uno::Reference< ucb::XProgressHandler > SAL_CALL
128 getProgressHandler( )
129 throw (uno::RuntimeException)
131 return 0;
134 // XInteractionHandler
135 virtual void SAL_CALL
136 handle( const uno::Reference< task::XInteractionRequest >& Request )
137 throw (uno::RuntimeException);
139 private:
141 void
142 handleAuthenticationRequest(
143 ucb::AuthenticationRequest const&,
144 uno::Sequence< uno::Reference< task::XInteractionContinuation > > const&)
145 SAL_THROW((uno::RuntimeException))
149 uno::Reference< lang::XMultiServiceFactory > m_xSMgr;
152 //=========================================================================
153 void SAL_CALL CommandEnvironment_Impl::acquire()
154 throw()
156 OWeakObject::acquire();
159 //=========================================================================
160 void SAL_CALL CommandEnvironment_Impl::release()
161 throw()
163 OWeakObject::release();
166 //=========================================================================
167 uno::Any SAL_CALL CommandEnvironment_Impl::queryInterface(
168 const uno::Type & rType )
169 throw( uno::RuntimeException )
171 uno::Any aRet = cppu::queryInterface(
172 rType,
173 static_cast< ucb::XCommandEnvironment * >( this ),
174 static_cast< task::XInteractionHandler * >( this ) );
175 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
178 //=========================================================================
179 void SAL_CALL CommandEnvironment_Impl::handle(
180 const uno::Reference< task::XInteractionRequest >& rIRequest )
181 throw (uno::RuntimeException)
183 if (!rIRequest.is())
184 return;
186 uno::Any aAnyRequest(rIRequest->getRequest());
188 ucb::AuthenticationRequest rRequest;
189 if (!(aAnyRequest >>= rRequest))
190 return;
192 uno::Sequence< uno::Reference< task::XInteractionContinuation > >
193 rContinuations = rIRequest->getContinuations();
195 // get continuations
196 uno::Reference< task::XInteractionRetry > xRetry;
197 uno::Reference< task::XInteractionAbort > xAbort;
198 uno::Reference< ucb::XInteractionSupplyAuthentication >
199 xSupplyAuthentication;
201 for (sal_Int32 i = 0; i < rContinuations.getLength(); ++i) {
202 xRetry = uno::Reference< task::XInteractionRetry >(
203 rContinuations[i], uno::UNO_QUERY );
204 if( xRetry.is() )
205 continue;
207 xAbort = uno::Reference< task::XInteractionAbort >(
208 rContinuations[i], uno::UNO_QUERY );
209 if (xAbort.is())
210 continue;
212 xSupplyAuthentication
213 = uno::Reference< ucb::XInteractionSupplyAuthentication >(
214 rContinuations[i], uno::UNO_QUERY );
215 if( xSupplyAuthentication.is() )
216 continue;
219 bool bRemember;
220 bool bRememberPersistent;
221 if (xSupplyAuthentication.is())
223 ucb::RememberAuthentication eDefault;
224 uno::Sequence< ucb::RememberAuthentication > aModes(
225 xSupplyAuthentication->getRememberPasswordModes(eDefault));
226 bRemember = eDefault != ucb::RememberAuthentication_NO;
227 bRememberPersistent = false;
228 for (sal_Int32 i = 0; i < aModes.getLength(); ++i)
229 if (aModes[i] == ucb::RememberAuthentication_PERSISTENT)
231 bRememberPersistent = true;
232 break;
235 else
237 bRemember = false;
238 bRememberPersistent = false;
241 uno::Reference< task::XPasswordContainer > xContainer;
244 xContainer
245 = uno::Reference< task::XPasswordContainer >(
246 m_xSMgr->createInstance(
247 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
248 "com.sun.star.task.PasswordContainer"))),
249 uno::UNO_QUERY);
251 catch (uno::Exception const &)
255 // xContainer works with userName passwdSequences pairs:
256 if (xContainer.is() && rRequest.HasUserName && rRequest.HasPassword )
260 if (rRequest.UserName.getLength() == 0)
262 task::UrlRecord
263 aRec(xContainer->find(rRequest.ServerName, this));
264 if (aRec.UserList.getLength() != 0)
266 if (xSupplyAuthentication->canSetUserName())
267 xSupplyAuthentication->
268 setUserName(aRec.UserList[0].UserName.getStr());
269 if (xSupplyAuthentication->canSetPassword())
271 OSL_ENSURE(aRec.UserList[0].Passwords.getLength() != 0,
272 "empty password list");
273 xSupplyAuthentication->
274 setPassword(aRec.UserList[0].Passwords[0].getStr());
276 if (aRec.UserList[0].Passwords.getLength() > 1)
278 if (rRequest.HasRealm)
280 if (xSupplyAuthentication->canSetRealm())
281 xSupplyAuthentication->
282 setRealm(aRec.UserList[0].Passwords[1].
283 getStr());
285 else if (xSupplyAuthentication->canSetAccount())
286 xSupplyAuthentication->
287 setAccount(aRec.UserList[0].Passwords[1].
288 getStr());
290 xSupplyAuthentication->select();
291 return;
294 else
296 task::UrlRecord
297 aRec(xContainer->findForName(rRequest.ServerName,
298 rRequest.UserName,
299 this));
300 if (aRec.UserList.getLength() != 0)
302 OSL_ENSURE(aRec.UserList[0].Passwords.getLength() != 0,
303 "empty password list");
304 if (!rRequest.HasPassword
305 || rRequest.Password != aRec.UserList[0].Passwords[0])
307 if (xSupplyAuthentication->canSetUserName())
308 xSupplyAuthentication->
309 setUserName(aRec.UserList[0].UserName.getStr());
310 if (xSupplyAuthentication->canSetPassword())
311 xSupplyAuthentication->
312 setPassword(aRec.UserList[0].Passwords[0].
313 getStr());
314 if (aRec.UserList[0].Passwords.getLength() > 1)
316 if (rRequest.HasRealm)
318 if (xSupplyAuthentication->canSetRealm())
319 xSupplyAuthentication->
320 setRealm(aRec.UserList[0].Passwords[1].
321 getStr());
323 else if (xSupplyAuthentication->canSetAccount())
324 xSupplyAuthentication->
325 setAccount(aRec.UserList[0].Passwords[1].
326 getStr());
328 xSupplyAuthentication->select();
329 return;
334 catch (task::NoMasterException const &)
335 {} // user did not enter master password
337 return;
340 //=========================================================================
341 //=========================================================================
343 // Content Implementation.
345 //=========================================================================
346 //=========================================================================
348 // Our signal - 246 is just a random number ;-)
349 #define TICKER_THREAD_USER_SIGNAL ( OSL_SIGNAL_USER_RESERVED + 246 )
351 // -------------------------------------------------------------------
352 // A thread that 'ticks' - emits the user signal every second
353 // -------------------------------------------------------------------
354 class TickerThread : public osl::Thread
356 bool m_bFinish;
358 public:
360 TickerThread() : osl::Thread(), m_bFinish( false ) {}
362 void finish() { m_bFinish = true; }
364 protected:
366 virtual void SAL_CALL run();
369 void TickerThread::run()
371 // we have to go through the loop more often to be able to finish ~quickly
372 const int nNth = 25;
374 int nCount = nNth;
375 while ( !m_bFinish )
377 if ( nCount-- <= 0 )
379 osl_raiseSignal( TICKER_THREAD_USER_SIGNAL, NULL );
380 nCount = nNth;
383 TimeValue aTV;
384 aTV.Seconds = 0;
385 aTV.Nanosec = 1000000000/nNth;
386 wait( aTV );
390 // -------------------------------------------------------------------
391 // A class that takes care of creating and destroying the ticker thread
392 // -------------------------------------------------------------------
393 class TickerThreadController
395 osl::Mutex m_aMutex;
396 int m_nCount;
397 TickerThread *m_pTickerThread;
399 public:
401 TickerThreadController() : m_nCount( 0 ), m_pTickerThread( NULL ) {}
403 void start();
404 void stop();
407 void TickerThreadController::start()
409 osl::MutexGuard aGuard( m_aMutex );
411 if ( ( m_nCount++ == 0 ) && !m_pTickerThread )
413 m_pTickerThread = new TickerThread();
414 m_pTickerThread->create();
418 void TickerThreadController::stop()
420 osl::MutexGuard aGuard( m_aMutex );
422 if ( ( --m_nCount == 0 ) && m_pTickerThread )
424 m_pTickerThread->finish();
425 m_pTickerThread->join();
427 delete m_pTickerThread;
428 m_pTickerThread = NULL;
432 // -------------------------------------------------------------------
433 // Signal handler
434 // -------------------------------------------------------------------
435 oslSignalAction Content::HandleLockingSignal( void* pData, oslSignalInfo* pSignalInfo )
437 Content *pContent = static_cast< Content *>( pData );
439 #if OSL_DEBUG_LEVEL > 0
440 fprintf( stderr, "Content::HandleLockingSignal: pContent=%p pSignalInfo=%p\n", pContent, pSignalInfo );
441 #endif
443 if ( !pContent )
444 return osl_Signal_ActCallNextHdl;
446 if ( pSignalInfo &&
447 pSignalInfo->Signal == osl_Signal_User &&
448 pSignalInfo->UserSignal == TICKER_THREAD_USER_SIGNAL )
450 pContent->RefreshLock();
452 else if ( !pSignalInfo || ( pSignalInfo->Signal != osl_Signal_User ) )
454 // terminating or something
455 pContent->m_xResAccess->UNLOCK( *pContent->m_pLock, pContent->m_xLockEnv );
456 delete pContent->m_pLock;
457 pContent->m_pLock = NULL;
460 return osl_Signal_ActCallNextHdl;
463 static TickerThreadController sTickerThreadController;
465 //=========================================================================
466 // ctr for content on an existing webdav resource
467 Content::Content(
468 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
469 ContentProvider* pProvider,
470 const uno::Reference< ucb::XContentIdentifier >& Identifier,
471 rtl::Reference< DAVSessionFactory > const & rSessionFactory )
472 throw ( ucb::ContentCreationException )
473 : ContentImplHelper( rxSMgr, pProvider, Identifier ),
474 m_eResourceType( UNKNOWN ),
475 m_pProvider( pProvider ),
476 m_bTransient( false ),
477 m_bCollection( false ),
478 m_bDidGetOrHead( false ),
479 m_bForceReadOnly( false ),
480 m_pLock( NULL ),
481 m_nToExpire( -1 ),
482 m_pSignalHandler( NULL )
486 m_xResAccess.reset( new DAVResourceAccess(
487 rxSMgr,
488 rSessionFactory,
489 Identifier->getContentIdentifier() ) );
491 NeonUri aURI( Identifier->getContentIdentifier() );
492 m_aEscapedTitle = aURI.GetPathBaseName();
494 m_pSignalHandler = osl_addSignalHandler( HandleLockingSignal, this );
496 #if OSL_DEBUG_LEVEL > 0
497 fprintf( stderr, "Content::Content (existing resource): this=%p m_pSignalHandler=%p\n", this, m_pSignalHandler );
498 fprintf( stderr, " identifier=%s\n", rtl::OUStringToOString( Identifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8 ).getStr() );
499 #endif
500 sTickerThreadController.start();
502 catch ( DAVException const & )
504 throw ucb::ContentCreationException();
508 //=========================================================================
509 // ctr for content on an non-existing webdav resource
510 Content::Content(
511 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
512 ContentProvider* pProvider,
513 const uno::Reference< ucb::XContentIdentifier >& Identifier,
514 rtl::Reference< DAVSessionFactory > const & rSessionFactory,
515 sal_Bool isCollection )
516 throw ( ucb::ContentCreationException )
517 : ContentImplHelper( rxSMgr, pProvider, Identifier ),
518 m_eResourceType( UNKNOWN ),
519 m_pProvider( pProvider ),
520 m_bTransient( true ),
521 m_bCollection( isCollection ),
522 m_bDidGetOrHead( false ),
523 m_bForceReadOnly( false ),
524 m_pLock( NULL ),
525 m_nToExpire( -1 ),
526 m_pSignalHandler( NULL )
530 m_xResAccess.reset( new DAVResourceAccess(
531 rxSMgr, rSessionFactory, Identifier->getContentIdentifier() ) );
533 m_pSignalHandler = osl_addSignalHandler( HandleLockingSignal, this );
535 #if OSL_DEBUG_LEVEL > 0
536 fprintf( stderr, "Content::Content (nonexistent resource): this=%p m_pSignalHandler=%p\n", this, m_pSignalHandler );
537 fprintf( stderr, " identifier=%s\n", rtl::OUStringToOString( Identifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8 ).getStr() );
538 #endif
539 sTickerThreadController.start();
541 catch ( DAVException const & )
543 throw ucb::ContentCreationException();
546 // Do not set m_aEscapedTitle here! Content::insert relays on this!!!
549 //=========================================================================
550 // virtual
551 Content::~Content()
553 #if OSL_DEBUG_LEVEL > 0
554 fprintf( stderr, "Content::~Content: this=%p m_pSignalHandler=%p\n", this, m_pSignalHandler );
555 #endif
556 sTickerThreadController.stop();
558 osl_removeSignalHandler( m_pSignalHandler );
560 if (m_pLock != NULL)
562 try {
563 m_xResAccess->UNLOCK( *m_pLock, m_xLockEnv );
564 delete m_pLock;
565 m_pLock = NULL;
567 catch ( ucb::CommandFailedException const & )
573 // -------------------------------------------------------------------
574 // Lock the resource again
575 // -------------------------------------------------------------------
576 void Content::RefreshLock( void )
578 osl::MutexGuard aGuard( m_aLock );
580 #if OSL_DEBUG_LEVEL > 0
581 fprintf( stderr, "Content::RefreshLock(): m_nToExpire=%d m_pLock=%p\n", m_nToExpire, m_pLock);
582 #endif
584 if ( m_nToExpire > 0 )
585 --m_nToExpire;
587 // Refresh the lock if it expires in less than 30 s
588 if ( m_pLock && m_nToExpire >= 0 && m_nToExpire < 30 )
590 m_xResAccess->LOCK( *m_pLock, m_xLockEnv );
592 m_nToExpire = m_pLock->Timeout;
596 //=========================================================================
598 // XInterface methods.
600 //=========================================================================
602 // virtual
603 void SAL_CALL Content::acquire()
604 throw( )
606 ContentImplHelper::acquire();
609 //=========================================================================
610 // virtual
611 void SAL_CALL Content::release()
612 throw( )
614 ContentImplHelper::release();
617 //=========================================================================
618 // virtual
619 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
620 throw ( uno::RuntimeException )
622 // Note: isFolder may require network activities! So call it only
623 // if it is really necessary!!!
624 uno::Any aRet = cppu::queryInterface(
625 rType,
626 static_cast< ucb::XContentCreator * >( this ) );
627 if ( aRet.hasValue() )
631 return isFolder( new CommandEnvironment_Impl(m_xSMgr) )
632 ? aRet
633 : uno::Any();
635 catch ( uno::RuntimeException const & )
637 throw;
639 catch ( uno::Exception const & )
641 return uno::Any();
644 return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType );
647 //=========================================================================
649 // XTypeProvider methods.
651 //=========================================================================
653 XTYPEPROVIDER_COMMON_IMPL( Content );
655 //=========================================================================
656 // virtual
657 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
658 throw( uno::RuntimeException )
660 sal_Bool bFolder = sal_False;
663 bFolder
664 = isFolder( uno::Reference< ucb::XCommandEnvironment >() );
666 catch ( uno::RuntimeException const & )
668 throw;
670 catch ( uno::Exception const & )
674 cppu::OTypeCollection * pCollection = 0;
676 if ( bFolder )
678 static cppu::OTypeCollection* pFolderTypes = 0;
680 pCollection = pFolderTypes;
681 if ( !pCollection )
683 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
685 pCollection = pFolderTypes;
686 if ( !pCollection )
688 static cppu::OTypeCollection aCollection(
689 CPPU_TYPE_REF( lang::XTypeProvider ),
690 CPPU_TYPE_REF( lang::XServiceInfo ),
691 CPPU_TYPE_REF( lang::XComponent ),
692 CPPU_TYPE_REF( ucb::XContent ),
693 CPPU_TYPE_REF( ucb::XCommandProcessor ),
694 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
695 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
696 CPPU_TYPE_REF( beans::XPropertyContainer ),
697 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
698 CPPU_TYPE_REF( container::XChild ),
699 CPPU_TYPE_REF( ucb::XContentCreator ) ); // !!
700 pCollection = &aCollection;
701 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
702 pFolderTypes = pCollection;
705 else {
706 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
709 else
711 static cppu::OTypeCollection* pDocumentTypes = 0;
713 pCollection = pDocumentTypes;
714 if ( !pCollection )
716 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
718 pCollection = pDocumentTypes;
719 if ( !pCollection )
721 static cppu::OTypeCollection aCollection(
722 CPPU_TYPE_REF( lang::XTypeProvider ),
723 CPPU_TYPE_REF( lang::XServiceInfo ),
724 CPPU_TYPE_REF( lang::XComponent ),
725 CPPU_TYPE_REF( ucb::XContent ),
726 CPPU_TYPE_REF( ucb::XCommandProcessor ),
727 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
728 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
729 CPPU_TYPE_REF( beans::XPropertyContainer ),
730 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
731 CPPU_TYPE_REF( container::XChild ) );
732 pCollection = &aCollection;
733 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
734 pDocumentTypes = pCollection;
737 else {
738 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
742 return (*pCollection).getTypes();
745 //=========================================================================
747 // XServiceInfo methods.
749 //=========================================================================
751 // virtual
752 rtl::OUString SAL_CALL Content::getImplementationName()
753 throw( uno::RuntimeException )
755 return rtl::OUString::createFromAscii(
756 "com.sun.star.comp.ucb.WebDAVContent" );
759 //=========================================================================
760 // virtual
761 uno::Sequence< rtl::OUString > SAL_CALL Content::getSupportedServiceNames()
762 throw( uno::RuntimeException )
764 uno::Sequence< rtl::OUString > aSNS( 1 );
765 aSNS.getArray()[ 0 ]
766 = rtl::OUString::createFromAscii( WEBDAV_CONTENT_SERVICE_NAME );
767 return aSNS;
770 //=========================================================================
772 // XContent methods.
774 //=========================================================================
776 // virtual
777 rtl::OUString SAL_CALL Content::getContentType()
778 throw( uno::RuntimeException )
780 sal_Bool bFolder = sal_False;
783 bFolder
784 = isFolder( uno::Reference< ucb::XCommandEnvironment >() );
786 catch ( uno::RuntimeException const & )
788 throw;
790 catch ( uno::Exception const & )
794 if ( bFolder )
795 return rtl::OUString::createFromAscii( WEBDAV_COLLECTION_TYPE );
797 return rtl::OUString::createFromAscii( WEBDAV_CONTENT_TYPE );
800 //=========================================================================
802 // XCommandProcessor methods.
804 //=========================================================================
806 // virtual
807 uno::Any SAL_CALL Content::execute(
808 const ucb::Command& aCommand,
809 sal_Int32 /*CommandId*/,
810 const uno::Reference< ucb::XCommandEnvironment >& Environment )
811 throw( uno::Exception,
812 ucb::CommandAbortedException,
813 uno::RuntimeException )
815 #if OSL_DEBUG_LEVEL > 0
816 fprintf( stderr, "WebDAV: Content::execute(): this=%p command=%s\n",
817 this, rtl::OUStringToOString( aCommand.Name, RTL_TEXTENCODING_UTF8 ).getStr() );
818 #endif
820 uno::Any aRet;
822 if ( aCommand.Name.equalsAsciiL(
823 RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ) )
825 //////////////////////////////////////////////////////////////////
826 // getPropertyValues
827 //////////////////////////////////////////////////////////////////
829 uno::Sequence< beans::Property > Properties;
830 if ( !( aCommand.Argument >>= Properties ) )
832 ucbhelper::cancelCommandExecution(
833 uno::makeAny( lang::IllegalArgumentException(
834 rtl::OUString::createFromAscii(
835 "Wrong argument type!" ),
836 static_cast< cppu::OWeakObject * >( this ),
837 -1 ) ),
838 Environment );
839 // Unreachable
842 aRet <<= getPropertyValues( Properties, Environment );
844 else if ( aCommand.Name.equalsAsciiL(
845 RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ) )
847 //////////////////////////////////////////////////////////////////
848 // setPropertyValues
849 //////////////////////////////////////////////////////////////////
851 uno::Sequence< beans::PropertyValue > aProperties;
852 if ( !( aCommand.Argument >>= aProperties ) )
854 ucbhelper::cancelCommandExecution(
855 uno::makeAny( lang::IllegalArgumentException(
856 rtl::OUString::createFromAscii(
857 "Wrong argument type!" ),
858 static_cast< cppu::OWeakObject * >( this ),
859 -1 ) ),
860 Environment );
861 // Unreachable
864 if ( !aProperties.getLength() )
866 ucbhelper::cancelCommandExecution(
867 uno::makeAny( lang::IllegalArgumentException(
868 rtl::OUString::createFromAscii(
869 "No properties!" ),
870 static_cast< cppu::OWeakObject * >( this ),
871 -1 ) ),
872 Environment );
873 // Unreachable
876 aRet <<= setPropertyValues( aProperties, Environment );
878 else if ( aCommand.Name.equalsAsciiL(
879 RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ) )
881 //////////////////////////////////////////////////////////////////
882 // getPropertySetInfo
883 //////////////////////////////////////////////////////////////////
885 // Note: Implemented by base class.
886 aRet <<= getPropertySetInfo( Environment,
887 sal_False /* don't cache data */ );
889 else if ( aCommand.Name.equalsAsciiL(
890 RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ) )
892 //////////////////////////////////////////////////////////////////
893 // getCommandInfo
894 //////////////////////////////////////////////////////////////////
896 // Note: Implemented by base class.
897 aRet <<= getCommandInfo( Environment, sal_False );
899 else if ( aCommand.Name.equalsAsciiL(
900 RTL_CONSTASCII_STRINGPARAM( "open" ) ) )
902 //////////////////////////////////////////////////////////////////
903 // open
904 //////////////////////////////////////////////////////////////////
906 ucb::OpenCommandArgument2 aOpenCommand;
907 if ( !( aCommand.Argument >>= aOpenCommand ) )
909 ucbhelper::cancelCommandExecution(
910 uno::makeAny( lang::IllegalArgumentException(
911 rtl::OUString::createFromAscii(
912 "Wrong argument type!" ),
913 static_cast< cppu::OWeakObject * >( this ),
914 -1 ) ),
915 Environment );
916 // Unreachable
919 aRet = open( aOpenCommand, Environment );
921 else if ( aCommand.Name.equalsAsciiL(
922 RTL_CONSTASCII_STRINGPARAM( "insert" ) ) )
924 //////////////////////////////////////////////////////////////////
925 // insert
926 //////////////////////////////////////////////////////////////////
928 ucb::InsertCommandArgument arg;
929 if ( !( aCommand.Argument >>= arg ) )
931 ucbhelper::cancelCommandExecution(
932 uno::makeAny( lang::IllegalArgumentException(
933 rtl::OUString::createFromAscii(
934 "Wrong argument type!" ),
935 static_cast< cppu::OWeakObject * >( this ),
936 -1 ) ),
937 Environment );
938 // Unreachable
941 insert( arg.Data, arg.ReplaceExisting, Environment );
943 else if ( aCommand.Name.equalsAsciiL(
944 RTL_CONSTASCII_STRINGPARAM( "delete" ) ) )
946 //////////////////////////////////////////////////////////////////
947 // delete
948 //////////////////////////////////////////////////////////////////
950 sal_Bool bDeletePhysical = sal_False;
951 aCommand.Argument >>= bDeletePhysical;
953 // KSO: Ignore parameter and destroy the content, if you don't support
954 // putting objects into trashcan. ( Since we do not have a trash can
955 // service yet (src603), you actually have no other choice. )
956 // if ( bDeletePhysical )
957 // {
960 std::auto_ptr< DAVResourceAccess > xResAccess;
962 osl::Guard< osl::Mutex > aGuard( m_aMutex );
963 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
965 xResAccess->DESTROY( Environment );
967 osl::Guard< osl::Mutex > aGuard( m_aMutex );
968 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
971 catch ( DAVException const & e )
973 cancelCommandExecution( e, Environment, sal_True );
974 // Unreachable
976 // }
978 // Propagate destruction.
979 destroy( bDeletePhysical );
981 // Remove own and all children's Additional Core Properties.
982 removeAdditionalPropertySet( sal_True );
984 else if ( aCommand.Name.equalsAsciiL(
985 RTL_CONSTASCII_STRINGPARAM( "transfer" ) )
986 && isFolder( Environment ) )
988 //////////////////////////////////////////////////////////////////
989 // transfer
990 // ( Not available at documents )
991 //////////////////////////////////////////////////////////////////
993 ucb::TransferInfo transferArgs;
994 if ( !( aCommand.Argument >>= transferArgs ) )
996 ucbhelper::cancelCommandExecution(
997 uno::makeAny( lang::IllegalArgumentException(
998 rtl::OUString::createFromAscii(
999 "Wrong argument type!" ),
1000 static_cast< cppu::OWeakObject * >( this ),
1001 -1 ) ),
1002 Environment );
1003 // Unreachable
1006 transfer( transferArgs, Environment );
1008 else if ( aCommand.Name.equalsAsciiL(
1009 RTL_CONSTASCII_STRINGPARAM( "post" ) ) )
1011 //////////////////////////////////////////////////////////////////
1012 // post
1013 //////////////////////////////////////////////////////////////////
1015 ucb::PostCommandArgument2 aArg;
1016 if ( !( aCommand.Argument >>= aArg ) )
1018 ucbhelper::cancelCommandExecution(
1019 uno::makeAny( lang::IllegalArgumentException(
1020 rtl::OUString::createFromAscii(
1021 "Wrong argument type!" ),
1022 static_cast< cppu::OWeakObject * >( this ),
1023 -1 ) ),
1024 Environment );
1025 // Unreachable
1028 post( aArg, Environment );
1030 else
1032 //////////////////////////////////////////////////////////////////
1033 // Unsupported command
1034 //////////////////////////////////////////////////////////////////
1036 ucbhelper::cancelCommandExecution(
1037 uno::makeAny( ucb::UnsupportedCommandException(
1038 rtl::OUString(),
1039 static_cast< cppu::OWeakObject * >( this ) ) ),
1040 Environment );
1041 // Unreachable
1044 return aRet;
1047 //=========================================================================
1048 // virtual
1049 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
1050 throw( uno::RuntimeException )
1054 std::auto_ptr< DAVResourceAccess > xResAccess;
1056 osl::MutexGuard aGuard( m_aMutex );
1057 xResAccess.reset(
1058 new DAVResourceAccess( *m_xResAccess.get() ) );
1060 xResAccess->ABORT();
1062 catch ( DAVException const & /*e*/ )
1064 // ABORT command failed!
1068 //=========================================================================
1070 // XPropertyContainer methods.
1072 //=========================================================================
1074 // virtual
1075 void SAL_CALL Content::addProperty( const rtl::OUString& Name,
1076 sal_Int16 Attributes,
1077 const uno::Any& DefaultValue )
1078 throw( beans::PropertyExistException,
1079 beans::IllegalTypeException,
1080 lang::IllegalArgumentException,
1081 uno::RuntimeException )
1083 // if ( m_bTransient )
1084 // @@@ ???
1086 if ( !Name.getLength() )
1087 throw lang::IllegalArgumentException();
1089 #if OSL_DEBUG_LEVEL > 0
1090 fprintf( stderr, "WebDAV: Content::addProperty(): this=%p property=%s\n",
1091 this, rtl::OUStringToOString( Name, RTL_TEXTENCODING_UTF8 ).getStr() );
1092 #endif
1094 // Check property type.
1095 if ( !UCBDeadPropertyValue::supportsType( DefaultValue.getValueType() ) )
1097 OSL_ENSURE( sal_False, "Content::addProperty - "
1098 "Unsupported property type!" );
1099 throw beans::IllegalTypeException();
1102 //////////////////////////////////////////////////////////////////////
1103 // Make sure a property with the requested name does not already
1104 // exist in dynamic and static(!) properties.
1105 //////////////////////////////////////////////////////////////////////
1107 // @@@ Need real command environment here, but where to get it from?
1108 // XPropertyContainer interface should be replaced by
1109 // XCommandProcessor commands!
1110 uno::Reference< ucb::XCommandEnvironment > xEnv;
1112 // Note: This requires network access!
1113 if ( getPropertySetInfo( xEnv, sal_False /* don't cache data */ )
1114 ->hasPropertyByName( Name ) )
1116 // Property does already exist.
1117 throw beans::PropertyExistException();
1120 //////////////////////////////////////////////////////////////////////
1121 // Add a new dynamic property.
1122 //////////////////////////////////////////////////////////////////////
1124 ProppatchValue aValue( PROPSET, Name, DefaultValue );
1126 std::vector< ProppatchValue > aProppatchValues;
1127 aProppatchValues.push_back( aValue );
1131 // Set property value at server.
1132 std::auto_ptr< DAVResourceAccess > xResAccess;
1134 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1135 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
1137 xResAccess->PROPPATCH( aProppatchValues, xEnv );
1139 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1140 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
1143 // Notify propertyset info change listeners.
1144 beans::PropertySetInfoChangeEvent evt(
1145 static_cast< cppu::OWeakObject * >( this ),
1146 Name,
1147 -1, // No handle available
1148 beans::PropertySetInfoChange::PROPERTY_INSERTED );
1149 notifyPropertySetInfoChange( evt );
1151 catch ( DAVException const & e )
1153 if ( e.getStatus() == SC_FORBIDDEN )
1155 // Support for setting arbitrary dead properties is optional!
1157 // Store property locally.
1158 ContentImplHelper::addProperty(
1159 Name, Attributes, DefaultValue );
1161 else
1163 if ( shouldAccessNetworkAfterException( e ) )
1167 const ResourceType & rType = getResourceType( xEnv );
1168 switch ( rType )
1170 case UNKNOWN:
1171 case DAV:
1172 throw lang::IllegalArgumentException();
1174 case FTP:
1175 case NON_DAV:
1176 // Store property locally.
1177 ContentImplHelper::addProperty( Name,
1178 Attributes,
1179 DefaultValue );
1180 break;
1182 default:
1183 OSL_ENSURE( sal_False,
1184 "Content::addProperty - "
1185 "Unsupported resource type!" );
1186 break;
1189 catch ( uno::Exception const & )
1191 OSL_ENSURE( sal_False,
1192 "Content::addProperty - "
1193 "Unable to determine resource type!" );
1196 else
1198 OSL_ENSURE( sal_False,
1199 "Content::addProperty - "
1200 "Unable to determine resource type!" );
1206 //=========================================================================
1207 // virtual
1208 void SAL_CALL Content::removeProperty( const rtl::OUString& Name )
1209 throw( beans::UnknownPropertyException,
1210 beans::NotRemoveableException,
1211 uno::RuntimeException )
1213 // @@@ Need real command environment here, but where to get it from?
1214 // XPropertyContainer interface should be replaced by
1215 // XCommandProcessor commands!
1216 uno::Reference< ucb::XCommandEnvironment > xEnv;
1218 #if 0
1219 // @@@ REMOVEABLE z.Z. nicht richtig an der PropSetInfo gesetzt!!!
1222 beans::Property aProp
1223 = getPropertySetInfo( xEnv, sal_False /* don't cache data */ )
1224 ->getPropertyByName( Name );
1226 if ( !( aProp.Attributes & beans::PropertyAttribute::REMOVEABLE ) )
1228 // Not removeable!
1229 throw beans::NotRemoveableException();
1232 catch ( beans::UnknownPropertyException const & )
1234 // OSL_ENSURE( sal_False, "removeProperty - Unknown property!" );
1235 throw;
1237 #endif
1239 //////////////////////////////////////////////////////////////////////
1240 // Try to remove property from server.
1241 //////////////////////////////////////////////////////////////////////
1243 #if OSL_DEBUG_LEVEL > 0
1244 fprintf( stderr, "WebDAV: Content::removeProperty(): this=%p property=%s\n",
1245 this, rtl::OUStringToOString( Name, RTL_TEXTENCODING_UTF8 ).getStr() );
1246 #endif
1250 std::vector< ProppatchValue > aProppatchValues;
1251 ProppatchValue aValue( PROPREMOVE, Name, uno::Any() );
1252 aProppatchValues.push_back( aValue );
1254 // Remove property value from server.
1255 std::auto_ptr< DAVResourceAccess > xResAccess;
1257 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1258 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
1260 xResAccess->PROPPATCH( aProppatchValues, xEnv );
1262 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1263 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
1266 // Notify propertyset info change listeners.
1267 beans::PropertySetInfoChangeEvent evt(
1268 static_cast< cppu::OWeakObject * >( this ),
1269 Name,
1270 -1, // No handle available
1271 beans::PropertySetInfoChange::PROPERTY_REMOVED );
1272 notifyPropertySetInfoChange( evt );
1274 catch ( DAVException const & e )
1276 if ( e.getStatus() == SC_FORBIDDEN )
1278 // Support for setting arbitrary dead properties is optional!
1280 // Try to remove property from local store.
1281 ContentImplHelper::removeProperty( Name );
1283 else
1285 if ( shouldAccessNetworkAfterException( e ) )
1289 const ResourceType & rType = getResourceType( xEnv );
1290 switch ( rType )
1292 case UNKNOWN:
1293 case DAV:
1294 throw beans::UnknownPropertyException();
1296 case FTP:
1297 case NON_DAV:
1298 // Try to remove property from local store.
1299 ContentImplHelper::removeProperty( Name );
1300 break;
1302 default:
1303 OSL_ENSURE( sal_False,
1304 "Content::removeProperty - "
1305 "Unsupported resource type!" );
1306 break;
1309 catch ( uno::Exception const & )
1311 OSL_ENSURE( sal_False,
1312 "Content::removeProperty - "
1313 "Unable to determine resource type!" );
1316 else
1318 OSL_ENSURE( sal_False,
1319 "Content::removeProperty - "
1320 "Unable to determine resource type!" );
1321 // throw beans::UnknownPropertyException();
1327 //=========================================================================
1329 // XContentCreator methods.
1331 //=========================================================================
1333 // virtual
1334 uno::Sequence< ucb::ContentInfo > SAL_CALL
1335 Content::queryCreatableContentsInfo()
1336 throw( uno::RuntimeException )
1338 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1340 uno::Sequence< ucb::ContentInfo > aSeq( 2 );
1342 // document.
1343 aSeq.getArray()[ 0 ].Type
1344 = rtl::OUString::createFromAscii( WEBDAV_CONTENT_TYPE );
1345 aSeq.getArray()[ 0 ].Attributes
1346 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
1347 | ucb::ContentInfoAttribute::KIND_DOCUMENT;
1349 beans::Property aProp;
1350 m_pProvider->getProperty(
1351 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ), aProp );
1353 uno::Sequence< beans::Property > aDocProps( 1 );
1354 aDocProps.getArray()[ 0 ] = aProp;
1355 aSeq.getArray()[ 0 ].Properties = aDocProps;
1357 // folder.
1358 aSeq.getArray()[ 1 ].Type
1359 = rtl::OUString::createFromAscii( WEBDAV_COLLECTION_TYPE );
1360 aSeq.getArray()[ 1 ].Attributes
1361 = ucb::ContentInfoAttribute::KIND_FOLDER;
1363 uno::Sequence< beans::Property > aFolderProps( 1 );
1364 aFolderProps.getArray()[ 0 ] = aProp;
1365 aSeq.getArray()[ 1 ].Properties = aFolderProps;
1366 return aSeq;
1369 //=========================================================================
1370 // virtual
1371 uno::Reference< ucb::XContent > SAL_CALL
1372 Content::createNewContent( const ucb::ContentInfo& Info )
1373 throw( uno::RuntimeException )
1375 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1377 if ( !Info.Type.getLength() )
1378 return uno::Reference< ucb::XContent >();
1380 if ( ( !Info.Type.equalsAsciiL(
1381 RTL_CONSTASCII_STRINGPARAM( WEBDAV_COLLECTION_TYPE ) ) )
1383 ( !Info.Type.equalsAsciiL(
1384 RTL_CONSTASCII_STRINGPARAM( WEBDAV_CONTENT_TYPE ) ) ) )
1385 return uno::Reference< ucb::XContent >();
1387 rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
1389 OSL_ENSURE( aURL.getLength() > 0,
1390 "WebdavContent::createNewContent - empty identifier!" );
1392 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
1393 aURL += rtl::OUString::createFromAscii( "/" );
1395 sal_Bool isCollection;
1396 if ( Info.Type.equalsAsciiL(
1397 RTL_CONSTASCII_STRINGPARAM( WEBDAV_COLLECTION_TYPE ) ) )
1399 aURL += rtl::OUString::createFromAscii( "New_Collection" );
1400 isCollection = sal_True;
1402 else
1404 aURL += rtl::OUString::createFromAscii( "New_Content" );
1405 isCollection = sal_False;
1408 uno::Reference< ucb::XContentIdentifier > xId(
1409 new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ) );
1411 // create the local content
1414 return new ::webdav_ucp::Content( m_xSMgr,
1415 m_pProvider,
1416 xId,
1417 m_xResAccess->getSessionFactory(),
1418 isCollection );
1420 catch ( ucb::ContentCreationException & )
1422 return uno::Reference< ucb::XContent >();
1426 //=========================================================================
1427 // virtual
1428 rtl::OUString Content::getParentURL()
1430 // <scheme>:// -> ""
1431 // <scheme>://foo -> ""
1432 // <scheme>://foo/ -> ""
1433 // <scheme>://foo/bar -> <scheme>://foo/
1434 // <scheme>://foo/bar/ -> <scheme>://foo/
1435 // <scheme>://foo/bar/abc -> <scheme>://foo/bar/
1437 rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
1439 sal_Int32 nPos = aURL.lastIndexOf( '/' );
1440 if ( nPos == ( aURL.getLength() - 1 ) )
1442 // Trailing slash found. Skip.
1443 nPos = aURL.lastIndexOf( '/', nPos );
1446 sal_Int32 nPos1 = aURL.lastIndexOf( '/', nPos );
1447 if ( nPos1 != -1 )
1448 nPos1 = aURL.lastIndexOf( '/', nPos1 );
1450 if ( nPos1 == -1 )
1451 return rtl::OUString();
1453 return rtl::OUString( aURL.copy( 0, nPos + 1 ) );
1456 //=========================================================================
1458 // Non-interface methods.
1460 //=========================================================================
1462 // static
1463 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1464 const uno::Reference< lang::XMultiServiceFactory >& rSMgr,
1465 const uno::Sequence< beans::Property >& rProperties,
1466 const ContentProperties& rData,
1467 const rtl::Reference< ::ucbhelper::ContentProviderImplHelper >& rProvider,
1468 const rtl::OUString& rContentId )
1470 // Note: Empty sequence means "get values of all supported properties".
1472 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
1473 = new ::ucbhelper::PropertyValueSet( rSMgr );
1475 sal_Int32 nCount = rProperties.getLength();
1476 if ( nCount )
1478 uno::Reference< beans::XPropertySet > xAdditionalPropSet;
1479 sal_Bool bTriedToGetAdditonalPropSet = sal_False;
1481 const beans::Property* pProps = rProperties.getConstArray();
1482 for ( sal_Int32 n = 0; n < nCount; ++n )
1484 const beans::Property& rProp = pProps[ n ];
1486 // Process standard UCB, DAV and HTTP properties.
1487 const uno::Any & rValue = rData.getValue( rProp.Name );
1488 if ( rValue.hasValue() )
1490 xRow->appendObject( rProp, rValue );
1492 else
1494 // Process local Additional Properties.
1495 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
1497 xAdditionalPropSet
1498 = uno::Reference< beans::XPropertySet >(
1499 rProvider->getAdditionalPropertySet( rContentId,
1500 sal_False ),
1501 uno::UNO_QUERY );
1502 bTriedToGetAdditonalPropSet = sal_True;
1505 if ( !xAdditionalPropSet.is() ||
1506 !xRow->appendPropertySetValue(
1507 xAdditionalPropSet, rProp ) )
1509 // Append empty entry.
1510 xRow->appendVoid( rProp );
1515 else
1517 // Append all standard UCB, DAV and HTTP properties.
1519 const std::auto_ptr< PropertyValueMap > & xProps = rData.getProperties();
1521 PropertyValueMap::const_iterator it = xProps->begin();
1522 PropertyValueMap::const_iterator end = xProps->end();
1524 ContentProvider * pProvider
1525 = static_cast< ContentProvider * >( rProvider.get() );
1526 beans::Property aProp;
1528 while ( it != end )
1530 if ( pProvider->getProperty( (*it).first, aProp ) )
1531 xRow->appendObject( aProp, (*it).second.value() );
1533 ++it;
1536 // Append all local Additional Properties.
1537 uno::Reference< beans::XPropertySet > xSet(
1538 rProvider->getAdditionalPropertySet( rContentId, sal_False ),
1539 uno::UNO_QUERY );
1540 xRow->appendPropertySet( xSet );
1543 return uno::Reference< sdbc::XRow >( xRow.get() );
1546 //=========================================================================
1547 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1548 const uno::Sequence< beans::Property >& rProperties,
1549 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1550 throw ( uno::Exception )
1552 std::auto_ptr< ContentProperties > xProps;
1553 std::auto_ptr< ContentProperties > xCachedProps;
1554 std::auto_ptr< DAVResourceAccess > xResAccess;
1555 rtl::OUString aEscapedTitle;
1556 bool bHasAll = false;
1557 uno::Reference< lang::XMultiServiceFactory > xSMgr;
1558 uno::Reference< ucb::XContentIdentifier > xIdentifier;
1559 rtl::Reference< ::ucbhelper::ContentProviderImplHelper > xProvider;
1561 #if OSL_DEBUG_LEVEL > 0
1562 fprintf( stderr, "WebDAV: Content::getPropertyValues(): answering the following properties: " );
1563 for ( int i = 0; i < rProperties.getLength(); ++i )
1564 fprintf( stderr, " %s,",
1565 rtl::OUStringToOString( rProperties[i].Name, RTL_TEXTENCODING_UTF8 ).getStr() );
1566 fprintf( stderr, "\n" );
1567 #endif
1569 // WebDAV supports XActiveDataStreamer
1570 // We have to return TRUE on
1571 // - SupportsActiveStreaming - always
1572 // - IsReadOnly - if we forced read only due to failed locking
1573 if ( rProperties.getLength() == 1 )
1575 if ( rProperties[ 0 ].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "SupportsActiveStreaming" ) ) ||
1576 ( rProperties[ 0 ].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsReadOnly" ) ) && m_bForceReadOnly ) )
1578 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
1579 = new ::ucbhelper::PropertyValueSet( m_xSMgr );
1580 xRow->appendBoolean( rProperties[0], sal_True );
1582 return uno::Reference< sdbc::XRow >( xRow.get() );
1587 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1589 aEscapedTitle = NeonUri::unescape( m_aEscapedTitle );
1590 xSMgr.set( m_xSMgr );
1591 xIdentifier.set( m_xIdentifier );
1592 xProvider.set( m_xProvider.get() );
1593 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
1595 // First, ask cache...
1596 if ( m_xCachedProps.get() )
1598 xCachedProps.reset( new ContentProperties( *m_xCachedProps.get() ) );
1600 std::vector< rtl::OUString > aMissingProps;
1601 if ( xCachedProps->containsAllNames( rProperties, aMissingProps ) )
1603 // All properties are already in cache! No server access needed.
1604 bHasAll = true;
1607 // use the cached ContentProperties instance
1608 xProps.reset( new ContentProperties( *xCachedProps.get() ) );
1612 if ( !m_bTransient && !bHasAll )
1614 /////////////////////////////////////////////////////////////////////
1615 // Obtain values from server...
1616 /////////////////////////////////////////////////////////////////////
1618 // First, identify whether resource is DAV or not
1619 const ResourceType & rType = getResourceType( xEnv, xResAccess );
1621 bool bNetworkAccessAllowed = true;
1623 if ( DAV == rType )
1625 // cache lookup... getResourceType may fill the props cache via PROPFIND!
1626 if ( m_xCachedProps.get() )
1628 xCachedProps.reset( new ContentProperties( *m_xCachedProps.get() ) );
1630 std::vector< rtl::OUString > aMissingProps;
1631 if ( xCachedProps->containsAllNames( rProperties, aMissingProps ) )
1633 // All properties are already in cache! No server access needed.
1634 bHasAll = true;
1637 // use the cached ContentProperties instance
1638 xProps.reset( new ContentProperties( *xCachedProps.get() ) );
1641 if ( !bHasAll )
1643 // Only DAV resources support PROPFIND
1644 std::vector< rtl::OUString > aPropNames;
1646 uno::Sequence< beans::Property > aProperties( rProperties.getLength() );
1648 if ( m_aFailedPropNames.size() > 0 )
1650 sal_Int32 nProps = 0;
1651 sal_Int32 nCount = rProperties.getLength();
1652 for ( sal_Int32 n = 0; n < nCount; ++n )
1654 const rtl::OUString & rName = rProperties[ n ].Name;
1656 std::vector< rtl::OUString >::const_iterator it
1657 = m_aFailedPropNames.begin();
1658 std::vector< rtl::OUString >::const_iterator end
1659 = m_aFailedPropNames.end();
1661 while ( it != end )
1663 if ( *it == rName )
1664 break;
1666 ++it;
1669 if ( it == end )
1671 aProperties[ nProps ] = rProperties[ n ];
1672 nProps++;
1676 aProperties.realloc( nProps );
1678 else
1680 aProperties = rProperties;
1683 if ( aProperties.getLength() > 0 )
1684 ContentProperties::UCBNamesToDAVNames(
1685 aProperties, aPropNames );
1687 if ( aPropNames.size() > 0 )
1689 std::vector< DAVResource > resources;
1692 xResAccess->PROPFIND(
1693 DAVZERO, aPropNames, resources, xEnv );
1695 if ( 1 == resources.size() )
1697 if ( xProps.get())
1698 xProps->addProperties(
1699 aPropNames, ContentProperties( resources[ 0 ] ));
1700 else
1701 xProps.reset(
1702 new ContentProperties( resources[ 0 ] ) );
1705 catch ( DAVException const & e )
1707 bNetworkAccessAllowed
1708 = shouldAccessNetworkAfterException( e );
1710 if ( !bNetworkAccessAllowed )
1712 if ( e.getStatus() == SC_NOT_FOUND )
1713 xProps.reset();
1714 else
1716 cancelCommandExecution( e, xEnv );
1717 // unreachable
1725 if ( bNetworkAccessAllowed )
1727 // All properties obtained already?
1728 std::vector< rtl::OUString > aMissingProps;
1729 if ( !( xProps.get()
1730 && xProps->containsAllNames(
1731 rProperties, aMissingProps ) )
1732 && !m_bDidGetOrHead )
1734 // Possibly the missing props can be obtained using a HEAD
1735 // request.
1737 std::vector< rtl::OUString > aHeaderNames;
1738 ContentProperties::UCBNamesToHTTPNames(
1739 rProperties,
1740 aHeaderNames,
1741 true /* bIncludeUnmatched */ );
1743 if ( aHeaderNames.size() > 0 )
1747 DAVResource resource;
1748 xResAccess->HEAD( aHeaderNames, resource, xEnv );
1749 m_bDidGetOrHead = true;
1751 if ( xProps.get() )
1752 xProps->addProperties(
1753 aMissingProps,
1754 ContentProperties( resource ) );
1755 else
1756 xProps.reset ( new ContentProperties( resource ) );
1758 if ( m_eResourceType == NON_DAV )
1759 xProps->addProperties( aMissingProps,
1760 ContentProperties(
1761 aEscapedTitle,
1762 false ) );
1764 catch ( DAVException const & e )
1766 bNetworkAccessAllowed
1767 = shouldAccessNetworkAfterException( e );
1769 if ( !bNetworkAccessAllowed )
1771 cancelCommandExecution( e, xEnv );
1772 // unreachable
1778 // might trigger HTTP redirect.
1779 // Therefore, title must be upadated here.
1780 NeonUri aUri( xResAccess->getURL() );
1781 aEscapedTitle = aUri.GetPathBaseName();
1783 if ( UNKNOWN == rType )
1785 xProps.reset(
1786 new ContentProperties( aEscapedTitle ) );
1789 // For DAV resources we only know the Title, for non-DAV
1790 // resources we additionally know that it is a document.
1791 if ( DAV == rType )
1793 //xProps.reset(
1794 // new ContentProperties( aEscapedTitle ) );
1795 xProps->addProperty( rtl::OUString(
1796 RTL_CONSTASCII_USTRINGPARAM(
1797 "Title" )),
1798 uno::makeAny( aEscapedTitle), true);
1800 else
1802 if ( !xProps.get() )
1803 xProps.reset(
1804 new ContentProperties( aEscapedTitle, false ) );
1805 else
1806 xProps->addProperty( rtl::OUString(
1807 RTL_CONSTASCII_USTRINGPARAM(
1808 "Title" )),
1809 uno::makeAny( aEscapedTitle), true);
1811 xProps->addProperty( rtl::OUString(
1812 RTL_CONSTASCII_USTRINGPARAM(
1813 "IsFolder" )),
1814 uno::makeAny( false), true);
1815 xProps->addProperty( rtl::OUString(
1816 RTL_CONSTASCII_USTRINGPARAM(
1817 "IsDocument" )),
1818 uno::makeAny( true), true);
1822 else
1824 // No server access for just created (not yet committed) objects.
1825 // Only a minimal set of properties supported at this stage.
1826 if (m_bTransient)
1827 xProps.reset( new ContentProperties( aEscapedTitle,
1828 m_bCollection ) );
1831 // Add BaseURI property, if requested.
1832 if ( !xProps->contains(
1833 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseURI" ) ) ) )
1835 xProps->addProperty( rtl::OUString(
1836 RTL_CONSTASCII_USTRINGPARAM(
1837 "BaseURI" ) ),
1838 uno::makeAny(
1839 getBaseURI( xResAccess ) ),
1840 true );
1843 uno::Reference< sdbc::XRow > xResultRow
1844 = getPropertyValues( xSMgr,
1845 rProperties,
1846 *xProps,
1847 xProvider,
1848 xIdentifier->getContentIdentifier() );
1851 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1853 if ( !m_xCachedProps.get() )
1854 m_xCachedProps.reset( new ContentProperties( *xProps.get() ) );
1855 else
1856 m_xCachedProps->addProperties( *xProps.get() );
1858 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
1859 m_aEscapedTitle = aEscapedTitle;
1862 return xResultRow;
1865 //=========================================================================
1866 uno::Sequence< uno::Any > Content::setPropertyValues(
1867 const uno::Sequence< beans::PropertyValue >& rValues,
1868 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1869 throw ( uno::Exception )
1871 uno::Reference< lang::XMultiServiceFactory > xSMgr;
1872 uno::Reference< ucb::XContentIdentifier > xIdentifier;
1873 rtl::Reference< ContentProvider > xProvider;
1874 sal_Bool bTransient;
1875 std::auto_ptr< DAVResourceAccess > xResAccess;
1878 osl::Guard< osl::Mutex > aGuard( m_aMutex );
1880 xProvider.set( m_pProvider );
1881 xIdentifier.set( m_xIdentifier );
1882 bTransient = m_bTransient;
1883 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
1884 xSMgr.set( m_xSMgr );
1887 uno::Sequence< uno::Any > aRet( rValues.getLength() );
1888 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1889 sal_Int32 nChanged = 0;
1891 beans::PropertyChangeEvent aEvent;
1892 aEvent.Source = static_cast< cppu::OWeakObject * >( this );
1893 aEvent.Further = sal_False;
1894 // aEvent.PropertyName =
1895 aEvent.PropertyHandle = -1;
1896 // aEvent.OldValue =
1897 // aEvent.NewValue =
1899 std::vector< ProppatchValue > aProppatchValues;
1900 std::vector< sal_Int32 > aProppatchPropsPositions;
1902 uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1903 sal_Bool bTriedToGetAdditonalPropSet = sal_False;
1905 sal_Bool bExchange = sal_False;
1906 rtl::OUString aNewTitle;
1907 rtl::OUString aOldTitle;
1908 sal_Int32 nTitlePos = -1;
1910 uno::Reference< beans::XPropertySetInfo > xInfo;
1912 const beans::PropertyValue* pValues = rValues.getConstArray();
1913 sal_Int32 nCount = rValues.getLength();
1914 for ( sal_Int32 n = 0; n < nCount; ++n )
1916 const beans::PropertyValue& rValue = pValues[ n ];
1917 const rtl::OUString & rName = rValue.Name;
1919 beans::Property aTmpProp;
1920 xProvider->getProperty( rName, aTmpProp );
1922 if ( aTmpProp.Attributes & beans::PropertyAttribute::READONLY )
1924 // Read-only property!
1925 aRet[ n ] <<= lang::IllegalAccessException(
1926 rtl::OUString::createFromAscii(
1927 "Property is read-only!" ),
1928 static_cast< cppu::OWeakObject * >( this ) );
1929 continue;
1932 //////////////////////////////////////////////////////////////////
1933 // Mandatory props.
1934 //////////////////////////////////////////////////////////////////
1936 if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) )
1938 // Read-only property!
1939 aRet[ n ] <<= lang::IllegalAccessException(
1940 rtl::OUString::createFromAscii(
1941 "Property is read-only!" ),
1942 static_cast< cppu::OWeakObject * >( this ) );
1944 else if ( rName.equalsAsciiL(
1945 RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
1947 // Read-only property!
1948 aRet[ n ] <<= lang::IllegalAccessException(
1949 rtl::OUString::createFromAscii(
1950 "Property is read-only!" ),
1951 static_cast< cppu::OWeakObject * >( this ) );
1953 else if ( rName.equalsAsciiL(
1954 RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
1956 // Read-only property!
1957 aRet[ n ] <<= lang::IllegalAccessException(
1958 rtl::OUString::createFromAscii(
1959 "Property is read-only!" ),
1960 static_cast< cppu::OWeakObject * >( this ) );
1962 else if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
1964 rtl::OUString aNewValue;
1965 if ( rValue.Value >>= aNewValue )
1967 // No empty titles!
1968 if ( aNewValue.getLength() > 0 )
1970 try
1972 NeonUri aURI( xIdentifier->getContentIdentifier() );
1973 aOldTitle = aURI.GetPathBaseNameUnescaped();
1975 if ( aNewValue != aOldTitle )
1977 // modified title -> modified URL -> exchange !
1978 if ( !bTransient )
1979 bExchange = sal_True;
1981 // new value will be set later...
1982 aNewTitle = aNewValue;
1984 // remember position within sequence of values (for
1985 // error handling).
1986 nTitlePos = n;
1989 catch ( DAVException const & )
1991 aRet[ n ] <<= lang::IllegalArgumentException(
1992 rtl::OUString::createFromAscii(
1993 "Invalid content identifier!" ),
1994 static_cast< cppu::OWeakObject * >( this ),
1995 -1 );
1998 else
2000 aRet[ n ] <<= lang::IllegalArgumentException(
2001 rtl::OUString::createFromAscii(
2002 "Empty title not allowed!" ),
2003 static_cast< cppu::OWeakObject * >( this ),
2004 -1 );
2007 else
2009 aRet[ n ] <<= beans::IllegalTypeException(
2010 rtl::OUString::createFromAscii(
2011 "Property value has wrong type!" ),
2012 static_cast< cppu::OWeakObject * >( this ) );
2015 else
2017 //////////////////////////////////////////////////////////////
2018 // Optional props.
2019 //////////////////////////////////////////////////////////////
2021 if ( !xInfo.is() )
2022 xInfo = getPropertySetInfo( xEnv,
2023 sal_False /* don't cache data */ );
2025 if ( !xInfo->hasPropertyByName( rName ) )
2027 // Check, whether property exists. Skip otherwise.
2028 // PROPPATCH::set would add the property automatically, which
2029 // is not allowed for "setPropertyValues" command!
2030 aRet[ n ] <<= beans::UnknownPropertyException(
2031 rtl::OUString::createFromAscii(
2032 "Property is unknown!" ),
2033 static_cast< cppu::OWeakObject * >( this ) );
2034 continue;
2037 if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) )
2039 // Read-only property!
2040 aRet[ n ] <<= lang::IllegalAccessException(
2041 rtl::OUString::createFromAscii(
2042 "Property is read-only!" ),
2043 static_cast< cppu::OWeakObject * >( this ) );
2045 else if ( rName.equalsAsciiL(
2046 RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) )
2048 // Read-only property!
2049 aRet[ n ] <<= lang::IllegalAccessException(
2050 rtl::OUString::createFromAscii(
2051 "Property is read-only!" ),
2052 static_cast< cppu::OWeakObject * >( this ) );
2054 else if ( rName.equalsAsciiL(
2055 RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) )
2057 // Read-only property!
2058 aRet[ n ] <<= lang::IllegalAccessException(
2059 rtl::OUString::createFromAscii(
2060 "Property is read-only!" ),
2061 static_cast< cppu::OWeakObject * >( this ) );
2063 else if ( rName.equalsAsciiL(
2064 RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) )
2066 // Read-only property!
2067 // (but could be writable, if 'getcontenttype' would be)
2068 aRet[ n ] <<= lang::IllegalAccessException(
2069 rtl::OUString::createFromAscii(
2070 "Property is read-only!" ),
2071 static_cast< cppu::OWeakObject * >( this ) );
2073 else
2075 if ( getResourceType( xEnv, xResAccess ) == DAV )
2077 // Property value will be set on server.
2078 ProppatchValue aValue( PROPSET, rName, rValue.Value );
2079 aProppatchValues.push_back( aValue );
2081 // remember position within sequence of values (for
2082 // error handling).
2083 aProppatchPropsPositions.push_back( n );
2085 else
2087 // Property value will be stored in local property store.
2088 if ( !bTriedToGetAdditonalPropSet &&
2089 !xAdditionalPropSet.is() )
2091 xAdditionalPropSet
2092 = getAdditionalPropertySet( sal_False );
2093 bTriedToGetAdditonalPropSet = sal_True;
2096 if ( xAdditionalPropSet.is() )
2100 uno::Any aOldValue
2101 = xAdditionalPropSet->getPropertyValue( rName );
2102 if ( aOldValue != rValue.Value )
2104 xAdditionalPropSet->setPropertyValue(
2105 rName, rValue.Value );
2107 aEvent.PropertyName = rName;
2108 aEvent.OldValue = aOldValue;
2109 aEvent.NewValue = rValue.Value;
2111 aChanges.getArray()[ nChanged ] = aEvent;
2112 nChanged++;
2115 catch ( beans::UnknownPropertyException const & e )
2117 aRet[ n ] <<= e;
2119 catch ( lang::WrappedTargetException const & e )
2121 aRet[ n ] <<= e;
2123 catch ( beans::PropertyVetoException const & e )
2125 aRet[ n ] <<= e;
2127 catch ( lang::IllegalArgumentException const & e )
2129 aRet[ n ] <<= e;
2132 else
2134 aRet[ n ] <<= uno::Exception(
2135 rtl::OUString::createFromAscii(
2136 "No property set for storing the value!" ),
2137 static_cast< cppu::OWeakObject * >( this ) );
2142 } // for
2144 if ( !bTransient && aProppatchValues.size() )
2148 // Set property values at server.
2149 xResAccess->PROPPATCH( aProppatchValues, xEnv );
2151 std::vector< ProppatchValue >::const_iterator it
2152 = aProppatchValues.begin();
2153 std::vector< ProppatchValue >::const_iterator end
2154 = aProppatchValues.end();
2156 while ( it != end )
2158 aEvent.PropertyName = (*it).name;
2159 aEvent.OldValue = uno::Any(); // @@@ to expensive to obtain!
2160 aEvent.NewValue = (*it).value;
2162 aChanges.getArray()[ nChanged ] = aEvent;
2163 nChanged++;
2165 ++it;
2168 catch ( DAVException const & e )
2170 // OSL_ENSURE( sal_False,
2171 // "Content::setPropertyValues - PROPPATCH failed!" );
2173 #if 1
2174 cancelCommandExecution( e, xEnv );
2175 // unreachable
2176 #else
2177 // Note: PROPPATCH either sets ALL property values OR NOTHING.
2179 std::vector< sal_Int32 >::const_iterator it
2180 = aProppatchPropsPositions.begin();
2181 std::vector< sal_Int32 >::const_iterator end
2182 = aProppatchPropsPositions.end();
2184 while ( it != end )
2186 // Set error.
2187 aRet[ (*it) ] <<= MapDAVException( e, sal_True );
2188 ++it;
2190 #endif
2194 if ( bExchange )
2196 // Assemble new content identifier...
2198 rtl::OUString aNewURL = getParentURL();
2199 if ( aNewURL.lastIndexOf( '/' ) != ( aNewURL.getLength() - 1 ) )
2200 aNewURL += rtl::OUString::createFromAscii( "/" );
2202 aNewURL += NeonUri::escapeSegment( aNewTitle );
2204 uno::Reference< ucb::XContentIdentifier > xNewId
2205 = new ::ucbhelper::ContentIdentifier( xSMgr, aNewURL );
2206 uno::Reference< ucb::XContentIdentifier > xOldId = xIdentifier;
2210 NeonUri sourceURI( xOldId->getContentIdentifier() );
2211 NeonUri targetURI( xNewId->getContentIdentifier() );
2212 targetURI.SetScheme( sourceURI.GetScheme() );
2214 xResAccess->MOVE(
2215 sourceURI.GetPath(), targetURI.GetURI(), sal_False, xEnv );
2216 // @@@ Should check for resources that could not be moved
2217 // (due to source access or target overwrite) and send
2218 // this information through the interaction handler.
2220 // @@@ Existing content should be checked to see if it needs
2221 // to be deleted at the source
2223 // @@@ Existing content should be checked to see if it has
2224 // been overwritten at the target
2226 if ( exchangeIdentity( xNewId ) )
2228 xResAccess->setURL( aNewURL );
2230 // DAV resources store all additional props on server!
2231 // // Adapt Additional Core Properties.
2232 // renameAdditionalPropertySet( xOldId->getContentIdentifier(),
2233 // xNewId->getContentIdentifier(),
2234 // sal_True );
2236 else
2238 // Do not set new title!
2239 aNewTitle = rtl::OUString();
2241 // Set error .
2242 aRet[ nTitlePos ] <<= uno::Exception(
2243 rtl::OUString::createFromAscii( "Exchange failed!" ),
2244 static_cast< cppu::OWeakObject * >( this ) );
2247 catch ( DAVException const & e )
2249 // Do not set new title!
2250 aNewTitle = rtl::OUString();
2252 // Set error .
2253 aRet[ nTitlePos ] <<= MapDAVException( e, sal_True );
2257 if ( aNewTitle.getLength() )
2259 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2261 aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" );
2262 aEvent.OldValue = uno::makeAny( aOldTitle );
2263 aEvent.NewValue = uno::makeAny( aNewTitle );
2265 m_aEscapedTitle = NeonUri::escapeSegment( aNewTitle );
2267 aChanges.getArray()[ nChanged ] = aEvent;
2268 nChanged++;
2271 if ( nChanged > 0 )
2273 aChanges.realloc( nChanged );
2274 notifyPropertiesChange( aChanges );
2278 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2279 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2282 return aRet;
2285 //=========================================================================
2286 uno::Any Content::open(
2287 const ucb::OpenCommandArgument2 & rArg,
2288 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2289 throw( uno::Exception )
2291 uno::Any aRet;
2293 #if OSL_DEBUG_LEVEL > 0
2294 fprintf( stderr, "WebDAV: Content::open() this=%p\n", this );
2295 #endif
2297 sal_Bool bOpenFolder = ( ( rArg.Mode == ucb::OpenMode::ALL ) ||
2298 ( rArg.Mode == ucb::OpenMode::FOLDERS ) ||
2299 ( rArg.Mode == ucb::OpenMode::DOCUMENTS ) );
2300 if ( bOpenFolder )
2302 if ( isFolder( xEnv ) )
2304 // Open collection.
2306 uno::Reference< ucb::XDynamicResultSet > xSet
2307 = new DynamicResultSet( m_xSMgr, this, rArg, xEnv );
2308 aRet <<= xSet;
2310 else
2312 // Error: Not a folder!
2314 rtl::OUStringBuffer aMsg;
2315 if ( getResourceType( xEnv ) == FTP )
2317 // #114653#
2318 aMsg.appendAscii( "FTP over HTTP proxy: resource cannot "
2319 "be opened as folder! Wrong Open Mode!" );
2321 else
2323 aMsg.appendAscii( "Non-folder resource cannot be "
2324 "opened as folder! Wrong Open Mode!" );
2327 ucbhelper::cancelCommandExecution(
2328 uno::makeAny(
2329 lang::IllegalArgumentException(
2330 aMsg.makeStringAndClear(),
2331 static_cast< cppu::OWeakObject * >( this ),
2332 -1 ) ),
2333 xEnv );
2334 // Unreachable
2338 if ( !rArg.Sink.is() )
2339 return aRet;
2341 // Open document.
2343 if ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE )
2345 #if OSL_DEBUG_LEVEL > 0
2346 fprintf( stderr, "WebDAV: rArg.Mode currently(?) unsupported\n" );
2347 #endif
2348 // Currently(?) unsupported.
2349 ucbhelper::cancelCommandExecution(
2350 uno::makeAny(
2351 ucb::UnsupportedOpenModeException(
2352 rtl::OUString(),
2353 static_cast< cppu::OWeakObject * >( this ),
2354 sal_Int16( rArg.Mode ) ) ),
2355 xEnv );
2356 // Unreachable
2359 rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
2360 uno::Reference< io::XOutputStream > xOut
2361 = uno::Reference< io::XOutputStream >( rArg.Sink, uno::UNO_QUERY );
2362 if ( xOut.is() )
2364 #if OSL_DEBUG_LEVEL > 0
2365 fprintf( stderr, "WebDAV: rArg.Sink is XOutputStream\n" );
2366 #endif
2367 // PUSH: write data
2370 std::auto_ptr< DAVResourceAccess > xResAccess;
2373 osl::MutexGuard aGuard( m_aMutex );
2375 xResAccess.reset(
2376 new DAVResourceAccess( *m_xResAccess.get() ) );
2379 DAVResource aResource;
2380 std::vector< rtl::OUString > aHeaders;
2382 xResAccess->GET( xOut, aHeaders, aResource, xEnv );
2383 m_bDidGetOrHead = true;
2386 osl::MutexGuard aGuard( m_aMutex );
2388 // cache headers.
2389 if ( !m_xCachedProps.get())
2390 m_xCachedProps.reset( new ContentProperties( aResource ) );
2391 else
2392 m_xCachedProps->addProperties( aResource );
2394 m_xResAccess.reset(
2395 new DAVResourceAccess( *xResAccess.get() ) );
2398 catch ( DAVException const & e )
2400 cancelCommandExecution( e, xEnv );
2401 // Unreachable
2404 else
2406 uno::Reference< io::XActiveDataSink > xDataSink
2407 = uno::Reference< io::XActiveDataSink >( rArg.Sink,
2408 uno::UNO_QUERY );
2409 if ( xDataSink.is() )
2411 #if OSL_DEBUG_LEVEL > 0
2412 fprintf( stderr, "WebDAV: rArg.Sink is XActiveDataSink\n" );
2413 #endif
2414 // PULL: wait for client read
2418 osl::MutexGuard aGuard( m_aMutex );
2420 // throw away previously cached headers.
2421 m_xCachedProps.reset();
2423 // fill inputsream sync; return if all data present
2424 DAVResource aResource;
2425 std::vector< rtl::OUString > aHeaders;
2426 // // Obtain list containing all HTTP headers that can
2427 // // be mapped to UCB properties.
2428 // ContentProperties::getMappableHTTPHeaders( aHeaders );
2429 uno::Reference< io::XInputStream > xIn
2430 = m_xResAccess->GET( aHeaders, aResource, xEnv )->getInputStream();
2433 osl::MutexGuard aGuard( m_aMutex );
2435 m_xCachedProps.reset(
2436 new ContentProperties( aResource ) );
2439 xDataSink->setInputStream( xIn );
2441 catch ( DAVException const & e )
2443 cancelCommandExecution( e, xEnv );
2444 // Unreachable
2447 else
2449 uno::Reference< io::XActiveDataStreamer > xDataStreamer
2450 = uno::Reference< io::XActiveDataStreamer >( rArg.Sink,
2451 uno::UNO_QUERY );
2452 if ( xDataStreamer.is() && !m_bForceReadOnly )
2454 #if OSL_DEBUG_LEVEL > 0
2455 fprintf( stderr, "WebDAV: rArg.Sink is XActiveDataStreamer\n" );
2456 #endif
2457 // prepare the lock
2458 m_pLock = new ucb::Lock;
2459 m_pLock->Depth = ucb::LockDepth_ZERO;
2460 m_pLock->Scope = ucb::LockScope_EXCLUSIVE;
2461 m_pLock->Timeout = 2*60; // 2 minutes
2463 m_nToExpire = m_pLock->Timeout;
2465 // PULL: wait for client read
2468 std::auto_ptr< DAVResourceAccess > xResAccess;
2470 osl::MutexGuard aGuard( m_aMutex );
2472 xResAccess.reset(
2473 new DAVResourceAccess( *m_xResAccess.get() ) );
2476 // fill inputsream sync; return if all data present
2477 DAVResource aResource;
2478 std::vector< rtl::OUString > aHeaders;
2480 try {
2481 m_xResAccess->LOCK( *m_pLock, xEnv );
2482 m_xLockEnv = xEnv;
2484 catch ( ucb::CommandFailedException const &e )
2486 // stream locked?
2487 ucb::InteractiveIOException aIoException;
2488 if ( ( e.Reason >>= aIoException ) && ( aIoException.Code == ucb::IOErrorCode_LOCKING_VIOLATION ) )
2490 delete m_pLock;
2491 m_pLock = NULL;
2492 // yes => we must be read only at the next try
2493 m_bForceReadOnly = sal_True;
2496 throw;
2499 uno::Reference< io::XStream > xStream
2500 = xResAccess->GET( aHeaders, aResource, xEnv, sal_True );
2501 m_bDidGetOrHead = true;
2503 // pass the URL to the stream
2504 static_cast< NeonInputStream* >( xStream.get() )->SetURL( m_xResAccess->getURL() );
2507 osl::MutexGuard aGuard( m_aMutex );
2509 // cache headers.
2510 if ( !m_xCachedProps.get())
2511 m_xCachedProps.reset( new ContentProperties( aResource ) );
2512 else
2513 m_xCachedProps->addProperties( aResource.properties );
2515 m_xResAccess.reset(
2516 new DAVResourceAccess( *xResAccess.get() ) );
2519 xDataStreamer->setStream( xStream );
2521 catch ( DAVException const & e )
2523 m_xResAccess->UNLOCK( *m_pLock, xEnv );
2524 delete m_pLock;
2525 m_pLock = NULL;
2526 m_bForceReadOnly = sal_False;
2528 cancelCommandExecution( e, xEnv );
2529 // Unreachable
2532 else
2534 #if OSL_DEBUG_LEVEL > 0
2535 fprintf( stderr, "WebDAV: unsupported rArg.Sink\n" );
2536 #endif
2537 // Note: aOpenCommand.Sink may contain an XStream
2538 // implementation. Support for this type of
2539 // sink is optional...
2540 ucbhelper::cancelCommandExecution(
2541 uno::makeAny(
2542 ucb::UnsupportedDataSinkException(
2543 rtl::OUString(),
2544 static_cast< cppu::OWeakObject * >( this ),
2545 rArg.Sink ) ),
2546 xEnv );
2547 // Unreachable
2552 return aRet;
2555 //=========================================================================
2556 void Content::post(
2557 const ucb::PostCommandArgument2 & rArg,
2558 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2559 throw( uno::Exception )
2561 #if OSL_DEBUG_LEVEL > 0
2562 fprintf( stderr, "WebDAV: Content::post() this=%p\n", this );
2563 #endif
2565 uno::Reference< io::XActiveDataSink > xSink( rArg.Sink, uno::UNO_QUERY );
2566 if ( xSink.is() )
2568 #if OSL_DEBUG_LEVEL > 0
2569 fprintf( stderr, "WebDAV: rArg.Sink is XActiveDataSink\n" );
2570 #endif
2573 std::auto_ptr< DAVResourceAccess > xResAccess;
2575 osl::MutexGuard aGuard( m_aMutex );
2576 xResAccess.reset(
2577 new DAVResourceAccess( *m_xResAccess.get() ) );
2580 uno::Reference< io::XInputStream > xResult
2581 = xResAccess->POST( rArg.MediaType,
2582 rArg.Referer,
2583 rArg.Source,
2584 xEnv );
2587 osl::MutexGuard aGuard( m_aMutex );
2588 m_xResAccess.reset(
2589 new DAVResourceAccess( *xResAccess.get() ) );
2592 xSink->setInputStream( xResult );
2594 catch ( DAVException const & e )
2596 cancelCommandExecution( e, xEnv, sal_True );
2597 // Unreachable
2600 else
2602 uno::Reference< io::XOutputStream > xResult( rArg.Sink, uno::UNO_QUERY );
2603 if ( xResult.is() )
2605 #if OSL_DEBUG_LEVEL > 0
2606 fprintf( stderr, "WebDAV: rArg.Sink is XOutputStream\n" );
2607 #endif
2610 std::auto_ptr< DAVResourceAccess > xResAccess;
2612 osl::MutexGuard aGuard( m_aMutex );
2613 xResAccess.reset(
2614 new DAVResourceAccess( *m_xResAccess.get() ) );
2617 xResAccess->POST( rArg.MediaType,
2618 rArg.Referer,
2619 rArg.Source,
2620 xResult,
2621 xEnv );
2624 osl::MutexGuard aGuard( m_aMutex );
2625 m_xResAccess.reset(
2626 new DAVResourceAccess( *xResAccess.get() ) );
2629 catch ( DAVException const & e )
2631 cancelCommandExecution( e, xEnv, sal_True );
2632 // Unreachable
2635 else
2637 #if OSL_DEBUG_LEVEL > 0
2638 fprintf( stderr, "WebDAV: rArg.Sink is XActiveDataStreamer (or something)\n" );
2639 #endif
2640 ucbhelper::cancelCommandExecution(
2641 uno::makeAny(
2642 ucb::UnsupportedDataSinkException(
2643 rtl::OUString(),
2644 static_cast< cppu::OWeakObject * >( this ),
2645 rArg.Sink ) ),
2646 xEnv );
2647 // Unreachable
2652 //=========================================================================
2653 void Content::queryChildren( ContentRefList& rChildren )
2655 // Obtain a list with a snapshot of all currently instanciated contents
2656 // from provider and extract the contents which are direct children
2657 // of this content.
2659 ::ucbhelper::ContentRefList aAllContents;
2660 m_xProvider->queryExistingContents( aAllContents );
2662 rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
2663 sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
2665 if ( nURLPos != ( aURL.getLength() - 1 ) )
2667 // No trailing slash found. Append.
2668 aURL += rtl::OUString::createFromAscii( "/" );
2671 sal_Int32 nLen = aURL.getLength();
2673 ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin();
2674 ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
2676 while ( it != end )
2678 ::ucbhelper::ContentImplHelperRef xChild = (*it);
2679 rtl::OUString aChildURL
2680 = xChild->getIdentifier()->getContentIdentifier();
2682 // Is aURL a prefix of aChildURL?
2683 if ( ( aChildURL.getLength() > nLen ) &&
2684 ( aChildURL.compareTo( aURL, nLen ) == 0 ) )
2686 sal_Int32 nPos = nLen;
2687 nPos = aChildURL.indexOf( '/', nPos );
2689 if ( ( nPos == -1 ) ||
2690 ( nPos == ( aChildURL.getLength() - 1 ) ) )
2692 // No further slashes / only a final slash. It's a child!
2693 rChildren.push_back(
2694 ::webdav_ucp::Content::ContentRef(
2695 static_cast< ::webdav_ucp::Content * >(
2696 xChild.get() ) ) );
2699 ++it;
2703 //=========================================================================
2704 void Content::insert(
2705 const uno::Reference< io::XInputStream > & xInputStream,
2706 sal_Bool bReplaceExisting,
2707 const uno::Reference< ucb::XCommandEnvironment >& Environment )
2708 throw( uno::Exception )
2710 sal_Bool bTransient, bCollection;
2711 rtl::OUString aEscapedTitle;
2712 std::auto_ptr< DAVResourceAccess > xResAccess;
2714 #if OSL_DEBUG_LEVEL > 0
2715 fprintf( stderr, "WebDAV: Content::insert() this=%p\n", this );
2716 #endif
2719 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2721 bTransient = m_bTransient;
2722 bCollection = m_bCollection;
2723 aEscapedTitle = m_aEscapedTitle;
2724 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
2727 // Check, if all required properties are present.
2729 if ( aEscapedTitle.getLength() == 0 )
2731 OSL_ENSURE( sal_False, "Content::insert - Title missing!" );
2733 uno::Sequence< rtl::OUString > aProps( 1 );
2734 aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" );
2735 ucbhelper::cancelCommandExecution(
2736 uno::makeAny( ucb::MissingPropertiesException(
2737 rtl::OUString(),
2738 static_cast< cppu::OWeakObject * >( this ),
2739 aProps ) ),
2740 Environment );
2741 // Unreachable
2744 if ( !bReplaceExisting )
2746 /* [RFC 2616] - HTTP
2748 The PUT method requests that the enclosed entity be stored under the
2749 supplied Request-URI. If the Request-URI refers to an already
2750 existing resource, the enclosed entity SHOULD be considered as a
2751 modified version of the one residing on the origin server.
2754 /* [RFC 2518] - WebDAV
2756 MKCOL creates a new collection resource at the location specified by
2757 the Request-URI. If the resource identified by the Request-URI is
2758 non-null then the MKCOL MUST fail.
2761 // ==> Complain on PUT, continue on MKCOL.
2762 if ( !bTransient || ( bTransient && !bCollection ) )
2764 ucb::UnsupportedNameClashException aEx(
2765 rtl::OUString::createFromAscii(
2766 "Unable to write without overwrite!" ),
2767 static_cast< cppu::OWeakObject * >( this ),
2768 ucb::NameClash::ERROR );
2770 uno::Reference< task::XInteractionHandler > xIH;
2772 if ( Environment.is() )
2773 xIH = Environment->getInteractionHandler();
2775 if ( xIH.is() )
2777 uno::Any aExAsAny( uno::makeAny( aEx ) );
2779 rtl::Reference< ucbhelper::SimpleInteractionRequest > xRequest
2780 = new ucbhelper::SimpleInteractionRequest(
2781 aExAsAny,
2782 ucbhelper::CONTINUATION_APPROVE
2783 | ucbhelper::CONTINUATION_DISAPPROVE );
2784 xIH->handle( xRequest.get() );
2786 const sal_Int32 nResp = xRequest->getResponse();
2788 switch ( nResp )
2790 case ucbhelper::CONTINUATION_UNKNOWN:
2791 // Not handled; throw.
2792 throw aEx;
2793 // break;
2795 case ucbhelper::CONTINUATION_APPROVE:
2796 // Continue -> Overwrite.
2797 bReplaceExisting = sal_True;
2798 break;
2800 case ucbhelper::CONTINUATION_DISAPPROVE:
2801 // Abort.
2802 throw ucb::CommandFailedException(
2803 rtl::OUString(),
2804 uno::Reference< uno::XInterface >(),
2805 aExAsAny );
2806 // break;
2808 default:
2809 OSL_ENSURE( sal_False,
2810 "Content::insert - "
2811 "Unknown interaction selection!" );
2812 throw ucb::CommandFailedException(
2813 rtl::OUString::createFromAscii(
2814 "Unknown interaction selection!" ),
2815 uno::Reference< uno::XInterface >(),
2816 aExAsAny );
2817 // break;
2820 else
2822 // No IH; throw.
2823 throw aEx;
2828 if ( bTransient )
2830 // Assemble new content identifier...
2831 rtl::OUString aURL = getParentURL();
2832 if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) )
2833 aURL += rtl::OUString::createFromAscii( "/" );
2835 aURL += aEscapedTitle;
2839 xResAccess->setURL( aURL );
2841 if ( bCollection )
2842 xResAccess->MKCOL( Environment );
2843 else
2844 xResAccess->PUT( xInputStream, Environment );
2846 catch ( DAVException const & except )
2848 if ( bCollection )
2850 if ( except.getStatus() == SC_METHOD_NOT_ALLOWED )
2852 // [RFC 2518] - WebDAV
2853 // 405 (Method Not Allowed) - MKCOL can only be
2854 // executed on a deleted/non-existent resource.
2856 if ( bReplaceExisting )
2858 // Destroy old resource.
2861 xResAccess->DESTROY( Environment );
2863 catch ( DAVException const & e )
2865 cancelCommandExecution( e, Environment, sal_True );
2866 // Unreachable
2869 // Insert (recursion!).
2870 insert( xInputStream, bReplaceExisting, Environment );
2873 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2874 m_xResAccess.reset(
2875 new DAVResourceAccess( *xResAccess.get() ) );
2878 // Success!
2879 return;
2881 else
2883 rtl::OUString aTitle;
2886 NeonUri aURI( aURL );
2887 aTitle = aURI.GetPathBaseNameUnescaped();
2889 catch ( DAVException const & )
2893 ucbhelper::cancelCommandExecution(
2894 uno::makeAny(
2895 ucb::NameClashException(
2896 rtl::OUString(),
2897 static_cast< cppu::OWeakObject * >( this ),
2898 task::InteractionClassification_ERROR,
2899 aTitle ) ),
2900 Environment );
2901 // Unreachable
2906 cancelCommandExecution( except, Environment, sal_True );
2907 // Unreachable
2911 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2912 m_xIdentifier
2913 = new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL );
2916 inserted();
2919 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2920 m_bTransient = sal_False;
2923 else
2925 if ( !xInputStream.is() )
2927 ucbhelper::cancelCommandExecution(
2928 uno::makeAny(
2929 ucb::MissingInputStreamException(
2930 rtl::OUString(),
2931 static_cast< cppu::OWeakObject * >( this ) ) ),
2932 Environment );
2933 // Unreachable
2938 xResAccess->PUT( xInputStream, Environment );
2940 catch ( DAVException const & e )
2942 cancelCommandExecution( e, Environment, sal_True );
2943 // Unreachable
2948 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2949 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2953 //=========================================================================
2954 void Content::transfer(
2955 const ucb::TransferInfo & rArgs,
2956 const uno::Reference< ucb::XCommandEnvironment >& Environment )
2957 throw( uno::Exception )
2959 uno::Reference< lang::XMultiServiceFactory > xSMgr;
2960 uno::Reference< ucb::XContentIdentifier > xIdentifier;
2961 uno::Reference< ucb::XContentProvider > xProvider;
2962 std::auto_ptr< DAVResourceAccess > xResAccess;
2965 osl::Guard< osl::Mutex > aGuard( m_aMutex );
2967 xSMgr.set( m_xSMgr );
2968 xIdentifier.set( m_xIdentifier );
2969 xProvider.set( m_xProvider.get() );
2970 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
2973 rtl::OUString aTargetURI;
2976 NeonUri sourceURI( rArgs.SourceURL );
2977 NeonUri targetURI( xIdentifier->getContentIdentifier() );
2978 aTargetURI = targetURI.GetPathBaseNameUnescaped();
2980 // Check source's and target's URL scheme
2982 const rtl::OUString aScheme = sourceURI.GetScheme().toAsciiLowerCase();
2983 if ( aScheme.equalsAsciiL(
2984 RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) )
2986 sourceURI.SetScheme(
2987 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2989 else if ( aScheme.equalsAsciiL(
2990 RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) )
2992 sourceURI.SetScheme(
2993 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2995 else if ( aScheme.equalsAsciiL(
2996 RTL_CONSTASCII_STRINGPARAM( PLAIN_WEBDAV_URL_SCHEME ) ) )
2998 sourceURI.SetScheme(
2999 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
3001 else if ( aScheme.equalsAsciiL(
3002 RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) )
3004 sourceURI.SetScheme(
3005 rtl::OUString::createFromAscii( HTTPS_URL_SCHEME ) );
3007 else if ( aScheme.equalsAsciiL(
3008 RTL_CONSTASCII_STRINGPARAM( PLAIN_WEBDAVS_URL_SCHEME ) ) )
3010 sourceURI.SetScheme(
3011 rtl::OUString::createFromAscii( HTTPS_URL_SCHEME ) );
3013 else
3015 if ( !aScheme.equalsAsciiL(
3016 RTL_CONSTASCII_STRINGPARAM( HTTP_URL_SCHEME ) ) &&
3017 !aScheme.equalsAsciiL(
3018 RTL_CONSTASCII_STRINGPARAM( HTTPS_URL_SCHEME ) ) )
3020 ucbhelper::cancelCommandExecution(
3021 uno::makeAny(
3022 ucb::InteractiveBadTransferURLException(
3023 rtl::OUString::createFromAscii(
3024 "Unsupported URL scheme!" ),
3025 static_cast< cppu::OWeakObject * >( this ) ) ),
3026 Environment );
3027 // Unreachable
3031 if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
3032 RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) )
3033 targetURI.SetScheme(
3034 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
3035 else if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
3036 RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) )
3037 targetURI.SetScheme(
3038 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
3039 else if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
3040 RTL_CONSTASCII_STRINGPARAM( PLAIN_WEBDAV_URL_SCHEME ) ) )
3041 targetURI.SetScheme(
3042 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
3043 else if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
3044 RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) )
3045 targetURI.SetScheme(
3046 rtl::OUString::createFromAscii( HTTPS_URL_SCHEME ) );
3047 else if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
3048 RTL_CONSTASCII_STRINGPARAM( PLAIN_WEBDAVS_URL_SCHEME ) ) )
3049 targetURI.SetScheme(
3050 rtl::OUString::createFromAscii( HTTPS_URL_SCHEME ) );
3052 // @@@ This implementation of 'transfer' only works
3053 // if the source and target are located at same host.
3054 // (Neon does not support cross-server copy/move)
3056 // Check for same host
3058 if ( sourceURI.GetHost().getLength() &&
3059 ( sourceURI.GetHost() != targetURI.GetHost() ) )
3061 ucbhelper::cancelCommandExecution(
3062 uno::makeAny( ucb::InteractiveBadTransferURLException(
3063 rtl::OUString::createFromAscii(
3064 "Different hosts!" ),
3065 static_cast< cppu::OWeakObject * >( this ) ) ),
3066 Environment );
3067 // Unreachable
3070 rtl::OUString aTitle = rArgs.NewTitle;
3072 if ( !aTitle.getLength() )
3073 aTitle = sourceURI.GetPathBaseNameUnescaped();
3075 if ( aTitle.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "/" ) ) )
3077 // kso: ???
3078 aTitle = rtl::OUString();
3081 targetURI.AppendPath( aTitle );
3083 rtl::OUString aTargetURL = xIdentifier->getContentIdentifier();
3084 if ( ( aTargetURL.lastIndexOf( '/' ) + 1 )
3085 != aTargetURL.getLength() )
3086 aTargetURL += rtl::OUString::createFromAscii( "/" );
3088 aTargetURL += aTitle;
3090 uno::Reference< ucb::XContentIdentifier > xTargetId
3091 = new ::ucbhelper::ContentIdentifier( xSMgr, aTargetURL );
3093 DAVResourceAccess aSourceAccess( xSMgr,
3094 xResAccess->getSessionFactory(),
3095 sourceURI.GetURI() );
3097 if ( rArgs.MoveData == sal_True )
3099 uno::Reference< ucb::XContentIdentifier > xId
3100 = new ::ucbhelper::ContentIdentifier( xSMgr, rArgs.SourceURL );
3102 // Note: The static cast is okay here, because its sure that
3103 // xProvider is always the WebDAVContentProvider.
3104 rtl::Reference< Content > xSource
3105 = static_cast< Content * >(
3106 xProvider->queryContent( xId ).get() );
3108 // [RFC 2518] - WebDAV
3109 // If a resource exists at the destination and the Overwrite
3110 // header is "T" then prior to performing the move the server
3111 // MUST perform a DELETE with "Depth: infinity" on the
3112 // destination resource. If the Overwrite header is set to
3113 // "F" then the operation will fail.
3115 aSourceAccess.MOVE( sourceURI.GetPath(),
3116 targetURI.GetURI(),
3117 rArgs.NameClash
3118 == ucb::NameClash::OVERWRITE,
3119 Environment );
3121 if ( xSource.is() )
3123 // Propagate destruction to listeners.
3124 xSource->destroy( sal_True );
3127 // DAV resources store all additional props on server!
3128 // // Rename own and all children's Additional Core Properties.
3129 // renameAdditionalPropertySet( xId->getContentIdentifier(),
3130 // xTargetId->getContentIdentifier(),
3131 // sal_True );
3133 else
3135 // [RFC 2518] - WebDAV
3136 // If a resource exists at the destination and the Overwrite
3137 // header is "T" then prior to performing the copy the server
3138 // MUST perform a DELETE with "Depth: infinity" on the
3139 // destination resource. If the Overwrite header is set to
3140 // "F" then the operation will fail.
3142 aSourceAccess.COPY( sourceURI.GetPath(),
3143 targetURI.GetURI(),
3144 rArgs.NameClash
3145 == ucb::NameClash::OVERWRITE,
3146 Environment );
3148 // DAV resources store all additional props on server!
3149 // // Copy own and all children's Additional Core Properties.
3150 // copyAdditionalPropertySet( xId->getContentIdentifier(),
3151 // xTargetId->getContentIdentifier(),
3152 // sal_True );
3155 // Note: The static cast is okay here, because its sure that
3156 // xProvider is always the WebDAVContentProvider.
3157 rtl::Reference< Content > xTarget
3158 = static_cast< Content * >(
3159 xProvider->queryContent( xTargetId ).get() );
3161 // Announce transfered content in its new folder.
3162 xTarget->inserted();
3164 catch ( ucb::IllegalIdentifierException const & )
3166 // queryContent
3168 catch ( DAVException const & e )
3170 // [RFC 2518] - WebDAV
3171 // 412 (Precondition Failed) - The server was unable to maintain
3172 // the liveness of the properties listed in the propertybehavior
3173 // XML element or the Overwrite header is "F" and the state of
3174 // the destination resource is non-null.
3176 if ( e.getStatus() == SC_PRECONDITION_FAILED )
3178 switch ( rArgs.NameClash )
3180 case ucb::NameClash::ERROR:
3182 ucbhelper::cancelCommandExecution(
3183 uno::makeAny(
3184 ucb::NameClashException(
3185 rtl::OUString(),
3186 static_cast< cppu::OWeakObject * >( this ),
3187 task::InteractionClassification_ERROR,
3188 aTargetURI ) ),
3189 Environment );
3190 // Unreachable
3193 case ucb::NameClash::OVERWRITE:
3194 break;
3196 case ucb::NameClash::KEEP: // deprecated
3197 case ucb::NameClash::RENAME:
3198 case ucb::NameClash::ASK:
3199 default:
3201 ucbhelper::cancelCommandExecution(
3202 uno::makeAny(
3203 ucb::UnsupportedNameClashException(
3204 rtl::OUString(),
3205 static_cast< cppu::OWeakObject * >( this ),
3206 rArgs.NameClash ) ),
3207 Environment );
3208 // Unreachable
3213 cancelCommandExecution( e, Environment, sal_True );
3214 // Unreachable
3218 osl::Guard< osl::Mutex > aGuard( m_aMutex );
3219 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
3223 //=========================================================================
3224 void Content::destroy( sal_Bool bDeletePhysical )
3225 throw( uno::Exception )
3227 // @@@ take care about bDeletePhysical -> trashcan support
3228 rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
3230 uno::Reference< ucb::XContent > xThis = this;
3232 deleted();
3234 osl::Guard< osl::Mutex > aGuard( m_aMutex );
3236 // Process instanciated children...
3238 ::webdav_ucp::Content::ContentRefList aChildren;
3239 queryChildren( aChildren );
3241 ContentRefList::const_iterator it = aChildren.begin();
3242 ContentRefList::const_iterator end = aChildren.end();
3244 while ( it != end )
3246 (*it)->destroy( bDeletePhysical );
3247 ++it;
3251 //=========================================================================
3252 sal_Bool Content::exchangeIdentity(
3253 const uno::Reference< ucb::XContentIdentifier >& xNewId )
3255 if ( !xNewId.is() )
3256 return sal_False;
3258 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
3260 uno::Reference< ucb::XContent > xThis = this;
3262 // Already persistent?
3263 if ( m_bTransient )
3265 OSL_ENSURE( sal_False, "Content::exchangeIdentity - Not persistent!" );
3266 return sal_False;
3269 // Exchange own identitity.
3271 // Fail, if a content with given id already exists.
3272 // if ( !hasData( xNewId ) )
3274 rtl::OUString aOldURL = m_xIdentifier->getContentIdentifier();
3276 aGuard.clear();
3277 if ( exchange( xNewId ) )
3279 // Process instanciated children...
3281 ContentRefList aChildren;
3282 queryChildren( aChildren );
3284 ContentRefList::const_iterator it = aChildren.begin();
3285 ContentRefList::const_iterator end = aChildren.end();
3287 while ( it != end )
3289 ContentRef xChild = (*it);
3291 // Create new content identifier for the child...
3292 uno::Reference< ucb::XContentIdentifier >
3293 xOldChildId = xChild->getIdentifier();
3294 rtl::OUString aOldChildURL
3295 = xOldChildId->getContentIdentifier();
3296 rtl::OUString aNewChildURL
3297 = aOldChildURL.replaceAt(
3299 aOldURL.getLength(),
3300 xNewId->getContentIdentifier() );
3301 uno::Reference< ucb::XContentIdentifier >
3302 xNewChildId
3303 = new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewChildURL );
3305 if ( !xChild->exchangeIdentity( xNewChildId ) )
3306 return sal_False;
3308 ++it;
3310 return sal_True;
3314 OSL_ENSURE( sal_False,
3315 "Content::exchangeIdentity - "
3316 "Panic! Cannot exchange identity!" );
3317 return sal_False;
3320 //=========================================================================
3321 sal_Bool Content::isFolder(
3322 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
3323 throw( uno::Exception )
3326 osl::MutexGuard aGuard( m_aMutex );
3328 if ( m_bTransient )
3329 return m_bCollection;
3332 uno::Sequence< beans::Property > aProperties( 1 );
3333 aProperties[ 0 ].Name = rtl::OUString::createFromAscii( "IsFolder" );
3334 aProperties[ 0 ].Handle = -1;
3335 uno::Reference< sdbc::XRow > xRow( getPropertyValues( aProperties, xEnv ) );
3336 if ( xRow.is() )
3340 return xRow->getBoolean( 1 );
3342 catch ( sdbc::SQLException const & )
3347 return sal_False;
3350 //=========================================================================
3351 uno::Any Content::MapDAVException( const DAVException & e, sal_Bool bWrite )
3353 // Map DAVException...
3354 uno::Any aException;
3356 switch ( e.getStatus() )
3358 case SC_NOT_FOUND:
3360 uno::Sequence< uno::Any > aArgs( 1 );
3361 aArgs[ 0 ] <<= beans::PropertyValue(
3362 rtl::OUString::createFromAscii("Uri"), -1,
3363 uno::makeAny(m_xIdentifier->getContentIdentifier()),
3364 beans::PropertyState_DIRECT_VALUE);
3366 aException <<=
3367 ucb::InteractiveAugmentedIOException(
3368 rtl::OUString::createFromAscii( "Not found!" ),
3369 static_cast< cppu::OWeakObject * >( this ),
3370 task::InteractionClassification_ERROR,
3371 ucb::IOErrorCode_NOT_EXISTING,
3372 aArgs );
3373 return aException;
3376 default:
3377 break;
3380 switch ( e.getError() )
3382 case DAVException::DAV_HTTP_ERROR:
3384 if ( bWrite )
3385 aException <<=
3386 ucb::InteractiveNetworkWriteException(
3387 rtl::OUString(),
3388 static_cast< cppu::OWeakObject * >( this ),
3389 task::InteractionClassification_ERROR,
3390 e.getData() );
3391 else
3392 aException <<=
3393 ucb::InteractiveNetworkReadException(
3394 rtl::OUString(),
3395 static_cast< cppu::OWeakObject * >( this ),
3396 task::InteractionClassification_ERROR,
3397 e.getData() );
3398 break;
3401 case DAVException::DAV_HTTP_LOOKUP:
3402 aException <<=
3403 ucb::InteractiveNetworkResolveNameException(
3404 rtl::OUString(),
3405 static_cast< cppu::OWeakObject * >( this ),
3406 task::InteractionClassification_ERROR,
3407 e.getData() );
3408 break;
3410 // @@@ No matching InteractiveNetwork*Exception
3411 // case DAVException::DAV_HTTP_AUTH:
3412 // break;
3414 // @@@ No matching InteractiveNetwork*Exception
3415 // case DAVException::DAV_HTTP_AUTHPROXY:
3416 // break;
3418 case DAVException::DAV_HTTP_CONNECT:
3419 aException <<=
3420 ucb::InteractiveNetworkConnectException(
3421 rtl::OUString(),
3422 static_cast< cppu::OWeakObject * >( this ),
3423 task::InteractionClassification_ERROR,
3424 e.getData() );
3425 break;
3427 // @@@ No matching InteractiveNetwork*Exception
3428 // case DAVException::DAV_HTTP_TIMEOUT:
3429 // break;
3431 // @@@ No matching InteractiveNetwork*Exception
3432 // case DAVException::DAV_HTTP_REDIRECT:
3433 // break;
3435 // @@@ No matching InteractiveNetwork*Exception
3436 // case DAVException::DAV_SESSION_CREATE:
3437 // break;
3439 case DAVException::DAV_INVALID_ARG:
3440 aException <<=
3441 lang::IllegalArgumentException(
3442 rtl::OUString(),
3443 static_cast< cppu::OWeakObject * >( this ),
3444 -1 );
3445 break;
3447 default:
3448 aException <<=
3449 ucb::InteractiveNetworkGeneralException(
3450 rtl::OUString(),
3451 static_cast< cppu::OWeakObject * >( this ),
3452 task::InteractionClassification_ERROR );
3453 break;
3456 return aException;
3459 //=========================================================================
3460 // static
3461 bool Content::shouldAccessNetworkAfterException( const DAVException & e )
3463 if ( ( e.getStatus() == SC_NOT_FOUND ) ||
3464 ( e.getError() == DAVException::DAV_HTTP_LOOKUP ) ||
3465 ( e.getError() == DAVException::DAV_HTTP_CONNECT ) ||
3466 ( e.getError() == DAVException::DAV_HTTP_AUTH ) ||
3467 ( e.getError() == DAVException::DAV_HTTP_AUTHPROXY ) )
3468 return false;
3470 return true;
3473 //=========================================================================
3474 void Content::cancelCommandExecution(
3475 const DAVException & e,
3476 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
3477 sal_Bool bWrite /* = sal_False */ )
3478 throw ( uno::Exception )
3480 ucbhelper::cancelCommandExecution( MapDAVException( e, bWrite ), xEnv );
3481 // Unreachable
3484 //=========================================================================
3485 const rtl::OUString Content::getBaseURI( const std::auto_ptr< DAVResourceAccess > & rResAccess )
3487 osl::Guard< osl::Mutex > aGuard( m_aMutex );
3489 // First, try to obtain value of response header "Content-Location".
3490 if ( m_xCachedProps.get() )
3492 rtl::OUString aLocation;
3493 m_xCachedProps->getValue( rtl::OUString(
3494 RTL_CONSTASCII_USTRINGPARAM(
3495 "Content-Location" ) ) ) >>= aLocation;
3496 if ( aLocation.getLength() )
3500 // Do not use m_xIdentifier->getContentIdentifier() because it
3501 // for example does not reflect redirects applied to requests
3502 // done using the original URI but m_xResAccess' URI does.
3503 return rtl::Uri::convertRelToAbs( rResAccess->getURL(),
3504 aLocation );
3506 catch ( rtl::MalformedUriException const & )
3512 return rtl::OUString( rResAccess->getURL() );
3515 //=========================================================================
3516 const Content::ResourceType & Content::getResourceType(
3517 const uno::Reference< ucb::XCommandEnvironment >& xEnv,
3518 const std::auto_ptr< DAVResourceAccess > & rResAccess )
3519 throw ( uno::Exception )
3521 if ( m_eResourceType == UNKNOWN )
3523 osl::Guard< osl::Mutex > aGuard( m_aMutex );
3525 ResourceType eResourceType;
3526 eResourceType = m_eResourceType;
3528 const rtl::OUString & rURL = rResAccess->getURL();
3529 const rtl::OUString aScheme(
3530 rURL.copy( 0, rURL.indexOf( ':' ) ).toAsciiLowerCase() );
3532 if ( aScheme.equalsAsciiL(
3533 RTL_CONSTASCII_STRINGPARAM( FTP_URL_SCHEME ) ) )
3535 eResourceType = FTP;
3537 else
3541 // Try to fetch some frequently used property value, e.g. those
3542 // used when loading documents... along with identifying whether
3543 // this is a DAV resource.
3544 std::vector< DAVResource > resources;
3545 std::vector< rtl::OUString > aPropNames;
3546 uno::Sequence< beans::Property > aProperties( 4 );
3547 aProperties[ 0 ].Name = rtl::OUString::createFromAscii( "IsFolder" );
3548 aProperties[ 1 ].Name = rtl::OUString::createFromAscii( "IsDocument" );
3549 aProperties[ 2 ].Name = rtl::OUString::createFromAscii( "IsReadOnly" );
3550 aProperties[ 3 ].Name = rtl::OUString::createFromAscii( "MediaType" );
3552 ContentProperties::UCBNamesToDAVNames(
3553 aProperties, aPropNames );
3555 rResAccess->PROPFIND(
3556 DAVZERO, aPropNames, resources, xEnv );
3558 if ( resources.size() == 1 )
3560 m_xCachedProps.reset( new ContentProperties( resources[ 0 ] ) );
3561 m_xCachedProps->containsAllNames( aProperties, m_aFailedPropNames );
3563 eResourceType = DAV;
3565 catch ( DAVException const& e)
3567 rResAccess->resetUri();
3569 if (e.getStatus() == SC_METHOD_NOT_ALLOWED)
3571 // Status SC_METHOD_NOT_ALLOWED is a safe indicator that the
3572 // resource is NON_DAV
3573 eResourceType = NON_DAV;
3577 m_eResourceType = eResourceType;
3580 return m_eResourceType;
3583 //=========================================================================
3584 const Content::ResourceType & Content::getResourceType(
3585 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
3586 throw ( uno::Exception )
3588 return getResourceType( xEnv, m_xResAccess );