📄 ftp.cc
字号:
if ( p_access[0] == 'l' ) { tmp = p_name; int i = tmp.findRev( QString::fromLatin1(" -> ") ); if ( i != -1 ) { de.link = p_name + i + 4; tmp.truncate( i ); p_name = tmp.ascii(); } else de.link = QString::null; } else de.link = QString::null; if (strchr(p_name, '/')) return 0L; // Don't trick us! de.access = 0; de.type = S_IFREG; switch ( p_access[0] ) { case 'd': de.type = S_IFDIR; break; case 's': de.type = S_IFSOCK; break; case 'b': de.type = S_IFBLK; break; case 'c': de.type = S_IFCHR; break; case 'l': de.type = S_IFREG; // we don't set S_IFLNK here. de.link says it. break; default: break; } if ( p_access[1] == 'r' ) de.access |= S_IRUSR; if ( p_access[2] == 'w' ) de.access |= S_IWUSR; if ( p_access[3] == 'x' ) de.access |= S_IXUSR; if ( p_access[4] == 'r' ) de.access |= S_IRGRP; if ( p_access[5] == 'w' ) de.access |= S_IWGRP; if ( p_access[6] == 'x' ) de.access |= S_IXGRP; if ( p_access[7] == 'r' ) de.access |= S_IROTH; if ( p_access[8] == 'w' ) de.access |= S_IWOTH; if ( p_access[9] == 'x' ) de.access |= S_IXOTH; // maybe fromLocal8Bit would be better in some cases, // but what proves that the ftp server is in the same encoding // than the user ?? de.owner = QString::fromLatin1(p_owner); de.group = QString::fromLatin1(p_group); de.size = atoi(p_size); QCString tmp( p_name ); // Some sites put more than one space between the date and the name // e.g. ftp://ftp.uni-marburg.de/mirror/ de.name = QString::fromLatin1(tmp.stripWhiteSpace()); // Parsing the date is somewhat tricky // Examples : "Oct 6 22:49", "May 13 1999" // First get current time - we need the current month and year time_t currentTime = time( 0L ); struct tm * tmptr = gmtime( ¤tTime ); int currentMonth = tmptr->tm_mon; //kdDebug(7102) << "Current time :" << asctime( tmptr ) << endl; // Reset time fields tmptr->tm_sec = 0; tmptr->tm_min = 0; tmptr->tm_hour = 0; // Get day number (always second field) tmptr->tm_mday = atoi( p_date_2 ); // Get month from first field // NOTE : no, we don't want to use KLocale here // It seems all FTP servers use the English way //kdDebug() << "Looking for month " << p_date_1 << endl; static const char * s_months[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; for ( int c = 0 ; c < 12 ; c ++ ) if ( !strcmp( p_date_1, s_months[c]) ) { //kdDebug() << "Found month " << c << " for " << p_date_1 << endl; tmptr->tm_mon = c; break; } // 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 kdWarning(7102) << "Can't parse third field " << p_date_3 << endl; } //kdDebug(7102) << asctime( tmptr ) << endl; de.date = mktime( tmptr ); return( &de ); } } return 0L;}bool Ftp::ftpCloseDir(){ if( dirfile ) { kdDebug(7102) << "... closing" << endl; if ( ! ftpCloseCommand() ) return false; fclose( dirfile ); dirfile = 0L; } else kdDebug(7102) << "ftpCloseDir but no dirfile ??" << endl; return true;}//////////// get, put ////////void Ftp::get( const KURL & url ){ kdDebug(7102) << "Ftp::get " << url.url() << endl; if (!m_bLoggedOn) { openConnection(); if (!m_bLoggedOn) { kdDebug(7102) << "Login failure, aborting" << endl; return; } } // try to find the size of the file (and check that it exists at the same time) // 550 is "File does not exist"/"not a plain file" if ( !ftpSize( url.path(), 'I' ) && strncmp( rspbuf, "550", 3) == 0 ) { // Not a file, or doesn't exist. We need to find out. QCString tmp = "cwd "; tmp += url.path().latin1(); if ( ftpSendCmd( tmp, '2' ) ) { // Ok it's a dir in fact kdDebug(7102) << "Ftp::get: it is a directory in fact" << endl; error( ERR_IS_DIRECTORY, url.path() ); } else { kdDebug(7102) << "Ftp::get: doesn't exist" << endl; error( ERR_DOES_NOT_EXIST, url.path() ); } return; } unsigned long offset = 0; QString resumeOffset = metaData(QString::fromLatin1("resume")); if ( !resumeOffset.isEmpty() ) { offset = resumeOffset.toInt(); kdDebug(7102) << "Ftp::get got offset from medata : " << offset << endl; } if ( !ftpOpenCommand( "retr", url.path(), 'I', ERR_CANNOT_OPEN_FOR_READING, offset ) ) { kdWarning(7102) << "Can't open for reading" << endl; return; } // Read the size from the response string if ( strlen( rspbuf ) > 4 && m_size == 0 ) { const char * p = strrchr( rspbuf, '(' ); if ( p != 0L ) m_size = atol( p + 1 ); } size_t bytesLeft = m_size - offset; kdDebug(7102) << "Ftp::get starting with offset=" << offset << endl; int processed_size = offset; time_t t_start = time( 0L ); time_t t_last = t_start; char buffer[ 2048 ]; QByteArray array; QByteArray mimetypeBuffer; bool mimetypeEmitted = false; while( bytesLeft > 0 ) { int n = ftpRead( buffer, 2048 ); bytesLeft -= n; // Buffer the first 1024 bytes for mimetype determination if ( !mimetypeEmitted ) { int oldSize = mimetypeBuffer.size(); mimetypeBuffer.resize(oldSize + n); memcpy(mimetypeBuffer.data()+oldSize, buffer, n); // Found enough data - or we're arriving to the end of the file -> emit mimetype if (mimetypeBuffer.size() >= 1024 || bytesLeft <= 0) { KMimeMagicResult * result = KMimeMagic::self()->findBufferFileType( mimetypeBuffer, url.fileName() ); kdDebug(7102) << "Emitting mimetype " << result->mimeType() << endl; mimeType( result->mimeType() ); mimetypeEmitted = true; data( mimetypeBuffer ); mimetypeBuffer.resize(0); // Emit total size AFTER mimetype totalSize( m_size ); } } else if ( n > 0 ) { array.setRawData(buffer, n); data( array ); array.resetRawData(buffer, n); } else // unexpected eof. Happens when the daemon gets killed. { error( ERR_COULD_NOT_READ, url.path() ); return; } processed_size += n; time_t t = time( 0L ); if ( t - t_last >= 1 ) { processedSize( processed_size ); speed( ( processed_size - offset ) / ( t - t_start ) ); t_last = t; } } kdDebug(7102) << "Get: done, sending empty QByteArray" << endl; data( QByteArray() ); kdDebug(7102) << "Get: calling ftpCloseCommand()" << endl; (void) ftpCloseCommand(); // proceed even on error processedSize( m_size ); time_t t = time( 0L ); if ( t - t_start >= 1 ) speed( ( processed_size - offset ) / ( t - t_start ) ); kdDebug(7102) << "Get: emitting finished()" << endl; finished();}/*void Ftp::mimetype( const KURL& url ){ if (!m_bLoggedOn) { openConnection(); if (!m_bLoggedOn) { kdDebug(7102) << "Login failure, aborting" << endl; return; } } if ( !ftpOpenCommand( "retr", url.path(), 'I', ERR_CANNOT_OPEN_FOR_READING, 0 ) ) { kdWarning(7102) << "Can't open for reading" << endl; 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 = ftpRead( buffer, 2048 ); array.setRawData(buffer, n); data( array ); array.resetRawData(buffer, n); kdDebug(7102) << "aborting" << endl; ftpAbortTransfer(); kdDebug(7102) << "finished" << endl; finished(); kdDebug(7102) << "after finished" << endl;}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 kdDebug(7102) << "send ABOR" << endl; QCString buf = "ABOR\r\n"; if ( KSocks::self()->write( sControl, buf.data(), buf.length() ) <= 0 ) { error( ERR_COULD_NOT_WRITE, QString::null ); return; } // kdDebug(7102) << "read resp" << endl; if ( readresp() != '2' ) { error( ERR_COULD_NOT_READ, QString::null ); return; } kdDebug(7102) << "close sockets" << endl; closeSockets();}*/void Ftp::put( const KURL& dest_url, int permissions, bool overwrite, bool resume ){ QString dest_orig = dest_url.path(); if (!m_bLoggedOn) { openConnection(); if (!m_bLoggedOn) { kdDebug(7102) << "Login failure, aborting" << endl; return; } } kdDebug(7102) << "Put " << dest_orig << endl; QString dest_part( dest_orig ); dest_part += QString::fromLatin1(".part"); bool bMarkPartial = config()->readBoolEntry("MarkPartial", true); // Don't use mark partial over anonymous FTP. // My incoming dir allows put but not rename... if (m_user == FTP_LOGIN) bMarkPartial = false; if ( ftpSize( dest_orig, 'I' ) ) { if ( m_size == 0 ) { // delete files with zero size QCString cmd = "DELE "; cmd += dest_orig.ascii(); if ( !ftpSendCmd( cmd, '2' ) ) { error( ERR_CANNOT_DELETE_PARTIAL, dest_orig ); return; } } else if ( !overwrite && !resume ) { error( ERR_FILE_ALREADY_EXIST, dest_orig ); return; } else if ( bMarkPartial ) { // when using mark partial, append .part extension if ( !ftpRename( dest_orig, dest_part, true ) ) { error( KIO::ERR_CANNOT_RENAME_PARTIAL, dest_orig ); return; } } // Don't chmod an existing file permissions = -1; } else if ( ftpSize( dest_part, 'I' ) ) { // file with extension .part exists if ( m_size == 0 ) { // delete files with zero size QCString cmd = "DELE "; cmd += dest_part.ascii(); if ( !ftpSendCmd( cmd, '2' ) ) { error( ERR_CANNOT_DELETE_PARTIAL, dest_orig ); return; } } else if ( !overwrite && !resume ) { error( ERR_FILE_ALREADY_EXIST, dest_orig ); return; } else if ( !bMarkPartial ) { // when using mark partial, remove .part extension if ( !ftpRename( dest_part, dest_orig, true ) ) { error( KIO::ERR_CANNOT_RENAME_PARTIAL, dest_orig ); return; } } } QString dest; // if we are using marking of partial downloads -> add .part extension if ( bMarkPartial ) { kdDebug(7102) << "Adding .part extension to " << dest_orig << endl; dest = dest_part; } else dest = dest_orig; unsigned long offset = 0; // set the mode according to offset if ( resume ) { offset = m_size; kdDebug(7102) << "Offset = " << (unsigned int) offset << "d" << endl; } if (! ftpOpenCommand( "stor", dest, 'I', ERR_COULD_NOT_WRITE, offset ) ) return; int result; // Loop until we got 'dataEnd' do { QByteArray buffer; dataReq(); // Request for data result = readData( buffer ); if (result > 0) { ftpWrite( buffer.data(), buffer.size() ); } } while ( result > 0 ); if (result != 0) // error { (void) ftpCloseCommand(); // don't care about errors kdDebug(7102) << "Error during 'put'. Aborting." << endl; if (bMarkPartial) { // Remove if smaller than minimum size if ( ftpSize( dest, 'I' ) && ( m_size < (unsigned long) config()->readNumEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE) ) ) { QCString cmd = "DELE "; cmd += dest.ascii(); (void) ftpSendCmd( cmd, '\0' ); } } return; } if ( !ftpCloseCommand() ) { error( KIO::ERR_COULD_NOT_WRITE, dest_orig); return; } // after full download rename the file back to original name if ( bMarkPartial ) { kdDebug(7102) << "renaming dest (" << dest << ") back to dest_orig (" << dest_orig << ")" << endl; if ( !ftpRename( dest, dest_orig, true ) ) { error( KIO::ERR_CANNOT_RENAME_PARTIAL, dest_orig ); return; } } // set final permissions if ( permissions != -1 ) { if ( m_user == FTP_LOGIN ) kdDebug(7102) << "Trying to chmod over anonymous FTP ???" << endl; // chmod the file we just put, ignoring errors. (void) ftpChmod( dest_orig, permissions ); } // We have done our job => finish finished();}/* This is related to "canResume" ... not sure how Old main.cc contained: if ( !ftp.ftpResume( 0 ) ) m_bCanResume = false;bool Ftp::ftpResume( unsigned long offset ){ char buf[64]; sprintf(buf, "rest %ld", offset); if ( !ftpSendCmd( buf, '3' ) ) { error( ERR_CANNOT_RESUME, QString::null ); return false; } return true;}*//** Use the SIZE command to get the file size. Warning : the size depends on the transfer mode, hence the second arg. */bool Ftp::ftpSize( const QString & path, char mode ){ QCString buf; buf.sprintf("type %c", mode); if ( !ftpSendCmd( buf, '2' ) ) { return false; } buf="SIZE "; buf+=path.ascii(); if (!ftpSendCmd(buf,'2')) { m_size = 0; return false; } m_size = atol(rspbuf+4); // skip leading "213 " (response code) return true;}size_t Ftp::ftpRead(void *buffer, long len){ size_t n = KSocks::self()->read( sData, buffer, len ); return n;}size_t Ftp::ftpWrite(void *buffer, long len){ return( KSocks::self()->write( sData, buffer, len ) );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -