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