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