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 "NeonUri.hxx"
85 #include "UCBDeadPropertyValue.hxx"
86 
87 using namespace com::sun::star;
88 using namespace webdav_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         NeonUri 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 FTP:
807                     case NON_DAV:
808                         // Store property locally.
809                         ContentImplHelper::addProperty( Name,
810                                                         Attributes,
811                                                         DefaultValue );
812                         break;
813 
814                     default:
815                         OSL_ENSURE( sal_False,
816                                     "Content::addProperty - "
817                                     "Unsupported resource type!" );
818                         break;
819                     }
820                 }
821                 catch ( uno::Exception const & )
822                 {
823                     OSL_ENSURE( sal_False,
824                                 "Content::addProperty - "
825                                 "Unable to determine resource type!" );
826                 }
827             }
828             else
829             {
830                 OSL_ENSURE( sal_False,
831                             "Content::addProperty - "
832                             "Unable to determine resource type!" );
833             }
834         }
835     }
836 }
837 
838 //=========================================================================
839 // virtual
840 void SAL_CALL Content::removeProperty( const rtl::OUString& Name )
841     throw( beans::UnknownPropertyException,
842            beans::NotRemoveableException,
843            uno::RuntimeException )
844 {
845     // @@@ Need real command environment here, but where to get it from?
846     //     XPropertyContainer interface should be replaced by
847     //     XCommandProcessor commands!
848     uno::Reference< ucb::XCommandEnvironment > xEnv;
849 
850 #if 0
851     // @@@ REMOVEABLE z.Z. nicht richtig an der PropSetInfo gesetzt!!!
852     try
853     {
854         beans::Property aProp
855             = getPropertySetInfo( xEnv, sal_False /* don't cache data */ )
856                 ->getPropertyByName( Name );
857 
858         if ( !( aProp.Attributes & beans::PropertyAttribute::REMOVEABLE ) )
859         {
860             // Not removeable!
861             throw beans::NotRemoveableException();
862         }
863     }
864     catch ( beans::UnknownPropertyException const & )
865     {
866         //OSL_ENSURE( sal_False, "removeProperty - Unknown property!" );
867         throw;
868     }
869 #endif
870 
871     //////////////////////////////////////////////////////////////////////
872     // Try to remove property from server.
873     //////////////////////////////////////////////////////////////////////
874 
875     try
876     {
877         std::vector< ProppatchValue > aProppatchValues;
878         ProppatchValue aValue( PROPREMOVE, Name, uno::Any() );
879         aProppatchValues.push_back( aValue );
880 
881         // Remove property value from server.
882         std::auto_ptr< DAVResourceAccess > xResAccess;
883         {
884             osl::Guard< osl::Mutex > aGuard( m_aMutex );
885             xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
886         }
887         xResAccess->PROPPATCH( aProppatchValues, xEnv );
888         {
889             osl::Guard< osl::Mutex > aGuard( m_aMutex );
890             m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
891         }
892 
893         // Notify propertyset info change listeners.
894         beans::PropertySetInfoChangeEvent evt(
895             static_cast< cppu::OWeakObject * >( this ),
896             Name,
897             -1, // No handle available
898             beans::PropertySetInfoChange::PROPERTY_REMOVED );
899         notifyPropertySetInfoChange( evt );
900     }
901     catch ( DAVException const & e )
902     {
903         if ( e.getStatus() == SC_FORBIDDEN )
904         {
905             // Support for setting arbitrary dead properties is optional!
906 
907             // Try to remove property from local store.
908             ContentImplHelper::removeProperty( Name );
909         }
910         else
911         {
912             if ( shouldAccessNetworkAfterException( e ) )
913             {
914                 try
915                 {
916                     const ResourceType & rType = getResourceType( xEnv );
917                     switch ( rType )
918                     {
919                         case UNKNOWN:
920                         case DAV:
921                             throw beans::UnknownPropertyException();
922 
923                         case FTP:
924                         case NON_DAV:
925                             // Try to remove property from local store.
926                             ContentImplHelper::removeProperty( Name );
927                             break;
928 
929                         default:
930                             OSL_ENSURE( sal_False,
931                                         "Content::removeProperty - "
932                                         "Unsupported resource type!" );
933                             break;
934                     }
935                 }
936                 catch ( uno::Exception const & )
937                 {
938                     OSL_ENSURE( sal_False,
939                                 "Content::removeProperty - "
940                                 "Unable to determine resource type!" );
941                 }
942             }
943             else
944             {
945                 OSL_ENSURE( sal_False,
946                             "Content::removeProperty - "
947                             "Unable to determine resource type!" );
948 //                throw beans::UnknownPropertyException();
949             }
950         }
951     }
952 }
953 
954 //=========================================================================
955 //
956 // XContentCreator methods.
957 //
958 //=========================================================================
959 
960 // virtual
961 uno::Sequence< ucb::ContentInfo > SAL_CALL
962 Content::queryCreatableContentsInfo()
963     throw( uno::RuntimeException )
964 {
965     osl::Guard< osl::Mutex > aGuard( m_aMutex );
966 
967     uno::Sequence< ucb::ContentInfo > aSeq( 2 );
968 
969     // document.
970     aSeq.getArray()[ 0 ].Type
971         = rtl::OUString::createFromAscii( WEBDAV_CONTENT_TYPE );
972     aSeq.getArray()[ 0 ].Attributes
973         = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
974           | ucb::ContentInfoAttribute::KIND_DOCUMENT;
975 
976     beans::Property aProp;
977     m_pProvider->getProperty(
978         rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ), aProp );
979 
980     uno::Sequence< beans::Property > aDocProps( 1 );
981     aDocProps.getArray()[ 0 ] = aProp;
982     aSeq.getArray()[ 0 ].Properties = aDocProps;
983 
984     // folder.
985     aSeq.getArray()[ 1 ].Type
986         = rtl::OUString::createFromAscii( WEBDAV_COLLECTION_TYPE );
987     aSeq.getArray()[ 1 ].Attributes
988         = ucb::ContentInfoAttribute::KIND_FOLDER;
989 
990     uno::Sequence< beans::Property > aFolderProps( 1 );
991     aFolderProps.getArray()[ 0 ] = aProp;
992     aSeq.getArray()[ 1 ].Properties = aFolderProps;
993     return aSeq;
994 }
995 
996 //=========================================================================
997 // virtual
998 uno::Reference< ucb::XContent > SAL_CALL
999 Content::createNewContent( const ucb::ContentInfo& Info )
1000     throw( uno::RuntimeException )
1001 {
1002     osl::Guard< osl::Mutex > aGuard( m_aMutex );
1003 
1004     if ( !Info.Type.getLength() )
1005         return uno::Reference< ucb::XContent >();
1006 
1007     if ( ( !Info.Type.equalsAsciiL(
1008                RTL_CONSTASCII_STRINGPARAM( WEBDAV_COLLECTION_TYPE ) ) )
1009          &&
1010          ( !Info.Type.equalsAsciiL(
1011              RTL_CONSTASCII_STRINGPARAM( WEBDAV_CONTENT_TYPE ) ) ) )
1012         return uno::Reference< ucb::XContent >();
1013 
1014     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
1015 
1016     OSL_ENSURE( aURL.getLength() > 0,
1017                 "WebdavContent::createNewContent - empty identifier!" );
1018 
1019     if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
1020         aURL += rtl::OUString::createFromAscii( "/" );
1021 
1022     sal_Bool isCollection;
1023     if ( Info.Type.equalsAsciiL(
1024              RTL_CONSTASCII_STRINGPARAM( WEBDAV_COLLECTION_TYPE ) ) )
1025     {
1026         aURL += rtl::OUString::createFromAscii( "New_Collection" );
1027         isCollection = sal_True;
1028     }
1029     else
1030     {
1031         aURL += rtl::OUString::createFromAscii( "New_Content" );
1032         isCollection = sal_False;
1033     }
1034 
1035     uno::Reference< ucb::XContentIdentifier > xId(
1036                     new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ) );
1037 
1038     // create the local content
1039     try
1040     {
1041         return new ::webdav_ucp::Content( m_xSMgr,
1042                                           m_pProvider,
1043                                           xId,
1044                                           m_xResAccess->getSessionFactory(),
1045                                           isCollection );
1046     }
1047     catch ( ucb::ContentCreationException & )
1048     {
1049         return uno::Reference< ucb::XContent >();
1050     }
1051 }
1052 
1053 //=========================================================================
1054 // virtual
1055 rtl::OUString Content::getParentURL()
1056 {
1057     // <scheme>://              -> ""
1058     // <scheme>://foo           -> ""
1059     // <scheme>://foo/          -> ""
1060     // <scheme>://foo/bar       -> <scheme>://foo/
1061     // <scheme>://foo/bar/      -> <scheme>://foo/
1062     // <scheme>://foo/bar/abc   -> <scheme>://foo/bar/
1063 
1064     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
1065 
1066     sal_Int32 nPos = aURL.lastIndexOf( '/' );
1067     if ( nPos == ( aURL.getLength() - 1 ) )
1068     {
1069         // Trailing slash found. Skip.
1070         nPos = aURL.lastIndexOf( '/', nPos );
1071     }
1072 
1073     sal_Int32 nPos1 = aURL.lastIndexOf( '/', nPos );
1074     if ( nPos1 != -1 )
1075         nPos1 = aURL.lastIndexOf( '/', nPos1 );
1076 
1077     if ( nPos1 == -1 )
1078         return rtl::OUString();
1079 
1080     return rtl::OUString( aURL.copy( 0, nPos + 1 ) );
1081 }
1082 
1083 //=========================================================================
1084 //
1085 // Non-interface methods.
1086 //
1087 //=========================================================================
1088 
1089 // static
1090 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1091     const uno::Reference< lang::XMultiServiceFactory >& rSMgr,
1092     const uno::Sequence< beans::Property >& rProperties,
1093     const ContentProperties& rData,
1094     const rtl::Reference< ::ucbhelper::ContentProviderImplHelper >& rProvider,
1095     const rtl::OUString& rContentId )
1096 {
1097     // Note: Empty sequence means "get values of all supported properties".
1098 
1099     rtl::Reference< ::ucbhelper::PropertyValueSet > xRow
1100         = new ::ucbhelper::PropertyValueSet( rSMgr );
1101 
1102     sal_Int32 nCount = rProperties.getLength();
1103     if ( nCount )
1104     {
1105         uno::Reference< beans::XPropertySet > xAdditionalPropSet;
1106         sal_Bool bTriedToGetAdditonalPropSet = sal_False;
1107 
1108         const beans::Property* pProps = rProperties.getConstArray();
1109         for ( sal_Int32 n = 0; n < nCount; ++n )
1110         {
1111             const beans::Property& rProp = pProps[ n ];
1112 
1113             // Process standard UCB, DAV and HTTP properties.
1114             const uno::Any & rValue = rData.getValue( rProp.Name );
1115             if ( rValue.hasValue() )
1116             {
1117                 xRow->appendObject( rProp, rValue );
1118             }
1119             else
1120             {
1121                 // Process local Additional Properties.
1122                 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() )
1123                 {
1124                     xAdditionalPropSet
1125                         = uno::Reference< beans::XPropertySet >(
1126                             rProvider->getAdditionalPropertySet( rContentId,
1127                                                                  sal_False ),
1128                             uno::UNO_QUERY );
1129                     bTriedToGetAdditonalPropSet = sal_True;
1130                 }
1131 
1132                 if ( !xAdditionalPropSet.is() ||
1133                      !xRow->appendPropertySetValue(
1134                                             xAdditionalPropSet, rProp ) )
1135                 {
1136                     // Append empty entry.
1137                     xRow->appendVoid( rProp );
1138                 }
1139             }
1140         }
1141     }
1142     else
1143     {
1144         // Append all standard UCB, DAV and HTTP properties.
1145 
1146         const std::auto_ptr< PropertyValueMap > & xProps = rData.getProperties();
1147 
1148         PropertyValueMap::const_iterator it  = xProps->begin();
1149         PropertyValueMap::const_iterator end = xProps->end();
1150 
1151         ContentProvider * pProvider
1152             = static_cast< ContentProvider * >( rProvider.get() );
1153         beans::Property aProp;
1154 
1155         while ( it != end )
1156         {
1157             if ( pProvider->getProperty( (*it).first, aProp ) )
1158                 xRow->appendObject( aProp, (*it).second.value() );
1159 
1160             ++it;
1161         }
1162 
1163         // Append all local Additional Properties.
1164         uno::Reference< beans::XPropertySet > xSet(
1165             rProvider->getAdditionalPropertySet( rContentId, sal_False ),
1166             uno::UNO_QUERY );
1167         xRow->appendPropertySet( xSet );
1168     }
1169 
1170     return uno::Reference< sdbc::XRow >( xRow.get() );
1171 }
1172 
1173 //=========================================================================
1174 uno::Reference< sdbc::XRow > Content::getPropertyValues(
1175                 const uno::Sequence< beans::Property >& rProperties,
1176                 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1177     throw ( uno::Exception )
1178 {
1179     std::auto_ptr< ContentProperties > xProps;
1180     std::auto_ptr< ContentProperties > xCachedProps;
1181     std::auto_ptr< DAVResourceAccess > xResAccess;
1182     rtl::OUString aUnescapedTitle;
1183     bool bHasAll = false;
1184     uno::Reference< lang::XMultiServiceFactory > xSMgr;
1185     uno::Reference< ucb::XContentIdentifier > xIdentifier;
1186     rtl::Reference< ::ucbhelper::ContentProviderImplHelper > xProvider;
1187 
1188     {
1189         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1190 
1191         aUnescapedTitle = NeonUri::unescape( m_aEscapedTitle );
1192         xSMgr.set( m_xSMgr );
1193         xIdentifier.set( m_xIdentifier );
1194         xProvider.set( m_xProvider.get() );
1195         xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
1196 
1197         // First, ask cache...
1198         if ( m_xCachedProps.get() )
1199         {
1200             xCachedProps.reset( new ContentProperties( *m_xCachedProps.get() ) );
1201 
1202             std::vector< rtl::OUString > aMissingProps;
1203             if ( xCachedProps->containsAllNames( rProperties, aMissingProps ) )
1204             {
1205                 // All properties are already in cache! No server access needed.
1206                 bHasAll = true;
1207             }
1208 
1209             // use the cached ContentProperties instance
1210             xProps.reset( new ContentProperties( *xCachedProps.get() ) );
1211         }
1212     }
1213 
1214     if ( !m_bTransient && !bHasAll )
1215     {
1216         /////////////////////////////////////////////////////////////////////
1217         // Obtain values from server...
1218         /////////////////////////////////////////////////////////////////////
1219 
1220         // First, identify whether resource is DAV or not
1221         const ResourceType & rType = getResourceType( xEnv, xResAccess );
1222 
1223         bool bNetworkAccessAllowed = true;
1224 
1225         if ( DAV == rType )
1226         {
1227             // cache lookup... getResourceType may fill the props cache via
1228             // PROPFIND!
1229             if ( m_xCachedProps.get() )
1230             {
1231                 xCachedProps.reset(
1232                     new ContentProperties( *m_xCachedProps.get() ) );
1233 
1234                 std::vector< rtl::OUString > aMissingProps;
1235                 if ( xCachedProps->containsAllNames(
1236                          rProperties, aMissingProps ) )
1237                 {
1238                     // All properties are already in cache! No server access
1239                     // needed.
1240                     bHasAll = true;
1241                 }
1242 
1243                 // use the cached ContentProperties instance
1244                 xProps.reset( new ContentProperties( *xCachedProps.get() ) );
1245             }
1246 
1247             if ( !bHasAll )
1248             {
1249                 // Only DAV resources support PROPFIND
1250                 std::vector< rtl::OUString > aPropNames;
1251 
1252                 uno::Sequence< beans::Property > aProperties(
1253                     rProperties.getLength() );
1254 
1255                 if ( m_aFailedPropNames.size() > 0 )
1256                 {
1257                     sal_Int32 nProps = 0;
1258                     sal_Int32 nCount = rProperties.getLength();
1259                     for ( sal_Int32 n = 0; n < nCount; ++n )
1260                     {
1261                         const rtl::OUString & rName = rProperties[ n ].Name;
1262 
1263                         std::vector< rtl::OUString >::const_iterator it
1264                             = m_aFailedPropNames.begin();
1265                         std::vector< rtl::OUString >::const_iterator end
1266                             = m_aFailedPropNames.end();
1267 
1268                         while ( it != end )
1269                         {
1270                             if ( *it == rName )
1271                                 break;
1272 
1273                             ++it;
1274                         }
1275 
1276                         if ( it == end )
1277                         {
1278                             aProperties[ nProps ] = rProperties[ n ];
1279                             nProps++;
1280                         }
1281                     }
1282 
1283                     aProperties.realloc( nProps );
1284                 }
1285                 else
1286                 {
1287                     aProperties = rProperties;
1288                 }
1289 
1290                 if ( aProperties.getLength() > 0 )
1291                     ContentProperties::UCBNamesToDAVNames(
1292                         aProperties, aPropNames );
1293 
1294                 if ( aPropNames.size() > 0 )
1295                 {
1296                     std::vector< DAVResource > resources;
1297                     try
1298                     {
1299                         xResAccess->PROPFIND(
1300                             DAVZERO, aPropNames, resources, xEnv );
1301 
1302                         if ( 1 == resources.size() )
1303                         {
1304                             if ( xProps.get())
1305                                 xProps->addProperties(
1306                                     aPropNames,
1307                                     ContentProperties( resources[ 0 ] ));
1308                             else
1309                                 xProps.reset(
1310                                     new ContentProperties( resources[ 0 ] ) );
1311                         }
1312                     }
1313                     catch ( DAVException const & e )
1314                     {
1315                         bNetworkAccessAllowed
1316                             = shouldAccessNetworkAfterException( e );
1317 
1318                         if ( !bNetworkAccessAllowed )
1319                         {
1320                             cancelCommandExecution( e, xEnv );
1321                             // unreachable
1322                         }
1323                     }
1324                 }
1325             }
1326         }
1327 
1328         if ( bNetworkAccessAllowed )
1329         {
1330             // All properties obtained already?
1331             std::vector< rtl::OUString > aMissingProps;
1332             if ( !( xProps.get()
1333                     && xProps->containsAllNames(
1334                         rProperties, aMissingProps ) )
1335                  && !m_bDidGetOrHead )
1336             {
1337                 // Possibly the missing props can be obtained using a HEAD
1338                 // request.
1339 
1340                 std::vector< rtl::OUString > aHeaderNames;
1341                 ContentProperties::UCBNamesToHTTPNames(
1342                     rProperties,
1343                     aHeaderNames,
1344                     true /* bIncludeUnmatched */ );
1345 
1346                 if ( aHeaderNames.size() > 0 )
1347                 {
1348                     try
1349                     {
1350                         DAVResource resource;
1351                         xResAccess->HEAD( aHeaderNames, resource, xEnv );
1352                         m_bDidGetOrHead = true;
1353 
1354                         if ( xProps.get() )
1355                             xProps->addProperties(
1356                                 aMissingProps,
1357                                 ContentProperties( resource ) );
1358                         else
1359                             xProps.reset ( new ContentProperties( resource ) );
1360 
1361                         if ( m_eResourceType == NON_DAV )
1362                             xProps->addProperties( aMissingProps,
1363                                                    ContentProperties(
1364                                                        aUnescapedTitle,
1365                                                        false ) );
1366                     }
1367                     catch ( DAVException const & e )
1368                     {
1369                         bNetworkAccessAllowed
1370                             = shouldAccessNetworkAfterException( e );
1371 
1372                         if ( !bNetworkAccessAllowed )
1373                         {
1374                             cancelCommandExecution( e, xEnv );
1375                             // unreachable
1376                         }
1377                     }
1378                 }
1379             }
1380         }
1381 
1382         // might trigger HTTP redirect.
1383         // Therefore, title must be updated here.
1384         NeonUri aUri( xResAccess->getURL() );
1385         aUnescapedTitle = aUri.GetPathBaseNameUnescaped();
1386 
1387         if ( rType == UNKNOWN )
1388         {
1389             xProps.reset( new ContentProperties( aUnescapedTitle ) );
1390         }
1391 
1392         // For DAV resources we only know the Title, for non-DAV
1393         // resources we additionally know that it is a document.
1394 
1395         if ( rType == DAV )
1396         {
1397             //xProps.reset(
1398             //    new ContentProperties( aUnescapedTitle ) );
1399             xProps->addProperty(
1400                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ),
1401                 uno::makeAny( aUnescapedTitle ),
1402                 true );
1403         }
1404         else
1405         {
1406             if ( !xProps.get() )
1407                 xProps.reset( new ContentProperties( aUnescapedTitle, false ) );
1408             else
1409                 xProps->addProperty(
1410                     rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ),
1411                     uno::makeAny( aUnescapedTitle ),
1412                     true );
1413 
1414             xProps->addProperty(
1415                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ),
1416                 uno::makeAny( false ),
1417                 true );
1418             xProps->addProperty(
1419                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ),
1420                 uno::makeAny( true ),
1421                 true );
1422         }
1423     }
1424     else
1425     {
1426         // No server access for just created (not yet committed) objects.
1427         // Only a minimal set of properties supported at this stage.
1428         if (m_bTransient)
1429             xProps.reset( new ContentProperties( aUnescapedTitle,
1430                                                  m_bCollection ) );
1431     }
1432 
1433     sal_Int32 nCount = rProperties.getLength();
1434     for ( sal_Int32 n = 0; n < nCount; ++n )
1435     {
1436         const rtl::OUString rName = rProperties[ n ].Name;
1437         if ( rName.equalsAsciiL(
1438                       RTL_CONSTASCII_STRINGPARAM( "BaseURI" ) ) )
1439         {
1440             // Add BaseURI property, if requested.
1441             xProps->addProperty(
1442                  rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseURI" ) ),
1443                  uno::makeAny( getBaseURI( xResAccess ) ),
1444                  true );
1445         }
1446         else if ( rName.equalsAsciiL(
1447                       RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
1448         {
1449             // Add CreatableContentsInfo property, if requested.
1450             sal_Bool bFolder = sal_False;
1451             xProps->getValue(
1452                 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ) )
1453                     >>= bFolder;
1454             xProps->addProperty(
1455                 rtl::OUString(
1456                     RTL_CONSTASCII_USTRINGPARAM( "CreatableContentsInfo" ) ),
1457                 uno::makeAny( bFolder
1458                                   ? queryCreatableContentsInfo()
1459                                   : uno::Sequence< ucb::ContentInfo >() ),
1460                 true );
1461         }
1462     }
1463 
1464     uno::Reference< sdbc::XRow > xResultRow
1465         = getPropertyValues( xSMgr,
1466                              rProperties,
1467                              *xProps,
1468                              xProvider,
1469                              xIdentifier->getContentIdentifier() );
1470 
1471     {
1472         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1473 
1474         if ( !m_xCachedProps.get() )
1475             m_xCachedProps.reset( new CachableContentProperties( *xProps.get() ) );
1476         else
1477             m_xCachedProps->addProperties( *xProps.get() );
1478 
1479         m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
1480         m_aEscapedTitle = NeonUri::escapeSegment( aUnescapedTitle );
1481     }
1482 
1483     return xResultRow;
1484 }
1485 
1486 //=========================================================================
1487 uno::Sequence< uno::Any > Content::setPropertyValues(
1488                 const uno::Sequence< beans::PropertyValue >& rValues,
1489                 const uno::Reference< ucb::XCommandEnvironment >& xEnv )
1490     throw ( uno::Exception )
1491 {
1492     uno::Reference< lang::XMultiServiceFactory > xSMgr;
1493     uno::Reference< ucb::XContentIdentifier >    xIdentifier;
1494     rtl::Reference< ContentProvider >            xProvider;
1495     sal_Bool bTransient;
1496     std::auto_ptr< DAVResourceAccess > xResAccess;
1497 
1498     {
1499         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1500 
1501         xProvider.set( m_pProvider );
1502         xIdentifier.set( m_xIdentifier );
1503         bTransient = m_bTransient;
1504         xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
1505         xSMgr.set( m_xSMgr );
1506     }
1507 
1508     uno::Sequence< uno::Any > aRet( rValues.getLength() );
1509     uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() );
1510     sal_Int32 nChanged = 0;
1511 
1512     beans::PropertyChangeEvent aEvent;
1513     aEvent.Source         = static_cast< cppu::OWeakObject * >( this );
1514     aEvent.Further        = sal_False;
1515     // aEvent.PropertyName =
1516     aEvent.PropertyHandle = -1;
1517     // aEvent.OldValue   =
1518     // aEvent.NewValue   =
1519 
1520     std::vector< ProppatchValue > aProppatchValues;
1521     std::vector< sal_Int32 > aProppatchPropsPositions;
1522 
1523     uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet;
1524     sal_Bool bTriedToGetAdditonalPropSet = sal_False;
1525 
1526     sal_Bool bExchange = sal_False;
1527     rtl::OUString aNewTitle;
1528     rtl::OUString aOldTitle;
1529     sal_Int32 nTitlePos = -1;
1530 
1531     uno::Reference< beans::XPropertySetInfo > xInfo;
1532 
1533     const beans::PropertyValue* pValues = rValues.getConstArray();
1534     sal_Int32 nCount = rValues.getLength();
1535     for ( sal_Int32 n = 0; n < nCount; ++n )
1536     {
1537         const beans::PropertyValue& rValue = pValues[ n ];
1538         const rtl::OUString & rName = rValue.Name;
1539 
1540         beans::Property aTmpProp;
1541         xProvider->getProperty( rName, aTmpProp );
1542 
1543         if ( aTmpProp.Attributes & beans::PropertyAttribute::READONLY )
1544         {
1545             // Read-only property!
1546             aRet[ n ] <<= lang::IllegalAccessException(
1547                             rtl::OUString::createFromAscii(
1548                                 "Property is read-only!" ),
1549                             static_cast< cppu::OWeakObject * >( this ) );
1550             continue;
1551         }
1552 
1553         //////////////////////////////////////////////////////////////////
1554         // Mandatory props.
1555         //////////////////////////////////////////////////////////////////
1556 
1557         if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) )
1558         {
1559             // Read-only property!
1560             aRet[ n ] <<= lang::IllegalAccessException(
1561                 rtl::OUString::createFromAscii(
1562                     "Property is read-only!" ),
1563                 static_cast< cppu::OWeakObject * >( this ) );
1564         }
1565         else if ( rName.equalsAsciiL(
1566                       RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) )
1567         {
1568             // Read-only property!
1569             aRet[ n ] <<= lang::IllegalAccessException(
1570                 rtl::OUString::createFromAscii(
1571                     "Property is read-only!" ),
1572                 static_cast< cppu::OWeakObject * >( this ) );
1573         }
1574         else if ( rName.equalsAsciiL(
1575                       RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) )
1576         {
1577             // Read-only property!
1578             aRet[ n ] <<= lang::IllegalAccessException(
1579                             rtl::OUString::createFromAscii(
1580                                 "Property is read-only!" ),
1581                             static_cast< cppu::OWeakObject * >( this ) );
1582         }
1583         else if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) )
1584         {
1585             rtl::OUString aNewValue;
1586             if ( rValue.Value >>= aNewValue )
1587             {
1588                 // No empty titles!
1589                 if ( aNewValue.getLength() > 0 )
1590                 {
1591                     try
1592                     {
1593                         NeonUri aURI( xIdentifier->getContentIdentifier() );
1594                         aOldTitle = aURI.GetPathBaseNameUnescaped();
1595 
1596                         if ( aNewValue != aOldTitle )
1597                         {
1598                             // modified title -> modified URL -> exchange !
1599                             if ( !bTransient )
1600                                 bExchange = sal_True;
1601 
1602                             // new value will be set later...
1603                             aNewTitle = aNewValue;
1604 
1605                             // remember position within sequence of values (for
1606                             // error handling).
1607                             nTitlePos = n;
1608                         }
1609                     }
1610                     catch ( DAVException const & )
1611                     {
1612                         aRet[ n ] <<= lang::IllegalArgumentException(
1613                             rtl::OUString::createFromAscii(
1614                                 "Invalid content identifier!" ),
1615                             static_cast< cppu::OWeakObject * >( this ),
1616                             -1 );
1617                     }
1618                 }
1619                 else
1620                 {
1621                     aRet[ n ] <<= lang::IllegalArgumentException(
1622                         rtl::OUString::createFromAscii(
1623                             "Empty title not allowed!" ),
1624                         static_cast< cppu::OWeakObject * >( this ),
1625                         -1 );
1626                 }
1627             }
1628             else
1629             {
1630                 aRet[ n ] <<= beans::IllegalTypeException(
1631                     rtl::OUString::createFromAscii(
1632                         "Property value has wrong type!" ),
1633                     static_cast< cppu::OWeakObject * >( this ) );
1634             }
1635         }
1636         else
1637         {
1638             //////////////////////////////////////////////////////////////
1639             // Optional props.
1640             //////////////////////////////////////////////////////////////
1641 
1642             if ( !xInfo.is() )
1643                 xInfo = getPropertySetInfo( xEnv,
1644                                             sal_False /* don't cache data */ );
1645 
1646             if ( !xInfo->hasPropertyByName( rName ) )
1647             {
1648                 // Check, whether property exists. Skip otherwise.
1649                 // PROPPATCH::set would add the property automatically, which
1650                 // is not allowed for "setPropertyValues" command!
1651                 aRet[ n ] <<= beans::UnknownPropertyException(
1652                                 rtl::OUString::createFromAscii(
1653                                     "Property is unknown!" ),
1654                                 static_cast< cppu::OWeakObject * >( this ) );
1655                 continue;
1656             }
1657 
1658             if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) )
1659             {
1660                 // Read-only property!
1661                 aRet[ n ] <<= lang::IllegalAccessException(
1662                                 rtl::OUString::createFromAscii(
1663                                     "Property is read-only!" ),
1664                                 static_cast< cppu::OWeakObject * >( this ) );
1665             }
1666             else if ( rName.equalsAsciiL(
1667                         RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) )
1668             {
1669                 // Read-only property!
1670                 aRet[ n ] <<= lang::IllegalAccessException(
1671                                 rtl::OUString::createFromAscii(
1672                                     "Property is read-only!" ),
1673                                 static_cast< cppu::OWeakObject * >( this ) );
1674             }
1675             else if ( rName.equalsAsciiL(
1676                         RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) )
1677             {
1678                 // Read-only property!
1679                 aRet[ n ] <<= lang::IllegalAccessException(
1680                                 rtl::OUString::createFromAscii(
1681                                     "Property is read-only!" ),
1682                                 static_cast< cppu::OWeakObject * >( this ) );
1683             }
1684             else if ( rName.equalsAsciiL(
1685                         RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) )
1686             {
1687                 // Read-only property!
1688                 // (but could be writable, if 'getcontenttype' would be)
1689                 aRet[ n ] <<= lang::IllegalAccessException(
1690                                 rtl::OUString::createFromAscii(
1691                                     "Property is read-only!" ),
1692                                 static_cast< cppu::OWeakObject * >( this ) );
1693             }
1694             if ( rName.equalsAsciiL(
1695                      RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) )
1696             {
1697                 // Read-only property!
1698                 aRet[ n ] <<= lang::IllegalAccessException(
1699                                 rtl::OUString::createFromAscii(
1700                                     "Property is read-only!" ),
1701                                 static_cast< cppu::OWeakObject * >( this ) );
1702             }
1703             else
1704             {
1705                 if ( getResourceType( xEnv, xResAccess ) == DAV )
1706                 {
1707                     // Property value will be set on server.
1708                     ProppatchValue aValue( PROPSET, rName, rValue.Value );
1709                     aProppatchValues.push_back( aValue );
1710 
1711                     // remember position within sequence of values (for
1712                     // error handling).
1713                     aProppatchPropsPositions.push_back( n );
1714                 }
1715                 else
1716                 {
1717                     // Property value will be stored in local property store.
1718                     if ( !bTriedToGetAdditonalPropSet &&
1719                          !xAdditionalPropSet.is() )
1720                     {
1721                         xAdditionalPropSet
1722                             = getAdditionalPropertySet( sal_False );
1723                         bTriedToGetAdditonalPropSet = sal_True;
1724                     }
1725 
1726                     if ( xAdditionalPropSet.is() )
1727                     {
1728                         try
1729                         {
1730                             uno::Any aOldValue
1731                                 = xAdditionalPropSet->getPropertyValue( rName );
1732                             if ( aOldValue != rValue.Value )
1733                             {
1734                                 xAdditionalPropSet->setPropertyValue(
1735                                                         rName, rValue.Value );
1736 
1737                                 aEvent.PropertyName = rName;
1738                                 aEvent.OldValue     = aOldValue;
1739                                 aEvent.NewValue     = rValue.Value;
1740 
1741                                 aChanges.getArray()[ nChanged ] = aEvent;
1742                                 nChanged++;
1743                             }
1744                         }
1745                         catch ( beans::UnknownPropertyException const & e )
1746                         {
1747                             aRet[ n ] <<= e;
1748                         }
1749                         catch ( lang::WrappedTargetException const & e )
1750                         {
1751                             aRet[ n ] <<= e;
1752                         }
1753                         catch ( beans::PropertyVetoException const & e )
1754                         {
1755                             aRet[ n ] <<= e;
1756                         }
1757                         catch ( lang::IllegalArgumentException const & e )
1758                         {
1759                             aRet[ n ] <<= e;
1760                         }
1761                     }
1762                     else
1763                     {
1764                         aRet[ n ] <<= uno::Exception(
1765                                 rtl::OUString::createFromAscii(
1766                                     "No property set for storing the value!" ),
1767                                 static_cast< cppu::OWeakObject * >( this ) );
1768                     }
1769                 }
1770             }
1771         }
1772     } // for
1773 
1774     if ( !bTransient && aProppatchValues.size() )
1775     {
1776         try
1777         {
1778             // Set property values at server.
1779             xResAccess->PROPPATCH( aProppatchValues, xEnv );
1780 
1781             std::vector< ProppatchValue >::const_iterator it
1782                 = aProppatchValues.begin();
1783             std::vector< ProppatchValue >::const_iterator end
1784                 = aProppatchValues.end();
1785 
1786             while ( it != end )
1787             {
1788                 aEvent.PropertyName = (*it).name;
1789                 aEvent.OldValue     = uno::Any(); // @@@ to expensive to obtain!
1790                 aEvent.NewValue     = (*it).value;
1791 
1792                 aChanges.getArray()[ nChanged ] = aEvent;
1793                 nChanged++;
1794 
1795                 ++it;
1796             }
1797         }
1798         catch ( DAVException const & e )
1799         {
1800 //            OSL_ENSURE( sal_False,
1801 //                        "Content::setPropertyValues - PROPPATCH failed!" );
1802 
1803 #if 1
1804             cancelCommandExecution( e, xEnv );
1805             // unreachable
1806 #else
1807             // Note: PROPPATCH either sets ALL property values OR NOTHING.
1808 
1809             std::vector< sal_Int32 >::const_iterator it
1810                 = aProppatchPropsPositions.begin();
1811             std::vector< sal_Int32 >::const_iterator end
1812                 = aProppatchPropsPositions.end();
1813 
1814             while ( it != end )
1815             {
1816                 // Set error.
1817                 aRet[ (*it) ] <<= MapDAVException( e, sal_True );
1818                 ++it;
1819             }
1820 #endif
1821         }
1822     }
1823 
1824     if ( bExchange )
1825     {
1826         // Assemble new content identifier...
1827 
1828         rtl::OUString aNewURL = getParentURL();
1829         if ( aNewURL.lastIndexOf( '/' ) != ( aNewURL.getLength() - 1 ) )
1830             aNewURL += rtl::OUString::createFromAscii( "/" );
1831 
1832         aNewURL += NeonUri::escapeSegment( aNewTitle );
1833 
1834         uno::Reference< ucb::XContentIdentifier > xNewId
1835             = new ::ucbhelper::ContentIdentifier( xSMgr, aNewURL );
1836         uno::Reference< ucb::XContentIdentifier > xOldId = xIdentifier;
1837 
1838         try
1839         {
1840             NeonUri sourceURI( xOldId->getContentIdentifier() );
1841             NeonUri targetURI( xNewId->getContentIdentifier() );
1842             targetURI.SetScheme( sourceURI.GetScheme() );
1843 
1844             xResAccess->MOVE(
1845                 sourceURI.GetPath(), targetURI.GetURI(), sal_False, xEnv );
1846             // @@@ Should check for resources that could not be moved
1847             //     (due to source access or target overwrite) and send
1848             //     this information through the interaction handler.
1849 
1850             // @@@ Existing content should be checked to see if it needs
1851             //     to be deleted at the source
1852 
1853             // @@@ Existing content should be checked to see if it has
1854             //     been overwritten at the target
1855 
1856             if ( exchangeIdentity( xNewId ) )
1857             {
1858                 xResAccess->setURL( aNewURL );
1859 
1860 // DAV resources store all additional props on server!
1861 //              // Adapt Additional Core Properties.
1862 //              renameAdditionalPropertySet( xOldId->getContentIdentifier(),
1863 //                                           xNewId->getContentIdentifier(),
1864 //                                           sal_True );
1865             }
1866             else
1867             {
1868                 // Do not set new title!
1869                 aNewTitle = rtl::OUString();
1870 
1871                 // Set error .
1872                 aRet[ nTitlePos ] <<= uno::Exception(
1873                     rtl::OUString::createFromAscii( "Exchange failed!" ),
1874                     static_cast< cppu::OWeakObject * >( this ) );
1875             }
1876         }
1877         catch ( DAVException const & e )
1878         {
1879             // Do not set new title!
1880             aNewTitle = rtl::OUString();
1881 
1882             // Set error .
1883             aRet[ nTitlePos ] <<= MapDAVException( e, sal_True );
1884         }
1885     }
1886 
1887     if ( aNewTitle.getLength() )
1888     {
1889         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1890 
1891         aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" );
1892         aEvent.OldValue     = uno::makeAny( aOldTitle );
1893         aEvent.NewValue     = uno::makeAny( aNewTitle );
1894 
1895         m_aEscapedTitle     = NeonUri::escapeSegment( aNewTitle );
1896 
1897         aChanges.getArray()[ nChanged ] = aEvent;
1898         nChanged++;
1899     }
1900 
1901     if ( nChanged > 0 )
1902     {
1903         aChanges.realloc( nChanged );
1904         notifyPropertiesChange( aChanges );
1905     }
1906 
1907     {
1908         osl::Guard< osl::Mutex > aGuard( m_aMutex );
1909         m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
1910     }
1911 
1912     return aRet;
1913 }
1914 
1915 //=========================================================================
1916 uno::Any Content::open(
1917                 const ucb::OpenCommandArgument2 & rArg,
1918                 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
1919     throw( uno::Exception )
1920 {
1921     uno::Any aRet;
1922 
1923     sal_Bool bOpenFolder = ( ( rArg.Mode == ucb::OpenMode::ALL ) ||
1924                              ( rArg.Mode == ucb::OpenMode::FOLDERS ) ||
1925                              ( rArg.Mode == ucb::OpenMode::DOCUMENTS ) );
1926     if ( bOpenFolder )
1927     {
1928         if ( isFolder( xEnv ) )
1929         {
1930             // Open collection.
1931 
1932             uno::Reference< ucb::XDynamicResultSet > xSet
1933                 = new DynamicResultSet( m_xSMgr, this, rArg, xEnv );
1934             aRet <<= xSet;
1935         }
1936         else
1937         {
1938             // Error: Not a folder!
1939 
1940             rtl::OUStringBuffer aMsg;
1941             if ( getResourceType( xEnv ) == FTP )
1942             {
1943                 // #114653#
1944                 aMsg.appendAscii( "FTP over HTTP proxy: resource cannot "
1945                                   "be opened as folder! Wrong Open Mode!" );
1946             }
1947             else
1948             {
1949                 aMsg.appendAscii( "Non-folder resource cannot be "
1950                                   "opened as folder! Wrong Open Mode!" );
1951             }
1952 
1953             ucbhelper::cancelCommandExecution(
1954                 uno::makeAny(
1955                     lang::IllegalArgumentException(
1956                         aMsg.makeStringAndClear(),
1957                         static_cast< cppu::OWeakObject * >( this ),
1958                         -1 ) ),
1959                 xEnv );
1960             // Unreachable
1961         }
1962     }
1963 
1964     if ( rArg.Sink.is() )
1965     {
1966         // Open document.
1967 
1968         if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
1969              ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) )
1970         {
1971             // Currently(?) unsupported.
1972             ucbhelper::cancelCommandExecution(
1973                 uno::makeAny(
1974                     ucb::UnsupportedOpenModeException(
1975                             rtl::OUString(),
1976                             static_cast< cppu::OWeakObject * >( this ),
1977                             sal_Int16( rArg.Mode ) ) ),
1978                 xEnv );
1979             // Unreachable
1980         }
1981 
1982         rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
1983         uno::Reference< io::XOutputStream > xOut
1984             = uno::Reference< io::XOutputStream >( rArg.Sink, uno::UNO_QUERY );
1985         if ( xOut.is() )
1986         {
1987             // PUSH: write data
1988             try
1989             {
1990                 std::auto_ptr< DAVResourceAccess > xResAccess;
1991 
1992                 {
1993                     osl::MutexGuard aGuard( m_aMutex );
1994 
1995                     xResAccess.reset(
1996                         new DAVResourceAccess( *m_xResAccess.get() ) );
1997                 }
1998 
1999                 DAVResource aResource;
2000                 std::vector< rtl::OUString > aHeaders;
2001 
2002                 xResAccess->GET( xOut, aHeaders, aResource, xEnv );
2003                 m_bDidGetOrHead = true;
2004 
2005                 {
2006                     osl::MutexGuard aGuard( m_aMutex );
2007 
2008                     // cache headers.
2009                     if ( !m_xCachedProps.get())
2010                         m_xCachedProps.reset(
2011                             new CachableContentProperties( aResource ) );
2012                     else
2013                         m_xCachedProps->addProperties( aResource );
2014 
2015                     m_xResAccess.reset(
2016                         new DAVResourceAccess( *xResAccess.get() ) );
2017                 }
2018             }
2019             catch ( DAVException const & e )
2020             {
2021                 cancelCommandExecution( e, xEnv );
2022                 // Unreachable
2023             }
2024         }
2025         else
2026         {
2027             uno::Reference< io::XActiveDataSink > xDataSink
2028                 = uno::Reference< io::XActiveDataSink >( rArg.Sink,
2029                                                          uno::UNO_QUERY );
2030             if ( xDataSink.is() )
2031             {
2032                 // PULL: wait for client read
2033                 try
2034                 {
2035                     std::auto_ptr< DAVResourceAccess > xResAccess;
2036                     {
2037                         osl::MutexGuard aGuard( m_aMutex );
2038 
2039                         xResAccess.reset(
2040                             new DAVResourceAccess( *m_xResAccess.get() ) );
2041                     }
2042 
2043                     // fill inputsream sync; return if all data present
2044                     DAVResource aResource;
2045                     std::vector< rtl::OUString > aHeaders;
2046 
2047                     uno::Reference< io::XInputStream > xIn
2048                         = xResAccess->GET( aHeaders, aResource, xEnv );
2049                     m_bDidGetOrHead = true;
2050 
2051                     {
2052                         osl::MutexGuard aGuard( m_aMutex );
2053 
2054                         // cache headers.
2055                         if ( !m_xCachedProps.get())
2056                             m_xCachedProps.reset(
2057                                 new CachableContentProperties( aResource ) );
2058                         else
2059                             m_xCachedProps->addProperties(
2060                                 aResource.properties );
2061 
2062                         m_xResAccess.reset(
2063                             new DAVResourceAccess( *xResAccess.get() ) );
2064                     }
2065 
2066                     xDataSink->setInputStream( xIn );
2067                 }
2068                 catch ( DAVException const & e )
2069                 {
2070                     cancelCommandExecution( e, xEnv );
2071                     // Unreachable
2072                 }
2073             }
2074             else
2075             {
2076                 // Note: aOpenCommand.Sink may contain an XStream
2077                 //       implementation. Support for this type of
2078                 //       sink is optional...
2079                 ucbhelper::cancelCommandExecution(
2080                     uno::makeAny(
2081                         ucb::UnsupportedDataSinkException(
2082                             rtl::OUString(),
2083                             static_cast< cppu::OWeakObject * >( this ),
2084                             rArg.Sink ) ),
2085                     xEnv );
2086                 // Unreachable
2087             }
2088         }
2089     }
2090 
2091     return aRet;
2092 }
2093 
2094 //=========================================================================
2095 void Content::post(
2096                 const ucb::PostCommandArgument2 & rArg,
2097                 const uno::Reference< ucb::XCommandEnvironment > & xEnv )
2098     throw( uno::Exception )
2099 {
2100     uno::Reference< io::XActiveDataSink > xSink( rArg.Sink, uno::UNO_QUERY );
2101     if ( xSink.is() )
2102     {
2103         try
2104         {
2105             std::auto_ptr< DAVResourceAccess > xResAccess;
2106             {
2107                 osl::MutexGuard aGuard( m_aMutex );
2108                 xResAccess.reset(
2109                     new DAVResourceAccess( *m_xResAccess.get() ) );
2110             }
2111 
2112             uno::Reference< io::XInputStream > xResult
2113                 = xResAccess->POST( rArg.MediaType,
2114                                     rArg.Referer,
2115                                     rArg.Source,
2116                                     xEnv );
2117 
2118             {
2119                  osl::MutexGuard aGuard( m_aMutex );
2120                  m_xResAccess.reset(
2121                      new DAVResourceAccess( *xResAccess.get() ) );
2122             }
2123 
2124             xSink->setInputStream( xResult );
2125         }
2126         catch ( DAVException const & e )
2127         {
2128             cancelCommandExecution( e, xEnv, sal_True );
2129             // Unreachable
2130         }
2131     }
2132     else
2133     {
2134         uno::Reference< io::XOutputStream > xResult( rArg.Sink, uno::UNO_QUERY );
2135         if ( xResult.is() )
2136         {
2137             try
2138             {
2139                 std::auto_ptr< DAVResourceAccess > xResAccess;
2140                 {
2141                     osl::MutexGuard aGuard( m_aMutex );
2142                     xResAccess.reset(
2143                         new DAVResourceAccess( *m_xResAccess.get() ) );
2144                 }
2145 
2146                 xResAccess->POST( rArg.MediaType,
2147                                   rArg.Referer,
2148                                   rArg.Source,
2149                                   xResult,
2150                                   xEnv );
2151 
2152                 {
2153                     osl::MutexGuard aGuard( m_aMutex );
2154                     m_xResAccess.reset(
2155                         new DAVResourceAccess( *xResAccess.get() ) );
2156                 }
2157             }
2158             catch ( DAVException const & e )
2159             {
2160                 cancelCommandExecution( e, xEnv, sal_True );
2161                 // Unreachable
2162             }
2163         }
2164         else
2165         {
2166             ucbhelper::cancelCommandExecution(
2167                 uno::makeAny(
2168                     ucb::UnsupportedDataSinkException(
2169                         rtl::OUString(),
2170                         static_cast< cppu::OWeakObject * >( this ),
2171                         rArg.Sink ) ),
2172                 xEnv );
2173             // Unreachable
2174         }
2175     }
2176 }
2177 
2178 //=========================================================================
2179 void Content::queryChildren( ContentRefList& rChildren )
2180 {
2181     // Obtain a list with a snapshot of all currently instanciated contents
2182     // from provider and extract the contents which are direct children
2183     // of this content.
2184 
2185     ::ucbhelper::ContentRefList aAllContents;
2186     m_xProvider->queryExistingContents( aAllContents );
2187 
2188     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
2189     sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
2190 
2191     if ( nURLPos != ( aURL.getLength() - 1 ) )
2192     {
2193         // No trailing slash found. Append.
2194         aURL += rtl::OUString::createFromAscii( "/" );
2195     }
2196 
2197     sal_Int32 nLen = aURL.getLength();
2198 
2199     ::ucbhelper::ContentRefList::const_iterator it  = aAllContents.begin();
2200     ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end();
2201 
2202     while ( it != end )
2203     {
2204         ::ucbhelper::ContentImplHelperRef xChild = (*it);
2205         rtl::OUString aChildURL
2206             = xChild->getIdentifier()->getContentIdentifier();
2207 
2208         // Is aURL a prefix of aChildURL?
2209         if ( ( aChildURL.getLength() > nLen ) &&
2210              ( aChildURL.compareTo( aURL, nLen ) == 0 ) )
2211         {
2212             sal_Int32 nPos = nLen;
2213             nPos = aChildURL.indexOf( '/', nPos );
2214 
2215             if ( ( nPos == -1 ) ||
2216                  ( nPos == ( aChildURL.getLength() - 1 ) ) )
2217             {
2218                 // No further slashes / only a final slash. It's a child!
2219                 rChildren.push_back(
2220                     ::webdav_ucp::Content::ContentRef(
2221                         static_cast< ::webdav_ucp::Content * >(
2222                             xChild.get() ) ) );
2223             }
2224         }
2225         ++it;
2226     }
2227 }
2228 
2229 //=========================================================================
2230 void Content::insert(
2231         const uno::Reference< io::XInputStream > & xInputStream,
2232         sal_Bool bReplaceExisting,
2233         const uno::Reference< ucb::XCommandEnvironment >& Environment )
2234     throw( uno::Exception )
2235 {
2236     sal_Bool bTransient, bCollection;
2237     rtl::OUString aEscapedTitle;
2238     std::auto_ptr< DAVResourceAccess > xResAccess;
2239 
2240     {
2241         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2242 
2243         bTransient    = m_bTransient;
2244         bCollection   = m_bCollection;
2245         aEscapedTitle = m_aEscapedTitle;
2246         xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
2247     }
2248 
2249     // Check, if all required properties are present.
2250 
2251     if ( aEscapedTitle.getLength() == 0 )
2252     {
2253         OSL_ENSURE( sal_False, "Content::insert - Title missing!" );
2254 
2255         uno::Sequence< rtl::OUString > aProps( 1 );
2256         aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" );
2257         ucbhelper::cancelCommandExecution(
2258             uno::makeAny( ucb::MissingPropertiesException(
2259                                 rtl::OUString(),
2260                                 static_cast< cppu::OWeakObject * >( this ),
2261                                 aProps ) ),
2262             Environment );
2263         // Unreachable
2264     }
2265 
2266     if ( !bReplaceExisting )
2267     {
2268         /* [RFC 2616] - HTTP
2269 
2270            The PUT method requests that the enclosed entity be stored under the
2271            supplied Request-URI. If the Request-URI refers to an already
2272            existing resource, the enclosed entity SHOULD be considered as a
2273            modified version of the one residing on the origin server.
2274         */
2275 
2276         /* [RFC 2518] - WebDAV
2277 
2278            MKCOL creates a new collection resource at the location specified by
2279            the Request-URI.  If the resource identified by the Request-URI is
2280            non-null then the MKCOL MUST fail.
2281         */
2282 
2283         // ==> Complain on PUT, continue on MKCOL.
2284         if ( !bTransient || ( bTransient && !bCollection  ) )
2285         {
2286             ucb::UnsupportedNameClashException aEx(
2287                 rtl::OUString::createFromAscii(
2288                     "Unable to write without overwrite!" ),
2289                 static_cast< cppu::OWeakObject * >( this ),
2290                 ucb::NameClash::ERROR );
2291 
2292             uno::Reference< task::XInteractionHandler > xIH;
2293 
2294             if ( Environment.is() )
2295                 xIH = Environment->getInteractionHandler();
2296 
2297             if ( xIH.is() )
2298             {
2299                 uno::Any aExAsAny( uno::makeAny( aEx ) );
2300 
2301                 rtl::Reference< ucbhelper::SimpleInteractionRequest > xRequest
2302                     = new ucbhelper::SimpleInteractionRequest(
2303                         aExAsAny,
2304                         ucbhelper::CONTINUATION_APPROVE
2305                             | ucbhelper::CONTINUATION_DISAPPROVE );
2306                 xIH->handle( xRequest.get() );
2307 
2308                 const sal_Int32 nResp = xRequest->getResponse();
2309 
2310                 switch ( nResp )
2311                 {
2312                     case ucbhelper::CONTINUATION_UNKNOWN:
2313                         // Not handled; throw.
2314                         throw aEx;
2315 //                            break;
2316 
2317                     case ucbhelper::CONTINUATION_APPROVE:
2318                         // Continue -> Overwrite.
2319                         bReplaceExisting = sal_True;
2320                         break;
2321 
2322                     case ucbhelper::CONTINUATION_DISAPPROVE:
2323                         // Abort.
2324                         throw ucb::CommandFailedException(
2325                                     rtl::OUString(),
2326                                     uno::Reference< uno::XInterface >(),
2327                                     aExAsAny );
2328 //                            break;
2329 
2330                     default:
2331                         OSL_ENSURE( sal_False,
2332                                     "Content::insert - "
2333                                     "Unknown interaction selection!" );
2334                         throw ucb::CommandFailedException(
2335                                     rtl::OUString::createFromAscii(
2336                                         "Unknown interaction selection!" ),
2337                                     uno::Reference< uno::XInterface >(),
2338                                     aExAsAny );
2339 //                            break;
2340                 }
2341             }
2342             else
2343             {
2344                 // No IH; throw.
2345                 throw aEx;
2346             }
2347         }
2348     }
2349 
2350     if ( bTransient )
2351     {
2352         // Assemble new content identifier...
2353         rtl::OUString aURL = getParentURL();
2354         if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) )
2355             aURL += rtl::OUString::createFromAscii( "/" );
2356 
2357         aURL += aEscapedTitle;
2358 
2359         try
2360         {
2361             xResAccess->setURL( aURL );
2362 
2363             if ( bCollection )
2364                 xResAccess->MKCOL( Environment );
2365             else
2366                 xResAccess->PUT( xInputStream, Environment );
2367         }
2368         catch ( DAVException const & except )
2369         {
2370             if ( bCollection )
2371             {
2372                 if ( except.getStatus() == SC_METHOD_NOT_ALLOWED )
2373                 {
2374                     // [RFC 2518] - WebDAV
2375                     // 405 (Method Not Allowed) - MKCOL can only be
2376                     // executed on a deleted/non-existent resource.
2377 
2378                     if ( bReplaceExisting )
2379                     {
2380                         // Destroy old resource.
2381                         try
2382                         {
2383                             xResAccess->DESTROY( Environment );
2384                         }
2385                         catch ( DAVException const & e )
2386                         {
2387                             cancelCommandExecution( e, Environment, sal_True );
2388                             // Unreachable
2389                         }
2390 
2391                         // Insert (recursion!).
2392                         insert( xInputStream, bReplaceExisting, Environment );
2393 
2394                         {
2395                             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2396                             m_xResAccess.reset(
2397                                 new DAVResourceAccess( *xResAccess.get() ) );
2398                         }
2399 
2400                         // Success!
2401                         return;
2402                     }
2403                     else
2404                     {
2405                         rtl::OUString aTitle;
2406                         try
2407                         {
2408                             NeonUri aURI( aURL );
2409                             aTitle = aURI.GetPathBaseNameUnescaped();
2410                         }
2411                         catch ( DAVException const & )
2412                         {
2413                         }
2414 
2415                         ucbhelper::cancelCommandExecution(
2416                             uno::makeAny(
2417                                 ucb::NameClashException(
2418                                     rtl::OUString(),
2419                                     static_cast< cppu::OWeakObject * >( this ),
2420                                     task::InteractionClassification_ERROR,
2421                                     aTitle ) ),
2422                             Environment );
2423                         // Unreachable
2424                     }
2425                 }
2426             }
2427 
2428             cancelCommandExecution( except, Environment, sal_True );
2429             // Unreachable
2430         }
2431 
2432         {
2433             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2434             m_xIdentifier
2435                 = new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL );
2436         }
2437 
2438         inserted();
2439 
2440         {
2441             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2442             m_bTransient = sal_False;
2443         }
2444     }
2445     else
2446     {
2447         if ( !xInputStream.is() )
2448         {
2449             ucbhelper::cancelCommandExecution(
2450                 uno::makeAny(
2451                     ucb::MissingInputStreamException(
2452                         rtl::OUString(),
2453                         static_cast< cppu::OWeakObject * >( this ) ) ),
2454                 Environment );
2455             // Unreachable
2456         }
2457 
2458         try
2459         {
2460             xResAccess->PUT( xInputStream, Environment );
2461         }
2462         catch ( DAVException const & e )
2463         {
2464             cancelCommandExecution( e, Environment, sal_True );
2465             // Unreachable
2466         }
2467     }
2468 
2469     {
2470         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2471         m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2472     }
2473 }
2474 
2475 //=========================================================================
2476 void Content::transfer(
2477         const ucb::TransferInfo & rArgs,
2478         const uno::Reference< ucb::XCommandEnvironment >& Environment )
2479     throw( uno::Exception )
2480 {
2481     uno::Reference< lang::XMultiServiceFactory > xSMgr;
2482     uno::Reference< ucb::XContentIdentifier >    xIdentifier;
2483     uno::Reference< ucb::XContentProvider >      xProvider;
2484     std::auto_ptr< DAVResourceAccess > xResAccess;
2485 
2486     {
2487         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2488 
2489         xSMgr.set( m_xSMgr );
2490         xIdentifier.set( m_xIdentifier );
2491         xProvider.set( m_xProvider.get() );
2492         xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
2493     }
2494 
2495     rtl::OUString aTargetURI;
2496     try
2497     {
2498         NeonUri sourceURI( rArgs.SourceURL );
2499         NeonUri targetURI( xIdentifier->getContentIdentifier() );
2500         aTargetURI = targetURI.GetPathBaseNameUnescaped();
2501 
2502         // Check source's and target's URL scheme
2503         //
2504         const rtl::OUString aScheme = sourceURI.GetScheme().toAsciiLowerCase();
2505         if ( aScheme.equalsAsciiL(
2506                 RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) )
2507         {
2508             sourceURI.SetScheme(
2509                 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2510         }
2511         else if ( aScheme.equalsAsciiL(
2512                 RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) )
2513         {
2514             sourceURI.SetScheme(
2515                 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2516         }
2517         else if ( aScheme.equalsAsciiL(
2518                 RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) )
2519         {
2520             sourceURI.SetScheme(
2521                 rtl::OUString::createFromAscii( HTTPS_URL_SCHEME ) );
2522         }
2523         else
2524         {
2525             if ( !aScheme.equalsAsciiL(
2526                     RTL_CONSTASCII_STRINGPARAM( HTTP_URL_SCHEME ) ) &&
2527                  !aScheme.equalsAsciiL(
2528                     RTL_CONSTASCII_STRINGPARAM( HTTPS_URL_SCHEME ) ) )
2529             {
2530                 ucbhelper::cancelCommandExecution(
2531                     uno::makeAny(
2532                         ucb::InteractiveBadTransferURLException(
2533                             rtl::OUString::createFromAscii(
2534                                 "Unsupported URL scheme!" ),
2535                             static_cast< cppu::OWeakObject * >( this ) ) ),
2536                     Environment );
2537                 // Unreachable
2538             }
2539         }
2540 
2541         if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
2542                  RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) )
2543             targetURI.SetScheme(
2544                 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2545         else if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL(
2546                  RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) )
2547             targetURI.SetScheme(
2548                 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) );
2549 
2550         // @@@ This implementation of 'transfer' only works
2551         //     if the source and target are located at same host.
2552         //     (Neon does not support cross-server copy/move)
2553 
2554         // Check for same host
2555         //
2556         if ( sourceURI.GetHost().getLength() &&
2557              ( sourceURI.GetHost() != targetURI.GetHost() ) )
2558         {
2559             ucbhelper::cancelCommandExecution(
2560                 uno::makeAny( ucb::InteractiveBadTransferURLException(
2561                                 rtl::OUString::createFromAscii(
2562                                     "Different hosts!" ),
2563                                 static_cast< cppu::OWeakObject * >( this ) ) ),
2564                 Environment );
2565             // Unreachable
2566         }
2567 
2568         rtl::OUString aTitle = rArgs.NewTitle;
2569 
2570         if ( !aTitle.getLength() )
2571             aTitle = sourceURI.GetPathBaseNameUnescaped();
2572 
2573         if ( aTitle.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "/" ) ) )
2574         {
2575             // kso: ???
2576             aTitle = rtl::OUString();
2577         }
2578 
2579         targetURI.AppendPath( aTitle );
2580 
2581         rtl::OUString aTargetURL = xIdentifier->getContentIdentifier();
2582         if ( ( aTargetURL.lastIndexOf( '/' ) + 1 )
2583                 != aTargetURL.getLength() )
2584             aTargetURL += rtl::OUString::createFromAscii( "/" );
2585 
2586         aTargetURL += aTitle;
2587 
2588         uno::Reference< ucb::XContentIdentifier > xTargetId
2589             = new ::ucbhelper::ContentIdentifier( xSMgr, aTargetURL );
2590 
2591         DAVResourceAccess aSourceAccess( xSMgr,
2592                                          xResAccess->getSessionFactory(),
2593                                          sourceURI.GetURI() );
2594 
2595         if ( rArgs.MoveData == sal_True )
2596         {
2597             uno::Reference< ucb::XContentIdentifier > xId
2598                 = new ::ucbhelper::ContentIdentifier( xSMgr, rArgs.SourceURL );
2599 
2600             // Note: The static cast is okay here, because its sure that
2601             //       xProvider is always the WebDAVContentProvider.
2602             rtl::Reference< Content > xSource
2603                 = static_cast< Content * >(
2604                     xProvider->queryContent( xId ).get() );
2605 
2606             // [RFC 2518] - WebDAV
2607             // If a resource exists at the destination and the Overwrite
2608             // header is "T" then prior to performing the move the server
2609             // MUST perform a DELETE with "Depth: infinity" on the
2610             // destination resource.  If the Overwrite header is set to
2611             // "F" then the operation will fail.
2612 
2613             aSourceAccess.MOVE( sourceURI.GetPath(),
2614                                 targetURI.GetURI(),
2615                                 rArgs.NameClash
2616                                     == ucb::NameClash::OVERWRITE,
2617                                 Environment );
2618 
2619             if ( xSource.is() )
2620             {
2621                 // Propagate destruction to listeners.
2622                 xSource->destroy( sal_True );
2623             }
2624 
2625 // DAV resources store all additional props on server!
2626 //              // Rename own and all children's Additional Core Properties.
2627 //              renameAdditionalPropertySet( xId->getContentIdentifier(),
2628 //                                           xTargetId->getContentIdentifier(),
2629 //                                           sal_True );
2630         }
2631         else
2632         {
2633             // [RFC 2518] - WebDAV
2634             // If a resource exists at the destination and the Overwrite
2635             // header is "T" then prior to performing the copy the server
2636             // MUST perform a DELETE with "Depth: infinity" on the
2637             // destination resource.  If the Overwrite header is set to
2638             // "F" then the operation will fail.
2639 
2640             aSourceAccess.COPY( sourceURI.GetPath(),
2641                                 targetURI.GetURI(),
2642                                 rArgs.NameClash
2643                                     == ucb::NameClash::OVERWRITE,
2644                                 Environment );
2645 
2646 // DAV resources store all additional props on server!
2647 //              // Copy own and all children's Additional Core Properties.
2648 //              copyAdditionalPropertySet( xId->getContentIdentifier(),
2649 //                                         xTargetId->getContentIdentifier(),
2650 //                                         sal_True );
2651         }
2652 
2653         // Note: The static cast is okay here, because its sure that
2654         //       xProvider is always the WebDAVContentProvider.
2655         rtl::Reference< Content > xTarget
2656             = static_cast< Content * >(
2657                     xProvider->queryContent( xTargetId ).get() );
2658 
2659         // Announce transfered content in its new folder.
2660         xTarget->inserted();
2661     }
2662     catch ( ucb::IllegalIdentifierException const & )
2663     {
2664         // queryContent
2665     }
2666     catch ( DAVException const & e )
2667     {
2668         // [RFC 2518] - WebDAV
2669         // 412 (Precondition Failed) - The server was unable to maintain
2670         // the liveness of the properties listed in the propertybehavior
2671         // XML element or the Overwrite header is "F" and the state of
2672         // the destination resource is non-null.
2673 
2674         if ( e.getStatus() == SC_PRECONDITION_FAILED )
2675         {
2676             switch ( rArgs.NameClash )
2677             {
2678                 case ucb::NameClash::ERROR:
2679                 {
2680                     ucbhelper::cancelCommandExecution(
2681                         uno::makeAny(
2682                             ucb::NameClashException(
2683                                 rtl::OUString(),
2684                                 static_cast< cppu::OWeakObject * >( this ),
2685                                 task::InteractionClassification_ERROR,
2686                                 aTargetURI ) ),
2687                         Environment );
2688                     // Unreachable
2689                 }
2690 
2691                 case ucb::NameClash::OVERWRITE:
2692                     break;
2693 
2694                 case ucb::NameClash::KEEP: // deprecated
2695                 case ucb::NameClash::RENAME:
2696                 case ucb::NameClash::ASK:
2697                 default:
2698                 {
2699                     ucbhelper::cancelCommandExecution(
2700                         uno::makeAny(
2701                             ucb::UnsupportedNameClashException(
2702                                 rtl::OUString(),
2703                                 static_cast< cppu::OWeakObject * >( this ),
2704                                 rArgs.NameClash ) ),
2705                         Environment );
2706                     // Unreachable
2707                 }
2708             }
2709         }
2710 
2711         cancelCommandExecution( e, Environment, sal_True );
2712         // Unreachable
2713     }
2714 
2715     {
2716         osl::Guard< osl::Mutex > aGuard( m_aMutex );
2717         m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2718     }
2719 }
2720 
2721 //=========================================================================
2722 void Content::destroy( sal_Bool bDeletePhysical )
2723     throw( uno::Exception )
2724 {
2725     // @@@ take care about bDeletePhysical -> trashcan support
2726     rtl::OUString aURL = m_xIdentifier->getContentIdentifier();
2727 
2728     uno::Reference< ucb::XContent > xThis = this;
2729 
2730     deleted();
2731 
2732     osl::Guard< osl::Mutex > aGuard( m_aMutex );
2733 
2734     // Process instanciated children...
2735 
2736     ::webdav_ucp::Content::ContentRefList aChildren;
2737     queryChildren( aChildren );
2738 
2739     ContentRefList::const_iterator it  = aChildren.begin();
2740     ContentRefList::const_iterator end = aChildren.end();
2741 
2742     while ( it != end )
2743     {
2744         (*it)->destroy( bDeletePhysical );
2745         ++it;
2746     }
2747 }
2748 
2749 //=========================================================================
2750 bool Content::supportsExclusiveWriteLock(
2751   const uno::Reference< ucb::XCommandEnvironment >& Environment )
2752 {
2753     if ( getResourceType( Environment ) == DAV )
2754     {
2755         if ( m_xCachedProps.get() )
2756         {
2757             uno::Sequence< ucb::LockEntry > aSupportedLocks;
2758             if ( m_xCachedProps->getValue( DAVProperties::SUPPORTEDLOCK )
2759                 >>= aSupportedLocks )
2760             {
2761                 for ( sal_Int32 n = 0; n < aSupportedLocks.getLength(); ++n )
2762                 {
2763                     if ( aSupportedLocks[ n ].Scope
2764                             == ucb::LockScope_EXCLUSIVE &&
2765                          aSupportedLocks[ n ].Type
2766                             == ucb::LockType_WRITE )
2767                         return true;
2768                 }
2769             }
2770         }
2771     }
2772     return false;
2773 }
2774 
2775 //=========================================================================
2776 void Content::lock(
2777         const uno::Reference< ucb::XCommandEnvironment >& Environment )
2778     throw( uno::Exception )
2779 {
2780     try
2781     {
2782         std::auto_ptr< DAVResourceAccess > xResAccess;
2783         {
2784             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2785             xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
2786         }
2787 
2788         uno::Any aOwnerAny;
2789         aOwnerAny
2790             <<= rtl::OUString::createFromAscii( "http://ucb.openoffice.org" );
2791 
2792         ucb::Lock aLock(
2793             ucb::LockScope_EXCLUSIVE,
2794             ucb::LockType_WRITE,
2795             ucb::LockDepth_ZERO,
2796             aOwnerAny,
2797             180, // lock timeout in secs
2798             //-1, // infinite lock
2799             uno::Sequence< ::rtl::OUString >() );
2800 
2801         xResAccess->LOCK( aLock, Environment );
2802 
2803         {
2804             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2805             m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2806         }
2807     }
2808     catch ( DAVException const & e )
2809     {
2810         cancelCommandExecution( e, Environment, sal_False );
2811         // Unreachable
2812     }
2813 }
2814 
2815 //=========================================================================
2816 void Content::unlock(
2817         const uno::Reference< ucb::XCommandEnvironment >& Environment )
2818     throw( uno::Exception )
2819 {
2820     try
2821     {
2822         std::auto_ptr< DAVResourceAccess > xResAccess;
2823         {
2824             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2825             xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) );
2826         }
2827 
2828         xResAccess->UNLOCK( Environment );
2829 
2830         {
2831             osl::Guard< osl::Mutex > aGuard( m_aMutex );
2832             m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) );
2833         }
2834     }
2835     catch ( DAVException const & e )
2836     {
2837         cancelCommandExecution( e, Environment, sal_False );
2838         // Unreachable
2839     }
2840 }
2841 
2842 //=========================================================================
2843 sal_Bool Content::exchangeIdentity(
2844     const uno::Reference< ucb::XContentIdentifier >& xNewId )
2845 {
2846     if ( !xNewId.is() )
2847         return sal_False;
2848 
2849     osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
2850 
2851     uno::Reference< ucb::XContent > xThis = this;
2852 
2853     // Already persistent?
2854     if ( m_bTransient )
2855     {
2856         OSL_ENSURE( sal_False, "Content::exchangeIdentity - Not persistent!" );
2857         return sal_False;
2858     }
2859 
2860     // Exchange own identitity.
2861 
2862     // Fail, if a content with given id already exists.
2863 //  if ( !hasData( xNewId ) )
2864     {
2865         rtl::OUString aOldURL = m_xIdentifier->getContentIdentifier();
2866 
2867         aGuard.clear();
2868         if ( exchange( xNewId ) )
2869         {
2870             // Process instanciated children...
2871 
2872             ContentRefList aChildren;
2873             queryChildren( aChildren );
2874 
2875             ContentRefList::const_iterator it  = aChildren.begin();
2876             ContentRefList::const_iterator end = aChildren.end();
2877 
2878             while ( it != end )
2879             {
2880                 ContentRef xChild = (*it);
2881 
2882                 // Create new content identifier for the child...
2883                 uno::Reference< ucb::XContentIdentifier >
2884                     xOldChildId = xChild->getIdentifier();
2885                 rtl::OUString aOldChildURL
2886                     = xOldChildId->getContentIdentifier();
2887                 rtl::OUString aNewChildURL
2888                     = aOldChildURL.replaceAt(
2889                         0,
2890                         aOldURL.getLength(),
2891                         xNewId->getContentIdentifier() );
2892                 uno::Reference< ucb::XContentIdentifier > xNewChildId
2893                     = new ::ucbhelper::ContentIdentifier(
2894                         m_xSMgr, aNewChildURL );
2895 
2896                 if ( !xChild->exchangeIdentity( xNewChildId ) )
2897                     return sal_False;
2898 
2899                 ++it;
2900             }
2901             return sal_True;
2902         }
2903     }
2904 
2905     OSL_ENSURE( sal_False,
2906                 "Content::exchangeIdentity - "
2907                 "Panic! Cannot exchange identity!" );
2908     return sal_False;
2909 }
2910 
2911 //=========================================================================
2912 sal_Bool Content::isFolder(
2913             const uno::Reference< ucb::XCommandEnvironment >& xEnv )
2914     throw( uno::Exception )
2915 {
2916     {
2917         osl::MutexGuard aGuard( m_aMutex );
2918 
2919         if ( m_bTransient )
2920             return m_bCollection;
2921     }
2922 
2923     uno::Sequence< beans::Property > aProperties( 1 );
2924     aProperties[ 0 ].Name   = rtl::OUString::createFromAscii( "IsFolder" );
2925     aProperties[ 0 ].Handle = -1;
2926     uno::Reference< sdbc::XRow > xRow( getPropertyValues( aProperties, xEnv ) );
2927     if ( xRow.is() )
2928     {
2929         try
2930         {
2931             return xRow->getBoolean( 1 );
2932         }
2933         catch ( sdbc::SQLException const & )
2934         {
2935         }
2936     }
2937 
2938     return sal_False;
2939 }
2940 
2941 //=========================================================================
2942 uno::Any Content::MapDAVException( const DAVException & e, sal_Bool bWrite )
2943 {
2944     // Map DAVException...
2945     uno::Any aException;
2946 
2947     rtl::OUString aURL;
2948     if ( m_bTransient )
2949     {
2950         aURL = getParentURL();
2951         if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) )
2952             aURL += rtl::OUString::createFromAscii( "/" );
2953 
2954         aURL += m_aEscapedTitle;
2955     }
2956     else
2957     {
2958         aURL = m_xIdentifier->getContentIdentifier();
2959     }
2960 
2961     switch ( e.getStatus() )
2962     {
2963         case SC_NOT_FOUND:
2964         {
2965             uno::Sequence< uno::Any > aArgs( 1 );
2966             aArgs[ 0 ] <<= beans::PropertyValue(
2967                 rtl::OUString::createFromAscii("Uri"), -1,
2968                 uno::makeAny(aURL),
2969                 beans::PropertyState_DIRECT_VALUE);
2970 
2971             aException <<=
2972                 ucb::InteractiveAugmentedIOException(
2973                     rtl::OUString::createFromAscii( "Not found!" ),
2974                     static_cast< cppu::OWeakObject * >( this ),
2975                     task::InteractionClassification_ERROR,
2976                     ucb::IOErrorCode_NOT_EXISTING,
2977                     aArgs );
2978             return aException;
2979         }
2980         default:
2981             break;
2982     }
2983 
2984     switch ( e.getError() )
2985     {
2986     case DAVException::DAV_HTTP_ERROR:
2987         {
2988             if ( bWrite )
2989                 aException <<=
2990                     ucb::InteractiveNetworkWriteException(
2991                         e.getData(),
2992                         static_cast< cppu::OWeakObject * >( this ),
2993                         task::InteractionClassification_ERROR,
2994                         e.getData() );
2995             else
2996                 aException <<=
2997                     ucb::InteractiveNetworkReadException(
2998                         e.getData(),
2999                         static_cast< cppu::OWeakObject * >( this ),
3000                         task::InteractionClassification_ERROR,
3001                         e.getData() );
3002             break;
3003         }
3004 
3005     case DAVException::DAV_HTTP_LOOKUP:
3006         aException <<=
3007             ucb::InteractiveNetworkResolveNameException(
3008                 rtl::OUString(),
3009                 static_cast< cppu::OWeakObject * >( this ),
3010                 task::InteractionClassification_ERROR,
3011                 e.getData() );
3012         break;
3013 
3014 // @@@ No matching InteractiveNetwork*Exception
3015 //    case DAVException::DAV_HTTP_AUTH:
3016 //        break;
3017 
3018 // @@@ No matching InteractiveNetwork*Exception
3019 //    case DAVException::DAV_HTTP_AUTHPROXY:
3020 //        break;
3021 
3022     case DAVException::DAV_HTTP_CONNECT:
3023         aException <<=
3024             ucb::InteractiveNetworkConnectException(
3025                 rtl::OUString(),
3026                 static_cast< cppu::OWeakObject * >( this ),
3027                 task::InteractionClassification_ERROR,
3028                 e.getData() );
3029         break;
3030 
3031 // @@@ No matching InteractiveNetwork*Exception
3032 //    case DAVException::DAV_HTTP_TIMEOUT:
3033 //        break;
3034 
3035 // @@@ No matching InteractiveNetwork*Exception
3036 //     case DAVException::DAV_HTTP_REDIRECT:
3037 //         break;
3038 
3039 // @@@ No matching InteractiveNetwork*Exception
3040 //     case DAVException::DAV_SESSION_CREATE:
3041 //         break;
3042 
3043     case DAVException::DAV_INVALID_ARG:
3044         aException <<=
3045             lang::IllegalArgumentException(
3046                 rtl::OUString(),
3047                 static_cast< cppu::OWeakObject * >( this ),
3048                 -1 );
3049         break;
3050 
3051     case DAVException::DAV_LOCKED:
3052 #if 1
3053         aException <<=
3054             ucb::InteractiveLockingLockedException(
3055                 rtl::OUString::createFromAscii( "Locked!" ),
3056                 static_cast< cppu::OWeakObject * >( this ),
3057                 task::InteractionClassification_ERROR,
3058                 aURL,
3059                 sal_False ); // not SelfOwned
3060 #else
3061         {
3062             uno::Sequence< uno::Any > aArgs( 1 );
3063             aArgs[ 0 ] <<= beans::PropertyValue(
3064                 rtl::OUString::createFromAscii("Uri"), -1,
3065                 uno::makeAny(aURL),
3066                 beans::PropertyState_DIRECT_VALUE);
3067 
3068             aException <<=
3069                 ucb::InteractiveAugmentedIOException(
3070                     rtl::OUString::createFromAscii( "Locked!" ),
3071                     static_cast< cppu::OWeakObject * >( this ),
3072                     task::InteractionClassification_ERROR,
3073                     ucb::IOErrorCode_LOCKING_VIOLATION,
3074                     aArgs );
3075         }
3076 #endif
3077         break;
3078 
3079     case DAVException::DAV_LOCKED_SELF:
3080         aException <<=
3081             ucb::InteractiveLockingLockedException(
3082                 rtl::OUString::createFromAscii( "Locked (self)!" ),
3083                 static_cast< cppu::OWeakObject * >( this ),
3084                 task::InteractionClassification_ERROR,
3085                 aURL,
3086                 sal_True ); // SelfOwned
3087         break;
3088 
3089     case DAVException::DAV_NOT_LOCKED:
3090         aException <<=
3091             ucb::InteractiveLockingNotLockedException(
3092                 rtl::OUString::createFromAscii( "Not locked!" ),
3093                 static_cast< cppu::OWeakObject * >( this ),
3094                 task::InteractionClassification_ERROR,
3095                 aURL );
3096         break;
3097 
3098     case DAVException::DAV_LOCK_EXPIRED:
3099         aException <<=
3100             ucb::InteractiveLockingLockExpiredException(
3101                 rtl::OUString::createFromAscii( "Lock expired!" ),
3102                 static_cast< cppu::OWeakObject * >( this ),
3103                 task::InteractionClassification_ERROR,
3104                 aURL );
3105         break;
3106 
3107     default:
3108         aException <<=
3109             ucb::InteractiveNetworkGeneralException(
3110                 rtl::OUString(),
3111                 static_cast< cppu::OWeakObject * >( this ),
3112                 task::InteractionClassification_ERROR );
3113         break;
3114     }
3115 
3116     return aException;
3117 }
3118 
3119 //=========================================================================
3120 // static
3121 bool Content::shouldAccessNetworkAfterException( const DAVException & e )
3122 {
3123     if ( ( e.getStatus() == SC_NOT_FOUND ) ||
3124          ( e.getError() == DAVException::DAV_HTTP_LOOKUP ) ||
3125          ( e.getError() == DAVException::DAV_HTTP_CONNECT ) ||
3126          ( e.getError() == DAVException::DAV_HTTP_AUTH ) ||
3127          ( e.getError() == DAVException::DAV_HTTP_AUTHPROXY ) )
3128         return false;
3129 
3130     return true;
3131 }
3132 
3133 //=========================================================================
3134 void Content::cancelCommandExecution(
3135                 const DAVException & e,
3136                 const uno::Reference< ucb::XCommandEnvironment > & xEnv,
3137                 sal_Bool bWrite /* = sal_False */ )
3138     throw ( uno::Exception )
3139 {
3140     ucbhelper::cancelCommandExecution( MapDAVException( e, bWrite ), xEnv );
3141     // Unreachable
3142 }
3143 
3144 //=========================================================================
3145 const rtl::OUString
3146 Content::getBaseURI( const std::auto_ptr< DAVResourceAccess > & rResAccess )
3147 {
3148     osl::Guard< osl::Mutex > aGuard( m_aMutex );
3149 
3150     // First, try to obtain value of response header "Content-Location".
3151     if ( m_xCachedProps.get() )
3152     {
3153         rtl::OUString aLocation;
3154         m_xCachedProps->getValue( rtl::OUString(
3155                                     RTL_CONSTASCII_USTRINGPARAM(
3156                                         "Content-Location" ) ) ) >>= aLocation;
3157         if ( aLocation.getLength() )
3158         {
3159             try
3160             {
3161                 // Do not use m_xIdentifier->getContentIdentifier() because it
3162                 // for example does not reflect redirects applied to requests
3163                 // done using the original URI but m_xResAccess' URI does.
3164                 return rtl::Uri::convertRelToAbs( rResAccess->getURL(),
3165                                                   aLocation );
3166             }
3167             catch ( rtl::MalformedUriException const & )
3168             {
3169             }
3170         }
3171     }
3172 
3173     return rtl::OUString( rResAccess->getURL() );
3174 }
3175 
3176 //=========================================================================
3177 const Content::ResourceType & Content::getResourceType(
3178                     const uno::Reference< ucb::XCommandEnvironment >& xEnv,
3179                     const std::auto_ptr< DAVResourceAccess > & rResAccess )
3180     throw ( uno::Exception )
3181 {
3182     if ( m_eResourceType == UNKNOWN )
3183     {
3184         osl::Guard< osl::Mutex > aGuard( m_aMutex );
3185 
3186         ResourceType eResourceType;
3187         eResourceType = m_eResourceType;
3188 
3189         const rtl::OUString & rURL = rResAccess->getURL();
3190         const rtl::OUString aScheme(
3191             rURL.copy( 0, rURL.indexOf( ':' ) ).toAsciiLowerCase() );
3192 
3193         if ( aScheme.equalsAsciiL(
3194                 RTL_CONSTASCII_STRINGPARAM( FTP_URL_SCHEME ) ) )
3195         {
3196             eResourceType = FTP;
3197         }
3198         else
3199         {
3200             try
3201             {
3202                 // Try to fetch some frequently used property value, e.g. those
3203                 // used when loading documents... along with identifying whether
3204                 // this is a DAV resource.
3205                 std::vector< DAVResource > resources;
3206                 std::vector< rtl::OUString > aPropNames;
3207                 uno::Sequence< beans::Property > aProperties( 5 );
3208                 aProperties[ 0 ].Name
3209                     = rtl::OUString::createFromAscii( "IsFolder" );
3210                 aProperties[ 1 ].Name
3211                     = rtl::OUString::createFromAscii( "IsDocument" );
3212                 aProperties[ 2 ].Name
3213                     = rtl::OUString::createFromAscii( "IsReadOnly" );
3214                 aProperties[ 3 ].Name
3215                     = rtl::OUString::createFromAscii( "MediaType" );
3216                 aProperties[ 4 ].Name
3217                     = DAVProperties::SUPPORTEDLOCK;
3218 
3219                 ContentProperties::UCBNamesToDAVNames(
3220                     aProperties, aPropNames );
3221 
3222                 rResAccess->PROPFIND(
3223                     DAVZERO, aPropNames, resources, xEnv );
3224 
3225                 if ( resources.size() == 1 )
3226                 {
3227                     m_xCachedProps.reset(
3228                         new CachableContentProperties( resources[ 0 ] ) );
3229                     m_xCachedProps->containsAllNames(
3230                         aProperties, m_aFailedPropNames );
3231                 }
3232 
3233                 eResourceType = DAV;
3234             }
3235             catch ( DAVException const & e )
3236             {
3237                 rResAccess->resetUri();
3238 
3239                 if ( e.getStatus() == SC_METHOD_NOT_ALLOWED )
3240                 {
3241                     // Status SC_METHOD_NOT_ALLOWED is a safe indicator that the
3242                     // resource is NON_DAV
3243                     eResourceType = NON_DAV;
3244                 }
3245             }
3246         }
3247         m_eResourceType = eResourceType;
3248     }
3249     return m_eResourceType;
3250 }
3251 
3252 //=========================================================================
3253 const Content::ResourceType & Content::getResourceType(
3254                     const uno::Reference< ucb::XCommandEnvironment >& xEnv )
3255     throw ( uno::Exception )
3256 {
3257     return getResourceType( xEnv, m_xResAccess );
3258 }
3259