ftp.cc
来自「konqueror3 embedded版本, KDE环境下的当家浏览器的嵌入式版」· CC 代码 · 共 2,199 行 · 第 1/5 页
CC
2,199 行
( sscanf(start, "(%d,%d,%d,%d,%d,%d)",&i[0], &i[1], &i[2], &i[3], &i[4], &i[5]) != 6 && sscanf(start, "=%d,%d,%d,%d,%d,%d", &i[0], &i[1], &i[2], &i[3], &i[4], &i[5]) != 6 ) ) { kdError(7102) << "parsing IP and port numbers failed. String parsed: " << start << endl; return ERR_INTERNAL; } // Make hostname and port number ... QString host; host.sprintf("%d.%d.%d.%d", i[0], i[1], i[2], i[3]); int port = i[4] << 8 | i[5]; // now connect the data socket ... m_data = new FtpSocket("PASV"); m_data->setAddress(host, port); kdDebug(7102) << "Connecting to " << host << " on port " << port << endl; return m_data->connectSocket(connectTimeout(), false);}/* * ftpOpenEPSVDataConnection - opens a data connection via EPSV */int Ftp::ftpOpenEPSVDataConnection(){ assert(m_control != NULL); // must have control connection socket assert(m_data == NULL); // ... but no data connection const KSocketAddress *sa = m_control->peerAddress(); int portnum; // we are sure sa is a KInetSocketAddress, because we asked for KExtendedSocket::inetSocket // when we connected const KInetSocketAddress *sin = static_cast<const KInetSocketAddress*>(sa); if (m_extControl & epsvUnknown || sa == NULL) return ERR_INTERNAL; m_bPasv = true; if( !ftpSendCmd("EPSV") || (m_iRespType != 2) ) { // unknown command? if( m_iRespType == 5 ) { kdDebug(7102) << "disabling use of EPSV" << endl; m_extControl |= epsvUnknown; } return ERR_INTERNAL; } char *start = strchr(ftpResponse(3), '|'); if ( !start || sscanf(start, "|||%d|", &portnum) != 1) return ERR_INTERNAL; m_data = new FtpSocket("EPSV"); m_data->setAddress(sin->nodeName(), portnum); return m_data->connectSocket(connectTimeout(), false) != 0;}/* * ftpOpenEPRTDataConnection * @return 0 on success, ERR_INTERNAL if mode not acceptable -or- a fatal error code */int Ftp::ftpOpenEPRTDataConnection(){ assert(m_control != NULL); // must have control connection socket assert(m_data == NULL); // ... but no data connection // yes, we are sure this is a KInetSocketAddress const KInetSocketAddress *sin = static_cast<const KInetSocketAddress*>(m_control->localAddress()); m_bPasv = false; if (m_extControl & eprtUnknown || sin == NULL) return ERR_INTERNAL; m_data = new FtpSocket("EPRT"); m_data->setHost(sin->nodeName()); m_data->setPort(0); // setting port to 0 will make us bind to a random, free port m_data->setSocketFlags(KExtendedSocket::noResolve | KExtendedSocket::passiveSocket | KExtendedSocket::inetSocket); if (m_data->listen(1) < 0) return ERR_COULD_NOT_LISTEN; sin = static_cast<const KInetSocketAddress*>(m_data->localAddress()); if (sin == NULL) return ERR_INTERNAL; // QString command = QString::fromLatin1("eprt |%1|%2|%3|").arg(sin->ianaFamily()) // .arg(sin->nodeName()) // .arg(sin->port()); QCString command; command.sprintf("eprt |%d|%s|%d|", sin->ianaFamily(), sin->nodeName().latin1(), sin->port()); // FIXME! Encoding for hostnames? if( ftpSendCmd(command) && (m_iRespType == 2) ) return 0; // unknown command? if( m_iRespType == 5 ) { kdDebug(7102) << "disabling use of EPRT" << endl; m_extControl |= eprtUnknown; } return ERR_INTERNAL;}/* * ftpOpenDataConnection - set up data connection * * The routine calls several ftpOpenXxxxConnection() helpers to find * the best connection mode. If a helper cannot connect if returns * ERR_INTERNAL - so this is not really an error! All other error * codes are treated as fatal, e.g. they are passed back to the caller * who is responsible for calling error(). ftpOpenPortDataConnection * can be called as last try and it does never return ERR_INTERNAL. * * @return 0 if successful, err code otherwise */int Ftp::ftpOpenDataConnection(){ // make sure that we are logged on and have no data connection... assert( m_bLoggedOn ); ftpCloseDataConnection(); int iErrCode = 0; int iErrCodePASV = 0; // Remember error code from PASV // First try passive (EPSV & PASV) modes if( !config()->readBoolEntry("DisablePassiveMode", false) ) { iErrCode = ftpOpenPASVDataConnection(); if(iErrCode == 0) return 0; // success iErrCodePASV = iErrCode; ftpCloseDataConnection(); if( !config()->readBoolEntry("DisableEPSV", false) ) { iErrCode = ftpOpenEPSVDataConnection(); if(iErrCode == 0) return 0; // success ftpCloseDataConnection(); } // if we sent EPSV ALL already and it was accepted, then we can't // use active connections any more if (m_extControl & epsvAllSent) return iErrCodePASV ? iErrCodePASV : iErrCode; } if( !config()->readBoolEntry("DisableEPRT", false) ) { iErrCode = ftpOpenEPRTDataConnection(); if(iErrCode == 0) return 0; // success ftpCloseDataConnection(); } // fall back to port mode iErrCode = ftpOpenPortDataConnection(); if(iErrCode == 0) return 0; // success ftpCloseDataConnection(); // prefer to return the error code from PASV if any, since that's what should have worked in the first place return iErrCodePASV ? iErrCodePASV : iErrCode;}/* * ftpOpenPortDataConnection - set up data connection * * @return 0 if successfull, err code otherwise (but never ERR_INTERNAL * because this is the last connection mode that is tried) */int Ftp::ftpOpenPortDataConnection(){ assert(m_control != NULL); // must have control connection socket assert(m_data == NULL); // ... but no data connection m_bPasv = false; // create a socket, bind it and let it listen ... m_data = new FtpSocket("PORT"); m_data->setSocketFlags(KExtendedSocket::noResolve | KExtendedSocket::passiveSocket | KExtendedSocket::inetSocket); // yes, we are sure this is a KInetSocketAddress const KInetSocketAddress* pAddr = static_cast<const KInetSocketAddress*>(m_control->localAddress()); m_data->setAddress(pAddr->nodeName(), "0"); m_data->setAddressReusable(true); if(m_data->listen(1) < 0) return ERR_COULD_NOT_LISTEN; struct linger lng = { 0, 0 }; if ( !m_data->setSocketOption(SO_LINGER, (char*)&lng, sizeof(lng)) ) return ERR_COULD_NOT_CREATE_SOCKET; // send the PORT command ... pAddr = static_cast<const KInetSocketAddress*>(m_data->localAddress()); struct sockaddr* psa = (struct sockaddr*)pAddr->addressV4(); unsigned char* pData = (unsigned char*)(psa->sa_data); QCString portCmd; portCmd.sprintf("port %d,%d,%d,%d,%d,%d", pData[2], pData[3], pData[4], pData[5], pData[0], pData[1]); if( ftpSendCmd(portCmd) && (m_iRespType == 2) ) return 0; return ERR_COULD_NOT_CONNECT;}/* * ftpAcceptConnect - wait for incoming connection * Used by @ref ftpOpenCommand * * return false on error or timeout */int Ftp::ftpAcceptConnect(){ assert(m_data != NULL); if ( m_bPasv ) { m_data->setServer(-1); return true; } int sSock = m_data->fd(); struct sockaddr addr; for(;;) { fd_set mask; FD_ZERO(&mask); FD_SET(sSock,&mask); int r = KSocks::self()->select(sSock + 1, &mask, NULL, NULL, 0L); if( r < 0 && errno != EINTR && errno != EAGAIN ) continue; if( r > 0 ) break; } ksocklen_t l = sizeof(addr); m_data->setServer( KSocks::self()->accept(sSock, &addr, &l) ); return (m_data->server() != -1);}bool Ftp::ftpOpenCommand( const char *_command, const QString & _path, char _mode, int errorcode, KIO::fileoffset_t _offset ){ int errCode = 0; if( !ftpDataMode(_mode) ) errCode = ERR_COULD_NOT_CONNECT; else errCode = ftpOpenDataConnection(); if(errCode != 0) { error(errCode, m_host); return false; } if ( _offset > 0 ) { // send rest command if offset > 0, this applies to retr and stor commands char buf[100]; sprintf(buf, "rest %lld", _offset); if ( !ftpSendCmd( buf ) ) return false; if( m_iRespType != 3 ) { error( ERR_CANNOT_RESUME, _path ); // should never happen return false; } } QCString tmp = _command; QString errormessage; if ( !_path.isEmpty() ) { tmp += " "; tmp += remoteEncoding()->encode(_path); } if( !ftpSendCmd( tmp ) || (m_iRespType != 1) ) { if( _offset > 0 && strcmp(_command, "retr") == 0 && (m_iRespType == 4) ) errorcode = ERR_CANNOT_RESUME; // The error here depends on the command errormessage = _path; } else { // Only now we know for sure that we can resume if ( _offset > 0 && strcmp(_command, "retr") == 0 ) canResume(); if( ftpAcceptConnect() ) { m_bBusy = true; // cleared in ftpCloseCommand return true; } errorcode = ERR_COULD_NOT_ACCEPT; } error(errorcode, errormessage); return false;}bool Ftp::ftpCloseCommand(){ // first close data sockets (if opened), then read response that // we got for whatever was used in ftpOpenCommand ( should be 226 ) if(m_data) { delete m_data; m_data = NULL; } if(!m_bBusy) return true; kdDebug(7102) << "ftpCloseCommand: reading command result" << endl; m_bBusy = false; if(ftpResponse(-1) <= 0 || (m_iRespType != 2) ) { kdDebug(7102) << "ftpCloseCommand: no transfer complete message" << endl; return false; } return true;}void Ftp::mkdir( const KURL & url, int permissions ){ if( !ftpOpenConnection(loginImplicit) ) return; QString path = remoteEncoding()->encode(url); QCString buf = "mkd "; buf += remoteEncoding()->encode(path); if( !ftpSendCmd( buf ) || (m_iRespType != 2) ) { QString currentPath( m_currentPath ); // Check whether or not mkdir failed because // the directory already exists... if( ftpFolder( path, false ) ) { error( ERR_DIR_ALREADY_EXIST, path ); // Change the directory back to what it was... (void) ftpFolder( currentPath, false ); return; } error( ERR_COULD_NOT_MKDIR, path ); return; } if ( permissions != -1 ) { // chmod the dir we just created, ignoring errors. (void) ftpChmod( path, permissions ); } finished();}void Ftp::rename( const KURL& src, const KURL& dst, bool overwrite ){ if( !ftpOpenConnection(loginImplicit) ) return; // The actual functionality is in ftpRename because put needs it if ( ftpRename( src.path(), dst.path(), overwrite ) ) finished(); else error( ERR_CANNOT_RENAME, src.path() );}bool Ftp::ftpRename( const QString & src, const QString & dst, bool /* overwrite */ ){ // TODO honor overwrite assert( m_bLoggedOn ); int pos = src.findRev("/"); if( !ftpFolder(src.left(pos+1), false) ) return false; QCString from_cmd = "RNFR "; from_cmd += remoteEncoding()->encode(src.mid(pos+1)); if( !ftpSendCmd( from_cmd ) || (m_iRespType != 3) ) return false; QCString to_cmd = "RNTO "; to_cmd += remoteEncoding()->encode(dst); if( !ftpSendCmd( to_cmd ) || (m_iRespType != 2) ) return false; return true;}void Ftp::del( const KURL& url, bool isfile ){ if( !ftpOpenConnection(loginImplicit) ) return; // When deleting a directory, we must exit from it first // The last command probably went into it (to stat it) if ( !isfile ) ftpFolder(remoteEncoding()->directory(url), false); // ignore errors QCString cmd = isfile ? "DELE " : "RMD "; cmd += remoteEncoding()->encode(url); if( !ftpSendCmd( cmd ) || (m_iRespType != 2) ) error( ERR_CANNOT_DELETE, url.path() ); else finished();}bool Ftp::ftpChmod( const QString & path, int permissions ){ assert( m_bLoggedOn ); if(m_extControl & chmodUnknown) // previous errors? return false; // we need to do bit AND 777 to get permissions, in case // we were sent a full mode (unlikely) QCString cmd; cmd.sprintf("SITE CHMOD %o ", permissions & 511 ); cmd += remoteEncoding()->encode(path); ftpSendCmd(cmd); if(m_iRespType == 2) return true; if(m_iRespCode == 500) { m_extControl |= chmodUnknown; kdDebug(7102) << "ftpChmod: CHMOD not supported - disabling"; } return false;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?