xref: /trunk/main/ucb/source/ucp/ftp/ftpcontent.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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