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