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