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