ftp.cc

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

CC
2,199
字号
  if(loginMode == loginImplicit && m_bLoggedOn)  {    assert(m_control != NULL);    // must have control connection socket    return true;  }  kdDebug(7102) << "ftpOpenConnection " << m_host << ":" << m_port << " "                << m_user << " [password hidden]" << endl;  infoMessage( i18n("Opening connection to host %1").arg(m_host) );  if ( m_host.isEmpty() )  {    error( ERR_UNKNOWN_HOST, QString::null );    return false;  }  assert( !m_bLoggedOn );  m_initialPath = QString::null;  m_currentPath = QString::null;  QString host = m_bUseProxy ? m_proxyURL.host() : m_host;  unsigned short 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").arg(m_host) );  if(loginMode != loginDefered)  {    m_bLoggedOn = ftpLogin();    if( !m_bLoggedOn )      return false;       // error emitted by ftpLogin  }  m_bTextMode = config()->readBoolEntry("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, unsigned short int port ){  if ( port == 0 )  {    struct servent *pse;    if ( ( pse = getservbyname( "ftp", "tcp" ) ) == NULL )        port = 21;    else        port = ntohs(pse->s_port);  }  // implicitly close, then try to open a new connection ...  closeConnection();  int iErrorCode = ERR_OUT_OF_MEMORY;  QString sErrorMsg;  m_control = new FtpSocket("CNTL");  if(m_control != NULL)  {    // now connect to the server and read the login message ...    m_control->setAddress(host, port);    iErrorCode = m_control->connectSocket(connectTimeout(), true);    sErrorMsg = host;    // 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").arg(host).arg(psz);        iErrorCode = ERR_COULD_NOT_CONNECT;      }    }  }  // if there was a problem - report it ...  if(iErrorCode == 0)             // OK, return success    return true;  closeConnection();              // clean-up on error  error(iErrorCode, sErrorMsg);  return false;}/** * Called by @ref openConnection. It logs us in. * @ref m_initialPath is set to the current working directory * if logging on was successful. * * @return true on success. */bool Ftp::ftpLogin(){  infoMessage( i18n("Sending login information") );  assert( !m_bLoggedOn );  QString user = m_user;  QString pass = m_pass;  if ( config()->readBoolEntry("EnableAutoLogin") )  {    QString au = config()->readEntry("autoLoginUser");    if ( !au.isEmpty() )    {        user = au;        pass = config()->readEntry("autoLoginPass");    }  }  // Try anonymous login if both username/password  // information is blank.  if (user.isEmpty() && pass.isEmpty())  {    user = FTP_LOGIN;    pass = FTP_PASSWD;  }  AuthInfo info;  info.url.setProtocol( "ftp" );  info.url.setHost( m_host );  info.url.setPort( m_port );  info.url.setUser( user );  QCString tempbuf;  int failedAuth = 0;  do  {    // Check the cache and/or prompt user for password if 1st    // login attempt failed OR the user supplied a login name,    // but no password.    if ( failedAuth > 0 || (!user.isEmpty() && pass.isEmpty()) )    {      QString errorMsg;      kdDebug(7102) << "Prompting user for login info..." << endl;      // Ask user if we should retry after when login fails!      if( failedAuth > 0 )      {        errorMsg = i18n("Message sent:\nLogin using username=%1 and "                        "password=[hidden]\n\nServer replied:\n%2\n\n"                        ).arg(user).arg(ftpResponse(0));      }      if ( user != FTP_LOGIN )        info.username = user;      info.prompt = i18n("You need to supply a username and a password "                          "to access this site.");      info.commentLabel = i18n( "Site:" );      info.comment = i18n("<b>%1</b>").arg( m_host );      info.keepPassword = true; // Prompt the user for persistence as well.      info.readOnly = (!m_user.isEmpty() && m_user != FTP_LOGIN);      bool disablePassDlg = config()->readBoolEntry( "DisablePassDlg", false );      if ( disablePassDlg || !openPassDlg( info, errorMsg ) )      {        error( ERR_USER_CANCELED, m_host );        return false;      }      else      {        user = info.username;        pass = info.password;      }    }    tempbuf = "user ";    tempbuf += user.latin1();    if ( m_bUseProxy )    {      tempbuf += '@';      tempbuf += m_host.latin1();      if ( m_port > 0 && m_port != DEFAULT_FTP_PORT )      {        tempbuf += ':';        tempbuf += QString::number(m_port).latin1();      }    }    kdDebug(7102) << "Sending Login name: " << tempbuf << endl;    bool loggedIn = ( ftpSendCmd(tempbuf) && (m_iRespCode == 230) );    bool needPass = (m_iRespCode == 331);    // Prompt user for login info if we do not    // get back a "230" or "331".    if ( !loggedIn && !needPass )    {      kdDebug(7102) << "Login failed: " << ftpResponse(0) << endl;      ++failedAuth;      continue;  // Well we failed, prompt the user please!!    }    if( needPass )    {      tempbuf = "pass ";      tempbuf += pass.latin1();      kdDebug(7102) << "Sending Login password: " << "[protected]" << endl;      loggedIn = ( ftpSendCmd(tempbuf) && (m_iRespCode == 230) );    }    if ( loggedIn )    {      // Do not cache the default login!!      if( user != FTP_LOGIN && pass != FTP_PASSWD )        cacheAuthentication( info );      failedAuth = -1;    }  } while( ++failedAuth );  kdDebug(7102) << "Login OK" << endl;  infoMessage( i18n("Login OK") );  // Okay, we're logged in. If this is IIS 4, switch dir listing style to Unix:  // Thanks to jk@soegaard.net (Jens Kristian S鴊aard) for this hint  if( ftpSendCmd("syst") && (m_iRespType == 2) )  {    if( !strncmp( ftpResponse(0), "215 Windows_NT", 14 ) ) // should do for any version    {      ftpSendCmd( "site dirstyle" );      // Check if it was already in Unix style      // Patch from Keith Refson <Keith.Refson@earth.ox.ac.uk>      if( !strncmp( ftpResponse(0), "200 MSDOS-like directory output is on", 37 ))         //It was in Unix style already!         ftpSendCmd( "site dirstyle" );      // windows won't support chmod before KDE konquers their desktop...      m_extControl |= chmodUnknown;    }  }  else    kdWarning(7102) << "syst failed" << endl;  if ( config()->readBoolEntry ("EnableAutoLoginMacro") )    ftpAutoLoginMacro ();  // Get the current working directory  kdDebug(7102) << "Searching for pwd" << endl;  if( !ftpSendCmd("pwd") || (m_iRespType != 2) )  {    kdDebug(7102) << "Couldn't issue pwd command" << endl;    error( ERR_COULD_NOT_LOGIN, i18n("Could not login to %1.").arg(m_host) ); // or anything better ?    return false;  }  QString sTmp = remoteEncoding()->decode( ftpResponse(3) );  int iBeg = sTmp.find('"');  int iEnd = sTmp.findRev('"');  if(iBeg > 0 && iBeg < iEnd)  {    m_initialPath = sTmp.mid(iBeg+1, iEnd-iBeg-1);    if(m_initialPath[0] != '/') m_initialPath.prepend('/');    kdDebug(7102) << "Initial path set to: " << m_initialPath << endl;    m_currentPath = m_initialPath;  }  return true;}void Ftp::ftpAutoLoginMacro (){  QString macro = metaData( "autoLoginMacro" );  if ( macro.isEmpty() )    return;    QStringList list = QStringList::split('\n', macro);      for(QStringList::Iterator it = list.begin() ; it != list.end() ; ++it )      {    if ( (*it).startsWith("init") )        {          list = QStringList::split( '\\', macro);          it = list.begin();          ++it;  // ignore the macro name          for( ; it != list.end() ; ++it )          {            // TODO: Add support for arbitrary commands            // besides simply changing directory!!            if ( (*it).startsWith( "cwd" ) )              ftpFolder( (*it).mid(4).stripWhiteSpace(), false );          }          break;        }      }}/** * ftpSendCmd - send a command (@p cmd) and read response * * @param maxretries number of time it should retry. Since it recursively * calls itself if it can't read the answer (this happens especially after * timeouts), we need to limit the recursiveness ;-) * * return true if any response received, false on error */bool Ftp::ftpSendCmd( const QCString& cmd, int maxretries ){  assert(m_control != NULL);    // must have control connection socket  if ( cmd.find( '\r' ) != -1 || cmd.find( '\n' ) != -1)  {    kdWarning(7102) << "Invalid command received (contains CR or LF):"                    << cmd.data() << endl;    error( ERR_UNSUPPORTED_ACTION, m_host );    return false;  }  // Don't print out the password...  bool isPassCmd = (cmd.left(4).lower() == "pass");  if ( !isPassCmd )    kdDebug(7102) << "send> " << cmd.data() << endl;  else    kdDebug(7102) << "send> pass [protected]" << endl;  // Send the message...  QCString buf = cmd;  buf += "\r\n";      // Yes, must use CR/LF - see http://cr.yp.to/ftp/request.html  int num = m_control->write(buf.data(), buf.length());  // If we were able to successfully send the command, then we will  // attempt to read the response. Otherwise, take action to re-attempt  // the login based on the maximum number of retires specified...  if( num > 0 )    ftpResponse(-1);  else  { m_iRespType = m_iRespCode = 0;    m_control->textClear();  }  // If respCh is NULL or the response is 421 (Timed-out), we try to re-send  // the command based on the value of maxretries.  if( (m_iRespType <= 0) || (m_iRespCode == 421) )  {    // We have not yet logged on...    if (!m_bLoggedOn)    {      // The command was sent from the ftpLogin function, i.e. we are actually      // attempting to login in. NOTE: If we already sent the username, we      // return false and let the user decide whether (s)he wants to start from      // the beginning...      if (maxretries > 0 && !isPassCmd)      {        closeConnection ();        if( ftpOpenConnection(loginDefered) )          ftpSendCmd ( cmd, maxretries - 1 );      }      return false;    }    else    {      if ( maxretries < 1 )        return false;      else      {        kdDebug(7102) << "Was not able to communicate with " << m_host << endl                      << "Attempting to re-establish connection." << endl;        closeConnection(); // Close the old connection...        openConnection();  // Attempt to re-establish a new connection...        if (!m_bLoggedOn)        {          if (m_control != NULL)  // if openConnection succeeded ...          {            kdDebug(7102) << "Login failure, aborting" << endl;            error (ERR_COULD_NOT_LOGIN, m_host);            closeConnection ();          }          return false;        }        kdDebug(7102) << "Logged back in, re-issuing command" << endl;        // If we were able to login, resend the command...        if (maxretries)          maxretries--;        return ftpSendCmd( cmd, maxretries );      }    }  }  return true;}/* * ftpOpenPASVDataConnection - set up data connection, using PASV mode * * return 1 if successful, 0 otherwise * doesn't set error message, since non-pasv mode will always be tried if * this one fails */int Ftp::ftpOpenPASVDataConnection(){  assert(m_control != NULL);    // must have control connection socket  assert(m_data == NULL);       // ... but no data connection  // Check that we can do PASV  const KSocketAddress *sa = m_control->peerAddress();  if (sa != NULL && sa->family() != PF_INET)    return ERR_INTERNAL;       // no PASV for non-PF_INET connections  if (m_extControl & pasvUnknown)    return ERR_INTERNAL;       // already tried and got "unknown command"  m_bPasv = true;  /* Let's PASsiVe*/  if( !ftpSendCmd("PASV") || (m_iRespType != 2) )  {    kdDebug(7102) << "PASV attempt failed" << endl;    // unknown command?    if( m_iRespType == 5 )    {        kdDebug(7102) << "disabling use of PASV" << endl;        m_extControl |= pasvUnknown;    }    return ERR_INTERNAL;  }  // The usual answer is '227 Entering Passive Mode. (160,39,200,55,6,245)'  // but anonftpd gives '227 =160,39,200,55,6,245'  int i[6];  char *start = strchr(ftpResponse(3), '(');  if ( !start )    start = strchr(ftpResponse(3), '=');  if ( !start ||

⌨️ 快捷键说明

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