diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /ucb/source/ucp/ftp | |
parent | Initial commit. (diff) | |
download | libreoffice-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 '')
27 files changed, 5751 insertions, 0 deletions
diff --git a/ucb/source/ucp/ftp/curl.hxx b/ucb/source/ucp/ftp/curl.hxx new file mode 100644 index 000000000..3dac8a057 --- /dev/null +++ b/ucb/source/ucp/ftp/curl.hxx @@ -0,0 +1,24 @@ +/* -*- 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 . + */ + +#pragma once + +#include <curl/curl.h> + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpcfunc.cxx b/ucb/source/ucp/ftp/ftpcfunc.cxx new file mode 100644 index 000000000..a39043aa7 --- /dev/null +++ b/ucb/source/ucp/ftp/ftpcfunc.cxx @@ -0,0 +1,50 @@ +/* -*- 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 <osl/file.h> +#include "ftpcontentidentifier.hxx" +#include "ftpcfunc.hxx" + +using namespace ftp; +using namespace com::sun::star::uno; + +extern "C" { + + int file_write(void *buffer,size_t size,size_t nmemb,void *stream) + { + oslFileHandle aFile = reinterpret_cast< oslFileHandle >( stream ); + if( !aFile ) + return 0; + + sal_uInt64 nWritten = 0; + sal_uInt64 nToWrite( size * nmemb ); + osl_writeFile( aFile, buffer, nToWrite, &nWritten ); + + return nWritten != nToWrite ? 0 : nmemb; + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpcfunc.hxx b/ucb/source/ucp/ftp/ftpcfunc.hxx new file mode 100644 index 000000000..f5a29a3fb --- /dev/null +++ b/ucb/source/ucp/ftp/ftpcfunc.hxx @@ -0,0 +1,39 @@ +/* -*- 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 + ************************************************************************** + + *************************************************************************/ +#pragma once + +#include <stddef.h> + +extern "C" { + +/** callback for curl_easy_perform(), + * forwarding the written content to the stream. + * stream has to be of type oslFileHandle. + */ + +int file_write(void* buffer, size_t size, size_t nmemb, void* stream); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpcontainer.hxx b/ucb/source/ucp/ftp/ftpcontainer.hxx new file mode 100644 index 000000000..e555111a2 --- /dev/null +++ b/ucb/source/ucp/ftp/ftpcontainer.hxx @@ -0,0 +1,56 @@ +/* -*- 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 + ************************************************************************** + + *************************************************************************/ + +#pragma once + +#include <sal/types.h> + +namespace ftp { + +class MemoryContainer { + +public: + + MemoryContainer(); + + ~MemoryContainer(); + + int append( + const void* pBuffer, + size_t size, + size_t nmemb + ) noexcept; + + + sal_uInt32 m_nLen,m_nWritePos; + void *m_pBuffer; +}; + +} + + +extern "C" int memory_write( + void *buffer,size_t size,size_t nmemb,void *stream); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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: */ diff --git a/ucb/source/ucp/ftp/ftpcontent.hxx b/ucb/source/ucp/ftp/ftpcontent.hxx new file mode 100644 index 000000000..ab0bda66a --- /dev/null +++ b/ucb/source/ucp/ftp/ftpcontent.hxx @@ -0,0 +1,146 @@ +/* -*- 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 . + */ + +#pragma once + +#include <ucbhelper/contenthelper.hxx> +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/ucb/XContentCreator.hpp> +#include "ftpurl.hxx" + +namespace com::sun::star::beans { + struct Property; + struct PropertyValue; +} + +namespace com::sun::star::sdbc { + class XRow; +} + + +namespace ftp +{ + +class FTPContentProvider; + +class FTPContent : public ::ucbhelper::ContentImplHelper, + public css::ucb::XContentCreator +{ +public: + + FTPContent( const css::uno::Reference< + css::uno::XComponentContext >& rxContext, + FTPContentProvider* pProvider, + const css::uno::Reference< + css::ucb::XContentIdentifier >& Identifier, + const FTPURL& FtpUrl); + + FTPContent( const css::uno::Reference< + css::uno::XComponentContext >& rxContext, + FTPContentProvider* pProvider, + const css::uno::Reference< + css::ucb::XContentIdentifier >& Identifier, + const css::ucb::ContentInfo& aInfo); + + + virtual ~FTPContent() override; + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + // XTypeProvider + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XContent + virtual OUString SAL_CALL getContentType() override; + + // XCommandProcessor + virtual css::uno::Any SAL_CALL execute( const css::ucb::Command& aCommand, + sal_Int32 CommandId, + const css::uno::Reference< + css::ucb::XCommandEnvironment >& Environment ) override; + + virtual void SAL_CALL abort(sal_Int32 CommandId) override; + + // XContentCreator + virtual css::uno::Sequence< + css::ucb::ContentInfo > SAL_CALL + queryCreatableContentsInfo( ) override; + + virtual css::uno::Reference< + css::ucb::XContent > SAL_CALL + createNewContent( const css::ucb::ContentInfo& Info ) override; + + // XChild + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override; + + virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override; + + /// @throws css::uno::RuntimeException + static css::uno::Sequence< css::ucb::ContentInfo > queryCreatableContentsInfo_Static(); + +private: + + FTPContentProvider *m_pFCP; + FTPURL m_aFTPURL; + bool m_bInserted; + bool m_bTitleSet; + css::ucb::ContentInfo m_aInfo; + + virtual css::uno::Sequence< css::beans::Property > + getProperties( const css::uno::Reference< + css::ucb::XCommandEnvironment > & xEnv ) override; + + + virtual css::uno::Sequence< css::ucb::CommandInfo> + getCommands(const css::uno::Reference< + css::ucb::XCommandEnvironment > & xEnv) override; + + + virtual OUString getParentURL() override; + + css::uno::Reference<css::sdbc::XRow> + getPropertyValues( + const css::uno::Sequence< + css::beans::Property>& seqProp + ); + + css::uno::Sequence<css::uno::Any> + setPropertyValues( const css::uno::Sequence< + css::beans::PropertyValue>& seqPropVal); + + void insert(const css::ucb::InsertCommandArgument&, + const css::uno::Reference< + css::ucb::XCommandEnvironment>&); + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpcontentcaps.cxx b/ucb/source/ucp/ftp/ftpcontentcaps.cxx new file mode 100644 index 000000000..64dd0e92d --- /dev/null +++ b/ucb/source/ucp/ftp/ftpcontentcaps.cxx @@ -0,0 +1,167 @@ +/* -*- 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 . + */ + + +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/ucb/CommandInfo.hpp> +#include <com/sun/star/ucb/OpenCommandArgument2.hpp> +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/uno/Sequence.hxx> + +#include "ftpcontent.hxx" + +using namespace com::sun::star; +using namespace ftp; + +// virtual +uno::Sequence< beans::Property > FTPContent::getProperties( + const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/) +{ + #define PROPS_COUNT 8 + + static const beans::Property aPropsInfoTable[] = + { + beans::Property( + "ContentType", + -1, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + ), + beans::Property( + "IsDocument", + -1, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + ), + beans::Property( + "IsFolder", + -1, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + ), + beans::Property( + "Title", + -1, + cppu::UnoType<OUString>::get(), + beans::PropertyAttribute::BOUND + // | beans::PropertyAttribute::READONLY + ), + beans::Property( + "Size", + -1, + cppu::UnoType<sal_Int64>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + ), + beans::Property( + "DateCreated", + -1, + cppu::UnoType<util::DateTime>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + ), + beans::Property( + "IsReadOnly", + -1, + cppu::UnoType<bool>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + ), + beans::Property( + "CreatableContentsInfo", + -1, + cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + ) + }; + + return uno::Sequence< beans::Property >( aPropsInfoTable, PROPS_COUNT ); +} + + +// virtual +uno::Sequence< ucb::CommandInfo > FTPContent::getCommands( + const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/ ) +{ +// osl::MutexGuard aGuard( m_aMutex ); + + + // Supported commands + + + #define COMMAND_COUNT 8 + + static const ucb::CommandInfo aCommandInfoTable[] = + { + + // Required commands + + ucb::CommandInfo( + "getCommandInfo", + -1, + cppu::UnoType<void>::get() + ), + ucb::CommandInfo( + "getPropertySetInfo", + -1, + cppu::UnoType<void>::get() + ), + ucb::CommandInfo( + "getPropertyValues", + -1, + cppu::UnoType<uno::Sequence< beans::Property >>::get() + ), + ucb::CommandInfo( + "setPropertyValues", + -1, + cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get() + ), + ucb::CommandInfo( + "open", + -1, + cppu::UnoType<ucb::OpenCommandArgument2>::get() + ), + ucb::CommandInfo( + "insert", + -1, + cppu::UnoType<ucb::InsertCommandArgument>::get() + ), + ucb::CommandInfo( + "delete", + -1, + cppu::UnoType<bool>::get() + ), + ucb::CommandInfo( + "createNewContent", + -1, + cppu::UnoType<ucb::ContentInfo>::get() + ) + }; + + return uno::Sequence< ucb::CommandInfo >( aCommandInfoTable, COMMAND_COUNT ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpcontentidentifier.cxx b/ucb/source/ucp/ftp/ftpcontentidentifier.cxx new file mode 100644 index 000000000..8bdc1b935 --- /dev/null +++ b/ucb/source/ucp/ftp/ftpcontentidentifier.cxx @@ -0,0 +1,63 @@ +/* -*- 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 "ftpcontentidentifier.hxx" + +using namespace ftp; +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; +using namespace com::sun::star::lang; + + +FTPContentIdentifier::FTPContentIdentifier( + const OUString& ident +) + : m_ident(ident) +{ +} + + +FTPContentIdentifier::~FTPContentIdentifier() +{ +} + + +OUString SAL_CALL +FTPContentIdentifier::getContentIdentifier( +) +{ + return m_ident; +} + + +OUString SAL_CALL +FTPContentIdentifier::getContentProviderScheme( +) +{ + return "ftp"; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpcontentidentifier.hxx b/ucb/source/ucp/ftp/ftpcontentidentifier.hxx new file mode 100644 index 000000000..c91ad704f --- /dev/null +++ b/ucb/source/ucp/ftp/ftpcontentidentifier.hxx @@ -0,0 +1,59 @@ +/* -*- 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 + ************************************************************************** + + *************************************************************************/ +#pragma once + +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/ucb/XContentIdentifier.hpp> + + +namespace ftp { + + class FTPContentIdentifier : + public cppu::WeakImplHelper<css::ucb::XContentIdentifier> + { + public: + + explicit FTPContentIdentifier(const OUString& ident); + + virtual ~FTPContentIdentifier() override; + + // XContentIdentifier + + virtual OUString SAL_CALL + getContentIdentifier() override; + + virtual OUString SAL_CALL + getContentProviderScheme() override; + + + private: + + OUString m_ident; + }; + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpcontentprovider.cxx b/ucb/source/ucp/ftp/ftpcontentprovider.cxx new file mode 100644 index 000000000..5200fcfd1 --- /dev/null +++ b/ucb/source/ucp/ftp/ftpcontentprovider.cxx @@ -0,0 +1,244 @@ +/* -*- 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 . + */ + +#include <sal/config.h> + +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/ucb/IllegalIdentifierException.hpp> +#include <com/sun/star/ucb/UniversalContentBroker.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/weak.hxx> +#include "ftpcontentprovider.hxx" +#include "ftpcontent.hxx" +#include "ftploaderthread.hxx" + +using namespace ftp; +using namespace com::sun::star::lang; +using namespace com::sun::star::container; +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; +using namespace com::sun::star::beans; + +// ContentProvider Implementation. + +FTPContentProvider::FTPContentProvider( const Reference< XComponentContext >& rxContext) + : ::ucbhelper::ContentProviderImplHelper(rxContext) +{ +} + + +// virtual +FTPContentProvider::~FTPContentProvider() +{ + m_ftpLoaderThread.reset(); + m_pProxyDecider.reset(); +} + +// XInterface methods. +void SAL_CALL FTPContentProvider::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL FTPContentProvider::release() + noexcept +{ + OWeakObject::release(); +} + +css::uno::Any SAL_CALL FTPContentProvider::queryInterface( const css::uno::Type & rType ) +{ + css::uno::Any aRet = cppu::queryInterface( rType, + static_cast< XTypeProvider* >(this), + static_cast< XServiceInfo* >(this), + static_cast< XContentProvider* >(this) + ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + +// XTypeProvider methods. +css::uno::Sequence< sal_Int8 > SAL_CALL FTPContentProvider::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +css::uno::Sequence< css::uno::Type > SAL_CALL FTPContentProvider::getTypes() +{ + static cppu::OTypeCollection s_aCollection( + cppu::UnoType<XTypeProvider>::get(), + cppu::UnoType<XServiceInfo>::get(), + cppu::UnoType<XContentProvider>::get() + ); + + return s_aCollection.getTypes(); +} + + +// XServiceInfo methods. + +OUString SAL_CALL FTPContentProvider::getImplementationName() +{ + return "com.sun.star.comp.FTPContentProvider"; +} + +sal_Bool SAL_CALL FTPContentProvider::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +css::uno::Sequence< OUString > SAL_CALL FTPContentProvider::getSupportedServiceNames() +{ + return { FTP_CONTENT_PROVIDER_SERVICE_NAME }; +} + + + +// XContentProvider methods. + +// virtual +Reference<XContent> SAL_CALL FTPContentProvider::queryContent( + const Reference< XContentIdentifier >& xCanonicId) +{ + // Check, if a content with given id already exists... + Reference<XContent> xContent = queryExistingContent(xCanonicId); + if(xContent.is()) + return xContent; + + // A new content has to be returned: + { + // Initialize + osl::MutexGuard aGuard( m_aMutex ); + if(!m_ftpLoaderThread || !m_pProxyDecider) + { + try { + init(); + } catch (css::uno::Exception const & ex) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( ex.Message, + css::uno::Reference< css::uno::XInterface >(), + anyEx ); + } catch( ... ) { + throw RuntimeException(); + } + + if(!m_ftpLoaderThread || !m_pProxyDecider) + throw RuntimeException(); + } + } + + try { + FTPURL aURL(xCanonicId->getContentIdentifier(), + this); + + if(!m_pProxyDecider->shouldUseProxy( + "ftp", + aURL.host(), + aURL.port().toInt32())) + { + xContent = new FTPContent( m_xContext, this,xCanonicId,aURL); + registerNewContent(xContent); + } + else { + Reference<XContentProvider> xProvider(UniversalContentBroker::create( m_xContext )->queryContentProvider("http:")); + if(!xProvider.is()) + throw RuntimeException(); + return xProvider->queryContent(xCanonicId); + } + } catch(const malformed_exception&) { + throw IllegalIdentifierException(); + } + + // may throw IllegalIdentifierException + return xContent; +} + +void FTPContentProvider::init() +{ + m_ftpLoaderThread.reset( new FTPLoaderThread() ); + m_pProxyDecider.reset( new ucbhelper::InternetProxyDecider( m_xContext ) ); +} + +CURL* FTPContentProvider::handle() +{ + // Cannot be zero if called from here; + return m_ftpLoaderThread->handle(); +} + + +void FTPContentProvider::forHost( std::u16string_view host, + std::u16string_view port, + std::u16string_view username, + OUString& password, + OUString& account) +{ + osl::MutexGuard aGuard(m_aMutex); + for(const ServerInfo & i : m_ServerInfo) + if(host == i.host && + port == i.port && + username == i.username ) + { + password = i.password; + account = i.account; + return; + } +} + +bool FTPContentProvider::setHost( const OUString& host, + const OUString& port, + const OUString& username, + const OUString& password, + const OUString& account) +{ + ServerInfo inf; + inf.host = host; + inf.port = port; + inf.username = username; + inf.password = password; + inf.account = account; + + bool present(false); + osl::MutexGuard aGuard(m_aMutex); + for(ServerInfo & i : m_ServerInfo) + if(host == i.host && + port == i.port && + username == i.username) + { + present = true; + i.password = password; + i.account = account; + } + + if(!present) + m_ServerInfo.push_back(inf); + + return !present; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +ucb_ftp_FTPContentProvider_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new FTPContentProvider(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpcontentprovider.hxx b/ucb/source/ucp/ftp/ftpcontentprovider.hxx new file mode 100644 index 000000000..fe1247b9e --- /dev/null +++ b/ucb/source/ucp/ftp/ftpcontentprovider.hxx @@ -0,0 +1,107 @@ +/* -*- 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 . + */ + +#pragma once + +#include <vector> +#include <ucbhelper/proxydecider.hxx> +#include <ucbhelper/providerhelper.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include "curl.hxx" + +// UNO service name for the provider. This name will be used by the UCB to +// create instances of the provider. + +inline constexpr OUStringLiteral FTP_CONTENT_PROVIDER_SERVICE_NAME = u"com.sun.star.ucb.FTPContentProvider"; +inline constexpr OUStringLiteral FTP_CONTENT_TYPE = u"application/ftp-content"; + +/** + * Definition of ftpcontentprovider + */ +namespace ftp +{ + class FTPLoaderThread; + + class FTPContentProvider: + public ::ucbhelper::ContentProviderImplHelper + { + public: + + explicit FTPContentProvider( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + + virtual ~FTPContentProvider() override; + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() + noexcept override; + virtual void SAL_CALL release() + noexcept override; + + // XTypeProvider + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XContentProvider + virtual css::uno::Reference< css::ucb::XContent > SAL_CALL + queryContent( const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier ) override; + + CURL* handle(); + + /** host is in the form host:port. + */ + + void forHost(std::u16string_view host, + std::u16string_view port, + std::u16string_view username, + OUString& password, + OUString& account); + + bool setHost(const OUString& host, + const OUString& port, + const OUString& username, + const OUString& password, + const OUString& account); + + struct ServerInfo + { + OUString host; + OUString port; + OUString username; + OUString password; + OUString account; + }; + + private: + std::unique_ptr<FTPLoaderThread> m_ftpLoaderThread; + std::unique_ptr<ucbhelper::InternetProxyDecider> m_pProxyDecider; + std::vector<ServerInfo> m_ServerInfo; + + void init(); + }; // end class FTPContentProvider + +} // end namespace ftp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpdirp.cxx b/ucb/source/ucp/ftp/ftpdirp.cxx new file mode 100644 index 000000000..69bea64ab --- /dev/null +++ b/ucb/source/ucp/ftp/ftpdirp.cxx @@ -0,0 +1,1269 @@ +/* -*- 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 "ftpdirp.hxx" +#include <osl/time.h> + + +using namespace ftp; + +static bool ascii_isWhitespace( sal_Unicode ch ) +{ + return ((ch <= 0x20) && ch); +} + + +/*======================================================================== + * + * FTPDirectoryParser implementation. + * + *======================================================================*/ +/* + * parseDOS. + * Accepts one of two styles: + * + * 1 *WSP 1*2DIGIT ("." / "-") 1*2DIGIT ("." / "-") 1*4DIGIT 1*WSP + * 1*2DIGIT ":" 1*2DIGIT [*WSP ("A" / "P") "M"] 1*WSP + * ((DIGIT *(DIGIT / "." / ",")) / "<DIR>") 1*WSP 1*OCTET + * + * interpreted as: mm.dd.yy hh:mm (size / <DIR>) name + * + * 2 *WSP 1*DIGIT 1*WSP *(1*CHAR *WSP) *1("DIR" 1*WSP) 1*2DIGIT "-" 1*2DIGIT + * "-" 1*4DIGIT 1*WSP 1*2DIGIT ":" 1*2DIGIT 1*WSP 1*OCTET + * + * interpreted as: size attribs DIR mm-dd-yy hh:mm name + */ + +bool FTPDirectoryParser::parseDOS ( + FTPDirentry &rEntry, + const char *pBuffer) +{ + bool bDirectory = false; + sal_uInt32 nSize = 0; + sal_uInt16 nYear = 0; + sal_uInt16 nMonth = 0; + sal_uInt16 nDay = 0; + sal_uInt16 nHour = 0; + sal_uInt16 nMinute = 0; + + enum StateType + { + STATE_INIT_LWS, + STATE_MONTH_OR_SIZE, + STATE_1_DAY, STATE_1_YEAR, STATE_1_YEAR_LWS, STATE_1_HOUR, + STATE_1_MINUTE, STATE_1_MINUTE_LWS, STATE_1_AP, + STATE_1_APM, STATE_1_LESS, STATE_1_D, STATE_1_DI, + STATE_1_DIR, STATE_1_SIZE, + STATE_2_SIZE, STATE_2_SIZE_LWS, STATE_2_ATTRIB, + STATE_2_D, STATE_2_DI, STATE_2_DIR_LWS, + STATE_2_MONTH, STATE_2_DAY, STATE_2_YEAR, STATE_2_YEAR_LWS, + STATE_2_HOUR, STATE_2_MINUTE, + STATE_LWS_NAME, + STATE_ERROR + }; + + int nDigits = 0; + enum StateType eState = STATE_INIT_LWS; + for (const char *p = pBuffer; + eState != STATE_ERROR && *p; + ++p) + { + switch (eState) + { + case STATE_INIT_LWS: + if (*p >= '0' && *p <= '9') + { + nMonth = *p - '0'; + nDigits = 1; + eState = STATE_MONTH_OR_SIZE; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_MONTH_OR_SIZE: + if (*p >= '0' && *p <= '9') + { + nMonth = 10 * nMonth + (*p - '0'); + if (nDigits < 2) + ++nDigits; + else + { + nSize = nMonth; + nMonth = 0; + eState = STATE_2_SIZE; + } + } + else if (ascii_isWhitespace(*p)) + { + nSize = nMonth; + nMonth = 0; + eState = STATE_2_SIZE_LWS; + } + else if ((*p == '.' || *p == '-') && nMonth && nMonth <= 12) + { + nDigits = 0; + eState = STATE_1_DAY; + } + else + eState = STATE_ERROR; + break; + + case STATE_1_DAY: + if (*p >= '0' && *p <= '9') + if (nDigits < 2) + { + nDay = 10 * nDay + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + else if ((*p == '.' || *p == '-') && nDay && nDay <= 31) + { + nDigits = 0; + eState = STATE_1_YEAR; + } + else + eState = STATE_ERROR; + break; + + case STATE_1_YEAR: + if (*p >= '0' && *p <= '9') + { + if (nDigits < 4) + { + nYear = 10 * nYear + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + } + else + { + if (ascii_isWhitespace(*p)) + eState = STATE_1_YEAR_LWS; + else + eState = STATE_ERROR; + } + break; + + case STATE_1_YEAR_LWS: + if (*p >= '0' && *p <= '9') + { + nHour = *p - '0'; + nDigits = 1; + eState = STATE_1_HOUR; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_1_HOUR: + if (*p >= '0' && *p <= '9') + if (nDigits < 2) + { + nHour = 10 * nHour + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + else if (*p == ':' && nHour < 24) + { + nDigits = 0; + eState = STATE_1_MINUTE; + } + else + eState = STATE_ERROR; + break; + + case STATE_1_MINUTE: + if (*p >= '0' && *p <= '9') + if (nDigits < 2) + { + nMinute = 10 * nMinute + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + else if ((*p == 'a' || *p == 'A') && nMinute < 60) + if (nHour >= 1 && nHour <= 11) + eState = STATE_1_AP; + else if (nHour == 12) + { + nHour = 0; + eState = STATE_1_AP; + } + else + eState = STATE_ERROR; + else if ((*p == 'p' || *p == 'P') && nMinute < 60) + if (nHour >= 1 && nHour <= 11) + { + nHour += 12; + eState = STATE_1_AP; + } + else if (nHour == 12) + eState = STATE_1_AP; + else + eState = STATE_ERROR; + else if (ascii_isWhitespace(*p) && (nMinute < 60)) + eState = STATE_1_MINUTE_LWS; + else + eState = STATE_ERROR; + break; + + case STATE_1_MINUTE_LWS: + if (*p == 'a' || *p == 'A') + if (nHour >= 1 && nHour <= 11) + eState = STATE_1_AP; + else if (nHour == 12) + { + nHour = 0; + eState = STATE_1_AP; + } + else + eState = STATE_ERROR; + else if (*p == 'p' || *p == 'P') + if (nHour >= 1 && nHour <= 11) + { + nHour += 12; + eState = STATE_1_AP; + } + else if (nHour == 12) + eState = STATE_1_AP; + else + eState = STATE_ERROR; + else if (*p == '<') + eState = STATE_1_LESS; + else if (*p >= '0' && *p <= '9') + { + nSize = *p - '0'; + eState = STATE_1_SIZE; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_1_AP: + eState = *p == 'm' || *p == 'M' ? STATE_1_APM : STATE_ERROR; + break; + + case STATE_1_APM: + if (*p == '<') + eState = STATE_1_LESS; + else if (*p >= '0' && *p <= '9') + { + nSize = *p - '0'; + eState = STATE_1_SIZE; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_1_LESS: + eState = *p == 'd' || *p == 'D' ? STATE_1_D : STATE_ERROR; + break; + + case STATE_1_D: + eState = *p == 'i' || *p == 'I' ? STATE_1_DI : STATE_ERROR; + break; + + case STATE_1_DI: + eState = *p == 'r' || *p == 'R' ? STATE_1_DIR : STATE_ERROR; + break; + + case STATE_1_DIR: + if (*p == '>') + { + bDirectory = true; + eState = STATE_LWS_NAME; + } + else + eState = STATE_ERROR; + break; + + case STATE_1_SIZE: + if (*p >= '0' && *p <= '9') + nSize = 10 * nSize + (*p - '0'); + else if (ascii_isWhitespace(*p)) + eState = STATE_LWS_NAME; + else + eState = STATE_ERROR; + break; + + case STATE_2_SIZE: + if (*p >= '0' && *p <= '9') + nSize = 10 * nSize + (*p - '0'); + else if (ascii_isWhitespace(*p)) + eState = STATE_2_SIZE_LWS; + else + eState = STATE_ERROR; + break; + + case STATE_2_SIZE_LWS: + if (*p == 'd' || *p == 'D') + eState = STATE_2_D; + else if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')) + eState = STATE_2_ATTRIB; + else if (*p >= '0' && *p <= '9') + { + nMonth = *p - '0'; + nDigits = 1; + eState = STATE_2_MONTH; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_2_ATTRIB: + if (ascii_isWhitespace(*p)) + eState = STATE_2_SIZE_LWS; + else if ((*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z')) + eState = STATE_ERROR; + break; + + case STATE_2_D: + if (*p == 'i' || *p == 'I') + eState = STATE_2_DI; + else if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')) + eState = STATE_2_ATTRIB; + else if (ascii_isWhitespace(*p)) + eState = STATE_2_SIZE_LWS; + else + eState = STATE_ERROR; + break; + + case STATE_2_DI: + if (*p == 'r' || *p == 'R') + { + bDirectory = true; + eState = STATE_2_DIR_LWS; + } + else + { + if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z')) + eState = STATE_2_ATTRIB; + else if (ascii_isWhitespace(*p)) + eState = STATE_2_SIZE_LWS; + else + eState = STATE_ERROR; + } + break; + + case STATE_2_DIR_LWS: + if (*p >= '0' && *p <= '9') + { + nMonth = *p - '0'; + nDigits = 1; + eState = STATE_2_MONTH; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_2_MONTH: + if (*p >= '0' && *p <= '9') + if (nDigits < 2) + { + nMonth = 10 * nMonth + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + else if (*p == '-' && nMonth && nMonth <= 12) + { + nDigits = 0; + eState = STATE_2_DAY; + } + else + eState = STATE_ERROR; + break; + + case STATE_2_DAY: + if (*p >= '0' && *p <= '9') + if (nDigits < 2) + { + nDay = 10 * nDay + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + else if (*p == '-' && nDay && nDay <= 31) + { + nDigits = 0; + eState = STATE_2_YEAR; + } + else + eState = STATE_ERROR; + break; + + case STATE_2_YEAR: + if (*p >= '0' && *p <= '9') + { + if (nDigits < 4) + { + nYear = 10 * nYear + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + } + else + { + if (ascii_isWhitespace(*p)) + eState = STATE_2_YEAR_LWS; + else + eState = STATE_ERROR; + } + break; + + case STATE_2_YEAR_LWS: + if (*p >= '0' && *p <= '9') + { + nHour = *p - '0'; + nDigits = 1; + eState = STATE_2_HOUR; + } + else if (!ascii_isWhitespace(*p)) + eState = STATE_ERROR; + break; + + case STATE_2_HOUR: + if (*p >= '0' && *p <= '9') + if (nDigits < 2) + { + nHour = 10 * nHour + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + else if (*p == ':' && nHour < 24) + { + nDigits = 0; + eState = STATE_2_MINUTE; + } + else + eState = STATE_ERROR; + break; + + case STATE_2_MINUTE: + if (*p >= '0' && *p <= '9') + { + if (nDigits < 2) + { + nMinute = 10 * nMinute + (*p - '0'); + ++nDigits; + } + else + eState = STATE_ERROR; + } + else + { + if (ascii_isWhitespace(*p) && (nMinute < 60)) + eState = STATE_LWS_NAME; + else + eState = STATE_ERROR; + } + break; + + case STATE_LWS_NAME: + if (!ascii_isWhitespace(*p)) + { + setPath (rEntry.m_aName, p); + if (bDirectory) + rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISDIR; + rEntry.m_nSize = nSize; + + setYear (rEntry.m_aDate, nYear); + + rEntry.m_aDate.SetMonth(nMonth); + rEntry.m_aDate.SetDay(nDay); + rEntry.m_aDate.SetHour(nHour); + rEntry.m_aDate.SetMin(nMinute); + + return true; + } + break; + case STATE_ERROR: + break; + } + } + + return false; +} + +/* + * parseVMS. + * Directory entries may span one or two lines: + * + * entry: *lws name *1(*lws <NEWLINE>) 1*lws size 1*lws datetime rest + * + * name: filename "." filetype ";" version + * filename: 1*39fchar + * filetype: 1*39fchar + * version: non0digit *digit + * + * size: "0" / non0digit *digit + * + * datetime: date 1*lwsp time + * date: day "-" month "-" year + * day: (*1"0" non0digit) / ("1"-"2" digit) / ("3" "0"-"1") + * month: "JAN" / "FEB" / "MAR" / "APR" / "MAY" / "JUN" / "JUL" / "AUG" + * / "SEP" / "OCT" / "NOV" / "DEC" ; all case insensitive + * year: 2digit / 4digit + * time: hour ":" minute + * hour: ((*1"0" / "1") digit) / ("2" "0"-"3") + * minute: "0"-"5" digit + * + * rest: *1(lws *<ANY>) + * + * lws: <TAB> / <SPACE> + * non0digit: "1"-"9" + * digit: "0" / non0digit + * fchar: "A"-"Z" / "a"-"z" / digit / "-" / "_" / "$" + * + * For directories, the returned name is the <filename> part; for non- + * directory files, the returned name is the <filename "." filetype> part. + * An entry is a directory iff its filetype is "DIR" (ignoring case). + * + * The READ, WRITE, and ISLINK mode bits are not supported. + * + * The returned size is the <size> part, multiplied by 512, and with the high + * order bits truncated to fit into a sal_uInt32. + * + */ +bool FTPDirectoryParser::parseVMS ( + FTPDirentry &rEntry, + const char *pBuffer) +{ + static OUString aFirstLineName; + static bool bFirstLineDir = false; + + for (bool bFirstLine = true;; bFirstLine = false) + { + const char *p = pBuffer; + if (bFirstLine) + { + // Skip <*lws> part: + while (*p == '\t' || *p == ' ') + ++p; + + // Parse <filename "."> part: + const char *pFileName = p; + while ((*p >= 'A' && *p <= 'Z') || + (*p >= 'a' && *p <= 'z') || + (*p >= '0' && *p <= '9') || + *p == '-' || *p == '_' || *p == '$') + ++p; + + if (*p != '.' || p == pFileName || p - pFileName > 39) + { + if (!aFirstLineName.isEmpty()) + continue; + else + return false; + } + + // Parse <filetype ";"> part: + const char *pFileType = ++p; + while ((*p >= 'A' && *p <= 'Z') || + (*p >= 'a' && *p <= 'z') || + (*p >= '0' && *p <= '9') || + *p == '-' || *p == '_' || *p == '$') + ++p; + + if (*p != ';' || p == pFileName || p - pFileName > 39) + { + if (!aFirstLineName.isEmpty()) + continue; + else + return false; + } + ++p; + + // Set entry's name and mode (ISDIR flag): + if ((p - pFileType == 4) && + (pFileType[0] == 'D' || pFileType[0] == 'd') && + (pFileType[1] == 'I' || pFileType[1] == 'i') && + (pFileType[2] == 'R' || pFileType[2] == 'r') ) + { + setPath (rEntry.m_aName, pFileName, (pFileType - pFileName)); + rEntry.m_nMode = INETCOREFTP_FILEMODE_ISDIR; + } + else + { + setPath (rEntry.m_aName, pFileName, (p - pFileName)); + rEntry.m_nMode = 0; + } + + // Skip <version> part: + if (*p < '1' || *p > '9') + { + if (!aFirstLineName.isEmpty()) + continue; + else + return false; + } + ++p; + while (*p >= '0' && *p <= '9') + ++p; + + // Parse <1*lws> or <*lws <NEWLINE>> part: + bool bLWS = false; + while (*p == '\t' || *p == ' ') + { + bLWS = true; + ++p; + } + if (*p) + { + if (!bLWS) + { + if (!aFirstLineName.isEmpty()) + continue; + else + return false; + } + } + else + { + /* + * First line of entry spanning two lines, + * wait for second line. + */ + aFirstLineName = rEntry.m_aName; + bFirstLineDir = + ((rEntry.m_nMode & INETCOREFTP_FILEMODE_ISDIR) != 0); + return false; + } + } + else + { + /* + * Second line of entry spanning two lines, + * restore entry's name and mode (ISDIR flag). + */ + rEntry.m_aName = aFirstLineName; + rEntry.m_nMode = (bFirstLineDir ? INETCOREFTP_FILEMODE_ISDIR : 0); + + // Skip <1*lws> part: + if (*p != '\t' && *p != ' ') + return false; + ++p; + while (*p == '\t' || *p == ' ') + ++p; + } + + // Parse <size> part and set entry's size: + if (*p < '0' || *p > '9') + return false; + sal_uInt32 nSize = *p - '0'; + if (*p++ != '0') + while (*p >= '0' && *p <= '9') + nSize = 10 * rEntry.m_nSize + (*p++ - '0'); + rEntry.m_nSize = 512 * nSize; + + // Skip <1*lws> part: + if (*p != '\t' && *p != ' ') + return false; + ++p; + while (*p == '\t' || *p == ' ') + ++p; + + // Parse <day "-"> part and set entry date's day: + sal_uInt16 nDay; + if (*p == '0') + { + ++p; + if (*p < '1' || *p > '9') + return false; + nDay = *p++ - '0'; + } + else if (*p == '1' || *p == '2') + { + nDay = *p++ - '0'; + if (*p >= '0' && *p <= '9') + nDay = 10 * nDay + (*p++ - '0'); + } + else if (*p == '3') + { + ++p; + nDay = (*p == '0' || *p == '1') ? 30 + (*p++ - '0') : 3; + } + else if (*p >= '4' && *p <= '9') + nDay = *p++ - '0'; + else + return false; + + rEntry.m_aDate.SetDay(nDay); + if (*p++ != '-') + return false; + + // Parse <month "-"> part and set entry date's month: + char const * pMonth = p; + sal_Int32 const monthLen = 3; + for (int i = 0; i < monthLen; ++i) + { + if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z'))) + return false; + ++p; + } + if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "JAN", monthLen) == 0) + rEntry.m_aDate.SetMonth(1); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "FEB", monthLen) == 0) + rEntry.m_aDate.SetMonth(2); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "MAR", monthLen) == 0) + rEntry.m_aDate.SetMonth(3); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "APR", monthLen) == 0) + rEntry.m_aDate.SetMonth(4); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "MAY", monthLen) == 0) + rEntry.m_aDate.SetMonth(5); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "JUN", monthLen) == 0) + rEntry.m_aDate.SetMonth(6); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "JUL", monthLen) == 0) + rEntry.m_aDate.SetMonth(7); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "AUG", monthLen) == 0) + rEntry.m_aDate.SetMonth(8); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "SEP", monthLen) == 0) + rEntry.m_aDate.SetMonth(9); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "OCT", monthLen) == 0) + rEntry.m_aDate.SetMonth(10); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "NOV", monthLen) == 0) + rEntry.m_aDate.SetMonth(11); + else if (rtl_str_compareIgnoreAsciiCase_WithLength( + pMonth, monthLen, "DEC", monthLen) == 0) + rEntry.m_aDate.SetMonth(12); + else + return false; + if (*p++ != '-') + return false; + + // Parse <year> part and set entry date's year: + sal_uInt16 nYear = 0; + for (int i = 0; i < 2; ++i) + { + if (*p < '0' || *p > '9') + return false; + nYear = 10 * nYear + (*p++ - '0'); + } + if (*p >= '0' && *p <= '9') + { + nYear = 10 * nYear + (*p++ - '0'); + if (*p < '0' || *p > '9') + return false; + nYear = 10 * nYear + (*p++ - '0'); + } + setYear (rEntry.m_aDate, nYear); + + // Skip <1*lws> part: + if (*p != '\t' && *p != ' ') + return false; + ++p; + while (*p == '\t' || *p == ' ') + ++p; + + // Parse <hour ":"> part and set entry time's hour: + sal_uInt16 nHour; + if (*p == '0' || *p == '1') + { + nHour = *p++ - '0'; + if (*p >= '0' && *p <= '9') + nHour = 10 * nHour + (*p++ - '0'); + } + else if (*p == '2') + { + ++p; + nHour = (*p >= '0' && *p <= '3') ? 20 + (*p++ - '0') : 2; + } + else if (*p >= '3' && *p <= '9') + nHour = *p++ - '0'; + else + return false; + + rEntry.m_aDate.SetHour(nHour); + if (*p++ != ':') + return false; + + /* + * Parse <minute> part and set entry time's minutes, + * seconds (0), and nanoseconds (0). + */ + if (*p < '0' || *p > '5') + return false; + + sal_uInt16 nMinute = *p++ - '0'; + if (*p < '0' || *p > '9') + return false; + + nMinute = 10 * nMinute + (*p++ - '0'); + rEntry.m_aDate.SetMin(nMinute); + rEntry.m_aDate.SetSec(0); + rEntry.m_aDate.SetNanoSec(0); + + // Skip <rest> part: + return !*p || *p == '\t' || *p == ' '; + } +} + +/* + * parseUNIX + */ +bool FTPDirectoryParser::parseUNIX ( + FTPDirentry &rEntry, + const char *pBuffer) +{ + const char *p1, *p2; + p1 = pBuffer; + + if (!((*p1 == '-') || (*p1 == 'd') || (*p1 == 'l'))) + return false; + + // 1st column: FileMode. + if (*p1 == 'd') + rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISDIR; + + if (*p1 == 'l') + rEntry.m_nMode |= INETCOREFTP_FILEMODE_ISLINK; + + // Skip to end of column and set rights by the way + while (*p1 && !ascii_isWhitespace(*p1)) { + if(*p1 == 'r') + rEntry.m_nMode |= INETCOREFTP_FILEMODE_READ; + else if(*p1 == 'w') + rEntry.m_nMode |= INETCOREFTP_FILEMODE_WRITE; + p1++; + } + + /* + * Scan for the sequence of size and date fields: + * *LWS 1*DIGIT 1*LWS 3CHAR 1*LWS 1*2DIGIT 1*LWS + * (4DIGIT / (1*2DIGIT ":" 2DIGIT)) 1*LWS + */ + enum Mode + { + FOUND_NONE, FOUND_SIZE, FOUND_MONTH, FOUND_DAY, FOUND_YEAR_TIME + }; + + const char *pDayStart = nullptr; + const char *pDayEnd = nullptr; + Mode eMode; + for (eMode = FOUND_NONE; *p1 && eMode != FOUND_YEAR_TIME; p1 = p2 + 1) + { + while (*p1 && ascii_isWhitespace(*p1)) + ++p1; + p2 = p1; + while (*p2 && !ascii_isWhitespace(*p2)) + ++p2; + + switch (eMode) + { + case FOUND_NONE: + if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize)) + eMode = FOUND_SIZE; + break; + + case FOUND_SIZE: + if (parseUNIX_isMonthField (p1, p2, rEntry.m_aDate)) + eMode = FOUND_MONTH; + else if (!parseUNIX_isSizeField (p1, p2, rEntry.m_nSize)) + eMode = FOUND_NONE; + break; + + case FOUND_MONTH: + if (parseUNIX_isDayField (p1, p2, rEntry.m_aDate)) + { + pDayStart = p1; + pDayEnd = p2; + eMode = FOUND_DAY; + } + else if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize)) + eMode = FOUND_SIZE; + else + eMode = FOUND_NONE; + break; + + case FOUND_DAY: + if (parseUNIX_isYearTimeField (p1, p2, rEntry.m_aDate)) + eMode = FOUND_YEAR_TIME; + else if ( + parseUNIX_isSizeField ( + pDayStart, pDayEnd, rEntry.m_nSize) && + parseUNIX_isMonthField ( + p1, p2, rEntry.m_aDate)) + eMode = FOUND_MONTH; + else if (parseUNIX_isSizeField (p1, p2, rEntry.m_nSize)) + eMode = FOUND_SIZE; + else + eMode = FOUND_NONE; + break; + // coverity[dead_error_begin] - following conditions exist to avoid compiler warning + case FOUND_YEAR_TIME: + break; + } + } + + if (eMode == FOUND_YEAR_TIME) + { + // 9th column: FileName (rest of line). + while (*p1 && ascii_isWhitespace(*p1)) p1++; + setPath (rEntry.m_aName, p1); + + // Done. + return true; + } + return false; +} + +/* + * parseUNIX_isSizeField. + */ +bool FTPDirectoryParser::parseUNIX_isSizeField ( + const char *pStart, + const char *pEnd, + sal_uInt32 &rSize) +{ + if (!*pStart || !*pEnd || pStart == pEnd) + return false; + + rSize = 0; + if (*pStart >= '0' && *pStart <= '9') + { + for (; pStart < pEnd; ++pStart) + if ((*pStart >= '0') && (*pStart <= '9')) + rSize = 10 * rSize + (*pStart - '0'); + else + return false; + return true; + } + else + { + /* + * For a combination of long group name and large file size, + * some FTPDs omit LWS between those two columns. + */ + int nNonDigits = 0; + int nDigits = 0; + + for (; pStart < pEnd; ++pStart) + if ((*pStart >= '1') && (*pStart <= '9')) + { + ++nDigits; + rSize = 10 * rSize + (*pStart - '0'); + } + else if ((*pStart == '0') && nDigits) + { + ++nDigits; + rSize *= 10; + } + else if ((*pStart > ' ') && (sal::static_int_cast<sal_uInt8>(*pStart) <= '\x7F')) + { + nNonDigits += nDigits + 1; + nDigits = 0; + rSize = 0; + } + else + return false; + return ((nNonDigits >= 9) && (nDigits >= 7)); + } +} + +/* + * parseUNIX_isMonthField. + */ +bool FTPDirectoryParser::parseUNIX_isMonthField ( + const char *pStart, + const char *pEnd, + DateTime &rDateTime) +{ + if (!*pStart || !*pEnd || pStart + 3 != pEnd) + return false; + + if ((pStart[0] == 'j' || pStart[0] == 'J') && + (pStart[1] == 'a' || pStart[1] == 'A') && + (pStart[2] == 'n' || pStart[2] == 'N') ) + { + rDateTime.SetMonth(1); + return true; + } + if ((pStart[0] == 'f' || pStart[0] == 'F') && + (pStart[1] == 'e' || pStart[1] == 'E') && + (pStart[2] == 'b' || pStart[2] == 'B') ) + { + rDateTime.SetMonth(2); + return true; + } + if ((pStart[0] == 'm' || pStart[0] == 'M') && + (pStart[1] == 'a' || pStart[1] == 'A') && + (pStart[2] == 'r' || pStart[2] == 'R') ) + { + rDateTime.SetMonth(3); + return true; + } + if ((pStart[0] == 'a' || pStart[0] == 'A') && + (pStart[1] == 'p' || pStart[1] == 'P') && + (pStart[2] == 'r' || pStart[2] == 'R') ) + { + rDateTime.SetMonth(4); + return true; + } + if ((pStart[0] == 'm' || pStart[0] == 'M') && + (pStart[1] == 'a' || pStart[1] == 'A') && + (pStart[2] == 'y' || pStart[2] == 'Y') ) + { + rDateTime.SetMonth(5); + return true; + } + if ((pStart[0] == 'j' || pStart[0] == 'J') && + (pStart[1] == 'u' || pStart[1] == 'U') && + (pStart[2] == 'n' || pStart[2] == 'N') ) + { + rDateTime.SetMonth(6); + return true; + } + if ((pStart[0] == 'j' || pStart[0] == 'J') && + (pStart[1] == 'u' || pStart[1] == 'U') && + (pStart[2] == 'l' || pStart[2] == 'L') ) + { + rDateTime.SetMonth(7); + return true; + } + if ((pStart[0] == 'a' || pStart[0] == 'A') && + (pStart[1] == 'u' || pStart[1] == 'U') && + (pStart[2] == 'g' || pStart[2] == 'G') ) + { + rDateTime.SetMonth(8); + return true; + } + if ((pStart[0] == 's' || pStart[0] == 'S') && + (pStart[1] == 'e' || pStart[1] == 'E') && + (pStart[2] == 'p' || pStart[2] == 'P') ) + { + rDateTime.SetMonth(9); + return true; + } + if ((pStart[0] == 'o' || pStart[0] == 'O') && + (pStart[1] == 'c' || pStart[1] == 'C') && + (pStart[2] == 't' || pStart[2] == 'T') ) + { + rDateTime.SetMonth(10); + return true; + } + if ((pStart[0] == 'n' || pStart[0] == 'N') && + (pStart[1] == 'o' || pStart[1] == 'O') && + (pStart[2] == 'v' || pStart[2] == 'V') ) + { + rDateTime.SetMonth(11); + return true; + } + if ((pStart[0] == 'd' || pStart[0] == 'D') && + (pStart[1] == 'e' || pStart[1] == 'E') && + (pStart[2] == 'c' || pStart[2] == 'C') ) + { + rDateTime.SetMonth(12); + return true; + } + return false; +} + +/* + * parseUNIX_isDayField. + */ +bool FTPDirectoryParser::parseUNIX_isDayField ( + const char *pStart, + const char *pEnd, + DateTime &rDateTime) +{ + if (!*pStart || !*pEnd || pStart == pEnd) + return false; + if (*pStart < '0' || *pStart > '9') + return false; + + sal_uInt16 nDay = *pStart - '0'; + if (pStart + 1 < pEnd) + { + if (pStart + 2 != pEnd || pStart[1] < '0' || pStart[1] > '9') + return false; + nDay = 10 * nDay + (pStart[1] - '0'); + } + if (!nDay || nDay > 31) + return false; + + rDateTime.SetDay(nDay); + return true; +} + +/* + * parseUNIX_isYearTimeField. + */ +bool FTPDirectoryParser::parseUNIX_isYearTimeField ( + const char *pStart, + const char *pEnd, + DateTime &rDateTime) +{ + if (!*pStart || !*pEnd || pStart == pEnd || + *pStart < '0' || *pStart > '9') + return false; + + sal_uInt16 nNumber = *pStart - '0'; + ++pStart; + + if (pStart == pEnd) + return false; + if (*pStart == ':') + return parseUNIX_isTime (pStart, pEnd, nNumber, rDateTime); + if (*pStart < '0' || *pStart > '9') + return false; + + nNumber = 10 * nNumber + (*pStart - '0'); + ++pStart; + + if (pStart == pEnd) + return false; + if (*pStart == ':') + return parseUNIX_isTime (pStart, pEnd, nNumber, rDateTime); + if (*pStart < '0' || *pStart > '9') + return false; + + nNumber = 10 * nNumber + (*pStart - '0'); + ++pStart; + + if (pStart == pEnd || *pStart < '0' || *pStart > '9') + return false; + + nNumber = 10 * nNumber + (*pStart - '0'); + if (pStart + 1 != pEnd || nNumber < 1970) + return false; + + rDateTime.SetYear(nNumber); + rDateTime.SetTime(); + return true; +} + +/* + * parseUNIX_isTime. + */ +bool FTPDirectoryParser::parseUNIX_isTime ( + const char *pStart, + const char *pEnd, + sal_uInt16 nHour, + DateTime &rDateTime) +{ + if ((nHour > 23 ) || (pStart + 3 != pEnd) || + (pStart[1] < '0') || (pStart[1] > '5') || + (pStart[2] < '0') || (pStart[2] > '9') ) + return false; + + sal_uInt16 nMin = 10 * (pStart[1] - '0') + (pStart[2] - '0'); + + rDateTime.SetHour (nHour); + rDateTime.SetMin (nMin); + rDateTime.SetSec (0); + rDateTime.SetNanoSec (0); + +// Date aCurDate; +// if (rDateTime.GetMonth() > aCurDate.GetMonth()) +// rDateTime.SetYear(aCurDate.GetYear() - 1); +// else +// rDateTime.SetYear(aCurDate.GetYear()); +// return sal_True; + + TimeValue aTimeVal; + osl_getSystemTime(&aTimeVal); + oslDateTime aCurrDateTime; + osl_getDateTimeFromTimeValue(&aTimeVal,&aCurrDateTime); + + if (rDateTime.GetMonth() > aCurrDateTime.Month) + rDateTime.SetYear(aCurrDateTime.Year - 1); + else + rDateTime.SetYear(aCurrDateTime.Year); + return true; +} + +/* + * setYear. + * + * Two-digit years are taken as within 50 years back and 49 years forward + * (both ends inclusive) from the current year. The returned date is not + * checked for validity of the given day in the given month and year. + * + */ +void FTPDirectoryParser::setYear ( + DateTime &rDateTime, sal_uInt16 nYear) +{ + if (nYear < 100) + { + TimeValue aTimeVal; + osl_getSystemTime(&aTimeVal); + oslDateTime aCurrDateTime; + osl_getDateTimeFromTimeValue(&aTimeVal,&aCurrDateTime); + sal_uInt16 nCurrentYear = aCurrDateTime.Year; +// sal_uInt16 nCurrentYear = Date().GetYear(); + sal_uInt16 nCurrentCentury = nCurrentYear / 100; + nCurrentYear %= 100; + if (nCurrentYear < 50) + if (nYear <= nCurrentYear) + nYear += nCurrentCentury * 100; + else if (nYear < nCurrentYear + 50) + nYear += nCurrentCentury * 100; + else + nYear += (nCurrentCentury - 1) * 100; + else + if (nYear >= nCurrentYear) + nYear += nCurrentCentury * 100; + else if (nYear >= nCurrentYear - 50) + nYear += nCurrentCentury * 100; + else + nYear += (nCurrentCentury + 1) * 100; + } + + rDateTime.SetYear(nYear); +} + +/* + * setPath. + */ +bool FTPDirectoryParser::setPath ( + OUString &rPath, const char *value, sal_Int32 length) +{ + if (value) + { + if (length < 0) + length = rtl_str_getLength (value); + rPath = OUString (value, length, RTL_TEXTENCODING_UTF8); + } + return (!!value); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpdirp.hxx b/ucb/source/ucp/ftp/ftpdirp.hxx new file mode 100644 index 000000000..ae9f36a47 --- /dev/null +++ b/ucb/source/ucp/ftp/ftpdirp.hxx @@ -0,0 +1,158 @@ +/* -*- 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 + ************************************************************************** + + *************************************************************************/ +#pragma once + +#include <rtl/ustring.hxx> +#include <com/sun/star/util/DateTime.hpp> + + +namespace ftp { + + /*======================================================================== + * + * the DateTime structure + * + *======================================================================*/ + + struct DateTime + : public css::util::DateTime + { + DateTime() : css::util::DateTime(0, 0, 0, 0, 0, 0, 0, false) { } + + void SetYear(sal_uInt16 year) { Year = year; } + void SetMonth(sal_uInt16 month) { Month = month; } + void SetDay(sal_uInt16 day) { Day = day; } + // Only zero allowed and used for time-argument + void SetTime() { Hours = 0; Minutes = 0; Seconds = 0; NanoSeconds = 0; } + void SetHour(sal_uInt16 hours) { Hours = hours; } + void SetMin(sal_uInt16 minutes) { Minutes = minutes; } + void SetSec(sal_uInt16 seconds) { Seconds = seconds; } + void SetNanoSec(sal_uInt32 nanoSec) { NanoSeconds = nanoSec; } + + sal_uInt16 GetMonth() const { return Month; } + }; + + +/*======================================================================== + * + * the directory information structure + * + *======================================================================*/ + + enum FTPDirentryMode { INETCOREFTP_FILEMODE_UNKNOWN = 0x00, + INETCOREFTP_FILEMODE_READ = 0x01, + INETCOREFTP_FILEMODE_WRITE = 0x02, + INETCOREFTP_FILEMODE_ISDIR = 0x04, + INETCOREFTP_FILEMODE_ISLINK = 0x08 }; + + struct FTPDirentry + { + OUString m_aURL; + OUString m_aName; + DateTime m_aDate; + sal_uInt32 m_nMode; + sal_uInt32 m_nSize; + + FTPDirentry() + : m_aDate(), + m_nMode(INETCOREFTP_FILEMODE_UNKNOWN), + m_nSize(sal_uInt32(-1)) { } + + void clear() { + m_aURL.clear(); + m_aName.clear(); + m_aDate = DateTime(); + m_nMode = INETCOREFTP_FILEMODE_UNKNOWN; + m_nSize = sal_uInt32(-1); + } + }; + + +/*======================================================================== + * + * the directory parser + * + *======================================================================*/ + + + class FTPDirectoryParser + { + public: + static bool parseDOS ( + FTPDirentry &rEntry, + const char *pBuffer ); + + static bool parseVMS ( + FTPDirentry &rEntry, + const char *pBuffer ); + + static bool parseUNIX ( + FTPDirentry &rEntry, + const char *pBuffer ); + + + private: + + static bool parseUNIX_isSizeField ( + const char *pStart, + const char *pEnd, + sal_uInt32 &rSize); + + static bool parseUNIX_isMonthField ( + const char *pStart, + const char *pEnd, + DateTime& rDateTime); + + static bool parseUNIX_isDayField ( + const char *pStart, + const char *pEnd, + DateTime& rDateTime); + + static bool parseUNIX_isYearTimeField ( + const char *pStart, + const char *pEnd, + DateTime& rDateTime); + + static bool parseUNIX_isTime ( + const char *pStart, + const char *pEnd, + sal_uInt16 nHour, + DateTime& rDateTime); + + static void setYear ( + DateTime& rDateTime, + sal_uInt16 nYear); + + static bool setPath ( + OUString& rPath, + const char *value, + sal_Int32 length = -1); + }; + + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpdynresultset.cxx b/ucb/source/ucp/ftp/ftpdynresultset.cxx new file mode 100644 index 000000000..8021f9dd4 --- /dev/null +++ b/ucb/source/ucp/ftp/ftpdynresultset.cxx @@ -0,0 +1,67 @@ +/* -*- 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 . + */ + +#include <com/sun/star/sdbc/XResultSet.hpp> +#include "ftpdynresultset.hxx" +#include "ftpresultsetfactory.hxx" + +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::ucb; +using namespace com::sun::star::uno; + + +using namespace ftp; + + +// DynamicResultSet Implementation. + + +DynamicResultSet::DynamicResultSet( + const Reference< XComponentContext >& rxContext, + const OpenCommandArgument2& rCommand, + std::unique_ptr<ResultSetFactory> pFactory ) + : ResultSetImplHelper( rxContext, rCommand ), + m_pFactory( std::move(pFactory) ) +{ +} + +DynamicResultSet::~DynamicResultSet() +{ +} + + +// Non-interface methods. + + +void DynamicResultSet::initStatic() +{ + m_xResultSet1.set( m_pFactory->createResultSet() ); +} + + +void DynamicResultSet::initDynamic() +{ + m_xResultSet1.set( m_pFactory->createResultSet() ); + + m_xResultSet2 = m_xResultSet1; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpdynresultset.hxx b/ucb/source/ucp/ftp/ftpdynresultset.hxx new file mode 100644 index 000000000..76a070a6d --- /dev/null +++ b/ucb/source/ucp/ftp/ftpdynresultset.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ + +#pragma once + +#include <memory> +#include <ucbhelper/resultsethelper.hxx> + +namespace ftp { + + class ResultSetFactory; + + class DynamicResultSet : public ::ucbhelper::ResultSetImplHelper + { + std::unique_ptr<ResultSetFactory> m_pFactory; + + private: + virtual void initStatic() override; + virtual void initDynamic() override; + + public: + DynamicResultSet( + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::ucb::OpenCommandArgument2& rCommand, + std::unique_ptr<ResultSetFactory> pFactory ); + + virtual ~DynamicResultSet() override; + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpintreq.cxx b/ucb/source/ucp/ftp/ftpintreq.cxx new file mode 100644 index 000000000..32c765a4e --- /dev/null +++ b/ucb/source/ucp/ftp/ftpintreq.cxx @@ -0,0 +1,64 @@ +/* -*- 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 . + */ + +#include "ftpintreq.hxx" + +#include <comphelper/interaction.hxx> + +#include <com/sun/star/ucb/UnsupportedNameClashException.hpp> +#include <com/sun/star/ucb/NameClash.hpp> + +using namespace cppu; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::ucb; +using namespace com::sun::star::task; +using namespace ftp; + +XInteractionApproveImpl::XInteractionApproveImpl() + : m_bSelected(false) +{ +} + +void SAL_CALL XInteractionApproveImpl::select() { m_bSelected = true; } + +// XInteractionDisapproveImpl + +XInteractionDisapproveImpl::XInteractionDisapproveImpl() {} + +void SAL_CALL XInteractionDisapproveImpl::select() {} + +// XInteractionRequestImpl + +XInteractionRequestImpl::XInteractionRequestImpl() + : p1(new XInteractionApproveImpl) +{ + std::vector<uno::Reference<task::XInteractionContinuation>> continuations{ + Reference<XInteractionContinuation>(p1), + Reference<XInteractionContinuation>(new XInteractionDisapproveImpl) + }; + UnsupportedNameClashException excep; + excep.NameClash = NameClash::ERROR; + m_xRequest.set(new ::comphelper::OInteractionRequest(Any(excep), std::move(continuations))); +} + +bool XInteractionRequestImpl::approved() const { return p1->isSelected(); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpintreq.hxx b/ucb/source/ucp/ftp/ftpintreq.hxx new file mode 100644 index 000000000..79bf74ed7 --- /dev/null +++ b/ucb/source/ucp/ftp/ftpintreq.hxx @@ -0,0 +1,84 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/task/XInteractionDisapprove.hpp> +#include <com/sun/star/task/XInteractionApprove.hpp> +#include <com/sun/star/task/XInteractionRequest.hpp> +#include <cppuhelper/implbase.hxx> + + +namespace ftp { + + class XInteractionApproveImpl : public cppu::WeakImplHelper < + css::task::XInteractionApprove > + { + public: + + XInteractionApproveImpl(); + + virtual void SAL_CALL select() override; + + bool isSelected() const { return m_bSelected;} + + private: + + bool m_bSelected; + }; + + + class XInteractionDisapproveImpl : public cppu::WeakImplHelper < + css::task::XInteractionDisapprove > + { + public: + + XInteractionDisapproveImpl(); + + virtual void SAL_CALL select() override; + }; + + + class XInteractionRequestImpl + { + public: + + XInteractionRequestImpl(); + + bool approved() const; + + css::uno::Reference<css::task::XInteractionRequest> const& getRequest() const + { + return m_xRequest; + } + + private: + + XInteractionApproveImpl* p1; + + css::uno::Reference<css::task::XInteractionRequest> m_xRequest; + + XInteractionRequestImpl(const XInteractionRequestImpl&) = delete; + XInteractionRequestImpl& operator=(const XInteractionRequestImpl&) = delete; + }; + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftploaderthread.cxx b/ucb/source/ucp/ftp/ftploaderthread.cxx new file mode 100644 index 000000000..f5ebfe36c --- /dev/null +++ b/ucb/source/ucp/ftp/ftploaderthread.cxx @@ -0,0 +1,92 @@ +/* -*- 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 "ftploaderthread.hxx" +#include "curl.hxx" + +using namespace ftp; + + +/********************************************************************************/ +/* */ +/* cleanup function for thread specific data */ +/* */ +/********************************************************************************/ + +extern "C" { + + static int memory_write_dummy(void *,size_t,size_t,void *) + { + return 0; + } + + static void delete_CURL(void *pData) + { + // Otherwise response for QUIT will be sent to already destroyed + // MemoryContainer via non-dummy memory_write function. + (void)curl_easy_setopt(static_cast<CURL*>(pData), + CURLOPT_HEADERFUNCTION, + memory_write_dummy); + curl_easy_cleanup(static_cast<CURL*>(pData)); + } + +} + +/********************************************************************************/ +/* */ +/* Member part of FTPLoaderThread */ +/* */ +/********************************************************************************/ + + +FTPLoaderThread::FTPLoaderThread() + : m_threadKey(osl_createThreadKey(delete_CURL)) { +} + + +FTPLoaderThread::~FTPLoaderThread() { + osl_destroyThreadKey(m_threadKey); +} + + +CURL* FTPLoaderThread::handle() { + CURL* ret = static_cast<CURL*>(osl_getThreadKeyData(m_threadKey)); + if(!ret) { + ret = curl_easy_init(); + if (ret != nullptr) { + // Make sure curl is not internally using environment variables like + // "ftp_proxy": + if (curl_easy_setopt(ret, CURLOPT_PROXY, "") != CURLE_OK) { + curl_easy_cleanup(ret); + ret = nullptr; + } + } + osl_setThreadKeyData(m_threadKey, ret); + } + + return ret; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftploaderthread.hxx b/ucb/source/ucp/ftp/ftploaderthread.hxx new file mode 100644 index 000000000..79ba60d1d --- /dev/null +++ b/ucb/source/ucp/ftp/ftploaderthread.hxx @@ -0,0 +1,59 @@ +/* -*- 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 + ************************************************************************** + + *************************************************************************/ + +#pragma once + +#include <osl/thread.h> +#include "curl.hxx" + +namespace ftp { + + /** A loaderthread acts as factory for CURL-handles, + * the key being ( implicit ) the threadid. + * Owner is a FTPContentProvider-instance + */ + + class FTPLoaderThread + { + public: + + FTPLoaderThread(); + ~FTPLoaderThread(); + + CURL* handle(); + + + private: + FTPLoaderThread(const FTPLoaderThread&) = delete; + FTPLoaderThread& operator=(const FTPLoaderThread&) = delete; + + oslThreadKey m_threadKey; + + }; // end class FTPLoaderThread + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpresultsetI.cxx b/ucb/source/ucp/ftp/ftpresultsetI.cxx new file mode 100644 index 000000000..baef97284 --- /dev/null +++ b/ucb/source/ucp/ftp/ftpresultsetI.cxx @@ -0,0 +1,90 @@ +/* -*- 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 . + */ + + +#include <ucbhelper/propertyvalueset.hxx> +#include <rtl/ref.hxx> +#include <com/sun/star/ucb/Command.hpp> +#include "ftpresultsetI.hxx" +#include "ftpcontent.hxx" + + +using namespace ftp; +using namespace com::sun::star::ucb; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; + + +ResultSetI::ResultSetI(const Reference<XComponentContext>& rxContext, + const Reference<XContentProvider>& xProvider, + const Sequence<Property>& seqProp, + const std::vector<FTPDirentry>& dirvec) + : ResultSetBase(rxContext,xProvider,seqProp) +{ + for(const auto & i : dirvec) + m_aPath.push_back(i.m_aURL); + + // m_aIdents holds the content identifiers + + m_aItems.resize( m_aPath.size() ); + m_aIdents.resize( m_aPath.size() ); + + for(size_t n = 0; n < m_aItems.size(); ++n) { + rtl::Reference<ucbhelper::PropertyValueSet> xRow = + new ucbhelper::PropertyValueSet(rxContext); + + for( const auto& rProp : seqProp) { + const OUString& Name = rProp.Name; + if(Name == "ContentType") + xRow->appendString(rProp, + OUString( "application/ftp" )); + else if(Name == "Title") + xRow->appendString(rProp,dirvec[n].m_aName); + else if(Name == "IsReadOnly") + xRow->appendBoolean(rProp, + (dirvec[n].m_nMode & + INETCOREFTP_FILEMODE_WRITE) == INETCOREFTP_FILEMODE_WRITE); + else if(Name == "IsDocument") + xRow->appendBoolean(rProp, + (dirvec[n].m_nMode & + INETCOREFTP_FILEMODE_ISDIR) != INETCOREFTP_FILEMODE_ISDIR); + else if(Name == "IsFolder") + xRow->appendBoolean(rProp, + ( dirvec[n].m_nMode & + INETCOREFTP_FILEMODE_ISDIR) == INETCOREFTP_FILEMODE_ISDIR); + else if(Name == "Size") + xRow->appendLong(rProp, + dirvec[n].m_nSize); + else if(Name == "DateCreated") + xRow->appendTimestamp(rProp, + dirvec[n].m_aDate); + else if(Name == "CreatableContentsInfo") + xRow->appendObject( + rProp, + Any(FTPContent::queryCreatableContentsInfo_Static())); + else + xRow->appendVoid(rProp); + } + m_aItems[n].set(xRow); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpresultsetI.hxx b/ucb/source/ucp/ftp/ftpresultsetI.hxx new file mode 100644 index 000000000..259469dd1 --- /dev/null +++ b/ucb/source/ucp/ftp/ftpresultsetI.hxx @@ -0,0 +1,46 @@ +/* -*- 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 . + */ +#pragma once + +#include <com/sun/star/ucb/XContentProvider.hpp> +#include <com/sun/star/beans/Property.hpp> +#include "ftpresultsetbase.hxx" +#include "ftpdirp.hxx" + + +namespace ftp { + + class ResultSetI + : public ResultSetBase + { + public: + + ResultSetI( + const css::uno::Reference< css::uno::XComponentContext>& rxContext, + const css::uno::Reference< css::ucb::XContentProvider>& xProvider, + const css::uno::Sequence< css::beans::Property >& seq, + const std::vector<FTPDirentry>& dirvec); + + private: + }; + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpresultsetbase.cxx b/ucb/source/ucp/ftp/ftpresultsetbase.cxx new file mode 100644 index 000000000..815145918 --- /dev/null +++ b/ucb/source/ucp/ftp/ftpresultsetbase.cxx @@ -0,0 +1,509 @@ +/* -*- 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 . + */ + +#include <ucbhelper/contentidentifier.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <ucbhelper/resultsetmetadata.hxx> +#include <cppuhelper/queryinterface.hxx> +#include "ftpresultsetbase.hxx" + +using namespace ftp; +using namespace com::sun::star; + +ResultSetBase::ResultSetBase( + const uno::Reference< uno::XComponentContext >& rxContext, + const uno::Reference< ucb::XContentProvider >& xProvider, + const uno::Sequence< beans::Property >& seq ) + : m_xContext( rxContext ), + m_xProvider( xProvider ), + m_nRow( -1 ), + m_nWasNull( true ), + m_sProperty( seq ) +{ +} + +ResultSetBase::~ResultSetBase() +{ +} + + +// XInterface + +void SAL_CALL +ResultSetBase::acquire() + noexcept +{ + OWeakObject::acquire(); +} + + +void SAL_CALL +ResultSetBase::release() + noexcept +{ + OWeakObject::release(); +} + + +uno::Any SAL_CALL +ResultSetBase::queryInterface( const uno::Type& rType ) +{ + uno::Any aRet = cppu::queryInterface( + rType, + static_cast< lang::XComponent* >(this), + static_cast< sdbc::XRow* >(this), + static_cast< sdbc::XResultSet* >(this), + static_cast< sdbc::XResultSetMetaDataSupplier* >(this), + static_cast< beans::XPropertySet* >(this), + static_cast< ucb::XContentAccess* >(this) ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + + +// XComponent + + +void SAL_CALL +ResultSetBase::addEventListener( + const uno::Reference< lang::XEventListener >& Listener ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( ! m_pDisposeEventListeners ) + m_pDisposeEventListeners.reset( + new comphelper::OInterfaceContainerHelper3<lang::XEventListener>( m_aMutex ) ); + + m_pDisposeEventListeners->addInterface( Listener ); +} + + +void SAL_CALL +ResultSetBase::removeEventListener( + const uno::Reference< lang::XEventListener >& Listener ) +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( m_pDisposeEventListeners ) + m_pDisposeEventListeners->removeInterface( Listener ); +} + + +void SAL_CALL +ResultSetBase::dispose() +{ + osl::MutexGuard aGuard( m_aMutex ); + + lang::EventObject aEvt; + aEvt.Source = static_cast< lang::XComponent * >( this ); + + if ( m_pDisposeEventListeners && m_pDisposeEventListeners->getLength() ) + { + m_pDisposeEventListeners->disposeAndClear( aEvt ); + } + if( m_pRowCountListeners && m_pRowCountListeners->getLength() ) + { + m_pRowCountListeners->disposeAndClear( aEvt ); + } + if( m_pIsFinalListeners && m_pIsFinalListeners->getLength() ) + { + m_pIsFinalListeners->disposeAndClear( aEvt ); + } +} + + +// XResultSet + +sal_Bool SAL_CALL +ResultSetBase::next() +{ + ++m_nRow; + return m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()); +} + + +sal_Bool SAL_CALL +ResultSetBase::isBeforeFirst() +{ + return m_nRow == -1; +} + + +sal_Bool SAL_CALL +ResultSetBase::isAfterLast() +{ + return m_nRow >= sal::static_int_cast<sal_Int32>(m_aItems.size()); // Cannot happen, if m_aFolder.isOpen() +} + + +sal_Bool SAL_CALL +ResultSetBase::isFirst() +{ + return m_nRow == 0; +} + + +sal_Bool SAL_CALL +ResultSetBase::isLast() +{ + if( m_nRow == sal::static_int_cast<sal_Int32>(m_aItems.size()) - 1 ) + return true; + else + return false; +} + + +void SAL_CALL +ResultSetBase::beforeFirst() +{ + m_nRow = -1; +} + + +void SAL_CALL +ResultSetBase::afterLast() +{ + m_nRow = m_aItems.size(); +} + + +sal_Bool SAL_CALL +ResultSetBase::first() +{ + m_nRow = -1; + return next(); +} + + +sal_Bool SAL_CALL +ResultSetBase::last() +{ + m_nRow = m_aItems.size() - 1; + return true; +} + + +sal_Int32 SAL_CALL +ResultSetBase::getRow() +{ + // Test, whether behind last row + if( -1 == m_nRow || m_nRow >= sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return 0; + else + return m_nRow+1; +} + + +sal_Bool SAL_CALL ResultSetBase::absolute( sal_Int32 row ) +{ + if( row >= 0 ) + m_nRow = row - 1; + else + { + last(); + m_nRow += ( row + 1 ); + if( m_nRow < -1 ) + m_nRow = -1; + } + + return 0<= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()); +} + + +sal_Bool SAL_CALL +ResultSetBase::relative( sal_Int32 row ) +{ + if( isAfterLast() || isBeforeFirst() ) + throw sdbc::SQLException(); + + if( row > 0 ) + while( row-- ) + next(); + else if( row < 0 ) + while( row++ && m_nRow > - 1 ) + previous(); + + return 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()); +} + + +sal_Bool SAL_CALL +ResultSetBase::previous() +{ + if( m_nRow > sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + m_nRow = m_aItems.size(); // Correct Handling of afterLast + if( 0 <= m_nRow ) -- m_nRow; + + return 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()); +} + + +void SAL_CALL +ResultSetBase::refreshRow() +{ +} + + +sal_Bool SAL_CALL +ResultSetBase::rowUpdated() +{ + return false; +} + +sal_Bool SAL_CALL +ResultSetBase::rowInserted() +{ + return false; +} + +sal_Bool SAL_CALL +ResultSetBase::rowDeleted() +{ + return false; +} + + +uno::Reference< uno::XInterface > SAL_CALL +ResultSetBase::getStatement() +{ + return uno::Reference< uno::XInterface >(); +} + + +// XCloseable + +void SAL_CALL +ResultSetBase::close() +{ +} + + +OUString SAL_CALL +ResultSetBase::queryContentIdentifierString() +{ + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aPath[m_nRow]; + else + return OUString(); +} + + +uno::Reference< ucb::XContentIdentifier > SAL_CALL +ResultSetBase::queryContentIdentifier() +{ + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + { + if(!m_aIdents[m_nRow].is()) { + OUString url = queryContentIdentifierString(); + if(!url.isEmpty() ) + m_aIdents[m_nRow] = + uno::Reference< ucb::XContentIdentifier >( + new ::ucbhelper::ContentIdentifier(url) ); + } + return m_aIdents[m_nRow]; + } + + return uno::Reference<ucb::XContentIdentifier>(); +} + + +uno::Reference< ucb::XContent > SAL_CALL +ResultSetBase::queryContent() +{ + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_xProvider->queryContent(queryContentIdentifier()); + else + return uno::Reference< ucb::XContent >(); +} + +namespace { + +class XPropertySetInfoImpl + : public cppu::OWeakObject, + public beans::XPropertySetInfo +{ +public: + + explicit XPropertySetInfoImpl( const uno::Sequence< beans::Property >& aSeq ) + : m_aSeq( aSeq ) + { + } + + void SAL_CALL acquire() + noexcept override + { + OWeakObject::acquire(); + } + + + void SAL_CALL release() + noexcept override + { + OWeakObject::release(); + } + + uno::Any SAL_CALL queryInterface( const uno::Type& rType ) override + { + uno::Any aRet = cppu::queryInterface( + rType, + static_cast< beans::XPropertySetInfo* >(this) ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); + } + + uno::Sequence< beans::Property > SAL_CALL getProperties() override + { + return m_aSeq; + } + + beans::Property SAL_CALL getPropertyByName( const OUString& aName ) override + { + auto pProp = std::find_if(std::cbegin(m_aSeq), std::cend(m_aSeq), + [&aName](const beans::Property& rProp) { return aName == rProp.Name; }); + if (pProp != std::cend(m_aSeq)) + return *pProp; + throw beans::UnknownPropertyException(aName); + } + + sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override + { + return std::any_of(std::cbegin(m_aSeq), std::cend(m_aSeq), + [&Name](const beans::Property& rProp) { return Name == rProp.Name; }); + } + +private: + + uno::Sequence< beans::Property > m_aSeq; +}; + +} + +// XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL +ResultSetBase::getPropertySetInfo() +{ + uno::Sequence< beans::Property > seq + { + { "RowCount", -1, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY }, + { "IsRowCountFinal", -1, cppu::UnoType<sal_Bool>::get(), beans::PropertyAttribute::READONLY } + }; + + return uno::Reference< beans::XPropertySetInfo > ( + new XPropertySetInfoImpl( seq ) ); +} + + +void SAL_CALL ResultSetBase::setPropertyValue( + const OUString& aPropertyName, const uno::Any& /*aValue*/ ) +{ + if( aPropertyName == "IsRowCountFinal" || + aPropertyName == "RowCount" ) + return; + + throw beans::UnknownPropertyException(aPropertyName); +} + + +uno::Any SAL_CALL ResultSetBase::getPropertyValue( + const OUString& PropertyName ) +{ + if( PropertyName == "IsRowCountFinal" ) + { + return uno::Any(true); + } + else if ( PropertyName == "RowCount" ) + { + sal_Int32 count = m_aItems.size(); + return uno::Any(count); + } + else + throw beans::UnknownPropertyException(PropertyName); +} + + +void SAL_CALL ResultSetBase::addPropertyChangeListener( + const OUString& aPropertyName, + const uno::Reference< beans::XPropertyChangeListener >& xListener ) +{ + if( aPropertyName == "IsRowCountFinal" ) + { + osl::MutexGuard aGuard( m_aMutex ); + if ( ! m_pIsFinalListeners ) + m_pIsFinalListeners.reset( + new comphelper::OInterfaceContainerHelper3<beans::XPropertyChangeListener>( m_aMutex ) ); + + m_pIsFinalListeners->addInterface( xListener ); + } + else if ( aPropertyName == "RowCount" ) + { + osl::MutexGuard aGuard( m_aMutex ); + if ( ! m_pRowCountListeners ) + m_pRowCountListeners.reset( + new comphelper::OInterfaceContainerHelper3<beans::XPropertyChangeListener>( m_aMutex ) ); + m_pRowCountListeners->addInterface( xListener ); + } + else + throw beans::UnknownPropertyException(aPropertyName); +} + + +void SAL_CALL ResultSetBase::removePropertyChangeListener( + const OUString& aPropertyName, + const uno::Reference< beans::XPropertyChangeListener >& aListener ) +{ + if( aPropertyName == "IsRowCountFinal" && + m_pIsFinalListeners ) + { + osl::MutexGuard aGuard( m_aMutex ); + m_pIsFinalListeners->removeInterface( aListener ); + } + else if ( aPropertyName == "RowCount" && + m_pRowCountListeners ) + { + osl::MutexGuard aGuard( m_aMutex ); + m_pRowCountListeners->removeInterface( aListener ); + } + else + throw beans::UnknownPropertyException(aPropertyName); +} + + +void SAL_CALL ResultSetBase::addVetoableChangeListener( + const OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ +} + + +void SAL_CALL ResultSetBase::removeVetoableChangeListener( + const OUString& /*PropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ +} + + +// XResultSetMetaDataSupplier +uno::Reference< sdbc::XResultSetMetaData > SAL_CALL +ResultSetBase::getMetaData() +{ + return new ::ucbhelper::ResultSetMetaData( m_xContext, m_sProperty ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpresultsetbase.hxx b/ucb/source/ucp/ftp/ftpresultsetbase.hxx new file mode 100644 index 000000000..cfb447f6e --- /dev/null +++ b/ucb/source/ucp/ftp/ftpresultsetbase.hxx @@ -0,0 +1,410 @@ +/* -*- 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 . + */ +#pragma once + +#include <vector> +#include <cppuhelper/weak.hxx> +#include <comphelper/interfacecontainer3.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/ucb/XContentProvider.hpp> +#include <com/sun/star/ucb/XContentIdentifier.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/Property.hpp> + + +namespace ftp { + + class ResultSetBase + : public cppu::OWeakObject, + public css::lang::XComponent, + public css::sdbc::XRow, + public css::sdbc::XResultSet, + public css::sdbc::XCloseable, + public css::sdbc::XResultSetMetaDataSupplier, + public css::beans::XPropertySet, + public css::ucb::XContentAccess + { + public: + + ResultSetBase(const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::ucb::XContentProvider >& xProvider, + const css::uno::Sequence< css::beans::Property >& seq); + + virtual ~ResultSetBase() override; + + // XInterface + virtual css::uno::Any SAL_CALL + queryInterface( const css::uno::Type& aType ) override; + + virtual void SAL_CALL + acquire() + noexcept override; + + virtual void SAL_CALL + release() + noexcept override; + + // XComponent + virtual void SAL_CALL + dispose() override; + + virtual void SAL_CALL + addEventListener( + const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + + virtual void SAL_CALL + removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + + // XRow + virtual sal_Bool SAL_CALL + wasNull() override + { + if( 0<= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + m_nWasNull = m_aItems[m_nRow]->wasNull(); + else + m_nWasNull = true; + return m_nWasNull; + } + + virtual OUString SAL_CALL + getString( sal_Int32 columnIndex ) override + { + OUString ret; + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + ret = m_aItems[m_nRow]->getString( columnIndex ); + + return ret; + } + + virtual sal_Bool SAL_CALL + getBoolean( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getBoolean( columnIndex ); + else + return false; + } + + virtual sal_Int8 SAL_CALL + getByte( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getByte( columnIndex ); + else + return sal_Int8( 0 ); + } + + virtual sal_Int16 SAL_CALL + getShort( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getShort( columnIndex ); + else + return sal_Int16( 0 ); + } + + virtual sal_Int32 SAL_CALL + getInt( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getInt( columnIndex ); + else + return 0; + } + + virtual sal_Int64 SAL_CALL + getLong( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getLong( columnIndex ); + else + return sal_Int64( 0 ); + } + + virtual float SAL_CALL + getFloat( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getFloat( columnIndex ); + else + return float( 0 ); + } + + virtual double SAL_CALL + getDouble( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getDouble( columnIndex ); + else + return double( 0 ); + } + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL + getBytes( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getBytes( columnIndex ); + else + return css::uno::Sequence< sal_Int8 >(); + } + + virtual css::util::Date SAL_CALL + getDate( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getDate( columnIndex ); + else + return css::util::Date(); + } + + virtual css::util::Time SAL_CALL + getTime( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getTime( columnIndex ); + else + return css::util::Time(); + } + + virtual css::util::DateTime SAL_CALL + getTimestamp( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getTimestamp( columnIndex ); + else + return css::util::DateTime(); + } + + + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getBinaryStream( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getBinaryStream( columnIndex ); + else + return css::uno::Reference< css::io::XInputStream >(); + } + + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getCharacterStream( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getCharacterStream( columnIndex ); + else + return css::uno::Reference< css::io::XInputStream >(); + } + + virtual css::uno::Any SAL_CALL + getObject( sal_Int32 columnIndex, + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getObject( columnIndex,typeMap ); + else + return css::uno::Any(); + } + + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL + getRef( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getRef( columnIndex ); + else + return css::uno::Reference< css::sdbc::XRef >(); + } + + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL + getBlob( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getBlob( columnIndex ); + else + return css::uno::Reference< css::sdbc::XBlob >(); + } + + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL + getClob( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getClob( columnIndex ); + else + return css::uno::Reference< css::sdbc::XClob >(); + } + + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL + getArray( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getArray( columnIndex ); + else + return css::uno::Reference< + css::sdbc::XArray >(); + } + + + // XResultSet + + virtual sal_Bool SAL_CALL + next() override; + + virtual sal_Bool SAL_CALL + isBeforeFirst() override; + + virtual sal_Bool SAL_CALL + isAfterLast() override; + + virtual sal_Bool SAL_CALL + isFirst() override; + + virtual sal_Bool SAL_CALL + isLast() override; + + virtual void SAL_CALL + beforeFirst() override; + + virtual void SAL_CALL + afterLast() override; + + virtual sal_Bool SAL_CALL + first() override; + + virtual sal_Bool SAL_CALL + last() override; + + virtual sal_Int32 SAL_CALL + getRow() override; + + virtual sal_Bool SAL_CALL + absolute( + sal_Int32 row ) override; + + virtual sal_Bool SAL_CALL + relative( + sal_Int32 rows ) override; + + virtual sal_Bool SAL_CALL + previous() override; + + virtual void SAL_CALL + refreshRow() override; + + virtual sal_Bool SAL_CALL + rowUpdated() override; + + virtual sal_Bool SAL_CALL + rowInserted() override; + + virtual sal_Bool SAL_CALL + rowDeleted() override; + + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + getStatement() override; + + // XCloseable + + virtual void SAL_CALL + close() override; + + // XContentAccess + + virtual OUString SAL_CALL + queryContentIdentifierString() override; + + virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL + queryContentIdentifier() override; + + virtual css::uno::Reference< css::ucb::XContent > SAL_CALL + queryContent() override; + + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL + getMetaData() override; + + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + virtual void SAL_CALL setPropertyValue( + const OUString& aPropertyName, + const css::uno::Any& aValue ) override; + + virtual css::uno::Any SAL_CALL + getPropertyValue( + const OUString& PropertyName ) override; + + virtual void SAL_CALL + addPropertyChangeListener( + const OUString& aPropertyName, + const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + + virtual void SAL_CALL + removePropertyChangeListener( + const OUString& aPropertyName, + const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + + virtual void SAL_CALL + addVetoableChangeListener( + const OUString& PropertyName, + const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + virtual void SAL_CALL removeVetoableChangeListener( + const OUString& PropertyName, + const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + protected: + + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + css::uno::Reference< css::ucb::XContentProvider > + m_xProvider; + sal_Int32 m_nRow; + bool m_nWasNull; + + typedef std::vector< css::uno::Reference<css::ucb::XContentIdentifier > > + IdentSet; + typedef std::vector< css::uno::Reference< css::sdbc::XRow > > + ItemSet; + + IdentSet m_aIdents; + ItemSet m_aItems; + std::vector<OUString> m_aPath; + + css::uno::Sequence< css::beans::Property > + m_sProperty; + + osl::Mutex m_aMutex; + std::unique_ptr<comphelper::OInterfaceContainerHelper3<css::lang::XEventListener>> m_pDisposeEventListeners; + std::unique_ptr<comphelper::OInterfaceContainerHelper3<css::beans::XPropertyChangeListener>> m_pRowCountListeners; + std::unique_ptr<comphelper::OInterfaceContainerHelper3<css::beans::XPropertyChangeListener>> m_pIsFinalListeners; + }; + + +} // end namespace fileaccess + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpresultsetfactory.hxx b/ucb/source/ucp/ftp/ftpresultsetfactory.hxx new file mode 100644 index 000000000..d521c570d --- /dev/null +++ b/ucb/source/ucp/ftp/ftpresultsetfactory.hxx @@ -0,0 +1,57 @@ +/* -*- 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 + ************************************************************************** + + *************************************************************************/ +#pragma once + +#include "ftpresultsetbase.hxx" +#include "ftpdirp.hxx" +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <rtl/ref.hxx> +#include <vector> + +namespace ftp { + +class ResultSetBase; + +class ResultSetFactory +{ +public: + ResultSetFactory(const css::uno::Reference<css::uno::XComponentContext >& rxContext, + const css::uno::Reference<css::ucb::XContentProvider >& xProvider, + const css::uno::Sequence<css::beans::Property>& seq, + std::vector<FTPDirentry>&& dirvec); + + rtl::Reference<ResultSetBase> createResultSet(); +private: + css::uno::Reference< css::uno::XComponentContext > m_xContext; + css::uno::Reference< css::ucb::XContentProvider > m_xProvider; + css::uno::Sequence< css::beans::Property > m_seq; + std::vector<FTPDirentry> m_dirvec; +}; + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpurl.cxx b/ucb/source/ucp/ftp/ftpurl.cxx new file mode 100644 index 000000000..13b7e839c --- /dev/null +++ b/ucb/source/ucp/ftp/ftpurl.cxx @@ -0,0 +1,804 @@ +/* -*- 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 <sal/config.h> +#include <sal/log.hxx> + +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <string.h> +#include <rtl/uri.hxx> +#include <o3tl/safeint.hxx> + +#include "ftpurl.hxx" +#include "ftpcontentprovider.hxx" +#include "ftpcfunc.hxx" +#include "ftpcontainer.hxx" +#include <memory> + +using namespace ftp; +using namespace com::sun::star::ucb; +using namespace com::sun::star::uno; + +namespace { + +OUString encodePathSegment(OUString const & decoded) { + return rtl::Uri::encode( + decoded, rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8); +} + +OUString decodePathSegment(OUString const & encoded) { + return rtl::Uri::decode( + encoded, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8); +} + +} + +MemoryContainer::MemoryContainer() + : m_nLen(0), + m_nWritePos(0), + m_pBuffer(nullptr) +{ +} + +MemoryContainer::~MemoryContainer() +{ + std::free(m_pBuffer); +} + + +int MemoryContainer::append( + const void* pBuffer, + size_t size, + size_t nmemb +) noexcept +{ + sal_uInt32 nLen = size*nmemb; + sal_uInt32 tmp(nLen + m_nWritePos); + + if(m_nLen < tmp) { // enlarge in steps of multiples of 1K + do { + m_nLen+=1024; + } while(m_nLen < tmp); + + if (auto p = std::realloc(m_pBuffer, m_nLen)) + m_pBuffer = p; + else + return 0; + } + + memcpy(static_cast<sal_Int8*>(m_pBuffer)+m_nWritePos, + pBuffer,nLen); + m_nWritePos = tmp; + return nLen; +} + + +extern "C" { + + int memory_write(void *buffer,size_t size,size_t nmemb,void *stream) + { + MemoryContainer *_stream = + static_cast<MemoryContainer*>(stream); + + if(!_stream) + return 0; + + return _stream->append(buffer,size,nmemb); + } + +} + + +FTPURL::FTPURL(const FTPURL& r) + : m_pFCP(r.m_pFCP), + m_aUsername(r.m_aUsername), + m_bShowPassword(r.m_bShowPassword), + m_aHost(r.m_aHost), + m_aPort(r.m_aPort), + m_aPathSegmentVec(r.m_aPathSegmentVec) + +{ +} + + +FTPURL::FTPURL(const OUString& url, + FTPContentProvider* pFCP) + : m_pFCP(pFCP), + m_aUsername("anonymous"), + m_bShowPassword(false), + m_aPort("21") +{ + parse(url); // can reset m_bShowPassword +} + + +FTPURL::~FTPURL() +{ +} + + +void FTPURL::parse(const OUString& url) +{ + OUString aPassword, urlRest; + + if(url.getLength() < 6 || !url.startsWithIgnoreAsciiCase("ftp://", &urlRest)) + throw malformed_exception(); + + // determine "username:password@host:port" + OUString aExpr; + sal_Int32 nIdx = urlRest.indexOf('/'); + if (nIdx == -1) + { + aExpr = urlRest; + urlRest = ""; + } + else + { + aExpr = urlRest.copy(0, nIdx); + urlRest = urlRest.copy(nIdx + 1); + } + + sal_Int32 l = aExpr.indexOf('@'); + m_aHost = aExpr.copy(1+l); + + if(l != -1) { + // Now username and password. + aExpr = aExpr.copy(0,l); + l = aExpr.indexOf(':'); + if(l != -1) { + aPassword = aExpr.copy(1+l); + if(!aPassword.isEmpty()) + m_bShowPassword = true; + } + if(l > 0) + // Overwritten only if the username is not empty. + m_aUsername = aExpr.copy(0,l); + else if(!aExpr.isEmpty()) + m_aUsername = aExpr; + } + + l = m_aHost.lastIndexOf(':'); + sal_Int32 ipv6Back = m_aHost.lastIndexOf(']'); + if((ipv6Back == -1 && l != -1) // not ipv6, but a port + || + (ipv6Back != -1 && 1+ipv6Back == l) // ipv6, and a port + ) + { + if(1+l<m_aHost.getLength()) + m_aPort = m_aHost.copy(1+l); + m_aHost = m_aHost.copy(0,l); + } + + // now determine the pathsegments ... + while(!urlRest.isEmpty()) + { + nIdx = urlRest.indexOf('/'); + OUString segment; + if(nIdx == -1) + { + segment = urlRest; + urlRest = ""; + } + else + { + segment = urlRest.copy(0, nIdx); + urlRest = urlRest.copy(nIdx + 1); + } + if( segment == ".." && !m_aPathSegmentVec.empty() && m_aPathSegmentVec.back() != ".." ) + m_aPathSegmentVec.pop_back(); + else if( segment == "." ) + ; // Ignore + else + // This is a legal name. + m_aPathSegmentVec.push_back( segment ); + } + + if(m_bShowPassword) + m_pFCP->setHost(m_aHost, + m_aPort, + m_aUsername, + aPassword, + ""/*aAccount*/); + + // now check for something like ";type=i" at end of url + if(!m_aPathSegmentVec.empty()) + { + l = m_aPathSegmentVec.back().indexOf(';'); + if (l != -1) + { + m_aType = m_aPathSegmentVec.back().copy(l); + m_aPathSegmentVec.back() = m_aPathSegmentVec.back().copy(0,l); + } + } +} + + +OUString FTPURL::ident(bool withslash,bool internal) const +{ + // rebuild the url as one without ellipses, + // and more important, as one without username and + // password. ( These are set together with the command. ) + + OUStringBuffer bff; + bff.append("ftp://"); + + if( m_aUsername != "anonymous" ) { + bff.append(m_aUsername); + + OUString aPassword,aAccount; + m_pFCP->forHost(m_aHost, + m_aPort, + m_aUsername, + aPassword, + aAccount); + + if((m_bShowPassword || internal) && + !aPassword.isEmpty() ) + bff.append(':') + .append(aPassword); + + bff.append('@'); + } + bff.append(m_aHost); + + if( m_aPort != "21" ) + bff.append(':') + .append(m_aPort) + .append('/'); + else + bff.append('/'); + + for(size_t i = 0; i < m_aPathSegmentVec.size(); ++i) + if(i == 0) + bff.append(m_aPathSegmentVec[i]); + else + bff.append('/').append(m_aPathSegmentVec[i]); + if(withslash) + if(!bff.isEmpty() && bff[bff.getLength()-1] != '/') + bff.append('/'); + + bff.append(m_aType); + return bff.makeStringAndClear(); +} + + +OUString FTPURL::parent(bool internal) const +{ + OUStringBuffer bff; + + bff.append("ftp://"); + + if( m_aUsername != "anonymous" ) { + bff.append(m_aUsername); + + OUString aPassword,aAccount; + m_pFCP->forHost(m_aHost, + m_aPort, + m_aUsername, + aPassword, + aAccount); + + if((internal || m_bShowPassword) && !aPassword.isEmpty()) + bff.append(':') + .append(aPassword); + + bff.append('@'); + } + + bff.append(m_aHost); + + if( m_aPort != "21" ) + bff.append(':') + .append(m_aPort) + .append('/'); + else + bff.append('/'); + + OUString last; + + for(size_t i = 0; i < m_aPathSegmentVec.size(); ++i) + if(1+i == m_aPathSegmentVec.size()) + last = m_aPathSegmentVec[i]; + else if(i == 0) + bff.append(m_aPathSegmentVec[i]); + else + bff.append('/').append(m_aPathSegmentVec[i]); + + if(last.isEmpty()) + bff.append(".."); + else if ( last == ".." ) + bff.append(last + "/.."); + + bff.append(m_aType); + return bff.makeStringAndClear(); +} + + +void FTPURL::child(const OUString& title) +{ + m_aPathSegmentVec.push_back(encodePathSegment(title)); +} + + +OUString FTPURL::child() const +{ + return + !m_aPathSegmentVec.empty() ? + decodePathSegment(m_aPathSegmentVec.back()) : OUString(); +} + + +/** Listing of a directory. + */ + +namespace ftp { + + namespace { + + enum OS { + FTP_DOS,FTP_UNIX,FTP_VMS,FTP_UNKNOWN + }; + + } + +} + + +#define SET_CONTROL_CONTAINER \ + MemoryContainer control; \ + (void)curl_easy_setopt(curl, \ + CURLOPT_HEADERFUNCTION, \ + memory_write); \ + (void)curl_easy_setopt(curl, \ + CURLOPT_WRITEHEADER, \ + &control) + + +static void setCurlUrl(CURL* curl, OUString const & url) +{ + OString urlParAscii(url.getStr(), + url.getLength(), + RTL_TEXTENCODING_UTF8); + (void)curl_easy_setopt(curl, + CURLOPT_URL, + urlParAscii.getStr()); +}; + +oslFileHandle FTPURL::open() +{ + if(m_aPathSegmentVec.empty()) + throw curl_exception(CURLE_FTP_COULDNT_RETR_FILE); + + CURL *curl = m_pFCP->handle(); + + SET_CONTROL_CONTAINER; + OUString url(ident(false,true)); + setCurlUrl(curl, url); + + oslFileHandle res( nullptr ); + if ( osl_createTempFile( nullptr, &res, nullptr ) == osl_File_E_None ) + { + (void)curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,file_write); + (void)curl_easy_setopt(curl,CURLOPT_WRITEDATA,res); + + (void)curl_easy_setopt(curl,CURLOPT_POSTQUOTE,0); + CURLcode err = curl_easy_perform(curl); + + if(err == CURLE_OK) + { + oslFileError rc = osl_setFilePos( res, osl_Pos_Absolut, 0 ); + SAL_WARN_IF(rc != osl_File_E_None, "ucb.ucp.ftp", + "osl_setFilePos failed"); + } + else { + osl_closeFile(res); + res = nullptr; + throw curl_exception(err); + } + } + + return res; +} + + +std::vector<FTPDirentry> FTPURL::list( + sal_Int16 nMode +) const +{ + CURL *curl = m_pFCP->handle(); + + SET_CONTROL_CONTAINER; + (void)curl_easy_setopt(curl,CURLOPT_NOBODY,false); + MemoryContainer data; + (void)curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,memory_write); + (void)curl_easy_setopt(curl,CURLOPT_WRITEDATA,&data); + + OUString url(ident(true,true)); + setCurlUrl(curl, url); + (void)curl_easy_setopt(curl,CURLOPT_POSTQUOTE,0); + + CURLcode err = curl_easy_perform(curl); + if(err != CURLE_OK) + throw curl_exception(err); + + // now evaluate the error messages + + sal_uInt32 len = data.m_nWritePos; + char* fwd = static_cast<char*>(data.m_pBuffer); + char *p1, *p2; + p1 = p2 = fwd; + + OS osKind(FTP_UNKNOWN); + std::vector<FTPDirentry> resvec; + FTPDirentry aDirEntry; + // ensure slash at the end + OUString viewurl(ident(true,false)); + + while(true) { + while(o3tl::make_unsigned(p2-fwd) < len && *p2 != '\n') ++p2; + if(o3tl::make_unsigned(p2-fwd) == len) break; + + *p2 = 0; + switch(osKind) { + // While FTP knows the 'system'-command, + // which returns the operating system type, + // this is not usable here: There are Windows-server + // formatting the output like UNIX-ls command. + case FTP_DOS: + FTPDirectoryParser::parseDOS(aDirEntry,p1); + break; + case FTP_UNIX: + FTPDirectoryParser::parseUNIX(aDirEntry,p1); + break; + case FTP_VMS: + FTPDirectoryParser::parseVMS(aDirEntry,p1); + break; + default: + if(FTPDirectoryParser::parseUNIX(aDirEntry,p1)) + osKind = FTP_UNIX; + else if(FTPDirectoryParser::parseDOS(aDirEntry,p1)) + osKind = FTP_DOS; + else if(FTPDirectoryParser::parseVMS(aDirEntry,p1)) + osKind = FTP_VMS; + } + aDirEntry.m_aName = aDirEntry.m_aName.trim(); + if( osKind != int(FTP_UNKNOWN) && aDirEntry.m_aName != ".." && aDirEntry.m_aName != "." ) { + aDirEntry.m_aURL = viewurl + encodePathSegment(aDirEntry.m_aName); + + bool isDir = (aDirEntry.m_nMode & INETCOREFTP_FILEMODE_ISDIR) == INETCOREFTP_FILEMODE_ISDIR; + switch(nMode) { + case OpenMode::DOCUMENTS: + if(!isDir) + resvec.push_back(aDirEntry); + break; + case OpenMode::FOLDERS: + if(isDir) + resvec.push_back(aDirEntry); + break; + default: + resvec.push_back(aDirEntry); + }; + } + aDirEntry.clear(); + p1 = p2 + 1; + } + + return resvec; +} + + +OUString FTPURL::net_title() const +{ + CURL *curl = m_pFCP->handle(); + + SET_CONTROL_CONTAINER; + (void)curl_easy_setopt(curl,CURLOPT_NOBODY,true); // no data => no transfer + struct curl_slist *slist = nullptr; + // post request + slist = curl_slist_append(slist,"PWD"); + (void)curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist); + + bool try_more(true); + CURLcode err; + OUString aNetTitle; + + while(true) { + OUString url(ident(false,true)); + + if(try_more && !url.endsWith("/")) + url += "/"; // add end-slash + else if(!try_more && url.endsWith("/")) + url = url.copy(0,url.getLength()-1); // remove end-slash + + setCurlUrl(curl, url); + err = curl_easy_perform(curl); + + if(err == CURLE_OK) { // get the title from the server + char* fwd = static_cast<char*>(control.m_pBuffer); + sal_uInt32 len = control.m_nWritePos; + + aNetTitle = OUString(fwd,len,RTL_TEXTENCODING_UTF8); + // the buffer now contains the name of the file; + // analyze the output: + // Format of current working directory: + // 257 "/bla/bla" is current directory + sal_Int32 index1 = aNetTitle.lastIndexOf("257"); + index1 = aNetTitle.indexOf('"', index1 + std::strlen("257")) + 1; + sal_Int32 index2 = aNetTitle.indexOf('"', index1); + aNetTitle = index2 > index1 + ? aNetTitle.copy(index1, index2 - index1) : OUString(); + if( aNetTitle != "/" ) { + index1 = aNetTitle.lastIndexOf('/'); + aNetTitle = aNetTitle.copy(1+index1); + } + try_more = false; + } else if(err == CURLE_BAD_PASSWORD_ENTERED) + // the client should retry after getting the correct + // username + password + throw curl_exception(err); +#if LIBCURL_VERSION_NUM>=0x070d01 /* 7.13.1 */ + else if(err == CURLE_LOGIN_DENIED) + // the client should retry after getting the correct + // username + password + throw curl_exception(err); +#endif + else if(try_more && err == CURLE_FTP_ACCESS_DENIED) { + // We were either denied access when trying to login to + // an FTP server or when trying to change working directory + // to the one given in the URL. + if(!m_aPathSegmentVec.empty()) + // determine title from URL + aNetTitle = decodePathSegment(m_aPathSegmentVec.back()); + else + // must be root + aNetTitle = "/"; + try_more = false; + } + + if(try_more) + try_more = false; + else + break; + } + + curl_slist_free_all(slist); + return aNetTitle; +} + + +FTPDirentry FTPURL::direntry() const +{ + OUString nettitle = net_title(); + FTPDirentry aDirentry; + + aDirentry.m_aName = nettitle; // init aDirentry + if( nettitle == "/" || nettitle == ".." ) + aDirentry.m_nMode = INETCOREFTP_FILEMODE_ISDIR; + else + aDirentry.m_nMode = INETCOREFTP_FILEMODE_UNKNOWN; + + aDirentry.m_nSize = 0; + + if( nettitle != "/" ) { + // try to open the parent directory + FTPURL aURL(parent(),m_pFCP); + + std::vector<FTPDirentry> aList = aURL.list(OpenMode::ALL); + + for(const FTPDirentry & d : aList) { + if(d.m_aName == nettitle) { // the relevant file is found + aDirentry = d; + break; + } + } + } + return aDirentry; +} + + +extern "C" { + + static size_t memory_read(void *ptr,size_t size,size_t nmemb,void *stream) + { + sal_Int32 nRequested = sal_Int32(size*nmemb); + CurlInput *curlInput = static_cast<CurlInput*>(stream); + if(curlInput) + return size_t(curlInput->read(static_cast<sal_Int8*>(ptr),nRequested)); + else + return 0; + } + +} + + +void FTPURL::insert(bool replaceExisting,void* stream) const +{ + if(!replaceExisting) { +// FTPDirentry aDirentry(direntry()); +// if(aDirentry.m_nMode == INETCOREFTP_FILEMODE_UNKNOWN) + // throw curl_exception(FILE_EXIST_DURING_INSERT); + throw curl_exception(FILE_MIGHT_EXIST_DURING_INSERT); + } // else + // overwrite is default in libcurl + + CURL *curl = m_pFCP->handle(); + + SET_CONTROL_CONTAINER; + (void)curl_easy_setopt(curl,CURLOPT_NOBODY,false); // no data => no transfer + (void)curl_easy_setopt(curl,CURLOPT_POSTQUOTE,0); + (void)curl_easy_setopt(curl,CURLOPT_QUOTE,0); + (void)curl_easy_setopt(curl,CURLOPT_READFUNCTION,memory_read); + (void)curl_easy_setopt(curl,CURLOPT_READDATA,stream); + (void)curl_easy_setopt(curl, CURLOPT_UPLOAD,1); + + OUString url(ident(false,true)); + setCurlUrl(curl, url); + + CURLcode err = curl_easy_perform(curl); + (void)curl_easy_setopt(curl, CURLOPT_UPLOAD,false); + + if(err != CURLE_OK) + throw curl_exception(err); +} + + +void FTPURL::mkdir(bool ReplaceExisting) const +{ + OString title; + if(!m_aPathSegmentVec.empty()) { + OUString titleOU = m_aPathSegmentVec.back(); + titleOU = decodePathSegment(titleOU); + title = OString(titleOU.getStr(), + titleOU.getLength(), + RTL_TEXTENCODING_UTF8); + } + else + // will give an error + title = OString("/"); + + OString aDel = "del " + title; + OString mkd = "mkd " + title; + + struct curl_slist *slist = nullptr; + + FTPDirentry aDirentry(direntry()); + if(!ReplaceExisting) { +// if(aDirentry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN) +// throw curl_exception(FOLDER_EXIST_DURING_INSERT); + throw curl_exception(FOLDER_MIGHT_EXIST_DURING_INSERT); + } else if(aDirentry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN) + slist = curl_slist_append(slist,aDel.getStr()); + + slist = curl_slist_append(slist,mkd.getStr()); + + CURL *curl = m_pFCP->handle(); + SET_CONTROL_CONTAINER; + (void)curl_easy_setopt(curl,CURLOPT_NOBODY,true); // no data => no transfer + (void)curl_easy_setopt(curl,CURLOPT_QUOTE,0); + + // post request + (void)curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist); + + OUString url(parent(true)); + if(!url.endsWith("/")) + url += "/"; + setCurlUrl(curl, url); + + CURLcode err = curl_easy_perform(curl); + curl_slist_free_all(slist); + if(err != CURLE_OK) + throw curl_exception(err); +} + + +OUString FTPURL::ren(const OUString& NewTitle) +{ + CURL *curl = m_pFCP->handle(); + + // post request + OUString OldTitle = net_title(); + OString renamefrom = "RNFR " + + OString(OldTitle.getStr(), + OldTitle.getLength(), + RTL_TEXTENCODING_UTF8); + + OString renameto = "RNTO " + + OString(NewTitle.getStr(), + NewTitle.getLength(), + RTL_TEXTENCODING_UTF8); + + struct curl_slist *slist = nullptr; + slist = curl_slist_append(slist,renamefrom.getStr()); + slist = curl_slist_append(slist,renameto.getStr()); + (void)curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist); + + SET_CONTROL_CONTAINER; + (void)curl_easy_setopt(curl,CURLOPT_NOBODY,true); // no data => no transfer + (void)curl_easy_setopt(curl,CURLOPT_QUOTE,0); + + OUString url(parent(true)); + if(!url.endsWith("/")) + url += "/"; + setCurlUrl(curl, url); + + CURLcode err = curl_easy_perform(curl); + curl_slist_free_all(slist); + if(err != CURLE_OK) + throw curl_exception(err); + else if( !m_aPathSegmentVec.empty() && m_aPathSegmentVec.back() != ".." ) + m_aPathSegmentVec.back() = encodePathSegment(NewTitle); + return OldTitle; +} + + +void FTPURL::del() const +{ + FTPDirentry aDirentry(direntry()); + + OString dele(aDirentry.m_aName.getStr(), + aDirentry.m_aName.getLength(), + RTL_TEXTENCODING_UTF8); + + if(aDirentry.m_nMode & INETCOREFTP_FILEMODE_ISDIR) { + std::vector<FTPDirentry> vec = list(sal_Int16(OpenMode::ALL)); + for(const FTPDirentry & i : vec) + { + try { + FTPURL url(i.m_aURL,m_pFCP); + url.del(); + } catch(const curl_exception&) { + } + } + dele = "RMD " + dele; + } + else if(aDirentry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN) + dele = "DELE " + dele; + else + return; + + // post request + CURL *curl = m_pFCP->handle(); + struct curl_slist *slist = nullptr; + slist = curl_slist_append(slist,dele.getStr()); + (void)curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist); + + SET_CONTROL_CONTAINER; + (void)curl_easy_setopt(curl,CURLOPT_NOBODY,true); // no data => no transfer + (void)curl_easy_setopt(curl,CURLOPT_QUOTE,0); + + OUString url(parent(true)); + if(!url.endsWith("/")) + url += "/"; + setCurlUrl(curl, url); + + CURLcode err = curl_easy_perform(curl); + curl_slist_free_all(slist); + if(err != CURLE_OK) + throw curl_exception(err); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ftpurl.hxx b/ucb/source/ucp/ftp/ftpurl.hxx new file mode 100644 index 000000000..b64eb6ecf --- /dev/null +++ b/ucb/source/ucp/ftp/ftpurl.hxx @@ -0,0 +1,161 @@ +/* -*- 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 + ************************************************************************** + + *************************************************************************/ + +#pragma once + +#include "curl.hxx" + +#include <rtl/ustring.hxx> +#include <osl/file.h> +#include <vector> + +#include "ftpdirp.hxx" + +namespace ftp { + + /** Forward declarations. + */ + + class FTPContentProvider; + + + enum FTPErrors { FOLDER_MIGHT_EXIST_DURING_INSERT = CURL_LAST, + FILE_MIGHT_EXIST_DURING_INSERT }; + + class malformed_exception : public std::exception { }; + + class curl_exception : public std::exception + { + public: + + explicit curl_exception(sal_Int32 err) + : n_err(err) { } + + sal_Int32 code() const { return n_err; } + + + private: + + sal_Int32 n_err; + }; + + class CurlInput { + public: + // returns the number of bytes actually read + virtual sal_Int32 read(sal_Int8 *dest,sal_Int32 nBytesRequested) = 0; + + protected: + ~CurlInput() {} + }; + + + class FTPURL + { + public: + /// @throws malformed_exception + FTPURL( + const OUString& aIdent, + FTPContentProvider* pFCP + ); + + FTPURL(const FTPURL& r); + + ~FTPURL(); + + const OUString& host() const { return m_aHost; } + + const OUString& port() const { return m_aPort; } + + const OUString& username() const { return m_aUsername; } + + /** This returns the URL, but cleaned from + * unnecessary ellipses. + */ + + OUString ident(bool withslash,bool internal) const; + + /** returns the parent url. + */ + + OUString parent(bool internal = false) const; + + /** sets the unencoded title */ + void child(const OUString& title); + + /** returns the unencoded title */ + OUString child() const; + + /// @throws curl_exception + std::vector<FTPDirentry> list(sal_Int16 nMode) const; + + // returns a pointer to an open tempfile, + // sought to the beginning of. + /// @throws curl_exception + oslFileHandle open(); + + /// @throws curl_exception + /// @throws malformed_exception + FTPDirentry direntry() const; + + /// @throws curl_exception + void insert(bool ReplaceExisting,void* stream) const; + + /// @throws curl_exception + /// @throws malformed_exception + void mkdir(bool ReplaceExisting) const; + + /// @throws curl_exception + OUString ren(const OUString& NewTitle); + + /// @throws curl_exception + /// @throws malformed_exception + void del() const; + + + private: + + FTPContentProvider *m_pFCP; + + mutable OUString m_aUsername; + bool m_bShowPassword; + mutable OUString m_aHost; + mutable OUString m_aPort; + mutable OUString m_aType; + + /** Contains the encoded pathsegments of the url. + */ + std::vector<OUString> m_aPathSegmentVec; + + /// @throws malformed_exception + void parse(const OUString& url); + + /// @throws curl_exception + OUString net_title() const; + }; + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/ftp/ucpftp1.component b/ucb/source/ucp/ftp/ucpftp1.component new file mode 100644 index 000000000..e71a0837d --- /dev/null +++ b/ucb/source/ucp/ftp/ucpftp1.component @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.FTPContentProvider" + constructor="ucb_ftp_FTPContentProvider_get_implementation" single-instance="true"> + <service name="com.sun.star.ucb.FTPContentProvider"/> + </implementation> +</component> |