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

📄 ftp.cpp

📁 一个用QT开发的FTP客户端
💻 CPP
📖 第 1 页 / 共 5 页
字号:
  bool protpSucc = (ftpSendCmd("PROT P") && (m_iRespType == 2));  if (!protpSucc)  {    // Set the data channel to clear (should not be necessary, just in case).    ftpSendCmd("PROT C");    return false;  }    return true;}/* * 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()->readEntry("DisablePassiveMode", false) )  {    iErrCode = ftpOpenPASVDataConnection();    if(iErrCode == 0)    {      // success      requestDataEncryption();      return 0;     }    iErrCodePASV = iErrCode;    ftpCloseDataConnection();    if ( !config()->readEntry("DisableEPSV", false) )    {      iErrCode = ftpOpenEPSVDataConnection();      if(iErrCode == 0)      {	// success	requestDataEncryption();	return 0;       }      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;  }  // fall back to port mode  iErrCode = ftpOpenPortDataConnection();  if(iErrCode == 0)   {    // success    requestDataEncryption();    return 0;   }  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 successful, 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;  if (m_extControl & eprtUnknown)    return ERR_INTERNAL;  //QTcpServer *server = new SslServer();  SslServer *server = new SslServer(); //KSocketFactory::listen("ftp-data");  server = new SslServer();  server->setProxy(KSocketFactory::proxyForListening("ftp-data"));  server->listen();  if (!server->isListening())  {    delete server;    return ERR_COULD_NOT_LISTEN;  }  server->setMaxPendingConnections(1);  QString command;  QHostAddress localAddress = m_control->localAddress();  if (localAddress.protocol() == QAbstractSocket::IPv4Protocol)  {    struct    {      quint32 ip4;      quint16 port;    } data;    data.ip4 = localAddress.toIPv4Address();    data.port = server->serverPort();    unsigned char *pData = reinterpret_cast<unsigned char*>(&data);    command.sprintf("PORT %d,%d,%d,%d,%d,%d",pData[0],pData[1],pData[2],pData[3],pData[4],pData[5]);  }  else if (localAddress.protocol() == QAbstractSocket::IPv6Protocol)  {    command = QString("EPRT |2|%2|%3|").arg(localAddress.toString()).arg(server->serverPort());  }  if( ftpSendCmd(command.toLatin1()) && (m_iRespType == 2) ) return 0;  {    server->waitForNewConnection(connectTimeout() * 1000);    m_data = server->socket();    //m_data = server->nextPendingConnection();    delete server;    return m_data ? 0 : ERR_COULD_NOT_CONNECT;  }  delete server;  return ERR_INTERNAL;}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;  }  bool useDataEnc = requestDataEncryption();  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;    }  }  QByteArray 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();    m_bBusy = true;              // cleared in ftpCloseCommand    if (useDataEnc)     {      int result = encryptDataChannel();      if (result != 0)       {	error(result, "TLS Negotiation failed on the data channel."); 	return false;      }    }    return true;  }  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;  kDebug(7102) << "ftpCloseCommand: reading command result";  m_bBusy = false;  if(!ftpResponse(-1) || (m_iRespType != 2) )  {    kDebug(7102) << "ftpCloseCommand: no transfer complete message";    return false;  }  return true;}void Ftp::mkdir( const KUrl & url, int permissions ){  if( !ftpOpenConnection(loginImplicit) )        return;  QString path = remoteEncoding()->encode(url);  QByteArray 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, KIO::JobFlags flags ){  if( !ftpOpenConnection(loginImplicit) )        return;  // The actual functionality is in ftpRename because put needs it  if ( ftpRename( src.path(), dst.path(), flags ) )    finished();  else    error( ERR_CANNOT_RENAME, src.path() );}bool Ftp::ftpRename( const QString & src, const QString & dst, KIO::JobFlags ){  // TODO honor overwrite  assert( m_bLoggedOn );  int pos = src.lastIndexOf("/");  if( !ftpFolder(src.left(pos+1), false) )      return false;  QByteArray from_cmd = "RNFR ";  from_cmd += remoteEncoding()->encode(src.mid(pos+1));  if( !ftpSendCmd( from_cmd ) || (m_iRespType != 3) )      return false;  QByteArray 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  QByteArray 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)  QString cmd = QString::fromLatin1("SITE CHMOD ") + QString::number( permissions & 511, 8 /*octal*/ ) + ' ';  cmd += path;  ftpSendCmd(remoteEncoding()->encode(cmd));  if(m_iRespType == 2)     return true;  if(m_iRespCode == 500)  {    m_extControl |= chmodUnknown;    kDebug(7102) << "ftpChmod: CHMOD not supported - disabling";  }  return false;}void Ftp::chmod( const KUrl & url, int permissions ){  if( !ftpOpenConnection(loginImplicit) )        return;  if ( !ftpChmod( url.path(), permissions ) )    error( ERR_CANNOT_CHMOD, url.path() );  else    finished();}void Ftp::ftpCreateUDSEntry( const QString & filename, FtpEntry& ftpEnt, UDSEntry& entry, bool isDir ){  assert(entry.count() == 0); // by contract :-)  entry.insert( KIO::UDSEntry::UDS_NAME, filename );  entry.insert( KIO::UDSEntry::UDS_SIZE, ftpEnt.size );  entry.insert( KIO::UDSEntry::UDS_MODIFICATION_TIME, ftpEnt.date );  entry.insert( KIO::UDSEntry::UDS_ACCESS, ftpEnt.access );  entry.insert( KIO::UDSEntry::UDS_USER, ftpEnt.owner );  if ( !ftpEnt.group.isEmpty() )  {    entry.insert( KIO::UDSEntry::UDS_GROUP, ftpEnt.group );  }  if ( !ftpEnt.link.isEmpty() )  {    entry.insert( KIO::UDSEntry::UDS_LINK_DEST, ftpEnt.link );    KMimeType::Ptr mime = KMimeType::findByUrl( KUrl("ftps://host/" + filename ) );    // Links on ftp sites are often links to dirs, and we have no way to check    // that. Let's do like Netscape : assume dirs generally.    // But we do this only when the mimetype can't be known from the filename.    // --> we do better than Netscape :-)    if ( mime->name() == KMimeType::defaultMimeType() )    {      kDebug(7102) << "Setting guessed mime type to inode/directory for " << filename;      entry.insert( KIO::UDSEntry::UDS_GUESSED_MIME_TYPE, QString::fromLatin1( "inode/directory" ) );      isDir = true;    }  }  entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, isDir ? S_IFDIR : ftpEnt.type );  // entry.insert KIO::UDSEntry::UDS_ACCESS_TIME,buff.st_atime);  // entry.insert KIO::UDSEntry::UDS_CREATION_TIME,buff.st_ctime);}void Ftp::ftpShortStatAnswer( const QString& filename, bool isDir ){    UDSEntry entry;    entry.insert( KIO::UDSEntry::UDS_NAME, filename );    entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, isDir ? S_IFDIR : S_IFREG );    entry.insert( KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH );    // No details about size, ownership, group, etc.    statEntry(entry);    finished();}void Ftp::ftpStatAnswerNotFound( const QString & path, const QString & filename ){    // Only do the 'hack' below if we want to download an existing file (i.e. when looking at the "source")    // When e.g. uploading a file, we still need stat() to return "not found"    // when the file doesn't exist.    QString statSide = metaData("statSide");    kDebug(7102) << "Ftp::stat statSide=" << statSide;    if ( statSide == "source" )    {        kDebug(7102) << "Not found, but assuming found, because some servers don't allow listing";        // MS Server is incapable of handling "list <blah>" in a case insensitive way        // But "retr <blah>" works. So lie in stat(), to get going...        //        // There's also the case of ftp://ftp2.3ddownloads.com/90380/linuxgames/loki/patches/ut/ut-patch-436.run        // where listing permissions are denied, but downloading is still possible.        ftpShortStatAnswer( filename, false /*file, not dir*/ );        return;    }    error( ERR_DOES_NOT_EXIST, path );}void Ftp::stat( const KUrl &url){  kDebug(7102) << "Ftp::stat : path='" << url.path() << "'";  if( !ftpOpenConnection(loginImplicit) )        return;  QString path = QDir::cleanPath( url.path() );

⌨️ 快捷键说明

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