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