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 #include <com/sun/star/beans/PropertyAttribute.hpp> 33 34 #include "ftpdynresultset.hxx" 35 #include "ftpresultsetfactory.hxx" 36 #include "ftpresultsetI.hxx" 37 #include "ftpcontent.hxx" 38 #include "ftpcontentprovider.hxx" 39 #include "ftpinpstr.hxx" 40 #include "ftpdirp.hxx" 41 #include "ftpcontentidentifier.hxx" 42 #include "ftpcfunc.hxx" 43 #include "ftpstrcont.hxx" 44 #include "ftpintreq.hxx" 45 46 #include <memory> 47 #include <vector> 48 #include <rtl/memory.h> 49 #include "curl.hxx" 50 #include <curl/easy.h> 51 #include <ucbhelper/cancelcommandexecution.hxx> 52 #include <ucbhelper/contentidentifier.hxx> 53 #include <ucbhelper/propertyvalueset.hxx> 54 #include <ucbhelper/contentidentifier.hxx> 55 #include <ucbhelper/cancelcommandexecution.hxx> 56 #include <ucbhelper/simpleauthenticationrequest.hxx> 57 #include <com/sun/star/lang/IllegalAccessException.hpp> 58 #include <com/sun/star/ucb/ContentInfoAttribute.hpp> 59 #include <com/sun/star/beans/UnknownPropertyException.hpp> 60 #include <com/sun/star/beans/Property.hpp> 61 #include <com/sun/star/beans/PropertyValue.hpp> 62 #include <com/sun/star/ucb/XCommandInfo.hpp> 63 #include <com/sun/star/io/XActiveDataSink.hpp> 64 #include <com/sun/star/io/XOutputStream.hpp> 65 #include <com/sun/star/io/XActiveDataStreamer.hpp> 66 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp> 67 #include <com/sun/star/ucb/OpenCommandArgument2.hpp> 68 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp> 69 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp> 70 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp> 71 #include <com/sun/star/ucb/InteractiveIOException.hpp> 72 #include <com/sun/star/ucb/MissingPropertiesException.hpp> 73 #include <com/sun/star/ucb/MissingInputStreamException.hpp> 74 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp> 75 #include <com/sun/star/ucb/NameClashException.hpp> 76 //#include <com/sun/star/ucb/NameClash.hpp> 77 #include <com/sun/star/ucb/OpenMode.hpp> 78 #include <com/sun/star/ucb/IOErrorCode.hpp> 79 80 using namespace ftp; 81 using namespace com::sun::star::task; 82 using namespace com::sun::star::container; 83 using namespace com::sun::star::lang; 84 using namespace com::sun::star::uno; 85 using namespace com::sun::star::ucb; 86 using namespace com::sun::star::beans; 87 using namespace com::sun::star::io; 88 using namespace com::sun::star::sdbc; 89 90 91 92 //========================================================================= 93 //========================================================================= 94 // 95 // Content Implementation. 96 // 97 //========================================================================= 98 //========================================================================= 99 100 FTPContent::FTPContent( const Reference< XMultiServiceFactory >& rxSMgr, 101 FTPContentProvider* pProvider, 102 const Reference< XContentIdentifier >& Identifier, 103 const FTPURL& aFTPURL) 104 : ContentImplHelper(rxSMgr,pProvider,Identifier), 105 m_pFCP(pProvider), 106 m_aFTPURL(aFTPURL), 107 m_bInserted(false), 108 m_bTitleSet(false) 109 { 110 } 111 112 113 114 FTPContent::FTPContent( const Reference< XMultiServiceFactory >& rxSMgr, 115 FTPContentProvider* pProvider, 116 const Reference< XContentIdentifier >& Identifier, 117 const ContentInfo& Info) 118 : ContentImplHelper(rxSMgr,pProvider,Identifier), 119 m_pFCP(pProvider), 120 m_aFTPURL(Identifier->getContentIdentifier(), 121 pProvider), 122 m_bInserted(true), 123 m_bTitleSet(false), 124 m_aInfo(Info) 125 { 126 } 127 128 129 130 //========================================================================= 131 132 FTPContent::~FTPContent() 133 { 134 } 135 136 137 //========================================================================= 138 // 139 // XInterface methods. 140 // 141 //========================================================================= 142 143 XINTERFACE_IMPL_6( FTPContent, 144 XTypeProvider, 145 XServiceInfo, 146 XContent, 147 XCommandProcessor, 148 XContentCreator, 149 XChild); 150 151 //========================================================================= 152 // 153 // XTypeProvider methods. 154 // 155 //========================================================================= 156 157 XTYPEPROVIDER_IMPL_6( FTPContent, 158 XTypeProvider, 159 XServiceInfo, 160 XContent, 161 XCommandProcessor, 162 XContentCreator, 163 XChild); 164 165 //========================================================================= 166 // 167 // XServiceInfo methods. 168 // 169 //========================================================================= 170 171 // needed, because the service shall not be creatable!! 172 #undef XSERVICEINFO_CREATE_INSTANCE_IMPL 173 #define XSERVICEINFO_CREATE_INSTANCE_IMPL( Class ) 174 175 XSERVICEINFO_IMPL_1( FTPContent, 176 rtl::OUString::createFromAscii( 177 "com.sun.star.comp.FTPContent"), 178 rtl::OUString::createFromAscii( 179 "com.sun.star.ucb.FTPContent")); 180 181 182 183 //========================================================================= 184 // 185 // XContent methods. 186 // 187 //========================================================================= 188 189 // virtual 190 rtl::OUString SAL_CALL FTPContent::getContentType() 191 throw( RuntimeException ) 192 { 193 return rtl::OUString::createFromAscii(FTP_CONTENT_TYPE); 194 } 195 196 197 //========================================================================= 198 // 199 // XCommandProcessor methods. 200 // 201 //========================================================================= 202 203 204 //virtual 205 void SAL_CALL FTPContent::abort( sal_Int32 /*CommandId*/ ) 206 throw( RuntimeException ) 207 { 208 } 209 210 211 212 /***************************************************************************/ 213 /* */ 214 /* Internal implementation class. */ 215 /* */ 216 /***************************************************************************/ 217 218 219 class ResultSetFactoryI 220 : public ResultSetFactory 221 { 222 public: 223 224 ResultSetFactoryI(const Reference<XMultiServiceFactory >& xSMgr, 225 const Reference<XContentProvider >& xProvider, 226 sal_Int32 nOpenMode, 227 const Sequence<Property>& seq, 228 const Sequence<NumberedSortingInfo>& seqSort, 229 const std::vector<FTPDirentry>& dirvec) 230 : m_xSMgr(xSMgr), 231 m_xProvider(xProvider), 232 m_nOpenMode(nOpenMode), 233 m_seq(seq), 234 m_seqSort(seqSort), 235 m_dirvec(dirvec) 236 { 237 } 238 239 virtual ResultSetBase* createResultSet() 240 { 241 return new ResultSetI(m_xSMgr, 242 m_xProvider, 243 m_nOpenMode, 244 m_seq, 245 m_seqSort, 246 m_dirvec); 247 } 248 249 public: 250 251 Reference< XMultiServiceFactory > m_xSMgr; 252 Reference< XContentProvider > m_xProvider; 253 sal_Int32 m_nOpenMode; 254 Sequence< Property > m_seq; 255 Sequence< NumberedSortingInfo > m_seqSort; 256 std::vector<FTPDirentry> m_dirvec; 257 }; 258 259 260 261 //========================================================================= 262 // 263 // XCommandProcessor methods. 264 // 265 //========================================================================= 266 267 enum ACTION { NOACTION, 268 THROWAUTHENTICATIONREQUEST, 269 THROWACCESSDENIED, 270 THROWINTERACTIVECONNECT, 271 THROWRESOLVENAME, 272 THROWQUOTE, 273 THROWNOFILE, 274 THROWGENERAL }; 275 276 277 // virtual 278 Any SAL_CALL FTPContent::execute( 279 const Command& aCommand, 280 sal_Int32 /*CommandId*/, 281 const Reference< 282 XCommandEnvironment >& Environment 283 ) 284 throw( 285 Exception, 286 CommandAbortedException, 287 RuntimeException 288 ) 289 { 290 ACTION action(NOACTION); 291 Any aRet; 292 293 while(true) 294 try { 295 if(action == THROWAUTHENTICATIONREQUEST) { 296 // try to get a continuation first 297 rtl::OUString aRealm,aPassword,aAccount; 298 m_pFCP->forHost(m_aFTPURL.host(), 299 m_aFTPURL.port(), 300 m_aFTPURL.username(), 301 aPassword, 302 aAccount); 303 rtl::Reference<ucbhelper::SimpleAuthenticationRequest> 304 p( new ucbhelper::SimpleAuthenticationRequest( 305 m_aFTPURL.ident(false, false), 306 m_aFTPURL.host(), // ServerName 307 ucbhelper::SimpleAuthenticationRequest::ENTITY_NA, 308 aRealm, 309 ucbhelper::SimpleAuthenticationRequest 310 ::ENTITY_FIXED, 311 m_aFTPURL.username(), 312 ucbhelper::SimpleAuthenticationRequest 313 ::ENTITY_MODIFY, 314 aPassword)); 315 316 Reference<XInteractionHandler> xInteractionHandler; 317 if(Environment.is()) 318 xInteractionHandler = 319 Environment->getInteractionHandler(); 320 321 if( xInteractionHandler.is()) { 322 xInteractionHandler->handle(p.get()); 323 324 Reference<XInterface> xSelection( 325 p->getSelection().get()); 326 327 if(Reference<XInteractionRetry>( 328 xSelection,UNO_QUERY).is()) 329 action = NOACTION; 330 else if(Reference<XInteractionSupplyAuthentication>( 331 xSelection,UNO_QUERY).is()) { 332 m_pFCP->setHost( 333 m_aFTPURL.host(), 334 m_aFTPURL.port(), 335 m_aFTPURL.username(), 336 p->getAuthenticationSupplier()->getPassword(), 337 aAccount); 338 action = NOACTION; 339 } 340 } 341 aRet = p->getRequest(); 342 } 343 344 // if(aCommand.Name.compareToAscii( 345 // "getPropertyValues") == 0 && 346 // action != NOACTION) { 347 // // It is not allowed to throw if 348 // // command is getPropertyValues 349 // rtl::Reference<ucbhelper::PropertyValueSet> xRow = 350 // new ucbhelper::PropertyValueSet(m_xSMgr); 351 // Sequence<Property> Properties; 352 // aCommand.Argument >>= Properties; 353 // for(int i = 0; i < Properties.getLength(); ++i) 354 // xRow->appendVoid(Properties[i]); 355 // aRet <<= Reference<XRow>(xRow.get()); 356 // return aRet; 357 // } 358 359 switch (action) 360 { 361 case NOACTION: 362 break; 363 364 case THROWAUTHENTICATIONREQUEST: 365 ucbhelper::cancelCommandExecution( 366 aRet, 367 Reference<XCommandEnvironment>(0)); 368 break; 369 370 case THROWACCESSDENIED: 371 { 372 Sequence<Any> seq(1); 373 PropertyValue value; 374 value.Name = rtl::OUString::createFromAscii("Uri"); 375 value.Handle = -1; 376 value.Value <<= m_aFTPURL.ident(false,false); 377 value.State = PropertyState_DIRECT_VALUE; 378 seq[0] <<= value; 379 ucbhelper::cancelCommandExecution( 380 IOErrorCode_ACCESS_DENIED, 381 seq, 382 Environment); 383 break; 384 } 385 case THROWINTERACTIVECONNECT: 386 { 387 InteractiveNetworkConnectException excep; 388 excep.Server = m_aFTPURL.host(); 389 aRet <<= excep; 390 ucbhelper::cancelCommandExecution( 391 aRet, 392 Environment); 393 break; 394 } 395 case THROWRESOLVENAME: 396 { 397 InteractiveNetworkResolveNameException excep; 398 excep.Server = m_aFTPURL.host(); 399 aRet <<= excep; 400 ucbhelper::cancelCommandExecution( 401 aRet, 402 Environment); 403 break; 404 } 405 case THROWNOFILE: 406 { 407 Sequence<Any> seq(1); 408 PropertyValue value; 409 value.Name = rtl::OUString::createFromAscii("Uri"); 410 value.Handle = -1; 411 value.Value <<= m_aFTPURL.ident(false,false); 412 value.State = PropertyState_DIRECT_VALUE; 413 seq[0] <<= value; 414 ucbhelper::cancelCommandExecution( 415 IOErrorCode_NO_FILE, 416 seq, 417 Environment); 418 break; 419 } 420 case THROWQUOTE: 421 case THROWGENERAL: 422 ucbhelper::cancelCommandExecution( 423 IOErrorCode_GENERAL, 424 Sequence<Any>(0), 425 Environment); 426 break; 427 } 428 429 if(aCommand.Name.compareToAscii("getPropertyValues") == 0) { 430 Sequence<Property> Properties; 431 if(!(aCommand.Argument >>= Properties)) 432 { 433 aRet <<= IllegalArgumentException( 434 rtl::OUString::createFromAscii( 435 "Wrong argument type!" ), 436 static_cast< cppu::OWeakObject * >(this), 437 -1); 438 ucbhelper::cancelCommandExecution(aRet,Environment); 439 } 440 441 aRet <<= getPropertyValues(Properties,Environment); 442 } 443 else if(aCommand.Name.compareToAscii("setPropertyValues") == 0) 444 { 445 Sequence<PropertyValue> propertyValues; 446 447 if( ! ( aCommand.Argument >>= propertyValues ) ) { 448 aRet <<= IllegalArgumentException( 449 rtl::OUString::createFromAscii( 450 "Wrong argument type!" ), 451 static_cast< cppu::OWeakObject * >(this), 452 -1); 453 ucbhelper::cancelCommandExecution(aRet,Environment); 454 } 455 456 aRet <<= setPropertyValues(propertyValues); 457 } 458 else if(aCommand.Name.compareToAscii("getCommandInfo") == 0) { 459 // Note: Implemented by base class. 460 aRet <<= getCommandInfo(Environment); 461 } 462 else if(aCommand.Name.compareToAscii("getPropertySetInfo") == 0) { 463 // Note: Implemented by base class. 464 aRet <<= getPropertySetInfo(Environment); 465 } 466 else if(aCommand.Name.compareToAscii( "insert" ) == 0) 467 { 468 InsertCommandArgument aInsertArgument; 469 if ( ! ( aCommand.Argument >>= aInsertArgument ) ) { 470 aRet <<= IllegalArgumentException( 471 rtl::OUString::createFromAscii( 472 "Wrong argument type!" ), 473 static_cast< cppu::OWeakObject * >(this), 474 -1); 475 ucbhelper::cancelCommandExecution(aRet,Environment); 476 } 477 insert(aInsertArgument,Environment); 478 } 479 else if(aCommand.Name.compareToAscii("delete") == 0) { 480 m_aFTPURL.del(); 481 deleted(); 482 } 483 else if(aCommand.Name.compareToAscii( "open" ) == 0) { 484 OpenCommandArgument2 aOpenCommand; 485 if ( !( aCommand.Argument >>= aOpenCommand ) ) { 486 aRet <<= IllegalArgumentException( 487 rtl::OUString::createFromAscii( 488 "Wrong argument type!" ), 489 static_cast< cppu::OWeakObject * >(this), 490 -1); 491 492 ucbhelper::cancelCommandExecution(aRet,Environment); 493 } 494 495 if(aOpenCommand.Mode == OpenMode::DOCUMENT) { 496 // Open as a document 497 Reference<XActiveDataSink> 498 xActiveDataSink(aOpenCommand.Sink,UNO_QUERY); 499 Reference< XOutputStream > 500 xOutputStream(aOpenCommand.Sink,UNO_QUERY); 501 502 if(xActiveDataSink.is()) { 503 xActiveDataSink->setInputStream( 504 new FTPInputStream(m_aFTPURL.open())); 505 } 506 else if(xOutputStream.is()) { 507 Reference<XInputStream> xStream( 508 new FTPInputStream(m_aFTPURL.open())); 509 Sequence<sal_Int8> byte_seq(4096); 510 sal_Int32 n = 1000; // value does not matter here 511 for (;;) { 512 n = xStream->readBytes(byte_seq,4096); 513 if (n == 0) { 514 break; 515 } 516 try { 517 if(byte_seq.getLength() != n) 518 byte_seq.realloc(n); 519 xOutputStream->writeBytes(byte_seq); 520 } catch(const NotConnectedException&) { 521 522 } catch(const BufferSizeExceededException&) { 523 524 } catch(const IOException&) { 525 526 } 527 } 528 if(n) { 529 Sequence<Any> seq(1); 530 PropertyValue value; 531 value.Name = 532 rtl::OUString::createFromAscii("Uri"); 533 value.Handle = -1; 534 value.Value <<= m_aFTPURL.ident(false,false); 535 value.State = PropertyState_DIRECT_VALUE; 536 seq[0] <<= value; 537 ucbhelper::cancelCommandExecution( 538 IOErrorCode_UNKNOWN, 539 seq, 540 Environment); 541 } 542 } 543 else { 544 aRet <<= UnsupportedDataSinkException( 545 rtl::OUString(), 546 static_cast< cppu::OWeakObject * >(this), 547 aOpenCommand.Sink); 548 ucbhelper::cancelCommandExecution(aRet,Environment); 549 } 550 } 551 else if(aOpenCommand.Mode == OpenMode::ALL || 552 aOpenCommand.Mode == OpenMode::DOCUMENTS || 553 aOpenCommand.Mode == OpenMode::FOLDERS ) { 554 std::vector<FTPDirentry> resvec = 555 m_aFTPURL.list(sal_Int16(aOpenCommand.Mode)); 556 Reference< XDynamicResultSet > xSet 557 = new DynamicResultSet( 558 m_xSMgr, 559 this, 560 aOpenCommand, 561 Environment, 562 new ResultSetFactoryI(m_xSMgr, 563 m_xProvider.get(), 564 aOpenCommand.Mode, 565 aOpenCommand.Properties, 566 aOpenCommand.SortingInfo, 567 resvec)); 568 aRet <<= xSet; 569 } 570 else if(aOpenCommand.Mode == 571 OpenMode::DOCUMENT_SHARE_DENY_NONE || 572 aOpenCommand.Mode == 573 OpenMode::DOCUMENT_SHARE_DENY_WRITE) { 574 // Unsupported OpenMode 575 aRet <<= UnsupportedOpenModeException( 576 rtl::OUString(), 577 static_cast< cppu::OWeakObject * >(this), 578 static_cast< sal_Int16 >(aOpenCommand.Mode)); 579 ucbhelper::cancelCommandExecution(aRet,Environment); 580 } 581 else { 582 aRet <<= IllegalArgumentException( 583 rtl::OUString::createFromAscii( 584 "Unexpected OpenMode!" ), 585 static_cast< cppu::OWeakObject * >(this), 586 -1); 587 588 ucbhelper::cancelCommandExecution(aRet,Environment); 589 } 590 } else if(aCommand.Name.compareToAscii("createNewContent") == 0) { 591 ContentInfo aArg; 592 if (!(aCommand.Argument >>= aArg)) { 593 ucbhelper::cancelCommandExecution( 594 makeAny( 595 IllegalArgumentException( 596 rtl::OUString::createFromAscii( 597 "Wrong argument type!" ), 598 static_cast< cppu::OWeakObject * >(this), 599 -1)), 600 Environment); 601 // Unreachable 602 } 603 aRet <<= createNewContent(aArg); 604 } else { 605 aRet <<= UnsupportedCommandException( 606 aCommand.Name, 607 static_cast< cppu::OWeakObject * >(this)); 608 ucbhelper::cancelCommandExecution(aRet,Environment); 609 } 610 611 return aRet; 612 } catch(const curl_exception& e) { 613 if(e.code() == CURLE_COULDNT_CONNECT) 614 action = THROWINTERACTIVECONNECT; 615 else if(e.code() == CURLE_COULDNT_RESOLVE_HOST ) 616 action = THROWRESOLVENAME; 617 else if(e.code() == CURLE_FTP_USER_PASSWORD_INCORRECT || 618 e.code() == CURLE_LOGIN_DENIED || 619 e.code() == CURLE_BAD_PASSWORD_ENTERED || 620 e.code() == CURLE_FTP_WEIRD_PASS_REPLY) 621 action = THROWAUTHENTICATIONREQUEST; 622 else if(e.code() == CURLE_FTP_ACCESS_DENIED) 623 action = THROWACCESSDENIED; 624 else if(e.code() == CURLE_FTP_QUOTE_ERROR) 625 action = THROWQUOTE; 626 else if(e.code() == CURLE_FTP_COULDNT_RETR_FILE) 627 action = THROWNOFILE; 628 else 629 // nothing known about the cause of the error 630 action = THROWGENERAL; 631 } 632 } 633 634 #define FTP_FILE rtl::OUString::createFromAscii( \ 635 "application/" \ 636 "vnd.sun.staroffice.ftp-file") 637 638 #define FTP_FOLDER rtl::OUString::createFromAscii( \ 639 "application/" \ 640 "vnd.sun.staroffice.ftp-folder") 641 642 Sequence<ContentInfo > SAL_CALL 643 FTPContent::queryCreatableContentsInfo( ) 644 throw (RuntimeException) 645 { 646 return queryCreatableContentsInfo_Static(); 647 } 648 649 // static 650 Sequence<ContentInfo > 651 FTPContent::queryCreatableContentsInfo_Static( ) 652 throw (RuntimeException) 653 { 654 Sequence< ContentInfo > seq(2); 655 656 seq[0].Type = FTP_FILE; 657 seq[0].Attributes = ContentInfoAttribute::INSERT_WITH_INPUTSTREAM 658 | ContentInfoAttribute::KIND_DOCUMENT; 659 Sequence< Property > props( 1 ); 660 props[0] = Property( 661 rtl::OUString::createFromAscii( "Title" ), 662 -1, 663 getCppuType( static_cast< rtl::OUString* >( 0 ) ), 664 PropertyAttribute::MAYBEVOID 665 | PropertyAttribute::BOUND ); 666 seq[0].Properties = props; 667 668 // folder 669 seq[1].Type = FTP_FOLDER; 670 seq[1].Attributes = ContentInfoAttribute::KIND_FOLDER; 671 seq[1].Properties = props; 672 673 return seq; 674 } 675 676 Reference<XContent > SAL_CALL 677 FTPContent::createNewContent( const ContentInfo& Info ) 678 throw (RuntimeException) 679 { 680 if(Info.Type.equalsAscii("application/" 681 "vnd.sun.staroffice.ftp-file") || 682 Info.Type.equalsAscii("application/" 683 "vnd.sun.staroffice.ftp-folder")) 684 return new FTPContent(m_xSMgr, 685 m_pFCP, 686 m_xIdentifier,Info); 687 else 688 return Reference<XContent>(0); 689 } 690 691 692 693 694 Reference<XInterface > SAL_CALL 695 FTPContent::getParent( ) 696 throw (RuntimeException) 697 { 698 Reference<XContentIdentifier> 699 xIdent(new FTPContentIdentifier(m_aFTPURL.parent(false))); 700 Reference<XContent> xContent(m_xProvider->queryContent(xIdent)); 701 return Reference<XInterface>(xContent,UNO_QUERY); 702 } 703 704 705 void SAL_CALL 706 FTPContent::setParent(const Reference<XInterface >& /*Parent*/ ) 707 throw (NoSupportException, 708 RuntimeException) 709 { 710 throw NoSupportException(); 711 } 712 713 714 715 rtl::OUString FTPContent::getParentURL() 716 { 717 return m_aFTPURL.parent(); 718 } 719 720 721 class InsertData 722 : public CurlInput { 723 724 public: 725 726 InsertData(const Reference<XInputStream>& xInputStream) 727 : m_xInputStream(xInputStream) { } 728 virtual ~InsertData() {} 729 730 // returns the number of bytes actually read 731 virtual sal_Int32 read(sal_Int8 *dest,sal_Int32 nBytesRequested); 732 733 private: 734 735 Reference<XInputStream> m_xInputStream; 736 }; 737 738 739 740 sal_Int32 InsertData::read(sal_Int8 *dest,sal_Int32 nBytesRequested) 741 { 742 sal_Int32 m = 0; 743 744 if(m_xInputStream.is()) { 745 Sequence<sal_Int8> seq(nBytesRequested); 746 m = m_xInputStream->readBytes(seq,nBytesRequested); 747 rtl_copyMemory(dest,seq.getConstArray(),m); 748 } 749 return m; 750 } 751 752 753 void FTPContent::insert(const InsertCommandArgument& aInsertCommand, 754 const Reference<XCommandEnvironment>& Env) 755 { 756 osl::MutexGuard aGuard(m_aMutex); 757 758 if(m_bInserted && !m_bTitleSet) { 759 MissingPropertiesException excep; 760 excep.Properties.realloc(1); 761 excep.Properties[0] = rtl::OUString::createFromAscii("Title"); 762 Any aAny; aAny <<= excep; 763 ucbhelper::cancelCommandExecution(aAny,Env); 764 } 765 766 if(m_bInserted && 767 m_aInfo.Type == FTP_FILE && 768 !aInsertCommand.Data.is()) 769 { 770 MissingInputStreamException excep; 771 Any aAny; aAny <<= excep; 772 ucbhelper::cancelCommandExecution(aAny,Env); 773 } 774 775 bool bReplace(aInsertCommand.ReplaceExisting); 776 777 retry: 778 try { 779 if(m_aInfo.Type == FTP_FILE) { 780 InsertData data(aInsertCommand.Data); 781 m_aFTPURL.insert(bReplace,&data); 782 } else if(m_aInfo.Type == FTP_FOLDER) 783 m_aFTPURL.mkdir(bReplace); 784 } catch(const curl_exception& e) { 785 if(e.code() == FILE_EXIST_DURING_INSERT || 786 e.code() == FOLDER_EXIST_DURING_INSERT) { 787 // Deprecated, not used anymore: 788 NameClashException excep; 789 excep.Name = m_aFTPURL.child(); 790 Any aAny; 791 aAny <<= excep; 792 ucbhelper::cancelCommandExecution(aAny,Env); 793 } else if(e.code() == FOLDER_MIGHT_EXIST_DURING_INSERT || 794 e.code() == FILE_MIGHT_EXIST_DURING_INSERT) { 795 // Interact 796 Reference<XInteractionHandler> xInt; 797 if(Env.is()) 798 xInt = Env->getInteractionHandler(); 799 800 UnsupportedNameClashException excep; 801 excep.NameClash = 0; //NameClash::ERROR; 802 803 if(!xInt.is()) { 804 Any aAny; 805 aAny <<= excep; 806 ucbhelper::cancelCommandExecution(aAny,Env); 807 } 808 809 XInteractionRequestImpl* p = 810 new XInteractionRequestImpl(m_aFTPURL.child()); 811 Reference<XInteractionRequest> req(p); 812 xInt->handle(req); 813 if(p->approved()) { 814 bReplace = true; 815 goto retry; 816 } 817 else 818 throw excep; 819 } 820 else 821 throw; 822 } 823 824 // May not be reached, because both mkdir and insert can throw curl- 825 // exceptions 826 m_bInserted = false; 827 inserted(); 828 } 829 830 831 832 Reference< XRow > FTPContent::getPropertyValues( 833 const Sequence< Property >& seqProp, 834 const Reference<XCommandEnvironment>& /*environment*/ 835 ) 836 { 837 rtl::Reference<ucbhelper::PropertyValueSet> xRow = 838 new ucbhelper::PropertyValueSet(m_xSMgr); 839 840 FTPDirentry aDirEntry = m_aFTPURL.direntry(); 841 842 for(sal_Int32 i = 0; i < seqProp.getLength(); ++i) { 843 const rtl::OUString& Name = seqProp[i].Name; 844 if(Name.compareToAscii("Title") == 0) 845 xRow->appendString(seqProp[i],aDirEntry.m_aName); 846 else if(Name.compareToAscii("CreatableContentsInfo") == 0) 847 xRow->appendObject(seqProp[i], 848 makeAny(queryCreatableContentsInfo())); 849 else if(aDirEntry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN) { 850 if(Name.compareToAscii("ContentType") == 0) 851 xRow->appendString(seqProp[i], 852 aDirEntry.m_nMode&INETCOREFTP_FILEMODE_ISDIR 853 ? FTP_FOLDER 854 : FTP_FILE ); 855 else if(Name.compareToAscii("IsReadOnly") == 0) 856 xRow->appendBoolean(seqProp[i], 857 aDirEntry.m_nMode 858 & INETCOREFTP_FILEMODE_WRITE 859 ? 0 860 : 1 ); 861 else if(Name.compareToAscii("IsDocument") == 0) 862 xRow->appendBoolean(seqProp[i], 863 ! sal_Bool(aDirEntry.m_nMode & 864 INETCOREFTP_FILEMODE_ISDIR)); 865 else if(Name.compareToAscii("IsFolder") == 0) 866 xRow->appendBoolean(seqProp[i], 867 sal_Bool(aDirEntry.m_nMode & 868 INETCOREFTP_FILEMODE_ISDIR)); 869 else if(Name.compareToAscii("Size") == 0) 870 xRow->appendLong(seqProp[i], 871 aDirEntry.m_nSize); 872 else if(Name.compareToAscii("DateCreated") == 0) 873 xRow->appendTimestamp(seqProp[i], 874 aDirEntry.m_aDate); 875 else 876 xRow->appendVoid(seqProp[i]); 877 } else 878 xRow->appendVoid(seqProp[i]); 879 } 880 881 return Reference<XRow>(xRow.get()); 882 } 883 884 885 886 Sequence<Any> FTPContent::setPropertyValues( 887 const Sequence<PropertyValue>& seqPropVal) 888 { 889 Sequence<Any> ret(seqPropVal.getLength()); 890 Sequence<PropertyChangeEvent > evt; 891 892 osl::MutexGuard aGuard(m_aMutex); 893 for(sal_Int32 i = 0; i < ret.getLength(); ++i) { 894 if(seqPropVal[i].Name.equalsAscii("Title")) { 895 rtl::OUString Title; 896 if(!(seqPropVal[i].Value >>= Title)) { 897 ret[i] <<= IllegalTypeException(); 898 continue; 899 } else if(!Title.getLength()) { 900 ret[i] <<= IllegalArgumentException(); 901 continue; 902 } 903 904 if(m_bInserted) { 905 m_aFTPURL.child(Title); 906 m_xIdentifier = 907 new FTPContentIdentifier(m_aFTPURL.ident(false,false)); 908 m_bTitleSet = true; 909 } else 910 try { 911 rtl::OUString OldTitle = m_aFTPURL.ren(Title); 912 evt.realloc(1); 913 evt[0].PropertyName = 914 rtl::OUString::createFromAscii("Title"); 915 evt[0].Further = false; 916 evt[0].PropertyHandle = -1; 917 evt[0].OldValue <<= OldTitle; 918 evt[0].NewValue <<= Title; 919 } catch(const curl_exception&) { 920 InteractiveIOException excep; 921 // any better possibility here? 922 // ( the error code is always CURLE_FTP_QUOTE_ERROR ) 923 excep.Code = IOErrorCode_ACCESS_DENIED; 924 ret[i] <<= excep; 925 } 926 } else { 927 Sequence<Property> props = 928 getProperties(Reference<XCommandEnvironment>(0)); 929 930 // either unknown or read-only 931 ret[i] <<= UnknownPropertyException(); 932 for(sal_Int32 j = 0; j < props.getLength(); ++j) 933 if(props[j].Name == seqPropVal[i].Name) { 934 ret[i] <<= IllegalAccessException( 935 rtl::OUString::createFromAscii( 936 "Property is read-only!"), 937 //props[j].Attributes & PropertyAttribute::READONLY 938 // ? "Property is read-only!" 939 // : "Access denied!"), 940 static_cast< cppu::OWeakObject * >( this )); 941 break; 942 } 943 } 944 } 945 946 if(evt.getLength()) { 947 // title has changed 948 notifyPropertiesChange(evt); 949 exchange(new FTPContentIdentifier(m_aFTPURL.ident(false,false))); 950 } 951 952 return ret; 953 } 954