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