⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftp.cpp

📁 一个用QT开发的FTP客户端
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; c-file-style: "stroustrup" -*-/*  This file is part of the KDE libraries    Copyright (C) 2000-2006 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.*//*    Recommended reading explaining FTP details and quirks:      http://cr.yp.to/ftp.html  (by D.J. Bernstein)    RFC:      RFC  959 "File Transfer Protocol (FTP)"      RFC 1635 "How to Use Anonymous FTP"      RFC 2428 "FTP Extensions for IPv6 and NATs" (defines EPRT and EPSV)*/#define  KIO_FTP_PRIVATE_INCLUDE#include "ftp.h"#include <sys/stat.h>#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#include <netinet/in.h>#include <arpa/inet.h>#include <assert.h>#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <netdb.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <signal.h>#if TIME_WITH_SYS_TIME#include <time.h>#endif#include <QtCore/QDir>#include <QtNetwork/QHostAddress>#include <QtNetwork/QTcpServer>#include <kdebug.h>#include <kglobal.h>#include <klocale.h>#include <kcomponentdata.h>#include <kmimetype.h>#include <kio/ioslave_defaults.h>#include <kio/slaveconfig.h>#include <kremoteencoding.h>#include <ksocketfactory.h>#include <kde_file.h>#include <kconfiggroup.h>#include <kmessagebox.h>#ifdef HAVE_STRTOLL  #define charToLongLong(a) strtoll(a, 0, 10)#else  #define charToLongLong(a) strtol(a, 0, 10)#endif#define FTP_LOGIN   "anonymous"#define FTP_PASSWD  "anonymous@"//#undef  kDebug#define ENABLE_CAN_RESUME// JPF: somebody should find a better solution for this or move this to KIO// JPF: anyhow, in KDE 3.2.0 I found diffent MAX_IPC_SIZE definitions!namespace KIO {    enum buffersizes    {  /**        * largest buffer size that should be used to transfer data between        * KIO slaves using the data() function        */        maximumIpcSize = 32 * 1024,        /**         * this is a reasonable value for an initial read() that a KIO slave         * can do to obtain data via a slow network connection.         */        initialIpcSize =  2 * 1024,        /**         * recommended size of a data block passed to findBufferFileType()         */        mimimumMimeSize =     1024    };    // JPF: this helper was derived from write_all in file.cc (FileProtocol).    static // JPF: in ftp.cc we make it static    /**     * This helper handles some special issues (blocking and interrupted     * system call) when writing to a file handle.     *     * @return 0 on success or an error code on failure (ERR_COULD_NOT_WRITE,     * ERR_DISK_FULL, ERR_CONNECTION_BROKEN).     */   int WriteToFile(int fd, const char *buf, size_t len)   {      while (len > 0)      {  // JPF: shouldn't there be a KDE_write?         ssize_t written = write(fd, buf, len);         if (written >= 0)         {   buf += written;             len -= written;             continue;         }         switch(errno)         {   case EINTR:   continue;             case EPIPE:   return ERR_CONNECTION_BROKEN;             case ENOSPC:  return ERR_DISK_FULL;             default:      return ERR_COULD_NOT_WRITE;         }      }      return 0;   }}KIO::filesize_t Ftp::UnknownSize = (KIO::filesize_t)-1;using namespace KIO;extern "C" int KDE_EXPORT kdemain( int argc, char **argv ){  KComponentData componentData( "kio_ftpc", "kdelibs4" );  ( void ) KGlobal::locale();  kDebug(7102) << "Starting " << getpid();  if (argc != 4)  {     fprintf(stderr, "Usage: kio_ftps protocol domain-socket1 domain-socket2\n");     exit(-1);  }  Ftp slave(argv[2], argv[3]);  slave.dispatchLoop();  kDebug(7102) << "Done";  return 0;}//===============================================================================// Ftp//===============================================================================Ftp::Ftp( const QByteArray &pool, const QByteArray &app )    : SlaveBase( "ftps", pool, app ){  // init the socket data  m_data = m_control = NULL;  ftpCloseControlConnection();  // init other members  m_port = 0;  kDebug(7102) << "Ftp::Ftp()";}Ftp::~Ftp(){  kDebug(7102) << "Ftp::~Ftp()";  closeConnection();}/** * This closes a data connection opened by ftpOpenDataConnection(). */void Ftp::ftpCloseDataConnection(){  delete m_data;  m_data = NULL;}/** * This closes a control connection opened by ftpOpenControlConnection() and reinits the * related states.  This method gets called from the constructor with m_control = NULL. */void Ftp::ftpCloseControlConnection(){  m_extControl = 0;  delete m_control;  m_control = NULL;  m_cDataMode = 0;  m_bLoggedOn = false;    // logon needs control connction  m_bTextMode = false;  m_bBusy = false;}/** * Returns the last response from the server (iOffset >= 0)  -or-  reads a new response * (iOffset < 0). The result is returned (with iOffset chars skipped for iOffset > 0). */const char* Ftp::ftpResponse(int iOffset){  assert(m_control != NULL);    // must have control connection socket  const char *pTxt = m_lastControlLine.data();  // read the next line ...  if(iOffset < 0)  {    int  iMore = 0;    m_iRespCode = 0;    // If the server sends multiline responses "nnn-text" we loop here until    // a final "nnn text" line is reached. Only data from the final line will    // be stored. Some servers (OpenBSD) send a single "nnn-" followed by    // optional lines that start with a space and a final "nnn text" line.    do {      while (!m_control->canReadLine() && m_control->waitForReadyRead()) {}      m_lastControlLine = m_control->readLine();      pTxt = m_lastControlLine.data();      int nBytes = m_lastControlLine.size();      int iCode  = atoi(pTxt);      if(iCode > 0) m_iRespCode = iCode;      // ignore lines starting with a space in multiline response      if(iMore != 0 && pTxt[0] == 32)        ;      // otherwise the line should start with "nnn-" or "nnn "      else if(nBytes < 4 || iCode < 100)        iMore = 0;      // we got a valid line, now check for multiline responses ...      else if(iMore == 0 && pTxt[3] == '-')        iMore = iCode;      // "nnn " ends multiline mode ...      else if(iMore != 0 && (iMore != iCode || pTxt[3] != '-'))        iMore = 0;      if(iMore != 0)         kDebug(7102) << "    > " << pTxt;    } while(iMore != 0);    kDebug(7102) << "resp> " << pTxt;    m_iRespType = (m_iRespCode > 0) ? m_iRespCode / 100 : 0;  }  // return text with offset ...  while(iOffset-- > 0 && pTxt[0])    pTxt++;  return pTxt;}void Ftp::closeConnection(){  if(m_control != NULL || m_data != NULL)    kDebug(7102) << "Ftp::closeConnection m_bLoggedOn=" << m_bLoggedOn << " m_bBusy=" << m_bBusy;  if(m_bBusy)              // ftpCloseCommand not called  {    kWarning(7102) << "Ftp::closeConnection Abandoned data stream";    ftpCloseDataConnection();  }  if(m_bLoggedOn)           // send quit  {    if( !ftpSendCmd( "quit", 0 ) || (m_iRespType != 2) )      kWarning(7102) << "Ftp::closeConnection QUIT returned error: " << m_iRespCode;  }  // close the data and control connections ...  ftpCloseDataConnection();  ftpCloseControlConnection();}void Ftp::setHost( const QString& _host, quint16 _port, const QString& _user,                   const QString& _pass ){  kDebug(7102) << "Ftp::setHost (" << getpid() << "): " << _host << " port=" << _port;  m_proxyURL = metaData("UseProxy");  m_bUseProxy = (m_proxyURL.isValid() && m_proxyURL.protocol() == "ftp");  if ( m_host != _host || m_port != _port ||       m_user != _user || m_pass != _pass )    closeConnection();  m_host = _host;  m_port = _port;  m_user = _user;  m_pass = _pass;}void Ftp::openConnection(){  ftpOpenConnection(loginExplicit);}bool Ftp::ftpOpenConnection (LoginMode loginMode){  // check for implicit login if we are already logged on ...  if(loginMode == loginImplicit && m_bLoggedOn)  {    assert(m_control != NULL);    // must have control connection socket    return true;  }  kDebug(7102) << "ftpOpenConnection " << m_host << ":" << m_port << " "                << m_user << " [password hidden]";  infoMessage( i18n("Opening connection to host %1", m_host) );  if ( m_host.isEmpty() )  {    error( ERR_UNKNOWN_HOST, QString() );    return false;  }  assert( !m_bLoggedOn );  m_initialPath.clear();  m_currentPath.clear();  QString host = m_bUseProxy ? m_proxyURL.host() : m_host;  int port = m_bUseProxy ? m_proxyURL.port() : m_port;  if (!ftpOpenControlConnection(host, port) )    return false;          // error emitted by ftpOpenControlConnection  infoMessage( i18n("Connected to host %1", m_host) );  if(loginMode != loginDefered)  {    m_bLoggedOn = ftpLogin();    if( !m_bLoggedOn )      return false;       // error emitted by ftpLogin  }  m_bTextMode = config()->readEntry("textmode", false);  connected();  return true;}/** * Called by @ref openConnection. It opens the control connection to the ftp server. * * @return true on success. */bool Ftp::ftpOpenControlConnection( const QString &host, int port, bool ignoreSslErrors ){  m_bIgnoreSslErrors = ignoreSslErrors;  // implicitly close, then try to open a new connection ...  closeConnection();  QString sErrorMsg;  // now connect to the server and read the login message ...  if (port == 0)    port = 21;                  // default FTP port	m_control = new QSslSocket();	KSocketFactory::synchronousConnectToHost(m_control, "ftps", host, port, connectTimeout() * 1000);  int iErrorCode = m_control->state() == QAbstractSocket::ConnectedState ? 0 : ERR_COULD_NOT_CONNECT;  // on connect success try to read the server message...  if(iErrorCode == 0)  {    const char* psz = ftpResponse(-1);    if(m_iRespType != 2)    { // login not successful, do we have an message text?      if(psz[0])        sErrorMsg = i18n("%1.\n\nReason: %2", host, psz);      iErrorCode = ERR_COULD_NOT_CONNECT;    }  }  else  {    if (m_control->error() == QAbstractSocket::HostNotFoundError)      iErrorCode = ERR_UNKNOWN_HOST;    sErrorMsg = QString("%1: %2").arg(host).arg(m_control->errorString());  }  // Send unencrypted "AUTH TLS" request.  // TODO: redirect to FTP fallback on negative response.  if(iErrorCode == 0)   {    bool authSucc = (ftpSendCmd("AUTH TLS") && (m_iRespCode == 234));    if (!authSucc)    {      iErrorCode = ERR_SLAVE_DEFINED;      sErrorMsg = i18n("The FTP server does not seem to support ftps-encryption.");    }  }  // Starts the encryption  if(iErrorCode == 0)   {    // If the method has been called with ignoreSslErrors, make the ssl socket    // ignore the errors during handshakes.     if (ignoreSslErrors) m_control->ignoreSslErrors();    m_control->startClientEncryption();    if (!m_control->waitForEncrypted(connectTimeout() * 1000))     {      // It is quite common, that the TLS handshake fails, as the majority       // of certificates are self signed, and thus the host cannot be verified.      // If the user wants to continue nevertheless, this method is called      // again, with the "ignoreSslErrors" flag.      bool doNotIgnore = false;      QList<QSslError> errors = m_control->sslErrors();      for (int i = 0; i < errors.size(); ++i)       {	if (messageBox(WarningContinueCancel, errors.at(i).errorString(), 	"TLS Handshake Error", 	i18n("&Continue"), 	i18n("&Cancel")) == KMessageBox::Cancel) doNotIgnore = false; 	      }      if (doNotIgnore)       {	iErrorCode = ERR_SLAVE_DEFINED;	sErrorMsg = i18n("TLS Handshake Error.");      }      else      {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -