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 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
abort(sal_Int32)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
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)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
createResultSet()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
execute(const Command & aCommand,sal_Int32,const Reference<XCommandEnvironment> & Environment)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
queryCreatableContentsInfo()643 FTPContent::queryCreatableContentsInfo( )
644 throw (RuntimeException)
645 {
646 return queryCreatableContentsInfo_Static();
647 }
648
649 // static
650 Sequence<ContentInfo >
queryCreatableContentsInfo_Static()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
createNewContent(const ContentInfo & Info)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
getParent()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
setParent(const Reference<XInterface> &)706 FTPContent::setParent(const Reference<XInterface >& /*Parent*/ )
707 throw (NoSupportException,
708 RuntimeException)
709 {
710 throw NoSupportException();
711 }
712
713
714
getParentURL()715 rtl::OUString FTPContent::getParentURL()
716 {
717 return m_aFTPURL.parent();
718 }
719
720
721 class InsertData
722 : public CurlInput {
723
724 public:
725
InsertData(const Reference<XInputStream> & xInputStream)726 InsertData(const Reference<XInputStream>& xInputStream)
727 : m_xInputStream(xInputStream) { }
~InsertData()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
read(sal_Int8 * dest,sal_Int32 nBytesRequested)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
insert(const InsertCommandArgument & aInsertCommand,const Reference<XCommandEnvironment> & Env)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
getPropertyValues(const Sequence<Property> & seqProp,const Reference<XCommandEnvironment> &)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
setPropertyValues(const Sequence<PropertyValue> & seqPropVal)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