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 + -
显示快捷键?