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