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

📄 ftp.cpp

📁 一个用QT开发的FTP客户端
💻 CPP
📖 第 1 页 / 共 5 页
字号:
      // Parse third field      if ( strlen( p_date_3 ) == 4 ) // 4 digits, looks like a year        tmptr->tm_year = atoi( p_date_3 ) - 1900;      else      {        // otherwise, the year is implicit        // according to man ls, this happens when it is between than 6 months        // old and 1 hour in the future.        // So the year is : current year if tm_mon <= currentMonth+1        // otherwise current year minus one        // (The +1 is a security for the "+1 hour" at the end of the month issue)        if ( tmptr->tm_mon > currentMonth + 1 )          tmptr->tm_year--;        // and p_date_3 contains probably a time        char * semicolon;        if ( ( semicolon = (char*)strchr( p_date_3, ':' ) ) )        {          *semicolon = '\0';          tmptr->tm_min = atoi( semicolon + 1 );          tmptr->tm_hour = atoi( p_date_3 );        }        else          kWarning(7102) << "Can't parse third field " << p_date_3;      }      //kDebug(7102) << asctime( tmptr );      de.date = mktime( tmptr );      return true;    }  } // line invalid, loop to get another line  return false;}//===============================================================================// public: get           download file from server// helper: ftpGet        called from get() and copy()//===============================================================================void Ftp::get( const KUrl & url ){  kDebug(7102) << "Ftp::get " << url.url();  int iError = 0;  ftpGet(iError, -1, url, 0);               // iError gets status  if(iError)                                // can have only server side errs     error(iError, url.path());  ftpCloseCommand();                        // must close command!}Ftp::StatusCode Ftp::ftpGet(int& iError, int iCopyFile, const KUrl& url, KIO::fileoffset_t llOffset){  // Calls error() by itself!  if( !ftpOpenConnection(loginImplicit) )    return statusServerError;  // Try to find the size of the file (and check that it exists at  // the same time). If we get back a 550, "File does not exist"  // or "not a plain file", check if it is a directory. If it is a  // directory, return an error; otherwise simply try to retrieve  // the request...  if ( !ftpSize( url.path(), '?' ) && (m_iRespCode == 550) &&       ftpFolder(url.path(), false) )  {    // Ok it's a dir in fact    kDebug(7102) << "ftpGet: it is a directory in fact";    iError = ERR_IS_DIRECTORY;    return statusServerError;  }  QString resumeOffset = metaData("resume");  if ( !resumeOffset.isEmpty() )  {    llOffset = resumeOffset.toLongLong();    kDebug(7102) << "ftpGet: got offset from metadata : " << llOffset;  }  if( !ftpOpenCommand("retr", url.path(), '?', ERR_CANNOT_OPEN_FOR_READING, llOffset) )  {    kWarning(7102) << "ftpGet: Can't open for reading";    return statusServerError;  }  // Read the size from the response string  if(m_size == UnknownSize)  {    const char* psz = strrchr( ftpResponse(4), '(' );    if(psz) m_size = charToLongLong(psz+1);    if (!m_size) m_size = UnknownSize;  }  KIO::filesize_t bytesLeft = 0;  if ( m_size != UnknownSize )    bytesLeft = m_size - llOffset;  kDebug(7102) << "ftpGet: starting with offset=" << llOffset;  KIO::fileoffset_t processed_size = llOffset;  QByteArray array;  bool mimetypeEmitted = false;  char buffer[maximumIpcSize];  // start with small data chunks in case of a slow data source (modem)  // - unfortunately this has a negative impact on performance for large  // - files - so we will increase the block size after a while ...  int iBlockSize = initialIpcSize;  int iBufferCur = 0;  while(m_size == UnknownSize || bytesLeft > 0)  {  // let the buffer size grow if the file is larger 64kByte ...    if(processed_size-llOffset > 1024 * 64)      iBlockSize = maximumIpcSize;    // read the data and detect EOF or error ...    if(iBlockSize+iBufferCur > (int)sizeof(buffer))      iBlockSize = sizeof(buffer) - iBufferCur;    if (m_data->bytesAvailable() == 0)      m_data->waitForReadyRead();    int n = m_data->read( buffer+iBufferCur, iBlockSize );    if(n <= 0)    {   // this is how we detect EOF in case of unknown size      if( m_size == UnknownSize && n == 0 )        break;      // unexpected eof. Happens when the daemon gets killed.      iError = ERR_COULD_NOT_READ;      return statusServerError;    }    processed_size += n;    // collect very small data chunks in buffer before processing ...    if(m_size != UnknownSize)    {      bytesLeft -= n;      iBufferCur += n;      if(iBufferCur < mimimumMimeSize && bytesLeft > 0)      {        processedSize( processed_size );        continue;      }      n = iBufferCur;      iBufferCur = 0;    }    // get the mime type and set the total size ...    if(!mimetypeEmitted)    {      mimetypeEmitted = true;      array = QByteArray::fromRawData(buffer, n);      KMimeType::Ptr mime = KMimeType::findByNameAndContent(url.fileName(), array);      array.clear();      kDebug(7102) << "ftpGet: Emitting mimetype " << mime->name();      mimeType( mime->name() );      if( m_size != UnknownSize )	// Emit total size AFTER mimetype        totalSize( m_size );    }    // write output file or pass to data pump ...    if(iCopyFile == -1)    {        array = QByteArray::fromRawData(buffer, n);        data( array );        array.clear();    }    else if( (iError = WriteToFile(iCopyFile, buffer, n)) != 0)       return statusClientError;              // client side error    processedSize( processed_size );  }  kDebug(7102) << "ftpGet: done";  if(iCopyFile == -1)          // must signal EOF to data pump ...    data(array);               // array is empty and must be empty!  processedSize( m_size == UnknownSize ? processed_size : m_size );  kDebug(7102) << "ftpGet: emitting finished()";  finished();  return statusSuccess;}#if 0  void Ftp::mimetype( const KUrl& url )  {    if( !ftpOpenConnection(loginImplicit) )          return;    if ( !ftpOpenCommand( "retr", url.path(), 'I', ERR_CANNOT_OPEN_FOR_READING, 0 ) ) {      kWarning(7102) << "Can't open for reading";      return;    }    char buffer[ 2048 ];    QByteArray array;    // Get one chunk of data only and send it, KIO::Job will determine the    // mimetype from it using KMimeMagic    int n = m_data->read( buffer, 2048 );    array.setRawData(buffer, n);    data( array );    array.resetRawData(buffer, n);    kDebug(7102) << "aborting";    ftpAbortTransfer();    kDebug(7102) << "finished";    finished();    kDebug(7102) << "after finished";  }  void Ftp::ftpAbortTransfer()  {    // RFC 959, page 34-35    // IAC (interpret as command) = 255 ; IP (interrupt process) = 254    // DM = 242 (data mark)     char msg[4];     // 1. User system inserts the Telnet "Interrupt Process" (IP) signal     //   in the Telnet stream.     msg[0] = (char) 255; //IAC     msg[1] = (char) 254; //IP     (void) send(sControl, msg, 2, 0);     // 2. User system sends the Telnet "Sync" signal.     msg[0] = (char) 255; //IAC     msg[1] = (char) 242; //DM     if (send(sControl, msg, 2, MSG_OOB) != 2)       ; // error...     // Send ABOR     kDebug(7102) << "send ABOR";     QCString buf = "ABOR\r\n";     if ( KSocks::self()->write( sControl, buf.data(), buf.length() ) <= 0 )  {       error( ERR_COULD_NOT_WRITE, QString() );       return;     }     //     kDebug(7102) << "read resp";     if ( readresp() != '2' )     {       error( ERR_COULD_NOT_READ, QString() );       return;     }    kDebug(7102) << "close sockets";    closeSockets();  }#endif//===============================================================================// public: put           upload file to server// helper: ftpPut        called from put() and copy()//===============================================================================void Ftp::put(const KUrl& url, int permissions, KIO::JobFlags flags){  kDebug(7102) << "Ftp::put " << url.url();  int iError = 0;                           // iError gets status  ftpPut(iError, -1, url, permissions, flags);  if(iError)                                // can have only server side errs     error(iError, url.path());  ftpCloseCommand();                        // must close command!}Ftp::StatusCode Ftp::ftpPut(int& iError, int iCopyFile, const KUrl& dest_url,                            int permissions, KIO::JobFlags flags){  if( !ftpOpenConnection(loginImplicit) )    return statusServerError;  // Don't use mark partial over anonymous FTP.  // My incoming dir allows put but not rename...  bool bMarkPartial;  if (m_user.isEmpty () || m_user == FTP_LOGIN)    bMarkPartial = false;  else    bMarkPartial = config()->readEntry("MarkPartial", true);  QString dest_orig = dest_url.path();  QString dest_part( dest_orig );  dest_part += ".part";  if ( ftpSize( dest_orig, 'I' ) )  {    if ( m_size == 0 )    { // delete files with zero size      QByteArray cmd = "DELE ";      cmd += remoteEncoding()->encode(dest_orig);      if( !ftpSendCmd( cmd ) || (m_iRespType != 2) )      {        iError = ERR_CANNOT_DELETE_PARTIAL;        return statusServerError;      }    }    else if ( !(flags & KIO::Overwrite) && !(flags & KIO::Resume) )    {       iError = ERR_FILE_ALREADY_EXIST;       return statusServerError;    }    else if ( bMarkPartial )    { // when using mark partial, append .part extension      if ( !ftpRename( dest_orig, dest_part, KIO::Overwrite ) )      {        iError = ERR_CANNOT_RENAME_PARTIAL;        return statusServerError;      }    }    // Don't chmod an existing file    permissions = -1;  }  else if ( bMarkPartial && ftpSize( dest_part, 'I' ) )  { // file with extension .part exists    if ( m_size == 0 )    {  // delete files with zero size      QByteArray cmd = "DELE ";      cmd += remoteEncoding()->encode(dest_part);      if ( !ftpSendCmd( cmd ) || (m_iRespType != 2) )      {        iError = ERR_CANNOT_DELETE_PARTIAL;        return statusServerError;      }    }    else if ( !(flags & KIO::Overwrite) && !(flags & KIO::Resume) )    {      flags |= canResume (m_size) ? KIO::Resume : KIO::DefaultFlags;      if (!(flags & KIO::Resume))      {        iError = ERR_FILE_ALREADY_EXIST;        return statusServerError;      }    }  }  else    m_size = 0;  QString dest;  // if we are using marking of partial downloads -> add .part extension  if ( bMarkPartial ) {    kDebug(7102) << "Adding .part extension to " << dest_orig;    dest = dest_part;  } else    dest = dest_orig;  KIO::fileoffset_t offset = 0;  // set the mode according to offset  if( (flags & KIO::Resume) && m_size > 0 )  {    offset = m_size;    if(iCopyFile != -1)    {      if( KDE_lseek(iCopyFile, offset, SEEK_SET) < 0 )      {        iError = ERR_CANNOT_RESUME;        return statusClientError;      }    }  }  if (! ftpOpenCommand( "stor", dest, '?', ERR_COULD_NOT_WRITE, offset ) )     return statusServerError;  kDebug(7102) << "ftpPut: starting with offset=" << offset;  KIO::fileoffset_t processed_size = offset;  QByteArray buffer;  int result;  int iBlockSize = initialIpcSize;  // Loop until we got 'dataEnd'  do  {    if(iCopyFile == -1)    {      dataReq(); // Request for data      result = readData( buffer );    }    else    { // let the buffer size grow if the file is larger 64kByte ...      if(processed_size-offset > 1024 * 64)        iBlockSize = maximumIpcSize;      buffer.resize(iBlockSize);      result = ::read(iCopyFile, buffer.data(), buffer.size());      if(result < 0)        iError = ERR_COULD_NOT_WRITE;      else        buffer.resize(result);    }    if (result > 0)    {      m_data->write( buffer );      while (m_data->bytesToWrite() && m_data->waitForBytesWritten()) {}      processed_size += result;      processedSize (processed_size);    }  }  while ( result > 0 );  if (result != 0) // error  {    ftpCloseCommand();               // don't care about errors    kDebug(7102) << "Error during 'put'. Aborting.";    if (bMarkPartial)    {      // Remove if smaller than minimum size      if ( ftpSize( dest, 'I' ) &&           ( processed_size < config()->readEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE) ) )      {        QByteArray cmd = "DELE ";        cmd += remoteEncoding()->encode(dest);        (void) ftpSendCmd( cmd );      }    }    return statusServerError;  }  if ( !ftpCloseCommand() )  {    iError = ERR_COULD_NOT_WRITE;    return statusServerError;  }  // after full download rename the file back to original name  if ( bMarkPartial )  {    kDebug(7102) << "renaming dest (" << dest << ") back to dest_orig (" << dest_orig << ")";    if ( !ftpRename( dest, dest_orig, KIO::Overwrite ) )    {      iError = ERR_CANNOT_RENAME_PARTIAL;      return statusServerError;    }  }  // set final permissions  if ( permissions != -1 )  {    if ( m_user == FTP_LOGIN )      kDebug(7102) << "Trying to chmod over anonymous FTP ???";    // chmod the file we just put    if ( ! ftpChmod( dest_orig, permissions ) )    {        // To be tested        //if ( m_user != FTP_LOGIN )        //    warning( i18n( "Could not change permissions for\n%1" ).arg( dest_orig ) );    }  }  /

⌨️ 快捷键说明

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