ftp.cc

来自「konqueror3 embedded版本, KDE环境下的当家浏览器的嵌入式版」· CC 代码 · 共 2,199 行 · 第 1/5 页

CC
2,199
字号
// -*- 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.    Recommended reading explaining FTP details and quirks:      http://cr.yp.to/ftp.html  (by D.J. Bernstein)*/#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 <qdir.h>#include <kdebug.h>#include <klocale.h>#include <kinstance.h>#include <kmimemagic.h>#include <kmimetype.h>#include <ksockaddr.h>#include <kio/ioslave_defaults.h>#include <kio/slaveconfig.h>#include <kremoteencoding.h>#include <klargefile.h>#ifdef HAVE_STRTOLL  #define charToLongLong(a) strtoll(a, 0, 10)#else  #define charToLongLong(a) strtol(a, 0, 10)#endif// JPF: a remark on coding style (2004-03-06):// Some calls to QString::fromLatin1() were removed from the code. In most places// the KDE code relies on implicit creation of QStrings. Also Qt has a lot of// const char* overloads, so that using QString::fromLatin1() can be ineffectient!#define FTP_LOGIN   "anonymous"#define FTP_PASSWD  "anonymous@"//#undef  kdDebug#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" { KDE_EXPORT int ftp_kdemain(int argc, char **argv); }int ftp_kdemain( int argc, char **argv ){  KLocale::setMainCatalogue("kdelibs");  KInstance instance( "kio_ftp" );  ( void ) KGlobal::locale();  kdDebug(7102) << "Starting " << getpid() << endl;  if (argc != 4)  {     fprintf(stderr, "Usage: kio_ftp protocol domain-socket1 domain-socket2\n");     exit(-1);  }  Ftp slave(argv[2], argv[3]);  slave.dispatchLoop();  kdDebug(7102) << "Done" << endl;  return 0;}//===============================================================================// FtpTextReader    Read Text lines from a file (or socket)//===============================================================================void FtpTextReader::textClear(){ m_iTextLine = m_iTextBuff = 0;  m_szText[0] = 0;  m_bTextEOF = m_bTextTruncated = false;}int FtpTextReader::textRead(FtpSocket *pSock){  // if we have still buffered data then move it to the left  char* pEOL;  if(m_iTextLine < m_iTextBuff)  { m_iTextBuff -= m_iTextLine;    memmove(m_szText, m_szText+m_iTextLine, m_iTextBuff);    pEOL = (char*)memchr(m_szText, '\n', m_iTextBuff);  // have a complete line?  }  else  { m_iTextBuff = 0;    pEOL = NULL;  }  m_bTextEOF = m_bTextTruncated = false;  // read data from the control socket until a complete line is read  int  nBytes;  while(pEOL == NULL)  {    if(m_iTextBuff > textReadLimit)    {  m_bTextTruncated = true;       m_iTextBuff = textReadLimit;    }    nBytes = pSock->read(m_szText+m_iTextBuff, sizeof(m_szText)-m_iTextBuff);    if(nBytes <= 0)    {      // This error can occur after the server closed the connection (after a timeout)      if(nBytes < 0)        pSock->debugMessage("textRead failed");      m_bTextEOF = true;      pEOL = m_szText + m_iTextBuff;    }    else    {      m_iTextBuff += nBytes;      pEOL = (char*)memchr(m_szText, '\n', m_iTextBuff);    }  }  nBytes = pEOL - m_szText;  m_iTextLine = nBytes + 1;  if(nBytes > textReadLimit)  { m_bTextTruncated = true;    nBytes = textReadLimit;  }  if(nBytes && m_szText[nBytes-1] == '\r')    nBytes--;  m_szText[nBytes] = 0;  return nBytes;}//===============================================================================// FtpSocket        Helper Class for Data or Control Connections//===============================================================================void FtpSocket::debugMessage(const char* pszMsg) const{  kdDebug(7102) << m_pszName << ": " << pszMsg << endl;}int FtpSocket::errorMessage(int iErrorCode, const char* pszMsg) const{  kdError(7102) << m_pszName << ": " << pszMsg << endl;  return iErrorCode;}int FtpSocket::connectSocket(int iTimeOutSec, bool bControl){  closeSocket();  int iOpt = bControl ? KExtendedSocket::inetSocket                      : KExtendedSocket::noResolve;  setSocketFlags(iOpt | socketFlags());  setTimeout(iTimeOutSec);  int iCon = KExtendedSocket::connect();  if(iCon  < 0)  { int iErrorCode = (status() == IO_LookupError)                   ? ERR_UNKNOWN_HOST : ERR_COULD_NOT_CONNECT;    QString strMsg = KExtendedSocket::strError(status(), systemError());    strMsg.prepend("connect failed (code %1): ");    return errorMessage(iErrorCode, strMsg.arg(iCon).latin1());  }  if( !setAddressReusable(true) )    return errorMessage(ERR_COULD_NOT_CREATE_SOCKET, "setAddressReusable failed");  if(!bControl)  { int on=1;    if( !setSocketOption(SO_KEEPALIVE, (char *)&on, sizeof(on)) )      errorMessage(0, "Keepalive not allowed");    struct linger lng = { 1, 120 };    if( !setSocketOption(SO_LINGER, (char *)&lng, sizeof (lng)) )      errorMessage(0, "Linger mode was not allowed.");  }  debugMessage("connected");  return 0;}void FtpSocket::closeSocket(){  if(m_server != -1 || fd() != -1)    debugMessage("disconnected");  if(m_server != -1)  {    ::shutdown(m_server, SHUT_RDWR);    ::close(m_server);    m_server = -1;  }  if(socketStatus() > nothing)    reset();  textClear();}bool FtpSocket::setSocketOption(int opt, char*arg, socklen_t len) const{  return (setsockopt(sock(), SOL_SOCKET, opt, arg, len) != -1);}//===============================================================================// Ftp//===============================================================================Ftp::Ftp( const QCString &pool, const QCString &app )    : SlaveBase( "ftp", pool, app ){  // init the socket data  m_data = m_control = NULL;  ftpCloseControlConnection();  // init other members  m_port = 0;  kdDebug(7102) << "Ftp::Ftp()" << endl;}Ftp::~Ftp(){  kdDebug(7102) << "Ftp::~Ftp()" << endl;  closeConnection();}/** * This closes a data connection opened by ftpOpenDataConnection(). */void Ftp::ftpCloseDataConnection(){  if(m_data != NULL)  { 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;  if(m_control)    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_control->textLine();  // 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 {      int nBytes = m_control->textRead();      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)         kdDebug(7102) << "    > " << pTxt << endl;    } while(iMore != 0);    kdDebug(7102) << "resp> " << pTxt << endl;    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)    kdDebug(7102) << "Ftp::closeConnection m_bLoggedOn=" << m_bLoggedOn << " m_bBusy=" << m_bBusy << endl;  if(m_bBusy)              // ftpCloseCommand not called  {    kdWarning(7102) << "Ftp::closeConnection Abandoned data stream" << endl;    ftpCloseDataConnection();  }  if(m_bLoggedOn)           // send quit  {    if( !ftpSendCmd( "quit", 0 ) || (m_iRespType != 2) )      kdWarning(7102) << "Ftp::closeConnection QUIT returned error: " << m_iRespCode << endl;  }  // close the data and control connections ...  ftpCloseDataConnection();  ftpCloseControlConnection();}void Ftp::setHost( const QString& _host, int _port, const QString& _user,                   const QString& _pass ){  kdDebug(7102) << "Ftp::setHost (" << getpid() << "): " << _host << endl;  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 ...

⌨️ 快捷键说明

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