⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftp.cpp

📁 一个用QT开发的FTP客户端
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	closeConnection();	return ftpOpenControlConnection(host, port, true);      }    }  }  // 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()->readEntry("EnableAutoLogin", false) )  {    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 );  if ( m_port > 0 && m_port != DEFAULT_FTP_PORT )      info.url.setPort( m_port );  info.url.setUser( user );  QByteArray 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;      kDebug(7102) << "Prompting user for login info...";      // 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"                        , user, 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>",  m_host );      info.keepPassword = true; // Prompt the user for persistence as well.      info.readOnly = (!m_user.isEmpty() && m_user != FTP_LOGIN);      bool disablePassDlg = config()->readEntry( "DisablePassDlg", false );      if ( disablePassDlg || !openPasswordDialog( info, errorMsg ) )      {        error( ERR_USER_CANCELED, m_host );        return false;      }      else      {        user = info.username;        pass = info.password;      }    }    tempbuf = "USER ";    tempbuf += user.toLatin1();    if ( m_bUseProxy )    {      tempbuf += '@';      tempbuf += m_host.toLatin1();      if ( m_port > 0 && m_port != DEFAULT_FTP_PORT )      {        tempbuf += ':';        tempbuf += QString::number(m_port).toLatin1();      }    }    kDebug(7102) << "Sending Login name: " << tempbuf;    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 )    {      kDebug(7102) << "Login failed: " << ftpResponse(0);      ++failedAuth;      continue;  // Well we failed, prompt the user please!!    }    if( needPass )    {      tempbuf = "pass ";      tempbuf += pass.toLatin1();      kDebug(7102) << "Sending Login password: " << "[protected]";      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 );  kDebug(7102) << "Login OK";  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 Sgaard) 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    kWarning(7102) << "SYST failed";  if ( config()->readEntry ("EnableAutoLoginMacro", false) )    ftpAutoLoginMacro ();  // Get the current working directory  kDebug(7102) << "Searching for pwd";  if( !ftpSendCmd("PWD") || (m_iRespType != 2) )  {    kDebug(7102) << "Couldn't issue pwd command";    error( ERR_COULD_NOT_LOGIN, i18n("Could not login to %1.", m_host) ); // or anything better ?    return false;  }  QString sTmp = remoteEncoding()->decode( ftpResponse(3) );  int iBeg = sTmp.indexOf('"');  int iEnd = sTmp.lastIndexOf('"');  if(iBeg > 0 && iBeg < iEnd)  {    m_initialPath = sTmp.mid(iBeg+1, iEnd-iBeg-1);    if(m_initialPath[0] != '/') m_initialPath.prepend('/');    kDebug(7102) << "Initial path set to: " << m_initialPath;    m_currentPath = m_initialPath;  }  return true;}void Ftp::ftpAutoLoginMacro (){  QString macro = metaData( "autoLoginMacro" );  if ( macro.isEmpty() )    return;  QStringList list = macro.split('\n',QString::SkipEmptyParts);  for(QStringList::Iterator it = list.begin() ; it != list.end() ; ++it )  {    if ( (*it).startsWith("init") )    {      list = macro.split( '\\',QString::SkipEmptyParts);      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).trimmed(), 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 QByteArray& cmd, int maxretries ){  assert(m_control != NULL);    // must have control connection socket  if ( cmd.indexOf( '\r' ) != -1 || cmd.indexOf( '\n' ) != -1)  {    kWarning(7102) << "Invalid command received (contains CR or LF):"                    << cmd.data();    error( ERR_UNSUPPORTED_ACTION, m_host );    return false;  }  // Don't print out the password...  bool isPassCmd = (cmd.left(4).toLower() == "pass");  if ( !isPassCmd )    kDebug(7102) << "send> " << cmd.data();  else    kDebug(7102) << "send> pass [protected]";  // Send the message...  QByteArray buf = cmd;  buf += "\r\n";      // Yes, must use CR/LF - see http://cr.yp.to/ftp/request.html  int num = m_control->write(buf);  while (m_control->bytesToWrite() && m_control->waitForBytesWritten()) {}  // 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;  }  // 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      {        kDebug(7102) << "Was not able to communicate with " << m_host                      << "Attempting to re-establish connection.";        closeConnection(); // Close the old connection...        openConnection();  // Attempt to re-establish a new connection...        if (!m_bLoggedOn)        {          if (m_control != NULL)  // if openConnection succeeded ...          {            kDebug(7102) << "Login failure, aborting";            error (ERR_COULD_NOT_LOGIN, m_host);            closeConnection ();          }          return false;        }        kDebug(7102) << "Logged back in, re-issuing command";        // 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 0 if successful, ERR_INTERNAL 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  QHostAddress addr = m_control->peerAddress();  if (addr.protocol() != QAbstractSocket::IPv4Protocol)    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) )  {    kDebug(7102) << "PASV attempt failed";    // unknown command?    if( m_iRespType == 5 )    {        kDebug(7102) << "disabling use of PASV";        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];  const char *start = strchr(ftpResponse(3), '(');  if ( !start )    start = strchr(ftpResponse(3), '=');  if ( !start ||       ( 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 ) )  {    kError(7102) << "parsing IP and port numbers failed. String parsed: " << start;    return ERR_INTERNAL;  }  // we ignore the host part on purpose for two reasons  // a) it might be wrong anyway  // b) it would make us being suceptible to a port scanning attack  // now connect the data socket ...  quint16 port = i[4] << 8 | i[5];  kDebug(7102) << "Connecting to " << addr.toString() << " port " << port;  m_data = new QSslSocket();  KSocketFactory::synchronousConnectToHost(m_data, "ftp-data", addr.toString(), port, connectTimeout() * 1000);  return m_data->state() == QAbstractSocket::ConnectedState ? 0 : ERR_INTERNAL;}/* * 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  QHostAddress address = m_control->peerAddress();  int portnum;  if (m_extControl & epsvUnknown)    return ERR_INTERNAL;  m_bPasv = true;  if( !ftpSendCmd("EPSV") || (m_iRespType != 2) )  {    // unknown command?    if( m_iRespType == 5 )    {       kDebug(7102) << "disabling use of EPSV";       m_extControl |= epsvUnknown;    }    return ERR_INTERNAL;  }  const char *start = strchr(ftpResponse(3), '|');  if ( !start || sscanf(start, "|||%d|", &portnum) != 1)    return ERR_INTERNAL;  m_data = new QSslSocket();  KSocketFactory::synchronousConnectToHost(m_data, "ftp-data", address.toString(), portnum,                                                    connectTimeout() * 1000);  return m_data->isOpen() ? 0 : ERR_INTERNAL;}int Ftp::encryptDataChannel(){  if (m_bIgnoreSslErrors) m_data->ignoreSslErrors();  if (m_bPasv) m_data->startClientEncryption();  else m_data->startServerEncryption();  if (!m_data->waitForEncrypted(connectTimeout() * 1000)) return ERR_SLAVE_DEFINED;  return 0;}bool Ftp::requestDataEncryption(){  // initate tls transfer for data chanel on the control channel   bool pbszSucc = (ftpSendCmd("PBSZ 0") && (m_iRespType == 2));  if (!pbszSucc) return false;      // try protected data transfer first

⌨️ 快捷键说明

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