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 #include <rtl/uri.hxx> 27 #include <rtl/ustrbuf.hxx> 28 #include <osl/file.hxx> 29 30 #include "osl/diagnose.h" 31 #include <com/sun/star/ucb/OpenMode.hpp> 32 #ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBBUTE_HPP_ 33 #include <com/sun/star/beans/PropertyAttribute.hpp> 34 #endif 35 #include <com/sun/star/ucb/XProgressHandler.hpp> 36 #include <com/sun/star/task/XInteractionHandler.hpp> 37 #include <com/sun/star/io/XActiveDataStreamer.hpp> 38 #include <com/sun/star/io/XOutputStream.hpp> 39 #include <com/sun/star/ucb/NumberedSortingInfo.hpp> 40 #include <com/sun/star/io/XActiveDataSink.hpp> 41 #include <com/sun/star/beans/PropertyChangeEvent.hpp> 42 #include <com/sun/star/beans/PropertySetInfoChange.hpp> 43 #include <com/sun/star/ucb/ContentAction.hpp> 44 #include <com/sun/star/ucb/NameClash.hpp> 45 #include "filglob.hxx" 46 #include "filid.hxx" 47 #include "filrow.hxx" 48 #include "bc.hxx" 49 #include "prov.hxx" 50 #ifndef _FILERROR_HXX_ 51 #include "filerror.hxx" 52 #endif 53 #include "filinsreq.hxx" 54 55 56 using namespace fileaccess; 57 using namespace com::sun::star; 58 using namespace com::sun::star::uno; 59 using namespace com::sun::star::ucb; 60 61 // PropertyListeners 62 63 64 typedef cppu::OMultiTypeInterfaceContainerHelperVar< rtl::OUString,hashOUString,equalOUString > 65 PropertyListeners_impl; 66 67 class fileaccess::PropertyListeners 68 : public PropertyListeners_impl 69 { 70 public: 71 PropertyListeners( ::osl::Mutex& aMutex ) 72 : PropertyListeners_impl( aMutex ) 73 { 74 } 75 }; 76 77 78 /****************************************************************************************/ 79 /* */ 80 /* BaseContent */ 81 /* */ 82 /****************************************************************************************/ 83 84 //////////////////////////////////////////////////////////////////////////////// 85 // Private Constructor for just inserted Contents 86 87 BaseContent::BaseContent( shell* pMyShell, 88 const rtl::OUString& parentName, 89 sal_Bool bFolder ) 90 : m_pMyShell( pMyShell ), 91 m_xContentIdentifier( 0 ), 92 m_aUncPath( parentName ), 93 m_bFolder( bFolder ), 94 m_nState( JustInserted ), 95 m_pDisposeEventListeners( 0 ), 96 m_pContentEventListeners( 0 ), 97 m_pPropertySetInfoChangeListeners( 0 ), 98 m_pPropertyListener( 0 ) 99 { 100 m_pMyShell->m_pProvider->acquire(); 101 // No registering, since we have no name 102 } 103 104 105 //////////////////////////////////////////////////////////////////////////////// 106 // Constructor for full featured Contents 107 108 BaseContent::BaseContent( shell* pMyShell, 109 const Reference< XContentIdentifier >& xContentIdentifier, 110 const rtl::OUString& aUncPath ) 111 : m_pMyShell( pMyShell ), 112 m_xContentIdentifier( xContentIdentifier ), 113 m_aUncPath( aUncPath ), 114 m_bFolder( false ), 115 m_nState( FullFeatured ), 116 m_pDisposeEventListeners( 0 ), 117 m_pContentEventListeners( 0 ), 118 m_pPropertySetInfoChangeListeners( 0 ), 119 m_pPropertyListener( 0 ) 120 { 121 m_pMyShell->m_pProvider->acquire(); 122 m_pMyShell->registerNotifier( m_aUncPath,this ); 123 m_pMyShell->insertDefaultProperties( m_aUncPath ); 124 } 125 126 127 BaseContent::~BaseContent( ) 128 { 129 if( ( m_nState & FullFeatured ) || ( m_nState & Deleted ) ) 130 { 131 m_pMyShell->deregisterNotifier( m_aUncPath,this ); 132 } 133 m_pMyShell->m_pProvider->release(); 134 135 delete m_pDisposeEventListeners; 136 delete m_pContentEventListeners; 137 delete m_pPropertyListener; 138 delete m_pPropertySetInfoChangeListeners; 139 } 140 141 142 ////////////////////////////////////////////////////////////////////////// 143 // XInterface 144 ////////////////////////////////////////////////////////////////////////// 145 146 void SAL_CALL 147 BaseContent::acquire( void ) 148 throw() 149 { 150 OWeakObject::acquire(); 151 } 152 153 154 void SAL_CALL 155 BaseContent::release( void ) 156 throw() 157 { 158 OWeakObject::release(); 159 } 160 161 162 Any SAL_CALL 163 BaseContent::queryInterface( const Type& rType ) 164 throw( RuntimeException ) 165 { 166 Any aRet = cppu::queryInterface( rType, 167 SAL_STATIC_CAST( lang::XComponent*, this ), 168 SAL_STATIC_CAST( lang::XTypeProvider*, this ), 169 SAL_STATIC_CAST( lang::XServiceInfo*, this ), 170 SAL_STATIC_CAST( XCommandProcessor*, this ), 171 SAL_STATIC_CAST( container::XChild*, this ), 172 SAL_STATIC_CAST( beans::XPropertiesChangeNotifier*, this ), 173 SAL_STATIC_CAST( beans::XPropertyContainer*, this ), 174 SAL_STATIC_CAST( XContentCreator*,this ), 175 SAL_STATIC_CAST( beans::XPropertySetInfoChangeNotifier*, this ), 176 SAL_STATIC_CAST( XContent*,this) ); 177 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); 178 } 179 180 181 182 183 ////////////////////////////////////////////////////////////////////////////////////////// 184 // XComponent 185 //////////////////////////////////////////////////////////////////////////////////////// 186 187 void SAL_CALL 188 BaseContent::addEventListener( const Reference< lang::XEventListener >& Listener ) 189 throw( RuntimeException ) 190 { 191 osl::MutexGuard aGuard( m_aMutex ); 192 193 if ( ! m_pDisposeEventListeners ) 194 m_pDisposeEventListeners = 195 new cppu::OInterfaceContainerHelper( m_aEventListenerMutex ); 196 197 m_pDisposeEventListeners->addInterface( Listener ); 198 } 199 200 201 void SAL_CALL 202 BaseContent::removeEventListener( const Reference< lang::XEventListener >& Listener ) 203 throw( RuntimeException ) 204 { 205 osl::MutexGuard aGuard( m_aMutex ); 206 207 if ( m_pDisposeEventListeners ) 208 m_pDisposeEventListeners->removeInterface( Listener ); 209 } 210 211 212 void SAL_CALL 213 BaseContent::dispose() 214 throw( RuntimeException ) 215 { 216 lang::EventObject aEvt; 217 cppu::OInterfaceContainerHelper* pDisposeEventListeners; 218 cppu::OInterfaceContainerHelper* pContentEventListeners; 219 cppu::OInterfaceContainerHelper* pPropertySetInfoChangeListeners; 220 PropertyListeners* pPropertyListener; 221 222 { 223 osl::MutexGuard aGuard( m_aMutex ); 224 aEvt.Source = static_cast< XContent* >( this ); 225 226 227 pDisposeEventListeners = 228 m_pDisposeEventListeners, m_pDisposeEventListeners = 0; 229 230 pContentEventListeners = 231 m_pContentEventListeners, m_pContentEventListeners = 0; 232 233 pPropertySetInfoChangeListeners = 234 m_pPropertySetInfoChangeListeners, 235 m_pPropertySetInfoChangeListeners = 0; 236 237 pPropertyListener = 238 m_pPropertyListener, m_pPropertyListener = 0; 239 } 240 241 if ( pDisposeEventListeners && pDisposeEventListeners->getLength() ) 242 pDisposeEventListeners->disposeAndClear( aEvt ); 243 244 if ( pContentEventListeners && pContentEventListeners->getLength() ) 245 pContentEventListeners->disposeAndClear( aEvt ); 246 247 if( pPropertyListener ) 248 pPropertyListener->disposeAndClear( aEvt ); 249 250 if( pPropertySetInfoChangeListeners ) 251 pPropertySetInfoChangeListeners->disposeAndClear( aEvt ); 252 253 delete pDisposeEventListeners; 254 delete pContentEventListeners; 255 delete pPropertyListener; 256 delete pPropertySetInfoChangeListeners; 257 } 258 259 260 261 ////////////////////////////////////////////////////////////////////////////////////////// 262 // XServiceInfo 263 ////////////////////////////////////////////////////////////////////////////////////////// 264 265 rtl::OUString SAL_CALL 266 BaseContent::getImplementationName() 267 throw( RuntimeException) 268 { 269 return rtl::OUString::createFromAscii( "com.sun.star.comp.ucb.FileContent" ); 270 } 271 272 273 274 sal_Bool SAL_CALL 275 BaseContent::supportsService( const rtl::OUString& ServiceName ) 276 throw( RuntimeException) 277 { 278 if( ServiceName.compareToAscii( "com.sun.star.ucb.FileContent" ) == 0 ) 279 return true; 280 else 281 return false; 282 } 283 284 285 286 Sequence< rtl::OUString > SAL_CALL 287 BaseContent::getSupportedServiceNames() 288 throw( RuntimeException ) 289 { 290 Sequence< rtl::OUString > ret( 1 ); 291 ret[0] = rtl::OUString::createFromAscii( "com.sun.star.ucb.FileContent" ); 292 return ret; 293 } 294 295 296 297 ////////////////////////////////////////////////////////////////////////////////////////// 298 // XTypeProvider 299 ////////////////////////////////////////////////////////////////////////////////////////// 300 301 XTYPEPROVIDER_IMPL_10( BaseContent, 302 lang::XComponent, 303 lang::XTypeProvider, 304 lang::XServiceInfo, 305 XCommandProcessor, 306 XContentCreator, 307 XContent, 308 container::XChild, 309 beans::XPropertiesChangeNotifier, 310 beans::XPropertyContainer, 311 beans::XPropertySetInfoChangeNotifier ) 312 313 314 ////////////////////////////////////////////////////////////////////////////////////////// 315 // XCommandProcessor 316 ////////////////////////////////////////////////////////////////////////////////////////// 317 318 sal_Int32 SAL_CALL 319 BaseContent::createCommandIdentifier( void ) 320 throw( RuntimeException ) 321 { 322 return m_pMyShell->getCommandId(); 323 } 324 325 326 void SAL_CALL 327 BaseContent::abort( sal_Int32 CommandId ) 328 throw( RuntimeException ) 329 { 330 m_pMyShell->abort( CommandId ); 331 } 332 333 334 Any SAL_CALL 335 BaseContent::execute( const Command& aCommand, 336 sal_Int32 CommandId, 337 const Reference< XCommandEnvironment >& Environment ) 338 throw( Exception, 339 CommandAbortedException, 340 RuntimeException ) 341 { 342 if( ! CommandId ) 343 // A Command with commandid zero cannot be aborted 344 CommandId = createCommandIdentifier(); 345 346 m_pMyShell->startTask( CommandId, 347 Environment ); 348 349 Any aAny; 350 351 if( ! aCommand.Name.compareToAscii( "getPropertySetInfo" ) ) // No exceptions 352 { 353 aAny <<= getPropertySetInfo( CommandId ); 354 } 355 else if( ! aCommand.Name.compareToAscii( "getCommandInfo" ) ) // no exceptions 356 { 357 aAny <<= getCommandInfo(); 358 } 359 else if( ! aCommand.Name.compareToAscii( "setPropertyValues" ) ) 360 { 361 Sequence< beans::PropertyValue > sPropertyValues; 362 363 if( ! ( aCommand.Argument >>= sPropertyValues ) ) 364 m_pMyShell->installError( CommandId, 365 TASKHANDLING_WRONG_SETPROPERTYVALUES_ARGUMENT ); 366 else 367 aAny <<= setPropertyValues( CommandId,sPropertyValues ); // calls endTask by itself 368 } 369 else if( ! aCommand.Name.compareToAscii( "getPropertyValues" ) ) 370 { 371 Sequence< beans::Property > ListOfRequestedProperties; 372 373 if( ! ( aCommand.Argument >>= ListOfRequestedProperties ) ) 374 m_pMyShell->installError( CommandId, 375 TASKHANDLING_WRONG_GETPROPERTYVALUES_ARGUMENT ); 376 else 377 aAny <<= getPropertyValues( CommandId, 378 ListOfRequestedProperties ); 379 } 380 else if( ! aCommand.Name.compareToAscii( "open" ) ) 381 { 382 OpenCommandArgument2 aOpenArgument; 383 if( ! ( aCommand.Argument >>= aOpenArgument ) ) 384 m_pMyShell->installError( CommandId, 385 TASKHANDLING_WRONG_OPEN_ARGUMENT ); 386 else 387 { 388 Reference< XDynamicResultSet > result = open( CommandId,aOpenArgument ); 389 if( result.is() ) 390 aAny <<= result; 391 } 392 } 393 else if( ! aCommand.Name.compareToAscii( "delete" ) ) 394 { 395 if( ! aCommand.Argument.has< sal_Bool >() ) 396 m_pMyShell->installError( CommandId, 397 TASKHANDLING_WRONG_DELETE_ARGUMENT ); 398 else 399 deleteContent( CommandId ); 400 } 401 else if( ! aCommand.Name.compareToAscii( "transfer" ) ) 402 { 403 TransferInfo aTransferInfo; 404 if( ! ( aCommand.Argument >>= aTransferInfo ) ) 405 m_pMyShell->installError( CommandId, 406 TASKHANDLING_WRONG_TRANSFER_ARGUMENT ); 407 else 408 transfer( CommandId, aTransferInfo ); 409 } 410 else if( ! aCommand.Name.compareToAscii( "insert" ) ) 411 { 412 InsertCommandArgument aInsertArgument; 413 if( ! ( aCommand.Argument >>= aInsertArgument ) ) 414 m_pMyShell->installError( CommandId, 415 TASKHANDLING_WRONG_INSERT_ARGUMENT ); 416 else 417 insert( CommandId,aInsertArgument ); 418 } 419 else if( ! aCommand.Name.compareToAscii( "getCasePreservingURL" ) ) 420 { 421 Sequence< beans::Property > seq(1); 422 seq[0] = beans::Property( 423 rtl::OUString::createFromAscii("CasePreservingURL"), 424 -1, 425 getCppuType( static_cast< sal_Bool* >(0) ), 426 0 ); 427 Reference< sdbc::XRow > xRow = getPropertyValues( CommandId,seq ); 428 rtl::OUString CasePreservingURL = xRow->getString(1); 429 if(!xRow->wasNull()) 430 aAny <<= CasePreservingURL; 431 } 432 else if( ! aCommand.Name.compareToAscii( "createNewContent" ) ) 433 { 434 ucb::ContentInfo aArg; 435 if ( !( aCommand.Argument >>= aArg ) ) 436 m_pMyShell->installError( CommandId, 437 TASKHANDLING_WRONG_CREATENEWCONTENT_ARGUMENT ); 438 else 439 aAny <<= createNewContent( aArg ); 440 } 441 else 442 m_pMyShell->installError( CommandId, 443 TASKHANDLER_UNSUPPORTED_COMMAND ); 444 445 446 // This is the only function allowed to throw an exception 447 endTask( CommandId ); 448 449 return aAny; 450 } 451 452 453 454 void SAL_CALL 455 BaseContent::addPropertiesChangeListener( 456 const Sequence< rtl::OUString >& PropertyNames, 457 const Reference< beans::XPropertiesChangeListener >& Listener ) 458 throw( RuntimeException ) 459 { 460 if( ! Listener.is() ) 461 return; 462 463 osl::MutexGuard aGuard( m_aMutex ); 464 465 if( ! m_pPropertyListener ) 466 m_pPropertyListener = new PropertyListeners( m_aEventListenerMutex ); 467 468 469 if( PropertyNames.getLength() == 0 ) 470 m_pPropertyListener->addInterface( rtl::OUString(),Listener ); 471 else 472 { 473 Reference< beans::XPropertySetInfo > xProp = m_pMyShell->info_p( m_aUncPath ); 474 for( sal_Int32 i = 0; i < PropertyNames.getLength(); ++i ) 475 if( xProp->hasPropertyByName( PropertyNames[i] ) ) 476 m_pPropertyListener->addInterface( PropertyNames[i],Listener ); 477 } 478 } 479 480 481 void SAL_CALL 482 BaseContent::removePropertiesChangeListener( const Sequence< rtl::OUString >& PropertyNames, 483 const Reference< beans::XPropertiesChangeListener >& Listener ) 484 throw( RuntimeException ) 485 { 486 if( ! Listener.is() ) 487 return; 488 489 osl::MutexGuard aGuard( m_aMutex ); 490 491 if( ! m_pPropertyListener ) 492 return; 493 494 for( sal_Int32 i = 0; i < PropertyNames.getLength(); ++i ) 495 m_pPropertyListener->removeInterface( PropertyNames[i],Listener ); 496 497 m_pPropertyListener->removeInterface( rtl::OUString(), Listener ); 498 } 499 500 501 ///////////////////////////////////////////////////////////////////////////////////////// 502 // XContent 503 ///////////////////////////////////////////////////////////////////////////////////////// 504 505 Reference< ucb::XContentIdentifier > SAL_CALL 506 BaseContent::getIdentifier() 507 throw( RuntimeException ) 508 { 509 return m_xContentIdentifier; 510 } 511 512 513 rtl::OUString SAL_CALL 514 BaseContent::getContentType() 515 throw( RuntimeException ) 516 { 517 if( !( m_nState & Deleted ) ) 518 { 519 if( m_nState & JustInserted ) 520 { 521 if ( m_bFolder ) 522 return m_pMyShell->FolderContentType; 523 else 524 return m_pMyShell->FileContentType; 525 } 526 else 527 { 528 try 529 { 530 // Who am I ? 531 Sequence< beans::Property > seq(1); 532 seq[0] = beans::Property( rtl::OUString::createFromAscii("IsDocument"), 533 -1, 534 getCppuType( static_cast< sal_Bool* >(0) ), 535 0 ); 536 Reference< sdbc::XRow > xRow = getPropertyValues( -1,seq ); 537 sal_Bool IsDocument = xRow->getBoolean( 1 ); 538 539 if ( !xRow->wasNull() ) 540 { 541 if ( IsDocument ) 542 return m_pMyShell->FileContentType; 543 else 544 return m_pMyShell->FolderContentType; 545 } 546 else 547 { 548 OSL_ENSURE( false, 549 "BaseContent::getContentType - Property value was null!" ); 550 } 551 } 552 catch ( sdbc::SQLException const & ) 553 { 554 OSL_ENSURE( false, 555 "BaseContent::getContentType - Caught SQLException!" ); 556 } 557 } 558 } 559 560 return rtl::OUString(); 561 } 562 563 564 565 void SAL_CALL 566 BaseContent::addContentEventListener( 567 const Reference< XContentEventListener >& Listener ) 568 throw( RuntimeException ) 569 { 570 osl::MutexGuard aGuard( m_aMutex ); 571 572 if ( ! m_pContentEventListeners ) 573 m_pContentEventListeners = 574 new cppu::OInterfaceContainerHelper( m_aEventListenerMutex ); 575 576 577 m_pContentEventListeners->addInterface( Listener ); 578 } 579 580 581 void SAL_CALL 582 BaseContent::removeContentEventListener( 583 const Reference< XContentEventListener >& Listener ) 584 throw( RuntimeException ) 585 { 586 osl::MutexGuard aGuard( m_aMutex ); 587 588 if ( m_pContentEventListeners ) 589 m_pContentEventListeners->removeInterface( Listener ); 590 } 591 592 593 594 //////////////////////////////////////////////////////////////////////////////// 595 // XPropertyContainer 596 //////////////////////////////////////////////////////////////////////////////// 597 598 599 void SAL_CALL 600 BaseContent::addProperty( 601 const rtl::OUString& Name, 602 sal_Int16 Attributes, 603 const Any& DefaultValue ) 604 throw( beans::PropertyExistException, 605 beans::IllegalTypeException, 606 lang::IllegalArgumentException, 607 RuntimeException) 608 { 609 if( ( m_nState & JustInserted ) || ( m_nState & Deleted ) || Name == rtl::OUString() ) 610 { 611 throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); 612 } 613 614 m_pMyShell->associate( m_aUncPath,Name,DefaultValue,Attributes ); 615 } 616 617 618 void SAL_CALL 619 BaseContent::removeProperty( 620 const rtl::OUString& Name ) 621 throw( beans::UnknownPropertyException, 622 beans::NotRemoveableException, 623 RuntimeException) 624 { 625 626 if( m_nState & Deleted ) 627 throw beans::UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 628 629 m_pMyShell->deassociate( m_aUncPath, Name ); 630 } 631 632 //////////////////////////////////////////////////////////////////////////////// 633 // XContentCreator 634 //////////////////////////////////////////////////////////////////////////////// 635 636 Sequence< ContentInfo > SAL_CALL 637 BaseContent::queryCreatableContentsInfo( 638 void ) 639 throw( RuntimeException ) 640 { 641 return m_pMyShell->queryCreatableContentsInfo(); 642 } 643 644 645 Reference< XContent > SAL_CALL 646 BaseContent::createNewContent( 647 const ContentInfo& Info ) 648 throw( RuntimeException ) 649 { 650 // Check type. 651 if ( !Info.Type.getLength() ) 652 return Reference< XContent >(); 653 654 sal_Bool bFolder 655 = ( Info.Type.compareTo( m_pMyShell->FolderContentType ) == 0 ); 656 if ( !bFolder ) 657 { 658 if ( Info.Type.compareTo( m_pMyShell->FileContentType ) != 0 ) 659 { 660 // Neither folder nor file to create! 661 return Reference< XContent >(); 662 } 663 } 664 665 // Who am I ? 666 sal_Bool IsDocument = false; 667 668 try 669 { 670 Sequence< beans::Property > seq(1); 671 seq[0] = beans::Property( rtl::OUString::createFromAscii("IsDocument"), 672 -1, 673 getCppuType( static_cast< sal_Bool* >(0) ), 674 0 ); 675 Reference< sdbc::XRow > xRow = getPropertyValues( -1,seq ); 676 IsDocument = xRow->getBoolean( 1 ); 677 678 if ( xRow->wasNull() ) 679 { 680 IsDocument = false; 681 // OSL_ENSURE( false, 682 // "BaseContent::createNewContent - Property value was null!" ); 683 // return Reference< XContent >(); 684 } 685 } 686 catch ( sdbc::SQLException const & ) 687 { 688 OSL_ENSURE( false, 689 "BaseContent::createNewContent - Caught SQLException!" ); 690 return Reference< XContent >(); 691 } 692 693 rtl::OUString dstUncPath; 694 695 if( IsDocument ) 696 { 697 // KSO: Why is a document a XContentCreator? This is quite unusual. 698 dstUncPath = getParentName( m_aUncPath ); 699 } 700 else 701 dstUncPath = m_aUncPath; 702 703 BaseContent* p = new BaseContent( m_pMyShell, dstUncPath, bFolder ); 704 return Reference< XContent >( p ); 705 } 706 707 708 //////////////////////////////////////////////////////////////////////////////// 709 // XPropertySetInfoChangeNotifier 710 //////////////////////////////////////////////////////////////////////////////// 711 712 713 void SAL_CALL 714 BaseContent::addPropertySetInfoChangeListener( 715 const Reference< beans::XPropertySetInfoChangeListener >& Listener ) 716 throw( RuntimeException ) 717 { 718 osl::MutexGuard aGuard( m_aMutex ); 719 if( ! m_pPropertySetInfoChangeListeners ) 720 m_pPropertySetInfoChangeListeners = new cppu::OInterfaceContainerHelper( m_aEventListenerMutex ); 721 722 m_pPropertySetInfoChangeListeners->addInterface( Listener ); 723 } 724 725 726 void SAL_CALL 727 BaseContent::removePropertySetInfoChangeListener( 728 const Reference< beans::XPropertySetInfoChangeListener >& Listener ) 729 throw( RuntimeException ) 730 { 731 osl::MutexGuard aGuard( m_aMutex ); 732 733 if( m_pPropertySetInfoChangeListeners ) 734 m_pPropertySetInfoChangeListeners->removeInterface( Listener ); 735 } 736 737 738 //////////////////////////////////////////////////////////////////////////////// 739 // XChild 740 //////////////////////////////////////////////////////////////////////////////// 741 742 Reference< XInterface > SAL_CALL 743 BaseContent::getParent( 744 void ) 745 throw( RuntimeException ) 746 { 747 rtl::OUString ParentUnq = getParentName( m_aUncPath ); 748 rtl::OUString ParentUrl; 749 750 751 sal_Bool err = m_pMyShell->getUrlFromUnq( ParentUnq, ParentUrl ); 752 if( err ) 753 return Reference< XInterface >( 0 ); 754 755 FileContentIdentifier* p = new FileContentIdentifier( m_pMyShell,ParentUnq ); 756 Reference< XContentIdentifier > Identifier( p ); 757 758 try 759 { 760 Reference< XContent > content = m_pMyShell->m_pProvider->queryContent( Identifier ); 761 return Reference<XInterface>(content,UNO_QUERY); 762 } 763 catch( IllegalIdentifierException ) 764 { 765 return Reference< XInterface >(); 766 } 767 } 768 769 770 void SAL_CALL 771 BaseContent::setParent( 772 const Reference< XInterface >& ) 773 throw( lang::NoSupportException, 774 RuntimeException) 775 { 776 throw lang::NoSupportException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 777 } 778 779 780 ////////////////////////////////////////////////////////////////////////////////////////// 781 // Private Methods 782 ////////////////////////////////////////////////////////////////////////////////////////// 783 784 785 Reference< XCommandInfo > SAL_CALL 786 BaseContent::getCommandInfo() 787 throw( RuntimeException ) 788 { 789 if( m_nState & Deleted ) 790 return Reference< XCommandInfo >(); 791 792 return m_pMyShell->info_c(); 793 } 794 795 796 Reference< beans::XPropertySetInfo > SAL_CALL 797 BaseContent::getPropertySetInfo( 798 sal_Int32 ) 799 throw( RuntimeException ) 800 { 801 if( m_nState & Deleted ) 802 return Reference< beans::XPropertySetInfo >(); 803 804 return m_pMyShell->info_p( m_aUncPath ); 805 } 806 807 808 809 810 Reference< sdbc::XRow > SAL_CALL 811 BaseContent::getPropertyValues( 812 sal_Int32 nMyCommandIdentifier, 813 const Sequence< beans::Property >& PropertySet ) 814 throw( RuntimeException ) 815 { 816 sal_Int32 nProps = PropertySet.getLength(); 817 if ( !nProps ) 818 return Reference< sdbc::XRow >(); 819 820 if( m_nState & Deleted ) 821 { 822 Sequence< Any > aValues( nProps ); 823 return Reference< sdbc::XRow >( new XRow_impl( m_pMyShell, aValues ) ); 824 } 825 826 if( m_nState & JustInserted ) 827 { 828 Sequence< Any > aValues( nProps ); 829 Any* pValues = aValues.getArray(); 830 831 const beans::Property* pProps = PropertySet.getConstArray(); 832 833 for ( sal_Int32 n = 0; n < nProps; ++n ) 834 { 835 const beans::Property& rProp = pProps[ n ]; 836 Any& rValue = pValues[ n ]; 837 838 if( rProp.Name.compareToAscii( "ContentType" ) == 0 ) 839 { 840 rValue <<= m_bFolder ? m_pMyShell->FolderContentType 841 : m_pMyShell->FileContentType; 842 } 843 else if( rProp.Name.compareToAscii( "IsFolder" ) == 0 ) 844 { 845 rValue <<= m_bFolder; 846 } 847 else if( rProp.Name.compareToAscii( "IsDocument" ) == 0 ) 848 { 849 rValue <<= sal_Bool( !m_bFolder ); 850 } 851 } 852 853 return Reference< sdbc::XRow >( 854 new XRow_impl( m_pMyShell, aValues ) ); 855 } 856 857 return m_pMyShell->getv( nMyCommandIdentifier, 858 m_aUncPath, 859 PropertySet ); 860 } 861 862 863 Sequence< Any > SAL_CALL 864 BaseContent::setPropertyValues( 865 sal_Int32 nMyCommandIdentifier, 866 const Sequence< beans::PropertyValue >& Values ) 867 throw() 868 { 869 if( m_nState & Deleted ) 870 { // To do 871 return Sequence< Any >( Values.getLength() ); 872 } 873 874 const rtl::OUString Title = rtl::OUString::createFromAscii( "Title" ); 875 876 // Special handling for files which have to be inserted 877 if( m_nState & JustInserted ) 878 { 879 for( sal_Int32 i = 0; i < Values.getLength(); ++i ) 880 { 881 if( Values[i].Name == Title ) 882 { 883 rtl::OUString NewTitle; 884 if( Values[i].Value >>= NewTitle ) 885 { 886 if ( m_nState & NameForInsertionSet ) 887 { 888 // User wants to set another Title before "insert". 889 // m_aUncPath contains previous own URI. 890 891 sal_Int32 nLastSlash = m_aUncPath.lastIndexOf( '/' ); 892 bool bTrailingSlash = false; 893 if ( nLastSlash == m_aUncPath.getLength() - 1 ) 894 { 895 bTrailingSlash = true; 896 nLastSlash 897 = m_aUncPath.lastIndexOf( '/', nLastSlash ); 898 } 899 900 OSL_ENSURE( nLastSlash != -1, 901 "BaseContent::setPropertyValues: " 902 "Invalid URL!" ); 903 904 rtl::OUStringBuffer aBuf( 905 m_aUncPath.copy( 0, nLastSlash + 1 ) ); 906 907 if ( NewTitle.getLength() > 0 ) 908 { 909 aBuf.append( NewTitle ); 910 if ( bTrailingSlash ) 911 aBuf.append( sal_Unicode( '/' ) ); 912 } 913 else 914 { 915 m_nState &= ~NameForInsertionSet; 916 } 917 918 m_aUncPath = aBuf.makeStringAndClear(); 919 } 920 else 921 { 922 if ( NewTitle.getLength() > 0 ) 923 { 924 // Initial Title before "insert". 925 // m_aUncPath contains parent's URI. 926 927 if( m_aUncPath.lastIndexOf( sal_Unicode('/') ) != m_aUncPath.getLength() - 1 ) 928 m_aUncPath += rtl::OUString::createFromAscii("/"); 929 930 m_aUncPath += rtl::Uri::encode( NewTitle, 931 rtl_UriCharClassPchar, 932 rtl_UriEncodeIgnoreEscapes, 933 RTL_TEXTENCODING_UTF8 ); 934 m_nState |= NameForInsertionSet; 935 } 936 } 937 } 938 } 939 } 940 941 return Sequence< Any >( Values.getLength() ); 942 } 943 else 944 { 945 Sequence< Any > ret = m_pMyShell->setv( m_aUncPath, // Does not handle Title 946 Values ); 947 948 // Special handling Title: Setting Title is equivalent to a renaming of the underlying file 949 for( sal_Int32 i = 0; i < Values.getLength(); ++i ) 950 { 951 if( Values[i].Name != Title ) 952 continue; // handled by setv 953 954 rtl::OUString NewTitle; 955 if( !( Values[i].Value >>= NewTitle ) ) 956 { 957 ret[i] <<= beans::IllegalTypeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 958 break; 959 } 960 else if( ! NewTitle.getLength() ) 961 { 962 ret[i] <<= lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); 963 break; 964 } 965 966 967 rtl::OUString aDstName = getParentName( m_aUncPath ); 968 if( aDstName.lastIndexOf( sal_Unicode('/') ) != aDstName.getLength() - 1 ) 969 aDstName += rtl::OUString::createFromAscii("/"); 970 971 aDstName += rtl::Uri::encode( NewTitle, 972 rtl_UriCharClassPchar, 973 rtl_UriEncodeIgnoreEscapes, 974 RTL_TEXTENCODING_UTF8 ); 975 976 m_pMyShell->move( nMyCommandIdentifier, // move notifies the childs also; 977 m_aUncPath, 978 aDstName, 979 NameClash::KEEP ); 980 981 try 982 { 983 endTask( nMyCommandIdentifier ); 984 } 985 catch( const Exception& e ) 986 { 987 ret[i] <<= e; 988 } 989 990 // NameChanges come back trough a ContentEvent 991 break; // only handling Title 992 } // end for 993 994 return ret; 995 } 996 } 997 998 999 1000 Reference< XDynamicResultSet > SAL_CALL 1001 BaseContent::open( 1002 sal_Int32 nMyCommandIdentifier, 1003 const OpenCommandArgument2& aCommandArgument ) 1004 throw() 1005 { 1006 Reference< XDynamicResultSet > retValue( 0 ); 1007 1008 if( ( m_nState & Deleted ) ) 1009 { 1010 m_pMyShell->installError( nMyCommandIdentifier, 1011 TASKHANDLING_DELETED_STATE_IN_OPEN_COMMAND ); 1012 } 1013 else if( m_nState & JustInserted ) 1014 { 1015 m_pMyShell->installError( nMyCommandIdentifier, 1016 TASKHANDLING_INSERTED_STATE_IN_OPEN_COMMAND ); 1017 } 1018 else 1019 { 1020 if( aCommandArgument.Mode == OpenMode::DOCUMENT || 1021 aCommandArgument.Mode == OpenMode::DOCUMENT_SHARE_DENY_NONE ) 1022 1023 { 1024 Reference< io::XOutputStream > outputStream( aCommandArgument.Sink,UNO_QUERY ); 1025 if( outputStream.is() ) 1026 { 1027 m_pMyShell->page( nMyCommandIdentifier, 1028 m_aUncPath, 1029 outputStream ); 1030 } 1031 1032 sal_Bool bLock = ( aCommandArgument.Mode != OpenMode::DOCUMENT_SHARE_DENY_NONE ); 1033 1034 Reference< io::XActiveDataSink > activeDataSink( aCommandArgument.Sink,UNO_QUERY ); 1035 if( activeDataSink.is() ) 1036 { 1037 activeDataSink->setInputStream( m_pMyShell->open( nMyCommandIdentifier, 1038 m_aUncPath, 1039 bLock ) ); 1040 } 1041 1042 Reference< io::XActiveDataStreamer > activeDataStreamer( aCommandArgument.Sink,UNO_QUERY ); 1043 if( activeDataStreamer.is() ) 1044 { 1045 activeDataStreamer->setStream( m_pMyShell->open_rw( nMyCommandIdentifier, 1046 m_aUncPath, 1047 bLock ) ); 1048 } 1049 } 1050 else if ( aCommandArgument.Mode == OpenMode::ALL || 1051 aCommandArgument.Mode == OpenMode::FOLDERS || 1052 aCommandArgument.Mode == OpenMode::DOCUMENTS ) 1053 { 1054 retValue = m_pMyShell->ls( nMyCommandIdentifier, 1055 m_aUncPath, 1056 aCommandArgument.Mode, 1057 aCommandArgument.Properties, 1058 aCommandArgument.SortingInfo ); 1059 } 1060 // else if( aCommandArgument.Mode == 1061 // OpenMode::DOCUMENT_SHARE_DENY_NONE || 1062 // aCommandArgument.Mode == 1063 // OpenMode::DOCUMENT_SHARE_DENY_WRITE ) 1064 // m_pMyShell->installError( nMyCommandIdentifier, 1065 // TASKHANDLING_UNSUPPORTED_OPEN_MODE, 1066 // aCommandArgument.Mode); 1067 else 1068 m_pMyShell->installError( nMyCommandIdentifier, 1069 TASKHANDLING_UNSUPPORTED_OPEN_MODE, 1070 aCommandArgument.Mode); 1071 } 1072 1073 return retValue; 1074 } 1075 1076 1077 1078 void SAL_CALL 1079 BaseContent::deleteContent( sal_Int32 nMyCommandIdentifier ) 1080 throw() 1081 { 1082 if( m_nState & Deleted ) 1083 return; 1084 1085 if( m_pMyShell->remove( nMyCommandIdentifier,m_aUncPath ) ) 1086 { 1087 osl::MutexGuard aGuard( m_aMutex ); 1088 m_nState |= Deleted; 1089 } 1090 } 1091 1092 1093 1094 void SAL_CALL 1095 BaseContent::transfer( sal_Int32 nMyCommandIdentifier, 1096 const TransferInfo& aTransferInfo ) 1097 throw() 1098 { 1099 if( m_nState & Deleted ) 1100 return; 1101 1102 if( aTransferInfo.SourceURL.compareToAscii( "file:",5 ) != 0 ) 1103 { 1104 m_pMyShell->installError( nMyCommandIdentifier, 1105 TASKHANDLING_TRANSFER_INVALIDSCHEME ); 1106 return; 1107 } 1108 1109 rtl::OUString srcUnc; 1110 if( m_pMyShell->getUnqFromUrl( aTransferInfo.SourceURL,srcUnc ) ) 1111 { 1112 m_pMyShell->installError( nMyCommandIdentifier, 1113 TASKHANDLING_TRANSFER_INVALIDURL ); 1114 return; 1115 } 1116 1117 rtl::OUString srcUncPath = srcUnc; 1118 1119 // Determine the new title ! 1120 rtl::OUString NewTitle; 1121 if( aTransferInfo.NewTitle.getLength() ) 1122 NewTitle = rtl::Uri::encode( aTransferInfo.NewTitle, 1123 rtl_UriCharClassPchar, 1124 rtl_UriEncodeIgnoreEscapes, 1125 RTL_TEXTENCODING_UTF8 ); 1126 else 1127 NewTitle = srcUncPath.copy( 1 + srcUncPath.lastIndexOf( sal_Unicode('/') ) ); 1128 1129 // Is destination a document or a folder ? 1130 Sequence< beans::Property > seq(1); 1131 seq[0] = beans::Property( rtl::OUString::createFromAscii("IsDocument"), 1132 -1, 1133 getCppuType( static_cast< sal_Bool* >(0) ), 1134 0 ); 1135 Reference< sdbc::XRow > xRow = getPropertyValues( nMyCommandIdentifier,seq ); 1136 sal_Bool IsDocument = xRow->getBoolean( 1 ); 1137 if( xRow->wasNull() ) 1138 { // Destination file type could not be determined 1139 m_pMyShell->installError( nMyCommandIdentifier, 1140 TASKHANDLING_TRANSFER_DESTFILETYPE ); 1141 return; 1142 } 1143 1144 rtl::OUString dstUncPath; 1145 if( IsDocument ) 1146 { // as sibling 1147 sal_Int32 lastSlash = m_aUncPath.lastIndexOf( sal_Unicode('/') ); 1148 dstUncPath = m_aUncPath.copy(0,lastSlash ); 1149 } 1150 else 1151 // as child 1152 dstUncPath = m_aUncPath; 1153 1154 dstUncPath += ( rtl::OUString::createFromAscii( "/" ) + NewTitle ); 1155 1156 sal_Int32 NameClash = aTransferInfo.NameClash; 1157 1158 if( aTransferInfo.MoveData ) 1159 m_pMyShell->move( nMyCommandIdentifier,srcUncPath,dstUncPath,NameClash ); 1160 else 1161 m_pMyShell->copy( nMyCommandIdentifier,srcUncPath,dstUncPath,NameClash ); 1162 } 1163 1164 1165 1166 1167 void SAL_CALL BaseContent::insert( sal_Int32 nMyCommandIdentifier, 1168 const InsertCommandArgument& aInsertArgument ) 1169 throw() 1170 { 1171 if( m_nState & FullFeatured ) 1172 { 1173 m_pMyShell->write( nMyCommandIdentifier, 1174 m_aUncPath, 1175 aInsertArgument.ReplaceExisting, 1176 aInsertArgument.Data ); 1177 return; 1178 } 1179 1180 if( ! ( m_nState & JustInserted ) ) 1181 { 1182 m_pMyShell->installError( nMyCommandIdentifier, 1183 TASKHANDLING_NOFRESHINSERT_IN_INSERT_COMMAND ); 1184 return; 1185 } 1186 1187 // Inserts the content, which has the flag m_bIsFresh 1188 1189 if !( m_nState & NameForInsertionSet ) 1190 { 1191 m_pMyShell->installError( nMyCommandIdentifier, 1192 TASKHANDLING_NONAMESET_INSERT_COMMAND ); 1193 return; 1194 } 1195 1196 // Inserting a document or a file? 1197 sal_Bool bDocument = false; 1198 1199 Sequence< beans::Property > seq(1); 1200 seq[0] = beans::Property( rtl::OUString::createFromAscii("IsDocument"), 1201 -1, 1202 getCppuType( static_cast< sal_Bool* >(0) ), 1203 0 ); 1204 1205 Reference< sdbc::XRow > xRow = getPropertyValues( -1,seq ); 1206 1207 bool contentTypeSet = true; // is set to false, if contentType not set 1208 try 1209 { 1210 bDocument = xRow->getBoolean( 1 ); 1211 if( xRow->wasNull() ) 1212 contentTypeSet = false; 1213 1214 } 1215 catch ( sdbc::SQLException const & ) 1216 { 1217 OSL_ENSURE( false, 1218 "BaseContent::insert - Caught SQLException!" ); 1219 contentTypeSet = false; 1220 } 1221 1222 if( ! contentTypeSet ) 1223 { 1224 m_pMyShell->installError( nMyCommandIdentifier, 1225 TASKHANDLING_NOCONTENTTYPE_INSERT_COMMAND ); 1226 return; 1227 } 1228 1229 1230 sal_Bool success = false; 1231 if( bDocument ) 1232 success = m_pMyShell->mkfil( nMyCommandIdentifier, 1233 m_aUncPath, 1234 aInsertArgument.ReplaceExisting, 1235 aInsertArgument.Data ); 1236 else 1237 { 1238 while( ! success ) 1239 { 1240 success = m_pMyShell->mkdir( nMyCommandIdentifier, 1241 m_aUncPath, 1242 aInsertArgument.ReplaceExisting ); 1243 if( success ) 1244 break; 1245 1246 XInteractionRequestImpl *aRequestImpl = 1247 new XInteractionRequestImpl( 1248 rtl::Uri::decode( 1249 getTitle(m_aUncPath), 1250 rtl_UriDecodeWithCharset, 1251 RTL_TEXTENCODING_UTF8), 1252 (cppu::OWeakObject*)this, 1253 m_pMyShell,nMyCommandIdentifier); 1254 uno::Reference< task::XInteractionRequest > aReq( aRequestImpl ); 1255 1256 m_pMyShell->handleTask( nMyCommandIdentifier,aReq ); 1257 if( aRequestImpl->aborted() || 1258 !aRequestImpl->newName().getLength() ) 1259 // means aborting 1260 break; 1261 1262 // determine new uncpath 1263 m_pMyShell->clearError( nMyCommandIdentifier ); 1264 m_aUncPath = getParentName( m_aUncPath ); 1265 if( m_aUncPath.lastIndexOf( sal_Unicode('/') ) != m_aUncPath.getLength() - 1 ) 1266 m_aUncPath += rtl::OUString::createFromAscii("/"); 1267 1268 m_aUncPath += rtl::Uri::encode( aRequestImpl->newName(), 1269 rtl_UriCharClassPchar, 1270 rtl_UriEncodeIgnoreEscapes, 1271 RTL_TEXTENCODING_UTF8 ); 1272 } 1273 } 1274 1275 if ( ! success ) 1276 return; 1277 1278 FileContentIdentifier* p = new FileContentIdentifier( m_pMyShell,m_aUncPath ); 1279 m_xContentIdentifier = Reference< XContentIdentifier >( p ); 1280 1281 m_pMyShell->registerNotifier( m_aUncPath,this ); 1282 m_pMyShell->insertDefaultProperties( m_aUncPath ); 1283 1284 osl::MutexGuard aGuard( m_aMutex ); 1285 m_nState = FullFeatured; 1286 } 1287 1288 1289 1290 void SAL_CALL BaseContent::endTask( sal_Int32 CommandId ) 1291 { 1292 // This is the only function allowed to throw an exception 1293 m_pMyShell->endTask( CommandId,m_aUncPath,this ); 1294 } 1295 1296 1297 1298 ContentEventNotifier* 1299 BaseContent::cDEL( void ) 1300 { 1301 osl::MutexGuard aGuard( m_aMutex ); 1302 1303 m_nState |= Deleted; 1304 1305 ContentEventNotifier* p; 1306 if( m_pContentEventListeners ) 1307 p = new ContentEventNotifier( m_pMyShell, 1308 this, 1309 m_xContentIdentifier, 1310 m_pContentEventListeners->getElements() ); 1311 else 1312 p = 0; 1313 1314 return p; 1315 } 1316 1317 1318 ContentEventNotifier* 1319 BaseContent::cEXC( const rtl::OUString aNewName ) 1320 { 1321 osl::MutexGuard aGuard( m_aMutex ); 1322 1323 Reference< XContentIdentifier > xOldRef = m_xContentIdentifier; 1324 m_aUncPath = aNewName; 1325 FileContentIdentifier* pp = new FileContentIdentifier( m_pMyShell,aNewName ); 1326 m_xContentIdentifier = Reference< XContentIdentifier >( pp ); 1327 1328 ContentEventNotifier* p = 0; 1329 if( m_pContentEventListeners ) 1330 p = new ContentEventNotifier( m_pMyShell, 1331 this, 1332 m_xContentIdentifier, 1333 xOldRef, 1334 m_pContentEventListeners->getElements() ); 1335 1336 return p; 1337 } 1338 1339 1340 ContentEventNotifier* 1341 BaseContent::cCEL( void ) 1342 { 1343 osl::MutexGuard aGuard( m_aMutex ); 1344 ContentEventNotifier* p = 0; 1345 if( m_pContentEventListeners ) 1346 p = new ContentEventNotifier( m_pMyShell, 1347 this, 1348 m_xContentIdentifier, 1349 m_pContentEventListeners->getElements() ); 1350 1351 return p; 1352 } 1353 1354 PropertySetInfoChangeNotifier* 1355 BaseContent::cPSL( void ) 1356 { 1357 osl::MutexGuard aGuard( m_aMutex ); 1358 PropertySetInfoChangeNotifier* p = 0; 1359 if( m_pPropertySetInfoChangeListeners ) 1360 p = new PropertySetInfoChangeNotifier( m_pMyShell, 1361 this, 1362 m_xContentIdentifier, 1363 m_pPropertySetInfoChangeListeners->getElements() ); 1364 1365 return p; 1366 } 1367 1368 1369 1370 PropertyChangeNotifier* 1371 BaseContent::cPCL( void ) 1372 { 1373 osl::MutexGuard aGuard( m_aMutex ); 1374 1375 Sequence< rtl::OUString > seqNames; 1376 1377 if( m_pPropertyListener ) 1378 seqNames = m_pPropertyListener->getContainedTypes(); 1379 1380 PropertyChangeNotifier* p = 0; 1381 1382 sal_Int32 length = seqNames.getLength(); 1383 1384 if( length ) 1385 { 1386 ListenerMap* listener = new ListenerMap(); 1387 for( sal_Int32 i = 0; i < length; ++i ) 1388 { 1389 (*listener)[seqNames[i]] = m_pPropertyListener->getContainer( seqNames[i] )->getElements(); 1390 } 1391 1392 p = new PropertyChangeNotifier( m_pMyShell, 1393 this, 1394 m_xContentIdentifier, 1395 listener ); 1396 } 1397 1398 return p; 1399 } 1400 1401 1402 rtl::OUString BaseContent::getKey( void ) 1403 { 1404 return m_aUncPath; 1405 } 1406