/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: ftpcontent.cxx,v $ * $Revision: 1.29 $ * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_ucb.hxx" /************************************************************************** TODO ************************************************************************** *************************************************************************/ #include #include "ftpdynresultset.hxx" #include "ftpresultsetfactory.hxx" #include "ftpresultsetI.hxx" #include "ftpcontent.hxx" #include "ftpcontentprovider.hxx" #include "ftpinpstr.hxx" #include "ftpdirp.hxx" #include "ftpcontentidentifier.hxx" #include "ftpcfunc.hxx" #include "ftpstrcont.hxx" #include "ftpintreq.hxx" #include #include #include #include "curl.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include 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< XMultiServiceFactory >& rxSMgr, FTPContentProvider* pProvider, const Reference< XContentIdentifier >& Identifier) : ContentImplHelper(rxSMgr,pProvider,Identifier), m_pFCP(pProvider), m_aFTPURL(Identifier->getContentIdentifier(), pProvider), m_bInserted(false), m_bTitleSet(false) { } FTPContent::FTPContent( const Reference< XMultiServiceFactory >& rxSMgr, FTPContentProvider* pProvider, const Reference< XContentIdentifier >& Identifier, const FTPURL& aFTPURL) : ContentImplHelper(rxSMgr,pProvider,Identifier), m_pFCP(pProvider), m_aFTPURL(aFTPURL), m_bInserted(false), m_bTitleSet(false) { } FTPContent::FTPContent( const Reference< XMultiServiceFactory >& rxSMgr, FTPContentProvider* pProvider, const Reference< XContentIdentifier >& Identifier, const ContentInfo& Info) : ContentImplHelper(rxSMgr,pProvider,Identifier), m_pFCP(pProvider), m_aFTPURL(Identifier->getContentIdentifier(), pProvider), m_bInserted(true), m_bTitleSet(false), m_aInfo(Info) { } //========================================================================= FTPContent::~FTPContent() { } //========================================================================= // // XInterface methods. // //========================================================================= XINTERFACE_IMPL_6( FTPContent, XTypeProvider, XServiceInfo, XContent, XCommandProcessor, XContentCreator, XChild); //========================================================================= // // XTypeProvider methods. // //========================================================================= XTYPEPROVIDER_IMPL_6( FTPContent, XTypeProvider, XServiceInfo, XContent, XCommandProcessor, XContentCreator, XChild); //========================================================================= // // XServiceInfo methods. // //========================================================================= // needed, because the service shall not be creatable!! #undef XSERVICEINFO_CREATE_INSTANCE_IMPL #define XSERVICEINFO_CREATE_INSTANCE_IMPL( Class ) XSERVICEINFO_IMPL_1( FTPContent, rtl::OUString::createFromAscii( "com.sun.star.comp.FTPContent"), rtl::OUString::createFromAscii( "com.sun.star.ucb.FTPContent")); //========================================================================= // // XContent methods. // //========================================================================= // virtual rtl::OUString SAL_CALL FTPContent::getContentType() throw( RuntimeException ) { return rtl::OUString::createFromAscii(FTP_CONTENT_TYPE); } //========================================================================= // // XCommandProcessor methods. // //========================================================================= //virtual void SAL_CALL FTPContent::abort( sal_Int32 /*CommandId*/ ) throw( RuntimeException ) { } /***************************************************************************/ /* */ /* Interne Implklasse */ /* */ /***************************************************************************/ class ResultSetFactoryI : public ResultSetFactory { public: ResultSetFactoryI(const Reference& xSMgr, const Reference& xProvider, sal_Int32 nOpenMode, const Sequence& seq, const Sequence& seqSort, const std::vector& dirvec) : m_xSMgr(xSMgr), m_xProvider(xProvider), m_nOpenMode(nOpenMode), m_seq(seq), m_seqSort(seqSort), m_dirvec(dirvec) { } virtual ResultSetBase* createResultSet() { return new ResultSetI(m_xSMgr, m_xProvider, m_nOpenMode, m_seq, m_seqSort, m_dirvec); } public: Reference< XMultiServiceFactory > m_xSMgr; Reference< XContentProvider > m_xProvider; sal_Int32 m_nOpenMode; Sequence< Property > m_seq; Sequence< NumberedSortingInfo > m_seqSort; std::vector m_dirvec; }; //========================================================================= // // XCommandProcessor methods. // //========================================================================= enum ACTION { NOACTION, THROWAUTHENTICATIONREQUEST, THROWACCESSDENIED, THROWINTERACTIVECONNECT, THROWRESOLVENAME, THROWQUOTE, THROWNOFILE, THROWGENERAL }; // virtual Any SAL_CALL FTPContent::execute( const Command& aCommand, sal_Int32 /*CommandId*/, const Reference< XCommandEnvironment >& Environment ) throw( Exception, CommandAbortedException, RuntimeException ) { ACTION action(NOACTION); Any aRet; while(true) try { if(action == THROWAUTHENTICATIONREQUEST) { // try to get a continuation first rtl::OUString aRealm,aPassword,aAccount; m_pFCP->forHost(m_aFTPURL.host(), m_aFTPURL.port(), m_aFTPURL.username(), aPassword, aAccount); rtl::Reference p( new ucbhelper::SimpleAuthenticationRequest( m_aFTPURL.ident(false, false), m_aFTPURL.host(), // ServerName ucbhelper::SimpleAuthenticationRequest::ENTITY_NA, aRealm, ucbhelper::SimpleAuthenticationRequest ::ENTITY_FIXED, m_aFTPURL.username(), ucbhelper::SimpleAuthenticationRequest ::ENTITY_MODIFY, aPassword)); Reference xInteractionHandler; if(Environment.is()) xInteractionHandler = Environment->getInteractionHandler(); if( xInteractionHandler.is()) { xInteractionHandler->handle(p.get()); Reference xSelection( p->getSelection().get()); if(Reference( xSelection,UNO_QUERY).is()) action = NOACTION; else if(Reference( 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.compareToAscii( // "getPropertyValues") == 0 && // action != NOACTION) { // // It is not allowed to throw if // // command is getPropertyValues // rtl::Reference xRow = // new ucbhelper::PropertyValueSet(m_xSMgr); // Sequence Properties; // aCommand.Argument >>= Properties; // for(int i = 0; i < Properties.getLength(); ++i) // xRow->appendVoid(Properties[i]); // aRet <<= Reference(xRow.get()); // return aRet; // } if(action == THROWAUTHENTICATIONREQUEST) { ucbhelper::cancelCommandExecution( aRet, Reference(0)); } else if(action == THROWACCESSDENIED) { Sequence seq(1); PropertyValue value; value.Name = rtl::OUString::createFromAscii("Uri"); value.Handle = -1; value.Value <<= m_aFTPURL.ident(false,false); value.State = PropertyState_DIRECT_VALUE; seq[0] <<= value; ucbhelper::cancelCommandExecution( IOErrorCode_ACCESS_DENIED, seq, Environment); } else if(action == THROWINTERACTIVECONNECT) { InteractiveNetworkConnectException excep; excep.Server = m_aFTPURL.host(); aRet <<= excep; ucbhelper::cancelCommandExecution( aRet, Environment); } else if(action == THROWRESOLVENAME) { InteractiveNetworkResolveNameException excep; excep.Server = m_aFTPURL.host(); aRet <<= excep; ucbhelper::cancelCommandExecution( aRet, Environment); } else if(action == THROWNOFILE) { Sequence seq(1); PropertyValue value; value.Name = rtl::OUString::createFromAscii("Uri"); value.Handle = -1; value.Value <<= m_aFTPURL.ident(false,false); value.State = PropertyState_DIRECT_VALUE; seq[0] <<= value; ucbhelper::cancelCommandExecution( IOErrorCode_NO_FILE, seq, Environment); } else if(action == THROWQUOTE || action == THROWGENERAL) { ucbhelper::cancelCommandExecution( IOErrorCode_GENERAL, Sequence(0), Environment); } if(aCommand.Name.compareToAscii("getPropertyValues") == 0) { Sequence Properties; if(!(aCommand.Argument >>= Properties)) { aRet <<= IllegalArgumentException(); ucbhelper::cancelCommandExecution(aRet,Environment); } aRet <<= getPropertyValues(Properties,Environment); } else if(aCommand.Name.compareToAscii("setPropertyValues") == 0) { Sequence propertyValues; if( ! ( aCommand.Argument >>= propertyValues ) ) { aRet <<= IllegalArgumentException(); ucbhelper::cancelCommandExecution(aRet,Environment); } aRet <<= setPropertyValues(propertyValues); } else if(aCommand.Name.compareToAscii("getCommandInfo") == 0) { // Note: Implemented by base class. aRet <<= getCommandInfo(Environment); } else if(aCommand.Name.compareToAscii("getPropertySetInfo") == 0) { // Note: Implemented by base class. aRet <<= getPropertySetInfo(Environment); } else if(aCommand.Name.compareToAscii( "insert" ) == 0) { InsertCommandArgument aInsertArgument; if ( ! ( aCommand.Argument >>= aInsertArgument ) ) { aRet <<= IllegalArgumentException(); ucbhelper::cancelCommandExecution(aRet,Environment); } insert(aInsertArgument,Environment); } else if(aCommand.Name.compareToAscii("delete") == 0) { m_aFTPURL.del(); deleted(); } else if(aCommand.Name.compareToAscii( "open" ) == 0) { OpenCommandArgument2 aOpenCommand; if ( !( aCommand.Argument >>= aOpenCommand ) ) { aRet <<= IllegalArgumentException(); ucbhelper::cancelCommandExecution(aRet,Environment); } if(aOpenCommand.Mode == OpenMode::DOCUMENT) { // Open as a document Reference xActiveDataSink(aOpenCommand.Sink,UNO_QUERY); Reference< XOutputStream > xOutputStream(aOpenCommand.Sink,UNO_QUERY); if(xActiveDataSink.is()) { xActiveDataSink->setInputStream( new FTPInputStream(m_aFTPURL.open())); } else if(xOutputStream.is()) { Reference xStream( new FTPInputStream(m_aFTPURL.open())); Sequence byte_seq(4096); sal_Int32 n = 1000; // value does not matter here for (;;) { 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&) { } } if(n) { Sequence seq(1); PropertyValue value; value.Name = rtl::OUString::createFromAscii("Uri"); value.Handle = -1; value.Value <<= m_aFTPURL.ident(false,false); value.State = PropertyState_DIRECT_VALUE; seq[0] <<= value; ucbhelper::cancelCommandExecution( IOErrorCode_UNKNOWN, seq, Environment); } } else { aRet <<= UnsupportedDataSinkException(); ucbhelper::cancelCommandExecution(aRet,Environment); } } else if(aOpenCommand.Mode == OpenMode::ALL || aOpenCommand.Mode == OpenMode::DOCUMENTS || aOpenCommand.Mode == OpenMode::FOLDERS ) { std::vector resvec = m_aFTPURL.list(sal_Int16(aOpenCommand.Mode)); Reference< XDynamicResultSet > xSet = new DynamicResultSet( m_xSMgr, this, aOpenCommand, Environment, new ResultSetFactoryI(m_xSMgr, m_xProvider.get(), aOpenCommand.Mode, aOpenCommand.Properties, aOpenCommand.SortingInfo, resvec)); aRet <<= xSet; } else if(aOpenCommand.Mode == OpenMode::DOCUMENT_SHARE_DENY_NONE || aOpenCommand.Mode == OpenMode::DOCUMENT_SHARE_DENY_WRITE) { // Unsupported OpenMode aRet <<= UnsupportedOpenModeException(); ucbhelper::cancelCommandExecution(aRet,Environment); } else { // IllegalArgumentException:: No OpenMode aRet <<= IllegalArgumentException(); ucbhelper::cancelCommandExecution(aRet,Environment); } } else { aRet <<= UnsupportedCommandException(); ucbhelper::cancelCommandExecution(aRet,Environment); } return aRet; } catch(const curl_exception& e) { if(e.code() == CURLE_COULDNT_CONNECT) action = THROWINTERACTIVECONNECT; else if(e.code() == CURLE_COULDNT_RESOLVE_HOST ) action = THROWRESOLVENAME; else if(e.code() == CURLE_FTP_USER_PASSWORD_INCORRECT || 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 course of the error action = THROWGENERAL; } } #define FTP_FILE rtl::OUString::createFromAscii( \ "application/" \ "vnd.sun.staroffice.ftp-file") #define FTP_FOLDER rtl::OUString::createFromAscii( \ "application/" \ "vnd.sun.staroffice.ftp-folder") Sequence SAL_CALL FTPContent::queryCreatableContentsInfo( ) throw (RuntimeException) { Sequence< ContentInfo > seq(2); seq[0].Type = FTP_FILE; seq[0].Attributes = ContentInfoAttribute::INSERT_WITH_INPUTSTREAM | ContentInfoAttribute::KIND_DOCUMENT; Sequence< Property > props( 1 ); props[0] = Property( rtl::OUString::createFromAscii( "Title" ), -1, getCppuType( static_cast< rtl::OUString* >( 0 ) ), PropertyAttribute::MAYBEVOID | PropertyAttribute::BOUND ); seq[0].Properties = props; // folder seq[1].Type = FTP_FOLDER; seq[1].Attributes = ContentInfoAttribute::KIND_FOLDER; seq[1].Properties = props; return seq; } Reference SAL_CALL FTPContent::createNewContent( const ContentInfo& Info ) throw (RuntimeException) { if(Info.Type.equalsAscii("application/" "vnd.sun.staroffice.ftp-file") || Info.Type.equalsAscii("application/" "vnd.sun.staroffice.ftp-folder")) return new FTPContent(m_xSMgr, m_pFCP, m_xIdentifier,Info); else return Reference(0); } Reference SAL_CALL FTPContent::getParent( ) throw (RuntimeException) { Reference xIdent(new FTPContentIdentifier(m_aFTPURL.parent(false))); Reference xContent(m_xProvider->queryContent(xIdent)); return Reference(xContent,UNO_QUERY); } void SAL_CALL FTPContent::setParent(const Reference& /*Parent*/ ) throw (NoSupportException, RuntimeException) { throw NoSupportException(); } rtl::OUString FTPContent::getParentURL() { return m_aFTPURL.parent(); } class InsertData : public CurlInput { public: InsertData(const Reference& xInputStream) : m_xInputStream(xInputStream) { } virtual ~InsertData() {} // returns the number of bytes actually read virtual sal_Int32 read(sal_Int8 *dest,sal_Int32 nBytesRequested); private: Reference m_xInputStream; }; sal_Int32 InsertData::read(sal_Int8 *dest,sal_Int32 nBytesRequested) { sal_Int32 m = 0; if(m_xInputStream.is()) { Sequence seq(nBytesRequested); m = m_xInputStream->readBytes(seq,nBytesRequested); rtl_copyMemory(dest,seq.getConstArray(),m); } return m; } void FTPContent::insert(const InsertCommandArgument& aInsertCommand, const Reference& Env) { osl::MutexGuard aGuard(m_aMutex); if(m_bInserted && !m_bTitleSet) { MissingPropertiesException excep; excep.Properties.realloc(1); excep.Properties[0] = rtl::OUString::createFromAscii("Title"); Any aAny; aAny <<= excep; ucbhelper::cancelCommandExecution(aAny,Env); } if(m_bInserted && m_aInfo.Type == FTP_FILE && !aInsertCommand.Data.is()) { MissingInputStreamException excep; Any aAny; aAny <<= excep; ucbhelper::cancelCommandExecution(aAny,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() == FILE_EXIST_DURING_INSERT || e.code() == FOLDER_EXIST_DURING_INSERT) { // Deprecated, not used anymore: NameClashException excep; excep.Name = m_aFTPURL.child(); Any aAny; aAny <<= excep; ucbhelper::cancelCommandExecution(aAny,Env); } else if(e.code() == FOLDER_MIGHT_EXIST_DURING_INSERT || e.code() == FILE_MIGHT_EXIST_DURING_INSERT) { // Interact Reference xInt; if(Env.is()) xInt = Env->getInteractionHandler(); UnsupportedNameClashException excep; excep.NameClash = 0; //NameClash::ERROR; if(!xInt.is()) { Any aAny; aAny <<= excep; ucbhelper::cancelCommandExecution(aAny,Env); } XInteractionRequestImpl* p = new XInteractionRequestImpl(m_aFTPURL.child()); Reference req(p); xInt->handle(req); if(p->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, const Reference& /*environment*/ ) { rtl::Reference xRow = new ucbhelper::PropertyValueSet(m_xSMgr); FTPDirentry aDirEntry = m_aFTPURL.direntry(); for(sal_Int32 i = 0; i < seqProp.getLength(); ++i) { const rtl::OUString& Name = seqProp[i].Name; if(Name.compareToAscii("Title") == 0) xRow->appendString(seqProp[i],aDirEntry.m_aName); else if(aDirEntry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN) { if(Name.compareToAscii("ContentType") == 0) xRow->appendString(seqProp[i], aDirEntry.m_nMode&INETCOREFTP_FILEMODE_ISDIR ? FTP_FOLDER : FTP_FILE ); else if(Name.compareToAscii("IsReadOnly") == 0) xRow->appendBoolean(seqProp[i], aDirEntry.m_nMode & INETCOREFTP_FILEMODE_WRITE ? 0 : 1 ); else if(Name.compareToAscii("IsDocument") == 0) xRow->appendBoolean(seqProp[i], ! sal_Bool(aDirEntry.m_nMode & INETCOREFTP_FILEMODE_ISDIR)); else if(Name.compareToAscii("IsFolder") == 0) xRow->appendBoolean(seqProp[i], sal_Bool(aDirEntry.m_nMode & INETCOREFTP_FILEMODE_ISDIR)); else if(Name.compareToAscii("Size") == 0) xRow->appendLong(seqProp[i], aDirEntry.m_nSize); else if(Name.compareToAscii("DateCreated") == 0) xRow->appendTimestamp(seqProp[i], aDirEntry.m_aDate); else xRow->appendVoid(seqProp[i]); } else xRow->appendVoid(seqProp[i]); } return Reference(xRow.get()); } Sequence FTPContent::setPropertyValues( const Sequence& seqPropVal) { Sequence props = getProperties(Reference(0)); Sequence ret(seqPropVal.getLength()); Sequence evt; osl::MutexGuard aGuard(m_aMutex); for(sal_Int32 i = 0; i < ret.getLength(); ++i) { if(seqPropVal[i].Name.equalsAscii("Title")) { rtl::OUString Title; if(!(seqPropVal[i].Value >>= Title)) { ret[i] <<= IllegalTypeException(); continue; } else if(!Title.getLength()) { ret[i] <<= IllegalArgumentException(); continue; } if(m_bInserted) { m_aFTPURL.child(Title); m_xIdentifier = new FTPContentIdentifier(m_aFTPURL.ident(false,false)); m_bTitleSet = true; } else try { rtl::OUString OldTitle = m_aFTPURL.ren(Title); evt.realloc(1); evt[0].PropertyName = rtl::OUString::createFromAscii("Title"); evt[0].Further = false; evt[0].PropertyHandle = -1; evt[0].OldValue <<= OldTitle; evt[0].NewValue <<= 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; ret[i] <<= excep; } } else { // either not unknown or illegal ret[i] <<= UnknownPropertyException(); for(sal_Int32 j = 0; j < props.getLength(); ++j) if(props[j].Name == seqPropVal[i].Name) { ret[i] <<= IllegalAccessException(); break; } } } if(evt.getLength()) { // title has changed notifyPropertiesChange(evt); exchange(new FTPContentIdentifier(m_aFTPURL.ident(false,false))); } return ret; }