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