diff options
Diffstat (limited to 'kioslave/ftp/ftp.h')
-rw-r--r-- | kioslave/ftp/ftp.h | 598 |
1 files changed, 598 insertions, 0 deletions
diff --git a/kioslave/ftp/ftp.h b/kioslave/ftp/ftp.h new file mode 100644 index 000000000..e754152d2 --- /dev/null +++ b/kioslave/ftp/ftp.h @@ -0,0 +1,598 @@ +// -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- +/* This file is part of the KDE libraries + Copyright (C) 2000 David Faure <faure@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +// $Id$ + +#ifndef __ftp_h__ +#define __ftp_h__ + +#include <config.h> + +#include <sys/types.h> +#include <sys/socket.h> + +#include <qcstring.h> +#include <qstring.h> + +#include <kurl.h> +#include <kio/slavebase.h> +#include <kextsock.h> +#include <ksocks.h> + +struct FtpEntry +{ + QString name; + QString owner; + QString group; + QString link; + + KIO::filesize_t size; + mode_t type; + mode_t access; + time_t date; +}; + +//=============================================================================== +// FtpTextReader A helper class to read text lines from a socket +//=============================================================================== + +#ifdef KIO_FTP_PRIVATE_INCLUDE +class FtpSocket; + +class FtpTextReader +{ +public: + FtpTextReader() { textClear(); } + +/** + * Resets the status of the object, also called from xtor + */ + void textClear(); + +/** + * Read a line from the socket into m_szText. Only the first RESP_READ_LIMIT + * characters are copied. If the server response is longer all extra data up to + * the new-line gets discarded. An ending CR gets stripped. The number of chars + * in the buffer is returned. Use textToLong() to check for truncation! + */ + int textRead(FtpSocket *pSock); + +/** + * An accessor to the data read by textRead() + */ + const char* textLine() const { return m_szText; } + +/** + * Returns true if the last textRead() resulted in a truncated line + */ + bool textTooLong() const { return m_bTextTruncated; } + +/** + * Returns true if the last textRead() got an EOF or an error + */ + bool textEOF() const { return m_bTextEOF; } + + enum { + + /** + * This is the physical size of m_szText. Only up to textReadLimit + * characters are used to store a server reply. If the server reply + * is longer, the stored line gets truncated - see textTooLong()! + */ + textReadBuffer = 2048, + +/** + * Max number of chars returned from textLine(). If the server + * sends more all chars until the next new-line are discarded. + */ + textReadLimit = 1024 + }; + +private: + /** + * textRead() sets this true on trucation (e.g. line too long) + */ + bool m_bTextTruncated; + + /** + * textRead() sets this true if the read returns 0 bytes or error + */ + bool m_bTextEOF; + + /** + * textRead() fills this buffer with data + */ + char m_szText[textReadBuffer]; + + /** + * the number of bytes in the current response line + */ + int m_iTextLine; + + /** + * the number of bytes in the response buffer (includes m_iRespLine) + */ + int m_iTextBuff; +}; +#endif // KIO_FTP_PRIVATE_INCLUDE + +//=============================================================================== +// FtpSocket Helper Class for Data or Control Connections +//=============================================================================== +#ifdef KIO_FTP_PRIVATE_INCLUDE +class FtpSocket : public FtpTextReader, public KExtendedSocket +{ +private: + // hide the default xtor + FtpSocket() {} +public: +/** + * The one and only public xtor. The string data passed to the + * xtor must remain valid during the object's lifetime - it is + * used in debug messages to identify the socket instance. + */ + FtpSocket(const char* pszName) + { + m_pszName = pszName; + m_server = -1; + } + + ~FtpSocket() { closeSocket(); } + +/** + * Resets the status of the object, also called from xtor + */ + void closeSocket(); + +/** + * We may have a server connection socket if not in passive mode. This + * routine returns the server socket set by setServer. The sock() + * function will return the server socket - if it is set. + */ + int server() const { return m_server; } + +/** + * Set the server socket if arg >= 0, otherwise clear it. + */ + void setServer(int i) { m_server = (i >= 0) ? i : -1; } + +/** + * returns the effective socket that user used for read/write. See server() + */ + int sock() const { return (m_server != -1) ? m_server : fd(); } + +/** + * output an debug message via kdDebug + */ + void debugMessage(const char* pszMsg) const; + +/** + * output an error message via kdError, returns iErrorCode + */ + int errorMessage(int iErrorCode, const char* pszMsg) const; + +/** + * connect socket and set some options (reuse, keepalive, linger) + */ + int connectSocket(int iTimeOutSec, bool bControl); + +/** + * utility to simplify calls to ::setsockopt(). Uses sock(). + */ + bool setSocketOption(int opt, char*arg, socklen_t len) const; + +/** + * utility to read data from the effective socket, see sock() + */ + long read(void* pData, long iMaxlen) + { + return KSocks::self()->read(sock(), pData, iMaxlen); + } + +/** + * utility to write data to the effective socket, see sock() + */ + long write(void* pData, long iMaxlen) + { + return KSocks::self()->write(sock(), pData, iMaxlen); + } + +/** + * Use the inherited FtpTextReader to read a line from the socket + */ + int textRead() + { + return FtpTextReader::textRead(this); + } + +private: + const char* m_pszName; // set by the xtor, used for debug output + int m_server; // socket override, see setSock() +}; +#else + class FtpSocket; +#endif // KIO_FTP_PRIVATE_INCLUDE + +//=============================================================================== +// Ftp +//=============================================================================== +class Ftp : public KIO::SlaveBase +{ + // Ftp() {} + +public: + Ftp( const QCString &pool, const QCString &app ); + virtual ~Ftp(); + + virtual void setHost( const QString& host, int port, const QString& user, const QString& pass ); + + /** + * Connects to a ftp server and logs us in + * m_bLoggedOn is set to true if logging on was successful. + * It is set to false if the connection becomes closed. + * + */ + virtual void openConnection(); + + /** + * Closes the connection + */ + virtual void closeConnection(); + + virtual void stat( const KURL &url ); + + virtual void listDir( const KURL & url ); + virtual void mkdir( const KURL & url, int permissions ); + virtual void rename( const KURL & src, const KURL & dest, bool overwrite ); + virtual void del( const KURL & url, bool isfile ); + virtual void chmod( const KURL & url, int permissions ); + + virtual void get( const KURL& url ); + virtual void put( const KURL& url, int permissions, bool overwrite, bool resume); + //virtual void mimetype( const KURL& url ); + + virtual void slave_status(); + + /** + * Handles the case that one side of the job is a local file + */ + virtual void copy( const KURL &src, const KURL &dest, int permissions, bool overwrite ); + +private: + // ------------------------------------------------------------------------ + // All the methods named ftpXyz are lowlevel methods that are not exported. + // The implement functionality used by the public high-level methods. Some + // low-level methods still use error() to emit errors. This behaviour is not + // recommended - please return a boolean status or an error code instead! + // ------------------------------------------------------------------------ + + /** + * Status Code returned from ftpPut() and ftpGet(), used to select + * source or destination url for error messages + */ + typedef enum { + statusSuccess, + statusClientError, + statusServerError + } StatusCode; + + /** + * Login Mode for ftpOpenConnection + */ + typedef enum { + loginDefered, + loginExplicit, + loginImplicit + } LoginMode; + + /** + * Connect and login to the FTP server. + * + * @param loginMode controls if login info should be sent<br> + * loginDefered - must not be logged on, no login info is sent<br> + * loginExplicit - must not be logged on, login info is sent<br> + * loginImplicit - login info is sent if not logged on + * + * @return true on success (a login failure would return false). + */ + bool ftpOpenConnection (LoginMode loginMode); + + /** + * Executes any auto login macro's as specified in a .netrc file. + */ + void ftpAutoLoginMacro (); + + /** + * Called by openConnection. It logs us in. + * m_initialPath is set to the current working directory + * if logging on was successful. + * + * @return true on success. + */ + bool ftpLogin(); + + /** + * ftpSendCmd - send a command (@p cmd) and read response + * + * @param maxretries number of time it should retry. Since it recursively + * calls itself if it can't read the answer (this happens especially after + * timeouts), we need to limit the recursiveness ;-) + * + * return true if any response received, false on error + */ + bool ftpSendCmd( const QCString& cmd, int maxretries = 1 ); + + /** + * Use the SIZE command to get the file size. + * @param mode the size depends on the transfer mode, hence this arg. + * @return true on success + * Gets the size into m_size. + */ + bool ftpSize( const QString & path, char mode ); + + /** + * Set the current working directory, but only if not yet current + */ + bool ftpFolder(const QString& path, bool bReportError); + + /** + * Runs a command on the ftp server like "list" or "retr". In contrast to + * ftpSendCmd a data connection is opened. The corresponding socket + * sData is available for reading/writing on success. + * The connection must be closed afterwards with ftpCloseCommand. + * + * @param mode is 'A' or 'I'. 'A' means ASCII transfer, 'I' means binary transfer. + * @param errorcode the command-dependent error code to emit on error + * + * @return true if the command was accepted by the server. + */ + bool ftpOpenCommand( const char *command, const QString & path, char mode, + int errorcode, KIO::fileoffset_t offset = 0 ); + + /** + * The counterpart to openCommand. + * Closes data sockets and then reads line sent by server at + * end of command. + * @return false on error (line doesn't start with '2') + */ + bool ftpCloseCommand(); + + /** + * Send "TYPE I" or "TYPE A" only if required, see m_cDataMode. + * + * Use 'A' to select ASCII and 'I' to select BINARY mode. If + * cMode is '?' the m_bTextMode flag is used to choose a mode. + */ + bool ftpDataMode(char cMode); + + //void ftpAbortTransfer(); + + /** + * Used by ftpOpenCommand, return 0 on success or an error code + */ + int ftpOpenDataConnection(); + + /** + * closes a data connection, see ftpOpenDataConnection() + */ + void ftpCloseDataConnection(); + + /** + * Helper for ftpOpenDataConnection + */ + int ftpOpenPASVDataConnection(); + /** + * Helper for ftpOpenDataConnection + */ + int ftpOpenEPSVDataConnection(); + /** + * Helper for ftpOpenDataConnection + */ + int ftpOpenEPRTDataConnection(); + /** + * Helper for ftpOpenDataConnection + */ + int ftpOpenPortDataConnection(); + + /** + * ftpAcceptConnect - wait for incoming connection + * + * return -2 on error or timeout + * otherwise returns socket descriptor + */ + int ftpAcceptConnect(); + + bool ftpChmod( const QString & path, int permissions ); + + // used by listDir + bool ftpOpenDir( const QString & path ); + /** + * Called to parse directory listings, call this until it returns false + */ + bool ftpReadDir(FtpEntry& ftpEnt); + + /** + * Helper to fill an UDSEntry + */ + void ftpCreateUDSEntry( const QString & filename, FtpEntry& ftpEnt, KIO::UDSEntry& entry, bool isDir ); + + void ftpShortStatAnswer( const QString& filename, bool isDir ); + + void ftpStatAnswerNotFound( const QString & path, const QString & filename ); + + /** + * This is the internal implementation of rename() - set put(). + * + * @return true on success. + */ + bool ftpRename( const QString & src, const QString & dst, bool overwrite ); + + /** + * Called by openConnection. It opens the control connection to the ftp server. + * + * @return true on success. + */ + bool ftpOpenControlConnection( const QString & host, unsigned short int port ); + + /** + * closes the socket holding the control connection (see ftpOpenControlConnection) + */ + void ftpCloseControlConnection(); + + /** + * read a response from the server (a trailing CR gets stripped) + * @param iOffset -1 to read a new line from the server<br> + * 0 to return the whole response string + * >0 to return the response with iOffset chars skipped + * @return the reponse message with iOffset chars skipped (or "" if iOffset points + * behind the available data) + */ + const char* ftpResponse(int iOffset); + + /** + * This is the internal implementation of get() - see copy(). + * + * IMPORTANT: the caller should call ftpCloseCommand() on return. + * The function does not call error(), the caller should do this. + * + * @param iError set to an ERR_xxxx code on error + * @param iCopyFile -1 -or- handle of a local destination file + * @param hCopyOffset local file only: non-zero for resume + * @return 0 for success, -1 for server error, -2 for client error + */ + StatusCode ftpGet(int& iError, int iCopyFile, const KURL& url, KIO::fileoffset_t hCopyOffset); + + /** + * This is the internal implementation of put() - see copy(). + * + * IMPORTANT: the caller should call ftpCloseCommand() on return. + * The function does not call error(), the caller should do this. + * + * @param iError set to an ERR_xxxx code on error + * @param iCopyFile -1 -or- handle of a local source file + * @return 0 for success, -1 for server error, -2 for client error + */ + StatusCode ftpPut(int& iError, int iCopyFile, const KURL& url, int permissions, bool overwrite, bool resume); + + /** + * helper called from copy() to implement FILE -> FTP transfers + * + * @param iError set to an ERR_xxxx code on error + * @param iCopyFile [out] handle of a local source file + * @param sCopyFile path of the local source file + * @return 0 for success, -1 for server error, -2 for client error + */ + StatusCode ftpCopyPut(int& iError, int& iCopyFile, QString sCopyFile, const KURL& url, int permissions, bool overwrite); + + /** + * helper called from copy() to implement FTP -> FILE transfers + * + * @param iError set to an ERR_xxxx code on error + * @param iCopyFile [out] handle of a local source file + * @param sCopyFile path of the local destination file + * @return 0 for success, -1 for server error, -2 for client error + */ + StatusCode ftpCopyGet(int& iError, int& iCopyFile, QString sCopyFile, const KURL& url, int permissions, bool overwrite); + +private: // data members + + QString m_host; + unsigned short int m_port; + QString m_user; + QString m_pass; + /** + * Where we end up after connecting + */ + QString m_initialPath; + KURL m_proxyURL; + + /** + * the current working directory - see ftpFolder + */ + QString m_currentPath; + + /** + * the status returned by the FTP protocol, set in ftpResponse() + */ + int m_iRespCode; + + /** + * the status/100 returned by the FTP protocol, set in ftpResponse() + */ + int m_iRespType; + + /** + * This flag is maintained by ftpDataMode() and contains I or A after + * ftpDataMode() has successfully set the mode. + */ + char m_cDataMode; + + /** + * true if logged on (m_control should also be non-NULL) + */ + bool m_bLoggedOn; + + /** + * true if a "textmode" metadata key was found by ftpLogin(). This + * switches the ftp data transfer mode from binary to ASCII. + */ + bool m_bTextMode; + + /** + * true if a data stream is open, used in closeConnection(). + * + * When the user cancels a get or put command the Ftp dtor will be called, + * which in turn calls closeConnection(). The later would try to send QUIT + * which won't work until timeout. ftpOpenCommand sets the m_bBusy flag so + * that the sockets will be closed immedeately - the server should be + * capable of handling this and return an error code on thru the control + * connection. The m_bBusy gets cleared by the ftpCloseCommand() routine. + */ + bool m_bBusy; + + bool m_bPasv; + bool m_bUseProxy; + + KIO::filesize_t m_size; + static KIO::filesize_t UnknownSize; + + enum + { + epsvUnknown = 0x01, + epsvAllUnknown = 0x02, + eprtUnknown = 0x04, + epsvAllSent = 0x10, + pasvUnknown = 0x20, + chmodUnknown = 0x100 + }; + int m_extControl; + + /** + * control connection socket, only set if openControl() succeeded + */ + FtpSocket *m_control; + + /** + * data connection socket + */ + FtpSocket *m_data; +}; + +#endif |