1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 /**************************************************************************
23 **************************************************************************
25 *************************************************************************/
26 #include <com/sun/star/beans/PropertyAttribute.hpp>
28 #include "ftpdynresultset.hxx"
29 #include "ftpresultsetfactory.hxx"
30 #include "ftpresultsetI.hxx"
31 #include "ftpcontent.hxx"
32 #include "ftpcontentprovider.hxx"
33 #include "ftpdirp.hxx"
34 #include "ftpcontentidentifier.hxx"
35 #include "ftpintreq.hxx"
41 #include <comphelper/propertysequence.hxx>
42 #include <cppuhelper/queryinterface.hxx>
43 #include <cppuhelper/supportsservice.hxx>
44 #include <cppuhelper/typeprovider.hxx>
45 #include <ucbhelper/cancelcommandexecution.hxx>
46 #include <ucbhelper/fd_inputstream.hxx>
47 #include <ucbhelper/propertyvalueset.hxx>
48 #include <ucbhelper/simpleauthenticationrequest.hxx>
49 #include <com/sun/star/lang/IllegalAccessException.hpp>
50 #include <com/sun/star/lang/NoSupportException.hpp>
51 #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
52 #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
53 #include <com/sun/star/beans/IllegalTypeException.hpp>
54 #include <com/sun/star/beans/UnknownPropertyException.hpp>
55 #include <com/sun/star/beans/Property.hpp>
56 #include <com/sun/star/ucb/XCommandInfo.hpp>
57 #include <com/sun/star/io/BufferSizeExceededException.hpp>
58 #include <com/sun/star/io/IOException.hpp>
59 #include <com/sun/star/io/NotConnectedException.hpp>
60 #include <com/sun/star/io/XActiveDataSink.hpp>
61 #include <com/sun/star/io/XOutputStream.hpp>
62 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
63 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
64 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
65 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
66 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
67 #include <com/sun/star/ucb/InteractiveIOException.hpp>
68 #include <com/sun/star/ucb/MissingPropertiesException.hpp>
69 #include <com/sun/star/ucb/MissingInputStreamException.hpp>
70 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
71 #include <com/sun/star/ucb/OpenMode.hpp>
72 #include <com/sun/star/ucb/IOErrorCode.hpp>
75 using namespace com::sun::star::task
;
76 using namespace com::sun::star::container
;
77 using namespace com::sun::star::lang
;
78 using namespace com::sun::star::uno
;
79 using namespace com::sun::star::ucb
;
80 using namespace com::sun::star::beans
;
81 using namespace com::sun::star::io
;
82 using namespace com::sun::star::sdbc
;
85 // Content Implementation.
87 FTPContent::FTPContent( const Reference
< XComponentContext
>& rxContext
,
88 FTPContentProvider
* pProvider
,
89 const Reference
< XContentIdentifier
>& Identifier
,
90 const FTPURL
& aFTPURL
)
91 : ContentImplHelper(rxContext
,pProvider
,Identifier
)
99 FTPContent::FTPContent( const Reference
< XComponentContext
>& rxContext
,
100 FTPContentProvider
* pProvider
,
101 const Reference
< XContentIdentifier
>& Identifier
,
102 const ContentInfo
& Info
)
103 : ContentImplHelper(rxContext
,pProvider
,Identifier
)
105 , m_aFTPURL(Identifier
->getContentIdentifier(), pProvider
)
112 FTPContent::~FTPContent()
116 // XInterface methods.
118 void SAL_CALL
FTPContent::acquire()
121 OWeakObject::acquire();
124 void SAL_CALL
FTPContent::release()
127 OWeakObject::release();
130 css::uno::Any SAL_CALL
FTPContent::queryInterface( const css::uno::Type
& rType
)
132 css::uno::Any aRet
= cppu::queryInterface( rType
,
133 static_cast< XTypeProvider
* >(this),
134 static_cast< XServiceInfo
* >(this),
135 static_cast< XContent
* >(this),
136 static_cast< XCommandProcessor
* >(this),
137 static_cast< XContentCreator
* >(this),
138 static_cast< XChild
* >(this)
140 return aRet
.hasValue() ? aRet
: OWeakObject::queryInterface( rType
);
143 // XTypeProvider methods.
145 css::uno::Sequence
< sal_Int8
> SAL_CALL
FTPContent::getImplementationId()
147 return css::uno::Sequence
<sal_Int8
>();
150 css::uno::Sequence
< css::uno::Type
> SAL_CALL
FTPContent::getTypes()
152 static cppu::OTypeCollection
s_aCollection(
153 cppu::UnoType
<XTypeProvider
>::get(),
154 cppu::UnoType
<XServiceInfo
>::get(),
155 cppu::UnoType
<XContent
>::get(),
156 cppu::UnoType
<XCommandProcessor
>::get(),
157 cppu::UnoType
<XContentCreator
>::get(),
158 cppu::UnoType
<XChild
>::get()
161 return s_aCollection
.getTypes();
165 // XServiceInfo methods.
167 OUString SAL_CALL
FTPContent::getImplementationName()
169 return "com.sun.star.comp.FTPContent";
172 sal_Bool SAL_CALL
FTPContent::supportsService( const OUString
& ServiceName
)
174 return cppu::supportsService( this, ServiceName
);
177 css::uno::Sequence
< OUString
> SAL_CALL
FTPContent::getSupportedServiceNames()
179 return { "com.sun.star.ucb.FTPContent" };
186 OUString SAL_CALL
FTPContent::getContentType()
188 return FTP_CONTENT_TYPE
;
191 // XCommandProcessor methods.
194 void SAL_CALL
FTPContent::abort( sal_Int32
/*CommandId*/ )
199 ResultSetFactory::ResultSetFactory(const Reference
<XComponentContext
>& rxContext
,
200 const Reference
<XContentProvider
>& xProvider
,
201 const Sequence
<Property
>& seq
,
202 const std::vector
<FTPDirentry
>& dirvec
)
203 : m_xContext(rxContext
),
204 m_xProvider(xProvider
),
211 rtl::Reference
<ResultSetBase
> ResultSetFactory::createResultSet()
213 return new ResultSetI(m_xContext
,
220 // XCommandProcessor methods.
224 enum ACTION
{ NOACTION
,
225 THROWAUTHENTICATIONREQUEST
,
227 THROWINTERACTIVECONNECT
,
236 Any SAL_CALL
FTPContent::execute( const Command
& aCommand
,
237 sal_Int32
/*CommandId*/,
239 XCommandEnvironment
>& Environment
)
241 ACTION
action(NOACTION
);
248 if(action
== THROWAUTHENTICATIONREQUEST
)
250 // try to get a continuation first
251 OUString aPassword
,aAccount
;
252 m_pFCP
->forHost(m_aFTPURL
.host(),
254 m_aFTPURL
.username(),
257 rtl::Reference
<ucbhelper::SimpleAuthenticationRequest
>
258 p( new ucbhelper::SimpleAuthenticationRequest(
259 m_aFTPURL
.ident(false, false),
260 m_aFTPURL
.host(), // ServerName
261 ucbhelper::SimpleAuthenticationRequest::ENTITY_NA
,
263 ucbhelper::SimpleAuthenticationRequest
265 m_aFTPURL
.username(),
266 ucbhelper::SimpleAuthenticationRequest
270 Reference
<XInteractionHandler
> xInteractionHandler
;
272 xInteractionHandler
=
273 Environment
->getInteractionHandler();
275 if( xInteractionHandler
.is()) {
276 xInteractionHandler
->handle(p
);
278 Reference
<XInterface
> xSelection(
281 if(Reference
<XInteractionRetry
>(
282 xSelection
,UNO_QUERY
).is())
284 else if(Reference
<XInteractionSupplyAuthentication
>(
285 xSelection
,UNO_QUERY
).is()) {
289 m_aFTPURL
.username(),
290 p
->getAuthenticationSupplier()->getPassword(),
295 aRet
= p
->getRequest();
298 // if(aCommand.Name.equalsAscii(
299 // "getPropertyValues") &&
300 // action != NOACTION) {
301 // // It is not allowed to throw if
302 // // command is getPropertyValues
303 // rtl::Reference<ucbhelper::PropertyValueSet> xRow =
304 // new ucbhelper::PropertyValueSet(m_xSMgr);
305 // Sequence<Property> Properties;
306 // aCommand.Argument >>= Properties;
307 // for(int i = 0; i < Properties.getLength(); ++i)
308 // xRow->appendVoid(Properties[i]);
309 // aRet <<= Reference<XRow>(xRow.get());
318 case THROWAUTHENTICATIONREQUEST
:
319 ucbhelper::cancelCommandExecution(
321 Reference
<XCommandEnvironment
>(nullptr));
324 case THROWACCESSDENIED
:
326 Sequence
<Any
> seq(comphelper::InitAnyPropertySequence(
328 {"Uri", Any(m_aFTPURL
.ident(false,false))}
330 ucbhelper::cancelCommandExecution(
331 IOErrorCode_ACCESS_DENIED
,
336 case THROWINTERACTIVECONNECT
:
338 InteractiveNetworkConnectException excep
;
339 excep
.Server
= m_aFTPURL
.host();
341 ucbhelper::cancelCommandExecution(
346 case THROWRESOLVENAME
:
348 InteractiveNetworkResolveNameException excep
;
349 excep
.Server
= m_aFTPURL
.host();
351 ucbhelper::cancelCommandExecution(
358 Sequence
<Any
> seq(comphelper::InitAnyPropertySequence(
360 {"Uri", Any(m_aFTPURL
.ident(false,false))}
362 ucbhelper::cancelCommandExecution(
370 ucbhelper::cancelCommandExecution(
377 if(aCommand
.Name
== "getPropertyValues") {
378 Sequence
<Property
> Properties
;
379 if(!(aCommand
.Argument
>>= Properties
))
381 aRet
<<= IllegalArgumentException(
382 "Wrong argument type!",
383 static_cast< cppu::OWeakObject
* >(this),
385 ucbhelper::cancelCommandExecution(aRet
,Environment
);
388 aRet
<<= getPropertyValues(Properties
);
390 else if(aCommand
.Name
== "setPropertyValues")
392 Sequence
<PropertyValue
> propertyValues
;
394 if( ! ( aCommand
.Argument
>>= propertyValues
) ) {
395 aRet
<<= IllegalArgumentException(
396 "Wrong argument type!",
397 static_cast< cppu::OWeakObject
* >(this),
399 ucbhelper::cancelCommandExecution(aRet
,Environment
);
402 aRet
<<= setPropertyValues(propertyValues
);
404 else if(aCommand
.Name
== "getCommandInfo") {
405 // Note: Implemented by base class.
406 aRet
<<= getCommandInfo(Environment
);
408 else if(aCommand
.Name
== "getPropertySetInfo") {
409 // Note: Implemented by base class.
410 aRet
<<= getPropertySetInfo(Environment
);
412 else if(aCommand
.Name
== "insert")
414 InsertCommandArgument aInsertArgument
;
415 if ( ! ( aCommand
.Argument
>>= aInsertArgument
) ) {
416 aRet
<<= IllegalArgumentException(
417 "Wrong argument type!",
418 static_cast< cppu::OWeakObject
* >(this),
420 ucbhelper::cancelCommandExecution(aRet
,Environment
);
422 insert(aInsertArgument
,Environment
);
424 else if(aCommand
.Name
== "delete") {
428 else if(aCommand
.Name
== "open") {
429 OpenCommandArgument2 aOpenCommand
;
430 if ( !( aCommand
.Argument
>>= aOpenCommand
) ) {
431 aRet
<<= IllegalArgumentException(
432 "Wrong argument type!",
433 static_cast< cppu::OWeakObject
* >(this),
436 ucbhelper::cancelCommandExecution(aRet
,Environment
);
439 if(aOpenCommand
.Mode
== OpenMode::DOCUMENT
) {
440 // Open as a document
441 Reference
<XActiveDataSink
>
442 xActiveDataSink(aOpenCommand
.Sink
,UNO_QUERY
);
443 Reference
< XOutputStream
>
444 xOutputStream(aOpenCommand
.Sink
,UNO_QUERY
);
446 if(xActiveDataSink
.is()) {
447 xActiveDataSink
->setInputStream(
448 new ucbhelper::FdInputStream(m_aFTPURL
.open()));
450 else if(xOutputStream
.is()) {
451 Reference
<XInputStream
> xStream(
452 new ucbhelper::FdInputStream(m_aFTPURL
.open()));
454 Sequence
<sal_Int8
> byte_seq(4096);
455 sal_Int32 n
= xStream
->readBytes(byte_seq
, 4096);
460 if(byte_seq
.getLength() != n
)
462 xOutputStream
->writeBytes(byte_seq
);
463 } catch(const NotConnectedException
&) {
465 } catch(const BufferSizeExceededException
&) {
467 } catch(const IOException
&) {
473 aRet
<<= UnsupportedDataSinkException(
475 static_cast< cppu::OWeakObject
* >(this),
477 ucbhelper::cancelCommandExecution(aRet
,Environment
);
480 else if(aOpenCommand
.Mode
== OpenMode::ALL
||
481 aOpenCommand
.Mode
== OpenMode::DOCUMENTS
||
482 aOpenCommand
.Mode
== OpenMode::FOLDERS
) {
483 std::vector
<FTPDirentry
> resvec
=
484 m_aFTPURL
.list(sal_Int16(aOpenCommand
.Mode
));
485 Reference
< XDynamicResultSet
> xSet
486 = new DynamicResultSet(
489 std::make_unique
<ResultSetFactory
>(m_xContext
,
491 aOpenCommand
.Properties
,
495 else if(aOpenCommand
.Mode
==
496 OpenMode::DOCUMENT_SHARE_DENY_NONE
||
498 OpenMode::DOCUMENT_SHARE_DENY_WRITE
) {
499 // Unsupported OpenMode
500 aRet
<<= UnsupportedOpenModeException(
502 static_cast< cppu::OWeakObject
* >(this),
503 static_cast< sal_Int16
>(aOpenCommand
.Mode
));
504 ucbhelper::cancelCommandExecution(aRet
,Environment
);
507 aRet
<<= IllegalArgumentException(
508 "Unexpected OpenMode!",
509 static_cast< cppu::OWeakObject
* >(this),
512 ucbhelper::cancelCommandExecution(aRet
,Environment
);
514 } else if(aCommand
.Name
== "createNewContent") {
516 if (!(aCommand
.Argument
>>= aArg
)) {
517 ucbhelper::cancelCommandExecution(
519 IllegalArgumentException(
520 "Wrong argument type!",
521 static_cast< cppu::OWeakObject
* >(this),
526 aRet
<<= createNewContent(aArg
);
528 aRet
<<= UnsupportedCommandException(
530 static_cast< cppu::OWeakObject
* >(this));
531 ucbhelper::cancelCommandExecution(aRet
,Environment
);
536 catch(const curl_exception
& e
)
538 if(e
.code() == CURLE_COULDNT_CONNECT
)
539 action
= THROWINTERACTIVECONNECT
;
540 else if(e
.code() == CURLE_COULDNT_RESOLVE_HOST
)
541 action
= THROWRESOLVENAME
;
542 else if(e
.code() == CURLE_FTP_USER_PASSWORD_INCORRECT
||
543 e
.code() == CURLE_LOGIN_DENIED
||
544 e
.code() == CURLE_BAD_PASSWORD_ENTERED
||
545 e
.code() == CURLE_FTP_WEIRD_PASS_REPLY
)
546 action
= THROWAUTHENTICATIONREQUEST
;
547 else if(e
.code() == CURLE_FTP_ACCESS_DENIED
)
548 action
= THROWACCESSDENIED
;
549 else if(e
.code() == CURLE_FTP_QUOTE_ERROR
)
551 else if(e
.code() == CURLE_FTP_COULDNT_RETR_FILE
)
552 action
= THROWNOFILE
;
554 // nothing known about the cause of the error
555 action
= THROWGENERAL
;
560 #define FTP_FILE "application/vnd.sun.staroffice.ftp-file"
562 #define FTP_FOLDER "application/vnd.sun.staroffice.ftp-folder"
564 Sequence
<ContentInfo
> SAL_CALL
565 FTPContent::queryCreatableContentsInfo( )
567 return queryCreatableContentsInfo_Static();
571 Sequence
<ContentInfo
>
572 FTPContent::queryCreatableContentsInfo_Static( )
574 Sequence
< Property
> props( 1 );
578 cppu::UnoType
<OUString
>::get(),
579 PropertyAttribute::MAYBEVOID
580 | PropertyAttribute::BOUND
);
583 { FTP_FILE
, ContentInfoAttribute::INSERT_WITH_INPUTSTREAM
| ContentInfoAttribute::KIND_DOCUMENT
, props
},
584 { FTP_FOLDER
, ContentInfoAttribute::KIND_FOLDER
, props
}
588 Reference
<XContent
> SAL_CALL
589 FTPContent::createNewContent( const ContentInfo
& Info
)
591 if( Info
.Type
=="application/vnd.sun.staroffice.ftp-file" || Info
.Type
== "application/vnd.sun.staroffice.ftp-folder" )
592 return new FTPContent(m_xContext
,
596 return Reference
<XContent
>(nullptr);
600 Reference
<XInterface
> SAL_CALL
601 FTPContent::getParent( )
603 Reference
<XContentIdentifier
>
604 xIdent(new FTPContentIdentifier(m_aFTPURL
.parent()));
605 return Reference
<XInterface
>( m_xProvider
->queryContent(xIdent
), UNO_QUERY
);
610 FTPContent::setParent(const Reference
<XInterface
>& /*Parent*/ )
612 throw NoSupportException();
616 OUString
FTPContent::getParentURL()
618 return m_aFTPURL
.parent();
628 explicit InsertData(const Reference
<XInputStream
>& xInputStream
)
629 : m_xInputStream(xInputStream
) { }
630 virtual ~InsertData() {}
632 // returns the number of bytes actually read
633 virtual sal_Int32
read(sal_Int8
*dest
,sal_Int32 nBytesRequested
) override
;
637 Reference
<XInputStream
> m_xInputStream
;
642 sal_Int32
InsertData::read(sal_Int8
*dest
,sal_Int32 nBytesRequested
)
646 if(m_xInputStream
.is()) {
647 Sequence
<sal_Int8
> seq(nBytesRequested
);
648 m
= m_xInputStream
->readBytes(seq
,nBytesRequested
);
649 memcpy(dest
,seq
.getConstArray(),m
);
655 void FTPContent::insert(const InsertCommandArgument
& aInsertCommand
,
656 const Reference
<XCommandEnvironment
>& Env
)
658 osl::MutexGuard
aGuard(m_aMutex
);
660 if(m_bInserted
&& !m_bTitleSet
) {
661 MissingPropertiesException excep
;
662 excep
.Properties
.realloc(1);
663 excep
.Properties
[0] = "Title";
664 ucbhelper::cancelCommandExecution(Any(excep
), Env
);
668 m_aInfo
.Type
== FTP_FILE
&&
669 !aInsertCommand
.Data
.is())
671 MissingInputStreamException excep
;
672 ucbhelper::cancelCommandExecution(Any(excep
), Env
);
675 bool bReplace(aInsertCommand
.ReplaceExisting
);
679 if(m_aInfo
.Type
== FTP_FILE
) {
680 InsertData
data(aInsertCommand
.Data
);
681 m_aFTPURL
.insert(bReplace
,&data
);
682 } else if(m_aInfo
.Type
== FTP_FOLDER
)
683 m_aFTPURL
.mkdir(bReplace
);
684 } catch(const curl_exception
& e
) {
685 if(e
.code() == FOLDER_MIGHT_EXIST_DURING_INSERT
||
686 e
.code() == FILE_MIGHT_EXIST_DURING_INSERT
) {
688 Reference
<XInteractionHandler
> xInt
;
690 xInt
= Env
->getInteractionHandler();
692 UnsupportedNameClashException excep
;
693 excep
.NameClash
= 0; //NameClash::ERROR;
696 ucbhelper::cancelCommandExecution(Any(excep
), Env
);
699 XInteractionRequestImpl request
;
700 const Reference
<XInteractionRequest
>& xReq(request
.getRequest());
702 if (request
.approved()) {
713 // May not be reached, because both mkdir and insert can throw curl-
720 Reference
< XRow
> FTPContent::getPropertyValues(
721 const Sequence
< Property
>& seqProp
724 rtl::Reference
<ucbhelper::PropertyValueSet
> xRow
=
725 new ucbhelper::PropertyValueSet(m_xContext
);
727 FTPDirentry aDirEntry
= m_aFTPURL
.direntry();
729 for(const auto& rProp
: seqProp
) {
730 const OUString
& Name
= rProp
.Name
;
732 xRow
->appendString(rProp
,aDirEntry
.m_aName
);
733 else if(Name
== "CreatableContentsInfo")
734 xRow
->appendObject(rProp
,
735 makeAny(queryCreatableContentsInfo()));
736 else if(aDirEntry
.m_nMode
!= INETCOREFTP_FILEMODE_UNKNOWN
) {
737 if(Name
== "ContentType")
738 xRow
->appendString(rProp
,
739 (aDirEntry
.m_nMode
& INETCOREFTP_FILEMODE_ISDIR
)
740 ? OUString(FTP_FOLDER
)
741 : OUString(FTP_FILE
) );
742 else if(Name
== "IsReadOnly")
743 xRow
->appendBoolean(rProp
,
745 & INETCOREFTP_FILEMODE_WRITE
) == 0 );
746 else if(Name
== "IsDocument")
747 xRow
->appendBoolean(rProp
,
749 INETCOREFTP_FILEMODE_ISDIR
) != INETCOREFTP_FILEMODE_ISDIR
);
750 else if(Name
== "IsFolder")
751 xRow
->appendBoolean(rProp
,
753 INETCOREFTP_FILEMODE_ISDIR
) == INETCOREFTP_FILEMODE_ISDIR
);
754 else if(Name
== "Size")
755 xRow
->appendLong(rProp
,
757 else if(Name
== "DateCreated")
758 xRow
->appendTimestamp(rProp
,
761 xRow
->appendVoid(rProp
);
763 xRow
->appendVoid(rProp
);
770 Sequence
<Any
> FTPContent::setPropertyValues(
771 const Sequence
<PropertyValue
>& seqPropVal
)
773 Sequence
<Any
> ret(seqPropVal
.getLength());
774 Sequence
<PropertyChangeEvent
> evt
;
776 osl::MutexGuard
aGuard(m_aMutex
);
777 for(sal_Int32 i
= 0; i
< ret
.getLength(); ++i
) {
778 if ( seqPropVal
[i
].Name
== "Title" ) {
780 if(!(seqPropVal
[i
].Value
>>= Title
)) {
781 ret
[i
] <<= IllegalTypeException();
783 } else if(Title
.isEmpty()) {
784 ret
[i
] <<= IllegalArgumentException();
789 m_aFTPURL
.child(Title
);
791 new FTPContentIdentifier(m_aFTPURL
.ident(false,false));
795 OUString OldTitle
= m_aFTPURL
.ren(Title
);
797 evt
[0].PropertyName
= "Title";
798 evt
[0].Further
= false;
799 evt
[0].PropertyHandle
= -1;
800 evt
[0].OldValue
<<= OldTitle
;
801 evt
[0].NewValue
<<= Title
;
802 } catch(const curl_exception
&) {
803 InteractiveIOException excep
;
804 // any better possibility here?
805 // ( the error code is always CURLE_FTP_QUOTE_ERROR )
806 excep
.Code
= IOErrorCode_ACCESS_DENIED
;
810 Sequence
<Property
> props
=
811 getProperties(Reference
<XCommandEnvironment
>(nullptr));
813 // either unknown or read-only
814 ret
[i
] <<= UnknownPropertyException();
815 const auto& rName
= seqPropVal
[i
].Name
;
816 auto pProp
= std::find_if(props
.begin(), props
.end(),
817 [&rName
](const Property
& rProp
) { return rProp
.Name
== rName
; });
818 if (pProp
!= props
.end()) {
819 ret
[i
] <<= IllegalAccessException(
820 "Property is read-only!",
821 //props[j].Attributes & PropertyAttribute::READONLY
822 // ? "Property is read-only!"
823 // : "Access denied!"),
824 static_cast< cppu::OWeakObject
* >( this ));
829 if(evt
.hasElements()) {
831 notifyPropertiesChange(evt
);
832 (void)exchange(new FTPContentIdentifier(m_aFTPURL
.ident(false,false)));
838 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */