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