1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_ucb.hxx"
30 
31 /**************************************************************************
32                                   TODO
33  **************************************************************************
34 
35  *************************************************************************/
36 
37 #include <osl/diagnose.h>
38 #include "osl/doublecheckedlocking.h"
39 #include <rtl/uri.hxx>
40 #include <rtl/ustrbuf.hxx>
41 #include <ucbhelper/contentidentifier.hxx>
42 #include <ucbhelper/propertyvalueset.hxx>
43 #include <ucbhelper/simpleinteractionrequest.hxx>
44 #include <ucbhelper/cancelcommandexecution.hxx>
45 
46 #include <com/sun/star/beans/PropertyAttribute.hpp>
47 #include <com/sun/star/beans/PropertySetInfoChange.hpp>
48 #include <com/sun/star/beans/PropertySetInfoChangeEvent.hpp>
49 #include <com/sun/star/beans/PropertyValue.hpp>
50 #include <com/sun/star/io/XActiveDataSink.hpp>
51 #include <com/sun/star/io/XOutputStream.hpp>
52 #include <com/sun/star/lang/IllegalAccessException.hpp>
53 #include <com/sun/star/task/PasswordContainerInteractionHandler.hpp>
54 #include <com/sun/star/ucb/CommandEnvironment.hpp>
55 #include <com/sun/star/ucb/CommandFailedException.hpp>
56 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
57 #include <com/sun/star/ucb/InsertCommandArgument.hpp>
58 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
59 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
60 #include "com/sun/star/ucb/InteractiveLockingLockedException.hpp"
61 #include "com/sun/star/ucb/InteractiveLockingLockExpiredException.hpp"
62 #include "com/sun/star/ucb/InteractiveLockingNotLockedException.hpp"
63 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
64 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
65 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp>
66 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
67 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp>
68 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
69 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
70 #include <com/sun/star/ucb/NameClash.hpp>
71 #include <com/sun/star/ucb/NameClashException.hpp>
72 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
73 #include <com/sun/star/ucb/OpenMode.hpp>
74 #include <com/sun/star/ucb/PostCommandArgument2.hpp>
75 #include <com/sun/star/ucb/TransferInfo.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 <com/sun/star/ucb/XCommandInfo.hpp>
81 #include <com/sun/star/ucb/XPersistentPropertySet.hpp>
82 #include <com/sun/star/uno/XComponentContext.hpp>
83 
84 #include "webdavcontent.hxx"
85 #include "webdavprovider.hxx"
86 #include "webdavresultset.hxx"
87 #include "ContentProperties.hxx"
88 #include "NeonUri.hxx"
89 #include "UCBDeadPropertyValue.hxx"
90 
91 using namespace com::sun::star;
92 using namespace webdav_ucp;
93 
94 //=========================================================================
95 //=========================================================================
96 //
97 // Content Implementation.
98 //
99 //=========================================================================
100 //=========================================================================
101 
102 //=========================================================================
103 // ctr for content on an existing webdav resource
104 Content::Content(
105           const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
106           ContentProvider* pProvider,
107           const uno::Reference< ucb::XContentIdentifier >& Identifier,
108           rtl::Reference< DAVSessionFactory > const & rSessionFactory )
109   throw ( ucb::ContentCreationException )
110 : ContentImplHelper( rxSMgr, pProvider, Identifier ),
111   m_eResourceType( UNKNOWN ),
112   m_pProvider( pProvider ),
113   m_bTransient( false ),
114   m_bCollection( false ),
115   m_bDidGetOrHead( false )
116 {
117     try
118     {
119         m_xResAccess.reset( new DAVResourceAccess(
120                 rxSMgr,
121                 rSessionFactory,
122                 Identifier->getContentIdentifier() ) );
123 
124         NeonUri aURI( Identifier->getContentIdentifier() );
125         m_aEscapedTitle = aURI.GetPathBaseName();
126     }
127     catch ( DAVException const & )
128     {
129         throw ucb::ContentCreationException();
130     }
131 }
132 
133 //=========================================================================
134 // ctr for content on an non-existing webdav resource
135 Content::Content(
136             const uno::Reference< lang::XMultiServiceFactory >& rxSMgr,
137             ContentProvider* pProvider,
138             const uno::Reference< ucb::XContentIdentifier >& Identifier,
139             rtl::Reference< DAVSessionFactory > const & rSessionFactory,
140             sal_Bool isCollection )
141   throw ( ucb::ContentCreationException )
142 : ContentImplHelper( rxSMgr, pProvider, Identifier ),
143   m_eResourceType( UNKNOWN ),
144   m_pProvider( pProvider ),
145   m_bTransient( true ),
146   m_bCollection( isCollection ),
147   m_bDidGetOrHead( false )
148 {
149     try
150     {
151         m_xResAccess.reset( new DAVResourceAccess(
152             rxSMgr, rSessionFactory, Identifier->getContentIdentifier() ) );
153     }
154     catch ( DAVException const & )
155     {
156         throw ucb::ContentCreationException();
157     }
158 
159     // Do not set m_aEscapedTitle here! Content::insert relays on this!!!
160 }
161 
162 //=========================================================================
163 // virtual
164 Content::~Content()
165 {
166 }
167 
168 //=========================================================================
169 //
170 // XInterface methods.
171 //
172 //=========================================================================
173 
174 // virtual
175 void SAL_CALL Content::acquire()
176     throw( )
177 {
178     ContentImplHelper::acquire();
179 }
180 
181 //=========================================================================
182 // virtual
183 void SAL_CALL Content::release()
184     throw( )
185 {
186     ContentImplHelper::release();
187 }
188 
189 //=========================================================================
190 // virtual
191 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType )
192     throw ( uno::RuntimeException )
193 {
194     // Note: isFolder may require network activities! So call it only
195     //       if it is really necessary!!!
196     uno::Any aRet = cppu::queryInterface(
197         rType,
198         static_cast< ucb::XContentCreator * >( this ) );
199     if ( aRet.hasValue() )
200     {
201         try
202         {
203             uno::Reference< beans::XPropertySet > const xProps(
204                 m_xSMgr, uno::UNO_QUERY_THROW );
205             uno::Reference< uno::XComponentContext > xCtx;
206             xCtx.set( xProps->getPropertyValue(
207                 rtl::OUString(
208                     RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ),
209                 uno::UNO_QUERY_THROW );
210 
211             uno::Reference< task::XInteractionHandler > xIH(
212                 task::PasswordContainerInteractionHandler::create( xCtx ) );
213 
214             // Supply a command env to isFolder() that contains an interaction
215             // handler that uses the password container service to obtain
216             // credentials without displaying a password gui.
217 
218             uno::Reference< ucb::XCommandEnvironment > xCmdEnv(
219                 ucb::CommandEnvironment::create(
220                    xCtx,
221                    xIH,
222                    uno::Reference< ucb::XProgressHandler >() ) );
223 
224             return isFolder( xCmdEnv ) ? aRet : uno::Any();
225         }
226         catch ( uno::RuntimeException const & )
227         {
228             throw;
229         }
230         catch ( uno::Exception const & )
231         {
232             return uno::Any();
233         }
234     }
235     return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType );
236 }
237 
238 //=========================================================================
239 //
240 // XTypeProvider methods.
241 //
242 //=========================================================================
243 
244 XTYPEPROVIDER_COMMON_IMPL( Content );
245 
246 //=========================================================================
247 // virtual
248 uno::Sequence< uno::Type > SAL_CALL Content::getTypes()
249     throw( uno::RuntimeException )
250 {
251     sal_Bool bFolder = sal_False;
252     try
253     {
254         bFolder
255             = isFolder( uno::Reference< ucb::XCommandEnvironment >() );
256     }
257     catch ( uno::RuntimeException const & )
258     {
259         throw;
260     }
261     catch ( uno::Exception const & )
262     {
263     }
264 
265     cppu::OTypeCollection * pCollection = 0;
266 
267     if ( bFolder )
268     {
269         static cppu::OTypeCollection* pFolderTypes = 0;
270 
271         pCollection = pFolderTypes;
272         if ( !pCollection )
273         {
274             osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
275 
276             pCollection = pFolderTypes;
277             if ( !pCollection )
278             {
279                 static cppu::OTypeCollection aCollection(
280                     CPPU_TYPE_REF( lang::XTypeProvider ),
281                         CPPU_TYPE_REF( lang::XServiceInfo ),
282                         CPPU_TYPE_REF( lang::XComponent ),
283                         CPPU_TYPE_REF( ucb::XContent ),
284                         CPPU_TYPE_REF( ucb::XCommandProcessor ),
285                         CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
286                         CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
287                         CPPU_TYPE_REF( beans::XPropertyContainer ),
288                         CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
289                         CPPU_TYPE_REF( container::XChild ),
290                         CPPU_TYPE_REF( ucb::XContentCreator ) ); // !!
291                 pCollection = &aCollection;
292                 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
293                 pFolderTypes = pCollection;
294             }
295         }
296         else {
297             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
298         }
299     }
300     else
301     {
302         static cppu::OTypeCollection* pDocumentTypes = 0;
303 
304         pCollection = pDocumentTypes;
305         if ( !pCollection )
306         {
307             osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
308 
309             pCollection = pDocumentTypes;
310             if ( !pCollection )
311             {
312                 static cppu::OTypeCollection aCollection(
313                         CPPU_TYPE_REF( lang::XTypeProvider ),
314                         CPPU_TYPE_REF( lang::XServiceInfo ),
315                         CPPU_TYPE_REF( lang::XComponent ),
316                         CPPU_TYPE_REF( ucb::XContent ),
317                         CPPU_TYPE_REF( ucb::XCommandProcessor ),
318                         CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ),
319                         CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ),
320                         CPPU_TYPE_REF( beans::XPropertyContainer ),
321                         CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ),
322                         CPPU_TYPE_REF( container::XChild ) );
323                 pCollection = &aCollection;
324                 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
325                 pDocumentTypes = pCollection;
326             }
327         }
328         else {
329             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
330         }
331     }
332 
333     return (*pCollection).getTypes();
334 }
335 
336 //=========================================================================
337 //
338 // XServiceInfo methods.
339 //
340 //=========================================================================
341 
342 // virtual
343 rtl::OUString SAL_CALL Content::getImplementationName()
344     throw( uno::RuntimeException )
345 {
346     return rtl::OUString::createFromAscii(
347                             "com.sun.star.comp.ucb.WebDAVContent" );
348 }
349 
350 //=========================================================================
351 // virtual
352 uno::Sequence< rtl::OUString > SAL_CALL Content::getSupportedServiceNames()
353     throw( uno::RuntimeException )
354 {
355     uno::Sequence< rtl::OUString > aSNS( 1 );
356     aSNS.getArray()[ 0 ]
357         = rtl::OUString::createFromAscii( WEBDAV_CONTENT_SERVICE_NAME );
358     return aSNS;
359 }
360 
361 //=========================================================================
362 //
363 // XContent methods.
364 //
365 //=========================================================================
366 
367 // virtual
368 rtl::OUString SAL_CALL Content::getContentType()
369     throw( uno::RuntimeException )
370 {
371     sal_Bool bFolder = sal_False;
372     try
373     {
374         bFolder
375             = isFolder( uno::Reference< ucb::XCommandEnvironment >() );
376     }
377     catch ( uno::RuntimeException const & )
378     {
379         throw;
380     }
381     catch ( uno::Exception const & )
382     {
383     }
384 
385     if ( bFolder )
386         return rtl::OUString::createFromAscii( WEBDAV_COLLECTION_TYPE );
387 
388     return rtl::OUString::createFromAscii( WEBDAV_CONTENT_TYPE );
389 }
390 
391 //=========================================================================
392 //
393 // XCommandProcessor methods.
394 //
395 //=========================================================================
396 
397 // virtual
398 uno::Any SAL_CALL Content::execute(
399         const ucb::Command& aCommand,
400         sal_Int32 /*CommandId*/,
401         const uno::Reference< ucb::XCommandEnvironment >& Environment )
402     throw( uno::Exception,
403            ucb::CommandAbortedException,
404            uno::RuntimeException )
405 {
406     OSL_TRACE( ">>>>> Content::execute: start: command: %s, env: %s",
407                rtl::OUStringToOString( aCommand.Name,
408                                        RTL_TEXTENCODING_UTF8 ).getStr(),
409                Environment.is() ? "present" : "missing" );
410 
411     uno::Any aRet;
412 
413     if ( aCommand.Name.equalsAsciiL(
414              RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ) )
415     {
416         //////////////////////////////////////////////////////////////////
417         // getPropertyValues
418         //////////////////////////////////////////////////////////////////
419 
420         uno::Sequence< beans::Property > Properties;
421         if ( !( aCommand.Argument >>= Properties ) )
422         {
423             ucbhelper::cancelCommandExecution(
424                 uno::makeAny( lang::IllegalArgumentException(
425                                     rtl::OUString::createFromAscii(
426                                         "Wrong argument type!" ),
427                                     static_cast< cppu::OWeakObject * >( this ),
428                                     -1 ) ),
429                 Environment );
430             // Unreachable
431         }
432 
433         aRet <<= getPropertyValues( Properties, Environment );
434     }
435     else if ( aCommand.Name.equalsAsciiL(
436                   RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ) )
437     {
438         //////////////////////////////////////////////////////////////////
439         // setPropertyValues
440         //////////////////////////////////////////////////////////////////
441 
442         uno::Sequence< beans::PropertyValue > aProperties;
443         if ( !( aCommand.Argument >>= aProperties ) )
444         {
445             ucbhelper::cancelCommandExecution(
446                 uno::makeAny( lang::IllegalArgumentException(
447                                     rtl::OUString::createFromAscii(
448                                         "Wrong argument type!" ),
449                                     static_cast< cppu::OWeakObject * >( this ),
450                                     -1 ) ),
451                 Environment );
452             // Unreachable
453         }
454 
455         if ( !aProperties.getLength() )
456         {
457             ucbhelper::cancelCommandExecution(
458                 uno::makeAny( lang::IllegalArgumentException(
459                                     rtl::OUString::createFromAscii(
460                                         "No properties!" ),
461                                     static_cast< cppu::OWeakObject * >( this ),
462                                     -1 ) ),
463                 Environment );
464             // Unreachable
465         }
466 
467         aRet <<= setPropertyValues( aProperties, Environment );
468     }
469     else if ( aCommand.Name.equalsAsciiL(
470                   RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ) )
471     {
472         //////////////////////////////////////////////////////////////////
473         // getPropertySetInfo
474         //////////////////////////////////////////////////////////////////
475 
476         // Note: Implemented by base class.
477         aRet <<= getPropertySetInfo( Environment,
478                                      sal_False /* don't cache data */ );
479     }
480     else if ( aCommand.Name.equalsAsciiL(
481                   RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ) )
482     {
483         //////////////////////////////////////////////////////////////////
484         // getCommandInfo
485         //////////////////////////////////////////////////////////////////
486 
487         // Note: Implemented by base class.
488         aRet <<= getCommandInfo( Environment, sal_False );
489     }
490     else if ( aCommand.Name.equalsAsciiL(
491                   RTL_CONSTASCII_STRINGPARAM( "open" ) ) )
492     {
493         //////////////////////////////////////////////////////////////////
494         // open
495         //////////////////////////////////////////////////////////////////
496 
497         ucb::OpenCommandArgument2 aOpenCommand;
498         if ( !( aCommand.Argument >>= aOpenCommand ) )
499         {
500             ucbhelper::cancelCommandExecution(
501                 uno::makeAny( lang::IllegalArgumentException(
502                                     rtl::OUString::createFromAscii(
503                                         "Wrong argument type!" ),
504                                     static_cast< cppu::OWeakObject * >( this ),
505                                     -1 ) ),
506                 Environment );
507             // Unreachable
508         }
509 
510         aRet = open( aOpenCommand, Environment );
511     }
512     else if ( aCommand.Name.equalsAsciiL(
513                   RTL_CONSTASCII_STRINGPARAM( "insert" ) ) )
514     {
515         //////////////////////////////////////////////////////////////////
516         // insert
517         //////////////////////////////////////////////////////////////////
518 
519         ucb::InsertCommandArgument arg;
520         if ( !( aCommand.Argument >>= arg ) )
521         {
522             ucbhelper::cancelCommandExecution(
523                 uno::makeAny( lang::IllegalArgumentException(
524                                     rtl::OUString::createFromAscii(
525                                         "Wrong argument type!" ),
526                                     static_cast< cppu::OWeakObject * >( this ),
527                                     -1 ) ),
528                 Environment );
529             // Unreachable
530         }
531 
532         insert( arg.Data, arg.ReplaceExisting, Environment );
533     }
534     else if ( aCommand.Name.equalsAsciiL(
535                   RTL_CONSTASCII_STRINGPARAM( "delete" ) ) )
536     {
537         //////////////////////////////////////////////////////////////////
538         // delete
539         //////////////////////////////////////////////////////////////////
540 
541         sal_Bool bDeletePhysical = sal_False;
542         aCommand.Argument >>= bDeletePhysical;
543 
544 //  KSO: Ignore parameter and destroy the content, if you don't support
545 //       putting objects into trashcan. ( Since we do not have a trash can
546 //       service yet (src603), you actually have no other choice. )
547 //      if ( bDeletePhysical )
548 //  {
549         try
550         {
551             std::auto_ptr< DAVResourceAccess > xResAccess;
552             {
553                 osl::Guard< osl::Mutex > aGuard( m_aMutex );
554                 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
555             }
556             xResAccess->DESTROY( Environment );
557             {
558                 osl::Guard< osl::Mutex > aGuard( m_aMutex );
559                 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
560             }
561         }
562         catch ( DAVException const & e )
563         {
564             cancelCommandExecution( e, Environment, sal_True );
565             // Unreachable
566         }
567 //      }
568 
569         // Propagate destruction.
570         destroy( bDeletePhysical );
571 
572         // Remove own and all children's Additional Core Properties.
573         removeAdditionalPropertySet( sal_True );
574     }
575     else if ( aCommand.Name.equalsAsciiL(
576                   RTL_CONSTASCII_STRINGPARAM( "transfer" ) )
577               && isFolder( Environment ) )
578     {
579         //////////////////////////////////////////////////////////////////
580         // transfer
581         //  ( Not available at documents )
582         //////////////////////////////////////////////////////////////////
583 
584         ucb::TransferInfo transferArgs;
585         if ( !( aCommand.Argument >>= transferArgs ) )
586         {
587             ucbhelper::cancelCommandExecution(
588                 uno::makeAny( lang::IllegalArgumentException(
589                                   rtl::OUString::createFromAscii(
590                                       "Wrong argument type!" ),
591                                   static_cast< cppu::OWeakObject * >( this ),
592                                   -1 ) ),
593                 Environment );
594             // Unreachable
595         }
596 
597         transfer( transferArgs, Environment );
598     }
599     else if ( aCommand.Name.equalsAsciiL(
600                   RTL_CONSTASCII_STRINGPARAM( "post" ) ) )
601     {
602         //////////////////////////////////////////////////////////////////
603         // post
604         //////////////////////////////////////////////////////////////////
605 
606         ucb::PostCommandArgument2 aArg;
607         if ( !( aCommand.Argument >>= aArg ) )
608         {
609             ucbhelper::cancelCommandExecution(
610                 uno::makeAny( lang::IllegalArgumentException(
611                                     rtl::OUString::createFromAscii(
612                                         "Wrong argument type!" ),
613                                     static_cast< cppu::OWeakObject * >( this ),
614                                     -1 ) ),
615                 Environment );
616             // Unreachable
617         }
618 
619         post( aArg, Environment );
620     }
621     else if ( aCommand.Name.equalsAsciiL(
622                   RTL_CONSTASCII_STRINGPARAM( "lock" ) ) &&
623               supportsExclusiveWriteLock( Environment ) )
624     {
625         //////////////////////////////////////////////////////////////////
626         // lock
627         //////////////////////////////////////////////////////////////////
628 
629         lock( Environment );
630     }
631     else if ( aCommand.Name.equalsAsciiL(
632                   RTL_CONSTASCII_STRINGPARAM( "unlock" ) ) &&
633               supportsExclusiveWriteLock( Environment ) )
634     {
635         //////////////////////////////////////////////////////////////////
636         // unlock
637         //////////////////////////////////////////////////////////////////
638 
639         unlock( Environment );
640     }
641     else if ( aCommand.Name.equalsAsciiL(
642                   RTL_CONSTASCII_STRINGPARAM( "createNewContent" ) ) &&
643               isFolder( Environment ) )
644     {
645         //////////////////////////////////////////////////////////////////
646         // createNewContent
647         //////////////////////////////////////////////////////////////////
648 
649         ucb::ContentInfo aArg;
650         if ( !( aCommand.Argument >>= aArg ) )
651         {
652             ucbhelper::cancelCommandExecution(
653                 uno::makeAny( lang::IllegalArgumentException(
654                                     rtl::OUString::createFromAscii(
655                                         "Wrong argument type!" ),
656                                     static_cast< cppu::OWeakObject * >( this ),
657                                     -1 ) ),
658                 Environment );
659             // Unreachable
660         }
661 
662         aRet = uno::makeAny( createNewContent( aArg ) );
663     }
664     else
665     {
666         //////////////////////////////////////////////////////////////////
667         // Unsupported command
668         //////////////////////////////////////////////////////////////////
669 
670         ucbhelper::cancelCommandExecution(
671             uno::makeAny( ucb::UnsupportedCommandException(
672                               aCommand.Name,
673                               static_cast< cppu::OWeakObject * >( this ) ) ),
674             Environment );
675         // Unreachable
676     }
677 
678     OSL_TRACE( "<<<<< Content::execute: end: command: %s",
679                rtl::OUStringToOString( aCommand.Name,
680                                        RTL_TEXTENCODING_UTF8 ).getStr() );
681 
682     return aRet;
683 }
684 
685 //=========================================================================
686 // virtual
687 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
688     throw( uno::RuntimeException )
689 {
690     try
691     {
692         std::auto_ptr< DAVResourceAccess > xResAccess;
693         {
694             osl::MutexGuard aGuard( m_aMutex );
695             xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
696         }
697         xResAccess->abort();
698         {
699             osl::Guard< osl::Mutex > aGuard( m_aMutex );
700             m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
701         }
702     }
703     catch ( DAVException const & )
704     {
705         // abort failed!
706     }
707 }
708 
709 //=========================================================================
710 //
711 // XPropertyContainer methods.
712 //
713 //=========================================================================
714 
715 // virtual
716 void SAL_CALL Content::addProperty( const rtl::OUString& Name,
717                                     sal_Int16 Attributes,
718                                     const uno::Any& DefaultValue )
719     throw( beans::PropertyExistException,
720            beans::IllegalTypeException,
721            lang::IllegalArgumentException,
722            uno::RuntimeException )
723 {
724 //    if ( m_bTransient )
725 //   @@@ ???
726 
727     if ( !Name.getLength() )
728         throw lang::IllegalArgumentException();
729 
730     // Check property type.
731     if ( !UCBDeadPropertyValue::supportsType( DefaultValue.getValueType() ) )
732     {
733         OSL_ENSURE( sal_False,
734                     "Content::addProperty - Unsupported property type!" );
735         throw beans::IllegalTypeException();
736     }
737 
738     //////////////////////////////////////////////////////////////////////
739     // Make sure a property with the requested name does not already
740     // exist in dynamic and static(!) properties.
741     //////////////////////////////////////////////////////////////////////
742 
743     // @@@ Need real command environment here, but where to get it from?
744     //     XPropertyContainer interface should be replaced by
745     //     XCommandProcessor commands!
746     uno::Reference< ucb::XCommandEnvironment > xEnv;
747 
748     // Note: This requires network access!
749     if ( getPropertySetInfo( xEnv, sal_False /* don't cache data */ )
750              ->hasPropertyByName( Name ) )
751     {
752         // Property does already exist.
753         throw beans::PropertyExistException();
754     }
755 
756     //////////////////////////////////////////////////////////////////////
757     // Add a new dynamic property.
758     //////////////////////////////////////////////////////////////////////
759 
760     ProppatchValue aValue( PROPSET, Name, DefaultValue );
761 
762     std::vector< ProppatchValue > aProppatchValues;
763     aProppatchValues.push_back( aValue );
764 
765     try
766     {
767         // Set property value at server.
768         std::auto_ptr< DAVResourceAccess > xResAccess;
769         {
770             osl::Guard< osl::Mutex > aGuard( m_aMutex );
771             xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
772         }
773         xResAccess->PROPPATCH( aProppatchValues, xEnv );
774         {
775             osl::Guard< osl::Mutex > aGuard( m_aMutex );
776             m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
777         }
778 
779         // Notify propertyset info change listeners.
780         beans::PropertySetInfoChangeEvent evt(
781             static_cast< cppu::OWeakObject * >( this ),
782             Name,
783             -1, // No handle available
784             beans::PropertySetInfoChange::PROPERTY_INSERTED );
785         notifyPropertySetInfoChange( evt );
786     }
787     catch ( DAVException const & e )
788     {
789         if ( e.getStatus() == SC_FORBIDDEN )
790         {
791             // Support for setting arbitrary dead properties is optional!
792 
793             // Store property locally.
794             ContentImplHelper::addProperty(
795                 Name, Attributes, DefaultValue );
796         }
797         else
798         {
799             if ( shouldAccessNetworkAfterException( e ) )
800             {
801                 try
802                 {
803                     const ResourceType & rType = getResourceType( xEnv );
804                     switch ( rType )
805                     {
806                     case UNKNOWN:
807                     case DAV:
808                         throw lang::IllegalArgumentException();
809 
810                     case FTP:
811                     case NON_DAV:
812                         // Store property locally.
813                         ContentImplHelper::addProperty( Name,
814                                                         Attributes,
815                                                         DefaultValue );
816                         break;
817 
818                     default:
819                         OSL_ENSURE( sal_False,
820                                     "Content::addProperty - "
821                                     "Unsupported resource type!" );
822                         break;
823                     }
824                 }
825                 catch ( uno::Exception const & )
826                 {
827                     OSL_ENSURE( sal_False,
828                                 "Content::addProperty - "
829                                 "Unable to determine resource type!" );
830                 }
831             }
832             else
833             {
834                 OSL_ENSURE( sal_False,
835                             "Content::addProperty - "
836                             "Unable to determine resource type!" );
837             }
838         }
839     }
840 }
841 
842 //=========================================================================
843 // virtual
844 void SAL_CALL Content::removeProperty( const rtl::OUString& Name )
845     throw( beans::UnknownPropertyException,
846            beans::NotRemoveableException,
847            uno::RuntimeException )
848 {
849     // @@@ Need real command environment here, but where to get it from?
850     //     XPropertyContainer interface should be replaced by
851     //     XCommandProcessor commands!
852     uno::Reference< ucb::XCommandEnvironment > xEnv;
853 
854 #if 0
855     // @@@ REMOVEABLE z.Z. nicht richtig an der PropSetInfo gesetzt!!!
856     try
857     {
858         beans::Property aProp
859             = getPropertySetInfo( xEnv, sal_False /* don't cache data */ )
860                 ->getPropertyByName( Name );
861 
862         if ( !( aProp.Attributes & beans::PropertyAttribute::REMOVEABLE ) )
863         {
864             // Not removeable!
865             throw beans::NotRemoveableException();
866         }
867     }
868     catch ( beans::UnknownPropertyException const & )
869     {
870         //OSL_ENSURE( sal_False, "removeProperty - Unknown property!" );
871         throw;
872     }
873 #endif
874 
875     //////////////////////////////////////////////////////////////////////
876     // Try to remove property from server.
877     //////////////////////////////////////////////////////////////////////
878 
879     try
880     {
881         std::vector< ProppatchValue > aProppatchValues;
882         ProppatchValue aValue( PROPREMOVE, Name, uno::Any() );
883         aProppatchValues.push_back( aValue );
884 
885         // Remove property value from server.
886         std::auto_ptr< DAVResourceAccess > xResAccess;
887         {
888             osl::Guard< osl::Mutex > aGuard( m_aMutex );
889             xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
890         }
891         xResAccess->PROPPATCH( aProppatchValues, xEnv );
892         {
893             osl::Guard< osl::Mutex > aGuard( m_aMutex );
894             m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
895         }
896 
897         // Notify propertyset info change listeners.
898         beans::PropertySetInfoChangeEvent evt(
899             static_cast< cppu::OWeakObject * >( this ),
900             Name,
901             -1, // No handle available
902             beans::PropertySetInfoChange::PROPERTY_REMOVED );
903         notifyPropertySetInfoChange( evt );
904     }
905     catch ( DAVException const & e )
906     {
907         if ( e.getStatus() == SC_FORBIDDEN )
908         {
909             // Support for setting arbitrary dead properties is optional!
910 
911             // Try to remove property from local store.
912             ContentImplHelper::removeProperty( Name );
913         }
914         else
915         {
916             if ( shouldAccessNetworkAfterException( e ) )
917             {
918                 try
919                 {
920                     const ResourceType & rType = getResourceType( xEnv );
921                     switch ( rType )
922                     {
923                         case UNKNOWN:
924                         case DAV:
925                             throw beans::UnknownPropertyException();
926 
927                         case FTP:
928                         case NON_DAV:
929                             // Try to remove property from local store.
930                             ContentImplHelper::removeProperty( Name );
931                             break;
932 
933                         default:
934                             OSL_ENSURE( sal_False,
935                                         "Content::removeProperty - "
936                                         "Unsupported resource type!" );
937                             break;
938                     }
939                 }
940                 catch ( uno::Exception const & )
941                 {
942                     OSL_ENSURE( sal_False,
943                                 "Content::removeProperty - "
944                                 "Unable to determine resource type!" );
945                 }
946             }
947             else
948             {
949                 OSL_ENSURE( sal_False,
950                             "Content::removeProperty - "
951                             "Unable to determine resource type!" );
952 //                throw beans::UnknownPropertyException();
953             }
954         }
955     }
956 }
957 
958 //=========================================================================
959 //
960 // XContentCreator methods.
961 //
962 //=========================================================================
963 
964 // virtual
965 uno::Sequence< ucb::ContentInfo > SAL_CALL
966 Content::queryCreatableContentsInfo()
967     throw( uno::RuntimeException )
968 {
969     osl::Guard< osl::Mutex > aGuard( m_aMutex );
970 
971     uno::Sequence< ucb::ContentInfo > aSeq( 2 );
972 
973     // document.
974     aSeq.getArray()[ 0 ].Type
975         = rtl::OUString::createFromAscii( WEBDAV_CONTENT_TYPE );
976     aSeq.getArray()[ 0 ].Attributes
977         = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
978           | ucb::ContentInfoAttribute::KIND_DOCUMENT;
979 
980     beans::Property aProp;
981     m_pProvider->getProperty(
982         rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ), aProp );
983 
984     uno::Sequence< beans::Property > aDocProps( 1 );
985     aDocProps.getArray()[ 0 ] = aProp;
986     aSeq.getArray()[ 0 ].Properties = aDocProps;
987 
988     // folder.
989     aSeq.getArray()[ 1 ].Type
990         = rtl::OUString::createFromAscii( WEBDAV_COLLECTION_TYPE );
991     aSeq.getArray()[ 1 ].Attributes
992         = ucb::ContentInfoAttribute::KIND_FOLDER;
993 
994     uno::Sequence< beans::Property > aFolderProps( 1 );
995     aFolderProps.getArray()[ 0 ] = aProp;
996     aSeq.getArray()[ 1 ].Properties = aFolderProps;
997     return aSeq;
998 }
999 
1000 //=========================================================================
1001 // virtual
1002 uno::Reference< ucb::XContent > SAL_CALL
1003 Content::createNewContent( const ucb::ContentInfo& Info )
1004     throw( uno::RuntimeException )
1005 {
1006     osl::Guard< osl::Mutex > aGuard( m_aMutex );
1007 
1008     if ( !Info.Type.getLength() )
1009         return uno::Reference< ucb::XContent >();
1010 
1011     if ( ( !Info.Type.equalsAsciiL(
1012                RTL_CONSTASCII_STRINGPARAM( WEBDAV_COLLECTION_TYPE ) ) )
1013          &&
1014          ( !Info.Type.equalsAsciiL(
1015              RTL_CONSTASCII_STRINGPARAM( WEBDAV_CONTENT_TYPE ) ) ) )
1016         return uno::Reference< ucb::XContent >();
1017 
1018     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
1019 
1020     OSL_ENSURE( aURL.getLength() > 0,
1021                 "WebdavContent::createNewContent - empty identifier!" );
1022 
1023     if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
1024         aURL += rtl::OUString::createFromAscii( "/" );
1025 
1026     sal_Bool isCollection;
1027     if ( Info.Type.equalsAsciiL(
1028              RTL_CONSTASCII_STRINGPARAM( WEBDAV_COLLECTION_TYPE ) ) )
1029     {
1030         aURL += rtl::OUString::createFromAscii( "New_Collection" );
1031         isCollection = sal_True;
1032     }
1033     else
1034     {
1035         aURL += rtl::OUString::createFromAscii( "New_Content" );
1036         isCollection = sal_False;
1037     }
1038 
1039     uno::Reference< ucb::XContentIdentifier > xId(
1040                     new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ) );
1041 
1042     // create the local content
1043     try
1044     {
1045         return new ::webdav_ucp::Content( m_xSMgr,
1046                                           m_pProvider,
1047                                           xId,
1048                                           m_xResAccess->getSessionFactory(),
1049                                           isCollection );
1050     }
1051     catch ( ucb::ContentCreationException & )
1052     {
1053         return uno::Reference< ucb::XContent >();
1054     }
1055 }
1056 
1057 //=========================================================================
1058 // virtual
1059 rtl::OUString Content::getParentURL()
1060 {
1061     // <scheme>://              -> ""
1062     // <scheme>://foo           -> ""
1063     // <scheme>://foo/          -> ""
1064     // <scheme>://foo/bar       -> <scheme>://foo/
1065     // <scheme>://foo/bar/      -> <scheme>://foo/
1066     // <scheme>://foo/bar/abc   -> <scheme>://foo/bar/
1067 
1068     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
1069 
1070     sal_Int32 nPos = aURL.lastIndexOf( '/' );
1071     if ( nPos == ( aURL.getLength() - 1 ) )
1072     {
1073         // Trailing slash found. Skip.
1074         nPos = aURL.lastIndexOf( '/', nPos );
1075     }
1076 
1077     sal_Int32 nPos1 = aURL.lastIndexOf( '/', nPos );
1078     if ( nPos1 != -1 )
1079         nPos1 = aURL.lastIndexOf( '/', nPos1 );
1080 
1081     if ( nPos1 == -1 )
1082         return rtl::OUString();
1083 
1084     return rtl::OUString( aURL.copy( 0, nPos + 1 ) );
1085 }
1086 
1087 //=========================================================================
1088 //
1089 // Non-interface methods.
1090 //
1091 //=========================================================================
1092 
1093 // static
1094 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1095     const uno::Reference< lang::XMultiServiceFactory >& rSMgr,
1096     const uno::Sequence< beans::Property >& rProperties,
1097     const ContentProperties& rData,
1098     const rtl::Reference< ::ucbhelper::ContentProviderImplHelper >& rProvider,
1099     const rtl::OUString& rContentId )
1100 {
1101     // Note: Empty sequence means "get values of all supported properties".
1102 
1103     rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
1104         = new ::ucbhelper::PropertyValueSet( rSMgr );
1105 
1106     sal_Int32 nCount = rProperties.getLength();
1107     if ( nCount )
1108     {
1109         uno::Reference< beans::XPropertySet > xAdditionalPropSet;
1110         sal_Bool bTriedToGetAdditonalPropSet = sal_False;
1111 
1112         const beans::Property* pProps = rProperties.getConstArray();
1113         for ( sal_Int32 n = 0; n < nCount; ++n )
1114         {
1115             const beans::Property& rProp = pProps[ n ];
1116 
1117             // Process standard UCB, DAV and HTTP properties.
1118             const uno::Any & rValue = rData.getValue( rProp.Name );
1119             if ( rValue.hasValue() )
1120             {
1121                 xRow->appendObject( rProp, rValue );
1122             }
1123             else
1124             {
1125                 // Process local Additional Properties.
1126                 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
1127                 {
1128                     xAdditionalPropSet
1129                         = uno::Reference< beans::XPropertySet >(
1130                             rProvider->getAdditionalPropertySet( rContentId,
1131                                                                  sal_False ),
1132                             uno::UNO_QUERY );
1133                     bTriedToGetAdditonalPropSet = sal_True;
1134                 }
1135 
1136                 if ( !xAdditionalPropSet.is() ||
1137                      !xRow->appendPropertySetValue(
1138                                             xAdditionalPropSet, rProp ) )
1139                 {
1140                     // Append empty entry.
1141                     xRow->appendVoid( rProp );
1142                 }
1143             }
1144         }
1145     }
1146     else
1147     {
1148         // Append all standard UCB, DAV and HTTP properties.
1149 
1150         const std::auto_ptr< PropertyValueMap > & xProps = rData.getProperties();
1151 
1152         PropertyValueMap::const_iterator it  = xProps->begin();
1153         PropertyValueMap::const_iterator end = xProps->end();
1154 
1155         ContentProvider * pProvider
1156             = static_cast< ContentProvider * >( rProvider.get() );
1157         beans::Property aProp;
1158 
1159         while ( it != end )
1160         {
1161             if ( pProvider->getProperty( (*it).first, aProp ) )
1162                 xRow->appendObject( aProp, (*it).second.value() );
1163 
1164             ++it;
1165         }
1166 
1167         // Append all local Additional Properties.
1168         uno::Reference< beans::XPropertySet > xSet(
1169             rProvider->getAdditionalPropertySet( rContentId, sal_False ),
1170             uno::UNO_QUERY );
1171         xRow->appendPropertySet( xSet );
1172     }
1173 
1174     return uno::Reference< sdbc::XRow >( xRow.get() );
1175 }
1176 
1177 //=========================================================================
1178 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1179                 const uno::Sequence< beans::Property >& rProperties,
1180                 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1181     throw ( uno::Exception )
1182 {
1183     std::auto_ptr< ContentProperties > xProps;
1184     std::auto_ptr< ContentProperties > xCachedProps;
1185     std::auto_ptr< DAVResourceAccess > xResAccess;
1186     rtl::OUString aUnescapedTitle;
1187     bool bHasAll = false;
1188     uno::Reference< lang::XMultiServiceFactory > xSMgr;
1189     uno::Reference< ucb::XContentIdentifier > xIdentifier;
1190     rtl::Reference< ::ucbhelper::ContentProviderImplHelper > xProvider;
1191 
1192     {
1193         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1194 
1195         aUnescapedTitle = NeonUri::unescape( m_aEscapedTitle );
1196         xSMgr.set( m_xSMgr );
1197         xIdentifier.set( m_xIdentifier );
1198         xProvider.set( m_xProvider.get() );
1199         xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
1200 
1201         // First, ask cache...
1202         if ( m_xCachedProps.get() )
1203         {
1204             xCachedProps.reset( new ContentProperties( *m_xCachedProps.get() ) );
1205 
1206             std::vector< rtl::OUString > aMissingProps;
1207             if ( xCachedProps->containsAllNames( rProperties, aMissingProps ) )
1208             {
1209                 // All properties are already in cache! No server access needed.
1210                 bHasAll = true;
1211             }
1212 
1213             // use the cached ContentProperties instance
1214             xProps.reset( new ContentProperties( *xCachedProps.get() ) );
1215         }
1216     }
1217 
1218     if ( !m_bTransient && !bHasAll )
1219     {
1220         /////////////////////////////////////////////////////////////////////
1221         // Obtain values from server...
1222         /////////////////////////////////////////////////////////////////////
1223 
1224         // First, identify whether resource is DAV or not
1225         const ResourceType & rType = getResourceType( xEnv, xResAccess );
1226 
1227         bool bNetworkAccessAllowed = true;
1228 
1229         if ( DAV == rType )
1230         {
1231             // cache lookup... getResourceType may fill the props cache via
1232             // PROPFIND!
1233             if ( m_xCachedProps.get() )
1234             {
1235                 xCachedProps.reset(
1236                     new ContentProperties( *m_xCachedProps.get() ) );
1237 
1238                 std::vector< rtl::OUString > aMissingProps;
1239                 if ( xCachedProps->containsAllNames(
1240                          rProperties, aMissingProps ) )
1241                 {
1242                     // All properties are already in cache! No server access
1243                     // needed.
1244                     bHasAll = true;
1245                 }
1246 
1247                 // use the cached ContentProperties instance
1248                 xProps.reset( new ContentProperties( *xCachedProps.get() ) );
1249             }
1250 
1251             if ( !bHasAll )
1252             {
1253                 // Only DAV resources support PROPFIND
1254                 std::vector< rtl::OUString > aPropNames;
1255 
1256                 uno::Sequence< beans::Property > aProperties(
1257                     rProperties.getLength() );
1258 
1259                 if ( m_aFailedPropNames.size() > 0 )
1260                 {
1261                     sal_Int32 nProps = 0;
1262                     sal_Int32 nCount = rProperties.getLength();
1263                     for ( sal_Int32 n = 0; n < nCount; ++n )
1264                     {
1265                         const rtl::OUString & rName = rProperties[ n ].Name;
1266 
1267                         std::vector< rtl::OUString >::const_iterator it
1268                             = m_aFailedPropNames.begin();
1269                         std::vector< rtl::OUString >::const_iterator end
1270                             = m_aFailedPropNames.end();
1271 
1272                         while ( it != end )
1273                         {
1274                             if ( *it == rName )
1275                                 break;
1276 
1277                             ++it;
1278                         }
1279 
1280                         if ( it == end )
1281                         {
1282                             aProperties[ nProps ] = rProperties[ n ];
1283                             nProps++;
1284                         }
1285                     }
1286 
1287                     aProperties.realloc( nProps );
1288                 }
1289                 else
1290                 {
1291                     aProperties = rProperties;
1292                 }
1293 
1294                 if ( aProperties.getLength() > 0 )
1295                     ContentProperties::UCBNamesToDAVNames(
1296                         aProperties, aPropNames );
1297 
1298                 if ( aPropNames.size() > 0 )
1299                 {
1300                     std::vector< DAVResource > resources;
1301                     try
1302                     {
1303                         xResAccess->PROPFIND(
1304                             DAVZERO, aPropNames, resources, xEnv );
1305 
1306                         if ( 1 == resources.size() )
1307                         {
1308                             if ( xProps.get())
1309                                 xProps->addProperties(
1310                                     aPropNames,
1311                                     ContentProperties( resources[ 0 ] ));
1312                             else
1313                                 xProps.reset(
1314                                     new ContentProperties( resources[ 0 ] ) );
1315                         }
1316                     }
1317                     catch ( DAVException const & e )
1318                     {
1319                         bNetworkAccessAllowed
1320                             = shouldAccessNetworkAfterException( e );
1321 
1322                         if ( !bNetworkAccessAllowed )
1323                         {
1324                             cancelCommandExecution( e, xEnv );
1325                             // unreachable
1326                         }
1327                     }
1328                 }
1329             }
1330         }
1331 
1332         if ( bNetworkAccessAllowed )
1333         {
1334             // All properties obtained already?
1335             std::vector< rtl::OUString > aMissingProps;
1336             if ( !( xProps.get()
1337                     && xProps->containsAllNames(
1338                         rProperties, aMissingProps ) )
1339                  && !m_bDidGetOrHead )
1340             {
1341                 // Possibly the missing props can be obtained using a HEAD
1342                 // request.
1343 
1344                 std::vector< rtl::OUString > aHeaderNames;
1345                 ContentProperties::UCBNamesToHTTPNames(
1346                     rProperties,
1347                     aHeaderNames,
1348                     true /* bIncludeUnmatched */ );
1349 
1350                 if ( aHeaderNames.size() > 0 )
1351                 {
1352                     try
1353                     {
1354                         DAVResource resource;
1355                         xResAccess->HEAD( aHeaderNames, resource, xEnv );
1356                         m_bDidGetOrHead = true;
1357 
1358                         if ( xProps.get() )
1359                             xProps->addProperties(
1360                                 aMissingProps,
1361                                 ContentProperties( resource ) );
1362                         else
1363                             xProps.reset ( new ContentProperties( resource ) );
1364 
1365                         if ( m_eResourceType == NON_DAV )
1366                             xProps->addProperties( aMissingProps,
1367                                                    ContentProperties(
1368                                                        aUnescapedTitle,
1369                                                        false ) );
1370                     }
1371                     catch ( DAVException const & e )
1372                     {
1373                         bNetworkAccessAllowed
1374                             = shouldAccessNetworkAfterException( e );
1375 
1376                         if ( !bNetworkAccessAllowed )
1377                         {
1378                             cancelCommandExecution( e, xEnv );
1379                             // unreachable
1380                         }
1381                     }
1382                 }
1383             }
1384         }
1385 
1386         // might trigger HTTP redirect.
1387         // Therefore, title must be updated here.
1388         NeonUri aUri( xResAccess->getURL() );
1389         aUnescapedTitle = aUri.GetPathBaseNameUnescaped();
1390 
1391         if ( rType == UNKNOWN )
1392         {
1393             xProps.reset( new ContentProperties( aUnescapedTitle ) );
1394         }
1395 
1396         // For DAV resources we only know the Title, for non-DAV
1397         // resources we additionally know that it is a document.
1398 
1399         if ( rType == DAV )
1400         {
1401             //xProps.reset(
1402             //    new ContentProperties( aUnescapedTitle ) );
1403             xProps->addProperty(
1404                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ),
1405                 uno::makeAny( aUnescapedTitle ),
1406                 true );
1407         }
1408         else
1409         {
1410             if ( !xProps.get() )
1411                 xProps.reset( new ContentProperties( aUnescapedTitle, false ) );
1412             else
1413                 xProps->addProperty(
1414                     rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ),
1415                     uno::makeAny( aUnescapedTitle ),
1416                     true );
1417 
1418             xProps->addProperty(
1419                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ),
1420                 uno::makeAny( false ),
1421                 true );
1422             xProps->addProperty(
1423                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ),
1424                 uno::makeAny( true ),
1425                 true );
1426         }
1427     }
1428     else
1429     {
1430         // No server access for just created (not yet committed) objects.
1431         // Only a minimal set of properties supported at this stage.
1432         if (m_bTransient)
1433             xProps.reset( new ContentProperties( aUnescapedTitle,
1434                                                  m_bCollection ) );
1435     }
1436 
1437     sal_Int32 nCount = rProperties.getLength();
1438     for ( sal_Int32 n = 0; n < nCount; ++n )
1439     {
1440         const rtl::OUString rName = rProperties[ n ].Name;
1441         if ( rName.equalsAsciiL(
1442                       RTL_CONSTASCII_STRINGPARAM( "BaseURI" ) ) )
1443         {
1444             // Add BaseURI property, if requested.
1445             xProps->addProperty(
1446                  rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseURI" ) ),
1447                  uno::makeAny( getBaseURI( xResAccess ) ),
1448                  true );
1449         }
1450         else if ( rName.equalsAsciiL(
1451                       RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
1452         {
1453             // Add CreatableContentsInfo property, if requested.
1454             sal_Bool bFolder = sal_False;
1455             xProps->getValue(
1456                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ) )
1457                     >>= bFolder;
1458             xProps->addProperty(
1459                 rtl::OUString(
1460                     RTL_CONSTASCII_USTRINGPARAM( "CreatableContentsInfo" ) ),
1461                 uno::makeAny( bFolder
1462                                   ? queryCreatableContentsInfo()
1463                                   : uno::Sequence< ucb::ContentInfo >() ),
1464                 true );
1465         }
1466     }
1467 
1468     uno::Reference< sdbc::XRow > xResultRow
1469         = getPropertyValues( xSMgr,
1470                              rProperties,
1471                              *xProps,
1472                              xProvider,
1473                              xIdentifier->getContentIdentifier() );
1474 
1475     {
1476         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1477 
1478         if ( !m_xCachedProps.get() )
1479             m_xCachedProps.reset( new CachableContentProperties( *xProps.get() ) );
1480         else
1481             m_xCachedProps->addProperties( *xProps.get() );
1482 
1483         m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
1484         m_aEscapedTitle = NeonUri::escapeSegment( aUnescapedTitle );
1485     }
1486 
1487     return xResultRow;
1488 }
1489 
1490 //=========================================================================
1491 uno::Sequence< uno::Any > Content::setPropertyValues(
1492                 const uno::Sequence< beans::PropertyValue >& rValues,
1493                 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1494     throw ( uno::Exception )
1495 {
1496     uno::Reference< lang::XMultiServiceFactory > xSMgr;
1497     uno::Reference< ucb::XContentIdentifier >    xIdentifier;
1498     rtl::Reference< ContentProvider >            xProvider;
1499     sal_Bool bTransient;
1500     std::auto_ptr< DAVResourceAccess > xResAccess;
1501 
1502     {
1503         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1504 
1505         xProvider.set( m_pProvider );
1506         xIdentifier.set( m_xIdentifier );
1507         bTransient = m_bTransient;
1508         xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
1509         xSMgr.set( m_xSMgr );
1510     }
1511 
1512     uno::Sequence< uno::Any > aRet( rValues.getLength() );
1513     uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1514     sal_Int32 nChanged = 0;
1515 
1516     beans::PropertyChangeEvent aEvent;
1517     aEvent.Source         = static_cast< cppu::OWeakObject * >( this );
1518     aEvent.Further        = sal_False;
1519     // aEvent.PropertyName =
1520     aEvent.PropertyHandle = -1;
1521     // aEvent.OldValue   =
1522     // aEvent.NewValue   =
1523 
1524     std::vector< ProppatchValue > aProppatchValues;
1525     std::vector< sal_Int32 > aProppatchPropsPositions;
1526 
1527     uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1528     sal_Bool bTriedToGetAdditonalPropSet = sal_False;
1529 
1530     sal_Bool bExchange = sal_False;
1531     rtl::OUString aNewTitle;
1532     rtl::OUString aOldTitle;
1533     sal_Int32 nTitlePos = -1;
1534 
1535     uno::Reference< beans::XPropertySetInfo > xInfo;
1536 
1537     const beans::PropertyValue* pValues = rValues.getConstArray();
1538     sal_Int32 nCount = rValues.getLength();
1539     for ( sal_Int32 n = 0; n < nCount; ++n )
1540     {
1541         const beans::PropertyValue& rValue = pValues[ n ];
1542         const rtl::OUString & rName = rValue.Name;
1543 
1544         beans::Property aTmpProp;
1545         xProvider->getProperty( rName, aTmpProp );
1546 
1547         if ( aTmpProp.Attributes & beans::PropertyAttribute::READONLY )
1548         {
1549             // Read-only property!
1550             aRet[ n ] <<= lang::IllegalAccessException(
1551                             rtl::OUString::createFromAscii(
1552                                 "Property is read-only!" ),
1553                             static_cast< cppu::OWeakObject * >( this ) );
1554             continue;
1555         }
1556 
1557         //////////////////////////////////////////////////////////////////
1558         // Mandatory props.
1559         //////////////////////////////////////////////////////////////////
1560 
1561         if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) )
1562         {
1563             // Read-only property!
1564             aRet[ n ] <<= lang::IllegalAccessException(
1565                 rtl::OUString::createFromAscii(
1566                     "Property is read-only!" ),
1567                 static_cast< cppu::OWeakObject * >( this ) );
1568         }
1569         else if ( rName.equalsAsciiL(
1570                       RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
1571         {
1572             // Read-only property!
1573             aRet[ n ] <<= lang::IllegalAccessException(
1574                 rtl::OUString::createFromAscii(
1575                     "Property is read-only!" ),
1576                 static_cast< cppu::OWeakObject * >( this ) );
1577         }
1578         else if ( rName.equalsAsciiL(
1579                       RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
1580         {
1581             // Read-only property!
1582             aRet[ n ] <<= lang::IllegalAccessException(
1583                             rtl::OUString::createFromAscii(
1584                                 "Property is read-only!" ),
1585                             static_cast< cppu::OWeakObject * >( this ) );
1586         }
1587         else if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
1588         {
1589             rtl::OUString aNewValue;
1590             if ( rValue.Value >>= aNewValue )
1591             {
1592                 // No empty titles!
1593                 if ( aNewValue.getLength() > 0 )
1594                 {
1595                     try
1596                     {
1597                         NeonUri aURI( xIdentifier->getContentIdentifier() );
1598                         aOldTitle = aURI.GetPathBaseNameUnescaped();
1599 
1600                         if ( aNewValue != aOldTitle )
1601                         {
1602                             // modified title -> modified URL -> exchange !
1603                             if ( !bTransient )
1604                                 bExchange = sal_True;
1605 
1606                             // new value will be set later...
1607                             aNewTitle = aNewValue;
1608 
1609                             // remember position within sequence of values (for
1610                             // error handling).
1611                             nTitlePos = n;
1612                         }
1613                     }
1614                     catch ( DAVException const & )
1615                     {
1616                         aRet[ n ] <<= lang::IllegalArgumentException(
1617                             rtl::OUString::createFromAscii(
1618                                 "Invalid content identifier!" ),
1619                             static_cast< cppu::OWeakObject * >( this ),
1620                             -1 );
1621                     }
1622                 }
1623                 else
1624                 {
1625                     aRet[ n ] <<= lang::IllegalArgumentException(
1626                         rtl::OUString::createFromAscii(
1627                             "Empty title not allowed!" ),
1628                         static_cast< cppu::OWeakObject * >( this ),
1629                         -1 );
1630                 }
1631             }
1632             else
1633             {
1634                 aRet[ n ] <<= beans::IllegalTypeException(
1635                     rtl::OUString::createFromAscii(
1636                         "Property value has wrong type!" ),
1637                     static_cast< cppu::OWeakObject * >( this ) );
1638             }
1639         }
1640         else
1641         {
1642             //////////////////////////////////////////////////////////////
1643             // Optional props.
1644             //////////////////////////////////////////////////////////////
1645 
1646             if ( !xInfo.is() )
1647                 xInfo = getPropertySetInfo( xEnv,
1648                                             sal_False /* don't cache data */ );
1649 
1650             if ( !xInfo->hasPropertyByName( rName ) )
1651             {
1652                 // Check, whether property exists. Skip otherwise.
1653                 // PROPPATCH::set would add the property automatically, which
1654                 // is not allowed for "setPropertyValues" command!
1655                 aRet[ n ] <<= beans::UnknownPropertyException(
1656                                 rtl::OUString::createFromAscii(
1657                                     "Property is unknown!" ),
1658                                 static_cast< cppu::OWeakObject * >( this ) );
1659                 continue;
1660             }
1661 
1662             if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) )
1663             {
1664                 // Read-only property!
1665                 aRet[ n ] <<= lang::IllegalAccessException(
1666                                 rtl::OUString::createFromAscii(
1667                                     "Property is read-only!" ),
1668                                 static_cast< cppu::OWeakObject * >( this ) );
1669             }
1670             else if ( rName.equalsAsciiL(
1671                         RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) )
1672             {
1673                 // Read-only property!
1674                 aRet[ n ] <<= lang::IllegalAccessException(
1675                                 rtl::OUString::createFromAscii(
1676                                     "Property is read-only!" ),
1677                                 static_cast< cppu::OWeakObject * >( this ) );
1678             }
1679             else if ( rName.equalsAsciiL(
1680                         RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) )
1681             {
1682                 // Read-only property!
1683                 aRet[ n ] <<= lang::IllegalAccessException(
1684                                 rtl::OUString::createFromAscii(
1685                                     "Property is read-only!" ),
1686                                 static_cast< cppu::OWeakObject * >( this ) );
1687             }
1688             else if ( rName.equalsAsciiL(
1689                         RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) )
1690             {
1691                 // Read-only property!
1692                 // (but could be writable, if 'getcontenttype' would be)
1693                 aRet[ n ] <<= lang::IllegalAccessException(
1694                                 rtl::OUString::createFromAscii(
1695                                     "Property is read-only!" ),
1696                                 static_cast< cppu::OWeakObject * >( this ) );
1697             }
1698             if ( rName.equalsAsciiL(
1699                      RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
1700             {
1701                 // Read-only property!
1702                 aRet[ n ] <<= lang::IllegalAccessException(
1703                                 rtl::OUString::createFromAscii(
1704                                     "Property is read-only!" ),
1705                                 static_cast< cppu::OWeakObject * >( this ) );
1706             }
1707             else
1708             {
1709                 if ( getResourceType( xEnv, xResAccess ) == DAV )
1710                 {
1711                     // Property value will be set on server.
1712                     ProppatchValue aValue( PROPSET, rName, rValue.Value );
1713                     aProppatchValues.push_back( aValue );
1714 
1715                     // remember position within sequence of values (for
1716                     // error handling).
1717                     aProppatchPropsPositions.push_back( n );
1718                 }
1719                 else
1720                 {
1721                     // Property value will be stored in local property store.
1722                     if ( !bTriedToGetAdditonalPropSet &&
1723                          !xAdditionalPropSet.is() )
1724                     {
1725                         xAdditionalPropSet
1726                             = getAdditionalPropertySet( sal_False );
1727                         bTriedToGetAdditonalPropSet = sal_True;
1728                     }
1729 
1730                     if ( xAdditionalPropSet.is() )
1731                     {
1732                         try
1733                         {
1734                             uno::Any aOldValue
1735                                 = xAdditionalPropSet->getPropertyValue( rName );
1736                             if ( aOldValue != rValue.Value )
1737                             {
1738                                 xAdditionalPropSet->setPropertyValue(
1739                                                         rName, rValue.Value );
1740 
1741                                 aEvent.PropertyName = rName;
1742                                 aEvent.OldValue     = aOldValue;
1743                                 aEvent.NewValue     = rValue.Value;
1744 
1745                                 aChanges.getArray()[ nChanged ] = aEvent;
1746                                 nChanged++;
1747                             }
1748                         }
1749                         catch ( beans::UnknownPropertyException const & e )
1750                         {
1751                             aRet[ n ] <<= e;
1752                         }
1753                         catch ( lang::WrappedTargetException const & e )
1754                         {
1755                             aRet[ n ] <<= e;
1756                         }
1757                         catch ( beans::PropertyVetoException const & e )
1758                         {
1759                             aRet[ n ] <<= e;
1760                         }
1761                         catch ( lang::IllegalArgumentException const & e )
1762                         {
1763                             aRet[ n ] <<= e;
1764                         }
1765                     }
1766                     else
1767                     {
1768                         aRet[ n ] <<= uno::Exception(
1769                                 rtl::OUString::createFromAscii(
1770                                     "No property set for storing the value!" ),
1771                                 static_cast< cppu::OWeakObject * >( this ) );
1772                     }
1773                 }
1774             }
1775         }
1776     } // for
1777 
1778     if ( !bTransient && aProppatchValues.size() )
1779     {
1780         try
1781         {
1782             // Set property values at server.
1783             xResAccess->PROPPATCH( aProppatchValues, xEnv );
1784 
1785             std::vector< ProppatchValue >::const_iterator it
1786                 = aProppatchValues.begin();
1787             std::vector< ProppatchValue >::const_iterator end
1788                 = aProppatchValues.end();
1789 
1790             while ( it != end )
1791             {
1792                 aEvent.PropertyName = (*it).name;
1793                 aEvent.OldValue     = uno::Any(); // @@@ to expensive to obtain!
1794                 aEvent.NewValue     = (*it).value;
1795 
1796                 aChanges.getArray()[ nChanged ] = aEvent;
1797                 nChanged++;
1798 
1799                 ++it;
1800             }
1801         }
1802         catch ( DAVException const & e )
1803         {
1804 //            OSL_ENSURE( sal_False,
1805 //                        "Content::setPropertyValues - PROPPATCH failed!" );
1806 
1807 #if 1
1808             cancelCommandExecution( e, xEnv );
1809             // unreachable
1810 #else
1811             // Note: PROPPATCH either sets ALL property values OR NOTHING.
1812 
1813             std::vector< sal_Int32 >::const_iterator it
1814                 = aProppatchPropsPositions.begin();
1815             std::vector< sal_Int32 >::const_iterator end
1816                 = aProppatchPropsPositions.end();
1817 
1818             while ( it != end )
1819             {
1820                 // Set error.
1821                 aRet[ (*it) ] <<= MapDAVException( e, sal_True );
1822                 ++it;
1823             }
1824 #endif
1825         }
1826     }
1827 
1828     if ( bExchange )
1829     {
1830         // Assemble new content identifier...
1831 
1832         rtl::OUString aNewURL = getParentURL();
1833         if ( aNewURL.lastIndexOf( '/' ) != ( aNewURL.getLength() - 1 ) )
1834             aNewURL += rtl::OUString::createFromAscii( "/" );
1835 
1836         aNewURL += NeonUri::escapeSegment( aNewTitle );
1837 
1838         uno::Reference< ucb::XContentIdentifier > xNewId
1839             = new ::ucbhelper::ContentIdentifier( xSMgr, aNewURL );
1840         uno::Reference< ucb::XContentIdentifier > xOldId = xIdentifier;
1841 
1842         try
1843         {
1844             NeonUri sourceURI( xOldId->getContentIdentifier() );
1845             NeonUri targetURI( xNewId->getContentIdentifier() );
1846             targetURI.SetScheme( sourceURI.GetScheme() );
1847 
1848             xResAccess->MOVE(
1849                 sourceURI.GetPath(), targetURI.GetURI(), sal_False, xEnv );
1850             // @@@ Should check for resources that could not be moved
1851             //     (due to source access or target overwrite) and send
1852             //     this information through the interaction handler.
1853 
1854             // @@@ Existing content should be checked to see if it needs
1855             //     to be deleted at the source
1856 
1857             // @@@ Existing content should be checked to see if it has
1858             //     been overwritten at the target
1859 
1860             if ( exchangeIdentity( xNewId ) )
1861             {
1862                 xResAccess->setURL( aNewURL );
1863 
1864 // DAV resources store all additional props on server!
1865 //              // Adapt Additional Core Properties.
1866 //              renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1867 //                                           xNewId->getContentIdentifier(),
1868 //                                           sal_True );
1869             }
1870             else
1871             {
1872                 // Do not set new title!
1873                 aNewTitle = rtl::OUString();
1874 
1875                 // Set error .
1876                 aRet[ nTitlePos ] <<= uno::Exception(
1877                     rtl::OUString::createFromAscii( "Exchange failed!" ),
1878                     static_cast< cppu::OWeakObject * >( this ) );
1879             }
1880         }
1881         catch ( DAVException const & e )
1882         {
1883             // Do not set new title!
1884             aNewTitle = rtl::OUString();
1885 
1886             // Set error .
1887             aRet[ nTitlePos ] <<= MapDAVException( e, sal_True );
1888         }
1889     }
1890 
1891     if ( aNewTitle.getLength() )
1892     {
1893         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1894 
1895         aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" );
1896         aEvent.OldValue     = uno::makeAny( aOldTitle );
1897         aEvent.NewValue     = uno::makeAny( aNewTitle );
1898 
1899         m_aEscapedTitle     = NeonUri::escapeSegment( aNewTitle );
1900 
1901         aChanges.getArray()[ nChanged ] = aEvent;
1902         nChanged++;
1903     }
1904 
1905     if ( nChanged > 0 )
1906     {
1907         aChanges.realloc( nChanged );
1908         notifyPropertiesChange( aChanges );
1909     }
1910 
1911     {
1912         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1913         m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
1914     }
1915 
1916     return aRet;
1917 }
1918 
1919 //=========================================================================
1920 uno::Any Content::open(
1921                 const ucb::OpenCommandArgument2 & rArg,
1922                 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1923     throw( uno::Exception )
1924 {
1925     uno::Any aRet;
1926 
1927     sal_Bool bOpenFolder = ( ( rArg.Mode == ucb::OpenMode::ALL ) ||
1928                              ( rArg.Mode == ucb::OpenMode::FOLDERS ) ||
1929                              ( rArg.Mode == ucb::OpenMode::DOCUMENTS ) );
1930     if ( bOpenFolder )
1931     {
1932         if ( isFolder( xEnv ) )
1933         {
1934             // Open collection.
1935 
1936             uno::Reference< ucb::XDynamicResultSet > xSet
1937                 = new DynamicResultSet( m_xSMgr, this, rArg, xEnv );
1938             aRet <<= xSet;
1939         }
1940         else
1941         {
1942             // Error: Not a folder!
1943 
1944             rtl::OUStringBuffer aMsg;
1945             if ( getResourceType( xEnv ) == FTP )
1946             {
1947                 // #114653#
1948                 aMsg.appendAscii( "FTP over HTTP proxy: resource cannot "
1949                                   "be opened as folder! Wrong Open Mode!" );
1950             }
1951             else
1952             {
1953                 aMsg.appendAscii( "Non-folder resource cannot be "
1954                                   "opened as folder! Wrong Open Mode!" );
1955             }
1956 
1957             ucbhelper::cancelCommandExecution(
1958                 uno::makeAny(
1959                     lang::IllegalArgumentException(
1960                         aMsg.makeStringAndClear(),
1961                         static_cast< cppu::OWeakObject * >( this ),
1962                         -1 ) ),
1963                 xEnv );
1964             // Unreachable
1965         }
1966     }
1967 
1968     if ( rArg.Sink.is() )
1969     {
1970         // Open document.
1971 
1972         if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
1973              ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
1974         {
1975             // Currently(?) unsupported.
1976             ucbhelper::cancelCommandExecution(
1977                 uno::makeAny(
1978                     ucb::UnsupportedOpenModeException(
1979                             rtl::OUString(),
1980                             static_cast< cppu::OWeakObject * >( this ),
1981                             sal_Int16( rArg.Mode ) ) ),
1982                 xEnv );
1983             // Unreachable
1984         }
1985 
1986         rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
1987         uno::Reference< io::XOutputStream > xOut
1988             = uno::Reference< io::XOutputStream >( rArg.Sink, uno::UNO_QUERY );
1989         if ( xOut.is() )
1990         {
1991             // PUSH: write data
1992             try
1993             {
1994                 std::auto_ptr< DAVResourceAccess > xResAccess;
1995 
1996                 {
1997                     osl::MutexGuard aGuard( m_aMutex );
1998 
1999                     xResAccess.reset(
2000                         new DAVResourceAccess( *m_xResAccess.get() ) );
2001                 }
2002 
2003                 DAVResource aResource;
2004                 std::vector< rtl::OUString > aHeaders;
2005 
2006                 xResAccess->GET( xOut, aHeaders, aResource, xEnv );
2007                 m_bDidGetOrHead = true;
2008 
2009                 {
2010                     osl::MutexGuard aGuard( m_aMutex );
2011 
2012                     // cache headers.
2013                     if ( !m_xCachedProps.get())
2014                         m_xCachedProps.reset(
2015                             new CachableContentProperties( aResource ) );
2016                     else
2017                         m_xCachedProps->addProperties( aResource );
2018 
2019                     m_xResAccess.reset(
2020                         new DAVResourceAccess( *xResAccess.get() ) );
2021                 }
2022             }
2023             catch ( DAVException const & e )
2024             {
2025                 cancelCommandExecution( e, xEnv );
2026                 // Unreachable
2027             }
2028         }
2029         else
2030         {
2031             uno::Reference< io::XActiveDataSink > xDataSink
2032                 = uno::Reference< io::XActiveDataSink >( rArg.Sink,
2033                                                          uno::UNO_QUERY );
2034             if ( xDataSink.is() )
2035             {
2036                 // PULL: wait for client read
2037                 try
2038                 {
2039                     std::auto_ptr< DAVResourceAccess > xResAccess;
2040                     {
2041                         osl::MutexGuard aGuard( m_aMutex );
2042 
2043                         xResAccess.reset(
2044                             new DAVResourceAccess( *m_xResAccess.get() ) );
2045                     }
2046 
2047                     // fill inputsream sync; return if all data present
2048                     DAVResource aResource;
2049                     std::vector< rtl::OUString > aHeaders;
2050 
2051                     uno::Reference< io::XInputStream > xIn
2052                         = xResAccess->GET( aHeaders, aResource, xEnv );
2053                     m_bDidGetOrHead = true;
2054 
2055                     {
2056                         osl::MutexGuard aGuard( m_aMutex );
2057 
2058                         // cache headers.
2059                         if ( !m_xCachedProps.get())
2060                             m_xCachedProps.reset(
2061                                 new CachableContentProperties( aResource ) );
2062                         else
2063                             m_xCachedProps->addProperties(
2064                                 aResource.properties );
2065 
2066                         m_xResAccess.reset(
2067                             new DAVResourceAccess( *xResAccess.get() ) );
2068                     }
2069 
2070                     xDataSink->setInputStream( xIn );
2071                 }
2072                 catch ( DAVException const & e )
2073                 {
2074                     cancelCommandExecution( e, xEnv );
2075                     // Unreachable
2076                 }
2077             }
2078             else
2079             {
2080                 // Note: aOpenCommand.Sink may contain an XStream
2081                 //       implementation. Support for this type of
2082                 //       sink is optional...
2083                 ucbhelper::cancelCommandExecution(
2084                     uno::makeAny(
2085                         ucb::UnsupportedDataSinkException(
2086                             rtl::OUString(),
2087                             static_cast< cppu::OWeakObject * >( this ),
2088                             rArg.Sink ) ),
2089                     xEnv );
2090                 // Unreachable
2091             }
2092         }
2093     }
2094 
2095     return aRet;
2096 }
2097 
2098 //=========================================================================
2099 void Content::post(
2100                 const ucb::PostCommandArgument2 & rArg,
2101                 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2102     throw( uno::Exception )
2103 {
2104     uno::Reference< io::XActiveDataSink > xSink( rArg.Sink, uno::UNO_QUERY );
2105     if ( xSink.is() )
2106     {
2107         try
2108         {
2109             std::auto_ptr< DAVResourceAccess > xResAccess;
2110             {
2111                 osl::MutexGuard aGuard( m_aMutex );
2112                 xResAccess.reset(
2113                     new DAVResourceAccess( *m_xResAccess.get() ) );
2114             }
2115 
2116             uno::Reference< io::XInputStream > xResult
2117                 = xResAccess->POST( rArg.MediaType,
2118                                     rArg.Referer,
2119                                     rArg.Source,
2120                                     xEnv );
2121 
2122             {
2123                  osl::MutexGuard aGuard( m_aMutex );
2124                  m_xResAccess.reset(
2125                      new DAVResourceAccess( *xResAccess.get() ) );
2126             }
2127 
2128             xSink->setInputStream( xResult );
2129         }
2130         catch ( DAVException const & e )
2131         {
2132             cancelCommandExecution( e, xEnv, sal_True );
2133             // Unreachable
2134         }
2135     }
2136     else
2137     {
2138         uno::Reference< io::XOutputStream > xResult( rArg.Sink, uno::UNO_QUERY );
2139         if ( xResult.is() )
2140         {
2141             try
2142             {
2143                 std::auto_ptr< DAVResourceAccess > xResAccess;
2144                 {
2145                     osl::MutexGuard aGuard( m_aMutex );
2146                     xResAccess.reset(
2147                         new DAVResourceAccess( *m_xResAccess.get() ) );
2148                 }
2149 
2150                 xResAccess->POST( rArg.MediaType,
2151                                   rArg.Referer,
2152                                   rArg.Source,
2153                                   xResult,
2154                                   xEnv );
2155 
2156                 {
2157                     osl::MutexGuard aGuard( m_aMutex );
2158                     m_xResAccess.reset(
2159                         new DAVResourceAccess( *xResAccess.get() ) );
2160                 }
2161             }
2162             catch ( DAVException const & e )
2163             {
2164                 cancelCommandExecution( e, xEnv, sal_True );
2165                 // Unreachable
2166             }
2167         }
2168         else
2169         {
2170             ucbhelper::cancelCommandExecution(
2171                 uno::makeAny(
2172                     ucb::UnsupportedDataSinkException(
2173                         rtl::OUString(),
2174                         static_cast< cppu::OWeakObject * >( this ),
2175                         rArg.Sink ) ),
2176                 xEnv );
2177             // Unreachable
2178         }
2179     }
2180 }
2181 
2182 //=========================================================================
2183 void Content::queryChildren( ContentRefList& rChildren )
2184 {
2185     // Obtain a list with a snapshot of all currently instanciated contents
2186     // from provider and extract the contents which are direct children
2187     // of this content.
2188 
2189     ::ucbhelper::ContentRefList aAllContents;
2190     m_xProvider->queryExistingContents( aAllContents );
2191 
2192     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
2193     sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
2194 
2195     if ( nURLPos != ( aURL.getLength() - 1 ) )
2196     {
2197         // No trailing slash found. Append.
2198         aURL += rtl::OUString::createFromAscii( "/" );
2199     }
2200 
2201     sal_Int32 nLen = aURL.getLength();
2202 
2203     ::ucbhelper::ContentRefList::const_iterator it  = aAllContents.begin();
2204     ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
2205 
2206     while ( it != end )
2207     {
2208         ::ucbhelper::ContentImplHelperRef xChild = (*it);
2209         rtl::OUString aChildURL
2210             = xChild->getIdentifier()->getContentIdentifier();
2211 
2212         // Is aURL a prefix of aChildURL?
2213         if ( ( aChildURL.getLength() > nLen ) &&
2214              ( aChildURL.compareTo( aURL, nLen ) == 0 ) )
2215         {
2216             sal_Int32 nPos = nLen;
2217             nPos = aChildURL.indexOf( '/', nPos );
2218 
2219             if ( ( nPos == -1 ) ||
2220                  ( nPos == ( aChildURL.getLength() - 1 ) ) )
2221             {
2222                 // No further slashes / only a final slash. It's a child!
2223                 rChildren.push_back(
2224                     ::webdav_ucp::Content::ContentRef(
2225                         static_cast< ::webdav_ucp::Content * >(
2226                             xChild.get() ) ) );
2227             }
2228         }
2229         ++it;
2230     }
2231 }
2232 
2233 //=========================================================================
2234 void Content::insert(
2235         const uno::Reference< io::XInputStream > & xInputStream,
2236         sal_Bool bReplaceExisting,
2237         const uno::Reference< ucb::XCommandEnvironment >& Environment )
2238     throw( uno::Exception )
2239 {
2240     sal_Bool bTransient, bCollection;
2241     rtl::OUString aEscapedTitle;
2242     std::auto_ptr< DAVResourceAccess > xResAccess;
2243 
2244     {
2245         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2246 
2247         bTransient    = m_bTransient;
2248         bCollection   = m_bCollection;
2249         aEscapedTitle = m_aEscapedTitle;
2250         xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
2251     }
2252 
2253     // Check, if all required properties are present.
2254 
2255     if ( aEscapedTitle.getLength() == 0 )
2256     {
2257         OSL_ENSURE( sal_False, "Content::insert - Title missing!" );
2258 
2259         uno::Sequence< rtl::OUString > aProps( 1 );
2260         aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" );
2261         ucbhelper::cancelCommandExecution(
2262             uno::makeAny( ucb::MissingPropertiesException(
2263                                 rtl::OUString(),
2264                                 static_cast< cppu::OWeakObject * >( this ),
2265                                 aProps ) ),
2266             Environment );
2267         // Unreachable
2268     }
2269 
2270     if ( !bReplaceExisting )
2271     {
2272         /* [RFC 2616] - HTTP
2273 
2274            The PUT method requests that the enclosed entity be stored under the
2275            supplied Request-URI. If the Request-URI refers to an already
2276            existing resource, the enclosed entity SHOULD be considered as a
2277            modified version of the one residing on the origin server.
2278         */
2279 
2280         /* [RFC 2518] - WebDAV
2281 
2282            MKCOL creates a new collection resource at the location specified by
2283            the Request-URI.  If the resource identified by the Request-URI is
2284            non-null then the MKCOL MUST fail.
2285         */
2286 
2287         // ==> Complain on PUT, continue on MKCOL.
2288         if ( !bTransient || ( bTransient && !bCollection  ) )
2289         {
2290             ucb::UnsupportedNameClashException aEx(
2291                 rtl::OUString::createFromAscii(
2292                     "Unable to write without overwrite!" ),
2293                 static_cast< cppu::OWeakObject * >( this ),
2294                 ucb::NameClash::ERROR );
2295 
2296             uno::Reference< task::XInteractionHandler > xIH;
2297 
2298             if ( Environment.is() )
2299                 xIH = Environment->getInteractionHandler();
2300 
2301             if ( xIH.is() )
2302             {
2303                 uno::Any aExAsAny( uno::makeAny( aEx ) );
2304 
2305                 rtl::Reference< ucbhelper::SimpleInteractionRequest > xRequest
2306                     = new ucbhelper::SimpleInteractionRequest(
2307                         aExAsAny,
2308                         ucbhelper::CONTINUATION_APPROVE
2309                             | ucbhelper::CONTINUATION_DISAPPROVE );
2310                 xIH->handle( xRequest.get() );
2311 
2312                 const sal_Int32 nResp = xRequest->getResponse();
2313 
2314                 switch ( nResp )
2315                 {
2316                     case ucbhelper::CONTINUATION_UNKNOWN:
2317                         // Not handled; throw.
2318                         throw aEx;
2319 //                            break;
2320 
2321                     case ucbhelper::CONTINUATION_APPROVE:
2322                         // Continue -> Overwrite.
2323                         bReplaceExisting = sal_True;
2324                         break;
2325 
2326                     case ucbhelper::CONTINUATION_DISAPPROVE:
2327                         // Abort.
2328                         throw ucb::CommandFailedException(
2329                                     rtl::OUString(),
2330                                     uno::Reference< uno::XInterface >(),
2331                                     aExAsAny );
2332 //                            break;
2333 
2334                     default:
2335                         OSL_ENSURE( sal_False,
2336                                     "Content::insert - "
2337                                     "Unknown interaction selection!" );
2338                         throw ucb::CommandFailedException(
2339                                     rtl::OUString::createFromAscii(
2340                                         "Unknown interaction selection!" ),
2341                                     uno::Reference< uno::XInterface >(),
2342                                     aExAsAny );
2343 //                            break;
2344                 }
2345             }
2346             else
2347             {
2348                 // No IH; throw.
2349                 throw aEx;
2350             }
2351         }
2352     }
2353 
2354     if ( bTransient )
2355     {
2356         // Assemble new content identifier...
2357         rtl::OUString aURL = getParentURL();
2358         if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) )
2359             aURL += rtl::OUString::createFromAscii( "/" );
2360 
2361         aURL += aEscapedTitle;
2362 
2363         try
2364         {
2365             xResAccess->setURL( aURL );
2366 
2367             if ( bCollection )
2368                 xResAccess->MKCOL( Environment );
2369             else
2370                 xResAccess->PUT( xInputStream, Environment );
2371         }
2372         catch ( DAVException const & except )
2373         {
2374             if ( bCollection )
2375             {
2376                 if ( except.getStatus() == SC_METHOD_NOT_ALLOWED )
2377                 {
2378                     // [RFC 2518] - WebDAV
2379                     // 405 (Method Not Allowed) - MKCOL can only be
2380                     // executed on a deleted/non-existent resource.
2381 
2382                     if ( bReplaceExisting )
2383                     {
2384                         // Destroy old resource.
2385                         try
2386                         {
2387                             xResAccess->DESTROY( Environment );
2388                         }
2389                         catch ( DAVException const & e )
2390                         {
2391                             cancelCommandExecution( e, Environment, sal_True );
2392                             // Unreachable
2393                         }
2394 
2395                         // Insert (recursion!).
2396                         insert( xInputStream, bReplaceExisting, Environment );
2397 
2398                         {
2399                             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2400                             m_xResAccess.reset(
2401                                 new DAVResourceAccess( *xResAccess.get() ) );
2402                         }
2403 
2404                         // Success!
2405                         return;
2406                     }
2407                     else
2408                     {
2409                         rtl::OUString aTitle;
2410                         try
2411                         {
2412                             NeonUri aURI( aURL );
2413                             aTitle = aURI.GetPathBaseNameUnescaped();
2414                         }
2415                         catch ( DAVException const & )
2416                         {
2417                         }
2418 
2419                         ucbhelper::cancelCommandExecution(
2420                             uno::makeAny(
2421                                 ucb::NameClashException(
2422                                     rtl::OUString(),
2423                                     static_cast< cppu::OWeakObject * >( this ),
2424                                     task::InteractionClassification_ERROR,
2425                                     aTitle ) ),
2426                             Environment );
2427                         // Unreachable
2428                     }
2429                 }
2430             }
2431 
2432             cancelCommandExecution( except, Environment, sal_True );
2433             // Unreachable
2434         }
2435 
2436         {
2437             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2438             m_xIdentifier
2439                 = new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL );
2440         }
2441 
2442         inserted();
2443 
2444         {
2445             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2446             m_bTransient = sal_False;
2447         }
2448     }
2449     else
2450     {
2451         if ( !xInputStream.is() )
2452         {
2453             ucbhelper::cancelCommandExecution(
2454                 uno::makeAny(
2455                     ucb::MissingInputStreamException(
2456                         rtl::OUString(),
2457                         static_cast< cppu::OWeakObject * >( this ) ) ),
2458                 Environment );
2459             // Unreachable
2460         }
2461 
2462         try
2463         {
2464             xResAccess->PUT( xInputStream, Environment );
2465         }
2466         catch ( DAVException const & e )
2467         {
2468             cancelCommandExecution( e, Environment, sal_True );
2469             // Unreachable
2470         }
2471     }
2472 
2473     {
2474         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2475         m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2476     }
2477 }
2478 
2479 //=========================================================================
2480 void Content::transfer(
2481         const ucb::TransferInfo & rArgs,
2482         const uno::Reference< ucb::XCommandEnvironment >& Environment )
2483     throw( uno::Exception )
2484 {
2485     uno::Reference< lang::XMultiServiceFactory > xSMgr;
2486     uno::Reference< ucb::XContentIdentifier >    xIdentifier;
2487     uno::Reference< ucb::XContentProvider >      xProvider;
2488     std::auto_ptr< DAVResourceAccess > xResAccess;
2489 
2490     {
2491         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2492 
2493         xSMgr.set( m_xSMgr );
2494         xIdentifier.set( m_xIdentifier );
2495         xProvider.set( m_xProvider.get() );
2496         xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
2497     }
2498 
2499     rtl::OUString aTargetURI;
2500     try
2501     {
2502         NeonUri sourceURI( rArgs.SourceURL );
2503         NeonUri targetURI( xIdentifier->getContentIdentifier() );
2504         aTargetURI = targetURI.GetPathBaseNameUnescaped();
2505 
2506         // Check source's and target's URL scheme
2507         //
2508         const rtl::OUString aScheme = sourceURI.GetScheme().toAsciiLowerCase();
2509         if ( aScheme.equalsAsciiL(
2510                 RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) )
2511         {
2512             sourceURI.SetScheme(
2513                 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2514         }
2515         else if ( aScheme.equalsAsciiL(
2516                 RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) )
2517         {
2518             sourceURI.SetScheme(
2519                 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2520         }
2521         else if ( aScheme.equalsAsciiL(
2522                 RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) )
2523         {
2524             sourceURI.SetScheme(
2525                 rtl::OUString::createFromAscii( HTTPS_URL_SCHEME ) );
2526         }
2527         else
2528         {
2529             if ( !aScheme.equalsAsciiL(
2530                     RTL_CONSTASCII_STRINGPARAM( HTTP_URL_SCHEME ) ) &&
2531                  !aScheme.equalsAsciiL(
2532                     RTL_CONSTASCII_STRINGPARAM( HTTPS_URL_SCHEME ) ) )
2533             {
2534                 ucbhelper::cancelCommandExecution(
2535                     uno::makeAny(
2536                         ucb::InteractiveBadTransferURLException(
2537                             rtl::OUString::createFromAscii(
2538                                 "Unsupported URL scheme!" ),
2539                             static_cast< cppu::OWeakObject * >( this ) ) ),
2540                     Environment );
2541                 // Unreachable
2542             }
2543         }
2544 
2545         if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
2546                  RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) )
2547             targetURI.SetScheme(
2548                 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2549         else if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
2550                  RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) )
2551             targetURI.SetScheme(
2552                 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2553 
2554         // @@@ This implementation of 'transfer' only works
2555         //     if the source and target are located at same host.
2556         //     (Neon does not support cross-server copy/move)
2557 
2558         // Check for same host
2559         //
2560         if ( sourceURI.GetHost().getLength() &&
2561              ( sourceURI.GetHost() != targetURI.GetHost() ) )
2562         {
2563             ucbhelper::cancelCommandExecution(
2564                 uno::makeAny( ucb::InteractiveBadTransferURLException(
2565                                 rtl::OUString::createFromAscii(
2566                                     "Different hosts!" ),
2567                                 static_cast< cppu::OWeakObject * >( this ) ) ),
2568                 Environment );
2569             // Unreachable
2570         }
2571 
2572         rtl::OUString aTitle = rArgs.NewTitle;
2573 
2574         if ( !aTitle.getLength() )
2575             aTitle = sourceURI.GetPathBaseNameUnescaped();
2576 
2577         if ( aTitle.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "/" ) ) )
2578         {
2579             // kso: ???
2580             aTitle = rtl::OUString();
2581         }
2582 
2583         targetURI.AppendPath( aTitle );
2584 
2585         rtl::OUString aTargetURL = xIdentifier->getContentIdentifier();
2586         if ( ( aTargetURL.lastIndexOf( '/' ) + 1 )
2587                 != aTargetURL.getLength() )
2588             aTargetURL += rtl::OUString::createFromAscii( "/" );
2589 
2590         aTargetURL += aTitle;
2591 
2592         uno::Reference< ucb::XContentIdentifier > xTargetId
2593             = new ::ucbhelper::ContentIdentifier( xSMgr, aTargetURL );
2594 
2595         DAVResourceAccess aSourceAccess( xSMgr,
2596                                          xResAccess->getSessionFactory(),
2597                                          sourceURI.GetURI() );
2598 
2599         if ( rArgs.MoveData == sal_True )
2600         {
2601             uno::Reference< ucb::XContentIdentifier > xId
2602                 = new ::ucbhelper::ContentIdentifier( xSMgr, rArgs.SourceURL );
2603 
2604             // Note: The static cast is okay here, because its sure that
2605             //       xProvider is always the WebDAVContentProvider.
2606             rtl::Reference< Content > xSource
2607                 = static_cast< Content * >(
2608                     xProvider->queryContent( xId ).get() );
2609 
2610             // [RFC 2518] - WebDAV
2611             // If a resource exists at the destination and the Overwrite
2612             // header is "T" then prior to performing the move the server
2613             // MUST perform a DELETE with "Depth: infinity" on the
2614             // destination resource.  If the Overwrite header is set to
2615             // "F" then the operation will fail.
2616 
2617             aSourceAccess.MOVE( sourceURI.GetPath(),
2618                                 targetURI.GetURI(),
2619                                 rArgs.NameClash
2620                                     == ucb::NameClash::OVERWRITE,
2621                                 Environment );
2622 
2623             if ( xSource.is() )
2624             {
2625                 // Propagate destruction to listeners.
2626                 xSource->destroy( sal_True );
2627             }
2628 
2629 // DAV resources store all additional props on server!
2630 //              // Rename own and all children's Additional Core Properties.
2631 //              renameAdditionalPropertySet( xId->getContentIdentifier(),
2632 //                                           xTargetId->getContentIdentifier(),
2633 //                                           sal_True );
2634         }
2635         else
2636         {
2637             // [RFC 2518] - WebDAV
2638             // If a resource exists at the destination and the Overwrite
2639             // header is "T" then prior to performing the copy the server
2640             // MUST perform a DELETE with "Depth: infinity" on the
2641             // destination resource.  If the Overwrite header is set to
2642             // "F" then the operation will fail.
2643 
2644             aSourceAccess.COPY( sourceURI.GetPath(),
2645                                 targetURI.GetURI(),
2646                                 rArgs.NameClash
2647                                     == ucb::NameClash::OVERWRITE,
2648                                 Environment );
2649 
2650 // DAV resources store all additional props on server!
2651 //              // Copy own and all children's Additional Core Properties.
2652 //              copyAdditionalPropertySet( xId->getContentIdentifier(),
2653 //                                         xTargetId->getContentIdentifier(),
2654 //                                         sal_True );
2655         }
2656 
2657         // Note: The static cast is okay here, because its sure that
2658         //       xProvider is always the WebDAVContentProvider.
2659         rtl::Reference< Content > xTarget
2660             = static_cast< Content * >(
2661                     xProvider->queryContent( xTargetId ).get() );
2662 
2663         // Announce transfered content in its new folder.
2664         xTarget->inserted();
2665     }
2666     catch ( ucb::IllegalIdentifierException const & )
2667     {
2668         // queryContent
2669     }
2670     catch ( DAVException const & e )
2671     {
2672         // [RFC 2518] - WebDAV
2673         // 412 (Precondition Failed) - The server was unable to maintain
2674         // the liveness of the properties listed in the propertybehavior
2675         // XML element or the Overwrite header is "F" and the state of
2676         // the destination resource is non-null.
2677 
2678         if ( e.getStatus() == SC_PRECONDITION_FAILED )
2679         {
2680             switch ( rArgs.NameClash )
2681             {
2682                 case ucb::NameClash::ERROR:
2683                 {
2684                     ucbhelper::cancelCommandExecution(
2685                         uno::makeAny(
2686                             ucb::NameClashException(
2687                                 rtl::OUString(),
2688                                 static_cast< cppu::OWeakObject * >( this ),
2689                                 task::InteractionClassification_ERROR,
2690                                 aTargetURI ) ),
2691                         Environment );
2692                     // Unreachable
2693                 }
2694 
2695                 case ucb::NameClash::OVERWRITE:
2696                     break;
2697 
2698                 case ucb::NameClash::KEEP: // deprecated
2699                 case ucb::NameClash::RENAME:
2700                 case ucb::NameClash::ASK:
2701                 default:
2702                 {
2703                     ucbhelper::cancelCommandExecution(
2704                         uno::makeAny(
2705                             ucb::UnsupportedNameClashException(
2706                                 rtl::OUString(),
2707                                 static_cast< cppu::OWeakObject * >( this ),
2708                                 rArgs.NameClash ) ),
2709                         Environment );
2710                     // Unreachable
2711                 }
2712             }
2713         }
2714 
2715         cancelCommandExecution( e, Environment, sal_True );
2716         // Unreachable
2717     }
2718 
2719     {
2720         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2721         m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2722     }
2723 }
2724 
2725 //=========================================================================
2726 void Content::destroy( sal_Bool bDeletePhysical )
2727     throw( uno::Exception )
2728 {
2729     // @@@ take care about bDeletePhysical -> trashcan support
2730     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
2731 
2732     uno::Reference< ucb::XContent > xThis = this;
2733 
2734     deleted();
2735 
2736     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2737 
2738     // Process instanciated children...
2739 
2740     ::webdav_ucp::Content::ContentRefList aChildren;
2741     queryChildren( aChildren );
2742 
2743     ContentRefList::const_iterator it  = aChildren.begin();
2744     ContentRefList::const_iterator end = aChildren.end();
2745 
2746     while ( it != end )
2747     {
2748         (*it)->destroy( bDeletePhysical );
2749         ++it;
2750     }
2751 }
2752 
2753 //=========================================================================
2754 bool Content::supportsExclusiveWriteLock(
2755   const uno::Reference< ucb::XCommandEnvironment >& Environment )
2756 {
2757     if ( getResourceType( Environment ) == DAV )
2758     {
2759         if ( m_xCachedProps.get() )
2760         {
2761             uno::Sequence< ucb::LockEntry > aSupportedLocks;
2762             if ( m_xCachedProps->getValue( DAVProperties::SUPPORTEDLOCK )
2763                 >>= aSupportedLocks )
2764             {
2765                 for ( sal_Int32 n = 0; n < aSupportedLocks.getLength(); ++n )
2766                 {
2767                     if ( aSupportedLocks[ n ].Scope
2768                             == ucb::LockScope_EXCLUSIVE &&
2769                          aSupportedLocks[ n ].Type
2770                             == ucb::LockType_WRITE )
2771                         return true;
2772                 }
2773             }
2774         }
2775     }
2776     return false;
2777 }
2778 
2779 //=========================================================================
2780 void Content::lock(
2781         const uno::Reference< ucb::XCommandEnvironment >& Environment )
2782     throw( uno::Exception )
2783 {
2784     try
2785     {
2786         std::auto_ptr< DAVResourceAccess > xResAccess;
2787         {
2788             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2789             xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
2790         }
2791 
2792         uno::Any aOwnerAny;
2793         aOwnerAny
2794             <<= rtl::OUString::createFromAscii( "http://ucb.openoffice.org" );
2795 
2796         ucb::Lock aLock(
2797             ucb::LockScope_EXCLUSIVE,
2798             ucb::LockType_WRITE,
2799             ucb::LockDepth_ZERO,
2800             aOwnerAny,
2801             180, // lock timeout in secs
2802             //-1, // infinite lock
2803             uno::Sequence< ::rtl::OUString >() );
2804 
2805         xResAccess->LOCK( aLock, Environment );
2806 
2807         {
2808             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2809             m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2810         }
2811     }
2812     catch ( DAVException const & e )
2813     {
2814         cancelCommandExecution( e, Environment, sal_False );
2815         // Unreachable
2816     }
2817 }
2818 
2819 //=========================================================================
2820 void Content::unlock(
2821         const uno::Reference< ucb::XCommandEnvironment >& Environment )
2822     throw( uno::Exception )
2823 {
2824     try
2825     {
2826         std::auto_ptr< DAVResourceAccess > xResAccess;
2827         {
2828             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2829             xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
2830         }
2831 
2832         xResAccess->UNLOCK( Environment );
2833 
2834         {
2835             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2836             m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2837         }
2838     }
2839     catch ( DAVException const & e )
2840     {
2841         cancelCommandExecution( e, Environment, sal_False );
2842         // Unreachable
2843     }
2844 }
2845 
2846 //=========================================================================
2847 sal_Bool Content::exchangeIdentity(
2848     const uno::Reference< ucb::XContentIdentifier >& xNewId )
2849 {
2850     if ( !xNewId.is() )
2851         return sal_False;
2852 
2853     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
2854 
2855     uno::Reference< ucb::XContent > xThis = this;
2856 
2857     // Already persistent?
2858     if ( m_bTransient )
2859     {
2860         OSL_ENSURE( sal_False, "Content::exchangeIdentity - Not persistent!" );
2861         return sal_False;
2862     }
2863 
2864     // Exchange own identitity.
2865 
2866     // Fail, if a content with given id already exists.
2867 //  if ( !hasData( xNewId ) )
2868     {
2869         rtl::OUString aOldURL = m_xIdentifier->getContentIdentifier();
2870 
2871         aGuard.clear();
2872         if ( exchange( xNewId ) )
2873         {
2874             // Process instanciated children...
2875 
2876             ContentRefList aChildren;
2877             queryChildren( aChildren );
2878 
2879             ContentRefList::const_iterator it  = aChildren.begin();
2880             ContentRefList::const_iterator end = aChildren.end();
2881 
2882             while ( it != end )
2883             {
2884                 ContentRef xChild = (*it);
2885 
2886                 // Create new content identifier for the child...
2887                 uno::Reference< ucb::XContentIdentifier >
2888                     xOldChildId = xChild->getIdentifier();
2889                 rtl::OUString aOldChildURL
2890                     = xOldChildId->getContentIdentifier();
2891                 rtl::OUString aNewChildURL
2892                     = aOldChildURL.replaceAt(
2893                         0,
2894                         aOldURL.getLength(),
2895                         xNewId->getContentIdentifier() );
2896                 uno::Reference< ucb::XContentIdentifier > xNewChildId
2897                     = new ::ucbhelper::ContentIdentifier(
2898                         m_xSMgr, aNewChildURL );
2899 
2900                 if ( !xChild->exchangeIdentity( xNewChildId ) )
2901                     return sal_False;
2902 
2903                 ++it;
2904             }
2905             return sal_True;
2906         }
2907     }
2908 
2909     OSL_ENSURE( sal_False,
2910                 "Content::exchangeIdentity - "
2911                 "Panic! Cannot exchange identity!" );
2912     return sal_False;
2913 }
2914 
2915 //=========================================================================
2916 sal_Bool Content::isFolder(
2917             const uno::Reference< ucb::XCommandEnvironment >& xEnv )
2918     throw( uno::Exception )
2919 {
2920     {
2921         osl::MutexGuard aGuard( m_aMutex );
2922 
2923         if ( m_bTransient )
2924             return m_bCollection;
2925     }
2926 
2927     uno::Sequence< beans::Property > aProperties( 1 );
2928     aProperties[ 0 ].Name   = rtl::OUString::createFromAscii( "IsFolder" );
2929     aProperties[ 0 ].Handle = -1;
2930     uno::Reference< sdbc::XRow > xRow( getPropertyValues( aProperties, xEnv ) );
2931     if ( xRow.is() )
2932     {
2933         try
2934         {
2935             return xRow->getBoolean( 1 );
2936         }
2937         catch ( sdbc::SQLException const & )
2938         {
2939         }
2940     }
2941 
2942     return sal_False;
2943 }
2944 
2945 //=========================================================================
2946 uno::Any Content::MapDAVException( const DAVException & e, sal_Bool bWrite )
2947 {
2948     // Map DAVException...
2949     uno::Any aException;
2950 
2951     rtl::OUString aURL;
2952     if ( m_bTransient )
2953     {
2954         aURL = getParentURL();
2955         if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) )
2956             aURL += rtl::OUString::createFromAscii( "/" );
2957 
2958         aURL += m_aEscapedTitle;
2959     }
2960     else
2961     {
2962         aURL = m_xIdentifier->getContentIdentifier();
2963     }
2964 
2965     switch ( e.getStatus() )
2966     {
2967         case SC_NOT_FOUND:
2968         {
2969             uno::Sequence< uno::Any > aArgs( 1 );
2970             aArgs[ 0 ] <<= beans::PropertyValue(
2971                 rtl::OUString::createFromAscii("Uri"), -1,
2972                 uno::makeAny(aURL),
2973                 beans::PropertyState_DIRECT_VALUE);
2974 
2975             aException <<=
2976                 ucb::InteractiveAugmentedIOException(
2977                     rtl::OUString::createFromAscii( "Not found!" ),
2978                     static_cast< cppu::OWeakObject * >( this ),
2979                     task::InteractionClassification_ERROR,
2980                     ucb::IOErrorCode_NOT_EXISTING,
2981                     aArgs );
2982             return aException;
2983         }
2984         default:
2985             break;
2986     }
2987 
2988     switch ( e.getError() )
2989     {
2990     case DAVException::DAV_HTTP_ERROR:
2991         {
2992             if ( bWrite )
2993                 aException <<=
2994                     ucb::InteractiveNetworkWriteException(
2995                         e.getData(),
2996                         static_cast< cppu::OWeakObject * >( this ),
2997                         task::InteractionClassification_ERROR,
2998                         e.getData() );
2999             else
3000                 aException <<=
3001                     ucb::InteractiveNetworkReadException(
3002                         e.getData(),
3003                         static_cast< cppu::OWeakObject * >( this ),
3004                         task::InteractionClassification_ERROR,
3005                         e.getData() );
3006             break;
3007         }
3008 
3009     case DAVException::DAV_HTTP_LOOKUP:
3010         aException <<=
3011             ucb::InteractiveNetworkResolveNameException(
3012                 rtl::OUString(),
3013                 static_cast< cppu::OWeakObject * >( this ),
3014                 task::InteractionClassification_ERROR,
3015                 e.getData() );
3016         break;
3017 
3018 // @@@ No matching InteractiveNetwork*Exception
3019 //    case DAVException::DAV_HTTP_AUTH:
3020 //        break;
3021 
3022 // @@@ No matching InteractiveNetwork*Exception
3023 //    case DAVException::DAV_HTTP_AUTHPROXY:
3024 //        break;
3025 
3026     case DAVException::DAV_HTTP_CONNECT:
3027         aException <<=
3028             ucb::InteractiveNetworkConnectException(
3029                 rtl::OUString(),
3030                 static_cast< cppu::OWeakObject * >( this ),
3031                 task::InteractionClassification_ERROR,
3032                 e.getData() );
3033         break;
3034 
3035 // @@@ No matching InteractiveNetwork*Exception
3036 //    case DAVException::DAV_HTTP_TIMEOUT:
3037 //        break;
3038 
3039 // @@@ No matching InteractiveNetwork*Exception
3040 //     case DAVException::DAV_HTTP_REDIRECT:
3041 //         break;
3042 
3043 // @@@ No matching InteractiveNetwork*Exception
3044 //     case DAVException::DAV_SESSION_CREATE:
3045 //         break;
3046 
3047     case DAVException::DAV_INVALID_ARG:
3048         aException <<=
3049             lang::IllegalArgumentException(
3050                 rtl::OUString(),
3051                 static_cast< cppu::OWeakObject * >( this ),
3052                 -1 );
3053         break;
3054 
3055     case DAVException::DAV_LOCKED:
3056 #if 1
3057         aException <<=
3058             ucb::InteractiveLockingLockedException(
3059                 rtl::OUString::createFromAscii( "Locked!" ),
3060                 static_cast< cppu::OWeakObject * >( this ),
3061                 task::InteractionClassification_ERROR,
3062                 aURL,
3063                 sal_False ); // not SelfOwned
3064 #else
3065         {
3066             uno::Sequence< uno::Any > aArgs( 1 );
3067             aArgs[ 0 ] <<= beans::PropertyValue(
3068                 rtl::OUString::createFromAscii("Uri"), -1,
3069                 uno::makeAny(aURL),
3070                 beans::PropertyState_DIRECT_VALUE);
3071 
3072             aException <<=
3073                 ucb::InteractiveAugmentedIOException(
3074                     rtl::OUString::createFromAscii( "Locked!" ),
3075                     static_cast< cppu::OWeakObject * >( this ),
3076                     task::InteractionClassification_ERROR,
3077                     ucb::IOErrorCode_LOCKING_VIOLATION,
3078                     aArgs );
3079         }
3080 #endif
3081         break;
3082 
3083     case DAVException::DAV_LOCKED_SELF:
3084         aException <<=
3085             ucb::InteractiveLockingLockedException(
3086                 rtl::OUString::createFromAscii( "Locked (self)!" ),
3087                 static_cast< cppu::OWeakObject * >( this ),
3088                 task::InteractionClassification_ERROR,
3089                 aURL,
3090                 sal_True ); // SelfOwned
3091         break;
3092 
3093     case DAVException::DAV_NOT_LOCKED:
3094         aException <<=
3095             ucb::InteractiveLockingNotLockedException(
3096                 rtl::OUString::createFromAscii( "Not locked!" ),
3097                 static_cast< cppu::OWeakObject * >( this ),
3098                 task::InteractionClassification_ERROR,
3099                 aURL );
3100         break;
3101 
3102     case DAVException::DAV_LOCK_EXPIRED:
3103         aException <<=
3104             ucb::InteractiveLockingLockExpiredException(
3105                 rtl::OUString::createFromAscii( "Lock expired!" ),
3106                 static_cast< cppu::OWeakObject * >( this ),
3107                 task::InteractionClassification_ERROR,
3108                 aURL );
3109         break;
3110 
3111     default:
3112         aException <<=
3113             ucb::InteractiveNetworkGeneralException(
3114                 rtl::OUString(),
3115                 static_cast< cppu::OWeakObject * >( this ),
3116                 task::InteractionClassification_ERROR );
3117         break;
3118     }
3119 
3120     return aException;
3121 }
3122 
3123 //=========================================================================
3124 // static
3125 bool Content::shouldAccessNetworkAfterException( const DAVException & e )
3126 {
3127     if ( ( e.getStatus() == SC_NOT_FOUND ) ||
3128          ( e.getError() == DAVException::DAV_HTTP_LOOKUP ) ||
3129          ( e.getError() == DAVException::DAV_HTTP_CONNECT ) ||
3130          ( e.getError() == DAVException::DAV_HTTP_AUTH ) ||
3131          ( e.getError() == DAVException::DAV_HTTP_AUTHPROXY ) )
3132         return false;
3133 
3134     return true;
3135 }
3136 
3137 //=========================================================================
3138 void Content::cancelCommandExecution(
3139                 const DAVException & e,
3140                 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
3141                 sal_Bool bWrite /* = sal_False */ )
3142     throw ( uno::Exception )
3143 {
3144     ucbhelper::cancelCommandExecution( MapDAVException( e, bWrite ), xEnv );
3145     // Unreachable
3146 }
3147 
3148 //=========================================================================
3149 const rtl::OUString
3150 Content::getBaseURI( const std::auto_ptr< DAVResourceAccess > & rResAccess )
3151 {
3152     osl::Guard< osl::Mutex > aGuard( m_aMutex );
3153 
3154     // First, try to obtain value of response header "Content-Location".
3155     if ( m_xCachedProps.get() )
3156     {
3157         rtl::OUString aLocation;
3158         m_xCachedProps->getValue( rtl::OUString(
3159                                     RTL_CONSTASCII_USTRINGPARAM(
3160                                         "Content-Location" ) ) ) >>= aLocation;
3161         if ( aLocation.getLength() )
3162         {
3163             try
3164             {
3165                 // Do not use m_xIdentifier->getContentIdentifier() because it
3166                 // for example does not reflect redirects applied to requests
3167                 // done using the original URI but m_xResAccess' URI does.
3168                 return rtl::Uri::convertRelToAbs( rResAccess->getURL(),
3169                                                   aLocation );
3170             }
3171             catch ( rtl::MalformedUriException const & )
3172             {
3173             }
3174         }
3175     }
3176 
3177     return rtl::OUString( rResAccess->getURL() );
3178 }
3179 
3180 //=========================================================================
3181 const Content::ResourceType & Content::getResourceType(
3182                     const uno::Reference< ucb::XCommandEnvironment >& xEnv,
3183                     const std::auto_ptr< DAVResourceAccess > & rResAccess )
3184     throw ( uno::Exception )
3185 {
3186     if ( m_eResourceType == UNKNOWN )
3187     {
3188         osl::Guard< osl::Mutex > aGuard( m_aMutex );
3189 
3190         ResourceType eResourceType;
3191         eResourceType = m_eResourceType;
3192 
3193         const rtl::OUString & rURL = rResAccess->getURL();
3194         const rtl::OUString aScheme(
3195             rURL.copy( 0, rURL.indexOf( ':' ) ).toAsciiLowerCase() );
3196 
3197         if ( aScheme.equalsAsciiL(
3198                 RTL_CONSTASCII_STRINGPARAM( FTP_URL_SCHEME ) ) )
3199         {
3200             eResourceType = FTP;
3201         }
3202         else
3203         {
3204             try
3205             {
3206                 // Try to fetch some frequently used property value, e.g. those
3207                 // used when loading documents... along with identifying whether
3208                 // this is a DAV resource.
3209                 std::vector< DAVResource > resources;
3210                 std::vector< rtl::OUString > aPropNames;
3211                 uno::Sequence< beans::Property > aProperties( 5 );
3212                 aProperties[ 0 ].Name
3213                     = rtl::OUString::createFromAscii( "IsFolder" );
3214                 aProperties[ 1 ].Name
3215                     = rtl::OUString::createFromAscii( "IsDocument" );
3216                 aProperties[ 2 ].Name
3217                     = rtl::OUString::createFromAscii( "IsReadOnly" );
3218                 aProperties[ 3 ].Name
3219                     = rtl::OUString::createFromAscii( "MediaType" );
3220                 aProperties[ 4 ].Name
3221                     = DAVProperties::SUPPORTEDLOCK;
3222 
3223                 ContentProperties::UCBNamesToDAVNames(
3224                     aProperties, aPropNames );
3225 
3226                 rResAccess->PROPFIND(
3227                     DAVZERO, aPropNames, resources, xEnv );
3228 
3229                 if ( resources.size() == 1 )
3230                 {
3231                     m_xCachedProps.reset(
3232                         new CachableContentProperties( resources[ 0 ] ) );
3233                     m_xCachedProps->containsAllNames(
3234                         aProperties, m_aFailedPropNames );
3235                 }
3236 
3237                 eResourceType = DAV;
3238             }
3239             catch ( DAVException const & e )
3240             {
3241                 rResAccess->resetUri();
3242 
3243                 if ( e.getStatus() == SC_METHOD_NOT_ALLOWED )
3244                 {
3245                     // Status SC_METHOD_NOT_ALLOWED is a safe indicator that the
3246                     // resource is NON_DAV
3247                     eResourceType = NON_DAV;
3248                 }
3249             }
3250         }
3251         m_eResourceType = eResourceType;
3252     }
3253     return m_eResourceType;
3254 }
3255 
3256 //=========================================================================
3257 const Content::ResourceType & Content::getResourceType(
3258                     const uno::Reference< ucb::XCommandEnvironment >& xEnv )
3259     throw ( uno::Exception )
3260 {
3261     return getResourceType( xEnv, m_xResAccess );
3262 }
3263