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