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