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