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