summaryrefslogtreecommitdiffstats
path: root/ucb/source/ucp/ftp/ftpcontent.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /ucb/source/ucp/ftp/ftpcontent.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ucb/source/ucp/ftp/ftpcontent.cxx')
-rw-r--r--ucb/source/ucp/ftp/ftpcontent.cxx852
1 files changed, 852 insertions, 0 deletions
diff --git a/ucb/source/ucp/ftp/ftpcontent.cxx b/ucb/source/ucp/ftp/ftpcontent.cxx
new file mode 100644
index 000000000..4c7888e25
--- /dev/null
+++ b/ucb/source/ucp/ftp/ftpcontent.cxx
@@ -0,0 +1,852 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+/**************************************************************************
+ TODO
+ **************************************************************************
+
+ *************************************************************************/
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include "ftpdynresultset.hxx"
+#include "ftpresultsetfactory.hxx"
+#include "ftpresultsetI.hxx"
+#include "ftpcontent.hxx"
+#include "ftpcontentprovider.hxx"
+#include "ftpdirp.hxx"
+#include "ftpcontentidentifier.hxx"
+#include "ftpintreq.hxx"
+
+#include <memory>
+#include <vector>
+#include <string.h>
+#include "curl.hxx"
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <ucbhelper/cancelcommandexecution.hxx>
+#include <ucbhelper/fd_inputstream.hxx>
+#include <ucbhelper/propertyvalueset.hxx>
+#include <ucbhelper/simpleauthenticationrequest.hxx>
+#include <com/sun/star/lang/IllegalAccessException.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
+#include <com/sun/star/ucb/UnsupportedCommandException.hpp>
+#include <com/sun/star/beans/IllegalTypeException.hpp>
+#include <com/sun/star/beans/UnknownPropertyException.hpp>
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/ucb/XCommandInfo.hpp>
+#include <com/sun/star/io/BufferSizeExceededException.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/io/NotConnectedException.hpp>
+#include <com/sun/star/io/XActiveDataSink.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
+#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
+#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
+#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
+#include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp>
+#include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
+#include <com/sun/star/ucb/InteractiveIOException.hpp>
+#include <com/sun/star/ucb/MissingPropertiesException.hpp>
+#include <com/sun/star/ucb/MissingInputStreamException.hpp>
+#include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
+#include <com/sun/star/ucb/OpenMode.hpp>
+#include <com/sun/star/ucb/IOErrorCode.hpp>
+
+using namespace ftp;
+using namespace com::sun::star::task;
+using namespace com::sun::star::container;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::ucb;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::io;
+using namespace com::sun::star::sdbc;
+
+
+// Content Implementation.
+
+FTPContent::FTPContent( const Reference< XComponentContext >& rxContext,
+ FTPContentProvider* pProvider,
+ const Reference< XContentIdentifier >& Identifier,
+ const FTPURL& aFTPURL)
+ : ContentImplHelper(rxContext,pProvider,Identifier)
+ , m_pFCP(pProvider)
+ , m_aFTPURL(aFTPURL)
+ , m_bInserted(false)
+ , m_bTitleSet(false)
+{
+}
+
+FTPContent::FTPContent( const Reference< XComponentContext >& rxContext,
+ FTPContentProvider* pProvider,
+ const Reference< XContentIdentifier >& Identifier,
+ const ContentInfo& Info)
+ : ContentImplHelper(rxContext,pProvider,Identifier)
+ , m_pFCP(pProvider)
+ , m_aFTPURL(Identifier->getContentIdentifier(), pProvider)
+ , m_bInserted(true)
+ , m_bTitleSet(false)
+ , m_aInfo(Info)
+{
+}
+
+FTPContent::~FTPContent()
+{
+}
+
+// XInterface methods.
+
+void SAL_CALL FTPContent::acquire()
+ noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL FTPContent::release()
+ noexcept
+{
+ OWeakObject::release();
+}
+
+css::uno::Any SAL_CALL FTPContent::queryInterface( const css::uno::Type & rType )
+{
+ css::uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< XTypeProvider* >(this),
+ static_cast< XServiceInfo* >(this),
+ static_cast< XContent* >(this),
+ static_cast< XCommandProcessor* >(this),
+ static_cast< XContentCreator* >(this),
+ static_cast< XChild* >(this)
+ );
+ return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
+}
+
+// XTypeProvider methods.
+
+css::uno::Sequence< sal_Int8 > SAL_CALL FTPContent::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL FTPContent::getTypes()
+{
+ static cppu::OTypeCollection s_aCollection(
+ cppu::UnoType<XTypeProvider>::get(),
+ cppu::UnoType<XServiceInfo>::get(),
+ cppu::UnoType<XContent>::get(),
+ cppu::UnoType<XCommandProcessor>::get(),
+ cppu::UnoType<XContentCreator>::get(),
+ cppu::UnoType<XChild>::get()
+ );
+
+ return s_aCollection.getTypes();
+}
+
+
+// XServiceInfo methods.
+
+OUString SAL_CALL FTPContent::getImplementationName()
+{
+ return "com.sun.star.comp.FTPContent";
+}
+
+sal_Bool SAL_CALL FTPContent::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+css::uno::Sequence< OUString > SAL_CALL FTPContent::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.FTPContent" };
+}
+
+
+// XContent methods.
+
+// virtual
+OUString SAL_CALL FTPContent::getContentType()
+{
+ return FTP_CONTENT_TYPE;
+}
+
+// XCommandProcessor methods.
+
+//virtual
+void SAL_CALL FTPContent::abort( sal_Int32 /*CommandId*/ )
+{
+}
+
+
+ResultSetFactory::ResultSetFactory(const Reference<XComponentContext >& rxContext,
+ const Reference<XContentProvider >& xProvider,
+ const Sequence<Property>& seq,
+ std::vector<FTPDirentry>&& dirvec)
+ : m_xContext(rxContext),
+ m_xProvider(xProvider),
+ m_seq(seq),
+ m_dirvec(std::move(dirvec))
+{
+}
+
+
+rtl::Reference<ResultSetBase> ResultSetFactory::createResultSet()
+{
+ return new ResultSetI(m_xContext,
+ m_xProvider,
+ m_seq,
+ m_dirvec);
+}
+
+
+// XCommandProcessor methods.
+
+namespace {
+
+enum ACTION { NOACTION,
+ THROWAUTHENTICATIONREQUEST,
+ THROWACCESSDENIED,
+ THROWINTERACTIVECONNECT,
+ THROWMALFORMED,
+ THROWRESOLVENAME,
+ THROWQUOTE,
+ THROWNOFILE,
+ THROWGENERAL };
+
+}
+
+// virtual
+Any SAL_CALL FTPContent::execute( const Command& aCommand,
+ sal_Int32 /*CommandId*/,
+ const Reference<
+ XCommandEnvironment >& Environment)
+{
+ ACTION action(NOACTION);
+ Any aRet;
+
+ while(true)
+ {
+ try
+ {
+ if(action == THROWAUTHENTICATIONREQUEST)
+ {
+ // try to get a continuation first
+ OUString aPassword,aAccount;
+ m_pFCP->forHost(m_aFTPURL.host(),
+ m_aFTPURL.port(),
+ m_aFTPURL.username(),
+ aPassword,
+ aAccount);
+ rtl::Reference<ucbhelper::SimpleAuthenticationRequest>
+ p( new ucbhelper::SimpleAuthenticationRequest(
+ m_aFTPURL.ident(false, false),
+ m_aFTPURL.host(), // ServerName
+ ucbhelper::SimpleAuthenticationRequest::ENTITY_NA,
+ OUString(),
+ ucbhelper::SimpleAuthenticationRequest
+ ::ENTITY_FIXED,
+ m_aFTPURL.username(),
+ ucbhelper::SimpleAuthenticationRequest
+ ::ENTITY_MODIFY,
+ aPassword));
+
+ Reference<XInteractionHandler> xInteractionHandler;
+ if(Environment.is())
+ xInteractionHandler =
+ Environment->getInteractionHandler();
+
+ if( xInteractionHandler.is()) {
+ xInteractionHandler->handle(p);
+
+ Reference<XInterface> xSelection(
+ p->getSelection());
+
+ if(Reference<XInteractionRetry>(
+ xSelection,UNO_QUERY).is())
+ action = NOACTION;
+ else if(Reference<XInteractionSupplyAuthentication>(
+ xSelection,UNO_QUERY).is()) {
+ m_pFCP->setHost(
+ m_aFTPURL.host(),
+ m_aFTPURL.port(),
+ m_aFTPURL.username(),
+ p->getAuthenticationSupplier()->getPassword(),
+ aAccount);
+ action = NOACTION;
+ }
+ }
+ aRet = p->getRequest();
+ }
+
+// if(aCommand.Name.equalsAscii(
+// "getPropertyValues") &&
+// action != NOACTION) {
+// // It is not allowed to throw if
+// // command is getPropertyValues
+// rtl::Reference<ucbhelper::PropertyValueSet> xRow =
+// new ucbhelper::PropertyValueSet(m_xSMgr);
+// Sequence<Property> Properties;
+// aCommand.Argument >>= Properties;
+// for(int i = 0; i < Properties.getLength(); ++i)
+// xRow->appendVoid(Properties[i]);
+// aRet <<= Reference<XRow>(xRow.get());
+// return aRet;
+// }
+
+ switch (action)
+ {
+ case NOACTION:
+ break;
+
+ case THROWAUTHENTICATIONREQUEST:
+ ucbhelper::cancelCommandExecution(
+ aRet,
+ Reference<XCommandEnvironment>(nullptr));
+ break;
+
+ case THROWACCESSDENIED:
+ {
+ Sequence<Any> seq(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", Any(m_aFTPURL.ident(false,false))}
+ }));
+ ucbhelper::cancelCommandExecution(
+ IOErrorCode_ACCESS_DENIED,
+ seq,
+ Environment);
+ break;
+ }
+ case THROWINTERACTIVECONNECT:
+ {
+ InteractiveNetworkConnectException excep;
+ excep.Server = m_aFTPURL.host();
+ aRet <<= excep;
+ ucbhelper::cancelCommandExecution(
+ aRet,
+ Environment);
+ break;
+ }
+ case THROWMALFORMED:
+ {
+ IllegalIdentifierException ex;
+ aRet <<= ex;
+ ucbhelper::cancelCommandExecution(
+ aRet,
+ Environment);
+ break;
+ }
+ case THROWRESOLVENAME:
+ {
+ InteractiveNetworkResolveNameException excep;
+ excep.Server = m_aFTPURL.host();
+ aRet <<= excep;
+ ucbhelper::cancelCommandExecution(
+ aRet,
+ Environment);
+ break;
+ }
+ case THROWNOFILE:
+ {
+ Sequence<Any> seq(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", Any(m_aFTPURL.ident(false,false))}
+ }));
+ ucbhelper::cancelCommandExecution(
+ IOErrorCode_NO_FILE,
+ seq,
+ Environment);
+ break;
+ }
+ case THROWQUOTE:
+ case THROWGENERAL:
+ ucbhelper::cancelCommandExecution(
+ IOErrorCode_GENERAL,
+ Sequence<Any>(0),
+ Environment);
+ break;
+ }
+
+ if(aCommand.Name == "getPropertyValues") {
+ Sequence<Property> Properties;
+ if(!(aCommand.Argument >>= Properties))
+ {
+ aRet <<= IllegalArgumentException(
+ "Wrong argument type!",
+ static_cast< cppu::OWeakObject * >(this),
+ -1);
+ ucbhelper::cancelCommandExecution(aRet,Environment);
+ }
+
+ aRet <<= getPropertyValues(Properties);
+ }
+ else if(aCommand.Name == "setPropertyValues")
+ {
+ Sequence<PropertyValue> propertyValues;
+
+ if( ! ( aCommand.Argument >>= propertyValues ) ) {
+ aRet <<= IllegalArgumentException(
+ "Wrong argument type!",
+ static_cast< cppu::OWeakObject * >(this),
+ -1);
+ ucbhelper::cancelCommandExecution(aRet,Environment);
+ }
+
+ aRet <<= setPropertyValues(propertyValues);
+ }
+ else if(aCommand.Name == "getCommandInfo") {
+ // Note: Implemented by base class.
+ aRet <<= getCommandInfo(Environment);
+ }
+ else if(aCommand.Name == "getPropertySetInfo") {
+ // Note: Implemented by base class.
+ aRet <<= getPropertySetInfo(Environment);
+ }
+ else if(aCommand.Name == "insert")
+ {
+ InsertCommandArgument aInsertArgument;
+ if ( ! ( aCommand.Argument >>= aInsertArgument ) ) {
+ aRet <<= IllegalArgumentException(
+ "Wrong argument type!",
+ static_cast< cppu::OWeakObject * >(this),
+ -1);
+ ucbhelper::cancelCommandExecution(aRet,Environment);
+ }
+ insert(aInsertArgument,Environment);
+ }
+ else if(aCommand.Name == "delete") {
+ m_aFTPURL.del();
+ deleted();
+ }
+ else if(aCommand.Name == "open") {
+ OpenCommandArgument2 aOpenCommand;
+ if ( !( aCommand.Argument >>= aOpenCommand ) ) {
+ aRet <<= IllegalArgumentException(
+ "Wrong argument type!",
+ static_cast< cppu::OWeakObject * >(this),
+ -1);
+
+ ucbhelper::cancelCommandExecution(aRet,Environment);
+ }
+
+ if(aOpenCommand.Mode == OpenMode::DOCUMENT) {
+ // Open as a document
+ Reference<XActiveDataSink>
+ xActiveDataSink(aOpenCommand.Sink,UNO_QUERY);
+ Reference< XOutputStream >
+ xOutputStream(aOpenCommand.Sink,UNO_QUERY);
+
+ if(xActiveDataSink.is()) {
+ xActiveDataSink->setInputStream(
+ new ucbhelper::FdInputStream(m_aFTPURL.open()));
+ }
+ else if(xOutputStream.is()) {
+ Reference<XInputStream> xStream(
+ new ucbhelper::FdInputStream(m_aFTPURL.open()));
+ for (;;) {
+ Sequence<sal_Int8> byte_seq(4096);
+ sal_Int32 n = xStream->readBytes(byte_seq, 4096);
+ if (n == 0) {
+ break;
+ }
+ try {
+ if(byte_seq.getLength() != n)
+ byte_seq.realloc(n);
+ xOutputStream->writeBytes(byte_seq);
+ } catch(const NotConnectedException&) {
+
+ } catch(const BufferSizeExceededException&) {
+
+ } catch(const IOException&) {
+
+ }
+ }
+ }
+ else {
+ aRet <<= UnsupportedDataSinkException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >(this),
+ aOpenCommand.Sink);
+ ucbhelper::cancelCommandExecution(aRet,Environment);
+ }
+ }
+ else if(aOpenCommand.Mode == OpenMode::ALL ||
+ aOpenCommand.Mode == OpenMode::DOCUMENTS ||
+ aOpenCommand.Mode == OpenMode::FOLDERS ) {
+ std::vector<FTPDirentry> resvec =
+ m_aFTPURL.list(sal_Int16(aOpenCommand.Mode));
+ Reference< XDynamicResultSet > xSet
+ = new DynamicResultSet(
+ m_xContext,
+ aOpenCommand,
+ std::make_unique<ResultSetFactory>(m_xContext,
+ m_xProvider.get(),
+ aOpenCommand.Properties,
+ std::move(resvec)));
+ aRet <<= xSet;
+ }
+ else if(aOpenCommand.Mode ==
+ OpenMode::DOCUMENT_SHARE_DENY_NONE ||
+ aOpenCommand.Mode ==
+ OpenMode::DOCUMENT_SHARE_DENY_WRITE) {
+ // Unsupported OpenMode
+ aRet <<= UnsupportedOpenModeException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >(this),
+ static_cast< sal_Int16 >(aOpenCommand.Mode));
+ ucbhelper::cancelCommandExecution(aRet,Environment);
+ }
+ else {
+ aRet <<= IllegalArgumentException(
+ "Unexpected OpenMode!",
+ static_cast< cppu::OWeakObject * >(this),
+ -1);
+
+ ucbhelper::cancelCommandExecution(aRet,Environment);
+ }
+ } else if(aCommand.Name == "createNewContent") {
+ ContentInfo aArg;
+ if (!(aCommand.Argument >>= aArg)) {
+ ucbhelper::cancelCommandExecution(
+ Any(
+ IllegalArgumentException(
+ "Wrong argument type!",
+ static_cast< cppu::OWeakObject * >(this),
+ -1)),
+ Environment);
+ // Unreachable
+ }
+ aRet <<= createNewContent(aArg);
+ } else {
+ aRet <<= UnsupportedCommandException(
+ aCommand.Name,
+ static_cast< cppu::OWeakObject * >(this));
+ ucbhelper::cancelCommandExecution(aRet,Environment);
+ }
+
+ return aRet;
+ }
+ catch(const curl_exception& e)
+ {
+ if(e.code() == CURLE_COULDNT_CONNECT)
+ action = THROWINTERACTIVECONNECT;
+ else if (e.code() == CURLE_URL_MALFORMAT)
+ {
+ action = THROWMALFORMED;
+ }
+ else if(e.code() == CURLE_COULDNT_RESOLVE_HOST )
+ action = THROWRESOLVENAME;
+ else if(e.code() == CURLE_FTP_USER_PASSWORD_INCORRECT ||
+ e.code() == CURLE_LOGIN_DENIED ||
+ e.code() == CURLE_BAD_PASSWORD_ENTERED ||
+ e.code() == CURLE_FTP_WEIRD_PASS_REPLY)
+ action = THROWAUTHENTICATIONREQUEST;
+ else if(e.code() == CURLE_FTP_ACCESS_DENIED)
+ action = THROWACCESSDENIED;
+ else if(e.code() == CURLE_FTP_QUOTE_ERROR)
+ action = THROWQUOTE;
+ else if(e.code() == CURLE_FTP_COULDNT_RETR_FILE)
+ action = THROWNOFILE;
+ else
+ // nothing known about the cause of the error
+ action = THROWGENERAL;
+ }
+ }
+}
+
+constexpr OUStringLiteral FTP_FILE = u"application/vnd.sun.staroffice.ftp-file";
+
+constexpr OUStringLiteral FTP_FOLDER = u"application/vnd.sun.staroffice.ftp-folder";
+
+Sequence<ContentInfo > SAL_CALL
+FTPContent::queryCreatableContentsInfo( )
+{
+ return queryCreatableContentsInfo_Static();
+}
+
+// static
+Sequence<ContentInfo >
+FTPContent::queryCreatableContentsInfo_Static( )
+{
+ Sequence< Property > props{ Property(
+ "Title",
+ -1,
+ cppu::UnoType<OUString>::get(),
+ PropertyAttribute::MAYBEVOID
+ | PropertyAttribute::BOUND ) };
+ return
+ {
+ { FTP_FILE, ContentInfoAttribute::INSERT_WITH_INPUTSTREAM | ContentInfoAttribute::KIND_DOCUMENT, props },
+ { FTP_FOLDER, ContentInfoAttribute::KIND_FOLDER, props }
+ };
+}
+
+Reference<XContent > SAL_CALL
+FTPContent::createNewContent( const ContentInfo& Info )
+{
+ if( Info.Type =="application/vnd.sun.staroffice.ftp-file" || Info.Type == "application/vnd.sun.staroffice.ftp-folder" )
+ return new FTPContent(m_xContext,
+ m_pFCP,
+ m_xIdentifier,Info);
+ else
+ return Reference<XContent>(nullptr);
+}
+
+
+Reference<XInterface > SAL_CALL
+FTPContent::getParent( )
+{
+ Reference<XContentIdentifier>
+ xIdent(new FTPContentIdentifier(m_aFTPURL.parent()));
+ return Reference<XInterface>( m_xProvider->queryContent(xIdent), UNO_QUERY );
+}
+
+
+void SAL_CALL
+FTPContent::setParent(const Reference<XInterface >& /*Parent*/ )
+{
+ throw NoSupportException();
+}
+
+
+OUString FTPContent::getParentURL()
+{
+ return m_aFTPURL.parent();
+}
+
+namespace {
+
+class InsertData
+ : public CurlInput {
+
+public:
+
+ explicit InsertData(const Reference<XInputStream>& xInputStream)
+ : m_xInputStream(xInputStream) { }
+ virtual ~InsertData() {}
+
+ // returns the number of bytes actually read
+ virtual sal_Int32 read(sal_Int8 *dest,sal_Int32 nBytesRequested) override;
+
+private:
+
+ Reference<XInputStream> m_xInputStream;
+};
+
+}
+
+sal_Int32 InsertData::read(sal_Int8 *dest,sal_Int32 nBytesRequested)
+{
+ sal_Int32 m = 0;
+
+ if(m_xInputStream.is()) {
+ Sequence<sal_Int8> seq(nBytesRequested);
+ m = m_xInputStream->readBytes(seq,nBytesRequested);
+ memcpy(dest,seq.getConstArray(),m);
+ }
+ return m;
+}
+
+
+void FTPContent::insert(const InsertCommandArgument& aInsertCommand,
+ const Reference<XCommandEnvironment>& Env)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ if(m_bInserted && !m_bTitleSet) {
+ MissingPropertiesException excep;
+ excep.Properties = { "Title" };
+ ucbhelper::cancelCommandExecution(Any(excep), Env);
+ }
+
+ if(m_bInserted &&
+ m_aInfo.Type == FTP_FILE &&
+ !aInsertCommand.Data.is())
+ {
+ MissingInputStreamException excep;
+ ucbhelper::cancelCommandExecution(Any(excep), Env);
+ }
+
+ bool bReplace(aInsertCommand.ReplaceExisting);
+
+ retry:
+ try {
+ if(m_aInfo.Type == FTP_FILE) {
+ InsertData data(aInsertCommand.Data);
+ m_aFTPURL.insert(bReplace,&data);
+ } else if(m_aInfo.Type == FTP_FOLDER)
+ m_aFTPURL.mkdir(bReplace);
+ } catch(const curl_exception& e) {
+ if(e.code() == FOLDER_MIGHT_EXIST_DURING_INSERT ||
+ e.code() == FILE_MIGHT_EXIST_DURING_INSERT) {
+ // Interact
+ Reference<XInteractionHandler> xInt;
+ if(Env.is())
+ xInt = Env->getInteractionHandler();
+
+ UnsupportedNameClashException excep;
+ excep.NameClash = 0; //NameClash::ERROR;
+
+ if(!xInt.is()) {
+ ucbhelper::cancelCommandExecution(Any(excep), Env);
+ }
+
+ XInteractionRequestImpl request;
+ const Reference<XInteractionRequest>& xReq(request.getRequest());
+ xInt->handle(xReq);
+ if (request.approved()) {
+ bReplace = true;
+ goto retry;
+ }
+ else
+ throw excep;
+ }
+ else
+ throw;
+ }
+
+ // May not be reached, because both mkdir and insert can throw curl-
+ // exceptions
+ m_bInserted = false;
+ inserted();
+}
+
+
+Reference< XRow > FTPContent::getPropertyValues(
+ const Sequence< Property >& seqProp
+)
+{
+ rtl::Reference<ucbhelper::PropertyValueSet> xRow =
+ new ucbhelper::PropertyValueSet(m_xContext);
+
+ FTPDirentry aDirEntry = m_aFTPURL.direntry();
+
+ for(const auto& rProp : seqProp) {
+ const OUString& Name = rProp.Name;
+ if(Name == "Title")
+ xRow->appendString(rProp,aDirEntry.m_aName);
+ else if(Name == "CreatableContentsInfo")
+ xRow->appendObject(rProp,
+ Any(queryCreatableContentsInfo()));
+ else if(aDirEntry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN) {
+ if(Name == "ContentType")
+ xRow->appendString(rProp,
+ (aDirEntry.m_nMode & INETCOREFTP_FILEMODE_ISDIR)
+ ? OUString(FTP_FOLDER)
+ : OUString(FTP_FILE) );
+ else if(Name == "IsReadOnly")
+ xRow->appendBoolean(rProp,
+ (aDirEntry.m_nMode
+ & INETCOREFTP_FILEMODE_WRITE) == 0 );
+ else if(Name == "IsDocument")
+ xRow->appendBoolean(rProp,
+ (aDirEntry.m_nMode &
+ INETCOREFTP_FILEMODE_ISDIR) != INETCOREFTP_FILEMODE_ISDIR);
+ else if(Name == "IsFolder")
+ xRow->appendBoolean(rProp,
+ (aDirEntry.m_nMode &
+ INETCOREFTP_FILEMODE_ISDIR) == INETCOREFTP_FILEMODE_ISDIR);
+ else if(Name == "Size")
+ xRow->appendLong(rProp,
+ aDirEntry.m_nSize);
+ else if(Name == "DateCreated")
+ xRow->appendTimestamp(rProp,
+ aDirEntry.m_aDate);
+ else
+ xRow->appendVoid(rProp);
+ } else
+ xRow->appendVoid(rProp);
+ }
+
+ return xRow;
+}
+
+
+Sequence<Any> FTPContent::setPropertyValues(
+ const Sequence<PropertyValue>& seqPropVal)
+{
+ Sequence<Any> ret(seqPropVal.getLength());
+ auto retRange = asNonConstRange(ret);
+ Sequence<PropertyChangeEvent > evt;
+
+ osl::MutexGuard aGuard(m_aMutex);
+ for(sal_Int32 i = 0; i < ret.getLength(); ++i) {
+ if ( seqPropVal[i].Name == "Title" ) {
+ OUString Title;
+ if(!(seqPropVal[i].Value >>= Title)) {
+ retRange[i] <<= IllegalTypeException();
+ continue;
+ } else if(Title.isEmpty()) {
+ retRange[i] <<= IllegalArgumentException();
+ continue;
+ }
+
+ if(m_bInserted) {
+ m_aFTPURL.child(Title);
+ m_xIdentifier =
+ new FTPContentIdentifier(m_aFTPURL.ident(false,false));
+ m_bTitleSet = true;
+ } else
+ try {
+ OUString OldTitle = m_aFTPURL.ren(Title);
+ evt = { { /* Source */ {},
+ /* PropertyName */ "Title",
+ /* Further */ false,
+ /* PropertyHandle */ -1,
+ /* OldValue */ Any(OldTitle),
+ /* NewValue */ Any(Title) } };
+ } catch(const curl_exception&) {
+ InteractiveIOException excep;
+ // any better possibility here?
+ // ( the error code is always CURLE_FTP_QUOTE_ERROR )
+ excep.Code = IOErrorCode_ACCESS_DENIED;
+ retRange[i] <<= excep;
+ }
+ } else {
+ const Sequence<Property> props =
+ getProperties(Reference<XCommandEnvironment>(nullptr));
+
+ // either unknown or read-only
+ retRange[i] <<= UnknownPropertyException();
+ const auto& rName = seqPropVal[i].Name;
+ auto pProp = std::find_if(props.begin(), props.end(),
+ [&rName](const Property& rProp) { return rProp.Name == rName; });
+ if (pProp != props.end()) {
+ retRange[i] <<= IllegalAccessException(
+ "Property is read-only!",
+ //props[j].Attributes & PropertyAttribute::READONLY
+ // ? "Property is read-only!"
+ // : "Access denied!"),
+ static_cast< cppu::OWeakObject * >( this ));
+ }
+ }
+ }
+
+ if(evt.hasElements()) {
+ // title has changed
+ notifyPropertiesChange(evt);
+ (void)exchange(new FTPContentIdentifier(m_aFTPURL.ident(false,false)));
+ }
+
+ return ret;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */