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             xProps->addProperty(
1661                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ContentType" ) ),
1662                 uno::makeAny( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( WEBDAV_CONTENT_TYPE ) ) ),
1663                 true );
1664         }
1665     }
1666     else
1667     {
1668         // No server access for just created (not yet committed) objects.
1669         // Only a minimal set of properties supported at this stage.
1670         if (m_bTransient)
1671             xProps.reset( new ContentProperties( aUnescapedTitle,
1672                                                  m_bCollection ) );
1673     }
1674 
1675     sal_Int32 nCount = rProperties.getLength();
1676     for ( sal_Int32 n = 0; n < nCount; ++n )
1677     {
1678         const rtl::OUString rName = rProperties[ n ].Name;
1679         if ( rName.equalsAsciiL(
1680                       RTL_CONSTASCII_STRINGPARAM( "BaseURI" ) ) )
1681         {
1682             // Add BaseURI property, if requested.
1683             xProps->addProperty(
1684                  rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseURI" ) ),
1685                  uno::makeAny( getBaseURI( xResAccess ) ),
1686                  true );
1687         }
1688         else if ( rName.equalsAsciiL(
1689                       RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
1690         {
1691             // Add CreatableContentsInfo property, if requested.
1692             sal_Bool bFolder = sal_False;
1693             xProps->getValue(
1694                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ) )
1695                     >>= bFolder;
1696             xProps->addProperty(
1697                 rtl::OUString(
1698                     RTL_CONSTASCII_USTRINGPARAM( "CreatableContentsInfo" ) ),
1699                 uno::makeAny( bFolder
1700                                   ? queryCreatableContentsInfo()
1701                                   : uno::Sequence< ucb::ContentInfo >() ),
1702                 true );
1703         }
1704     }
1705 
1706     uno::Reference< sdbc::XRow > xResultRow
1707         = getPropertyValues( xSMgr,
1708                              rProperties,
1709                              *xProps,
1710                              xProvider,
1711                              xIdentifier->getContentIdentifier() );
1712 
1713     {
1714         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1715 
1716         if ( !m_xCachedProps.get() )
1717             m_xCachedProps.reset( new CachableContentProperties( *xProps.get() ) );
1718         else
1719             m_xCachedProps->addProperties( *xProps.get() );
1720 
1721         m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
1722         m_aEscapedTitle = SerfUri::escapeSegment( aUnescapedTitle );
1723     }
1724 
1725     return xResultRow;
1726 }
1727 
1728 //=========================================================================
1729 uno::Sequence< uno::Any > Content::setPropertyValues(
1730                 const uno::Sequence< beans::PropertyValue >& rValues,
1731                 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1732     throw ( uno::Exception )
1733 {
1734     uno::Reference< lang::XMultiServiceFactory > xSMgr;
1735     uno::Reference< ucb::XContentIdentifier >    xIdentifier;
1736     rtl::Reference< ContentProvider >            xProvider;
1737     sal_Bool bTransient;
1738     std::auto_ptr< DAVResourceAccess > xResAccess;
1739 
1740     {
1741         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1742 
1743         xProvider.set( m_pProvider );
1744         xIdentifier.set( m_xIdentifier );
1745         bTransient = m_bTransient;
1746         xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
1747         xSMgr.set( m_xSMgr );
1748     }
1749 
1750     uno::Sequence< uno::Any > aRet( rValues.getLength() );
1751     uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1752     sal_Int32 nChanged = 0;
1753 
1754     beans::PropertyChangeEvent aEvent;
1755     aEvent.Source         = static_cast< cppu::OWeakObject * >( this );
1756     aEvent.Further        = sal_False;
1757     // aEvent.PropertyName =
1758     aEvent.PropertyHandle = -1;
1759     // aEvent.OldValue   =
1760     // aEvent.NewValue   =
1761 
1762     std::vector< ProppatchValue > aProppatchValues;
1763     std::vector< sal_Int32 > aProppatchPropsPositions;
1764 
1765     uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1766     sal_Bool bTriedToGetAdditonalPropSet = sal_False;
1767 
1768     sal_Bool bExchange = sal_False;
1769     rtl::OUString aNewTitle;
1770     rtl::OUString aOldTitle;
1771     sal_Int32 nTitlePos = -1;
1772 
1773     uno::Reference< beans::XPropertySetInfo > xInfo;
1774 
1775     const beans::PropertyValue* pValues = rValues.getConstArray();
1776     sal_Int32 nCount = rValues.getLength();
1777     for ( sal_Int32 n = 0; n < nCount; ++n )
1778     {
1779         const beans::PropertyValue& rValue = pValues[ n ];
1780         const rtl::OUString & rName = rValue.Name;
1781 
1782         beans::Property aTmpProp;
1783         xProvider->getProperty( rName, aTmpProp );
1784 
1785         if ( aTmpProp.Attributes & beans::PropertyAttribute::READONLY )
1786         {
1787             // Read-only property!
1788             aRet[ n ] <<= lang::IllegalAccessException(
1789                             rtl::OUString::createFromAscii(
1790                                 "Property is read-only!" ),
1791                             static_cast< cppu::OWeakObject * >( this ) );
1792             continue;
1793         }
1794 
1795         //////////////////////////////////////////////////////////////////
1796         // Mandatory props.
1797         //////////////////////////////////////////////////////////////////
1798 
1799         if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) )
1800         {
1801             // Read-only property!
1802             aRet[ n ] <<= lang::IllegalAccessException(
1803                 rtl::OUString::createFromAscii(
1804                     "Property is read-only!" ),
1805                 static_cast< cppu::OWeakObject * >( this ) );
1806         }
1807         else if ( rName.equalsAsciiL(
1808                       RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
1809         {
1810             // Read-only property!
1811             aRet[ n ] <<= lang::IllegalAccessException(
1812                 rtl::OUString::createFromAscii(
1813                     "Property is read-only!" ),
1814                 static_cast< cppu::OWeakObject * >( this ) );
1815         }
1816         else if ( rName.equalsAsciiL(
1817                       RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
1818         {
1819             // Read-only property!
1820             aRet[ n ] <<= lang::IllegalAccessException(
1821                             rtl::OUString::createFromAscii(
1822                                 "Property is read-only!" ),
1823                             static_cast< cppu::OWeakObject * >( this ) );
1824         }
1825         else if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
1826         {
1827             rtl::OUString aNewValue;
1828             if ( rValue.Value >>= aNewValue )
1829             {
1830                 // No empty titles!
1831                 if ( aNewValue.getLength() > 0 )
1832                 {
1833                     try
1834                     {
1835                         SerfUri aURI( xIdentifier->getContentIdentifier() );
1836                         aOldTitle = aURI.GetPathBaseNameUnescaped();
1837 
1838                         if ( aNewValue != aOldTitle )
1839                         {
1840                             // modified title -> modified URL -> exchange !
1841                             if ( !bTransient )
1842                                 bExchange = sal_True;
1843 
1844                             // new value will be set later...
1845                             aNewTitle = aNewValue;
1846 
1847                             // remember position within sequence of values (for
1848                             // error handling).
1849                             nTitlePos = n;
1850                         }
1851                     }
1852                     catch ( DAVException const & )
1853                     {
1854                         aRet[ n ] <<= lang::IllegalArgumentException(
1855                             rtl::OUString::createFromAscii(
1856                                 "Invalid content identifier!" ),
1857                             static_cast< cppu::OWeakObject * >( this ),
1858                             -1 );
1859                     }
1860                 }
1861                 else
1862                 {
1863                     aRet[ n ] <<= lang::IllegalArgumentException(
1864                         rtl::OUString::createFromAscii(
1865                             "Empty title not allowed!" ),
1866                         static_cast< cppu::OWeakObject * >( this ),
1867                         -1 );
1868                 }
1869             }
1870             else
1871             {
1872                 aRet[ n ] <<= beans::IllegalTypeException(
1873                     rtl::OUString::createFromAscii(
1874                         "Property value has wrong type!" ),
1875                     static_cast< cppu::OWeakObject * >( this ) );
1876             }
1877         }
1878         else
1879         {
1880             //////////////////////////////////////////////////////////////
1881             // Optional props.
1882             //////////////////////////////////////////////////////////////
1883 
1884             rtl::OUString aSpecialName;
1885             bool bIsSpecial = DAVProperties::isUCBSpecialProperty( rName, aSpecialName );
1886 
1887             if ( !xInfo.is() )
1888                 xInfo = getPropertySetInfo( xEnv,
1889                                             sal_False /* don't cache data */ );
1890 
1891             if ( !xInfo->hasPropertyByName( bIsSpecial ? aSpecialName : rName ) )
1892             {
1893                 // Check, whether property exists. Skip otherwise.
1894                 // PROPPATCH::set would add the property automatically, which
1895                 // is not allowed for "setPropertyValues" command!
1896                 aRet[ n ] <<= beans::UnknownPropertyException(
1897                                 rtl::OUString::createFromAscii(
1898                                     "Property is unknown!" ),
1899                                 static_cast< cppu::OWeakObject * >( this ) );
1900                 continue;
1901             }
1902 
1903             if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) )
1904             {
1905                 // Read-only property!
1906                 aRet[ n ] <<= lang::IllegalAccessException(
1907                                 rtl::OUString::createFromAscii(
1908                                     "Property is read-only!" ),
1909                                 static_cast< cppu::OWeakObject * >( this ) );
1910             }
1911             else if ( rName.equalsAsciiL(
1912                         RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) )
1913             {
1914                 // Read-only property!
1915                 aRet[ n ] <<= lang::IllegalAccessException(
1916                                 rtl::OUString::createFromAscii(
1917                                     "Property is read-only!" ),
1918                                 static_cast< cppu::OWeakObject * >( this ) );
1919             }
1920             else if ( rName.equalsAsciiL(
1921                         RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) )
1922             {
1923                 // Read-only property!
1924                 aRet[ n ] <<= lang::IllegalAccessException(
1925                                 rtl::OUString::createFromAscii(
1926                                     "Property is read-only!" ),
1927                                 static_cast< cppu::OWeakObject * >( this ) );
1928             }
1929             else if ( rName.equalsAsciiL(
1930                         RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) )
1931             {
1932                 // Read-only property!
1933                 // (but could be writable, if 'getcontenttype' would be)
1934                 aRet[ n ] <<= lang::IllegalAccessException(
1935                                 rtl::OUString::createFromAscii(
1936                                     "Property is read-only!" ),
1937                                 static_cast< cppu::OWeakObject * >( this ) );
1938             }
1939             if ( rName.equalsAsciiL(
1940                     RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
1941             {
1942                 // Read-only property!
1943                 aRet[ n ] <<= lang::IllegalAccessException(
1944                                 rtl::OUString::createFromAscii(
1945                                     "Property is read-only!" ),
1946                                 static_cast< cppu::OWeakObject * >( this ) );
1947             }
1948             else
1949             {
1950                 if ( getResourceType( xEnv, xResAccess ) == DAV )
1951                 {
1952                     // Property value will be set on server.
1953                     ProppatchValue aValue( PROPSET, rName, rValue.Value );
1954                     aProppatchValues.push_back( aValue );
1955 
1956                     // remember position within sequence of values (for
1957                     // error handling).
1958                     aProppatchPropsPositions.push_back( n );
1959                 }
1960                 else
1961                 {
1962                     // Property value will be stored in local property store.
1963                     if ( !bTriedToGetAdditonalPropSet &&
1964                          !xAdditionalPropSet.is() )
1965                     {
1966                         xAdditionalPropSet
1967                             = getAdditionalPropertySet( sal_False );
1968                         bTriedToGetAdditonalPropSet = sal_True;
1969                     }
1970 
1971                     if ( xAdditionalPropSet.is() )
1972                     {
1973                         try
1974                         {
1975                             uno::Any aOldValue
1976                                 = xAdditionalPropSet->getPropertyValue( rName );
1977                             if ( aOldValue != rValue.Value )
1978                             {
1979                                 xAdditionalPropSet->setPropertyValue(
1980                                                         rName, rValue.Value );
1981 
1982                                 aEvent.PropertyName = rName;
1983                                 aEvent.OldValue     = aOldValue;
1984                                 aEvent.NewValue     = rValue.Value;
1985 
1986                                 aChanges.getArray()[ nChanged ] = aEvent;
1987                                 nChanged++;
1988                             }
1989                         }
1990                         catch ( beans::UnknownPropertyException const & e )
1991                         {
1992                             aRet[ n ] <<= e;
1993                         }
1994                         catch ( lang::WrappedTargetException const & e )
1995                         {
1996                             aRet[ n ] <<= e;
1997                         }
1998                         catch ( beans::PropertyVetoException const & e )
1999                         {
2000                             aRet[ n ] <<= e;
2001                         }
2002                         catch ( lang::IllegalArgumentException const & e )
2003                         {
2004                             aRet[ n ] <<= e;
2005                         }
2006                     }
2007                     else
2008                     {
2009                         aRet[ n ] <<= uno::Exception(
2010                                 rtl::OUString::createFromAscii(
2011                                     "No property set for storing the value!" ),
2012                                 static_cast< cppu::OWeakObject * >( this ) );
2013                     }
2014                 }
2015             }
2016         }
2017     } // for
2018 
2019     if ( !bTransient && aProppatchValues.size() )
2020     {
2021         try
2022         {
2023             // Set property values at server.
2024             xResAccess->PROPPATCH( aProppatchValues, xEnv );
2025 
2026             std::vector< ProppatchValue >::const_iterator it
2027                 = aProppatchValues.begin();
2028             std::vector< ProppatchValue >::const_iterator end
2029                 = aProppatchValues.end();
2030 
2031             while ( it != end )
2032             {
2033                 aEvent.PropertyName = (*it).name;
2034                 aEvent.OldValue     = uno::Any(); // @@@ to expensive to obtain!
2035                 aEvent.NewValue     = (*it).value;
2036 
2037                 aChanges.getArray()[ nChanged ] = aEvent;
2038                 nChanged++;
2039 
2040                 ++it;
2041             }
2042         }
2043         catch ( DAVException const & e )
2044         {
2045 //            OSL_ENSURE( sal_False,
2046 //                        "Content::setPropertyValues - PROPPATCH failed!" );
2047 
2048 #if 1
2049             cancelCommandExecution( e, xEnv );
2050             // unreachable
2051 #else
2052             // Note: PROPPATCH either sets ALL property values OR NOTHING.
2053 
2054             std::vector< sal_Int32 >::const_iterator it
2055                 = aProppatchPropsPositions.begin();
2056             std::vector< sal_Int32 >::const_iterator end
2057                 = aProppatchPropsPositions.end();
2058 
2059             while ( it != end )
2060             {
2061                 // Set error.
2062                 aRet[ (*it) ] <<= MapDAVException( e, sal_True );
2063                 ++it;
2064             }
2065 #endif
2066         }
2067     }
2068 
2069     if ( bExchange )
2070     {
2071         // Assemble new content identifier...
2072 
2073         rtl::OUString aNewURL = getParentURL();
2074         if ( aNewURL.lastIndexOf( '/' ) != ( aNewURL.getLength() - 1 ) )
2075             aNewURL += rtl::OUString::createFromAscii( "/" );
2076 
2077         aNewURL += SerfUri::escapeSegment( aNewTitle );
2078 
2079         uno::Reference< ucb::XContentIdentifier > xNewId
2080             = new ::ucbhelper::ContentIdentifier( xSMgr, aNewURL );
2081         uno::Reference< ucb::XContentIdentifier > xOldId = xIdentifier;
2082 
2083         try
2084         {
2085             SerfUri sourceURI( xOldId->getContentIdentifier() );
2086             SerfUri targetURI( xNewId->getContentIdentifier() );
2087             targetURI.SetScheme( sourceURI.GetScheme() );
2088 
2089             xResAccess->MOVE(
2090                 sourceURI.GetPath(), targetURI.GetURI(), sal_False, xEnv );
2091             // @@@ Should check for resources that could not be moved
2092             //     (due to source access or target overwrite) and send
2093             //     this information through the interaction handler.
2094 
2095             // @@@ Existing content should be checked to see if it needs
2096             //     to be deleted at the source
2097 
2098             // @@@ Existing content should be checked to see if it has
2099             //     been overwritten at the target
2100 
2101             if ( exchangeIdentity( xNewId ) )
2102             {
2103                 xResAccess->setURL( aNewURL );
2104 
2105 // DAV resources store all additional props on server!
2106 //              // Adapt Additional Core Properties.
2107 //              renameAdditionalPropertySet( xOldId->getContentIdentifier(),
2108 //                                           xNewId->getContentIdentifier(),
2109 //                                           sal_True );
2110             }
2111             else
2112             {
2113                 // Do not set new title!
2114                 aNewTitle = rtl::OUString();
2115 
2116                 // Set error .
2117                 aRet[ nTitlePos ] <<= uno::Exception(
2118                     rtl::OUString::createFromAscii( "Exchange failed!" ),
2119                     static_cast< cppu::OWeakObject * >( this ) );
2120             }
2121         }
2122         catch ( DAVException const & e )
2123         {
2124             // Do not set new title!
2125             aNewTitle = rtl::OUString();
2126 
2127             // Set error .
2128             aRet[ nTitlePos ] <<= MapDAVException( e, sal_True );
2129         }
2130     }
2131 
2132     if ( aNewTitle.getLength() )
2133     {
2134         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2135 
2136         aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" );
2137         aEvent.OldValue     = uno::makeAny( aOldTitle );
2138         aEvent.NewValue     = uno::makeAny( aNewTitle );
2139 
2140         m_aEscapedTitle     = SerfUri::escapeSegment( aNewTitle );
2141 
2142         aChanges.getArray()[ nChanged ] = aEvent;
2143         nChanged++;
2144     }
2145 
2146     if ( nChanged > 0 )
2147     {
2148         aChanges.realloc( nChanged );
2149         notifyPropertiesChange( aChanges );
2150     }
2151 
2152     {
2153         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2154         m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2155     }
2156 
2157     return aRet;
2158 }
2159 
2160 //=========================================================================
2161 uno::Any Content::open(
2162                 const ucb::OpenCommandArgument2 & rArg,
2163                 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2164     throw( uno::Exception )
2165 {
2166     uno::Any aRet;
2167 
2168     sal_Bool bOpenFolder = ( ( rArg.Mode == ucb::OpenMode::ALL ) ||
2169                              ( rArg.Mode == ucb::OpenMode::FOLDERS ) ||
2170                              ( rArg.Mode == ucb::OpenMode::DOCUMENTS ) );
2171     if ( bOpenFolder )
2172     {
2173         if ( isFolder( xEnv ) )
2174         {
2175             // Open collection.
2176 
2177             uno::Reference< ucb::XDynamicResultSet > xSet
2178                 = new DynamicResultSet( m_xSMgr, this, rArg, xEnv );
2179             aRet <<= xSet;
2180         }
2181         else
2182         {
2183             // Error: Not a folder!
2184 
2185             rtl::OUStringBuffer aMsg;
2186             aMsg.appendAscii( "Non-folder resource cannot be "
2187                               "opened as folder! Wrong Open Mode!" );
2188 
2189             ucbhelper::cancelCommandExecution(
2190                 uno::makeAny(
2191                     lang::IllegalArgumentException(
2192                         aMsg.makeStringAndClear(),
2193                         static_cast< cppu::OWeakObject * >( this ),
2194                         -1 ) ),
2195                 xEnv );
2196             // Unreachable
2197         }
2198     }
2199 
2200     if ( rArg.Sink.is() )
2201     {
2202         // Open document.
2203 
2204         if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
2205              ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
2206         {
2207             // Currently(?) unsupported.
2208             ucbhelper::cancelCommandExecution(
2209                 uno::makeAny(
2210                     ucb::UnsupportedOpenModeException(
2211                             rtl::OUString(),
2212                             static_cast< cppu::OWeakObject * >( this ),
2213                             sal_Int16( rArg.Mode ) ) ),
2214                 xEnv );
2215             // Unreachable
2216         }
2217 
2218         rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
2219         uno::Reference< io::XOutputStream > xOut
2220             = uno::Reference< io::XOutputStream >( rArg.Sink, uno::UNO_QUERY );
2221         if ( xOut.is() )
2222         {
2223             // PUSH: write data
2224             try
2225             {
2226                 std::auto_ptr< DAVResourceAccess > xResAccess;
2227 
2228                 {
2229                     osl::MutexGuard aGuard( m_aMutex );
2230 
2231                     xResAccess.reset(
2232                         new DAVResourceAccess( *m_xResAccess.get() ) );
2233                 }
2234 
2235                 DAVResource aResource;
2236                 std::vector< rtl::OUString > aHeaders;
2237 
2238                 xResAccess->GET( xOut, aHeaders, aResource, xEnv );
2239                 m_bDidGetOrHead = true;
2240 
2241                 {
2242                     osl::MutexGuard aGuard( m_aMutex );
2243 
2244                     // cache headers.
2245                     if ( !m_xCachedProps.get())
2246                         m_xCachedProps.reset(
2247                             new CachableContentProperties( aResource ) );
2248                     else
2249                         m_xCachedProps->addProperties( aResource );
2250 
2251                     m_xResAccess.reset(
2252                         new DAVResourceAccess( *xResAccess.get() ) );
2253                 }
2254             }
2255             catch ( DAVException const & e )
2256             {
2257                 cancelCommandExecution( e, xEnv );
2258                 // Unreachable
2259             }
2260         }
2261         else
2262         {
2263             uno::Reference< io::XActiveDataSink > xDataSink
2264                 = uno::Reference< io::XActiveDataSink >( rArg.Sink,
2265                                                          uno::UNO_QUERY );
2266             if ( xDataSink.is() )
2267             {
2268                 // PULL: wait for client read
2269                 try
2270                 {
2271                     std::auto_ptr< DAVResourceAccess > xResAccess;
2272                     {
2273                         osl::MutexGuard aGuard( m_aMutex );
2274 
2275                         xResAccess.reset(
2276                             new DAVResourceAccess( *m_xResAccess.get() ) );
2277                     }
2278 
2279                     // fill inputsream sync; return if all data present
2280                     DAVResource aResource;
2281                     std::vector< rtl::OUString > aHeaders;
2282 
2283                     uno::Reference< io::XInputStream > xIn
2284                         = xResAccess->GET( aHeaders, aResource, xEnv );
2285                     m_bDidGetOrHead = true;
2286 
2287                     {
2288                         osl::MutexGuard aGuard( m_aMutex );
2289 
2290                         // cache headers.
2291                         if ( !m_xCachedProps.get())
2292                             m_xCachedProps.reset(
2293                                 new CachableContentProperties( aResource ) );
2294                         else
2295                             m_xCachedProps->addProperties(
2296                                 aResource.properties );
2297 
2298                         m_xResAccess.reset(
2299                             new DAVResourceAccess( *xResAccess.get() ) );
2300                     }
2301 
2302                     xDataSink->setInputStream( xIn );
2303                 }
2304                 catch ( DAVException const & e )
2305                 {
2306                     cancelCommandExecution( e, xEnv );
2307                     // Unreachable
2308                 }
2309             }
2310             else
2311             {
2312                 // Note: aOpenCommand.Sink may contain an XStream
2313                 //       implementation. Support for this type of
2314                 //       sink is optional...
2315                 ucbhelper::cancelCommandExecution(
2316                     uno::makeAny(
2317                         ucb::UnsupportedDataSinkException(
2318                             rtl::OUString(),
2319                             static_cast< cppu::OWeakObject * >( this ),
2320                             rArg.Sink ) ),
2321                     xEnv );
2322                 // Unreachable
2323             }
2324         }
2325     }
2326 
2327     return aRet;
2328 }
2329 
2330 //=========================================================================
2331 void Content::post(
2332                 const ucb::PostCommandArgument2 & rArg,
2333                 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2334     throw( uno::Exception )
2335 {
2336     uno::Reference< io::XActiveDataSink > xSink( rArg.Sink, uno::UNO_QUERY );
2337     if ( xSink.is() )
2338     {
2339         try
2340         {
2341             std::auto_ptr< DAVResourceAccess > xResAccess;
2342             {
2343                 osl::MutexGuard aGuard( m_aMutex );
2344                 xResAccess.reset(
2345                     new DAVResourceAccess( *m_xResAccess.get() ) );
2346             }
2347 
2348             uno::Reference< io::XInputStream > xResult
2349                 = xResAccess->POST( rArg.MediaType,
2350                                     rArg.Referer,
2351                                     rArg.Source,
2352                                     xEnv );
2353 
2354             {
2355                  osl::MutexGuard aGuard( m_aMutex );
2356                  m_xResAccess.reset(
2357                      new DAVResourceAccess( *xResAccess.get() ) );
2358             }
2359 
2360             xSink->setInputStream( xResult );
2361         }
2362         catch ( DAVException const & e )
2363         {
2364             cancelCommandExecution( e, xEnv, sal_True );
2365             // Unreachable
2366         }
2367     }
2368     else
2369     {
2370         uno::Reference< io::XOutputStream > xResult( rArg.Sink, uno::UNO_QUERY );
2371         if ( xResult.is() )
2372         {
2373             try
2374             {
2375                 std::auto_ptr< DAVResourceAccess > xResAccess;
2376                 {
2377                     osl::MutexGuard aGuard( m_aMutex );
2378                     xResAccess.reset(
2379                         new DAVResourceAccess( *m_xResAccess.get() ) );
2380                 }
2381 
2382                 xResAccess->POST( rArg.MediaType,
2383                                   rArg.Referer,
2384                                   rArg.Source,
2385                                   xResult,
2386                                   xEnv );
2387 
2388                 {
2389                     osl::MutexGuard aGuard( m_aMutex );
2390                     m_xResAccess.reset(
2391                         new DAVResourceAccess( *xResAccess.get() ) );
2392                 }
2393             }
2394             catch ( DAVException const & e )
2395             {
2396                 cancelCommandExecution( e, xEnv, sal_True );
2397                 // Unreachable
2398             }
2399         }
2400         else
2401         {
2402             ucbhelper::cancelCommandExecution(
2403                 uno::makeAny(
2404                     ucb::UnsupportedDataSinkException(
2405                         rtl::OUString(),
2406                         static_cast< cppu::OWeakObject * >( this ),
2407                         rArg.Sink ) ),
2408                 xEnv );
2409             // Unreachable
2410         }
2411     }
2412 }
2413 
2414 //=========================================================================
2415 void Content::queryChildren( ContentRefList& rChildren )
2416 {
2417     // Obtain a list with a snapshot of all currently instanciated contents
2418     // from provider and extract the contents which are direct children
2419     // of this content.
2420 
2421     ::ucbhelper::ContentRefList aAllContents;
2422     m_xProvider->queryExistingContents( aAllContents );
2423 
2424     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
2425     sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
2426 
2427     if ( nURLPos != ( aURL.getLength() - 1 ) )
2428     {
2429         // No trailing slash found. Append.
2430         aURL += rtl::OUString::createFromAscii( "/" );
2431     }
2432 
2433     sal_Int32 nLen = aURL.getLength();
2434 
2435     ::ucbhelper::ContentRefList::const_iterator it  = aAllContents.begin();
2436     ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
2437 
2438     while ( it != end )
2439     {
2440         ::ucbhelper::ContentImplHelperRef xChild = (*it);
2441         rtl::OUString aChildURL
2442             = xChild->getIdentifier()->getContentIdentifier();
2443 
2444         // Is aURL a prefix of aChildURL?
2445         if ( ( aChildURL.getLength() > nLen ) &&
2446              ( aChildURL.compareTo( aURL, nLen ) == 0 ) )
2447         {
2448             sal_Int32 nPos = nLen;
2449             nPos = aChildURL.indexOf( '/', nPos );
2450 
2451             if ( ( nPos == -1 ) ||
2452                  ( nPos == ( aChildURL.getLength() - 1 ) ) )
2453             {
2454                 // No further slashes / only a final slash. It's a child!
2455                 rChildren.push_back(
2456                     ::http_dav_ucp::Content::ContentRef(
2457                         static_cast< ::http_dav_ucp::Content * >(
2458                             xChild.get() ) ) );
2459             }
2460         }
2461         ++it;
2462     }
2463 }
2464 
2465 //=========================================================================
2466 void Content::insert(
2467         const uno::Reference< io::XInputStream > & xInputStream,
2468         sal_Bool bReplaceExisting,
2469         const uno::Reference< ucb::XCommandEnvironment >& Environment )
2470     throw( uno::Exception )
2471 {
2472     sal_Bool bTransient, bCollection;
2473     rtl::OUString aEscapedTitle;
2474     std::auto_ptr< DAVResourceAccess > xResAccess;
2475 
2476     {
2477         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2478 
2479         bTransient    = m_bTransient;
2480         bCollection   = m_bCollection;
2481         aEscapedTitle = m_aEscapedTitle;
2482         xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
2483     }
2484 
2485     // Check, if all required properties are present.
2486 
2487     if ( aEscapedTitle.getLength() == 0 )
2488     {
2489         OSL_ENSURE( sal_False, "Content::insert - Title missing!" );
2490 
2491         uno::Sequence< rtl::OUString > aProps( 1 );
2492         aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" );
2493         ucbhelper::cancelCommandExecution(
2494             uno::makeAny( ucb::MissingPropertiesException(
2495                                 rtl::OUString(),
2496                                 static_cast< cppu::OWeakObject * >( this ),
2497                                 aProps ) ),
2498             Environment );
2499         // Unreachable
2500     }
2501 
2502     if ( !bReplaceExisting )
2503     {
2504         /* [RFC 2616] - HTTP
2505 
2506            The PUT method requests that the enclosed entity be stored under the
2507            supplied Request-URI. If the Request-URI refers to an already
2508            existing resource, the enclosed entity SHOULD be considered as a
2509            modified version of the one residing on the origin server.
2510         */
2511 
2512         /* [RFC 2518] - WebDAV
2513 
2514            MKCOL creates a new collection resource at the location specified by
2515            the Request-URI.  If the resource identified by the Request-URI is
2516            non-null then the MKCOL MUST fail.
2517         */
2518 
2519         // ==> Complain on PUT, continue on MKCOL.
2520         if ( !bTransient || ( bTransient && !bCollection  ) )
2521         {
2522 #undef ERROR
2523             ucb::UnsupportedNameClashException aEx(
2524                 rtl::OUString::createFromAscii( "Unable to write without overwrite!" ),
2525                 static_cast< cppu::OWeakObject * >( this ),
2526                 ucb::NameClash::ERROR );
2527 
2528             uno::Reference< task::XInteractionHandler > xIH;
2529 
2530             if ( Environment.is() )
2531                 xIH = Environment->getInteractionHandler();
2532 
2533             if ( xIH.is() )
2534             {
2535                 uno::Any aExAsAny( uno::makeAny( aEx ) );
2536 
2537                 rtl::Reference< ucbhelper::SimpleInteractionRequest > xRequest
2538                     = new ucbhelper::SimpleInteractionRequest(
2539                         aExAsAny,
2540                         ucbhelper::CONTINUATION_APPROVE
2541                             | ucbhelper::CONTINUATION_DISAPPROVE );
2542                 xIH->handle( xRequest.get() );
2543 
2544                 const sal_Int32 nResp = xRequest->getResponse();
2545 
2546                 switch ( nResp )
2547                 {
2548                     case ucbhelper::CONTINUATION_UNKNOWN:
2549                         // Not handled; throw.
2550                         throw aEx;
2551 //                            break;
2552 
2553                     case ucbhelper::CONTINUATION_APPROVE:
2554                         // Continue -> Overwrite.
2555                         bReplaceExisting = sal_True;
2556                         break;
2557 
2558                     case ucbhelper::CONTINUATION_DISAPPROVE:
2559                         // Abort.
2560                         throw ucb::CommandFailedException(
2561                                     rtl::OUString(),
2562                                     uno::Reference< uno::XInterface >(),
2563                                     aExAsAny );
2564 //                            break;
2565 
2566                     default:
2567                         OSL_ENSURE( sal_False,
2568                                     "Content::insert - "
2569                                     "Unknown interaction selection!" );
2570                         throw ucb::CommandFailedException(
2571                                     rtl::OUString::createFromAscii(
2572                                         "Unknown interaction selection!" ),
2573                                     uno::Reference< uno::XInterface >(),
2574                                     aExAsAny );
2575 //                            break;
2576                 }
2577             }
2578             else
2579             {
2580                 // No IH; throw.
2581                 throw aEx;
2582             }
2583         }
2584     }
2585 
2586     if ( bTransient )
2587     {
2588         // Assemble new content identifier...
2589         rtl::OUString aURL = getParentURL();
2590         if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) )
2591             aURL += rtl::OUString::createFromAscii( "/" );
2592 
2593         aURL += aEscapedTitle;
2594 
2595         try
2596         {
2597             xResAccess->setURL( aURL );
2598 
2599             if ( bCollection )
2600                 xResAccess->MKCOL( Environment );
2601             else
2602                 xResAccess->PUT( xInputStream, Environment );
2603         }
2604         catch ( DAVException const & except )
2605         {
2606             if ( bCollection )
2607             {
2608                 if ( except.getStatus() == SC_METHOD_NOT_ALLOWED )
2609                 {
2610                     // [RFC 2518] - WebDAV
2611                     // 405 (Method Not Allowed) - MKCOL can only be
2612                     // executed on a deleted/non-existent resource.
2613 
2614                     if ( bReplaceExisting )
2615                     {
2616                         // Destroy old resource.
2617                         try
2618                         {
2619                             xResAccess->DESTROY( Environment );
2620                         }
2621                         catch ( DAVException const & e )
2622                         {
2623                             cancelCommandExecution( e, Environment, sal_True );
2624                             // Unreachable
2625                         }
2626 
2627                         // Insert (recursion!).
2628                         insert( xInputStream, bReplaceExisting, Environment );
2629 
2630                         {
2631                             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2632                             m_xResAccess.reset(
2633                                 new DAVResourceAccess( *xResAccess.get() ) );
2634                         }
2635 
2636                         // Success!
2637                         return;
2638                     }
2639                     else
2640                     {
2641                         rtl::OUString aTitle;
2642                         try
2643                         {
2644                             SerfUri aURI( aURL );
2645                             aTitle = aURI.GetPathBaseNameUnescaped();
2646                         }
2647                         catch ( DAVException const & )
2648                         {
2649                         }
2650 
2651                         ucbhelper::cancelCommandExecution(
2652                             uno::makeAny(
2653                                 ucb::NameClashException(
2654                                     rtl::OUString(),
2655                                     static_cast< cppu::OWeakObject * >( this ),
2656                                     task::InteractionClassification_ERROR,
2657                                     aTitle ) ),
2658                             Environment );
2659                         // Unreachable
2660                     }
2661                 }
2662             }
2663 
2664             cancelCommandExecution( except, Environment, sal_True );
2665             // Unreachable
2666         }
2667 
2668         {
2669             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2670             m_xIdentifier
2671                 = new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL );
2672         }
2673 
2674         inserted();
2675 
2676         {
2677             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2678             m_bTransient = sal_False;
2679         }
2680     }
2681     else
2682     {
2683         if ( !xInputStream.is() )
2684         {
2685             ucbhelper::cancelCommandExecution(
2686                 uno::makeAny(
2687                     ucb::MissingInputStreamException(
2688                         rtl::OUString(),
2689                         static_cast< cppu::OWeakObject * >( this ) ) ),
2690                 Environment );
2691             // Unreachable
2692         }
2693 
2694         try
2695         {
2696             xResAccess->PUT( xInputStream, Environment );
2697         }
2698         catch ( DAVException const & e )
2699         {
2700             cancelCommandExecution( e, Environment, sal_True );
2701             // Unreachable
2702         }
2703     }
2704 
2705     {
2706         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2707         m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2708     }
2709 }
2710 
2711 //=========================================================================
2712 void Content::transfer(
2713         const ucb::TransferInfo & rArgs,
2714         const uno::Reference< ucb::XCommandEnvironment >& Environment )
2715     throw( uno::Exception )
2716 {
2717     uno::Reference< lang::XMultiServiceFactory > xSMgr;
2718     uno::Reference< ucb::XContentIdentifier >    xIdentifier;
2719     uno::Reference< ucb::XContentProvider >      xProvider;
2720     std::auto_ptr< DAVResourceAccess > xResAccess;
2721 
2722     {
2723         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2724 
2725         xSMgr.set( m_xSMgr );
2726         xIdentifier.set( m_xIdentifier );
2727         xProvider.set( m_xProvider.get() );
2728         xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
2729     }
2730 
2731     rtl::OUString aTargetURI;
2732     try
2733     {
2734         SerfUri sourceURI( rArgs.SourceURL );
2735         SerfUri targetURI( xIdentifier->getContentIdentifier() );
2736         aTargetURI = targetURI.GetPathBaseNameUnescaped();
2737 
2738         // Check source's and target's URL scheme
2739         //
2740         const rtl::OUString aScheme = sourceURI.GetScheme().toAsciiLowerCase();
2741         if ( aScheme.equalsAsciiL(
2742                 RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) )
2743         {
2744             sourceURI.SetScheme(
2745                 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2746         }
2747         else if ( aScheme.equalsAsciiL(
2748                 RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) )
2749         {
2750             sourceURI.SetScheme(
2751                 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2752         }
2753         else if ( aScheme.equalsAsciiL(
2754                 RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) )
2755         {
2756             sourceURI.SetScheme(
2757                 rtl::OUString::createFromAscii( HTTPS_URL_SCHEME ) );
2758         }
2759         else
2760         {
2761             if ( !aScheme.equalsAsciiL(
2762                     RTL_CONSTASCII_STRINGPARAM( HTTP_URL_SCHEME ) ) &&
2763                  !aScheme.equalsAsciiL(
2764                     RTL_CONSTASCII_STRINGPARAM( HTTPS_URL_SCHEME ) ) )
2765             {
2766                 ucbhelper::cancelCommandExecution(
2767                     uno::makeAny(
2768                         ucb::InteractiveBadTransferURLException(
2769                             rtl::OUString::createFromAscii(
2770                                 "Unsupported URL scheme!" ),
2771                             static_cast< cppu::OWeakObject * >( this ) ) ),
2772                     Environment );
2773                 // Unreachable
2774             }
2775         }
2776 
2777         if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
2778                  RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) )
2779             targetURI.SetScheme(
2780                 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2781         else if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
2782                  RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) )
2783             targetURI.SetScheme(
2784                 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2785 
2786         // @@@ This implementation of 'transfer' only works
2787         //     if the source and target are located at same host.
2788         //     (Neon does not support cross-server copy/move)
2789 
2790         // Check for same host
2791         //
2792         if ( sourceURI.GetHost().getLength() &&
2793              ( sourceURI.GetHost() != targetURI.GetHost() ) )
2794         {
2795             ucbhelper::cancelCommandExecution(
2796                 uno::makeAny( ucb::InteractiveBadTransferURLException(
2797                                 rtl::OUString::createFromAscii(
2798                                     "Different hosts!" ),
2799                                 static_cast< cppu::OWeakObject * >( this ) ) ),
2800                 Environment );
2801             // Unreachable
2802         }
2803 
2804         rtl::OUString aTitle = rArgs.NewTitle;
2805 
2806         if ( !aTitle.getLength() )
2807             aTitle = sourceURI.GetPathBaseNameUnescaped();
2808 
2809         if ( aTitle.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "/" ) ) )
2810         {
2811             // kso: ???
2812             aTitle = rtl::OUString();
2813         }
2814 
2815         targetURI.AppendPath( aTitle );
2816 
2817         rtl::OUString aTargetURL = xIdentifier->getContentIdentifier();
2818         if ( ( aTargetURL.lastIndexOf( '/' ) + 1 )
2819                 != aTargetURL.getLength() )
2820             aTargetURL += rtl::OUString::createFromAscii( "/" );
2821 
2822         aTargetURL += aTitle;
2823 
2824         uno::Reference< ucb::XContentIdentifier > xTargetId
2825             = new ::ucbhelper::ContentIdentifier( xSMgr, aTargetURL );
2826 
2827         DAVResourceAccess aSourceAccess( xSMgr,
2828                                          xResAccess->getSessionFactory(),
2829                                          sourceURI.GetURI() );
2830 
2831         if ( rArgs.MoveData == sal_True )
2832         {
2833             uno::Reference< ucb::XContentIdentifier > xId
2834                 = new ::ucbhelper::ContentIdentifier( xSMgr, rArgs.SourceURL );
2835 
2836             // Note: The static cast is okay here, because its sure that
2837             //       xProvider is always the WebDAVContentProvider.
2838             rtl::Reference< Content > xSource
2839                 = static_cast< Content * >(
2840                     xProvider->queryContent( xId ).get() );
2841 
2842             // [RFC 2518] - WebDAV
2843             // If a resource exists at the destination and the Overwrite
2844             // header is "T" then prior to performing the move the server
2845             // MUST perform a DELETE with "Depth: infinity" on the
2846             // destination resource.  If the Overwrite header is set to
2847             // "F" then the operation will fail.
2848 
2849             aSourceAccess.MOVE( sourceURI.GetPath(),
2850                                 targetURI.GetURI(),
2851                                 rArgs.NameClash
2852                                     == ucb::NameClash::OVERWRITE,
2853                                 Environment );
2854 
2855             if ( xSource.is() )
2856             {
2857                 // Propagate destruction to listeners.
2858                 xSource->destroy( sal_True );
2859             }
2860 
2861 // DAV resources store all additional props on server!
2862 //              // Rename own and all children's Additional Core Properties.
2863 //              renameAdditionalPropertySet( xId->getContentIdentifier(),
2864 //                                           xTargetId->getContentIdentifier(),
2865 //                                           sal_True );
2866         }
2867         else
2868         {
2869             // [RFC 2518] - WebDAV
2870             // If a resource exists at the destination and the Overwrite
2871             // header is "T" then prior to performing the copy the server
2872             // MUST perform a DELETE with "Depth: infinity" on the
2873             // destination resource.  If the Overwrite header is set to
2874             // "F" then the operation will fail.
2875 
2876             aSourceAccess.COPY( sourceURI.GetPath(),
2877                                 targetURI.GetURI(),
2878                                 rArgs.NameClash
2879                                     == ucb::NameClash::OVERWRITE,
2880                                 Environment );
2881 
2882 // DAV resources store all additional props on server!
2883 //              // Copy own and all children's Additional Core Properties.
2884 //              copyAdditionalPropertySet( xId->getContentIdentifier(),
2885 //                                         xTargetId->getContentIdentifier(),
2886 //                                         sal_True );
2887         }
2888 
2889         // Note: The static cast is okay here, because its sure that
2890         //       xProvider is always the WebDAVContentProvider.
2891         rtl::Reference< Content > xTarget
2892             = static_cast< Content * >(
2893                     xProvider->queryContent( xTargetId ).get() );
2894 
2895         // Announce transferred content in its new folder.
2896         xTarget->inserted();
2897     }
2898     catch ( ucb::IllegalIdentifierException const & )
2899     {
2900         // queryContent
2901     }
2902     catch ( DAVException const & e )
2903     {
2904         // [RFC 2518] - WebDAV
2905         // 412 (Precondition Failed) - The server was unable to maintain
2906         // the liveness of the properties listed in the propertybehavior
2907         // XML element or the Overwrite header is "F" and the state of
2908         // the destination resource is non-null.
2909 
2910         if ( e.getStatus() == SC_PRECONDITION_FAILED )
2911         {
2912             switch ( rArgs.NameClash )
2913             {
2914                 case 0/*ucb::NameClash::ERROR*/:
2915                 {
2916                     ucbhelper::cancelCommandExecution(
2917                         uno::makeAny(
2918                             ucb::NameClashException(
2919                                 rtl::OUString(),
2920                                 static_cast< cppu::OWeakObject * >( this ),
2921                                 task::InteractionClassification_ERROR,
2922                                 aTargetURI ) ),
2923                         Environment );
2924                     // Unreachable
2925                 }
2926 
2927                 case ucb::NameClash::OVERWRITE:
2928                     break;
2929 
2930                 case ucb::NameClash::KEEP: // deprecated
2931                 case ucb::NameClash::RENAME:
2932                 case ucb::NameClash::ASK:
2933                 default:
2934                 {
2935                     ucbhelper::cancelCommandExecution(
2936                         uno::makeAny(
2937                             ucb::UnsupportedNameClashException(
2938                                 rtl::OUString(),
2939                                 static_cast< cppu::OWeakObject * >( this ),
2940                                 rArgs.NameClash ) ),
2941                         Environment );
2942                     // Unreachable
2943                 }
2944             }
2945         }
2946 
2947         cancelCommandExecution( e, Environment, sal_True );
2948         // Unreachable
2949     }
2950 
2951     {
2952         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2953         m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2954     }
2955 }
2956 
2957 //=========================================================================
2958 void Content::destroy( sal_Bool bDeletePhysical )
2959     throw( uno::Exception )
2960 {
2961     // @@@ take care about bDeletePhysical -> trashcan support
2962     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
2963 
2964     uno::Reference< ucb::XContent > xThis = this;
2965 
2966     deleted();
2967 
2968     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2969 
2970     // Process instanciated children...
2971 
2972     ::http_dav_ucp::Content::ContentRefList aChildren;
2973     queryChildren( aChildren );
2974 
2975     ContentRefList::const_iterator it  = aChildren.begin();
2976     ContentRefList::const_iterator end = aChildren.end();
2977 
2978     while ( it != end )
2979     {
2980         (*it)->destroy( bDeletePhysical );
2981         ++it;
2982     }
2983 }
2984 
2985 //=========================================================================
2986 bool Content::supportsExclusiveWriteLock(
2987   const uno::Reference< ucb::XCommandEnvironment >& Environment )
2988 {
2989     if ( getResourceType( Environment ) == DAV )
2990     {
2991         if ( m_xCachedProps.get() )
2992         {
2993             uno::Sequence< ucb::LockEntry > aSupportedLocks;
2994             if ( m_xCachedProps->getValue( DAVProperties::SUPPORTEDLOCK )
2995                 >>= aSupportedLocks )
2996             {
2997                 for ( sal_Int32 n = 0; n < aSupportedLocks.getLength(); ++n )
2998                 {
2999                     if ( aSupportedLocks[ n ].Scope
3000                             == ucb::LockScope_EXCLUSIVE &&
3001                          aSupportedLocks[ n ].Type
3002                             == ucb::LockType_WRITE )
3003                         return true;
3004                 }
3005             }
3006         }
3007     }
3008     return false;
3009 }
3010 
3011 //=========================================================================
3012 void Content::lock(
3013         const uno::Reference< ucb::XCommandEnvironment >& Environment )
3014     throw( uno::Exception )
3015 {
3016     try
3017     {
3018         std::auto_ptr< DAVResourceAccess > xResAccess;
3019         {
3020             osl::Guard< osl::Mutex > aGuard( m_aMutex );
3021             xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
3022         }
3023 
3024         uno::Any aOwnerAny;
3025         aOwnerAny
3026             <<= rtl::OUString::createFromAscii( "http://ucb.openoffice.org" );
3027 
3028         ucb::Lock aLock(
3029             ucb::LockScope_EXCLUSIVE,
3030             ucb::LockType_WRITE,
3031             ucb::LockDepth_ZERO,
3032             aOwnerAny,
3033             180, // lock timeout in secs
3034             //-1, // infinite lock
3035             uno::Sequence< ::rtl::OUString >() );
3036 
3037         xResAccess->LOCK( aLock, Environment );
3038 
3039         {
3040             osl::Guard< osl::Mutex > aGuard( m_aMutex );
3041             m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
3042         }
3043     }
3044     catch ( DAVException const & e )
3045     {
3046         cancelCommandExecution( e, Environment, sal_False );
3047         // Unreachable
3048     }
3049 }
3050 
3051 //=========================================================================
3052 void Content::unlock(
3053         const uno::Reference< ucb::XCommandEnvironment >& Environment )
3054     throw( uno::Exception )
3055 {
3056     try
3057     {
3058         std::auto_ptr< DAVResourceAccess > xResAccess;
3059         {
3060             osl::Guard< osl::Mutex > aGuard( m_aMutex );
3061             xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
3062         }
3063 
3064         xResAccess->UNLOCK( Environment );
3065 
3066         {
3067             osl::Guard< osl::Mutex > aGuard( m_aMutex );
3068             m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
3069         }
3070     }
3071     catch ( DAVException const & e )
3072     {
3073         cancelCommandExecution( e, Environment, sal_False );
3074         // Unreachable
3075     }
3076 }
3077 
3078 //=========================================================================
3079 sal_Bool Content::exchangeIdentity(
3080     const uno::Reference< ucb::XContentIdentifier >& xNewId )
3081 {
3082     if ( !xNewId.is() )
3083         return sal_False;
3084 
3085     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
3086 
3087     uno::Reference< ucb::XContent > xThis = this;
3088 
3089     // Already persistent?
3090     if ( m_bTransient )
3091     {
3092         OSL_ENSURE( sal_False, "Content::exchangeIdentity - Not persistent!" );
3093         return sal_False;
3094     }
3095 
3096     // Exchange own identitity.
3097 
3098     // Fail, if a content with given id already exists.
3099 //  if ( !hasData( xNewId ) )
3100     {
3101         rtl::OUString aOldURL = m_xIdentifier->getContentIdentifier();
3102 
3103         aGuard.clear();
3104         if ( exchange( xNewId ) )
3105         {
3106             // Process instanciated children...
3107 
3108             ContentRefList aChildren;
3109             queryChildren( aChildren );
3110 
3111             ContentRefList::const_iterator it  = aChildren.begin();
3112             ContentRefList::const_iterator end = aChildren.end();
3113 
3114             while ( it != end )
3115             {
3116                 ContentRef xChild = (*it);
3117 
3118                 // Create new content identifier for the child...
3119                 uno::Reference< ucb::XContentIdentifier >
3120                     xOldChildId = xChild->getIdentifier();
3121                 rtl::OUString aOldChildURL
3122                     = xOldChildId->getContentIdentifier();
3123                 rtl::OUString aNewChildURL
3124                     = aOldChildURL.replaceAt(
3125                         0,
3126                         aOldURL.getLength(),
3127                         xNewId->getContentIdentifier() );
3128                 uno::Reference< ucb::XContentIdentifier > xNewChildId
3129                     = new ::ucbhelper::ContentIdentifier(
3130                         m_xSMgr, aNewChildURL );
3131 
3132                 if ( !xChild->exchangeIdentity( xNewChildId ) )
3133                     return sal_False;
3134 
3135                 ++it;
3136             }
3137             return sal_True;
3138         }
3139     }
3140 
3141     OSL_ENSURE( sal_False,
3142                 "Content::exchangeIdentity - "
3143                 "Panic! Cannot exchange identity!" );
3144     return sal_False;
3145 }
3146 
3147 //=========================================================================
3148 sal_Bool Content::isFolder(
3149             const uno::Reference< ucb::XCommandEnvironment >& xEnv )
3150     throw( uno::Exception )
3151 {
3152     {
3153         osl::MutexGuard aGuard( m_aMutex );
3154 
3155         if ( m_bTransient )
3156             return m_bCollection;
3157     }
3158 
3159     uno::Sequence< beans::Property > aProperties( 1 );
3160     aProperties[ 0 ].Name   = rtl::OUString::createFromAscii( "IsFolder" );
3161     aProperties[ 0 ].Handle = -1;
3162     uno::Reference< sdbc::XRow > xRow( getPropertyValues( aProperties, xEnv ) );
3163     if ( xRow.is() )
3164     {
3165         try
3166         {
3167             return xRow->getBoolean( 1 );
3168         }
3169         catch ( sdbc::SQLException const & )
3170         {
3171         }
3172     }
3173 
3174     return sal_False;
3175 }
3176 
3177 //=========================================================================
3178 uno::Any Content::MapDAVException( const DAVException & e, sal_Bool bWrite )
3179 {
3180     // Map DAVException...
3181     uno::Any aException;
3182 
3183     rtl::OUString aURL;
3184     if ( m_bTransient )
3185     {
3186         aURL = getParentURL();
3187         if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) )
3188             aURL += rtl::OUString::createFromAscii( "/" );
3189 
3190         aURL += m_aEscapedTitle;
3191     }
3192     else
3193     {
3194         aURL = m_xIdentifier->getContentIdentifier();
3195     }
3196 
3197     switch ( e.getStatus() )
3198     {
3199         case SC_NOT_FOUND:
3200         {
3201             uno::Sequence< uno::Any > aArgs( 1 );
3202             aArgs[ 0 ] <<= beans::PropertyValue(
3203                 rtl::OUString::createFromAscii("Uri"), -1,
3204                 uno::makeAny(aURL),
3205                 beans::PropertyState_DIRECT_VALUE);
3206 
3207             aException <<=
3208                 ucb::InteractiveAugmentedIOException(
3209                     rtl::OUString::createFromAscii( "Not found!" ),
3210                     static_cast< cppu::OWeakObject * >( this ),
3211                     task::InteractionClassification_ERROR,
3212                     ucb::IOErrorCode_NOT_EXISTING,
3213                     aArgs );
3214             return aException;
3215         }
3216         default:
3217             break;
3218     }
3219 
3220     switch ( e.getError() )
3221     {
3222     case DAVException::DAV_HTTP_ERROR:
3223         {
3224             if ( bWrite )
3225                 aException <<=
3226                     ucb::InteractiveNetworkWriteException(
3227                         e.getData(),
3228                         static_cast< cppu::OWeakObject * >( this ),
3229                         task::InteractionClassification_ERROR,
3230                         e.getData() );
3231             else
3232                 aException <<=
3233                     ucb::InteractiveNetworkReadException(
3234                         e.getData(),
3235                         static_cast< cppu::OWeakObject * >( this ),
3236                         task::InteractionClassification_ERROR,
3237                         e.getData() );
3238             break;
3239         }
3240 
3241     case DAVException::DAV_HTTP_LOOKUP:
3242         aException <<=
3243             ucb::InteractiveNetworkResolveNameException(
3244                 rtl::OUString(),
3245                 static_cast< cppu::OWeakObject * >( this ),
3246                 task::InteractionClassification_ERROR,
3247                 e.getData() );
3248         break;
3249 
3250 // @@@ No matching InteractiveNetwork*Exception
3251 //    case DAVException::DAV_HTTP_AUTH:
3252 //        break;
3253 
3254 // @@@ No matching InteractiveNetwork*Exception
3255 //    case DAVException::DAV_HTTP_AUTHPROXY:
3256 //        break;
3257 
3258     case DAVException::DAV_HTTP_CONNECT:
3259         aException <<=
3260             ucb::InteractiveNetworkConnectException(
3261                 rtl::OUString(),
3262                 static_cast< cppu::OWeakObject * >( this ),
3263                 task::InteractionClassification_ERROR,
3264                 e.getData() );
3265         break;
3266 
3267 // @@@ No matching InteractiveNetwork*Exception
3268 //    case DAVException::DAV_HTTP_TIMEOUT:
3269 //        break;
3270 
3271 // @@@ No matching InteractiveNetwork*Exception
3272 //     case DAVException::DAV_HTTP_REDIRECT:
3273 //         break;
3274 
3275 // @@@ No matching InteractiveNetwork*Exception
3276 //     case DAVException::DAV_SESSION_CREATE:
3277 //         break;
3278 
3279     case DAVException::DAV_INVALID_ARG:
3280         aException <<=
3281             lang::IllegalArgumentException(
3282                 rtl::OUString(),
3283                 static_cast< cppu::OWeakObject * >( this ),
3284                 -1 );
3285         break;
3286 
3287     case DAVException::DAV_LOCKED:
3288 #if 1
3289         aException <<=
3290             ucb::InteractiveLockingLockedException(
3291                 rtl::OUString::createFromAscii( "Locked!" ),
3292                 static_cast< cppu::OWeakObject * >( this ),
3293                 task::InteractionClassification_ERROR,
3294                 aURL,
3295                 sal_False ); // not SelfOwned
3296 #else
3297         {
3298             uno::Sequence< uno::Any > aArgs( 1 );
3299             aArgs[ 0 ] <<= beans::PropertyValue(
3300                 rtl::OUString::createFromAscii("Uri"), -1,
3301                 uno::makeAny(aURL),
3302                 beans::PropertyState_DIRECT_VALUE);
3303 
3304             aException <<=
3305                 ucb::InteractiveAugmentedIOException(
3306                     rtl::OUString::createFromAscii( "Locked!" ),
3307                     static_cast< cppu::OWeakObject * >( this ),
3308                     task::InteractionClassification_ERROR,
3309                     ucb::IOErrorCode_LOCKING_VIOLATION,
3310                     aArgs );
3311         }
3312 #endif
3313         break;
3314 
3315     case DAVException::DAV_LOCKED_SELF:
3316         aException <<=
3317             ucb::InteractiveLockingLockedException(
3318                 rtl::OUString::createFromAscii( "Locked (self)!" ),
3319                 static_cast< cppu::OWeakObject * >( this ),
3320                 task::InteractionClassification_ERROR,
3321                 aURL,
3322                 sal_True ); // SelfOwned
3323         break;
3324 
3325     case DAVException::DAV_NOT_LOCKED:
3326         aException <<=
3327             ucb::InteractiveLockingNotLockedException(
3328                 rtl::OUString::createFromAscii( "Not locked!" ),
3329                 static_cast< cppu::OWeakObject * >( this ),
3330                 task::InteractionClassification_ERROR,
3331                 aURL );
3332         break;
3333 
3334     case DAVException::DAV_LOCK_EXPIRED:
3335         aException <<=
3336             ucb::InteractiveLockingLockExpiredException(
3337                 rtl::OUString::createFromAscii( "Lock expired!" ),
3338                 static_cast< cppu::OWeakObject * >( this ),
3339                 task::InteractionClassification_ERROR,
3340                 aURL );
3341         break;
3342 
3343     default:
3344         aException <<=
3345             ucb::InteractiveNetworkGeneralException(
3346                 rtl::OUString(),
3347                 static_cast< cppu::OWeakObject * >( this ),
3348                 task::InteractionClassification_ERROR );
3349         break;
3350     }
3351 
3352     return aException;
3353 }
3354 
3355 // #i124421# force the availability of type_info symbols for exceptions
3356 // that used to be passed around in uno::Any variables and thrown later
3357 void ucb_dummyThrower( int i) {
3358     switch( i) {
3359         case 10: throw ucb::InteractiveNetworkGeneralException();
3360         case 11: throw ucb::InteractiveAugmentedIOException();
3361         case 12: throw ucb::InteractiveNetworkGeneralException();
3362         case 13: throw ucb::InteractiveNetworkWriteException();
3363         case 14: throw ucb::InteractiveNetworkReadException();
3364         case 15: throw ucb::InteractiveNetworkConnectException();
3365         case 16: throw ucb::InteractiveLockingLockedException();
3366         case 17: throw ucb::InteractiveLockingNotLockedException();
3367         case 18: throw ucb::InteractiveNetworkGeneralException();
3368         case 19: throw ucb::InteractiveLockingLockExpiredException();
3369     }
3370 }
3371 
3372 //=========================================================================
3373 // static
3374 bool Content::shouldAccessNetworkAfterException( const DAVException & e )
3375 {
3376     if ( ( e.getStatus() == SC_NOT_FOUND ) ||
3377          ( e.getError() == DAVException::DAV_HTTP_LOOKUP ) ||
3378          ( e.getError() == DAVException::DAV_HTTP_CONNECT ) ||
3379          ( e.getError() == DAVException::DAV_HTTP_AUTH ) ||
3380          ( e.getError() == DAVException::DAV_HTTP_AUTHPROXY ) )
3381         return false;
3382 
3383     return true;
3384 }
3385 
3386 //=========================================================================
3387 void Content::cancelCommandExecution(
3388                 const DAVException & e,
3389                 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
3390                 sal_Bool bWrite /* = sal_False */ )
3391     throw ( uno::Exception )
3392 {
3393     ucbhelper::cancelCommandExecution( MapDAVException( e, bWrite ), xEnv );
3394     // Unreachable
3395 }
3396 
3397 //=========================================================================
3398 const rtl::OUString
3399 Content::getBaseURI( const std::auto_ptr< DAVResourceAccess > & rResAccess )
3400 {
3401     osl::Guard< osl::Mutex > aGuard( m_aMutex );
3402 
3403     // First, try to obtain value of response header "Content-Location".
3404     if ( m_xCachedProps.get() )
3405     {
3406         rtl::OUString aLocation;
3407         m_xCachedProps->getValue( rtl::OUString(
3408                                     RTL_CONSTASCII_USTRINGPARAM(
3409                                         "Content-Location" ) ) ) >>= aLocation;
3410         if ( aLocation.getLength() )
3411         {
3412             try
3413             {
3414                 // Do not use m_xIdentifier->getContentIdentifier() because it
3415                 // for example does not reflect redirects applied to requests
3416                 // done using the original URI but m_xResAccess' URI does.
3417                 return rtl::Uri::convertRelToAbs( rResAccess->getURL(),
3418                                                   aLocation );
3419             }
3420             catch ( rtl::MalformedUriException const & )
3421             {
3422             }
3423         }
3424     }
3425 
3426     return rtl::OUString( rResAccess->getURL() );
3427 }
3428 
3429 //=========================================================================
3430 const Content::ResourceType & Content::getResourceType(
3431                     const uno::Reference< ucb::XCommandEnvironment >& xEnv,
3432                     const std::auto_ptr< DAVResourceAccess > & rResAccess )
3433     throw ( uno::Exception )
3434 {
3435     if ( m_eResourceType == UNKNOWN )
3436     {
3437         osl::Guard< osl::Mutex > aGuard( m_aMutex );
3438 
3439         ResourceType eResourceType;
3440         eResourceType = m_eResourceType;
3441 
3442         const rtl::OUString & rURL = rResAccess->getURL();
3443         const rtl::OUString aScheme(
3444             rURL.copy( 0, rURL.indexOf( ':' ) ).toAsciiLowerCase() );
3445 
3446         try
3447         {
3448             // Try to fetch some frequently used property value, e.g. those
3449             // used when loading documents... along with identifying whether
3450             // this is a DAV resource.
3451             std::vector< DAVResource > resources;
3452             std::vector< rtl::OUString > aPropNames;
3453             uno::Sequence< beans::Property > aProperties( 5 );
3454             aProperties[ 0 ].Name
3455                 = rtl::OUString::createFromAscii( "IsFolder" );
3456             aProperties[ 1 ].Name
3457                 = rtl::OUString::createFromAscii( "IsDocument" );
3458             aProperties[ 2 ].Name
3459                 = rtl::OUString::createFromAscii( "IsReadOnly" );
3460             aProperties[ 3 ].Name
3461                 = rtl::OUString::createFromAscii( "MediaType" );
3462             aProperties[ 4 ].Name
3463                 = DAVProperties::SUPPORTEDLOCK;
3464 
3465             ContentProperties::UCBNamesToDAVNames(
3466                 aProperties, aPropNames );
3467 
3468             rResAccess->PROPFIND(
3469                 DAVZERO, aPropNames, resources, xEnv );
3470 
3471             // TODO - is this really only one?
3472             if ( resources.size() == 1 )
3473             {
3474                 m_xCachedProps.reset(
3475                     new CachableContentProperties( resources[ 0 ] ) );
3476                 m_xCachedProps->containsAllNames(
3477                     aProperties, m_aFailedPropNames );
3478             }
3479 
3480             eResourceType = DAV;
3481         }
3482         catch ( DAVException const & e )
3483         {
3484             rResAccess->resetUri();
3485 
3486             if ( e.getStatus() == SC_METHOD_NOT_ALLOWED )
3487             {
3488                 // Status SC_METHOD_NOT_ALLOWED is a safe indicator that the
3489                 // resource is NON_DAV
3490                 eResourceType = NON_DAV;
3491             }
3492             // cancel command execution is case that no user authentication data has been provided.
3493             if ( e.getError() == DAVException::DAV_HTTP_NOAUTH )
3494             {
3495                 cancelCommandExecution( e, uno::Reference< ucb::XCommandEnvironment >() );
3496             }
3497         }
3498         m_eResourceType = eResourceType;
3499     }
3500     return m_eResourceType;
3501 }
3502 
3503 //=========================================================================
3504 const Content::ResourceType & Content::getResourceType(
3505                     const uno::Reference< ucb::XCommandEnvironment >& xEnv )
3506     throw ( uno::Exception )
3507 {
3508     return getResourceType( xEnv, m_xResAccess );
3509 }
3510